]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
UBUNTU: SAUCE: Update zfs to e02aaf17f15ad274fa1f24c9c826f1477911ea3f
authorTim Gardner <tim.gardner@canonical.com>
Wed, 26 Oct 2016 18:23:52 +0000 (12:23 -0600)
committerTim Gardner <tim.gardner@canonical.com>
Mon, 20 Feb 2017 03:57:58 +0000 (20:57 -0700)
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
2000 files changed:
zfs/META
zfs/Makefile.am
zfs/Makefile.in [deleted file]
zfs/TEST [new file with mode: 0644]
zfs/aclocal.m4 [deleted file]
zfs/cmd/Makefile.am [new file with mode: 0644]
zfs/cmd/Makefile.in [deleted file]
zfs/cmd/arc_summary/Makefile.am [new file with mode: 0644]
zfs/cmd/arc_summary/Makefile.in [deleted file]
zfs/cmd/arc_summary/arc_summary.py [new file with mode: 0755]
zfs/cmd/arcstat/Makefile.am [new file with mode: 0644]
zfs/cmd/arcstat/Makefile.in [deleted file]
zfs/cmd/arcstat/arcstat.py [new file with mode: 0755]
zfs/cmd/dbufstat/Makefile.am [new file with mode: 0644]
zfs/cmd/dbufstat/Makefile.in [deleted file]
zfs/cmd/dbufstat/dbufstat.py [new file with mode: 0755]
zfs/cmd/fsck_zfs/Makefile.am [new file with mode: 0644]
zfs/cmd/fsck_zfs/Makefile.in [deleted file]
zfs/cmd/fsck_zfs/fsck.zfs [new file with mode: 0755]
zfs/cmd/mount_zfs/Makefile.am [new file with mode: 0644]
zfs/cmd/mount_zfs/Makefile.in [deleted file]
zfs/cmd/mount_zfs/mount_zfs.c [new file with mode: 0644]
zfs/cmd/raidz_test/Makefile.am [new file with mode: 0644]
zfs/cmd/raidz_test/raidz_bench.c [new file with mode: 0644]
zfs/cmd/raidz_test/raidz_test.c [new file with mode: 0644]
zfs/cmd/raidz_test/raidz_test.h [new file with mode: 0644]
zfs/cmd/vdev_id/Makefile.am [new file with mode: 0644]
zfs/cmd/vdev_id/Makefile.in [deleted file]
zfs/cmd/vdev_id/vdev_id [new file with mode: 0755]
zfs/cmd/zdb/Makefile.am [new file with mode: 0644]
zfs/cmd/zdb/Makefile.in [deleted file]
zfs/cmd/zdb/zdb.c [new file with mode: 0644]
zfs/cmd/zdb/zdb_il.c [new file with mode: 0644]
zfs/cmd/zed/Makefile.am [new file with mode: 0644]
zfs/cmd/zed/Makefile.in [deleted file]
zfs/cmd/zed/agents/zfs_agents.h [new file with mode: 0644]
zfs/cmd/zed/agents/zfs_diagnosis.c [new file with mode: 0644]
zfs/cmd/zed/agents/zfs_mod.c [new file with mode: 0644]
zfs/cmd/zed/agents/zfs_retire.c [new file with mode: 0644]
zfs/cmd/zed/zed.c [new file with mode: 0644]
zfs/cmd/zed/zed.d/README [new file with mode: 0644]
zfs/cmd/zed/zed.d/all-debug.sh [new file with mode: 0755]
zfs/cmd/zed/zed.d/all-syslog.sh [new file with mode: 0755]
zfs/cmd/zed/zed.d/checksum-notify.sh [new symlink]
zfs/cmd/zed/zed.d/checksum-spare.sh [new symlink]
zfs/cmd/zed/zed.d/data-notify.sh [new symlink]
zfs/cmd/zed/zed.d/generic-notify.sh [new file with mode: 0755]
zfs/cmd/zed/zed.d/io-notify.sh [new file with mode: 0755]
zfs/cmd/zed/zed.d/io-spare.sh [new file with mode: 0755]
zfs/cmd/zed/zed.d/resilver_finish-notify.sh [new symlink]
zfs/cmd/zed/zed.d/scrub_finish-notify.sh [new file with mode: 0755]
zfs/cmd/zed/zed.d/statechange-led.sh [new file with mode: 0755]
zfs/cmd/zed/zed.d/vdev_attach-led.sh [new symlink]
zfs/cmd/zed/zed.d/vdev_clear-led.sh [new symlink]
zfs/cmd/zed/zed.d/zed-functions.sh [new file with mode: 0644]
zfs/cmd/zed/zed.d/zed.rc [new file with mode: 0644]
zfs/cmd/zed/zed.h [new file with mode: 0644]
zfs/cmd/zed/zed_conf.c [new file with mode: 0644]
zfs/cmd/zed/zed_conf.h [new file with mode: 0644]
zfs/cmd/zed/zed_disk_event.c [new file with mode: 0644]
zfs/cmd/zed/zed_disk_event.h [new file with mode: 0644]
zfs/cmd/zed/zed_event.c [new file with mode: 0644]
zfs/cmd/zed/zed_event.h [new file with mode: 0644]
zfs/cmd/zed/zed_exec.c [new file with mode: 0644]
zfs/cmd/zed/zed_exec.h [new file with mode: 0644]
zfs/cmd/zed/zed_file.c [new file with mode: 0644]
zfs/cmd/zed/zed_file.h [new file with mode: 0644]
zfs/cmd/zed/zed_log.c [new file with mode: 0644]
zfs/cmd/zed/zed_log.h [new file with mode: 0644]
zfs/cmd/zed/zed_strings.c [new file with mode: 0644]
zfs/cmd/zed/zed_strings.h [new file with mode: 0644]
zfs/cmd/zfs/Makefile.am [new file with mode: 0644]
zfs/cmd/zfs/Makefile.in [deleted file]
zfs/cmd/zfs/zfs_iter.c [new file with mode: 0644]
zfs/cmd/zfs/zfs_iter.h [new file with mode: 0644]
zfs/cmd/zfs/zfs_main.c [new file with mode: 0644]
zfs/cmd/zfs/zfs_util.h [new file with mode: 0644]
zfs/cmd/zhack/Makefile.am [new file with mode: 0644]
zfs/cmd/zhack/Makefile.in [deleted file]
zfs/cmd/zhack/zhack.c [new file with mode: 0644]
zfs/cmd/zinject/Makefile.am [new file with mode: 0644]
zfs/cmd/zinject/Makefile.in [deleted file]
zfs/cmd/zinject/translate.c [new file with mode: 0644]
zfs/cmd/zinject/zinject.c [new file with mode: 0644]
zfs/cmd/zinject/zinject.h [new file with mode: 0644]
zfs/cmd/zpios/Makefile.am [new file with mode: 0644]
zfs/cmd/zpios/Makefile.in [deleted file]
zfs/cmd/zpios/zpios.h [new file with mode: 0644]
zfs/cmd/zpios/zpios_main.c [new file with mode: 0644]
zfs/cmd/zpios/zpios_util.c [new file with mode: 0644]
zfs/cmd/zpool/Makefile.am [new file with mode: 0644]
zfs/cmd/zpool/Makefile.in [deleted file]
zfs/cmd/zpool/zpool_iter.c [new file with mode: 0644]
zfs/cmd/zpool/zpool_main.c [new file with mode: 0644]
zfs/cmd/zpool/zpool_util.c [new file with mode: 0644]
zfs/cmd/zpool/zpool_util.h [new file with mode: 0644]
zfs/cmd/zpool/zpool_vdev.c [new file with mode: 0644]
zfs/cmd/zstreamdump/Makefile.am [new file with mode: 0644]
zfs/cmd/zstreamdump/Makefile.in [deleted file]
zfs/cmd/zstreamdump/zstreamdump.c [new file with mode: 0644]
zfs/cmd/ztest/Makefile.am [new file with mode: 0644]
zfs/cmd/ztest/Makefile.in [deleted file]
zfs/cmd/ztest/ztest.c [new file with mode: 0644]
zfs/cmd/zvol_id/Makefile.am [new file with mode: 0644]
zfs/cmd/zvol_id/Makefile.in [deleted file]
zfs/cmd/zvol_id/zvol_id_main.c [new file with mode: 0644]
zfs/config/Rules.am
zfs/config/always-arch.m4 [new file with mode: 0644]
zfs/config/compile [deleted file]
zfs/config/config.guess [deleted file]
zfs/config/config.sub [deleted file]
zfs/config/depcomp [deleted file]
zfs/config/dkms.m4 [deleted file]
zfs/config/install-sh [deleted file]
zfs/config/kernel-acl.m4
zfs/config/kernel-blk-queue-unplug.m4 [new file with mode: 0644]
zfs/config/kernel-check-disk-size-change.m4 [deleted file]
zfs/config/kernel-file-dentry.m4 [new file with mode: 0644]
zfs/config/kernel-fpu.m4 [new file with mode: 0644]
zfs/config/kernel-kobj-name-len.m4 [deleted file]
zfs/config/kernel-kuid-helpers.m4 [new file with mode: 0644]
zfs/config/kernel-lookup-bdev.m4
zfs/config/kernel-mod-param.m4 [new file with mode: 0644]
zfs/config/kernel-rename.m4 [new file with mode: 0644]
zfs/config/kernel-setattr-prepare.m4 [new file with mode: 0644]
zfs/config/kernel-super-userns.m4 [new file with mode: 0644]
zfs/config/kernel-xattr-handler.m4
zfs/config/kernel.m4
zfs/config/libtool.m4 [deleted file]
zfs/config/ltmain.sh [deleted file]
zfs/config/ltoptions.m4 [deleted file]
zfs/config/ltsugar.m4 [deleted file]
zfs/config/ltversion.m4 [deleted file]
zfs/config/lt~obsolete.m4 [deleted file]
zfs/config/missing [deleted file]
zfs/config/suppressed-warnings.txt [new file with mode: 0644]
zfs/config/toolchain-simd.m4 [new file with mode: 0644]
zfs/config/user-arch.m4 [deleted file]
zfs/config/user-commands.m4 [new file with mode: 0644]
zfs/config/user-libattr.m4 [new file with mode: 0644]
zfs/config/user-libblkid.m4
zfs/config/user-libdevmapper.m4 [new file with mode: 0644]
zfs/config/user-libtirpc.m4 [new file with mode: 0644]
zfs/config/user-libudev.m4 [new file with mode: 0644]
zfs/config/user-libuuid.m4
zfs/config/user-zlib.m4
zfs/config/user.m4
zfs/config/zfs-build.m4
zfs/config/zfs-meta.m4
zfs/configure [deleted file]
zfs/configure.ac
zfs/contrib/Makefile.in [deleted file]
zfs/contrib/bash_completion.d/Makefile.in [deleted file]
zfs/contrib/dracut/02zfsexpandknowledge/Makefile.am [new file with mode: 0644]
zfs/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in [new file with mode: 0755]
zfs/contrib/dracut/90zfs/Makefile.am
zfs/contrib/dracut/90zfs/Makefile.in [deleted file]
zfs/contrib/dracut/90zfs/export-zfs.sh.in
zfs/contrib/dracut/90zfs/module-setup.sh.in
zfs/contrib/dracut/90zfs/mount-zfs.sh.in
zfs/contrib/dracut/90zfs/parse-zfs.sh.in
zfs/contrib/dracut/90zfs/zfs-generator.sh.in [new file with mode: 0755]
zfs/contrib/dracut/90zfs/zfs-lib.sh.in
zfs/contrib/dracut/90zfs/zfs-needshutdown.sh.in [new file with mode: 0644]
zfs/contrib/dracut/Makefile.am
zfs/contrib/dracut/Makefile.in [deleted file]
zfs/contrib/initramfs/Makefile.am
zfs/contrib/initramfs/Makefile.in [deleted file]
zfs/contrib/initramfs/scripts/local-top/zfs [new file with mode: 0755]
zfs/contrib/initramfs/scripts/zfs
zfs/copy-builtin
zfs/cp [deleted file]
zfs/dkms.conf [deleted file]
zfs/etc/Makefile.am [new file with mode: 0644]
zfs/etc/Makefile.in [deleted file]
zfs/etc/init.d/Makefile.am [new file with mode: 0644]
zfs/etc/init.d/Makefile.in [deleted file]
zfs/etc/init.d/README.md [new file with mode: 0644]
zfs/etc/init.d/zfs-functions.in
zfs/etc/init.d/zfs-import.in [changed mode: 0644->0755]
zfs/etc/init.d/zfs-mount.in [changed mode: 0644->0755]
zfs/etc/init.d/zfs-share.in [changed mode: 0644->0755]
zfs/etc/init.d/zfs-zed.in [changed mode: 0644->0755]
zfs/etc/init.d/zfs.in
zfs/etc/modules-load.d/Makefile.am [new file with mode: 0644]
zfs/etc/modules-load.d/Makefile.in [deleted file]
zfs/etc/modules-load.d/zfs.conf.in
zfs/etc/systemd/Makefile.am [new file with mode: 0644]
zfs/etc/systemd/Makefile.in [deleted file]
zfs/etc/systemd/system/50-zfs.preset.in
zfs/etc/systemd/system/Makefile.am [new file with mode: 0644]
zfs/etc/systemd/system/Makefile.in [deleted file]
zfs/etc/systemd/system/zfs-import-cache.service.in
zfs/etc/systemd/system/zfs-import-scan.service.in
zfs/etc/systemd/system/zfs-mount.service.in
zfs/etc/systemd/system/zfs-share.service.in
zfs/etc/systemd/system/zfs-zed.service.in
zfs/etc/systemd/system/zfs.target.in
zfs/etc/zfs/Makefile.am [new file with mode: 0644]
zfs/etc/zfs/Makefile.in [deleted file]
zfs/etc/zfs/vdev_id.conf.alias.example [new file with mode: 0644]
zfs/etc/zfs/vdev_id.conf.multipath.example [new file with mode: 0644]
zfs/etc/zfs/vdev_id.conf.sas_direct.example [new file with mode: 0644]
zfs/etc/zfs/vdev_id.conf.sas_switch.example [new file with mode: 0644]
zfs/include/Makefile.in [deleted file]
zfs/include/libzfs.h
zfs/include/libzfs_core.h
zfs/include/libzfs_impl.h
zfs/include/linux/Makefile.am
zfs/include/linux/Makefile.in [deleted file]
zfs/include/linux/blkdev_compat.h
zfs/include/linux/mod_compat.h [new file with mode: 0644]
zfs/include/linux/simd_aarch64.h [new file with mode: 0644]
zfs/include/linux/simd_x86.h [new file with mode: 0644]
zfs/include/linux/vfs_compat.h
zfs/include/sys/Makefile.am
zfs/include/sys/Makefile.in [deleted file]
zfs/include/sys/arc.h
zfs/include/sys/arc_impl.h
zfs/include/sys/avl.h
zfs/include/sys/bqueue.h [new file with mode: 0644]
zfs/include/sys/crypto/Makefile.am [new file with mode: 0644]
zfs/include/sys/crypto/api.h [new file with mode: 0644]
zfs/include/sys/crypto/common.h [new file with mode: 0644]
zfs/include/sys/crypto/icp.h [new file with mode: 0644]
zfs/include/sys/dbuf.h
zfs/include/sys/dmu.h
zfs/include/sys/dmu_impl.h
zfs/include/sys/dmu_objset.h
zfs/include/sys/dmu_send.h
zfs/include/sys/dmu_traverse.h
zfs/include/sys/dmu_zfetch.h
zfs/include/sys/dnode.h
zfs/include/sys/dsl_dataset.h
zfs/include/sys/dsl_deleg.h
zfs/include/sys/dsl_dir.h
zfs/include/sys/dsl_prop.h
zfs/include/sys/edonr.h [new file with mode: 0644]
zfs/include/sys/efi_partition.h
zfs/include/sys/fm/Makefile.in [deleted file]
zfs/include/sys/fm/fs/Makefile.in [deleted file]
zfs/include/sys/fm/fs/zfs.h
zfs/include/sys/fm/protocol.h
zfs/include/sys/fs/Makefile.in [deleted file]
zfs/include/sys/fs/zfs.h
zfs/include/sys/metaslab.h
zfs/include/sys/metaslab_impl.h
zfs/include/sys/mntent.h
zfs/include/sys/pathname.h [new file with mode: 0644]
zfs/include/sys/policy.h [new file with mode: 0644]
zfs/include/sys/refcount.h
zfs/include/sys/sa_impl.h
zfs/include/sys/sha2.h [new file with mode: 0644]
zfs/include/sys/skein.h [new file with mode: 0644]
zfs/include/sys/spa.h
zfs/include/sys/spa_checksum.h [new file with mode: 0644]
zfs/include/sys/spa_impl.h
zfs/include/sys/sysevent.h [new file with mode: 0644]
zfs/include/sys/sysevent/Makefile.am [new file with mode: 0644]
zfs/include/sys/sysevent/dev.h [new file with mode: 0644]
zfs/include/sys/sysevent/eventdefs.h [new file with mode: 0644]
zfs/include/sys/trace_acl.h
zfs/include/sys/trace_arc.h
zfs/include/sys/trace_common.h [new file with mode: 0644]
zfs/include/sys/trace_dbgmsg.h
zfs/include/sys/trace_dbuf.h
zfs/include/sys/trace_zio.h [new file with mode: 0644]
zfs/include/sys/trace_zrlock.h
zfs/include/sys/vdev.h
zfs/include/sys/vdev_disk.h
zfs/include/sys/vdev_impl.h
zfs/include/sys/vdev_raidz.h [new file with mode: 0644]
zfs/include/sys/vdev_raidz_impl.h [new file with mode: 0644]
zfs/include/sys/zap.h
zfs/include/sys/zap_impl.h
zfs/include/sys/zfs_context.h
zfs/include/sys/zfs_ctldir.h
zfs/include/sys/zfs_ioctl.h
zfs/include/sys/zfs_ratelimit.h [new file with mode: 0644]
zfs/include/sys/zfs_rlock.h
zfs/include/sys/zfs_vfsops.h
zfs/include/sys/zfs_vnops.h
zfs/include/sys/zfs_znode.h
zfs/include/sys/zil.h
zfs/include/sys/zio.h
zfs/include/sys/zio_checksum.h
zfs/include/sys/zio_compress.h
zfs/include/sys/zio_impl.h
zfs/include/sys/zio_priority.h [new file with mode: 0644]
zfs/include/sys/zpl.h
zfs/include/sys/zvol.h
zfs/include/zfeature_common.h
zfs/include/zfs_deleg.h
zfs/include/zfs_fletcher.h
zfs/include/zpios-ctl.h
zfs/include/zpios-internal.h
zfs/lib/Makefile.am [new file with mode: 0644]
zfs/lib/Makefile.in [deleted file]
zfs/lib/libavl/Makefile.am [new file with mode: 0644]
zfs/lib/libavl/Makefile.in [deleted file]
zfs/lib/libefi/Makefile.am [new file with mode: 0644]
zfs/lib/libefi/Makefile.in [deleted file]
zfs/lib/libefi/rdwr_efi.c [new file with mode: 0644]
zfs/lib/libicp/Makefile.am [new file with mode: 0644]
zfs/lib/libnvpair/Makefile.am [new file with mode: 0644]
zfs/lib/libnvpair/Makefile.in [deleted file]
zfs/lib/libnvpair/libnvpair.c [new file with mode: 0644]
zfs/lib/libnvpair/nvpair_alloc_system.c [new file with mode: 0644]
zfs/lib/libshare/Makefile.am [new file with mode: 0644]
zfs/lib/libshare/Makefile.in [deleted file]
zfs/lib/libshare/libshare.c [new file with mode: 0644]
zfs/lib/libshare/libshare_impl.h [new file with mode: 0644]
zfs/lib/libshare/nfs.c [new file with mode: 0644]
zfs/lib/libshare/nfs.h [new file with mode: 0644]
zfs/lib/libshare/smb.c [new file with mode: 0644]
zfs/lib/libshare/smb.h [new file with mode: 0644]
zfs/lib/libspl/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/Makefile.in [deleted file]
zfs/lib/libspl/asm-generic/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/asm-generic/Makefile.in [deleted file]
zfs/lib/libspl/asm-generic/atomic.c [new file with mode: 0644]
zfs/lib/libspl/asm-i386/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/asm-i386/Makefile.in [deleted file]
zfs/lib/libspl/asm-i386/atomic.S [new file with mode: 0644]
zfs/lib/libspl/asm-x86_64/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/asm-x86_64/Makefile.in [deleted file]
zfs/lib/libspl/asm-x86_64/atomic.S [new file with mode: 0644]
zfs/lib/libspl/getexecname.c [new file with mode: 0644]
zfs/lib/libspl/gethrestime.c [new file with mode: 0644]
zfs/lib/libspl/gethrtime.c [new file with mode: 0644]
zfs/lib/libspl/getmntany.c [new file with mode: 0644]
zfs/lib/libspl/include/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/include/Makefile.in [deleted file]
zfs/lib/libspl/include/assert.h [new file with mode: 0644]
zfs/lib/libspl/include/atomic.h [new file with mode: 0644]
zfs/lib/libspl/include/attr.h [new file with mode: 0644]
zfs/lib/libspl/include/devid.h [new file with mode: 0644]
zfs/lib/libspl/include/ia32/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/include/ia32/Makefile.in [deleted file]
zfs/lib/libspl/include/ia32/sys/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/include/ia32/sys/Makefile.in [deleted file]
zfs/lib/libspl/include/ia32/sys/asm_linkage.h [new file with mode: 0644]
zfs/lib/libspl/include/libdevinfo.h [new file with mode: 0644]
zfs/lib/libspl/include/libgen.h [new file with mode: 0644]
zfs/lib/libspl/include/libshare.h [new file with mode: 0644]
zfs/lib/libspl/include/limits.h [new file with mode: 0644]
zfs/lib/libspl/include/locale.h [new file with mode: 0644]
zfs/lib/libspl/include/note.h [new file with mode: 0644]
zfs/lib/libspl/include/rpc/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/include/rpc/Makefile.in [deleted file]
zfs/lib/libspl/include/rpc/xdr.h [new file with mode: 0644]
zfs/lib/libspl/include/statcommon.h [new file with mode: 0644]
zfs/lib/libspl/include/stdio.h [new file with mode: 0644]
zfs/lib/libspl/include/stdlib.h [new file with mode: 0644]
zfs/lib/libspl/include/string.h [new file with mode: 0644]
zfs/lib/libspl/include/strings.h [new file with mode: 0644]
zfs/lib/libspl/include/stropts.h [new file with mode: 0644]
zfs/lib/libspl/include/synch.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/include/sys/Makefile.in [deleted file]
zfs/lib/libspl/include/sys/acl.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/acl_impl.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/bitmap.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/byteorder.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/callb.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/cmn_err.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/compress.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/cred.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/debug.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/dkio.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/dklabel.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/dktp/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/include/sys/dktp/Makefile.in [deleted file]
zfs/lib/libspl/include/sys/dktp/fdisk.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/feature_tests.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/file.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/frame.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/int_limits.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/int_types.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/inttypes.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/isa_defs.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/kmem.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/kstat.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/list.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/list_impl.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/mhd.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/mkdev.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/mnttab.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/mount.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/note.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/param.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/policy.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/priv.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/processor.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/stack.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/stat.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/stropts.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/sunddi.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/sysevent/Makefile.in [deleted file]
zfs/lib/libspl/include/sys/sysmacros.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/systeminfo.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/systm.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/time.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/types.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/types32.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/tzfile.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/uio.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/va_list.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/varargs.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/vnode.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/vtoc.h [new file with mode: 0644]
zfs/lib/libspl/include/sys/zone.h [new file with mode: 0644]
zfs/lib/libspl/include/thread.h [new file with mode: 0644]
zfs/lib/libspl/include/tzfile.h [new file with mode: 0644]
zfs/lib/libspl/include/ucred.h [new file with mode: 0644]
zfs/lib/libspl/include/umem.h [new file with mode: 0644]
zfs/lib/libspl/include/unistd.h [new file with mode: 0644]
zfs/lib/libspl/include/util/Makefile.am [new file with mode: 0644]
zfs/lib/libspl/include/util/Makefile.in [deleted file]
zfs/lib/libspl/include/util/sscanf.h [new file with mode: 0644]
zfs/lib/libspl/include/zone.h [new file with mode: 0644]
zfs/lib/libspl/list.c [new file with mode: 0644]
zfs/lib/libspl/mkdirp.c [new file with mode: 0644]
zfs/lib/libspl/strlcat.c [new file with mode: 0644]
zfs/lib/libspl/strlcpy.c [new file with mode: 0644]
zfs/lib/libspl/strnlen.c [new file with mode: 0644]
zfs/lib/libspl/timestamp.c [new file with mode: 0644]
zfs/lib/libspl/zone.c [new file with mode: 0644]
zfs/lib/libunicode/Makefile.am [new file with mode: 0644]
zfs/lib/libunicode/Makefile.in [deleted file]
zfs/lib/libuutil/Makefile.am [new file with mode: 0644]
zfs/lib/libuutil/Makefile.in [deleted file]
zfs/lib/libuutil/uu_alloc.c [new file with mode: 0644]
zfs/lib/libuutil/uu_avl.c [new file with mode: 0644]
zfs/lib/libuutil/uu_dprintf.c [new file with mode: 0644]
zfs/lib/libuutil/uu_ident.c [new file with mode: 0644]
zfs/lib/libuutil/uu_list.c [new file with mode: 0644]
zfs/lib/libuutil/uu_misc.c [new file with mode: 0644]
zfs/lib/libuutil/uu_open.c [new file with mode: 0644]
zfs/lib/libuutil/uu_pname.c [new file with mode: 0644]
zfs/lib/libuutil/uu_string.c [new file with mode: 0644]
zfs/lib/libuutil/uu_strtoint.c [new file with mode: 0644]
zfs/lib/libzfs/Makefile.am [new file with mode: 0644]
zfs/lib/libzfs/Makefile.in [deleted file]
zfs/lib/libzfs/libzfs.pc.in
zfs/lib/libzfs/libzfs_changelist.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_config.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_core.pc.in
zfs/lib/libzfs/libzfs_dataset.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_diff.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_fru.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_import.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_iter.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_mount.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_pool.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_sendrecv.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_status.c [new file with mode: 0644]
zfs/lib/libzfs/libzfs_util.c [new file with mode: 0644]
zfs/lib/libzfs_core/Makefile.am [new file with mode: 0644]
zfs/lib/libzfs_core/Makefile.in [deleted file]
zfs/lib/libzfs_core/libzfs_core.c [new file with mode: 0644]
zfs/lib/libzpool/Makefile.am [new file with mode: 0644]
zfs/lib/libzpool/Makefile.in [deleted file]
zfs/lib/libzpool/kernel.c [new file with mode: 0644]
zfs/lib/libzpool/taskq.c [new file with mode: 0644]
zfs/lib/libzpool/util.c [new file with mode: 0644]
zfs/man/Makefile.am [new file with mode: 0644]
zfs/man/Makefile.in [deleted file]
zfs/man/man1/Makefile.am [new file with mode: 0644]
zfs/man/man1/Makefile.in [deleted file]
zfs/man/man1/cstyle.1 [new file with mode: 0644]
zfs/man/man1/raidz_test.1 [new file with mode: 0644]
zfs/man/man1/zhack.1 [new file with mode: 0644]
zfs/man/man1/zpios.1 [new file with mode: 0644]
zfs/man/man1/ztest.1 [new file with mode: 0644]
zfs/man/man5/Makefile.am [new file with mode: 0644]
zfs/man/man5/Makefile.in [deleted file]
zfs/man/man5/vdev_id.conf.5 [new file with mode: 0644]
zfs/man/man5/zfs-events.5 [new file with mode: 0644]
zfs/man/man5/zfs-module-parameters.5 [new file with mode: 0644]
zfs/man/man5/zpool-features.5 [new file with mode: 0644]
zfs/man/man8/Makefile.am [new file with mode: 0644]
zfs/man/man8/Makefile.in [deleted file]
zfs/man/man8/fsck.zfs.8 [new file with mode: 0644]
zfs/man/man8/mount.zfs.8 [new file with mode: 0644]
zfs/man/man8/vdev_id.8 [new file with mode: 0644]
zfs/man/man8/zdb.8 [new file with mode: 0644]
zfs/man/man8/zed.8.in
zfs/man/man8/zfs.8 [new file with mode: 0644]
zfs/man/man8/zinject.8 [new file with mode: 0644]
zfs/man/man8/zpool.8 [new file with mode: 0644]
zfs/man/man8/zstreamdump.8 [new file with mode: 0644]
zfs/module/Makefile.in
zfs/module/avl/avl.c
zfs/module/icp/Makefile.in [new file with mode: 0644]
zfs/module/icp/algs/aes/aes_impl.c [new file with mode: 0644]
zfs/module/icp/algs/aes/aes_modes.c [new file with mode: 0644]
zfs/module/icp/algs/edonr/edonr.c [new file with mode: 0644]
zfs/module/icp/algs/edonr/edonr_byteorder.h [new file with mode: 0644]
zfs/module/icp/algs/modes/cbc.c [new file with mode: 0644]
zfs/module/icp/algs/modes/ccm.c [new file with mode: 0644]
zfs/module/icp/algs/modes/ctr.c [new file with mode: 0644]
zfs/module/icp/algs/modes/ecb.c [new file with mode: 0644]
zfs/module/icp/algs/modes/gcm.c [new file with mode: 0644]
zfs/module/icp/algs/modes/modes.c [new file with mode: 0644]
zfs/module/icp/algs/sha1/sha1.c [new file with mode: 0644]
zfs/module/icp/algs/sha2/sha2.c [new file with mode: 0644]
zfs/module/icp/algs/skein/THIRDPARTYLICENSE [new file with mode: 0644]
zfs/module/icp/algs/skein/THIRDPARTYLICENSE.descrip [new file with mode: 0644]
zfs/module/icp/algs/skein/skein.c [new file with mode: 0644]
zfs/module/icp/algs/skein/skein_block.c [new file with mode: 0644]
zfs/module/icp/algs/skein/skein_impl.h [new file with mode: 0644]
zfs/module/icp/algs/skein/skein_iv.c [new file with mode: 0644]
zfs/module/icp/algs/skein/skein_port.h [new file with mode: 0644]
zfs/module/icp/api/kcf_cipher.c [new file with mode: 0644]
zfs/module/icp/api/kcf_ctxops.c [new file with mode: 0644]
zfs/module/icp/api/kcf_digest.c [new file with mode: 0644]
zfs/module/icp/api/kcf_mac.c [new file with mode: 0644]
zfs/module/icp/api/kcf_miscapi.c [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman.descrip [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl.descrip [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/aes_amd64.S [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/aes_intel.S [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/aeskey.c [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/aesopt.h [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/aestab.h [new file with mode: 0644]
zfs/module/icp/asm-x86_64/aes/aestab2.h [new file with mode: 0644]
zfs/module/icp/asm-x86_64/modes/gcm_intel.S [new file with mode: 0644]
zfs/module/icp/asm-x86_64/sha1/sha1-x86_64.S [new file with mode: 0644]
zfs/module/icp/asm-x86_64/sha2/sha256_impl.S [new file with mode: 0644]
zfs/module/icp/asm-x86_64/sha2/sha512_impl.S [new file with mode: 0644]
zfs/module/icp/core/kcf_callprov.c [new file with mode: 0644]
zfs/module/icp/core/kcf_mech_tabs.c [new file with mode: 0644]
zfs/module/icp/core/kcf_prov_lib.c [new file with mode: 0644]
zfs/module/icp/core/kcf_prov_tabs.c [new file with mode: 0644]
zfs/module/icp/core/kcf_sched.c [new file with mode: 0644]
zfs/module/icp/illumos-crypto.c [new file with mode: 0644]
zfs/module/icp/include/aes/aes_impl.h [new file with mode: 0644]
zfs/module/icp/include/modes/modes.h [new file with mode: 0644]
zfs/module/icp/include/sha1/sha1.h [new file with mode: 0644]
zfs/module/icp/include/sha1/sha1_consts.h [new file with mode: 0644]
zfs/module/icp/include/sha1/sha1_impl.h [new file with mode: 0644]
zfs/module/icp/include/sha2/sha2_consts.h [new file with mode: 0644]
zfs/module/icp/include/sha2/sha2_impl.h [new file with mode: 0644]
zfs/module/icp/include/sys/asm_linkage.h [new file with mode: 0644]
zfs/module/icp/include/sys/bitmap.h [new file with mode: 0644]
zfs/module/icp/include/sys/crypto/elfsign.h [new file with mode: 0644]
zfs/module/icp/include/sys/crypto/impl.h [new file with mode: 0644]
zfs/module/icp/include/sys/crypto/ioctl.h [new file with mode: 0644]
zfs/module/icp/include/sys/crypto/ioctladmin.h [new file with mode: 0644]
zfs/module/icp/include/sys/crypto/ops_impl.h [new file with mode: 0644]
zfs/module/icp/include/sys/crypto/sched_impl.h [new file with mode: 0644]
zfs/module/icp/include/sys/crypto/spi.h [new file with mode: 0644]
zfs/module/icp/include/sys/ia32/asm_linkage.h [new file with mode: 0644]
zfs/module/icp/include/sys/ia32/stack.h [new file with mode: 0644]
zfs/module/icp/include/sys/ia32/trap.h [new file with mode: 0644]
zfs/module/icp/include/sys/modctl.h [new file with mode: 0644]
zfs/module/icp/include/sys/modhash.h [new file with mode: 0644]
zfs/module/icp/include/sys/modhash_impl.h [new file with mode: 0644]
zfs/module/icp/include/sys/stack.h [new file with mode: 0644]
zfs/module/icp/include/sys/trap.h [new file with mode: 0644]
zfs/module/icp/io/aes.c [new file with mode: 0644]
zfs/module/icp/io/edonr_mod.c [new file with mode: 0644]
zfs/module/icp/io/sha1_mod.c [new file with mode: 0644]
zfs/module/icp/io/sha2_mod.c [new file with mode: 0644]
zfs/module/icp/io/skein_mod.c [new file with mode: 0644]
zfs/module/icp/os/modconf.c [new file with mode: 0644]
zfs/module/icp/os/modhash.c [new file with mode: 0644]
zfs/module/icp/spi/kcf_spi.c [new file with mode: 0644]
zfs/module/nvpair/nvpair.c
zfs/module/unicode/u8_textprep.c
zfs/module/zcommon/Makefile.in
zfs/module/zcommon/zfs_comutil.c
zfs/module/zcommon/zfs_deleg.c
zfs/module/zcommon/zfs_fletcher.c
zfs/module/zcommon/zfs_fletcher_aarch64_neon.c [new file with mode: 0644]
zfs/module/zcommon/zfs_fletcher_avx512.c [new file with mode: 0644]
zfs/module/zcommon/zfs_fletcher_intel.c [new file with mode: 0644]
zfs/module/zcommon/zfs_fletcher_sse.c [new file with mode: 0644]
zfs/module/zcommon/zfs_namecheck.c
zfs/module/zcommon/zfs_prop.c
zfs/module/zcommon/zfs_uio.c
zfs/module/zcommon/zpool_prop.c
zfs/module/zfs/Makefile.in
zfs/module/zfs/arc.c
zfs/module/zfs/bptree.c
zfs/module/zfs/bqueue.c [new file with mode: 0644]
zfs/module/zfs/dbuf.c
zfs/module/zfs/dbuf_stats.c
zfs/module/zfs/ddt.c
zfs/module/zfs/dmu.c
zfs/module/zfs/dmu_diff.c
zfs/module/zfs/dmu_object.c
zfs/module/zfs/dmu_objset.c
zfs/module/zfs/dmu_send.c
zfs/module/zfs/dmu_traverse.c
zfs/module/zfs/dmu_tx.c
zfs/module/zfs/dmu_zfetch.c
zfs/module/zfs/dnode.c
zfs/module/zfs/dnode_sync.c
zfs/module/zfs/dsl_bookmark.c
zfs/module/zfs/dsl_dataset.c
zfs/module/zfs/dsl_deadlist.c
zfs/module/zfs/dsl_deleg.c
zfs/module/zfs/dsl_destroy.c
zfs/module/zfs/dsl_dir.c
zfs/module/zfs/dsl_pool.c [changed mode: 0755->0644]
zfs/module/zfs/dsl_prop.c
zfs/module/zfs/dsl_scan.c
zfs/module/zfs/dsl_userhold.c
zfs/module/zfs/edonr_zfs.c [new file with mode: 0644]
zfs/module/zfs/fm.c
zfs/module/zfs/metaslab.c
zfs/module/zfs/multilist.c
zfs/module/zfs/pathname.c [new file with mode: 0644]
zfs/module/zfs/policy.c [new file with mode: 0644]
zfs/module/zfs/range_tree.c
zfs/module/zfs/refcount.c
zfs/module/zfs/sa.c
zfs/module/zfs/sha256.c
zfs/module/zfs/skein_zfs.c [new file with mode: 0644]
zfs/module/zfs/spa.c
zfs/module/zfs/spa_config.c
zfs/module/zfs/spa_history.c
zfs/module/zfs/spa_misc.c
zfs/module/zfs/spa_stats.c
zfs/module/zfs/space_map.c
zfs/module/zfs/space_reftree.c
zfs/module/zfs/trace.c
zfs/module/zfs/txg.c
zfs/module/zfs/unique.c
zfs/module/zfs/vdev.c
zfs/module/zfs/vdev_cache.c
zfs/module/zfs/vdev_disk.c
zfs/module/zfs/vdev_file.c
zfs/module/zfs/vdev_label.c
zfs/module/zfs/vdev_mirror.c
zfs/module/zfs/vdev_queue.c
zfs/module/zfs/vdev_raidz.c
zfs/module/zfs/vdev_raidz_math.c [new file with mode: 0644]
zfs/module/zfs/vdev_raidz_math_aarch64_neon.c [new file with mode: 0644]
zfs/module/zfs/vdev_raidz_math_aarch64_neon_common.h [new file with mode: 0644]
zfs/module/zfs/vdev_raidz_math_aarch64_neonx2.c [new file with mode: 0644]
zfs/module/zfs/vdev_raidz_math_avx2.c [new file with mode: 0644]
zfs/module/zfs/vdev_raidz_math_impl.h [new file with mode: 0644]
zfs/module/zfs/vdev_raidz_math_scalar.c [new file with mode: 0644]
zfs/module/zfs/vdev_raidz_math_sse2.c [new file with mode: 0644]
zfs/module/zfs/vdev_raidz_math_ssse3.c [new file with mode: 0644]
zfs/module/zfs/zap.c
zfs/module/zfs/zap_micro.c
zfs/module/zfs/zfeature.c
zfs/module/zfs/zfeature_common.c
zfs/module/zfs/zfs_acl.c
zfs/module/zfs/zfs_ctldir.c
zfs/module/zfs/zfs_dir.c
zfs/module/zfs/zfs_fm.c
zfs/module/zfs/zfs_fuid.c
zfs/module/zfs/zfs_ioctl.c
zfs/module/zfs/zfs_log.c
zfs/module/zfs/zfs_replay.c
zfs/module/zfs/zfs_rlock.c
zfs/module/zfs/zfs_sa.c
zfs/module/zfs/zfs_vfsops.c
zfs/module/zfs/zfs_vnops.c
zfs/module/zfs/zfs_znode.c
zfs/module/zfs/zil.c
zfs/module/zfs/zio.c
zfs/module/zfs/zio_checksum.c
zfs/module/zfs/zio_inject.c
zfs/module/zfs/zpl_ctldir.c
zfs/module/zfs/zpl_file.c
zfs/module/zfs/zpl_inode.c
zfs/module/zfs/zpl_xattr.c
zfs/module/zfs/zvol.c
zfs/module/zpios/pios.c
zfs/rpm/Makefile.am [new file with mode: 0644]
zfs/rpm/Makefile.in [deleted file]
zfs/rpm/generic/Makefile.am [new file with mode: 0644]
zfs/rpm/generic/Makefile.in [deleted file]
zfs/rpm/generic/zfs-dkms.spec.in
zfs/rpm/generic/zfs-kmod.spec.in
zfs/rpm/generic/zfs.spec.in
zfs/rpm/redhat/Makefile.am [new file with mode: 0644]
zfs/rpm/redhat/Makefile.in [deleted file]
zfs/rpm/redhat/zfs-dkms.spec.in [changed from file to symlink]
zfs/rpm/redhat/zfs-kmod.spec.in
zfs/rpm/redhat/zfs.spec.in [changed from file to symlink]
zfs/scripts/.gitignore [new file with mode: 0644]
zfs/scripts/Makefile.am [new file with mode: 0644]
zfs/scripts/Makefile.in [deleted file]
zfs/scripts/common.sh.in
zfs/scripts/cstyle.pl [new file with mode: 0755]
zfs/scripts/dkms.mkconf [new file with mode: 0755]
zfs/scripts/dkms.postbuild [new file with mode: 0755]
zfs/scripts/kmodtool [new file with mode: 0755]
zfs/scripts/smb.sh [new file with mode: 0755]
zfs/scripts/zconfig.sh [new file with mode: 0755]
zfs/scripts/zfs-helpers.sh [new file with mode: 0755]
zfs/scripts/zfs-tests.sh [new file with mode: 0755]
zfs/scripts/zfs.sh [new file with mode: 0755]
zfs/scripts/zfs2zol-patch.sed [new file with mode: 0755]
zfs/scripts/ziltest.sh [new file with mode: 0755]
zfs/scripts/zimport.sh [new file with mode: 0755]
zfs/scripts/zloop.sh [new file with mode: 0755]
zfs/scripts/zol2zfs-patch.sed [new file with mode: 0755]
zfs/scripts/zpios-profile/Makefile.am [new file with mode: 0644]
zfs/scripts/zpios-profile/Makefile.in [deleted file]
zfs/scripts/zpios-profile/zpios-profile-disk.sh [new file with mode: 0755]
zfs/scripts/zpios-profile/zpios-profile-pids.sh [new file with mode: 0755]
zfs/scripts/zpios-profile/zpios-profile-post.sh [new file with mode: 0755]
zfs/scripts/zpios-profile/zpios-profile-pre.sh [new file with mode: 0755]
zfs/scripts/zpios-profile/zpios-profile.sh [new file with mode: 0755]
zfs/scripts/zpios-sanity.sh [new file with mode: 0755]
zfs/scripts/zpios-survey.sh [new file with mode: 0755]
zfs/scripts/zpios-test/16th-8192rc-4rs-1cs-4off.sh [new file with mode: 0755]
zfs/scripts/zpios-test/1th-16rc-4rs-1cs-4off.sh [new file with mode: 0755]
zfs/scripts/zpios-test/1x256th-65536rc-4rs-1cs-4off.sh [new file with mode: 0755]
zfs/scripts/zpios-test/256th-65536rc-4rs-1cs-4off.sh [new file with mode: 0755]
zfs/scripts/zpios-test/4th-1024rc-4rs-1cs-4off.sh [new file with mode: 0755]
zfs/scripts/zpios-test/Makefile.am [new file with mode: 0644]
zfs/scripts/zpios-test/Makefile.in [deleted file]
zfs/scripts/zpios-test/large-thread-survey.sh [new symlink]
zfs/scripts/zpios-test/large.sh [new symlink]
zfs/scripts/zpios-test/lustre.sh [new file with mode: 0644]
zfs/scripts/zpios-test/medium.sh [new symlink]
zfs/scripts/zpios-test/small.sh [new symlink]
zfs/scripts/zpios-test/tiny.sh [new symlink]
zfs/scripts/zpios.sh [new file with mode: 0755]
zfs/scripts/zpool-config/Makefile.am [new file with mode: 0644]
zfs/scripts/zpool-config/Makefile.in [deleted file]
zfs/scripts/zpool-config/dm0-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/file-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/file-raid10.sh [new file with mode: 0644]
zfs/scripts/zpool-config/file-raidz.sh [new file with mode: 0644]
zfs/scripts/zpool-config/file-raidz2.sh [new file with mode: 0644]
zfs/scripts/zpool-config/hda-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-faulty-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-faulty-raid10.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-faulty-raidz.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-faulty-raidz2.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-faulty-raidz3.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-raid10.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-raidz.sh [new file with mode: 0644]
zfs/scripts/zpool-config/lo-raidz2.sh [new file with mode: 0644]
zfs/scripts/zpool-config/md0-raid10.sh [new file with mode: 0644]
zfs/scripts/zpool-config/md0-raid5.sh [new file with mode: 0644]
zfs/scripts/zpool-config/ram0-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/scsi_debug-noraid.sh [new file with mode: 0644]
zfs/scripts/zpool-config/scsi_debug-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/scsi_debug-raid10.sh [new file with mode: 0644]
zfs/scripts/zpool-config/scsi_debug-raidz.sh [new file with mode: 0644]
zfs/scripts/zpool-config/scsi_debug-raidz2.sh [new file with mode: 0644]
zfs/scripts/zpool-config/scsi_debug-raidz3.sh [new file with mode: 0644]
zfs/scripts/zpool-config/sda-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/zpool-raid0.sh [new file with mode: 0644]
zfs/scripts/zpool-config/zpool-raid10.sh [new file with mode: 0644]
zfs/scripts/zpool-config/zpool-raidz.sh [new file with mode: 0644]
zfs/scripts/zpool-create.sh [new file with mode: 0755]
zfs/tests/Makefile.am [new file with mode: 0644]
zfs/tests/README.md [new file with mode: 0644]
zfs/tests/runfiles/Makefile.am [new file with mode: 0644]
zfs/tests/runfiles/linux.run [new file with mode: 0644]
zfs/tests/runfiles/perf-regression.run [new file with mode: 0644]
zfs/tests/test-runner/Makefile.am [new file with mode: 0644]
zfs/tests/test-runner/cmd/Makefile.am [new file with mode: 0644]
zfs/tests/test-runner/cmd/test-runner.py [new file with mode: 0755]
zfs/tests/test-runner/include/Makefile.am [new file with mode: 0644]
zfs/tests/test-runner/include/logapi.shlib [new file with mode: 0644]
zfs/tests/test-runner/include/stf.shlib [new file with mode: 0644]
zfs/tests/test-runner/man/Makefile.am [new file with mode: 0644]
zfs/tests/test-runner/man/test-runner.1 [new file with mode: 0644]
zfs/tests/zfs-tests/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/chg_usr_exec/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/chg_usr_exec/chg_usr_exec.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/devname2devid/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/devname2devid/devname2devid.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/dir_rd_update/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/dir_rd_update/dir_rd_update.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/file_check/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/file_check/file_check.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/file_common.h [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/file_trunc/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/file_trunc/file_trunc.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/file_write/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/file_write/file_write.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/largest_file/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/largest_file/largest_file.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mkbusy/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mkbusy/mkbusy.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mkfile/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mkfile/mkfile.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mkfiles/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mkfiles/mkfiles.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mktree/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mktree/mktree.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mmap_exec/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mmap_exec/mmap_exec.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mmapwrite/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/mmapwrite/mmapwrite.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/randfree_file/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/randfree_file/randfree_file.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/readmmap/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/readmmap/readmmap.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/rename_dir/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/rename_dir/rename_dir.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/rm_lnkcnt_zero_file/rm_lnkcnt_zero_file.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/threadsappend/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/threadsappend/threadsappend.c [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/xattrtest/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/cmd/xattrtest/xattrtest.c [new file with mode: 0644]
zfs/tests/zfs-tests/include/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/include/commands.cfg.in [new file with mode: 0644]
zfs/tests/zfs-tests/include/default.cfg.in [new file with mode: 0644]
zfs/tests/zfs-tests/include/libtest.shlib [new file with mode: 0644]
zfs/tests/zfs-tests/include/math.shlib [new file with mode: 0644]
zfs/tests/zfs-tests/include/properties.shlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/acl/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/acl/acl.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/acl/acl_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/acl/posix/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/acl/posix/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/acl/posix/posix_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/acl/posix/posix_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/acl/posix/posix_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/acl/posix/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/atime/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/atime/atime.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/atime/atime_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/atime/atime_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/atime/atime_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/atime/atime_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/atime/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/atime/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_007_pos.ksh [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/bootfs/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cache/cache.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cache/cache.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cache/cache_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cache_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cache/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cachefile/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cachefile/cachefile.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cachefile/cachefile.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/casenorm/case_all_values.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/casenorm.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/casenorm/casenorm.kshlib [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_formd_delete.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_formd_lookup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_none_delete.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_none_lookup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_delete.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_lookup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_lookup_ci.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_delete.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_lookup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_lookup_ci.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/norm_all_values.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_formd_delete.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_formd_lookup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_none_delete.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_none_lookup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/casenorm/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/checksum/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/checksum/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/checksum/default.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/checksum/edonr_test.c [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/checksum/filetest_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/checksum/run_edonr_test.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/checksum/run_sha2_test.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/checksum/run_skein_test.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/checksum/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/checksum/sha2_test.c [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/checksum/skein_test.c [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/clean_mirror/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/clean_mirror/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/clean_mirror/default.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/clean_mirror/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/cli_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zdb/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/properties.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_012_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_013_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_006_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_012_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_013_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_014_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_015_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_016_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_006_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_011_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_all_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_006_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/zfs_written_property_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_012_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_013_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_012_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_013_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/zfs_reservation_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/zfs_reservation_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cache_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cache_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/checksum_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/compression_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/onoffs_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/property_alias_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/readonly_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/reservation_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/ro_props_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/share_mount_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/snapdir_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/version_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_all_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_006_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/zpool_attach_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_011_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_012_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_014_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_015_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_016_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_017_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_018_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_019_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_020_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_021_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_022_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_023_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_024_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/zpool_detach_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/zpool_history_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/zpool_history_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_011_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_012_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_013_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_all_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_rename_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/zpool_offline_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/zpool_offline_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/zpool_online_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/zpool_online_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/zpool_replace_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_006_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/arcstat_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/dbufstat_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/misc.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zdb_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_allow_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_clone_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_create_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_destroy_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_get_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_inherit_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_mount_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_promote_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_receive_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_rename_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_rollback_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_send_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_set_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_share_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_snapshot_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unallow_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unmount_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unshare_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_upgrade_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_add_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_attach_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_clear_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_create_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_destroy_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_detach_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_export_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_get_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_history_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_import_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_import_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_offline_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_online_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_remove_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_replace_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_scrub_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_set_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_status_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_upgrade_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/zpool_list_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/zpool_list_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/compression/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/compression/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/compression/compress.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/compression/compress_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/compression/compress_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/compression/compress_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/compression/compress_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/compression/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/ctime/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/ctime/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/ctime/ctime_001_pos.c [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/ctime/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/delegate/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/delegate.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/delegate/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_011_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_012_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/devices/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/devices/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/devices/devices.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/devices/devices_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/devices/devices_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/devices/devices_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/devices/devices_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/devices/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/exec/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/exec/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/exec/exec_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/exec/exec_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/exec/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/features/async_destroy/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/features/async_destroy/async_destroy_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/async_destroy/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/async_destroy/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/features/large_dnode/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/grow_pool/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/grow_pool/grow_pool.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/grow_pool/grow_pool_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/grow_replicas/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/grow_replicas/grow_replicas.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/grow_replicas/grow_replicas_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/history/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/history/history_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_006_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/history_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/history/i386.migratedpool.DAT.Z [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/history/i386.orig_history.txt [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/history/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/history/sparc.migratedpool.DAT.Z [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/history/sparc.orig_history.txt [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/history/zfs-pool-v4.dat.Z [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/README.config [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/README.state [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inheritance/config001.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config002.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config003.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config004.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config005.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config006.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config007.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config008.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config009.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config010.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config011.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config012.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config013.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config014.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config015.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config016.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config017.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config018.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config019.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config020.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config021.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config022.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config023.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/config024.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/inherit.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inheritance/state001.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state002.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state003.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state004.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state005.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state006.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state007.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state008.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state009.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state010.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state011.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state012.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state013.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state014.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state015.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state016.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state017.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state018.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state019.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state020.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state021.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state022.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state023.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inheritance/state024.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inuse/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inuse/inuse.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/inuse/inuse_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inuse/inuse_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inuse/inuse_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inuse/inuse_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inuse/inuse_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inuse/inuse_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inuse/inuse_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inuse/inuse_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/inuse/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/large_files/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/large_files/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/large_files/large_files_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/large_files/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/largest_pool/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/largest_pool/largest_pool.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/largest_pool/largest_pool_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/link_count/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/link_count/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/link_count/link_count_001.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/link_count/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/migration/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/migration/migration.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/migration/migration_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/migration_012_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/migration/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mmap/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/mmap/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mmap/mmap.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/mmap/mmap_read_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mmap/mmap_write_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mmap/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mount/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/mount/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mount/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mount/umount_001.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mount/umountall_001.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mv_files/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/mv_files/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mv_files/mv_files.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/mv_files/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nestedfs/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/nestedfs/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nestedfs/nestedfs_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nestedfs/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/no_space/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/no_space/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/no_space/enospc.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/no_space/enospc_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/no_space/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/nopwrite/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite.shlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_copies.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_mtime.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_negative.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_promoted_clone.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_recsize.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_sync.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_varying_compression.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_volume.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/nopwrite/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/online_offline/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/online_offline/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/online_offline/online_offline.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/online_offline/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/pool_names/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/pool_names/pool_names_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/pool_names/pool_names_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/poolversion/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/poolversion/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/poolversion/poolversion_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/poolversion/poolversion_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/poolversion/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/privilege/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/privilege/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/privilege/privilege_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/privilege/privilege_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/privilege/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/quota/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/quota/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/quota/quota.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/quota/quota.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/quota/quota_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/quota/quota_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/quota/quota_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/quota/quota_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/quota/quota_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/quota/quota_006_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/quota/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/raidz/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/raidz/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/raidz/raidz_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/raidz/raidz_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/raidz/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/redundancy/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/redundancy/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/redundancy/redundancy.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_004_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/redundancy/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refquota/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/refquota/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refquota/refquota_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refquota/refquota_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refquota/refquota_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refquota/refquota_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refquota/refquota_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refquota/refquota_006_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refquota/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refreserv/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/refreserv/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refreserv/refreserv.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/refreserv/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rename_dirs/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/rename_dirs/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rename_dirs/rename_dirs_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rename_dirs/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/replacement/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/replacement/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/replacement/replacement.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/replacement/replacement_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/replacement/replacement_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/replacement/replacement_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/replacement/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/reservation/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/reservation/reservation.shlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_001_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_002_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_003_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_004_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_005_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_006_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_007_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_008_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_009_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_010_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_011_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_012_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_013_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_014_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_015_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_016_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_017_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/reservation_018_pos.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/reservation/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rootpool/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/rootpool/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rootpool/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/rsend/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/rsend/rsend.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_012_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_013_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_014_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_019_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_020_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_021_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_022_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/rsend_024_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/rsend/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/default.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/scrub_mirror/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/slog/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/slog/slog.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/slog/slog_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_008_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_011_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_012_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_013_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/slog/slog_014_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/snapshot/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/clone_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/rollback_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/rollback_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/rollback_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_012_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_013_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_014_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_015_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_016_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_017_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapused/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/snapused/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapused/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapused/snapused.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/snapused/snapused_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapused/snapused_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapused/snapused_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapused/snapused_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/snapused/snapused_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/sparse/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/sparse/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/sparse/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/sparse/sparse.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/sparse/sparse_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/threadsappend/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/threadsappend/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/threadsappend/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/threadsappend/threadsappend_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/truncate/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/truncate/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/truncate/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/truncate/truncate.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/truncate/truncate_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/truncate/truncate_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/upgrade/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/upgrade/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/upgrade/upgrade_userobj_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/userquota/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/groupspace_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/groupspace_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/groupspace_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_009_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_010_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_012_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_013_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userquota_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/userquota/userspace_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userspace_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/userquota/userspace_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_007_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/write_dirs/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/write_dirs/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/write_dirs/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/xattr/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_002_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_007_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_008_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_009_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_010_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_011_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_012_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_013_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/xattr/xattr_common.kshlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/zvol_ENOSPC.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/zvol_ENOSPC_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_common.shlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_001_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_003_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_005_neg.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/cleanup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap.cfg [new file with mode: 0644]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_001_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_002_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_003_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_004_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_005_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_006_pos.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/fio/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/fio/mkfiles.fio [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/fio/random_reads.fio [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/fio/random_readwrite.fio [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/fio/random_writes.fio [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/fio/sequential_reads.fio [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/fio/sequential_writes.fio [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/perf.shlib [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/regression/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/regression/random_reads.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/regression/random_readwrite.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/regression/random_writes.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/regression/sequential_reads.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/regression/sequential_reads_cached.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/regression/sequential_reads_cached_clone.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/regression/sequential_writes.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/regression/setup.ksh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/perf/scripts/Makefile.am [new file with mode: 0644]
zfs/tests/zfs-tests/tests/perf/scripts/prefetch_io.sh [new file with mode: 0755]
zfs/tests/zfs-tests/tests/stress/Makefile.am [new file with mode: 0644]
zfs/udev/Makefile.am [new file with mode: 0644]
zfs/udev/Makefile.in [deleted file]
zfs/udev/rules.d/60-zvol.rules.in
zfs/udev/rules.d/69-vdev.rules.in
zfs/udev/rules.d/90-zfs.rules.in
zfs/udev/rules.d/Makefile.am [new file with mode: 0644]
zfs/udev/rules.d/Makefile.in [deleted file]
zfs/zfs-script-config.sh.in
zfs/zfs_config.h.in [deleted file]

index d4e82c2bfa8ad20d3001c3a5ae95fe5c46b88951..386f15114e530462bed478054b8477b81be05afe 100644 (file)
--- a/zfs/META
+++ b/zfs/META
@@ -1,8 +1,8 @@
 Meta:         1
 Name:         zfs
 Branch:       1.0
-Version:      0.6.5.8
-Release:      0ubuntu1
+Version:      0.7.0
+Release:      rc1
 Release-Tags: relext
 License:      CDDL
 Author:       OpenZFS on Linux
index eacc76a8cde32d8e3ef807389c1d1670908c5cd1..26f684d5923b3becd27af896e93c36c0b7860f18 100644 (file)
@@ -6,7 +6,7 @@ include config/tgz.am
 
 SUBDIRS = include rpm
 if CONFIG_USER
-SUBDIRS += udev etc man scripts lib cmd contrib
+SUBDIRS += udev etc man scripts lib tests cmd contrib
 endif
 if CONFIG_KERNEL
 SUBDIRS += module
@@ -39,7 +39,7 @@ dist-hook:
        sed -i 's/Release:[[:print:]]*/Release:      $(RELEASE)/' \
                $(distdir)/META
 
-checkstyle: cstyle shellcheck
+checkstyle: cstyle shellcheck flake8
 
 cstyle:
        @find ${top_srcdir} -name '*.[hc]' ! -name 'zfs_config.*' \
@@ -59,7 +59,12 @@ lint: cppcheck
 
 cppcheck:
        @if type cppcheck > /dev/null 2>&1; then \
-               cppcheck --quiet --force ${top_srcdir}; \
+               cppcheck --quiet --force --error-exitcode=2 ${top_srcdir}; \
+       fi
+
+flake8:
+       @if type flake8 > /dev/null 2>&1; then \
+               flake8 ${top_srcdir}; \
        fi
 
 ctags:
diff --git a/zfs/Makefile.in b/zfs/Makefile.in
deleted file mode 100644 (file)
index 62f1a4c..0000000
+++ /dev/null
@@ -1,1314 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-###############################################################################
-# Copyright (C) 2007-2013 Lawrence Livermore National Security, LLC.
-# Copyright (C) 2007 The Regents of the University of California.
-# Written by Brian Behlendorf <behlendorf1@llnl.gov>.
-###############################################################################
-# Build targets for RPM packages.
-###############################################################################
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-@CONFIG_USER_TRUE@am__append_1 = udev etc man scripts lib cmd contrib
-@CONFIG_KERNEL_TRUE@am__append_2 = module
-subdir = .
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
-       $(am__configure_deps) $(am__extra_HEADERS_DIST) \
-       $(am__DIST_COMMON)
-am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
- configure.lineno config.status.lineno
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = zfs_config.h
-CONFIG_CLEAN_FILES = module/Makefile module/avl/Makefile \
-       module/nvpair/Makefile module/unicode/Makefile \
-       module/zcommon/Makefile module/zfs/Makefile \
-       module/zpios/Makefile zfs-script-config.sh zfs.release
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-       ctags-recursive dvi-recursive html-recursive info-recursive \
-       install-data-recursive install-dvi-recursive \
-       install-exec-recursive install-html-recursive \
-       install-info-recursive install-pdf-recursive \
-       install-ps-recursive install-recursive installcheck-recursive \
-       installdirs-recursive pdf-recursive ps-recursive \
-       tags-recursive uninstall-recursive
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__extra_HEADERS_DIST = zfs.release.in zfs_config.h.in
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(extradir)" "$(DESTDIR)$(kerneldir)"
-HEADERS = $(extra_HEADERS) $(nodist_kernel_HEADERS)
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-       cscope distdir dist dist-all distcheck
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
-       $(LISP)zfs_config.h.in
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-CSCOPE = cscope
-DIST_SUBDIRS = include rpm udev etc man scripts lib cmd contrib module
-am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config/deb.am \
-       $(srcdir)/config/rpm.am $(srcdir)/config/tgz.am \
-       $(srcdir)/zfs-script-config.sh.in $(srcdir)/zfs.release.in \
-       $(srcdir)/zfs_config.h.in $(top_srcdir)/config/compile \
-       $(top_srcdir)/config/config.guess \
-       $(top_srcdir)/config/config.sub \
-       $(top_srcdir)/config/install-sh $(top_srcdir)/config/ltmain.sh \
-       $(top_srcdir)/config/missing $(top_srcdir)/module/Makefile.in \
-       $(top_srcdir)/module/avl/Makefile.in \
-       $(top_srcdir)/module/nvpair/Makefile.in \
-       $(top_srcdir)/module/unicode/Makefile.in \
-       $(top_srcdir)/module/zcommon/Makefile.in \
-       $(top_srcdir)/module/zfs/Makefile.in \
-       $(top_srcdir)/module/zpios/Makefile.in AUTHORS config/compile \
-       config/config.guess config/config.sub config/install-sh \
-       config/ltmain.sh config/missing
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-distdir = $(PACKAGE)-$(VERSION)
-top_distdir = $(distdir)
-am__remove_distdir = \
-  if test -d "$(distdir)"; then \
-    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
-      && rm -rf "$(distdir)" \
-      || { sleep 5 && rm -rf "$(distdir)"; }; \
-  else :; fi
-am__post_remove_distdir = $(am__remove_distdir)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
-DIST_ARCHIVES = $(distdir).tar.gz
-GZIP_ENV = --best
-DIST_TARGETS = dist-gzip
-distuninstallcheck_listfiles = find . -type f -print
-am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
-  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
-distcleancheck_listfiles = find . -type f -print
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-ACLOCAL_AMFLAGS = -I config
-SUBDIRS = include rpm $(am__append_1) $(am__append_2)
-@CONFIG_KERNEL_TRUE@extradir = @prefix@/src/zfs-$(VERSION)
-@CONFIG_KERNEL_TRUE@extra_HEADERS = zfs.release.in zfs_config.h.in
-@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/zfs-$(VERSION)/$(LINUX_VERSION)
-@CONFIG_KERNEL_TRUE@nodist_kernel_HEADERS = zfs.release zfs_config.h module/$(LINUX_SYMBOLS)
-AUTOMAKE_OPTIONS = foreign
-EXTRA_DIST = autogen.sh copy-builtin config/config.awk config/rpm.am \
-       config/deb.am config/tgz.am META DISCLAIMER COPYRIGHT \
-       README.markdown OPENSOLARIS.LICENSE
-all: zfs_config.h
-       $(MAKE) $(AM_MAKEFLAGS) all-recursive
-
-.SUFFIXES:
-am--refresh: Makefile
-       @:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/config/rpm.am $(srcdir)/config/deb.am $(srcdir)/config/tgz.am $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
-             $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
-               && exit 0; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --foreign Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           echo ' $(SHELL) ./config.status'; \
-           $(SHELL) ./config.status;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
-       esac;
-$(srcdir)/config/rpm.am $(srcdir)/config/deb.am $(srcdir)/config/tgz.am $(am__empty):
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       $(SHELL) ./config.status --recheck
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       $(am__cd) $(srcdir) && $(AUTOCONF)
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
-$(am__aclocal_m4_deps):
-
-zfs_config.h: stamp-h1
-       @test -f $@ || rm -f stamp-h1
-       @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
-
-stamp-h1: $(srcdir)/zfs_config.h.in $(top_builddir)/config.status
-       @rm -f stamp-h1
-       cd $(top_builddir) && $(SHELL) ./config.status zfs_config.h
-$(srcdir)/zfs_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
-       ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
-       rm -f stamp-h1
-       touch $@
-
-distclean-hdr:
-       -rm -f zfs_config.h stamp-h1
-module/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/Makefile.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-module/avl/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/avl/Makefile.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-module/nvpair/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/nvpair/Makefile.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-module/unicode/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/unicode/Makefile.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-module/zcommon/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/zcommon/Makefile.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-module/zfs/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/zfs/Makefile.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-module/zpios/Makefile: $(top_builddir)/config.status $(top_srcdir)/module/zpios/Makefile.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-zfs-script-config.sh: $(top_builddir)/config.status $(srcdir)/zfs-script-config.sh.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-zfs.release: $(top_builddir)/config.status $(srcdir)/zfs.release.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-
-distclean-libtool:
-       -rm -f libtool config.lt
-install-extraHEADERS: $(extra_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(extra_HEADERS)'; test -n "$(extradir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(extradir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(extradir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(extradir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(extradir)" || exit $$?; \
-       done
-
-uninstall-extraHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(extra_HEADERS)'; test -n "$(extradir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(extradir)'; $(am__uninstall_files_from_dir)
-install-nodist_kernelHEADERS: $(nodist_kernel_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(nodist_kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(kerneldir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(kerneldir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(kerneldir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(kerneldir)" || exit $$?; \
-       done
-
-uninstall-nodist_kernelHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(nodist_kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(kerneldir)'; $(am__uninstall_files_from_dir)
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-       @fail=; \
-       if $(am__make_keepgoing); then \
-         failcom='fail=yes'; \
-       else \
-         failcom='exit 1'; \
-       fi; \
-       dot_seen=no; \
-       target=`echo $@ | sed s/-recursive//`; \
-       case "$@" in \
-         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-         *) list='$(SUBDIRS)' ;; \
-       esac; \
-       for subdir in $$list; do \
-         echo "Making $$target in $$subdir"; \
-         if test "$$subdir" = "."; then \
-           dot_seen=yes; \
-           local_target="$$target-am"; \
-         else \
-           local_target="$$target"; \
-         fi; \
-         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-         || eval $$failcom; \
-       done; \
-       if test "$$dot_seen" = "no"; then \
-         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-       fi; test -z "$$fail"
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-         include_option=--etags-include; \
-         empty_fix=.; \
-       else \
-         include_option=--include; \
-         empty_fix=; \
-       fi; \
-       list='$(SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           test ! -f $$subdir/TAGS || \
-             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-         fi; \
-       done; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscope: cscope.files
-       test ! -s cscope.files \
-         || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
-clean-cscope:
-       -rm -f cscope.files
-cscope.files: clean-cscope cscopelist
-cscopelist: cscopelist-recursive
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-       -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
-
-distdir: $(DISTFILES)
-       $(am__remove_distdir)
-       test -d "$(distdir)" || mkdir "$(distdir)"
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           $(am__make_dryrun) \
-             || test -d "$(distdir)/$$subdir" \
-             || $(MKDIR_P) "$(distdir)/$$subdir" \
-             || exit 1; \
-           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-           $(am__relativize); \
-           new_distdir=$$reldir; \
-           dir1=$$subdir; dir2="$(top_distdir)"; \
-           $(am__relativize); \
-           new_top_distdir=$$reldir; \
-           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-           ($(am__cd) $$subdir && \
-             $(MAKE) $(AM_MAKEFLAGS) \
-               top_distdir="$$new_top_distdir" \
-               distdir="$$new_distdir" \
-               am__remove_distdir=: \
-               am__skip_length_check=: \
-               am__skip_mode_fix=: \
-               distdir) \
-             || exit 1; \
-         fi; \
-       done
-       $(MAKE) $(AM_MAKEFLAGS) \
-         top_distdir="$(top_distdir)" distdir="$(distdir)" \
-         dist-hook
-       -test -n "$(am__skip_mode_fix)" \
-       || find "$(distdir)" -type d ! -perm -755 \
-               -exec chmod u+rwx,go+rx {} \; -o \
-         ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
-         ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
-         ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
-       || chmod -R a+r "$(distdir)"
-dist-gzip: distdir
-       tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
-       $(am__post_remove_distdir)
-
-dist-bzip2: distdir
-       tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
-       $(am__post_remove_distdir)
-
-dist-lzip: distdir
-       tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
-       $(am__post_remove_distdir)
-
-dist-xz: distdir
-       tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
-       $(am__post_remove_distdir)
-
-dist-tarZ: distdir
-       @echo WARNING: "Support for distribution archives compressed with" \
-                      "legacy program 'compress' is deprecated." >&2
-       @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
-       tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
-       $(am__post_remove_distdir)
-
-dist-shar: distdir
-       @echo WARNING: "Support for shar distribution archives is" \
-                      "deprecated." >&2
-       @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
-       shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
-       $(am__post_remove_distdir)
-
-dist-zip: distdir
-       -rm -f $(distdir).zip
-       zip -rq $(distdir).zip $(distdir)
-       $(am__post_remove_distdir)
-
-dist dist-all:
-       $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
-       $(am__post_remove_distdir)
-
-# This target untars the dist file and tries a VPATH configuration.  Then
-# it guarantees that the distribution is self-contained by making another
-# tarfile.
-distcheck: dist
-       case '$(DIST_ARCHIVES)' in \
-       *.tar.gz*) \
-         GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
-       *.tar.bz2*) \
-         bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
-       *.tar.lz*) \
-         lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
-       *.tar.xz*) \
-         xz -dc $(distdir).tar.xz | $(am__untar) ;;\
-       *.tar.Z*) \
-         uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
-       *.shar.gz*) \
-         GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
-       *.zip*) \
-         unzip $(distdir).zip ;;\
-       esac
-       chmod -R a-w $(distdir)
-       chmod u+w $(distdir)
-       mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
-       chmod a-w $(distdir)
-       test -d $(distdir)/_build || exit 0; \
-       dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
-         && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
-         && am__cwd=`pwd` \
-         && $(am__cd) $(distdir)/_build/sub \
-         && ../../configure \
-           $(AM_DISTCHECK_CONFIGURE_FLAGS) \
-           $(DISTCHECK_CONFIGURE_FLAGS) \
-           --srcdir=../.. --prefix="$$dc_install_base" \
-         && $(MAKE) $(AM_MAKEFLAGS) \
-         && $(MAKE) $(AM_MAKEFLAGS) dvi \
-         && $(MAKE) $(AM_MAKEFLAGS) check \
-         && $(MAKE) $(AM_MAKEFLAGS) install \
-         && $(MAKE) $(AM_MAKEFLAGS) installcheck \
-         && $(MAKE) $(AM_MAKEFLAGS) uninstall \
-         && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
-               distuninstallcheck \
-         && chmod -R a-w "$$dc_install_base" \
-         && ({ \
-              (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
-              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
-              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
-              && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
-                   distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
-             } || { rm -rf "$$dc_destdir"; exit 1; }) \
-         && rm -rf "$$dc_destdir" \
-         && $(MAKE) $(AM_MAKEFLAGS) dist \
-         && rm -rf $(DIST_ARCHIVES) \
-         && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
-         && cd "$$am__cwd" \
-         || exit 1
-       $(am__post_remove_distdir)
-       @(echo "$(distdir) archives ready for distribution: "; \
-         list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
-         sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
-distuninstallcheck:
-       @test -n '$(distuninstallcheck_dir)' || { \
-         echo 'ERROR: trying to run $@ with an empty' \
-              '$$(distuninstallcheck_dir)' >&2; \
-         exit 1; \
-       }; \
-       $(am__cd) '$(distuninstallcheck_dir)' || { \
-         echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
-         exit 1; \
-       }; \
-       test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
-          || { echo "ERROR: files left after uninstall:" ; \
-               if test -n "$(DESTDIR)"; then \
-                 echo "  (check DESTDIR support)"; \
-               fi ; \
-               $(distuninstallcheck_listfiles) ; \
-               exit 1; } >&2
-distcleancheck: distclean
-       @if test '$(srcdir)' = . ; then \
-         echo "ERROR: distcleancheck can only run from a VPATH build" ; \
-         exit 1 ; \
-       fi
-       @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
-         || { echo "ERROR: files left in build directory after distclean:" ; \
-              $(distcleancheck_listfiles) ; \
-              exit 1; } >&2
-check-am: all-am
-check: check-recursive
-all-am: Makefile $(HEADERS) zfs_config.h
-installdirs: installdirs-recursive
-installdirs-am:
-       for dir in "$(DESTDIR)$(extradir)" "$(DESTDIR)$(kerneldir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-recursive
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-recursive
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-recursive
-       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-hdr \
-       distclean-libtool distclean-local distclean-tags
-
-dvi: dvi-recursive
-
-dvi-am:
-
-html: html-recursive
-
-html-am:
-
-info: info-recursive
-
-info-am:
-
-install-data-am: install-extraHEADERS install-nodist_kernelHEADERS
-
-install-dvi: install-dvi-recursive
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-recursive
-
-install-html-am:
-
-install-info: install-info-recursive
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-recursive
-
-install-pdf-am:
-
-install-ps: install-ps-recursive
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-recursive
-       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
-       -rm -rf $(top_srcdir)/autom4te.cache
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-recursive
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-recursive
-
-pdf-am:
-
-ps: ps-recursive
-
-ps-am:
-
-uninstall-am: uninstall-extraHEADERS uninstall-nodist_kernelHEADERS
-
-.MAKE: $(am__recursive_targets) all install-am install-strip
-
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
-       am--refresh check check-am clean clean-cscope clean-generic \
-       clean-libtool cscope cscopelist-am ctags ctags-am dist \
-       dist-all dist-bzip2 dist-gzip dist-hook dist-lzip dist-shar \
-       dist-tarZ dist-xz dist-zip distcheck distclean \
-       distclean-generic distclean-hdr distclean-libtool \
-       distclean-local distclean-tags distcleancheck distdir \
-       distuninstallcheck dvi dvi-am html html-am info info-am \
-       install install-am install-data install-data-am install-dvi \
-       install-dvi-am install-exec install-exec-am \
-       install-extraHEADERS install-html install-html-am install-info \
-       install-info-am install-man install-nodist_kernelHEADERS \
-       install-pdf install-pdf-am install-ps install-ps-am \
-       install-strip installcheck installcheck-am installdirs \
-       installdirs-am maintainer-clean maintainer-clean-generic \
-       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
-       ps ps-am tags tags-am uninstall uninstall-am \
-       uninstall-extraHEADERS uninstall-nodist_kernelHEADERS
-
-.PRECIOUS: Makefile
-
-
-srpm-kmod:
-       $(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-kmod" \
-               def='${SRPM_DEFINE_COMMON} ${SRPM_DEFINE_KMOD}' srpm-common
-
-srpm-dkms:
-       $(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-dkms" \
-               def='${SRPM_DEFINE_COMMON} ${SRPM_DEFINE_DKMS}' srpm-common
-
-srpm-utils:
-       $(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}" \
-               def='${SRPM_DEFINE_COMMON} ${SRPM_DEFINE_UTIL}' srpm-common
-
-srpm: srpm-kmod srpm-dkms srpm-utils
-srpms: srpm-kmod srpm-dkms srpm-utils
-
-rpm-kmod: srpm-kmod
-       $(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-kmod" \
-               def='${RPM_DEFINE_COMMON} ${RPM_DEFINE_KMOD}' rpm-common
-
-rpm-dkms: srpm-dkms
-       $(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}-dkms" \
-               def='${RPM_DEFINE_COMMON} ${RPM_DEFINE_DKMS}' rpm-common
-
-rpm-utils: srpm-utils
-       $(MAKE) $(AM_MAKEFLAGS) pkg="${PACKAGE}" \
-               def='${RPM_DEFINE_COMMON} ${RPM_DEFINE_UTIL}' rpm-common
-
-rpm: rpm-kmod rpm-dkms rpm-utils
-rpms: rpm-kmod rpm-dkms rpm-utils
-
-rpm-local:
-       @(if test "${HAVE_RPMBUILD}" = "no"; then \
-               echo -e "\n" \
-       "*** Required util ${RPMBUILD} missing.  Please install the\n" \
-       "*** package for your distribution which provides ${RPMBUILD},\n" \
-       "*** re-run configure, and try again.\n"; \
-               exit 1; \
-       fi; \
-       mkdir -p $(rpmbuild)/TMP && \
-       mkdir -p $(rpmbuild)/BUILD && \
-       mkdir -p $(rpmbuild)/RPMS && \
-       mkdir -p $(rpmbuild)/SRPMS && \
-       mkdir -p $(rpmbuild)/SPECS && \
-       cp ${RPM_SPEC_DIR}/$(rpmspec) $(rpmbuild)/SPECS && \
-       mkdir -p $(rpmbuild)/SOURCES && \
-       cp $(top_srcdir)/scripts/kmodtool $(rpmbuild)/SOURCES && \
-       cp $(distdir).tar.gz $(rpmbuild)/SOURCES)
-
-srpm-common: dist
-       @(dist=`$(RPM) --eval %{?dist}`; \
-       rpmpkg=$(pkg)-$(VERSION)-$(RELEASE)$$dist*src.rpm; \
-       rpmspec=$(pkg).spec; \
-       rpmbuild=`mktemp -t -d $(PACKAGE)-build-$$USER-XXXXXXXX`; \
-       $(MAKE) $(AM_MAKEFLAGS) \
-               rpmbuild="$$rpmbuild" \
-               rpmspec="$$rpmspec" \
-               rpm-local || exit 1; \
-       LANG=C $(RPMBUILD) \
-               --define "_tmppath $$rpmbuild/TMP" \
-               --define "_topdir $$rpmbuild" \
-               $(def) -bs $$rpmbuild/SPECS/$$rpmspec || exit 1; \
-       cp $$rpmbuild/SRPMS/$$rpmpkg . || exit 1; \
-       rm -R $$rpmbuild)
-
-rpm-common: 
-       @(dist=`$(RPM) --eval %{?dist}`; \
-       rpmpkg=$(pkg)-$(VERSION)-$(RELEASE)$$dist*src.rpm; \
-       rpmspec=$(pkg).spec; \
-       rpmbuild=`mktemp -t -d $(PACKAGE)-build-$$USER-XXXXXXXX`; \
-       $(MAKE) $(AM_MAKEFLAGS) \
-               rpmbuild="$$rpmbuild" \
-               rpmspec="$$rpmspec" \
-               rpm-local || exit 1; \
-       LANG=C ${RPMBUILD} \
-               --define "_tmppath $$rpmbuild/TMP" \
-               --define "_topdir $$rpmbuild" \
-               $(def) --rebuild $$rpmpkg || exit 1; \
-       cp $$rpmbuild/RPMS/*/* . || exit 1; \
-       rm -R $$rpmbuild)
-deb-local:
-       @(if test "${HAVE_DPKGBUILD}" = "no"; then \
-               echo -e "\n" \
-       "*** Required util ${DPKGBUILD} missing.  Please install the\n" \
-        "*** package for your distribution which provides ${DPKGBUILD},\n" \
-       "*** re-run configure, and try again.\n"; \
-                exit 1; \
-       fi; \
-       if test "${HAVE_ALIEN}" = "no"; then \
-               echo -e "\n" \
-       "*** Required util ${ALIEN} missing.  Please install the\n" \
-        "*** package for your distribution which provides ${ALIEN},\n" \
-       "*** re-run configure, and try again.\n"; \
-                exit 1; \
-       fi)
-
-deb-kmod: deb-local rpm-kmod
-@CONFIG_KERNEL_TRUE@   name=${PACKAGE}; \
-@CONFIG_KERNEL_TRUE@   version=${VERSION}-${RELEASE}; \
-@CONFIG_KERNEL_TRUE@   arch=`$(RPM) -qp $${name}-kmod-$${version}.src.rpm --qf %{arch} | tail -1`; \
-@CONFIG_KERNEL_TRUE@   pkg1=kmod-$${name}*$${version}.$${arch}.rpm; \
-@CONFIG_KERNEL_TRUE@   fakeroot $(ALIEN) --bump=0 --scripts --to-deb $$pkg1; \
-@CONFIG_KERNEL_TRUE@   $(RM) $$pkg1
-
-deb-utils: deb-local rpm-utils
-@CONFIG_USER_TRUE@     name=${PACKAGE}; \
-@CONFIG_USER_TRUE@     version=${VERSION}-${RELEASE}; \
-@CONFIG_USER_TRUE@     arch=`$(RPM) -qp $${name}-$${version}.src.rpm --qf %{arch} | tail -1`; \
-@CONFIG_USER_TRUE@     pkg1=$${name}-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg2=libnvpair1-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg3=libuutil1-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg4=libzfs2-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg5=libzpool2-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg6=libzfs2-devel-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg7=$${name}-test-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg8=$${name}-dracut-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg9=$${name}-initramfs-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     fakeroot $(ALIEN) --bump=0 --scripts --to-deb \
-@CONFIG_USER_TRUE@         $$pkg1 $$pkg2 $$pkg3 $$pkg4 $$pkg5 $$pkg6 $$pkg7 \
-@CONFIG_USER_TRUE@         $$pkg8 $$pkg9;
-@CONFIG_USER_TRUE@     $(RM) $$pkg1 $$pkg2 $$pkg3 $$pkg4 $$pkg5 $$pkg6 $$pkg7 \
-@CONFIG_USER_TRUE@         $$pkg8 $$pkg9;
-
-deb: deb-kmod deb-utils
-tgz-local:
-       @(if test "${HAVE_ALIEN}" = "no"; then \
-               echo -e "\n" \
-       "*** Required util ${ALIEN} missing.  Please install the\n" \
-        "*** package for your distribution which provides ${ALIEN},\n" \
-       "*** re-run configure, and try again.\n"; \
-                exit 1; \
-       fi)
-
-tgz-kmod: tgz-local rpm-kmod
-@CONFIG_KERNEL_TRUE@   name=${PACKAGE}; \
-@CONFIG_KERNEL_TRUE@   version=${VERSION}-${RELEASE}; \
-@CONFIG_KERNEL_TRUE@   arch=`$(RPM) -qp $${name}-kmod-$${version}.src.rpm --qf %{arch} | tail -1`; \
-@CONFIG_KERNEL_TRUE@   pkg1=kmod-$${name}*$${version}.$${arch}.rpm; \
-@CONFIG_KERNEL_TRUE@   fakeroot $(ALIEN) --scripts --to-tgz $$pkg1; \
-@CONFIG_KERNEL_TRUE@   $(RM) $$pkg1
-
-tgz-utils: tgz-local rpm-utils
-@CONFIG_USER_TRUE@     name=${PACKAGE}; \
-@CONFIG_USER_TRUE@     version=${VERSION}-${RELEASE}; \
-@CONFIG_USER_TRUE@     arch=`$(RPM) -qp $${name}-$${version}.src.rpm --qf %{arch} | tail -1`; \
-@CONFIG_USER_TRUE@     pkg1=$${name}-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg2=$${name}-devel-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     pkg3=$${name}-test-$${version}.$${arch}.rpm; \
-@CONFIG_USER_TRUE@     fakeroot $(ALIEN) --scripts --to-tgz $$pkg1 $$pkg2 $$pkg3; \
-@CONFIG_USER_TRUE@     $(RM) $$pkg1 $$pkg2 $$pkg3
-
-tgz: tgz-kmod tgz-utils
-
-distclean-local::
-       -$(RM) -R autom4te*.cache
-       -find . \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \
-               -o -name .pc -o -name .hg -o -name .git \) -prune -o \
-               \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
-               -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
-               -o -name '.*.rej' -o -name '.script-config' -o -size 0 \
-               -o -name '*%' -o -name '.*.cmd' -o -name 'core' \
-               -o -name 'Makefile' -o -name 'Module.symvers' \
-               -o -name '*.order' -o -name '*.markers' \) \
-               -type f -print | xargs $(RM)
-
-dist-hook:
-       sed -i 's/Release:[[:print:]]*/Release:      $(RELEASE)/' \
-               $(distdir)/META
-
-checkstyle: cstyle shellcheck
-
-cstyle:
-       @find ${top_srcdir} -name '*.[hc]' ! -name 'zfs_config.*' \
-               ! -name '*.mod.c' -type f -exec scripts/cstyle.pl {} \+
-
-shellcheck:
-       @if type shellcheck > /dev/null 2>&1; then \
-               (find ${top_srcdir} -type f -name '*.sh.in' -o -type f \
-                -name '*.sh'; find etc/init.d/zfs*.in -type f) | \
-                grep -v 'zfs-script-config' | \
-                while read file; do \
-                       shellcheck --format gcc "$$file"; \
-                done; \
-        fi
-
-lint: cppcheck
-
-cppcheck:
-       @if type cppcheck > /dev/null 2>&1; then \
-               cppcheck --quiet --force ${top_srcdir}; \
-       fi
-
-ctags:
-       $(RM) tags
-       find $(top_srcdir) -name .git -prune -o -name '*.[hc]' | xargs ctags
-
-etags:
-       $(RM) TAGS
-       find $(top_srcdir) -name .pc -prune -o -name '*.[hc]' | xargs etags -a
-
-tags: ctags etags
-
-pkg: @DEFAULT_PACKAGE@
-pkg-kmod: @DEFAULT_PACKAGE@-kmod
-pkg-utils: @DEFAULT_PACKAGE@-utils
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/zfs/TEST b/zfs/TEST
new file mode 100644 (file)
index 0000000..1cdbde8
--- /dev/null
+++ b/zfs/TEST
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+### prepare
+#TEST_PREPARE_WATCHDOG="no"
+
+### SPLAT
+#TEST_SPLAT_SKIP="yes"
+#TEST_SPLAT_OPTIONS="-acvx"
+
+### ztest
+#TEST_ZTEST_SKIP="yes"
+#TEST_ZTEST_TIMEOUT=1800
+#TEST_ZTEST_DIR="/var/tmp/"
+#TEST_ZTEST_OPTIONS="-V"
+
+### ziltest
+#TEST_ZILTEST_SKIP="yes"
+#TEST_ZILTEST_OPTIONS=""
+
+### zconfig
+#TEST_ZCONFIG_SKIP="yes"
+TEST_ZCONFIG_OPTIONS="-c -s10"
+
+### zimport
+#TEST_ZIMPORT_SKIP="yes"
+#TEST_ZIMPORT_DIR="/var/tmp/zimport"
+#TEST_ZIMPORT_VERSIONS="master installed"
+#TEST_ZIMPORT_POOLS="zol-0.6.1 zol-0.6.2 master installed"
+#TEST_ZIMPORT_OPTIONS="-c"
+
+### xfstests
+#TEST_XFSTESTS_SKIP="yes"
+#TEST_XFSTESTS_URL="https://github.com/behlendorf/xfstests/archive/"
+#TEST_XFSTESTS_VER="zfs.tar.gz"
+#TEST_XFSTESTS_POOL="tank"
+#TEST_XFSTESTS_FS="xfstests"
+#TEST_XFSTESTS_VDEV="/var/tmp/vdev"
+#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
+#TEST_FILEBENCH_SKIP="yes"
+#TEST_FILEBENCH_URL="http://build.zfsonlinux.org/"
+#TEST_FILEBENCH_VER="filebench-1.4.9.1.tar.gz"
+#TEST_FILEBENCH_RUNTIME=10
+#TEST_FILEBENCH_POOL="tank"
+#TEST_FILEBENCH_FS="filebench"
+#TEST_FILEBENCH_VDEV="/var/tmp/vdev"
+#TEST_FILEBENCH_DIR="/$TEST_FILEBENCH_POOL/$TEST_FILEBENCH_FS"
+#TEST_FILEBENCH_OPTIONS=""
+
+### zfsstress
+#TEST_ZFSSTRESS_SKIP="yes"
+#TEST_ZFSSTRESS_URL="https://github.com/nedbass/zfsstress/archive/"
+#TEST_ZFSSTRESS_VER="master.tar.gz"
+#TEST_ZFSSTRESS_RUNTIME=300
+#TEST_ZFSSTRESS_POOL="tank"
+#TEST_ZFSSTRESS_FS="fish"
+#TEST_ZFSSTRESS_VDEV="/var/tmp/vdev"
+#TEST_ZFSSTRESS_DIR="/$TEST_ZFSSTRESS_POOL/$TEST_ZFSSTRESS_FS"
+#TEST_ZFSSTRESS_OPTIONS=""
+
+### per-builder customization
+#
+# BB_NAME=builder-name <distribution-version-architecture-type>
+# - distribution=Amazon,Debian,Fedora,RHEL,SUSE,Ubuntu
+# - version=x.y
+# - architecture=x86_64,i686,arm,aarch64
+# - type=build,test
+#
+case "$BB_NAME" in
+Amazon*)
+    ;;
+CentOS*)
+    # Sporadic VERIFY(!zilog_is_dirty(zilog)) failed
+    TEST_ZILTEST_SKIP="yes"
+    ;;
+Debian*)
+    ;;
+Fedora*)
+    ;;
+RHEL*)
+    ;;
+SUSE*)
+    ;;
+Ubuntu*)
+    ;;
+*)
+    ;;
+esac
diff --git a/zfs/aclocal.m4 b/zfs/aclocal.m4
deleted file mode 100644 (file)
index 036341b..0000000
+++ /dev/null
@@ -1,1297 +0,0 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
-
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
-m4_ifndef([AC_AUTOCONF_VERSION],
-  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
-[m4_warning([this file was generated for autoconf 2.69.
-You have another version of autoconf.  It may work, but is not guaranteed to.
-If you have problems, you may need to regenerate the build system entirely.
-To do so, use the procedure documented by the package, typically 'autoreconf'.])])
-
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_AUTOMAKE_VERSION(VERSION)
-# ----------------------------
-# Automake X.Y traces this macro to ensure aclocal.m4 has been
-# generated from the m4 files accompanying Automake X.Y.
-# (This private macro should not be called outside this file.)
-AC_DEFUN([AM_AUTOMAKE_VERSION],
-[am__api_version='1.15'
-dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
-dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.15], [],
-      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
-])
-
-# _AM_AUTOCONF_VERSION(VERSION)
-# -----------------------------
-# aclocal traces this macro to find the Autoconf version.
-# This is a private macro too.  Using m4_define simplifies
-# the logic in aclocal, which can simply ignore this definition.
-m4_define([_AM_AUTOCONF_VERSION], [])
-
-# AM_SET_CURRENT_AUTOMAKE_VERSION
-# -------------------------------
-# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
-# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
-AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
-m4_ifndef([AC_AUTOCONF_VERSION],
-  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
-
-# Figure out how to run the assembler.                      -*- Autoconf -*-
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_PROG_AS
-# ----------
-AC_DEFUN([AM_PROG_AS],
-[# By default we simply use the C compiler to build assembly code.
-AC_REQUIRE([AC_PROG_CC])
-test "${CCAS+set}" = set || CCAS=$CC
-test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS
-AC_ARG_VAR([CCAS],      [assembler compiler command (defaults to CC)])
-AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)])
-_AM_IF_OPTION([no-dependencies],, [_AM_DEPENDENCIES([CCAS])])dnl
-])
-
-# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
-# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
-# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
-#
-# Of course, Automake must honor this variable whenever it calls a
-# tool from the auxiliary directory.  The problem is that $srcdir (and
-# therefore $ac_aux_dir as well) can be either absolute or relative,
-# depending on how configure is run.  This is pretty annoying, since
-# it makes $ac_aux_dir quite unusable in subdirectories: in the top
-# source directory, any form will work fine, but in subdirectories a
-# relative path needs to be adjusted first.
-#
-# $ac_aux_dir/missing
-#    fails when called from a subdirectory if $ac_aux_dir is relative
-# $top_srcdir/$ac_aux_dir/missing
-#    fails if $ac_aux_dir is absolute,
-#    fails when called from a subdirectory in a VPATH build with
-#          a relative $ac_aux_dir
-#
-# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
-# are both prefixed by $srcdir.  In an in-source build this is usually
-# harmless because $srcdir is '.', but things will broke when you
-# start a VPATH build or use an absolute $srcdir.
-#
-# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
-# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
-#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
-# and then we would define $MISSING as
-#   MISSING="\${SHELL} $am_aux_dir/missing"
-# This will work as long as MISSING is not called from configure, because
-# unfortunately $(top_srcdir) has no meaning in configure.
-# However there are other variables, like CC, which are often used in
-# configure, and could therefore not use this "fixed" $ac_aux_dir.
-#
-# Another solution, used here, is to always expand $ac_aux_dir to an
-# absolute PATH.  The drawback is that using absolute paths prevent a
-# configured tree to be moved without reconfiguration.
-
-AC_DEFUN([AM_AUX_DIR_EXPAND],
-[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
-# Expand $ac_aux_dir to an absolute path.
-am_aux_dir=`cd "$ac_aux_dir" && pwd`
-])
-
-# AM_CONDITIONAL                                            -*- Autoconf -*-
-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_CONDITIONAL(NAME, SHELL-CONDITION)
-# -------------------------------------
-# Define a conditional.
-AC_DEFUN([AM_CONDITIONAL],
-[AC_PREREQ([2.52])dnl
- m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
-       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
-AC_SUBST([$1_TRUE])dnl
-AC_SUBST([$1_FALSE])dnl
-_AM_SUBST_NOTMAKE([$1_TRUE])dnl
-_AM_SUBST_NOTMAKE([$1_FALSE])dnl
-m4_define([_AM_COND_VALUE_$1], [$2])dnl
-if $2; then
-  $1_TRUE=
-  $1_FALSE='#'
-else
-  $1_TRUE='#'
-  $1_FALSE=
-fi
-AC_CONFIG_COMMANDS_PRE(
-[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
-  AC_MSG_ERROR([[conditional "$1" was never defined.
-Usually this means the macro was only invoked conditionally.]])
-fi])])
-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-
-# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
-# written in clear, in which case automake, when reading aclocal.m4,
-# will think it sees a *use*, and therefore will trigger all it's
-# C support machinery.  Also note that it means that autoscan, seeing
-# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
-
-
-# _AM_DEPENDENCIES(NAME)
-# ----------------------
-# See how the compiler implements dependency checking.
-# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
-# We try a few techniques and use that to set a single cache variable.
-#
-# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
-# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
-# dependency, and given that the user is not expected to run this macro,
-# just rely on AC_PROG_CC.
-AC_DEFUN([_AM_DEPENDENCIES],
-[AC_REQUIRE([AM_SET_DEPDIR])dnl
-AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
-AC_REQUIRE([AM_MAKE_INCLUDE])dnl
-AC_REQUIRE([AM_DEP_TRACK])dnl
-
-m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
-      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
-      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
-      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
-      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
-      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
-                    [depcc="$$1"   am_compiler_list=])
-
-AC_CACHE_CHECK([dependency style of $depcc],
-               [am_cv_$1_dependencies_compiler_type],
-[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
-  # We make a subdir and do the tests there.  Otherwise we can end up
-  # making bogus files that we don't know about and never remove.  For
-  # instance it was reported that on HP-UX the gcc test will end up
-  # making a dummy file named 'D' -- because '-MD' means "put the output
-  # in D".
-  rm -rf conftest.dir
-  mkdir conftest.dir
-  # Copy depcomp to subdir because otherwise we won't find it if we're
-  # using a relative directory.
-  cp "$am_depcomp" conftest.dir
-  cd conftest.dir
-  # We will build objects and dependencies in a subdirectory because
-  # it helps to detect inapplicable dependency modes.  For instance
-  # both Tru64's cc and ICC support -MD to output dependencies as a
-  # side effect of compilation, but ICC will put the dependencies in
-  # the current directory while Tru64 will put them in the object
-  # directory.
-  mkdir sub
-
-  am_cv_$1_dependencies_compiler_type=none
-  if test "$am_compiler_list" = ""; then
-     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
-  fi
-  am__universal=false
-  m4_case([$1], [CC],
-    [case " $depcc " in #(
-     *\ -arch\ *\ -arch\ *) am__universal=true ;;
-     esac],
-    [CXX],
-    [case " $depcc " in #(
-     *\ -arch\ *\ -arch\ *) am__universal=true ;;
-     esac])
-
-  for depmode in $am_compiler_list; do
-    # Setup a source with many dependencies, because some compilers
-    # like to wrap large dependency lists on column 80 (with \), and
-    # we should not choose a depcomp mode which is confused by this.
-    #
-    # We need to recreate these files for each test, as the compiler may
-    # overwrite some of them when testing with obscure command lines.
-    # This happens at least with the AIX C compiler.
-    : > sub/conftest.c
-    for i in 1 2 3 4 5 6; do
-      echo '#include "conftst'$i'.h"' >> sub/conftest.c
-      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
-      # Solaris 10 /bin/sh.
-      echo '/* dummy */' > sub/conftst$i.h
-    done
-    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
-
-    # We check with '-c' and '-o' for the sake of the "dashmstdout"
-    # mode.  It turns out that the SunPro C++ compiler does not properly
-    # handle '-M -o', and we need to detect this.  Also, some Intel
-    # versions had trouble with output in subdirs.
-    am__obj=sub/conftest.${OBJEXT-o}
-    am__minus_obj="-o $am__obj"
-    case $depmode in
-    gcc)
-      # This depmode causes a compiler race in universal mode.
-      test "$am__universal" = false || continue
-      ;;
-    nosideeffect)
-      # After this tag, mechanisms are not by side-effect, so they'll
-      # only be used when explicitly requested.
-      if test "x$enable_dependency_tracking" = xyes; then
-       continue
-      else
-       break
-      fi
-      ;;
-    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
-      # This compiler won't grok '-c -o', but also, the minuso test has
-      # not run yet.  These depmodes are late enough in the game, and
-      # so weak that their functioning should not be impacted.
-      am__obj=conftest.${OBJEXT-o}
-      am__minus_obj=
-      ;;
-    none) break ;;
-    esac
-    if depmode=$depmode \
-       source=sub/conftest.c object=$am__obj \
-       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
-       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
-         >/dev/null 2>conftest.err &&
-       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
-       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
-       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
-       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
-      # icc doesn't choke on unknown options, it will just issue warnings
-      # or remarks (even with -Werror).  So we grep stderr for any message
-      # that says an option was ignored or not supported.
-      # When given -MP, icc 7.0 and 7.1 complain thusly:
-      #   icc: Command line warning: ignoring option '-M'; no argument required
-      # The diagnosis changed in icc 8.0:
-      #   icc: Command line remark: option '-MP' not supported
-      if (grep 'ignoring option' conftest.err ||
-          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
-        am_cv_$1_dependencies_compiler_type=$depmode
-        break
-      fi
-    fi
-  done
-
-  cd ..
-  rm -rf conftest.dir
-else
-  am_cv_$1_dependencies_compiler_type=none
-fi
-])
-AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
-AM_CONDITIONAL([am__fastdep$1], [
-  test "x$enable_dependency_tracking" != xno \
-  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
-])
-
-
-# AM_SET_DEPDIR
-# -------------
-# Choose a directory name for dependency files.
-# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
-AC_DEFUN([AM_SET_DEPDIR],
-[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
-AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
-])
-
-
-# AM_DEP_TRACK
-# ------------
-AC_DEFUN([AM_DEP_TRACK],
-[AC_ARG_ENABLE([dependency-tracking], [dnl
-AS_HELP_STRING(
-  [--enable-dependency-tracking],
-  [do not reject slow dependency extractors])
-AS_HELP_STRING(
-  [--disable-dependency-tracking],
-  [speeds up one-time build])])
-if test "x$enable_dependency_tracking" != xno; then
-  am_depcomp="$ac_aux_dir/depcomp"
-  AMDEPBACKSLASH='\'
-  am__nodep='_no'
-fi
-AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
-AC_SUBST([AMDEPBACKSLASH])dnl
-_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
-AC_SUBST([am__nodep])dnl
-_AM_SUBST_NOTMAKE([am__nodep])dnl
-])
-
-# Generate code to set up dependency tracking.              -*- Autoconf -*-
-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-
-# _AM_OUTPUT_DEPENDENCY_COMMANDS
-# ------------------------------
-AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
-[{
-  # Older Autoconf quotes --file arguments for eval, but not when files
-  # are listed without --file.  Let's play safe and only enable the eval
-  # if we detect the quoting.
-  case $CONFIG_FILES in
-  *\'*) eval set x "$CONFIG_FILES" ;;
-  *)   set x $CONFIG_FILES ;;
-  esac
-  shift
-  for mf
-  do
-    # Strip MF so we end up with the name of the file.
-    mf=`echo "$mf" | sed -e 's/:.*$//'`
-    # Check whether this is an Automake generated Makefile or not.
-    # We used to match only the files named 'Makefile.in', but
-    # some people rename them; so instead we look at the file content.
-    # Grep'ing the first line is not enough: some people post-process
-    # each Makefile.in and add a new line on top of each file to say so.
-    # Grep'ing the whole file is not good either: AIX grep has a line
-    # limit of 2048, but all sed's we know have understand at least 4000.
-    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
-      dirpart=`AS_DIRNAME("$mf")`
-    else
-      continue
-    fi
-    # Extract the definition of DEPDIR, am__include, and am__quote
-    # from the Makefile without running 'make'.
-    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
-    test -z "$DEPDIR" && continue
-    am__include=`sed -n 's/^am__include = //p' < "$mf"`
-    test -z "$am__include" && continue
-    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
-    # Find all dependency output files, they are included files with
-    # $(DEPDIR) in their names.  We invoke sed twice because it is the
-    # simplest approach to changing $(DEPDIR) to its actual value in the
-    # expansion.
-    for file in `sed -n "
-      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
-        sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
-      # Make sure the directory exists.
-      test -f "$dirpart/$file" && continue
-      fdir=`AS_DIRNAME(["$file"])`
-      AS_MKDIR_P([$dirpart/$fdir])
-      # echo "creating $dirpart/$file"
-      echo '# dummy' > "$dirpart/$file"
-    done
-  done
-}
-])# _AM_OUTPUT_DEPENDENCY_COMMANDS
-
-
-# AM_OUTPUT_DEPENDENCY_COMMANDS
-# -----------------------------
-# This macro should only be invoked once -- use via AC_REQUIRE.
-#
-# This code is only required when automatic dependency tracking
-# is enabled.  FIXME.  This creates each '.P' file that we will
-# need in order to bootstrap the dependency handling code.
-AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
-[AC_CONFIG_COMMANDS([depfiles],
-     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
-     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
-])
-
-# Do all the work for Automake.                             -*- Autoconf -*-
-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This macro actually does too much.  Some checks are only needed if
-# your package does certain things.  But this isn't really a big deal.
-
-dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
-m4_define([AC_PROG_CC],
-m4_defn([AC_PROG_CC])
-[_AM_PROG_CC_C_O
-])
-
-# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
-# AM_INIT_AUTOMAKE([OPTIONS])
-# -----------------------------------------------
-# The call with PACKAGE and VERSION arguments is the old style
-# call (pre autoconf-2.50), which is being phased out.  PACKAGE
-# and VERSION should now be passed to AC_INIT and removed from
-# the call to AM_INIT_AUTOMAKE.
-# We support both call styles for the transition.  After
-# the next Automake release, Autoconf can make the AC_INIT
-# arguments mandatory, and then we can depend on a new Autoconf
-# release and drop the old call support.
-AC_DEFUN([AM_INIT_AUTOMAKE],
-[AC_PREREQ([2.65])dnl
-dnl Autoconf wants to disallow AM_ names.  We explicitly allow
-dnl the ones we care about.
-m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
-AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
-AC_REQUIRE([AC_PROG_INSTALL])dnl
-if test "`cd $srcdir && pwd`" != "`pwd`"; then
-  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
-  # is not polluted with repeated "-I."
-  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
-  # test to see if srcdir already configured
-  if test -f $srcdir/config.status; then
-    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
-  fi
-fi
-
-# test whether we have cygpath
-if test -z "$CYGPATH_W"; then
-  if (cygpath --version) >/dev/null 2>/dev/null; then
-    CYGPATH_W='cygpath -w'
-  else
-    CYGPATH_W=echo
-  fi
-fi
-AC_SUBST([CYGPATH_W])
-
-# Define the identity of the package.
-dnl Distinguish between old-style and new-style calls.
-m4_ifval([$2],
-[AC_DIAGNOSE([obsolete],
-             [$0: two- and three-arguments forms are deprecated.])
-m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
- AC_SUBST([PACKAGE], [$1])dnl
- AC_SUBST([VERSION], [$2])],
-[_AM_SET_OPTIONS([$1])dnl
-dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
-m4_if(
-  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
-  [ok:ok],,
-  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
- AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
- AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
-
-_AM_IF_OPTION([no-define],,
-[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
- AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
-
-# Some tools Automake needs.
-AC_REQUIRE([AM_SANITY_CHECK])dnl
-AC_REQUIRE([AC_ARG_PROGRAM])dnl
-AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
-AM_MISSING_PROG([AUTOCONF], [autoconf])
-AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
-AM_MISSING_PROG([AUTOHEADER], [autoheader])
-AM_MISSING_PROG([MAKEINFO], [makeinfo])
-AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
-AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
-AC_REQUIRE([AC_PROG_MKDIR_P])dnl
-# For better backward compatibility.  To be removed once Automake 1.9.x
-# dies out for good.  For more background, see:
-# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
-# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
-AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
-# We need awk for the "check" target (and possibly the TAP driver).  The
-# system "awk" is bad on some platforms.
-AC_REQUIRE([AC_PROG_AWK])dnl
-AC_REQUIRE([AC_PROG_MAKE_SET])dnl
-AC_REQUIRE([AM_SET_LEADING_DOT])dnl
-_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
-             [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
-                            [_AM_PROG_TAR([v7])])])
-_AM_IF_OPTION([no-dependencies],,
-[AC_PROVIDE_IFELSE([AC_PROG_CC],
-                 [_AM_DEPENDENCIES([CC])],
-                 [m4_define([AC_PROG_CC],
-                            m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
-AC_PROVIDE_IFELSE([AC_PROG_CXX],
-                 [_AM_DEPENDENCIES([CXX])],
-                 [m4_define([AC_PROG_CXX],
-                            m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
-AC_PROVIDE_IFELSE([AC_PROG_OBJC],
-                 [_AM_DEPENDENCIES([OBJC])],
-                 [m4_define([AC_PROG_OBJC],
-                            m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
-AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
-                 [_AM_DEPENDENCIES([OBJCXX])],
-                 [m4_define([AC_PROG_OBJCXX],
-                            m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
-])
-AC_REQUIRE([AM_SILENT_RULES])dnl
-dnl The testsuite driver may need to know about EXEEXT, so add the
-dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
-dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
-AC_CONFIG_COMMANDS_PRE(dnl
-[m4_provide_if([_AM_COMPILER_EXEEXT],
-  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
-
-# POSIX will say in a future version that running "rm -f" with no argument
-# is OK; and we want to be able to make that assumption in our Makefile
-# recipes.  So use an aggressive probe to check that the usage we want is
-# actually supported "in the wild" to an acceptable degree.
-# See automake bug#10828.
-# To make any issue more visible, cause the running configure to be aborted
-# by default if the 'rm' program in use doesn't match our expectations; the
-# user can still override this though.
-if rm -f && rm -fr && rm -rf; then : OK; else
-  cat >&2 <<'END'
-Oops!
-
-Your 'rm' program seems unable to run without file operands specified
-on the command line, even when the '-f' option is present.  This is contrary
-to the behaviour of most rm programs out there, and not conforming with
-the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
-
-Please tell bug-automake@gnu.org about your system, including the value
-of your $PATH and any error possibly output before this message.  This
-can help us improve future automake versions.
-
-END
-  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
-    echo 'Configuration will proceed anyway, since you have set the' >&2
-    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
-    echo >&2
-  else
-    cat >&2 <<'END'
-Aborting the configuration process, to ensure you take notice of the issue.
-
-You can download and install GNU coreutils to get an 'rm' implementation
-that behaves properly: <http://www.gnu.org/software/coreutils/>.
-
-If you want to complete the configuration process using your problematic
-'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
-to "yes", and re-run configure.
-
-END
-    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
-  fi
-fi
-dnl The trailing newline in this macro's definition is deliberate, for
-dnl backward compatibility and to allow trailing 'dnl'-style comments
-dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
-])
-
-dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
-dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
-dnl mangled by Autoconf and run in a shell conditional statement.
-m4_define([_AC_COMPILER_EXEEXT],
-m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
-
-# When config.status generates a header, we must update the stamp-h file.
-# This file resides in the same directory as the config header
-# that is generated.  The stamp files are numbered to have different names.
-
-# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
-# loop where config.status creates the headers, so we can generate
-# our stamp files there.
-AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
-[# Compute $1's index in $config_headers.
-_am_arg=$1
-_am_stamp_count=1
-for _am_header in $config_headers :; do
-  case $_am_header in
-    $_am_arg | $_am_arg:* )
-      break ;;
-    * )
-      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
-  esac
-done
-echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_PROG_INSTALL_SH
-# ------------------
-# Define $install_sh.
-AC_DEFUN([AM_PROG_INSTALL_SH],
-[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-if test x"${install_sh+set}" != xset; then
-  case $am_aux_dir in
-  *\ * | *\    *)
-    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
-  *)
-    install_sh="\${SHELL} $am_aux_dir/install-sh"
-  esac
-fi
-AC_SUBST([install_sh])])
-
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# Check whether the underlying file-system supports filenames
-# with a leading dot.  For instance MS-DOS doesn't.
-AC_DEFUN([AM_SET_LEADING_DOT],
-[rm -rf .tst 2>/dev/null
-mkdir .tst 2>/dev/null
-if test -d .tst; then
-  am__leading_dot=.
-else
-  am__leading_dot=_
-fi
-rmdir .tst 2>/dev/null
-AC_SUBST([am__leading_dot])])
-
-# Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
-# From Jim Meyering
-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_MAINTAINER_MODE([DEFAULT-MODE])
-# ----------------------------------
-# Control maintainer-specific portions of Makefiles.
-# Default is to disable them, unless 'enable' is passed literally.
-# For symmetry, 'disable' may be passed as well.  Anyway, the user
-# can override the default with the --enable/--disable switch.
-AC_DEFUN([AM_MAINTAINER_MODE],
-[m4_case(m4_default([$1], [disable]),
-       [enable], [m4_define([am_maintainer_other], [disable])],
-       [disable], [m4_define([am_maintainer_other], [enable])],
-       [m4_define([am_maintainer_other], [enable])
-        m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
-AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
-  dnl maintainer-mode's default is 'disable' unless 'enable' is passed
-  AC_ARG_ENABLE([maintainer-mode],
-    [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
-      am_maintainer_other[ make rules and dependencies not useful
-      (and sometimes confusing) to the casual installer])],
-    [USE_MAINTAINER_MODE=$enableval],
-    [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
-  AC_MSG_RESULT([$USE_MAINTAINER_MODE])
-  AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
-  MAINT=$MAINTAINER_MODE_TRUE
-  AC_SUBST([MAINT])dnl
-]
-)
-
-# Check to see how 'make' treats includes.                 -*- Autoconf -*-
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_MAKE_INCLUDE()
-# -----------------
-# Check to see how make treats includes.
-AC_DEFUN([AM_MAKE_INCLUDE],
-[am_make=${MAKE-make}
-cat > confinc << 'END'
-am__doit:
-       @echo this is the am__doit target
-.PHONY: am__doit
-END
-# If we don't find an include directive, just comment out the code.
-AC_MSG_CHECKING([for style of include used by $am_make])
-am__include="#"
-am__quote=
-_am_result=none
-# First try GNU make style include.
-echo "include confinc" > confmf
-# Ignore all kinds of additional output from 'make'.
-case `$am_make -s -f confmf 2> /dev/null` in #(
-*the\ am__doit\ target*)
-  am__include=include
-  am__quote=
-  _am_result=GNU
-  ;;
-esac
-# Now try BSD make style include.
-if test "$am__include" = "#"; then
-   echo '.include "confinc"' > confmf
-   case `$am_make -s -f confmf 2> /dev/null` in #(
-   *the\ am__doit\ target*)
-     am__include=.include
-     am__quote="\""
-     _am_result=BSD
-     ;;
-   esac
-fi
-AC_SUBST([am__include])
-AC_SUBST([am__quote])
-AC_MSG_RESULT([$_am_result])
-rm -f confinc confmf
-])
-
-# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_MISSING_PROG(NAME, PROGRAM)
-# ------------------------------
-AC_DEFUN([AM_MISSING_PROG],
-[AC_REQUIRE([AM_MISSING_HAS_RUN])
-$1=${$1-"${am_missing_run}$2"}
-AC_SUBST($1)])
-
-# AM_MISSING_HAS_RUN
-# ------------------
-# Define MISSING if not defined so far and test if it is modern enough.
-# If it is, set am_missing_run to use it, otherwise, to nothing.
-AC_DEFUN([AM_MISSING_HAS_RUN],
-[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-AC_REQUIRE_AUX_FILE([missing])dnl
-if test x"${MISSING+set}" != xset; then
-  case $am_aux_dir in
-  *\ * | *\    *)
-    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
-  *)
-    MISSING="\${SHELL} $am_aux_dir/missing" ;;
-  esac
-fi
-# Use eval to expand $SHELL
-if eval "$MISSING --is-lightweight"; then
-  am_missing_run="$MISSING "
-else
-  am_missing_run=
-  AC_MSG_WARN(['missing' script is too old or missing])
-fi
-])
-
-# Helper functions for option handling.                     -*- Autoconf -*-
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# _AM_MANGLE_OPTION(NAME)
-# -----------------------
-AC_DEFUN([_AM_MANGLE_OPTION],
-[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
-
-# _AM_SET_OPTION(NAME)
-# --------------------
-# Set option NAME.  Presently that only means defining a flag for this option.
-AC_DEFUN([_AM_SET_OPTION],
-[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
-
-# _AM_SET_OPTIONS(OPTIONS)
-# ------------------------
-# OPTIONS is a space-separated list of Automake options.
-AC_DEFUN([_AM_SET_OPTIONS],
-[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
-
-# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
-# -------------------------------------------
-# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
-AC_DEFUN([_AM_IF_OPTION],
-[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# _AM_PROG_CC_C_O
-# ---------------
-# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
-# to automatically call this.
-AC_DEFUN([_AM_PROG_CC_C_O],
-[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
-AC_REQUIRE_AUX_FILE([compile])dnl
-AC_LANG_PUSH([C])dnl
-AC_CACHE_CHECK(
-  [whether $CC understands -c and -o together],
-  [am_cv_prog_cc_c_o],
-  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
-  # Make sure it works both with $CC and with simple cc.
-  # Following AC_PROG_CC_C_O, we do the test twice because some
-  # compilers refuse to overwrite an existing .o file with -o,
-  # though they will create one.
-  am_cv_prog_cc_c_o=yes
-  for am_i in 1 2; do
-    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
-         && test -f conftest2.$ac_objext; then
-      : OK
-    else
-      am_cv_prog_cc_c_o=no
-      break
-    fi
-  done
-  rm -f core conftest*
-  unset am_i])
-if test "$am_cv_prog_cc_c_o" != yes; then
-   # Losing compiler, so override with the script.
-   # FIXME: It is wrong to rewrite CC.
-   # But if we don't then we get into trouble of one sort or another.
-   # A longer-term fix would be to have automake use am__CC in this case,
-   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
-   CC="$am_aux_dir/compile $CC"
-fi
-AC_LANG_POP([C])])
-
-# For backward compatibility.
-AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_RUN_LOG(COMMAND)
-# -------------------
-# Run COMMAND, save the exit status in ac_status, and log it.
-# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
-AC_DEFUN([AM_RUN_LOG],
-[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
-   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
-   ac_status=$?
-   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
-   (exit $ac_status); }])
-
-# Check to make sure that the build environment is sane.    -*- Autoconf -*-
-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_SANITY_CHECK
-# ---------------
-AC_DEFUN([AM_SANITY_CHECK],
-[AC_MSG_CHECKING([whether build environment is sane])
-# Reject unsafe characters in $srcdir or the absolute working directory
-# name.  Accept space and tab only in the latter.
-am_lf='
-'
-case `pwd` in
-  *[[\\\"\#\$\&\'\`$am_lf]]*)
-    AC_MSG_ERROR([unsafe absolute working directory name]);;
-esac
-case $srcdir in
-  *[[\\\"\#\$\&\'\`$am_lf\ \   ]]*)
-    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
-esac
-
-# Do 'set' in a subshell so we don't clobber the current shell's
-# arguments.  Must try -L first in case configure is actually a
-# symlink; some systems play weird games with the mod time of symlinks
-# (eg FreeBSD returns the mod time of the symlink's containing
-# directory).
-if (
-   am_has_slept=no
-   for am_try in 1 2; do
-     echo "timestamp, slept: $am_has_slept" > conftest.file
-     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
-     if test "$[*]" = "X"; then
-       # -L didn't work.
-       set X `ls -t "$srcdir/configure" conftest.file`
-     fi
-     if test "$[*]" != "X $srcdir/configure conftest.file" \
-       && test "$[*]" != "X conftest.file $srcdir/configure"; then
-
-       # If neither matched, then we have a broken ls.  This can happen
-       # if, for instance, CONFIG_SHELL is bash and it inherits a
-       # broken ls alias from the environment.  This has actually
-       # happened.  Such a system could not be considered "sane".
-       AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
-  alias in your environment])
-     fi
-     if test "$[2]" = conftest.file || test $am_try -eq 2; then
-       break
-     fi
-     # Just in case.
-     sleep 1
-     am_has_slept=yes
-   done
-   test "$[2]" = conftest.file
-   )
-then
-   # Ok.
-   :
-else
-   AC_MSG_ERROR([newly created file is older than distributed files!
-Check your system clock])
-fi
-AC_MSG_RESULT([yes])
-# If we didn't sleep, we still need to ensure time stamps of config.status and
-# generated files are strictly newer.
-am_sleep_pid=
-if grep 'slept: no' conftest.file >/dev/null 2>&1; then
-  ( sleep 1 ) &
-  am_sleep_pid=$!
-fi
-AC_CONFIG_COMMANDS_PRE(
-  [AC_MSG_CHECKING([that generated files are newer than configure])
-   if test -n "$am_sleep_pid"; then
-     # Hide warnings about reused PIDs.
-     wait $am_sleep_pid 2>/dev/null
-   fi
-   AC_MSG_RESULT([done])])
-rm -f conftest.file
-])
-
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_SILENT_RULES([DEFAULT])
-# --------------------------
-# Enable less verbose build rules; with the default set to DEFAULT
-# ("yes" being less verbose, "no" or empty being verbose).
-AC_DEFUN([AM_SILENT_RULES],
-[AC_ARG_ENABLE([silent-rules], [dnl
-AS_HELP_STRING(
-  [--enable-silent-rules],
-  [less verbose build output (undo: "make V=1")])
-AS_HELP_STRING(
-  [--disable-silent-rules],
-  [verbose build output (undo: "make V=0")])dnl
-])
-case $enable_silent_rules in @%:@ (((
-  yes) AM_DEFAULT_VERBOSITY=0;;
-   no) AM_DEFAULT_VERBOSITY=1;;
-    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
-esac
-dnl
-dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
-dnl do not support nested variable expansions.
-dnl See automake bug#9928 and bug#10237.
-am_make=${MAKE-make}
-AC_CACHE_CHECK([whether $am_make supports nested variables],
-   [am_cv_make_support_nested_variables],
-   [if AS_ECHO([['TRUE=$(BAR$(V))
-BAR0=false
-BAR1=true
-V=1
-am__doit:
-       @$(TRUE)
-.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
-  am_cv_make_support_nested_variables=yes
-else
-  am_cv_make_support_nested_variables=no
-fi])
-if test $am_cv_make_support_nested_variables = yes; then
-  dnl Using '$V' instead of '$(V)' breaks IRIX make.
-  AM_V='$(V)'
-  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
-else
-  AM_V=$AM_DEFAULT_VERBOSITY
-  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
-fi
-AC_SUBST([AM_V])dnl
-AM_SUBST_NOTMAKE([AM_V])dnl
-AC_SUBST([AM_DEFAULT_V])dnl
-AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
-AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
-AM_BACKSLASH='\'
-AC_SUBST([AM_BACKSLASH])dnl
-_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
-])
-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# AM_PROG_INSTALL_STRIP
-# ---------------------
-# One issue with vendor 'install' (even GNU) is that you can't
-# specify the program used to strip binaries.  This is especially
-# annoying in cross-compiling environments, where the build's strip
-# is unlikely to handle the host's binaries.
-# Fortunately install-sh will honor a STRIPPROG variable, so we
-# always use install-sh in "make install-strip", and initialize
-# STRIPPROG with the value of the STRIP variable (set by the user).
-AC_DEFUN([AM_PROG_INSTALL_STRIP],
-[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
-# Installed binaries are usually stripped using 'strip' when the user
-# run "make install-strip".  However 'strip' might not be the right
-# tool to use in cross-compilation environments, therefore Automake
-# will honor the 'STRIP' environment variable to overrule this program.
-dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
-if test "$cross_compiling" != no; then
-  AC_CHECK_TOOL([STRIP], [strip], :)
-fi
-INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
-AC_SUBST([INSTALL_STRIP_PROGRAM])])
-
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# _AM_SUBST_NOTMAKE(VARIABLE)
-# ---------------------------
-# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
-# This macro is traced by Automake.
-AC_DEFUN([_AM_SUBST_NOTMAKE])
-
-# AM_SUBST_NOTMAKE(VARIABLE)
-# --------------------------
-# Public sister of _AM_SUBST_NOTMAKE.
-AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
-
-# Check how to create a tarball.                            -*- Autoconf -*-
-
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# _AM_PROG_TAR(FORMAT)
-# --------------------
-# Check how to create a tarball in format FORMAT.
-# FORMAT should be one of 'v7', 'ustar', or 'pax'.
-#
-# Substitute a variable $(am__tar) that is a command
-# writing to stdout a FORMAT-tarball containing the directory
-# $tardir.
-#     tardir=directory && $(am__tar) > result.tar
-#
-# Substitute a variable $(am__untar) that extract such
-# a tarball read from stdin.
-#     $(am__untar) < result.tar
-#
-AC_DEFUN([_AM_PROG_TAR],
-[# Always define AMTAR for backward compatibility.  Yes, it's still used
-# in the wild :-(  We should find a proper way to deprecate it ...
-AC_SUBST([AMTAR], ['$${TAR-tar}'])
-
-# We'll loop over all known methods to create a tar archive until one works.
-_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
-
-m4_if([$1], [v7],
-  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
-
-  [m4_case([$1],
-    [ustar],
-     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
-      # There is notably a 21 bits limit for the UID and the GID.  In fact,
-      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
-      # and bug#13588).
-      am_max_uid=2097151 # 2^21 - 1
-      am_max_gid=$am_max_uid
-      # The $UID and $GID variables are not portable, so we need to resort
-      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
-      # below are definitely unexpected, so allow the users to see them
-      # (that is, avoid stderr redirection).
-      am_uid=`id -u || echo unknown`
-      am_gid=`id -g || echo unknown`
-      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
-      if test $am_uid -le $am_max_uid; then
-         AC_MSG_RESULT([yes])
-      else
-         AC_MSG_RESULT([no])
-         _am_tools=none
-      fi
-      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
-      if test $am_gid -le $am_max_gid; then
-         AC_MSG_RESULT([yes])
-      else
-        AC_MSG_RESULT([no])
-        _am_tools=none
-      fi],
-
-  [pax],
-    [],
-
-  [m4_fatal([Unknown tar format])])
-
-  AC_MSG_CHECKING([how to create a $1 tar archive])
-
-  # Go ahead even if we have the value already cached.  We do so because we
-  # need to set the values for the 'am__tar' and 'am__untar' variables.
-  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
-
-  for _am_tool in $_am_tools; do
-    case $_am_tool in
-    gnutar)
-      for _am_tar in tar gnutar gtar; do
-        AM_RUN_LOG([$_am_tar --version]) && break
-      done
-      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
-      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
-      am__untar="$_am_tar -xf -"
-      ;;
-    plaintar)
-      # Must skip GNU tar: if it does not support --format= it doesn't create
-      # ustar tarball either.
-      (tar --version) >/dev/null 2>&1 && continue
-      am__tar='tar chf - "$$tardir"'
-      am__tar_='tar chf - "$tardir"'
-      am__untar='tar xf -'
-      ;;
-    pax)
-      am__tar='pax -L -x $1 -w "$$tardir"'
-      am__tar_='pax -L -x $1 -w "$tardir"'
-      am__untar='pax -r'
-      ;;
-    cpio)
-      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
-      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
-      am__untar='cpio -i -H $1 -d'
-      ;;
-    none)
-      am__tar=false
-      am__tar_=false
-      am__untar=false
-      ;;
-    esac
-
-    # If the value was cached, stop now.  We just wanted to have am__tar
-    # and am__untar set.
-    test -n "${am_cv_prog_tar_$1}" && break
-
-    # tar/untar a dummy directory, and stop if the command works.
-    rm -rf conftest.dir
-    mkdir conftest.dir
-    echo GrepMe > conftest.dir/file
-    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
-    rm -rf conftest.dir
-    if test -s conftest.tar; then
-      AM_RUN_LOG([$am__untar <conftest.tar])
-      AM_RUN_LOG([cat conftest.dir/file])
-      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
-    fi
-  done
-  rm -rf conftest.dir
-
-  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
-  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
-
-AC_SUBST([am__tar])
-AC_SUBST([am__untar])
-]) # _AM_PROG_TAR
-
-m4_include([config/always-no-bool-compare.m4])
-m4_include([config/always-no-unused-but-set-variable.m4])
-m4_include([config/dkms.m4])
-m4_include([config/kernel-acl.m4])
-m4_include([config/kernel-automount.m4])
-m4_include([config/kernel-bdev-block-device-operations.m4])
-m4_include([config/kernel-bdev-logical-size.m4])
-m4_include([config/kernel-bdev-physical-size.m4])
-m4_include([config/kernel-bdi-setup-and-register.m4])
-m4_include([config/kernel-bio-bvec-iter.m4])
-m4_include([config/kernel-bio-end-io-t-args.m4])
-m4_include([config/kernel-bio-failfast.m4])
-m4_include([config/kernel-bio-op.m4])
-m4_include([config/kernel-bio-rw-barrier.m4])
-m4_include([config/kernel-bio-rw-discard.m4])
-m4_include([config/kernel-blk-queue-flush.m4])
-m4_include([config/kernel-blk-queue-max-hw-sectors.m4])
-m4_include([config/kernel-blk-queue-max-segments.m4])
-m4_include([config/kernel-blkdev-get-by-path.m4])
-m4_include([config/kernel-blkdev-get.m4])
-m4_include([config/kernel-block-device-operations-release-void.m4])
-m4_include([config/kernel-check-disk-size-change.m4])
-m4_include([config/kernel-clear-inode.m4])
-m4_include([config/kernel-commit-metadata.m4])
-m4_include([config/kernel-create-nameidata.m4])
-m4_include([config/kernel-current_bio_tail.m4])
-m4_include([config/kernel-d-make-root.m4])
-m4_include([config/kernel-d-obtain-alias.m4])
-m4_include([config/kernel-d-prune-aliases.m4])
-m4_include([config/kernel-declare-event-class.m4])
-m4_include([config/kernel-dentry-operations.m4])
-m4_include([config/kernel-dirty-inode.m4])
-m4_include([config/kernel-discard-granularity.m4])
-m4_include([config/kernel-elevator-change.m4])
-m4_include([config/kernel-encode-fh-inode.m4])
-m4_include([config/kernel-evict-inode.m4])
-m4_include([config/kernel-fallocate.m4])
-m4_include([config/kernel-file-inode.m4])
-m4_include([config/kernel-fmode-t.m4])
-m4_include([config/kernel-follow-down-one.m4])
-m4_include([config/kernel-fsync.m4])
-m4_include([config/kernel-generic_io_acct.m4])
-m4_include([config/kernel-get-disk-ro.m4])
-m4_include([config/kernel-get-gendisk.m4])
-m4_include([config/kernel-get-link.m4])
-m4_include([config/kernel-insert-inode-locked.m4])
-m4_include([config/kernel-invalidate-bdev-args.m4])
-m4_include([config/kernel-is_owner_or_cap.m4])
-m4_include([config/kernel-kmap-atomic-args.m4])
-m4_include([config/kernel-kobj-name-len.m4])
-m4_include([config/kernel-lookup-bdev.m4])
-m4_include([config/kernel-lookup-nameidata.m4])
-m4_include([config/kernel-lseek-execute.m4])
-m4_include([config/kernel-mk-request-fn.m4])
-m4_include([config/kernel-mkdir-umode-t.m4])
-m4_include([config/kernel-mount-nodev.m4])
-m4_include([config/kernel-open-bdev-exclusive.m4])
-m4_include([config/kernel-put-link.m4])
-m4_include([config/kernel-security-inode-init.m4])
-m4_include([config/kernel-set-nlink.m4])
-m4_include([config/kernel-sget-args.m4])
-m4_include([config/kernel-show-options.m4])
-m4_include([config/kernel-shrink.m4])
-m4_include([config/kernel-submit_bio.m4])
-m4_include([config/kernel-truncate-range.m4])
-m4_include([config/kernel-truncate-setsize.m4])
-m4_include([config/kernel-vfs-iterate.m4])
-m4_include([config/kernel-vfs-rw-iterate.m4])
-m4_include([config/kernel-xattr-handler.m4])
-m4_include([config/kernel.m4])
-m4_include([config/libtool.m4])
-m4_include([config/ltoptions.m4])
-m4_include([config/ltsugar.m4])
-m4_include([config/ltversion.m4])
-m4_include([config/lt~obsolete.m4])
-m4_include([config/mount-helper.m4])
-m4_include([config/user-arch.m4])
-m4_include([config/user-dracut.m4])
-m4_include([config/user-frame-larger-than.m4])
-m4_include([config/user-libblkid.m4])
-m4_include([config/user-libuuid.m4])
-m4_include([config/user-runstatedir.m4])
-m4_include([config/user-systemd.m4])
-m4_include([config/user-sysvinit.m4])
-m4_include([config/user-udev.m4])
-m4_include([config/user-zlib.m4])
-m4_include([config/user.m4])
-m4_include([config/zfs-build.m4])
-m4_include([config/zfs-meta.m4])
diff --git a/zfs/cmd/Makefile.am b/zfs/cmd/Makefile.am
new file mode 100644 (file)
index 0000000..04aa7c6
--- /dev/null
@@ -0,0 +1,3 @@
+SUBDIRS  = zfs zpool zdb zhack zinject zstreamdump ztest zpios
+SUBDIRS += mount_zfs fsck_zfs zvol_id vdev_id arcstat dbufstat zed
+SUBDIRS += arc_summary raidz_test
diff --git a/zfs/cmd/Makefile.in b/zfs/cmd/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/arc_summary/Makefile.am b/zfs/cmd/arc_summary/Makefile.am
new file mode 100644 (file)
index 0000000..815af3b
--- /dev/null
@@ -0,0 +1 @@
+dist_bin_SCRIPTS = arc_summary.py
diff --git a/zfs/cmd/arc_summary/Makefile.in b/zfs/cmd/arc_summary/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/arc_summary/arc_summary.py b/zfs/cmd/arc_summary/arc_summary.py
new file mode 100755 (executable)
index 0000000..e7448fa
--- /dev/null
@@ -0,0 +1,991 @@
+#!/usr/bin/python
+#
+# $Id: arc_summary.pl,v 388:e27800740aa2 2011-07-08 02:53:29Z jhell $
+#
+# Copyright (c) 2008 Ben Rockwood <benr@cuddletech.com>,
+# Copyright (c) 2010 Martin Matuska <mm@FreeBSD.org>,
+# Copyright (c) 2010-2011 Jason J. Hellenthal <jhell@DataIX.net>,
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# If you are having troubles when using this script from cron(8) please try
+# adjusting your PATH before reporting problems.
+#
+# /usr/bin & /sbin
+#
+# Binaries used are:
+#
+# dc(1), kldstat(8), sed(1), sysctl(8) & vmstat(8)
+#
+# Binaries that I am working on phasing out are:
+#
+# dc(1) & sed(1)
+
+import sys
+import time
+import getopt
+import re
+from os import listdir
+from subprocess import Popen, PIPE
+from decimal import Decimal as D
+
+
+usetunable = True
+show_tunable_descriptions = False
+alternate_tunable_layout = False
+kstat_pobj = re.compile("^([^:]+):\s+(.+)\s*$", flags=re.M)
+
+
+def get_Kstat():
+    def load_proc_kstats(fn, namespace):
+        kstats = [line.strip() for line in open(fn)]
+        del kstats[0:2]
+        for kstat in kstats:
+            kstat = kstat.strip()
+            name, unused, value = kstat.split()
+            Kstat[namespace + name] = D(value)
+
+    Kstat = {}
+    load_proc_kstats('/proc/spl/kstat/zfs/arcstats',
+                     'kstat.zfs.misc.arcstats.')
+    load_proc_kstats('/proc/spl/kstat/zfs/zfetchstats',
+                     'kstat.zfs.misc.zfetchstats.')
+    load_proc_kstats('/proc/spl/kstat/zfs/vdev_cache_stats',
+                     'kstat.zfs.misc.vdev_cache_stats.')
+
+    return Kstat
+
+
+def div1():
+    sys.stdout.write("\n")
+    for i in range(18):
+        sys.stdout.write("%s" % "----")
+    sys.stdout.write("\n")
+
+
+def div2():
+    sys.stdout.write("\n")
+
+
+def fBytes(Bytes=0, Decimal=2):
+    kbytes = (2 ** 10)
+    mbytes = (2 ** 20)
+    gbytes = (2 ** 30)
+    tbytes = (2 ** 40)
+    pbytes = (2 ** 50)
+    ebytes = (2 ** 60)
+    zbytes = (2 ** 70)
+    ybytes = (2 ** 80)
+
+    if Bytes >= ybytes:
+        return str("%0." + str(Decimal) + "f") % (Bytes / ybytes) + "\tYiB"
+    elif Bytes >= zbytes:
+        return str("%0." + str(Decimal) + "f") % (Bytes / zbytes) + "\tZiB"
+    elif Bytes >= ebytes:
+        return str("%0." + str(Decimal) + "f") % (Bytes / ebytes) + "\tEiB"
+    elif Bytes >= pbytes:
+        return str("%0." + str(Decimal) + "f") % (Bytes / pbytes) + "\tPiB"
+    elif Bytes >= tbytes:
+        return str("%0." + str(Decimal) + "f") % (Bytes / tbytes) + "\tTiB"
+    elif Bytes >= gbytes:
+        return str("%0." + str(Decimal) + "f") % (Bytes / gbytes) + "\tGiB"
+    elif Bytes >= mbytes:
+        return str("%0." + str(Decimal) + "f") % (Bytes / mbytes) + "\tMiB"
+    elif Bytes >= kbytes:
+        return str("%0." + str(Decimal) + "f") % (Bytes / kbytes) + "\tKiB"
+    elif Bytes == 0:
+        return str("%d" % 0) + "\tBytes"
+    else:
+        return str("%d" % Bytes) + "\tBytes"
+
+
+def fHits(Hits=0, Decimal=2):
+    khits = (10 ** 3)
+    mhits = (10 ** 6)
+    bhits = (10 ** 9)
+    thits = (10 ** 12)
+    qhits = (10 ** 15)
+    Qhits = (10 ** 18)
+    shits = (10 ** 21)
+    Shits = (10 ** 24)
+
+    if Hits >= Shits:
+        return str("%0." + str(Decimal) + "f") % (Hits / Shits) + "S"
+    elif Hits >= shits:
+        return str("%0." + str(Decimal) + "f") % (Hits / shits) + "s"
+    elif Hits >= Qhits:
+        return str("%0." + str(Decimal) + "f") % (Hits / Qhits) + "Q"
+    elif Hits >= qhits:
+        return str("%0." + str(Decimal) + "f") % (Hits / qhits) + "q"
+    elif Hits >= thits:
+        return str("%0." + str(Decimal) + "f") % (Hits / thits) + "t"
+    elif Hits >= bhits:
+        return str("%0." + str(Decimal) + "f") % (Hits / bhits) + "b"
+    elif Hits >= mhits:
+        return str("%0." + str(Decimal) + "f") % (Hits / mhits) + "m"
+    elif Hits >= khits:
+        return str("%0." + str(Decimal) + "f") % (Hits / khits) + "k"
+    elif Hits == 0:
+        return str("%d" % 0)
+    else:
+        return str("%d" % Hits)
+
+
+def fPerc(lVal=0, rVal=0, Decimal=2):
+    if rVal > 0:
+        return str("%0." + str(Decimal) + "f") % (100 * (lVal / rVal)) + "%"
+    else:
+        return str("%0." + str(Decimal) + "f") % 100 + "%"
+
+
+def get_arc_summary(Kstat):
+
+    output = {}
+    memory_throttle_count = Kstat[
+        "kstat.zfs.misc.arcstats.memory_throttle_count"
+        ]
+
+    if memory_throttle_count > 0:
+        output['health'] = 'THROTTLED'
+    else:
+        output['health'] = 'HEALTHY'
+
+    output['memory_throttle_count'] = fHits(memory_throttle_count)
+
+    # ARC Misc.
+    deleted = Kstat["kstat.zfs.misc.arcstats.deleted"]
+    mutex_miss = Kstat["kstat.zfs.misc.arcstats.mutex_miss"]
+
+    # ARC Misc.
+    output["arc_misc"] = {}
+    output["arc_misc"]["deleted"] = fHits(deleted)
+    output["arc_misc"]['mutex_miss'] = fHits(mutex_miss)
+    output["arc_misc"]['evict_skips'] = fHits(mutex_miss)
+
+    # ARC Sizing
+    arc_size = Kstat["kstat.zfs.misc.arcstats.size"]
+    mru_size = Kstat["kstat.zfs.misc.arcstats.p"]
+    target_max_size = Kstat["kstat.zfs.misc.arcstats.c_max"]
+    target_min_size = Kstat["kstat.zfs.misc.arcstats.c_min"]
+    target_size = Kstat["kstat.zfs.misc.arcstats.c"]
+
+    target_size_ratio = (target_max_size / target_min_size)
+
+    # ARC Sizing
+    output['arc_sizing'] = {}
+    output['arc_sizing']['arc_size'] = {
+        'per': fPerc(arc_size, target_max_size),
+        'num': fBytes(arc_size),
+    }
+    output['arc_sizing']['target_max_size'] = {
+        'ratio': target_size_ratio,
+        'num': fBytes(target_max_size),
+    }
+    output['arc_sizing']['target_min_size'] = {
+        'per': fPerc(target_min_size, target_max_size),
+        'num': fBytes(target_min_size),
+    }
+    output['arc_sizing']['target_size'] = {
+        'per': fPerc(target_size, target_max_size),
+        'num': fBytes(target_size),
+    }
+
+    # ARC Hash Breakdown
+    output['arc_hash_break'] = {}
+    output['arc_hash_break']['hash_chain_max'] = Kstat[
+        "kstat.zfs.misc.arcstats.hash_chain_max"
+        ]
+    output['arc_hash_break']['hash_chains'] = Kstat[
+        "kstat.zfs.misc.arcstats.hash_chains"
+        ]
+    output['arc_hash_break']['hash_collisions'] = Kstat[
+        "kstat.zfs.misc.arcstats.hash_collisions"
+        ]
+    output['arc_hash_break']['hash_elements'] = Kstat[
+        "kstat.zfs.misc.arcstats.hash_elements"
+        ]
+    output['arc_hash_break']['hash_elements_max'] = Kstat[
+        "kstat.zfs.misc.arcstats.hash_elements_max"
+        ]
+
+    output['arc_size_break'] = {}
+    if arc_size > target_size:
+        mfu_size = (arc_size - mru_size)
+        output['arc_size_break']['recently_used_cache_size'] = {
+            'per': fPerc(mru_size, arc_size),
+            'num': fBytes(mru_size),
+        }
+        output['arc_size_break']['frequently_used_cache_size'] = {
+            'per': fPerc(mfu_size, arc_size),
+            'num': fBytes(mfu_size),
+        }
+
+    elif arc_size < target_size:
+        mfu_size = (target_size - mru_size)
+        output['arc_size_break']['recently_used_cache_size'] = {
+            'per': fPerc(mru_size, target_size),
+            'num': fBytes(mru_size),
+        }
+        output['arc_size_break']['frequently_used_cache_size'] = {
+            'per': fPerc(mfu_size, target_size),
+            'num': fBytes(mfu_size),
+        }
+
+    # ARC Hash Breakdown
+    hash_chain_max = Kstat["kstat.zfs.misc.arcstats.hash_chain_max"]
+    hash_chains = Kstat["kstat.zfs.misc.arcstats.hash_chains"]
+    hash_collisions = Kstat["kstat.zfs.misc.arcstats.hash_collisions"]
+    hash_elements = Kstat["kstat.zfs.misc.arcstats.hash_elements"]
+    hash_elements_max = Kstat["kstat.zfs.misc.arcstats.hash_elements_max"]
+
+    output['arc_hash_break'] = {}
+    output['arc_hash_break']['elements_max'] = fHits(hash_elements_max)
+    output['arc_hash_break']['elements_current'] = {
+        'per': fPerc(hash_elements, hash_elements_max),
+        'num': fHits(hash_elements),
+        }
+    output['arc_hash_break']['collisions'] = fHits(hash_collisions)
+    output['arc_hash_break']['chain_max'] = fHits(hash_chain_max)
+    output['arc_hash_break']['chains'] = fHits(hash_chains)
+
+    return output
+
+
+def _arc_summary(Kstat):
+    # ARC Sizing
+    arc = get_arc_summary(Kstat)
+
+    sys.stdout.write("ARC Summary: (%s)\n" % arc['health'])
+
+    sys.stdout.write("\tMemory Throttle Count:\t\t\t%s\n" %
+                     arc['memory_throttle_count'])
+    sys.stdout.write("\n")
+
+    # ARC Misc.
+    sys.stdout.write("ARC Misc:\n")
+    sys.stdout.write("\tDeleted:\t\t\t\t%s\n" % arc['arc_misc']['deleted'])
+    sys.stdout.write("\tMutex Misses:\t\t\t\t%s\n" %
+                     arc['arc_misc']['mutex_miss'])
+    sys.stdout.write("\tEvict Skips:\t\t\t\t%s\n" %
+                     arc['arc_misc']['mutex_miss'])
+    sys.stdout.write("\n")
+
+    # ARC Sizing
+    sys.stdout.write("ARC Size:\t\t\t\t%s\t%s\n" % (
+        arc['arc_sizing']['arc_size']['per'],
+        arc['arc_sizing']['arc_size']['num']
+        )
+    )
+    sys.stdout.write("\tTarget Size: (Adaptive)\t\t%s\t%s\n" % (
+        arc['arc_sizing']['target_size']['per'],
+        arc['arc_sizing']['target_size']['num'],
+        )
+    )
+
+    sys.stdout.write("\tMin Size (Hard Limit):\t\t%s\t%s\n" % (
+        arc['arc_sizing']['target_min_size']['per'],
+        arc['arc_sizing']['target_min_size']['num'],
+        )
+    )
+
+    sys.stdout.write("\tMax Size (High Water):\t\t%d:1\t%s\n" % (
+        arc['arc_sizing']['target_max_size']['ratio'],
+        arc['arc_sizing']['target_max_size']['num'],
+        )
+    )
+
+    sys.stdout.write("\nARC Size Breakdown:\n")
+    sys.stdout.write("\tRecently Used Cache Size:\t%s\t%s\n" % (
+        arc['arc_size_break']['recently_used_cache_size']['per'],
+        arc['arc_size_break']['recently_used_cache_size']['num'],
+        )
+    )
+    sys.stdout.write("\tFrequently Used Cache Size:\t%s\t%s\n" % (
+        arc['arc_size_break']['frequently_used_cache_size']['per'],
+        arc['arc_size_break']['frequently_used_cache_size']['num'],
+        )
+    )
+
+    sys.stdout.write("\n")
+
+    # ARC Hash Breakdown
+    sys.stdout.write("ARC Hash Breakdown:\n")
+    sys.stdout.write("\tElements Max:\t\t\t\t%s\n" %
+                     arc['arc_hash_break']['elements_max'])
+    sys.stdout.write("\tElements Current:\t\t%s\t%s\n" % (
+        arc['arc_hash_break']['elements_current']['per'],
+        arc['arc_hash_break']['elements_current']['num'],
+        )
+    )
+    sys.stdout.write("\tCollisions:\t\t\t\t%s\n" %
+                     arc['arc_hash_break']['collisions'])
+    sys.stdout.write("\tChain Max:\t\t\t\t%s\n" %
+                     arc['arc_hash_break']['chain_max'])
+    sys.stdout.write("\tChains:\t\t\t\t\t%s\n" %
+                     arc['arc_hash_break']['chains'])
+
+
+def get_arc_efficiency(Kstat):
+    output = {}
+
+    arc_hits = Kstat["kstat.zfs.misc.arcstats.hits"]
+    arc_misses = Kstat["kstat.zfs.misc.arcstats.misses"]
+    demand_data_hits = Kstat["kstat.zfs.misc.arcstats.demand_data_hits"]
+    demand_data_misses = Kstat["kstat.zfs.misc.arcstats.demand_data_misses"]
+    demand_metadata_hits = Kstat[
+        "kstat.zfs.misc.arcstats.demand_metadata_hits"
+        ]
+    demand_metadata_misses = Kstat[
+        "kstat.zfs.misc.arcstats.demand_metadata_misses"
+        ]
+    mfu_ghost_hits = Kstat["kstat.zfs.misc.arcstats.mfu_ghost_hits"]
+    mfu_hits = Kstat["kstat.zfs.misc.arcstats.mfu_hits"]
+    mru_ghost_hits = Kstat["kstat.zfs.misc.arcstats.mru_ghost_hits"]
+    mru_hits = Kstat["kstat.zfs.misc.arcstats.mru_hits"]
+    prefetch_data_hits = Kstat["kstat.zfs.misc.arcstats.prefetch_data_hits"]
+    prefetch_data_misses = Kstat[
+        "kstat.zfs.misc.arcstats.prefetch_data_misses"
+        ]
+    prefetch_metadata_hits = Kstat[
+        "kstat.zfs.misc.arcstats.prefetch_metadata_hits"
+        ]
+    prefetch_metadata_misses = Kstat[
+        "kstat.zfs.misc.arcstats.prefetch_metadata_misses"
+        ]
+
+    anon_hits = arc_hits - (
+        mfu_hits + mru_hits + mfu_ghost_hits + mru_ghost_hits
+        )
+    arc_accesses_total = (arc_hits + arc_misses)
+    demand_data_total = (demand_data_hits + demand_data_misses)
+    prefetch_data_total = (prefetch_data_hits + prefetch_data_misses)
+    real_hits = (mfu_hits + mru_hits)
+
+    output["total_accesses"] = fHits(arc_accesses_total)
+    output["cache_hit_ratio"] = {
+        'per': fPerc(arc_hits, arc_accesses_total),
+        'num': fHits(arc_hits),
+    }
+    output["cache_miss_ratio"] = {
+        'per': fPerc(arc_misses, arc_accesses_total),
+        'num': fHits(arc_misses),
+    }
+    output["actual_hit_ratio"] = {
+        'per': fPerc(real_hits, arc_accesses_total),
+        'num': fHits(real_hits),
+    }
+    output["data_demand_efficiency"] = {
+        'per': fPerc(demand_data_hits, demand_data_total),
+        'num': fHits(demand_data_total),
+    }
+
+    if prefetch_data_total > 0:
+        output["data_prefetch_efficiency"] = {
+            'per': fPerc(prefetch_data_hits, prefetch_data_total),
+            'num': fHits(prefetch_data_total),
+        }
+
+    if anon_hits > 0:
+        output["cache_hits_by_cache_list"] = {}
+        output["cache_hits_by_cache_list"]["anonymously_used"] = {
+            'per': fPerc(anon_hits, arc_hits),
+            'num': fHits(anon_hits),
+        }
+
+    output["most_recently_used"] = {
+        'per': fPerc(mru_hits, arc_hits),
+        'num': fHits(mru_hits),
+    }
+    output["most_frequently_used"] = {
+        'per': fPerc(mfu_hits, arc_hits),
+        'num': fHits(mfu_hits),
+    }
+    output["most_recently_used_ghost"] = {
+        'per': fPerc(mru_ghost_hits, arc_hits),
+        'num': fHits(mru_ghost_hits),
+    }
+    output["most_frequently_used_ghost"] = {
+        'per': fPerc(mfu_ghost_hits, arc_hits),
+        'num': fHits(mfu_ghost_hits),
+    }
+
+    output["cache_hits_by_data_type"] = {}
+    output["cache_hits_by_data_type"]["demand_data"] = {
+        'per': fPerc(demand_data_hits, arc_hits),
+        'num': fHits(demand_data_hits),
+    }
+    output["cache_hits_by_data_type"]["prefetch_data"] = {
+        'per': fPerc(prefetch_data_hits, arc_hits),
+        'num': fHits(prefetch_data_hits),
+    }
+    output["cache_hits_by_data_type"]["demand_metadata"] = {
+        'per': fPerc(demand_metadata_hits, arc_hits),
+        'num': fHits(demand_metadata_hits),
+    }
+    output["cache_hits_by_data_type"]["prefetch_metadata"] = {
+        'per': fPerc(prefetch_metadata_hits, arc_hits),
+        'num': fHits(prefetch_metadata_hits),
+    }
+
+    output["cache_misses_by_data_type"] = {}
+    output["cache_misses_by_data_type"]["demand_data"] = {
+        'per': fPerc(demand_data_misses, arc_misses),
+        'num': fHits(demand_data_misses),
+    }
+    output["cache_misses_by_data_type"]["prefetch_data"] = {
+        'per': fPerc(prefetch_data_misses, arc_misses),
+        'num': fHits(prefetch_data_misses),
+    }
+    output["cache_misses_by_data_type"]["demand_metadata"] = {
+        'per': fPerc(demand_metadata_misses, arc_misses),
+        'num': fHits(demand_metadata_misses),
+    }
+    output["cache_misses_by_data_type"]["prefetch_metadata"] = {
+        'per': fPerc(prefetch_metadata_misses, arc_misses),
+        'num': fHits(prefetch_metadata_misses),
+    }
+
+    return output
+
+
+def _arc_efficiency(Kstat):
+    arc = get_arc_efficiency(Kstat)
+
+    sys.stdout.write("ARC Total accesses:\t\t\t\t\t%s\n" %
+                     arc['total_accesses'])
+    sys.stdout.write("\tCache Hit Ratio:\t\t%s\t%s\n" % (
+        arc['cache_hit_ratio']['per'],
+        arc['cache_hit_ratio']['num'],
+        )
+    )
+    sys.stdout.write("\tCache Miss Ratio:\t\t%s\t%s\n" % (
+        arc['cache_miss_ratio']['per'],
+        arc['cache_miss_ratio']['num'],
+        )
+    )
+
+    sys.stdout.write("\tActual Hit Ratio:\t\t%s\t%s\n" % (
+        arc['actual_hit_ratio']['per'],
+        arc['actual_hit_ratio']['num'],
+        )
+    )
+
+    sys.stdout.write("\n")
+    sys.stdout.write("\tData Demand Efficiency:\t\t%s\t%s\n" % (
+        arc['data_demand_efficiency']['per'],
+        arc['data_demand_efficiency']['num'],
+        )
+    )
+
+    if 'data_prefetch_efficiency' in arc:
+        sys.stdout.write("\tData Prefetch Efficiency:\t%s\t%s\n" % (
+            arc['data_prefetch_efficiency']['per'],
+            arc['data_prefetch_efficiency']['num'],
+            )
+        )
+    sys.stdout.write("\n")
+
+    sys.stdout.write("\tCACHE HITS BY CACHE LIST:\n")
+    if 'cache_hits_by_cache_list' in arc:
+        sys.stdout.write("\t  Anonymously Used:\t\t%s\t%s\n" % (
+            arc['cache_hits_by_cache_list']['anonymously_used']['per'],
+            arc['cache_hits_by_cache_list']['anonymously_used']['num'],
+            )
+        )
+    sys.stdout.write("\t  Most Recently Used:\t\t%s\t%s\n" % (
+        arc['most_recently_used']['per'],
+        arc['most_recently_used']['num'],
+        )
+    )
+    sys.stdout.write("\t  Most Frequently Used:\t\t%s\t%s\n" % (
+        arc['most_frequently_used']['per'],
+        arc['most_frequently_used']['num'],
+        )
+    )
+    sys.stdout.write("\t  Most Recently Used Ghost:\t%s\t%s\n" % (
+        arc['most_recently_used_ghost']['per'],
+        arc['most_recently_used_ghost']['num'],
+        )
+    )
+    sys.stdout.write("\t  Most Frequently Used Ghost:\t%s\t%s\n" % (
+        arc['most_frequently_used_ghost']['per'],
+        arc['most_frequently_used_ghost']['num'],
+        )
+    )
+
+    sys.stdout.write("\n\tCACHE HITS BY DATA TYPE:\n")
+    sys.stdout.write("\t  Demand Data:\t\t\t%s\t%s\n" % (
+        arc["cache_hits_by_data_type"]['demand_data']['per'],
+        arc["cache_hits_by_data_type"]['demand_data']['num'],
+        )
+    )
+    sys.stdout.write("\t  Prefetch Data:\t\t%s\t%s\n" % (
+        arc["cache_hits_by_data_type"]['prefetch_data']['per'],
+        arc["cache_hits_by_data_type"]['prefetch_data']['num'],
+        )
+    )
+    sys.stdout.write("\t  Demand Metadata:\t\t%s\t%s\n" % (
+        arc["cache_hits_by_data_type"]['demand_metadata']['per'],
+        arc["cache_hits_by_data_type"]['demand_metadata']['num'],
+        )
+    )
+    sys.stdout.write("\t  Prefetch Metadata:\t\t%s\t%s\n" % (
+        arc["cache_hits_by_data_type"]['prefetch_metadata']['per'],
+        arc["cache_hits_by_data_type"]['prefetch_metadata']['num'],
+        )
+    )
+
+    sys.stdout.write("\n\tCACHE MISSES BY DATA TYPE:\n")
+    sys.stdout.write("\t  Demand Data:\t\t\t%s\t%s\n" % (
+        arc["cache_misses_by_data_type"]['demand_data']['per'],
+        arc["cache_misses_by_data_type"]['demand_data']['num'],
+        )
+    )
+    sys.stdout.write("\t  Prefetch Data:\t\t%s\t%s\n" % (
+        arc["cache_misses_by_data_type"]['prefetch_data']['per'],
+        arc["cache_misses_by_data_type"]['prefetch_data']['num'],
+        )
+    )
+    sys.stdout.write("\t  Demand Metadata:\t\t%s\t%s\n" % (
+        arc["cache_misses_by_data_type"]['demand_metadata']['per'],
+        arc["cache_misses_by_data_type"]['demand_metadata']['num'],
+        )
+    )
+    sys.stdout.write("\t  Prefetch Metadata:\t\t%s\t%s\n" % (
+        arc["cache_misses_by_data_type"]['prefetch_metadata']['per'],
+        arc["cache_misses_by_data_type"]['prefetch_metadata']['num'],
+        )
+    )
+
+
+def get_l2arc_summary(Kstat):
+    output = {}
+
+    l2_abort_lowmem = Kstat["kstat.zfs.misc.arcstats.l2_abort_lowmem"]
+    l2_cksum_bad = Kstat["kstat.zfs.misc.arcstats.l2_cksum_bad"]
+    l2_evict_lock_retry = Kstat["kstat.zfs.misc.arcstats.l2_evict_lock_retry"]
+    l2_evict_reading = Kstat["kstat.zfs.misc.arcstats.l2_evict_reading"]
+    l2_feeds = Kstat["kstat.zfs.misc.arcstats.l2_feeds"]
+    l2_free_on_write = Kstat["kstat.zfs.misc.arcstats.l2_free_on_write"]
+    l2_hdr_size = Kstat["kstat.zfs.misc.arcstats.l2_hdr_size"]
+    l2_hits = Kstat["kstat.zfs.misc.arcstats.l2_hits"]
+    l2_io_error = Kstat["kstat.zfs.misc.arcstats.l2_io_error"]
+    l2_misses = Kstat["kstat.zfs.misc.arcstats.l2_misses"]
+    l2_rw_clash = Kstat["kstat.zfs.misc.arcstats.l2_rw_clash"]
+    l2_size = Kstat["kstat.zfs.misc.arcstats.l2_size"]
+    l2_asize = Kstat["kstat.zfs.misc.arcstats.l2_asize"]
+    l2_writes_done = Kstat["kstat.zfs.misc.arcstats.l2_writes_done"]
+    l2_writes_error = Kstat["kstat.zfs.misc.arcstats.l2_writes_error"]
+    l2_writes_sent = Kstat["kstat.zfs.misc.arcstats.l2_writes_sent"]
+
+    l2_access_total = (l2_hits + l2_misses)
+    output['l2_health_count'] = (l2_writes_error + l2_cksum_bad + l2_io_error)
+
+    output['l2_access_total'] = l2_access_total
+    output['l2_size'] = l2_size
+    output['l2_asize'] = l2_asize
+
+    if l2_size > 0 and l2_access_total > 0:
+
+        if output['l2_health_count'] > 0:
+            output["health"] = "DEGRADED"
+        else:
+            output["health"] = "HEALTHY"
+
+        output["low_memory_aborts"] = fHits(l2_abort_lowmem)
+        output["free_on_write"] = fHits(l2_free_on_write)
+        output["rw_clashes"] = fHits(l2_rw_clash)
+        output["bad_checksums"] = fHits(l2_cksum_bad)
+        output["io_errors"] = fHits(l2_io_error)
+
+        output["l2_arc_size"] = {}
+        output["l2_arc_size"]["adative"] = fBytes(l2_size)
+        output["l2_arc_size"]["actual"] = {
+            'per': fPerc(l2_asize, l2_size),
+            'num': fBytes(l2_asize)
+            }
+        output["l2_arc_size"]["head_size"] = {
+            'per': fPerc(l2_hdr_size, l2_size),
+            'num': fBytes(l2_hdr_size),
+        }
+
+        output["l2_arc_evicts"] = {}
+        output["l2_arc_evicts"]['lock_retries'] = fHits(l2_evict_lock_retry)
+        output["l2_arc_evicts"]['reading'] = fHits(l2_evict_reading)
+
+        output['l2_arc_breakdown'] = {}
+        output['l2_arc_breakdown']['value'] = fHits(l2_access_total)
+        output['l2_arc_breakdown']['hit_ratio'] = {
+            'per': fPerc(l2_hits, l2_access_total),
+            'num': fHits(l2_hits),
+        }
+        output['l2_arc_breakdown']['miss_ratio'] = {
+            'per': fPerc(l2_misses, l2_access_total),
+            'num': fHits(l2_misses),
+        }
+        output['l2_arc_breakdown']['feeds'] = fHits(l2_feeds)
+
+        output['l2_arc_buffer'] = {}
+
+        output['l2_arc_writes'] = {}
+        output['l2_writes_done'] = l2_writes_done
+        output['l2_writes_sent'] = l2_writes_sent
+        if l2_writes_done != l2_writes_sent:
+            output['l2_arc_writes']['writes_sent'] = {
+                'value': "FAULTED",
+                'num': fHits(l2_writes_sent),
+            }
+            output['l2_arc_writes']['done_ratio'] = {
+                'per': fPerc(l2_writes_done, l2_writes_sent),
+                'num': fHits(l2_writes_done),
+            }
+            output['l2_arc_writes']['error_ratio'] = {
+                'per': fPerc(l2_writes_error, l2_writes_sent),
+                'num': fHits(l2_writes_error),
+            }
+        else:
+            output['l2_arc_writes']['writes_sent'] = {
+                'per': fPerc(100),
+                'num': fHits(l2_writes_sent),
+            }
+
+    return output
+
+
+def _l2arc_summary(Kstat):
+
+    arc = get_l2arc_summary(Kstat)
+
+    if arc['l2_size'] > 0 and arc['l2_access_total'] > 0:
+        sys.stdout.write("L2 ARC Summary: ")
+        if arc['l2_health_count'] > 0:
+            sys.stdout.write("(DEGRADED)\n")
+        else:
+            sys.stdout.write("(HEALTHY)\n")
+        sys.stdout.write("\tLow Memory Aborts:\t\t\t%s\n" %
+                         arc['low_memory_aborts'])
+        sys.stdout.write("\tFree on Write:\t\t\t\t%s\n" % arc['free_on_write'])
+        sys.stdout.write("\tR/W Clashes:\t\t\t\t%s\n" % arc['rw_clashes'])
+        sys.stdout.write("\tBad Checksums:\t\t\t\t%s\n" % arc['bad_checksums'])
+        sys.stdout.write("\tIO Errors:\t\t\t\t%s\n" % arc['io_errors'])
+        sys.stdout.write("\n")
+
+        sys.stdout.write("L2 ARC Size: (Adaptive)\t\t\t\t%s\n" %
+                         arc["l2_arc_size"]["adative"])
+        sys.stdout.write("\tCompressed:\t\t\t%s\t%s\n" % (
+            arc["l2_arc_size"]["actual"]["per"],
+            arc["l2_arc_size"]["actual"]["num"],
+            )
+        )
+        sys.stdout.write("\tHeader Size:\t\t\t%s\t%s\n" % (
+            arc["l2_arc_size"]["head_size"]["per"],
+            arc["l2_arc_size"]["head_size"]["num"],
+            )
+        )
+        sys.stdout.write("\n")
+
+        if arc["l2_arc_evicts"]['lock_retries'] + \
+                arc["l2_arc_evicts"]["reading"] > 0:
+            sys.stdout.write("L2 ARC Evicts:\n")
+            sys.stdout.write("\tLock Retries:\t\t\t\t%s\n" %
+                             arc["l2_arc_evicts"]['lock_retries'])
+            sys.stdout.write("\tUpon Reading:\t\t\t\t%s\n" %
+                             arc["l2_arc_evicts"]["reading"])
+            sys.stdout.write("\n")
+
+        sys.stdout.write("L2 ARC Breakdown:\t\t\t\t%s\n" %
+                         arc['l2_arc_breakdown']['value'])
+        sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
+            arc['l2_arc_breakdown']['hit_ratio']['per'],
+            arc['l2_arc_breakdown']['hit_ratio']['num'],
+            )
+        )
+
+        sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
+            arc['l2_arc_breakdown']['miss_ratio']['per'],
+            arc['l2_arc_breakdown']['miss_ratio']['num'],
+            )
+        )
+
+        sys.stdout.write("\tFeeds:\t\t\t\t\t%s\n" %
+                         arc['l2_arc_breakdown']['feeds'])
+        sys.stdout.write("\n")
+
+        sys.stdout.write("L2 ARC Writes:\n")
+        if arc['l2_writes_done'] != arc['l2_writes_sent']:
+            sys.stdout.write("\tWrites Sent: (%s)\t\t\t\t%s\n" % (
+                arc['l2_arc_writes']['writes_sent']['value'],
+                arc['l2_arc_writes']['writes_sent']['num'],
+                )
+            )
+            sys.stdout.write("\t  Done Ratio:\t\t\t%s\t%s\n" % (
+                arc['l2_arc_writes']['done_ratio']['per'],
+                arc['l2_arc_writes']['done_ratio']['num'],
+                )
+            )
+            sys.stdout.write("\t  Error Ratio:\t\t\t%s\t%s\n" % (
+                arc['l2_arc_writes']['error_ratio']['per'],
+                arc['l2_arc_writes']['error_ratio']['num'],
+                )
+            )
+        else:
+            sys.stdout.write("\tWrites Sent:\t\t\t%s\t%s\n" % (
+                arc['l2_arc_writes']['writes_sent']['per'],
+                arc['l2_arc_writes']['writes_sent']['num'],
+                )
+            )
+
+
+def get_dmu_summary(Kstat):
+    output = {}
+
+    zfetch_hits = Kstat["kstat.zfs.misc.zfetchstats.hits"]
+    zfetch_misses = Kstat["kstat.zfs.misc.zfetchstats.misses"]
+
+    zfetch_access_total = (zfetch_hits + zfetch_misses)
+    output['zfetch_access_total'] = zfetch_access_total
+
+    if zfetch_access_total > 0:
+        output['dmu'] = {}
+        output['dmu']['efficiency'] = {}
+        output['dmu']['efficiency']['value'] = fHits(zfetch_access_total)
+        output['dmu']['efficiency']['hit_ratio'] = {
+            'per': fPerc(zfetch_hits, zfetch_access_total),
+            'num': fHits(zfetch_hits),
+        }
+        output['dmu']['efficiency']['miss_ratio'] = {
+            'per': fPerc(zfetch_misses, zfetch_access_total),
+            'num': fHits(zfetch_misses),
+        }
+
+    return output
+
+
+def _dmu_summary(Kstat):
+
+    arc = get_dmu_summary(Kstat)
+
+    if arc['zfetch_access_total'] > 0:
+        sys.stdout.write("DMU Prefetch Efficiency:\t\t\t\t\t%s\n" %
+                         arc['dmu']['efficiency']['value'])
+        sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
+            arc['dmu']['efficiency']['hit_ratio']['per'],
+            arc['dmu']['efficiency']['hit_ratio']['num'],
+            )
+        )
+        sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
+            arc['dmu']['efficiency']['miss_ratio']['per'],
+            arc['dmu']['efficiency']['miss_ratio']['num'],
+            )
+        )
+
+        sys.stdout.write("\n")
+
+
+def get_vdev_summary(Kstat):
+    output = {}
+
+    vdev_cache_delegations = \
+        Kstat["kstat.zfs.misc.vdev_cache_stats.delegations"]
+    vdev_cache_misses = Kstat["kstat.zfs.misc.vdev_cache_stats.misses"]
+    vdev_cache_hits = Kstat["kstat.zfs.misc.vdev_cache_stats.hits"]
+    vdev_cache_total = (vdev_cache_misses + vdev_cache_hits +
+                        vdev_cache_delegations)
+
+    output['vdev_cache_total'] = vdev_cache_total
+
+    if vdev_cache_total > 0:
+        output['summary'] = fHits(vdev_cache_total)
+        output['hit_ratio'] = {
+            'per': fPerc(vdev_cache_hits, vdev_cache_total),
+            'num': fHits(vdev_cache_hits),
+        }
+        output['miss_ratio'] = {
+            'per': fPerc(vdev_cache_misses, vdev_cache_total),
+            'num': fHits(vdev_cache_misses),
+        }
+        output['delegations'] = {
+            'per': fPerc(vdev_cache_delegations, vdev_cache_total),
+            'num': fHits(vdev_cache_delegations),
+        }
+
+    return output
+
+
+def _vdev_summary(Kstat):
+    arc = get_vdev_summary(Kstat)
+
+    if arc['vdev_cache_total'] > 0:
+        sys.stdout.write("VDEV Cache Summary:\t\t\t\t%s\n" % arc['summary'])
+        sys.stdout.write("\tHit Ratio:\t\t\t%s\t%s\n" % (
+            arc['hit_ratio']['per'],
+            arc['hit_ratio']['num'],
+        ))
+        sys.stdout.write("\tMiss Ratio:\t\t\t%s\t%s\n" % (
+            arc['miss_ratio']['per'],
+            arc['miss_ratio']['num'],
+        ))
+        sys.stdout.write("\tDelegations:\t\t\t%s\t%s\n" % (
+            arc['delegations']['per'],
+            arc['delegations']['num'],
+        ))
+
+
+def _tunable_summary(Kstat):
+    global show_tunable_descriptions
+    global alternate_tunable_layout
+
+    names = listdir("/sys/module/zfs/parameters/")
+
+    values = {}
+    for name in names:
+        with open("/sys/module/zfs/parameters/" + name) as f:
+            value = f.read()
+        values[name] = value.strip()
+
+    descriptions = {}
+
+    if show_tunable_descriptions:
+        try:
+            command = ["/sbin/modinfo", "zfs", "-0"]
+            p = Popen(command, stdin=PIPE, stdout=PIPE,
+                      stderr=PIPE, shell=False, close_fds=True)
+            p.wait()
+
+            description_list = p.communicate()[0].strip().split('\0')
+
+            if p.returncode == 0:
+                for tunable in description_list:
+                    if tunable[0:5] == 'parm:':
+                        tunable = tunable[5:].strip()
+                        name, description = tunable.split(':', 1)
+                        if not description:
+                            description = "Description unavailable"
+                        descriptions[name] = description
+            else:
+                sys.stderr.write("%s: '%s' exited with code %i\n" %
+                                 (sys.argv[0], command[0], p.returncode))
+                sys.stderr.write("Tunable descriptions will be disabled.\n")
+        except OSError as e:
+            sys.stderr.write("%s: Cannot run '%s': %s\n" %
+                             (sys.argv[0], command[0], e.strerror))
+            sys.stderr.write("Tunable descriptions will be disabled.\n")
+
+    sys.stdout.write("ZFS Tunable:\n")
+    for name in names:
+        if not name:
+            continue
+
+        format = "\t%-50s%s\n"
+        if alternate_tunable_layout:
+            format = "\t%s=%s\n"
+
+        if show_tunable_descriptions and name in descriptions:
+            sys.stdout.write("\t# %s\n" % descriptions[name])
+
+        sys.stdout.write(format % (name, values[name]))
+
+
+unSub = [
+    _arc_summary,
+    _arc_efficiency,
+    _l2arc_summary,
+    _dmu_summary,
+    _vdev_summary,
+    _tunable_summary
+]
+
+
+def zfs_header():
+    daydate = time.strftime("%a %b %d %H:%M:%S %Y")
+
+    div1()
+    sys.stdout.write("ZFS Subsystem Report\t\t\t\t%s" % daydate)
+    div2()
+
+
+def usage():
+    sys.stdout.write("Usage: arc_summary.py [-h] [-a] [-d] [-p PAGE]\n\n")
+    sys.stdout.write("\t -h, --help           : "
+                     "Print this help message and exit\n")
+    sys.stdout.write("\t -a, --alternate      : "
+                     "Show an alternate sysctl layout\n")
+    sys.stdout.write("\t -d, --description    : "
+                     "Show the sysctl descriptions\n")
+    sys.stdout.write("\t -p PAGE, --page=PAGE : "
+                     "Select a single output page to display,\n")
+    sys.stdout.write("\t                        "
+                     "should be an integer between 1 and " +
+                     str(len(unSub)) + "\n\n")
+    sys.stdout.write("Examples:\n")
+    sys.stdout.write("\tarc_summary.py -a\n")
+    sys.stdout.write("\tarc_summary.py -p 4\n")
+    sys.stdout.write("\tarc_summary.py -ad\n")
+    sys.stdout.write("\tarc_summary.py --page=2\n")
+
+
+def main():
+    global show_tunable_descriptions
+    global alternate_tunable_layout
+
+    opts, args = getopt.getopt(
+        sys.argv[1:], "adp:h", ["alternate", "description", "page=", "help"]
+    )
+
+    args = {}
+    for opt, arg in opts:
+        if opt in ('-a', '--alternate'):
+            args['a'] = True
+        if opt in ('-d', '--description'):
+            args['d'] = True
+        if opt in ('-p', '--page'):
+            args['p'] = arg
+        if opt in ('-h', '--help'):
+            usage()
+            sys.exit()
+
+    Kstat = get_Kstat()
+
+    alternate_tunable_layout = 'a' in args
+    show_tunable_descriptions = 'd' in args
+
+    pages = []
+
+    if 'p' in args:
+        try:
+            pages.append(unSub[int(args['p']) - 1])
+        except IndexError:
+            sys.stderr.write('the argument to -p must be between 1 and ' +
+                             str(len(unSub)) + '\n')
+            sys.exit()
+    else:
+        pages = unSub
+
+    zfs_header()
+    for page in pages:
+        page(Kstat)
+        div2()
+
+if __name__ == '__main__':
+    main()
diff --git a/zfs/cmd/arcstat/Makefile.am b/zfs/cmd/arcstat/Makefile.am
new file mode 100644 (file)
index 0000000..8987b24
--- /dev/null
@@ -0,0 +1 @@
+dist_bin_SCRIPTS = arcstat.py
diff --git a/zfs/cmd/arcstat/Makefile.in b/zfs/cmd/arcstat/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/arcstat/arcstat.py b/zfs/cmd/arcstat/arcstat.py
new file mode 100755 (executable)
index 0000000..b743fd8
--- /dev/null
@@ -0,0 +1,462 @@
+#!/usr/bin/python
+#
+# Print out ZFS ARC Statistics exported via kstat(1)
+# For a definition of fields, or usage, use arctstat.pl -v
+#
+# This script is a fork of the original arcstat.pl (0.1) by
+# Neelakanth Nadgir, originally published on his Sun blog on
+# 09/18/2007
+#     http://blogs.sun.com/realneel/entry/zfs_arc_statistics
+#
+# This version aims to improve upon the original by adding features
+# and fixing bugs as needed.  This version is maintained by
+# Mike Harsch and is hosted in a public open source repository:
+#    http://github.com/mharsch/arcstat
+#
+# Comments, Questions, or Suggestions are always welcome.
+# Contact the maintainer at ( mike at harschsystems dot com )
+#
+# 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
+#
+#
+# Fields have a fixed width. Every interval, we fill the "v"
+# hash with its corresponding value (v[field]=value) using calculate().
+# @hdr is the array of fields that needs to be printed, so we
+# just iterate over this array and print the values using our pretty printer.
+#
+
+
+import sys
+import time
+import getopt
+import re
+import copy
+
+from decimal import Decimal
+from signal import signal, SIGINT, SIGWINCH, SIG_DFL
+
+cols = {
+    # HDR:        [Size, Scale, Description]
+    "time":       [8, -1, "Time"],
+    "hits":       [4, 1000, "ARC reads per second"],
+    "miss":       [4, 1000, "ARC misses per second"],
+    "read":       [4, 1000, "Total ARC accesses per second"],
+    "hit%":       [4, 100, "ARC Hit percentage"],
+    "miss%":      [5, 100, "ARC miss percentage"],
+    "dhit":       [4, 1000, "Demand hits per second"],
+    "dmis":       [4, 1000, "Demand misses per second"],
+    "dh%":        [3, 100, "Demand hit percentage"],
+    "dm%":        [3, 100, "Demand miss percentage"],
+    "phit":       [4, 1000, "Prefetch hits per second"],
+    "pmis":       [4, 1000, "Prefetch misses per second"],
+    "ph%":        [3, 100, "Prefetch hits percentage"],
+    "pm%":        [3, 100, "Prefetch miss percentage"],
+    "mhit":       [4, 1000, "Metadata hits per second"],
+    "mmis":       [4, 1000, "Metadata misses per second"],
+    "mread":      [4, 1000, "Metadata accesses per second"],
+    "mh%":        [3, 100, "Metadata hit percentage"],
+    "mm%":        [3, 100, "Metadata miss percentage"],
+    "arcsz":      [5, 1024, "ARC Size"],
+    "c":          [4, 1024, "ARC Target Size"],
+    "mfu":        [4, 1000, "MFU List hits per second"],
+    "mru":        [4, 1000, "MRU List hits per second"],
+    "mfug":       [4, 1000, "MFU Ghost List hits per second"],
+    "mrug":       [4, 1000, "MRU Ghost List hits per second"],
+    "eskip":      [5, 1000, "evict_skip per second"],
+    "mtxmis":     [6, 1000, "mutex_miss per second"],
+    "dread":      [5, 1000, "Demand accesses per second"],
+    "pread":      [5, 1000, "Prefetch accesses per second"],
+    "l2hits":     [6, 1000, "L2ARC hits per second"],
+    "l2miss":     [6, 1000, "L2ARC misses per second"],
+    "l2read":     [6, 1000, "Total L2ARC accesses per second"],
+    "l2hit%":     [6, 100, "L2ARC access hit percentage"],
+    "l2miss%":    [7, 100, "L2ARC access miss percentage"],
+    "l2asize":    [7, 1024, "Actual (compressed) size of the L2ARC"],
+    "l2size":     [6, 1024, "Size of the L2ARC"],
+    "l2bytes":    [7, 1024, "bytes read per second from the L2ARC"],
+}
+
+v = {}
+hdr = ["time", "read", "miss", "miss%", "dmis", "dm%", "pmis", "pm%", "mmis",
+       "mm%", "arcsz", "c"]
+xhdr = ["time", "mfu", "mru", "mfug", "mrug", "eskip", "mtxmis", "dread",
+        "pread", "read"]
+sint = 1               # Default interval is 1 second
+count = 1              # Default count is 1
+hdr_intr = 20          # Print header every 20 lines of output
+opfile = None
+sep = "  "              # Default separator is 2 spaces
+version = "0.4"
+l2exist = False
+cmd = ("Usage: arcstat.py [-hvx] [-f fields] [-o file] [-s string] [interval "
+       "[count]]\n")
+cur = {}
+d = {}
+out = None
+kstat = None
+float_pobj = re.compile("^[0-9]+(\.[0-9]+)?$")
+
+
+def detailed_usage():
+    sys.stderr.write("%s\n" % cmd)
+    sys.stderr.write("Field definitions are as follows:\n")
+    for key in cols:
+        sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
+    sys.stderr.write("\n")
+
+    sys.exit(0)
+
+
+def usage():
+    sys.stderr.write("%s\n" % cmd)
+    sys.stderr.write("\t -h : Print this help message\n")
+    sys.stderr.write("\t -v : List all possible field headers and definitions"
+                     "\n")
+    sys.stderr.write("\t -x : Print extended stats\n")
+    sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
+    sys.stderr.write("\t -o : Redirect output to the specified file\n")
+    sys.stderr.write("\t -s : Override default field separator with custom "
+                     "character or string\n")
+    sys.stderr.write("\nExamples:\n")
+    sys.stderr.write("\tarcstat.py -o /tmp/a.log 2 10\n")
+    sys.stderr.write("\tarcstat.py -s \",\" -o /tmp/a.log 2 10\n")
+    sys.stderr.write("\tarcstat.py -v\n")
+    sys.stderr.write("\tarcstat.py -f time,hit%,dh%,ph%,mh% 1\n")
+    sys.stderr.write("\n")
+
+    sys.exit(1)
+
+
+def kstat_update():
+    global kstat
+
+    k = [line.strip() for line in open('/proc/spl/kstat/zfs/arcstats')]
+
+    if not k:
+        sys.exit(1)
+
+    del k[0:2]
+    kstat = {}
+
+    for s in k:
+        if not s:
+            continue
+
+        name, unused, value = s.split()
+        kstat[name] = Decimal(value)
+
+
+def snap_stats():
+    global cur
+    global kstat
+
+    prev = copy.deepcopy(cur)
+    kstat_update()
+
+    cur = kstat
+    for key in cur:
+        if re.match(key, "class"):
+            continue
+        if key in prev:
+            d[key] = cur[key] - prev[key]
+        else:
+            d[key] = cur[key]
+
+
+def prettynum(sz, scale, num=0):
+    suffix = [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
+    index = 0
+    save = 0
+
+    # Special case for date field
+    if scale == -1:
+        return "%s" % num
+
+    # Rounding error, return 0
+    elif 0 < num < 1:
+        num = 0
+
+    while num > scale and index < 5:
+        save = num
+        num = num / scale
+        index += 1
+
+    if index == 0:
+        return "%*d" % (sz, num)
+
+    if (save / scale) < 10:
+        return "%*.1f%s" % (sz - 1, num, suffix[index])
+    else:
+        return "%*d%s" % (sz - 1, num, suffix[index])
+
+
+def print_values():
+    global hdr
+    global sep
+    global v
+
+    for col in hdr:
+        sys.stdout.write("%s%s" % (
+            prettynum(cols[col][0], cols[col][1], v[col]),
+            sep
+        ))
+    sys.stdout.write("\n")
+
+
+def print_header():
+    global hdr
+    global sep
+
+    for col in hdr:
+        sys.stdout.write("%*s%s" % (cols[col][0], col, sep))
+    sys.stdout.write("\n")
+
+
+def get_terminal_lines():
+    try:
+        import fcntl
+        import termios
+        import struct
+        data = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, '1234')
+        sz = struct.unpack('hh', data)
+        return sz[0]
+    except:
+        pass
+
+
+def update_hdr_intr():
+    global hdr_intr
+
+    lines = get_terminal_lines()
+    if lines and lines > 3:
+        hdr_intr = lines - 3
+
+
+def resize_handler(signum, frame):
+    update_hdr_intr()
+
+
+def init():
+    global sint
+    global count
+    global hdr
+    global xhdr
+    global opfile
+    global sep
+    global out
+    global l2exist
+
+    desired_cols = None
+    xflag = False
+    hflag = False
+    vflag = False
+    i = 1
+
+    try:
+        opts, args = getopt.getopt(
+            sys.argv[1:],
+            "xo:hvs:f:",
+            [
+                "extended",
+                "outfile",
+                "help",
+                "verbose",
+                "seperator",
+                "columns"
+            ]
+        )
+    except getopt.error as msg:
+        sys.stderr.write(msg)
+        usage()
+        opts = None
+
+    for opt, arg in opts:
+        if opt in ('-x', '--extended'):
+            xflag = True
+        if opt in ('-o', '--outfile'):
+            opfile = arg
+            i += 1
+        if opt in ('-h', '--help'):
+            hflag = True
+        if opt in ('-v', '--verbose'):
+            vflag = True
+        if opt in ('-s', '--seperator'):
+            sep = arg
+            i += 1
+        if opt in ('-f', '--columns'):
+            desired_cols = arg
+            i += 1
+        i += 1
+
+    argv = sys.argv[i:]
+    sint = Decimal(argv[0]) if argv else sint
+    count = int(argv[1]) if len(argv) > 1 else count
+
+    if len(argv) > 1:
+        sint = Decimal(argv[0])
+        count = int(argv[1])
+
+    elif len(argv) > 0:
+        sint = Decimal(argv[0])
+        count = 0
+
+    if hflag or (xflag and desired_cols):
+        usage()
+
+    if vflag:
+        detailed_usage()
+
+    if xflag:
+        hdr = xhdr
+
+    update_hdr_intr()
+
+    # check if L2ARC exists
+    snap_stats()
+    l2_size = cur.get("l2_size")
+    if l2_size:
+        l2exist = True
+
+    if desired_cols:
+        hdr = desired_cols.split(",")
+
+        invalid = []
+        incompat = []
+        for ele in hdr:
+            if ele not in cols:
+                invalid.append(ele)
+            elif not l2exist and ele.startswith("l2"):
+                sys.stdout.write("No L2ARC Here\n%s\n" % ele)
+                incompat.append(ele)
+
+        if len(invalid) > 0:
+            sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
+            usage()
+
+        if len(incompat) > 0:
+            sys.stderr.write("Incompatible field specified! -- %s\n" %
+                             incompat)
+            usage()
+
+    if opfile:
+        try:
+            out = open(opfile, "w")
+            sys.stdout = out
+
+        except IOError:
+            sys.stderr.write("Cannot open %s for writing\n" % opfile)
+            sys.exit(1)
+
+
+def calculate():
+    global d
+    global v
+    global l2exist
+
+    v = dict()
+    v["time"] = time.strftime("%H:%M:%S", time.localtime())
+    v["hits"] = d["hits"] / sint
+    v["miss"] = d["misses"] / sint
+    v["read"] = v["hits"] + v["miss"]
+    v["hit%"] = 100 * v["hits"] / v["read"] if v["read"] > 0 else 0
+    v["miss%"] = 100 - v["hit%"] if v["read"] > 0 else 0
+
+    v["dhit"] = (d["demand_data_hits"] + d["demand_metadata_hits"]) / sint
+    v["dmis"] = (d["demand_data_misses"] + d["demand_metadata_misses"]) / sint
+
+    v["dread"] = v["dhit"] + v["dmis"]
+    v["dh%"] = 100 * v["dhit"] / v["dread"] if v["dread"] > 0 else 0
+    v["dm%"] = 100 - v["dh%"] if v["dread"] > 0 else 0
+
+    v["phit"] = (d["prefetch_data_hits"] + d["prefetch_metadata_hits"]) / sint
+    v["pmis"] = (d["prefetch_data_misses"] +
+                 d["prefetch_metadata_misses"]) / sint
+
+    v["pread"] = v["phit"] + v["pmis"]
+    v["ph%"] = 100 * v["phit"] / v["pread"] if v["pread"] > 0 else 0
+    v["pm%"] = 100 - v["ph%"] if v["pread"] > 0 else 0
+
+    v["mhit"] = (d["prefetch_metadata_hits"] +
+                 d["demand_metadata_hits"]) / sint
+    v["mmis"] = (d["prefetch_metadata_misses"] +
+                 d["demand_metadata_misses"]) / sint
+
+    v["mread"] = v["mhit"] + v["mmis"]
+    v["mh%"] = 100 * v["mhit"] / v["mread"] if v["mread"] > 0 else 0
+    v["mm%"] = 100 - v["mh%"] if v["mread"] > 0 else 0
+
+    v["arcsz"] = cur["size"]
+    v["c"] = cur["c"]
+    v["mfu"] = d["mfu_hits"] / sint
+    v["mru"] = d["mru_hits"] / sint
+    v["mrug"] = d["mru_ghost_hits"] / sint
+    v["mfug"] = d["mfu_ghost_hits"] / sint
+    v["eskip"] = d["evict_skip"] / sint
+    v["mtxmis"] = d["mutex_miss"] / sint
+
+    if l2exist:
+        v["l2hits"] = d["l2_hits"] / sint
+        v["l2miss"] = d["l2_misses"] / sint
+        v["l2read"] = v["l2hits"] + v["l2miss"]
+        v["l2hit%"] = 100 * v["l2hits"] / v["l2read"] if v["l2read"] > 0 else 0
+
+        v["l2miss%"] = 100 - v["l2hit%"] if v["l2read"] > 0 else 0
+        v["l2asize"] = cur["l2_asize"]
+        v["l2size"] = cur["l2_size"]
+        v["l2bytes"] = d["l2_read_bytes"] / sint
+
+
+def main():
+    global sint
+    global count
+    global hdr_intr
+
+    i = 0
+    count_flag = 0
+
+    init()
+    if count > 0:
+        count_flag = 1
+
+    signal(SIGINT, SIG_DFL)
+    signal(SIGWINCH, resize_handler)
+    while True:
+        if i == 0:
+            print_header()
+
+        snap_stats()
+        calculate()
+        print_values()
+
+        if count_flag == 1:
+            if count <= 1:
+                break
+            count -= 1
+
+        i = 0 if i >= hdr_intr else i + 1
+        time.sleep(sint)
+
+    if out:
+        out.close()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/zfs/cmd/dbufstat/Makefile.am b/zfs/cmd/dbufstat/Makefile.am
new file mode 100644 (file)
index 0000000..19bffb0
--- /dev/null
@@ -0,0 +1 @@
+dist_bin_SCRIPTS = dbufstat.py
diff --git a/zfs/cmd/dbufstat/Makefile.in b/zfs/cmd/dbufstat/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/dbufstat/dbufstat.py b/zfs/cmd/dbufstat/dbufstat.py
new file mode 100755 (executable)
index 0000000..ceb0160
--- /dev/null
@@ -0,0 +1,581 @@
+#!/usr/bin/python
+#
+# Print out statistics for all cached dmu buffers.  This information
+# is available through the dbufs kstat and may be post-processed as
+# needed by the script.
+#
+# 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 (C) 2013 Lawrence Livermore National Security, LLC.
+# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+#
+
+import sys
+import getopt
+import errno
+
+bhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize"]
+bxhdr = ["pool", "objset", "object", "level", "blkid", "offset", "dbsize",
+         "meta", "state", "dbholds", "list", "atype", "flags",
+         "count", "asize", "access", "mru", "gmru", "mfu", "gmfu", "l2",
+         "l2_dattr", "l2_asize", "l2_comp", "aholds", "dtype", "btype",
+         "data_bs", "meta_bs", "bsize", "lvls", "dholds", "blocks", "dsize"]
+bincompat = ["cached", "direct", "indirect", "bonus", "spill"]
+
+dhdr = ["pool", "objset", "object", "dtype", "cached"]
+dxhdr = ["pool", "objset", "object", "dtype", "btype", "data_bs", "meta_bs",
+         "bsize", "lvls", "dholds", "blocks", "dsize", "cached", "direct",
+         "indirect", "bonus", "spill"]
+dincompat = ["level", "blkid", "offset", "dbsize", "meta", "state", "dbholds",
+             "list", "atype", "flags", "count", "asize", "access",
+             "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr", "l2_asize",
+             "l2_comp", "aholds"]
+
+thdr = ["pool", "objset", "dtype", "cached"]
+txhdr = ["pool", "objset", "dtype", "cached", "direct", "indirect",
+         "bonus", "spill"]
+tincompat = ["object", "level", "blkid", "offset", "dbsize", "meta", "state",
+             "dbholds", "list", "atype", "flags", "count", "asize",
+             "access", "mru", "gmru", "mfu", "gmfu", "l2", "l2_dattr",
+             "l2_asize", "l2_comp", "aholds", "btype", "data_bs", "meta_bs",
+             "bsize", "lvls", "dholds", "blocks", "dsize"]
+
+cols = {
+    # hdr:        [size, scale, description]
+    "pool":       [15,   -1, "pool name"],
+    "objset":     [6,    -1, "dataset identification number"],
+    "object":     [10,   -1, "object number"],
+    "level":      [5,    -1, "indirection level of buffer"],
+    "blkid":      [8,    -1, "block number of buffer"],
+    "offset":     [12, 1024, "offset in object of buffer"],
+    "dbsize":     [7,  1024, "size of buffer"],
+    "meta":       [4,    -1, "is this buffer metadata?"],
+    "state":      [5,    -1, "state of buffer (read, cached, etc)"],
+    "dbholds":    [7,  1000, "number of holds on buffer"],
+    "list":       [4,    -1, "which ARC list contains this buffer"],
+    "atype":      [7,    -1, "ARC header type (data or metadata)"],
+    "flags":      [8,    -1, "ARC read flags"],
+    "count":      [5,    -1, "ARC data count"],
+    "asize":      [7,  1024, "size of this ARC buffer"],
+    "access":     [10,   -1, "time this ARC buffer was last accessed"],
+    "mru":        [5,  1000, "hits while on the ARC's MRU list"],
+    "gmru":       [5,  1000, "hits while on the ARC's MRU ghost list"],
+    "mfu":        [5,  1000, "hits while on the ARC's MFU list"],
+    "gmfu":       [5,  1000, "hits while on the ARC's MFU ghost list"],
+    "l2":         [5,  1000, "hits while on the L2ARC"],
+    "l2_dattr":   [8,    -1, "L2ARC disk address/offset"],
+    "l2_asize":   [8,  1024, "L2ARC alloc'd size (depending on compression)"],
+    "l2_comp":    [21,   -1, "L2ARC compression algorithm for buffer"],
+    "aholds":     [6,  1000, "number of holds on this ARC buffer"],
+    "dtype":      [27,   -1, "dnode type"],
+    "btype":      [27,   -1, "bonus buffer type"],
+    "data_bs":    [7,  1024, "data block size"],
+    "meta_bs":    [7,  1024, "metadata block size"],
+    "bsize":      [6,  1024, "bonus buffer size"],
+    "lvls":       [6,    -1, "number of indirection levels"],
+    "dholds":     [6,  1000, "number of holds on dnode"],
+    "blocks":     [8,  1000, "number of allocated blocks"],
+    "dsize":      [12, 1024, "size of dnode"],
+    "cached":     [6,  1024, "bytes cached for all blocks"],
+    "direct":     [6,  1024, "bytes cached for direct blocks"],
+    "indirect":   [8,  1024, "bytes cached for indirect blocks"],
+    "bonus":      [5,  1024, "bytes cached for bonus buffer"],
+    "spill":      [5,  1024, "bytes cached for spill block"],
+}
+
+hdr = None
+xhdr = None
+sep = "  "  # Default separator is 2 spaces
+cmd = ("Usage: dbufstat.py [-bdhrtvx] [-i file] [-f fields] [-o file] "
+       "[-s string]\n")
+raw = 0
+
+
+def print_incompat_helper(incompat):
+    cnt = 0
+    for key in sorted(incompat):
+        if cnt is 0:
+            sys.stderr.write("\t")
+        elif cnt > 8:
+            sys.stderr.write(",\n\t")
+            cnt = 0
+        else:
+            sys.stderr.write(", ")
+
+        sys.stderr.write("%s" % key)
+        cnt += 1
+
+    sys.stderr.write("\n\n")
+
+
+def detailed_usage():
+    sys.stderr.write("%s\n" % cmd)
+
+    sys.stderr.write("Field definitions incompatible with '-b' option:\n")
+    print_incompat_helper(bincompat)
+
+    sys.stderr.write("Field definitions incompatible with '-d' option:\n")
+    print_incompat_helper(dincompat)
+
+    sys.stderr.write("Field definitions incompatible with '-t' option:\n")
+    print_incompat_helper(tincompat)
+
+    sys.stderr.write("Field definitions are as follows:\n")
+    for key in sorted(cols.keys()):
+        sys.stderr.write("%11s : %s\n" % (key, cols[key][2]))
+    sys.stderr.write("\n")
+
+    sys.exit(0)
+
+
+def usage():
+    sys.stderr.write("%s\n" % cmd)
+    sys.stderr.write("\t -b : Print table of information for each dbuf\n")
+    sys.stderr.write("\t -d : Print table of information for each dnode\n")
+    sys.stderr.write("\t -h : Print this help message\n")
+    sys.stderr.write("\t -r : Print raw values\n")
+    sys.stderr.write("\t -t : Print table of information for each dnode type"
+                     "\n")
+    sys.stderr.write("\t -v : List all possible field headers and definitions"
+                     "\n")
+    sys.stderr.write("\t -x : Print extended stats\n")
+    sys.stderr.write("\t -i : Redirect input from the specified file\n")
+    sys.stderr.write("\t -f : Specify specific fields to print (see -v)\n")
+    sys.stderr.write("\t -o : Redirect output to the specified file\n")
+    sys.stderr.write("\t -s : Override default field separator with custom "
+                     "character or string\n")
+    sys.stderr.write("\nExamples:\n")
+    sys.stderr.write("\tdbufstat.py -d -o /tmp/d.log\n")
+    sys.stderr.write("\tdbufstat.py -t -s \",\" -o /tmp/t.log\n")
+    sys.stderr.write("\tdbufstat.py -v\n")
+    sys.stderr.write("\tdbufstat.py -d -f pool,object,objset,dsize,cached\n")
+    sys.stderr.write("\n")
+
+    sys.exit(1)
+
+
+def prettynum(sz, scale, num=0):
+    global raw
+
+    suffix = [' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']
+    index = 0
+    save = 0
+
+    if raw or scale == -1:
+        return "%*s" % (sz, num)
+
+    # Rounding error, return 0
+    elif 0 < num < 1:
+        num = 0
+
+    while num > scale and index < 5:
+        save = num
+        num = num / scale
+        index += 1
+
+    if index == 0:
+        return "%*d" % (sz, num)
+
+    if (save / scale) < 10:
+        return "%*.1f%s" % (sz - 1, num, suffix[index])
+    else:
+        return "%*d%s" % (sz - 1, num, suffix[index])
+
+
+def print_values(v):
+    global hdr
+    global sep
+
+    try:
+        for col in hdr:
+            sys.stdout.write("%s%s" % (
+                prettynum(cols[col][0], cols[col][1], v[col]), sep))
+        sys.stdout.write("\n")
+    except IOError as e:
+        if e.errno == errno.EPIPE:
+            sys.exit(1)
+
+
+def print_header():
+    global hdr
+    global sep
+
+    try:
+        for col in hdr:
+            sys.stdout.write("%*s%s" % (cols[col][0], col, sep))
+        sys.stdout.write("\n")
+    except IOError as e:
+        if e.errno == errno.EPIPE:
+            sys.exit(1)
+
+
+def get_typestring(t):
+    type_strings = ["DMU_OT_NONE",
+                    # general:
+                    "DMU_OT_OBJECT_DIRECTORY",
+                    "DMU_OT_OBJECT_ARRAY",
+                    "DMU_OT_PACKED_NVLIST",
+                    "DMU_OT_PACKED_NVLIST_SIZE",
+                    "DMU_OT_BPOBJ",
+                    "DMU_OT_BPOBJ_HDR",
+                    # spa:
+                    "DMU_OT_SPACE_MAP_HEADER",
+                    "DMU_OT_SPACE_MAP",
+                    # zil:
+                    "DMU_OT_INTENT_LOG",
+                    # dmu:
+                    "DMU_OT_DNODE",
+                    "DMU_OT_OBJSET",
+                    # dsl:
+                    "DMU_OT_DSL_DIR",
+                    "DMU_OT_DSL_DIR_CHILD_MAP",
+                    "DMU_OT_DSL_DS_SNAP_MAP",
+                    "DMU_OT_DSL_PROPS",
+                    "DMU_OT_DSL_DATASET",
+                    # zpl:
+                    "DMU_OT_ZNODE",
+                    "DMU_OT_OLDACL",
+                    "DMU_OT_PLAIN_FILE_CONTENTS",
+                    "DMU_OT_DIRECTORY_CONTENTS",
+                    "DMU_OT_MASTER_NODE",
+                    "DMU_OT_UNLINKED_SET",
+                    # zvol:
+                    "DMU_OT_ZVOL",
+                    "DMU_OT_ZVOL_PROP",
+                    # other; for testing only!
+                    "DMU_OT_PLAIN_OTHER",
+                    "DMU_OT_UINT64_OTHER",
+                    "DMU_OT_ZAP_OTHER",
+                    # new object types:
+                    "DMU_OT_ERROR_LOG",
+                    "DMU_OT_SPA_HISTORY",
+                    "DMU_OT_SPA_HISTORY_OFFSETS",
+                    "DMU_OT_POOL_PROPS",
+                    "DMU_OT_DSL_PERMS",
+                    "DMU_OT_ACL",
+                    "DMU_OT_SYSACL",
+                    "DMU_OT_FUID",
+                    "DMU_OT_FUID_SIZE",
+                    "DMU_OT_NEXT_CLONES",
+                    "DMU_OT_SCAN_QUEUE",
+                    "DMU_OT_USERGROUP_USED",
+                    "DMU_OT_USERGROUP_QUOTA",
+                    "DMU_OT_USERREFS",
+                    "DMU_OT_DDT_ZAP",
+                    "DMU_OT_DDT_STATS",
+                    "DMU_OT_SA",
+                    "DMU_OT_SA_MASTER_NODE",
+                    "DMU_OT_SA_ATTR_REGISTRATION",
+                    "DMU_OT_SA_ATTR_LAYOUTS",
+                    "DMU_OT_SCAN_XLATE",
+                    "DMU_OT_DEDUP",
+                    "DMU_OT_DEADLIST",
+                    "DMU_OT_DEADLIST_HDR",
+                    "DMU_OT_DSL_CLONES",
+                    "DMU_OT_BPOBJ_SUBOBJ"]
+
+    # If "-rr" option is used, don't convert to string representation
+    if raw > 1:
+        return "%i" % t
+
+    try:
+        return type_strings[t]
+    except IndexError:
+        return "%i" % t
+
+
+def get_compstring(c):
+    comp_strings = ["ZIO_COMPRESS_INHERIT", "ZIO_COMPRESS_ON",
+                    "ZIO_COMPRESS_OFF",     "ZIO_COMPRESS_LZJB",
+                    "ZIO_COMPRESS_EMPTY",   "ZIO_COMPRESS_GZIP_1",
+                    "ZIO_COMPRESS_GZIP_2",  "ZIO_COMPRESS_GZIP_3",
+                    "ZIO_COMPRESS_GZIP_4",  "ZIO_COMPRESS_GZIP_5",
+                    "ZIO_COMPRESS_GZIP_6",  "ZIO_COMPRESS_GZIP_7",
+                    "ZIO_COMPRESS_GZIP_8",  "ZIO_COMPRESS_GZIP_9",
+                    "ZIO_COMPRESS_ZLE",     "ZIO_COMPRESS_LZ4",
+                    "ZIO_COMPRESS_FUNCTION"]
+
+    # If "-rr" option is used, don't convert to string representation
+    if raw > 1:
+        return "%i" % c
+
+    try:
+        return comp_strings[c]
+    except IndexError:
+        return "%i" % c
+
+
+def parse_line(line, labels):
+    global hdr
+
+    new = dict()
+    val = None
+    for col in hdr:
+        # These are "special" fields computed in the update_dict
+        # function, prevent KeyError exception on labels[col] for these.
+        if col not in ['bonus', 'cached', 'direct', 'indirect', 'spill']:
+            val = line[labels[col]]
+
+        if col in ['pool', 'flags']:
+            new[col] = str(val)
+        elif col in ['dtype', 'btype']:
+            new[col] = get_typestring(int(val))
+        elif col in ['l2_comp']:
+            new[col] = get_compstring(int(val))
+        else:
+            new[col] = int(val)
+
+    return new
+
+
+def update_dict(d, k, line, labels):
+    pool = line[labels['pool']]
+    objset = line[labels['objset']]
+    key = line[labels[k]]
+
+    dbsize = int(line[labels['dbsize']])
+    blkid = int(line[labels['blkid']])
+    level = int(line[labels['level']])
+
+    if pool not in d:
+        d[pool] = dict()
+
+    if objset not in d[pool]:
+        d[pool][objset] = dict()
+
+    if key not in d[pool][objset]:
+        d[pool][objset][key] = parse_line(line, labels)
+        d[pool][objset][key]['bonus'] = 0
+        d[pool][objset][key]['cached'] = 0
+        d[pool][objset][key]['direct'] = 0
+        d[pool][objset][key]['indirect'] = 0
+        d[pool][objset][key]['spill'] = 0
+
+    d[pool][objset][key]['cached'] += dbsize
+
+    if blkid == -1:
+        d[pool][objset][key]['bonus'] += dbsize
+    elif blkid == -2:
+        d[pool][objset][key]['spill'] += dbsize
+    else:
+        if level == 0:
+            d[pool][objset][key]['direct'] += dbsize
+        else:
+            d[pool][objset][key]['indirect'] += dbsize
+
+    return d
+
+
+def print_dict(d):
+    print_header()
+    for pool in list(d.keys()):
+        for objset in list(d[pool].keys()):
+            for v in list(d[pool][objset].values()):
+                print_values(v)
+
+
+def dnodes_build_dict(filehandle):
+    labels = dict()
+    dnodes = dict()
+
+    # First 3 lines are header information, skip the first two
+    for i in range(2):
+        next(filehandle)
+
+    # The third line contains the labels and index locations
+    for i, v in enumerate(next(filehandle).split()):
+        labels[v] = i
+
+    # The rest of the file is buffer information
+    for line in filehandle:
+        update_dict(dnodes, 'object', line.split(), labels)
+
+    return dnodes
+
+
+def types_build_dict(filehandle):
+    labels = dict()
+    types = dict()
+
+    # First 3 lines are header information, skip the first two
+    for i in range(2):
+        next(filehandle)
+
+    # The third line contains the labels and index locations
+    for i, v in enumerate(next(filehandle).split()):
+        labels[v] = i
+
+    # The rest of the file is buffer information
+    for line in filehandle:
+        update_dict(types, 'dtype', line.split(), labels)
+
+    return types
+
+
+def buffers_print_all(filehandle):
+    labels = dict()
+
+    # First 3 lines are header information, skip the first two
+    for i in range(2):
+        next(filehandle)
+
+    # The third line contains the labels and index locations
+    for i, v in enumerate(next(filehandle).split()):
+        labels[v] = i
+
+    print_header()
+
+    # The rest of the file is buffer information
+    for line in filehandle:
+        print_values(parse_line(line.split(), labels))
+
+
+def main():
+    global hdr
+    global sep
+    global raw
+
+    desired_cols = None
+    bflag = False
+    dflag = False
+    hflag = False
+    ifile = None
+    ofile = None
+    tflag = False
+    vflag = False
+    xflag = False
+
+    try:
+        opts, args = getopt.getopt(
+            sys.argv[1:],
+            "bdf:hi:o:rs:tvx",
+            [
+                "buffers",
+                "dnodes",
+                "columns",
+                "help",
+                "infile",
+                "outfile",
+                "seperator",
+                "types",
+                "verbose",
+                "extended"
+            ]
+        )
+    except getopt.error:
+        usage()
+        opts = None
+
+    for opt, arg in opts:
+        if opt in ('-b', '--buffers'):
+            bflag = True
+        if opt in ('-d', '--dnodes'):
+            dflag = True
+        if opt in ('-f', '--columns'):
+            desired_cols = arg
+        if opt in ('-h', '--help'):
+            hflag = True
+        if opt in ('-i', '--infile'):
+            ifile = arg
+        if opt in ('-o', '--outfile'):
+            ofile = arg
+        if opt in ('-r', '--raw'):
+            raw += 1
+        if opt in ('-s', '--seperator'):
+            sep = arg
+        if opt in ('-t', '--types'):
+            tflag = True
+        if opt in ('-v', '--verbose'):
+            vflag = True
+        if opt in ('-x', '--extended'):
+            xflag = True
+
+    if hflag or (xflag and desired_cols):
+        usage()
+
+    if vflag:
+        detailed_usage()
+
+    # Ensure at most only one of b, d, or t flags are set
+    if (bflag and dflag) or (bflag and tflag) or (dflag and tflag):
+        usage()
+
+    if bflag:
+        hdr = bxhdr if xflag else bhdr
+    elif tflag:
+        hdr = txhdr if xflag else thdr
+    else:  # Even if dflag is False, it's the default if none set
+        dflag = True
+        hdr = dxhdr if xflag else dhdr
+
+    if desired_cols:
+        hdr = desired_cols.split(",")
+
+        invalid = []
+        incompat = []
+        for ele in hdr:
+            if ele not in cols:
+                invalid.append(ele)
+            elif ((bflag and bincompat and ele in bincompat) or
+                  (dflag and dincompat and ele in dincompat) or
+                  (tflag and tincompat and ele in tincompat)):
+                    incompat.append(ele)
+
+        if len(invalid) > 0:
+            sys.stderr.write("Invalid column definition! -- %s\n" % invalid)
+            usage()
+
+        if len(incompat) > 0:
+            sys.stderr.write("Incompatible field specified! -- %s\n" %
+                             incompat)
+            usage()
+
+    if ofile:
+        try:
+            tmp = open(ofile, "w")
+            sys.stdout = tmp
+
+        except IOError:
+            sys.stderr.write("Cannot open %s for writing\n" % ofile)
+            sys.exit(1)
+
+    if not ifile:
+        ifile = '/proc/spl/kstat/zfs/dbufs'
+
+    if ifile is not "-":
+        try:
+            tmp = open(ifile, "r")
+            sys.stdin = tmp
+        except IOError:
+            sys.stderr.write("Cannot open %s for reading\n" % ifile)
+            sys.exit(1)
+
+    if bflag:
+        buffers_print_all(sys.stdin)
+
+    if dflag:
+        print_dict(dnodes_build_dict(sys.stdin))
+
+    if tflag:
+        print_dict(types_build_dict(sys.stdin))
+
+if __name__ == '__main__':
+    main()
diff --git a/zfs/cmd/fsck_zfs/Makefile.am b/zfs/cmd/fsck_zfs/Makefile.am
new file mode 100644 (file)
index 0000000..2380f56
--- /dev/null
@@ -0,0 +1 @@
+dist_sbin_SCRIPTS = fsck.zfs
diff --git a/zfs/cmd/fsck_zfs/Makefile.in b/zfs/cmd/fsck_zfs/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/fsck_zfs/fsck.zfs b/zfs/cmd/fsck_zfs/fsck.zfs
new file mode 100755 (executable)
index 0000000..f1685db
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# fsck.zfs: A fsck helper to accomidate distributions that expect
+# to be able to execute a fsck on all filesystem types.  Currently
+# this script does nothing but it could be extended to act as a
+# compatibility wrapper for 'zpool scrub'.
+#
+
+exit 0
diff --git a/zfs/cmd/mount_zfs/Makefile.am b/zfs/cmd/mount_zfs/Makefile.am
new file mode 100644 (file)
index 0000000..b1d9389
--- /dev/null
@@ -0,0 +1,22 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+#
+# Ignore the prefix for the mount helper.  It must be installed in /sbin/
+# because this path is hardcoded in the mount(8) for security reasons.
+#
+sbindir=$(mounthelperdir)
+sbin_PROGRAMS = mount.zfs
+
+mount_zfs_SOURCES = \
+       mount_zfs.c
+
+mount_zfs_LDADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
diff --git a/zfs/cmd/mount_zfs/Makefile.in b/zfs/cmd/mount_zfs/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/mount_zfs/mount_zfs.c b/zfs/cmd/mount_zfs/mount_zfs.c
new file mode 100644 (file)
index 0000000..f6631a5
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Lawrence Livermore National Security, LLC.
+ */
+
+#include <libintl.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+#include <sys/mntent.h>
+#include <sys/stat.h>
+#include <libzfs.h>
+#include <locale.h>
+#include <getopt.h>
+#include <fcntl.h>
+
+#define        ZS_COMMENT      0x00000000      /* comment */
+#define        ZS_ZFSUTIL      0x00000001      /* caller is zfs(8) */
+
+libzfs_handle_t *g_zfs;
+
+typedef struct option_map {
+       const char *name;
+       unsigned long mntmask;
+       unsigned long zfsmask;
+} option_map_t;
+
+static const option_map_t option_map[] = {
+       /* Canonicalized filesystem independent options from mount(8) */
+       { MNTOPT_NOAUTO,        MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_DEFAULTS,      MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_NODEVICES,     MS_NODEV,       ZS_COMMENT      },
+       { MNTOPT_DIRSYNC,       MS_DIRSYNC,     ZS_COMMENT      },
+       { MNTOPT_NOEXEC,        MS_NOEXEC,      ZS_COMMENT      },
+       { MNTOPT_GROUP,         MS_GROUP,       ZS_COMMENT      },
+       { MNTOPT_NETDEV,        MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_NOFAIL,        MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_NOSUID,        MS_NOSUID,      ZS_COMMENT      },
+       { MNTOPT_OWNER,         MS_OWNER,       ZS_COMMENT      },
+       { MNTOPT_REMOUNT,       MS_REMOUNT,     ZS_COMMENT      },
+       { MNTOPT_RO,            MS_RDONLY,      ZS_COMMENT      },
+       { MNTOPT_RW,            MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_SYNC,          MS_SYNCHRONOUS, ZS_COMMENT      },
+       { MNTOPT_USER,          MS_USERS,       ZS_COMMENT      },
+       { MNTOPT_USERS,         MS_USERS,       ZS_COMMENT      },
+       /* acl flags passed with util-linux-2.24 mount command */
+       { MNTOPT_ACL,           MS_POSIXACL,    ZS_COMMENT      },
+       { MNTOPT_NOACL,         MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_POSIXACL,      MS_POSIXACL,    ZS_COMMENT      },
+#ifdef MS_NOATIME
+       { MNTOPT_NOATIME,       MS_NOATIME,     ZS_COMMENT      },
+#endif
+#ifdef MS_NODIRATIME
+       { MNTOPT_NODIRATIME,    MS_NODIRATIME,  ZS_COMMENT      },
+#endif
+#ifdef MS_RELATIME
+       { MNTOPT_RELATIME,      MS_RELATIME,    ZS_COMMENT      },
+#endif
+#ifdef MS_STRICTATIME
+       { MNTOPT_STRICTATIME,   MS_STRICTATIME, ZS_COMMENT      },
+#endif
+#ifdef MS_LAZYTIME
+       { MNTOPT_LAZYTIME,      MS_LAZYTIME,    ZS_COMMENT      },
+#endif
+       { MNTOPT_CONTEXT,       MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_FSCONTEXT,     MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_DEFCONTEXT,    MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_ROOTCONTEXT,   MS_COMMENT,     ZS_COMMENT      },
+#ifdef MS_I_VERSION
+       { MNTOPT_IVERSION,      MS_I_VERSION,   ZS_COMMENT      },
+#endif
+#ifdef MS_MANDLOCK
+       { MNTOPT_NBMAND,        MS_MANDLOCK,    ZS_COMMENT      },
+#endif
+       /* Valid options not found in mount(8) */
+       { MNTOPT_BIND,          MS_BIND,        ZS_COMMENT      },
+#ifdef MS_REC
+       { MNTOPT_RBIND,         MS_BIND|MS_REC, ZS_COMMENT      },
+#endif
+       { MNTOPT_COMMENT,       MS_COMMENT,     ZS_COMMENT      },
+#ifdef MS_NOSUB
+       { MNTOPT_NOSUB,         MS_NOSUB,       ZS_COMMENT      },
+#endif
+#ifdef MS_SILENT
+       { MNTOPT_QUIET,         MS_SILENT,      ZS_COMMENT      },
+#endif
+       /* Custom zfs options */
+       { MNTOPT_XATTR,         MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_NOXATTR,       MS_COMMENT,     ZS_COMMENT      },
+       { MNTOPT_ZFSUTIL,       MS_COMMENT,     ZS_ZFSUTIL      },
+       { NULL,                 0,              0               } };
+
+/*
+ * Break the mount option in to a name/value pair.  The name is
+ * validated against the option map and mount flags set accordingly.
+ */
+static int
+parse_option(char *mntopt, unsigned long *mntflags,
+    unsigned long *zfsflags, int sloppy)
+{
+       const option_map_t *opt;
+       char *ptr, *name, *value = NULL;
+       int error = 0;
+
+       name = strdup(mntopt);
+       if (name == NULL)
+               return (ENOMEM);
+
+       for (ptr = name; ptr && *ptr; ptr++) {
+               if (*ptr == '=') {
+                       *ptr = '\0';
+                       value = ptr+1;
+                       VERIFY3P(value, !=, NULL);
+                       break;
+               }
+       }
+
+       for (opt = option_map; opt->name != NULL; opt++) {
+               if (strncmp(name, opt->name, strlen(name)) == 0) {
+                       *mntflags |= opt->mntmask;
+                       *zfsflags |= opt->zfsmask;
+                       error = 0;
+                       goto out;
+               }
+       }
+
+       if (!sloppy)
+               error = ENOENT;
+out:
+       /* If required further process on the value may be done here */
+       free(name);
+       return (error);
+}
+
+/*
+ * Translate the mount option string in to MS_* mount flags for the
+ * kernel vfs.  When sloppy is non-zero unknown options will be ignored
+ * otherwise they are considered fatal are copied in to badopt.
+ */
+static int
+parse_options(char *mntopts, unsigned long *mntflags, unsigned long *zfsflags,
+    int sloppy, char *badopt, char *mtabopt)
+{
+       int error = 0, quote = 0, flag = 0, count = 0;
+       char *ptr, *opt, *opts;
+
+       opts = strdup(mntopts);
+       if (opts == NULL)
+               return (ENOMEM);
+
+       *mntflags = 0;
+       opt = NULL;
+
+       /*
+        * Scan through all mount options which must be comma delimited.
+        * We must be careful to notice regions which are double quoted
+        * and skip commas in these regions.  Each option is then checked
+        * to determine if it is a known option.
+        */
+       for (ptr = opts; ptr && !flag; ptr++) {
+               if (opt == NULL)
+                       opt = ptr;
+
+               if (*ptr == '"')
+                       quote = !quote;
+
+               if (quote)
+                       continue;
+
+               if (*ptr == '\0')
+                       flag = 1;
+
+               if ((*ptr == ',') || (*ptr == '\0')) {
+                       *ptr = '\0';
+
+                       error = parse_option(opt, mntflags, zfsflags, sloppy);
+                       if (error) {
+                               strcpy(badopt, opt);
+                               goto out;
+
+                       }
+
+                       if (!(*mntflags & MS_REMOUNT) &&
+                           !(*zfsflags & ZS_ZFSUTIL)) {
+                               if (count > 0)
+                                       strlcat(mtabopt, ",", MNT_LINE_MAX);
+
+                               strlcat(mtabopt, opt, MNT_LINE_MAX);
+                               count++;
+                       }
+
+                       opt = NULL;
+               }
+       }
+
+out:
+       free(opts);
+       return (error);
+}
+
+/*
+ * Return the pool/dataset to mount given the name passed to mount.  This
+ * is expected to be of the form pool/dataset, however may also refer to
+ * a block device if that device contains a valid zfs label.
+ */
+static char *
+parse_dataset(char *dataset)
+{
+       char cwd[PATH_MAX];
+       struct stat64 statbuf;
+       int error;
+       int len;
+
+       /*
+        * We expect a pool/dataset to be provided, however if we're
+        * given a device which is a member of a zpool we attempt to
+        * extract the pool name stored in the label.  Given the pool
+        * name we can mount the root dataset.
+        */
+       error = stat64(dataset, &statbuf);
+       if (error == 0) {
+               nvlist_t *config;
+               char *name;
+               int fd;
+
+               fd = open(dataset, O_RDONLY);
+               if (fd < 0)
+                       goto out;
+
+               error = zpool_read_label(fd, &config, NULL);
+               (void) close(fd);
+               if (error)
+                       goto out;
+
+               error = nvlist_lookup_string(config,
+                   ZPOOL_CONFIG_POOL_NAME, &name);
+               if (error) {
+                       nvlist_free(config);
+               } else {
+                       dataset = strdup(name);
+                       nvlist_free(config);
+                       return (dataset);
+               }
+       }
+out:
+       /*
+        * If a file or directory in your current working directory is
+        * named 'dataset' then mount(8) will prepend your current working
+        * directory to the dataset.  There is no way to prevent this
+        * behavior so we simply check for it and strip the prepended
+        * patch when it is added.
+        */
+       if (getcwd(cwd, PATH_MAX) == NULL)
+               return (dataset);
+
+       len = strlen(cwd);
+
+       /* Do not add one when cwd already ends in a trailing '/' */
+       if (strncmp(cwd, dataset, len) == 0)
+               return (dataset + len + (cwd[len-1] != '/'));
+
+       return (dataset);
+}
+
+/*
+ * Update the mtab_* code to use the libmount library when it is commonly
+ * available otherwise fallback to legacy mode.  The mount(8) utility will
+ * manage the lock file for us to prevent racing updates to /etc/mtab.
+ */
+static int
+mtab_is_writeable(void)
+{
+       struct stat st;
+       int error, fd;
+
+       error = lstat("/etc/mtab", &st);
+       if (error || S_ISLNK(st.st_mode))
+               return (0);
+
+       fd = open("/etc/mtab", O_RDWR | O_CREAT, 0644);
+       if (fd < 0)
+               return (0);
+
+       close(fd);
+       return (1);
+}
+
+static int
+mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts)
+{
+       struct mntent mnt;
+       FILE *fp;
+       int error;
+
+       mnt.mnt_fsname = dataset;
+       mnt.mnt_dir = mntpoint;
+       mnt.mnt_type = type;
+       mnt.mnt_opts = mntopts ? mntopts : "";
+       mnt.mnt_freq = 0;
+       mnt.mnt_passno = 0;
+
+       fp = setmntent("/etc/mtab", "a+");
+       if (!fp) {
+               (void) fprintf(stderr, gettext(
+                   "filesystem '%s' was mounted, but /etc/mtab "
+                   "could not be opened due to error %d\n"),
+                   dataset, errno);
+               return (MOUNT_FILEIO);
+       }
+
+       error = addmntent(fp, &mnt);
+       if (error) {
+               (void) fprintf(stderr, gettext(
+                   "filesystem '%s' was mounted, but /etc/mtab "
+                   "could not be updated due to error %d\n"),
+                   dataset, errno);
+               return (MOUNT_FILEIO);
+       }
+
+       (void) endmntent(fp);
+
+       return (MOUNT_SUCCESS);
+}
+
+static void
+append_mntopt(const char *name, const char *val, char *mntopts,
+    char *mtabopt, boolean_t quote)
+{
+       char tmp[MNT_LINE_MAX];
+
+       snprintf(tmp, MNT_LINE_MAX, quote ? ",%s=\"%s\"" : ",%s=%s", name, val);
+
+       if (mntopts)
+               strlcat(mntopts, tmp, MNT_LINE_MAX);
+
+       if (mtabopt)
+               strlcat(mtabopt, tmp, MNT_LINE_MAX);
+}
+
+static void
+zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name,
+    char *mntopts, char *mtabopt)
+{
+       char context[ZFS_MAXPROPLEN];
+
+       if (zfs_prop_get(zhp, zpt, context, sizeof (context),
+           NULL, NULL, 0, B_FALSE) == 0) {
+               if (strcmp(context, "none") != 0)
+                   append_mntopt(name, context, mntopts, mtabopt, B_TRUE);
+       }
+}
+
+int
+main(int argc, char **argv)
+{
+       zfs_handle_t *zhp;
+       char prop[ZFS_MAXPROPLEN];
+       uint64_t zfs_version = 0;
+       char mntopts[MNT_LINE_MAX] = { '\0' };
+       char badopt[MNT_LINE_MAX] = { '\0' };
+       char mtabopt[MNT_LINE_MAX] = { '\0' };
+       char mntpoint[PATH_MAX];
+       char *dataset;
+       unsigned long mntflags = 0, zfsflags = 0, remount = 0;
+       int sloppy = 0, fake = 0, verbose = 0, nomtab = 0, zfsutil = 0;
+       int error, c;
+
+       (void) setlocale(LC_ALL, "");
+       (void) textdomain(TEXT_DOMAIN);
+
+       opterr = 0;
+
+       /* check options */
+       while ((c = getopt_long(argc, argv, "sfnvo:h?", 0, 0)) != -1) {
+               switch (c) {
+               case 's':
+                       sloppy = 1;
+                       break;
+               case 'f':
+                       fake = 1;
+                       break;
+               case 'n':
+                       nomtab = 1;
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               case 'o':
+                       (void) strlcpy(mntopts, optarg, sizeof (mntopts));
+                       break;
+               case 'h':
+               case '?':
+                       (void) fprintf(stderr, gettext("Invalid option '%c'\n"),
+                           optopt);
+                       (void) fprintf(stderr, gettext("Usage: mount.zfs "
+                           "[-sfnv] [-o options] <dataset> <mountpoint>\n"));
+                       return (MOUNT_USAGE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check that we only have two arguments */
+       if (argc != 2) {
+               if (argc == 0)
+                       (void) fprintf(stderr, gettext("missing dataset "
+                           "argument\n"));
+               else if (argc == 1)
+                       (void) fprintf(stderr,
+                           gettext("missing mountpoint argument\n"));
+               else
+                       (void) fprintf(stderr, gettext("too many arguments\n"));
+               (void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n");
+               return (MOUNT_USAGE);
+       }
+
+       dataset = parse_dataset(argv[0]);
+
+       /* canonicalize the mount point */
+       if (realpath(argv[1], mntpoint) == NULL) {
+               (void) fprintf(stderr, gettext("filesystem '%s' cannot be "
+                   "mounted at '%s' due to canonicalization error %d.\n"),
+                   dataset, argv[1], errno);
+               return (MOUNT_SYSERR);
+       }
+
+       /* validate mount options and set mntflags */
+       error = parse_options(mntopts, &mntflags, &zfsflags, sloppy,
+           badopt, mtabopt);
+       if (error) {
+               switch (error) {
+               case ENOMEM:
+                       (void) fprintf(stderr, gettext("filesystem '%s' "
+                           "cannot be mounted due to a memory allocation "
+                           "failure.\n"), dataset);
+                       return (MOUNT_SYSERR);
+               case ENOENT:
+                       (void) fprintf(stderr, gettext("filesystem '%s' "
+                           "cannot be mounted due to invalid option "
+                           "'%s'.\n"), dataset, badopt);
+                       (void) fprintf(stderr, gettext("Use the '-s' option "
+                           "to ignore the bad mount option.\n"));
+                       return (MOUNT_USAGE);
+               default:
+                       (void) fprintf(stderr, gettext("filesystem '%s' "
+                           "cannot be mounted due to internal error %d.\n"),
+                           dataset, error);
+                       return (MOUNT_SOFTWARE);
+               }
+       }
+
+       if (verbose)
+               (void) fprintf(stdout, gettext("mount.zfs:\n"
+                   "  dataset:    \"%s\"\n  mountpoint: \"%s\"\n"
+                   "  mountflags: 0x%lx\n  zfsflags:   0x%lx\n"
+                   "  mountopts:  \"%s\"\n  mtabopts:   \"%s\"\n"),
+                   dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt);
+
+       if (mntflags & MS_REMOUNT) {
+               nomtab = 1;
+               remount = 1;
+       }
+
+       if (zfsflags & ZS_ZFSUTIL)
+               zfsutil = 1;
+
+       if ((g_zfs = libzfs_init()) == NULL) {
+               (void) fprintf(stderr, "%s", libzfs_error_init(errno));
+               return (MOUNT_SYSERR);
+       }
+
+       /* try to open the dataset to access the mount point */
+       if ((zhp = zfs_open(g_zfs, dataset,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL) {
+               (void) fprintf(stderr, gettext("filesystem '%s' cannot be "
+                   "mounted, unable to open the dataset\n"), dataset);
+               libzfs_fini(g_zfs);
+               return (MOUNT_USAGE);
+       }
+
+       /*
+        * Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists
+        * if it does, create a tmp variable in case it's needed
+        * checks to see if the selinux context is set to the default
+        * if it is, allow the setting of the other context properties
+        * this is needed because the 'context' property overrides others
+        * if it is not the default, set the 'context' property
+        */
+       if (zfs_prop_get(zhp, ZFS_PROP_SELINUX_CONTEXT, prop, sizeof (prop),
+           NULL, NULL, 0, B_FALSE) == 0) {
+               if (strcmp(prop, "none") == 0) {
+                       zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_FSCONTEXT,
+                           MNTOPT_FSCONTEXT, mntopts, mtabopt);
+                       zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_DEFCONTEXT,
+                           MNTOPT_DEFCONTEXT, mntopts, mtabopt);
+                       zfs_selinux_setcontext(zhp,
+                           ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT,
+                           mntopts, mtabopt);
+               } else {
+                       append_mntopt(MNTOPT_CONTEXT, prop,
+                           mntopts, mtabopt, B_TRUE);
+               }
+       }
+
+       /* A hint used to determine an auto-mounted snapshot mount point */
+       append_mntopt(MNTOPT_MNTPOINT, mntpoint, mntopts, NULL, B_FALSE);
+
+       /* treat all snapshots as legacy mount points */
+       if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT)
+               (void) strlcpy(prop, ZFS_MOUNTPOINT_LEGACY, ZFS_MAXPROPLEN);
+       else
+               (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop,
+                   sizeof (prop), NULL, NULL, 0, B_FALSE);
+
+       /*
+        * Fetch the max supported zfs version in case we get ENOTSUP
+        * back from the mount command, since we need the zfs handle
+        * to do so.
+        */
+       zfs_version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+       if (zfs_version == 0) {
+               fprintf(stderr, gettext("unable to fetch "
+                   "ZFS version for filesystem '%s'\n"), dataset);
+               return (MOUNT_SYSERR);
+       }
+
+       zfs_close(zhp);
+       libzfs_fini(g_zfs);
+
+       /*
+        * Legacy mount points may only be mounted using 'mount', never using
+        * 'zfs mount'.  However, since 'zfs mount' actually invokes 'mount'
+        * we differentiate the two cases using the 'zfsutil' mount option.
+        * This mount option should only be supplied by the 'zfs mount' util.
+        *
+        * The only exception to the above rule is '-o remount' which is
+        * always allowed for non-legacy datasets.  This is done because when
+        * using zfs as your root file system both rc.sysinit/umountroot and
+        * systemd depend on 'mount -o remount <mountpoint>' to work.
+        */
+       if (zfsutil && (strcmp(prop, ZFS_MOUNTPOINT_LEGACY) == 0)) {
+               (void) fprintf(stderr, gettext(
+                   "filesystem '%s' cannot be mounted using 'zfs mount'.\n"
+                   "Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n"
+                   "See zfs(8) for more information.\n"),
+                   dataset, mntpoint, dataset, mntpoint);
+               return (MOUNT_USAGE);
+       }
+
+       if (!zfsutil && !(remount || fake) &&
+           strcmp(prop, ZFS_MOUNTPOINT_LEGACY)) {
+               (void) fprintf(stderr, gettext(
+                   "filesystem '%s' cannot be mounted using 'mount'.\n"
+                   "Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n"
+                   "See zfs(8) for more information.\n"),
+                   dataset, "legacy", dataset);
+               return (MOUNT_USAGE);
+       }
+
+       if (!fake) {
+               error = mount(dataset, mntpoint, MNTTYPE_ZFS,
+                   mntflags, mntopts);
+       }
+
+       if (error) {
+               switch (errno) {
+               case ENOENT:
+                       (void) fprintf(stderr, gettext("mount point "
+                           "'%s' does not exist\n"), mntpoint);
+                       return (MOUNT_SYSERR);
+               case EBUSY:
+                       (void) fprintf(stderr, gettext("filesystem "
+                           "'%s' is already mounted\n"), dataset);
+                       return (MOUNT_BUSY);
+               case ENOTSUP:
+                       if (zfs_version > ZPL_VERSION) {
+                               (void) fprintf(stderr,
+                                   gettext("filesystem '%s' (v%d) is not "
+                                   "supported by this implementation of "
+                                   "ZFS (max v%d).\n"), dataset,
+                                   (int) zfs_version, (int) ZPL_VERSION);
+                       } else {
+                               (void) fprintf(stderr,
+                                   gettext("filesystem '%s' mount "
+                                   "failed for unknown reason.\n"), dataset);
+                       }
+                       return (MOUNT_SYSERR);
+               default:
+                       (void) fprintf(stderr, gettext("filesystem "
+                           "'%s' can not be mounted due to error "
+                           "%d\n"), dataset, errno);
+                       return (MOUNT_USAGE);
+               }
+       }
+
+       if (!nomtab && mtab_is_writeable()) {
+               error = mtab_update(dataset, mntpoint, MNTTYPE_ZFS, mtabopt);
+               if (error)
+                       return (error);
+       }
+
+       return (MOUNT_SUCCESS);
+}
diff --git a/zfs/cmd/raidz_test/Makefile.am b/zfs/cmd/raidz_test/Makefile.am
new file mode 100644 (file)
index 0000000..23ad08a
--- /dev/null
@@ -0,0 +1,21 @@
+include $(top_srcdir)/config/Rules.am
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+AM_CPPFLAGS += -DDEBUG
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+bin_PROGRAMS = raidz_test
+
+raidz_test_SOURCES = \
+       raidz_test.h \
+       raidz_test.c \
+       raidz_bench.c
+
+raidz_test_LDADD = \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la
+
+raidz_test_LDADD += -lm -ldl
diff --git a/zfs/cmd/raidz_test/raidz_bench.c b/zfs/cmd/raidz_test/raidz_bench.c
new file mode 100644 (file)
index 0000000..f1710cc
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/zio.h>
+#include <sys/vdev_raidz.h>
+#include <sys/vdev_raidz_impl.h>
+#include <stdio.h>
+
+#include <sys/time.h>
+
+#include "raidz_test.h"
+
+#define        GEN_BENCH_MEMORY        (((uint64_t)1ULL)<<32)
+#define        REC_BENCH_MEMORY        (((uint64_t)1ULL)<<29)
+#define        BENCH_ASHIFT            12
+#define        MIN_CS_SHIFT            BENCH_ASHIFT
+#define        MAX_CS_SHIFT            SPA_MAXBLOCKSHIFT
+
+static zio_t zio_bench;
+static raidz_map_t *rm_bench;
+static size_t max_data_size = SPA_MAXBLOCKSIZE;
+
+static void
+bench_init_raidz_map(void)
+{
+       zio_bench.io_offset = 0;
+       zio_bench.io_size = max_data_size;
+
+       /*
+        * To permit larger column sizes these have to be done
+        * allocated using aligned alloc instead of zio_data_buf_alloc
+        */
+       zio_bench.io_data = raidz_alloc(max_data_size);
+
+       init_zio_data(&zio_bench);
+}
+
+static void
+bench_fini_raidz_maps(void)
+{
+       /* tear down golden zio */
+       raidz_free(zio_bench.io_data, max_data_size);
+       bzero(&zio_bench, sizeof (zio_t));
+}
+
+static inline void
+run_gen_bench_impl(const char *impl)
+{
+       int fn, ncols;
+       uint64_t ds, iter_cnt, iter, disksize;
+       hrtime_t start;
+       double elapsed, d_bw;
+
+       /* Benchmark generate functions */
+       for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) {
+
+               for (ds = MIN_CS_SHIFT; ds <= MAX_CS_SHIFT; ds++) {
+                       /* create suitable raidz_map */
+                       ncols = rto_opts.rto_dcols + fn + 1;
+                       zio_bench.io_size = 1ULL << ds;
+                       rm_bench = vdev_raidz_map_alloc(&zio_bench,
+                           BENCH_ASHIFT, ncols, fn+1);
+
+                       /* estimate iteration count */
+                       iter_cnt = GEN_BENCH_MEMORY;
+                       iter_cnt /= zio_bench.io_size;
+
+                       start = gethrtime();
+                       for (iter = 0; iter < iter_cnt; iter++)
+                               vdev_raidz_generate_parity(rm_bench);
+                       elapsed = NSEC2SEC((double) (gethrtime() - start));
+
+                       disksize = (1ULL << ds) / rto_opts.rto_dcols;
+                       d_bw = (double)iter_cnt * (double)disksize;
+                       d_bw /= (1024.0 * 1024.0 * elapsed);
+
+                       LOG(D_ALL, "%10s, %8s, %zu, %10llu, %lf, %lf, %u\n",
+                           impl,
+                           raidz_gen_name[fn],
+                           rto_opts.rto_dcols,
+                           (1ULL<<ds),
+                           d_bw,
+                           d_bw * (double)(ncols),
+                           (unsigned) iter_cnt);
+
+                       vdev_raidz_map_free(rm_bench);
+               }
+       }
+}
+
+void
+run_gen_bench(void)
+{
+       char **impl_name;
+
+       LOG(D_INFO, DBLSEP "\nBenchmarking parity generation...\n\n");
+       LOG(D_ALL, "impl, math, dcols, iosize, disk_bw, total_bw, iter\n");
+
+       for (impl_name = (char **)raidz_impl_names; *impl_name != NULL;
+           impl_name++) {
+
+               if (vdev_raidz_impl_set(*impl_name) != 0)
+                       continue;
+
+               run_gen_bench_impl(*impl_name);
+       }
+}
+
+static void
+run_rec_bench_impl(const char *impl)
+{
+       int fn, ncols, nbad;
+       uint64_t ds, iter_cnt, iter, disksize;
+       hrtime_t start;
+       double elapsed, d_bw;
+       static const int tgt[7][3] = {
+               {1, 2, 3},      /* rec_p:   bad QR & D[0]       */
+               {0, 2, 3},      /* rec_q:   bad PR & D[0]       */
+               {0, 1, 3},      /* rec_r:   bad PQ & D[0]       */
+               {2, 3, 4},      /* rec_pq:  bad R  & D[0][1]    */
+               {1, 3, 4},      /* rec_pr:  bad Q  & D[0][1]    */
+               {0, 3, 4},      /* rec_qr:  bad P  & D[0][1]    */
+               {3, 4, 5}       /* rec_pqr: bad    & D[0][1][2] */
+       };
+
+       for (fn = 0; fn < RAIDZ_REC_NUM; fn++) {
+               for (ds = MIN_CS_SHIFT; ds <= MAX_CS_SHIFT; ds++) {
+
+                       /* create suitable raidz_map */
+                       ncols = rto_opts.rto_dcols + PARITY_PQR;
+                       zio_bench.io_size = 1ULL << ds;
+
+                       /*
+                        * raidz block is too short to test
+                        * the requested method
+                        */
+                       if (zio_bench.io_size / rto_opts.rto_dcols <
+                           (1ULL << BENCH_ASHIFT))
+                               continue;
+
+                       rm_bench = vdev_raidz_map_alloc(&zio_bench,
+                               BENCH_ASHIFT, ncols, PARITY_PQR);
+
+                       /* estimate iteration count */
+                       iter_cnt = (REC_BENCH_MEMORY);
+                       iter_cnt /= zio_bench.io_size;
+
+                       /* calculate how many bad columns there are */
+                       nbad = MIN(3, raidz_ncols(rm_bench) -
+                           raidz_parity(rm_bench));
+
+                       start = gethrtime();
+                       for (iter = 0; iter < iter_cnt; iter++)
+                               vdev_raidz_reconstruct(rm_bench, tgt[fn], nbad);
+                       elapsed = NSEC2SEC((double) (gethrtime() - start));
+
+                       disksize = (1ULL << ds) / rto_opts.rto_dcols;
+                       d_bw = (double)iter_cnt * (double)(disksize);
+                       d_bw /= (1024.0 * 1024.0 * elapsed);
+
+                       LOG(D_ALL, "%10s, %8s, %zu, %10llu, %lf, %lf, %u\n",
+                           impl,
+                           raidz_rec_name[fn],
+                           rto_opts.rto_dcols,
+                           (1ULL<<ds),
+                           d_bw,
+                           d_bw * (double)ncols,
+                           (unsigned) iter_cnt);
+
+                       vdev_raidz_map_free(rm_bench);
+               }
+       }
+}
+
+void
+run_rec_bench(void)
+{
+       char **impl_name;
+
+       LOG(D_INFO, DBLSEP "\nBenchmarking data reconstruction...\n\n");
+       LOG(D_ALL, "impl, math, dcols, iosize, disk_bw, total_bw, iter\n");
+
+       for (impl_name = (char **)raidz_impl_names; *impl_name != NULL;
+           impl_name++) {
+
+               if (vdev_raidz_impl_set(*impl_name) != 0)
+                       continue;
+
+               run_rec_bench_impl(*impl_name);
+       }
+}
+
+void
+run_raidz_benchmark(void)
+{
+       bench_init_raidz_map();
+
+       run_gen_bench();
+       run_rec_bench();
+
+       bench_fini_raidz_maps();
+}
diff --git a/zfs/cmd/raidz_test/raidz_test.c b/zfs/cmd/raidz_test/raidz_test.c
new file mode 100644 (file)
index 0000000..0019ae8
--- /dev/null
@@ -0,0 +1,784 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/zio.h>
+#include <umem.h>
+#include <sys/vdev_raidz.h>
+#include <sys/vdev_raidz_impl.h>
+#include <assert.h>
+#include <stdio.h>
+#include "raidz_test.h"
+
+static int *rand_data;
+raidz_test_opts_t rto_opts;
+
+static char gdb[256];
+static const char gdb_tmpl[] = "gdb -ex \"set pagination 0\" -p %d";
+
+static void sig_handler(int signo)
+{
+       struct sigaction action;
+       /*
+        * Restore default action and re-raise signal so SIGSEGV and
+        * SIGABRT can trigger a core dump.
+        */
+       action.sa_handler = SIG_DFL;
+       sigemptyset(&action.sa_mask);
+       action.sa_flags = 0;
+       (void) sigaction(signo, &action, NULL);
+
+       if (rto_opts.rto_gdb)
+               if (system(gdb));
+
+       raise(signo);
+}
+
+static void print_opts(raidz_test_opts_t *opts, boolean_t force)
+{
+       char *verbose;
+       switch (opts->rto_v) {
+               case 0:
+                       verbose = "no";
+                       break;
+               case 1:
+                       verbose = "info";
+                       break;
+               default:
+                       verbose = "debug";
+                       break;
+       }
+
+       if (force || opts->rto_v >= D_INFO) {
+               (void) fprintf(stdout, DBLSEP "Running with options:\n"
+                   "  (-a) zio ashift                   : %zu\n"
+                   "  (-o) zio offset                   : 1 << %zu\n"
+                   "  (-d) number of raidz data columns : %zu\n"
+                   "  (-s) size of DATA                 : 1 << %zu\n"
+                   "  (-S) sweep parameters             : %s \n"
+                   "  (-v) verbose                      : %s \n\n",
+                   opts->rto_ashift,                   /* -a */
+                   ilog2(opts->rto_offset),            /* -o */
+                   opts->rto_dcols,                    /* -d */
+                   ilog2(opts->rto_dsize),             /* -s */
+                   opts->rto_sweep ? "yes" : "no",     /* -S */
+                   verbose                             /* -v */
+               );
+       }
+}
+
+static void usage(boolean_t requested)
+{
+       const raidz_test_opts_t *o = &rto_opts_defaults;
+
+       FILE *fp = requested ? stdout : stderr;
+
+       (void) fprintf(fp, "Usage:\n"
+       "\t[-a zio ashift (default: %zu)]\n"
+       "\t[-o zio offset, exponent radix 2 (default: %zu)]\n"
+       "\t[-d number of raidz data columns (default: %zu)]\n"
+       "\t[-s zio size, exponent radix 2 (default: %zu)]\n"
+       "\t[-S parameter sweep (default: %s)]\n"
+       "\t[-t timeout for parameter sweep test]\n"
+       "\t[-B benchmark all raidz implementations]\n"
+       "\t[-v increase verbosity (default: %zu)]\n"
+       "\t[-h (print help)]\n"
+       "\t[-T test the test, see if failure would be detected]\n"
+       "\t[-D debug (attach gdb on SIGSEGV)]\n"
+       "",
+       o->rto_ashift,                          /* -a */
+       ilog2(o->rto_offset),                   /* -o */
+       o->rto_dcols,                           /* -d */
+       ilog2(o->rto_dsize),                    /* -s */
+       rto_opts.rto_sweep ? "yes" : "no",      /* -S */
+       o->rto_v                                /* -d */
+       );
+
+       exit(requested ? 0 : 1);
+}
+
+static void process_options(int argc, char **argv)
+{
+       size_t value;
+       int opt;
+
+       raidz_test_opts_t *o = &rto_opts;
+
+       bcopy(&rto_opts_defaults, o, sizeof (*o));
+
+       while ((opt = getopt(argc, argv, "TDBSvha:o:d:s:t:")) != -1) {
+               value = 0;
+
+               switch (opt) {
+               case 'a':
+                       value = strtoull(optarg, NULL, 0);
+                       o->rto_ashift = MIN(13, MAX(9, value));
+                       break;
+               case 'o':
+                       value = strtoull(optarg, NULL, 0);
+                       o->rto_offset = ((1ULL << MIN(12, value)) >> 9) << 9;
+                       break;
+               case 'd':
+                       value = strtoull(optarg, NULL, 0);
+                       o->rto_dcols = MIN(255, MAX(1, value));
+                       break;
+               case 's':
+                       value = strtoull(optarg, NULL, 0);
+                       o->rto_dsize = 1ULL <<  MIN(SPA_MAXBLOCKSHIFT,
+                           MAX(SPA_MINBLOCKSHIFT, value));
+                       break;
+               case 't':
+                       value = strtoull(optarg, NULL, 0);
+                       o->rto_sweep_timeout = value;
+                       break;
+               case 'v':
+                       o->rto_v++;
+                       break;
+               case 'S':
+                       o->rto_sweep = 1;
+                       break;
+               case 'B':
+                       o->rto_benchmark = 1;
+                       break;
+               case 'D':
+                       o->rto_gdb = 1;
+                       break;
+               case 'T':
+                       o->rto_sanity = 1;
+                       break;
+               case 'h':
+                       usage(B_TRUE);
+                       break;
+               case '?':
+               default:
+                       usage(B_FALSE);
+                       break;
+               }
+       }
+}
+
+#define        DATA_COL(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_data)
+#define        DATA_COL_SIZE(rm, i) ((rm)->rm_col[raidz_parity(rm) + (i)].rc_size)
+
+#define        CODE_COL(rm, i) ((rm)->rm_col[(i)].rc_data)
+#define        CODE_COL_SIZE(rm, i) ((rm)->rm_col[(i)].rc_size)
+
+static int
+cmp_code(raidz_test_opts_t *opts, const raidz_map_t *rm, const int parity)
+{
+       int i, ret = 0;
+
+       VERIFY(parity >= 1 && parity <= 3);
+
+       for (i = 0; i < parity; i++) {
+               if (0 != memcmp(CODE_COL(rm, i), CODE_COL(opts->rm_golden, i),
+                       CODE_COL_SIZE(rm, i))) {
+                       ret++;
+
+                       LOG_OPT(D_DEBUG, opts,
+                           "\nParity block [%d] different!\n", i);
+               }
+       }
+       return (ret);
+}
+
+static int
+cmp_data(raidz_test_opts_t *opts, raidz_map_t *rm)
+{
+       int i, ret = 0;
+       int dcols = opts->rm_golden->rm_cols - raidz_parity(opts->rm_golden);
+
+       for (i = 0; i < dcols; i++) {
+               if (0 != memcmp(DATA_COL(opts->rm_golden, i), DATA_COL(rm, i),
+                       DATA_COL_SIZE(opts->rm_golden, i))) {
+                       ret++;
+
+                       LOG_OPT(D_DEBUG, opts,
+                           "\nData block [%d] different!\n", i);
+               }
+       }
+       return (ret);
+}
+
+static void
+corrupt_colums(raidz_map_t *rm, const int *tgts, const int cnt)
+{
+       int i;
+       int *dst;
+       raidz_col_t *col;
+
+       for (i = 0; i < cnt; i++) {
+               col = &rm->rm_col[tgts[i]];
+               dst = col->rc_data;
+               for (i = 0; i < col->rc_size / sizeof (int); i++)
+                       dst[i] = rand();
+       }
+}
+
+void
+init_zio_data(zio_t *zio)
+{
+       int i;
+       int *dst = (int *) zio->io_data;
+
+       for (i = 0; i < zio->io_size / sizeof (int); i++) {
+               dst[i] = rand_data[i];
+       }
+}
+
+static void
+fini_raidz_map(zio_t **zio, raidz_map_t **rm)
+{
+       vdev_raidz_map_free(*rm);
+       raidz_free((*zio)->io_data, (*zio)->io_size);
+       umem_free(*zio, sizeof (zio_t));
+
+       *zio = NULL;
+       *rm = NULL;
+}
+
+static int
+init_raidz_golden_map(raidz_test_opts_t *opts, const int parity)
+{
+       int err = 0;
+       zio_t *zio_test;
+       raidz_map_t *rm_test;
+       const size_t total_ncols = opts->rto_dcols + parity;
+
+       if (opts->rm_golden) {
+               fini_raidz_map(&opts->zio_golden, &opts->rm_golden);
+       }
+
+       opts->zio_golden = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
+       zio_test = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
+
+       opts->zio_golden->io_offset = zio_test->io_offset = opts->rto_offset;
+       opts->zio_golden->io_size = zio_test->io_size = opts->rto_dsize;
+
+       opts->zio_golden->io_data = raidz_alloc(opts->rto_dsize);
+       zio_test->io_data = raidz_alloc(opts->rto_dsize);
+
+       init_zio_data(opts->zio_golden);
+       init_zio_data(zio_test);
+
+       VERIFY0(vdev_raidz_impl_set("original"));
+
+       opts->rm_golden = vdev_raidz_map_alloc(opts->zio_golden,
+           opts->rto_ashift, total_ncols, parity);
+       rm_test = vdev_raidz_map_alloc(zio_test,
+           opts->rto_ashift, total_ncols, parity);
+
+       VERIFY(opts->zio_golden);
+       VERIFY(opts->rm_golden);
+
+       vdev_raidz_generate_parity(opts->rm_golden);
+       vdev_raidz_generate_parity(rm_test);
+
+       /* sanity check */
+       err |= cmp_data(opts, rm_test);
+       err |= cmp_code(opts, rm_test, parity);
+
+       if (err)
+               ERR("initializing the golden copy ... [FAIL]!\n");
+
+       /* tear down raidz_map of test zio */
+       fini_raidz_map(&zio_test, &rm_test);
+
+       return (err);
+}
+
+static raidz_map_t *
+init_raidz_map(raidz_test_opts_t *opts, zio_t **zio, const int parity)
+{
+       raidz_map_t *rm = NULL;
+       const size_t alloc_dsize = opts->rto_dsize;
+       const size_t total_ncols = opts->rto_dcols + parity;
+       const int ccols[] = { 0, 1, 2 };
+
+       VERIFY(zio);
+       VERIFY(parity <= 3 && parity >= 1);
+
+       *zio = umem_zalloc(sizeof (zio_t), UMEM_NOFAIL);
+
+       (*zio)->io_offset = 0;
+       (*zio)->io_size = alloc_dsize;
+       (*zio)->io_data = raidz_alloc(alloc_dsize);
+       init_zio_data(*zio);
+
+       rm = vdev_raidz_map_alloc(*zio, opts->rto_ashift,
+               total_ncols, parity);
+       VERIFY(rm);
+
+       /* Make sure code columns are destroyed */
+       corrupt_colums(rm, ccols, parity);
+
+       return (rm);
+}
+
+static int
+run_gen_check(raidz_test_opts_t *opts)
+{
+       char **impl_name;
+       int fn, err = 0;
+       zio_t *zio_test;
+       raidz_map_t *rm_test;
+
+       err = init_raidz_golden_map(opts, PARITY_PQR);
+       if (0 != err)
+               return (err);
+
+       LOG(D_INFO, DBLSEP);
+       LOG(D_INFO, "Testing parity generation...\n");
+
+       for (impl_name = (char **)raidz_impl_names+1; *impl_name != NULL;
+           impl_name++) {
+
+               LOG(D_INFO, SEP);
+               LOG(D_INFO, "\tTesting [%s] implementation...", *impl_name);
+
+               if (0 != vdev_raidz_impl_set(*impl_name)) {
+                       LOG(D_INFO, "[SKIP]\n");
+                       continue;
+               } else {
+                       LOG(D_INFO, "[SUPPORTED]\n");
+               }
+
+               for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) {
+
+                       /* Check if should stop */
+                       if (rto_opts.rto_should_stop)
+                               return (err);
+
+                       /* create suitable raidz_map */
+                       rm_test = init_raidz_map(opts, &zio_test, fn+1);
+                       VERIFY(rm_test);
+
+                       LOG(D_INFO, "\t\tTesting method [%s] ...",
+                           raidz_gen_name[fn]);
+
+                       if (!opts->rto_sanity)
+                               vdev_raidz_generate_parity(rm_test);
+
+                       if (cmp_code(opts, rm_test, fn+1) != 0) {
+                               LOG(D_INFO, "[FAIL]\n");
+                               err++;
+                       } else
+                               LOG(D_INFO, "[PASS]\n");
+
+                       fini_raidz_map(&zio_test, &rm_test);
+               }
+       }
+
+       fini_raidz_map(&opts->zio_golden, &opts->rm_golden);
+
+       return (err);
+}
+
+static int
+run_rec_check_impl(raidz_test_opts_t *opts, raidz_map_t *rm, const int fn)
+{
+       int x0, x1, x2;
+       int tgtidx[3];
+       int err = 0;
+       static const int rec_tgts[7][3] = {
+               {1, 2, 3},      /* rec_p:   bad QR & D[0]       */
+               {0, 2, 3},      /* rec_q:   bad PR & D[0]       */
+               {0, 1, 3},      /* rec_r:   bad PQ & D[0]       */
+               {2, 3, 4},      /* rec_pq:  bad R  & D[0][1]    */
+               {1, 3, 4},      /* rec_pr:  bad Q  & D[0][1]    */
+               {0, 3, 4},      /* rec_qr:  bad P  & D[0][1]    */
+               {3, 4, 5}       /* rec_pqr: bad    & D[0][1][2] */
+       };
+
+       memcpy(tgtidx, rec_tgts[fn], sizeof (tgtidx));
+
+       if (fn < RAIDZ_REC_PQ) {
+               /* can reconstruct 1 failed data disk */
+               for (x0 = 0; x0 < opts->rto_dcols; x0++) {
+                       if (x0 >= rm->rm_cols - raidz_parity(rm))
+                               continue;
+
+                       /* Check if should stop */
+                       if (rto_opts.rto_should_stop)
+                               return (err);
+
+                       LOG(D_DEBUG, "[%d] ", x0);
+
+                       tgtidx[2] = x0 + raidz_parity(rm);
+
+                       corrupt_colums(rm, tgtidx+2, 1);
+
+                       if (!opts->rto_sanity)
+                               vdev_raidz_reconstruct(rm, tgtidx, 3);
+
+                       if (cmp_data(opts, rm) != 0) {
+                               err++;
+                               LOG(D_DEBUG, "\nREC D[%d]... [FAIL]\n", x0);
+                       }
+               }
+
+       } else if (fn < RAIDZ_REC_PQR) {
+               /* can reconstruct 2 failed data disk */
+               for (x0 = 0; x0 < opts->rto_dcols; x0++) {
+                       if (x0 >= rm->rm_cols - raidz_parity(rm))
+                               continue;
+                       for (x1 = x0 + 1; x1 < opts->rto_dcols; x1++) {
+                               if (x1 >= rm->rm_cols - raidz_parity(rm))
+                                       continue;
+
+                               /* Check if should stop */
+                               if (rto_opts.rto_should_stop)
+                                       return (err);
+
+                               LOG(D_DEBUG, "[%d %d] ", x0, x1);
+
+                               tgtidx[1] = x0 + raidz_parity(rm);
+                               tgtidx[2] = x1 + raidz_parity(rm);
+
+                               corrupt_colums(rm, tgtidx+1, 2);
+
+                               if (!opts->rto_sanity)
+                                       vdev_raidz_reconstruct(rm, tgtidx, 3);
+
+                               if (cmp_data(opts, rm) != 0) {
+                                       err++;
+                                       LOG(D_DEBUG, "\nREC D[%d %d]... "
+                                           "[FAIL]\n", x0, x1);
+                               }
+                       }
+               }
+       } else {
+               /* can reconstruct 3 failed data disk */
+               for (x0 = 0;
+                       x0 < opts->rto_dcols; x0++) {
+                       if (x0 >= rm->rm_cols - raidz_parity(rm))
+                               continue;
+                       for (x1 = x0 + 1;
+                               x1 < opts->rto_dcols; x1++) {
+                               if (x1 >= rm->rm_cols - raidz_parity(rm))
+                                       continue;
+                               for (x2 = x1 + 1;
+                                       x2 < opts->rto_dcols; x2++) {
+                                       if (x2 >=
+                                               rm->rm_cols - raidz_parity(rm))
+                                               continue;
+
+                                       /* Check if should stop */
+                                       if (rto_opts.rto_should_stop)
+                                               return (err);
+
+                                       LOG(D_DEBUG, "[%d %d %d]", x0, x1, x2);
+
+                                       tgtidx[0] = x0 + raidz_parity(rm);
+                                       tgtidx[1] = x1 + raidz_parity(rm);
+                                       tgtidx[2] = x2 + raidz_parity(rm);
+
+                                       corrupt_colums(rm, tgtidx, 3);
+
+                                       if (!opts->rto_sanity)
+                                               vdev_raidz_reconstruct(rm,
+                                                       tgtidx, 3);
+
+                                       if (cmp_data(opts, rm) != 0) {
+                                               err++;
+                                               LOG(D_DEBUG,
+                                                   "\nREC D[%d %d %d]... "
+                                                   "[FAIL]\n", x0, x1, x2);
+                                       }
+                               }
+                       }
+               }
+       }
+       return (err);
+}
+
+static int
+run_rec_check(raidz_test_opts_t *opts)
+{
+       char **impl_name;
+       unsigned fn, err = 0;
+       zio_t *zio_test;
+       raidz_map_t *rm_test;
+
+       err = init_raidz_golden_map(opts, PARITY_PQR);
+       if (0 != err)
+               return (err);
+
+       LOG(D_INFO, DBLSEP);
+       LOG(D_INFO, "Testing data reconstruction...\n");
+
+       for (impl_name = (char **)raidz_impl_names+1; *impl_name != NULL;
+           impl_name++) {
+
+               LOG(D_INFO, SEP);
+               LOG(D_INFO, "\tTesting [%s] implementation...", *impl_name);
+
+               if (vdev_raidz_impl_set(*impl_name) != 0) {
+                       LOG(D_INFO, "[SKIP]\n");
+                       continue;
+               } else
+                       LOG(D_INFO, "[SUPPORTED]\n");
+
+
+               /* create suitable raidz_map */
+               rm_test = init_raidz_map(opts, &zio_test, PARITY_PQR);
+               /* generate parity */
+               vdev_raidz_generate_parity(rm_test);
+
+               for (fn = 0; fn < RAIDZ_REC_NUM; fn++) {
+
+                       LOG(D_INFO, "\t\tTesting method [%s] ...",
+                               raidz_rec_name[fn]);
+
+                       if (run_rec_check_impl(opts, rm_test, fn) != 0) {
+                               LOG(D_INFO, "[FAIL]\n");
+                               err++;
+
+                       } else
+                               LOG(D_INFO, "[PASS]\n");
+
+               }
+               /* tear down test raidz_map */
+               fini_raidz_map(&zio_test, &rm_test);
+       }
+
+       fini_raidz_map(&opts->zio_golden, &opts->rm_golden);
+
+       return (err);
+}
+
+static int
+run_test(raidz_test_opts_t *opts)
+{
+       int err = 0;
+
+       if (opts == NULL)
+               opts = &rto_opts;
+
+       print_opts(opts, B_FALSE);
+
+       err |= run_gen_check(opts);
+       err |= run_rec_check(opts);
+
+       return (err);
+}
+
+#define        SWEEP_RUNNING   0
+#define        SWEEP_FINISHED  1
+#define        SWEEP_ERROR     2
+#define        SWEEP_TIMEOUT   3
+
+static int sweep_state = 0;
+static raidz_test_opts_t failed_opts;
+
+static kmutex_t sem_mtx;
+static kcondvar_t sem_cv;
+static int max_free_slots;
+static int free_slots;
+
+static void
+sweep_thread(void *arg)
+{
+       int err = 0;
+       raidz_test_opts_t *opts = (raidz_test_opts_t *) arg;
+       VERIFY(opts != NULL);
+
+       err = run_test(opts);
+
+       if (rto_opts.rto_sanity) {
+               /* 25% chance that a sweep test fails */
+               if (rand() < (RAND_MAX/4))
+                       err = 1;
+       }
+
+       if (0 != err) {
+               mutex_enter(&sem_mtx);
+               memcpy(&failed_opts, opts, sizeof (raidz_test_opts_t));
+               sweep_state = SWEEP_ERROR;
+               mutex_exit(&sem_mtx);
+       }
+
+       umem_free(opts, sizeof (raidz_test_opts_t));
+
+       /* signal the next thread */
+       mutex_enter(&sem_mtx);
+       free_slots++;
+       cv_signal(&sem_cv);
+       mutex_exit(&sem_mtx);
+
+       thread_exit();
+}
+
+static int
+run_sweep(void)
+{
+       static const size_t dcols_v[] = { 1, 2, 3, 4, 5, 6, 7, 8, 12, 15, 16 };
+       static const size_t ashift_v[] = { 9, 12, 14 };
+       static const size_t size_v[] = { 1 << 9, 21 * (1 << 9), 13 * (1 << 12),
+               1 << 17, (1 << 20) - (1 << 12), SPA_MAXBLOCKSIZE };
+
+       (void) setvbuf(stdout, NULL, _IONBF, 0);
+
+       ulong_t total_comb = ARRAY_SIZE(size_v) * ARRAY_SIZE(ashift_v) *
+           ARRAY_SIZE(dcols_v);
+       ulong_t tried_comb = 0;
+       hrtime_t time_diff, start_time = gethrtime();
+       raidz_test_opts_t *opts;
+       int a, d, s;
+
+       max_free_slots = free_slots = MAX(2, boot_ncpus);
+
+       mutex_init(&sem_mtx, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&sem_cv, NULL, CV_DEFAULT, NULL);
+
+       for (s = 0; s < ARRAY_SIZE(size_v); s++)
+       for (a = 0; a < ARRAY_SIZE(ashift_v); a++)
+       for (d = 0; d < ARRAY_SIZE(dcols_v); d++) {
+
+               if (size_v[s] < (1 << ashift_v[a])) {
+                       total_comb--;
+                       continue;
+               }
+
+               if (++tried_comb % 20 == 0)
+                       LOG(D_ALL, "%lu/%lu... ", tried_comb, total_comb);
+
+               /* wait for signal to start new thread */
+               mutex_enter(&sem_mtx);
+               while (cv_timedwait_sig(&sem_cv, &sem_mtx,
+                   ddi_get_lbolt() + hz)) {
+
+                       /* check if should stop the test (timeout) */
+                       time_diff = (gethrtime() - start_time) / NANOSEC;
+                       if (rto_opts.rto_sweep_timeout > 0 &&
+                           time_diff >= rto_opts.rto_sweep_timeout) {
+                               sweep_state = SWEEP_TIMEOUT;
+                               rto_opts.rto_should_stop = B_TRUE;
+                               mutex_exit(&sem_mtx);
+                               goto exit;
+                       }
+
+                       /* check if should stop the test (error) */
+                       if (sweep_state != SWEEP_RUNNING) {
+                               mutex_exit(&sem_mtx);
+                               goto exit;
+                       }
+
+                       /* exit loop if a slot is available */
+                       if (free_slots > 0) {
+                               break;
+                       }
+               }
+
+               free_slots--;
+               mutex_exit(&sem_mtx);
+
+               opts = umem_zalloc(sizeof (raidz_test_opts_t), UMEM_NOFAIL);
+               opts->rto_ashift = ashift_v[a];
+               opts->rto_dcols = dcols_v[d];
+               opts->rto_offset = (1 << ashift_v[a]) * rand();
+               opts->rto_dsize = size_v[s];
+               opts->rto_v = 0; /* be quiet */
+
+               VERIFY3P(zk_thread_create(NULL, 0,
+                   (thread_func_t) sweep_thread,
+                   (void *) opts, TS_RUN, NULL, 0, 0,
+                   PTHREAD_CREATE_JOINABLE), !=, NULL);
+       }
+
+exit:
+       LOG(D_ALL, "\nWaiting for test threads to finish...\n");
+       mutex_enter(&sem_mtx);
+       VERIFY(free_slots <= max_free_slots);
+       while (free_slots < max_free_slots) {
+               (void) cv_wait(&sem_cv, &sem_mtx);
+       }
+       mutex_exit(&sem_mtx);
+
+       if (sweep_state == SWEEP_ERROR) {
+               ERR("Sweep test failed! Failed option: \n");
+               print_opts(&failed_opts, B_TRUE);
+       } else {
+               if (sweep_state == SWEEP_TIMEOUT)
+                       LOG(D_ALL, "Test timeout (%lus). Stopping...\n",
+                           (ulong_t)rto_opts.rto_sweep_timeout);
+
+               LOG(D_ALL, "Sweep test succeeded on %lu raidz maps!\n",
+                   (ulong_t)tried_comb);
+       }
+
+       return (sweep_state == SWEEP_ERROR ? SWEEP_ERROR : 0);
+}
+
+int
+main(int argc, char **argv)
+{
+       size_t i;
+       struct sigaction action;
+       int err = 0;
+
+       /* init gdb string early */
+       (void) sprintf(gdb, gdb_tmpl, getpid());
+
+       action.sa_handler = sig_handler;
+       sigemptyset(&action.sa_mask);
+       action.sa_flags = 0;
+
+       if (sigaction(SIGSEGV, &action, NULL) < 0) {
+               ERR("raidz_test: cannot catch SIGSEGV: %s.\n", strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       (void) setvbuf(stdout, NULL, _IOLBF, 0);
+
+       dprintf_setup(&argc, argv);
+
+       process_options(argc, argv);
+
+       kernel_init(FREAD);
+
+       /* setup random data because rand() is not reentrant */
+       rand_data = (int *) umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
+       srand((unsigned)time(NULL) * getpid());
+       for (i = 0; i < SPA_MAXBLOCKSIZE / sizeof (int); i++)
+               rand_data[i] = rand();
+
+       mprotect(rand_data, SPA_MAXBLOCKSIZE, PROT_READ);
+
+       if (rto_opts.rto_benchmark) {
+               run_raidz_benchmark();
+       } else if (rto_opts.rto_sweep) {
+               err = run_sweep();
+       } else {
+               err = run_test(NULL);
+       }
+
+       umem_free(rand_data, SPA_MAXBLOCKSIZE);
+       kernel_fini();
+
+       return (err);
+}
diff --git a/zfs/cmd/raidz_test/raidz_test.h b/zfs/cmd/raidz_test/raidz_test.h
new file mode 100644 (file)
index 0000000..89bbf41
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#ifndef        RAIDZ_TEST_H
+#define        RAIDZ_TEST_H
+
+#include <sys/spa.h>
+
+static const char *raidz_impl_names[] = {
+       "original",
+       "scalar",
+       "sse2",
+       "ssse3",
+       "avx2",
+       "aarch64_neon",
+       "aarch64_neonx2",
+       NULL
+};
+
+typedef struct raidz_test_opts {
+       size_t rto_ashift;
+       size_t rto_offset;
+       size_t rto_dcols;
+       size_t rto_dsize;
+       size_t rto_v;
+       size_t rto_sweep;
+       size_t rto_sweep_timeout;
+       size_t rto_benchmark;
+       size_t rto_sanity;
+       size_t rto_gdb;
+
+       /* non-user options */
+       boolean_t rto_should_stop;
+
+       zio_t *zio_golden;
+       raidz_map_t *rm_golden;
+} raidz_test_opts_t;
+
+static const raidz_test_opts_t rto_opts_defaults = {
+       .rto_ashift = 9,
+       .rto_offset = 1ULL << 0,
+       .rto_dcols = 8,
+       .rto_dsize = 1<<19,
+       .rto_v = 0,
+       .rto_sweep = 0,
+       .rto_benchmark = 0,
+       .rto_sanity = 0,
+       .rto_gdb = 0,
+       .rto_should_stop = B_FALSE
+};
+
+extern raidz_test_opts_t rto_opts;
+
+static inline size_t ilog2(size_t a)
+{
+       return (a > 1 ? 1 + ilog2(a >> 1) : 0);
+}
+
+
+#define        D_ALL   0
+#define        D_INFO  1
+#define        D_DEBUG 2
+
+#define        LOG(lvl, a...)                          \
+{                                              \
+       if (rto_opts.rto_v >= lvl)              \
+               (void) fprintf(stdout, a);      \
+}                                              \
+
+#define        LOG_OPT(lvl, opt, a...)                 \
+{                                              \
+       if (opt->rto_v >= lvl)                  \
+               (void) fprintf(stdout, a);      \
+}                                              \
+
+#define        ERR(a...)       (void) fprintf(stderr, a)
+
+
+#define        DBLSEP "================\n"
+#define        SEP    "----------------\n"
+
+
+#define        raidz_alloc(size)       zio_data_buf_alloc(size)
+#define        raidz_free(p, size)     zio_data_buf_free(p, size)
+
+
+void init_zio_data(zio_t *zio);
+
+void run_raidz_benchmark(void);
+
+#endif /* RAIDZ_TEST_H */
diff --git a/zfs/cmd/vdev_id/Makefile.am b/zfs/cmd/vdev_id/Makefile.am
new file mode 100644 (file)
index 0000000..fb815fa
--- /dev/null
@@ -0,0 +1 @@
+dist_udev_SCRIPTS = vdev_id
diff --git a/zfs/cmd/vdev_id/Makefile.in b/zfs/cmd/vdev_id/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/vdev_id/vdev_id b/zfs/cmd/vdev_id/vdev_id
new file mode 100755 (executable)
index 0000000..0d617a8
--- /dev/null
@@ -0,0 +1,403 @@
+#!/bin/sh
+#
+# vdev_id: udev helper to generate user-friendly names for JBOD disks
+#
+# This script parses the file /etc/zfs/vdev_id.conf to map a
+# physical path in a storage topology to a channel name.  The
+# channel name is combined with a disk enclosure slot number to
+# create an alias that reflects the physical location of the drive.
+# This is particularly helpful when it comes to tasks like replacing
+# failed drives.  Slot numbers may also be re-mapped in case the
+# default numbering is unsatisfactory.  The drive aliases will be
+# created as symbolic links in /dev/disk/by-vdev.
+#
+# The currently supported topologies are sas_direct and sas_switch.
+# A multipath mode is supported in which dm-mpath devices are
+# handled by examining the first-listed running component disk.  In
+# multipath mode the configuration file should contain a channel
+# definition with the same name for each path to a given enclosure.
+#
+# The alias keyword provides a simple way to map already-existing
+# device symlinks to more convenient names.  It is suitable for
+# small, static configurations or for sites that have some automated
+# way to generate the mapping file.
+#
+#
+# Some example configuration files are given below.
+
+# #
+# # Example vdev_id.conf - sas_direct.
+# #
+#
+# multipath     no
+# topology      sas_direct
+# phys_per_port 4
+# slot          bay
+#
+# #       PCI_ID  HBA PORT  CHANNEL NAME
+# channel 85:00.0 1         A
+# channel 85:00.0 0         B
+# channel 86:00.0 1         C
+# channel 86:00.0 0         D
+#
+# # Custom mapping for Channel A
+#
+# #    Linux      Mapped
+# #    Slot       Slot      Channel
+# slot 1          7         A
+# slot 2          10        A
+# slot 3          3         A
+# slot 4          6         A
+#
+# # Default mapping for B, C, and D
+# slot 1          4
+# slot 2          2
+# slot 3          1
+# slot 4          3
+
+# #
+# # Example vdev_id.conf - sas_switch
+# #
+#
+# topology      sas_switch
+#
+# #       SWITCH PORT  CHANNEL NAME
+# channel 1            A
+# channel 2            B
+# channel 3            C
+# channel 4            D
+
+# #
+# # Example vdev_id.conf - multipath
+# #
+#
+# multipath yes
+#
+# #       PCI_ID  HBA PORT  CHANNEL NAME
+# channel 85:00.0 1         A
+# channel 85:00.0 0         B
+# channel 86:00.0 1         A
+# channel 86:00.0 0         B
+
+# #
+# # Example vdev_id.conf - alias
+# #
+#
+# #     by-vdev
+# #     name     fully qualified or base name of device link
+# alias d1       /dev/disk/by-id/wwn-0x5000c5002de3b9ca
+# alias d2       wwn-0x5000c5002def789e
+
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
+CONFIG=/etc/zfs/vdev_id.conf
+PHYS_PER_PORT=
+DEV=
+MULTIPATH=
+TOPOLOGY=
+BAY=
+
+usage() {
+       cat << EOF
+Usage: vdev_id [-h]
+       vdev_id <-d device> [-c config_file] [-p phys_per_port]
+               [-g sas_direct|sas_switch] [-m]
+
+  -c    specify name of alernate config file [default=$CONFIG]
+  -d    specify basename of device (i.e. sda)
+  -g    Storage network topology [default="$TOPOLOGY"]
+  -m    Run in multipath mode
+  -p    number of phy's per switch port [default=$PHYS_PER_PORT]
+  -h    show this summary
+EOF
+       exit 0
+}
+
+map_slot() {
+       local LINUX_SLOT=$1
+       local CHANNEL=$2
+       local MAPPED_SLOT=
+
+       MAPPED_SLOT=`awk "\\$1 == \"slot\" && \\$2 == ${LINUX_SLOT} && \
+                       \\$4 ~ /^${CHANNEL}$|^$/ { print \\$3; exit }" $CONFIG`
+       if [ -z "$MAPPED_SLOT" ] ; then
+               MAPPED_SLOT=$LINUX_SLOT
+       fi
+       printf "%d" ${MAPPED_SLOT}
+}
+
+map_channel() {
+       local MAPPED_CHAN=
+       local PCI_ID=$1
+       local PORT=$2
+
+       case $TOPOLOGY in
+               "sas_switch")
+               MAPPED_CHAN=`awk "\\$1 == \"channel\" && \\$2 == ${PORT} \
+                       { print \\$3; exit }" $CONFIG`
+               ;;
+               "sas_direct")
+               MAPPED_CHAN=`awk "\\$1 == \"channel\" && \
+                       \\$2 == \"${PCI_ID}\" && \\$3 == ${PORT} \
+                       { print \\$4; exit }" $CONFIG`
+               ;;
+       esac
+       printf "%s" ${MAPPED_CHAN}
+}
+
+sas_handler() {
+       if [ -z "$PHYS_PER_PORT" ] ; then
+               PHYS_PER_PORT=`awk "\\$1 == \"phys_per_port\" \
+                       {print \\$2; exit}" $CONFIG`
+       fi
+       PHYS_PER_PORT=${PHYS_PER_PORT:-4}
+       if ! echo $PHYS_PER_PORT | grep -q -E '^[0-9]+$' ; then
+               echo "Error: phys_per_port value $PHYS_PER_PORT is non-numeric"
+               exit 1
+       fi
+
+       if [ -z "$MULTIPATH_MODE" ] ; then
+               MULTIPATH_MODE=`awk "\\$1 == \"multipath\" \
+                       {print \\$2; exit}" $CONFIG`
+       fi
+
+       # Use first running component device if we're handling a dm-mpath device
+       if [ "$MULTIPATH_MODE" = "yes" ] ; then
+               # If udev didn't tell us the UUID via DM_NAME, check /dev/mapper
+               if [ -z "$DM_NAME" ] ; then
+                       DM_NAME=`ls -l --full-time /dev/mapper |
+                               awk "/\/$DEV$/{print \\$9}"`
+               fi
+
+               # For raw disks udev exports DEVTYPE=partition when
+               # handling partitions, and the rules can be written to
+               # take advantage of this to append a -part suffix.  For
+               # dm devices we get DEVTYPE=disk even for partitions so
+               # we have to append the -part suffix directly in the
+               # helper.
+               if [ "$DEVTYPE" != "partition" ] ; then
+                       PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
+               fi
+
+               # Strip off partition information.
+               DM_NAME=`echo $DM_NAME | sed 's/p[0-9][0-9]*$//'`
+               if [ -z "$DM_NAME" ] ; then
+                       return
+               fi
+
+               # Get the raw scsi device name from multipath -l.  Strip off
+               # leading pipe symbols to make field numbering consistent.
+               DEV=`multipath -l $DM_NAME |
+                       awk '/running/{gsub("^[|]"," "); print $3 ; exit}'`
+               if [ -z "$DEV" ] ; then
+                       return
+               fi
+       fi
+
+       if echo $DEV | grep -q ^/devices/ ; then
+               sys_path=$DEV
+       else
+               sys_path=`udevadm info -q path -p /sys/block/$DEV 2>/dev/null`
+       fi
+
+       # Use positional parameters as an ad-hoc array
+       set -- $(echo "$sys_path" | tr / ' ')
+       num_dirs=$#
+       scsi_host_dir="/sys"
+
+       # Get path up to /sys/.../hostX
+       i=1
+       while [ $i -le $num_dirs ] ; do
+               d=$(eval echo \${$i})
+               scsi_host_dir="$scsi_host_dir/$d"
+               echo $d | grep -q -E '^host[0-9]+$' && break
+               i=$(($i + 1))
+       done
+
+       if [ $i = $num_dirs ] ; then
+               return
+       fi
+
+       PCI_ID=$(eval echo \${$(($i -1))} | awk -F: '{print $2":"$3}')
+
+       # In sas_switch mode, the directory four levels beneath
+       # /sys/.../hostX contains symlinks to phy devices that reveal
+       # the switch port number.  In sas_direct mode, the phy links one
+       # directory down reveal the HBA port.
+       port_dir=$scsi_host_dir
+       case $TOPOLOGY in
+               "sas_switch") j=$(($i + 4)) ;;
+               "sas_direct") j=$(($i + 1)) ;;
+       esac
+
+       i=$(($i + 1))
+       while [ $i -le $j ] ; do
+               port_dir="$port_dir/$(eval echo \${$i})"
+               i=$(($i + 1))
+       done
+
+       PHY=`ls -d $port_dir/phy* 2>/dev/null | head -1 | awk -F: '{print $NF}'`
+       if [ -z "$PHY" ] ; then
+               return
+       fi
+       PORT=$(( $PHY / $PHYS_PER_PORT ))
+
+       # Look in /sys/.../sas_device/end_device-X for the bay_identifier
+       # attribute.
+       end_device_dir=$port_dir
+       while [ $i -lt $num_dirs ] ; do
+               d=$(eval echo \${$i})
+               end_device_dir="$end_device_dir/$d"
+               if echo $d | grep -q '^end_device' ; then
+                       end_device_dir="$end_device_dir/sas_device/$d"
+                       break
+               fi
+               i=$(($i + 1))
+       done
+
+       SLOT=
+       case $BAY in
+       "bay")
+               SLOT=`cat $end_device_dir/bay_identifier 2>/dev/null`
+               ;;
+       "phy")
+               SLOT=`cat $end_device_dir/phy_identifier 2>/dev/null`
+               ;;
+       "id")
+               i=$(($i + 1))
+               d=$(eval echo \${$i})
+               SLOT=`echo $d | sed -e 's/^.*://'`
+               ;;
+       "lun")
+               i=$(($i + 2))
+               d=$(eval echo \${$i})
+               SLOT=`echo $d | sed -e 's/^.*://'`
+               ;;
+       esac
+       if [ -z "$SLOT" ] ; then
+               return
+       fi
+
+       CHAN=`map_channel $PCI_ID $PORT`
+       SLOT=`map_slot $SLOT $CHAN`
+       if [ -z "$CHAN" ] ; then
+               return
+       fi
+       echo ${CHAN}${SLOT}${PART}
+}
+
+alias_handler () {
+       # Special handling is needed to correctly append a -part suffix
+       # to partitions of device mapper devices.  The DEVTYPE attribute
+       # is normally set to "disk" instead of "partition" in this case,
+       # so the udev rules won't handle that for us as they do for
+       # "plain" block devices.
+       #
+       # For example, we may have the following links for a device and its
+       # partitions,
+       #
+       #  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0   -> ../../dm-0
+       #  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p1 -> ../../dm-1
+       #  /dev/disk/by-id/dm-name-isw_dibgbfcije_ARRAY0p2 -> ../../dm-3
+       #
+       # and the following alias in vdev_id.conf.
+       #
+       #   alias A0 dm-name-isw_dibgbfcije_ARRAY0
+       #
+       # The desired outcome is for the following links to be created
+       # without having explicitly defined aliases for the partitions.
+       #
+       #  /dev/disk/by-vdev/A0       -> ../../dm-0
+       #  /dev/disk/by-vdev/A0-part1 -> ../../dm-1
+       #  /dev/disk/by-vdev/A0-part2 -> ../../dm-3
+       #
+       # Warning: The following grep pattern will misidentify whole-disk
+       #          devices whose names end with 'p' followed by a string of
+       #          digits as partitions, causing alias creation to fail. This
+       #          ambiguity seems unavoidable, so devices using this facility
+       #          must not use such names.
+       local DM_PART=
+       if echo $DM_NAME | grep -q -E 'p[0-9][0-9]*$' ; then
+               if [ "$DEVTYPE" != "partition" ] ; then
+                       DM_PART=`echo $DM_NAME | awk -Fp '/p/{print "-part"$2}'`
+               fi
+       fi
+
+       # DEVLINKS attribute must have been populated by already-run udev rules.
+       for link in $DEVLINKS ; do
+               # Remove partition information to match key of top-level device.
+               if [ -n "$DM_PART" ] ; then
+                       link=`echo $link | sed 's/p[0-9][0-9]*$//'`
+               fi
+               # Check both the fully qualified and the base name of link.
+               for l in $link `basename $link` ; do
+                       alias=`awk "\\$1 == \"alias\" && \\$3 == \"${l}\" \
+                                       { print \\$2; exit }" $CONFIG`
+                       if [ -n "$alias" ] ; then
+                               echo ${alias}${DM_PART}
+                               return
+                       fi
+               done
+       done
+}
+
+while getopts 'c:d:g:mp:h' OPTION; do
+       case ${OPTION} in
+       c)
+               CONFIG=${OPTARG}
+               ;;
+       d)
+               DEV=${OPTARG}
+               ;;
+       g)
+               TOPOLOGY=$OPTARG
+               ;;
+       p)
+               PHYS_PER_PORT=${OPTARG}
+               ;;
+       m)
+               MULTIPATH_MODE=yes
+               ;;
+       h)
+               usage
+               ;;
+       esac
+done
+
+if [ ! -r $CONFIG ] ; then
+       exit 0
+fi
+
+if [ -z "$DEV" ] ; then
+       echo "Error: missing required option -d"
+       exit 1
+fi
+
+if [ -z "$TOPOLOGY" ] ; then
+       TOPOLOGY=`awk "\\$1 == \"topology\" {print \\$2; exit}" $CONFIG`
+fi
+
+if [ -z "$BAY" ] ; then
+       BAY=`awk "\\$1 == \"slot\" {print \\$2; exit}" $CONFIG`
+fi
+
+# First check if an alias was defined for this device.
+ID_VDEV=`alias_handler`
+
+if [ -z "$ID_VDEV" ] ; then
+       BAY=${BAY:-bay}
+       TOPOLOGY=${TOPOLOGY:-sas_direct}
+       case $TOPOLOGY in
+               sas_direct|sas_switch)
+                       ID_VDEV=`sas_handler`
+                       ;;
+               *)
+                       echo "Error: unknown topology $TOPOLOGY"
+                       exit 1
+                       ;;
+       esac
+fi
+
+if [ -n "$ID_VDEV" ] ; then
+       echo "ID_VDEV=${ID_VDEV}"
+       echo "ID_VDEV_PATH=disk/by-vdev/${ID_VDEV}"
+fi
diff --git a/zfs/cmd/zdb/Makefile.am b/zfs/cmd/zdb/Makefile.am
new file mode 100644 (file)
index 0000000..eb8e677
--- /dev/null
@@ -0,0 +1,20 @@
+include $(top_srcdir)/config/Rules.am
+
+AM_CPPFLAGS += -DDEBUG
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+sbin_PROGRAMS = zdb
+
+zdb_SOURCES = \
+       zdb.c \
+       zdb_il.c
+
+zdb_LDADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
diff --git a/zfs/cmd/zdb/Makefile.in b/zfs/cmd/zdb/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zdb/zdb.c b/zfs/cmd/zdb/zdb.c
new file mode 100644 (file)
index 0000000..b9b0b29
--- /dev/null
@@ -0,0 +1,3922 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2015, Intel Corporation.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu.h>
+#include <sys/zap.h>
+#include <sys/fs/zfs.h>
+#include <sys/zfs_znode.h>
+#include <sys/zfs_sa.h>
+#include <sys/sa.h>
+#include <sys/sa_impl.h>
+#include <sys/vdev.h>
+#include <sys/vdev_impl.h>
+#include <sys/metaslab_impl.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dir.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_pool.h>
+#include <sys/dbuf.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/dmu_traverse.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+#include <sys/zfs_fuid.h>
+#include <sys/arc.h>
+#include <sys/ddt.h>
+#include <sys/zfeature.h>
+#include <zfs_comutil.h>
+#include <libzfs.h>
+
+#define        ZDB_COMPRESS_NAME(idx) ((idx) < ZIO_COMPRESS_FUNCTIONS ?        \
+       zio_compress_table[(idx)].ci_name : "UNKNOWN")
+#define        ZDB_CHECKSUM_NAME(idx) ((idx) < ZIO_CHECKSUM_FUNCTIONS ?        \
+       zio_checksum_table[(idx)].ci_name : "UNKNOWN")
+#define        ZDB_OT_TYPE(idx) ((idx) < DMU_OT_NUMTYPES ? (idx) :             \
+       (((idx) == DMU_OTN_ZAP_DATA || (idx) == DMU_OTN_ZAP_METADATA) ? \
+       DMU_OT_ZAP_OTHER : DMU_OT_NUMTYPES))
+
+static char *
+zdb_ot_name(dmu_object_type_t type)
+{
+       if (type < DMU_OT_NUMTYPES)
+               return (dmu_ot[type].ot_name);
+       else if ((type & DMU_OT_NEWTYPE) &&
+               ((type & DMU_OT_BYTESWAP_MASK) < DMU_BSWAP_NUMFUNCS))
+               return (dmu_ot_byteswap[type & DMU_OT_BYTESWAP_MASK].ob_name);
+       else
+               return ("UNKNOWN");
+}
+
+#ifndef lint
+extern int zfs_recover;
+extern uint64_t zfs_arc_max, zfs_arc_meta_limit;
+extern int zfs_vdev_async_read_max_active;
+#else
+int zfs_recover;
+uint64_t zfs_arc_max, zfs_arc_meta_limit;
+int zfs_vdev_async_read_max_active;
+#endif
+
+const char cmdname[] = "zdb";
+uint8_t dump_opt[256];
+
+typedef void object_viewer_t(objset_t *, uint64_t, void *data, size_t size);
+
+extern void dump_intent_log(zilog_t *);
+uint64_t *zopt_object = NULL;
+int zopt_objects = 0;
+libzfs_handle_t *g_zfs;
+uint64_t max_inflight = 1000;
+
+static void snprintf_blkptr_compact(char *, size_t, const blkptr_t *);
+
+/*
+ * These libumem hooks provide a reasonable set of defaults for the allocator's
+ * debugging facilities.
+ */
+const char *
+_umem_debug_init(void)
+{
+       return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+       return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+
+static void
+usage(void)
+{
+       (void) fprintf(stderr,
+           "Usage: %s [-CumMdibcsDvhLXFPA] [-t txg] [-e [-p path...]] "
+           "[-U config] [-I inflight I/Os] [-x dumpdir] poolname [object...]\n"
+           "       %s [-divPA] [-e -p path...] [-U config] dataset "
+           "[object...]\n"
+           "       %s -mM [-LXFPA] [-t txg] [-e [-p path...]] [-U config] "
+           "poolname [vdev [metaslab...]]\n"
+           "       %s -R [-A] [-e [-p path...]] poolname "
+           "vdev:offset:size[:flags]\n"
+           "       %s -S [-PA] [-e [-p path...]] [-U config] poolname\n"
+           "       %s -l [-uA] device\n"
+           "       %s -C [-A] [-U config]\n\n",
+           cmdname, cmdname, cmdname, cmdname, cmdname, cmdname, cmdname);
+
+       (void) fprintf(stderr, "    Dataset name must include at least one "
+           "separator character '/' or '@'\n");
+       (void) fprintf(stderr, "    If dataset name is specified, only that "
+           "dataset is dumped\n");
+       (void) fprintf(stderr, "    If object numbers are specified, only "
+           "those objects are dumped\n\n");
+       (void) fprintf(stderr, "    Options to control amount of output:\n");
+       (void) fprintf(stderr, "        -u uberblock\n");
+       (void) fprintf(stderr, "        -d dataset(s)\n");
+       (void) fprintf(stderr, "        -i intent logs\n");
+       (void) fprintf(stderr, "        -C config (or cachefile if alone)\n");
+       (void) fprintf(stderr, "        -h pool history\n");
+       (void) fprintf(stderr, "        -b block statistics\n");
+       (void) fprintf(stderr, "        -m metaslabs\n");
+       (void) fprintf(stderr, "        -M metaslab groups\n");
+       (void) fprintf(stderr, "        -c checksum all metadata (twice for "
+           "all data) blocks\n");
+       (void) fprintf(stderr, "        -s report stats on zdb's I/O\n");
+       (void) fprintf(stderr, "        -D dedup statistics\n");
+       (void) fprintf(stderr, "        -S simulate dedup to measure effect\n");
+       (void) fprintf(stderr, "        -v verbose (applies to all others)\n");
+       (void) fprintf(stderr, "        -l dump label contents\n");
+       (void) fprintf(stderr, "        -L disable leak tracking (do not "
+           "load spacemaps)\n");
+       (void) fprintf(stderr, "        -R read and display block from a "
+           "device\n\n");
+       (void) fprintf(stderr, "    Below options are intended for use "
+           "with other options:\n");
+       (void) fprintf(stderr, "        -A ignore assertions (-A), enable "
+           "panic recovery (-AA) or both (-AAA)\n");
+       (void) fprintf(stderr, "        -F attempt automatic rewind within "
+           "safe range of transaction groups\n");
+       (void) fprintf(stderr, "        -U <cachefile_path> -- use alternate "
+           "cachefile\n");
+       (void) fprintf(stderr, "        -X attempt extreme rewind (does not "
+           "work with dataset)\n");
+       (void) fprintf(stderr, "        -e pool is exported/destroyed/"
+           "has altroot/not in a cachefile\n");
+       (void) fprintf(stderr, "        -p <path> -- use one or more with "
+           "-e to specify path to vdev dir\n");
+       (void) fprintf(stderr, "        -x <dumpdir> -- "
+           "dump all read blocks into specified directory\n");
+       (void) fprintf(stderr, "        -P print numbers in parsable form\n");
+       (void) fprintf(stderr, "        -t <txg> -- highest txg to use when "
+           "searching for uberblocks\n");
+       (void) fprintf(stderr, "        -I <number of inflight I/Os> -- "
+           "specify the maximum number of "
+           "checksumming I/Os [default is 200]\n");
+       (void) fprintf(stderr, "Specify an option more than once (e.g. -bb) "
+           "to make only that option verbose\n");
+       (void) fprintf(stderr, "Default is to dump everything non-verbosely\n");
+       exit(1);
+}
+
+/*
+ * Called for usage errors that are discovered after a call to spa_open(),
+ * dmu_bonus_hold(), or pool_match().  abort() is called for other errors.
+ */
+
+static void
+fatal(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       (void) fprintf(stderr, "%s: ", cmdname);
+       (void) vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void) fprintf(stderr, "\n");
+
+       exit(1);
+}
+
+/* ARGSUSED */
+static void
+dump_packed_nvlist(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       nvlist_t *nv;
+       size_t nvsize = *(uint64_t *)data;
+       char *packed = umem_alloc(nvsize, UMEM_NOFAIL);
+
+       VERIFY(0 == dmu_read(os, object, 0, nvsize, packed, DMU_READ_PREFETCH));
+
+       VERIFY(nvlist_unpack(packed, nvsize, &nv, 0) == 0);
+
+       umem_free(packed, nvsize);
+
+       dump_nvlist(nv, 8);
+
+       nvlist_free(nv);
+}
+
+/* ARGSUSED */
+static void
+dump_history_offsets(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       spa_history_phys_t *shp = data;
+
+       if (shp == NULL)
+               return;
+
+       (void) printf("\t\tpool_create_len = %llu\n",
+           (u_longlong_t)shp->sh_pool_create_len);
+       (void) printf("\t\tphys_max_off = %llu\n",
+           (u_longlong_t)shp->sh_phys_max_off);
+       (void) printf("\t\tbof = %llu\n",
+           (u_longlong_t)shp->sh_bof);
+       (void) printf("\t\teof = %llu\n",
+           (u_longlong_t)shp->sh_eof);
+       (void) printf("\t\trecords_lost = %llu\n",
+           (u_longlong_t)shp->sh_records_lost);
+}
+
+static void
+zdb_nicenum(uint64_t num, char *buf)
+{
+       if (dump_opt['P'])
+               (void) sprintf(buf, "%llu", (longlong_t)num);
+       else
+               nicenum(num, buf);
+}
+
+const char histo_stars[] = "****************************************";
+const int histo_width = sizeof (histo_stars) - 1;
+
+static void
+dump_histogram(const uint64_t *histo, int size, int offset)
+{
+       int i;
+       int minidx = size - 1;
+       int maxidx = 0;
+       uint64_t max = 0;
+
+       for (i = 0; i < size; i++) {
+               if (histo[i] > max)
+                       max = histo[i];
+               if (histo[i] > 0 && i > maxidx)
+                       maxidx = i;
+               if (histo[i] > 0 && i < minidx)
+                       minidx = i;
+       }
+
+       if (max < histo_width)
+               max = histo_width;
+
+       for (i = minidx; i <= maxidx; i++) {
+               (void) printf("\t\t\t%3u: %6llu %s\n",
+                   i + offset, (u_longlong_t)histo[i],
+                   &histo_stars[(max - histo[i]) * histo_width / max]);
+       }
+}
+
+static void
+dump_zap_stats(objset_t *os, uint64_t object)
+{
+       int error;
+       zap_stats_t zs;
+
+       error = zap_get_stats(os, object, &zs);
+       if (error)
+               return;
+
+       if (zs.zs_ptrtbl_len == 0) {
+               ASSERT(zs.zs_num_blocks == 1);
+               (void) printf("\tmicrozap: %llu bytes, %llu entries\n",
+                   (u_longlong_t)zs.zs_blocksize,
+                   (u_longlong_t)zs.zs_num_entries);
+               return;
+       }
+
+       (void) printf("\tFat ZAP stats:\n");
+
+       (void) printf("\t\tPointer table:\n");
+       (void) printf("\t\t\t%llu elements\n",
+           (u_longlong_t)zs.zs_ptrtbl_len);
+       (void) printf("\t\t\tzt_blk: %llu\n",
+           (u_longlong_t)zs.zs_ptrtbl_zt_blk);
+       (void) printf("\t\t\tzt_numblks: %llu\n",
+           (u_longlong_t)zs.zs_ptrtbl_zt_numblks);
+       (void) printf("\t\t\tzt_shift: %llu\n",
+           (u_longlong_t)zs.zs_ptrtbl_zt_shift);
+       (void) printf("\t\t\tzt_blks_copied: %llu\n",
+           (u_longlong_t)zs.zs_ptrtbl_blks_copied);
+       (void) printf("\t\t\tzt_nextblk: %llu\n",
+           (u_longlong_t)zs.zs_ptrtbl_nextblk);
+
+       (void) printf("\t\tZAP entries: %llu\n",
+           (u_longlong_t)zs.zs_num_entries);
+       (void) printf("\t\tLeaf blocks: %llu\n",
+           (u_longlong_t)zs.zs_num_leafs);
+       (void) printf("\t\tTotal blocks: %llu\n",
+           (u_longlong_t)zs.zs_num_blocks);
+       (void) printf("\t\tzap_block_type: 0x%llx\n",
+           (u_longlong_t)zs.zs_block_type);
+       (void) printf("\t\tzap_magic: 0x%llx\n",
+           (u_longlong_t)zs.zs_magic);
+       (void) printf("\t\tzap_salt: 0x%llx\n",
+           (u_longlong_t)zs.zs_salt);
+
+       (void) printf("\t\tLeafs with 2^n pointers:\n");
+       dump_histogram(zs.zs_leafs_with_2n_pointers, ZAP_HISTOGRAM_SIZE, 0);
+
+       (void) printf("\t\tBlocks with n*5 entries:\n");
+       dump_histogram(zs.zs_blocks_with_n5_entries, ZAP_HISTOGRAM_SIZE, 0);
+
+       (void) printf("\t\tBlocks n/10 full:\n");
+       dump_histogram(zs.zs_blocks_n_tenths_full, ZAP_HISTOGRAM_SIZE, 0);
+
+       (void) printf("\t\tEntries with n chunks:\n");
+       dump_histogram(zs.zs_entries_using_n_chunks, ZAP_HISTOGRAM_SIZE, 0);
+
+       (void) printf("\t\tBuckets with n entries:\n");
+       dump_histogram(zs.zs_buckets_with_n_entries, ZAP_HISTOGRAM_SIZE, 0);
+}
+
+/*ARGSUSED*/
+static void
+dump_none(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_unknown(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       (void) printf("\tUNKNOWN OBJECT TYPE\n");
+}
+
+/*ARGSUSED*/
+void
+dump_uint8(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_uint64(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_zap(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       zap_cursor_t zc;
+       zap_attribute_t attr;
+       void *prop;
+       int i;
+
+       dump_zap_stats(os, object);
+       (void) printf("\n");
+
+       for (zap_cursor_init(&zc, os, object);
+           zap_cursor_retrieve(&zc, &attr) == 0;
+           zap_cursor_advance(&zc)) {
+               (void) printf("\t\t%s = ", attr.za_name);
+               if (attr.za_num_integers == 0) {
+                       (void) printf("\n");
+                       continue;
+               }
+               prop = umem_zalloc(attr.za_num_integers *
+                   attr.za_integer_length, UMEM_NOFAIL);
+               (void) zap_lookup(os, object, attr.za_name,
+                   attr.za_integer_length, attr.za_num_integers, prop);
+               if (attr.za_integer_length == 1) {
+                       (void) printf("%s", (char *)prop);
+               } else {
+                       for (i = 0; i < attr.za_num_integers; i++) {
+                               switch (attr.za_integer_length) {
+                               case 2:
+                                       (void) printf("%u ",
+                                           ((uint16_t *)prop)[i]);
+                                       break;
+                               case 4:
+                                       (void) printf("%u ",
+                                           ((uint32_t *)prop)[i]);
+                                       break;
+                               case 8:
+                                       (void) printf("%lld ",
+                                           (u_longlong_t)((int64_t *)prop)[i]);
+                                       break;
+                               }
+                       }
+               }
+               (void) printf("\n");
+               umem_free(prop, attr.za_num_integers * attr.za_integer_length);
+       }
+       zap_cursor_fini(&zc);
+}
+
+static void
+dump_bpobj(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       bpobj_phys_t *bpop = data;
+       uint64_t i;
+       char bytes[32], comp[32], uncomp[32];
+
+       if (bpop == NULL)
+               return;
+
+       zdb_nicenum(bpop->bpo_bytes, bytes);
+       zdb_nicenum(bpop->bpo_comp, comp);
+       zdb_nicenum(bpop->bpo_uncomp, uncomp);
+
+       (void) printf("\t\tnum_blkptrs = %llu\n",
+           (u_longlong_t)bpop->bpo_num_blkptrs);
+       (void) printf("\t\tbytes = %s\n", bytes);
+       if (size >= BPOBJ_SIZE_V1) {
+               (void) printf("\t\tcomp = %s\n", comp);
+               (void) printf("\t\tuncomp = %s\n", uncomp);
+       }
+       if (size >= sizeof (*bpop)) {
+               (void) printf("\t\tsubobjs = %llu\n",
+                   (u_longlong_t)bpop->bpo_subobjs);
+               (void) printf("\t\tnum_subobjs = %llu\n",
+                   (u_longlong_t)bpop->bpo_num_subobjs);
+       }
+
+       if (dump_opt['d'] < 5)
+               return;
+
+       for (i = 0; i < bpop->bpo_num_blkptrs; i++) {
+               char blkbuf[BP_SPRINTF_LEN];
+               blkptr_t bp;
+
+               int err = dmu_read(os, object,
+                   i * sizeof (bp), sizeof (bp), &bp, 0);
+               if (err != 0) {
+                       (void) printf("got error %u from dmu_read\n", err);
+                       break;
+               }
+               snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), &bp);
+               (void) printf("\t%s\n", blkbuf);
+       }
+}
+
+/* ARGSUSED */
+static void
+dump_bpobj_subobjs(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       dmu_object_info_t doi;
+       int64_t i;
+
+       VERIFY0(dmu_object_info(os, object, &doi));
+       uint64_t *subobjs = kmem_alloc(doi.doi_max_offset, KM_SLEEP);
+
+       int err = dmu_read(os, object, 0, doi.doi_max_offset, subobjs, 0);
+       if (err != 0) {
+               (void) printf("got error %u from dmu_read\n", err);
+               kmem_free(subobjs, doi.doi_max_offset);
+               return;
+       }
+
+       int64_t last_nonzero = -1;
+       for (i = 0; i < doi.doi_max_offset / 8; i++) {
+               if (subobjs[i] != 0)
+                       last_nonzero = i;
+       }
+
+       for (i = 0; i <= last_nonzero; i++) {
+               (void) printf("\t%llu\n", (u_longlong_t)subobjs[i]);
+       }
+       kmem_free(subobjs, doi.doi_max_offset);
+}
+
+/*ARGSUSED*/
+static void
+dump_ddt_zap(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       dump_zap_stats(os, object);
+       /* contents are printed elsewhere, properly decoded */
+}
+
+/*ARGSUSED*/
+static void
+dump_sa_attrs(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       zap_cursor_t zc;
+       zap_attribute_t attr;
+
+       dump_zap_stats(os, object);
+       (void) printf("\n");
+
+       for (zap_cursor_init(&zc, os, object);
+           zap_cursor_retrieve(&zc, &attr) == 0;
+           zap_cursor_advance(&zc)) {
+               (void) printf("\t\t%s = ", attr.za_name);
+               if (attr.za_num_integers == 0) {
+                       (void) printf("\n");
+                       continue;
+               }
+               (void) printf(" %llx : [%d:%d:%d]\n",
+                   (u_longlong_t)attr.za_first_integer,
+                   (int)ATTR_LENGTH(attr.za_first_integer),
+                   (int)ATTR_BSWAP(attr.za_first_integer),
+                   (int)ATTR_NUM(attr.za_first_integer));
+       }
+       zap_cursor_fini(&zc);
+}
+
+/*ARGSUSED*/
+static void
+dump_sa_layouts(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       zap_cursor_t zc;
+       zap_attribute_t attr;
+       uint16_t *layout_attrs;
+       int i;
+
+       dump_zap_stats(os, object);
+       (void) printf("\n");
+
+       for (zap_cursor_init(&zc, os, object);
+           zap_cursor_retrieve(&zc, &attr) == 0;
+           zap_cursor_advance(&zc)) {
+               (void) printf("\t\t%s = [", attr.za_name);
+               if (attr.za_num_integers == 0) {
+                       (void) printf("\n");
+                       continue;
+               }
+
+               VERIFY(attr.za_integer_length == 2);
+               layout_attrs = umem_zalloc(attr.za_num_integers *
+                   attr.za_integer_length, UMEM_NOFAIL);
+
+               VERIFY(zap_lookup(os, object, attr.za_name,
+                   attr.za_integer_length,
+                   attr.za_num_integers, layout_attrs) == 0);
+
+               for (i = 0; i != attr.za_num_integers; i++)
+                       (void) printf(" %d ", (int)layout_attrs[i]);
+               (void) printf("]\n");
+               umem_free(layout_attrs,
+                   attr.za_num_integers * attr.za_integer_length);
+       }
+       zap_cursor_fini(&zc);
+}
+
+/*ARGSUSED*/
+static void
+dump_zpldir(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       zap_cursor_t zc;
+       zap_attribute_t attr;
+       const char *typenames[] = {
+               /* 0 */ "not specified",
+               /* 1 */ "FIFO",
+               /* 2 */ "Character Device",
+               /* 3 */ "3 (invalid)",
+               /* 4 */ "Directory",
+               /* 5 */ "5 (invalid)",
+               /* 6 */ "Block Device",
+               /* 7 */ "7 (invalid)",
+               /* 8 */ "Regular File",
+               /* 9 */ "9 (invalid)",
+               /* 10 */ "Symbolic Link",
+               /* 11 */ "11 (invalid)",
+               /* 12 */ "Socket",
+               /* 13 */ "Door",
+               /* 14 */ "Event Port",
+               /* 15 */ "15 (invalid)",
+       };
+
+       dump_zap_stats(os, object);
+       (void) printf("\n");
+
+       for (zap_cursor_init(&zc, os, object);
+           zap_cursor_retrieve(&zc, &attr) == 0;
+           zap_cursor_advance(&zc)) {
+               (void) printf("\t\t%s = %lld (type: %s)\n",
+                   attr.za_name, ZFS_DIRENT_OBJ(attr.za_first_integer),
+                   typenames[ZFS_DIRENT_TYPE(attr.za_first_integer)]);
+       }
+       zap_cursor_fini(&zc);
+}
+
+int
+get_dtl_refcount(vdev_t *vd)
+{
+       int refcount = 0;
+       int c;
+
+       if (vd->vdev_ops->vdev_op_leaf) {
+               space_map_t *sm = vd->vdev_dtl_sm;
+
+               if (sm != NULL &&
+                   sm->sm_dbuf->db_size == sizeof (space_map_phys_t))
+                       return (1);
+               return (0);
+       }
+
+       for (c = 0; c < vd->vdev_children; c++)
+               refcount += get_dtl_refcount(vd->vdev_child[c]);
+       return (refcount);
+}
+
+int
+get_metaslab_refcount(vdev_t *vd)
+{
+       int refcount = 0;
+       int c, m;
+
+       if (vd->vdev_top == vd && !vd->vdev_removing) {
+               for (m = 0; m < vd->vdev_ms_count; m++) {
+                       space_map_t *sm = vd->vdev_ms[m]->ms_sm;
+
+                       if (sm != NULL &&
+                           sm->sm_dbuf->db_size == sizeof (space_map_phys_t))
+                               refcount++;
+               }
+       }
+       for (c = 0; c < vd->vdev_children; c++)
+               refcount += get_metaslab_refcount(vd->vdev_child[c]);
+
+       return (refcount);
+}
+
+static int
+verify_spacemap_refcounts(spa_t *spa)
+{
+       uint64_t expected_refcount = 0;
+       uint64_t actual_refcount;
+
+       (void) feature_get_refcount(spa,
+           &spa_feature_table[SPA_FEATURE_SPACEMAP_HISTOGRAM],
+           &expected_refcount);
+       actual_refcount = get_dtl_refcount(spa->spa_root_vdev);
+       actual_refcount += get_metaslab_refcount(spa->spa_root_vdev);
+
+       if (expected_refcount != actual_refcount) {
+               (void) printf("space map refcount mismatch: expected %lld != "
+                   "actual %lld\n",
+                   (longlong_t)expected_refcount,
+                   (longlong_t)actual_refcount);
+               return (2);
+       }
+       return (0);
+}
+
+static void
+dump_spacemap(objset_t *os, space_map_t *sm)
+{
+       uint64_t alloc, offset, entry;
+       char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
+                           "INVALID", "INVALID", "INVALID", "INVALID" };
+
+       if (sm == NULL)
+               return;
+
+       /*
+        * Print out the freelist entries in both encoded and decoded form.
+        */
+       alloc = 0;
+       for (offset = 0; offset < space_map_length(sm);
+           offset += sizeof (entry)) {
+               uint8_t mapshift = sm->sm_shift;
+
+               VERIFY0(dmu_read(os, space_map_object(sm), offset,
+                   sizeof (entry), &entry, DMU_READ_PREFETCH));
+               if (SM_DEBUG_DECODE(entry)) {
+
+                       (void) printf("\t    [%6llu] %s: txg %llu, pass %llu\n",
+                           (u_longlong_t)(offset / sizeof (entry)),
+                           ddata[SM_DEBUG_ACTION_DECODE(entry)],
+                           (u_longlong_t)SM_DEBUG_TXG_DECODE(entry),
+                           (u_longlong_t)SM_DEBUG_SYNCPASS_DECODE(entry));
+               } else {
+                       (void) printf("\t    [%6llu]    %c  range:"
+                           " %010llx-%010llx  size: %06llx\n",
+                           (u_longlong_t)(offset / sizeof (entry)),
+                           SM_TYPE_DECODE(entry) == SM_ALLOC ? 'A' : 'F',
+                           (u_longlong_t)((SM_OFFSET_DECODE(entry) <<
+                           mapshift) + sm->sm_start),
+                           (u_longlong_t)((SM_OFFSET_DECODE(entry) <<
+                           mapshift) + sm->sm_start +
+                           (SM_RUN_DECODE(entry) << mapshift)),
+                           (u_longlong_t)(SM_RUN_DECODE(entry) << mapshift));
+                       if (SM_TYPE_DECODE(entry) == SM_ALLOC)
+                               alloc += SM_RUN_DECODE(entry) << mapshift;
+                       else
+                               alloc -= SM_RUN_DECODE(entry) << mapshift;
+               }
+       }
+       if (alloc != space_map_allocated(sm)) {
+               (void) printf("space_map_object alloc (%llu) INCONSISTENT "
+                   "with space map summary (%llu)\n",
+                   (u_longlong_t)space_map_allocated(sm), (u_longlong_t)alloc);
+       }
+}
+
+static void
+dump_metaslab_stats(metaslab_t *msp)
+{
+       char maxbuf[32];
+       range_tree_t *rt = msp->ms_tree;
+       avl_tree_t *t = &msp->ms_size_tree;
+       int free_pct = range_tree_space(rt) * 100 / msp->ms_size;
+
+       zdb_nicenum(metaslab_block_maxsize(msp), maxbuf);
+
+       (void) printf("\t %25s %10lu   %7s  %6s   %4s %4d%%\n",
+           "segments", avl_numnodes(t), "maxsize", maxbuf,
+           "freepct", free_pct);
+       (void) printf("\tIn-memory histogram:\n");
+       dump_histogram(rt->rt_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
+}
+
+static void
+dump_metaslab(metaslab_t *msp)
+{
+       vdev_t *vd = msp->ms_group->mg_vd;
+       spa_t *spa = vd->vdev_spa;
+       space_map_t *sm = msp->ms_sm;
+       char freebuf[32];
+
+       zdb_nicenum(msp->ms_size - space_map_allocated(sm), freebuf);
+
+       (void) printf(
+           "\tmetaslab %6llu   offset %12llx   spacemap %6llu   free    %5s\n",
+           (u_longlong_t)msp->ms_id, (u_longlong_t)msp->ms_start,
+           (u_longlong_t)space_map_object(sm), freebuf);
+
+       if (dump_opt['m'] > 2 && !dump_opt['L']) {
+               mutex_enter(&msp->ms_lock);
+               metaslab_load_wait(msp);
+               if (!msp->ms_loaded) {
+                       VERIFY0(metaslab_load(msp));
+                       range_tree_stat_verify(msp->ms_tree);
+               }
+               dump_metaslab_stats(msp);
+               metaslab_unload(msp);
+               mutex_exit(&msp->ms_lock);
+       }
+
+       if (dump_opt['m'] > 1 && sm != NULL &&
+           spa_feature_is_active(spa, SPA_FEATURE_SPACEMAP_HISTOGRAM)) {
+               /*
+                * The space map histogram represents free space in chunks
+                * of sm_shift (i.e. bucket 0 refers to 2^sm_shift).
+                */
+               (void) printf("\tOn-disk histogram:\t\tfragmentation %llu\n",
+                   (u_longlong_t)msp->ms_fragmentation);
+               dump_histogram(sm->sm_phys->smp_histogram,
+                   SPACE_MAP_HISTOGRAM_SIZE, sm->sm_shift);
+       }
+
+       if (dump_opt['d'] > 5 || dump_opt['m'] > 3) {
+               ASSERT(msp->ms_size == (1ULL << vd->vdev_ms_shift));
+
+               mutex_enter(&msp->ms_lock);
+               dump_spacemap(spa->spa_meta_objset, msp->ms_sm);
+               mutex_exit(&msp->ms_lock);
+       }
+}
+
+static void
+print_vdev_metaslab_header(vdev_t *vd)
+{
+       (void) printf("\tvdev %10llu\n\t%-10s%5llu   %-19s   %-15s   %-10s\n",
+           (u_longlong_t)vd->vdev_id,
+           "metaslabs", (u_longlong_t)vd->vdev_ms_count,
+           "offset", "spacemap", "free");
+       (void) printf("\t%15s   %19s   %15s   %10s\n",
+           "---------------", "-------------------",
+           "---------------", "-------------");
+}
+
+static void
+dump_metaslab_groups(spa_t *spa)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+       metaslab_class_t *mc = spa_normal_class(spa);
+       uint64_t fragmentation;
+       int c;
+
+       metaslab_class_histogram_verify(mc);
+
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               metaslab_group_t *mg = tvd->vdev_mg;
+
+               if (mg->mg_class != mc)
+                       continue;
+
+               metaslab_group_histogram_verify(mg);
+               mg->mg_fragmentation = metaslab_group_fragmentation(mg);
+
+               (void) printf("\tvdev %10llu\t\tmetaslabs%5llu\t\t"
+                   "fragmentation",
+                   (u_longlong_t)tvd->vdev_id,
+                   (u_longlong_t)tvd->vdev_ms_count);
+               if (mg->mg_fragmentation == ZFS_FRAG_INVALID) {
+                       (void) printf("%3s\n", "-");
+               } else {
+                       (void) printf("%3llu%%\n",
+                           (u_longlong_t)mg->mg_fragmentation);
+               }
+               dump_histogram(mg->mg_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
+       }
+
+       (void) printf("\tpool %s\tfragmentation", spa_name(spa));
+       fragmentation = metaslab_class_fragmentation(mc);
+       if (fragmentation == ZFS_FRAG_INVALID)
+               (void) printf("\t%3s\n", "-");
+       else
+               (void) printf("\t%3llu%%\n", (u_longlong_t)fragmentation);
+       dump_histogram(mc->mc_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
+}
+
+static void
+dump_metaslabs(spa_t *spa)
+{
+       vdev_t *vd, *rvd = spa->spa_root_vdev;
+       uint64_t m, c = 0, children = rvd->vdev_children;
+
+       (void) printf("\nMetaslabs:\n");
+
+       if (!dump_opt['d'] && zopt_objects > 0) {
+               c = zopt_object[0];
+
+               if (c >= children)
+                       (void) fatal("bad vdev id: %llu", (u_longlong_t)c);
+
+               if (zopt_objects > 1) {
+                       vd = rvd->vdev_child[c];
+                       print_vdev_metaslab_header(vd);
+
+                       for (m = 1; m < zopt_objects; m++) {
+                               if (zopt_object[m] < vd->vdev_ms_count)
+                                       dump_metaslab(
+                                           vd->vdev_ms[zopt_object[m]]);
+                               else
+                                       (void) fprintf(stderr, "bad metaslab "
+                                           "number %llu\n",
+                                           (u_longlong_t)zopt_object[m]);
+                       }
+                       (void) printf("\n");
+                       return;
+               }
+               children = c + 1;
+       }
+       for (; c < children; c++) {
+               vd = rvd->vdev_child[c];
+               print_vdev_metaslab_header(vd);
+
+               for (m = 0; m < vd->vdev_ms_count; m++)
+                       dump_metaslab(vd->vdev_ms[m]);
+               (void) printf("\n");
+       }
+}
+
+static void
+dump_dde(const ddt_t *ddt, const ddt_entry_t *dde, uint64_t index)
+{
+       const ddt_phys_t *ddp = dde->dde_phys;
+       const ddt_key_t *ddk = &dde->dde_key;
+       char *types[4] = { "ditto", "single", "double", "triple" };
+       char blkbuf[BP_SPRINTF_LEN];
+       blkptr_t blk;
+       int p;
+
+       for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+               if (ddp->ddp_phys_birth == 0)
+                       continue;
+               ddt_bp_create(ddt->ddt_checksum, ddk, ddp, &blk);
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), &blk);
+               (void) printf("index %llx refcnt %llu %s %s\n",
+                   (u_longlong_t)index, (u_longlong_t)ddp->ddp_refcnt,
+                   types[p], blkbuf);
+       }
+}
+
+static void
+dump_dedup_ratio(const ddt_stat_t *dds)
+{
+       double rL, rP, rD, D, dedup, compress, copies;
+
+       if (dds->dds_blocks == 0)
+               return;
+
+       rL = (double)dds->dds_ref_lsize;
+       rP = (double)dds->dds_ref_psize;
+       rD = (double)dds->dds_ref_dsize;
+       D = (double)dds->dds_dsize;
+
+       dedup = rD / D;
+       compress = rL / rP;
+       copies = rD / rP;
+
+       (void) printf("dedup = %.2f, compress = %.2f, copies = %.2f, "
+           "dedup * compress / copies = %.2f\n\n",
+           dedup, compress, copies, dedup * compress / copies);
+}
+
+static void
+dump_ddt(ddt_t *ddt, enum ddt_type type, enum ddt_class class)
+{
+       char name[DDT_NAMELEN];
+       ddt_entry_t dde;
+       uint64_t walk = 0;
+       dmu_object_info_t doi;
+       uint64_t count, dspace, mspace;
+       int error;
+
+       error = ddt_object_info(ddt, type, class, &doi);
+
+       if (error == ENOENT)
+               return;
+       ASSERT(error == 0);
+
+       error = ddt_object_count(ddt, type, class, &count);
+       ASSERT(error == 0);
+       if (count == 0)
+               return;
+
+       dspace = doi.doi_physical_blocks_512 << 9;
+       mspace = doi.doi_fill_count * doi.doi_data_block_size;
+
+       ddt_object_name(ddt, type, class, name);
+
+       (void) printf("%s: %llu entries, size %llu on disk, %llu in core\n",
+           name,
+           (u_longlong_t)count,
+           (u_longlong_t)(dspace / count),
+           (u_longlong_t)(mspace / count));
+
+       if (dump_opt['D'] < 3)
+               return;
+
+       zpool_dump_ddt(NULL, &ddt->ddt_histogram[type][class]);
+
+       if (dump_opt['D'] < 4)
+               return;
+
+       if (dump_opt['D'] < 5 && class == DDT_CLASS_UNIQUE)
+               return;
+
+       (void) printf("%s contents:\n\n", name);
+
+       while ((error = ddt_object_walk(ddt, type, class, &walk, &dde)) == 0)
+               dump_dde(ddt, &dde, walk);
+
+       ASSERT(error == ENOENT);
+
+       (void) printf("\n");
+}
+
+static void
+dump_all_ddts(spa_t *spa)
+{
+       ddt_histogram_t ddh_total;
+       ddt_stat_t dds_total;
+       enum zio_checksum c;
+       enum ddt_type type;
+       enum ddt_class class;
+
+       bzero(&ddh_total, sizeof (ddt_histogram_t));
+       bzero(&dds_total, sizeof (ddt_stat_t));
+
+       for (c = 0; c < ZIO_CHECKSUM_FUNCTIONS; c++) {
+               ddt_t *ddt = spa->spa_ddt[c];
+               for (type = 0; type < DDT_TYPES; type++) {
+                       for (class = 0; class < DDT_CLASSES;
+                           class++) {
+                               dump_ddt(ddt, type, class);
+                       }
+               }
+       }
+
+       ddt_get_dedup_stats(spa, &dds_total);
+
+       if (dds_total.dds_blocks == 0) {
+               (void) printf("All DDTs are empty\n");
+               return;
+       }
+
+       (void) printf("\n");
+
+       if (dump_opt['D'] > 1) {
+               (void) printf("DDT histogram (aggregated over all DDTs):\n");
+               ddt_get_dedup_histogram(spa, &ddh_total);
+               zpool_dump_ddt(&dds_total, &ddh_total);
+       }
+
+       dump_dedup_ratio(&dds_total);
+}
+
+static void
+dump_dtl_seg(void *arg, uint64_t start, uint64_t size)
+{
+       char *prefix = arg;
+
+       (void) printf("%s [%llu,%llu) length %llu\n",
+           prefix,
+           (u_longlong_t)start,
+           (u_longlong_t)(start + size),
+           (u_longlong_t)(size));
+}
+
+static void
+dump_dtl(vdev_t *vd, int indent)
+{
+       spa_t *spa = vd->vdev_spa;
+       boolean_t required;
+       char *name[DTL_TYPES] = { "missing", "partial", "scrub", "outage" };
+       char prefix[256];
+       int c, t;
+
+       spa_vdev_state_enter(spa, SCL_NONE);
+       required = vdev_dtl_required(vd);
+       (void) spa_vdev_state_exit(spa, NULL, 0);
+
+       if (indent == 0)
+               (void) printf("\nDirty time logs:\n\n");
+
+       (void) printf("\t%*s%s [%s]\n", indent, "",
+           vd->vdev_path ? vd->vdev_path :
+           vd->vdev_parent ? vd->vdev_ops->vdev_op_type : spa_name(spa),
+           required ? "DTL-required" : "DTL-expendable");
+
+       for (t = 0; t < DTL_TYPES; t++) {
+               range_tree_t *rt = vd->vdev_dtl[t];
+               if (range_tree_space(rt) == 0)
+                       continue;
+               (void) snprintf(prefix, sizeof (prefix), "\t%*s%s",
+                   indent + 2, "", name[t]);
+               mutex_enter(rt->rt_lock);
+               range_tree_walk(rt, dump_dtl_seg, prefix);
+               mutex_exit(rt->rt_lock);
+               if (dump_opt['d'] > 5 && vd->vdev_children == 0)
+                       dump_spacemap(spa->spa_meta_objset,
+                           vd->vdev_dtl_sm);
+       }
+
+       for (c = 0; c < vd->vdev_children; c++)
+               dump_dtl(vd->vdev_child[c], indent + 4);
+}
+
+static void
+dump_history(spa_t *spa)
+{
+       nvlist_t **events = NULL;
+       char *buf;
+       uint64_t resid, len, off = 0;
+       uint_t num = 0;
+       int error;
+       time_t tsec;
+       struct tm t;
+       char tbuf[30];
+       char internalstr[MAXPATHLEN];
+       int i;
+
+       if ((buf = malloc(SPA_OLD_MAXBLOCKSIZE)) == NULL) {
+               (void) fprintf(stderr, "%s: unable to allocate I/O buffer\n",
+                   __func__);
+               return;
+       }
+
+       do {
+               len = SPA_OLD_MAXBLOCKSIZE;
+
+               if ((error = spa_history_get(spa, &off, &len, buf)) != 0) {
+                       (void) fprintf(stderr, "Unable to read history: "
+                           "error %d\n", error);
+                       free(buf);
+                       return;
+               }
+
+               if (zpool_history_unpack(buf, len, &resid, &events, &num) != 0)
+                       break;
+
+               off -= resid;
+       } while (len != 0);
+
+       (void) printf("\nHistory:\n");
+       for (i = 0; i < num; i++) {
+               uint64_t time, txg, ievent;
+               char *cmd, *intstr;
+               boolean_t printed = B_FALSE;
+
+               if (nvlist_lookup_uint64(events[i], ZPOOL_HIST_TIME,
+                   &time) != 0)
+                       goto next;
+               if (nvlist_lookup_string(events[i], ZPOOL_HIST_CMD,
+                   &cmd) != 0) {
+                       if (nvlist_lookup_uint64(events[i],
+                           ZPOOL_HIST_INT_EVENT, &ievent) != 0)
+                               goto next;
+                       verify(nvlist_lookup_uint64(events[i],
+                           ZPOOL_HIST_TXG, &txg) == 0);
+                       verify(nvlist_lookup_string(events[i],
+                           ZPOOL_HIST_INT_STR, &intstr) == 0);
+                       if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS)
+                               goto next;
+
+                       (void) snprintf(internalstr,
+                           sizeof (internalstr),
+                           "[internal %s txg:%lld] %s",
+                           zfs_history_event_names[ievent],
+                           (longlong_t)txg, intstr);
+                       cmd = internalstr;
+               }
+               tsec = time;
+               (void) localtime_r(&tsec, &t);
+               (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
+               (void) printf("%s %s\n", tbuf, cmd);
+               printed = B_TRUE;
+
+next:
+               if (dump_opt['h'] > 1) {
+                       if (!printed)
+                               (void) printf("unrecognized record:\n");
+                       dump_nvlist(events[i], 2);
+               }
+       }
+       free(buf);
+}
+
+/*ARGSUSED*/
+static void
+dump_dnode(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+static uint64_t
+blkid2offset(const dnode_phys_t *dnp, const blkptr_t *bp,
+    const zbookmark_phys_t *zb)
+{
+       if (dnp == NULL) {
+               ASSERT(zb->zb_level < 0);
+               if (zb->zb_object == 0)
+                       return (zb->zb_blkid);
+               return (zb->zb_blkid * BP_GET_LSIZE(bp));
+       }
+
+       ASSERT(zb->zb_level >= 0);
+
+       return ((zb->zb_blkid <<
+           (zb->zb_level * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT))) *
+           dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT);
+}
+
+static void
+snprintf_blkptr_compact(char *blkbuf, size_t buflen, const blkptr_t *bp)
+{
+       const dva_t *dva = bp->blk_dva;
+       int ndvas = dump_opt['d'] > 5 ? BP_GET_NDVAS(bp) : 1;
+       int i;
+
+       if (dump_opt['b'] >= 6) {
+               snprintf_blkptr(blkbuf, buflen, bp);
+               return;
+       }
+
+       if (BP_IS_EMBEDDED(bp)) {
+               (void) sprintf(blkbuf,
+                   "EMBEDDED et=%u %llxL/%llxP B=%llu",
+                   (int)BPE_GET_ETYPE(bp),
+                   (u_longlong_t)BPE_GET_LSIZE(bp),
+                   (u_longlong_t)BPE_GET_PSIZE(bp),
+                   (u_longlong_t)bp->blk_birth);
+               return;
+       }
+
+       blkbuf[0] = '\0';
+
+       for (i = 0; i < ndvas; i++)
+               (void) snprintf(blkbuf + strlen(blkbuf),
+                   buflen - strlen(blkbuf), "%llu:%llx:%llx ",
+                   (u_longlong_t)DVA_GET_VDEV(&dva[i]),
+                   (u_longlong_t)DVA_GET_OFFSET(&dva[i]),
+                   (u_longlong_t)DVA_GET_ASIZE(&dva[i]));
+
+       if (BP_IS_HOLE(bp)) {
+               (void) snprintf(blkbuf + strlen(blkbuf),
+                   buflen - strlen(blkbuf),
+                   "%llxL B=%llu",
+                   (u_longlong_t)BP_GET_LSIZE(bp),
+                   (u_longlong_t)bp->blk_birth);
+       } else {
+               (void) snprintf(blkbuf + strlen(blkbuf),
+                   buflen - strlen(blkbuf),
+                   "%llxL/%llxP F=%llu B=%llu/%llu",
+                   (u_longlong_t)BP_GET_LSIZE(bp),
+                   (u_longlong_t)BP_GET_PSIZE(bp),
+                   (u_longlong_t)BP_GET_FILL(bp),
+                   (u_longlong_t)bp->blk_birth,
+                   (u_longlong_t)BP_PHYSICAL_BIRTH(bp));
+       }
+}
+
+static void
+print_indirect(blkptr_t *bp, const zbookmark_phys_t *zb,
+    const dnode_phys_t *dnp)
+{
+       char blkbuf[BP_SPRINTF_LEN];
+       int l;
+
+       if (!BP_IS_EMBEDDED(bp)) {
+               ASSERT3U(BP_GET_TYPE(bp), ==, dnp->dn_type);
+               ASSERT3U(BP_GET_LEVEL(bp), ==, zb->zb_level);
+       }
+
+       (void) printf("%16llx ", (u_longlong_t)blkid2offset(dnp, bp, zb));
+
+       ASSERT(zb->zb_level >= 0);
+
+       for (l = dnp->dn_nlevels - 1; l >= -1; l--) {
+               if (l == zb->zb_level) {
+                       (void) printf("L%llx", (u_longlong_t)zb->zb_level);
+               } else {
+                       (void) printf(" ");
+               }
+       }
+
+       snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp);
+       (void) printf("%s\n", blkbuf);
+}
+
+static int
+visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
+    blkptr_t *bp, const zbookmark_phys_t *zb)
+{
+       int err = 0;
+
+       if (bp->blk_birth == 0)
+               return (0);
+
+       print_indirect(bp, zb, dnp);
+
+       if (BP_GET_LEVEL(bp) > 0 && !BP_IS_HOLE(bp)) {
+               arc_flags_t flags = ARC_FLAG_WAIT;
+               int i;
+               blkptr_t *cbp;
+               int epb = BP_GET_LSIZE(bp) >> SPA_BLKPTRSHIFT;
+               arc_buf_t *buf;
+               uint64_t fill = 0;
+
+               err = arc_read(NULL, spa, bp, arc_getbuf_func, &buf,
+                   ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
+               if (err)
+                       return (err);
+               ASSERT(buf->b_data);
+
+               /* recursively visit blocks below this */
+               cbp = buf->b_data;
+               for (i = 0; i < epb; i++, cbp++) {
+                       zbookmark_phys_t czb;
+
+                       SET_BOOKMARK(&czb, zb->zb_objset, zb->zb_object,
+                           zb->zb_level - 1,
+                           zb->zb_blkid * epb + i);
+                       err = visit_indirect(spa, dnp, cbp, &czb);
+                       if (err)
+                               break;
+                       fill += BP_GET_FILL(cbp);
+               }
+               if (!err)
+                       ASSERT3U(fill, ==, BP_GET_FILL(bp));
+               arc_buf_destroy(buf, &buf);
+       }
+
+       return (err);
+}
+
+/*ARGSUSED*/
+static void
+dump_indirect(dnode_t *dn)
+{
+       dnode_phys_t *dnp = dn->dn_phys;
+       int j;
+       zbookmark_phys_t czb;
+
+       (void) printf("Indirect blocks:\n");
+
+       SET_BOOKMARK(&czb, dmu_objset_id(dn->dn_objset),
+           dn->dn_object, dnp->dn_nlevels - 1, 0);
+       for (j = 0; j < dnp->dn_nblkptr; j++) {
+               czb.zb_blkid = j;
+               (void) visit_indirect(dmu_objset_spa(dn->dn_objset), dnp,
+                   &dnp->dn_blkptr[j], &czb);
+       }
+
+       (void) printf("\n");
+}
+
+/*ARGSUSED*/
+static void
+dump_dsl_dir(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       dsl_dir_phys_t *dd = data;
+       time_t crtime;
+       char nice[32];
+
+       if (dd == NULL)
+               return;
+
+       ASSERT3U(size, >=, sizeof (dsl_dir_phys_t));
+
+       crtime = dd->dd_creation_time;
+       (void) printf("\t\tcreation_time = %s", ctime(&crtime));
+       (void) printf("\t\thead_dataset_obj = %llu\n",
+           (u_longlong_t)dd->dd_head_dataset_obj);
+       (void) printf("\t\tparent_dir_obj = %llu\n",
+           (u_longlong_t)dd->dd_parent_obj);
+       (void) printf("\t\torigin_obj = %llu\n",
+           (u_longlong_t)dd->dd_origin_obj);
+       (void) printf("\t\tchild_dir_zapobj = %llu\n",
+           (u_longlong_t)dd->dd_child_dir_zapobj);
+       zdb_nicenum(dd->dd_used_bytes, nice);
+       (void) printf("\t\tused_bytes = %s\n", nice);
+       zdb_nicenum(dd->dd_compressed_bytes, nice);
+       (void) printf("\t\tcompressed_bytes = %s\n", nice);
+       zdb_nicenum(dd->dd_uncompressed_bytes, nice);
+       (void) printf("\t\tuncompressed_bytes = %s\n", nice);
+       zdb_nicenum(dd->dd_quota, nice);
+       (void) printf("\t\tquota = %s\n", nice);
+       zdb_nicenum(dd->dd_reserved, nice);
+       (void) printf("\t\treserved = %s\n", nice);
+       (void) printf("\t\tprops_zapobj = %llu\n",
+           (u_longlong_t)dd->dd_props_zapobj);
+       (void) printf("\t\tdeleg_zapobj = %llu\n",
+           (u_longlong_t)dd->dd_deleg_zapobj);
+       (void) printf("\t\tflags = %llx\n",
+           (u_longlong_t)dd->dd_flags);
+
+#define        DO(which) \
+       zdb_nicenum(dd->dd_used_breakdown[DD_USED_ ## which], nice); \
+       (void) printf("\t\tused_breakdown[" #which "] = %s\n", nice)
+       DO(HEAD);
+       DO(SNAP);
+       DO(CHILD);
+       DO(CHILD_RSRV);
+       DO(REFRSRV);
+#undef DO
+}
+
+/*ARGSUSED*/
+static void
+dump_dsl_dataset(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       dsl_dataset_phys_t *ds = data;
+       time_t crtime;
+       char used[32], compressed[32], uncompressed[32], unique[32];
+       char blkbuf[BP_SPRINTF_LEN];
+
+       if (ds == NULL)
+               return;
+
+       ASSERT(size == sizeof (*ds));
+       crtime = ds->ds_creation_time;
+       zdb_nicenum(ds->ds_referenced_bytes, used);
+       zdb_nicenum(ds->ds_compressed_bytes, compressed);
+       zdb_nicenum(ds->ds_uncompressed_bytes, uncompressed);
+       zdb_nicenum(ds->ds_unique_bytes, unique);
+       snprintf_blkptr(blkbuf, sizeof (blkbuf), &ds->ds_bp);
+
+       (void) printf("\t\tdir_obj = %llu\n",
+           (u_longlong_t)ds->ds_dir_obj);
+       (void) printf("\t\tprev_snap_obj = %llu\n",
+           (u_longlong_t)ds->ds_prev_snap_obj);
+       (void) printf("\t\tprev_snap_txg = %llu\n",
+           (u_longlong_t)ds->ds_prev_snap_txg);
+       (void) printf("\t\tnext_snap_obj = %llu\n",
+           (u_longlong_t)ds->ds_next_snap_obj);
+       (void) printf("\t\tsnapnames_zapobj = %llu\n",
+           (u_longlong_t)ds->ds_snapnames_zapobj);
+       (void) printf("\t\tnum_children = %llu\n",
+           (u_longlong_t)ds->ds_num_children);
+       (void) printf("\t\tuserrefs_obj = %llu\n",
+           (u_longlong_t)ds->ds_userrefs_obj);
+       (void) printf("\t\tcreation_time = %s", ctime(&crtime));
+       (void) printf("\t\tcreation_txg = %llu\n",
+           (u_longlong_t)ds->ds_creation_txg);
+       (void) printf("\t\tdeadlist_obj = %llu\n",
+           (u_longlong_t)ds->ds_deadlist_obj);
+       (void) printf("\t\tused_bytes = %s\n", used);
+       (void) printf("\t\tcompressed_bytes = %s\n", compressed);
+       (void) printf("\t\tuncompressed_bytes = %s\n", uncompressed);
+       (void) printf("\t\tunique = %s\n", unique);
+       (void) printf("\t\tfsid_guid = %llu\n",
+           (u_longlong_t)ds->ds_fsid_guid);
+       (void) printf("\t\tguid = %llu\n",
+           (u_longlong_t)ds->ds_guid);
+       (void) printf("\t\tflags = %llx\n",
+           (u_longlong_t)ds->ds_flags);
+       (void) printf("\t\tnext_clones_obj = %llu\n",
+           (u_longlong_t)ds->ds_next_clones_obj);
+       (void) printf("\t\tprops_obj = %llu\n",
+           (u_longlong_t)ds->ds_props_obj);
+       (void) printf("\t\tbp = %s\n", blkbuf);
+}
+
+/* ARGSUSED */
+static int
+dump_bptree_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       char blkbuf[BP_SPRINTF_LEN];
+
+       if (bp->blk_birth != 0) {
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+               (void) printf("\t%s\n", blkbuf);
+       }
+       return (0);
+}
+
+static void
+dump_bptree(objset_t *os, uint64_t obj, char *name)
+{
+       char bytes[32];
+       bptree_phys_t *bt;
+       dmu_buf_t *db;
+
+       if (dump_opt['d'] < 3)
+               return;
+
+       VERIFY3U(0, ==, dmu_bonus_hold(os, obj, FTAG, &db));
+       bt = db->db_data;
+       zdb_nicenum(bt->bt_bytes, bytes);
+       (void) printf("\n    %s: %llu datasets, %s\n",
+           name, (unsigned long long)(bt->bt_end - bt->bt_begin), bytes);
+       dmu_buf_rele(db, FTAG);
+
+       if (dump_opt['d'] < 5)
+               return;
+
+       (void) printf("\n");
+
+       (void) bptree_iterate(os, obj, B_FALSE, dump_bptree_cb, NULL, NULL);
+}
+
+/* ARGSUSED */
+static int
+dump_bpobj_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       char blkbuf[BP_SPRINTF_LEN];
+
+       ASSERT(bp->blk_birth != 0);
+       snprintf_blkptr_compact(blkbuf, sizeof (blkbuf), bp);
+       (void) printf("\t%s\n", blkbuf);
+       return (0);
+}
+
+static void
+dump_full_bpobj(bpobj_t *bpo, char *name, int indent)
+{
+       char bytes[32];
+       char comp[32];
+       char uncomp[32];
+       uint64_t i;
+
+       if (dump_opt['d'] < 3)
+               return;
+
+       zdb_nicenum(bpo->bpo_phys->bpo_bytes, bytes);
+       if (bpo->bpo_havesubobj && bpo->bpo_phys->bpo_subobjs != 0) {
+               zdb_nicenum(bpo->bpo_phys->bpo_comp, comp);
+               zdb_nicenum(bpo->bpo_phys->bpo_uncomp, uncomp);
+               (void) printf("    %*s: object %llu, %llu local blkptrs, "
+                   "%llu subobjs in object, %llu, %s (%s/%s comp)\n",
+                   indent * 8, name,
+                   (u_longlong_t)bpo->bpo_object,
+                   (u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
+                   (u_longlong_t)bpo->bpo_phys->bpo_num_subobjs,
+                   (u_longlong_t)bpo->bpo_phys->bpo_subobjs,
+                   bytes, comp, uncomp);
+
+               for (i = 0; i < bpo->bpo_phys->bpo_num_subobjs; i++) {
+                       uint64_t subobj;
+                       bpobj_t subbpo;
+                       int error;
+                       VERIFY0(dmu_read(bpo->bpo_os,
+                           bpo->bpo_phys->bpo_subobjs,
+                           i * sizeof (subobj), sizeof (subobj), &subobj, 0));
+                       error = bpobj_open(&subbpo, bpo->bpo_os, subobj);
+                       if (error != 0) {
+                               (void) printf("ERROR %u while trying to open "
+                                   "subobj id %llu\n",
+                                   error, (u_longlong_t)subobj);
+                               continue;
+                       }
+                       dump_full_bpobj(&subbpo, "subobj", indent + 1);
+                       bpobj_close(&subbpo);
+               }
+       } else {
+               (void) printf("    %*s: object %llu, %llu blkptrs, %s\n",
+                   indent * 8, name,
+                   (u_longlong_t)bpo->bpo_object,
+                   (u_longlong_t)bpo->bpo_phys->bpo_num_blkptrs,
+                   bytes);
+       }
+
+       if (dump_opt['d'] < 5)
+               return;
+
+
+       if (indent == 0) {
+               (void) bpobj_iterate_nofree(bpo, dump_bpobj_cb, NULL, NULL);
+               (void) printf("\n");
+       }
+}
+
+static void
+dump_deadlist(dsl_deadlist_t *dl)
+{
+       dsl_deadlist_entry_t *dle;
+       uint64_t unused;
+       char bytes[32];
+       char comp[32];
+       char uncomp[32];
+
+       if (dump_opt['d'] < 3)
+               return;
+
+       if (dl->dl_oldfmt) {
+               dump_full_bpobj(&dl->dl_bpobj, "old-format deadlist", 0);
+               return;
+       }
+
+       zdb_nicenum(dl->dl_phys->dl_used, bytes);
+       zdb_nicenum(dl->dl_phys->dl_comp, comp);
+       zdb_nicenum(dl->dl_phys->dl_uncomp, uncomp);
+       (void) printf("\n    Deadlist: %s (%s/%s comp)\n",
+           bytes, comp, uncomp);
+
+       if (dump_opt['d'] < 4)
+               return;
+
+       (void) printf("\n");
+
+       /* force the tree to be loaded */
+       dsl_deadlist_space_range(dl, 0, UINT64_MAX, &unused, &unused, &unused);
+
+       for (dle = avl_first(&dl->dl_tree); dle;
+           dle = AVL_NEXT(&dl->dl_tree, dle)) {
+               if (dump_opt['d'] >= 5) {
+                       char buf[128];
+                       (void) snprintf(buf, sizeof (buf),
+                           "mintxg %llu -> obj %llu",
+                           (longlong_t)dle->dle_mintxg,
+                           (longlong_t)dle->dle_bpobj.bpo_object);
+
+                       dump_full_bpobj(&dle->dle_bpobj, buf, 0);
+               } else {
+                       (void) printf("mintxg %llu -> obj %llu\n",
+                           (longlong_t)dle->dle_mintxg,
+                           (longlong_t)dle->dle_bpobj.bpo_object);
+
+               }
+       }
+}
+
+static avl_tree_t idx_tree;
+static avl_tree_t domain_tree;
+static boolean_t fuid_table_loaded;
+static boolean_t sa_loaded;
+sa_attr_type_t *sa_attr_table;
+
+static void
+fuid_table_destroy(void)
+{
+       if (fuid_table_loaded) {
+               zfs_fuid_table_destroy(&idx_tree, &domain_tree);
+               fuid_table_loaded = B_FALSE;
+       }
+}
+
+/*
+ * print uid or gid information.
+ * For normal POSIX id just the id is printed in decimal format.
+ * For CIFS files with FUID the fuid is printed in hex followed by
+ * the domain-rid string.
+ */
+static void
+print_idstr(uint64_t id, const char *id_type)
+{
+       if (FUID_INDEX(id)) {
+               char *domain;
+
+               domain = zfs_fuid_idx_domain(&idx_tree, FUID_INDEX(id));
+               (void) printf("\t%s     %llx [%s-%d]\n", id_type,
+                   (u_longlong_t)id, domain, (int)FUID_RID(id));
+       } else {
+               (void) printf("\t%s     %llu\n", id_type, (u_longlong_t)id);
+       }
+
+}
+
+static void
+dump_uidgid(objset_t *os, uint64_t uid, uint64_t gid)
+{
+       uint32_t uid_idx, gid_idx;
+
+       uid_idx = FUID_INDEX(uid);
+       gid_idx = FUID_INDEX(gid);
+
+       /* Load domain table, if not already loaded */
+       if (!fuid_table_loaded && (uid_idx || gid_idx)) {
+               uint64_t fuid_obj;
+
+               /* first find the fuid object.  It lives in the master node */
+               VERIFY(zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES,
+                   8, 1, &fuid_obj) == 0);
+               zfs_fuid_avl_tree_create(&idx_tree, &domain_tree);
+               (void) zfs_fuid_table_load(os, fuid_obj,
+                   &idx_tree, &domain_tree);
+               fuid_table_loaded = B_TRUE;
+       }
+
+       print_idstr(uid, "uid");
+       print_idstr(gid, "gid");
+}
+
+static void
+dump_znode_sa_xattr(sa_handle_t *hdl)
+{
+       nvlist_t *sa_xattr;
+       nvpair_t *elem = NULL;
+       int sa_xattr_size = 0;
+       int sa_xattr_entries = 0;
+       int error;
+       char *sa_xattr_packed;
+
+       error = sa_size(hdl, sa_attr_table[ZPL_DXATTR], &sa_xattr_size);
+       if (error || sa_xattr_size == 0)
+               return;
+
+       sa_xattr_packed = malloc(sa_xattr_size);
+       if (sa_xattr_packed == NULL)
+               return;
+
+       error = sa_lookup(hdl, sa_attr_table[ZPL_DXATTR],
+           sa_xattr_packed, sa_xattr_size);
+       if (error) {
+               free(sa_xattr_packed);
+               return;
+       }
+
+       error = nvlist_unpack(sa_xattr_packed, sa_xattr_size, &sa_xattr, 0);
+       if (error) {
+               free(sa_xattr_packed);
+               return;
+       }
+
+       while ((elem = nvlist_next_nvpair(sa_xattr, elem)) != NULL)
+               sa_xattr_entries++;
+
+       (void) printf("\tSA xattrs: %d bytes, %d entries\n\n",
+           sa_xattr_size, sa_xattr_entries);
+       while ((elem = nvlist_next_nvpair(sa_xattr, elem)) != NULL) {
+               uchar_t *value;
+               uint_t cnt, idx;
+
+               (void) printf("\t\t%s = ", nvpair_name(elem));
+               nvpair_value_byte_array(elem, &value, &cnt);
+               for (idx = 0; idx < cnt; ++idx) {
+                       if (isprint(value[idx]))
+                               (void) putchar(value[idx]);
+                       else
+                               (void) printf("\\%3.3o", value[idx]);
+               }
+               (void) putchar('\n');
+       }
+
+       nvlist_free(sa_xattr);
+       free(sa_xattr_packed);
+}
+
+/*ARGSUSED*/
+static void
+dump_znode(objset_t *os, uint64_t object, void *data, size_t size)
+{
+       char path[MAXPATHLEN * 2];      /* allow for xattr and failure prefix */
+       sa_handle_t *hdl;
+       uint64_t xattr, rdev, gen;
+       uint64_t uid, gid, mode, fsize, parent, links;
+       uint64_t pflags;
+       uint64_t acctm[2], modtm[2], chgtm[2], crtm[2];
+       time_t z_crtime, z_atime, z_mtime, z_ctime;
+       sa_bulk_attr_t bulk[12];
+       int idx = 0;
+       int error;
+
+       if (!sa_loaded) {
+               uint64_t sa_attrs = 0;
+               uint64_t version;
+
+               VERIFY(zap_lookup(os, MASTER_NODE_OBJ, ZPL_VERSION_STR,
+                   8, 1, &version) == 0);
+               if (version >= ZPL_VERSION_SA) {
+                       VERIFY(zap_lookup(os, MASTER_NODE_OBJ, ZFS_SA_ATTRS,
+                           8, 1, &sa_attrs) == 0);
+               }
+               if ((error = sa_setup(os, sa_attrs, zfs_attr_table,
+                   ZPL_END, &sa_attr_table)) != 0) {
+                       (void) printf("sa_setup failed errno %d, can't "
+                           "display znode contents\n", error);
+                       return;
+               }
+               sa_loaded = B_TRUE;
+       }
+
+       if (sa_handle_get(os, object, NULL, SA_HDL_PRIVATE, &hdl)) {
+               (void) printf("Failed to get handle for SA znode\n");
+               return;
+       }
+
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_UID], NULL, &uid, 8);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_GID], NULL, &gid, 8);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_LINKS], NULL,
+           &links, 8);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_GEN], NULL, &gen, 8);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_MODE], NULL,
+           &mode, 8);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_PARENT],
+           NULL, &parent, 8);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_SIZE], NULL,
+           &fsize, 8);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_ATIME], NULL,
+           acctm, 16);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_MTIME], NULL,
+           modtm, 16);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_CRTIME], NULL,
+           crtm, 16);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_CTIME], NULL,
+           chgtm, 16);
+       SA_ADD_BULK_ATTR(bulk, idx, sa_attr_table[ZPL_FLAGS], NULL,
+           &pflags, 8);
+
+       if (sa_bulk_lookup(hdl, bulk, idx)) {
+               (void) sa_handle_destroy(hdl);
+               return;
+       }
+
+       error = zfs_obj_to_path(os, object, path, sizeof (path));
+       if (error != 0) {
+               (void) snprintf(path, sizeof (path), "\?\?\?<object#%llu>",
+                   (u_longlong_t)object);
+       }
+       if (dump_opt['d'] < 3) {
+               (void) printf("\t%s\n", path);
+               (void) sa_handle_destroy(hdl);
+               return;
+       }
+
+       z_crtime = (time_t)crtm[0];
+       z_atime = (time_t)acctm[0];
+       z_mtime = (time_t)modtm[0];
+       z_ctime = (time_t)chgtm[0];
+
+       (void) printf("\tpath   %s\n", path);
+       dump_uidgid(os, uid, gid);
+       (void) printf("\tatime  %s", ctime(&z_atime));
+       (void) printf("\tmtime  %s", ctime(&z_mtime));
+       (void) printf("\tctime  %s", ctime(&z_ctime));
+       (void) printf("\tcrtime %s", ctime(&z_crtime));
+       (void) printf("\tgen    %llu\n", (u_longlong_t)gen);
+       (void) printf("\tmode   %llo\n", (u_longlong_t)mode);
+       (void) printf("\tsize   %llu\n", (u_longlong_t)fsize);
+       (void) printf("\tparent %llu\n", (u_longlong_t)parent);
+       (void) printf("\tlinks  %llu\n", (u_longlong_t)links);
+       (void) printf("\tpflags %llx\n", (u_longlong_t)pflags);
+       if (sa_lookup(hdl, sa_attr_table[ZPL_XATTR], &xattr,
+           sizeof (uint64_t)) == 0)
+               (void) printf("\txattr  %llu\n", (u_longlong_t)xattr);
+       if (sa_lookup(hdl, sa_attr_table[ZPL_RDEV], &rdev,
+           sizeof (uint64_t)) == 0)
+               (void) printf("\trdev   0x%016llx\n", (u_longlong_t)rdev);
+       dump_znode_sa_xattr(hdl);
+       sa_handle_destroy(hdl);
+}
+
+/*ARGSUSED*/
+static void
+dump_acl(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+/*ARGSUSED*/
+static void
+dump_dmu_objset(objset_t *os, uint64_t object, void *data, size_t size)
+{
+}
+
+static object_viewer_t *object_viewer[DMU_OT_NUMTYPES + 1] = {
+       dump_none,              /* unallocated                  */
+       dump_zap,               /* object directory             */
+       dump_uint64,            /* object array                 */
+       dump_none,              /* packed nvlist                */
+       dump_packed_nvlist,     /* packed nvlist size           */
+       dump_none,              /* bpobj                        */
+       dump_bpobj,             /* bpobj header                 */
+       dump_none,              /* SPA space map header         */
+       dump_none,              /* SPA space map                */
+       dump_none,              /* ZIL intent log               */
+       dump_dnode,             /* DMU dnode                    */
+       dump_dmu_objset,        /* DMU objset                   */
+       dump_dsl_dir,           /* DSL directory                */
+       dump_zap,               /* DSL directory child map      */
+       dump_zap,               /* DSL dataset snap map         */
+       dump_zap,               /* DSL props                    */
+       dump_dsl_dataset,       /* DSL dataset                  */
+       dump_znode,             /* ZFS znode                    */
+       dump_acl,               /* ZFS V0 ACL                   */
+       dump_uint8,             /* ZFS plain file               */
+       dump_zpldir,            /* ZFS directory                */
+       dump_zap,               /* ZFS master node              */
+       dump_zap,               /* ZFS delete queue             */
+       dump_uint8,             /* zvol object                  */
+       dump_zap,               /* zvol prop                    */
+       dump_uint8,             /* other uint8[]                */
+       dump_uint64,            /* other uint64[]               */
+       dump_zap,               /* other ZAP                    */
+       dump_zap,               /* persistent error log         */
+       dump_uint8,             /* SPA history                  */
+       dump_history_offsets,   /* SPA history offsets          */
+       dump_zap,               /* Pool properties              */
+       dump_zap,               /* DSL permissions              */
+       dump_acl,               /* ZFS ACL                      */
+       dump_uint8,             /* ZFS SYSACL                   */
+       dump_none,              /* FUID nvlist                  */
+       dump_packed_nvlist,     /* FUID nvlist size             */
+       dump_zap,               /* DSL dataset next clones      */
+       dump_zap,               /* DSL scrub queue              */
+       dump_zap,               /* ZFS user/group used          */
+       dump_zap,               /* ZFS user/group quota         */
+       dump_zap,               /* snapshot refcount tags       */
+       dump_ddt_zap,           /* DDT ZAP object               */
+       dump_zap,               /* DDT statistics               */
+       dump_znode,             /* SA object                    */
+       dump_zap,               /* SA Master Node               */
+       dump_sa_attrs,          /* SA attribute registration    */
+       dump_sa_layouts,        /* SA attribute layouts         */
+       dump_zap,               /* DSL scrub translations       */
+       dump_none,              /* fake dedup BP                */
+       dump_zap,               /* deadlist                     */
+       dump_none,              /* deadlist hdr                 */
+       dump_zap,               /* dsl clones                   */
+       dump_bpobj_subobjs,     /* bpobj subobjs                */
+       dump_unknown,           /* Unknown type, must be last   */
+};
+
+static void
+dump_object(objset_t *os, uint64_t object, int verbosity, int *print_header)
+{
+       dmu_buf_t *db = NULL;
+       dmu_object_info_t doi;
+       dnode_t *dn;
+       void *bonus = NULL;
+       size_t bsize = 0;
+       char iblk[32], dblk[32], lsize[32], asize[32], fill[32], dnsize[32];
+       char bonus_size[32];
+       char aux[50];
+       int error;
+
+       if (*print_header) {
+               (void) printf("\n%10s  %3s  %5s  %5s  %5s  %6s  %5s  %6s  %s\n",
+                   "Object", "lvl", "iblk", "dblk", "dsize", "dnsize",
+                   "lsize", "%full", "type");
+               *print_header = 0;
+       }
+
+       if (object == 0) {
+               dn = DMU_META_DNODE(os);
+       } else {
+               error = dmu_bonus_hold(os, object, FTAG, &db);
+               if (error)
+                       fatal("dmu_bonus_hold(%llu) failed, errno %u",
+                           object, error);
+               bonus = db->db_data;
+               bsize = db->db_size;
+               dn = DB_DNODE((dmu_buf_impl_t *)db);
+       }
+       dmu_object_info_from_dnode(dn, &doi);
+
+       zdb_nicenum(doi.doi_metadata_block_size, iblk);
+       zdb_nicenum(doi.doi_data_block_size, dblk);
+       zdb_nicenum(doi.doi_max_offset, lsize);
+       zdb_nicenum(doi.doi_physical_blocks_512 << 9, asize);
+       zdb_nicenum(doi.doi_bonus_size, bonus_size);
+       zdb_nicenum(doi.doi_dnodesize, dnsize);
+       (void) sprintf(fill, "%6.2f", 100.0 * doi.doi_fill_count *
+           doi.doi_data_block_size / (object == 0 ? DNODES_PER_BLOCK : 1) /
+           doi.doi_max_offset);
+
+       aux[0] = '\0';
+
+       if (doi.doi_checksum != ZIO_CHECKSUM_INHERIT || verbosity >= 6) {
+               (void) snprintf(aux + strlen(aux), sizeof (aux), " (K=%s)",
+                   ZDB_CHECKSUM_NAME(doi.doi_checksum));
+       }
+
+       if (doi.doi_compress != ZIO_COMPRESS_INHERIT || verbosity >= 6) {
+               (void) snprintf(aux + strlen(aux), sizeof (aux), " (Z=%s)",
+                   ZDB_COMPRESS_NAME(doi.doi_compress));
+       }
+
+       (void) printf("%10lld  %3u  %5s  %5s  %5s  %6s  %5s  %6s  %s%s\n",
+           (u_longlong_t)object, doi.doi_indirection, iblk, dblk,
+           asize, dnsize, lsize, fill, zdb_ot_name(doi.doi_type), aux);
+
+       if (doi.doi_bonus_type != DMU_OT_NONE && verbosity > 3) {
+               (void) printf("%10s  %3s  %5s  %5s  %5s  %5s  %5s  %6s  %s\n",
+                   "", "", "", "", "", "", bonus_size, "bonus",
+                   zdb_ot_name(doi.doi_bonus_type));
+       }
+
+       if (verbosity >= 4) {
+               (void) printf("\tdnode flags: %s%s%s%s\n",
+                   (dn->dn_phys->dn_flags & DNODE_FLAG_USED_BYTES) ?
+                   "USED_BYTES " : "",
+                   (dn->dn_phys->dn_flags & DNODE_FLAG_USERUSED_ACCOUNTED) ?
+                   "USERUSED_ACCOUNTED " : "",
+                   (dn->dn_phys->dn_flags & DNODE_FLAG_USEROBJUSED_ACCOUNTED) ?
+                   "USEROBJUSED_ACCOUNTED " : "",
+                   (dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR) ?
+                   "SPILL_BLKPTR" : "");
+               (void) printf("\tdnode maxblkid: %llu\n",
+                   (longlong_t)dn->dn_phys->dn_maxblkid);
+
+               object_viewer[ZDB_OT_TYPE(doi.doi_bonus_type)](os, object,
+                   bonus, bsize);
+               object_viewer[ZDB_OT_TYPE(doi.doi_type)](os, object, NULL, 0);
+               *print_header = 1;
+       }
+
+       if (verbosity >= 5)
+               dump_indirect(dn);
+
+       if (verbosity >= 5) {
+               /*
+                * Report the list of segments that comprise the object.
+                */
+               uint64_t start = 0;
+               uint64_t end;
+               uint64_t blkfill = 1;
+               int minlvl = 1;
+
+               if (dn->dn_type == DMU_OT_DNODE) {
+                       minlvl = 0;
+                       blkfill = DNODES_PER_BLOCK;
+               }
+
+               for (;;) {
+                       char segsize[32];
+                       error = dnode_next_offset(dn,
+                           0, &start, minlvl, blkfill, 0);
+                       if (error)
+                               break;
+                       end = start;
+                       error = dnode_next_offset(dn,
+                           DNODE_FIND_HOLE, &end, minlvl, blkfill, 0);
+                       zdb_nicenum(end - start, segsize);
+                       (void) printf("\t\tsegment [%016llx, %016llx)"
+                           " size %5s\n", (u_longlong_t)start,
+                           (u_longlong_t)end, segsize);
+                       if (error)
+                               break;
+                       start = end;
+               }
+       }
+
+       if (db != NULL)
+               dmu_buf_rele(db, FTAG);
+}
+
+static char *objset_types[DMU_OST_NUMTYPES] = {
+       "NONE", "META", "ZPL", "ZVOL", "OTHER", "ANY" };
+
+static void
+dump_dir(objset_t *os)
+{
+       dmu_objset_stats_t dds;
+       uint64_t object, object_count;
+       uint64_t refdbytes, usedobjs, scratch;
+       char numbuf[32];
+       char blkbuf[BP_SPRINTF_LEN + 20];
+       char osname[ZFS_MAX_DATASET_NAME_LEN];
+       char *type = "UNKNOWN";
+       int verbosity = dump_opt['d'];
+       int print_header = 1;
+       int i, error;
+
+       dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
+       dmu_objset_fast_stat(os, &dds);
+       dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
+
+       if (dds.dds_type < DMU_OST_NUMTYPES)
+               type = objset_types[dds.dds_type];
+
+       if (dds.dds_type == DMU_OST_META) {
+               dds.dds_creation_txg = TXG_INITIAL;
+               usedobjs = BP_GET_FILL(os->os_rootbp);
+               refdbytes = dsl_dir_phys(os->os_spa->spa_dsl_pool->dp_mos_dir)->
+                   dd_used_bytes;
+       } else {
+               dmu_objset_space(os, &refdbytes, &scratch, &usedobjs, &scratch);
+       }
+
+       ASSERT3U(usedobjs, ==, BP_GET_FILL(os->os_rootbp));
+
+       zdb_nicenum(refdbytes, numbuf);
+
+       if (verbosity >= 4) {
+               (void) snprintf(blkbuf, sizeof (blkbuf), ", rootbp ");
+               (void) snprintf_blkptr(blkbuf + strlen(blkbuf),
+                   sizeof (blkbuf) - strlen(blkbuf), os->os_rootbp);
+       } else {
+               blkbuf[0] = '\0';
+       }
+
+       dmu_objset_name(os, osname);
+
+       (void) printf("Dataset %s [%s], ID %llu, cr_txg %llu, "
+           "%s, %llu objects%s\n",
+           osname, type, (u_longlong_t)dmu_objset_id(os),
+           (u_longlong_t)dds.dds_creation_txg,
+           numbuf, (u_longlong_t)usedobjs, blkbuf);
+
+       if (zopt_objects != 0) {
+               for (i = 0; i < zopt_objects; i++)
+                       dump_object(os, zopt_object[i], verbosity,
+                           &print_header);
+               (void) printf("\n");
+               return;
+       }
+
+       if (dump_opt['i'] != 0 || verbosity >= 2)
+               dump_intent_log(dmu_objset_zil(os));
+
+       if (dmu_objset_ds(os) != NULL)
+               dump_deadlist(&dmu_objset_ds(os)->ds_deadlist);
+
+       if (verbosity < 2)
+               return;
+
+       if (BP_IS_HOLE(os->os_rootbp))
+               return;
+
+       dump_object(os, 0, verbosity, &print_header);
+       object_count = 0;
+       if (DMU_USERUSED_DNODE(os) != NULL &&
+           DMU_USERUSED_DNODE(os)->dn_type != 0) {
+               dump_object(os, DMU_USERUSED_OBJECT, verbosity, &print_header);
+               dump_object(os, DMU_GROUPUSED_OBJECT, verbosity, &print_header);
+       }
+
+       object = 0;
+       while ((error = dmu_object_next(os, &object, B_FALSE, 0)) == 0) {
+               dump_object(os, object, verbosity, &print_header);
+               object_count++;
+       }
+
+       ASSERT3U(object_count, ==, usedobjs);
+
+       (void) printf("\n");
+
+       if (error != ESRCH) {
+               (void) fprintf(stderr, "dmu_object_next() = %d\n", error);
+               abort();
+       }
+}
+
+static void
+dump_uberblock(uberblock_t *ub, const char *header, const char *footer)
+{
+       time_t timestamp = ub->ub_timestamp;
+
+       (void) printf("%s", header ? header : "");
+       (void) printf("\tmagic = %016llx\n", (u_longlong_t)ub->ub_magic);
+       (void) printf("\tversion = %llu\n", (u_longlong_t)ub->ub_version);
+       (void) printf("\ttxg = %llu\n", (u_longlong_t)ub->ub_txg);
+       (void) printf("\tguid_sum = %llu\n", (u_longlong_t)ub->ub_guid_sum);
+       (void) printf("\ttimestamp = %llu UTC = %s",
+           (u_longlong_t)ub->ub_timestamp, asctime(localtime(&timestamp)));
+       if (dump_opt['u'] >= 3) {
+               char blkbuf[BP_SPRINTF_LEN];
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), &ub->ub_rootbp);
+               (void) printf("\trootbp = %s\n", blkbuf);
+       }
+       (void) printf("%s", footer ? footer : "");
+}
+
+static void
+dump_config(spa_t *spa)
+{
+       dmu_buf_t *db;
+       size_t nvsize = 0;
+       int error = 0;
+
+
+       error = dmu_bonus_hold(spa->spa_meta_objset,
+           spa->spa_config_object, FTAG, &db);
+
+       if (error == 0) {
+               nvsize = *(uint64_t *)db->db_data;
+               dmu_buf_rele(db, FTAG);
+
+               (void) printf("\nMOS Configuration:\n");
+               dump_packed_nvlist(spa->spa_meta_objset,
+                   spa->spa_config_object, (void *)&nvsize, 1);
+       } else {
+               (void) fprintf(stderr, "dmu_bonus_hold(%llu) failed, errno %d",
+                   (u_longlong_t)spa->spa_config_object, error);
+       }
+}
+
+static void
+dump_cachefile(const char *cachefile)
+{
+       int fd;
+       struct stat64 statbuf;
+       char *buf;
+       nvlist_t *config;
+
+       if ((fd = open64(cachefile, O_RDONLY)) < 0) {
+               (void) printf("cannot open '%s': %s\n", cachefile,
+                   strerror(errno));
+               exit(1);
+       }
+
+       if (fstat64(fd, &statbuf) != 0) {
+               (void) printf("failed to stat '%s': %s\n", cachefile,
+                   strerror(errno));
+               exit(1);
+       }
+
+       if ((buf = malloc(statbuf.st_size)) == NULL) {
+               (void) fprintf(stderr, "failed to allocate %llu bytes\n",
+                   (u_longlong_t)statbuf.st_size);
+               exit(1);
+       }
+
+       if (read(fd, buf, statbuf.st_size) != statbuf.st_size) {
+               (void) fprintf(stderr, "failed to read %llu bytes\n",
+                   (u_longlong_t)statbuf.st_size);
+               exit(1);
+       }
+
+       (void) close(fd);
+
+       if (nvlist_unpack(buf, statbuf.st_size, &config, 0) != 0) {
+               (void) fprintf(stderr, "failed to unpack nvlist\n");
+               exit(1);
+       }
+
+       free(buf);
+
+       dump_nvlist(config, 0);
+
+       nvlist_free(config);
+}
+
+#define        ZDB_MAX_UB_HEADER_SIZE 32
+
+static void
+dump_label_uberblocks(vdev_label_t *lbl, uint64_t ashift)
+{
+       vdev_t vd;
+       vdev_t *vdp = &vd;
+       char header[ZDB_MAX_UB_HEADER_SIZE];
+       int i;
+
+       vd.vdev_ashift = ashift;
+       vdp->vdev_top = vdp;
+
+       for (i = 0; i < VDEV_UBERBLOCK_COUNT(vdp); i++) {
+               uint64_t uoff = VDEV_UBERBLOCK_OFFSET(vdp, i);
+               uberblock_t *ub = (void *)((char *)lbl + uoff);
+
+               if (uberblock_verify(ub))
+                       continue;
+               (void) snprintf(header, ZDB_MAX_UB_HEADER_SIZE,
+                   "Uberblock[%d]\n", i);
+               dump_uberblock(ub, header, "");
+       }
+}
+
+static void
+dump_label(const char *dev)
+{
+       int fd;
+       vdev_label_t label;
+       char *path, *buf = label.vl_vdev_phys.vp_nvlist;
+       size_t buflen = sizeof (label.vl_vdev_phys.vp_nvlist);
+       struct stat64 statbuf;
+       uint64_t psize, ashift;
+       int len = strlen(dev) + 1;
+       int l;
+
+       if (strncmp(dev, "/dev/dsk/", 9) == 0) {
+               len++;
+               path = malloc(len);
+               (void) snprintf(path, len, "%s%s", "/dev/rdsk/", dev + 9);
+       } else {
+               path = strdup(dev);
+       }
+
+       if ((fd = open64(path, O_RDONLY)) < 0) {
+               (void) printf("cannot open '%s': %s\n", path, strerror(errno));
+               free(path);
+               exit(1);
+       }
+
+       if (fstat64_blk(fd, &statbuf) != 0) {
+               (void) printf("failed to stat '%s': %s\n", path,
+                   strerror(errno));
+               free(path);
+               (void) close(fd);
+               exit(1);
+       }
+
+       psize = statbuf.st_size;
+       psize = P2ALIGN(psize, (uint64_t)sizeof (vdev_label_t));
+
+       for (l = 0; l < VDEV_LABELS; l++) {
+               nvlist_t *config = NULL;
+
+               (void) printf("--------------------------------------------\n");
+               (void) printf("LABEL %d\n", l);
+               (void) printf("--------------------------------------------\n");
+
+               if (pread64(fd, &label, sizeof (label),
+                   vdev_label_offset(psize, l, 0)) != sizeof (label)) {
+                       (void) printf("failed to read label %d\n", l);
+                       continue;
+               }
+
+               if (nvlist_unpack(buf, buflen, &config, 0) != 0) {
+                       (void) printf("failed to unpack label %d\n", l);
+                       ashift = SPA_MINBLOCKSHIFT;
+               } else {
+                       nvlist_t *vdev_tree = NULL;
+
+                       dump_nvlist(config, 4);
+                       if ((nvlist_lookup_nvlist(config,
+                           ZPOOL_CONFIG_VDEV_TREE, &vdev_tree) != 0) ||
+                           (nvlist_lookup_uint64(vdev_tree,
+                           ZPOOL_CONFIG_ASHIFT, &ashift) != 0))
+                               ashift = SPA_MINBLOCKSHIFT;
+                       nvlist_free(config);
+               }
+               if (dump_opt['u'])
+                       dump_label_uberblocks(&label, ashift);
+       }
+
+       free(path);
+       (void) close(fd);
+}
+
+static uint64_t dataset_feature_count[SPA_FEATURES];
+
+/*ARGSUSED*/
+static int
+dump_one_dir(const char *dsname, void *arg)
+{
+       int error;
+       objset_t *os;
+       spa_feature_t f;
+
+       error = dmu_objset_own(dsname, DMU_OST_ANY, B_TRUE, FTAG, &os);
+       if (error) {
+               (void) printf("Could not open %s, error %d\n", dsname, error);
+               return (0);
+       }
+
+       for (f = 0; f < SPA_FEATURES; f++) {
+               if (!dmu_objset_ds(os)->ds_feature_inuse[f])
+                       continue;
+               ASSERT(spa_feature_table[f].fi_flags &
+                   ZFEATURE_FLAG_PER_DATASET);
+               dataset_feature_count[f]++;
+       }
+
+       dump_dir(os);
+       dmu_objset_disown(os, FTAG);
+       fuid_table_destroy();
+       sa_loaded = B_FALSE;
+       return (0);
+}
+
+/*
+ * Block statistics.
+ */
+#define        PSIZE_HISTO_SIZE (SPA_OLD_MAXBLOCKSIZE / SPA_MINBLOCKSIZE + 2)
+typedef struct zdb_blkstats {
+       uint64_t zb_asize;
+       uint64_t zb_lsize;
+       uint64_t zb_psize;
+       uint64_t zb_count;
+       uint64_t zb_gangs;
+       uint64_t zb_ditto_samevdev;
+       uint64_t zb_psize_histogram[PSIZE_HISTO_SIZE];
+} zdb_blkstats_t;
+
+/*
+ * Extended object types to report deferred frees and dedup auto-ditto blocks.
+ */
+#define        ZDB_OT_DEFERRED (DMU_OT_NUMTYPES + 0)
+#define        ZDB_OT_DITTO    (DMU_OT_NUMTYPES + 1)
+#define        ZDB_OT_OTHER    (DMU_OT_NUMTYPES + 2)
+#define        ZDB_OT_TOTAL    (DMU_OT_NUMTYPES + 3)
+
+static char *zdb_ot_extname[] = {
+       "deferred free",
+       "dedup ditto",
+       "other",
+       "Total",
+};
+
+#define        ZB_TOTAL        DN_MAX_LEVELS
+
+typedef struct zdb_cb {
+       zdb_blkstats_t  zcb_type[ZB_TOTAL + 1][ZDB_OT_TOTAL + 1];
+       uint64_t        zcb_dedup_asize;
+       uint64_t        zcb_dedup_blocks;
+       uint64_t        zcb_embedded_blocks[NUM_BP_EMBEDDED_TYPES];
+       uint64_t        zcb_embedded_histogram[NUM_BP_EMBEDDED_TYPES]
+           [BPE_PAYLOAD_SIZE + 1];
+       uint64_t        zcb_start;
+       uint64_t        zcb_lastprint;
+       uint64_t        zcb_totalasize;
+       uint64_t        zcb_errors[256];
+       int             zcb_readfails;
+       int             zcb_haderrors;
+       spa_t           *zcb_spa;
+} zdb_cb_t;
+
+static void
+zdb_count_block(zdb_cb_t *zcb, zilog_t *zilog, const blkptr_t *bp,
+    dmu_object_type_t type)
+{
+       uint64_t refcnt = 0;
+       int i;
+
+       ASSERT(type < ZDB_OT_TOTAL);
+
+       if (zilog && zil_bp_tree_add(zilog, bp) != 0)
+               return;
+
+       for (i = 0; i < 4; i++) {
+               int l = (i < 2) ? BP_GET_LEVEL(bp) : ZB_TOTAL;
+               int t = (i & 1) ? type : ZDB_OT_TOTAL;
+               int equal;
+               zdb_blkstats_t *zb = &zcb->zcb_type[l][t];
+
+               zb->zb_asize += BP_GET_ASIZE(bp);
+               zb->zb_lsize += BP_GET_LSIZE(bp);
+               zb->zb_psize += BP_GET_PSIZE(bp);
+               zb->zb_count++;
+
+               /*
+                * The histogram is only big enough to record blocks up to
+                * SPA_OLD_MAXBLOCKSIZE; larger blocks go into the last,
+                * "other", bucket.
+                */
+               int idx = BP_GET_PSIZE(bp) >> SPA_MINBLOCKSHIFT;
+               idx = MIN(idx, SPA_OLD_MAXBLOCKSIZE / SPA_MINBLOCKSIZE + 1);
+               zb->zb_psize_histogram[idx]++;
+
+               zb->zb_gangs += BP_COUNT_GANG(bp);
+
+               switch (BP_GET_NDVAS(bp)) {
+               case 2:
+                       if (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+                           DVA_GET_VDEV(&bp->blk_dva[1]))
+                               zb->zb_ditto_samevdev++;
+                       break;
+               case 3:
+                       equal = (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+                           DVA_GET_VDEV(&bp->blk_dva[1])) +
+                           (DVA_GET_VDEV(&bp->blk_dva[0]) ==
+                           DVA_GET_VDEV(&bp->blk_dva[2])) +
+                           (DVA_GET_VDEV(&bp->blk_dva[1]) ==
+                           DVA_GET_VDEV(&bp->blk_dva[2]));
+                       if (equal != 0)
+                               zb->zb_ditto_samevdev++;
+                       break;
+               }
+
+       }
+
+       if (BP_IS_EMBEDDED(bp)) {
+               zcb->zcb_embedded_blocks[BPE_GET_ETYPE(bp)]++;
+               zcb->zcb_embedded_histogram[BPE_GET_ETYPE(bp)]
+                   [BPE_GET_PSIZE(bp)]++;
+               return;
+       }
+
+       if (dump_opt['L'])
+               return;
+
+       if (BP_GET_DEDUP(bp)) {
+               ddt_t *ddt;
+               ddt_entry_t *dde;
+
+               ddt = ddt_select(zcb->zcb_spa, bp);
+               ddt_enter(ddt);
+               dde = ddt_lookup(ddt, bp, B_FALSE);
+
+               if (dde == NULL) {
+                       refcnt = 0;
+               } else {
+                       ddt_phys_t *ddp = ddt_phys_select(dde, bp);
+                       ddt_phys_decref(ddp);
+                       refcnt = ddp->ddp_refcnt;
+                       if (ddt_phys_total_refcnt(dde) == 0)
+                               ddt_remove(ddt, dde);
+               }
+               ddt_exit(ddt);
+       }
+
+       VERIFY3U(zio_wait(zio_claim(NULL, zcb->zcb_spa,
+           refcnt ? 0 : spa_first_txg(zcb->zcb_spa),
+           bp, NULL, NULL, ZIO_FLAG_CANFAIL)), ==, 0);
+}
+
+static void
+zdb_blkptr_done(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       blkptr_t *bp = zio->io_bp;
+       int ioerr = zio->io_error;
+       zdb_cb_t *zcb = zio->io_private;
+       zbookmark_phys_t *zb = &zio->io_bookmark;
+
+       zio_data_buf_free(zio->io_data, zio->io_size);
+
+       mutex_enter(&spa->spa_scrub_lock);
+       spa->spa_scrub_inflight--;
+       cv_broadcast(&spa->spa_scrub_io_cv);
+
+       if (ioerr && !(zio->io_flags & ZIO_FLAG_SPECULATIVE)) {
+               char blkbuf[BP_SPRINTF_LEN];
+
+               zcb->zcb_haderrors = 1;
+               zcb->zcb_errors[ioerr]++;
+
+               if (dump_opt['b'] >= 2)
+                       snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+               else
+                       blkbuf[0] = '\0';
+
+               (void) printf("zdb_blkptr_cb: "
+                   "Got error %d reading "
+                   "<%llu, %llu, %lld, %llx> %s -- skipping\n",
+                   ioerr,
+                   (u_longlong_t)zb->zb_objset,
+                   (u_longlong_t)zb->zb_object,
+                   (u_longlong_t)zb->zb_level,
+                   (u_longlong_t)zb->zb_blkid,
+                   blkbuf);
+       }
+       mutex_exit(&spa->spa_scrub_lock);
+}
+
+static int
+zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+       zdb_cb_t *zcb = arg;
+       dmu_object_type_t type;
+       boolean_t is_metadata;
+
+       if (bp == NULL)
+               return (0);
+
+       if (dump_opt['b'] >= 5 && bp->blk_birth > 0) {
+               char blkbuf[BP_SPRINTF_LEN];
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+               (void) printf("objset %llu object %llu "
+                   "level %lld offset 0x%llx %s\n",
+                   (u_longlong_t)zb->zb_objset,
+                   (u_longlong_t)zb->zb_object,
+                   (longlong_t)zb->zb_level,
+                   (u_longlong_t)blkid2offset(dnp, bp, zb),
+                   blkbuf);
+       }
+
+       if (BP_IS_HOLE(bp))
+               return (0);
+
+       type = BP_GET_TYPE(bp);
+
+       zdb_count_block(zcb, zilog, bp,
+           (type & DMU_OT_NEWTYPE) ? ZDB_OT_OTHER : type);
+
+       is_metadata = (BP_GET_LEVEL(bp) != 0 || DMU_OT_IS_METADATA(type));
+
+       if (!BP_IS_EMBEDDED(bp) &&
+           (dump_opt['c'] > 1 || (dump_opt['c'] && is_metadata))) {
+               size_t size = BP_GET_PSIZE(bp);
+               void *data = zio_data_buf_alloc(size);
+               int flags = ZIO_FLAG_CANFAIL | ZIO_FLAG_SCRUB | ZIO_FLAG_RAW;
+
+               /* If it's an intent log block, failure is expected. */
+               if (zb->zb_level == ZB_ZIL_LEVEL)
+                       flags |= ZIO_FLAG_SPECULATIVE;
+
+               mutex_enter(&spa->spa_scrub_lock);
+               while (spa->spa_scrub_inflight > max_inflight)
+                       cv_wait(&spa->spa_scrub_io_cv, &spa->spa_scrub_lock);
+               spa->spa_scrub_inflight++;
+               mutex_exit(&spa->spa_scrub_lock);
+
+               zio_nowait(zio_read(NULL, spa, bp, data, size,
+                   zdb_blkptr_done, zcb, ZIO_PRIORITY_ASYNC_READ, flags, zb));
+       }
+
+       zcb->zcb_readfails = 0;
+
+       /* only call gethrtime() every 100 blocks */
+       static int iters;
+       if (++iters > 100)
+               iters = 0;
+       else
+               return (0);
+
+       if (dump_opt['b'] < 5 && gethrtime() > zcb->zcb_lastprint + NANOSEC) {
+               uint64_t now = gethrtime();
+               char buf[10];
+               uint64_t bytes = zcb->zcb_type[ZB_TOTAL][ZDB_OT_TOTAL].zb_asize;
+               int kb_per_sec =
+                   1 + bytes / (1 + ((now - zcb->zcb_start) / 1000 / 1000));
+               int sec_remaining =
+                   (zcb->zcb_totalasize - bytes) / 1024 / kb_per_sec;
+
+               zfs_nicenum(bytes, buf, sizeof (buf));
+               (void) fprintf(stderr,
+                   "\r%5s completed (%4dMB/s) "
+                   "estimated time remaining: %uhr %02umin %02usec        ",
+                   buf, kb_per_sec / 1024,
+                   sec_remaining / 60 / 60,
+                   sec_remaining / 60 % 60,
+                   sec_remaining % 60);
+
+               zcb->zcb_lastprint = now;
+       }
+
+       return (0);
+}
+
+static void
+zdb_leak(void *arg, uint64_t start, uint64_t size)
+{
+       vdev_t *vd = arg;
+
+       (void) printf("leaked space: vdev %llu, offset 0x%llx, size %llu\n",
+           (u_longlong_t)vd->vdev_id, (u_longlong_t)start, (u_longlong_t)size);
+}
+
+static metaslab_ops_t zdb_metaslab_ops = {
+       NULL    /* alloc */
+};
+
+static void
+zdb_ddt_leak_init(spa_t *spa, zdb_cb_t *zcb)
+{
+       ddt_bookmark_t ddb = { 0 };
+       ddt_entry_t dde;
+       int error;
+       int p;
+
+       while ((error = ddt_walk(spa, &ddb, &dde)) == 0) {
+               blkptr_t blk;
+               ddt_phys_t *ddp = dde.dde_phys;
+
+               if (ddb.ddb_class == DDT_CLASS_UNIQUE)
+                       return;
+
+               ASSERT(ddt_phys_total_refcnt(&dde) > 1);
+
+               for (p = 0; p < DDT_PHYS_TYPES; p++, ddp++) {
+                       if (ddp->ddp_phys_birth == 0)
+                               continue;
+                       ddt_bp_create(ddb.ddb_checksum,
+                           &dde.dde_key, ddp, &blk);
+                       if (p == DDT_PHYS_DITTO) {
+                               zdb_count_block(zcb, NULL, &blk, ZDB_OT_DITTO);
+                       } else {
+                               zcb->zcb_dedup_asize +=
+                                   BP_GET_ASIZE(&blk) * (ddp->ddp_refcnt - 1);
+                               zcb->zcb_dedup_blocks++;
+                       }
+               }
+               if (!dump_opt['L']) {
+                       ddt_t *ddt = spa->spa_ddt[ddb.ddb_checksum];
+                       ddt_enter(ddt);
+                       VERIFY(ddt_lookup(ddt, &blk, B_TRUE) != NULL);
+                       ddt_exit(ddt);
+               }
+       }
+
+       ASSERT(error == ENOENT);
+}
+
+static void
+zdb_leak_init(spa_t *spa, zdb_cb_t *zcb)
+{
+       zcb->zcb_spa = spa;
+       uint64_t c, m;
+
+       if (!dump_opt['L']) {
+               vdev_t *rvd = spa->spa_root_vdev;
+               for (c = 0; c < rvd->vdev_children; c++) {
+                       vdev_t *vd = rvd->vdev_child[c];
+                       for (m = 0; m < vd->vdev_ms_count; m++) {
+                               metaslab_t *msp = vd->vdev_ms[m];
+                               mutex_enter(&msp->ms_lock);
+                               metaslab_unload(msp);
+
+                               /*
+                                * For leak detection, we overload the metaslab
+                                * ms_tree to contain allocated segments
+                                * instead of free segments. As a result,
+                                * we can't use the normal metaslab_load/unload
+                                * interfaces.
+                                */
+                               if (msp->ms_sm != NULL) {
+                                       (void) fprintf(stderr,
+                                           "\rloading space map for "
+                                           "vdev %llu of %llu, "
+                                           "metaslab %llu of %llu ...",
+                                           (longlong_t)c,
+                                           (longlong_t)rvd->vdev_children,
+                                           (longlong_t)m,
+                                           (longlong_t)vd->vdev_ms_count);
+
+                                       msp->ms_ops = &zdb_metaslab_ops;
+
+                                       /*
+                                        * We don't want to spend the CPU
+                                        * manipulating the size-ordered
+                                        * tree, so clear the range_tree
+                                        * ops.
+                                        */
+                                       msp->ms_tree->rt_ops = NULL;
+                                       VERIFY0(space_map_load(msp->ms_sm,
+                                           msp->ms_tree, SM_ALLOC));
+                                       msp->ms_loaded = B_TRUE;
+                               }
+                               mutex_exit(&msp->ms_lock);
+                       }
+               }
+               (void) fprintf(stderr, "\n");
+       }
+
+       spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+
+       zdb_ddt_leak_init(spa, zcb);
+
+       spa_config_exit(spa, SCL_CONFIG, FTAG);
+}
+
+static void
+zdb_leak_fini(spa_t *spa)
+{
+       int c, m;
+
+       if (!dump_opt['L']) {
+               vdev_t *rvd = spa->spa_root_vdev;
+               for (c = 0; c < rvd->vdev_children; c++) {
+                       vdev_t *vd = rvd->vdev_child[c];
+                       for (m = 0; m < vd->vdev_ms_count; m++) {
+                               metaslab_t *msp = vd->vdev_ms[m];
+                               mutex_enter(&msp->ms_lock);
+
+                               /*
+                                * The ms_tree has been overloaded to
+                                * contain allocated segments. Now that we
+                                * finished traversing all blocks, any
+                                * block that remains in the ms_tree
+                                * represents an allocated block that we
+                                * did not claim during the traversal.
+                                * Claimed blocks would have been removed
+                                * from the ms_tree.
+                                */
+                               range_tree_vacate(msp->ms_tree, zdb_leak, vd);
+                               msp->ms_loaded = B_FALSE;
+
+                               mutex_exit(&msp->ms_lock);
+                       }
+               }
+       }
+}
+
+/* ARGSUSED */
+static int
+count_block_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx)
+{
+       zdb_cb_t *zcb = arg;
+
+       if (dump_opt['b'] >= 5) {
+               char blkbuf[BP_SPRINTF_LEN];
+               snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+               (void) printf("[%s] %s\n",
+                   "deferred free", blkbuf);
+       }
+       zdb_count_block(zcb, NULL, bp, ZDB_OT_DEFERRED);
+       return (0);
+}
+
+static int
+dump_block_stats(spa_t *spa)
+{
+       zdb_cb_t zcb;
+       zdb_blkstats_t *zb, *tzb;
+       uint64_t norm_alloc, norm_space, total_alloc, total_found;
+       int flags = TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA | TRAVERSE_HARD;
+       boolean_t leaks = B_FALSE;
+       int e, c;
+       bp_embedded_type_t i;
+
+       (void) printf("\nTraversing all blocks %s%s%s%s%s...\n\n",
+           (dump_opt['c'] || !dump_opt['L']) ? "to verify " : "",
+           (dump_opt['c'] == 1) ? "metadata " : "",
+           dump_opt['c'] ? "checksums " : "",
+           (dump_opt['c'] && !dump_opt['L']) ? "and verify " : "",
+           !dump_opt['L'] ? "nothing leaked " : "");
+
+       /*
+        * Load all space maps as SM_ALLOC maps, then traverse the pool
+        * claiming each block we discover.  If the pool is perfectly
+        * consistent, the space maps will be empty when we're done.
+        * Anything left over is a leak; any block we can't claim (because
+        * it's not part of any space map) is a double allocation,
+        * reference to a freed block, or an unclaimed log block.
+        */
+       bzero(&zcb, sizeof (zdb_cb_t));
+       zdb_leak_init(spa, &zcb);
+
+       /*
+        * If there's a deferred-free bplist, process that first.
+        */
+       (void) bpobj_iterate_nofree(&spa->spa_deferred_bpobj,
+           count_block_cb, &zcb, NULL);
+       if (spa_version(spa) >= SPA_VERSION_DEADLISTS) {
+               (void) bpobj_iterate_nofree(&spa->spa_dsl_pool->dp_free_bpobj,
+                   count_block_cb, &zcb, NULL);
+       }
+       if (spa_feature_is_active(spa, SPA_FEATURE_ASYNC_DESTROY)) {
+               VERIFY3U(0, ==, bptree_iterate(spa->spa_meta_objset,
+                   spa->spa_dsl_pool->dp_bptree_obj, B_FALSE, count_block_cb,
+                   &zcb, NULL));
+       }
+
+       if (dump_opt['c'] > 1)
+               flags |= TRAVERSE_PREFETCH_DATA;
+
+       zcb.zcb_totalasize = metaslab_class_get_alloc(spa_normal_class(spa));
+       zcb.zcb_start = zcb.zcb_lastprint = gethrtime();
+       zcb.zcb_haderrors |= traverse_pool(spa, 0, flags, zdb_blkptr_cb, &zcb);
+
+       /*
+        * If we've traversed the data blocks then we need to wait for those
+        * I/Os to complete. We leverage "The Godfather" zio to wait on
+        * all async I/Os to complete.
+        */
+       if (dump_opt['c']) {
+               for (c = 0; c < max_ncpus; c++) {
+                       (void) zio_wait(spa->spa_async_zio_root[c]);
+                       spa->spa_async_zio_root[c] = zio_root(spa, NULL, NULL,
+                           ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
+                           ZIO_FLAG_GODFATHER);
+               }
+       }
+
+       if (zcb.zcb_haderrors) {
+               (void) printf("\nError counts:\n\n");
+               (void) printf("\t%5s  %s\n", "errno", "count");
+               for (e = 0; e < 256; e++) {
+                       if (zcb.zcb_errors[e] != 0) {
+                               (void) printf("\t%5d  %llu\n",
+                                   e, (u_longlong_t)zcb.zcb_errors[e]);
+                       }
+               }
+       }
+
+       /*
+        * Report any leaked segments.
+        */
+       zdb_leak_fini(spa);
+
+       tzb = &zcb.zcb_type[ZB_TOTAL][ZDB_OT_TOTAL];
+
+       norm_alloc = metaslab_class_get_alloc(spa_normal_class(spa));
+       norm_space = metaslab_class_get_space(spa_normal_class(spa));
+
+       total_alloc = norm_alloc + metaslab_class_get_alloc(spa_log_class(spa));
+       total_found = tzb->zb_asize - zcb.zcb_dedup_asize;
+
+       if (total_found == total_alloc) {
+               if (!dump_opt['L'])
+                       (void) printf("\n\tNo leaks (block sum matches space"
+                           " maps exactly)\n");
+       } else {
+               (void) printf("block traversal size %llu != alloc %llu "
+                   "(%s %lld)\n",
+                   (u_longlong_t)total_found,
+                   (u_longlong_t)total_alloc,
+                   (dump_opt['L']) ? "unreachable" : "leaked",
+                   (longlong_t)(total_alloc - total_found));
+               leaks = B_TRUE;
+       }
+
+       if (tzb->zb_count == 0)
+               return (2);
+
+       (void) printf("\n");
+       (void) printf("\tbp count:      %10llu\n",
+           (u_longlong_t)tzb->zb_count);
+       (void) printf("\tganged count:  %10llu\n",
+           (longlong_t)tzb->zb_gangs);
+       (void) printf("\tbp logical:    %10llu      avg: %6llu\n",
+           (u_longlong_t)tzb->zb_lsize,
+           (u_longlong_t)(tzb->zb_lsize / tzb->zb_count));
+       (void) printf("\tbp physical:   %10llu      avg:"
+           " %6llu     compression: %6.2f\n",
+           (u_longlong_t)tzb->zb_psize,
+           (u_longlong_t)(tzb->zb_psize / tzb->zb_count),
+           (double)tzb->zb_lsize / tzb->zb_psize);
+       (void) printf("\tbp allocated:  %10llu      avg:"
+           " %6llu     compression: %6.2f\n",
+           (u_longlong_t)tzb->zb_asize,
+           (u_longlong_t)(tzb->zb_asize / tzb->zb_count),
+           (double)tzb->zb_lsize / tzb->zb_asize);
+       (void) printf("\tbp deduped:    %10llu    ref>1:"
+           " %6llu   deduplication: %6.2f\n",
+           (u_longlong_t)zcb.zcb_dedup_asize,
+           (u_longlong_t)zcb.zcb_dedup_blocks,
+           (double)zcb.zcb_dedup_asize / tzb->zb_asize + 1.0);
+       (void) printf("\tSPA allocated: %10llu     used: %5.2f%%\n",
+           (u_longlong_t)norm_alloc, 100.0 * norm_alloc / norm_space);
+
+       for (i = 0; i < NUM_BP_EMBEDDED_TYPES; i++) {
+               if (zcb.zcb_embedded_blocks[i] == 0)
+                       continue;
+               (void) printf("\n");
+               (void) printf("\tadditional, non-pointer bps of type %u: "
+                   "%10llu\n",
+                   i, (u_longlong_t)zcb.zcb_embedded_blocks[i]);
+
+               if (dump_opt['b'] >= 3) {
+                       (void) printf("\t number of (compressed) bytes:  "
+                           "number of bps\n");
+                       dump_histogram(zcb.zcb_embedded_histogram[i],
+                           sizeof (zcb.zcb_embedded_histogram[i]) /
+                           sizeof (zcb.zcb_embedded_histogram[i][0]), 0);
+               }
+       }
+
+       if (tzb->zb_ditto_samevdev != 0) {
+               (void) printf("\tDittoed blocks on same vdev: %llu\n",
+                   (longlong_t)tzb->zb_ditto_samevdev);
+       }
+
+       if (dump_opt['b'] >= 2) {
+               int l, t, level;
+               (void) printf("\nBlocks\tLSIZE\tPSIZE\tASIZE"
+                   "\t  avg\t comp\t%%Total\tType\n");
+
+               for (t = 0; t <= ZDB_OT_TOTAL; t++) {
+                       char csize[32], lsize[32], psize[32], asize[32];
+                       char avg[32], gang[32];
+                       char *typename;
+
+                       if (t < DMU_OT_NUMTYPES)
+                               typename = dmu_ot[t].ot_name;
+                       else
+                               typename = zdb_ot_extname[t - DMU_OT_NUMTYPES];
+
+                       if (zcb.zcb_type[ZB_TOTAL][t].zb_asize == 0) {
+                               (void) printf("%6s\t%5s\t%5s\t%5s"
+                                   "\t%5s\t%5s\t%6s\t%s\n",
+                                   "-",
+                                   "-",
+                                   "-",
+                                   "-",
+                                   "-",
+                                   "-",
+                                   "-",
+                                   typename);
+                               continue;
+                       }
+
+                       for (l = ZB_TOTAL - 1; l >= -1; l--) {
+                               level = (l == -1 ? ZB_TOTAL : l);
+                               zb = &zcb.zcb_type[level][t];
+
+                               if (zb->zb_asize == 0)
+                                       continue;
+
+                               if (dump_opt['b'] < 3 && level != ZB_TOTAL)
+                                       continue;
+
+                               if (level == 0 && zb->zb_asize ==
+                                   zcb.zcb_type[ZB_TOTAL][t].zb_asize)
+                                       continue;
+
+                               zdb_nicenum(zb->zb_count, csize);
+                               zdb_nicenum(zb->zb_lsize, lsize);
+                               zdb_nicenum(zb->zb_psize, psize);
+                               zdb_nicenum(zb->zb_asize, asize);
+                               zdb_nicenum(zb->zb_asize / zb->zb_count, avg);
+                               zdb_nicenum(zb->zb_gangs, gang);
+
+                               (void) printf("%6s\t%5s\t%5s\t%5s\t%5s"
+                                   "\t%5.2f\t%6.2f\t",
+                                   csize, lsize, psize, asize, avg,
+                                   (double)zb->zb_lsize / zb->zb_psize,
+                                   100.0 * zb->zb_asize / tzb->zb_asize);
+
+                               if (level == ZB_TOTAL)
+                                       (void) printf("%s\n", typename);
+                               else
+                                       (void) printf("    L%d %s\n",
+                                           level, typename);
+
+                               if (dump_opt['b'] >= 3 && zb->zb_gangs > 0) {
+                                       (void) printf("\t number of ganged "
+                                           "blocks: %s\n", gang);
+                               }
+
+                               if (dump_opt['b'] >= 4) {
+                                       (void) printf("psize "
+                                           "(in 512-byte sectors): "
+                                           "number of blocks\n");
+                                       dump_histogram(zb->zb_psize_histogram,
+                                           PSIZE_HISTO_SIZE, 0);
+                               }
+                       }
+               }
+       }
+
+       (void) printf("\n");
+
+       if (leaks)
+               return (2);
+
+       if (zcb.zcb_haderrors)
+               return (3);
+
+       return (0);
+}
+
+typedef struct zdb_ddt_entry {
+       ddt_key_t       zdde_key;
+       uint64_t        zdde_ref_blocks;
+       uint64_t        zdde_ref_lsize;
+       uint64_t        zdde_ref_psize;
+       uint64_t        zdde_ref_dsize;
+       avl_node_t      zdde_node;
+} zdb_ddt_entry_t;
+
+/* ARGSUSED */
+static int
+zdb_ddt_add_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+{
+       avl_tree_t *t = arg;
+       avl_index_t where;
+       zdb_ddt_entry_t *zdde, zdde_search;
+
+       if (bp == NULL || BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
+               return (0);
+
+       if (dump_opt['S'] > 1 && zb->zb_level == ZB_ROOT_LEVEL) {
+               (void) printf("traversing objset %llu, %llu objects, "
+                   "%lu blocks so far\n",
+                   (u_longlong_t)zb->zb_objset,
+                   (u_longlong_t)BP_GET_FILL(bp),
+                   avl_numnodes(t));
+       }
+
+       if (BP_IS_HOLE(bp) || BP_GET_CHECKSUM(bp) == ZIO_CHECKSUM_OFF ||
+           BP_GET_LEVEL(bp) > 0 || DMU_OT_IS_METADATA(BP_GET_TYPE(bp)))
+               return (0);
+
+       ddt_key_fill(&zdde_search.zdde_key, bp);
+
+       zdde = avl_find(t, &zdde_search, &where);
+
+       if (zdde == NULL) {
+               zdde = umem_zalloc(sizeof (*zdde), UMEM_NOFAIL);
+               zdde->zdde_key = zdde_search.zdde_key;
+               avl_insert(t, zdde, where);
+       }
+
+       zdde->zdde_ref_blocks += 1;
+       zdde->zdde_ref_lsize += BP_GET_LSIZE(bp);
+       zdde->zdde_ref_psize += BP_GET_PSIZE(bp);
+       zdde->zdde_ref_dsize += bp_get_dsize_sync(spa, bp);
+
+       return (0);
+}
+
+static void
+dump_simulated_ddt(spa_t *spa)
+{
+       avl_tree_t t;
+       void *cookie = NULL;
+       zdb_ddt_entry_t *zdde;
+       ddt_histogram_t ddh_total;
+       ddt_stat_t dds_total;
+
+       bzero(&ddh_total, sizeof (ddt_histogram_t));
+       bzero(&dds_total, sizeof (ddt_stat_t));
+
+       avl_create(&t, ddt_entry_compare,
+           sizeof (zdb_ddt_entry_t), offsetof(zdb_ddt_entry_t, zdde_node));
+
+       spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER);
+
+       (void) traverse_pool(spa, 0, TRAVERSE_PRE | TRAVERSE_PREFETCH_METADATA,
+           zdb_ddt_add_cb, &t);
+
+       spa_config_exit(spa, SCL_CONFIG, FTAG);
+
+       while ((zdde = avl_destroy_nodes(&t, &cookie)) != NULL) {
+               ddt_stat_t dds;
+               uint64_t refcnt = zdde->zdde_ref_blocks;
+               ASSERT(refcnt != 0);
+
+               dds.dds_blocks = zdde->zdde_ref_blocks / refcnt;
+               dds.dds_lsize = zdde->zdde_ref_lsize / refcnt;
+               dds.dds_psize = zdde->zdde_ref_psize / refcnt;
+               dds.dds_dsize = zdde->zdde_ref_dsize / refcnt;
+
+               dds.dds_ref_blocks = zdde->zdde_ref_blocks;
+               dds.dds_ref_lsize = zdde->zdde_ref_lsize;
+               dds.dds_ref_psize = zdde->zdde_ref_psize;
+               dds.dds_ref_dsize = zdde->zdde_ref_dsize;
+
+               ddt_stat_add(&ddh_total.ddh_stat[highbit64(refcnt) - 1],
+                   &dds, 0);
+
+               umem_free(zdde, sizeof (*zdde));
+       }
+
+       avl_destroy(&t);
+
+       ddt_histogram_stat(&dds_total, &ddh_total);
+
+       (void) printf("Simulated DDT histogram:\n");
+
+       zpool_dump_ddt(&dds_total, &ddh_total);
+
+       dump_dedup_ratio(&dds_total);
+}
+
+static void
+dump_zpool(spa_t *spa)
+{
+       dsl_pool_t *dp = spa_get_dsl(spa);
+       int rc = 0;
+
+       if (dump_opt['S']) {
+               dump_simulated_ddt(spa);
+               return;
+       }
+
+       if (!dump_opt['e'] && dump_opt['C'] > 1) {
+               (void) printf("\nCached configuration:\n");
+               dump_nvlist(spa->spa_config, 8);
+       }
+
+       if (dump_opt['C'])
+               dump_config(spa);
+
+       if (dump_opt['u'])
+               dump_uberblock(&spa->spa_uberblock, "\nUberblock:\n", "\n");
+
+       if (dump_opt['D'])
+               dump_all_ddts(spa);
+
+       if (dump_opt['d'] > 2 || dump_opt['m'])
+               dump_metaslabs(spa);
+       if (dump_opt['M'])
+               dump_metaslab_groups(spa);
+
+       if (dump_opt['d'] || dump_opt['i']) {
+               spa_feature_t f;
+
+               dump_dir(dp->dp_meta_objset);
+               if (dump_opt['d'] >= 3) {
+                       dump_full_bpobj(&spa->spa_deferred_bpobj,
+                           "Deferred frees", 0);
+                       if (spa_version(spa) >= SPA_VERSION_DEADLISTS) {
+                               dump_full_bpobj(
+                                   &spa->spa_dsl_pool->dp_free_bpobj,
+                                   "Pool snapshot frees", 0);
+                       }
+
+                       if (spa_feature_is_active(spa,
+                           SPA_FEATURE_ASYNC_DESTROY)) {
+                               dump_bptree(spa->spa_meta_objset,
+                                   spa->spa_dsl_pool->dp_bptree_obj,
+                                   "Pool dataset frees");
+                       }
+                       dump_dtl(spa->spa_root_vdev, 0);
+               }
+               (void) dmu_objset_find(spa_name(spa), dump_one_dir,
+                   NULL, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
+
+               for (f = 0; f < SPA_FEATURES; f++) {
+                       uint64_t refcount;
+
+                       if (!(spa_feature_table[f].fi_flags &
+                           ZFEATURE_FLAG_PER_DATASET)) {
+                               ASSERT0(dataset_feature_count[f]);
+                               continue;
+                       }
+                       if (feature_get_refcount(spa, &spa_feature_table[f],
+                           &refcount) == ENOTSUP)
+                               continue;
+                       if (dataset_feature_count[f] != refcount) {
+                               (void) printf("%s feature refcount mismatch: "
+                                   "%lld datasets != %lld refcount\n",
+                                   spa_feature_table[f].fi_uname,
+                                   (longlong_t)dataset_feature_count[f],
+                                   (longlong_t)refcount);
+                               rc = 2;
+                       } else {
+                               (void) printf("Verified %s feature refcount "
+                                   "of %llu is correct\n",
+                                   spa_feature_table[f].fi_uname,
+                                   (longlong_t)refcount);
+                       }
+               }
+       }
+       if (rc == 0 && (dump_opt['b'] || dump_opt['c']))
+               rc = dump_block_stats(spa);
+
+       if (rc == 0)
+               rc = verify_spacemap_refcounts(spa);
+
+       if (dump_opt['s'])
+               show_pool_stats(spa);
+
+       if (dump_opt['h'])
+               dump_history(spa);
+
+       if (rc != 0)
+               exit(rc);
+}
+
+#define        ZDB_FLAG_CHECKSUM       0x0001
+#define        ZDB_FLAG_DECOMPRESS     0x0002
+#define        ZDB_FLAG_BSWAP          0x0004
+#define        ZDB_FLAG_GBH            0x0008
+#define        ZDB_FLAG_INDIRECT       0x0010
+#define        ZDB_FLAG_PHYS           0x0020
+#define        ZDB_FLAG_RAW            0x0040
+#define        ZDB_FLAG_PRINT_BLKPTR   0x0080
+
+int flagbits[256];
+
+static void
+zdb_print_blkptr(blkptr_t *bp, int flags)
+{
+       char blkbuf[BP_SPRINTF_LEN];
+
+       if (flags & ZDB_FLAG_BSWAP)
+               byteswap_uint64_array((void *)bp, sizeof (blkptr_t));
+
+       snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+       (void) printf("%s\n", blkbuf);
+}
+
+static void
+zdb_dump_indirect(blkptr_t *bp, int nbps, int flags)
+{
+       int i;
+
+       for (i = 0; i < nbps; i++)
+               zdb_print_blkptr(&bp[i], flags);
+}
+
+static void
+zdb_dump_gbh(void *buf, int flags)
+{
+       zdb_dump_indirect((blkptr_t *)buf, SPA_GBH_NBLKPTRS, flags);
+}
+
+static void
+zdb_dump_block_raw(void *buf, uint64_t size, int flags)
+{
+       if (flags & ZDB_FLAG_BSWAP)
+               byteswap_uint64_array(buf, size);
+       VERIFY(write(fileno(stdout), buf, size) == size);
+}
+
+static void
+zdb_dump_block(char *label, void *buf, uint64_t size, int flags)
+{
+       uint64_t *d = (uint64_t *)buf;
+       int nwords = size / sizeof (uint64_t);
+       int do_bswap = !!(flags & ZDB_FLAG_BSWAP);
+       int i, j;
+       char *hdr, *c;
+
+
+       if (do_bswap)
+               hdr = " 7 6 5 4 3 2 1 0   f e d c b a 9 8";
+       else
+               hdr = " 0 1 2 3 4 5 6 7   8 9 a b c d e f";
+
+       (void) printf("\n%s\n%6s   %s  0123456789abcdef\n", label, "", hdr);
+
+#ifdef _LITTLE_ENDIAN
+       /* correct the endianess */
+       do_bswap = !do_bswap;
+#endif
+       for (i = 0; i < nwords; i += 2) {
+               (void) printf("%06llx:  %016llx  %016llx  ",
+                   (u_longlong_t)(i * sizeof (uint64_t)),
+                   (u_longlong_t)(do_bswap ? BSWAP_64(d[i]) : d[i]),
+                   (u_longlong_t)(do_bswap ? BSWAP_64(d[i + 1]) : d[i + 1]));
+
+               c = (char *)&d[i];
+               for (j = 0; j < 2 * sizeof (uint64_t); j++)
+                       (void) printf("%c", isprint(c[j]) ? c[j] : '.');
+               (void) printf("\n");
+       }
+}
+
+/*
+ * There are two acceptable formats:
+ *     leaf_name         - For example: c1t0d0 or /tmp/ztest.0a
+ *     child[.child]*    - For example: 0.1.1
+ *
+ * The second form can be used to specify arbitrary vdevs anywhere
+ * in the heirarchy.  For example, in a pool with a mirror of
+ * RAID-Zs, you can specify either RAID-Z vdev with 0.0 or 0.1 .
+ */
+static vdev_t *
+zdb_vdev_lookup(vdev_t *vdev, char *path)
+{
+       char *s, *p, *q;
+       int i;
+
+       if (vdev == NULL)
+               return (NULL);
+
+       /* First, assume the x.x.x.x format */
+       i = (int)strtoul(path, &s, 10);
+       if (s == path || (s && *s != '.' && *s != '\0'))
+               goto name;
+       if (i < 0 || i >= vdev->vdev_children)
+               return (NULL);
+
+       vdev = vdev->vdev_child[i];
+       if (s && *s == '\0')
+               return (vdev);
+       return (zdb_vdev_lookup(vdev, s+1));
+
+name:
+       for (i = 0; i < vdev->vdev_children; i++) {
+               vdev_t *vc = vdev->vdev_child[i];
+
+               if (vc->vdev_path == NULL) {
+                       vc = zdb_vdev_lookup(vc, path);
+                       if (vc == NULL)
+                               continue;
+                       else
+                               return (vc);
+               }
+
+               p = strrchr(vc->vdev_path, '/');
+               p = p ? p + 1 : vc->vdev_path;
+               q = &vc->vdev_path[strlen(vc->vdev_path) - 2];
+
+               if (strcmp(vc->vdev_path, path) == 0)
+                       return (vc);
+               if (strcmp(p, path) == 0)
+                       return (vc);
+               if (strcmp(q, "s0") == 0 && strncmp(p, path, q - p) == 0)
+                       return (vc);
+       }
+
+       return (NULL);
+}
+
+/*
+ * Read a block from a pool and print it out.  The syntax of the
+ * block descriptor is:
+ *
+ *     pool:vdev_specifier:offset:size[:flags]
+ *
+ *     pool           - The name of the pool you wish to read from
+ *     vdev_specifier - Which vdev (see comment for zdb_vdev_lookup)
+ *     offset         - offset, in hex, in bytes
+ *     size           - Amount of data to read, in hex, in bytes
+ *     flags          - A string of characters specifying options
+ *              b: Decode a blkptr at given offset within block
+ *             *c: Calculate and display checksums
+ *              d: Decompress data before dumping
+ *              e: Byteswap data before dumping
+ *              g: Display data as a gang block header
+ *              i: Display as an indirect block
+ *              p: Do I/O to physical offset
+ *              r: Dump raw data to stdout
+ *
+ *              * = not yet implemented
+ */
+static void
+zdb_read_block(char *thing, spa_t *spa)
+{
+       blkptr_t blk, *bp = &blk;
+       dva_t *dva = bp->blk_dva;
+       int flags = 0;
+       uint64_t offset = 0, size = 0, psize = 0, lsize = 0, blkptr_offset = 0;
+       zio_t *zio;
+       vdev_t *vd;
+       void *pbuf, *lbuf, *buf;
+       char *s, *p, *dup, *vdev, *flagstr;
+       int i, error;
+
+       dup = strdup(thing);
+       s = strtok(dup, ":");
+       vdev = s ? s : "";
+       s = strtok(NULL, ":");
+       offset = strtoull(s ? s : "", NULL, 16);
+       s = strtok(NULL, ":");
+       size = strtoull(s ? s : "", NULL, 16);
+       s = strtok(NULL, ":");
+       flagstr = s ? s : "";
+
+       s = NULL;
+       if (size == 0)
+               s = "size must not be zero";
+       if (!IS_P2ALIGNED(size, DEV_BSIZE))
+               s = "size must be a multiple of sector size";
+       if (!IS_P2ALIGNED(offset, DEV_BSIZE))
+               s = "offset must be a multiple of sector size";
+       if (s) {
+               (void) printf("Invalid block specifier: %s  - %s\n", thing, s);
+               free(dup);
+               return;
+       }
+
+       for (s = strtok(flagstr, ":"); s; s = strtok(NULL, ":")) {
+               for (i = 0; flagstr[i]; i++) {
+                       int bit = flagbits[(uchar_t)flagstr[i]];
+
+                       if (bit == 0) {
+                               (void) printf("***Invalid flag: %c\n",
+                                   flagstr[i]);
+                               continue;
+                       }
+                       flags |= bit;
+
+                       /* If it's not something with an argument, keep going */
+                       if ((bit & (ZDB_FLAG_CHECKSUM |
+                           ZDB_FLAG_PRINT_BLKPTR)) == 0)
+                               continue;
+
+                       p = &flagstr[i + 1];
+                       if (bit == ZDB_FLAG_PRINT_BLKPTR) {
+                               blkptr_offset = strtoull(p, &p, 16);
+                               i = p - &flagstr[i + 1];
+                       }
+                       if (*p != ':' && *p != '\0') {
+                               (void) printf("***Invalid flag arg: '%s'\n", s);
+                               free(dup);
+                               return;
+                       }
+               }
+       }
+
+       vd = zdb_vdev_lookup(spa->spa_root_vdev, vdev);
+       if (vd == NULL) {
+               (void) printf("***Invalid vdev: %s\n", vdev);
+               free(dup);
+               return;
+       } else {
+               if (vd->vdev_path)
+                       (void) fprintf(stderr, "Found vdev: %s\n",
+                           vd->vdev_path);
+               else
+                       (void) fprintf(stderr, "Found vdev type: %s\n",
+                           vd->vdev_ops->vdev_op_type);
+       }
+
+       psize = size;
+       lsize = size;
+
+       /* Some 4K native devices require 4K buffer alignment */
+       pbuf = umem_alloc_aligned(SPA_MAXBLOCKSIZE, PAGESIZE, UMEM_NOFAIL);
+       lbuf = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
+
+       BP_ZERO(bp);
+
+       DVA_SET_VDEV(&dva[0], vd->vdev_id);
+       DVA_SET_OFFSET(&dva[0], offset);
+       DVA_SET_GANG(&dva[0], !!(flags & ZDB_FLAG_GBH));
+       DVA_SET_ASIZE(&dva[0], vdev_psize_to_asize(vd, psize));
+
+       BP_SET_BIRTH(bp, TXG_INITIAL, TXG_INITIAL);
+
+       BP_SET_LSIZE(bp, lsize);
+       BP_SET_PSIZE(bp, psize);
+       BP_SET_COMPRESS(bp, ZIO_COMPRESS_OFF);
+       BP_SET_CHECKSUM(bp, ZIO_CHECKSUM_OFF);
+       BP_SET_TYPE(bp, DMU_OT_NONE);
+       BP_SET_LEVEL(bp, 0);
+       BP_SET_DEDUP(bp, 0);
+       BP_SET_BYTEORDER(bp, ZFS_HOST_BYTEORDER);
+
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+       zio = zio_root(spa, NULL, NULL, 0);
+
+       if (vd == vd->vdev_top) {
+               /*
+                * Treat this as a normal block read.
+                */
+               zio_nowait(zio_read(zio, spa, bp, pbuf, psize, NULL, NULL,
+                   ZIO_PRIORITY_SYNC_READ,
+                   ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW, NULL));
+       } else {
+               /*
+                * Treat this as a vdev child I/O.
+                */
+               zio_nowait(zio_vdev_child_io(zio, bp, vd, offset, pbuf, psize,
+                   ZIO_TYPE_READ, ZIO_PRIORITY_SYNC_READ,
+                   ZIO_FLAG_DONT_CACHE | ZIO_FLAG_DONT_QUEUE |
+                   ZIO_FLAG_DONT_PROPAGATE | ZIO_FLAG_DONT_RETRY |
+                   ZIO_FLAG_CANFAIL | ZIO_FLAG_RAW, NULL, NULL));
+       }
+
+       error = zio_wait(zio);
+       spa_config_exit(spa, SCL_STATE, FTAG);
+
+       if (error) {
+               (void) printf("Read of %s failed, error: %d\n", thing, error);
+               goto out;
+       }
+
+       if (flags & ZDB_FLAG_DECOMPRESS) {
+               /*
+                * We don't know how the data was compressed, so just try
+                * every decompress function at every inflated blocksize.
+                */
+               enum zio_compress c;
+               void *pbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
+               void *lbuf2 = umem_alloc(SPA_MAXBLOCKSIZE, UMEM_NOFAIL);
+
+               bcopy(pbuf, pbuf2, psize);
+
+               VERIFY(random_get_pseudo_bytes((uint8_t *)pbuf + psize,
+                   SPA_MAXBLOCKSIZE - psize) == 0);
+
+               VERIFY(random_get_pseudo_bytes((uint8_t *)pbuf2 + psize,
+                   SPA_MAXBLOCKSIZE - psize) == 0);
+
+               /*
+                * XXX - On the one hand, with SPA_MAXBLOCKSIZE at 16MB,
+                * this could take a while and we should let the user know
+                * we are not stuck.  On the other hand, printing progress
+                * info gets old after a while.  What to do?
+                */
+               for (lsize = psize + SPA_MINBLOCKSIZE;
+                   lsize <= SPA_MAXBLOCKSIZE; lsize += SPA_MINBLOCKSIZE) {
+                       for (c = 0; c < ZIO_COMPRESS_FUNCTIONS; c++) {
+                               (void) fprintf(stderr,
+                                   "Trying %05llx -> %05llx (%s)\n",
+                                   (u_longlong_t)psize, (u_longlong_t)lsize,
+                                   zio_compress_table[c].ci_name);
+                               if (zio_decompress_data(c, pbuf, lbuf,
+                                   psize, lsize) == 0 &&
+                                   zio_decompress_data(c, pbuf2, lbuf2,
+                                   psize, lsize) == 0 &&
+                                   bcmp(lbuf, lbuf2, lsize) == 0)
+                                       break;
+                       }
+                       if (c != ZIO_COMPRESS_FUNCTIONS)
+                               break;
+               }
+
+               umem_free(pbuf2, SPA_MAXBLOCKSIZE);
+               umem_free(lbuf2, SPA_MAXBLOCKSIZE);
+
+               if (lsize <= psize) {
+                       (void) printf("Decompress of %s failed\n", thing);
+                       goto out;
+               }
+               buf = lbuf;
+               size = lsize;
+       } else {
+               buf = pbuf;
+               size = psize;
+       }
+
+       if (flags & ZDB_FLAG_PRINT_BLKPTR)
+               zdb_print_blkptr((blkptr_t *)(void *)
+                   ((uintptr_t)buf + (uintptr_t)blkptr_offset), flags);
+       else if (flags & ZDB_FLAG_RAW)
+               zdb_dump_block_raw(buf, size, flags);
+       else if (flags & ZDB_FLAG_INDIRECT)
+               zdb_dump_indirect((blkptr_t *)buf, size / sizeof (blkptr_t),
+                   flags);
+       else if (flags & ZDB_FLAG_GBH)
+               zdb_dump_gbh(buf, flags);
+       else
+               zdb_dump_block(thing, buf, size, flags);
+
+out:
+       umem_free(pbuf, SPA_MAXBLOCKSIZE);
+       umem_free(lbuf, SPA_MAXBLOCKSIZE);
+       free(dup);
+}
+
+static boolean_t
+pool_match(nvlist_t *cfg, char *tgt)
+{
+       uint64_t v, guid = strtoull(tgt, NULL, 0);
+       char *s;
+
+       if (guid != 0) {
+               if (nvlist_lookup_uint64(cfg, ZPOOL_CONFIG_POOL_GUID, &v) == 0)
+                       return (v == guid);
+       } else {
+               if (nvlist_lookup_string(cfg, ZPOOL_CONFIG_POOL_NAME, &s) == 0)
+                       return (strcmp(s, tgt) == 0);
+       }
+       return (B_FALSE);
+}
+
+static char *
+find_zpool(char **target, nvlist_t **configp, int dirc, char **dirv)
+{
+       nvlist_t *pools;
+       nvlist_t *match = NULL;
+       char *name = NULL;
+       char *sepp = NULL;
+       char sep = '\0';
+       int count = 0;
+       importargs_t args = { 0 };
+
+       args.paths = dirc;
+       args.path = dirv;
+       args.can_be_active = B_TRUE;
+
+       if ((sepp = strpbrk(*target, "/@")) != NULL) {
+               sep = *sepp;
+               *sepp = '\0';
+       }
+
+       pools = zpool_search_import(g_zfs, &args);
+
+       if (pools != NULL) {
+               nvpair_t *elem = NULL;
+               while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
+                       verify(nvpair_value_nvlist(elem, configp) == 0);
+                       if (pool_match(*configp, *target)) {
+                               count++;
+                               if (match != NULL) {
+                                       /* print previously found config */
+                                       if (name != NULL) {
+                                               (void) printf("%s\n", name);
+                                               dump_nvlist(match, 8);
+                                               name = NULL;
+                                       }
+                                       (void) printf("%s\n",
+                                           nvpair_name(elem));
+                                       dump_nvlist(*configp, 8);
+                               } else {
+                                       match = *configp;
+                                       name = nvpair_name(elem);
+                               }
+                       }
+               }
+       }
+       if (count > 1)
+               (void) fatal("\tMatched %d pools - use pool GUID "
+                   "instead of pool name or \n"
+                   "\tpool name part of a dataset name to select pool", count);
+
+       if (sepp)
+               *sepp = sep;
+       /*
+        * If pool GUID was specified for pool id, replace it with pool name
+        */
+       if (name && (strstr(*target, name) != *target)) {
+               int sz = 1 + strlen(name) + ((sepp) ? strlen(sepp) : 0);
+
+               *target = umem_alloc(sz, UMEM_NOFAIL);
+               (void) snprintf(*target, sz, "%s%s", name, sepp ? sepp : "");
+       }
+
+       *configp = name ? match : NULL;
+
+       return (name);
+}
+
+int
+main(int argc, char **argv)
+{
+       int i, c;
+       struct rlimit rl = { 1024, 1024 };
+       spa_t *spa = NULL;
+       objset_t *os = NULL;
+       int dump_all = 1;
+       int verbose = 0;
+       int error = 0;
+       char **searchdirs = NULL;
+       int nsearch = 0;
+       char *target;
+       nvlist_t *policy = NULL;
+       uint64_t max_txg = UINT64_MAX;
+       int flags = ZFS_IMPORT_MISSING_LOG;
+       int rewind = ZPOOL_NEVER_REWIND;
+       char *spa_config_path_env;
+       boolean_t target_is_spa = B_TRUE;
+
+       (void) setrlimit(RLIMIT_NOFILE, &rl);
+       (void) enable_extended_FILE_stdio(-1, -1);
+
+       dprintf_setup(&argc, argv);
+
+       /*
+        * If there is an environment variable SPA_CONFIG_PATH it overrides
+        * default spa_config_path setting. If -U flag is specified it will
+        * override this environment variable settings once again.
+        */
+       spa_config_path_env = getenv("SPA_CONFIG_PATH");
+       if (spa_config_path_env != NULL)
+               spa_config_path = spa_config_path_env;
+
+       while ((c = getopt(argc, argv,
+           "bcdhilmMI:suCDRSAFLXx:evp:t:U:PV")) != -1) {
+               switch (c) {
+               case 'b':
+               case 'c':
+               case 'd':
+               case 'h':
+               case 'i':
+               case 'l':
+               case 'm':
+               case 's':
+               case 'u':
+               case 'C':
+               case 'D':
+               case 'M':
+               case 'R':
+               case 'S':
+                       dump_opt[c]++;
+                       dump_all = 0;
+                       break;
+               case 'A':
+               case 'F':
+               case 'L':
+               case 'X':
+               case 'e':
+               case 'P':
+                       dump_opt[c]++;
+                       break;
+               case 'V':
+                       flags |= ZFS_IMPORT_VERBATIM;
+                       break;
+               case 'I':
+                       max_inflight = strtoull(optarg, NULL, 0);
+                       if (max_inflight == 0) {
+                               (void) fprintf(stderr, "maximum number "
+                                   "of inflight I/Os must be greater "
+                                   "than 0\n");
+                               usage();
+                       }
+                       break;
+               case 'p':
+                       if (searchdirs == NULL) {
+                               searchdirs = umem_alloc(sizeof (char *),
+                                   UMEM_NOFAIL);
+                       } else {
+                               char **tmp = umem_alloc((nsearch + 1) *
+                                   sizeof (char *), UMEM_NOFAIL);
+                               bcopy(searchdirs, tmp, nsearch *
+                                   sizeof (char *));
+                               umem_free(searchdirs,
+                                   nsearch * sizeof (char *));
+                               searchdirs = tmp;
+                       }
+                       searchdirs[nsearch++] = optarg;
+                       break;
+               case 'x':
+                       vn_dumpdir = optarg;
+                       break;
+               case 't':
+                       max_txg = strtoull(optarg, NULL, 0);
+                       if (max_txg < TXG_INITIAL) {
+                               (void) fprintf(stderr, "incorrect txg "
+                                   "specified: %s\n", optarg);
+                               usage();
+                       }
+                       break;
+               case 'U':
+                       spa_config_path = optarg;
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       if (!dump_opt['e'] && searchdirs != NULL) {
+               (void) fprintf(stderr, "-p option requires use of -e\n");
+               usage();
+       }
+
+#if defined(_LP64)
+       /*
+        * ZDB does not typically re-read blocks; therefore limit the ARC
+        * to 256 MB, which can be used entirely for metadata.
+        */
+       zfs_arc_max = zfs_arc_meta_limit = 256 * 1024 * 1024;
+#endif
+
+       /*
+        * "zdb -c" uses checksum-verifying scrub i/os which are async reads.
+        * "zdb -b" uses traversal prefetch which uses async reads.
+        * For good performance, let several of them be active at once.
+        */
+       zfs_vdev_async_read_max_active = 10;
+
+       kernel_init(FREAD);
+       if ((g_zfs = libzfs_init()) == NULL) {
+               (void) fprintf(stderr, "%s", libzfs_error_init(errno));
+               return (1);
+       }
+
+       if (dump_all)
+               verbose = MAX(verbose, 1);
+
+       for (c = 0; c < 256; c++) {
+               if (dump_all && !strchr("elAFLRSXP", c))
+                       dump_opt[c] = 1;
+               if (dump_opt[c])
+                       dump_opt[c] += verbose;
+       }
+
+       aok = (dump_opt['A'] == 1) || (dump_opt['A'] > 2);
+       zfs_recover = (dump_opt['A'] > 1);
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 2 && dump_opt['R'])
+               usage();
+       if (argc < 1) {
+               if (!dump_opt['e'] && dump_opt['C']) {
+                       dump_cachefile(spa_config_path);
+                       return (0);
+               }
+               usage();
+       }
+
+       if (dump_opt['l']) {
+               dump_label(argv[0]);
+               return (0);
+       }
+
+       if (dump_opt['X'] || dump_opt['F'])
+               rewind = ZPOOL_DO_REWIND |
+                   (dump_opt['X'] ? ZPOOL_EXTREME_REWIND : 0);
+
+       if (nvlist_alloc(&policy, NV_UNIQUE_NAME_TYPE, 0) != 0 ||
+           nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, max_txg) != 0 ||
+           nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind) != 0)
+               fatal("internal error: %s", strerror(ENOMEM));
+
+       error = 0;
+       target = argv[0];
+
+       if (dump_opt['e']) {
+               nvlist_t *cfg = NULL;
+               char *name = find_zpool(&target, &cfg, nsearch, searchdirs);
+
+               error = ENOENT;
+               if (name) {
+                       if (dump_opt['C'] > 1) {
+                               (void) printf("\nConfiguration for import:\n");
+                               dump_nvlist(cfg, 8);
+                       }
+                       if (nvlist_add_nvlist(cfg,
+                           ZPOOL_REWIND_POLICY, policy) != 0) {
+                               fatal("can't open '%s': %s",
+                                   target, strerror(ENOMEM));
+                       }
+                       error = spa_import(name, cfg, NULL, flags);
+               }
+       }
+
+       if (strpbrk(target, "/@") != NULL) {
+               size_t targetlen;
+
+               target_is_spa = B_FALSE;
+               targetlen = strlen(target);
+               if (targetlen && target[targetlen - 1] == '/')
+                       target[targetlen - 1] = '\0';
+       }
+
+       if (error == 0) {
+               if (target_is_spa || dump_opt['R']) {
+                       error = spa_open_rewind(target, &spa, FTAG, policy,
+                           NULL);
+                       if (error) {
+                               /*
+                                * If we're missing the log device then
+                                * try opening the pool after clearing the
+                                * log state.
+                                */
+                               mutex_enter(&spa_namespace_lock);
+                               if ((spa = spa_lookup(target)) != NULL &&
+                                   spa->spa_log_state == SPA_LOG_MISSING) {
+                                       spa->spa_log_state = SPA_LOG_CLEAR;
+                                       error = 0;
+                               }
+                               mutex_exit(&spa_namespace_lock);
+
+                               if (!error) {
+                                       error = spa_open_rewind(target, &spa,
+                                           FTAG, policy, NULL);
+                               }
+                       }
+               } else {
+                       error = dmu_objset_own(target, DMU_OST_ANY,
+                           B_TRUE, FTAG, &os);
+               }
+       }
+       nvlist_free(policy);
+
+       if (error)
+               fatal("can't open '%s': %s", target, strerror(error));
+
+       argv++;
+       argc--;
+       if (!dump_opt['R']) {
+               if (argc > 0) {
+                       zopt_objects = argc;
+                       zopt_object = calloc(zopt_objects, sizeof (uint64_t));
+                       for (i = 0; i < zopt_objects; i++) {
+                               errno = 0;
+                               zopt_object[i] = strtoull(argv[i], NULL, 0);
+                               if (zopt_object[i] == 0 && errno != 0)
+                                       fatal("bad number %s: %s",
+                                           argv[i], strerror(errno));
+                       }
+               }
+               if (os != NULL) {
+                       dump_dir(os);
+               } else if (zopt_objects > 0 && !dump_opt['m']) {
+                       dump_dir(spa->spa_meta_objset);
+               } else {
+                       dump_zpool(spa);
+               }
+       } else {
+               flagbits['b'] = ZDB_FLAG_PRINT_BLKPTR;
+               flagbits['c'] = ZDB_FLAG_CHECKSUM;
+               flagbits['d'] = ZDB_FLAG_DECOMPRESS;
+               flagbits['e'] = ZDB_FLAG_BSWAP;
+               flagbits['g'] = ZDB_FLAG_GBH;
+               flagbits['i'] = ZDB_FLAG_INDIRECT;
+               flagbits['p'] = ZDB_FLAG_PHYS;
+               flagbits['r'] = ZDB_FLAG_RAW;
+
+               for (i = 0; i < argc; i++)
+                       zdb_read_block(argv[i], spa);
+       }
+
+       (os != NULL) ? dmu_objset_disown(os, FTAG) : spa_close(spa, FTAG);
+
+       fuid_table_destroy();
+       sa_loaded = B_FALSE;
+
+       libzfs_fini(g_zfs);
+       kernel_fini();
+
+       return (0);
+}
diff --git a/zfs/cmd/zdb/zdb_il.c b/zfs/cmd/zdb/zdb_il.c
new file mode 100644 (file)
index 0000000..1501e87
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * 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.
+ * Copyright (c) 2012 Cyril Plisko. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * Print intent log header and statistics.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+
+extern uint8_t dump_opt[256];
+
+static char prefix[4] = "\t\t\t";
+
+static void
+print_log_bp(const blkptr_t *bp, const char *prefix)
+{
+       char blkbuf[BP_SPRINTF_LEN];
+
+       snprintf_blkptr(blkbuf, sizeof (blkbuf), bp);
+       (void) printf("%s%s\n", prefix, blkbuf);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_create(zilog_t *zilog, int txtype, lr_create_t *lr)
+{
+       time_t crtime = lr->lr_crtime[0];
+       char *name, *link;
+       lr_attr_t *lrattr;
+
+       name = (char *)(lr + 1);
+
+       if (lr->lr_common.lrc_txtype == TX_CREATE_ATTR ||
+           lr->lr_common.lrc_txtype == TX_MKDIR_ATTR) {
+               lrattr = (lr_attr_t *)(lr + 1);
+               name += ZIL_XVAT_SIZE(lrattr->lr_attr_masksize);
+       }
+
+       if (txtype == TX_SYMLINK) {
+               link = name + strlen(name) + 1;
+               (void) printf("%s%s -> %s\n", prefix, name, link);
+       } else if (txtype != TX_MKXATTR) {
+               (void) printf("%s%s\n", prefix, name);
+       }
+
+       (void) printf("%s%s", prefix, ctime(&crtime));
+       (void) printf("%sdoid %llu, foid %llu, slots %llu, mode %llo\n", prefix,
+           (u_longlong_t)lr->lr_doid,
+           (u_longlong_t)LR_FOID_GET_OBJ(lr->lr_foid),
+           (u_longlong_t)LR_FOID_GET_SLOTS(lr->lr_foid),
+           (longlong_t)lr->lr_mode);
+       (void) printf("%suid %llu, gid %llu, gen %llu, rdev 0x%llx\n", prefix,
+           (u_longlong_t)lr->lr_uid, (u_longlong_t)lr->lr_gid,
+           (u_longlong_t)lr->lr_gen, (u_longlong_t)lr->lr_rdev);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_remove(zilog_t *zilog, int txtype, lr_remove_t *lr)
+{
+       (void) printf("%sdoid %llu, name %s\n", prefix,
+           (u_longlong_t)lr->lr_doid, (char *)(lr + 1));
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_link(zilog_t *zilog, int txtype, lr_link_t *lr)
+{
+       (void) printf("%sdoid %llu, link_obj %llu, name %s\n", prefix,
+           (u_longlong_t)lr->lr_doid, (u_longlong_t)lr->lr_link_obj,
+           (char *)(lr + 1));
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_rename(zilog_t *zilog, int txtype, lr_rename_t *lr)
+{
+       char *snm = (char *)(lr + 1);
+       char *tnm = snm + strlen(snm) + 1;
+
+       (void) printf("%ssdoid %llu, tdoid %llu\n", prefix,
+           (u_longlong_t)lr->lr_sdoid, (u_longlong_t)lr->lr_tdoid);
+       (void) printf("%ssrc %s tgt %s\n", prefix, snm, tnm);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_write(zilog_t *zilog, int txtype, lr_write_t *lr)
+{
+       char *data, *dlimit;
+       blkptr_t *bp = &lr->lr_blkptr;
+       zbookmark_phys_t zb;
+       char *buf;
+       int verbose = MAX(dump_opt['d'], dump_opt['i']);
+       int error;
+
+       (void) printf("%sfoid %llu, offset %llx, length %llx\n", prefix,
+           (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_offset,
+           (u_longlong_t)lr->lr_length);
+
+       if (txtype == TX_WRITE2 || verbose < 5)
+               return;
+
+       if ((buf = malloc(SPA_MAXBLOCKSIZE)) == NULL)
+               return;
+
+       if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
+               (void) printf("%shas blkptr, %s\n", prefix,
+                   !BP_IS_HOLE(bp) &&
+                   bp->blk_birth >= spa_first_txg(zilog->zl_spa) ?
+                   "will claim" : "won't claim");
+               print_log_bp(bp, prefix);
+
+               if (BP_IS_HOLE(bp)) {
+                       (void) printf("\t\t\tLSIZE 0x%llx\n",
+                           (u_longlong_t)BP_GET_LSIZE(bp));
+                       bzero(buf, SPA_MAXBLOCKSIZE);
+                       (void) printf("%s<hole>\n", prefix);
+                       goto exit;
+               }
+               if (bp->blk_birth < zilog->zl_header->zh_claim_txg) {
+                       (void) printf("%s<block already committed>\n", prefix);
+                       goto exit;
+               }
+
+               SET_BOOKMARK(&zb, dmu_objset_id(zilog->zl_os),
+                   lr->lr_foid, ZB_ZIL_LEVEL,
+                   lr->lr_offset / BP_GET_LSIZE(bp));
+
+               error = zio_wait(zio_read(NULL, zilog->zl_spa,
+                   bp, buf, BP_GET_LSIZE(bp), NULL, NULL,
+                   ZIO_PRIORITY_SYNC_READ, ZIO_FLAG_CANFAIL, &zb));
+               if (error)
+                       goto exit;
+               data = buf;
+       } else {
+               data = (char *)(lr + 1);
+       }
+
+       dlimit = data + MIN(lr->lr_length,
+           (verbose < 6 ? 20 : SPA_MAXBLOCKSIZE));
+
+       (void) printf("%s", prefix);
+       while (data < dlimit) {
+               if (isprint(*data))
+                       (void) printf("%c ", *data);
+               else
+                       (void) printf("%2hhX", *data);
+               data++;
+       }
+       (void) printf("\n");
+exit:
+       free(buf);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_truncate(zilog_t *zilog, int txtype, lr_truncate_t *lr)
+{
+       (void) printf("%sfoid %llu, offset 0x%llx, length 0x%llx\n", prefix,
+           (u_longlong_t)lr->lr_foid, (longlong_t)lr->lr_offset,
+           (u_longlong_t)lr->lr_length);
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_setattr(zilog_t *zilog, int txtype, lr_setattr_t *lr)
+{
+       time_t atime = (time_t)lr->lr_atime[0];
+       time_t mtime = (time_t)lr->lr_mtime[0];
+
+       (void) printf("%sfoid %llu, mask 0x%llx\n", prefix,
+           (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_mask);
+
+       if (lr->lr_mask & AT_MODE) {
+               (void) printf("%sAT_MODE  %llo\n", prefix,
+                   (longlong_t)lr->lr_mode);
+       }
+
+       if (lr->lr_mask & AT_UID) {
+               (void) printf("%sAT_UID   %llu\n", prefix,
+                   (u_longlong_t)lr->lr_uid);
+       }
+
+       if (lr->lr_mask & AT_GID) {
+               (void) printf("%sAT_GID   %llu\n", prefix,
+                   (u_longlong_t)lr->lr_gid);
+       }
+
+       if (lr->lr_mask & AT_SIZE) {
+               (void) printf("%sAT_SIZE  %llu\n", prefix,
+                   (u_longlong_t)lr->lr_size);
+       }
+
+       if (lr->lr_mask & AT_ATIME) {
+               (void) printf("%sAT_ATIME %llu.%09llu %s", prefix,
+                   (u_longlong_t)lr->lr_atime[0],
+                   (u_longlong_t)lr->lr_atime[1],
+                   ctime(&atime));
+       }
+
+       if (lr->lr_mask & AT_MTIME) {
+               (void) printf("%sAT_MTIME %llu.%09llu %s", prefix,
+                   (u_longlong_t)lr->lr_mtime[0],
+                   (u_longlong_t)lr->lr_mtime[1],
+                   ctime(&mtime));
+       }
+}
+
+/* ARGSUSED */
+static void
+zil_prt_rec_acl(zilog_t *zilog, int txtype, lr_acl_t *lr)
+{
+       (void) printf("%sfoid %llu, aclcnt %llu\n", prefix,
+           (u_longlong_t)lr->lr_foid, (u_longlong_t)lr->lr_aclcnt);
+}
+
+typedef void (*zil_prt_rec_func_t)(zilog_t *, int, void *);
+typedef struct zil_rec_info {
+       zil_prt_rec_func_t      zri_print;
+       char                    *zri_name;
+       uint64_t                zri_count;
+} zil_rec_info_t;
+
+static zil_rec_info_t zil_rec_info[TX_MAX_TYPE] = {
+       { NULL,                 "Total              " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_CREATE          " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_MKDIR           " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_MKXATTR         " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_SYMLINK         " },
+       { (zil_prt_rec_func_t)zil_prt_rec_remove,       "TX_REMOVE          " },
+       { (zil_prt_rec_func_t)zil_prt_rec_remove,       "TX_RMDIR           " },
+       { (zil_prt_rec_func_t)zil_prt_rec_link,         "TX_LINK            " },
+       { (zil_prt_rec_func_t)zil_prt_rec_rename,       "TX_RENAME          " },
+       { (zil_prt_rec_func_t)zil_prt_rec_write,        "TX_WRITE           " },
+       { (zil_prt_rec_func_t)zil_prt_rec_truncate,     "TX_TRUNCATE        " },
+       { (zil_prt_rec_func_t)zil_prt_rec_setattr,      "TX_SETATTR         " },
+       { (zil_prt_rec_func_t)zil_prt_rec_acl,          "TX_ACL_V0          " },
+       { (zil_prt_rec_func_t)zil_prt_rec_acl,          "TX_ACL_ACL         " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_CREATE_ACL      " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_CREATE_ATTR     " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_CREATE_ACL_ATTR " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_MKDIR_ACL       " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_MKDIR_ATTR      " },
+       { (zil_prt_rec_func_t)zil_prt_rec_create,       "TX_MKDIR_ACL_ATTR  " },
+       { (zil_prt_rec_func_t)zil_prt_rec_write,        "TX_WRITE2          " },
+};
+
+/* ARGSUSED */
+static int
+print_log_record(zilog_t *zilog, lr_t *lr, void *arg, uint64_t claim_txg)
+{
+       int txtype;
+       int verbose = MAX(dump_opt['d'], dump_opt['i']);
+
+       /* reduce size of txtype to strip off TX_CI bit */
+       txtype = lr->lrc_txtype;
+
+       ASSERT(txtype != 0 && (uint_t)txtype < TX_MAX_TYPE);
+       ASSERT(lr->lrc_txg);
+
+       (void) printf("\t\t%s%s len %6llu, txg %llu, seq %llu\n",
+           (lr->lrc_txtype & TX_CI) ? "CI-" : "",
+           zil_rec_info[txtype].zri_name,
+           (u_longlong_t)lr->lrc_reclen,
+           (u_longlong_t)lr->lrc_txg,
+           (u_longlong_t)lr->lrc_seq);
+
+       if (txtype && verbose >= 3)
+               zil_rec_info[txtype].zri_print(zilog, txtype, lr);
+
+       zil_rec_info[txtype].zri_count++;
+       zil_rec_info[0].zri_count++;
+
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+print_log_block(zilog_t *zilog, blkptr_t *bp, void *arg, uint64_t claim_txg)
+{
+       char blkbuf[BP_SPRINTF_LEN + 10];
+       int verbose = MAX(dump_opt['d'], dump_opt['i']);
+       char *claim;
+
+       if (verbose <= 3)
+               return (0);
+
+       if (verbose >= 5) {
+               (void) strcpy(blkbuf, ", ");
+               snprintf_blkptr(blkbuf + strlen(blkbuf),
+                   sizeof (blkbuf) - strlen(blkbuf), bp);
+       } else {
+               blkbuf[0] = '\0';
+       }
+
+       if (claim_txg != 0)
+               claim = "already claimed";
+       else if (bp->blk_birth >= spa_first_txg(zilog->zl_spa))
+               claim = "will claim";
+       else
+               claim = "won't claim";
+
+       (void) printf("\tBlock seqno %llu, %s%s\n",
+           (u_longlong_t)bp->blk_cksum.zc_word[ZIL_ZC_SEQ], claim, blkbuf);
+
+       return (0);
+}
+
+static void
+print_log_stats(int verbose)
+{
+       int i, w, p10;
+
+       if (verbose > 3)
+               (void) printf("\n");
+
+       if (zil_rec_info[0].zri_count == 0)
+               return;
+
+       for (w = 1, p10 = 10; zil_rec_info[0].zri_count >= p10; p10 *= 10)
+               w++;
+
+       for (i = 0; i < TX_MAX_TYPE; i++)
+               if (zil_rec_info[i].zri_count || verbose >= 3)
+                       (void) printf("\t\t%s %*llu\n",
+                           zil_rec_info[i].zri_name, w,
+                           (u_longlong_t)zil_rec_info[i].zri_count);
+       (void) printf("\n");
+}
+
+/* ARGSUSED */
+void
+dump_intent_log(zilog_t *zilog)
+{
+       const zil_header_t *zh = zilog->zl_header;
+       int verbose = MAX(dump_opt['d'], dump_opt['i']);
+       int i;
+
+       if (BP_IS_HOLE(&zh->zh_log) || verbose < 1)
+               return;
+
+       (void) printf("\n    ZIL header: claim_txg %llu, "
+           "claim_blk_seq %llu, claim_lr_seq %llu",
+           (u_longlong_t)zh->zh_claim_txg,
+           (u_longlong_t)zh->zh_claim_blk_seq,
+           (u_longlong_t)zh->zh_claim_lr_seq);
+       (void) printf(" replay_seq %llu, flags 0x%llx\n",
+           (u_longlong_t)zh->zh_replay_seq, (u_longlong_t)zh->zh_flags);
+
+       for (i = 0; i < TX_MAX_TYPE; i++)
+               zil_rec_info[i].zri_count = 0;
+
+       if (verbose >= 2) {
+               (void) printf("\n");
+               (void) zil_parse(zilog, print_log_block, print_log_record, NULL,
+                   zh->zh_claim_txg);
+               print_log_stats(verbose);
+       }
+}
diff --git a/zfs/cmd/zed/Makefile.am b/zfs/cmd/zed/Makefile.am
new file mode 100644 (file)
index 0000000..d35dfc4
--- /dev/null
@@ -0,0 +1,86 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+EXTRA_DIST = zed.d/README
+
+sbin_PROGRAMS = zed
+
+ZED_SRC = \
+       zed.c \
+       zed.h \
+       zed_conf.c \
+       zed_conf.h \
+       zed_disk_event.c \
+       zed_disk_event.h \
+       zed_event.c \
+       zed_event.h \
+       zed_exec.c \
+       zed_exec.h \
+       zed_file.c \
+       zed_file.h \
+       zed_log.c \
+       zed_log.h \
+       zed_strings.c \
+       zed_strings.h
+
+FMA_SRC = \
+       agents/zfs_agents.h \
+       agents/zfs_diagnosis.c \
+       agents/zfs_mod.c \
+       agents/zfs_retire.c
+
+zed_SOURCES = $(ZED_SRC) $(FMA_SRC)
+
+zed_LDADD = \
+       $(top_builddir)/lib/libavl/libavl.la \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libspl/libspl.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+
+zedconfdir = $(sysconfdir)/zfs/zed.d
+
+dist_zedconf_DATA = \
+       zed.d/zed-functions.sh \
+       zed.d/zed.rc
+
+zedexecdir = $(libexecdir)/zfs/zed.d
+
+dist_zedexec_SCRIPTS = \
+       zed.d/all-debug.sh \
+       zed.d/all-syslog.sh \
+       zed.d/checksum-notify.sh \
+       zed.d/checksum-spare.sh \
+       zed.d/data-notify.sh \
+       zed.d/generic-notify.sh \
+       zed.d/io-notify.sh \
+       zed.d/io-spare.sh \
+       zed.d/resilver_finish-notify.sh \
+       zed.d/scrub_finish-notify.sh \
+       zed.d/statechange-led.sh \
+       zed.d/vdev_clear-led.sh
+
+zedconfdefaults = \
+       all-syslog.sh \
+       checksum-notify.sh \
+       checksum-spare.sh \
+       data-notify.sh \
+       io-notify.sh \
+       io-spare.sh \
+       resilver_finish-notify.sh \
+       scrub_finish-notify.sh \
+       statechange-blinkled.sh \
+       vdev_clear-blinkled.sh
+
+install-data-hook:
+       $(MKDIR_P) "$(DESTDIR)$(zedconfdir)"
+       for f in $(zedconfdefaults); do \
+         test -f "$(DESTDIR)$(zedconfdir)/$${f}" -o \
+              -L "$(DESTDIR)$(zedconfdir)/$${f}" || \
+           ln -s "$(zedexecdir)/$${f}" "$(DESTDIR)$(zedconfdir)"; \
+       done
+       chmod 0600 "$(DESTDIR)$(zedconfdir)/zed.rc"
diff --git a/zfs/cmd/zed/Makefile.in b/zfs/cmd/zed/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zed/agents/zfs_agents.h b/zfs/cmd/zed/agents/zfs_agents.h
new file mode 100644 (file)
index 0000000..4630f22
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2016, Intel Corporation.
+ */
+
+#ifndef        ZFS_AGENTS_H
+#define        ZFS_AGENTS_H
+
+#include <libzfs.h>
+#include <libnvpair.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Agents from ZFS FMA and syseventd - linked directly into ZED daemon binary
+ */
+
+/*
+ * ZFS Sysevent Linkable Module (SLM)
+ */
+extern int zfs_slm_init(libzfs_handle_t *zfs_hdl);
+extern void zfs_slm_fini(void);
+extern void zfs_slm_event(const char *, const char *, nvlist_t *);
+
+/*
+ * ZFS FMA Retire Agent
+ */
+extern int zfs_retire_init(libzfs_handle_t *zfs_hdl);
+extern void zfs_retire_fini(void);
+extern void zfs_retire_recv(nvlist_t *nvl, const char *class);
+
+/*
+ * ZFS FMA Diagnosis Engine
+ */
+extern int zfs_diagnosis_init(libzfs_handle_t *zfs_hdl);
+extern void zfs_diagnosis_fini(void);
+extern void zfs_diagnosis_recv(nvlist_t *nvl, const char *class);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !ZFS_AGENTS_H */
diff --git a/zfs/cmd/zed/agents/zfs_diagnosis.c b/zfs/cmd/zed/agents/zfs_diagnosis.c
new file mode 100644 (file)
index 0000000..4d534a4
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "zfs_agents.h"
+#include "../zed_log.h"
+
+
+/*ARGSUSED*/
+void
+zfs_diagnosis_recv(nvlist_t *nvl, const char *class)
+{
+}
+
+/*ARGSUSED*/
+int
+zfs_diagnosis_init(libzfs_handle_t *zfs_hdl)
+{
+       return (0);
+}
+
+/*ARGSUSED*/
+void
+zfs_diagnosis_fini(void)
+{
+}
diff --git a/zfs/cmd/zed/agents/zfs_mod.c b/zfs/cmd/zed/agents/zfs_mod.c
new file mode 100644 (file)
index 0000000..a073956
--- /dev/null
@@ -0,0 +1,921 @@
+/*
+ * 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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2016, Intel Corporation.
+ */
+
+/*
+ * ZFS syseventd module.
+ *
+ * file origin: openzfs/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c
+ *
+ * The purpose of this module is to identify when devices are added to the
+ * system, and appropriately online or replace the affected vdevs.
+ *
+ * When a device is added to the system:
+ *
+ *     1. Search for any vdevs whose devid matches that of the newly added
+ *        device.
+ *
+ *     2. If no vdevs are found, then search for any vdevs whose udev path
+ *        matches that of the new device.
+ *
+ *     3. If no vdevs match by either method, then ignore the event.
+ *
+ *     4. Attempt to online the device with a flag to indicate that it should
+ *        be unspared when resilvering completes.  If this succeeds, then the
+ *        same device was inserted and we should continue normally.
+ *
+ *     5. If the pool does not have the 'autoreplace' property set, attempt to
+ *        online the device again without the unspare flag, which will
+ *        generate a FMA fault.
+ *
+ *     6. If the pool has the 'autoreplace' property set, and the matching vdev
+ *        is a whole disk, then label the new disk and attempt a 'zpool
+ *        replace'.
+ *
+ * The module responds to EC_DEV_ADD events.  The special ESC_ZFS_VDEV_CHECK
+ * event indicates that a device failed to open during pool load, but the
+ * autoreplace property was set.  In this case, we deferred the associated
+ * FMA fault until our module had a chance to process the autoreplace logic.
+ * If the device could not be replaced, then the second online attempt will
+ * trigger the FMA fault that we skipped earlier.
+ *
+ * ZFS on Linux porting notes:
+ *     In lieu of a thread pool, just spawn a thread on demmand.
+ *     Linux udev provides a disk insert for both the disk and the partition
+ *
+ */
+
+#include <ctype.h>
+#include <devid.h>
+#include <fcntl.h>
+#include <libnvpair.h>
+#include <libzfs.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/list.h>
+#include <sys/sunddi.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dev.h>
+#include <pthread.h>
+#include <unistd.h>
+#include "zfs_agents.h"
+#include "../zed_log.h"
+
+#define        DEV_BYID_PATH   "/dev/disk/by-id/"
+#define        DEV_BYPATH_PATH "/dev/disk/by-path/"
+
+typedef void (*zfs_process_func_t)(zpool_handle_t *, nvlist_t *, boolean_t);
+
+libzfs_handle_t *g_zfshdl;
+list_t g_pool_list;    /* list of unavailable pools at initialization */
+list_t g_device_list;  /* list of disks with asynchronous label request */
+boolean_t g_enumeration_done;
+pthread_t g_zfs_tid;
+
+typedef struct unavailpool {
+       zpool_handle_t  *uap_zhp;
+       pthread_t       uap_enable_tid; /* dataset enable thread if activated */
+       list_node_t     uap_node;
+} unavailpool_t;
+
+typedef struct pendingdev {
+       char            pd_physpath[128];
+       list_node_t     pd_node;
+} pendingdev_t;
+
+static int
+zfs_toplevel_state(zpool_handle_t *zhp)
+{
+       nvlist_t *nvroot;
+       vdev_stat_t *vs;
+       unsigned int c;
+
+       verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
+           ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+       verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &c) == 0);
+       return (vs->vs_state);
+}
+
+static int
+zfs_unavail_pool(zpool_handle_t *zhp, void *data)
+{
+       zed_log_msg(LOG_INFO, "zfs_unavail_pool: examining '%s' (state %d)",
+           zpool_get_name(zhp), (int)zfs_toplevel_state(zhp));
+
+       if (zfs_toplevel_state(zhp) < VDEV_STATE_DEGRADED) {
+               unavailpool_t *uap;
+               uap = malloc(sizeof (unavailpool_t));
+               uap->uap_zhp = zhp;
+               uap->uap_enable_tid = 0;
+               list_insert_tail((list_t *)data, uap);
+       } else {
+               zpool_close(zhp);
+       }
+       return (0);
+}
+
+/*
+ * Two stage replace on Linux
+ * since we get disk notifications
+ * we can wait for partitioned disk slice to show up!
+ *
+ * First stage tags the disk, initiates async partitioning, and returns
+ * Second stage finds the tag and proceeds to ZFS labeling/replace
+ *
+ * disk-add --> label-disk + tag-disk --> partition-add --> zpool_vdev_attach
+ *
+ * 1. physical match with no fs, no partition
+ *     tag it top, partition disk
+ *
+ * 2. physical match again, see partion and tag
+ *
+ */
+
+/*
+ * The device associated with the given vdev (either by devid or physical path)
+ * has been added to the system.  If 'isdisk' is set, then we only attempt a
+ * replacement if it's a whole disk.  This also implies that we should label the
+ * disk first.
+ *
+ * First, we attempt to online the device (making sure to undo any spare
+ * operation when finished).  If this succeeds, then we're done.  If it fails,
+ * and the new state is VDEV_CANT_OPEN, it indicates that the device was opened,
+ * but that the label was not what we expected.  If the 'autoreplace' property
+ * is not set, then we relabel the disk (if specified), and attempt a 'zpool
+ * replace'.  If the online is successful, but the new state is something else
+ * (REMOVED or FAULTED), it indicates that we're out of sync or in some sort of
+ * race, and we should avoid attempting to relabel the disk.
+ *
+ * Also can arrive here from a ESC_ZFS_VDEV_CHECK event
+ */
+static void
+zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled)
+{
+       char *path;
+       vdev_state_t newstate;
+       nvlist_t *nvroot, *newvd;
+       pendingdev_t *device;
+       uint64_t wholedisk = 0ULL;
+       uint64_t offline = 0ULL;
+       uint64_t guid = 0ULL;
+       char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL;
+       char rawpath[PATH_MAX], fullpath[PATH_MAX];
+       char devpath[PATH_MAX];
+       int ret;
+       int is_dm = 0;
+       uint_t c;
+       vdev_stat_t *vs;
+
+       if (nvlist_lookup_string(vdev, ZPOOL_CONFIG_PATH, &path) != 0)
+               return;
+
+       /* Skip healthy disks */
+       verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &c) == 0);
+       if (vs->vs_state == VDEV_STATE_HEALTHY) {
+               zed_log_msg(LOG_INFO, "%s: %s is already healthy, skip it.",
+                   __func__, path);
+               return;
+       }
+
+       (void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_PHYS_PATH, &physpath);
+       (void) nvlist_lookup_string(vdev, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
+           &enc_sysfs_path);
+       (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
+       (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline);
+       (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid);
+
+       if (offline)
+               return;  /* don't intervene if it was taken offline */
+
+#ifdef HAVE_LIBDEVMAPPER
+       is_dm = zfs_dev_is_dm(path);
+#endif
+       zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'"
+           " wholedisk %d, dm %d (%llu)", zpool_get_name(zhp), path,
+           physpath ? physpath : "NULL", wholedisk, is_dm,
+           (long long unsigned int)guid);
+
+       /*
+        * The VDEV guid is preferred for identification (gets passed in path)
+        */
+       if (guid != 0) {
+               (void) snprintf(fullpath, sizeof (fullpath), "%llu",
+                   (long long unsigned int)guid);
+       } else {
+               /*
+                * otherwise use path sans partition suffix for whole disks
+                */
+               (void) strlcpy(fullpath, path, sizeof (fullpath));
+               if (wholedisk) {
+                       char *spath = zfs_strip_partition(fullpath);
+                       if (!spath) {
+                               zed_log_msg(LOG_INFO, "%s: Can't alloc",
+                                   __func__);
+                               return;
+                       }
+
+                       (void) strlcpy(fullpath, spath, sizeof (fullpath));
+                       free(spath);
+               }
+       }
+
+       /*
+        * Attempt to online the device.
+        */
+       if (zpool_vdev_online(zhp, fullpath,
+           ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 &&
+           (newstate == VDEV_STATE_HEALTHY ||
+           newstate == VDEV_STATE_DEGRADED)) {
+               zed_log_msg(LOG_INFO, "  zpool_vdev_online: vdev %s is %s",
+                   fullpath, (newstate == VDEV_STATE_HEALTHY) ?
+                   "HEALTHY" : "DEGRADED");
+               return;
+       }
+
+       /*
+        * If the pool doesn't have the autoreplace property set, then attempt
+        * a true online (without the unspare flag), which will trigger a FMA
+        * fault.
+        */
+       if (!is_dm && (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) ||
+           !wholedisk || physpath == NULL)) {
+               (void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
+                   &newstate);
+               zed_log_msg(LOG_INFO, "  zpool_vdev_online: %s FORCEFAULT (%s)",
+                   fullpath, libzfs_error_description(g_zfshdl));
+               return;
+       }
+
+       /*
+        * convert physical path into its current device node
+        */
+       (void) snprintf(rawpath, sizeof (rawpath), "%s%s", DEV_BYPATH_PATH,
+           physpath);
+       if (realpath(rawpath, devpath) == NULL && !is_dm) {
+               zed_log_msg(LOG_INFO, "  realpath: %s failed (%s)",
+                   rawpath, strerror(errno));
+
+               (void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT,
+                   &newstate);
+
+               zed_log_msg(LOG_INFO, "  zpool_vdev_online: %s FORCEFAULT (%s)",
+                   fullpath, libzfs_error_description(g_zfshdl));
+               return;
+       }
+
+       if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL)) {
+               zed_log_msg(LOG_INFO, "%s: Autoreplace is not enabled on this"
+                   " pool, ignore disk.", __func__);
+               return;
+       }
+
+       /* Only autoreplace bad disks */
+       if ((vs->vs_state != VDEV_STATE_DEGRADED) &&
+           (vs->vs_state != VDEV_STATE_FAULTED) &&
+           (vs->vs_state != VDEV_STATE_CANT_OPEN)) {
+               return;
+       }
+
+       nvlist_lookup_string(vdev, "new_devid", &new_devid);
+
+       if (is_dm) {
+               /* Don't label device mapper or multipath disks. */
+       } else if (!labeled) {
+               /*
+                * we're auto-replacing a raw disk, so label it first
+                */
+               char *leafname;
+
+               /*
+                * If this is a request to label a whole disk, then attempt to
+                * write out the label.  Before we can label the disk, we need
+                * to map the physical string that was matched on to the under
+                * lying device node.
+                *
+                * If any part of this process fails, then do a force online
+                * to trigger a ZFS fault for the device (and any hot spare
+                * replacement).
+                */
+               leafname = strrchr(devpath, '/') + 1;
+
+               /*
+                * If this is a request to label a whole disk, then attempt to
+                * write out the label.
+                */
+               if (zpool_label_disk(g_zfshdl, zhp, leafname) != 0) {
+                       zed_log_msg(LOG_INFO, "  zpool_label_disk: could not "
+                           "label '%s' (%s)", leafname,
+                           libzfs_error_description(g_zfshdl));
+
+                       (void) zpool_vdev_online(zhp, fullpath,
+                           ZFS_ONLINE_FORCEFAULT, &newstate);
+                       return;
+               }
+
+               /*
+                * The disk labeling is asynchronous on Linux. Just record
+                * this label request and return as there will be another
+                * disk add event for the partition after the labeling is
+                * completed.
+                */
+               device = malloc(sizeof (pendingdev_t));
+               (void) strlcpy(device->pd_physpath, physpath,
+                   sizeof (device->pd_physpath));
+               list_insert_tail(&g_device_list, device);
+
+               zed_log_msg(LOG_INFO, "  zpool_label_disk: async '%s' (%llu)",
+                   leafname, (u_longlong_t) guid);
+
+               return; /* resumes at EC_DEV_ADD.ESC_DISK for partition */
+
+       } else /* labeled */ {
+               boolean_t found = B_FALSE;
+               /*
+                * match up with request above to label the disk
+                */
+               for (device = list_head(&g_device_list); device != NULL;
+                   device = list_next(&g_device_list, device)) {
+                       if (strcmp(physpath, device->pd_physpath) == 0) {
+                               list_remove(&g_device_list, device);
+                               free(device);
+                               found = B_TRUE;
+                               break;
+                       }
+               }
+               if (!found) {
+                       /* unexpected partition slice encountered */
+                       (void) zpool_vdev_online(zhp, fullpath,
+                           ZFS_ONLINE_FORCEFAULT, &newstate);
+                       return;
+               }
+
+               zed_log_msg(LOG_INFO, "  zpool_label_disk: resume '%s' (%llu)",
+                   physpath, (u_longlong_t) guid);
+
+               (void) snprintf(devpath, sizeof (devpath), "%s%s",
+                   DEV_BYID_PATH, new_devid);
+       }
+
+       /*
+        * Construct the root vdev to pass to zpool_vdev_attach().  While adding
+        * the entire vdev structure is harmless, we construct a reduced set of
+        * path/physpath/wholedisk to keep it simple.
+        */
+       if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0) {
+               zed_log_msg(LOG_WARNING, "zfs_mod: nvlist_alloc out of memory");
+               return;
+       }
+       if (nvlist_alloc(&newvd, NV_UNIQUE_NAME, 0) != 0) {
+               zed_log_msg(LOG_WARNING, "zfs_mod: nvlist_alloc out of memory");
+               nvlist_free(nvroot);
+               return;
+       }
+
+       if (nvlist_add_string(newvd, ZPOOL_CONFIG_TYPE, VDEV_TYPE_DISK) != 0 ||
+           nvlist_add_string(newvd, ZPOOL_CONFIG_PATH, path) != 0 ||
+           nvlist_add_string(newvd, ZPOOL_CONFIG_DEVID, new_devid) != 0 ||
+           (physpath != NULL && nvlist_add_string(newvd,
+           ZPOOL_CONFIG_PHYS_PATH, physpath) != 0) ||
+           nvlist_add_string(newvd, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
+           enc_sysfs_path) != 0 ||
+           nvlist_add_uint64(newvd, ZPOOL_CONFIG_WHOLE_DISK, wholedisk) != 0 ||
+           nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) != 0 ||
+           nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN, &newvd,
+           1) != 0) {
+               zed_log_msg(LOG_WARNING, "zfs_mod: unable to add nvlist pairs");
+               nvlist_free(newvd);
+               nvlist_free(nvroot);
+               return;
+       }
+
+       nvlist_free(newvd);
+
+       /*
+        * auto replace a leaf disk at same physical location
+        */
+       ret = zpool_vdev_attach(zhp, fullpath, path, nvroot, B_TRUE);
+
+       zed_log_msg(LOG_INFO, "  zpool_vdev_replace: %s with %s (%s)",
+           fullpath, path, (ret == 0) ? "no errors" :
+           libzfs_error_description(g_zfshdl));
+
+       nvlist_free(nvroot);
+}
+
+/*
+ * Utility functions to find a vdev matching given criteria.
+ */
+typedef struct dev_data {
+       const char              *dd_compare;
+       const char              *dd_prop;
+       zfs_process_func_t      dd_func;
+       boolean_t               dd_found;
+       boolean_t               dd_islabeled;
+       uint64_t                dd_pool_guid;
+       uint64_t                dd_vdev_guid;
+       const char              *dd_new_devid;
+} dev_data_t;
+
+static void
+zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data)
+{
+       dev_data_t *dp = data;
+       char *path = NULL;
+       uint_t c, children;
+       nvlist_t **child;
+
+       /*
+        * First iterate over any children.
+        */
+       if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++)
+                       zfs_iter_vdev(zhp, child[c], data);
+               return;
+       }
+
+       /* once a vdev was matched and processed there is nothing left to do */
+       if (dp->dd_found)
+               return;
+
+       /*
+        * Match by GUID if available otherwise fallback to devid or physical
+        */
+       if (dp->dd_vdev_guid != 0) {
+               uint64_t guid;
+
+               if (nvlist_lookup_uint64(nvl, ZPOOL_CONFIG_GUID,
+                   &guid) != 0 || guid != dp->dd_vdev_guid) {
+                       return;
+               }
+               zed_log_msg(LOG_INFO, "  zfs_iter_vdev: matched on %llu", guid);
+               dp->dd_found = B_TRUE;
+
+       } else if (dp->dd_compare != NULL) {
+               /*
+                * NOTE: On Linux there is an event for partition, so unlike
+                * illumos, substring matching is not required to accomodate
+                * the partition suffix. An exact match will be present in
+                * the dp->dd_compare value.
+                */
+               if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 ||
+                   strcmp(dp->dd_compare, path) != 0)
+                       return;
+
+               zed_log_msg(LOG_INFO, "  zfs_iter_vdev: matched %s on %s",
+                   dp->dd_prop, path);
+               dp->dd_found = B_TRUE;
+
+               /* pass the new devid for use by replacing code */
+               if (dp->dd_new_devid != NULL) {
+                       (void) nvlist_add_string(nvl, "new_devid",
+                           dp->dd_new_devid);
+               }
+       }
+
+       (dp->dd_func)(zhp, nvl, dp->dd_islabeled);
+}
+
+static void *
+zfs_enable_ds(void *arg)
+{
+       unavailpool_t *pool = (unavailpool_t *)arg;
+
+       assert(pool->uap_enable_tid = pthread_self());
+
+       (void) zpool_enable_datasets(pool->uap_zhp, NULL, 0);
+       zpool_close(pool->uap_zhp);
+       pool->uap_zhp = NULL;
+
+       /* Note: zfs_slm_fini() will cleanup this pool entry on exit */
+       return (NULL);
+}
+
+static int
+zfs_iter_pool(zpool_handle_t *zhp, void *data)
+{
+       nvlist_t *config, *nvl;
+       dev_data_t *dp = data;
+       uint64_t pool_guid;
+       unavailpool_t *pool;
+
+       zed_log_msg(LOG_INFO, "zfs_iter_pool: evaluating vdevs on %s (by %s)",
+           zpool_get_name(zhp), dp->dd_vdev_guid ? "GUID" : dp->dd_prop);
+
+       /*
+        * For each vdev in this pool, look for a match to apply dd_func
+        */
+       if ((config = zpool_get_config(zhp, NULL)) != NULL) {
+               if (dp->dd_pool_guid == 0 ||
+                   (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+                   &pool_guid) == 0 && pool_guid == dp->dd_pool_guid)) {
+                       (void) nvlist_lookup_nvlist(config,
+                           ZPOOL_CONFIG_VDEV_TREE, &nvl);
+                       zfs_iter_vdev(zhp, nvl, data);
+               }
+       }
+
+       /*
+        * if this pool was originally unavailable,
+        * then enable its datasets asynchronously
+        */
+       if (g_enumeration_done)  {
+               for (pool = list_head(&g_pool_list); pool != NULL;
+                   pool = list_next(&g_pool_list, pool)) {
+
+                       if (pool->uap_enable_tid != 0)
+                               continue;       /* entry already processed */
+                       if (strcmp(zpool_get_name(zhp),
+                           zpool_get_name(pool->uap_zhp)))
+                               continue;
+                       if (zfs_toplevel_state(zhp) >= VDEV_STATE_DEGRADED) {
+                               /* send to a background thread; keep on list */
+                               (void) pthread_create(&pool->uap_enable_tid,
+                                   NULL, zfs_enable_ds, pool);
+                               break;
+                       }
+               }
+       }
+
+       zpool_close(zhp);
+       return (dp->dd_found);  /* cease iteration after a match */
+}
+
+/*
+ * Given a physical device location, iterate over all
+ * (pool, vdev) pairs which correspond to that location.
+ */
+static boolean_t
+devphys_iter(const char *physical, const char *devid, zfs_process_func_t func,
+    boolean_t is_slice)
+{
+       dev_data_t data = { 0 };
+
+       data.dd_compare = physical;
+       data.dd_func = func;
+       data.dd_prop = ZPOOL_CONFIG_PHYS_PATH;
+       data.dd_found = B_FALSE;
+       data.dd_islabeled = is_slice;
+       data.dd_new_devid = devid;      /* used by auto replace code */
+
+       (void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
+
+       return (data.dd_found);
+}
+
+/*
+ * Given a device identifier, find any vdevs with a matching devid.
+ * On Linux we can match devid directly which is always a whole disk.
+ */
+static boolean_t
+devid_iter(const char *devid, zfs_process_func_t func, boolean_t is_slice)
+{
+       dev_data_t data = { 0 };
+
+       data.dd_compare = devid;
+       data.dd_func = func;
+       data.dd_prop = ZPOOL_CONFIG_DEVID;
+       data.dd_found = B_FALSE;
+       data.dd_islabeled = is_slice;
+       data.dd_new_devid = devid;
+
+       (void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
+
+       return (data.dd_found);
+}
+
+/*
+ * Handle a EC_DEV_ADD.ESC_DISK event.
+ *
+ * illumos
+ *     Expects: DEV_PHYS_PATH string in schema
+ *     Matches: vdev's ZPOOL_CONFIG_PHYS_PATH or ZPOOL_CONFIG_DEVID
+ *
+ *      path: '/dev/dsk/c0t1d0s0' (persistent)
+ *     devid: 'id1,sd@SATA_____Hitachi_HDS72101______JP2940HZ3H74MC/a'
+ * phys_path: '/pci@0,0/pci103c,1609@11/disk@1,0:a'
+ *
+ * linux
+ *     provides: DEV_PHYS_PATH and DEV_IDENTIFIER strings in schema
+ *     Matches: vdev's ZPOOL_CONFIG_PHYS_PATH or ZPOOL_CONFIG_DEVID
+ *
+ *      path: '/dev/sdc1' (not persistent)
+ *     devid: 'ata-SAMSUNG_HD204UI_S2HGJD2Z805891-part1'
+ * phys_path: 'pci-0000:04:00.0-sas-0x4433221106000000-lun-0'
+ */
+static int
+zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi)
+{
+       char *devpath = NULL, *devid;
+       boolean_t is_slice;
+
+       /*
+        * Expecting a devid string and an optional physical location
+        */
+       if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0)
+               return (-1);
+
+       (void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath);
+
+       is_slice = (nvlist_lookup_boolean(nvl, DEV_IS_PART) == 0);
+
+       zed_log_msg(LOG_INFO, "zfs_deliver_add: adding %s (%s) (is_slice %d)",
+           devid, devpath ? devpath : "NULL", is_slice);
+
+       /*
+        * Iterate over all vdevs looking for a match in the folllowing order:
+        * 1. ZPOOL_CONFIG_DEVID (identifies the unique disk)
+        * 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location).
+        *
+        * For disks, we only want to pay attention to vdevs marked as whole
+        * disks.  For multipath devices does whole disk apply? (TBD).
+        */
+       if (!devid_iter(devid, zfs_process_add, is_slice) && devpath != NULL) {
+               if (!is_slice) {
+                       (void) devphys_iter(devpath, devid, zfs_process_add,
+                           is_slice);
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * Called when we receive a VDEV_CHECK event, which indicates a device could not
+ * be opened during initial pool open, but the autoreplace property was set on
+ * the pool.  In this case, we treat it as if it were an add event.
+ */
+static int
+zfs_deliver_check(nvlist_t *nvl)
+{
+       dev_data_t data = { 0 };
+
+       if (nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID,
+           &data.dd_pool_guid) != 0 ||
+           nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID,
+           &data.dd_vdev_guid) != 0 ||
+           data.dd_vdev_guid == 0)
+               return (0);
+
+       zed_log_msg(LOG_INFO, "zfs_deliver_check: pool '%llu', vdev %llu",
+           data.dd_pool_guid, data.dd_vdev_guid);
+
+       data.dd_func = zfs_process_add;
+
+       (void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);
+
+       return (0);
+}
+
+static int
+zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
+{
+       char *devname = data;
+       boolean_t avail_spare, l2cache;
+       vdev_state_t newstate;
+       nvlist_t *tgt;
+
+       zed_log_msg(LOG_INFO, "zfsdle_vdev_online: searching for '%s' in '%s'",
+           devname, zpool_get_name(zhp));
+
+       if ((tgt = zpool_find_vdev_by_physpath(zhp, devname,
+           &avail_spare, &l2cache, NULL)) != NULL) {
+               char *path, fullpath[MAXPATHLEN];
+               uint64_t wholedisk = 0ULL;
+
+               verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH,
+                   &path) == 0);
+               verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
+                   &wholedisk) == 0);
+
+               (void) strlcpy(fullpath, path, sizeof (fullpath));
+               if (wholedisk) {
+                       char *spath = zfs_strip_partition(fullpath);
+                       if (!spath) {
+                               zed_log_msg(LOG_INFO, "%s: Can't alloc",
+                                   __func__);
+                               return (0);
+                       }
+
+                       (void) strlcpy(fullpath, spath, sizeof (fullpath));
+                       free(spath);
+
+                       /*
+                        * We need to reopen the pool associated with this
+                        * device so that the kernel can update the size
+                        * of the expanded device.
+                        */
+                       (void) zpool_reopen(zhp);
+               }
+
+               if (zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
+                       zed_log_msg(LOG_INFO, "zfsdle_vdev_online: setting "
+                           "device '%s' to ONLINE state in pool '%s'",
+                           fullpath, zpool_get_name(zhp));
+                       if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL)
+                               (void) zpool_vdev_online(zhp, fullpath, 0,
+                                   &newstate);
+               }
+               zpool_close(zhp);
+               return (1);
+       }
+       zpool_close(zhp);
+       return (0);
+}
+
+/*
+ * This function handles the ESC_DEV_DLE event.
+ */
+static int
+zfs_deliver_dle(nvlist_t *nvl)
+{
+       char *devname;
+
+       if (nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devname) != 0) {
+               zed_log_msg(LOG_INFO, "zfs_deliver_event: no physpath");
+               return (-1);
+       }
+
+       if (zpool_iter(g_zfshdl, zfsdle_vdev_online, devname) != 1) {
+               zed_log_msg(LOG_INFO, "zfs_deliver_event: device '%s' not "
+                   "found", devname);
+               return (1);
+       }
+       return (0);
+}
+
+/*
+ * syseventd daemon module event handler
+ *
+ * Handles syseventd daemon zfs device related events:
+ *
+ *     EC_DEV_ADD.ESC_DISK
+ *     EC_DEV_STATUS.ESC_DEV_DLE
+ *     EC_ZFS.ESC_ZFS_VDEV_CHECK
+ *
+ * Note: assumes only one thread active at a time (not thread safe)
+ */
+static int
+zfs_slm_deliver_event(const char *class, const char *subclass, nvlist_t *nvl)
+{
+       int ret;
+       boolean_t is_lofi = B_FALSE, is_check = B_FALSE, is_dle = B_FALSE;
+
+       if (strcmp(class, EC_DEV_ADD) == 0) {
+               /*
+                * We're mainly interested in disk additions, but we also listen
+                * for new loop devices, to allow for simplified testing.
+                */
+               if (strcmp(subclass, ESC_DISK) == 0)
+                       is_lofi = B_FALSE;
+               else if (strcmp(subclass, ESC_LOFI) == 0)
+                       is_lofi = B_TRUE;
+               else
+                       return (0);
+
+               is_check = B_FALSE;
+       } else if (strcmp(class, EC_ZFS) == 0 &&
+           strcmp(subclass, ESC_ZFS_VDEV_CHECK) == 0) {
+               /*
+                * This event signifies that a device failed to open
+                * during pool load, but the 'autoreplace' property was
+                * set, so we should pretend it's just been added.
+                */
+               is_check = B_TRUE;
+       } else if (strcmp(class, EC_DEV_STATUS) == 0 &&
+           strcmp(subclass, ESC_DEV_DLE) == 0) {
+               is_dle = B_TRUE;
+       } else {
+               return (0);
+       }
+
+       if (is_dle)
+               ret = zfs_deliver_dle(nvl);
+       else if (is_check)
+               ret = zfs_deliver_check(nvl);
+       else
+               ret = zfs_deliver_add(nvl, is_lofi);
+
+       return (ret);
+}
+
+/*ARGSUSED*/
+static void *
+zfs_enum_pools(void *arg)
+{
+       (void) zpool_iter(g_zfshdl, zfs_unavail_pool, (void *)&g_pool_list);
+       /*
+        * Linux - instead of using a thread pool, each list entry
+        * will spawn a thread when an unavailable pool transitions
+        * to available. zfs_slm_fini will wait for these threads.
+        */
+       g_enumeration_done = B_TRUE;
+       return (NULL);
+}
+
+/*
+ * called from zed daemon at startup
+ *
+ * sent messages from zevents or udev monitor
+ *
+ * For now, each agent has it's own libzfs instance
+ */
+int
+zfs_slm_init(libzfs_handle_t *zfs_hdl)
+{
+       if ((g_zfshdl = libzfs_init()) == NULL)
+               return (-1);
+
+       /*
+        * collect a list of unavailable pools (asynchronously,
+        * since this can take a while)
+        */
+       list_create(&g_pool_list, sizeof (struct unavailpool),
+           offsetof(struct unavailpool, uap_node));
+
+       if (pthread_create(&g_zfs_tid, NULL, zfs_enum_pools, NULL) != 0) {
+               list_destroy(&g_pool_list);
+               return (-1);
+       }
+
+       list_create(&g_device_list, sizeof (struct pendingdev),
+           offsetof(struct pendingdev, pd_node));
+
+       return (0);
+}
+
+void
+zfs_slm_fini()
+{
+       unavailpool_t *pool;
+       pendingdev_t *device;
+
+       /* wait for zfs_enum_pools thread to complete */
+       (void) pthread_join(g_zfs_tid, NULL);
+
+       while ((pool = (list_head(&g_pool_list))) != NULL) {
+               /*
+                * each pool entry has two possibilities
+                * 1. was made available (so wait for zfs_enable_ds thread)
+                * 2. still unavailable (just close the pool)
+                */
+               if (pool->uap_enable_tid)
+                       (void) pthread_join(pool->uap_enable_tid, NULL);
+               else if (pool->uap_zhp != NULL)
+                       zpool_close(pool->uap_zhp);
+
+               list_remove(&g_pool_list, pool);
+               free(pool);
+       }
+       list_destroy(&g_pool_list);
+
+       while ((device = (list_head(&g_device_list))) != NULL) {
+               list_remove(&g_device_list, device);
+               free(device);
+       }
+       list_destroy(&g_device_list);
+
+       libzfs_fini(g_zfshdl);
+}
+
+void
+zfs_slm_event(const char *class, const char *subclass, nvlist_t *nvl)
+{
+       static pthread_mutex_t serialize = PTHREAD_MUTEX_INITIALIZER;
+
+       /*
+        * Serialize incoming events from zfs or libudev sources
+        */
+       (void) pthread_mutex_lock(&serialize);
+       zed_log_msg(LOG_INFO, "zfs_slm_event: %s.%s", class, subclass);
+       (void) zfs_slm_deliver_event(class, subclass, nvl);
+       (void) pthread_mutex_unlock(&serialize);
+}
diff --git a/zfs/cmd/zed/agents/zfs_retire.c b/zfs/cmd/zed/agents/zfs_retire.c
new file mode 100644 (file)
index 0000000..64930a1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "zfs_agents.h"
+#include "../zed_log.h"
+
+/*ARGSUSED*/
+void
+zfs_retire_recv(nvlist_t *nvl, const char *class)
+{
+}
+
+/*ARGSUSED*/
+int
+zfs_retire_init(libzfs_handle_t *zfs_hdl)
+{
+       return (0);
+}
+
+/*ARGSUSED*/
+void
+zfs_retire_fini(void)
+{
+}
diff --git a/zfs/cmd/zed/zed.c b/zfs/cmd/zed/zed.c
new file mode 100644 (file)
index 0000000..55ab68c
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "zed.h"
+#include "zed_conf.h"
+#include "zed_event.h"
+#include "zed_file.h"
+#include "zed_log.h"
+
+static volatile sig_atomic_t _got_exit = 0;
+static volatile sig_atomic_t _got_hup = 0;
+
+/*
+ * Signal handler for SIGINT & SIGTERM.
+ */
+static void
+_exit_handler(int signum)
+{
+       _got_exit = 1;
+}
+
+/*
+ * Signal handler for SIGHUP.
+ */
+static void
+_hup_handler(int signum)
+{
+       _got_hup = 1;
+}
+
+/*
+ * Register signal handlers.
+ */
+static void
+_setup_sig_handlers(void)
+{
+       struct sigaction sa;
+
+       if (sigemptyset(&sa.sa_mask) < 0)
+               zed_log_die("Failed to initialize sigset");
+
+       sa.sa_flags = SA_RESTART;
+       sa.sa_handler = SIG_IGN;
+
+       if (sigaction(SIGPIPE, &sa, NULL) < 0)
+               zed_log_die("Failed to ignore SIGPIPE");
+
+       sa.sa_handler = _exit_handler;
+       if (sigaction(SIGINT, &sa, NULL) < 0)
+               zed_log_die("Failed to register SIGINT handler");
+
+       if (sigaction(SIGTERM, &sa, NULL) < 0)
+               zed_log_die("Failed to register SIGTERM handler");
+
+       sa.sa_handler = _hup_handler;
+       if (sigaction(SIGHUP, &sa, NULL) < 0)
+               zed_log_die("Failed to register SIGHUP handler");
+}
+
+/*
+ * Lock all current and future pages in the virtual memory address space.
+ * Access to locked pages will never be delayed by a page fault.
+ *
+ * EAGAIN is tested up to max_tries in case this is a transient error.
+ *
+ * Note that memory locks are not inherited by a child created via fork()
+ * and are automatically removed during an execve().  As such, this must
+ * be called after the daemon fork()s (when running in the background).
+ */
+static void
+_lock_memory(void)
+{
+#if HAVE_MLOCKALL
+       int i = 0;
+       const int max_tries = 10;
+
+       for (i = 0; i < max_tries; i++) {
+               if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) {
+                       zed_log_msg(LOG_INFO, "Locked all pages in memory");
+                       return;
+               }
+               if (errno != EAGAIN)
+                       break;
+       }
+       zed_log_die("Failed to lock memory pages: %s", strerror(errno));
+
+#else /* HAVE_MLOCKALL */
+       zed_log_die("Failed to lock memory pages: mlockall() not supported");
+#endif /* HAVE_MLOCKALL */
+}
+
+/*
+ * Start daemonization of the process including the double fork().
+ *
+ * The parent process will block here until _finish_daemonize() is called
+ * (in the grandchild process), at which point the parent process will exit.
+ * This prevents the parent process from exiting until initialization is
+ * complete.
+ */
+static void
+_start_daemonize(void)
+{
+       pid_t pid;
+       struct sigaction sa;
+
+       /* Create pipe for communicating with child during daemonization. */
+       zed_log_pipe_open();
+
+       /* Background process and ensure child is not process group leader. */
+       pid = fork();
+       if (pid < 0) {
+               zed_log_die("Failed to create child process: %s",
+                   strerror(errno));
+       } else if (pid > 0) {
+
+               /* Close writes since parent will only read from pipe. */
+               zed_log_pipe_close_writes();
+
+               /* Wait for notification that daemonization is complete. */
+               zed_log_pipe_wait();
+
+               zed_log_pipe_close_reads();
+               _exit(EXIT_SUCCESS);
+       }
+
+       /* Close reads since child will only write to pipe. */
+       zed_log_pipe_close_reads();
+
+       /* Create independent session and detach from terminal. */
+       if (setsid() < 0)
+               zed_log_die("Failed to create new session: %s",
+                   strerror(errno));
+
+       /* Prevent child from terminating on HUP when session leader exits. */
+       if (sigemptyset(&sa.sa_mask) < 0)
+               zed_log_die("Failed to initialize sigset");
+
+       sa.sa_flags = 0;
+       sa.sa_handler = SIG_IGN;
+
+       if (sigaction(SIGHUP, &sa, NULL) < 0)
+               zed_log_die("Failed to ignore SIGHUP");
+
+       /* Ensure process cannot re-acquire terminal. */
+       pid = fork();
+       if (pid < 0) {
+               zed_log_die("Failed to create grandchild process: %s",
+                   strerror(errno));
+       } else if (pid > 0) {
+               _exit(EXIT_SUCCESS);
+       }
+}
+
+/*
+ * Finish daemonization of the process by closing stdin/stdout/stderr.
+ *
+ * This must be called at the end of initialization after all external
+ * communication channels are established and accessible.
+ */
+static void
+_finish_daemonize(void)
+{
+       int devnull;
+
+       /* Preserve fd 0/1/2, but discard data to/from stdin/stdout/stderr. */
+       devnull = open("/dev/null", O_RDWR);
+       if (devnull < 0)
+               zed_log_die("Failed to open /dev/null: %s", strerror(errno));
+
+       if (dup2(devnull, STDIN_FILENO) < 0)
+               zed_log_die("Failed to dup /dev/null onto stdin: %s",
+                   strerror(errno));
+
+       if (dup2(devnull, STDOUT_FILENO) < 0)
+               zed_log_die("Failed to dup /dev/null onto stdout: %s",
+                   strerror(errno));
+
+       if (dup2(devnull, STDERR_FILENO) < 0)
+               zed_log_die("Failed to dup /dev/null onto stderr: %s",
+                   strerror(errno));
+
+       if ((devnull > STDERR_FILENO) && (close(devnull) < 0))
+               zed_log_die("Failed to close /dev/null: %s", strerror(errno));
+
+       /* Notify parent that daemonization is complete. */
+       zed_log_pipe_close_writes();
+}
+
+/*
+ * ZFS Event Daemon (ZED).
+ */
+int
+main(int argc, char *argv[])
+{
+       struct zed_conf *zcp;
+       uint64_t saved_eid;
+       int64_t saved_etime[2];
+
+       zed_log_init(argv[0]);
+       zed_log_stderr_open(LOG_NOTICE);
+       zcp = zed_conf_create();
+       zed_conf_parse_opts(zcp, argc, argv);
+       if (zcp->do_verbose)
+               zed_log_stderr_open(LOG_INFO);
+
+       if (geteuid() != 0)
+               zed_log_die("Must be run as root");
+
+       zed_conf_parse_file(zcp);
+
+       zed_file_close_from(STDERR_FILENO + 1);
+
+       (void) umask(0);
+
+       if (chdir("/") < 0)
+               zed_log_die("Failed to change to root directory");
+
+       if (zed_conf_scan_dir(zcp) < 0)
+               exit(EXIT_FAILURE);
+
+       if (!zcp->do_foreground) {
+               _start_daemonize();
+               zed_log_syslog_open(LOG_DAEMON);
+       }
+       _setup_sig_handlers();
+
+       if (zcp->do_memlock)
+               _lock_memory();
+
+       if ((zed_conf_write_pid(zcp) < 0) && (!zcp->do_force))
+               exit(EXIT_FAILURE);
+
+       if (!zcp->do_foreground)
+               _finish_daemonize();
+
+       zed_log_msg(LOG_NOTICE,
+           "ZFS Event Daemon %s-%s (PID %d)",
+           ZFS_META_VERSION, ZFS_META_RELEASE, (int) getpid());
+
+       if (zed_conf_open_state(zcp) < 0)
+               exit(EXIT_FAILURE);
+
+       if (zed_conf_read_state(zcp, &saved_eid, saved_etime) < 0)
+               exit(EXIT_FAILURE);
+
+       zed_event_init(zcp);
+       zed_event_seek(zcp, saved_eid, saved_etime);
+
+       while (!_got_exit) {
+               if (_got_hup) {
+                       _got_hup = 0;
+                       (void) zed_conf_scan_dir(zcp);
+               }
+               zed_event_service(zcp);
+       }
+       zed_log_msg(LOG_NOTICE, "Exiting");
+       zed_event_fini(zcp);
+       zed_conf_destroy(zcp);
+       zed_log_fini();
+       exit(EXIT_SUCCESS);
+}
diff --git a/zfs/cmd/zed/zed.d/README b/zfs/cmd/zed/zed.d/README
new file mode 100644 (file)
index 0000000..b4cb115
--- /dev/null
@@ -0,0 +1,30 @@
+Shell scripts are the recommended choice for ZEDLETs that mostly call
+other utilities and do relatively little data manipulation.
+
+Shell scripts MUST work on both bash and dash.
+
+Shell scripts MUST run cleanly through ShellCheck:
+  http://www.shellcheck.net/
+
+General functions reside in "zed-functions.sh".  Use them where applicable.
+
+Additional references that may be of use:
+
+  Google Shell Style Guide
+  https://google-styleguide.googlecode.com/svn/trunk/shell.xml
+
+  Dash as /bin/sh
+  https://wiki.ubuntu.com/DashAsBinSh
+
+  Common shell script mistakes
+  http://www.pixelbeat.org/programming/shell_script_mistakes.html
+
+  Filenames and Pathnames in Shell: How to do it Correctly
+  http://www.dwheeler.com/essays/filenames-in-shell.html
+
+  Autoconf: Portable Shell Programming
+  https://www.gnu.org/software/autoconf/manual/autoconf.html#Portable-Shell
+
+Please BE CONSISTENT with the existing style, check for errors,
+minimize dependencies where possible, try to be portable,
+and comment anything non-obvious.  Festina lente.
diff --git a/zfs/cmd/zed/zed.d/all-debug.sh b/zfs/cmd/zed/zed.d/all-debug.sh
new file mode 100755 (executable)
index 0000000..057e39b
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# Log all environment variables to ZED_DEBUG_LOG.
+#
+# This can be a useful aid when developing/debugging ZEDLETs since it shows the
+# environment variables defined for each zevent.
+
+[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
+. "${ZED_ZEDLET_DIR}/zed-functions.sh"
+
+: "${ZED_DEBUG_LOG:="${TMPDIR:="/tmp"}/zed.debug.log"}"
+
+lockfile="$(basename -- "${ZED_DEBUG_LOG}").lock"
+
+umask 077
+zed_lock "${lockfile}"
+exec >> "${ZED_DEBUG_LOG}"
+
+printenv | sort
+echo
+
+exec >&-
+zed_unlock "${lockfile}"
+exit 0
diff --git a/zfs/cmd/zed/zed.d/all-syslog.sh b/zfs/cmd/zed/zed.d/all-syslog.sh
new file mode 100755 (executable)
index 0000000..5a3c8ad
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# Log the zevent via syslog.
+
+[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
+. "${ZED_ZEDLET_DIR}/zed-functions.sh"
+
+zed_log_msg "eid=${ZEVENT_EID}" "class=${ZEVENT_SUBCLASS}" \
+    "${ZEVENT_POOL:+"pool=${ZEVENT_POOL}"}" \
+    "${ZEVENT_VDEV_STATE_STR:+"vdev_state=${ZEVENT_VDEV_STATE_STR}"}"
+exit 0
diff --git a/zfs/cmd/zed/zed.d/checksum-notify.sh b/zfs/cmd/zed/zed.d/checksum-notify.sh
new file mode 120000 (symlink)
index 0000000..9008738
--- /dev/null
@@ -0,0 +1 @@
+io-notify.sh
\ No newline at end of file
diff --git a/zfs/cmd/zed/zed.d/checksum-spare.sh b/zfs/cmd/zed/zed.d/checksum-spare.sh
new file mode 120000 (symlink)
index 0000000..f564f93
--- /dev/null
@@ -0,0 +1 @@
+io-spare.sh
\ No newline at end of file
diff --git a/zfs/cmd/zed/zed.d/data-notify.sh b/zfs/cmd/zed/zed.d/data-notify.sh
new file mode 120000 (symlink)
index 0000000..9008738
--- /dev/null
@@ -0,0 +1 @@
+io-notify.sh
\ No newline at end of file
diff --git a/zfs/cmd/zed/zed.d/generic-notify.sh b/zfs/cmd/zed/zed.d/generic-notify.sh
new file mode 100755 (executable)
index 0000000..e438031
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# Send notification in response to a given zevent.
+#
+# This is a generic script than can be symlinked to a file in the
+# enabled-zedlets directory to have a notification sent when a particular
+# class of zevents occurs.  The symlink filename must begin with the zevent
+# (sub)class string (e.g., "probe_failure-notify.sh" for the "probe_failure"
+# subclass).  Refer to the zed(8) manpage for details.
+#
+# Only one notification per ZED_NOTIFY_INTERVAL_SECS will be sent for a given
+# class/pool combination.  This protects against spamming the recipient
+# should multiple events occur together in time for the same pool.
+#
+# Exit codes:
+#   0: notification sent
+#   1: notification failed
+#   2: notification not configured
+#   3: notification suppressed
+
+[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
+. "${ZED_ZEDLET_DIR}/zed-functions.sh"
+
+# Rate-limit the notification based in part on the filename.
+#
+rate_limit_tag="${ZEVENT_POOL};${ZEVENT_SUBCLASS};$(basename -- "$0")"
+rate_limit_interval="${ZED_NOTIFY_INTERVAL_SECS}"
+zed_rate_limit "${rate_limit_tag}" "${rate_limit_interval}" || exit 3
+
+umask 077
+pool_str="${ZEVENT_POOL:+" for ${ZEVENT_POOL}"}"
+host_str=" on $(hostname)"
+note_subject="ZFS ${ZEVENT_SUBCLASS} event${pool_str}${host_str}"
+note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
+{
+    echo "ZFS has posted the following event:"
+    echo
+    echo "   eid: ${ZEVENT_EID}"
+    echo " class: ${ZEVENT_SUBCLASS}"
+    echo "  host: $(hostname)"
+    echo "  time: ${ZEVENT_TIME_STRING}"
+
+    [ -n "${ZEVENT_VDEV_TYPE}" ] && echo " vtype: ${ZEVENT_VDEV_TYPE}"
+    [ -n "${ZEVENT_VDEV_PATH}" ] && echo " vpath: ${ZEVENT_VDEV_PATH}"
+    [ -n "${ZEVENT_VDEV_GUID}" ] && echo " vguid: ${ZEVENT_VDEV_GUID}"
+
+    [ -n "${ZEVENT_POOL}" ] && [ -x "${ZPOOL}" ] \
+        && "${ZPOOL}" status "${ZEVENT_POOL}"
+
+} > "${note_pathname}"
+
+zed_notify "${note_subject}" "${note_pathname}"; rv=$?
+rm -f "${note_pathname}"
+exit "${rv}"
diff --git a/zfs/cmd/zed/zed.d/io-notify.sh b/zfs/cmd/zed/zed.d/io-notify.sh
new file mode 100755 (executable)
index 0000000..3ce918a
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# Send notification in response to a CHECKSUM, DATA, or IO error.
+#
+# Only one notification per ZED_NOTIFY_INTERVAL_SECS will be sent for a given
+# class/pool/[vdev] combination.  This protects against spamming the recipient
+# should multiple events occur together in time for the same pool/[vdev].
+#
+# Exit codes:
+#   0: notification sent
+#   1: notification failed
+#   2: notification not configured
+#   3: notification suppressed
+#   9: internal error
+
+[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
+. "${ZED_ZEDLET_DIR}/zed-functions.sh"
+
+[ -n "${ZEVENT_POOL}" ] || exit 9
+[ -n "${ZEVENT_SUBCLASS}" ] || exit 9
+
+if [ "${ZEVENT_SUBCLASS}" != "checksum" ] \
+        && [ "${ZEVENT_SUBCLASS}" != "data" ] \
+        && [ "${ZEVENT_SUBCLASS}" != "io" ]; then
+    zed_log_err "unsupported event class \"${ZEVENT_SUBCLASS}\""
+    exit 9
+fi
+
+rate_limit_tag="${ZEVENT_POOL};${ZEVENT_VDEV_GUID:-0};${ZEVENT_SUBCLASS};notify"
+zed_rate_limit "${rate_limit_tag}" || exit 3
+
+umask 077
+note_subject="ZFS ${ZEVENT_SUBCLASS} error for ${ZEVENT_POOL} on $(hostname)"
+note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
+{
+    [ "${ZEVENT_SUBCLASS}" = "io" ] && article="an" || article="a"
+
+    echo "ZFS has detected ${article} ${ZEVENT_SUBCLASS} error:"
+    echo
+    echo "   eid: ${ZEVENT_EID}"
+    echo " class: ${ZEVENT_SUBCLASS}"
+    echo "  host: $(hostname)"
+    echo "  time: ${ZEVENT_TIME_STRING}"
+
+    [ -n "${ZEVENT_VDEV_TYPE}" ] && echo " vtype: ${ZEVENT_VDEV_TYPE}"
+    [ -n "${ZEVENT_VDEV_PATH}" ] && echo " vpath: ${ZEVENT_VDEV_PATH}"
+    [ -n "${ZEVENT_VDEV_GUID}" ] && echo " vguid: ${ZEVENT_VDEV_GUID}"
+
+    [ -n "${ZEVENT_VDEV_CKSUM_ERRORS}" ] \
+        && echo " cksum: ${ZEVENT_VDEV_CKSUM_ERRORS}"
+
+    [ -n "${ZEVENT_VDEV_READ_ERRORS}" ] \
+        && echo "  read: ${ZEVENT_VDEV_READ_ERRORS}"
+
+    [ -n "${ZEVENT_VDEV_WRITE_ERRORS}" ] \
+        && echo " write: ${ZEVENT_VDEV_WRITE_ERRORS}"
+
+    echo "  pool: ${ZEVENT_POOL}"
+
+} > "${note_pathname}"
+
+zed_notify "${note_subject}" "${note_pathname}"; rv=$?
+rm -f "${note_pathname}"
+exit "${rv}"
diff --git a/zfs/cmd/zed/zed.d/io-spare.sh b/zfs/cmd/zed/zed.d/io-spare.sh
new file mode 100755 (executable)
index 0000000..1835cb4
--- /dev/null
@@ -0,0 +1,239 @@
+#!/bin/sh
+#
+# Replace a device with a hot spare in response to IO or CHECKSUM errors.
+# The following actions will be performed automatically when the number
+# of errors exceed the limit set by ZED_SPARE_ON_IO_ERRORS or
+# ZED_SPARE_ON_CHECKSUM_ERRORS.
+#
+# 1) FAULT the device on IO errors, no futher IO will be attempted.
+#    DEGRADE the device on checksum errors, the device is still
+#    functional and can be used to service IO requests.
+# 2) Set the SES fault beacon for the device.
+# 3) Replace the device with a hot spare if any are available.
+#
+# Once the hot sparing operation is complete either the failed device or
+# the hot spare must be manually retired using the 'zpool detach' command.
+# The 'autoreplace' functionality which would normally take care of this
+# under Illumos has not yet been implemented.
+#
+# Full support for autoreplace is planned, but it requires that the full
+# ZFS Diagnosis Engine be ported.  In the meanwhile this script provides
+# the majority of the expected hot spare functionality.
+#
+# Exit codes:
+#   0: hot spare replacement successful
+#   1: hot spare device not available
+#   2: hot sparing disabled or threshold not reached
+#   3: device already faulted or degraded
+#   9: internal error
+
+[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
+. "${ZED_ZEDLET_DIR}/zed-functions.sh"
+
+# Disabled by default.  Enable in the zed.rc file.
+: "${ZED_SPARE_ON_CHECKSUM_ERRORS:=0}"
+: "${ZED_SPARE_ON_IO_ERRORS:=0}"
+
+
+# query_vdev_status (pool, vdev)
+#
+# Given a [pool] and [vdev], return the matching vdev path & status on stdout.
+#
+# Warning: This function does not handle the case of [pool] or [vdev]
+# containing whitespace.  Beware of ShellCheck SC2046.  Caveat emptor.
+#
+# Arguments
+#   pool: pool name
+#   vdev: virtual device name
+#
+# StdOut
+#   arg1: vdev pathname
+#   arg2: vdev status
+#
+query_vdev_status()
+{
+    local pool="$1"
+    local vdev="$2"
+    local t
+
+    vdev="$(basename -- "${vdev}")"
+    ([ -n "${pool}" ] && [ -n "${vdev}" ]) || return
+    t="$(printf '\t')"
+
+    "${ZPOOL}" status "${pool}" 2>/dev/null | sed -n -e \
+        "s,^[ $t]*\(.*${vdev}\(-part[0-9]\+\)\?\)[ $t]*\([A-Z]\+\).*,\1 \3,p" \
+        | tail -1
+}
+
+
+# notify (old_vdev, new_vdev, num_errors)
+#
+# Send a notification regarding the hot spare replacement.
+#
+# Arguments
+#   old_vdev: path of old vdev that has failed
+#   new_vdev: path of new vdev used as the hot spare replacement
+#   num_errors: number of errors that triggered this replacement
+#
+notify()
+{
+    local old_vdev="$1"
+    local new_vdev="$2"
+    local num_errors="$3"
+    local note_subject
+    local note_pathname
+    local s
+    local rv
+
+    umask 077
+    note_subject="ZFS hot spare replacement for ${ZEVENT_POOL} on $(hostname)"
+    note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
+    {
+        [ "${num_errors}" -ne 1 ] 2>/dev/null && s="s"
+
+        echo "ZFS has replaced a failing device with a hot spare after" \
+            "${num_errors} ${ZEVENT_SUBCLASS} error${s}:"
+        echo
+        echo "   eid: ${ZEVENT_EID}"
+        echo " class: ${ZEVENT_SUBCLASS}"
+        echo "  host: $(hostname)"
+        echo "  time: ${ZEVENT_TIME_STRING}"
+        echo "   old: ${old_vdev}"
+        echo "   new: ${new_vdev}"
+
+        "${ZPOOL}" status "${ZEVENT_POOL}"
+
+    } > "${note_pathname}"
+
+    zed_notify "${note_subject}" "${note_pathname}"; rv=$?
+    rm -f "${note_pathname}"
+    return "${rv}"
+}
+
+
+# main
+#
+# Arguments
+#   none
+#
+# Return
+#   see above
+#
+main()
+{
+    local num_errors
+    local action
+    local lockfile
+    local vdev_path
+    local vdev_status
+    local spare
+    local spare_path
+    local spare_status
+    local zpool_err
+    local zpool_rv
+    local rv
+
+    # Avoid hot-sparing a hot-spare.
+    #
+    # Note: ZEVENT_VDEV_PATH is not defined for ZEVENT_VDEV_TYPE=spare.
+    #
+    [ "${ZEVENT_VDEV_TYPE}" = "spare" ] && exit 2
+
+    [ -n "${ZEVENT_POOL}" ] || exit 9
+    [ -n "${ZEVENT_VDEV_GUID}" ] || exit 9
+    [ -n "${ZEVENT_VDEV_PATH}" ] || exit 9
+
+    zed_check_cmd "${ZPOOL}" "${ZINJECT}" || exit 9
+
+    # Fault the device after a given number of I/O errors.
+    #
+    if [ "${ZEVENT_SUBCLASS}" = "io" ]; then
+        if [ "${ZED_SPARE_ON_IO_ERRORS}" -gt 0 ]; then
+            num_errors=$((ZEVENT_VDEV_READ_ERRORS + ZEVENT_VDEV_WRITE_ERRORS))
+            [ "${num_errors}" -ge "${ZED_SPARE_ON_IO_ERRORS}" ] \
+                && action="fault"
+        fi 2>/dev/null
+
+    # Degrade the device after a given number of checksum errors.
+    #
+    elif [ "${ZEVENT_SUBCLASS}" = "checksum" ]; then
+        if [ "${ZED_SPARE_ON_CHECKSUM_ERRORS}" -gt 0 ]; then
+            num_errors="${ZEVENT_VDEV_CKSUM_ERRORS}"
+            [ "${num_errors}" -ge "${ZED_SPARE_ON_CHECKSUM_ERRORS}" ] \
+                && action="degrade"
+        fi 2>/dev/null
+
+    else
+        zed_log_err "unsupported event class \"${ZEVENT_SUBCLASS}\""
+        exit 9
+    fi
+
+    # Error threshold not reached.
+    #
+    if [ -z "${action}" ]; then
+        exit 2
+    fi
+
+    lockfile="zed.spare.lock"
+    zed_lock "${lockfile}"
+
+    # shellcheck disable=SC2046
+    set -- $(query_vdev_status "${ZEVENT_POOL}" "${ZEVENT_VDEV_PATH}")
+    vdev_path="$1"
+    vdev_status="$2"
+
+    # Device is already FAULTED or DEGRADED.
+    #
+    if [ "${vdev_status}" = "FAULTED" ] \
+            || [ "${vdev_status}" = "DEGRADED" ]; then
+        rv=3
+
+    else
+        rv=1
+
+        # 1) FAULT or DEGRADE the device.
+        #
+        "${ZINJECT}" -d "${ZEVENT_VDEV_GUID}" -A "${action}" "${ZEVENT_POOL}"
+
+        # 2) Set the SES fault beacon.
+        #
+        # TODO: Set the 'fault' or 'ident' beacon for the device.  This can
+        # be done through the sg_ses utility.  The only hard part is to map
+        # the sd device to its corresponding enclosure and slot.  We may
+        # be able to leverage the existing vdev_id scripts for this.
+        #
+        # $ sg_ses --dev-slot-num=0 --set=ident /dev/sg3
+        # $ sg_ses --dev-slot-num=0 --clear=ident /dev/sg3
+
+        # 3) Replace the device with a hot spare.
+        #
+        # Round-robin through the spares trying those that are available.
+        #
+        for spare in ${ZEVENT_VDEV_SPARE_PATHS}; do
+
+            # shellcheck disable=SC2046
+            set -- $(query_vdev_status "${ZEVENT_POOL}" "${spare}")
+            spare_path="$1"
+            spare_status="$2"
+
+            [ "${spare_status}" = "AVAIL" ] || continue
+
+            zpool_err="$("${ZPOOL}" replace "${ZEVENT_POOL}" \
+                "${ZEVENT_VDEV_GUID}" "${spare_path}" 2>&1)"; zpool_rv=$?
+
+            if [ "${zpool_rv}" -ne 0 ]; then
+                [ -n "${zpool_err}" ] && zed_log_err "zpool ${zpool_err}"
+            else
+                notify "${vdev_path}" "${spare_path}" "${num_errors}"
+                rv=0
+                break
+            fi
+        done
+    fi
+
+    zed_unlock "${lockfile}"
+    exit "${rv}"
+}
+
+
+main "$@"
diff --git a/zfs/cmd/zed/zed.d/resilver_finish-notify.sh b/zfs/cmd/zed/zed.d/resilver_finish-notify.sh
new file mode 120000 (symlink)
index 0000000..e4c56bc
--- /dev/null
@@ -0,0 +1 @@
+scrub_finish-notify.sh
\ No newline at end of file
diff --git a/zfs/cmd/zed/zed.d/scrub_finish-notify.sh b/zfs/cmd/zed/zed.d/scrub_finish-notify.sh
new file mode 100755 (executable)
index 0000000..2145a10
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# Send notification in response to a RESILVER_FINISH or SCRUB_FINISH.
+#
+# By default, "zpool status" output will only be included for a scrub_finish
+# zevent if the pool is not healthy; to always include its output, set
+# ZED_NOTIFY_VERBOSE=1.
+#
+# Exit codes:
+#   0: notification sent
+#   1: notification failed
+#   2: notification not configured
+#   3: notification suppressed
+#   9: internal error
+
+[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
+. "${ZED_ZEDLET_DIR}/zed-functions.sh"
+
+[ -n "${ZEVENT_POOL}" ] || exit 9
+[ -n "${ZEVENT_SUBCLASS}" ] || exit 9
+
+if   [ "${ZEVENT_SUBCLASS}" = "resilver_finish" ]; then
+    action="resilver"
+elif [ "${ZEVENT_SUBCLASS}" = "scrub_finish" ]; then
+    action="scrub"
+else
+    zed_log_err "unsupported event class \"${ZEVENT_SUBCLASS}\""
+    exit 9
+fi
+
+zed_check_cmd "${ZPOOL}" || exit 9
+
+# For scrub, suppress notification if the pool is healthy
+# and verbosity is not enabled.
+#
+if [ "${ZEVENT_SUBCLASS}" = "scrub_finish" ]; then
+    healthy="$("${ZPOOL}" status -x "${ZEVENT_POOL}" \
+        | grep "'${ZEVENT_POOL}' is healthy")"
+    [ -n "${healthy}" ] && [ "${ZED_NOTIFY_VERBOSE}" -eq 0 ] && exit 3
+fi
+
+umask 077
+note_subject="ZFS ${ZEVENT_SUBCLASS} event for ${ZEVENT_POOL} on $(hostname)"
+note_pathname="${TMPDIR:="/tmp"}/$(basename -- "$0").${ZEVENT_EID}.$$"
+{
+    echo "ZFS has finished a ${action}:"
+    echo
+    echo "   eid: ${ZEVENT_EID}"
+    echo " class: ${ZEVENT_SUBCLASS}"
+    echo "  host: $(hostname)"
+    echo "  time: ${ZEVENT_TIME_STRING}"
+
+    "${ZPOOL}" status "${ZEVENT_POOL}"
+
+} > "${note_pathname}"
+
+zed_notify "${note_subject}" "${note_pathname}"; rv=$?
+rm -f "${note_pathname}"
+exit "${rv}"
diff --git a/zfs/cmd/zed/zed.d/statechange-led.sh b/zfs/cmd/zed/zed.d/statechange-led.sh
new file mode 100755 (executable)
index 0000000..257e4a8
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/bash
+#
+# Turn off/on the VDEV's enclosure fault LEDs when the pool's state changes.
+#
+# Turn LED on if the VDEV becomes faulted or degraded, and turn it back off
+# when it's online again.  It will also turn on the LED (or keep it on) if
+# the drive becomes unavailable, unless the drive was in was a previously
+# online state (online->unavail is a normal state transition during an
+# autoreplace).
+#
+# This script requires that your enclosure be supported by the
+# Linux SCSI enclosure services (ses) driver.  The script will do nothing
+# if you have no enclosure, or if your enclosure isn't supported.
+#
+# This script also requires ZFS to be built with libdevmapper support.
+#
+# Exit codes:
+#   0: enclosure led successfully set
+#   1: enclosure leds not not available
+#   2: enclosure leds administratively disabled
+#   3: ZED didn't pass enclosure sysfs path
+#   4: Enclosure sysfs path doesn't exist
+
+[ -f "${ZED_ZEDLET_DIR}/zed.rc" ] && . "${ZED_ZEDLET_DIR}/zed.rc"
+. "${ZED_ZEDLET_DIR}/zed-functions.sh"
+
+if [ ! -d /sys/class/enclosure ] ; then
+       exit 1
+fi
+
+if [ "${ZED_USE_ENCLOSURE_LEDS}" != "1" ] ; then
+       exit 2
+fi
+
+[ -n "${ZEVENT_VDEV_ENC_SYSFS_PATH}" ] || exit 3
+
+[ -e "${ZEVENT_VDEV_ENC_SYSFS_PATH}/fault" ] || exit 4
+
+# Turn on/off enclosure LEDs
+function led
+{
+       file="$1/fault"
+       val=$2
+
+       # We want to check the current state first, since writing to the
+       # 'fault' entry always always causes a SES command, even if the
+       # current state is already what you want.
+       current=$(cat "${file}")
+
+       # On some enclosures if you write 1 to fault, and read it back,
+       # it will return 2.  Treat all non-zero values as 1 for
+       # simplicity.
+       if [ "$current" != "0" ] ; then
+               current=1
+       fi
+
+       if [ "$current" != "$val" ] ; then
+               # Set the value twice.  I've seen enclosures that were
+               # flakey about setting it the first time.
+               echo "$val" > "$file"
+               echo "$val" > "$file"
+       fi
+}
+
+# Decide whether to turn on/off an LED based on the state
+# Pass in path name and fault string ("ONLINE"/"FAULTED"/"DEGRADED"...etc)
+#
+# We only turn on LEDs when a drive becomes FAULTED, DEGRADED, or UNAVAIL and
+# only turn it on when it comes back ONLINE.  All other states are ignored, and
+# keep the previous LED state.  
+function process {
+       path="$1"
+       fault=$2
+       if [ "$fault" == "FAULTED" ] || [ "$fault" == "DEGRADED" ] || \
+          [ "$fault" == "UNAVAIL" ] ; then
+               led "$path" 1
+       elif [ "$fault" == "ONLINE" ] ; then
+               led "$path" 0
+       fi
+}
+
+process "$ZEVENT_VDEV_ENC_SYSFS_PATH" "$ZEVENT_VDEV_STATE_STR"
diff --git a/zfs/cmd/zed/zed.d/vdev_attach-led.sh b/zfs/cmd/zed/zed.d/vdev_attach-led.sh
new file mode 120000 (symlink)
index 0000000..7d74043
--- /dev/null
@@ -0,0 +1 @@
+statechange-led.sh
\ No newline at end of file
diff --git a/zfs/cmd/zed/zed.d/vdev_clear-led.sh b/zfs/cmd/zed/zed.d/vdev_clear-led.sh
new file mode 120000 (symlink)
index 0000000..7d74043
--- /dev/null
@@ -0,0 +1 @@
+statechange-led.sh
\ No newline at end of file
diff --git a/zfs/cmd/zed/zed.d/zed-functions.sh b/zfs/cmd/zed/zed.d/zed-functions.sh
new file mode 100644 (file)
index 0000000..1ddafa9
--- /dev/null
@@ -0,0 +1,415 @@
+# zed-functions.sh
+#
+# ZED helper functions for use in ZEDLETs
+
+
+# Variable Defaults
+#
+: "${ZED_LOCKDIR:="/var/lock"}"
+: "${ZED_NOTIFY_INTERVAL_SECS:=3600}"
+: "${ZED_NOTIFY_VERBOSE:=0}"
+: "${ZED_RUNDIR:="/var/run"}"
+: "${ZED_SYSLOG_PRIORITY:="daemon.notice"}"
+: "${ZED_SYSLOG_TAG:="zed"}"
+
+ZED_FLOCK_FD=8
+
+
+# zed_check_cmd (cmd, ...)
+#
+# For each argument given, search PATH for the executable command [cmd].
+# Log a message if [cmd] is not found.
+#
+# Arguments
+#   cmd: name of executable command for which to search
+#
+# Return
+#   0 if all commands are found in PATH and are executable
+#   n for a count of the command executables that are not found
+#
+zed_check_cmd()
+{
+    local cmd
+    local rv=0
+
+    for cmd; do
+        if ! command -v "${cmd}" >/dev/null 2>&1; then
+            zed_log_err "\"${cmd}\" not installed"
+            rv=$((rv + 1))
+        fi
+    done
+    return "${rv}"
+}
+
+
+# zed_log_msg (msg, ...)
+#
+# Write all argument strings to the system log.
+#
+# Globals
+#   ZED_SYSLOG_PRIORITY
+#   ZED_SYSLOG_TAG
+#
+# Return
+#   nothing
+#
+zed_log_msg()
+{
+    logger -p "${ZED_SYSLOG_PRIORITY}" -t "${ZED_SYSLOG_TAG}" -- "$@"
+}
+
+
+# zed_log_err (msg, ...)
+#
+# Write an error message to the system log.  This message will contain the
+# script name, EID, and all argument strings.
+#
+# Globals
+#   ZED_SYSLOG_PRIORITY
+#   ZED_SYSLOG_TAG
+#   ZEVENT_EID
+#
+# Return
+#   nothing
+#
+zed_log_err()
+{
+    logger -p "${ZED_SYSLOG_PRIORITY}" -t "${ZED_SYSLOG_TAG}" -- "error:" \
+        "$(basename -- "$0"):""${ZEVENT_EID:+" eid=${ZEVENT_EID}:"}" "$@"
+}
+
+
+# zed_lock (lockfile, [fd])
+#
+# Obtain an exclusive (write) lock on [lockfile].  If the lock cannot be
+# immediately acquired, wait until it becomes available.
+#
+# Every zed_lock() must be paired with a corresponding zed_unlock().
+#
+# By default, flock-style locks associate the lockfile with file descriptor 8.
+# The bash manpage warns that file descriptors >9 should be used with care as
+# they may conflict with file descriptors used internally by the shell.  File
+# descriptor 9 is reserved for zed_rate_limit().  If concurrent locks are held
+# within the same process, they must use different file descriptors (preferably
+# decrementing from 8); otherwise, obtaining a new lock with a given file
+# descriptor will release the previous lock associated with that descriptor.
+#
+# Arguments
+#   lockfile: pathname of the lock file; the lock will be stored in
+#     ZED_LOCKDIR unless the pathname contains a "/".
+#   fd: integer for the file descriptor used by flock (OPTIONAL unless holding
+#     concurrent locks)
+#
+# Globals
+#   ZED_FLOCK_FD
+#   ZED_LOCKDIR
+#
+# Return
+#   nothing
+#
+zed_lock()
+{
+    local lockfile="$1"
+    local fd="${2:-${ZED_FLOCK_FD}}"
+    local umask_bak
+    local err
+
+    [ -n "${lockfile}" ] || return
+    if ! expr "${lockfile}" : '.*/' >/dev/null 2>&1; then
+        lockfile="${ZED_LOCKDIR}/${lockfile}"
+    fi
+
+    umask_bak="$(umask)"
+    umask 077
+
+    # Obtain a lock on the file bound to the given file descriptor.
+    #
+    eval "exec ${fd}> '${lockfile}'"
+    err="$(flock --exclusive "${fd}" 2>&1)"
+    if [ $? -ne 0 ]; then
+        zed_log_err "failed to lock \"${lockfile}\": ${err}"
+    fi
+
+    umask "${umask_bak}"
+}
+
+
+# zed_unlock (lockfile, [fd])
+#
+# Release the lock on [lockfile].
+#
+# Arguments
+#   lockfile: pathname of the lock file
+#   fd: integer for the file descriptor used by flock (must match the file
+#     descriptor passed to the zed_lock function call)
+#
+# Globals
+#   ZED_FLOCK_FD
+#   ZED_LOCKDIR
+#
+# Return
+#   nothing
+#
+zed_unlock()
+{
+    local lockfile="$1"
+    local fd="${2:-${ZED_FLOCK_FD}}"
+    local err
+
+    [ -n "${lockfile}" ] || return
+    if ! expr "${lockfile}" : '.*/' >/dev/null 2>&1; then
+        lockfile="${ZED_LOCKDIR}/${lockfile}"
+    fi
+
+    # Release the lock and close the file descriptor.
+    #
+    err="$(flock --unlock "${fd}" 2>&1)"
+    if [ $? -ne 0 ]; then
+        zed_log_err "failed to unlock \"${lockfile}\": ${err}"
+    fi
+    eval "exec ${fd}>&-"
+}
+
+
+# zed_notify (subject, pathname)
+#
+# Send a notification via all available methods.
+#
+# Arguments
+#   subject: notification subject
+#   pathname: pathname containing the notification message (OPTIONAL)
+#
+# Return
+#   0: notification succeeded via at least one method
+#   1: notification failed
+#   2: no notification methods configured
+#
+zed_notify()
+{
+    local subject="$1"
+    local pathname="$2"
+    local num_success=0
+    local num_failure=0
+
+    zed_notify_email "${subject}" "${pathname}"; rv=$?
+    [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
+    [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
+
+    zed_notify_pushbullet "${subject}" "${pathname}"; rv=$?
+    [ "${rv}" -eq 0 ] && num_success=$((num_success + 1))
+    [ "${rv}" -eq 1 ] && num_failure=$((num_failure + 1))
+
+    [ "${num_success}" -gt 0 ] && return 0
+    [ "${num_failure}" -gt 0 ] && return 1
+    return 2
+}
+
+
+# zed_notify_email (subject, pathname)
+#
+# Send a notification via email to the address specified by ZED_EMAIL_ADDR.
+#
+# Requires the mail executable to be installed in the standard PATH, or
+# ZED_EMAIL_PROG to be defined with the pathname of an executable capable of
+# reading a message body from stdin.
+#
+# Command-line options to the mail executable can be specified in
+# ZED_EMAIL_OPTS.  This undergoes the following keyword substitutions:
+# - @ADDRESS@ is replaced with the space-delimited recipient email address(es)
+# - @SUBJECT@ is replaced with the notification subject
+#
+# Arguments
+#   subject: notification subject
+#   pathname: pathname containing the notification message (OPTIONAL)
+#
+# Globals
+#   ZED_EMAIL_PROG
+#   ZED_EMAIL_OPTS
+#   ZED_EMAIL_ADDR
+#
+# Return
+#   0: notification sent
+#   1: notification failed
+#   2: not configured
+#
+zed_notify_email()
+{
+    local subject="$1"
+    local pathname="${2:-"/dev/null"}"
+
+    : "${ZED_EMAIL_PROG:="mail"}"
+    : "${ZED_EMAIL_OPTS:="-s '@SUBJECT@' @ADDRESS@"}"
+
+    # For backward compatibility with ZED_EMAIL.
+    if [ -n "${ZED_EMAIL}" ] && [ -z "${ZED_EMAIL_ADDR}" ]; then
+        ZED_EMAIL_ADDR="${ZED_EMAIL}"
+    fi
+    [ -n "${ZED_EMAIL_ADDR}" ] || return 2
+
+    zed_check_cmd "${ZED_EMAIL_PROG}" || return 1
+
+    [ -n "${subject}" ] || return 1
+    if [ ! -r "${pathname}" ]; then
+        zed_log_err \
+                "$(basename "${ZED_EMAIL_PROG}") cannot read \"${pathname}\""
+        return 1
+    fi
+
+    ZED_EMAIL_OPTS="$(echo "${ZED_EMAIL_OPTS}" \
+        | sed   -e "s/@ADDRESS@/${ZED_EMAIL_ADDR}/g" \
+                -e "s/@SUBJECT@/${subject}/g")"
+
+    # shellcheck disable=SC2086
+    eval "${ZED_EMAIL_PROG}" ${ZED_EMAIL_OPTS} < "${pathname}" >/dev/null 2>&1
+    rv=$?
+    if [ "${rv}" -ne 0 ]; then
+        zed_log_err "$(basename "${ZED_EMAIL_PROG}") exit=${rv}"
+        return 1
+    fi
+    return 0
+}
+
+
+# zed_notify_pushbullet (subject, pathname)
+#
+# Send a notification via Pushbullet <https://www.pushbullet.com/>.
+# The access token (ZED_PUSHBULLET_ACCESS_TOKEN) identifies this client to the
+# Pushbullet server.  The optional channel tag (ZED_PUSHBULLET_CHANNEL_TAG) is
+# for pushing to notification feeds that can be subscribed to; if a channel is
+# not defined, push notifications will instead be sent to all devices
+# associated with the account specified by the access token.
+#
+# Requires awk, curl, and sed executables to be installed in the standard PATH.
+#
+# References
+#   https://docs.pushbullet.com/
+#   https://www.pushbullet.com/security
+#
+# Arguments
+#   subject: notification subject
+#   pathname: pathname containing the notification message (OPTIONAL)
+#
+# Globals
+#   ZED_PUSHBULLET_ACCESS_TOKEN
+#   ZED_PUSHBULLET_CHANNEL_TAG
+#
+# Return
+#   0: notification sent
+#   1: notification failed
+#   2: not configured
+#
+zed_notify_pushbullet()
+{
+    local subject="$1"
+    local pathname="${2:-"/dev/null"}"
+    local msg_body
+    local msg_tag
+    local msg_json
+    local msg_out
+    local msg_err
+    local url="https://api.pushbullet.com/v2/pushes"
+
+    [ -n "${ZED_PUSHBULLET_ACCESS_TOKEN}" ] || return 2
+
+    [ -n "${subject}" ] || return 1
+    if [ ! -r "${pathname}" ]; then
+        zed_log_err "pushbullet cannot read \"${pathname}\""
+        return 1
+    fi
+
+    zed_check_cmd "awk" "curl" "sed" || return 1
+
+    # Escape the following characters in the message body for JSON:
+    # newline, backslash, double quote, horizontal tab, vertical tab,
+    # and carriage return.
+    #
+    msg_body="$(awk '{ ORS="\\n" } { gsub(/\\/, "\\\\"); gsub(/"/, "\\\"");
+        gsub(/\t/, "\\t"); gsub(/\f/, "\\f"); gsub(/\r/, "\\r"); print }' \
+        "${pathname}")"
+
+    # Push to a channel if one is configured.
+    #
+    [ -n "${ZED_PUSHBULLET_CHANNEL_TAG}" ] && msg_tag="$(printf \
+        '"channel_tag": "%s", ' "${ZED_PUSHBULLET_CHANNEL_TAG}")"
+
+    # Construct the JSON message for pushing a note.
+    #
+    msg_json="$(printf '{%s"type": "note", "title": "%s", "body": "%s"}' \
+        "${msg_tag}" "${subject}" "${msg_body}")"
+
+    # Send the POST request and check for errors.
+    #
+    msg_out="$(curl -u "${ZED_PUSHBULLET_ACCESS_TOKEN}:" -X POST "${url}" \
+        --header "Content-Type: application/json" --data-binary "${msg_json}" \
+        2>/dev/null)"; rv=$?
+    if [ "${rv}" -ne 0 ]; then
+        zed_log_err "curl exit=${rv}"
+        return 1
+    fi
+    msg_err="$(echo "${msg_out}" \
+        | sed -n -e 's/.*"error" *:.*"message" *: *"\([^"]*\)".*/\1/p')"
+    if [ -n "${msg_err}" ]; then
+        zed_log_err "pushbullet \"${msg_err}"\"
+        return 1
+    fi
+    return 0
+}
+
+
+# zed_rate_limit (tag, [interval])
+#
+# Check whether an event of a given type [tag] has already occurred within the
+# last [interval] seconds.
+#
+# This function obtains a lock on the statefile using file descriptor 9.
+#
+# Arguments
+#   tag: arbitrary string for grouping related events to rate-limit
+#   interval: time interval in seconds (OPTIONAL)
+#
+# Globals
+#   ZED_NOTIFY_INTERVAL_SECS
+#   ZED_RUNDIR
+#
+# Return
+#   0 if the event should be processed
+#   1 if the event should be dropped
+#
+# State File Format
+#   time;tag
+#
+zed_rate_limit()
+{
+    local tag="$1"
+    local interval="${2:-${ZED_NOTIFY_INTERVAL_SECS}}"
+    local lockfile="zed.zedlet.state.lock"
+    local lockfile_fd=9
+    local statefile="${ZED_RUNDIR}/zed.zedlet.state"
+    local time_now
+    local time_prev
+    local umask_bak
+    local rv=0
+
+    [ -n "${tag}" ] || return 0
+
+    zed_lock "${lockfile}" "${lockfile_fd}"
+    time_now="$(date +%s)"
+    time_prev="$(egrep "^[0-9]+;${tag}\$" "${statefile}" 2>/dev/null \
+        | tail -1 | cut -d\; -f1)"
+
+    if [ -n "${time_prev}" ] \
+            && [ "$((time_now - time_prev))" -lt "${interval}" ]; then
+        rv=1
+    else
+        umask_bak="$(umask)"
+        umask 077
+        egrep -v "^[0-9]+;${tag}\$" "${statefile}" 2>/dev/null \
+            > "${statefile}.$$"
+        echo "${time_now};${tag}" >> "${statefile}.$$"
+        mv -f "${statefile}.$$" "${statefile}"
+        umask "${umask_bak}"
+    fi
+
+    zed_unlock "${lockfile}" "${lockfile_fd}"
+    return "${rv}"
+}
diff --git a/zfs/cmd/zed/zed.d/zed.rc b/zfs/cmd/zed/zed.d/zed.rc
new file mode 100644 (file)
index 0000000..2dce048
--- /dev/null
@@ -0,0 +1,105 @@
+##
+# zed.rc
+#
+# This file should be owned by root and permissioned 0600.
+##
+
+##
+# Absolute path to the debug output file.
+#
+#ZED_DEBUG_LOG="/tmp/zed.debug.log"
+
+##
+# Email address of the zpool administrator for receipt of notifications;
+#   multiple addresses can be specified if they are delimited by whitespace.
+# Email will only be sent if ZED_EMAIL_ADDR is defined.
+# Disabled by default; uncomment to enable.
+#
+#ZED_EMAIL_ADDR="root"
+
+##
+# Name or path of executable responsible for sending notifications via email;
+#   the mail program must be capable of reading a message body from stdin.
+# Email will only be sent if ZED_EMAIL_ADDR is defined.
+#
+#ZED_EMAIL_PROG="mail"
+
+##
+# Command-line options for ZED_EMAIL_PROG.
+# The string @ADDRESS@ will be replaced with the recipient email address(es).
+# The string @SUBJECT@ will be replaced with the notification subject;
+#   this should be protected with quotes to prevent word-splitting.
+# Email will only be sent if ZED_EMAIL_ADDR is defined.
+#
+#ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"
+
+##
+# Default directory for zed lock files.
+#
+#ZED_LOCKDIR="/var/lock"
+
+##
+# Minimum number of seconds between notifications for a similar event.
+#
+#ZED_NOTIFY_INTERVAL_SECS=3600
+
+##
+# Notification verbosity.
+#   If set to 0, suppress notification if the pool is healthy.
+#   If set to 1, send notification regardless of pool health.
+#
+#ZED_NOTIFY_VERBOSE=0
+
+##
+# Pushbullet access token.
+# This grants full access to your account -- protect it accordingly!
+#   <https://www.pushbullet.com/get-started>
+#   <https://www.pushbullet.com/account>
+# Disabled by default; uncomment to enable.
+#
+#ZED_PUSHBULLET_ACCESS_TOKEN=""
+
+##
+# Pushbullet channel tag for push notification feeds that can be subscribed to.
+#   <https://www.pushbullet.com/my-channel>
+# If not defined, push notifications will instead be sent to all devices
+#   associated with the account specified by the access token.
+# Disabled by default; uncomment to enable.
+#
+#ZED_PUSHBULLET_CHANNEL_TAG=""
+
+##
+# Default directory for zed state files.
+#
+#ZED_RUNDIR="/var/run"
+
+##
+# Replace a device with a hot spare after N checksum errors are detected.
+# Disabled by default; uncomment to enable.
+#
+#ZED_SPARE_ON_CHECKSUM_ERRORS=10
+
+##
+# Replace a device with a hot spare after N I/O errors are detected.
+# Disabled by default; uncomment to enable.
+#
+#ZED_SPARE_ON_IO_ERRORS=1
+
+##
+# Turn on/off enclosure LEDs when drives get DEGRADED/FAULTED.  This works for
+# device mapper and multipath devices as well.  Your enclosure must be
+# supported by the Linux SES driver for this to work.
+#
+ZED_USE_ENCLOSURE_LEDS=1
+
+
+##
+# The syslog priority (e.g., specified as a "facility.level" pair).
+#
+#ZED_SYSLOG_PRIORITY="daemon.notice"
+
+##
+# The syslog tag for marking zed events.
+#
+#ZED_SYSLOG_TAG="zed"
+
diff --git a/zfs/cmd/zed/zed.h b/zfs/cmd/zed/zed.h
new file mode 100644 (file)
index 0000000..3ac0e63
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#ifndef        ZED_H
+#define        ZED_H
+
+/*
+ * Absolute path for the default zed configuration file.
+ */
+#define        ZED_CONF_FILE           SYSCONFDIR "/zfs/zed.conf"
+
+/*
+ * Absolute path for the default zed pid file.
+ */
+#define        ZED_PID_FILE            RUNSTATEDIR "/zed.pid"
+
+/*
+ * Absolute path for the default zed state file.
+ */
+#define        ZED_STATE_FILE          RUNSTATEDIR "/zed.state"
+
+/*
+ * Absolute path for the default zed zedlet directory.
+ */
+#define        ZED_ZEDLET_DIR          SYSCONFDIR "/zfs/zed.d"
+
+/*
+ * Reserved for future use.
+ */
+#define        ZED_MAX_EVENTS          0
+
+/*
+ * Reserved for future use.
+ */
+#define        ZED_MIN_EVENTS          0
+
+/*
+ * String prefix for ZED variables passed via environment variables.
+ */
+#define        ZED_VAR_PREFIX          "ZED_"
+
+/*
+ * String prefix for ZFS event names passed via environment variables.
+ */
+#define        ZEVENT_VAR_PREFIX       "ZEVENT_"
+
+#endif /* !ZED_H */
diff --git a/zfs/cmd/zed/zed_conf.c b/zfs/cmd/zed/zed_conf.c
new file mode 100644 (file)
index 0000000..6dfd14e
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include "zed.h"
+#include "zed_conf.h"
+#include "zed_file.h"
+#include "zed_log.h"
+#include "zed_strings.h"
+
+/*
+ * Return a new configuration with default values.
+ */
+struct zed_conf *
+zed_conf_create(void)
+{
+       struct zed_conf *zcp;
+
+       zcp = calloc(1, sizeof (*zcp));
+       if (!zcp)
+               goto nomem;
+
+       zcp->syslog_facility = LOG_DAEMON;
+       zcp->min_events = ZED_MIN_EVENTS;
+       zcp->max_events = ZED_MAX_EVENTS;
+       zcp->pid_fd = -1;
+       zcp->zedlets = NULL;            /* created via zed_conf_scan_dir() */
+       zcp->state_fd = -1;             /* opened via zed_conf_open_state() */
+       zcp->zfs_hdl = NULL;            /* opened via zed_event_init() */
+       zcp->zevent_fd = -1;            /* opened via zed_event_init() */
+
+       if (!(zcp->conf_file = strdup(ZED_CONF_FILE)))
+               goto nomem;
+
+       if (!(zcp->pid_file = strdup(ZED_PID_FILE)))
+               goto nomem;
+
+       if (!(zcp->zedlet_dir = strdup(ZED_ZEDLET_DIR)))
+               goto nomem;
+
+       if (!(zcp->state_file = strdup(ZED_STATE_FILE)))
+               goto nomem;
+
+       return (zcp);
+
+nomem:
+       zed_log_die("Failed to create conf: %s", strerror(errno));
+       return (NULL);
+}
+
+/*
+ * Destroy the configuration [zcp].
+ *
+ * Note: zfs_hdl & zevent_fd are destroyed via zed_event_fini().
+ */
+void
+zed_conf_destroy(struct zed_conf *zcp)
+{
+       if (!zcp)
+               return;
+
+       if (zcp->state_fd >= 0) {
+               if (close(zcp->state_fd) < 0)
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to close state file \"%s\": %s",
+                           zcp->state_file, strerror(errno));
+               zcp->state_fd = -1;
+       }
+       if (zcp->pid_file) {
+               if ((unlink(zcp->pid_file) < 0) && (errno != ENOENT))
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to remove PID file \"%s\": %s",
+                           zcp->pid_file, strerror(errno));
+       }
+       if (zcp->pid_fd >= 0) {
+               if (close(zcp->pid_fd) < 0)
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to close PID file \"%s\": %s",
+                           zcp->pid_file, strerror(errno));
+               zcp->pid_fd = -1;
+       }
+       if (zcp->conf_file) {
+               free(zcp->conf_file);
+               zcp->conf_file = NULL;
+       }
+       if (zcp->pid_file) {
+               free(zcp->pid_file);
+               zcp->pid_file = NULL;
+       }
+       if (zcp->zedlet_dir) {
+               free(zcp->zedlet_dir);
+               zcp->zedlet_dir = NULL;
+       }
+       if (zcp->state_file) {
+               free(zcp->state_file);
+               zcp->state_file = NULL;
+       }
+       if (zcp->zedlets) {
+               zed_strings_destroy(zcp->zedlets);
+               zcp->zedlets = NULL;
+       }
+       free(zcp);
+}
+
+/*
+ * Display command-line help and exit.
+ *
+ * If [got_err] is 0, output to stdout and exit normally;
+ * otherwise, output to stderr and exit with a failure status.
+ */
+static void
+_zed_conf_display_help(const char *prog, int got_err)
+{
+       FILE *fp = got_err ? stderr : stdout;
+       int w1 = 4;                     /* width of leading whitespace */
+       int w2 = 8;                     /* width of L-justified option field */
+
+       fprintf(fp, "Usage: %s [OPTION]...\n", (prog ? prog : "zed"));
+       fprintf(fp, "\n");
+       fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-h",
+           "Display help.");
+       fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-L",
+           "Display license information.");
+       fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-V",
+           "Display version information.");
+       fprintf(fp, "\n");
+       fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-v",
+           "Be verbose.");
+       fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-f",
+           "Force daemon to run.");
+       fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-F",
+           "Run daemon in the foreground.");
+       fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-M",
+           "Lock all pages in memory.");
+       fprintf(fp, "%*c%*s %s\n", w1, 0x20, -w2, "-Z",
+           "Zero state file.");
+       fprintf(fp, "\n");
+#if 0
+       fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-c FILE",
+           "Read configuration from FILE.", ZED_CONF_FILE);
+#endif
+       fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-d DIR",
+           "Read enabled ZEDLETs from DIR.", ZED_ZEDLET_DIR);
+       fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-p FILE",
+           "Write daemon's PID to FILE.", ZED_PID_FILE);
+       fprintf(fp, "%*c%*s %s [%s]\n", w1, 0x20, -w2, "-s FILE",
+           "Write daemon's state to FILE.", ZED_STATE_FILE);
+       fprintf(fp, "\n");
+
+       exit(got_err ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+/*
+ * Display license information to stdout and exit.
+ */
+static void
+_zed_conf_display_license(void)
+{
+       const char **pp;
+       const char *text[] = {
+           "The ZFS Event Daemon (ZED) is distributed under the terms of the",
+           "  Common Development and Distribution License (CDDL-1.0)",
+           "  <http://opensource.org/licenses/CDDL-1.0>.",
+           "",
+           "Developed at Lawrence Livermore National Laboratory"
+           " (LLNL-CODE-403049).",
+           "",
+           NULL
+       };
+
+       for (pp = text; *pp; pp++)
+               printf("%s\n", *pp);
+
+       exit(EXIT_SUCCESS);
+}
+
+/*
+ * Display version information to stdout and exit.
+ */
+static void
+_zed_conf_display_version(void)
+{
+       printf("%s-%s-%s\n",
+           ZFS_META_NAME, ZFS_META_VERSION, ZFS_META_RELEASE);
+
+       exit(EXIT_SUCCESS);
+}
+
+/*
+ * Copy the [path] string to the [resultp] ptr.
+ * If [path] is not an absolute path, prefix it with the current working dir.
+ * If [resultp] is non-null, free its existing string before assignment.
+ */
+static void
+_zed_conf_parse_path(char **resultp, const char *path)
+{
+       char buf[PATH_MAX];
+
+       assert(resultp != NULL);
+       assert(path != NULL);
+
+       if (*resultp)
+               free(*resultp);
+
+       if (path[0] == '/') {
+               *resultp = strdup(path);
+       } else if (!getcwd(buf, sizeof (buf))) {
+               zed_log_die("Failed to get current working dir: %s",
+                   strerror(errno));
+       } else if (strlcat(buf, "/", sizeof (buf)) >= sizeof (buf)) {
+               zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG));
+       } else if (strlcat(buf, path, sizeof (buf)) >= sizeof (buf)) {
+               zed_log_die("Failed to copy path: %s", strerror(ENAMETOOLONG));
+       } else {
+               *resultp = strdup(buf);
+       }
+       if (!*resultp)
+               zed_log_die("Failed to copy path: %s", strerror(ENOMEM));
+}
+
+/*
+ * Parse the command-line options into the configuration [zcp].
+ */
+void
+zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv)
+{
+       const char * const opts = ":hLVc:d:p:s:vfFMZ";
+       int opt;
+
+       if (!zcp || !argv || !argv[0])
+               zed_log_die("Failed to parse options: Internal error");
+
+       opterr = 0;                     /* suppress default getopt err msgs */
+
+       while ((opt = getopt(argc, argv, opts)) != -1) {
+               switch (opt) {
+               case 'h':
+                       _zed_conf_display_help(argv[0], EXIT_SUCCESS);
+                       break;
+               case 'L':
+                       _zed_conf_display_license();
+                       break;
+               case 'V':
+                       _zed_conf_display_version();
+                       break;
+               case 'c':
+                       _zed_conf_parse_path(&zcp->conf_file, optarg);
+                       break;
+               case 'd':
+                       _zed_conf_parse_path(&zcp->zedlet_dir, optarg);
+                       break;
+               case 'p':
+                       _zed_conf_parse_path(&zcp->pid_file, optarg);
+                       break;
+               case 's':
+                       _zed_conf_parse_path(&zcp->state_file, optarg);
+                       break;
+               case 'v':
+                       zcp->do_verbose = 1;
+                       break;
+               case 'f':
+                       zcp->do_force = 1;
+                       break;
+               case 'F':
+                       zcp->do_foreground = 1;
+                       break;
+               case 'M':
+                       zcp->do_memlock = 1;
+                       break;
+               case 'Z':
+                       zcp->do_zero = 1;
+                       break;
+               case '?':
+               default:
+                       if (optopt == '?')
+                               _zed_conf_display_help(argv[0], EXIT_SUCCESS);
+
+                       fprintf(stderr, "%s: %s '-%c'\n\n", argv[0],
+                           "Invalid option", optopt);
+                       _zed_conf_display_help(argv[0], EXIT_FAILURE);
+                       break;
+               }
+       }
+}
+
+/*
+ * Parse the configuration file into the configuration [zcp].
+ *
+ * FIXME: Not yet implemented.
+ */
+void
+zed_conf_parse_file(struct zed_conf *zcp)
+{
+       if (!zcp)
+               zed_log_die("Failed to parse config: %s", strerror(EINVAL));
+}
+
+/*
+ * Scan the [zcp] zedlet_dir for files to exec based on the event class.
+ * Files must be executable by user, but not writable by group or other.
+ * Dotfiles are ignored.
+ *
+ * Return 0 on success with an updated set of zedlets,
+ * or -1 on error with errno set.
+ *
+ * FIXME: Check if zedlet_dir and all parent dirs are secure.
+ */
+int
+zed_conf_scan_dir(struct zed_conf *zcp)
+{
+       zed_strings_t *zedlets;
+       DIR *dirp;
+       struct dirent *direntp;
+       char pathname[PATH_MAX];
+       struct stat st;
+       int n;
+
+       if (!zcp) {
+               errno = EINVAL;
+               zed_log_msg(LOG_ERR, "Failed to scan zedlet dir: %s",
+                   strerror(errno));
+               return (-1);
+       }
+       zedlets = zed_strings_create();
+       if (!zedlets) {
+               errno = ENOMEM;
+               zed_log_msg(LOG_WARNING, "Failed to scan dir \"%s\": %s",
+                   zcp->zedlet_dir, strerror(errno));
+               return (-1);
+       }
+       dirp = opendir(zcp->zedlet_dir);
+       if (!dirp) {
+               int errno_bak = errno;
+               zed_log_msg(LOG_WARNING, "Failed to open dir \"%s\": %s",
+                   zcp->zedlet_dir, strerror(errno));
+               zed_strings_destroy(zedlets);
+               errno = errno_bak;
+               return (-1);
+       }
+       while ((direntp = readdir(dirp))) {
+               if (direntp->d_name[0] == '.')
+                       continue;
+
+               n = snprintf(pathname, sizeof (pathname),
+                   "%s/%s", zcp->zedlet_dir, direntp->d_name);
+               if ((n < 0) || (n >= sizeof (pathname))) {
+                       zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s",
+                           direntp->d_name, strerror(ENAMETOOLONG));
+                       continue;
+               }
+               if (stat(pathname, &st) < 0) {
+                       zed_log_msg(LOG_WARNING, "Failed to stat \"%s\": %s",
+                           pathname, strerror(errno));
+                       continue;
+               }
+               if (!S_ISREG(st.st_mode)) {
+                       zed_log_msg(LOG_INFO,
+                           "Ignoring \"%s\": not a regular file",
+                           direntp->d_name);
+                       continue;
+               }
+               if ((st.st_uid != 0) && !zcp->do_force) {
+                       zed_log_msg(LOG_NOTICE,
+                           "Ignoring \"%s\": not owned by root",
+                           direntp->d_name);
+                       continue;
+               }
+               if (!(st.st_mode & S_IXUSR)) {
+                       zed_log_msg(LOG_INFO,
+                           "Ignoring \"%s\": not executable by user",
+                           direntp->d_name);
+                       continue;
+               }
+               if ((st.st_mode & S_IWGRP) & !zcp->do_force) {
+                       zed_log_msg(LOG_NOTICE,
+                           "Ignoring \"%s\": writable by group",
+                           direntp->d_name);
+                       continue;
+               }
+               if ((st.st_mode & S_IWOTH) & !zcp->do_force) {
+                       zed_log_msg(LOG_NOTICE,
+                           "Ignoring \"%s\": writable by other",
+                           direntp->d_name);
+                       continue;
+               }
+               if (zed_strings_add(zedlets, NULL, direntp->d_name) < 0) {
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to register \"%s\": %s",
+                           direntp->d_name, strerror(errno));
+                       continue;
+               }
+               if (zcp->do_verbose)
+                       zed_log_msg(LOG_INFO,
+                           "Registered zedlet \"%s\"", direntp->d_name);
+       }
+       if (closedir(dirp) < 0) {
+               int errno_bak = errno;
+               zed_log_msg(LOG_WARNING, "Failed to close dir \"%s\": %s",
+                   zcp->zedlet_dir, strerror(errno));
+               zed_strings_destroy(zedlets);
+               errno = errno_bak;
+               return (-1);
+       }
+       if (zcp->zedlets)
+               zed_strings_destroy(zcp->zedlets);
+
+       zcp->zedlets = zedlets;
+       return (0);
+}
+
+/*
+ * Write the PID file specified in [zcp].
+ * Return 0 on success, -1 on error.
+ *
+ * This must be called after fork()ing to become a daemon (so the correct PID
+ * is recorded), but before daemonization is complete and the parent process
+ * exits (for synchronization with systemd).
+ */
+int
+zed_conf_write_pid(struct zed_conf *zcp)
+{
+       const mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+       const mode_t filemode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+       char buf[PATH_MAX];
+       int n;
+       char *p;
+       mode_t mask;
+       int rv;
+
+       if (!zcp || !zcp->pid_file) {
+               errno = EINVAL;
+               zed_log_msg(LOG_ERR, "Failed to create PID file: %s",
+                   strerror(errno));
+               return (-1);
+       }
+       assert(zcp->pid_fd == -1);
+       /*
+        * Create PID file directory if needed.
+        */
+       n = strlcpy(buf, zcp->pid_file, sizeof (buf));
+       if (n >= sizeof (buf)) {
+               errno = ENAMETOOLONG;
+               zed_log_msg(LOG_ERR, "Failed to create PID file: %s",
+                   strerror(errno));
+               goto err;
+       }
+       p = strrchr(buf, '/');
+       if (p)
+               *p = '\0';
+
+       if ((mkdirp(buf, dirmode) < 0) && (errno != EEXIST)) {
+               zed_log_msg(LOG_ERR, "Failed to create directory \"%s\": %s",
+                   buf, strerror(errno));
+               goto err;
+       }
+       /*
+        * Obtain PID file lock.
+        */
+       mask = umask(0);
+       umask(mask | 022);
+       zcp->pid_fd = open(zcp->pid_file, (O_RDWR | O_CREAT), filemode);
+       umask(mask);
+       if (zcp->pid_fd < 0) {
+               zed_log_msg(LOG_ERR, "Failed to open PID file \"%s\": %s",
+                   zcp->pid_file, strerror(errno));
+               goto err;
+       }
+       rv = zed_file_lock(zcp->pid_fd);
+       if (rv < 0) {
+               zed_log_msg(LOG_ERR, "Failed to lock PID file \"%s\": %s",
+                   zcp->pid_file, strerror(errno));
+               goto err;
+       } else if (rv > 0) {
+               pid_t pid = zed_file_is_locked(zcp->pid_fd);
+               if (pid < 0) {
+                       zed_log_msg(LOG_ERR,
+                           "Failed to test lock on PID file \"%s\"",
+                           zcp->pid_file);
+               } else if (pid > 0) {
+                       zed_log_msg(LOG_ERR,
+                           "Found PID %d bound to PID file \"%s\"",
+                           pid, zcp->pid_file);
+               } else {
+                       zed_log_msg(LOG_ERR,
+                           "Inconsistent lock state on PID file \"%s\"",
+                           zcp->pid_file);
+               }
+               goto err;
+       }
+       /*
+        * Write PID file.
+        */
+       n = snprintf(buf, sizeof (buf), "%d\n", (int) getpid());
+       if ((n < 0) || (n >= sizeof (buf))) {
+               errno = ERANGE;
+               zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
+                   zcp->pid_file, strerror(errno));
+       } else if (zed_file_write_n(zcp->pid_fd, buf, n) != n) {
+               zed_log_msg(LOG_ERR, "Failed to write PID file \"%s\": %s",
+                   zcp->pid_file, strerror(errno));
+       } else if (fdatasync(zcp->pid_fd) < 0) {
+               zed_log_msg(LOG_ERR, "Failed to sync PID file \"%s\": %s",
+                   zcp->pid_file, strerror(errno));
+       } else {
+               return (0);
+       }
+
+err:
+       if (zcp->pid_fd >= 0) {
+               (void) close(zcp->pid_fd);
+               zcp->pid_fd = -1;
+       }
+       return (-1);
+}
+
+/*
+ * Open and lock the [zcp] state_file.
+ * Return 0 on success, -1 on error.
+ *
+ * FIXME: Move state information into kernel.
+ */
+int
+zed_conf_open_state(struct zed_conf *zcp)
+{
+       char dirbuf[PATH_MAX];
+       mode_t dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+       int n;
+       char *p;
+       int rv;
+
+       if (!zcp || !zcp->state_file) {
+               errno = EINVAL;
+               zed_log_msg(LOG_ERR, "Failed to open state file: %s",
+                   strerror(errno));
+               return (-1);
+       }
+       n = strlcpy(dirbuf, zcp->state_file, sizeof (dirbuf));
+       if (n >= sizeof (dirbuf)) {
+               errno = ENAMETOOLONG;
+               zed_log_msg(LOG_WARNING, "Failed to open state file: %s",
+                   strerror(errno));
+               return (-1);
+       }
+       p = strrchr(dirbuf, '/');
+       if (p)
+               *p = '\0';
+
+       if ((mkdirp(dirbuf, dirmode) < 0) && (errno != EEXIST)) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to create directory \"%s\": %s",
+                   dirbuf, strerror(errno));
+               return (-1);
+       }
+       if (zcp->state_fd >= 0) {
+               if (close(zcp->state_fd) < 0) {
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to close state file \"%s\": %s",
+                           zcp->state_file, strerror(errno));
+                       return (-1);
+               }
+       }
+       if (zcp->do_zero)
+               (void) unlink(zcp->state_file);
+
+       zcp->state_fd = open(zcp->state_file,
+           (O_RDWR | O_CREAT), (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
+       if (zcp->state_fd < 0) {
+               zed_log_msg(LOG_WARNING, "Failed to open state file \"%s\": %s",
+                   zcp->state_file, strerror(errno));
+               return (-1);
+       }
+       rv = zed_file_lock(zcp->state_fd);
+       if (rv < 0) {
+               zed_log_msg(LOG_WARNING, "Failed to lock state file \"%s\": %s",
+                   zcp->state_file, strerror(errno));
+               return (-1);
+       }
+       if (rv > 0) {
+               pid_t pid = zed_file_is_locked(zcp->state_fd);
+               if (pid < 0) {
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to test lock on state file \"%s\"",
+                           zcp->state_file);
+               } else if (pid > 0) {
+                       zed_log_msg(LOG_WARNING,
+                           "Found PID %d bound to state file \"%s\"",
+                           pid, zcp->state_file);
+               } else {
+                       zed_log_msg(LOG_WARNING,
+                           "Inconsistent lock state on state file \"%s\"",
+                           zcp->state_file);
+               }
+               return (-1);
+       }
+       return (0);
+}
+
+/*
+ * Read the opened [zcp] state_file to obtain the eid & etime of the last event
+ * processed.  Write the state from the last event to the [eidp] & [etime] args
+ * passed by reference.  Note that etime[] is an array of size 2.
+ * Return 0 on success, -1 on error.
+ */
+int
+zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[])
+{
+       ssize_t len;
+       struct iovec iov[3];
+       ssize_t n;
+
+       if (!zcp || !eidp || !etime) {
+               errno = EINVAL;
+               zed_log_msg(LOG_ERR,
+                   "Failed to read state file: %s", strerror(errno));
+               return (-1);
+       }
+       if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t) -1) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to reposition state file offset: %s",
+                   strerror(errno));
+               return (-1);
+       }
+       len = 0;
+       iov[0].iov_base = eidp;
+       len += iov[0].iov_len = sizeof (*eidp);
+       iov[1].iov_base = &etime[0];
+       len += iov[1].iov_len = sizeof (etime[0]);
+       iov[2].iov_base = &etime[1];
+       len += iov[2].iov_len = sizeof (etime[1]);
+
+       n = readv(zcp->state_fd, iov, 3);
+       if (n == 0) {
+               *eidp = 0;
+       } else if (n < 0) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to read state file \"%s\": %s",
+                   zcp->state_file, strerror(errno));
+               return (-1);
+       } else if (n != len) {
+               errno = EIO;
+               zed_log_msg(LOG_WARNING,
+                   "Failed to read state file \"%s\": Read %d of %d bytes",
+                   zcp->state_file, n, len);
+               return (-1);
+       }
+       return (0);
+}
+
+/*
+ * Write the [eid] & [etime] of the last processed event to the opened
+ * [zcp] state_file.  Note that etime[] is an array of size 2.
+ * Return 0 on success, -1 on error.
+ */
+int
+zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[])
+{
+       ssize_t len;
+       struct iovec iov[3];
+       ssize_t n;
+
+       if (!zcp) {
+               errno = EINVAL;
+               zed_log_msg(LOG_ERR,
+                   "Failed to write state file: %s", strerror(errno));
+               return (-1);
+       }
+       if (lseek(zcp->state_fd, 0, SEEK_SET) == (off_t) -1) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to reposition state file offset: %s",
+                   strerror(errno));
+               return (-1);
+       }
+       len = 0;
+       iov[0].iov_base = &eid;
+       len += iov[0].iov_len = sizeof (eid);
+       iov[1].iov_base = &etime[0];
+       len += iov[1].iov_len = sizeof (etime[0]);
+       iov[2].iov_base = &etime[1];
+       len += iov[2].iov_len = sizeof (etime[1]);
+
+       n = writev(zcp->state_fd, iov, 3);
+       if (n < 0) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to write state file \"%s\": %s",
+                   zcp->state_file, strerror(errno));
+               return (-1);
+       }
+       if (n != len) {
+               errno = EIO;
+               zed_log_msg(LOG_WARNING,
+                   "Failed to write state file \"%s\": Wrote %d of %d bytes",
+                   zcp->state_file, n, len);
+               return (-1);
+       }
+       if (fdatasync(zcp->state_fd) < 0) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to sync state file \"%s\": %s",
+                   zcp->state_file, strerror(errno));
+               return (-1);
+       }
+       return (0);
+}
diff --git a/zfs/cmd/zed/zed_conf.h b/zfs/cmd/zed/zed_conf.h
new file mode 100644 (file)
index 0000000..2bc6341
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#ifndef        ZED_CONF_H
+#define        ZED_CONF_H
+
+#include <libzfs.h>
+#include <stdint.h>
+#include "zed_strings.h"
+
+struct zed_conf {
+       unsigned        do_force:1;             /* true if force enabled */
+       unsigned        do_foreground:1;        /* true if run in foreground */
+       unsigned        do_memlock:1;           /* true if locking memory */
+       unsigned        do_verbose:1;           /* true if verbosity enabled */
+       unsigned        do_zero:1;              /* true if zeroing state */
+       int             syslog_facility;        /* syslog facility value */
+       int             min_events;             /* RESERVED FOR FUTURE USE */
+       int             max_events;             /* RESERVED FOR FUTURE USE */
+       char            *conf_file;             /* abs path to config file */
+       char            *pid_file;              /* abs path to pid file */
+       int             pid_fd;                 /* fd to pid file for lock */
+       char            *zedlet_dir;            /* abs path to zedlet dir */
+       zed_strings_t   *zedlets;               /* names of enabled zedlets */
+       char            *state_file;            /* abs path to state file */
+       int             state_fd;               /* fd to state file */
+       libzfs_handle_t *zfs_hdl;               /* handle to libzfs */
+       int             zevent_fd;              /* fd for access to zevents */
+};
+
+struct zed_conf *zed_conf_create(void);
+
+void zed_conf_destroy(struct zed_conf *zcp);
+
+void zed_conf_parse_opts(struct zed_conf *zcp, int argc, char **argv);
+
+void zed_conf_parse_file(struct zed_conf *zcp);
+
+int zed_conf_scan_dir(struct zed_conf *zcp);
+
+int zed_conf_write_pid(struct zed_conf *zcp);
+
+int zed_conf_open_state(struct zed_conf *zcp);
+
+int zed_conf_read_state(struct zed_conf *zcp, uint64_t *eidp, int64_t etime[]);
+
+int zed_conf_write_state(struct zed_conf *zcp, uint64_t eid, int64_t etime[]);
+
+#endif /* !ZED_CONF_H */
diff --git a/zfs/cmd/zed/zed_disk_event.c b/zfs/cmd/zed/zed_disk_event.c
new file mode 100644 (file)
index 0000000..b5f5750
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2016, Intel Corporation.
+ */
+
+#ifdef HAVE_LIBUDEV
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libnvpair.h>
+#include <libudev.h>
+#include <libzfs.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dev.h>
+
+#include "zed_log.h"
+#include "zed_disk_event.h"
+#include "agents/zfs_agents.h"
+
+/*
+ * Portions of ZED need to see disk events for disks belonging to ZFS pools.
+ * A libudev monitor is established to monitor block device actions and pass
+ * them on to internal ZED logic modules.  Initially, zfs_mod.c is the only
+ * consumer and is the Linux equivalent for the illumos syseventd ZFS SLM
+ * module responsible for handeling disk events for ZFS.
+ */
+
+pthread_t g_mon_tid;
+struct udev *g_udev;
+struct udev_monitor *g_mon;
+
+
+#define        DEV_BYID_PATH   "/dev/disk/by-id/"
+
+/* 64MB is minimum usable disk for ZFS */
+#define        MINIMUM_SECTORS         131072
+
+
+/*
+ * Post disk event to SLM module
+ *
+ * occurs in the context of monitor thread
+ */
+static void
+zed_udev_event(const char *class, const char *subclass, nvlist_t *nvl)
+{
+       char *strval;
+       uint64_t numval;
+
+       zed_log_msg(LOG_INFO, "zed_disk_event:");
+       zed_log_msg(LOG_INFO, "\tclass: %s", class);
+       zed_log_msg(LOG_INFO, "\tsubclass: %s", subclass);
+       if (nvlist_lookup_string(nvl, DEV_NAME, &strval) == 0)
+               zed_log_msg(LOG_INFO, "\t%s: %s", DEV_NAME, strval);
+       if (nvlist_lookup_string(nvl, DEV_PATH, &strval) == 0)
+               zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PATH, strval);
+       if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &strval) == 0)
+               zed_log_msg(LOG_INFO, "\t%s: %s", DEV_IDENTIFIER, strval);
+       if (nvlist_lookup_string(nvl, DEV_PHYS_PATH, &strval) == 0)
+               zed_log_msg(LOG_INFO, "\t%s: %s", DEV_PHYS_PATH, strval);
+       if (nvlist_lookup_uint64(nvl, DEV_SIZE, &numval) == 0)
+               zed_log_msg(LOG_INFO, "\t%s: %llu", DEV_SIZE, numval);
+       if (nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &numval) == 0)
+               zed_log_msg(LOG_INFO, "\t%s: %llu", ZFS_EV_POOL_GUID, numval);
+       if (nvlist_lookup_uint64(nvl, ZFS_EV_VDEV_GUID, &numval) == 0)
+               zed_log_msg(LOG_INFO, "\t%s: %llu", ZFS_EV_VDEV_GUID, numval);
+
+       (void) zfs_slm_event(class, subclass, nvl);
+}
+
+/*
+ * dev_event_nvlist: place event schema into an nv pair list
+ *
+ * NAME                        VALUE (example)
+ * --------------      --------------------------------------------------------
+ * DEV_NAME            /dev/sdl
+ * DEV_PATH            /devices/pci0000:00/0000:00:03.0/0000:04:00.0/host0/...
+ * DEV_IDENTIFIER      ata-Hitachi_HTS725050A9A362_100601PCG420VLJ37DMC
+ * DEV_PHYS_PATH       pci-0000:04:00.0-sas-0x4433221101000000-lun-0
+ * DEV_IS_PART         ---
+ * DEV_SIZE            500107862016
+ * ZFS_EV_POOL_GUID    17523635698032189180
+ * ZFS_EV_VDEV_GUID    14663607734290803088
+ */
+static nvlist_t *
+dev_event_nvlist(struct udev_device *dev)
+{
+       nvlist_t *nvl;
+       char strval[128];
+       const char *value, *path;
+       uint64_t guid;
+
+       if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+               return (NULL);
+
+       if (zfs_device_get_devid(dev, strval, sizeof (strval)) == 0)
+               (void) nvlist_add_string(nvl, DEV_IDENTIFIER, strval);
+       if (zfs_device_get_physical(dev, strval, sizeof (strval)) == 0)
+               (void) nvlist_add_string(nvl, DEV_PHYS_PATH, strval);
+       if ((path = udev_device_get_devnode(dev)) != NULL)
+               (void) nvlist_add_string(nvl, DEV_NAME, path);
+       if ((value = udev_device_get_devpath(dev)) != NULL)
+               (void) nvlist_add_string(nvl, DEV_PATH, value);
+       value = udev_device_get_devtype(dev);
+       if ((value != NULL && strcmp("partition", value) == 0) ||
+           (udev_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER")
+           != NULL)) {
+               (void) nvlist_add_boolean(nvl, DEV_IS_PART);
+       }
+       if ((value = udev_device_get_sysattr_value(dev, "size")) != NULL) {
+               uint64_t numval = DEV_BSIZE;
+
+               numval *= strtoull(value, NULL, 10);
+               (void) nvlist_add_uint64(nvl, DEV_SIZE, numval);
+       }
+
+       /*
+        * Grab the pool and vdev guids from blkid cache
+        */
+       value = udev_device_get_property_value(dev, "ID_FS_UUID");
+       if (value != NULL && (guid = strtoull(value, NULL, 10)) != 0)
+               (void) nvlist_add_uint64(nvl, ZFS_EV_POOL_GUID, guid);
+
+       value = udev_device_get_property_value(dev, "ID_FS_UUID_SUB");
+       if (value != NULL && (guid = strtoull(value, NULL, 10)) != 0)
+               (void) nvlist_add_uint64(nvl, ZFS_EV_VDEV_GUID, guid);
+
+       /*
+        * Either a vdev guid or a devid must be present for matching
+        */
+       if (!nvlist_exists(nvl, DEV_IDENTIFIER) &&
+           !nvlist_exists(nvl, ZFS_EV_VDEV_GUID)) {
+               nvlist_free(nvl);
+               return (NULL);
+       }
+
+       return (nvl);
+}
+
+/*
+ *  Listen for block device uevents
+ */
+static void *
+zed_udev_monitor(void *arg)
+{
+       struct udev_monitor *mon = arg;
+       char *tmp, *tmp2;
+
+       zed_log_msg(LOG_INFO, "Waiting for new uduev disk events...");
+
+       while (1) {
+               struct udev_device *dev;
+               const char *action, *type, *part, *sectors;
+               const char *bus, *uuid;
+               const char *class, *subclass;
+               nvlist_t *nvl;
+               boolean_t is_zfs = B_FALSE;
+
+               /* allow a cancellation while blocked (recvmsg) */
+               pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+               /* blocks at recvmsg until an event occurs */
+               if ((dev = udev_monitor_receive_device(mon)) == NULL) {
+                       zed_log_msg(LOG_WARNING, "zed_udev_monitor: receive "
+                           "device error %d", errno);
+                       continue;
+               }
+
+               /* allow all steps to complete before a cancellation */
+               pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+               /*
+                * Strongly typed device is the prefered filter
+                */
+               type = udev_device_get_property_value(dev, "ID_FS_TYPE");
+               if (type != NULL && type[0] != '\0') {
+                       if (strcmp(type, "zfs_member") == 0) {
+                               is_zfs = B_TRUE;
+                       } else {
+                               /* not ours, so skip */
+                               zed_log_msg(LOG_INFO, "zed_udev_monitor: skip "
+                                   "%s (in use by %s)",
+                                   udev_device_get_devnode(dev), type);
+                               udev_device_unref(dev);
+                               continue;
+                       }
+               }
+
+               /*
+                * if this is a disk and it is partitioned, then the
+                * zfs label will reside in a DEVTYPE=partition and
+                * we can skip passing this event
+                */
+               type = udev_device_get_property_value(dev, "DEVTYPE");
+               part = udev_device_get_property_value(dev,
+                   "ID_PART_TABLE_TYPE");
+               if (type != NULL && type[0] != '\0' &&
+                   strcmp(type, "disk") == 0 &&
+                   part != NULL && part[0] != '\0') {
+                       /* skip and wait for partition event */
+                       zed_log_msg(LOG_INFO, "zed_udev_monitor: %s waiting "
+                           "for slice", udev_device_get_devnode(dev));
+                       udev_device_unref(dev);
+                       continue;
+               }
+
+               /*
+                * ignore small partitions
+                */
+               sectors = udev_device_get_property_value(dev,
+                   "ID_PART_ENTRY_SIZE");
+               if (sectors == NULL)
+                       sectors = udev_device_get_sysattr_value(dev, "size");
+               if (sectors != NULL &&
+                   strtoull(sectors, NULL, 10) < MINIMUM_SECTORS) {
+                       udev_device_unref(dev);
+                       continue;
+               }
+
+               /*
+                * If the blkid probe didn't find ZFS, then a persistent
+                * device id string is required in the message schema
+                * for matching with vdevs. Preflight here for expected
+                * udev information.
+                */
+               bus = udev_device_get_property_value(dev, "ID_BUS");
+               uuid = udev_device_get_property_value(dev, "DM_UUID");
+               if (!is_zfs && (bus == NULL && uuid == NULL)) {
+                       zed_log_msg(LOG_INFO, "zed_udev_monitor: %s no devid "
+                           "source", udev_device_get_devnode(dev));
+                       udev_device_unref(dev);
+                       continue;
+               }
+
+               action = udev_device_get_action(dev);
+               if (strcmp(action, "add") == 0) {
+                       class = EC_DEV_ADD;
+                       subclass = ESC_DISK;
+               } else if (strcmp(action, "remove") == 0) {
+                       class = EC_DEV_REMOVE;
+                       subclass = ESC_DISK;
+               } else if (strcmp(action, "change") == 0) {
+                       class = EC_DEV_STATUS;
+                       subclass = ESC_DEV_DLE;
+               } else {
+                       zed_log_msg(LOG_WARNING, "zed_udev_monitor: %s unknown",
+                           action);
+                       udev_device_unref(dev);
+                       continue;
+               }
+
+               /*
+                * Special case an EC_DEV_ADD for multipath devices
+                *
+                * When a multipath device is created, udev reports the
+                * following:
+                *
+                * 1.   "add" event of the dm device for the multipath device
+                *      (like /dev/dm-3).
+                * 2.   "change" event to create the actual multipath device
+                *      symlink (like /dev/mapper/mpatha).  The event also
+                *      passes back the relevant DM vars we care about, like
+                *      DM_UUID.
+                * 3.   Another "change" event identical to #2 (that we ignore).
+                *
+                * To get the behavior we want, we treat the "change" event
+                * in #2 as a "add" event; as if "/dev/mapper/mpatha" was
+                * a new disk being added.
+                */
+               if (strcmp(class, EC_DEV_STATUS) == 0 &&
+                   udev_device_get_property_value(dev, "DM_UUID") &&
+                   udev_device_get_property_value(dev, "MPATH_SBIN_PATH")) {
+                       tmp = (char *) udev_device_get_devnode(dev);
+                       tmp2 = zfs_get_underlying_path(tmp);
+                       if (tmp && tmp2 && (strcmp(tmp, tmp2) != 0)) {
+                               /*
+                                * We have a real underlying device, which
+                                * means that this multipath "change" event is
+                                * an "add" event.
+                                *
+                                * If the multipath device and the underlying
+                                * dev are the same name (i.e. /dev/dm-5), then
+                                * there is no real underlying disk for this
+                                * multipath device, and so this "change" event
+                                * really a multipath removal.
+                                */
+                               class = EC_DEV_ADD;
+                               subclass = ESC_DISK;
+                       } else {
+                               /* multipath remove, ignore it. */
+                       }
+                       free(tmp2);
+               }
+
+               if ((nvl = dev_event_nvlist(dev)) != NULL) {
+                       zed_udev_event(class, subclass, nvl);
+                       nvlist_free(nvl);
+               }
+
+               udev_device_unref(dev);
+       }
+
+       return (NULL);
+}
+
+int
+zed_disk_event_init()
+{
+       int fd, fflags;
+
+       if ((g_udev = udev_new()) == NULL) {
+               zed_log_msg(LOG_WARNING, "udev_new failed (%d)", errno);
+               return (-1);
+       }
+
+       /* Set up a udev monitor for block devices */
+       g_mon = udev_monitor_new_from_netlink(g_udev, "udev");
+       udev_monitor_filter_add_match_subsystem_devtype(g_mon, "block", "disk");
+       udev_monitor_filter_add_match_subsystem_devtype(g_mon, "block",
+           "partition");
+       udev_monitor_enable_receiving(g_mon);
+
+       /* Make sure monitoring socket is blocking */
+       fd = udev_monitor_get_fd(g_mon);
+       if ((fflags = fcntl(fd, F_GETFL)) & O_NONBLOCK)
+               (void) fcntl(fd, F_SETFL, fflags & ~O_NONBLOCK);
+
+       /* spawn a thread to monitor events */
+       if (pthread_create(&g_mon_tid, NULL, zed_udev_monitor, g_mon) != 0) {
+               udev_monitor_unref(g_mon);
+               udev_unref(g_udev);
+               zed_log_msg(LOG_WARNING, "pthread_create failed");
+               return (-1);
+       }
+
+       zed_log_msg(LOG_INFO, "zed_disk_event_init");
+
+       return (0);
+}
+
+void
+zed_disk_event_fini()
+{
+       /* cancel monitor thread at recvmsg() */
+       (void) pthread_cancel(g_mon_tid);
+       (void) pthread_join(g_mon_tid, NULL);
+
+       /* cleanup udev resources */
+       udev_monitor_unref(g_mon);
+       udev_unref(g_udev);
+
+       zed_log_msg(LOG_INFO, "zed_disk_event_fini");
+}
+
+#else
+
+#include "zed_disk_event.h"
+
+int
+zed_disk_event_init()
+{
+       return (0);
+}
+
+void
+zed_disk_event_fini()
+{
+}
+
+#endif /* HAVE_LIBUDEV */
diff --git a/zfs/cmd/zed/zed_disk_event.h b/zfs/cmd/zed/zed_disk_event.h
new file mode 100644 (file)
index 0000000..ea9813d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2016, Intel Corporation.
+ */
+
+#ifndef        ZED_DISK_EVENT_H
+#define        ZED_DISK_EVENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int zed_disk_event_init(void);
+extern void zed_disk_event_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !ZED_DISK_EVENT_H */
diff --git a/zfs/cmd/zed/zed_event.c b/zfs/cmd/zed/zed_event.c
new file mode 100644 (file)
index 0000000..2c97b71
--- /dev/null
@@ -0,0 +1,926 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libzfs.h>                    /* FIXME: Replace with libzfs_core. */
+#include <paths.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/zfs_ioctl.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/fm/fs/zfs.h>
+#include "zed.h"
+#include "zed_conf.h"
+#include "zed_disk_event.h"
+#include "zed_exec.h"
+#include "zed_file.h"
+#include "zed_log.h"
+#include "zed_strings.h"
+
+#include "agents/zfs_agents.h"
+
+#define        MAXBUF  4096
+
+/*
+ * Open the libzfs interface.
+ */
+void
+zed_event_init(struct zed_conf *zcp)
+{
+       if (!zcp)
+               zed_log_die("Failed zed_event_init: %s", strerror(EINVAL));
+
+       zcp->zfs_hdl = libzfs_init();
+       if (!zcp->zfs_hdl)
+               zed_log_die("Failed to initialize libzfs");
+
+       zcp->zevent_fd = open(ZFS_DEV, O_RDWR);
+       if (zcp->zevent_fd < 0)
+               zed_log_die("Failed to open \"%s\": %s",
+                   ZFS_DEV, strerror(errno));
+
+       if (zfs_slm_init(zcp->zfs_hdl) != 0)
+               zed_log_die("Failed to initialize zfs slm");
+       if (zfs_diagnosis_init(zcp->zfs_hdl) != 0)
+               zed_log_die("Failed to initialize zfs diagnosis");
+       if (zfs_retire_init(zcp->zfs_hdl) != 0)
+               zed_log_die("Failed to initialize zfs retire");
+       if (zed_disk_event_init() != 0)
+               zed_log_die("Failed to initialize disk events");
+}
+
+/*
+ * Close the libzfs interface.
+ */
+void
+zed_event_fini(struct zed_conf *zcp)
+{
+       if (!zcp)
+               zed_log_die("Failed zed_event_fini: %s", strerror(EINVAL));
+
+       zed_disk_event_fini();
+       zfs_retire_fini();
+       zfs_diagnosis_fini();
+       zfs_slm_fini();
+
+       if (zcp->zevent_fd >= 0) {
+               if (close(zcp->zevent_fd) < 0)
+                       zed_log_msg(LOG_WARNING, "Failed to close \"%s\": %s",
+                           ZFS_DEV, strerror(errno));
+
+               zcp->zevent_fd = -1;
+       }
+       if (zcp->zfs_hdl) {
+               libzfs_fini(zcp->zfs_hdl);
+               zcp->zfs_hdl = NULL;
+       }
+}
+
+/*
+ * Seek to the event specified by [saved_eid] and [saved_etime].
+ * This protects against processing a given event more than once.
+ * Return 0 upon a successful seek to the specified event, or -1 otherwise.
+ *
+ * A zevent is considered to be uniquely specified by its (eid,time) tuple.
+ * The unsigned 64b eid is set to 1 when the kernel module is loaded, and
+ * incremented by 1 for each new event.  Since the state file can persist
+ * across a kernel module reload, the time must be checked to ensure a match.
+ */
+int
+zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid, int64_t saved_etime[])
+{
+       uint64_t eid;
+       int found;
+       nvlist_t *nvl;
+       int n_dropped;
+       int64_t *etime;
+       uint_t nelem;
+       int rv;
+
+       if (!zcp) {
+               errno = EINVAL;
+               zed_log_msg(LOG_ERR, "Failed to seek zevent: %s",
+                   strerror(errno));
+               return (-1);
+       }
+       eid = 0;
+       found = 0;
+       while ((eid < saved_eid) && !found) {
+               rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped,
+                   ZEVENT_NONBLOCK, zcp->zevent_fd);
+
+               if ((rv != 0) || !nvl)
+                       break;
+
+               if (n_dropped > 0) {
+                       zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
+                       /*
+                        * FIXME: Increase max size of event nvlist in
+                        *   /sys/module/zfs/parameters/zfs_zevent_len_max ?
+                        */
+               }
+               if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
+                       zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
+               } else if (nvlist_lookup_int64_array(nvl, "time",
+                   &etime, &nelem) != 0) {
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to lookup zevent time (eid=%llu)", eid);
+               } else if (nelem != 2) {
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to lookup zevent time (eid=%llu, nelem=%u)",
+                           eid, nelem);
+               } else if ((eid != saved_eid) ||
+                   (etime[0] != saved_etime[0]) ||
+                   (etime[1] != saved_etime[1])) {
+                       /* no-op */
+               } else {
+                       found = 1;
+               }
+               free(nvl);
+       }
+       if (!found && (saved_eid > 0)) {
+               if (zpool_events_seek(zcp->zfs_hdl, ZEVENT_SEEK_START,
+                   zcp->zevent_fd) < 0)
+                       zed_log_msg(LOG_WARNING, "Failed to seek to eid=0");
+               else
+                       eid = 0;
+       }
+       zed_log_msg(LOG_NOTICE, "Processing events since eid=%llu", eid);
+       return (found ? 0 : -1);
+}
+
+/*
+ * Return non-zero if nvpair [name] should be formatted in hex; o/w, return 0.
+ */
+static int
+_zed_event_value_is_hex(const char *name)
+{
+       const char *hex_suffix[] = {
+               "_guid",
+               "_guids",
+               NULL
+       };
+       const char **pp;
+       char *p;
+
+       if (!name)
+               return (0);
+
+       for (pp = hex_suffix; *pp; pp++) {
+               p = strstr(name, *pp);
+               if (p && strlen(p) == strlen(*pp))
+                       return (1);
+       }
+       return (0);
+}
+
+/*
+ * Add an environment variable for [eid] to the container [zsp].
+ *
+ * The variable name is the concatenation of [prefix] and [name] converted to
+ * uppercase with non-alphanumeric characters converted to underscores;
+ * [prefix] is optional, and [name] must begin with an alphabetic character.
+ * If the converted variable name already exists within the container [zsp],
+ * its existing value will be replaced with the new value.
+ *
+ * The variable value is specified by the format string [fmt].
+ *
+ * Returns 0 on success, and -1 on error (with errno set).
+ *
+ * All environment variables in [zsp] should be added through this function.
+ */
+static int
+_zed_event_add_var(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, const char *name, const char *fmt, ...)
+{
+       char keybuf[MAXBUF];
+       char valbuf[MAXBUF];
+       char *dstp;
+       const char *srcp;
+       const char *lastp;
+       int n;
+       int buflen;
+       va_list vargs;
+
+       assert(zsp != NULL);
+       assert(fmt != NULL);
+
+       if (!name) {
+               errno = EINVAL;
+               zed_log_msg(LOG_WARNING,
+                   "Failed to add variable for eid=%llu: Name is empty", eid);
+               return (-1);
+       } else if (!isalpha(name[0])) {
+               errno = EINVAL;
+               zed_log_msg(LOG_WARNING,
+                   "Failed to add variable for eid=%llu: "
+                   "Name \"%s\" is invalid", eid, name);
+               return (-1);
+       }
+       /*
+        * Construct the string key by converting PREFIX (if present) and NAME.
+        */
+       dstp = keybuf;
+       lastp = keybuf + sizeof (keybuf);
+       if (prefix) {
+               for (srcp = prefix; *srcp && (dstp < lastp); srcp++)
+                       *dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_';
+       }
+       for (srcp = name; *srcp && (dstp < lastp); srcp++)
+               *dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_';
+
+       if (dstp == lastp) {
+               errno = ENAMETOOLONG;
+               zed_log_msg(LOG_WARNING,
+                   "Failed to add variable for eid=%llu: Name too long", eid);
+               return (-1);
+       }
+       *dstp = '\0';
+       /*
+        * Construct the string specified by "[PREFIX][NAME]=[FMT]".
+        */
+       dstp = valbuf;
+       buflen = sizeof (valbuf);
+       n = strlcpy(dstp, keybuf, buflen);
+       if (n >= sizeof (valbuf)) {
+               errno = EMSGSIZE;
+               zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
+                   keybuf, eid, "Exceeded buffer size");
+               return (-1);
+       }
+       dstp += n;
+       buflen -= n;
+
+       *dstp++ = '=';
+       buflen--;
+
+       va_start(vargs, fmt);
+       n = vsnprintf(dstp, buflen, fmt, vargs);
+       va_end(vargs);
+
+       if ((n < 0) || (n >= buflen)) {
+               errno = EMSGSIZE;
+               zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
+                   keybuf, eid, "Exceeded buffer size");
+               return (-1);
+       } else if (zed_strings_add(zsp, keybuf, valbuf) < 0) {
+               zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
+                   keybuf, eid, strerror(errno));
+               return (-1);
+       }
+       return (0);
+}
+
+static int
+_zed_event_add_array_err(uint64_t eid, const char *name)
+{
+       errno = EMSGSIZE;
+       zed_log_msg(LOG_WARNING,
+           "Failed to convert nvpair \"%s\" for eid=%llu: "
+           "Exceeded buffer size", name, eid);
+       return (-1);
+}
+
+static int
+_zed_event_add_int8_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       int8_t *i8p;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT8_ARRAY));
+
+       name = nvpair_name(nvp);
+       (void) nvpair_value_int8_array(nvp, &i8p, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, "%d ", i8p[i]);
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+static int
+_zed_event_add_uint8_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       uint8_t *u8p;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT8_ARRAY));
+
+       name = nvpair_name(nvp);
+       (void) nvpair_value_uint8_array(nvp, &u8p, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, "%u ", u8p[i]);
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+static int
+_zed_event_add_int16_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       int16_t *i16p;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT16_ARRAY));
+
+       name = nvpair_name(nvp);
+       (void) nvpair_value_int16_array(nvp, &i16p, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, "%d ", i16p[i]);
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+static int
+_zed_event_add_uint16_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       uint16_t *u16p;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT16_ARRAY));
+
+       name = nvpair_name(nvp);
+       (void) nvpair_value_uint16_array(nvp, &u16p, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, "%u ", u16p[i]);
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+static int
+_zed_event_add_int32_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       int32_t *i32p;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT32_ARRAY));
+
+       name = nvpair_name(nvp);
+       (void) nvpair_value_int32_array(nvp, &i32p, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, "%d ", i32p[i]);
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+static int
+_zed_event_add_uint32_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       uint32_t *u32p;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT32_ARRAY));
+
+       name = nvpair_name(nvp);
+       (void) nvpair_value_uint32_array(nvp, &u32p, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, "%u ", u32p[i]);
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+static int
+_zed_event_add_int64_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       int64_t *i64p;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_INT64_ARRAY));
+
+       name = nvpair_name(nvp);
+       (void) nvpair_value_int64_array(nvp, &i64p, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, "%lld ", (u_longlong_t) i64p[i]);
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+static int
+_zed_event_add_uint64_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       const char *fmt;
+       uint64_t *u64p;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_UINT64_ARRAY));
+
+       name = nvpair_name(nvp);
+       fmt = _zed_event_value_is_hex(name) ? "0x%.16llX " : "%llu ";
+       (void) nvpair_value_uint64_array(nvp, &u64p, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, fmt, (u_longlong_t) u64p[i]);
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+static int
+_zed_event_add_string_array(uint64_t eid, zed_strings_t *zsp,
+    const char *prefix, nvpair_t *nvp)
+{
+       char buf[MAXBUF];
+       int buflen = sizeof (buf);
+       const char *name;
+       char **strp;
+       uint_t nelem;
+       uint_t i;
+       char *p;
+       int n;
+
+       assert((nvp != NULL) && (nvpair_type(nvp) == DATA_TYPE_STRING_ARRAY));
+
+       name = nvpair_name(nvp);
+       (void) nvpair_value_string_array(nvp, &strp, &nelem);
+       for (i = 0, p = buf; (i < nelem) && (buflen > 0); i++) {
+               n = snprintf(p, buflen, "%s ", strp[i] ? strp[i] : "<NULL>");
+               if ((n < 0) || (n >= buflen))
+                       return (_zed_event_add_array_err(eid, name));
+               p += n;
+               buflen -= n;
+       }
+       if (nelem > 0)
+               *--p = '\0';
+
+       return (_zed_event_add_var(eid, zsp, prefix, name, "%s", buf));
+}
+
+/*
+ * Convert the nvpair [nvp] to a string which is added to the environment
+ * of the child process.
+ * Return 0 on success, -1 on error.
+ *
+ * FIXME: Refactor with cmd/zpool/zpool_main.c:zpool_do_events_nvprint()?
+ */
+static void
+_zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
+{
+       const char *name;
+       data_type_t type;
+       const char *prefix = ZEVENT_VAR_PREFIX;
+       boolean_t b;
+       double d;
+       uint8_t i8;
+       uint16_t i16;
+       uint32_t i32;
+       uint64_t i64;
+       char *str;
+
+       assert(zsp != NULL);
+       assert(nvp != NULL);
+
+       name = nvpair_name(nvp);
+       type = nvpair_type(nvp);
+
+       switch (type) {
+       case DATA_TYPE_BOOLEAN:
+               _zed_event_add_var(eid, zsp, prefix, name, "%s", "1");
+               break;
+       case DATA_TYPE_BOOLEAN_VALUE:
+               (void) nvpair_value_boolean_value(nvp, &b);
+               _zed_event_add_var(eid, zsp, prefix, name, "%s", b ? "1" : "0");
+               break;
+       case DATA_TYPE_BYTE:
+               (void) nvpair_value_byte(nvp, &i8);
+               _zed_event_add_var(eid, zsp, prefix, name, "%d", i8);
+               break;
+       case DATA_TYPE_INT8:
+               (void) nvpair_value_int8(nvp, (int8_t *) &i8);
+               _zed_event_add_var(eid, zsp, prefix, name, "%d", i8);
+               break;
+       case DATA_TYPE_UINT8:
+               (void) nvpair_value_uint8(nvp, &i8);
+               _zed_event_add_var(eid, zsp, prefix, name, "%u", i8);
+               break;
+       case DATA_TYPE_INT16:
+               (void) nvpair_value_int16(nvp, (int16_t *) &i16);
+               _zed_event_add_var(eid, zsp, prefix, name, "%d", i16);
+               break;
+       case DATA_TYPE_UINT16:
+               (void) nvpair_value_uint16(nvp, &i16);
+               _zed_event_add_var(eid, zsp, prefix, name, "%u", i16);
+               break;
+       case DATA_TYPE_INT32:
+               (void) nvpair_value_int32(nvp, (int32_t *) &i32);
+               _zed_event_add_var(eid, zsp, prefix, name, "%d", i32);
+               break;
+       case DATA_TYPE_UINT32:
+               (void) nvpair_value_uint32(nvp, &i32);
+               _zed_event_add_var(eid, zsp, prefix, name, "%u", i32);
+               break;
+       case DATA_TYPE_INT64:
+               (void) nvpair_value_int64(nvp, (int64_t *) &i64);
+               _zed_event_add_var(eid, zsp, prefix, name,
+                   "%lld", (longlong_t) i64);
+               break;
+       case DATA_TYPE_UINT64:
+               (void) nvpair_value_uint64(nvp, &i64);
+               _zed_event_add_var(eid, zsp, prefix, name,
+                   (_zed_event_value_is_hex(name) ? "0x%.16llX" : "%llu"),
+                   (u_longlong_t) i64);
+               /*
+                * shadow readable strings for vdev state pairs
+                */
+               if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE) == 0 ||
+                   strcmp(name, FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE) == 0) {
+                       char alt[32];
+
+                       (void) snprintf(alt, sizeof (alt), "%s_str", name);
+                       _zed_event_add_var(eid, zsp, prefix, alt, "%s",
+                           zpool_state_to_name(i64, VDEV_AUX_NONE));
+               }
+               break;
+       case DATA_TYPE_DOUBLE:
+               (void) nvpair_value_double(nvp, &d);
+               _zed_event_add_var(eid, zsp, prefix, name, "%g", d);
+               break;
+       case DATA_TYPE_HRTIME:
+               (void) nvpair_value_hrtime(nvp, (hrtime_t *) &i64);
+               _zed_event_add_var(eid, zsp, prefix, name,
+                   "%llu", (u_longlong_t) i64);
+               break;
+       case DATA_TYPE_NVLIST:
+               _zed_event_add_var(eid, zsp, prefix, name,
+                   "%s", "_NOT_IMPLEMENTED_");                 /* FIXME */
+               break;
+       case DATA_TYPE_STRING:
+               (void) nvpair_value_string(nvp, &str);
+               _zed_event_add_var(eid, zsp, prefix, name,
+                   "%s", (str ? str : "<NULL>"));
+               break;
+       case DATA_TYPE_BOOLEAN_ARRAY:
+               _zed_event_add_var(eid, zsp, prefix, name,
+                   "%s", "_NOT_IMPLEMENTED_");                 /* FIXME */
+               break;
+       case DATA_TYPE_BYTE_ARRAY:
+               _zed_event_add_var(eid, zsp, prefix, name,
+                   "%s", "_NOT_IMPLEMENTED_");                 /* FIXME */
+               break;
+       case DATA_TYPE_INT8_ARRAY:
+               _zed_event_add_int8_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_UINT8_ARRAY:
+               _zed_event_add_uint8_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_INT16_ARRAY:
+               _zed_event_add_int16_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_UINT16_ARRAY:
+               _zed_event_add_uint16_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_INT32_ARRAY:
+               _zed_event_add_int32_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_UINT32_ARRAY:
+               _zed_event_add_uint32_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_INT64_ARRAY:
+               _zed_event_add_int64_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_UINT64_ARRAY:
+               _zed_event_add_uint64_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_STRING_ARRAY:
+               _zed_event_add_string_array(eid, zsp, prefix, nvp);
+               break;
+       case DATA_TYPE_NVLIST_ARRAY:
+               _zed_event_add_var(eid, zsp, prefix, name,
+                   "%s", "_NOT_IMPLEMENTED_");                 /* FIXME */
+               break;
+       default:
+               errno = EINVAL;
+               zed_log_msg(LOG_WARNING,
+                   "Failed to convert nvpair \"%s\" for eid=%llu: "
+                   "Unrecognized type=%u", name, eid, (unsigned int) type);
+               break;
+       }
+}
+
+/*
+ * Restrict various environment variables to safe and sane values
+ * when constructing the environment for the child process.
+ *
+ * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
+ */
+static void
+_zed_event_add_env_restrict(uint64_t eid, zed_strings_t *zsp)
+{
+       const char *env_restrict[][2] = {
+               { "IFS",                " \t\n" },
+               { "PATH",               _PATH_STDPATH },
+               { "ZDB",                SBINDIR "/zdb" },
+               { "ZED",                SBINDIR "/zed" },
+               { "ZFS",                SBINDIR "/zfs" },
+               { "ZINJECT",            SBINDIR "/zinject" },
+               { "ZPOOL",              SBINDIR "/zpool" },
+               { "ZFS_ALIAS",          ZFS_META_ALIAS },
+               { "ZFS_VERSION",        ZFS_META_VERSION },
+               { "ZFS_RELEASE",        ZFS_META_RELEASE },
+               { NULL,                 NULL }
+       };
+       const char *(*pa)[2];
+
+       assert(zsp != NULL);
+
+       for (pa = env_restrict; *(*pa); pa++) {
+               _zed_event_add_var(eid, zsp, NULL, (*pa)[0], "%s", (*pa)[1]);
+       }
+}
+
+/*
+ * Preserve specified variables from the parent environment
+ * when constructing the environment for the child process.
+ *
+ * Reference: Secure Programming Cookbook by Viega & Messier, Section 1.1.
+ */
+static void
+_zed_event_add_env_preserve(uint64_t eid, zed_strings_t *zsp)
+{
+       const char *env_preserve[] = {
+               "TZ",
+               NULL
+       };
+       const char **keyp;
+       const char *val;
+
+       assert(zsp != NULL);
+
+       for (keyp = env_preserve; *keyp; keyp++) {
+               if ((val = getenv(*keyp)))
+                       _zed_event_add_var(eid, zsp, NULL, *keyp, "%s", val);
+       }
+}
+
+/*
+ * Compute the "subclass" by removing the first 3 components of [class]
+ * (which will always be of the form "*.fs.zfs").  Return a pointer inside
+ * the string [class], or NULL if insufficient components exist.
+ */
+static const char *
+_zed_event_get_subclass(const char *class)
+{
+       const char *p;
+       int i;
+
+       if (!class)
+               return (NULL);
+
+       p = class;
+       for (i = 0; i < 3; i++) {
+               p = strchr(p, '.');
+               if (!p)
+                       break;
+               p++;
+       }
+       return (p);
+}
+
+/*
+ * Convert the zevent time from a 2-element array of 64b integers
+ * into a more convenient form:
+ * - TIME_SECS is the second component of the time.
+ * - TIME_NSECS is the nanosecond component of the time.
+ * - TIME_STRING is an almost-RFC3339-compliant string representation.
+ */
+static void
+_zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
+{
+       struct tm *stp;
+       char buf[32];
+
+       assert(zsp != NULL);
+       assert(etime != NULL);
+
+       _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_SECS",
+           "%lld", (long long int) etime[0]);
+       _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_NSECS",
+           "%lld", (long long int) etime[1]);
+
+       if (!(stp = localtime((const time_t *) &etime[0]))) {
+               zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
+                   ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "localtime error");
+       } else if (!strftime(buf, sizeof (buf), "%Y-%m-%d %H:%M:%S%z", stp)) {
+               zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
+                   ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "strftime error");
+       } else {
+               _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_STRING",
+                   "%s", buf);
+       }
+}
+
+static void
+_zed_internal_event(const char *class, nvlist_t *nvl)
+{
+       /*
+        * NOTE: only vdev check is handled for now
+        */
+       if (strcmp(class, "sysevent.fs.zfs.vdev_check") == 0) {
+               (void) zfs_slm_event("EC_zfs", "ESC_ZFS_vdev_check", nvl);
+       }
+}
+
+/*
+ * Service the next zevent, blocking until one is available.
+ */
+void
+zed_event_service(struct zed_conf *zcp)
+{
+       nvlist_t *nvl;
+       nvpair_t *nvp;
+       int n_dropped;
+       zed_strings_t *zsp;
+       uint64_t eid;
+       int64_t *etime;
+       uint_t nelem;
+       char *class;
+       const char *subclass;
+       int rv;
+
+       if (!zcp) {
+               errno = EINVAL;
+               zed_log_msg(LOG_ERR, "Failed to service zevent: %s",
+                   strerror(errno));
+               return;
+       }
+       rv = zpool_events_next(zcp->zfs_hdl, &nvl, &n_dropped, ZEVENT_NONE,
+           zcp->zevent_fd);
+
+       if ((rv != 0) || !nvl)
+               return;
+
+       if (n_dropped > 0) {
+               zed_log_msg(LOG_WARNING, "Missed %d events", n_dropped);
+               /*
+                * FIXME: Increase max size of event nvlist in
+                * /sys/module/zfs/parameters/zfs_zevent_len_max ?
+                */
+       }
+       if (nvlist_lookup_uint64(nvl, "eid", &eid) != 0) {
+               zed_log_msg(LOG_WARNING, "Failed to lookup zevent eid");
+       } else if (nvlist_lookup_int64_array(
+           nvl, "time", &etime, &nelem) != 0) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to lookup zevent time (eid=%llu)", eid);
+       } else if (nelem != 2) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to lookup zevent time (eid=%llu, nelem=%u)",
+                   eid, nelem);
+       } else if (nvlist_lookup_string(nvl, "class", &class) != 0) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to lookup zevent class (eid=%llu)", eid);
+       } else {
+               /* let internal modules see this event first */
+               _zed_internal_event(class, nvl);
+
+               zsp = zed_strings_create();
+
+               nvp = NULL;
+               while ((nvp = nvlist_next_nvpair(nvl, nvp)))
+                       _zed_event_add_nvpair(eid, zsp, nvp);
+
+               _zed_event_add_env_restrict(eid, zsp);
+               _zed_event_add_env_preserve(eid, zsp);
+
+               _zed_event_add_var(eid, zsp, ZED_VAR_PREFIX, "PID",
+                   "%d", (int) getpid());
+               _zed_event_add_var(eid, zsp, ZED_VAR_PREFIX, "ZEDLET_DIR",
+                   "%s", zcp->zedlet_dir);
+               subclass = _zed_event_get_subclass(class);
+               _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "SUBCLASS",
+                   "%s", (subclass ? subclass : class));
+
+               _zed_event_add_time_strings(eid, zsp, etime);
+
+               zed_exec_process(eid, class, subclass,
+                   zcp->zedlet_dir, zcp->zedlets, zsp, zcp->zevent_fd);
+
+               zed_conf_write_state(zcp, eid, etime);
+
+               zed_strings_destroy(zsp);
+       }
+       nvlist_free(nvl);
+}
diff --git a/zfs/cmd/zed/zed_event.h b/zfs/cmd/zed/zed_event.h
new file mode 100644 (file)
index 0000000..9f37b80
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#ifndef        ZED_EVENT_H
+#define        ZED_EVENT_H
+
+#include <stdint.h>
+
+void zed_event_init(struct zed_conf *zcp);
+
+void zed_event_fini(struct zed_conf *zcp);
+
+int zed_event_seek(struct zed_conf *zcp, uint64_t saved_eid,
+    int64_t saved_etime[]);
+
+void zed_event_service(struct zed_conf *zcp);
+
+#endif /* !ZED_EVENT_H */
diff --git a/zfs/cmd/zed/zed_exec.c b/zfs/cmd/zed/zed_exec.c
new file mode 100644 (file)
index 0000000..1a3b76d
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "zed_file.h"
+#include "zed_log.h"
+#include "zed_strings.h"
+
+#define        ZEVENT_FILENO   3
+
+/*
+ * Create an environment string array for passing to execve() using the
+ * NAME=VALUE strings in container [zsp].
+ * Return a newly-allocated environment, or NULL on error.
+ */
+static char **
+_zed_exec_create_env(zed_strings_t *zsp)
+{
+       int num_ptrs;
+       int buflen;
+       char *buf;
+       char **pp;
+       char *p;
+       const char *q;
+       int i;
+       int len;
+
+       num_ptrs = zed_strings_count(zsp) + 1;
+       buflen = num_ptrs * sizeof (char *);
+       for (q = zed_strings_first(zsp); q; q = zed_strings_next(zsp))
+               buflen += strlen(q) + 1;
+
+       buf = calloc(1, buflen);
+       if (!buf)
+               return (NULL);
+
+       pp = (char **) buf;
+       p = buf + (num_ptrs * sizeof (char *));
+       i = 0;
+       for (q = zed_strings_first(zsp); q; q = zed_strings_next(zsp)) {
+               pp[i] = p;
+               len = strlen(q) + 1;
+               memcpy(p, q, len);
+               p += len;
+               i++;
+       }
+       pp[i] = NULL;
+       assert(buf + buflen == p);
+       return ((char **) buf);
+}
+
+/*
+ * Fork a child process to handle event [eid].  The program [prog]
+ * in directory [dir] is executed with the envionment [env].
+ *
+ * The file descriptor [zfd] is the zevent_fd used to track the
+ * current cursor location within the zevent nvlist.
+ */
+static void
+_zed_exec_fork_child(uint64_t eid, const char *dir, const char *prog,
+    char *env[], int zfd)
+{
+       char path[PATH_MAX];
+       int n;
+       pid_t pid;
+       int fd;
+       pid_t wpid;
+       int status;
+
+       assert(dir != NULL);
+       assert(prog != NULL);
+       assert(env != NULL);
+       assert(zfd >= 0);
+
+       n = snprintf(path, sizeof (path), "%s/%s", dir, prog);
+       if ((n < 0) || (n >= sizeof (path))) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to fork \"%s\" for eid=%llu: %s",
+                   prog, eid, strerror(ENAMETOOLONG));
+               return;
+       }
+       pid = fork();
+       if (pid < 0) {
+               zed_log_msg(LOG_WARNING,
+                   "Failed to fork \"%s\" for eid=%llu: %s",
+                   prog, eid, strerror(errno));
+               return;
+       } else if (pid == 0) {
+               (void) umask(022);
+               if ((fd = open("/dev/null", O_RDWR)) != -1) {
+                       (void) dup2(fd, STDIN_FILENO);
+                       (void) dup2(fd, STDOUT_FILENO);
+                       (void) dup2(fd, STDERR_FILENO);
+               }
+               (void) dup2(zfd, ZEVENT_FILENO);
+               zed_file_close_from(ZEVENT_FILENO + 1);
+               execle(path, prog, NULL, env);
+               _exit(127);
+       } else {
+               zed_log_msg(LOG_INFO, "Invoking \"%s\" eid=%llu pid=%d",
+                   prog, eid, pid);
+               /* FIXME: Timeout rogue child processes with sigalarm? */
+restart:
+               wpid = waitpid(pid, &status, 0);
+               if (wpid == (pid_t) -1) {
+                       if (errno == EINTR)
+                               goto restart;
+                       zed_log_msg(LOG_WARNING,
+                           "Failed to wait for \"%s\" eid=%llu pid=%d",
+                           prog, eid, pid);
+               } else if (WIFEXITED(status)) {
+                       zed_log_msg(LOG_INFO,
+                           "Finished \"%s\" eid=%llu pid=%d exit=%d",
+                           prog, eid, pid, WEXITSTATUS(status));
+               } else if (WIFSIGNALED(status)) {
+                       zed_log_msg(LOG_INFO,
+                           "Finished \"%s\" eid=%llu pid=%d sig=%d/%s",
+                           prog, eid, pid, WTERMSIG(status),
+                           strsignal(WTERMSIG(status)));
+               } else {
+                       zed_log_msg(LOG_INFO,
+                           "Finished \"%s\" eid=%llu pid=%d status=0x%X",
+                           prog, eid, (unsigned int) status);
+               }
+       }
+}
+
+/*
+ * Process the event [eid] by synchronously invoking all zedlets with a
+ * matching class prefix.
+ *
+ * Each executable in [zedlets] from the directory [dir] is matched against
+ * the event's [class], [subclass], and the "all" class (which matches
+ * all events).  Every zedlet with a matching class prefix is invoked.
+ * The NAME=VALUE strings in [envs] will be passed to the zedlet as
+ * environment variables.
+ *
+ * The file descriptor [zfd] is the zevent_fd used to track the
+ * current cursor location within the zevent nvlist.
+ *
+ * Return 0 on success, -1 on error.
+ */
+int
+zed_exec_process(uint64_t eid, const char *class, const char *subclass,
+    const char *dir, zed_strings_t *zedlets, zed_strings_t *envs, int zfd)
+{
+       const char *class_strings[4];
+       const char *allclass = "all";
+       const char **csp;
+       const char *z;
+       char **e;
+       int n;
+
+       if (!dir || !zedlets || !envs || zfd < 0)
+               return (-1);
+
+       csp = class_strings;
+
+       if (class)
+               *csp++ = class;
+
+       if (subclass)
+               *csp++ = subclass;
+
+       if (allclass)
+               *csp++ = allclass;
+
+       *csp = NULL;
+
+       e = _zed_exec_create_env(envs);
+
+       for (z = zed_strings_first(zedlets); z; z = zed_strings_next(zedlets)) {
+               for (csp = class_strings; *csp; csp++) {
+                       n = strlen(*csp);
+                       if ((strncmp(z, *csp, n) == 0) && !isalpha(z[n]))
+                               _zed_exec_fork_child(eid, dir, z, e, zfd);
+               }
+       }
+       free(e);
+       return (0);
+}
diff --git a/zfs/cmd/zed/zed_exec.h b/zfs/cmd/zed/zed_exec.h
new file mode 100644 (file)
index 0000000..69179c9
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#ifndef        ZED_EXEC_H
+#define        ZED_EXEC_H
+
+#include <stdint.h>
+
+int zed_exec_process(uint64_t eid, const char *class, const char *subclass,
+    const char *dir, zed_strings_t *zedlets, zed_strings_t *envs,
+    int zevent_fd);
+
+#endif /* !ZED_EXEC_H */
diff --git a/zfs/cmd/zed/zed_file.c b/zfs/cmd/zed/zed_file.c
new file mode 100644 (file)
index 0000000..3a1a661
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "zed_log.h"
+
+/*
+ * Read up to [n] bytes from [fd] into [buf].
+ * Return the number of bytes read, 0 on EOF, or -1 on error.
+ */
+ssize_t
+zed_file_read_n(int fd, void *buf, size_t n)
+{
+       unsigned char *p;
+       size_t n_left;
+       ssize_t n_read;
+
+       p = buf;
+       n_left = n;
+       while (n_left > 0) {
+               if ((n_read = read(fd, p, n_left)) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       else
+                               return (-1);
+
+               } else if (n_read == 0) {
+                       break;
+               }
+               n_left -= n_read;
+               p += n_read;
+       }
+       return (n - n_left);
+}
+
+/*
+ * Write [n] bytes from [buf] out to [fd].
+ * Return the number of bytes written, or -1 on error.
+ */
+ssize_t
+zed_file_write_n(int fd, void *buf, size_t n)
+{
+       const unsigned char *p;
+       size_t n_left;
+       ssize_t n_written;
+
+       p = buf;
+       n_left = n;
+       while (n_left > 0) {
+               if ((n_written = write(fd, p, n_left)) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       else
+                               return (-1);
+
+               }
+               n_left -= n_written;
+               p += n_written;
+       }
+       return (n);
+}
+
+/*
+ * Set an exclusive advisory lock on the open file descriptor [fd].
+ * Return 0 on success, 1 if a conflicting lock is held by another process,
+ * or -1 on error (with errno set).
+ */
+int
+zed_file_lock(int fd)
+{
+       struct flock lock;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+
+       if (fcntl(fd, F_SETLK, &lock) < 0) {
+               if ((errno == EACCES) || (errno == EAGAIN))
+                       return (1);
+
+               return (-1);
+       }
+       return (0);
+}
+
+/*
+ * Release an advisory lock held on the open file descriptor [fd].
+ * Return 0 on success, or -1 on error (with errno set).
+ */
+int
+zed_file_unlock(int fd)
+{
+       struct flock lock;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       lock.l_type = F_UNLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+
+       if (fcntl(fd, F_SETLK, &lock) < 0)
+               return (-1);
+
+       return (0);
+}
+
+/*
+ * Test whether an exclusive advisory lock could be obtained for the open
+ * file descriptor [fd].
+ * Return 0 if the file is not locked, >0 for the PID of another process
+ * holding a conflicting lock, or -1 on error (with errno set).
+ */
+pid_t
+zed_file_is_locked(int fd)
+{
+       struct flock lock;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+
+       if (fcntl(fd, F_GETLK, &lock) < 0)
+               return (-1);
+
+       if (lock.l_type == F_UNLCK)
+               return (0);
+
+       return (lock.l_pid);
+}
+
+/*
+ * Close all open file descriptors greater than or equal to [lowfd].
+ * Any errors encountered while closing file descriptors are ignored.
+ */
+void
+zed_file_close_from(int lowfd)
+{
+       const int maxfd_def = 256;
+       int errno_bak;
+       struct rlimit rl;
+       int maxfd;
+       int fd;
+
+       errno_bak = errno;
+
+       if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
+               maxfd = maxfd_def;
+       } else if (rl.rlim_max == RLIM_INFINITY) {
+               maxfd = maxfd_def;
+       } else {
+               maxfd = rl.rlim_max;
+       }
+       for (fd = lowfd; fd < maxfd; fd++)
+               (void) close(fd);
+
+       errno = errno_bak;
+}
+
+/*
+ * Set the CLOEXEC flag on file descriptor [fd] so it will be automatically
+ * closed upon successful execution of one of the exec functions.
+ * Return 0 on success, or -1 on error.
+ *
+ * FIXME: No longer needed?
+ */
+int
+zed_file_close_on_exec(int fd)
+{
+       int flags;
+
+       if (fd < 0) {
+               errno = EBADF;
+               return (-1);
+       }
+       flags = fcntl(fd, F_GETFD);
+       if (flags == -1)
+               return (-1);
+
+       flags |= FD_CLOEXEC;
+
+       if (fcntl(fd, F_SETFD, flags) == -1)
+               return (-1);
+
+       return (0);
+}
diff --git a/zfs/cmd/zed/zed_file.h b/zfs/cmd/zed/zed_file.h
new file mode 100644 (file)
index 0000000..05f360d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#ifndef        ZED_FILE_H
+#define        ZED_FILE_H
+
+#include <sys/types.h>
+#include <unistd.h>
+
+ssize_t zed_file_read_n(int fd, void *buf, size_t n);
+
+ssize_t zed_file_write_n(int fd, void *buf, size_t n);
+
+int zed_file_lock(int fd);
+
+int zed_file_unlock(int fd);
+
+pid_t zed_file_is_locked(int fd);
+
+void zed_file_close_from(int fd);
+
+int zed_file_close_on_exec(int fd);
+
+#endif /* !ZED_FILE_H */
diff --git a/zfs/cmd/zed/zed_log.c b/zfs/cmd/zed/zed_log.c
new file mode 100644 (file)
index 0000000..ae1e2cd
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include "zed_log.h"
+
+#define        ZED_LOG_MAX_LOG_LEN     1024
+
+static struct {
+       unsigned do_stderr:1;
+       unsigned do_syslog:1;
+       const char *identity;
+       int priority;
+       int pipe_fd[2];
+} _ctx;
+
+/*
+ * Initialize the logging subsystem.
+ */
+void
+zed_log_init(const char *identity)
+{
+       if (identity) {
+               const char *p = strrchr(identity, '/');
+               _ctx.identity = (p != NULL) ? p + 1 : identity;
+       } else {
+               _ctx.identity = NULL;
+       }
+       _ctx.pipe_fd[0] = -1;
+       _ctx.pipe_fd[1] = -1;
+}
+
+/*
+ * Shutdown the logging subsystem.
+ */
+void
+zed_log_fini(void)
+{
+       zed_log_stderr_close();
+       zed_log_syslog_close();
+}
+
+/*
+ * Create pipe for communicating daemonization status between the parent and
+ * child processes across the double-fork().
+ */
+void
+zed_log_pipe_open(void)
+{
+       if ((_ctx.pipe_fd[0] != -1) || (_ctx.pipe_fd[1] != -1))
+               zed_log_die("Invalid use of zed_log_pipe_open in PID %d",
+                   (int) getpid());
+
+       if (pipe(_ctx.pipe_fd) < 0)
+               zed_log_die("Failed to create daemonize pipe in PID %d: %s",
+                   (int) getpid(), strerror(errno));
+}
+
+/*
+ * Close the read-half of the daemonize pipe.
+ *
+ * This should be called by the child after fork()ing from the parent since
+ * the child will never read from this pipe.
+ */
+void
+zed_log_pipe_close_reads(void)
+{
+       if (_ctx.pipe_fd[0] < 0)
+               zed_log_die(
+                   "Invalid use of zed_log_pipe_close_reads in PID %d",
+                   (int) getpid());
+
+       if (close(_ctx.pipe_fd[0]) < 0)
+               zed_log_die(
+                   "Failed to close reads on daemonize pipe in PID %d: %s",
+                   (int) getpid(), strerror(errno));
+
+       _ctx.pipe_fd[0] = -1;
+}
+
+/*
+ * Close the write-half of the daemonize pipe.
+ *
+ * This should be called by the parent after fork()ing its child since the
+ * parent will never write to this pipe.
+ *
+ * This should also be called by the child once initialization is complete
+ * in order to signal the parent that it can safely exit.
+ */
+void
+zed_log_pipe_close_writes(void)
+{
+       if (_ctx.pipe_fd[1] < 0)
+               zed_log_die(
+                   "Invalid use of zed_log_pipe_close_writes in PID %d",
+                   (int) getpid());
+
+       if (close(_ctx.pipe_fd[1]) < 0)
+               zed_log_die(
+                   "Failed to close writes on daemonize pipe in PID %d: %s",
+                   (int) getpid(), strerror(errno));
+
+       _ctx.pipe_fd[1] = -1;
+}
+
+/*
+ * Block on reading from the daemonize pipe until signaled by the child
+ * (via zed_log_pipe_close_writes()) that initialization is complete.
+ *
+ * This should only be called by the parent while waiting to exit after
+ * fork()ing the child.
+ */
+void
+zed_log_pipe_wait(void)
+{
+       ssize_t n;
+       char c;
+
+       if (_ctx.pipe_fd[0] < 0)
+               zed_log_die("Invalid use of zed_log_pipe_wait in PID %d",
+                   (int) getpid());
+
+       for (;;) {
+               n = read(_ctx.pipe_fd[0], &c, sizeof (c));
+               if (n < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       zed_log_die(
+                           "Failed to read from daemonize pipe in PID %d: %s",
+                           (int) getpid(), strerror(errno));
+               }
+               if (n == 0) {
+                       break;
+               }
+       }
+}
+
+/*
+ * Start logging messages at the syslog [priority] level or higher to stderr.
+ * Refer to syslog(3) for valid priority values.
+ */
+void
+zed_log_stderr_open(int priority)
+{
+       _ctx.do_stderr = 1;
+       _ctx.priority = priority;
+}
+
+/*
+ * Stop logging messages to stderr.
+ */
+void
+zed_log_stderr_close(void)
+{
+       if (_ctx.do_stderr)
+               _ctx.do_stderr = 0;
+}
+
+/*
+ * Start logging messages to syslog.
+ * Refer to syslog(3) for valid option/facility values.
+ */
+void
+zed_log_syslog_open(int facility)
+{
+       _ctx.do_syslog = 1;
+       openlog(_ctx.identity, LOG_NDELAY | LOG_PID, facility);
+}
+
+/*
+ * Stop logging messages to syslog.
+ */
+void
+zed_log_syslog_close(void)
+{
+       if (_ctx.do_syslog) {
+               _ctx.do_syslog = 0;
+               closelog();
+       }
+}
+
+/*
+ * Auxiliary function to log a message to syslog and/or stderr.
+ */
+static void
+_zed_log_aux(int priority, const char *fmt, va_list vargs)
+{
+       char buf[ZED_LOG_MAX_LOG_LEN];
+       int n;
+
+       if (!fmt)
+               return;
+
+       n = vsnprintf(buf, sizeof (buf), fmt, vargs);
+       if ((n < 0) || (n >= sizeof (buf))) {
+               buf[sizeof (buf) - 2] = '+';
+               buf[sizeof (buf) - 1] = '\0';
+       }
+
+       if (_ctx.do_syslog)
+               syslog(priority, "%s", buf);
+
+       if (_ctx.do_stderr && (priority <= _ctx.priority))
+               fprintf(stderr, "%s\n", buf);
+}
+
+/*
+ * Log a message at the given [priority] level specified by the printf-style
+ * format string [fmt].
+ */
+void
+zed_log_msg(int priority, const char *fmt, ...)
+{
+       va_list vargs;
+
+       if (fmt) {
+               va_start(vargs, fmt);
+               _zed_log_aux(priority, fmt, vargs);
+               va_end(vargs);
+       }
+}
+
+/*
+ * Log a fatal error message specified by the printf-style format string [fmt].
+ */
+void
+zed_log_die(const char *fmt, ...)
+{
+       va_list vargs;
+
+       if (fmt) {
+               va_start(vargs, fmt);
+               _zed_log_aux(LOG_ERR, fmt, vargs);
+               va_end(vargs);
+       }
+       exit(EXIT_FAILURE);
+}
diff --git a/zfs/cmd/zed/zed_log.h b/zfs/cmd/zed/zed_log.h
new file mode 100644 (file)
index 0000000..a03a4f5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#ifndef        ZED_LOG_H
+#define        ZED_LOG_H
+
+#include <syslog.h>
+
+void zed_log_init(const char *identity);
+
+void zed_log_fini(void);
+
+void zed_log_pipe_open(void);
+
+void zed_log_pipe_close_reads(void);
+
+void zed_log_pipe_close_writes(void);
+
+void zed_log_pipe_wait(void);
+
+void zed_log_stderr_open(int priority);
+
+void zed_log_stderr_close(void);
+
+void zed_log_syslog_open(int facility);
+
+void zed_log_syslog_close(void);
+
+void zed_log_msg(int priority, const char *fmt, ...);
+
+void zed_log_die(const char *fmt, ...);
+
+#endif /* !ZED_LOG_H */
diff --git a/zfs/cmd/zed/zed_strings.c b/zfs/cmd/zed/zed_strings.c
new file mode 100644 (file)
index 0000000..6942e9f
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/avl.h>
+#include <sys/sysmacros.h>
+#include "zed_strings.h"
+
+struct zed_strings {
+       avl_tree_t tree;
+       avl_node_t *iteratorp;
+};
+
+struct zed_strings_node {
+       avl_node_t node;
+       char *key;
+       char *val;
+};
+
+typedef struct zed_strings_node zed_strings_node_t;
+
+/*
+ * Compare zed_strings_node_t nodes [x1] and [x2].
+ * As required for the AVL tree, return -1 for <, 0 for ==, and +1 for >.
+ */
+static int
+_zed_strings_node_compare(const void *x1, const void *x2)
+{
+       const char *s1;
+       const char *s2;
+       int rv;
+
+       assert(x1 != NULL);
+       assert(x2 != NULL);
+
+       s1 = ((const zed_strings_node_t *) x1)->key;
+       assert(s1 != NULL);
+       s2 = ((const zed_strings_node_t *) x2)->key;
+       assert(s2 != NULL);
+       rv = strcmp(s1, s2);
+
+       if (rv < 0)
+               return (-1);
+
+       if (rv > 0)
+               return (1);
+
+       return (0);
+}
+
+/*
+ * Return a new string container, or NULL on error.
+ */
+zed_strings_t *
+zed_strings_create(void)
+{
+       zed_strings_t *zsp;
+
+       zsp = calloc(1, sizeof (*zsp));
+       if (!zsp)
+               return (NULL);
+
+       avl_create(&zsp->tree, _zed_strings_node_compare,
+           sizeof (zed_strings_node_t), offsetof(zed_strings_node_t, node));
+
+       zsp->iteratorp = NULL;
+       return (zsp);
+}
+
+/*
+ * Destroy the string node [np].
+ */
+static void
+_zed_strings_node_destroy(zed_strings_node_t *np)
+{
+       if (!np)
+               return;
+
+       if (np->key) {
+               if (np->key != np->val)
+                       free(np->key);
+               np->key = NULL;
+       }
+       if (np->val) {
+               free(np->val);
+               np->val = NULL;
+       }
+       free(np);
+}
+
+/*
+ * Return a new string node for storing the string [val], or NULL on error.
+ * If [key] is specified, it will be used to index the node; otherwise,
+ * the string [val] will be used.
+ */
+zed_strings_node_t *
+_zed_strings_node_create(const char *key, const char *val)
+{
+       zed_strings_node_t *np;
+
+       assert(val != NULL);
+
+       np = calloc(1, sizeof (*np));
+       if (!np)
+               return (NULL);
+
+       np->val = strdup(val);
+       if (!np->val)
+               goto nomem;
+
+       if (key) {
+               np->key = strdup(key);
+               if (!np->key)
+                       goto nomem;
+       } else {
+               np->key = np->val;
+       }
+       return (np);
+
+nomem:
+       _zed_strings_node_destroy(np);
+       return (NULL);
+}
+
+/*
+ * Destroy the string container [zsp] and all nodes within.
+ */
+void
+zed_strings_destroy(zed_strings_t *zsp)
+{
+       void *cookie;
+       zed_strings_node_t *np;
+
+       if (!zsp)
+               return;
+
+       cookie = NULL;
+       while ((np = avl_destroy_nodes(&zsp->tree, &cookie)))
+               _zed_strings_node_destroy(np);
+
+       avl_destroy(&zsp->tree);
+       free(zsp);
+}
+
+/*
+ * Add a copy of the string [s] indexed by [key] to the container [zsp].
+ * If [key] already exists within the container [zsp], it will be replaced
+ * with the new string [s].
+ * If [key] is NULL, the string [s] will be used as the key.
+ * Return 0 on success, or -1 on error.
+ */
+int
+zed_strings_add(zed_strings_t *zsp, const char *key, const char *s)
+{
+       zed_strings_node_t *newp, *oldp;
+
+       if (!zsp || !s) {
+               errno = EINVAL;
+               return (-1);
+       }
+       if (key == s)
+               key = NULL;
+
+       newp = _zed_strings_node_create(key, s);
+       if (!newp)
+               return (-1);
+
+       oldp = avl_find(&zsp->tree, newp, NULL);
+       if (oldp) {
+               avl_remove(&zsp->tree, oldp);
+               _zed_strings_node_destroy(oldp);
+       }
+       avl_add(&zsp->tree, newp);
+       return (0);
+}
+
+/*
+ * Return the first string in container [zsp].
+ * Return NULL if there are no strings, or on error.
+ * This can be called multiple times to re-traverse [zsp].
+ * XXX: Not thread-safe.
+ */
+const char *
+zed_strings_first(zed_strings_t *zsp)
+{
+       if (!zsp) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       zsp->iteratorp = avl_first(&zsp->tree);
+       if (!zsp->iteratorp)
+               return (NULL);
+
+       return (((zed_strings_node_t *) zsp->iteratorp)->val);
+
+}
+
+/*
+ * Return the next string in container [zsp].
+ * Return NULL after the last string, or on error.
+ * This must be called after zed_strings_first().
+ * XXX: Not thread-safe.
+ */
+const char *
+zed_strings_next(zed_strings_t *zsp)
+{
+       if (!zsp) {
+               errno = EINVAL;
+               return (NULL);
+       }
+       if (!zsp->iteratorp)
+               return (NULL);
+
+       zsp->iteratorp = AVL_NEXT(&zsp->tree, zsp->iteratorp);
+       if (!zsp->iteratorp)
+               return (NULL);
+
+       return (((zed_strings_node_t *)zsp->iteratorp)->val);
+}
+
+/*
+ * Return the number of strings in container [zsp], or -1 on error.
+ */
+int
+zed_strings_count(zed_strings_t *zsp)
+{
+       if (!zsp) {
+               errno = EINVAL;
+               return (-1);
+       }
+       return (avl_numnodes(&zsp->tree));
+}
diff --git a/zfs/cmd/zed/zed_strings.h b/zfs/cmd/zed/zed_strings.h
new file mode 100644 (file)
index 0000000..6177c76
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the ZFS Event Daemon (ZED)
+ * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+ * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+ * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+ * Refer to the ZoL git commit log for authoritative copyright attribution.
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License Version 1.0 (CDDL-1.0).
+ * You can obtain a copy of the license from the top-level file
+ * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+ * You may not use this file except in compliance with the license.
+ */
+
+#ifndef        ZED_STRINGS_H
+#define        ZED_STRINGS_H
+
+typedef struct zed_strings zed_strings_t;
+
+zed_strings_t * zed_strings_create(void);
+
+void zed_strings_destroy(zed_strings_t *zsp);
+
+int zed_strings_add(zed_strings_t *zsp, const char *key, const char *s);
+
+const char * zed_strings_first(zed_strings_t *zsp);
+
+const char * zed_strings_next(zed_strings_t *zsp);
+
+int zed_strings_count(zed_strings_t *zsp);
+
+#endif /* !ZED_STRINGS_H */
diff --git a/zfs/cmd/zfs/Makefile.am b/zfs/cmd/zfs/Makefile.am
new file mode 100644 (file)
index 0000000..e409095
--- /dev/null
@@ -0,0 +1,22 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+sbin_PROGRAMS = zfs
+
+zfs_SOURCES = \
+       zfs_iter.c \
+       zfs_iter.h \
+       zfs_main.c \
+       zfs_util.h
+
+zfs_LDADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+
+zfs_LDFLAGS = -pthread
diff --git a/zfs/cmd/zfs/Makefile.in b/zfs/cmd/zfs/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zfs/zfs_iter.c b/zfs/cmd/zfs/zfs_iter.c
new file mode 100644 (file)
index 0000000..e7f1622
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ */
+
+#include <libintl.h>
+#include <libuutil.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <libzfs.h>
+
+#include "zfs_util.h"
+#include "zfs_iter.h"
+
+/*
+ * This is a private interface used to gather up all the datasets specified on
+ * the command line so that we can iterate over them in order.
+ *
+ * First, we iterate over all filesystems, gathering them together into an
+ * AVL tree.  We report errors for any explicitly specified datasets
+ * that we couldn't open.
+ *
+ * When finished, we have an AVL tree of ZFS handles.  We go through and execute
+ * the provided callback for each one, passing whatever data the user supplied.
+ */
+
+typedef struct zfs_node {
+       zfs_handle_t    *zn_handle;
+       uu_avl_node_t   zn_avlnode;
+} zfs_node_t;
+
+typedef struct callback_data {
+       uu_avl_t                *cb_avl;
+       int                     cb_flags;
+       zfs_type_t              cb_types;
+       zfs_sort_column_t       *cb_sortcol;
+       zprop_list_t            **cb_proplist;
+       int                     cb_depth_limit;
+       int                     cb_depth;
+       uint8_t                 cb_props_table[ZFS_NUM_PROPS];
+} callback_data_t;
+
+uu_avl_pool_t *avl_pool;
+
+/*
+ * Include snaps if they were requested or if this a zfs list where types
+ * were not specified and the "listsnapshots" property is set on this pool.
+ */
+static boolean_t
+zfs_include_snapshots(zfs_handle_t *zhp, callback_data_t *cb)
+{
+       zpool_handle_t *zph;
+
+       if ((cb->cb_flags & ZFS_ITER_PROP_LISTSNAPS) == 0)
+               return (cb->cb_types & ZFS_TYPE_SNAPSHOT);
+
+       zph = zfs_get_pool_handle(zhp);
+       return (zpool_get_prop_int(zph, ZPOOL_PROP_LISTSNAPS, NULL));
+}
+
+/*
+ * Called for each dataset.  If the object is of an appropriate type,
+ * add it to the avl tree and recurse over any children as necessary.
+ */
+static int
+zfs_callback(zfs_handle_t *zhp, void *data)
+{
+       callback_data_t *cb = data;
+       boolean_t dontclose = B_FALSE;
+       boolean_t include_snaps = zfs_include_snapshots(zhp, cb);
+       boolean_t include_bmarks = (cb->cb_types & ZFS_TYPE_BOOKMARK);
+
+       if ((zfs_get_type(zhp) & cb->cb_types) ||
+           ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) {
+               uu_avl_index_t idx;
+               zfs_node_t *node = safe_malloc(sizeof (zfs_node_t));
+
+               node->zn_handle = zhp;
+               uu_avl_node_init(node, &node->zn_avlnode, avl_pool);
+               if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol,
+                   &idx) == NULL) {
+                       if (cb->cb_proplist) {
+                               if ((*cb->cb_proplist) &&
+                                   !(*cb->cb_proplist)->pl_all)
+                                       zfs_prune_proplist(zhp,
+                                           cb->cb_props_table);
+
+                               if (zfs_expand_proplist(zhp, cb->cb_proplist,
+                                   (cb->cb_flags & ZFS_ITER_RECVD_PROPS),
+                                   (cb->cb_flags & ZFS_ITER_LITERAL_PROPS))
+                                   != 0) {
+                                       free(node);
+                                       return (-1);
+                               }
+                       }
+                       uu_avl_insert(cb->cb_avl, node, idx);
+                       dontclose = B_TRUE;
+               } else {
+                       free(node);
+               }
+       }
+
+       /*
+        * Recurse if necessary.
+        */
+       if (cb->cb_flags & ZFS_ITER_RECURSE &&
+           ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 ||
+           cb->cb_depth < cb->cb_depth_limit)) {
+               cb->cb_depth++;
+               if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM)
+                       (void) zfs_iter_filesystems(zhp, zfs_callback, data);
+               if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
+                   ZFS_TYPE_BOOKMARK)) == 0) && include_snaps)
+                       (void) zfs_iter_snapshots(zhp,
+                           (cb->cb_flags & ZFS_ITER_SIMPLE) != 0, zfs_callback,
+                           data);
+               if (((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT |
+                   ZFS_TYPE_BOOKMARK)) == 0) && include_bmarks)
+                       (void) zfs_iter_bookmarks(zhp, zfs_callback, data);
+               cb->cb_depth--;
+       }
+
+       if (!dontclose)
+               zfs_close(zhp);
+
+       return (0);
+}
+
+int
+zfs_add_sort_column(zfs_sort_column_t **sc, const char *name,
+    boolean_t reverse)
+{
+       zfs_sort_column_t *col;
+       zfs_prop_t prop;
+
+       if ((prop = zfs_name_to_prop(name)) == ZPROP_INVAL &&
+           !zfs_prop_user(name))
+               return (-1);
+
+       col = safe_malloc(sizeof (zfs_sort_column_t));
+
+       col->sc_prop = prop;
+       col->sc_reverse = reverse;
+       if (prop == ZPROP_INVAL) {
+               col->sc_user_prop = safe_malloc(strlen(name) + 1);
+               (void) strcpy(col->sc_user_prop, name);
+       }
+
+       if (*sc == NULL) {
+               col->sc_last = col;
+               *sc = col;
+       } else {
+               (*sc)->sc_last->sc_next = col;
+               (*sc)->sc_last = col;
+       }
+
+       return (0);
+}
+
+void
+zfs_free_sort_columns(zfs_sort_column_t *sc)
+{
+       zfs_sort_column_t *col;
+
+       while (sc != NULL) {
+               col = sc->sc_next;
+               free(sc->sc_user_prop);
+               free(sc);
+               sc = col;
+       }
+}
+
+int
+zfs_sort_only_by_name(const zfs_sort_column_t *sc)
+{
+       return (sc != NULL && sc->sc_next == NULL &&
+           sc->sc_prop == ZFS_PROP_NAME);
+}
+
+/* ARGSUSED */
+static int
+zfs_compare(const void *larg, const void *rarg, void *unused)
+{
+       zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
+       zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
+       const char *lname = zfs_get_name(l);
+       const char *rname = zfs_get_name(r);
+       char *lat, *rat;
+       uint64_t lcreate, rcreate;
+       int ret;
+
+       lat = (char *)strchr(lname, '@');
+       rat = (char *)strchr(rname, '@');
+
+       if (lat != NULL)
+               *lat = '\0';
+       if (rat != NULL)
+               *rat = '\0';
+
+       ret = strcmp(lname, rname);
+       if (ret == 0) {
+               /*
+                * If we're comparing a dataset to one of its snapshots, we
+                * always make the full dataset first.
+                */
+               if (lat == NULL) {
+                       ret = -1;
+               } else if (rat == NULL) {
+                       ret = 1;
+               } else {
+                       /*
+                        * If we have two snapshots from the same dataset, then
+                        * we want to sort them according to creation time.  We
+                        * use the hidden CREATETXG property to get an absolute
+                        * ordering of snapshots.
+                        */
+                       lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
+                       rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
+
+                       /*
+                        * Both lcreate and rcreate being 0 means we don't have
+                        * properties and we should compare full name.
+                        */
+                       if (lcreate == 0 && rcreate == 0)
+                               ret = strcmp(lat + 1, rat + 1);
+                       else if (lcreate < rcreate)
+                               ret = -1;
+                       else if (lcreate > rcreate)
+                               ret = 1;
+               }
+       }
+
+       if (lat != NULL)
+               *lat = '@';
+       if (rat != NULL)
+               *rat = '@';
+
+       return (ret);
+}
+
+/*
+ * Sort datasets by specified columns.
+ *
+ * o  Numeric types sort in ascending order.
+ * o  String types sort in alphabetical order.
+ * o  Types inappropriate for a row sort that row to the literal
+ *    bottom, regardless of the specified ordering.
+ *
+ * If no sort columns are specified, or two datasets compare equally
+ * across all specified columns, they are sorted alphabetically by name
+ * with snapshots grouped under their parents.
+ */
+static int
+zfs_sort(const void *larg, const void *rarg, void *data)
+{
+       zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
+       zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
+       zfs_sort_column_t *sc = (zfs_sort_column_t *)data;
+       zfs_sort_column_t *psc;
+
+       for (psc = sc; psc != NULL; psc = psc->sc_next) {
+               char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN];
+               char *lstr, *rstr;
+               uint64_t lnum, rnum;
+               boolean_t lvalid, rvalid;
+               int ret = 0;
+
+               /*
+                * We group the checks below the generic code.  If 'lstr' and
+                * 'rstr' are non-NULL, then we do a string based comparison.
+                * Otherwise, we compare 'lnum' and 'rnum'.
+                */
+               lstr = rstr = NULL;
+               if (psc->sc_prop == ZPROP_INVAL) {
+                       nvlist_t *luser, *ruser;
+                       nvlist_t *lval, *rval;
+
+                       luser = zfs_get_user_props(l);
+                       ruser = zfs_get_user_props(r);
+
+                       lvalid = (nvlist_lookup_nvlist(luser,
+                           psc->sc_user_prop, &lval) == 0);
+                       rvalid = (nvlist_lookup_nvlist(ruser,
+                           psc->sc_user_prop, &rval) == 0);
+
+                       if (lvalid)
+                               verify(nvlist_lookup_string(lval,
+                                   ZPROP_VALUE, &lstr) == 0);
+                       if (rvalid)
+                               verify(nvlist_lookup_string(rval,
+                                   ZPROP_VALUE, &rstr) == 0);
+               } else if (psc->sc_prop == ZFS_PROP_NAME) {
+                       lvalid = rvalid = B_TRUE;
+
+                       (void) strlcpy(lbuf, zfs_get_name(l), sizeof (lbuf));
+                       (void) strlcpy(rbuf, zfs_get_name(r), sizeof (rbuf));
+
+                       lstr = lbuf;
+                       rstr = rbuf;
+               } else if (zfs_prop_is_string(psc->sc_prop)) {
+                       lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf,
+                           sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0);
+                       rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf,
+                           sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0);
+
+                       lstr = lbuf;
+                       rstr = rbuf;
+               } else {
+                       lvalid = zfs_prop_valid_for_type(psc->sc_prop,
+                           zfs_get_type(l), B_FALSE);
+                       rvalid = zfs_prop_valid_for_type(psc->sc_prop,
+                           zfs_get_type(r), B_FALSE);
+
+                       if (lvalid)
+                               (void) zfs_prop_get_numeric(l, psc->sc_prop,
+                                   &lnum, NULL, NULL, 0);
+                       if (rvalid)
+                               (void) zfs_prop_get_numeric(r, psc->sc_prop,
+                                   &rnum, NULL, NULL, 0);
+               }
+
+               if (!lvalid && !rvalid)
+                       continue;
+               else if (!lvalid)
+                       return (1);
+               else if (!rvalid)
+                       return (-1);
+
+               if (lstr)
+                       ret = strcmp(lstr, rstr);
+               else if (lnum < rnum)
+                       ret = -1;
+               else if (lnum > rnum)
+                       ret = 1;
+
+               if (ret != 0) {
+                       if (psc->sc_reverse == B_TRUE)
+                               ret = (ret < 0) ? 1 : -1;
+                       return (ret);
+               }
+       }
+
+       return (zfs_compare(larg, rarg, NULL));
+}
+
+int
+zfs_for_each(int argc, char **argv, int flags, zfs_type_t types,
+    zfs_sort_column_t *sortcol, zprop_list_t **proplist, int limit,
+    zfs_iter_f callback, void *data)
+{
+       callback_data_t cb = {0};
+       int ret = 0;
+       zfs_node_t *node;
+       uu_avl_walk_t *walk;
+
+       avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t),
+           offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT);
+
+       if (avl_pool == NULL)
+               nomem();
+
+       cb.cb_sortcol = sortcol;
+       cb.cb_flags = flags;
+       cb.cb_proplist = proplist;
+       cb.cb_types = types;
+       cb.cb_depth_limit = limit;
+       /*
+        * If cb_proplist is provided then in the zfs_handles created we
+        * retain only those properties listed in cb_proplist and sortcol.
+        * The rest are pruned. So, the caller should make sure that no other
+        * properties other than those listed in cb_proplist/sortcol are
+        * accessed.
+        *
+        * If cb_proplist is NULL then we retain all the properties.  We
+        * always retain the zoned property, which some other properties
+        * need (userquota & friends), and the createtxg property, which
+        * we need to sort snapshots.
+        */
+       if (cb.cb_proplist && *cb.cb_proplist) {
+               zprop_list_t *p = *cb.cb_proplist;
+
+               while (p) {
+                       if (p->pl_prop >= ZFS_PROP_TYPE &&
+                           p->pl_prop < ZFS_NUM_PROPS) {
+                               cb.cb_props_table[p->pl_prop] = B_TRUE;
+                       }
+                       p = p->pl_next;
+               }
+
+               while (sortcol) {
+                       if (sortcol->sc_prop >= ZFS_PROP_TYPE &&
+                           sortcol->sc_prop < ZFS_NUM_PROPS) {
+                               cb.cb_props_table[sortcol->sc_prop] = B_TRUE;
+                       }
+                       sortcol = sortcol->sc_next;
+               }
+
+               cb.cb_props_table[ZFS_PROP_ZONED] = B_TRUE;
+               cb.cb_props_table[ZFS_PROP_CREATETXG] = B_TRUE;
+       } else {
+               (void) memset(cb.cb_props_table, B_TRUE,
+                   sizeof (cb.cb_props_table));
+       }
+
+       if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
+               nomem();
+
+       if (argc == 0) {
+               /*
+                * If given no arguments, iterate over all datasets.
+                */
+               cb.cb_flags |= ZFS_ITER_RECURSE;
+               ret = zfs_iter_root(g_zfs, zfs_callback, &cb);
+       } else {
+               int i;
+               zfs_handle_t *zhp;
+               zfs_type_t argtype;
+
+               /*
+                * If we're recursive, then we always allow filesystems as
+                * arguments.  If we also are interested in snapshots or
+                * bookmarks, then we can take volumes as well.
+                */
+               argtype = types;
+               if (flags & ZFS_ITER_RECURSE) {
+                       argtype |= ZFS_TYPE_FILESYSTEM;
+                       if (types & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK))
+                               argtype |= ZFS_TYPE_VOLUME;
+               }
+
+               for (i = 0; i < argc; i++) {
+                       if (flags & ZFS_ITER_ARGS_CAN_BE_PATHS) {
+                               zhp = zfs_path_to_zhandle(g_zfs, argv[i],
+                                   argtype);
+                       } else {
+                               zhp = zfs_open(g_zfs, argv[i], argtype);
+                       }
+                       if (zhp != NULL)
+                               ret |= zfs_callback(zhp, &cb);
+                       else
+                               ret = 1;
+               }
+       }
+
+       /*
+        * At this point we've got our AVL tree full of zfs handles, so iterate
+        * over each one and execute the real user callback.
+        */
+       for (node = uu_avl_first(cb.cb_avl); node != NULL;
+           node = uu_avl_next(cb.cb_avl, node))
+               ret |= callback(node->zn_handle, data);
+
+       /*
+        * Finally, clean up the AVL tree.
+        */
+       if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
+               nomem();
+
+       while ((node = uu_avl_walk_next(walk)) != NULL) {
+               uu_avl_remove(cb.cb_avl, node);
+               zfs_close(node->zn_handle);
+               free(node);
+       }
+
+       uu_avl_walk_end(walk);
+       uu_avl_destroy(cb.cb_avl);
+       uu_avl_pool_destroy(avl_pool);
+
+       return (ret);
+}
diff --git a/zfs/cmd/zfs/zfs_iter.h b/zfs/cmd/zfs/zfs_iter.h
new file mode 100644 (file)
index 0000000..2697fbd
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#ifndef        ZFS_ITER_H
+#define        ZFS_ITER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct zfs_sort_column {
+       struct zfs_sort_column  *sc_next;
+       struct zfs_sort_column  *sc_last;
+       zfs_prop_t              sc_prop;
+       char                    *sc_user_prop;
+       boolean_t               sc_reverse;
+} zfs_sort_column_t;
+
+#define        ZFS_ITER_RECURSE           (1 << 0)
+#define        ZFS_ITER_ARGS_CAN_BE_PATHS (1 << 1)
+#define        ZFS_ITER_PROP_LISTSNAPS    (1 << 2)
+#define        ZFS_ITER_DEPTH_LIMIT       (1 << 3)
+#define        ZFS_ITER_RECVD_PROPS       (1 << 4)
+#define        ZFS_ITER_LITERAL_PROPS     (1 << 5)
+#define        ZFS_ITER_SIMPLE            (1 << 6)
+
+int zfs_for_each(int, char **, int options, zfs_type_t,
+    zfs_sort_column_t *, zprop_list_t **, int, zfs_iter_f, void *);
+int zfs_add_sort_column(zfs_sort_column_t **, const char *, boolean_t);
+void zfs_free_sort_columns(zfs_sort_column_t *);
+int zfs_sort_only_by_name(const zfs_sort_column_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZFS_ITER_H */
diff --git a/zfs/cmd/zfs/zfs_main.c b/zfs/cmd/zfs/zfs_main.c
new file mode 100644 (file)
index 0000000..8a49e31
--- /dev/null
@@ -0,0 +1,6992 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland.  All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <libuutil.h>
+#include <libnvpair.h>
+#include <locale.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <zone.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <sys/list.h>
+#include <sys/mkdev.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fs/zfs.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <libzfs.h>
+#include <libzfs_core.h>
+#include <zfs_prop.h>
+#include <zfs_deleg.h>
+#include <libuutil.h>
+#ifdef HAVE_IDMAP
+#include <aclutils.h>
+#include <directory.h>
+#endif /* HAVE_IDMAP */
+
+#include "zfs_iter.h"
+#include "zfs_util.h"
+#include "zfs_comutil.h"
+#include "libzfs_impl.h"
+
+libzfs_handle_t *g_zfs;
+
+static FILE *mnttab_file;
+static char history_str[HIS_MAX_RECORD_LEN];
+static boolean_t log_history = B_TRUE;
+
+static int zfs_do_clone(int argc, char **argv);
+static int zfs_do_create(int argc, char **argv);
+static int zfs_do_destroy(int argc, char **argv);
+static int zfs_do_get(int argc, char **argv);
+static int zfs_do_inherit(int argc, char **argv);
+static int zfs_do_list(int argc, char **argv);
+static int zfs_do_mount(int argc, char **argv);
+static int zfs_do_rename(int argc, char **argv);
+static int zfs_do_rollback(int argc, char **argv);
+static int zfs_do_set(int argc, char **argv);
+static int zfs_do_upgrade(int argc, char **argv);
+static int zfs_do_snapshot(int argc, char **argv);
+static int zfs_do_unmount(int argc, char **argv);
+static int zfs_do_share(int argc, char **argv);
+static int zfs_do_unshare(int argc, char **argv);
+static int zfs_do_send(int argc, char **argv);
+static int zfs_do_receive(int argc, char **argv);
+static int zfs_do_promote(int argc, char **argv);
+static int zfs_do_userspace(int argc, char **argv);
+static int zfs_do_allow(int argc, char **argv);
+static int zfs_do_unallow(int argc, char **argv);
+static int zfs_do_hold(int argc, char **argv);
+static int zfs_do_holds(int argc, char **argv);
+static int zfs_do_release(int argc, char **argv);
+static int zfs_do_diff(int argc, char **argv);
+static int zfs_do_bookmark(int argc, char **argv);
+
+/*
+ * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
+ */
+
+#ifdef DEBUG
+const char *
+_umem_debug_init(void)
+{
+       return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+       return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+#endif
+
+typedef enum {
+       HELP_CLONE,
+       HELP_CREATE,
+       HELP_DESTROY,
+       HELP_GET,
+       HELP_INHERIT,
+       HELP_UPGRADE,
+       HELP_LIST,
+       HELP_MOUNT,
+       HELP_PROMOTE,
+       HELP_RECEIVE,
+       HELP_RENAME,
+       HELP_ROLLBACK,
+       HELP_SEND,
+       HELP_SET,
+       HELP_SHARE,
+       HELP_SNAPSHOT,
+       HELP_UNMOUNT,
+       HELP_UNSHARE,
+       HELP_ALLOW,
+       HELP_UNALLOW,
+       HELP_USERSPACE,
+       HELP_GROUPSPACE,
+       HELP_HOLD,
+       HELP_HOLDS,
+       HELP_RELEASE,
+       HELP_DIFF,
+       HELP_BOOKMARK,
+} zfs_help_t;
+
+typedef struct zfs_command {
+       const char      *name;
+       int             (*func)(int argc, char **argv);
+       zfs_help_t      usage;
+} zfs_command_t;
+
+/*
+ * Master command table.  Each ZFS command has a name, associated function, and
+ * usage message.  The usage messages need to be internationalized, so we have
+ * to have a function to return the usage message based on a command index.
+ *
+ * These commands are organized according to how they are displayed in the usage
+ * message.  An empty command (one with a NULL name) indicates an empty line in
+ * the generic usage message.
+ */
+static zfs_command_t command_table[] = {
+       { "create",     zfs_do_create,          HELP_CREATE             },
+       { "destroy",    zfs_do_destroy,         HELP_DESTROY            },
+       { NULL },
+       { "snapshot",   zfs_do_snapshot,        HELP_SNAPSHOT           },
+       { "rollback",   zfs_do_rollback,        HELP_ROLLBACK           },
+       { "clone",      zfs_do_clone,           HELP_CLONE              },
+       { "promote",    zfs_do_promote,         HELP_PROMOTE            },
+       { "rename",     zfs_do_rename,          HELP_RENAME             },
+       { "bookmark",   zfs_do_bookmark,        HELP_BOOKMARK           },
+       { NULL },
+       { "list",       zfs_do_list,            HELP_LIST               },
+       { NULL },
+       { "set",        zfs_do_set,             HELP_SET                },
+       { "get",        zfs_do_get,             HELP_GET                },
+       { "inherit",    zfs_do_inherit,         HELP_INHERIT            },
+       { "upgrade",    zfs_do_upgrade,         HELP_UPGRADE            },
+       { "userspace",  zfs_do_userspace,       HELP_USERSPACE          },
+       { "groupspace", zfs_do_userspace,       HELP_GROUPSPACE         },
+       { NULL },
+       { "mount",      zfs_do_mount,           HELP_MOUNT              },
+       { "unmount",    zfs_do_unmount,         HELP_UNMOUNT            },
+       { "share",      zfs_do_share,           HELP_SHARE              },
+       { "unshare",    zfs_do_unshare,         HELP_UNSHARE            },
+       { NULL },
+       { "send",       zfs_do_send,            HELP_SEND               },
+       { "receive",    zfs_do_receive,         HELP_RECEIVE            },
+       { NULL },
+       { "allow",      zfs_do_allow,           HELP_ALLOW              },
+       { NULL },
+       { "unallow",    zfs_do_unallow,         HELP_UNALLOW            },
+       { NULL },
+       { "hold",       zfs_do_hold,            HELP_HOLD               },
+       { "holds",      zfs_do_holds,           HELP_HOLDS              },
+       { "release",    zfs_do_release,         HELP_RELEASE            },
+       { "diff",       zfs_do_diff,            HELP_DIFF               },
+};
+
+#define        NCOMMAND        (sizeof (command_table) / sizeof (command_table[0]))
+
+zfs_command_t *current_command;
+
+static const char *
+get_usage(zfs_help_t idx)
+{
+       switch (idx) {
+       case HELP_CLONE:
+               return (gettext("\tclone [-p] [-o property=value] ... "
+                   "<snapshot> <filesystem|volume>\n"));
+       case HELP_CREATE:
+               return (gettext("\tcreate [-p] [-o property=value] ... "
+                   "<filesystem>\n"
+                   "\tcreate [-ps] [-b blocksize] [-o property=value] ... "
+                   "-V <size> <volume>\n"));
+       case HELP_DESTROY:
+               return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
+                   "\tdestroy [-dnpRrv] "
+                   "<filesystem|volume>@<snap>[%<snap>][,...]\n"
+                   "\tdestroy <filesystem|volume>#<bookmark>\n"));
+       case HELP_GET:
+               return (gettext("\tget [-rHp] [-d max] "
+                   "[-o \"all\" | field[,...]]\n"
+                   "\t    [-t type[,...]] [-s source[,...]]\n"
+                   "\t    <\"all\" | property[,...]> "
+                   "[filesystem|volume|snapshot] ...\n"));
+       case HELP_INHERIT:
+               return (gettext("\tinherit [-rS] <property> "
+                   "<filesystem|volume|snapshot> ...\n"));
+       case HELP_UPGRADE:
+               return (gettext("\tupgrade [-v]\n"
+                   "\tupgrade [-r] [-V version] <-a | filesystem ...>\n"));
+       case HELP_LIST:
+               return (gettext("\tlist [-Hp] [-r|-d max] [-o property[,...]] "
+                   "[-s property]...\n\t    [-S property]... [-t type[,...]] "
+                   "[filesystem|volume|snapshot] ...\n"));
+       case HELP_MOUNT:
+               return (gettext("\tmount\n"
+                   "\tmount [-vO] [-o opts] <-a | filesystem>\n"));
+       case HELP_PROMOTE:
+               return (gettext("\tpromote <clone-filesystem>\n"));
+       case HELP_RECEIVE:
+               return (gettext("\treceive [-vnsFu] <filesystem|volume|"
+                   "snapshot>\n"
+                   "\treceive [-vnsFu] [-o origin=<snapshot>] [-d | -e] "
+                   "<filesystem>\n"
+                   "\treceive -A <filesystem|volume>\n"));
+       case HELP_RENAME:
+               return (gettext("\trename [-f] <filesystem|volume|snapshot> "
+                   "<filesystem|volume|snapshot>\n"
+                   "\trename [-f] -p <filesystem|volume> <filesystem|volume>\n"
+                   "\trename -r <snapshot> <snapshot>\n"));
+       case HELP_ROLLBACK:
+               return (gettext("\trollback [-rRf] <snapshot>\n"));
+       case HELP_SEND:
+               return (gettext("\tsend [-DnPpRvLec] [-[iI] snapshot] "
+                   "<snapshot>\n"
+                   "\tsend [-Le] [-i snapshot|bookmark] "
+                   "<filesystem|volume|snapshot>\n"
+                   "\tsend [-nvPe] -t <receive_resume_token>\n"));
+       case HELP_SET:
+               return (gettext("\tset <property=value> ... "
+                   "<filesystem|volume|snapshot> ...\n"));
+       case HELP_SHARE:
+               return (gettext("\tshare <-a | filesystem>\n"));
+       case HELP_SNAPSHOT:
+               return (gettext("\tsnapshot|snap [-r] [-o property=value] ... "
+                   "<filesystem|volume>@<snap> ...\n"));
+       case HELP_UNMOUNT:
+               return (gettext("\tunmount [-f] "
+                   "<-a | filesystem|mountpoint>\n"));
+       case HELP_UNSHARE:
+               return (gettext("\tunshare "
+                   "<-a | filesystem|mountpoint>\n"));
+       case HELP_ALLOW:
+               return (gettext("\tallow <filesystem|volume>\n"
+                   "\tallow [-ldug] "
+                   "<\"everyone\"|user|group>[,...] <perm|@setname>[,...]\n"
+                   "\t    <filesystem|volume>\n"
+                   "\tallow [-ld] -e <perm|@setname>[,...] "
+                   "<filesystem|volume>\n"
+                   "\tallow -c <perm|@setname>[,...] <filesystem|volume>\n"
+                   "\tallow -s @setname <perm|@setname>[,...] "
+                   "<filesystem|volume>\n"));
+       case HELP_UNALLOW:
+               return (gettext("\tunallow [-rldug] "
+                   "<\"everyone\"|user|group>[,...]\n"
+                   "\t    [<perm|@setname>[,...]] <filesystem|volume>\n"
+                   "\tunallow [-rld] -e [<perm|@setname>[,...]] "
+                   "<filesystem|volume>\n"
+                   "\tunallow [-r] -c [<perm|@setname>[,...]] "
+                   "<filesystem|volume>\n"
+                   "\tunallow [-r] -s @setname [<perm|@setname>[,...]] "
+                   "<filesystem|volume>\n"));
+       case HELP_USERSPACE:
+               return (gettext("\tuserspace [-Hinp] [-o field[,...]] "
+                   "[-s field] ...\n"
+                   "\t    [-S field] ... [-t type[,...]] "
+                   "<filesystem|snapshot>\n"));
+       case HELP_GROUPSPACE:
+               return (gettext("\tgroupspace [-Hinp] [-o field[,...]] "
+                   "[-s field] ...\n"
+                   "\t    [-S field] ... [-t type[,...]] "
+                   "<filesystem|snapshot>\n"));
+       case HELP_HOLD:
+               return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
+       case HELP_HOLDS:
+               return (gettext("\tholds [-r] <snapshot> ...\n"));
+       case HELP_RELEASE:
+               return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
+       case HELP_DIFF:
+               return (gettext("\tdiff [-FHt] <snapshot> "
+                   "[snapshot|filesystem]\n"));
+       case HELP_BOOKMARK:
+               return (gettext("\tbookmark <snapshot> <bookmark>\n"));
+       }
+
+       abort();
+       /* NOTREACHED */
+}
+
+void
+nomem(void)
+{
+       (void) fprintf(stderr, gettext("internal error: out of memory\n"));
+       exit(1);
+}
+
+/*
+ * Utility function to guarantee malloc() success.
+ */
+
+void *
+safe_malloc(size_t size)
+{
+       void *data;
+
+       if ((data = calloc(1, size)) == NULL)
+               nomem();
+
+       return (data);
+}
+
+static char *
+safe_strdup(char *str)
+{
+       char *dupstr = strdup(str);
+
+       if (dupstr == NULL)
+               nomem();
+
+       return (dupstr);
+}
+
+/*
+ * Callback routine that will print out information for each of
+ * the properties.
+ */
+static int
+usage_prop_cb(int prop, void *cb)
+{
+       FILE *fp = cb;
+
+       (void) fprintf(fp, "\t%-15s ", zfs_prop_to_name(prop));
+
+       if (zfs_prop_readonly(prop))
+               (void) fprintf(fp, " NO    ");
+       else
+               (void) fprintf(fp, "YES    ");
+
+       if (zfs_prop_inheritable(prop))
+               (void) fprintf(fp, "  YES   ");
+       else
+               (void) fprintf(fp, "   NO   ");
+
+       if (zfs_prop_values(prop) == NULL)
+               (void) fprintf(fp, "-\n");
+       else
+               (void) fprintf(fp, "%s\n", zfs_prop_values(prop));
+
+       return (ZPROP_CONT);
+}
+
+/*
+ * Display usage message.  If we're inside a command, display only the usage for
+ * that command.  Otherwise, iterate over the entire command table and display
+ * a complete usage message.
+ */
+static void
+usage(boolean_t requested)
+{
+       int i;
+       boolean_t show_properties = B_FALSE;
+       FILE *fp = requested ? stdout : stderr;
+
+       if (current_command == NULL) {
+
+               (void) fprintf(fp, gettext("usage: zfs command args ...\n"));
+               (void) fprintf(fp,
+                   gettext("where 'command' is one of the following:\n\n"));
+
+               for (i = 0; i < NCOMMAND; i++) {
+                       if (command_table[i].name == NULL)
+                               (void) fprintf(fp, "\n");
+                       else
+                               (void) fprintf(fp, "%s",
+                                   get_usage(command_table[i].usage));
+               }
+
+               (void) fprintf(fp, gettext("\nEach dataset is of the form: "
+                   "pool/[dataset/]*dataset[@name]\n"));
+       } else {
+               (void) fprintf(fp, gettext("usage:\n"));
+               (void) fprintf(fp, "%s", get_usage(current_command->usage));
+       }
+
+       if (current_command != NULL &&
+           (strcmp(current_command->name, "set") == 0 ||
+           strcmp(current_command->name, "get") == 0 ||
+           strcmp(current_command->name, "inherit") == 0 ||
+           strcmp(current_command->name, "list") == 0))
+               show_properties = B_TRUE;
+
+       if (show_properties) {
+               (void) fprintf(fp,
+                   gettext("\nThe following properties are supported:\n"));
+
+               (void) fprintf(fp, "\n\t%-14s %s  %s   %s\n\n",
+                   "PROPERTY", "EDIT", "INHERIT", "VALUES");
+
+               /* Iterate over all properties */
+               (void) zprop_iter(usage_prop_cb, fp, B_FALSE, B_TRUE,
+                   ZFS_TYPE_DATASET);
+
+               (void) fprintf(fp, "\t%-15s ", "userused@...");
+               (void) fprintf(fp, " NO       NO   <size>\n");
+               (void) fprintf(fp, "\t%-15s ", "groupused@...");
+               (void) fprintf(fp, " NO       NO   <size>\n");
+               (void) fprintf(fp, "\t%-15s ", "userquota@...");
+               (void) fprintf(fp, "YES       NO   <size> | none\n");
+               (void) fprintf(fp, "\t%-15s ", "groupquota@...");
+               (void) fprintf(fp, "YES       NO   <size> | none\n");
+               (void) fprintf(fp, "\t%-15s ", "written@<snap>");
+               (void) fprintf(fp, " NO       NO   <size>\n");
+
+               (void) fprintf(fp, gettext("\nSizes are specified in bytes "
+                   "with standard units such as K, M, G, etc.\n"));
+               (void) fprintf(fp, gettext("\nUser-defined properties can "
+                   "be specified by using a name containing a colon (:).\n"));
+               (void) fprintf(fp, gettext("\nThe {user|group}{used|quota}@ "
+                   "properties must be appended with\n"
+                   "a user or group specifier of one of these forms:\n"
+                   "    POSIX name      (eg: \"matt\")\n"
+                   "    POSIX id        (eg: \"126829\")\n"
+                   "    SMB name@domain (eg: \"matt@sun\")\n"
+                   "    SMB SID         (eg: \"S-1-234-567-89\")\n"));
+       } else {
+               (void) fprintf(fp,
+                   gettext("\nFor the property list, run: %s\n"),
+                   "zfs set|get");
+               (void) fprintf(fp,
+                   gettext("\nFor the delegated permission list, run: %s\n"),
+                   "zfs allow|unallow");
+       }
+
+       /*
+        * See comments at end of main().
+        */
+       if (getenv("ZFS_ABORT") != NULL) {
+               (void) printf("dumping core by request\n");
+               abort();
+       }
+
+       exit(requested ? 0 : 2);
+}
+
+/*
+ * Take a property=value argument string and add it to the given nvlist.
+ * Modifies the argument inplace.
+ */
+static int
+parseprop(nvlist_t *props, char *propname)
+{
+       char *propval, *strval;
+
+       if ((propval = strchr(propname, '=')) == NULL) {
+               (void) fprintf(stderr, gettext("missing "
+                   "'=' for property=value argument\n"));
+               return (-1);
+       }
+       *propval = '\0';
+       propval++;
+       if (nvlist_lookup_string(props, propname, &strval) == 0) {
+               (void) fprintf(stderr, gettext("property '%s' "
+                   "specified multiple times\n"), propname);
+               return (-1);
+       }
+       if (nvlist_add_string(props, propname, propval) != 0)
+               nomem();
+       return (0);
+}
+
+static int
+parse_depth(char *opt, int *flags)
+{
+       char *tmp;
+       int depth;
+
+       depth = (int)strtol(opt, &tmp, 0);
+       if (*tmp) {
+               (void) fprintf(stderr,
+                   gettext("%s is not an integer\n"), optarg);
+               usage(B_FALSE);
+       }
+       if (depth < 0) {
+               (void) fprintf(stderr,
+                   gettext("Depth can not be negative.\n"));
+               usage(B_FALSE);
+       }
+       *flags |= (ZFS_ITER_DEPTH_LIMIT|ZFS_ITER_RECURSE);
+       return (depth);
+}
+
+#define        PROGRESS_DELAY 2                /* seconds */
+
+static char *pt_reverse = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+static time_t pt_begin;
+static char *pt_header = NULL;
+static boolean_t pt_shown;
+
+static void
+start_progress_timer(void)
+{
+       pt_begin = time(NULL) + PROGRESS_DELAY;
+       pt_shown = B_FALSE;
+}
+
+static void
+set_progress_header(char *header)
+{
+       assert(pt_header == NULL);
+       pt_header = safe_strdup(header);
+       if (pt_shown) {
+               (void) printf("%s: ", header);
+               (void) fflush(stdout);
+       }
+}
+
+static void
+update_progress(char *update)
+{
+       if (!pt_shown && time(NULL) > pt_begin) {
+               int len = strlen(update);
+
+               (void) printf("%s: %s%*.*s", pt_header, update, len, len,
+                   pt_reverse);
+               (void) fflush(stdout);
+               pt_shown = B_TRUE;
+       } else if (pt_shown) {
+               int len = strlen(update);
+
+               (void) printf("%s%*.*s", update, len, len, pt_reverse);
+               (void) fflush(stdout);
+       }
+}
+
+static void
+finish_progress(char *done)
+{
+       if (pt_shown) {
+               (void) printf("%s\n", done);
+               (void) fflush(stdout);
+       }
+       free(pt_header);
+       pt_header = NULL;
+}
+
+static int
+zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type)
+{
+       zfs_handle_t *zhp = NULL;
+       int ret = 0;
+
+       zhp = zfs_open(hdl, dataset, type);
+       if (zhp == NULL)
+               return (1);
+
+       /*
+        * Volumes may neither be mounted or shared.  Potentially in the
+        * future filesystems detected on these volumes could be mounted.
+        */
+       if (zfs_get_type(zhp) == ZFS_TYPE_VOLUME) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       /*
+        * Mount and/or share the new filesystem as appropriate.  We provide a
+        * verbose error message to let the user know that their filesystem was
+        * in fact created, even if we failed to mount or share it.
+        *
+        * If the user doesn't want the dataset automatically mounted, then
+        * skip the mount/share step
+        */
+       if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type, B_FALSE) &&
+           zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON) {
+               if (geteuid() != 0) {
+                       (void) fprintf(stderr, gettext("filesystem "
+                           "successfully created, but it may only be "
+                           "mounted by root\n"));
+                       ret = 1;
+               } else if (zfs_mount(zhp, NULL, 0) != 0) {
+                       (void) fprintf(stderr, gettext("filesystem "
+                           "successfully created, but not mounted\n"));
+                       ret = 1;
+               } else if (zfs_share(zhp) != 0) {
+                       (void) fprintf(stderr, gettext("filesystem "
+                           "successfully created, but not shared\n"));
+                       ret = 1;
+               }
+       }
+
+       zfs_close(zhp);
+
+       return (ret);
+}
+
+/*
+ * zfs clone [-p] [-o prop=value] ... <snap> <fs | vol>
+ *
+ * Given an existing dataset, create a writable copy whose initial contents
+ * are the same as the source.  The newly created dataset maintains a
+ * dependency on the original; the original cannot be destroyed so long as
+ * the clone exists.
+ *
+ * The '-p' flag creates all the non-existing ancestors of the target first.
+ */
+static int
+zfs_do_clone(int argc, char **argv)
+{
+       zfs_handle_t *zhp = NULL;
+       boolean_t parents = B_FALSE;
+       nvlist_t *props;
+       int ret = 0;
+       int c;
+
+       if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+
+       /* check options */
+       while ((c = getopt(argc, argv, "o:p")) != -1) {
+               switch (c) {
+               case 'o':
+                       if (parseprop(props, optarg) != 0) {
+                               nvlist_free(props);
+                               return (1);
+                       }
+                       break;
+               case 'p':
+                       parents = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       goto usage;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing source dataset "
+                   "argument\n"));
+               goto usage;
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing target dataset "
+                   "argument\n"));
+               goto usage;
+       }
+       if (argc > 2) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               goto usage;
+       }
+
+       /* open the source dataset */
+       if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL) {
+               nvlist_free(props);
+               return (1);
+       }
+
+       if (parents && zfs_name_valid(argv[1], ZFS_TYPE_FILESYSTEM |
+           ZFS_TYPE_VOLUME)) {
+               /*
+                * Now create the ancestors of the target dataset.  If the
+                * target already exists and '-p' option was used we should not
+                * complain.
+                */
+               if (zfs_dataset_exists(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM |
+                   ZFS_TYPE_VOLUME)) {
+                       zfs_close(zhp);
+                       nvlist_free(props);
+                       return (0);
+               }
+               if (zfs_create_ancestors(g_zfs, argv[1]) != 0) {
+                       zfs_close(zhp);
+                       nvlist_free(props);
+                       return (1);
+               }
+       }
+
+       /* pass to libzfs */
+       ret = zfs_clone(zhp, argv[1], props);
+
+       /* create the mountpoint if necessary */
+       if (ret == 0) {
+               if (log_history) {
+                       (void) zpool_log_history(g_zfs, history_str);
+                       log_history = B_FALSE;
+               }
+
+               ret = zfs_mount_and_share(g_zfs, argv[1], ZFS_TYPE_DATASET);
+       }
+
+       zfs_close(zhp);
+       nvlist_free(props);
+
+       return (!!ret);
+
+usage:
+       if (zhp)
+               zfs_close(zhp);
+       nvlist_free(props);
+       usage(B_FALSE);
+       return (-1);
+}
+
+/*
+ * zfs create [-p] [-o prop=value] ... fs
+ * zfs create [-ps] [-b blocksize] [-o prop=value] ... -V vol size
+ *
+ * Create a new dataset.  This command can be used to create filesystems
+ * and volumes.  Snapshot creation is handled by 'zfs snapshot'.
+ * For volumes, the user must specify a size to be used.
+ *
+ * The '-s' flag applies only to volumes, and indicates that we should not try
+ * to set the reservation for this volume.  By default we set a reservation
+ * equal to the size for any volume.  For pools with SPA_VERSION >=
+ * SPA_VERSION_REFRESERVATION, we set a refreservation instead.
+ *
+ * The '-p' flag creates all the non-existing ancestors of the target first.
+ */
+static int
+zfs_do_create(int argc, char **argv)
+{
+       zfs_type_t type = ZFS_TYPE_FILESYSTEM;
+       uint64_t volsize = 0;
+       int c;
+       boolean_t noreserve = B_FALSE;
+       boolean_t bflag = B_FALSE;
+       boolean_t parents = B_FALSE;
+       int ret = 1;
+       nvlist_t *props;
+       uint64_t intval;
+
+       if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":V:b:so:p")) != -1) {
+               switch (c) {
+               case 'V':
+                       type = ZFS_TYPE_VOLUME;
+                       if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
+                               (void) fprintf(stderr, gettext("bad volume "
+                                   "size '%s': %s\n"), optarg,
+                                   libzfs_error_description(g_zfs));
+                               goto error;
+                       }
+
+                       if (nvlist_add_uint64(props,
+                           zfs_prop_to_name(ZFS_PROP_VOLSIZE), intval) != 0)
+                               nomem();
+                       volsize = intval;
+                       break;
+               case 'p':
+                       parents = B_TRUE;
+                       break;
+               case 'b':
+                       bflag = B_TRUE;
+                       if (zfs_nicestrtonum(g_zfs, optarg, &intval) != 0) {
+                               (void) fprintf(stderr, gettext("bad volume "
+                                   "block size '%s': %s\n"), optarg,
+                                   libzfs_error_description(g_zfs));
+                               goto error;
+                       }
+
+                       if (nvlist_add_uint64(props,
+                           zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+                           intval) != 0)
+                               nomem();
+                       break;
+               case 'o':
+                       if (parseprop(props, optarg) != 0)
+                               goto error;
+                       break;
+               case 's':
+                       noreserve = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing size "
+                           "argument\n"));
+                       goto badusage;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       goto badusage;
+               }
+       }
+
+       if ((bflag || noreserve) && type != ZFS_TYPE_VOLUME) {
+               (void) fprintf(stderr, gettext("'-s' and '-b' can only be "
+                   "used when creating a volume\n"));
+               goto badusage;
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc == 0) {
+               (void) fprintf(stderr, gettext("missing %s argument\n"),
+                   zfs_type_to_name(type));
+               goto badusage;
+       }
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               goto badusage;
+       }
+
+       if (type == ZFS_TYPE_VOLUME && !noreserve) {
+               zpool_handle_t *zpool_handle;
+               nvlist_t *real_props = NULL;
+               uint64_t spa_version;
+               char *p;
+               zfs_prop_t resv_prop;
+               char *strval;
+               char msg[1024];
+
+               if ((p = strchr(argv[0], '/')))
+                       *p = '\0';
+               zpool_handle = zpool_open(g_zfs, argv[0]);
+               if (p != NULL)
+                       *p = '/';
+               if (zpool_handle == NULL)
+                       goto error;
+               spa_version = zpool_get_prop_int(zpool_handle,
+                   ZPOOL_PROP_VERSION, NULL);
+               if (spa_version >= SPA_VERSION_REFRESERVATION)
+                       resv_prop = ZFS_PROP_REFRESERVATION;
+               else
+                       resv_prop = ZFS_PROP_RESERVATION;
+
+               (void) snprintf(msg, sizeof (msg),
+                   gettext("cannot create '%s'"), argv[0]);
+               if (props && (real_props = zfs_valid_proplist(g_zfs, type,
+                   props, 0, NULL, zpool_handle, msg)) == NULL) {
+                       zpool_close(zpool_handle);
+                       goto error;
+               }
+               zpool_close(zpool_handle);
+
+               volsize = zvol_volsize_to_reservation(volsize, real_props);
+               nvlist_free(real_props);
+
+               if (nvlist_lookup_string(props, zfs_prop_to_name(resv_prop),
+                   &strval) != 0) {
+                       if (nvlist_add_uint64(props,
+                           zfs_prop_to_name(resv_prop), volsize) != 0) {
+                               nvlist_free(props);
+                               nomem();
+                       }
+               }
+       }
+
+       if (parents && zfs_name_valid(argv[0], type)) {
+               /*
+                * Now create the ancestors of target dataset.  If the target
+                * already exists and '-p' option was used we should not
+                * complain.
+                */
+               if (zfs_dataset_exists(g_zfs, argv[0], type)) {
+                       ret = 0;
+                       goto error;
+               }
+               if (zfs_create_ancestors(g_zfs, argv[0]) != 0)
+                       goto error;
+       }
+
+       /* pass to libzfs */
+       if (zfs_create(g_zfs, argv[0], type, props) != 0)
+               goto error;
+
+       if (log_history) {
+               (void) zpool_log_history(g_zfs, history_str);
+               log_history = B_FALSE;
+       }
+
+       ret = zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET);
+error:
+       nvlist_free(props);
+       return (ret);
+badusage:
+       nvlist_free(props);
+       usage(B_FALSE);
+       return (2);
+}
+
+/*
+ * zfs destroy [-rRf] <fs, vol>
+ * zfs destroy [-rRd] <snap>
+ *
+ *     -r      Recursively destroy all children
+ *     -R      Recursively destroy all dependents, including clones
+ *     -f      Force unmounting of any dependents
+ *     -d      If we can't destroy now, mark for deferred destruction
+ *
+ * Destroys the given dataset.  By default, it will unmount any filesystems,
+ * and refuse to destroy a dataset that has any dependents.  A dependent can
+ * either be a child, or a clone of a child.
+ */
+typedef struct destroy_cbdata {
+       boolean_t       cb_first;
+       boolean_t       cb_force;
+       boolean_t       cb_recurse;
+       boolean_t       cb_error;
+       boolean_t       cb_doclones;
+       zfs_handle_t    *cb_target;
+       boolean_t       cb_defer_destroy;
+       boolean_t       cb_verbose;
+       boolean_t       cb_parsable;
+       boolean_t       cb_dryrun;
+       nvlist_t        *cb_nvl;
+       nvlist_t        *cb_batchedsnaps;
+
+       /* first snap in contiguous run */
+       char            *cb_firstsnap;
+       /* previous snap in contiguous run */
+       char            *cb_prevsnap;
+       int64_t         cb_snapused;
+       char            *cb_snapspec;
+       char            *cb_bookmark;
+} destroy_cbdata_t;
+
+/*
+ * Check for any dependents based on the '-r' or '-R' flags.
+ */
+static int
+destroy_check_dependent(zfs_handle_t *zhp, void *data)
+{
+       destroy_cbdata_t *cbp = data;
+       const char *tname = zfs_get_name(cbp->cb_target);
+       const char *name = zfs_get_name(zhp);
+
+       if (strncmp(tname, name, strlen(tname)) == 0 &&
+           (name[strlen(tname)] == '/' || name[strlen(tname)] == '@')) {
+               /*
+                * This is a direct descendant, not a clone somewhere else in
+                * the hierarchy.
+                */
+               if (cbp->cb_recurse)
+                       goto out;
+
+               if (cbp->cb_first) {
+                       (void) fprintf(stderr, gettext("cannot destroy '%s': "
+                           "%s has children\n"),
+                           zfs_get_name(cbp->cb_target),
+                           zfs_type_to_name(zfs_get_type(cbp->cb_target)));
+                       (void) fprintf(stderr, gettext("use '-r' to destroy "
+                           "the following datasets:\n"));
+                       cbp->cb_first = B_FALSE;
+                       cbp->cb_error = B_TRUE;
+               }
+
+               (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
+       } else {
+               /*
+                * This is a clone.  We only want to report this if the '-r'
+                * wasn't specified, or the target is a snapshot.
+                */
+               if (!cbp->cb_recurse &&
+                   zfs_get_type(cbp->cb_target) != ZFS_TYPE_SNAPSHOT)
+                       goto out;
+
+               if (cbp->cb_first) {
+                       (void) fprintf(stderr, gettext("cannot destroy '%s': "
+                           "%s has dependent clones\n"),
+                           zfs_get_name(cbp->cb_target),
+                           zfs_type_to_name(zfs_get_type(cbp->cb_target)));
+                       (void) fprintf(stderr, gettext("use '-R' to destroy "
+                           "the following datasets:\n"));
+                       cbp->cb_first = B_FALSE;
+                       cbp->cb_error = B_TRUE;
+                       cbp->cb_dryrun = B_TRUE;
+               }
+
+               (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
+       }
+
+out:
+       zfs_close(zhp);
+       return (0);
+}
+
+static int
+destroy_callback(zfs_handle_t *zhp, void *data)
+{
+       destroy_cbdata_t *cb = data;
+       const char *name = zfs_get_name(zhp);
+
+       if (cb->cb_verbose) {
+               if (cb->cb_parsable) {
+                       (void) printf("destroy\t%s\n", name);
+               } else if (cb->cb_dryrun) {
+                       (void) printf(gettext("would destroy %s\n"),
+                           name);
+               } else {
+                       (void) printf(gettext("will destroy %s\n"),
+                           name);
+               }
+       }
+
+       /*
+        * Ignore pools (which we've already flagged as an error before getting
+        * here).
+        */
+       if (strchr(zfs_get_name(zhp), '/') == NULL &&
+           zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
+               zfs_close(zhp);
+               return (0);
+       }
+       if (cb->cb_dryrun) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       /*
+        * We batch up all contiguous snapshots (even of different
+        * filesystems) and destroy them with one ioctl.  We can't
+        * simply do all snap deletions and then all fs deletions,
+        * because we must delete a clone before its origin.
+        */
+       if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
+               fnvlist_add_boolean(cb->cb_batchedsnaps, name);
+       } else {
+               int error = zfs_destroy_snaps_nvl(g_zfs,
+                   cb->cb_batchedsnaps, B_FALSE);
+               fnvlist_free(cb->cb_batchedsnaps);
+               cb->cb_batchedsnaps = fnvlist_alloc();
+
+               if (error != 0 ||
+                   zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0) != 0 ||
+                   zfs_destroy(zhp, cb->cb_defer_destroy) != 0) {
+                       zfs_close(zhp);
+                       return (-1);
+               }
+       }
+
+       zfs_close(zhp);
+       return (0);
+}
+
+static int
+destroy_print_cb(zfs_handle_t *zhp, void *arg)
+{
+       destroy_cbdata_t *cb = arg;
+       const char *name = zfs_get_name(zhp);
+       int err = 0;
+
+       if (nvlist_exists(cb->cb_nvl, name)) {
+               if (cb->cb_firstsnap == NULL)
+                       cb->cb_firstsnap = strdup(name);
+               if (cb->cb_prevsnap != NULL)
+                       free(cb->cb_prevsnap);
+               /* this snap continues the current range */
+               cb->cb_prevsnap = strdup(name);
+               if (cb->cb_firstsnap == NULL || cb->cb_prevsnap == NULL)
+                       nomem();
+               if (cb->cb_verbose) {
+                       if (cb->cb_parsable) {
+                               (void) printf("destroy\t%s\n", name);
+                       } else if (cb->cb_dryrun) {
+                               (void) printf(gettext("would destroy %s\n"),
+                                   name);
+                       } else {
+                               (void) printf(gettext("will destroy %s\n"),
+                                   name);
+                       }
+               }
+       } else if (cb->cb_firstsnap != NULL) {
+               /* end of this range */
+               uint64_t used = 0;
+               err = lzc_snaprange_space(cb->cb_firstsnap,
+                   cb->cb_prevsnap, &used);
+               cb->cb_snapused += used;
+               free(cb->cb_firstsnap);
+               cb->cb_firstsnap = NULL;
+               free(cb->cb_prevsnap);
+               cb->cb_prevsnap = NULL;
+       }
+       zfs_close(zhp);
+       return (err);
+}
+
+static int
+destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
+{
+       int err;
+       assert(cb->cb_firstsnap == NULL);
+       assert(cb->cb_prevsnap == NULL);
+       err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
+       if (cb->cb_firstsnap != NULL) {
+               uint64_t used = 0;
+               if (err == 0) {
+                       err = lzc_snaprange_space(cb->cb_firstsnap,
+                           cb->cb_prevsnap, &used);
+               }
+               cb->cb_snapused += used;
+               free(cb->cb_firstsnap);
+               cb->cb_firstsnap = NULL;
+               free(cb->cb_prevsnap);
+               cb->cb_prevsnap = NULL;
+       }
+       return (err);
+}
+
+static int
+snapshot_to_nvl_cb(zfs_handle_t *zhp, void *arg)
+{
+       destroy_cbdata_t *cb = arg;
+       int err = 0;
+
+       /* Check for clones. */
+       if (!cb->cb_doclones && !cb->cb_defer_destroy) {
+               cb->cb_target = zhp;
+               cb->cb_first = B_TRUE;
+               err = zfs_iter_dependents(zhp, B_TRUE,
+                   destroy_check_dependent, cb);
+       }
+
+       if (err == 0) {
+               if (nvlist_add_boolean(cb->cb_nvl, zfs_get_name(zhp)))
+                       nomem();
+       }
+       zfs_close(zhp);
+       return (err);
+}
+
+static int
+gather_snapshots(zfs_handle_t *zhp, void *arg)
+{
+       destroy_cbdata_t *cb = arg;
+       int err = 0;
+
+       err = zfs_iter_snapspec(zhp, cb->cb_snapspec, snapshot_to_nvl_cb, cb);
+       if (err == ENOENT)
+               err = 0;
+       if (err != 0)
+               goto out;
+
+       if (cb->cb_verbose) {
+               err = destroy_print_snapshots(zhp, cb);
+               if (err != 0)
+                       goto out;
+       }
+
+       if (cb->cb_recurse)
+               err = zfs_iter_filesystems(zhp, gather_snapshots, cb);
+
+out:
+       zfs_close(zhp);
+       return (err);
+}
+
+static int
+destroy_clones(destroy_cbdata_t *cb)
+{
+       nvpair_t *pair;
+       for (pair = nvlist_next_nvpair(cb->cb_nvl, NULL);
+           pair != NULL;
+           pair = nvlist_next_nvpair(cb->cb_nvl, pair)) {
+               zfs_handle_t *zhp = zfs_open(g_zfs, nvpair_name(pair),
+                   ZFS_TYPE_SNAPSHOT);
+               if (zhp != NULL) {
+                       boolean_t defer = cb->cb_defer_destroy;
+                       int err;
+
+                       /*
+                        * We can't defer destroy non-snapshots, so set it to
+                        * false while destroying the clones.
+                        */
+                       cb->cb_defer_destroy = B_FALSE;
+                       err = zfs_iter_dependents(zhp, B_FALSE,
+                           destroy_callback, cb);
+                       cb->cb_defer_destroy = defer;
+                       zfs_close(zhp);
+                       if (err != 0)
+                               return (err);
+               }
+       }
+       return (0);
+}
+
+static int
+zfs_do_destroy(int argc, char **argv)
+{
+       destroy_cbdata_t cb = { 0 };
+       int rv = 0;
+       int err = 0;
+       int c;
+       zfs_handle_t *zhp = NULL;
+       char *at, *pound;
+       zfs_type_t type = ZFS_TYPE_DATASET;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "vpndfrR")) != -1) {
+               switch (c) {
+               case 'v':
+                       cb.cb_verbose = B_TRUE;
+                       break;
+               case 'p':
+                       cb.cb_verbose = B_TRUE;
+                       cb.cb_parsable = B_TRUE;
+                       break;
+               case 'n':
+                       cb.cb_dryrun = B_TRUE;
+                       break;
+               case 'd':
+                       cb.cb_defer_destroy = B_TRUE;
+                       type = ZFS_TYPE_SNAPSHOT;
+                       break;
+               case 'f':
+                       cb.cb_force = B_TRUE;
+                       break;
+               case 'r':
+                       cb.cb_recurse = B_TRUE;
+                       break;
+               case 'R':
+                       cb.cb_recurse = B_TRUE;
+                       cb.cb_doclones = B_TRUE;
+                       break;
+               case '?':
+               default:
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc == 0) {
+               (void) fprintf(stderr, gettext("missing dataset argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       at = strchr(argv[0], '@');
+       pound = strchr(argv[0], '#');
+       if (at != NULL) {
+
+               /* Build the list of snaps to destroy in cb_nvl. */
+               cb.cb_nvl = fnvlist_alloc();
+
+               *at = '\0';
+               zhp = zfs_open(g_zfs, argv[0],
+                   ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+               if (zhp == NULL) {
+                       nvlist_free(cb.cb_nvl);
+                       return (1);
+               }
+
+               cb.cb_snapspec = at + 1;
+               if (gather_snapshots(zfs_handle_dup(zhp), &cb) != 0 ||
+                   cb.cb_error) {
+                       rv = 1;
+                       goto out;
+               }
+
+               if (nvlist_empty(cb.cb_nvl)) {
+                       (void) fprintf(stderr, gettext("could not find any "
+                           "snapshots to destroy; check snapshot names.\n"));
+                       rv = 1;
+                       goto out;
+               }
+
+               if (cb.cb_verbose) {
+                       char buf[16];
+                       zfs_nicenum(cb.cb_snapused, buf, sizeof (buf));
+                       if (cb.cb_parsable) {
+                               (void) printf("reclaim\t%llu\n",
+                                   (u_longlong_t)cb.cb_snapused);
+                       } else if (cb.cb_dryrun) {
+                               (void) printf(gettext("would reclaim %s\n"),
+                                   buf);
+                       } else {
+                               (void) printf(gettext("will reclaim %s\n"),
+                                   buf);
+                       }
+               }
+
+               if (!cb.cb_dryrun) {
+                       if (cb.cb_doclones) {
+                               cb.cb_batchedsnaps = fnvlist_alloc();
+                               err = destroy_clones(&cb);
+                               if (err == 0) {
+                                       err = zfs_destroy_snaps_nvl(g_zfs,
+                                           cb.cb_batchedsnaps, B_FALSE);
+                               }
+                               if (err != 0) {
+                                       rv = 1;
+                                       goto out;
+                               }
+                       }
+                       if (err == 0) {
+                               err = zfs_destroy_snaps_nvl(g_zfs, cb.cb_nvl,
+                                   cb.cb_defer_destroy);
+                       }
+               }
+
+               if (err != 0)
+                       rv = 1;
+       } else if (pound != NULL) {
+               int err;
+               nvlist_t *nvl;
+
+               if (cb.cb_dryrun) {
+                       (void) fprintf(stderr,
+                           "dryrun is not supported with bookmark\n");
+                       return (-1);
+               }
+
+               if (cb.cb_defer_destroy) {
+                       (void) fprintf(stderr,
+                           "defer destroy is not supported with bookmark\n");
+                       return (-1);
+               }
+
+               if (cb.cb_recurse) {
+                       (void) fprintf(stderr,
+                           "recursive is not supported with bookmark\n");
+                       return (-1);
+               }
+
+               if (!zfs_bookmark_exists(argv[0])) {
+                       (void) fprintf(stderr, gettext("bookmark '%s' "
+                           "does not exist.\n"), argv[0]);
+                       return (1);
+               }
+
+               nvl = fnvlist_alloc();
+               fnvlist_add_boolean(nvl, argv[0]);
+
+               err = lzc_destroy_bookmarks(nvl, NULL);
+               if (err != 0) {
+                       (void) zfs_standard_error(g_zfs, err,
+                           "cannot destroy bookmark");
+               }
+
+               nvlist_free(nvl);
+
+               return (err);
+       } else {
+               /* Open the given dataset */
+               if ((zhp = zfs_open(g_zfs, argv[0], type)) == NULL)
+                       return (1);
+
+               cb.cb_target = zhp;
+
+               /*
+                * Perform an explicit check for pools before going any further.
+                */
+               if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
+                   zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) {
+                       (void) fprintf(stderr, gettext("cannot destroy '%s': "
+                           "operation does not apply to pools\n"),
+                           zfs_get_name(zhp));
+                       (void) fprintf(stderr, gettext("use 'zfs destroy -r "
+                           "%s' to destroy all datasets in the pool\n"),
+                           zfs_get_name(zhp));
+                       (void) fprintf(stderr, gettext("use 'zpool destroy %s' "
+                           "to destroy the pool itself\n"), zfs_get_name(zhp));
+                       rv = 1;
+                       goto out;
+               }
+
+               /*
+                * Check for any dependents and/or clones.
+                */
+               cb.cb_first = B_TRUE;
+               if (!cb.cb_doclones &&
+                   zfs_iter_dependents(zhp, B_TRUE, destroy_check_dependent,
+                   &cb) != 0) {
+                       rv = 1;
+                       goto out;
+               }
+
+               if (cb.cb_error) {
+                       rv = 1;
+                       goto out;
+               }
+
+               cb.cb_batchedsnaps = fnvlist_alloc();
+               if (zfs_iter_dependents(zhp, B_FALSE, destroy_callback,
+                   &cb) != 0) {
+                       rv = 1;
+                       goto out;
+               }
+
+               /*
+                * Do the real thing.  The callback will close the
+                * handle regardless of whether it succeeds or not.
+                */
+               err = destroy_callback(zhp, &cb);
+               zhp = NULL;
+               if (err == 0) {
+                       err = zfs_destroy_snaps_nvl(g_zfs,
+                           cb.cb_batchedsnaps, cb.cb_defer_destroy);
+               }
+               if (err != 0)
+                       rv = 1;
+       }
+
+out:
+       fnvlist_free(cb.cb_batchedsnaps);
+       fnvlist_free(cb.cb_nvl);
+       if (zhp != NULL)
+               zfs_close(zhp);
+       return (rv);
+}
+
+static boolean_t
+is_recvd_column(zprop_get_cbdata_t *cbp)
+{
+       int i;
+       zfs_get_column_t col;
+
+       for (i = 0; i < ZFS_GET_NCOLS &&
+           (col = cbp->cb_columns[i]) != GET_COL_NONE; i++)
+               if (col == GET_COL_RECVD)
+                       return (B_TRUE);
+       return (B_FALSE);
+}
+
+/*
+ * zfs get [-rHp] [-o all | field[,field]...] [-s source[,source]...]
+ *     < all | property[,property]... > < fs | snap | vol > ...
+ *
+ *     -r      recurse over any child datasets
+ *     -H      scripted mode.  Headers are stripped, and fields are separated
+ *             by tabs instead of spaces.
+ *     -o      Set of fields to display.  One of "name,property,value,
+ *             received,source". Default is "name,property,value,source".
+ *             "all" is an alias for all five.
+ *     -s      Set of sources to allow.  One of
+ *             "local,default,inherited,received,temporary,none".  Default is
+ *             all six.
+ *     -p      Display values in parsable (literal) format.
+ *
+ *  Prints properties for the given datasets.  The user can control which
+ *  columns to display as well as which property types to allow.
+ */
+
+/*
+ * Invoked to display the properties for a single dataset.
+ */
+static int
+get_callback(zfs_handle_t *zhp, void *data)
+{
+       char buf[ZFS_MAXPROPLEN];
+       char rbuf[ZFS_MAXPROPLEN];
+       zprop_source_t sourcetype;
+       char source[ZFS_MAX_DATASET_NAME_LEN];
+       zprop_get_cbdata_t *cbp = data;
+       nvlist_t *user_props = zfs_get_user_props(zhp);
+       zprop_list_t *pl = cbp->cb_proplist;
+       nvlist_t *propval;
+       char *strval;
+       char *sourceval;
+       boolean_t received = is_recvd_column(cbp);
+
+       for (; pl != NULL; pl = pl->pl_next) {
+               char *recvdval = NULL;
+               /*
+                * Skip the special fake placeholder.  This will also skip over
+                * the name property when 'all' is specified.
+                */
+               if (pl->pl_prop == ZFS_PROP_NAME &&
+                   pl == cbp->cb_proplist)
+                       continue;
+
+               if (pl->pl_prop != ZPROP_INVAL) {
+                       if (zfs_prop_get(zhp, pl->pl_prop, buf,
+                           sizeof (buf), &sourcetype, source,
+                           sizeof (source),
+                           cbp->cb_literal) != 0) {
+                               if (pl->pl_all)
+                                       continue;
+                               if (!zfs_prop_valid_for_type(pl->pl_prop,
+                                   ZFS_TYPE_DATASET, B_FALSE)) {
+                                       (void) fprintf(stderr,
+                                           gettext("No such property '%s'\n"),
+                                           zfs_prop_to_name(pl->pl_prop));
+                                       continue;
+                               }
+                               sourcetype = ZPROP_SRC_NONE;
+                               (void) strlcpy(buf, "-", sizeof (buf));
+                       }
+
+                       if (received && (zfs_prop_get_recvd(zhp,
+                           zfs_prop_to_name(pl->pl_prop), rbuf, sizeof (rbuf),
+                           cbp->cb_literal) == 0))
+                               recvdval = rbuf;
+
+                       zprop_print_one_property(zfs_get_name(zhp), cbp,
+                           zfs_prop_to_name(pl->pl_prop),
+                           buf, sourcetype, source, recvdval);
+               } else if (zfs_prop_userquota(pl->pl_user_prop)) {
+                       sourcetype = ZPROP_SRC_LOCAL;
+
+                       if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
+                           buf, sizeof (buf), cbp->cb_literal) != 0) {
+                               sourcetype = ZPROP_SRC_NONE;
+                               (void) strlcpy(buf, "-", sizeof (buf));
+                       }
+
+                       zprop_print_one_property(zfs_get_name(zhp), cbp,
+                           pl->pl_user_prop, buf, sourcetype, source, NULL);
+               } else if (zfs_prop_written(pl->pl_user_prop)) {
+                       sourcetype = ZPROP_SRC_LOCAL;
+
+                       if (zfs_prop_get_written(zhp, pl->pl_user_prop,
+                           buf, sizeof (buf), cbp->cb_literal) != 0) {
+                               sourcetype = ZPROP_SRC_NONE;
+                               (void) strlcpy(buf, "-", sizeof (buf));
+                       }
+
+                       zprop_print_one_property(zfs_get_name(zhp), cbp,
+                           pl->pl_user_prop, buf, sourcetype, source, NULL);
+               } else {
+                       if (nvlist_lookup_nvlist(user_props,
+                           pl->pl_user_prop, &propval) != 0) {
+                               if (pl->pl_all)
+                                       continue;
+                               sourcetype = ZPROP_SRC_NONE;
+                               strval = "-";
+                       } else {
+                               verify(nvlist_lookup_string(propval,
+                                   ZPROP_VALUE, &strval) == 0);
+                               verify(nvlist_lookup_string(propval,
+                                   ZPROP_SOURCE, &sourceval) == 0);
+
+                               if (strcmp(sourceval,
+                                   zfs_get_name(zhp)) == 0) {
+                                       sourcetype = ZPROP_SRC_LOCAL;
+                               } else if (strcmp(sourceval,
+                                   ZPROP_SOURCE_VAL_RECVD) == 0) {
+                                       sourcetype = ZPROP_SRC_RECEIVED;
+                               } else {
+                                       sourcetype = ZPROP_SRC_INHERITED;
+                                       (void) strlcpy(source,
+                                           sourceval, sizeof (source));
+                               }
+                       }
+
+                       if (received && (zfs_prop_get_recvd(zhp,
+                           pl->pl_user_prop, rbuf, sizeof (rbuf),
+                           cbp->cb_literal) == 0))
+                               recvdval = rbuf;
+
+                       zprop_print_one_property(zfs_get_name(zhp), cbp,
+                           pl->pl_user_prop, strval, sourcetype,
+                           source, recvdval);
+               }
+       }
+
+       return (0);
+}
+
+static int
+zfs_do_get(int argc, char **argv)
+{
+       zprop_get_cbdata_t cb = { 0 };
+       int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
+       int types = ZFS_TYPE_DATASET;
+       char *value, *fields;
+       int ret = 0;
+       int limit = 0;
+       zprop_list_t fake_name = { 0 };
+
+       /*
+        * Set up default columns and sources.
+        */
+       cb.cb_sources = ZPROP_SRC_ALL;
+       cb.cb_columns[0] = GET_COL_NAME;
+       cb.cb_columns[1] = GET_COL_PROPERTY;
+       cb.cb_columns[2] = GET_COL_VALUE;
+       cb.cb_columns[3] = GET_COL_SOURCE;
+       cb.cb_type = ZFS_TYPE_DATASET;
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":d:o:s:rt:Hp")) != -1) {
+               switch (c) {
+               case 'p':
+                       cb.cb_literal = B_TRUE;
+                       break;
+               case 'd':
+                       limit = parse_depth(optarg, &flags);
+                       break;
+               case 'r':
+                       flags |= ZFS_ITER_RECURSE;
+                       break;
+               case 'H':
+                       cb.cb_scripted = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case 'o':
+                       /*
+                        * Process the set of columns to display.  We zero out
+                        * the structure to give us a blank slate.
+                        */
+                       bzero(&cb.cb_columns, sizeof (cb.cb_columns));
+                       i = 0;
+                       while (*optarg != '\0') {
+                               static char *col_subopts[] =
+                                   { "name", "property", "value", "received",
+                                   "source", "all", NULL };
+
+                               if (i == ZFS_GET_NCOLS) {
+                                       (void) fprintf(stderr, gettext("too "
+                                           "many fields given to -o "
+                                           "option\n"));
+                                       usage(B_FALSE);
+                               }
+
+                               switch (getsubopt(&optarg, col_subopts,
+                                   &value)) {
+                               case 0:
+                                       cb.cb_columns[i++] = GET_COL_NAME;
+                                       break;
+                               case 1:
+                                       cb.cb_columns[i++] = GET_COL_PROPERTY;
+                                       break;
+                               case 2:
+                                       cb.cb_columns[i++] = GET_COL_VALUE;
+                                       break;
+                               case 3:
+                                       cb.cb_columns[i++] = GET_COL_RECVD;
+                                       flags |= ZFS_ITER_RECVD_PROPS;
+                                       break;
+                               case 4:
+                                       cb.cb_columns[i++] = GET_COL_SOURCE;
+                                       break;
+                               case 5:
+                                       if (i > 0) {
+                                               (void) fprintf(stderr,
+                                                   gettext("\"all\" conflicts "
+                                                   "with specific fields "
+                                                   "given to -o option\n"));
+                                               usage(B_FALSE);
+                                       }
+                                       cb.cb_columns[0] = GET_COL_NAME;
+                                       cb.cb_columns[1] = GET_COL_PROPERTY;
+                                       cb.cb_columns[2] = GET_COL_VALUE;
+                                       cb.cb_columns[3] = GET_COL_RECVD;
+                                       cb.cb_columns[4] = GET_COL_SOURCE;
+                                       flags |= ZFS_ITER_RECVD_PROPS;
+                                       i = ZFS_GET_NCOLS;
+                                       break;
+                               default:
+                                       (void) fprintf(stderr,
+                                           gettext("invalid column name "
+                                           "'%s'\n"), value);
+                                       usage(B_FALSE);
+                               }
+                       }
+                       break;
+
+               case 's':
+                       cb.cb_sources = 0;
+                       while (*optarg != '\0') {
+                               static char *source_subopts[] = {
+                                       "local", "default", "inherited",
+                                       "received", "temporary", "none",
+                                       NULL };
+
+                               switch (getsubopt(&optarg, source_subopts,
+                                   &value)) {
+                               case 0:
+                                       cb.cb_sources |= ZPROP_SRC_LOCAL;
+                                       break;
+                               case 1:
+                                       cb.cb_sources |= ZPROP_SRC_DEFAULT;
+                                       break;
+                               case 2:
+                                       cb.cb_sources |= ZPROP_SRC_INHERITED;
+                                       break;
+                               case 3:
+                                       cb.cb_sources |= ZPROP_SRC_RECEIVED;
+                                       break;
+                               case 4:
+                                       cb.cb_sources |= ZPROP_SRC_TEMPORARY;
+                                       break;
+                               case 5:
+                                       cb.cb_sources |= ZPROP_SRC_NONE;
+                                       break;
+                               default:
+                                       (void) fprintf(stderr,
+                                           gettext("invalid source "
+                                           "'%s'\n"), value);
+                                       usage(B_FALSE);
+                               }
+                       }
+                       break;
+
+               case 't':
+                       types = 0;
+                       flags &= ~ZFS_ITER_PROP_LISTSNAPS;
+                       while (*optarg != '\0') {
+                               static char *type_subopts[] = { "filesystem",
+                                   "volume", "snapshot", "bookmark",
+                                   "all", NULL };
+
+                               switch (getsubopt(&optarg, type_subopts,
+                                   &value)) {
+                               case 0:
+                                       types |= ZFS_TYPE_FILESYSTEM;
+                                       break;
+                               case 1:
+                                       types |= ZFS_TYPE_VOLUME;
+                                       break;
+                               case 2:
+                                       types |= ZFS_TYPE_SNAPSHOT;
+                                       break;
+                               case 3:
+                                       types |= ZFS_TYPE_BOOKMARK;
+                                       break;
+                               case 4:
+                                       types = ZFS_TYPE_DATASET |
+                                           ZFS_TYPE_BOOKMARK;
+                                       break;
+
+                               default:
+                                       (void) fprintf(stderr,
+                                           gettext("invalid type '%s'\n"),
+                                           value);
+                                       usage(B_FALSE);
+                               }
+                       }
+                       break;
+
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing property "
+                   "argument\n"));
+               usage(B_FALSE);
+       }
+
+       fields = argv[0];
+
+       if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
+           != 0)
+               usage(B_FALSE);
+
+       argc--;
+       argv++;
+
+       /*
+        * As part of zfs_expand_proplist(), we keep track of the maximum column
+        * width for each property.  For the 'NAME' (and 'SOURCE') columns, we
+        * need to know the maximum name length.  However, the user likely did
+        * not specify 'name' as one of the properties to fetch, so we need to
+        * make sure we always include at least this property for
+        * print_get_headers() to work properly.
+        */
+       if (cb.cb_proplist != NULL) {
+               fake_name.pl_prop = ZFS_PROP_NAME;
+               fake_name.pl_width = strlen(gettext("NAME"));
+               fake_name.pl_next = cb.cb_proplist;
+               cb.cb_proplist = &fake_name;
+       }
+
+       cb.cb_first = B_TRUE;
+
+       /* run for each object */
+       ret = zfs_for_each(argc, argv, flags, types, NULL,
+           &cb.cb_proplist, limit, get_callback, &cb);
+
+       if (cb.cb_proplist == &fake_name)
+               zprop_free_list(fake_name.pl_next);
+       else
+               zprop_free_list(cb.cb_proplist);
+
+       return (ret);
+}
+
+/*
+ * inherit [-rS] <property> <fs|vol> ...
+ *
+ *     -r      Recurse over all children
+ *     -S      Revert to received value, if any
+ *
+ * For each dataset specified on the command line, inherit the given property
+ * from its parent.  Inheriting a property at the pool level will cause it to
+ * use the default value.  The '-r' flag will recurse over all children, and is
+ * useful for setting a property on a hierarchy-wide basis, regardless of any
+ * local modifications for each dataset.
+ */
+
+typedef struct inherit_cbdata {
+       const char *cb_propname;
+       boolean_t cb_received;
+} inherit_cbdata_t;
+
+static int
+inherit_recurse_cb(zfs_handle_t *zhp, void *data)
+{
+       inherit_cbdata_t *cb = data;
+       zfs_prop_t prop = zfs_name_to_prop(cb->cb_propname);
+
+       /*
+        * If we're doing it recursively, then ignore properties that
+        * are not valid for this type of dataset.
+        */
+       if (prop != ZPROP_INVAL &&
+           !zfs_prop_valid_for_type(prop, zfs_get_type(zhp), B_FALSE))
+               return (0);
+
+       return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
+}
+
+static int
+inherit_cb(zfs_handle_t *zhp, void *data)
+{
+       inherit_cbdata_t *cb = data;
+
+       return (zfs_prop_inherit(zhp, cb->cb_propname, cb->cb_received) != 0);
+}
+
+static int
+zfs_do_inherit(int argc, char **argv)
+{
+       int c;
+       zfs_prop_t prop;
+       inherit_cbdata_t cb = { 0 };
+       char *propname;
+       int ret = 0;
+       int flags = 0;
+       boolean_t received = B_FALSE;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "rS")) != -1) {
+               switch (c) {
+               case 'r':
+                       flags |= ZFS_ITER_RECURSE;
+                       break;
+               case 'S':
+                       received = B_TRUE;
+                       break;
+               case '?':
+               default:
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing property argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing dataset argument\n"));
+               usage(B_FALSE);
+       }
+
+       propname = argv[0];
+       argc--;
+       argv++;
+
+       if ((prop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
+               if (zfs_prop_readonly(prop)) {
+                       (void) fprintf(stderr, gettext(
+                           "%s property is read-only\n"),
+                           propname);
+                       return (1);
+               }
+               if (!zfs_prop_inheritable(prop) && !received) {
+                       (void) fprintf(stderr, gettext("'%s' property cannot "
+                           "be inherited\n"), propname);
+                       if (prop == ZFS_PROP_QUOTA ||
+                           prop == ZFS_PROP_RESERVATION ||
+                           prop == ZFS_PROP_REFQUOTA ||
+                           prop == ZFS_PROP_REFRESERVATION) {
+                               (void) fprintf(stderr, gettext("use 'zfs set "
+                                   "%s=none' to clear\n"), propname);
+                               (void) fprintf(stderr, gettext("use 'zfs "
+                                   "inherit -S %s' to revert to received "
+                                   "value\n"), propname);
+                       }
+                       return (1);
+               }
+               if (received && (prop == ZFS_PROP_VOLSIZE ||
+                   prop == ZFS_PROP_VERSION)) {
+                       (void) fprintf(stderr, gettext("'%s' property cannot "
+                           "be reverted to a received value\n"), propname);
+                       return (1);
+               }
+       } else if (!zfs_prop_user(propname)) {
+               (void) fprintf(stderr, gettext("invalid property '%s'\n"),
+                   propname);
+               usage(B_FALSE);
+       }
+
+       cb.cb_propname = propname;
+       cb.cb_received = received;
+
+       if (flags & ZFS_ITER_RECURSE) {
+               ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
+                   NULL, NULL, 0, inherit_recurse_cb, &cb);
+       } else {
+               ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_DATASET,
+                   NULL, NULL, 0, inherit_cb, &cb);
+       }
+
+       return (ret);
+}
+
+typedef struct upgrade_cbdata {
+       uint64_t cb_numupgraded;
+       uint64_t cb_numsamegraded;
+       uint64_t cb_numfailed;
+       uint64_t cb_version;
+       boolean_t cb_newer;
+       boolean_t cb_foundone;
+       char cb_lastfs[ZFS_MAX_DATASET_NAME_LEN];
+} upgrade_cbdata_t;
+
+static int
+same_pool(zfs_handle_t *zhp, const char *name)
+{
+       int len1 = strcspn(name, "/@");
+       const char *zhname = zfs_get_name(zhp);
+       int len2 = strcspn(zhname, "/@");
+
+       if (len1 != len2)
+               return (B_FALSE);
+       return (strncmp(name, zhname, len1) == 0);
+}
+
+static int
+upgrade_list_callback(zfs_handle_t *zhp, void *data)
+{
+       upgrade_cbdata_t *cb = data;
+       int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+
+       /* list if it's old/new */
+       if ((!cb->cb_newer && version < ZPL_VERSION) ||
+           (cb->cb_newer && version > ZPL_VERSION)) {
+               char *str;
+               if (cb->cb_newer) {
+                       str = gettext("The following filesystems are "
+                           "formatted using a newer software version and\n"
+                           "cannot be accessed on the current system.\n\n");
+               } else {
+                       str = gettext("The following filesystems are "
+                           "out of date, and can be upgraded.  After being\n"
+                           "upgraded, these filesystems (and any 'zfs send' "
+                           "streams generated from\n"
+                           "subsequent snapshots) will no longer be "
+                           "accessible by older software versions.\n\n");
+               }
+
+               if (!cb->cb_foundone) {
+                       (void) puts(str);
+                       (void) printf(gettext("VER  FILESYSTEM\n"));
+                       (void) printf(gettext("---  ------------\n"));
+                       cb->cb_foundone = B_TRUE;
+               }
+
+               (void) printf("%2u   %s\n", version, zfs_get_name(zhp));
+       }
+
+       return (0);
+}
+
+static int
+upgrade_set_callback(zfs_handle_t *zhp, void *data)
+{
+       upgrade_cbdata_t *cb = data;
+       int version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+       int needed_spa_version;
+       int spa_version;
+
+       if (zfs_spa_version(zhp, &spa_version) < 0)
+               return (-1);
+
+       needed_spa_version = zfs_spa_version_map(cb->cb_version);
+
+       if (needed_spa_version < 0)
+               return (-1);
+
+       if (spa_version < needed_spa_version) {
+               /* can't upgrade */
+               (void) printf(gettext("%s: can not be "
+                   "upgraded; the pool version needs to first "
+                   "be upgraded\nto version %d\n\n"),
+                   zfs_get_name(zhp), needed_spa_version);
+               cb->cb_numfailed++;
+               return (0);
+       }
+
+       /* upgrade */
+       if (version < cb->cb_version) {
+               char verstr[16];
+               (void) snprintf(verstr, sizeof (verstr),
+                   "%llu", (u_longlong_t)cb->cb_version);
+               if (cb->cb_lastfs[0] && !same_pool(zhp, cb->cb_lastfs)) {
+                       /*
+                        * If they did "zfs upgrade -a", then we could
+                        * be doing ioctls to different pools.  We need
+                        * to log this history once to each pool, and bypass
+                        * the normal history logging that happens in main().
+                        */
+                       (void) zpool_log_history(g_zfs, history_str);
+                       log_history = B_FALSE;
+               }
+               if (zfs_prop_set(zhp, "version", verstr) == 0)
+                       cb->cb_numupgraded++;
+               else
+                       cb->cb_numfailed++;
+               (void) strcpy(cb->cb_lastfs, zfs_get_name(zhp));
+       } else if (version > cb->cb_version) {
+               /* can't downgrade */
+               (void) printf(gettext("%s: can not be downgraded; "
+                   "it is already at version %u\n"),
+                   zfs_get_name(zhp), version);
+               cb->cb_numfailed++;
+       } else {
+               cb->cb_numsamegraded++;
+       }
+       return (0);
+}
+
+/*
+ * zfs upgrade
+ * zfs upgrade -v
+ * zfs upgrade [-r] [-V <version>] <-a | filesystem>
+ */
+static int
+zfs_do_upgrade(int argc, char **argv)
+{
+       boolean_t all = B_FALSE;
+       boolean_t showversions = B_FALSE;
+       int ret = 0;
+       upgrade_cbdata_t cb = { 0 };
+       signed char c;
+       int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "rvV:a")) != -1) {
+               switch (c) {
+               case 'r':
+                       flags |= ZFS_ITER_RECURSE;
+                       break;
+               case 'v':
+                       showversions = B_TRUE;
+                       break;
+               case 'V':
+                       if (zfs_prop_string_to_index(ZFS_PROP_VERSION,
+                           optarg, &cb.cb_version) != 0) {
+                               (void) fprintf(stderr,
+                                   gettext("invalid version %s\n"), optarg);
+                               usage(B_FALSE);
+                       }
+                       break;
+               case 'a':
+                       all = B_TRUE;
+                       break;
+               case '?':
+               default:
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if ((!all && !argc) && ((flags & ZFS_ITER_RECURSE) | cb.cb_version))
+               usage(B_FALSE);
+       if (showversions && (flags & ZFS_ITER_RECURSE || all ||
+           cb.cb_version || argc))
+               usage(B_FALSE);
+       if ((all || argc) && (showversions))
+               usage(B_FALSE);
+       if (all && argc)
+               usage(B_FALSE);
+
+       if (showversions) {
+               /* Show info on available versions. */
+               (void) printf(gettext("The following filesystem versions are "
+                   "supported:\n\n"));
+               (void) printf(gettext("VER  DESCRIPTION\n"));
+               (void) printf("---  -----------------------------------------"
+                   "---------------\n");
+               (void) printf(gettext(" 1   Initial ZFS filesystem version\n"));
+               (void) printf(gettext(" 2   Enhanced directory entries\n"));
+               (void) printf(gettext(" 3   Case insensitive and filesystem "
+                   "user identifier (FUID)\n"));
+               (void) printf(gettext(" 4   userquota, groupquota "
+                   "properties\n"));
+               (void) printf(gettext(" 5   System attributes\n"));
+               (void) printf(gettext("\nFor more information on a particular "
+                   "version, including supported releases,\n"));
+               (void) printf("see the ZFS Administration Guide.\n\n");
+               ret = 0;
+       } else if (argc || all) {
+               /* Upgrade filesystems */
+               if (cb.cb_version == 0)
+                       cb.cb_version = ZPL_VERSION;
+               ret = zfs_for_each(argc, argv, flags, ZFS_TYPE_FILESYSTEM,
+                   NULL, NULL, 0, upgrade_set_callback, &cb);
+               (void) printf(gettext("%llu filesystems upgraded\n"),
+                   (u_longlong_t)cb.cb_numupgraded);
+               if (cb.cb_numsamegraded) {
+                       (void) printf(gettext("%llu filesystems already at "
+                           "this version\n"),
+                           (u_longlong_t)cb.cb_numsamegraded);
+               }
+               if (cb.cb_numfailed != 0)
+                       ret = 1;
+       } else {
+               /* List old-version filesytems */
+               boolean_t found;
+               (void) printf(gettext("This system is currently running "
+                   "ZFS filesystem version %llu.\n\n"), ZPL_VERSION);
+
+               flags |= ZFS_ITER_RECURSE;
+               ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
+                   NULL, NULL, 0, upgrade_list_callback, &cb);
+
+               found = cb.cb_foundone;
+               cb.cb_foundone = B_FALSE;
+               cb.cb_newer = B_TRUE;
+
+               ret = zfs_for_each(0, NULL, flags, ZFS_TYPE_FILESYSTEM,
+                   NULL, NULL, 0, upgrade_list_callback, &cb);
+
+               if (!cb.cb_foundone && !found) {
+                       (void) printf(gettext("All filesystems are "
+                           "formatted with the current version.\n"));
+               }
+       }
+
+       return (ret);
+}
+
+/*
+ * zfs userspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
+ *               [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
+ * zfs groupspace [-Hinp] [-o field[,...]] [-s field [-s field]...]
+ *                [-S field [-S field]...] [-t type[,...]] filesystem | snapshot
+ *
+ *     -H      Scripted mode; elide headers and separate columns by tabs.
+ *     -i      Translate SID to POSIX ID.
+ *     -n      Print numeric ID instead of user/group name.
+ *     -o      Control which fields to display.
+ *     -p      Use exact (parsable) numeric output.
+ *     -s      Specify sort columns, descending order.
+ *     -S      Specify sort columns, ascending order.
+ *     -t      Control which object types to display.
+ *
+ *     Displays space consumed by, and quotas on, each user in the specified
+ *     filesystem or snapshot.
+ */
+
+/* us_field_types, us_field_hdr and us_field_names should be kept in sync */
+enum us_field_types {
+       USFIELD_TYPE,
+       USFIELD_NAME,
+       USFIELD_USED,
+       USFIELD_QUOTA,
+       USFIELD_OBJUSED,
+       USFIELD_OBJQUOTA
+};
+static char *us_field_hdr[] = { "TYPE", "NAME", "USED", "QUOTA",
+                                   "OBJUSED", "OBJQUOTA" };
+static char *us_field_names[] = { "type", "name", "used", "quota",
+                                   "objused", "objquota" };
+#define        USFIELD_LAST    (sizeof (us_field_names) / sizeof (char *))
+
+#define        USTYPE_PSX_GRP  (1 << 0)
+#define        USTYPE_PSX_USR  (1 << 1)
+#define        USTYPE_SMB_GRP  (1 << 2)
+#define        USTYPE_SMB_USR  (1 << 3)
+#define        USTYPE_ALL      \
+       (USTYPE_PSX_GRP | USTYPE_PSX_USR | USTYPE_SMB_GRP | USTYPE_SMB_USR)
+
+static int us_type_bits[] = {
+       USTYPE_PSX_GRP,
+       USTYPE_PSX_USR,
+       USTYPE_SMB_GRP,
+       USTYPE_SMB_USR,
+       USTYPE_ALL
+};
+static char *us_type_names[] = { "posixgroup", "posixuser", "smbgroup",
+       "smbuser", "all" };
+
+typedef struct us_node {
+       nvlist_t        *usn_nvl;
+       uu_avl_node_t   usn_avlnode;
+       uu_list_node_t  usn_listnode;
+} us_node_t;
+
+typedef struct us_cbdata {
+       nvlist_t        **cb_nvlp;
+       uu_avl_pool_t   *cb_avl_pool;
+       uu_avl_t        *cb_avl;
+       boolean_t       cb_numname;
+       boolean_t       cb_nicenum;
+       boolean_t       cb_sid2posix;
+       zfs_userquota_prop_t cb_prop;
+       zfs_sort_column_t *cb_sortcol;
+       size_t          cb_width[USFIELD_LAST];
+} us_cbdata_t;
+
+static boolean_t us_populated = B_FALSE;
+
+typedef struct {
+       zfs_sort_column_t *si_sortcol;
+       boolean_t       si_numname;
+} us_sort_info_t;
+
+static int
+us_field_index(char *field)
+{
+       int i;
+
+       for (i = 0; i < USFIELD_LAST; i++) {
+               if (strcmp(field, us_field_names[i]) == 0)
+                       return (i);
+       }
+
+       return (-1);
+}
+
+static int
+us_compare(const void *larg, const void *rarg, void *unused)
+{
+       const us_node_t *l = larg;
+       const us_node_t *r = rarg;
+       us_sort_info_t *si = (us_sort_info_t *)unused;
+       zfs_sort_column_t *sortcol = si->si_sortcol;
+       boolean_t numname = si->si_numname;
+       nvlist_t *lnvl = l->usn_nvl;
+       nvlist_t *rnvl = r->usn_nvl;
+       int rc = 0;
+       boolean_t lvb, rvb;
+
+       for (; sortcol != NULL; sortcol = sortcol->sc_next) {
+               char *lvstr = "";
+               char *rvstr = "";
+               uint32_t lv32 = 0;
+               uint32_t rv32 = 0;
+               uint64_t lv64 = 0;
+               uint64_t rv64 = 0;
+               zfs_prop_t prop = sortcol->sc_prop;
+               const char *propname = NULL;
+               boolean_t reverse = sortcol->sc_reverse;
+
+               switch (prop) {
+               case ZFS_PROP_TYPE:
+                       propname = "type";
+                       (void) nvlist_lookup_uint32(lnvl, propname, &lv32);
+                       (void) nvlist_lookup_uint32(rnvl, propname, &rv32);
+                       if (rv32 != lv32)
+                               rc = (rv32 < lv32) ? 1 : -1;
+                       break;
+               case ZFS_PROP_NAME:
+                       propname = "name";
+                       if (numname) {
+compare_nums:
+                               (void) nvlist_lookup_uint64(lnvl, propname,
+                                   &lv64);
+                               (void) nvlist_lookup_uint64(rnvl, propname,
+                                   &rv64);
+                               if (rv64 != lv64)
+                                       rc = (rv64 < lv64) ? 1 : -1;
+                       } else {
+                               if ((nvlist_lookup_string(lnvl, propname,
+                                               &lvstr) == ENOENT) ||
+                                   (nvlist_lookup_string(rnvl, propname,
+                                               &rvstr) == ENOENT)) {
+                                       goto compare_nums;
+                               }
+                               rc = strcmp(lvstr, rvstr);
+                       }
+                       break;
+               case ZFS_PROP_USED:
+               case ZFS_PROP_QUOTA:
+                       if (!us_populated)
+                               break;
+                       if (prop == ZFS_PROP_USED)
+                               propname = "used";
+                       else
+                               propname = "quota";
+                       (void) nvlist_lookup_uint64(lnvl, propname, &lv64);
+                       (void) nvlist_lookup_uint64(rnvl, propname, &rv64);
+                       if (rv64 != lv64)
+                               rc = (rv64 < lv64) ? 1 : -1;
+                       break;
+               default:
+                       break;
+               }
+
+               if (rc != 0) {
+                       if (rc < 0)
+                               return (reverse ? 1 : -1);
+                       else
+                               return (reverse ? -1 : 1);
+               }
+       }
+
+       /*
+        * If entries still seem to be the same, check if they are of the same
+        * type (smbentity is added only if we are doing SID to POSIX ID
+        * translation where we can have duplicate type/name combinations).
+        */
+       if (nvlist_lookup_boolean_value(lnvl, "smbentity", &lvb) == 0 &&
+           nvlist_lookup_boolean_value(rnvl, "smbentity", &rvb) == 0 &&
+           lvb != rvb)
+               return (lvb < rvb ? -1 : 1);
+
+       return (0);
+}
+
+static boolean_t
+zfs_prop_is_user(unsigned p)
+{
+       return (p == ZFS_PROP_USERUSED || p == ZFS_PROP_USERQUOTA ||
+           p == ZFS_PROP_USEROBJUSED || p == ZFS_PROP_USEROBJQUOTA);
+}
+
+static boolean_t
+zfs_prop_is_group(unsigned p)
+{
+       return (p == ZFS_PROP_GROUPUSED || p == ZFS_PROP_GROUPQUOTA ||
+           p == ZFS_PROP_GROUPOBJUSED || p == ZFS_PROP_GROUPOBJQUOTA);
+}
+
+static inline const char *
+us_type2str(unsigned field_type)
+{
+       switch (field_type) {
+       case USTYPE_PSX_USR:
+               return ("POSIX User");
+       case USTYPE_PSX_GRP:
+               return ("POSIX Group");
+       case USTYPE_SMB_USR:
+               return ("SMB User");
+       case USTYPE_SMB_GRP:
+               return ("SMB Group");
+       default:
+               return ("Undefined");
+       }
+}
+
+static int
+userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
+{
+       us_cbdata_t *cb = (us_cbdata_t *)arg;
+       zfs_userquota_prop_t prop = cb->cb_prop;
+       char *name = NULL;
+       char *propname;
+       char sizebuf[32];
+       us_node_t *node;
+       uu_avl_pool_t *avl_pool = cb->cb_avl_pool;
+       uu_avl_t *avl = cb->cb_avl;
+       uu_avl_index_t idx;
+       nvlist_t *props;
+       us_node_t *n;
+       zfs_sort_column_t *sortcol = cb->cb_sortcol;
+       unsigned type = 0;
+       const char *typestr;
+       size_t namelen;
+       size_t typelen;
+       size_t sizelen;
+       int typeidx, nameidx, sizeidx;
+       us_sort_info_t sortinfo = { sortcol, cb->cb_numname };
+       boolean_t smbentity = B_FALSE;
+
+       if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+       node = safe_malloc(sizeof (us_node_t));
+       uu_avl_node_init(node, &node->usn_avlnode, avl_pool);
+       node->usn_nvl = props;
+
+       if (domain != NULL && domain[0] != '\0') {
+#ifdef HAVE_IDMAP
+               /* SMB */
+               char sid[MAXNAMELEN + 32];
+               uid_t id;
+               uint64_t classes;
+               int err;
+               directory_error_t e;
+
+               smbentity = B_TRUE;
+
+               (void) snprintf(sid, sizeof (sid), "%s-%u", domain, rid);
+
+               if (prop == ZFS_PROP_GROUPUSED || prop == ZFS_PROP_GROUPQUOTA) {
+                       type = USTYPE_SMB_GRP;
+                       err = sid_to_id(sid, B_FALSE, &id);
+               } else {
+                       type = USTYPE_SMB_USR;
+                       err = sid_to_id(sid, B_TRUE, &id);
+               }
+
+               if (err == 0) {
+                       rid = id;
+                       if (!cb->cb_sid2posix) {
+                               e = directory_name_from_sid(NULL, sid, &name,
+                                   &classes);
+                               if (e != NULL)
+                                       directory_error_free(e);
+                               if (name == NULL)
+                                       name = sid;
+                       }
+               }
+#else
+               nvlist_free(props);
+               free(node);
+
+               return (-1);
+#endif /* HAVE_IDMAP */
+       }
+
+       if (cb->cb_sid2posix || domain == NULL || domain[0] == '\0') {
+               /* POSIX or -i */
+               if (zfs_prop_is_group(prop)) {
+                       type = USTYPE_PSX_GRP;
+                       if (!cb->cb_numname) {
+                               struct group *g;
+
+                               if ((g = getgrgid(rid)) != NULL)
+                                       name = g->gr_name;
+                       }
+               } else {
+                       type = USTYPE_PSX_USR;
+                       if (!cb->cb_numname) {
+                               struct passwd *p;
+
+                               if ((p = getpwuid(rid)) != NULL)
+                                       name = p->pw_name;
+                       }
+               }
+       }
+
+       /*
+        * Make sure that the type/name combination is unique when doing
+        * SID to POSIX ID translation (hence changing the type from SMB to
+        * POSIX).
+        */
+       if (cb->cb_sid2posix &&
+           nvlist_add_boolean_value(props, "smbentity", smbentity) != 0)
+               nomem();
+
+       /* Calculate/update width of TYPE field */
+       typestr = us_type2str(type);
+       typelen = strlen(gettext(typestr));
+       typeidx = us_field_index("type");
+       if (typelen > cb->cb_width[typeidx])
+               cb->cb_width[typeidx] = typelen;
+       if (nvlist_add_uint32(props, "type", type) != 0)
+               nomem();
+
+       /* Calculate/update width of NAME field */
+       if ((cb->cb_numname && cb->cb_sid2posix) || name == NULL) {
+               if (nvlist_add_uint64(props, "name", rid) != 0)
+                       nomem();
+               namelen = snprintf(NULL, 0, "%u", rid);
+       } else {
+               if (nvlist_add_string(props, "name", name) != 0)
+                       nomem();
+               namelen = strlen(name);
+       }
+       nameidx = us_field_index("name");
+       if (namelen > cb->cb_width[nameidx])
+               cb->cb_width[nameidx] = namelen;
+
+       /*
+        * Check if this type/name combination is in the list and update it;
+        * otherwise add new node to the list.
+        */
+       if ((n = uu_avl_find(avl, node, &sortinfo, &idx)) == NULL) {
+               uu_avl_insert(avl, node, idx);
+       } else {
+               nvlist_free(props);
+               free(node);
+               node = n;
+               props = node->usn_nvl;
+       }
+
+       /* Calculate/update width of USED/QUOTA fields */
+       if (cb->cb_nicenum)
+               zfs_nicenum(space, sizebuf, sizeof (sizebuf));
+       else
+               (void) snprintf(sizebuf, sizeof (sizebuf), "%llu",
+                   (u_longlong_t)space);
+       sizelen = strlen(sizebuf);
+       if (prop == ZFS_PROP_USERUSED || prop == ZFS_PROP_GROUPUSED) {
+               propname = "used";
+               if (!nvlist_exists(props, "quota"))
+                       (void) nvlist_add_uint64(props, "quota", 0);
+       } else if (prop == ZFS_PROP_USERQUOTA || prop == ZFS_PROP_GROUPQUOTA) {
+               propname = "quota";
+               if (!nvlist_exists(props, "used"))
+                       (void) nvlist_add_uint64(props, "used", 0);
+       } else if (prop == ZFS_PROP_USEROBJUSED ||
+                   prop == ZFS_PROP_GROUPOBJUSED) {
+               propname = "objused";
+               if (!nvlist_exists(props, "objquota"))
+                       (void) nvlist_add_uint64(props, "objquota", 0);
+       } else if (prop == ZFS_PROP_USEROBJQUOTA ||
+                   prop == ZFS_PROP_GROUPOBJQUOTA) {
+               propname = "objquota";
+               if (!nvlist_exists(props, "objused"))
+                       (void) nvlist_add_uint64(props, "objused", 0);
+       } else {
+               return (-1);
+       }
+       sizeidx = us_field_index(propname);
+       if (sizelen > cb->cb_width[sizeidx])
+               cb->cb_width[sizeidx] = sizelen;
+
+       if (nvlist_add_uint64(props, propname, space) != 0)
+               nomem();
+
+       return (0);
+}
+
+static void
+print_us_node(boolean_t scripted, boolean_t parsable, int *fields, int types,
+    size_t *width, us_node_t *node)
+{
+       nvlist_t *nvl = node->usn_nvl;
+       char valstr[MAXNAMELEN];
+       boolean_t first = B_TRUE;
+       int cfield = 0;
+       int field;
+       uint32_t ustype;
+
+       /* Check type */
+       (void) nvlist_lookup_uint32(nvl, "type", &ustype);
+       if (!(ustype & types))
+               return;
+
+       while ((field = fields[cfield]) != USFIELD_LAST) {
+               nvpair_t *nvp = NULL;
+               data_type_t type;
+               uint32_t val32;
+               uint64_t val64;
+               char *strval = "-";
+
+               while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+                       if (strcmp(nvpair_name(nvp),
+                           us_field_names[field]) == 0)
+                               break;
+               }
+
+               type = nvp == NULL ? DATA_TYPE_UNKNOWN : nvpair_type(nvp);
+               switch (type) {
+               case DATA_TYPE_UINT32:
+                       (void) nvpair_value_uint32(nvp, &val32);
+                       break;
+               case DATA_TYPE_UINT64:
+                       (void) nvpair_value_uint64(nvp, &val64);
+                       break;
+               case DATA_TYPE_STRING:
+                       (void) nvpair_value_string(nvp, &strval);
+                       break;
+               case DATA_TYPE_UNKNOWN:
+                       break;
+               default:
+                       (void) fprintf(stderr, "invalid data type\n");
+               }
+
+               switch (field) {
+               case USFIELD_TYPE:
+                       if (type == DATA_TYPE_UINT32)
+                               strval = (char *)us_type2str(val32);
+                       break;
+               case USFIELD_NAME:
+                       if (type == DATA_TYPE_UINT64) {
+                               (void) sprintf(valstr, "%llu",
+                                   (u_longlong_t) val64);
+                               strval = valstr;
+                       }
+                       break;
+               case USFIELD_USED:
+               case USFIELD_QUOTA:
+               case USFIELD_OBJUSED:
+               case USFIELD_OBJQUOTA:
+                       if (type == DATA_TYPE_UINT64) {
+                               if (parsable) {
+                                       (void) sprintf(valstr, "%llu",
+                                           (u_longlong_t) val64);
+                               } else {
+                                       zfs_nicenum(val64, valstr,
+                                           sizeof (valstr));
+                               }
+                               if ((field == USFIELD_QUOTA ||
+                                   field == USFIELD_OBJQUOTA) &&
+                                   strcmp(valstr, "0") == 0)
+                                       strval = "none";
+                               else
+                                       strval = valstr;
+                       }
+                       break;
+               }
+
+               if (!first) {
+                       if (scripted)
+                               (void) printf("\t");
+                       else
+                               (void) printf("  ");
+               }
+               if (scripted)
+                       (void) printf("%s", strval);
+               else if (field == USFIELD_TYPE || field == USFIELD_NAME)
+                       (void) printf("%-*s", (int) width[field], strval);
+               else
+                       (void) printf("%*s", (int) width[field], strval);
+
+               first = B_FALSE;
+               cfield++;
+       }
+
+       (void) printf("\n");
+}
+
+static void
+print_us(boolean_t scripted, boolean_t parsable, int *fields, int types,
+    size_t *width, boolean_t rmnode, uu_avl_t *avl)
+{
+       us_node_t *node;
+       const char *col;
+       int cfield = 0;
+       int field;
+
+       if (!scripted) {
+               boolean_t first = B_TRUE;
+
+               while ((field = fields[cfield]) != USFIELD_LAST) {
+                       col = gettext(us_field_hdr[field]);
+                       if (field == USFIELD_TYPE || field == USFIELD_NAME) {
+                               (void) printf(first ? "%-*s" : "  %-*s",
+                                   (int) width[field], col);
+                       } else {
+                               (void) printf(first ? "%*s" : "  %*s",
+                                   (int) width[field], col);
+                       }
+                       first = B_FALSE;
+                       cfield++;
+               }
+               (void) printf("\n");
+       }
+
+       for (node = uu_avl_first(avl); node; node = uu_avl_next(avl, node)) {
+               print_us_node(scripted, parsable, fields, types, width, node);
+               if (rmnode)
+                       nvlist_free(node->usn_nvl);
+       }
+}
+
+static int
+zfs_do_userspace(int argc, char **argv)
+{
+       zfs_handle_t *zhp;
+       zfs_userquota_prop_t p;
+       uu_avl_pool_t *avl_pool;
+       uu_avl_t *avl_tree;
+       uu_avl_walk_t *walk;
+       char *delim;
+       char deffields[] = "type,name,used,quota,objused,objquota";
+       char *ofield = NULL;
+       char *tfield = NULL;
+       int cfield = 0;
+       int fields[256];
+       int i;
+       boolean_t scripted = B_FALSE;
+       boolean_t prtnum = B_FALSE;
+       boolean_t parsable = B_FALSE;
+       boolean_t sid2posix = B_FALSE;
+       int ret = 0;
+       int c;
+       zfs_sort_column_t *sortcol = NULL;
+       int types = USTYPE_PSX_USR | USTYPE_SMB_USR;
+       us_cbdata_t cb;
+       us_node_t *node;
+       us_node_t *rmnode;
+       uu_list_pool_t *listpool;
+       uu_list_t *list;
+       uu_avl_index_t idx = 0;
+       uu_list_index_t idx2 = 0;
+
+       if (argc < 2)
+               usage(B_FALSE);
+
+       if (strcmp(argv[0], "groupspace") == 0)
+               /* Toggle default group types */
+               types = USTYPE_PSX_GRP | USTYPE_SMB_GRP;
+
+       while ((c = getopt(argc, argv, "nHpo:s:S:t:i")) != -1) {
+               switch (c) {
+               case 'n':
+                       prtnum = B_TRUE;
+                       break;
+               case 'H':
+                       scripted = B_TRUE;
+                       break;
+               case 'p':
+                       parsable = B_TRUE;
+                       break;
+               case 'o':
+                       ofield = optarg;
+                       break;
+               case 's':
+               case 'S':
+                       if (zfs_add_sort_column(&sortcol, optarg,
+                           c == 's' ? B_FALSE : B_TRUE) != 0) {
+                               (void) fprintf(stderr,
+                                   gettext("invalid field '%s'\n"), optarg);
+                               usage(B_FALSE);
+                       }
+                       break;
+               case 't':
+                       tfield = optarg;
+                       break;
+               case 'i':
+                       sid2posix = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing dataset name\n"));
+               usage(B_FALSE);
+       }
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       /* Use default output fields if not specified using -o */
+       if (ofield == NULL)
+               ofield = deffields;
+       do {
+               if ((delim = strchr(ofield, ',')) != NULL)
+                       *delim = '\0';
+               if ((fields[cfield++] = us_field_index(ofield)) == -1) {
+                       (void) fprintf(stderr, gettext("invalid type '%s' "
+                           "for -o option\n"), ofield);
+                       return (-1);
+               }
+               if (delim != NULL)
+                       ofield = delim + 1;
+       } while (delim != NULL);
+       fields[cfield] = USFIELD_LAST;
+
+       /* Override output types (-t option) */
+       if (tfield != NULL) {
+               types = 0;
+
+               do {
+                       boolean_t found = B_FALSE;
+
+                       if ((delim = strchr(tfield, ',')) != NULL)
+                               *delim = '\0';
+                       for (i = 0; i < sizeof (us_type_bits) / sizeof (int);
+                           i++) {
+                               if (strcmp(tfield, us_type_names[i]) == 0) {
+                                       found = B_TRUE;
+                                       types |= us_type_bits[i];
+                                       break;
+                               }
+                       }
+                       if (!found) {
+                               (void) fprintf(stderr, gettext("invalid type "
+                                   "'%s' for -t option\n"), tfield);
+                               return (-1);
+                       }
+                       if (delim != NULL)
+                               tfield = delim + 1;
+               } while (delim != NULL);
+       }
+
+       if ((zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET)) == NULL)
+               return (1);
+
+       if ((avl_pool = uu_avl_pool_create("us_avl_pool", sizeof (us_node_t),
+           offsetof(us_node_t, usn_avlnode), us_compare, UU_DEFAULT)) == NULL)
+               nomem();
+       if ((avl_tree = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL)
+               nomem();
+
+       /* Always add default sorting columns */
+       (void) zfs_add_sort_column(&sortcol, "type", B_FALSE);
+       (void) zfs_add_sort_column(&sortcol, "name", B_FALSE);
+
+       cb.cb_sortcol = sortcol;
+       cb.cb_numname = prtnum;
+       cb.cb_nicenum = !parsable;
+       cb.cb_avl_pool = avl_pool;
+       cb.cb_avl = avl_tree;
+       cb.cb_sid2posix = sid2posix;
+
+       for (i = 0; i < USFIELD_LAST; i++)
+               cb.cb_width[i] = strlen(gettext(us_field_hdr[i]));
+
+       for (p = 0; p < ZFS_NUM_USERQUOTA_PROPS; p++) {
+               if ((zfs_prop_is_user(p) &&
+                   !(types & (USTYPE_PSX_USR | USTYPE_SMB_USR))) ||
+                   (zfs_prop_is_group(p) &&
+                   !(types & (USTYPE_PSX_GRP | USTYPE_SMB_GRP))))
+                       continue;
+
+               cb.cb_prop = p;
+               if ((ret = zfs_userspace(zhp, p, userspace_cb, &cb)) != 0)
+                       return (ret);
+       }
+
+       /* Sort the list */
+       if ((node = uu_avl_first(avl_tree)) == NULL)
+               return (0);
+
+       us_populated = B_TRUE;
+
+       listpool = uu_list_pool_create("tmplist", sizeof (us_node_t),
+           offsetof(us_node_t, usn_listnode), NULL, UU_DEFAULT);
+       list = uu_list_create(listpool, NULL, UU_DEFAULT);
+       uu_list_node_init(node, &node->usn_listnode, listpool);
+
+       while (node != NULL) {
+               rmnode = node;
+               node = uu_avl_next(avl_tree, node);
+               uu_avl_remove(avl_tree, rmnode);
+               if (uu_list_find(list, rmnode, NULL, &idx2) == NULL)
+                       uu_list_insert(list, rmnode, idx2);
+       }
+
+       for (node = uu_list_first(list); node != NULL;
+           node = uu_list_next(list, node)) {
+               us_sort_info_t sortinfo = { sortcol, cb.cb_numname };
+
+               if (uu_avl_find(avl_tree, node, &sortinfo, &idx) == NULL)
+                       uu_avl_insert(avl_tree, node, idx);
+       }
+
+       uu_list_destroy(list);
+       uu_list_pool_destroy(listpool);
+
+       /* Print and free node nvlist memory */
+       print_us(scripted, parsable, fields, types, cb.cb_width, B_TRUE,
+           cb.cb_avl);
+
+       zfs_free_sort_columns(sortcol);
+
+       /* Clean up the AVL tree */
+       if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL)
+               nomem();
+
+       while ((node = uu_avl_walk_next(walk)) != NULL) {
+               uu_avl_remove(cb.cb_avl, node);
+               free(node);
+       }
+
+       uu_avl_walk_end(walk);
+       uu_avl_destroy(avl_tree);
+       uu_avl_pool_destroy(avl_pool);
+
+       return (ret);
+}
+
+/*
+ * list [-Hp][-r|-d max] [-o property[,...]] [-s property] ... [-S property]
+ *      [-t type[,...]] [filesystem|volume|snapshot] ...
+ *
+ *     -H      Scripted mode; elide headers and separate columns by tabs
+ *     -p      Display values in parsable (literal) format.
+ *     -r      Recurse over all children
+ *     -d      Limit recursion by depth.
+ *     -o      Control which fields to display.
+ *     -s      Specify sort columns, descending order.
+ *     -S      Specify sort columns, ascending order.
+ *     -t      Control which object types to display.
+ *
+ * When given no arguments, list all filesystems in the system.
+ * Otherwise, list the specified datasets, optionally recursing down them if
+ * '-r' is specified.
+ */
+typedef struct list_cbdata {
+       boolean_t       cb_first;
+       boolean_t       cb_literal;
+       boolean_t       cb_scripted;
+       zprop_list_t    *cb_proplist;
+} list_cbdata_t;
+
+/*
+ * Given a list of columns to display, output appropriate headers for each one.
+ */
+static void
+print_header(list_cbdata_t *cb)
+{
+       zprop_list_t *pl = cb->cb_proplist;
+       char headerbuf[ZFS_MAXPROPLEN];
+       const char *header;
+       int i;
+       boolean_t first = B_TRUE;
+       boolean_t right_justify;
+
+       for (; pl != NULL; pl = pl->pl_next) {
+               if (!first) {
+                       (void) printf("  ");
+               } else {
+                       first = B_FALSE;
+               }
+
+               right_justify = B_FALSE;
+               if (pl->pl_prop != ZPROP_INVAL) {
+                       header = zfs_prop_column_name(pl->pl_prop);
+                       right_justify = zfs_prop_align_right(pl->pl_prop);
+               } else {
+                       for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
+                               headerbuf[i] = toupper(pl->pl_user_prop[i]);
+                       headerbuf[i] = '\0';
+                       header = headerbuf;
+               }
+
+               if (pl->pl_next == NULL && !right_justify)
+                       (void) printf("%s", header);
+               else if (right_justify)
+                       (void) printf("%*s", (int)pl->pl_width, header);
+               else
+                       (void) printf("%-*s", (int)pl->pl_width, header);
+       }
+
+       (void) printf("\n");
+}
+
+/*
+ * Given a dataset and a list of fields, print out all the properties according
+ * to the described layout.
+ */
+static void
+print_dataset(zfs_handle_t *zhp, list_cbdata_t *cb)
+{
+       zprop_list_t *pl = cb->cb_proplist;
+       boolean_t first = B_TRUE;
+       char property[ZFS_MAXPROPLEN];
+       nvlist_t *userprops = zfs_get_user_props(zhp);
+       nvlist_t *propval;
+       char *propstr;
+       boolean_t right_justify;
+
+       for (; pl != NULL; pl = pl->pl_next) {
+               if (!first) {
+                       if (cb->cb_scripted)
+                               (void) printf("\t");
+                       else
+                               (void) printf("  ");
+               } else {
+                       first = B_FALSE;
+               }
+
+               if (pl->pl_prop == ZFS_PROP_NAME) {
+                       (void) strlcpy(property, zfs_get_name(zhp),
+                           sizeof (property));
+                       propstr = property;
+                       right_justify = zfs_prop_align_right(pl->pl_prop);
+               } else if (pl->pl_prop != ZPROP_INVAL) {
+                       if (zfs_prop_get(zhp, pl->pl_prop, property,
+                           sizeof (property), NULL, NULL, 0,
+                           cb->cb_literal) != 0)
+                               propstr = "-";
+                       else
+                               propstr = property;
+                       right_justify = zfs_prop_align_right(pl->pl_prop);
+               } else if (zfs_prop_userquota(pl->pl_user_prop)) {
+                       if (zfs_prop_get_userquota(zhp, pl->pl_user_prop,
+                           property, sizeof (property), cb->cb_literal) != 0)
+                               propstr = "-";
+                       else
+                               propstr = property;
+                       right_justify = B_TRUE;
+               } else if (zfs_prop_written(pl->pl_user_prop)) {
+                       if (zfs_prop_get_written(zhp, pl->pl_user_prop,
+                           property, sizeof (property), cb->cb_literal) != 0)
+                               propstr = "-";
+                       else
+                               propstr = property;
+                       right_justify = B_TRUE;
+               } else {
+                       if (nvlist_lookup_nvlist(userprops,
+                           pl->pl_user_prop, &propval) != 0)
+                               propstr = "-";
+                       else
+                               verify(nvlist_lookup_string(propval,
+                                   ZPROP_VALUE, &propstr) == 0);
+                       right_justify = B_FALSE;
+               }
+
+               /*
+                * If this is being called in scripted mode, or if this is the
+                * last column and it is left-justified, don't include a width
+                * format specifier.
+                */
+               if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
+                       (void) printf("%s", propstr);
+               else if (right_justify)
+                       (void) printf("%*s", (int)pl->pl_width, propstr);
+               else
+                       (void) printf("%-*s", (int)pl->pl_width, propstr);
+       }
+
+       (void) printf("\n");
+}
+
+/*
+ * Generic callback function to list a dataset or snapshot.
+ */
+static int
+list_callback(zfs_handle_t *zhp, void *data)
+{
+       list_cbdata_t *cbp = data;
+
+       if (cbp->cb_first) {
+               if (!cbp->cb_scripted)
+                       print_header(cbp);
+               cbp->cb_first = B_FALSE;
+       }
+
+       print_dataset(zhp, cbp);
+
+       return (0);
+}
+
+static int
+zfs_do_list(int argc, char **argv)
+{
+       int c;
+       static char default_fields[] =
+           "name,used,available,referenced,mountpoint";
+       int types = ZFS_TYPE_DATASET;
+       boolean_t types_specified = B_FALSE;
+       char *fields = NULL;
+       list_cbdata_t cb = { 0 };
+       char *value;
+       int limit = 0;
+       int ret = 0;
+       zfs_sort_column_t *sortcol = NULL;
+       int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "HS:d:o:prs:t:")) != -1) {
+               switch (c) {
+               case 'o':
+                       fields = optarg;
+                       break;
+               case 'p':
+                       cb.cb_literal = B_TRUE;
+                       flags |= ZFS_ITER_LITERAL_PROPS;
+                       break;
+               case 'd':
+                       limit = parse_depth(optarg, &flags);
+                       break;
+               case 'r':
+                       flags |= ZFS_ITER_RECURSE;
+                       break;
+               case 'H':
+                       cb.cb_scripted = B_TRUE;
+                       break;
+               case 's':
+                       if (zfs_add_sort_column(&sortcol, optarg,
+                           B_FALSE) != 0) {
+                               (void) fprintf(stderr,
+                                   gettext("invalid property '%s'\n"), optarg);
+                               usage(B_FALSE);
+                       }
+                       break;
+               case 'S':
+                       if (zfs_add_sort_column(&sortcol, optarg,
+                           B_TRUE) != 0) {
+                               (void) fprintf(stderr,
+                                   gettext("invalid property '%s'\n"), optarg);
+                               usage(B_FALSE);
+                       }
+                       break;
+               case 't':
+                       types = 0;
+                       types_specified = B_TRUE;
+                       flags &= ~ZFS_ITER_PROP_LISTSNAPS;
+                       while (*optarg != '\0') {
+                               static char *type_subopts[] = { "filesystem",
+                                   "volume", "snapshot", "snap", "bookmark",
+                                   "all", NULL };
+
+                               switch (getsubopt(&optarg, type_subopts,
+                                   &value)) {
+                               case 0:
+                                       types |= ZFS_TYPE_FILESYSTEM;
+                                       break;
+                               case 1:
+                                       types |= ZFS_TYPE_VOLUME;
+                                       break;
+                               case 2:
+                               case 3:
+                                       types |= ZFS_TYPE_SNAPSHOT;
+                                       break;
+                               case 4:
+                                       types |= ZFS_TYPE_BOOKMARK;
+                                       break;
+                               case 5:
+                                       types = ZFS_TYPE_DATASET |
+                                           ZFS_TYPE_BOOKMARK;
+                                       break;
+                               default:
+                                       (void) fprintf(stderr,
+                                           gettext("invalid type '%s'\n"),
+                                           value);
+                                       usage(B_FALSE);
+                               }
+                       }
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (fields == NULL)
+               fields = default_fields;
+
+       /*
+        * If we are only going to list snapshot names and sort by name,
+        * then we can use faster version.
+        */
+       if (strcmp(fields, "name") == 0 && zfs_sort_only_by_name(sortcol))
+               flags |= ZFS_ITER_SIMPLE;
+
+       /*
+        * If "-o space" and no types were specified, don't display snapshots.
+        */
+       if (strcmp(fields, "space") == 0 && types_specified == B_FALSE)
+               types &= ~ZFS_TYPE_SNAPSHOT;
+
+       /*
+        * If the user specifies '-o all', the zprop_get_list() doesn't
+        * normally include the name of the dataset.  For 'zfs list', we always
+        * want this property to be first.
+        */
+       if (zprop_get_list(g_zfs, fields, &cb.cb_proplist, ZFS_TYPE_DATASET)
+           != 0)
+               usage(B_FALSE);
+
+       cb.cb_first = B_TRUE;
+
+       ret = zfs_for_each(argc, argv, flags, types, sortcol, &cb.cb_proplist,
+           limit, list_callback, &cb);
+
+       zprop_free_list(cb.cb_proplist);
+       zfs_free_sort_columns(sortcol);
+
+       if (ret == 0 && cb.cb_first && !cb.cb_scripted)
+               (void) fprintf(stderr, gettext("no datasets available\n"));
+
+       return (ret);
+}
+
+/*
+ * zfs rename [-f] <fs | snap | vol> <fs | snap | vol>
+ * zfs rename [-f] -p <fs | vol> <fs | vol>
+ * zfs rename -r <snap> <snap>
+ *
+ * Renames the given dataset to another of the same type.
+ *
+ * The '-p' flag creates all the non-existing ancestors of the target first.
+ */
+/* ARGSUSED */
+static int
+zfs_do_rename(int argc, char **argv)
+{
+       zfs_handle_t *zhp;
+       int c;
+       int ret = 0;
+       boolean_t recurse = B_FALSE;
+       boolean_t parents = B_FALSE;
+       boolean_t force_unmount = B_FALSE;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "prf")) != -1) {
+               switch (c) {
+               case 'p':
+                       parents = B_TRUE;
+                       break;
+               case 'r':
+                       recurse = B_TRUE;
+                       break;
+               case 'f':
+                       force_unmount = B_TRUE;
+                       break;
+               case '?':
+               default:
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing source dataset "
+                   "argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing target dataset "
+                   "argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc > 2) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       if (recurse && parents) {
+               (void) fprintf(stderr, gettext("-p and -r options are mutually "
+                   "exclusive\n"));
+               usage(B_FALSE);
+       }
+
+       if (recurse && strchr(argv[0], '@') == 0) {
+               (void) fprintf(stderr, gettext("source dataset for recursive "
+                   "rename must be a snapshot\n"));
+               usage(B_FALSE);
+       }
+
+       if ((zhp = zfs_open(g_zfs, argv[0], parents ? ZFS_TYPE_FILESYSTEM |
+           ZFS_TYPE_VOLUME : ZFS_TYPE_DATASET)) == NULL)
+               return (1);
+
+       /* If we were asked and the name looks good, try to create ancestors. */
+       if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp)) &&
+           zfs_create_ancestors(g_zfs, argv[1]) != 0) {
+               zfs_close(zhp);
+               return (1);
+       }
+
+       ret = (zfs_rename(zhp, argv[1], recurse, force_unmount) != 0);
+
+       zfs_close(zhp);
+       return (ret);
+}
+
+/*
+ * zfs promote <fs>
+ *
+ * Promotes the given clone fs to be the parent
+ */
+/* ARGSUSED */
+static int
+zfs_do_promote(int argc, char **argv)
+{
+       zfs_handle_t *zhp;
+       int ret = 0;
+
+       /* check options */
+       if (argc > 1 && argv[1][0] == '-') {
+               (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                   argv[1][1]);
+               usage(B_FALSE);
+       }
+
+       /* check number of arguments */
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing clone filesystem"
+                   " argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc > 2) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       zhp = zfs_open(g_zfs, argv[1], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+       if (zhp == NULL)
+               return (1);
+
+       ret = (zfs_promote(zhp) != 0);
+
+
+       zfs_close(zhp);
+       return (ret);
+}
+
+/*
+ * zfs rollback [-rRf] <snapshot>
+ *
+ *     -r      Delete any intervening snapshots before doing rollback
+ *     -R      Delete any snapshots and their clones
+ *     -f      ignored for backwards compatability
+ *
+ * Given a filesystem, rollback to a specific snapshot, discarding any changes
+ * since then and making it the active dataset.  If more recent snapshots exist,
+ * the command will complain unless the '-r' flag is given.
+ */
+typedef struct rollback_cbdata {
+       uint64_t        cb_create;
+       boolean_t       cb_first;
+       int             cb_doclones;
+       char            *cb_target;
+       int             cb_error;
+       boolean_t       cb_recurse;
+} rollback_cbdata_t;
+
+static int
+rollback_check_dependent(zfs_handle_t *zhp, void *data)
+{
+       rollback_cbdata_t *cbp = data;
+
+       if (cbp->cb_first && cbp->cb_recurse) {
+               (void) fprintf(stderr, gettext("cannot rollback to "
+                   "'%s': clones of previous snapshots exist\n"),
+                   cbp->cb_target);
+               (void) fprintf(stderr, gettext("use '-R' to "
+                   "force deletion of the following clones and "
+                   "dependents:\n"));
+               cbp->cb_first = 0;
+               cbp->cb_error = 1;
+       }
+
+       (void) fprintf(stderr, "%s\n", zfs_get_name(zhp));
+
+       zfs_close(zhp);
+       return (0);
+}
+
+
+/*
+ * Report any snapshots more recent than the one specified.  Used when '-r' is
+ * not specified.  We reuse this same callback for the snapshot dependents - if
+ * 'cb_dependent' is set, then this is a dependent and we should report it
+ * without checking the transaction group.
+ */
+static int
+rollback_check(zfs_handle_t *zhp, void *data)
+{
+       rollback_cbdata_t *cbp = data;
+
+       if (cbp->cb_doclones) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
+               if (cbp->cb_first && !cbp->cb_recurse) {
+                       (void) fprintf(stderr, gettext("cannot "
+                           "rollback to '%s': more recent snapshots "
+                           "or bookmarks exist\n"),
+                           cbp->cb_target);
+                       (void) fprintf(stderr, gettext("use '-r' to "
+                           "force deletion of the following "
+                           "snapshots and bookmarks:\n"));
+                       cbp->cb_first = 0;
+                       cbp->cb_error = 1;
+               }
+
+               if (cbp->cb_recurse) {
+                       if (zfs_iter_dependents(zhp, B_TRUE,
+                           rollback_check_dependent, cbp) != 0) {
+                               zfs_close(zhp);
+                               return (-1);
+                       }
+               } else {
+                       (void) fprintf(stderr, "%s\n",
+                           zfs_get_name(zhp));
+               }
+       }
+       zfs_close(zhp);
+       return (0);
+}
+
+static int
+zfs_do_rollback(int argc, char **argv)
+{
+       int ret = 0;
+       int c;
+       boolean_t force = B_FALSE;
+       rollback_cbdata_t cb = { 0 };
+       zfs_handle_t *zhp, *snap;
+       char parentname[ZFS_MAX_DATASET_NAME_LEN];
+       char *delim;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "rRf")) != -1) {
+               switch (c) {
+               case 'r':
+                       cb.cb_recurse = 1;
+                       break;
+               case 'R':
+                       cb.cb_recurse = 1;
+                       cb.cb_doclones = 1;
+                       break;
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing dataset argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       /* open the snapshot */
+       if ((snap = zfs_open(g_zfs, argv[0], ZFS_TYPE_SNAPSHOT)) == NULL)
+               return (1);
+
+       /* open the parent dataset */
+       (void) strlcpy(parentname, argv[0], sizeof (parentname));
+       verify((delim = strrchr(parentname, '@')) != NULL);
+       *delim = '\0';
+       if ((zhp = zfs_open(g_zfs, parentname, ZFS_TYPE_DATASET)) == NULL) {
+               zfs_close(snap);
+               return (1);
+       }
+
+       /*
+        * Check for more recent snapshots and/or clones based on the presence
+        * of '-r' and '-R'.
+        */
+       cb.cb_target = argv[0];
+       cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
+       cb.cb_first = B_TRUE;
+       cb.cb_error = 0;
+       if ((ret = zfs_iter_snapshots(zhp, B_FALSE, rollback_check, &cb)) != 0)
+               goto out;
+       if ((ret = zfs_iter_bookmarks(zhp, rollback_check, &cb)) != 0)
+               goto out;
+
+       if ((ret = cb.cb_error) != 0)
+               goto out;
+
+       /*
+        * Rollback parent to the given snapshot.
+        */
+       ret = zfs_rollback(zhp, snap, force);
+
+out:
+       zfs_close(snap);
+       zfs_close(zhp);
+
+       if (ret == 0)
+               return (0);
+       else
+               return (1);
+}
+
+/*
+ * zfs set property=value ... { fs | snap | vol } ...
+ *
+ * Sets the given properties for all datasets specified on the command line.
+ */
+
+static int
+set_callback(zfs_handle_t *zhp, void *data)
+{
+       nvlist_t *props = data;
+
+       if (zfs_prop_set_list(zhp, props) != 0) {
+               switch (libzfs_errno(g_zfs)) {
+               case EZFS_MOUNTFAILED:
+                       (void) fprintf(stderr, gettext("property may be set "
+                           "but unable to remount filesystem\n"));
+                       break;
+               case EZFS_SHARENFSFAILED:
+                       (void) fprintf(stderr, gettext("property may be set "
+                           "but unable to reshare filesystem\n"));
+                       break;
+               }
+               return (1);
+       }
+       return (0);
+}
+
+static int
+zfs_do_set(int argc, char **argv)
+{
+       nvlist_t *props = NULL;
+       int ds_start = -1; /* argv idx of first dataset arg */
+       int ret = 0;
+       int i;
+
+       /* check for options */
+       if (argc > 1 && argv[1][0] == '-') {
+               (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                   argv[1][1]);
+               usage(B_FALSE);
+       }
+
+       /* check number of arguments */
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing arguments\n"));
+               usage(B_FALSE);
+       }
+       if (argc < 3) {
+               if (strchr(argv[1], '=') == NULL) {
+                       (void) fprintf(stderr, gettext("missing property=value "
+                           "argument(s)\n"));
+               } else {
+                       (void) fprintf(stderr, gettext("missing dataset "
+                           "name(s)\n"));
+               }
+               usage(B_FALSE);
+       }
+
+       /* validate argument order:  prop=val args followed by dataset args */
+       for (i = 1; i < argc; i++) {
+               if (strchr(argv[i], '=') != NULL) {
+                       if (ds_start > 0) {
+                               /* out-of-order prop=val argument */
+                               (void) fprintf(stderr, gettext("invalid "
+                                   "argument order\n"));
+                               usage(B_FALSE);
+                       }
+               } else if (ds_start < 0) {
+                       ds_start = i;
+               }
+       }
+       if (ds_start < 0) {
+               (void) fprintf(stderr, gettext("missing dataset name(s)\n"));
+               usage(B_FALSE);
+       }
+
+       /* Populate a list of property settings */
+       if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+       for (i = 1; i < ds_start; i++) {
+               if ((ret = parseprop(props, argv[i])) != 0)
+                       goto error;
+       }
+
+       ret = zfs_for_each(argc - ds_start, argv + ds_start, 0,
+           ZFS_TYPE_DATASET, NULL, NULL, 0, set_callback, props);
+
+error:
+       nvlist_free(props);
+       return (ret);
+}
+
+typedef struct snap_cbdata {
+       nvlist_t *sd_nvl;
+       boolean_t sd_recursive;
+       const char *sd_snapname;
+} snap_cbdata_t;
+
+static int
+zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
+{
+       snap_cbdata_t *sd = arg;
+       char *name;
+       int rv = 0;
+       int error;
+
+       if (sd->sd_recursive &&
+           zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) != 0) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       error = asprintf(&name, "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
+       if (error == -1)
+               nomem();
+       fnvlist_add_boolean(sd->sd_nvl, name);
+       free(name);
+
+       if (sd->sd_recursive)
+               rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
+       zfs_close(zhp);
+       return (rv);
+}
+
+/*
+ * zfs snapshot [-r] [-o prop=value] ... <fs@snap>
+ *
+ * Creates a snapshot with the given name.  While functionally equivalent to
+ * 'zfs create', it is a separate command to differentiate intent.
+ */
+static int
+zfs_do_snapshot(int argc, char **argv)
+{
+       int ret = 0;
+       signed char c;
+       nvlist_t *props;
+       snap_cbdata_t sd = { 0 };
+       boolean_t multiple_snaps = B_FALSE;
+
+       if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+       if (nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+
+       /* check options */
+       while ((c = getopt(argc, argv, "ro:")) != -1) {
+               switch (c) {
+               case 'o':
+                       if (parseprop(props, optarg) != 0) {
+                               nvlist_free(sd.sd_nvl);
+                               nvlist_free(props);
+                               return (1);
+                       }
+                       break;
+               case 'r':
+                       sd.sd_recursive = B_TRUE;
+                       multiple_snaps = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       goto usage;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing snapshot argument\n"));
+               goto usage;
+       }
+
+       if (argc > 1)
+               multiple_snaps = B_TRUE;
+       for (; argc > 0; argc--, argv++) {
+               char *atp;
+               zfs_handle_t *zhp;
+
+               atp = strchr(argv[0], '@');
+               if (atp == NULL)
+                       goto usage;
+               *atp = '\0';
+               sd.sd_snapname = atp + 1;
+               zhp = zfs_open(g_zfs, argv[0],
+                   ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+               if (zhp == NULL)
+                       goto usage;
+               if (zfs_snapshot_cb(zhp, &sd) != 0)
+                       goto usage;
+       }
+
+       ret = zfs_snapshot_nvl(g_zfs, sd.sd_nvl, props);
+       nvlist_free(sd.sd_nvl);
+       nvlist_free(props);
+       if (ret != 0 && multiple_snaps)
+               (void) fprintf(stderr, gettext("no snapshots were created\n"));
+       return (ret != 0);
+
+usage:
+       nvlist_free(sd.sd_nvl);
+       nvlist_free(props);
+       usage(B_FALSE);
+       return (-1);
+}
+
+/*
+ * Send a backup stream to stdout.
+ */
+static int
+zfs_do_send(int argc, char **argv)
+{
+       char *fromname = NULL;
+       char *toname = NULL;
+       char *resume_token = NULL;
+       char *cp;
+       zfs_handle_t *zhp;
+       sendflags_t flags = { 0 };
+       int c, err;
+       nvlist_t *dbgnv = NULL;
+       boolean_t extraverbose = B_FALSE;
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":i:I:RDpvnPLet:c")) != -1) {
+               switch (c) {
+               case 'i':
+                       if (fromname)
+                               usage(B_FALSE);
+                       fromname = optarg;
+                       break;
+               case 'I':
+                       if (fromname)
+                               usage(B_FALSE);
+                       fromname = optarg;
+                       flags.doall = B_TRUE;
+                       break;
+               case 'R':
+                       flags.replicate = B_TRUE;
+                       break;
+               case 'p':
+                       flags.props = B_TRUE;
+                       break;
+               case 'P':
+                       flags.parsable = B_TRUE;
+                       flags.verbose = B_TRUE;
+                       break;
+               case 'v':
+                       if (flags.verbose)
+                               extraverbose = B_TRUE;
+                       flags.verbose = B_TRUE;
+                       flags.progress = B_TRUE;
+                       break;
+               case 'D':
+                       flags.dedup = B_TRUE;
+                       break;
+               case 'n':
+                       flags.dryrun = B_TRUE;
+                       break;
+               case 'L':
+                       flags.largeblock = B_TRUE;
+                       break;
+               case 'e':
+                       flags.embed_data = B_TRUE;
+                       break;
+               case 't':
+                       resume_token = optarg;
+                       break;
+               case 'c':
+                       flags.compress = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (resume_token != NULL) {
+               if (fromname != NULL || flags.replicate || flags.props ||
+                   flags.dedup) {
+                       (void) fprintf(stderr,
+                           gettext("invalid flags combined with -t\n"));
+                       usage(B_FALSE);
+               }
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("no additional "
+                           "arguments are permitted with -t\n"));
+                       usage(B_FALSE);
+               }
+       } else {
+               if (argc < 1) {
+                       (void) fprintf(stderr,
+                           gettext("missing snapshot argument\n"));
+                       usage(B_FALSE);
+               }
+               if (argc > 1) {
+                       (void) fprintf(stderr, gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+       }
+
+       if (!flags.dryrun && isatty(STDOUT_FILENO)) {
+               (void) fprintf(stderr,
+                   gettext("Error: Stream can not be written to a terminal.\n"
+                   "You must redirect standard output.\n"));
+               return (1);
+       }
+
+       if (resume_token != NULL) {
+               return (zfs_send_resume(g_zfs, &flags, STDOUT_FILENO,
+                   resume_token));
+       }
+
+       /*
+        * Special case sending a filesystem, or from a bookmark.
+        */
+       if (strchr(argv[0], '@') == NULL ||
+           (fromname && strchr(fromname, '#') != NULL)) {
+               char frombuf[ZFS_MAX_DATASET_NAME_LEN];
+               enum lzc_send_flags lzc_flags = 0;
+
+               if (flags.replicate || flags.doall || flags.props ||
+                   flags.dedup || flags.dryrun || flags.verbose ||
+                   flags.progress) {
+                       (void) fprintf(stderr,
+                           gettext("Error: "
+                           "Unsupported flag with filesystem or bookmark.\n"));
+                       return (1);
+               }
+
+               zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_DATASET);
+               if (zhp == NULL)
+                       return (1);
+
+               if (flags.largeblock)
+                       lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;
+               if (flags.embed_data)
+                       lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
+               if (flags.compress)
+                       lzc_flags |= LZC_SEND_FLAG_COMPRESS;
+
+               if (fromname != NULL &&
+                   (fromname[0] == '#' || fromname[0] == '@')) {
+                       /*
+                        * Incremental source name begins with # or @.
+                        * Default to same fs as target.
+                        */
+                       (void) strlcpy(frombuf, argv[0], sizeof (frombuf));
+                       cp = strchr(frombuf, '@');
+                       if (cp != NULL)
+                               *cp = '\0';
+                       (void) strlcat(frombuf, fromname, sizeof (frombuf));
+                       fromname = frombuf;
+               }
+               err = zfs_send_one(zhp, fromname, STDOUT_FILENO, lzc_flags);
+               zfs_close(zhp);
+               return (err != 0);
+       }
+
+       cp = strchr(argv[0], '@');
+       *cp = '\0';
+       toname = cp + 1;
+       zhp = zfs_open(g_zfs, argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+       if (zhp == NULL)
+               return (1);
+
+       /*
+        * If they specified the full path to the snapshot, chop off
+        * everything except the short name of the snapshot, but special
+        * case if they specify the origin.
+        */
+       if (fromname && (cp = strchr(fromname, '@')) != NULL) {
+               char origin[ZFS_MAX_DATASET_NAME_LEN];
+               zprop_source_t src;
+
+               (void) zfs_prop_get(zhp, ZFS_PROP_ORIGIN,
+                   origin, sizeof (origin), &src, NULL, 0, B_FALSE);
+
+               if (strcmp(origin, fromname) == 0) {
+                       fromname = NULL;
+                       flags.fromorigin = B_TRUE;
+               } else {
+                       *cp = '\0';
+                       if (cp != fromname && strcmp(argv[0], fromname)) {
+                               (void) fprintf(stderr,
+                                   gettext("incremental source must be "
+                                   "in same filesystem\n"));
+                               usage(B_FALSE);
+                       }
+                       fromname = cp + 1;
+                       if (strchr(fromname, '@') || strchr(fromname, '/')) {
+                               (void) fprintf(stderr,
+                                   gettext("invalid incremental source\n"));
+                               usage(B_FALSE);
+                       }
+               }
+       }
+
+       if (flags.replicate && fromname == NULL)
+               flags.doall = B_TRUE;
+
+       err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO, NULL, 0,
+           extraverbose ? &dbgnv : NULL);
+
+       if (extraverbose && dbgnv != NULL) {
+               /*
+                * dump_nvlist prints to stdout, but that's been
+                * redirected to a file.  Make it print to stderr
+                * instead.
+                */
+               (void) dup2(STDERR_FILENO, STDOUT_FILENO);
+               dump_nvlist(dbgnv, 0);
+               nvlist_free(dbgnv);
+       }
+       zfs_close(zhp);
+
+       return (err != 0);
+}
+
+/*
+ * Restore a backup stream from stdin.
+ */
+static int
+zfs_do_receive(int argc, char **argv)
+{
+       int c, err;
+       recvflags_t flags = { 0 };
+       boolean_t abort_resumable = B_FALSE;
+
+       nvlist_t *props;
+       nvpair_t *nvp = NULL;
+
+       if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":o:denuvFsA")) != -1) {
+               switch (c) {
+               case 'o':
+                       if (parseprop(props, optarg) != 0) {
+                               nvlist_free(props);
+                               return (1);
+                       }
+                       break;
+               case 'd':
+                       flags.isprefix = B_TRUE;
+                       break;
+               case 'e':
+                       flags.isprefix = B_TRUE;
+                       flags.istail = B_TRUE;
+                       break;
+               case 'n':
+                       flags.dryrun = B_TRUE;
+                       break;
+               case 'u':
+                       flags.nomount = B_TRUE;
+                       break;
+               case 'v':
+                       flags.verbose = B_TRUE;
+                       break;
+               case 's':
+                       flags.resumable = B_TRUE;
+                       break;
+               case 'F':
+                       flags.force = B_TRUE;
+                       break;
+               case 'A':
+                       abort_resumable = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing snapshot argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       while ((nvp = nvlist_next_nvpair(props, nvp))) {
+               if (strcmp(nvpair_name(nvp), "origin") != 0) {
+                       (void) fprintf(stderr, gettext("invalid option"));
+                       usage(B_FALSE);
+               }
+       }
+
+       if (abort_resumable) {
+               if (flags.isprefix || flags.istail || flags.dryrun ||
+                   flags.resumable || flags.nomount) {
+                       (void) fprintf(stderr, gettext("invalid option"));
+                       usage(B_FALSE);
+               }
+
+               char namebuf[ZFS_MAX_DATASET_NAME_LEN];
+               (void) snprintf(namebuf, sizeof (namebuf),
+                   "%s/%%recv", argv[0]);
+
+               if (zfs_dataset_exists(g_zfs, namebuf,
+                   ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) {
+                       zfs_handle_t *zhp = zfs_open(g_zfs,
+                           namebuf, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+                       if (zhp == NULL) {
+                               nvlist_free(props);
+                               return (1);
+                       }
+                       err = zfs_destroy(zhp, B_FALSE);
+                       zfs_close(zhp);
+               } else {
+                       zfs_handle_t *zhp = zfs_open(g_zfs,
+                           argv[0], ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+                       if (zhp == NULL)
+                               usage(B_FALSE);
+                       if (!zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) ||
+                           zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+                           NULL, 0, NULL, NULL, 0, B_TRUE) == -1) {
+                               (void) fprintf(stderr,
+                                   gettext("'%s' does not have any "
+                                   "resumable receive state to abort\n"),
+                                   argv[0]);
+                               nvlist_free(props);
+                               zfs_close(zhp);
+                               return (1);
+                       }
+                       err = zfs_destroy(zhp, B_FALSE);
+                       zfs_close(zhp);
+               }
+               nvlist_free(props);
+               return (err != 0);
+       }
+
+       if (isatty(STDIN_FILENO)) {
+               (void) fprintf(stderr,
+                   gettext("Error: Backup stream can not be read "
+                   "from a terminal.\n"
+                   "You must redirect standard input.\n"));
+               nvlist_free(props);
+               return (1);
+       }
+       err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);
+       nvlist_free(props);
+
+       return (err != 0);
+}
+
+/*
+ * allow/unallow stuff
+ */
+/* copied from zfs/sys/dsl_deleg.h */
+#define        ZFS_DELEG_PERM_CREATE           "create"
+#define        ZFS_DELEG_PERM_DESTROY          "destroy"
+#define        ZFS_DELEG_PERM_SNAPSHOT         "snapshot"
+#define        ZFS_DELEG_PERM_ROLLBACK         "rollback"
+#define        ZFS_DELEG_PERM_CLONE            "clone"
+#define        ZFS_DELEG_PERM_PROMOTE          "promote"
+#define        ZFS_DELEG_PERM_RENAME           "rename"
+#define        ZFS_DELEG_PERM_MOUNT            "mount"
+#define        ZFS_DELEG_PERM_SHARE            "share"
+#define        ZFS_DELEG_PERM_SEND             "send"
+#define        ZFS_DELEG_PERM_RECEIVE          "receive"
+#define        ZFS_DELEG_PERM_ALLOW            "allow"
+#define        ZFS_DELEG_PERM_USERPROP         "userprop"
+#define        ZFS_DELEG_PERM_VSCAN            "vscan" /* ??? */
+#define        ZFS_DELEG_PERM_USERQUOTA        "userquota"
+#define        ZFS_DELEG_PERM_GROUPQUOTA       "groupquota"
+#define        ZFS_DELEG_PERM_USERUSED         "userused"
+#define        ZFS_DELEG_PERM_GROUPUSED        "groupused"
+#define        ZFS_DELEG_PERM_USEROBJQUOTA     "userobjquota"
+#define        ZFS_DELEG_PERM_GROUPOBJQUOTA    "groupobjquota"
+#define        ZFS_DELEG_PERM_USEROBJUSED      "userobjused"
+#define        ZFS_DELEG_PERM_GROUPOBJUSED     "groupobjused"
+
+#define        ZFS_DELEG_PERM_HOLD             "hold"
+#define        ZFS_DELEG_PERM_RELEASE          "release"
+#define        ZFS_DELEG_PERM_DIFF             "diff"
+#define        ZFS_DELEG_PERM_BOOKMARK         "bookmark"
+
+#define        ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE
+
+static zfs_deleg_perm_tab_t zfs_deleg_perm_tbl[] = {
+       { ZFS_DELEG_PERM_ALLOW, ZFS_DELEG_NOTE_ALLOW },
+       { ZFS_DELEG_PERM_CLONE, ZFS_DELEG_NOTE_CLONE },
+       { ZFS_DELEG_PERM_CREATE, ZFS_DELEG_NOTE_CREATE },
+       { ZFS_DELEG_PERM_DESTROY, ZFS_DELEG_NOTE_DESTROY },
+       { ZFS_DELEG_PERM_DIFF, ZFS_DELEG_NOTE_DIFF},
+       { ZFS_DELEG_PERM_HOLD, ZFS_DELEG_NOTE_HOLD },
+       { ZFS_DELEG_PERM_MOUNT, ZFS_DELEG_NOTE_MOUNT },
+       { ZFS_DELEG_PERM_PROMOTE, ZFS_DELEG_NOTE_PROMOTE },
+       { ZFS_DELEG_PERM_RECEIVE, ZFS_DELEG_NOTE_RECEIVE },
+       { ZFS_DELEG_PERM_RELEASE, ZFS_DELEG_NOTE_RELEASE },
+       { ZFS_DELEG_PERM_RENAME, ZFS_DELEG_NOTE_RENAME },
+       { ZFS_DELEG_PERM_ROLLBACK, ZFS_DELEG_NOTE_ROLLBACK },
+       { ZFS_DELEG_PERM_SEND, ZFS_DELEG_NOTE_SEND },
+       { ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
+       { ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
+       { ZFS_DELEG_PERM_BOOKMARK, ZFS_DELEG_NOTE_BOOKMARK },
+
+       { ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA },
+       { ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED },
+       { ZFS_DELEG_PERM_USERPROP, ZFS_DELEG_NOTE_USERPROP },
+       { ZFS_DELEG_PERM_USERQUOTA, ZFS_DELEG_NOTE_USERQUOTA },
+       { ZFS_DELEG_PERM_USERUSED, ZFS_DELEG_NOTE_USERUSED },
+       { ZFS_DELEG_PERM_USEROBJQUOTA, ZFS_DELEG_NOTE_USEROBJQUOTA },
+       { ZFS_DELEG_PERM_USEROBJUSED, ZFS_DELEG_NOTE_USEROBJUSED },
+       { ZFS_DELEG_PERM_GROUPOBJQUOTA, ZFS_DELEG_NOTE_GROUPOBJQUOTA },
+       { ZFS_DELEG_PERM_GROUPOBJUSED, ZFS_DELEG_NOTE_GROUPOBJUSED },
+       { NULL, ZFS_DELEG_NOTE_NONE }
+};
+
+/* permission structure */
+typedef struct deleg_perm {
+       zfs_deleg_who_type_t    dp_who_type;
+       const char              *dp_name;
+       boolean_t               dp_local;
+       boolean_t               dp_descend;
+} deleg_perm_t;
+
+/* */
+typedef struct deleg_perm_node {
+       deleg_perm_t            dpn_perm;
+
+       uu_avl_node_t           dpn_avl_node;
+} deleg_perm_node_t;
+
+typedef struct fs_perm fs_perm_t;
+
+/* permissions set */
+typedef struct who_perm {
+       zfs_deleg_who_type_t    who_type;
+       const char              *who_name;              /* id */
+       char                    who_ug_name[256];       /* user/group name */
+       fs_perm_t               *who_fsperm;            /* uplink */
+
+       uu_avl_t                *who_deleg_perm_avl;    /* permissions */
+} who_perm_t;
+
+/* */
+typedef struct who_perm_node {
+       who_perm_t      who_perm;
+       uu_avl_node_t   who_avl_node;
+} who_perm_node_t;
+
+typedef struct fs_perm_set fs_perm_set_t;
+/* fs permissions */
+struct fs_perm {
+       const char              *fsp_name;
+
+       uu_avl_t                *fsp_sc_avl;    /* sets,create */
+       uu_avl_t                *fsp_uge_avl;   /* user,group,everyone */
+
+       fs_perm_set_t           *fsp_set;       /* uplink */
+};
+
+/* */
+typedef struct fs_perm_node {
+       fs_perm_t       fspn_fsperm;
+       uu_avl_t        *fspn_avl;
+
+       uu_list_node_t  fspn_list_node;
+} fs_perm_node_t;
+
+/* top level structure */
+struct fs_perm_set {
+       uu_list_pool_t  *fsps_list_pool;
+       uu_list_t       *fsps_list; /* list of fs_perms */
+
+       uu_avl_pool_t   *fsps_named_set_avl_pool;
+       uu_avl_pool_t   *fsps_who_perm_avl_pool;
+       uu_avl_pool_t   *fsps_deleg_perm_avl_pool;
+};
+
+static inline const char *
+deleg_perm_type(zfs_deleg_note_t note)
+{
+       /* subcommands */
+       switch (note) {
+               /* SUBCOMMANDS */
+               /* OTHER */
+       case ZFS_DELEG_NOTE_GROUPQUOTA:
+       case ZFS_DELEG_NOTE_GROUPUSED:
+       case ZFS_DELEG_NOTE_USERPROP:
+       case ZFS_DELEG_NOTE_USERQUOTA:
+       case ZFS_DELEG_NOTE_USERUSED:
+       case ZFS_DELEG_NOTE_USEROBJQUOTA:
+       case ZFS_DELEG_NOTE_USEROBJUSED:
+       case ZFS_DELEG_NOTE_GROUPOBJQUOTA:
+       case ZFS_DELEG_NOTE_GROUPOBJUSED:
+               /* other */
+               return (gettext("other"));
+       default:
+               return (gettext("subcommand"));
+       }
+}
+
+static int inline
+who_type2weight(zfs_deleg_who_type_t who_type)
+{
+       int res;
+       switch (who_type) {
+               case ZFS_DELEG_NAMED_SET_SETS:
+               case ZFS_DELEG_NAMED_SET:
+                       res = 0;
+                       break;
+               case ZFS_DELEG_CREATE_SETS:
+               case ZFS_DELEG_CREATE:
+                       res = 1;
+                       break;
+               case ZFS_DELEG_USER_SETS:
+               case ZFS_DELEG_USER:
+                       res = 2;
+                       break;
+               case ZFS_DELEG_GROUP_SETS:
+               case ZFS_DELEG_GROUP:
+                       res = 3;
+                       break;
+               case ZFS_DELEG_EVERYONE_SETS:
+               case ZFS_DELEG_EVERYONE:
+                       res = 4;
+                       break;
+               default:
+                       res = -1;
+       }
+
+       return (res);
+}
+
+/* ARGSUSED */
+static int
+who_perm_compare(const void *larg, const void *rarg, void *unused)
+{
+       const who_perm_node_t *l = larg;
+       const who_perm_node_t *r = rarg;
+       zfs_deleg_who_type_t ltype = l->who_perm.who_type;
+       zfs_deleg_who_type_t rtype = r->who_perm.who_type;
+       int lweight = who_type2weight(ltype);
+       int rweight = who_type2weight(rtype);
+       int res = lweight - rweight;
+       if (res == 0)
+               res = strncmp(l->who_perm.who_name, r->who_perm.who_name,
+                   ZFS_MAX_DELEG_NAME-1);
+
+       if (res == 0)
+               return (0);
+       if (res > 0)
+               return (1);
+       else
+               return (-1);
+}
+
+/* ARGSUSED */
+static int
+deleg_perm_compare(const void *larg, const void *rarg, void *unused)
+{
+       const deleg_perm_node_t *l = larg;
+       const deleg_perm_node_t *r = rarg;
+       int res =  strncmp(l->dpn_perm.dp_name, r->dpn_perm.dp_name,
+           ZFS_MAX_DELEG_NAME-1);
+
+       if (res == 0)
+               return (0);
+
+       if (res > 0)
+               return (1);
+       else
+               return (-1);
+}
+
+static inline void
+fs_perm_set_init(fs_perm_set_t *fspset)
+{
+       bzero(fspset, sizeof (fs_perm_set_t));
+
+       if ((fspset->fsps_list_pool = uu_list_pool_create("fsps_list_pool",
+           sizeof (fs_perm_node_t), offsetof(fs_perm_node_t, fspn_list_node),
+           NULL, UU_DEFAULT)) == NULL)
+               nomem();
+       if ((fspset->fsps_list = uu_list_create(fspset->fsps_list_pool, NULL,
+           UU_DEFAULT)) == NULL)
+               nomem();
+
+       if ((fspset->fsps_named_set_avl_pool = uu_avl_pool_create(
+           "named_set_avl_pool", sizeof (who_perm_node_t), offsetof(
+           who_perm_node_t, who_avl_node), who_perm_compare,
+           UU_DEFAULT)) == NULL)
+               nomem();
+
+       if ((fspset->fsps_who_perm_avl_pool = uu_avl_pool_create(
+           "who_perm_avl_pool", sizeof (who_perm_node_t), offsetof(
+           who_perm_node_t, who_avl_node), who_perm_compare,
+           UU_DEFAULT)) == NULL)
+               nomem();
+
+       if ((fspset->fsps_deleg_perm_avl_pool = uu_avl_pool_create(
+           "deleg_perm_avl_pool", sizeof (deleg_perm_node_t), offsetof(
+           deleg_perm_node_t, dpn_avl_node), deleg_perm_compare, UU_DEFAULT))
+           == NULL)
+               nomem();
+}
+
+static inline void fs_perm_fini(fs_perm_t *);
+static inline void who_perm_fini(who_perm_t *);
+
+static inline void
+fs_perm_set_fini(fs_perm_set_t *fspset)
+{
+       fs_perm_node_t *node = uu_list_first(fspset->fsps_list);
+
+       while (node != NULL) {
+               fs_perm_node_t *next_node =
+                   uu_list_next(fspset->fsps_list, node);
+               fs_perm_t *fsperm = &node->fspn_fsperm;
+               fs_perm_fini(fsperm);
+               uu_list_remove(fspset->fsps_list, node);
+               free(node);
+               node = next_node;
+       }
+
+       uu_avl_pool_destroy(fspset->fsps_named_set_avl_pool);
+       uu_avl_pool_destroy(fspset->fsps_who_perm_avl_pool);
+       uu_avl_pool_destroy(fspset->fsps_deleg_perm_avl_pool);
+}
+
+static inline void
+deleg_perm_init(deleg_perm_t *deleg_perm, zfs_deleg_who_type_t type,
+    const char *name)
+{
+       deleg_perm->dp_who_type = type;
+       deleg_perm->dp_name = name;
+}
+
+static inline void
+who_perm_init(who_perm_t *who_perm, fs_perm_t *fsperm,
+    zfs_deleg_who_type_t type, const char *name)
+{
+       uu_avl_pool_t   *pool;
+       pool = fsperm->fsp_set->fsps_deleg_perm_avl_pool;
+
+       bzero(who_perm, sizeof (who_perm_t));
+
+       if ((who_perm->who_deleg_perm_avl = uu_avl_create(pool, NULL,
+           UU_DEFAULT)) == NULL)
+               nomem();
+
+       who_perm->who_type = type;
+       who_perm->who_name = name;
+       who_perm->who_fsperm = fsperm;
+}
+
+static inline void
+who_perm_fini(who_perm_t *who_perm)
+{
+       deleg_perm_node_t *node = uu_avl_first(who_perm->who_deleg_perm_avl);
+
+       while (node != NULL) {
+               deleg_perm_node_t *next_node =
+                   uu_avl_next(who_perm->who_deleg_perm_avl, node);
+
+               uu_avl_remove(who_perm->who_deleg_perm_avl, node);
+               free(node);
+               node = next_node;
+       }
+
+       uu_avl_destroy(who_perm->who_deleg_perm_avl);
+}
+
+static inline void
+fs_perm_init(fs_perm_t *fsperm, fs_perm_set_t *fspset, const char *fsname)
+{
+       uu_avl_pool_t   *nset_pool = fspset->fsps_named_set_avl_pool;
+       uu_avl_pool_t   *who_pool = fspset->fsps_who_perm_avl_pool;
+
+       bzero(fsperm, sizeof (fs_perm_t));
+
+       if ((fsperm->fsp_sc_avl = uu_avl_create(nset_pool, NULL, UU_DEFAULT))
+           == NULL)
+               nomem();
+
+       if ((fsperm->fsp_uge_avl = uu_avl_create(who_pool, NULL, UU_DEFAULT))
+           == NULL)
+               nomem();
+
+       fsperm->fsp_set = fspset;
+       fsperm->fsp_name = fsname;
+}
+
+static inline void
+fs_perm_fini(fs_perm_t *fsperm)
+{
+       who_perm_node_t *node = uu_avl_first(fsperm->fsp_sc_avl);
+       while (node != NULL) {
+               who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_sc_avl,
+                   node);
+               who_perm_t *who_perm = &node->who_perm;
+               who_perm_fini(who_perm);
+               uu_avl_remove(fsperm->fsp_sc_avl, node);
+               free(node);
+               node = next_node;
+       }
+
+       node = uu_avl_first(fsperm->fsp_uge_avl);
+       while (node != NULL) {
+               who_perm_node_t *next_node = uu_avl_next(fsperm->fsp_uge_avl,
+                   node);
+               who_perm_t *who_perm = &node->who_perm;
+               who_perm_fini(who_perm);
+               uu_avl_remove(fsperm->fsp_uge_avl, node);
+               free(node);
+               node = next_node;
+       }
+
+       uu_avl_destroy(fsperm->fsp_sc_avl);
+       uu_avl_destroy(fsperm->fsp_uge_avl);
+}
+
+static void inline
+set_deleg_perm_node(uu_avl_t *avl, deleg_perm_node_t *node,
+    zfs_deleg_who_type_t who_type, const char *name, char locality)
+{
+       uu_avl_index_t idx = 0;
+
+       deleg_perm_node_t *found_node = NULL;
+       deleg_perm_t    *deleg_perm = &node->dpn_perm;
+
+       deleg_perm_init(deleg_perm, who_type, name);
+
+       if ((found_node = uu_avl_find(avl, node, NULL, &idx))
+           == NULL)
+               uu_avl_insert(avl, node, idx);
+       else {
+               node = found_node;
+               deleg_perm = &node->dpn_perm;
+       }
+
+
+       switch (locality) {
+       case ZFS_DELEG_LOCAL:
+               deleg_perm->dp_local = B_TRUE;
+               break;
+       case ZFS_DELEG_DESCENDENT:
+               deleg_perm->dp_descend = B_TRUE;
+               break;
+       case ZFS_DELEG_NA:
+               break;
+       default:
+               assert(B_FALSE); /* invalid locality */
+       }
+}
+
+static inline int
+parse_who_perm(who_perm_t *who_perm, nvlist_t *nvl, char locality)
+{
+       nvpair_t *nvp = NULL;
+       fs_perm_set_t *fspset = who_perm->who_fsperm->fsp_set;
+       uu_avl_t *avl = who_perm->who_deleg_perm_avl;
+       zfs_deleg_who_type_t who_type = who_perm->who_type;
+
+       while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+               const char *name = nvpair_name(nvp);
+               data_type_t type = nvpair_type(nvp);
+               uu_avl_pool_t *avl_pool = fspset->fsps_deleg_perm_avl_pool;
+               deleg_perm_node_t *node =
+                   safe_malloc(sizeof (deleg_perm_node_t));
+
+               VERIFY(type == DATA_TYPE_BOOLEAN);
+
+               uu_avl_node_init(node, &node->dpn_avl_node, avl_pool);
+               set_deleg_perm_node(avl, node, who_type, name, locality);
+       }
+
+       return (0);
+}
+
+static inline int
+parse_fs_perm(fs_perm_t *fsperm, nvlist_t *nvl)
+{
+       nvpair_t *nvp = NULL;
+       fs_perm_set_t *fspset = fsperm->fsp_set;
+
+       while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+               nvlist_t *nvl2 = NULL;
+               const char *name = nvpair_name(nvp);
+               uu_avl_t *avl = NULL;
+               uu_avl_pool_t *avl_pool = NULL;
+               zfs_deleg_who_type_t perm_type = name[0];
+               char perm_locality = name[1];
+               const char *perm_name = name + 3;
+               boolean_t is_set = B_TRUE;
+               who_perm_t *who_perm = NULL;
+
+               assert('$' == name[2]);
+
+               if (nvpair_value_nvlist(nvp, &nvl2) != 0)
+                       return (-1);
+
+               switch (perm_type) {
+               case ZFS_DELEG_CREATE:
+               case ZFS_DELEG_CREATE_SETS:
+               case ZFS_DELEG_NAMED_SET:
+               case ZFS_DELEG_NAMED_SET_SETS:
+                       avl_pool = fspset->fsps_named_set_avl_pool;
+                       avl = fsperm->fsp_sc_avl;
+                       break;
+               case ZFS_DELEG_USER:
+               case ZFS_DELEG_USER_SETS:
+               case ZFS_DELEG_GROUP:
+               case ZFS_DELEG_GROUP_SETS:
+               case ZFS_DELEG_EVERYONE:
+               case ZFS_DELEG_EVERYONE_SETS:
+                       avl_pool = fspset->fsps_who_perm_avl_pool;
+                       avl = fsperm->fsp_uge_avl;
+                       break;
+               default:
+                       break;
+               }
+
+               if (is_set) {
+                       who_perm_node_t *found_node = NULL;
+                       who_perm_node_t *node = safe_malloc(
+                           sizeof (who_perm_node_t));
+                       who_perm = &node->who_perm;
+                       uu_avl_index_t idx = 0;
+
+                       uu_avl_node_init(node, &node->who_avl_node, avl_pool);
+                       who_perm_init(who_perm, fsperm, perm_type, perm_name);
+
+                       if ((found_node = uu_avl_find(avl, node, NULL, &idx))
+                           == NULL) {
+                               if (avl == fsperm->fsp_uge_avl) {
+                                       uid_t rid = 0;
+                                       struct passwd *p = NULL;
+                                       struct group *g = NULL;
+                                       const char *nice_name = NULL;
+
+                                       switch (perm_type) {
+                                       case ZFS_DELEG_USER_SETS:
+                                       case ZFS_DELEG_USER:
+                                               rid = atoi(perm_name);
+                                               p = getpwuid(rid);
+                                               if (p)
+                                                       nice_name = p->pw_name;
+                                               break;
+                                       case ZFS_DELEG_GROUP_SETS:
+                                       case ZFS_DELEG_GROUP:
+                                               rid = atoi(perm_name);
+                                               g = getgrgid(rid);
+                                               if (g)
+                                                       nice_name = g->gr_name;
+                                               break;
+                                       default:
+                                               break;
+                                       }
+
+                                       if (nice_name != NULL)
+                                               (void) strlcpy(
+                                                   node->who_perm.who_ug_name,
+                                                   nice_name, 256);
+                               }
+
+                               uu_avl_insert(avl, node, idx);
+                       } else {
+                               node = found_node;
+                               who_perm = &node->who_perm;
+                       }
+               }
+               VERIFY3P(who_perm, !=, NULL);
+               (void) parse_who_perm(who_perm, nvl2, perm_locality);
+       }
+
+       return (0);
+}
+
+static inline int
+parse_fs_perm_set(fs_perm_set_t *fspset, nvlist_t *nvl)
+{
+       nvpair_t *nvp = NULL;
+       uu_avl_index_t idx = 0;
+
+       while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+               nvlist_t *nvl2 = NULL;
+               const char *fsname = nvpair_name(nvp);
+               data_type_t type = nvpair_type(nvp);
+               fs_perm_t *fsperm = NULL;
+               fs_perm_node_t *node = safe_malloc(sizeof (fs_perm_node_t));
+               if (node == NULL)
+                       nomem();
+
+               fsperm = &node->fspn_fsperm;
+
+               VERIFY(DATA_TYPE_NVLIST == type);
+
+               uu_list_node_init(node, &node->fspn_list_node,
+                   fspset->fsps_list_pool);
+
+               idx = uu_list_numnodes(fspset->fsps_list);
+               fs_perm_init(fsperm, fspset, fsname);
+
+               if (nvpair_value_nvlist(nvp, &nvl2) != 0)
+                       return (-1);
+
+               (void) parse_fs_perm(fsperm, nvl2);
+
+               uu_list_insert(fspset->fsps_list, node, idx);
+       }
+
+       return (0);
+}
+
+static inline const char *
+deleg_perm_comment(zfs_deleg_note_t note)
+{
+       const char *str = "";
+
+       /* subcommands */
+       switch (note) {
+               /* SUBCOMMANDS */
+       case ZFS_DELEG_NOTE_ALLOW:
+               str = gettext("Must also have the permission that is being"
+                   "\n\t\t\t\tallowed");
+               break;
+       case ZFS_DELEG_NOTE_CLONE:
+               str = gettext("Must also have the 'create' ability and 'mount'"
+                   "\n\t\t\t\tability in the origin file system");
+               break;
+       case ZFS_DELEG_NOTE_CREATE:
+               str = gettext("Must also have the 'mount' ability");
+               break;
+       case ZFS_DELEG_NOTE_DESTROY:
+               str = gettext("Must also have the 'mount' ability");
+               break;
+       case ZFS_DELEG_NOTE_DIFF:
+               str = gettext("Allows lookup of paths within a dataset;"
+                   "\n\t\t\t\tgiven an object number. Ordinary users need this"
+                   "\n\t\t\t\tin order to use zfs diff");
+               break;
+       case ZFS_DELEG_NOTE_HOLD:
+               str = gettext("Allows adding a user hold to a snapshot");
+               break;
+       case ZFS_DELEG_NOTE_MOUNT:
+               str = gettext("Allows mount/umount of ZFS datasets");
+               break;
+       case ZFS_DELEG_NOTE_PROMOTE:
+               str = gettext("Must also have the 'mount'\n\t\t\t\tand"
+                   " 'promote' ability in the origin file system");
+               break;
+       case ZFS_DELEG_NOTE_RECEIVE:
+               str = gettext("Must also have the 'mount' and 'create'"
+                   " ability");
+               break;
+       case ZFS_DELEG_NOTE_RELEASE:
+               str = gettext("Allows releasing a user hold which\n\t\t\t\t"
+                   "might destroy the snapshot");
+               break;
+       case ZFS_DELEG_NOTE_RENAME:
+               str = gettext("Must also have the 'mount' and 'create'"
+                   "\n\t\t\t\tability in the new parent");
+               break;
+       case ZFS_DELEG_NOTE_ROLLBACK:
+               str = gettext("");
+               break;
+       case ZFS_DELEG_NOTE_SEND:
+               str = gettext("");
+               break;
+       case ZFS_DELEG_NOTE_SHARE:
+               str = gettext("Allows sharing file systems over NFS or SMB"
+                   "\n\t\t\t\tprotocols");
+               break;
+       case ZFS_DELEG_NOTE_SNAPSHOT:
+               str = gettext("");
+               break;
+/*
+ *     case ZFS_DELEG_NOTE_VSCAN:
+ *             str = gettext("");
+ *             break;
+ */
+               /* OTHER */
+       case ZFS_DELEG_NOTE_GROUPQUOTA:
+               str = gettext("Allows accessing any groupquota@... property");
+               break;
+       case ZFS_DELEG_NOTE_GROUPUSED:
+               str = gettext("Allows reading any groupused@... property");
+               break;
+       case ZFS_DELEG_NOTE_USERPROP:
+               str = gettext("Allows changing any user property");
+               break;
+       case ZFS_DELEG_NOTE_USERQUOTA:
+               str = gettext("Allows accessing any userquota@... property");
+               break;
+       case ZFS_DELEG_NOTE_USERUSED:
+               str = gettext("Allows reading any userused@... property");
+               break;
+       case ZFS_DELEG_NOTE_USEROBJQUOTA:
+               str = gettext("Allows accessing any userobjquota@... property");
+               break;
+       case ZFS_DELEG_NOTE_GROUPOBJQUOTA:
+               str = gettext("Allows accessing any \n\t\t\t\t"
+                   "groupobjquota@... property");
+               break;
+       case ZFS_DELEG_NOTE_GROUPOBJUSED:
+               str = gettext("Allows reading any groupobjused@... property");
+               break;
+       case ZFS_DELEG_NOTE_USEROBJUSED:
+               str = gettext("Allows reading any userobjused@... property");
+               break;
+               /* other */
+       default:
+               str = "";
+       }
+
+       return (str);
+}
+
+struct allow_opts {
+       boolean_t local;
+       boolean_t descend;
+       boolean_t user;
+       boolean_t group;
+       boolean_t everyone;
+       boolean_t create;
+       boolean_t set;
+       boolean_t recursive; /* unallow only */
+       boolean_t prt_usage;
+
+       boolean_t prt_perms;
+       char *who;
+       char *perms;
+       const char *dataset;
+};
+
+static inline int
+prop_cmp(const void *a, const void *b)
+{
+       const char *str1 = *(const char **)a;
+       const char *str2 = *(const char **)b;
+       return (strcmp(str1, str2));
+}
+
+static void
+allow_usage(boolean_t un, boolean_t requested, const char *msg)
+{
+       const char *opt_desc[] = {
+               "-h", gettext("show this help message and exit"),
+               "-l", gettext("set permission locally"),
+               "-d", gettext("set permission for descents"),
+               "-u", gettext("set permission for user"),
+               "-g", gettext("set permission for group"),
+               "-e", gettext("set permission for everyone"),
+               "-c", gettext("set create time permission"),
+               "-s", gettext("define permission set"),
+               /* unallow only */
+               "-r", gettext("remove permissions recursively"),
+       };
+       size_t unallow_size = sizeof (opt_desc) / sizeof (char *);
+       size_t allow_size = unallow_size - 2;
+       const char *props[ZFS_NUM_PROPS];
+       int i;
+       size_t count = 0;
+       FILE *fp = requested ? stdout : stderr;
+       zprop_desc_t *pdtbl = zfs_prop_get_table();
+       const char *fmt = gettext("%-16s %-14s\t%s\n");
+
+       (void) fprintf(fp, gettext("Usage: %s\n"), get_usage(un ? HELP_UNALLOW :
+           HELP_ALLOW));
+       (void) fprintf(fp, gettext("Options:\n"));
+       for (i = 0; i < (un ? unallow_size : allow_size); i++) {
+               const char *opt = opt_desc[i++];
+               const char *optdsc = opt_desc[i];
+               (void) fprintf(fp, gettext("  %-10s  %s\n"), opt, optdsc);
+       }
+
+       (void) fprintf(fp, gettext("\nThe following permissions are "
+           "supported:\n\n"));
+       (void) fprintf(fp, fmt, gettext("NAME"), gettext("TYPE"),
+           gettext("NOTES"));
+       for (i = 0; i < ZFS_NUM_DELEG_NOTES; i++) {
+               const char *perm_name = zfs_deleg_perm_tbl[i].z_perm;
+               zfs_deleg_note_t perm_note = zfs_deleg_perm_tbl[i].z_note;
+               const char *perm_type = deleg_perm_type(perm_note);
+               const char *perm_comment = deleg_perm_comment(perm_note);
+               (void) fprintf(fp, fmt, perm_name, perm_type, perm_comment);
+       }
+
+       for (i = 0; i < ZFS_NUM_PROPS; i++) {
+               zprop_desc_t *pd = &pdtbl[i];
+               if (pd->pd_visible != B_TRUE)
+                       continue;
+
+               if (pd->pd_attr == PROP_READONLY)
+                       continue;
+
+               props[count++] = pd->pd_name;
+       }
+       props[count] = NULL;
+
+       qsort(props, count, sizeof (char *), prop_cmp);
+
+       for (i = 0; i < count; i++)
+               (void) fprintf(fp, fmt, props[i], gettext("property"), "");
+
+       if (msg != NULL)
+               (void) fprintf(fp, gettext("\nzfs: error: %s"), msg);
+
+       exit(requested ? 0 : 2);
+}
+
+static inline const char *
+munge_args(int argc, char **argv, boolean_t un, size_t expected_argc,
+    char **permsp)
+{
+       if (un && argc == expected_argc - 1)
+               *permsp = NULL;
+       else if (argc == expected_argc)
+               *permsp = argv[argc - 2];
+       else
+               allow_usage(un, B_FALSE,
+                   gettext("wrong number of parameters\n"));
+
+       return (argv[argc - 1]);
+}
+
+static void
+parse_allow_args(int argc, char **argv, boolean_t un, struct allow_opts *opts)
+{
+       int uge_sum = opts->user + opts->group + opts->everyone;
+       int csuge_sum = opts->create + opts->set + uge_sum;
+       int ldcsuge_sum = csuge_sum + opts->local + opts->descend;
+       int all_sum = un ? ldcsuge_sum + opts->recursive : ldcsuge_sum;
+
+       if (uge_sum > 1)
+               allow_usage(un, B_FALSE,
+                   gettext("-u, -g, and -e are mutually exclusive\n"));
+
+       if (opts->prt_usage) {
+               if (argc == 0 && all_sum == 0)
+                       allow_usage(un, B_TRUE, NULL);
+               else
+                       usage(B_FALSE);
+       }
+
+       if (opts->set) {
+               if (csuge_sum > 1)
+                       allow_usage(un, B_FALSE,
+                           gettext("invalid options combined with -s\n"));
+
+               opts->dataset = munge_args(argc, argv, un, 3, &opts->perms);
+               if (argv[0][0] != '@')
+                       allow_usage(un, B_FALSE,
+                           gettext("invalid set name: missing '@' prefix\n"));
+               opts->who = argv[0];
+       } else if (opts->create) {
+               if (ldcsuge_sum > 1)
+                       allow_usage(un, B_FALSE,
+                           gettext("invalid options combined with -c\n"));
+               opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
+       } else if (opts->everyone) {
+               if (csuge_sum > 1)
+                       allow_usage(un, B_FALSE,
+                           gettext("invalid options combined with -e\n"));
+               opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
+       } else if (uge_sum == 0 && argc > 0 && strcmp(argv[0], "everyone")
+           == 0) {
+               opts->everyone = B_TRUE;
+               argc--;
+               argv++;
+               opts->dataset = munge_args(argc, argv, un, 2, &opts->perms);
+       } else if (argc == 1 && !un) {
+               opts->prt_perms = B_TRUE;
+               opts->dataset = argv[argc-1];
+       } else {
+               opts->dataset = munge_args(argc, argv, un, 3, &opts->perms);
+               opts->who = argv[0];
+       }
+
+       if (!opts->local && !opts->descend) {
+               opts->local = B_TRUE;
+               opts->descend = B_TRUE;
+       }
+}
+
+static void
+store_allow_perm(zfs_deleg_who_type_t type, boolean_t local, boolean_t descend,
+    const char *who, char *perms, nvlist_t *top_nvl)
+{
+       int i;
+       char ld[2] = { '\0', '\0' };
+       char who_buf[MAXNAMELEN + 32];
+       char base_type = ZFS_DELEG_WHO_UNKNOWN;
+       char set_type = ZFS_DELEG_WHO_UNKNOWN;
+       nvlist_t *base_nvl = NULL;
+       nvlist_t *set_nvl = NULL;
+       nvlist_t *nvl;
+
+       if (nvlist_alloc(&base_nvl, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+       if (nvlist_alloc(&set_nvl, NV_UNIQUE_NAME, 0) !=  0)
+               nomem();
+
+       switch (type) {
+       case ZFS_DELEG_NAMED_SET_SETS:
+       case ZFS_DELEG_NAMED_SET:
+               set_type = ZFS_DELEG_NAMED_SET_SETS;
+               base_type = ZFS_DELEG_NAMED_SET;
+               ld[0] = ZFS_DELEG_NA;
+               break;
+       case ZFS_DELEG_CREATE_SETS:
+       case ZFS_DELEG_CREATE:
+               set_type = ZFS_DELEG_CREATE_SETS;
+               base_type = ZFS_DELEG_CREATE;
+               ld[0] = ZFS_DELEG_NA;
+               break;
+       case ZFS_DELEG_USER_SETS:
+       case ZFS_DELEG_USER:
+               set_type = ZFS_DELEG_USER_SETS;
+               base_type = ZFS_DELEG_USER;
+               if (local)
+                       ld[0] = ZFS_DELEG_LOCAL;
+               if (descend)
+                       ld[1] = ZFS_DELEG_DESCENDENT;
+               break;
+       case ZFS_DELEG_GROUP_SETS:
+       case ZFS_DELEG_GROUP:
+               set_type = ZFS_DELEG_GROUP_SETS;
+               base_type = ZFS_DELEG_GROUP;
+               if (local)
+                       ld[0] = ZFS_DELEG_LOCAL;
+               if (descend)
+                       ld[1] = ZFS_DELEG_DESCENDENT;
+               break;
+       case ZFS_DELEG_EVERYONE_SETS:
+       case ZFS_DELEG_EVERYONE:
+               set_type = ZFS_DELEG_EVERYONE_SETS;
+               base_type = ZFS_DELEG_EVERYONE;
+               if (local)
+                       ld[0] = ZFS_DELEG_LOCAL;
+               if (descend)
+                       ld[1] = ZFS_DELEG_DESCENDENT;
+       default:
+               break;
+       }
+
+       if (perms != NULL) {
+               char *curr = perms;
+               char *end = curr + strlen(perms);
+
+               while (curr < end) {
+                       char *delim = strchr(curr, ',');
+                       if (delim == NULL)
+                               delim = end;
+                       else
+                               *delim = '\0';
+
+                       if (curr[0] == '@')
+                               nvl = set_nvl;
+                       else
+                               nvl = base_nvl;
+
+                       (void) nvlist_add_boolean(nvl, curr);
+                       if (delim != end)
+                               *delim = ',';
+                       curr = delim + 1;
+               }
+
+               for (i = 0; i < 2; i++) {
+                       char locality = ld[i];
+                       if (locality == 0)
+                               continue;
+
+                       if (!nvlist_empty(base_nvl)) {
+                               if (who != NULL)
+                                       (void) snprintf(who_buf,
+                                           sizeof (who_buf), "%c%c$%s",
+                                           base_type, locality, who);
+                               else
+                                       (void) snprintf(who_buf,
+                                           sizeof (who_buf), "%c%c$",
+                                           base_type, locality);
+
+                               (void) nvlist_add_nvlist(top_nvl, who_buf,
+                                   base_nvl);
+                       }
+
+
+                       if (!nvlist_empty(set_nvl)) {
+                               if (who != NULL)
+                                       (void) snprintf(who_buf,
+                                           sizeof (who_buf), "%c%c$%s",
+                                           set_type, locality, who);
+                               else
+                                       (void) snprintf(who_buf,
+                                           sizeof (who_buf), "%c%c$",
+                                           set_type, locality);
+
+                               (void) nvlist_add_nvlist(top_nvl, who_buf,
+                                   set_nvl);
+                       }
+               }
+       } else {
+               for (i = 0; i < 2; i++) {
+                       char locality = ld[i];
+                       if (locality == 0)
+                               continue;
+
+                       if (who != NULL)
+                               (void) snprintf(who_buf, sizeof (who_buf),
+                                   "%c%c$%s", base_type, locality, who);
+                       else
+                               (void) snprintf(who_buf, sizeof (who_buf),
+                                   "%c%c$", base_type, locality);
+                       (void) nvlist_add_boolean(top_nvl, who_buf);
+
+                       if (who != NULL)
+                               (void) snprintf(who_buf, sizeof (who_buf),
+                                   "%c%c$%s", set_type, locality, who);
+                       else
+                               (void) snprintf(who_buf, sizeof (who_buf),
+                                   "%c%c$", set_type, locality);
+                       (void) nvlist_add_boolean(top_nvl, who_buf);
+               }
+       }
+}
+
+static int
+construct_fsacl_list(boolean_t un, struct allow_opts *opts, nvlist_t **nvlp)
+{
+       if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+
+       if (opts->set) {
+               store_allow_perm(ZFS_DELEG_NAMED_SET, opts->local,
+                   opts->descend, opts->who, opts->perms, *nvlp);
+       } else if (opts->create) {
+               store_allow_perm(ZFS_DELEG_CREATE, opts->local,
+                   opts->descend, NULL, opts->perms, *nvlp);
+       } else if (opts->everyone) {
+               store_allow_perm(ZFS_DELEG_EVERYONE, opts->local,
+                   opts->descend, NULL, opts->perms, *nvlp);
+       } else {
+               char *curr = opts->who;
+               char *end = curr + strlen(curr);
+
+               while (curr < end) {
+                       const char *who;
+                       zfs_deleg_who_type_t who_type = ZFS_DELEG_WHO_UNKNOWN;
+                       char *endch;
+                       char *delim = strchr(curr, ',');
+                       char errbuf[256];
+                       char id[64];
+                       struct passwd *p = NULL;
+                       struct group *g = NULL;
+
+                       uid_t rid;
+                       if (delim == NULL)
+                               delim = end;
+                       else
+                               *delim = '\0';
+
+                       rid = (uid_t)strtol(curr, &endch, 0);
+                       if (opts->user) {
+                               who_type = ZFS_DELEG_USER;
+                               if (*endch != '\0')
+                                       p = getpwnam(curr);
+                               else
+                                       p = getpwuid(rid);
+
+                               if (p != NULL)
+                                       rid = p->pw_uid;
+                               else {
+                                       (void) snprintf(errbuf, 256, gettext(
+                                           "invalid user %s"), curr);
+                                       allow_usage(un, B_TRUE, errbuf);
+                               }
+                       } else if (opts->group) {
+                               who_type = ZFS_DELEG_GROUP;
+                               if (*endch != '\0')
+                                       g = getgrnam(curr);
+                               else
+                                       g = getgrgid(rid);
+
+                               if (g != NULL)
+                                       rid = g->gr_gid;
+                               else {
+                                       (void) snprintf(errbuf, 256, gettext(
+                                           "invalid group %s"),  curr);
+                                       allow_usage(un, B_TRUE, errbuf);
+                               }
+                       } else {
+                               if (*endch != '\0') {
+                                       p = getpwnam(curr);
+                               } else {
+                                       p = getpwuid(rid);
+                               }
+
+                               if (p == NULL) {
+                                       if (*endch != '\0') {
+                                               g = getgrnam(curr);
+                                       } else {
+                                               g = getgrgid(rid);
+                                       }
+                               }
+
+                               if (p != NULL) {
+                                       who_type = ZFS_DELEG_USER;
+                                       rid = p->pw_uid;
+                               } else if (g != NULL) {
+                                       who_type = ZFS_DELEG_GROUP;
+                                       rid = g->gr_gid;
+                               } else {
+                                       (void) snprintf(errbuf, 256, gettext(
+                                           "invalid user/group %s"), curr);
+                                       allow_usage(un, B_TRUE, errbuf);
+                               }
+                       }
+
+                       (void) sprintf(id, "%u", rid);
+                       who = id;
+
+                       store_allow_perm(who_type, opts->local,
+                           opts->descend, who, opts->perms, *nvlp);
+                       curr = delim + 1;
+               }
+       }
+
+       return (0);
+}
+
+static void
+print_set_creat_perms(uu_avl_t *who_avl)
+{
+       const char *sc_title[] = {
+               gettext("Permission sets:\n"),
+               gettext("Create time permissions:\n"),
+               NULL
+       };
+       const char **title_ptr = sc_title;
+       who_perm_node_t *who_node = NULL;
+       int prev_weight = -1;
+
+       for (who_node = uu_avl_first(who_avl); who_node != NULL;
+           who_node = uu_avl_next(who_avl, who_node)) {
+               uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl;
+               zfs_deleg_who_type_t who_type = who_node->who_perm.who_type;
+               const char *who_name = who_node->who_perm.who_name;
+               int weight = who_type2weight(who_type);
+               boolean_t first = B_TRUE;
+               deleg_perm_node_t *deleg_node;
+
+               if (prev_weight != weight) {
+                       (void) printf("%s", *title_ptr++);
+                       prev_weight = weight;
+               }
+
+               if (who_name == NULL || strnlen(who_name, 1) == 0)
+                       (void) printf("\t");
+               else
+                       (void) printf("\t%s ", who_name);
+
+               for (deleg_node = uu_avl_first(avl); deleg_node != NULL;
+                   deleg_node = uu_avl_next(avl, deleg_node)) {
+                       if (first) {
+                               (void) printf("%s",
+                                   deleg_node->dpn_perm.dp_name);
+                               first = B_FALSE;
+                       } else
+                               (void) printf(",%s",
+                                   deleg_node->dpn_perm.dp_name);
+               }
+
+               (void) printf("\n");
+       }
+}
+
+static void inline
+print_uge_deleg_perms(uu_avl_t *who_avl, boolean_t local, boolean_t descend,
+    const char *title)
+{
+       who_perm_node_t *who_node = NULL;
+       boolean_t prt_title = B_TRUE;
+       uu_avl_walk_t *walk;
+
+       if ((walk = uu_avl_walk_start(who_avl, UU_WALK_ROBUST)) == NULL)
+               nomem();
+
+       while ((who_node = uu_avl_walk_next(walk)) != NULL) {
+               const char *who_name = who_node->who_perm.who_name;
+               const char *nice_who_name = who_node->who_perm.who_ug_name;
+               uu_avl_t *avl = who_node->who_perm.who_deleg_perm_avl;
+               zfs_deleg_who_type_t who_type = who_node->who_perm.who_type;
+               char delim = ' ';
+               deleg_perm_node_t *deleg_node;
+               boolean_t prt_who = B_TRUE;
+
+               for (deleg_node = uu_avl_first(avl);
+                   deleg_node != NULL;
+                   deleg_node = uu_avl_next(avl, deleg_node)) {
+                       if (local != deleg_node->dpn_perm.dp_local ||
+                           descend != deleg_node->dpn_perm.dp_descend)
+                               continue;
+
+                       if (prt_who) {
+                               const char *who = NULL;
+                               if (prt_title) {
+                                       prt_title = B_FALSE;
+                                       (void) printf("%s", title);
+                               }
+
+                               switch (who_type) {
+                               case ZFS_DELEG_USER_SETS:
+                               case ZFS_DELEG_USER:
+                                       who = gettext("user");
+                                       if (nice_who_name)
+                                               who_name  = nice_who_name;
+                                       break;
+                               case ZFS_DELEG_GROUP_SETS:
+                               case ZFS_DELEG_GROUP:
+                                       who = gettext("group");
+                                       if (nice_who_name)
+                                               who_name  = nice_who_name;
+                                       break;
+                               case ZFS_DELEG_EVERYONE_SETS:
+                               case ZFS_DELEG_EVERYONE:
+                                       who = gettext("everyone");
+                                       who_name = NULL;
+                               default:
+                                       break;
+                               }
+
+                               prt_who = B_FALSE;
+                               if (who_name == NULL)
+                                       (void) printf("\t%s", who);
+                               else
+                                       (void) printf("\t%s %s", who, who_name);
+                       }
+
+                       (void) printf("%c%s", delim,
+                           deleg_node->dpn_perm.dp_name);
+                       delim = ',';
+               }
+
+               if (!prt_who)
+                       (void) printf("\n");
+       }
+
+       uu_avl_walk_end(walk);
+}
+
+static void
+print_fs_perms(fs_perm_set_t *fspset)
+{
+       fs_perm_node_t *node = NULL;
+       char buf[MAXNAMELEN + 32];
+       const char *dsname = buf;
+
+       for (node = uu_list_first(fspset->fsps_list); node != NULL;
+           node = uu_list_next(fspset->fsps_list, node)) {
+               uu_avl_t *sc_avl = node->fspn_fsperm.fsp_sc_avl;
+               uu_avl_t *uge_avl = node->fspn_fsperm.fsp_uge_avl;
+               int left = 0;
+
+               (void) snprintf(buf, sizeof (buf),
+                   gettext("---- Permissions on %s "),
+                   node->fspn_fsperm.fsp_name);
+               (void) printf("%s", dsname);
+               left = 70 - strlen(buf);
+               while (left-- > 0)
+                       (void) printf("-");
+               (void) printf("\n");
+
+               print_set_creat_perms(sc_avl);
+               print_uge_deleg_perms(uge_avl, B_TRUE, B_FALSE,
+                   gettext("Local permissions:\n"));
+               print_uge_deleg_perms(uge_avl, B_FALSE, B_TRUE,
+                   gettext("Descendent permissions:\n"));
+               print_uge_deleg_perms(uge_avl, B_TRUE, B_TRUE,
+                   gettext("Local+Descendent permissions:\n"));
+       }
+}
+
+static fs_perm_set_t fs_perm_set = { NULL, NULL, NULL, NULL };
+
+struct deleg_perms {
+       boolean_t un;
+       nvlist_t *nvl;
+};
+
+static int
+set_deleg_perms(zfs_handle_t *zhp, void *data)
+{
+       struct deleg_perms *perms = (struct deleg_perms *)data;
+       zfs_type_t zfs_type = zfs_get_type(zhp);
+
+       if (zfs_type != ZFS_TYPE_FILESYSTEM && zfs_type != ZFS_TYPE_VOLUME)
+               return (0);
+
+       return (zfs_set_fsacl(zhp, perms->un, perms->nvl));
+}
+
+static int
+zfs_do_allow_unallow_impl(int argc, char **argv, boolean_t un)
+{
+       zfs_handle_t *zhp;
+       nvlist_t *perm_nvl = NULL;
+       nvlist_t *update_perm_nvl = NULL;
+       int error = 1;
+       int c;
+       struct allow_opts opts = { 0 };
+
+       const char *optstr = un ? "ldugecsrh" : "ldugecsh";
+
+       /* check opts */
+       while ((c = getopt(argc, argv, optstr)) != -1) {
+               switch (c) {
+               case 'l':
+                       opts.local = B_TRUE;
+                       break;
+               case 'd':
+                       opts.descend = B_TRUE;
+                       break;
+               case 'u':
+                       opts.user = B_TRUE;
+                       break;
+               case 'g':
+                       opts.group = B_TRUE;
+                       break;
+               case 'e':
+                       opts.everyone = B_TRUE;
+                       break;
+               case 's':
+                       opts.set = B_TRUE;
+                       break;
+               case 'c':
+                       opts.create = B_TRUE;
+                       break;
+               case 'r':
+                       opts.recursive = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case 'h':
+                       opts.prt_usage = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check arguments */
+       parse_allow_args(argc, argv, un, &opts);
+
+       /* try to open the dataset */
+       if ((zhp = zfs_open(g_zfs, opts.dataset, ZFS_TYPE_FILESYSTEM |
+           ZFS_TYPE_VOLUME)) == NULL) {
+               (void) fprintf(stderr, "Failed to open dataset: %s\n",
+                   opts.dataset);
+               return (-1);
+       }
+
+       if (zfs_get_fsacl(zhp, &perm_nvl) != 0)
+               goto cleanup2;
+
+       fs_perm_set_init(&fs_perm_set);
+       if (parse_fs_perm_set(&fs_perm_set, perm_nvl) != 0) {
+               (void) fprintf(stderr, "Failed to parse fsacl permissions\n");
+               goto cleanup1;
+       }
+
+       if (opts.prt_perms)
+               print_fs_perms(&fs_perm_set);
+       else {
+               (void) construct_fsacl_list(un, &opts, &update_perm_nvl);
+               if (zfs_set_fsacl(zhp, un, update_perm_nvl) != 0)
+                       goto cleanup0;
+
+               if (un && opts.recursive) {
+                       struct deleg_perms data = { un, update_perm_nvl };
+                       if (zfs_iter_filesystems(zhp, set_deleg_perms,
+                           &data) != 0)
+                               goto cleanup0;
+               }
+       }
+
+       error = 0;
+
+cleanup0:
+       nvlist_free(perm_nvl);
+       nvlist_free(update_perm_nvl);
+cleanup1:
+       fs_perm_set_fini(&fs_perm_set);
+cleanup2:
+       zfs_close(zhp);
+
+       return (error);
+}
+
+static int
+zfs_do_allow(int argc, char **argv)
+{
+       return (zfs_do_allow_unallow_impl(argc, argv, B_FALSE));
+}
+
+static int
+zfs_do_unallow(int argc, char **argv)
+{
+       return (zfs_do_allow_unallow_impl(argc, argv, B_TRUE));
+}
+
+static int
+zfs_do_hold_rele_impl(int argc, char **argv, boolean_t holding)
+{
+       int errors = 0;
+       int i;
+       const char *tag;
+       boolean_t recursive = B_FALSE;
+       const char *opts = holding ? "rt" : "r";
+       int c;
+
+       /* check options */
+       while ((c = getopt(argc, argv, opts)) != -1) {
+               switch (c) {
+               case 'r':
+                       recursive = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 2)
+               usage(B_FALSE);
+
+       tag = argv[0];
+       --argc;
+       ++argv;
+
+       if (holding && tag[0] == '.') {
+               /* tags starting with '.' are reserved for libzfs */
+               (void) fprintf(stderr, gettext("tag may not start with '.'\n"));
+               usage(B_FALSE);
+       }
+
+       for (i = 0; i < argc; ++i) {
+               zfs_handle_t *zhp;
+               char parent[ZFS_MAX_DATASET_NAME_LEN];
+               const char *delim;
+               char *path = argv[i];
+
+               delim = strchr(path, '@');
+               if (delim == NULL) {
+                       (void) fprintf(stderr,
+                           gettext("'%s' is not a snapshot\n"), path);
+                       ++errors;
+                       continue;
+               }
+               (void) strncpy(parent, path, delim - path);
+               parent[delim - path] = '\0';
+
+               zhp = zfs_open(g_zfs, parent,
+                   ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+               if (zhp == NULL) {
+                       ++errors;
+                       continue;
+               }
+               if (holding) {
+                       if (zfs_hold(zhp, delim+1, tag, recursive, -1) != 0)
+                               ++errors;
+               } else {
+                       if (zfs_release(zhp, delim+1, tag, recursive) != 0)
+                               ++errors;
+               }
+               zfs_close(zhp);
+       }
+
+       return (errors != 0);
+}
+
+/*
+ * zfs hold [-r] [-t] <tag> <snap> ...
+ *
+ *     -r      Recursively hold
+ *
+ * Apply a user-hold with the given tag to the list of snapshots.
+ */
+static int
+zfs_do_hold(int argc, char **argv)
+{
+       return (zfs_do_hold_rele_impl(argc, argv, B_TRUE));
+}
+
+/*
+ * zfs release [-r] <tag> <snap> ...
+ *
+ *     -r      Recursively release
+ *
+ * Release a user-hold with the given tag from the list of snapshots.
+ */
+static int
+zfs_do_release(int argc, char **argv)
+{
+       return (zfs_do_hold_rele_impl(argc, argv, B_FALSE));
+}
+
+typedef struct holds_cbdata {
+       boolean_t       cb_recursive;
+       const char      *cb_snapname;
+       nvlist_t        **cb_nvlp;
+       size_t          cb_max_namelen;
+       size_t          cb_max_taglen;
+} holds_cbdata_t;
+
+#define        STRFTIME_FMT_STR "%a %b %e %k:%M %Y"
+#define        DATETIME_BUF_LEN (32)
+/*
+ *
+ */
+static void
+print_holds(boolean_t scripted, int nwidth, int tagwidth, nvlist_t *nvl)
+{
+       int i;
+       nvpair_t *nvp = NULL;
+       char *hdr_cols[] = { "NAME", "TAG", "TIMESTAMP" };
+       const char *col;
+
+       if (!scripted) {
+               for (i = 0; i < 3; i++) {
+                       col = gettext(hdr_cols[i]);
+                       if (i < 2)
+                               (void) printf("%-*s  ", i ? tagwidth : nwidth,
+                                   col);
+                       else
+                               (void) printf("%s\n", col);
+               }
+       }
+
+       while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+               char *zname = nvpair_name(nvp);
+               nvlist_t *nvl2;
+               nvpair_t *nvp2 = NULL;
+               (void) nvpair_value_nvlist(nvp, &nvl2);
+               while ((nvp2 = nvlist_next_nvpair(nvl2, nvp2)) != NULL) {
+                       char tsbuf[DATETIME_BUF_LEN];
+                       char *tagname = nvpair_name(nvp2);
+                       uint64_t val = 0;
+                       time_t time;
+                       struct tm t;
+                       char sep = scripted ? '\t' : ' ';
+                       int sepnum = scripted ? 1 : 2;
+
+                       (void) nvpair_value_uint64(nvp2, &val);
+                       time = (time_t)val;
+                       (void) localtime_r(&time, &t);
+                       (void) strftime(tsbuf, DATETIME_BUF_LEN,
+                           gettext(STRFTIME_FMT_STR), &t);
+
+                       (void) printf("%-*s%*c%-*s%*c%s\n", nwidth, zname,
+                           sepnum, sep, tagwidth, tagname, sepnum, sep, tsbuf);
+               }
+       }
+}
+
+/*
+ * Generic callback function to list a dataset or snapshot.
+ */
+static int
+holds_callback(zfs_handle_t *zhp, void *data)
+{
+       holds_cbdata_t *cbp = data;
+       nvlist_t *top_nvl = *cbp->cb_nvlp;
+       nvlist_t *nvl = NULL;
+       nvpair_t *nvp = NULL;
+       const char *zname = zfs_get_name(zhp);
+       size_t znamelen = strlen(zname);
+
+       if (cbp->cb_recursive) {
+               const char *snapname;
+               char *delim  = strchr(zname, '@');
+               if (delim == NULL)
+                       return (0);
+
+               snapname = delim + 1;
+               if (strcmp(cbp->cb_snapname, snapname))
+                       return (0);
+       }
+
+       if (zfs_get_holds(zhp, &nvl) != 0)
+               return (-1);
+
+       if (znamelen > cbp->cb_max_namelen)
+               cbp->cb_max_namelen  = znamelen;
+
+       while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
+               const char *tag = nvpair_name(nvp);
+               size_t taglen = strlen(tag);
+               if (taglen > cbp->cb_max_taglen)
+                       cbp->cb_max_taglen  = taglen;
+       }
+
+       return (nvlist_add_nvlist(top_nvl, zname, nvl));
+}
+
+/*
+ * zfs holds [-r] <snap> ...
+ *
+ *     -r      Recursively hold
+ */
+static int
+zfs_do_holds(int argc, char **argv)
+{
+       int errors = 0;
+       int c;
+       int i;
+       boolean_t scripted = B_FALSE;
+       boolean_t recursive = B_FALSE;
+       const char *opts = "rH";
+       nvlist_t *nvl;
+
+       int types = ZFS_TYPE_SNAPSHOT;
+       holds_cbdata_t cb = { 0 };
+
+       int limit = 0;
+       int ret = 0;
+       int flags = 0;
+
+       /* check options */
+       while ((c = getopt(argc, argv, opts)) != -1) {
+               switch (c) {
+               case 'r':
+                       recursive = B_TRUE;
+                       break;
+               case 'H':
+                       scripted = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       if (recursive) {
+               types |= ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME;
+               flags |= ZFS_ITER_RECURSE;
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 1)
+               usage(B_FALSE);
+
+       if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+               nomem();
+
+       for (i = 0; i < argc; ++i) {
+               char *snapshot = argv[i];
+               const char *delim;
+               const char *snapname;
+
+               delim = strchr(snapshot, '@');
+               if (delim == NULL) {
+                       (void) fprintf(stderr,
+                           gettext("'%s' is not a snapshot\n"), snapshot);
+                       ++errors;
+                       continue;
+               }
+               snapname = delim + 1;
+               if (recursive)
+                       snapshot[delim - snapshot] = '\0';
+
+               cb.cb_recursive = recursive;
+               cb.cb_snapname = snapname;
+               cb.cb_nvlp = &nvl;
+
+               /*
+                *  1. collect holds data, set format options
+                */
+               ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit,
+                   holds_callback, &cb);
+               if (ret != 0)
+                       ++errors;
+       }
+
+       /*
+        *  2. print holds data
+        */
+       print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl);
+
+       if (nvlist_empty(nvl))
+               (void) fprintf(stderr, gettext("no datasets available\n"));
+
+       nvlist_free(nvl);
+
+       return (0 != errors);
+}
+
+#define        CHECK_SPINNER 30
+#define        SPINNER_TIME 3          /* seconds */
+#define        MOUNT_TIME 5            /* seconds */
+
+static int
+get_one_dataset(zfs_handle_t *zhp, void *data)
+{
+       static char *spin[] = { "-", "\\", "|", "/" };
+       static int spinval = 0;
+       static int spincheck = 0;
+       static time_t last_spin_time = (time_t)0;
+       get_all_cb_t *cbp = data;
+       zfs_type_t type = zfs_get_type(zhp);
+
+       if (cbp->cb_verbose) {
+               if (--spincheck < 0) {
+                       time_t now = time(NULL);
+                       if (last_spin_time + SPINNER_TIME < now) {
+                               update_progress(spin[spinval++ % 4]);
+                               last_spin_time = now;
+                       }
+                       spincheck = CHECK_SPINNER;
+               }
+       }
+
+       /*
+        * Iterate over any nested datasets.
+        */
+       if (zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) {
+               zfs_close(zhp);
+               return (1);
+       }
+
+       /*
+        * Skip any datasets whose type does not match.
+        */
+       if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
+               zfs_close(zhp);
+               return (0);
+       }
+       libzfs_add_handle(cbp, zhp);
+       assert(cbp->cb_used <= cbp->cb_alloc);
+
+       return (0);
+}
+
+static void
+get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
+{
+       get_all_cb_t cb = { 0 };
+       cb.cb_verbose = verbose;
+       cb.cb_getone = get_one_dataset;
+
+       if (verbose)
+               set_progress_header(gettext("Reading ZFS config"));
+       (void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
+
+       *dslist = cb.cb_handles;
+       *count = cb.cb_used;
+
+       if (verbose)
+               finish_progress(gettext("done."));
+}
+
+/*
+ * Generic callback for sharing or mounting filesystems.  Because the code is so
+ * similar, we have a common function with an extra parameter to determine which
+ * mode we are using.
+ */
+#define        OP_SHARE        0x1
+#define        OP_MOUNT        0x2
+
+/*
+ * Share or mount a dataset.
+ */
+static int
+share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
+    boolean_t explicit, const char *options)
+{
+       char mountpoint[ZFS_MAXPROPLEN];
+       char shareopts[ZFS_MAXPROPLEN];
+       char smbshareopts[ZFS_MAXPROPLEN];
+       const char *cmdname = op == OP_SHARE ? "share" : "mount";
+       struct mnttab mnt;
+       uint64_t zoned, canmount;
+       boolean_t shared_nfs, shared_smb;
+
+       assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM);
+
+       /*
+        * Check to make sure we can mount/share this dataset.  If we
+        * are in the global zone and the filesystem is exported to a
+        * local zone, or if we are in a local zone and the
+        * filesystem is not exported, then it is an error.
+        */
+       zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+
+       if (zoned && getzoneid() == GLOBAL_ZONEID) {
+               if (!explicit)
+                       return (0);
+
+               (void) fprintf(stderr, gettext("cannot %s '%s': "
+                   "dataset is exported to a local zone\n"), cmdname,
+                   zfs_get_name(zhp));
+               return (1);
+
+       } else if (!zoned && getzoneid() != GLOBAL_ZONEID) {
+               if (!explicit)
+                       return (0);
+
+               (void) fprintf(stderr, gettext("cannot %s '%s': "
+                   "permission denied\n"), cmdname,
+                   zfs_get_name(zhp));
+               return (1);
+       }
+
+       /*
+        * Ignore any filesystems which don't apply to us. This
+        * includes those with a legacy mountpoint, or those with
+        * legacy share options.
+        */
+       verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
+           sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
+       verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
+           sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0);
+       verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshareopts,
+           sizeof (smbshareopts), NULL, NULL, 0, B_FALSE) == 0);
+
+       if (op == OP_SHARE && strcmp(shareopts, "off") == 0 &&
+           strcmp(smbshareopts, "off") == 0) {
+               if (!explicit)
+                       return (0);
+
+               (void) fprintf(stderr, gettext("cannot share '%s': "
+                   "legacy share\n"), zfs_get_name(zhp));
+               (void) fprintf(stderr, gettext("use share(1M) to "
+                   "share this filesystem, or set "
+                   "sharenfs property on\n"));
+               return (1);
+       }
+
+       /*
+        * We cannot share or mount legacy filesystems. If the
+        * shareopts is non-legacy but the mountpoint is legacy, we
+        * treat it as a legacy share.
+        */
+       if (strcmp(mountpoint, "legacy") == 0) {
+               if (!explicit)
+                       return (0);
+
+               (void) fprintf(stderr, gettext("cannot %s '%s': "
+                   "legacy mountpoint\n"), cmdname, zfs_get_name(zhp));
+               (void) fprintf(stderr, gettext("use %s(1M) to "
+                   "%s this filesystem\n"), cmdname, cmdname);
+               return (1);
+       }
+
+       if (strcmp(mountpoint, "none") == 0) {
+               if (!explicit)
+                       return (0);
+
+               (void) fprintf(stderr, gettext("cannot %s '%s': no "
+                   "mountpoint set\n"), cmdname, zfs_get_name(zhp));
+               return (1);
+       }
+
+       /*
+        * canmount     explicit        outcome
+        * on           no              pass through
+        * on           yes             pass through
+        * off          no              return 0
+        * off          yes             display error, return 1
+        * noauto       no              return 0
+        * noauto       yes             pass through
+        */
+       canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
+       if (canmount == ZFS_CANMOUNT_OFF) {
+               if (!explicit)
+                       return (0);
+
+               (void) fprintf(stderr, gettext("cannot %s '%s': "
+                   "'canmount' property is set to 'off'\n"), cmdname,
+                   zfs_get_name(zhp));
+               return (1);
+       } else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
+               return (0);
+       }
+
+       /*
+        * If this filesystem is inconsistent and has a receive resume
+        * token, we can not mount it.
+        */
+       if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
+           zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+           NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
+               if (!explicit)
+                       return (0);
+
+               (void) fprintf(stderr, gettext("cannot %s '%s': "
+                   "Contains partially-completed state from "
+                   "\"zfs receive -r\", which can be resumed with "
+                   "\"zfs send -t\"\n"),
+                   cmdname, zfs_get_name(zhp));
+               return (1);
+       }
+
+       /*
+        * At this point, we have verified that the mountpoint and/or
+        * shareopts are appropriate for auto management. If the
+        * filesystem is already mounted or shared, return (failing
+        * for explicit requests); otherwise mount or share the
+        * filesystem.
+        */
+       switch (op) {
+       case OP_SHARE:
+
+               shared_nfs = zfs_is_shared_nfs(zhp, NULL);
+               shared_smb = zfs_is_shared_smb(zhp, NULL);
+
+               if ((shared_nfs && shared_smb) ||
+                   ((shared_nfs && strcmp(shareopts, "on") == 0) &&
+                   (strcmp(smbshareopts, "off") == 0)) ||
+                   ((shared_smb && strcmp(smbshareopts, "on") == 0) &&
+                   (strcmp(shareopts, "off") == 0))) {
+                       if (!explicit)
+                               return (0);
+
+                       (void) fprintf(stderr, gettext("cannot share "
+                           "'%s': filesystem already shared\n"),
+                           zfs_get_name(zhp));
+                       return (1);
+               }
+
+               if (!zfs_is_mounted(zhp, NULL) &&
+                   zfs_mount(zhp, NULL, 0) != 0)
+                       return (1);
+
+               if (protocol == NULL) {
+                       if (zfs_shareall(zhp) != 0)
+                               return (1);
+               } else if (strcmp(protocol, "nfs") == 0) {
+                       if (zfs_share_nfs(zhp))
+                               return (1);
+               } else if (strcmp(protocol, "smb") == 0) {
+                       if (zfs_share_smb(zhp))
+                               return (1);
+               } else {
+                       (void) fprintf(stderr, gettext("cannot share "
+                           "'%s': invalid share type '%s' "
+                           "specified\n"),
+                           zfs_get_name(zhp), protocol);
+                       return (1);
+               }
+
+               break;
+
+       case OP_MOUNT:
+               if (options == NULL)
+                       mnt.mnt_mntopts = "";
+               else
+                       mnt.mnt_mntopts = (char *)options;
+
+               if (!hasmntopt(&mnt, MNTOPT_REMOUNT) &&
+                   zfs_is_mounted(zhp, NULL)) {
+                       if (!explicit)
+                               return (0);
+
+                       (void) fprintf(stderr, gettext("cannot mount "
+                           "'%s': filesystem already mounted\n"),
+                           zfs_get_name(zhp));
+                       return (1);
+               }
+
+               if (zfs_mount(zhp, options, flags) != 0)
+                       return (1);
+               break;
+       }
+
+       return (0);
+}
+
+/*
+ * Reports progress in the form "(current/total)".  Not thread-safe.
+ */
+static void
+report_mount_progress(int current, int total)
+{
+       static time_t last_progress_time = 0;
+       time_t now = time(NULL);
+       char info[32];
+
+       /* report 1..n instead of 0..n-1 */
+       ++current;
+
+       /* display header if we're here for the first time */
+       if (current == 1) {
+               set_progress_header(gettext("Mounting ZFS filesystems"));
+       } else if (current != total && last_progress_time + MOUNT_TIME >= now) {
+               /* too soon to report again */
+               return;
+       }
+
+       last_progress_time = now;
+
+       (void) sprintf(info, "(%d/%d)", current, total);
+
+       if (current == total)
+               finish_progress(info);
+       else
+               update_progress(info);
+}
+
+static void
+append_options(char *mntopts, char *newopts)
+{
+       int len = strlen(mntopts);
+
+       /* original length plus new string to append plus 1 for the comma */
+       if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
+               (void) fprintf(stderr, gettext("the opts argument for "
+                   "'%s' option is too long (more than %d chars)\n"),
+                   "-o", MNT_LINE_MAX);
+               usage(B_FALSE);
+       }
+
+       if (*mntopts)
+               mntopts[len++] = ',';
+
+       (void) strcpy(&mntopts[len], newopts);
+}
+
+static int
+share_mount(int op, int argc, char **argv)
+{
+       int do_all = 0;
+       boolean_t verbose = B_FALSE;
+       int c, ret = 0;
+       char *options = NULL;
+       int flags = 0;
+
+       /* check options */
+       while ((c = getopt(argc, argv, op == OP_MOUNT ? ":avo:O" : "a"))
+           != -1) {
+               switch (c) {
+               case 'a':
+                       do_all = 1;
+                       break;
+               case 'v':
+                       verbose = B_TRUE;
+                       break;
+               case 'o':
+                       if (*optarg == '\0') {
+                               (void) fprintf(stderr, gettext("empty mount "
+                                   "options (-o) specified\n"));
+                               usage(B_FALSE);
+                       }
+
+                       if (options == NULL)
+                               options = safe_malloc(MNT_LINE_MAX + 1);
+
+                       /* option validation is done later */
+                       append_options(options, optarg);
+                       break;
+               case 'O':
+                       flags |= MS_OVERLAY;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (do_all) {
+               zfs_handle_t **dslist = NULL;
+               size_t i, count = 0;
+               char *protocol = NULL;
+
+               if (op == OP_SHARE && argc > 0) {
+                       if (strcmp(argv[0], "nfs") != 0 &&
+                           strcmp(argv[0], "smb") != 0) {
+                               (void) fprintf(stderr, gettext("share type "
+                                   "must be 'nfs' or 'smb'\n"));
+                               usage(B_FALSE);
+                       }
+                       protocol = argv[0];
+                       argc--;
+                       argv++;
+               }
+
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+
+               start_progress_timer();
+               get_all_datasets(&dslist, &count, verbose);
+
+               if (count == 0) {
+                       if (options != NULL)
+                               free(options);
+                       return (0);
+               }
+
+               qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp);
+
+               for (i = 0; i < count; i++) {
+                       if (verbose)
+                               report_mount_progress(i, count);
+
+                       if (share_mount_one(dslist[i], op, flags, protocol,
+                           B_FALSE, options) != 0)
+                               ret = 1;
+                       zfs_close(dslist[i]);
+               }
+
+               free(dslist);
+       } else if (argc == 0) {
+               struct mnttab entry;
+
+               if ((op == OP_SHARE) || (options != NULL)) {
+                       (void) fprintf(stderr, gettext("missing filesystem "
+                           "argument (specify -a for all)\n"));
+                       usage(B_FALSE);
+               }
+
+               /*
+                * When mount is given no arguments, go through
+                * /proc/self/mounts and display any active ZFS mounts.
+                * We hide any snapshots, since they are controlled
+                * automatically.
+                */
+
+               /* Reopen MNTTAB to prevent reading stale data from open file */
+               if (freopen(MNTTAB, "r", mnttab_file) == NULL) {
+                       if (options != NULL)
+                               free(options);
+                       return (ENOENT);
+               }
+
+               while (getmntent(mnttab_file, &entry) == 0) {
+                       if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
+                           strchr(entry.mnt_special, '@') != NULL)
+                               continue;
+
+                       (void) printf("%-30s  %s\n", entry.mnt_special,
+                           entry.mnt_mountp);
+               }
+
+       } else {
+               zfs_handle_t *zhp;
+
+               if (argc > 1) {
+                       (void) fprintf(stderr,
+                           gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+
+               if ((zhp = zfs_open(g_zfs, argv[0],
+                   ZFS_TYPE_FILESYSTEM)) == NULL) {
+                       ret = 1;
+               } else {
+                       ret = share_mount_one(zhp, op, flags, NULL, B_TRUE,
+                           options);
+                       zfs_close(zhp);
+               }
+       }
+
+       if (options != NULL)
+               free(options);
+
+       return (ret);
+}
+
+/*
+ * zfs mount -a [nfs]
+ * zfs mount filesystem
+ *
+ * Mount all filesystems, or mount the given filesystem.
+ */
+static int
+zfs_do_mount(int argc, char **argv)
+{
+       return (share_mount(OP_MOUNT, argc, argv));
+}
+
+/*
+ * zfs share -a [nfs | smb]
+ * zfs share filesystem
+ *
+ * Share all filesystems, or share the given filesystem.
+ */
+static int
+zfs_do_share(int argc, char **argv)
+{
+       return (share_mount(OP_SHARE, argc, argv));
+}
+
+typedef struct unshare_unmount_node {
+       zfs_handle_t    *un_zhp;
+       char            *un_mountp;
+       uu_avl_node_t   un_avlnode;
+} unshare_unmount_node_t;
+
+/* ARGSUSED */
+static int
+unshare_unmount_compare(const void *larg, const void *rarg, void *unused)
+{
+       const unshare_unmount_node_t *l = larg;
+       const unshare_unmount_node_t *r = rarg;
+
+       return (strcmp(l->un_mountp, r->un_mountp));
+}
+
+/*
+ * Convenience routine used by zfs_do_umount() and manual_unmount().  Given an
+ * absolute path, find the entry /proc/self/mounts, verify that its a
+ * ZFS filesystems, and unmount it appropriately.
+ */
+static int
+unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
+{
+       zfs_handle_t *zhp;
+       int ret = 0;
+       struct stat64 statbuf;
+       struct extmnttab entry;
+       const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount";
+       ino_t path_inode;
+
+       /*
+        * Search for the path in /proc/self/mounts. Rather than looking for the
+        * specific path, which can be fooled by non-standard paths (i.e. ".."
+        * or "//"), we stat() the path and search for the corresponding
+        * (major,minor) device pair.
+        */
+       if (stat64(path, &statbuf) != 0) {
+               (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
+                   cmdname, path, strerror(errno));
+               return (1);
+       }
+       path_inode = statbuf.st_ino;
+
+       /*
+        * Search for the given (major,minor) pair in the mount table.
+        */
+
+       /* Reopen MNTTAB to prevent reading stale data from open file */
+       if (freopen(MNTTAB, "r", mnttab_file) == NULL)
+               return (ENOENT);
+
+       while ((ret = getextmntent(mnttab_file, &entry, 0)) == 0) {
+               if (entry.mnt_major == major(statbuf.st_dev) &&
+                   entry.mnt_minor == minor(statbuf.st_dev))
+                       break;
+       }
+       if (ret != 0) {
+               if (op == OP_SHARE) {
+                       (void) fprintf(stderr, gettext("cannot %s '%s': not "
+                           "currently mounted\n"), cmdname, path);
+                       return (1);
+               }
+               (void) fprintf(stderr, gettext("warning: %s not in"
+                   "/proc/self/mounts\n"), path);
+               if ((ret = umount2(path, flags)) != 0)
+                       (void) fprintf(stderr, gettext("%s: %s\n"), path,
+                           strerror(errno));
+               return (ret != 0);
+       }
+
+       if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
+               (void) fprintf(stderr, gettext("cannot %s '%s': not a ZFS "
+                   "filesystem\n"), cmdname, path);
+               return (1);
+       }
+
+       if ((zhp = zfs_open(g_zfs, entry.mnt_special,
+           ZFS_TYPE_FILESYSTEM)) == NULL)
+               return (1);
+
+       ret = 1;
+       if (stat64(entry.mnt_mountp, &statbuf) != 0) {
+               (void) fprintf(stderr, gettext("cannot %s '%s': %s\n"),
+                   cmdname, path, strerror(errno));
+               goto out;
+       } else if (statbuf.st_ino != path_inode) {
+               (void) fprintf(stderr, gettext("cannot "
+                   "%s '%s': not a mountpoint\n"), cmdname, path);
+               goto out;
+       }
+
+       if (op == OP_SHARE) {
+               char nfs_mnt_prop[ZFS_MAXPROPLEN];
+               char smbshare_prop[ZFS_MAXPROPLEN];
+
+               verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS, nfs_mnt_prop,
+                   sizeof (nfs_mnt_prop), NULL, NULL, 0, B_FALSE) == 0);
+               verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB, smbshare_prop,
+                   sizeof (smbshare_prop), NULL, NULL, 0, B_FALSE) == 0);
+
+               if (strcmp(nfs_mnt_prop, "off") == 0 &&
+                   strcmp(smbshare_prop, "off") == 0) {
+                       (void) fprintf(stderr, gettext("cannot unshare "
+                           "'%s': legacy share\n"), path);
+                       (void) fprintf(stderr, gettext("use exportfs(8) "
+                           "or smbcontrol(1) to unshare this filesystem\n"));
+               } else if (!zfs_is_shared(zhp)) {
+                       (void) fprintf(stderr, gettext("cannot unshare '%s': "
+                           "not currently shared\n"), path);
+               } else {
+                       ret = zfs_unshareall_bypath(zhp, path);
+               }
+       } else {
+               char mtpt_prop[ZFS_MAXPROPLEN];
+
+               verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mtpt_prop,
+                   sizeof (mtpt_prop), NULL, NULL, 0, B_FALSE) == 0);
+
+               if (is_manual) {
+                       ret = zfs_unmount(zhp, NULL, flags);
+               } else if (strcmp(mtpt_prop, "legacy") == 0) {
+                       (void) fprintf(stderr, gettext("cannot unmount "
+                           "'%s': legacy mountpoint\n"),
+                           zfs_get_name(zhp));
+                       (void) fprintf(stderr, gettext("use umount(8) "
+                           "to unmount this filesystem\n"));
+               } else {
+                       ret = zfs_unmountall(zhp, flags);
+               }
+       }
+
+out:
+       zfs_close(zhp);
+
+       return (ret != 0);
+}
+
+/*
+ * Generic callback for unsharing or unmounting a filesystem.
+ */
+static int
+unshare_unmount(int op, int argc, char **argv)
+{
+       int do_all = 0;
+       int flags = 0;
+       int ret = 0;
+       int c;
+       zfs_handle_t *zhp;
+       char nfs_mnt_prop[ZFS_MAXPROPLEN];
+       char sharesmb[ZFS_MAXPROPLEN];
+
+       /* check options */
+       while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) {
+               switch (c) {
+               case 'a':
+                       do_all = 1;
+                       break;
+               case 'f':
+                       flags = MS_FORCE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (do_all) {
+               /*
+                * We could make use of zfs_for_each() to walk all datasets in
+                * the system, but this would be very inefficient, especially
+                * since we would have to linearly search /proc/self/mounts for
+                * each one. Instead, do one pass through /proc/self/mounts
+                * looking for zfs entries and call zfs_unmount() for each one.
+                *
+                * Things get a little tricky if the administrator has created
+                * mountpoints beneath other ZFS filesystems.  In this case, we
+                * have to unmount the deepest filesystems first.  To accomplish
+                * this, we place all the mountpoints in an AVL tree sorted by
+                * the special type (dataset name), and walk the result in
+                * reverse to make sure to get any snapshots first.
+                */
+               struct mnttab entry;
+               uu_avl_pool_t *pool;
+               uu_avl_t *tree = NULL;
+               unshare_unmount_node_t *node;
+               uu_avl_index_t idx;
+               uu_avl_walk_t *walk;
+
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+
+               if (((pool = uu_avl_pool_create("unmount_pool",
+                   sizeof (unshare_unmount_node_t),
+                   offsetof(unshare_unmount_node_t, un_avlnode),
+                   unshare_unmount_compare, UU_DEFAULT)) == NULL) ||
+                   ((tree = uu_avl_create(pool, NULL, UU_DEFAULT)) == NULL))
+                       nomem();
+
+               /* Reopen MNTTAB to prevent reading stale data from open file */
+               if (freopen(MNTTAB, "r", mnttab_file) == NULL)
+                       return (ENOENT);
+
+               while (getmntent(mnttab_file, &entry) == 0) {
+
+                       /* ignore non-ZFS entries */
+                       if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
+                               continue;
+
+                       /* ignore snapshots */
+                       if (strchr(entry.mnt_special, '@') != NULL)
+                               continue;
+
+                       if ((zhp = zfs_open(g_zfs, entry.mnt_special,
+                           ZFS_TYPE_FILESYSTEM)) == NULL) {
+                               ret = 1;
+                               continue;
+                       }
+
+                       switch (op) {
+                       case OP_SHARE:
+                               verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
+                                   nfs_mnt_prop,
+                                   sizeof (nfs_mnt_prop),
+                                   NULL, NULL, 0, B_FALSE) == 0);
+                               if (strcmp(nfs_mnt_prop, "off") != 0)
+                                       break;
+                               verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
+                                   nfs_mnt_prop,
+                                   sizeof (nfs_mnt_prop),
+                                   NULL, NULL, 0, B_FALSE) == 0);
+                               if (strcmp(nfs_mnt_prop, "off") == 0)
+                                       continue;
+                               break;
+                       case OP_MOUNT:
+                               /* Ignore legacy mounts */
+                               verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
+                                   nfs_mnt_prop,
+                                   sizeof (nfs_mnt_prop),
+                                   NULL, NULL, 0, B_FALSE) == 0);
+                               if (strcmp(nfs_mnt_prop, "legacy") == 0)
+                                       continue;
+                               /* Ignore canmount=noauto mounts */
+                               if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
+                                   ZFS_CANMOUNT_NOAUTO)
+                                       continue;
+                       default:
+                               break;
+                       }
+
+                       node = safe_malloc(sizeof (unshare_unmount_node_t));
+                       node->un_zhp = zhp;
+                       node->un_mountp = safe_strdup(entry.mnt_mountp);
+
+                       uu_avl_node_init(node, &node->un_avlnode, pool);
+
+                       if (uu_avl_find(tree, node, NULL, &idx) == NULL) {
+                               uu_avl_insert(tree, node, idx);
+                       } else {
+                               zfs_close(node->un_zhp);
+                               free(node->un_mountp);
+                               free(node);
+                       }
+               }
+
+               /*
+                * Walk the AVL tree in reverse, unmounting each filesystem and
+                * removing it from the AVL tree in the process.
+                */
+               if ((walk = uu_avl_walk_start(tree,
+                   UU_WALK_REVERSE | UU_WALK_ROBUST)) == NULL)
+                       nomem();
+
+               while ((node = uu_avl_walk_next(walk)) != NULL) {
+                       uu_avl_remove(tree, node);
+
+                       switch (op) {
+                       case OP_SHARE:
+                               if (zfs_unshareall_bypath(node->un_zhp,
+                                   node->un_mountp) != 0)
+                                       ret = 1;
+                               break;
+
+                       case OP_MOUNT:
+                               if (zfs_unmount(node->un_zhp,
+                                   node->un_mountp, flags) != 0)
+                                       ret = 1;
+                               break;
+                       }
+
+                       zfs_close(node->un_zhp);
+                       free(node->un_mountp);
+                       free(node);
+               }
+
+               uu_avl_walk_end(walk);
+               uu_avl_destroy(tree);
+               uu_avl_pool_destroy(pool);
+
+       } else {
+               if (argc != 1) {
+                       if (argc == 0)
+                               (void) fprintf(stderr,
+                                   gettext("missing filesystem argument\n"));
+                       else
+                               (void) fprintf(stderr,
+                                   gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+
+               /*
+                * We have an argument, but it may be a full path or a ZFS
+                * filesystem.  Pass full paths off to unmount_path() (shared by
+                * manual_unmount), otherwise open the filesystem and pass to
+                * zfs_unmount().
+                */
+               if (argv[0][0] == '/')
+                       return (unshare_unmount_path(op, argv[0],
+                           flags, B_FALSE));
+
+               if ((zhp = zfs_open(g_zfs, argv[0],
+                   ZFS_TYPE_FILESYSTEM)) == NULL)
+                       return (1);
+
+               verify(zfs_prop_get(zhp, op == OP_SHARE ?
+                   ZFS_PROP_SHARENFS : ZFS_PROP_MOUNTPOINT,
+                   nfs_mnt_prop, sizeof (nfs_mnt_prop), NULL,
+                   NULL, 0, B_FALSE) == 0);
+
+               switch (op) {
+               case OP_SHARE:
+                       verify(zfs_prop_get(zhp, ZFS_PROP_SHARENFS,
+                           nfs_mnt_prop,
+                           sizeof (nfs_mnt_prop),
+                           NULL, NULL, 0, B_FALSE) == 0);
+                       verify(zfs_prop_get(zhp, ZFS_PROP_SHARESMB,
+                           sharesmb, sizeof (sharesmb), NULL, NULL,
+                           0, B_FALSE) == 0);
+
+                       if (strcmp(nfs_mnt_prop, "off") == 0 &&
+                           strcmp(sharesmb, "off") == 0) {
+                               (void) fprintf(stderr, gettext("cannot "
+                                   "unshare '%s': legacy share\n"),
+                                   zfs_get_name(zhp));
+                               (void) fprintf(stderr, gettext("use "
+                                   "unshare(1M) to unshare this "
+                                   "filesystem\n"));
+                               ret = 1;
+                       } else if (!zfs_is_shared(zhp)) {
+                               (void) fprintf(stderr, gettext("cannot "
+                                   "unshare '%s': not currently "
+                                   "shared\n"), zfs_get_name(zhp));
+                               ret = 1;
+                       } else if (zfs_unshareall(zhp) != 0) {
+                               ret = 1;
+                       }
+                       break;
+
+               case OP_MOUNT:
+                       if (strcmp(nfs_mnt_prop, "legacy") == 0) {
+                               (void) fprintf(stderr, gettext("cannot "
+                                   "unmount '%s': legacy "
+                                   "mountpoint\n"), zfs_get_name(zhp));
+                               (void) fprintf(stderr, gettext("use "
+                                   "umount(1M) to unmount this "
+                                   "filesystem\n"));
+                               ret = 1;
+                       } else if (!zfs_is_mounted(zhp, NULL)) {
+                               (void) fprintf(stderr, gettext("cannot "
+                                   "unmount '%s': not currently "
+                                   "mounted\n"),
+                                   zfs_get_name(zhp));
+                               ret = 1;
+                       } else if (zfs_unmountall(zhp, flags) != 0) {
+                               ret = 1;
+                       }
+                       break;
+               }
+
+               zfs_close(zhp);
+       }
+
+       return (ret);
+}
+
+/*
+ * zfs unmount -a
+ * zfs unmount filesystem
+ *
+ * Unmount all filesystems, or a specific ZFS filesystem.
+ */
+static int
+zfs_do_unmount(int argc, char **argv)
+{
+       return (unshare_unmount(OP_MOUNT, argc, argv));
+}
+
+/*
+ * zfs unshare -a
+ * zfs unshare filesystem
+ *
+ * Unshare all filesystems, or a specific ZFS filesystem.
+ */
+static int
+zfs_do_unshare(int argc, char **argv)
+{
+       return (unshare_unmount(OP_SHARE, argc, argv));
+}
+
+static int
+find_command_idx(char *command, int *idx)
+{
+       int i;
+
+       for (i = 0; i < NCOMMAND; i++) {
+               if (command_table[i].name == NULL)
+                       continue;
+
+               if (strcmp(command, command_table[i].name) == 0) {
+                       *idx = i;
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+static int
+zfs_do_diff(int argc, char **argv)
+{
+       zfs_handle_t *zhp;
+       int flags = 0;
+       char *tosnap = NULL;
+       char *fromsnap = NULL;
+       char *atp, *copy;
+       int err = 0;
+       int c;
+
+       while ((c = getopt(argc, argv, "FHt")) != -1) {
+               switch (c) {
+               case 'F':
+                       flags |= ZFS_DIFF_CLASSIFY;
+                       break;
+               case 'H':
+                       flags |= ZFS_DIFF_PARSEABLE;
+                       break;
+               case 't':
+                       flags |= ZFS_DIFF_TIMESTAMP;
+                       break;
+               default:
+                       (void) fprintf(stderr,
+                           gettext("invalid option '%c'\n"), optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
+               (void) fprintf(stderr,
+               gettext("must provide at least one snapshot name\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc > 2) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       fromsnap = argv[0];
+       tosnap = (argc == 2) ? argv[1] : NULL;
+
+       copy = NULL;
+       if (*fromsnap != '@')
+               copy = strdup(fromsnap);
+       else if (tosnap)
+               copy = strdup(tosnap);
+       if (copy == NULL)
+               usage(B_FALSE);
+
+       if ((atp = strchr(copy, '@')))
+               *atp = '\0';
+
+       if ((zhp = zfs_open(g_zfs, copy, ZFS_TYPE_FILESYSTEM)) == NULL) {
+               free(copy);
+               return (1);
+       }
+       free(copy);
+
+       /*
+        * Ignore SIGPIPE so that the library can give us
+        * information on any failure
+        */
+       (void) sigignore(SIGPIPE);
+
+       err = zfs_show_diffs(zhp, STDOUT_FILENO, fromsnap, tosnap, flags);
+
+       zfs_close(zhp);
+
+       return (err != 0);
+}
+
+/*
+ * zfs bookmark <fs@snap> <fs#bmark>
+ *
+ * Creates a bookmark with the given name from the given snapshot.
+ */
+static int
+zfs_do_bookmark(int argc, char **argv)
+{
+       char snapname[ZFS_MAX_DATASET_NAME_LEN];
+       zfs_handle_t *zhp;
+       nvlist_t *nvl;
+       int ret = 0;
+       int c;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "")) != -1) {
+               switch (c) {
+               case '?':
+                       (void) fprintf(stderr,
+                           gettext("invalid option '%c'\n"), optopt);
+                       goto usage;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing snapshot argument\n"));
+               goto usage;
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing bookmark argument\n"));
+               goto usage;
+       }
+
+       if (strchr(argv[1], '#') == NULL) {
+               (void) fprintf(stderr,
+                   gettext("invalid bookmark name '%s' -- "
+                   "must contain a '#'\n"), argv[1]);
+               goto usage;
+       }
+
+       if (argv[0][0] == '@') {
+               /*
+                * Snapshot name begins with @.
+                * Default to same fs as bookmark.
+                */
+               (void) strlcpy(snapname, argv[1], sizeof (snapname));
+               *strchr(snapname, '#') = '\0';
+               (void) strlcat(snapname, argv[0], sizeof (snapname));
+       } else {
+               (void) strlcpy(snapname, argv[0], sizeof (snapname));
+       }
+       zhp = zfs_open(g_zfs, snapname, ZFS_TYPE_SNAPSHOT);
+       if (zhp == NULL)
+               goto usage;
+       zfs_close(zhp);
+
+
+       nvl = fnvlist_alloc();
+       fnvlist_add_string(nvl, argv[1], snapname);
+       ret = lzc_bookmark(nvl, NULL);
+       fnvlist_free(nvl);
+
+       if (ret != 0) {
+               const char *err_msg;
+               char errbuf[1024];
+
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "cannot create bookmark '%s'"), argv[1]);
+
+               switch (ret) {
+               case EXDEV:
+                       err_msg = "bookmark is in a different pool";
+                       break;
+               case EEXIST:
+                       err_msg = "bookmark exists";
+                       break;
+               case EINVAL:
+                       err_msg = "invalid argument";
+                       break;
+               case ENOTSUP:
+                       err_msg = "bookmark feature not enabled";
+                       break;
+               case ENOSPC:
+                       err_msg = "out of space";
+                       break;
+               default:
+                       err_msg = "unknown error";
+                       break;
+               }
+               (void) fprintf(stderr, "%s: %s\n", errbuf,
+                   dgettext(TEXT_DOMAIN, err_msg));
+       }
+
+       return (ret != 0);
+
+usage:
+       usage(B_FALSE);
+       return (-1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int ret = 0;
+       int i = 0;
+       char *cmdname;
+
+       (void) setlocale(LC_ALL, "");
+       (void) textdomain(TEXT_DOMAIN);
+
+       dprintf_setup(&argc, argv);
+
+       opterr = 0;
+
+       /*
+        * Make sure the user has specified some command.
+        */
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing command\n"));
+               usage(B_FALSE);
+       }
+
+       cmdname = argv[1];
+
+       /*
+        * The 'umount' command is an alias for 'unmount'
+        */
+       if (strcmp(cmdname, "umount") == 0)
+               cmdname = "unmount";
+
+       /*
+        * The 'recv' command is an alias for 'receive'
+        */
+       if (strcmp(cmdname, "recv") == 0)
+               cmdname = "receive";
+
+       /*
+        * The 'snap' command is an alias for 'snapshot'
+        */
+       if (strcmp(cmdname, "snap") == 0)
+               cmdname = "snapshot";
+
+       /*
+        * Special case '-?'
+        */
+       if ((strcmp(cmdname, "-?") == 0) ||
+           (strcmp(cmdname, "--help") == 0))
+               usage(B_TRUE);
+
+       if ((g_zfs = libzfs_init()) == NULL) {
+               (void) fprintf(stderr, "%s", libzfs_error_init(errno));
+               return (1);
+       }
+
+       mnttab_file = g_zfs->libzfs_mnttab;
+
+       zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
+
+       libzfs_print_on_error(g_zfs, B_TRUE);
+
+       /*
+        * Run the appropriate command.
+        */
+       libzfs_mnttab_cache(g_zfs, B_TRUE);
+       if (find_command_idx(cmdname, &i) == 0) {
+               current_command = &command_table[i];
+               ret = command_table[i].func(argc - 1, argv + 1);
+       } else if (strchr(cmdname, '=') != NULL) {
+               verify(find_command_idx("set", &i) == 0);
+               current_command = &command_table[i];
+               ret = command_table[i].func(argc, argv);
+       } else {
+               (void) fprintf(stderr, gettext("unrecognized "
+                   "command '%s'\n"), cmdname);
+               usage(B_FALSE);
+               ret = 1;
+       }
+
+       if (ret == 0 && log_history)
+               (void) zpool_log_history(g_zfs, history_str);
+
+       libzfs_fini(g_zfs);
+
+       /*
+        * The 'ZFS_ABORT' environment variable causes us to dump core on exit
+        * for the purposes of running ::findleaks.
+        */
+       if (getenv("ZFS_ABORT") != NULL) {
+               (void) printf("dumping core by request\n");
+               abort();
+       }
+
+       return (ret);
+}
diff --git a/zfs/cmd/zfs/zfs_util.h b/zfs/cmd/zfs/zfs_util.h
new file mode 100644 (file)
index 0000000..3ddff9e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _ZFS_UTIL_H
+#define        _ZFS_UTIL_H
+
+#include <libzfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void * safe_malloc(size_t size);
+void nomem(void);
+libzfs_handle_t *g_zfs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZFS_UTIL_H */
diff --git a/zfs/cmd/zhack/Makefile.am b/zfs/cmd/zhack/Makefile.am
new file mode 100644 (file)
index 0000000..a7bce5d
--- /dev/null
@@ -0,0 +1,17 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+sbin_PROGRAMS = zhack
+
+zhack_SOURCES = \
+       zhack.c
+
+zhack_LDADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
diff --git a/zfs/cmd/zhack/Makefile.in b/zfs/cmd/zhack/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zhack/zhack.c b/zfs/cmd/zhack/zhack.c
new file mode 100644 (file)
index 0000000..e769451
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ * 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 (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ */
+
+/*
+ * zhack is a debugging tool that can write changes to ZFS pool using libzpool
+ * for testing purposes. Altering pools with zhack is unsupported and may
+ * result in corrupted pools.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/spa_impl.h>
+#include <sys/dmu.h>
+#include <sys/zap.h>
+#include <sys/zfs_znode.h>
+#include <sys/dsl_synctask.h>
+#include <sys/vdev.h>
+#include <sys/fs/zfs.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_pool.h>
+#include <sys/zio_checksum.h>
+#include <sys/zio_compress.h>
+#include <sys/zfeature.h>
+#include <sys/dmu_tx.h>
+#include <libzfs.h>
+
+extern boolean_t zfeature_checks_disable;
+
+const char cmdname[] = "zhack";
+libzfs_handle_t *g_zfs;
+static importargs_t g_importargs;
+static char *g_pool;
+static boolean_t g_readonly;
+
+static void
+usage(void)
+{
+       (void) fprintf(stderr,
+           "Usage: %s [-c cachefile] [-d dir] <subcommand> <args> ...\n"
+           "where <subcommand> <args> is one of the following:\n"
+           "\n", cmdname);
+
+       (void) fprintf(stderr,
+           "    feature stat <pool>\n"
+           "        print information about enabled features\n"
+           "    feature enable [-r] [-d desc] <pool> <feature>\n"
+           "        add a new enabled feature to the pool\n"
+           "        -d <desc> sets the feature's description\n"
+           "        -r set read-only compatible flag for feature\n"
+           "    feature ref [-md] <pool> <feature>\n"
+           "        change the refcount on the given feature\n"
+           "        -d decrease instead of increase the refcount\n"
+           "        -m add the feature to the label if increasing refcount\n"
+           "\n"
+           "    <feature> : should be a feature guid\n");
+       exit(1);
+}
+
+
+static void
+fatal(spa_t *spa, void *tag, const char *fmt, ...)
+{
+       va_list ap;
+
+       if (spa != NULL) {
+               spa_close(spa, tag);
+               (void) spa_export(g_pool, NULL, B_TRUE, B_FALSE);
+       }
+
+       va_start(ap, fmt);
+       (void) fprintf(stderr, "%s: ", cmdname);
+       (void) vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void) fprintf(stderr, "\n");
+
+       exit(1);
+}
+
+/* ARGSUSED */
+static int
+space_delta_cb(dmu_object_type_t bonustype, void *data,
+    uint64_t *userp, uint64_t *groupp)
+{
+       /*
+        * Is it a valid type of object to track?
+        */
+       if (bonustype != DMU_OT_ZNODE && bonustype != DMU_OT_SA)
+               return (ENOENT);
+       (void) fprintf(stderr, "modifying object that needs user accounting");
+       abort();
+       /* NOTREACHED */
+}
+
+/*
+ * Target is the dataset whose pool we want to open.
+ */
+static void
+import_pool(const char *target, boolean_t readonly)
+{
+       nvlist_t *config;
+       nvlist_t *pools;
+       int error;
+       char *sepp;
+       spa_t *spa;
+       nvpair_t *elem;
+       nvlist_t *props;
+       char *name;
+
+       kernel_init(readonly ? FREAD : (FREAD | FWRITE));
+       g_zfs = libzfs_init();
+       ASSERT(g_zfs != NULL);
+
+       dmu_objset_register_type(DMU_OST_ZFS, space_delta_cb);
+
+       g_readonly = readonly;
+
+       /*
+        * If we only want readonly access, it's OK if we find
+        * a potentially-active (ie, imported into the kernel) pool from the
+        * default cachefile.
+        */
+       if (readonly && spa_open(target, &spa, FTAG) == 0) {
+               spa_close(spa, FTAG);
+               return;
+       }
+
+       g_importargs.unique = B_TRUE;
+       g_importargs.can_be_active = readonly;
+       g_pool = strdup(target);
+       if ((sepp = strpbrk(g_pool, "/@")) != NULL)
+               *sepp = '\0';
+       g_importargs.poolname = g_pool;
+       pools = zpool_search_import(g_zfs, &g_importargs);
+
+       if (nvlist_empty(pools)) {
+               if (!g_importargs.can_be_active) {
+                       g_importargs.can_be_active = B_TRUE;
+                       if (zpool_search_import(g_zfs, &g_importargs) != NULL ||
+                           spa_open(target, &spa, FTAG) == 0) {
+                               fatal(spa, FTAG, "cannot import '%s': pool is "
+                                   "active; run " "\"zpool export %s\" "
+                                   "first\n", g_pool, g_pool);
+                       }
+               }
+
+               fatal(NULL, FTAG, "cannot import '%s': no such pool "
+                   "available\n", g_pool);
+       }
+
+       elem = nvlist_next_nvpair(pools, NULL);
+       name = nvpair_name(elem);
+       VERIFY(nvpair_value_nvlist(elem, &config) == 0);
+
+       props = NULL;
+       if (readonly) {
+               VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+               VERIFY(nvlist_add_uint64(props,
+                   zpool_prop_to_name(ZPOOL_PROP_READONLY), 1) == 0);
+       }
+
+       zfeature_checks_disable = B_TRUE;
+       error = spa_import(name, config, props, ZFS_IMPORT_NORMAL);
+       zfeature_checks_disable = B_FALSE;
+       if (error == EEXIST)
+               error = 0;
+
+       if (error)
+               fatal(NULL, FTAG, "can't import '%s': %s", name,
+                   strerror(error));
+}
+
+static void
+zhack_spa_open(const char *target, boolean_t readonly, void *tag, spa_t **spa)
+{
+       int err;
+
+       import_pool(target, readonly);
+
+       zfeature_checks_disable = B_TRUE;
+       err = spa_open(target, spa, tag);
+       zfeature_checks_disable = B_FALSE;
+
+       if (err != 0)
+               fatal(*spa, FTAG, "cannot open '%s': %s", target,
+                   strerror(err));
+       if (spa_version(*spa) < SPA_VERSION_FEATURES) {
+               fatal(*spa, FTAG, "'%s' has version %d, features not enabled",
+                   target, (int)spa_version(*spa));
+       }
+}
+
+static void
+dump_obj(objset_t *os, uint64_t obj, const char *name)
+{
+       zap_cursor_t zc;
+       zap_attribute_t za;
+
+       (void) printf("%s_obj:\n", name);
+
+       for (zap_cursor_init(&zc, os, obj);
+           zap_cursor_retrieve(&zc, &za) == 0;
+           zap_cursor_advance(&zc)) {
+               if (za.za_integer_length == 8) {
+                       ASSERT(za.za_num_integers == 1);
+                       (void) printf("\t%s = %llu\n",
+                           za.za_name, (u_longlong_t)za.za_first_integer);
+               } else {
+                       ASSERT(za.za_integer_length == 1);
+                       char val[1024];
+                       VERIFY(zap_lookup(os, obj, za.za_name,
+                           1, sizeof (val), val) == 0);
+                       (void) printf("\t%s = %s\n", za.za_name, val);
+               }
+       }
+       zap_cursor_fini(&zc);
+}
+
+static void
+dump_mos(spa_t *spa)
+{
+       nvlist_t *nv = spa->spa_label_features;
+       nvpair_t *pair;
+
+       (void) printf("label config:\n");
+       for (pair = nvlist_next_nvpair(nv, NULL);
+           pair != NULL;
+           pair = nvlist_next_nvpair(nv, pair)) {
+               (void) printf("\t%s\n", nvpair_name(pair));
+       }
+}
+
+static void
+zhack_do_feature_stat(int argc, char **argv)
+{
+       spa_t *spa;
+       objset_t *os;
+       char *target;
+
+       argc--;
+       argv++;
+
+       if (argc < 1) {
+               (void) fprintf(stderr, "error: missing pool name\n");
+               usage();
+       }
+       target = argv[0];
+
+       zhack_spa_open(target, B_TRUE, FTAG, &spa);
+       os = spa->spa_meta_objset;
+
+       dump_obj(os, spa->spa_feat_for_read_obj, "for_read");
+       dump_obj(os, spa->spa_feat_for_write_obj, "for_write");
+       dump_obj(os, spa->spa_feat_desc_obj, "descriptions");
+       if (spa_feature_is_active(spa, SPA_FEATURE_ENABLED_TXG)) {
+               dump_obj(os, spa->spa_feat_enabled_txg_obj, "enabled_txg");
+       }
+       dump_mos(spa);
+
+       spa_close(spa, FTAG);
+}
+
+static void
+zhack_feature_enable_sync(void *arg, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       zfeature_info_t *feature = arg;
+
+       feature_enable_sync(spa, feature, tx);
+
+       spa_history_log_internal(spa, "zhack enable feature", tx,
+           "name=%s flags=%u",
+           feature->fi_guid, feature->fi_flags);
+}
+
+static void
+zhack_do_feature_enable(int argc, char **argv)
+{
+       char c;
+       char *desc, *target;
+       spa_t *spa;
+       objset_t *mos;
+       zfeature_info_t feature;
+       spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
+
+       /*
+        * Features are not added to the pool's label until their refcounts
+        * are incremented, so fi_mos can just be left as false for now.
+        */
+       desc = NULL;
+       feature.fi_uname = "zhack";
+       feature.fi_flags = 0;
+       feature.fi_depends = nodeps;
+       feature.fi_feature = SPA_FEATURE_NONE;
+
+       optind = 1;
+       while ((c = getopt(argc, argv, "+rd:")) != -1) {
+               switch (c) {
+               case 'r':
+                       feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
+                       break;
+               case 'd':
+                       desc = strdup(optarg);
+                       break;
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       if (desc == NULL)
+               desc = strdup("zhack injected");
+       feature.fi_desc = desc;
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 2) {
+               (void) fprintf(stderr, "error: missing feature or pool name\n");
+               usage();
+       }
+       target = argv[0];
+       feature.fi_guid = argv[1];
+
+       if (!zfeature_is_valid_guid(feature.fi_guid))
+               fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
+
+       zhack_spa_open(target, B_FALSE, FTAG, &spa);
+       mos = spa->spa_meta_objset;
+
+       if (zfeature_is_supported(feature.fi_guid))
+               fatal(spa, FTAG, "'%s' is a real feature, will not enable");
+       if (0 == zap_contains(mos, spa->spa_feat_desc_obj, feature.fi_guid))
+               fatal(spa, FTAG, "feature already enabled: %s",
+                   feature.fi_guid);
+
+       VERIFY0(dsl_sync_task(spa_name(spa), NULL,
+           zhack_feature_enable_sync, &feature, 5, ZFS_SPACE_CHECK_NORMAL));
+
+       spa_close(spa, FTAG);
+
+       free(desc);
+}
+
+static void
+feature_incr_sync(void *arg, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       zfeature_info_t *feature = arg;
+       uint64_t refcount;
+
+       VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
+       feature_sync(spa, feature, refcount + 1, tx);
+       spa_history_log_internal(spa, "zhack feature incr", tx,
+           "name=%s", feature->fi_guid);
+}
+
+static void
+feature_decr_sync(void *arg, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       zfeature_info_t *feature = arg;
+       uint64_t refcount;
+
+       VERIFY0(feature_get_refcount_from_disk(spa, feature, &refcount));
+       feature_sync(spa, feature, refcount - 1, tx);
+       spa_history_log_internal(spa, "zhack feature decr", tx,
+           "name=%s", feature->fi_guid);
+}
+
+static void
+zhack_do_feature_ref(int argc, char **argv)
+{
+       char c;
+       char *target;
+       boolean_t decr = B_FALSE;
+       spa_t *spa;
+       objset_t *mos;
+       zfeature_info_t feature;
+       spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
+
+       /*
+        * fi_desc does not matter here because it was written to disk
+        * when the feature was enabled, but we need to properly set the
+        * feature for read or write based on the information we read off
+        * disk later.
+        */
+       feature.fi_uname = "zhack";
+       feature.fi_flags = 0;
+       feature.fi_desc = NULL;
+       feature.fi_depends = nodeps;
+       feature.fi_feature = SPA_FEATURE_NONE;
+
+       optind = 1;
+       while ((c = getopt(argc, argv, "+md")) != -1) {
+               switch (c) {
+               case 'm':
+                       feature.fi_flags |= ZFEATURE_FLAG_MOS;
+                       break;
+               case 'd':
+                       decr = B_TRUE;
+                       break;
+               default:
+                       usage();
+                       break;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 2) {
+               (void) fprintf(stderr, "error: missing feature or pool name\n");
+               usage();
+       }
+       target = argv[0];
+       feature.fi_guid = argv[1];
+
+       if (!zfeature_is_valid_guid(feature.fi_guid))
+               fatal(NULL, FTAG, "invalid feature guid: %s", feature.fi_guid);
+
+       zhack_spa_open(target, B_FALSE, FTAG, &spa);
+       mos = spa->spa_meta_objset;
+
+       if (zfeature_is_supported(feature.fi_guid)) {
+               fatal(spa, FTAG,
+                   "'%s' is a real feature, will not change refcount");
+       }
+
+       if (0 == zap_contains(mos, spa->spa_feat_for_read_obj,
+           feature.fi_guid)) {
+               feature.fi_flags &= ~ZFEATURE_FLAG_READONLY_COMPAT;
+       } else if (0 == zap_contains(mos, spa->spa_feat_for_write_obj,
+           feature.fi_guid)) {
+               feature.fi_flags |= ZFEATURE_FLAG_READONLY_COMPAT;
+       } else {
+               fatal(spa, FTAG, "feature is not enabled: %s", feature.fi_guid);
+       }
+
+       if (decr) {
+               uint64_t count;
+               if (feature_get_refcount_from_disk(spa, &feature,
+                   &count) == 0 && count == 0) {
+                       fatal(spa, FTAG, "feature refcount already 0: %s",
+                           feature.fi_guid);
+               }
+       }
+
+       VERIFY0(dsl_sync_task(spa_name(spa), NULL,
+           decr ? feature_decr_sync : feature_incr_sync, &feature,
+           5, ZFS_SPACE_CHECK_NORMAL));
+
+       spa_close(spa, FTAG);
+}
+
+static int
+zhack_do_feature(int argc, char **argv)
+{
+       char *subcommand;
+
+       argc--;
+       argv++;
+       if (argc == 0) {
+               (void) fprintf(stderr,
+                   "error: no feature operation specified\n");
+               usage();
+       }
+
+       subcommand = argv[0];
+       if (strcmp(subcommand, "stat") == 0) {
+               zhack_do_feature_stat(argc, argv);
+       } else if (strcmp(subcommand, "enable") == 0) {
+               zhack_do_feature_enable(argc, argv);
+       } else if (strcmp(subcommand, "ref") == 0) {
+               zhack_do_feature_ref(argc, argv);
+       } else {
+               (void) fprintf(stderr, "error: unknown subcommand: %s\n",
+                   subcommand);
+               usage();
+       }
+
+       return (0);
+}
+
+#define        MAX_NUM_PATHS 1024
+
+int
+main(int argc, char **argv)
+{
+       extern void zfs_prop_init(void);
+
+       char *path[MAX_NUM_PATHS];
+       const char *subcommand;
+       int rv = 0;
+       char c;
+
+       g_importargs.path = path;
+
+       dprintf_setup(&argc, argv);
+       zfs_prop_init();
+
+       while ((c = getopt(argc, argv, "+c:d:")) != -1) {
+               switch (c) {
+               case 'c':
+                       g_importargs.cachefile = optarg;
+                       break;
+               case 'd':
+                       assert(g_importargs.paths < MAX_NUM_PATHS);
+                       g_importargs.path[g_importargs.paths++] = optarg;
+                       break;
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 1;
+
+       if (argc == 0) {
+               (void) fprintf(stderr, "error: no command specified\n");
+               usage();
+       }
+
+       subcommand = argv[0];
+
+       if (strcmp(subcommand, "feature") == 0) {
+               rv = zhack_do_feature(argc, argv);
+       } else {
+               (void) fprintf(stderr, "error: unknown subcommand: %s\n",
+                   subcommand);
+               usage();
+       }
+
+       if (!g_readonly && spa_export(g_pool, NULL, B_TRUE, B_FALSE) != 0) {
+               fatal(NULL, FTAG, "pool export failed; "
+                   "changes may not be committed to disk\n");
+       }
+
+       libzfs_fini(g_zfs);
+       kernel_fini();
+
+       return (rv);
+}
diff --git a/zfs/cmd/zinject/Makefile.am b/zfs/cmd/zinject/Makefile.am
new file mode 100644 (file)
index 0000000..2500bee
--- /dev/null
@@ -0,0 +1,19 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+sbin_PROGRAMS = zinject
+
+zinject_SOURCES = \
+       translate.c \
+       zinject.c \
+       zinject.h
+
+zinject_LDADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
diff --git a/zfs/cmd/zinject/Makefile.in b/zfs/cmd/zinject/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zinject/translate.c b/zfs/cmd/zinject/translate.c
new file mode 100644 (file)
index 0000000..1aef074
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * 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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <libzfs.h>
+
+#include <sys/zfs_context.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/file.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <sys/dmu.h>
+#include <sys/dmu_objset.h>
+#include <sys/dnode.h>
+#include <sys/vdev_impl.h>
+
+#include <sys/mkdev.h>
+
+#include "zinject.h"
+
+extern void kernel_init(int);
+extern void kernel_fini(void);
+
+static int debug;
+
+static void
+ziprintf(const char *fmt, ...)
+{
+       va_list ap;
+
+       if (!debug)
+               return;
+
+       va_start(ap, fmt);
+       (void) vprintf(fmt, ap);
+       va_end(ap);
+}
+
+static void
+compress_slashes(const char *src, char *dest)
+{
+       while (*src != '\0') {
+               *dest = *src++;
+               while (*dest == '/' && *src == '/')
+                       ++src;
+               ++dest;
+       }
+       *dest = '\0';
+}
+
+/*
+ * Given a full path to a file, translate into a dataset name and a relative
+ * path within the dataset.  'dataset' must be at least MAXNAMELEN characters,
+ * and 'relpath' must be at least MAXPATHLEN characters.  We also pass a stat64
+ * buffer, which we need later to get the object ID.
+ */
+static int
+parse_pathname(const char *inpath, char *dataset, char *relpath,
+    struct stat64 *statbuf)
+{
+       struct extmnttab mp;
+       FILE *fp;
+       int match;
+       const char *rel;
+       char fullpath[MAXPATHLEN];
+
+       compress_slashes(inpath, fullpath);
+
+       if (fullpath[0] != '/') {
+               (void) fprintf(stderr, "invalid object '%s': must be full "
+                   "path\n", fullpath);
+               usage();
+               return (-1);
+       }
+
+       if (strlen(fullpath) >= MAXPATHLEN) {
+               (void) fprintf(stderr, "invalid object; pathname too long\n");
+               return (-1);
+       }
+
+       if (stat64(fullpath, statbuf) != 0) {
+               (void) fprintf(stderr, "cannot open '%s': %s\n",
+                   fullpath, strerror(errno));
+               return (-1);
+       }
+
+#ifdef HAVE_SETMNTENT
+       if ((fp = setmntent(MNTTAB, "r")) == NULL) {
+#else
+       if ((fp = fopen(MNTTAB, "r")) == NULL) {
+#endif
+               (void) fprintf(stderr, "cannot open %s\n", MNTTAB);
+               return (-1);
+       }
+
+       match = 0;
+       while (getextmntent(fp, &mp, sizeof (mp)) == 0) {
+               if (makedev(mp.mnt_major, mp.mnt_minor) == statbuf->st_dev) {
+                       match = 1;
+                       break;
+               }
+       }
+
+       if (!match) {
+               (void) fprintf(stderr, "cannot find mountpoint for '%s'\n",
+                   fullpath);
+               return (-1);
+       }
+
+       if (strcmp(mp.mnt_fstype, MNTTYPE_ZFS) != 0) {
+               (void) fprintf(stderr, "invalid path '%s': not a ZFS "
+                   "filesystem\n", fullpath);
+               return (-1);
+       }
+
+       if (strncmp(fullpath, mp.mnt_mountp, strlen(mp.mnt_mountp)) != 0) {
+               (void) fprintf(stderr, "invalid path '%s': mountpoint "
+                   "doesn't match path\n", fullpath);
+               return (-1);
+       }
+
+       (void) strcpy(dataset, mp.mnt_special);
+
+       rel = fullpath + strlen(mp.mnt_mountp);
+       if (rel[0] == '/')
+               rel++;
+       (void) strcpy(relpath, rel);
+
+       return (0);
+}
+
+/*
+ * Convert from a (dataset, path) pair into a (objset, object) pair.  Note that
+ * we grab the object number from the inode number, since looking this up via
+ * libzpool is a real pain.
+ */
+/* ARGSUSED */
+static int
+object_from_path(const char *dataset, const char *path, struct stat64 *statbuf,
+    zinject_record_t *record)
+{
+       objset_t *os;
+       int err;
+
+       /*
+        * Before doing any libzpool operations, call sync() to ensure that the
+        * on-disk state is consistent with the in-core state.
+        */
+       sync();
+
+       err = dmu_objset_own(dataset, DMU_OST_ZFS, B_TRUE, FTAG, &os);
+       if (err != 0) {
+               (void) fprintf(stderr, "cannot open dataset '%s': %s\n",
+                   dataset, strerror(err));
+               return (-1);
+       }
+
+       record->zi_objset = dmu_objset_id(os);
+       record->zi_object = statbuf->st_ino;
+
+       dmu_objset_disown(os, FTAG);
+
+       return (0);
+}
+
+/*
+ * Calculate the real range based on the type, level, and range given.
+ */
+static int
+calculate_range(const char *dataset, err_type_t type, int level, char *range,
+    zinject_record_t *record)
+{
+       objset_t *os = NULL;
+       dnode_t *dn = NULL;
+       int err;
+       int ret = -1;
+
+       /*
+        * Determine the numeric range from the string.
+        */
+       if (range == NULL) {
+               /*
+                * If range is unspecified, set the range to [0,-1], which
+                * indicates that the whole object should be treated as an
+                * error.
+                */
+               record->zi_start = 0;
+               record->zi_end = -1ULL;
+       } else {
+               char *end;
+
+               /* XXX add support for suffixes */
+               record->zi_start = strtoull(range, &end, 10);
+
+
+               if (*end == '\0')
+                       record->zi_end = record->zi_start + 1;
+               else if (*end == ',')
+                       record->zi_end = strtoull(end + 1, &end, 10);
+
+               if (*end != '\0') {
+                       (void) fprintf(stderr, "invalid range '%s': must be "
+                           "a numeric range of the form 'start[,end]'\n",
+                           range);
+                       goto out;
+               }
+       }
+
+       switch (type) {
+       default:
+               break;
+       case TYPE_DATA:
+               break;
+
+       case TYPE_DNODE:
+               /*
+                * If this is a request to inject faults into the dnode, then we
+                * must translate the current (objset,object) pair into an
+                * offset within the metadnode for the objset.  Specifying any
+                * kind of range with type 'dnode' is illegal.
+                */
+               if (range != NULL) {
+                       (void) fprintf(stderr, "range cannot be specified when "
+                           "type is 'dnode'\n");
+                       goto out;
+               }
+
+               record->zi_start = record->zi_object * sizeof (dnode_phys_t);
+               record->zi_end = record->zi_start + sizeof (dnode_phys_t);
+               record->zi_object = 0;
+               break;
+       }
+
+       /*
+        * Get the dnode associated with object, so we can calculate the block
+        * size.
+        */
+       if ((err = dmu_objset_own(dataset, DMU_OST_ANY,
+           B_TRUE, FTAG, &os)) != 0) {
+               (void) fprintf(stderr, "cannot open dataset '%s': %s\n",
+                   dataset, strerror(err));
+               goto out;
+       }
+
+       if (record->zi_object == 0) {
+               dn = DMU_META_DNODE(os);
+       } else {
+               err = dnode_hold(os, record->zi_object, FTAG, &dn);
+               if (err != 0) {
+                       (void) fprintf(stderr, "failed to hold dnode "
+                           "for object %llu\n",
+                           (u_longlong_t)record->zi_object);
+                       goto out;
+               }
+       }
+
+
+       ziprintf("data shift: %d\n", (int)dn->dn_datablkshift);
+       ziprintf(" ind shift: %d\n", (int)dn->dn_indblkshift);
+
+       /*
+        * Translate range into block IDs.
+        */
+       if (record->zi_start != 0 || record->zi_end != -1ULL) {
+               record->zi_start >>= dn->dn_datablkshift;
+               record->zi_end >>= dn->dn_datablkshift;
+       }
+
+       /*
+        * Check level, and then translate level 0 blkids into ranges
+        * appropriate for level of indirection.
+        */
+       record->zi_level = level;
+       if (level > 0) {
+               ziprintf("level 0 blkid range: [%llu, %llu]\n",
+                   record->zi_start, record->zi_end);
+
+               if (level >= dn->dn_nlevels) {
+                       (void) fprintf(stderr, "level %d exceeds max level "
+                           "of object (%d)\n", level, dn->dn_nlevels - 1);
+                       goto out;
+               }
+
+               if (record->zi_start != 0 || record->zi_end != 0) {
+                       int shift = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
+
+                       for (; level > 0; level--) {
+                               record->zi_start >>= shift;
+                               record->zi_end >>= shift;
+                       }
+               }
+       }
+
+       ret = 0;
+out:
+       if (dn) {
+               if (dn != DMU_META_DNODE(os))
+                       dnode_rele(dn, FTAG);
+       }
+       if (os)
+               dmu_objset_disown(os, FTAG);
+
+       return (ret);
+}
+
+int
+translate_record(err_type_t type, const char *object, const char *range,
+    int level, zinject_record_t *record, char *poolname, char *dataset)
+{
+       char path[MAXPATHLEN];
+       char *slash;
+       struct stat64 statbuf;
+       int ret = -1;
+
+       kernel_init(FREAD);
+
+       debug = (getenv("ZINJECT_DEBUG") != NULL);
+
+       ziprintf("translating: %s\n", object);
+
+       if (MOS_TYPE(type)) {
+               /*
+                * MOS objects are treated specially.
+                */
+               switch (type) {
+               default:
+                       break;
+               case TYPE_MOS:
+                       record->zi_type = 0;
+                       break;
+               case TYPE_MOSDIR:
+                       record->zi_type = DMU_OT_OBJECT_DIRECTORY;
+                       break;
+               case TYPE_METASLAB:
+                       record->zi_type = DMU_OT_OBJECT_ARRAY;
+                       break;
+               case TYPE_CONFIG:
+                       record->zi_type = DMU_OT_PACKED_NVLIST;
+                       break;
+               case TYPE_BPOBJ:
+                       record->zi_type = DMU_OT_BPOBJ;
+                       break;
+               case TYPE_SPACEMAP:
+                       record->zi_type = DMU_OT_SPACE_MAP;
+                       break;
+               case TYPE_ERRLOG:
+                       record->zi_type = DMU_OT_ERROR_LOG;
+                       break;
+               }
+
+               dataset[0] = '\0';
+               (void) strcpy(poolname, object);
+               return (0);
+       }
+
+       /*
+        * Convert a full path into a (dataset, file) pair.
+        */
+       if (parse_pathname(object, dataset, path, &statbuf) != 0)
+               goto err;
+
+       ziprintf("   dataset: %s\n", dataset);
+       ziprintf("      path: %s\n", path);
+
+       /*
+        * Convert (dataset, file) into (objset, object)
+        */
+       if (object_from_path(dataset, path, &statbuf, record) != 0)
+               goto err;
+
+       ziprintf("raw objset: %llu\n", record->zi_objset);
+       ziprintf("raw object: %llu\n", record->zi_object);
+
+       /*
+        * For the given object, calculate the real (type, level, range)
+        */
+       if (calculate_range(dataset, type, level, (char *)range, record) != 0)
+               goto err;
+
+       ziprintf("    objset: %llu\n", record->zi_objset);
+       ziprintf("    object: %llu\n", record->zi_object);
+       if (record->zi_start == 0 &&
+           record->zi_end == -1ULL)
+               ziprintf("     range: all\n");
+       else
+               ziprintf("     range: [%llu, %llu]\n", record->zi_start,
+                   record->zi_end);
+
+       /*
+        * Copy the pool name
+        */
+       (void) strcpy(poolname, dataset);
+       if ((slash = strchr(poolname, '/')) != NULL)
+               *slash = '\0';
+
+       ret = 0;
+
+err:
+       kernel_fini();
+       return (ret);
+}
+
+int
+translate_raw(const char *str, zinject_record_t *record)
+{
+       /*
+        * A raw bookmark of the form objset:object:level:blkid, where each
+        * number is a hexidecimal value.
+        */
+       if (sscanf(str, "%llx:%llx:%x:%llx", (u_longlong_t *)&record->zi_objset,
+           (u_longlong_t *)&record->zi_object, &record->zi_level,
+           (u_longlong_t *)&record->zi_start) != 4) {
+               (void) fprintf(stderr, "bad raw spec '%s': must be of the form "
+                   "'objset:object:level:blkid'\n", str);
+               return (-1);
+       }
+
+       record->zi_end = record->zi_start;
+
+       return (0);
+}
+
+int
+translate_device(const char *pool, const char *device, err_type_t label_type,
+    zinject_record_t *record)
+{
+       char *end;
+       zpool_handle_t *zhp;
+       nvlist_t *tgt;
+       boolean_t isspare, iscache;
+
+       /*
+        * Given a device name or GUID, create an appropriate injection record
+        * with zi_guid set.
+        */
+       if ((zhp = zpool_open(g_zfs, pool)) == NULL)
+               return (-1);
+
+       record->zi_guid = strtoull(device, &end, 0);
+       if (record->zi_guid == 0 || *end != '\0') {
+               tgt = zpool_find_vdev(zhp, device, &isspare, &iscache, NULL);
+
+               if (tgt == NULL) {
+                       (void) fprintf(stderr, "cannot find device '%s' in "
+                           "pool '%s'\n", device, pool);
+                       zpool_close(zhp);
+                       return (-1);
+               }
+
+               verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
+                   &record->zi_guid) == 0);
+       }
+
+       /*
+        * Device faults can take on three different forms:
+        * 1). delayed or hanging I/O
+        * 2). zfs label faults
+        * 3). generic disk faults
+        */
+       if (record->zi_timer != 0) {
+               record->zi_cmd = ZINJECT_DELAY_IO;
+       } else if (label_type != TYPE_INVAL) {
+               record->zi_cmd = ZINJECT_LABEL_FAULT;
+       } else {
+               record->zi_cmd = ZINJECT_DEVICE_FAULT;
+       }
+
+       switch (label_type) {
+       default:
+               break;
+       case TYPE_LABEL_UBERBLOCK:
+               record->zi_start = offsetof(vdev_label_t, vl_uberblock[0]);
+               record->zi_end = record->zi_start + VDEV_UBERBLOCK_RING - 1;
+               break;
+       case TYPE_LABEL_NVLIST:
+               record->zi_start = offsetof(vdev_label_t, vl_vdev_phys);
+               record->zi_end = record->zi_start + VDEV_PHYS_SIZE - 1;
+               break;
+       case TYPE_LABEL_PAD1:
+               record->zi_start = offsetof(vdev_label_t, vl_pad1);
+               record->zi_end = record->zi_start + VDEV_PAD_SIZE - 1;
+               break;
+       case TYPE_LABEL_PAD2:
+               record->zi_start = offsetof(vdev_label_t, vl_pad2);
+               record->zi_end = record->zi_start + VDEV_PAD_SIZE - 1;
+               break;
+       }
+       zpool_close(zhp);
+       return (0);
+}
diff --git a/zfs/cmd/zinject/zinject.c b/zfs/cmd/zinject/zinject.c
new file mode 100644 (file)
index 0000000..396c52a
--- /dev/null
@@ -0,0 +1,1128 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ */
+
+/*
+ * ZFS Fault Injector
+ *
+ * This userland component takes a set of options and uses libzpool to translate
+ * from a user-visible object type and name to an internal representation.
+ * There are two basic types of faults: device faults and data faults.
+ *
+ *
+ * DEVICE FAULTS
+ *
+ * Errors can be injected into a particular vdev using the '-d' option.  This
+ * option takes a path or vdev GUID to uniquely identify the device within a
+ * pool.  There are two types of errors that can be injected, EIO and ENXIO,
+ * that can be controlled through the '-e' option.  The default is ENXIO.  For
+ * EIO failures, any attempt to read data from the device will return EIO, but
+ * subsequent attempt to reopen the device will succeed.  For ENXIO failures,
+ * any attempt to read from the device will return EIO, but any attempt to
+ * reopen the device will also return ENXIO.
+ * For label faults, the -L option must be specified. This allows faults
+ * to be injected into either the nvlist, uberblock, pad1, or pad2 region
+ * of all the labels for the specified device.
+ *
+ * This form of the command looks like:
+ *
+ *     zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
+ *
+ *
+ * DATA FAULTS
+ *
+ * We begin with a tuple of the form:
+ *
+ *     <type,level,range,object>
+ *
+ *     type    A string describing the type of data to target.  Each type
+ *             implicitly describes how to interpret 'object'. Currently,
+ *             the following values are supported:
+ *
+ *             data            User data for a file
+ *             dnode           Dnode for a file or directory
+ *
+ *             The following MOS objects are special.  Instead of injecting
+ *             errors on a particular object or blkid, we inject errors across
+ *             all objects of the given type.
+ *
+ *             mos             Any data in the MOS
+ *             mosdir          object directory
+ *             config          pool configuration
+ *             bpobj           blkptr list
+ *             spacemap        spacemap
+ *             metaslab        metaslab
+ *             errlog          persistent error log
+ *
+ *     level   Object level.  Defaults to '0', not applicable to all types.  If
+ *             a range is given, this corresponds to the indirect block
+ *             corresponding to the specific range.
+ *
+ *     range   A numerical range [start,end) within the object.  Defaults to
+ *             the full size of the file.
+ *
+ *     object  A string describing the logical location of the object.  For
+ *             files and directories (currently the only supported types),
+ *             this is the path of the object on disk.
+ *
+ * This is translated, via libzpool, into the following internal representation:
+ *
+ *     <type,objset,object,level,range>
+ *
+ * These types should be self-explanatory.  This tuple is then passed to the
+ * kernel via a special ioctl() to initiate fault injection for the given
+ * object.  Note that 'type' is not strictly necessary for fault injection, but
+ * is used when translating existing faults into a human-readable string.
+ *
+ *
+ * The command itself takes one of the forms:
+ *
+ *     zinject
+ *     zinject <-a | -u pool>
+ *     zinject -c <id|all>
+ *     zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
+ *         [-r range] <object>
+ *     zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
+ *
+ * With no arguments, the command prints all currently registered injection
+ * handlers, with their numeric identifiers.
+ *
+ * The '-c' option will clear the given handler, or all handlers if 'all' is
+ * specified.
+ *
+ * The '-e' option takes a string describing the errno to simulate.  This must
+ * be either 'io' or 'checksum'.  In most cases this will result in the same
+ * behavior, but RAID-Z will produce a different set of ereports for this
+ * situation.
+ *
+ * The '-a', '-u', and '-m' flags toggle internal flush behavior.  If '-a' is
+ * specified, then the ARC cache is flushed appropriately.  If '-u' is
+ * specified, then the underlying SPA is unloaded.  Either of these flags can be
+ * specified independently of any other handlers.  The '-m' flag automatically
+ * does an unmount and remount of the underlying dataset to aid in flushing the
+ * cache.
+ *
+ * The '-f' flag controls the frequency of errors injected, expressed as a
+ * integer percentage between 1 and 100.  The default is 100.
+ *
+ * The this form is responsible for actually injecting the handler into the
+ * framework.  It takes the arguments described above, translates them to the
+ * internal tuple using libzpool, and then issues an ioctl() to register the
+ * handler.
+ *
+ * The final form can target a specific bookmark, regardless of whether a
+ * human-readable interface has been designed.  It allows developers to specify
+ * a particular block by number.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <sys/fs/zfs.h>
+#include <sys/mount.h>
+
+#include <libzfs.h>
+
+#undef verify  /* both libzfs.h and zfs_context.h want to define this */
+
+#include "zinject.h"
+
+libzfs_handle_t *g_zfs;
+int zfs_fd;
+
+#define        ECKSUM  EBADE
+
+static const char *errtable[TYPE_INVAL] = {
+       "data",
+       "dnode",
+       "mos",
+       "mosdir",
+       "metaslab",
+       "config",
+       "bpobj",
+       "spacemap",
+       "errlog",
+       "uber",
+       "nvlist",
+       "pad1",
+       "pad2"
+};
+
+static err_type_t
+name_to_type(const char *arg)
+{
+       int i;
+       for (i = 0; i < TYPE_INVAL; i++)
+               if (strcmp(errtable[i], arg) == 0)
+                       return (i);
+
+       return (TYPE_INVAL);
+}
+
+static const char *
+type_to_name(uint64_t type)
+{
+       switch (type) {
+       case DMU_OT_OBJECT_DIRECTORY:
+               return ("mosdir");
+       case DMU_OT_OBJECT_ARRAY:
+               return ("metaslab");
+       case DMU_OT_PACKED_NVLIST:
+               return ("config");
+       case DMU_OT_BPOBJ:
+               return ("bpobj");
+       case DMU_OT_SPACE_MAP:
+               return ("spacemap");
+       case DMU_OT_ERROR_LOG:
+               return ("errlog");
+       default:
+               return ("-");
+       }
+}
+
+
+/*
+ * Print usage message.
+ */
+void
+usage(void)
+{
+       (void) printf(
+           "usage:\n"
+           "\n"
+           "\tzinject\n"
+           "\n"
+           "\t\tList all active injection records.\n"
+           "\n"
+           "\tzinject -c <id|all>\n"
+           "\n"
+           "\t\tClear the particular record (if given a numeric ID), or\n"
+           "\t\tall records if 'all' is specified.\n"
+           "\n"
+           "\tzinject -p <function name> pool\n"
+           "\t\tInject a panic fault at the specified function. Only \n"
+           "\t\tfunctions which call spa_vdev_config_exit(), or \n"
+           "\t\tspa_vdev_exit() will trigger a panic.\n"
+           "\n"
+           "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
+           "\t    [-T <read|write|free|claim|all> pool\n"
+           "\t\tInject a fault into a particular device or the device's\n"
+           "\t\tlabel.  Label injection can either be 'nvlist', 'uber',\n "
+           "\t\t'pad1', or 'pad2'.\n"
+           "\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n"
+           "\n"
+           "\tzinject -d device -A <degrade|fault> -D <delay secs> pool\n"
+           "\t\tPerform a specific action on a particular device.\n"
+           "\n"
+           "\tzinject -d device -D latency:lanes pool\n"
+           "\n"
+           "\t\tAdd an artificial delay to IO requests on a particular\n"
+           "\t\tdevice, such that the requests take a minimum of 'latency'\n"
+           "\t\tmilliseconds to complete. Each delay has an associated\n"
+           "\t\tnumber of 'lanes' which defines the number of concurrent\n"
+           "\t\tIO requests that can be processed.\n"
+           "\n"
+           "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
+           "\t\tthe device will only be able to service a single IO request\n"
+           "\t\tat a time with each request taking 10 ms to complete. So,\n"
+           "\t\tif only a single request is submitted every 10 ms, the\n"
+           "\t\taverage latency will be 10 ms; but if more than one request\n"
+           "\t\tis submitted every 10 ms, the average latency will be more\n"
+           "\t\tthan 10 ms.\n"
+           "\n"
+           "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
+           "\t\tlanes (-D 10:2), then the device will be able to service\n"
+           "\t\ttwo requests at a time, each with a minimum latency of\n"
+           "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
+           "\t\tthe average latency will be 10 ms; but if more than two\n"
+           "\t\trequests are submitted every 10 ms, the average latency\n"
+           "\t\twill be more than 10 ms.\n"
+           "\n"
+           "\t\tAlso note, these delays are additive. So two invocations\n"
+           "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
+           "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
+           "\t\tlanes with differing target latencies. For example, an\n"
+           "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
+           "\t\tcreate 3 lanes on the device; one lane with a latency\n"
+           "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
+           "\n"
+           "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
+           "\t\tCause the pool to stop writing blocks yet not\n"
+           "\t\treport errors for a duration.  Simulates buggy hardware\n"
+           "\t\tthat fails to honor cache flush requests.\n"
+           "\t\tDefault duration is 30 seconds.  The machine is panicked\n"
+           "\t\tat the end of the duration.\n"
+           "\n"
+           "\tzinject -b objset:object:level:blkid pool\n"
+           "\n"
+           "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
+           "\t\tspecified by the remaining tuple.  Each number is in\n"
+           "\t\thexidecimal, and only one block can be specified.\n"
+           "\n"
+           "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n"
+           "\t    [-a] [-m] [-u] [-f freq] <object>\n"
+           "\n"
+           "\t\tInject an error into the object specified by the '-t' option\n"
+           "\t\tand the object descriptor.  The 'object' parameter is\n"
+           "\t\tinterpreted depending on the '-t' option.\n"
+           "\n"
+           "\t\t-q\tQuiet mode.  Only print out the handler number added.\n"
+           "\t\t-e\tInject a specific error.  Must be either 'io' or\n"
+           "\t\t\t'checksum'.  Default is 'io'.\n"
+           "\t\t-l\tInject error at a particular block level. Default is "
+           "0.\n"
+           "\t\t-m\tAutomatically remount underlying filesystem.\n"
+           "\t\t-r\tInject error over a particular logical range of an\n"
+           "\t\t\tobject.  Will be translated to the appropriate blkid\n"
+           "\t\t\trange according to the object's properties.\n"
+           "\t\t-a\tFlush the ARC cache.  Can be specified without any\n"
+           "\t\t\tassociated object.\n"
+           "\t\t-u\tUnload the associated pool.  Can be specified with only\n"
+           "\t\t\ta pool object.\n"
+           "\t\t-f\tOnly inject errors a fraction of the time.  Expressed as\n"
+           "\t\t\ta percentage between 1 and 100.\n"
+           "\n"
+           "\t-t data\t\tInject an error into the plain file contents of a\n"
+           "\t\t\tfile.  The object must be specified as a complete path\n"
+           "\t\t\tto a file on a ZFS filesystem.\n"
+           "\n"
+           "\t-t dnode\tInject an error into the metadnode in the block\n"
+           "\t\t\tcorresponding to the dnode for a file or directory.  The\n"
+           "\t\t\t'-r' option is incompatible with this mode.  The object\n"
+           "\t\t\tis specified as a complete path to a file or directory\n"
+           "\t\t\ton a ZFS filesystem.\n"
+           "\n"
+           "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
+           "\t\t\ttype.  Valid types are: mos, mosdir, config, bpobj,\n"
+           "\t\t\tspacemap, metaslab, errlog.  The only valid <object> is\n"
+           "\t\t\tthe poolname.\n");
+}
+
+static int
+iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
+    void *data)
+{
+       zfs_cmd_t zc = {"\0"};
+       int ret;
+
+       while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
+               if ((ret = func((int)zc.zc_guid, zc.zc_name,
+                   &zc.zc_inject_record, data)) != 0)
+                       return (ret);
+
+       if (errno != ENOENT) {
+               (void) fprintf(stderr, "Unable to list handlers: %s\n",
+                   strerror(errno));
+               return (-1);
+       }
+
+       return (0);
+}
+
+static int
+print_data_handler(int id, const char *pool, zinject_record_t *record,
+    void *data)
+{
+       int *count = data;
+
+       if (record->zi_guid != 0 || record->zi_func[0] != '\0')
+               return (0);
+
+       if (*count == 0) {
+               (void) printf("%3s  %-15s  %-6s  %-6s  %-8s  %3s  %-15s\n",
+                   "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL",  "RANGE");
+               (void) printf("---  ---------------  ------  "
+                   "------  --------  ---  ---------------\n");
+       }
+
+       *count += 1;
+
+       (void) printf("%3d  %-15s  %-6llu  %-6llu  %-8s  %3d  ", id, pool,
+           (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object,
+           type_to_name(record->zi_type), record->zi_level);
+
+       if (record->zi_start == 0 &&
+           record->zi_end == -1ULL)
+               (void) printf("all\n");
+       else
+               (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
+                   (u_longlong_t)record->zi_end);
+
+       return (0);
+}
+
+static int
+print_device_handler(int id, const char *pool, zinject_record_t *record,
+    void *data)
+{
+       int *count = data;
+
+       if (record->zi_guid == 0 || record->zi_func[0] != '\0')
+               return (0);
+
+       if (record->zi_cmd == ZINJECT_DELAY_IO)
+               return (0);
+
+       if (*count == 0) {
+               (void) printf("%3s  %-15s  %s\n", "ID", "POOL", "GUID");
+               (void) printf("---  ---------------  ----------------\n");
+       }
+
+       *count += 1;
+
+       (void) printf("%3d  %-15s  %llx\n", id, pool,
+           (u_longlong_t)record->zi_guid);
+
+       return (0);
+}
+
+static int
+print_delay_handler(int id, const char *pool, zinject_record_t *record,
+    void *data)
+{
+       int *count = data;
+
+       if (record->zi_guid == 0 || record->zi_func[0] != '\0')
+               return (0);
+
+       if (record->zi_cmd != ZINJECT_DELAY_IO)
+               return (0);
+
+       if (*count == 0) {
+               (void) printf("%3s  %-15s  %-15s  %-15s  %s\n",
+                   "ID", "POOL", "DELAY (ms)", "LANES", "GUID");
+               (void) printf("---  ---------------  ---------------  "
+                   "---------------  ----------------\n");
+       }
+
+       *count += 1;
+
+       (void) printf("%3d  %-15s  %-15llu  %-15llu  %llx\n", id, pool,
+           (u_longlong_t)NSEC2MSEC(record->zi_timer),
+           (u_longlong_t)record->zi_nlanes,
+           (u_longlong_t)record->zi_guid);
+
+       return (0);
+}
+
+static int
+print_panic_handler(int id, const char *pool, zinject_record_t *record,
+    void *data)
+{
+       int *count = data;
+
+       if (record->zi_func[0] == '\0')
+               return (0);
+
+       if (*count == 0) {
+               (void) printf("%3s  %-15s  %s\n", "ID", "POOL", "FUNCTION");
+               (void) printf("---  ---------------  ----------------\n");
+       }
+
+       *count += 1;
+
+       (void) printf("%3d  %-15s  %s\n", id, pool, record->zi_func);
+
+       return (0);
+}
+
+/*
+ * Print all registered error handlers.  Returns the number of handlers
+ * registered.
+ */
+static int
+print_all_handlers(void)
+{
+       int count = 0, total = 0;
+
+       (void) iter_handlers(print_device_handler, &count);
+       if (count > 0) {
+               total += count;
+               (void) printf("\n");
+               count = 0;
+       }
+
+       (void) iter_handlers(print_delay_handler, &count);
+       if (count > 0) {
+               total += count;
+               (void) printf("\n");
+               count = 0;
+       }
+
+       (void) iter_handlers(print_data_handler, &count);
+       if (count > 0) {
+               total += count;
+               (void) printf("\n");
+               count = 0;
+       }
+
+       (void) iter_handlers(print_panic_handler, &count);
+
+       return (count + total);
+}
+
+/* ARGSUSED */
+static int
+cancel_one_handler(int id, const char *pool, zinject_record_t *record,
+    void *data)
+{
+       zfs_cmd_t zc = {"\0"};
+
+       zc.zc_guid = (uint64_t)id;
+
+       if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
+               (void) fprintf(stderr, "failed to remove handler %d: %s\n",
+                   id, strerror(errno));
+               return (1);
+       }
+
+       return (0);
+}
+
+/*
+ * Remove all fault injection handlers.
+ */
+static int
+cancel_all_handlers(void)
+{
+       int ret = iter_handlers(cancel_one_handler, NULL);
+
+       if (ret == 0)
+               (void) printf("removed all registered handlers\n");
+
+       return (ret);
+}
+
+/*
+ * Remove a specific fault injection handler.
+ */
+static int
+cancel_handler(int id)
+{
+       zfs_cmd_t zc = {"\0"};
+
+       zc.zc_guid = (uint64_t)id;
+
+       if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
+               (void) fprintf(stderr, "failed to remove handler %d: %s\n",
+                   id, strerror(errno));
+               return (1);
+       }
+
+       (void) printf("removed handler %d\n", id);
+
+       return (0);
+}
+
+/*
+ * Register a new fault injection handler.
+ */
+static int
+register_handler(const char *pool, int flags, zinject_record_t *record,
+    int quiet)
+{
+       zfs_cmd_t zc = {"\0"};
+
+       (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
+       zc.zc_inject_record = *record;
+       zc.zc_guid = flags;
+
+       if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
+               (void) fprintf(stderr, "failed to add handler: %s\n",
+                   strerror(errno));
+               return (1);
+       }
+
+       if (flags & ZINJECT_NULL)
+               return (0);
+
+       if (quiet) {
+               (void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
+       } else {
+               (void) printf("Added handler %llu with the following "
+                   "properties:\n", (u_longlong_t)zc.zc_guid);
+               (void) printf("  pool: %s\n", pool);
+               if (record->zi_guid) {
+                       (void) printf("  vdev: %llx\n",
+                           (u_longlong_t)record->zi_guid);
+               } else if (record->zi_func[0] != '\0') {
+                       (void) printf("  panic function: %s\n",
+                           record->zi_func);
+               } else if (record->zi_duration > 0) {
+                       (void) printf(" time: %lld seconds\n",
+                           (u_longlong_t)record->zi_duration);
+               } else if (record->zi_duration < 0) {
+                       (void) printf(" txgs: %lld \n",
+                           (u_longlong_t)-record->zi_duration);
+               } else {
+                       (void) printf("objset: %llu\n",
+                           (u_longlong_t)record->zi_objset);
+                       (void) printf("object: %llu\n",
+                           (u_longlong_t)record->zi_object);
+                       (void) printf("  type: %llu\n",
+                           (u_longlong_t)record->zi_type);
+                       (void) printf(" level: %d\n", record->zi_level);
+                       if (record->zi_start == 0 &&
+                           record->zi_end == -1ULL)
+                               (void) printf(" range: all\n");
+                       else
+                               (void) printf(" range: [%llu, %llu)\n",
+                                   (u_longlong_t)record->zi_start,
+                                   (u_longlong_t)record->zi_end);
+               }
+       }
+
+       return (0);
+}
+
+int
+perform_action(const char *pool, zinject_record_t *record, int cmd)
+{
+       zfs_cmd_t zc = {"\0"};
+
+       ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
+       (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
+       zc.zc_guid = record->zi_guid;
+       zc.zc_cookie = cmd;
+
+       if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+               return (0);
+
+       return (1);
+}
+
+static int
+parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
+{
+       unsigned long scan_delay;
+       unsigned long scan_nlanes;
+
+       if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
+               return (1);
+
+       /*
+        * We explicitly disallow a delay of zero here, because we key
+        * off this value being non-zero in translate_device(), to
+        * determine if the fault is a ZINJECT_DELAY_IO fault or not.
+        */
+       if (scan_delay == 0)
+               return (1);
+
+       /*
+        * The units for the CLI delay parameter is milliseconds, but
+        * the data passed to the kernel is interpreted as nanoseconds.
+        * Thus we scale the milliseconds to nanoseconds here, and this
+        * nanosecond value is used to pass the delay to the kernel.
+        */
+       *delay = MSEC2NSEC(scan_delay);
+       *nlanes = scan_nlanes;
+
+       return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+       int c;
+       char *range = NULL;
+       char *cancel = NULL;
+       char *end;
+       char *raw = NULL;
+       char *device = NULL;
+       int level = 0;
+       int quiet = 0;
+       int error = 0;
+       int domount = 0;
+       int io_type = ZIO_TYPES;
+       int action = VDEV_STATE_UNKNOWN;
+       err_type_t type = TYPE_INVAL;
+       err_type_t label = TYPE_INVAL;
+       zinject_record_t record = { 0 };
+       char pool[MAXNAMELEN] = "";
+       char dataset[MAXNAMELEN] = "";
+       zfs_handle_t *zhp = NULL;
+       int nowrites = 0;
+       int dur_txg = 0;
+       int dur_secs = 0;
+       int ret;
+       int flags = 0;
+
+       if ((g_zfs = libzfs_init()) == NULL) {
+               (void) fprintf(stderr, "%s", libzfs_error_init(errno));
+               return (1);
+       }
+
+       libzfs_print_on_error(g_zfs, B_TRUE);
+
+       if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
+               (void) fprintf(stderr, "failed to open ZFS device\n");
+               libzfs_fini(g_zfs);
+               return (1);
+       }
+
+       if (argc == 1) {
+               /*
+                * No arguments.  Print the available handlers.  If there are no
+                * available handlers, direct the user to '-h' for help
+                * information.
+                */
+               if (print_all_handlers() == 0) {
+                       (void) printf("No handlers registered.\n");
+                       (void) printf("Run 'zinject -h' for usage "
+                           "information.\n");
+               }
+               libzfs_fini(g_zfs);
+               return (0);
+       }
+
+       while ((c = getopt(argc, argv,
+           ":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
+               switch (c) {
+               case 'a':
+                       flags |= ZINJECT_FLUSH_ARC;
+                       break;
+               case 'A':
+                       if (strcasecmp(optarg, "degrade") == 0) {
+                               action = VDEV_STATE_DEGRADED;
+                       } else if (strcasecmp(optarg, "fault") == 0) {
+                               action = VDEV_STATE_FAULTED;
+                       } else {
+                               (void) fprintf(stderr, "invalid action '%s': "
+                                   "must be 'degrade' or 'fault'\n", optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case 'b':
+                       raw = optarg;
+                       break;
+               case 'c':
+                       cancel = optarg;
+                       break;
+               case 'd':
+                       device = optarg;
+                       break;
+               case 'D':
+                       errno = 0;
+                       ret = parse_delay(optarg, &record.zi_timer,
+                           &record.zi_nlanes);
+                       if (ret != 0) {
+
+                               (void) fprintf(stderr, "invalid i/o delay "
+                                   "value: '%s'\n", optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case 'e':
+                       if (strcasecmp(optarg, "io") == 0) {
+                               error = EIO;
+                       } else if (strcasecmp(optarg, "checksum") == 0) {
+                               error = ECKSUM;
+                       } else if (strcasecmp(optarg, "nxio") == 0) {
+                               error = ENXIO;
+                       } else if (strcasecmp(optarg, "dtl") == 0) {
+                               error = ECHILD;
+                       } else {
+                               (void) fprintf(stderr, "invalid error type "
+                                   "'%s': must be 'io', 'checksum' or "
+                                   "'nxio'\n", optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case 'f':
+                       record.zi_freq = atoi(optarg);
+                       if (record.zi_freq < 1 || record.zi_freq > 100) {
+                               (void) fprintf(stderr, "frequency range must "
+                                   "be in the range (0, 100]\n");
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case 'F':
+                       record.zi_failfast = B_TRUE;
+                       break;
+               case 'g':
+                       dur_txg = 1;
+                       record.zi_duration = (int)strtol(optarg, &end, 10);
+                       if (record.zi_duration <= 0 || *end != '\0') {
+                               (void) fprintf(stderr, "invalid duration '%s': "
+                                   "must be a positive integer\n", optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       /* store duration of txgs as its negative */
+                       record.zi_duration *= -1;
+                       break;
+               case 'h':
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (0);
+               case 'I':
+                       /* default duration, if one hasn't yet been defined */
+                       nowrites = 1;
+                       if (dur_secs == 0 && dur_txg == 0)
+                               record.zi_duration = 30;
+                       break;
+               case 'l':
+                       level = (int)strtol(optarg, &end, 10);
+                       if (*end != '\0') {
+                               (void) fprintf(stderr, "invalid level '%s': "
+                                   "must be an integer\n", optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case 'm':
+                       domount = 1;
+                       break;
+               case 'p':
+                       (void) strlcpy(record.zi_func, optarg,
+                           sizeof (record.zi_func));
+                       record.zi_cmd = ZINJECT_PANIC;
+                       break;
+               case 'q':
+                       quiet = 1;
+                       break;
+               case 'r':
+                       range = optarg;
+                       break;
+               case 's':
+                       dur_secs = 1;
+                       record.zi_duration = (int)strtol(optarg, &end, 10);
+                       if (record.zi_duration <= 0 || *end != '\0') {
+                               (void) fprintf(stderr, "invalid duration '%s': "
+                                   "must be a positive integer\n", optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case 'T':
+                       if (strcasecmp(optarg, "read") == 0) {
+                               io_type = ZIO_TYPE_READ;
+                       } else if (strcasecmp(optarg, "write") == 0) {
+                               io_type = ZIO_TYPE_WRITE;
+                       } else if (strcasecmp(optarg, "free") == 0) {
+                               io_type = ZIO_TYPE_FREE;
+                       } else if (strcasecmp(optarg, "claim") == 0) {
+                               io_type = ZIO_TYPE_CLAIM;
+                       } else if (strcasecmp(optarg, "all") == 0) {
+                               io_type = ZIO_TYPES;
+                       } else {
+                               (void) fprintf(stderr, "invalid I/O type "
+                                   "'%s': must be 'read', 'write', 'free', "
+                                   "'claim' or 'all'\n", optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case 't':
+                       if ((type = name_to_type(optarg)) == TYPE_INVAL &&
+                           !MOS_TYPE(type)) {
+                               (void) fprintf(stderr, "invalid type '%s'\n",
+                                   optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case 'u':
+                       flags |= ZINJECT_UNLOAD_SPA;
+                       break;
+               case 'L':
+                       if ((label = name_to_type(optarg)) == TYPE_INVAL &&
+                           !LABEL_TYPE(type)) {
+                               (void) fprintf(stderr, "invalid label type "
+                                   "'%s'\n", optarg);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       break;
+               case ':':
+                       (void) fprintf(stderr, "option -%c requires an "
+                           "operand\n", optopt);
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (1);
+               case '?':
+                       (void) fprintf(stderr, "invalid option '%c'\n",
+                           optopt);
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (record.zi_duration != 0)
+               record.zi_cmd = ZINJECT_IGNORED_WRITES;
+
+       if (cancel != NULL) {
+               /*
+                * '-c' is invalid with any other options.
+                */
+               if (raw != NULL || range != NULL || type != TYPE_INVAL ||
+                   level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
+                       (void) fprintf(stderr, "cancel (-c) incompatible with "
+                           "any other options\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+               if (argc != 0) {
+                       (void) fprintf(stderr, "extraneous argument to '-c'\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               if (strcmp(cancel, "all") == 0) {
+                       return (cancel_all_handlers());
+               } else {
+                       int id = (int)strtol(cancel, &end, 10);
+                       if (*end != '\0') {
+                               (void) fprintf(stderr, "invalid handle id '%s':"
+                                   " must be an integer or 'all'\n", cancel);
+                               usage();
+                               libzfs_fini(g_zfs);
+                               return (1);
+                       }
+                       return (cancel_handler(id));
+               }
+       }
+
+       if (device != NULL) {
+               /*
+                * Device (-d) injection uses a completely different mechanism
+                * for doing injection, so handle it separately here.
+                */
+               if (raw != NULL || range != NULL || type != TYPE_INVAL ||
+                   level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
+                       (void) fprintf(stderr, "device (-d) incompatible with "
+                           "data error injection\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               if (argc != 1) {
+                       (void) fprintf(stderr, "device (-d) injection requires "
+                           "a single pool name\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               (void) strlcpy(pool, argv[0], sizeof (pool));
+               dataset[0] = '\0';
+
+               if (error == ECKSUM) {
+                       (void) fprintf(stderr, "device error type must be "
+                           "'io' or 'nxio'\n");
+                       libzfs_fini(g_zfs);
+                       return (1);
+               }
+
+               record.zi_iotype = io_type;
+               if (translate_device(pool, device, label, &record) != 0) {
+                       libzfs_fini(g_zfs);
+                       return (1);
+               }
+               if (!error)
+                       error = ENXIO;
+
+               if (action != VDEV_STATE_UNKNOWN)
+                       return (perform_action(pool, &record, action));
+
+       } else if (raw != NULL) {
+               if (range != NULL || type != TYPE_INVAL || level != 0 ||
+                   record.zi_cmd != ZINJECT_UNINITIALIZED) {
+                       (void) fprintf(stderr, "raw (-b) format with "
+                           "any other options\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               if (argc != 1) {
+                       (void) fprintf(stderr, "raw (-b) format expects a "
+                           "single pool name\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               (void) strlcpy(pool, argv[0], sizeof (pool));
+               dataset[0] = '\0';
+
+               if (error == ENXIO) {
+                       (void) fprintf(stderr, "data error type must be "
+                           "'checksum' or 'io'\n");
+                       libzfs_fini(g_zfs);
+                       return (1);
+               }
+
+               record.zi_cmd = ZINJECT_DATA_FAULT;
+               if (translate_raw(raw, &record) != 0) {
+                       libzfs_fini(g_zfs);
+                       return (1);
+               }
+               if (!error)
+                       error = EIO;
+       } else if (record.zi_cmd == ZINJECT_PANIC) {
+               if (raw != NULL || range != NULL || type != TYPE_INVAL ||
+                   level != 0 || device != NULL) {
+                       (void) fprintf(stderr, "panic (-p) incompatible with "
+                           "other options\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               if (argc < 1 || argc > 2) {
+                       (void) fprintf(stderr, "panic (-p) injection requires "
+                           "a single pool name and an optional id\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               (void) strlcpy(pool, argv[0], sizeof (pool));
+               if (argv[1] != NULL)
+                       record.zi_type = atoi(argv[1]);
+               dataset[0] = '\0';
+       } else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
+               if (nowrites == 0) {
+                       (void) fprintf(stderr, "-s or -g meaningless "
+                           "without -I (ignore writes)\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               } else if (dur_secs && dur_txg) {
+                       (void) fprintf(stderr, "choose a duration either "
+                           "in seconds (-s) or a number of txgs (-g) "
+                           "but not both\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               } else if (argc != 1) {
+                       (void) fprintf(stderr, "ignore writes (-I) "
+                           "injection requires a single pool name\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               (void) strlcpy(pool, argv[0], sizeof (pool));
+               dataset[0] = '\0';
+       } else if (type == TYPE_INVAL) {
+               if (flags == 0) {
+                       (void) fprintf(stderr, "at least one of '-b', '-d', "
+                           "'-t', '-a', '-p', '-I' or '-u' "
+                           "must be specified\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
+                       (void) strlcpy(pool, argv[0], sizeof (pool));
+                       dataset[0] = '\0';
+               } else if (argc != 0) {
+                       (void) fprintf(stderr, "extraneous argument for "
+                           "'-f'\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               flags |= ZINJECT_NULL;
+       } else {
+               if (argc != 1) {
+                       (void) fprintf(stderr, "missing object\n");
+                       usage();
+                       libzfs_fini(g_zfs);
+                       return (2);
+               }
+
+               if (error == ENXIO) {
+                       (void) fprintf(stderr, "data error type must be "
+                           "'checksum' or 'io'\n");
+                       libzfs_fini(g_zfs);
+                       return (1);
+               }
+
+               record.zi_cmd = ZINJECT_DATA_FAULT;
+               if (translate_record(type, argv[0], range, level, &record, pool,
+                   dataset) != 0) {
+                   libzfs_fini(g_zfs);
+                       return (1);
+               }
+               if (!error)
+                       error = EIO;
+       }
+
+       /*
+        * If this is pool-wide metadata, unmount everything.  The ioctl() will
+        * unload the pool, so that we trigger spa-wide reopen of metadata next
+        * time we access the pool.
+        */
+       if (dataset[0] != '\0' && domount) {
+               if ((zhp = zfs_open(g_zfs, dataset,
+                       ZFS_TYPE_DATASET)) == NULL) {
+                       libzfs_fini(g_zfs);
+                       return (1);
+               }
+               if (zfs_unmount(zhp, NULL, 0) != 0) {
+                       libzfs_fini(g_zfs);
+                       return (1);
+               }
+       }
+
+       record.zi_error = error;
+
+       ret = register_handler(pool, flags, &record, quiet);
+
+       if (dataset[0] != '\0' && domount)
+               ret = (zfs_mount(zhp, NULL, 0) != 0);
+
+       libzfs_fini(g_zfs);
+
+       return (ret);
+}
diff --git a/zfs/cmd/zinject/zinject.h b/zfs/cmd/zinject/zinject.h
new file mode 100644 (file)
index 0000000..46fdcad
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        _ZINJECT_H
+#define        _ZINJECT_H
+
+#include <sys/zfs_ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+       TYPE_DATA,              /* plain file contents          */
+       TYPE_DNODE,             /* metadnode contents           */
+       TYPE_MOS,               /* all MOS data                 */
+       TYPE_MOSDIR,            /* MOS object directory         */
+       TYPE_METASLAB,          /* metaslab objects             */
+       TYPE_CONFIG,            /* MOS config                   */
+       TYPE_BPOBJ,             /* block pointer list           */
+       TYPE_SPACEMAP,          /* space map objects            */
+       TYPE_ERRLOG,            /* persistent error log         */
+       TYPE_LABEL_UBERBLOCK,   /* label specific uberblock     */
+       TYPE_LABEL_NVLIST,      /* label specific nvlist        */
+       TYPE_LABEL_PAD1,        /* label specific 8K pad1 area  */
+       TYPE_LABEL_PAD2,        /* label specific 8K pad2 area  */
+       TYPE_INVAL
+} err_type_t;
+
+#define        MOS_TYPE(t)     \
+       ((t) >= TYPE_MOS && (t) < TYPE_LABEL_UBERBLOCK)
+
+#define        LABEL_TYPE(t)   \
+       ((t) >= TYPE_LABEL_UBERBLOCK && (t) < TYPE_INVAL)
+
+int translate_record(err_type_t type, const char *object, const char *range,
+    int level, zinject_record_t *record, char *poolname, char *dataset);
+int translate_raw(const char *raw, zinject_record_t *record);
+int translate_device(const char *pool, const char *device,
+    err_type_t label_type, zinject_record_t *record);
+void usage(void);
+
+extern libzfs_handle_t *g_zfs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZINJECT_H */
diff --git a/zfs/cmd/zpios/Makefile.am b/zfs/cmd/zpios/Makefile.am
new file mode 100644 (file)
index 0000000..9dabb65
--- /dev/null
@@ -0,0 +1,11 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include
+
+sbin_PROGRAMS = zpios
+
+zpios_SOURCES = \
+       zpios_main.c \
+       zpios_util.c \
+       zpios.h
diff --git a/zfs/cmd/zpios/Makefile.in b/zfs/cmd/zpios/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zpios/zpios.h b/zfs/cmd/zpios/zpios.h
new file mode 100644 (file)
index 0000000..4a69b9e
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *  ZPIOS is a heavily modified version of the original PIOS test code.
+ *  It is designed to have the test code running in the Linux kernel
+ *  against ZFS while still being flexibly controled from user space.
+ *
+ *  Copyright (C) 2008-2010 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  LLNL-CODE-403049
+ *
+ *  Original PIOS Test Code
+ *  Copyright (C) 2004 Cluster File Systems, Inc.
+ *  Written by Peter Braam <braam@clusterfs.com>
+ *             Atul Vidwansa <atul@clusterfs.com>
+ *             Milind Dumbare <milind@clusterfs.com>
+ *
+ *  This file is part of ZFS on Linux.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  ZPIOS is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  ZPIOS is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with ZPIOS.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Copyright (c) 2015, Intel Corporation.
+ */
+
+#ifndef _ZPIOS_H
+#define        _ZPIOS_H
+
+#include <zpios-ctl.h>
+
+#define        VERSION_SIZE            64
+
+/* Regular expressions */
+#define        REGEX_NUMBERS           "^[0-9]+$"
+#define        REGEX_NUMBERS_COMMA     "^([0-9]+,)*[0-9]+$"
+#define        REGEX_SIZE              "^[0-9]+[kKmMgGtT]?$"
+#define        REGEX_SIZE_COMMA        "^([0-9]+[kKmMgGtT]?,)*[0-9]+[kKmMgGtT]?$"
+
+/* Flags for low, high, incr */
+#define        FLAG_SET                0x01
+#define        FLAG_LOW                0x02
+#define        FLAG_HIGH               0x04
+#define        FLAG_INCR               0x08
+
+#define        TRUE                    1
+#define        FALSE                   0
+
+#define        KB                      (1024)
+#define        MB                      (KB * 1024)
+#define        GB                      (MB * 1024)
+#define        TB                      (GB * 1024)
+
+#define        KMGT_SIZE               16
+
+/*
+ * All offsets, sizes and counts can be passed to the application in
+ * multiple ways.
+ * 1. a value (stored in val[0], val_count will be 1)
+ * 2. a comma separated list of values (stored in val[], using val_count)
+ * 3. a range and block sizes, low, high, factor (val_count must be 0)
+ */
+typedef struct pios_range_repeat {
+       uint64_t val[32];               /* Comma sep array, or low, high, inc */
+       uint64_t val_count;             /* Num of values */
+       uint64_t val_low;
+       uint64_t val_high;
+       uint64_t val_inc_perc;
+       uint64_t next_val;              /* For multiple runs in get_next() */
+} range_repeat_t;
+
+typedef struct cmd_args {
+       range_repeat_t T;               /* Thread count */
+       range_repeat_t N;               /* Region count */
+       range_repeat_t O;               /* Offset count */
+       range_repeat_t C;               /* Chunksize */
+       range_repeat_t S;               /* Regionsize */
+       range_repeat_t B;               /* Blocksize */
+
+       const char *pool;               /* Pool */
+       const char *name;               /* Name */
+       uint32_t flags;                 /* Flags */
+       uint32_t block_size;            /* ZFS block size */
+       uint32_t io_type;               /* DMUIO only */
+       uint32_t verbose;               /* Verbose */
+       uint32_t human_readable;        /* Human readable output */
+
+       uint64_t regionnoise;           /* Region noise */
+       uint64_t chunknoise;            /* Chunk noise */
+       uint64_t thread_delay;          /* Thread delay */
+
+       char pre[ZPIOS_PATH_SIZE];      /* Pre-exec hook */
+       char post[ZPIOS_PATH_SIZE];     /* Post-exec hook */
+       char log[ZPIOS_PATH_SIZE];      /* Requested log dir */
+
+       /* Control */
+       int current_id;
+       uint64_t current_T;
+       uint64_t current_N;
+       uint64_t current_C;
+       uint64_t current_S;
+       uint64_t current_O;
+       uint64_t current_B;
+
+       uint32_t rc;
+} cmd_args_t;
+
+int set_count(char *pattern1, char *pattern2, range_repeat_t *range,
+    char *optarg, uint32_t *flags, char *arg);
+int set_lhi(char *pattern, range_repeat_t *range, char *optarg,
+    int flag, uint32_t *flag_thread, char *arg);
+int set_noise(uint64_t *noise, char *optarg, char *arg);
+int set_load_params(cmd_args_t *args, char *optarg);
+int check_mutual_exclusive_command_lines(uint32_t flag, char *arg);
+void print_stats_header(cmd_args_t *args);
+void print_stats(cmd_args_t *args, zpios_cmd_t *cmd);
+
+#endif /* _ZPIOS_H */
diff --git a/zfs/cmd/zpios/zpios_main.c b/zfs/cmd/zpios/zpios_main.c
new file mode 100644 (file)
index 0000000..9110488
--- /dev/null
@@ -0,0 +1,681 @@
+/*
+ *  ZPIOS is a heavily modified version of the original PIOS test code.
+ *  It is designed to have the test code running in the Linux kernel
+ *  against ZFS while still being flexibly controlled from user space.
+ *
+ *  Copyright (C) 2008-2010 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  LLNL-CODE-403049
+ *
+ *  Original PIOS Test Code
+ *  Copyright (C) 2004 Cluster File Systems, Inc.
+ *  Written by Peter Braam <braam@clusterfs.com>
+ *             Atul Vidwansa <atul@clusterfs.com>
+ *             Milind Dumbare <milind@clusterfs.com>
+ *
+ *  This file is part of ZFS on Linux.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  ZPIOS is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  ZPIOS is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with ZPIOS.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Copyright (c) 2015, Intel Corporation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include "zpios.h"
+
+static const char short_opt[] =
+       "t:l:h:e:n:i:j:k:o:m:q:r:c:a:b:g:s:A:B:C:"
+       "S:L:p:M:xP:R:G:I:N:T:VzOfHv?";
+static const struct option long_opt[] = {
+       {"threadcount",         required_argument,      0,      't' },
+       {"threadcount_low",     required_argument,      0,      'l' },
+       {"threadcount_high",    required_argument,      0,      'h' },
+       {"threadcount_incr",    required_argument,      0,      'e' },
+       {"regioncount",         required_argument,      0,      'n' },
+       {"regioncount_low",     required_argument,      0,      'i' },
+       {"regioncount_high",    required_argument,      0,      'j' },
+       {"regioncount_incr",    required_argument,      0,      'k' },
+       {"offset",              required_argument,      0,      'o' },
+       {"offset_low",          required_argument,      0,      'm' },
+       {"offset_high",         required_argument,      0,      'q' },
+       {"offset_incr",         required_argument,      0,      'r' },
+       {"chunksize",           required_argument,      0,      'c' },
+       {"chunksize_low",       required_argument,      0,      'a' },
+       {"chunksize_high",      required_argument,      0,      'b' },
+       {"chunksize_incr",      required_argument,      0,      'g' },
+       {"regionsize",          required_argument,      0,      's' },
+       {"regionsize_low",      required_argument,      0,      'A' },
+       {"regionsize_high",     required_argument,      0,      'B' },
+       {"regionsize_incr",     required_argument,      0,      'C' },
+       {"blocksize",           required_argument,      0,      'S' },
+       {"load",                required_argument,      0,      'L' },
+       {"pool",                required_argument,      0,      'p' },
+       {"name",                required_argument,      0,      'M' },
+       {"cleanup",             no_argument,            0,      'x' },
+       {"prerun",              required_argument,      0,      'P' },
+       {"postrun",             required_argument,      0,      'R' },
+       {"log",                 required_argument,      0,      'G' },
+       {"regionnoise",         required_argument,      0,      'I' },
+       {"chunknoise",          required_argument,      0,      'N' },
+       {"threaddelay",         required_argument,      0,      'T' },
+       {"verify",              no_argument,            0,      'V' },
+       {"zerocopy",            no_argument,            0,      'z' },
+       {"nowait",              no_argument,            0,      'O' },
+       {"noprefetch",          no_argument,            0,      'f' },
+       {"human-readable",      no_argument,            0,      'H' },
+       {"verbose",             no_argument,            0,      'v' },
+       {"help",                no_argument,            0,      '?' },
+       { 0,                    0,                      0,      0 },
+};
+
+static int zpiosctl_fd;                                /* Control file descriptor */
+static char zpios_version[VERSION_SIZE];       /* Kernel version string */
+static char *zpios_buffer = NULL;              /* Scratch space area */
+static int zpios_buffer_size = 0;              /* Scratch space size */
+
+static int
+usage(void)
+{
+       fprintf(stderr, "Usage: zpios\n");
+       fprintf(stderr,
+               "       --threadcount       -t    =values\n"
+               "       --threadcount_low   -l    =value\n"
+               "       --threadcount_high  -h    =value\n"
+               "       --threadcount_incr  -e    =value\n"
+               "       --regioncount       -n    =values\n"
+               "       --regioncount_low   -i    =value\n"
+               "       --regioncount_high  -j    =value\n"
+               "       --regioncount_incr  -k    =value\n"
+               "       --offset            -o    =values\n"
+               "       --offset_low        -m    =value\n"
+               "       --offset_high       -q    =value\n"
+               "       --offset_incr       -r    =value\n"
+               "       --chunksize         -c    =values\n"
+               "       --chunksize_low     -a    =value\n"
+               "       --chunksize_high    -b    =value\n"
+               "       --chunksize_incr    -g    =value\n"
+               "       --regionsize        -s    =values\n"
+               "       --regionsize_low    -A    =value\n"
+               "       --regionsize_high   -B    =value\n"
+               "       --regionsize_incr   -C    =value\n"
+               "       --blocksize         -S    =values\n"
+               "       --load              -L    =dmuio|ssf|fpp\n"
+               "       --pool              -p    =pool name\n"
+               "       --name              -M    =test name\n"
+               "       --cleanup           -x\n"
+               "       --prerun            -P    =pre-command\n"
+               "       --postrun           -R    =post-command\n"
+               "       --log               -G    =log directory\n"
+               "       --regionnoise       -I    =shift\n"
+               "       --chunknoise        -N    =bytes\n"
+               "       --threaddelay       -T    =jiffies\n"
+               "       --verify            -V\n"
+               "       --zerocopy          -z\n"
+               "       --nowait            -O\n"
+               "       --noprefetch        -f\n"
+               "       --human-readable    -H\n"
+               "       --verbose           -v    =increase verbosity\n"
+               "       --help              -?    =this help\n\n");
+
+       return (0);
+}
+
+static void args_fini(cmd_args_t *args)
+{
+       assert(args != NULL);
+       free(args);
+}
+
+/* block size is 128K to 16M, power of 2 */
+#define        MIN_BLKSIZE     (128ULL << 10)
+#define        MAX_BLKSIZE     (16ULL << 20)
+#define        POW_OF_TWO(x)   (((x) & ((x) - 1)) == 0)
+
+static cmd_args_t *
+args_init(int argc, char **argv)
+{
+       cmd_args_t *args;
+       uint32_t fl_th = 0;
+       uint32_t fl_rc = 0;
+       uint32_t fl_of = 0;
+       uint32_t fl_rs = 0;
+       uint32_t fl_cs = 0;
+       uint32_t fl_bs = 0;
+       int c, rc, i;
+
+       if (argc == 1) {
+               usage();
+               return ((cmd_args_t *)NULL);
+       }
+
+       /* Configure and populate the args structures */
+       args = malloc(sizeof (*args));
+       if (args == NULL)
+               return (NULL);
+
+       memset(args, 0, sizeof (*args));
+
+       /* provide a default block size of 128K */
+       args->B.next_val = 0;
+       args->B.val[0] = MIN_BLKSIZE;
+       args->B.val_count = 1;
+
+       while ((c = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1) {
+               rc = 0;
+
+               switch (c) {
+               case 't': /* --thread count */
+                       rc = set_count(REGEX_NUMBERS, REGEX_NUMBERS_COMMA,
+                           &args->T, optarg, &fl_th, "threadcount");
+                       break;
+               case 'l': /* --threadcount_low */
+                       rc = set_lhi(REGEX_NUMBERS, &args->T, optarg,
+                           FLAG_LOW, &fl_th, "threadcount_low");
+                       break;
+               case 'h': /* --threadcount_high */
+                       rc = set_lhi(REGEX_NUMBERS, &args->T, optarg,
+                           FLAG_HIGH, &fl_th, "threadcount_high");
+                       break;
+               case 'e': /* --threadcount_inc */
+                       rc = set_lhi(REGEX_NUMBERS, &args->T, optarg,
+                           FLAG_INCR, &fl_th, "threadcount_incr");
+                       break;
+               case 'n': /* --regioncount */
+                       rc = set_count(REGEX_NUMBERS, REGEX_NUMBERS_COMMA,
+                           &args->N, optarg, &fl_rc, "regioncount");
+                       break;
+               case 'i': /* --regioncount_low */
+                       rc = set_lhi(REGEX_NUMBERS, &args->N, optarg,
+                           FLAG_LOW, &fl_rc, "regioncount_low");
+                       break;
+               case 'j': /* --regioncount_high */
+                       rc = set_lhi(REGEX_NUMBERS, &args->N, optarg,
+                           FLAG_HIGH, &fl_rc, "regioncount_high");
+                       break;
+               case 'k': /* --regioncount_inc */
+                       rc = set_lhi(REGEX_NUMBERS, &args->N, optarg,
+                           FLAG_INCR, &fl_rc, "regioncount_incr");
+                       break;
+               case 'o': /* --offset */
+                       rc = set_count(REGEX_SIZE, REGEX_SIZE_COMMA,
+                           &args->O, optarg, &fl_of, "offset");
+                       break;
+               case 'm': /* --offset_low */
+                       rc = set_lhi(REGEX_SIZE, &args->O, optarg,
+                           FLAG_LOW, &fl_of, "offset_low");
+                       break;
+               case 'q': /* --offset_high */
+                       rc = set_lhi(REGEX_SIZE, &args->O, optarg,
+                           FLAG_HIGH, &fl_of, "offset_high");
+                       break;
+               case 'r': /* --offset_inc */
+                       rc = set_lhi(REGEX_NUMBERS, &args->O, optarg,
+                           FLAG_INCR, &fl_of, "offset_incr");
+                       break;
+               case 'c': /* --chunksize */
+                       rc = set_count(REGEX_SIZE, REGEX_SIZE_COMMA,
+                           &args->C, optarg, &fl_cs, "chunksize");
+                       break;
+               case 'a': /* --chunksize_low */
+                       rc = set_lhi(REGEX_SIZE, &args->C, optarg,
+                           FLAG_LOW, &fl_cs, "chunksize_low");
+                       break;
+               case 'b': /* --chunksize_high */
+                       rc = set_lhi(REGEX_SIZE, &args->C, optarg,
+                           FLAG_HIGH, &fl_cs, "chunksize_high");
+                       break;
+               case 'g': /* --chunksize_inc */
+                       rc = set_lhi(REGEX_NUMBERS, &args->C, optarg,
+                           FLAG_INCR, &fl_cs, "chunksize_incr");
+                       break;
+               case 's': /* --regionsize */
+                       rc = set_count(REGEX_SIZE, REGEX_SIZE_COMMA,
+                           &args->S, optarg, &fl_rs, "regionsize");
+                       break;
+               case 'A': /* --regionsize_low */
+                       rc = set_lhi(REGEX_SIZE, &args->S, optarg,
+                           FLAG_LOW, &fl_rs, "regionsize_low");
+                       break;
+               case 'B': /* --regionsize_high */
+                       rc = set_lhi(REGEX_SIZE, &args->S, optarg,
+                           FLAG_HIGH, &fl_rs, "regionsize_high");
+                       break;
+               case 'C': /* --regionsize_inc */
+                       rc = set_lhi(REGEX_NUMBERS, &args->S, optarg,
+                           FLAG_INCR, &fl_rs, "regionsize_incr");
+                       break;
+               case 'S': /* --blocksize */
+                       rc = set_count(REGEX_SIZE, REGEX_SIZE_COMMA,
+                           &args->B, optarg, &fl_bs, "blocksize");
+                       break;
+               case 'L': /* --load */
+                       rc = set_load_params(args, optarg);
+                       break;
+               case 'p': /* --pool */
+                       args->pool = optarg;
+                       break;
+               case 'M':
+                       args->name = optarg;
+                       break;
+               case 'x': /* --cleanup */
+                       args->flags |= DMU_REMOVE;
+                       break;
+               case 'P': /* --prerun */
+                       strncpy(args->pre, optarg, ZPIOS_PATH_SIZE - 1);
+                       break;
+               case 'R': /* --postrun */
+                       strncpy(args->post, optarg, ZPIOS_PATH_SIZE - 1);
+                       break;
+               case 'G': /* --log */
+                       strncpy(args->log, optarg, ZPIOS_PATH_SIZE - 1);
+                       break;
+               case 'I': /* --regionnoise */
+                       rc = set_noise(&args->regionnoise, optarg,
+                           "regionnoise");
+                       break;
+               case 'N': /* --chunknoise */
+                       rc = set_noise(&args->chunknoise, optarg, "chunknoise");
+                       break;
+               case 'T': /* --threaddelay */
+                       rc = set_noise(&args->thread_delay, optarg,
+                           "threaddelay");
+                       break;
+               case 'V': /* --verify */
+                       args->flags |= DMU_VERIFY;
+                       break;
+               case 'z': /* --zerocopy */
+                       args->flags |= (DMU_WRITE_ZC | DMU_READ_ZC);
+                       break;
+               case 'O': /* --nowait */
+                       args->flags |= DMU_WRITE_NOWAIT;
+                       break;
+               case 'f': /* --noprefetch */
+                       args->flags |= DMU_READ_NOPF;
+                       break;
+               case 'H': /* --human-readable */
+                       args->human_readable = 1;
+                       break;
+               case 'v': /* --verbose */
+                       args->verbose++;
+                       break;
+               case '?':
+                       rc = 1;
+                       break;
+               default:
+                       fprintf(stderr, "Unknown option '%s'\n",
+                           argv[optind - 1]);
+                       rc = EINVAL;
+                       break;
+               }
+
+               if (rc) {
+                       usage();
+                       args_fini(args);
+                       return (NULL);
+               }
+       }
+
+       check_mutual_exclusive_command_lines(fl_th, "threadcount");
+       check_mutual_exclusive_command_lines(fl_rc, "regioncount");
+       check_mutual_exclusive_command_lines(fl_of, "offset");
+       check_mutual_exclusive_command_lines(fl_rs, "regionsize");
+       check_mutual_exclusive_command_lines(fl_cs, "chunksize");
+
+       if (args->pool == NULL) {
+               fprintf(stderr, "Error: Pool not specified\n");
+               usage();
+               args_fini(args);
+               return (NULL);
+       }
+
+       if ((args->flags & (DMU_WRITE_ZC | DMU_READ_ZC)) &&
+           (args->flags & DMU_VERIFY)) {
+               fprintf(stderr, "Error, --zerocopy incompatible --verify, "
+                   "used for performance analysis only\n");
+               usage();
+               args_fini(args);
+               return (NULL);
+       }
+
+       /* validate block size(s) */
+       for (i = 0; i < args->B.val_count; i++) {
+               int bs = args->B.val[i];
+
+               if (bs < MIN_BLKSIZE || bs > MAX_BLKSIZE || !POW_OF_TWO(bs)) {
+                       fprintf(stderr, "Error: invalid block size %d\n", bs);
+                       args_fini(args);
+                       return (NULL);
+               }
+       }
+
+       return (args);
+}
+
+static int
+dev_clear(void)
+{
+       zpios_cfg_t cfg;
+       int rc;
+
+       memset(&cfg, 0, sizeof (cfg));
+       cfg.cfg_magic = ZPIOS_CFG_MAGIC;
+       cfg.cfg_cmd   = ZPIOS_CFG_BUFFER_CLEAR;
+       cfg.cfg_arg1  = 0;
+
+       rc = ioctl(zpiosctl_fd, ZPIOS_CFG, &cfg);
+       if (rc)
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                   (unsigned long) ZPIOS_CFG, cfg.cfg_cmd, errno);
+
+       (void) lseek(zpiosctl_fd, 0, SEEK_SET);
+
+       return (rc);
+}
+
+/* Passing a size of zero simply results in querying the current size */
+static int
+dev_size(int size)
+{
+       zpios_cfg_t cfg;
+       int rc;
+
+       memset(&cfg, 0, sizeof (cfg));
+       cfg.cfg_magic = ZPIOS_CFG_MAGIC;
+       cfg.cfg_cmd   = ZPIOS_CFG_BUFFER_SIZE;
+       cfg.cfg_arg1  = size;
+
+       rc = ioctl(zpiosctl_fd, ZPIOS_CFG, &cfg);
+       if (rc) {
+               fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
+                   (unsigned long) ZPIOS_CFG, cfg.cfg_cmd, errno);
+               return (rc);
+       }
+
+       return (cfg.cfg_rc1);
+}
+
+static void
+dev_fini(void)
+{
+       if (zpios_buffer)
+               free(zpios_buffer);
+
+       if (zpiosctl_fd != -1) {
+               if (close(zpiosctl_fd) == -1) {
+                       fprintf(stderr, "Unable to close %s: %d\n",
+                           ZPIOS_DEV, errno);
+               }
+       }
+}
+
+static int
+dev_init(void)
+{
+       int rc;
+
+       zpiosctl_fd = open(ZPIOS_DEV, O_RDONLY);
+       if (zpiosctl_fd == -1) {
+               fprintf(stderr, "Unable to open %s: %d\n"
+                   "Is the zpios module loaded?\n", ZPIOS_DEV, errno);
+               rc = errno;
+               goto error;
+       }
+
+       if ((rc = dev_clear()))
+               goto error;
+
+       if ((rc = dev_size(0)) < 0)
+               goto error;
+
+       zpios_buffer_size = rc;
+       zpios_buffer = (char *)malloc(zpios_buffer_size);
+       if (zpios_buffer == NULL) {
+               rc = ENOMEM;
+               goto error;
+       }
+
+       memset(zpios_buffer, 0, zpios_buffer_size);
+       return (0);
+error:
+       if (zpiosctl_fd != -1) {
+               if (close(zpiosctl_fd) == -1) {
+                       fprintf(stderr, "Unable to close %s: %d\n",
+                           ZPIOS_DEV, errno);
+               }
+       }
+
+       return (rc);
+}
+
+static int
+get_next(uint64_t *val, range_repeat_t *range)
+{
+       /* if low, incr, high is given */
+       if (range->val_count == 0) {
+               *val = (range->val_low) +
+                   (range->val_low * range->next_val / 100);
+
+               if (*val > range->val_high)
+                       return (0); /* No more values, limit exceeded */
+
+               if (!range->next_val)
+                       range->next_val = range->val_inc_perc;
+               else
+                       range->next_val = range->next_val + range->val_inc_perc;
+
+               return (1); /* more values to come */
+
+       /* if only one val is given */
+       } else if (range->val_count == 1) {
+               if (range->next_val)
+                       return (0); /* No more values, we only have one */
+
+               *val = range->val[0];
+               range->next_val = 1;
+               return (1); /* more values to come */
+
+       /* if comma separated values are given */
+       } else if (range->val_count > 1) {
+               if (range->next_val > range->val_count - 1)
+                       return (0); /* No more values, limit exceeded */
+
+               *val = range->val[range->next_val];
+               range->next_val++;
+               return (1); /* more values to come */
+       }
+
+       return (0);
+}
+
+static int
+run_one(cmd_args_t *args, uint32_t id, uint32_t T, uint32_t N,
+    uint64_t C, uint64_t S, uint64_t O, uint64_t B)
+{
+       zpios_cmd_t *cmd;
+       int rc, rc2, cmd_size;
+
+       dev_clear();
+
+       cmd_size =
+               sizeof (zpios_cmd_t)
+               + ((T + N + 1) * sizeof (zpios_stats_t));
+       cmd = (zpios_cmd_t *)malloc(cmd_size);
+       if (cmd == NULL)
+               return (ENOMEM);
+
+       memset(cmd, 0, cmd_size);
+       cmd->cmd_magic = ZPIOS_CMD_MAGIC;
+       strncpy(cmd->cmd_pool, args->pool, ZPIOS_NAME_SIZE - 1);
+       strncpy(cmd->cmd_pre, args->pre, ZPIOS_PATH_SIZE - 1);
+       strncpy(cmd->cmd_post, args->post, ZPIOS_PATH_SIZE - 1);
+       strncpy(cmd->cmd_log, args->log, ZPIOS_PATH_SIZE - 1);
+       cmd->cmd_id = id;
+       cmd->cmd_chunk_size = C;
+       cmd->cmd_thread_count = T;
+       cmd->cmd_region_count = N;
+       cmd->cmd_region_size = S;
+       cmd->cmd_offset = O;
+       cmd->cmd_block_size = B;
+       cmd->cmd_region_noise = args->regionnoise;
+       cmd->cmd_chunk_noise = args->chunknoise;
+       cmd->cmd_thread_delay = args->thread_delay;
+       cmd->cmd_flags = args->flags;
+       cmd->cmd_data_size = (T + N + 1) * sizeof (zpios_stats_t);
+
+       rc = ioctl(zpiosctl_fd, ZPIOS_CMD, cmd);
+       if (rc)
+               args->rc = errno;
+
+       print_stats(args, cmd);
+
+       if (args->verbose) {
+               rc2 = read(zpiosctl_fd, zpios_buffer, zpios_buffer_size);
+               zpios_buffer[zpios_buffer_size - 1] = '\0';
+               if (rc2 < 0) {
+                       fprintf(stdout, "Error reading results: %d\n", rc2);
+               } else if ((rc2 > 0) && (strlen(zpios_buffer) > 0)) {
+                       fprintf(stdout, "\n%s\n", zpios_buffer);
+                       fflush(stdout);
+               }
+       }
+
+       free(cmd);
+
+       return (rc);
+}
+
+static int
+run_offsets(cmd_args_t *args)
+{
+       int rc = 0;
+
+       while (rc == 0 && get_next(&args->current_O, &args->O)) {
+               rc = run_one(args, args->current_id,
+                   args->current_T, args->current_N, args->current_C,
+                   args->current_S, args->current_O, args->current_B);
+               args->current_id++;
+       }
+
+       args->O.next_val = 0;
+       return (rc);
+}
+
+static int
+run_region_counts(cmd_args_t *args)
+{
+       int rc = 0;
+
+       while (rc == 0 && get_next((uint64_t *)&args->current_N, &args->N))
+               rc = run_offsets(args);
+
+       args->N.next_val = 0;
+       return (rc);
+}
+
+static int
+run_region_sizes(cmd_args_t *args)
+{
+       int rc = 0;
+
+       while (rc == 0 && get_next(&args->current_S, &args->S)) {
+               if (args->current_S < args->current_C) {
+                       fprintf(stderr, "Error: in any run chunksize must "
+                           "be strictly smaller than regionsize.\n");
+                       return (EINVAL);
+               }
+
+               rc = run_region_counts(args);
+       }
+
+       args->S.next_val = 0;
+       return (rc);
+}
+
+static int
+run_chunk_sizes(cmd_args_t *args)
+{
+       int rc = 0;
+
+       while (rc == 0 && get_next(&args->current_C, &args->C)) {
+               rc = run_region_sizes(args);
+       }
+
+       args->C.next_val = 0;
+       return (rc);
+}
+
+static int
+run_block_sizes(cmd_args_t *args)
+{
+       int rc = 0;
+
+       while (rc == 0 && get_next(&args->current_B, &args->B)) {
+               rc = run_chunk_sizes(args);
+       }
+
+       args->B.next_val = 0;
+       return (rc);
+}
+
+
+static int
+run_thread_counts(cmd_args_t *args)
+{
+       int rc = 0;
+
+       while (rc == 0 && get_next((uint64_t *)&args->current_T, &args->T))
+               rc = run_block_sizes(args);
+
+       return (rc);
+}
+
+int
+main(int argc, char **argv)
+{
+       cmd_args_t *args;
+       int rc = 0;
+
+       /* Argument init and parsing */
+       if ((args = args_init(argc, argv)) == NULL) {
+               rc = -1;
+               goto out;
+       }
+
+       /* Device specific init */
+       if ((rc = dev_init()))
+               goto out;
+
+       /* Generic kernel version string */
+       if (args->verbose)
+               fprintf(stdout, "%s", zpios_version);
+
+       print_stats_header(args);
+       rc = run_thread_counts(args);
+out:
+       if (args != NULL)
+               args_fini(args);
+
+       dev_fini();
+       return (rc);
+}
diff --git a/zfs/cmd/zpios/zpios_util.c b/zfs/cmd/zpios/zpios_util.c
new file mode 100644 (file)
index 0000000..b31ba51
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+ *  ZPIOS is a heavily modified version of the original PIOS test code.
+ *  It is designed to have the test code running in the Linux kernel
+ *  against ZFS while still being flexibly controled from user space.
+ *
+ *  Copyright (C) 2008-2010 Lawrence Livermore National Security, LLC.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
+ *  LLNL-CODE-403049
+ *
+ *  Original PIOS Test Code
+ *  Copyright (C) 2004 Cluster File Systems, Inc.
+ *  Written by Peter Braam <braam@clusterfs.com>
+ *             Atul Vidwansa <atul@clusterfs.com>
+ *             Milind Dumbare <milind@clusterfs.com>
+ *
+ *  This file is part of ZFS on Linux.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  ZPIOS is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  ZPIOS is distributed in the hope that it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with ZPIOS.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Copyright (c) 2015, Intel Corporation.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <regex.h>
+#include "zpios.h"
+
+/* extracts an unsigned int (64) and K,M,G,T from the string */
+/* and returns a 64 bit value converted to the proper units */
+static int
+kmgt_to_uint64(const char *str, uint64_t *val)
+{
+       char *endptr;
+       int rc = 0;
+
+       *val = strtoll(str, &endptr, 0);
+       if ((str == endptr) && (*val == 0))
+               return (EINVAL);
+
+       switch (endptr[0]) {
+               case 'k': case 'K':
+                       *val = (*val) << 10;
+                       break;
+               case 'm': case 'M':
+                       *val = (*val) << 20;
+                       break;
+               case 'g': case 'G':
+                       *val = (*val) << 30;
+                       break;
+               case 't': case 'T':
+                       *val = (*val) << 40;
+                       break;
+               case '\0':
+                       break;
+               default:
+                       rc = EINVAL;
+       }
+
+       return (rc);
+}
+
+static char *
+uint64_to_kmgt(char *str, uint64_t val)
+{
+       char postfix[] = "kmgt";
+       int i = -1;
+
+       while ((val >= KB) && (i < 4)) {
+               val = (val >> 10);
+               i++;
+       }
+
+       if (i >= 4)
+               (void) snprintf(str, KMGT_SIZE-1, "inf");
+       else
+               (void) snprintf(str, KMGT_SIZE-1, "%lu%c", (unsigned long)val,
+                   (i == -1) ? '\0' : postfix[i]);
+
+       return (str);
+}
+
+static char *
+kmgt_per_sec(char *str, uint64_t v, double t)
+{
+       char postfix[] = "kmgt";
+       double val = ((double)v) / t;
+       int i = -1;
+
+       while ((val >= (double)KB) && (i < 4)) {
+               val /= (double)KB;
+               i++;
+       }
+
+       if (i >= 4)
+               (void) snprintf(str, KMGT_SIZE-1, "inf");
+       else
+               (void) snprintf(str, KMGT_SIZE-1, "%.2f%c", val,
+                   (i == -1) ? '\0' : postfix[i]);
+
+       return (str);
+}
+
+static char *
+print_flags(char *str, uint32_t flags)
+{
+       str[0] = (flags & DMU_WRITE)  ? 'w' : '-';
+       str[1] = (flags & DMU_READ)   ? 'r' : '-';
+       str[2] = (flags & DMU_VERIFY) ? 'v' : '-';
+       str[3] = (flags & DMU_REMOVE) ? 'c' : '-';
+       str[4] = (flags & DMU_FPP)    ? 'p' : 's';
+       str[5] = (flags & (DMU_WRITE_ZC | DMU_READ_ZC)) ? 'z' : '-';
+       str[6] = (flags & DMU_WRITE_NOWAIT) ? 'O' : '-';
+       str[7] = '\0';
+
+       return (str);
+}
+
+static int
+regex_match(const char *string, char *pattern)
+{
+       regex_t re = { 0 };
+       int rc;
+
+       rc = regcomp(&re, pattern, REG_EXTENDED | REG_NOSUB | REG_ICASE);
+       if (rc) {
+               fprintf(stderr, "Error: Couldn't do regcomp, %d\n", rc);
+               return (rc);
+       }
+
+       rc = regexec(&re, string, (size_t) 0, NULL, 0);
+       regfree(&re);
+
+       return (rc);
+}
+
+/* fills the pios_range_repeat structure of comma separated values */
+static int
+split_string(const char *optarg, char *pattern, range_repeat_t *range)
+{
+       const char comma[] = ",";
+       char *cp, *token[32];
+       int rc, i = 0;
+
+       if ((rc = regex_match(optarg, pattern)))
+               return (rc);
+
+       cp = strdup(optarg);
+       if (cp == NULL)
+               return (ENOMEM);
+
+       do {
+               /*
+                * STRTOK(3) Each subsequent call, with a null pointer as the
+                * value of the * first  argument, starts searching from the
+                * saved pointer and behaves as described above.
+                */
+               if (i == 0) {
+                       token[i] = strtok(cp, comma);
+               } else {
+                       token[i] = strtok(NULL, comma);
+               }
+       } while ((token[i++] != NULL) && (i < 32));
+
+       range->val_count = i - 1;
+
+       for (i = 0; i < range->val_count; i++)
+               kmgt_to_uint64(token[i], &range->val[i]);
+
+       free(cp);
+       return (0);
+}
+
+int
+set_count(char *pattern1, char *pattern2, range_repeat_t *range,
+    char *optarg, uint32_t *flags, char *arg)
+{
+       uint64_t count = range->val_count;
+
+       if (flags)
+               *flags |= FLAG_SET;
+
+       range->next_val = 0;
+
+       if (regex_match(optarg, pattern1) == 0) {
+               kmgt_to_uint64(optarg, &range->val[0]);
+               range->val_count = 1;
+       } else if (split_string(optarg, pattern2, range) < 0) {
+               fprintf(stderr, "Error: Incorrect pattern for %s, '%s'\n",
+                   arg, optarg);
+               return (EINVAL);
+       } else if (count == range->val_count) {
+               fprintf(stderr, "Error: input ignored for %s, '%s'\n",
+                   arg, optarg);
+       }
+
+       return (0);
+}
+
+/*
+ * Validates the value with regular expression and sets low, high, incr
+ * according to value at which flag will be set. Sets the flag after.
+ */
+int
+set_lhi(char *pattern, range_repeat_t *range, char *optarg,
+    int flag, uint32_t *flag_thread, char *arg)
+{
+       int rc;
+
+       if ((rc = regex_match(optarg, pattern))) {
+               fprintf(stderr, "Error: Wrong pattern in %s, '%s'\n",
+                       arg, optarg);
+               return (rc);
+       }
+
+       switch (flag) {
+               case FLAG_LOW:
+                       kmgt_to_uint64(optarg, &range->val_low);
+                       break;
+               case FLAG_HIGH:
+                       kmgt_to_uint64(optarg, &range->val_high);
+                       break;
+               case FLAG_INCR:
+                       kmgt_to_uint64(optarg, &range->val_inc_perc);
+                       break;
+               default:
+                       assert(0);
+       }
+
+       *flag_thread |= flag;
+
+       return (0);
+}
+
+int
+set_noise(uint64_t *noise, char *optarg, char *arg)
+{
+       if (regex_match(optarg, REGEX_NUMBERS) == 0) {
+               kmgt_to_uint64(optarg, noise);
+       } else {
+               fprintf(stderr, "Error: Incorrect pattern for %s\n", arg);
+               return (EINVAL);
+       }
+
+       return (0);
+}
+
+int
+set_load_params(cmd_args_t *args, char *optarg)
+{
+       char *param, *search, *searchdup, comma[] = ",";
+       int rc = 0;
+
+       search = strdup(optarg);
+       if (search == NULL)
+               return (ENOMEM);
+       searchdup = search;
+
+       while ((param = strtok(search, comma)) != NULL) {
+               search = NULL;
+
+               if (strcmp("fpp", param) == 0) {
+                       args->flags |= DMU_FPP; /* File Per Process/Thread */
+               } else if (strcmp("ssf", param) == 0) {
+                       args->flags &= ~DMU_FPP; /* Single Shared File */
+               } else if (strcmp("dmuio", param) == 0) {
+                       args->io_type |= DMU_IO;
+                       args->flags |= (DMU_WRITE | DMU_READ);
+               } else {
+                       fprintf(stderr, "Invalid load: %s\n", param);
+                       rc = EINVAL;
+               }
+       }
+
+       free(searchdup);
+
+       return (rc);
+}
+
+
+/*
+ * Checks the low, high, increment values against the single value for
+ * mutual exclusion, for e.g threadcount is mutually exclusive to
+ * threadcount_low, ..._high, ..._incr
+ */
+int
+check_mutual_exclusive_command_lines(uint32_t flag, char *arg)
+{
+       if ((flag & FLAG_SET) && (flag & (FLAG_LOW | FLAG_HIGH | FLAG_INCR))) {
+               fprintf(stderr, "Error: --%s can not be given with --%s_low, "
+                   "--%s_high or --%s_incr.\n", arg, arg, arg, arg);
+               return (0);
+       }
+
+       if ((flag & (FLAG_LOW | FLAG_HIGH | FLAG_INCR)) && !(flag & FLAG_SET)) {
+               if (flag != (FLAG_LOW | FLAG_HIGH | FLAG_INCR)) {
+                       fprintf(stderr, "Error: One or more values missing "
+                           "from --%s_low, --%s_high, --%s_incr.\n",
+                           arg, arg, arg);
+                       return (0);
+               }
+       }
+
+       return (1);
+}
+
+void
+print_stats_header(cmd_args_t *args)
+{
+       if (args->verbose) {
+               printf(
+                   "status    name        id\tth-cnt\trg-cnt\trg-sz\t"
+                   "ch-sz\toffset\trg-no\tch-no\tth-dly\tflags\tblksz\ttime\t"
+                   "cr-time\trm-time\twr-time\trd-time\twr-data\twr-ch\t"
+                   "wr-bw\trd-data\trd-ch\trd-bw\n");
+               printf(
+                   "-------------------------------------------------"
+                   "-------------------------------------------------"
+                   "-------------------------------------------------"
+                   "--------------------------------------------------\n");
+       } else {
+               printf(
+                   "status    name        id\t"
+                   "wr-data\twr-ch\twr-bw\t"
+                   "rd-data\trd-ch\trd-bw\n");
+               printf(
+                   "-----------------------------------------"
+                   "--------------------------------------\n");
+       }
+}
+
+static void
+print_stats_human_readable(cmd_args_t *args, zpios_cmd_t *cmd)
+{
+       zpios_stats_t *summary_stats;
+       double t_time, wr_time, rd_time, cr_time, rm_time;
+       char str[KMGT_SIZE];
+
+       if (args->rc)
+               printf("FAIL: %3d ", args->rc);
+       else
+               printf("PASS:     ");
+
+       printf("%-12s", args->name ? args->name : ZPIOS_NAME);
+       printf("%2u\t", cmd->cmd_id);
+
+       if (args->verbose) {
+               printf("%u\t", cmd->cmd_thread_count);
+               printf("%u\t", cmd->cmd_region_count);
+               printf("%s\t", uint64_to_kmgt(str, cmd->cmd_region_size));
+               printf("%s\t", uint64_to_kmgt(str, cmd->cmd_chunk_size));
+               printf("%s\t", uint64_to_kmgt(str, cmd->cmd_offset));
+               printf("%s\t", uint64_to_kmgt(str, cmd->cmd_region_noise));
+               printf("%s\t", uint64_to_kmgt(str, cmd->cmd_chunk_noise));
+               printf("%s\t", uint64_to_kmgt(str, cmd->cmd_thread_delay));
+               printf("%s\t", print_flags(str, cmd->cmd_flags));
+               printf("%s\t", uint64_to_kmgt(str, cmd->cmd_block_size));
+       }
+
+       if (args->rc) {
+               printf("\n");
+               return;
+       }
+
+       summary_stats = (zpios_stats_t *)cmd->cmd_data_str;
+       t_time  = zpios_timespec_to_double(summary_stats->total_time.delta);
+       wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta);
+       rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta);
+       cr_time = zpios_timespec_to_double(summary_stats->cr_time.delta);
+       rm_time = zpios_timespec_to_double(summary_stats->rm_time.delta);
+
+       if (args->verbose) {
+               printf("%.2f\t", t_time);
+               printf("%.3f\t", cr_time);
+               printf("%.3f\t", rm_time);
+               printf("%.2f\t", wr_time);
+               printf("%.2f\t", rd_time);
+       }
+
+       printf("%s\t", uint64_to_kmgt(str, summary_stats->wr_data));
+       printf("%s\t", uint64_to_kmgt(str, summary_stats->wr_chunks));
+       printf("%s\t", kmgt_per_sec(str, summary_stats->wr_data, wr_time));
+
+       printf("%s\t", uint64_to_kmgt(str, summary_stats->rd_data));
+       printf("%s\t", uint64_to_kmgt(str, summary_stats->rd_chunks));
+       printf("%s\n", kmgt_per_sec(str, summary_stats->rd_data, rd_time));
+       fflush(stdout);
+}
+
+static void
+print_stats_table(cmd_args_t *args, zpios_cmd_t *cmd)
+{
+       zpios_stats_t *summary_stats;
+       double wr_time, rd_time;
+
+       if (args->rc)
+               printf("FAIL: %3d ", args->rc);
+       else
+               printf("PASS:     ");
+
+       printf("%-12s", args->name ? args->name : ZPIOS_NAME);
+       printf("%2u\t", cmd->cmd_id);
+
+       if (args->verbose) {
+               printf("%u\t", cmd->cmd_thread_count);
+               printf("%u\t", cmd->cmd_region_count);
+               printf("%llu\t", (long long unsigned)cmd->cmd_region_size);
+               printf("%llu\t", (long long unsigned)cmd->cmd_chunk_size);
+               printf("%llu\t", (long long unsigned)cmd->cmd_offset);
+               printf("%u\t", cmd->cmd_region_noise);
+               printf("%u\t", cmd->cmd_chunk_noise);
+               printf("%u\t", cmd->cmd_thread_delay);
+               printf("0x%x\t", cmd->cmd_flags);
+               printf("%u\t", cmd->cmd_block_size);
+       }
+
+       if (args->rc) {
+               printf("\n");
+               return;
+       }
+
+       summary_stats = (zpios_stats_t *)cmd->cmd_data_str;
+       wr_time = zpios_timespec_to_double(summary_stats->wr_time.delta);
+       rd_time = zpios_timespec_to_double(summary_stats->rd_time.delta);
+
+       if (args->verbose) {
+               printf("%ld.%02ld\t",
+                   (long)summary_stats->total_time.delta.ts_sec,
+                   (long)summary_stats->total_time.delta.ts_nsec);
+               printf("%ld.%02ld\t",
+                   (long)summary_stats->cr_time.delta.ts_sec,
+                   (long)summary_stats->cr_time.delta.ts_nsec);
+               printf("%ld.%02ld\t",
+                   (long)summary_stats->rm_time.delta.ts_sec,
+                   (long)summary_stats->rm_time.delta.ts_nsec);
+               printf("%ld.%02ld\t",
+                   (long)summary_stats->wr_time.delta.ts_sec,
+                   (long)summary_stats->wr_time.delta.ts_nsec);
+               printf("%ld.%02ld\t",
+                   (long)summary_stats->rd_time.delta.ts_sec,
+                   (long)summary_stats->rd_time.delta.ts_nsec);
+       }
+
+       printf("%lld\t", (long long unsigned)summary_stats->wr_data);
+       printf("%lld\t", (long long unsigned)summary_stats->wr_chunks);
+       printf("%.4f\t", (double)summary_stats->wr_data / wr_time);
+
+       printf("%lld\t", (long long unsigned)summary_stats->rd_data);
+       printf("%lld\t", (long long unsigned)summary_stats->rd_chunks);
+       printf("%.4f\n", (double)summary_stats->rd_data / rd_time);
+       fflush(stdout);
+}
+
+void
+print_stats(cmd_args_t *args, zpios_cmd_t *cmd)
+{
+       if (args->human_readable)
+               print_stats_human_readable(args, cmd);
+       else
+               print_stats_table(args, cmd);
+}
diff --git a/zfs/cmd/zpool/Makefile.am b/zfs/cmd/zpool/Makefile.am
new file mode 100644 (file)
index 0000000..b4ff106
--- /dev/null
@@ -0,0 +1,22 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+sbin_PROGRAMS = zpool
+
+zpool_SOURCES = \
+       zpool_iter.c \
+       zpool_main.c \
+       zpool_util.c \
+       zpool_util.h \
+       zpool_vdev.c
+
+zpool_LDADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la \
+       -lm $(LIBBLKID)
diff --git a/zfs/cmd/zpool/Makefile.in b/zfs/cmd/zpool/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zpool/zpool_iter.c b/zfs/cmd/zpool/zpool_iter.c
new file mode 100644 (file)
index 0000000..1b64a5a
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * 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 <libintl.h>
+#include <libuutil.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <libzfs.h>
+
+#include "zpool_util.h"
+
+/*
+ * Private interface for iterating over pools specified on the command line.
+ * Most consumers will call for_each_pool, but in order to support iostat, we
+ * allow fined grained control through the zpool_list_t interface.
+ */
+
+typedef struct zpool_node {
+       zpool_handle_t  *zn_handle;
+       uu_avl_node_t   zn_avlnode;
+       int             zn_mark;
+} zpool_node_t;
+
+struct zpool_list {
+       boolean_t       zl_findall;
+       uu_avl_t        *zl_avl;
+       uu_avl_pool_t   *zl_pool;
+       zprop_list_t    **zl_proplist;
+};
+
+/* ARGSUSED */
+static int
+zpool_compare(const void *larg, const void *rarg, void *unused)
+{
+       zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle;
+       zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle;
+       const char *lname = zpool_get_name(l);
+       const char *rname = zpool_get_name(r);
+
+       return (strcmp(lname, rname));
+}
+
+/*
+ * Callback function for pool_list_get().  Adds the given pool to the AVL tree
+ * of known pools.
+ */
+static int
+add_pool(zpool_handle_t *zhp, void *data)
+{
+       zpool_list_t *zlp = data;
+       zpool_node_t *node = safe_malloc(sizeof (zpool_node_t));
+       uu_avl_index_t idx;
+
+       node->zn_handle = zhp;
+       uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool);
+       if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) {
+               if (zlp->zl_proplist &&
+                   zpool_expand_proplist(zhp, zlp->zl_proplist) != 0) {
+                       zpool_close(zhp);
+                       free(node);
+                       return (-1);
+               }
+               uu_avl_insert(zlp->zl_avl, node, idx);
+       } else {
+               zpool_close(zhp);
+               free(node);
+               return (-1);
+       }
+
+       return (0);
+}
+
+/*
+ * Create a list of pools based on the given arguments.  If we're given no
+ * arguments, then iterate over all pools in the system and add them to the AVL
+ * tree.  Otherwise, add only those pool explicitly specified on the command
+ * line.
+ */
+zpool_list_t *
+pool_list_get(int argc, char **argv, zprop_list_t **proplist, int *err)
+{
+       zpool_list_t *zlp;
+
+       zlp = safe_malloc(sizeof (zpool_list_t));
+
+       zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t),
+           offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT);
+
+       if (zlp->zl_pool == NULL)
+               zpool_no_memory();
+
+       if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL,
+           UU_DEFAULT)) == NULL)
+               zpool_no_memory();
+
+       zlp->zl_proplist = proplist;
+
+       if (argc == 0) {
+               (void) zpool_iter(g_zfs, add_pool, zlp);
+               zlp->zl_findall = B_TRUE;
+       } else {
+               int i;
+
+               for (i = 0; i < argc; i++) {
+                       zpool_handle_t *zhp;
+
+                       if ((zhp = zpool_open_canfail(g_zfs, argv[i]))) {
+                               if (add_pool(zhp, zlp) != 0)
+                                       *err = B_TRUE;
+                       } else {
+                               *err = B_TRUE;
+                       }
+               }
+       }
+
+       return (zlp);
+}
+
+/*
+ * Search for any new pools, adding them to the list.  We only add pools when no
+ * options were given on the command line.  Otherwise, we keep the list fixed as
+ * those that were explicitly specified.
+ */
+void
+pool_list_update(zpool_list_t *zlp)
+{
+       if (zlp->zl_findall)
+               (void) zpool_iter(g_zfs, add_pool, zlp);
+}
+
+/*
+ * Iterate over all pools in the list, executing the callback for each
+ */
+int
+pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func,
+    void *data)
+{
+       zpool_node_t *node, *next_node;
+       int ret = 0;
+
+       for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) {
+               next_node = uu_avl_next(zlp->zl_avl, node);
+               if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL ||
+                   unavail)
+                       ret |= func(node->zn_handle, data);
+       }
+
+       return (ret);
+}
+
+/*
+ * Remove the given pool from the list.  When running iostat, we want to remove
+ * those pools that no longer exist.
+ */
+void
+pool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp)
+{
+       zpool_node_t search, *node;
+
+       search.zn_handle = zhp;
+       if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) {
+               uu_avl_remove(zlp->zl_avl, node);
+               zpool_close(node->zn_handle);
+               free(node);
+       }
+}
+
+/*
+ * Free all the handles associated with this list.
+ */
+void
+pool_list_free(zpool_list_t *zlp)
+{
+       uu_avl_walk_t *walk;
+       zpool_node_t *node;
+
+       if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) {
+               (void) fprintf(stderr,
+                   gettext("internal error: out of memory"));
+               exit(1);
+       }
+
+       while ((node = uu_avl_walk_next(walk)) != NULL) {
+               uu_avl_remove(zlp->zl_avl, node);
+               zpool_close(node->zn_handle);
+               free(node);
+       }
+
+       uu_avl_walk_end(walk);
+       uu_avl_destroy(zlp->zl_avl);
+       uu_avl_pool_destroy(zlp->zl_pool);
+
+       free(zlp);
+}
+
+/*
+ * Returns the number of elements in the pool list.
+ */
+int
+pool_list_count(zpool_list_t *zlp)
+{
+       return (uu_avl_numnodes(zlp->zl_avl));
+}
+
+/*
+ * High level function which iterates over all pools given on the command line,
+ * using the pool_list_* interfaces.
+ */
+int
+for_each_pool(int argc, char **argv, boolean_t unavail,
+    zprop_list_t **proplist, zpool_iter_f func, void *data)
+{
+       zpool_list_t *list;
+       int ret = 0;
+
+       if ((list = pool_list_get(argc, argv, proplist, &ret)) == NULL)
+               return (1);
+
+       if (pool_list_iter(list, unavail, func, data) != 0)
+               ret = 1;
+
+       pool_list_free(list);
+
+       return (ret);
+}
+
+static int
+for_each_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, pool_vdev_iter_f func,
+    void *data)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       int ret = 0;
+       int i;
+       char *type;
+
+       const char *list[] = {
+           ZPOOL_CONFIG_SPARES,
+           ZPOOL_CONFIG_L2CACHE,
+           ZPOOL_CONFIG_CHILDREN
+       };
+
+       for (i = 0; i < ARRAY_SIZE(list); i++) {
+               if (nvlist_lookup_nvlist_array(nv, list[i], &child,
+                   &children) == 0) {
+                       for (c = 0; c < children; c++) {
+                               uint64_t ishole = 0;
+
+                               (void) nvlist_lookup_uint64(child[c],
+                                   ZPOOL_CONFIG_IS_HOLE, &ishole);
+
+                               if (ishole)
+                                       continue;
+
+                               ret |= for_each_vdev_cb(zhp, child[c], func,
+                                   data);
+                       }
+               }
+       }
+
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
+               return (ret);
+
+       /* Don't run our function on root vdevs */
+       if (strcmp(type, VDEV_TYPE_ROOT) != 0) {
+               ret |= func(zhp, nv, data);
+       }
+
+       return (ret);
+}
+
+/*
+ * This is the equivalent of for_each_pool() for vdevs.  It iterates thorough
+ * all vdevs in the pool, ignoring root vdevs and holes, calling func() on
+ * each one.
+ *
+ * @zhp:       Zpool handle
+ * @func:      Function to call on each vdev
+ * @data:      Custom data to pass to the function
+ */
+int
+for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data)
+{
+       nvlist_t *config, *nvroot = NULL;
+
+       if ((config = zpool_get_config(zhp, NULL)) != NULL) {
+               verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+                   &nvroot) == 0);
+       }
+       return (for_each_vdev_cb(zhp, nvroot, func, data));
+}
diff --git a/zfs/cmd/zpool/zpool_main.c b/zfs/cmd/zpool/zpool_main.c
new file mode 100644 (file)
index 0000000..b6702f2
--- /dev/null
@@ -0,0 +1,7475 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012 by Frederik Wessels. All rights reserved.
+ * Copyright (c) 2012 by Cyril Plisko. All rights reserved.
+ * Copyright (c) 2013 by Prasad Joshi (sTec). All rights reserved.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <libuutil.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <zone.h>
+#include <zfs_prop.h>
+#include <sys/fs/zfs.h>
+#include <sys/stat.h>
+#include <sys/fm/fs/zfs.h>
+#include <sys/fm/util.h>
+#include <sys/fm/protocol.h>
+#include <sys/zfs_ioctl.h>
+#include <math.h>
+
+#include <libzfs.h>
+
+#include "zpool_util.h"
+#include "zfs_comutil.h"
+#include "zfeature_common.h"
+
+#include "statcommon.h"
+
+static int zpool_do_create(int, char **);
+static int zpool_do_destroy(int, char **);
+
+static int zpool_do_add(int, char **);
+static int zpool_do_remove(int, char **);
+static int zpool_do_labelclear(int, char **);
+
+static int zpool_do_list(int, char **);
+static int zpool_do_iostat(int, char **);
+static int zpool_do_status(int, char **);
+
+static int zpool_do_online(int, char **);
+static int zpool_do_offline(int, char **);
+static int zpool_do_clear(int, char **);
+static int zpool_do_reopen(int, char **);
+
+static int zpool_do_reguid(int, char **);
+
+static int zpool_do_attach(int, char **);
+static int zpool_do_detach(int, char **);
+static int zpool_do_replace(int, char **);
+static int zpool_do_split(int, char **);
+
+static int zpool_do_scrub(int, char **);
+
+static int zpool_do_import(int, char **);
+static int zpool_do_export(int, char **);
+
+static int zpool_do_upgrade(int, char **);
+
+static int zpool_do_history(int, char **);
+static int zpool_do_events(int, char **);
+
+static int zpool_do_get(int, char **);
+static int zpool_do_set(int, char **);
+
+/*
+ * These libumem hooks provide a reasonable set of defaults for the allocator's
+ * debugging facilities.
+ */
+
+#ifdef DEBUG
+const char *
+_umem_debug_init(void)
+{
+       return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+       return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+#endif
+
+typedef enum {
+       HELP_ADD,
+       HELP_ATTACH,
+       HELP_CLEAR,
+       HELP_CREATE,
+       HELP_DESTROY,
+       HELP_DETACH,
+       HELP_EXPORT,
+       HELP_HISTORY,
+       HELP_IMPORT,
+       HELP_IOSTAT,
+       HELP_LABELCLEAR,
+       HELP_LIST,
+       HELP_OFFLINE,
+       HELP_ONLINE,
+       HELP_REPLACE,
+       HELP_REMOVE,
+       HELP_SCRUB,
+       HELP_STATUS,
+       HELP_UPGRADE,
+       HELP_EVENTS,
+       HELP_GET,
+       HELP_SET,
+       HELP_SPLIT,
+       HELP_REGUID,
+       HELP_REOPEN
+} zpool_help_t;
+
+
+/*
+ * Flags for stats to display with "zpool iostats"
+ */
+enum iostat_type {
+       IOS_DEFAULT = 0,
+       IOS_LATENCY = 1,
+       IOS_QUEUES = 2,
+       IOS_L_HISTO = 3,
+       IOS_RQ_HISTO = 4,
+       IOS_COUNT,      /* always last element */
+};
+
+/* iostat_type entries as bitmasks */
+#define        IOS_DEFAULT_M   (1ULL << IOS_DEFAULT)
+#define        IOS_LATENCY_M   (1ULL << IOS_LATENCY)
+#define        IOS_QUEUES_M    (1ULL << IOS_QUEUES)
+#define        IOS_L_HISTO_M   (1ULL << IOS_L_HISTO)
+#define        IOS_RQ_HISTO_M  (1ULL << IOS_RQ_HISTO)
+
+/* Mask of all the histo bits */
+#define        IOS_ANYHISTO_M (IOS_L_HISTO_M | IOS_RQ_HISTO_M)
+
+/*
+ * Lookup table for iostat flags to nvlist names.  Basically a list
+ * of all the nvlists a flag requires.  Also specifies the order in
+ * which data gets printed in zpool iostat.
+ */
+static const char *vsx_type_to_nvlist[IOS_COUNT][11] = {
+       [IOS_L_HISTO] = {
+           ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
+           NULL},
+       [IOS_LATENCY] = {
+           ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
+           ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
+           NULL},
+       [IOS_QUEUES] = {
+           ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE,
+           ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE,
+           ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE,
+           ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
+           ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
+           NULL},
+       [IOS_RQ_HISTO] = {
+           ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO,
+           ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO,
+           ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO,
+           ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO,
+           ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO,
+           ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO,
+           ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO,
+           ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO,
+           ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO,
+           ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO,
+           NULL},
+};
+
+
+/*
+ * Given a cb->cb_flags with a histogram bit set, return the iostat_type.
+ * Right now, only one histo bit is ever set at one time, so we can
+ * just do a highbit64(a)
+ */
+#define        IOS_HISTO_IDX(a)        (highbit64(a & IOS_ANYHISTO_M) - 1)
+
+typedef struct zpool_command {
+       const char      *name;
+       int             (*func)(int, char **);
+       zpool_help_t    usage;
+} zpool_command_t;
+
+/*
+ * Master command table.  Each ZFS command has a name, associated function, and
+ * usage message.  The usage messages need to be internationalized, so we have
+ * to have a function to return the usage message based on a command index.
+ *
+ * These commands are organized according to how they are displayed in the usage
+ * message.  An empty command (one with a NULL name) indicates an empty line in
+ * the generic usage message.
+ */
+static zpool_command_t command_table[] = {
+       { "create",     zpool_do_create,        HELP_CREATE             },
+       { "destroy",    zpool_do_destroy,       HELP_DESTROY            },
+       { NULL },
+       { "add",        zpool_do_add,           HELP_ADD                },
+       { "remove",     zpool_do_remove,        HELP_REMOVE             },
+       { NULL },
+       { "labelclear", zpool_do_labelclear,    HELP_LABELCLEAR         },
+       { NULL },
+       { "list",       zpool_do_list,          HELP_LIST               },
+       { "iostat",     zpool_do_iostat,        HELP_IOSTAT             },
+       { "status",     zpool_do_status,        HELP_STATUS             },
+       { NULL },
+       { "online",     zpool_do_online,        HELP_ONLINE             },
+       { "offline",    zpool_do_offline,       HELP_OFFLINE            },
+       { "clear",      zpool_do_clear,         HELP_CLEAR              },
+       { "reopen",     zpool_do_reopen,        HELP_REOPEN             },
+       { NULL },
+       { "attach",     zpool_do_attach,        HELP_ATTACH             },
+       { "detach",     zpool_do_detach,        HELP_DETACH             },
+       { "replace",    zpool_do_replace,       HELP_REPLACE            },
+       { "split",      zpool_do_split,         HELP_SPLIT              },
+       { NULL },
+       { "scrub",      zpool_do_scrub,         HELP_SCRUB              },
+       { NULL },
+       { "import",     zpool_do_import,        HELP_IMPORT             },
+       { "export",     zpool_do_export,        HELP_EXPORT             },
+       { "upgrade",    zpool_do_upgrade,       HELP_UPGRADE            },
+       { "reguid",     zpool_do_reguid,        HELP_REGUID             },
+       { NULL },
+       { "history",    zpool_do_history,       HELP_HISTORY            },
+       { "events",     zpool_do_events,        HELP_EVENTS             },
+       { NULL },
+       { "get",        zpool_do_get,           HELP_GET                },
+       { "set",        zpool_do_set,           HELP_SET                },
+};
+
+#define        NCOMMAND        (ARRAY_SIZE(command_table))
+
+static zpool_command_t *current_command;
+static char history_str[HIS_MAX_RECORD_LEN];
+static boolean_t log_history = B_TRUE;
+static uint_t timestamp_fmt = NODATE;
+
+static const char *
+get_usage(zpool_help_t idx) {
+       switch (idx) {
+       case HELP_ADD:
+               return (gettext("\tadd [-fgLnP] [-o property=value] "
+                   "<pool> <vdev> ...\n"));
+       case HELP_ATTACH:
+               return (gettext("\tattach [-f] [-o property=value] "
+                   "<pool> <device> <new-device>\n"));
+       case HELP_CLEAR:
+               return (gettext("\tclear [-nF] <pool> [device]\n"));
+       case HELP_CREATE:
+               return (gettext("\tcreate [-fnd] [-o property=value] ... \n"
+                   "\t    [-O file-system-property=value] ... \n"
+                   "\t    [-m mountpoint] [-R root] <pool> <vdev> ...\n"));
+       case HELP_DESTROY:
+               return (gettext("\tdestroy [-f] <pool>\n"));
+       case HELP_DETACH:
+               return (gettext("\tdetach <pool> <device>\n"));
+       case HELP_EXPORT:
+               return (gettext("\texport [-af] <pool> ...\n"));
+       case HELP_HISTORY:
+               return (gettext("\thistory [-il] [<pool>] ...\n"));
+       case HELP_IMPORT:
+               return (gettext("\timport [-d dir] [-D]\n"
+                   "\timport [-d dir | -c cachefile] [-F [-n]] <pool | id>\n"
+                   "\timport [-o mntopts] [-o property=value] ... \n"
+                   "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
+                   "[-R root] [-F [-n]] -a\n"
+                   "\timport [-o mntopts] [-o property=value] ... \n"
+                   "\t    [-d dir | -c cachefile] [-D] [-f] [-m] [-N] "
+                   "[-R root] [-F [-n]]\n"
+                   "\t    <pool | id> [newpool]\n"));
+       case HELP_IOSTAT:
+               return (gettext("\tiostat [-T d | u] [-ghHLpPvy] "
+                   "[[-lq]|[-r|-w]]\n"
+                   "\t    [[pool ...]|[pool vdev ...]|[vdev ...]] "
+                   "[interval [count]]\n"));
+       case HELP_LABELCLEAR:
+               return (gettext("\tlabelclear [-f] <vdev>\n"));
+       case HELP_LIST:
+               return (gettext("\tlist [-gHLpPv] [-o property[,...]] "
+                   "[-T d|u] [pool] ... [interval [count]]\n"));
+       case HELP_OFFLINE:
+               return (gettext("\toffline [-t] <pool> <device> ...\n"));
+       case HELP_ONLINE:
+               return (gettext("\tonline <pool> <device> ...\n"));
+       case HELP_REPLACE:
+               return (gettext("\treplace [-f] [-o property=value] "
+                   "<pool> <device> [new-device]\n"));
+       case HELP_REMOVE:
+               return (gettext("\tremove <pool> <device> ...\n"));
+       case HELP_REOPEN:
+               return (gettext("\treopen <pool>\n"));
+       case HELP_SCRUB:
+               return (gettext("\tscrub [-s] <pool> ...\n"));
+       case HELP_STATUS:
+               return (gettext("\tstatus [-gLPvxD] [-T d|u] [pool] ... "
+                   "[interval [count]]\n"));
+       case HELP_UPGRADE:
+               return (gettext("\tupgrade\n"
+                   "\tupgrade -v\n"
+                   "\tupgrade [-V version] <-a | pool ...>\n"));
+       case HELP_EVENTS:
+               return (gettext("\tevents [-vHfc]\n"));
+       case HELP_GET:
+               return (gettext("\tget [-Hp] [-o \"all\" | field[,...]] "
+                   "<\"all\" | property[,...]> <pool> ...\n"));
+       case HELP_SET:
+               return (gettext("\tset <property=value> <pool> \n"));
+       case HELP_SPLIT:
+               return (gettext("\tsplit [-gLnP] [-R altroot] [-o mntopts]\n"
+                   "\t    [-o property=value] <pool> <newpool> "
+                   "[<device> ...]\n"));
+       case HELP_REGUID:
+               return (gettext("\treguid <pool>\n"));
+       }
+
+       abort();
+       /* NOTREACHED */
+}
+
+
+/*
+ * Callback routine that will print out a pool property value.
+ */
+static int
+print_prop_cb(int prop, void *cb)
+{
+       FILE *fp = cb;
+
+       (void) fprintf(fp, "\t%-15s  ", zpool_prop_to_name(prop));
+
+       if (zpool_prop_readonly(prop))
+               (void) fprintf(fp, "  NO   ");
+       else
+               (void) fprintf(fp, " YES   ");
+
+       if (zpool_prop_values(prop) == NULL)
+               (void) fprintf(fp, "-\n");
+       else
+               (void) fprintf(fp, "%s\n", zpool_prop_values(prop));
+
+       return (ZPROP_CONT);
+}
+
+/*
+ * Display usage message.  If we're inside a command, display only the usage for
+ * that command.  Otherwise, iterate over the entire command table and display
+ * a complete usage message.
+ */
+void
+usage(boolean_t requested)
+{
+       FILE *fp = requested ? stdout : stderr;
+
+       if (current_command == NULL) {
+               int i;
+
+               (void) fprintf(fp, gettext("usage: zpool command args ...\n"));
+               (void) fprintf(fp,
+                   gettext("where 'command' is one of the following:\n\n"));
+
+               for (i = 0; i < NCOMMAND; i++) {
+                       if (command_table[i].name == NULL)
+                               (void) fprintf(fp, "\n");
+                       else
+                               (void) fprintf(fp, "%s",
+                                   get_usage(command_table[i].usage));
+               }
+       } else {
+               (void) fprintf(fp, gettext("usage:\n"));
+               (void) fprintf(fp, "%s", get_usage(current_command->usage));
+       }
+
+       if (current_command != NULL &&
+           ((strcmp(current_command->name, "set") == 0) ||
+           (strcmp(current_command->name, "get") == 0) ||
+           (strcmp(current_command->name, "list") == 0))) {
+
+               (void) fprintf(fp,
+                   gettext("\nthe following properties are supported:\n"));
+
+               (void) fprintf(fp, "\n\t%-15s  %s   %s\n\n",
+                   "PROPERTY", "EDIT", "VALUES");
+
+               /* Iterate over all properties */
+               (void) zprop_iter(print_prop_cb, fp, B_FALSE, B_TRUE,
+                   ZFS_TYPE_POOL);
+
+               (void) fprintf(fp, "\t%-15s   ", "feature@...");
+               (void) fprintf(fp, "YES   disabled | enabled | active\n");
+
+               (void) fprintf(fp, gettext("\nThe feature@ properties must be "
+                   "appended with a feature name.\nSee zpool-features(5).\n"));
+       }
+
+       /*
+        * See comments at end of main().
+        */
+       if (getenv("ZFS_ABORT") != NULL) {
+               (void) printf("dumping core by request\n");
+               abort();
+       }
+
+       exit(requested ? 0 : 2);
+}
+
+void
+print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
+    boolean_t print_logs, int name_flags)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       char *vname;
+
+       if (name != NULL)
+               (void) printf("\t%*s%s\n", indent, "", name);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               return;
+
+       for (c = 0; c < children; c++) {
+               uint64_t is_log = B_FALSE;
+
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &is_log);
+               if ((is_log && !print_logs) || (!is_log && print_logs))
+                       continue;
+
+               vname = zpool_vdev_name(g_zfs, zhp, child[c], name_flags);
+               print_vdev_tree(zhp, vname, child[c], indent + 2,
+                   B_FALSE, name_flags);
+               free(vname);
+       }
+}
+
+static boolean_t
+prop_list_contains_feature(nvlist_t *proplist)
+{
+       nvpair_t *nvp;
+       for (nvp = nvlist_next_nvpair(proplist, NULL); NULL != nvp;
+           nvp = nvlist_next_nvpair(proplist, nvp)) {
+               if (zpool_prop_feature(nvpair_name(nvp)))
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+/*
+ * Add a property pair (name, string-value) into a property nvlist.
+ */
+static int
+add_prop_list(const char *propname, char *propval, nvlist_t **props,
+    boolean_t poolprop)
+{
+       zpool_prop_t prop = ZPROP_INVAL;
+       zfs_prop_t fprop;
+       nvlist_t *proplist;
+       const char *normnm;
+       char *strval;
+
+       if (*props == NULL &&
+           nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
+               (void) fprintf(stderr,
+                   gettext("internal error: out of memory\n"));
+               return (1);
+       }
+
+       proplist = *props;
+
+       if (poolprop) {
+               const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
+
+               if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
+                   !zpool_prop_feature(propname)) {
+                       (void) fprintf(stderr, gettext("property '%s' is "
+                           "not a valid pool property\n"), propname);
+                       return (2);
+               }
+
+               /*
+                * feature@ properties and version should not be specified
+                * at the same time.
+                */
+               if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) &&
+                   nvlist_exists(proplist, vname)) ||
+                   (prop == ZPOOL_PROP_VERSION &&
+                   prop_list_contains_feature(proplist))) {
+                       (void) fprintf(stderr, gettext("'feature@' and "
+                           "'version' properties cannot be specified "
+                           "together\n"));
+                       return (2);
+               }
+
+
+               if (zpool_prop_feature(propname))
+                       normnm = propname;
+               else
+                       normnm = zpool_prop_to_name(prop);
+       } else {
+               if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
+                       normnm = zfs_prop_to_name(fprop);
+               } else {
+                       normnm = propname;
+               }
+       }
+
+       if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
+           prop != ZPOOL_PROP_CACHEFILE) {
+               (void) fprintf(stderr, gettext("property '%s' "
+                   "specified multiple times\n"), propname);
+               return (2);
+       }
+
+       if (nvlist_add_string(proplist, normnm, propval) != 0) {
+               (void) fprintf(stderr, gettext("internal "
+                   "error: out of memory\n"));
+               return (1);
+       }
+
+       return (0);
+}
+
+/*
+ * Set a default property pair (name, string-value) in a property nvlist
+ */
+static int
+add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
+    boolean_t poolprop)
+{
+       char *pval;
+
+       if (nvlist_lookup_string(*props, propname, &pval) == 0)
+               return (0);
+
+       return (add_prop_list(propname, propval, props, B_TRUE));
+}
+
+/*
+ * zpool add [-fgLnP] [-o property=value] <pool> <vdev> ...
+ *
+ *     -f      Force addition of devices, even if they appear in use
+ *     -g      Display guid for individual vdev name.
+ *     -L      Follow links when resolving vdev path name.
+ *     -n      Do not add the devices, but display the resulting layout if
+ *             they were to be added.
+ *     -o      Set property=value.
+ *     -P      Display full path for vdev name.
+ *
+ * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
+ * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
+ * libzfs.
+ */
+int
+zpool_do_add(int argc, char **argv)
+{
+       boolean_t force = B_FALSE;
+       boolean_t dryrun = B_FALSE;
+       int name_flags = 0;
+       int c;
+       nvlist_t *nvroot;
+       char *poolname;
+       int ret;
+       zpool_handle_t *zhp;
+       nvlist_t *config;
+       nvlist_t *props = NULL;
+       char *propval;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "fgLno:P")) != -1) {
+               switch (c) {
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               case 'g':
+                       name_flags |= VDEV_NAME_GUID;
+                       break;
+               case 'L':
+                       name_flags |= VDEV_NAME_FOLLOW_LINKS;
+                       break;
+               case 'n':
+                       dryrun = B_TRUE;
+                       break;
+               case 'o':
+                       if ((propval = strchr(optarg, '=')) == NULL) {
+                               (void) fprintf(stderr, gettext("missing "
+                                   "'=' for -o option\n"));
+                               usage(B_FALSE);
+                       }
+                       *propval = '\0';
+                       propval++;
+
+                       if ((strcmp(optarg, ZPOOL_CONFIG_ASHIFT) != 0) ||
+                           (add_prop_list(optarg, propval, &props, B_TRUE)))
+                               usage(B_FALSE);
+                       break;
+               case 'P':
+                       name_flags |= VDEV_NAME_PATH;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing vdev specification\n"));
+               usage(B_FALSE);
+       }
+
+       poolname = argv[0];
+
+       argc--;
+       argv++;
+
+       if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+               return (1);
+
+       if ((config = zpool_get_config(zhp, NULL)) == NULL) {
+               (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
+                   poolname);
+               zpool_close(zhp);
+               return (1);
+       }
+
+       /* pass off to get_vdev_spec for processing */
+       nvroot = make_root_vdev(zhp, props, force, !force, B_FALSE, dryrun,
+           argc, argv);
+       if (nvroot == NULL) {
+               zpool_close(zhp);
+               return (1);
+       }
+
+       if (dryrun) {
+               nvlist_t *poolnvroot;
+               nvlist_t **l2child;
+               uint_t l2children, c;
+               char *vname;
+               boolean_t hadcache = B_FALSE;
+
+               verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+                   &poolnvroot) == 0);
+
+               (void) printf(gettext("would update '%s' to the following "
+                   "configuration:\n"), zpool_get_name(zhp));
+
+               /* print original main pool and new tree */
+               print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE,
+                   name_flags);
+               print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE, name_flags);
+
+               /* Do the same for the logs */
+               if (num_logs(poolnvroot) > 0) {
+                       print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE,
+                           name_flags);
+                       print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE,
+                           name_flags);
+               } else if (num_logs(nvroot) > 0) {
+                       print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE,
+                           name_flags);
+               }
+
+               /* Do the same for the caches */
+               if (nvlist_lookup_nvlist_array(poolnvroot, ZPOOL_CONFIG_L2CACHE,
+                   &l2child, &l2children) == 0 && l2children) {
+                       hadcache = B_TRUE;
+                       (void) printf(gettext("\tcache\n"));
+                       for (c = 0; c < l2children; c++) {
+                               vname = zpool_vdev_name(g_zfs, NULL,
+                                   l2child[c], name_flags);
+                               (void) printf("\t  %s\n", vname);
+                               free(vname);
+                       }
+               }
+               if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+                   &l2child, &l2children) == 0 && l2children) {
+                       if (!hadcache)
+                               (void) printf(gettext("\tcache\n"));
+                       for (c = 0; c < l2children; c++) {
+                               vname = zpool_vdev_name(g_zfs, NULL,
+                                   l2child[c], name_flags);
+                               (void) printf("\t  %s\n", vname);
+                               free(vname);
+                       }
+               }
+
+               ret = 0;
+       } else {
+               ret = (zpool_add(zhp, nvroot) != 0);
+       }
+
+       nvlist_free(props);
+       nvlist_free(nvroot);
+       zpool_close(zhp);
+
+       return (ret);
+}
+
+/*
+ * zpool remove  <pool> <vdev> ...
+ *
+ * Removes the given vdev from the pool.  Currently, this supports removing
+ * spares, cache, and log devices from the pool.
+ */
+int
+zpool_do_remove(int argc, char **argv)
+{
+       char *poolname;
+       int i, ret = 0;
+       zpool_handle_t *zhp = NULL;
+
+       argc--;
+       argv++;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing device\n"));
+               usage(B_FALSE);
+       }
+
+       poolname = argv[0];
+
+       if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+               return (1);
+
+       for (i = 1; i < argc; i++) {
+               if (zpool_vdev_remove(zhp, argv[i]) != 0)
+                       ret = 1;
+       }
+       zpool_close(zhp);
+
+       return (ret);
+}
+
+/*
+ * zpool labelclear <vdev>
+ *
+ * Verifies that the vdev is not active and zeros out the label information
+ * on the device.
+ */
+int
+zpool_do_labelclear(int argc, char **argv)
+{
+       char *vdev, *name;
+       int c, fd = -1, ret = 0;
+       pool_state_t state;
+       boolean_t inuse = B_FALSE;
+       boolean_t force = B_FALSE;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "f")) != -1) {
+               switch (c) {
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               default:
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get vdev name */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing vdev device name\n"));
+               usage(B_FALSE);
+       }
+
+       vdev = argv[0];
+       if ((fd = open(vdev, O_RDWR)) < 0) {
+               (void) fprintf(stderr, gettext("Unable to open %s\n"), vdev);
+               return (B_FALSE);
+       }
+
+       name = NULL;
+       if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0) {
+               if (force)
+                       goto wipe_label;
+
+               (void) fprintf(stderr,
+                   gettext("Unable to determine pool state for %s\n"
+                   "Use -f to force the clearing any label data\n"), vdev);
+
+               return (1);
+       }
+
+       if (inuse) {
+               switch (state) {
+               default:
+               case POOL_STATE_ACTIVE:
+               case POOL_STATE_SPARE:
+               case POOL_STATE_L2CACHE:
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n"
+                           "\tVdev %s is a member (%s), of pool \"%s\".\n"
+                           "\tTo remove label information from this device, "
+                           "export or destroy\n\tthe pool, or remove %s from "
+                           "the configuration of this pool\n\tand retry the "
+                           "labelclear operation.\n"),
+                           vdev, zpool_pool_state_to_name(state), name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_EXPORTED:
+                       if (force)
+                               break;
+
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n\tVdev "
+                           "%s is a member of the exported pool \"%s\".\n"
+                           "\tUse \"zpool labelclear -f %s\" to force the "
+                           "removal of label\n\tinformation.\n"),
+                           vdev, name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_POTENTIALLY_ACTIVE:
+                       if (force)
+                               break;
+
+                       (void) fprintf(stderr,
+                           gettext("labelclear operation failed.\n"
+                           "\tVdev %s is a member of the pool \"%s\".\n"
+                           "\tThis pool is unknown to this system, but may "
+                           "be active on\n\tanother system. Use "
+                           "\'zpool labelclear -f %s\' to force the\n"
+                           "\tremoval of label information.\n"),
+                           vdev, name, vdev);
+                       ret = 1;
+                       goto errout;
+
+               case POOL_STATE_DESTROYED:
+                       /* inuse should never be set for a destroyed pool... */
+                       break;
+               }
+       }
+
+wipe_label:
+       if (zpool_clear_label(fd) != 0) {
+               (void) fprintf(stderr,
+                   gettext("Label clear failed on vdev %s\n"), vdev);
+               ret = 1;
+       }
+
+errout:
+       close(fd);
+       if (name != NULL)
+               free(name);
+
+       return (ret);
+}
+
+/*
+ * zpool create [-fnd] [-o property=value] ...
+ *             [-O file-system-property=value] ...
+ *             [-R root] [-m mountpoint] <pool> <dev> ...
+ *
+ *     -f      Force creation, even if devices appear in use
+ *     -n      Do not create the pool, but display the resulting layout if it
+ *             were to be created.
+ *      -R     Create a pool under an alternate root
+ *      -m     Set default mountpoint for the root dataset.  By default it's
+ *             '/<pool>'
+ *     -o      Set property=value.
+ *     -o      Set feature@feature=enabled|disabled.
+ *     -d      Don't automatically enable all supported pool features
+ *             (individual features can be enabled with -o).
+ *     -O      Set fsproperty=value in the pool's root file system
+ *
+ * Creates the named pool according to the given vdev specification.  The
+ * bulk of the vdev processing is done in get_vdev_spec() in zpool_vdev.c.  Once
+ * we get the nvlist back from get_vdev_spec(), we either print out the contents
+ * (if '-n' was specified), or pass it to libzfs to do the creation.
+ */
+int
+zpool_do_create(int argc, char **argv)
+{
+       boolean_t force = B_FALSE;
+       boolean_t dryrun = B_FALSE;
+       boolean_t enable_all_pool_feat = B_TRUE;
+       int c;
+       nvlist_t *nvroot = NULL;
+       char *poolname;
+       char *tname = NULL;
+       int ret = 1;
+       char *altroot = NULL;
+       char *mountpoint = NULL;
+       nvlist_t *fsprops = NULL;
+       nvlist_t *props = NULL;
+       char *propval;
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":fndR:m:o:O:t:")) != -1) {
+               switch (c) {
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               case 'n':
+                       dryrun = B_TRUE;
+                       break;
+               case 'd':
+                       enable_all_pool_feat = B_FALSE;
+                       break;
+               case 'R':
+                       altroot = optarg;
+                       if (add_prop_list(zpool_prop_to_name(
+                           ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
+                               goto errout;
+                       if (add_prop_list_default(zpool_prop_to_name(
+                           ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+                               goto errout;
+                       break;
+               case 'm':
+                       /* Equivalent to -O mountpoint=optarg */
+                       mountpoint = optarg;
+                       break;
+               case 'o':
+                       if ((propval = strchr(optarg, '=')) == NULL) {
+                               (void) fprintf(stderr, gettext("missing "
+                                   "'=' for -o option\n"));
+                               goto errout;
+                       }
+                       *propval = '\0';
+                       propval++;
+
+                       if (add_prop_list(optarg, propval, &props, B_TRUE))
+                               goto errout;
+
+                       /*
+                        * If the user is creating a pool that doesn't support
+                        * feature flags, don't enable any features.
+                        */
+                       if (zpool_name_to_prop(optarg) == ZPOOL_PROP_VERSION) {
+                               char *end;
+                               u_longlong_t ver;
+
+                               ver = strtoull(propval, &end, 10);
+                               if (*end == '\0' &&
+                                   ver < SPA_VERSION_FEATURES) {
+                                       enable_all_pool_feat = B_FALSE;
+                               }
+                       }
+                       if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT)
+                               altroot = propval;
+                       break;
+               case 'O':
+                       if ((propval = strchr(optarg, '=')) == NULL) {
+                               (void) fprintf(stderr, gettext("missing "
+                                   "'=' for -O option\n"));
+                               goto errout;
+                       }
+                       *propval = '\0';
+                       propval++;
+
+                       /*
+                        * Mountpoints are checked and then added later.
+                        * Uniquely among properties, they can be specified
+                        * more than once, to avoid conflict with -m.
+                        */
+                       if (0 == strcmp(optarg,
+                           zfs_prop_to_name(ZFS_PROP_MOUNTPOINT))) {
+                               mountpoint = propval;
+                       } else if (add_prop_list(optarg, propval, &fsprops,
+                           B_FALSE)) {
+                               goto errout;
+                       }
+                       break;
+               case 't':
+                       /*
+                        * Sanity check temporary pool name.
+                        */
+                       if (strchr(optarg, '/') != NULL) {
+                               (void) fprintf(stderr, gettext("cannot create "
+                                   "'%s': invalid character '/' in temporary "
+                                   "name\n"), optarg);
+                               (void) fprintf(stderr, gettext("use 'zfs "
+                                   "create' to create a dataset\n"));
+                               goto errout;
+                       }
+
+                       if (add_prop_list(zpool_prop_to_name(
+                           ZPOOL_PROP_TNAME), optarg, &props, B_TRUE))
+                               goto errout;
+                       if (add_prop_list_default(zpool_prop_to_name(
+                           ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+                               goto errout;
+                       tname = optarg;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       goto badusage;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       goto badusage;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name argument\n"));
+               goto badusage;
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing vdev specification\n"));
+               goto badusage;
+       }
+
+       poolname = argv[0];
+
+       /*
+        * As a special case, check for use of '/' in the name, and direct the
+        * user to use 'zfs create' instead.
+        */
+       if (strchr(poolname, '/') != NULL) {
+               (void) fprintf(stderr, gettext("cannot create '%s': invalid "
+                   "character '/' in pool name\n"), poolname);
+               (void) fprintf(stderr, gettext("use 'zfs create' to "
+                   "create a dataset\n"));
+               goto errout;
+       }
+
+       /* pass off to get_vdev_spec for bulk processing */
+       nvroot = make_root_vdev(NULL, props, force, !force, B_FALSE, dryrun,
+           argc - 1, argv + 1);
+       if (nvroot == NULL)
+               goto errout;
+
+       /* make_root_vdev() allows 0 toplevel children if there are spares */
+       if (!zfs_allocatable_devs(nvroot)) {
+               (void) fprintf(stderr, gettext("invalid vdev "
+                   "specification: at least one toplevel vdev must be "
+                   "specified\n"));
+               goto errout;
+       }
+
+       if (altroot != NULL && altroot[0] != '/') {
+               (void) fprintf(stderr, gettext("invalid alternate root '%s': "
+                   "must be an absolute path\n"), altroot);
+               goto errout;
+       }
+
+       /*
+        * Check the validity of the mountpoint and direct the user to use the
+        * '-m' mountpoint option if it looks like its in use.
+        */
+       if (mountpoint == NULL ||
+           (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
+           strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) != 0)) {
+               char buf[MAXPATHLEN];
+               DIR *dirp;
+
+               if (mountpoint && mountpoint[0] != '/') {
+                       (void) fprintf(stderr, gettext("invalid mountpoint "
+                           "'%s': must be an absolute path, 'legacy', or "
+                           "'none'\n"), mountpoint);
+                       goto errout;
+               }
+
+               if (mountpoint == NULL) {
+                       if (altroot != NULL)
+                               (void) snprintf(buf, sizeof (buf), "%s/%s",
+                                   altroot, poolname);
+                       else
+                               (void) snprintf(buf, sizeof (buf), "/%s",
+                                   poolname);
+               } else {
+                       if (altroot != NULL)
+                               (void) snprintf(buf, sizeof (buf), "%s%s",
+                                   altroot, mountpoint);
+                       else
+                               (void) snprintf(buf, sizeof (buf), "%s",
+                                   mountpoint);
+               }
+
+               if ((dirp = opendir(buf)) == NULL && errno != ENOENT) {
+                       (void) fprintf(stderr, gettext("mountpoint '%s' : "
+                           "%s\n"), buf, strerror(errno));
+                       (void) fprintf(stderr, gettext("use '-m' "
+                           "option to provide a different default\n"));
+                       goto errout;
+               } else if (dirp) {
+                       int count = 0;
+
+                       while (count < 3 && readdir(dirp) != NULL)
+                               count++;
+                       (void) closedir(dirp);
+
+                       if (count > 2) {
+                               (void) fprintf(stderr, gettext("mountpoint "
+                                   "'%s' exists and is not empty\n"), buf);
+                               (void) fprintf(stderr, gettext("use '-m' "
+                                   "option to provide a "
+                                   "different default\n"));
+                               goto errout;
+                       }
+               }
+       }
+
+       /*
+        * Now that the mountpoint's validity has been checked, ensure that
+        * the property is set appropriately prior to creating the pool.
+        */
+       if (mountpoint != NULL) {
+               ret = add_prop_list(zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
+                   mountpoint, &fsprops, B_FALSE);
+               if (ret != 0)
+                       goto errout;
+       }
+
+       ret = 1;
+       if (dryrun) {
+               /*
+                * For a dry run invocation, print out a basic message and run
+                * through all the vdevs in the list and print out in an
+                * appropriate hierarchy.
+                */
+               (void) printf(gettext("would create '%s' with the "
+                   "following layout:\n\n"), poolname);
+
+               print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE, 0);
+               if (num_logs(nvroot) > 0)
+                       print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE, 0);
+
+               ret = 0;
+       } else {
+               /*
+                * Hand off to libzfs.
+                */
+               spa_feature_t i;
+               for (i = 0; i < SPA_FEATURES; i++) {
+                       char propname[MAXPATHLEN];
+                       char *propval;
+                       zfeature_info_t *feat = &spa_feature_table[i];
+
+                       (void) snprintf(propname, sizeof (propname),
+                           "feature@%s", feat->fi_uname);
+
+                       /*
+                        * Only features contained in props will be enabled:
+                        * remove from the nvlist every ZFS_FEATURE_DISABLED
+                        * value and add every missing ZFS_FEATURE_ENABLED if
+                        * enable_all_pool_feat is set.
+                        */
+                       if (!nvlist_lookup_string(props, propname, &propval)) {
+                               if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0)
+                                       (void) nvlist_remove_all(props,
+                                           propname);
+                       } else if (enable_all_pool_feat) {
+                               ret = add_prop_list(propname,
+                                   ZFS_FEATURE_ENABLED, &props, B_TRUE);
+                               if (ret != 0)
+                                       goto errout;
+                       }
+               }
+
+               ret = 1;
+               if (zpool_create(g_zfs, poolname,
+                   nvroot, props, fsprops) == 0) {
+                       zfs_handle_t *pool = zfs_open(g_zfs,
+                           tname ? tname : poolname, ZFS_TYPE_FILESYSTEM);
+                       if (pool != NULL) {
+                               if (zfs_mount(pool, NULL, 0) == 0)
+                                       ret = zfs_shareall(pool);
+                               zfs_close(pool);
+                       }
+               } else if (libzfs_errno(g_zfs) == EZFS_INVALIDNAME) {
+                       (void) fprintf(stderr, gettext("pool name may have "
+                           "been omitted\n"));
+               }
+       }
+
+errout:
+       nvlist_free(nvroot);
+       nvlist_free(fsprops);
+       nvlist_free(props);
+       return (ret);
+badusage:
+       nvlist_free(fsprops);
+       nvlist_free(props);
+       usage(B_FALSE);
+       return (2);
+}
+
+/*
+ * zpool destroy <pool>
+ *
+ *     -f      Forcefully unmount any datasets
+ *
+ * Destroy the given pool.  Automatically unmounts any datasets in the pool.
+ */
+int
+zpool_do_destroy(int argc, char **argv)
+{
+       boolean_t force = B_FALSE;
+       int c;
+       char *pool;
+       zpool_handle_t *zhp;
+       int ret;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "f")) != -1) {
+               switch (c) {
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* check arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool argument\n"));
+               usage(B_FALSE);
+       }
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       pool = argv[0];
+
+       if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
+               /*
+                * As a special case, check for use of '/' in the name, and
+                * direct the user to use 'zfs destroy' instead.
+                */
+               if (strchr(pool, '/') != NULL)
+                       (void) fprintf(stderr, gettext("use 'zfs destroy' to "
+                           "destroy a dataset\n"));
+               return (1);
+       }
+
+       if (zpool_disable_datasets(zhp, force) != 0) {
+               (void) fprintf(stderr, gettext("could not destroy '%s': "
+                   "could not unmount datasets\n"), zpool_get_name(zhp));
+               zpool_close(zhp);
+               return (1);
+       }
+
+       /* The history must be logged as part of the export */
+       log_history = B_FALSE;
+
+       ret = (zpool_destroy(zhp, history_str) != 0);
+
+       zpool_close(zhp);
+
+       return (ret);
+}
+
+typedef struct export_cbdata {
+       boolean_t force;
+       boolean_t hardforce;
+} export_cbdata_t;
+
+/*
+ * Export one pool
+ */
+int
+zpool_export_one(zpool_handle_t *zhp, void *data)
+{
+       export_cbdata_t *cb = data;
+
+       if (zpool_disable_datasets(zhp, cb->force) != 0)
+               return (1);
+
+       /* The history must be logged as part of the export */
+       log_history = B_FALSE;
+
+       if (cb->hardforce) {
+               if (zpool_export_force(zhp, history_str) != 0)
+                       return (1);
+       } else if (zpool_export(zhp, cb->force, history_str) != 0) {
+               return (1);
+       }
+
+       return (0);
+}
+
+/*
+ * zpool export [-f] <pool> ...
+ *
+ *     -a      Export all pools
+ *     -f      Forcefully unmount datasets
+ *
+ * Export the given pools.  By default, the command will attempt to cleanly
+ * unmount any active datasets within the pool.  If the '-f' flag is specified,
+ * then the datasets will be forcefully unmounted.
+ */
+int
+zpool_do_export(int argc, char **argv)
+{
+       export_cbdata_t cb;
+       boolean_t do_all = B_FALSE;
+       boolean_t force = B_FALSE;
+       boolean_t hardforce = B_FALSE;
+       int c, ret;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "afF")) != -1) {
+               switch (c) {
+               case 'a':
+                       do_all = B_TRUE;
+                       break;
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               case 'F':
+                       hardforce = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       cb.force = force;
+       cb.hardforce = hardforce;
+       argc -= optind;
+       argv += optind;
+
+       if (do_all) {
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+
+               return (for_each_pool(argc, argv, B_TRUE, NULL,
+                   zpool_export_one, &cb));
+       }
+
+       /* check arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool argument\n"));
+               usage(B_FALSE);
+       }
+
+       ret = for_each_pool(argc, argv, B_TRUE, NULL, zpool_export_one, &cb);
+
+       return (ret);
+}
+
+/*
+ * Given a vdev configuration, determine the maximum width needed for the device
+ * name column.
+ */
+static int
+max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max,
+    int name_flags)
+{
+       char *name;
+       nvlist_t **child;
+       uint_t c, children;
+       int ret;
+
+       name = zpool_vdev_name(g_zfs, zhp, nv, name_flags | VDEV_NAME_TYPE_ID);
+       if (strlen(name) + depth > max)
+               max = strlen(name) + depth;
+
+       free(name);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if ((ret = max_width(zhp, child[c], depth + 2,
+                           max, name_flags)) > max)
+                               max = ret;
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if ((ret = max_width(zhp, child[c], depth + 2,
+                           max, name_flags)) > max)
+                               max = ret;
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if ((ret = max_width(zhp, child[c], depth + 2,
+                           max, name_flags)) > max)
+                               max = ret;
+       }
+
+       return (max);
+}
+
+typedef struct spare_cbdata {
+       uint64_t        cb_guid;
+       zpool_handle_t  *cb_zhp;
+} spare_cbdata_t;
+
+static boolean_t
+find_vdev(nvlist_t *nv, uint64_t search)
+{
+       uint64_t guid;
+       nvlist_t **child;
+       uint_t c, children;
+
+       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0 &&
+           search == guid)
+               return (B_TRUE);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if (find_vdev(child[c], search))
+                               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+static int
+find_spare(zpool_handle_t *zhp, void *data)
+{
+       spare_cbdata_t *cbp = data;
+       nvlist_t *config, *nvroot;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+
+       if (find_vdev(nvroot, cbp->cb_guid)) {
+               cbp->cb_zhp = zhp;
+               return (1);
+       }
+
+       zpool_close(zhp);
+       return (0);
+}
+
+typedef struct status_cbdata {
+       int             cb_count;
+       int             cb_name_flags;
+       int             cb_namewidth;
+       boolean_t       cb_allpools;
+       boolean_t       cb_verbose;
+       boolean_t       cb_explain;
+       boolean_t       cb_first;
+       boolean_t       cb_dedup_stats;
+       boolean_t       cb_print_status;
+} status_cbdata_t;
+
+/*
+ * Print out configuration state as requested by status_callback.
+ */
+static void
+print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name,
+    nvlist_t *nv, int depth, boolean_t isspare)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       pool_scan_stat_t *ps = NULL;
+       vdev_stat_t *vs;
+       char rbuf[6], wbuf[6], cbuf[6];
+       char *vname;
+       uint64_t notpresent;
+       spare_cbdata_t spare_cb;
+       char *state;
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               children = 0;
+
+       verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &c) == 0);
+
+       state = zpool_state_to_name(vs->vs_state, vs->vs_aux);
+       if (isspare) {
+               /*
+                * For hot spares, we use the terms 'INUSE' and 'AVAILABLE' for
+                * online drives.
+                */
+               if (vs->vs_aux == VDEV_AUX_SPARED)
+                       state = "INUSE";
+               else if (vs->vs_state == VDEV_STATE_HEALTHY)
+                       state = "AVAIL";
+       }
+
+       (void) printf("\t%*s%-*s  %-8s", depth, "", cb->cb_namewidth - depth,
+           name, state);
+
+       if (!isspare) {
+               zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf));
+               zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf));
+               zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf));
+               (void) printf(" %5s %5s %5s", rbuf, wbuf, cbuf);
+       }
+
+       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
+           &notpresent) == 0) {
+               char *path;
+               verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0);
+               (void) printf("  was %s", path);
+       } else if (vs->vs_aux != 0) {
+               (void) printf("  ");
+
+               switch (vs->vs_aux) {
+               case VDEV_AUX_OPEN_FAILED:
+                       (void) printf(gettext("cannot open"));
+                       break;
+
+               case VDEV_AUX_BAD_GUID_SUM:
+                       (void) printf(gettext("missing device"));
+                       break;
+
+               case VDEV_AUX_NO_REPLICAS:
+                       (void) printf(gettext("insufficient replicas"));
+                       break;
+
+               case VDEV_AUX_VERSION_NEWER:
+                       (void) printf(gettext("newer version"));
+                       break;
+
+               case VDEV_AUX_UNSUP_FEAT:
+                       (void) printf(gettext("unsupported feature(s)"));
+                       break;
+
+               case VDEV_AUX_SPARED:
+                       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
+                           &spare_cb.cb_guid) == 0);
+                       if (zpool_iter(g_zfs, find_spare, &spare_cb) == 1) {
+                               if (strcmp(zpool_get_name(spare_cb.cb_zhp),
+                                   zpool_get_name(zhp)) == 0)
+                                       (void) printf(gettext("currently in "
+                                           "use"));
+                               else
+                                       (void) printf(gettext("in use by "
+                                           "pool '%s'"),
+                                           zpool_get_name(spare_cb.cb_zhp));
+                               zpool_close(spare_cb.cb_zhp);
+                       } else {
+                               (void) printf(gettext("currently in use"));
+                       }
+                       break;
+
+               case VDEV_AUX_ERR_EXCEEDED:
+                       (void) printf(gettext("too many errors"));
+                       break;
+
+               case VDEV_AUX_IO_FAILURE:
+                       (void) printf(gettext("experienced I/O failures"));
+                       break;
+
+               case VDEV_AUX_BAD_LOG:
+                       (void) printf(gettext("bad intent log"));
+                       break;
+
+               case VDEV_AUX_EXTERNAL:
+                       (void) printf(gettext("external device fault"));
+                       break;
+
+               case VDEV_AUX_SPLIT_POOL:
+                       (void) printf(gettext("split into new pool"));
+                       break;
+
+               default:
+                       (void) printf(gettext("corrupted data"));
+                       break;
+               }
+       }
+
+       (void) nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS,
+           (uint64_t **)&ps, &c);
+
+       if (ps && ps->pss_state == DSS_SCANNING &&
+           vs->vs_scan_processed != 0 && children == 0) {
+               (void) printf(gettext("  (%s)"),
+                   (ps->pss_func == POOL_SCAN_RESILVER) ?
+                   "resilvering" : "repairing");
+       }
+
+       (void) printf("\n");
+
+       for (c = 0; c < children; c++) {
+               uint64_t islog = B_FALSE, ishole = B_FALSE;
+
+               /* Don't print logs or holes here */
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &islog);
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
+                   &ishole);
+               if (islog || ishole)
+                       continue;
+               vname = zpool_vdev_name(g_zfs, zhp, child[c],
+                   cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+               print_status_config(zhp, cb, vname, child[c], depth + 2,
+                   isspare);
+               free(vname);
+       }
+}
+
+/*
+ * Print the configuration of an exported pool.  Iterate over all vdevs in the
+ * pool, printing out the name and status for each one.
+ */
+static void
+print_import_config(status_cbdata_t *cb, const char *name, nvlist_t *nv,
+    int depth)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       vdev_stat_t *vs;
+       char *type, *vname;
+
+       verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+       if (strcmp(type, VDEV_TYPE_MISSING) == 0 ||
+           strcmp(type, VDEV_TYPE_HOLE) == 0)
+               return;
+
+       verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &c) == 0);
+
+       (void) printf("\t%*s%-*s", depth, "", cb->cb_namewidth - depth, name);
+       (void) printf("  %s", zpool_state_to_name(vs->vs_state, vs->vs_aux));
+
+       if (vs->vs_aux != 0) {
+               (void) printf("  ");
+
+               switch (vs->vs_aux) {
+               case VDEV_AUX_OPEN_FAILED:
+                       (void) printf(gettext("cannot open"));
+                       break;
+
+               case VDEV_AUX_BAD_GUID_SUM:
+                       (void) printf(gettext("missing device"));
+                       break;
+
+               case VDEV_AUX_NO_REPLICAS:
+                       (void) printf(gettext("insufficient replicas"));
+                       break;
+
+               case VDEV_AUX_VERSION_NEWER:
+                       (void) printf(gettext("newer version"));
+                       break;
+
+               case VDEV_AUX_UNSUP_FEAT:
+                       (void) printf(gettext("unsupported feature(s)"));
+                       break;
+
+               case VDEV_AUX_ERR_EXCEEDED:
+                       (void) printf(gettext("too many errors"));
+                       break;
+
+               default:
+                       (void) printf(gettext("corrupted data"));
+                       break;
+               }
+       }
+       (void) printf("\n");
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               return;
+
+       for (c = 0; c < children; c++) {
+               uint64_t is_log = B_FALSE;
+
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &is_log);
+               if (is_log)
+                       continue;
+
+               vname = zpool_vdev_name(g_zfs, NULL, child[c],
+                   cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+               print_import_config(cb, vname, child[c], depth + 2);
+               free(vname);
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+           &child, &children) == 0) {
+               (void) printf(gettext("\tcache\n"));
+               for (c = 0; c < children; c++) {
+                       vname = zpool_vdev_name(g_zfs, NULL, child[c],
+                           cb->cb_name_flags);
+                       (void) printf("\t  %s\n", vname);
+                       free(vname);
+               }
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+           &child, &children) == 0) {
+               (void) printf(gettext("\tspares\n"));
+               for (c = 0; c < children; c++) {
+                       vname = zpool_vdev_name(g_zfs, NULL, child[c],
+                           cb->cb_name_flags);
+                       (void) printf("\t  %s\n", vname);
+                       free(vname);
+               }
+       }
+}
+
+/*
+ * Print log vdevs.
+ * Logs are recorded as top level vdevs in the main pool child array
+ * but with "is_log" set to 1. We use either print_status_config() or
+ * print_import_config() to print the top level logs then any log
+ * children (eg mirrored slogs) are printed recursively - which
+ * works because only the top level vdev is marked "is_log"
+ */
+static void
+print_logs(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *nv)
+{
+       uint_t c, children;
+       nvlist_t **child;
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
+           &children) != 0)
+               return;
+
+       (void) printf(gettext("\tlogs\n"));
+
+       for (c = 0; c < children; c++) {
+               uint64_t is_log = B_FALSE;
+               char *name;
+
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &is_log);
+               if (!is_log)
+                       continue;
+               name = zpool_vdev_name(g_zfs, zhp, child[c],
+                   cb->cb_name_flags | VDEV_NAME_TYPE_ID);
+               if (cb->cb_print_status)
+                       print_status_config(zhp, cb, name, child[c], 2,
+                           B_FALSE);
+               else
+                       print_import_config(cb, name, child[c], 2);
+               free(name);
+       }
+}
+
+/*
+ * Display the status for the given pool.
+ */
+static void
+show_import(nvlist_t *config)
+{
+       uint64_t pool_state;
+       vdev_stat_t *vs;
+       char *name;
+       uint64_t guid;
+       char *msgid;
+       nvlist_t *nvroot;
+       zpool_status_t reason;
+       zpool_errata_t errata;
+       const char *health;
+       uint_t vsc;
+       char *comment;
+       status_cbdata_t cb = { 0 };
+
+       verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+           &name) == 0);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+           &guid) == 0);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+           &pool_state) == 0);
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+
+       verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &vsc) == 0);
+       health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
+
+       reason = zpool_import_status(config, &msgid, &errata);
+
+       (void) printf(gettext("   pool: %s\n"), name);
+       (void) printf(gettext("     id: %llu\n"), (u_longlong_t)guid);
+       (void) printf(gettext("  state: %s"), health);
+       if (pool_state == POOL_STATE_DESTROYED)
+               (void) printf(gettext(" (DESTROYED)"));
+       (void) printf("\n");
+
+       switch (reason) {
+       case ZPOOL_STATUS_MISSING_DEV_R:
+       case ZPOOL_STATUS_MISSING_DEV_NR:
+       case ZPOOL_STATUS_BAD_GUID_SUM:
+               (void) printf(gettext(" status: One or more devices are "
+                   "missing from the system.\n"));
+               break;
+
+       case ZPOOL_STATUS_CORRUPT_LABEL_R:
+       case ZPOOL_STATUS_CORRUPT_LABEL_NR:
+               (void) printf(gettext(" status: One or more devices contains "
+                   "corrupted data.\n"));
+               break;
+
+       case ZPOOL_STATUS_CORRUPT_DATA:
+               (void) printf(
+                   gettext(" status: The pool data is corrupted.\n"));
+               break;
+
+       case ZPOOL_STATUS_OFFLINE_DEV:
+               (void) printf(gettext(" status: One or more devices "
+                   "are offlined.\n"));
+               break;
+
+       case ZPOOL_STATUS_CORRUPT_POOL:
+               (void) printf(gettext(" status: The pool metadata is "
+                   "corrupted.\n"));
+               break;
+
+       case ZPOOL_STATUS_VERSION_OLDER:
+               (void) printf(gettext(" status: The pool is formatted using a "
+                   "legacy on-disk version.\n"));
+               break;
+
+       case ZPOOL_STATUS_VERSION_NEWER:
+               (void) printf(gettext(" status: The pool is formatted using an "
+                   "incompatible version.\n"));
+               break;
+
+       case ZPOOL_STATUS_FEAT_DISABLED:
+               (void) printf(gettext(" status: Some supported features are "
+                   "not enabled on the pool.\n"));
+               break;
+
+       case ZPOOL_STATUS_UNSUP_FEAT_READ:
+               (void) printf(gettext("status: The pool uses the following "
+                   "feature(s) not supported on this sytem:\n"));
+               zpool_print_unsup_feat(config);
+               break;
+
+       case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+               (void) printf(gettext("status: The pool can only be accessed "
+                   "in read-only mode on this system. It\n\tcannot be "
+                   "accessed in read-write mode because it uses the "
+                   "following\n\tfeature(s) not supported on this system:\n"));
+               zpool_print_unsup_feat(config);
+               break;
+
+       case ZPOOL_STATUS_HOSTID_MISMATCH:
+               (void) printf(gettext(" status: The pool was last accessed by "
+                   "another system.\n"));
+               break;
+
+       case ZPOOL_STATUS_FAULTED_DEV_R:
+       case ZPOOL_STATUS_FAULTED_DEV_NR:
+               (void) printf(gettext(" status: One or more devices are "
+                   "faulted.\n"));
+               break;
+
+       case ZPOOL_STATUS_BAD_LOG:
+               (void) printf(gettext(" status: An intent log record cannot be "
+                   "read.\n"));
+               break;
+
+       case ZPOOL_STATUS_RESILVERING:
+               (void) printf(gettext(" status: One or more devices were being "
+                   "resilvered.\n"));
+               break;
+
+       case ZPOOL_STATUS_ERRATA:
+               (void) printf(gettext(" status: Errata #%d detected.\n"),
+                   errata);
+               break;
+
+       default:
+               /*
+                * No other status can be seen when importing pools.
+                */
+               assert(reason == ZPOOL_STATUS_OK);
+       }
+
+       /*
+        * Print out an action according to the overall state of the pool.
+        */
+       if (vs->vs_state == VDEV_STATE_HEALTHY) {
+               if (reason == ZPOOL_STATUS_VERSION_OLDER ||
+                   reason == ZPOOL_STATUS_FEAT_DISABLED) {
+                       (void) printf(gettext(" action: The pool can be "
+                           "imported using its name or numeric identifier, "
+                           "though\n\tsome features will not be available "
+                           "without an explicit 'zpool upgrade'.\n"));
+               } else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) {
+                       (void) printf(gettext(" action: The pool can be "
+                           "imported using its name or numeric "
+                           "identifier and\n\tthe '-f' flag.\n"));
+               } else if (reason == ZPOOL_STATUS_ERRATA) {
+                       switch (errata) {
+                       case ZPOOL_ERRATA_NONE:
+                               break;
+
+                       case ZPOOL_ERRATA_ZOL_2094_SCRUB:
+                               (void) printf(gettext(" action: The pool can "
+                                   "be imported using its name or numeric "
+                                   "identifier,\n\thowever there is a compat"
+                                   "ibility issue which should be corrected"
+                                   "\n\tby running 'zpool scrub'\n"));
+                               break;
+
+                       case ZPOOL_ERRATA_ZOL_2094_ASYNC_DESTROY:
+                               (void) printf(gettext(" action: The pool can"
+                                   "not be imported with this version of ZFS "
+                                   "due to\n\tan active asynchronous destroy. "
+                                   "Revert to an earlier version\n\tand "
+                                   "allow the destroy to complete before "
+                                   "updating.\n"));
+                               break;
+
+                       default:
+                               /*
+                                * All errata must contain an action message.
+                                */
+                               assert(0);
+                       }
+               } else {
+                       (void) printf(gettext(" action: The pool can be "
+                           "imported using its name or numeric "
+                           "identifier.\n"));
+               }
+       } else if (vs->vs_state == VDEV_STATE_DEGRADED) {
+               (void) printf(gettext(" action: The pool can be imported "
+                   "despite missing or damaged devices.  The\n\tfault "
+                   "tolerance of the pool may be compromised if imported.\n"));
+       } else {
+               switch (reason) {
+               case ZPOOL_STATUS_VERSION_NEWER:
+                       (void) printf(gettext(" action: The pool cannot be "
+                           "imported.  Access the pool on a system running "
+                           "newer\n\tsoftware, or recreate the pool from "
+                           "backup.\n"));
+                       break;
+               case ZPOOL_STATUS_UNSUP_FEAT_READ:
+                       (void) printf(gettext("action: The pool cannot be "
+                           "imported. Access the pool on a system that "
+                           "supports\n\tthe required feature(s), or recreate "
+                           "the pool from backup.\n"));
+                       break;
+               case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+                       (void) printf(gettext("action: The pool cannot be "
+                           "imported in read-write mode. Import the pool "
+                           "with\n"
+                           "\t\"-o readonly=on\", access the pool on a system "
+                           "that supports the\n\trequired feature(s), or "
+                           "recreate the pool from backup.\n"));
+                       break;
+               case ZPOOL_STATUS_MISSING_DEV_R:
+               case ZPOOL_STATUS_MISSING_DEV_NR:
+               case ZPOOL_STATUS_BAD_GUID_SUM:
+                       (void) printf(gettext(" action: The pool cannot be "
+                           "imported. Attach the missing\n\tdevices and try "
+                           "again.\n"));
+                       break;
+               default:
+                       (void) printf(gettext(" action: The pool cannot be "
+                           "imported due to damaged devices or data.\n"));
+               }
+       }
+
+       /* Print the comment attached to the pool. */
+       if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0)
+               (void) printf(gettext("comment: %s\n"), comment);
+
+       /*
+        * If the state is "closed" or "can't open", and the aux state
+        * is "corrupt data":
+        */
+       if (((vs->vs_state == VDEV_STATE_CLOSED) ||
+           (vs->vs_state == VDEV_STATE_CANT_OPEN)) &&
+           (vs->vs_aux == VDEV_AUX_CORRUPT_DATA)) {
+               if (pool_state == POOL_STATE_DESTROYED)
+                       (void) printf(gettext("\tThe pool was destroyed, "
+                           "but can be imported using the '-Df' flags.\n"));
+               else if (pool_state != POOL_STATE_EXPORTED)
+                       (void) printf(gettext("\tThe pool may be active on "
+                           "another system, but can be imported using\n\t"
+                           "the '-f' flag.\n"));
+       }
+
+       if (msgid != NULL)
+               (void) printf(gettext("   see: http://zfsonlinux.org/msg/%s\n"),
+                   msgid);
+
+       (void) printf(gettext(" config:\n\n"));
+
+       cb.cb_namewidth = max_width(NULL, nvroot, 0, 0, 0);
+       if (cb.cb_namewidth < 10)
+               cb.cb_namewidth = 10;
+
+       print_import_config(&cb, name, nvroot, 0);
+       if (num_logs(nvroot) > 0)
+               print_logs(NULL, &cb, nvroot);
+
+       if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
+               (void) printf(gettext("\n\tAdditional devices are known to "
+                   "be part of this pool, though their\n\texact "
+                   "configuration cannot be determined.\n"));
+       }
+}
+
+/*
+ * Perform the import for the given configuration.  This passes the heavy
+ * lifting off to zpool_import_props(), and then mounts the datasets contained
+ * within the pool.
+ */
+static int
+do_import(nvlist_t *config, const char *newname, const char *mntopts,
+    nvlist_t *props, int flags)
+{
+       zpool_handle_t *zhp;
+       char *name;
+       uint64_t state;
+       uint64_t version;
+
+       verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+           &name) == 0);
+
+       verify(nvlist_lookup_uint64(config,
+           ZPOOL_CONFIG_POOL_STATE, &state) == 0);
+       verify(nvlist_lookup_uint64(config,
+           ZPOOL_CONFIG_VERSION, &version) == 0);
+       if (!SPA_VERSION_IS_SUPPORTED(version)) {
+               (void) fprintf(stderr, gettext("cannot import '%s': pool "
+                   "is formatted using an unsupported ZFS version\n"), name);
+               return (1);
+       } else if (state != POOL_STATE_EXPORTED &&
+           !(flags & ZFS_IMPORT_ANY_HOST)) {
+               uint64_t hostid = 0;
+               unsigned long system_hostid = get_system_hostid();
+
+               (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID,
+                   &hostid);
+
+               if (hostid != 0 && (unsigned long)hostid != system_hostid) {
+                       char *hostname;
+                       uint64_t timestamp;
+                       time_t t;
+
+                       verify(nvlist_lookup_string(config,
+                           ZPOOL_CONFIG_HOSTNAME, &hostname) == 0);
+                       verify(nvlist_lookup_uint64(config,
+                           ZPOOL_CONFIG_TIMESTAMP, &timestamp) == 0);
+                       t = timestamp;
+                       (void) fprintf(stderr, gettext("cannot import "
+                           "'%s': pool may be in use from other "
+                           "system, it was last accessed by %s "
+                           "(hostid: 0x%lx) on %s"), name, hostname,
+                           (unsigned long)hostid,
+                           asctime(localtime(&t)));
+                       (void) fprintf(stderr, gettext("use '-f' to "
+                           "import anyway\n"));
+                       return (1);
+               }
+       }
+
+       if (zpool_import_props(g_zfs, config, newname, props, flags) != 0)
+               return (1);
+
+       if (newname != NULL)
+               name = (char *)newname;
+
+       if ((zhp = zpool_open_canfail(g_zfs, name)) == NULL)
+               return (1);
+
+       if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
+           !(flags & ZFS_IMPORT_ONLY) &&
+           zpool_enable_datasets(zhp, mntopts, 0) != 0) {
+               zpool_close(zhp);
+               return (1);
+       }
+
+       zpool_close(zhp);
+       return (0);
+}
+
+/*
+ * zpool import [-d dir] [-D]
+ *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
+ *              [-d dir | -c cachefile] [-f] -a
+ *       import [-o mntopts] [-o prop=value] ... [-R root] [-D]
+ *              [-d dir | -c cachefile] [-f] [-n] [-F] <pool | id> [newpool]
+ *
+ *      -c     Read pool information from a cachefile instead of searching
+ *             devices.
+ *
+ *       -d    Scan in a specific directory, other than /dev/.  More than
+ *             one directory can be specified using multiple '-d' options.
+ *
+ *       -D     Scan for previously destroyed pools or import all or only
+ *              specified destroyed pools.
+ *
+ *       -R    Temporarily import the pool, with all mountpoints relative to
+ *             the given root.  The pool will remain exported when the machine
+ *             is rebooted.
+ *
+ *       -V    Import even in the presence of faulted vdevs.  This is an
+ *             intentionally undocumented option for testing purposes, and
+ *             treats the pool configuration as complete, leaving any bad
+ *             vdevs in the FAULTED state. In other words, it does verbatim
+ *             import.
+ *
+ *       -f    Force import, even if it appears that the pool is active.
+ *
+ *       -F     Attempt rewind if necessary.
+ *
+ *       -n     See if rewind would work, but don't actually rewind.
+ *
+ *       -N     Import the pool but don't mount datasets.
+ *
+ *       -T     Specify a starting txg to use for import. This option is
+ *             intentionally undocumented option for testing purposes.
+ *
+ *       -a    Import all pools found.
+ *
+ *       -o    Set property=value and/or temporary mount options (without '=').
+ *
+ *      -s     Scan using the default search path, the libblkid cache will
+ *             not be consulted.
+ *
+ * The import command scans for pools to import, and import pools based on pool
+ * name and GUID.  The pool can also be renamed as part of the import process.
+ */
+int
+zpool_do_import(int argc, char **argv)
+{
+       char **searchdirs = NULL;
+       char *env, *envdup = NULL;
+       int nsearch = 0;
+       int c;
+       int err = 0;
+       nvlist_t *pools = NULL;
+       boolean_t do_all = B_FALSE;
+       boolean_t do_destroyed = B_FALSE;
+       char *mntopts = NULL;
+       nvpair_t *elem;
+       nvlist_t *config;
+       uint64_t searchguid = 0;
+       char *searchname = NULL;
+       char *propval;
+       nvlist_t *found_config;
+       nvlist_t *policy = NULL;
+       nvlist_t *props = NULL;
+       boolean_t first;
+       int flags = ZFS_IMPORT_NORMAL;
+       uint32_t rewind_policy = ZPOOL_NO_REWIND;
+       boolean_t dryrun = B_FALSE;
+       boolean_t do_rewind = B_FALSE;
+       boolean_t xtreme_rewind = B_FALSE;
+       boolean_t do_scan = B_FALSE;
+       uint64_t pool_state, txg = -1ULL;
+       char *cachefile = NULL;
+       importargs_t idata = { 0 };
+       char *endptr;
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":aCc:d:DEfFmnNo:R:stT:VX")) != -1) {
+               switch (c) {
+               case 'a':
+                       do_all = B_TRUE;
+                       break;
+               case 'c':
+                       cachefile = optarg;
+                       break;
+               case 'd':
+                       if (searchdirs == NULL) {
+                               searchdirs = safe_malloc(sizeof (char *));
+                       } else {
+                               char **tmp = safe_malloc((nsearch + 1) *
+                                   sizeof (char *));
+                               bcopy(searchdirs, tmp, nsearch *
+                                   sizeof (char *));
+                               free(searchdirs);
+                               searchdirs = tmp;
+                       }
+                       searchdirs[nsearch++] = optarg;
+                       break;
+               case 'D':
+                       do_destroyed = B_TRUE;
+                       break;
+               case 'f':
+                       flags |= ZFS_IMPORT_ANY_HOST;
+                       break;
+               case 'F':
+                       do_rewind = B_TRUE;
+                       break;
+               case 'm':
+                       flags |= ZFS_IMPORT_MISSING_LOG;
+                       break;
+               case 'n':
+                       dryrun = B_TRUE;
+                       break;
+               case 'N':
+                       flags |= ZFS_IMPORT_ONLY;
+                       break;
+               case 'o':
+                       if ((propval = strchr(optarg, '=')) != NULL) {
+                               *propval = '\0';
+                               propval++;
+                               if (add_prop_list(optarg, propval,
+                                   &props, B_TRUE))
+                                       goto error;
+                       } else {
+                               mntopts = optarg;
+                       }
+                       break;
+               case 'R':
+                       if (add_prop_list(zpool_prop_to_name(
+                           ZPOOL_PROP_ALTROOT), optarg, &props, B_TRUE))
+                               goto error;
+                       if (add_prop_list_default(zpool_prop_to_name(
+                           ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+                               goto error;
+                       break;
+               case 's':
+                       do_scan = B_TRUE;
+                       break;
+               case 't':
+                       flags |= ZFS_IMPORT_TEMP_NAME;
+                       if (add_prop_list_default(zpool_prop_to_name(
+                           ZPOOL_PROP_CACHEFILE), "none", &props, B_TRUE))
+                               goto error;
+                       break;
+
+               case 'T':
+                       errno = 0;
+                       txg = strtoull(optarg, &endptr, 0);
+                       if (errno != 0 || *endptr != '\0') {
+                               (void) fprintf(stderr,
+                                   gettext("invalid txg value\n"));
+                               usage(B_FALSE);
+                       }
+                       rewind_policy = ZPOOL_DO_REWIND | ZPOOL_EXTREME_REWIND;
+                       break;
+               case 'V':
+                       flags |= ZFS_IMPORT_VERBATIM;
+                       break;
+               case 'X':
+                       xtreme_rewind = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (cachefile && nsearch != 0) {
+               (void) fprintf(stderr, gettext("-c is incompatible with -d\n"));
+               usage(B_FALSE);
+       }
+
+       if ((dryrun || xtreme_rewind) && !do_rewind) {
+               (void) fprintf(stderr,
+                   gettext("-n or -X only meaningful with -F\n"));
+               usage(B_FALSE);
+       }
+       if (dryrun)
+               rewind_policy = ZPOOL_TRY_REWIND;
+       else if (do_rewind)
+               rewind_policy = ZPOOL_DO_REWIND;
+       if (xtreme_rewind)
+               rewind_policy |= ZPOOL_EXTREME_REWIND;
+
+       /* In the future, we can capture further policy and include it here */
+       if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
+           nvlist_add_uint64(policy, ZPOOL_REWIND_REQUEST_TXG, txg) != 0 ||
+           nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
+               goto error;
+
+       /* check argument count */
+       if (do_all) {
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+       } else {
+               if (argc > 2) {
+                       (void) fprintf(stderr, gettext("too many arguments\n"));
+                       usage(B_FALSE);
+               }
+       }
+
+       /*
+        * Check for the effective uid.  We do this explicitly here because
+        * otherwise any attempt to discover pools will silently fail.
+        */
+       if (argc == 0 && geteuid() != 0) {
+               (void) fprintf(stderr, gettext("cannot "
+                   "discover pools: permission denied\n"));
+               if (searchdirs != NULL)
+                       free(searchdirs);
+
+               nvlist_free(props);
+               nvlist_free(policy);
+               return (1);
+       }
+
+       /*
+        * Depending on the arguments given, we do one of the following:
+        *
+        *      <none>  Iterate through all pools and display information about
+        *              each one.
+        *
+        *      -a      Iterate through all pools and try to import each one.
+        *
+        *      <id>    Find the pool that corresponds to the given GUID/pool
+        *              name and import that one.
+        *
+        *      -D      Above options applies only to destroyed pools.
+        */
+       if (argc != 0) {
+               char *endptr;
+
+               errno = 0;
+               searchguid = strtoull(argv[0], &endptr, 10);
+               if (errno != 0 || *endptr != '\0') {
+                       searchname = argv[0];
+                       searchguid = 0;
+               }
+               found_config = NULL;
+
+               /*
+                * User specified a name or guid.  Ensure it's unique.
+                */
+               idata.unique = B_TRUE;
+       }
+
+       /*
+        * Check the environment for the preferred search path.
+        */
+       if ((searchdirs == NULL) && (env = getenv("ZPOOL_IMPORT_PATH"))) {
+               char *dir;
+
+               envdup = strdup(env);
+
+               dir = strtok(envdup, ":");
+               while (dir != NULL) {
+                       if (searchdirs == NULL) {
+                               searchdirs = safe_malloc(sizeof (char *));
+                       } else {
+                               char **tmp = safe_malloc((nsearch + 1) *
+                                   sizeof (char *));
+                               bcopy(searchdirs, tmp, nsearch *
+                                   sizeof (char *));
+                               free(searchdirs);
+                               searchdirs = tmp;
+                       }
+                       searchdirs[nsearch++] = dir;
+                       dir = strtok(NULL, ":");
+               }
+       }
+
+       idata.path = searchdirs;
+       idata.paths = nsearch;
+       idata.poolname = searchname;
+       idata.guid = searchguid;
+       idata.cachefile = cachefile;
+       idata.scan = do_scan;
+
+       /*
+        * Under Linux the zpool_find_import_impl() function leverages the
+        * taskq implementation to parallelize device scanning.  It is
+        * therefore necessary to initialize this functionality for the
+        * duration of the zpool_search_import() function.
+        */
+       thread_init();
+       pools = zpool_search_import(g_zfs, &idata);
+       thread_fini();
+
+       if (pools != NULL && idata.exists &&
+           (argc == 1 || strcmp(argv[0], argv[1]) == 0)) {
+               (void) fprintf(stderr, gettext("cannot import '%s': "
+                   "a pool with that name already exists\n"),
+                   argv[0]);
+               (void) fprintf(stderr, gettext("use the form '%s "
+                   "<pool | id> <newpool>' to give it a new name\n"),
+                   "zpool import");
+               err = 1;
+       } else if (pools == NULL && idata.exists) {
+               (void) fprintf(stderr, gettext("cannot import '%s': "
+                   "a pool with that name is already created/imported,\n"),
+                   argv[0]);
+               (void) fprintf(stderr, gettext("and no additional pools "
+                   "with that name were found\n"));
+               err = 1;
+       } else if (pools == NULL) {
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("cannot import '%s': "
+                           "no such pool available\n"), argv[0]);
+               }
+               err = 1;
+       }
+
+       if (err == 1) {
+               if (searchdirs != NULL)
+                       free(searchdirs);
+               if (envdup != NULL)
+                       free(envdup);
+               nvlist_free(policy);
+               nvlist_free(pools);
+               nvlist_free(props);
+               return (1);
+       }
+
+       /*
+        * At this point we have a list of import candidate configs. Even if
+        * we were searching by pool name or guid, we still need to
+        * post-process the list to deal with pool state and possible
+        * duplicate names.
+        */
+       err = 0;
+       elem = NULL;
+       first = B_TRUE;
+       while ((elem = nvlist_next_nvpair(pools, elem)) != NULL) {
+
+               verify(nvpair_value_nvlist(elem, &config) == 0);
+
+               verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+                   &pool_state) == 0);
+               if (!do_destroyed && pool_state == POOL_STATE_DESTROYED)
+                       continue;
+               if (do_destroyed && pool_state != POOL_STATE_DESTROYED)
+                       continue;
+
+               verify(nvlist_add_nvlist(config, ZPOOL_REWIND_POLICY,
+                   policy) == 0);
+
+               if (argc == 0) {
+                       if (first)
+                               first = B_FALSE;
+                       else if (!do_all)
+                               (void) printf("\n");
+
+                       if (do_all) {
+                               err |= do_import(config, NULL, mntopts,
+                                   props, flags);
+                       } else {
+                               show_import(config);
+                       }
+               } else if (searchname != NULL) {
+                       char *name;
+
+                       /*
+                        * We are searching for a pool based on name.
+                        */
+                       verify(nvlist_lookup_string(config,
+                           ZPOOL_CONFIG_POOL_NAME, &name) == 0);
+
+                       if (strcmp(name, searchname) == 0) {
+                               if (found_config != NULL) {
+                                       (void) fprintf(stderr, gettext(
+                                           "cannot import '%s': more than "
+                                           "one matching pool\n"), searchname);
+                                       (void) fprintf(stderr, gettext(
+                                           "import by numeric ID instead\n"));
+                                       err = B_TRUE;
+                               }
+                               found_config = config;
+                       }
+               } else {
+                       uint64_t guid;
+
+                       /*
+                        * Search for a pool by guid.
+                        */
+                       verify(nvlist_lookup_uint64(config,
+                           ZPOOL_CONFIG_POOL_GUID, &guid) == 0);
+
+                       if (guid == searchguid)
+                               found_config = config;
+               }
+       }
+
+       /*
+        * If we were searching for a specific pool, verify that we found a
+        * pool, and then do the import.
+        */
+       if (argc != 0 && err == 0) {
+               if (found_config == NULL) {
+                       (void) fprintf(stderr, gettext("cannot import '%s': "
+                           "no such pool available\n"), argv[0]);
+                       err = B_TRUE;
+               } else {
+                       err |= do_import(found_config, argc == 1 ? NULL :
+                           argv[1], mntopts, props, flags);
+               }
+       }
+
+       /*
+        * If we were just looking for pools, report an error if none were
+        * found.
+        */
+       if (argc == 0 && first)
+               (void) fprintf(stderr,
+                   gettext("no pools available to import\n"));
+
+error:
+       nvlist_free(props);
+       nvlist_free(pools);
+       nvlist_free(policy);
+       if (searchdirs != NULL)
+               free(searchdirs);
+       if (envdup != NULL)
+               free(envdup);
+
+       return (err ? 1 : 0);
+}
+
+typedef struct iostat_cbdata {
+       uint64_t cb_flags;
+       int cb_name_flags;
+       int cb_namewidth;
+       int cb_iteration;
+       char **cb_vdev_names; /* Only show these vdevs */
+       unsigned int cb_vdev_names_count;
+       boolean_t cb_verbose;
+       boolean_t cb_literal;
+       boolean_t cb_scripted;
+       zpool_list_t *cb_list;
+} iostat_cbdata_t;
+
+/*  iostat labels */
+typedef struct name_and_columns {
+       const char *name;       /* Column name */
+       unsigned int columns;   /* Center name to this number of columns */
+} name_and_columns_t;
+
+#define        IOSTAT_MAX_LABELS       11      /* Max number of labels on one line */
+
+static const name_and_columns_t iostat_top_labels[][IOSTAT_MAX_LABELS] =
+{
+       [IOS_DEFAULT] = {{"capacity", 2}, {"operations", 2}, {"bandwidth", 2},
+           {NULL}},
+       [IOS_LATENCY] = {{"total_wait", 2}, {"disk_wait", 2}, {"syncq_wait", 2},
+           {"asyncq_wait", 2}, {"scrub"}},
+       [IOS_QUEUES] = {{"syncq_read", 2}, {"syncq_write", 2},
+           {"asyncq_read", 2}, {"asyncq_write", 2}, {"scrubq_read", 2},
+           {NULL}},
+       [IOS_L_HISTO] = {{"total_wait", 2}, {"disk_wait", 2},
+           {"sync_queue", 2}, {"async_queue", 2}, {NULL}},
+       [IOS_RQ_HISTO] = {{"sync_read", 2}, {"sync_write", 2},
+           {"async_read", 2}, {"async_write", 2}, {"scrub", 2}, {NULL}},
+
+};
+
+/* Shorthand - if "columns" field not set, default to 1 column */
+static const name_and_columns_t iostat_bottom_labels[][IOSTAT_MAX_LABELS] =
+{
+       [IOS_DEFAULT] = {{"alloc"}, {"free"}, {"read"}, {"write"}, {"read"},
+           {"write"}, {NULL}},
+       [IOS_LATENCY] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"},
+           {"write"}, {"read"}, {"write"}, {"wait"}, {NULL}},
+       [IOS_QUEUES] = {{"pend"}, {"activ"}, {"pend"}, {"activ"}, {"pend"},
+           {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"}, {NULL}},
+       [IOS_L_HISTO] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"},
+           {"write"}, {"read"}, {"write"}, {"scrub"}, {NULL}},
+       [IOS_RQ_HISTO] = {{"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"},
+           {"ind"}, {"agg"}, {"ind"}, {"agg"}, {NULL}},
+};
+
+static const char *histo_to_title[] = {
+       [IOS_L_HISTO] = "latency",
+       [IOS_RQ_HISTO] = "req_size",
+};
+
+/*
+ * Return the number of labels in a null-terminated name_and_columns_t
+ * array.
+ *
+ */
+static unsigned int
+label_array_len(const name_and_columns_t *labels)
+{
+       int i = 0;
+
+       while (labels[i].name)
+               i++;
+
+       return (i);
+}
+
+/*
+ * Return the number of strings in a null-terminated string array.
+ * For example:
+ *
+ *     const char foo[] = {"bar", "baz", NULL}
+ *
+ * returns 2
+ */
+static uint64_t
+str_array_len(const char *array[])
+{
+       uint64_t i = 0;
+       while (array[i])
+               i++;
+
+       return (i);
+}
+
+
+/*
+ * Return a default column width for default/latency/queue columns. This does
+ * not include histograms, which have their columns autosized.
+ */
+static unsigned int
+default_column_width(iostat_cbdata_t *cb, enum iostat_type type)
+{
+       unsigned long column_width = 5; /* Normal niceprint */
+       static unsigned long widths[] = {
+               /*
+                * Choose some sane default column sizes for printing the
+                * raw numbers.
+                */
+               [IOS_DEFAULT] = 15, /* 1PB capacity */
+               [IOS_LATENCY] = 10, /* 1B ns = 10sec */
+               [IOS_QUEUES] = 6,   /* 1M queue entries */
+       };
+
+       if (cb->cb_literal)
+               column_width = widths[type];
+
+       return (column_width);
+}
+
+/*
+ * Print the column labels, i.e:
+ *
+ *   capacity     operations     bandwidth
+ * alloc   free   read  write   read  write  ...
+ *
+ * If force_column_width is set, use it for the column width.  If not set, use
+ * the default column width.
+ */
+void
+print_iostat_labels(iostat_cbdata_t *cb, unsigned int force_column_width,
+    const name_and_columns_t labels[][IOSTAT_MAX_LABELS])
+{
+       int i, idx, s;
+       unsigned int text_start, rw_column_width, spaces_to_end;
+       uint64_t flags = cb->cb_flags;
+       uint64_t f;
+       unsigned int column_width = force_column_width;
+
+       /* For each bit set in flags */
+       for (f = flags; f; f &= ~(1ULL << idx)) {
+               idx = lowbit64(f) - 1;
+               if (!force_column_width)
+                       column_width = default_column_width(cb, idx);
+               /* Print our top labels centered over "read  write" label. */
+               for (i = 0; i < label_array_len(labels[idx]); i++) {
+                       const char *name = labels[idx][i].name;
+                       /*
+                        * We treat labels[][].columns == 0 as shorthand
+                        * for one column.  It makes writing out the label
+                        * tables more concise.
+                        */
+                       unsigned int columns = MAX(1, labels[idx][i].columns);
+                       unsigned int slen = strlen(name);
+
+                       rw_column_width = (column_width * columns) +
+                           (2 * (columns - 1));
+
+                       text_start = (int) ((rw_column_width)/columns -
+                           slen/columns);
+
+                       printf("  ");   /* Two spaces between columns */
+
+                       /* Space from beginning of column to label */
+                       for (s = 0; s < text_start; s++)
+                               printf(" ");
+
+                       printf("%s", name);
+
+                       /* Print space after label to end of column */
+                       spaces_to_end = rw_column_width - text_start - slen;
+                       for (s = 0; s < spaces_to_end; s++)
+                               printf(" ");
+
+               }
+       }
+       printf("\n");
+}
+
+/*
+ * Utility function to print out a line of dashes like:
+ *
+ *     --------------------------------  -----  -----  -----  -----  -----
+ *
+ * ...or a dashed named-row line like:
+ *
+ *     logs                                  -      -      -      -      -
+ *
+ * @cb:                                iostat data
+ *
+ * @force_column_width         If non-zero, use the value as the column width.
+ *                             Otherwise use the default column widths.
+ *
+ * @name:                      Print a dashed named-row line starting
+ *                             with @name.  Otherwise, print a regular
+ *                             dashed line.
+ */
+static void
+print_iostat_dashes(iostat_cbdata_t *cb, unsigned int force_column_width,
+    const char *name)
+{
+       int i;
+       unsigned int namewidth;
+       uint64_t flags = cb->cb_flags;
+       uint64_t f;
+       int idx;
+       const name_and_columns_t *labels;
+       const char *title;
+
+
+       if (cb->cb_flags & IOS_ANYHISTO_M) {
+               title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)];
+       } else if (cb->cb_vdev_names_count) {
+               title = "vdev";
+       } else  {
+               title = "pool";
+       }
+
+       namewidth = MAX(MAX(strlen(title), cb->cb_namewidth),
+           name ? strlen(name) : 0);
+
+
+       if (name) {
+               printf("%-*s", namewidth, name);
+       } else {
+               for (i = 0; i < namewidth; i++)
+                       (void) printf("-");
+       }
+
+       /* For each bit in flags */
+       for (f = flags; f; f &= ~(1ULL << idx)) {
+               unsigned int column_width;
+               idx = lowbit64(f) - 1;
+               if (force_column_width)
+                       column_width = force_column_width;
+               else
+                       column_width = default_column_width(cb, idx);
+
+               labels = iostat_bottom_labels[idx];
+               for (i = 0; i < label_array_len(labels); i++) {
+                       if (name)
+                               printf("  %*s-", column_width - 1, " ");
+                       else
+                               printf("  %.*s", column_width,
+                                   "--------------------");
+               }
+       }
+       printf("\n");
+}
+
+
+static void
+print_iostat_separator_impl(iostat_cbdata_t *cb,
+    unsigned int force_column_width)
+{
+       print_iostat_dashes(cb, force_column_width, NULL);
+}
+
+static void
+print_iostat_separator(iostat_cbdata_t *cb)
+{
+       print_iostat_separator_impl(cb, 0);
+}
+
+static void
+print_iostat_header_impl(iostat_cbdata_t *cb, unsigned int force_column_width,
+    const char *histo_vdev_name)
+{
+       unsigned int namewidth;
+       const char *title;
+
+       if (cb->cb_flags & IOS_ANYHISTO_M) {
+               title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)];
+       } else if (cb->cb_vdev_names_count) {
+               title = "vdev";
+       } else  {
+               title = "pool";
+       }
+
+       namewidth = MAX(MAX(strlen(title), cb->cb_namewidth),
+           histo_vdev_name ? strlen(histo_vdev_name) : 0);
+
+       if (histo_vdev_name)
+               printf("%-*s", namewidth, histo_vdev_name);
+       else
+               printf("%*s", namewidth, "");
+
+
+       print_iostat_labels(cb, force_column_width, iostat_top_labels);
+
+       printf("%-*s", namewidth, title);
+
+       print_iostat_labels(cb, force_column_width, iostat_bottom_labels);
+
+       print_iostat_separator_impl(cb, force_column_width);
+}
+
+static void
+print_iostat_header(iostat_cbdata_t *cb)
+{
+       print_iostat_header_impl(cb, 0, NULL);
+}
+
+
+/*
+ * Display a single statistic.
+ */
+static void
+print_one_stat(uint64_t value, enum zfs_nicenum_format format,
+    unsigned int column_size, boolean_t scripted)
+{
+       char buf[64];
+
+       zfs_nicenum_format(value, buf, sizeof (buf), format);
+
+       if (scripted)
+               printf("\t%s", buf);
+       else
+               printf("  %*s", column_size, buf);
+}
+
+/*
+ * Calculate the default vdev stats
+ *
+ * Subtract oldvs from newvs, apply a scaling factor, and save the resulting
+ * stats into calcvs.
+ */
+static void
+calc_default_iostats(vdev_stat_t *oldvs, vdev_stat_t *newvs,
+    vdev_stat_t *calcvs)
+{
+       int i;
+
+       memcpy(calcvs, newvs, sizeof (*calcvs));
+       for (i = 0; i < ARRAY_SIZE(calcvs->vs_ops); i++)
+               calcvs->vs_ops[i] = (newvs->vs_ops[i] - oldvs->vs_ops[i]);
+
+       for (i = 0; i < ARRAY_SIZE(calcvs->vs_bytes); i++)
+               calcvs->vs_bytes[i] = (newvs->vs_bytes[i] - oldvs->vs_bytes[i]);
+}
+
+/*
+ * Internal representation of the extended iostats data.
+ *
+ * The extended iostat stats are exported in nvlists as either uint64_t arrays
+ * or single uint64_t's.  We make both look like arrays to make them easier
+ * to process.  In order to make single uint64_t's look like arrays, we set
+ * __data to the stat data, and then set *data = &__data with count = 1.  Then,
+ * we can just use *data and count.
+ */
+struct stat_array {
+       uint64_t *data;
+       uint_t count;   /* Number of entries in data[] */
+       uint64_t __data; /* Only used when data is a single uint64_t */
+};
+
+static uint64_t
+stat_histo_max(struct stat_array *nva, unsigned int len) {
+       uint64_t max = 0;
+       int i;
+       for (i = 0; i < len; i++)
+               max = MAX(max, array64_max(nva[i].data, nva[i].count));
+
+       return (max);
+}
+
+/*
+ * Helper function to lookup a uint64_t array or uint64_t value and store its
+ * data as a stat_array.  If the nvpair is a single uint64_t value, then we make
+ * it look like a one element array to make it easier to process.
+ */
+static int
+nvpair64_to_stat_array(nvlist_t *nvl, const char *name,
+    struct stat_array *nva) {
+       nvpair_t *tmp;
+       int ret;
+
+       verify(nvlist_lookup_nvpair(nvl, name, &tmp) == 0);
+       switch (nvpair_type(tmp)) {
+       case DATA_TYPE_UINT64_ARRAY:
+               ret = nvpair_value_uint64_array(tmp, &nva->data, &nva->count);
+               break;
+       case DATA_TYPE_UINT64:
+               ret = nvpair_value_uint64(tmp, &nva->__data);
+               nva->data = &nva->__data;
+               nva->count = 1;
+               break;
+       default:
+               /* Not a uint64_t */
+               ret = EINVAL;
+               break;
+       }
+
+       return (ret);
+}
+
+/*
+ * Given a list of nvlist names, look up the extended stats in newnv and oldnv,
+ * subtract them, and return the results in a newly allocated stat_array.
+ * You must free the returned array after you are done with it with
+ * free_calc_stats().
+ *
+ * Additionally, you can set "oldnv" to NULL if you simply want the newnv
+ * values.
+ */
+static struct stat_array *
+calc_and_alloc_stats_ex(const char **names, unsigned int len, nvlist_t *oldnv,
+    nvlist_t *newnv)
+{
+       nvlist_t *oldnvx = NULL, *newnvx;
+       struct stat_array *oldnva, *newnva, *calcnva;
+       int i, j;
+       unsigned int alloc_size = (sizeof (struct stat_array)) * len;
+
+       /* Extract our extended stats nvlist from the main list */
+       verify(nvlist_lookup_nvlist(newnv, ZPOOL_CONFIG_VDEV_STATS_EX,
+           &newnvx) == 0);
+       if (oldnv) {
+               verify(nvlist_lookup_nvlist(oldnv, ZPOOL_CONFIG_VDEV_STATS_EX,
+                   &oldnvx) == 0);
+       }
+
+       newnva = safe_malloc(alloc_size);
+       oldnva = safe_malloc(alloc_size);
+       calcnva = safe_malloc(alloc_size);
+
+       for (j = 0; j < len; j++) {
+               verify(nvpair64_to_stat_array(newnvx, names[j],
+                   &newnva[j]) == 0);
+               calcnva[j].count = newnva[j].count;
+               alloc_size = calcnva[j].count * sizeof (calcnva[j].data[0]);
+               calcnva[j].data = safe_malloc(alloc_size);
+               memcpy(calcnva[j].data, newnva[j].data, alloc_size);
+
+               if (oldnvx) {
+                       verify(nvpair64_to_stat_array(oldnvx, names[j],
+                           &oldnva[j]) == 0);
+                       for (i = 0; i < oldnva[j].count; i++)
+                               calcnva[j].data[i] -= oldnva[j].data[i];
+               }
+       }
+       free(newnva);
+       free(oldnva);
+       return (calcnva);
+}
+
+static void
+free_calc_stats(struct stat_array *nva, unsigned int len)
+{
+       int i;
+       for (i = 0; i < len; i++)
+               free(nva[i].data);
+
+       free(nva);
+}
+
+static void
+print_iostat_histo(struct stat_array *nva, unsigned int len,
+    iostat_cbdata_t *cb, unsigned int column_width, unsigned int namewidth,
+    double scale)
+{
+       int i, j;
+       char buf[6];
+       uint64_t val;
+       enum zfs_nicenum_format format;
+       unsigned int buckets;
+       unsigned int start_bucket;
+
+       if (cb->cb_literal)
+               format = ZFS_NICENUM_RAW;
+       else
+               format = ZFS_NICENUM_1024;
+
+       /* All these histos are the same size, so just use nva[0].count */
+       buckets = nva[0].count;
+
+       if (cb->cb_flags & IOS_RQ_HISTO_M) {
+               /* Start at 512 - req size should never be lower than this */
+               start_bucket = 9;
+       } else {
+               start_bucket = 0;
+       }
+
+       for (j = start_bucket; j < buckets; j++) {
+               /* Print histogram bucket label */
+               if (cb->cb_flags & IOS_L_HISTO_M) {
+                       /* Ending range of this bucket */
+                       val = (1UL << (j + 1)) - 1;
+                       zfs_nicetime(val, buf, sizeof (buf));
+               } else {
+                       /* Request size (starting range of bucket) */
+                       val = (1UL << j);
+                       zfs_nicenum(val, buf, sizeof (buf));
+               }
+
+               if (cb->cb_scripted)
+                       printf("%llu", (u_longlong_t) val);
+               else
+                       printf("%-*s", namewidth, buf);
+
+               /* Print the values on the line */
+               for (i = 0; i < len; i++) {
+                       print_one_stat(nva[i].data[j] * scale, format,
+                           column_width, cb->cb_scripted);
+               }
+               printf("\n");
+       }
+}
+
+static void
+print_solid_separator(unsigned int length)
+{
+       while (length--)
+               printf("-");
+       printf("\n");
+}
+
+static void
+print_iostat_histos(iostat_cbdata_t *cb, nvlist_t *oldnv,
+    nvlist_t *newnv, double scale, const char *name)
+{
+       unsigned int column_width;
+       unsigned int namewidth;
+       unsigned int entire_width;
+       enum iostat_type type;
+       struct stat_array *nva;
+       const char **names;
+       unsigned int names_len;
+
+       /* What type of histo are we? */
+       type = IOS_HISTO_IDX(cb->cb_flags);
+
+       /* Get NULL-terminated array of nvlist names for our histo */
+       names = vsx_type_to_nvlist[type];
+       names_len = str_array_len(names); /* num of names */
+
+       nva = calc_and_alloc_stats_ex(names, names_len, oldnv, newnv);
+
+       if (cb->cb_literal) {
+               column_width = MAX(5,
+                   (unsigned int) log10(stat_histo_max(nva, names_len)) + 1);
+       } else {
+               column_width = 5;
+       }
+
+       namewidth = MAX(cb->cb_namewidth,
+           strlen(histo_to_title[IOS_HISTO_IDX(cb->cb_flags)]));
+
+       /*
+        * Calculate the entire line width of what we're printing.  The
+        * +2 is for the two spaces between columns:
+        */
+       /*       read  write                            */
+       /*      -----  -----                            */
+       /*      |___|  <---------- column_width         */
+       /*                                              */
+       /*      |__________|  <--- entire_width         */
+       /*                                              */
+       entire_width = namewidth + (column_width + 2) *
+           label_array_len(iostat_bottom_labels[type]);
+
+       if (cb->cb_scripted)
+               printf("%s\n", name);
+       else
+               print_iostat_header_impl(cb, column_width, name);
+
+       print_iostat_histo(nva, names_len, cb, column_width,
+           namewidth, scale);
+
+       free_calc_stats(nva, names_len);
+       if (!cb->cb_scripted)
+               print_solid_separator(entire_width);
+}
+
+/*
+ * Calculate the average latency of a power-of-two latency histogram
+ */
+static uint64_t
+single_histo_average(uint64_t *histo, unsigned int buckets)
+{
+       int i;
+       uint64_t count = 0, total = 0;
+
+       for (i = 0; i < buckets; i++) {
+               /*
+                * Our buckets are power-of-two latency ranges.  Use the
+                * midpoint latency of each bucket to calculate the average.
+                * For example:
+                *
+                * Bucket          Midpoint
+                * 8ns-15ns:       12ns
+                * 16ns-31ns:      24ns
+                * ...
+                */
+               if (histo[i] != 0) {
+                       total += histo[i] * (((1UL << i) + ((1UL << i)/2)));
+                       count += histo[i];
+               }
+       }
+
+       /* Prevent divide by zero */
+       return (count == 0 ? 0 : total / count);
+}
+
+static void
+print_iostat_queues(iostat_cbdata_t *cb, nvlist_t *oldnv,
+    nvlist_t *newnv, double scale)
+{
+       int i;
+       uint64_t val;
+       const char *names[] = {
+               ZPOOL_CONFIG_VDEV_SYNC_R_PEND_QUEUE,
+               ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE,
+               ZPOOL_CONFIG_VDEV_SYNC_W_PEND_QUEUE,
+               ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE,
+               ZPOOL_CONFIG_VDEV_ASYNC_R_PEND_QUEUE,
+               ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE,
+               ZPOOL_CONFIG_VDEV_ASYNC_W_PEND_QUEUE,
+               ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
+               ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE,
+               ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
+       };
+
+       struct stat_array *nva;
+
+       unsigned int column_width = default_column_width(cb, IOS_QUEUES);
+       enum zfs_nicenum_format format;
+
+       nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), NULL, newnv);
+
+       if (cb->cb_literal)
+               format = ZFS_NICENUM_RAW;
+       else
+               format = ZFS_NICENUM_1024;
+
+       for (i = 0; i < ARRAY_SIZE(names); i++) {
+               val = nva[i].data[0] * scale;
+               print_one_stat(val, format, column_width, cb->cb_scripted);
+       }
+
+       free_calc_stats(nva, ARRAY_SIZE(names));
+}
+
+static void
+print_iostat_latency(iostat_cbdata_t *cb, nvlist_t *oldnv,
+    nvlist_t *newnv, double scale)
+{
+       int i;
+       uint64_t val;
+       const char *names[] = {
+               ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
+               ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
+               ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
+               ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
+               ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO,
+               ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO,
+               ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
+               ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
+               ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
+       };
+       struct stat_array *nva;
+
+       unsigned int column_width = default_column_width(cb, IOS_LATENCY);
+       enum zfs_nicenum_format format;
+
+       nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), oldnv, newnv);
+
+       if (cb->cb_literal)
+               format = ZFS_NICENUM_RAW;
+       else
+               format = ZFS_NICENUM_TIME;
+
+       /* Print our avg latencies on the line */
+       for (i = 0; i < ARRAY_SIZE(names); i++) {
+               /* Compute average latency for a latency histo */
+               val = single_histo_average(nva[i].data, nva[i].count) * scale;
+               print_one_stat(val, format, column_width, cb->cb_scripted);
+       }
+       free_calc_stats(nva, ARRAY_SIZE(names));
+}
+
+/*
+ * Print default statistics (capacity/operations/bandwidth)
+ */
+static void
+print_iostat_default(vdev_stat_t *vs, iostat_cbdata_t *cb, double scale)
+{
+       unsigned int column_width = default_column_width(cb, IOS_DEFAULT);
+       enum zfs_nicenum_format format;
+       char na;        /* char to print for "not applicable" values */
+
+       if (cb->cb_literal) {
+               format = ZFS_NICENUM_RAW;
+               na = '0';
+       } else {
+               format = ZFS_NICENUM_1024;
+               na = '-';
+       }
+
+       /* only toplevel vdevs have capacity stats */
+       if (vs->vs_space == 0) {
+               if (cb->cb_scripted)
+                       printf("\t%c\t%c", na, na);
+               else
+                       printf("  %*c  %*c", column_width, na, column_width,
+                           na);
+       } else {
+               print_one_stat(vs->vs_alloc, format, column_width,
+                   cb->cb_scripted);
+               print_one_stat(vs->vs_space - vs->vs_alloc, format,
+                   column_width, cb->cb_scripted);
+       }
+
+       print_one_stat((uint64_t)(vs->vs_ops[ZIO_TYPE_READ] * scale),
+           format, column_width, cb->cb_scripted);
+       print_one_stat((uint64_t)(vs->vs_ops[ZIO_TYPE_WRITE] * scale),
+           format, column_width, cb->cb_scripted);
+       print_one_stat((uint64_t)(vs->vs_bytes[ZIO_TYPE_READ] * scale),
+           format, column_width, cb->cb_scripted);
+       print_one_stat((uint64_t)(vs->vs_bytes[ZIO_TYPE_WRITE] * scale),
+           format, column_width, cb->cb_scripted);
+}
+
+/*
+ * Print out all the statistics for the given vdev.  This can either be the
+ * toplevel configuration, or called recursively.  If 'name' is NULL, then this
+ * is a verbose output, and we don't want to display the toplevel pool stats.
+ *
+ * Returns the number of stat lines printed.
+ */
+unsigned int
+print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
+    nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
+{
+       nvlist_t **oldchild, **newchild;
+       uint_t c, children;
+       vdev_stat_t *oldvs, *newvs, *calcvs;
+       vdev_stat_t zerovs = { 0 };
+       char *vname;
+       int i;
+       int ret = 0;
+       uint64_t tdelta;
+       double scale;
+
+       calcvs = safe_malloc(sizeof (*calcvs));
+
+       if (oldnv != NULL) {
+               verify(nvlist_lookup_uint64_array(oldnv,
+                   ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&oldvs, &c) == 0);
+       } else {
+               oldvs = &zerovs;
+       }
+
+       /* Do we only want to see a specific vdev? */
+       for (i = 0; i < cb->cb_vdev_names_count; i++) {
+               /* Yes we do.  Is this the vdev? */
+               if (strcmp(name, cb->cb_vdev_names[i]) == 0) {
+                       /*
+                        * This is our vdev.  Since it is the only vdev we
+                        * will be displaying, make depth = 0 so that it
+                        * doesn't get indented.
+                        */
+                       depth = 0;
+                       break;
+               }
+       }
+
+       if (cb->cb_vdev_names_count && (i == cb->cb_vdev_names_count)) {
+               /* Couldn't match the name */
+               goto children;
+       }
+
+
+       verify(nvlist_lookup_uint64_array(newnv, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&newvs, &c) == 0);
+
+       /*
+        * Print the vdev name unless it's is a histogram.  Histograms
+        * display the vdev name in the header itself.
+        */
+       if (!(cb->cb_flags & IOS_ANYHISTO_M)) {
+               if (cb->cb_scripted) {
+                       printf("%s", name);
+               } else {
+                       if (strlen(name) + depth > cb->cb_namewidth)
+                               (void) printf("%*s%s", depth, "", name);
+                       else
+                               (void) printf("%*s%s%*s", depth, "", name,
+                                   (int)(cb->cb_namewidth - strlen(name) -
+                                   depth), "");
+               }
+       }
+
+       /* Calculate our scaling factor */
+       tdelta = newvs->vs_timestamp - oldvs->vs_timestamp;
+       if ((oldvs->vs_timestamp == 0) && (cb->cb_flags & IOS_ANYHISTO_M)) {
+               /*
+                * If we specify printing histograms with no time interval, then
+                * print the histogram numbers over the entire lifetime of the
+                * vdev.
+                */
+               scale = 1;
+       } else {
+               if (tdelta == 0)
+                       scale = 1.0;
+               else
+                       scale = (double)NANOSEC / tdelta;
+       }
+
+       if (cb->cb_flags & IOS_DEFAULT_M) {
+               calc_default_iostats(oldvs, newvs, calcvs);
+               print_iostat_default(calcvs, cb, scale);
+       }
+       if (cb->cb_flags & IOS_LATENCY_M)
+               print_iostat_latency(cb, oldnv, newnv, scale);
+       if (cb->cb_flags & IOS_QUEUES_M)
+               print_iostat_queues(cb, oldnv, newnv, scale);
+       if (cb->cb_flags & IOS_ANYHISTO_M) {
+               printf("\n");
+               print_iostat_histos(cb, oldnv, newnv, scale, name);
+       }
+
+       if (!(cb->cb_flags & IOS_ANYHISTO_M))
+               printf("\n");
+
+       ret++;
+
+children:
+
+       free(calcvs);
+
+       if (!cb->cb_verbose)
+               return (ret);
+
+       if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_CHILDREN,
+           &newchild, &children) != 0)
+               return (ret);
+
+       if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_CHILDREN,
+           &oldchild, &c) != 0)
+               return (ret);
+
+       for (c = 0; c < children; c++) {
+               uint64_t ishole = B_FALSE, islog = B_FALSE;
+
+               (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_HOLE,
+                   &ishole);
+
+               (void) nvlist_lookup_uint64(newchild[c], ZPOOL_CONFIG_IS_LOG,
+                   &islog);
+
+               if (ishole || islog)
+                       continue;
+
+               vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+                   cb->cb_name_flags);
+               ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
+                   newchild[c], cb, depth + 2);
+               free(vname);
+       }
+
+       /*
+        * Log device section
+        */
+
+       if (num_logs(newnv) > 0) {
+               if ((!(cb->cb_flags & IOS_ANYHISTO_M)) && !cb->cb_scripted &&
+                   !cb->cb_vdev_names) {
+                       print_iostat_dashes(cb, 0, "logs");
+               }
+
+               for (c = 0; c < children; c++) {
+                       uint64_t islog = B_FALSE;
+                       (void) nvlist_lookup_uint64(newchild[c],
+                           ZPOOL_CONFIG_IS_LOG, &islog);
+
+                       if (islog) {
+                               vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+                                   cb->cb_name_flags);
+                               ret += print_vdev_stats(zhp, vname, oldnv ?
+                                   oldchild[c] : NULL, newchild[c],
+                                   cb, depth + 2);
+                               free(vname);
+                       }
+               }
+
+       }
+
+       /*
+        * Include level 2 ARC devices in iostat output
+        */
+       if (nvlist_lookup_nvlist_array(newnv, ZPOOL_CONFIG_L2CACHE,
+           &newchild, &children) != 0)
+               return (ret);
+
+       if (oldnv && nvlist_lookup_nvlist_array(oldnv, ZPOOL_CONFIG_L2CACHE,
+           &oldchild, &c) != 0)
+               return (ret);
+
+       if (children > 0) {
+               if ((!(cb->cb_flags & IOS_ANYHISTO_M)) && !cb->cb_scripted &&
+                   !cb->cb_vdev_names) {
+                       print_iostat_dashes(cb, 0, "cache");
+               }
+
+               for (c = 0; c < children; c++) {
+                       vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+                           cb->cb_name_flags);
+                       ret += print_vdev_stats(zhp, vname, oldnv ? oldchild[c]
+                           : NULL, newchild[c], cb, depth + 2);
+                       free(vname);
+               }
+       }
+
+       return (ret);
+}
+
+static int
+refresh_iostat(zpool_handle_t *zhp, void *data)
+{
+       iostat_cbdata_t *cb = data;
+       boolean_t missing;
+
+       /*
+        * If the pool has disappeared, remove it from the list and continue.
+        */
+       if (zpool_refresh_stats(zhp, &missing) != 0)
+               return (-1);
+
+       if (missing)
+               pool_list_remove(cb->cb_list, zhp);
+
+       return (0);
+}
+
+/*
+ * Callback to print out the iostats for the given pool.
+ */
+int
+print_iostat(zpool_handle_t *zhp, void *data)
+{
+       iostat_cbdata_t *cb = data;
+       nvlist_t *oldconfig, *newconfig;
+       nvlist_t *oldnvroot, *newnvroot;
+       int ret;
+
+       newconfig = zpool_get_config(zhp, &oldconfig);
+
+       if (cb->cb_iteration == 1)
+               oldconfig = NULL;
+
+       verify(nvlist_lookup_nvlist(newconfig, ZPOOL_CONFIG_VDEV_TREE,
+           &newnvroot) == 0);
+
+       if (oldconfig == NULL)
+               oldnvroot = NULL;
+       else
+               verify(nvlist_lookup_nvlist(oldconfig, ZPOOL_CONFIG_VDEV_TREE,
+                   &oldnvroot) == 0);
+
+       ret = print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot,
+                                                                       cb, 0);
+       if ((ret != 0) && !(cb->cb_flags & IOS_ANYHISTO_M) &&
+           !cb->cb_scripted && cb->cb_verbose && !cb->cb_vdev_names_count) {
+               print_iostat_separator(cb);
+       }
+
+       return (ret);
+}
+
+static int
+get_columns(void)
+{
+       struct winsize ws;
+       int columns = 80;
+       int error;
+
+       if (isatty(STDOUT_FILENO)) {
+               error = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
+               if (error == 0)
+                       columns = ws.ws_col;
+       } else {
+               columns = 999;
+       }
+
+       return (columns);
+}
+
+int
+get_namewidth(zpool_handle_t *zhp, void *data)
+{
+       iostat_cbdata_t *cb = data;
+       nvlist_t *config, *nvroot;
+       int columns;
+
+       if ((config = zpool_get_config(zhp, NULL)) != NULL) {
+               verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+                   &nvroot) == 0);
+               unsigned int poolname_len = strlen(zpool_get_name(zhp));
+               if (!cb->cb_verbose)
+                       cb->cb_namewidth = poolname_len;
+               else
+                       cb->cb_namewidth = MAX(poolname_len,
+                           max_width(zhp, nvroot, 0, cb->cb_namewidth,
+                           cb->cb_name_flags));
+       }
+       /*
+        * The width must be at least 10, but may be as large as the
+        * column width - 42 so that we can still fit in one line.
+        */
+       columns = get_columns();
+
+       if (cb->cb_namewidth < 10)
+               cb->cb_namewidth = 10;
+       if (cb->cb_namewidth > columns - 42)
+               cb->cb_namewidth = columns - 42;
+
+       return (0);
+}
+
+/*
+ * Parse the input string, get the 'interval' and 'count' value if there is one.
+ */
+static void
+get_interval_count(int *argcp, char **argv, float *iv,
+    unsigned long *cnt)
+{
+       float interval = 0;
+       unsigned long count = 0;
+       int argc = *argcp;
+
+       /*
+        * Determine if the last argument is an integer or a pool name
+        */
+       if (argc > 0 && isnumber(argv[argc - 1])) {
+               char *end;
+
+               errno = 0;
+               interval = strtof(argv[argc - 1], &end);
+
+               if (*end == '\0' && errno == 0) {
+                       if (interval == 0) {
+                               (void) fprintf(stderr, gettext("interval "
+                                   "cannot be zero\n"));
+                               usage(B_FALSE);
+                       }
+                       /*
+                        * Ignore the last parameter
+                        */
+                       argc--;
+               } else {
+                       /*
+                        * If this is not a valid number, just plow on.  The
+                        * user will get a more informative error message later
+                        * on.
+                        */
+                       interval = 0;
+               }
+       }
+
+       /*
+        * If the last argument is also an integer, then we have both a count
+        * and an interval.
+        */
+       if (argc > 0 && isnumber(argv[argc - 1])) {
+               char *end;
+
+               errno = 0;
+               count = interval;
+               interval = strtof(argv[argc - 1], &end);
+
+               if (*end == '\0' && errno == 0) {
+                       if (interval == 0) {
+                               (void) fprintf(stderr, gettext("interval "
+                                   "cannot be zero\n"));
+                               usage(B_FALSE);
+                       }
+
+                       /*
+                        * Ignore the last parameter
+                        */
+                       argc--;
+               } else {
+                       interval = 0;
+               }
+       }
+
+       *iv = interval;
+       *cnt = count;
+       *argcp = argc;
+}
+
+static void
+get_timestamp_arg(char c)
+{
+       if (c == 'u')
+               timestamp_fmt = UDATE;
+       else if (c == 'd')
+               timestamp_fmt = DDATE;
+       else
+               usage(B_FALSE);
+}
+
+/*
+ * Return stat flags that are supported by all pools by both the module and
+ * zpool iostat.  "*data" should be initialized to all 0xFFs before running.
+ * It will get ANDed down until only the flags that are supported on all pools
+ * remain.
+ */
+static int
+get_stat_flags_cb(zpool_handle_t *zhp, void *data)
+{
+       uint64_t *mask = data;
+       nvlist_t *config, *nvroot, *nvx;
+       uint64_t flags = 0;
+       int i, j;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+
+       /* Default stats are always supported, but for completeness.. */
+       if (nvlist_exists(nvroot, ZPOOL_CONFIG_VDEV_STATS))
+               flags |= IOS_DEFAULT_M;
+
+       /* Get our extended stats nvlist from the main list */
+       if (nvlist_lookup_nvlist(nvroot, ZPOOL_CONFIG_VDEV_STATS_EX,
+           &nvx) != 0) {
+               /*
+                * No extended stats; they're probably running an older
+                * module.  No big deal, we support that too.
+                */
+               goto end;
+       }
+
+       /* For each extended stat, make sure all its nvpairs are supported */
+       for (j = 0; j < ARRAY_SIZE(vsx_type_to_nvlist); j++) {
+               if (!vsx_type_to_nvlist[j][0])
+                       continue;
+
+               /* Start off by assuming the flag is supported, then check */
+               flags |= (1ULL << j);
+               for (i = 0; vsx_type_to_nvlist[j][i]; i++) {
+                       if (!nvlist_exists(nvx, vsx_type_to_nvlist[j][i])) {
+                               /* flag isn't supported */
+                               flags = flags & ~(1ULL  << j);
+                               break;
+                       }
+               }
+       }
+end:
+       *mask = *mask & flags;
+       return (0);
+}
+
+/*
+ * Return a bitmask of stats that are supported on all pools by both the module
+ * and zpool iostat.
+ */
+static uint64_t
+get_stat_flags(zpool_list_t *list)
+{
+       uint64_t mask = -1;
+
+       /*
+        * get_stat_flags_cb() will lop off bits from "mask" until only the
+        * flags that are supported on all pools remain.
+        */
+       pool_list_iter(list, B_FALSE, get_stat_flags_cb, &mask);
+       return (mask);
+}
+
+/*
+ * Return 1 if cb_data->cb_vdev_names[0] is this vdev's name, 0 otherwise.
+ */
+static int
+is_vdev_cb(zpool_handle_t *zhp, nvlist_t *nv, void *cb_data)
+{
+       iostat_cbdata_t *cb = cb_data;
+       char *name = NULL;
+       int ret = 0;
+
+       name = zpool_vdev_name(g_zfs, zhp, nv, cb->cb_name_flags);
+
+       if (strcmp(name, cb->cb_vdev_names[0]) == 0)
+               ret = 1; /* match */
+       free(name);
+
+       return (ret);
+}
+
+/*
+ * Returns 1 if cb_data->cb_vdev_names[0] is a vdev name, 0 otherwise.
+ */
+static int
+is_vdev(zpool_handle_t *zhp, void *cb_data)
+{
+       return (for_each_vdev(zhp, is_vdev_cb, cb_data));
+}
+
+/*
+ * Check if vdevs are in a pool
+ *
+ * Return 1 if all argv[] strings are vdev names in pool "pool_name". Otherwise
+ * return 0.  If pool_name is NULL, then search all pools.
+ */
+static int
+are_vdevs_in_pool(int argc, char **argv, char *pool_name,
+    iostat_cbdata_t *cb)
+{
+       char **tmp_name;
+       int ret = 0;
+       int i;
+       int pool_count = 0;
+
+       if ((argc == 0) || !*argv)
+               return (0);
+
+       if (pool_name)
+               pool_count = 1;
+
+       /* Temporarily hijack cb_vdev_names for a second... */
+       tmp_name = cb->cb_vdev_names;
+
+       /* Go though our list of prospective vdev names */
+       for (i = 0; i < argc; i++) {
+               cb->cb_vdev_names = argv + i;
+
+               /* Is this name a vdev in our pools? */
+               ret = for_each_pool(pool_count, &pool_name, B_TRUE, NULL,
+                   is_vdev, cb);
+               if (!ret) {
+                       /* No match */
+                       break;
+               }
+       }
+
+       cb->cb_vdev_names = tmp_name;
+
+       return (ret);
+}
+
+static int
+is_pool_cb(zpool_handle_t *zhp, void *data)
+{
+       char *name = data;
+       if (strcmp(name, zpool_get_name(zhp)) == 0)
+               return (1);
+
+       return (0);
+}
+
+/*
+ * Do we have a pool named *name?  If so, return 1, otherwise 0.
+ */
+static int
+is_pool(char *name)
+{
+       return (for_each_pool(0, NULL, B_TRUE, NULL,  is_pool_cb, name));
+}
+
+/* Are all our argv[] strings pool names?  If so return 1, 0 otherwise. */
+static int
+are_all_pools(int argc, char **argv) {
+       if ((argc == 0) || !*argv)
+               return (0);
+
+       while (--argc >= 0)
+               if (!is_pool(argv[argc]))
+                       return (0);
+
+       return (1);
+}
+
+/*
+ * Helper function to print out vdev/pool names we can't resolve.  Used for an
+ * error message.
+ */
+static void
+error_list_unresolved_vdevs(int argc, char **argv, char *pool_name,
+    iostat_cbdata_t *cb)
+{
+       int i;
+       char *name;
+       char *str;
+       for (i = 0; i < argc; i++) {
+               name = argv[i];
+
+               if (is_pool(name))
+                       str = gettext("pool");
+               else if (are_vdevs_in_pool(1, &name, pool_name, cb))
+                       str = gettext("vdev in this pool");
+               else if (are_vdevs_in_pool(1, &name, NULL, cb))
+                       str = gettext("vdev in another pool");
+               else
+                       str = gettext("unknown");
+
+               fprintf(stderr, "\t%s (%s)\n", name, str);
+       }
+}
+
+/*
+ * Same as get_interval_count(), but with additional checks to not misinterpret
+ * guids as interval/count values.  Assumes VDEV_NAME_GUID is set in
+ * cb.cb_name_flags.
+ */
+static void
+get_interval_count_filter_guids(int *argc, char **argv, float *interval,
+    unsigned long *count, iostat_cbdata_t *cb)
+{
+       char **tmpargv = argv;
+       int argc_for_interval = 0;
+
+       /* Is the last arg an interval value?  Or a guid? */
+       if (*argc >= 1 && !are_vdevs_in_pool(1, &argv[*argc - 1], NULL, cb)) {
+               /*
+                * The last arg is not a guid, so it's probably an
+                * interval value.
+                */
+               argc_for_interval++;
+
+               if (*argc >= 2 &&
+                   !are_vdevs_in_pool(1, &argv[*argc - 2], NULL, cb)) {
+                       /*
+                        * The 2nd to last arg is not a guid, so it's probably
+                        * an interval value.
+                        */
+                       argc_for_interval++;
+               }
+       }
+
+       /* Point to our list of possible intervals */
+       tmpargv = &argv[*argc - argc_for_interval];
+
+       *argc = *argc - argc_for_interval;
+       get_interval_count(&argc_for_interval, tmpargv,
+           interval, count);
+}
+
+/*
+ * Floating point sleep().  Allows you to pass in a floating point value for
+ * seconds.
+ */
+static void
+fsleep(float sec) {
+       struct timespec req;
+       req.tv_sec = floor(sec);
+       req.tv_nsec = (sec - (float)req.tv_sec) * NANOSEC;
+       nanosleep(&req, NULL);
+}
+
+
+/*
+ * zpool iostat [-ghHLpPvy] [[-lq]|[-r|-w]] [-n name] [-T d|u]
+ *             [[ pool ...]|[pool vdev ...]|[vdev ...]]
+ *             [interval [count]]
+ *
+ *     -g      Display guid for individual vdev name.
+ *     -L      Follow links when resolving vdev path name.
+ *     -P      Display full path for vdev name.
+ *     -v      Display statistics for individual vdevs
+ *     -h      Display help
+ *     -p      Display values in parsable (exact) format.
+ *     -H      Scripted mode.  Don't display headers, and separate properties
+ *             by a single tab.
+ *     -l      Display average latency
+ *     -q      Display queue depths
+ *     -w      Display latency histograms
+ *     -r      Display request size histogram
+ *     -T      Display a timestamp in date(1) or Unix format
+ *
+ * This command can be tricky because we want to be able to deal with pool
+ * creation/destruction as well as vdev configuration changes.  The bulk of this
+ * processing is handled by the pool_list_* routines in zpool_iter.c.  We rely
+ * on pool_list_update() to detect the addition of new pools.  Configuration
+ * changes are all handled within libzfs.
+ */
+int
+zpool_do_iostat(int argc, char **argv)
+{
+       int c;
+       int ret;
+       int npools;
+       float interval = 0;
+       unsigned long count = 0;
+       zpool_list_t *list;
+       boolean_t verbose = B_FALSE;
+       boolean_t latency = B_FALSE, l_histo = B_FALSE, rq_histo = B_FALSE;
+       boolean_t queues = B_FALSE, parsable = B_FALSE, scripted = B_FALSE;
+       boolean_t omit_since_boot = B_FALSE;
+       boolean_t guid = B_FALSE;
+       boolean_t follow_links = B_FALSE;
+       boolean_t full_name = B_FALSE;
+       iostat_cbdata_t cb = { 0 };
+
+       /* Used for printing error message */
+       const char flag_to_arg[] = {[IOS_LATENCY] = 'l', [IOS_QUEUES] = 'q',
+           [IOS_L_HISTO] = 'w', [IOS_RQ_HISTO] = 'r'};
+
+       uint64_t unsupported_flags;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "gLPT:vyhplqrwH")) != -1) {
+               switch (c) {
+               case 'g':
+                       guid = B_TRUE;
+                       break;
+               case 'L':
+                       follow_links = B_TRUE;
+                       break;
+               case 'P':
+                       full_name = B_TRUE;
+                       break;
+               case 'T':
+                       get_timestamp_arg(*optarg);
+                       break;
+               case 'v':
+                       verbose = B_TRUE;
+                       break;
+               case 'p':
+                       parsable = B_TRUE;
+                       break;
+               case 'l':
+                       latency = B_TRUE;
+                       break;
+               case 'q':
+                       queues = B_TRUE;
+                       break;
+               case 'H':
+                       scripted = B_TRUE;
+                       break;
+               case 'w':
+                       l_histo = B_TRUE;
+                       break;
+               case 'r':
+                       rq_histo = B_TRUE;
+                       break;
+               case 'y':
+                       omit_since_boot = B_TRUE;
+                       break;
+               case 'h':
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       cb.cb_literal = parsable;
+       cb.cb_scripted = scripted;
+
+       if (guid)
+               cb.cb_name_flags |= VDEV_NAME_GUID;
+       if (follow_links)
+               cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+       if (full_name)
+               cb.cb_name_flags |= VDEV_NAME_PATH;
+       cb.cb_iteration = 0;
+       cb.cb_namewidth = 0;
+       cb.cb_verbose = verbose;
+
+       /* Get our interval and count values (if any) */
+       if (guid) {
+               get_interval_count_filter_guids(&argc, argv, &interval,
+                   &count, &cb);
+       } else {
+               get_interval_count(&argc, argv, &interval, &count);
+       }
+
+       if (argc == 0) {
+               /* No args, so just print the defaults. */
+       } else if (are_all_pools(argc, argv)) {
+               /* All the args are pool names */
+       } else if (are_vdevs_in_pool(argc, argv, NULL, &cb)) {
+               /* All the args are vdevs */
+               cb.cb_vdev_names = argv;
+               cb.cb_vdev_names_count = argc;
+               argc = 0; /* No pools to process */
+       } else if (are_all_pools(1, argv)) {
+               /* The first arg is a pool name */
+               if (are_vdevs_in_pool(argc - 1, argv + 1, argv[0], &cb)) {
+                       /* ...and the rest are vdev names */
+                       cb.cb_vdev_names = argv + 1;
+                       cb.cb_vdev_names_count = argc - 1;
+                       argc = 1; /* One pool to process */
+               } else {
+                       fprintf(stderr, gettext("Expected either a list of "));
+                       fprintf(stderr, gettext("pools, or list of vdevs in"));
+                       fprintf(stderr, " \"%s\", ", argv[0]);
+                       fprintf(stderr, gettext("but got:\n"));
+                       error_list_unresolved_vdevs(argc - 1, argv + 1,
+                           argv[0], &cb);
+                       fprintf(stderr, "\n");
+                       usage(B_FALSE);
+                       return (1);
+               }
+       } else {
+               /*
+                * The args don't make sense. The first arg isn't a pool name,
+                * nor are all the args vdevs.
+                */
+               fprintf(stderr, gettext("Unable to parse pools/vdevs list.\n"));
+               fprintf(stderr, "\n");
+               return (1);
+       }
+
+       if (cb.cb_vdev_names_count != 0) {
+               /*
+                * If user specified vdevs, it implies verbose.
+                */
+               cb.cb_verbose = B_TRUE;
+       }
+
+       /*
+        * Construct the list of all interesting pools.
+        */
+       ret = 0;
+       if ((list = pool_list_get(argc, argv, NULL, &ret)) == NULL)
+               return (1);
+
+       if (pool_list_count(list) == 0 && argc != 0) {
+               pool_list_free(list);
+               return (1);
+       }
+
+       if (pool_list_count(list) == 0 && interval == 0) {
+               pool_list_free(list);
+               (void) fprintf(stderr, gettext("no pools available\n"));
+               return (1);
+       }
+
+       if ((l_histo || rq_histo) && (queues || latency)) {
+               pool_list_free(list);
+               (void) fprintf(stderr,
+                   gettext("[-r|-w] isn't allowed with [-q|-l]\n"));
+               usage(B_FALSE);
+               return (1);
+       }
+
+       if (l_histo && rq_histo) {
+               pool_list_free(list);
+               (void) fprintf(stderr,
+                   gettext("Only one of [-r|-w] can be passed at a time\n"));
+               usage(B_FALSE);
+               return (1);
+       }
+
+       /*
+        * Enter the main iostat loop.
+        */
+       cb.cb_list = list;
+
+       if (l_histo) {
+               /*
+                * Histograms tables look out of place when you try to display
+                * them with the other stats, so make a rule that you can only
+                * print histograms by themselves.
+                */
+               cb.cb_flags = IOS_L_HISTO_M;
+       } else if (rq_histo) {
+               cb.cb_flags = IOS_RQ_HISTO_M;
+       } else {
+               cb.cb_flags = IOS_DEFAULT_M;
+               if (latency)
+                       cb.cb_flags |= IOS_LATENCY_M;
+               if (queues)
+                       cb.cb_flags |= IOS_QUEUES_M;
+       }
+
+       /*
+        * See if the module supports all the stats we want to display.
+        */
+       unsupported_flags = cb.cb_flags & ~get_stat_flags(list);
+       if (unsupported_flags) {
+               uint64_t f;
+               int idx;
+               fprintf(stderr,
+                   gettext("The loaded zfs module doesn't support:"));
+
+               /* for each bit set in unsupported_flags */
+               for (f = unsupported_flags; f; f &= ~(1ULL << idx)) {
+                       idx = lowbit64(f) - 1;
+                       fprintf(stderr, " -%c", flag_to_arg[idx]);
+               }
+
+               fprintf(stderr, ".  Try running a newer module.\n"),
+               pool_list_free(list);
+
+               return (1);
+       }
+
+
+       for (;;) {
+               if ((npools = pool_list_count(list)) == 0)
+                       (void) fprintf(stderr, gettext("no pools available\n"));
+               else {
+                       /*
+                        * If this is the first iteration and -y was supplied
+                        * we skip any printing.
+                        */
+                       boolean_t skip = (omit_since_boot &&
+                           cb.cb_iteration == 0);
+
+                       /*
+                        * Refresh all statistics.  This is done as an
+                        * explicit step before calculating the maximum name
+                        * width, so that any * configuration changes are
+                        * properly accounted for.
+                        */
+                       (void) pool_list_iter(list, B_FALSE, refresh_iostat,
+                           &cb);
+
+                       /*
+                        * Iterate over all pools to determine the maximum width
+                        * for the pool / device name column across all pools.
+                        */
+                       cb.cb_namewidth = 0;
+                       (void) pool_list_iter(list, B_FALSE, get_namewidth,
+                           &cb);
+
+                       if (timestamp_fmt != NODATE)
+                               print_timestamp(timestamp_fmt);
+
+                       /*
+                        * If it's the first time and we're not skipping it,
+                        * or either skip or verbose mode, print the header.
+                        *
+                        * The histogram code explicitly prints its header on
+                        * every vdev, so skip this for histograms.
+                        */
+                       if (((++cb.cb_iteration == 1 && !skip) ||
+                           (skip != verbose)) &&
+                           (!(cb.cb_flags & IOS_ANYHISTO_M)) &&
+                           !cb.cb_scripted)
+                               print_iostat_header(&cb);
+
+                       if (skip) {
+                               (void) fsleep(interval);
+                               continue;
+                       }
+
+                       pool_list_iter(list, B_FALSE, print_iostat, &cb);
+
+                       /*
+                        * If there's more than one pool, and we're not in
+                        * verbose mode (which prints a separator for us),
+                        * then print a separator.
+                        *
+                        * In addition, if we're printing specific vdevs then
+                        * we also want an ending separator.
+                        */
+                       if (((npools > 1 && !verbose &&
+                           !(cb.cb_flags & IOS_ANYHISTO_M)) ||
+                           (!(cb.cb_flags & IOS_ANYHISTO_M) &&
+                           cb.cb_vdev_names_count)) &&
+                           !cb.cb_scripted) {
+                               print_iostat_separator(&cb);
+                       }
+               }
+
+               /*
+                * Flush the output so that redirection to a file isn't buffered
+                * indefinitely.
+                */
+               (void) fflush(stdout);
+
+               if (interval == 0)
+                       break;
+
+               if (count != 0 && --count == 0)
+                       break;
+
+               (void) fsleep(interval);
+       }
+
+       pool_list_free(list);
+
+       return (ret);
+}
+
+typedef struct list_cbdata {
+       boolean_t       cb_verbose;
+       int             cb_name_flags;
+       int             cb_namewidth;
+       boolean_t       cb_scripted;
+       zprop_list_t    *cb_proplist;
+       boolean_t       cb_literal;
+} list_cbdata_t;
+
+/*
+ * Given a list of columns to display, output appropriate headers for each one.
+ */
+static void
+print_header(list_cbdata_t *cb)
+{
+       zprop_list_t *pl = cb->cb_proplist;
+       char headerbuf[ZPOOL_MAXPROPLEN];
+       const char *header;
+       boolean_t first = B_TRUE;
+       boolean_t right_justify;
+       size_t width = 0;
+
+       for (; pl != NULL; pl = pl->pl_next) {
+               width = pl->pl_width;
+               if (first && cb->cb_verbose) {
+                       /*
+                        * Reset the width to accommodate the verbose listing
+                        * of devices.
+                        */
+                       width = cb->cb_namewidth;
+               }
+
+               if (!first)
+                       (void) printf("  ");
+               else
+                       first = B_FALSE;
+
+               right_justify = B_FALSE;
+               if (pl->pl_prop != ZPROP_INVAL) {
+                       header = zpool_prop_column_name(pl->pl_prop);
+                       right_justify = zpool_prop_align_right(pl->pl_prop);
+               } else {
+                       int i;
+
+                       for (i = 0; pl->pl_user_prop[i] != '\0'; i++)
+                               headerbuf[i] = toupper(pl->pl_user_prop[i]);
+                       headerbuf[i] = '\0';
+                       header = headerbuf;
+               }
+
+               if (pl->pl_next == NULL && !right_justify)
+                       (void) printf("%s", header);
+               else if (right_justify)
+                       (void) printf("%*s", (int)width, header);
+               else
+                       (void) printf("%-*s", (int)width, header);
+       }
+
+       (void) printf("\n");
+}
+
+/*
+ * Given a pool and a list of properties, print out all the properties according
+ * to the described layout.
+ */
+static void
+print_pool(zpool_handle_t *zhp, list_cbdata_t *cb)
+{
+       zprop_list_t *pl = cb->cb_proplist;
+       boolean_t first = B_TRUE;
+       char property[ZPOOL_MAXPROPLEN];
+       char *propstr;
+       boolean_t right_justify;
+       size_t width;
+
+       for (; pl != NULL; pl = pl->pl_next) {
+
+               width = pl->pl_width;
+               if (first && cb->cb_verbose) {
+                       /*
+                        * Reset the width to accommodate the verbose listing
+                        * of devices.
+                        */
+                       width = cb->cb_namewidth;
+               }
+
+               if (!first) {
+                       if (cb->cb_scripted)
+                               (void) printf("\t");
+                       else
+                               (void) printf("  ");
+               } else {
+                       first = B_FALSE;
+               }
+
+               right_justify = B_FALSE;
+               if (pl->pl_prop != ZPROP_INVAL) {
+                       if (zpool_get_prop(zhp, pl->pl_prop, property,
+                           sizeof (property), NULL, cb->cb_literal) != 0)
+                               propstr = "-";
+                       else
+                               propstr = property;
+
+                       right_justify = zpool_prop_align_right(pl->pl_prop);
+               } else if ((zpool_prop_feature(pl->pl_user_prop) ||
+                   zpool_prop_unsupported(pl->pl_user_prop)) &&
+                   zpool_prop_get_feature(zhp, pl->pl_user_prop, property,
+                   sizeof (property)) == 0) {
+                       propstr = property;
+               } else {
+                       propstr = "-";
+               }
+
+
+               /*
+                * If this is being called in scripted mode, or if this is the
+                * last column and it is left-justified, don't include a width
+                * format specifier.
+                */
+               if (cb->cb_scripted || (pl->pl_next == NULL && !right_justify))
+                       (void) printf("%s", propstr);
+               else if (right_justify)
+                       (void) printf("%*s", (int)width, propstr);
+               else
+                       (void) printf("%-*s", (int)width, propstr);
+       }
+
+       (void) printf("\n");
+}
+
+static void
+print_one_column(zpool_prop_t prop, uint64_t value, boolean_t scripted,
+    boolean_t valid, enum zfs_nicenum_format format)
+{
+       char propval[64];
+       boolean_t fixed;
+       size_t width = zprop_width(prop, &fixed, ZFS_TYPE_POOL);
+
+       switch (prop) {
+       case ZPOOL_PROP_EXPANDSZ:
+               if (value == 0)
+                       (void) strlcpy(propval, "-", sizeof (propval));
+               else
+                       zfs_nicenum_format(value, propval, sizeof (propval),
+                           format);
+               break;
+       case ZPOOL_PROP_FRAGMENTATION:
+               if (value == ZFS_FRAG_INVALID) {
+                       (void) strlcpy(propval, "-", sizeof (propval));
+               } else if (format == ZFS_NICENUM_RAW) {
+                       (void) snprintf(propval, sizeof (propval), "%llu",
+                           (unsigned long long)value);
+               } else {
+                       (void) snprintf(propval, sizeof (propval), "%llu%%",
+                           (unsigned long long)value);
+               }
+               break;
+       case ZPOOL_PROP_CAPACITY:
+               if (format == ZFS_NICENUM_RAW)
+                       (void) snprintf(propval, sizeof (propval), "%llu",
+                           (unsigned long long)value);
+               else
+                       (void) snprintf(propval, sizeof (propval), "%llu%%",
+                           (unsigned long long)value);
+               break;
+       default:
+               zfs_nicenum_format(value, propval, sizeof (propval), format);
+       }
+
+       if (!valid)
+               (void) strlcpy(propval, "-", sizeof (propval));
+
+       if (scripted)
+               (void) printf("\t%s", propval);
+       else
+               (void) printf("  %*s", (int)width, propval);
+}
+
+void
+print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
+    list_cbdata_t *cb, int depth)
+{
+       nvlist_t **child;
+       vdev_stat_t *vs;
+       uint_t c, children;
+       char *vname;
+       boolean_t scripted = cb->cb_scripted;
+       uint64_t islog = B_FALSE;
+       boolean_t haslog = B_FALSE;
+       char *dashes = "%-*s      -      -      -         -      -      -\n";
+
+       verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &c) == 0);
+
+       if (name != NULL) {
+               boolean_t toplevel = (vs->vs_space != 0);
+               uint64_t cap;
+               enum zfs_nicenum_format format;
+
+               if (cb->cb_literal)
+                       format = ZFS_NICENUM_RAW;
+               else
+                       format = ZFS_NICENUM_1024;
+
+               if (scripted)
+                       (void) printf("\t%s", name);
+               else if (strlen(name) + depth > cb->cb_namewidth)
+                       (void) printf("%*s%s", depth, "", name);
+               else
+                       (void) printf("%*s%s%*s", depth, "", name,
+                           (int)(cb->cb_namewidth - strlen(name) - depth), "");
+
+               /*
+                * Print the properties for the individual vdevs. Some
+                * properties are only applicable to toplevel vdevs. The
+                * 'toplevel' boolean value is passed to the print_one_column()
+                * to indicate that the value is valid.
+                */
+               print_one_column(ZPOOL_PROP_SIZE, vs->vs_space, scripted,
+                   toplevel, format);
+               print_one_column(ZPOOL_PROP_ALLOCATED, vs->vs_alloc, scripted,
+                   toplevel, format);
+               print_one_column(ZPOOL_PROP_FREE, vs->vs_space - vs->vs_alloc,
+                   scripted, toplevel, format);
+               print_one_column(ZPOOL_PROP_EXPANDSZ, vs->vs_esize, scripted,
+                   B_TRUE, format);
+               print_one_column(ZPOOL_PROP_FRAGMENTATION,
+                   vs->vs_fragmentation, scripted,
+                   (vs->vs_fragmentation != ZFS_FRAG_INVALID && toplevel),
+                   format);
+               cap = (vs->vs_space == 0) ? 0 :
+                   (vs->vs_alloc * 100 / vs->vs_space);
+               print_one_column(ZPOOL_PROP_CAPACITY, cap, scripted, toplevel,
+                   format);
+               (void) printf("\n");
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               return;
+
+       for (c = 0; c < children; c++) {
+               uint64_t ishole = B_FALSE;
+
+               if (nvlist_lookup_uint64(child[c],
+                   ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
+                       continue;
+
+               if (nvlist_lookup_uint64(child[c],
+                   ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) {
+                       haslog = B_TRUE;
+                       continue;
+               }
+
+               vname = zpool_vdev_name(g_zfs, zhp, child[c],
+                   cb->cb_name_flags);
+               print_list_stats(zhp, vname, child[c], cb, depth + 2);
+               free(vname);
+       }
+
+       if (haslog == B_TRUE) {
+               /* LINTED E_SEC_PRINTF_VAR_FMT */
+               (void) printf(dashes, cb->cb_namewidth, "log");
+               for (c = 0; c < children; c++) {
+                       if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                           &islog) != 0 || !islog)
+                               continue;
+                       vname = zpool_vdev_name(g_zfs, zhp, child[c],
+                           cb->cb_name_flags);
+                       print_list_stats(zhp, vname, child[c], cb, depth + 2);
+                       free(vname);
+               }
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+           &child, &children) == 0 && children > 0) {
+               /* LINTED E_SEC_PRINTF_VAR_FMT */
+               (void) printf(dashes, cb->cb_namewidth, "cache");
+               for (c = 0; c < children; c++) {
+                       vname = zpool_vdev_name(g_zfs, zhp, child[c],
+                           cb->cb_name_flags);
+                       print_list_stats(zhp, vname, child[c], cb, depth + 2);
+                       free(vname);
+               }
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
+           &children) == 0 && children > 0) {
+               /* LINTED E_SEC_PRINTF_VAR_FMT */
+               (void) printf(dashes, cb->cb_namewidth, "spare");
+               for (c = 0; c < children; c++) {
+                       vname = zpool_vdev_name(g_zfs, zhp, child[c],
+                           cb->cb_name_flags);
+                       print_list_stats(zhp, vname, child[c], cb, depth + 2);
+                       free(vname);
+               }
+       }
+}
+
+
+/*
+ * Generic callback function to list a pool.
+ */
+int
+list_callback(zpool_handle_t *zhp, void *data)
+{
+       list_cbdata_t *cbp = data;
+       nvlist_t *config;
+       nvlist_t *nvroot;
+
+       config = zpool_get_config(zhp, NULL);
+
+       print_pool(zhp, cbp);
+       if (!cbp->cb_verbose)
+               return (0);
+
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+       print_list_stats(zhp, NULL, nvroot, cbp, 0);
+
+       return (0);
+}
+
+/*
+ * zpool list [-gHLpP] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
+ *
+ *     -g      Display guid for individual vdev name.
+ *     -H      Scripted mode.  Don't display headers, and separate properties
+ *             by a single tab.
+ *     -L      Follow links when resolving vdev path name.
+ *     -o      List of properties to display.  Defaults to
+ *             "name,size,allocated,free,expandsize,fragmentation,capacity,"
+ *             "dedupratio,health,altroot"
+ *     -p      Display values in parsable (exact) format.
+ *     -P      Display full path for vdev name.
+ *     -T      Display a timestamp in date(1) or Unix format
+ *
+ * List all pools in the system, whether or not they're healthy.  Output space
+ * statistics for each one, as well as health status summary.
+ */
+int
+zpool_do_list(int argc, char **argv)
+{
+       int c;
+       int ret = 0;
+       list_cbdata_t cb = { 0 };
+       static char default_props[] =
+           "name,size,allocated,free,expandsize,fragmentation,capacity,"
+           "dedupratio,health,altroot";
+       char *props = default_props;
+       float interval = 0;
+       unsigned long count = 0;
+       zpool_list_t *list;
+       boolean_t first = B_TRUE;
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":gHLo:pPT:v")) != -1) {
+               switch (c) {
+               case 'g':
+                       cb.cb_name_flags |= VDEV_NAME_GUID;
+                       break;
+               case 'H':
+                       cb.cb_scripted = B_TRUE;
+                       break;
+               case 'L':
+                       cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+                       break;
+               case 'o':
+                       props = optarg;
+                       break;
+               case 'P':
+                       cb.cb_name_flags |= VDEV_NAME_PATH;
+                       break;
+               case 'p':
+                       cb.cb_literal = B_TRUE;
+                       break;
+               case 'T':
+                       get_timestamp_arg(*optarg);
+                       break;
+               case 'v':
+                       cb.cb_verbose = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       get_interval_count(&argc, argv, &interval, &count);
+
+       if (zprop_get_list(g_zfs, props, &cb.cb_proplist, ZFS_TYPE_POOL) != 0)
+               usage(B_FALSE);
+
+       for (;;) {
+               if ((list = pool_list_get(argc, argv, &cb.cb_proplist,
+                   &ret)) == NULL)
+                       return (1);
+
+               if (pool_list_count(list) == 0)
+                       break;
+
+               if (timestamp_fmt != NODATE)
+                       print_timestamp(timestamp_fmt);
+
+               if (!cb.cb_scripted && (first || cb.cb_verbose)) {
+                       print_header(&cb);
+                       first = B_FALSE;
+               }
+               ret = pool_list_iter(list, B_TRUE, list_callback, &cb);
+
+               if (interval == 0)
+                       break;
+
+               if (count != 0 && --count == 0)
+                       break;
+
+               pool_list_free(list);
+               (void) fsleep(interval);
+       }
+
+       if (argc == 0 && !cb.cb_scripted && pool_list_count(list) == 0) {
+               (void) printf(gettext("no pools available\n"));
+               ret = 0;
+       }
+
+       pool_list_free(list);
+       zprop_free_list(cb.cb_proplist);
+       return (ret);
+}
+
+static int
+zpool_do_attach_or_replace(int argc, char **argv, int replacing)
+{
+       boolean_t force = B_FALSE;
+       int c;
+       nvlist_t *nvroot;
+       char *poolname, *old_disk, *new_disk;
+       zpool_handle_t *zhp;
+       nvlist_t *props = NULL;
+       char *propval;
+       int ret;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "fo:")) != -1) {
+               switch (c) {
+               case 'f':
+                       force = B_TRUE;
+                       break;
+               case 'o':
+                       if ((propval = strchr(optarg, '=')) == NULL) {
+                               (void) fprintf(stderr, gettext("missing "
+                                   "'=' for -o option\n"));
+                               usage(B_FALSE);
+                       }
+                       *propval = '\0';
+                       propval++;
+
+                       if ((strcmp(optarg, ZPOOL_CONFIG_ASHIFT) != 0) ||
+                           (add_prop_list(optarg, propval, &props, B_TRUE)))
+                               usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name argument\n"));
+               usage(B_FALSE);
+       }
+
+       poolname = argv[0];
+
+       if (argc < 2) {
+               (void) fprintf(stderr,
+                   gettext("missing <device> specification\n"));
+               usage(B_FALSE);
+       }
+
+       old_disk = argv[1];
+
+       if (argc < 3) {
+               if (!replacing) {
+                       (void) fprintf(stderr,
+                           gettext("missing <new_device> specification\n"));
+                       usage(B_FALSE);
+               }
+               new_disk = old_disk;
+               argc -= 1;
+               argv += 1;
+       } else {
+               new_disk = argv[2];
+               argc -= 2;
+               argv += 2;
+       }
+
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       if ((zhp = zpool_open(g_zfs, poolname)) == NULL) {
+               nvlist_free(props);
+               return (1);
+       }
+
+       if (zpool_get_config(zhp, NULL) == NULL) {
+               (void) fprintf(stderr, gettext("pool '%s' is unavailable\n"),
+                   poolname);
+               zpool_close(zhp);
+               nvlist_free(props);
+               return (1);
+       }
+
+       nvroot = make_root_vdev(zhp, props, force, B_FALSE, replacing, B_FALSE,
+           argc, argv);
+       if (nvroot == NULL) {
+               zpool_close(zhp);
+               nvlist_free(props);
+               return (1);
+       }
+
+       ret = zpool_vdev_attach(zhp, old_disk, new_disk, nvroot, replacing);
+
+       nvlist_free(props);
+       nvlist_free(nvroot);
+       zpool_close(zhp);
+
+       return (ret);
+}
+
+/*
+ * zpool replace [-f] <pool> <device> <new_device>
+ *
+ *     -f      Force attach, even if <new_device> appears to be in use.
+ *
+ * Replace <device> with <new_device>.
+ */
+/* ARGSUSED */
+int
+zpool_do_replace(int argc, char **argv)
+{
+       return (zpool_do_attach_or_replace(argc, argv, B_TRUE));
+}
+
+/*
+ * zpool attach [-f] [-o property=value] <pool> <device> <new_device>
+ *
+ *     -f      Force attach, even if <new_device> appears to be in use.
+ *     -o      Set property=value.
+ *
+ * Attach <new_device> to the mirror containing <device>.  If <device> is not
+ * part of a mirror, then <device> will be transformed into a mirror of
+ * <device> and <new_device>.  In either case, <new_device> will begin life
+ * with a DTL of [0, now], and will immediately begin to resilver itself.
+ */
+int
+zpool_do_attach(int argc, char **argv)
+{
+       return (zpool_do_attach_or_replace(argc, argv, B_FALSE));
+}
+
+/*
+ * zpool detach [-f] <pool> <device>
+ *
+ *     -f      Force detach of <device>, even if DTLs argue against it
+ *             (not supported yet)
+ *
+ * Detach a device from a mirror.  The operation will be refused if <device>
+ * is the last device in the mirror, or if the DTLs indicate that this device
+ * has the only valid copy of some data.
+ */
+/* ARGSUSED */
+int
+zpool_do_detach(int argc, char **argv)
+{
+       int c;
+       char *poolname, *path;
+       zpool_handle_t *zhp;
+       int ret;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "f")) != -1) {
+               switch (c) {
+               case 'f':
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name argument\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc < 2) {
+               (void) fprintf(stderr,
+                   gettext("missing <device> specification\n"));
+               usage(B_FALSE);
+       }
+
+       poolname = argv[0];
+       path = argv[1];
+
+       if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+               return (1);
+
+       ret = zpool_vdev_detach(zhp, path);
+
+       zpool_close(zhp);
+
+       return (ret);
+}
+
+/*
+ * zpool split [-gLnP] [-o prop=val] ...
+ *             [-o mntopt] ...
+ *             [-R altroot] <pool> <newpool> [<device> ...]
+ *
+ *     -g      Display guid for individual vdev name.
+ *     -L      Follow links when resolving vdev path name.
+ *     -n      Do not split the pool, but display the resulting layout if
+ *             it were to be split.
+ *     -o      Set property=value, or set mount options.
+ *     -P      Display full path for vdev name.
+ *     -R      Mount the split-off pool under an alternate root.
+ *
+ * Splits the named pool and gives it the new pool name.  Devices to be split
+ * off may be listed, provided that no more than one device is specified
+ * per top-level vdev mirror.  The newly split pool is left in an exported
+ * state unless -R is specified.
+ *
+ * Restrictions: the top-level of the pool pool must only be made up of
+ * mirrors; all devices in the pool must be healthy; no device may be
+ * undergoing a resilvering operation.
+ */
+int
+zpool_do_split(int argc, char **argv)
+{
+       char *srcpool, *newpool, *propval;
+       char *mntopts = NULL;
+       splitflags_t flags;
+       int c, ret = 0;
+       zpool_handle_t *zhp;
+       nvlist_t *config, *props = NULL;
+
+       flags.dryrun = B_FALSE;
+       flags.import = B_FALSE;
+       flags.name_flags = 0;
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":gLR:no:P")) != -1) {
+               switch (c) {
+               case 'g':
+                       flags.name_flags |= VDEV_NAME_GUID;
+                       break;
+               case 'L':
+                       flags.name_flags |= VDEV_NAME_FOLLOW_LINKS;
+                       break;
+               case 'R':
+                       flags.import = B_TRUE;
+                       if (add_prop_list(
+                           zpool_prop_to_name(ZPOOL_PROP_ALTROOT), optarg,
+                           &props, B_TRUE) != 0) {
+                               nvlist_free(props);
+                               usage(B_FALSE);
+                       }
+                       break;
+               case 'n':
+                       flags.dryrun = B_TRUE;
+                       break;
+               case 'o':
+                       if ((propval = strchr(optarg, '=')) != NULL) {
+                               *propval = '\0';
+                               propval++;
+                               if (add_prop_list(optarg, propval,
+                                   &props, B_TRUE) != 0) {
+                                       nvlist_free(props);
+                                       usage(B_FALSE);
+                               }
+                       } else {
+                               mntopts = optarg;
+                       }
+                       break;
+               case 'P':
+                       flags.name_flags |= VDEV_NAME_PATH;
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+                       break;
+               }
+       }
+
+       if (!flags.import && mntopts != NULL) {
+               (void) fprintf(stderr, gettext("setting mntopts is only "
+                   "valid when importing the pool\n"));
+               usage(B_FALSE);
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("Missing pool name\n"));
+               usage(B_FALSE);
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("Missing new pool name\n"));
+               usage(B_FALSE);
+       }
+
+       srcpool = argv[0];
+       newpool = argv[1];
+
+       argc -= 2;
+       argv += 2;
+
+       if ((zhp = zpool_open(g_zfs, srcpool)) == NULL) {
+               nvlist_free(props);
+               return (1);
+       }
+
+       config = split_mirror_vdev(zhp, newpool, props, flags, argc, argv);
+       if (config == NULL) {
+               ret = 1;
+       } else {
+               if (flags.dryrun) {
+                       (void) printf(gettext("would create '%s' with the "
+                           "following layout:\n\n"), newpool);
+                       print_vdev_tree(NULL, newpool, config, 0, B_FALSE,
+                           flags.name_flags);
+               }
+       }
+
+       zpool_close(zhp);
+
+       if (ret != 0 || flags.dryrun || !flags.import) {
+               nvlist_free(config);
+               nvlist_free(props);
+               return (ret);
+       }
+
+       /*
+        * The split was successful. Now we need to open the new
+        * pool and import it.
+        */
+       if ((zhp = zpool_open_canfail(g_zfs, newpool)) == NULL) {
+               nvlist_free(config);
+               nvlist_free(props);
+               return (1);
+       }
+       if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL &&
+           zpool_enable_datasets(zhp, mntopts, 0) != 0) {
+               ret = 1;
+               (void) fprintf(stderr, gettext("Split was successful, but "
+                   "the datasets could not all be mounted\n"));
+               (void) fprintf(stderr, gettext("Try doing '%s' with a "
+                   "different altroot\n"), "zpool import");
+       }
+       zpool_close(zhp);
+       nvlist_free(config);
+       nvlist_free(props);
+
+       return (ret);
+}
+
+
+
+/*
+ * zpool online <pool> <device> ...
+ */
+int
+zpool_do_online(int argc, char **argv)
+{
+       int c, i;
+       char *poolname;
+       zpool_handle_t *zhp;
+       int ret = 0;
+       vdev_state_t newstate;
+       int flags = 0;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "et")) != -1) {
+               switch (c) {
+               case 'e':
+                       flags |= ZFS_ONLINE_EXPAND;
+                       break;
+               case 't':
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name\n"));
+               usage(B_FALSE);
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing device name\n"));
+               usage(B_FALSE);
+       }
+
+       poolname = argv[0];
+
+       if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+               return (1);
+
+       for (i = 1; i < argc; i++) {
+               if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
+                       if (newstate != VDEV_STATE_HEALTHY) {
+                               (void) printf(gettext("warning: device '%s' "
+                                   "onlined, but remains in faulted state\n"),
+                                   argv[i]);
+                               if (newstate == VDEV_STATE_FAULTED)
+                                       (void) printf(gettext("use 'zpool "
+                                           "clear' to restore a faulted "
+                                           "device\n"));
+                               else
+                                       (void) printf(gettext("use 'zpool "
+                                           "replace' to replace devices "
+                                           "that are no longer present\n"));
+                       }
+               } else {
+                       ret = 1;
+               }
+       }
+
+       zpool_close(zhp);
+
+       return (ret);
+}
+
+/*
+ * zpool offline [-ft] <pool> <device> ...
+ *
+ *     -f      Force the device into the offline state, even if doing
+ *             so would appear to compromise pool availability.
+ *             (not supported yet)
+ *
+ *     -t      Only take the device off-line temporarily.  The offline
+ *             state will not be persistent across reboots.
+ */
+/* ARGSUSED */
+int
+zpool_do_offline(int argc, char **argv)
+{
+       int c, i;
+       char *poolname;
+       zpool_handle_t *zhp;
+       int ret = 0;
+       boolean_t istmp = B_FALSE;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "ft")) != -1) {
+               switch (c) {
+               case 't':
+                       istmp = B_TRUE;
+                       break;
+               case 'f':
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name\n"));
+               usage(B_FALSE);
+       }
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing device name\n"));
+               usage(B_FALSE);
+       }
+
+       poolname = argv[0];
+
+       if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+               return (1);
+
+       for (i = 1; i < argc; i++) {
+               if (zpool_vdev_offline(zhp, argv[i], istmp) != 0)
+                       ret = 1;
+       }
+
+       zpool_close(zhp);
+
+       return (ret);
+}
+
+/*
+ * zpool clear <pool> [device]
+ *
+ * Clear all errors associated with a pool or a particular device.
+ */
+int
+zpool_do_clear(int argc, char **argv)
+{
+       int c;
+       int ret = 0;
+       boolean_t dryrun = B_FALSE;
+       boolean_t do_rewind = B_FALSE;
+       boolean_t xtreme_rewind = B_FALSE;
+       uint32_t rewind_policy = ZPOOL_NO_REWIND;
+       nvlist_t *policy = NULL;
+       zpool_handle_t *zhp;
+       char *pool, *device;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "FnX")) != -1) {
+               switch (c) {
+               case 'F':
+                       do_rewind = B_TRUE;
+                       break;
+               case 'n':
+                       dryrun = B_TRUE;
+                       break;
+               case 'X':
+                       xtreme_rewind = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc > 2) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       if ((dryrun || xtreme_rewind) && !do_rewind) {
+               (void) fprintf(stderr,
+                   gettext("-n or -X only meaningful with -F\n"));
+               usage(B_FALSE);
+       }
+       if (dryrun)
+               rewind_policy = ZPOOL_TRY_REWIND;
+       else if (do_rewind)
+               rewind_policy = ZPOOL_DO_REWIND;
+       if (xtreme_rewind)
+               rewind_policy |= ZPOOL_EXTREME_REWIND;
+
+       /* In future, further rewind policy choices can be passed along here */
+       if (nvlist_alloc(&policy, NV_UNIQUE_NAME, 0) != 0 ||
+           nvlist_add_uint32(policy, ZPOOL_REWIND_REQUEST, rewind_policy) != 0)
+               return (1);
+
+       pool = argv[0];
+       device = argc == 2 ? argv[1] : NULL;
+
+       if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL) {
+               nvlist_free(policy);
+               return (1);
+       }
+
+       if (zpool_clear(zhp, device, policy) != 0)
+               ret = 1;
+
+       zpool_close(zhp);
+
+       nvlist_free(policy);
+
+       return (ret);
+}
+
+/*
+ * zpool reguid <pool>
+ */
+int
+zpool_do_reguid(int argc, char **argv)
+{
+       int c;
+       char *poolname;
+       zpool_handle_t *zhp;
+       int ret = 0;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "")) != -1) {
+               switch (c) {
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       /* get pool name and check number of arguments */
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       poolname = argv[0];
+       if ((zhp = zpool_open(g_zfs, poolname)) == NULL)
+               return (1);
+
+       ret = zpool_reguid(zhp);
+
+       zpool_close(zhp);
+       return (ret);
+}
+
+
+/*
+ * zpool reopen <pool>
+ *
+ * Reopen the pool so that the kernel can update the sizes of all vdevs.
+ */
+int
+zpool_do_reopen(int argc, char **argv)
+{
+       int c;
+       int ret = 0;
+       zpool_handle_t *zhp;
+       char *pool;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "")) != -1) {
+               switch (c) {
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc--;
+       argv++;
+
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc > 1) {
+               (void) fprintf(stderr, gettext("too many arguments\n"));
+               usage(B_FALSE);
+       }
+
+       pool = argv[0];
+       if ((zhp = zpool_open_canfail(g_zfs, pool)) == NULL)
+               return (1);
+
+       ret = zpool_reopen(zhp);
+       zpool_close(zhp);
+       return (ret);
+}
+
+typedef struct scrub_cbdata {
+       int     cb_type;
+       int     cb_argc;
+       char    **cb_argv;
+} scrub_cbdata_t;
+
+int
+scrub_callback(zpool_handle_t *zhp, void *data)
+{
+       scrub_cbdata_t *cb = data;
+       int err;
+
+       /*
+        * Ignore faulted pools.
+        */
+       if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+               (void) fprintf(stderr, gettext("cannot scrub '%s': pool is "
+                   "currently unavailable\n"), zpool_get_name(zhp));
+               return (1);
+       }
+
+       err = zpool_scan(zhp, cb->cb_type);
+
+       return (err != 0);
+}
+
+/*
+ * zpool scrub [-s] <pool> ...
+ *
+ *     -s      Stop.  Stops any in-progress scrub.
+ */
+int
+zpool_do_scrub(int argc, char **argv)
+{
+       int c;
+       scrub_cbdata_t cb;
+
+       cb.cb_type = POOL_SCAN_SCRUB;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "s")) != -1) {
+               switch (c) {
+               case 's':
+                       cb.cb_type = POOL_SCAN_NONE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       cb.cb_argc = argc;
+       cb.cb_argv = argv;
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing pool name argument\n"));
+               usage(B_FALSE);
+       }
+
+       return (for_each_pool(argc, argv, B_TRUE, NULL, scrub_callback, &cb));
+}
+
+/*
+ * Print out detailed scrub status.
+ */
+void
+print_scan_status(pool_scan_stat_t *ps)
+{
+       time_t start, end;
+       uint64_t elapsed, mins_left, hours_left;
+       uint64_t pass_exam, examined, total;
+       uint_t rate;
+       double fraction_done;
+       char processed_buf[7], examined_buf[7], total_buf[7], rate_buf[7];
+
+       (void) printf(gettext("  scan: "));
+
+       /* If there's never been a scan, there's not much to say. */
+       if (ps == NULL || ps->pss_func == POOL_SCAN_NONE ||
+           ps->pss_func >= POOL_SCAN_FUNCS) {
+               (void) printf(gettext("none requested\n"));
+               return;
+       }
+
+       start = ps->pss_start_time;
+       end = ps->pss_end_time;
+       zfs_nicenum(ps->pss_processed, processed_buf, sizeof (processed_buf));
+
+       assert(ps->pss_func == POOL_SCAN_SCRUB ||
+           ps->pss_func == POOL_SCAN_RESILVER);
+       /*
+        * Scan is finished or canceled.
+        */
+       if (ps->pss_state == DSS_FINISHED) {
+               uint64_t minutes_taken = (end - start) / 60;
+               char *fmt = NULL;
+
+               if (ps->pss_func == POOL_SCAN_SCRUB) {
+                       fmt = gettext("scrub repaired %s in %lluh%um with "
+                           "%llu errors on %s");
+               } else if (ps->pss_func == POOL_SCAN_RESILVER) {
+                       fmt = gettext("resilvered %s in %lluh%um with "
+                           "%llu errors on %s");
+               }
+               /* LINTED */
+               (void) printf(fmt, processed_buf,
+                   (u_longlong_t)(minutes_taken / 60),
+                   (uint_t)(minutes_taken % 60),
+                   (u_longlong_t)ps->pss_errors,
+                   ctime((time_t *)&end));
+               return;
+       } else if (ps->pss_state == DSS_CANCELED) {
+               if (ps->pss_func == POOL_SCAN_SCRUB) {
+                       (void) printf(gettext("scrub canceled on %s"),
+                           ctime(&end));
+               } else if (ps->pss_func == POOL_SCAN_RESILVER) {
+                       (void) printf(gettext("resilver canceled on %s"),
+                           ctime(&end));
+               }
+               return;
+       }
+
+       assert(ps->pss_state == DSS_SCANNING);
+
+       /*
+        * Scan is in progress.
+        */
+       if (ps->pss_func == POOL_SCAN_SCRUB) {
+               (void) printf(gettext("scrub in progress since %s"),
+                   ctime(&start));
+       } else if (ps->pss_func == POOL_SCAN_RESILVER) {
+               (void) printf(gettext("resilver in progress since %s"),
+                   ctime(&start));
+       }
+
+       examined = ps->pss_examined ? ps->pss_examined : 1;
+       total = ps->pss_to_examine;
+       fraction_done = (double)examined / total;
+
+       /* elapsed time for this pass */
+       elapsed = time(NULL) - ps->pss_pass_start;
+       elapsed = elapsed ? elapsed : 1;
+       pass_exam = ps->pss_pass_exam ? ps->pss_pass_exam : 1;
+       rate = pass_exam / elapsed;
+       rate = rate ? rate : 1;
+       mins_left = ((total - examined) / rate) / 60;
+       hours_left = mins_left / 60;
+
+       zfs_nicenum(examined, examined_buf, sizeof (examined_buf));
+       zfs_nicenum(total, total_buf, sizeof (total_buf));
+       zfs_nicenum(rate, rate_buf, sizeof (rate_buf));
+
+       /*
+        * do not print estimated time if hours_left is more than 30 days
+        */
+       (void) printf(gettext("\t%s scanned out of %s at %s/s"),
+           examined_buf, total_buf, rate_buf);
+       if (hours_left < (30 * 24)) {
+               (void) printf(gettext(", %lluh%um to go\n"),
+                   (u_longlong_t)hours_left, (uint_t)(mins_left % 60));
+       } else {
+               (void) printf(gettext(
+                   ", (scan is slow, no estimated time)\n"));
+       }
+
+       if (ps->pss_func == POOL_SCAN_RESILVER) {
+               (void) printf(gettext("\t%s resilvered, %.2f%% done\n"),
+                   processed_buf, 100 * fraction_done);
+       } else if (ps->pss_func == POOL_SCAN_SCRUB) {
+               (void) printf(gettext("\t%s repaired, %.2f%% done\n"),
+                   processed_buf, 100 * fraction_done);
+       }
+}
+
+static void
+print_error_log(zpool_handle_t *zhp)
+{
+       nvlist_t *nverrlist = NULL;
+       nvpair_t *elem;
+       char *pathname;
+       size_t len = MAXPATHLEN * 2;
+
+       if (zpool_get_errlog(zhp, &nverrlist) != 0) {
+               (void) printf("errors: List of errors unavailable "
+                   "(insufficient privileges)\n");
+               return;
+       }
+
+       (void) printf("errors: Permanent errors have been "
+           "detected in the following files:\n\n");
+
+       pathname = safe_malloc(len);
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(nverrlist, elem)) != NULL) {
+               nvlist_t *nv;
+               uint64_t dsobj, obj;
+
+               verify(nvpair_value_nvlist(elem, &nv) == 0);
+               verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_DATASET,
+                   &dsobj) == 0);
+               verify(nvlist_lookup_uint64(nv, ZPOOL_ERR_OBJECT,
+                   &obj) == 0);
+               zpool_obj_to_path(zhp, dsobj, obj, pathname, len);
+               (void) printf("%7s %s\n", "", pathname);
+       }
+       free(pathname);
+       nvlist_free(nverrlist);
+}
+
+static void
+print_spares(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **spares,
+    uint_t nspares)
+{
+       uint_t i;
+       char *name;
+
+       if (nspares == 0)
+               return;
+
+       (void) printf(gettext("\tspares\n"));
+
+       for (i = 0; i < nspares; i++) {
+               name = zpool_vdev_name(g_zfs, zhp, spares[i],
+                   cb->cb_name_flags);
+               print_status_config(zhp, cb, name, spares[i], 2, B_TRUE);
+               free(name);
+       }
+}
+
+static void
+print_l2cache(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t **l2cache,
+    uint_t nl2cache)
+{
+       uint_t i;
+       char *name;
+
+       if (nl2cache == 0)
+               return;
+
+       (void) printf(gettext("\tcache\n"));
+
+       for (i = 0; i < nl2cache; i++) {
+               name = zpool_vdev_name(g_zfs, zhp, l2cache[i],
+                   cb->cb_name_flags);
+               print_status_config(zhp, cb, name, l2cache[i], 2, B_FALSE);
+               free(name);
+       }
+}
+
+static void
+print_dedup_stats(nvlist_t *config)
+{
+       ddt_histogram_t *ddh;
+       ddt_stat_t *dds;
+       ddt_object_t *ddo;
+       uint_t c;
+
+       /*
+        * If the pool was faulted then we may not have been able to
+        * obtain the config. Otherwise, if we have anything in the dedup
+        * table continue processing the stats.
+        */
+       if (nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_OBJ_STATS,
+           (uint64_t **)&ddo, &c) != 0)
+               return;
+
+       (void) printf("\n");
+       (void) printf(gettext(" dedup: "));
+       if (ddo->ddo_count == 0) {
+               (void) printf(gettext("no DDT entries\n"));
+               return;
+       }
+
+       (void) printf("DDT entries %llu, size %llu on disk, %llu in core\n",
+           (u_longlong_t)ddo->ddo_count,
+           (u_longlong_t)ddo->ddo_dspace,
+           (u_longlong_t)ddo->ddo_mspace);
+
+       verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_STATS,
+           (uint64_t **)&dds, &c) == 0);
+       verify(nvlist_lookup_uint64_array(config, ZPOOL_CONFIG_DDT_HISTOGRAM,
+           (uint64_t **)&ddh, &c) == 0);
+       zpool_dump_ddt(dds, ddh);
+}
+
+/*
+ * Display a summary of pool status.  Displays a summary such as:
+ *
+ *        pool: tank
+ *     status: DEGRADED
+ *     reason: One or more devices ...
+ *         see: http://zfsonlinux.org/msg/ZFS-xxxx-01
+ *     config:
+ *             mirror          DEGRADED
+ *                c1t0d0       OK
+ *                c2t0d0       UNAVAIL
+ *
+ * When given the '-v' option, we print out the complete config.  If the '-e'
+ * option is specified, then we print out error rate information as well.
+ */
+int
+status_callback(zpool_handle_t *zhp, void *data)
+{
+       status_cbdata_t *cbp = data;
+       nvlist_t *config, *nvroot;
+       char *msgid;
+       zpool_status_t reason;
+       zpool_errata_t errata;
+       const char *health;
+       uint_t c;
+       vdev_stat_t *vs;
+
+       config = zpool_get_config(zhp, NULL);
+       reason = zpool_get_status(zhp, &msgid, &errata);
+
+       cbp->cb_count++;
+
+       /*
+        * If we were given 'zpool status -x', only report those pools with
+        * problems.
+        */
+       if (cbp->cb_explain &&
+           (reason == ZPOOL_STATUS_OK ||
+           reason == ZPOOL_STATUS_VERSION_OLDER ||
+           reason == ZPOOL_STATUS_FEAT_DISABLED)) {
+               if (!cbp->cb_allpools) {
+                       (void) printf(gettext("pool '%s' is healthy\n"),
+                           zpool_get_name(zhp));
+                       if (cbp->cb_first)
+                               cbp->cb_first = B_FALSE;
+               }
+               return (0);
+       }
+
+       if (cbp->cb_first)
+               cbp->cb_first = B_FALSE;
+       else
+               (void) printf("\n");
+
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+       verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &c) == 0);
+       health = zpool_state_to_name(vs->vs_state, vs->vs_aux);
+
+       (void) printf(gettext("  pool: %s\n"), zpool_get_name(zhp));
+       (void) printf(gettext(" state: %s\n"), health);
+
+       switch (reason) {
+       case ZPOOL_STATUS_MISSING_DEV_R:
+               (void) printf(gettext("status: One or more devices could not "
+                   "be opened.  Sufficient replicas exist for\n\tthe pool to "
+                   "continue functioning in a degraded state.\n"));
+               (void) printf(gettext("action: Attach the missing device and "
+                   "online it using 'zpool online'.\n"));
+               break;
+
+       case ZPOOL_STATUS_MISSING_DEV_NR:
+               (void) printf(gettext("status: One or more devices could not "
+                   "be opened.  There are insufficient\n\treplicas for the "
+                   "pool to continue functioning.\n"));
+               (void) printf(gettext("action: Attach the missing device and "
+                   "online it using 'zpool online'.\n"));
+               break;
+
+       case ZPOOL_STATUS_CORRUPT_LABEL_R:
+               (void) printf(gettext("status: One or more devices could not "
+                   "be used because the label is missing or\n\tinvalid.  "
+                   "Sufficient replicas exist for the pool to continue\n\t"
+                   "functioning in a degraded state.\n"));
+               (void) printf(gettext("action: Replace the device using "
+                   "'zpool replace'.\n"));
+               break;
+
+       case ZPOOL_STATUS_CORRUPT_LABEL_NR:
+               (void) printf(gettext("status: One or more devices could not "
+                   "be used because the label is missing \n\tor invalid.  "
+                   "There are insufficient replicas for the pool to "
+                   "continue\n\tfunctioning.\n"));
+               zpool_explain_recover(zpool_get_handle(zhp),
+                   zpool_get_name(zhp), reason, config);
+               break;
+
+       case ZPOOL_STATUS_FAILING_DEV:
+               (void) printf(gettext("status: One or more devices has "
+                   "experienced an unrecoverable error.  An\n\tattempt was "
+                   "made to correct the error.  Applications are "
+                   "unaffected.\n"));
+               (void) printf(gettext("action: Determine if the device needs "
+                   "to be replaced, and clear the errors\n\tusing "
+                   "'zpool clear' or replace the device with 'zpool "
+                   "replace'.\n"));
+               break;
+
+       case ZPOOL_STATUS_OFFLINE_DEV:
+               (void) printf(gettext("status: One or more devices has "
+                   "been taken offline by the administrator.\n\tSufficient "
+                   "replicas exist for the pool to continue functioning in "
+                   "a\n\tdegraded state.\n"));
+               (void) printf(gettext("action: Online the device using "
+                   "'zpool online' or replace the device with\n\t'zpool "
+                   "replace'.\n"));
+               break;
+
+       case ZPOOL_STATUS_REMOVED_DEV:
+               (void) printf(gettext("status: One or more devices has "
+                   "been removed by the administrator.\n\tSufficient "
+                   "replicas exist for the pool to continue functioning in "
+                   "a\n\tdegraded state.\n"));
+               (void) printf(gettext("action: Online the device using "
+                   "'zpool online' or replace the device with\n\t'zpool "
+                   "replace'.\n"));
+               break;
+
+       case ZPOOL_STATUS_RESILVERING:
+               (void) printf(gettext("status: One or more devices is "
+                   "currently being resilvered.  The pool will\n\tcontinue "
+                   "to function, possibly in a degraded state.\n"));
+               (void) printf(gettext("action: Wait for the resilver to "
+                   "complete.\n"));
+               break;
+
+       case ZPOOL_STATUS_CORRUPT_DATA:
+               (void) printf(gettext("status: One or more devices has "
+                   "experienced an error resulting in data\n\tcorruption.  "
+                   "Applications may be affected.\n"));
+               (void) printf(gettext("action: Restore the file in question "
+                   "if possible.  Otherwise restore the\n\tentire pool from "
+                   "backup.\n"));
+               break;
+
+       case ZPOOL_STATUS_CORRUPT_POOL:
+               (void) printf(gettext("status: The pool metadata is corrupted "
+                   "and the pool cannot be opened.\n"));
+               zpool_explain_recover(zpool_get_handle(zhp),
+                   zpool_get_name(zhp), reason, config);
+               break;
+
+       case ZPOOL_STATUS_VERSION_OLDER:
+               (void) printf(gettext("status: The pool is formatted using a "
+                   "legacy on-disk format.  The pool can\n\tstill be used, "
+                   "but some features are unavailable.\n"));
+               (void) printf(gettext("action: Upgrade the pool using 'zpool "
+                   "upgrade'.  Once this is done, the\n\tpool will no longer "
+                   "be accessible on software that does not support\n\t"
+                   "feature flags.\n"));
+               break;
+
+       case ZPOOL_STATUS_VERSION_NEWER:
+               (void) printf(gettext("status: The pool has been upgraded to a "
+                   "newer, incompatible on-disk version.\n\tThe pool cannot "
+                   "be accessed on this system.\n"));
+               (void) printf(gettext("action: Access the pool from a system "
+                   "running more recent software, or\n\trestore the pool from "
+                   "backup.\n"));
+               break;
+
+       case ZPOOL_STATUS_FEAT_DISABLED:
+               (void) printf(gettext("status: Some supported features are not "
+                   "enabled on the pool. The pool can\n\tstill be used, but "
+                   "some features are unavailable.\n"));
+               (void) printf(gettext("action: Enable all features using "
+                   "'zpool upgrade'. Once this is done,\n\tthe pool may no "
+                   "longer be accessible by software that does not support\n\t"
+                   "the features. See zpool-features(5) for details.\n"));
+               break;
+
+       case ZPOOL_STATUS_UNSUP_FEAT_READ:
+               (void) printf(gettext("status: The pool cannot be accessed on "
+                   "this system because it uses the\n\tfollowing feature(s) "
+                   "not supported on this system:\n"));
+               zpool_print_unsup_feat(config);
+               (void) printf("\n");
+               (void) printf(gettext("action: Access the pool from a system "
+                   "that supports the required feature(s),\n\tor restore the "
+                   "pool from backup.\n"));
+               break;
+
+       case ZPOOL_STATUS_UNSUP_FEAT_WRITE:
+               (void) printf(gettext("status: The pool can only be accessed "
+                   "in read-only mode on this system. It\n\tcannot be "
+                   "accessed in read-write mode because it uses the "
+                   "following\n\tfeature(s) not supported on this system:\n"));
+               zpool_print_unsup_feat(config);
+               (void) printf("\n");
+               (void) printf(gettext("action: The pool cannot be accessed in "
+                   "read-write mode. Import the pool with\n"
+                   "\t\"-o readonly=on\", access the pool from a system that "
+                   "supports the\n\trequired feature(s), or restore the "
+                   "pool from backup.\n"));
+               break;
+
+       case ZPOOL_STATUS_FAULTED_DEV_R:
+               (void) printf(gettext("status: One or more devices are "
+                   "faulted in response to persistent errors.\n\tSufficient "
+                   "replicas exist for the pool to continue functioning "
+                   "in a\n\tdegraded state.\n"));
+               (void) printf(gettext("action: Replace the faulted device, "
+                   "or use 'zpool clear' to mark the device\n\trepaired.\n"));
+               break;
+
+       case ZPOOL_STATUS_FAULTED_DEV_NR:
+               (void) printf(gettext("status: One or more devices are "
+                   "faulted in response to persistent errors.  There are "
+                   "insufficient replicas for the pool to\n\tcontinue "
+                   "functioning.\n"));
+               (void) printf(gettext("action: Destroy and re-create the pool "
+                   "from a backup source.  Manually marking the device\n"
+                   "\trepaired using 'zpool clear' may allow some data "
+                   "to be recovered.\n"));
+               break;
+
+       case ZPOOL_STATUS_IO_FAILURE_WAIT:
+       case ZPOOL_STATUS_IO_FAILURE_CONTINUE:
+               (void) printf(gettext("status: One or more devices are "
+                   "faulted in response to IO failures.\n"));
+               (void) printf(gettext("action: Make sure the affected devices "
+                   "are connected, then run 'zpool clear'.\n"));
+               break;
+
+       case ZPOOL_STATUS_BAD_LOG:
+               (void) printf(gettext("status: An intent log record "
+                   "could not be read.\n"
+                   "\tWaiting for administrator intervention to fix the "
+                   "faulted pool.\n"));
+               (void) printf(gettext("action: Either restore the affected "
+                   "device(s) and run 'zpool online',\n"
+                   "\tor ignore the intent log records by running "
+                   "'zpool clear'.\n"));
+               break;
+
+       case ZPOOL_STATUS_HOSTID_MISMATCH:
+               (void) printf(gettext("status: Mismatch between pool hostid "
+                   "and system hostid on imported pool.\n\tThis pool was "
+                   "previously imported into a system with a different "
+                   "hostid,\n\tand then was verbatim imported into this "
+                   "system.\n"));
+               (void) printf(gettext("action: Export this pool on all systems "
+                   "on which it is imported.\n"
+                   "\tThen import it to correct the mismatch.\n"));
+               break;
+
+       case ZPOOL_STATUS_ERRATA:
+               (void) printf(gettext("status: Errata #%d detected.\n"),
+                   errata);
+
+               switch (errata) {
+               case ZPOOL_ERRATA_NONE:
+                       break;
+
+               case ZPOOL_ERRATA_ZOL_2094_SCRUB:
+                       (void) printf(gettext("action: To correct the issue "
+                           "run 'zpool scrub'.\n"));
+                       break;
+
+               default:
+                       /*
+                        * All errata which allow the pool to be imported
+                        * must contain an action message.
+                        */
+                       assert(0);
+               }
+               break;
+
+       default:
+               /*
+                * The remaining errors can't actually be generated, yet.
+                */
+               assert(reason == ZPOOL_STATUS_OK);
+       }
+
+       if (msgid != NULL)
+               (void) printf(gettext("   see: http://zfsonlinux.org/msg/%s\n"),
+                   msgid);
+
+       if (config != NULL) {
+               uint64_t nerr;
+               nvlist_t **spares, **l2cache;
+               uint_t nspares, nl2cache;
+               pool_scan_stat_t *ps = NULL;
+
+               (void) nvlist_lookup_uint64_array(nvroot,
+                   ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
+               print_scan_status(ps);
+
+               cbp->cb_namewidth = max_width(zhp, nvroot, 0, 0,
+                   cbp->cb_name_flags);
+               if (cbp->cb_namewidth < 10)
+                       cbp->cb_namewidth = 10;
+
+               (void) printf(gettext("config:\n\n"));
+               (void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"),
+                   cbp->cb_namewidth, "NAME", "STATE", "READ", "WRITE",
+                   "CKSUM");
+               print_status_config(zhp, cbp, zpool_get_name(zhp), nvroot, 0,
+                   B_FALSE);
+
+               if (num_logs(nvroot) > 0)
+                       print_logs(zhp, cbp, nvroot);
+               if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+                   &l2cache, &nl2cache) == 0)
+                       print_l2cache(zhp, cbp, l2cache, nl2cache);
+
+               if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+                   &spares, &nspares) == 0)
+                       print_spares(zhp, cbp, spares, nspares);
+
+               if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
+                   &nerr) == 0) {
+                       nvlist_t *nverrlist = NULL;
+
+                       /*
+                        * If the approximate error count is small, get a
+                        * precise count by fetching the entire log and
+                        * uniquifying the results.
+                        */
+                       if (nerr > 0 && nerr < 100 && !cbp->cb_verbose &&
+                           zpool_get_errlog(zhp, &nverrlist) == 0) {
+                               nvpair_t *elem;
+
+                               elem = NULL;
+                               nerr = 0;
+                               while ((elem = nvlist_next_nvpair(nverrlist,
+                                   elem)) != NULL) {
+                                       nerr++;
+                               }
+                       }
+                       nvlist_free(nverrlist);
+
+                       (void) printf("\n");
+
+                       if (nerr == 0)
+                               (void) printf(gettext("errors: No known data "
+                                   "errors\n"));
+                       else if (!cbp->cb_verbose)
+                               (void) printf(gettext("errors: %llu data "
+                                   "errors, use '-v' for a list\n"),
+                                   (u_longlong_t)nerr);
+                       else
+                               print_error_log(zhp);
+               }
+
+               if (cbp->cb_dedup_stats)
+                       print_dedup_stats(config);
+       } else {
+               (void) printf(gettext("config: The configuration cannot be "
+                   "determined.\n"));
+       }
+
+       return (0);
+}
+
+/*
+ * zpool status [-gLPvx] [-T d|u] [pool] ... [interval [count]]
+ *
+ *     -g      Display guid for individual vdev name.
+ *     -L      Follow links when resolving vdev path name.
+ *     -P      Display full path for vdev name.
+ *     -v      Display complete error logs
+ *     -x      Display only pools with potential problems
+ *     -D      Display dedup status (undocumented)
+ *     -T      Display a timestamp in date(1) or Unix format
+ *
+ * Describes the health status of all pools or some subset.
+ */
+int
+zpool_do_status(int argc, char **argv)
+{
+       int c;
+       int ret;
+       float interval = 0;
+       unsigned long count = 0;
+       status_cbdata_t cb = { 0 };
+
+       /* check options */
+       while ((c = getopt(argc, argv, "gLPvxDT:")) != -1) {
+               switch (c) {
+               case 'g':
+                       cb.cb_name_flags |= VDEV_NAME_GUID;
+                       break;
+               case 'L':
+                       cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+                       break;
+               case 'P':
+                       cb.cb_name_flags |= VDEV_NAME_PATH;
+                       break;
+               case 'v':
+                       cb.cb_verbose = B_TRUE;
+                       break;
+               case 'x':
+                       cb.cb_explain = B_TRUE;
+                       break;
+               case 'D':
+                       cb.cb_dedup_stats = B_TRUE;
+                       break;
+               case 'T':
+                       get_timestamp_arg(*optarg);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       get_interval_count(&argc, argv, &interval, &count);
+
+       if (argc == 0)
+               cb.cb_allpools = B_TRUE;
+
+       cb.cb_first = B_TRUE;
+       cb.cb_print_status = B_TRUE;
+
+       for (;;) {
+               if (timestamp_fmt != NODATE)
+                       print_timestamp(timestamp_fmt);
+
+               ret = for_each_pool(argc, argv, B_TRUE, NULL,
+                   status_callback, &cb);
+
+               if (argc == 0 && cb.cb_count == 0)
+                       (void) fprintf(stderr, gettext("no pools available\n"));
+               else if (cb.cb_explain && cb.cb_first && cb.cb_allpools)
+                       (void) printf(gettext("all pools are healthy\n"));
+
+               if (ret != 0)
+                       return (ret);
+
+               if (interval == 0)
+                       break;
+
+               if (count != 0 && --count == 0)
+                       break;
+
+               (void) fsleep(interval);
+       }
+
+       return (0);
+}
+
+typedef struct upgrade_cbdata {
+       int     cb_first;
+       int     cb_argc;
+       uint64_t cb_version;
+       char    **cb_argv;
+} upgrade_cbdata_t;
+
+static int
+check_unsupp_fs(zfs_handle_t *zhp, void *unsupp_fs)
+{
+       int zfs_version = (int) zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+       int *count = (int *)unsupp_fs;
+
+       if (zfs_version > ZPL_VERSION) {
+               (void) printf(gettext("%s (v%d) is not supported by this "
+                   "implementation of ZFS.\n"),
+                   zfs_get_name(zhp), zfs_version);
+               (*count)++;
+       }
+
+       zfs_iter_filesystems(zhp, check_unsupp_fs, unsupp_fs);
+
+       zfs_close(zhp);
+
+       return (0);
+}
+
+static int
+upgrade_version(zpool_handle_t *zhp, uint64_t version)
+{
+       int ret;
+       nvlist_t *config;
+       uint64_t oldversion;
+       int unsupp_fs = 0;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &oldversion) == 0);
+
+       assert(SPA_VERSION_IS_SUPPORTED(oldversion));
+       assert(oldversion < version);
+
+       ret = zfs_iter_root(zpool_get_handle(zhp), check_unsupp_fs, &unsupp_fs);
+       if (ret != 0)
+               return (ret);
+
+       if (unsupp_fs) {
+               (void) fprintf(stderr, gettext("Upgrade not performed due "
+                   "to %d unsupported filesystems (max v%d).\n"),
+                   unsupp_fs, (int) ZPL_VERSION);
+               return (1);
+       }
+
+       ret = zpool_upgrade(zhp, version);
+       if (ret != 0)
+               return (ret);
+
+       if (version >= SPA_VERSION_FEATURES) {
+               (void) printf(gettext("Successfully upgraded "
+                   "'%s' from version %llu to feature flags.\n"),
+                   zpool_get_name(zhp), (u_longlong_t) oldversion);
+       } else {
+               (void) printf(gettext("Successfully upgraded "
+                   "'%s' from version %llu to version %llu.\n"),
+                   zpool_get_name(zhp), (u_longlong_t) oldversion,
+                   (u_longlong_t) version);
+       }
+
+       return (0);
+}
+
+static int
+upgrade_enable_all(zpool_handle_t *zhp, int *countp)
+{
+       int i, ret, count;
+       boolean_t firstff = B_TRUE;
+       nvlist_t *enabled = zpool_get_features(zhp);
+
+       count = 0;
+       for (i = 0; i < SPA_FEATURES; i++) {
+               const char *fname = spa_feature_table[i].fi_uname;
+               const char *fguid = spa_feature_table[i].fi_guid;
+               if (!nvlist_exists(enabled, fguid)) {
+                       char *propname;
+                       verify(-1 != asprintf(&propname, "feature@%s", fname));
+                       ret = zpool_set_prop(zhp, propname,
+                           ZFS_FEATURE_ENABLED);
+                       if (ret != 0) {
+                               free(propname);
+                               return (ret);
+                       }
+                       count++;
+
+                       if (firstff) {
+                               (void) printf(gettext("Enabled the "
+                                   "following features on '%s':\n"),
+                                   zpool_get_name(zhp));
+                               firstff = B_FALSE;
+                       }
+                       (void) printf(gettext("  %s\n"), fname);
+                       free(propname);
+               }
+       }
+
+       if (countp != NULL)
+               *countp = count;
+       return (0);
+}
+
+static int
+upgrade_cb(zpool_handle_t *zhp, void *arg)
+{
+       upgrade_cbdata_t *cbp = arg;
+       nvlist_t *config;
+       uint64_t version;
+       boolean_t printnl = B_FALSE;
+       int ret;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &version) == 0);
+
+       assert(SPA_VERSION_IS_SUPPORTED(version));
+
+       if (version < cbp->cb_version) {
+               cbp->cb_first = B_FALSE;
+               ret = upgrade_version(zhp, cbp->cb_version);
+               if (ret != 0)
+                       return (ret);
+               printnl = B_TRUE;
+
+               /*
+                * If they did "zpool upgrade -a", then we could
+                * be doing ioctls to different pools.  We need
+                * to log this history once to each pool, and bypass
+                * the normal history logging that happens in main().
+                */
+               (void) zpool_log_history(g_zfs, history_str);
+               log_history = B_FALSE;
+       }
+
+       if (cbp->cb_version >= SPA_VERSION_FEATURES) {
+               int count;
+               ret = upgrade_enable_all(zhp, &count);
+               if (ret != 0)
+                       return (ret);
+
+               if (count > 0) {
+                       cbp->cb_first = B_FALSE;
+                       printnl = B_TRUE;
+               }
+       }
+
+       if (printnl) {
+               (void) printf(gettext("\n"));
+       }
+
+       return (0);
+}
+
+static int
+upgrade_list_older_cb(zpool_handle_t *zhp, void *arg)
+{
+       upgrade_cbdata_t *cbp = arg;
+       nvlist_t *config;
+       uint64_t version;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &version) == 0);
+
+       assert(SPA_VERSION_IS_SUPPORTED(version));
+
+       if (version < SPA_VERSION_FEATURES) {
+               if (cbp->cb_first) {
+                       (void) printf(gettext("The following pools are "
+                           "formatted with legacy version numbers and can\n"
+                           "be upgraded to use feature flags.  After "
+                           "being upgraded, these pools\nwill no "
+                           "longer be accessible by software that does not "
+                           "support feature\nflags.\n\n"));
+                       (void) printf(gettext("VER  POOL\n"));
+                       (void) printf(gettext("---  ------------\n"));
+                       cbp->cb_first = B_FALSE;
+               }
+
+               (void) printf("%2llu   %s\n", (u_longlong_t)version,
+                   zpool_get_name(zhp));
+       }
+
+       return (0);
+}
+
+static int
+upgrade_list_disabled_cb(zpool_handle_t *zhp, void *arg)
+{
+       upgrade_cbdata_t *cbp = arg;
+       nvlist_t *config;
+       uint64_t version;
+
+       config = zpool_get_config(zhp, NULL);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &version) == 0);
+
+       if (version >= SPA_VERSION_FEATURES) {
+               int i;
+               boolean_t poolfirst = B_TRUE;
+               nvlist_t *enabled = zpool_get_features(zhp);
+
+               for (i = 0; i < SPA_FEATURES; i++) {
+                       const char *fguid = spa_feature_table[i].fi_guid;
+                       const char *fname = spa_feature_table[i].fi_uname;
+                       if (!nvlist_exists(enabled, fguid)) {
+                               if (cbp->cb_first) {
+                                       (void) printf(gettext("\nSome "
+                                           "supported features are not "
+                                           "enabled on the following pools. "
+                                           "Once a\nfeature is enabled the "
+                                           "pool may become incompatible with "
+                                           "software\nthat does not support "
+                                           "the feature. See "
+                                           "zpool-features(5) for "
+                                           "details.\n\n"));
+                                       (void) printf(gettext("POOL  "
+                                           "FEATURE\n"));
+                                       (void) printf(gettext("------"
+                                           "---------\n"));
+                                       cbp->cb_first = B_FALSE;
+                               }
+
+                               if (poolfirst) {
+                                       (void) printf(gettext("%s\n"),
+                                           zpool_get_name(zhp));
+                                       poolfirst = B_FALSE;
+                               }
+
+                               (void) printf(gettext("      %s\n"), fname);
+                       }
+                       /*
+                        * If they did "zpool upgrade -a", then we could
+                        * be doing ioctls to different pools.  We need
+                        * to log this history once to each pool, and bypass
+                        * the normal history logging that happens in main().
+                        */
+                       (void) zpool_log_history(g_zfs, history_str);
+                       log_history = B_FALSE;
+               }
+       }
+
+       return (0);
+}
+
+/* ARGSUSED */
+static int
+upgrade_one(zpool_handle_t *zhp, void *data)
+{
+       boolean_t printnl = B_FALSE;
+       upgrade_cbdata_t *cbp = data;
+       uint64_t cur_version;
+       int ret;
+
+       if (strcmp("log", zpool_get_name(zhp)) == 0) {
+               (void) fprintf(stderr, gettext("'log' is now a reserved word\n"
+                   "Pool 'log' must be renamed using export and import"
+                   " to upgrade.\n"));
+               return (1);
+       }
+
+       cur_version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
+       if (cur_version > cbp->cb_version) {
+               (void) printf(gettext("Pool '%s' is already formatted "
+                   "using more current version '%llu'.\n\n"),
+                   zpool_get_name(zhp), (u_longlong_t) cur_version);
+               return (0);
+       }
+
+       if (cbp->cb_version != SPA_VERSION && cur_version == cbp->cb_version) {
+               (void) printf(gettext("Pool '%s' is already formatted "
+                   "using version %llu.\n\n"), zpool_get_name(zhp),
+                   (u_longlong_t) cbp->cb_version);
+               return (0);
+       }
+
+       if (cur_version != cbp->cb_version) {
+               printnl = B_TRUE;
+               ret = upgrade_version(zhp, cbp->cb_version);
+               if (ret != 0)
+                       return (ret);
+       }
+
+       if (cbp->cb_version >= SPA_VERSION_FEATURES) {
+               int count = 0;
+               ret = upgrade_enable_all(zhp, &count);
+               if (ret != 0)
+                       return (ret);
+
+               if (count != 0) {
+                       printnl = B_TRUE;
+               } else if (cur_version == SPA_VERSION) {
+                       (void) printf(gettext("Pool '%s' already has all "
+                           "supported features enabled.\n"),
+                           zpool_get_name(zhp));
+               }
+       }
+
+       if (printnl) {
+               (void) printf(gettext("\n"));
+       }
+
+       return (0);
+}
+
+/*
+ * zpool upgrade
+ * zpool upgrade -v
+ * zpool upgrade [-V version] <-a | pool ...>
+ *
+ * With no arguments, display downrev'd ZFS pool available for upgrade.
+ * Individual pools can be upgraded by specifying the pool, and '-a' will
+ * upgrade all pools.
+ */
+int
+zpool_do_upgrade(int argc, char **argv)
+{
+       int c;
+       upgrade_cbdata_t cb = { 0 };
+       int ret = 0;
+       boolean_t showversions = B_FALSE;
+       boolean_t upgradeall = B_FALSE;
+       char *end;
+
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":avV:")) != -1) {
+               switch (c) {
+               case 'a':
+                       upgradeall = B_TRUE;
+                       break;
+               case 'v':
+                       showversions = B_TRUE;
+                       break;
+               case 'V':
+                       cb.cb_version = strtoll(optarg, &end, 10);
+                       if (*end != '\0' ||
+                           !SPA_VERSION_IS_SUPPORTED(cb.cb_version)) {
+                               (void) fprintf(stderr,
+                                   gettext("invalid version '%s'\n"), optarg);
+                               usage(B_FALSE);
+                       }
+                       break;
+               case ':':
+                       (void) fprintf(stderr, gettext("missing argument for "
+                           "'%c' option\n"), optopt);
+                       usage(B_FALSE);
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       cb.cb_argc = argc;
+       cb.cb_argv = argv;
+       argc -= optind;
+       argv += optind;
+
+       if (cb.cb_version == 0) {
+               cb.cb_version = SPA_VERSION;
+       } else if (!upgradeall && argc == 0) {
+               (void) fprintf(stderr, gettext("-V option is "
+                   "incompatible with other arguments\n"));
+               usage(B_FALSE);
+       }
+
+       if (showversions) {
+               if (upgradeall || argc != 0) {
+                       (void) fprintf(stderr, gettext("-v option is "
+                           "incompatible with other arguments\n"));
+                       usage(B_FALSE);
+               }
+       } else if (upgradeall) {
+               if (argc != 0) {
+                       (void) fprintf(stderr, gettext("-a option should not "
+                           "be used along with a pool name\n"));
+                       usage(B_FALSE);
+               }
+       }
+
+       (void) printf(gettext("This system supports ZFS pool feature "
+           "flags.\n\n"));
+       if (showversions) {
+               int i;
+
+               (void) printf(gettext("The following features are "
+                   "supported:\n\n"));
+               (void) printf(gettext("FEAT DESCRIPTION\n"));
+               (void) printf("----------------------------------------------"
+                   "---------------\n");
+               for (i = 0; i < SPA_FEATURES; i++) {
+                       zfeature_info_t *fi = &spa_feature_table[i];
+                       const char *ro =
+                           (fi->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
+                           " (read-only compatible)" : "";
+
+                       (void) printf("%-37s%s\n", fi->fi_uname, ro);
+                       (void) printf("     %s\n", fi->fi_desc);
+               }
+               (void) printf("\n");
+
+               (void) printf(gettext("The following legacy versions are also "
+                   "supported:\n\n"));
+               (void) printf(gettext("VER  DESCRIPTION\n"));
+               (void) printf("---  -----------------------------------------"
+                   "---------------\n");
+               (void) printf(gettext(" 1   Initial ZFS version\n"));
+               (void) printf(gettext(" 2   Ditto blocks "
+                   "(replicated metadata)\n"));
+               (void) printf(gettext(" 3   Hot spares and double parity "
+                   "RAID-Z\n"));
+               (void) printf(gettext(" 4   zpool history\n"));
+               (void) printf(gettext(" 5   Compression using the gzip "
+                   "algorithm\n"));
+               (void) printf(gettext(" 6   bootfs pool property\n"));
+               (void) printf(gettext(" 7   Separate intent log devices\n"));
+               (void) printf(gettext(" 8   Delegated administration\n"));
+               (void) printf(gettext(" 9   refquota and refreservation "
+                   "properties\n"));
+               (void) printf(gettext(" 10  Cache devices\n"));
+               (void) printf(gettext(" 11  Improved scrub performance\n"));
+               (void) printf(gettext(" 12  Snapshot properties\n"));
+               (void) printf(gettext(" 13  snapused property\n"));
+               (void) printf(gettext(" 14  passthrough-x aclinherit\n"));
+               (void) printf(gettext(" 15  user/group space accounting\n"));
+               (void) printf(gettext(" 16  stmf property support\n"));
+               (void) printf(gettext(" 17  Triple-parity RAID-Z\n"));
+               (void) printf(gettext(" 18  Snapshot user holds\n"));
+               (void) printf(gettext(" 19  Log device removal\n"));
+               (void) printf(gettext(" 20  Compression using zle "
+                   "(zero-length encoding)\n"));
+               (void) printf(gettext(" 21  Deduplication\n"));
+               (void) printf(gettext(" 22  Received properties\n"));
+               (void) printf(gettext(" 23  Slim ZIL\n"));
+               (void) printf(gettext(" 24  System attributes\n"));
+               (void) printf(gettext(" 25  Improved scrub stats\n"));
+               (void) printf(gettext(" 26  Improved snapshot deletion "
+                   "performance\n"));
+               (void) printf(gettext(" 27  Improved snapshot creation "
+                   "performance\n"));
+               (void) printf(gettext(" 28  Multiple vdev replacements\n"));
+               (void) printf(gettext("\nFor more information on a particular "
+                   "version, including supported releases,\n"));
+               (void) printf(gettext("see the ZFS Administration Guide.\n\n"));
+       } else if (argc == 0 && upgradeall) {
+               cb.cb_first = B_TRUE;
+               ret = zpool_iter(g_zfs, upgrade_cb, &cb);
+               if (ret == 0 && cb.cb_first) {
+                       if (cb.cb_version == SPA_VERSION) {
+                               (void) printf(gettext("All pools are already "
+                                   "formatted using feature flags.\n\n"));
+                               (void) printf(gettext("Every feature flags "
+                                   "pool already has all supported features "
+                                   "enabled.\n"));
+                       } else {
+                               (void) printf(gettext("All pools are already "
+                                   "formatted with version %llu or higher.\n"),
+                                   (u_longlong_t) cb.cb_version);
+                       }
+               }
+       } else if (argc == 0) {
+               cb.cb_first = B_TRUE;
+               ret = zpool_iter(g_zfs, upgrade_list_older_cb, &cb);
+               assert(ret == 0);
+
+               if (cb.cb_first) {
+                       (void) printf(gettext("All pools are formatted "
+                           "using feature flags.\n\n"));
+               } else {
+                       (void) printf(gettext("\nUse 'zpool upgrade -v' "
+                           "for a list of available legacy versions.\n"));
+               }
+
+               cb.cb_first = B_TRUE;
+               ret = zpool_iter(g_zfs, upgrade_list_disabled_cb, &cb);
+               assert(ret == 0);
+
+               if (cb.cb_first) {
+                       (void) printf(gettext("Every feature flags pool has "
+                           "all supported features enabled.\n"));
+               } else {
+                       (void) printf(gettext("\n"));
+               }
+       } else {
+               ret = for_each_pool(argc, argv, B_FALSE, NULL,
+                   upgrade_one, &cb);
+       }
+
+       return (ret);
+}
+
+typedef struct hist_cbdata {
+       boolean_t first;
+       boolean_t longfmt;
+       boolean_t internal;
+} hist_cbdata_t;
+
+/*
+ * Print out the command history for a specific pool.
+ */
+static int
+get_history_one(zpool_handle_t *zhp, void *data)
+{
+       nvlist_t *nvhis;
+       nvlist_t **records;
+       uint_t numrecords;
+       int ret, i;
+       hist_cbdata_t *cb = (hist_cbdata_t *)data;
+
+       cb->first = B_FALSE;
+
+       (void) printf(gettext("History for '%s':\n"), zpool_get_name(zhp));
+
+       if ((ret = zpool_get_history(zhp, &nvhis)) != 0)
+               return (ret);
+
+       verify(nvlist_lookup_nvlist_array(nvhis, ZPOOL_HIST_RECORD,
+           &records, &numrecords) == 0);
+       for (i = 0; i < numrecords; i++) {
+               nvlist_t *rec = records[i];
+               char tbuf[30] = "";
+
+               if (nvlist_exists(rec, ZPOOL_HIST_TIME)) {
+                       time_t tsec;
+                       struct tm t;
+
+                       tsec = fnvlist_lookup_uint64(records[i],
+                           ZPOOL_HIST_TIME);
+                       (void) localtime_r(&tsec, &t);
+                       (void) strftime(tbuf, sizeof (tbuf), "%F.%T", &t);
+               }
+
+               if (nvlist_exists(rec, ZPOOL_HIST_CMD)) {
+                       (void) printf("%s %s", tbuf,
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_CMD));
+               } else if (nvlist_exists(rec, ZPOOL_HIST_INT_EVENT)) {
+                       int ievent =
+                           fnvlist_lookup_uint64(rec, ZPOOL_HIST_INT_EVENT);
+                       if (!cb->internal)
+                               continue;
+                       if (ievent >= ZFS_NUM_LEGACY_HISTORY_EVENTS) {
+                               (void) printf("%s unrecognized record:\n",
+                                   tbuf);
+                               dump_nvlist(rec, 4);
+                               continue;
+                       }
+                       (void) printf("%s [internal %s txg:%lld] %s", tbuf,
+                           zfs_history_event_names[ievent],
+                           (longlong_t) fnvlist_lookup_uint64(
+                           rec, ZPOOL_HIST_TXG),
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_INT_STR));
+               } else if (nvlist_exists(rec, ZPOOL_HIST_INT_NAME)) {
+                       if (!cb->internal)
+                               continue;
+                       (void) printf("%s [txg:%lld] %s", tbuf,
+                           (longlong_t) fnvlist_lookup_uint64(
+                           rec, ZPOOL_HIST_TXG),
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_INT_NAME));
+                       if (nvlist_exists(rec, ZPOOL_HIST_DSNAME)) {
+                               (void) printf(" %s (%llu)",
+                                   fnvlist_lookup_string(rec,
+                                   ZPOOL_HIST_DSNAME),
+                                   (u_longlong_t)fnvlist_lookup_uint64(rec,
+                                   ZPOOL_HIST_DSID));
+                       }
+                       (void) printf(" %s", fnvlist_lookup_string(rec,
+                           ZPOOL_HIST_INT_STR));
+               } else if (nvlist_exists(rec, ZPOOL_HIST_IOCTL)) {
+                       if (!cb->internal)
+                               continue;
+                       (void) printf("%s ioctl %s\n", tbuf,
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_IOCTL));
+                       if (nvlist_exists(rec, ZPOOL_HIST_INPUT_NVL)) {
+                               (void) printf("    input:\n");
+                               dump_nvlist(fnvlist_lookup_nvlist(rec,
+                                   ZPOOL_HIST_INPUT_NVL), 8);
+                       }
+                       if (nvlist_exists(rec, ZPOOL_HIST_OUTPUT_NVL)) {
+                               (void) printf("    output:\n");
+                               dump_nvlist(fnvlist_lookup_nvlist(rec,
+                                   ZPOOL_HIST_OUTPUT_NVL), 8);
+                       }
+               } else {
+                       if (!cb->internal)
+                               continue;
+                       (void) printf("%s unrecognized record:\n", tbuf);
+                       dump_nvlist(rec, 4);
+               }
+
+               if (!cb->longfmt) {
+                       (void) printf("\n");
+                       continue;
+               }
+               (void) printf(" [");
+               if (nvlist_exists(rec, ZPOOL_HIST_WHO)) {
+                       uid_t who = fnvlist_lookup_uint64(rec, ZPOOL_HIST_WHO);
+                       struct passwd *pwd = getpwuid(who);
+                       (void) printf("user %d ", (int)who);
+                       if (pwd != NULL)
+                               (void) printf("(%s) ", pwd->pw_name);
+               }
+               if (nvlist_exists(rec, ZPOOL_HIST_HOST)) {
+                       (void) printf("on %s",
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_HOST));
+               }
+               if (nvlist_exists(rec, ZPOOL_HIST_ZONE)) {
+                       (void) printf(":%s",
+                           fnvlist_lookup_string(rec, ZPOOL_HIST_ZONE));
+               }
+
+               (void) printf("]");
+               (void) printf("\n");
+       }
+       (void) printf("\n");
+       nvlist_free(nvhis);
+
+       return (ret);
+}
+
+/*
+ * zpool history <pool>
+ *
+ * Displays the history of commands that modified pools.
+ */
+int
+zpool_do_history(int argc, char **argv)
+{
+       hist_cbdata_t cbdata = { 0 };
+       int ret;
+       int c;
+
+       cbdata.first = B_TRUE;
+       /* check options */
+       while ((c = getopt(argc, argv, "li")) != -1) {
+               switch (c) {
+               case 'l':
+                       cbdata.longfmt = B_TRUE;
+                       break;
+               case 'i':
+                       cbdata.internal = B_TRUE;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       ret = for_each_pool(argc, argv, B_FALSE,  NULL, get_history_one,
+           &cbdata);
+
+       if (argc == 0 && cbdata.first == B_TRUE) {
+               (void) fprintf(stderr, gettext("no pools available\n"));
+               return (0);
+       }
+
+       return (ret);
+}
+
+typedef struct ev_opts {
+       int verbose;
+       int scripted;
+       int follow;
+       int clear;
+} ev_opts_t;
+
+static void
+zpool_do_events_short(nvlist_t *nvl)
+{
+       char ctime_str[26], str[32], *ptr;
+       int64_t *tv;
+       uint_t n;
+
+       verify(nvlist_lookup_int64_array(nvl, FM_EREPORT_TIME, &tv, &n) == 0);
+       memset(str, ' ', 32);
+       (void) ctime_r((const time_t *)&tv[0], ctime_str);
+       (void) strncpy(str, ctime_str+4,  6);           /* 'Jun 30' */
+       (void) strncpy(str+7, ctime_str+20, 4);         /* '1993' */
+       (void) strncpy(str+12, ctime_str+11, 8);        /* '21:49:08' */
+       (void) sprintf(str+20, ".%09lld", (longlong_t)tv[1]); /* '.123456789' */
+       (void) printf(gettext("%s "), str);
+
+       verify(nvlist_lookup_string(nvl, FM_CLASS, &ptr) == 0);
+       (void) printf(gettext("%s\n"), ptr);
+}
+
+static void
+zpool_do_events_nvprint(nvlist_t *nvl, int depth)
+{
+       nvpair_t *nvp;
+
+       for (nvp = nvlist_next_nvpair(nvl, NULL);
+           nvp != NULL; nvp = nvlist_next_nvpair(nvl, nvp)) {
+
+               data_type_t type = nvpair_type(nvp);
+               const char *name = nvpair_name(nvp);
+
+               boolean_t b;
+               uint8_t i8;
+               uint16_t i16;
+               uint32_t i32;
+               uint64_t i64;
+               char *str;
+               nvlist_t *cnv;
+
+               printf(gettext("%*s%s = "), depth, "", name);
+
+               switch (type) {
+               case DATA_TYPE_BOOLEAN:
+                       printf(gettext("%s"), "1");
+                       break;
+
+               case DATA_TYPE_BOOLEAN_VALUE:
+                       (void) nvpair_value_boolean_value(nvp, &b);
+                       printf(gettext("%s"), b ? "1" : "0");
+                       break;
+
+               case DATA_TYPE_BYTE:
+                       (void) nvpair_value_byte(nvp, &i8);
+                       printf(gettext("0x%x"), i8);
+                       break;
+
+               case DATA_TYPE_INT8:
+                       (void) nvpair_value_int8(nvp, (void *)&i8);
+                       printf(gettext("0x%x"), i8);
+                       break;
+
+               case DATA_TYPE_UINT8:
+                       (void) nvpair_value_uint8(nvp, &i8);
+                       printf(gettext("0x%x"), i8);
+                       break;
+
+               case DATA_TYPE_INT16:
+                       (void) nvpair_value_int16(nvp, (void *)&i16);
+                       printf(gettext("0x%x"), i16);
+                       break;
+
+               case DATA_TYPE_UINT16:
+                       (void) nvpair_value_uint16(nvp, &i16);
+                       printf(gettext("0x%x"), i16);
+                       break;
+
+               case DATA_TYPE_INT32:
+                       (void) nvpair_value_int32(nvp, (void *)&i32);
+                       printf(gettext("0x%x"), i32);
+                       break;
+
+               case DATA_TYPE_UINT32:
+                       (void) nvpair_value_uint32(nvp, &i32);
+                       printf(gettext("0x%x"), i32);
+                       break;
+
+               case DATA_TYPE_INT64:
+                       (void) nvpair_value_int64(nvp, (void *)&i64);
+                       printf(gettext("0x%llx"), (u_longlong_t)i64);
+                       break;
+
+               case DATA_TYPE_UINT64:
+                       (void) nvpair_value_uint64(nvp, &i64);
+                       /*
+                        * translate vdev state values to readable
+                        * strings to aide zpool events consumers
+                        */
+                       if (strcmp(name,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE) == 0 ||
+                           strcmp(name,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE) == 0) {
+                               printf(gettext("\"%s\" (0x%llx)"),
+                                   zpool_state_to_name(i64, VDEV_AUX_NONE),
+                                   (u_longlong_t)i64);
+                       } else {
+                               printf(gettext("0x%llx"), (u_longlong_t)i64);
+                       }
+                       break;
+
+               case DATA_TYPE_HRTIME:
+                       (void) nvpair_value_hrtime(nvp, (void *)&i64);
+                       printf(gettext("0x%llx"), (u_longlong_t)i64);
+                       break;
+
+               case DATA_TYPE_STRING:
+                       (void) nvpair_value_string(nvp, &str);
+                       printf(gettext("\"%s\""), str ? str : "<NULL>");
+                       break;
+
+               case DATA_TYPE_NVLIST:
+                       printf(gettext("(embedded nvlist)\n"));
+                       (void) nvpair_value_nvlist(nvp, &cnv);
+                       zpool_do_events_nvprint(cnv, depth + 8);
+                       printf(gettext("%*s(end %s)"), depth, "", name);
+                       break;
+
+               case DATA_TYPE_NVLIST_ARRAY: {
+                       nvlist_t **val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_nvlist_array(nvp, &val, &nelem);
+                       printf(gettext("(%d embedded nvlists)\n"), nelem);
+                       for (i = 0; i < nelem; i++) {
+                               printf(gettext("%*s%s[%d] = %s\n"),
+                                   depth, "", name, i, "(embedded nvlist)");
+                               zpool_do_events_nvprint(val[i], depth + 8);
+                               printf(gettext("%*s(end %s[%i])\n"),
+                                   depth, "", name, i);
+                       }
+                       printf(gettext("%*s(end %s)\n"), depth, "", name);
+                       }
+                       break;
+
+               case DATA_TYPE_INT8_ARRAY: {
+                       int8_t *val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_int8_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("0x%x "), val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_UINT8_ARRAY: {
+                       uint8_t *val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_uint8_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("0x%x "), val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_INT16_ARRAY: {
+                       int16_t *val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_int16_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("0x%x "), val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_UINT16_ARRAY: {
+                       uint16_t *val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_uint16_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("0x%x "), val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_INT32_ARRAY: {
+                       int32_t *val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_int32_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("0x%x "), val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_UINT32_ARRAY: {
+                       uint32_t *val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_uint32_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("0x%x "), val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_INT64_ARRAY: {
+                       int64_t *val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_int64_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("0x%llx "),
+                                   (u_longlong_t)val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_UINT64_ARRAY: {
+                       uint64_t *val;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_uint64_array(nvp, &val, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("0x%llx "),
+                                   (u_longlong_t)val[i]);
+
+                       break;
+                       }
+
+               case DATA_TYPE_STRING_ARRAY: {
+                       char **str;
+                       uint_t i, nelem;
+
+                       (void) nvpair_value_string_array(nvp, &str, &nelem);
+                       for (i = 0; i < nelem; i++)
+                               printf(gettext("\"%s\" "),
+                                   str[i] ? str[i] : "<NULL>");
+
+                       break;
+                       }
+
+               case DATA_TYPE_BOOLEAN_ARRAY:
+               case DATA_TYPE_BYTE_ARRAY:
+               case DATA_TYPE_DOUBLE:
+               case DATA_TYPE_UNKNOWN:
+                       printf(gettext("<unknown>"));
+                       break;
+               }
+
+               printf(gettext("\n"));
+       }
+}
+
+static int
+zpool_do_events_next(ev_opts_t *opts)
+{
+       nvlist_t *nvl;
+       int zevent_fd, ret, dropped;
+
+       zevent_fd = open(ZFS_DEV, O_RDWR);
+       VERIFY(zevent_fd >= 0);
+
+       if (!opts->scripted)
+               (void) printf(gettext("%-30s %s\n"), "TIME", "CLASS");
+
+       while (1) {
+               ret = zpool_events_next(g_zfs, &nvl, &dropped,
+                   (opts->follow ? ZEVENT_NONE : ZEVENT_NONBLOCK), zevent_fd);
+               if (ret || nvl == NULL)
+                       break;
+
+               if (dropped > 0)
+                       (void) printf(gettext("dropped %d events\n"), dropped);
+
+               zpool_do_events_short(nvl);
+
+               if (opts->verbose) {
+                       zpool_do_events_nvprint(nvl, 8);
+                       printf(gettext("\n"));
+               }
+               (void) fflush(stdout);
+
+               nvlist_free(nvl);
+       }
+
+       VERIFY(0 == close(zevent_fd));
+
+       return (ret);
+}
+
+static int
+zpool_do_events_clear(ev_opts_t *opts)
+{
+       int count, ret;
+
+       ret = zpool_events_clear(g_zfs, &count);
+       if (!ret)
+               (void) printf(gettext("cleared %d events\n"), count);
+
+       return (ret);
+}
+
+/*
+ * zpool events [-vfc]
+ *
+ * Displays events logs by ZFS.
+ */
+int
+zpool_do_events(int argc, char **argv)
+{
+       ev_opts_t opts = { 0 };
+       int ret;
+       int c;
+
+       /* check options */
+       while ((c = getopt(argc, argv, "vHfc")) != -1) {
+               switch (c) {
+               case 'v':
+                       opts.verbose = 1;
+                       break;
+               case 'H':
+                       opts.scripted = 1;
+                       break;
+               case 'f':
+                       opts.follow = 1;
+                       break;
+               case 'c':
+                       opts.clear = 1;
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (opts.clear)
+               ret = zpool_do_events_clear(&opts);
+       else
+               ret = zpool_do_events_next(&opts);
+
+       return (ret);
+}
+
+static int
+get_callback(zpool_handle_t *zhp, void *data)
+{
+       zprop_get_cbdata_t *cbp = (zprop_get_cbdata_t *)data;
+       char value[MAXNAMELEN];
+       zprop_source_t srctype;
+       zprop_list_t *pl;
+
+       for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
+
+               /*
+                * Skip the special fake placeholder. This will also skip
+                * over the name property when 'all' is specified.
+                */
+               if (pl->pl_prop == ZPOOL_PROP_NAME &&
+                   pl == cbp->cb_proplist)
+                       continue;
+
+               if (pl->pl_prop == ZPROP_INVAL &&
+                   (zpool_prop_feature(pl->pl_user_prop) ||
+                   zpool_prop_unsupported(pl->pl_user_prop))) {
+                       srctype = ZPROP_SRC_LOCAL;
+
+                       if (zpool_prop_get_feature(zhp, pl->pl_user_prop,
+                           value, sizeof (value)) == 0) {
+                               zprop_print_one_property(zpool_get_name(zhp),
+                                   cbp, pl->pl_user_prop, value, srctype,
+                                   NULL, NULL);
+                       }
+               } else {
+                       if (zpool_get_prop(zhp, pl->pl_prop, value,
+                           sizeof (value), &srctype, cbp->cb_literal) != 0)
+                               continue;
+
+                       zprop_print_one_property(zpool_get_name(zhp), cbp,
+                           zpool_prop_to_name(pl->pl_prop), value, srctype,
+                           NULL, NULL);
+               }
+       }
+       return (0);
+}
+
+/*
+ * zpool get [-Hp] [-o "all" | field[,...]] <"all" | property[,...]> <pool> ...
+ *
+ *     -H      Scripted mode.  Don't display headers, and separate properties
+ *             by a single tab.
+ *     -o      List of columns to display.  Defaults to
+ *             "name,property,value,source".
+ *     -p      Diplay values in parsable (exact) format.
+ *
+ * Get properties of pools in the system. Output space statistics
+ * for each one as well as other attributes.
+ */
+int
+zpool_do_get(int argc, char **argv)
+{
+       zprop_get_cbdata_t cb = { 0 };
+       zprop_list_t fake_name = { 0 };
+       int ret;
+       int c, i;
+       char *value;
+
+       cb.cb_first = B_TRUE;
+
+       /*
+        * Set up default columns and sources.
+        */
+       cb.cb_sources = ZPROP_SRC_ALL;
+       cb.cb_columns[0] = GET_COL_NAME;
+       cb.cb_columns[1] = GET_COL_PROPERTY;
+       cb.cb_columns[2] = GET_COL_VALUE;
+       cb.cb_columns[3] = GET_COL_SOURCE;
+       cb.cb_type = ZFS_TYPE_POOL;
+
+       /* check options */
+       while ((c = getopt(argc, argv, ":Hpo:")) != -1) {
+               switch (c) {
+               case 'p':
+                       cb.cb_literal = B_TRUE;
+                       break;
+               case 'H':
+                       cb.cb_scripted = B_TRUE;
+                       break;
+               case 'o':
+                       bzero(&cb.cb_columns, sizeof (cb.cb_columns));
+                       i = 0;
+                       while (*optarg != '\0') {
+                               static char *col_subopts[] =
+                               { "name", "property", "value", "source",
+                               "all", NULL };
+
+                               if (i == ZFS_GET_NCOLS) {
+                                       (void) fprintf(stderr, gettext("too "
+                                       "many fields given to -o "
+                                       "option\n"));
+                                       usage(B_FALSE);
+                               }
+
+                               switch (getsubopt(&optarg, col_subopts,
+                                   &value)) {
+                               case 0:
+                                       cb.cb_columns[i++] = GET_COL_NAME;
+                                       break;
+                               case 1:
+                                       cb.cb_columns[i++] = GET_COL_PROPERTY;
+                                       break;
+                               case 2:
+                                       cb.cb_columns[i++] = GET_COL_VALUE;
+                                       break;
+                               case 3:
+                                       cb.cb_columns[i++] = GET_COL_SOURCE;
+                                       break;
+                               case 4:
+                                       if (i > 0) {
+                                               (void) fprintf(stderr,
+                                                   gettext("\"all\" conflicts "
+                                                   "with specific fields "
+                                                   "given to -o option\n"));
+                                               usage(B_FALSE);
+                                       }
+                                       cb.cb_columns[0] = GET_COL_NAME;
+                                       cb.cb_columns[1] = GET_COL_PROPERTY;
+                                       cb.cb_columns[2] = GET_COL_VALUE;
+                                       cb.cb_columns[3] = GET_COL_SOURCE;
+                                       i = ZFS_GET_NCOLS;
+                                       break;
+                               default:
+                                       (void) fprintf(stderr,
+                                           gettext("invalid column name "
+                                           "'%s'\n"), value);
+                                       usage(B_FALSE);
+                               }
+                       }
+                       break;
+               case '?':
+                       (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                           optopt);
+                       usage(B_FALSE);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1) {
+               (void) fprintf(stderr, gettext("missing property "
+                   "argument\n"));
+               usage(B_FALSE);
+       }
+
+       if (zprop_get_list(g_zfs, argv[0], &cb.cb_proplist,
+           ZFS_TYPE_POOL) != 0)
+               usage(B_FALSE);
+
+       argc--;
+       argv++;
+
+       if (cb.cb_proplist != NULL) {
+               fake_name.pl_prop = ZPOOL_PROP_NAME;
+               fake_name.pl_width = strlen(gettext("NAME"));
+               fake_name.pl_next = cb.cb_proplist;
+               cb.cb_proplist = &fake_name;
+       }
+
+       ret = for_each_pool(argc, argv, B_TRUE, &cb.cb_proplist,
+           get_callback, &cb);
+
+       if (cb.cb_proplist == &fake_name)
+               zprop_free_list(fake_name.pl_next);
+       else
+               zprop_free_list(cb.cb_proplist);
+
+       return (ret);
+}
+
+typedef struct set_cbdata {
+       char *cb_propname;
+       char *cb_value;
+       boolean_t cb_any_successful;
+} set_cbdata_t;
+
+int
+set_callback(zpool_handle_t *zhp, void *data)
+{
+       int error;
+       set_cbdata_t *cb = (set_cbdata_t *)data;
+
+       error = zpool_set_prop(zhp, cb->cb_propname, cb->cb_value);
+
+       if (!error)
+               cb->cb_any_successful = B_TRUE;
+
+       return (error);
+}
+
+int
+zpool_do_set(int argc, char **argv)
+{
+       set_cbdata_t cb = { 0 };
+       int error;
+
+       if (argc > 1 && argv[1][0] == '-') {
+               (void) fprintf(stderr, gettext("invalid option '%c'\n"),
+                   argv[1][1]);
+               usage(B_FALSE);
+       }
+
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing property=value "
+                   "argument\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc < 3) {
+               (void) fprintf(stderr, gettext("missing pool name\n"));
+               usage(B_FALSE);
+       }
+
+       if (argc > 3) {
+               (void) fprintf(stderr, gettext("too many pool names\n"));
+               usage(B_FALSE);
+       }
+
+       cb.cb_propname = argv[1];
+       cb.cb_value = strchr(cb.cb_propname, '=');
+       if (cb.cb_value == NULL) {
+               (void) fprintf(stderr, gettext("missing value in "
+                   "property=value argument\n"));
+               usage(B_FALSE);
+       }
+
+       *(cb.cb_value) = '\0';
+       cb.cb_value++;
+
+       error = for_each_pool(argc - 2, argv + 2, B_TRUE, NULL,
+           set_callback, &cb);
+
+       return (error);
+}
+
+static int
+find_command_idx(char *command, int *idx)
+{
+       int i;
+
+       for (i = 0; i < NCOMMAND; i++) {
+               if (command_table[i].name == NULL)
+                       continue;
+
+               if (strcmp(command, command_table[i].name) == 0) {
+                       *idx = i;
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+int
+main(int argc, char **argv)
+{
+       int ret;
+       int i = 0;
+       char *cmdname;
+
+       (void) setlocale(LC_ALL, "");
+       (void) textdomain(TEXT_DOMAIN);
+       srand(time(NULL));
+
+       dprintf_setup(&argc, argv);
+
+       opterr = 0;
+
+       /*
+        * Make sure the user has specified some command.
+        */
+       if (argc < 2) {
+               (void) fprintf(stderr, gettext("missing command\n"));
+               usage(B_FALSE);
+       }
+
+       cmdname = argv[1];
+
+       /*
+        * Special case '-?'
+        */
+       if ((strcmp(cmdname, "-?") == 0) || strcmp(cmdname, "--help") == 0)
+               usage(B_TRUE);
+
+       if ((g_zfs = libzfs_init()) == NULL) {
+               (void) fprintf(stderr, "%s", libzfs_error_init(errno));
+               return (1);
+       }
+
+       libzfs_print_on_error(g_zfs, B_TRUE);
+
+       zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
+
+       /*
+        * Run the appropriate command.
+        */
+       if (find_command_idx(cmdname, &i) == 0) {
+               current_command = &command_table[i];
+               ret = command_table[i].func(argc - 1, argv + 1);
+       } else if (strchr(cmdname, '=')) {
+               verify(find_command_idx("set", &i) == 0);
+               current_command = &command_table[i];
+               ret = command_table[i].func(argc, argv);
+       } else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
+               /*
+                * 'freeze' is a vile debugging abomination, so we treat
+                * it as such.
+                */
+               char buf[16384];
+               int fd = open(ZFS_DEV, O_RDWR);
+               (void) strlcpy((void *)buf, argv[2], sizeof (buf));
+               return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
+       } else {
+               (void) fprintf(stderr, gettext("unrecognized "
+                   "command '%s'\n"), cmdname);
+               usage(B_FALSE);
+               ret = 1;
+       }
+
+       if (ret == 0 && log_history)
+               (void) zpool_log_history(g_zfs, history_str);
+
+       libzfs_fini(g_zfs);
+
+       /*
+        * The 'ZFS_ABORT' environment variable causes us to dump core on exit
+        * for the purposes of running ::findleaks.
+        */
+       if (getenv("ZFS_ABORT") != NULL) {
+               (void) printf("dumping core by request\n");
+               abort();
+       }
+
+       return (ret);
+}
diff --git a/zfs/cmd/zpool/zpool_util.c b/zfs/cmd/zpool/zpool_util.c
new file mode 100644 (file)
index 0000000..df3f9bf
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include "zpool_util.h"
+
+/*
+ * Utility function to guarantee malloc() success.
+ */
+void *
+safe_malloc(size_t size)
+{
+       void *data;
+
+       if ((data = calloc(1, size)) == NULL) {
+               (void) fprintf(stderr, "internal error: out of memory\n");
+               exit(1);
+       }
+
+       return (data);
+}
+
+/*
+ * Display an out of memory error message and abort the current program.
+ */
+void
+zpool_no_memory(void)
+{
+       assert(errno == ENOMEM);
+       (void) fprintf(stderr,
+           gettext("internal error: out of memory\n"));
+       exit(1);
+}
+
+/*
+ * Return the number of logs in supplied nvlist
+ */
+uint_t
+num_logs(nvlist_t *nv)
+{
+       uint_t nlogs = 0;
+       uint_t c, children;
+       nvlist_t **child;
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               return (0);
+
+       for (c = 0; c < children; c++) {
+               uint64_t is_log = B_FALSE;
+
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &is_log);
+               if (is_log)
+                       nlogs++;
+       }
+       return (nlogs);
+}
+
+/* Find the max element in an array of uint64_t values */
+uint64_t
+array64_max(uint64_t array[], unsigned int len) {
+       uint64_t max = 0;
+       int i;
+       for (i = 0; i < len; i++)
+               max = MAX(max, array[i]);
+
+       return (max);
+}
+
+/*
+ * Return 1 if "str" is a number string, 0 otherwise.  Works for integer and
+ * floating point numbers.
+ */
+int
+isnumber(char *str) {
+       for (; *str; str++)
+               if (!(isdigit(*str) || (*str == '.')))
+                       return (0);
+
+       return (1);
+}
diff --git a/zfs/cmd/zpool/zpool_util.h b/zfs/cmd/zpool/zpool_util.h
new file mode 100644 (file)
index 0000000..f279fd5
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef        ZPOOL_UTIL_H
+#define        ZPOOL_UTIL_H
+
+#include <libnvpair.h>
+#include <libzfs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Basic utility functions
+ */
+void *safe_malloc(size_t);
+void zpool_no_memory(void);
+uint_t num_logs(nvlist_t *nv);
+uint64_t array64_max(uint64_t array[], unsigned int len);
+int isnumber(char *str);
+
+/*
+ * Virtual device functions
+ */
+
+nvlist_t *make_root_vdev(zpool_handle_t *zhp, nvlist_t *props, int force,
+    int check_rep, boolean_t replacing, boolean_t dryrun, int argc,
+    char **argv);
+nvlist_t *split_mirror_vdev(zpool_handle_t *zhp, char *newname,
+    nvlist_t *props, splitflags_t flags, int argc, char **argv);
+
+/*
+ * Pool list functions
+ */
+int for_each_pool(int, char **, boolean_t unavail, zprop_list_t **,
+    zpool_iter_f, void *);
+
+/* Vdev list functions */
+typedef int (*pool_vdev_iter_f)(zpool_handle_t *, nvlist_t *, void *);
+int for_each_vdev(zpool_handle_t *zhp, pool_vdev_iter_f func, void *data);
+
+typedef struct zpool_list zpool_list_t;
+
+zpool_list_t *pool_list_get(int, char **, zprop_list_t **, int *);
+void pool_list_update(zpool_list_t *);
+int pool_list_iter(zpool_list_t *, int unavail, zpool_iter_f, void *);
+void pool_list_free(zpool_list_t *);
+int pool_list_count(zpool_list_t *);
+void pool_list_remove(zpool_list_t *, zpool_handle_t *);
+
+libzfs_handle_t *g_zfs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZPOOL_UTIL_H */
diff --git a/zfs/cmd/zpool/zpool_vdev.c b/zfs/cmd/zpool/zpool_vdev.c
new file mode 100644 (file)
index 0000000..91fe013
--- /dev/null
@@ -0,0 +1,1756 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2016 Intel Corporation.
+ */
+
+/*
+ * Functions to convert between a list of vdevs and an nvlist representing the
+ * configuration.  Each entry in the list can be one of:
+ *
+ *     Device vdevs
+ *             disk=(path=..., devid=...)
+ *             file=(path=...)
+ *
+ *     Group vdevs
+ *             raidz[1|2]=(...)
+ *             mirror=(...)
+ *
+ *     Hot spares
+ *
+ * While the underlying implementation supports it, group vdevs cannot contain
+ * other group vdevs.  All userland verification of devices is contained within
+ * this file.  If successful, the nvlist returned can be passed directly to the
+ * kernel; we've done as much verification as possible in userland.
+ *
+ * Hot spares are a special case, and passed down as an array of disk vdevs, at
+ * the same level as the root of the vdev tree.
+ *
+ * The only function exported by this file is 'make_root_vdev'.  The
+ * function performs several passes:
+ *
+ *     1. Construct the vdev specification.  Performs syntax validation and
+ *         makes sure each device is valid.
+ *     2. Check for devices in use.  Using libblkid to make sure that no
+ *         devices are also in use.  Some can be overridden using the 'force'
+ *         flag, others cannot.
+ *     3. Check for replication errors if the 'force' flag is not specified.
+ *         validates that the replication level is consistent across the
+ *         entire pool.
+ *     4. Call libzfs to label any whole disks with an EFI label.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <devid.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <libnvpair.h>
+#include <limits.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/efi_partition.h>
+#include <sys/stat.h>
+#include <sys/vtoc.h>
+#include <sys/mntent.h>
+#include <uuid/uuid.h>
+#include <blkid/blkid.h>
+#include "zpool_util.h"
+#include <sys/zfs_context.h>
+
+/*
+ * For any given vdev specification, we can have multiple errors.  The
+ * vdev_error() function keeps track of whether we have seen an error yet, and
+ * prints out a header if its the first error we've seen.
+ */
+boolean_t error_seen;
+boolean_t is_force;
+
+typedef struct vdev_disk_db_entry
+{
+       char id[24];
+       int sector_size;
+} vdev_disk_db_entry_t;
+
+/*
+ * Database of block devices that lie about physical sector sizes.  The
+ * identification string must be precisely 24 characters to avoid false
+ * negatives
+ */
+static vdev_disk_db_entry_t vdev_disk_database[] = {
+       {"ATA     ADATA SSD S396 3", 8192},
+       {"ATA     APPLE SSD SM128E", 8192},
+       {"ATA     APPLE SSD SM256E", 8192},
+       {"ATA     APPLE SSD SM512E", 8192},
+       {"ATA     APPLE SSD SM768E", 8192},
+       {"ATA     C400-MTFDDAC064M", 8192},
+       {"ATA     C400-MTFDDAC128M", 8192},
+       {"ATA     C400-MTFDDAC256M", 8192},
+       {"ATA     C400-MTFDDAC512M", 8192},
+       {"ATA     Corsair Force 3 ", 8192},
+       {"ATA     Corsair Force GS", 8192},
+       {"ATA     INTEL SSDSA2CT04", 8192},
+       {"ATA     INTEL SSDSA2BZ10", 8192},
+       {"ATA     INTEL SSDSA2BZ20", 8192},
+       {"ATA     INTEL SSDSA2BZ30", 8192},
+       {"ATA     INTEL SSDSA2CW04", 8192},
+       {"ATA     INTEL SSDSA2CW08", 8192},
+       {"ATA     INTEL SSDSA2CW12", 8192},
+       {"ATA     INTEL SSDSA2CW16", 8192},
+       {"ATA     INTEL SSDSA2CW30", 8192},
+       {"ATA     INTEL SSDSA2CW60", 8192},
+       {"ATA     INTEL SSDSC2CT06", 8192},
+       {"ATA     INTEL SSDSC2CT12", 8192},
+       {"ATA     INTEL SSDSC2CT18", 8192},
+       {"ATA     INTEL SSDSC2CT24", 8192},
+       {"ATA     INTEL SSDSC2CW06", 8192},
+       {"ATA     INTEL SSDSC2CW12", 8192},
+       {"ATA     INTEL SSDSC2CW18", 8192},
+       {"ATA     INTEL SSDSC2CW24", 8192},
+       {"ATA     INTEL SSDSC2CW48", 8192},
+       {"ATA     KINGSTON SH100S3", 8192},
+       {"ATA     KINGSTON SH103S3", 8192},
+       {"ATA     M4-CT064M4SSD2  ", 8192},
+       {"ATA     M4-CT128M4SSD2  ", 8192},
+       {"ATA     M4-CT256M4SSD2  ", 8192},
+       {"ATA     M4-CT512M4SSD2  ", 8192},
+       {"ATA     OCZ-AGILITY2    ", 8192},
+       {"ATA     OCZ-AGILITY3    ", 8192},
+       {"ATA     OCZ-VERTEX2 3.5 ", 8192},
+       {"ATA     OCZ-VERTEX3     ", 8192},
+       {"ATA     OCZ-VERTEX3 LT  ", 8192},
+       {"ATA     OCZ-VERTEX3 MI  ", 8192},
+       {"ATA     OCZ-VERTEX4     ", 8192},
+       {"ATA     SAMSUNG MZ7WD120", 8192},
+       {"ATA     SAMSUNG MZ7WD240", 8192},
+       {"ATA     SAMSUNG MZ7WD480", 8192},
+       {"ATA     SAMSUNG MZ7WD960", 8192},
+       {"ATA     SAMSUNG SSD 830 ", 8192},
+       {"ATA     Samsung SSD 840 ", 8192},
+       {"ATA     SanDisk SSD U100", 8192},
+       {"ATA     TOSHIBA THNSNH06", 8192},
+       {"ATA     TOSHIBA THNSNH12", 8192},
+       {"ATA     TOSHIBA THNSNH25", 8192},
+       {"ATA     TOSHIBA THNSNH51", 8192},
+       {"ATA     APPLE SSD TS064C", 4096},
+       {"ATA     APPLE SSD TS128C", 4096},
+       {"ATA     APPLE SSD TS256C", 4096},
+       {"ATA     APPLE SSD TS512C", 4096},
+       {"ATA     INTEL SSDSA2M040", 4096},
+       {"ATA     INTEL SSDSA2M080", 4096},
+       {"ATA     INTEL SSDSA2M160", 4096},
+       {"ATA     INTEL SSDSC2MH12", 4096},
+       {"ATA     INTEL SSDSC2MH25", 4096},
+       {"ATA     OCZ CORE_SSD    ", 4096},
+       {"ATA     OCZ-VERTEX      ", 4096},
+       {"ATA     SAMSUNG MCCOE32G", 4096},
+       {"ATA     SAMSUNG MCCOE64G", 4096},
+       {"ATA     SAMSUNG SSD PM80", 4096},
+       /* Flash drives optimized for 4KB IOs on larger pages */
+       {"ATA     INTEL SSDSC2BA10", 4096},
+       {"ATA     INTEL SSDSC2BA20", 4096},
+       {"ATA     INTEL SSDSC2BA40", 4096},
+       {"ATA     INTEL SSDSC2BA80", 4096},
+       {"ATA     INTEL SSDSC2BB08", 4096},
+       {"ATA     INTEL SSDSC2BB12", 4096},
+       {"ATA     INTEL SSDSC2BB16", 4096},
+       {"ATA     INTEL SSDSC2BB24", 4096},
+       {"ATA     INTEL SSDSC2BB30", 4096},
+       {"ATA     INTEL SSDSC2BB40", 4096},
+       {"ATA     INTEL SSDSC2BB48", 4096},
+       {"ATA     INTEL SSDSC2BB60", 4096},
+       {"ATA     INTEL SSDSC2BB80", 4096},
+       {"ATA     INTEL SSDSC2BW24", 4096},
+       {"ATA     INTEL SSDSC2BP24", 4096},
+       {"ATA     INTEL SSDSC2BP48", 4096},
+       {"NA      SmrtStorSDLKAE9W", 4096},
+       /* Imported from Open Solaris */
+       {"ATA     MARVELL SD88SA02", 4096},
+       /* Advanced format Hard drives */
+       {"ATA     Hitachi HDS5C303", 4096},
+       {"ATA     SAMSUNG HD204UI ", 4096},
+       {"ATA     ST2000DL004 HD20", 4096},
+       {"ATA     WDC WD10EARS-00M", 4096},
+       {"ATA     WDC WD10EARS-00S", 4096},
+       {"ATA     WDC WD10EARS-00Z", 4096},
+       {"ATA     WDC WD15EARS-00M", 4096},
+       {"ATA     WDC WD15EARS-00S", 4096},
+       {"ATA     WDC WD15EARS-00Z", 4096},
+       {"ATA     WDC WD20EARS-00M", 4096},
+       {"ATA     WDC WD20EARS-00S", 4096},
+       {"ATA     WDC WD20EARS-00Z", 4096},
+       {"ATA     WDC WD1600BEVT-0", 4096},
+       {"ATA     WDC WD2500BEVT-0", 4096},
+       {"ATA     WDC WD3200BEVT-0", 4096},
+       {"ATA     WDC WD5000BEVT-0", 4096},
+       /* Virtual disks: Assume zvols with default volblocksize */
+#if 0
+       {"ATA     QEMU HARDDISK   ", 8192},
+       {"IET     VIRTUAL-DISK    ", 8192},
+       {"OI      COMSTAR         ", 8192},
+       {"SUN     COMSTAR         ", 8192},
+       {"NETAPP  LUN             ", 8192},
+#endif
+};
+
+static const int vdev_disk_database_size =
+       sizeof (vdev_disk_database) / sizeof (vdev_disk_database[0]);
+
+#define        INQ_REPLY_LEN   96
+#define        INQ_CMD_LEN     6
+
+static boolean_t
+check_sector_size_database(char *path, int *sector_size)
+{
+       unsigned char inq_buff[INQ_REPLY_LEN];
+       unsigned char sense_buffer[32];
+       unsigned char inq_cmd_blk[INQ_CMD_LEN] =
+           {INQUIRY, 0, 0, 0, INQ_REPLY_LEN, 0};
+       sg_io_hdr_t io_hdr;
+       int error;
+       int fd;
+       int i;
+
+       /* Prepare INQUIRY command */
+       memset(&io_hdr, 0, sizeof (sg_io_hdr_t));
+       io_hdr.interface_id = 'S';
+       io_hdr.cmd_len = sizeof (inq_cmd_blk);
+       io_hdr.mx_sb_len = sizeof (sense_buffer);
+       io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+       io_hdr.dxfer_len = INQ_REPLY_LEN;
+       io_hdr.dxferp = inq_buff;
+       io_hdr.cmdp = inq_cmd_blk;
+       io_hdr.sbp = sense_buffer;
+       io_hdr.timeout = 10;            /* 10 milliseconds is ample time */
+
+       if ((fd = open(path, O_RDONLY|O_DIRECT)) < 0)
+               return (B_FALSE);
+
+       error = ioctl(fd, SG_IO, (unsigned long) &io_hdr);
+
+       (void) close(fd);
+
+       if (error < 0)
+               return (B_FALSE);
+
+       if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
+               return (B_FALSE);
+
+       for (i = 0; i < vdev_disk_database_size; i++) {
+               if (memcmp(inq_buff + 8, vdev_disk_database[i].id, 24))
+                       continue;
+
+               *sector_size = vdev_disk_database[i].sector_size;
+               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+/*PRINTFLIKE1*/
+static void
+vdev_error(const char *fmt, ...)
+{
+       va_list ap;
+
+       if (!error_seen) {
+               (void) fprintf(stderr, gettext("invalid vdev specification\n"));
+               if (!is_force)
+                       (void) fprintf(stderr, gettext("use '-f' to override "
+                           "the following errors:\n"));
+               else
+                       (void) fprintf(stderr, gettext("the following errors "
+                           "must be manually repaired:\n"));
+               error_seen = B_TRUE;
+       }
+
+       va_start(ap, fmt);
+       (void) vfprintf(stderr, fmt, ap);
+       va_end(ap);
+}
+
+/*
+ * Check that a file is valid.  All we can do in this case is check that it's
+ * not in use by another pool, and not in use by swap.
+ */
+static int
+check_file(const char *file, boolean_t force, boolean_t isspare)
+{
+       char  *name;
+       int fd;
+       int ret = 0;
+       pool_state_t state;
+       boolean_t inuse;
+
+       if ((fd = open(file, O_RDONLY)) < 0)
+               return (0);
+
+       if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) == 0 && inuse) {
+               const char *desc;
+
+               switch (state) {
+               case POOL_STATE_ACTIVE:
+                       desc = gettext("active");
+                       break;
+
+               case POOL_STATE_EXPORTED:
+                       desc = gettext("exported");
+                       break;
+
+               case POOL_STATE_POTENTIALLY_ACTIVE:
+                       desc = gettext("potentially active");
+                       break;
+
+               default:
+                       desc = gettext("unknown");
+                       break;
+               }
+
+               /*
+                * Allow hot spares to be shared between pools.
+                */
+               if (state == POOL_STATE_SPARE && isspare) {
+                       free(name);
+                       (void) close(fd);
+                       return (0);
+               }
+
+               if (state == POOL_STATE_ACTIVE ||
+                   state == POOL_STATE_SPARE || !force) {
+                       switch (state) {
+                       case POOL_STATE_SPARE:
+                               vdev_error(gettext("%s is reserved as a hot "
+                                   "spare for pool %s\n"), file, name);
+                               break;
+                       default:
+                               vdev_error(gettext("%s is part of %s pool "
+                                   "'%s'\n"), file, desc, name);
+                               break;
+                       }
+                       ret = -1;
+               }
+
+               free(name);
+       }
+
+       (void) close(fd);
+       return (ret);
+}
+
+static void
+check_error(int err)
+{
+       (void) fprintf(stderr, gettext("warning: device in use checking "
+           "failed: %s\n"), strerror(err));
+}
+
+static int
+check_slice(const char *path, blkid_cache cache, int force, boolean_t isspare)
+{
+       int err;
+       char *value;
+
+       /* No valid type detected device is safe to use */
+       value = blkid_get_tag_value(cache, "TYPE", path);
+       if (value == NULL)
+               return (0);
+
+       /*
+        * If libblkid detects a ZFS device, we check the device
+        * using check_file() to see if it's safe.  The one safe
+        * case is a spare device shared between multiple pools.
+        */
+       if (strcmp(value, "zfs_member") == 0) {
+               err = check_file(path, force, isspare);
+       } else {
+               if (force) {
+                       err = 0;
+               } else {
+                       err = -1;
+                       vdev_error(gettext("%s contains a filesystem of "
+                           "type '%s'\n"), path, value);
+               }
+       }
+
+       free(value);
+
+       return (err);
+}
+
+/*
+ * Validate that a disk including all partitions are safe to use.
+ *
+ * For EFI labeled disks this can done relatively easily with the libefi
+ * library.  The partition numbers are extracted from the label and used
+ * to generate the expected /dev/ paths.  Each partition can then be
+ * checked for conflicts.
+ *
+ * For non-EFI labeled disks (MBR/EBR/etc) the same process is possible
+ * but due to the lack of a readily available libraries this scanning is
+ * not implemented.  Instead only the device path as given is checked.
+ */
+static int
+check_disk(const char *path, blkid_cache cache, int force,
+    boolean_t isspare, boolean_t iswholedisk)
+{
+       struct dk_gpt *vtoc;
+       char slice_path[MAXPATHLEN];
+       int err = 0;
+       int fd, i;
+
+       if (!iswholedisk)
+               return (check_slice(path, cache, force, isspare));
+
+       if ((fd = open(path, O_RDONLY|O_DIRECT)) < 0) {
+               check_error(errno);
+               return (-1);
+       }
+
+       /*
+        * Expected to fail for non-EFI labled disks.  Just check the device
+        * as given and do not attempt to detect and scan partitions.
+        */
+       err = efi_alloc_and_read(fd, &vtoc);
+       if (err) {
+               (void) close(fd);
+               return (check_slice(path, cache, force, isspare));
+       }
+
+       /*
+        * The primary efi partition label is damaged however the secondary
+        * label at the end of the device is intact.  Rather than use this
+        * label we should play it safe and treat this as a non efi device.
+        */
+       if (vtoc->efi_flags & EFI_GPT_PRIMARY_CORRUPT) {
+               efi_free(vtoc);
+               (void) close(fd);
+
+               if (force) {
+                       /* Partitions will now be created using the backup */
+                       return (0);
+               } else {
+                       vdev_error(gettext("%s contains a corrupt primary "
+                           "EFI label.\n"), path);
+                       return (-1);
+               }
+       }
+
+       for (i = 0; i < vtoc->efi_nparts; i++) {
+
+               if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED ||
+                   uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))
+                       continue;
+
+               if (strncmp(path, UDISK_ROOT, strlen(UDISK_ROOT)) == 0)
+                       (void) snprintf(slice_path, sizeof (slice_path),
+                           "%s%s%d", path, "-part", i+1);
+               else
+                       (void) snprintf(slice_path, sizeof (slice_path),
+                           "%s%s%d", path, isdigit(path[strlen(path)-1]) ?
+                           "p" : "", i+1);
+
+               err = check_slice(slice_path, cache, force, isspare);
+               if (err)
+                       break;
+       }
+
+       efi_free(vtoc);
+       (void) close(fd);
+
+       return (err);
+}
+
+static int
+check_device(const char *path, boolean_t force,
+    boolean_t isspare, boolean_t iswholedisk)
+{
+       blkid_cache cache;
+       int error;
+
+       error = blkid_get_cache(&cache, NULL);
+       if (error != 0) {
+               check_error(error);
+               return (-1);
+       }
+
+       error = check_disk(path, cache, force, isspare, iswholedisk);
+       blkid_put_cache(cache);
+
+       return (error);
+}
+
+/*
+ * By "whole disk" we mean an entire physical disk (something we can
+ * label, toggle the write cache on, etc.) as opposed to the full
+ * capacity of a pseudo-device such as lofi or did.  We act as if we
+ * are labeling the disk, which should be a pretty good test of whether
+ * it's a viable device or not.  Returns B_TRUE if it is and B_FALSE if
+ * it isn't.
+ */
+static boolean_t
+is_whole_disk(const char *path)
+{
+       struct dk_gpt *label;
+       int fd;
+
+       if ((fd = open(path, O_RDONLY|O_DIRECT)) < 0)
+               return (B_FALSE);
+       if (efi_alloc_and_init(fd, EFI_NUMPAR, &label) != 0) {
+               (void) close(fd);
+               return (B_FALSE);
+       }
+       efi_free(label);
+       (void) close(fd);
+       return (B_TRUE);
+}
+
+/*
+ * This may be a shorthand device path or it could be total gibberish.
+ * Check to see if it is a known device available in zfs_vdev_paths.
+ * As part of this check, see if we've been given an entire disk
+ * (minus the slice number).
+ */
+static int
+is_shorthand_path(const char *arg, char *path, size_t path_size,
+    struct stat64 *statbuf, boolean_t *wholedisk)
+{
+       int error;
+
+       error = zfs_resolve_shortname(arg, path, path_size);
+       if (error == 0) {
+               *wholedisk = is_whole_disk(path);
+               if (*wholedisk || (stat64(path, statbuf) == 0))
+                       return (0);
+       }
+
+       strlcpy(path, arg, path_size);
+       memset(statbuf, 0, sizeof (*statbuf));
+       *wholedisk = B_FALSE;
+
+       return (error);
+}
+
+/*
+ * Determine if the given path is a hot spare within the given configuration.
+ * If no configuration is given we rely solely on the label.
+ */
+static boolean_t
+is_spare(nvlist_t *config, const char *path)
+{
+       int fd;
+       pool_state_t state;
+       char *name = NULL;
+       nvlist_t *label;
+       uint64_t guid, spareguid;
+       nvlist_t *nvroot;
+       nvlist_t **spares;
+       uint_t i, nspares;
+       boolean_t inuse;
+
+       if ((fd = open(path, O_RDONLY)) < 0)
+               return (B_FALSE);
+
+       if (zpool_in_use(g_zfs, fd, &state, &name, &inuse) != 0 ||
+           !inuse ||
+           state != POOL_STATE_SPARE ||
+           zpool_read_label(fd, &label, NULL) != 0) {
+               free(name);
+               (void) close(fd);
+               return (B_FALSE);
+       }
+       free(name);
+       (void) close(fd);
+
+       if (config == NULL) {
+               nvlist_free(label);
+               return (B_TRUE);
+       }
+
+       verify(nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &guid) == 0);
+       nvlist_free(label);
+
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+           &spares, &nspares) == 0) {
+               for (i = 0; i < nspares; i++) {
+                       verify(nvlist_lookup_uint64(spares[i],
+                           ZPOOL_CONFIG_GUID, &spareguid) == 0);
+                       if (spareguid == guid)
+                               return (B_TRUE);
+               }
+       }
+
+       return (B_FALSE);
+}
+
+/*
+ * Create a leaf vdev.  Determine if this is a file or a device.  If it's a
+ * device, fill in the device id to make a complete nvlist.  Valid forms for a
+ * leaf vdev are:
+ *
+ *     /dev/xxx        Complete disk path
+ *     /xxx            Full path to file
+ *     xxx             Shorthand for <zfs_vdev_paths>/xxx
+ */
+static nvlist_t *
+make_leaf_vdev(nvlist_t *props, const char *arg, uint64_t is_log)
+{
+       char path[MAXPATHLEN];
+       struct stat64 statbuf;
+       nvlist_t *vdev = NULL;
+       char *type = NULL;
+       boolean_t wholedisk = B_FALSE;
+       uint64_t ashift = 0;
+       int err;
+
+       /*
+        * Determine what type of vdev this is, and put the full path into
+        * 'path'.  We detect whether this is a device of file afterwards by
+        * checking the st_mode of the file.
+        */
+       if (arg[0] == '/') {
+               /*
+                * Complete device or file path.  Exact type is determined by
+                * examining the file descriptor afterwards.  Symbolic links
+                * are resolved to their real paths for the is_whole_disk()
+                * and S_ISBLK/S_ISREG type checks.  However, we are careful
+                * to store the given path as ZPOOL_CONFIG_PATH to ensure we
+                * can leverage udev's persistent device labels.
+                */
+               if (realpath(arg, path) == NULL) {
+                       (void) fprintf(stderr,
+                           gettext("cannot resolve path '%s'\n"), arg);
+                       return (NULL);
+               }
+
+               wholedisk = is_whole_disk(path);
+               if (!wholedisk && (stat64(path, &statbuf) != 0)) {
+                       (void) fprintf(stderr,
+                           gettext("cannot open '%s': %s\n"),
+                           path, strerror(errno));
+                       return (NULL);
+               }
+
+               /* After is_whole_disk() check restore original passed path */
+               strlcpy(path, arg, sizeof (path));
+       } else {
+               err = is_shorthand_path(arg, path, sizeof (path),
+                   &statbuf, &wholedisk);
+               if (err != 0) {
+                       /*
+                        * If we got ENOENT, then the user gave us
+                        * gibberish, so try to direct them with a
+                        * reasonable error message.  Otherwise,
+                        * regurgitate strerror() since it's the best we
+                        * can do.
+                        */
+                       if (err == ENOENT) {
+                               (void) fprintf(stderr,
+                                   gettext("cannot open '%s': no such "
+                                   "device in %s\n"), arg, DISK_ROOT);
+                               (void) fprintf(stderr,
+                                   gettext("must be a full path or "
+                                   "shorthand device name\n"));
+                               return (NULL);
+                       } else {
+                               (void) fprintf(stderr,
+                                   gettext("cannot open '%s': %s\n"),
+                                   path, strerror(errno));
+                               return (NULL);
+                       }
+               }
+       }
+
+       /*
+        * Determine whether this is a device or a file.
+        */
+       if (wholedisk || S_ISBLK(statbuf.st_mode)) {
+               type = VDEV_TYPE_DISK;
+       } else if (S_ISREG(statbuf.st_mode)) {
+               type = VDEV_TYPE_FILE;
+       } else {
+               (void) fprintf(stderr, gettext("cannot use '%s': must be a "
+                   "block device or regular file\n"), path);
+               return (NULL);
+       }
+
+       /*
+        * Finally, we have the complete device or file, and we know that it is
+        * acceptable to use.  Construct the nvlist to describe this vdev.  All
+        * vdevs have a 'path' element, and devices also have a 'devid' element.
+        */
+       verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
+       verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
+       verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
+       verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+       if (strcmp(type, VDEV_TYPE_DISK) == 0)
+               verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
+                   (uint64_t)wholedisk) == 0);
+
+       /*
+        * Override defaults if custom properties are provided.
+        */
+       if (props != NULL) {
+               char *value = NULL;
+
+               if (nvlist_lookup_string(props,
+                   zpool_prop_to_name(ZPOOL_PROP_ASHIFT), &value) == 0)
+                       zfs_nicestrtonum(NULL, value, &ashift);
+       }
+
+       /*
+        * If the device is known to incorrectly report its physical sector
+        * size explicitly provide the known correct value.
+        */
+       if (ashift == 0) {
+               int sector_size;
+
+               if (check_sector_size_database(path, &sector_size) == B_TRUE)
+                       ashift = highbit64(sector_size) - 1;
+       }
+
+       if (ashift > 0)
+               (void) nvlist_add_uint64(vdev, ZPOOL_CONFIG_ASHIFT, ashift);
+
+       return (vdev);
+}
+
+/*
+ * Go through and verify the replication level of the pool is consistent.
+ * Performs the following checks:
+ *
+ *     For the new spec, verifies that devices in mirrors and raidz are the
+ *     same size.
+ *
+ *     If the current configuration already has inconsistent replication
+ *     levels, ignore any other potential problems in the new spec.
+ *
+ *     Otherwise, make sure that the current spec (if there is one) and the new
+ *     spec have consistent replication levels.
+ */
+typedef struct replication_level {
+       char *zprl_type;
+       uint64_t zprl_children;
+       uint64_t zprl_parity;
+} replication_level_t;
+
+#define        ZPOOL_FUZZ      (16 * 1024 * 1024)
+
+/*
+ * Given a list of toplevel vdevs, return the current replication level.  If
+ * the config is inconsistent, then NULL is returned.  If 'fatal' is set, then
+ * an error message will be displayed for each self-inconsistent vdev.
+ */
+static replication_level_t *
+get_replication(nvlist_t *nvroot, boolean_t fatal)
+{
+       nvlist_t **top;
+       uint_t t, toplevels;
+       nvlist_t **child;
+       uint_t c, children;
+       nvlist_t *nv;
+       char *type;
+       replication_level_t lastrep = { 0 }, rep, *ret;
+       boolean_t dontreport;
+
+       ret = safe_malloc(sizeof (replication_level_t));
+
+       verify(nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+           &top, &toplevels) == 0);
+
+       lastrep.zprl_type = NULL;
+       for (t = 0; t < toplevels; t++) {
+               uint64_t is_log = B_FALSE;
+
+               nv = top[t];
+
+               /*
+                * For separate logs we ignore the top level vdev replication
+                * constraints.
+                */
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &is_log);
+               if (is_log)
+                       continue;
+
+               verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE,
+                   &type) == 0);
+               if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+                   &child, &children) != 0) {
+                       /*
+                        * This is a 'file' or 'disk' vdev.
+                        */
+                       rep.zprl_type = type;
+                       rep.zprl_children = 1;
+                       rep.zprl_parity = 0;
+               } else {
+                       uint64_t vdev_size;
+
+                       /*
+                        * This is a mirror or RAID-Z vdev.  Go through and make
+                        * sure the contents are all the same (files vs. disks),
+                        * keeping track of the number of elements in the
+                        * process.
+                        *
+                        * We also check that the size of each vdev (if it can
+                        * be determined) is the same.
+                        */
+                       rep.zprl_type = type;
+                       rep.zprl_children = 0;
+
+                       if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
+                               verify(nvlist_lookup_uint64(nv,
+                                   ZPOOL_CONFIG_NPARITY,
+                                   &rep.zprl_parity) == 0);
+                               assert(rep.zprl_parity != 0);
+                       } else {
+                               rep.zprl_parity = 0;
+                       }
+
+                       /*
+                        * The 'dontreport' variable indicates that we've
+                        * already reported an error for this spec, so don't
+                        * bother doing it again.
+                        */
+                       type = NULL;
+                       dontreport = 0;
+                       vdev_size = -1ULL;
+                       for (c = 0; c < children; c++) {
+                               nvlist_t *cnv = child[c];
+                               char *path;
+                               struct stat64 statbuf;
+                               uint64_t size = -1ULL;
+                               char *childtype;
+                               int fd, err;
+
+                               rep.zprl_children++;
+
+                               verify(nvlist_lookup_string(cnv,
+                                   ZPOOL_CONFIG_TYPE, &childtype) == 0);
+
+                               /*
+                                * If this is a replacing or spare vdev, then
+                                * get the real first child of the vdev.
+                                */
+                               if (strcmp(childtype,
+                                   VDEV_TYPE_REPLACING) == 0 ||
+                                   strcmp(childtype, VDEV_TYPE_SPARE) == 0) {
+                                       nvlist_t **rchild;
+                                       uint_t rchildren;
+
+                                       verify(nvlist_lookup_nvlist_array(cnv,
+                                           ZPOOL_CONFIG_CHILDREN, &rchild,
+                                           &rchildren) == 0);
+                                       assert(rchildren == 2);
+                                       cnv = rchild[0];
+
+                                       verify(nvlist_lookup_string(cnv,
+                                           ZPOOL_CONFIG_TYPE,
+                                           &childtype) == 0);
+                               }
+
+                               verify(nvlist_lookup_string(cnv,
+                                   ZPOOL_CONFIG_PATH, &path) == 0);
+
+                               /*
+                                * If we have a raidz/mirror that combines disks
+                                * with files, report it as an error.
+                                */
+                               if (!dontreport && type != NULL &&
+                                   strcmp(type, childtype) != 0) {
+                                       if (ret != NULL)
+                                               free(ret);
+                                       ret = NULL;
+                                       if (fatal)
+                                               vdev_error(gettext(
+                                                   "mismatched replication "
+                                                   "level: %s contains both "
+                                                   "files and devices\n"),
+                                                   rep.zprl_type);
+                                       else
+                                               return (NULL);
+                                       dontreport = B_TRUE;
+                               }
+
+                               /*
+                                * According to stat(2), the value of 'st_size'
+                                * is undefined for block devices and character
+                                * devices.  But there is no effective way to
+                                * determine the real size in userland.
+                                *
+                                * Instead, we'll take advantage of an
+                                * implementation detail of spec_size().  If the
+                                * device is currently open, then we (should)
+                                * return a valid size.
+                                *
+                                * If we still don't get a valid size (indicated
+                                * by a size of 0 or MAXOFFSET_T), then ignore
+                                * this device altogether.
+                                */
+                               if ((fd = open(path, O_RDONLY)) >= 0) {
+                                       err = fstat64(fd, &statbuf);
+                                       (void) close(fd);
+                               } else {
+                                       err = stat64(path, &statbuf);
+                               }
+
+                               if (err != 0 ||
+                                   statbuf.st_size == 0 ||
+                                   statbuf.st_size == MAXOFFSET_T)
+                                       continue;
+
+                               size = statbuf.st_size;
+
+                               /*
+                                * Also make sure that devices and
+                                * slices have a consistent size.  If
+                                * they differ by a significant amount
+                                * (~16MB) then report an error.
+                                */
+                               if (!dontreport &&
+                                   (vdev_size != -1ULL &&
+                                   (labs(size - vdev_size) >
+                                   ZPOOL_FUZZ))) {
+                                       if (ret != NULL)
+                                               free(ret);
+                                       ret = NULL;
+                                       if (fatal)
+                                               vdev_error(gettext(
+                                                   "%s contains devices of "
+                                                   "different sizes\n"),
+                                                   rep.zprl_type);
+                                       else
+                                               return (NULL);
+                                       dontreport = B_TRUE;
+                               }
+
+                               type = childtype;
+                               vdev_size = size;
+                       }
+               }
+
+               /*
+                * At this point, we have the replication of the last toplevel
+                * vdev in 'rep'.  Compare it to 'lastrep' to see if its
+                * different.
+                */
+               if (lastrep.zprl_type != NULL) {
+                       if (strcmp(lastrep.zprl_type, rep.zprl_type) != 0) {
+                               if (ret != NULL)
+                                       free(ret);
+                               ret = NULL;
+                               if (fatal)
+                                       vdev_error(gettext(
+                                           "mismatched replication level: "
+                                           "both %s and %s vdevs are "
+                                           "present\n"),
+                                           lastrep.zprl_type, rep.zprl_type);
+                               else
+                                       return (NULL);
+                       } else if (lastrep.zprl_parity != rep.zprl_parity) {
+                               if (ret)
+                                       free(ret);
+                               ret = NULL;
+                               if (fatal)
+                                       vdev_error(gettext(
+                                           "mismatched replication level: "
+                                           "both %llu and %llu device parity "
+                                           "%s vdevs are present\n"),
+                                           lastrep.zprl_parity,
+                                           rep.zprl_parity,
+                                           rep.zprl_type);
+                               else
+                                       return (NULL);
+                       } else if (lastrep.zprl_children != rep.zprl_children) {
+                               if (ret)
+                                       free(ret);
+                               ret = NULL;
+                               if (fatal)
+                                       vdev_error(gettext(
+                                           "mismatched replication level: "
+                                           "both %llu-way and %llu-way %s "
+                                           "vdevs are present\n"),
+                                           lastrep.zprl_children,
+                                           rep.zprl_children,
+                                           rep.zprl_type);
+                               else
+                                       return (NULL);
+                       }
+               }
+               lastrep = rep;
+       }
+
+       if (ret != NULL)
+               *ret = rep;
+
+       return (ret);
+}
+
+/*
+ * Check the replication level of the vdev spec against the current pool.  Calls
+ * get_replication() to make sure the new spec is self-consistent.  If the pool
+ * has a consistent replication level, then we ignore any errors.  Otherwise,
+ * report any difference between the two.
+ */
+static int
+check_replication(nvlist_t *config, nvlist_t *newroot)
+{
+       nvlist_t **child;
+       uint_t  children;
+       replication_level_t *current = NULL, *new;
+       int ret;
+
+       /*
+        * If we have a current pool configuration, check to see if it's
+        * self-consistent.  If not, simply return success.
+        */
+       if (config != NULL) {
+               nvlist_t *nvroot;
+
+               verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+                   &nvroot) == 0);
+               if ((current = get_replication(nvroot, B_FALSE)) == NULL)
+                       return (0);
+       }
+       /*
+        * for spares there may be no children, and therefore no
+        * replication level to check
+        */
+       if ((nvlist_lookup_nvlist_array(newroot, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0) || (children == 0)) {
+               free(current);
+               return (0);
+       }
+
+       /*
+        * If all we have is logs then there's no replication level to check.
+        */
+       if (num_logs(newroot) == children) {
+               free(current);
+               return (0);
+       }
+
+       /*
+        * Get the replication level of the new vdev spec, reporting any
+        * inconsistencies found.
+        */
+       if ((new = get_replication(newroot, B_TRUE)) == NULL) {
+               free(current);
+               return (-1);
+       }
+
+       /*
+        * Check to see if the new vdev spec matches the replication level of
+        * the current pool.
+        */
+       ret = 0;
+       if (current != NULL) {
+               if (strcmp(current->zprl_type, new->zprl_type) != 0) {
+                       vdev_error(gettext(
+                           "mismatched replication level: pool uses %s "
+                           "and new vdev is %s\n"),
+                           current->zprl_type, new->zprl_type);
+                       ret = -1;
+               } else if (current->zprl_parity != new->zprl_parity) {
+                       vdev_error(gettext(
+                           "mismatched replication level: pool uses %llu "
+                           "device parity and new vdev uses %llu\n"),
+                           current->zprl_parity, new->zprl_parity);
+                       ret = -1;
+               } else if (current->zprl_children != new->zprl_children) {
+                       vdev_error(gettext(
+                           "mismatched replication level: pool uses %llu-way "
+                           "%s and new vdev uses %llu-way %s\n"),
+                           current->zprl_children, current->zprl_type,
+                           new->zprl_children, new->zprl_type);
+                       ret = -1;
+               }
+       }
+
+       free(new);
+       if (current != NULL)
+               free(current);
+
+       return (ret);
+}
+
+static int
+zero_label(char *path)
+{
+       const int size = 4096;
+       char buf[size];
+       int err, fd;
+
+       if ((fd = open(path, O_WRONLY|O_EXCL)) < 0) {
+               (void) fprintf(stderr, gettext("cannot open '%s': %s\n"),
+                   path, strerror(errno));
+               return (-1);
+       }
+
+       memset(buf, 0, size);
+       err = write(fd, buf, size);
+       (void) fdatasync(fd);
+       (void) close(fd);
+
+       if (err == -1) {
+               (void) fprintf(stderr, gettext("cannot zero first %d bytes "
+                   "of '%s': %s\n"), size, path, strerror(errno));
+               return (-1);
+       }
+
+       if (err != size) {
+               (void) fprintf(stderr, gettext("could only zero %d/%d bytes "
+                   "of '%s'\n"), err, size, path);
+               return (-1);
+       }
+
+       return (0);
+}
+
+/*
+ * Go through and find any whole disks in the vdev specification, labelling them
+ * as appropriate.  When constructing the vdev spec, we were unable to open this
+ * device in order to provide a devid.  Now that we have labelled the disk and
+ * know that slice 0 is valid, we can construct the devid now.
+ *
+ * If the disk was already labeled with an EFI label, we will have gotten the
+ * devid already (because we were able to open the whole disk).  Otherwise, we
+ * need to get the devid after we label the disk.
+ */
+static int
+make_disks(zpool_handle_t *zhp, nvlist_t *nv)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       char *type, *path;
+       char devpath[MAXPATHLEN];
+       char udevpath[MAXPATHLEN];
+       uint64_t wholedisk;
+       struct stat64 statbuf;
+       int is_exclusive = 0;
+       int fd;
+       int ret;
+
+       verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0) {
+
+               if (strcmp(type, VDEV_TYPE_DISK) != 0)
+                       return (0);
+
+               /*
+                * We have a disk device.  If this is a whole disk write
+                * out the efi partition table, otherwise write zero's to
+                * the first 4k of the partition.  This is to ensure that
+                * libblkid will not misidentify the partition due to a
+                * magic value left by the previous filesystem.
+                */
+               verify(!nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path));
+               verify(!nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
+                   &wholedisk));
+
+               if (!wholedisk) {
+                       /*
+                        * Update device id string for mpath nodes (Linux only)
+                        */
+                       if (is_mpath_whole_disk(path))
+                               update_vdev_config_dev_strs(nv);
+
+                       (void) zero_label(path);
+                       return (0);
+               }
+
+               if (realpath(path, devpath) == NULL) {
+                       ret = errno;
+                       (void) fprintf(stderr,
+                           gettext("cannot resolve path '%s'\n"), path);
+                       return (ret);
+               }
+
+               /*
+                * Remove any previously existing symlink from a udev path to
+                * the device before labeling the disk.  This ensures that
+                * only newly created links are used.  Otherwise there is a
+                * window between when udev deletes and recreates the link
+                * during which access attempts will fail with ENOENT.
+                */
+               strlcpy(udevpath, path, MAXPATHLEN);
+               (void) zfs_append_partition(udevpath, MAXPATHLEN);
+
+               fd = open(devpath, O_RDWR|O_EXCL);
+               if (fd == -1) {
+                       if (errno == EBUSY)
+                               is_exclusive = 1;
+               } else {
+                       (void) close(fd);
+               }
+
+               /*
+                * If the partition exists, contains a valid spare label,
+                * and is opened exclusively there is no need to partition
+                * it.  Hot spares have already been partitioned and are
+                * held open exclusively by the kernel as a safety measure.
+                *
+                * If the provided path is for a /dev/disk/ device its
+                * symbolic link will be removed, partition table created,
+                * and then block until udev creates the new link.
+                */
+               if (!is_exclusive || !is_spare(NULL, udevpath)) {
+                       char *devnode = strrchr(devpath, '/') + 1;
+
+                       ret = strncmp(udevpath, UDISK_ROOT, strlen(UDISK_ROOT));
+                       if (ret == 0) {
+                               ret = lstat64(udevpath, &statbuf);
+                               if (ret == 0 && S_ISLNK(statbuf.st_mode))
+                                       (void) unlink(udevpath);
+                       }
+
+                       /*
+                        * When labeling a pool the raw device node name
+                        * is provided as it appears under /dev/.
+                        */
+                       if (zpool_label_disk(g_zfs, zhp, devnode) == -1)
+                               return (-1);
+
+                       /*
+                        * Wait for udev to signal the device is available
+                        * by the provided path.
+                        */
+                       ret = zpool_label_disk_wait(udevpath, DISK_LABEL_WAIT);
+                       if (ret) {
+                               (void) fprintf(stderr,
+                                   gettext("missing link: %s was "
+                                   "partitioned but %s is missing\n"),
+                                   devnode, udevpath);
+                               return (ret);
+                       }
+
+                       ret = zero_label(udevpath);
+                       if (ret)
+                               return (ret);
+               }
+
+               /*
+                * Update the path to refer to the partition.  The presence of
+                * the 'whole_disk' field indicates to the CLI that we should
+                * chop off the partition number when displaying the device in
+                * future output.
+                */
+               verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, udevpath) == 0);
+
+               /*
+                * Update device id strings for whole disks (Linux only)
+                */
+               update_vdev_config_dev_strs(nv);
+
+               return (0);
+       }
+
+       for (c = 0; c < children; c++)
+               if ((ret = make_disks(zhp, child[c])) != 0)
+                       return (ret);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+           &child, &children) == 0)
+               for (c = 0; c < children; c++)
+                       if ((ret = make_disks(zhp, child[c])) != 0)
+                               return (ret);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+           &child, &children) == 0)
+               for (c = 0; c < children; c++)
+                       if ((ret = make_disks(zhp, child[c])) != 0)
+                               return (ret);
+
+       return (0);
+}
+
+/*
+ * Go through and find any devices that are in use.  We rely on libdiskmgt for
+ * the majority of this task.
+ */
+static boolean_t
+is_device_in_use(nvlist_t *config, nvlist_t *nv, boolean_t force,
+    boolean_t replacing, boolean_t isspare)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       char *type, *path;
+       int ret = 0;
+       char buf[MAXPATHLEN];
+       uint64_t wholedisk = B_FALSE;
+       boolean_t anyinuse = B_FALSE;
+
+       verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0) {
+
+               verify(!nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path));
+               if (strcmp(type, VDEV_TYPE_DISK) == 0)
+                       verify(!nvlist_lookup_uint64(nv,
+                           ZPOOL_CONFIG_WHOLE_DISK, &wholedisk));
+
+               /*
+                * As a generic check, we look to see if this is a replace of a
+                * hot spare within the same pool.  If so, we allow it
+                * regardless of what libblkid or zpool_in_use() says.
+                */
+               if (replacing) {
+                       (void) strlcpy(buf, path, sizeof (buf));
+                       if (wholedisk) {
+                               ret = zfs_append_partition(buf,  sizeof (buf));
+                               if (ret == -1)
+                                       return (-1);
+                       }
+
+                       if (is_spare(config, buf))
+                               return (B_FALSE);
+               }
+
+               if (strcmp(type, VDEV_TYPE_DISK) == 0)
+                       ret = check_device(path, force, isspare, wholedisk);
+
+               else if (strcmp(type, VDEV_TYPE_FILE) == 0)
+                       ret = check_file(path, force, isspare);
+
+               return (ret != 0);
+       }
+
+       for (c = 0; c < children; c++)
+               if (is_device_in_use(config, child[c], force, replacing,
+                   B_FALSE))
+                       anyinuse = B_TRUE;
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+           &child, &children) == 0)
+               for (c = 0; c < children; c++)
+                       if (is_device_in_use(config, child[c], force, replacing,
+                           B_TRUE))
+                               anyinuse = B_TRUE;
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+           &child, &children) == 0)
+               for (c = 0; c < children; c++)
+                       if (is_device_in_use(config, child[c], force, replacing,
+                           B_FALSE))
+                               anyinuse = B_TRUE;
+
+       return (anyinuse);
+}
+
+static const char *
+is_grouping(const char *type, int *mindev, int *maxdev)
+{
+       if (strncmp(type, "raidz", 5) == 0) {
+               const char *p = type + 5;
+               char *end;
+               long nparity;
+
+               if (*p == '\0') {
+                       nparity = 1;
+               } else if (*p == '0') {
+                       return (NULL); /* no zero prefixes allowed */
+               } else {
+                       errno = 0;
+                       nparity = strtol(p, &end, 10);
+                       if (errno != 0 || nparity < 1 || nparity >= 255 ||
+                           *end != '\0')
+                               return (NULL);
+               }
+
+               if (mindev != NULL)
+                       *mindev = nparity + 1;
+               if (maxdev != NULL)
+                       *maxdev = 255;
+               return (VDEV_TYPE_RAIDZ);
+       }
+
+       if (maxdev != NULL)
+               *maxdev = INT_MAX;
+
+       if (strcmp(type, "mirror") == 0) {
+               if (mindev != NULL)
+                       *mindev = 2;
+               return (VDEV_TYPE_MIRROR);
+       }
+
+       if (strcmp(type, "spare") == 0) {
+               if (mindev != NULL)
+                       *mindev = 1;
+               return (VDEV_TYPE_SPARE);
+       }
+
+       if (strcmp(type, "log") == 0) {
+               if (mindev != NULL)
+                       *mindev = 1;
+               return (VDEV_TYPE_LOG);
+       }
+
+       if (strcmp(type, "cache") == 0) {
+               if (mindev != NULL)
+                       *mindev = 1;
+               return (VDEV_TYPE_L2CACHE);
+       }
+
+       return (NULL);
+}
+
+/*
+ * Construct a syntactically valid vdev specification,
+ * and ensure that all devices and files exist and can be opened.
+ * Note: we don't bother freeing anything in the error paths
+ * because the program is just going to exit anyway.
+ */
+nvlist_t *
+construct_spec(nvlist_t *props, int argc, char **argv)
+{
+       nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
+       int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
+       const char *type;
+       uint64_t is_log;
+       boolean_t seen_logs;
+
+       top = NULL;
+       toplevels = 0;
+       spares = NULL;
+       l2cache = NULL;
+       nspares = 0;
+       nlogs = 0;
+       nl2cache = 0;
+       is_log = B_FALSE;
+       seen_logs = B_FALSE;
+       nvroot = NULL;
+
+       while (argc > 0) {
+               nv = NULL;
+
+               /*
+                * If it's a mirror or raidz, the subsequent arguments are
+                * its leaves -- until we encounter the next mirror or raidz.
+                */
+               if ((type = is_grouping(argv[0], &mindev, &maxdev)) != NULL) {
+                       nvlist_t **child = NULL;
+                       int c, children = 0;
+
+                       if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
+                               if (spares != NULL) {
+                                       (void) fprintf(stderr,
+                                           gettext("invalid vdev "
+                                           "specification: 'spare' can be "
+                                           "specified only once\n"));
+                                       goto spec_out;
+                               }
+                               is_log = B_FALSE;
+                       }
+
+                       if (strcmp(type, VDEV_TYPE_LOG) == 0) {
+                               if (seen_logs) {
+                                       (void) fprintf(stderr,
+                                           gettext("invalid vdev "
+                                           "specification: 'log' can be "
+                                           "specified only once\n"));
+                                       goto spec_out;
+                               }
+                               seen_logs = B_TRUE;
+                               is_log = B_TRUE;
+                               argc--;
+                               argv++;
+                               /*
+                                * A log is not a real grouping device.
+                                * We just set is_log and continue.
+                                */
+                               continue;
+                       }
+
+                       if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
+                               if (l2cache != NULL) {
+                                       (void) fprintf(stderr,
+                                           gettext("invalid vdev "
+                                           "specification: 'cache' can be "
+                                           "specified only once\n"));
+                                       goto spec_out;
+                               }
+                               is_log = B_FALSE;
+                       }
+
+                       if (is_log) {
+                               if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
+                                       (void) fprintf(stderr,
+                                           gettext("invalid vdev "
+                                           "specification: unsupported 'log' "
+                                           "device: %s\n"), type);
+                                       goto spec_out;
+                               }
+                               nlogs++;
+                       }
+
+                       for (c = 1; c < argc; c++) {
+                               if (is_grouping(argv[c], NULL, NULL) != NULL)
+                                       break;
+                               children++;
+                               child = realloc(child,
+                                   children * sizeof (nvlist_t *));
+                               if (child == NULL)
+                                       zpool_no_memory();
+                               if ((nv = make_leaf_vdev(props, argv[c],
+                                   B_FALSE)) == NULL) {
+                                       for (c = 0; c < children - 1; c++)
+                                               nvlist_free(child[c]);
+                                       free(child);
+                                       goto spec_out;
+                               }
+
+                               child[children - 1] = nv;
+                       }
+
+                       if (children < mindev) {
+                               (void) fprintf(stderr, gettext("invalid vdev "
+                                   "specification: %s requires at least %d "
+                                   "devices\n"), argv[0], mindev);
+                               for (c = 0; c < children; c++)
+                                       nvlist_free(child[c]);
+                               free(child);
+                               goto spec_out;
+                       }
+
+                       if (children > maxdev) {
+                               (void) fprintf(stderr, gettext("invalid vdev "
+                                   "specification: %s supports no more than "
+                                   "%d devices\n"), argv[0], maxdev);
+                               for (c = 0; c < children; c++)
+                                       nvlist_free(child[c]);
+                               free(child);
+                               goto spec_out;
+                       }
+
+                       argc -= c;
+                       argv += c;
+
+                       if (strcmp(type, VDEV_TYPE_SPARE) == 0) {
+                               spares = child;
+                               nspares = children;
+                               continue;
+                       } else if (strcmp(type, VDEV_TYPE_L2CACHE) == 0) {
+                               l2cache = child;
+                               nl2cache = children;
+                               continue;
+                       } else {
+                               verify(nvlist_alloc(&nv, NV_UNIQUE_NAME,
+                                   0) == 0);
+                               verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
+                                   type) == 0);
+                               verify(nvlist_add_uint64(nv,
+                                   ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+                               if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
+                                       verify(nvlist_add_uint64(nv,
+                                           ZPOOL_CONFIG_NPARITY,
+                                           mindev - 1) == 0);
+                               }
+                               verify(nvlist_add_nvlist_array(nv,
+                                   ZPOOL_CONFIG_CHILDREN, child,
+                                   children) == 0);
+
+                               for (c = 0; c < children; c++)
+                                       nvlist_free(child[c]);
+                               free(child);
+                       }
+               } else {
+                       /*
+                        * We have a device.  Pass off to make_leaf_vdev() to
+                        * construct the appropriate nvlist describing the vdev.
+                        */
+                       if ((nv = make_leaf_vdev(props, argv[0],
+                           is_log)) == NULL)
+                               goto spec_out;
+
+                       if (is_log)
+                               nlogs++;
+                       argc--;
+                       argv++;
+               }
+
+               toplevels++;
+               top = realloc(top, toplevels * sizeof (nvlist_t *));
+               if (top == NULL)
+                       zpool_no_memory();
+               top[toplevels - 1] = nv;
+       }
+
+       if (toplevels == 0 && nspares == 0 && nl2cache == 0) {
+               (void) fprintf(stderr, gettext("invalid vdev "
+                   "specification: at least one toplevel vdev must be "
+                   "specified\n"));
+               goto spec_out;
+       }
+
+       if (seen_logs && nlogs == 0) {
+               (void) fprintf(stderr, gettext("invalid vdev specification: "
+                   "log requires at least 1 device\n"));
+               goto spec_out;
+       }
+
+       /*
+        * Finally, create nvroot and add all top-level vdevs to it.
+        */
+       verify(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) == 0);
+       verify(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
+           VDEV_TYPE_ROOT) == 0);
+       verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+           top, toplevels) == 0);
+       if (nspares != 0)
+               verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+                   spares, nspares) == 0);
+       if (nl2cache != 0)
+               verify(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+                   l2cache, nl2cache) == 0);
+
+spec_out:
+       for (t = 0; t < toplevels; t++)
+               nvlist_free(top[t]);
+       for (t = 0; t < nspares; t++)
+               nvlist_free(spares[t]);
+       for (t = 0; t < nl2cache; t++)
+               nvlist_free(l2cache[t]);
+
+       free(spares);
+       free(l2cache);
+       free(top);
+
+       return (nvroot);
+}
+
+nvlist_t *
+split_mirror_vdev(zpool_handle_t *zhp, char *newname, nvlist_t *props,
+    splitflags_t flags, int argc, char **argv)
+{
+       nvlist_t *newroot = NULL, **child;
+       uint_t c, children;
+
+       if (argc > 0) {
+               if ((newroot = construct_spec(props, argc, argv)) == NULL) {
+                       (void) fprintf(stderr, gettext("Unable to build a "
+                           "pool from the specified devices\n"));
+                       return (NULL);
+               }
+
+               if (!flags.dryrun && make_disks(zhp, newroot) != 0) {
+                       nvlist_free(newroot);
+                       return (NULL);
+               }
+
+               /* avoid any tricks in the spec */
+               verify(nvlist_lookup_nvlist_array(newroot,
+                   ZPOOL_CONFIG_CHILDREN, &child, &children) == 0);
+               for (c = 0; c < children; c++) {
+                       char *path;
+                       const char *type;
+                       int min, max;
+
+                       verify(nvlist_lookup_string(child[c],
+                           ZPOOL_CONFIG_PATH, &path) == 0);
+                       if ((type = is_grouping(path, &min, &max)) != NULL) {
+                               (void) fprintf(stderr, gettext("Cannot use "
+                                   "'%s' as a device for splitting\n"), type);
+                               nvlist_free(newroot);
+                               return (NULL);
+                       }
+               }
+       }
+
+       if (zpool_vdev_split(zhp, newname, &newroot, props, flags) != 0) {
+               nvlist_free(newroot);
+               return (NULL);
+       }
+
+       return (newroot);
+}
+
+/*
+ * Get and validate the contents of the given vdev specification.  This ensures
+ * that the nvlist returned is well-formed, that all the devices exist, and that
+ * they are not currently in use by any other known consumer.  The 'poolconfig'
+ * parameter is the current configuration of the pool when adding devices
+ * existing pool, and is used to perform additional checks, such as changing the
+ * replication level of the pool.  It can be 'NULL' to indicate that this is a
+ * new pool.  The 'force' flag controls whether devices should be forcefully
+ * added, even if they appear in use.
+ */
+nvlist_t *
+make_root_vdev(zpool_handle_t *zhp, nvlist_t *props, int force, int check_rep,
+    boolean_t replacing, boolean_t dryrun, int argc, char **argv)
+{
+       nvlist_t *newroot;
+       nvlist_t *poolconfig = NULL;
+       is_force = force;
+
+       /*
+        * Construct the vdev specification.  If this is successful, we know
+        * that we have a valid specification, and that all devices can be
+        * opened.
+        */
+       if ((newroot = construct_spec(props, argc, argv)) == NULL)
+               return (NULL);
+
+       if (zhp && ((poolconfig = zpool_get_config(zhp, NULL)) == NULL)) {
+               nvlist_free(newroot);
+               return (NULL);
+       }
+
+       /*
+        * Validate each device to make sure that its not shared with another
+        * subsystem.  We do this even if 'force' is set, because there are some
+        * uses (such as a dedicated dump device) that even '-f' cannot
+        * override.
+        */
+       if (is_device_in_use(poolconfig, newroot, force, replacing, B_FALSE)) {
+               nvlist_free(newroot);
+               return (NULL);
+       }
+
+       /*
+        * Check the replication level of the given vdevs and report any errors
+        * found.  We include the existing pool spec, if any, as we need to
+        * catch changes against the existing replication level.
+        */
+       if (check_rep && check_replication(poolconfig, newroot) != 0) {
+               nvlist_free(newroot);
+               return (NULL);
+       }
+
+       /*
+        * Run through the vdev specification and label any whole disks found.
+        */
+       if (!dryrun && make_disks(zhp, newroot) != 0) {
+               nvlist_free(newroot);
+               return (NULL);
+       }
+
+       return (newroot);
+}
diff --git a/zfs/cmd/zstreamdump/Makefile.am b/zfs/cmd/zstreamdump/Makefile.am
new file mode 100644 (file)
index 0000000..b46958d
--- /dev/null
@@ -0,0 +1,17 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+sbin_PROGRAMS = zstreamdump
+
+zstreamdump_SOURCES = \
+       zstreamdump.c
+
+zstreamdump_LDADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
diff --git a/zfs/cmd/zstreamdump/Makefile.in b/zfs/cmd/zstreamdump/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zstreamdump/zstreamdump.c b/zfs/cmd/zstreamdump/zstreamdump.c
new file mode 100644 (file)
index 0000000..e0bc345
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Portions Copyright 2012 Martin Matuska <martin@matuska.org>
+ */
+
+/*
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
+ */
+
+#include <ctype.h>
+#include <libnvpair.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+
+#include <sys/dmu.h>
+#include <sys/zfs_ioctl.h>
+#include <sys/zio.h>
+#include <zfs_fletcher.h>
+
+/*
+ * If dump mode is enabled, the number of bytes to print per line
+ */
+#define        BYTES_PER_LINE  16
+/*
+ * If dump mode is enabled, the number of bytes to group together, separated
+ * by newlines or spaces
+ */
+#define        DUMP_GROUPING   4
+
+uint64_t total_write_size = 0;
+uint64_t total_stream_len = 0;
+FILE *send_stream = 0;
+boolean_t do_byteswap = B_FALSE;
+boolean_t do_cksum = B_TRUE;
+
+static void
+usage(void)
+{
+       (void) fprintf(stderr, "usage: zstreamdump [-v] [-C] [-d] < file\n");
+       (void) fprintf(stderr, "\t -v -- verbose\n");
+       (void) fprintf(stderr, "\t -C -- suppress checksum verification\n");
+       (void) fprintf(stderr, "\t -d -- dump contents of blocks modified, "
+           "implies verbose\n");
+       exit(1);
+}
+
+static void *
+safe_malloc(size_t size)
+{
+       void *rv = malloc(size);
+       if (rv == NULL) {
+               (void) fprintf(stderr, "ERROR; failed to allocate %zu bytes\n",
+                   size);
+               abort();
+       }
+       return (rv);
+}
+
+/*
+ * ssread - send stream read.
+ *
+ * Read while computing incremental checksum
+ */
+static size_t
+ssread(void *buf, size_t len, zio_cksum_t *cksum)
+{
+       size_t outlen;
+
+       if ((outlen = fread(buf, len, 1, send_stream)) == 0)
+               return (0);
+
+       if (do_cksum) {
+               if (do_byteswap)
+                       fletcher_4_incremental_byteswap(buf, len, cksum);
+               else
+                       fletcher_4_incremental_native(buf, len, cksum);
+       }
+       total_stream_len += len;
+       return (outlen);
+}
+
+static size_t
+read_hdr(dmu_replay_record_t *drr, zio_cksum_t *cksum)
+{
+       ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+           ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
+       size_t r = ssread(drr, sizeof (*drr) - sizeof (zio_cksum_t), cksum);
+       if (r == 0)
+               return (0);
+       zio_cksum_t saved_cksum = *cksum;
+       r = ssread(&drr->drr_u.drr_checksum.drr_checksum,
+           sizeof (zio_cksum_t), cksum);
+       if (r == 0)
+               return (0);
+       if (!ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.drr_checksum.drr_checksum) &&
+           !ZIO_CHECKSUM_EQUAL(saved_cksum,
+           drr->drr_u.drr_checksum.drr_checksum)) {
+               fprintf(stderr, "invalid checksum\n");
+               (void) printf("Incorrect checksum in record header.\n");
+               (void) printf("Expected checksum = %llx/%llx/%llx/%llx\n",
+                   (longlong_t)saved_cksum.zc_word[0],
+                   (longlong_t)saved_cksum.zc_word[1],
+                   (longlong_t)saved_cksum.zc_word[2],
+                   (longlong_t)saved_cksum.zc_word[3]);
+               return (0);
+       }
+       return (sizeof (*drr));
+}
+
+/*
+ * Print part of a block in ASCII characters
+ */
+static void
+print_ascii_block(char *subbuf, int length)
+{
+       int i;
+
+       for (i = 0; i < length; i++) {
+               char char_print = isprint(subbuf[i]) ? subbuf[i] : '.';
+               if (i != 0 && i % DUMP_GROUPING == 0) {
+                       (void) printf(" ");
+               }
+               (void) printf("%c", char_print);
+       }
+       (void) printf("\n");
+}
+
+/*
+ * print_block - Dump the contents of a modified block to STDOUT
+ *
+ * Assume that buf has capacity evenly divisible by BYTES_PER_LINE
+ */
+static void
+print_block(char *buf, int length)
+{
+       int i;
+       /*
+        * Start printing ASCII characters at a constant offset, after
+        * the hex prints. Leave 3 characters per byte on a line (2 digit
+        * hex number plus 1 space) plus spaces between characters and
+        * groupings.
+        */
+       int ascii_start = BYTES_PER_LINE * 3 +
+           BYTES_PER_LINE / DUMP_GROUPING + 2;
+
+       for (i = 0; i < length; i += BYTES_PER_LINE) {
+               int j;
+               int this_line_length = MIN(BYTES_PER_LINE, length - i);
+               int print_offset = 0;
+
+               for (j = 0; j < this_line_length; j++) {
+                       int buf_offset = i + j;
+
+                       /*
+                        * Separate every DUMP_GROUPING bytes by a space.
+                        */
+                       if (buf_offset % DUMP_GROUPING == 0) {
+                               print_offset += printf(" ");
+                       }
+
+                       /*
+                        * Print the two-digit hex value for this byte.
+                        */
+                       unsigned char hex_print = buf[buf_offset];
+                       print_offset += printf("%02x ", hex_print);
+               }
+
+               (void) printf("%*s", ascii_start - print_offset, " ");
+
+               print_ascii_block(buf + i, this_line_length);
+       }
+}
+
+int
+main(int argc, char *argv[])
+{
+       char *buf = safe_malloc(SPA_MAXBLOCKSIZE);
+       uint64_t drr_record_count[DRR_NUMTYPES] = { 0 };
+       uint64_t total_records = 0;
+       dmu_replay_record_t thedrr;
+       dmu_replay_record_t *drr = &thedrr;
+       struct drr_begin *drrb = &thedrr.drr_u.drr_begin;
+       struct drr_end *drre = &thedrr.drr_u.drr_end;
+       struct drr_object *drro = &thedrr.drr_u.drr_object;
+       struct drr_freeobjects *drrfo = &thedrr.drr_u.drr_freeobjects;
+       struct drr_write *drrw = &thedrr.drr_u.drr_write;
+       struct drr_write_byref *drrwbr = &thedrr.drr_u.drr_write_byref;
+       struct drr_free *drrf = &thedrr.drr_u.drr_free;
+       struct drr_spill *drrs = &thedrr.drr_u.drr_spill;
+       struct drr_write_embedded *drrwe = &thedrr.drr_u.drr_write_embedded;
+       struct drr_checksum *drrc = &thedrr.drr_u.drr_checksum;
+       char c;
+       boolean_t verbose = B_FALSE;
+       boolean_t very_verbose = B_FALSE;
+       boolean_t first = B_TRUE;
+       /*
+        * dump flag controls whether the contents of any modified data blocks
+        * are printed to the console during processing of the stream. Warning:
+        * for large streams, this can obviously lead to massive prints.
+        */
+       boolean_t dump = B_FALSE;
+       int err;
+       zio_cksum_t zc = { { 0 } };
+       zio_cksum_t pcksum = { { 0 } };
+
+       while ((c = getopt(argc, argv, ":vCd")) != -1) {
+               switch (c) {
+               case 'C':
+                       do_cksum = B_FALSE;
+                       break;
+               case 'v':
+                       if (verbose)
+                               very_verbose = B_TRUE;
+                       verbose = B_TRUE;
+                       break;
+               case 'd':
+                       dump = B_TRUE;
+                       verbose = B_TRUE;
+                       very_verbose = B_TRUE;
+                       break;
+               case ':':
+                       (void) fprintf(stderr,
+                           "missing argument for '%c' option\n", optopt);
+                       usage();
+                       break;
+               case '?':
+                       (void) fprintf(stderr, "invalid option '%c'\n",
+                           optopt);
+                       usage();
+                       break;
+               }
+       }
+
+       if (isatty(STDIN_FILENO)) {
+               (void) fprintf(stderr,
+                   "Error: Backup stream can not be read "
+                   "from a terminal.\n"
+                   "You must redirect standard input.\n");
+               exit(1);
+       }
+
+       send_stream = stdin;
+       while (read_hdr(drr, &zc)) {
+
+               /*
+                * If this is the first DMU record being processed, check for
+                * the magic bytes and figure out the endian-ness based on them.
+                */
+               if (first) {
+                       if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
+                               do_byteswap = B_TRUE;
+                               if (do_cksum) {
+                                       ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
+                                       /*
+                                        * recalculate header checksum now
+                                        * that we know it needs to be
+                                        * byteswapped.
+                                        */
+                                       fletcher_4_incremental_byteswap(drr,
+                                           sizeof (dmu_replay_record_t), &zc);
+                               }
+                       } else if (drrb->drr_magic != DMU_BACKUP_MAGIC) {
+                               (void) fprintf(stderr, "Invalid stream "
+                                   "(bad magic number)\n");
+                               exit(1);
+                       }
+                       first = B_FALSE;
+               }
+               if (do_byteswap) {
+                       drr->drr_type = BSWAP_32(drr->drr_type);
+                       drr->drr_payloadlen =
+                           BSWAP_32(drr->drr_payloadlen);
+               }
+
+               /*
+                * At this point, the leading fields of the replay record
+                * (drr_type and drr_payloadlen) have been byte-swapped if
+                * necessary, but the rest of the data structure (the
+                * union of type-specific structures) is still in its
+                * original state.
+                */
+               if (drr->drr_type >= DRR_NUMTYPES) {
+                       (void) printf("INVALID record found: type 0x%x\n",
+                           drr->drr_type);
+                       (void) printf("Aborting.\n");
+                       exit(1);
+               }
+
+               drr_record_count[drr->drr_type]++;
+               total_records++;
+
+               switch (drr->drr_type) {
+               case DRR_BEGIN:
+                       if (do_byteswap) {
+                               drrb->drr_magic = BSWAP_64(drrb->drr_magic);
+                               drrb->drr_versioninfo =
+                                   BSWAP_64(drrb->drr_versioninfo);
+                               drrb->drr_creation_time =
+                                   BSWAP_64(drrb->drr_creation_time);
+                               drrb->drr_type = BSWAP_32(drrb->drr_type);
+                               drrb->drr_flags = BSWAP_32(drrb->drr_flags);
+                               drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
+                               drrb->drr_fromguid =
+                                   BSWAP_64(drrb->drr_fromguid);
+                       }
+
+                       (void) printf("BEGIN record\n");
+                       (void) printf("\thdrtype = %lld\n",
+                           DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo));
+                       (void) printf("\tfeatures = %llx\n",
+                           DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo));
+                       (void) printf("\tmagic = %llx\n",
+                           (u_longlong_t)drrb->drr_magic);
+                       (void) printf("\tcreation_time = %llx\n",
+                           (u_longlong_t)drrb->drr_creation_time);
+                       (void) printf("\ttype = %u\n", drrb->drr_type);
+                       (void) printf("\tflags = 0x%x\n", drrb->drr_flags);
+                       (void) printf("\ttoguid = %llx\n",
+                           (u_longlong_t)drrb->drr_toguid);
+                       (void) printf("\tfromguid = %llx\n",
+                           (u_longlong_t)drrb->drr_fromguid);
+                       (void) printf("\ttoname = %s\n", drrb->drr_toname);
+                       if (verbose)
+                               (void) printf("\n");
+
+                       if (drr->drr_payloadlen != 0) {
+                               nvlist_t *nv;
+                               int sz = drr->drr_payloadlen;
+
+                               if (sz > SPA_MAXBLOCKSIZE) {
+                                       free(buf);
+                                       buf = safe_malloc(sz);
+                               }
+                               (void) ssread(buf, sz, &zc);
+                               if (ferror(send_stream))
+                                       perror("fread");
+                               err = nvlist_unpack(buf, sz, &nv, 0);
+                               if (err)
+                                       perror(strerror(err));
+                               nvlist_print(stdout, nv);
+                               nvlist_free(nv);
+                       }
+                       break;
+
+               case DRR_END:
+                       if (do_byteswap) {
+                               drre->drr_checksum.zc_word[0] =
+                                   BSWAP_64(drre->drr_checksum.zc_word[0]);
+                               drre->drr_checksum.zc_word[1] =
+                                   BSWAP_64(drre->drr_checksum.zc_word[1]);
+                               drre->drr_checksum.zc_word[2] =
+                                   BSWAP_64(drre->drr_checksum.zc_word[2]);
+                               drre->drr_checksum.zc_word[3] =
+                                   BSWAP_64(drre->drr_checksum.zc_word[3]);
+                       }
+                       /*
+                        * We compare against the *previous* checksum
+                        * value, because the stored checksum is of
+                        * everything before the DRR_END record.
+                        */
+                       if (do_cksum && !ZIO_CHECKSUM_EQUAL(drre->drr_checksum,
+                           pcksum)) {
+                               (void) printf("Expected checksum differs from "
+                                   "checksum in stream.\n");
+                               (void) printf("Expected checksum = "
+                                   "%llx/%llx/%llx/%llx\n",
+                                   (long long unsigned int)pcksum.zc_word[0],
+                                   (long long unsigned int)pcksum.zc_word[1],
+                                   (long long unsigned int)pcksum.zc_word[2],
+                                   (long long unsigned int)pcksum.zc_word[3]);
+                       }
+                       (void) printf("END checksum = %llx/%llx/%llx/%llx\n",
+                           (long long unsigned int)
+                           drre->drr_checksum.zc_word[0],
+                           (long long unsigned int)
+                           drre->drr_checksum.zc_word[1],
+                           (long long unsigned int)
+                           drre->drr_checksum.zc_word[2],
+                           (long long unsigned int)
+                           drre->drr_checksum.zc_word[3]);
+
+                       ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
+                       break;
+
+               case DRR_OBJECT:
+                       if (do_byteswap) {
+                               drro->drr_object = BSWAP_64(drro->drr_object);
+                               drro->drr_type = BSWAP_32(drro->drr_type);
+                               drro->drr_bonustype =
+                                   BSWAP_32(drro->drr_bonustype);
+                               drro->drr_blksz = BSWAP_32(drro->drr_blksz);
+                               drro->drr_bonuslen =
+                                   BSWAP_32(drro->drr_bonuslen);
+                               drro->drr_toguid = BSWAP_64(drro->drr_toguid);
+                       }
+                       if (verbose) {
+                               (void) printf("OBJECT object = %llu type = %u "
+                                   "bonustype = %u blksz = %u bonuslen = %u\n",
+                                   (u_longlong_t)drro->drr_object,
+                                   drro->drr_type,
+                                   drro->drr_bonustype,
+                                   drro->drr_blksz,
+                                   drro->drr_bonuslen);
+                       }
+                       if (drro->drr_bonuslen > 0) {
+                               (void) ssread(buf, P2ROUNDUP(drro->drr_bonuslen,
+                                   8), &zc);
+                               if (dump) {
+                                       print_block(buf,
+                                           P2ROUNDUP(drro->drr_bonuslen, 8));
+                               }
+                       }
+                       break;
+
+               case DRR_FREEOBJECTS:
+                       if (do_byteswap) {
+                               drrfo->drr_firstobj =
+                                   BSWAP_64(drrfo->drr_firstobj);
+                               drrfo->drr_numobjs =
+                                   BSWAP_64(drrfo->drr_numobjs);
+                               drrfo->drr_toguid = BSWAP_64(drrfo->drr_toguid);
+                       }
+                       if (verbose) {
+                               (void) printf("FREEOBJECTS firstobj = %llu "
+                                   "numobjs = %llu\n",
+                                   (u_longlong_t)drrfo->drr_firstobj,
+                                   (u_longlong_t)drrfo->drr_numobjs);
+                       }
+                       break;
+
+               case DRR_WRITE:
+                       if (do_byteswap) {
+                               drrw->drr_object = BSWAP_64(drrw->drr_object);
+                               drrw->drr_type = BSWAP_32(drrw->drr_type);
+                               drrw->drr_offset = BSWAP_64(drrw->drr_offset);
+                               drrw->drr_logical_size =
+                                   BSWAP_64(drrw->drr_logical_size);
+                               drrw->drr_toguid = BSWAP_64(drrw->drr_toguid);
+                               drrw->drr_key.ddk_prop =
+                                   BSWAP_64(drrw->drr_key.ddk_prop);
+                               drrw->drr_compressed_size =
+                                   BSWAP_64(drrw->drr_compressed_size);
+                       }
+
+                       uint64_t payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw);
+
+                       /*
+                        * If this is verbose and/or dump output,
+                        * print info on the modified block
+                        */
+                       if (verbose) {
+                               (void) printf("WRITE object = %llu type = %u "
+                                   "checksum type = %u compression type = %u\n"
+                                   "    offset = %llu logical_size = %llu "
+                                   "compressed_size = %llu "
+                                   "payload_size = %llu "
+                                   "props = %llx\n",
+                                   (u_longlong_t)drrw->drr_object,
+                                   drrw->drr_type,
+                                   drrw->drr_checksumtype,
+                                   drrw->drr_compressiontype,
+                                   (u_longlong_t)drrw->drr_offset,
+                                   (u_longlong_t)drrw->drr_logical_size,
+                                   (u_longlong_t)drrw->drr_compressed_size,
+                                   (u_longlong_t)payload_size,
+                                   (u_longlong_t)drrw->drr_key.ddk_prop);
+                       }
+
+                       /*
+                        * Read the contents of the block in from STDIN to buf
+                        */
+                       (void) ssread(buf, payload_size, &zc);
+                       /*
+                        * If in dump mode
+                        */
+                       if (dump) {
+                               print_block(buf, payload_size);
+                       }
+                       total_write_size += payload_size;
+                       break;
+
+               case DRR_WRITE_BYREF:
+                       if (do_byteswap) {
+                               drrwbr->drr_object =
+                                   BSWAP_64(drrwbr->drr_object);
+                               drrwbr->drr_offset =
+                                   BSWAP_64(drrwbr->drr_offset);
+                               drrwbr->drr_length =
+                                   BSWAP_64(drrwbr->drr_length);
+                               drrwbr->drr_toguid =
+                                   BSWAP_64(drrwbr->drr_toguid);
+                               drrwbr->drr_refguid =
+                                   BSWAP_64(drrwbr->drr_refguid);
+                               drrwbr->drr_refobject =
+                                   BSWAP_64(drrwbr->drr_refobject);
+                               drrwbr->drr_refoffset =
+                                   BSWAP_64(drrwbr->drr_refoffset);
+                               drrwbr->drr_key.ddk_prop =
+                                   BSWAP_64(drrwbr->drr_key.ddk_prop);
+                       }
+                       if (verbose) {
+                               (void) printf("WRITE_BYREF object = %llu "
+                                   "checksum type = %u props = %llx\n"
+                                   "    offset = %llu length = %llu\n"
+                                   "toguid = %llx refguid = %llx\n"
+                                   "    refobject = %llu refoffset = %llu\n",
+                                   (u_longlong_t)drrwbr->drr_object,
+                                   drrwbr->drr_checksumtype,
+                                   (u_longlong_t)drrwbr->drr_key.ddk_prop,
+                                   (u_longlong_t)drrwbr->drr_offset,
+                                   (u_longlong_t)drrwbr->drr_length,
+                                   (u_longlong_t)drrwbr->drr_toguid,
+                                   (u_longlong_t)drrwbr->drr_refguid,
+                                   (u_longlong_t)drrwbr->drr_refobject,
+                                   (u_longlong_t)drrwbr->drr_refoffset);
+                       }
+                       break;
+
+               case DRR_FREE:
+                       if (do_byteswap) {
+                               drrf->drr_object = BSWAP_64(drrf->drr_object);
+                               drrf->drr_offset = BSWAP_64(drrf->drr_offset);
+                               drrf->drr_length = BSWAP_64(drrf->drr_length);
+                       }
+                       if (verbose) {
+                               (void) printf("FREE object = %llu "
+                                   "offset = %llu length = %lld\n",
+                                   (u_longlong_t)drrf->drr_object,
+                                   (u_longlong_t)drrf->drr_offset,
+                                   (longlong_t)drrf->drr_length);
+                       }
+                       break;
+               case DRR_SPILL:
+                       if (do_byteswap) {
+                               drrs->drr_object = BSWAP_64(drrs->drr_object);
+                               drrs->drr_length = BSWAP_64(drrs->drr_length);
+                       }
+                       if (verbose) {
+                               (void) printf("SPILL block for object = %llu "
+                                   "length = %llu\n",
+                                   (long long unsigned int)drrs->drr_object,
+                                   (long long unsigned int)drrs->drr_length);
+                       }
+                       (void) ssread(buf, drrs->drr_length, &zc);
+                       if (dump) {
+                               print_block(buf, drrs->drr_length);
+                       }
+                       break;
+               case DRR_WRITE_EMBEDDED:
+                       if (do_byteswap) {
+                               drrwe->drr_object =
+                                   BSWAP_64(drrwe->drr_object);
+                               drrwe->drr_offset =
+                                   BSWAP_64(drrwe->drr_offset);
+                               drrwe->drr_length =
+                                   BSWAP_64(drrwe->drr_length);
+                               drrwe->drr_toguid =
+                                   BSWAP_64(drrwe->drr_toguid);
+                               drrwe->drr_lsize =
+                                   BSWAP_32(drrwe->drr_lsize);
+                               drrwe->drr_psize =
+                                   BSWAP_32(drrwe->drr_psize);
+                       }
+                       if (verbose) {
+                               (void) printf("WRITE_EMBEDDED object = %llu "
+                                   "offset = %llu length = %llu\n"
+                                   "    toguid = %llx comp = %u etype = %u "
+                                   "lsize = %u psize = %u\n",
+                                   (u_longlong_t)drrwe->drr_object,
+                                   (u_longlong_t)drrwe->drr_offset,
+                                   (u_longlong_t)drrwe->drr_length,
+                                   (u_longlong_t)drrwe->drr_toguid,
+                                   drrwe->drr_compression,
+                                   drrwe->drr_etype,
+                                   drrwe->drr_lsize,
+                                   drrwe->drr_psize);
+                       }
+                       (void) ssread(buf,
+                           P2ROUNDUP(drrwe->drr_psize, 8), &zc);
+                       break;
+               case DRR_NUMTYPES:
+                       /* should never be reached */
+                       exit(1);
+               }
+               if (drr->drr_type != DRR_BEGIN && very_verbose) {
+                       (void) printf("    checksum = %llx/%llx/%llx/%llx\n",
+                           (longlong_t)drrc->drr_checksum.zc_word[0],
+                           (longlong_t)drrc->drr_checksum.zc_word[1],
+                           (longlong_t)drrc->drr_checksum.zc_word[2],
+                           (longlong_t)drrc->drr_checksum.zc_word[3]);
+               }
+               pcksum = zc;
+       }
+       free(buf);
+
+       /* Print final summary */
+
+       (void) printf("SUMMARY:\n");
+       (void) printf("\tTotal DRR_BEGIN records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_BEGIN]);
+       (void) printf("\tTotal DRR_END records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_END]);
+       (void) printf("\tTotal DRR_OBJECT records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_OBJECT]);
+       (void) printf("\tTotal DRR_FREEOBJECTS records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_FREEOBJECTS]);
+       (void) printf("\tTotal DRR_WRITE records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_WRITE]);
+       (void) printf("\tTotal DRR_WRITE_BYREF records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_WRITE_BYREF]);
+       (void) printf("\tTotal DRR_WRITE_EMBEDDED records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_WRITE_EMBEDDED]);
+       (void) printf("\tTotal DRR_FREE records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_FREE]);
+       (void) printf("\tTotal DRR_SPILL records = %lld\n",
+           (u_longlong_t)drr_record_count[DRR_SPILL]);
+       (void) printf("\tTotal records = %lld\n",
+           (u_longlong_t)total_records);
+       (void) printf("\tTotal write size = %lld (0x%llx)\n",
+           (u_longlong_t)total_write_size, (u_longlong_t)total_write_size);
+       (void) printf("\tTotal stream length = %lld (0x%llx)\n",
+           (u_longlong_t)total_stream_len, (u_longlong_t)total_stream_len);
+       return (0);
+}
diff --git a/zfs/cmd/ztest/Makefile.am b/zfs/cmd/ztest/Makefile.am
new file mode 100644 (file)
index 0000000..a2f3b5a
--- /dev/null
@@ -0,0 +1,22 @@
+include $(top_srcdir)/config/Rules.am
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+AM_CPPFLAGS += -DDEBUG
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+sbin_PROGRAMS = ztest
+
+ztest_SOURCES = \
+       ztest.c
+
+ztest_LDADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libzpool/libzpool.la \
+       $(top_builddir)/lib/libzfs/libzfs.la \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la
+
+ztest_LDADD += -lm
diff --git a/zfs/cmd/ztest/Makefile.in b/zfs/cmd/ztest/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/ztest/ztest.c b/zfs/cmd/ztest/ztest.c
new file mode 100644 (file)
index 0000000..2e4dae3
--- /dev/null
@@ -0,0 +1,6952 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ */
+
+/*
+ * The objective of this program is to provide a DMU/ZAP/SPA stress test
+ * that runs entirely in userland, is easy to use, and easy to extend.
+ *
+ * The overall design of the ztest program is as follows:
+ *
+ * (1) For each major functional area (e.g. adding vdevs to a pool,
+ *     creating and destroying datasets, reading and writing objects, etc)
+ *     we have a simple routine to test that functionality.  These
+ *     individual routines do not have to do anything "stressful".
+ *
+ * (2) We turn these simple functionality tests into a stress test by
+ *     running them all in parallel, with as many threads as desired,
+ *     and spread across as many datasets, objects, and vdevs as desired.
+ *
+ * (3) While all this is happening, we inject faults into the pool to
+ *     verify that self-healing data really works.
+ *
+ * (4) Every time we open a dataset, we change its checksum and compression
+ *     functions.  Thus even individual objects vary from block to block
+ *     in which checksum they use and whether they're compressed.
+ *
+ * (5) To verify that we never lose on-disk consistency after a crash,
+ *     we run the entire test in a child of the main process.
+ *     At random times, the child self-immolates with a SIGKILL.
+ *     This is the software equivalent of pulling the power cord.
+ *     The parent then runs the test again, using the existing
+ *     storage pool, as many times as desired. If backwards compatibility
+ *     testing is enabled ztest will sometimes run the "older" version
+ *     of ztest after a SIGKILL.
+ *
+ * (6) To verify that we don't have future leaks or temporal incursions,
+ *     many of the functional tests record the transaction group number
+ *     as part of their data.  When reading old data, they verify that
+ *     the transaction group number is less than the current, open txg.
+ *     If you add a new test, please do this if applicable.
+ *
+ * (7) Threads are created with a reduced stack size, for sanity checking.
+ *     Therefore, it's important not to allocate huge buffers on the stack.
+ *
+ * When run with no arguments, ztest runs for about five minutes and
+ * produces no output if successful.  To get a little bit of information,
+ * specify -V.  To get more information, specify -VV, and so on.
+ *
+ * To turn this into an overnight stress test, use -T to specify run time.
+ *
+ * You can ask more more vdevs [-v], datasets [-d], or threads [-t]
+ * to increase the pool capacity, fanout, and overall stress level.
+ *
+ * Use the -k option to set the desired frequency of kills.
+ *
+ * When ztest invokes itself it passes all relevant information through a
+ * temporary file which is mmap-ed in the child process. This allows shared
+ * memory to survive the exec syscall. The ztest_shared_hdr_t struct is always
+ * stored at offset 0 of this file and contains information on the size and
+ * number of shared structures in the file. The information stored in this file
+ * must remain backwards compatible with older versions of ztest so that
+ * ztest can invoke them during backwards compatibility testing (-B).
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
+#include <sys/txg.h>
+#include <sys/dbuf.h>
+#include <sys/zap.h>
+#include <sys/dmu_objset.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/zio.h>
+#include <sys/zil.h>
+#include <sys/zil_impl.h>
+#include <sys/zfs_rlock.h>
+#include <sys/vdev_impl.h>
+#include <sys/vdev_file.h>
+#include <sys/spa_impl.h>
+#include <sys/metaslab_impl.h>
+#include <sys/dsl_prop.h>
+#include <sys/dsl_dataset.h>
+#include <sys/dsl_destroy.h>
+#include <sys/dsl_scan.h>
+#include <sys/zio_checksum.h>
+#include <sys/refcount.h>
+#include <sys/zfeature.h>
+#include <sys/dsl_userhold.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <umem.h>
+#include <ctype.h>
+#include <math.h>
+#include <sys/fs/zfs.h>
+#include <zfs_fletcher.h>
+#include <libnvpair.h>
+#ifdef __GLIBC__
+#include <execinfo.h> /* for backtrace() */
+#endif
+
+static int ztest_fd_data = -1;
+static int ztest_fd_rand = -1;
+
+typedef struct ztest_shared_hdr {
+       uint64_t        zh_hdr_size;
+       uint64_t        zh_opts_size;
+       uint64_t        zh_size;
+       uint64_t        zh_stats_size;
+       uint64_t        zh_stats_count;
+       uint64_t        zh_ds_size;
+       uint64_t        zh_ds_count;
+} ztest_shared_hdr_t;
+
+static ztest_shared_hdr_t *ztest_shared_hdr;
+
+typedef struct ztest_shared_opts {
+       char zo_pool[ZFS_MAX_DATASET_NAME_LEN];
+       char zo_dir[ZFS_MAX_DATASET_NAME_LEN];
+       char zo_alt_ztest[MAXNAMELEN];
+       char zo_alt_libpath[MAXNAMELEN];
+       uint64_t zo_vdevs;
+       uint64_t zo_vdevtime;
+       size_t zo_vdev_size;
+       int zo_ashift;
+       int zo_mirrors;
+       int zo_raidz;
+       int zo_raidz_parity;
+       int zo_datasets;
+       int zo_threads;
+       uint64_t zo_passtime;
+       uint64_t zo_killrate;
+       int zo_verbose;
+       int zo_init;
+       uint64_t zo_time;
+       uint64_t zo_maxloops;
+       uint64_t zo_metaslab_gang_bang;
+} ztest_shared_opts_t;
+
+static const ztest_shared_opts_t ztest_opts_defaults = {
+       .zo_pool = { 'z', 't', 'e', 's', 't', '\0' },
+       .zo_dir = { '/', 't', 'm', 'p', '\0' },
+       .zo_alt_ztest = { '\0' },
+       .zo_alt_libpath = { '\0' },
+       .zo_vdevs = 5,
+       .zo_ashift = SPA_MINBLOCKSHIFT,
+       .zo_mirrors = 2,
+       .zo_raidz = 4,
+       .zo_raidz_parity = 1,
+       .zo_vdev_size = SPA_MINDEVSIZE * 2,
+       .zo_datasets = 7,
+       .zo_threads = 23,
+       .zo_passtime = 60,              /* 60 seconds */
+       .zo_killrate = 70,              /* 70% kill rate */
+       .zo_verbose = 0,
+       .zo_init = 1,
+       .zo_time = 300,                 /* 5 minutes */
+       .zo_maxloops = 50,              /* max loops during spa_freeze() */
+       .zo_metaslab_gang_bang = 32 << 10
+};
+
+extern uint64_t metaslab_gang_bang;
+extern uint64_t metaslab_df_alloc_threshold;
+extern int metaslab_preload_limit;
+extern boolean_t zfs_compressed_arc_enabled;
+
+static ztest_shared_opts_t *ztest_shared_opts;
+static ztest_shared_opts_t ztest_opts;
+
+typedef struct ztest_shared_ds {
+       uint64_t        zd_seq;
+} ztest_shared_ds_t;
+
+static ztest_shared_ds_t *ztest_shared_ds;
+#define        ZTEST_GET_SHARED_DS(d) (&ztest_shared_ds[d])
+
+#define        BT_MAGIC        0x123456789abcdefULL
+#define        MAXFAULTS() \
+       (MAX(zs->zs_mirrors, 1) * (ztest_opts.zo_raidz_parity + 1) - 1)
+
+enum ztest_io_type {
+       ZTEST_IO_WRITE_TAG,
+       ZTEST_IO_WRITE_PATTERN,
+       ZTEST_IO_WRITE_ZEROES,
+       ZTEST_IO_TRUNCATE,
+       ZTEST_IO_SETATTR,
+       ZTEST_IO_REWRITE,
+       ZTEST_IO_TYPES
+};
+
+typedef struct ztest_block_tag {
+       uint64_t        bt_magic;
+       uint64_t        bt_objset;
+       uint64_t        bt_object;
+       uint64_t        bt_dnodesize;
+       uint64_t        bt_offset;
+       uint64_t        bt_gen;
+       uint64_t        bt_txg;
+       uint64_t        bt_crtxg;
+} ztest_block_tag_t;
+
+typedef struct bufwad {
+       uint64_t        bw_index;
+       uint64_t        bw_txg;
+       uint64_t        bw_data;
+} bufwad_t;
+
+typedef struct rll {
+       void            *rll_writer;
+       int             rll_readers;
+       kmutex_t        rll_lock;
+       kcondvar_t      rll_cv;
+} rll_t;
+
+typedef struct zll {
+       list_t z_list;
+       kmutex_t z_lock;
+} zll_t;
+
+#define        ZTEST_RANGE_LOCKS       64
+#define        ZTEST_OBJECT_LOCKS      64
+
+/*
+ * Object descriptor.  Used as a template for object lookup/create/remove.
+ */
+typedef struct ztest_od {
+       uint64_t        od_dir;
+       uint64_t        od_object;
+       dmu_object_type_t od_type;
+       dmu_object_type_t od_crtype;
+       uint64_t        od_blocksize;
+       uint64_t        od_crblocksize;
+       uint64_t        od_crdnodesize;
+       uint64_t        od_gen;
+       uint64_t        od_crgen;
+       char            od_name[ZFS_MAX_DATASET_NAME_LEN];
+} ztest_od_t;
+
+/*
+ * Per-dataset state.
+ */
+typedef struct ztest_ds {
+       ztest_shared_ds_t *zd_shared;
+       objset_t        *zd_os;
+       rwlock_t        zd_zilog_lock;
+       zilog_t         *zd_zilog;
+       ztest_od_t      *zd_od;         /* debugging aid */
+       char            zd_name[ZFS_MAX_DATASET_NAME_LEN];
+       kmutex_t        zd_dirobj_lock;
+       rll_t           zd_object_lock[ZTEST_OBJECT_LOCKS];
+       zll_t           zd_range_lock[ZTEST_RANGE_LOCKS];
+} ztest_ds_t;
+
+/*
+ * Per-iteration state.
+ */
+typedef void ztest_func_t(ztest_ds_t *zd, uint64_t id);
+
+typedef struct ztest_info {
+       ztest_func_t    *zi_func;       /* test function */
+       uint64_t        zi_iters;       /* iterations per execution */
+       uint64_t        *zi_interval;   /* execute every <interval> seconds */
+       const char      *zi_funcname;   /* name of test function */
+} ztest_info_t;
+
+typedef struct ztest_shared_callstate {
+       uint64_t        zc_count;       /* per-pass count */
+       uint64_t        zc_time;        /* per-pass time */
+       uint64_t        zc_next;        /* next time to call this function */
+} ztest_shared_callstate_t;
+
+static ztest_shared_callstate_t *ztest_shared_callstate;
+#define        ZTEST_GET_SHARED_CALLSTATE(c) (&ztest_shared_callstate[c])
+
+ztest_func_t ztest_dmu_read_write;
+ztest_func_t ztest_dmu_write_parallel;
+ztest_func_t ztest_dmu_object_alloc_free;
+ztest_func_t ztest_dmu_commit_callbacks;
+ztest_func_t ztest_zap;
+ztest_func_t ztest_zap_parallel;
+ztest_func_t ztest_zil_commit;
+ztest_func_t ztest_zil_remount;
+ztest_func_t ztest_dmu_read_write_zcopy;
+ztest_func_t ztest_dmu_objset_create_destroy;
+ztest_func_t ztest_dmu_prealloc;
+ztest_func_t ztest_fzap;
+ztest_func_t ztest_dmu_snapshot_create_destroy;
+ztest_func_t ztest_dsl_prop_get_set;
+ztest_func_t ztest_spa_prop_get_set;
+ztest_func_t ztest_spa_create_destroy;
+ztest_func_t ztest_fault_inject;
+ztest_func_t ztest_ddt_repair;
+ztest_func_t ztest_dmu_snapshot_hold;
+ztest_func_t ztest_spa_rename;
+ztest_func_t ztest_scrub;
+ztest_func_t ztest_dsl_dataset_promote_busy;
+ztest_func_t ztest_vdev_attach_detach;
+ztest_func_t ztest_vdev_LUN_growth;
+ztest_func_t ztest_vdev_add_remove;
+ztest_func_t ztest_vdev_aux_add_remove;
+ztest_func_t ztest_split_pool;
+ztest_func_t ztest_reguid;
+ztest_func_t ztest_spa_upgrade;
+ztest_func_t ztest_fletcher;
+ztest_func_t ztest_fletcher_incr;
+ztest_func_t ztest_verify_dnode_bt;
+
+uint64_t zopt_always = 0ULL * NANOSEC;         /* all the time */
+uint64_t zopt_incessant = 1ULL * NANOSEC / 10; /* every 1/10 second */
+uint64_t zopt_often = 1ULL * NANOSEC;          /* every second */
+uint64_t zopt_sometimes = 10ULL * NANOSEC;     /* every 10 seconds */
+uint64_t zopt_rarely = 60ULL * NANOSEC;                /* every 60 seconds */
+
+#define        ZTI_INIT(func, iters, interval) \
+       {   .zi_func = (func), \
+           .zi_iters = (iters), \
+           .zi_interval = (interval), \
+           .zi_funcname = # func }
+
+ztest_info_t ztest_info[] = {
+       ZTI_INIT(ztest_dmu_read_write, 1, &zopt_always),
+       ZTI_INIT(ztest_dmu_write_parallel, 10, &zopt_always),
+       ZTI_INIT(ztest_dmu_object_alloc_free, 1, &zopt_always),
+       ZTI_INIT(ztest_dmu_commit_callbacks, 1, &zopt_always),
+       ZTI_INIT(ztest_zap, 30, &zopt_always),
+       ZTI_INIT(ztest_zap_parallel, 100, &zopt_always),
+       ZTI_INIT(ztest_split_pool, 1, &zopt_always),
+       ZTI_INIT(ztest_zil_commit, 1, &zopt_incessant),
+       ZTI_INIT(ztest_zil_remount, 1, &zopt_sometimes),
+       ZTI_INIT(ztest_dmu_read_write_zcopy, 1, &zopt_often),
+       ZTI_INIT(ztest_dmu_objset_create_destroy, 1, &zopt_often),
+       ZTI_INIT(ztest_dsl_prop_get_set, 1, &zopt_often),
+       ZTI_INIT(ztest_spa_prop_get_set, 1, &zopt_sometimes),
+#if 0
+       ZTI_INIT(ztest_dmu_prealloc, 1, &zopt_sometimes),
+#endif
+       ZTI_INIT(ztest_fzap, 1, &zopt_sometimes),
+       ZTI_INIT(ztest_dmu_snapshot_create_destroy, 1, &zopt_sometimes),
+       ZTI_INIT(ztest_spa_create_destroy, 1, &zopt_sometimes),
+       ZTI_INIT(ztest_fault_inject, 1, &zopt_sometimes),
+       ZTI_INIT(ztest_ddt_repair, 1, &zopt_sometimes),
+       ZTI_INIT(ztest_dmu_snapshot_hold, 1, &zopt_sometimes),
+       ZTI_INIT(ztest_reguid, 1, &zopt_rarely),
+       ZTI_INIT(ztest_spa_rename, 1, &zopt_rarely),
+       ZTI_INIT(ztest_scrub, 1, &zopt_rarely),
+       ZTI_INIT(ztest_spa_upgrade, 1, &zopt_rarely),
+       ZTI_INIT(ztest_dsl_dataset_promote_busy, 1, &zopt_rarely),
+       ZTI_INIT(ztest_vdev_attach_detach, 1, &zopt_sometimes),
+       ZTI_INIT(ztest_vdev_LUN_growth, 1, &zopt_rarely),
+       ZTI_INIT(ztest_vdev_add_remove, 1, &ztest_opts.zo_vdevtime),
+       ZTI_INIT(ztest_vdev_aux_add_remove, 1, &ztest_opts.zo_vdevtime),
+       ZTI_INIT(ztest_fletcher, 1, &zopt_rarely),
+       ZTI_INIT(ztest_fletcher_incr, 1, &zopt_rarely),
+       ZTI_INIT(ztest_verify_dnode_bt, 1, &zopt_sometimes),
+};
+
+#define        ZTEST_FUNCS     (sizeof (ztest_info) / sizeof (ztest_info_t))
+
+/*
+ * The following struct is used to hold a list of uncalled commit callbacks.
+ * The callbacks are ordered by txg number.
+ */
+typedef struct ztest_cb_list {
+       kmutex_t        zcl_callbacks_lock;
+       list_t          zcl_callbacks;
+} ztest_cb_list_t;
+
+/*
+ * Stuff we need to share writably between parent and child.
+ */
+typedef struct ztest_shared {
+       boolean_t       zs_do_init;
+       hrtime_t        zs_proc_start;
+       hrtime_t        zs_proc_stop;
+       hrtime_t        zs_thread_start;
+       hrtime_t        zs_thread_stop;
+       hrtime_t        zs_thread_kill;
+       uint64_t        zs_enospc_count;
+       uint64_t        zs_vdev_next_leaf;
+       uint64_t        zs_vdev_aux;
+       uint64_t        zs_alloc;
+       uint64_t        zs_space;
+       uint64_t        zs_splits;
+       uint64_t        zs_mirrors;
+       uint64_t        zs_metaslab_sz;
+       uint64_t        zs_metaslab_df_alloc_threshold;
+       uint64_t        zs_guid;
+} ztest_shared_t;
+
+#define        ID_PARALLEL     -1ULL
+
+static char ztest_dev_template[] = "%s/%s.%llua";
+static char ztest_aux_template[] = "%s/%s.%s.%llu";
+ztest_shared_t *ztest_shared;
+
+static spa_t *ztest_spa = NULL;
+static ztest_ds_t *ztest_ds;
+
+static kmutex_t ztest_vdev_lock;
+
+/*
+ * The ztest_name_lock protects the pool and dataset namespace used by
+ * the individual tests. To modify the namespace, consumers must grab
+ * this lock as writer. Grabbing the lock as reader will ensure that the
+ * namespace does not change while the lock is held.
+ */
+static rwlock_t ztest_name_lock;
+
+static boolean_t ztest_dump_core = B_TRUE;
+static boolean_t ztest_exiting;
+
+/* Global commit callback list */
+static ztest_cb_list_t zcl;
+/* Commit cb delay */
+static uint64_t zc_min_txg_delay = UINT64_MAX;
+static int zc_cb_counter = 0;
+
+/*
+ * Minimum number of commit callbacks that need to be registered for us to check
+ * whether the minimum txg delay is acceptable.
+ */
+#define        ZTEST_COMMIT_CB_MIN_REG 100
+
+/*
+ * If a number of txgs equal to this threshold have been created after a commit
+ * callback has been registered but not called, then we assume there is an
+ * implementation bug.
+ */
+#define        ZTEST_COMMIT_CB_THRESH  (TXG_CONCURRENT_STATES + 1000)
+
+extern uint64_t metaslab_gang_bang;
+extern uint64_t metaslab_df_alloc_threshold;
+
+enum ztest_object {
+       ZTEST_META_DNODE = 0,
+       ZTEST_DIROBJ,
+       ZTEST_OBJECTS
+};
+
+static void usage(boolean_t) __NORETURN;
+
+/*
+ * These libumem hooks provide a reasonable set of defaults for the allocator's
+ * debugging facilities.
+ */
+const char *
+_umem_debug_init(void)
+{
+       return ("default,verbose"); /* $UMEM_DEBUG setting */
+}
+
+const char *
+_umem_logging_init(void)
+{
+       return ("fail,contents"); /* $UMEM_LOGGING setting */
+}
+
+#define        BACKTRACE_SZ    100
+
+static void sig_handler(int signo)
+{
+       struct sigaction action;
+#ifdef __GLIBC__ /* backtrace() is a GNU extension */
+       int nptrs;
+       void *buffer[BACKTRACE_SZ];
+
+       nptrs = backtrace(buffer, BACKTRACE_SZ);
+       backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
+#endif
+
+       /*
+        * Restore default action and re-raise signal so SIGSEGV and
+        * SIGABRT can trigger a core dump.
+        */
+       action.sa_handler = SIG_DFL;
+       sigemptyset(&action.sa_mask);
+       action.sa_flags = 0;
+       (void) sigaction(signo, &action, NULL);
+       raise(signo);
+}
+
+#define        FATAL_MSG_SZ    1024
+
+char *fatal_msg;
+
+static void
+fatal(int do_perror, char *message, ...)
+{
+       va_list args;
+       int save_errno = errno;
+       char *buf;
+
+       (void) fflush(stdout);
+       buf = umem_alloc(FATAL_MSG_SZ, UMEM_NOFAIL);
+
+       va_start(args, message);
+       (void) sprintf(buf, "ztest: ");
+       /* LINTED */
+       (void) vsprintf(buf + strlen(buf), message, args);
+       va_end(args);
+       if (do_perror) {
+               (void) snprintf(buf + strlen(buf), FATAL_MSG_SZ - strlen(buf),
+                   ": %s", strerror(save_errno));
+       }
+       (void) fprintf(stderr, "%s\n", buf);
+       fatal_msg = buf;                        /* to ease debugging */
+       if (ztest_dump_core)
+               abort();
+       exit(3);
+}
+
+static int
+str2shift(const char *buf)
+{
+       const char *ends = "BKMGTPEZ";
+       int i;
+
+       if (buf[0] == '\0')
+               return (0);
+       for (i = 0; i < strlen(ends); i++) {
+               if (toupper(buf[0]) == ends[i])
+                       break;
+       }
+       if (i == strlen(ends)) {
+               (void) fprintf(stderr, "ztest: invalid bytes suffix: %s\n",
+                   buf);
+               usage(B_FALSE);
+       }
+       if (buf[1] == '\0' || (toupper(buf[1]) == 'B' && buf[2] == '\0')) {
+               return (10*i);
+       }
+       (void) fprintf(stderr, "ztest: invalid bytes suffix: %s\n", buf);
+       usage(B_FALSE);
+       /* NOTREACHED */
+}
+
+static uint64_t
+nicenumtoull(const char *buf)
+{
+       char *end;
+       uint64_t val;
+
+       val = strtoull(buf, &end, 0);
+       if (end == buf) {
+               (void) fprintf(stderr, "ztest: bad numeric value: %s\n", buf);
+               usage(B_FALSE);
+       } else if (end[0] == '.') {
+               double fval = strtod(buf, &end);
+               fval *= pow(2, str2shift(end));
+               if (fval > UINT64_MAX) {
+                       (void) fprintf(stderr, "ztest: value too large: %s\n",
+                           buf);
+                       usage(B_FALSE);
+               }
+               val = (uint64_t)fval;
+       } else {
+               int shift = str2shift(end);
+               if (shift >= 64 || (val << shift) >> shift != val) {
+                       (void) fprintf(stderr, "ztest: value too large: %s\n",
+                           buf);
+                       usage(B_FALSE);
+               }
+               val <<= shift;
+       }
+       return (val);
+}
+
+static void
+usage(boolean_t requested)
+{
+       const ztest_shared_opts_t *zo = &ztest_opts_defaults;
+
+       char nice_vdev_size[10];
+       char nice_gang_bang[10];
+       FILE *fp = requested ? stdout : stderr;
+
+       nicenum(zo->zo_vdev_size, nice_vdev_size);
+       nicenum(zo->zo_metaslab_gang_bang, nice_gang_bang);
+
+       (void) fprintf(fp, "Usage: %s\n"
+           "\t[-v vdevs (default: %llu)]\n"
+           "\t[-s size_of_each_vdev (default: %s)]\n"
+           "\t[-a alignment_shift (default: %d)] use 0 for random\n"
+           "\t[-m mirror_copies (default: %d)]\n"
+           "\t[-r raidz_disks (default: %d)]\n"
+           "\t[-R raidz_parity (default: %d)]\n"
+           "\t[-d datasets (default: %d)]\n"
+           "\t[-t threads (default: %d)]\n"
+           "\t[-g gang_block_threshold (default: %s)]\n"
+           "\t[-i init_count (default: %d)] initialize pool i times\n"
+           "\t[-k kill_percentage (default: %llu%%)]\n"
+           "\t[-p pool_name (default: %s)]\n"
+           "\t[-f dir (default: %s)] file directory for vdev files\n"
+           "\t[-V] verbose (use multiple times for ever more blather)\n"
+           "\t[-E] use existing pool instead of creating new one\n"
+           "\t[-T time (default: %llu sec)] total run time\n"
+           "\t[-F freezeloops (default: %llu)] max loops in spa_freeze()\n"
+           "\t[-P passtime (default: %llu sec)] time per pass\n"
+           "\t[-B alt_ztest (default: <none>)] alternate ztest path\n"
+           "\t[-h] (print help)\n"
+           "",
+           zo->zo_pool,
+           (u_longlong_t)zo->zo_vdevs,                 /* -v */
+           nice_vdev_size,                             /* -s */
+           zo->zo_ashift,                              /* -a */
+           zo->zo_mirrors,                             /* -m */
+           zo->zo_raidz,                               /* -r */
+           zo->zo_raidz_parity,                        /* -R */
+           zo->zo_datasets,                            /* -d */
+           zo->zo_threads,                             /* -t */
+           nice_gang_bang,                             /* -g */
+           zo->zo_init,                                /* -i */
+           (u_longlong_t)zo->zo_killrate,              /* -k */
+           zo->zo_pool,                                /* -p */
+           zo->zo_dir,                                 /* -f */
+           (u_longlong_t)zo->zo_time,                  /* -T */
+           (u_longlong_t)zo->zo_maxloops,              /* -F */
+           (u_longlong_t)zo->zo_passtime);
+       exit(requested ? 0 : 1);
+}
+
+static void
+process_options(int argc, char **argv)
+{
+       char *path;
+       ztest_shared_opts_t *zo = &ztest_opts;
+
+       int opt;
+       uint64_t value;
+       char altdir[MAXNAMELEN] = { 0 };
+
+       bcopy(&ztest_opts_defaults, zo, sizeof (*zo));
+
+       while ((opt = getopt(argc, argv,
+           "v:s:a:m:r:R:d:t:g:i:k:p:f:VET:P:hF:B:")) != EOF) {
+               value = 0;
+               switch (opt) {
+               case 'v':
+               case 's':
+               case 'a':
+               case 'm':
+               case 'r':
+               case 'R':
+               case 'd':
+               case 't':
+               case 'g':
+               case 'i':
+               case 'k':
+               case 'T':
+               case 'P':
+               case 'F':
+                       value = nicenumtoull(optarg);
+               }
+               switch (opt) {
+               case 'v':
+                       zo->zo_vdevs = value;
+                       break;
+               case 's':
+                       zo->zo_vdev_size = MAX(SPA_MINDEVSIZE, value);
+                       break;
+               case 'a':
+                       zo->zo_ashift = value;
+                       break;
+               case 'm':
+                       zo->zo_mirrors = value;
+                       break;
+               case 'r':
+                       zo->zo_raidz = MAX(1, value);
+                       break;
+               case 'R':
+                       zo->zo_raidz_parity = MIN(MAX(value, 1), 3);
+                       break;
+               case 'd':
+                       zo->zo_datasets = MAX(1, value);
+                       break;
+               case 't':
+                       zo->zo_threads = MAX(1, value);
+                       break;
+               case 'g':
+                       zo->zo_metaslab_gang_bang = MAX(SPA_MINBLOCKSIZE << 1,
+                           value);
+                       break;
+               case 'i':
+                       zo->zo_init = value;
+                       break;
+               case 'k':
+                       zo->zo_killrate = value;
+                       break;
+               case 'p':
+                       (void) strlcpy(zo->zo_pool, optarg,
+                           sizeof (zo->zo_pool));
+                       break;
+               case 'f':
+                       path = realpath(optarg, NULL);
+                       if (path == NULL) {
+                               (void) fprintf(stderr, "error: %s: %s\n",
+                                   optarg, strerror(errno));
+                               usage(B_FALSE);
+                       } else {
+                               (void) strlcpy(zo->zo_dir, path,
+                                   sizeof (zo->zo_dir));
+                               free(path);
+                       }
+                       break;
+               case 'V':
+                       zo->zo_verbose++;
+                       break;
+               case 'E':
+                       zo->zo_init = 0;
+                       break;
+               case 'T':
+                       zo->zo_time = value;
+                       break;
+               case 'P':
+                       zo->zo_passtime = MAX(1, value);
+                       break;
+               case 'F':
+                       zo->zo_maxloops = MAX(1, value);
+                       break;
+               case 'B':
+                       (void) strlcpy(altdir, optarg, sizeof (altdir));
+                       break;
+               case 'h':
+                       usage(B_TRUE);
+                       break;
+               case '?':
+               default:
+                       usage(B_FALSE);
+                       break;
+               }
+       }
+
+       zo->zo_raidz_parity = MIN(zo->zo_raidz_parity, zo->zo_raidz - 1);
+
+       zo->zo_vdevtime =
+           (zo->zo_vdevs > 0 ? zo->zo_time * NANOSEC / zo->zo_vdevs :
+           UINT64_MAX >> 2);
+
+       if (strlen(altdir) > 0) {
+               char *cmd;
+               char *realaltdir;
+               char *bin;
+               char *ztest;
+               char *isa;
+               int isalen;
+
+               cmd = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+               realaltdir = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+
+               VERIFY(NULL != realpath(getexecname(), cmd));
+               if (0 != access(altdir, F_OK)) {
+                       ztest_dump_core = B_FALSE;
+                       fatal(B_TRUE, "invalid alternate ztest path: %s",
+                           altdir);
+               }
+               VERIFY(NULL != realpath(altdir, realaltdir));
+
+               /*
+                * 'cmd' should be of the form "<anything>/usr/bin/<isa>/ztest".
+                * We want to extract <isa> to determine if we should use
+                * 32 or 64 bit binaries.
+                */
+               bin = strstr(cmd, "/usr/bin/");
+               ztest = strstr(bin, "/ztest");
+               isa = bin + 9;
+               isalen = ztest - isa;
+               (void) snprintf(zo->zo_alt_ztest, sizeof (zo->zo_alt_ztest),
+                   "%s/usr/bin/%.*s/ztest", realaltdir, isalen, isa);
+               (void) snprintf(zo->zo_alt_libpath, sizeof (zo->zo_alt_libpath),
+                   "%s/usr/lib/%.*s", realaltdir, isalen, isa);
+
+               if (0 != access(zo->zo_alt_ztest, X_OK)) {
+                       ztest_dump_core = B_FALSE;
+                       fatal(B_TRUE, "invalid alternate ztest: %s",
+                           zo->zo_alt_ztest);
+               } else if (0 != access(zo->zo_alt_libpath, X_OK)) {
+                       ztest_dump_core = B_FALSE;
+                       fatal(B_TRUE, "invalid alternate lib directory %s",
+                           zo->zo_alt_libpath);
+               }
+
+               umem_free(cmd, MAXPATHLEN);
+               umem_free(realaltdir, MAXPATHLEN);
+       }
+}
+
+static void
+ztest_kill(ztest_shared_t *zs)
+{
+       zs->zs_alloc = metaslab_class_get_alloc(spa_normal_class(ztest_spa));
+       zs->zs_space = metaslab_class_get_space(spa_normal_class(ztest_spa));
+
+       /*
+        * Before we kill off ztest, make sure that the config is updated.
+        * See comment above spa_config_sync().
+        */
+       mutex_enter(&spa_namespace_lock);
+       spa_config_sync(ztest_spa, B_FALSE, B_FALSE);
+       mutex_exit(&spa_namespace_lock);
+
+       (void) kill(getpid(), SIGKILL);
+}
+
+static uint64_t
+ztest_random(uint64_t range)
+{
+       uint64_t r;
+
+       ASSERT3S(ztest_fd_rand, >=, 0);
+
+       if (range == 0)
+               return (0);
+
+       if (read(ztest_fd_rand, &r, sizeof (r)) != sizeof (r))
+               fatal(1, "short read from /dev/urandom");
+
+       return (r % range);
+}
+
+/* ARGSUSED */
+static void
+ztest_record_enospc(const char *s)
+{
+       ztest_shared->zs_enospc_count++;
+}
+
+static uint64_t
+ztest_get_ashift(void)
+{
+       if (ztest_opts.zo_ashift == 0)
+               return (SPA_MINBLOCKSHIFT + ztest_random(5));
+       return (ztest_opts.zo_ashift);
+}
+
+static nvlist_t *
+make_vdev_file(char *path, char *aux, char *pool, size_t size, uint64_t ashift)
+{
+       char *pathbuf;
+       uint64_t vdev;
+       nvlist_t *file;
+
+       pathbuf = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+
+       if (ashift == 0)
+               ashift = ztest_get_ashift();
+
+       if (path == NULL) {
+               path = pathbuf;
+
+               if (aux != NULL) {
+                       vdev = ztest_shared->zs_vdev_aux;
+                       (void) snprintf(path, MAXPATHLEN,
+                           ztest_aux_template, ztest_opts.zo_dir,
+                           pool == NULL ? ztest_opts.zo_pool : pool,
+                           aux, vdev);
+               } else {
+                       vdev = ztest_shared->zs_vdev_next_leaf++;
+                       (void) snprintf(path, MAXPATHLEN,
+                           ztest_dev_template, ztest_opts.zo_dir,
+                           pool == NULL ? ztest_opts.zo_pool : pool, vdev);
+               }
+       }
+
+       if (size != 0) {
+               int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
+               if (fd == -1)
+                       fatal(1, "can't open %s", path);
+               if (ftruncate(fd, size) != 0)
+                       fatal(1, "can't ftruncate %s", path);
+               (void) close(fd);
+       }
+
+       VERIFY(nvlist_alloc(&file, NV_UNIQUE_NAME, 0) == 0);
+       VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_TYPE, VDEV_TYPE_FILE) == 0);
+       VERIFY(nvlist_add_string(file, ZPOOL_CONFIG_PATH, path) == 0);
+       VERIFY(nvlist_add_uint64(file, ZPOOL_CONFIG_ASHIFT, ashift) == 0);
+       umem_free(pathbuf, MAXPATHLEN);
+
+       return (file);
+}
+
+static nvlist_t *
+make_vdev_raidz(char *path, char *aux, char *pool, size_t size,
+    uint64_t ashift, int r)
+{
+       nvlist_t *raidz, **child;
+       int c;
+
+       if (r < 2)
+               return (make_vdev_file(path, aux, pool, size, ashift));
+       child = umem_alloc(r * sizeof (nvlist_t *), UMEM_NOFAIL);
+
+       for (c = 0; c < r; c++)
+               child[c] = make_vdev_file(path, aux, pool, size, ashift);
+
+       VERIFY(nvlist_alloc(&raidz, NV_UNIQUE_NAME, 0) == 0);
+       VERIFY(nvlist_add_string(raidz, ZPOOL_CONFIG_TYPE,
+           VDEV_TYPE_RAIDZ) == 0);
+       VERIFY(nvlist_add_uint64(raidz, ZPOOL_CONFIG_NPARITY,
+           ztest_opts.zo_raidz_parity) == 0);
+       VERIFY(nvlist_add_nvlist_array(raidz, ZPOOL_CONFIG_CHILDREN,
+           child, r) == 0);
+
+       for (c = 0; c < r; c++)
+               nvlist_free(child[c]);
+
+       umem_free(child, r * sizeof (nvlist_t *));
+
+       return (raidz);
+}
+
+static nvlist_t *
+make_vdev_mirror(char *path, char *aux, char *pool, size_t size,
+    uint64_t ashift, int r, int m)
+{
+       nvlist_t *mirror, **child;
+       int c;
+
+       if (m < 1)
+               return (make_vdev_raidz(path, aux, pool, size, ashift, r));
+
+       child = umem_alloc(m * sizeof (nvlist_t *), UMEM_NOFAIL);
+
+       for (c = 0; c < m; c++)
+               child[c] = make_vdev_raidz(path, aux, pool, size, ashift, r);
+
+       VERIFY(nvlist_alloc(&mirror, NV_UNIQUE_NAME, 0) == 0);
+       VERIFY(nvlist_add_string(mirror, ZPOOL_CONFIG_TYPE,
+           VDEV_TYPE_MIRROR) == 0);
+       VERIFY(nvlist_add_nvlist_array(mirror, ZPOOL_CONFIG_CHILDREN,
+           child, m) == 0);
+
+       for (c = 0; c < m; c++)
+               nvlist_free(child[c]);
+
+       umem_free(child, m * sizeof (nvlist_t *));
+
+       return (mirror);
+}
+
+static nvlist_t *
+make_vdev_root(char *path, char *aux, char *pool, size_t size, uint64_t ashift,
+    int log, int r, int m, int t)
+{
+       nvlist_t *root, **child;
+       int c;
+
+       ASSERT(t > 0);
+
+       child = umem_alloc(t * sizeof (nvlist_t *), UMEM_NOFAIL);
+
+       for (c = 0; c < t; c++) {
+               child[c] = make_vdev_mirror(path, aux, pool, size, ashift,
+                   r, m);
+               VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   log) == 0);
+       }
+
+       VERIFY(nvlist_alloc(&root, NV_UNIQUE_NAME, 0) == 0);
+       VERIFY(nvlist_add_string(root, ZPOOL_CONFIG_TYPE, VDEV_TYPE_ROOT) == 0);
+       VERIFY(nvlist_add_nvlist_array(root, aux ? aux : ZPOOL_CONFIG_CHILDREN,
+           child, t) == 0);
+
+       for (c = 0; c < t; c++)
+               nvlist_free(child[c]);
+
+       umem_free(child, t * sizeof (nvlist_t *));
+
+       return (root);
+}
+
+/*
+ * Find a random spa version. Returns back a random spa version in the
+ * range [initial_version, SPA_VERSION_FEATURES].
+ */
+static uint64_t
+ztest_random_spa_version(uint64_t initial_version)
+{
+       uint64_t version = initial_version;
+
+       if (version <= SPA_VERSION_BEFORE_FEATURES) {
+               version = version +
+                   ztest_random(SPA_VERSION_BEFORE_FEATURES - version + 1);
+       }
+
+       if (version > SPA_VERSION_BEFORE_FEATURES)
+               version = SPA_VERSION_FEATURES;
+
+       ASSERT(SPA_VERSION_IS_SUPPORTED(version));
+       return (version);
+}
+
+static int
+ztest_random_blocksize(void)
+{
+       /*
+        * Choose a block size >= the ashift.
+        * If the SPA supports new MAXBLOCKSIZE, test up to 1MB blocks.
+        */
+       int maxbs = SPA_OLD_MAXBLOCKSHIFT;
+       if (spa_maxblocksize(ztest_spa) == SPA_MAXBLOCKSIZE)
+               maxbs = 20;
+       uint64_t block_shift =
+           ztest_random(maxbs - ztest_spa->spa_max_ashift + 1);
+       return (1 << (SPA_MINBLOCKSHIFT + block_shift));
+}
+
+static int
+ztest_random_dnodesize(void)
+{
+       int slots;
+       int max_slots = spa_maxdnodesize(ztest_spa) >> DNODE_SHIFT;
+
+       if (max_slots == DNODE_MIN_SLOTS)
+               return (DNODE_MIN_SIZE);
+
+       /*
+        * Weight the random distribution more heavily toward smaller
+        * dnode sizes since that is more likely to reflect real-world
+        * usage.
+        */
+       ASSERT3U(max_slots, >, 4);
+       switch (ztest_random(10)) {
+       case 0:
+               slots = 5 + ztest_random(max_slots - 4);
+               break;
+       case 1 ... 4:
+               slots = 2 + ztest_random(3);
+               break;
+       default:
+               slots = 1;
+               break;
+       }
+
+       return (slots << DNODE_SHIFT);
+}
+
+static int
+ztest_random_ibshift(void)
+{
+       return (DN_MIN_INDBLKSHIFT +
+           ztest_random(DN_MAX_INDBLKSHIFT - DN_MIN_INDBLKSHIFT + 1));
+}
+
+static uint64_t
+ztest_random_vdev_top(spa_t *spa, boolean_t log_ok)
+{
+       uint64_t top;
+       vdev_t *rvd = spa->spa_root_vdev;
+       vdev_t *tvd;
+
+       ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0);
+
+       do {
+               top = ztest_random(rvd->vdev_children);
+               tvd = rvd->vdev_child[top];
+       } while (tvd->vdev_ishole || (tvd->vdev_islog && !log_ok) ||
+           tvd->vdev_mg == NULL || tvd->vdev_mg->mg_class == NULL);
+
+       return (top);
+}
+
+static uint64_t
+ztest_random_dsl_prop(zfs_prop_t prop)
+{
+       uint64_t value;
+
+       do {
+               value = zfs_prop_random_value(prop, ztest_random(-1ULL));
+       } while (prop == ZFS_PROP_CHECKSUM && value == ZIO_CHECKSUM_OFF);
+
+       return (value);
+}
+
+static int
+ztest_dsl_prop_set_uint64(char *osname, zfs_prop_t prop, uint64_t value,
+    boolean_t inherit)
+{
+       const char *propname = zfs_prop_to_name(prop);
+       const char *valname;
+       char *setpoint;
+       uint64_t curval;
+       int error;
+
+       error = dsl_prop_set_int(osname, propname,
+           (inherit ? ZPROP_SRC_NONE : ZPROP_SRC_LOCAL), value);
+
+       if (error == ENOSPC) {
+               ztest_record_enospc(FTAG);
+               return (error);
+       }
+       ASSERT0(error);
+
+       setpoint = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+       VERIFY0(dsl_prop_get_integer(osname, propname, &curval, setpoint));
+
+       if (ztest_opts.zo_verbose >= 6) {
+               int err;
+
+               err = zfs_prop_index_to_string(prop, curval, &valname);
+               if (err)
+                       (void) printf("%s %s = %llu at '%s'\n",
+                           osname, propname, (unsigned long long)curval,
+                               setpoint);
+               else
+                       (void) printf("%s %s = %s at '%s'\n",
+                           osname, propname, valname, setpoint);
+       }
+       umem_free(setpoint, MAXPATHLEN);
+
+       return (error);
+}
+
+static int
+ztest_spa_prop_set_uint64(zpool_prop_t prop, uint64_t value)
+{
+       spa_t *spa = ztest_spa;
+       nvlist_t *props = NULL;
+       int error;
+
+       VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+       VERIFY(nvlist_add_uint64(props, zpool_prop_to_name(prop), value) == 0);
+
+       error = spa_prop_set(spa, props);
+
+       nvlist_free(props);
+
+       if (error == ENOSPC) {
+               ztest_record_enospc(FTAG);
+               return (error);
+       }
+       ASSERT0(error);
+
+       return (error);
+}
+
+
+/*
+ * Object and range lock mechanics
+ */
+typedef struct {
+       list_node_t z_lnode;
+       refcount_t z_refcnt;
+       uint64_t z_object;
+       zfs_rlock_t z_range_lock;
+} ztest_znode_t;
+
+typedef struct {
+       rl_t *z_rl;
+       ztest_znode_t *z_ztznode;
+} ztest_zrl_t;
+
+static ztest_znode_t *
+ztest_znode_init(uint64_t object)
+{
+       ztest_znode_t *zp = umem_alloc(sizeof (*zp), UMEM_NOFAIL);
+
+       list_link_init(&zp->z_lnode);
+       refcount_create(&zp->z_refcnt);
+       zp->z_object = object;
+       zfs_rlock_init(&zp->z_range_lock);
+
+       return (zp);
+}
+
+static void
+ztest_znode_fini(ztest_znode_t *zp)
+{
+       ASSERT(refcount_is_zero(&zp->z_refcnt));
+       zfs_rlock_destroy(&zp->z_range_lock);
+       zp->z_object = 0;
+       refcount_destroy(&zp->z_refcnt);
+       list_link_init(&zp->z_lnode);
+       umem_free(zp, sizeof (*zp));
+}
+
+static void
+ztest_zll_init(zll_t *zll)
+{
+       mutex_init(&zll->z_lock, NULL, MUTEX_DEFAULT, NULL);
+       list_create(&zll->z_list, sizeof (ztest_znode_t),
+           offsetof(ztest_znode_t, z_lnode));
+}
+
+static void
+ztest_zll_destroy(zll_t *zll)
+{
+       list_destroy(&zll->z_list);
+       mutex_destroy(&zll->z_lock);
+}
+
+#define        RL_TAG "range_lock"
+static ztest_znode_t *
+ztest_znode_get(ztest_ds_t *zd, uint64_t object)
+{
+       zll_t *zll = &zd->zd_range_lock[object & (ZTEST_OBJECT_LOCKS - 1)];
+       ztest_znode_t *zp = NULL;
+       mutex_enter(&zll->z_lock);
+       for (zp = list_head(&zll->z_list); (zp);
+           zp = list_next(&zll->z_list, zp)) {
+               if (zp->z_object == object) {
+                       refcount_add(&zp->z_refcnt, RL_TAG);
+                       break;
+               }
+       }
+       if (zp == NULL) {
+               zp = ztest_znode_init(object);
+               refcount_add(&zp->z_refcnt, RL_TAG);
+               list_insert_head(&zll->z_list, zp);
+       }
+       mutex_exit(&zll->z_lock);
+       return (zp);
+}
+
+static void
+ztest_znode_put(ztest_ds_t *zd, ztest_znode_t *zp)
+{
+       zll_t *zll = NULL;
+       ASSERT3U(zp->z_object, !=, 0);
+       zll = &zd->zd_range_lock[zp->z_object & (ZTEST_OBJECT_LOCKS - 1)];
+       mutex_enter(&zll->z_lock);
+       refcount_remove(&zp->z_refcnt, RL_TAG);
+       if (refcount_is_zero(&zp->z_refcnt)) {
+               list_remove(&zll->z_list, zp);
+               ztest_znode_fini(zp);
+       }
+       mutex_exit(&zll->z_lock);
+}
+
+
+static void
+ztest_rll_init(rll_t *rll)
+{
+       rll->rll_writer = NULL;
+       rll->rll_readers = 0;
+       mutex_init(&rll->rll_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&rll->rll_cv, NULL, CV_DEFAULT, NULL);
+}
+
+static void
+ztest_rll_destroy(rll_t *rll)
+{
+       ASSERT(rll->rll_writer == NULL);
+       ASSERT(rll->rll_readers == 0);
+       mutex_destroy(&rll->rll_lock);
+       cv_destroy(&rll->rll_cv);
+}
+
+static void
+ztest_rll_lock(rll_t *rll, rl_type_t type)
+{
+       mutex_enter(&rll->rll_lock);
+
+       if (type == RL_READER) {
+               while (rll->rll_writer != NULL)
+                       (void) cv_wait(&rll->rll_cv, &rll->rll_lock);
+               rll->rll_readers++;
+       } else {
+               while (rll->rll_writer != NULL || rll->rll_readers)
+                       (void) cv_wait(&rll->rll_cv, &rll->rll_lock);
+               rll->rll_writer = curthread;
+       }
+
+       mutex_exit(&rll->rll_lock);
+}
+
+static void
+ztest_rll_unlock(rll_t *rll)
+{
+       mutex_enter(&rll->rll_lock);
+
+       if (rll->rll_writer) {
+               ASSERT(rll->rll_readers == 0);
+               rll->rll_writer = NULL;
+       } else {
+               ASSERT(rll->rll_readers != 0);
+               ASSERT(rll->rll_writer == NULL);
+               rll->rll_readers--;
+       }
+
+       if (rll->rll_writer == NULL && rll->rll_readers == 0)
+               cv_broadcast(&rll->rll_cv);
+
+       mutex_exit(&rll->rll_lock);
+}
+
+static void
+ztest_object_lock(ztest_ds_t *zd, uint64_t object, rl_type_t type)
+{
+       rll_t *rll = &zd->zd_object_lock[object & (ZTEST_OBJECT_LOCKS - 1)];
+
+       ztest_rll_lock(rll, type);
+}
+
+static void
+ztest_object_unlock(ztest_ds_t *zd, uint64_t object)
+{
+       rll_t *rll = &zd->zd_object_lock[object & (ZTEST_OBJECT_LOCKS - 1)];
+
+       ztest_rll_unlock(rll);
+}
+
+static ztest_zrl_t *
+ztest_zrl_init(rl_t *rl, ztest_znode_t *zp)
+{
+       ztest_zrl_t *zrl = umem_alloc(sizeof (*zrl), UMEM_NOFAIL);
+       zrl->z_rl = rl;
+       zrl->z_ztznode = zp;
+       return (zrl);
+}
+
+static void
+ztest_zrl_fini(ztest_zrl_t *zrl)
+{
+       umem_free(zrl, sizeof (*zrl));
+}
+
+static ztest_zrl_t *
+ztest_range_lock(ztest_ds_t *zd, uint64_t object, uint64_t offset,
+    uint64_t size, rl_type_t type)
+{
+       ztest_znode_t *zp = ztest_znode_get(zd, object);
+       rl_t *rl = zfs_range_lock(&zp->z_range_lock, offset,
+           size, type);
+       return (ztest_zrl_init(rl, zp));
+}
+
+static void
+ztest_range_unlock(ztest_ds_t *zd, ztest_zrl_t *zrl)
+{
+       zfs_range_unlock(zrl->z_rl);
+       ztest_znode_put(zd, zrl->z_ztznode);
+       ztest_zrl_fini(zrl);
+}
+
+static void
+ztest_zd_init(ztest_ds_t *zd, ztest_shared_ds_t *szd, objset_t *os)
+{
+       zd->zd_os = os;
+       zd->zd_zilog = dmu_objset_zil(os);
+       zd->zd_shared = szd;
+       dmu_objset_name(os, zd->zd_name);
+       int l;
+
+       if (zd->zd_shared != NULL)
+               zd->zd_shared->zd_seq = 0;
+
+       VERIFY(rwlock_init(&zd->zd_zilog_lock, USYNC_THREAD, NULL) == 0);
+       mutex_init(&zd->zd_dirobj_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       for (l = 0; l < ZTEST_OBJECT_LOCKS; l++)
+               ztest_rll_init(&zd->zd_object_lock[l]);
+
+       for (l = 0; l < ZTEST_RANGE_LOCKS; l++)
+               ztest_zll_init(&zd->zd_range_lock[l]);
+}
+
+static void
+ztest_zd_fini(ztest_ds_t *zd)
+{
+       int l;
+
+       mutex_destroy(&zd->zd_dirobj_lock);
+       (void) rwlock_destroy(&zd->zd_zilog_lock);
+
+       for (l = 0; l < ZTEST_OBJECT_LOCKS; l++)
+               ztest_rll_destroy(&zd->zd_object_lock[l]);
+
+       for (l = 0; l < ZTEST_RANGE_LOCKS; l++)
+               ztest_zll_destroy(&zd->zd_range_lock[l]);
+}
+
+#define        TXG_MIGHTWAIT   (ztest_random(10) == 0 ? TXG_NOWAIT : TXG_WAIT)
+
+static uint64_t
+ztest_tx_assign(dmu_tx_t *tx, uint64_t txg_how, const char *tag)
+{
+       uint64_t txg;
+       int error;
+
+       /*
+        * Attempt to assign tx to some transaction group.
+        */
+       error = dmu_tx_assign(tx, txg_how);
+       if (error) {
+               if (error == ERESTART) {
+                       ASSERT(txg_how == TXG_NOWAIT);
+                       dmu_tx_wait(tx);
+               } else {
+                       ASSERT3U(error, ==, ENOSPC);
+                       ztest_record_enospc(tag);
+               }
+               dmu_tx_abort(tx);
+               return (0);
+       }
+       txg = dmu_tx_get_txg(tx);
+       ASSERT(txg != 0);
+       return (txg);
+}
+
+static void
+ztest_pattern_set(void *buf, uint64_t size, uint64_t value)
+{
+       uint64_t *ip = buf;
+       uint64_t *ip_end = (uint64_t *)((uintptr_t)buf + (uintptr_t)size);
+
+       while (ip < ip_end)
+               *ip++ = value;
+}
+
+#ifndef NDEBUG
+static boolean_t
+ztest_pattern_match(void *buf, uint64_t size, uint64_t value)
+{
+       uint64_t *ip = buf;
+       uint64_t *ip_end = (uint64_t *)((uintptr_t)buf + (uintptr_t)size);
+       uint64_t diff = 0;
+
+       while (ip < ip_end)
+               diff |= (value - *ip++);
+
+       return (diff == 0);
+}
+#endif
+
+static void
+ztest_bt_generate(ztest_block_tag_t *bt, objset_t *os, uint64_t object,
+    uint64_t dnodesize, uint64_t offset, uint64_t gen, uint64_t txg,
+    uint64_t crtxg)
+{
+       bt->bt_magic = BT_MAGIC;
+       bt->bt_objset = dmu_objset_id(os);
+       bt->bt_object = object;
+       bt->bt_dnodesize = dnodesize;
+       bt->bt_offset = offset;
+       bt->bt_gen = gen;
+       bt->bt_txg = txg;
+       bt->bt_crtxg = crtxg;
+}
+
+static void
+ztest_bt_verify(ztest_block_tag_t *bt, objset_t *os, uint64_t object,
+    uint64_t dnodesize, uint64_t offset, uint64_t gen, uint64_t txg,
+    uint64_t crtxg)
+{
+       ASSERT3U(bt->bt_magic, ==, BT_MAGIC);
+       ASSERT3U(bt->bt_objset, ==, dmu_objset_id(os));
+       ASSERT3U(bt->bt_object, ==, object);
+       ASSERT3U(bt->bt_dnodesize, ==, dnodesize);
+       ASSERT3U(bt->bt_offset, ==, offset);
+       ASSERT3U(bt->bt_gen, <=, gen);
+       ASSERT3U(bt->bt_txg, <=, txg);
+       ASSERT3U(bt->bt_crtxg, ==, crtxg);
+}
+
+static ztest_block_tag_t *
+ztest_bt_bonus(dmu_buf_t *db)
+{
+       dmu_object_info_t doi;
+       ztest_block_tag_t *bt;
+
+       dmu_object_info_from_db(db, &doi);
+       ASSERT3U(doi.doi_bonus_size, <=, db->db_size);
+       ASSERT3U(doi.doi_bonus_size, >=, sizeof (*bt));
+       bt = (void *)((char *)db->db_data + doi.doi_bonus_size - sizeof (*bt));
+
+       return (bt);
+}
+
+/*
+ * Generate a token to fill up unused bonus buffer space.  Try to make
+ * it unique to the object, generation, and offset to verify that data
+ * is not getting overwritten by data from other dnodes.
+ */
+#define        ZTEST_BONUS_FILL_TOKEN(obj, ds, gen, offset) \
+       (((ds) << 48) | ((gen) << 32) | ((obj) << 8) | (offset))
+
+/*
+ * Fill up the unused bonus buffer region before the block tag with a
+ * verifiable pattern. Filling the whole bonus area with non-zero data
+ * helps ensure that all dnode traversal code properly skips the
+ * interior regions of large dnodes.
+ */
+void
+ztest_fill_unused_bonus(dmu_buf_t *db, void *end, uint64_t obj,
+    objset_t *os, uint64_t gen)
+{
+       uint64_t *bonusp;
+
+       ASSERT(IS_P2ALIGNED((char *)end - (char *)db->db_data, 8));
+
+       for (bonusp = db->db_data; bonusp < (uint64_t *)end; bonusp++) {
+               uint64_t token = ZTEST_BONUS_FILL_TOKEN(obj, dmu_objset_id(os),
+                   gen, bonusp - (uint64_t *)db->db_data);
+               *bonusp = token;
+       }
+}
+
+/*
+ * Verify that the unused area of a bonus buffer is filled with the
+ * expected tokens.
+ */
+void
+ztest_verify_unused_bonus(dmu_buf_t *db, void *end, uint64_t obj,
+    objset_t *os, uint64_t gen)
+{
+       uint64_t *bonusp;
+
+       for (bonusp = db->db_data; bonusp < (uint64_t *)end; bonusp++) {
+               uint64_t token = ZTEST_BONUS_FILL_TOKEN(obj, dmu_objset_id(os),
+                   gen, bonusp - (uint64_t *)db->db_data);
+               VERIFY3U(*bonusp, ==, token);
+       }
+}
+
+/*
+ * ZIL logging ops
+ */
+
+#define        lrz_type        lr_mode
+#define        lrz_blocksize   lr_uid
+#define        lrz_ibshift     lr_gid
+#define        lrz_bonustype   lr_rdev
+#define        lrz_dnodesize   lr_crtime[1]
+
+static void
+ztest_log_create(ztest_ds_t *zd, dmu_tx_t *tx, lr_create_t *lr)
+{
+       char *name = (void *)(lr + 1);          /* name follows lr */
+       size_t namesize = strlen(name) + 1;
+       itx_t *itx;
+
+       if (zil_replaying(zd->zd_zilog, tx))
+               return;
+
+       itx = zil_itx_create(TX_CREATE, sizeof (*lr) + namesize);
+       bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+           sizeof (*lr) + namesize - sizeof (lr_t));
+
+       zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+static void
+ztest_log_remove(ztest_ds_t *zd, dmu_tx_t *tx, lr_remove_t *lr, uint64_t object)
+{
+       char *name = (void *)(lr + 1);          /* name follows lr */
+       size_t namesize = strlen(name) + 1;
+       itx_t *itx;
+
+       if (zil_replaying(zd->zd_zilog, tx))
+               return;
+
+       itx = zil_itx_create(TX_REMOVE, sizeof (*lr) + namesize);
+       bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+           sizeof (*lr) + namesize - sizeof (lr_t));
+
+       itx->itx_oid = object;
+       zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+static void
+ztest_log_write(ztest_ds_t *zd, dmu_tx_t *tx, lr_write_t *lr)
+{
+       itx_t *itx;
+       itx_wr_state_t write_state = ztest_random(WR_NUM_STATES);
+
+       if (zil_replaying(zd->zd_zilog, tx))
+               return;
+
+       if (lr->lr_length > ZIL_MAX_LOG_DATA)
+               write_state = WR_INDIRECT;
+
+       itx = zil_itx_create(TX_WRITE,
+           sizeof (*lr) + (write_state == WR_COPIED ? lr->lr_length : 0));
+
+       if (write_state == WR_COPIED &&
+           dmu_read(zd->zd_os, lr->lr_foid, lr->lr_offset, lr->lr_length,
+           ((lr_write_t *)&itx->itx_lr) + 1, DMU_READ_NO_PREFETCH) != 0) {
+               zil_itx_destroy(itx);
+               itx = zil_itx_create(TX_WRITE, sizeof (*lr));
+               write_state = WR_NEED_COPY;
+       }
+       itx->itx_private = zd;
+       itx->itx_wr_state = write_state;
+       itx->itx_sync = (ztest_random(8) == 0);
+       itx->itx_sod += (write_state == WR_NEED_COPY ? lr->lr_length : 0);
+
+       bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+           sizeof (*lr) - sizeof (lr_t));
+
+       zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+static void
+ztest_log_truncate(ztest_ds_t *zd, dmu_tx_t *tx, lr_truncate_t *lr)
+{
+       itx_t *itx;
+
+       if (zil_replaying(zd->zd_zilog, tx))
+               return;
+
+       itx = zil_itx_create(TX_TRUNCATE, sizeof (*lr));
+       bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+           sizeof (*lr) - sizeof (lr_t));
+
+       itx->itx_sync = B_FALSE;
+       zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+static void
+ztest_log_setattr(ztest_ds_t *zd, dmu_tx_t *tx, lr_setattr_t *lr)
+{
+       itx_t *itx;
+
+       if (zil_replaying(zd->zd_zilog, tx))
+               return;
+
+       itx = zil_itx_create(TX_SETATTR, sizeof (*lr));
+       bcopy(&lr->lr_common + 1, &itx->itx_lr + 1,
+           sizeof (*lr) - sizeof (lr_t));
+
+       itx->itx_sync = B_FALSE;
+       zil_itx_assign(zd->zd_zilog, itx, tx);
+}
+
+/*
+ * ZIL replay ops
+ */
+static int
+ztest_replay_create(ztest_ds_t *zd, lr_create_t *lr, boolean_t byteswap)
+{
+       char *name = (void *)(lr + 1);          /* name follows lr */
+       objset_t *os = zd->zd_os;
+       ztest_block_tag_t *bbt;
+       dmu_buf_t *db;
+       dmu_tx_t *tx;
+       uint64_t txg;
+       int error = 0;
+       int bonuslen;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       ASSERT(lr->lr_doid == ZTEST_DIROBJ);
+       ASSERT(name[0] != '\0');
+
+       tx = dmu_tx_create(os);
+
+       dmu_tx_hold_zap(tx, lr->lr_doid, B_TRUE, name);
+
+       if (lr->lrz_type == DMU_OT_ZAP_OTHER) {
+               dmu_tx_hold_zap(tx, DMU_NEW_OBJECT, B_TRUE, NULL);
+       } else {
+               dmu_tx_hold_bonus(tx, DMU_NEW_OBJECT);
+       }
+
+       txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+       if (txg == 0)
+               return (ENOSPC);
+
+       ASSERT(dmu_objset_zil(os)->zl_replay == !!lr->lr_foid);
+       bonuslen = DN_BONUS_SIZE(lr->lrz_dnodesize);
+
+       if (lr->lrz_type == DMU_OT_ZAP_OTHER) {
+               if (lr->lr_foid == 0) {
+                       lr->lr_foid = zap_create_dnsize(os,
+                           lr->lrz_type, lr->lrz_bonustype,
+                           bonuslen, lr->lrz_dnodesize, tx);
+               } else {
+                       error = zap_create_claim_dnsize(os, lr->lr_foid,
+                           lr->lrz_type, lr->lrz_bonustype,
+                           bonuslen, lr->lrz_dnodesize, tx);
+               }
+       } else {
+               if (lr->lr_foid == 0) {
+                       lr->lr_foid = dmu_object_alloc_dnsize(os,
+                           lr->lrz_type, 0, lr->lrz_bonustype,
+                           bonuslen, lr->lrz_dnodesize, tx);
+               } else {
+                       error = dmu_object_claim_dnsize(os, lr->lr_foid,
+                           lr->lrz_type, 0, lr->lrz_bonustype,
+                           bonuslen, lr->lrz_dnodesize, tx);
+               }
+       }
+
+       if (error) {
+               ASSERT3U(error, ==, EEXIST);
+               ASSERT(zd->zd_zilog->zl_replay);
+               dmu_tx_commit(tx);
+               return (error);
+       }
+
+       ASSERT(lr->lr_foid != 0);
+
+       if (lr->lrz_type != DMU_OT_ZAP_OTHER)
+               VERIFY3U(0, ==, dmu_object_set_blocksize(os, lr->lr_foid,
+                   lr->lrz_blocksize, lr->lrz_ibshift, tx));
+
+       VERIFY3U(0, ==, dmu_bonus_hold(os, lr->lr_foid, FTAG, &db));
+       bbt = ztest_bt_bonus(db);
+       dmu_buf_will_dirty(db, tx);
+       ztest_bt_generate(bbt, os, lr->lr_foid, lr->lrz_dnodesize, -1ULL,
+           lr->lr_gen, txg, txg);
+       ztest_fill_unused_bonus(db, bbt, lr->lr_foid, os, lr->lr_gen);
+       dmu_buf_rele(db, FTAG);
+
+       VERIFY3U(0, ==, zap_add(os, lr->lr_doid, name, sizeof (uint64_t), 1,
+           &lr->lr_foid, tx));
+
+       (void) ztest_log_create(zd, tx, lr);
+
+       dmu_tx_commit(tx);
+
+       return (0);
+}
+
+static int
+ztest_replay_remove(ztest_ds_t *zd, lr_remove_t *lr, boolean_t byteswap)
+{
+       char *name = (void *)(lr + 1);          /* name follows lr */
+       objset_t *os = zd->zd_os;
+       dmu_object_info_t doi;
+       dmu_tx_t *tx;
+       uint64_t object, txg;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       ASSERT(lr->lr_doid == ZTEST_DIROBJ);
+       ASSERT(name[0] != '\0');
+
+       VERIFY3U(0, ==,
+           zap_lookup(os, lr->lr_doid, name, sizeof (object), 1, &object));
+       ASSERT(object != 0);
+
+       ztest_object_lock(zd, object, RL_WRITER);
+
+       VERIFY3U(0, ==, dmu_object_info(os, object, &doi));
+
+       tx = dmu_tx_create(os);
+
+       dmu_tx_hold_zap(tx, lr->lr_doid, B_FALSE, name);
+       dmu_tx_hold_free(tx, object, 0, DMU_OBJECT_END);
+
+       txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+       if (txg == 0) {
+               ztest_object_unlock(zd, object);
+               return (ENOSPC);
+       }
+
+       if (doi.doi_type == DMU_OT_ZAP_OTHER) {
+               VERIFY3U(0, ==, zap_destroy(os, object, tx));
+       } else {
+               VERIFY3U(0, ==, dmu_object_free(os, object, tx));
+       }
+
+       VERIFY3U(0, ==, zap_remove(os, lr->lr_doid, name, tx));
+
+       (void) ztest_log_remove(zd, tx, lr, object);
+
+       dmu_tx_commit(tx);
+
+       ztest_object_unlock(zd, object);
+
+       return (0);
+}
+
+static int
+ztest_replay_write(ztest_ds_t *zd, lr_write_t *lr, boolean_t byteswap)
+{
+       objset_t *os = zd->zd_os;
+       void *data = lr + 1;                    /* data follows lr */
+       uint64_t offset, length;
+       ztest_block_tag_t *bt = data;
+       ztest_block_tag_t *bbt;
+       uint64_t gen, txg, lrtxg, crtxg;
+       dmu_object_info_t doi;
+       dmu_tx_t *tx;
+       dmu_buf_t *db;
+       arc_buf_t *abuf = NULL;
+       ztest_zrl_t *rl;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       offset = lr->lr_offset;
+       length = lr->lr_length;
+
+       /* If it's a dmu_sync() block, write the whole block */
+       if (lr->lr_common.lrc_reclen == sizeof (lr_write_t)) {
+               uint64_t blocksize = BP_GET_LSIZE(&lr->lr_blkptr);
+               if (length < blocksize) {
+                       offset -= offset % blocksize;
+                       length = blocksize;
+               }
+       }
+
+       if (bt->bt_magic == BSWAP_64(BT_MAGIC))
+               byteswap_uint64_array(bt, sizeof (*bt));
+
+       if (bt->bt_magic != BT_MAGIC)
+               bt = NULL;
+
+       ztest_object_lock(zd, lr->lr_foid, RL_READER);
+       rl = ztest_range_lock(zd, lr->lr_foid, offset, length, RL_WRITER);
+
+       VERIFY3U(0, ==, dmu_bonus_hold(os, lr->lr_foid, FTAG, &db));
+
+       dmu_object_info_from_db(db, &doi);
+
+       bbt = ztest_bt_bonus(db);
+       ASSERT3U(bbt->bt_magic, ==, BT_MAGIC);
+       gen = bbt->bt_gen;
+       crtxg = bbt->bt_crtxg;
+       lrtxg = lr->lr_common.lrc_txg;
+
+       tx = dmu_tx_create(os);
+
+       dmu_tx_hold_write(tx, lr->lr_foid, offset, length);
+
+       if (ztest_random(8) == 0 && length == doi.doi_data_block_size &&
+           P2PHASE(offset, length) == 0)
+               abuf = dmu_request_arcbuf(db, length);
+
+       txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+       if (txg == 0) {
+               if (abuf != NULL)
+                       dmu_return_arcbuf(abuf);
+               dmu_buf_rele(db, FTAG);
+               ztest_range_unlock(zd, rl);
+               ztest_object_unlock(zd, lr->lr_foid);
+               return (ENOSPC);
+       }
+
+       if (bt != NULL) {
+               /*
+                * Usually, verify the old data before writing new data --
+                * but not always, because we also want to verify correct
+                * behavior when the data was not recently read into cache.
+                */
+               ASSERT(offset % doi.doi_data_block_size == 0);
+               if (ztest_random(4) != 0) {
+                       int prefetch = ztest_random(2) ?
+                           DMU_READ_PREFETCH : DMU_READ_NO_PREFETCH;
+                       ztest_block_tag_t rbt;
+
+                       VERIFY(dmu_read(os, lr->lr_foid, offset,
+                           sizeof (rbt), &rbt, prefetch) == 0);
+                       if (rbt.bt_magic == BT_MAGIC) {
+                               ztest_bt_verify(&rbt, os, lr->lr_foid, 0,
+                                   offset, gen, txg, crtxg);
+                       }
+               }
+
+               /*
+                * Writes can appear to be newer than the bonus buffer because
+                * the ztest_get_data() callback does a dmu_read() of the
+                * open-context data, which may be different than the data
+                * as it was when the write was generated.
+                */
+               if (zd->zd_zilog->zl_replay) {
+                       ztest_bt_verify(bt, os, lr->lr_foid, 0, offset,
+                           MAX(gen, bt->bt_gen), MAX(txg, lrtxg),
+                           bt->bt_crtxg);
+               }
+
+               /*
+                * Set the bt's gen/txg to the bonus buffer's gen/txg
+                * so that all of the usual ASSERTs will work.
+                */
+               ztest_bt_generate(bt, os, lr->lr_foid, 0, offset, gen, txg,
+                   crtxg);
+       }
+
+       if (abuf == NULL) {
+               dmu_write(os, lr->lr_foid, offset, length, data, tx);
+       } else {
+               bcopy(data, abuf->b_data, length);
+               dmu_assign_arcbuf(db, offset, abuf, tx);
+       }
+
+       (void) ztest_log_write(zd, tx, lr);
+
+       dmu_buf_rele(db, FTAG);
+
+       dmu_tx_commit(tx);
+
+       ztest_range_unlock(zd, rl);
+       ztest_object_unlock(zd, lr->lr_foid);
+
+       return (0);
+}
+
+static int
+ztest_replay_truncate(ztest_ds_t *zd, lr_truncate_t *lr, boolean_t byteswap)
+{
+       objset_t *os = zd->zd_os;
+       dmu_tx_t *tx;
+       uint64_t txg;
+       ztest_zrl_t *rl;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       ztest_object_lock(zd, lr->lr_foid, RL_READER);
+       rl = ztest_range_lock(zd, lr->lr_foid, lr->lr_offset, lr->lr_length,
+           RL_WRITER);
+
+       tx = dmu_tx_create(os);
+
+       dmu_tx_hold_free(tx, lr->lr_foid, lr->lr_offset, lr->lr_length);
+
+       txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+       if (txg == 0) {
+               ztest_range_unlock(zd, rl);
+               ztest_object_unlock(zd, lr->lr_foid);
+               return (ENOSPC);
+       }
+
+       VERIFY(dmu_free_range(os, lr->lr_foid, lr->lr_offset,
+           lr->lr_length, tx) == 0);
+
+       (void) ztest_log_truncate(zd, tx, lr);
+
+       dmu_tx_commit(tx);
+
+       ztest_range_unlock(zd, rl);
+       ztest_object_unlock(zd, lr->lr_foid);
+
+       return (0);
+}
+
+static int
+ztest_replay_setattr(ztest_ds_t *zd, lr_setattr_t *lr, boolean_t byteswap)
+{
+       objset_t *os = zd->zd_os;
+       dmu_tx_t *tx;
+       dmu_buf_t *db;
+       ztest_block_tag_t *bbt;
+       uint64_t txg, lrtxg, crtxg, dnodesize;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       ztest_object_lock(zd, lr->lr_foid, RL_WRITER);
+
+       VERIFY3U(0, ==, dmu_bonus_hold(os, lr->lr_foid, FTAG, &db));
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_bonus(tx, lr->lr_foid);
+
+       txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+       if (txg == 0) {
+               dmu_buf_rele(db, FTAG);
+               ztest_object_unlock(zd, lr->lr_foid);
+               return (ENOSPC);
+       }
+
+       bbt = ztest_bt_bonus(db);
+       ASSERT3U(bbt->bt_magic, ==, BT_MAGIC);
+       crtxg = bbt->bt_crtxg;
+       lrtxg = lr->lr_common.lrc_txg;
+       dnodesize = bbt->bt_dnodesize;
+
+       if (zd->zd_zilog->zl_replay) {
+               ASSERT(lr->lr_size != 0);
+               ASSERT(lr->lr_mode != 0);
+               ASSERT(lrtxg != 0);
+       } else {
+               /*
+                * Randomly change the size and increment the generation.
+                */
+               lr->lr_size = (ztest_random(db->db_size / sizeof (*bbt)) + 1) *
+                   sizeof (*bbt);
+               lr->lr_mode = bbt->bt_gen + 1;
+               ASSERT(lrtxg == 0);
+       }
+
+       /*
+        * Verify that the current bonus buffer is not newer than our txg.
+        */
+       ztest_bt_verify(bbt, os, lr->lr_foid, dnodesize, -1ULL, lr->lr_mode,
+           MAX(txg, lrtxg), crtxg);
+
+       dmu_buf_will_dirty(db, tx);
+
+       ASSERT3U(lr->lr_size, >=, sizeof (*bbt));
+       ASSERT3U(lr->lr_size, <=, db->db_size);
+       VERIFY0(dmu_set_bonus(db, lr->lr_size, tx));
+       bbt = ztest_bt_bonus(db);
+
+       ztest_bt_generate(bbt, os, lr->lr_foid, dnodesize, -1ULL, lr->lr_mode,
+           txg, crtxg);
+       ztest_fill_unused_bonus(db, bbt, lr->lr_foid, os, bbt->bt_gen);
+       dmu_buf_rele(db, FTAG);
+
+       (void) ztest_log_setattr(zd, tx, lr);
+
+       dmu_tx_commit(tx);
+
+       ztest_object_unlock(zd, lr->lr_foid);
+
+       return (0);
+}
+
+zil_replay_func_t ztest_replay_vector[TX_MAX_TYPE] = {
+       NULL,                           /* 0 no such transaction type */
+       (zil_replay_func_t)ztest_replay_create,         /* TX_CREATE */
+       NULL,                                           /* TX_MKDIR */
+       NULL,                                           /* TX_MKXATTR */
+       NULL,                                           /* TX_SYMLINK */
+       (zil_replay_func_t)ztest_replay_remove,         /* TX_REMOVE */
+       NULL,                                           /* TX_RMDIR */
+       NULL,                                           /* TX_LINK */
+       NULL,                                           /* TX_RENAME */
+       (zil_replay_func_t)ztest_replay_write,          /* TX_WRITE */
+       (zil_replay_func_t)ztest_replay_truncate,       /* TX_TRUNCATE */
+       (zil_replay_func_t)ztest_replay_setattr,        /* TX_SETATTR */
+       NULL,                                           /* TX_ACL */
+       NULL,                                           /* TX_CREATE_ACL */
+       NULL,                                           /* TX_CREATE_ATTR */
+       NULL,                                           /* TX_CREATE_ACL_ATTR */
+       NULL,                                           /* TX_MKDIR_ACL */
+       NULL,                                           /* TX_MKDIR_ATTR */
+       NULL,                                           /* TX_MKDIR_ACL_ATTR */
+       NULL,                                           /* TX_WRITE2 */
+};
+
+/*
+ * ZIL get_data callbacks
+ */
+typedef struct ztest_zgd_private {
+       ztest_ds_t *z_zd;
+       ztest_zrl_t *z_rl;
+       uint64_t z_object;
+} ztest_zgd_private_t;
+
+static void
+ztest_get_done(zgd_t *zgd, int error)
+{
+       ztest_zgd_private_t *zzp = zgd->zgd_private;
+       ztest_ds_t *zd = zzp->z_zd;
+       uint64_t object = zzp->z_object;
+
+       if (zgd->zgd_db)
+               dmu_buf_rele(zgd->zgd_db, zgd);
+
+       ztest_range_unlock(zd, zzp->z_rl);
+       ztest_object_unlock(zd, object);
+
+       if (error == 0 && zgd->zgd_bp)
+               zil_add_block(zgd->zgd_zilog, zgd->zgd_bp);
+
+       umem_free(zgd, sizeof (*zgd));
+       umem_free(zzp, sizeof (*zzp));
+}
+
+static int
+ztest_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
+{
+       ztest_ds_t *zd = arg;
+       objset_t *os = zd->zd_os;
+       uint64_t object = lr->lr_foid;
+       uint64_t offset = lr->lr_offset;
+       uint64_t size = lr->lr_length;
+       blkptr_t *bp = &lr->lr_blkptr;
+       uint64_t txg = lr->lr_common.lrc_txg;
+       uint64_t crtxg;
+       dmu_object_info_t doi;
+       dmu_buf_t *db;
+       zgd_t *zgd;
+       int error;
+       ztest_zgd_private_t *zgd_private;
+
+       ztest_object_lock(zd, object, RL_READER);
+       error = dmu_bonus_hold(os, object, FTAG, &db);
+       if (error) {
+               ztest_object_unlock(zd, object);
+               return (error);
+       }
+
+       crtxg = ztest_bt_bonus(db)->bt_crtxg;
+
+       if (crtxg == 0 || crtxg > txg) {
+               dmu_buf_rele(db, FTAG);
+               ztest_object_unlock(zd, object);
+               return (ENOENT);
+       }
+
+       dmu_object_info_from_db(db, &doi);
+       dmu_buf_rele(db, FTAG);
+       db = NULL;
+
+       zgd = umem_zalloc(sizeof (*zgd), UMEM_NOFAIL);
+       zgd->zgd_zilog = zd->zd_zilog;
+       zgd_private = umem_zalloc(sizeof (ztest_zgd_private_t), UMEM_NOFAIL);
+       zgd_private->z_zd = zd;
+       zgd_private->z_object = object;
+       zgd->zgd_private = zgd_private;
+
+       if (buf != NULL) {      /* immediate write */
+               zgd_private->z_rl = ztest_range_lock(zd, object, offset, size,
+                   RL_READER);
+
+               error = dmu_read(os, object, offset, size, buf,
+                   DMU_READ_NO_PREFETCH);
+               ASSERT(error == 0);
+       } else {
+               size = doi.doi_data_block_size;
+               if (ISP2(size)) {
+                       offset = P2ALIGN(offset, size);
+               } else {
+                       ASSERT(offset < size);
+                       offset = 0;
+               }
+
+               zgd_private->z_rl = ztest_range_lock(zd, object, offset, size,
+                   RL_READER);
+
+               error = dmu_buf_hold(os, object, offset, zgd, &db,
+                   DMU_READ_NO_PREFETCH);
+
+               if (error == 0) {
+                       blkptr_t *obp = dmu_buf_get_blkptr(db);
+                       if (obp) {
+                               ASSERT(BP_IS_HOLE(bp));
+                               *bp = *obp;
+                       }
+
+                       zgd->zgd_db = db;
+                       zgd->zgd_bp = bp;
+
+                       ASSERT(db->db_offset == offset);
+                       ASSERT(db->db_size == size);
+
+                       error = dmu_sync(zio, lr->lr_common.lrc_txg,
+                           ztest_get_done, zgd);
+
+                       if (error == 0)
+                               return (0);
+               }
+       }
+
+       ztest_get_done(zgd, error);
+
+       return (error);
+}
+
+static void *
+ztest_lr_alloc(size_t lrsize, char *name)
+{
+       char *lr;
+       size_t namesize = name ? strlen(name) + 1 : 0;
+
+       lr = umem_zalloc(lrsize + namesize, UMEM_NOFAIL);
+
+       if (name)
+               bcopy(name, lr + lrsize, namesize);
+
+       return (lr);
+}
+
+void
+ztest_lr_free(void *lr, size_t lrsize, char *name)
+{
+       size_t namesize = name ? strlen(name) + 1 : 0;
+
+       umem_free(lr, lrsize + namesize);
+}
+
+/*
+ * Lookup a bunch of objects.  Returns the number of objects not found.
+ */
+static int
+ztest_lookup(ztest_ds_t *zd, ztest_od_t *od, int count)
+{
+       int missing = 0;
+       int error;
+       int i;
+
+       ASSERT(mutex_held(&zd->zd_dirobj_lock));
+
+       for (i = 0; i < count; i++, od++) {
+               od->od_object = 0;
+               error = zap_lookup(zd->zd_os, od->od_dir, od->od_name,
+                   sizeof (uint64_t), 1, &od->od_object);
+               if (error) {
+                       ASSERT(error == ENOENT);
+                       ASSERT(od->od_object == 0);
+                       missing++;
+               } else {
+                       dmu_buf_t *db;
+                       ztest_block_tag_t *bbt;
+                       dmu_object_info_t doi;
+
+                       ASSERT(od->od_object != 0);
+                       ASSERT(missing == 0);   /* there should be no gaps */
+
+                       ztest_object_lock(zd, od->od_object, RL_READER);
+                       VERIFY3U(0, ==, dmu_bonus_hold(zd->zd_os,
+                           od->od_object, FTAG, &db));
+                       dmu_object_info_from_db(db, &doi);
+                       bbt = ztest_bt_bonus(db);
+                       ASSERT3U(bbt->bt_magic, ==, BT_MAGIC);
+                       od->od_type = doi.doi_type;
+                       od->od_blocksize = doi.doi_data_block_size;
+                       od->od_gen = bbt->bt_gen;
+                       dmu_buf_rele(db, FTAG);
+                       ztest_object_unlock(zd, od->od_object);
+               }
+       }
+
+       return (missing);
+}
+
+static int
+ztest_create(ztest_ds_t *zd, ztest_od_t *od, int count)
+{
+       int missing = 0;
+       int i;
+
+       ASSERT(mutex_held(&zd->zd_dirobj_lock));
+
+       for (i = 0; i < count; i++, od++) {
+               if (missing) {
+                       od->od_object = 0;
+                       missing++;
+                       continue;
+               }
+
+               lr_create_t *lr = ztest_lr_alloc(sizeof (*lr), od->od_name);
+
+               lr->lr_doid = od->od_dir;
+               lr->lr_foid = 0;        /* 0 to allocate, > 0 to claim */
+               lr->lrz_type = od->od_crtype;
+               lr->lrz_blocksize = od->od_crblocksize;
+               lr->lrz_ibshift = ztest_random_ibshift();
+               lr->lrz_bonustype = DMU_OT_UINT64_OTHER;
+               lr->lrz_dnodesize = od->od_crdnodesize;
+               lr->lr_gen = od->od_crgen;
+               lr->lr_crtime[0] = time(NULL);
+
+               if (ztest_replay_create(zd, lr, B_FALSE) != 0) {
+                       ASSERT(missing == 0);
+                       od->od_object = 0;
+                       missing++;
+               } else {
+                       od->od_object = lr->lr_foid;
+                       od->od_type = od->od_crtype;
+                       od->od_blocksize = od->od_crblocksize;
+                       od->od_gen = od->od_crgen;
+                       ASSERT(od->od_object != 0);
+               }
+
+               ztest_lr_free(lr, sizeof (*lr), od->od_name);
+       }
+
+       return (missing);
+}
+
+static int
+ztest_remove(ztest_ds_t *zd, ztest_od_t *od, int count)
+{
+       int missing = 0;
+       int error;
+       int i;
+
+       ASSERT(mutex_held(&zd->zd_dirobj_lock));
+
+       od += count - 1;
+
+       for (i = count - 1; i >= 0; i--, od--) {
+               if (missing) {
+                       missing++;
+                       continue;
+               }
+
+               /*
+                * No object was found.
+                */
+               if (od->od_object == 0)
+                       continue;
+
+               lr_remove_t *lr = ztest_lr_alloc(sizeof (*lr), od->od_name);
+
+               lr->lr_doid = od->od_dir;
+
+               if ((error = ztest_replay_remove(zd, lr, B_FALSE)) != 0) {
+                       ASSERT3U(error, ==, ENOSPC);
+                       missing++;
+               } else {
+                       od->od_object = 0;
+               }
+               ztest_lr_free(lr, sizeof (*lr), od->od_name);
+       }
+
+       return (missing);
+}
+
+static int
+ztest_write(ztest_ds_t *zd, uint64_t object, uint64_t offset, uint64_t size,
+    void *data)
+{
+       lr_write_t *lr;
+       int error;
+
+       lr = ztest_lr_alloc(sizeof (*lr) + size, NULL);
+
+       lr->lr_foid = object;
+       lr->lr_offset = offset;
+       lr->lr_length = size;
+       lr->lr_blkoff = 0;
+       BP_ZERO(&lr->lr_blkptr);
+
+       bcopy(data, lr + 1, size);
+
+       error = ztest_replay_write(zd, lr, B_FALSE);
+
+       ztest_lr_free(lr, sizeof (*lr) + size, NULL);
+
+       return (error);
+}
+
+static int
+ztest_truncate(ztest_ds_t *zd, uint64_t object, uint64_t offset, uint64_t size)
+{
+       lr_truncate_t *lr;
+       int error;
+
+       lr = ztest_lr_alloc(sizeof (*lr), NULL);
+
+       lr->lr_foid = object;
+       lr->lr_offset = offset;
+       lr->lr_length = size;
+
+       error = ztest_replay_truncate(zd, lr, B_FALSE);
+
+       ztest_lr_free(lr, sizeof (*lr), NULL);
+
+       return (error);
+}
+
+static int
+ztest_setattr(ztest_ds_t *zd, uint64_t object)
+{
+       lr_setattr_t *lr;
+       int error;
+
+       lr = ztest_lr_alloc(sizeof (*lr), NULL);
+
+       lr->lr_foid = object;
+       lr->lr_size = 0;
+       lr->lr_mode = 0;
+
+       error = ztest_replay_setattr(zd, lr, B_FALSE);
+
+       ztest_lr_free(lr, sizeof (*lr), NULL);
+
+       return (error);
+}
+
+static void
+ztest_prealloc(ztest_ds_t *zd, uint64_t object, uint64_t offset, uint64_t size)
+{
+       objset_t *os = zd->zd_os;
+       dmu_tx_t *tx;
+       uint64_t txg;
+       ztest_zrl_t *rl;
+
+       txg_wait_synced(dmu_objset_pool(os), 0);
+
+       ztest_object_lock(zd, object, RL_READER);
+       rl = ztest_range_lock(zd, object, offset, size, RL_WRITER);
+
+       tx = dmu_tx_create(os);
+
+       dmu_tx_hold_write(tx, object, offset, size);
+
+       txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+
+       if (txg != 0) {
+               dmu_prealloc(os, object, offset, size, tx);
+               dmu_tx_commit(tx);
+               txg_wait_synced(dmu_objset_pool(os), txg);
+       } else {
+               (void) dmu_free_long_range(os, object, offset, size);
+       }
+
+       ztest_range_unlock(zd, rl);
+       ztest_object_unlock(zd, object);
+}
+
+static void
+ztest_io(ztest_ds_t *zd, uint64_t object, uint64_t offset)
+{
+       int err;
+       ztest_block_tag_t wbt;
+       dmu_object_info_t doi;
+       enum ztest_io_type io_type;
+       uint64_t blocksize;
+       void *data;
+
+       VERIFY(dmu_object_info(zd->zd_os, object, &doi) == 0);
+       blocksize = doi.doi_data_block_size;
+       data = umem_alloc(blocksize, UMEM_NOFAIL);
+
+       /*
+        * Pick an i/o type at random, biased toward writing block tags.
+        */
+       io_type = ztest_random(ZTEST_IO_TYPES);
+       if (ztest_random(2) == 0)
+               io_type = ZTEST_IO_WRITE_TAG;
+
+       (void) rw_rdlock(&zd->zd_zilog_lock);
+
+       switch (io_type) {
+
+       case ZTEST_IO_WRITE_TAG:
+               ztest_bt_generate(&wbt, zd->zd_os, object, doi.doi_dnodesize,
+                   offset, 0, 0, 0);
+               (void) ztest_write(zd, object, offset, sizeof (wbt), &wbt);
+               break;
+
+       case ZTEST_IO_WRITE_PATTERN:
+               (void) memset(data, 'a' + (object + offset) % 5, blocksize);
+               if (ztest_random(2) == 0) {
+                       /*
+                        * Induce fletcher2 collisions to ensure that
+                        * zio_ddt_collision() detects and resolves them
+                        * when using fletcher2-verify for deduplication.
+                        */
+                       ((uint64_t *)data)[0] ^= 1ULL << 63;
+                       ((uint64_t *)data)[4] ^= 1ULL << 63;
+               }
+               (void) ztest_write(zd, object, offset, blocksize, data);
+               break;
+
+       case ZTEST_IO_WRITE_ZEROES:
+               bzero(data, blocksize);
+               (void) ztest_write(zd, object, offset, blocksize, data);
+               break;
+
+       case ZTEST_IO_TRUNCATE:
+               (void) ztest_truncate(zd, object, offset, blocksize);
+               break;
+
+       case ZTEST_IO_SETATTR:
+               (void) ztest_setattr(zd, object);
+               break;
+       default:
+               break;
+
+       case ZTEST_IO_REWRITE:
+               (void) rw_rdlock(&ztest_name_lock);
+               err = ztest_dsl_prop_set_uint64(zd->zd_name,
+                   ZFS_PROP_CHECKSUM, spa_dedup_checksum(ztest_spa),
+                   B_FALSE);
+               VERIFY(err == 0 || err == ENOSPC);
+               err = ztest_dsl_prop_set_uint64(zd->zd_name,
+                   ZFS_PROP_COMPRESSION,
+                   ztest_random_dsl_prop(ZFS_PROP_COMPRESSION),
+                   B_FALSE);
+               VERIFY(err == 0 || err == ENOSPC);
+               (void) rw_unlock(&ztest_name_lock);
+
+               VERIFY0(dmu_read(zd->zd_os, object, offset, blocksize, data,
+                   DMU_READ_NO_PREFETCH));
+
+               (void) ztest_write(zd, object, offset, blocksize, data);
+               break;
+       }
+
+       (void) rw_unlock(&zd->zd_zilog_lock);
+
+       umem_free(data, blocksize);
+}
+
+/*
+ * Initialize an object description template.
+ */
+static void
+ztest_od_init(ztest_od_t *od, uint64_t id, char *tag, uint64_t index,
+    dmu_object_type_t type, uint64_t blocksize, uint64_t dnodesize,
+    uint64_t gen)
+{
+       od->od_dir = ZTEST_DIROBJ;
+       od->od_object = 0;
+
+       od->od_crtype = type;
+       od->od_crblocksize = blocksize ? blocksize : ztest_random_blocksize();
+       od->od_crdnodesize = dnodesize ? dnodesize : ztest_random_dnodesize();
+       od->od_crgen = gen;
+
+       od->od_type = DMU_OT_NONE;
+       od->od_blocksize = 0;
+       od->od_gen = 0;
+
+       (void) snprintf(od->od_name, sizeof (od->od_name), "%s(%lld)[%llu]",
+           tag, (longlong_t)id, (u_longlong_t)index);
+}
+
+/*
+ * Lookup or create the objects for a test using the od template.
+ * If the objects do not all exist, or if 'remove' is specified,
+ * remove any existing objects and create new ones.  Otherwise,
+ * use the existing objects.
+ */
+static int
+ztest_object_init(ztest_ds_t *zd, ztest_od_t *od, size_t size, boolean_t remove)
+{
+       int count = size / sizeof (*od);
+       int rv = 0;
+
+       mutex_enter(&zd->zd_dirobj_lock);
+       if ((ztest_lookup(zd, od, count) != 0 || remove) &&
+           (ztest_remove(zd, od, count) != 0 ||
+           ztest_create(zd, od, count) != 0))
+               rv = -1;
+       zd->zd_od = od;
+       mutex_exit(&zd->zd_dirobj_lock);
+
+       return (rv);
+}
+
+/* ARGSUSED */
+void
+ztest_zil_commit(ztest_ds_t *zd, uint64_t id)
+{
+       zilog_t *zilog = zd->zd_zilog;
+
+       (void) rw_rdlock(&zd->zd_zilog_lock);
+
+       zil_commit(zilog, ztest_random(ZTEST_OBJECTS));
+
+       /*
+        * Remember the committed values in zd, which is in parent/child
+        * shared memory.  If we die, the next iteration of ztest_run()
+        * will verify that the log really does contain this record.
+        */
+       mutex_enter(&zilog->zl_lock);
+       ASSERT(zd->zd_shared != NULL);
+       ASSERT3U(zd->zd_shared->zd_seq, <=, zilog->zl_commit_lr_seq);
+       zd->zd_shared->zd_seq = zilog->zl_commit_lr_seq;
+       mutex_exit(&zilog->zl_lock);
+
+       (void) rw_unlock(&zd->zd_zilog_lock);
+}
+
+/*
+ * This function is designed to simulate the operations that occur during a
+ * mount/unmount operation.  We hold the dataset across these operations in an
+ * attempt to expose any implicit assumptions about ZIL management.
+ */
+/* ARGSUSED */
+void
+ztest_zil_remount(ztest_ds_t *zd, uint64_t id)
+{
+       objset_t *os = zd->zd_os;
+
+       /*
+        * We grab the zd_dirobj_lock to ensure that no other thread is
+        * updating the zil (i.e. adding in-memory log records) and the
+        * zd_zilog_lock to block any I/O.
+        */
+       mutex_enter(&zd->zd_dirobj_lock);
+       (void) rw_wrlock(&zd->zd_zilog_lock);
+
+       /* zfs_sb_teardown() */
+       zil_close(zd->zd_zilog);
+
+       /* zfsvfs_setup() */
+       VERIFY(zil_open(os, ztest_get_data) == zd->zd_zilog);
+       zil_replay(os, zd, ztest_replay_vector);
+
+       (void) rw_unlock(&zd->zd_zilog_lock);
+       mutex_exit(&zd->zd_dirobj_lock);
+}
+
+/*
+ * Verify that we can't destroy an active pool, create an existing pool,
+ * or create a pool with a bad vdev spec.
+ */
+/* ARGSUSED */
+void
+ztest_spa_create_destroy(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_shared_opts_t *zo = &ztest_opts;
+       spa_t *spa;
+       nvlist_t *nvroot;
+
+       /*
+        * Attempt to create using a bad file.
+        */
+       nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
+       VERIFY3U(ENOENT, ==,
+           spa_create("ztest_bad_file", nvroot, NULL, NULL));
+       nvlist_free(nvroot);
+
+       /*
+        * Attempt to create using a bad mirror.
+        */
+       nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 2, 1);
+       VERIFY3U(ENOENT, ==,
+           spa_create("ztest_bad_mirror", nvroot, NULL, NULL));
+       nvlist_free(nvroot);
+
+       /*
+        * Attempt to create an existing pool.  It shouldn't matter
+        * what's in the nvroot; we should fail with EEXIST.
+        */
+       (void) rw_rdlock(&ztest_name_lock);
+       nvroot = make_vdev_root("/dev/bogus", NULL, NULL, 0, 0, 0, 0, 0, 1);
+       VERIFY3U(EEXIST, ==, spa_create(zo->zo_pool, nvroot, NULL, NULL));
+       nvlist_free(nvroot);
+       VERIFY3U(0, ==, spa_open(zo->zo_pool, &spa, FTAG));
+       VERIFY3U(EBUSY, ==, spa_destroy(zo->zo_pool));
+       spa_close(spa, FTAG);
+
+       (void) rw_unlock(&ztest_name_lock);
+}
+
+/* ARGSUSED */
+void
+ztest_spa_upgrade(ztest_ds_t *zd, uint64_t id)
+{
+       spa_t *spa;
+       uint64_t initial_version = SPA_VERSION_INITIAL;
+       uint64_t version, newversion;
+       nvlist_t *nvroot, *props;
+       char *name;
+
+       mutex_enter(&ztest_vdev_lock);
+       name = kmem_asprintf("%s_upgrade", ztest_opts.zo_pool);
+
+       /*
+        * Clean up from previous runs.
+        */
+       (void) spa_destroy(name);
+
+       nvroot = make_vdev_root(NULL, NULL, name, ztest_opts.zo_vdev_size, 0,
+           0, ztest_opts.zo_raidz, ztest_opts.zo_mirrors, 1);
+
+       /*
+        * If we're configuring a RAIDZ device then make sure that the
+        * the initial version is capable of supporting that feature.
+        */
+       switch (ztest_opts.zo_raidz_parity) {
+       case 0:
+       case 1:
+               initial_version = SPA_VERSION_INITIAL;
+               break;
+       case 2:
+               initial_version = SPA_VERSION_RAIDZ2;
+               break;
+       case 3:
+               initial_version = SPA_VERSION_RAIDZ3;
+               break;
+       }
+
+       /*
+        * Create a pool with a spa version that can be upgraded. Pick
+        * a value between initial_version and SPA_VERSION_BEFORE_FEATURES.
+        */
+       do {
+               version = ztest_random_spa_version(initial_version);
+       } while (version > SPA_VERSION_BEFORE_FEATURES);
+
+       props = fnvlist_alloc();
+       fnvlist_add_uint64(props,
+           zpool_prop_to_name(ZPOOL_PROP_VERSION), version);
+       VERIFY3S(spa_create(name, nvroot, props, NULL), ==, 0);
+       fnvlist_free(nvroot);
+       fnvlist_free(props);
+
+       VERIFY3S(spa_open(name, &spa, FTAG), ==, 0);
+       VERIFY3U(spa_version(spa), ==, version);
+       newversion = ztest_random_spa_version(version + 1);
+
+       if (ztest_opts.zo_verbose >= 4) {
+               (void) printf("upgrading spa version from %llu to %llu\n",
+                   (u_longlong_t)version, (u_longlong_t)newversion);
+       }
+
+       spa_upgrade(spa, newversion);
+       VERIFY3U(spa_version(spa), >, version);
+       VERIFY3U(spa_version(spa), ==, fnvlist_lookup_uint64(spa->spa_config,
+           zpool_prop_to_name(ZPOOL_PROP_VERSION)));
+       spa_close(spa, FTAG);
+
+       strfree(name);
+       mutex_exit(&ztest_vdev_lock);
+}
+
+static vdev_t *
+vdev_lookup_by_path(vdev_t *vd, const char *path)
+{
+       vdev_t *mvd;
+       int c;
+
+       if (vd->vdev_path != NULL && strcmp(path, vd->vdev_path) == 0)
+               return (vd);
+
+       for (c = 0; c < vd->vdev_children; c++)
+               if ((mvd = vdev_lookup_by_path(vd->vdev_child[c], path)) !=
+                   NULL)
+                       return (mvd);
+
+       return (NULL);
+}
+
+/*
+ * Find the first available hole which can be used as a top-level.
+ */
+int
+find_vdev_hole(spa_t *spa)
+{
+       vdev_t *rvd = spa->spa_root_vdev;
+       int c;
+
+       ASSERT(spa_config_held(spa, SCL_VDEV, RW_READER) == SCL_VDEV);
+
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *cvd = rvd->vdev_child[c];
+
+               if (cvd->vdev_ishole)
+                       break;
+       }
+       return (c);
+}
+
+/*
+ * Verify that vdev_add() works as expected.
+ */
+/* ARGSUSED */
+void
+ztest_vdev_add_remove(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_shared_t *zs = ztest_shared;
+       spa_t *spa = ztest_spa;
+       uint64_t leaves;
+       uint64_t guid;
+       nvlist_t *nvroot;
+       int error;
+
+       mutex_enter(&ztest_vdev_lock);
+       leaves = MAX(zs->zs_mirrors + zs->zs_splits, 1) * ztest_opts.zo_raidz;
+
+       spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+       ztest_shared->zs_vdev_next_leaf = find_vdev_hole(spa) * leaves;
+
+       /*
+        * If we have slogs then remove them 1/4 of the time.
+        */
+       if (spa_has_slogs(spa) && ztest_random(4) == 0) {
+               /*
+                * Grab the guid from the head of the log class rotor.
+                */
+               guid = spa_log_class(spa)->mc_rotor->mg_vd->vdev_guid;
+
+               spa_config_exit(spa, SCL_VDEV, FTAG);
+
+               /*
+                * We have to grab the zs_name_lock as writer to
+                * prevent a race between removing a slog (dmu_objset_find)
+                * and destroying a dataset. Removing the slog will
+                * grab a reference on the dataset which may cause
+                * dsl_destroy_head() to fail with EBUSY thus
+                * leaving the dataset in an inconsistent state.
+                */
+               rw_wrlock(&ztest_name_lock);
+               error = spa_vdev_remove(spa, guid, B_FALSE);
+               rw_unlock(&ztest_name_lock);
+
+               if (error && error != EEXIST)
+                       fatal(0, "spa_vdev_remove() = %d", error);
+       } else {
+               spa_config_exit(spa, SCL_VDEV, FTAG);
+
+               /*
+                * Make 1/4 of the devices be log devices.
+                */
+               nvroot = make_vdev_root(NULL, NULL, NULL,
+                   ztest_opts.zo_vdev_size, 0,
+                   ztest_random(4) == 0, ztest_opts.zo_raidz,
+                   zs->zs_mirrors, 1);
+
+               error = spa_vdev_add(spa, nvroot);
+               nvlist_free(nvroot);
+
+               if (error == ENOSPC)
+                       ztest_record_enospc("spa_vdev_add");
+               else if (error != 0)
+                       fatal(0, "spa_vdev_add() = %d", error);
+       }
+
+       mutex_exit(&ztest_vdev_lock);
+}
+
+/*
+ * Verify that adding/removing aux devices (l2arc, hot spare) works as expected.
+ */
+/* ARGSUSED */
+void
+ztest_vdev_aux_add_remove(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_shared_t *zs = ztest_shared;
+       spa_t *spa = ztest_spa;
+       vdev_t *rvd = spa->spa_root_vdev;
+       spa_aux_vdev_t *sav;
+       char *aux;
+       char *path;
+       uint64_t guid = 0;
+       int error;
+
+       path = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+
+       if (ztest_random(2) == 0) {
+               sav = &spa->spa_spares;
+               aux = ZPOOL_CONFIG_SPARES;
+       } else {
+               sav = &spa->spa_l2cache;
+               aux = ZPOOL_CONFIG_L2CACHE;
+       }
+
+       mutex_enter(&ztest_vdev_lock);
+
+       spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+       if (sav->sav_count != 0 && ztest_random(4) == 0) {
+               /*
+                * Pick a random device to remove.
+                */
+               guid = sav->sav_vdevs[ztest_random(sav->sav_count)]->vdev_guid;
+       } else {
+               /*
+                * Find an unused device we can add.
+                */
+               zs->zs_vdev_aux = 0;
+               for (;;) {
+                       int c;
+                       (void) snprintf(path, MAXPATHLEN, ztest_aux_template,
+                           ztest_opts.zo_dir, ztest_opts.zo_pool, aux,
+                           zs->zs_vdev_aux);
+                       for (c = 0; c < sav->sav_count; c++)
+                               if (strcmp(sav->sav_vdevs[c]->vdev_path,
+                                   path) == 0)
+                                       break;
+                       if (c == sav->sav_count &&
+                           vdev_lookup_by_path(rvd, path) == NULL)
+                               break;
+                       zs->zs_vdev_aux++;
+               }
+       }
+
+       spa_config_exit(spa, SCL_VDEV, FTAG);
+
+       if (guid == 0) {
+               /*
+                * Add a new device.
+                */
+               nvlist_t *nvroot = make_vdev_root(NULL, aux, NULL,
+                   (ztest_opts.zo_vdev_size * 5) / 4, 0, 0, 0, 0, 1);
+               error = spa_vdev_add(spa, nvroot);
+               if (error != 0)
+                       fatal(0, "spa_vdev_add(%p) = %d", nvroot, error);
+               nvlist_free(nvroot);
+       } else {
+               /*
+                * Remove an existing device.  Sometimes, dirty its
+                * vdev state first to make sure we handle removal
+                * of devices that have pending state changes.
+                */
+               if (ztest_random(2) == 0)
+                       (void) vdev_online(spa, guid, 0, NULL);
+
+               error = spa_vdev_remove(spa, guid, B_FALSE);
+               if (error != 0 && error != EBUSY)
+                       fatal(0, "spa_vdev_remove(%llu) = %d", guid, error);
+       }
+
+       mutex_exit(&ztest_vdev_lock);
+
+       umem_free(path, MAXPATHLEN);
+}
+
+/*
+ * split a pool if it has mirror tlvdevs
+ */
+/* ARGSUSED */
+void
+ztest_split_pool(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_shared_t *zs = ztest_shared;
+       spa_t *spa = ztest_spa;
+       vdev_t *rvd = spa->spa_root_vdev;
+       nvlist_t *tree, **child, *config, *split, **schild;
+       uint_t c, children, schildren = 0, lastlogid = 0;
+       int error = 0;
+
+       mutex_enter(&ztest_vdev_lock);
+
+       /* ensure we have a useable config; mirrors of raidz aren't supported */
+       if (zs->zs_mirrors < 3 || ztest_opts.zo_raidz > 1) {
+               mutex_exit(&ztest_vdev_lock);
+               return;
+       }
+
+       /* clean up the old pool, if any */
+       (void) spa_destroy("splitp");
+
+       spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+       /* generate a config from the existing config */
+       mutex_enter(&spa->spa_props_lock);
+       VERIFY(nvlist_lookup_nvlist(spa->spa_config, ZPOOL_CONFIG_VDEV_TREE,
+           &tree) == 0);
+       mutex_exit(&spa->spa_props_lock);
+
+       VERIFY(nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child,
+           &children) == 0);
+
+       schild = malloc(rvd->vdev_children * sizeof (nvlist_t *));
+       for (c = 0; c < children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               nvlist_t **mchild;
+               uint_t mchildren;
+
+               if (tvd->vdev_islog || tvd->vdev_ops == &vdev_hole_ops) {
+                       VERIFY(nvlist_alloc(&schild[schildren], NV_UNIQUE_NAME,
+                           0) == 0);
+                       VERIFY(nvlist_add_string(schild[schildren],
+                           ZPOOL_CONFIG_TYPE, VDEV_TYPE_HOLE) == 0);
+                       VERIFY(nvlist_add_uint64(schild[schildren],
+                           ZPOOL_CONFIG_IS_HOLE, 1) == 0);
+                       if (lastlogid == 0)
+                               lastlogid = schildren;
+                       ++schildren;
+                       continue;
+               }
+               lastlogid = 0;
+               VERIFY(nvlist_lookup_nvlist_array(child[c],
+                   ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0);
+               VERIFY(nvlist_dup(mchild[0], &schild[schildren++], 0) == 0);
+       }
+
+       /* OK, create a config that can be used to split */
+       VERIFY(nvlist_alloc(&split, NV_UNIQUE_NAME, 0) == 0);
+       VERIFY(nvlist_add_string(split, ZPOOL_CONFIG_TYPE,
+           VDEV_TYPE_ROOT) == 0);
+       VERIFY(nvlist_add_nvlist_array(split, ZPOOL_CONFIG_CHILDREN, schild,
+           lastlogid != 0 ? lastlogid : schildren) == 0);
+
+       VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, 0) == 0);
+       VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, split) == 0);
+
+       for (c = 0; c < schildren; c++)
+               nvlist_free(schild[c]);
+       free(schild);
+       nvlist_free(split);
+
+       spa_config_exit(spa, SCL_VDEV, FTAG);
+
+       (void) rw_wrlock(&ztest_name_lock);
+       error = spa_vdev_split_mirror(spa, "splitp", config, NULL, B_FALSE);
+       (void) rw_unlock(&ztest_name_lock);
+
+       nvlist_free(config);
+
+       if (error == 0) {
+               (void) printf("successful split - results:\n");
+               mutex_enter(&spa_namespace_lock);
+               show_pool_stats(spa);
+               show_pool_stats(spa_lookup("splitp"));
+               mutex_exit(&spa_namespace_lock);
+               ++zs->zs_splits;
+               --zs->zs_mirrors;
+       }
+       mutex_exit(&ztest_vdev_lock);
+
+}
+
+/*
+ * Verify that we can attach and detach devices.
+ */
+/* ARGSUSED */
+void
+ztest_vdev_attach_detach(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_shared_t *zs = ztest_shared;
+       spa_t *spa = ztest_spa;
+       spa_aux_vdev_t *sav = &spa->spa_spares;
+       vdev_t *rvd = spa->spa_root_vdev;
+       vdev_t *oldvd, *newvd, *pvd;
+       nvlist_t *root;
+       uint64_t leaves;
+       uint64_t leaf, top;
+       uint64_t ashift = ztest_get_ashift();
+       uint64_t oldguid, pguid;
+       uint64_t oldsize, newsize;
+       char *oldpath, *newpath;
+       int replacing;
+       int oldvd_has_siblings = B_FALSE;
+       int newvd_is_spare = B_FALSE;
+       int oldvd_is_log;
+       int error, expected_error;
+
+       oldpath = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+       newpath = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+
+       mutex_enter(&ztest_vdev_lock);
+       leaves = MAX(zs->zs_mirrors, 1) * ztest_opts.zo_raidz;
+
+       spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER);
+
+       /*
+        * Decide whether to do an attach or a replace.
+        */
+       replacing = ztest_random(2);
+
+       /*
+        * Pick a random top-level vdev.
+        */
+       top = ztest_random_vdev_top(spa, B_TRUE);
+
+       /*
+        * Pick a random leaf within it.
+        */
+       leaf = ztest_random(leaves);
+
+       /*
+        * Locate this vdev.
+        */
+       oldvd = rvd->vdev_child[top];
+       if (zs->zs_mirrors >= 1) {
+               ASSERT(oldvd->vdev_ops == &vdev_mirror_ops);
+               ASSERT(oldvd->vdev_children >= zs->zs_mirrors);
+               oldvd = oldvd->vdev_child[leaf / ztest_opts.zo_raidz];
+       }
+       if (ztest_opts.zo_raidz > 1) {
+               ASSERT(oldvd->vdev_ops == &vdev_raidz_ops);
+               ASSERT(oldvd->vdev_children == ztest_opts.zo_raidz);
+               oldvd = oldvd->vdev_child[leaf % ztest_opts.zo_raidz];
+       }
+
+       /*
+        * If we're already doing an attach or replace, oldvd may be a
+        * mirror vdev -- in which case, pick a random child.
+        */
+       while (oldvd->vdev_children != 0) {
+               oldvd_has_siblings = B_TRUE;
+               ASSERT(oldvd->vdev_children >= 2);
+               oldvd = oldvd->vdev_child[ztest_random(oldvd->vdev_children)];
+       }
+
+       oldguid = oldvd->vdev_guid;
+       oldsize = vdev_get_min_asize(oldvd);
+       oldvd_is_log = oldvd->vdev_top->vdev_islog;
+       (void) strcpy(oldpath, oldvd->vdev_path);
+       pvd = oldvd->vdev_parent;
+       pguid = pvd->vdev_guid;
+
+       /*
+        * If oldvd has siblings, then half of the time, detach it.
+        */
+       if (oldvd_has_siblings && ztest_random(2) == 0) {
+               spa_config_exit(spa, SCL_VDEV, FTAG);
+               error = spa_vdev_detach(spa, oldguid, pguid, B_FALSE);
+               if (error != 0 && error != ENODEV && error != EBUSY &&
+                   error != ENOTSUP)
+                       fatal(0, "detach (%s) returned %d", oldpath, error);
+               goto out;
+       }
+
+       /*
+        * For the new vdev, choose with equal probability between the two
+        * standard paths (ending in either 'a' or 'b') or a random hot spare.
+        */
+       if (sav->sav_count != 0 && ztest_random(3) == 0) {
+               newvd = sav->sav_vdevs[ztest_random(sav->sav_count)];
+               newvd_is_spare = B_TRUE;
+               (void) strcpy(newpath, newvd->vdev_path);
+       } else {
+               (void) snprintf(newpath, MAXPATHLEN, ztest_dev_template,
+                   ztest_opts.zo_dir, ztest_opts.zo_pool,
+                   top * leaves + leaf);
+               if (ztest_random(2) == 0)
+                       newpath[strlen(newpath) - 1] = 'b';
+               newvd = vdev_lookup_by_path(rvd, newpath);
+       }
+
+       if (newvd) {
+               newsize = vdev_get_min_asize(newvd);
+       } else {
+               /*
+                * Make newsize a little bigger or smaller than oldsize.
+                * If it's smaller, the attach should fail.
+                * If it's larger, and we're doing a replace,
+                * we should get dynamic LUN growth when we're done.
+                */
+               newsize = 10 * oldsize / (9 + ztest_random(3));
+       }
+
+       /*
+        * If pvd is not a mirror or root, the attach should fail with ENOTSUP,
+        * unless it's a replace; in that case any non-replacing parent is OK.
+        *
+        * If newvd is already part of the pool, it should fail with EBUSY.
+        *
+        * If newvd is too small, it should fail with EOVERFLOW.
+        */
+       if (pvd->vdev_ops != &vdev_mirror_ops &&
+           pvd->vdev_ops != &vdev_root_ops && (!replacing ||
+           pvd->vdev_ops == &vdev_replacing_ops ||
+           pvd->vdev_ops == &vdev_spare_ops))
+               expected_error = ENOTSUP;
+       else if (newvd_is_spare && (!replacing || oldvd_is_log))
+               expected_error = ENOTSUP;
+       else if (newvd == oldvd)
+               expected_error = replacing ? 0 : EBUSY;
+       else if (vdev_lookup_by_path(rvd, newpath) != NULL)
+               expected_error = EBUSY;
+       else if (newsize < oldsize)
+               expected_error = EOVERFLOW;
+       else if (ashift > oldvd->vdev_top->vdev_ashift)
+               expected_error = EDOM;
+       else
+               expected_error = 0;
+
+       spa_config_exit(spa, SCL_VDEV, FTAG);
+
+       /*
+        * Build the nvlist describing newpath.
+        */
+       root = make_vdev_root(newpath, NULL, NULL, newvd == NULL ? newsize : 0,
+           ashift, 0, 0, 0, 1);
+
+       error = spa_vdev_attach(spa, oldguid, root, replacing);
+
+       nvlist_free(root);
+
+       /*
+        * If our parent was the replacing vdev, but the replace completed,
+        * then instead of failing with ENOTSUP we may either succeed,
+        * fail with ENODEV, or fail with EOVERFLOW.
+        */
+       if (expected_error == ENOTSUP &&
+           (error == 0 || error == ENODEV || error == EOVERFLOW))
+               expected_error = error;
+
+       /*
+        * If someone grew the LUN, the replacement may be too small.
+        */
+       if (error == EOVERFLOW || error == EBUSY)
+               expected_error = error;
+
+       /* XXX workaround 6690467 */
+       if (error != expected_error && expected_error != EBUSY) {
+               fatal(0, "attach (%s %llu, %s %llu, %d) "
+                   "returned %d, expected %d",
+                   oldpath, oldsize, newpath,
+                   newsize, replacing, error, expected_error);
+       }
+out:
+       mutex_exit(&ztest_vdev_lock);
+
+       umem_free(oldpath, MAXPATHLEN);
+       umem_free(newpath, MAXPATHLEN);
+}
+
+/*
+ * Callback function which expands the physical size of the vdev.
+ */
+vdev_t *
+grow_vdev(vdev_t *vd, void *arg)
+{
+       ASSERTV(spa_t *spa = vd->vdev_spa);
+       size_t *newsize = arg;
+       size_t fsize;
+       int fd;
+
+       ASSERT(spa_config_held(spa, SCL_STATE, RW_READER) == SCL_STATE);
+       ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+       if ((fd = open(vd->vdev_path, O_RDWR)) == -1)
+               return (vd);
+
+       fsize = lseek(fd, 0, SEEK_END);
+       VERIFY(ftruncate(fd, *newsize) == 0);
+
+       if (ztest_opts.zo_verbose >= 6) {
+               (void) printf("%s grew from %lu to %lu bytes\n",
+                   vd->vdev_path, (ulong_t)fsize, (ulong_t)*newsize);
+       }
+       (void) close(fd);
+       return (NULL);
+}
+
+/*
+ * Callback function which expands a given vdev by calling vdev_online().
+ */
+/* ARGSUSED */
+vdev_t *
+online_vdev(vdev_t *vd, void *arg)
+{
+       spa_t *spa = vd->vdev_spa;
+       vdev_t *tvd = vd->vdev_top;
+       uint64_t guid = vd->vdev_guid;
+       uint64_t generation = spa->spa_config_generation + 1;
+       vdev_state_t newstate = VDEV_STATE_UNKNOWN;
+       int error;
+
+       ASSERT(spa_config_held(spa, SCL_STATE, RW_READER) == SCL_STATE);
+       ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+       /* Calling vdev_online will initialize the new metaslabs */
+       spa_config_exit(spa, SCL_STATE, spa);
+       error = vdev_online(spa, guid, ZFS_ONLINE_EXPAND, &newstate);
+       spa_config_enter(spa, SCL_STATE, spa, RW_READER);
+
+       /*
+        * If vdev_online returned an error or the underlying vdev_open
+        * failed then we abort the expand. The only way to know that
+        * vdev_open fails is by checking the returned newstate.
+        */
+       if (error || newstate != VDEV_STATE_HEALTHY) {
+               if (ztest_opts.zo_verbose >= 5) {
+                       (void) printf("Unable to expand vdev, state %llu, "
+                           "error %d\n", (u_longlong_t)newstate, error);
+               }
+               return (vd);
+       }
+       ASSERT3U(newstate, ==, VDEV_STATE_HEALTHY);
+
+       /*
+        * Since we dropped the lock we need to ensure that we're
+        * still talking to the original vdev. It's possible this
+        * vdev may have been detached/replaced while we were
+        * trying to online it.
+        */
+       if (generation != spa->spa_config_generation) {
+               if (ztest_opts.zo_verbose >= 5) {
+                       (void) printf("vdev configuration has changed, "
+                           "guid %llu, state %llu, expected gen %llu, "
+                           "got gen %llu\n",
+                           (u_longlong_t)guid,
+                           (u_longlong_t)tvd->vdev_state,
+                           (u_longlong_t)generation,
+                           (u_longlong_t)spa->spa_config_generation);
+               }
+               return (vd);
+       }
+       return (NULL);
+}
+
+/*
+ * Traverse the vdev tree calling the supplied function.
+ * We continue to walk the tree until we either have walked all
+ * children or we receive a non-NULL return from the callback.
+ * If a NULL callback is passed, then we just return back the first
+ * leaf vdev we encounter.
+ */
+vdev_t *
+vdev_walk_tree(vdev_t *vd, vdev_t *(*func)(vdev_t *, void *), void *arg)
+{
+       uint_t c;
+
+       if (vd->vdev_ops->vdev_op_leaf) {
+               if (func == NULL)
+                       return (vd);
+               else
+                       return (func(vd, arg));
+       }
+
+       for (c = 0; c < vd->vdev_children; c++) {
+               vdev_t *cvd = vd->vdev_child[c];
+               if ((cvd = vdev_walk_tree(cvd, func, arg)) != NULL)
+                       return (cvd);
+       }
+       return (NULL);
+}
+
+/*
+ * Verify that dynamic LUN growth works as expected.
+ */
+/* ARGSUSED */
+void
+ztest_vdev_LUN_growth(ztest_ds_t *zd, uint64_t id)
+{
+       spa_t *spa = ztest_spa;
+       vdev_t *vd, *tvd;
+       metaslab_class_t *mc;
+       metaslab_group_t *mg;
+       size_t psize, newsize;
+       uint64_t top;
+       uint64_t old_class_space, new_class_space, old_ms_count, new_ms_count;
+
+       mutex_enter(&ztest_vdev_lock);
+       spa_config_enter(spa, SCL_STATE, spa, RW_READER);
+
+       top = ztest_random_vdev_top(spa, B_TRUE);
+
+       tvd = spa->spa_root_vdev->vdev_child[top];
+       mg = tvd->vdev_mg;
+       mc = mg->mg_class;
+       old_ms_count = tvd->vdev_ms_count;
+       old_class_space = metaslab_class_get_space(mc);
+
+       /*
+        * Determine the size of the first leaf vdev associated with
+        * our top-level device.
+        */
+       vd = vdev_walk_tree(tvd, NULL, NULL);
+       ASSERT3P(vd, !=, NULL);
+       ASSERT(vd->vdev_ops->vdev_op_leaf);
+
+       psize = vd->vdev_psize;
+
+       /*
+        * We only try to expand the vdev if it's healthy, less than 4x its
+        * original size, and it has a valid psize.
+        */
+       if (tvd->vdev_state != VDEV_STATE_HEALTHY ||
+           psize == 0 || psize >= 4 * ztest_opts.zo_vdev_size) {
+               spa_config_exit(spa, SCL_STATE, spa);
+               mutex_exit(&ztest_vdev_lock);
+               return;
+       }
+       ASSERT(psize > 0);
+       newsize = psize + psize / 8;
+       ASSERT3U(newsize, >, psize);
+
+       if (ztest_opts.zo_verbose >= 6) {
+               (void) printf("Expanding LUN %s from %lu to %lu\n",
+                   vd->vdev_path, (ulong_t)psize, (ulong_t)newsize);
+       }
+
+       /*
+        * Growing the vdev is a two step process:
+        *      1). expand the physical size (i.e. relabel)
+        *      2). online the vdev to create the new metaslabs
+        */
+       if (vdev_walk_tree(tvd, grow_vdev, &newsize) != NULL ||
+           vdev_walk_tree(tvd, online_vdev, NULL) != NULL ||
+           tvd->vdev_state != VDEV_STATE_HEALTHY) {
+               if (ztest_opts.zo_verbose >= 5) {
+                       (void) printf("Could not expand LUN because "
+                           "the vdev configuration changed.\n");
+               }
+               spa_config_exit(spa, SCL_STATE, spa);
+               mutex_exit(&ztest_vdev_lock);
+               return;
+       }
+
+       spa_config_exit(spa, SCL_STATE, spa);
+
+       /*
+        * Expanding the LUN will update the config asynchronously,
+        * thus we must wait for the async thread to complete any
+        * pending tasks before proceeding.
+        */
+       for (;;) {
+               boolean_t done;
+               mutex_enter(&spa->spa_async_lock);
+               done = (spa->spa_async_thread == NULL && !spa->spa_async_tasks);
+               mutex_exit(&spa->spa_async_lock);
+               if (done)
+                       break;
+               txg_wait_synced(spa_get_dsl(spa), 0);
+               (void) poll(NULL, 0, 100);
+       }
+
+       spa_config_enter(spa, SCL_STATE, spa, RW_READER);
+
+       tvd = spa->spa_root_vdev->vdev_child[top];
+       new_ms_count = tvd->vdev_ms_count;
+       new_class_space = metaslab_class_get_space(mc);
+
+       if (tvd->vdev_mg != mg || mg->mg_class != mc) {
+               if (ztest_opts.zo_verbose >= 5) {
+                       (void) printf("Could not verify LUN expansion due to "
+                           "intervening vdev offline or remove.\n");
+               }
+               spa_config_exit(spa, SCL_STATE, spa);
+               mutex_exit(&ztest_vdev_lock);
+               return;
+       }
+
+       /*
+        * Make sure we were able to grow the vdev.
+        */
+       if (new_ms_count <= old_ms_count)
+               fatal(0, "LUN expansion failed: ms_count %llu <= %llu\n",
+                   old_ms_count, new_ms_count);
+
+       /*
+        * Make sure we were able to grow the pool.
+        */
+       if (new_class_space <= old_class_space)
+               fatal(0, "LUN expansion failed: class_space %llu <= %llu\n",
+                   old_class_space, new_class_space);
+
+       if (ztest_opts.zo_verbose >= 5) {
+               char oldnumbuf[6], newnumbuf[6];
+
+               nicenum(old_class_space, oldnumbuf);
+               nicenum(new_class_space, newnumbuf);
+               (void) printf("%s grew from %s to %s\n",
+                   spa->spa_name, oldnumbuf, newnumbuf);
+       }
+
+       spa_config_exit(spa, SCL_STATE, spa);
+       mutex_exit(&ztest_vdev_lock);
+}
+
+/*
+ * Verify that dmu_objset_{create,destroy,open,close} work as expected.
+ */
+/* ARGSUSED */
+static void
+ztest_objset_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx)
+{
+       /*
+        * Create the objects common to all ztest datasets.
+        */
+       VERIFY(zap_create_claim(os, ZTEST_DIROBJ,
+           DMU_OT_ZAP_OTHER, DMU_OT_NONE, 0, tx) == 0);
+}
+
+static int
+ztest_dataset_create(char *dsname)
+{
+       uint64_t zilset = ztest_random(100);
+       int err = dmu_objset_create(dsname, DMU_OST_OTHER, 0,
+           ztest_objset_create_cb, NULL);
+
+       if (err || zilset < 80)
+               return (err);
+
+       if (ztest_opts.zo_verbose >= 5)
+               (void) printf("Setting dataset %s to sync always\n", dsname);
+       return (ztest_dsl_prop_set_uint64(dsname, ZFS_PROP_SYNC,
+           ZFS_SYNC_ALWAYS, B_FALSE));
+}
+
+/* ARGSUSED */
+static int
+ztest_objset_destroy_cb(const char *name, void *arg)
+{
+       objset_t *os;
+       dmu_object_info_t doi;
+       int error;
+
+       /*
+        * Verify that the dataset contains a directory object.
+        */
+       VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_TRUE, FTAG, &os));
+       error = dmu_object_info(os, ZTEST_DIROBJ, &doi);
+       if (error != ENOENT) {
+               /* We could have crashed in the middle of destroying it */
+               ASSERT0(error);
+               ASSERT3U(doi.doi_type, ==, DMU_OT_ZAP_OTHER);
+               ASSERT3S(doi.doi_physical_blocks_512, >=, 0);
+       }
+       dmu_objset_disown(os, FTAG);
+
+       /*
+        * Destroy the dataset.
+        */
+       if (strchr(name, '@') != NULL) {
+               VERIFY0(dsl_destroy_snapshot(name, B_FALSE));
+       } else {
+               VERIFY0(dsl_destroy_head(name));
+       }
+       return (0);
+}
+
+static boolean_t
+ztest_snapshot_create(char *osname, uint64_t id)
+{
+       char snapname[ZFS_MAX_DATASET_NAME_LEN];
+       int error;
+
+       (void) snprintf(snapname, sizeof (snapname), "%llu", (u_longlong_t)id);
+
+       error = dmu_objset_snapshot_one(osname, snapname);
+       if (error == ENOSPC) {
+               ztest_record_enospc(FTAG);
+               return (B_FALSE);
+       }
+       if (error != 0 && error != EEXIST) {
+               fatal(0, "ztest_snapshot_create(%s@%s) = %d", osname,
+                   snapname, error);
+       }
+       return (B_TRUE);
+}
+
+static boolean_t
+ztest_snapshot_destroy(char *osname, uint64_t id)
+{
+       char snapname[ZFS_MAX_DATASET_NAME_LEN];
+       int error;
+
+       (void) snprintf(snapname, sizeof (snapname), "%s@%llu", osname,
+           (u_longlong_t)id);
+
+       error = dsl_destroy_snapshot(snapname, B_FALSE);
+       if (error != 0 && error != ENOENT)
+               fatal(0, "ztest_snapshot_destroy(%s) = %d", snapname, error);
+       return (B_TRUE);
+}
+
+/* ARGSUSED */
+void
+ztest_dmu_objset_create_destroy(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_ds_t *zdtmp;
+       int iters;
+       int error;
+       objset_t *os, *os2;
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       zilog_t *zilog;
+       int i;
+
+       zdtmp = umem_alloc(sizeof (ztest_ds_t), UMEM_NOFAIL);
+
+       (void) rw_rdlock(&ztest_name_lock);
+
+       (void) snprintf(name, sizeof (name), "%s/temp_%llu",
+           ztest_opts.zo_pool, (u_longlong_t)id);
+
+       /*
+        * If this dataset exists from a previous run, process its replay log
+        * half of the time.  If we don't replay it, then dsl_destroy_head()
+        * (invoked from ztest_objset_destroy_cb()) should just throw it away.
+        */
+       if (ztest_random(2) == 0 &&
+           dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os) == 0) {
+               ztest_zd_init(zdtmp, NULL, os);
+               zil_replay(os, zdtmp, ztest_replay_vector);
+               ztest_zd_fini(zdtmp);
+               dmu_objset_disown(os, FTAG);
+       }
+
+       /*
+        * There may be an old instance of the dataset we're about to
+        * create lying around from a previous run.  If so, destroy it
+        * and all of its snapshots.
+        */
+       (void) dmu_objset_find(name, ztest_objset_destroy_cb, NULL,
+           DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
+
+       /*
+        * Verify that the destroyed dataset is no longer in the namespace.
+        */
+       VERIFY3U(ENOENT, ==, dmu_objset_own(name, DMU_OST_OTHER, B_TRUE,
+           FTAG, &os));
+
+       /*
+        * Verify that we can create a new dataset.
+        */
+       error = ztest_dataset_create(name);
+       if (error) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc(FTAG);
+                       goto out;
+               }
+               fatal(0, "dmu_objset_create(%s) = %d", name, error);
+       }
+
+       VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os));
+
+       ztest_zd_init(zdtmp, NULL, os);
+
+       /*
+        * Open the intent log for it.
+        */
+       zilog = zil_open(os, ztest_get_data);
+
+       /*
+        * Put some objects in there, do a little I/O to them,
+        * and randomly take a couple of snapshots along the way.
+        */
+       iters = ztest_random(5);
+       for (i = 0; i < iters; i++) {
+               ztest_dmu_object_alloc_free(zdtmp, id);
+               if (ztest_random(iters) == 0)
+                       (void) ztest_snapshot_create(name, i);
+       }
+
+       /*
+        * Verify that we cannot create an existing dataset.
+        */
+       VERIFY3U(EEXIST, ==,
+           dmu_objset_create(name, DMU_OST_OTHER, 0, NULL, NULL));
+
+       /*
+        * Verify that we can hold an objset that is also owned.
+        */
+       VERIFY3U(0, ==, dmu_objset_hold(name, FTAG, &os2));
+       dmu_objset_rele(os2, FTAG);
+
+       /*
+        * Verify that we cannot own an objset that is already owned.
+        */
+       VERIFY3U(EBUSY, ==,
+           dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, FTAG, &os2));
+
+       zil_close(zilog);
+       dmu_objset_disown(os, FTAG);
+       ztest_zd_fini(zdtmp);
+out:
+       (void) rw_unlock(&ztest_name_lock);
+
+       umem_free(zdtmp, sizeof (ztest_ds_t));
+}
+
+/*
+ * Verify that dmu_snapshot_{create,destroy,open,close} work as expected.
+ */
+void
+ztest_dmu_snapshot_create_destroy(ztest_ds_t *zd, uint64_t id)
+{
+       (void) rw_rdlock(&ztest_name_lock);
+       (void) ztest_snapshot_destroy(zd->zd_name, id);
+       (void) ztest_snapshot_create(zd->zd_name, id);
+       (void) rw_unlock(&ztest_name_lock);
+}
+
+/*
+ * Cleanup non-standard snapshots and clones.
+ */
+void
+ztest_dsl_dataset_cleanup(char *osname, uint64_t id)
+{
+       char *snap1name;
+       char *clone1name;
+       char *snap2name;
+       char *clone2name;
+       char *snap3name;
+       int error;
+
+       snap1name  = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+       clone1name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+       snap2name  = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+       clone2name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+       snap3name  = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+
+       (void) snprintf(snap1name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s@s1_%llu", osname, (u_longlong_t)id);
+       (void) snprintf(clone1name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s/c1_%llu", osname, (u_longlong_t)id);
+       (void) snprintf(snap2name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s@s2_%llu", clone1name, (u_longlong_t)id);
+       (void) snprintf(clone2name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s/c2_%llu", osname, (u_longlong_t)id);
+       (void) snprintf(snap3name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s@s3_%llu", clone1name, (u_longlong_t)id);
+
+       error = dsl_destroy_head(clone2name);
+       if (error && error != ENOENT)
+               fatal(0, "dsl_destroy_head(%s) = %d", clone2name, error);
+       error = dsl_destroy_snapshot(snap3name, B_FALSE);
+       if (error && error != ENOENT)
+               fatal(0, "dsl_destroy_snapshot(%s) = %d", snap3name, error);
+       error = dsl_destroy_snapshot(snap2name, B_FALSE);
+       if (error && error != ENOENT)
+               fatal(0, "dsl_destroy_snapshot(%s) = %d", snap2name, error);
+       error = dsl_destroy_head(clone1name);
+       if (error && error != ENOENT)
+               fatal(0, "dsl_destroy_head(%s) = %d", clone1name, error);
+       error = dsl_destroy_snapshot(snap1name, B_FALSE);
+       if (error && error != ENOENT)
+               fatal(0, "dsl_destroy_snapshot(%s) = %d", snap1name, error);
+
+       umem_free(snap1name, ZFS_MAX_DATASET_NAME_LEN);
+       umem_free(clone1name, ZFS_MAX_DATASET_NAME_LEN);
+       umem_free(snap2name, ZFS_MAX_DATASET_NAME_LEN);
+       umem_free(clone2name, ZFS_MAX_DATASET_NAME_LEN);
+       umem_free(snap3name, ZFS_MAX_DATASET_NAME_LEN);
+}
+
+/*
+ * Verify dsl_dataset_promote handles EBUSY
+ */
+void
+ztest_dsl_dataset_promote_busy(ztest_ds_t *zd, uint64_t id)
+{
+       objset_t *os;
+       char *snap1name;
+       char *clone1name;
+       char *snap2name;
+       char *clone2name;
+       char *snap3name;
+       char *osname = zd->zd_name;
+       int error;
+
+       snap1name  = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+       clone1name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+       snap2name  = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+       clone2name = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+       snap3name  = umem_alloc(ZFS_MAX_DATASET_NAME_LEN, UMEM_NOFAIL);
+
+       (void) rw_rdlock(&ztest_name_lock);
+
+       ztest_dsl_dataset_cleanup(osname, id);
+
+       (void) snprintf(snap1name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s@s1_%llu", osname, (u_longlong_t)id);
+       (void) snprintf(clone1name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s/c1_%llu", osname, (u_longlong_t)id);
+       (void) snprintf(snap2name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s@s2_%llu", clone1name, (u_longlong_t)id);
+       (void) snprintf(clone2name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s/c2_%llu", osname, (u_longlong_t)id);
+       (void) snprintf(snap3name, ZFS_MAX_DATASET_NAME_LEN,
+           "%s@s3_%llu", clone1name, (u_longlong_t)id);
+
+       error = dmu_objset_snapshot_one(osname, strchr(snap1name, '@') + 1);
+       if (error && error != EEXIST) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc(FTAG);
+                       goto out;
+               }
+               fatal(0, "dmu_take_snapshot(%s) = %d", snap1name, error);
+       }
+
+       error = dmu_objset_clone(clone1name, snap1name);
+       if (error) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc(FTAG);
+                       goto out;
+               }
+               fatal(0, "dmu_objset_create(%s) = %d", clone1name, error);
+       }
+
+       error = dmu_objset_snapshot_one(clone1name, strchr(snap2name, '@') + 1);
+       if (error && error != EEXIST) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc(FTAG);
+                       goto out;
+               }
+               fatal(0, "dmu_open_snapshot(%s) = %d", snap2name, error);
+       }
+
+       error = dmu_objset_snapshot_one(clone1name, strchr(snap3name, '@') + 1);
+       if (error && error != EEXIST) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc(FTAG);
+                       goto out;
+               }
+               fatal(0, "dmu_open_snapshot(%s) = %d", snap3name, error);
+       }
+
+       error = dmu_objset_clone(clone2name, snap3name);
+       if (error) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc(FTAG);
+                       goto out;
+               }
+               fatal(0, "dmu_objset_create(%s) = %d", clone2name, error);
+       }
+
+       error = dmu_objset_own(snap2name, DMU_OST_ANY, B_TRUE, FTAG, &os);
+       if (error)
+               fatal(0, "dmu_objset_own(%s) = %d", snap2name, error);
+       error = dsl_dataset_promote(clone2name, NULL);
+       if (error == ENOSPC) {
+               dmu_objset_disown(os, FTAG);
+               ztest_record_enospc(FTAG);
+               goto out;
+       }
+       if (error != EBUSY)
+               fatal(0, "dsl_dataset_promote(%s), %d, not EBUSY", clone2name,
+                   error);
+       dmu_objset_disown(os, FTAG);
+
+out:
+       ztest_dsl_dataset_cleanup(osname, id);
+
+       (void) rw_unlock(&ztest_name_lock);
+
+       umem_free(snap1name, ZFS_MAX_DATASET_NAME_LEN);
+       umem_free(clone1name, ZFS_MAX_DATASET_NAME_LEN);
+       umem_free(snap2name, ZFS_MAX_DATASET_NAME_LEN);
+       umem_free(clone2name, ZFS_MAX_DATASET_NAME_LEN);
+       umem_free(snap3name, ZFS_MAX_DATASET_NAME_LEN);
+}
+
+#undef OD_ARRAY_SIZE
+#define        OD_ARRAY_SIZE   4
+
+/*
+ * Verify that dmu_object_{alloc,free} work as expected.
+ */
+void
+ztest_dmu_object_alloc_free(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_od_t *od;
+       int batchsize;
+       int size;
+       int b;
+
+       size = sizeof (ztest_od_t) * OD_ARRAY_SIZE;
+       od = umem_alloc(size, UMEM_NOFAIL);
+       batchsize = OD_ARRAY_SIZE;
+
+       for (b = 0; b < batchsize; b++)
+               ztest_od_init(od + b, id, FTAG, b, DMU_OT_UINT64_OTHER,
+                   0, 0, 0);
+
+       /*
+        * Destroy the previous batch of objects, create a new batch,
+        * and do some I/O on the new objects.
+        */
+       if (ztest_object_init(zd, od, size, B_TRUE) != 0)
+               return;
+
+       while (ztest_random(4 * batchsize) != 0)
+               ztest_io(zd, od[ztest_random(batchsize)].od_object,
+                   ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
+
+       umem_free(od, size);
+}
+
+#undef OD_ARRAY_SIZE
+#define        OD_ARRAY_SIZE   2
+
+/*
+ * Verify that dmu_{read,write} work as expected.
+ */
+void
+ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id)
+{
+       int size;
+       ztest_od_t *od;
+
+       objset_t *os = zd->zd_os;
+       size = sizeof (ztest_od_t) * OD_ARRAY_SIZE;
+       od = umem_alloc(size, UMEM_NOFAIL);
+       dmu_tx_t *tx;
+       int i, freeit, error;
+       uint64_t n, s, txg;
+       bufwad_t *packbuf, *bigbuf, *pack, *bigH, *bigT;
+       uint64_t packobj, packoff, packsize, bigobj, bigoff, bigsize;
+       uint64_t chunksize = (1000 + ztest_random(1000)) * sizeof (uint64_t);
+       uint64_t regions = 997;
+       uint64_t stride = 123456789ULL;
+       uint64_t width = 40;
+       int free_percent = 5;
+
+       /*
+        * This test uses two objects, packobj and bigobj, that are always
+        * updated together (i.e. in the same tx) so that their contents are
+        * in sync and can be compared.  Their contents relate to each other
+        * in a simple way: packobj is a dense array of 'bufwad' structures,
+        * while bigobj is a sparse array of the same bufwads.  Specifically,
+        * for any index n, there are three bufwads that should be identical:
+        *
+        *      packobj, at offset n * sizeof (bufwad_t)
+        *      bigobj, at the head of the nth chunk
+        *      bigobj, at the tail of the nth chunk
+        *
+        * The chunk size is arbitrary. It doesn't have to be a power of two,
+        * and it doesn't have any relation to the object blocksize.
+        * The only requirement is that it can hold at least two bufwads.
+        *
+        * Normally, we write the bufwad to each of these locations.
+        * However, free_percent of the time we instead write zeroes to
+        * packobj and perform a dmu_free_range() on bigobj.  By comparing
+        * bigobj to packobj, we can verify that the DMU is correctly
+        * tracking which parts of an object are allocated and free,
+        * and that the contents of the allocated blocks are correct.
+        */
+
+       /*
+        * Read the directory info.  If it's the first time, set things up.
+        */
+       ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, chunksize);
+       ztest_od_init(od + 1, id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, 0,
+           chunksize);
+
+       if (ztest_object_init(zd, od, size, B_FALSE) != 0) {
+               umem_free(od, size);
+               return;
+       }
+
+       bigobj = od[0].od_object;
+       packobj = od[1].od_object;
+       chunksize = od[0].od_gen;
+       ASSERT(chunksize == od[1].od_gen);
+
+       /*
+        * Prefetch a random chunk of the big object.
+        * Our aim here is to get some async reads in flight
+        * for blocks that we may free below; the DMU should
+        * handle this race correctly.
+        */
+       n = ztest_random(regions) * stride + ztest_random(width);
+       s = 1 + ztest_random(2 * width - 1);
+       dmu_prefetch(os, bigobj, 0, n * chunksize, s * chunksize,
+           ZIO_PRIORITY_SYNC_READ);
+
+       /*
+        * Pick a random index and compute the offsets into packobj and bigobj.
+        */
+       n = ztest_random(regions) * stride + ztest_random(width);
+       s = 1 + ztest_random(width - 1);
+
+       packoff = n * sizeof (bufwad_t);
+       packsize = s * sizeof (bufwad_t);
+
+       bigoff = n * chunksize;
+       bigsize = s * chunksize;
+
+       packbuf = umem_alloc(packsize, UMEM_NOFAIL);
+       bigbuf = umem_alloc(bigsize, UMEM_NOFAIL);
+
+       /*
+        * free_percent of the time, free a range of bigobj rather than
+        * overwriting it.
+        */
+       freeit = (ztest_random(100) < free_percent);
+
+       /*
+        * Read the current contents of our objects.
+        */
+       error = dmu_read(os, packobj, packoff, packsize, packbuf,
+           DMU_READ_PREFETCH);
+       ASSERT0(error);
+       error = dmu_read(os, bigobj, bigoff, bigsize, bigbuf,
+           DMU_READ_PREFETCH);
+       ASSERT0(error);
+
+       /*
+        * Get a tx for the mods to both packobj and bigobj.
+        */
+       tx = dmu_tx_create(os);
+
+       dmu_tx_hold_write(tx, packobj, packoff, packsize);
+
+       if (freeit)
+               dmu_tx_hold_free(tx, bigobj, bigoff, bigsize);
+       else
+               dmu_tx_hold_write(tx, bigobj, bigoff, bigsize);
+
+       /* This accounts for setting the checksum/compression. */
+       dmu_tx_hold_bonus(tx, bigobj);
+
+       txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+       if (txg == 0) {
+               umem_free(packbuf, packsize);
+               umem_free(bigbuf, bigsize);
+               umem_free(od, size);
+               return;
+       }
+
+       enum zio_checksum cksum;
+       do {
+               cksum = (enum zio_checksum)
+                   ztest_random_dsl_prop(ZFS_PROP_CHECKSUM);
+       } while (cksum >= ZIO_CHECKSUM_LEGACY_FUNCTIONS);
+       dmu_object_set_checksum(os, bigobj, cksum, tx);
+
+       enum zio_compress comp;
+       do {
+               comp = (enum zio_compress)
+                   ztest_random_dsl_prop(ZFS_PROP_COMPRESSION);
+       } while (comp >= ZIO_COMPRESS_LEGACY_FUNCTIONS);
+       dmu_object_set_compress(os, bigobj, comp, tx);
+
+       /*
+        * For each index from n to n + s, verify that the existing bufwad
+        * in packobj matches the bufwads at the head and tail of the
+        * corresponding chunk in bigobj.  Then update all three bufwads
+        * with the new values we want to write out.
+        */
+       for (i = 0; i < s; i++) {
+               /* LINTED */
+               pack = (bufwad_t *)((char *)packbuf + i * sizeof (bufwad_t));
+               /* LINTED */
+               bigH = (bufwad_t *)((char *)bigbuf + i * chunksize);
+               /* LINTED */
+               bigT = (bufwad_t *)((char *)bigH + chunksize) - 1;
+
+               ASSERT((uintptr_t)bigH - (uintptr_t)bigbuf < bigsize);
+               ASSERT((uintptr_t)bigT - (uintptr_t)bigbuf < bigsize);
+
+               if (pack->bw_txg > txg)
+                       fatal(0, "future leak: got %llx, open txg is %llx",
+                           pack->bw_txg, txg);
+
+               if (pack->bw_data != 0 && pack->bw_index != n + i)
+                       fatal(0, "wrong index: got %llx, wanted %llx+%llx",
+                           pack->bw_index, n, i);
+
+               if (bcmp(pack, bigH, sizeof (bufwad_t)) != 0)
+                       fatal(0, "pack/bigH mismatch in %p/%p", pack, bigH);
+
+               if (bcmp(pack, bigT, sizeof (bufwad_t)) != 0)
+                       fatal(0, "pack/bigT mismatch in %p/%p", pack, bigT);
+
+               if (freeit) {
+                       bzero(pack, sizeof (bufwad_t));
+               } else {
+                       pack->bw_index = n + i;
+                       pack->bw_txg = txg;
+                       pack->bw_data = 1 + ztest_random(-2ULL);
+               }
+               *bigH = *pack;
+               *bigT = *pack;
+       }
+
+       /*
+        * We've verified all the old bufwads, and made new ones.
+        * Now write them out.
+        */
+       dmu_write(os, packobj, packoff, packsize, packbuf, tx);
+
+       if (freeit) {
+               if (ztest_opts.zo_verbose >= 7) {
+                       (void) printf("freeing offset %llx size %llx"
+                           " txg %llx\n",
+                           (u_longlong_t)bigoff,
+                           (u_longlong_t)bigsize,
+                           (u_longlong_t)txg);
+               }
+               VERIFY(0 == dmu_free_range(os, bigobj, bigoff, bigsize, tx));
+       } else {
+               if (ztest_opts.zo_verbose >= 7) {
+                       (void) printf("writing offset %llx size %llx"
+                           " txg %llx\n",
+                           (u_longlong_t)bigoff,
+                           (u_longlong_t)bigsize,
+                           (u_longlong_t)txg);
+               }
+               dmu_write(os, bigobj, bigoff, bigsize, bigbuf, tx);
+       }
+
+       dmu_tx_commit(tx);
+
+       /*
+        * Sanity check the stuff we just wrote.
+        */
+       {
+               void *packcheck = umem_alloc(packsize, UMEM_NOFAIL);
+               void *bigcheck = umem_alloc(bigsize, UMEM_NOFAIL);
+
+               VERIFY(0 == dmu_read(os, packobj, packoff,
+                   packsize, packcheck, DMU_READ_PREFETCH));
+               VERIFY(0 == dmu_read(os, bigobj, bigoff,
+                   bigsize, bigcheck, DMU_READ_PREFETCH));
+
+               ASSERT(bcmp(packbuf, packcheck, packsize) == 0);
+               ASSERT(bcmp(bigbuf, bigcheck, bigsize) == 0);
+
+               umem_free(packcheck, packsize);
+               umem_free(bigcheck, bigsize);
+       }
+
+       umem_free(packbuf, packsize);
+       umem_free(bigbuf, bigsize);
+       umem_free(od, size);
+}
+
+void
+compare_and_update_pbbufs(uint64_t s, bufwad_t *packbuf, bufwad_t *bigbuf,
+    uint64_t bigsize, uint64_t n, uint64_t chunksize, uint64_t txg)
+{
+       uint64_t i;
+       bufwad_t *pack;
+       bufwad_t *bigH;
+       bufwad_t *bigT;
+
+       /*
+        * For each index from n to n + s, verify that the existing bufwad
+        * in packobj matches the bufwads at the head and tail of the
+        * corresponding chunk in bigobj.  Then update all three bufwads
+        * with the new values we want to write out.
+        */
+       for (i = 0; i < s; i++) {
+               /* LINTED */
+               pack = (bufwad_t *)((char *)packbuf + i * sizeof (bufwad_t));
+               /* LINTED */
+               bigH = (bufwad_t *)((char *)bigbuf + i * chunksize);
+               /* LINTED */
+               bigT = (bufwad_t *)((char *)bigH + chunksize) - 1;
+
+               ASSERT((uintptr_t)bigH - (uintptr_t)bigbuf < bigsize);
+               ASSERT((uintptr_t)bigT - (uintptr_t)bigbuf < bigsize);
+
+               if (pack->bw_txg > txg)
+                       fatal(0, "future leak: got %llx, open txg is %llx",
+                           pack->bw_txg, txg);
+
+               if (pack->bw_data != 0 && pack->bw_index != n + i)
+                       fatal(0, "wrong index: got %llx, wanted %llx+%llx",
+                           pack->bw_index, n, i);
+
+               if (bcmp(pack, bigH, sizeof (bufwad_t)) != 0)
+                       fatal(0, "pack/bigH mismatch in %p/%p", pack, bigH);
+
+               if (bcmp(pack, bigT, sizeof (bufwad_t)) != 0)
+                       fatal(0, "pack/bigT mismatch in %p/%p", pack, bigT);
+
+               pack->bw_index = n + i;
+               pack->bw_txg = txg;
+               pack->bw_data = 1 + ztest_random(-2ULL);
+
+               *bigH = *pack;
+               *bigT = *pack;
+       }
+}
+
+#undef OD_ARRAY_SIZE
+#define        OD_ARRAY_SIZE   2
+
+void
+ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id)
+{
+       objset_t *os = zd->zd_os;
+       ztest_od_t *od;
+       dmu_tx_t *tx;
+       uint64_t i;
+       int error;
+       int size;
+       uint64_t n, s, txg;
+       bufwad_t *packbuf, *bigbuf;
+       uint64_t packobj, packoff, packsize, bigobj, bigoff, bigsize;
+       uint64_t blocksize = ztest_random_blocksize();
+       uint64_t chunksize = blocksize;
+       uint64_t regions = 997;
+       uint64_t stride = 123456789ULL;
+       uint64_t width = 9;
+       dmu_buf_t *bonus_db;
+       arc_buf_t **bigbuf_arcbufs;
+       dmu_object_info_t doi;
+
+       size = sizeof (ztest_od_t) * OD_ARRAY_SIZE;
+       od = umem_alloc(size, UMEM_NOFAIL);
+
+       /*
+        * This test uses two objects, packobj and bigobj, that are always
+        * updated together (i.e. in the same tx) so that their contents are
+        * in sync and can be compared.  Their contents relate to each other
+        * in a simple way: packobj is a dense array of 'bufwad' structures,
+        * while bigobj is a sparse array of the same bufwads.  Specifically,
+        * for any index n, there are three bufwads that should be identical:
+        *
+        *      packobj, at offset n * sizeof (bufwad_t)
+        *      bigobj, at the head of the nth chunk
+        *      bigobj, at the tail of the nth chunk
+        *
+        * The chunk size is set equal to bigobj block size so that
+        * dmu_assign_arcbuf() can be tested for object updates.
+        */
+
+       /*
+        * Read the directory info.  If it's the first time, set things up.
+        */
+       ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0, 0);
+       ztest_od_init(od + 1, id, FTAG, 1, DMU_OT_UINT64_OTHER, 0, 0,
+           chunksize);
+
+
+       if (ztest_object_init(zd, od, size, B_FALSE) != 0) {
+               umem_free(od, size);
+               return;
+       }
+
+       bigobj = od[0].od_object;
+       packobj = od[1].od_object;
+       blocksize = od[0].od_blocksize;
+       chunksize = blocksize;
+       ASSERT(chunksize == od[1].od_gen);
+
+       VERIFY(dmu_object_info(os, bigobj, &doi) == 0);
+       VERIFY(ISP2(doi.doi_data_block_size));
+       VERIFY(chunksize == doi.doi_data_block_size);
+       VERIFY(chunksize >= 2 * sizeof (bufwad_t));
+
+       /*
+        * Pick a random index and compute the offsets into packobj and bigobj.
+        */
+       n = ztest_random(regions) * stride + ztest_random(width);
+       s = 1 + ztest_random(width - 1);
+
+       packoff = n * sizeof (bufwad_t);
+       packsize = s * sizeof (bufwad_t);
+
+       bigoff = n * chunksize;
+       bigsize = s * chunksize;
+
+       packbuf = umem_zalloc(packsize, UMEM_NOFAIL);
+       bigbuf = umem_zalloc(bigsize, UMEM_NOFAIL);
+
+       VERIFY3U(0, ==, dmu_bonus_hold(os, bigobj, FTAG, &bonus_db));
+
+       bigbuf_arcbufs = umem_zalloc(2 * s * sizeof (arc_buf_t *), UMEM_NOFAIL);
+
+       /*
+        * Iteration 0 test zcopy for DB_UNCACHED dbufs.
+        * Iteration 1 test zcopy to already referenced dbufs.
+        * Iteration 2 test zcopy to dirty dbuf in the same txg.
+        * Iteration 3 test zcopy to dbuf dirty in previous txg.
+        * Iteration 4 test zcopy when dbuf is no longer dirty.
+        * Iteration 5 test zcopy when it can't be done.
+        * Iteration 6 one more zcopy write.
+        */
+       for (i = 0; i < 7; i++) {
+               uint64_t j;
+               uint64_t off;
+
+               /*
+                * In iteration 5 (i == 5) use arcbufs
+                * that don't match bigobj blksz to test
+                * dmu_assign_arcbuf() when it can't directly
+                * assign an arcbuf to a dbuf.
+                */
+               for (j = 0; j < s; j++) {
+                       if (i != 5 || chunksize < (SPA_MINBLOCKSIZE * 2)) {
+                               bigbuf_arcbufs[j] =
+                                   dmu_request_arcbuf(bonus_db, chunksize);
+                       } else {
+                               bigbuf_arcbufs[2 * j] =
+                                   dmu_request_arcbuf(bonus_db, chunksize / 2);
+                               bigbuf_arcbufs[2 * j + 1] =
+                                   dmu_request_arcbuf(bonus_db, chunksize / 2);
+                       }
+               }
+
+               /*
+                * Get a tx for the mods to both packobj and bigobj.
+                */
+               tx = dmu_tx_create(os);
+
+               dmu_tx_hold_write(tx, packobj, packoff, packsize);
+               dmu_tx_hold_write(tx, bigobj, bigoff, bigsize);
+
+               txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+               if (txg == 0) {
+                       umem_free(packbuf, packsize);
+                       umem_free(bigbuf, bigsize);
+                       for (j = 0; j < s; j++) {
+                               if (i != 5 ||
+                                   chunksize < (SPA_MINBLOCKSIZE * 2)) {
+                                       dmu_return_arcbuf(bigbuf_arcbufs[j]);
+                               } else {
+                                       dmu_return_arcbuf(
+                                           bigbuf_arcbufs[2 * j]);
+                                       dmu_return_arcbuf(
+                                           bigbuf_arcbufs[2 * j + 1]);
+                               }
+                       }
+                       umem_free(bigbuf_arcbufs, 2 * s * sizeof (arc_buf_t *));
+                       umem_free(od, size);
+                       dmu_buf_rele(bonus_db, FTAG);
+                       return;
+               }
+
+               /*
+                * 50% of the time don't read objects in the 1st iteration to
+                * test dmu_assign_arcbuf() for the case when there're no
+                * existing dbufs for the specified offsets.
+                */
+               if (i != 0 || ztest_random(2) != 0) {
+                       error = dmu_read(os, packobj, packoff,
+                           packsize, packbuf, DMU_READ_PREFETCH);
+                       ASSERT0(error);
+                       error = dmu_read(os, bigobj, bigoff, bigsize,
+                           bigbuf, DMU_READ_PREFETCH);
+                       ASSERT0(error);
+               }
+               compare_and_update_pbbufs(s, packbuf, bigbuf, bigsize,
+                   n, chunksize, txg);
+
+               /*
+                * We've verified all the old bufwads, and made new ones.
+                * Now write them out.
+                */
+               dmu_write(os, packobj, packoff, packsize, packbuf, tx);
+               if (ztest_opts.zo_verbose >= 7) {
+                       (void) printf("writing offset %llx size %llx"
+                           " txg %llx\n",
+                           (u_longlong_t)bigoff,
+                           (u_longlong_t)bigsize,
+                           (u_longlong_t)txg);
+               }
+               for (off = bigoff, j = 0; j < s; j++, off += chunksize) {
+                       dmu_buf_t *dbt;
+                       if (i != 5 || chunksize < (SPA_MINBLOCKSIZE * 2)) {
+                               bcopy((caddr_t)bigbuf + (off - bigoff),
+                                   bigbuf_arcbufs[j]->b_data, chunksize);
+                       } else {
+                               bcopy((caddr_t)bigbuf + (off - bigoff),
+                                   bigbuf_arcbufs[2 * j]->b_data,
+                                   chunksize / 2);
+                               bcopy((caddr_t)bigbuf + (off - bigoff) +
+                                   chunksize / 2,
+                                   bigbuf_arcbufs[2 * j + 1]->b_data,
+                                   chunksize / 2);
+                       }
+
+                       if (i == 1) {
+                               VERIFY(dmu_buf_hold(os, bigobj, off,
+                                   FTAG, &dbt, DMU_READ_NO_PREFETCH) == 0);
+                       }
+                       if (i != 5 || chunksize < (SPA_MINBLOCKSIZE * 2)) {
+                               dmu_assign_arcbuf(bonus_db, off,
+                                   bigbuf_arcbufs[j], tx);
+                       } else {
+                               dmu_assign_arcbuf(bonus_db, off,
+                                   bigbuf_arcbufs[2 * j], tx);
+                               dmu_assign_arcbuf(bonus_db,
+                                   off + chunksize / 2,
+                                   bigbuf_arcbufs[2 * j + 1], tx);
+                       }
+                       if (i == 1) {
+                               dmu_buf_rele(dbt, FTAG);
+                       }
+               }
+               dmu_tx_commit(tx);
+
+               /*
+                * Sanity check the stuff we just wrote.
+                */
+               {
+                       void *packcheck = umem_alloc(packsize, UMEM_NOFAIL);
+                       void *bigcheck = umem_alloc(bigsize, UMEM_NOFAIL);
+
+                       VERIFY(0 == dmu_read(os, packobj, packoff,
+                           packsize, packcheck, DMU_READ_PREFETCH));
+                       VERIFY(0 == dmu_read(os, bigobj, bigoff,
+                           bigsize, bigcheck, DMU_READ_PREFETCH));
+
+                       ASSERT(bcmp(packbuf, packcheck, packsize) == 0);
+                       ASSERT(bcmp(bigbuf, bigcheck, bigsize) == 0);
+
+                       umem_free(packcheck, packsize);
+                       umem_free(bigcheck, bigsize);
+               }
+               if (i == 2) {
+                       txg_wait_open(dmu_objset_pool(os), 0);
+               } else if (i == 3) {
+                       txg_wait_synced(dmu_objset_pool(os), 0);
+               }
+       }
+
+       dmu_buf_rele(bonus_db, FTAG);
+       umem_free(packbuf, packsize);
+       umem_free(bigbuf, bigsize);
+       umem_free(bigbuf_arcbufs, 2 * s * sizeof (arc_buf_t *));
+       umem_free(od, size);
+}
+
+/* ARGSUSED */
+void
+ztest_dmu_write_parallel(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_od_t *od;
+
+       od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+       uint64_t offset = (1ULL << (ztest_random(20) + 43)) +
+           (ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
+
+       /*
+        * Have multiple threads write to large offsets in an object
+        * to verify that parallel writes to an object -- even to the
+        * same blocks within the object -- doesn't cause any trouble.
+        */
+       ztest_od_init(od, ID_PARALLEL, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
+
+       if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0)
+               return;
+
+       while (ztest_random(10) != 0)
+               ztest_io(zd, od->od_object, offset);
+
+       umem_free(od, sizeof (ztest_od_t));
+}
+
+void
+ztest_dmu_prealloc(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_od_t *od;
+       uint64_t offset = (1ULL << (ztest_random(4) + SPA_MAXBLOCKSHIFT)) +
+           (ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
+       uint64_t count = ztest_random(20) + 1;
+       uint64_t blocksize = ztest_random_blocksize();
+       void *data;
+
+       od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+
+       ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0, 0);
+
+       if (ztest_object_init(zd, od, sizeof (ztest_od_t),
+           !ztest_random(2)) != 0) {
+               umem_free(od, sizeof (ztest_od_t));
+               return;
+       }
+
+       if (ztest_truncate(zd, od->od_object, offset, count * blocksize) != 0) {
+               umem_free(od, sizeof (ztest_od_t));
+               return;
+       }
+
+       ztest_prealloc(zd, od->od_object, offset, count * blocksize);
+
+       data = umem_zalloc(blocksize, UMEM_NOFAIL);
+
+       while (ztest_random(count) != 0) {
+               uint64_t randoff = offset + (ztest_random(count) * blocksize);
+               if (ztest_write(zd, od->od_object, randoff, blocksize,
+                   data) != 0)
+                       break;
+               while (ztest_random(4) != 0)
+                       ztest_io(zd, od->od_object, randoff);
+       }
+
+       umem_free(data, blocksize);
+       umem_free(od, sizeof (ztest_od_t));
+}
+
+/*
+ * Verify that zap_{create,destroy,add,remove,update} work as expected.
+ */
+#define        ZTEST_ZAP_MIN_INTS      1
+#define        ZTEST_ZAP_MAX_INTS      4
+#define        ZTEST_ZAP_MAX_PROPS     1000
+
+void
+ztest_zap(ztest_ds_t *zd, uint64_t id)
+{
+       objset_t *os = zd->zd_os;
+       ztest_od_t *od;
+       uint64_t object;
+       uint64_t txg, last_txg;
+       uint64_t value[ZTEST_ZAP_MAX_INTS];
+       uint64_t zl_ints, zl_intsize, prop;
+       int i, ints;
+       dmu_tx_t *tx;
+       char propname[100], txgname[100];
+       int error;
+       char *hc[2] = { "s.acl.h", ".s.open.h.hyLZlg" };
+
+       od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+       ztest_od_init(od, id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0, 0);
+
+       if (ztest_object_init(zd, od, sizeof (ztest_od_t),
+                       !ztest_random(2)) != 0)
+               goto out;
+
+       object = od->od_object;
+
+       /*
+        * Generate a known hash collision, and verify that
+        * we can lookup and remove both entries.
+        */
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
+       txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+       if (txg == 0)
+               goto out;
+       for (i = 0; i < 2; i++) {
+               value[i] = i;
+               VERIFY3U(0, ==, zap_add(os, object, hc[i], sizeof (uint64_t),
+                   1, &value[i], tx));
+       }
+       for (i = 0; i < 2; i++) {
+               VERIFY3U(EEXIST, ==, zap_add(os, object, hc[i],
+                   sizeof (uint64_t), 1, &value[i], tx));
+               VERIFY3U(0, ==,
+                   zap_length(os, object, hc[i], &zl_intsize, &zl_ints));
+               ASSERT3U(zl_intsize, ==, sizeof (uint64_t));
+               ASSERT3U(zl_ints, ==, 1);
+       }
+       for (i = 0; i < 2; i++) {
+               VERIFY3U(0, ==, zap_remove(os, object, hc[i], tx));
+       }
+       dmu_tx_commit(tx);
+
+       /*
+        * Generate a buch of random entries.
+        */
+       ints = MAX(ZTEST_ZAP_MIN_INTS, object % ZTEST_ZAP_MAX_INTS);
+
+       prop = ztest_random(ZTEST_ZAP_MAX_PROPS);
+       (void) sprintf(propname, "prop_%llu", (u_longlong_t)prop);
+       (void) sprintf(txgname, "txg_%llu", (u_longlong_t)prop);
+       bzero(value, sizeof (value));
+       last_txg = 0;
+
+       /*
+        * If these zap entries already exist, validate their contents.
+        */
+       error = zap_length(os, object, txgname, &zl_intsize, &zl_ints);
+       if (error == 0) {
+               ASSERT3U(zl_intsize, ==, sizeof (uint64_t));
+               ASSERT3U(zl_ints, ==, 1);
+
+               VERIFY(zap_lookup(os, object, txgname, zl_intsize,
+                   zl_ints, &last_txg) == 0);
+
+               VERIFY(zap_length(os, object, propname, &zl_intsize,
+                   &zl_ints) == 0);
+
+               ASSERT3U(zl_intsize, ==, sizeof (uint64_t));
+               ASSERT3U(zl_ints, ==, ints);
+
+               VERIFY(zap_lookup(os, object, propname, zl_intsize,
+                   zl_ints, value) == 0);
+
+               for (i = 0; i < ints; i++) {
+                       ASSERT3U(value[i], ==, last_txg + object + i);
+               }
+       } else {
+               ASSERT3U(error, ==, ENOENT);
+       }
+
+       /*
+        * Atomically update two entries in our zap object.
+        * The first is named txg_%llu, and contains the txg
+        * in which the property was last updated.  The second
+        * is named prop_%llu, and the nth element of its value
+        * should be txg + object + n.
+        */
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
+       txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+       if (txg == 0)
+               goto out;
+
+       if (last_txg > txg)
+               fatal(0, "zap future leak: old %llu new %llu", last_txg, txg);
+
+       for (i = 0; i < ints; i++)
+               value[i] = txg + object + i;
+
+       VERIFY3U(0, ==, zap_update(os, object, txgname, sizeof (uint64_t),
+           1, &txg, tx));
+       VERIFY3U(0, ==, zap_update(os, object, propname, sizeof (uint64_t),
+           ints, value, tx));
+
+       dmu_tx_commit(tx);
+
+       /*
+        * Remove a random pair of entries.
+        */
+       prop = ztest_random(ZTEST_ZAP_MAX_PROPS);
+       (void) sprintf(propname, "prop_%llu", (u_longlong_t)prop);
+       (void) sprintf(txgname, "txg_%llu", (u_longlong_t)prop);
+
+       error = zap_length(os, object, txgname, &zl_intsize, &zl_ints);
+
+       if (error == ENOENT)
+               goto out;
+
+       ASSERT0(error);
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
+       txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+       if (txg == 0)
+               goto out;
+       VERIFY3U(0, ==, zap_remove(os, object, txgname, tx));
+       VERIFY3U(0, ==, zap_remove(os, object, propname, tx));
+       dmu_tx_commit(tx);
+out:
+       umem_free(od, sizeof (ztest_od_t));
+}
+
+/*
+ * Testcase to test the upgrading of a microzap to fatzap.
+ */
+void
+ztest_fzap(ztest_ds_t *zd, uint64_t id)
+{
+       objset_t *os = zd->zd_os;
+       ztest_od_t *od;
+       uint64_t object, txg;
+       int i;
+
+       od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+       ztest_od_init(od, id, FTAG, 0, DMU_OT_ZAP_OTHER, 0, 0, 0);
+
+       if (ztest_object_init(zd, od, sizeof (ztest_od_t),
+                               !ztest_random(2)) != 0)
+               goto out;
+       object = od->od_object;
+
+       /*
+        * Add entries to this ZAP and make sure it spills over
+        * and gets upgraded to a fatzap. Also, since we are adding
+        * 2050 entries we should see ptrtbl growth and leaf-block split.
+        */
+       for (i = 0; i < 2050; i++) {
+               char name[ZFS_MAX_DATASET_NAME_LEN];
+               uint64_t value = i;
+               dmu_tx_t *tx;
+               int error;
+
+               (void) snprintf(name, sizeof (name), "fzap-%llu-%llu",
+                   (u_longlong_t)id, (u_longlong_t)value);
+
+               tx = dmu_tx_create(os);
+               dmu_tx_hold_zap(tx, object, B_TRUE, name);
+               txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+               if (txg == 0)
+                       goto out;
+               error = zap_add(os, object, name, sizeof (uint64_t), 1,
+                   &value, tx);
+               ASSERT(error == 0 || error == EEXIST);
+               dmu_tx_commit(tx);
+       }
+out:
+       umem_free(od, sizeof (ztest_od_t));
+}
+
+/* ARGSUSED */
+void
+ztest_zap_parallel(ztest_ds_t *zd, uint64_t id)
+{
+       objset_t *os = zd->zd_os;
+       ztest_od_t *od;
+       uint64_t txg, object, count, wsize, wc, zl_wsize, zl_wc;
+       dmu_tx_t *tx;
+       int i, namelen, error;
+       int micro = ztest_random(2);
+       char name[20], string_value[20];
+       void *data;
+
+       od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+       ztest_od_init(od, ID_PARALLEL, FTAG, micro, DMU_OT_ZAP_OTHER, 0, 0, 0);
+
+       if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) {
+               umem_free(od, sizeof (ztest_od_t));
+               return;
+       }
+
+       object = od->od_object;
+
+       /*
+        * Generate a random name of the form 'xxx.....' where each
+        * x is a random printable character and the dots are dots.
+        * There are 94 such characters, and the name length goes from
+        * 6 to 20, so there are 94^3 * 15 = 12,458,760 possible names.
+        */
+       namelen = ztest_random(sizeof (name) - 5) + 5 + 1;
+
+       for (i = 0; i < 3; i++)
+               name[i] = '!' + ztest_random('~' - '!' + 1);
+       for (; i < namelen - 1; i++)
+               name[i] = '.';
+       name[i] = '\0';
+
+       if ((namelen & 1) || micro) {
+               wsize = sizeof (txg);
+               wc = 1;
+               data = &txg;
+       } else {
+               wsize = 1;
+               wc = namelen;
+               data = string_value;
+       }
+
+       count = -1ULL;
+       VERIFY0(zap_count(os, object, &count));
+       ASSERT(count != -1ULL);
+
+       /*
+        * Select an operation: length, lookup, add, update, remove.
+        */
+       i = ztest_random(5);
+
+       if (i >= 2) {
+               tx = dmu_tx_create(os);
+               dmu_tx_hold_zap(tx, object, B_TRUE, NULL);
+               txg = ztest_tx_assign(tx, TXG_MIGHTWAIT, FTAG);
+               if (txg == 0) {
+                       umem_free(od, sizeof (ztest_od_t));
+                       return;
+               }
+               bcopy(name, string_value, namelen);
+       } else {
+               tx = NULL;
+               txg = 0;
+               bzero(string_value, namelen);
+       }
+
+       switch (i) {
+
+       case 0:
+               error = zap_length(os, object, name, &zl_wsize, &zl_wc);
+               if (error == 0) {
+                       ASSERT3U(wsize, ==, zl_wsize);
+                       ASSERT3U(wc, ==, zl_wc);
+               } else {
+                       ASSERT3U(error, ==, ENOENT);
+               }
+               break;
+
+       case 1:
+               error = zap_lookup(os, object, name, wsize, wc, data);
+               if (error == 0) {
+                       if (data == string_value &&
+                           bcmp(name, data, namelen) != 0)
+                               fatal(0, "name '%s' != val '%s' len %d",
+                                   name, data, namelen);
+               } else {
+                       ASSERT3U(error, ==, ENOENT);
+               }
+               break;
+
+       case 2:
+               error = zap_add(os, object, name, wsize, wc, data, tx);
+               ASSERT(error == 0 || error == EEXIST);
+               break;
+
+       case 3:
+               VERIFY(zap_update(os, object, name, wsize, wc, data, tx) == 0);
+               break;
+
+       case 4:
+               error = zap_remove(os, object, name, tx);
+               ASSERT(error == 0 || error == ENOENT);
+               break;
+       }
+
+       if (tx != NULL)
+               dmu_tx_commit(tx);
+
+       umem_free(od, sizeof (ztest_od_t));
+}
+
+/*
+ * Commit callback data.
+ */
+typedef struct ztest_cb_data {
+       list_node_t             zcd_node;
+       uint64_t                zcd_txg;
+       int                     zcd_expected_err;
+       boolean_t               zcd_added;
+       boolean_t               zcd_called;
+       spa_t                   *zcd_spa;
+} ztest_cb_data_t;
+
+/* This is the actual commit callback function */
+static void
+ztest_commit_callback(void *arg, int error)
+{
+       ztest_cb_data_t *data = arg;
+       uint64_t synced_txg;
+
+       VERIFY(data != NULL);
+       VERIFY3S(data->zcd_expected_err, ==, error);
+       VERIFY(!data->zcd_called);
+
+       synced_txg = spa_last_synced_txg(data->zcd_spa);
+       if (data->zcd_txg > synced_txg)
+               fatal(0, "commit callback of txg %" PRIu64 " called prematurely"
+                   ", last synced txg = %" PRIu64 "\n", data->zcd_txg,
+                   synced_txg);
+
+       data->zcd_called = B_TRUE;
+
+       if (error == ECANCELED) {
+               ASSERT0(data->zcd_txg);
+               ASSERT(!data->zcd_added);
+
+               /*
+                * The private callback data should be destroyed here, but
+                * since we are going to check the zcd_called field after
+                * dmu_tx_abort(), we will destroy it there.
+                */
+               return;
+       }
+
+       ASSERT(data->zcd_added);
+       ASSERT3U(data->zcd_txg, !=, 0);
+
+       (void) mutex_enter(&zcl.zcl_callbacks_lock);
+
+       /* See if this cb was called more quickly */
+       if ((synced_txg - data->zcd_txg) < zc_min_txg_delay)
+               zc_min_txg_delay = synced_txg - data->zcd_txg;
+
+       /* Remove our callback from the list */
+       list_remove(&zcl.zcl_callbacks, data);
+
+       (void) mutex_exit(&zcl.zcl_callbacks_lock);
+
+       umem_free(data, sizeof (ztest_cb_data_t));
+}
+
+/* Allocate and initialize callback data structure */
+static ztest_cb_data_t *
+ztest_create_cb_data(objset_t *os, uint64_t txg)
+{
+       ztest_cb_data_t *cb_data;
+
+       cb_data = umem_zalloc(sizeof (ztest_cb_data_t), UMEM_NOFAIL);
+
+       cb_data->zcd_txg = txg;
+       cb_data->zcd_spa = dmu_objset_spa(os);
+       list_link_init(&cb_data->zcd_node);
+
+       return (cb_data);
+}
+
+/*
+ * Commit callback test.
+ */
+void
+ztest_dmu_commit_callbacks(ztest_ds_t *zd, uint64_t id)
+{
+       objset_t *os = zd->zd_os;
+       ztest_od_t *od;
+       dmu_tx_t *tx;
+       ztest_cb_data_t *cb_data[3], *tmp_cb;
+       uint64_t old_txg, txg;
+       int i, error = 0;
+
+       od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+       ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
+
+       if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) {
+               umem_free(od, sizeof (ztest_od_t));
+               return;
+       }
+
+       tx = dmu_tx_create(os);
+
+       cb_data[0] = ztest_create_cb_data(os, 0);
+       dmu_tx_callback_register(tx, ztest_commit_callback, cb_data[0]);
+
+       dmu_tx_hold_write(tx, od->od_object, 0, sizeof (uint64_t));
+
+       /* Every once in a while, abort the transaction on purpose */
+       if (ztest_random(100) == 0)
+               error = -1;
+
+       if (!error)
+               error = dmu_tx_assign(tx, TXG_NOWAIT);
+
+       txg = error ? 0 : dmu_tx_get_txg(tx);
+
+       cb_data[0]->zcd_txg = txg;
+       cb_data[1] = ztest_create_cb_data(os, txg);
+       dmu_tx_callback_register(tx, ztest_commit_callback, cb_data[1]);
+
+       if (error) {
+               /*
+                * It's not a strict requirement to call the registered
+                * callbacks from inside dmu_tx_abort(), but that's what
+                * it's supposed to happen in the current implementation
+                * so we will check for that.
+                */
+               for (i = 0; i < 2; i++) {
+                       cb_data[i]->zcd_expected_err = ECANCELED;
+                       VERIFY(!cb_data[i]->zcd_called);
+               }
+
+               dmu_tx_abort(tx);
+
+               for (i = 0; i < 2; i++) {
+                       VERIFY(cb_data[i]->zcd_called);
+                       umem_free(cb_data[i], sizeof (ztest_cb_data_t));
+               }
+
+               umem_free(od, sizeof (ztest_od_t));
+               return;
+       }
+
+       cb_data[2] = ztest_create_cb_data(os, txg);
+       dmu_tx_callback_register(tx, ztest_commit_callback, cb_data[2]);
+
+       /*
+        * Read existing data to make sure there isn't a future leak.
+        */
+       VERIFY(0 == dmu_read(os, od->od_object, 0, sizeof (uint64_t),
+           &old_txg, DMU_READ_PREFETCH));
+
+       if (old_txg > txg)
+               fatal(0, "future leak: got %" PRIu64 ", open txg is %" PRIu64,
+                   old_txg, txg);
+
+       dmu_write(os, od->od_object, 0, sizeof (uint64_t), &txg, tx);
+
+       (void) mutex_enter(&zcl.zcl_callbacks_lock);
+
+       /*
+        * Since commit callbacks don't have any ordering requirement and since
+        * it is theoretically possible for a commit callback to be called
+        * after an arbitrary amount of time has elapsed since its txg has been
+        * synced, it is difficult to reliably determine whether a commit
+        * callback hasn't been called due to high load or due to a flawed
+        * implementation.
+        *
+        * In practice, we will assume that if after a certain number of txgs a
+        * commit callback hasn't been called, then most likely there's an
+        * implementation bug..
+        */
+       tmp_cb = list_head(&zcl.zcl_callbacks);
+       if (tmp_cb != NULL &&
+           tmp_cb->zcd_txg + ZTEST_COMMIT_CB_THRESH < txg) {
+               fatal(0, "Commit callback threshold exceeded, oldest txg: %"
+                   PRIu64 ", open txg: %" PRIu64 "\n", tmp_cb->zcd_txg, txg);
+       }
+
+       /*
+        * Let's find the place to insert our callbacks.
+        *
+        * Even though the list is ordered by txg, it is possible for the
+        * insertion point to not be the end because our txg may already be
+        * quiescing at this point and other callbacks in the open txg
+        * (from other objsets) may have sneaked in.
+        */
+       tmp_cb = list_tail(&zcl.zcl_callbacks);
+       while (tmp_cb != NULL && tmp_cb->zcd_txg > txg)
+               tmp_cb = list_prev(&zcl.zcl_callbacks, tmp_cb);
+
+       /* Add the 3 callbacks to the list */
+       for (i = 0; i < 3; i++) {
+               if (tmp_cb == NULL)
+                       list_insert_head(&zcl.zcl_callbacks, cb_data[i]);
+               else
+                       list_insert_after(&zcl.zcl_callbacks, tmp_cb,
+                           cb_data[i]);
+
+               cb_data[i]->zcd_added = B_TRUE;
+               VERIFY(!cb_data[i]->zcd_called);
+
+               tmp_cb = cb_data[i];
+       }
+
+       zc_cb_counter += 3;
+
+       (void) mutex_exit(&zcl.zcl_callbacks_lock);
+
+       dmu_tx_commit(tx);
+
+       umem_free(od, sizeof (ztest_od_t));
+}
+
+/*
+ * Visit each object in the dataset. Verify that its properties
+ * are consistent what was stored in the block tag when it was created,
+ * and that its unused bonus buffer space has not been overwritten.
+ */
+void
+ztest_verify_dnode_bt(ztest_ds_t *zd, uint64_t id)
+{
+       objset_t *os = zd->zd_os;
+       uint64_t obj;
+       int err = 0;
+
+       for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 0)) {
+               ztest_block_tag_t *bt = NULL;
+               dmu_object_info_t doi;
+               dmu_buf_t *db;
+
+               if (dmu_bonus_hold(os, obj, FTAG, &db) != 0)
+                       continue;
+
+               dmu_object_info_from_db(db, &doi);
+               if (doi.doi_bonus_size >= sizeof (*bt))
+                       bt = ztest_bt_bonus(db);
+
+               if (bt && bt->bt_magic == BT_MAGIC) {
+                       ztest_bt_verify(bt, os, obj, doi.doi_dnodesize,
+                           bt->bt_offset, bt->bt_gen, bt->bt_txg,
+                           bt->bt_crtxg);
+                       ztest_verify_unused_bonus(db, bt, obj, os, bt->bt_gen);
+               }
+
+               dmu_buf_rele(db, FTAG);
+       }
+}
+
+/* ARGSUSED */
+void
+ztest_dsl_prop_get_set(ztest_ds_t *zd, uint64_t id)
+{
+       zfs_prop_t proplist[] = {
+               ZFS_PROP_CHECKSUM,
+               ZFS_PROP_COMPRESSION,
+               ZFS_PROP_COPIES,
+               ZFS_PROP_DEDUP
+       };
+       int p;
+
+       (void) rw_rdlock(&ztest_name_lock);
+
+       for (p = 0; p < sizeof (proplist) / sizeof (proplist[0]); p++)
+               (void) ztest_dsl_prop_set_uint64(zd->zd_name, proplist[p],
+                   ztest_random_dsl_prop(proplist[p]), (int)ztest_random(2));
+
+       VERIFY0(ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_RECORDSIZE,
+           ztest_random_blocksize(), (int)ztest_random(2)));
+
+       (void) rw_unlock(&ztest_name_lock);
+}
+
+/* ARGSUSED */
+void
+ztest_spa_prop_get_set(ztest_ds_t *zd, uint64_t id)
+{
+       nvlist_t *props = NULL;
+
+       (void) rw_rdlock(&ztest_name_lock);
+
+       (void) ztest_spa_prop_set_uint64(ZPOOL_PROP_DEDUPDITTO,
+           ZIO_DEDUPDITTO_MIN + ztest_random(ZIO_DEDUPDITTO_MIN));
+
+       VERIFY0(spa_prop_get(ztest_spa, &props));
+
+       if (ztest_opts.zo_verbose >= 6)
+               dump_nvlist(props, 4);
+
+       nvlist_free(props);
+
+       (void) rw_unlock(&ztest_name_lock);
+}
+
+static int
+user_release_one(const char *snapname, const char *holdname)
+{
+       nvlist_t *snaps, *holds;
+       int error;
+
+       snaps = fnvlist_alloc();
+       holds = fnvlist_alloc();
+       fnvlist_add_boolean(holds, holdname);
+       fnvlist_add_nvlist(snaps, snapname, holds);
+       fnvlist_free(holds);
+       error = dsl_dataset_user_release(snaps, NULL);
+       fnvlist_free(snaps);
+       return (error);
+}
+
+/*
+ * Test snapshot hold/release and deferred destroy.
+ */
+void
+ztest_dmu_snapshot_hold(ztest_ds_t *zd, uint64_t id)
+{
+       int error;
+       objset_t *os = zd->zd_os;
+       objset_t *origin;
+       char snapname[100];
+       char fullname[100];
+       char clonename[100];
+       char tag[100];
+       char osname[ZFS_MAX_DATASET_NAME_LEN];
+       nvlist_t *holds;
+
+       (void) rw_rdlock(&ztest_name_lock);
+
+       dmu_objset_name(os, osname);
+
+       (void) snprintf(snapname, sizeof (snapname), "sh1_%llu",
+           (u_longlong_t)id);
+       (void) snprintf(fullname, sizeof (fullname), "%s@%s", osname, snapname);
+       (void) snprintf(clonename, sizeof (clonename),
+           "%s/ch1_%llu", osname, (u_longlong_t)id);
+       (void) snprintf(tag, sizeof (tag), "tag_%llu", (u_longlong_t)id);
+
+       /*
+        * Clean up from any previous run.
+        */
+       error = dsl_destroy_head(clonename);
+       if (error != ENOENT)
+               ASSERT0(error);
+       error = user_release_one(fullname, tag);
+       if (error != ESRCH && error != ENOENT)
+               ASSERT0(error);
+       error = dsl_destroy_snapshot(fullname, B_FALSE);
+       if (error != ENOENT)
+               ASSERT0(error);
+
+       /*
+        * Create snapshot, clone it, mark snap for deferred destroy,
+        * destroy clone, verify snap was also destroyed.
+        */
+       error = dmu_objset_snapshot_one(osname, snapname);
+       if (error) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc("dmu_objset_snapshot");
+                       goto out;
+               }
+               fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
+       }
+
+       error = dmu_objset_clone(clonename, fullname);
+       if (error) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc("dmu_objset_clone");
+                       goto out;
+               }
+               fatal(0, "dmu_objset_clone(%s) = %d", clonename, error);
+       }
+
+       error = dsl_destroy_snapshot(fullname, B_TRUE);
+       if (error) {
+               fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
+                   fullname, error);
+       }
+
+       error = dsl_destroy_head(clonename);
+       if (error)
+               fatal(0, "dsl_destroy_head(%s) = %d", clonename, error);
+
+       error = dmu_objset_hold(fullname, FTAG, &origin);
+       if (error != ENOENT)
+               fatal(0, "dmu_objset_hold(%s) = %d", fullname, error);
+
+       /*
+        * Create snapshot, add temporary hold, verify that we can't
+        * destroy a held snapshot, mark for deferred destroy,
+        * release hold, verify snapshot was destroyed.
+        */
+       error = dmu_objset_snapshot_one(osname, snapname);
+       if (error) {
+               if (error == ENOSPC) {
+                       ztest_record_enospc("dmu_objset_snapshot");
+                       goto out;
+               }
+               fatal(0, "dmu_objset_snapshot(%s) = %d", fullname, error);
+       }
+
+       holds = fnvlist_alloc();
+       fnvlist_add_string(holds, fullname, tag);
+       error = dsl_dataset_user_hold(holds, 0, NULL);
+       fnvlist_free(holds);
+
+       if (error == ENOSPC) {
+               ztest_record_enospc("dsl_dataset_user_hold");
+               goto out;
+       } else if (error) {
+               fatal(0, "dsl_dataset_user_hold(%s, %s) = %u",
+                   fullname, tag, error);
+       }
+
+       error = dsl_destroy_snapshot(fullname, B_FALSE);
+       if (error != EBUSY) {
+               fatal(0, "dsl_destroy_snapshot(%s, B_FALSE) = %d",
+                   fullname, error);
+       }
+
+       error = dsl_destroy_snapshot(fullname, B_TRUE);
+       if (error) {
+               fatal(0, "dsl_destroy_snapshot(%s, B_TRUE) = %d",
+                   fullname, error);
+       }
+
+       error = user_release_one(fullname, tag);
+       if (error)
+               fatal(0, "user_release_one(%s, %s) = %d", fullname, tag, error);
+
+       VERIFY3U(dmu_objset_hold(fullname, FTAG, &origin), ==, ENOENT);
+
+out:
+       (void) rw_unlock(&ztest_name_lock);
+}
+
+/*
+ * Inject random faults into the on-disk data.
+ */
+/* ARGSUSED */
+void
+ztest_fault_inject(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_shared_t *zs = ztest_shared;
+       spa_t *spa = ztest_spa;
+       int fd;
+       uint64_t offset;
+       uint64_t leaves;
+       uint64_t bad = 0x1990c0ffeedecadeull;
+       uint64_t top, leaf;
+       char *path0;
+       char *pathrand;
+       size_t fsize;
+       int bshift = SPA_MAXBLOCKSHIFT + 2;     /* don't scrog all labels */
+       int iters = 1000;
+       int maxfaults;
+       int mirror_save;
+       vdev_t *vd0 = NULL;
+       uint64_t guid0 = 0;
+       boolean_t islog = B_FALSE;
+
+       path0 = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+       pathrand = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+
+       mutex_enter(&ztest_vdev_lock);
+       maxfaults = MAXFAULTS();
+       leaves = MAX(zs->zs_mirrors, 1) * ztest_opts.zo_raidz;
+       mirror_save = zs->zs_mirrors;
+       mutex_exit(&ztest_vdev_lock);
+
+       ASSERT(leaves >= 1);
+
+       /*
+        * Grab the name lock as reader. There are some operations
+        * which don't like to have their vdevs changed while
+        * they are in progress (i.e. spa_change_guid). Those
+        * operations will have grabbed the name lock as writer.
+        */
+       (void) rw_rdlock(&ztest_name_lock);
+
+       /*
+        * We need SCL_STATE here because we're going to look at vd0->vdev_tsd.
+        */
+       spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
+
+       if (ztest_random(2) == 0) {
+               /*
+                * Inject errors on a normal data device or slog device.
+                */
+               top = ztest_random_vdev_top(spa, B_TRUE);
+               leaf = ztest_random(leaves) + zs->zs_splits;
+
+               /*
+                * Generate paths to the first leaf in this top-level vdev,
+                * and to the random leaf we selected.  We'll induce transient
+                * write failures and random online/offline activity on leaf 0,
+                * and we'll write random garbage to the randomly chosen leaf.
+                */
+               (void) snprintf(path0, MAXPATHLEN, ztest_dev_template,
+                   ztest_opts.zo_dir, ztest_opts.zo_pool,
+                   top * leaves + zs->zs_splits);
+               (void) snprintf(pathrand, MAXPATHLEN, ztest_dev_template,
+                   ztest_opts.zo_dir, ztest_opts.zo_pool,
+                   top * leaves + leaf);
+
+               vd0 = vdev_lookup_by_path(spa->spa_root_vdev, path0);
+               if (vd0 != NULL && vd0->vdev_top->vdev_islog)
+                       islog = B_TRUE;
+
+               /*
+                * If the top-level vdev needs to be resilvered
+                * then we only allow faults on the device that is
+                * resilvering.
+                */
+               if (vd0 != NULL && maxfaults != 1 &&
+                   (!vdev_resilver_needed(vd0->vdev_top, NULL, NULL) ||
+                   vd0->vdev_resilver_txg != 0)) {
+                       /*
+                        * Make vd0 explicitly claim to be unreadable,
+                        * or unwriteable, or reach behind its back
+                        * and close the underlying fd.  We can do this if
+                        * maxfaults == 0 because we'll fail and reexecute,
+                        * and we can do it if maxfaults >= 2 because we'll
+                        * have enough redundancy.  If maxfaults == 1, the
+                        * combination of this with injection of random data
+                        * corruption below exceeds the pool's fault tolerance.
+                        */
+                       vdev_file_t *vf = vd0->vdev_tsd;
+
+                       if (vf != NULL && ztest_random(3) == 0) {
+                               (void) close(vf->vf_vnode->v_fd);
+                               vf->vf_vnode->v_fd = -1;
+                       } else if (ztest_random(2) == 0) {
+                               vd0->vdev_cant_read = B_TRUE;
+                       } else {
+                               vd0->vdev_cant_write = B_TRUE;
+                       }
+                       guid0 = vd0->vdev_guid;
+               }
+       } else {
+               /*
+                * Inject errors on an l2cache device.
+                */
+               spa_aux_vdev_t *sav = &spa->spa_l2cache;
+
+               if (sav->sav_count == 0) {
+                       spa_config_exit(spa, SCL_STATE, FTAG);
+                       (void) rw_unlock(&ztest_name_lock);
+                       goto out;
+               }
+               vd0 = sav->sav_vdevs[ztest_random(sav->sav_count)];
+               guid0 = vd0->vdev_guid;
+               (void) strcpy(path0, vd0->vdev_path);
+               (void) strcpy(pathrand, vd0->vdev_path);
+
+               leaf = 0;
+               leaves = 1;
+               maxfaults = INT_MAX;    /* no limit on cache devices */
+       }
+
+       spa_config_exit(spa, SCL_STATE, FTAG);
+       (void) rw_unlock(&ztest_name_lock);
+
+       /*
+        * If we can tolerate two or more faults, or we're dealing
+        * with a slog, randomly online/offline vd0.
+        */
+       if ((maxfaults >= 2 || islog) && guid0 != 0) {
+               if (ztest_random(10) < 6) {
+                       int flags = (ztest_random(2) == 0 ?
+                           ZFS_OFFLINE_TEMPORARY : 0);
+
+                       /*
+                        * We have to grab the zs_name_lock as writer to
+                        * prevent a race between offlining a slog and
+                        * destroying a dataset. Offlining the slog will
+                        * grab a reference on the dataset which may cause
+                        * dsl_destroy_head() to fail with EBUSY thus
+                        * leaving the dataset in an inconsistent state.
+                        */
+                       if (islog)
+                               (void) rw_wrlock(&ztest_name_lock);
+
+                       VERIFY(vdev_offline(spa, guid0, flags) != EBUSY);
+
+                       if (islog)
+                               (void) rw_unlock(&ztest_name_lock);
+               } else {
+                       /*
+                        * Ideally we would like to be able to randomly
+                        * call vdev_[on|off]line without holding locks
+                        * to force unpredictable failures but the side
+                        * effects of vdev_[on|off]line prevent us from
+                        * doing so. We grab the ztest_vdev_lock here to
+                        * prevent a race between injection testing and
+                        * aux_vdev removal.
+                        */
+                       mutex_enter(&ztest_vdev_lock);
+                       (void) vdev_online(spa, guid0, 0, NULL);
+                       mutex_exit(&ztest_vdev_lock);
+               }
+       }
+
+       if (maxfaults == 0)
+               goto out;
+
+       /*
+        * We have at least single-fault tolerance, so inject data corruption.
+        */
+       fd = open(pathrand, O_RDWR);
+
+       if (fd == -1)   /* we hit a gap in the device namespace */
+               goto out;
+
+       fsize = lseek(fd, 0, SEEK_END);
+
+       while (--iters != 0) {
+               /*
+                * The offset must be chosen carefully to ensure that
+                * we do not inject a given logical block with errors
+                * on two different leaf devices, because ZFS can not
+                * tolerate that (if maxfaults==1).
+                *
+                * We divide each leaf into chunks of size
+                * (# leaves * SPA_MAXBLOCKSIZE * 4).  Within each chunk
+                * there is a series of ranges to which we can inject errors.
+                * Each range can accept errors on only a single leaf vdev.
+                * The error injection ranges are separated by ranges
+                * which we will not inject errors on any device (DMZs).
+                * Each DMZ must be large enough such that a single block
+                * can not straddle it, so that a single block can not be
+                * a target in two different injection ranges (on different
+                * leaf vdevs).
+                *
+                * For example, with 3 leaves, each chunk looks like:
+                *    0 to  32M: injection range for leaf 0
+                *  32M to  64M: DMZ - no injection allowed
+                *  64M to  96M: injection range for leaf 1
+                *  96M to 128M: DMZ - no injection allowed
+                * 128M to 160M: injection range for leaf 2
+                * 160M to 192M: DMZ - no injection allowed
+                */
+               offset = ztest_random(fsize / (leaves << bshift)) *
+                   (leaves << bshift) + (leaf << bshift) +
+                   (ztest_random(1ULL << (bshift - 1)) & -8ULL);
+
+               if (offset >= fsize)
+                       continue;
+
+               mutex_enter(&ztest_vdev_lock);
+               if (mirror_save != zs->zs_mirrors) {
+                       mutex_exit(&ztest_vdev_lock);
+                       (void) close(fd);
+                       goto out;
+               }
+
+               if (pwrite(fd, &bad, sizeof (bad), offset) != sizeof (bad))
+                       fatal(1, "can't inject bad word at 0x%llx in %s",
+                           offset, pathrand);
+
+               mutex_exit(&ztest_vdev_lock);
+
+               if (ztest_opts.zo_verbose >= 7)
+                       (void) printf("injected bad word into %s,"
+                           " offset 0x%llx\n", pathrand, (u_longlong_t)offset);
+       }
+
+       (void) close(fd);
+out:
+       umem_free(path0, MAXPATHLEN);
+       umem_free(pathrand, MAXPATHLEN);
+}
+
+/*
+ * Verify that DDT repair works as expected.
+ */
+void
+ztest_ddt_repair(ztest_ds_t *zd, uint64_t id)
+{
+       ztest_shared_t *zs = ztest_shared;
+       spa_t *spa = ztest_spa;
+       objset_t *os = zd->zd_os;
+       ztest_od_t *od;
+       uint64_t object, blocksize, txg, pattern, psize;
+       enum zio_checksum checksum = spa_dedup_checksum(spa);
+       dmu_buf_t *db;
+       dmu_tx_t *tx;
+       void *buf;
+       blkptr_t blk;
+       int copies = 2 * ZIO_DEDUPDITTO_MIN;
+       int i;
+
+       blocksize = ztest_random_blocksize();
+       blocksize = MIN(blocksize, 2048);       /* because we write so many */
+
+       od = umem_alloc(sizeof (ztest_od_t), UMEM_NOFAIL);
+       ztest_od_init(od, id, FTAG, 0, DMU_OT_UINT64_OTHER, blocksize, 0, 0);
+
+       if (ztest_object_init(zd, od, sizeof (ztest_od_t), B_FALSE) != 0) {
+               umem_free(od, sizeof (ztest_od_t));
+               return;
+       }
+
+       /*
+        * Take the name lock as writer to prevent anyone else from changing
+        * the pool and dataset properies we need to maintain during this test.
+        */
+       (void) rw_wrlock(&ztest_name_lock);
+
+       if (ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_DEDUP, checksum,
+           B_FALSE) != 0 ||
+           ztest_dsl_prop_set_uint64(zd->zd_name, ZFS_PROP_COPIES, 1,
+           B_FALSE) != 0) {
+               (void) rw_unlock(&ztest_name_lock);
+               umem_free(od, sizeof (ztest_od_t));
+               return;
+       }
+
+       object = od[0].od_object;
+       blocksize = od[0].od_blocksize;
+       pattern = zs->zs_guid ^ dmu_objset_fsid_guid(os);
+
+       ASSERT(object != 0);
+
+       tx = dmu_tx_create(os);
+       dmu_tx_hold_write(tx, object, 0, copies * blocksize);
+       txg = ztest_tx_assign(tx, TXG_WAIT, FTAG);
+       if (txg == 0) {
+               (void) rw_unlock(&ztest_name_lock);
+               umem_free(od, sizeof (ztest_od_t));
+               return;
+       }
+
+       /*
+        * Write all the copies of our block.
+        */
+       for (i = 0; i < copies; i++) {
+               uint64_t offset = i * blocksize;
+               int error = dmu_buf_hold(os, object, offset, FTAG, &db,
+                   DMU_READ_NO_PREFETCH);
+               if (error != 0) {
+                       fatal(B_FALSE, "dmu_buf_hold(%p, %llu, %llu) = %u",
+                           os, (long long)object, (long long) offset, error);
+               }
+               ASSERT(db->db_offset == offset);
+               ASSERT(db->db_size == blocksize);
+               ASSERT(ztest_pattern_match(db->db_data, db->db_size, pattern) ||
+                   ztest_pattern_match(db->db_data, db->db_size, 0ULL));
+               dmu_buf_will_fill(db, tx);
+               ztest_pattern_set(db->db_data, db->db_size, pattern);
+               dmu_buf_rele(db, FTAG);
+       }
+
+       dmu_tx_commit(tx);
+       txg_wait_synced(spa_get_dsl(spa), txg);
+
+       /*
+        * Find out what block we got.
+        */
+       VERIFY0(dmu_buf_hold(os, object, 0, FTAG, &db,
+           DMU_READ_NO_PREFETCH));
+       blk = *((dmu_buf_impl_t *)db)->db_blkptr;
+       dmu_buf_rele(db, FTAG);
+
+       /*
+        * Damage the block.  Dedup-ditto will save us when we read it later.
+        */
+       psize = BP_GET_PSIZE(&blk);
+       buf = zio_buf_alloc(psize);
+       ztest_pattern_set(buf, psize, ~pattern);
+
+       (void) zio_wait(zio_rewrite(NULL, spa, 0, &blk,
+           buf, psize, NULL, NULL, ZIO_PRIORITY_SYNC_WRITE,
+           ZIO_FLAG_CANFAIL | ZIO_FLAG_INDUCE_DAMAGE, NULL));
+
+       zio_buf_free(buf, psize);
+
+       (void) rw_unlock(&ztest_name_lock);
+       umem_free(od, sizeof (ztest_od_t));
+}
+
+/*
+ * Scrub the pool.
+ */
+/* ARGSUSED */
+void
+ztest_scrub(ztest_ds_t *zd, uint64_t id)
+{
+       spa_t *spa = ztest_spa;
+
+       (void) spa_scan(spa, POOL_SCAN_SCRUB);
+       (void) poll(NULL, 0, 100); /* wait a moment, then force a restart */
+       (void) spa_scan(spa, POOL_SCAN_SCRUB);
+}
+
+/*
+ * Change the guid for the pool.
+ */
+/* ARGSUSED */
+void
+ztest_reguid(ztest_ds_t *zd, uint64_t id)
+{
+       spa_t *spa = ztest_spa;
+       uint64_t orig, load;
+       int error;
+
+       orig = spa_guid(spa);
+       load = spa_load_guid(spa);
+
+       (void) rw_wrlock(&ztest_name_lock);
+       error = spa_change_guid(spa);
+       (void) rw_unlock(&ztest_name_lock);
+
+       if (error != 0)
+               return;
+
+       if (ztest_opts.zo_verbose >= 4) {
+               (void) printf("Changed guid old %llu -> %llu\n",
+                   (u_longlong_t)orig, (u_longlong_t)spa_guid(spa));
+       }
+
+       VERIFY3U(orig, !=, spa_guid(spa));
+       VERIFY3U(load, ==, spa_load_guid(spa));
+}
+
+/*
+ * Rename the pool to a different name and then rename it back.
+ */
+/* ARGSUSED */
+void
+ztest_spa_rename(ztest_ds_t *zd, uint64_t id)
+{
+       char *oldname, *newname;
+       spa_t *spa;
+
+       (void) rw_wrlock(&ztest_name_lock);
+
+       oldname = ztest_opts.zo_pool;
+       newname = umem_alloc(strlen(oldname) + 5, UMEM_NOFAIL);
+       (void) strcpy(newname, oldname);
+       (void) strcat(newname, "_tmp");
+
+       /*
+        * Do the rename
+        */
+       VERIFY3U(0, ==, spa_rename(oldname, newname));
+
+       /*
+        * Try to open it under the old name, which shouldn't exist
+        */
+       VERIFY3U(ENOENT, ==, spa_open(oldname, &spa, FTAG));
+
+       /*
+        * Open it under the new name and make sure it's still the same spa_t.
+        */
+       VERIFY3U(0, ==, spa_open(newname, &spa, FTAG));
+
+       ASSERT(spa == ztest_spa);
+       spa_close(spa, FTAG);
+
+       /*
+        * Rename it back to the original
+        */
+       VERIFY3U(0, ==, spa_rename(newname, oldname));
+
+       /*
+        * Make sure it can still be opened
+        */
+       VERIFY3U(0, ==, spa_open(oldname, &spa, FTAG));
+
+       ASSERT(spa == ztest_spa);
+       spa_close(spa, FTAG);
+
+       umem_free(newname, strlen(newname) + 1);
+
+       (void) rw_unlock(&ztest_name_lock);
+}
+
+void
+ztest_fletcher(ztest_ds_t *zd, uint64_t id)
+{
+       hrtime_t end = gethrtime() + NANOSEC;
+
+       while (gethrtime() <= end) {
+               int run_count = 100;
+               void *buf;
+               uint32_t size;
+               int *ptr;
+               int i;
+               zio_cksum_t zc_ref;
+               zio_cksum_t zc_ref_byteswap;
+
+               size = ztest_random_blocksize();
+               buf = umem_alloc(size, UMEM_NOFAIL);
+
+               for (i = 0, ptr = buf; i < size / sizeof (*ptr); i++, ptr++)
+                       *ptr = ztest_random(UINT_MAX);
+
+               VERIFY0(fletcher_4_impl_set("scalar"));
+               fletcher_4_native(buf, size, NULL, &zc_ref);
+               fletcher_4_byteswap(buf, size, NULL, &zc_ref_byteswap);
+
+               VERIFY0(fletcher_4_impl_set("cycle"));
+               while (run_count-- > 0) {
+                       zio_cksum_t zc;
+                       zio_cksum_t zc_byteswap;
+
+                       fletcher_4_byteswap(buf, size, NULL, &zc_byteswap);
+                       fletcher_4_native(buf, size, NULL, &zc);
+
+                       VERIFY0(bcmp(&zc, &zc_ref, sizeof (zc)));
+                       VERIFY0(bcmp(&zc_byteswap, &zc_ref_byteswap,
+                           sizeof (zc_byteswap)));
+               }
+
+               umem_free(buf, size);
+       }
+}
+
+void
+ztest_fletcher_incr(ztest_ds_t *zd, uint64_t id)
+{
+       void *buf;
+       size_t size;
+       int *ptr;
+       int i;
+       zio_cksum_t zc_ref;
+       zio_cksum_t zc_ref_bswap;
+
+       hrtime_t end = gethrtime() + NANOSEC;
+
+       while (gethrtime() <= end) {
+               int run_count = 100;
+
+               size = ztest_random_blocksize();
+               buf = umem_alloc(size, UMEM_NOFAIL);
+
+               for (i = 0, ptr = buf; i < size / sizeof (*ptr); i++, ptr++)
+                       *ptr = ztest_random(UINT_MAX);
+
+               VERIFY0(fletcher_4_impl_set("scalar"));
+               fletcher_4_native(buf, size, NULL, &zc_ref);
+               fletcher_4_byteswap(buf, size, NULL, &zc_ref_bswap);
+
+               VERIFY0(fletcher_4_impl_set("cycle"));
+
+               while (run_count-- > 0) {
+                       zio_cksum_t zc;
+                       zio_cksum_t zc_bswap;
+                       size_t pos = 0;
+
+                       ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
+                       ZIO_SET_CHECKSUM(&zc_bswap, 0, 0, 0, 0);
+
+                       while (pos < size) {
+                               size_t inc = 64 * ztest_random(size / 67);
+                               /* sometimes add few bytes to test non-simd */
+                               if (ztest_random(100) < 10)
+                                       inc += P2ALIGN(ztest_random(64),
+                                           sizeof (uint32_t));
+
+                               if (inc > (size - pos))
+                                       inc = size - pos;
+
+                               fletcher_4_incremental_native(buf + pos, inc,
+                                   &zc);
+                               fletcher_4_incremental_byteswap(buf + pos, inc,
+                                   &zc_bswap);
+
+                               pos += inc;
+                       }
+
+                       VERIFY3U(pos, ==, size);
+
+                       VERIFY(ZIO_CHECKSUM_EQUAL(zc, zc_ref));
+                       VERIFY(ZIO_CHECKSUM_EQUAL(zc_bswap, zc_ref_bswap));
+
+                       /*
+                        * verify if incremental on the whole buffer is
+                        * equivalent to non-incremental version
+                        */
+                       ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
+                       ZIO_SET_CHECKSUM(&zc_bswap, 0, 0, 0, 0);
+
+                       fletcher_4_incremental_native(buf, size, &zc);
+                       fletcher_4_incremental_byteswap(buf, size, &zc_bswap);
+
+                       VERIFY(ZIO_CHECKSUM_EQUAL(zc, zc_ref));
+                       VERIFY(ZIO_CHECKSUM_EQUAL(zc_bswap, zc_ref_bswap));
+               }
+
+               umem_free(buf, size);
+       }
+}
+
+static int
+ztest_check_path(char *path)
+{
+       struct stat s;
+       /* return true on success */
+       return (!stat(path, &s));
+}
+
+static void
+ztest_get_zdb_bin(char *bin, int len)
+{
+       char *zdb_path;
+       /*
+        * Try to use ZDB_PATH and in-tree zdb path. If not successful, just
+        * let popen to search through PATH.
+        */
+       if ((zdb_path = getenv("ZDB_PATH"))) {
+               strlcpy(bin, zdb_path, len); /* In env */
+               if (!ztest_check_path(bin)) {
+                       ztest_dump_core = 0;
+                       fatal(1, "invalid ZDB_PATH '%s'", bin);
+               }
+               return;
+       }
+
+       VERIFY(realpath(getexecname(), bin) != NULL);
+       if (strstr(bin, "/ztest/")) {
+               strstr(bin, "/ztest/")[0] = '\0'; /* In-tree */
+               strcat(bin, "/zdb/zdb");
+               if (ztest_check_path(bin))
+                       return;
+       }
+       strcpy(bin, "zdb");
+}
+
+/*
+ * Verify pool integrity by running zdb.
+ */
+static void
+ztest_run_zdb(char *pool)
+{
+       int status;
+       char *bin;
+       char *zdb;
+       char *zbuf;
+       const int len = MAXPATHLEN + MAXNAMELEN + 20;
+       FILE *fp;
+
+       bin = umem_alloc(len, UMEM_NOFAIL);
+       zdb = umem_alloc(len, UMEM_NOFAIL);
+       zbuf = umem_alloc(1024, UMEM_NOFAIL);
+
+       ztest_get_zdb_bin(bin, len);
+
+       (void) sprintf(zdb,
+           "%s -bcc%s%s -d -U %s %s",
+           bin,
+           ztest_opts.zo_verbose >= 3 ? "s" : "",
+           ztest_opts.zo_verbose >= 4 ? "v" : "",
+           spa_config_path,
+           pool);
+
+       if (ztest_opts.zo_verbose >= 5)
+               (void) printf("Executing %s\n", strstr(zdb, "zdb "));
+
+       fp = popen(zdb, "r");
+
+       while (fgets(zbuf, 1024, fp) != NULL)
+               if (ztest_opts.zo_verbose >= 3)
+                       (void) printf("%s", zbuf);
+
+       status = pclose(fp);
+
+       if (status == 0)
+               goto out;
+
+       ztest_dump_core = 0;
+       if (WIFEXITED(status))
+               fatal(0, "'%s' exit code %d", zdb, WEXITSTATUS(status));
+       else
+               fatal(0, "'%s' died with signal %d", zdb, WTERMSIG(status));
+out:
+       umem_free(bin, len);
+       umem_free(zdb, len);
+       umem_free(zbuf, 1024);
+}
+
+static void
+ztest_walk_pool_directory(char *header)
+{
+       spa_t *spa = NULL;
+
+       if (ztest_opts.zo_verbose >= 6)
+               (void) printf("%s\n", header);
+
+       mutex_enter(&spa_namespace_lock);
+       while ((spa = spa_next(spa)) != NULL)
+               if (ztest_opts.zo_verbose >= 6)
+                       (void) printf("\t%s\n", spa_name(spa));
+       mutex_exit(&spa_namespace_lock);
+}
+
+static void
+ztest_spa_import_export(char *oldname, char *newname)
+{
+       nvlist_t *config, *newconfig;
+       uint64_t pool_guid;
+       spa_t *spa;
+       int error;
+
+       if (ztest_opts.zo_verbose >= 4) {
+               (void) printf("import/export: old = %s, new = %s\n",
+                   oldname, newname);
+       }
+
+       /*
+        * Clean up from previous runs.
+        */
+       (void) spa_destroy(newname);
+
+       /*
+        * Get the pool's configuration and guid.
+        */
+       VERIFY3U(0, ==, spa_open(oldname, &spa, FTAG));
+
+       /*
+        * Kick off a scrub to tickle scrub/export races.
+        */
+       if (ztest_random(2) == 0)
+               (void) spa_scan(spa, POOL_SCAN_SCRUB);
+
+       pool_guid = spa_guid(spa);
+       spa_close(spa, FTAG);
+
+       ztest_walk_pool_directory("pools before export");
+
+       /*
+        * Export it.
+        */
+       VERIFY3U(0, ==, spa_export(oldname, &config, B_FALSE, B_FALSE));
+
+       ztest_walk_pool_directory("pools after export");
+
+       /*
+        * Try to import it.
+        */
+       newconfig = spa_tryimport(config);
+       ASSERT(newconfig != NULL);
+       nvlist_free(newconfig);
+
+       /*
+        * Import it under the new name.
+        */
+       error = spa_import(newname, config, NULL, 0);
+       if (error != 0) {
+               dump_nvlist(config, 0);
+               fatal(B_FALSE, "couldn't import pool %s as %s: error %u",
+                   oldname, newname, error);
+       }
+
+       ztest_walk_pool_directory("pools after import");
+
+       /*
+        * Try to import it again -- should fail with EEXIST.
+        */
+       VERIFY3U(EEXIST, ==, spa_import(newname, config, NULL, 0));
+
+       /*
+        * Try to import it under a different name -- should fail with EEXIST.
+        */
+       VERIFY3U(EEXIST, ==, spa_import(oldname, config, NULL, 0));
+
+       /*
+        * Verify that the pool is no longer visible under the old name.
+        */
+       VERIFY3U(ENOENT, ==, spa_open(oldname, &spa, FTAG));
+
+       /*
+        * Verify that we can open and close the pool using the new name.
+        */
+       VERIFY3U(0, ==, spa_open(newname, &spa, FTAG));
+       ASSERT(pool_guid == spa_guid(spa));
+       spa_close(spa, FTAG);
+
+       nvlist_free(config);
+}
+
+static void
+ztest_resume(spa_t *spa)
+{
+       if (spa_suspended(spa) && ztest_opts.zo_verbose >= 6)
+               (void) printf("resuming from suspended state\n");
+       spa_vdev_state_enter(spa, SCL_NONE);
+       vdev_clear(spa, NULL);
+       (void) spa_vdev_state_exit(spa, NULL, 0);
+       (void) zio_resume(spa);
+}
+
+static void *
+ztest_resume_thread(void *arg)
+{
+       spa_t *spa = arg;
+
+       while (!ztest_exiting) {
+               if (spa_suspended(spa))
+                       ztest_resume(spa);
+               (void) poll(NULL, 0, 100);
+
+               /*
+                * Periodically change the zfs_compressed_arc_enabled setting.
+                */
+               if (ztest_random(10) == 0)
+                       zfs_compressed_arc_enabled = ztest_random(2);
+       }
+
+       thread_exit();
+
+       return (NULL);
+}
+
+#define        GRACE   300
+
+#if 0
+static void
+ztest_deadman_alarm(int sig)
+{
+       fatal(0, "failed to complete within %d seconds of deadline", GRACE);
+}
+#endif
+
+static void
+ztest_execute(int test, ztest_info_t *zi, uint64_t id)
+{
+       ztest_ds_t *zd = &ztest_ds[id % ztest_opts.zo_datasets];
+       ztest_shared_callstate_t *zc = ZTEST_GET_SHARED_CALLSTATE(test);
+       hrtime_t functime = gethrtime();
+       int i;
+
+       for (i = 0; i < zi->zi_iters; i++)
+               zi->zi_func(zd, id);
+
+       functime = gethrtime() - functime;
+
+       atomic_add_64(&zc->zc_count, 1);
+       atomic_add_64(&zc->zc_time, functime);
+
+       if (ztest_opts.zo_verbose >= 4)
+               (void) printf("%6.2f sec in %s\n",
+                   (double)functime / NANOSEC, zi->zi_funcname);
+}
+
+static void *
+ztest_thread(void *arg)
+{
+       int rand;
+       uint64_t id = (uintptr_t)arg;
+       ztest_shared_t *zs = ztest_shared;
+       uint64_t call_next;
+       hrtime_t now;
+       ztest_info_t *zi;
+       ztest_shared_callstate_t *zc;
+
+       while ((now = gethrtime()) < zs->zs_thread_stop) {
+               /*
+                * See if it's time to force a crash.
+                */
+               if (now > zs->zs_thread_kill)
+                       ztest_kill(zs);
+
+               /*
+                * If we're getting ENOSPC with some regularity, stop.
+                */
+               if (zs->zs_enospc_count > 10)
+                       break;
+
+               /*
+                * Pick a random function to execute.
+                */
+               rand = ztest_random(ZTEST_FUNCS);
+               zi = &ztest_info[rand];
+               zc = ZTEST_GET_SHARED_CALLSTATE(rand);
+               call_next = zc->zc_next;
+
+               if (now >= call_next &&
+                   atomic_cas_64(&zc->zc_next, call_next, call_next +
+                   ztest_random(2 * zi->zi_interval[0] + 1)) == call_next) {
+                       ztest_execute(rand, zi, id);
+               }
+       }
+
+       thread_exit();
+
+       return (NULL);
+}
+
+static void
+ztest_dataset_name(char *dsname, char *pool, int d)
+{
+       (void) snprintf(dsname, ZFS_MAX_DATASET_NAME_LEN, "%s/ds_%d", pool, d);
+}
+
+static void
+ztest_dataset_destroy(int d)
+{
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       int t;
+
+       ztest_dataset_name(name, ztest_opts.zo_pool, d);
+
+       if (ztest_opts.zo_verbose >= 3)
+               (void) printf("Destroying %s to free up space\n", name);
+
+       /*
+        * Cleanup any non-standard clones and snapshots.  In general,
+        * ztest thread t operates on dataset (t % zopt_datasets),
+        * so there may be more than one thing to clean up.
+        */
+       for (t = d; t < ztest_opts.zo_threads;
+           t += ztest_opts.zo_datasets)
+               ztest_dsl_dataset_cleanup(name, t);
+
+       (void) dmu_objset_find(name, ztest_objset_destroy_cb, NULL,
+           DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
+}
+
+static void
+ztest_dataset_dirobj_verify(ztest_ds_t *zd)
+{
+       uint64_t usedobjs, dirobjs, scratch;
+
+       /*
+        * ZTEST_DIROBJ is the object directory for the entire dataset.
+        * Therefore, the number of objects in use should equal the
+        * number of ZTEST_DIROBJ entries, +1 for ZTEST_DIROBJ itself.
+        * If not, we have an object leak.
+        *
+        * Note that we can only check this in ztest_dataset_open(),
+        * when the open-context and syncing-context values agree.
+        * That's because zap_count() returns the open-context value,
+        * while dmu_objset_space() returns the rootbp fill count.
+        */
+       VERIFY3U(0, ==, zap_count(zd->zd_os, ZTEST_DIROBJ, &dirobjs));
+       dmu_objset_space(zd->zd_os, &scratch, &scratch, &usedobjs, &scratch);
+       ASSERT3U(dirobjs + 1, ==, usedobjs);
+}
+
+static int
+ztest_dataset_open(int d)
+{
+       ztest_ds_t *zd = &ztest_ds[d];
+       uint64_t committed_seq = ZTEST_GET_SHARED_DS(d)->zd_seq;
+       objset_t *os;
+       zilog_t *zilog;
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       int error;
+
+       ztest_dataset_name(name, ztest_opts.zo_pool, d);
+
+       (void) rw_rdlock(&ztest_name_lock);
+
+       error = ztest_dataset_create(name);
+       if (error == ENOSPC) {
+               (void) rw_unlock(&ztest_name_lock);
+               ztest_record_enospc(FTAG);
+               return (error);
+       }
+       ASSERT(error == 0 || error == EEXIST);
+
+       VERIFY0(dmu_objset_own(name, DMU_OST_OTHER, B_FALSE, zd, &os));
+       (void) rw_unlock(&ztest_name_lock);
+
+       ztest_zd_init(zd, ZTEST_GET_SHARED_DS(d), os);
+
+       zilog = zd->zd_zilog;
+
+       if (zilog->zl_header->zh_claim_lr_seq != 0 &&
+           zilog->zl_header->zh_claim_lr_seq < committed_seq)
+               fatal(0, "missing log records: claimed %llu < committed %llu",
+                   zilog->zl_header->zh_claim_lr_seq, committed_seq);
+
+       ztest_dataset_dirobj_verify(zd);
+
+       zil_replay(os, zd, ztest_replay_vector);
+
+       ztest_dataset_dirobj_verify(zd);
+
+       if (ztest_opts.zo_verbose >= 6)
+               (void) printf("%s replay %llu blocks, %llu records, seq %llu\n",
+                   zd->zd_name,
+                   (u_longlong_t)zilog->zl_parse_blk_count,
+                   (u_longlong_t)zilog->zl_parse_lr_count,
+                   (u_longlong_t)zilog->zl_replaying_seq);
+
+       zilog = zil_open(os, ztest_get_data);
+
+       if (zilog->zl_replaying_seq != 0 &&
+           zilog->zl_replaying_seq < committed_seq)
+               fatal(0, "missing log records: replayed %llu < committed %llu",
+                   zilog->zl_replaying_seq, committed_seq);
+
+       return (0);
+}
+
+static void
+ztest_dataset_close(int d)
+{
+       ztest_ds_t *zd = &ztest_ds[d];
+
+       zil_close(zd->zd_zilog);
+       dmu_objset_disown(zd->zd_os, zd);
+
+       ztest_zd_fini(zd);
+}
+
+/*
+ * Kick off threads to run tests on all datasets in parallel.
+ */
+static void
+ztest_run(ztest_shared_t *zs)
+{
+       kt_did_t *tid;
+       spa_t *spa;
+       objset_t *os;
+       kthread_t *resume_thread;
+       uint64_t object;
+       int error;
+       int t, d;
+
+       ztest_exiting = B_FALSE;
+
+       /*
+        * Initialize parent/child shared state.
+        */
+       mutex_init(&ztest_vdev_lock, NULL, MUTEX_DEFAULT, NULL);
+       VERIFY(rwlock_init(&ztest_name_lock, USYNC_THREAD, NULL) == 0);
+
+       zs->zs_thread_start = gethrtime();
+       zs->zs_thread_stop =
+           zs->zs_thread_start + ztest_opts.zo_passtime * NANOSEC;
+       zs->zs_thread_stop = MIN(zs->zs_thread_stop, zs->zs_proc_stop);
+       zs->zs_thread_kill = zs->zs_thread_stop;
+       if (ztest_random(100) < ztest_opts.zo_killrate) {
+               zs->zs_thread_kill -=
+                   ztest_random(ztest_opts.zo_passtime * NANOSEC);
+       }
+
+       mutex_init(&zcl.zcl_callbacks_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       list_create(&zcl.zcl_callbacks, sizeof (ztest_cb_data_t),
+           offsetof(ztest_cb_data_t, zcd_node));
+
+       /*
+        * Open our pool.
+        */
+       kernel_init(FREAD | FWRITE);
+       VERIFY0(spa_open(ztest_opts.zo_pool, &spa, FTAG));
+       spa->spa_debug = B_TRUE;
+       metaslab_preload_limit = ztest_random(20) + 1;
+       ztest_spa = spa;
+
+       VERIFY0(dmu_objset_own(ztest_opts.zo_pool,
+           DMU_OST_ANY, B_TRUE, FTAG, &os));
+       zs->zs_guid = dmu_objset_fsid_guid(os);
+       dmu_objset_disown(os, FTAG);
+
+       spa->spa_dedup_ditto = 2 * ZIO_DEDUPDITTO_MIN;
+
+       /*
+        * We don't expect the pool to suspend unless maxfaults == 0,
+        * in which case ztest_fault_inject() temporarily takes away
+        * the only valid replica.
+        */
+       if (MAXFAULTS() == 0)
+               spa->spa_failmode = ZIO_FAILURE_MODE_WAIT;
+       else
+               spa->spa_failmode = ZIO_FAILURE_MODE_PANIC;
+
+       /*
+        * Create a thread to periodically resume suspended I/O.
+        */
+       VERIFY3P((resume_thread = zk_thread_create(NULL, 0,
+           (thread_func_t)ztest_resume_thread, spa, TS_RUN, NULL, 0, 0,
+           PTHREAD_CREATE_JOINABLE)), !=, NULL);
+
+#if 0
+       /*
+        * Set a deadman alarm to abort() if we hang.
+        */
+       signal(SIGALRM, ztest_deadman_alarm);
+       alarm((zs->zs_thread_stop - zs->zs_thread_start) / NANOSEC + GRACE);
+#endif
+
+       /*
+        * Verify that we can safely inquire about about any object,
+        * whether it's allocated or not.  To make it interesting,
+        * we probe a 5-wide window around each power of two.
+        * This hits all edge cases, including zero and the max.
+        */
+       for (t = 0; t < 64; t++) {
+               for (d = -5; d <= 5; d++) {
+                       error = dmu_object_info(spa->spa_meta_objset,
+                           (1ULL << t) + d, NULL);
+                       ASSERT(error == 0 || error == ENOENT ||
+                           error == EINVAL);
+               }
+       }
+
+       /*
+        * If we got any ENOSPC errors on the previous run, destroy something.
+        */
+       if (zs->zs_enospc_count != 0) {
+               int d = ztest_random(ztest_opts.zo_datasets);
+               ztest_dataset_destroy(d);
+       }
+       zs->zs_enospc_count = 0;
+
+       tid = umem_zalloc(ztest_opts.zo_threads * sizeof (kt_did_t),
+           UMEM_NOFAIL);
+
+       if (ztest_opts.zo_verbose >= 4)
+               (void) printf("starting main threads...\n");
+
+       /*
+        * Kick off all the tests that run in parallel.
+        */
+       for (t = 0; t < ztest_opts.zo_threads; t++) {
+               kthread_t *thread;
+
+               if (t < ztest_opts.zo_datasets &&
+                   ztest_dataset_open(t) != 0) {
+                       umem_free(tid,
+                           ztest_opts.zo_threads * sizeof (kt_did_t));
+                       return;
+               }
+
+               VERIFY3P(thread = zk_thread_create(NULL, 0,
+                   (thread_func_t)ztest_thread,
+                   (void *)(uintptr_t)t, TS_RUN, NULL, 0, 0,
+                   PTHREAD_CREATE_JOINABLE), !=, NULL);
+               tid[t] = thread->t_tid;
+       }
+
+       /*
+        * Wait for all of the tests to complete.  We go in reverse order
+        * so we don't close datasets while threads are still using them.
+        */
+       for (t = ztest_opts.zo_threads - 1; t >= 0; t--) {
+               thread_join(tid[t]);
+               if (t < ztest_opts.zo_datasets)
+                       ztest_dataset_close(t);
+       }
+
+       txg_wait_synced(spa_get_dsl(spa), 0);
+
+       zs->zs_alloc = metaslab_class_get_alloc(spa_normal_class(spa));
+       zs->zs_space = metaslab_class_get_space(spa_normal_class(spa));
+
+       umem_free(tid, ztest_opts.zo_threads * sizeof (kt_did_t));
+
+       /* Kill the resume thread */
+       ztest_exiting = B_TRUE;
+       thread_join(resume_thread->t_tid);
+       ztest_resume(spa);
+
+       /*
+        * Right before closing the pool, kick off a bunch of async I/O;
+        * spa_close() should wait for it to complete.
+        */
+       for (object = 1; object < 50; object++) {
+               dmu_prefetch(spa->spa_meta_objset, object, 0, 0, 1ULL << 20,
+                   ZIO_PRIORITY_SYNC_READ);
+       }
+
+       /* Verify that at least one commit cb was called in a timely fashion */
+       if (zc_cb_counter >= ZTEST_COMMIT_CB_MIN_REG)
+               VERIFY0(zc_min_txg_delay);
+
+       spa_close(spa, FTAG);
+
+       /*
+        * Verify that we can loop over all pools.
+        */
+       mutex_enter(&spa_namespace_lock);
+       for (spa = spa_next(NULL); spa != NULL; spa = spa_next(spa))
+               if (ztest_opts.zo_verbose > 3)
+                       (void) printf("spa_next: found %s\n", spa_name(spa));
+       mutex_exit(&spa_namespace_lock);
+
+       /*
+        * Verify that we can export the pool and reimport it under a
+        * different name.
+        */
+       if (ztest_random(2) == 0) {
+               char name[ZFS_MAX_DATASET_NAME_LEN];
+               (void) snprintf(name, sizeof (name), "%s_import",
+                   ztest_opts.zo_pool);
+               ztest_spa_import_export(ztest_opts.zo_pool, name);
+               ztest_spa_import_export(name, ztest_opts.zo_pool);
+       }
+
+       kernel_fini();
+
+       list_destroy(&zcl.zcl_callbacks);
+       mutex_destroy(&zcl.zcl_callbacks_lock);
+       (void) rwlock_destroy(&ztest_name_lock);
+       mutex_destroy(&ztest_vdev_lock);
+}
+
+static void
+ztest_freeze(void)
+{
+       ztest_ds_t *zd = &ztest_ds[0];
+       spa_t *spa;
+       int numloops = 0;
+
+       if (ztest_opts.zo_verbose >= 3)
+               (void) printf("testing spa_freeze()...\n");
+
+       kernel_init(FREAD | FWRITE);
+       VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
+       VERIFY3U(0, ==, ztest_dataset_open(0));
+       spa->spa_debug = B_TRUE;
+       ztest_spa = spa;
+
+       /*
+        * Force the first log block to be transactionally allocated.
+        * We have to do this before we freeze the pool -- otherwise
+        * the log chain won't be anchored.
+        */
+       while (BP_IS_HOLE(&zd->zd_zilog->zl_header->zh_log)) {
+               ztest_dmu_object_alloc_free(zd, 0);
+               zil_commit(zd->zd_zilog, 0);
+       }
+
+       txg_wait_synced(spa_get_dsl(spa), 0);
+
+       /*
+        * Freeze the pool.  This stops spa_sync() from doing anything,
+        * so that the only way to record changes from now on is the ZIL.
+        */
+       spa_freeze(spa);
+
+       /*
+        * Because it is hard to predict how much space a write will actually
+        * require beforehand, we leave ourselves some fudge space to write over
+        * capacity.
+        */
+       uint64_t capacity = metaslab_class_get_space(spa_normal_class(spa)) / 2;
+
+       /*
+        * Run tests that generate log records but don't alter the pool config
+        * or depend on DSL sync tasks (snapshots, objset create/destroy, etc).
+        * We do a txg_wait_synced() after each iteration to force the txg
+        * to increase well beyond the last synced value in the uberblock.
+        * The ZIL should be OK with that.
+        *
+        * Run a random number of times less than zo_maxloops and ensure we do
+        * not run out of space on the pool.
+        */
+       while (ztest_random(10) != 0 &&
+           numloops++ < ztest_opts.zo_maxloops &&
+           metaslab_class_get_alloc(spa_normal_class(spa)) < capacity) {
+               ztest_od_t od;
+               ztest_od_init(&od, 0, FTAG, 0, DMU_OT_UINT64_OTHER, 0, 0, 0);
+               VERIFY0(ztest_object_init(zd, &od, sizeof (od), B_FALSE));
+               ztest_io(zd, od.od_object,
+                   ztest_random(ZTEST_RANGE_LOCKS) << SPA_MAXBLOCKSHIFT);
+               txg_wait_synced(spa_get_dsl(spa), 0);
+       }
+
+       /*
+        * Commit all of the changes we just generated.
+        */
+       zil_commit(zd->zd_zilog, 0);
+       txg_wait_synced(spa_get_dsl(spa), 0);
+
+       /*
+        * Close our dataset and close the pool.
+        */
+       ztest_dataset_close(0);
+       spa_close(spa, FTAG);
+       kernel_fini();
+
+       /*
+        * Open and close the pool and dataset to induce log replay.
+        */
+       kernel_init(FREAD | FWRITE);
+       VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
+       ASSERT(spa_freeze_txg(spa) == UINT64_MAX);
+       VERIFY3U(0, ==, ztest_dataset_open(0));
+       ztest_dataset_close(0);
+
+       spa->spa_debug = B_TRUE;
+       ztest_spa = spa;
+       txg_wait_synced(spa_get_dsl(spa), 0);
+       ztest_reguid(NULL, 0);
+
+       spa_close(spa, FTAG);
+       kernel_fini();
+}
+
+void
+print_time(hrtime_t t, char *timebuf)
+{
+       hrtime_t s = t / NANOSEC;
+       hrtime_t m = s / 60;
+       hrtime_t h = m / 60;
+       hrtime_t d = h / 24;
+
+       s -= m * 60;
+       m -= h * 60;
+       h -= d * 24;
+
+       timebuf[0] = '\0';
+
+       if (d)
+               (void) sprintf(timebuf,
+                   "%llud%02lluh%02llum%02llus", d, h, m, s);
+       else if (h)
+               (void) sprintf(timebuf, "%lluh%02llum%02llus", h, m, s);
+       else if (m)
+               (void) sprintf(timebuf, "%llum%02llus", m, s);
+       else
+               (void) sprintf(timebuf, "%llus", s);
+}
+
+static nvlist_t *
+make_random_props(void)
+{
+       nvlist_t *props;
+
+       VERIFY(nvlist_alloc(&props, NV_UNIQUE_NAME, 0) == 0);
+       if (ztest_random(2) == 0)
+               return (props);
+       VERIFY(nvlist_add_uint64(props, "autoreplace", 1) == 0);
+
+       return (props);
+}
+
+/*
+ * Create a storage pool with the given name and initial vdev size.
+ * Then test spa_freeze() functionality.
+ */
+static void
+ztest_init(ztest_shared_t *zs)
+{
+       spa_t *spa;
+       nvlist_t *nvroot, *props;
+       int i;
+
+       mutex_init(&ztest_vdev_lock, NULL, MUTEX_DEFAULT, NULL);
+       VERIFY(rwlock_init(&ztest_name_lock, USYNC_THREAD, NULL) == 0);
+
+       kernel_init(FREAD | FWRITE);
+
+       /*
+        * Create the storage pool.
+        */
+       (void) spa_destroy(ztest_opts.zo_pool);
+       ztest_shared->zs_vdev_next_leaf = 0;
+       zs->zs_splits = 0;
+       zs->zs_mirrors = ztest_opts.zo_mirrors;
+       nvroot = make_vdev_root(NULL, NULL, NULL, ztest_opts.zo_vdev_size, 0,
+           0, ztest_opts.zo_raidz, zs->zs_mirrors, 1);
+       props = make_random_props();
+       for (i = 0; i < SPA_FEATURES; i++) {
+               char *buf;
+               VERIFY3S(-1, !=, asprintf(&buf, "feature@%s",
+                   spa_feature_table[i].fi_uname));
+               VERIFY3U(0, ==, nvlist_add_uint64(props, buf, 0));
+               free(buf);
+       }
+       VERIFY3U(0, ==, spa_create(ztest_opts.zo_pool, nvroot, props, NULL));
+       nvlist_free(nvroot);
+       nvlist_free(props);
+
+       VERIFY3U(0, ==, spa_open(ztest_opts.zo_pool, &spa, FTAG));
+       zs->zs_metaslab_sz =
+           1ULL << spa->spa_root_vdev->vdev_child[0]->vdev_ms_shift;
+       spa_close(spa, FTAG);
+
+       kernel_fini();
+
+       ztest_run_zdb(ztest_opts.zo_pool);
+
+       ztest_freeze();
+
+       ztest_run_zdb(ztest_opts.zo_pool);
+
+       (void) rwlock_destroy(&ztest_name_lock);
+       mutex_destroy(&ztest_vdev_lock);
+}
+
+static void
+setup_data_fd(void)
+{
+       static char ztest_name_data[] = "/tmp/ztest.data.XXXXXX";
+
+       ztest_fd_data = mkstemp(ztest_name_data);
+       ASSERT3S(ztest_fd_data, >=, 0);
+       (void) unlink(ztest_name_data);
+}
+
+static int
+shared_data_size(ztest_shared_hdr_t *hdr)
+{
+       int size;
+
+       size = hdr->zh_hdr_size;
+       size += hdr->zh_opts_size;
+       size += hdr->zh_size;
+       size += hdr->zh_stats_size * hdr->zh_stats_count;
+       size += hdr->zh_ds_size * hdr->zh_ds_count;
+
+       return (size);
+}
+
+static void
+setup_hdr(void)
+{
+       int size;
+       ztest_shared_hdr_t *hdr;
+
+       hdr = (void *)mmap(0, P2ROUNDUP(sizeof (*hdr), getpagesize()),
+           PROT_READ | PROT_WRITE, MAP_SHARED, ztest_fd_data, 0);
+       ASSERT(hdr != MAP_FAILED);
+
+       VERIFY3U(0, ==, ftruncate(ztest_fd_data, sizeof (ztest_shared_hdr_t)));
+
+       hdr->zh_hdr_size = sizeof (ztest_shared_hdr_t);
+       hdr->zh_opts_size = sizeof (ztest_shared_opts_t);
+       hdr->zh_size = sizeof (ztest_shared_t);
+       hdr->zh_stats_size = sizeof (ztest_shared_callstate_t);
+       hdr->zh_stats_count = ZTEST_FUNCS;
+       hdr->zh_ds_size = sizeof (ztest_shared_ds_t);
+       hdr->zh_ds_count = ztest_opts.zo_datasets;
+
+       size = shared_data_size(hdr);
+       VERIFY3U(0, ==, ftruncate(ztest_fd_data, size));
+
+       (void) munmap((caddr_t)hdr, P2ROUNDUP(sizeof (*hdr), getpagesize()));
+}
+
+static void
+setup_data(void)
+{
+       int size, offset;
+       ztest_shared_hdr_t *hdr;
+       uint8_t *buf;
+
+       hdr = (void *)mmap(0, P2ROUNDUP(sizeof (*hdr), getpagesize()),
+           PROT_READ, MAP_SHARED, ztest_fd_data, 0);
+       ASSERT(hdr != MAP_FAILED);
+
+       size = shared_data_size(hdr);
+
+       (void) munmap((caddr_t)hdr, P2ROUNDUP(sizeof (*hdr), getpagesize()));
+       hdr = ztest_shared_hdr = (void *)mmap(0, P2ROUNDUP(size, getpagesize()),
+           PROT_READ | PROT_WRITE, MAP_SHARED, ztest_fd_data, 0);
+       ASSERT(hdr != MAP_FAILED);
+       buf = (uint8_t *)hdr;
+
+       offset = hdr->zh_hdr_size;
+       ztest_shared_opts = (void *)&buf[offset];
+       offset += hdr->zh_opts_size;
+       ztest_shared = (void *)&buf[offset];
+       offset += hdr->zh_size;
+       ztest_shared_callstate = (void *)&buf[offset];
+       offset += hdr->zh_stats_size * hdr->zh_stats_count;
+       ztest_shared_ds = (void *)&buf[offset];
+}
+
+static boolean_t
+exec_child(char *cmd, char *libpath, boolean_t ignorekill, int *statusp)
+{
+       pid_t pid;
+       int status;
+       char *cmdbuf = NULL;
+
+       pid = fork();
+
+       if (cmd == NULL) {
+               cmdbuf = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+               (void) strlcpy(cmdbuf, getexecname(), MAXPATHLEN);
+               cmd = cmdbuf;
+       }
+
+       if (pid == -1)
+               fatal(1, "fork failed");
+
+       if (pid == 0) { /* child */
+               char *emptyargv[2] = { cmd, NULL };
+               char fd_data_str[12];
+
+               struct rlimit rl = { 1024, 1024 };
+               (void) setrlimit(RLIMIT_NOFILE, &rl);
+
+               (void) close(ztest_fd_rand);
+               VERIFY(11 >= snprintf(fd_data_str, 12, "%d", ztest_fd_data));
+               VERIFY(0 == setenv("ZTEST_FD_DATA", fd_data_str, 1));
+
+               (void) enable_extended_FILE_stdio(-1, -1);
+               if (libpath != NULL)
+                       VERIFY(0 == setenv("LD_LIBRARY_PATH", libpath, 1));
+               (void) execv(cmd, emptyargv);
+               ztest_dump_core = B_FALSE;
+               fatal(B_TRUE, "exec failed: %s", cmd);
+       }
+
+       if (cmdbuf != NULL) {
+               umem_free(cmdbuf, MAXPATHLEN);
+               cmd = NULL;
+       }
+
+       while (waitpid(pid, &status, 0) != pid)
+               continue;
+       if (statusp != NULL)
+               *statusp = status;
+
+       if (WIFEXITED(status)) {
+               if (WEXITSTATUS(status) != 0) {
+                       (void) fprintf(stderr, "child exited with code %d\n",
+                           WEXITSTATUS(status));
+                       exit(2);
+               }
+               return (B_FALSE);
+       } else if (WIFSIGNALED(status)) {
+               if (!ignorekill || WTERMSIG(status) != SIGKILL) {
+                       (void) fprintf(stderr, "child died with signal %d\n",
+                           WTERMSIG(status));
+                       exit(3);
+               }
+               return (B_TRUE);
+       } else {
+               (void) fprintf(stderr, "something strange happened to child\n");
+               exit(4);
+               /* NOTREACHED */
+       }
+}
+
+static void
+ztest_run_init(void)
+{
+       int i;
+
+       ztest_shared_t *zs = ztest_shared;
+
+       ASSERT(ztest_opts.zo_init != 0);
+
+       /*
+        * Blow away any existing copy of zpool.cache
+        */
+       (void) remove(spa_config_path);
+
+       /*
+        * Create and initialize our storage pool.
+        */
+       for (i = 1; i <= ztest_opts.zo_init; i++) {
+               bzero(zs, sizeof (ztest_shared_t));
+               if (ztest_opts.zo_verbose >= 3 &&
+                   ztest_opts.zo_init != 1) {
+                       (void) printf("ztest_init(), pass %d\n", i);
+               }
+               ztest_init(zs);
+       }
+}
+
+int
+main(int argc, char **argv)
+{
+       int kills = 0;
+       int iters = 0;
+       int older = 0;
+       int newer = 0;
+       ztest_shared_t *zs;
+       ztest_info_t *zi;
+       ztest_shared_callstate_t *zc;
+       char timebuf[100];
+       char numbuf[6];
+       spa_t *spa;
+       char *cmd;
+       boolean_t hasalt;
+       int f;
+       char *fd_data_str = getenv("ZTEST_FD_DATA");
+       struct sigaction action;
+
+       (void) setvbuf(stdout, NULL, _IOLBF, 0);
+
+       dprintf_setup(&argc, argv);
+
+       action.sa_handler = sig_handler;
+       sigemptyset(&action.sa_mask);
+       action.sa_flags = 0;
+
+       if (sigaction(SIGSEGV, &action, NULL) < 0) {
+               (void) fprintf(stderr, "ztest: cannot catch SIGSEGV: %s.\n",
+                   strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       if (sigaction(SIGABRT, &action, NULL) < 0) {
+               (void) fprintf(stderr, "ztest: cannot catch SIGABRT: %s.\n",
+                   strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       ztest_fd_rand = open("/dev/urandom", O_RDONLY);
+       ASSERT3S(ztest_fd_rand, >=, 0);
+
+       if (!fd_data_str) {
+               process_options(argc, argv);
+
+               setup_data_fd();
+               setup_hdr();
+               setup_data();
+               bcopy(&ztest_opts, ztest_shared_opts,
+                   sizeof (*ztest_shared_opts));
+       } else {
+               ztest_fd_data = atoi(fd_data_str);
+               setup_data();
+               bcopy(ztest_shared_opts, &ztest_opts, sizeof (ztest_opts));
+       }
+       ASSERT3U(ztest_opts.zo_datasets, ==, ztest_shared_hdr->zh_ds_count);
+
+       /* Override location of zpool.cache */
+       VERIFY(asprintf((char **)&spa_config_path, "%s/zpool.cache",
+           ztest_opts.zo_dir) != -1);
+
+       ztest_ds = umem_alloc(ztest_opts.zo_datasets * sizeof (ztest_ds_t),
+           UMEM_NOFAIL);
+       zs = ztest_shared;
+
+       if (fd_data_str) {
+               metaslab_gang_bang = ztest_opts.zo_metaslab_gang_bang;
+               metaslab_df_alloc_threshold =
+                   zs->zs_metaslab_df_alloc_threshold;
+
+               if (zs->zs_do_init)
+                       ztest_run_init();
+               else
+                       ztest_run(zs);
+               exit(0);
+       }
+
+       hasalt = (strlen(ztest_opts.zo_alt_ztest) != 0);
+
+       if (ztest_opts.zo_verbose >= 1) {
+               (void) printf("%llu vdevs, %d datasets, %d threads,"
+                   " %llu seconds...\n",
+                   (u_longlong_t)ztest_opts.zo_vdevs,
+                   ztest_opts.zo_datasets,
+                   ztest_opts.zo_threads,
+                   (u_longlong_t)ztest_opts.zo_time);
+       }
+
+       cmd = umem_alloc(MAXNAMELEN, UMEM_NOFAIL);
+       (void) strlcpy(cmd, getexecname(), MAXNAMELEN);
+
+       zs->zs_do_init = B_TRUE;
+       if (strlen(ztest_opts.zo_alt_ztest) != 0) {
+               if (ztest_opts.zo_verbose >= 1) {
+                       (void) printf("Executing older ztest for "
+                           "initialization: %s\n", ztest_opts.zo_alt_ztest);
+               }
+               VERIFY(!exec_child(ztest_opts.zo_alt_ztest,
+                   ztest_opts.zo_alt_libpath, B_FALSE, NULL));
+       } else {
+               VERIFY(!exec_child(NULL, NULL, B_FALSE, NULL));
+       }
+       zs->zs_do_init = B_FALSE;
+
+       zs->zs_proc_start = gethrtime();
+       zs->zs_proc_stop = zs->zs_proc_start + ztest_opts.zo_time * NANOSEC;
+
+       for (f = 0; f < ZTEST_FUNCS; f++) {
+               zi = &ztest_info[f];
+               zc = ZTEST_GET_SHARED_CALLSTATE(f);
+               if (zs->zs_proc_start + zi->zi_interval[0] > zs->zs_proc_stop)
+                       zc->zc_next = UINT64_MAX;
+               else
+                       zc->zc_next = zs->zs_proc_start +
+                           ztest_random(2 * zi->zi_interval[0] + 1);
+       }
+
+       /*
+        * Run the tests in a loop.  These tests include fault injection
+        * to verify that self-healing data works, and forced crashes
+        * to verify that we never lose on-disk consistency.
+        */
+       while (gethrtime() < zs->zs_proc_stop) {
+               int status;
+               boolean_t killed;
+
+               /*
+                * Initialize the workload counters for each function.
+                */
+               for (f = 0; f < ZTEST_FUNCS; f++) {
+                       zc = ZTEST_GET_SHARED_CALLSTATE(f);
+                       zc->zc_count = 0;
+                       zc->zc_time = 0;
+               }
+
+               /* Set the allocation switch size */
+               zs->zs_metaslab_df_alloc_threshold =
+                   ztest_random(zs->zs_metaslab_sz / 4) + 1;
+
+               if (!hasalt || ztest_random(2) == 0) {
+                       if (hasalt && ztest_opts.zo_verbose >= 1) {
+                               (void) printf("Executing newer ztest: %s\n",
+                                   cmd);
+                       }
+                       newer++;
+                       killed = exec_child(cmd, NULL, B_TRUE, &status);
+               } else {
+                       if (hasalt && ztest_opts.zo_verbose >= 1) {
+                               (void) printf("Executing older ztest: %s\n",
+                                   ztest_opts.zo_alt_ztest);
+                       }
+                       older++;
+                       killed = exec_child(ztest_opts.zo_alt_ztest,
+                           ztest_opts.zo_alt_libpath, B_TRUE, &status);
+               }
+
+               if (killed)
+                       kills++;
+               iters++;
+
+               if (ztest_opts.zo_verbose >= 1) {
+                       hrtime_t now = gethrtime();
+
+                       now = MIN(now, zs->zs_proc_stop);
+                       print_time(zs->zs_proc_stop - now, timebuf);
+                       nicenum(zs->zs_space, numbuf);
+
+                       (void) printf("Pass %3d, %8s, %3llu ENOSPC, "
+                           "%4.1f%% of %5s used, %3.0f%% done, %8s to go\n",
+                           iters,
+                           WIFEXITED(status) ? "Complete" : "SIGKILL",
+                           (u_longlong_t)zs->zs_enospc_count,
+                           100.0 * zs->zs_alloc / zs->zs_space,
+                           numbuf,
+                           100.0 * (now - zs->zs_proc_start) /
+                           (ztest_opts.zo_time * NANOSEC), timebuf);
+               }
+
+               if (ztest_opts.zo_verbose >= 2) {
+                       (void) printf("\nWorkload summary:\n\n");
+                       (void) printf("%7s %9s   %s\n",
+                           "Calls", "Time", "Function");
+                       (void) printf("%7s %9s   %s\n",
+                           "-----", "----", "--------");
+                       for (f = 0; f < ZTEST_FUNCS; f++) {
+                               zi = &ztest_info[f];
+                               zc = ZTEST_GET_SHARED_CALLSTATE(f);
+                               print_time(zc->zc_time, timebuf);
+                               (void) printf("%7llu %9s   %s\n",
+                                   (u_longlong_t)zc->zc_count, timebuf,
+                                   zi->zi_funcname);
+                       }
+                       (void) printf("\n");
+               }
+
+               /*
+                * It's possible that we killed a child during a rename test,
+                * in which case we'll have a 'ztest_tmp' pool lying around
+                * instead of 'ztest'.  Do a blind rename in case this happened.
+                */
+               kernel_init(FREAD);
+               if (spa_open(ztest_opts.zo_pool, &spa, FTAG) == 0) {
+                       spa_close(spa, FTAG);
+               } else {
+                       char tmpname[ZFS_MAX_DATASET_NAME_LEN];
+                       kernel_fini();
+                       kernel_init(FREAD | FWRITE);
+                       (void) snprintf(tmpname, sizeof (tmpname), "%s_tmp",
+                           ztest_opts.zo_pool);
+                       (void) spa_rename(tmpname, ztest_opts.zo_pool);
+               }
+               kernel_fini();
+
+               ztest_run_zdb(ztest_opts.zo_pool);
+       }
+
+       if (ztest_opts.zo_verbose >= 1) {
+               if (hasalt) {
+                       (void) printf("%d runs of older ztest: %s\n", older,
+                           ztest_opts.zo_alt_ztest);
+                       (void) printf("%d runs of newer ztest: %s\n", newer,
+                           cmd);
+               }
+               (void) printf("%d killed, %d completed, %.0f%% kill rate\n",
+                   kills, iters - kills, (100.0 * kills) / MAX(1, iters));
+       }
+
+       umem_free(cmd, MAXNAMELEN);
+
+       return (0);
+}
diff --git a/zfs/cmd/zvol_id/Makefile.am b/zfs/cmd/zvol_id/Makefile.am
new file mode 100644 (file)
index 0000000..d131c63
--- /dev/null
@@ -0,0 +1,14 @@
+include $(top_srcdir)/config/Rules.am
+
+# Disable GCC stack protection for zvol_id.  This is a kludge and should be
+# removed once https://github.com/zfsonlinux/zfs/issues/569 is resolved.
+AM_CFLAGS += -fno-stack-protector
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+udev_PROGRAMS = zvol_id
+
+zvol_id_SOURCES = \
+       zvol_id_main.c
diff --git a/zfs/cmd/zvol_id/Makefile.in b/zfs/cmd/zvol_id/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/cmd/zvol_id/zvol_id_main.c b/zfs/cmd/zvol_id/zvol_id_main.c
new file mode 100644 (file)
index 0000000..6bd5113
--- /dev/null
@@ -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 (c) 2011, Fajar A. Nugraha.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/ioctl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/zfs_znode.h>
+#include <sys/fs/zfs.h>
+
+static int
+ioctl_get_msg(char *var, int fd)
+{
+       int error = 0;
+       char msg[ZFS_MAX_DATASET_NAME_LEN];
+
+       error = ioctl(fd, BLKZNAME, msg);
+       if (error < 0) {
+               return (error);
+       }
+
+       snprintf(var, ZFS_MAX_DATASET_NAME_LEN, "%s", msg);
+       return (error);
+}
+
+int
+main(int argc, char **argv)
+{
+       int fd, error = 0;
+       char zvol_name[ZFS_MAX_DATASET_NAME_LEN];
+       char zvol_name_part[ZFS_MAX_DATASET_NAME_LEN];
+       char *dev_name;
+       struct stat64 statbuf;
+       int dev_minor, dev_part;
+       int i;
+
+       if (argc < 2) {
+               printf("Usage: %s /dev/zvol_device_node\n", argv[0]);
+               return (EINVAL);
+       }
+
+       dev_name = argv[1];
+       error = stat64(dev_name, &statbuf);
+       if (error != 0) {
+               printf("Unable to access device file: %s\n", dev_name);
+               return (errno);
+       }
+
+       dev_minor = minor(statbuf.st_rdev);
+       dev_part = dev_minor % ZVOL_MINORS;
+
+       fd = open(dev_name, O_RDONLY);
+       if (fd < 0) {
+               printf("Unable to open device file: %s\n", dev_name);
+               return (errno);
+       }
+
+       error = ioctl_get_msg(zvol_name, fd);
+       if (error < 0) {
+               printf("ioctl_get_msg failed:%s\n", strerror(errno));
+               return (errno);
+       }
+       if (dev_part > 0)
+               snprintf(zvol_name_part, ZFS_MAX_DATASET_NAME_LEN,
+                   "%s-part%d", zvol_name, dev_part);
+       else
+               snprintf(zvol_name_part, ZFS_MAX_DATASET_NAME_LEN,
+                   "%s", zvol_name);
+
+       for (i = 0; i < strlen(zvol_name_part); i++) {
+               if (isblank(zvol_name_part[i]))
+                       zvol_name_part[i] = '+';
+       }
+
+       printf("%s\n", zvol_name_part);
+       close(fd);
+       return (error);
+}
index af20ddb3964f9c0273d699d448c070d571e68884..20a21e972bcd3e270b760f9c0cc6259cf64c2c91 100644 (file)
@@ -7,7 +7,8 @@ AM_CFLAGS += ${NO_BOOL_COMPARE}
 AM_CFLAGS += -fno-strict-aliasing
 AM_CPPFLAGS  = -D_GNU_SOURCE -D__EXTENSIONS__ -D_REENTRANT
 AM_CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS -D_FILE_OFFSET_BITS=64
-AM_CPPFLAGS += -D_LARGEFILE64_SOURCE -DTEXT_DOMAIN=\"zfs-linux-user\"
+AM_CPPFLAGS += -D_LARGEFILE64_SOURCE -DHAVE_LARGE_STACKS=1
+AM_CPPFLAGS += -DTEXT_DOMAIN=\"zfs-linux-user\"
 AM_CPPFLAGS += -DLIBEXECDIR=\"$(libexecdir)\"
 AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\"
 AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\"
diff --git a/zfs/config/always-arch.m4 b/zfs/config/always-arch.m4
new file mode 100644 (file)
index 0000000..c3e6b4a
--- /dev/null
@@ -0,0 +1,22 @@
+dnl #
+dnl # Set the target arch for libspl atomic implementation and the icp
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_ARCH], [
+       AC_MSG_CHECKING(for target asm dir)
+       TARGET_ARCH=`echo ${target_cpu} | sed -e s/i.86/i386/`
+
+       case $TARGET_ARCH in
+       i386|x86_64)
+               TARGET_ASM_DIR=asm-${TARGET_ARCH}
+               ;;
+       *)
+               TARGET_ASM_DIR=asm-generic
+               ;;
+       esac
+
+       AC_SUBST([TARGET_ASM_DIR])
+       AM_CONDITIONAL([TARGET_ASM_X86_64], test $TARGET_ASM_DIR = asm-x86_64)
+       AM_CONDITIONAL([TARGET_ASM_I386], test $TARGET_ASM_DIR = asm-i386)
+       AM_CONDITIONAL([TARGET_ASM_GENERIC], test $TARGET_ASM_DIR = asm-generic)
+       AC_MSG_RESULT([$TARGET_ASM_DIR])
+])
diff --git a/zfs/config/compile b/zfs/config/compile
deleted file mode 100755 (executable)
index a85b723..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-#! /bin/sh
-# Wrapper for compilers which do not understand '-c -o'.
-
-scriptversion=2012-10-14.11; # UTC
-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
-# Written by Tom Tromey <tromey@cygnus.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# This file is maintained in Automake, please report
-# bugs to <bug-automake@gnu.org> or send patches to
-# <automake-patches@gnu.org>.
-
-nl='
-'
-
-# We need space, tab and new line, in precisely that order.  Quoting is
-# there to prevent tools from complaining about whitespace usage.
-IFS=" ""       $nl"
-
-file_conv=
-
-# func_file_conv build_file lazy
-# Convert a $build file to $host form and store it in $file
-# Currently only supports Windows hosts. If the determined conversion
-# type is listed in (the comma separated) LAZY, no conversion will
-# take place.
-func_file_conv ()
-{
-  file=$1
-  case $file in
-    / | /[!/]*) # absolute file, and not a UNC file
-      if test -z "$file_conv"; then
-       # lazily determine how to convert abs files
-       case `uname -s` in
-         MINGW*)
-           file_conv=mingw
-           ;;
-         CYGWIN*)
-           file_conv=cygwin
-           ;;
-         *)
-           file_conv=wine
-           ;;
-       esac
-      fi
-      case $file_conv/,$2, in
-       *,$file_conv,*)
-         ;;
-       mingw/*)
-         file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
-         ;;
-       cygwin/*)
-         file=`cygpath -m "$file" || echo "$file"`
-         ;;
-       wine/*)
-         file=`winepath -w "$file" || echo "$file"`
-         ;;
-      esac
-      ;;
-  esac
-}
-
-# func_cl_dashL linkdir
-# Make cl look for libraries in LINKDIR
-func_cl_dashL ()
-{
-  func_file_conv "$1"
-  if test -z "$lib_path"; then
-    lib_path=$file
-  else
-    lib_path="$lib_path;$file"
-  fi
-  linker_opts="$linker_opts -LIBPATH:$file"
-}
-
-# func_cl_dashl library
-# Do a library search-path lookup for cl
-func_cl_dashl ()
-{
-  lib=$1
-  found=no
-  save_IFS=$IFS
-  IFS=';'
-  for dir in $lib_path $LIB
-  do
-    IFS=$save_IFS
-    if $shared && test -f "$dir/$lib.dll.lib"; then
-      found=yes
-      lib=$dir/$lib.dll.lib
-      break
-    fi
-    if test -f "$dir/$lib.lib"; then
-      found=yes
-      lib=$dir/$lib.lib
-      break
-    fi
-    if test -f "$dir/lib$lib.a"; then
-      found=yes
-      lib=$dir/lib$lib.a
-      break
-    fi
-  done
-  IFS=$save_IFS
-
-  if test "$found" != yes; then
-    lib=$lib.lib
-  fi
-}
-
-# func_cl_wrapper cl arg...
-# Adjust compile command to suit cl
-func_cl_wrapper ()
-{
-  # Assume a capable shell
-  lib_path=
-  shared=:
-  linker_opts=
-  for arg
-  do
-    if test -n "$eat"; then
-      eat=
-    else
-      case $1 in
-       -o)
-         # configure might choose to run compile as 'compile cc -o foo foo.c'.
-         eat=1
-         case $2 in
-           *.o | *.[oO][bB][jJ])
-             func_file_conv "$2"
-             set x "$@" -Fo"$file"
-             shift
-             ;;
-           *)
-             func_file_conv "$2"
-             set x "$@" -Fe"$file"
-             shift
-             ;;
-         esac
-         ;;
-       -I)
-         eat=1
-         func_file_conv "$2" mingw
-         set x "$@" -I"$file"
-         shift
-         ;;
-       -I*)
-         func_file_conv "${1#-I}" mingw
-         set x "$@" -I"$file"
-         shift
-         ;;
-       -l)
-         eat=1
-         func_cl_dashl "$2"
-         set x "$@" "$lib"
-         shift
-         ;;
-       -l*)
-         func_cl_dashl "${1#-l}"
-         set x "$@" "$lib"
-         shift
-         ;;
-       -L)
-         eat=1
-         func_cl_dashL "$2"
-         ;;
-       -L*)
-         func_cl_dashL "${1#-L}"
-         ;;
-       -static)
-         shared=false
-         ;;
-       -Wl,*)
-         arg=${1#-Wl,}
-         save_ifs="$IFS"; IFS=','
-         for flag in $arg; do
-           IFS="$save_ifs"
-           linker_opts="$linker_opts $flag"
-         done
-         IFS="$save_ifs"
-         ;;
-       -Xlinker)
-         eat=1
-         linker_opts="$linker_opts $2"
-         ;;
-       -*)
-         set x "$@" "$1"
-         shift
-         ;;
-       *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
-         func_file_conv "$1"
-         set x "$@" -Tp"$file"
-         shift
-         ;;
-       *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
-         func_file_conv "$1" mingw
-         set x "$@" "$file"
-         shift
-         ;;
-       *)
-         set x "$@" "$1"
-         shift
-         ;;
-      esac
-    fi
-    shift
-  done
-  if test -n "$linker_opts"; then
-    linker_opts="-link$linker_opts"
-  fi
-  exec "$@" $linker_opts
-  exit 1
-}
-
-eat=
-
-case $1 in
-  '')
-     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
-     exit 1;
-     ;;
-  -h | --h*)
-    cat <<\EOF
-Usage: compile [--help] [--version] PROGRAM [ARGS]
-
-Wrapper for compilers which do not understand '-c -o'.
-Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
-arguments, and rename the output as expected.
-
-If you are trying to build a whole package this is not the
-right script to run: please start by reading the file 'INSTALL'.
-
-Report bugs to <bug-automake@gnu.org>.
-EOF
-    exit $?
-    ;;
-  -v | --v*)
-    echo "compile $scriptversion"
-    exit $?
-    ;;
-  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
-    func_cl_wrapper "$@"      # Doesn't return...
-    ;;
-esac
-
-ofile=
-cfile=
-
-for arg
-do
-  if test -n "$eat"; then
-    eat=
-  else
-    case $1 in
-      -o)
-       # configure might choose to run compile as 'compile cc -o foo foo.c'.
-       # So we strip '-o arg' only if arg is an object.
-       eat=1
-       case $2 in
-         *.o | *.obj)
-           ofile=$2
-           ;;
-         *)
-           set x "$@" -o "$2"
-           shift
-           ;;
-       esac
-       ;;
-      *.c)
-       cfile=$1
-       set x "$@" "$1"
-       shift
-       ;;
-      *)
-       set x "$@" "$1"
-       shift
-       ;;
-    esac
-  fi
-  shift
-done
-
-if test -z "$ofile" || test -z "$cfile"; then
-  # If no '-o' option was seen then we might have been invoked from a
-  # pattern rule where we don't need one.  That is ok -- this is a
-  # normal compilation that the losing compiler can handle.  If no
-  # '.c' file was seen then we are probably linking.  That is also
-  # ok.
-  exec "$@"
-fi
-
-# Name of file we expect compiler to create.
-cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
-
-# Create the lock directory.
-# Note: use '[/\\:.-]' here to ensure that we don't use the same name
-# that we are using for the .o file.  Also, base the name on the expected
-# object file name, since that is what matters with a parallel build.
-lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
-while true; do
-  if mkdir "$lockdir" >/dev/null 2>&1; then
-    break
-  fi
-  sleep 1
-done
-# FIXME: race condition here if user kills between mkdir and trap.
-trap "rmdir '$lockdir'; exit 1" 1 2 15
-
-# Run the compile.
-"$@"
-ret=$?
-
-if test -f "$cofile"; then
-  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
-elif test -f "${cofile}bj"; then
-  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
-fi
-
-rmdir "$lockdir"
-exit $ret
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/zfs/config/config.guess b/zfs/config/config.guess
deleted file mode 100755 (executable)
index 1659250..0000000
+++ /dev/null
@@ -1,1441 +0,0 @@
-#! /bin/sh
-# Attempt to guess a canonical system name.
-#   Copyright 1992-2015 Free Software Foundation, Inc.
-
-timestamp='2015-08-20'
-
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that
-# program.  This Exception is an additional permission under section 7
-# of the GNU General Public License, version 3 ("GPLv3").
-#
-# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
-#
-# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
-#
-# Please send patches to <config-patches@gnu.org>.
-
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION]
-
-Output the configuration name of the system \`$me' is run on.
-
-Operation modes:
-  -h, --help         print this help, then exit
-  -t, --time-stamp   print date of last modification, then exit
-  -v, --version      print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.guess ($timestamp)
-
-Originally written by Per Bothner.
-Copyright 1992-2015 Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions.  There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
-  case $1 in
-    --time-stamp | --time* | -t )
-       echo "$timestamp" ; exit ;;
-    --version | -v )
-       echo "$version" ; exit ;;
-    --help | --h* | -h )
-       echo "$usage"; exit ;;
-    -- )     # Stop option processing
-       shift; break ;;
-    - )        # Use stdin as input.
-       break ;;
-    -* )
-       echo "$me: invalid option $1$help" >&2
-       exit 1 ;;
-    * )
-       break ;;
-  esac
-done
-
-if test $# != 0; then
-  echo "$me: too many arguments$help" >&2
-  exit 1
-fi
-
-trap 'exit 1' 1 2 15
-
-# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
-# compiler to aid in system detection is discouraged as it requires
-# temporary files to be created and, as you can see below, it is a
-# headache to deal with in a portable fashion.
-
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
-
-# Portable tmp directory creation inspired by the Autoconf team.
-
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,)    echo "int x;" > $dummy.c ;
-       for c in cc gcc c89 c99 ; do
-         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
-            CC_FOR_BUILD="$c"; break ;
-         fi ;
-       done ;
-       if test x"$CC_FOR_BUILD" = x ; then
-         CC_FOR_BUILD=no_compiler_found ;
-       fi
-       ;;
- ,,*)   CC_FOR_BUILD=$CC ;;
- ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
-       PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-case "${UNAME_SYSTEM}" in
-Linux|GNU|GNU/*)
-       # If the system lacks a compiler, then just pick glibc.
-       # We could probably try harder.
-       LIBC=gnu
-
-       eval $set_cc_for_build
-       cat <<-EOF > $dummy.c
-       #include <features.h>
-       #if defined(__UCLIBC__)
-       LIBC=uclibc
-       #elif defined(__dietlibc__)
-       LIBC=dietlibc
-       #else
-       LIBC=gnu
-       #endif
-       EOF
-       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
-       ;;
-esac
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
-    *:NetBSD:*:*)
-       # NetBSD (nbsd) targets should (where applicable) match one or
-       # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
-       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
-       # switched to ELF, *-*-netbsd* would select the old
-       # object file format.  This provides both forward
-       # compatibility and a consistent mechanism for selecting the
-       # object file format.
-       #
-       # Note: NetBSD doesn't particularly care about the vendor
-       # portion of the name.  We always set it to "unknown".
-       sysctl="sysctl -n hw.machine_arch"
-       UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
-           /sbin/$sysctl 2>/dev/null || \
-           /usr/sbin/$sysctl 2>/dev/null || \
-           echo unknown)`
-       case "${UNAME_MACHINE_ARCH}" in
-           armeb) machine=armeb-unknown ;;
-           arm*) machine=arm-unknown ;;
-           sh3el) machine=shl-unknown ;;
-           sh3eb) machine=sh-unknown ;;
-           sh5el) machine=sh5le-unknown ;;
-           earmv*)
-               arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
-               endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
-               machine=${arch}${endian}-unknown
-               ;;
-           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
-       esac
-       # The Operating System including object format, if it has switched
-       # to ELF recently, or will in the future.
-       case "${UNAME_MACHINE_ARCH}" in
-           arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
-               eval $set_cc_for_build
-               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
-                       | grep -q __ELF__
-               then
-                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
-                   # Return netbsd for either.  FIX?
-                   os=netbsd
-               else
-                   os=netbsdelf
-               fi
-               ;;
-           *)
-               os=netbsd
-               ;;
-       esac
-       # Determine ABI tags.
-       case "${UNAME_MACHINE_ARCH}" in
-           earm*)
-               expr='s/^earmv[0-9]/-eabi/;s/eb$//'
-               abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
-               ;;
-       esac
-       # The OS release
-       # Debian GNU/NetBSD machines have a different userland, and
-       # thus, need a distinct triplet. However, they do not need
-       # kernel version information, so it can be replaced with a
-       # suitable tag, in the style of linux-gnu.
-       case "${UNAME_VERSION}" in
-           Debian*)
-               release='-gnu'
-               ;;
-           *)
-               release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
-               ;;
-       esac
-       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
-       # contains redundant information, the shorter form:
-       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-       echo "${machine}-${os}${release}${abi}"
-       exit ;;
-    *:Bitrig:*:*)
-       UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
-       echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
-       exit ;;
-    *:OpenBSD:*:*)
-       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
-       echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
-       exit ;;
-    *:ekkoBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
-       exit ;;
-    *:SolidBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
-       exit ;;
-    macppc:MirBSD:*:*)
-       echo powerpc-unknown-mirbsd${UNAME_RELEASE}
-       exit ;;
-    *:MirBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
-       exit ;;
-    *:Sortix:*:*)
-       echo ${UNAME_MACHINE}-unknown-sortix
-       exit ;;
-    alpha:OSF1:*:*)
-       case $UNAME_RELEASE in
-       *4.0)
-               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
-               ;;
-       *5.*)
-               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
-               ;;
-       esac
-       # According to Compaq, /usr/sbin/psrinfo has been available on
-       # OSF/1 and Tru64 systems produced since 1995.  I hope that
-       # covers most systems running today.  This code pipes the CPU
-       # types through head -n 1, so we only detect the type of CPU 0.
-       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
-       case "$ALPHA_CPU_TYPE" in
-           "EV4 (21064)")
-               UNAME_MACHINE="alpha" ;;
-           "EV4.5 (21064)")
-               UNAME_MACHINE="alpha" ;;
-           "LCA4 (21066/21068)")
-               UNAME_MACHINE="alpha" ;;
-           "EV5 (21164)")
-               UNAME_MACHINE="alphaev5" ;;
-           "EV5.6 (21164A)")
-               UNAME_MACHINE="alphaev56" ;;
-           "EV5.6 (21164PC)")
-               UNAME_MACHINE="alphapca56" ;;
-           "EV5.7 (21164PC)")
-               UNAME_MACHINE="alphapca57" ;;
-           "EV6 (21264)")
-               UNAME_MACHINE="alphaev6" ;;
-           "EV6.7 (21264A)")
-               UNAME_MACHINE="alphaev67" ;;
-           "EV6.8CB (21264C)")
-               UNAME_MACHINE="alphaev68" ;;
-           "EV6.8AL (21264B)")
-               UNAME_MACHINE="alphaev68" ;;
-           "EV6.8CX (21264D)")
-               UNAME_MACHINE="alphaev68" ;;
-           "EV6.9A (21264/EV69A)")
-               UNAME_MACHINE="alphaev69" ;;
-           "EV7 (21364)")
-               UNAME_MACHINE="alphaev7" ;;
-           "EV7.9 (21364A)")
-               UNAME_MACHINE="alphaev79" ;;
-       esac
-       # A Pn.n version is a patched version.
-       # A Vn.n version is a released version.
-       # A Tn.n version is a released field test version.
-       # A Xn.n version is an unreleased experimental baselevel.
-       # 1.2 uses "1.2" for uname -r.
-       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-       # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
-       exitcode=$?
-       trap '' 0
-       exit $exitcode ;;
-    Alpha\ *:Windows_NT*:*)
-       # How do we know it's Interix rather than the generic POSIX subsystem?
-       # Should we change UNAME_MACHINE based on the output of uname instead
-       # of the specific Alpha model?
-       echo alpha-pc-interix
-       exit ;;
-    21064:Windows_NT:50:3)
-       echo alpha-dec-winnt3.5
-       exit ;;
-    Amiga*:UNIX_System_V:4.0:*)
-       echo m68k-unknown-sysv4
-       exit ;;
-    *:[Aa]miga[Oo][Ss]:*:*)
-       echo ${UNAME_MACHINE}-unknown-amigaos
-       exit ;;
-    *:[Mm]orph[Oo][Ss]:*:*)
-       echo ${UNAME_MACHINE}-unknown-morphos
-       exit ;;
-    *:OS/390:*:*)
-       echo i370-ibm-openedition
-       exit ;;
-    *:z/VM:*:*)
-       echo s390-ibm-zvmoe
-       exit ;;
-    *:OS400:*:*)
-       echo powerpc-ibm-os400
-       exit ;;
-    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
-       echo arm-acorn-riscix${UNAME_RELEASE}
-       exit ;;
-    arm*:riscos:*:*|arm*:RISCOS:*:*)
-       echo arm-unknown-riscos
-       exit ;;
-    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
-       echo hppa1.1-hitachi-hiuxmpp
-       exit ;;
-    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
-       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
-       if test "`(/bin/universe) 2>/dev/null`" = att ; then
-               echo pyramid-pyramid-sysv3
-       else
-               echo pyramid-pyramid-bsd
-       fi
-       exit ;;
-    NILE*:*:*:dcosx)
-       echo pyramid-pyramid-svr4
-       exit ;;
-    DRS?6000:unix:4.0:6*)
-       echo sparc-icl-nx6
-       exit ;;
-    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
-       case `/usr/bin/uname -p` in
-           sparc) echo sparc-icl-nx7; exit ;;
-       esac ;;
-    s390x:SunOS:*:*)
-       echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit ;;
-    sun4H:SunOS:5.*:*)
-       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit ;;
-    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
-       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit ;;
-    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
-       echo i386-pc-auroraux${UNAME_RELEASE}
-       exit ;;
-    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
-       eval $set_cc_for_build
-       SUN_ARCH="i386"
-       # If there is a compiler, see if it is configured for 64-bit objects.
-       # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
-       # This test works for both compilers.
-       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-           if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
-               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-               grep IS_64BIT_ARCH >/dev/null
-           then
-               SUN_ARCH="x86_64"
-           fi
-       fi
-       echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit ;;
-    sun4*:SunOS:6*:*)
-       # According to config.sub, this is the proper way to canonicalize
-       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
-       # it's likely to be more like Solaris than SunOS4.
-       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit ;;
-    sun4*:SunOS:*:*)
-       case "`/usr/bin/arch -k`" in
-           Series*|S4*)
-               UNAME_RELEASE=`uname -v`
-               ;;
-       esac
-       # Japanese Language versions have a version number like `4.1.3-JL'.
-       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
-       exit ;;
-    sun3*:SunOS:*:*)
-       echo m68k-sun-sunos${UNAME_RELEASE}
-       exit ;;
-    sun*:*:4.2BSD:*)
-       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
-       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
-       case "`/bin/arch`" in
-           sun3)
-               echo m68k-sun-sunos${UNAME_RELEASE}
-               ;;
-           sun4)
-               echo sparc-sun-sunos${UNAME_RELEASE}
-               ;;
-       esac
-       exit ;;
-    aushp:SunOS:*:*)
-       echo sparc-auspex-sunos${UNAME_RELEASE}
-       exit ;;
-    # The situation for MiNT is a little confusing.  The machine name
-    # can be virtually everything (everything which is not
-    # "atarist" or "atariste" at least should have a processor
-    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
-    # to the lowercase version "mint" (or "freemint").  Finally
-    # the system name "TOS" denotes a system which is actually not
-    # MiNT.  But MiNT is downward compatible to TOS, so this should
-    # be no problem.
-    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-       echo m68k-atari-mint${UNAME_RELEASE}
-       exit ;;
-    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
-       echo m68k-atari-mint${UNAME_RELEASE}
-       exit ;;
-    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-       echo m68k-atari-mint${UNAME_RELEASE}
-       exit ;;
-    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-       echo m68k-milan-mint${UNAME_RELEASE}
-       exit ;;
-    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-       echo m68k-hades-mint${UNAME_RELEASE}
-       exit ;;
-    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-       echo m68k-unknown-mint${UNAME_RELEASE}
-       exit ;;
-    m68k:machten:*:*)
-       echo m68k-apple-machten${UNAME_RELEASE}
-       exit ;;
-    powerpc:machten:*:*)
-       echo powerpc-apple-machten${UNAME_RELEASE}
-       exit ;;
-    RISC*:Mach:*:*)
-       echo mips-dec-mach_bsd4.3
-       exit ;;
-    RISC*:ULTRIX:*:*)
-       echo mips-dec-ultrix${UNAME_RELEASE}
-       exit ;;
-    VAX*:ULTRIX*:*:*)
-       echo vax-dec-ultrix${UNAME_RELEASE}
-       exit ;;
-    2020:CLIX:*:* | 2430:CLIX:*:*)
-       echo clipper-intergraph-clix${UNAME_RELEASE}
-       exit ;;
-    mips:*:*:UMIPS | mips:*:*:RISCos)
-       eval $set_cc_for_build
-       sed 's/^        //' << EOF >$dummy.c
-#ifdef __cplusplus
-#include <stdio.h>  /* for printf() prototype */
-       int main (int argc, char *argv[]) {
-#else
-       int main (argc, argv) int argc; char *argv[]; {
-#endif
-       #if defined (host_mips) && defined (MIPSEB)
-       #if defined (SYSTYPE_SYSV)
-         printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
-       #endif
-       #if defined (SYSTYPE_SVR4)
-         printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
-       #endif
-       #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
-         printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
-       #endif
-       #endif
-         exit (-1);
-       }
-EOF
-       $CC_FOR_BUILD -o $dummy $dummy.c &&
-         dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
-         SYSTEM_NAME=`$dummy $dummyarg` &&
-           { echo "$SYSTEM_NAME"; exit; }
-       echo mips-mips-riscos${UNAME_RELEASE}
-       exit ;;
-    Motorola:PowerMAX_OS:*:*)
-       echo powerpc-motorola-powermax
-       exit ;;
-    Motorola:*:4.3:PL8-*)
-       echo powerpc-harris-powermax
-       exit ;;
-    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
-       echo powerpc-harris-powermax
-       exit ;;
-    Night_Hawk:Power_UNIX:*:*)
-       echo powerpc-harris-powerunix
-       exit ;;
-    m88k:CX/UX:7*:*)
-       echo m88k-harris-cxux7
-       exit ;;
-    m88k:*:4*:R4*)
-       echo m88k-motorola-sysv4
-       exit ;;
-    m88k:*:3*:R3*)
-       echo m88k-motorola-sysv3
-       exit ;;
-    AViiON:dgux:*:*)
-       # DG/UX returns AViiON for all architectures
-       UNAME_PROCESSOR=`/usr/bin/uname -p`
-       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
-       then
-           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
-              [ ${TARGET_BINARY_INTERFACE}x = x ]
-           then
-               echo m88k-dg-dgux${UNAME_RELEASE}
-           else
-               echo m88k-dg-dguxbcs${UNAME_RELEASE}
-           fi
-       else
-           echo i586-dg-dgux${UNAME_RELEASE}
-       fi
-       exit ;;
-    M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
-       echo m88k-dolphin-sysv3
-       exit ;;
-    M88*:*:R3*:*)
-       # Delta 88k system running SVR3
-       echo m88k-motorola-sysv3
-       exit ;;
-    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
-       echo m88k-tektronix-sysv3
-       exit ;;
-    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
-       echo m68k-tektronix-bsd
-       exit ;;
-    *:IRIX*:*:*)
-       echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
-       exit ;;
-    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
-       echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
-       exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
-    i*86:AIX:*:*)
-       echo i386-ibm-aix
-       exit ;;
-    ia64:AIX:*:*)
-       if [ -x /usr/bin/oslevel ] ; then
-               IBM_REV=`/usr/bin/oslevel`
-       else
-               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
-       fi
-       echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
-       exit ;;
-    *:AIX:2:3)
-       if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
-               eval $set_cc_for_build
-               sed 's/^                //' << EOF >$dummy.c
-               #include <sys/systemcfg.h>
-
-               main()
-                       {
-                       if (!__power_pc())
-                               exit(1);
-                       puts("powerpc-ibm-aix3.2.5");
-                       exit(0);
-                       }
-EOF
-               if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
-               then
-                       echo "$SYSTEM_NAME"
-               else
-                       echo rs6000-ibm-aix3.2.5
-               fi
-       elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
-               echo rs6000-ibm-aix3.2.4
-       else
-               echo rs6000-ibm-aix3.2
-       fi
-       exit ;;
-    *:AIX:*:[4567])
-       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
-       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
-               IBM_ARCH=rs6000
-       else
-               IBM_ARCH=powerpc
-       fi
-       if [ -x /usr/bin/lslpp ] ; then
-               IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
-                          awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
-       else
-               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
-       fi
-       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
-       exit ;;
-    *:AIX:*:*)
-       echo rs6000-ibm-aix
-       exit ;;
-    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
-       echo romp-ibm-bsd4.4
-       exit ;;
-    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
-       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
-       exit ;;                             # report: romp-ibm BSD 4.3
-    *:BOSX:*:*)
-       echo rs6000-bull-bosx
-       exit ;;
-    DPX/2?00:B.O.S.:*:*)
-       echo m68k-bull-sysv3
-       exit ;;
-    9000/[34]??:4.3bsd:1.*:*)
-       echo m68k-hp-bsd
-       exit ;;
-    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
-       echo m68k-hp-bsd4.4
-       exit ;;
-    9000/[34678]??:HP-UX:*:*)
-       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
-       case "${UNAME_MACHINE}" in
-           9000/31? )            HP_ARCH=m68000 ;;
-           9000/[34]?? )         HP_ARCH=m68k ;;
-           9000/[678][0-9][0-9])
-               if [ -x /usr/bin/getconf ]; then
-                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
-                   sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
-                   case "${sc_cpu_version}" in
-                     523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
-                     528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
-                     532)                      # CPU_PA_RISC2_0
-                       case "${sc_kernel_bits}" in
-                         32) HP_ARCH="hppa2.0n" ;;
-                         64) HP_ARCH="hppa2.0w" ;;
-                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
-                       esac ;;
-                   esac
-               fi
-               if [ "${HP_ARCH}" = "" ]; then
-                   eval $set_cc_for_build
-                   sed 's/^            //' << EOF >$dummy.c
-
-               #define _HPUX_SOURCE
-               #include <stdlib.h>
-               #include <unistd.h>
-
-               int main ()
-               {
-               #if defined(_SC_KERNEL_BITS)
-                   long bits = sysconf(_SC_KERNEL_BITS);
-               #endif
-                   long cpu  = sysconf (_SC_CPU_VERSION);
-
-                   switch (cpu)
-                       {
-                       case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
-                       case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
-                       case CPU_PA_RISC2_0:
-               #if defined(_SC_KERNEL_BITS)
-                           switch (bits)
-                               {
-                               case 64: puts ("hppa2.0w"); break;
-                               case 32: puts ("hppa2.0n"); break;
-                               default: puts ("hppa2.0"); break;
-                               } break;
-               #else  /* !defined(_SC_KERNEL_BITS) */
-                           puts ("hppa2.0"); break;
-               #endif
-                       default: puts ("hppa1.0"); break;
-                       }
-                   exit (0);
-               }
-EOF
-                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
-                   test -z "$HP_ARCH" && HP_ARCH=hppa
-               fi ;;
-       esac
-       if [ ${HP_ARCH} = "hppa2.0w" ]
-       then
-           eval $set_cc_for_build
-
-           # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
-           # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
-           # generating 64-bit code.  GNU and HP use different nomenclature:
-           #
-           # $ CC_FOR_BUILD=cc ./config.guess
-           # => hppa2.0w-hp-hpux11.23
-           # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
-           # => hppa64-hp-hpux11.23
-
-           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
-               grep -q __LP64__
-           then
-               HP_ARCH="hppa2.0w"
-           else
-               HP_ARCH="hppa64"
-           fi
-       fi
-       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
-       exit ;;
-    ia64:HP-UX:*:*)
-       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
-       echo ia64-hp-hpux${HPUX_REV}
-       exit ;;
-    3050*:HI-UX:*:*)
-       eval $set_cc_for_build
-       sed 's/^        //' << EOF >$dummy.c
-       #include <unistd.h>
-       int
-       main ()
-       {
-         long cpu = sysconf (_SC_CPU_VERSION);
-         /* The order matters, because CPU_IS_HP_MC68K erroneously returns
-            true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
-            results, however.  */
-         if (CPU_IS_PA_RISC (cpu))
-           {
-             switch (cpu)
-               {
-                 case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
-                 case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
-                 case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
-                 default: puts ("hppa-hitachi-hiuxwe2"); break;
-               }
-           }
-         else if (CPU_IS_HP_MC68K (cpu))
-           puts ("m68k-hitachi-hiuxwe2");
-         else puts ("unknown-hitachi-hiuxwe2");
-         exit (0);
-       }
-EOF
-       $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
-               { echo "$SYSTEM_NAME"; exit; }
-       echo unknown-hitachi-hiuxwe2
-       exit ;;
-    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
-       echo hppa1.1-hp-bsd
-       exit ;;
-    9000/8??:4.3bsd:*:*)
-       echo hppa1.0-hp-bsd
-       exit ;;
-    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
-       echo hppa1.0-hp-mpeix
-       exit ;;
-    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
-       echo hppa1.1-hp-osf
-       exit ;;
-    hp8??:OSF1:*:*)
-       echo hppa1.0-hp-osf
-       exit ;;
-    i*86:OSF1:*:*)
-       if [ -x /usr/sbin/sysversion ] ; then
-           echo ${UNAME_MACHINE}-unknown-osf1mk
-       else
-           echo ${UNAME_MACHINE}-unknown-osf1
-       fi
-       exit ;;
-    parisc*:Lites*:*:*)
-       echo hppa1.1-hp-lites
-       exit ;;
-    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
-       echo c1-convex-bsd
-       exit ;;
-    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
-       if getsysinfo -f scalar_acc
-       then echo c32-convex-bsd
-       else echo c2-convex-bsd
-       fi
-       exit ;;
-    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
-       echo c34-convex-bsd
-       exit ;;
-    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
-       echo c38-convex-bsd
-       exit ;;
-    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
-       echo c4-convex-bsd
-       exit ;;
-    CRAY*Y-MP:*:*:*)
-       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
-    CRAY*[A-Z]90:*:*:*)
-       echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
-       | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
-             -e 's/\.[^.]*$/.X/'
-       exit ;;
-    CRAY*TS:*:*:*)
-       echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
-    CRAY*T3E:*:*:*)
-       echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
-    CRAY*SV1:*:*:*)
-       echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
-    *:UNICOS/mp:*:*)
-       echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit ;;
-    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
-       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-       FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
-       echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-       exit ;;
-    5000:UNIX_System_V:4.*:*)
-       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-       FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
-       echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-       exit ;;
-    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
-       echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
-       exit ;;
-    sparc*:BSD/OS:*:*)
-       echo sparc-unknown-bsdi${UNAME_RELEASE}
-       exit ;;
-    *:BSD/OS:*:*)
-       echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
-       exit ;;
-    *:FreeBSD:*:*)
-       UNAME_PROCESSOR=`/usr/bin/uname -p`
-       case ${UNAME_PROCESSOR} in
-           amd64)
-               echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
-           *)
-               echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
-       esac
-       exit ;;
-    i*:CYGWIN*:*)
-       echo ${UNAME_MACHINE}-pc-cygwin
-       exit ;;
-    *:MINGW64*:*)
-       echo ${UNAME_MACHINE}-pc-mingw64
-       exit ;;
-    *:MINGW*:*)
-       echo ${UNAME_MACHINE}-pc-mingw32
-       exit ;;
-    *:MSYS*:*)
-       echo ${UNAME_MACHINE}-pc-msys
-       exit ;;
-    i*:windows32*:*)
-       # uname -m includes "-pc" on this system.
-       echo ${UNAME_MACHINE}-mingw32
-       exit ;;
-    i*:PW*:*)
-       echo ${UNAME_MACHINE}-pc-pw32
-       exit ;;
-    *:Interix*:*)
-       case ${UNAME_MACHINE} in
-           x86)
-               echo i586-pc-interix${UNAME_RELEASE}
-               exit ;;
-           authenticamd | genuineintel | EM64T)
-               echo x86_64-unknown-interix${UNAME_RELEASE}
-               exit ;;
-           IA64)
-               echo ia64-unknown-interix${UNAME_RELEASE}
-               exit ;;
-       esac ;;
-    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
-       echo i${UNAME_MACHINE}-pc-mks
-       exit ;;
-    8664:Windows_NT:*)
-       echo x86_64-pc-mks
-       exit ;;
-    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
-       # How do we know it's Interix rather than the generic POSIX subsystem?
-       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
-       # UNAME_MACHINE based on the output of uname instead of i386?
-       echo i586-pc-interix
-       exit ;;
-    i*:UWIN*:*)
-       echo ${UNAME_MACHINE}-pc-uwin
-       exit ;;
-    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
-       echo x86_64-unknown-cygwin
-       exit ;;
-    p*:CYGWIN*:*)
-       echo powerpcle-unknown-cygwin
-       exit ;;
-    prep*:SunOS:5.*:*)
-       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
-       exit ;;
-    *:GNU:*:*)
-       # the GNU system
-       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
-       exit ;;
-    *:GNU/*:*:*)
-       # other systems with GNU libc and userland
-       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
-       exit ;;
-    i*86:Minix:*:*)
-       echo ${UNAME_MACHINE}-pc-minix
-       exit ;;
-    aarch64:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    aarch64_be:Linux:*:*)
-       UNAME_MACHINE=aarch64_be
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    alpha:Linux:*:*)
-       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
-         EV5)   UNAME_MACHINE=alphaev5 ;;
-         EV56)  UNAME_MACHINE=alphaev56 ;;
-         PCA56) UNAME_MACHINE=alphapca56 ;;
-         PCA57) UNAME_MACHINE=alphapca56 ;;
-         EV6)   UNAME_MACHINE=alphaev6 ;;
-         EV67)  UNAME_MACHINE=alphaev67 ;;
-         EV68*) UNAME_MACHINE=alphaev68 ;;
-       esac
-       objdump --private-headers /bin/sh | grep -q ld.so.1
-       if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    arc:Linux:*:* | arceb:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    arm*:Linux:*:*)
-       eval $set_cc_for_build
-       if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
-           | grep -q __ARM_EABI__
-       then
-           echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       else
-           if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
-               | grep -q __ARM_PCS_VFP
-           then
-               echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
-           else
-               echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
-           fi
-       fi
-       exit ;;
-    avr32*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    cris:Linux:*:*)
-       echo ${UNAME_MACHINE}-axis-linux-${LIBC}
-       exit ;;
-    crisv32:Linux:*:*)
-       echo ${UNAME_MACHINE}-axis-linux-${LIBC}
-       exit ;;
-    e2k:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    frv:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    hexagon:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    i*86:Linux:*:*)
-       echo ${UNAME_MACHINE}-pc-linux-${LIBC}
-       exit ;;
-    ia64:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    m32r*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    m68*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    mips:Linux:*:* | mips64:Linux:*:*)
-       eval $set_cc_for_build
-       sed 's/^        //' << EOF >$dummy.c
-       #undef CPU
-       #undef ${UNAME_MACHINE}
-       #undef ${UNAME_MACHINE}el
-       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-       CPU=${UNAME_MACHINE}el
-       #else
-       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-       CPU=${UNAME_MACHINE}
-       #else
-       CPU=
-       #endif
-       #endif
-EOF
-       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
-       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
-       ;;
-    openrisc*:Linux:*:*)
-       echo or1k-unknown-linux-${LIBC}
-       exit ;;
-    or32:Linux:*:* | or1k*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    padre:Linux:*:*)
-       echo sparc-unknown-linux-${LIBC}
-       exit ;;
-    parisc64:Linux:*:* | hppa64:Linux:*:*)
-       echo hppa64-unknown-linux-${LIBC}
-       exit ;;
-    parisc:Linux:*:* | hppa:Linux:*:*)
-       # Look for CPU level
-       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
-         PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
-         PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
-         *)    echo hppa-unknown-linux-${LIBC} ;;
-       esac
-       exit ;;
-    ppc64:Linux:*:*)
-       echo powerpc64-unknown-linux-${LIBC}
-       exit ;;
-    ppc:Linux:*:*)
-       echo powerpc-unknown-linux-${LIBC}
-       exit ;;
-    ppc64le:Linux:*:*)
-       echo powerpc64le-unknown-linux-${LIBC}
-       exit ;;
-    ppcle:Linux:*:*)
-       echo powerpcle-unknown-linux-${LIBC}
-       exit ;;
-    s390:Linux:*:* | s390x:Linux:*:*)
-       echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
-       exit ;;
-    sh64*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    sh*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    sparc:Linux:*:* | sparc64:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    tile*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    vax:Linux:*:*)
-       echo ${UNAME_MACHINE}-dec-linux-${LIBC}
-       exit ;;
-    x86_64:Linux:*:*)
-       echo ${UNAME_MACHINE}-pc-linux-${LIBC}
-       exit ;;
-    xtensa*:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
-       exit ;;
-    i*86:DYNIX/ptx:4*:*)
-       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
-       # earlier versions are messed up and put the nodename in both
-       # sysname and nodename.
-       echo i386-sequent-sysv4
-       exit ;;
-    i*86:UNIX_SV:4.2MP:2.*)
-       # Unixware is an offshoot of SVR4, but it has its own version
-       # number series starting with 2...
-       # I am not positive that other SVR4 systems won't match this,
-       # I just have to hope.  -- rms.
-       # Use sysv4.2uw... so that sysv4* matches it.
-       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
-       exit ;;
-    i*86:OS/2:*:*)
-       # If we were able to find `uname', then EMX Unix compatibility
-       # is probably installed.
-       echo ${UNAME_MACHINE}-pc-os2-emx
-       exit ;;
-    i*86:XTS-300:*:STOP)
-       echo ${UNAME_MACHINE}-unknown-stop
-       exit ;;
-    i*86:atheos:*:*)
-       echo ${UNAME_MACHINE}-unknown-atheos
-       exit ;;
-    i*86:syllable:*:*)
-       echo ${UNAME_MACHINE}-pc-syllable
-       exit ;;
-    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
-       echo i386-unknown-lynxos${UNAME_RELEASE}
-       exit ;;
-    i*86:*DOS:*:*)
-       echo ${UNAME_MACHINE}-pc-msdosdjgpp
-       exit ;;
-    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
-       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
-       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
-       else
-               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
-       fi
-       exit ;;
-    i*86:*:5:[678]*)
-       # UnixWare 7.x, OpenUNIX and OpenServer 6.
-       case `/bin/uname -X | grep "^Machine"` in
-           *486*)           UNAME_MACHINE=i486 ;;
-           *Pentium)        UNAME_MACHINE=i586 ;;
-           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
-       esac
-       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
-       exit ;;
-    i*86:*:3.2:*)
-       if test -f /usr/options/cb.name; then
-               UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
-               echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
-       elif /bin/uname -X 2>/dev/null >/dev/null ; then
-               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
-               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
-               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
-                       && UNAME_MACHINE=i586
-               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
-                       && UNAME_MACHINE=i686
-               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
-                       && UNAME_MACHINE=i686
-               echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
-       else
-               echo ${UNAME_MACHINE}-pc-sysv32
-       fi
-       exit ;;
-    pc:*:*:*)
-       # Left here for compatibility:
-       # uname -m prints for DJGPP always 'pc', but it prints nothing about
-       # the processor, so we play safe by assuming i586.
-       # Note: whatever this is, it MUST be the same as what config.sub
-       # prints for the "djgpp" host, or else GDB configury will decide that
-       # this is a cross-build.
-       echo i586-pc-msdosdjgpp
-       exit ;;
-    Intel:Mach:3*:*)
-       echo i386-pc-mach3
-       exit ;;
-    paragon:*:*:*)
-       echo i860-intel-osf1
-       exit ;;
-    i860:*:4.*:*) # i860-SVR4
-       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
-         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
-       else # Add other i860-SVR4 vendors below as they are discovered.
-         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
-       fi
-       exit ;;
-    mini*:CTIX:SYS*5:*)
-       # "miniframe"
-       echo m68010-convergent-sysv
-       exit ;;
-    mc68k:UNIX:SYSTEM5:3.51m)
-       echo m68k-convergent-sysv
-       exit ;;
-    M680?0:D-NIX:5.3:*)
-       echo m68k-diab-dnix
-       exit ;;
-    M68*:*:R3V[5678]*:*)
-       test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
-    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
-       OS_REL=''
-       test -r /etc/.relid \
-       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
-       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-         && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
-       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
-         && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
-    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
-       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-         && { echo i486-ncr-sysv4; exit; } ;;
-    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
-       OS_REL='.3'
-       test -r /etc/.relid \
-           && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
-       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-           && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
-       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
-           && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
-       /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
-           && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
-    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
-       echo m68k-unknown-lynxos${UNAME_RELEASE}
-       exit ;;
-    mc68030:UNIX_System_V:4.*:*)
-       echo m68k-atari-sysv4
-       exit ;;
-    TSUNAMI:LynxOS:2.*:*)
-       echo sparc-unknown-lynxos${UNAME_RELEASE}
-       exit ;;
-    rs6000:LynxOS:2.*:*)
-       echo rs6000-unknown-lynxos${UNAME_RELEASE}
-       exit ;;
-    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
-       echo powerpc-unknown-lynxos${UNAME_RELEASE}
-       exit ;;
-    SM[BE]S:UNIX_SV:*:*)
-       echo mips-dde-sysv${UNAME_RELEASE}
-       exit ;;
-    RM*:ReliantUNIX-*:*:*)
-       echo mips-sni-sysv4
-       exit ;;
-    RM*:SINIX-*:*:*)
-       echo mips-sni-sysv4
-       exit ;;
-    *:SINIX-*:*:*)
-       if uname -p 2>/dev/null >/dev/null ; then
-               UNAME_MACHINE=`(uname -p) 2>/dev/null`
-               echo ${UNAME_MACHINE}-sni-sysv4
-       else
-               echo ns32k-sni-sysv
-       fi
-       exit ;;
-    PENTIUM:*:4.0*:*)  # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
-                       # says <Richard.M.Bartel@ccMail.Census.GOV>
-       echo i586-unisys-sysv4
-       exit ;;
-    *:UNIX_System_V:4*:FTX*)
-       # From Gerald Hewes <hewes@openmarket.com>.
-       # How about differentiating between stratus architectures? -djm
-       echo hppa1.1-stratus-sysv4
-       exit ;;
-    *:*:*:FTX*)
-       # From seanf@swdc.stratus.com.
-       echo i860-stratus-sysv4
-       exit ;;
-    i*86:VOS:*:*)
-       # From Paul.Green@stratus.com.
-       echo ${UNAME_MACHINE}-stratus-vos
-       exit ;;
-    *:VOS:*:*)
-       # From Paul.Green@stratus.com.
-       echo hppa1.1-stratus-vos
-       exit ;;
-    mc68*:A/UX:*:*)
-       echo m68k-apple-aux${UNAME_RELEASE}
-       exit ;;
-    news*:NEWS-OS:6*:*)
-       echo mips-sony-newsos6
-       exit ;;
-    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
-       if [ -d /usr/nec ]; then
-               echo mips-nec-sysv${UNAME_RELEASE}
-       else
-               echo mips-unknown-sysv${UNAME_RELEASE}
-       fi
-       exit ;;
-    BeBox:BeOS:*:*)    # BeOS running on hardware made by Be, PPC only.
-       echo powerpc-be-beos
-       exit ;;
-    BeMac:BeOS:*:*)    # BeOS running on Mac or Mac clone, PPC only.
-       echo powerpc-apple-beos
-       exit ;;
-    BePC:BeOS:*:*)     # BeOS running on Intel PC compatible.
-       echo i586-pc-beos
-       exit ;;
-    BePC:Haiku:*:*)    # Haiku running on Intel PC compatible.
-       echo i586-pc-haiku
-       exit ;;
-    x86_64:Haiku:*:*)
-       echo x86_64-unknown-haiku
-       exit ;;
-    SX-4:SUPER-UX:*:*)
-       echo sx4-nec-superux${UNAME_RELEASE}
-       exit ;;
-    SX-5:SUPER-UX:*:*)
-       echo sx5-nec-superux${UNAME_RELEASE}
-       exit ;;
-    SX-6:SUPER-UX:*:*)
-       echo sx6-nec-superux${UNAME_RELEASE}
-       exit ;;
-    SX-7:SUPER-UX:*:*)
-       echo sx7-nec-superux${UNAME_RELEASE}
-       exit ;;
-    SX-8:SUPER-UX:*:*)
-       echo sx8-nec-superux${UNAME_RELEASE}
-       exit ;;
-    SX-8R:SUPER-UX:*:*)
-       echo sx8r-nec-superux${UNAME_RELEASE}
-       exit ;;
-    Power*:Rhapsody:*:*)
-       echo powerpc-apple-rhapsody${UNAME_RELEASE}
-       exit ;;
-    *:Rhapsody:*:*)
-       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
-       exit ;;
-    *:Darwin:*:*)
-       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
-       eval $set_cc_for_build
-       if test "$UNAME_PROCESSOR" = unknown ; then
-           UNAME_PROCESSOR=powerpc
-       fi
-       if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
-           if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-               if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-                   (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-                   grep IS_64BIT_ARCH >/dev/null
-               then
-                   case $UNAME_PROCESSOR in
-                       i386) UNAME_PROCESSOR=x86_64 ;;
-                       powerpc) UNAME_PROCESSOR=powerpc64 ;;
-                   esac
-               fi
-           fi
-       elif test "$UNAME_PROCESSOR" = i386 ; then
-           # Avoid executing cc on OS X 10.9, as it ships with a stub
-           # that puts up a graphical alert prompting to install
-           # developer tools.  Any system running Mac OS X 10.7 or
-           # later (Darwin 11 and later) is required to have a 64-bit
-           # processor. This is not true of the ARM version of Darwin
-           # that Apple uses in portable devices.
-           UNAME_PROCESSOR=x86_64
-       fi
-       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
-       exit ;;
-    *:procnto*:*:* | *:QNX:[0123456789]*:*)
-       UNAME_PROCESSOR=`uname -p`
-       if test "$UNAME_PROCESSOR" = "x86"; then
-               UNAME_PROCESSOR=i386
-               UNAME_MACHINE=pc
-       fi
-       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
-       exit ;;
-    *:QNX:*:4*)
-       echo i386-pc-qnx
-       exit ;;
-    NEO-?:NONSTOP_KERNEL:*:*)
-       echo neo-tandem-nsk${UNAME_RELEASE}
-       exit ;;
-    NSE-*:NONSTOP_KERNEL:*:*)
-       echo nse-tandem-nsk${UNAME_RELEASE}
-       exit ;;
-    NSR-?:NONSTOP_KERNEL:*:*)
-       echo nsr-tandem-nsk${UNAME_RELEASE}
-       exit ;;
-    *:NonStop-UX:*:*)
-       echo mips-compaq-nonstopux
-       exit ;;
-    BS2000:POSIX*:*:*)
-       echo bs2000-siemens-sysv
-       exit ;;
-    DS/*:UNIX_System_V:*:*)
-       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
-       exit ;;
-    *:Plan9:*:*)
-       # "uname -m" is not consistent, so use $cputype instead. 386
-       # is converted to i386 for consistency with other x86
-       # operating systems.
-       if test "$cputype" = "386"; then
-           UNAME_MACHINE=i386
-       else
-           UNAME_MACHINE="$cputype"
-       fi
-       echo ${UNAME_MACHINE}-unknown-plan9
-       exit ;;
-    *:TOPS-10:*:*)
-       echo pdp10-unknown-tops10
-       exit ;;
-    *:TENEX:*:*)
-       echo pdp10-unknown-tenex
-       exit ;;
-    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
-       echo pdp10-dec-tops20
-       exit ;;
-    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
-       echo pdp10-xkl-tops20
-       exit ;;
-    *:TOPS-20:*:*)
-       echo pdp10-unknown-tops20
-       exit ;;
-    *:ITS:*:*)
-       echo pdp10-unknown-its
-       exit ;;
-    SEI:*:*:SEIUX)
-       echo mips-sei-seiux${UNAME_RELEASE}
-       exit ;;
-    *:DragonFly:*:*)
-       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
-       exit ;;
-    *:*VMS:*:*)
-       UNAME_MACHINE=`(uname -p) 2>/dev/null`
-       case "${UNAME_MACHINE}" in
-           A*) echo alpha-dec-vms ; exit ;;
-           I*) echo ia64-dec-vms ; exit ;;
-           V*) echo vax-dec-vms ; exit ;;
-       esac ;;
-    *:XENIX:*:SysV)
-       echo i386-pc-xenix
-       exit ;;
-    i*86:skyos:*:*)
-       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
-       exit ;;
-    i*86:rdos:*:*)
-       echo ${UNAME_MACHINE}-pc-rdos
-       exit ;;
-    i*86:AROS:*:*)
-       echo ${UNAME_MACHINE}-pc-aros
-       exit ;;
-    x86_64:VMkernel:*:*)
-       echo ${UNAME_MACHINE}-unknown-esx
-       exit ;;
-esac
-
-cat >&2 <<EOF
-$0: unable to guess system type
-
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
-
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
-and
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
-
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <config-patches@gnu.org> in order to provide the needed
-information to handle your system.
-
-config.guess timestamp = $timestamp
-
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
-
-hostinfo               = `(hostinfo) 2>/dev/null`
-/bin/universe          = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch              = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
-
-UNAME_MACHINE = ${UNAME_MACHINE}
-UNAME_RELEASE = ${UNAME_RELEASE}
-UNAME_SYSTEM  = ${UNAME_SYSTEM}
-UNAME_VERSION = ${UNAME_VERSION}
-EOF
-
-exit 1
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
diff --git a/zfs/config/config.sub b/zfs/config/config.sub
deleted file mode 100755 (executable)
index 1acc966..0000000
+++ /dev/null
@@ -1,1813 +0,0 @@
-#! /bin/sh
-# Configuration validation subroutine script.
-#   Copyright 1992-2015 Free Software Foundation, Inc.
-
-timestamp='2015-08-20'
-
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that
-# program.  This Exception is an additional permission under section 7
-# of the GNU General Public License, version 3 ("GPLv3").
-
-
-# Please send patches to <config-patches@gnu.org>.
-#
-# Configuration subroutine to validate and canonicalize a configuration type.
-# Supply the specified configuration type as an argument.
-# If it is invalid, we print an error message on stderr and exit with code 1.
-# Otherwise, we print the canonical config type on stdout and succeed.
-
-# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
-
-# This file is supposed to be the same for all GNU packages
-# and recognize all the CPU types, system types and aliases
-# that are meaningful with *any* GNU software.
-# Each package is responsible for reporting which valid configurations
-# it does not support.  The user should be able to distinguish
-# a failure to support a valid configuration from a meaningless
-# configuration.
-
-# The goal of this file is to map all the various variations of a given
-# machine specification into a single specification in the form:
-#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or in some cases, the newer four-part form:
-#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# It is wrong to echo any other type of specification.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
-       $0 [OPTION] ALIAS
-
-Canonicalize a configuration name.
-
-Operation modes:
-  -h, --help         print this help, then exit
-  -t, --time-stamp   print date of last modification, then exit
-  -v, --version      print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.sub ($timestamp)
-
-Copyright 1992-2015 Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions.  There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
-  case $1 in
-    --time-stamp | --time* | -t )
-       echo "$timestamp" ; exit ;;
-    --version | -v )
-       echo "$version" ; exit ;;
-    --help | --h* | -h )
-       echo "$usage"; exit ;;
-    -- )     # Stop option processing
-       shift; break ;;
-    - )        # Use stdin as input.
-       break ;;
-    -* )
-       echo "$me: invalid option $1$help"
-       exit 1 ;;
-
-    *local*)
-       # First pass through any local machine types.
-       echo $1
-       exit ;;
-
-    * )
-       break ;;
-  esac
-done
-
-case $# in
- 0) echo "$me: missing argument$help" >&2
-    exit 1;;
- 1) ;;
- *) echo "$me: too many arguments$help" >&2
-    exit 1;;
-esac
-
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
-  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
-  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
-  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
-  kopensolaris*-gnu* | \
-  storm-chaos* | os2-emx* | rtmk-nova*)
-    os=-$maybe_os
-    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
-    ;;
-  android-linux)
-    os=-linux-android
-    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
-    ;;
-  *)
-    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
-    if [ $basic_machine != $1 ]
-    then os=`echo $1 | sed 's/.*-/-/'`
-    else os=; fi
-    ;;
-esac
-
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work.  We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
-       -sun*os*)
-               # Prevent following clause from handling this invalid input.
-               ;;
-       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
-       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
-       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
-       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-       -apple | -axis | -knuth | -cray | -microblaze*)
-               os=
-               basic_machine=$1
-               ;;
-       -bluegene*)
-               os=-cnk
-               ;;
-       -sim | -cisco | -oki | -wec | -winbond)
-               os=
-               basic_machine=$1
-               ;;
-       -scout)
-               ;;
-       -wrs)
-               os=-vxworks
-               basic_machine=$1
-               ;;
-       -chorusos*)
-               os=-chorusos
-               basic_machine=$1
-               ;;
-       -chorusrdb)
-               os=-chorusrdb
-               basic_machine=$1
-               ;;
-       -hiux*)
-               os=-hiuxwe2
-               ;;
-       -sco6)
-               os=-sco5v6
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco5)
-               os=-sco3.2v5
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco4)
-               os=-sco3.2v4
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco3.2.[4-9]*)
-               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco3.2v[4-9]*)
-               # Don't forget version if it is 3.2v4 or newer.
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco5v6*)
-               # Don't forget version if it is 3.2v4 or newer.
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -sco*)
-               os=-sco3.2v2
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -udk*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -isc)
-               os=-isc2.2
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -clix*)
-               basic_machine=clipper-intergraph
-               ;;
-       -isc*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
-               ;;
-       -lynx*178)
-               os=-lynxos178
-               ;;
-       -lynx*5)
-               os=-lynxos5
-               ;;
-       -lynx*)
-               os=-lynxos
-               ;;
-       -ptx*)
-               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
-               ;;
-       -windowsnt*)
-               os=`echo $os | sed -e 's/windowsnt/winnt/'`
-               ;;
-       -psos*)
-               os=-psos
-               ;;
-       -mint | -mint[0-9]*)
-               basic_machine=m68k-atari
-               os=-mint
-               ;;
-esac
-
-# Decode aliases for certain CPU-COMPANY combinations.
-case $basic_machine in
-       # Recognize the basic CPU types without company name.
-       # Some are omitted here because they have special meanings below.
-       1750a | 580 \
-       | a29k \
-       | aarch64 | aarch64_be \
-       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
-       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
-       | am33_2.0 \
-       | arc | arceb \
-       | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
-       | avr | avr32 \
-       | ba \
-       | be32 | be64 \
-       | bfin \
-       | c4x | c8051 | clipper \
-       | d10v | d30v | dlx | dsp16xx \
-       | e2k | epiphany \
-       | fido | fr30 | frv | ft32 \
-       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
-       | hexagon \
-       | i370 | i860 | i960 | ia64 \
-       | ip2k | iq2000 \
-       | k1om \
-       | le32 | le64 \
-       | lm32 \
-       | m32c | m32r | m32rle | m68000 | m68k | m88k \
-       | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
-       | mips | mipsbe | mipseb | mipsel | mipsle \
-       | mips16 \
-       | mips64 | mips64el \
-       | mips64octeon | mips64octeonel \
-       | mips64orion | mips64orionel \
-       | mips64r5900 | mips64r5900el \
-       | mips64vr | mips64vrel \
-       | mips64vr4100 | mips64vr4100el \
-       | mips64vr4300 | mips64vr4300el \
-       | mips64vr5000 | mips64vr5000el \
-       | mips64vr5900 | mips64vr5900el \
-       | mipsisa32 | mipsisa32el \
-       | mipsisa32r2 | mipsisa32r2el \
-       | mipsisa32r6 | mipsisa32r6el \
-       | mipsisa64 | mipsisa64el \
-       | mipsisa64r2 | mipsisa64r2el \
-       | mipsisa64r6 | mipsisa64r6el \
-       | mipsisa64sb1 | mipsisa64sb1el \
-       | mipsisa64sr71k | mipsisa64sr71kel \
-       | mipsr5900 | mipsr5900el \
-       | mipstx39 | mipstx39el \
-       | mn10200 | mn10300 \
-       | moxie \
-       | mt \
-       | msp430 \
-       | nds32 | nds32le | nds32be \
-       | nios | nios2 | nios2eb | nios2el \
-       | ns16k | ns32k \
-       | open8 | or1k | or1knd | or32 \
-       | pdp10 | pdp11 | pj | pjl \
-       | powerpc | powerpc64 | powerpc64le | powerpcle \
-       | pyramid \
-       | riscv32 | riscv64 \
-       | rl78 | rx \
-       | score \
-       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
-       | sh64 | sh64le \
-       | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
-       | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
-       | spu \
-       | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
-       | ubicom32 \
-       | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
-       | visium \
-       | we32k \
-       | x86 | xc16x | xstormy16 | xtensa \
-       | z8k | z80)
-               basic_machine=$basic_machine-unknown
-               ;;
-       c54x)
-               basic_machine=tic54x-unknown
-               ;;
-       c55x)
-               basic_machine=tic55x-unknown
-               ;;
-       c6x)
-               basic_machine=tic6x-unknown
-               ;;
-       leon|leon[3-9])
-               basic_machine=sparc-$basic_machine
-               ;;
-       m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
-               basic_machine=$basic_machine-unknown
-               os=-none
-               ;;
-       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
-               ;;
-       ms1)
-               basic_machine=mt-unknown
-               ;;
-
-       strongarm | thumb | xscale)
-               basic_machine=arm-unknown
-               ;;
-       xgate)
-               basic_machine=$basic_machine-unknown
-               os=-none
-               ;;
-       xscaleeb)
-               basic_machine=armeb-unknown
-               ;;
-
-       xscaleel)
-               basic_machine=armel-unknown
-               ;;
-
-       # We use `pc' rather than `unknown'
-       # because (1) that's what they normally are, and
-       # (2) the word "unknown" tends to confuse beginning users.
-       i*86 | x86_64)
-         basic_machine=$basic_machine-pc
-         ;;
-       # Object if more than one company name word.
-       *-*-*)
-               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
-               exit 1
-               ;;
-       # Recognize the basic CPU types with company name.
-       580-* \
-       | a29k-* \
-       | aarch64-* | aarch64_be-* \
-       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
-       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
-       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
-       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
-       | avr-* | avr32-* \
-       | ba-* \
-       | be32-* | be64-* \
-       | bfin-* | bs2000-* \
-       | c[123]* | c30-* | [cjt]90-* | c4x-* \
-       | c8051-* | clipper-* | craynv-* | cydra-* \
-       | d10v-* | d30v-* | dlx-* \
-       | e2k-* | elxsi-* \
-       | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
-       | h8300-* | h8500-* \
-       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
-       | hexagon-* \
-       | i*86-* | i860-* | i960-* | ia64-* \
-       | ip2k-* | iq2000-* \
-       | k1om-* \
-       | le32-* | le64-* \
-       | lm32-* \
-       | m32c-* | m32r-* | m32rle-* \
-       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
-       | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
-       | microblaze-* | microblazeel-* \
-       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
-       | mips16-* \
-       | mips64-* | mips64el-* \
-       | mips64octeon-* | mips64octeonel-* \
-       | mips64orion-* | mips64orionel-* \
-       | mips64r5900-* | mips64r5900el-* \
-       | mips64vr-* | mips64vrel-* \
-       | mips64vr4100-* | mips64vr4100el-* \
-       | mips64vr4300-* | mips64vr4300el-* \
-       | mips64vr5000-* | mips64vr5000el-* \
-       | mips64vr5900-* | mips64vr5900el-* \
-       | mipsisa32-* | mipsisa32el-* \
-       | mipsisa32r2-* | mipsisa32r2el-* \
-       | mipsisa32r6-* | mipsisa32r6el-* \
-       | mipsisa64-* | mipsisa64el-* \
-       | mipsisa64r2-* | mipsisa64r2el-* \
-       | mipsisa64r6-* | mipsisa64r6el-* \
-       | mipsisa64sb1-* | mipsisa64sb1el-* \
-       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
-       | mipsr5900-* | mipsr5900el-* \
-       | mipstx39-* | mipstx39el-* \
-       | mmix-* \
-       | mt-* \
-       | msp430-* \
-       | nds32-* | nds32le-* | nds32be-* \
-       | nios-* | nios2-* | nios2eb-* | nios2el-* \
-       | none-* | np1-* | ns16k-* | ns32k-* \
-       | open8-* \
-       | or1k*-* \
-       | orion-* \
-       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
-       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
-       | pyramid-* \
-       | riscv32-* | riscv64-* \
-       | rl78-* | romp-* | rs6000-* | rx-* \
-       | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
-       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
-       | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
-       | sparclite-* \
-       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
-       | tahoe-* \
-       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
-       | tile*-* \
-       | tron-* \
-       | ubicom32-* \
-       | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
-       | vax-* \
-       | visium-* \
-       | we32k-* \
-       | x86-* | x86_64-* | xc16x-* | xps100-* \
-       | xstormy16-* | xtensa*-* \
-       | ymp-* \
-       | z8k-* | z80-*)
-               ;;
-       # Recognize the basic CPU types without company name, with glob match.
-       xtensa*)
-               basic_machine=$basic_machine-unknown
-               ;;
-       # Recognize the various machine names and aliases which stand
-       # for a CPU type and a company and sometimes even an OS.
-       386bsd)
-               basic_machine=i386-unknown
-               os=-bsd
-               ;;
-       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
-               basic_machine=m68000-att
-               ;;
-       3b*)
-               basic_machine=we32k-att
-               ;;
-       a29khif)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       abacus)
-               basic_machine=abacus-unknown
-               ;;
-       adobe68k)
-               basic_machine=m68010-adobe
-               os=-scout
-               ;;
-       alliant | fx80)
-               basic_machine=fx80-alliant
-               ;;
-       altos | altos3068)
-               basic_machine=m68k-altos
-               ;;
-       am29k)
-               basic_machine=a29k-none
-               os=-bsd
-               ;;
-       amd64)
-               basic_machine=x86_64-pc
-               ;;
-       amd64-*)
-               basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       amdahl)
-               basic_machine=580-amdahl
-               os=-sysv
-               ;;
-       amiga | amiga-*)
-               basic_machine=m68k-unknown
-               ;;
-       amigaos | amigados)
-               basic_machine=m68k-unknown
-               os=-amigaos
-               ;;
-       amigaunix | amix)
-               basic_machine=m68k-unknown
-               os=-sysv4
-               ;;
-       apollo68)
-               basic_machine=m68k-apollo
-               os=-sysv
-               ;;
-       apollo68bsd)
-               basic_machine=m68k-apollo
-               os=-bsd
-               ;;
-       aros)
-               basic_machine=i386-pc
-               os=-aros
-               ;;
-        asmjs)
-               basic_machine=asmjs-unknown
-               ;;
-       aux)
-               basic_machine=m68k-apple
-               os=-aux
-               ;;
-       balance)
-               basic_machine=ns32k-sequent
-               os=-dynix
-               ;;
-       blackfin)
-               basic_machine=bfin-unknown
-               os=-linux
-               ;;
-       blackfin-*)
-               basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
-               os=-linux
-               ;;
-       bluegene*)
-               basic_machine=powerpc-ibm
-               os=-cnk
-               ;;
-       c54x-*)
-               basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       c55x-*)
-               basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       c6x-*)
-               basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       c90)
-               basic_machine=c90-cray
-               os=-unicos
-               ;;
-       cegcc)
-               basic_machine=arm-unknown
-               os=-cegcc
-               ;;
-       convex-c1)
-               basic_machine=c1-convex
-               os=-bsd
-               ;;
-       convex-c2)
-               basic_machine=c2-convex
-               os=-bsd
-               ;;
-       convex-c32)
-               basic_machine=c32-convex
-               os=-bsd
-               ;;
-       convex-c34)
-               basic_machine=c34-convex
-               os=-bsd
-               ;;
-       convex-c38)
-               basic_machine=c38-convex
-               os=-bsd
-               ;;
-       cray | j90)
-               basic_machine=j90-cray
-               os=-unicos
-               ;;
-       craynv)
-               basic_machine=craynv-cray
-               os=-unicosmp
-               ;;
-       cr16 | cr16-*)
-               basic_machine=cr16-unknown
-               os=-elf
-               ;;
-       crds | unos)
-               basic_machine=m68k-crds
-               ;;
-       crisv32 | crisv32-* | etraxfs*)
-               basic_machine=crisv32-axis
-               ;;
-       cris | cris-* | etrax*)
-               basic_machine=cris-axis
-               ;;
-       crx)
-               basic_machine=crx-unknown
-               os=-elf
-               ;;
-       da30 | da30-*)
-               basic_machine=m68k-da30
-               ;;
-       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
-               basic_machine=mips-dec
-               ;;
-       decsystem10* | dec10*)
-               basic_machine=pdp10-dec
-               os=-tops10
-               ;;
-       decsystem20* | dec20*)
-               basic_machine=pdp10-dec
-               os=-tops20
-               ;;
-       delta | 3300 | motorola-3300 | motorola-delta \
-             | 3300-motorola | delta-motorola)
-               basic_machine=m68k-motorola
-               ;;
-       delta88)
-               basic_machine=m88k-motorola
-               os=-sysv3
-               ;;
-       dicos)
-               basic_machine=i686-pc
-               os=-dicos
-               ;;
-       djgpp)
-               basic_machine=i586-pc
-               os=-msdosdjgpp
-               ;;
-       dpx20 | dpx20-*)
-               basic_machine=rs6000-bull
-               os=-bosx
-               ;;
-       dpx2* | dpx2*-bull)
-               basic_machine=m68k-bull
-               os=-sysv3
-               ;;
-       ebmon29k)
-               basic_machine=a29k-amd
-               os=-ebmon
-               ;;
-       elxsi)
-               basic_machine=elxsi-elxsi
-               os=-bsd
-               ;;
-       encore | umax | mmax)
-               basic_machine=ns32k-encore
-               ;;
-       es1800 | OSE68k | ose68k | ose | OSE)
-               basic_machine=m68k-ericsson
-               os=-ose
-               ;;
-       fx2800)
-               basic_machine=i860-alliant
-               ;;
-       genix)
-               basic_machine=ns32k-ns
-               ;;
-       gmicro)
-               basic_machine=tron-gmicro
-               os=-sysv
-               ;;
-       go32)
-               basic_machine=i386-pc
-               os=-go32
-               ;;
-       h3050r* | hiux*)
-               basic_machine=hppa1.1-hitachi
-               os=-hiuxwe2
-               ;;
-       h8300hms)
-               basic_machine=h8300-hitachi
-               os=-hms
-               ;;
-       h8300xray)
-               basic_machine=h8300-hitachi
-               os=-xray
-               ;;
-       h8500hms)
-               basic_machine=h8500-hitachi
-               os=-hms
-               ;;
-       harris)
-               basic_machine=m88k-harris
-               os=-sysv3
-               ;;
-       hp300-*)
-               basic_machine=m68k-hp
-               ;;
-       hp300bsd)
-               basic_machine=m68k-hp
-               os=-bsd
-               ;;
-       hp300hpux)
-               basic_machine=m68k-hp
-               os=-hpux
-               ;;
-       hp3k9[0-9][0-9] | hp9[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hp9k2[0-9][0-9] | hp9k31[0-9])
-               basic_machine=m68000-hp
-               ;;
-       hp9k3[2-9][0-9])
-               basic_machine=m68k-hp
-               ;;
-       hp9k6[0-9][0-9] | hp6[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hp9k7[0-79][0-9] | hp7[0-79][0-9])
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k78[0-9] | hp78[0-9])
-               # FIXME: really hppa2.0-hp
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
-               # FIXME: really hppa2.0-hp
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[0-9][13679] | hp8[0-9][13679])
-               basic_machine=hppa1.1-hp
-               ;;
-       hp9k8[0-9][0-9] | hp8[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               ;;
-       hppa-next)
-               os=-nextstep3
-               ;;
-       hppaosf)
-               basic_machine=hppa1.1-hp
-               os=-osf
-               ;;
-       hppro)
-               basic_machine=hppa1.1-hp
-               os=-proelf
-               ;;
-       i370-ibm* | ibm*)
-               basic_machine=i370-ibm
-               ;;
-       i*86v32)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv32
-               ;;
-       i*86v4*)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv4
-               ;;
-       i*86v)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-sysv
-               ;;
-       i*86sol2)
-               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
-               os=-solaris2
-               ;;
-       i386mach)
-               basic_machine=i386-mach
-               os=-mach
-               ;;
-       i386-vsta | vsta)
-               basic_machine=i386-unknown
-               os=-vsta
-               ;;
-       iris | iris4d)
-               basic_machine=mips-sgi
-               case $os in
-                   -irix*)
-                       ;;
-                   *)
-                       os=-irix4
-                       ;;
-               esac
-               ;;
-       isi68 | isi)
-               basic_machine=m68k-isi
-               os=-sysv
-               ;;
-       leon-*|leon[3-9]-*)
-               basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
-               ;;
-       m68knommu)
-               basic_machine=m68k-unknown
-               os=-linux
-               ;;
-       m68knommu-*)
-               basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
-               os=-linux
-               ;;
-       m88k-omron*)
-               basic_machine=m88k-omron
-               ;;
-       magnum | m3230)
-               basic_machine=mips-mips
-               os=-sysv
-               ;;
-       merlin)
-               basic_machine=ns32k-utek
-               os=-sysv
-               ;;
-       microblaze*)
-               basic_machine=microblaze-xilinx
-               ;;
-       mingw64)
-               basic_machine=x86_64-pc
-               os=-mingw64
-               ;;
-       mingw32)
-               basic_machine=i686-pc
-               os=-mingw32
-               ;;
-       mingw32ce)
-               basic_machine=arm-unknown
-               os=-mingw32ce
-               ;;
-       miniframe)
-               basic_machine=m68000-convergent
-               ;;
-       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
-               basic_machine=m68k-atari
-               os=-mint
-               ;;
-       mips3*-*)
-               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
-               ;;
-       mips3*)
-               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
-               ;;
-       monitor)
-               basic_machine=m68k-rom68k
-               os=-coff
-               ;;
-       morphos)
-               basic_machine=powerpc-unknown
-               os=-morphos
-               ;;
-       moxiebox)
-               basic_machine=moxie-unknown
-               os=-moxiebox
-               ;;
-       msdos)
-               basic_machine=i386-pc
-               os=-msdos
-               ;;
-       ms1-*)
-               basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
-               ;;
-       msys)
-               basic_machine=i686-pc
-               os=-msys
-               ;;
-       mvs)
-               basic_machine=i370-ibm
-               os=-mvs
-               ;;
-       nacl)
-               basic_machine=le32-unknown
-               os=-nacl
-               ;;
-       ncr3000)
-               basic_machine=i486-ncr
-               os=-sysv4
-               ;;
-       netbsd386)
-               basic_machine=i386-unknown
-               os=-netbsd
-               ;;
-       netwinder)
-               basic_machine=armv4l-rebel
-               os=-linux
-               ;;
-       news | news700 | news800 | news900)
-               basic_machine=m68k-sony
-               os=-newsos
-               ;;
-       news1000)
-               basic_machine=m68030-sony
-               os=-newsos
-               ;;
-       news-3600 | risc-news)
-               basic_machine=mips-sony
-               os=-newsos
-               ;;
-       necv70)
-               basic_machine=v70-nec
-               os=-sysv
-               ;;
-       next | m*-next )
-               basic_machine=m68k-next
-               case $os in
-                   -nextstep* )
-                       ;;
-                   -ns2*)
-                     os=-nextstep2
-                       ;;
-                   *)
-                     os=-nextstep3
-                       ;;
-               esac
-               ;;
-       nh3000)
-               basic_machine=m68k-harris
-               os=-cxux
-               ;;
-       nh[45]000)
-               basic_machine=m88k-harris
-               os=-cxux
-               ;;
-       nindy960)
-               basic_machine=i960-intel
-               os=-nindy
-               ;;
-       mon960)
-               basic_machine=i960-intel
-               os=-mon960
-               ;;
-       nonstopux)
-               basic_machine=mips-compaq
-               os=-nonstopux
-               ;;
-       np1)
-               basic_machine=np1-gould
-               ;;
-       neo-tandem)
-               basic_machine=neo-tandem
-               ;;
-       nse-tandem)
-               basic_machine=nse-tandem
-               ;;
-       nsr-tandem)
-               basic_machine=nsr-tandem
-               ;;
-       op50n-* | op60c-*)
-               basic_machine=hppa1.1-oki
-               os=-proelf
-               ;;
-       openrisc | openrisc-*)
-               basic_machine=or32-unknown
-               ;;
-       os400)
-               basic_machine=powerpc-ibm
-               os=-os400
-               ;;
-       OSE68000 | ose68000)
-               basic_machine=m68000-ericsson
-               os=-ose
-               ;;
-       os68k)
-               basic_machine=m68k-none
-               os=-os68k
-               ;;
-       pa-hitachi)
-               basic_machine=hppa1.1-hitachi
-               os=-hiuxwe2
-               ;;
-       paragon)
-               basic_machine=i860-intel
-               os=-osf
-               ;;
-       parisc)
-               basic_machine=hppa-unknown
-               os=-linux
-               ;;
-       parisc-*)
-               basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
-               os=-linux
-               ;;
-       pbd)
-               basic_machine=sparc-tti
-               ;;
-       pbb)
-               basic_machine=m68k-tti
-               ;;
-       pc532 | pc532-*)
-               basic_machine=ns32k-pc532
-               ;;
-       pc98)
-               basic_machine=i386-pc
-               ;;
-       pc98-*)
-               basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pentium | p5 | k5 | k6 | nexgen | viac3)
-               basic_machine=i586-pc
-               ;;
-       pentiumpro | p6 | 6x86 | athlon | athlon_*)
-               basic_machine=i686-pc
-               ;;
-       pentiumii | pentium2 | pentiumiii | pentium3)
-               basic_machine=i686-pc
-               ;;
-       pentium4)
-               basic_machine=i786-pc
-               ;;
-       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
-               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pentiumpro-* | p6-* | 6x86-* | athlon-*)
-               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
-               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pentium4-*)
-               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       pn)
-               basic_machine=pn-gould
-               ;;
-       power)  basic_machine=power-ibm
-               ;;
-       ppc | ppcbe)    basic_machine=powerpc-unknown
-               ;;
-       ppc-* | ppcbe-*)
-               basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ppcle | powerpclittle | ppc-le | powerpc-little)
-               basic_machine=powerpcle-unknown
-               ;;
-       ppcle-* | powerpclittle-*)
-               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ppc64)  basic_machine=powerpc64-unknown
-               ;;
-       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
-               basic_machine=powerpc64le-unknown
-               ;;
-       ppc64le-* | powerpc64little-*)
-               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       ps2)
-               basic_machine=i386-ibm
-               ;;
-       pw32)
-               basic_machine=i586-unknown
-               os=-pw32
-               ;;
-       rdos | rdos64)
-               basic_machine=x86_64-pc
-               os=-rdos
-               ;;
-       rdos32)
-               basic_machine=i386-pc
-               os=-rdos
-               ;;
-       rom68k)
-               basic_machine=m68k-rom68k
-               os=-coff
-               ;;
-       rm[46]00)
-               basic_machine=mips-siemens
-               ;;
-       rtpc | rtpc-*)
-               basic_machine=romp-ibm
-               ;;
-       s390 | s390-*)
-               basic_machine=s390-ibm
-               ;;
-       s390x | s390x-*)
-               basic_machine=s390x-ibm
-               ;;
-       sa29200)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       sb1)
-               basic_machine=mipsisa64sb1-unknown
-               ;;
-       sb1el)
-               basic_machine=mipsisa64sb1el-unknown
-               ;;
-       sde)
-               basic_machine=mipsisa32-sde
-               os=-elf
-               ;;
-       sei)
-               basic_machine=mips-sei
-               os=-seiux
-               ;;
-       sequent)
-               basic_machine=i386-sequent
-               ;;
-       sh)
-               basic_machine=sh-hitachi
-               os=-hms
-               ;;
-       sh5el)
-               basic_machine=sh5le-unknown
-               ;;
-       sh64)
-               basic_machine=sh64-unknown
-               ;;
-       sparclite-wrs | simso-wrs)
-               basic_machine=sparclite-wrs
-               os=-vxworks
-               ;;
-       sps7)
-               basic_machine=m68k-bull
-               os=-sysv2
-               ;;
-       spur)
-               basic_machine=spur-unknown
-               ;;
-       st2000)
-               basic_machine=m68k-tandem
-               ;;
-       stratus)
-               basic_machine=i860-stratus
-               os=-sysv4
-               ;;
-       strongarm-* | thumb-*)
-               basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
-               ;;
-       sun2)
-               basic_machine=m68000-sun
-               ;;
-       sun2os3)
-               basic_machine=m68000-sun
-               os=-sunos3
-               ;;
-       sun2os4)
-               basic_machine=m68000-sun
-               os=-sunos4
-               ;;
-       sun3os3)
-               basic_machine=m68k-sun
-               os=-sunos3
-               ;;
-       sun3os4)
-               basic_machine=m68k-sun
-               os=-sunos4
-               ;;
-       sun4os3)
-               basic_machine=sparc-sun
-               os=-sunos3
-               ;;
-       sun4os4)
-               basic_machine=sparc-sun
-               os=-sunos4
-               ;;
-       sun4sol2)
-               basic_machine=sparc-sun
-               os=-solaris2
-               ;;
-       sun3 | sun3-*)
-               basic_machine=m68k-sun
-               ;;
-       sun4)
-               basic_machine=sparc-sun
-               ;;
-       sun386 | sun386i | roadrunner)
-               basic_machine=i386-sun
-               ;;
-       sv1)
-               basic_machine=sv1-cray
-               os=-unicos
-               ;;
-       symmetry)
-               basic_machine=i386-sequent
-               os=-dynix
-               ;;
-       t3e)
-               basic_machine=alphaev5-cray
-               os=-unicos
-               ;;
-       t90)
-               basic_machine=t90-cray
-               os=-unicos
-               ;;
-       tile*)
-               basic_machine=$basic_machine-unknown
-               os=-linux-gnu
-               ;;
-       tx39)
-               basic_machine=mipstx39-unknown
-               ;;
-       tx39el)
-               basic_machine=mipstx39el-unknown
-               ;;
-       toad1)
-               basic_machine=pdp10-xkl
-               os=-tops20
-               ;;
-       tower | tower-32)
-               basic_machine=m68k-ncr
-               ;;
-       tpf)
-               basic_machine=s390x-ibm
-               os=-tpf
-               ;;
-       udi29k)
-               basic_machine=a29k-amd
-               os=-udi
-               ;;
-       ultra3)
-               basic_machine=a29k-nyu
-               os=-sym1
-               ;;
-       v810 | necv810)
-               basic_machine=v810-nec
-               os=-none
-               ;;
-       vaxv)
-               basic_machine=vax-dec
-               os=-sysv
-               ;;
-       vms)
-               basic_machine=vax-dec
-               os=-vms
-               ;;
-       vpp*|vx|vx-*)
-               basic_machine=f301-fujitsu
-               ;;
-       vxworks960)
-               basic_machine=i960-wrs
-               os=-vxworks
-               ;;
-       vxworks68)
-               basic_machine=m68k-wrs
-               os=-vxworks
-               ;;
-       vxworks29k)
-               basic_machine=a29k-wrs
-               os=-vxworks
-               ;;
-       w65*)
-               basic_machine=w65-wdc
-               os=-none
-               ;;
-       w89k-*)
-               basic_machine=hppa1.1-winbond
-               os=-proelf
-               ;;
-       xbox)
-               basic_machine=i686-pc
-               os=-mingw32
-               ;;
-       xps | xps100)
-               basic_machine=xps100-honeywell
-               ;;
-       xscale-* | xscalee[bl]-*)
-               basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
-               ;;
-       ymp)
-               basic_machine=ymp-cray
-               os=-unicos
-               ;;
-       z8k-*-coff)
-               basic_machine=z8k-unknown
-               os=-sim
-               ;;
-       z80-*-coff)
-               basic_machine=z80-unknown
-               os=-sim
-               ;;
-       none)
-               basic_machine=none-none
-               os=-none
-               ;;
-
-# Here we handle the default manufacturer of certain CPU types.  It is in
-# some cases the only manufacturer, in others, it is the most popular.
-       w89k)
-               basic_machine=hppa1.1-winbond
-               ;;
-       op50n)
-               basic_machine=hppa1.1-oki
-               ;;
-       op60c)
-               basic_machine=hppa1.1-oki
-               ;;
-       romp)
-               basic_machine=romp-ibm
-               ;;
-       mmix)
-               basic_machine=mmix-knuth
-               ;;
-       rs6000)
-               basic_machine=rs6000-ibm
-               ;;
-       vax)
-               basic_machine=vax-dec
-               ;;
-       pdp10)
-               # there are many clones, so DEC is not a safe bet
-               basic_machine=pdp10-unknown
-               ;;
-       pdp11)
-               basic_machine=pdp11-dec
-               ;;
-       we32k)
-               basic_machine=we32k-att
-               ;;
-       sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
-               basic_machine=sh-unknown
-               ;;
-       sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
-               basic_machine=sparc-sun
-               ;;
-       cydra)
-               basic_machine=cydra-cydrome
-               ;;
-       orion)
-               basic_machine=orion-highlevel
-               ;;
-       orion105)
-               basic_machine=clipper-highlevel
-               ;;
-       mac | mpw | mac-mpw)
-               basic_machine=m68k-apple
-               ;;
-       pmac | pmac-mpw)
-               basic_machine=powerpc-apple
-               ;;
-       *-unknown)
-               # Make sure to match an already-canonicalized machine name.
-               ;;
-       *)
-               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
-               exit 1
-               ;;
-esac
-
-# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
-       *-digital*)
-               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
-               ;;
-       *-commodore*)
-               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
-               ;;
-       *)
-               ;;
-esac
-
-# Decode manufacturer-specific aliases for certain operating systems.
-
-if [ x"$os" != x"" ]
-then
-case $os in
-       # First match some system type aliases
-       # that might get confused with valid system types.
-       # -solaris* is a basic system type, with this one exception.
-       -auroraux)
-               os=-auroraux
-               ;;
-       -solaris1 | -solaris1.*)
-               os=`echo $os | sed -e 's|solaris1|sunos4|'`
-               ;;
-       -solaris)
-               os=-solaris2
-               ;;
-       -svr4*)
-               os=-sysv4
-               ;;
-       -unixware*)
-               os=-sysv4.2uw
-               ;;
-       -gnu/linux*)
-               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
-               ;;
-       # First accept the basic system types.
-       # The portable systems comes first.
-       # Each alternative MUST END IN A *, to match a version number.
-       # -sysv* is not here because it comes later, after sysvr4.
-       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
-             | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
-             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
-             | -sym* | -kopensolaris* | -plan9* \
-             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-             | -aos* | -aros* | -cloudabi* | -sortix* \
-             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
-             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
-             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
-             | -bitrig* | -openbsd* | -solidbsd* \
-             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
-             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
-             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
-             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
-             | -chorusos* | -chorusrdb* | -cegcc* \
-             | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-             | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
-             | -linux-newlib* | -linux-musl* | -linux-uclibc* \
-             | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
-             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
-             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
-             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
-             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
-             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
-             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
-       # Remember, each alternative MUST END IN *, to match a version number.
-               ;;
-       -qnx*)
-               case $basic_machine in
-                   x86-* | i*86-*)
-                       ;;
-                   *)
-                       os=-nto$os
-                       ;;
-               esac
-               ;;
-       -nto-qnx*)
-               ;;
-       -nto*)
-               os=`echo $os | sed -e 's|nto|nto-qnx|'`
-               ;;
-       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
-             | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
-             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
-               ;;
-       -mac*)
-               os=`echo $os | sed -e 's|mac|macos|'`
-               ;;
-       -linux-dietlibc)
-               os=-linux-dietlibc
-               ;;
-       -linux*)
-               os=`echo $os | sed -e 's|linux|linux-gnu|'`
-               ;;
-       -sunos5*)
-               os=`echo $os | sed -e 's|sunos5|solaris2|'`
-               ;;
-       -sunos6*)
-               os=`echo $os | sed -e 's|sunos6|solaris3|'`
-               ;;
-       -opened*)
-               os=-openedition
-               ;;
-       -os400*)
-               os=-os400
-               ;;
-       -wince*)
-               os=-wince
-               ;;
-       -osfrose*)
-               os=-osfrose
-               ;;
-       -osf*)
-               os=-osf
-               ;;
-       -utek*)
-               os=-bsd
-               ;;
-       -dynix*)
-               os=-bsd
-               ;;
-       -acis*)
-               os=-aos
-               ;;
-       -atheos*)
-               os=-atheos
-               ;;
-       -syllable*)
-               os=-syllable
-               ;;
-       -386bsd)
-               os=-bsd
-               ;;
-       -ctix* | -uts*)
-               os=-sysv
-               ;;
-       -nova*)
-               os=-rtmk-nova
-               ;;
-       -ns2 )
-               os=-nextstep2
-               ;;
-       -nsk*)
-               os=-nsk
-               ;;
-       # Preserve the version number of sinix5.
-       -sinix5.*)
-               os=`echo $os | sed -e 's|sinix|sysv|'`
-               ;;
-       -sinix*)
-               os=-sysv4
-               ;;
-       -tpf*)
-               os=-tpf
-               ;;
-       -triton*)
-               os=-sysv3
-               ;;
-       -oss*)
-               os=-sysv3
-               ;;
-       -svr4)
-               os=-sysv4
-               ;;
-       -svr3)
-               os=-sysv3
-               ;;
-       -sysvr4)
-               os=-sysv4
-               ;;
-       # This must come after -sysvr4.
-       -sysv*)
-               ;;
-       -ose*)
-               os=-ose
-               ;;
-       -es1800*)
-               os=-ose
-               ;;
-       -xenix)
-               os=-xenix
-               ;;
-       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
-               os=-mint
-               ;;
-       -aros*)
-               os=-aros
-               ;;
-       -zvmoe)
-               os=-zvmoe
-               ;;
-       -dicos*)
-               os=-dicos
-               ;;
-       -nacl*)
-               ;;
-       -none)
-               ;;
-       *)
-               # Get rid of the `-' at the beginning of $os.
-               os=`echo $os | sed 's/[^-]*-//'`
-               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
-               exit 1
-               ;;
-esac
-else
-
-# Here we handle the default operating systems that come with various machines.
-# The value should be what the vendor currently ships out the door with their
-# machine or put another way, the most popular os provided with the machine.
-
-# Note that if you're going to try to match "-MANUFACTURER" here (say,
-# "-sun"), then you have to tell the case statement up towards the top
-# that MANUFACTURER isn't an operating system.  Otherwise, code above
-# will signal an error saying that MANUFACTURER isn't an operating
-# system, and we'll never get to this point.
-
-case $basic_machine in
-       score-*)
-               os=-elf
-               ;;
-       spu-*)
-               os=-elf
-               ;;
-       *-acorn)
-               os=-riscix1.2
-               ;;
-       arm*-rebel)
-               os=-linux
-               ;;
-       arm*-semi)
-               os=-aout
-               ;;
-       c4x-* | tic4x-*)
-               os=-coff
-               ;;
-       c8051-*)
-               os=-elf
-               ;;
-       hexagon-*)
-               os=-elf
-               ;;
-       tic54x-*)
-               os=-coff
-               ;;
-       tic55x-*)
-               os=-coff
-               ;;
-       tic6x-*)
-               os=-coff
-               ;;
-       # This must come before the *-dec entry.
-       pdp10-*)
-               os=-tops20
-               ;;
-       pdp11-*)
-               os=-none
-               ;;
-       *-dec | vax-*)
-               os=-ultrix4.2
-               ;;
-       m68*-apollo)
-               os=-domain
-               ;;
-       i386-sun)
-               os=-sunos4.0.2
-               ;;
-       m68000-sun)
-               os=-sunos3
-               ;;
-       m68*-cisco)
-               os=-aout
-               ;;
-       mep-*)
-               os=-elf
-               ;;
-       mips*-cisco)
-               os=-elf
-               ;;
-       mips*-*)
-               os=-elf
-               ;;
-       or32-*)
-               os=-coff
-               ;;
-       *-tti)  # must be before sparc entry or we get the wrong os.
-               os=-sysv3
-               ;;
-       sparc-* | *-sun)
-               os=-sunos4.1.1
-               ;;
-       *-be)
-               os=-beos
-               ;;
-       *-haiku)
-               os=-haiku
-               ;;
-       *-ibm)
-               os=-aix
-               ;;
-       *-knuth)
-               os=-mmixware
-               ;;
-       *-wec)
-               os=-proelf
-               ;;
-       *-winbond)
-               os=-proelf
-               ;;
-       *-oki)
-               os=-proelf
-               ;;
-       *-hp)
-               os=-hpux
-               ;;
-       *-hitachi)
-               os=-hiux
-               ;;
-       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
-               os=-sysv
-               ;;
-       *-cbm)
-               os=-amigaos
-               ;;
-       *-dg)
-               os=-dgux
-               ;;
-       *-dolphin)
-               os=-sysv3
-               ;;
-       m68k-ccur)
-               os=-rtu
-               ;;
-       m88k-omron*)
-               os=-luna
-               ;;
-       *-next )
-               os=-nextstep
-               ;;
-       *-sequent)
-               os=-ptx
-               ;;
-       *-crds)
-               os=-unos
-               ;;
-       *-ns)
-               os=-genix
-               ;;
-       i370-*)
-               os=-mvs
-               ;;
-       *-next)
-               os=-nextstep3
-               ;;
-       *-gould)
-               os=-sysv
-               ;;
-       *-highlevel)
-               os=-bsd
-               ;;
-       *-encore)
-               os=-bsd
-               ;;
-       *-sgi)
-               os=-irix
-               ;;
-       *-siemens)
-               os=-sysv4
-               ;;
-       *-masscomp)
-               os=-rtu
-               ;;
-       f30[01]-fujitsu | f700-fujitsu)
-               os=-uxpv
-               ;;
-       *-rom68k)
-               os=-coff
-               ;;
-       *-*bug)
-               os=-coff
-               ;;
-       *-apple)
-               os=-macos
-               ;;
-       *-atari*)
-               os=-mint
-               ;;
-       *)
-               os=-none
-               ;;
-esac
-fi
-
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer.  We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
-       *-unknown)
-               case $os in
-                       -riscix*)
-                               vendor=acorn
-                               ;;
-                       -sunos*)
-                               vendor=sun
-                               ;;
-                       -cnk*|-aix*)
-                               vendor=ibm
-                               ;;
-                       -beos*)
-                               vendor=be
-                               ;;
-                       -hpux*)
-                               vendor=hp
-                               ;;
-                       -mpeix*)
-                               vendor=hp
-                               ;;
-                       -hiux*)
-                               vendor=hitachi
-                               ;;
-                       -unos*)
-                               vendor=crds
-                               ;;
-                       -dgux*)
-                               vendor=dg
-                               ;;
-                       -luna*)
-                               vendor=omron
-                               ;;
-                       -genix*)
-                               vendor=ns
-                               ;;
-                       -mvs* | -opened*)
-                               vendor=ibm
-                               ;;
-                       -os400*)
-                               vendor=ibm
-                               ;;
-                       -ptx*)
-                               vendor=sequent
-                               ;;
-                       -tpf*)
-                               vendor=ibm
-                               ;;
-                       -vxsim* | -vxworks* | -windiss*)
-                               vendor=wrs
-                               ;;
-                       -aux*)
-                               vendor=apple
-                               ;;
-                       -hms*)
-                               vendor=hitachi
-                               ;;
-                       -mpw* | -macos*)
-                               vendor=apple
-                               ;;
-                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
-                               vendor=atari
-                               ;;
-                       -vos*)
-                               vendor=stratus
-                               ;;
-               esac
-               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
-               ;;
-esac
-
-echo $basic_machine$os
-exit
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
diff --git a/zfs/config/depcomp b/zfs/config/depcomp
deleted file mode 100755 (executable)
index fc98710..0000000
+++ /dev/null
@@ -1,791 +0,0 @@
-#! /bin/sh
-# depcomp - compile a program generating dependencies as side-effects
-
-scriptversion=2013-05-30.07; # UTC
-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
-
-case $1 in
-  '')
-    echo "$0: No command.  Try '$0 --help' for more information." 1>&2
-    exit 1;
-    ;;
-  -h | --h*)
-    cat <<\EOF
-Usage: depcomp [--help] [--version] PROGRAM [ARGS]
-
-Run PROGRAMS ARGS to compile a file, generating dependencies
-as side-effects.
-
-Environment variables:
-  depmode     Dependency tracking mode.
-  source      Source file read by 'PROGRAMS ARGS'.
-  object      Object file output by 'PROGRAMS ARGS'.
-  DEPDIR      directory where to store dependencies.
-  depfile     Dependency file to output.
-  tmpdepfile  Temporary file to use when outputting dependencies.
-  libtool     Whether libtool is used (yes/no).
-
-Report bugs to <bug-automake@gnu.org>.
-EOF
-    exit $?
-    ;;
-  -v | --v*)
-    echo "depcomp $scriptversion"
-    exit $?
-    ;;
-esac
-
-# Get the directory component of the given path, and save it in the
-# global variables '$dir'.  Note that this directory component will
-# be either empty or ending with a '/' character.  This is deliberate.
-set_dir_from ()
-{
-  case $1 in
-    */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
-      *) dir=;;
-  esac
-}
-
-# Get the suffix-stripped basename of the given path, and save it the
-# global variable '$base'.
-set_base_from ()
-{
-  base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
-}
-
-# If no dependency file was actually created by the compiler invocation,
-# we still have to create a dummy depfile, to avoid errors with the
-# Makefile "include basename.Plo" scheme.
-make_dummy_depfile ()
-{
-  echo "#dummy" > "$depfile"
-}
-
-# Factor out some common post-processing of the generated depfile.
-# Requires the auxiliary global variable '$tmpdepfile' to be set.
-aix_post_process_depfile ()
-{
-  # If the compiler actually managed to produce a dependency file,
-  # post-process it.
-  if test -f "$tmpdepfile"; then
-    # Each line is of the form 'foo.o: dependency.h'.
-    # Do two passes, one to just change these to
-    #   $object: dependency.h
-    # and one to simply output
-    #   dependency.h:
-    # which is needed to avoid the deleted-header problem.
-    { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
-      sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
-    } > "$depfile"
-    rm -f "$tmpdepfile"
-  else
-    make_dummy_depfile
-  fi
-}
-
-# A tabulation character.
-tab='  '
-# A newline character.
-nl='
-'
-# Character ranges might be problematic outside the C locale.
-# These definitions help.
-upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
-lower=abcdefghijklmnopqrstuvwxyz
-digits=0123456789
-alpha=${upper}${lower}
-
-if test -z "$depmode" || test -z "$source" || test -z "$object"; then
-  echo "depcomp: Variables source, object and depmode must be set" 1>&2
-  exit 1
-fi
-
-# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
-depfile=${depfile-`echo "$object" |
-  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
-tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
-
-rm -f "$tmpdepfile"
-
-# Avoid interferences from the environment.
-gccflag= dashmflag=
-
-# Some modes work just like other modes, but use different flags.  We
-# parameterize here, but still list the modes in the big case below,
-# to make depend.m4 easier to write.  Note that we *cannot* use a case
-# here, because this file can only contain one case statement.
-if test "$depmode" = hp; then
-  # HP compiler uses -M and no extra arg.
-  gccflag=-M
-  depmode=gcc
-fi
-
-if test "$depmode" = dashXmstdout; then
-  # This is just like dashmstdout with a different argument.
-  dashmflag=-xM
-  depmode=dashmstdout
-fi
-
-cygpath_u="cygpath -u -f -"
-if test "$depmode" = msvcmsys; then
-  # This is just like msvisualcpp but w/o cygpath translation.
-  # Just convert the backslash-escaped backslashes to single forward
-  # slashes to satisfy depend.m4
-  cygpath_u='sed s,\\\\,/,g'
-  depmode=msvisualcpp
-fi
-
-if test "$depmode" = msvc7msys; then
-  # This is just like msvc7 but w/o cygpath translation.
-  # Just convert the backslash-escaped backslashes to single forward
-  # slashes to satisfy depend.m4
-  cygpath_u='sed s,\\\\,/,g'
-  depmode=msvc7
-fi
-
-if test "$depmode" = xlc; then
-  # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
-  gccflag=-qmakedep=gcc,-MF
-  depmode=gcc
-fi
-
-case "$depmode" in
-gcc3)
-## gcc 3 implements dependency tracking that does exactly what
-## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
-## it if -MD -MP comes after the -MF stuff.  Hmm.
-## Unfortunately, FreeBSD c89 acceptance of flags depends upon
-## the command line argument order; so add the flags where they
-## appear in depend2.am.  Note that the slowdown incurred here
-## affects only configure: in makefiles, %FASTDEP% shortcuts this.
-  for arg
-  do
-    case $arg in
-    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
-    *)  set fnord "$@" "$arg" ;;
-    esac
-    shift # fnord
-    shift # $arg
-  done
-  "$@"
-  stat=$?
-  if test $stat -ne 0; then
-    rm -f "$tmpdepfile"
-    exit $stat
-  fi
-  mv "$tmpdepfile" "$depfile"
-  ;;
-
-gcc)
-## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
-## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
-## (see the conditional assignment to $gccflag above).
-## There are various ways to get dependency output from gcc.  Here's
-## why we pick this rather obscure method:
-## - Don't want to use -MD because we'd like the dependencies to end
-##   up in a subdir.  Having to rename by hand is ugly.
-##   (We might end up doing this anyway to support other compilers.)
-## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
-##   -MM, not -M (despite what the docs say).  Also, it might not be
-##   supported by the other compilers which use the 'gcc' depmode.
-## - Using -M directly means running the compiler twice (even worse
-##   than renaming).
-  if test -z "$gccflag"; then
-    gccflag=-MD,
-  fi
-  "$@" -Wp,"$gccflag$tmpdepfile"
-  stat=$?
-  if test $stat -ne 0; then
-    rm -f "$tmpdepfile"
-    exit $stat
-  fi
-  rm -f "$depfile"
-  echo "$object : \\" > "$depfile"
-  # The second -e expression handles DOS-style file names with drive
-  # letters.
-  sed -e 's/^[^:]*: / /' \
-      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
-## This next piece of magic avoids the "deleted header file" problem.
-## The problem is that when a header file which appears in a .P file
-## is deleted, the dependency causes make to die (because there is
-## typically no way to rebuild the header).  We avoid this by adding
-## dummy dependencies for each header file.  Too bad gcc doesn't do
-## this for us directly.
-## Some versions of gcc put a space before the ':'.  On the theory
-## that the space means something, we add a space to the output as
-## well.  hp depmode also adds that space, but also prefixes the VPATH
-## to the object.  Take care to not repeat it in the output.
-## Some versions of the HPUX 10.20 sed can't process this invocation
-## correctly.  Breaking it into two sed invocations is a workaround.
-  tr ' ' "$nl" < "$tmpdepfile" \
-    | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
-    | sed -e 's/$/ :/' >> "$depfile"
-  rm -f "$tmpdepfile"
-  ;;
-
-hp)
-  # This case exists only to let depend.m4 do its work.  It works by
-  # looking at the text of this script.  This case will never be run,
-  # since it is checked for above.
-  exit 1
-  ;;
-
-sgi)
-  if test "$libtool" = yes; then
-    "$@" "-Wp,-MDupdate,$tmpdepfile"
-  else
-    "$@" -MDupdate "$tmpdepfile"
-  fi
-  stat=$?
-  if test $stat -ne 0; then
-    rm -f "$tmpdepfile"
-    exit $stat
-  fi
-  rm -f "$depfile"
-
-  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
-    echo "$object : \\" > "$depfile"
-    # Clip off the initial element (the dependent).  Don't try to be
-    # clever and replace this with sed code, as IRIX sed won't handle
-    # lines with more than a fixed number of characters (4096 in
-    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
-    # the IRIX cc adds comments like '#:fec' to the end of the
-    # dependency line.
-    tr ' ' "$nl" < "$tmpdepfile" \
-      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
-      | tr "$nl" ' ' >> "$depfile"
-    echo >> "$depfile"
-    # The second pass generates a dummy entry for each header file.
-    tr ' ' "$nl" < "$tmpdepfile" \
-      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
-      >> "$depfile"
-  else
-    make_dummy_depfile
-  fi
-  rm -f "$tmpdepfile"
-  ;;
-
-xlc)
-  # This case exists only to let depend.m4 do its work.  It works by
-  # looking at the text of this script.  This case will never be run,
-  # since it is checked for above.
-  exit 1
-  ;;
-
-aix)
-  # The C for AIX Compiler uses -M and outputs the dependencies
-  # in a .u file.  In older versions, this file always lives in the
-  # current directory.  Also, the AIX compiler puts '$object:' at the
-  # start of each line; $object doesn't have directory information.
-  # Version 6 uses the directory in both cases.
-  set_dir_from "$object"
-  set_base_from "$object"
-  if test "$libtool" = yes; then
-    tmpdepfile1=$dir$base.u
-    tmpdepfile2=$base.u
-    tmpdepfile3=$dir.libs/$base.u
-    "$@" -Wc,-M
-  else
-    tmpdepfile1=$dir$base.u
-    tmpdepfile2=$dir$base.u
-    tmpdepfile3=$dir$base.u
-    "$@" -M
-  fi
-  stat=$?
-  if test $stat -ne 0; then
-    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
-    exit $stat
-  fi
-
-  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
-  do
-    test -f "$tmpdepfile" && break
-  done
-  aix_post_process_depfile
-  ;;
-
-tcc)
-  # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
-  # FIXME: That version still under development at the moment of writing.
-  #        Make that this statement remains true also for stable, released
-  #        versions.
-  # It will wrap lines (doesn't matter whether long or short) with a
-  # trailing '\', as in:
-  #
-  #   foo.o : \
-  #    foo.c \
-  #    foo.h \
-  #
-  # It will put a trailing '\' even on the last line, and will use leading
-  # spaces rather than leading tabs (at least since its commit 0394caf7
-  # "Emit spaces for -MD").
-  "$@" -MD -MF "$tmpdepfile"
-  stat=$?
-  if test $stat -ne 0; then
-    rm -f "$tmpdepfile"
-    exit $stat
-  fi
-  rm -f "$depfile"
-  # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
-  # We have to change lines of the first kind to '$object: \'.
-  sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
-  # And for each line of the second kind, we have to emit a 'dep.h:'
-  # dummy dependency, to avoid the deleted-header problem.
-  sed -n -e 's|^  *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
-  rm -f "$tmpdepfile"
-  ;;
-
-## The order of this option in the case statement is important, since the
-## shell code in configure will try each of these formats in the order
-## listed in this file.  A plain '-MD' option would be understood by many
-## compilers, so we must ensure this comes after the gcc and icc options.
-pgcc)
-  # Portland's C compiler understands '-MD'.
-  # Will always output deps to 'file.d' where file is the root name of the
-  # source file under compilation, even if file resides in a subdirectory.
-  # The object file name does not affect the name of the '.d' file.
-  # pgcc 10.2 will output
-  #    foo.o: sub/foo.c sub/foo.h
-  # and will wrap long lines using '\' :
-  #    foo.o: sub/foo.c ... \
-  #     sub/foo.h ... \
-  #     ...
-  set_dir_from "$object"
-  # Use the source, not the object, to determine the base name, since
-  # that's sadly what pgcc will do too.
-  set_base_from "$source"
-  tmpdepfile=$base.d
-
-  # For projects that build the same source file twice into different object
-  # files, the pgcc approach of using the *source* file root name can cause
-  # problems in parallel builds.  Use a locking strategy to avoid stomping on
-  # the same $tmpdepfile.
-  lockdir=$base.d-lock
-  trap "
-    echo '$0: caught signal, cleaning up...' >&2
-    rmdir '$lockdir'
-    exit 1
-  " 1 2 13 15
-  numtries=100
-  i=$numtries
-  while test $i -gt 0; do
-    # mkdir is a portable test-and-set.
-    if mkdir "$lockdir" 2>/dev/null; then
-      # This process acquired the lock.
-      "$@" -MD
-      stat=$?
-      # Release the lock.
-      rmdir "$lockdir"
-      break
-    else
-      # If the lock is being held by a different process, wait
-      # until the winning process is done or we timeout.
-      while test -d "$lockdir" && test $i -gt 0; do
-        sleep 1
-        i=`expr $i - 1`
-      done
-    fi
-    i=`expr $i - 1`
-  done
-  trap - 1 2 13 15
-  if test $i -le 0; then
-    echo "$0: failed to acquire lock after $numtries attempts" >&2
-    echo "$0: check lockdir '$lockdir'" >&2
-    exit 1
-  fi
-
-  if test $stat -ne 0; then
-    rm -f "$tmpdepfile"
-    exit $stat
-  fi
-  rm -f "$depfile"
-  # Each line is of the form `foo.o: dependent.h',
-  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
-  # Do two passes, one to just change these to
-  # `$object: dependent.h' and one to simply `dependent.h:'.
-  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
-  # Some versions of the HPUX 10.20 sed can't process this invocation
-  # correctly.  Breaking it into two sed invocations is a workaround.
-  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
-    | sed -e 's/$/ :/' >> "$depfile"
-  rm -f "$tmpdepfile"
-  ;;
-
-hp2)
-  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
-  # compilers, which have integrated preprocessors.  The correct option
-  # to use with these is +Maked; it writes dependencies to a file named
-  # 'foo.d', which lands next to the object file, wherever that
-  # happens to be.
-  # Much of this is similar to the tru64 case; see comments there.
-  set_dir_from  "$object"
-  set_base_from "$object"
-  if test "$libtool" = yes; then
-    tmpdepfile1=$dir$base.d
-    tmpdepfile2=$dir.libs/$base.d
-    "$@" -Wc,+Maked
-  else
-    tmpdepfile1=$dir$base.d
-    tmpdepfile2=$dir$base.d
-    "$@" +Maked
-  fi
-  stat=$?
-  if test $stat -ne 0; then
-     rm -f "$tmpdepfile1" "$tmpdepfile2"
-     exit $stat
-  fi
-
-  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
-  do
-    test -f "$tmpdepfile" && break
-  done
-  if test -f "$tmpdepfile"; then
-    sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
-    # Add 'dependent.h:' lines.
-    sed -ne '2,${
-               s/^ *//
-               s/ \\*$//
-               s/$/:/
-               p
-             }' "$tmpdepfile" >> "$depfile"
-  else
-    make_dummy_depfile
-  fi
-  rm -f "$tmpdepfile" "$tmpdepfile2"
-  ;;
-
-tru64)
-  # The Tru64 compiler uses -MD to generate dependencies as a side
-  # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
-  # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
-  # dependencies in 'foo.d' instead, so we check for that too.
-  # Subdirectories are respected.
-  set_dir_from  "$object"
-  set_base_from "$object"
-
-  if test "$libtool" = yes; then
-    # Libtool generates 2 separate objects for the 2 libraries.  These
-    # two compilations output dependencies in $dir.libs/$base.o.d and
-    # in $dir$base.o.d.  We have to check for both files, because
-    # one of the two compilations can be disabled.  We should prefer
-    # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
-    # automatically cleaned when .libs/ is deleted, while ignoring
-    # the former would cause a distcleancheck panic.
-    tmpdepfile1=$dir$base.o.d          # libtool 1.5
-    tmpdepfile2=$dir.libs/$base.o.d    # Likewise.
-    tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504
-    "$@" -Wc,-MD
-  else
-    tmpdepfile1=$dir$base.d
-    tmpdepfile2=$dir$base.d
-    tmpdepfile3=$dir$base.d
-    "$@" -MD
-  fi
-
-  stat=$?
-  if test $stat -ne 0; then
-    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
-    exit $stat
-  fi
-
-  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
-  do
-    test -f "$tmpdepfile" && break
-  done
-  # Same post-processing that is required for AIX mode.
-  aix_post_process_depfile
-  ;;
-
-msvc7)
-  if test "$libtool" = yes; then
-    showIncludes=-Wc,-showIncludes
-  else
-    showIncludes=-showIncludes
-  fi
-  "$@" $showIncludes > "$tmpdepfile"
-  stat=$?
-  grep -v '^Note: including file: ' "$tmpdepfile"
-  if test $stat -ne 0; then
-    rm -f "$tmpdepfile"
-    exit $stat
-  fi
-  rm -f "$depfile"
-  echo "$object : \\" > "$depfile"
-  # The first sed program below extracts the file names and escapes
-  # backslashes for cygpath.  The second sed program outputs the file
-  # name when reading, but also accumulates all include files in the
-  # hold buffer in order to output them again at the end.  This only
-  # works with sed implementations that can handle large buffers.
-  sed < "$tmpdepfile" -n '
-/^Note: including file:  *\(.*\)/ {
-  s//\1/
-  s/\\/\\\\/g
-  p
-}' | $cygpath_u | sort -u | sed -n '
-s/ /\\ /g
-s/\(.*\)/'"$tab"'\1 \\/p
-s/.\(.*\) \\/\1:/
-H
-$ {
-  s/.*/'"$tab"'/
-  G
-  p
-}' >> "$depfile"
-  echo >> "$depfile" # make sure the fragment doesn't end with a backslash
-  rm -f "$tmpdepfile"
-  ;;
-
-msvc7msys)
-  # This case exists only to let depend.m4 do its work.  It works by
-  # looking at the text of this script.  This case will never be run,
-  # since it is checked for above.
-  exit 1
-  ;;
-
-#nosideeffect)
-  # This comment above is used by automake to tell side-effect
-  # dependency tracking mechanisms from slower ones.
-
-dashmstdout)
-  # Important note: in order to support this mode, a compiler *must*
-  # always write the preprocessed file to stdout, regardless of -o.
-  "$@" || exit $?
-
-  # Remove the call to Libtool.
-  if test "$libtool" = yes; then
-    while test "X$1" != 'X--mode=compile'; do
-      shift
-    done
-    shift
-  fi
-
-  # Remove '-o $object'.
-  IFS=" "
-  for arg
-  do
-    case $arg in
-    -o)
-      shift
-      ;;
-    $object)
-      shift
-      ;;
-    *)
-      set fnord "$@" "$arg"
-      shift # fnord
-      shift # $arg
-      ;;
-    esac
-  done
-
-  test -z "$dashmflag" && dashmflag=-M
-  # Require at least two characters before searching for ':'
-  # in the target name.  This is to cope with DOS-style filenames:
-  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
-  "$@" $dashmflag |
-    sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
-  rm -f "$depfile"
-  cat < "$tmpdepfile" > "$depfile"
-  # Some versions of the HPUX 10.20 sed can't process this sed invocation
-  # correctly.  Breaking it into two sed invocations is a workaround.
-  tr ' ' "$nl" < "$tmpdepfile" \
-    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
-    | sed -e 's/$/ :/' >> "$depfile"
-  rm -f "$tmpdepfile"
-  ;;
-
-dashXmstdout)
-  # This case only exists to satisfy depend.m4.  It is never actually
-  # run, as this mode is specially recognized in the preamble.
-  exit 1
-  ;;
-
-makedepend)
-  "$@" || exit $?
-  # Remove any Libtool call
-  if test "$libtool" = yes; then
-    while test "X$1" != 'X--mode=compile'; do
-      shift
-    done
-    shift
-  fi
-  # X makedepend
-  shift
-  cleared=no eat=no
-  for arg
-  do
-    case $cleared in
-    no)
-      set ""; shift
-      cleared=yes ;;
-    esac
-    if test $eat = yes; then
-      eat=no
-      continue
-    fi
-    case "$arg" in
-    -D*|-I*)
-      set fnord "$@" "$arg"; shift ;;
-    # Strip any option that makedepend may not understand.  Remove
-    # the object too, otherwise makedepend will parse it as a source file.
-    -arch)
-      eat=yes ;;
-    -*|$object)
-      ;;
-    *)
-      set fnord "$@" "$arg"; shift ;;
-    esac
-  done
-  obj_suffix=`echo "$object" | sed 's/^.*\././'`
-  touch "$tmpdepfile"
-  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
-  rm -f "$depfile"
-  # makedepend may prepend the VPATH from the source file name to the object.
-  # No need to regex-escape $object, excess matching of '.' is harmless.
-  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
-  # Some versions of the HPUX 10.20 sed can't process the last invocation
-  # correctly.  Breaking it into two sed invocations is a workaround.
-  sed '1,2d' "$tmpdepfile" \
-    | tr ' ' "$nl" \
-    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
-    | sed -e 's/$/ :/' >> "$depfile"
-  rm -f "$tmpdepfile" "$tmpdepfile".bak
-  ;;
-
-cpp)
-  # Important note: in order to support this mode, a compiler *must*
-  # always write the preprocessed file to stdout.
-  "$@" || exit $?
-
-  # Remove the call to Libtool.
-  if test "$libtool" = yes; then
-    while test "X$1" != 'X--mode=compile'; do
-      shift
-    done
-    shift
-  fi
-
-  # Remove '-o $object'.
-  IFS=" "
-  for arg
-  do
-    case $arg in
-    -o)
-      shift
-      ;;
-    $object)
-      shift
-      ;;
-    *)
-      set fnord "$@" "$arg"
-      shift # fnord
-      shift # $arg
-      ;;
-    esac
-  done
-
-  "$@" -E \
-    | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-             -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-    | sed '$ s: \\$::' > "$tmpdepfile"
-  rm -f "$depfile"
-  echo "$object : \\" > "$depfile"
-  cat < "$tmpdepfile" >> "$depfile"
-  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
-  rm -f "$tmpdepfile"
-  ;;
-
-msvisualcpp)
-  # Important note: in order to support this mode, a compiler *must*
-  # always write the preprocessed file to stdout.
-  "$@" || exit $?
-
-  # Remove the call to Libtool.
-  if test "$libtool" = yes; then
-    while test "X$1" != 'X--mode=compile'; do
-      shift
-    done
-    shift
-  fi
-
-  IFS=" "
-  for arg
-  do
-    case "$arg" in
-    -o)
-      shift
-      ;;
-    $object)
-      shift
-      ;;
-    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
-        set fnord "$@"
-        shift
-        shift
-        ;;
-    *)
-        set fnord "$@" "$arg"
-        shift
-        shift
-        ;;
-    esac
-  done
-  "$@" -E 2>/dev/null |
-  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
-  rm -f "$depfile"
-  echo "$object : \\" > "$depfile"
-  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
-  echo "$tab" >> "$depfile"
-  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
-  rm -f "$tmpdepfile"
-  ;;
-
-msvcmsys)
-  # This case exists only to let depend.m4 do its work.  It works by
-  # looking at the text of this script.  This case will never be run,
-  # since it is checked for above.
-  exit 1
-  ;;
-
-none)
-  exec "$@"
-  ;;
-
-*)
-  echo "Unknown depmode $depmode" 1>&2
-  exit 1
-  ;;
-esac
-
-exit 0
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/zfs/config/dkms.m4 b/zfs/config/dkms.m4
deleted file mode 100644 (file)
index cfa1152..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-dnl #
-dnl # Prevent manual building in DKMS source tree.
-dnl #
-AC_DEFUN([ZFS_AC_DKMS_INHIBIT], [
-       AC_MSG_CHECKING([for dkms.conf file])
-        AS_IF([test -e dkms.conf], [
-               AC_MSG_ERROR([
-       *** ZFS should not be manually built in the DKMS source tree.
-       *** Remove all ZFS packages before compiling the ZoL sources.
-       *** Running "make install" breaks ZFS packages.])
-        ], [
-               AC_MSG_RESULT([not found])
-        ])
-])
diff --git a/zfs/config/install-sh b/zfs/config/install-sh
deleted file mode 100755 (executable)
index 59990a1..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-#!/bin/sh
-# install - install a program, script, or datafile
-
-scriptversion=2014-09-12.12; # UTC
-
-# This originates from X11R5 (mit/util/scripts/install.sh), which was
-# later released in X11R6 (xc/config/util/install.sh) with the
-# following copyright and license.
-#
-# Copyright (C) 1994 X Consortium
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
-# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Except as contained in this notice, the name of the X Consortium shall not
-# be used in advertising or otherwise to promote the sale, use or other deal-
-# ings in this Software without prior written authorization from the X Consor-
-# tium.
-#
-#
-# FSF changes to this file are in the public domain.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# 'make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-
-tab='  '
-nl='
-'
-IFS=" $tab$nl"
-
-# Set DOITPROG to "echo" to test this script.
-
-doit=${DOITPROG-}
-doit_exec=${doit:-exec}
-
-# Put in absolute file names if you don't have them in your path;
-# or use environment vars.
-
-chgrpprog=${CHGRPPROG-chgrp}
-chmodprog=${CHMODPROG-chmod}
-chownprog=${CHOWNPROG-chown}
-cmpprog=${CMPPROG-cmp}
-cpprog=${CPPROG-cp}
-mkdirprog=${MKDIRPROG-mkdir}
-mvprog=${MVPROG-mv}
-rmprog=${RMPROG-rm}
-stripprog=${STRIPPROG-strip}
-
-posix_mkdir=
-
-# Desired mode of installed file.
-mode=0755
-
-chgrpcmd=
-chmodcmd=$chmodprog
-chowncmd=
-mvcmd=$mvprog
-rmcmd="$rmprog -f"
-stripcmd=
-
-src=
-dst=
-dir_arg=
-dst_arg=
-
-copy_on_change=false
-is_target_a_directory=possibly
-
-usage="\
-Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
-   or: $0 [OPTION]... SRCFILES... DIRECTORY
-   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
-   or: $0 [OPTION]... -d DIRECTORIES...
-
-In the 1st form, copy SRCFILE to DSTFILE.
-In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
-In the 4th, create DIRECTORIES.
-
-Options:
-     --help     display this help and exit.
-     --version  display version info and exit.
-
-  -c            (ignored)
-  -C            install only if different (preserve the last data modification time)
-  -d            create directories instead of installing files.
-  -g GROUP      $chgrpprog installed files to GROUP.
-  -m MODE       $chmodprog installed files to MODE.
-  -o USER       $chownprog installed files to USER.
-  -s            $stripprog installed files.
-  -t DIRECTORY  install into DIRECTORY.
-  -T            report an error if DSTFILE is a directory.
-
-Environment variables override the default commands:
-  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
-  RMPROG STRIPPROG
-"
-
-while test $# -ne 0; do
-  case $1 in
-    -c) ;;
-
-    -C) copy_on_change=true;;
-
-    -d) dir_arg=true;;
-
-    -g) chgrpcmd="$chgrpprog $2"
-        shift;;
-
-    --help) echo "$usage"; exit $?;;
-
-    -m) mode=$2
-        case $mode in
-          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
-            echo "$0: invalid mode: $mode" >&2
-            exit 1;;
-        esac
-        shift;;
-
-    -o) chowncmd="$chownprog $2"
-        shift;;
-
-    -s) stripcmd=$stripprog;;
-
-    -t)
-        is_target_a_directory=always
-        dst_arg=$2
-        # Protect names problematic for 'test' and other utilities.
-        case $dst_arg in
-          -* | [=\(\)!]) dst_arg=./$dst_arg;;
-        esac
-        shift;;
-
-    -T) is_target_a_directory=never;;
-
-    --version) echo "$0 $scriptversion"; exit $?;;
-
-    --) shift
-        break;;
-
-    -*) echo "$0: invalid option: $1" >&2
-        exit 1;;
-
-    *)  break;;
-  esac
-  shift
-done
-
-# We allow the use of options -d and -T together, by making -d
-# take the precedence; this is for compatibility with GNU install.
-
-if test -n "$dir_arg"; then
-  if test -n "$dst_arg"; then
-    echo "$0: target directory not allowed when installing a directory." >&2
-    exit 1
-  fi
-fi
-
-if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
-  # When -d is used, all remaining arguments are directories to create.
-  # When -t is used, the destination is already specified.
-  # Otherwise, the last argument is the destination.  Remove it from $@.
-  for arg
-  do
-    if test -n "$dst_arg"; then
-      # $@ is not empty: it contains at least $arg.
-      set fnord "$@" "$dst_arg"
-      shift # fnord
-    fi
-    shift # arg
-    dst_arg=$arg
-    # Protect names problematic for 'test' and other utilities.
-    case $dst_arg in
-      -* | [=\(\)!]) dst_arg=./$dst_arg;;
-    esac
-  done
-fi
-
-if test $# -eq 0; then
-  if test -z "$dir_arg"; then
-    echo "$0: no input file specified." >&2
-    exit 1
-  fi
-  # It's OK to call 'install-sh -d' without argument.
-  # This can happen when creating conditional directories.
-  exit 0
-fi
-
-if test -z "$dir_arg"; then
-  if test $# -gt 1 || test "$is_target_a_directory" = always; then
-    if test ! -d "$dst_arg"; then
-      echo "$0: $dst_arg: Is not a directory." >&2
-      exit 1
-    fi
-  fi
-fi
-
-if test -z "$dir_arg"; then
-  do_exit='(exit $ret); exit $ret'
-  trap "ret=129; $do_exit" 1
-  trap "ret=130; $do_exit" 2
-  trap "ret=141; $do_exit" 13
-  trap "ret=143; $do_exit" 15
-
-  # Set umask so as not to create temps with too-generous modes.
-  # However, 'strip' requires both read and write access to temps.
-  case $mode in
-    # Optimize common cases.
-    *644) cp_umask=133;;
-    *755) cp_umask=22;;
-
-    *[0-7])
-      if test -z "$stripcmd"; then
-        u_plus_rw=
-      else
-        u_plus_rw='% 200'
-      fi
-      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
-    *)
-      if test -z "$stripcmd"; then
-        u_plus_rw=
-      else
-        u_plus_rw=,u+rw
-      fi
-      cp_umask=$mode$u_plus_rw;;
-  esac
-fi
-
-for src
-do
-  # Protect names problematic for 'test' and other utilities.
-  case $src in
-    -* | [=\(\)!]) src=./$src;;
-  esac
-
-  if test -n "$dir_arg"; then
-    dst=$src
-    dstdir=$dst
-    test -d "$dstdir"
-    dstdir_status=$?
-  else
-
-    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
-    # might cause directories to be created, which would be especially bad
-    # if $src (and thus $dsttmp) contains '*'.
-    if test ! -f "$src" && test ! -d "$src"; then
-      echo "$0: $src does not exist." >&2
-      exit 1
-    fi
-
-    if test -z "$dst_arg"; then
-      echo "$0: no destination specified." >&2
-      exit 1
-    fi
-    dst=$dst_arg
-
-    # If destination is a directory, append the input filename; won't work
-    # if double slashes aren't ignored.
-    if test -d "$dst"; then
-      if test "$is_target_a_directory" = never; then
-        echo "$0: $dst_arg: Is a directory" >&2
-        exit 1
-      fi
-      dstdir=$dst
-      dst=$dstdir/`basename "$src"`
-      dstdir_status=0
-    else
-      dstdir=`dirname "$dst"`
-      test -d "$dstdir"
-      dstdir_status=$?
-    fi
-  fi
-
-  obsolete_mkdir_used=false
-
-  if test $dstdir_status != 0; then
-    case $posix_mkdir in
-      '')
-        # Create intermediate dirs using mode 755 as modified by the umask.
-        # This is like FreeBSD 'install' as of 1997-10-28.
-        umask=`umask`
-        case $stripcmd.$umask in
-          # Optimize common cases.
-          *[2367][2367]) mkdir_umask=$umask;;
-          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
-          *[0-7])
-            mkdir_umask=`expr $umask + 22 \
-              - $umask % 100 % 40 + $umask % 20 \
-              - $umask % 10 % 4 + $umask % 2
-            `;;
-          *) mkdir_umask=$umask,go-w;;
-        esac
-
-        # With -d, create the new directory with the user-specified mode.
-        # Otherwise, rely on $mkdir_umask.
-        if test -n "$dir_arg"; then
-          mkdir_mode=-m$mode
-        else
-          mkdir_mode=
-        fi
-
-        posix_mkdir=false
-        case $umask in
-          *[123567][0-7][0-7])
-            # POSIX mkdir -p sets u+wx bits regardless of umask, which
-            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
-            ;;
-          *)
-            # $RANDOM is not portable (e.g. dash);  use it when possible to
-            # lower collision chance
-            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
-            trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
-
-            # As "mkdir -p" follows symlinks and we work in /tmp possibly;  so
-            # create the $tmpdir first (and fail if unsuccessful) to make sure
-            # that nobody tries to guess the $tmpdir name.
-            if (umask $mkdir_umask &&
-                $mkdirprog $mkdir_mode "$tmpdir" &&
-                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
-            then
-              if test -z "$dir_arg" || {
-                   # Check for POSIX incompatibilities with -m.
-                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
-                   # other-writable bit of parent directory when it shouldn't.
-                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
-                   test_tmpdir="$tmpdir/a"
-                   ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
-                   case $ls_ld_tmpdir in
-                     d????-?r-*) different_mode=700;;
-                     d????-?--*) different_mode=755;;
-                     *) false;;
-                   esac &&
-                   $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
-                     ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
-                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
-                   }
-                 }
-              then posix_mkdir=:
-              fi
-              rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
-            else
-              # Remove any dirs left behind by ancient mkdir implementations.
-              rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
-            fi
-            trap '' 0;;
-        esac;;
-    esac
-
-    if
-      $posix_mkdir && (
-        umask $mkdir_umask &&
-        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
-      )
-    then :
-    else
-
-      # The umask is ridiculous, or mkdir does not conform to POSIX,
-      # or it failed possibly due to a race condition.  Create the
-      # directory the slow way, step by step, checking for races as we go.
-
-      case $dstdir in
-        /*) prefix='/';;
-        [-=\(\)!]*) prefix='./';;
-        *)  prefix='';;
-      esac
-
-      oIFS=$IFS
-      IFS=/
-      set -f
-      set fnord $dstdir
-      shift
-      set +f
-      IFS=$oIFS
-
-      prefixes=
-
-      for d
-      do
-        test X"$d" = X && continue
-
-        prefix=$prefix$d
-        if test -d "$prefix"; then
-          prefixes=
-        else
-          if $posix_mkdir; then
-            (umask=$mkdir_umask &&
-             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
-            # Don't fail if two instances are running concurrently.
-            test -d "$prefix" || exit 1
-          else
-            case $prefix in
-              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
-              *) qprefix=$prefix;;
-            esac
-            prefixes="$prefixes '$qprefix'"
-          fi
-        fi
-        prefix=$prefix/
-      done
-
-      if test -n "$prefixes"; then
-        # Don't fail if two instances are running concurrently.
-        (umask $mkdir_umask &&
-         eval "\$doit_exec \$mkdirprog $prefixes") ||
-          test -d "$dstdir" || exit 1
-        obsolete_mkdir_used=true
-      fi
-    fi
-  fi
-
-  if test -n "$dir_arg"; then
-    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
-    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
-    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
-      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
-  else
-
-    # Make a couple of temp file names in the proper directory.
-    dsttmp=$dstdir/_inst.$$_
-    rmtmp=$dstdir/_rm.$$_
-
-    # Trap to clean up those temp files at exit.
-    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
-
-    # Copy the file name to the temp name.
-    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
-
-    # and set any options; do chmod last to preserve setuid bits.
-    #
-    # If any of these fail, we abort the whole thing.  If we want to
-    # ignore errors from any of these, just make sure not to ignore
-    # errors from the above "$doit $cpprog $src $dsttmp" command.
-    #
-    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
-    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
-    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
-    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
-
-    # If -C, don't bother to copy if it wouldn't change the file.
-    if $copy_on_change &&
-       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
-       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
-       set -f &&
-       set X $old && old=:$2:$4:$5:$6 &&
-       set X $new && new=:$2:$4:$5:$6 &&
-       set +f &&
-       test "$old" = "$new" &&
-       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
-    then
-      rm -f "$dsttmp"
-    else
-      # Rename the file to the real destination.
-      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
-
-      # The rename failed, perhaps because mv can't rename something else
-      # to itself, or perhaps because mv is so ancient that it does not
-      # support -f.
-      {
-        # Now remove or move aside any old file at destination location.
-        # We try this two ways since rm can't unlink itself on some
-        # systems and the destination file might be busy for other
-        # reasons.  In this case, the final cleanup might fail but the new
-        # file should still install successfully.
-        {
-          test ! -f "$dst" ||
-          $doit $rmcmd -f "$dst" 2>/dev/null ||
-          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
-            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
-          } ||
-          { echo "$0: cannot unlink or rename $dst" >&2
-            (exit 1); exit 1
-          }
-        } &&
-
-        # Now rename the file to the real destination.
-        $doit $mvcmd "$dsttmp" "$dst"
-      }
-    fi || exit 1
-
-    trap '' 0
-  fi
-done
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End:
index e6f2bf507ba932a3a679f44a25c4f11e483d4242..50b502c31416dfdfd5d1f5ee51487e0fed482a4e 100644 (file)
@@ -16,26 +16,27 @@ AC_DEFUN([ZFS_AC_KERNEL_POSIX_ACL_RELEASE], [
                AC_MSG_RESULT(yes)
                AC_DEFINE(HAVE_POSIX_ACL_RELEASE, 1,
                    [posix_acl_release() is available])
-       ],[
-               AC_MSG_RESULT(no)
-       ])
 
-       AC_MSG_CHECKING([whether posix_acl_release() is GPL-only])
-       ZFS_LINUX_TRY_COMPILE([
-               #include <linux/cred.h>
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
+               AC_MSG_CHECKING([whether posix_acl_release() is GPL-only])
+               ZFS_LINUX_TRY_COMPILE([
+                       #include <linux/module.h>
+                       #include <linux/cred.h>
+                       #include <linux/fs.h>
+                       #include <linux/posix_acl.h>
 
-               MODULE_LICENSE("$ZFS_META_LICENSE");
-       ],[
-               struct posix_acl* tmp = posix_acl_alloc(1, 0);
-               posix_acl_release(tmp);
+                       MODULE_LICENSE("$ZFS_META_LICENSE");
+               ],[
+                       struct posix_acl* tmp = posix_acl_alloc(1, 0);
+                       posix_acl_release(tmp);
+               ],[
+                       AC_MSG_RESULT(no)
+               ],[
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_POSIX_ACL_RELEASE_GPL_ONLY, 1,
+                           [posix_acl_release() is GPL-only])
+               ])
        ],[
                AC_MSG_RESULT(no)
-       ],[
-               AC_MSG_RESULT(yes)
-               AC_DEFINE(HAVE_POSIX_ACL_RELEASE_GPL_ONLY, 1,
-                   [posix_acl_release() is GPL-only])
        ])
 ])
 
diff --git a/zfs/config/kernel-blk-queue-unplug.m4 b/zfs/config/kernel-blk-queue-unplug.m4
new file mode 100644 (file)
index 0000000..075fbcc
--- /dev/null
@@ -0,0 +1,44 @@
+dnl #
+dnl # 2.6.32-2.6.35 API - The BIO_RW_UNPLUG enum can be used as a hint
+dnl # to unplug the queue.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_HAVE_BIO_RW_UNPLUG], [
+       AC_MSG_CHECKING([whether the BIO_RW_UNPLUG enum is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               extern enum bio_rw_flags rw;
+
+               rw = BIO_RW_UNPLUG;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BLK_QUEUE_HAVE_BIO_RW_UNPLUG, 1,
+                         [BIO_RW_UNPLUG is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_BLK_QUEUE_HAVE_BLK_PLUG], [
+       AC_MSG_CHECKING([whether struct blk_plug is available])
+       tmp_flags="$EXTRA_KCFLAGS"
+       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/blkdev.h>
+       ],[
+               struct blk_plug plug;
+
+               blk_start_plug(&plug);
+               blk_finish_plug(&plug);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_BLK_QUEUE_HAVE_BLK_PLUG, 1,
+                         [struct blk_plug is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+       EXTRA_KCFLAGS="$tmp_flags"
+])
diff --git a/zfs/config/kernel-check-disk-size-change.m4 b/zfs/config/kernel-check-disk-size-change.m4
deleted file mode 100644 (file)
index ea5c75f..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-dnl #
-dnl # 2.6.28 API change
-dnl # Added check_disk_size_change() helper function.
-dnl #
-AC_DEFUN([ZFS_AC_KERNEL_CHECK_DISK_SIZE_CHANGE],
-       [AC_MSG_CHECKING([whether check_disk_size_change() is available])
-       ZFS_LINUX_TRY_COMPILE_SYMBOL([
-               #include <linux/fs.h>
-       ], [
-               check_disk_size_change(NULL, NULL);
-       ], [check_disk_size_change], [fs/block_dev.c], [
-               AC_MSG_RESULT(yes)
-               AC_DEFINE(HAVE_CHECK_DISK_SIZE_CHANGE, 1,
-                         [check_disk_size_change() is available])
-       ], [
-               AC_MSG_RESULT(no)
-       ])
-])
diff --git a/zfs/config/kernel-file-dentry.m4 b/zfs/config/kernel-file-dentry.m4
new file mode 100644 (file)
index 0000000..daf742e
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # 4.1 API change
+dnl # struct access file->f_path.dentry was replaced by accessor function
+dnl # since fix torvalds/linux@4bacc9c9234c ("overlayfs: Make f_path always
+dnl # point to the overlay and f_inode to the underlay").
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FILE_DENTRY], [
+       AC_MSG_CHECKING([whether file_dentry() is available])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct file *f = NULL;
+               file_dentry(f);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FILE_DENTRY, 1, [file_dentry() is available])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-fpu.m4 b/zfs/config/kernel-fpu.m4
new file mode 100644 (file)
index 0000000..1c56909
--- /dev/null
@@ -0,0 +1,18 @@
+dnl #
+dnl # 4.2 API change
+dnl # asm/i387.h is replaced by asm/fpu/api.h
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_FPU], [
+       AC_MSG_CHECKING([whether asm/fpu/api.h exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/kernel.h>
+               #include <asm/fpu/api.h>
+       ],[
+               __kernel_fpu_begin();
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_FPU_API_H, 1, [kernel has <asm/fpu/api.h> interface])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-kobj-name-len.m4 b/zfs/config/kernel-kobj-name-len.m4
deleted file mode 100644 (file)
index 37999fa..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-dnl #
-dnl # 2.6.27 API change,
-dnl # kobject KOBJ_NAME_LEN static limit removed.  All users of this
-dnl # constant were removed prior to 2.6.27, but to be on the safe
-dnl # side this check ensures the constant is undefined.
-dnl #
-AC_DEFUN([ZFS_AC_KERNEL_KOBJ_NAME_LEN], [
-       AC_MSG_CHECKING([whether kernel defines KOBJ_NAME_LEN])
-       ZFS_LINUX_TRY_COMPILE([
-               #include <linux/kobject.h>
-       ],[
-               int val __attribute__ ((unused));
-               val = KOBJ_NAME_LEN;
-       ],[
-               AC_MSG_RESULT([yes])
-               AC_DEFINE(HAVE_KOBJ_NAME_LEN, 1,
-                         [kernel defines KOBJ_NAME_LEN])
-       ],[
-               AC_MSG_RESULT([no])
-       ])
-])
diff --git a/zfs/config/kernel-kuid-helpers.m4 b/zfs/config/kernel-kuid-helpers.m4
new file mode 100644 (file)
index 0000000..60713b9
--- /dev/null
@@ -0,0 +1,22 @@
+dnl #
+dnl # 3.5 API change,
+dnl # Since usernamespaces were introduced in kernel version 3.5, it
+dnl # became necessary to go through one more level of indirection
+dnl # when dealing with uid/gid - namely the kuid type.
+dnl #
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_KUID_HELPERS], [
+       AC_MSG_CHECKING([whether i_(uid|gid)_(read|write) exist])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+       ],[
+               struct inode *ip = NULL;
+               (void) i_uid_read(ip);
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_KUID_HELPERS, 1,
+                   [i_(uid|gid)_(read|write) exist])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
index 245f95f041f805411d461d770e4c6eae0d2d0d1e..abbf55d9bb391a6f57490ae6ec7df3c132cf54a3 100644 (file)
@@ -1,17 +1,29 @@
 dnl #
-dnl # 2.6.27 API change
-dnl # lookup_bdev() was exported.
+dnl # 2.6.27, lookup_bdev() was exported.
+dnl # 4.4.0-6.21 - x.y on Ubuntu, lookup_bdev() takes 2 arguments.
 dnl #
 AC_DEFUN([ZFS_AC_KERNEL_LOOKUP_BDEV],
-       [AC_MSG_CHECKING([whether lookup_bdev() is available])
+       [AC_MSG_CHECKING([whether lookup_bdev() wants 1 arg])
        ZFS_LINUX_TRY_COMPILE_SYMBOL([
                #include <linux/fs.h>
        ], [
                lookup_bdev(NULL);
        ], [lookup_bdev], [fs/block_dev.c], [
                AC_MSG_RESULT(yes)
-               AC_DEFINE(HAVE_LOOKUP_BDEV, 1, [lookup_bdev() is available])
+               AC_DEFINE(HAVE_1ARG_LOOKUP_BDEV, 1, [lookup_bdev() wants 1 arg])
        ], [
                AC_MSG_RESULT(no)
+               AC_MSG_CHECKING([whether lookup_bdev() wants 2 args])
+               ZFS_LINUX_TRY_COMPILE_SYMBOL([
+                       #include <linux/fs.h>
+               ], [
+                       lookup_bdev(NULL, FMODE_READ);
+               ], [lookup_bdev], [fs/block_dev.c], [
+                       AC_MSG_RESULT(yes)
+                       AC_DEFINE(HAVE_2ARGS_LOOKUP_BDEV, 1,
+                           [lookup_bdev() wants 2 args])
+               ], [
+                       AC_MSG_RESULT(no)
+               ])
        ])
-])
+])
\ No newline at end of file
diff --git a/zfs/config/kernel-mod-param.m4 b/zfs/config/kernel-mod-param.m4
new file mode 100644 (file)
index 0000000..b72be68
--- /dev/null
@@ -0,0 +1,30 @@
+dnl #
+dnl # Grsecurity kernel API change
+dnl # constified parameters of module_param_call() methods
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_MODULE_PARAM_CALL_CONST], [
+       AC_MSG_CHECKING([whether module_param_call() is hardened])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/module.h>
+               #include <linux/moduleparam.h>
+
+               int param_get(char *b, const struct kernel_param *kp)
+               {
+                       return (0);
+               }
+
+               int param_set(const char *b, const struct kernel_param *kp)
+               {
+                       return (0);
+               }
+
+               module_param_call(p, param_set, param_get, NULL, 0644);
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(MODULE_PARAM_CALL_CONST, 1,
+                   [hardened module_param_call])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-rename.m4 b/zfs/config/kernel-rename.m4
new file mode 100644 (file)
index 0000000..9f894fb
--- /dev/null
@@ -0,0 +1,25 @@
+dnl #
+dnl # 4.9 API change,
+dnl # iops->rename2() merged into iops->rename(), and iops->rename() now wants
+dnl # flags.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_RENAME_WANTS_FLAGS], [
+       AC_MSG_CHECKING([whether iops->rename() wants flags])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+               int rename_fn(struct inode *sip, struct dentry *sdp,
+                       struct inode *tip, struct dentry *tdp,
+                       unsigned int flags) { return 0; }
+
+               static const struct inode_operations
+                   iops __attribute__ ((unused)) = {
+                       .rename = rename_fn,
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1, [iops->rename() wants flags])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-setattr-prepare.m4 b/zfs/config/kernel-setattr-prepare.m4
new file mode 100644 (file)
index 0000000..32f7deb
--- /dev/null
@@ -0,0 +1,23 @@
+dnl #
+dnl # 4.9 API change
+dnl # The inode_change_ok() function has been renamed setattr_prepare()
+dnl # and updated to take a dentry rather than an inode.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SETATTR_PREPARE],
+       [AC_MSG_CHECKING([whether setattr_prepare() is available])
+       ZFS_LINUX_TRY_COMPILE_SYMBOL([
+               #include <linux/fs.h>
+       ], [
+               struct dentry *dentry = NULL;
+               struct iattr *attr = NULL;
+               int error;
+
+               error = setattr_prepare(dentry, attr);
+       ], [setattr_prepare], [fs/attr.c], [
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_SETATTR_PREPARE, 1,
+                   [setattr_prepare() is available])
+       ], [
+               AC_MSG_RESULT(no)
+       ])
+])
diff --git a/zfs/config/kernel-super-userns.m4 b/zfs/config/kernel-super-userns.m4
new file mode 100644 (file)
index 0000000..de94ad9
--- /dev/null
@@ -0,0 +1,21 @@
+dnl #
+dnl # 4.8 API change
+dnl # struct user_namespace was added to struct super_block as
+dnl # super->s_user_ns member
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SUPER_USER_NS], [
+       AC_MSG_CHECKING([whether super_block->s_user_ns exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+               #include <linux/user_namespace.h>
+       ],[
+               struct super_block super;
+               super.s_user_ns = (struct user_namespace *)NULL;
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_SUPER_USER_NS, 1,
+                   [super_block->s_user_ns exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
index dcffd4480c75672feb85f53704170d6d6705393e..300cb0ba8ea4650df507646aadbe551f18c6b1cc 100644 (file)
@@ -57,6 +57,31 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_NAME], [
        ])
 ])
 
+dnl #
+dnl # 4.9 API change,
+dnl # iops->{set,get,remove}xattr and generic_{set,get,remove}xattr are
+dnl # removed. xattr operations will directly go through sb->s_xattr.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_HAVE_GENERIC_SETXATTR], [
+       AC_MSG_CHECKING([whether generic_setxattr() exists])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/fs.h>
+               #include <linux/xattr.h>
+
+               static const struct inode_operations
+                   iops __attribute__ ((unused)) = {
+                       .setxattr = generic_setxattr
+               };
+       ],[
+       ],[
+               AC_MSG_RESULT(yes)
+               AC_DEFINE(HAVE_GENERIC_SETXATTR, 1,
+                   [generic_setxattr() exists])
+       ],[
+               AC_MSG_RESULT(no)
+       ])
+])
+
 dnl #
 dnl # Supported xattr handler get() interfaces checked newest to oldest.
 dnl #
@@ -89,6 +114,7 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_GET], [
                dnl # attr_handler, and handler_flags argument was removed and
                dnl # should be accessed by handler->flags.
                dnl #
+               AC_MSG_RESULT(no)
                AC_MSG_CHECKING([whether xattr_handler->get() wants xattr_handler])
                ZFS_LINUX_TRY_COMPILE([
                        #include <linux/xattr.h>
@@ -192,6 +218,7 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [
                dnl # xattr_handler, and handler_flags argument was removed and
                dnl # should be accessed by handler->flags.
                dnl #
+               AC_MSG_RESULT(no)
                AC_MSG_CHECKING([whether xattr_handler->set() wants xattr_handler])
                ZFS_LINUX_TRY_COMPILE([
                        #include <linux/xattr.h>
index 53720eeef5cfff103ae5aaf04aab064081d9e1b6..44a20f2135c6cd86f44c7d33c88b77138a19fb04 100644 (file)
@@ -1,5 +1,5 @@
 dnl #
-dnl # Default ZFS kernel configuration 
+dnl # Default ZFS kernel configuration
 dnl #
 AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        ZFS_AC_KERNEL
@@ -8,11 +8,11 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        ZFS_AC_KERNEL_CONFIG
        ZFS_AC_KERNEL_DECLARE_EVENT_CLASS
        ZFS_AC_KERNEL_CURRENT_BIO_TAIL
+       ZFS_AC_KERNEL_SUPER_USER_NS
        ZFS_AC_KERNEL_SUBMIT_BIO
        ZFS_AC_KERNEL_BDEV_BLOCK_DEVICE_OPERATIONS
        ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
        ZFS_AC_KERNEL_TYPE_FMODE_T
-       ZFS_AC_KERNEL_KOBJ_NAME_LEN
        ZFS_AC_KERNEL_3ARG_BLKDEV_GET
        ZFS_AC_KERNEL_BLKDEV_GET_BY_PATH
        ZFS_AC_KERNEL_OPEN_BDEV_EXCLUSIVE
@@ -33,6 +33,8 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        ZFS_AC_KERNEL_BLK_QUEUE_FLUSH
        ZFS_AC_KERNEL_BLK_QUEUE_MAX_HW_SECTORS
        ZFS_AC_KERNEL_BLK_QUEUE_MAX_SEGMENTS
+       ZFS_AC_KERNEL_BLK_QUEUE_HAVE_BIO_RW_UNPLUG
+       ZFS_AC_KERNEL_BLK_QUEUE_HAVE_BLK_PLUG
        ZFS_AC_KERNEL_GET_DISK_RO
        ZFS_AC_KERNEL_GET_GENDISK
        ZFS_AC_KERNEL_DISCARD_GRANULARITY
@@ -55,6 +57,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        ZFS_AC_KERNE_GET_ACL_HANDLE_CACHE
        ZFS_AC_KERNEL_SHOW_OPTIONS
        ZFS_AC_KERNEL_FILE_INODE
+       ZFS_AC_KERNEL_FILE_DENTRY
        ZFS_AC_KERNEL_FSYNC
        ZFS_AC_KERNEL_EVICT_INODE
        ZFS_AC_KERNEL_DIRTY_INODE_WITH_FLAGS
@@ -71,6 +74,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        ZFS_AC_KERNEL_ENCODE_FH_WITH_INODE
        ZFS_AC_KERNEL_COMMIT_METADATA
        ZFS_AC_KERNEL_CLEAR_INODE
+       ZFS_AC_KERNEL_SETATTR_PREPARE
        ZFS_AC_KERNEL_INSERT_INODE_LOCKED
        ZFS_AC_KERNEL_D_MAKE_ROOT
        ZFS_AC_KERNEL_D_OBTAIN_ALIAS
@@ -78,7 +82,6 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        ZFS_AC_KERNEL_D_SET_D_OP
        ZFS_AC_KERNEL_D_REVALIDATE_NAMEIDATA
        ZFS_AC_KERNEL_CONST_DENTRY_OPERATIONS
-       ZFS_AC_KERNEL_CHECK_DISK_SIZE_CHANGE
        ZFS_AC_KERNEL_TRUNCATE_SETSIZE
        ZFS_AC_KERNEL_6ARGS_SECURITY_INODE_INIT_SECURITY
        ZFS_AC_KERNEL_CALLBACK_SECURITY_INODE_INIT_SECURITY
@@ -98,6 +101,11 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        ZFS_AC_KERNEL_FOLLOW_DOWN_ONE
        ZFS_AC_KERNEL_MAKE_REQUEST_FN
        ZFS_AC_KERNEL_GENERIC_IO_ACCT
+       ZFS_AC_KERNEL_FPU
+       ZFS_AC_KERNEL_KUID_HELPERS
+       ZFS_AC_KERNEL_MODULE_PARAM_CALL_CONST
+       ZFS_AC_KERNEL_RENAME_WANTS_FLAGS
+       ZFS_AC_KERNEL_HAVE_GENERIC_SETXATTR
 
        AS_IF([test "$LINUX_OBJ" != "$LINUX"], [
                KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
@@ -259,7 +267,9 @@ AC_DEFUN([ZFS_AC_SPL], [
        AC_ARG_WITH([spl],
                AS_HELP_STRING([--with-spl=PATH],
                [Path to spl source]),
-               [splsrc="$withval"])
+               AS_IF([test "$withval" = "yes"],
+                       AC_MSG_ERROR([--with-spl=PATH requires a PATH]),
+                       [splsrc="$withval"]))
 
        AC_ARG_WITH([spl-obj],
                AS_HELP_STRING([--with-spl-obj=PATH],
@@ -285,6 +295,14 @@ AC_DEFUN([ZFS_AC_SPL], [
 
        AC_MSG_CHECKING([spl source directory])
        AS_IF([test -z "${splsrc}"], [
+               [all_spl_sources="
+               ${splsrc0}
+               ${splsrc1}
+               ${splsrc2}
+               ${splsrc3}
+               ${splsrc4}
+               ${splsrc5}
+               ${splsrc6}"],
                AS_IF([ test -e "${splsrc0}/spl.release.in"], [
                        splsrc=${splsrc0}
                ], [ test -e "${splsrc1}/spl.release.in"], [
@@ -303,6 +321,7 @@ AC_DEFUN([ZFS_AC_SPL], [
                        splsrc="[Not found]"
                ])
        ], [
+               [all_spl_sources="$withval"],
                AS_IF([test "$splsrc" = "NONE"], [
                        splbuild=NONE
                        splsrcver=NONE
@@ -314,7 +333,10 @@ AC_DEFUN([ZFS_AC_SPL], [
                AC_MSG_ERROR([
        *** Please make sure the kmod spl devel package for your distribution
        *** is installed then try again.  If that fails you can specify the
-       *** location of the spl source with the '--with-spl=PATH' option.])
+       *** location of the spl source with the '--with-spl=PATH' option.
+       *** The spl version must match the version of ZFS you are building,
+       *** ${VERSION}.  Failed to find spl.release.in in the following:
+       $all_spl_sources])
        ])
 
        dnl #
@@ -330,6 +352,10 @@ AC_DEFUN([ZFS_AC_SPL], [
        dnl # SPL package.
        dnl #
        AC_MSG_CHECKING([spl build directory])
+
+       all_spl_config_locs="${splsrc}/${LINUX_VERSION}
+       ${splsrc}"
+
        while true; do
                AS_IF([test -z "$splbuild"], [
                        AS_IF([ test -e "${splsrc}/${LINUX_VERSION}/spl_config.h" ], [
@@ -356,7 +382,9 @@ AC_DEFUN([ZFS_AC_SPL], [
        *** Please make sure the kmod spl devel <kernel> package for your
        *** distribution is installed then try again.  If that fails you
        *** can specify the location of the spl objects with the
-       *** '--with-spl-obj=PATH' option.])
+       *** '--with-spl-obj=PATH' option.  Failed to find spl_config.h in
+       *** any of the following:
+       $all_spl_config_locs])
        ])
 
        AC_MSG_CHECKING([spl source version])
@@ -468,9 +496,35 @@ AC_DEFUN([ZFS_AC_KERNEL_CONFIG], [
                ])
        ])
 
+       ZFS_AC_KERNEL_CONFIG_THREAD_SIZE
        ZFS_AC_KERNEL_CONFIG_DEBUG_LOCK_ALLOC
 ])
 
+dnl #
+dnl # Check configured THREAD_SIZE
+dnl #
+dnl # The stack size will vary by architecture, but as of Linux 3.15 on x86_64
+dnl # the default thread stack size was increased to 16K from 8K.  Therefore,
+dnl # on newer kernels and some architectures stack usage optimizations can be
+dnl # conditionally applied to improve performance without negatively impacting
+dnl # stability.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_CONFIG_THREAD_SIZE], [
+       AC_MSG_CHECKING([whether kernel was built with 16K or larger stacks])
+       ZFS_LINUX_TRY_COMPILE([
+               #include <linux/module.h>
+       ],[
+               #if (THREAD_SIZE < 16384)
+               #error "THREAD_SIZE is less than 16K"
+               #endif
+       ],[
+               AC_MSG_RESULT([yes])
+               AC_DEFINE(HAVE_LARGE_STACKS, 1, [kernel has large stacks])
+       ],[
+               AC_MSG_RESULT([no])
+       ])
+])
+
 dnl #
 dnl # Check CONFIG_DEBUG_LOCK_ALLOC
 dnl #
@@ -580,7 +634,7 @@ dnl #
 dnl # ZFS_LINUX_CONFIG
 dnl #
 AC_DEFUN([ZFS_LINUX_CONFIG],
-       [AC_MSG_CHECKING([whether Linux was built with CONFIG_$1])
+       [AC_MSG_CHECKING([whether kernel was built with CONFIG_$1])
        ZFS_LINUX_TRY_COMPILE([
                #include <linux/module.h>
        ],[
diff --git a/zfs/config/libtool.m4 b/zfs/config/libtool.m4
deleted file mode 100644 (file)
index ee80844..0000000
+++ /dev/null
@@ -1,8387 +0,0 @@
-# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
-#
-#   Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
-#   Written by Gordon Matzigkeit, 1996
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-m4_define([_LT_COPYING], [dnl
-# Copyright (C) 2014 Free Software Foundation, Inc.
-# This is free software; see the source for copying conditions.  There is NO
-# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-# GNU Libtool is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of of the License, or
-# (at your option) any later version.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program or library that is built
-# using GNU Libtool, you may include this file under the  same
-# distribution terms that you use for the rest of that program.
-#
-# GNU Libtool is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-])
-
-# serial 58 LT_INIT
-
-
-# LT_PREREQ(VERSION)
-# ------------------
-# Complain and exit if this libtool version is less that VERSION.
-m4_defun([LT_PREREQ],
-[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
-       [m4_default([$3],
-                  [m4_fatal([Libtool version $1 or higher is required],
-                            63)])],
-       [$2])])
-
-
-# _LT_CHECK_BUILDDIR
-# ------------------
-# Complain if the absolute build directory name contains unusual characters
-m4_defun([_LT_CHECK_BUILDDIR],
-[case `pwd` in
-  *\ * | *\    *)
-    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
-esac
-])
-
-
-# LT_INIT([OPTIONS])
-# ------------------
-AC_DEFUN([LT_INIT],
-[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
-AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
-AC_BEFORE([$0], [LT_LANG])dnl
-AC_BEFORE([$0], [LT_OUTPUT])dnl
-AC_BEFORE([$0], [LTDL_INIT])dnl
-m4_require([_LT_CHECK_BUILDDIR])dnl
-
-dnl Autoconf doesn't catch unexpanded LT_ macros by default:
-m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
-m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
-dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
-dnl unless we require an AC_DEFUNed macro:
-AC_REQUIRE([LTOPTIONS_VERSION])dnl
-AC_REQUIRE([LTSUGAR_VERSION])dnl
-AC_REQUIRE([LTVERSION_VERSION])dnl
-AC_REQUIRE([LTOBSOLETE_VERSION])dnl
-m4_require([_LT_PROG_LTMAIN])dnl
-
-_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
-
-dnl Parse OPTIONS
-_LT_SET_OPTIONS([$0], [$1])
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS=$ltmain
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-AC_SUBST(LIBTOOL)dnl
-
-_LT_SETUP
-
-# Only expand once:
-m4_define([LT_INIT])
-])# LT_INIT
-
-# Old names:
-AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
-AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
-dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
-
-
-# _LT_PREPARE_CC_BASENAME
-# -----------------------
-m4_defun([_LT_PREPARE_CC_BASENAME], [
-# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
-func_cc_basename ()
-{
-    for cc_temp in @S|@*""; do
-      case $cc_temp in
-        compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
-        distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
-        \-*) ;;
-        *) break;;
-      esac
-    done
-    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
-}
-])# _LT_PREPARE_CC_BASENAME
-
-
-# _LT_CC_BASENAME(CC)
-# -------------------
-# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
-# but that macro is also expanded into generated libtool script, which
-# arranges for $SED and $ECHO to be set by different means.
-m4_defun([_LT_CC_BASENAME],
-[m4_require([_LT_PREPARE_CC_BASENAME])dnl
-AC_REQUIRE([_LT_DECL_SED])dnl
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
-func_cc_basename $1
-cc_basename=$func_cc_basename_result
-])
-
-
-# _LT_FILEUTILS_DEFAULTS
-# ----------------------
-# It is okay to use these file commands and assume they have been set
-# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
-m4_defun([_LT_FILEUTILS_DEFAULTS],
-[: ${CP="cp -f"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-])# _LT_FILEUTILS_DEFAULTS
-
-
-# _LT_SETUP
-# ---------
-m4_defun([_LT_SETUP],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
-
-_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
-dnl
-_LT_DECL([], [host_alias], [0], [The host system])dnl
-_LT_DECL([], [host], [0])dnl
-_LT_DECL([], [host_os], [0])dnl
-dnl
-_LT_DECL([], [build_alias], [0], [The build system])dnl
-_LT_DECL([], [build], [0])dnl
-_LT_DECL([], [build_os], [0])dnl
-dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-dnl
-AC_REQUIRE([AC_PROG_LN_S])dnl
-test -z "$LN_S" && LN_S="ln -s"
-_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
-dnl
-AC_REQUIRE([LT_CMD_MAX_LEN])dnl
-_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
-_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
-dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
-m4_require([_LT_CMD_RELOAD])dnl
-m4_require([_LT_CHECK_MAGIC_METHOD])dnl
-m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
-m4_require([_LT_CMD_OLD_ARCHIVE])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_WITH_SYSROOT])dnl
-m4_require([_LT_CMD_TRUNCATE])dnl
-
-_LT_CONFIG_LIBTOOL_INIT([
-# See if we are running on zsh, and set the options that allow our
-# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}"; then
-   setopt NO_GLOB_SUBST
-fi
-])
-if test -n "${ZSH_VERSION+set}"; then
-   setopt NO_GLOB_SUBST
-fi
-
-_LT_CHECK_OBJDIR
-
-m4_require([_LT_TAG_COMPILER])dnl
-
-case $host_os in
-aix3*)
-  # AIX sometimes has problems with the GCC collect2 program.  For some
-  # reason, if we set the COLLECT_NAMES environment variable, the problems
-  # vanish in a puff of smoke.
-  if test set != "${COLLECT_NAMES+set}"; then
-    COLLECT_NAMES=
-    export COLLECT_NAMES
-  fi
-  ;;
-esac
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a '.a' archive for static linking (except MSVC,
-# which needs '.lib').
-libext=a
-
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-old_CC=$CC
-old_CFLAGS=$CFLAGS
-
-# Set sane defaults for various variables
-test -z "$CC" && CC=cc
-test -z "$LTCC" && LTCC=$CC
-test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
-test -z "$LD" && LD=ld
-test -z "$ac_objext" && ac_objext=o
-
-_LT_CC_BASENAME([$compiler])
-
-# Only perform the check for file, if the check method requires it
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-case $deplibs_check_method in
-file_magic*)
-  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
-    _LT_PATH_MAGIC
-  fi
-  ;;
-esac
-
-# Use C for the default configuration in the libtool script
-LT_SUPPORTED_TAG([CC])
-_LT_LANG_C_CONFIG
-_LT_LANG_DEFAULT_CONFIG
-_LT_CONFIG_COMMANDS
-])# _LT_SETUP
-
-
-# _LT_PREPARE_SED_QUOTE_VARS
-# --------------------------
-# Define a few sed substitution that help us do robust quoting.
-m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
-[# Backslashify metacharacters that are still active within
-# double-quoted strings.
-sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([["`\\]]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-])
-
-# _LT_PROG_LTMAIN
-# ---------------
-# Note that this code is called both from 'configure', and 'config.status'
-# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
-# 'config.status' has no value for ac_aux_dir unless we are using Automake,
-# so we pass a copy along to make sure it has a sensible value anyway.
-m4_defun([_LT_PROG_LTMAIN],
-[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
-_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
-ltmain=$ac_aux_dir/ltmain.sh
-])# _LT_PROG_LTMAIN
-
-
-## ------------------------------------- ##
-## Accumulate code for creating libtool. ##
-## ------------------------------------- ##
-
-# So that we can recreate a full libtool script including additional
-# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
-# in macros and then make a single call at the end using the 'libtool'
-# label.
-
-
-# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
-# ----------------------------------------
-# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL_INIT],
-[m4_ifval([$1],
-          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
-                     [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_INIT])
-
-
-# _LT_CONFIG_LIBTOOL([COMMANDS])
-# ------------------------------
-# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL],
-[m4_ifval([$1],
-          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
-                     [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
-
-
-# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
-# -----------------------------------------------------
-m4_defun([_LT_CONFIG_SAVE_COMMANDS],
-[_LT_CONFIG_LIBTOOL([$1])
-_LT_CONFIG_LIBTOOL_INIT([$2])
-])
-
-
-# _LT_FORMAT_COMMENT([COMMENT])
-# -----------------------------
-# Add leading comment marks to the start of each line, and a trailing
-# full-stop to the whole comment if one is not present already.
-m4_define([_LT_FORMAT_COMMENT],
-[m4_ifval([$1], [
-m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
-              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
-)])
-
-
-
-## ------------------------ ##
-## FIXME: Eliminate VARNAME ##
-## ------------------------ ##
-
-
-# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
-# -------------------------------------------------------------------
-# CONFIGNAME is the name given to the value in the libtool script.
-# VARNAME is the (base) name used in the configure script.
-# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
-# VARNAME.  Any other value will be used directly.
-m4_define([_LT_DECL],
-[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
-    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
-       [m4_ifval([$1], [$1], [$2])])
-    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
-    m4_ifval([$4],
-       [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
-    lt_dict_add_subkey([lt_decl_dict], [$2],
-       [tagged?], [m4_ifval([$5], [yes], [no])])])
-])
-
-
-# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
-# --------------------------------------------------------
-m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
-
-
-# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_tag_varnames],
-[_lt_decl_filter([tagged?], [yes], $@)])
-
-
-# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
-# ---------------------------------------------------------
-m4_define([_lt_decl_filter],
-[m4_case([$#],
-  [0], [m4_fatal([$0: too few arguments: $#])],
-  [1], [m4_fatal([$0: too few arguments: $#: $1])],
-  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
-  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
-  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
-])
-
-
-# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
-# --------------------------------------------------
-m4_define([lt_decl_quote_varnames],
-[_lt_decl_filter([value], [1], $@)])
-
-
-# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_dquote_varnames],
-[_lt_decl_filter([value], [2], $@)])
-
-
-# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_varnames_tagged],
-[m4_assert([$# <= 2])dnl
-_$0(m4_quote(m4_default([$1], [[, ]])),
-    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
-    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
-m4_define([_lt_decl_varnames_tagged],
-[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
-
-
-# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_all_varnames],
-[_$0(m4_quote(m4_default([$1], [[, ]])),
-     m4_if([$2], [],
-          m4_quote(lt_decl_varnames),
-       m4_quote(m4_shift($@))))[]dnl
-])
-m4_define([_lt_decl_all_varnames],
-[lt_join($@, lt_decl_varnames_tagged([$1],
-                       lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
-])
-
-
-# _LT_CONFIG_STATUS_DECLARE([VARNAME])
-# ------------------------------------
-# Quote a variable value, and forward it to 'config.status' so that its
-# declaration there will have the same value as in 'configure'.  VARNAME
-# must have a single quote delimited value for this to work.
-m4_define([_LT_CONFIG_STATUS_DECLARE],
-[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
-
-
-# _LT_CONFIG_STATUS_DECLARATIONS
-# ------------------------------
-# We delimit libtool config variables with single quotes, so when
-# we write them to config.status, we have to be sure to quote all
-# embedded single quotes properly.  In configure, this macro expands
-# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
-#
-#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
-m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
-    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAGS
-# ----------------
-# Output comment and list of tags supported by the script
-m4_defun([_LT_LIBTOOL_TAGS],
-[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
-available_tags='_LT_TAGS'dnl
-])
-
-
-# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
-# -----------------------------------
-# Extract the dictionary values for VARNAME (optionally with TAG) and
-# expand to a commented shell variable setting:
-#
-#    # Some comment about what VAR is for.
-#    visible_name=$lt_internal_name
-m4_define([_LT_LIBTOOL_DECLARE],
-[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
-                                          [description])))[]dnl
-m4_pushdef([_libtool_name],
-    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
-m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
-    [0], [_libtool_name=[$]$1],
-    [1], [_libtool_name=$lt_[]$1],
-    [2], [_libtool_name=$lt_[]$1],
-    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
-m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
-])
-
-
-# _LT_LIBTOOL_CONFIG_VARS
-# -----------------------
-# Produce commented declarations of non-tagged libtool config variables
-# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
-# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
-# section) are produced by _LT_LIBTOOL_TAG_VARS.
-m4_defun([_LT_LIBTOOL_CONFIG_VARS],
-[m4_foreach([_lt_var],
-    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
-    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAG_VARS(TAG)
-# -------------------------
-m4_define([_LT_LIBTOOL_TAG_VARS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
-    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
-
-
-# _LT_TAGVAR(VARNAME, [TAGNAME])
-# ------------------------------
-m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
-
-
-# _LT_CONFIG_COMMANDS
-# -------------------
-# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
-# variables for single and double quote escaping we saved from calls
-# to _LT_DECL, we can put quote escaped variables declarations
-# into 'config.status', and then the shell code to quote escape them in
-# for loops in 'config.status'.  Finally, any additional code accumulated
-# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
-m4_defun([_LT_CONFIG_COMMANDS],
-[AC_PROVIDE_IFELSE([LT_OUTPUT],
-       dnl If the libtool generation code has been placed in $CONFIG_LT,
-       dnl instead of duplicating it all over again into config.status,
-       dnl then we will have config.status run $CONFIG_LT later, so it
-       dnl needs to know what name is stored there:
-        [AC_CONFIG_COMMANDS([libtool],
-            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
-    dnl If the libtool generation code is destined for config.status,
-    dnl expand the accumulated commands and init code now:
-    [AC_CONFIG_COMMANDS([libtool],
-        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
-])#_LT_CONFIG_COMMANDS
-
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
-[
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-sed_quote_subst='$sed_quote_subst'
-double_quote_subst='$double_quote_subst'
-delay_variable_subst='$delay_variable_subst'
-_LT_CONFIG_STATUS_DECLARATIONS
-LTCC='$LTCC'
-LTCFLAGS='$LTCFLAGS'
-compiler='$compiler_DEFAULT'
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
-  eval 'cat <<_LTECHO_EOF
-\$[]1
-_LTECHO_EOF'
-}
-
-# Quote evaled strings.
-for var in lt_decl_all_varnames([[ \
-]], lt_decl_quote_varnames); do
-    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
-    *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
-      ;;
-    *)
-      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
-      ;;
-    esac
-done
-
-# Double-quote double-evaled strings.
-for var in lt_decl_all_varnames([[ \
-]], lt_decl_dquote_varnames); do
-    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
-    *[[\\\\\\\`\\"\\\$]]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
-      ;;
-    *)
-      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
-      ;;
-    esac
-done
-
-_LT_OUTPUT_LIBTOOL_INIT
-])
-
-# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
-# ------------------------------------
-# Generate a child script FILE with all initialization necessary to
-# reuse the environment learned by the parent script, and make the
-# file executable.  If COMMENT is supplied, it is inserted after the
-# '#!' sequence but before initialization text begins.  After this
-# macro, additional text can be appended to FILE to form the body of
-# the child script.  The macro ends with non-zero status if the
-# file could not be fully written (such as if the disk is full).
-m4_ifdef([AS_INIT_GENERATED],
-[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
-[m4_defun([_LT_GENERATED_FILE_INIT],
-[m4_require([AS_PREPARE])]dnl
-[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
-[lt_write_fail=0
-cat >$1 <<_ASEOF || lt_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-$2
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$1 <<\_ASEOF || lt_write_fail=1
-AS_SHELL_SANITIZE
-_AS_PREPARE
-exec AS_MESSAGE_FD>&1
-_ASEOF
-test 0 = "$lt_write_fail" && chmod +x $1[]dnl
-m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
-
-# LT_OUTPUT
-# ---------
-# This macro allows early generation of the libtool script (before
-# AC_OUTPUT is called), incase it is used in configure for compilation
-# tests.
-AC_DEFUN([LT_OUTPUT],
-[: ${CONFIG_LT=./config.lt}
-AC_MSG_NOTICE([creating $CONFIG_LT])
-_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
-[# Run this file to recreate a libtool stub with the current configuration.])
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-lt_cl_silent=false
-exec AS_MESSAGE_LOG_FD>>config.log
-{
-  echo
-  AS_BOX([Running $as_me.])
-} >&AS_MESSAGE_LOG_FD
-
-lt_cl_help="\
-'$as_me' creates a local libtool stub from the current configuration,
-for use in further configure time tests before the real libtool is
-generated.
-
-Usage: $[0] [[OPTIONS]]
-
-  -h, --help      print this help, then exit
-  -V, --version   print version number, then exit
-  -q, --quiet     do not print progress messages
-  -d, --debug     don't remove temporary files
-
-Report bugs to <bug-libtool@gnu.org>."
-
-lt_cl_version="\
-m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
-m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
-configured by $[0], generated by m4_PACKAGE_STRING.
-
-Copyright (C) 2011 Free Software Foundation, Inc.
-This config.lt script is free software; the Free Software Foundation
-gives unlimited permision to copy, distribute and modify it."
-
-while test 0 != $[#]
-do
-  case $[1] in
-    --version | --v* | -V )
-      echo "$lt_cl_version"; exit 0 ;;
-    --help | --h* | -h )
-      echo "$lt_cl_help"; exit 0 ;;
-    --debug | --d* | -d )
-      debug=: ;;
-    --quiet | --q* | --silent | --s* | -q )
-      lt_cl_silent=: ;;
-
-    -*) AC_MSG_ERROR([unrecognized option: $[1]
-Try '$[0] --help' for more information.]) ;;
-
-    *) AC_MSG_ERROR([unrecognized argument: $[1]
-Try '$[0] --help' for more information.]) ;;
-  esac
-  shift
-done
-
-if $lt_cl_silent; then
-  exec AS_MESSAGE_FD>/dev/null
-fi
-_LTEOF
-
-cat >>"$CONFIG_LT" <<_LTEOF
-_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
-_LTEOF
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-AC_MSG_NOTICE([creating $ofile])
-_LT_OUTPUT_LIBTOOL_COMMANDS
-AS_EXIT(0)
-_LTEOF
-chmod +x "$CONFIG_LT"
-
-# configure is writing to config.log, but config.lt does its own redirection,
-# appending to config.log, which fails on DOS, as config.log is still kept
-# open by configure.  Here we exec the FD to /dev/null, effectively closing
-# config.log, so it can be properly (re)opened and appended to by config.lt.
-lt_cl_success=:
-test yes = "$silent" &&
-  lt_config_lt_args="$lt_config_lt_args --quiet"
-exec AS_MESSAGE_LOG_FD>/dev/null
-$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
-exec AS_MESSAGE_LOG_FD>>config.log
-$lt_cl_success || AS_EXIT(1)
-])# LT_OUTPUT
-
-
-# _LT_CONFIG(TAG)
-# ---------------
-# If TAG is the built-in tag, create an initial libtool script with a
-# default configuration from the untagged config vars.  Otherwise add code
-# to config.status for appending the configuration named by TAG from the
-# matching tagged config vars.
-m4_defun([_LT_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_CONFIG_SAVE_COMMANDS([
-  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
-  m4_if(_LT_TAG, [C], [
-    # See if we are running on zsh, and set the options that allow our
-    # commands through without removal of \ escapes.
-    if test -n "${ZSH_VERSION+set}"; then
-      setopt NO_GLOB_SUBST
-    fi
-
-    cfgfile=${ofile}T
-    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
-    $RM "$cfgfile"
-
-    cat <<_LT_EOF >> "$cfgfile"
-#! $SHELL
-# Generated automatically by $as_me ($PACKAGE) $VERSION
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-
-# Provide generalized library-building support services.
-# Written by Gordon Matzigkeit, 1996
-
-_LT_COPYING
-_LT_LIBTOOL_TAGS
-
-# Configured defaults for sys_lib_dlsearch_path munging.
-: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
-
-# ### BEGIN LIBTOOL CONFIG
-_LT_LIBTOOL_CONFIG_VARS
-_LT_LIBTOOL_TAG_VARS
-# ### END LIBTOOL CONFIG
-
-_LT_EOF
-
-    cat <<'_LT_EOF' >> "$cfgfile"
-
-# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
-
-_LT_PREPARE_MUNGE_PATH_LIST
-_LT_PREPARE_CC_BASENAME
-
-# ### END FUNCTIONS SHARED WITH CONFIGURE
-
-_LT_EOF
-
-  case $host_os in
-  aix3*)
-    cat <<\_LT_EOF >> "$cfgfile"
-# AIX sometimes has problems with the GCC collect2 program.  For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test set != "${COLLECT_NAMES+set}"; then
-  COLLECT_NAMES=
-  export COLLECT_NAMES
-fi
-_LT_EOF
-    ;;
-  esac
-
-  _LT_PROG_LTMAIN
-
-  # We use sed instead of cat because bash on DJGPP gets confused if
-  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
-  # text mode, it properly converts lines to CR/LF.  This bash problem
-  # is reportedly fixed, but why not run on old versions too?
-  sed '$q' "$ltmain" >> "$cfgfile" \
-     || (rm -f "$cfgfile"; exit 1)
-
-   mv -f "$cfgfile" "$ofile" ||
-    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
-  chmod +x "$ofile"
-],
-[cat <<_LT_EOF >> "$ofile"
-
-dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
-dnl in a comment (ie after a #).
-# ### BEGIN LIBTOOL TAG CONFIG: $1
-_LT_LIBTOOL_TAG_VARS(_LT_TAG)
-# ### END LIBTOOL TAG CONFIG: $1
-_LT_EOF
-])dnl /m4_if
-],
-[m4_if([$1], [], [
-    PACKAGE='$PACKAGE'
-    VERSION='$VERSION'
-    RM='$RM'
-    ofile='$ofile'], [])
-])dnl /_LT_CONFIG_SAVE_COMMANDS
-])# _LT_CONFIG
-
-
-# LT_SUPPORTED_TAG(TAG)
-# ---------------------
-# Trace this macro to discover what tags are supported by the libtool
-# --tag option, using:
-#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
-AC_DEFUN([LT_SUPPORTED_TAG], [])
-
-
-# C support is built-in for now
-m4_define([_LT_LANG_C_enabled], [])
-m4_define([_LT_TAGS], [])
-
-
-# LT_LANG(LANG)
-# -------------
-# Enable libtool support for the given language if not already enabled.
-AC_DEFUN([LT_LANG],
-[AC_BEFORE([$0], [LT_OUTPUT])dnl
-m4_case([$1],
-  [C],                 [_LT_LANG(C)],
-  [C++],               [_LT_LANG(CXX)],
-  [Go],                        [_LT_LANG(GO)],
-  [Java],              [_LT_LANG(GCJ)],
-  [Fortran 77],                [_LT_LANG(F77)],
-  [Fortran],           [_LT_LANG(FC)],
-  [Windows Resource],  [_LT_LANG(RC)],
-  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
-    [_LT_LANG($1)],
-    [m4_fatal([$0: unsupported language: "$1"])])])dnl
-])# LT_LANG
-
-
-# _LT_LANG(LANGNAME)
-# ------------------
-m4_defun([_LT_LANG],
-[m4_ifdef([_LT_LANG_]$1[_enabled], [],
-  [LT_SUPPORTED_TAG([$1])dnl
-  m4_append([_LT_TAGS], [$1 ])dnl
-  m4_define([_LT_LANG_]$1[_enabled], [])dnl
-  _LT_LANG_$1_CONFIG($1)])dnl
-])# _LT_LANG
-
-
-m4_ifndef([AC_PROG_GO], [
-############################################################
-# NOTE: This macro has been submitted for inclusion into   #
-#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
-#  a released version of Autoconf we should remove this    #
-#  macro and use it instead.                               #
-############################################################
-m4_defun([AC_PROG_GO],
-[AC_LANG_PUSH(Go)dnl
-AC_ARG_VAR([GOC],     [Go compiler command])dnl
-AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
-_AC_ARG_VAR_LDFLAGS()dnl
-AC_CHECK_TOOL(GOC, gccgo)
-if test -z "$GOC"; then
-  if test -n "$ac_tool_prefix"; then
-    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
-  fi
-fi
-if test -z "$GOC"; then
-  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
-fi
-])#m4_defun
-])#m4_ifndef
-
-
-# _LT_LANG_DEFAULT_CONFIG
-# -----------------------
-m4_defun([_LT_LANG_DEFAULT_CONFIG],
-[AC_PROVIDE_IFELSE([AC_PROG_CXX],
-  [LT_LANG(CXX)],
-  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_F77],
-  [LT_LANG(F77)],
-  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_FC],
-  [LT_LANG(FC)],
-  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
-
-dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
-dnl pulling things in needlessly.
-AC_PROVIDE_IFELSE([AC_PROG_GCJ],
-  [LT_LANG(GCJ)],
-  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
-    [LT_LANG(GCJ)],
-    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
-      [LT_LANG(GCJ)],
-      [m4_ifdef([AC_PROG_GCJ],
-       [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
-       m4_ifdef([A][M_PROG_GCJ],
-       [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
-       m4_ifdef([LT_PROG_GCJ],
-       [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
-
-AC_PROVIDE_IFELSE([AC_PROG_GO],
-  [LT_LANG(GO)],
-  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
-
-AC_PROVIDE_IFELSE([LT_PROG_RC],
-  [LT_LANG(RC)],
-  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
-])# _LT_LANG_DEFAULT_CONFIG
-
-# Obsolete macros:
-AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
-AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
-AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
-AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
-AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
-dnl AC_DEFUN([AC_LIBTOOL_F77], [])
-dnl AC_DEFUN([AC_LIBTOOL_FC], [])
-dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
-dnl AC_DEFUN([AC_LIBTOOL_RC], [])
-
-
-# _LT_TAG_COMPILER
-# ----------------
-m4_defun([_LT_TAG_COMPILER],
-[AC_REQUIRE([AC_PROG_CC])dnl
-
-_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
-_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
-_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
-_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-])# _LT_TAG_COMPILER
-
-
-# _LT_COMPILER_BOILERPLATE
-# ------------------------
-# Check for compiler boilerplate output or warnings with
-# the simple compiler test code.
-m4_defun([_LT_COMPILER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_compile_test_code" >conftest.$ac_ext
-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_compiler_boilerplate=`cat conftest.err`
-$RM conftest*
-])# _LT_COMPILER_BOILERPLATE
-
-
-# _LT_LINKER_BOILERPLATE
-# ----------------------
-# Check for linker boilerplate output or warnings with
-# the simple link test code.
-m4_defun([_LT_LINKER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_link_test_code" >conftest.$ac_ext
-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_linker_boilerplate=`cat conftest.err`
-$RM -r conftest*
-])# _LT_LINKER_BOILERPLATE
-
-# _LT_REQUIRED_DARWIN_CHECKS
-# -------------------------
-m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
-  case $host_os in
-    rhapsody* | darwin*)
-    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
-    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
-    AC_CHECK_TOOL([LIPO], [lipo], [:])
-    AC_CHECK_TOOL([OTOOL], [otool], [:])
-    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
-    _LT_DECL([], [DSYMUTIL], [1],
-      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
-    _LT_DECL([], [NMEDIT], [1],
-      [Tool to change global to local symbols on Mac OS X])
-    _LT_DECL([], [LIPO], [1],
-      [Tool to manipulate fat objects and archives on Mac OS X])
-    _LT_DECL([], [OTOOL], [1],
-      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
-    _LT_DECL([], [OTOOL64], [1],
-      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
-
-    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
-      [lt_cv_apple_cc_single_mod=no
-      if test -z "$LT_MULTI_MODULE"; then
-       # By default we will add the -single_module flag. You can override
-       # by either setting the environment variable LT_MULTI_MODULE
-       # non-empty at configure time, or by adding -multi_module to the
-       # link flags.
-       rm -rf libconftest.dylib*
-       echo "int foo(void){return 1;}" > conftest.c
-       echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
-       $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
-         -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
-        _lt_result=$?
-       # If there is a non-empty error log, and "single_module"
-       # appears in it, assume the flag caused a linker warning
-        if test -s conftest.err && $GREP single_module conftest.err; then
-         cat conftest.err >&AS_MESSAGE_LOG_FD
-       # Otherwise, if the output was created with a 0 exit code from
-       # the compiler, it worked.
-       elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
-         lt_cv_apple_cc_single_mod=yes
-       else
-         cat conftest.err >&AS_MESSAGE_LOG_FD
-       fi
-       rm -rf libconftest.dylib*
-       rm -f conftest.*
-      fi])
-
-    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
-      [lt_cv_ld_exported_symbols_list],
-      [lt_cv_ld_exported_symbols_list=no
-      save_LDFLAGS=$LDFLAGS
-      echo "_main" > conftest.sym
-      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
-      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
-       [lt_cv_ld_exported_symbols_list=yes],
-       [lt_cv_ld_exported_symbols_list=no])
-       LDFLAGS=$save_LDFLAGS
-    ])
-
-    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
-      [lt_cv_ld_force_load=no
-      cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
-      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
-      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
-      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
-      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
-      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
-      cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
-      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
-      _lt_result=$?
-      if test -s conftest.err && $GREP force_load conftest.err; then
-       cat conftest.err >&AS_MESSAGE_LOG_FD
-      elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
-       lt_cv_ld_force_load=yes
-      else
-       cat conftest.err >&AS_MESSAGE_LOG_FD
-      fi
-        rm -f conftest.err libconftest.a conftest conftest.c
-        rm -rf conftest.dSYM
-    ])
-    case $host_os in
-    rhapsody* | darwin1.[[012]])
-      _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
-    darwin1.*)
-      _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
-    darwin*) # darwin 5.x on
-      # if running on 10.5 or later, the deployment target defaults
-      # to the OS version, if on x86, and 10.4, the deployment
-      # target defaults to 10.4. Don't you love it?
-      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
-       10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
-         _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
-       10.[[012]][[,.]]*)
-         _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
-       10.*)
-         _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
-      esac
-    ;;
-  esac
-    if test yes = "$lt_cv_apple_cc_single_mod"; then
-      _lt_dar_single_mod='$single_module'
-    fi
-    if test yes = "$lt_cv_ld_exported_symbols_list"; then
-      _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
-    else
-      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
-    fi
-    if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
-      _lt_dsymutil='~$DSYMUTIL $lib || :'
-    else
-      _lt_dsymutil=
-    fi
-    ;;
-  esac
-])
-
-
-# _LT_DARWIN_LINKER_FEATURES([TAG])
-# ---------------------------------
-# Checks for linker and compiler features on darwin
-m4_defun([_LT_DARWIN_LINKER_FEATURES],
-[
-  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
-  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-  _LT_TAGVAR(hardcode_direct, $1)=no
-  _LT_TAGVAR(hardcode_automatic, $1)=yes
-  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-  if test yes = "$lt_cv_ld_force_load"; then
-    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
-    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
-                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
-  else
-    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
-  fi
-  _LT_TAGVAR(link_all_deplibs, $1)=yes
-  _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
-  case $cc_basename in
-     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
-     *) _lt_dar_can_shared=$GCC ;;
-  esac
-  if test yes = "$_lt_dar_can_shared"; then
-    output_verbose_link_cmd=func_echo_all
-    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
-    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
-    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
-    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
-    m4_if([$1], [CXX],
-[   if test yes != "$lt_cv_apple_cc_single_mod"; then
-      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
-      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
-    fi
-],[])
-  else
-  _LT_TAGVAR(ld_shlibs, $1)=no
-  fi
-])
-
-# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
-# ----------------------------------
-# Links a minimal program and checks the executable
-# for the system default hardcoded library path. In most cases,
-# this is /usr/lib:/lib, but when the MPI compilers are used
-# the location of the communication and MPI libs are included too.
-# If we don't find anything, use the default library path according
-# to the aix ld manual.
-# Store the results from the different compilers for each TAGNAME.
-# Allow to override them for all tags through lt_cv_aix_libpath.
-m4_defun([_LT_SYS_MODULE_PATH_AIX],
-[m4_require([_LT_DECL_SED])dnl
-if test set = "${lt_cv_aix_libpath+set}"; then
-  aix_libpath=$lt_cv_aix_libpath
-else
-  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
-  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
-  lt_aix_libpath_sed='[
-      /Import File Strings/,/^$/ {
-         /^0/ {
-             s/^0  *\([^ ]*\) *$/\1/
-             p
-         }
-      }]'
-  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  # Check for a 64-bit object if we didn't find anything.
-  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
-    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  fi],[])
-  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
-    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
-  fi
-  ])
-  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
-fi
-])# _LT_SYS_MODULE_PATH_AIX
-
-
-# _LT_SHELL_INIT(ARG)
-# -------------------
-m4_define([_LT_SHELL_INIT],
-[m4_divert_text([M4SH-INIT], [$1
-])])# _LT_SHELL_INIT
-
-
-
-# _LT_PROG_ECHO_BACKSLASH
-# -----------------------
-# Find how we can fake an echo command that does not interpret backslash.
-# In particular, with Autoconf 2.60 or later we add some code to the start
-# of the generated configure script that will find a shell with a builtin
-# printf (that we can use as an echo command).
-m4_defun([_LT_PROG_ECHO_BACKSLASH],
-[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-
-AC_MSG_CHECKING([how to print strings])
-# Test print first, because it will be a builtin if present.
-if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
-   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='print -r --'
-elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='printf %s\n'
-else
-  # Use this function as a fallback that always works.
-  func_fallback_echo ()
-  {
-    eval 'cat <<_LTECHO_EOF
-$[]1
-_LTECHO_EOF'
-  }
-  ECHO='func_fallback_echo'
-fi
-
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
-    $ECHO "$*"
-}
-
-case $ECHO in
-  printf*) AC_MSG_RESULT([printf]) ;;
-  print*) AC_MSG_RESULT([print -r]) ;;
-  *) AC_MSG_RESULT([cat]) ;;
-esac
-
-m4_ifdef([_AS_DETECT_SUGGESTED],
-[_AS_DETECT_SUGGESTED([
-  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
-    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-    PATH=/empty FPATH=/empty; export PATH FPATH
-    test "X`printf %s $ECHO`" = "X$ECHO" \
-      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
-
-_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
-_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
-])# _LT_PROG_ECHO_BACKSLASH
-
-
-# _LT_WITH_SYSROOT
-# ----------------
-AC_DEFUN([_LT_WITH_SYSROOT],
-[AC_MSG_CHECKING([for sysroot])
-AC_ARG_WITH([sysroot],
-[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
-  [Search for dependent libraries within DIR (or the compiler's sysroot
-   if not specified).])],
-[], [with_sysroot=no])
-
-dnl lt_sysroot will always be passed unquoted.  We quote it here
-dnl in case the user passed a directory name.
-lt_sysroot=
-case $with_sysroot in #(
- yes)
-   if test yes = "$GCC"; then
-     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
-   fi
-   ;; #(
- /*)
-   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
-   ;; #(
- no|'')
-   ;; #(
- *)
-   AC_MSG_RESULT([$with_sysroot])
-   AC_MSG_ERROR([The sysroot must be an absolute path.])
-   ;;
-esac
-
- AC_MSG_RESULT([${lt_sysroot:-no}])
-_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
-[dependent libraries, and where our libraries should be installed.])])
-
-# _LT_ENABLE_LOCK
-# ---------------
-m4_defun([_LT_ENABLE_LOCK],
-[AC_ARG_ENABLE([libtool-lock],
-  [AS_HELP_STRING([--disable-libtool-lock],
-    [avoid locking (might break parallel builds)])])
-test no = "$enable_libtool_lock" || enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-ia64-*-hpux*)
-  # Find out what ABI is being produced by ac_compile, and set mode
-  # options accordingly.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.$ac_objext` in
-      *ELF-32*)
-       HPUX_IA64_MODE=32
-       ;;
-      *ELF-64*)
-       HPUX_IA64_MODE=64
-       ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-*-*-irix6*)
-  # Find out what ABI is being produced by ac_compile, and set linker
-  # options accordingly.
-  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    if test yes = "$lt_cv_prog_gnu_ld"; then
-      case `/usr/bin/file conftest.$ac_objext` in
-       *32-bit*)
-         LD="${LD-ld} -melf32bsmip"
-         ;;
-       *N32*)
-         LD="${LD-ld} -melf32bmipn32"
-         ;;
-       *64-bit*)
-         LD="${LD-ld} -melf64bmip"
-       ;;
-      esac
-    else
-      case `/usr/bin/file conftest.$ac_objext` in
-       *32-bit*)
-         LD="${LD-ld} -32"
-         ;;
-       *N32*)
-         LD="${LD-ld} -n32"
-         ;;
-       *64-bit*)
-         LD="${LD-ld} -64"
-         ;;
-      esac
-    fi
-  fi
-  rm -rf conftest*
-  ;;
-
-mips64*-*linux*)
-  # Find out what ABI is being produced by ac_compile, and set linker
-  # options accordingly.
-  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    emul=elf
-    case `/usr/bin/file conftest.$ac_objext` in
-      *32-bit*)
-       emul="${emul}32"
-       ;;
-      *64-bit*)
-       emul="${emul}64"
-       ;;
-    esac
-    case `/usr/bin/file conftest.$ac_objext` in
-      *MSB*)
-       emul="${emul}btsmip"
-       ;;
-      *LSB*)
-       emul="${emul}ltsmip"
-       ;;
-    esac
-    case `/usr/bin/file conftest.$ac_objext` in
-      *N32*)
-       emul="${emul}n32"
-       ;;
-    esac
-    LD="${LD-ld} -m $emul"
-  fi
-  rm -rf conftest*
-  ;;
-
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
-  # Find out what ABI is being produced by ac_compile, and set linker
-  # options accordingly.  Note that the listed cases only cover the
-  # situations where additional linker options are needed (such as when
-  # doing 32-bit compilation for a host where ld defaults to 64-bit, or
-  # vice versa); the common cases where no linker options are needed do
-  # not appear in the list.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.o` in
-      *32-bit*)
-       case $host in
-         x86_64-*kfreebsd*-gnu)
-           LD="${LD-ld} -m elf_i386_fbsd"
-           ;;
-         x86_64-*linux*)
-           case `/usr/bin/file conftest.o` in
-             *x86-64*)
-               LD="${LD-ld} -m elf32_x86_64"
-               ;;
-             *)
-               LD="${LD-ld} -m elf_i386"
-               ;;
-           esac
-           ;;
-         powerpc64le-*linux*)
-           LD="${LD-ld} -m elf32lppclinux"
-           ;;
-         powerpc64-*linux*)
-           LD="${LD-ld} -m elf32ppclinux"
-           ;;
-         s390x-*linux*)
-           LD="${LD-ld} -m elf_s390"
-           ;;
-         sparc64-*linux*)
-           LD="${LD-ld} -m elf32_sparc"
-           ;;
-       esac
-       ;;
-      *64-bit*)
-       case $host in
-         x86_64-*kfreebsd*-gnu)
-           LD="${LD-ld} -m elf_x86_64_fbsd"
-           ;;
-         x86_64-*linux*)
-           LD="${LD-ld} -m elf_x86_64"
-           ;;
-         powerpcle-*linux*)
-           LD="${LD-ld} -m elf64lppc"
-           ;;
-         powerpc-*linux*)
-           LD="${LD-ld} -m elf64ppc"
-           ;;
-         s390*-*linux*|s390*-*tpf*)
-           LD="${LD-ld} -m elf64_s390"
-           ;;
-         sparc*-*linux*)
-           LD="${LD-ld} -m elf64_sparc"
-           ;;
-       esac
-       ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-
-*-*-sco3.2v5*)
-  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
-  SAVE_CFLAGS=$CFLAGS
-  CFLAGS="$CFLAGS -belf"
-  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
-    [AC_LANG_PUSH(C)
-     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
-     AC_LANG_POP])
-  if test yes != "$lt_cv_cc_needs_belf"; then
-    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
-    CFLAGS=$SAVE_CFLAGS
-  fi
-  ;;
-*-*solaris*)
-  # Find out what ABI is being produced by ac_compile, and set linker
-  # options accordingly.
-  echo 'int i;' > conftest.$ac_ext
-  if AC_TRY_EVAL(ac_compile); then
-    case `/usr/bin/file conftest.o` in
-    *64-bit*)
-      case $lt_cv_prog_gnu_ld in
-      yes*)
-        case $host in
-        i?86-*-solaris*|x86_64-*-solaris*)
-          LD="${LD-ld} -m elf_x86_64"
-          ;;
-        sparc*-*-solaris*)
-          LD="${LD-ld} -m elf64_sparc"
-          ;;
-        esac
-        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
-        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
-          LD=${LD-ld}_sol2
-        fi
-        ;;
-      *)
-       if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
-         LD="${LD-ld} -64"
-       fi
-       ;;
-      esac
-      ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-esac
-
-need_locks=$enable_libtool_lock
-])# _LT_ENABLE_LOCK
-
-
-# _LT_PROG_AR
-# -----------
-m4_defun([_LT_PROG_AR],
-[AC_CHECK_TOOLS(AR, [ar], false)
-: ${AR=ar}
-: ${AR_FLAGS=cru}
-_LT_DECL([], [AR], [1], [The archiver])
-_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
-
-AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
-  [lt_cv_ar_at_file=no
-   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
-     [echo conftest.$ac_objext > conftest.lst
-      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
-      AC_TRY_EVAL([lt_ar_try])
-      if test 0 -eq "$ac_status"; then
-       # Ensure the archiver fails upon bogus file names.
-       rm -f conftest.$ac_objext libconftest.a
-       AC_TRY_EVAL([lt_ar_try])
-       if test 0 -ne "$ac_status"; then
-          lt_cv_ar_at_file=@
-        fi
-      fi
-      rm -f conftest.* libconftest.a
-     ])
-  ])
-
-if test no = "$lt_cv_ar_at_file"; then
-  archiver_list_spec=
-else
-  archiver_list_spec=$lt_cv_ar_at_file
-fi
-_LT_DECL([], [archiver_list_spec], [1],
-  [How to feed a file listing to the archiver])
-])# _LT_PROG_AR
-
-
-# _LT_CMD_OLD_ARCHIVE
-# -------------------
-m4_defun([_LT_CMD_OLD_ARCHIVE],
-[_LT_PROG_AR
-
-AC_CHECK_TOOL(STRIP, strip, :)
-test -z "$STRIP" && STRIP=:
-_LT_DECL([], [STRIP], [1], [A symbol stripping program])
-
-AC_CHECK_TOOL(RANLIB, ranlib, :)
-test -z "$RANLIB" && RANLIB=:
-_LT_DECL([], [RANLIB], [1],
-    [Commands used to install an old-style archive])
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
-  case $host_os in
-  bitrig* | openbsd*)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
-    ;;
-  *)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
-    ;;
-  esac
-  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
-fi
-
-case $host_os in
-  darwin*)
-    lock_old_archive_extraction=yes ;;
-  *)
-    lock_old_archive_extraction=no ;;
-esac
-_LT_DECL([], [old_postinstall_cmds], [2])
-_LT_DECL([], [old_postuninstall_cmds], [2])
-_LT_TAGDECL([], [old_archive_cmds], [2],
-    [Commands used to build an old-style archive])
-_LT_DECL([], [lock_old_archive_extraction], [0],
-    [Whether to use a lock for old archive extraction])
-])# _LT_CMD_OLD_ARCHIVE
-
-
-# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-#              [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------------------
-# Check whether the given compiler option works
-AC_DEFUN([_LT_COMPILER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
-  [$2=no
-   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="$3"  ## exclude from sc_useless_quotes_in_assignment
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   # The option is referenced via a variable to avoid confusing sed.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
-   (eval "$lt_compile" 2>conftest.err)
-   ac_status=$?
-   cat conftest.err >&AS_MESSAGE_LOG_FD
-   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
-   if (exit $ac_status) && test -s "$ac_outfile"; then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings other than the usual output.
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
-     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
-       $2=yes
-     fi
-   fi
-   $RM conftest*
-])
-
-if test yes = "[$]$2"; then
-    m4_if([$5], , :, [$5])
-else
-    m4_if([$6], , :, [$6])
-fi
-])# _LT_COMPILER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
-
-
-# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-#                  [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------
-# Check whether the given linker option works
-AC_DEFUN([_LT_LINKER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
-  [$2=no
-   save_LDFLAGS=$LDFLAGS
-   LDFLAGS="$LDFLAGS $3"
-   echo "$lt_simple_link_test_code" > conftest.$ac_ext
-   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
-     # The linker can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     if test -s conftest.err; then
-       # Append any errors to the config.log.
-       cat conftest.err 1>&AS_MESSAGE_LOG_FD
-       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
-       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-       if diff conftest.exp conftest.er2 >/dev/null; then
-         $2=yes
-       fi
-     else
-       $2=yes
-     fi
-   fi
-   $RM -r conftest*
-   LDFLAGS=$save_LDFLAGS
-])
-
-if test yes = "[$]$2"; then
-    m4_if([$4], , :, [$4])
-else
-    m4_if([$5], , :, [$5])
-fi
-])# _LT_LINKER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
-
-
-# LT_CMD_MAX_LEN
-#---------------
-AC_DEFUN([LT_CMD_MAX_LEN],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-# find the maximum length of command line arguments
-AC_MSG_CHECKING([the maximum length of command line arguments])
-AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
-  i=0
-  teststring=ABCD
-
-  case $build_os in
-  msdosdjgpp*)
-    # On DJGPP, this test can blow up pretty badly due to problems in libc
-    # (any single argument exceeding 2000 bytes causes a buffer overrun
-    # during glob expansion).  Even if it were fixed, the result of this
-    # check would be larger than it should be.
-    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
-    ;;
-
-  gnu*)
-    # Under GNU Hurd, this test is not required because there is
-    # no limit to the length of command line arguments.
-    # Libtool will interpret -1 as no limit whatsoever
-    lt_cv_sys_max_cmd_len=-1;
-    ;;
-
-  cygwin* | mingw* | cegcc*)
-    # On Win9x/ME, this test blows up -- it succeeds, but takes
-    # about 5 minutes as the teststring grows exponentially.
-    # Worse, since 9x/ME are not pre-emptively multitasking,
-    # you end up with a "frozen" computer, even though with patience
-    # the test eventually succeeds (with a max line length of 256k).
-    # Instead, let's just punt: use the minimum linelength reported by
-    # all of the supported platforms: 8192 (on NT/2K/XP).
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  mint*)
-    # On MiNT this can take a long time and run out of memory.
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  amigaos*)
-    # On AmigaOS with pdksh, this test takes hours, literally.
-    # So we just punt and use a minimum line length of 8192.
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
-    # This has been around since 386BSD, at least.  Likely further.
-    if test -x /sbin/sysctl; then
-      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
-    elif test -x /usr/sbin/sysctl; then
-      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
-    else
-      lt_cv_sys_max_cmd_len=65536      # usable default for all BSDs
-    fi
-    # And add a safety zone
-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
-    ;;
-
-  interix*)
-    # We know the value 262144 and hardcode it with a safety zone (like BSD)
-    lt_cv_sys_max_cmd_len=196608
-    ;;
-
-  os2*)
-    # The test takes a long time on OS/2.
-    lt_cv_sys_max_cmd_len=8192
-    ;;
-
-  osf*)
-    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
-    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
-    # nice to cause kernel panics so lets avoid the loop below.
-    # First set a reasonable default.
-    lt_cv_sys_max_cmd_len=16384
-    #
-    if test -x /sbin/sysconfig; then
-      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
-        *1*) lt_cv_sys_max_cmd_len=-1 ;;
-      esac
-    fi
-    ;;
-  sco3.2v5*)
-    lt_cv_sys_max_cmd_len=102400
-    ;;
-  sysv5* | sco5v6* | sysv4.2uw2*)
-    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
-    if test -n "$kargmax"; then
-      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[        ]]//'`
-    else
-      lt_cv_sys_max_cmd_len=32768
-    fi
-    ;;
-  *)
-    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
-    if test -n "$lt_cv_sys_max_cmd_len" && \
-       test undefined != "$lt_cv_sys_max_cmd_len"; then
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
-    else
-      # Make teststring a little bigger before we do anything with it.
-      # a 1K string should be a reasonable start.
-      for i in 1 2 3 4 5 6 7 8; do
-        teststring=$teststring$teststring
-      done
-      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
-      # If test is not a shell built-in, we'll probably end up computing a
-      # maximum length that is only half of the actual maximum length, but
-      # we can't tell.
-      while { test X`env echo "$teststring$teststring" 2>/dev/null` \
-                = "X$teststring$teststring"; } >/dev/null 2>&1 &&
-             test 17 != "$i" # 1/2 MB should be enough
-      do
-        i=`expr $i + 1`
-        teststring=$teststring$teststring
-      done
-      # Only check the string length outside the loop.
-      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
-      teststring=
-      # Add a significant safety factor because C++ compilers can tack on
-      # massive amounts of additional arguments before passing them to the
-      # linker.  It appears as though 1/2 is a usable value.
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
-    fi
-    ;;
-  esac
-])
-if test -n "$lt_cv_sys_max_cmd_len"; then
-  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
-else
-  AC_MSG_RESULT(none)
-fi
-max_cmd_len=$lt_cv_sys_max_cmd_len
-_LT_DECL([], [max_cmd_len], [0],
-    [What is the maximum length of a command?])
-])# LT_CMD_MAX_LEN
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
-
-
-# _LT_HEADER_DLFCN
-# ----------------
-m4_defun([_LT_HEADER_DLFCN],
-[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
-])# _LT_HEADER_DLFCN
-
-
-# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
-#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ----------------------------------------------------------------
-m4_defun([_LT_TRY_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test yes = "$cross_compiling"; then :
-  [$4]
-else
-  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
-  lt_status=$lt_dlunknown
-  cat > conftest.$ac_ext <<_LT_EOF
-[#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-#  define LT_DLGLOBAL          RTLD_GLOBAL
-#else
-#  ifdef DL_GLOBAL
-#    define LT_DLGLOBAL                DL_GLOBAL
-#  else
-#    define LT_DLGLOBAL                0
-#  endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
-   find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-#  ifdef RTLD_LAZY
-#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
-#  else
-#    ifdef DL_LAZY
-#      define LT_DLLAZY_OR_NOW         DL_LAZY
-#    else
-#      ifdef RTLD_NOW
-#        define LT_DLLAZY_OR_NOW       RTLD_NOW
-#      else
-#        ifdef DL_NOW
-#          define LT_DLLAZY_OR_NOW     DL_NOW
-#        else
-#          define LT_DLLAZY_OR_NOW     0
-#        endif
-#      endif
-#    endif
-#  endif
-#endif
-
-/* When -fvisibility=hidden is used, assume the code has been annotated
-   correspondingly for the symbols needed.  */
-#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
-  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
-  int status = $lt_dlunknown;
-
-  if (self)
-    {
-      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
-      else
-        {
-         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
-          else puts (dlerror ());
-       }
-      /* dlclose (self); */
-    }
-  else
-    puts (dlerror ());
-
-  return status;
-}]
-_LT_EOF
-  if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
-    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
-    lt_status=$?
-    case x$lt_status in
-      x$lt_dlno_uscore) $1 ;;
-      x$lt_dlneed_uscore) $2 ;;
-      x$lt_dlunknown|x*) $3 ;;
-    esac
-  else :
-    # compilation failed
-    $3
-  fi
-fi
-rm -fr conftest*
-])# _LT_TRY_DLOPEN_SELF
-
-
-# LT_SYS_DLOPEN_SELF
-# ------------------
-AC_DEFUN([LT_SYS_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test yes != "$enable_dlopen"; then
-  enable_dlopen=unknown
-  enable_dlopen_self=unknown
-  enable_dlopen_self_static=unknown
-else
-  lt_cv_dlopen=no
-  lt_cv_dlopen_libs=
-
-  case $host_os in
-  beos*)
-    lt_cv_dlopen=load_add_on
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=yes
-    ;;
-
-  mingw* | pw32* | cegcc*)
-    lt_cv_dlopen=LoadLibrary
-    lt_cv_dlopen_libs=
-    ;;
-
-  cygwin*)
-    lt_cv_dlopen=dlopen
-    lt_cv_dlopen_libs=
-    ;;
-
-  darwin*)
-    # if libdl is installed we need to link against it
-    AC_CHECK_LIB([dl], [dlopen],
-               [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
-    lt_cv_dlopen=dyld
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=yes
-    ])
-    ;;
-
-  tpf*)
-    # Don't try to run any link tests for TPF.  We know it's impossible
-    # because TPF is a cross-compiler, and we know how we open DSOs.
-    lt_cv_dlopen=dlopen
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=no
-    ;;
-
-  *)
-    AC_CHECK_FUNC([shl_load],
-         [lt_cv_dlopen=shl_load],
-      [AC_CHECK_LIB([dld], [shl_load],
-           [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
-       [AC_CHECK_FUNC([dlopen],
-             [lt_cv_dlopen=dlopen],
-         [AC_CHECK_LIB([dl], [dlopen],
-               [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
-           [AC_CHECK_LIB([svld], [dlopen],
-                 [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
-             [AC_CHECK_LIB([dld], [dld_link],
-                   [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
-             ])
-           ])
-         ])
-       ])
-      ])
-    ;;
-  esac
-
-  if test no = "$lt_cv_dlopen"; then
-    enable_dlopen=no
-  else
-    enable_dlopen=yes
-  fi
-
-  case $lt_cv_dlopen in
-  dlopen)
-    save_CPPFLAGS=$CPPFLAGS
-    test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
-    save_LDFLAGS=$LDFLAGS
-    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
-    save_LIBS=$LIBS
-    LIBS="$lt_cv_dlopen_libs $LIBS"
-
-    AC_CACHE_CHECK([whether a program can dlopen itself],
-         lt_cv_dlopen_self, [dnl
-         _LT_TRY_DLOPEN_SELF(
-           lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
-           lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
-    ])
-
-    if test yes = "$lt_cv_dlopen_self"; then
-      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
-      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
-         lt_cv_dlopen_self_static, [dnl
-         _LT_TRY_DLOPEN_SELF(
-           lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
-           lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
-      ])
-    fi
-
-    CPPFLAGS=$save_CPPFLAGS
-    LDFLAGS=$save_LDFLAGS
-    LIBS=$save_LIBS
-    ;;
-  esac
-
-  case $lt_cv_dlopen_self in
-  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
-  *) enable_dlopen_self=unknown ;;
-  esac
-
-  case $lt_cv_dlopen_self_static in
-  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
-  *) enable_dlopen_self_static=unknown ;;
-  esac
-fi
-_LT_DECL([dlopen_support], [enable_dlopen], [0],
-        [Whether dlopen is supported])
-_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
-        [Whether dlopen of programs is supported])
-_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
-        [Whether dlopen of statically linked programs is supported])
-])# LT_SYS_DLOPEN_SELF
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
-
-
-# _LT_COMPILER_C_O([TAGNAME])
-# ---------------------------
-# Check to see if options -c and -o are simultaneously supported by compiler.
-# This macro does not hard code the compiler like AC_PROG_CC_C_O.
-m4_defun([_LT_COMPILER_C_O],
-[m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
-  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
-  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
-   $RM -r conftest 2>/dev/null
-   mkdir conftest
-   cd conftest
-   mkdir out
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-   lt_compiler_flag="-o out/conftest2.$ac_objext"
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
-   (eval "$lt_compile" 2>out/conftest.err)
-   ac_status=$?
-   cat out/conftest.err >&AS_MESSAGE_LOG_FD
-   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
-   if (exit $ac_status) && test -s out/conftest2.$ac_objext
-   then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
-     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
-     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
-       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
-     fi
-   fi
-   chmod u+w . 2>&AS_MESSAGE_LOG_FD
-   $RM conftest*
-   # SGI C++ compiler will create directory out/ii_files/ for
-   # template instantiation
-   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
-   $RM out/* && rmdir out
-   cd ..
-   $RM -r conftest
-   $RM conftest*
-])
-_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
-       [Does compiler simultaneously support -c and -o options?])
-])# _LT_COMPILER_C_O
-
-
-# _LT_COMPILER_FILE_LOCKS([TAGNAME])
-# ----------------------------------
-# Check to see if we can do hard links to lock some files if needed
-m4_defun([_LT_COMPILER_FILE_LOCKS],
-[m4_require([_LT_ENABLE_LOCK])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_COMPILER_C_O([$1])
-
-hard_links=nottested
-if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
-  # do not overwrite the value of need_locks provided by the user
-  AC_MSG_CHECKING([if we can lock with hard links])
-  hard_links=yes
-  $RM conftest*
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  touch conftest.a
-  ln conftest.a conftest.b 2>&5 || hard_links=no
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  AC_MSG_RESULT([$hard_links])
-  if test no = "$hard_links"; then
-    AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
-    need_locks=warn
-  fi
-else
-  need_locks=no
-fi
-_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
-])# _LT_COMPILER_FILE_LOCKS
-
-
-# _LT_CHECK_OBJDIR
-# ----------------
-m4_defun([_LT_CHECK_OBJDIR],
-[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
-[rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
-  lt_cv_objdir=.libs
-else
-  # MS-DOS does not allow filenames that begin with a dot.
-  lt_cv_objdir=_libs
-fi
-rmdir .libs 2>/dev/null])
-objdir=$lt_cv_objdir
-_LT_DECL([], [objdir], [0],
-         [The name of the directory that contains temporary libtool files])dnl
-m4_pattern_allow([LT_OBJDIR])dnl
-AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
-  [Define to the sub-directory where libtool stores uninstalled libraries.])
-])# _LT_CHECK_OBJDIR
-
-
-# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
-# --------------------------------------
-# Check hardcoding attributes.
-m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
-[AC_MSG_CHECKING([how to hardcode library paths into programs])
-_LT_TAGVAR(hardcode_action, $1)=
-if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
-   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
-   test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
-
-  # We can hardcode non-existent directories.
-  if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
-     # If the only mechanism to avoid hardcoding is shlibpath_var, we
-     # have to relink, otherwise we might link with an installed library
-     # when we should be linking with a yet-to-be-installed one
-     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
-     test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
-    # Linking always hardcodes the temporary library directory.
-    _LT_TAGVAR(hardcode_action, $1)=relink
-  else
-    # We can link without hardcoding, and we can hardcode nonexisting dirs.
-    _LT_TAGVAR(hardcode_action, $1)=immediate
-  fi
-else
-  # We cannot hardcode anything, or else we can only hardcode existing
-  # directories.
-  _LT_TAGVAR(hardcode_action, $1)=unsupported
-fi
-AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
-
-if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
-   test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
-  # Fast installation is not supported
-  enable_fast_install=no
-elif test yes = "$shlibpath_overrides_runpath" ||
-     test no = "$enable_shared"; then
-  # Fast installation is not necessary
-  enable_fast_install=needless
-fi
-_LT_TAGDECL([], [hardcode_action], [0],
-    [How to hardcode a shared library path into an executable])
-])# _LT_LINKER_HARDCODE_LIBPATH
-
-
-# _LT_CMD_STRIPLIB
-# ----------------
-m4_defun([_LT_CMD_STRIPLIB],
-[m4_require([_LT_DECL_EGREP])
-striplib=
-old_striplib=
-AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
-  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
-  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
-  AC_MSG_RESULT([yes])
-else
-# FIXME - insert some real tests, host_os isn't really good enough
-  case $host_os in
-  darwin*)
-    if test -n "$STRIP"; then
-      striplib="$STRIP -x"
-      old_striplib="$STRIP -S"
-      AC_MSG_RESULT([yes])
-    else
-      AC_MSG_RESULT([no])
-    fi
-    ;;
-  *)
-    AC_MSG_RESULT([no])
-    ;;
-  esac
-fi
-_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
-_LT_DECL([], [striplib], [1])
-])# _LT_CMD_STRIPLIB
-
-
-# _LT_PREPARE_MUNGE_PATH_LIST
-# ---------------------------
-# Make sure func_munge_path_list() is defined correctly.
-m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
-[[# func_munge_path_list VARIABLE PATH
-# -----------------------------------
-# VARIABLE is name of variable containing _space_ separated list of
-# directories to be munged by the contents of PATH, which is string
-# having a format:
-# "DIR[:DIR]:"
-#       string "DIR[ DIR]" will be prepended to VARIABLE
-# ":DIR[:DIR]"
-#       string "DIR[ DIR]" will be appended to VARIABLE
-# "DIRP[:DIRP]::[DIRA:]DIRA"
-#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
-#       "DIRA[ DIRA]" will be appended to VARIABLE
-# "DIR[:DIR]"
-#       VARIABLE will be replaced by "DIR[ DIR]"
-func_munge_path_list ()
-{
-    case x@S|@2 in
-    x)
-        ;;
-    *:)
-        eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
-        ;;
-    x:*)
-        eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
-        ;;
-    *::*)
-        eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
-        eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
-        ;;
-    *)
-        eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
-        ;;
-    esac
-}
-]])# _LT_PREPARE_PATH_LIST
-
-
-# _LT_SYS_DYNAMIC_LINKER([TAG])
-# -----------------------------
-# PORTME Fill in your ld.so characteristics
-m4_defun([_LT_SYS_DYNAMIC_LINKER],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_OBJDUMP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
-AC_MSG_CHECKING([dynamic linker characteristics])
-m4_if([$1],
-       [], [
-if test yes = "$GCC"; then
-  case $host_os in
-    darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
-    *) lt_awk_arg='/^libraries:/' ;;
-  esac
-  case $host_os in
-    mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
-    *) lt_sed_strip_eq='s|=/|/|g' ;;
-  esac
-  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
-  case $lt_search_path_spec in
-  *\;*)
-    # if the path contains ";" then we assume it to be the separator
-    # otherwise default to the standard path separator (i.e. ":") - it is
-    # assumed that no part of a normal pathname contains ";" but that should
-    # okay in the real world where ";" in dirpaths is itself problematic.
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
-    ;;
-  *)
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
-    ;;
-  esac
-  # Ok, now we have the path, separated by spaces, we can step through it
-  # and add multilib dir if necessary...
-  lt_tmp_lt_search_path_spec=
-  lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
-  # ...but if some path component already ends with the multilib dir we assume
-  # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
-  case "$lt_multi_os_dir; $lt_search_path_spec " in
-  "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
-    lt_multi_os_dir=
-    ;;
-  esac
-  for lt_sys_path in $lt_search_path_spec; do
-    if test -d "$lt_sys_path$lt_multi_os_dir"; then
-      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
-    elif test -n "$lt_multi_os_dir"; then
-      test -d "$lt_sys_path" && \
-       lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
-    fi
-  done
-  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS = " "; FS = "/|\n";} {
-  lt_foo = "";
-  lt_count = 0;
-  for (lt_i = NF; lt_i > 0; lt_i--) {
-    if ($lt_i != "" && $lt_i != ".") {
-      if ($lt_i == "..") {
-        lt_count++;
-      } else {
-        if (lt_count == 0) {
-          lt_foo = "/" $lt_i lt_foo;
-        } else {
-          lt_count--;
-        }
-      }
-    }
-  }
-  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
-  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
-}'`
-  # AWK program above erroneously prepends '/' to C:/dos/paths
-  # for these hosts.
-  case $host_os in
-    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
-      $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
-  esac
-  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
-else
-  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-fi])
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-shrext_cmds=.so
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-need_lib_prefix=unknown
-hardcode_into_libs=no
-
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-need_version=unknown
-
-AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
-[User-defined run-time library search path.])
-
-case $host_os in
-aix3*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
-  shlibpath_var=LIBPATH
-
-  # AIX 3 has no versioning support, so we append a major version to the name.
-  soname_spec='$libname$release$shared_ext$major'
-  ;;
-
-aix[[4-9]]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  hardcode_into_libs=yes
-  if test ia64 = "$host_cpu"; then
-    # AIX 5 supports IA64
-    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
-    shlibpath_var=LD_LIBRARY_PATH
-  else
-    # With GCC up to 2.95.x, collect2 would create an import file
-    # for dependence libraries.  The import file would start with
-    # the line '#! .'.  This would cause the generated library to
-    # depend on '.', always an invalid library.  This was fixed in
-    # development snapshots of GCC prior to 3.0.
-    case $host_os in
-      aix4 | aix4.[[01]] | aix4.[[01]].*)
-      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
-          echo ' yes '
-          echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
-       :
-      else
-       can_build_shared=no
-      fi
-      ;;
-    esac
-    # Using Import Files as archive members, it is possible to support
-    # filename-based versioning of shared library archives on AIX. While
-    # this would work for both with and without runtime linking, it will
-    # prevent static linking of such archives. So we do filename-based
-    # shared library versioning with .so extension only, which is used
-    # when both runtime linking and shared linking is enabled.
-    # Unfortunately, runtime linking may impact performance, so we do
-    # not want this to be the default eventually. Also, we use the
-    # versioned .so libs for executables only if there is the -brtl
-    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
-    # To allow for filename-based versioning support, we need to create
-    # libNAME.so.V as an archive file, containing:
-    # *) an Import File, referring to the versioned filename of the
-    #    archive as well as the shared archive member, telling the
-    #    bitwidth (32 or 64) of that shared object, and providing the
-    #    list of exported symbols of that shared object, eventually
-    #    decorated with the 'weak' keyword
-    # *) the shared object with the F_LOADONLY flag set, to really avoid
-    #    it being seen by the linker.
-    # At run time we better use the real file rather than another symlink,
-    # but for link time we create the symlink libNAME.so -> libNAME.so.V
-
-    case $with_aix_soname,$aix_use_runtimelinking in
-    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
-    # soname into executable. Probably we can add versioning support to
-    # collect2, so additional links can be useful in future.
-    aix,yes) # traditional libtool
-      dynamic_linker='AIX unversionable lib.so'
-      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
-      # instead of lib<name>.a to let people know that these are not
-      # typical AIX shared libraries.
-      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-      ;;
-    aix,no) # traditional AIX only
-      dynamic_linker='AIX lib.a[(]lib.so.V[)]'
-      # We preserve .a as extension for shared libraries through AIX4.2
-      # and later when we are not doing run time linking.
-      library_names_spec='$libname$release.a $libname.a'
-      soname_spec='$libname$release$shared_ext$major'
-      ;;
-    svr4,*) # full svr4 only
-      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
-      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
-      # We do not specify a path in Import Files, so LIBPATH fires.
-      shlibpath_overrides_runpath=yes
-      ;;
-    *,yes) # both, prefer svr4
-      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
-      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
-      # unpreferred sharedlib libNAME.a needs extra handling
-      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
-      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
-      # We do not specify a path in Import Files, so LIBPATH fires.
-      shlibpath_overrides_runpath=yes
-      ;;
-    *,no) # both, prefer aix
-      dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
-      library_names_spec='$libname$release.a $libname.a'
-      soname_spec='$libname$release$shared_ext$major'
-      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
-      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
-      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
-      ;;
-    esac
-    shlibpath_var=LIBPATH
-  fi
-  ;;
-
-amigaos*)
-  case $host_cpu in
-  powerpc)
-    # Since July 2007 AmigaOS4 officially supports .so libraries.
-    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    ;;
-  m68k)
-    library_names_spec='$libname.ixlibrary $libname.a'
-    # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
-    ;;
-  esac
-  ;;
-
-beos*)
-  library_names_spec='$libname$shared_ext'
-  dynamic_linker="$host_os ld.so"
-  shlibpath_var=LIBRARY_PATH
-  ;;
-
-bsdi[[45]]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
-  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
-  # the default ld.so.conf also contains /usr/contrib/lib and
-  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
-  # libtool to hard-code these into programs
-  ;;
-
-cygwin* | mingw* | pw32* | cegcc*)
-  version_type=windows
-  shrext_cmds=.dll
-  need_version=no
-  need_lib_prefix=no
-
-  case $GCC,$cc_basename in
-  yes,*)
-    # gcc
-    library_names_spec='$libname.dll.a'
-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \$file`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog $dir/$dlname \$dldir/$dlname~
-      chmod a+x \$dldir/$dlname~
-      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
-        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
-      fi'
-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $RM \$dlpath'
-    shlibpath_overrides_runpath=yes
-
-    case $host_os in
-    cygwin*)
-      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
-      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
-m4_if([$1], [],[
-      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
-      ;;
-    mingw* | cegcc*)
-      # MinGW DLLs use traditional 'lib' prefix
-      soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
-      ;;
-    pw32*)
-      # pw32 DLLs use 'pw' prefix rather than 'lib'
-      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
-      ;;
-    esac
-    dynamic_linker='Win32 ld.exe'
-    ;;
-
-  *,cl*)
-    # Native MSVC
-    libname_spec='$name'
-    soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
-    library_names_spec='$libname.dll.lib'
-
-    case $build_os in
-    mingw*)
-      sys_lib_search_path_spec=
-      lt_save_ifs=$IFS
-      IFS=';'
-      for lt_path in $LIB
-      do
-        IFS=$lt_save_ifs
-        # Let DOS variable expansion print the short 8.3 style file name.
-        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
-        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
-      done
-      IFS=$lt_save_ifs
-      # Convert to MSYS style.
-      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
-      ;;
-    cygwin*)
-      # Convert to unix form, then to dos form, then back to unix form
-      # but this time dos style (no spaces!) so that the unix form looks
-      # like /cygdrive/c/PROGRA~1:/cygdr...
-      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
-      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
-      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
-      ;;
-    *)
-      sys_lib_search_path_spec=$LIB
-      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
-        # It is most probably a Windows format PATH.
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
-      else
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
-      fi
-      # FIXME: find the short name or the path components, as spaces are
-      # common. (e.g. "Program Files" -> "PROGRA~1")
-      ;;
-    esac
-
-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \$file`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog $dir/$dlname \$dldir/$dlname'
-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $RM \$dlpath'
-    shlibpath_overrides_runpath=yes
-    dynamic_linker='Win32 link.exe'
-    ;;
-
-  *)
-    # Assume MSVC wrapper
-    library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
-    dynamic_linker='Win32 ld.exe'
-    ;;
-  esac
-  # FIXME: first we should search . and the directory the executable is in
-  shlibpath_var=PATH
-  ;;
-
-darwin* | rhapsody*)
-  dynamic_linker="$host_os dyld"
-  version_type=darwin
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
-  soname_spec='$libname$release$major$shared_ext'
-  shlibpath_overrides_runpath=yes
-  shlibpath_var=DYLD_LIBRARY_PATH
-  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
-m4_if([$1], [],[
-  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
-  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
-  ;;
-
-dgux*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-freebsd* | dragonfly*)
-  # DragonFly does not have aout.  When/if they implement a new
-  # versioning mechanism, adjust this.
-  if test -x /usr/bin/objformat; then
-    objformat=`/usr/bin/objformat`
-  else
-    case $host_os in
-    freebsd[[23]].*) objformat=aout ;;
-    *) objformat=elf ;;
-    esac
-  fi
-  version_type=freebsd-$objformat
-  case $version_type in
-    freebsd-elf*)
-      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-      soname_spec='$libname$release$shared_ext$major'
-      need_version=no
-      need_lib_prefix=no
-      ;;
-    freebsd-*)
-      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
-      need_version=yes
-      ;;
-  esac
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_os in
-  freebsd2.*)
-    shlibpath_overrides_runpath=yes
-    ;;
-  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
-    shlibpath_overrides_runpath=yes
-    hardcode_into_libs=yes
-    ;;
-  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
-  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
-    shlibpath_overrides_runpath=no
-    hardcode_into_libs=yes
-    ;;
-  *) # from 4.6 on, and DragonFly
-    shlibpath_overrides_runpath=yes
-    hardcode_into_libs=yes
-    ;;
-  esac
-  ;;
-
-haiku*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  dynamic_linker="$host_os runtime_loader"
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
-  hardcode_into_libs=yes
-  ;;
-
-hpux9* | hpux10* | hpux11*)
-  # Give a soname corresponding to the major version so that dld.sl refuses to
-  # link against other versions.
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  case $host_cpu in
-  ia64*)
-    shrext_cmds='.so'
-    hardcode_into_libs=yes
-    dynamic_linker="$host_os dld.so"
-    shlibpath_var=LD_LIBRARY_PATH
-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    soname_spec='$libname$release$shared_ext$major'
-    if test 32 = "$HPUX_IA64_MODE"; then
-      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
-      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
-    else
-      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
-      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
-    fi
-    ;;
-  hppa*64*)
-    shrext_cmds='.sl'
-    hardcode_into_libs=yes
-    dynamic_linker="$host_os dld.sl"
-    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    soname_spec='$libname$release$shared_ext$major'
-    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-    ;;
-  *)
-    shrext_cmds='.sl'
-    dynamic_linker="$host_os dld.sl"
-    shlibpath_var=SHLIB_PATH
-    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    soname_spec='$libname$release$shared_ext$major'
-    ;;
-  esac
-  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
-  postinstall_cmds='chmod 555 $lib'
-  # or fails outright, so override atomically:
-  install_override_mode=555
-  ;;
-
-interix[[3-9]]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
-irix5* | irix6* | nonstopux*)
-  case $host_os in
-    nonstopux*) version_type=nonstopux ;;
-    *)
-       if test yes = "$lt_cv_prog_gnu_ld"; then
-               version_type=linux # correct to gnu/linux during the next big refactor
-       else
-               version_type=irix
-       fi ;;
-  esac
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='$libname$release$shared_ext$major'
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
-  case $host_os in
-  irix5* | nonstopux*)
-    libsuff= shlibsuff=
-    ;;
-  *)
-    case $LD in # libtool.m4 will add one of these switches to LD
-    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
-      libsuff= shlibsuff= libmagic=32-bit;;
-    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
-      libsuff=32 shlibsuff=N32 libmagic=N32;;
-    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
-      libsuff=64 shlibsuff=64 libmagic=64-bit;;
-    *) libsuff= shlibsuff= libmagic=never-match;;
-    esac
-    ;;
-  esac
-  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
-  shlibpath_overrides_runpath=no
-  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
-  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
-  hardcode_into_libs=yes
-  ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux*oldld* | linux*aout* | linux*coff*)
-  dynamic_linker=no
-  ;;
-
-linux*android*)
-  version_type=none # Android doesn't support versioned libraries.
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext'
-  soname_spec='$libname$release$shared_ext'
-  finish_cmds=
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-
-  # This implies no fast_install, which is unacceptable.
-  # Some rework will be needed to allow for fast_install
-  # before this can be enabled.
-  hardcode_into_libs=yes
-
-  dynamic_linker='Android linker'
-  # Don't embed -rpath directories since the linker doesn't support them.
-  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-  ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-
-  # Some binutils ld are patched to set DT_RUNPATH
-  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
-    [lt_cv_shlibpath_overrides_runpath=no
-    save_LDFLAGS=$LDFLAGS
-    save_libdir=$libdir
-    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
-        LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
-      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
-        [lt_cv_shlibpath_overrides_runpath=yes])])
-    LDFLAGS=$save_LDFLAGS
-    libdir=$save_libdir
-    ])
-  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
-
-  # This implies no fast_install, which is unacceptable.
-  # Some rework will be needed to allow for fast_install
-  # before this can be enabled.
-  hardcode_into_libs=yes
-
-  # Ideally, we could use ldconfig to report *all* directores which are
-  # searched for libraries, however this is still not possible.  Aside from not
-  # being certain /sbin/ldconfig is available, command
-  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
-  # even though it is searched at run-time.  Try to do the best guess by
-  # appending ld.so.conf contents (and includes) to the search path.
-  if test -f /etc/ld.so.conf; then
-    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[  ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
-    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
-  fi
-
-  # We used to test for /lib/ld.so.1 and disable shared libraries on
-  # powerpc, because MkLinux only supported shared libraries with the
-  # GNU dynamic linker.  Since this was broken with cross compilers,
-  # most powerpc-linux boxes support dynamic linking these days and
-  # people can always --disable-shared, the test was removed, and we
-  # assume the GNU/Linux dynamic linker is in use.
-  dynamic_linker='GNU/Linux ld.so'
-  ;;
-
-netbsdelf*-gnu)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  dynamic_linker='NetBSD ld.elf_so'
-  ;;
-
-netbsd*)
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
-    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-    dynamic_linker='NetBSD (a.out) ld.so'
-  else
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    soname_spec='$libname$release$shared_ext$major'
-    dynamic_linker='NetBSD ld.elf_so'
-  fi
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  ;;
-
-newsos6)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  ;;
-
-*nto* | *qnx*)
-  version_type=qnx
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  dynamic_linker='ldqnx.so'
-  ;;
-
-openbsd* | bitrig*)
-  version_type=sunos
-  sys_lib_dlsearch_path_spec=/usr/lib
-  need_lib_prefix=no
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
-    need_version=no
-  else
-    need_version=yes
-  fi
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  ;;
-
-os2*)
-  libname_spec='$name'
-  version_type=windows
-  shrext_cmds=.dll
-  need_version=no
-  need_lib_prefix=no
-  # OS/2 can only load a DLL with a base name of 8 characters or less.
-  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
-    v=$($ECHO $release$versuffix | tr -d .-);
-    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
-    $ECHO $n$v`$shared_ext'
-  library_names_spec='${libname}_dll.$libext'
-  dynamic_linker='OS/2 ld.exe'
-  shlibpath_var=BEGINLIBPATH
-  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-  postinstall_cmds='base_file=`basename \$file`~
-    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
-    dldir=$destdir/`dirname \$dlpath`~
-    test -d \$dldir || mkdir -p \$dldir~
-    $install_prog $dir/$dlname \$dldir/$dlname~
-    chmod a+x \$dldir/$dlname~
-    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
-      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
-    fi'
-  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
-    dlpath=$dir/\$dldll~
-    $RM \$dlpath'
-  ;;
-
-osf3* | osf4* | osf5*)
-  version_type=osf
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='$libname$release$shared_ext$major'
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
-  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-  ;;
-
-rdos*)
-  dynamic_linker=no
-  ;;
-
-solaris*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  # ldd complains unless libraries are executable
-  postinstall_cmds='chmod +x $lib'
-  ;;
-
-sunos4*)
-  version_type=sunos
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
-  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  if test yes = "$with_gnu_ld"; then
-    need_lib_prefix=no
-  fi
-  need_version=yes
-  ;;
-
-sysv4 | sysv4.3*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_vendor in
-    sni)
-      shlibpath_overrides_runpath=no
-      need_lib_prefix=no
-      runpath_var=LD_RUN_PATH
-      ;;
-    siemens)
-      need_lib_prefix=no
-      ;;
-    motorola)
-      need_lib_prefix=no
-      need_version=no
-      shlibpath_overrides_runpath=no
-      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
-      ;;
-  esac
-  ;;
-
-sysv4*MP*)
-  if test -d /usr/nec; then
-    version_type=linux # correct to gnu/linux during the next big refactor
-    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
-    soname_spec='$libname$shared_ext.$major'
-    shlibpath_var=LD_LIBRARY_PATH
-  fi
-  ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  version_type=sco
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  if test yes = "$with_gnu_ld"; then
-    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
-  else
-    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
-    case $host_os in
-      sco3.2v5*)
-        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
-       ;;
-    esac
-  fi
-  sys_lib_dlsearch_path_spec='/usr/lib'
-  ;;
-
-tpf*)
-  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
-uts4*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-*)
-  dynamic_linker=no
-  ;;
-esac
-AC_MSG_RESULT([$dynamic_linker])
-test no = "$dynamic_linker" && can_build_shared=no
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test yes = "$GCC"; then
-  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
-  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
-fi
-
-if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
-  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
-fi
-
-# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
-configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
-
-# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
-func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
-
-# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
-configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
-
-_LT_DECL([], [variables_saved_for_relink], [1],
-    [Variables whose values should be saved in libtool wrapper scripts and
-    restored at link time])
-_LT_DECL([], [need_lib_prefix], [0],
-    [Do we need the "lib" prefix for modules?])
-_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
-_LT_DECL([], [version_type], [0], [Library versioning type])
-_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
-_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
-_LT_DECL([], [shlibpath_overrides_runpath], [0],
-    [Is shlibpath searched before the hard-coded library search path?])
-_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
-_LT_DECL([], [library_names_spec], [1],
-    [[List of archive names.  First name is the real one, the rest are links.
-    The last name is the one that the linker finds with -lNAME]])
-_LT_DECL([], [soname_spec], [1],
-    [[The coded name of the library, if different from the real name]])
-_LT_DECL([], [install_override_mode], [1],
-    [Permission mode override for installation of shared libraries])
-_LT_DECL([], [postinstall_cmds], [2],
-    [Command to use after installation of a shared archive])
-_LT_DECL([], [postuninstall_cmds], [2],
-    [Command to use after uninstallation of a shared archive])
-_LT_DECL([], [finish_cmds], [2],
-    [Commands used to finish a libtool library installation in a directory])
-_LT_DECL([], [finish_eval], [1],
-    [[As "finish_cmds", except a single script fragment to be evaled but
-    not shown]])
-_LT_DECL([], [hardcode_into_libs], [0],
-    [Whether we should hardcode library paths into libraries])
-_LT_DECL([], [sys_lib_search_path_spec], [2],
-    [Compile-time system search path for libraries])
-_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
-    [Detected run-time system search path for libraries])
-_LT_DECL([], [configure_time_lt_sys_library_path], [2],
-    [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
-])# _LT_SYS_DYNAMIC_LINKER
-
-
-# _LT_PATH_TOOL_PREFIX(TOOL)
-# --------------------------
-# find a file program that can recognize shared library
-AC_DEFUN([_LT_PATH_TOOL_PREFIX],
-[m4_require([_LT_DECL_EGREP])dnl
-AC_MSG_CHECKING([for $1])
-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
-[case $MAGIC_CMD in
-[[\\/*] |  ?:[\\/]*])
-  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
-  ;;
-*)
-  lt_save_MAGIC_CMD=$MAGIC_CMD
-  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
-dnl $ac_dummy forces splitting on constant user-supplied paths.
-dnl POSIX.2 word splitting is done only on the output of word expansions,
-dnl not every word.  This closes a longstanding sh security hole.
-  ac_dummy="m4_if([$2], , $PATH, [$2])"
-  for ac_dir in $ac_dummy; do
-    IFS=$lt_save_ifs
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/$1"; then
-      lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
-      if test -n "$file_magic_test_file"; then
-       case $deplibs_check_method in
-       "file_magic "*)
-         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
-         MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
-           $EGREP "$file_magic_regex" > /dev/null; then
-           :
-         else
-           cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such.  This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem.  Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
-         fi ;;
-       esac
-      fi
-      break
-    fi
-  done
-  IFS=$lt_save_ifs
-  MAGIC_CMD=$lt_save_MAGIC_CMD
-  ;;
-esac])
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
-  AC_MSG_RESULT($MAGIC_CMD)
-else
-  AC_MSG_RESULT(no)
-fi
-_LT_DECL([], [MAGIC_CMD], [0],
-        [Used to examine libraries when file_magic_cmd begins with "file"])dnl
-])# _LT_PATH_TOOL_PREFIX
-
-# Old name:
-AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
-
-
-# _LT_PATH_MAGIC
-# --------------
-# find a file program that can recognize a shared library
-m4_defun([_LT_PATH_MAGIC],
-[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
-if test -z "$lt_cv_path_MAGIC_CMD"; then
-  if test -n "$ac_tool_prefix"; then
-    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
-  else
-    MAGIC_CMD=:
-  fi
-fi
-])# _LT_PATH_MAGIC
-
-
-# LT_PATH_LD
-# ----------
-# find the pathname to the GNU or non-GNU linker
-AC_DEFUN([LT_PATH_LD],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
-
-AC_ARG_WITH([gnu-ld],
-    [AS_HELP_STRING([--with-gnu-ld],
-       [assume the C compiler uses GNU ld @<:@default=no@:>@])],
-    [test no = "$withval" || with_gnu_ld=yes],
-    [with_gnu_ld=no])dnl
-
-ac_prog=ld
-if test yes = "$GCC"; then
-  # Check if gcc -print-prog-name=ld gives a path.
-  AC_MSG_CHECKING([for ld used by $CC])
-  case $host in
-  *-*-mingw*)
-    # gcc leaves a trailing carriage return, which upsets mingw
-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
-  *)
-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
-  esac
-  case $ac_prog in
-    # Accept absolute paths.
-    [[\\/]]* | ?:[[\\/]]*)
-      re_direlt='/[[^/]][[^/]]*/\.\./'
-      # Canonicalize the pathname of ld
-      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
-      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
-       ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
-      done
-      test -z "$LD" && LD=$ac_prog
-      ;;
-  "")
-    # If it fails, then pretend we aren't using GCC.
-    ac_prog=ld
-    ;;
-  *)
-    # If it is relative, then search for the first ld in PATH.
-    with_gnu_ld=unknown
-    ;;
-  esac
-elif test yes = "$with_gnu_ld"; then
-  AC_MSG_CHECKING([for GNU ld])
-else
-  AC_MSG_CHECKING([for non-GNU ld])
-fi
-AC_CACHE_VAL(lt_cv_path_LD,
-[if test -z "$LD"; then
-  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
-  for ac_dir in $PATH; do
-    IFS=$lt_save_ifs
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD=$ac_dir/$ac_prog
-      # Check to see if the program is GNU ld.  I'd rather use --version,
-      # but apparently some variants of GNU ld only accept -v.
-      # Break only if it was the GNU/non-GNU ld that we prefer.
-      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
-      *GNU* | *'with BFD'*)
-       test no != "$with_gnu_ld" && break
-       ;;
-      *)
-       test yes != "$with_gnu_ld" && break
-       ;;
-      esac
-    fi
-  done
-  IFS=$lt_save_ifs
-else
-  lt_cv_path_LD=$LD # Let the user override the test with a path.
-fi])
-LD=$lt_cv_path_LD
-if test -n "$LD"; then
-  AC_MSG_RESULT($LD)
-else
-  AC_MSG_RESULT(no)
-fi
-test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
-_LT_PATH_LD_GNU
-AC_SUBST([LD])
-
-_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
-])# LT_PATH_LD
-
-# Old names:
-AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
-AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_LD], [])
-dnl AC_DEFUN([AC_PROG_LD], [])
-
-
-# _LT_PATH_LD_GNU
-#- --------------
-m4_defun([_LT_PATH_LD_GNU],
-[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
-[# I'd rather use --version here, but apparently some GNU lds only accept -v.
-case `$LD -v 2>&1 </dev/null` in
-*GNU* | *'with BFD'*)
-  lt_cv_prog_gnu_ld=yes
-  ;;
-*)
-  lt_cv_prog_gnu_ld=no
-  ;;
-esac])
-with_gnu_ld=$lt_cv_prog_gnu_ld
-])# _LT_PATH_LD_GNU
-
-
-# _LT_CMD_RELOAD
-# --------------
-# find reload flag for linker
-#   -- PORTME Some linkers may need a different reload flag.
-m4_defun([_LT_CMD_RELOAD],
-[AC_CACHE_CHECK([for $LD option to reload object files],
-  lt_cv_ld_reload_flag,
-  [lt_cv_ld_reload_flag='-r'])
-reload_flag=$lt_cv_ld_reload_flag
-case $reload_flag in
-"" | " "*) ;;
-*) reload_flag=" $reload_flag" ;;
-esac
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    if test yes != "$GCC"; then
-      reload_cmds=false
-    fi
-    ;;
-  darwin*)
-    if test yes = "$GCC"; then
-      reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
-    else
-      reload_cmds='$LD$reload_flag -o $output$reload_objs'
-    fi
-    ;;
-esac
-_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
-_LT_TAGDECL([], [reload_cmds], [2])dnl
-])# _LT_CMD_RELOAD
-
-
-# _LT_PATH_DD
-# -----------
-# find a working dd
-m4_defun([_LT_PATH_DD],
-[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
-[printf 0123456789abcdef0123456789abcdef >conftest.i
-cat conftest.i conftest.i >conftest2.i
-: ${lt_DD:=$DD}
-AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
-[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
-  cmp -s conftest.i conftest.out \
-  && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
-fi])
-rm -f conftest.i conftest2.i conftest.out])
-])# _LT_PATH_DD
-
-
-# _LT_CMD_TRUNCATE
-# ----------------
-# find command to truncate a binary pipe
-m4_defun([_LT_CMD_TRUNCATE],
-[m4_require([_LT_PATH_DD])
-AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
-[printf 0123456789abcdef0123456789abcdef >conftest.i
-cat conftest.i conftest.i >conftest2.i
-lt_cv_truncate_bin=
-if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
-  cmp -s conftest.i conftest.out \
-  && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
-fi
-rm -f conftest.i conftest2.i conftest.out
-test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
-_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
-  [Command to truncate a binary pipe])
-])# _LT_CMD_TRUNCATE
-
-
-# _LT_CHECK_MAGIC_METHOD
-# ----------------------
-# how to check for library dependencies
-#  -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_MAGIC_METHOD],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-AC_CACHE_CHECK([how to recognize dependent libraries],
-lt_cv_deplibs_check_method,
-[lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# 'unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# that responds to the $file_magic_cmd with a given extended regex.
-# If you have 'file' or equivalent on your system and you're not sure
-# whether 'pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix[[4-9]]*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-beos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-bsdi[[45]]*)
-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
-  lt_cv_file_magic_cmd='/usr/bin/file -L'
-  lt_cv_file_magic_test_file=/shlib/libc.so
-  ;;
-
-cygwin*)
-  # func_win32_libid is a shell function defined in ltmain.sh
-  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
-  lt_cv_file_magic_cmd='func_win32_libid'
-  ;;
-
-mingw* | pw32*)
-  # Base MSYS/MinGW do not provide the 'file' command needed by
-  # func_win32_libid shell function, so use a weaker test based on 'objdump',
-  # unless we find 'file', for example because we are cross-compiling.
-  if ( file / ) >/dev/null 2>&1; then
-    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
-    lt_cv_file_magic_cmd='func_win32_libid'
-  else
-    # Keep this pattern in sync with the one in func_win32_libid.
-    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
-    lt_cv_file_magic_cmd='$OBJDUMP -f'
-  fi
-  ;;
-
-cegcc*)
-  # use the weaker test based on 'objdump'. See mingw*.
-  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
-  lt_cv_file_magic_cmd='$OBJDUMP -f'
-  ;;
-
-darwin* | rhapsody*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-freebsd* | dragonfly*)
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
-    case $host_cpu in
-    i*86 )
-      # Not sure whether the presence of OpenBSD here was a mistake.
-      # Let's accept both of them until this is cleared up.
-      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
-      lt_cv_file_magic_cmd=/usr/bin/file
-      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
-      ;;
-    esac
-  else
-    lt_cv_deplibs_check_method=pass_all
-  fi
-  ;;
-
-haiku*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-hpux10.20* | hpux11*)
-  lt_cv_file_magic_cmd=/usr/bin/file
-  case $host_cpu in
-  ia64*)
-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
-    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
-    ;;
-  hppa*64*)
-    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
-    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
-    ;;
-  *)
-    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
-    lt_cv_file_magic_test_file=/usr/lib/libc.sl
-    ;;
-  esac
-  ;;
-
-interix[[3-9]]*)
-  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
-  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
-  ;;
-
-irix5* | irix6* | nonstopux*)
-  case $LD in
-  *-32|*"-32 ") libmagic=32-bit;;
-  *-n32|*"-n32 ") libmagic=N32;;
-  *-64|*"-64 ") libmagic=64-bit;;
-  *) libmagic=never-match;;
-  esac
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-netbsd* | netbsdelf*-gnu)
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
-  fi
-  ;;
-
-newos6*)
-  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
-  lt_cv_file_magic_cmd=/usr/bin/file
-  lt_cv_file_magic_test_file=/usr/lib/libnls.so
-  ;;
-
-*nto* | *qnx*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-openbsd* | bitrig*)
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
-  fi
-  ;;
-
-osf3* | osf4* | osf5*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-rdos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-solaris*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-sysv4 | sysv4.3*)
-  case $host_vendor in
-  motorola)
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
-    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
-    ;;
-  ncr)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  sequent)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
-    ;;
-  sni)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
-    lt_cv_file_magic_test_file=/lib/libc.so
-    ;;
-  siemens)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  pc)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  esac
-  ;;
-
-tpf*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-os2*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-esac
-])
-
-file_magic_glob=
-want_nocaseglob=no
-if test "$build" = "$host"; then
-  case $host_os in
-  mingw* | pw32*)
-    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
-      want_nocaseglob=yes
-    else
-      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
-    fi
-    ;;
-  esac
-fi
-
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-_LT_DECL([], [deplibs_check_method], [1],
-    [Method to check whether dependent libraries are shared objects])
-_LT_DECL([], [file_magic_cmd], [1],
-    [Command to use when deplibs_check_method = "file_magic"])
-_LT_DECL([], [file_magic_glob], [1],
-    [How to find potential files when deplibs_check_method = "file_magic"])
-_LT_DECL([], [want_nocaseglob], [1],
-    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
-])# _LT_CHECK_MAGIC_METHOD
-
-
-# LT_PATH_NM
-# ----------
-# find the pathname to a BSD- or MS-compatible name lister
-AC_DEFUN([LT_PATH_NM],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
-[if test -n "$NM"; then
-  # Let the user override the test.
-  lt_cv_path_NM=$NM
-else
-  lt_nm_to_check=${ac_tool_prefix}nm
-  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
-    lt_nm_to_check="$lt_nm_to_check nm"
-  fi
-  for lt_tmp_nm in $lt_nm_to_check; do
-    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
-    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
-      IFS=$lt_save_ifs
-      test -z "$ac_dir" && ac_dir=.
-      tmp_nm=$ac_dir/$lt_tmp_nm
-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
-       # Check to see if the nm accepts a BSD-compat flag.
-       # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
-       #   nm: unknown option "B" ignored
-       # Tru64's nm complains that /dev/null is an invalid object file
-       # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
-       case $build_os in
-       mingw*) lt_bad_file=conftest.nm/nofile ;;
-       *) lt_bad_file=/dev/null ;;
-       esac
-       case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
-       *$lt_bad_file* | *'Invalid file or object type'*)
-         lt_cv_path_NM="$tmp_nm -B"
-         break 2
-         ;;
-       *)
-         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
-         */dev/null*)
-           lt_cv_path_NM="$tmp_nm -p"
-           break 2
-           ;;
-         *)
-           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
-           continue # so that we can try to find one that supports BSD flags
-           ;;
-         esac
-         ;;
-       esac
-      fi
-    done
-    IFS=$lt_save_ifs
-  done
-  : ${lt_cv_path_NM=no}
-fi])
-if test no != "$lt_cv_path_NM"; then
-  NM=$lt_cv_path_NM
-else
-  # Didn't find any BSD compatible name lister, look for dumpbin.
-  if test -n "$DUMPBIN"; then :
-    # Let the user override the test.
-  else
-    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
-    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
-    *COFF*)
-      DUMPBIN="$DUMPBIN -symbols -headers"
-      ;;
-    *)
-      DUMPBIN=:
-      ;;
-    esac
-  fi
-  AC_SUBST([DUMPBIN])
-  if test : != "$DUMPBIN"; then
-    NM=$DUMPBIN
-  fi
-fi
-test -z "$NM" && NM=nm
-AC_SUBST([NM])
-_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
-
-AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
-  [lt_cv_nm_interface="BSD nm"
-  echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
-  (eval "$ac_compile" 2>conftest.err)
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
-  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
-  cat conftest.out >&AS_MESSAGE_LOG_FD
-  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
-    lt_cv_nm_interface="MS dumpbin"
-  fi
-  rm -f conftest*])
-])# LT_PATH_NM
-
-# Old names:
-AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
-AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_NM], [])
-dnl AC_DEFUN([AC_PROG_NM], [])
-
-# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-# --------------------------------
-# how to determine the name of the shared library
-# associated with a specific link library.
-#  -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-m4_require([_LT_DECL_DLLTOOL])
-AC_CACHE_CHECK([how to associate runtime and link libraries],
-lt_cv_sharedlib_from_linklib_cmd,
-[lt_cv_sharedlib_from_linklib_cmd='unknown'
-
-case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
-  # two different shell functions defined in ltmain.sh;
-  # decide which one to use based on capabilities of $DLLTOOL
-  case `$DLLTOOL --help 2>&1` in
-  *--identify-strict*)
-    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
-    ;;
-  *)
-    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
-    ;;
-  esac
-  ;;
-*)
-  # fallback: assume linklib IS sharedlib
-  lt_cv_sharedlib_from_linklib_cmd=$ECHO
-  ;;
-esac
-])
-sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
-test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
-_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
-    [Command to associate shared and link libraries])
-])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-
-
-# _LT_PATH_MANIFEST_TOOL
-# ----------------------
-# locate the manifest tool
-m4_defun([_LT_PATH_MANIFEST_TOOL],
-[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
-test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
-  [lt_cv_path_mainfest_tool=no
-  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
-  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
-  cat conftest.err >&AS_MESSAGE_LOG_FD
-  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
-    lt_cv_path_mainfest_tool=yes
-  fi
-  rm -f conftest*])
-if test yes != "$lt_cv_path_mainfest_tool"; then
-  MANIFEST_TOOL=:
-fi
-_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
-])# _LT_PATH_MANIFEST_TOOL
-
-
-# _LT_DLL_DEF_P([FILE])
-# ---------------------
-# True iff FILE is a Windows DLL '.def' file.
-# Keep in sync with func_dll_def_p in the libtool script
-AC_DEFUN([_LT_DLL_DEF_P],
-[dnl
-  test DEF = "`$SED -n dnl
-    -e '\''s/^[[        ]]*//'\'' dnl Strip leading whitespace
-    -e '\''/^\(;.*\)*$/d'\'' dnl      Delete empty lines and comments
-    -e '\''s/^\(EXPORTS\|LIBRARY\)\([[  ]].*\)*$/DEF/p'\'' dnl
-    -e q dnl                          Only consider the first "real" line
-    $1`" dnl
-])# _LT_DLL_DEF_P
-
-
-# LT_LIB_M
-# --------
-# check for math library
-AC_DEFUN([LT_LIB_M],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case $host in
-*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
-  # These system don't have libm, or don't need it
-  ;;
-*-ncr-sysv4.3*)
-  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
-  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
-  ;;
-*)
-  AC_CHECK_LIB(m, cos, LIBM=-lm)
-  ;;
-esac
-AC_SUBST([LIBM])
-])# LT_LIB_M
-
-# Old name:
-AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_CHECK_LIBM], [])
-
-
-# _LT_COMPILER_NO_RTTI([TAGNAME])
-# -------------------------------
-m4_defun([_LT_COMPILER_NO_RTTI],
-[m4_require([_LT_TAG_COMPILER])dnl
-
-_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-
-if test yes = "$GCC"; then
-  case $cc_basename in
-  nvcc*)
-    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
-  *)
-    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
-  esac
-
-  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
-    lt_cv_prog_compiler_rtti_exceptions,
-    [-fno-rtti -fno-exceptions], [],
-    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
-fi
-_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
-       [Compiler flag to turn off builtin functions])
-])# _LT_COMPILER_NO_RTTI
-
-
-# _LT_CMD_GLOBAL_SYMBOLS
-# ----------------------
-m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_PROG_AWK])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-AC_MSG_CHECKING([command to parse $NM output from $compiler object])
-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
-[
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[[BCDEGRST]]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
-
-# Define system-specific variables.
-case $host_os in
-aix*)
-  symcode='[[BCDT]]'
-  ;;
-cygwin* | mingw* | pw32* | cegcc*)
-  symcode='[[ABCDGISTW]]'
-  ;;
-hpux*)
-  if test ia64 = "$host_cpu"; then
-    symcode='[[ABCDEGRST]]'
-  fi
-  ;;
-irix* | nonstopux*)
-  symcode='[[BCDEGRST]]'
-  ;;
-osf*)
-  symcode='[[BCDEGQRST]]'
-  ;;
-solaris*)
-  symcode='[[BDRT]]'
-  ;;
-sco3.2v5*)
-  symcode='[[DT]]'
-  ;;
-sysv4.2uw2*)
-  symcode='[[DT]]'
-  ;;
-sysv5* | sco5v6* | unixware* | OpenUNIX*)
-  symcode='[[ABDT]]'
-  ;;
-sysv4)
-  symcode='[[DFNSTU]]'
-  ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-case `$NM -V 2>&1` in
-*GNU* | *'with BFD'*)
-  symcode='[[ABCDGIRSTW]]' ;;
-esac
-
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-  # Gets list of data symbols to import.
-  lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
-  # Adjust the below global symbol transforms to fixup imported variables.
-  lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
-  lt_c_name_hook=" -e 's/^I .* \(.*\)$/  {\"\1\", (void *) 0},/p'"
-  lt_c_name_lib_hook="\
-  -e 's/^I .* \(lib.*\)$/  {\"\1\", (void *) 0},/p'\
-  -e 's/^I .* \(.*\)$/  {\"lib\1\", (void *) 0},/p'"
-else
-  # Disable hooks by default.
-  lt_cv_sys_global_symbol_to_import=
-  lt_cdecl_hook=
-  lt_c_name_hook=
-  lt_c_name_lib_hook=
-fi
-
-# Transform an extracted symbol line into a proper C declaration.
-# Some systems (esp. on ia64) link data and code symbols differently,
-# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n"\
-$lt_cdecl_hook\
-" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
-$lt_c_name_hook\
-" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/p'"
-
-# Transform an extracted symbol line into symbol name with lib prefix and
-# symbol address.
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
-$lt_c_name_lib_hook\
-" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
-" -e 's/^$symcode$symcode* .* \(lib.*\)$/  {\"\1\", (void *) \&\1},/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"lib\1\", (void *) \&\1},/p'"
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $build_os in
-mingw*)
-  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
-  ;;
-esac
-
-# Try without a prefix underscore, then with it.
-for ac_symprfx in "" "_"; do
-
-  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
-  symxfrm="\\1 $ac_symprfx\\2 \\2"
-
-  # Write the raw and C identifiers.
-  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-    # Fake it for dumpbin and say T for any non-static function,
-    # D for any global variable and I for any imported variable.
-    # Also find C++ and __fastcall symbols from MSVC++,
-    # which start with @ or ?.
-    lt_cv_sys_global_symbol_pipe="$AWK ['"\
-"     {last_section=section; section=\$ 3};"\
-"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
-"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
-"     /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
-"     /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
-"     /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
-"     \$ 0!~/External *\|/{next};"\
-"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
-"     {if(hide[section]) next};"\
-"     {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
-"     {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
-"     s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
-"     s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
-"     ' prfx=^$ac_symprfx]"
-  else
-    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[    ]]\($symcode$symcode*\)[[       ]][[    ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
-  fi
-  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
-
-  # Check to see that the pipe works correctly.
-  pipe_works=no
-
-  rm -f conftest*
-  cat > conftest.$ac_ext <<_LT_EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(void);
-void nm_test_func(void){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-_LT_EOF
-
-  if AC_TRY_EVAL(ac_compile); then
-    # Now try to grab the symbols.
-    nlist=conftest.nm
-    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
-      # Try sorting and uniquifying the output.
-      if sort "$nlist" | uniq > "$nlist"T; then
-       mv -f "$nlist"T "$nlist"
-      else
-       rm -f "$nlist"T
-      fi
-
-      # Make sure that we snagged all the symbols we need.
-      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
-       if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
-         cat <<_LT_EOF > conftest.$ac_ext
-/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
-#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
-/* DATA imports from DLLs on WIN32 can't be const, because runtime
-   relocations are performed -- see ld's documentation on pseudo-relocs.  */
-# define LT@&t@_DLSYM_CONST
-#elif defined __osf__
-/* This system does not cope well with relocations in const data.  */
-# define LT@&t@_DLSYM_CONST
-#else
-# define LT@&t@_DLSYM_CONST const
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-_LT_EOF
-         # Now generate the symbol file.
-         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
-
-         cat <<_LT_EOF >> conftest.$ac_ext
-
-/* The mapping between symbol names and symbols.  */
-LT@&t@_DLSYM_CONST struct {
-  const char *name;
-  void       *address;
-}
-lt__PROGRAM__LTX_preloaded_symbols[[]] =
-{
-  { "@PROGRAM@", (void *) 0 },
-_LT_EOF
-         $SED "s/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
-         cat <<\_LT_EOF >> conftest.$ac_ext
-  {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
-  return lt__PROGRAM__LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-_LT_EOF
-         # Now try linking the two files.
-         mv conftest.$ac_objext conftstm.$ac_objext
-         lt_globsym_save_LIBS=$LIBS
-         lt_globsym_save_CFLAGS=$CFLAGS
-         LIBS=conftstm.$ac_objext
-         CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
-         if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
-           pipe_works=yes
-         fi
-         LIBS=$lt_globsym_save_LIBS
-         CFLAGS=$lt_globsym_save_CFLAGS
-       else
-         echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
-       fi
-      else
-       echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
-      fi
-    else
-      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
-    fi
-  else
-    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
-    cat conftest.$ac_ext >&5
-  fi
-  rm -rf conftest* conftst*
-
-  # Do not use the global_symbol_pipe unless it works.
-  if test yes = "$pipe_works"; then
-    break
-  else
-    lt_cv_sys_global_symbol_pipe=
-  fi
-done
-])
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
-  lt_cv_sys_global_symbol_to_cdecl=
-fi
-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
-  AC_MSG_RESULT(failed)
-else
-  AC_MSG_RESULT(ok)
-fi
-
-# Response file support.
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-  nm_file_list_spec='@'
-elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
-  nm_file_list_spec='@'
-fi
-
-_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
-    [Take the output of nm and produce a listing of raw symbols and C names])
-_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
-    [Transform the output of nm in a proper C declaration])
-_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
-    [Transform the output of nm into a list of symbols to manually relocate])
-_LT_DECL([global_symbol_to_c_name_address],
-    [lt_cv_sys_global_symbol_to_c_name_address], [1],
-    [Transform the output of nm in a C name address pair])
-_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
-    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
-    [Transform the output of nm in a C name address pair when lib prefix is needed])
-_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
-    [The name lister interface])
-_LT_DECL([], [nm_file_list_spec], [1],
-    [Specify filename containing input files for $NM])
-]) # _LT_CMD_GLOBAL_SYMBOLS
-
-
-# _LT_COMPILER_PIC([TAGNAME])
-# ---------------------------
-m4_defun([_LT_COMPILER_PIC],
-[m4_require([_LT_TAG_COMPILER])dnl
-_LT_TAGVAR(lt_prog_compiler_wl, $1)=
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=
-_LT_TAGVAR(lt_prog_compiler_static, $1)=
-
-m4_if([$1], [CXX], [
-  # C++ specific cases for pic, static, wl, etc.
-  if test yes = "$GXX"; then
-    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-
-    case $host_os in
-    aix*)
-      # All AIX code is PIC.
-      if test ia64 = "$host_cpu"; then
-       # AIX 5 now supports IA64 processor
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-        ;;
-      m68k)
-            # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the '-m68020' flag to GCC prevents building anything better,
-            # like '-m68040'.
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
-        ;;
-      esac
-      ;;
-
-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
-      # PIC is the default for these OSes.
-      ;;
-    mingw* | cygwin* | os2* | pw32* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
-      # (--disable-auto-import) libraries
-      m4_if([$1], [GCJ], [],
-       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      case $host_os in
-      os2*)
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
-       ;;
-      esac
-      ;;
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
-      ;;
-    *djgpp*)
-      # DJGPP does not support shared libraries at all
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-      ;;
-    haiku*)
-      # PIC is the default for Haiku.
-      # The "-static" flag exists, but is broken.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)=
-      ;;
-    interix[[3-9]]*)
-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
-      # Instead, we relocate shared libraries at runtime.
-      ;;
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
-      fi
-      ;;
-    hpux*)
-      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
-      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
-      # sets the default TLS model and affects inlining.
-      case $host_cpu in
-      hppa*64*)
-       ;;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-       ;;
-      esac
-      ;;
-    *qnx* | *nto*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-    *)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-      ;;
-    esac
-  else
-    case $host_os in
-      aix[[4-9]]*)
-       # All AIX code is PIC.
-       if test ia64 = "$host_cpu"; then
-         # AIX 5 now supports IA64 processor
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-       else
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
-       fi
-       ;;
-      chorus*)
-       case $cc_basename in
-       cxch68*)
-         # Green Hills C++ Compiler
-         # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
-         ;;
-       esac
-       ;;
-      mingw* | cygwin* | os2* | pw32* | cegcc*)
-       # This hack is so that the source file can tell whether it is being
-       # built for inclusion in a dll (and should export symbols for example).
-       m4_if([$1], [GCJ], [],
-         [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-       ;;
-      dgux*)
-       case $cc_basename in
-         ec++*)
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           ;;
-         ghcx*)
-           # Green Hills C++ Compiler
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      freebsd* | dragonfly*)
-       # FreeBSD uses GNU C++
-       ;;
-      hpux9* | hpux10* | hpux11*)
-       case $cc_basename in
-         CC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
-           if test ia64 != "$host_cpu"; then
-             _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-           fi
-           ;;
-         aCC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
-           case $host_cpu in
-           hppa*64*|ia64*)
-             # +Z the default
-             ;;
-           *)
-             _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-             ;;
-           esac
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      interix*)
-       # This is c89, which is MS Visual C++ (no shared libs)
-       # Anyone wants to do a port?
-       ;;
-      irix5* | irix6* | nonstopux*)
-       case $cc_basename in
-         CC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-           # CC pic flag -KPIC is the default.
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-       case $cc_basename in
-         KCC*)
-           # KAI C++ Compiler
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-           ;;
-         ecpc* )
-           # old Intel C++ for x86_64, which still supported -KPIC.
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-           ;;
-         icpc* )
-           # Intel C++, used to be incompatible with GCC.
-           # ICC 10 doesn't accept -KPIC any more.
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-           ;;
-         pgCC* | pgcpp*)
-           # Portland Group C++ compiler
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-           ;;
-         cxx*)
-           # Compaq C++
-           # Make sure the PIC flag is empty.  It appears that all Alpha
-           # Linux and Compaq Tru64 Unix objects are PIC.
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-           ;;
-         xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
-           # IBM XL 8.0, 9.0 on PPC and BlueGene
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
-           ;;
-         *)
-           case `$CC -V 2>&1 | sed 5q` in
-           *Sun\ C*)
-             # Sun C++ 5.9
-             _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-             _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-             _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-             ;;
-           esac
-           ;;
-       esac
-       ;;
-      lynxos*)
-       ;;
-      m88k*)
-       ;;
-      mvs*)
-       case $cc_basename in
-         cxx*)
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      netbsd* | netbsdelf*-gnu)
-       ;;
-      *qnx* | *nto*)
-        # QNX uses GNU C++, but need to define -shared option too, otherwise
-        # it will coredump.
-        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-        ;;
-      osf3* | osf4* | osf5*)
-       case $cc_basename in
-         KCC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
-           ;;
-         RCC*)
-           # Rational C++ 2.4.1
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-           ;;
-         cxx*)
-           # Digital/Compaq C++
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           # Make sure the PIC flag is empty.  It appears that all Alpha
-           # Linux and Compaq Tru64 Unix objects are PIC.
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      psos*)
-       ;;
-      solaris*)
-       case $cc_basename in
-         CC* | sunCC*)
-           # Sun C++ 4.2, 5.x and Centerline C++
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-           ;;
-         gcx*)
-           # Green Hills C++ Compiler
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      sunos4*)
-       case $cc_basename in
-         CC*)
-           # Sun C++ 4.x
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-           ;;
-         lcc*)
-           # Lucid
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
-       case $cc_basename in
-         CC*)
-           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-           ;;
-       esac
-       ;;
-      tandem*)
-       case $cc_basename in
-         NCC*)
-           # NonStop-UX NCC 3.20
-           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-           ;;
-         *)
-           ;;
-       esac
-       ;;
-      vxworks*)
-       ;;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-       ;;
-    esac
-  fi
-],
-[
-  if test yes = "$GCC"; then
-    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-
-    case $host_os in
-      aix*)
-      # All AIX code is PIC.
-      if test ia64 = "$host_cpu"; then
-       # AIX 5 now supports IA64 processor
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-        ;;
-      m68k)
-            # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the '-m68020' flag to GCC prevents building anything better,
-            # like '-m68040'.
-            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
-        ;;
-      esac
-      ;;
-
-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
-      # PIC is the default for these OSes.
-      ;;
-
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
-      # (--disable-auto-import) libraries
-      m4_if([$1], [GCJ], [],
-       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      case $host_os in
-      os2*)
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
-       ;;
-      esac
-      ;;
-
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
-      ;;
-
-    haiku*)
-      # PIC is the default for Haiku.
-      # The "-static" flag exists, but is broken.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)=
-      ;;
-
-    hpux*)
-      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
-      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
-      # sets the default TLS model and affects inlining.
-      case $host_cpu in
-      hppa*64*)
-       # +Z the default
-       ;;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-       ;;
-      esac
-      ;;
-
-    interix[[3-9]]*)
-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
-      # Instead, we relocate shared libraries at runtime.
-      ;;
-
-    msdosdjgpp*)
-      # Just because we use GCC doesn't mean we suddenly get shared libraries
-      # on systems that don't support them.
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      enable_shared=no
-      ;;
-
-    *nto* | *qnx*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
-      fi
-      ;;
-
-    *)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-      ;;
-    esac
-
-    case $cc_basename in
-    nvcc*) # Cuda Compiler Driver 2.2
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
-      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
-        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
-      fi
-      ;;
-    esac
-  else
-    # PORTME Check for flag to pass linker flags through the system compiler.
-    case $host_os in
-    aix*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      if test ia64 = "$host_cpu"; then
-       # AIX 5 now supports IA64 processor
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      else
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
-      fi
-      ;;
-
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
-      case $cc_basename in
-      nagfor*)
-        # NAG Fortran compiler
-        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
-        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-        _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-        ;;
-      esac
-      ;;
-
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      m4_if([$1], [GCJ], [],
-       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
-      case $host_os in
-      os2*)
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
-       ;;
-      esac
-      ;;
-
-    hpux9* | hpux10* | hpux11*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
-      # not for PA HP-UX.
-      case $host_cpu in
-      hppa*64*|ia64*)
-       # +Z the default
-       ;;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
-       ;;
-      esac
-      # Is there a better lt_prog_compiler_static that works with the bundled CC?
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
-      ;;
-
-    irix5* | irix6* | nonstopux*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # PIC (with -KPIC) is the default.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-      case $cc_basename in
-      # old Intel for x86_64, which still supported -KPIC.
-      ecc*)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-        ;;
-      # icc used to be incompatible with GCC.
-      # ICC 10 doesn't accept -KPIC any more.
-      icc* | ifort*)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-        ;;
-      # Lahey Fortran 8.1.
-      lf95*)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
-       ;;
-      nagfor*)
-       # NAG Fortran compiler
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-       ;;
-      tcc*)
-       # Fabrice Bellard et al's Tiny C Compiler
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-       ;;
-      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
-        # Portland Group compilers (*not* the Pentium gcc compiler,
-       # which looks to be a dead project)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-        ;;
-      ccc*)
-        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-        # All Alpha code is PIC.
-        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-        ;;
-      xl* | bgxl* | bgf* | mpixl*)
-       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
-       ;;
-      *)
-       case `$CC -V 2>&1 | sed 5q` in
-       *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
-         # Sun Fortran 8.3 passes all unrecognized flags to the linker
-         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
-         ;;
-       *Sun\ F* | *Sun*Fortran*)
-         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-         ;;
-       *Sun\ C*)
-         # Sun C 5.9
-         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-         ;;
-        *Intel*\ [[CF]]*Compiler*)
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-         ;;
-       *Portland\ Group*)
-         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
-         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-         ;;
-       esac
-       ;;
-      esac
-      ;;
-
-    newsos6)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    *nto* | *qnx*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
-      ;;
-
-    osf3* | osf4* | osf5*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      # All OSF/1 code is PIC.
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    rdos*)
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
-      ;;
-
-    solaris*)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      case $cc_basename in
-      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
-      *)
-       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
-      esac
-      ;;
-
-    sunos4*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    sysv4 | sysv4.2uw2* | sysv4.3*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
-       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      fi
-      ;;
-
-    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    unicos*)
-      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      ;;
-
-    uts4*)
-      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
-      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
-      ;;
-
-    *)
-      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
-      ;;
-    esac
-  fi
-])
-case $host_os in
-  # For platforms that do not support PIC, -DPIC is meaningless:
-  *djgpp*)
-    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
-    ;;
-  *)
-    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
-    ;;
-esac
-
-AC_CACHE_CHECK([for $compiler option to produce PIC],
-  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
-  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
-
-#
-# Check to make sure the PIC flag actually works.
-#
-if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
-  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
-    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
-    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
-    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
-     "" | " "*) ;;
-     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
-     esac],
-    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
-     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
-fi
-_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
-       [Additional compiler flags for building library objects])
-
-_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
-       [How to pass a linker flag through the compiler])
-#
-# Check to make sure the static flag actually works.
-#
-wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
-_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
-  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
-  $lt_tmp_static_flag,
-  [],
-  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
-_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
-       [Compiler flag to prevent dynamic linking])
-])# _LT_COMPILER_PIC
-
-
-# _LT_LINKER_SHLIBS([TAGNAME])
-# ----------------------------
-# See if the linker supports building shared libraries.
-m4_defun([_LT_LINKER_SHLIBS],
-[AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
-m4_if([$1], [CXX], [
-  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
-  case $host_os in
-  aix[[4-9]]*)
-    # If we're using GNU nm, then we don't want the "-C" option.
-    # -C means demangle to GNU nm, but means don't demangle to AIX nm.
-    # Without the "-l" option, or with the "-B" option, AIX nm treats
-    # weak defined symbols like other global defined symbols, whereas
-    # GNU nm marks them as "W".
-    # While the 'weak' keyword is ignored in the Export File, we need
-    # it in the Import File for the 'aix-soname' feature, so we have
-    # to replace the "-B" option with "-P" for AIX nm.
-    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
-    else
-      _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
-    fi
-    ;;
-  pw32*)
-    _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
-    ;;
-  cygwin* | mingw* | cegcc*)
-    case $cc_basename in
-    cl*)
-      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
-      ;;
-    *)
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
-      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
-      ;;
-    esac
-    ;;
-  linux* | k*bsd*-gnu | gnu*)
-    _LT_TAGVAR(link_all_deplibs, $1)=no
-    ;;
-  *)
-    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-    ;;
-  esac
-], [
-  runpath_var=
-  _LT_TAGVAR(allow_undefined_flag, $1)=
-  _LT_TAGVAR(always_export_symbols, $1)=no
-  _LT_TAGVAR(archive_cmds, $1)=
-  _LT_TAGVAR(archive_expsym_cmds, $1)=
-  _LT_TAGVAR(compiler_needs_object, $1)=no
-  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
-  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-  _LT_TAGVAR(hardcode_automatic, $1)=no
-  _LT_TAGVAR(hardcode_direct, $1)=no
-  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
-  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-  _LT_TAGVAR(hardcode_libdir_separator, $1)=
-  _LT_TAGVAR(hardcode_minus_L, $1)=no
-  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-  _LT_TAGVAR(inherit_rpath, $1)=no
-  _LT_TAGVAR(link_all_deplibs, $1)=unknown
-  _LT_TAGVAR(module_cmds, $1)=
-  _LT_TAGVAR(module_expsym_cmds, $1)=
-  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
-  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
-  _LT_TAGVAR(thread_safe_flag_spec, $1)=
-  _LT_TAGVAR(whole_archive_flag_spec, $1)=
-  # include_expsyms should be a list of space-separated symbols to be *always*
-  # included in the symbol list
-  _LT_TAGVAR(include_expsyms, $1)=
-  # exclude_expsyms can be an extended regexp of symbols to exclude
-  # it will be wrapped by ' (' and ')$', so one must not match beginning or
-  # end of line.  Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
-  # as well as any symbol that contains 'd'.
-  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
-  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-  # platforms (ab)use it in PIC code, but their linkers get confused if
-  # the symbol is explicitly referenced.  Since portable code cannot
-  # rely on this symbol name, it's probably fine to never include it in
-  # preloaded symbol tables.
-  # Exclude shared library initialization/finalization symbols.
-dnl Note also adjust exclude_expsyms for C++ above.
-  extract_expsyms_cmds=
-
-  case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    # FIXME: the MSVC++ port hasn't been tested in a loooong time
-    # When not using gcc, we currently assume that we are using
-    # Microsoft Visual C++.
-    if test yes != "$GCC"; then
-      with_gnu_ld=no
-    fi
-    ;;
-  interix*)
-    # we just hope/assume this is gcc and not c89 (= MSVC++)
-    with_gnu_ld=yes
-    ;;
-  openbsd* | bitrig*)
-    with_gnu_ld=no
-    ;;
-  linux* | k*bsd*-gnu | gnu*)
-    _LT_TAGVAR(link_all_deplibs, $1)=no
-    ;;
-  esac
-
-  _LT_TAGVAR(ld_shlibs, $1)=yes
-
-  # On some targets, GNU ld is compatible enough with the native linker
-  # that we're better off using the native interface for both.
-  lt_use_gnu_ld_interface=no
-  if test yes = "$with_gnu_ld"; then
-    case $host_os in
-      aix*)
-       # The AIX port of GNU ld has always aspired to compatibility
-       # with the native linker.  However, as the warning in the GNU ld
-       # block says, versions before 2.19.5* couldn't really create working
-       # shared libraries, regardless of the interface used.
-       case `$LD -v 2>&1` in
-         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
-         *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
-         *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
-         *)
-           lt_use_gnu_ld_interface=yes
-           ;;
-       esac
-       ;;
-      *)
-       lt_use_gnu_ld_interface=yes
-       ;;
-    esac
-  fi
-
-  if test yes = "$lt_use_gnu_ld_interface"; then
-    # If archive_cmds runs LD, not CC, wlarc should be empty
-    wlarc='$wl'
-
-    # Set some defaults for GNU ld with shared library support. These
-    # are reset later if shared libraries are not supported. Putting them
-    # here allows them to be overridden if necessary.
-    runpath_var=LD_RUN_PATH
-    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
-    # ancient GNU ld didn't support --whole-archive et. al.
-    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
-      _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
-    else
-      _LT_TAGVAR(whole_archive_flag_spec, $1)=
-    fi
-    supports_anon_versioning=no
-    case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
-      *GNU\ gold*) supports_anon_versioning=yes ;;
-      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
-      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
-      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
-      *\ 2.11.*) ;; # other 2.11 versions
-      *) supports_anon_versioning=yes ;;
-    esac
-
-    # See if GNU ld supports shared libraries.
-    case $host_os in
-    aix[[3-9]]*)
-      # On AIX/PPC, the GNU linker is very broken
-      if test ia64 != "$host_cpu"; then
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.19, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support.  If you
-*** really care for shared libraries, you may want to install binutils
-*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
-*** You will then need to restart the configuration process.
-
-_LT_EOF
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-            _LT_TAGVAR(archive_expsym_cmds, $1)=''
-        ;;
-      m68k)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes
-        ;;
-      esac
-      ;;
-
-    beos*)
-      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
-       # support --undefined.  This deserves some investigation.  FIXME
-       _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    cygwin* | mingw* | pw32* | cegcc*)
-      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
-      # as there is no search path for DLLs.
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(always_export_symbols, $1)=no
-      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
-      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
-
-      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-       # If the export-symbols file already is a .def file, use it as
-       # is; otherwise, prepend EXPORTS...
-       _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
-          cp $export_symbols $output_objdir/$soname.def;
-        else
-          echo EXPORTS > $output_objdir/$soname.def;
-          cat $export_symbols >> $output_objdir/$soname.def;
-        fi~
-        $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    haiku*)
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    os2*)
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      shrext_cmds=.dll
-      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-       $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-       $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-       $ECHO EXPORTS >> $output_objdir/$libname.def~
-       emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
-       $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-       emximp -o $lib $output_objdir/$libname.def'
-      _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-       $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-       $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-       $ECHO EXPORTS >> $output_objdir/$libname.def~
-       prefix_cmds="$SED"~
-       if test EXPORTS = "`$SED 1q $export_symbols`"; then
-         prefix_cmds="$prefix_cmds -e 1d";
-       fi~
-       prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
-       cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
-       $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-       emximp -o $lib $output_objdir/$libname.def'
-      _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
-      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-      ;;
-
-    interix[[3-9]]*)
-      _LT_TAGVAR(hardcode_direct, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
-      # Instead, shared libraries are loaded at an image base (0x10000000 by
-      # default) and relocated if they conflict, which is a slow very memory
-      # consuming and fragmenting process.  To avoid this, we pick a random,
-      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
-      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      ;;
-
-    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
-      tmp_diet=no
-      if test linux-dietlibc = "$host_os"; then
-       case $cc_basename in
-         diet\ *) tmp_diet=yes;;       # linux-dietlibc with static linking (!diet-dyn)
-       esac
-      fi
-      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
-        && test no = "$tmp_diet"
-      then
-       tmp_addflag=' $pic_flag'
-       tmp_sharedflag='-shared'
-       case $cc_basename,$host_cpu in
-        pgcc*)                         # Portland Group C compiler
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-         tmp_addflag=' $pic_flag'
-         ;;
-       pgf77* | pgf90* | pgf95* | pgfortran*)
-                                       # Portland Group f77 and f90 compilers
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-         tmp_addflag=' $pic_flag -Mnomain' ;;
-       ecc*,ia64* | icc*,ia64*)        # Intel C compiler on ia64
-         tmp_addflag=' -i_dynamic' ;;
-       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
-         tmp_addflag=' -i_dynamic -nofor_main' ;;
-       ifc* | ifort*)                  # Intel Fortran compiler
-         tmp_addflag=' -nofor_main' ;;
-       lf95*)                          # Lahey Fortran 8.1
-         _LT_TAGVAR(whole_archive_flag_spec, $1)=
-         tmp_sharedflag='--shared' ;;
-        nagfor*)                        # NAGFOR 5.3
-          tmp_sharedflag='-Wl,-shared' ;;
-       xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
-         tmp_sharedflag='-qmkshrobj'
-         tmp_addflag= ;;
-       nvcc*)  # Cuda Compiler Driver 2.2
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-         _LT_TAGVAR(compiler_needs_object, $1)=yes
-         ;;
-       esac
-       case `$CC -V 2>&1 | sed 5q` in
-       *Sun\ C*)                       # Sun C 5.9
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-         _LT_TAGVAR(compiler_needs_object, $1)=yes
-         tmp_sharedflag='-G' ;;
-       *Sun\ F*)                       # Sun Fortran 8.3
-         tmp_sharedflag='-G' ;;
-       esac
-       _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-
-        if test yes = "$supports_anon_versioning"; then
-          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-            cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-            echo "local: *; };" >> $output_objdir/$libname.ver~
-            $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
-        fi
-
-       case $cc_basename in
-       tcc*)
-         _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
-         ;;
-       xlf* | bgf* | bgxlf* | mpixlf*)
-         # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-         _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
-         if test yes = "$supports_anon_versioning"; then
-           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-              echo "local: *; };" >> $output_objdir/$libname.ver~
-              $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
-         fi
-         ;;
-       esac
-      else
-        _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    netbsd* | netbsdelf*-gnu)
-      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-       _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
-       wlarc=
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-      fi
-      ;;
-
-    solaris*)
-      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
-      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
-      case `$LD -v 2>&1` in
-        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
-*** reliably create shared libraries on SCO systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
-       ;;
-       *)
-         # For security reasons, it is highly recommended that you always
-         # use absolute paths for naming shared libraries, and exclude the
-         # DT_RUNPATH tag from executables and libraries.  But doing so
-         # requires that you compile everything twice, which is a pain.
-         if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-         else
-           _LT_TAGVAR(ld_shlibs, $1)=no
-         fi
-       ;;
-      esac
-      ;;
-
-    sunos4*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-      wlarc=
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *)
-      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-    esac
-
-    if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
-      runpath_var=
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
-      _LT_TAGVAR(whole_archive_flag_spec, $1)=
-    fi
-  else
-    # PORTME fill in a description of your system's linker (not GNU ld)
-    case $host_os in
-    aix3*)
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      _LT_TAGVAR(always_export_symbols, $1)=yes
-      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
-      # Note: this linker hardcodes the directories in LIBPATH if there
-      # are no directories specified by -L.
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
-       # Neither direct hardcoding nor static linking is supported with a
-       # broken collect2.
-       _LT_TAGVAR(hardcode_direct, $1)=unsupported
-      fi
-      ;;
-
-    aix[[4-9]]*)
-      if test ia64 = "$host_cpu"; then
-       # On IA64, the linker does run time linking by default, so we don't
-       # have to do anything special.
-       aix_use_runtimelinking=no
-       exp_sym_flag='-Bexport'
-       no_entry_flag=
-      else
-       # If we're using GNU nm, then we don't want the "-C" option.
-       # -C means demangle to GNU nm, but means don't demangle to AIX nm.
-       # Without the "-l" option, or with the "-B" option, AIX nm treats
-       # weak defined symbols like other global defined symbols, whereas
-       # GNU nm marks them as "W".
-       # While the 'weak' keyword is ignored in the Export File, we need
-       # it in the Import File for the 'aix-soname' feature, so we have
-       # to replace the "-B" option with "-P" for AIX nm.
-       if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
-       else
-         _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
-       fi
-       aix_use_runtimelinking=no
-
-       # Test if we are trying to use run time linking or normal
-       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-       # have runtime linking enabled, and use it for executables.
-       # For shared libraries, we enable/disable runtime linking
-       # depending on the kind of the shared library created -
-       # when "with_aix_soname,aix_use_runtimelinking" is:
-       # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
-       # "aix,yes"  lib.so          shared, rtl:yes, for executables
-       #            lib.a           static archive
-       # "both,no"  lib.so.V(shr.o) shared, rtl:yes
-       #            lib.a(lib.so.V) shared, rtl:no,  for executables
-       # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
-       #            lib.a(lib.so.V) shared, rtl:no
-       # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
-       #            lib.a           static archive
-       case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
-         for ld_flag in $LDFLAGS; do
-         if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
-           aix_use_runtimelinking=yes
-           break
-         fi
-         done
-         if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
-           # With aix-soname=svr4, we create the lib.so.V shared archives only,
-           # so we don't have lib.a shared libs to link our executables.
-           # We have to force runtime linking in this case.
-           aix_use_runtimelinking=yes
-           LDFLAGS="$LDFLAGS -Wl,-brtl"
-         fi
-         ;;
-       esac
-
-       exp_sym_flag='-bexport'
-       no_entry_flag='-bnoentry'
-      fi
-
-      # When large executables or shared objects are built, AIX ld can
-      # have problems creating the table of contents.  If linking a library
-      # or program results in "error TOC overflow" add -mminimal-toc to
-      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
-      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
-      _LT_TAGVAR(archive_cmds, $1)=''
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
-      case $with_aix_soname,$aix_use_runtimelinking in
-      aix,*) ;; # traditional, no import file
-      svr4,* | *,yes) # use import file
-       # The Import File defines what to hardcode.
-       _LT_TAGVAR(hardcode_direct, $1)=no
-       _LT_TAGVAR(hardcode_direct_absolute, $1)=no
-       ;;
-      esac
-
-      if test yes = "$GCC"; then
-       case $host_os in aix4.[[012]]|aix4.[[012]].*)
-       # We only want to do this on AIX 4.2 and lower, the check
-       # below for broken collect2 doesn't work under 4.3+
-         collect2name=`$CC -print-prog-name=collect2`
-         if test -f "$collect2name" &&
-          strings "$collect2name" | $GREP resolve_lib_name >/dev/null
-         then
-         # We have reworked collect2
-         :
-         else
-         # We have old collect2
-         _LT_TAGVAR(hardcode_direct, $1)=unsupported
-         # It fails to find uninstalled libraries when the uninstalled
-         # path is not listed in the libpath.  Setting hardcode_minus_L
-         # to unsupported forces relinking
-         _LT_TAGVAR(hardcode_minus_L, $1)=yes
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-         _LT_TAGVAR(hardcode_libdir_separator, $1)=
-         fi
-         ;;
-       esac
-       shared_flag='-shared'
-       if test yes = "$aix_use_runtimelinking"; then
-         shared_flag="$shared_flag "'$wl-G'
-       fi
-       # Need to ensure runtime linking is disabled for the traditional
-       # shared library, or the linker may eventually find shared libraries
-       # /with/ Import File - we do not want to mix them.
-       shared_flag_aix='-shared'
-       shared_flag_svr4='-shared $wl-G'
-      else
-       # not using gcc
-       if test ia64 = "$host_cpu"; then
-       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
-       # chokes on -Wl,-G. The following line is correct:
-         shared_flag='-G'
-       else
-         if test yes = "$aix_use_runtimelinking"; then
-           shared_flag='$wl-G'
-         else
-           shared_flag='$wl-bM:SRE'
-         fi
-         shared_flag_aix='$wl-bM:SRE'
-         shared_flag_svr4='$wl-G'
-       fi
-      fi
-
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
-      # It seems that -bexpall does not export symbols beginning with
-      # underscore (_), so it is better to generate a list of symbols to export.
-      _LT_TAGVAR(always_export_symbols, $1)=yes
-      if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
-       # Warning - without using the other runtime loading flags (-brtl),
-       # -berok will link without error, but may produce a broken library.
-       _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
-        # Determine the default libpath from the value encoded in an
-        # empty executable.
-        _LT_SYS_MODULE_PATH_AIX([$1])
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
-      else
-       if test ia64 = "$host_cpu"; then
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
-         _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
-         _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
-       else
-        # Determine the default libpath from the value encoded in an
-        # empty executable.
-        _LT_SYS_MODULE_PATH_AIX([$1])
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
-         # Warning - without using the other run time loading flags,
-         # -berok will link without error, but may produce a broken library.
-         _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
-         _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
-         if test yes = "$with_gnu_ld"; then
-           # We only use this code for GNU lds that support --whole-archive.
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
-         else
-           # Exported symbols can be pulled into shared objects from archives
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
-         fi
-         _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-         _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
-         # -brtl affects multiple linker settings, -berok does not and is overridden later
-         compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
-         if test svr4 != "$with_aix_soname"; then
-           # This is similar to how AIX traditionally builds its shared libraries.
-           _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
-         fi
-         if test aix != "$with_aix_soname"; then
-           _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
-         else
-           # used by -dlpreopen to get the symbols
-           _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
-         fi
-         _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
-       fi
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-            _LT_TAGVAR(archive_expsym_cmds, $1)=''
-        ;;
-      m68k)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes
-        ;;
-      esac
-      ;;
-
-    bsdi[[45]]*)
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
-      ;;
-
-    cygwin* | mingw* | pw32* | cegcc*)
-      # When not using gcc, we currently assume that we are using
-      # Microsoft Visual C++.
-      # hardcode_libdir_flag_spec is actually meaningless, as there is
-      # no search path for DLLs.
-      case $cc_basename in
-      cl*)
-       # Native MSVC
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-       _LT_TAGVAR(always_export_symbols, $1)=yes
-       _LT_TAGVAR(file_list_spec, $1)='@'
-       # Tell ltmain to make .lib files, not .a files.
-       libext=lib
-       # Tell ltmain to make .dll files, not .so files.
-       shrext_cmds=.dll
-       # FIXME: Setting linknames here is a bad hack.
-       _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
-       _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
-            cp "$export_symbols" "$output_objdir/$soname.def";
-            echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
-          else
-            $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
-          fi~
-          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-          linknames='
-       # The linker will not automatically build a static lib if we build a DLL.
-       # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-       _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
-       _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
-       # Don't use ranlib
-       _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
-       _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
-          lt_tool_outputfile="@TOOL_OUTPUT@"~
-          case $lt_outputfile in
-            *.exe|*.EXE) ;;
-            *)
-              lt_outputfile=$lt_outputfile.exe
-              lt_tool_outputfile=$lt_tool_outputfile.exe
-              ;;
-          esac~
-          if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
-            $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-            $RM "$lt_outputfile.manifest";
-          fi'
-       ;;
-      *)
-       # Assume MSVC wrapper
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-       # Tell ltmain to make .lib files, not .a files.
-       libext=lib
-       # Tell ltmain to make .dll files, not .so files.
-       shrext_cmds=.dll
-       # FIXME: Setting linknames here is a bad hack.
-       _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
-       # The linker will automatically build a .lib file if we build a DLL.
-       _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-       # FIXME: Should let the user specify the lib program.
-       _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
-       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-       ;;
-      esac
-      ;;
-
-    darwin* | rhapsody*)
-      _LT_DARWIN_LINKER_FEATURES($1)
-      ;;
-
-    dgux*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
-    # support.  Future versions do this automatically, but an explicit c++rt0.o
-    # does not break anything, and helps significantly (at the cost of a little
-    # extra space).
-    freebsd2.2*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
-    freebsd2.*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
-    freebsd* | dragonfly*)
-      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    hpux9*)
-      if test yes = "$GCC"; then
-       _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-
-      # hardcode_minus_L: Not really in the search PATH,
-      # but as the default location of the library.
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-      ;;
-
-    hpux10*)
-      if test yes,no = "$GCC,$with_gnu_ld"; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
-      fi
-      if test no = "$with_gnu_ld"; then
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
-       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-       _LT_TAGVAR(hardcode_direct, $1)=yes
-       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-       _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-       # hardcode_minus_L: Not really in the search PATH,
-       # but as the default location of the library.
-       _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      fi
-      ;;
-
-    hpux11*)
-      if test yes,no = "$GCC,$with_gnu_ld"; then
-       case $host_cpu in
-       hppa*64*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       ia64*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       *)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       esac
-      else
-       case $host_cpu in
-       hppa*64*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       ia64*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       *)
-       m4_if($1, [], [
-         # Older versions of the 11.00 compiler do not understand -b yet
-         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
-         _LT_LINKER_OPTION([if $CC understands -b],
-           _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
-           [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
-           [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
-         [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
-         ;;
-       esac
-      fi
-      if test no = "$with_gnu_ld"; then
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
-       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-       case $host_cpu in
-       hppa*64*|ia64*)
-         _LT_TAGVAR(hardcode_direct, $1)=no
-         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-         ;;
-       *)
-         _LT_TAGVAR(hardcode_direct, $1)=yes
-         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-         _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-
-         # hardcode_minus_L: Not really in the search PATH,
-         # but as the default location of the library.
-         _LT_TAGVAR(hardcode_minus_L, $1)=yes
-         ;;
-       esac
-      fi
-      ;;
-
-    irix5* | irix6* | nonstopux*)
-      if test yes = "$GCC"; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-       # Try to use the -exported_symbol ld option, if it does not
-       # work, assume that -exports_file does not work either and
-       # implicitly export all symbols.
-       # This should be the same for all languages, so no per-tag cache variable.
-       AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
-         [lt_cv_irix_exported_symbol],
-         [save_LDFLAGS=$LDFLAGS
-          LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
-          AC_LINK_IFELSE(
-            [AC_LANG_SOURCE(
-               [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
-                             [C++], [[int foo (void) { return 0; }]],
-                             [Fortran 77], [[
-      subroutine foo
-      end]],
-                             [Fortran], [[
-      subroutine foo
-      end]])])],
-             [lt_cv_irix_exported_symbol=yes],
-             [lt_cv_irix_exported_symbol=no])
-           LDFLAGS=$save_LDFLAGS])
-       if test yes = "$lt_cv_irix_exported_symbol"; then
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
-       fi
-       _LT_TAGVAR(link_all_deplibs, $1)=no
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(inherit_rpath, $1)=yes
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    linux*)
-      case $cc_basename in
-      tcc*)
-       # Fabrice Bellard et al's Tiny C Compiler
-       _LT_TAGVAR(ld_shlibs, $1)=yes
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-       ;;
-      esac
-      ;;
-
-    netbsd* | netbsdelf*-gnu)
-      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-       _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    newsos6)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *nto* | *qnx*)
-      ;;
-
-    openbsd* | bitrig*)
-      if test -f /usr/libexec/ld.so; then
-       _LT_TAGVAR(hardcode_direct, $1)=yes
-       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-       if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
-         _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-       else
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
-       fi
-      else
-       _LT_TAGVAR(ld_shlibs, $1)=no
-      fi
-      ;;
-
-    os2*)
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-      shrext_cmds=.dll
-      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-       $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-       $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-       $ECHO EXPORTS >> $output_objdir/$libname.def~
-       emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
-       $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-       emximp -o $lib $output_objdir/$libname.def'
-      _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-       $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-       $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-       $ECHO EXPORTS >> $output_objdir/$libname.def~
-       prefix_cmds="$SED"~
-       if test EXPORTS = "`$SED 1q $export_symbols`"; then
-         prefix_cmds="$prefix_cmds -e 1d";
-       fi~
-       prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
-       cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
-       $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-       emximp -o $lib $output_objdir/$libname.def'
-      _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
-      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-      ;;
-
-    osf3*)
-      if test yes = "$GCC"; then
-       _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-      else
-       _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      ;;
-
-    osf4* | osf5*)     # as osf3* with the addition of -msym flag
-      if test yes = "$GCC"; then
-       _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-      else
-       _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
-          $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
-
-       # Both c and cxx compiler support -rpath directly
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-      fi
-      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-      ;;
-
-    solaris*)
-      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
-      if test yes = "$GCC"; then
-       wlarc='$wl'
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-          $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
-      else
-       case `$CC -V 2>&1` in
-       *"Compilers 5.0"*)
-         wlarc=''
-         _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-            $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
-         ;;
-       *)
-         wlarc='$wl'
-         _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-            $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
-         ;;
-       esac
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      case $host_os in
-      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-      *)
-       # The compiler driver will combine and reorder linker options,
-       # but understands '-z linker_flag'.  GCC discards it without '$wl',
-       # but is careful enough not to reorder.
-       # Supported since Solaris 2.6 (maybe 2.5.1?)
-       if test yes = "$GCC"; then
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
-       else
-         _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
-       fi
-       ;;
-      esac
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      ;;
-
-    sunos4*)
-      if test sequent = "$host_vendor"; then
-       # Use $CC to link under sequent, because it throws in some extra .o
-       # files that make .init and .fini sections work.
-       _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
-      fi
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_direct, $1)=yes
-      _LT_TAGVAR(hardcode_minus_L, $1)=yes
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    sysv4)
-      case $host_vendor in
-       sni)
-         _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
-       ;;
-       siemens)
-         ## LD is ld it makes a PLAMLIB
-         ## CC just makes a GrossModule.
-         _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
-         _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
-         _LT_TAGVAR(hardcode_direct, $1)=no
-        ;;
-       motorola)
-         _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
-       ;;
-      esac
-      runpath_var='LD_RUN_PATH'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    sysv4.3*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       runpath_var=LD_RUN_PATH
-       hardcode_runpath_var=yes
-       _LT_TAGVAR(ld_shlibs, $1)=yes
-      fi
-      ;;
-
-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
-      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      runpath_var='LD_RUN_PATH'
-
-      if test yes = "$GCC"; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      fi
-      ;;
-
-    sysv5* | sco3.2v5* | sco5v6*)
-      # Note: We CANNOT use -z defs as we might desire, because we do not
-      # link with -lc, and that would cause any symbols used from libc to
-      # always be unresolved, which means just about no library would
-      # ever link correctly.  If we're not using GNU ld we use -z text
-      # though, which does catch some bad symbols but isn't as heavy-handed
-      # as -z defs.
-      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
-      _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
-      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-      _LT_TAGVAR(link_all_deplibs, $1)=yes
-      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
-      runpath_var='LD_RUN_PATH'
-
-      if test yes = "$GCC"; then
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      fi
-      ;;
-
-    uts4*)
-      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      ;;
-
-    *)
-      _LT_TAGVAR(ld_shlibs, $1)=no
-      ;;
-    esac
-
-    if test sni = "$host_vendor"; then
-      case $host in
-      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-       _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
-       ;;
-      esac
-    fi
-  fi
-])
-AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
-
-_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
-
-_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
-_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
-_LT_DECL([], [extract_expsyms_cmds], [2],
-    [The commands to extract the exported symbol list from a shared archive])
-
-#
-# Do we need to explicitly link libc?
-#
-case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
-x|xyes)
-  # Assume -lc should be added
-  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-
-  if test yes,yes = "$GCC,$enable_shared"; then
-    case $_LT_TAGVAR(archive_cmds, $1) in
-    *'~'*)
-      # FIXME: we may have to deal with multi-command sequences.
-      ;;
-    '$CC '*)
-      # Test whether the compiler implicitly links with -lc since on some
-      # systems, -lgcc has to come before -lc. If gcc already passes -lc
-      # to ld, don't add -lc before -lgcc.
-      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
-       [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
-       [$RM conftest*
-       echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-       if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
-         soname=conftest
-         lib=conftest
-         libobjs=conftest.$ac_objext
-         deplibs=
-         wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
-         pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
-         compiler_flags=-v
-         linker_flags=-v
-         verstring=
-         output_objdir=.
-         libname=conftest
-         lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
-         _LT_TAGVAR(allow_undefined_flag, $1)=
-         if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
-         then
-           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-         else
-           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-         fi
-         _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
-       else
-         cat conftest.err 1>&5
-       fi
-       $RM conftest*
-       ])
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
-      ;;
-    esac
-  fi
-  ;;
-esac
-
-_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
-    [Whether or not to add -lc for building shared libraries])
-_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
-    [enable_shared_with_static_runtimes], [0],
-    [Whether or not to disallow shared libs when runtime libs are static])
-_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
-    [Compiler flag to allow reflexive dlopens])
-_LT_TAGDECL([], [whole_archive_flag_spec], [1],
-    [Compiler flag to generate shared objects directly from archives])
-_LT_TAGDECL([], [compiler_needs_object], [1],
-    [Whether the compiler copes with passing no objects directly])
-_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
-    [Create an old-style archive from a shared archive])
-_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
-    [Create a temporary old-style archive to link instead of a shared archive])
-_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
-_LT_TAGDECL([], [archive_expsym_cmds], [2])
-_LT_TAGDECL([], [module_cmds], [2],
-    [Commands used to build a loadable module if different from building
-    a shared archive.])
-_LT_TAGDECL([], [module_expsym_cmds], [2])
-_LT_TAGDECL([], [with_gnu_ld], [1],
-    [Whether we are building with GNU ld or not])
-_LT_TAGDECL([], [allow_undefined_flag], [1],
-    [Flag that allows shared libraries with undefined symbols to be built])
-_LT_TAGDECL([], [no_undefined_flag], [1],
-    [Flag that enforces no undefined symbols])
-_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
-    [Flag to hardcode $libdir into a binary during linking.
-    This must work even if $libdir does not exist])
-_LT_TAGDECL([], [hardcode_libdir_separator], [1],
-    [Whether we need a single "-rpath" flag with a separated argument])
-_LT_TAGDECL([], [hardcode_direct], [0],
-    [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
-    DIR into the resulting binary])
-_LT_TAGDECL([], [hardcode_direct_absolute], [0],
-    [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
-    DIR into the resulting binary and the resulting library dependency is
-    "absolute", i.e impossible to change by setting $shlibpath_var if the
-    library is relocated])
-_LT_TAGDECL([], [hardcode_minus_L], [0],
-    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
-    into the resulting binary])
-_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
-    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
-    into the resulting binary])
-_LT_TAGDECL([], [hardcode_automatic], [0],
-    [Set to "yes" if building a shared library automatically hardcodes DIR
-    into the library and all subsequent libraries and executables linked
-    against it])
-_LT_TAGDECL([], [inherit_rpath], [0],
-    [Set to yes if linker adds runtime paths of dependent libraries
-    to runtime path list])
-_LT_TAGDECL([], [link_all_deplibs], [0],
-    [Whether libtool must link a program against all its dependency libraries])
-_LT_TAGDECL([], [always_export_symbols], [0],
-    [Set to "yes" if exported symbols are required])
-_LT_TAGDECL([], [export_symbols_cmds], [2],
-    [The commands to list exported symbols])
-_LT_TAGDECL([], [exclude_expsyms], [1],
-    [Symbols that should not be listed in the preloaded symbols])
-_LT_TAGDECL([], [include_expsyms], [1],
-    [Symbols that must always be exported])
-_LT_TAGDECL([], [prelink_cmds], [2],
-    [Commands necessary for linking programs (against libraries) with templates])
-_LT_TAGDECL([], [postlink_cmds], [2],
-    [Commands necessary for finishing linking programs])
-_LT_TAGDECL([], [file_list_spec], [1],
-    [Specify filename containing input files])
-dnl FIXME: Not yet implemented
-dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
-dnl    [Compiler flag to generate thread safe objects])
-])# _LT_LINKER_SHLIBS
-
-
-# _LT_LANG_C_CONFIG([TAG])
-# ------------------------
-# Ensure that the configuration variables for a C compiler are suitably
-# defined.  These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_C_CONFIG],
-[m4_require([_LT_DECL_EGREP])dnl
-lt_save_CC=$CC
-AC_LANG_PUSH(C)
-
-# Source file extension for C test sources.
-ac_ext=c
-
-# Object file extension for compiled C test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="int some_variable = 0;"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
-
-_LT_TAG_COMPILER
-# Save the default compiler, since it gets overwritten when the other
-# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
-compiler_DEFAULT=$CC
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-## CAVEAT EMPTOR:
-## There is no encapsulation within the following macros, do not change
-## the running order or otherwise move them around unless you know exactly
-## what you are doing...
-if test -n "$compiler"; then
-  _LT_COMPILER_NO_RTTI($1)
-  _LT_COMPILER_PIC($1)
-  _LT_COMPILER_C_O($1)
-  _LT_COMPILER_FILE_LOCKS($1)
-  _LT_LINKER_SHLIBS($1)
-  _LT_SYS_DYNAMIC_LINKER($1)
-  _LT_LINKER_HARDCODE_LIBPATH($1)
-  LT_SYS_DLOPEN_SELF
-  _LT_CMD_STRIPLIB
-
-  # Report what library types will actually be built
-  AC_MSG_CHECKING([if libtool supports shared libraries])
-  AC_MSG_RESULT([$can_build_shared])
-
-  AC_MSG_CHECKING([whether to build shared libraries])
-  test no = "$can_build_shared" && enable_shared=no
-
-  # On AIX, shared libraries and static libraries use the same namespace, and
-  # are all built from PIC.
-  case $host_os in
-  aix3*)
-    test yes = "$enable_shared" && enable_static=no
-    if test -n "$RANLIB"; then
-      archive_cmds="$archive_cmds~\$RANLIB \$lib"
-      postinstall_cmds='$RANLIB $lib'
-    fi
-    ;;
-
-  aix[[4-9]]*)
-    if test ia64 != "$host_cpu"; then
-      case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
-      yes,aix,yes) ;;                  # shared object as lib.so file only
-      yes,svr4,*) ;;                   # shared object as lib.so archive member only
-      yes,*) enable_static=no ;;       # shared object in lib.a archive as well
-      esac
-    fi
-    ;;
-  esac
-  AC_MSG_RESULT([$enable_shared])
-
-  AC_MSG_CHECKING([whether to build static libraries])
-  # Make sure either enable_shared or enable_static is yes.
-  test yes = "$enable_shared" || enable_static=yes
-  AC_MSG_RESULT([$enable_static])
-
-  _LT_CONFIG($1)
-fi
-AC_LANG_POP
-CC=$lt_save_CC
-])# _LT_LANG_C_CONFIG
-
-
-# _LT_LANG_CXX_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for a C++ compiler are suitably
-# defined.  These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_CXX_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-if test -n "$CXX" && ( test no != "$CXX" &&
-    ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
-    (test g++ != "$CXX"))); then
-  AC_PROG_CXXCPP
-else
-  _lt_caught_CXX_error=yes
-fi
-
-AC_LANG_PUSH(C++)
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(compiler_needs_object, $1)=no
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for C++ test sources.
-ac_ext=cpp
-
-# Object file extension for compiled C++ test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the CXX compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test yes != "$_lt_caught_CXX_error"; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="int some_variable = 0;"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC=$CC
-  lt_save_CFLAGS=$CFLAGS
-  lt_save_LD=$LD
-  lt_save_GCC=$GCC
-  GCC=$GXX
-  lt_save_with_gnu_ld=$with_gnu_ld
-  lt_save_path_LD=$lt_cv_path_LD
-  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
-    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
-  else
-    $as_unset lt_cv_prog_gnu_ld
-  fi
-  if test -n "${lt_cv_path_LDCXX+set}"; then
-    lt_cv_path_LD=$lt_cv_path_LDCXX
-  else
-    $as_unset lt_cv_path_LD
-  fi
-  test -z "${LDCXX+set}" || LD=$LDCXX
-  CC=${CXX-"c++"}
-  CFLAGS=$CXXFLAGS
-  compiler=$CC
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-
-  if test -n "$compiler"; then
-    # We don't want -fno-exception when compiling C++ code, so set the
-    # no_builtin_flag separately
-    if test yes = "$GXX"; then
-      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
-    else
-      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-    fi
-
-    if test yes = "$GXX"; then
-      # Set up default GNU C++ configuration
-
-      LT_PATH_LD
-
-      # Check if GNU C++ uses GNU ld as the underlying linker, since the
-      # archiving commands below assume that GNU ld is being used.
-      if test yes = "$with_gnu_ld"; then
-        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
-        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
-
-        # If archive_cmds runs LD, not CC, wlarc should be empty
-        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
-        #     investigate it a little bit more. (MM)
-        wlarc='$wl'
-
-        # ancient GNU ld didn't support --whole-archive et. al.
-        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
-         $GREP 'no-whole-archive' > /dev/null; then
-          _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
-        else
-          _LT_TAGVAR(whole_archive_flag_spec, $1)=
-        fi
-      else
-        with_gnu_ld=no
-        wlarc=
-
-        # A generic and very simple default shared library creation
-        # command for GNU C++ for the case where it uses the native
-        # linker, instead of GNU ld.  If possible, this setting should
-        # overridden to take advantage of the native linker features on
-        # the platform it is being used on.
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
-      fi
-
-      # Commands to make compiler produce verbose output that lists
-      # what "hidden" libraries, object files and flags are used when
-      # linking a shared library.
-      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-
-    else
-      GXX=no
-      with_gnu_ld=no
-      wlarc=
-    fi
-
-    # PORTME: fill in a description of your system's C++ link characteristics
-    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
-    _LT_TAGVAR(ld_shlibs, $1)=yes
-    case $host_os in
-      aix3*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-      aix[[4-9]]*)
-        if test ia64 = "$host_cpu"; then
-          # On IA64, the linker does run time linking by default, so we don't
-          # have to do anything special.
-          aix_use_runtimelinking=no
-          exp_sym_flag='-Bexport'
-          no_entry_flag=
-        else
-          aix_use_runtimelinking=no
-
-          # Test if we are trying to use run time linking or normal
-          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-          # have runtime linking enabled, and use it for executables.
-          # For shared libraries, we enable/disable runtime linking
-          # depending on the kind of the shared library created -
-          # when "with_aix_soname,aix_use_runtimelinking" is:
-          # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
-          # "aix,yes"  lib.so          shared, rtl:yes, for executables
-          #            lib.a           static archive
-          # "both,no"  lib.so.V(shr.o) shared, rtl:yes
-          #            lib.a(lib.so.V) shared, rtl:no,  for executables
-          # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
-          #            lib.a(lib.so.V) shared, rtl:no
-          # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
-          #            lib.a           static archive
-          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
-           for ld_flag in $LDFLAGS; do
-             case $ld_flag in
-             *-brtl*)
-               aix_use_runtimelinking=yes
-               break
-               ;;
-             esac
-           done
-           if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
-             # With aix-soname=svr4, we create the lib.so.V shared archives only,
-             # so we don't have lib.a shared libs to link our executables.
-             # We have to force runtime linking in this case.
-             aix_use_runtimelinking=yes
-             LDFLAGS="$LDFLAGS -Wl,-brtl"
-           fi
-           ;;
-          esac
-
-          exp_sym_flag='-bexport'
-          no_entry_flag='-bnoentry'
-        fi
-
-        # When large executables or shared objects are built, AIX ld can
-        # have problems creating the table of contents.  If linking a library
-        # or program results in "error TOC overflow" add -mminimal-toc to
-        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
-        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
-        _LT_TAGVAR(archive_cmds, $1)=''
-        _LT_TAGVAR(hardcode_direct, $1)=yes
-        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-        _LT_TAGVAR(link_all_deplibs, $1)=yes
-        _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
-        case $with_aix_soname,$aix_use_runtimelinking in
-        aix,*) ;;      # no import file
-        svr4,* | *,yes) # use import file
-          # The Import File defines what to hardcode.
-          _LT_TAGVAR(hardcode_direct, $1)=no
-          _LT_TAGVAR(hardcode_direct_absolute, $1)=no
-          ;;
-        esac
-
-        if test yes = "$GXX"; then
-          case $host_os in aix4.[[012]]|aix4.[[012]].*)
-          # We only want to do this on AIX 4.2 and lower, the check
-          # below for broken collect2 doesn't work under 4.3+
-         collect2name=`$CC -print-prog-name=collect2`
-         if test -f "$collect2name" &&
-            strings "$collect2name" | $GREP resolve_lib_name >/dev/null
-         then
-           # We have reworked collect2
-           :
-         else
-           # We have old collect2
-           _LT_TAGVAR(hardcode_direct, $1)=unsupported
-           # It fails to find uninstalled libraries when the uninstalled
-           # path is not listed in the libpath.  Setting hardcode_minus_L
-           # to unsupported forces relinking
-           _LT_TAGVAR(hardcode_minus_L, $1)=yes
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-           _LT_TAGVAR(hardcode_libdir_separator, $1)=
-         fi
-          esac
-          shared_flag='-shared'
-         if test yes = "$aix_use_runtimelinking"; then
-           shared_flag=$shared_flag' $wl-G'
-         fi
-         # Need to ensure runtime linking is disabled for the traditional
-         # shared library, or the linker may eventually find shared libraries
-         # /with/ Import File - we do not want to mix them.
-         shared_flag_aix='-shared'
-         shared_flag_svr4='-shared $wl-G'
-        else
-          # not using gcc
-          if test ia64 = "$host_cpu"; then
-         # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
-         # chokes on -Wl,-G. The following line is correct:
-         shared_flag='-G'
-          else
-           if test yes = "$aix_use_runtimelinking"; then
-             shared_flag='$wl-G'
-           else
-             shared_flag='$wl-bM:SRE'
-           fi
-           shared_flag_aix='$wl-bM:SRE'
-           shared_flag_svr4='$wl-G'
-          fi
-        fi
-
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
-        # It seems that -bexpall does not export symbols beginning with
-        # underscore (_), so it is better to generate a list of symbols to
-       # export.
-        _LT_TAGVAR(always_export_symbols, $1)=yes
-       if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
-          # Warning - without using the other runtime loading flags (-brtl),
-          # -berok will link without error, but may produce a broken library.
-          # The "-G" linker flag allows undefined symbols.
-          _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
-          # Determine the default libpath from the value encoded in an empty
-          # executable.
-          _LT_SYS_MODULE_PATH_AIX([$1])
-          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
-
-          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
-        else
-          if test ia64 = "$host_cpu"; then
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
-           _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
-           _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
-          else
-           # Determine the default libpath from the value encoded in an
-           # empty executable.
-           _LT_SYS_MODULE_PATH_AIX([$1])
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
-           # Warning - without using the other run time loading flags,
-           # -berok will link without error, but may produce a broken library.
-           _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
-           _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
-           if test yes = "$with_gnu_ld"; then
-             # We only use this code for GNU lds that support --whole-archive.
-             _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
-           else
-             # Exported symbols can be pulled into shared objects from archives
-             _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
-           fi
-           _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
-           # -brtl affects multiple linker settings, -berok does not and is overridden later
-           compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
-           if test svr4 != "$with_aix_soname"; then
-             # This is similar to how AIX traditionally builds its shared
-             # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
-             _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
-           fi
-           if test aix != "$with_aix_soname"; then
-             _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
-           else
-             # used by -dlpreopen to get the symbols
-             _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
-           fi
-           _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
-          fi
-        fi
-        ;;
-
-      beos*)
-       if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-         # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
-         # support --undefined.  This deserves some investigation.  FIXME
-         _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-       else
-         _LT_TAGVAR(ld_shlibs, $1)=no
-       fi
-       ;;
-
-      chorus*)
-        case $cc_basename in
-          *)
-         # FIXME: insert proper C++ library support
-         _LT_TAGVAR(ld_shlibs, $1)=no
-         ;;
-        esac
-        ;;
-
-      cygwin* | mingw* | pw32* | cegcc*)
-       case $GXX,$cc_basename in
-       ,cl* | no,cl*)
-         # Native MSVC
-         # hardcode_libdir_flag_spec is actually meaningless, as there is
-         # no search path for DLLs.
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
-         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-         _LT_TAGVAR(always_export_symbols, $1)=yes
-         _LT_TAGVAR(file_list_spec, $1)='@'
-         # Tell ltmain to make .lib files, not .a files.
-         libext=lib
-         # Tell ltmain to make .dll files, not .so files.
-         shrext_cmds=.dll
-         # FIXME: Setting linknames here is a bad hack.
-         _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
-         _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
-              cp "$export_symbols" "$output_objdir/$soname.def";
-              echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
-            else
-              $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
-            fi~
-            $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-            linknames='
-         # The linker will not automatically build a static lib if we build a DLL.
-         # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
-         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-         # Don't use ranlib
-         _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
-         _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
-            lt_tool_outputfile="@TOOL_OUTPUT@"~
-            case $lt_outputfile in
-              *.exe|*.EXE) ;;
-              *)
-                lt_outputfile=$lt_outputfile.exe
-                lt_tool_outputfile=$lt_tool_outputfile.exe
-                ;;
-            esac~
-            func_to_tool_file "$lt_outputfile"~
-            if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
-              $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-              $RM "$lt_outputfile.manifest";
-            fi'
-         ;;
-       *)
-         # g++
-         # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
-         # as there is no search path for DLLs.
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-         _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
-         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-         _LT_TAGVAR(always_export_symbols, $1)=no
-         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-
-         if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-           # If the export-symbols file already is a .def file, use it as
-           # is; otherwise, prepend EXPORTS...
-           _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
-              cp $export_symbols $output_objdir/$soname.def;
-            else
-              echo EXPORTS > $output_objdir/$soname.def;
-              cat $export_symbols >> $output_objdir/$soname.def;
-            fi~
-            $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-         else
-           _LT_TAGVAR(ld_shlibs, $1)=no
-         fi
-         ;;
-       esac
-       ;;
-      darwin* | rhapsody*)
-        _LT_DARWIN_LINKER_FEATURES($1)
-       ;;
-
-      os2*)
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
-       _LT_TAGVAR(hardcode_minus_L, $1)=yes
-       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
-       shrext_cmds=.dll
-       _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-         $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-         $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-         $ECHO EXPORTS >> $output_objdir/$libname.def~
-         emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
-         $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-         emximp -o $lib $output_objdir/$libname.def'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-         $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-         $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-         $ECHO EXPORTS >> $output_objdir/$libname.def~
-         prefix_cmds="$SED"~
-         if test EXPORTS = "`$SED 1q $export_symbols`"; then
-           prefix_cmds="$prefix_cmds -e 1d";
-         fi~
-         prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
-         cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
-         $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-         emximp -o $lib $output_objdir/$libname.def'
-       _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
-       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-       ;;
-
-      dgux*)
-        case $cc_basename in
-          ec++*)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          ghcx*)
-           # Green Hills C++ Compiler
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          *)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-        esac
-        ;;
-
-      freebsd2.*)
-        # C++ shared libraries reported to be fairly broken before
-       # switch to ELF
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      freebsd-elf*)
-        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-        ;;
-
-      freebsd* | dragonfly*)
-        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
-        # conventions
-        _LT_TAGVAR(ld_shlibs, $1)=yes
-        ;;
-
-      haiku*)
-        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-        _LT_TAGVAR(link_all_deplibs, $1)=yes
-        ;;
-
-      hpux9*)
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-        _LT_TAGVAR(hardcode_direct, $1)=yes
-        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
-                                            # but as the default
-                                            # location of the library.
-
-        case $cc_basename in
-          CC*)
-            # FIXME: insert proper C++ library support
-            _LT_TAGVAR(ld_shlibs, $1)=no
-            ;;
-          aCC*)
-            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
-            # Commands to make compiler produce verbose output that lists
-            # what "hidden" libraries, object files and flags are used when
-            # linking a shared library.
-            #
-            # There doesn't appear to be a way to prevent this compiler from
-            # explicitly linking system object files so we need to strip them
-            # from the output so that they don't get included in the library
-            # dependencies.
-            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-            ;;
-          *)
-            if test yes = "$GXX"; then
-              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
-            else
-              # FIXME: insert proper C++ library support
-              _LT_TAGVAR(ld_shlibs, $1)=no
-            fi
-            ;;
-        esac
-        ;;
-
-      hpux10*|hpux11*)
-        if test no = "$with_gnu_ld"; then
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
-         _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-          case $host_cpu in
-            hppa*64*|ia64*)
-              ;;
-            *)
-             _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-              ;;
-          esac
-        fi
-        case $host_cpu in
-          hppa*64*|ia64*)
-            _LT_TAGVAR(hardcode_direct, $1)=no
-            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-            ;;
-          *)
-            _LT_TAGVAR(hardcode_direct, $1)=yes
-            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
-                                                # but as the default
-                                                # location of the library.
-            ;;
-        esac
-
-        case $cc_basename in
-          CC*)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          aCC*)
-           case $host_cpu in
-             hppa*64*)
-               _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-               ;;
-             ia64*)
-               _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-               ;;
-             *)
-               _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-               ;;
-           esac
-           # Commands to make compiler produce verbose output that lists
-           # what "hidden" libraries, object files and flags are used when
-           # linking a shared library.
-           #
-           # There doesn't appear to be a way to prevent this compiler from
-           # explicitly linking system object files so we need to strip them
-           # from the output so that they don't get included in the library
-           # dependencies.
-           output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-           ;;
-          *)
-           if test yes = "$GXX"; then
-             if test no = "$with_gnu_ld"; then
-               case $host_cpu in
-                 hppa*64*)
-                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-                   ;;
-                 ia64*)
-                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-                   ;;
-                 *)
-                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-                   ;;
-               esac
-             fi
-           else
-             # FIXME: insert proper C++ library support
-             _LT_TAGVAR(ld_shlibs, $1)=no
-           fi
-           ;;
-        esac
-        ;;
-
-      interix[[3-9]]*)
-       _LT_TAGVAR(hardcode_direct, $1)=no
-       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
-       _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-       # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
-       # Instead, shared libraries are loaded at an image base (0x10000000 by
-       # default) and relocated if they conflict, which is a slow very memory
-       # consuming and fragmenting process.  To avoid this, we pick a random,
-       # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
-       # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-       _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-       ;;
-      irix5* | irix6*)
-        case $cc_basename in
-          CC*)
-           # SGI C++
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-
-           # Archives containing C++ object files must be created using
-           # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
-           # necessary to make sure instantiated templates are included
-           # in the archive.
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
-           ;;
-          *)
-           if test yes = "$GXX"; then
-             if test no = "$with_gnu_ld"; then
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-             else
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
-             fi
-           fi
-           _LT_TAGVAR(link_all_deplibs, $1)=yes
-           ;;
-        esac
-        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-        _LT_TAGVAR(inherit_rpath, $1)=yes
-        ;;
-
-      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-        case $cc_basename in
-          KCC*)
-           # Kuck and Associates, Inc. (KAI) C++ Compiler
-
-           # KCC will only create a shared library if the output file
-           # ends with ".so" (or ".sl" for HP-UX), so rename the library
-           # to its proper name (with version) after linking.
-           _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
-           # Commands to make compiler produce verbose output that lists
-           # what "hidden" libraries, object files and flags are used when
-           # linking a shared library.
-           #
-           # There doesn't appear to be a way to prevent this compiler from
-           # explicitly linking system object files so we need to strip them
-           # from the output so that they don't get included in the library
-           # dependencies.
-           output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
-
-           # Archives containing C++ object files must be created using
-           # "CC -Bstatic", where "CC" is the KAI C++ compiler.
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
-           ;;
-         icpc* | ecpc* )
-           # Intel C++
-           with_gnu_ld=yes
-           # version 8.0 and above of icpc choke on multiply defined symbols
-           # if we add $predep_objects and $postdep_objects, however 7.1 and
-           # earlier do not add the objects themselves.
-           case `$CC -V 2>&1` in
-             *"Version 7."*)
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-               ;;
-             *)  # Version 8.0 or newer
-               tmp_idyn=
-               case $host_cpu in
-                 ia64*) tmp_idyn=' -i_dynamic';;
-               esac
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-               ;;
-           esac
-           _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
-           ;;
-          pgCC* | pgcpp*)
-            # Portland Group C++ compiler
-           case `$CC -V` in
-           *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
-             _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
-               rm -rf $tpldir~
-               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
-               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
-             _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
-                rm -rf $tpldir~
-                $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
-                $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
-                $RANLIB $oldlib'
-             _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
-                rm -rf $tpldir~
-                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
-             _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
-                rm -rf $tpldir~
-                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
-                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-             ;;
-           *) # Version 6 and above use weak symbols
-             _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
-             _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-             ;;
-           esac
-
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
-           _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-            ;;
-         cxx*)
-           # Compaq C++
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname  -o $lib $wl-retain-symbols-file $wl$export_symbols'
-
-           runpath_var=LD_RUN_PATH
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-           # Commands to make compiler produce verbose output that lists
-           # what "hidden" libraries, object files and flags are used when
-           # linking a shared library.
-           #
-           # There doesn't appear to be a way to prevent this compiler from
-           # explicitly linking system object files so we need to strip them
-           # from the output so that they don't get included in the library
-           # dependencies.
-           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
-           ;;
-         xl* | mpixl* | bgxl*)
-           # IBM XL 8.0 on PPC, with GNU ld
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
-           _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-           if test yes = "$supports_anon_versioning"; then
-             _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
-                cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-                echo "local: *; };" >> $output_objdir/$libname.ver~
-                $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
-           fi
-           ;;
-         *)
-           case `$CC -V 2>&1 | sed 5q` in
-           *Sun\ C*)
-             # Sun C++ 5.9
-             _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
-             _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-             _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
-             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-             _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-             _LT_TAGVAR(compiler_needs_object, $1)=yes
-
-             # Not sure whether something based on
-             # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
-             # would be better.
-             output_verbose_link_cmd='func_echo_all'
-
-             # Archives containing C++ object files must be created using
-             # "CC -xar", where "CC" is the Sun C++ compiler.  This is
-             # necessary to make sure instantiated templates are included
-             # in the archive.
-             _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
-             ;;
-           esac
-           ;;
-       esac
-       ;;
-
-      lynxos*)
-        # FIXME: insert proper C++ library support
-       _LT_TAGVAR(ld_shlibs, $1)=no
-       ;;
-
-      m88k*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-       ;;
-
-      mvs*)
-        case $cc_basename in
-          cxx*)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-         *)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-       esac
-       ;;
-
-      netbsd*)
-        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-         _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
-         wlarc=
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-         _LT_TAGVAR(hardcode_direct, $1)=yes
-         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       fi
-       # Workaround some broken pre-1.5 toolchains
-       output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
-       ;;
-
-      *nto* | *qnx*)
-        _LT_TAGVAR(ld_shlibs, $1)=yes
-       ;;
-
-      openbsd* | bitrig*)
-       if test -f /usr/libexec/ld.so; then
-         _LT_TAGVAR(hardcode_direct, $1)=yes
-         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
-         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
-         if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
-           _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-           _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
-         fi
-         output_verbose_link_cmd=func_echo_all
-       else
-         _LT_TAGVAR(ld_shlibs, $1)=no
-       fi
-       ;;
-
-      osf3* | osf4* | osf5*)
-        case $cc_basename in
-          KCC*)
-           # Kuck and Associates, Inc. (KAI) C++ Compiler
-
-           # KCC will only create a shared library if the output file
-           # ends with ".so" (or ".sl" for HP-UX), so rename the library
-           # to its proper name (with version) after linking.
-           _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
-           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-           # Archives containing C++ object files must be created using
-           # the KAI C++ compiler.
-           case $host in
-             osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
-             *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
-           esac
-           ;;
-          RCC*)
-           # Rational C++ 2.4.1
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          cxx*)
-           case $host in
-             osf3*)
-               _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-               _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-               ;;
-             *)
-               _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
-                  echo "-hidden">> $lib.exp~
-                  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
-                  $RM $lib.exp'
-               _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
-               ;;
-           esac
-
-           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-           # Commands to make compiler produce verbose output that lists
-           # what "hidden" libraries, object files and flags are used when
-           # linking a shared library.
-           #
-           # There doesn't appear to be a way to prevent this compiler from
-           # explicitly linking system object files so we need to strip them
-           # from the output so that they don't get included in the library
-           # dependencies.
-           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-           ;;
-         *)
-           if test yes,no = "$GXX,$with_gnu_ld"; then
-             _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
-             case $host in
-               osf3*)
-                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-                 ;;
-               *)
-                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-                 ;;
-             esac
-
-             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
-             _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
-             # Commands to make compiler produce verbose output that lists
-             # what "hidden" libraries, object files and flags are used when
-             # linking a shared library.
-             output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-
-           else
-             # FIXME: insert proper C++ library support
-             _LT_TAGVAR(ld_shlibs, $1)=no
-           fi
-           ;;
-        esac
-        ;;
-
-      psos*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      sunos4*)
-        case $cc_basename in
-          CC*)
-           # Sun C++ 4.x
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          lcc*)
-           # Lucid
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          *)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-        esac
-        ;;
-
-      solaris*)
-        case $cc_basename in
-          CC* | sunCC*)
-           # Sun C++ 4.2, 5.x and Centerline C++
-            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
-           _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
-           _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-              $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
-           _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-           case $host_os in
-             solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-             *)
-               # The compiler driver will combine and reorder linker options,
-               # but understands '-z linker_flag'.
-               # Supported since Solaris 2.6 (maybe 2.5.1?)
-               _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
-               ;;
-           esac
-           _LT_TAGVAR(link_all_deplibs, $1)=yes
-
-           output_verbose_link_cmd='func_echo_all'
-
-           # Archives containing C++ object files must be created using
-           # "CC -xar", where "CC" is the Sun C++ compiler.  This is
-           # necessary to make sure instantiated templates are included
-           # in the archive.
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
-           ;;
-          gcx*)
-           # Green Hills C++ Compiler
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
-
-           # The C++ compiler must be used to create the archive.
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
-           ;;
-          *)
-           # GNU C++ compiler with Solaris linker
-           if test yes,no = "$GXX,$with_gnu_ld"; then
-             _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
-             if $CC --version | $GREP -v '^2\.7' > /dev/null; then
-               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-                  $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-               # Commands to make compiler produce verbose output that lists
-               # what "hidden" libraries, object files and flags are used when
-               # linking a shared library.
-               output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-             else
-               # g++ 2.7 appears to require '-G' NOT '-shared' on this
-               # platform.
-               _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
-               _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-                  $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
-               # Commands to make compiler produce verbose output that lists
-               # what "hidden" libraries, object files and flags are used when
-               # linking a shared library.
-               output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
-             fi
-
-             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
-             case $host_os in
-               solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
-               *)
-                 _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
-                 ;;
-             esac
-           fi
-           ;;
-        esac
-        ;;
-
-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
-      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
-      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-      runpath_var='LD_RUN_PATH'
-
-      case $cc_basename in
-        CC*)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       *)
-         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-      esac
-      ;;
-
-      sysv5* | sco3.2v5* | sco5v6*)
-       # Note: We CANNOT use -z defs as we might desire, because we do not
-       # link with -lc, and that would cause any symbols used from libc to
-       # always be unresolved, which means just about no library would
-       # ever link correctly.  If we're not using GNU ld we use -z text
-       # though, which does catch some bad symbols but isn't as heavy-handed
-       # as -z defs.
-       _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
-       _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
-       _LT_TAGVAR(archive_cmds_need_lc, $1)=no
-       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
-       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
-       _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
-       _LT_TAGVAR(link_all_deplibs, $1)=yes
-       _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
-       runpath_var='LD_RUN_PATH'
-
-       case $cc_basename in
-          CC*)
-           _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
-              '"$_LT_TAGVAR(old_archive_cmds, $1)"
-           _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
-              '"$_LT_TAGVAR(reload_cmds, $1)"
-           ;;
-         *)
-           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-           ;;
-       esac
-      ;;
-
-      tandem*)
-        case $cc_basename in
-          NCC*)
-           # NonStop-UX NCC 3.20
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-          *)
-           # FIXME: insert proper C++ library support
-           _LT_TAGVAR(ld_shlibs, $1)=no
-           ;;
-        esac
-        ;;
-
-      vxworks*)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-
-      *)
-        # FIXME: insert proper C++ library support
-        _LT_TAGVAR(ld_shlibs, $1)=no
-        ;;
-    esac
-
-    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-    test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
-
-    _LT_TAGVAR(GCC, $1)=$GXX
-    _LT_TAGVAR(LD, $1)=$LD
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_SYS_HIDDEN_LIBDEPS($1)
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  CC=$lt_save_CC
-  CFLAGS=$lt_save_CFLAGS
-  LDCXX=$LD
-  LD=$lt_save_LD
-  GCC=$lt_save_GCC
-  with_gnu_ld=$lt_save_with_gnu_ld
-  lt_cv_path_LDCXX=$lt_cv_path_LD
-  lt_cv_path_LD=$lt_save_path_LD
-  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
-  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test yes != "$_lt_caught_CXX_error"
-
-AC_LANG_POP
-])# _LT_LANG_CXX_CONFIG
-
-
-# _LT_FUNC_STRIPNAME_CNF
-# ----------------------
-# func_stripname_cnf prefix suffix name
-# strip PREFIX and SUFFIX off of NAME.
-# PREFIX and SUFFIX must not contain globbing or regex special
-# characters, hashes, percent signs, but SUFFIX may contain a leading
-# dot (in which case that matches only a dot).
-#
-# This function is identical to the (non-XSI) version of func_stripname,
-# except this one can be used by m4 code that may be executed by configure,
-# rather than the libtool script.
-m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
-AC_REQUIRE([_LT_DECL_SED])
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
-func_stripname_cnf ()
-{
-  case @S|@2 in
-  .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
-  *)  func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
-  esac
-} # func_stripname_cnf
-])# _LT_FUNC_STRIPNAME_CNF
-
-
-# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
-# ---------------------------------
-# Figure out "hidden" library dependencies from verbose
-# compiler output when linking a shared library.
-# Parse the compiler output and extract the necessary
-# objects, libraries and library flags.
-m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
-# Dependencies to place before and after the object being linked:
-_LT_TAGVAR(predep_objects, $1)=
-_LT_TAGVAR(postdep_objects, $1)=
-_LT_TAGVAR(predeps, $1)=
-_LT_TAGVAR(postdeps, $1)=
-_LT_TAGVAR(compiler_lib_search_path, $1)=
-
-dnl we can't use the lt_simple_compile_test_code here,
-dnl because it contains code intended for an executable,
-dnl not a library.  It's possible we should let each
-dnl tag define a new lt_????_link_test_code variable,
-dnl but it's only used here...
-m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
-int a;
-void foo (void) { a = 0; }
-_LT_EOF
-], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
-class Foo
-{
-public:
-  Foo (void) { a = 0; }
-private:
-  int a;
-};
-_LT_EOF
-], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
-      subroutine foo
-      implicit none
-      integer*4 a
-      a=0
-      return
-      end
-_LT_EOF
-], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
-      subroutine foo
-      implicit none
-      integer a
-      a=0
-      return
-      end
-_LT_EOF
-], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
-public class foo {
-  private int a;
-  public void bar (void) {
-    a = 0;
-  }
-};
-_LT_EOF
-], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
-package foo
-func foo() {
-}
-_LT_EOF
-])
-
-_lt_libdeps_save_CFLAGS=$CFLAGS
-case "$CC $CFLAGS " in #(
-*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
-*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
-*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
-esac
-
-dnl Parse the compiler output and extract the necessary
-dnl objects, libraries and library flags.
-if AC_TRY_EVAL(ac_compile); then
-  # Parse the compiler output and extract the necessary
-  # objects, libraries and library flags.
-
-  # Sentinel used to keep track of whether or not we are before
-  # the conftest object file.
-  pre_test_object_deps_done=no
-
-  for p in `eval "$output_verbose_link_cmd"`; do
-    case $prev$p in
-
-    -L* | -R* | -l*)
-       # Some compilers place space between "-{L,R}" and the path.
-       # Remove the space.
-       if test x-L = "$p" ||
-          test x-R = "$p"; then
-        prev=$p
-        continue
-       fi
-
-       # Expand the sysroot to ease extracting the directories later.
-       if test -z "$prev"; then
-         case $p in
-         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
-         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
-         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
-         esac
-       fi
-       case $p in
-       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
-       esac
-       if test no = "$pre_test_object_deps_done"; then
-        case $prev in
-        -L | -R)
-          # Internal compiler library paths should come after those
-          # provided the user.  The postdeps already come after the
-          # user supplied libs so there is no need to process them.
-          if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
-            _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
-          else
-            _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
-          fi
-          ;;
-        # The "-l" case would never come before the object being
-        # linked, so don't bother handling this case.
-        esac
-       else
-        if test -z "$_LT_TAGVAR(postdeps, $1)"; then
-          _LT_TAGVAR(postdeps, $1)=$prev$p
-        else
-          _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
-        fi
-       fi
-       prev=
-       ;;
-
-    *.lto.$objext) ;; # Ignore GCC LTO objects
-    *.$objext)
-       # This assumes that the test object file only shows up
-       # once in the compiler output.
-       if test "$p" = "conftest.$objext"; then
-        pre_test_object_deps_done=yes
-        continue
-       fi
-
-       if test no = "$pre_test_object_deps_done"; then
-        if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
-          _LT_TAGVAR(predep_objects, $1)=$p
-        else
-          _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
-        fi
-       else
-        if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
-          _LT_TAGVAR(postdep_objects, $1)=$p
-        else
-          _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
-        fi
-       fi
-       ;;
-
-    *) ;; # Ignore the rest.
-
-    esac
-  done
-
-  # Clean up.
-  rm -f a.out a.exe
-else
-  echo "libtool.m4: error: problem compiling $1 test program"
-fi
-
-$RM -f confest.$objext
-CFLAGS=$_lt_libdeps_save_CFLAGS
-
-# PORTME: override above test on systems where it is broken
-m4_if([$1], [CXX],
-[case $host_os in
-interix[[3-9]]*)
-  # Interix 3.5 installs completely hosed .la files for C++, so rather than
-  # hack all around it, let's just trust "g++" to DTRT.
-  _LT_TAGVAR(predep_objects,$1)=
-  _LT_TAGVAR(postdep_objects,$1)=
-  _LT_TAGVAR(postdeps,$1)=
-  ;;
-esac
-])
-
-case " $_LT_TAGVAR(postdeps, $1) " in
-*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
-esac
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=
-if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
-fi
-_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
-    [The directories searched by this compiler when creating a shared library])
-_LT_TAGDECL([], [predep_objects], [1],
-    [Dependencies to place before and after the objects being linked to
-    create a shared library])
-_LT_TAGDECL([], [postdep_objects], [1])
-_LT_TAGDECL([], [predeps], [1])
-_LT_TAGDECL([], [postdeps], [1])
-_LT_TAGDECL([], [compiler_lib_search_path], [1],
-    [The library search path used internally by the compiler when linking
-    a shared library])
-])# _LT_SYS_HIDDEN_LIBDEPS
-
-
-# _LT_LANG_F77_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for a Fortran 77 compiler are
-# suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_F77_CONFIG],
-[AC_LANG_PUSH(Fortran 77)
-if test -z "$F77" || test no = "$F77"; then
-  _lt_disable_F77=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for f77 test sources.
-ac_ext=f
-
-# Object file extension for compiled f77 test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the F77 compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test yes != "$_lt_disable_F77"; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="\
-      subroutine t
-      return
-      end
-"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code="\
-      program t
-      end
-"
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC=$CC
-  lt_save_GCC=$GCC
-  lt_save_CFLAGS=$CFLAGS
-  CC=${F77-"f77"}
-  CFLAGS=$FFLAGS
-  compiler=$CC
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-  GCC=$G77
-  if test -n "$compiler"; then
-    AC_MSG_CHECKING([if libtool supports shared libraries])
-    AC_MSG_RESULT([$can_build_shared])
-
-    AC_MSG_CHECKING([whether to build shared libraries])
-    test no = "$can_build_shared" && enable_shared=no
-
-    # On AIX, shared libraries and static libraries use the same namespace, and
-    # are all built from PIC.
-    case $host_os in
-      aix3*)
-        test yes = "$enable_shared" && enable_static=no
-        if test -n "$RANLIB"; then
-          archive_cmds="$archive_cmds~\$RANLIB \$lib"
-          postinstall_cmds='$RANLIB $lib'
-        fi
-        ;;
-      aix[[4-9]]*)
-       if test ia64 != "$host_cpu"; then
-         case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
-         yes,aix,yes) ;;               # shared object as lib.so file only
-         yes,svr4,*) ;;                # shared object as lib.so archive member only
-         yes,*) enable_static=no ;;    # shared object in lib.a archive as well
-         esac
-       fi
-        ;;
-    esac
-    AC_MSG_RESULT([$enable_shared])
-
-    AC_MSG_CHECKING([whether to build static libraries])
-    # Make sure either enable_shared or enable_static is yes.
-    test yes = "$enable_shared" || enable_static=yes
-    AC_MSG_RESULT([$enable_static])
-
-    _LT_TAGVAR(GCC, $1)=$G77
-    _LT_TAGVAR(LD, $1)=$LD
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  GCC=$lt_save_GCC
-  CC=$lt_save_CC
-  CFLAGS=$lt_save_CFLAGS
-fi # test yes != "$_lt_disable_F77"
-
-AC_LANG_POP
-])# _LT_LANG_F77_CONFIG
-
-
-# _LT_LANG_FC_CONFIG([TAG])
-# -------------------------
-# Ensure that the configuration variables for a Fortran compiler are
-# suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_FC_CONFIG],
-[AC_LANG_PUSH(Fortran)
-
-if test -z "$FC" || test no = "$FC"; then
-  _lt_disable_FC=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for fc test sources.
-ac_ext=${ac_fc_srcext-f}
-
-# Object file extension for compiled fc test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the FC compiler isn't working.  Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test yes != "$_lt_disable_FC"; then
-  # Code to be used in simple compile tests
-  lt_simple_compile_test_code="\
-      subroutine t
-      return
-      end
-"
-
-  # Code to be used in simple link tests
-  lt_simple_link_test_code="\
-      program t
-      end
-"
-
-  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
-  _LT_TAG_COMPILER
-
-  # save warnings/boilerplate of simple test code
-  _LT_COMPILER_BOILERPLATE
-  _LT_LINKER_BOILERPLATE
-
-  # Allow CC to be a program name with arguments.
-  lt_save_CC=$CC
-  lt_save_GCC=$GCC
-  lt_save_CFLAGS=$CFLAGS
-  CC=${FC-"f95"}
-  CFLAGS=$FCFLAGS
-  compiler=$CC
-  GCC=$ac_cv_fc_compiler_gnu
-
-  _LT_TAGVAR(compiler, $1)=$CC
-  _LT_CC_BASENAME([$compiler])
-
-  if test -n "$compiler"; then
-    AC_MSG_CHECKING([if libtool supports shared libraries])
-    AC_MSG_RESULT([$can_build_shared])
-
-    AC_MSG_CHECKING([whether to build shared libraries])
-    test no = "$can_build_shared" && enable_shared=no
-
-    # On AIX, shared libraries and static libraries use the same namespace, and
-    # are all built from PIC.
-    case $host_os in
-      aix3*)
-        test yes = "$enable_shared" && enable_static=no
-        if test -n "$RANLIB"; then
-          archive_cmds="$archive_cmds~\$RANLIB \$lib"
-          postinstall_cmds='$RANLIB $lib'
-        fi
-        ;;
-      aix[[4-9]]*)
-       if test ia64 != "$host_cpu"; then
-         case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
-         yes,aix,yes) ;;               # shared object as lib.so file only
-         yes,svr4,*) ;;                # shared object as lib.so archive member only
-         yes,*) enable_static=no ;;    # shared object in lib.a archive as well
-         esac
-       fi
-        ;;
-    esac
-    AC_MSG_RESULT([$enable_shared])
-
-    AC_MSG_CHECKING([whether to build static libraries])
-    # Make sure either enable_shared or enable_static is yes.
-    test yes = "$enable_shared" || enable_static=yes
-    AC_MSG_RESULT([$enable_static])
-
-    _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
-    _LT_TAGVAR(LD, $1)=$LD
-
-    ## CAVEAT EMPTOR:
-    ## There is no encapsulation within the following macros, do not change
-    ## the running order or otherwise move them around unless you know exactly
-    ## what you are doing...
-    _LT_SYS_HIDDEN_LIBDEPS($1)
-    _LT_COMPILER_PIC($1)
-    _LT_COMPILER_C_O($1)
-    _LT_COMPILER_FILE_LOCKS($1)
-    _LT_LINKER_SHLIBS($1)
-    _LT_SYS_DYNAMIC_LINKER($1)
-    _LT_LINKER_HARDCODE_LIBPATH($1)
-
-    _LT_CONFIG($1)
-  fi # test -n "$compiler"
-
-  GCC=$lt_save_GCC
-  CC=$lt_save_CC
-  CFLAGS=$lt_save_CFLAGS
-fi # test yes != "$_lt_disable_FC"
-
-AC_LANG_POP
-])# _LT_LANG_FC_CONFIG
-
-
-# _LT_LANG_GCJ_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for the GNU Java Compiler compiler
-# are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_GCJ_CONFIG],
-[AC_REQUIRE([LT_PROG_GCJ])dnl
-AC_LANG_SAVE
-
-# Source file extension for Java test sources.
-ac_ext=java
-
-# Object file extension for compiled Java test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="class foo {}"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GCJ-"gcj"}
-CFLAGS=$GCJFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)=$LD
-_LT_CC_BASENAME([$compiler])
-
-# GCJ did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-## CAVEAT EMPTOR:
-## There is no encapsulation within the following macros, do not change
-## the running order or otherwise move them around unless you know exactly
-## what you are doing...
-if test -n "$compiler"; then
-  _LT_COMPILER_NO_RTTI($1)
-  _LT_COMPILER_PIC($1)
-  _LT_COMPILER_C_O($1)
-  _LT_COMPILER_FILE_LOCKS($1)
-  _LT_LINKER_SHLIBS($1)
-  _LT_LINKER_HARDCODE_LIBPATH($1)
-
-  _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GCJ_CONFIG
-
-
-# _LT_LANG_GO_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for the GNU Go compiler
-# are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_GO_CONFIG],
-[AC_REQUIRE([LT_PROG_GO])dnl
-AC_LANG_SAVE
-
-# Source file extension for Go test sources.
-ac_ext=go
-
-# Object file extension for compiled Go test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="package main; func main() { }"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='package main; func main() { }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GOC-"gccgo"}
-CFLAGS=$GOFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)=$LD
-_LT_CC_BASENAME([$compiler])
-
-# Go did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-## CAVEAT EMPTOR:
-## There is no encapsulation within the following macros, do not change
-## the running order or otherwise move them around unless you know exactly
-## what you are doing...
-if test -n "$compiler"; then
-  _LT_COMPILER_NO_RTTI($1)
-  _LT_COMPILER_PIC($1)
-  _LT_COMPILER_C_O($1)
-  _LT_COMPILER_FILE_LOCKS($1)
-  _LT_LINKER_SHLIBS($1)
-  _LT_LINKER_HARDCODE_LIBPATH($1)
-
-  _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GO_CONFIG
-
-
-# _LT_LANG_RC_CONFIG([TAG])
-# -------------------------
-# Ensure that the configuration variables for the Windows resource compiler
-# are suitably defined.  These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_RC_CONFIG],
-[AC_REQUIRE([LT_PROG_RC])dnl
-AC_LANG_SAVE
-
-# Source file extension for RC test sources.
-ac_ext=rc
-
-# Object file extension for compiled RC test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
-
-# Code to be used in simple link tests
-lt_simple_link_test_code=$lt_simple_compile_test_code
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=
-CC=${RC-"windres"}
-CFLAGS=
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_CC_BASENAME([$compiler])
-_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
-
-if test -n "$compiler"; then
-  :
-  _LT_CONFIG($1)
-fi
-
-GCC=$lt_save_GCC
-AC_LANG_RESTORE
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_RC_CONFIG
-
-
-# LT_PROG_GCJ
-# -----------
-AC_DEFUN([LT_PROG_GCJ],
-[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
-  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
-    [AC_CHECK_TOOL(GCJ, gcj,)
-      test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
-      AC_SUBST(GCJFLAGS)])])[]dnl
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
-
-
-# LT_PROG_GO
-# ----------
-AC_DEFUN([LT_PROG_GO],
-[AC_CHECK_TOOL(GOC, gccgo,)
-])
-
-
-# LT_PROG_RC
-# ----------
-AC_DEFUN([LT_PROG_RC],
-[AC_CHECK_TOOL(RC, windres,)
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_RC], [])
-
-
-# _LT_DECL_EGREP
-# --------------
-# If we don't have a new enough Autoconf to choose the best grep
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_EGREP],
-[AC_REQUIRE([AC_PROG_EGREP])dnl
-AC_REQUIRE([AC_PROG_FGREP])dnl
-test -z "$GREP" && GREP=grep
-_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
-_LT_DECL([], [EGREP], [1], [An ERE matcher])
-_LT_DECL([], [FGREP], [1], [A literal string matcher])
-dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
-AC_SUBST([GREP])
-])
-
-
-# _LT_DECL_OBJDUMP
-# --------------
-# If we don't have a new enough Autoconf to choose the best objdump
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_OBJDUMP],
-[AC_CHECK_TOOL(OBJDUMP, objdump, false)
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
-AC_SUBST([OBJDUMP])
-])
-
-# _LT_DECL_DLLTOOL
-# ----------------
-# Ensure DLLTOOL variable is set.
-m4_defun([_LT_DECL_DLLTOOL],
-[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
-AC_SUBST([DLLTOOL])
-])
-
-# _LT_DECL_SED
-# ------------
-# Check for a fully-functional sed program, that truncates
-# as few characters as possible.  Prefer GNU sed if found.
-m4_defun([_LT_DECL_SED],
-[AC_PROG_SED
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
-_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
-_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
-    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
-])# _LT_DECL_SED
-
-m4_ifndef([AC_PROG_SED], [
-############################################################
-# NOTE: This macro has been submitted for inclusion into   #
-#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
-#  a released version of Autoconf we should remove this    #
-#  macro and use it instead.                               #
-############################################################
-
-m4_defun([AC_PROG_SED],
-[AC_MSG_CHECKING([for a sed that does not truncate output])
-AC_CACHE_VAL(lt_cv_path_SED,
-[# Loop through the user's path and test for sed and gsed.
-# Then use that list of sed's as ones to test for truncation.
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for lt_ac_prog in sed gsed; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
-        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
-      fi
-    done
-  done
-done
-IFS=$as_save_IFS
-lt_ac_max=0
-lt_ac_count=0
-# Add /usr/xpg4/bin/sed as it is typically found on Solaris
-# along with /bin/sed that truncates output.
-for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
-  test ! -f "$lt_ac_sed" && continue
-  cat /dev/null > conftest.in
-  lt_ac_count=0
-  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
-  # Check for GNU sed and select it if it is found.
-  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
-    lt_cv_path_SED=$lt_ac_sed
-    break
-  fi
-  while true; do
-    cat conftest.in conftest.in >conftest.tmp
-    mv conftest.tmp conftest.in
-    cp conftest.in conftest.nl
-    echo >>conftest.nl
-    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
-    cmp -s conftest.out conftest.nl || break
-    # 10000 chars as input seems more than enough
-    test 10 -lt "$lt_ac_count" && break
-    lt_ac_count=`expr $lt_ac_count + 1`
-    if test "$lt_ac_count" -gt "$lt_ac_max"; then
-      lt_ac_max=$lt_ac_count
-      lt_cv_path_SED=$lt_ac_sed
-    fi
-  done
-done
-])
-SED=$lt_cv_path_SED
-AC_SUBST([SED])
-AC_MSG_RESULT([$SED])
-])#AC_PROG_SED
-])#m4_ifndef
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_SED], [])
-
-
-# _LT_CHECK_SHELL_FEATURES
-# ------------------------
-# Find out whether the shell is Bourne or XSI compatible,
-# or has some other useful features.
-m4_defun([_LT_CHECK_SHELL_FEATURES],
-[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  lt_unset=unset
-else
-  lt_unset=false
-fi
-_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
-
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
-    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
-  lt_SP2NL='tr \040 \012'
-  lt_NL2SP='tr \015\012 \040\040'
-  ;;
- *) # EBCDIC based system
-  lt_SP2NL='tr \100 \n'
-  lt_NL2SP='tr \r\n \100\100'
-  ;;
-esac
-_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
-_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
-])# _LT_CHECK_SHELL_FEATURES
-
-
-# _LT_PATH_CONVERSION_FUNCTIONS
-# -----------------------------
-# Determine what file name conversion functions should be used by
-# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
-# for certain cross-compile configurations and native mingw.
-m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_MSG_CHECKING([how to convert $build file names to $host format])
-AC_CACHE_VAL(lt_cv_to_host_file_cmd,
-[case $host in
-  *-*-mingw* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
-        ;;
-      *-*-cygwin* )
-        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
-        ;;
-      * ) # otherwise, assume *nix
-        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
-        ;;
-    esac
-    ;;
-  *-*-cygwin* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
-        ;;
-      *-*-cygwin* )
-        lt_cv_to_host_file_cmd=func_convert_file_noop
-        ;;
-      * ) # otherwise, assume *nix
-        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
-        ;;
-    esac
-    ;;
-  * ) # unhandled hosts (and "normal" native builds)
-    lt_cv_to_host_file_cmd=func_convert_file_noop
-    ;;
-esac
-])
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
-_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
-         [0], [convert $build file names to $host format])dnl
-
-AC_MSG_CHECKING([how to convert $build file names to toolchain format])
-AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
-[#assume ordinary cross tools, or native build.
-lt_cv_to_tool_file_cmd=func_convert_file_noop
-case $host in
-  *-*-mingw* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
-        ;;
-    esac
-    ;;
-esac
-])
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
-_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
-         [0], [convert $build files to toolchain format])dnl
-])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/zfs/config/ltmain.sh b/zfs/config/ltmain.sh
deleted file mode 100644 (file)
index 2ad8be8..0000000
+++ /dev/null
@@ -1,11156 +0,0 @@
-#! /bin/sh
-## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
-##               by inline-source v2014-01-03.01
-
-# libtool (GNU libtool) 2.4.6
-# Provide generalized library-building support services.
-# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-
-# Copyright (C) 1996-2015 Free Software Foundation, Inc.
-# This is free software; see the source for copying conditions.  There is NO
-# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-# GNU Libtool is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# As a special exception to the GNU General Public License,
-# if you distribute this file as part of a program or library that
-# is built using GNU Libtool, you may include this file under the
-# same distribution terms that you use for the rest of that program.
-#
-# GNU Libtool is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-PROGRAM=libtool
-PACKAGE=libtool
-VERSION="2.4.6 Debian-2.4.6-1"
-package_revision=2.4.6
-
-
-## ------ ##
-## Usage. ##
-## ------ ##
-
-# Run './libtool --help' for help with using this script from the
-# command line.
-
-
-## ------------------------------- ##
-## User overridable command paths. ##
-## ------------------------------- ##
-
-# After configure completes, it has a better idea of some of the
-# shell tools we need than the defaults used by the functions shared
-# with bootstrap, so set those here where they can still be over-
-# ridden by the user, but otherwise take precedence.
-
-: ${AUTOCONF="autoconf"}
-: ${AUTOMAKE="automake"}
-
-
-## -------------------------- ##
-## Source external libraries. ##
-## -------------------------- ##
-
-# Much of our low-level functionality needs to be sourced from external
-# libraries, which are installed to $pkgauxdir.
-
-# Set a version string for this script.
-scriptversion=2015-01-20.17; # UTC
-
-# General shell script boiler plate, and helper functions.
-# Written by Gary V. Vaughan, 2004
-
-# Copyright (C) 2004-2015 Free Software Foundation, Inc.
-# This is free software; see the source for copying conditions.  There is NO
-# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-
-# As a special exception to the GNU General Public License, if you distribute
-# this file as part of a program or library that is built using GNU Libtool,
-# you may include this file under the same distribution terms that you use
-# for the rest of that program.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# Please report bugs or propose patches to gary@gnu.org.
-
-
-## ------ ##
-## Usage. ##
-## ------ ##
-
-# Evaluate this file near the top of your script to gain access to
-# the functions and variables defined here:
-#
-#   . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
-#
-# If you need to override any of the default environment variable
-# settings, do that before evaluating this file.
-
-
-## -------------------- ##
-## Shell normalisation. ##
-## -------------------- ##
-
-# Some shells need a little help to be as Bourne compatible as possible.
-# Before doing anything else, make sure all that help has been provided!
-
-DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
-fi
-
-# NLS nuisances: We save the old values in case they are required later.
-_G_user_locale=
-_G_safe_locale=
-for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
-do
-  eval "if test set = \"\${$_G_var+set}\"; then
-          save_$_G_var=\$$_G_var
-          $_G_var=C
-         export $_G_var
-         _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
-         _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
-       fi"
-done
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-# Make sure IFS has a sensible default
-sp=' '
-nl='
-'
-IFS="$sp       $nl"
-
-# There are apparently some retarded systems that use ';' as a PATH separator!
-if test "${PATH_SEPARATOR+set}" != set; then
-  PATH_SEPARATOR=:
-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
-      PATH_SEPARATOR=';'
-  }
-fi
-
-
-
-## ------------------------- ##
-## Locate command utilities. ##
-## ------------------------- ##
-
-
-# func_executable_p FILE
-# ----------------------
-# Check that FILE is an executable regular file.
-func_executable_p ()
-{
-    test -f "$1" && test -x "$1"
-}
-
-
-# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
-# --------------------------------------------
-# Search for either a program that responds to --version with output
-# containing "GNU", or else returned by CHECK_FUNC otherwise, by
-# trying all the directories in PATH with each of the elements of
-# PROGS_LIST.
-#
-# CHECK_FUNC should accept the path to a candidate program, and
-# set $func_check_prog_result if it truncates its output less than
-# $_G_path_prog_max characters.
-func_path_progs ()
-{
-    _G_progs_list=$1
-    _G_check_func=$2
-    _G_PATH=${3-"$PATH"}
-
-    _G_path_prog_max=0
-    _G_path_prog_found=false
-    _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
-    for _G_dir in $_G_PATH; do
-      IFS=$_G_save_IFS
-      test -z "$_G_dir" && _G_dir=.
-      for _G_prog_name in $_G_progs_list; do
-        for _exeext in '' .EXE; do
-          _G_path_prog=$_G_dir/$_G_prog_name$_exeext
-          func_executable_p "$_G_path_prog" || continue
-          case `"$_G_path_prog" --version 2>&1` in
-            *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
-            *)     $_G_check_func $_G_path_prog
-                  func_path_progs_result=$func_check_prog_result
-                  ;;
-          esac
-          $_G_path_prog_found && break 3
-        done
-      done
-    done
-    IFS=$_G_save_IFS
-    test -z "$func_path_progs_result" && {
-      echo "no acceptable sed could be found in \$PATH" >&2
-      exit 1
-    }
-}
-
-
-# We want to be able to use the functions in this file before configure
-# has figured out where the best binaries are kept, which means we have
-# to search for them ourselves - except when the results are already set
-# where we skip the searches.
-
-# Unless the user overrides by setting SED, search the path for either GNU
-# sed, or the sed that truncates its output the least.
-test -z "$SED" && {
-  _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
-  for _G_i in 1 2 3 4 5 6 7; do
-    _G_sed_script=$_G_sed_script$nl$_G_sed_script
-  done
-  echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
-  _G_sed_script=
-
-  func_check_prog_sed ()
-  {
-    _G_path_prog=$1
-
-    _G_count=0
-    printf 0123456789 >conftest.in
-    while :
-    do
-      cat conftest.in conftest.in >conftest.tmp
-      mv conftest.tmp conftest.in
-      cp conftest.in conftest.nl
-      echo '' >> conftest.nl
-      "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
-      diff conftest.out conftest.nl >/dev/null 2>&1 || break
-      _G_count=`expr $_G_count + 1`
-      if test "$_G_count" -gt "$_G_path_prog_max"; then
-        # Best one so far, save it but keep looking for a better one
-        func_check_prog_result=$_G_path_prog
-        _G_path_prog_max=$_G_count
-      fi
-      # 10*(2^10) chars as input seems more than enough
-      test 10 -lt "$_G_count" && break
-    done
-    rm -f conftest.in conftest.tmp conftest.nl conftest.out
-  }
-
-  func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
-  rm -f conftest.sed
-  SED=$func_path_progs_result
-}
-
-
-# Unless the user overrides by setting GREP, search the path for either GNU
-# grep, or the grep that truncates its output the least.
-test -z "$GREP" && {
-  func_check_prog_grep ()
-  {
-    _G_path_prog=$1
-
-    _G_count=0
-    _G_path_prog_max=0
-    printf 0123456789 >conftest.in
-    while :
-    do
-      cat conftest.in conftest.in >conftest.tmp
-      mv conftest.tmp conftest.in
-      cp conftest.in conftest.nl
-      echo 'GREP' >> conftest.nl
-      "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
-      diff conftest.out conftest.nl >/dev/null 2>&1 || break
-      _G_count=`expr $_G_count + 1`
-      if test "$_G_count" -gt "$_G_path_prog_max"; then
-        # Best one so far, save it but keep looking for a better one
-        func_check_prog_result=$_G_path_prog
-        _G_path_prog_max=$_G_count
-      fi
-      # 10*(2^10) chars as input seems more than enough
-      test 10 -lt "$_G_count" && break
-    done
-    rm -f conftest.in conftest.tmp conftest.nl conftest.out
-  }
-
-  func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
-  GREP=$func_path_progs_result
-}
-
-
-## ------------------------------- ##
-## User overridable command paths. ##
-## ------------------------------- ##
-
-# All uppercase variable names are used for environment variables.  These
-# variables can be overridden by the user before calling a script that
-# uses them if a suitable command of that name is not already available
-# in the command search PATH.
-
-: ${CP="cp -f"}
-: ${ECHO="printf %s\n"}
-: ${EGREP="$GREP -E"}
-: ${FGREP="$GREP -F"}
-: ${LN_S="ln -s"}
-: ${MAKE="make"}
-: ${MKDIR="mkdir"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
-
-
-## -------------------- ##
-## Useful sed snippets. ##
-## -------------------- ##
-
-sed_dirname='s|/[^/]*$||'
-sed_basename='s|^.*/||'
-
-# Sed substitution that helps us do robust quoting.  It backslashifies
-# metacharacters that are still active within double-quoted strings.
-sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
-
-# Same as above, but do not quote variable references.
-sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
-
-# Sed substitution that turns a string into a regex matching for the
-# string literally.
-sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
-
-# Sed substitution that converts a w32 file name or path
-# that contains forward slashes, into one that contains
-# (escaped) backslashes.  A very naive implementation.
-sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
-
-# Re-'\' parameter expansions in output of sed_double_quote_subst that
-# were '\'-ed in input to the same.  If an odd number of '\' preceded a
-# '$' in input to sed_double_quote_subst, that '$' was protected from
-# expansion.  Since each input '\' is now two '\'s, look for any number
-# of runs of four '\'s followed by two '\'s and then a '$'.  '\' that '$'.
-_G_bs='\\'
-_G_bs2='\\\\'
-_G_bs4='\\\\\\\\'
-_G_dollar='\$'
-sed_double_backslash="\
-  s/$_G_bs4/&\\
-/g
-  s/^$_G_bs2$_G_dollar/$_G_bs&/
-  s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
-  s/\n//g"
-
-
-## ----------------- ##
-## Global variables. ##
-## ----------------- ##
-
-# Except for the global variables explicitly listed below, the following
-# functions in the '^func_' namespace, and the '^require_' namespace
-# variables initialised in the 'Resource management' section, sourcing
-# this file will not pollute your global namespace with anything
-# else. There's no portable way to scope variables in Bourne shell
-# though, so actually running these functions will sometimes place
-# results into a variable named after the function, and often use
-# temporary variables in the '^_G_' namespace. If you are careful to
-# avoid using those namespaces casually in your sourcing script, things
-# should continue to work as you expect. And, of course, you can freely
-# overwrite any of the functions or variables defined here before
-# calling anything to customize them.
-
-EXIT_SUCCESS=0
-EXIT_FAILURE=1
-EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
-EXIT_SKIP=77     # $? = 77 is used to indicate a skipped test to automake.
-
-# Allow overriding, eg assuming that you follow the convention of
-# putting '$debug_cmd' at the start of all your functions, you can get
-# bash to show function call trace with:
-#
-#    debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
-debug_cmd=${debug_cmd-":"}
-exit_cmd=:
-
-# By convention, finish your script with:
-#
-#    exit $exit_status
-#
-# so that you can set exit_status to non-zero if you want to indicate
-# something went wrong during execution without actually bailing out at
-# the point of failure.
-exit_status=$EXIT_SUCCESS
-
-# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
-# is ksh but when the shell is invoked as "sh" and the current value of
-# the _XPG environment variable is not equal to 1 (one), the special
-# positional parameter $0, within a function call, is the name of the
-# function.
-progpath=$0
-
-# The name of this program.
-progname=`$ECHO "$progpath" |$SED "$sed_basename"`
-
-# Make sure we have an absolute progpath for reexecution:
-case $progpath in
-  [\\/]*|[A-Za-z]:\\*) ;;
-  *[\\/]*)
-     progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
-     progdir=`cd "$progdir" && pwd`
-     progpath=$progdir/$progname
-     ;;
-  *)
-     _G_IFS=$IFS
-     IFS=${PATH_SEPARATOR-:}
-     for progdir in $PATH; do
-       IFS=$_G_IFS
-       test -x "$progdir/$progname" && break
-     done
-     IFS=$_G_IFS
-     test -n "$progdir" || progdir=`pwd`
-     progpath=$progdir/$progname
-     ;;
-esac
-
-
-## ----------------- ##
-## Standard options. ##
-## ----------------- ##
-
-# The following options affect the operation of the functions defined
-# below, and should be set appropriately depending on run-time para-
-# meters passed on the command line.
-
-opt_dry_run=false
-opt_quiet=false
-opt_verbose=false
-
-# Categories 'all' and 'none' are always available.  Append any others
-# you will pass as the first argument to func_warning from your own
-# code.
-warning_categories=
-
-# By default, display warnings according to 'opt_warning_types'.  Set
-# 'warning_func'  to ':' to elide all warnings, or func_fatal_error to
-# treat the next displayed warning as a fatal error.
-warning_func=func_warn_and_continue
-
-# Set to 'all' to display all warnings, 'none' to suppress all
-# warnings, or a space delimited list of some subset of
-# 'warning_categories' to display only the listed warnings.
-opt_warning_types=all
-
-
-## -------------------- ##
-## Resource management. ##
-## -------------------- ##
-
-# This section contains definitions for functions that each ensure a
-# particular resource (a file, or a non-empty configuration variable for
-# example) is available, and if appropriate to extract default values
-# from pertinent package files. Call them using their associated
-# 'require_*' variable to ensure that they are executed, at most, once.
-#
-# It's entirely deliberate that calling these functions can set
-# variables that don't obey the namespace limitations obeyed by the rest
-# of this file, in order that that they be as useful as possible to
-# callers.
-
-
-# require_term_colors
-# -------------------
-# Allow display of bold text on terminals that support it.
-require_term_colors=func_require_term_colors
-func_require_term_colors ()
-{
-    $debug_cmd
-
-    test -t 1 && {
-      # COLORTERM and USE_ANSI_COLORS environment variables take
-      # precedence, because most terminfo databases neglect to describe
-      # whether color sequences are supported.
-      test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
-
-      if test 1 = "$USE_ANSI_COLORS"; then
-        # Standard ANSI escape sequences
-        tc_reset='\e[0m'
-        tc_bold='\e[1m';   tc_standout='\e[7m'
-        tc_red='\e[31m';   tc_green='\e[32m'
-        tc_blue='\e[34m';  tc_cyan='\e[36m'
-      else
-        # Otherwise trust the terminfo database after all.
-        test -n "`tput sgr0 2>/dev/null`" && {
-          tc_reset=`tput sgr0`
-          test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
-          tc_standout=$tc_bold
-          test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
-          test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
-          test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
-          test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
-          test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
-        }
-      fi
-    }
-
-    require_term_colors=:
-}
-
-
-## ----------------- ##
-## Function library. ##
-## ----------------- ##
-
-# This section contains a variety of useful functions to call in your
-# scripts. Take note of the portable wrappers for features provided by
-# some modern shells, which will fall back to slower equivalents on
-# less featureful shells.
-
-
-# func_append VAR VALUE
-# ---------------------
-# Append VALUE onto the existing contents of VAR.
-
-  # We should try to minimise forks, especially on Windows where they are
-  # unreasonably slow, so skip the feature probes when bash or zsh are
-  # being used:
-  if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
-    : ${_G_HAVE_ARITH_OP="yes"}
-    : ${_G_HAVE_XSI_OPS="yes"}
-    # The += operator was introduced in bash 3.1
-    case $BASH_VERSION in
-      [12].* | 3.0 | 3.0*) ;;
-      *)
-        : ${_G_HAVE_PLUSEQ_OP="yes"}
-        ;;
-    esac
-  fi
-
-  # _G_HAVE_PLUSEQ_OP
-  # Can be empty, in which case the shell is probed, "yes" if += is
-  # useable or anything else if it does not work.
-  test -z "$_G_HAVE_PLUSEQ_OP" \
-    && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
-    && _G_HAVE_PLUSEQ_OP=yes
-
-if test yes = "$_G_HAVE_PLUSEQ_OP"
-then
-  # This is an XSI compatible shell, allowing a faster implementation...
-  eval 'func_append ()
-  {
-    $debug_cmd
-
-    eval "$1+=\$2"
-  }'
-else
-  # ...otherwise fall back to using expr, which is often a shell builtin.
-  func_append ()
-  {
-    $debug_cmd
-
-    eval "$1=\$$1\$2"
-  }
-fi
-
-
-# func_append_quoted VAR VALUE
-# ----------------------------
-# Quote VALUE and append to the end of shell variable VAR, separated
-# by a space.
-if test yes = "$_G_HAVE_PLUSEQ_OP"; then
-  eval 'func_append_quoted ()
-  {
-    $debug_cmd
-
-    func_quote_for_eval "$2"
-    eval "$1+=\\ \$func_quote_for_eval_result"
-  }'
-else
-  func_append_quoted ()
-  {
-    $debug_cmd
-
-    func_quote_for_eval "$2"
-    eval "$1=\$$1\\ \$func_quote_for_eval_result"
-  }
-fi
-
-
-# func_append_uniq VAR VALUE
-# --------------------------
-# Append unique VALUE onto the existing contents of VAR, assuming
-# entries are delimited by the first character of VALUE.  For example:
-#
-#   func_append_uniq options " --another-option option-argument"
-#
-# will only append to $options if " --another-option option-argument "
-# is not already present somewhere in $options already (note spaces at
-# each end implied by leading space in second argument).
-func_append_uniq ()
-{
-    $debug_cmd
-
-    eval _G_current_value='`$ECHO $'$1'`'
-    _G_delim=`expr "$2" : '\(.\)'`
-
-    case $_G_delim$_G_current_value$_G_delim in
-      *"$2$_G_delim"*) ;;
-      *) func_append "$@" ;;
-    esac
-}
-
-
-# func_arith TERM...
-# ------------------
-# Set func_arith_result to the result of evaluating TERMs.
-  test -z "$_G_HAVE_ARITH_OP" \
-    && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
-    && _G_HAVE_ARITH_OP=yes
-
-if test yes = "$_G_HAVE_ARITH_OP"; then
-  eval 'func_arith ()
-  {
-    $debug_cmd
-
-    func_arith_result=$(( $* ))
-  }'
-else
-  func_arith ()
-  {
-    $debug_cmd
-
-    func_arith_result=`expr "$@"`
-  }
-fi
-
-
-# func_basename FILE
-# ------------------
-# Set func_basename_result to FILE with everything up to and including
-# the last / stripped.
-if test yes = "$_G_HAVE_XSI_OPS"; then
-  # If this shell supports suffix pattern removal, then use it to avoid
-  # forking. Hide the definitions single quotes in case the shell chokes
-  # on unsupported syntax...
-  _b='func_basename_result=${1##*/}'
-  _d='case $1 in
-        */*) func_dirname_result=${1%/*}$2 ;;
-        *  ) func_dirname_result=$3        ;;
-      esac'
-
-else
-  # ...otherwise fall back to using sed.
-  _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
-  _d='func_dirname_result=`$ECHO "$1"  |$SED "$sed_dirname"`
-      if test "X$func_dirname_result" = "X$1"; then
-        func_dirname_result=$3
-      else
-        func_append func_dirname_result "$2"
-      fi'
-fi
-
-eval 'func_basename ()
-{
-    $debug_cmd
-
-    '"$_b"'
-}'
-
-
-# func_dirname FILE APPEND NONDIR_REPLACEMENT
-# -------------------------------------------
-# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
-# otherwise set result to NONDIR_REPLACEMENT.
-eval 'func_dirname ()
-{
-    $debug_cmd
-
-    '"$_d"'
-}'
-
-
-# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
-# --------------------------------------------------------
-# Perform func_basename and func_dirname in a single function
-# call:
-#   dirname:  Compute the dirname of FILE.  If nonempty,
-#             add APPEND to the result, otherwise set result
-#             to NONDIR_REPLACEMENT.
-#             value returned in "$func_dirname_result"
-#   basename: Compute filename of FILE.
-#             value retuned in "$func_basename_result"
-# For efficiency, we do not delegate to the functions above but instead
-# duplicate the functionality here.
-eval 'func_dirname_and_basename ()
-{
-    $debug_cmd
-
-    '"$_b"'
-    '"$_d"'
-}'
-
-
-# func_echo ARG...
-# ----------------
-# Echo program name prefixed message.
-func_echo ()
-{
-    $debug_cmd
-
-    _G_message=$*
-
-    func_echo_IFS=$IFS
-    IFS=$nl
-    for _G_line in $_G_message; do
-      IFS=$func_echo_IFS
-      $ECHO "$progname: $_G_line"
-    done
-    IFS=$func_echo_IFS
-}
-
-
-# func_echo_all ARG...
-# --------------------
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
-    $ECHO "$*"
-}
-
-
-# func_echo_infix_1 INFIX ARG...
-# ------------------------------
-# Echo program name, followed by INFIX on the first line, with any
-# additional lines not showing INFIX.
-func_echo_infix_1 ()
-{
-    $debug_cmd
-
-    $require_term_colors
-
-    _G_infix=$1; shift
-    _G_indent=$_G_infix
-    _G_prefix="$progname: $_G_infix: "
-    _G_message=$*
-
-    # Strip color escape sequences before counting printable length
-    for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
-    do
-      test -n "$_G_tc" && {
-        _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
-        _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
-      }
-    done
-    _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`"  " ## exclude from sc_prohibit_nested_quotes
-
-    func_echo_infix_1_IFS=$IFS
-    IFS=$nl
-    for _G_line in $_G_message; do
-      IFS=$func_echo_infix_1_IFS
-      $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
-      _G_prefix=$_G_indent
-    done
-    IFS=$func_echo_infix_1_IFS
-}
-
-
-# func_error ARG...
-# -----------------
-# Echo program name prefixed message to standard error.
-func_error ()
-{
-    $debug_cmd
-
-    $require_term_colors
-
-    func_echo_infix_1 "  $tc_standout${tc_red}error$tc_reset" "$*" >&2
-}
-
-
-# func_fatal_error ARG...
-# -----------------------
-# Echo program name prefixed message to standard error, and exit.
-func_fatal_error ()
-{
-    $debug_cmd
-
-    func_error "$*"
-    exit $EXIT_FAILURE
-}
-
-
-# func_grep EXPRESSION FILENAME
-# -----------------------------
-# Check whether EXPRESSION matches any line of FILENAME, without output.
-func_grep ()
-{
-    $debug_cmd
-
-    $GREP "$1" "$2" >/dev/null 2>&1
-}
-
-
-# func_len STRING
-# ---------------
-# Set func_len_result to the length of STRING. STRING may not
-# start with a hyphen.
-  test -z "$_G_HAVE_XSI_OPS" \
-    && (eval 'x=a/b/c;
-      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
-    && _G_HAVE_XSI_OPS=yes
-
-if test yes = "$_G_HAVE_XSI_OPS"; then
-  eval 'func_len ()
-  {
-    $debug_cmd
-
-    func_len_result=${#1}
-  }'
-else
-  func_len ()
-  {
-    $debug_cmd
-
-    func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
-  }
-fi
-
-
-# func_mkdir_p DIRECTORY-PATH
-# ---------------------------
-# Make sure the entire path to DIRECTORY-PATH is available.
-func_mkdir_p ()
-{
-    $debug_cmd
-
-    _G_directory_path=$1
-    _G_dir_list=
-
-    if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
-
-      # Protect directory names starting with '-'
-      case $_G_directory_path in
-        -*) _G_directory_path=./$_G_directory_path ;;
-      esac
-
-      # While some portion of DIR does not yet exist...
-      while test ! -d "$_G_directory_path"; do
-        # ...make a list in topmost first order.  Use a colon delimited
-       # list incase some portion of path contains whitespace.
-        _G_dir_list=$_G_directory_path:$_G_dir_list
-
-        # If the last portion added has no slash in it, the list is done
-        case $_G_directory_path in */*) ;; *) break ;; esac
-
-        # ...otherwise throw away the child directory and loop
-        _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
-      done
-      _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
-
-      func_mkdir_p_IFS=$IFS; IFS=:
-      for _G_dir in $_G_dir_list; do
-       IFS=$func_mkdir_p_IFS
-        # mkdir can fail with a 'File exist' error if two processes
-        # try to create one of the directories concurrently.  Don't
-        # stop in that case!
-        $MKDIR "$_G_dir" 2>/dev/null || :
-      done
-      IFS=$func_mkdir_p_IFS
-
-      # Bail out if we (or some other process) failed to create a directory.
-      test -d "$_G_directory_path" || \
-        func_fatal_error "Failed to create '$1'"
-    fi
-}
-
-
-# func_mktempdir [BASENAME]
-# -------------------------
-# Make a temporary directory that won't clash with other running
-# libtool processes, and avoids race conditions if possible.  If
-# given, BASENAME is the basename for that directory.
-func_mktempdir ()
-{
-    $debug_cmd
-
-    _G_template=${TMPDIR-/tmp}/${1-$progname}
-
-    if test : = "$opt_dry_run"; then
-      # Return a directory name, but don't create it in dry-run mode
-      _G_tmpdir=$_G_template-$$
-    else
-
-      # If mktemp works, use that first and foremost
-      _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
-
-      if test ! -d "$_G_tmpdir"; then
-        # Failing that, at least try and use $RANDOM to avoid a race
-        _G_tmpdir=$_G_template-${RANDOM-0}$$
-
-        func_mktempdir_umask=`umask`
-        umask 0077
-        $MKDIR "$_G_tmpdir"
-        umask $func_mktempdir_umask
-      fi
-
-      # If we're not in dry-run mode, bomb out on failure
-      test -d "$_G_tmpdir" || \
-        func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
-    fi
-
-    $ECHO "$_G_tmpdir"
-}
-
-
-# func_normal_abspath PATH
-# ------------------------
-# Remove doubled-up and trailing slashes, "." path components,
-# and cancel out any ".." path components in PATH after making
-# it an absolute path.
-func_normal_abspath ()
-{
-    $debug_cmd
-
-    # These SED scripts presuppose an absolute path with a trailing slash.
-    _G_pathcar='s|^/\([^/]*\).*$|\1|'
-    _G_pathcdr='s|^/[^/]*||'
-    _G_removedotparts=':dotsl
-               s|/\./|/|g
-               t dotsl
-               s|/\.$|/|'
-    _G_collapseslashes='s|/\{1,\}|/|g'
-    _G_finalslash='s|/*$|/|'
-
-    # Start from root dir and reassemble the path.
-    func_normal_abspath_result=
-    func_normal_abspath_tpath=$1
-    func_normal_abspath_altnamespace=
-    case $func_normal_abspath_tpath in
-      "")
-        # Empty path, that just means $cwd.
-        func_stripname '' '/' "`pwd`"
-        func_normal_abspath_result=$func_stripname_result
-        return
-        ;;
-      # The next three entries are used to spot a run of precisely
-      # two leading slashes without using negated character classes;
-      # we take advantage of case's first-match behaviour.
-      ///*)
-        # Unusual form of absolute path, do nothing.
-        ;;
-      //*)
-        # Not necessarily an ordinary path; POSIX reserves leading '//'
-        # and for example Cygwin uses it to access remote file shares
-        # over CIFS/SMB, so we conserve a leading double slash if found.
-        func_normal_abspath_altnamespace=/
-        ;;
-      /*)
-        # Absolute path, do nothing.
-        ;;
-      *)
-        # Relative path, prepend $cwd.
-        func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
-        ;;
-    esac
-
-    # Cancel out all the simple stuff to save iterations.  We also want
-    # the path to end with a slash for ease of parsing, so make sure
-    # there is one (and only one) here.
-    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
-          -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
-    while :; do
-      # Processed it all yet?
-      if test / = "$func_normal_abspath_tpath"; then
-        # If we ascended to the root using ".." the result may be empty now.
-        if test -z "$func_normal_abspath_result"; then
-          func_normal_abspath_result=/
-        fi
-        break
-      fi
-      func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
-          -e "$_G_pathcar"`
-      func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
-          -e "$_G_pathcdr"`
-      # Figure out what to do with it
-      case $func_normal_abspath_tcomponent in
-        "")
-          # Trailing empty path component, ignore it.
-          ;;
-        ..)
-          # Parent dir; strip last assembled component from result.
-          func_dirname "$func_normal_abspath_result"
-          func_normal_abspath_result=$func_dirname_result
-          ;;
-        *)
-          # Actual path component, append it.
-          func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
-          ;;
-      esac
-    done
-    # Restore leading double-slash if one was found on entry.
-    func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
-}
-
-
-# func_notquiet ARG...
-# --------------------
-# Echo program name prefixed message only when not in quiet mode.
-func_notquiet ()
-{
-    $debug_cmd
-
-    $opt_quiet || func_echo ${1+"$@"}
-
-    # A bug in bash halts the script if the last line of a function
-    # fails when set -e is in force, so we need another command to
-    # work around that:
-    :
-}
-
-
-# func_relative_path SRCDIR DSTDIR
-# --------------------------------
-# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
-func_relative_path ()
-{
-    $debug_cmd
-
-    func_relative_path_result=
-    func_normal_abspath "$1"
-    func_relative_path_tlibdir=$func_normal_abspath_result
-    func_normal_abspath "$2"
-    func_relative_path_tbindir=$func_normal_abspath_result
-
-    # Ascend the tree starting from libdir
-    while :; do
-      # check if we have found a prefix of bindir
-      case $func_relative_path_tbindir in
-        $func_relative_path_tlibdir)
-          # found an exact match
-          func_relative_path_tcancelled=
-          break
-          ;;
-        $func_relative_path_tlibdir*)
-          # found a matching prefix
-          func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
-          func_relative_path_tcancelled=$func_stripname_result
-          if test -z "$func_relative_path_result"; then
-            func_relative_path_result=.
-          fi
-          break
-          ;;
-        *)
-          func_dirname $func_relative_path_tlibdir
-          func_relative_path_tlibdir=$func_dirname_result
-          if test -z "$func_relative_path_tlibdir"; then
-            # Have to descend all the way to the root!
-            func_relative_path_result=../$func_relative_path_result
-            func_relative_path_tcancelled=$func_relative_path_tbindir
-            break
-          fi
-          func_relative_path_result=../$func_relative_path_result
-          ;;
-      esac
-    done
-
-    # Now calculate path; take care to avoid doubling-up slashes.
-    func_stripname '' '/' "$func_relative_path_result"
-    func_relative_path_result=$func_stripname_result
-    func_stripname '/' '/' "$func_relative_path_tcancelled"
-    if test -n "$func_stripname_result"; then
-      func_append func_relative_path_result "/$func_stripname_result"
-    fi
-
-    # Normalisation. If bindir is libdir, return '.' else relative path.
-    if test -n "$func_relative_path_result"; then
-      func_stripname './' '' "$func_relative_path_result"
-      func_relative_path_result=$func_stripname_result
-    fi
-
-    test -n "$func_relative_path_result" || func_relative_path_result=.
-
-    :
-}
-
-
-# func_quote_for_eval ARG...
-# --------------------------
-# Aesthetically quote ARGs to be evaled later.
-# This function returns two values:
-#   i) func_quote_for_eval_result
-#      double-quoted, suitable for a subsequent eval
-#  ii) func_quote_for_eval_unquoted_result
-#      has all characters that are still active within double
-#      quotes backslashified.
-func_quote_for_eval ()
-{
-    $debug_cmd
-
-    func_quote_for_eval_unquoted_result=
-    func_quote_for_eval_result=
-    while test 0 -lt $#; do
-      case $1 in
-        *[\\\`\"\$]*)
-         _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
-        *)
-          _G_unquoted_arg=$1 ;;
-      esac
-      if test -n "$func_quote_for_eval_unquoted_result"; then
-       func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
-      else
-        func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
-      fi
-
-      case $_G_unquoted_arg in
-        # Double-quote args containing shell metacharacters to delay
-        # word splitting, command substitution and variable expansion
-        # for a subsequent eval.
-        # Many Bourne shells cannot handle close brackets correctly
-        # in scan sets, so we specify it separately.
-        *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \  ]*|*]*|"")
-          _G_quoted_arg=\"$_G_unquoted_arg\"
-          ;;
-        *)
-          _G_quoted_arg=$_G_unquoted_arg
-         ;;
-      esac
-
-      if test -n "$func_quote_for_eval_result"; then
-       func_append func_quote_for_eval_result " $_G_quoted_arg"
-      else
-        func_append func_quote_for_eval_result "$_G_quoted_arg"
-      fi
-      shift
-    done
-}
-
-
-# func_quote_for_expand ARG
-# -------------------------
-# Aesthetically quote ARG to be evaled later; same as above,
-# but do not quote variable references.
-func_quote_for_expand ()
-{
-    $debug_cmd
-
-    case $1 in
-      *[\\\`\"]*)
-       _G_arg=`$ECHO "$1" | $SED \
-           -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
-      *)
-        _G_arg=$1 ;;
-    esac
-
-    case $_G_arg in
-      # Double-quote args containing shell metacharacters to delay
-      # word splitting and command substitution for a subsequent eval.
-      # Many Bourne shells cannot handle close brackets correctly
-      # in scan sets, so we specify it separately.
-      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \    ]*|*]*|"")
-        _G_arg=\"$_G_arg\"
-        ;;
-    esac
-
-    func_quote_for_expand_result=$_G_arg
-}
-
-
-# func_stripname PREFIX SUFFIX NAME
-# ---------------------------------
-# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
-# PREFIX and SUFFIX must not contain globbing or regex special
-# characters, hashes, percent signs, but SUFFIX may contain a leading
-# dot (in which case that matches only a dot).
-if test yes = "$_G_HAVE_XSI_OPS"; then
-  eval 'func_stripname ()
-  {
-    $debug_cmd
-
-    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
-    # positional parameters, so assign one to ordinary variable first.
-    func_stripname_result=$3
-    func_stripname_result=${func_stripname_result#"$1"}
-    func_stripname_result=${func_stripname_result%"$2"}
-  }'
-else
-  func_stripname ()
-  {
-    $debug_cmd
-
-    case $2 in
-      .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
-      *)  func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
-    esac
-  }
-fi
-
-
-# func_show_eval CMD [FAIL_EXP]
-# -----------------------------
-# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
-# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
-# is given, then evaluate it.
-func_show_eval ()
-{
-    $debug_cmd
-
-    _G_cmd=$1
-    _G_fail_exp=${2-':'}
-
-    func_quote_for_expand "$_G_cmd"
-    eval "func_notquiet $func_quote_for_expand_result"
-
-    $opt_dry_run || {
-      eval "$_G_cmd"
-      _G_status=$?
-      if test 0 -ne "$_G_status"; then
-       eval "(exit $_G_status); $_G_fail_exp"
-      fi
-    }
-}
-
-
-# func_show_eval_locale CMD [FAIL_EXP]
-# ------------------------------------
-# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
-# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
-# is given, then evaluate it.  Use the saved locale for evaluation.
-func_show_eval_locale ()
-{
-    $debug_cmd
-
-    _G_cmd=$1
-    _G_fail_exp=${2-':'}
-
-    $opt_quiet || {
-      func_quote_for_expand "$_G_cmd"
-      eval "func_echo $func_quote_for_expand_result"
-    }
-
-    $opt_dry_run || {
-      eval "$_G_user_locale
-           $_G_cmd"
-      _G_status=$?
-      eval "$_G_safe_locale"
-      if test 0 -ne "$_G_status"; then
-       eval "(exit $_G_status); $_G_fail_exp"
-      fi
-    }
-}
-
-
-# func_tr_sh
-# ----------
-# Turn $1 into a string suitable for a shell variable name.
-# Result is stored in $func_tr_sh_result.  All characters
-# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
-# if $1 begins with a digit, a '_' is prepended as well.
-func_tr_sh ()
-{
-    $debug_cmd
-
-    case $1 in
-    [0-9]* | *[!a-zA-Z0-9_]*)
-      func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
-      ;;
-    * )
-      func_tr_sh_result=$1
-      ;;
-    esac
-}
-
-
-# func_verbose ARG...
-# -------------------
-# Echo program name prefixed message in verbose mode only.
-func_verbose ()
-{
-    $debug_cmd
-
-    $opt_verbose && func_echo "$*"
-
-    :
-}
-
-
-# func_warn_and_continue ARG...
-# -----------------------------
-# Echo program name prefixed warning message to standard error.
-func_warn_and_continue ()
-{
-    $debug_cmd
-
-    $require_term_colors
-
-    func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
-}
-
-
-# func_warning CATEGORY ARG...
-# ----------------------------
-# Echo program name prefixed warning message to standard error. Warning
-# messages can be filtered according to CATEGORY, where this function
-# elides messages where CATEGORY is not listed in the global variable
-# 'opt_warning_types'.
-func_warning ()
-{
-    $debug_cmd
-
-    # CATEGORY must be in the warning_categories list!
-    case " $warning_categories " in
-      *" $1 "*) ;;
-      *) func_internal_error "invalid warning category '$1'" ;;
-    esac
-
-    _G_category=$1
-    shift
-
-    case " $opt_warning_types " in
-      *" $_G_category "*) $warning_func ${1+"$@"} ;;
-    esac
-}
-
-
-# func_sort_ver VER1 VER2
-# -----------------------
-# 'sort -V' is not generally available.
-# Note this deviates from the version comparison in automake
-# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
-# but this should suffice as we won't be specifying old
-# version formats or redundant trailing .0 in bootstrap.conf.
-# If we did want full compatibility then we should probably
-# use m4_version_compare from autoconf.
-func_sort_ver ()
-{
-    $debug_cmd
-
-    printf '%s\n%s\n' "$1" "$2" \
-      | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
-}
-
-# func_lt_ver PREV CURR
-# ---------------------
-# Return true if PREV and CURR are in the correct order according to
-# func_sort_ver, otherwise false.  Use it like this:
-#
-#  func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
-func_lt_ver ()
-{
-    $debug_cmd
-
-    test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
-}
-
-
-# Local variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'before-save-hook 'time-stamp)
-# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
-# time-stamp-time-zone: "UTC"
-# End:
-#! /bin/sh
-
-# Set a version string for this script.
-scriptversion=2014-01-07.03; # UTC
-
-# A portable, pluggable option parser for Bourne shell.
-# Written by Gary V. Vaughan, 2010
-
-# Copyright (C) 2010-2015 Free Software Foundation, Inc.
-# This is free software; see the source for copying conditions.  There is NO
-# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-# Please report bugs or propose patches to gary@gnu.org.
-
-
-## ------ ##
-## Usage. ##
-## ------ ##
-
-# This file is a library for parsing options in your shell scripts along
-# with assorted other useful supporting features that you can make use
-# of too.
-#
-# For the simplest scripts you might need only:
-#
-#   #!/bin/sh
-#   . relative/path/to/funclib.sh
-#   . relative/path/to/options-parser
-#   scriptversion=1.0
-#   func_options ${1+"$@"}
-#   eval set dummy "$func_options_result"; shift
-#   ...rest of your script...
-#
-# In order for the '--version' option to work, you will need to have a
-# suitably formatted comment like the one at the top of this file
-# starting with '# Written by ' and ending with '# warranty; '.
-#
-# For '-h' and '--help' to work, you will also need a one line
-# description of your script's purpose in a comment directly above the
-# '# Written by ' line, like the one at the top of this file.
-#
-# The default options also support '--debug', which will turn on shell
-# execution tracing (see the comment above debug_cmd below for another
-# use), and '--verbose' and the func_verbose function to allow your script
-# to display verbose messages only when your user has specified
-# '--verbose'.
-#
-# After sourcing this file, you can plug processing for additional
-# options by amending the variables from the 'Configuration' section
-# below, and following the instructions in the 'Option parsing'
-# section further down.
-
-## -------------- ##
-## Configuration. ##
-## -------------- ##
-
-# You should override these variables in your script after sourcing this
-# file so that they reflect the customisations you have added to the
-# option parser.
-
-# The usage line for option parsing errors and the start of '-h' and
-# '--help' output messages. You can embed shell variables for delayed
-# expansion at the time the message is displayed, but you will need to
-# quote other shell meta-characters carefully to prevent them being
-# expanded when the contents are evaled.
-usage='$progpath [OPTION]...'
-
-# Short help message in response to '-h' and '--help'.  Add to this or
-# override it after sourcing this library to reflect the full set of
-# options your script accepts.
-usage_message="\
-       --debug        enable verbose shell tracing
-   -W, --warnings=CATEGORY
-                      report the warnings falling in CATEGORY [all]
-   -v, --verbose      verbosely report processing
-       --version      print version information and exit
-   -h, --help         print short or long help message and exit
-"
-
-# Additional text appended to 'usage_message' in response to '--help'.
-long_help_message="
-Warning categories include:
-       'all'          show all warnings
-       'none'         turn off all the warnings
-       'error'        warnings are treated as fatal errors"
-
-# Help message printed before fatal option parsing errors.
-fatal_help="Try '\$progname --help' for more information."
-
-
-
-## ------------------------- ##
-## Hook function management. ##
-## ------------------------- ##
-
-# This section contains functions for adding, removing, and running hooks
-# to the main code.  A hook is just a named list of of function, that can
-# be run in order later on.
-
-# func_hookable FUNC_NAME
-# -----------------------
-# Declare that FUNC_NAME will run hooks added with
-# 'func_add_hook FUNC_NAME ...'.
-func_hookable ()
-{
-    $debug_cmd
-
-    func_append hookable_fns " $1"
-}
-
-
-# func_add_hook FUNC_NAME HOOK_FUNC
-# ---------------------------------
-# Request that FUNC_NAME call HOOK_FUNC before it returns.  FUNC_NAME must
-# first have been declared "hookable" by a call to 'func_hookable'.
-func_add_hook ()
-{
-    $debug_cmd
-
-    case " $hookable_fns " in
-      *" $1 "*) ;;
-      *) func_fatal_error "'$1' does not accept hook functions." ;;
-    esac
-
-    eval func_append ${1}_hooks '" $2"'
-}
-
-
-# func_remove_hook FUNC_NAME HOOK_FUNC
-# ------------------------------------
-# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
-func_remove_hook ()
-{
-    $debug_cmd
-
-    eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
-}
-
-
-# func_run_hooks FUNC_NAME [ARG]...
-# ---------------------------------
-# Run all hook functions registered to FUNC_NAME.
-# It is assumed that the list of hook functions contains nothing more
-# than a whitespace-delimited list of legal shell function names, and
-# no effort is wasted trying to catch shell meta-characters or preserve
-# whitespace.
-func_run_hooks ()
-{
-    $debug_cmd
-
-    case " $hookable_fns " in
-      *" $1 "*) ;;
-      *) func_fatal_error "'$1' does not support hook funcions.n" ;;
-    esac
-
-    eval _G_hook_fns=\$$1_hooks; shift
-
-    for _G_hook in $_G_hook_fns; do
-      eval $_G_hook '"$@"'
-
-      # store returned options list back into positional
-      # parameters for next 'cmd' execution.
-      eval _G_hook_result=\$${_G_hook}_result
-      eval set dummy "$_G_hook_result"; shift
-    done
-
-    func_quote_for_eval ${1+"$@"}
-    func_run_hooks_result=$func_quote_for_eval_result
-}
-
-
-
-## --------------- ##
-## Option parsing. ##
-## --------------- ##
-
-# In order to add your own option parsing hooks, you must accept the
-# full positional parameter list in your hook function, remove any
-# options that you action, and then pass back the remaining unprocessed
-# options in '<hooked_function_name>_result', escaped suitably for
-# 'eval'.  Like this:
-#
-#    my_options_prep ()
-#    {
-#        $debug_cmd
-#
-#        # Extend the existing usage message.
-#        usage_message=$usage_message'
-#      -s, --silent       don'\''t print informational messages
-#    '
-#
-#        func_quote_for_eval ${1+"$@"}
-#        my_options_prep_result=$func_quote_for_eval_result
-#    }
-#    func_add_hook func_options_prep my_options_prep
-#
-#
-#    my_silent_option ()
-#    {
-#        $debug_cmd
-#
-#        # Note that for efficiency, we parse as many options as we can
-#        # recognise in a loop before passing the remainder back to the
-#        # caller on the first unrecognised argument we encounter.
-#        while test $# -gt 0; do
-#          opt=$1; shift
-#          case $opt in
-#            --silent|-s) opt_silent=: ;;
-#            # Separate non-argument short options:
-#            -s*)         func_split_short_opt "$_G_opt"
-#                         set dummy "$func_split_short_opt_name" \
-#                             "-$func_split_short_opt_arg" ${1+"$@"}
-#                         shift
-#                         ;;
-#            *)            set dummy "$_G_opt" "$*"; shift; break ;;
-#          esac
-#        done
-#
-#        func_quote_for_eval ${1+"$@"}
-#        my_silent_option_result=$func_quote_for_eval_result
-#    }
-#    func_add_hook func_parse_options my_silent_option
-#
-#
-#    my_option_validation ()
-#    {
-#        $debug_cmd
-#
-#        $opt_silent && $opt_verbose && func_fatal_help "\
-#    '--silent' and '--verbose' options are mutually exclusive."
-#
-#        func_quote_for_eval ${1+"$@"}
-#        my_option_validation_result=$func_quote_for_eval_result
-#    }
-#    func_add_hook func_validate_options my_option_validation
-#
-# You'll alse need to manually amend $usage_message to reflect the extra
-# options you parse.  It's preferable to append if you can, so that
-# multiple option parsing hooks can be added safely.
-
-
-# func_options [ARG]...
-# ---------------------
-# All the functions called inside func_options are hookable. See the
-# individual implementations for details.
-func_hookable func_options
-func_options ()
-{
-    $debug_cmd
-
-    func_options_prep ${1+"$@"}
-    eval func_parse_options \
-        ${func_options_prep_result+"$func_options_prep_result"}
-    eval func_validate_options \
-        ${func_parse_options_result+"$func_parse_options_result"}
-
-    eval func_run_hooks func_options \
-        ${func_validate_options_result+"$func_validate_options_result"}
-
-    # save modified positional parameters for caller
-    func_options_result=$func_run_hooks_result
-}
-
-
-# func_options_prep [ARG]...
-# --------------------------
-# All initialisations required before starting the option parse loop.
-# Note that when calling hook functions, we pass through the list of
-# positional parameters.  If a hook function modifies that list, and
-# needs to propogate that back to rest of this script, then the complete
-# modified list must be put in 'func_run_hooks_result' before
-# returning.
-func_hookable func_options_prep
-func_options_prep ()
-{
-    $debug_cmd
-
-    # Option defaults:
-    opt_verbose=false
-    opt_warning_types=
-
-    func_run_hooks func_options_prep ${1+"$@"}
-
-    # save modified positional parameters for caller
-    func_options_prep_result=$func_run_hooks_result
-}
-
-
-# func_parse_options [ARG]...
-# ---------------------------
-# The main option parsing loop.
-func_hookable func_parse_options
-func_parse_options ()
-{
-    $debug_cmd
-
-    func_parse_options_result=
-
-    # this just eases exit handling
-    while test $# -gt 0; do
-      # Defer to hook functions for initial option parsing, so they
-      # get priority in the event of reusing an option name.
-      func_run_hooks func_parse_options ${1+"$@"}
-
-      # Adjust func_parse_options positional parameters to match
-      eval set dummy "$func_run_hooks_result"; shift
-
-      # Break out of the loop if we already parsed every option.
-      test $# -gt 0 || break
-
-      _G_opt=$1
-      shift
-      case $_G_opt in
-        --debug|-x)   debug_cmd='set -x'
-                      func_echo "enabling shell trace mode"
-                      $debug_cmd
-                      ;;
-
-        --no-warnings|--no-warning|--no-warn)
-                      set dummy --warnings none ${1+"$@"}
-                      shift
-                     ;;
-
-        --warnings|--warning|-W)
-                      test $# = 0 && func_missing_arg $_G_opt && break
-                      case " $warning_categories $1" in
-                        *" $1 "*)
-                          # trailing space prevents matching last $1 above
-                          func_append_uniq opt_warning_types " $1"
-                          ;;
-                        *all)
-                          opt_warning_types=$warning_categories
-                          ;;
-                        *none)
-                          opt_warning_types=none
-                          warning_func=:
-                          ;;
-                        *error)
-                          opt_warning_types=$warning_categories
-                          warning_func=func_fatal_error
-                          ;;
-                        *)
-                          func_fatal_error \
-                             "unsupported warning category: '$1'"
-                          ;;
-                      esac
-                      shift
-                      ;;
-
-        --verbose|-v) opt_verbose=: ;;
-        --version)    func_version ;;
-        -\?|-h)       func_usage ;;
-        --help)       func_help ;;
-
-       # Separate optargs to long options (plugins may need this):
-       --*=*)        func_split_equals "$_G_opt"
-                     set dummy "$func_split_equals_lhs" \
-                          "$func_split_equals_rhs" ${1+"$@"}
-                      shift
-                      ;;
-
-       # Separate optargs to short options:
-        -W*)
-                      func_split_short_opt "$_G_opt"
-                      set dummy "$func_split_short_opt_name" \
-                          "$func_split_short_opt_arg" ${1+"$@"}
-                      shift
-                      ;;
-
-        # Separate non-argument short options:
-        -\?*|-h*|-v*|-x*)
-                      func_split_short_opt "$_G_opt"
-                      set dummy "$func_split_short_opt_name" \
-                          "-$func_split_short_opt_arg" ${1+"$@"}
-                      shift
-                      ;;
-
-        --)           break ;;
-        -*)           func_fatal_help "unrecognised option: '$_G_opt'" ;;
-        *)            set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
-      esac
-    done
-
-    # save modified positional parameters for caller
-    func_quote_for_eval ${1+"$@"}
-    func_parse_options_result=$func_quote_for_eval_result
-}
-
-
-# func_validate_options [ARG]...
-# ------------------------------
-# Perform any sanity checks on option settings and/or unconsumed
-# arguments.
-func_hookable func_validate_options
-func_validate_options ()
-{
-    $debug_cmd
-
-    # Display all warnings if -W was not given.
-    test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
-
-    func_run_hooks func_validate_options ${1+"$@"}
-
-    # Bail if the options were screwed!
-    $exit_cmd $EXIT_FAILURE
-
-    # save modified positional parameters for caller
-    func_validate_options_result=$func_run_hooks_result
-}
-
-
-
-## ----------------- ##
-## Helper functions. ##
-## ----------------- ##
-
-# This section contains the helper functions used by the rest of the
-# hookable option parser framework in ascii-betical order.
-
-
-# func_fatal_help ARG...
-# ----------------------
-# Echo program name prefixed message to standard error, followed by
-# a help hint, and exit.
-func_fatal_help ()
-{
-    $debug_cmd
-
-    eval \$ECHO \""Usage: $usage"\"
-    eval \$ECHO \""$fatal_help"\"
-    func_error ${1+"$@"}
-    exit $EXIT_FAILURE
-}
-
-
-# func_help
-# ---------
-# Echo long help message to standard output and exit.
-func_help ()
-{
-    $debug_cmd
-
-    func_usage_message
-    $ECHO "$long_help_message"
-    exit 0
-}
-
-
-# func_missing_arg ARGNAME
-# ------------------------
-# Echo program name prefixed message to standard error and set global
-# exit_cmd.
-func_missing_arg ()
-{
-    $debug_cmd
-
-    func_error "Missing argument for '$1'."
-    exit_cmd=exit
-}
-
-
-# func_split_equals STRING
-# ------------------------
-# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
-# splitting STRING at the '=' sign.
-test -z "$_G_HAVE_XSI_OPS" \
-    && (eval 'x=a/b/c;
-      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
-    && _G_HAVE_XSI_OPS=yes
-
-if test yes = "$_G_HAVE_XSI_OPS"
-then
-  # This is an XSI compatible shell, allowing a faster implementation...
-  eval 'func_split_equals ()
-  {
-      $debug_cmd
-
-      func_split_equals_lhs=${1%%=*}
-      func_split_equals_rhs=${1#*=}
-      test "x$func_split_equals_lhs" = "x$1" \
-        && func_split_equals_rhs=
-  }'
-else
-  # ...otherwise fall back to using expr, which is often a shell builtin.
-  func_split_equals ()
-  {
-      $debug_cmd
-
-      func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
-      func_split_equals_rhs=
-      test "x$func_split_equals_lhs" = "x$1" \
-        || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
-  }
-fi #func_split_equals
-
-
-# func_split_short_opt SHORTOPT
-# -----------------------------
-# Set func_split_short_opt_name and func_split_short_opt_arg shell
-# variables after splitting SHORTOPT after the 2nd character.
-if test yes = "$_G_HAVE_XSI_OPS"
-then
-  # This is an XSI compatible shell, allowing a faster implementation...
-  eval 'func_split_short_opt ()
-  {
-      $debug_cmd
-
-      func_split_short_opt_arg=${1#??}
-      func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
-  }'
-else
-  # ...otherwise fall back to using expr, which is often a shell builtin.
-  func_split_short_opt ()
-  {
-      $debug_cmd
-
-      func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
-      func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
-  }
-fi #func_split_short_opt
-
-
-# func_usage
-# ----------
-# Echo short help message to standard output and exit.
-func_usage ()
-{
-    $debug_cmd
-
-    func_usage_message
-    $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
-    exit 0
-}
-
-
-# func_usage_message
-# ------------------
-# Echo short help message to standard output.
-func_usage_message ()
-{
-    $debug_cmd
-
-    eval \$ECHO \""Usage: $usage"\"
-    echo
-    $SED -n 's|^# ||
-        /^Written by/{
-          x;p;x
-        }
-       h
-       /^Written by/q' < "$progpath"
-    echo
-    eval \$ECHO \""$usage_message"\"
-}
-
-
-# func_version
-# ------------
-# Echo version message to standard output and exit.
-func_version ()
-{
-    $debug_cmd
-
-    printf '%s\n' "$progname $scriptversion"
-    $SED -n '
-        /(C)/!b go
-        :more
-        /\./!{
-          N
-          s|\n# | |
-          b more
-        }
-        :go
-        /^# Written by /,/# warranty; / {
-          s|^# ||
-          s|^# *$||
-          s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
-          p
-        }
-        /^# Written by / {
-          s|^# ||
-          p
-        }
-        /^warranty; /q' < "$progpath"
-
-    exit $?
-}
-
-
-# Local variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'before-save-hook 'time-stamp)
-# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
-# time-stamp-time-zone: "UTC"
-# End:
-
-# Set a version string.
-scriptversion='(GNU libtool) 2.4.6 Debian-2.4.6-1'
-
-
-# func_echo ARG...
-# ----------------
-# Libtool also displays the current mode in messages, so override
-# funclib.sh func_echo with this custom definition.
-func_echo ()
-{
-    $debug_cmd
-
-    _G_message=$*
-
-    func_echo_IFS=$IFS
-    IFS=$nl
-    for _G_line in $_G_message; do
-      IFS=$func_echo_IFS
-      $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
-    done
-    IFS=$func_echo_IFS
-}
-
-
-# func_warning ARG...
-# -------------------
-# Libtool warnings are not categorized, so override funclib.sh
-# func_warning with this simpler definition.
-func_warning ()
-{
-    $debug_cmd
-
-    $warning_func ${1+"$@"}
-}
-
-
-## ---------------- ##
-## Options parsing. ##
-## ---------------- ##
-
-# Hook in the functions to make sure our own options are parsed during
-# the option parsing loop.
-
-usage='$progpath [OPTION]... [MODE-ARG]...'
-
-# Short help message in response to '-h'.
-usage_message="Options:
-       --config             show all configuration variables
-       --debug              enable verbose shell tracing
-   -n, --dry-run            display commands without modifying any files
-       --features           display basic configuration information and exit
-       --mode=MODE          use operation mode MODE
-       --no-warnings        equivalent to '-Wnone'
-       --preserve-dup-deps  don't remove duplicate dependency libraries
-       --quiet, --silent    don't print informational messages
-       --tag=TAG            use configuration variables from tag TAG
-   -v, --verbose            print more informational messages than default
-       --version            print version information
-   -W, --warnings=CATEGORY  report the warnings falling in CATEGORY [all]
-   -h, --help, --help-all   print short, long, or detailed help message
-"
-
-# Additional text appended to 'usage_message' in response to '--help'.
-func_help ()
-{
-    $debug_cmd
-
-    func_usage_message
-    $ECHO "$long_help_message
-
-MODE must be one of the following:
-
-       clean           remove files from the build directory
-       compile         compile a source file into a libtool object
-       execute         automatically set library path, then run a program
-       finish          complete the installation of libtool libraries
-       install         install libraries or executables
-       link            create a library or an executable
-       uninstall       remove libraries from an installed directory
-
-MODE-ARGS vary depending on the MODE.  When passed as first option,
-'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
-Try '$progname --help --mode=MODE' for a more detailed description of MODE.
-
-When reporting a bug, please describe a test case to reproduce it and
-include the following information:
-
-       host-triplet:   $host
-       shell:          $SHELL
-       compiler:       $LTCC
-       compiler flags: $LTCFLAGS
-       linker:         $LD (gnu? $with_gnu_ld)
-       version:        $progname $scriptversion
-       automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
-       autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`
-
-Report bugs to <bug-libtool@gnu.org>.
-GNU libtool home page: <http://www.gnu.org/s/libtool/>.
-General help using GNU software: <http://www.gnu.org/gethelp/>."
-    exit 0
-}
-
-
-# func_lo2o OBJECT-NAME
-# ---------------------
-# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
-# object suffix.
-
-lo2o=s/\\.lo\$/.$objext/
-o2lo=s/\\.$objext\$/.lo/
-
-if test yes = "$_G_HAVE_XSI_OPS"; then
-  eval 'func_lo2o ()
-  {
-    case $1 in
-      *.lo) func_lo2o_result=${1%.lo}.$objext ;;
-      *   ) func_lo2o_result=$1               ;;
-    esac
-  }'
-
-  # func_xform LIBOBJ-OR-SOURCE
-  # ---------------------------
-  # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
-  # suffix to a '.lo' libtool-object suffix.
-  eval 'func_xform ()
-  {
-    func_xform_result=${1%.*}.lo
-  }'
-else
-  # ...otherwise fall back to using sed.
-  func_lo2o ()
-  {
-    func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
-  }
-
-  func_xform ()
-  {
-    func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
-  }
-fi
-
-
-# func_fatal_configuration ARG...
-# -------------------------------
-# Echo program name prefixed message to standard error, followed by
-# a configuration failure hint, and exit.
-func_fatal_configuration ()
-{
-    func__fatal_error ${1+"$@"} \
-      "See the $PACKAGE documentation for more information." \
-      "Fatal configuration error."
-}
-
-
-# func_config
-# -----------
-# Display the configuration for all the tags in this script.
-func_config ()
-{
-    re_begincf='^# ### BEGIN LIBTOOL'
-    re_endcf='^# ### END LIBTOOL'
-
-    # Default configuration.
-    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
-
-    # Now print the configurations for the tags.
-    for tagname in $taglist; do
-      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
-    done
-
-    exit $?
-}
-
-
-# func_features
-# -------------
-# Display the features supported by this script.
-func_features ()
-{
-    echo "host: $host"
-    if test yes = "$build_libtool_libs"; then
-      echo "enable shared libraries"
-    else
-      echo "disable shared libraries"
-    fi
-    if test yes = "$build_old_libs"; then
-      echo "enable static libraries"
-    else
-      echo "disable static libraries"
-    fi
-
-    exit $?
-}
-
-
-# func_enable_tag TAGNAME
-# -----------------------
-# Verify that TAGNAME is valid, and either flag an error and exit, or
-# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
-# variable here.
-func_enable_tag ()
-{
-    # Global variable:
-    tagname=$1
-
-    re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
-    re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
-    sed_extractcf=/$re_begincf/,/$re_endcf/p
-
-    # Validate tagname.
-    case $tagname in
-      *[!-_A-Za-z0-9,/]*)
-        func_fatal_error "invalid tag name: $tagname"
-        ;;
-    esac
-
-    # Don't test for the "default" C tag, as we know it's
-    # there but not specially marked.
-    case $tagname in
-        CC) ;;
-    *)
-        if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
-         taglist="$taglist $tagname"
-
-         # Evaluate the configuration.  Be careful to quote the path
-         # and the sed script, to avoid splitting on whitespace, but
-         # also don't use non-portable quotes within backquotes within
-         # quotes we have to do it in 2 steps:
-         extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
-         eval "$extractedcf"
-        else
-         func_error "ignoring unknown tag $tagname"
-        fi
-        ;;
-    esac
-}
-
-
-# func_check_version_match
-# ------------------------
-# Ensure that we are using m4 macros, and libtool script from the same
-# release of libtool.
-func_check_version_match ()
-{
-    if test "$package_revision" != "$macro_revision"; then
-      if test "$VERSION" != "$macro_version"; then
-        if test -z "$macro_version"; then
-          cat >&2 <<_LT_EOF
-$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
-$progname: definition of this LT_INIT comes from an older release.
-$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
-$progname: and run autoconf again.
-_LT_EOF
-        else
-          cat >&2 <<_LT_EOF
-$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
-$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
-$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
-$progname: and run autoconf again.
-_LT_EOF
-        fi
-      else
-        cat >&2 <<_LT_EOF
-$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
-$progname: but the definition of this LT_INIT comes from revision $macro_revision.
-$progname: You should recreate aclocal.m4 with macros from revision $package_revision
-$progname: of $PACKAGE $VERSION and run autoconf again.
-_LT_EOF
-      fi
-
-      exit $EXIT_MISMATCH
-    fi
-}
-
-
-# libtool_options_prep [ARG]...
-# -----------------------------
-# Preparation for options parsed by libtool.
-libtool_options_prep ()
-{
-    $debug_mode
-
-    # Option defaults:
-    opt_config=false
-    opt_dlopen=
-    opt_dry_run=false
-    opt_help=false
-    opt_mode=
-    opt_preserve_dup_deps=false
-    opt_quiet=false
-
-    nonopt=
-    preserve_args=
-
-    # Shorthand for --mode=foo, only valid as the first argument
-    case $1 in
-    clean|clea|cle|cl)
-      shift; set dummy --mode clean ${1+"$@"}; shift
-      ;;
-    compile|compil|compi|comp|com|co|c)
-      shift; set dummy --mode compile ${1+"$@"}; shift
-      ;;
-    execute|execut|execu|exec|exe|ex|e)
-      shift; set dummy --mode execute ${1+"$@"}; shift
-      ;;
-    finish|finis|fini|fin|fi|f)
-      shift; set dummy --mode finish ${1+"$@"}; shift
-      ;;
-    install|instal|insta|inst|ins|in|i)
-      shift; set dummy --mode install ${1+"$@"}; shift
-      ;;
-    link|lin|li|l)
-      shift; set dummy --mode link ${1+"$@"}; shift
-      ;;
-    uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
-      shift; set dummy --mode uninstall ${1+"$@"}; shift
-      ;;
-    esac
-
-    # Pass back the list of options.
-    func_quote_for_eval ${1+"$@"}
-    libtool_options_prep_result=$func_quote_for_eval_result
-}
-func_add_hook func_options_prep libtool_options_prep
-
-
-# libtool_parse_options [ARG]...
-# ---------------------------------
-# Provide handling for libtool specific options.
-libtool_parse_options ()
-{
-    $debug_cmd
-
-    # Perform our own loop to consume as many options as possible in
-    # each iteration.
-    while test $# -gt 0; do
-      _G_opt=$1
-      shift
-      case $_G_opt in
-        --dry-run|--dryrun|-n)
-                        opt_dry_run=:
-                        ;;
-
-        --config)       func_config ;;
-
-        --dlopen|-dlopen)
-                        opt_dlopen="${opt_dlopen+$opt_dlopen
-}$1"
-                        shift
-                        ;;
-
-        --preserve-dup-deps)
-                        opt_preserve_dup_deps=: ;;
-
-        --features)     func_features ;;
-
-        --finish)       set dummy --mode finish ${1+"$@"}; shift ;;
-
-        --help)         opt_help=: ;;
-
-        --help-all)     opt_help=': help-all' ;;
-
-        --mode)         test $# = 0 && func_missing_arg $_G_opt && break
-                        opt_mode=$1
-                        case $1 in
-                          # Valid mode arguments:
-                          clean|compile|execute|finish|install|link|relink|uninstall) ;;
-
-                          # Catch anything else as an error
-                          *) func_error "invalid argument for $_G_opt"
-                             exit_cmd=exit
-                             break
-                             ;;
-                        esac
-                        shift
-                        ;;
-
-        --no-silent|--no-quiet)
-                        opt_quiet=false
-                        func_append preserve_args " $_G_opt"
-                        ;;
-
-        --no-warnings|--no-warning|--no-warn)
-                        opt_warning=false
-                        func_append preserve_args " $_G_opt"
-                        ;;
-
-        --no-verbose)
-                        opt_verbose=false
-                        func_append preserve_args " $_G_opt"
-                        ;;
-
-        --silent|--quiet)
-                        opt_quiet=:
-                        opt_verbose=false
-                        func_append preserve_args " $_G_opt"
-                        ;;
-
-        --tag)          test $# = 0 && func_missing_arg $_G_opt && break
-                        opt_tag=$1
-                        func_append preserve_args " $_G_opt $1"
-                        func_enable_tag "$1"
-                        shift
-                        ;;
-
-        --verbose|-v)   opt_quiet=false
-                        opt_verbose=:
-                        func_append preserve_args " $_G_opt"
-                        ;;
-
-       # An option not handled by this hook function:
-        *)             set dummy "$_G_opt" ${1+"$@"};  shift; break  ;;
-      esac
-    done
-
-
-    # save modified positional parameters for caller
-    func_quote_for_eval ${1+"$@"}
-    libtool_parse_options_result=$func_quote_for_eval_result
-}
-func_add_hook func_parse_options libtool_parse_options
-
-
-
-# libtool_validate_options [ARG]...
-# ---------------------------------
-# Perform any sanity checks on option settings and/or unconsumed
-# arguments.
-libtool_validate_options ()
-{
-    # save first non-option argument
-    if test 0 -lt $#; then
-      nonopt=$1
-      shift
-    fi
-
-    # preserve --debug
-    test : = "$debug_cmd" || func_append preserve_args " --debug"
-
-    case $host in
-      # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
-      # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
-      *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
-        # don't eliminate duplications in $postdeps and $predeps
-        opt_duplicate_compiler_generated_deps=:
-        ;;
-      *)
-        opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
-        ;;
-    esac
-
-    $opt_help || {
-      # Sanity checks first:
-      func_check_version_match
-
-      test yes != "$build_libtool_libs" \
-        && test yes != "$build_old_libs" \
-        && func_fatal_configuration "not configured to build any kind of library"
-
-      # Darwin sucks
-      eval std_shrext=\"$shrext_cmds\"
-
-      # Only execute mode is allowed to have -dlopen flags.
-      if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
-        func_error "unrecognized option '-dlopen'"
-        $ECHO "$help" 1>&2
-        exit $EXIT_FAILURE
-      fi
-
-      # Change the help message to a mode-specific one.
-      generic_help=$help
-      help="Try '$progname --help --mode=$opt_mode' for more information."
-    }
-
-    # Pass back the unparsed argument list
-    func_quote_for_eval ${1+"$@"}
-    libtool_validate_options_result=$func_quote_for_eval_result
-}
-func_add_hook func_validate_options libtool_validate_options
-
-
-# Process options as early as possible so that --help and --version
-# can return quickly.
-func_options ${1+"$@"}
-eval set dummy "$func_options_result"; shift
-
-
-
-## ----------- ##
-##    Main.    ##
-## ----------- ##
-
-magic='%%%MAGIC variable%%%'
-magic_exe='%%%MAGIC EXE variable%%%'
-
-# Global variables.
-extracted_archives=
-extracted_serial=0
-
-# If this variable is set in any of the actions, the command in it
-# will be execed at the end.  This prevents here-documents from being
-# left over by shells.
-exec_cmd=
-
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
-  eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
-}
-
-# func_generated_by_libtool
-# True iff stdin has been generated by Libtool. This function is only
-# a basic sanity check; it will hardly flush out determined imposters.
-func_generated_by_libtool_p ()
-{
-  $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
-}
-
-# func_lalib_p file
-# True iff FILE is a libtool '.la' library or '.lo' object file.
-# This function is only a basic sanity check; it will hardly flush out
-# determined imposters.
-func_lalib_p ()
-{
-    test -f "$1" &&
-      $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
-}
-
-# func_lalib_unsafe_p file
-# True iff FILE is a libtool '.la' library or '.lo' object file.
-# This function implements the same check as func_lalib_p without
-# resorting to external programs.  To this end, it redirects stdin and
-# closes it afterwards, without saving the original file descriptor.
-# As a safety measure, use it only where a negative result would be
-# fatal anyway.  Works if 'file' does not exist.
-func_lalib_unsafe_p ()
-{
-    lalib_p=no
-    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
-       for lalib_p_l in 1 2 3 4
-       do
-           read lalib_p_line
-           case $lalib_p_line in
-               \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
-           esac
-       done
-       exec 0<&5 5<&-
-    fi
-    test yes = "$lalib_p"
-}
-
-# func_ltwrapper_script_p file
-# True iff FILE is a libtool wrapper script
-# This function is only a basic sanity check; it will hardly flush out
-# determined imposters.
-func_ltwrapper_script_p ()
-{
-    test -f "$1" &&
-      $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
-}
-
-# func_ltwrapper_executable_p file
-# True iff FILE is a libtool wrapper executable
-# This function is only a basic sanity check; it will hardly flush out
-# determined imposters.
-func_ltwrapper_executable_p ()
-{
-    func_ltwrapper_exec_suffix=
-    case $1 in
-    *.exe) ;;
-    *) func_ltwrapper_exec_suffix=.exe ;;
-    esac
-    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
-}
-
-# func_ltwrapper_scriptname file
-# Assumes file is an ltwrapper_executable
-# uses $file to determine the appropriate filename for a
-# temporary ltwrapper_script.
-func_ltwrapper_scriptname ()
-{
-    func_dirname_and_basename "$1" "" "."
-    func_stripname '' '.exe' "$func_basename_result"
-    func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
-}
-
-# func_ltwrapper_p file
-# True iff FILE is a libtool wrapper script or wrapper executable
-# This function is only a basic sanity check; it will hardly flush out
-# determined imposters.
-func_ltwrapper_p ()
-{
-    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
-}
-
-
-# func_execute_cmds commands fail_cmd
-# Execute tilde-delimited COMMANDS.
-# If FAIL_CMD is given, eval that upon failure.
-# FAIL_CMD may read-access the current command in variable CMD!
-func_execute_cmds ()
-{
-    $debug_cmd
-
-    save_ifs=$IFS; IFS='~'
-    for cmd in $1; do
-      IFS=$sp$nl
-      eval cmd=\"$cmd\"
-      IFS=$save_ifs
-      func_show_eval "$cmd" "${2-:}"
-    done
-    IFS=$save_ifs
-}
-
-
-# func_source file
-# Source FILE, adding directory component if necessary.
-# Note that it is not necessary on cygwin/mingw to append a dot to
-# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
-# behavior happens only for exec(3), not for open(2)!  Also, sourcing
-# 'FILE.' does not work on cygwin managed mounts.
-func_source ()
-{
-    $debug_cmd
-
-    case $1 in
-    */* | *\\*)        . "$1" ;;
-    *)         . "./$1" ;;
-    esac
-}
-
-
-# func_resolve_sysroot PATH
-# Replace a leading = in PATH with a sysroot.  Store the result into
-# func_resolve_sysroot_result
-func_resolve_sysroot ()
-{
-  func_resolve_sysroot_result=$1
-  case $func_resolve_sysroot_result in
-  =*)
-    func_stripname '=' '' "$func_resolve_sysroot_result"
-    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
-    ;;
-  esac
-}
-
-# func_replace_sysroot PATH
-# If PATH begins with the sysroot, replace it with = and
-# store the result into func_replace_sysroot_result.
-func_replace_sysroot ()
-{
-  case $lt_sysroot:$1 in
-  ?*:"$lt_sysroot"*)
-    func_stripname "$lt_sysroot" '' "$1"
-    func_replace_sysroot_result='='$func_stripname_result
-    ;;
-  *)
-    # Including no sysroot.
-    func_replace_sysroot_result=$1
-    ;;
-  esac
-}
-
-# func_infer_tag arg
-# Infer tagged configuration to use if any are available and
-# if one wasn't chosen via the "--tag" command line option.
-# Only attempt this if the compiler in the base compile
-# command doesn't match the default compiler.
-# arg is usually of the form 'gcc ...'
-func_infer_tag ()
-{
-    $debug_cmd
-
-    if test -n "$available_tags" && test -z "$tagname"; then
-      CC_quoted=
-      for arg in $CC; do
-       func_append_quoted CC_quoted "$arg"
-      done
-      CC_expanded=`func_echo_all $CC`
-      CC_quoted_expanded=`func_echo_all $CC_quoted`
-      case $@ in
-      # Blanks in the command may have been stripped by the calling shell,
-      # but not from the CC environment variable when configure was run.
-      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
-      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
-      # Blanks at the start of $base_compile will cause this to fail
-      # if we don't check for them as well.
-      *)
-       for z in $available_tags; do
-         if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
-           # Evaluate the configuration.
-           eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
-           CC_quoted=
-           for arg in $CC; do
-             # Double-quote args containing other shell metacharacters.
-             func_append_quoted CC_quoted "$arg"
-           done
-           CC_expanded=`func_echo_all $CC`
-           CC_quoted_expanded=`func_echo_all $CC_quoted`
-           case "$@ " in
-           " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
-           " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
-             # The compiler in the base compile command matches
-             # the one in the tagged configuration.
-             # Assume this is the tagged configuration we want.
-             tagname=$z
-             break
-             ;;
-           esac
-         fi
-       done
-       # If $tagname still isn't set, then no tagged configuration
-       # was found and let the user know that the "--tag" command
-       # line option must be used.
-       if test -z "$tagname"; then
-         func_echo "unable to infer tagged configuration"
-         func_fatal_error "specify a tag with '--tag'"
-#      else
-#        func_verbose "using $tagname tagged configuration"
-       fi
-       ;;
-      esac
-    fi
-}
-
-
-
-# func_write_libtool_object output_name pic_name nonpic_name
-# Create a libtool object file (analogous to a ".la" file),
-# but don't create it if we're doing a dry run.
-func_write_libtool_object ()
-{
-    write_libobj=$1
-    if test yes = "$build_libtool_libs"; then
-      write_lobj=\'$2\'
-    else
-      write_lobj=none
-    fi
-
-    if test yes = "$build_old_libs"; then
-      write_oldobj=\'$3\'
-    else
-      write_oldobj=none
-    fi
-
-    $opt_dry_run || {
-      cat >${write_libobj}T <<EOF
-# $write_libobj - a libtool object file
-# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# Name of the PIC object.
-pic_object=$write_lobj
-
-# Name of the non-PIC object
-non_pic_object=$write_oldobj
-
-EOF
-      $MV "${write_libobj}T" "$write_libobj"
-    }
-}
-
-
-##################################################
-# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
-##################################################
-
-# func_convert_core_file_wine_to_w32 ARG
-# Helper function used by file name conversion functions when $build is *nix,
-# and $host is mingw, cygwin, or some other w32 environment. Relies on a
-# correctly configured wine environment available, with the winepath program
-# in $build's $PATH.
-#
-# ARG is the $build file name to be converted to w32 format.
-# Result is available in $func_convert_core_file_wine_to_w32_result, and will
-# be empty on error (or when ARG is empty)
-func_convert_core_file_wine_to_w32 ()
-{
-  $debug_cmd
-
-  func_convert_core_file_wine_to_w32_result=$1
-  if test -n "$1"; then
-    # Unfortunately, winepath does not exit with a non-zero error code, so we
-    # are forced to check the contents of stdout. On the other hand, if the
-    # command is not found, the shell will set an exit code of 127 and print
-    # *an error message* to stdout. So we must check for both error code of
-    # zero AND non-empty stdout, which explains the odd construction:
-    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
-    if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
-      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
-        $SED -e "$sed_naive_backslashify"`
-    else
-      func_convert_core_file_wine_to_w32_result=
-    fi
-  fi
-}
-# end: func_convert_core_file_wine_to_w32
-
-
-# func_convert_core_path_wine_to_w32 ARG
-# Helper function used by path conversion functions when $build is *nix, and
-# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
-# configured wine environment available, with the winepath program in $build's
-# $PATH. Assumes ARG has no leading or trailing path separator characters.
-#
-# ARG is path to be converted from $build format to win32.
-# Result is available in $func_convert_core_path_wine_to_w32_result.
-# Unconvertible file (directory) names in ARG are skipped; if no directory names
-# are convertible, then the result may be empty.
-func_convert_core_path_wine_to_w32 ()
-{
-  $debug_cmd
-
-  # unfortunately, winepath doesn't convert paths, only file names
-  func_convert_core_path_wine_to_w32_result=
-  if test -n "$1"; then
-    oldIFS=$IFS
-    IFS=:
-    for func_convert_core_path_wine_to_w32_f in $1; do
-      IFS=$oldIFS
-      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
-      if test -n "$func_convert_core_file_wine_to_w32_result"; then
-        if test -z "$func_convert_core_path_wine_to_w32_result"; then
-          func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
-        else
-          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
-        fi
-      fi
-    done
-    IFS=$oldIFS
-  fi
-}
-# end: func_convert_core_path_wine_to_w32
-
-
-# func_cygpath ARGS...
-# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
-# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
-# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
-# (2), returns the Cygwin file name or path in func_cygpath_result (input
-# file name or path is assumed to be in w32 format, as previously converted
-# from $build's *nix or MSYS format). In case (3), returns the w32 file name
-# or path in func_cygpath_result (input file name or path is assumed to be in
-# Cygwin format). Returns an empty string on error.
-#
-# ARGS are passed to cygpath, with the last one being the file name or path to
-# be converted.
-#
-# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
-# environment variable; do not put it in $PATH.
-func_cygpath ()
-{
-  $debug_cmd
-
-  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
-    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
-    if test "$?" -ne 0; then
-      # on failure, ensure result is empty
-      func_cygpath_result=
-    fi
-  else
-    func_cygpath_result=
-    func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
-  fi
-}
-#end: func_cygpath
-
-
-# func_convert_core_msys_to_w32 ARG
-# Convert file name or path ARG from MSYS format to w32 format.  Return
-# result in func_convert_core_msys_to_w32_result.
-func_convert_core_msys_to_w32 ()
-{
-  $debug_cmd
-
-  # awkward: cmd appends spaces to result
-  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
-    $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
-}
-#end: func_convert_core_msys_to_w32
-
-
-# func_convert_file_check ARG1 ARG2
-# Verify that ARG1 (a file name in $build format) was converted to $host
-# format in ARG2. Otherwise, emit an error message, but continue (resetting
-# func_to_host_file_result to ARG1).
-func_convert_file_check ()
-{
-  $debug_cmd
-
-  if test -z "$2" && test -n "$1"; then
-    func_error "Could not determine host file name corresponding to"
-    func_error "  '$1'"
-    func_error "Continuing, but uninstalled executables may not work."
-    # Fallback:
-    func_to_host_file_result=$1
-  fi
-}
-# end func_convert_file_check
-
-
-# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
-# Verify that FROM_PATH (a path in $build format) was converted to $host
-# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
-# func_to_host_file_result to a simplistic fallback value (see below).
-func_convert_path_check ()
-{
-  $debug_cmd
-
-  if test -z "$4" && test -n "$3"; then
-    func_error "Could not determine the host path corresponding to"
-    func_error "  '$3'"
-    func_error "Continuing, but uninstalled executables may not work."
-    # Fallback.  This is a deliberately simplistic "conversion" and
-    # should not be "improved".  See libtool.info.
-    if test "x$1" != "x$2"; then
-      lt_replace_pathsep_chars="s|$1|$2|g"
-      func_to_host_path_result=`echo "$3" |
-        $SED -e "$lt_replace_pathsep_chars"`
-    else
-      func_to_host_path_result=$3
-    fi
-  fi
-}
-# end func_convert_path_check
-
-
-# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
-# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
-# and appending REPL if ORIG matches BACKPAT.
-func_convert_path_front_back_pathsep ()
-{
-  $debug_cmd
-
-  case $4 in
-  $1 ) func_to_host_path_result=$3$func_to_host_path_result
-    ;;
-  esac
-  case $4 in
-  $2 ) func_append func_to_host_path_result "$3"
-    ;;
-  esac
-}
-# end func_convert_path_front_back_pathsep
-
-
-##################################################
-# $build to $host FILE NAME CONVERSION FUNCTIONS #
-##################################################
-# invoked via '$to_host_file_cmd ARG'
-#
-# In each case, ARG is the path to be converted from $build to $host format.
-# Result will be available in $func_to_host_file_result.
-
-
-# func_to_host_file ARG
-# Converts the file name ARG from $build format to $host format. Return result
-# in func_to_host_file_result.
-func_to_host_file ()
-{
-  $debug_cmd
-
-  $to_host_file_cmd "$1"
-}
-# end func_to_host_file
-
-
-# func_to_tool_file ARG LAZY
-# converts the file name ARG from $build format to toolchain format. Return
-# result in func_to_tool_file_result.  If the conversion in use is listed
-# in (the comma separated) LAZY, no conversion takes place.
-func_to_tool_file ()
-{
-  $debug_cmd
-
-  case ,$2, in
-    *,"$to_tool_file_cmd",*)
-      func_to_tool_file_result=$1
-      ;;
-    *)
-      $to_tool_file_cmd "$1"
-      func_to_tool_file_result=$func_to_host_file_result
-      ;;
-  esac
-}
-# end func_to_tool_file
-
-
-# func_convert_file_noop ARG
-# Copy ARG to func_to_host_file_result.
-func_convert_file_noop ()
-{
-  func_to_host_file_result=$1
-}
-# end func_convert_file_noop
-
-
-# func_convert_file_msys_to_w32 ARG
-# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
-# conversion to w32 is not available inside the cwrapper.  Returns result in
-# func_to_host_file_result.
-func_convert_file_msys_to_w32 ()
-{
-  $debug_cmd
-
-  func_to_host_file_result=$1
-  if test -n "$1"; then
-    func_convert_core_msys_to_w32 "$1"
-    func_to_host_file_result=$func_convert_core_msys_to_w32_result
-  fi
-  func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_msys_to_w32
-
-
-# func_convert_file_cygwin_to_w32 ARG
-# Convert file name ARG from Cygwin to w32 format.  Returns result in
-# func_to_host_file_result.
-func_convert_file_cygwin_to_w32 ()
-{
-  $debug_cmd
-
-  func_to_host_file_result=$1
-  if test -n "$1"; then
-    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
-    # LT_CYGPATH in this case.
-    func_to_host_file_result=`cygpath -m "$1"`
-  fi
-  func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_cygwin_to_w32
-
-
-# func_convert_file_nix_to_w32 ARG
-# Convert file name ARG from *nix to w32 format.  Requires a wine environment
-# and a working winepath. Returns result in func_to_host_file_result.
-func_convert_file_nix_to_w32 ()
-{
-  $debug_cmd
-
-  func_to_host_file_result=$1
-  if test -n "$1"; then
-    func_convert_core_file_wine_to_w32 "$1"
-    func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
-  fi
-  func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_nix_to_w32
-
-
-# func_convert_file_msys_to_cygwin ARG
-# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
-# Returns result in func_to_host_file_result.
-func_convert_file_msys_to_cygwin ()
-{
-  $debug_cmd
-
-  func_to_host_file_result=$1
-  if test -n "$1"; then
-    func_convert_core_msys_to_w32 "$1"
-    func_cygpath -u "$func_convert_core_msys_to_w32_result"
-    func_to_host_file_result=$func_cygpath_result
-  fi
-  func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_msys_to_cygwin
-
-
-# func_convert_file_nix_to_cygwin ARG
-# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
-# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
-# in func_to_host_file_result.
-func_convert_file_nix_to_cygwin ()
-{
-  $debug_cmd
-
-  func_to_host_file_result=$1
-  if test -n "$1"; then
-    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
-    func_convert_core_file_wine_to_w32 "$1"
-    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
-    func_to_host_file_result=$func_cygpath_result
-  fi
-  func_convert_file_check "$1" "$func_to_host_file_result"
-}
-# end func_convert_file_nix_to_cygwin
-
-
-#############################################
-# $build to $host PATH CONVERSION FUNCTIONS #
-#############################################
-# invoked via '$to_host_path_cmd ARG'
-#
-# In each case, ARG is the path to be converted from $build to $host format.
-# The result will be available in $func_to_host_path_result.
-#
-# Path separators are also converted from $build format to $host format.  If
-# ARG begins or ends with a path separator character, it is preserved (but
-# converted to $host format) on output.
-#
-# All path conversion functions are named using the following convention:
-#   file name conversion function    : func_convert_file_X_to_Y ()
-#   path conversion function         : func_convert_path_X_to_Y ()
-# where, for any given $build/$host combination the 'X_to_Y' value is the
-# same.  If conversion functions are added for new $build/$host combinations,
-# the two new functions must follow this pattern, or func_init_to_host_path_cmd
-# will break.
-
-
-# func_init_to_host_path_cmd
-# Ensures that function "pointer" variable $to_host_path_cmd is set to the
-# appropriate value, based on the value of $to_host_file_cmd.
-to_host_path_cmd=
-func_init_to_host_path_cmd ()
-{
-  $debug_cmd
-
-  if test -z "$to_host_path_cmd"; then
-    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
-    to_host_path_cmd=func_convert_path_$func_stripname_result
-  fi
-}
-
-
-# func_to_host_path ARG
-# Converts the path ARG from $build format to $host format. Return result
-# in func_to_host_path_result.
-func_to_host_path ()
-{
-  $debug_cmd
-
-  func_init_to_host_path_cmd
-  $to_host_path_cmd "$1"
-}
-# end func_to_host_path
-
-
-# func_convert_path_noop ARG
-# Copy ARG to func_to_host_path_result.
-func_convert_path_noop ()
-{
-  func_to_host_path_result=$1
-}
-# end func_convert_path_noop
-
-
-# func_convert_path_msys_to_w32 ARG
-# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
-# conversion to w32 is not available inside the cwrapper.  Returns result in
-# func_to_host_path_result.
-func_convert_path_msys_to_w32 ()
-{
-  $debug_cmd
-
-  func_to_host_path_result=$1
-  if test -n "$1"; then
-    # Remove leading and trailing path separator characters from ARG.  MSYS
-    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
-    # and winepath ignores them completely.
-    func_stripname : : "$1"
-    func_to_host_path_tmp1=$func_stripname_result
-    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
-    func_to_host_path_result=$func_convert_core_msys_to_w32_result
-    func_convert_path_check : ";" \
-      "$func_to_host_path_tmp1" "$func_to_host_path_result"
-    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
-  fi
-}
-# end func_convert_path_msys_to_w32
-
-
-# func_convert_path_cygwin_to_w32 ARG
-# Convert path ARG from Cygwin to w32 format.  Returns result in
-# func_to_host_file_result.
-func_convert_path_cygwin_to_w32 ()
-{
-  $debug_cmd
-
-  func_to_host_path_result=$1
-  if test -n "$1"; then
-    # See func_convert_path_msys_to_w32:
-    func_stripname : : "$1"
-    func_to_host_path_tmp1=$func_stripname_result
-    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
-    func_convert_path_check : ";" \
-      "$func_to_host_path_tmp1" "$func_to_host_path_result"
-    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
-  fi
-}
-# end func_convert_path_cygwin_to_w32
-
-
-# func_convert_path_nix_to_w32 ARG
-# Convert path ARG from *nix to w32 format.  Requires a wine environment and
-# a working winepath.  Returns result in func_to_host_file_result.
-func_convert_path_nix_to_w32 ()
-{
-  $debug_cmd
-
-  func_to_host_path_result=$1
-  if test -n "$1"; then
-    # See func_convert_path_msys_to_w32:
-    func_stripname : : "$1"
-    func_to_host_path_tmp1=$func_stripname_result
-    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
-    func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
-    func_convert_path_check : ";" \
-      "$func_to_host_path_tmp1" "$func_to_host_path_result"
-    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
-  fi
-}
-# end func_convert_path_nix_to_w32
-
-
-# func_convert_path_msys_to_cygwin ARG
-# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
-# Returns result in func_to_host_file_result.
-func_convert_path_msys_to_cygwin ()
-{
-  $debug_cmd
-
-  func_to_host_path_result=$1
-  if test -n "$1"; then
-    # See func_convert_path_msys_to_w32:
-    func_stripname : : "$1"
-    func_to_host_path_tmp1=$func_stripname_result
-    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
-    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
-    func_to_host_path_result=$func_cygpath_result
-    func_convert_path_check : : \
-      "$func_to_host_path_tmp1" "$func_to_host_path_result"
-    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
-  fi
-}
-# end func_convert_path_msys_to_cygwin
-
-
-# func_convert_path_nix_to_cygwin ARG
-# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
-# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
-# func_to_host_file_result.
-func_convert_path_nix_to_cygwin ()
-{
-  $debug_cmd
-
-  func_to_host_path_result=$1
-  if test -n "$1"; then
-    # Remove leading and trailing path separator characters from
-    # ARG. msys behavior is inconsistent here, cygpath turns them
-    # into '.;' and ';.', and winepath ignores them completely.
-    func_stripname : : "$1"
-    func_to_host_path_tmp1=$func_stripname_result
-    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
-    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
-    func_to_host_path_result=$func_cygpath_result
-    func_convert_path_check : : \
-      "$func_to_host_path_tmp1" "$func_to_host_path_result"
-    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
-  fi
-}
-# end func_convert_path_nix_to_cygwin
-
-
-# func_dll_def_p FILE
-# True iff FILE is a Windows DLL '.def' file.
-# Keep in sync with _LT_DLL_DEF_P in libtool.m4
-func_dll_def_p ()
-{
-  $debug_cmd
-
-  func_dll_def_p_tmp=`$SED -n \
-    -e 's/^[    ]*//' \
-    -e '/^\(;.*\)*$/d' \
-    -e 's/^\(EXPORTS\|LIBRARY\)\([      ].*\)*$/DEF/p' \
-    -e q \
-    "$1"`
-  test DEF = "$func_dll_def_p_tmp"
-}
-
-
-# func_mode_compile arg...
-func_mode_compile ()
-{
-    $debug_cmd
-
-    # Get the compilation command and the source file.
-    base_compile=
-    srcfile=$nonopt  #  always keep a non-empty value in "srcfile"
-    suppress_opt=yes
-    suppress_output=
-    arg_mode=normal
-    libobj=
-    later=
-    pie_flag=
-
-    for arg
-    do
-      case $arg_mode in
-      arg  )
-       # do not "continue".  Instead, add this to base_compile
-       lastarg=$arg
-       arg_mode=normal
-       ;;
-
-      target )
-       libobj=$arg
-       arg_mode=normal
-       continue
-       ;;
-
-      normal )
-       # Accept any command-line options.
-       case $arg in
-       -o)
-         test -n "$libobj" && \
-           func_fatal_error "you cannot specify '-o' more than once"
-         arg_mode=target
-         continue
-         ;;
-
-       -pie | -fpie | -fPIE)
-          func_append pie_flag " $arg"
-         continue
-         ;;
-
-       -shared | -static | -prefer-pic | -prefer-non-pic)
-         func_append later " $arg"
-         continue
-         ;;
-
-       -no-suppress)
-         suppress_opt=no
-         continue
-         ;;
-
-       -Xcompiler)
-         arg_mode=arg  #  the next one goes into the "base_compile" arg list
-         continue      #  The current "srcfile" will either be retained or
-         ;;            #  replaced later.  I would guess that would be a bug.
-
-       -Wc,*)
-         func_stripname '-Wc,' '' "$arg"
-         args=$func_stripname_result
-         lastarg=
-         save_ifs=$IFS; IFS=,
-         for arg in $args; do
-           IFS=$save_ifs
-           func_append_quoted lastarg "$arg"
-         done
-         IFS=$save_ifs
-         func_stripname ' ' '' "$lastarg"
-         lastarg=$func_stripname_result
-
-         # Add the arguments to base_compile.
-         func_append base_compile " $lastarg"
-         continue
-         ;;
-
-       *)
-         # Accept the current argument as the source file.
-         # The previous "srcfile" becomes the current argument.
-         #
-         lastarg=$srcfile
-         srcfile=$arg
-         ;;
-       esac  #  case $arg
-       ;;
-      esac    #  case $arg_mode
-
-      # Aesthetically quote the previous argument.
-      func_append_quoted base_compile "$lastarg"
-    done # for arg
-
-    case $arg_mode in
-    arg)
-      func_fatal_error "you must specify an argument for -Xcompile"
-      ;;
-    target)
-      func_fatal_error "you must specify a target with '-o'"
-      ;;
-    *)
-      # Get the name of the library object.
-      test -z "$libobj" && {
-       func_basename "$srcfile"
-       libobj=$func_basename_result
-      }
-      ;;
-    esac
-
-    # Recognize several different file suffixes.
-    # If the user specifies -o file.o, it is replaced with file.lo
-    case $libobj in
-    *.[cCFSifmso] | \
-    *.ada | *.adb | *.ads | *.asm | \
-    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
-    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
-      func_xform "$libobj"
-      libobj=$func_xform_result
-      ;;
-    esac
-
-    case $libobj in
-    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
-    *)
-      func_fatal_error "cannot determine name of library object from '$libobj'"
-      ;;
-    esac
-
-    func_infer_tag $base_compile
-
-    for arg in $later; do
-      case $arg in
-      -shared)
-       test yes = "$build_libtool_libs" \
-         || func_fatal_configuration "cannot build a shared library"
-       build_old_libs=no
-       continue
-       ;;
-
-      -static)
-       build_libtool_libs=no
-       build_old_libs=yes
-       continue
-       ;;
-
-      -prefer-pic)
-       pic_mode=yes
-       continue
-       ;;
-
-      -prefer-non-pic)
-       pic_mode=no
-       continue
-       ;;
-      esac
-    done
-
-    func_quote_for_eval "$libobj"
-    test "X$libobj" != "X$func_quote_for_eval_result" \
-      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'   &()|`$[]' \
-      && func_warning "libobj name '$libobj' may not contain shell special characters."
-    func_dirname_and_basename "$obj" "/" ""
-    objname=$func_basename_result
-    xdir=$func_dirname_result
-    lobj=$xdir$objdir/$objname
-
-    test -z "$base_compile" && \
-      func_fatal_help "you must specify a compilation command"
-
-    # Delete any leftover library objects.
-    if test yes = "$build_old_libs"; then
-      removelist="$obj $lobj $libobj ${libobj}T"
-    else
-      removelist="$lobj $libobj ${libobj}T"
-    fi
-
-    # On Cygwin there's no "real" PIC flag so we must build both object types
-    case $host_os in
-    cygwin* | mingw* | pw32* | os2* | cegcc*)
-      pic_mode=default
-      ;;
-    esac
-    if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
-      # non-PIC code in shared libraries is not supported
-      pic_mode=default
-    fi
-
-    # Calculate the filename of the output object if compiler does
-    # not support -o with -c
-    if test no = "$compiler_c_o"; then
-      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
-      lockfile=$output_obj.lock
-    else
-      output_obj=
-      need_locks=no
-      lockfile=
-    fi
-
-    # Lock this critical section if it is needed
-    # We use this script file to make the link, it avoids creating a new file
-    if test yes = "$need_locks"; then
-      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
-       func_echo "Waiting for $lockfile to be removed"
-       sleep 2
-      done
-    elif test warn = "$need_locks"; then
-      if test -f "$lockfile"; then
-       $ECHO "\
-*** ERROR, $lockfile exists and contains:
-`cat $lockfile 2>/dev/null`
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support '-c' and '-o' together.  If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
-       $opt_dry_run || $RM $removelist
-       exit $EXIT_FAILURE
-      fi
-      func_append removelist " $output_obj"
-      $ECHO "$srcfile" > "$lockfile"
-    fi
-
-    $opt_dry_run || $RM $removelist
-    func_append removelist " $lockfile"
-    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
-
-    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
-    srcfile=$func_to_tool_file_result
-    func_quote_for_eval "$srcfile"
-    qsrcfile=$func_quote_for_eval_result
-
-    # Only build a PIC object if we are building libtool libraries.
-    if test yes = "$build_libtool_libs"; then
-      # Without this assignment, base_compile gets emptied.
-      fbsd_hideous_sh_bug=$base_compile
-
-      if test no != "$pic_mode"; then
-       command="$base_compile $qsrcfile $pic_flag"
-      else
-       # Don't build PIC code
-       command="$base_compile $qsrcfile"
-      fi
-
-      func_mkdir_p "$xdir$objdir"
-
-      if test -z "$output_obj"; then
-       # Place PIC objects in $objdir
-       func_append command " -o $lobj"
-      fi
-
-      func_show_eval_locale "$command" \
-          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
-
-      if test warn = "$need_locks" &&
-        test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
-       $ECHO "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support '-c' and '-o' together.  If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
-       $opt_dry_run || $RM $removelist
-       exit $EXIT_FAILURE
-      fi
-
-      # Just move the object if needed, then go on to compile the next one
-      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
-       func_show_eval '$MV "$output_obj" "$lobj"' \
-         'error=$?; $opt_dry_run || $RM $removelist; exit $error'
-      fi
-
-      # Allow error messages only from the first compilation.
-      if test yes = "$suppress_opt"; then
-       suppress_output=' >/dev/null 2>&1'
-      fi
-    fi
-
-    # Only build a position-dependent object if we build old libraries.
-    if test yes = "$build_old_libs"; then
-      if test yes != "$pic_mode"; then
-       # Don't build PIC code
-       command="$base_compile $qsrcfile$pie_flag"
-      else
-       command="$base_compile $qsrcfile $pic_flag"
-      fi
-      if test yes = "$compiler_c_o"; then
-       func_append command " -o $obj"
-      fi
-
-      # Suppress compiler output if we already did a PIC compilation.
-      func_append command "$suppress_output"
-      func_show_eval_locale "$command" \
-        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
-
-      if test warn = "$need_locks" &&
-        test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
-       $ECHO "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support '-c' and '-o' together.  If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
-       $opt_dry_run || $RM $removelist
-       exit $EXIT_FAILURE
-      fi
-
-      # Just move the object if needed
-      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
-       func_show_eval '$MV "$output_obj" "$obj"' \
-         'error=$?; $opt_dry_run || $RM $removelist; exit $error'
-      fi
-    fi
-
-    $opt_dry_run || {
-      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
-
-      # Unlock the critical section if it was locked
-      if test no != "$need_locks"; then
-       removelist=$lockfile
-        $RM "$lockfile"
-      fi
-    }
-
-    exit $EXIT_SUCCESS
-}
-
-$opt_help || {
-  test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
-}
-
-func_mode_help ()
-{
-    # We need to display help for each of the modes.
-    case $opt_mode in
-      "")
-        # Generic help is extracted from the usage comments
-        # at the start of this file.
-        func_help
-        ;;
-
-      clean)
-        $ECHO \
-"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
-
-Remove files from the build directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
-to RM.
-
-If FILE is a libtool library, object or program, all the files associated
-with it are deleted. Otherwise, only FILE itself is deleted using RM."
-        ;;
-
-      compile)
-      $ECHO \
-"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
-
-Compile a source file into a libtool library object.
-
-This mode accepts the following additional options:
-
-  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
-  -no-suppress      do not suppress compiler output for multiple passes
-  -prefer-pic       try to build PIC objects only
-  -prefer-non-pic   try to build non-PIC objects only
-  -shared           do not build a '.o' file suitable for static linking
-  -static           only build a '.o' file suitable for static linking
-  -Wc,FLAG          pass FLAG directly to the compiler
-
-COMPILE-COMMAND is a command to be used in creating a 'standard' object file
-from the given SOURCEFILE.
-
-The output file name is determined by removing the directory component from
-SOURCEFILE, then substituting the C source code suffix '.c' with the
-library object suffix, '.lo'."
-        ;;
-
-      execute)
-        $ECHO \
-"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
-
-Automatically set library path, then run a program.
-
-This mode accepts the following additional options:
-
-  -dlopen FILE      add the directory containing FILE to the library path
-
-This mode sets the library path environment variable according to '-dlopen'
-flags.
-
-If any of the ARGS are libtool executable wrappers, then they are translated
-into their corresponding uninstalled binary, and any of their required library
-directories are added to the library path.
-
-Then, COMMAND is executed, with ARGS as arguments."
-        ;;
-
-      finish)
-        $ECHO \
-"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
-
-Complete the installation of libtool libraries.
-
-Each LIBDIR is a directory that contains libtool libraries.
-
-The commands that this mode executes may require superuser privileges.  Use
-the '--dry-run' option if you just want to see what would be executed."
-        ;;
-
-      install)
-        $ECHO \
-"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
-
-Install executables or libraries.
-
-INSTALL-COMMAND is the installation command.  The first component should be
-either the 'install' or 'cp' program.
-
-The following components of INSTALL-COMMAND are treated specially:
-
-  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
-
-The rest of the components are interpreted as arguments to that command (only
-BSD-compatible install options are recognized)."
-        ;;
-
-      link)
-        $ECHO \
-"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
-
-Link object files or libraries together to form another library, or to
-create an executable program.
-
-LINK-COMMAND is a command using the C compiler that you would use to create
-a program from several object files.
-
-The following components of LINK-COMMAND are treated specially:
-
-  -all-static       do not do any dynamic linking at all
-  -avoid-version    do not add a version suffix if possible
-  -bindir BINDIR    specify path to binaries directory (for systems where
-                    libraries must be found in the PATH setting at runtime)
-  -dlopen FILE      '-dlpreopen' FILE if it cannot be dlopened at runtime
-  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
-  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
-  -export-symbols SYMFILE
-                    try to export only the symbols listed in SYMFILE
-  -export-symbols-regex REGEX
-                    try to export only the symbols matching REGEX
-  -LLIBDIR          search LIBDIR for required installed libraries
-  -lNAME            OUTPUT-FILE requires the installed library libNAME
-  -module           build a library that can dlopened
-  -no-fast-install  disable the fast-install mode
-  -no-install       link a not-installable executable
-  -no-undefined     declare that a library does not refer to external symbols
-  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
-  -objectlist FILE  use a list of object files found in FILE to specify objects
-  -os2dllname NAME  force a short DLL name on OS/2 (no effect on other OSes)
-  -precious-files-regex REGEX
-                    don't remove output files matching REGEX
-  -release RELEASE  specify package release information
-  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
-  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
-  -shared           only do dynamic linking of libtool libraries
-  -shrext SUFFIX    override the standard shared library file extension
-  -static           do not do any dynamic linking of uninstalled libtool libraries
-  -static-libtool-libs
-                    do not do any dynamic linking of libtool libraries
-  -version-info CURRENT[:REVISION[:AGE]]
-                    specify library version info [each variable defaults to 0]
-  -weak LIBNAME     declare that the target provides the LIBNAME interface
-  -Wc,FLAG
-  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
-  -Wl,FLAG
-  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
-  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
-
-All other options (arguments beginning with '-') are ignored.
-
-Every other argument is treated as a filename.  Files ending in '.la' are
-treated as uninstalled libtool libraries, other files are standard or library
-object files.
-
-If the OUTPUT-FILE ends in '.la', then a libtool library is created,
-only library objects ('.lo' files) may be specified, and '-rpath' is
-required, except when creating a convenience library.
-
-If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
-using 'ar' and 'ranlib', or on Windows using 'lib'.
-
-If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
-is created, otherwise an executable program is created."
-        ;;
-
-      uninstall)
-        $ECHO \
-"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
-
-Remove libraries from an installation directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
-to RM.
-
-If FILE is a libtool library, all the files associated with it are deleted.
-Otherwise, only FILE itself is deleted using RM."
-        ;;
-
-      *)
-        func_fatal_help "invalid operation mode '$opt_mode'"
-        ;;
-    esac
-
-    echo
-    $ECHO "Try '$progname --help' for more information about other modes."
-}
-
-# Now that we've collected a possible --mode arg, show help if necessary
-if $opt_help; then
-  if test : = "$opt_help"; then
-    func_mode_help
-  else
-    {
-      func_help noexit
-      for opt_mode in compile link execute install finish uninstall clean; do
-       func_mode_help
-      done
-    } | $SED -n '1p; 2,$s/^Usage:/  or: /p'
-    {
-      func_help noexit
-      for opt_mode in compile link execute install finish uninstall clean; do
-       echo
-       func_mode_help
-      done
-    } |
-    $SED '1d
-      /^When reporting/,/^Report/{
-       H
-       d
-      }
-      $x
-      /information about other modes/d
-      /more detailed .*MODE/d
-      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
-  fi
-  exit $?
-fi
-
-
-# func_mode_execute arg...
-func_mode_execute ()
-{
-    $debug_cmd
-
-    # The first argument is the command name.
-    cmd=$nonopt
-    test -z "$cmd" && \
-      func_fatal_help "you must specify a COMMAND"
-
-    # Handle -dlopen flags immediately.
-    for file in $opt_dlopen; do
-      test -f "$file" \
-       || func_fatal_help "'$file' is not a file"
-
-      dir=
-      case $file in
-      *.la)
-       func_resolve_sysroot "$file"
-       file=$func_resolve_sysroot_result
-
-       # Check to see that this really is a libtool archive.
-       func_lalib_unsafe_p "$file" \
-         || func_fatal_help "'$lib' is not a valid libtool archive"
-
-       # Read the libtool library.
-       dlname=
-       library_names=
-       func_source "$file"
-
-       # Skip this library if it cannot be dlopened.
-       if test -z "$dlname"; then
-         # Warn if it was a shared library.
-         test -n "$library_names" && \
-           func_warning "'$file' was not linked with '-export-dynamic'"
-         continue
-       fi
-
-       func_dirname "$file" "" "."
-       dir=$func_dirname_result
-
-       if test -f "$dir/$objdir/$dlname"; then
-         func_append dir "/$objdir"
-       else
-         if test ! -f "$dir/$dlname"; then
-           func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
-         fi
-       fi
-       ;;
-
-      *.lo)
-       # Just add the directory containing the .lo file.
-       func_dirname "$file" "" "."
-       dir=$func_dirname_result
-       ;;
-
-      *)
-       func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
-       continue
-       ;;
-      esac
-
-      # Get the absolute pathname.
-      absdir=`cd "$dir" && pwd`
-      test -n "$absdir" && dir=$absdir
-
-      # Now add the directory to shlibpath_var.
-      if eval "test -z \"\$$shlibpath_var\""; then
-       eval "$shlibpath_var=\"\$dir\""
-      else
-       eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
-      fi
-    done
-
-    # This variable tells wrapper scripts just to set shlibpath_var
-    # rather than running their programs.
-    libtool_execute_magic=$magic
-
-    # Check if any of the arguments is a wrapper script.
-    args=
-    for file
-    do
-      case $file in
-      -* | *.la | *.lo ) ;;
-      *)
-       # Do a test to see if this is really a libtool program.
-       if func_ltwrapper_script_p "$file"; then
-         func_source "$file"
-         # Transform arg to wrapped name.
-         file=$progdir/$program
-       elif func_ltwrapper_executable_p "$file"; then
-         func_ltwrapper_scriptname "$file"
-         func_source "$func_ltwrapper_scriptname_result"
-         # Transform arg to wrapped name.
-         file=$progdir/$program
-       fi
-       ;;
-      esac
-      # Quote arguments (to preserve shell metacharacters).
-      func_append_quoted args "$file"
-    done
-
-    if $opt_dry_run; then
-      # Display what would be done.
-      if test -n "$shlibpath_var"; then
-       eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
-       echo "export $shlibpath_var"
-      fi
-      $ECHO "$cmd$args"
-      exit $EXIT_SUCCESS
-    else
-      if test -n "$shlibpath_var"; then
-       # Export the shlibpath_var.
-       eval "export $shlibpath_var"
-      fi
-
-      # Restore saved environment variables
-      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
-      do
-       eval "if test \"\${save_$lt_var+set}\" = set; then
-                $lt_var=\$save_$lt_var; export $lt_var
-             else
-               $lt_unset $lt_var
-             fi"
-      done
-
-      # Now prepare to actually exec the command.
-      exec_cmd=\$cmd$args
-    fi
-}
-
-test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
-
-
-# func_mode_finish arg...
-func_mode_finish ()
-{
-    $debug_cmd
-
-    libs=
-    libdirs=
-    admincmds=
-
-    for opt in "$nonopt" ${1+"$@"}
-    do
-      if test -d "$opt"; then
-       func_append libdirs " $opt"
-
-      elif test -f "$opt"; then
-       if func_lalib_unsafe_p "$opt"; then
-         func_append libs " $opt"
-       else
-         func_warning "'$opt' is not a valid libtool archive"
-       fi
-
-      else
-       func_fatal_error "invalid argument '$opt'"
-      fi
-    done
-
-    if test -n "$libs"; then
-      if test -n "$lt_sysroot"; then
-        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
-        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
-      else
-        sysroot_cmd=
-      fi
-
-      # Remove sysroot references
-      if $opt_dry_run; then
-        for lib in $libs; do
-          echo "removing references to $lt_sysroot and '=' prefixes from $lib"
-        done
-      else
-        tmpdir=`func_mktempdir`
-        for lib in $libs; do
-         $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
-           > $tmpdir/tmp-la
-         mv -f $tmpdir/tmp-la $lib
-       done
-        ${RM}r "$tmpdir"
-      fi
-    fi
-
-    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
-      for libdir in $libdirs; do
-       if test -n "$finish_cmds"; then
-         # Do each command in the finish commands.
-         func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
-'"$cmd"'"'
-       fi
-       if test -n "$finish_eval"; then
-         # Do the single finish_eval.
-         eval cmds=\"$finish_eval\"
-         $opt_dry_run || eval "$cmds" || func_append admincmds "
-       $cmds"
-       fi
-      done
-    fi
-
-    # Exit here if they wanted silent mode.
-    $opt_quiet && exit $EXIT_SUCCESS
-
-    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
-      echo "----------------------------------------------------------------------"
-      echo "Libraries have been installed in:"
-      for libdir in $libdirs; do
-       $ECHO "   $libdir"
-      done
-      echo
-      echo "If you ever happen to want to link against installed libraries"
-      echo "in a given directory, LIBDIR, you must either use libtool, and"
-      echo "specify the full pathname of the library, or use the '-LLIBDIR'"
-      echo "flag during linking and do at least one of the following:"
-      if test -n "$shlibpath_var"; then
-       echo "   - add LIBDIR to the '$shlibpath_var' environment variable"
-       echo "     during execution"
-      fi
-      if test -n "$runpath_var"; then
-       echo "   - add LIBDIR to the '$runpath_var' environment variable"
-       echo "     during linking"
-      fi
-      if test -n "$hardcode_libdir_flag_spec"; then
-       libdir=LIBDIR
-       eval flag=\"$hardcode_libdir_flag_spec\"
-
-       $ECHO "   - use the '$flag' linker flag"
-      fi
-      if test -n "$admincmds"; then
-       $ECHO "   - have your system administrator run these commands:$admincmds"
-      fi
-      if test -f /etc/ld.so.conf; then
-       echo "   - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
-      fi
-      echo
-
-      echo "See any operating system documentation about shared libraries for"
-      case $host in
-       solaris2.[6789]|solaris2.1[0-9])
-         echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
-         echo "pages."
-         ;;
-       *)
-         echo "more information, such as the ld(1) and ld.so(8) manual pages."
-         ;;
-      esac
-      echo "----------------------------------------------------------------------"
-    fi
-    exit $EXIT_SUCCESS
-}
-
-test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
-
-
-# func_mode_install arg...
-func_mode_install ()
-{
-    $debug_cmd
-
-    # There may be an optional sh(1) argument at the beginning of
-    # install_prog (especially on Windows NT).
-    if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
-       # Allow the use of GNU shtool's install command.
-       case $nonopt in *shtool*) :;; *) false;; esac
-    then
-      # Aesthetically quote it.
-      func_quote_for_eval "$nonopt"
-      install_prog="$func_quote_for_eval_result "
-      arg=$1
-      shift
-    else
-      install_prog=
-      arg=$nonopt
-    fi
-
-    # The real first argument should be the name of the installation program.
-    # Aesthetically quote it.
-    func_quote_for_eval "$arg"
-    func_append install_prog "$func_quote_for_eval_result"
-    install_shared_prog=$install_prog
-    case " $install_prog " in
-      *[\\\ /]cp\ *) install_cp=: ;;
-      *) install_cp=false ;;
-    esac
-
-    # We need to accept at least all the BSD install flags.
-    dest=
-    files=
-    opts=
-    prev=
-    install_type=
-    isdir=false
-    stripme=
-    no_mode=:
-    for arg
-    do
-      arg2=
-      if test -n "$dest"; then
-       func_append files " $dest"
-       dest=$arg
-       continue
-      fi
-
-      case $arg in
-      -d) isdir=: ;;
-      -f)
-       if $install_cp; then :; else
-         prev=$arg
-       fi
-       ;;
-      -g | -m | -o)
-       prev=$arg
-       ;;
-      -s)
-       stripme=" -s"
-       continue
-       ;;
-      -*)
-       ;;
-      *)
-       # If the previous option needed an argument, then skip it.
-       if test -n "$prev"; then
-         if test X-m = "X$prev" && test -n "$install_override_mode"; then
-           arg2=$install_override_mode
-           no_mode=false
-         fi
-         prev=
-       else
-         dest=$arg
-         continue
-       fi
-       ;;
-      esac
-
-      # Aesthetically quote the argument.
-      func_quote_for_eval "$arg"
-      func_append install_prog " $func_quote_for_eval_result"
-      if test -n "$arg2"; then
-       func_quote_for_eval "$arg2"
-      fi
-      func_append install_shared_prog " $func_quote_for_eval_result"
-    done
-
-    test -z "$install_prog" && \
-      func_fatal_help "you must specify an install program"
-
-    test -n "$prev" && \
-      func_fatal_help "the '$prev' option requires an argument"
-
-    if test -n "$install_override_mode" && $no_mode; then
-      if $install_cp; then :; else
-       func_quote_for_eval "$install_override_mode"
-       func_append install_shared_prog " -m $func_quote_for_eval_result"
-      fi
-    fi
-
-    if test -z "$files"; then
-      if test -z "$dest"; then
-       func_fatal_help "no file or destination specified"
-      else
-       func_fatal_help "you must specify a destination"
-      fi
-    fi
-
-    # Strip any trailing slash from the destination.
-    func_stripname '' '/' "$dest"
-    dest=$func_stripname_result
-
-    # Check to see that the destination is a directory.
-    test -d "$dest" && isdir=:
-    if $isdir; then
-      destdir=$dest
-      destname=
-    else
-      func_dirname_and_basename "$dest" "" "."
-      destdir=$func_dirname_result
-      destname=$func_basename_result
-
-      # Not a directory, so check to see that there is only one file specified.
-      set dummy $files; shift
-      test "$#" -gt 1 && \
-       func_fatal_help "'$dest' is not a directory"
-    fi
-    case $destdir in
-    [\\/]* | [A-Za-z]:[\\/]*) ;;
-    *)
-      for file in $files; do
-       case $file in
-       *.lo) ;;
-       *)
-         func_fatal_help "'$destdir' must be an absolute directory name"
-         ;;
-       esac
-      done
-      ;;
-    esac
-
-    # This variable tells wrapper scripts just to set variables rather
-    # than running their programs.
-    libtool_install_magic=$magic
-
-    staticlibs=
-    future_libdirs=
-    current_libdirs=
-    for file in $files; do
-
-      # Do each installation.
-      case $file in
-      *.$libext)
-       # Do the static libraries later.
-       func_append staticlibs " $file"
-       ;;
-
-      *.la)
-       func_resolve_sysroot "$file"
-       file=$func_resolve_sysroot_result
-
-       # Check to see that this really is a libtool archive.
-       func_lalib_unsafe_p "$file" \
-         || func_fatal_help "'$file' is not a valid libtool archive"
-
-       library_names=
-       old_library=
-       relink_command=
-       func_source "$file"
-
-       # Add the libdir to current_libdirs if it is the destination.
-       if test "X$destdir" = "X$libdir"; then
-         case "$current_libdirs " in
-         *" $libdir "*) ;;
-         *) func_append current_libdirs " $libdir" ;;
-         esac
-       else
-         # Note the libdir as a future libdir.
-         case "$future_libdirs " in
-         *" $libdir "*) ;;
-         *) func_append future_libdirs " $libdir" ;;
-         esac
-       fi
-
-       func_dirname "$file" "/" ""
-       dir=$func_dirname_result
-       func_append dir "$objdir"
-
-       if test -n "$relink_command"; then
-         # Determine the prefix the user has applied to our future dir.
-         inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
-
-         # Don't allow the user to place us outside of our expected
-         # location b/c this prevents finding dependent libraries that
-         # are installed to the same prefix.
-         # At present, this check doesn't affect windows .dll's that
-         # are installed into $libdir/../bin (currently, that works fine)
-         # but it's something to keep an eye on.
-         test "$inst_prefix_dir" = "$destdir" && \
-           func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
-
-         if test -n "$inst_prefix_dir"; then
-           # Stick the inst_prefix_dir data into the link command.
-           relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
-         else
-           relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
-         fi
-
-         func_warning "relinking '$file'"
-         func_show_eval "$relink_command" \
-           'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
-       fi
-
-       # See the names of the shared library.
-       set dummy $library_names; shift
-       if test -n "$1"; then
-         realname=$1
-         shift
-
-         srcname=$realname
-         test -n "$relink_command" && srcname=${realname}T
-
-         # Install the shared library and build the symlinks.
-         func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
-             'exit $?'
-         tstripme=$stripme
-         case $host_os in
-         cygwin* | mingw* | pw32* | cegcc*)
-           case $realname in
-           *.dll.a)
-             tstripme=
-             ;;
-           esac
-           ;;
-         os2*)
-           case $realname in
-           *_dll.a)
-             tstripme=
-             ;;
-           esac
-           ;;
-         esac
-         if test -n "$tstripme" && test -n "$striplib"; then
-           func_show_eval "$striplib $destdir/$realname" 'exit $?'
-         fi
-
-         if test "$#" -gt 0; then
-           # Delete the old symlinks, and create new ones.
-           # Try 'ln -sf' first, because the 'ln' binary might depend on
-           # the symlink we replace!  Solaris /bin/ln does not understand -f,
-           # so we also need to try rm && ln -s.
-           for linkname
-           do
-             test "$linkname" != "$realname" \
-               && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
-           done
-         fi
-
-         # Do each command in the postinstall commands.
-         lib=$destdir/$realname
-         func_execute_cmds "$postinstall_cmds" 'exit $?'
-       fi
-
-       # Install the pseudo-library for information purposes.
-       func_basename "$file"
-       name=$func_basename_result
-       instname=$dir/${name}i
-       func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
-
-       # Maybe install the static library, too.
-       test -n "$old_library" && func_append staticlibs " $dir/$old_library"
-       ;;
-
-      *.lo)
-       # Install (i.e. copy) a libtool object.
-
-       # Figure out destination file name, if it wasn't already specified.
-       if test -n "$destname"; then
-         destfile=$destdir/$destname
-       else
-         func_basename "$file"
-         destfile=$func_basename_result
-         destfile=$destdir/$destfile
-       fi
-
-       # Deduce the name of the destination old-style object file.
-       case $destfile in
-       *.lo)
-         func_lo2o "$destfile"
-         staticdest=$func_lo2o_result
-         ;;
-       *.$objext)
-         staticdest=$destfile
-         destfile=
-         ;;
-       *)
-         func_fatal_help "cannot copy a libtool object to '$destfile'"
-         ;;
-       esac
-
-       # Install the libtool object if requested.
-       test -n "$destfile" && \
-         func_show_eval "$install_prog $file $destfile" 'exit $?'
-
-       # Install the old object if enabled.
-       if test yes = "$build_old_libs"; then
-         # Deduce the name of the old-style object file.
-         func_lo2o "$file"
-         staticobj=$func_lo2o_result
-         func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
-       fi
-       exit $EXIT_SUCCESS
-       ;;
-
-      *)
-       # Figure out destination file name, if it wasn't already specified.
-       if test -n "$destname"; then
-         destfile=$destdir/$destname
-       else
-         func_basename "$file"
-         destfile=$func_basename_result
-         destfile=$destdir/$destfile
-       fi
-
-       # If the file is missing, and there is a .exe on the end, strip it
-       # because it is most likely a libtool script we actually want to
-       # install
-       stripped_ext=
-       case $file in
-         *.exe)
-           if test ! -f "$file"; then
-             func_stripname '' '.exe' "$file"
-             file=$func_stripname_result
-             stripped_ext=.exe
-           fi
-           ;;
-       esac
-
-       # Do a test to see if this is really a libtool program.
-       case $host in
-       *cygwin* | *mingw*)
-           if func_ltwrapper_executable_p "$file"; then
-             func_ltwrapper_scriptname "$file"
-             wrapper=$func_ltwrapper_scriptname_result
-           else
-             func_stripname '' '.exe' "$file"
-             wrapper=$func_stripname_result
-           fi
-           ;;
-       *)
-           wrapper=$file
-           ;;
-       esac
-       if func_ltwrapper_script_p "$wrapper"; then
-         notinst_deplibs=
-         relink_command=
-
-         func_source "$wrapper"
-
-         # Check the variables that should have been set.
-         test -z "$generated_by_libtool_version" && \
-           func_fatal_error "invalid libtool wrapper script '$wrapper'"
-
-         finalize=:
-         for lib in $notinst_deplibs; do
-           # Check to see that each library is installed.
-           libdir=
-           if test -f "$lib"; then
-             func_source "$lib"
-           fi
-           libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
-           if test -n "$libdir" && test ! -f "$libfile"; then
-             func_warning "'$lib' has not been installed in '$libdir'"
-             finalize=false
-           fi
-         done
-
-         relink_command=
-         func_source "$wrapper"
-
-         outputname=
-         if test no = "$fast_install" && test -n "$relink_command"; then
-           $opt_dry_run || {
-             if $finalize; then
-               tmpdir=`func_mktempdir`
-               func_basename "$file$stripped_ext"
-               file=$func_basename_result
-               outputname=$tmpdir/$file
-               # Replace the output file specification.
-               relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
-
-               $opt_quiet || {
-                 func_quote_for_expand "$relink_command"
-                 eval "func_echo $func_quote_for_expand_result"
-               }
-               if eval "$relink_command"; then :
-                 else
-                 func_error "error: relink '$file' with the above command before installing it"
-                 $opt_dry_run || ${RM}r "$tmpdir"
-                 continue
-               fi
-               file=$outputname
-             else
-               func_warning "cannot relink '$file'"
-             fi
-           }
-         else
-           # Install the binary that we compiled earlier.
-           file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
-         fi
-       fi
-
-       # remove .exe since cygwin /usr/bin/install will append another
-       # one anyway
-       case $install_prog,$host in
-       */usr/bin/install*,*cygwin*)
-         case $file:$destfile in
-         *.exe:*.exe)
-           # this is ok
-           ;;
-         *.exe:*)
-           destfile=$destfile.exe
-           ;;
-         *:*.exe)
-           func_stripname '' '.exe' "$destfile"
-           destfile=$func_stripname_result
-           ;;
-         esac
-         ;;
-       esac
-       func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
-       $opt_dry_run || if test -n "$outputname"; then
-         ${RM}r "$tmpdir"
-       fi
-       ;;
-      esac
-    done
-
-    for file in $staticlibs; do
-      func_basename "$file"
-      name=$func_basename_result
-
-      # Set up the ranlib parameters.
-      oldlib=$destdir/$name
-      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
-      tool_oldlib=$func_to_tool_file_result
-
-      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
-
-      if test -n "$stripme" && test -n "$old_striplib"; then
-       func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
-      fi
-
-      # Do each command in the postinstall commands.
-      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
-    done
-
-    test -n "$future_libdirs" && \
-      func_warning "remember to run '$progname --finish$future_libdirs'"
-
-    if test -n "$current_libdirs"; then
-      # Maybe just do a dry run.
-      $opt_dry_run && current_libdirs=" -n$current_libdirs"
-      exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
-    else
-      exit $EXIT_SUCCESS
-    fi
-}
-
-test install = "$opt_mode" && func_mode_install ${1+"$@"}
-
-
-# func_generate_dlsyms outputname originator pic_p
-# Extract symbols from dlprefiles and create ${outputname}S.o with
-# a dlpreopen symbol table.
-func_generate_dlsyms ()
-{
-    $debug_cmd
-
-    my_outputname=$1
-    my_originator=$2
-    my_pic_p=${3-false}
-    my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
-    my_dlsyms=
-
-    if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
-      if test -n "$NM" && test -n "$global_symbol_pipe"; then
-       my_dlsyms=${my_outputname}S.c
-      else
-       func_error "not configured to extract global symbols from dlpreopened files"
-      fi
-    fi
-
-    if test -n "$my_dlsyms"; then
-      case $my_dlsyms in
-      "") ;;
-      *.c)
-       # Discover the nlist of each of the dlfiles.
-       nlist=$output_objdir/$my_outputname.nm
-
-       func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
-
-       # Parse the name list into a source file.
-       func_verbose "creating $output_objdir/$my_dlsyms"
-
-       $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
-/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
-/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
-
-#ifdef __cplusplus
-extern \"C\" {
-#endif
-
-#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
-#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
-#endif
-
-/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
-#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
-/* DATA imports from DLLs on WIN32 can't be const, because runtime
-   relocations are performed -- see ld's documentation on pseudo-relocs.  */
-# define LT_DLSYM_CONST
-#elif defined __osf__
-/* This system does not cope well with relocations in const data.  */
-# define LT_DLSYM_CONST
-#else
-# define LT_DLSYM_CONST const
-#endif
-
-#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
-
-/* External symbol declarations for the compiler. */\
-"
-
-       if test yes = "$dlself"; then
-         func_verbose "generating symbol list for '$output'"
-
-         $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
-
-         # Add our own program objects to the symbol list.
-         progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
-         for progfile in $progfiles; do
-           func_to_tool_file "$progfile" func_convert_file_msys_to_w32
-           func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
-           $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
-         done
-
-         if test -n "$exclude_expsyms"; then
-           $opt_dry_run || {
-             eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
-             eval '$MV "$nlist"T "$nlist"'
-           }
-         fi
-
-         if test -n "$export_symbols_regex"; then
-           $opt_dry_run || {
-             eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
-             eval '$MV "$nlist"T "$nlist"'
-           }
-         fi
-
-         # Prepare the list of exported symbols
-         if test -z "$export_symbols"; then
-           export_symbols=$output_objdir/$outputname.exp
-           $opt_dry_run || {
-             $RM $export_symbols
-             eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
-             case $host in
-             *cygwin* | *mingw* | *cegcc* )
-                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
-                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
-               ;;
-             esac
-           }
-         else
-           $opt_dry_run || {
-             eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
-             eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
-             eval '$MV "$nlist"T "$nlist"'
-             case $host in
-               *cygwin* | *mingw* | *cegcc* )
-                 eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
-                 eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
-                 ;;
-             esac
-           }
-         fi
-       fi
-
-       for dlprefile in $dlprefiles; do
-         func_verbose "extracting global C symbols from '$dlprefile'"
-         func_basename "$dlprefile"
-         name=$func_basename_result
-          case $host in
-           *cygwin* | *mingw* | *cegcc* )
-             # if an import library, we need to obtain dlname
-             if func_win32_import_lib_p "$dlprefile"; then
-               func_tr_sh "$dlprefile"
-               eval "curr_lafile=\$libfile_$func_tr_sh_result"
-               dlprefile_dlbasename=
-               if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
-                 # Use subshell, to avoid clobbering current variable values
-                 dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
-                 if test -n "$dlprefile_dlname"; then
-                   func_basename "$dlprefile_dlname"
-                   dlprefile_dlbasename=$func_basename_result
-                 else
-                   # no lafile. user explicitly requested -dlpreopen <import library>.
-                   $sharedlib_from_linklib_cmd "$dlprefile"
-                   dlprefile_dlbasename=$sharedlib_from_linklib_result
-                 fi
-               fi
-               $opt_dry_run || {
-                 if test -n "$dlprefile_dlbasename"; then
-                   eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
-                 else
-                   func_warning "Could not compute DLL name from $name"
-                   eval '$ECHO ": $name " >> "$nlist"'
-                 fi
-                 func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
-                 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
-                   $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
-               }
-             else # not an import lib
-               $opt_dry_run || {
-                 eval '$ECHO ": $name " >> "$nlist"'
-                 func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
-                 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
-               }
-             fi
-           ;;
-           *)
-             $opt_dry_run || {
-               eval '$ECHO ": $name " >> "$nlist"'
-               func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
-               eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
-             }
-           ;;
-          esac
-       done
-
-       $opt_dry_run || {
-         # Make sure we have at least an empty file.
-         test -f "$nlist" || : > "$nlist"
-
-         if test -n "$exclude_expsyms"; then
-           $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
-           $MV "$nlist"T "$nlist"
-         fi
-
-         # Try sorting and uniquifying the output.
-         if $GREP -v "^: " < "$nlist" |
-             if sort -k 3 </dev/null >/dev/null 2>&1; then
-               sort -k 3
-             else
-               sort +2
-             fi |
-             uniq > "$nlist"S; then
-           :
-         else
-           $GREP -v "^: " < "$nlist" > "$nlist"S
-         fi
-
-         if test -f "$nlist"S; then
-           eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
-         else
-           echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
-         fi
-
-         func_show_eval '$RM "${nlist}I"'
-         if test -n "$global_symbol_to_import"; then
-           eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
-         fi
-
-         echo >> "$output_objdir/$my_dlsyms" "\
-
-/* The mapping between symbol names and symbols.  */
-typedef struct {
-  const char *name;
-  void *address;
-} lt_dlsymlist;
-extern LT_DLSYM_CONST lt_dlsymlist
-lt_${my_prefix}_LTX_preloaded_symbols[];\
-"
-
-         if test -s "$nlist"I; then
-           echo >> "$output_objdir/$my_dlsyms" "\
-static void lt_syminit(void)
-{
-  LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
-  for (; symbol->name; ++symbol)
-    {"
-           $SED 's/.*/      if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
-           echo >> "$output_objdir/$my_dlsyms" "\
-    }
-}"
-         fi
-         echo >> "$output_objdir/$my_dlsyms" "\
-LT_DLSYM_CONST lt_dlsymlist
-lt_${my_prefix}_LTX_preloaded_symbols[] =
-{ {\"$my_originator\", (void *) 0},"
-
-         if test -s "$nlist"I; then
-           echo >> "$output_objdir/$my_dlsyms" "\
-  {\"@INIT@\", (void *) &lt_syminit},"
-         fi
-
-         case $need_lib_prefix in
-         no)
-           eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
-           ;;
-         *)
-           eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
-           ;;
-         esac
-         echo >> "$output_objdir/$my_dlsyms" "\
-  {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
-  return lt_${my_prefix}_LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif\
-"
-       } # !$opt_dry_run
-
-       pic_flag_for_symtable=
-       case "$compile_command " in
-       *" -static "*) ;;
-       *)
-         case $host in
-         # compiling the symbol table file with pic_flag works around
-         # a FreeBSD bug that causes programs to crash when -lm is
-         # linked before any other PIC object.  But we must not use
-         # pic_flag when linking with -static.  The problem exists in
-         # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
-         *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
-           pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
-         *-*-hpux*)
-           pic_flag_for_symtable=" $pic_flag"  ;;
-         *)
-           $my_pic_p && pic_flag_for_symtable=" $pic_flag"
-           ;;
-         esac
-         ;;
-       esac
-       symtab_cflags=
-       for arg in $LTCFLAGS; do
-         case $arg in
-         -pie | -fpie | -fPIE) ;;
-         *) func_append symtab_cflags " $arg" ;;
-         esac
-       done
-
-       # Now compile the dynamic symbol file.
-       func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
-
-       # Clean up the generated files.
-       func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
-
-       # Transform the symbol file into the correct name.
-       symfileobj=$output_objdir/${my_outputname}S.$objext
-       case $host in
-       *cygwin* | *mingw* | *cegcc* )
-         if test -f "$output_objdir/$my_outputname.def"; then
-           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
-           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
-         else
-           compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
-           finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
-         fi
-         ;;
-       *)
-         compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
-         finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
-         ;;
-       esac
-       ;;
-      *)
-       func_fatal_error "unknown suffix for '$my_dlsyms'"
-       ;;
-      esac
-    else
-      # We keep going just in case the user didn't refer to
-      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
-      # really was required.
-
-      # Nullify the symbol file.
-      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
-      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
-    fi
-}
-
-# func_cygming_gnu_implib_p ARG
-# This predicate returns with zero status (TRUE) if
-# ARG is a GNU/binutils-style import library. Returns
-# with nonzero status (FALSE) otherwise.
-func_cygming_gnu_implib_p ()
-{
-  $debug_cmd
-
-  func_to_tool_file "$1" func_convert_file_msys_to_w32
-  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
-  test -n "$func_cygming_gnu_implib_tmp"
-}
-
-# func_cygming_ms_implib_p ARG
-# This predicate returns with zero status (TRUE) if
-# ARG is an MS-style import library. Returns
-# with nonzero status (FALSE) otherwise.
-func_cygming_ms_implib_p ()
-{
-  $debug_cmd
-
-  func_to_tool_file "$1" func_convert_file_msys_to_w32
-  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
-  test -n "$func_cygming_ms_implib_tmp"
-}
-
-# func_win32_libid arg
-# return the library type of file 'arg'
-#
-# Need a lot of goo to handle *both* DLLs and import libs
-# Has to be a shell function in order to 'eat' the argument
-# that is supplied when $file_magic_command is called.
-# Despite the name, also deal with 64 bit binaries.
-func_win32_libid ()
-{
-  $debug_cmd
-
-  win32_libid_type=unknown
-  win32_fileres=`file -L $1 2>/dev/null`
-  case $win32_fileres in
-  *ar\ archive\ import\ library*) # definitely import
-    win32_libid_type="x86 archive import"
-    ;;
-  *ar\ archive*) # could be an import, or static
-    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
-    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
-       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
-      case $nm_interface in
-      "MS dumpbin")
-       if func_cygming_ms_implib_p "$1" ||
-          func_cygming_gnu_implib_p "$1"
-       then
-         win32_nmres=import
-       else
-         win32_nmres=
-       fi
-       ;;
-      *)
-       func_to_tool_file "$1" func_convert_file_msys_to_w32
-       win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
-         $SED -n -e '
-           1,100{
-               / I /{
-                   s|.*|import|
-                   p
-                   q
-               }
-           }'`
-       ;;
-      esac
-      case $win32_nmres in
-      import*)  win32_libid_type="x86 archive import";;
-      *)        win32_libid_type="x86 archive static";;
-      esac
-    fi
-    ;;
-  *DLL*)
-    win32_libid_type="x86 DLL"
-    ;;
-  *executable*) # but shell scripts are "executable" too...
-    case $win32_fileres in
-    *MS\ Windows\ PE\ Intel*)
-      win32_libid_type="x86 DLL"
-      ;;
-    esac
-    ;;
-  esac
-  $ECHO "$win32_libid_type"
-}
-
-# func_cygming_dll_for_implib ARG
-#
-# Platform-specific function to extract the
-# name of the DLL associated with the specified
-# import library ARG.
-# Invoked by eval'ing the libtool variable
-#    $sharedlib_from_linklib_cmd
-# Result is available in the variable
-#    $sharedlib_from_linklib_result
-func_cygming_dll_for_implib ()
-{
-  $debug_cmd
-
-  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
-}
-
-# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
-#
-# The is the core of a fallback implementation of a
-# platform-specific function to extract the name of the
-# DLL associated with the specified import library LIBNAME.
-#
-# SECTION_NAME is either .idata$6 or .idata$7, depending
-# on the platform and compiler that created the implib.
-#
-# Echos the name of the DLL associated with the
-# specified import library.
-func_cygming_dll_for_implib_fallback_core ()
-{
-  $debug_cmd
-
-  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
-  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
-    $SED '/^Contents of section '"$match_literal"':/{
-      # Place marker at beginning of archive member dllname section
-      s/.*/====MARK====/
-      p
-      d
-    }
-    # These lines can sometimes be longer than 43 characters, but
-    # are always uninteresting
-    /:[         ]*file format pe[i]\{,1\}-/d
-    /^In archive [^:]*:/d
-    # Ensure marker is printed
-    /^====MARK====/p
-    # Remove all lines with less than 43 characters
-    /^.\{43\}/!d
-    # From remaining lines, remove first 43 characters
-    s/^.\{43\}//' |
-    $SED -n '
-      # Join marker and all lines until next marker into a single line
-      /^====MARK====/ b para
-      H
-      $ b para
-      b
-      :para
-      x
-      s/\n//g
-      # Remove the marker
-      s/^====MARK====//
-      # Remove trailing dots and whitespace
-      s/[\. \t]*$//
-      # Print
-      /./p' |
-    # we now have a list, one entry per line, of the stringified
-    # contents of the appropriate section of all members of the
-    # archive that possess that section. Heuristic: eliminate
-    # all those that have a first or second character that is
-    # a '.' (that is, objdump's representation of an unprintable
-    # character.) This should work for all archives with less than
-    # 0x302f exports -- but will fail for DLLs whose name actually
-    # begins with a literal '.' or a single character followed by
-    # a '.'.
-    #
-    # Of those that remain, print the first one.
-    $SED -e '/^\./d;/^.\./d;q'
-}
-
-# func_cygming_dll_for_implib_fallback ARG
-# Platform-specific function to extract the
-# name of the DLL associated with the specified
-# import library ARG.
-#
-# This fallback implementation is for use when $DLLTOOL
-# does not support the --identify-strict option.
-# Invoked by eval'ing the libtool variable
-#    $sharedlib_from_linklib_cmd
-# Result is available in the variable
-#    $sharedlib_from_linklib_result
-func_cygming_dll_for_implib_fallback ()
-{
-  $debug_cmd
-
-  if func_cygming_gnu_implib_p "$1"; then
-    # binutils import library
-    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
-  elif func_cygming_ms_implib_p "$1"; then
-    # ms-generated import library
-    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
-  else
-    # unknown
-    sharedlib_from_linklib_result=
-  fi
-}
-
-
-# func_extract_an_archive dir oldlib
-func_extract_an_archive ()
-{
-    $debug_cmd
-
-    f_ex_an_ar_dir=$1; shift
-    f_ex_an_ar_oldlib=$1
-    if test yes = "$lock_old_archive_extraction"; then
-      lockfile=$f_ex_an_ar_oldlib.lock
-      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
-       func_echo "Waiting for $lockfile to be removed"
-       sleep 2
-      done
-    fi
-    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
-                  'stat=$?; rm -f "$lockfile"; exit $stat'
-    if test yes = "$lock_old_archive_extraction"; then
-      $opt_dry_run || rm -f "$lockfile"
-    fi
-    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
-     :
-    else
-      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
-    fi
-}
-
-
-# func_extract_archives gentop oldlib ...
-func_extract_archives ()
-{
-    $debug_cmd
-
-    my_gentop=$1; shift
-    my_oldlibs=${1+"$@"}
-    my_oldobjs=
-    my_xlib=
-    my_xabs=
-    my_xdir=
-
-    for my_xlib in $my_oldlibs; do
-      # Extract the objects.
-      case $my_xlib in
-       [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
-       *) my_xabs=`pwd`"/$my_xlib" ;;
-      esac
-      func_basename "$my_xlib"
-      my_xlib=$func_basename_result
-      my_xlib_u=$my_xlib
-      while :; do
-        case " $extracted_archives " in
-       *" $my_xlib_u "*)
-         func_arith $extracted_serial + 1
-         extracted_serial=$func_arith_result
-         my_xlib_u=lt$extracted_serial-$my_xlib ;;
-       *) break ;;
-       esac
-      done
-      extracted_archives="$extracted_archives $my_xlib_u"
-      my_xdir=$my_gentop/$my_xlib_u
-
-      func_mkdir_p "$my_xdir"
-
-      case $host in
-      *-darwin*)
-       func_verbose "Extracting $my_xabs"
-       # Do not bother doing anything if just a dry run
-       $opt_dry_run || {
-         darwin_orig_dir=`pwd`
-         cd $my_xdir || exit $?
-         darwin_archive=$my_xabs
-         darwin_curdir=`pwd`
-         func_basename "$darwin_archive"
-         darwin_base_archive=$func_basename_result
-         darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
-         if test -n "$darwin_arches"; then
-           darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
-           darwin_arch=
-           func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
-           for darwin_arch in  $darwin_arches; do
-             func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
-             $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
-             cd "unfat-$$/$darwin_base_archive-$darwin_arch"
-             func_extract_an_archive "`pwd`" "$darwin_base_archive"
-             cd "$darwin_curdir"
-             $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
-           done # $darwin_arches
-            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
-           darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
-           darwin_file=
-           darwin_files=
-           for darwin_file in $darwin_filelist; do
-             darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
-             $LIPO -create -output "$darwin_file" $darwin_files
-           done # $darwin_filelist
-           $RM -rf unfat-$$
-           cd "$darwin_orig_dir"
-         else
-           cd $darwin_orig_dir
-           func_extract_an_archive "$my_xdir" "$my_xabs"
-         fi # $darwin_arches
-       } # !$opt_dry_run
-       ;;
-      *)
-        func_extract_an_archive "$my_xdir" "$my_xabs"
-       ;;
-      esac
-      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
-    done
-
-    func_extract_archives_result=$my_oldobjs
-}
-
-
-# func_emit_wrapper [arg=no]
-#
-# Emit a libtool wrapper script on stdout.
-# Don't directly open a file because we may want to
-# incorporate the script contents within a cygwin/mingw
-# wrapper executable.  Must ONLY be called from within
-# func_mode_link because it depends on a number of variables
-# set therein.
-#
-# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
-# variable will take.  If 'yes', then the emitted script
-# will assume that the directory where it is stored is
-# the $objdir directory.  This is a cygwin/mingw-specific
-# behavior.
-func_emit_wrapper ()
-{
-       func_emit_wrapper_arg1=${1-no}
-
-       $ECHO "\
-#! $SHELL
-
-# $output - temporary wrapper script for $objdir/$outputname
-# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
-#
-# The $output program cannot be directly executed until all the libtool
-# libraries that it depends on are installed.
-#
-# This wrapper script should never be moved out of the build directory.
-# If it is, it will not operate correctly.
-
-# Sed substitution that helps us do robust quoting.  It backslashifies
-# metacharacters that are still active within double-quoted strings.
-sed_quote_subst='$sed_quote_subst'
-
-# Be Bourne compatible
-if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
-  emulate sh
-  NULLCMD=:
-  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '\${1+\"\$@\"}'='\"\$@\"'
-  setopt NO_GLOB_SUBST
-else
-  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
-fi
-BIN_SH=xpg4; export BIN_SH # for Tru64
-DUALCASE=1; export DUALCASE # for MKS sh
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-relink_command=\"$relink_command\"
-
-# This environment variable determines our operation mode.
-if test \"\$libtool_install_magic\" = \"$magic\"; then
-  # install mode needs the following variables:
-  generated_by_libtool_version='$macro_version'
-  notinst_deplibs='$notinst_deplibs'
-else
-  # When we are sourced in execute mode, \$file and \$ECHO are already set.
-  if test \"\$libtool_execute_magic\" != \"$magic\"; then
-    file=\"\$0\""
-
-    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
-    $ECHO "\
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
-  eval 'cat <<_LTECHO_EOF
-\$1
-_LTECHO_EOF'
-}
-    ECHO=\"$qECHO\"
-  fi
-
-# Very basic option parsing. These options are (a) specific to
-# the libtool wrapper, (b) are identical between the wrapper
-# /script/ and the wrapper /executable/ that is used only on
-# windows platforms, and (c) all begin with the string "--lt-"
-# (application programs are unlikely to have options that match
-# this pattern).
-#
-# There are only two supported options: --lt-debug and
-# --lt-dump-script. There is, deliberately, no --lt-help.
-#
-# The first argument to this parsing function should be the
-# script's $0 value, followed by "$@".
-lt_option_debug=
-func_parse_lt_options ()
-{
-  lt_script_arg0=\$0
-  shift
-  for lt_opt
-  do
-    case \"\$lt_opt\" in
-    --lt-debug) lt_option_debug=1 ;;
-    --lt-dump-script)
-        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
-        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
-        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
-        cat \"\$lt_dump_D/\$lt_dump_F\"
-        exit 0
-      ;;
-    --lt-*)
-        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
-        exit 1
-      ;;
-    esac
-  done
-
-  # Print the debug banner immediately:
-  if test -n \"\$lt_option_debug\"; then
-    echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
-  fi
-}
-
-# Used when --lt-debug. Prints its arguments to stdout
-# (redirection is the responsibility of the caller)
-func_lt_dump_args ()
-{
-  lt_dump_args_N=1;
-  for lt_arg
-  do
-    \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
-    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
-  done
-}
-
-# Core function for launching the target application
-func_exec_program_core ()
-{
-"
-  case $host in
-  # Backslashes separate directories on plain windows
-  *-*-mingw | *-*-os2* | *-cegcc*)
-    $ECHO "\
-      if test -n \"\$lt_option_debug\"; then
-        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
-        func_lt_dump_args \${1+\"\$@\"} 1>&2
-      fi
-      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
-"
-    ;;
-
-  *)
-    $ECHO "\
-      if test -n \"\$lt_option_debug\"; then
-        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
-        func_lt_dump_args \${1+\"\$@\"} 1>&2
-      fi
-      exec \"\$progdir/\$program\" \${1+\"\$@\"}
-"
-    ;;
-  esac
-  $ECHO "\
-      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
-      exit 1
-}
-
-# A function to encapsulate launching the target application
-# Strips options in the --lt-* namespace from \$@ and
-# launches target application with the remaining arguments.
-func_exec_program ()
-{
-  case \" \$* \" in
-  *\\ --lt-*)
-    for lt_wr_arg
-    do
-      case \$lt_wr_arg in
-      --lt-*) ;;
-      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
-      esac
-      shift
-    done ;;
-  esac
-  func_exec_program_core \${1+\"\$@\"}
-}
-
-  # Parse options
-  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
-
-  # Find the directory that this script lives in.
-  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
-  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
-
-  # Follow symbolic links until we get to the real thisdir.
-  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
-  while test -n \"\$file\"; do
-    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
-
-    # If there was a directory component, then change thisdir.
-    if test \"x\$destdir\" != \"x\$file\"; then
-      case \"\$destdir\" in
-      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
-      *) thisdir=\"\$thisdir/\$destdir\" ;;
-      esac
-    fi
-
-    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
-    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
-  done
-
-  # Usually 'no', except on cygwin/mingw when embedded into
-  # the cwrapper.
-  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
-  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
-    # special case for '.'
-    if test \"\$thisdir\" = \".\"; then
-      thisdir=\`pwd\`
-    fi
-    # remove .libs from thisdir
-    case \"\$thisdir\" in
-    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
-    $objdir )   thisdir=. ;;
-    esac
-  fi
-
-  # Try to get the absolute directory name.
-  absdir=\`cd \"\$thisdir\" && pwd\`
-  test -n \"\$absdir\" && thisdir=\"\$absdir\"
-"
-
-       if test yes = "$fast_install"; then
-         $ECHO "\
-  program=lt-'$outputname'$exeext
-  progdir=\"\$thisdir/$objdir\"
-
-  if test ! -f \"\$progdir/\$program\" ||
-     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
-       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
-
-    file=\"\$\$-\$program\"
-
-    if test ! -d \"\$progdir\"; then
-      $MKDIR \"\$progdir\"
-    else
-      $RM \"\$progdir/\$file\"
-    fi"
-
-         $ECHO "\
-
-    # relink executable if necessary
-    if test -n \"\$relink_command\"; then
-      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
-      else
-       \$ECHO \"\$relink_command_output\" >&2
-       $RM \"\$progdir/\$file\"
-       exit 1
-      fi
-    fi
-
-    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
-    { $RM \"\$progdir/\$program\";
-      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
-    $RM \"\$progdir/\$file\"
-  fi"
-       else
-         $ECHO "\
-  program='$outputname'
-  progdir=\"\$thisdir/$objdir\"
-"
-       fi
-
-       $ECHO "\
-
-  if test -f \"\$progdir/\$program\"; then"
-
-       # fixup the dll searchpath if we need to.
-       #
-       # Fix the DLL searchpath if we need to.  Do this before prepending
-       # to shlibpath, because on Windows, both are PATH and uninstalled
-       # libraries must come first.
-       if test -n "$dllsearchpath"; then
-         $ECHO "\
-    # Add the dll search path components to the executable PATH
-    PATH=$dllsearchpath:\$PATH
-"
-       fi
-
-       # Export our shlibpath_var if we have one.
-       if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
-         $ECHO "\
-    # Add our own library path to $shlibpath_var
-    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
-
-    # Some systems cannot cope with colon-terminated $shlibpath_var
-    # The second colon is a workaround for a bug in BeOS R4 sed
-    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
-
-    export $shlibpath_var
-"
-       fi
-
-       $ECHO "\
-    if test \"\$libtool_execute_magic\" != \"$magic\"; then
-      # Run the actual program with our arguments.
-      func_exec_program \${1+\"\$@\"}
-    fi
-  else
-    # The program doesn't exist.
-    \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
-    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
-    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
-    exit 1
-  fi
-fi\
-"
-}
-
-
-# func_emit_cwrapperexe_src
-# emit the source code for a wrapper executable on stdout
-# Must ONLY be called from within func_mode_link because
-# it depends on a number of variable set therein.
-func_emit_cwrapperexe_src ()
-{
-       cat <<EOF
-
-/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
-   Generated by $PROGRAM (GNU $PACKAGE) $VERSION
-
-   The $output program cannot be directly executed until all the libtool
-   libraries that it depends on are installed.
-
-   This wrapper executable should never be moved out of the build directory.
-   If it is, it will not operate correctly.
-*/
-EOF
-           cat <<"EOF"
-#ifdef _MSC_VER
-# define _CRT_SECURE_NO_DEPRECATE 1
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef _MSC_VER
-# include <direct.h>
-# include <process.h>
-# include <io.h>
-#else
-# include <unistd.h>
-# include <stdint.h>
-# ifdef __CYGWIN__
-#  include <io.h>
-# endif
-#endif
-#include <malloc.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
-
-/* declarations of non-ANSI functions */
-#if defined __MINGW32__
-# ifdef __STRICT_ANSI__
-int _putenv (const char *);
-# endif
-#elif defined __CYGWIN__
-# ifdef __STRICT_ANSI__
-char *realpath (const char *, char *);
-int putenv (char *);
-int setenv (const char *, const char *, int);
-# endif
-/* #elif defined other_platform || defined ... */
-#endif
-
-/* portability defines, excluding path handling macros */
-#if defined _MSC_VER
-# define setmode _setmode
-# define stat    _stat
-# define chmod   _chmod
-# define getcwd  _getcwd
-# define putenv  _putenv
-# define S_IXUSR _S_IEXEC
-#elif defined __MINGW32__
-# define setmode _setmode
-# define stat    _stat
-# define chmod   _chmod
-# define getcwd  _getcwd
-# define putenv  _putenv
-#elif defined __CYGWIN__
-# define HAVE_SETENV
-# define FOPEN_WB "wb"
-/* #elif defined other platforms ... */
-#endif
-
-#if defined PATH_MAX
-# define LT_PATHMAX PATH_MAX
-#elif defined MAXPATHLEN
-# define LT_PATHMAX MAXPATHLEN
-#else
-# define LT_PATHMAX 1024
-#endif
-
-#ifndef S_IXOTH
-# define S_IXOTH 0
-#endif
-#ifndef S_IXGRP
-# define S_IXGRP 0
-#endif
-
-/* path handling portability macros */
-#ifndef DIR_SEPARATOR
-# define DIR_SEPARATOR '/'
-# define PATH_SEPARATOR ':'
-#endif
-
-#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
-  defined __OS2__
-# define HAVE_DOS_BASED_FILE_SYSTEM
-# define FOPEN_WB "wb"
-# ifndef DIR_SEPARATOR_2
-#  define DIR_SEPARATOR_2 '\\'
-# endif
-# ifndef PATH_SEPARATOR_2
-#  define PATH_SEPARATOR_2 ';'
-# endif
-#endif
-
-#ifndef DIR_SEPARATOR_2
-# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
-#else /* DIR_SEPARATOR_2 */
-# define IS_DIR_SEPARATOR(ch) \
-       (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
-#endif /* DIR_SEPARATOR_2 */
-
-#ifndef PATH_SEPARATOR_2
-# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
-#else /* PATH_SEPARATOR_2 */
-# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
-#endif /* PATH_SEPARATOR_2 */
-
-#ifndef FOPEN_WB
-# define FOPEN_WB "w"
-#endif
-#ifndef _O_BINARY
-# define _O_BINARY 0
-#endif
-
-#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
-#define XFREE(stale) do { \
-  if (stale) { free (stale); stale = 0; } \
-} while (0)
-
-#if defined LT_DEBUGWRAPPER
-static int lt_debug = 1;
-#else
-static int lt_debug = 0;
-#endif
-
-const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
-
-void *xmalloc (size_t num);
-char *xstrdup (const char *string);
-const char *base_name (const char *name);
-char *find_executable (const char *wrapper);
-char *chase_symlinks (const char *pathspec);
-int make_executable (const char *path);
-int check_executable (const char *path);
-char *strendzap (char *str, const char *pat);
-void lt_debugprintf (const char *file, int line, const char *fmt, ...);
-void lt_fatal (const char *file, int line, const char *message, ...);
-static const char *nonnull (const char *s);
-static const char *nonempty (const char *s);
-void lt_setenv (const char *name, const char *value);
-char *lt_extend_str (const char *orig_value, const char *add, int to_end);
-void lt_update_exe_path (const char *name, const char *value);
-void lt_update_lib_path (const char *name, const char *value);
-char **prepare_spawn (char **argv);
-void lt_dump_script (FILE *f);
-EOF
-
-           cat <<EOF
-#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
-# define externally_visible volatile
-#else
-# define externally_visible __attribute__((externally_visible)) volatile
-#endif
-externally_visible const char * MAGIC_EXE = "$magic_exe";
-const char * LIB_PATH_VARNAME = "$shlibpath_var";
-EOF
-
-           if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
-              func_to_host_path "$temp_rpath"
-             cat <<EOF
-const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
-EOF
-           else
-             cat <<"EOF"
-const char * LIB_PATH_VALUE   = "";
-EOF
-           fi
-
-           if test -n "$dllsearchpath"; then
-              func_to_host_path "$dllsearchpath:"
-             cat <<EOF
-const char * EXE_PATH_VARNAME = "PATH";
-const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
-EOF
-           else
-             cat <<"EOF"
-const char * EXE_PATH_VARNAME = "";
-const char * EXE_PATH_VALUE   = "";
-EOF
-           fi
-
-           if test yes = "$fast_install"; then
-             cat <<EOF
-const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
-EOF
-           else
-             cat <<EOF
-const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
-EOF
-           fi
-
-
-           cat <<"EOF"
-
-#define LTWRAPPER_OPTION_PREFIX         "--lt-"
-
-static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
-static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
-static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
-
-int
-main (int argc, char *argv[])
-{
-  char **newargz;
-  int  newargc;
-  char *tmp_pathspec;
-  char *actual_cwrapper_path;
-  char *actual_cwrapper_name;
-  char *target_name;
-  char *lt_argv_zero;
-  int rval = 127;
-
-  int i;
-
-  program_name = (char *) xstrdup (base_name (argv[0]));
-  newargz = XMALLOC (char *, (size_t) argc + 1);
-
-  /* very simple arg parsing; don't want to rely on getopt
-   * also, copy all non cwrapper options to newargz, except
-   * argz[0], which is handled differently
-   */
-  newargc=0;
-  for (i = 1; i < argc; i++)
-    {
-      if (STREQ (argv[i], dumpscript_opt))
-       {
-EOF
-           case $host in
-             *mingw* | *cygwin* )
-               # make stdout use "unix" line endings
-               echo "          setmode(1,_O_BINARY);"
-               ;;
-             esac
-
-           cat <<"EOF"
-         lt_dump_script (stdout);
-         return 0;
-       }
-      if (STREQ (argv[i], debug_opt))
-       {
-          lt_debug = 1;
-          continue;
-       }
-      if (STREQ (argv[i], ltwrapper_option_prefix))
-        {
-          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
-             namespace, but it is not one of the ones we know about and
-             have already dealt with, above (inluding dump-script), then
-             report an error. Otherwise, targets might begin to believe
-             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
-             namespace. The first time any user complains about this, we'll
-             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
-             or a configure.ac-settable value.
-           */
-          lt_fatal (__FILE__, __LINE__,
-                   "unrecognized %s option: '%s'",
-                    ltwrapper_option_prefix, argv[i]);
-        }
-      /* otherwise ... */
-      newargz[++newargc] = xstrdup (argv[i]);
-    }
-  newargz[++newargc] = NULL;
-
-EOF
-           cat <<EOF
-  /* The GNU banner must be the first non-error debug message */
-  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
-EOF
-           cat <<"EOF"
-  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
-  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
-
-  tmp_pathspec = find_executable (argv[0]);
-  if (tmp_pathspec == NULL)
-    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
-  lt_debugprintf (__FILE__, __LINE__,
-                  "(main) found exe (before symlink chase) at: %s\n",
-                 tmp_pathspec);
-
-  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
-  lt_debugprintf (__FILE__, __LINE__,
-                  "(main) found exe (after symlink chase) at: %s\n",
-                 actual_cwrapper_path);
-  XFREE (tmp_pathspec);
-
-  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
-  strendzap (actual_cwrapper_path, actual_cwrapper_name);
-
-  /* wrapper name transforms */
-  strendzap (actual_cwrapper_name, ".exe");
-  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
-  XFREE (actual_cwrapper_name);
-  actual_cwrapper_name = tmp_pathspec;
-  tmp_pathspec = 0;
-
-  /* target_name transforms -- use actual target program name; might have lt- prefix */
-  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
-  strendzap (target_name, ".exe");
-  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
-  XFREE (target_name);
-  target_name = tmp_pathspec;
-  tmp_pathspec = 0;
-
-  lt_debugprintf (__FILE__, __LINE__,
-                 "(main) libtool target name: %s\n",
-                 target_name);
-EOF
-
-           cat <<EOF
-  newargz[0] =
-    XMALLOC (char, (strlen (actual_cwrapper_path) +
-                   strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
-  strcpy (newargz[0], actual_cwrapper_path);
-  strcat (newargz[0], "$objdir");
-  strcat (newargz[0], "/");
-EOF
-
-           cat <<"EOF"
-  /* stop here, and copy so we don't have to do this twice */
-  tmp_pathspec = xstrdup (newargz[0]);
-
-  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
-  strcat (newargz[0], actual_cwrapper_name);
-
-  /* DO want the lt- prefix here if it exists, so use target_name */
-  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
-  XFREE (tmp_pathspec);
-  tmp_pathspec = NULL;
-EOF
-
-           case $host_os in
-             mingw*)
-           cat <<"EOF"
-  {
-    char* p;
-    while ((p = strchr (newargz[0], '\\')) != NULL)
-      {
-       *p = '/';
-      }
-    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
-      {
-       *p = '/';
-      }
-  }
-EOF
-           ;;
-           esac
-
-           cat <<"EOF"
-  XFREE (target_name);
-  XFREE (actual_cwrapper_path);
-  XFREE (actual_cwrapper_name);
-
-  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
-  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
-  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
-     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
-     because on Windows, both *_VARNAMEs are PATH but uninstalled
-     libraries must come first. */
-  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
-  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
-
-  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
-                 nonnull (lt_argv_zero));
-  for (i = 0; i < newargc; i++)
-    {
-      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
-                     i, nonnull (newargz[i]));
-    }
-
-EOF
-
-           case $host_os in
-             mingw*)
-               cat <<"EOF"
-  /* execv doesn't actually work on mingw as expected on unix */
-  newargz = prepare_spawn (newargz);
-  rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
-  if (rval == -1)
-    {
-      /* failed to start process */
-      lt_debugprintf (__FILE__, __LINE__,
-                     "(main) failed to launch target \"%s\": %s\n",
-                     lt_argv_zero, nonnull (strerror (errno)));
-      return 127;
-    }
-  return rval;
-EOF
-               ;;
-             *)
-               cat <<"EOF"
-  execv (lt_argv_zero, newargz);
-  return rval; /* =127, but avoids unused variable warning */
-EOF
-               ;;
-           esac
-
-           cat <<"EOF"
-}
-
-void *
-xmalloc (size_t num)
-{
-  void *p = (void *) malloc (num);
-  if (!p)
-    lt_fatal (__FILE__, __LINE__, "memory exhausted");
-
-  return p;
-}
-
-char *
-xstrdup (const char *string)
-{
-  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
-                         string) : NULL;
-}
-
-const char *
-base_name (const char *name)
-{
-  const char *base;
-
-#if defined HAVE_DOS_BASED_FILE_SYSTEM
-  /* Skip over the disk name in MSDOS pathnames. */
-  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
-    name += 2;
-#endif
-
-  for (base = name; *name; name++)
-    if (IS_DIR_SEPARATOR (*name))
-      base = name + 1;
-  return base;
-}
-
-int
-check_executable (const char *path)
-{
-  struct stat st;
-
-  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
-                  nonempty (path));
-  if ((!path) || (!*path))
-    return 0;
-
-  if ((stat (path, &st) >= 0)
-      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
-    return 1;
-  else
-    return 0;
-}
-
-int
-make_executable (const char *path)
-{
-  int rval = 0;
-  struct stat st;
-
-  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
-                  nonempty (path));
-  if ((!path) || (!*path))
-    return 0;
-
-  if (stat (path, &st) >= 0)
-    {
-      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
-    }
-  return rval;
-}
-
-/* Searches for the full path of the wrapper.  Returns
-   newly allocated full path name if found, NULL otherwise
-   Does not chase symlinks, even on platforms that support them.
-*/
-char *
-find_executable (const char *wrapper)
-{
-  int has_slash = 0;
-  const char *p;
-  const char *p_next;
-  /* static buffer for getcwd */
-  char tmp[LT_PATHMAX + 1];
-  size_t tmp_len;
-  char *concat_name;
-
-  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
-                  nonempty (wrapper));
-
-  if ((wrapper == NULL) || (*wrapper == '\0'))
-    return NULL;
-
-  /* Absolute path? */
-#if defined HAVE_DOS_BASED_FILE_SYSTEM
-  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
-    {
-      concat_name = xstrdup (wrapper);
-      if (check_executable (concat_name))
-       return concat_name;
-      XFREE (concat_name);
-    }
-  else
-    {
-#endif
-      if (IS_DIR_SEPARATOR (wrapper[0]))
-       {
-         concat_name = xstrdup (wrapper);
-         if (check_executable (concat_name))
-           return concat_name;
-         XFREE (concat_name);
-       }
-#if defined HAVE_DOS_BASED_FILE_SYSTEM
-    }
-#endif
-
-  for (p = wrapper; *p; p++)
-    if (*p == '/')
-      {
-       has_slash = 1;
-       break;
-      }
-  if (!has_slash)
-    {
-      /* no slashes; search PATH */
-      const char *path = getenv ("PATH");
-      if (path != NULL)
-       {
-         for (p = path; *p; p = p_next)
-           {
-             const char *q;
-             size_t p_len;
-             for (q = p; *q; q++)
-               if (IS_PATH_SEPARATOR (*q))
-                 break;
-             p_len = (size_t) (q - p);
-             p_next = (*q == '\0' ? q : q + 1);
-             if (p_len == 0)
-               {
-                 /* empty path: current directory */
-                 if (getcwd (tmp, LT_PATHMAX) == NULL)
-                   lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
-                              nonnull (strerror (errno)));
-                 tmp_len = strlen (tmp);
-                 concat_name =
-                   XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
-                 memcpy (concat_name, tmp, tmp_len);
-                 concat_name[tmp_len] = '/';
-                 strcpy (concat_name + tmp_len + 1, wrapper);
-               }
-             else
-               {
-                 concat_name =
-                   XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
-                 memcpy (concat_name, p, p_len);
-                 concat_name[p_len] = '/';
-                 strcpy (concat_name + p_len + 1, wrapper);
-               }
-             if (check_executable (concat_name))
-               return concat_name;
-             XFREE (concat_name);
-           }
-       }
-      /* not found in PATH; assume curdir */
-    }
-  /* Relative path | not found in path: prepend cwd */
-  if (getcwd (tmp, LT_PATHMAX) == NULL)
-    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
-              nonnull (strerror (errno)));
-  tmp_len = strlen (tmp);
-  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
-  memcpy (concat_name, tmp, tmp_len);
-  concat_name[tmp_len] = '/';
-  strcpy (concat_name + tmp_len + 1, wrapper);
-
-  if (check_executable (concat_name))
-    return concat_name;
-  XFREE (concat_name);
-  return NULL;
-}
-
-char *
-chase_symlinks (const char *pathspec)
-{
-#ifndef S_ISLNK
-  return xstrdup (pathspec);
-#else
-  char buf[LT_PATHMAX];
-  struct stat s;
-  char *tmp_pathspec = xstrdup (pathspec);
-  char *p;
-  int has_symlinks = 0;
-  while (strlen (tmp_pathspec) && !has_symlinks)
-    {
-      lt_debugprintf (__FILE__, __LINE__,
-                     "checking path component for symlinks: %s\n",
-                     tmp_pathspec);
-      if (lstat (tmp_pathspec, &s) == 0)
-       {
-         if (S_ISLNK (s.st_mode) != 0)
-           {
-             has_symlinks = 1;
-             break;
-           }
-
-         /* search backwards for last DIR_SEPARATOR */
-         p = tmp_pathspec + strlen (tmp_pathspec) - 1;
-         while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
-           p--;
-         if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
-           {
-             /* no more DIR_SEPARATORS left */
-             break;
-           }
-         *p = '\0';
-       }
-      else
-       {
-         lt_fatal (__FILE__, __LINE__,
-                   "error accessing file \"%s\": %s",
-                   tmp_pathspec, nonnull (strerror (errno)));
-       }
-    }
-  XFREE (tmp_pathspec);
-
-  if (!has_symlinks)
-    {
-      return xstrdup (pathspec);
-    }
-
-  tmp_pathspec = realpath (pathspec, buf);
-  if (tmp_pathspec == 0)
-    {
-      lt_fatal (__FILE__, __LINE__,
-               "could not follow symlinks for %s", pathspec);
-    }
-  return xstrdup (tmp_pathspec);
-#endif
-}
-
-char *
-strendzap (char *str, const char *pat)
-{
-  size_t len, patlen;
-
-  assert (str != NULL);
-  assert (pat != NULL);
-
-  len = strlen (str);
-  patlen = strlen (pat);
-
-  if (patlen <= len)
-    {
-      str += len - patlen;
-      if (STREQ (str, pat))
-       *str = '\0';
-    }
-  return str;
-}
-
-void
-lt_debugprintf (const char *file, int line, const char *fmt, ...)
-{
-  va_list args;
-  if (lt_debug)
-    {
-      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
-      va_start (args, fmt);
-      (void) vfprintf (stderr, fmt, args);
-      va_end (args);
-    }
-}
-
-static void
-lt_error_core (int exit_status, const char *file,
-              int line, const char *mode,
-              const char *message, va_list ap)
-{
-  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
-  vfprintf (stderr, message, ap);
-  fprintf (stderr, ".\n");
-
-  if (exit_status >= 0)
-    exit (exit_status);
-}
-
-void
-lt_fatal (const char *file, int line, const char *message, ...)
-{
-  va_list ap;
-  va_start (ap, message);
-  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
-  va_end (ap);
-}
-
-static const char *
-nonnull (const char *s)
-{
-  return s ? s : "(null)";
-}
-
-static const char *
-nonempty (const char *s)
-{
-  return (s && !*s) ? "(empty)" : nonnull (s);
-}
-
-void
-lt_setenv (const char *name, const char *value)
-{
-  lt_debugprintf (__FILE__, __LINE__,
-                 "(lt_setenv) setting '%s' to '%s'\n",
-                  nonnull (name), nonnull (value));
-  {
-#ifdef HAVE_SETENV
-    /* always make a copy, for consistency with !HAVE_SETENV */
-    char *str = xstrdup (value);
-    setenv (name, str, 1);
-#else
-    size_t len = strlen (name) + 1 + strlen (value) + 1;
-    char *str = XMALLOC (char, len);
-    sprintf (str, "%s=%s", name, value);
-    if (putenv (str) != EXIT_SUCCESS)
-      {
-        XFREE (str);
-      }
-#endif
-  }
-}
-
-char *
-lt_extend_str (const char *orig_value, const char *add, int to_end)
-{
-  char *new_value;
-  if (orig_value && *orig_value)
-    {
-      size_t orig_value_len = strlen (orig_value);
-      size_t add_len = strlen (add);
-      new_value = XMALLOC (char, add_len + orig_value_len + 1);
-      if (to_end)
-        {
-          strcpy (new_value, orig_value);
-          strcpy (new_value + orig_value_len, add);
-        }
-      else
-        {
-          strcpy (new_value, add);
-          strcpy (new_value + add_len, orig_value);
-        }
-    }
-  else
-    {
-      new_value = xstrdup (add);
-    }
-  return new_value;
-}
-
-void
-lt_update_exe_path (const char *name, const char *value)
-{
-  lt_debugprintf (__FILE__, __LINE__,
-                 "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
-                  nonnull (name), nonnull (value));
-
-  if (name && *name && value && *value)
-    {
-      char *new_value = lt_extend_str (getenv (name), value, 0);
-      /* some systems can't cope with a ':'-terminated path #' */
-      size_t len = strlen (new_value);
-      while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
-        {
-          new_value[--len] = '\0';
-        }
-      lt_setenv (name, new_value);
-      XFREE (new_value);
-    }
-}
-
-void
-lt_update_lib_path (const char *name, const char *value)
-{
-  lt_debugprintf (__FILE__, __LINE__,
-                 "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
-                  nonnull (name), nonnull (value));
-
-  if (name && *name && value && *value)
-    {
-      char *new_value = lt_extend_str (getenv (name), value, 0);
-      lt_setenv (name, new_value);
-      XFREE (new_value);
-    }
-}
-
-EOF
-           case $host_os in
-             mingw*)
-               cat <<"EOF"
-
-/* Prepares an argument vector before calling spawn().
-   Note that spawn() does not by itself call the command interpreter
-     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
-      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-         GetVersionEx(&v);
-         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
-      }) ? "cmd.exe" : "command.com").
-   Instead it simply concatenates the arguments, separated by ' ', and calls
-   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
-   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
-   special way:
-   - Space and tab are interpreted as delimiters. They are not treated as
-     delimiters if they are surrounded by double quotes: "...".
-   - Unescaped double quotes are removed from the input. Their only effect is
-     that within double quotes, space and tab are treated like normal
-     characters.
-   - Backslashes not followed by double quotes are not special.
-   - But 2*n+1 backslashes followed by a double quote become
-     n backslashes followed by a double quote (n >= 0):
-       \" -> "
-       \\\" -> \"
-       \\\\\" -> \\"
- */
-#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
-#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
-char **
-prepare_spawn (char **argv)
-{
-  size_t argc;
-  char **new_argv;
-  size_t i;
-
-  /* Count number of arguments.  */
-  for (argc = 0; argv[argc] != NULL; argc++)
-    ;
-
-  /* Allocate new argument vector.  */
-  new_argv = XMALLOC (char *, argc + 1);
-
-  /* Put quoted arguments into the new argument vector.  */
-  for (i = 0; i < argc; i++)
-    {
-      const char *string = argv[i];
-
-      if (string[0] == '\0')
-       new_argv[i] = xstrdup ("\"\"");
-      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
-       {
-         int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
-         size_t length;
-         unsigned int backslashes;
-         const char *s;
-         char *quoted_string;
-         char *p;
-
-         length = 0;
-         backslashes = 0;
-         if (quote_around)
-           length++;
-         for (s = string; *s != '\0'; s++)
-           {
-             char c = *s;
-             if (c == '"')
-               length += backslashes + 1;
-             length++;
-             if (c == '\\')
-               backslashes++;
-             else
-               backslashes = 0;
-           }
-         if (quote_around)
-           length += backslashes + 1;
-
-         quoted_string = XMALLOC (char, length + 1);
-
-         p = quoted_string;
-         backslashes = 0;
-         if (quote_around)
-           *p++ = '"';
-         for (s = string; *s != '\0'; s++)
-           {
-             char c = *s;
-             if (c == '"')
-               {
-                 unsigned int j;
-                 for (j = backslashes + 1; j > 0; j--)
-                   *p++ = '\\';
-               }
-             *p++ = c;
-             if (c == '\\')
-               backslashes++;
-             else
-               backslashes = 0;
-           }
-         if (quote_around)
-           {
-             unsigned int j;
-             for (j = backslashes; j > 0; j--)
-               *p++ = '\\';
-             *p++ = '"';
-           }
-         *p = '\0';
-
-         new_argv[i] = quoted_string;
-       }
-      else
-       new_argv[i] = (char *) string;
-    }
-  new_argv[argc] = NULL;
-
-  return new_argv;
-}
-EOF
-               ;;
-           esac
-
-            cat <<"EOF"
-void lt_dump_script (FILE* f)
-{
-EOF
-           func_emit_wrapper yes |
-             $SED -n -e '
-s/^\(.\{79\}\)\(..*\)/\1\
-\2/
-h
-s/\([\\"]\)/\\\1/g
-s/$/\\n/
-s/\([^\n]*\).*/  fputs ("\1", f);/p
-g
-D'
-            cat <<"EOF"
-}
-EOF
-}
-# end: func_emit_cwrapperexe_src
-
-# func_win32_import_lib_p ARG
-# True if ARG is an import lib, as indicated by $file_magic_cmd
-func_win32_import_lib_p ()
-{
-    $debug_cmd
-
-    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
-    *import*) : ;;
-    *) false ;;
-    esac
-}
-
-# func_suncc_cstd_abi
-# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
-# Several compiler flags select an ABI that is incompatible with the
-# Cstd library. Avoid specifying it if any are in CXXFLAGS.
-func_suncc_cstd_abi ()
-{
-    $debug_cmd
-
-    case " $compile_command " in
-    *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
-      suncc_use_cstd_abi=no
-      ;;
-    *)
-      suncc_use_cstd_abi=yes
-      ;;
-    esac
-}
-
-# func_mode_link arg...
-func_mode_link ()
-{
-    $debug_cmd
-
-    case $host in
-    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
-      # It is impossible to link a dll without this setting, and
-      # we shouldn't force the makefile maintainer to figure out
-      # what system we are compiling for in order to pass an extra
-      # flag for every libtool invocation.
-      # allow_undefined=no
-
-      # FIXME: Unfortunately, there are problems with the above when trying
-      # to make a dll that has undefined symbols, in which case not
-      # even a static library is built.  For now, we need to specify
-      # -no-undefined on the libtool link line when we can be certain
-      # that all symbols are satisfied, otherwise we get a static library.
-      allow_undefined=yes
-      ;;
-    *)
-      allow_undefined=yes
-      ;;
-    esac
-    libtool_args=$nonopt
-    base_compile="$nonopt $@"
-    compile_command=$nonopt
-    finalize_command=$nonopt
-
-    compile_rpath=
-    finalize_rpath=
-    compile_shlibpath=
-    finalize_shlibpath=
-    convenience=
-    old_convenience=
-    deplibs=
-    old_deplibs=
-    compiler_flags=
-    linker_flags=
-    dllsearchpath=
-    lib_search_path=`pwd`
-    inst_prefix_dir=
-    new_inherited_linker_flags=
-
-    avoid_version=no
-    bindir=
-    dlfiles=
-    dlprefiles=
-    dlself=no
-    export_dynamic=no
-    export_symbols=
-    export_symbols_regex=
-    generated=
-    libobjs=
-    ltlibs=
-    module=no
-    no_install=no
-    objs=
-    os2dllname=
-    non_pic_objects=
-    precious_files_regex=
-    prefer_static_libs=no
-    preload=false
-    prev=
-    prevarg=
-    release=
-    rpath=
-    xrpath=
-    perm_rpath=
-    temp_rpath=
-    thread_safe=no
-    vinfo=
-    vinfo_number=no
-    weak_libs=
-    single_module=$wl-single_module
-    func_infer_tag $base_compile
-
-    # We need to know -static, to get the right output filenames.
-    for arg
-    do
-      case $arg in
-      -shared)
-       test yes != "$build_libtool_libs" \
-         && func_fatal_configuration "cannot build a shared library"
-       build_old_libs=no
-       break
-       ;;
-      -all-static | -static | -static-libtool-libs)
-       case $arg in
-       -all-static)
-         if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
-           func_warning "complete static linking is impossible in this configuration"
-         fi
-         if test -n "$link_static_flag"; then
-           dlopen_self=$dlopen_self_static
-         fi
-         prefer_static_libs=yes
-         ;;
-       -static)
-         if test -z "$pic_flag" && test -n "$link_static_flag"; then
-           dlopen_self=$dlopen_self_static
-         fi
-         prefer_static_libs=built
-         ;;
-       -static-libtool-libs)
-         if test -z "$pic_flag" && test -n "$link_static_flag"; then
-           dlopen_self=$dlopen_self_static
-         fi
-         prefer_static_libs=yes
-         ;;
-       esac
-       build_libtool_libs=no
-       build_old_libs=yes
-       break
-       ;;
-      esac
-    done
-
-    # See if our shared archives depend on static archives.
-    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
-
-    # Go through the arguments, transforming them on the way.
-    while test "$#" -gt 0; do
-      arg=$1
-      shift
-      func_quote_for_eval "$arg"
-      qarg=$func_quote_for_eval_unquoted_result
-      func_append libtool_args " $func_quote_for_eval_result"
-
-      # If the previous option needs an argument, assign it.
-      if test -n "$prev"; then
-       case $prev in
-       output)
-         func_append compile_command " @OUTPUT@"
-         func_append finalize_command " @OUTPUT@"
-         ;;
-       esac
-
-       case $prev in
-       bindir)
-         bindir=$arg
-         prev=
-         continue
-         ;;
-       dlfiles|dlprefiles)
-         $preload || {
-           # Add the symbol object into the linking commands.
-           func_append compile_command " @SYMFILE@"
-           func_append finalize_command " @SYMFILE@"
-           preload=:
-         }
-         case $arg in
-         *.la | *.lo) ;;  # We handle these cases below.
-         force)
-           if test no = "$dlself"; then
-             dlself=needless
-             export_dynamic=yes
-           fi
-           prev=
-           continue
-           ;;
-         self)
-           if test dlprefiles = "$prev"; then
-             dlself=yes
-           elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
-             dlself=yes
-           else
-             dlself=needless
-             export_dynamic=yes
-           fi
-           prev=
-           continue
-           ;;
-         *)
-           if test dlfiles = "$prev"; then
-             func_append dlfiles " $arg"
-           else
-             func_append dlprefiles " $arg"
-           fi
-           prev=
-           continue
-           ;;
-         esac
-         ;;
-       expsyms)
-         export_symbols=$arg
-         test -f "$arg" \
-           || func_fatal_error "symbol file '$arg' does not exist"
-         prev=
-         continue
-         ;;
-       expsyms_regex)
-         export_symbols_regex=$arg
-         prev=
-         continue
-         ;;
-       framework)
-         case $host in
-           *-*-darwin*)
-             case "$deplibs " in
-               *" $qarg.ltframework "*) ;;
-               *) func_append deplibs " $qarg.ltframework" # this is fixed later
-                  ;;
-             esac
-             ;;
-         esac
-         prev=
-         continue
-         ;;
-       inst_prefix)
-         inst_prefix_dir=$arg
-         prev=
-         continue
-         ;;
-       mllvm)
-         # Clang does not use LLVM to link, so we can simply discard any
-         # '-mllvm $arg' options when doing the link step.
-         prev=
-         continue
-         ;;
-       objectlist)
-         if test -f "$arg"; then
-           save_arg=$arg
-           moreargs=
-           for fil in `cat "$save_arg"`
-           do
-#            func_append moreargs " $fil"
-             arg=$fil
-             # A libtool-controlled object.
-
-             # Check to see that this really is a libtool object.
-             if func_lalib_unsafe_p "$arg"; then
-               pic_object=
-               non_pic_object=
-
-               # Read the .lo file
-               func_source "$arg"
-
-               if test -z "$pic_object" ||
-                  test -z "$non_pic_object" ||
-                  test none = "$pic_object" &&
-                  test none = "$non_pic_object"; then
-                 func_fatal_error "cannot find name of object for '$arg'"
-               fi
-
-               # Extract subdirectory from the argument.
-               func_dirname "$arg" "/" ""
-               xdir=$func_dirname_result
-
-               if test none != "$pic_object"; then
-                 # Prepend the subdirectory the object is found in.
-                 pic_object=$xdir$pic_object
-
-                 if test dlfiles = "$prev"; then
-                   if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
-                     func_append dlfiles " $pic_object"
-                     prev=
-                     continue
-                   else
-                     # If libtool objects are unsupported, then we need to preload.
-                     prev=dlprefiles
-                   fi
-                 fi
-
-                 # CHECK ME:  I think I busted this.  -Ossama
-                 if test dlprefiles = "$prev"; then
-                   # Preload the old-style object.
-                   func_append dlprefiles " $pic_object"
-                   prev=
-                 fi
-
-                 # A PIC object.
-                 func_append libobjs " $pic_object"
-                 arg=$pic_object
-               fi
-
-               # Non-PIC object.
-               if test none != "$non_pic_object"; then
-                 # Prepend the subdirectory the object is found in.
-                 non_pic_object=$xdir$non_pic_object
-
-                 # A standard non-PIC object
-                 func_append non_pic_objects " $non_pic_object"
-                 if test -z "$pic_object" || test none = "$pic_object"; then
-                   arg=$non_pic_object
-                 fi
-               else
-                 # If the PIC object exists, use it instead.
-                 # $xdir was prepended to $pic_object above.
-                 non_pic_object=$pic_object
-                 func_append non_pic_objects " $non_pic_object"
-               fi
-             else
-               # Only an error if not doing a dry-run.
-               if $opt_dry_run; then
-                 # Extract subdirectory from the argument.
-                 func_dirname "$arg" "/" ""
-                 xdir=$func_dirname_result
-
-                 func_lo2o "$arg"
-                 pic_object=$xdir$objdir/$func_lo2o_result
-                 non_pic_object=$xdir$func_lo2o_result
-                 func_append libobjs " $pic_object"
-                 func_append non_pic_objects " $non_pic_object"
-               else
-                 func_fatal_error "'$arg' is not a valid libtool object"
-               fi
-             fi
-           done
-         else
-           func_fatal_error "link input file '$arg' does not exist"
-         fi
-         arg=$save_arg
-         prev=
-         continue
-         ;;
-       os2dllname)
-         os2dllname=$arg
-         prev=
-         continue
-         ;;
-       precious_regex)
-         precious_files_regex=$arg
-         prev=
-         continue
-         ;;
-       release)
-         release=-$arg
-         prev=
-         continue
-         ;;
-       rpath | xrpath)
-         # We need an absolute path.
-         case $arg in
-         [\\/]* | [A-Za-z]:[\\/]*) ;;
-         *)
-           func_fatal_error "only absolute run-paths are allowed"
-           ;;
-         esac
-         if test rpath = "$prev"; then
-           case "$rpath " in
-           *" $arg "*) ;;
-           *) func_append rpath " $arg" ;;
-           esac
-         else
-           case "$xrpath " in
-           *" $arg "*) ;;
-           *) func_append xrpath " $arg" ;;
-           esac
-         fi
-         prev=
-         continue
-         ;;
-       shrext)
-         shrext_cmds=$arg
-         prev=
-         continue
-         ;;
-       weak)
-         func_append weak_libs " $arg"
-         prev=
-         continue
-         ;;
-       xcclinker)
-         func_append linker_flags " $qarg"
-         func_append compiler_flags " $qarg"
-         prev=
-         func_append compile_command " $qarg"
-         func_append finalize_command " $qarg"
-         continue
-         ;;
-       xcompiler)
-         func_append compiler_flags " $qarg"
-         prev=
-         func_append compile_command " $qarg"
-         func_append finalize_command " $qarg"
-         continue
-         ;;
-       xlinker)
-         func_append linker_flags " $qarg"
-         func_append compiler_flags " $wl$qarg"
-         prev=
-         func_append compile_command " $wl$qarg"
-         func_append finalize_command " $wl$qarg"
-         continue
-         ;;
-       *)
-         eval "$prev=\"\$arg\""
-         prev=
-         continue
-         ;;
-       esac
-      fi # test -n "$prev"
-
-      prevarg=$arg
-
-      case $arg in
-      -all-static)
-       if test -n "$link_static_flag"; then
-         # See comment for -static flag below, for more details.
-         func_append compile_command " $link_static_flag"
-         func_append finalize_command " $link_static_flag"
-       fi
-       continue
-       ;;
-
-      -allow-undefined)
-       # FIXME: remove this flag sometime in the future.
-       func_fatal_error "'-allow-undefined' must not be used because it is the default"
-       ;;
-
-      -avoid-version)
-       avoid_version=yes
-       continue
-       ;;
-
-      -bindir)
-       prev=bindir
-       continue
-       ;;
-
-      -dlopen)
-       prev=dlfiles
-       continue
-       ;;
-
-      -dlpreopen)
-       prev=dlprefiles
-       continue
-       ;;
-
-      -export-dynamic)
-       export_dynamic=yes
-       continue
-       ;;
-
-      -export-symbols | -export-symbols-regex)
-       if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
-         func_fatal_error "more than one -exported-symbols argument is not allowed"
-       fi
-       if test X-export-symbols = "X$arg"; then
-         prev=expsyms
-       else
-         prev=expsyms_regex
-       fi
-       continue
-       ;;
-
-      -framework)
-       prev=framework
-       continue
-       ;;
-
-      -inst-prefix-dir)
-       prev=inst_prefix
-       continue
-       ;;
-
-      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
-      # so, if we see these flags be careful not to treat them like -L
-      -L[A-Z][A-Z]*:*)
-       case $with_gcc/$host in
-       no/*-*-irix* | /*-*-irix*)
-         func_append compile_command " $arg"
-         func_append finalize_command " $arg"
-         ;;
-       esac
-       continue
-       ;;
-
-      -L*)
-       func_stripname "-L" '' "$arg"
-       if test -z "$func_stripname_result"; then
-         if test "$#" -gt 0; then
-           func_fatal_error "require no space between '-L' and '$1'"
-         else
-           func_fatal_error "need path for '-L' option"
-         fi
-       fi
-       func_resolve_sysroot "$func_stripname_result"
-       dir=$func_resolve_sysroot_result
-       # We need an absolute path.
-       case $dir in
-       [\\/]* | [A-Za-z]:[\\/]*) ;;
-       *)
-         absdir=`cd "$dir" && pwd`
-         test -z "$absdir" && \
-           func_fatal_error "cannot determine absolute directory name of '$dir'"
-         dir=$absdir
-         ;;
-       esac
-       case "$deplibs " in
-       *" -L$dir "* | *" $arg "*)
-         # Will only happen for absolute or sysroot arguments
-         ;;
-       *)
-         # Preserve sysroot, but never include relative directories
-         case $dir in
-           [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
-           *) func_append deplibs " -L$dir" ;;
-         esac
-         func_append lib_search_path " $dir"
-         ;;
-       esac
-       case $host in
-       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
-         testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
-         case :$dllsearchpath: in
-         *":$dir:"*) ;;
-         ::) dllsearchpath=$dir;;
-         *) func_append dllsearchpath ":$dir";;
-         esac
-         case :$dllsearchpath: in
-         *":$testbindir:"*) ;;
-         ::) dllsearchpath=$testbindir;;
-         *) func_append dllsearchpath ":$testbindir";;
-         esac
-         ;;
-       esac
-       continue
-       ;;
-
-      -l*)
-       if test X-lc = "X$arg" || test X-lm = "X$arg"; then
-         case $host in
-         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
-           # These systems don't actually have a C or math library (as such)
-           continue
-           ;;
-         *-*-os2*)
-           # These systems don't actually have a C library (as such)
-           test X-lc = "X$arg" && continue
-           ;;
-         *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
-           # Do not include libc due to us having libc/libc_r.
-           test X-lc = "X$arg" && continue
-           ;;
-         *-*-rhapsody* | *-*-darwin1.[012])
-           # Rhapsody C and math libraries are in the System framework
-           func_append deplibs " System.ltframework"
-           continue
-           ;;
-         *-*-sco3.2v5* | *-*-sco5v6*)
-           # Causes problems with __ctype
-           test X-lc = "X$arg" && continue
-           ;;
-         *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
-           # Compiler inserts libc in the correct place for threads to work
-           test X-lc = "X$arg" && continue
-           ;;
-         esac
-       elif test X-lc_r = "X$arg"; then
-        case $host in
-        *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
-          # Do not include libc_r directly, use -pthread flag.
-          continue
-          ;;
-        esac
-       fi
-       func_append deplibs " $arg"
-       continue
-       ;;
-
-      -mllvm)
-       prev=mllvm
-       continue
-       ;;
-
-      -module)
-       module=yes
-       continue
-       ;;
-
-      # Tru64 UNIX uses -model [arg] to determine the layout of C++
-      # classes, name mangling, and exception handling.
-      # Darwin uses the -arch flag to determine output architecture.
-      -model|-arch|-isysroot|--sysroot)
-       func_append compiler_flags " $arg"
-       func_append compile_command " $arg"
-       func_append finalize_command " $arg"
-       prev=xcompiler
-       continue
-       ;;
-
-      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
-      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
-       func_append compiler_flags " $arg"
-       func_append compile_command " $arg"
-       func_append finalize_command " $arg"
-       case "$new_inherited_linker_flags " in
-           *" $arg "*) ;;
-           * ) func_append new_inherited_linker_flags " $arg" ;;
-       esac
-       continue
-       ;;
-
-      -multi_module)
-       single_module=$wl-multi_module
-       continue
-       ;;
-
-      -no-fast-install)
-       fast_install=no
-       continue
-       ;;
-
-      -no-install)
-       case $host in
-       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
-         # The PATH hackery in wrapper scripts is required on Windows
-         # and Darwin in order for the loader to find any dlls it needs.
-         func_warning "'-no-install' is ignored for $host"
-         func_warning "assuming '-no-fast-install' instead"
-         fast_install=no
-         ;;
-       *) no_install=yes ;;
-       esac
-       continue
-       ;;
-
-      -no-undefined)
-       allow_undefined=no
-       continue
-       ;;
-
-      -objectlist)
-       prev=objectlist
-       continue
-       ;;
-
-      -os2dllname)
-       prev=os2dllname
-       continue
-       ;;
-
-      -o) prev=output ;;
-
-      -precious-files-regex)
-       prev=precious_regex
-       continue
-       ;;
-
-      -release)
-       prev=release
-       continue
-       ;;
-
-      -rpath)
-       prev=rpath
-       continue
-       ;;
-
-      -R)
-       prev=xrpath
-       continue
-       ;;
-
-      -R*)
-       func_stripname '-R' '' "$arg"
-       dir=$func_stripname_result
-       # We need an absolute path.
-       case $dir in
-       [\\/]* | [A-Za-z]:[\\/]*) ;;
-       =*)
-         func_stripname '=' '' "$dir"
-         dir=$lt_sysroot$func_stripname_result
-         ;;
-       *)
-         func_fatal_error "only absolute run-paths are allowed"
-         ;;
-       esac
-       case "$xrpath " in
-       *" $dir "*) ;;
-       *) func_append xrpath " $dir" ;;
-       esac
-       continue
-       ;;
-
-      -shared)
-       # The effects of -shared are defined in a previous loop.
-       continue
-       ;;
-
-      -shrext)
-       prev=shrext
-       continue
-       ;;
-
-      -static | -static-libtool-libs)
-       # The effects of -static are defined in a previous loop.
-       # We used to do the same as -all-static on platforms that
-       # didn't have a PIC flag, but the assumption that the effects
-       # would be equivalent was wrong.  It would break on at least
-       # Digital Unix and AIX.
-       continue
-       ;;
-
-      -thread-safe)
-       thread_safe=yes
-       continue
-       ;;
-
-      -version-info)
-       prev=vinfo
-       continue
-       ;;
-
-      -version-number)
-       prev=vinfo
-       vinfo_number=yes
-       continue
-       ;;
-
-      -weak)
-        prev=weak
-       continue
-       ;;
-
-      -Wc,*)
-       func_stripname '-Wc,' '' "$arg"
-       args=$func_stripname_result
-       arg=
-       save_ifs=$IFS; IFS=,
-       for flag in $args; do
-         IFS=$save_ifs
-          func_quote_for_eval "$flag"
-         func_append arg " $func_quote_for_eval_result"
-         func_append compiler_flags " $func_quote_for_eval_result"
-       done
-       IFS=$save_ifs
-       func_stripname ' ' '' "$arg"
-       arg=$func_stripname_result
-       ;;
-
-      -Wl,*)
-       func_stripname '-Wl,' '' "$arg"
-       args=$func_stripname_result
-       arg=
-       save_ifs=$IFS; IFS=,
-       for flag in $args; do
-         IFS=$save_ifs
-          func_quote_for_eval "$flag"
-         func_append arg " $wl$func_quote_for_eval_result"
-         func_append compiler_flags " $wl$func_quote_for_eval_result"
-         func_append linker_flags " $func_quote_for_eval_result"
-       done
-       IFS=$save_ifs
-       func_stripname ' ' '' "$arg"
-       arg=$func_stripname_result
-       ;;
-
-      -Xcompiler)
-       prev=xcompiler
-       continue
-       ;;
-
-      -Xlinker)
-       prev=xlinker
-       continue
-       ;;
-
-      -XCClinker)
-       prev=xcclinker
-       continue
-       ;;
-
-      # -msg_* for osf cc
-      -msg_*)
-       func_quote_for_eval "$arg"
-       arg=$func_quote_for_eval_result
-       ;;
-
-      # Flags to be passed through unchanged, with rationale:
-      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
-      # -r[0-9][0-9]*        specify processor for the SGI compiler
-      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
-      # +DA*, +DD*           enable 64-bit mode for the HP compiler
-      # -q*                  compiler args for the IBM compiler
-      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
-      # -F/path              path to uninstalled frameworks, gcc on darwin
-      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
-      # -fstack-protector*   stack protector flags for GCC
-      # @file                GCC response files
-      # -tp=*                Portland pgcc target processor selection
-      # --sysroot=*          for sysroot support
-      # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
-      # -specs=*             GCC specs files
-      # -stdlib=*            select c++ std lib with clang
-      # -fsanitize=*         Clang/GCC memory and address sanitizer
-      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
-      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
-      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
-      -specs=*|-fsanitize=*)
-        func_quote_for_eval "$arg"
-       arg=$func_quote_for_eval_result
-        func_append compile_command " $arg"
-        func_append finalize_command " $arg"
-        func_append compiler_flags " $arg"
-        continue
-        ;;
-
-      -Z*)
-        if test os2 = "`expr $host : '.*\(os2\)'`"; then
-          # OS/2 uses -Zxxx to specify OS/2-specific options
-         compiler_flags="$compiler_flags $arg"
-         func_append compile_command " $arg"
-         func_append finalize_command " $arg"
-         case $arg in
-         -Zlinker | -Zstack)
-           prev=xcompiler
-           ;;
-         esac
-         continue
-        else
-         # Otherwise treat like 'Some other compiler flag' below
-         func_quote_for_eval "$arg"
-         arg=$func_quote_for_eval_result
-        fi
-       ;;
-
-      # Some other compiler flag.
-      -* | +*)
-        func_quote_for_eval "$arg"
-       arg=$func_quote_for_eval_result
-       ;;
-
-      *.$objext)
-       # A standard object.
-       func_append objs " $arg"
-       ;;
-
-      *.lo)
-       # A libtool-controlled object.
-
-       # Check to see that this really is a libtool object.
-       if func_lalib_unsafe_p "$arg"; then
-         pic_object=
-         non_pic_object=
-
-         # Read the .lo file
-         func_source "$arg"
-
-         if test -z "$pic_object" ||
-            test -z "$non_pic_object" ||
-            test none = "$pic_object" &&
-            test none = "$non_pic_object"; then
-           func_fatal_error "cannot find name of object for '$arg'"
-         fi
-
-         # Extract subdirectory from the argument.
-         func_dirname "$arg" "/" ""
-         xdir=$func_dirname_result
-
-         test none = "$pic_object" || {
-           # Prepend the subdirectory the object is found in.
-           pic_object=$xdir$pic_object
-
-           if test dlfiles = "$prev"; then
-             if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
-               func_append dlfiles " $pic_object"
-               prev=
-               continue
-             else
-               # If libtool objects are unsupported, then we need to preload.
-               prev=dlprefiles
-             fi
-           fi
-
-           # CHECK ME:  I think I busted this.  -Ossama
-           if test dlprefiles = "$prev"; then
-             # Preload the old-style object.
-             func_append dlprefiles " $pic_object"
-             prev=
-           fi
-
-           # A PIC object.
-           func_append libobjs " $pic_object"
-           arg=$pic_object
-         }
-
-         # Non-PIC object.
-         if test none != "$non_pic_object"; then
-           # Prepend the subdirectory the object is found in.
-           non_pic_object=$xdir$non_pic_object
-
-           # A standard non-PIC object
-           func_append non_pic_objects " $non_pic_object"
-           if test -z "$pic_object" || test none = "$pic_object"; then
-             arg=$non_pic_object
-           fi
-         else
-           # If the PIC object exists, use it instead.
-           # $xdir was prepended to $pic_object above.
-           non_pic_object=$pic_object
-           func_append non_pic_objects " $non_pic_object"
-         fi
-       else
-         # Only an error if not doing a dry-run.
-         if $opt_dry_run; then
-           # Extract subdirectory from the argument.
-           func_dirname "$arg" "/" ""
-           xdir=$func_dirname_result
-
-           func_lo2o "$arg"
-           pic_object=$xdir$objdir/$func_lo2o_result
-           non_pic_object=$xdir$func_lo2o_result
-           func_append libobjs " $pic_object"
-           func_append non_pic_objects " $non_pic_object"
-         else
-           func_fatal_error "'$arg' is not a valid libtool object"
-         fi
-       fi
-       ;;
-
-      *.$libext)
-       # An archive.
-       func_append deplibs " $arg"
-       func_append old_deplibs " $arg"
-       continue
-       ;;
-
-      *.la)
-       # A libtool-controlled library.
-
-       func_resolve_sysroot "$arg"
-       if test dlfiles = "$prev"; then
-         # This library was specified with -dlopen.
-         func_append dlfiles " $func_resolve_sysroot_result"
-         prev=
-       elif test dlprefiles = "$prev"; then
-         # The library was specified with -dlpreopen.
-         func_append dlprefiles " $func_resolve_sysroot_result"
-         prev=
-       else
-         func_append deplibs " $func_resolve_sysroot_result"
-       fi
-       continue
-       ;;
-
-      # Some other compiler argument.
-      *)
-       # Unknown arguments in both finalize_command and compile_command need
-       # to be aesthetically quoted because they are evaled later.
-       func_quote_for_eval "$arg"
-       arg=$func_quote_for_eval_result
-       ;;
-      esac # arg
-
-      # Now actually substitute the argument into the commands.
-      if test -n "$arg"; then
-       func_append compile_command " $arg"
-       func_append finalize_command " $arg"
-      fi
-    done # argument parsing loop
-
-    test -n "$prev" && \
-      func_fatal_help "the '$prevarg' option requires an argument"
-
-    if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
-      eval arg=\"$export_dynamic_flag_spec\"
-      func_append compile_command " $arg"
-      func_append finalize_command " $arg"
-    fi
-
-    oldlibs=
-    # calculate the name of the file, without its directory
-    func_basename "$output"
-    outputname=$func_basename_result
-    libobjs_save=$libobjs
-
-    if test -n "$shlibpath_var"; then
-      # get the directories listed in $shlibpath_var
-      eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
-    else
-      shlib_search_path=
-    fi
-    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
-    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
-
-    # Definition is injected by LT_CONFIG during libtool generation.
-    func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
-
-    func_dirname "$output" "/" ""
-    output_objdir=$func_dirname_result$objdir
-    func_to_tool_file "$output_objdir/"
-    tool_output_objdir=$func_to_tool_file_result
-    # Create the object directory.
-    func_mkdir_p "$output_objdir"
-
-    # Determine the type of output
-    case $output in
-    "")
-      func_fatal_help "you must specify an output file"
-      ;;
-    *.$libext) linkmode=oldlib ;;
-    *.lo | *.$objext) linkmode=obj ;;
-    *.la) linkmode=lib ;;
-    *) linkmode=prog ;; # Anything else should be a program.
-    esac
-
-    specialdeplibs=
-
-    libs=
-    # Find all interdependent deplibs by searching for libraries
-    # that are linked more than once (e.g. -la -lb -la)
-    for deplib in $deplibs; do
-      if $opt_preserve_dup_deps; then
-       case "$libs " in
-       *" $deplib "*) func_append specialdeplibs " $deplib" ;;
-       esac
-      fi
-      func_append libs " $deplib"
-    done
-
-    if test lib = "$linkmode"; then
-      libs="$predeps $libs $compiler_lib_search_path $postdeps"
-
-      # Compute libraries that are listed more than once in $predeps
-      # $postdeps and mark them as special (i.e., whose duplicates are
-      # not to be eliminated).
-      pre_post_deps=
-      if $opt_duplicate_compiler_generated_deps; then
-       for pre_post_dep in $predeps $postdeps; do
-         case "$pre_post_deps " in
-         *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
-         esac
-         func_append pre_post_deps " $pre_post_dep"
-       done
-      fi
-      pre_post_deps=
-    fi
-
-    deplibs=
-    newdependency_libs=
-    newlib_search_path=
-    need_relink=no # whether we're linking any uninstalled libtool libraries
-    notinst_deplibs= # not-installed libtool libraries
-    notinst_path= # paths that contain not-installed libtool libraries
-
-    case $linkmode in
-    lib)
-       passes="conv dlpreopen link"
-       for file in $dlfiles $dlprefiles; do
-         case $file in
-         *.la) ;;
-         *)
-           func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
-           ;;
-         esac
-       done
-       ;;
-    prog)
-       compile_deplibs=
-       finalize_deplibs=
-       alldeplibs=false
-       newdlfiles=
-       newdlprefiles=
-       passes="conv scan dlopen dlpreopen link"
-       ;;
-    *)  passes="conv"
-       ;;
-    esac
-
-    for pass in $passes; do
-      # The preopen pass in lib mode reverses $deplibs; put it back here
-      # so that -L comes before libs that need it for instance...
-      if test lib,link = "$linkmode,$pass"; then
-       ## FIXME: Find the place where the list is rebuilt in the wrong
-       ##        order, and fix it there properly
-        tmp_deplibs=
-       for deplib in $deplibs; do
-         tmp_deplibs="$deplib $tmp_deplibs"
-       done
-       deplibs=$tmp_deplibs
-      fi
-
-      if test lib,link = "$linkmode,$pass" ||
-        test prog,scan = "$linkmode,$pass"; then
-       libs=$deplibs
-       deplibs=
-      fi
-      if test prog = "$linkmode"; then
-       case $pass in
-       dlopen) libs=$dlfiles ;;
-       dlpreopen) libs=$dlprefiles ;;
-       link)
-         libs="$deplibs %DEPLIBS%"
-         test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
-         ;;
-       esac
-      fi
-      if test lib,dlpreopen = "$linkmode,$pass"; then
-       # Collect and forward deplibs of preopened libtool libs
-       for lib in $dlprefiles; do
-         # Ignore non-libtool-libs
-         dependency_libs=
-         func_resolve_sysroot "$lib"
-         case $lib in
-         *.la) func_source "$func_resolve_sysroot_result" ;;
-         esac
-
-         # Collect preopened libtool deplibs, except any this library
-         # has declared as weak libs
-         for deplib in $dependency_libs; do
-           func_basename "$deplib"
-            deplib_base=$func_basename_result
-           case " $weak_libs " in
-           *" $deplib_base "*) ;;
-           *) func_append deplibs " $deplib" ;;
-           esac
-         done
-       done
-       libs=$dlprefiles
-      fi
-      if test dlopen = "$pass"; then
-       # Collect dlpreopened libraries
-       save_deplibs=$deplibs
-       deplibs=
-      fi
-
-      for deplib in $libs; do
-       lib=
-       found=false
-       case $deplib in
-       -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
-        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
-         if test prog,link = "$linkmode,$pass"; then
-           compile_deplibs="$deplib $compile_deplibs"
-           finalize_deplibs="$deplib $finalize_deplibs"
-         else
-           func_append compiler_flags " $deplib"
-           if test lib = "$linkmode"; then
-               case "$new_inherited_linker_flags " in
-                   *" $deplib "*) ;;
-                   * ) func_append new_inherited_linker_flags " $deplib" ;;
-               esac
-           fi
-         fi
-         continue
-         ;;
-       -l*)
-         if test lib != "$linkmode" && test prog != "$linkmode"; then
-           func_warning "'-l' is ignored for archives/objects"
-           continue
-         fi
-         func_stripname '-l' '' "$deplib"
-         name=$func_stripname_result
-         if test lib = "$linkmode"; then
-           searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
-         else
-           searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
-         fi
-         for searchdir in $searchdirs; do
-           for search_ext in .la $std_shrext .so .a; do
-             # Search the libtool library
-             lib=$searchdir/lib$name$search_ext
-             if test -f "$lib"; then
-               if test .la = "$search_ext"; then
-                 found=:
-               else
-                 found=false
-               fi
-               break 2
-             fi
-           done
-         done
-         if $found; then
-           # deplib is a libtool library
-           # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
-           # We need to do some special things here, and not later.
-           if test yes = "$allow_libtool_libs_with_static_runtimes"; then
-             case " $predeps $postdeps " in
-             *" $deplib "*)
-               if func_lalib_p "$lib"; then
-                 library_names=
-                 old_library=
-                 func_source "$lib"
-                 for l in $old_library $library_names; do
-                   ll=$l
-                 done
-                 if test "X$ll" = "X$old_library"; then # only static version available
-                   found=false
-                   func_dirname "$lib" "" "."
-                   ladir=$func_dirname_result
-                   lib=$ladir/$old_library
-                   if test prog,link = "$linkmode,$pass"; then
-                     compile_deplibs="$deplib $compile_deplibs"
-                     finalize_deplibs="$deplib $finalize_deplibs"
-                   else
-                     deplibs="$deplib $deplibs"
-                     test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
-                   fi
-                   continue
-                 fi
-               fi
-               ;;
-             *) ;;
-             esac
-           fi
-         else
-           # deplib doesn't seem to be a libtool library
-           if test prog,link = "$linkmode,$pass"; then
-             compile_deplibs="$deplib $compile_deplibs"
-             finalize_deplibs="$deplib $finalize_deplibs"
-           else
-             deplibs="$deplib $deplibs"
-             test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
-           fi
-           continue
-         fi
-         ;; # -l
-       *.ltframework)
-         if test prog,link = "$linkmode,$pass"; then
-           compile_deplibs="$deplib $compile_deplibs"
-           finalize_deplibs="$deplib $finalize_deplibs"
-         else
-           deplibs="$deplib $deplibs"
-           if test lib = "$linkmode"; then
-               case "$new_inherited_linker_flags " in
-                   *" $deplib "*) ;;
-                   * ) func_append new_inherited_linker_flags " $deplib" ;;
-               esac
-           fi
-         fi
-         continue
-         ;;
-       -L*)
-         case $linkmode in
-         lib)
-           deplibs="$deplib $deplibs"
-           test conv = "$pass" && continue
-           newdependency_libs="$deplib $newdependency_libs"
-           func_stripname '-L' '' "$deplib"
-           func_resolve_sysroot "$func_stripname_result"
-           func_append newlib_search_path " $func_resolve_sysroot_result"
-           ;;
-         prog)
-           if test conv = "$pass"; then
-             deplibs="$deplib $deplibs"
-             continue
-           fi
-           if test scan = "$pass"; then
-             deplibs="$deplib $deplibs"
-           else
-             compile_deplibs="$deplib $compile_deplibs"
-             finalize_deplibs="$deplib $finalize_deplibs"
-           fi
-           func_stripname '-L' '' "$deplib"
-           func_resolve_sysroot "$func_stripname_result"
-           func_append newlib_search_path " $func_resolve_sysroot_result"
-           ;;
-         *)
-           func_warning "'-L' is ignored for archives/objects"
-           ;;
-         esac # linkmode
-         continue
-         ;; # -L
-       -R*)
-         if test link = "$pass"; then
-           func_stripname '-R' '' "$deplib"
-           func_resolve_sysroot "$func_stripname_result"
-           dir=$func_resolve_sysroot_result
-           # Make sure the xrpath contains only unique directories.
-           case "$xrpath " in
-           *" $dir "*) ;;
-           *) func_append xrpath " $dir" ;;
-           esac
-         fi
-         deplibs="$deplib $deplibs"
-         continue
-         ;;
-       *.la)
-         func_resolve_sysroot "$deplib"
-         lib=$func_resolve_sysroot_result
-         ;;
-       *.$libext)
-         if test conv = "$pass"; then
-           deplibs="$deplib $deplibs"
-           continue
-         fi
-         case $linkmode in
-         lib)
-           # Linking convenience modules into shared libraries is allowed,
-           # but linking other static libraries is non-portable.
-           case " $dlpreconveniencelibs " in
-           *" $deplib "*) ;;
-           *)
-             valid_a_lib=false
-             case $deplibs_check_method in
-               match_pattern*)
-                 set dummy $deplibs_check_method; shift
-                 match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
-                 if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
-                   | $EGREP "$match_pattern_regex" > /dev/null; then
-                   valid_a_lib=:
-                 fi
-               ;;
-               pass_all)
-                 valid_a_lib=:
-               ;;
-             esac
-             if $valid_a_lib; then
-               echo
-               $ECHO "*** Warning: Linking the shared library $output against the"
-               $ECHO "*** static library $deplib is not portable!"
-               deplibs="$deplib $deplibs"
-             else
-               echo
-               $ECHO "*** Warning: Trying to link with static lib archive $deplib."
-               echo "*** I have the capability to make that library automatically link in when"
-               echo "*** you link to this library.  But I can only do this if you have a"
-               echo "*** shared version of the library, which you do not appear to have"
-               echo "*** because the file extensions .$libext of this argument makes me believe"
-               echo "*** that it is just a static archive that I should not use here."
-             fi
-             ;;
-           esac
-           continue
-           ;;
-         prog)
-           if test link != "$pass"; then
-             deplibs="$deplib $deplibs"
-           else
-             compile_deplibs="$deplib $compile_deplibs"
-             finalize_deplibs="$deplib $finalize_deplibs"
-           fi
-           continue
-           ;;
-         esac # linkmode
-         ;; # *.$libext
-       *.lo | *.$objext)
-         if test conv = "$pass"; then
-           deplibs="$deplib $deplibs"
-         elif test prog = "$linkmode"; then
-           if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
-             # If there is no dlopen support or we're linking statically,
-             # we need to preload.
-             func_append newdlprefiles " $deplib"
-             compile_deplibs="$deplib $compile_deplibs"
-             finalize_deplibs="$deplib $finalize_deplibs"
-           else
-             func_append newdlfiles " $deplib"
-           fi
-         fi
-         continue
-         ;;
-       %DEPLIBS%)
-         alldeplibs=:
-         continue
-         ;;
-       esac # case $deplib
-
-       $found || test -f "$lib" \
-         || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
-
-       # Check to see that this really is a libtool archive.
-       func_lalib_unsafe_p "$lib" \
-         || func_fatal_error "'$lib' is not a valid libtool archive"
-
-       func_dirname "$lib" "" "."
-       ladir=$func_dirname_result
-
-       dlname=
-       dlopen=
-       dlpreopen=
-       libdir=
-       library_names=
-       old_library=
-       inherited_linker_flags=
-       # If the library was installed with an old release of libtool,
-       # it will not redefine variables installed, or shouldnotlink
-       installed=yes
-       shouldnotlink=no
-       avoidtemprpath=
-
-
-       # Read the .la file
-       func_source "$lib"
-
-       # Convert "-framework foo" to "foo.ltframework"
-       if test -n "$inherited_linker_flags"; then
-         tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
-         for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
-           case " $new_inherited_linker_flags " in
-             *" $tmp_inherited_linker_flag "*) ;;
-             *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
-           esac
-         done
-       fi
-       dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
-       if test lib,link = "$linkmode,$pass" ||
-          test prog,scan = "$linkmode,$pass" ||
-          { test prog != "$linkmode" && test lib != "$linkmode"; }; then
-         test -n "$dlopen" && func_append dlfiles " $dlopen"
-         test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
-       fi
-
-       if test conv = "$pass"; then
-         # Only check for convenience libraries
-         deplibs="$lib $deplibs"
-         if test -z "$libdir"; then
-           if test -z "$old_library"; then
-             func_fatal_error "cannot find name of link library for '$lib'"
-           fi
-           # It is a libtool convenience library, so add in its objects.
-           func_append convenience " $ladir/$objdir/$old_library"
-           func_append old_convenience " $ladir/$objdir/$old_library"
-           tmp_libs=
-           for deplib in $dependency_libs; do
-             deplibs="$deplib $deplibs"
-             if $opt_preserve_dup_deps; then
-               case "$tmp_libs " in
-               *" $deplib "*) func_append specialdeplibs " $deplib" ;;
-               esac
-             fi
-             func_append tmp_libs " $deplib"
-           done
-         elif test prog != "$linkmode" && test lib != "$linkmode"; then
-           func_fatal_error "'$lib' is not a convenience library"
-         fi
-         continue
-       fi # $pass = conv
-
-
-       # Get the name of the library we link against.
-       linklib=
-       if test -n "$old_library" &&
-          { test yes = "$prefer_static_libs" ||
-            test built,no = "$prefer_static_libs,$installed"; }; then
-         linklib=$old_library
-       else
-         for l in $old_library $library_names; do
-           linklib=$l
-         done
-       fi
-       if test -z "$linklib"; then
-         func_fatal_error "cannot find name of link library for '$lib'"
-       fi
-
-       # This library was specified with -dlopen.
-       if test dlopen = "$pass"; then
-         test -z "$libdir" \
-           && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
-         if test -z "$dlname" ||
-            test yes != "$dlopen_support" ||
-            test no = "$build_libtool_libs"
-         then
-           # If there is no dlname, no dlopen support or we're linking
-           # statically, we need to preload.  We also need to preload any
-           # dependent libraries so libltdl's deplib preloader doesn't
-           # bomb out in the load deplibs phase.
-           func_append dlprefiles " $lib $dependency_libs"
-         else
-           func_append newdlfiles " $lib"
-         fi
-         continue
-       fi # $pass = dlopen
-
-       # We need an absolute path.
-       case $ladir in
-       [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
-       *)
-         abs_ladir=`cd "$ladir" && pwd`
-         if test -z "$abs_ladir"; then
-           func_warning "cannot determine absolute directory name of '$ladir'"
-           func_warning "passing it literally to the linker, although it might fail"
-           abs_ladir=$ladir
-         fi
-         ;;
-       esac
-       func_basename "$lib"
-       laname=$func_basename_result
-
-       # Find the relevant object directory and library name.
-       if test yes = "$installed"; then
-         if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
-           func_warning "library '$lib' was moved."
-           dir=$ladir
-           absdir=$abs_ladir
-           libdir=$abs_ladir
-         else
-           dir=$lt_sysroot$libdir
-           absdir=$lt_sysroot$libdir
-         fi
-         test yes = "$hardcode_automatic" && avoidtemprpath=yes
-       else
-         if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
-           dir=$ladir
-           absdir=$abs_ladir
-           # Remove this search path later
-           func_append notinst_path " $abs_ladir"
-         else
-           dir=$ladir/$objdir
-           absdir=$abs_ladir/$objdir
-           # Remove this search path later
-           func_append notinst_path " $abs_ladir"
-         fi
-       fi # $installed = yes
-       func_stripname 'lib' '.la' "$laname"
-       name=$func_stripname_result
-
-       # This library was specified with -dlpreopen.
-       if test dlpreopen = "$pass"; then
-         if test -z "$libdir" && test prog = "$linkmode"; then
-           func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
-         fi
-         case $host in
-           # special handling for platforms with PE-DLLs.
-           *cygwin* | *mingw* | *cegcc* )
-             # Linker will automatically link against shared library if both
-             # static and shared are present.  Therefore, ensure we extract
-             # symbols from the import library if a shared library is present
-             # (otherwise, the dlopen module name will be incorrect).  We do
-             # this by putting the import library name into $newdlprefiles.
-             # We recover the dlopen module name by 'saving' the la file
-             # name in a special purpose variable, and (later) extracting the
-             # dlname from the la file.
-             if test -n "$dlname"; then
-               func_tr_sh "$dir/$linklib"
-               eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
-               func_append newdlprefiles " $dir/$linklib"
-             else
-               func_append newdlprefiles " $dir/$old_library"
-               # Keep a list of preopened convenience libraries to check
-               # that they are being used correctly in the link pass.
-               test -z "$libdir" && \
-                 func_append dlpreconveniencelibs " $dir/$old_library"
-             fi
-           ;;
-           * )
-             # Prefer using a static library (so that no silly _DYNAMIC symbols
-             # are required to link).
-             if test -n "$old_library"; then
-               func_append newdlprefiles " $dir/$old_library"
-               # Keep a list of preopened convenience libraries to check
-               # that they are being used correctly in the link pass.
-               test -z "$libdir" && \
-                 func_append dlpreconveniencelibs " $dir/$old_library"
-             # Otherwise, use the dlname, so that lt_dlopen finds it.
-             elif test -n "$dlname"; then
-               func_append newdlprefiles " $dir/$dlname"
-             else
-               func_append newdlprefiles " $dir/$linklib"
-             fi
-           ;;
-         esac
-       fi # $pass = dlpreopen
-
-       if test -z "$libdir"; then
-         # Link the convenience library
-         if test lib = "$linkmode"; then
-           deplibs="$dir/$old_library $deplibs"
-         elif test prog,link = "$linkmode,$pass"; then
-           compile_deplibs="$dir/$old_library $compile_deplibs"
-           finalize_deplibs="$dir/$old_library $finalize_deplibs"
-         else
-           deplibs="$lib $deplibs" # used for prog,scan pass
-         fi
-         continue
-       fi
-
-
-       if test prog = "$linkmode" && test link != "$pass"; then
-         func_append newlib_search_path " $ladir"
-         deplibs="$lib $deplibs"
-
-         linkalldeplibs=false
-         if test no != "$link_all_deplibs" || test -z "$library_names" ||
-            test no = "$build_libtool_libs"; then
-           linkalldeplibs=:
-         fi
-
-         tmp_libs=
-         for deplib in $dependency_libs; do
-           case $deplib in
-           -L*) func_stripname '-L' '' "$deplib"
-                func_resolve_sysroot "$func_stripname_result"
-                func_append newlib_search_path " $func_resolve_sysroot_result"
-                ;;
-           esac
-           # Need to link against all dependency_libs?
-           if $linkalldeplibs; then
-             deplibs="$deplib $deplibs"
-           else
-             # Need to hardcode shared library paths
-             # or/and link against static libraries
-             newdependency_libs="$deplib $newdependency_libs"
-           fi
-           if $opt_preserve_dup_deps; then
-             case "$tmp_libs " in
-             *" $deplib "*) func_append specialdeplibs " $deplib" ;;
-             esac
-           fi
-           func_append tmp_libs " $deplib"
-         done # for deplib
-         continue
-       fi # $linkmode = prog...
-
-       if test prog,link = "$linkmode,$pass"; then
-         if test -n "$library_names" &&
-            { { test no = "$prefer_static_libs" ||
-                test built,yes = "$prefer_static_libs,$installed"; } ||
-              test -z "$old_library"; }; then
-           # We need to hardcode the library path
-           if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
-             # Make sure the rpath contains only unique directories.
-             case $temp_rpath: in
-             *"$absdir:"*) ;;
-             *) func_append temp_rpath "$absdir:" ;;
-             esac
-           fi
-
-           # Hardcode the library path.
-           # Skip directories that are in the system default run-time
-           # search path.
-           case " $sys_lib_dlsearch_path " in
-           *" $absdir "*) ;;
-           *)
-             case "$compile_rpath " in
-             *" $absdir "*) ;;
-             *) func_append compile_rpath " $absdir" ;;
-             esac
-             ;;
-           esac
-           case " $sys_lib_dlsearch_path " in
-           *" $libdir "*) ;;
-           *)
-             case "$finalize_rpath " in
-             *" $libdir "*) ;;
-             *) func_append finalize_rpath " $libdir" ;;
-             esac
-             ;;
-           esac
-         fi # $linkmode,$pass = prog,link...
-
-         if $alldeplibs &&
-            { test pass_all = "$deplibs_check_method" ||
-              { test yes = "$build_libtool_libs" &&
-                test -n "$library_names"; }; }; then
-           # We only need to search for static libraries
-           continue
-         fi
-       fi
-
-       link_static=no # Whether the deplib will be linked statically
-       use_static_libs=$prefer_static_libs
-       if test built = "$use_static_libs" && test yes = "$installed"; then
-         use_static_libs=no
-       fi
-       if test -n "$library_names" &&
-          { test no = "$use_static_libs" || test -z "$old_library"; }; then
-         case $host in
-         *cygwin* | *mingw* | *cegcc* | *os2*)
-             # No point in relinking DLLs because paths are not encoded
-             func_append notinst_deplibs " $lib"
-             need_relink=no
-           ;;
-         *)
-           if test no = "$installed"; then
-             func_append notinst_deplibs " $lib"
-             need_relink=yes
-           fi
-           ;;
-         esac
-         # This is a shared library
-
-         # Warn about portability, can't link against -module's on some
-         # systems (darwin).  Don't bleat about dlopened modules though!
-         dlopenmodule=
-         for dlpremoduletest in $dlprefiles; do
-           if test "X$dlpremoduletest" = "X$lib"; then
-             dlopenmodule=$dlpremoduletest
-             break
-           fi
-         done
-         if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
-           echo
-           if test prog = "$linkmode"; then
-             $ECHO "*** Warning: Linking the executable $output against the loadable module"
-           else
-             $ECHO "*** Warning: Linking the shared library $output against the loadable module"
-           fi
-           $ECHO "*** $linklib is not portable!"
-         fi
-         if test lib = "$linkmode" &&
-            test yes = "$hardcode_into_libs"; then
-           # Hardcode the library path.
-           # Skip directories that are in the system default run-time
-           # search path.
-           case " $sys_lib_dlsearch_path " in
-           *" $absdir "*) ;;
-           *)
-             case "$compile_rpath " in
-             *" $absdir "*) ;;
-             *) func_append compile_rpath " $absdir" ;;
-             esac
-             ;;
-           esac
-           case " $sys_lib_dlsearch_path " in
-           *" $libdir "*) ;;
-           *)
-             case "$finalize_rpath " in
-             *" $libdir "*) ;;
-             *) func_append finalize_rpath " $libdir" ;;
-             esac
-             ;;
-           esac
-         fi
-
-         if test -n "$old_archive_from_expsyms_cmds"; then
-           # figure out the soname
-           set dummy $library_names
-           shift
-           realname=$1
-           shift
-           libname=`eval "\\$ECHO \"$libname_spec\""`
-           # use dlname if we got it. it's perfectly good, no?
-           if test -n "$dlname"; then
-             soname=$dlname
-           elif test -n "$soname_spec"; then
-             # bleh windows
-             case $host in
-             *cygwin* | mingw* | *cegcc* | *os2*)
-               func_arith $current - $age
-               major=$func_arith_result
-               versuffix=-$major
-               ;;
-             esac
-             eval soname=\"$soname_spec\"
-           else
-             soname=$realname
-           fi
-
-           # Make a new name for the extract_expsyms_cmds to use
-           soroot=$soname
-           func_basename "$soroot"
-           soname=$func_basename_result
-           func_stripname 'lib' '.dll' "$soname"
-           newlib=libimp-$func_stripname_result.a
-
-           # If the library has no export list, then create one now
-           if test -f "$output_objdir/$soname-def"; then :
-           else
-             func_verbose "extracting exported symbol list from '$soname'"
-             func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
-           fi
-
-           # Create $newlib
-           if test -f "$output_objdir/$newlib"; then :; else
-             func_verbose "generating import library for '$soname'"
-             func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
-           fi
-           # make sure the library variables are pointing to the new library
-           dir=$output_objdir
-           linklib=$newlib
-         fi # test -n "$old_archive_from_expsyms_cmds"
-
-         if test prog = "$linkmode" || test relink != "$opt_mode"; then
-           add_shlibpath=
-           add_dir=
-           add=
-           lib_linked=yes
-           case $hardcode_action in
-           immediate | unsupported)
-             if test no = "$hardcode_direct"; then
-               add=$dir/$linklib
-               case $host in
-                 *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
-                 *-*-sysv4*uw2*) add_dir=-L$dir ;;
-                 *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
-                   *-*-unixware7*) add_dir=-L$dir ;;
-                 *-*-darwin* )
-                   # if the lib is a (non-dlopened) module then we cannot
-                   # link against it, someone is ignoring the earlier warnings
-                   if /usr/bin/file -L $add 2> /dev/null |
-                        $GREP ": [^:]* bundle" >/dev/null; then
-                     if test "X$dlopenmodule" != "X$lib"; then
-                       $ECHO "*** Warning: lib $linklib is a module, not a shared library"
-                       if test -z "$old_library"; then
-                         echo
-                         echo "*** And there doesn't seem to be a static archive available"
-                         echo "*** The link will probably fail, sorry"
-                       else
-                         add=$dir/$old_library
-                       fi
-                     elif test -n "$old_library"; then
-                       add=$dir/$old_library
-                     fi
-                   fi
-               esac
-             elif test no = "$hardcode_minus_L"; then
-               case $host in
-               *-*-sunos*) add_shlibpath=$dir ;;
-               esac
-               add_dir=-L$dir
-               add=-l$name
-             elif test no = "$hardcode_shlibpath_var"; then
-               add_shlibpath=$dir
-               add=-l$name
-             else
-               lib_linked=no
-             fi
-             ;;
-           relink)
-             if test yes = "$hardcode_direct" &&
-                test no = "$hardcode_direct_absolute"; then
-               add=$dir/$linklib
-             elif test yes = "$hardcode_minus_L"; then
-               add_dir=-L$absdir
-               # Try looking first in the location we're being installed to.
-               if test -n "$inst_prefix_dir"; then
-                 case $libdir in
-                   [\\/]*)
-                     func_append add_dir " -L$inst_prefix_dir$libdir"
-                     ;;
-                 esac
-               fi
-               add=-l$name
-             elif test yes = "$hardcode_shlibpath_var"; then
-               add_shlibpath=$dir
-               add=-l$name
-             else
-               lib_linked=no
-             fi
-             ;;
-           *) lib_linked=no ;;
-           esac
-
-           if test yes != "$lib_linked"; then
-             func_fatal_configuration "unsupported hardcode properties"
-           fi
-
-           if test -n "$add_shlibpath"; then
-             case :$compile_shlibpath: in
-             *":$add_shlibpath:"*) ;;
-             *) func_append compile_shlibpath "$add_shlibpath:" ;;
-             esac
-           fi
-           if test prog = "$linkmode"; then
-             test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
-             test -n "$add" && compile_deplibs="$add $compile_deplibs"
-           else
-             test -n "$add_dir" && deplibs="$add_dir $deplibs"
-             test -n "$add" && deplibs="$add $deplibs"
-             if test yes != "$hardcode_direct" &&
-                test yes != "$hardcode_minus_L" &&
-                test yes = "$hardcode_shlibpath_var"; then
-               case :$finalize_shlibpath: in
-               *":$libdir:"*) ;;
-               *) func_append finalize_shlibpath "$libdir:" ;;
-               esac
-             fi
-           fi
-         fi
-
-         if test prog = "$linkmode" || test relink = "$opt_mode"; then
-           add_shlibpath=
-           add_dir=
-           add=
-           # Finalize command for both is simple: just hardcode it.
-           if test yes = "$hardcode_direct" &&
-              test no = "$hardcode_direct_absolute"; then
-             add=$libdir/$linklib
-           elif test yes = "$hardcode_minus_L"; then
-             add_dir=-L$libdir
-             add=-l$name
-           elif test yes = "$hardcode_shlibpath_var"; then
-             case :$finalize_shlibpath: in
-             *":$libdir:"*) ;;
-             *) func_append finalize_shlibpath "$libdir:" ;;
-             esac
-             add=-l$name
-           elif test yes = "$hardcode_automatic"; then
-             if test -n "$inst_prefix_dir" &&
-                test -f "$inst_prefix_dir$libdir/$linklib"; then
-               add=$inst_prefix_dir$libdir/$linklib
-             else
-               add=$libdir/$linklib
-             fi
-           else
-             # We cannot seem to hardcode it, guess we'll fake it.
-             add_dir=-L$libdir
-             # Try looking first in the location we're being installed to.
-             if test -n "$inst_prefix_dir"; then
-               case $libdir in
-                 [\\/]*)
-                   func_append add_dir " -L$inst_prefix_dir$libdir"
-                   ;;
-               esac
-             fi
-             add=-l$name
-           fi
-
-           if test prog = "$linkmode"; then
-             test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
-             test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
-           else
-             test -n "$add_dir" && deplibs="$add_dir $deplibs"
-             test -n "$add" && deplibs="$add $deplibs"
-           fi
-         fi
-       elif test prog = "$linkmode"; then
-         # Here we assume that one of hardcode_direct or hardcode_minus_L
-         # is not unsupported.  This is valid on all known static and
-         # shared platforms.
-         if test unsupported != "$hardcode_direct"; then
-           test -n "$old_library" && linklib=$old_library
-           compile_deplibs="$dir/$linklib $compile_deplibs"
-           finalize_deplibs="$dir/$linklib $finalize_deplibs"
-         else
-           compile_deplibs="-l$name -L$dir $compile_deplibs"
-           finalize_deplibs="-l$name -L$dir $finalize_deplibs"
-         fi
-       elif test yes = "$build_libtool_libs"; then
-         # Not a shared library
-         if test pass_all != "$deplibs_check_method"; then
-           # We're trying link a shared library against a static one
-           # but the system doesn't support it.
-
-           # Just print a warning and add the library to dependency_libs so
-           # that the program can be linked against the static library.
-           echo
-           $ECHO "*** Warning: This system cannot link to static lib archive $lib."
-           echo "*** I have the capability to make that library automatically link in when"
-           echo "*** you link to this library.  But I can only do this if you have a"
-           echo "*** shared version of the library, which you do not appear to have."
-           if test yes = "$module"; then
-             echo "*** But as you try to build a module library, libtool will still create "
-             echo "*** a static module, that should work as long as the dlopening application"
-             echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
-             if test -z "$global_symbol_pipe"; then
-               echo
-               echo "*** However, this would only work if libtool was able to extract symbol"
-               echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
-               echo "*** not find such a program.  So, this module is probably useless."
-               echo "*** 'nm' from GNU binutils and a full rebuild may help."
-             fi
-             if test no = "$build_old_libs"; then
-               build_libtool_libs=module
-               build_old_libs=yes
-             else
-               build_libtool_libs=no
-             fi
-           fi
-         else
-           deplibs="$dir/$old_library $deplibs"
-           link_static=yes
-         fi
-       fi # link shared/static library?
-
-       if test lib = "$linkmode"; then
-         if test -n "$dependency_libs" &&
-            { test yes != "$hardcode_into_libs" ||
-              test yes = "$build_old_libs" ||
-              test yes = "$link_static"; }; then
-           # Extract -R from dependency_libs
-           temp_deplibs=
-           for libdir in $dependency_libs; do
-             case $libdir in
-             -R*) func_stripname '-R' '' "$libdir"
-                  temp_xrpath=$func_stripname_result
-                  case " $xrpath " in
-                  *" $temp_xrpath "*) ;;
-                  *) func_append xrpath " $temp_xrpath";;
-                  esac;;
-             *) func_append temp_deplibs " $libdir";;
-             esac
-           done
-           dependency_libs=$temp_deplibs
-         fi
-
-         func_append newlib_search_path " $absdir"
-         # Link against this library
-         test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
-         # ... and its dependency_libs
-         tmp_libs=
-         for deplib in $dependency_libs; do
-           newdependency_libs="$deplib $newdependency_libs"
-           case $deplib in
-              -L*) func_stripname '-L' '' "$deplib"
-                   func_resolve_sysroot "$func_stripname_result";;
-              *) func_resolve_sysroot "$deplib" ;;
-            esac
-           if $opt_preserve_dup_deps; then
-             case "$tmp_libs " in
-             *" $func_resolve_sysroot_result "*)
-                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
-             esac
-           fi
-           func_append tmp_libs " $func_resolve_sysroot_result"
-         done
-
-         if test no != "$link_all_deplibs"; then
-           # Add the search paths of all dependency libraries
-           for deplib in $dependency_libs; do
-             path=
-             case $deplib in
-             -L*) path=$deplib ;;
-             *.la)
-               func_resolve_sysroot "$deplib"
-               deplib=$func_resolve_sysroot_result
-               func_dirname "$deplib" "" "."
-               dir=$func_dirname_result
-               # We need an absolute path.
-               case $dir in
-               [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
-               *)
-                 absdir=`cd "$dir" && pwd`
-                 if test -z "$absdir"; then
-                   func_warning "cannot determine absolute directory name of '$dir'"
-                   absdir=$dir
-                 fi
-                 ;;
-               esac
-               if $GREP "^installed=no" $deplib > /dev/null; then
-               case $host in
-               *-*-darwin*)
-                 depdepl=
-                 eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
-                 if test -n "$deplibrary_names"; then
-                   for tmp in $deplibrary_names; do
-                     depdepl=$tmp
-                   done
-                   if test -f "$absdir/$objdir/$depdepl"; then
-                     depdepl=$absdir/$objdir/$depdepl
-                     darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
-                      if test -z "$darwin_install_name"; then
-                          darwin_install_name=`$OTOOL64 -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
-                      fi
-                     func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
-                     func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
-                     path=
-                   fi
-                 fi
-                 ;;
-               *)
-                 path=-L$absdir/$objdir
-                 ;;
-               esac
-               else
-                 eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
-                 test -z "$libdir" && \
-                   func_fatal_error "'$deplib' is not a valid libtool archive"
-                 test "$absdir" != "$libdir" && \
-                   func_warning "'$deplib' seems to be moved"
-
-                 path=-L$absdir
-               fi
-               ;;
-             esac
-             case " $deplibs " in
-             *" $path "*) ;;
-             *) deplibs="$path $deplibs" ;;
-             esac
-           done
-         fi # link_all_deplibs != no
-       fi # linkmode = lib
-      done # for deplib in $libs
-      if test link = "$pass"; then
-       if test prog = "$linkmode"; then
-         compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
-         finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
-       else
-         compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
-       fi
-      fi
-      dependency_libs=$newdependency_libs
-      if test dlpreopen = "$pass"; then
-       # Link the dlpreopened libraries before other libraries
-       for deplib in $save_deplibs; do
-         deplibs="$deplib $deplibs"
-       done
-      fi
-      if test dlopen != "$pass"; then
-       test conv = "$pass" || {
-         # Make sure lib_search_path contains only unique directories.
-         lib_search_path=
-         for dir in $newlib_search_path; do
-           case "$lib_search_path " in
-           *" $dir "*) ;;
-           *) func_append lib_search_path " $dir" ;;
-           esac
-         done
-         newlib_search_path=
-       }
-
-       if test prog,link = "$linkmode,$pass"; then
-         vars="compile_deplibs finalize_deplibs"
-       else
-         vars=deplibs
-       fi
-       for var in $vars dependency_libs; do
-         # Add libraries to $var in reverse order
-         eval tmp_libs=\"\$$var\"
-         new_libs=
-         for deplib in $tmp_libs; do
-           # FIXME: Pedantically, this is the right thing to do, so
-           #        that some nasty dependency loop isn't accidentally
-           #        broken:
-           #new_libs="$deplib $new_libs"
-           # Pragmatically, this seems to cause very few problems in
-           # practice:
-           case $deplib in
-           -L*) new_libs="$deplib $new_libs" ;;
-           -R*) ;;
-           *)
-             # And here is the reason: when a library appears more
-             # than once as an explicit dependence of a library, or
-             # is implicitly linked in more than once by the
-             # compiler, it is considered special, and multiple
-             # occurrences thereof are not removed.  Compare this
-             # with having the same library being listed as a
-             # dependency of multiple other libraries: in this case,
-             # we know (pedantically, we assume) the library does not
-             # need to be listed more than once, so we keep only the
-             # last copy.  This is not always right, but it is rare
-             # enough that we require users that really mean to play
-             # such unportable linking tricks to link the library
-             # using -Wl,-lname, so that libtool does not consider it
-             # for duplicate removal.
-             case " $specialdeplibs " in
-             *" $deplib "*) new_libs="$deplib $new_libs" ;;
-             *)
-               case " $new_libs " in
-               *" $deplib "*) ;;
-               *) new_libs="$deplib $new_libs" ;;
-               esac
-               ;;
-             esac
-             ;;
-           esac
-         done
-         tmp_libs=
-         for deplib in $new_libs; do
-           case $deplib in
-           -L*)
-             case " $tmp_libs " in
-             *" $deplib "*) ;;
-             *) func_append tmp_libs " $deplib" ;;
-             esac
-             ;;
-           *) func_append tmp_libs " $deplib" ;;
-           esac
-         done
-         eval $var=\"$tmp_libs\"
-       done # for var
-      fi
-
-      # Add Sun CC postdeps if required:
-      test CXX = "$tagname" && {
-        case $host_os in
-        linux*)
-          case `$CC -V 2>&1 | sed 5q` in
-          *Sun\ C*) # Sun C++ 5.9
-            func_suncc_cstd_abi
-
-            if test no != "$suncc_use_cstd_abi"; then
-              func_append postdeps ' -library=Cstd -library=Crun'
-            fi
-            ;;
-          esac
-          ;;
-
-        solaris*)
-          func_cc_basename "$CC"
-          case $func_cc_basename_result in
-          CC* | sunCC*)
-            func_suncc_cstd_abi
-
-            if test no != "$suncc_use_cstd_abi"; then
-              func_append postdeps ' -library=Cstd -library=Crun'
-            fi
-            ;;
-          esac
-          ;;
-        esac
-      }
-
-      # Last step: remove runtime libs from dependency_libs
-      # (they stay in deplibs)
-      tmp_libs=
-      for i in $dependency_libs; do
-       case " $predeps $postdeps $compiler_lib_search_path " in
-       *" $i "*)
-         i=
-         ;;
-       esac
-       if test -n "$i"; then
-         func_append tmp_libs " $i"
-       fi
-      done
-      dependency_libs=$tmp_libs
-    done # for pass
-    if test prog = "$linkmode"; then
-      dlfiles=$newdlfiles
-    fi
-    if test prog = "$linkmode" || test lib = "$linkmode"; then
-      dlprefiles=$newdlprefiles
-    fi
-
-    case $linkmode in
-    oldlib)
-      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
-       func_warning "'-dlopen' is ignored for archives"
-      fi
-
-      case " $deplibs" in
-      *\ -l* | *\ -L*)
-       func_warning "'-l' and '-L' are ignored for archives" ;;
-      esac
-
-      test -n "$rpath" && \
-       func_warning "'-rpath' is ignored for archives"
-
-      test -n "$xrpath" && \
-       func_warning "'-R' is ignored for archives"
-
-      test -n "$vinfo" && \
-       func_warning "'-version-info/-version-number' is ignored for archives"
-
-      test -n "$release" && \
-       func_warning "'-release' is ignored for archives"
-
-      test -n "$export_symbols$export_symbols_regex" && \
-       func_warning "'-export-symbols' is ignored for archives"
-
-      # Now set the variables for building old libraries.
-      build_libtool_libs=no
-      oldlibs=$output
-      func_append objs "$old_deplibs"
-      ;;
-
-    lib)
-      # Make sure we only generate libraries of the form 'libNAME.la'.
-      case $outputname in
-      lib*)
-       func_stripname 'lib' '.la' "$outputname"
-       name=$func_stripname_result
-       eval shared_ext=\"$shrext_cmds\"
-       eval libname=\"$libname_spec\"
-       ;;
-      *)
-       test no = "$module" \
-         && func_fatal_help "libtool library '$output' must begin with 'lib'"
-
-       if test no != "$need_lib_prefix"; then
-         # Add the "lib" prefix for modules if required
-         func_stripname '' '.la' "$outputname"
-         name=$func_stripname_result
-         eval shared_ext=\"$shrext_cmds\"
-         eval libname=\"$libname_spec\"
-       else
-         func_stripname '' '.la' "$outputname"
-         libname=$func_stripname_result
-       fi
-       ;;
-      esac
-
-      if test -n "$objs"; then
-       if test pass_all != "$deplibs_check_method"; then
-         func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
-       else
-         echo
-         $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
-         $ECHO "*** objects $objs is not portable!"
-         func_append libobjs " $objs"
-       fi
-      fi
-
-      test no = "$dlself" \
-       || func_warning "'-dlopen self' is ignored for libtool libraries"
-
-      set dummy $rpath
-      shift
-      test 1 -lt "$#" \
-       && func_warning "ignoring multiple '-rpath's for a libtool library"
-
-      install_libdir=$1
-
-      oldlibs=
-      if test -z "$rpath"; then
-       if test yes = "$build_libtool_libs"; then
-         # Building a libtool convenience library.
-         # Some compilers have problems with a '.al' extension so
-         # convenience libraries should have the same extension an
-         # archive normally would.
-         oldlibs="$output_objdir/$libname.$libext $oldlibs"
-         build_libtool_libs=convenience
-         build_old_libs=yes
-       fi
-
-       test -n "$vinfo" && \
-         func_warning "'-version-info/-version-number' is ignored for convenience libraries"
-
-       test -n "$release" && \
-         func_warning "'-release' is ignored for convenience libraries"
-      else
-
-       # Parse the version information argument.
-       save_ifs=$IFS; IFS=:
-       set dummy $vinfo 0 0 0
-       shift
-       IFS=$save_ifs
-
-       test -n "$7" && \
-         func_fatal_help "too many parameters to '-version-info'"
-
-       # convert absolute version numbers to libtool ages
-       # this retains compatibility with .la files and attempts
-       # to make the code below a bit more comprehensible
-
-       case $vinfo_number in
-       yes)
-         number_major=$1
-         number_minor=$2
-         number_revision=$3
-         #
-         # There are really only two kinds -- those that
-         # use the current revision as the major version
-         # and those that subtract age and use age as
-         # a minor version.  But, then there is irix
-         # that has an extra 1 added just for fun
-         #
-         case $version_type in
-         # correct linux to gnu/linux during the next big refactor
-         darwin|freebsd-elf|linux|osf|windows|none)
-           func_arith $number_major + $number_minor
-           current=$func_arith_result
-           age=$number_minor
-           revision=$number_revision
-           ;;
-         freebsd-aout|qnx|sunos)
-           current=$number_major
-           revision=$number_minor
-           age=0
-           ;;
-         irix|nonstopux)
-           func_arith $number_major + $number_minor
-           current=$func_arith_result
-           age=$number_minor
-           revision=$number_minor
-           lt_irix_increment=no
-           ;;
-         *)
-           func_fatal_configuration "$modename: unknown library version type '$version_type'"
-           ;;
-         esac
-         ;;
-       no)
-         current=$1
-         revision=$2
-         age=$3
-         ;;
-       esac
-
-       # Check that each of the things are valid numbers.
-       case $current in
-       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
-       *)
-         func_error "CURRENT '$current' must be a nonnegative integer"
-         func_fatal_error "'$vinfo' is not valid version information"
-         ;;
-       esac
-
-       case $revision in
-       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
-       *)
-         func_error "REVISION '$revision' must be a nonnegative integer"
-         func_fatal_error "'$vinfo' is not valid version information"
-         ;;
-       esac
-
-       case $age in
-       0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
-       *)
-         func_error "AGE '$age' must be a nonnegative integer"
-         func_fatal_error "'$vinfo' is not valid version information"
-         ;;
-       esac
-
-       if test "$age" -gt "$current"; then
-         func_error "AGE '$age' is greater than the current interface number '$current'"
-         func_fatal_error "'$vinfo' is not valid version information"
-       fi
-
-       # Calculate the version variables.
-       major=
-       versuffix=
-       verstring=
-       case $version_type in
-       none) ;;
-
-       darwin)
-         # Like Linux, but with the current version available in
-         # verstring for coding it into the library header
-         func_arith $current - $age
-         major=.$func_arith_result
-         versuffix=$major.$age.$revision
-         # Darwin ld doesn't like 0 for these options...
-         func_arith $current + 1
-         minor_current=$func_arith_result
-         xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
-         verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
-          # On Darwin other compilers
-          case $CC in
-              nagfor*)
-                  verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
-                  ;;
-              *)
-                  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
-                  ;;
-          esac
-         ;;
-
-       freebsd-aout)
-         major=.$current
-         versuffix=.$current.$revision
-         ;;
-
-       freebsd-elf)
-         func_arith $current - $age
-         major=.$func_arith_result
-         versuffix=$major.$age.$revision
-         ;;
-
-       irix | nonstopux)
-         if test no = "$lt_irix_increment"; then
-           func_arith $current - $age
-         else
-           func_arith $current - $age + 1
-         fi
-         major=$func_arith_result
-
-         case $version_type in
-           nonstopux) verstring_prefix=nonstopux ;;
-           *)         verstring_prefix=sgi ;;
-         esac
-         verstring=$verstring_prefix$major.$revision
-
-         # Add in all the interfaces that we are compatible with.
-         loop=$revision
-         while test 0 -ne "$loop"; do
-           func_arith $revision - $loop
-           iface=$func_arith_result
-           func_arith $loop - 1
-           loop=$func_arith_result
-           verstring=$verstring_prefix$major.$iface:$verstring
-         done
-
-         # Before this point, $major must not contain '.'.
-         major=.$major
-         versuffix=$major.$revision
-         ;;
-
-       linux) # correct to gnu/linux during the next big refactor
-         func_arith $current - $age
-         major=.$func_arith_result
-         versuffix=$major.$age.$revision
-         ;;
-
-       osf)
-         func_arith $current - $age
-         major=.$func_arith_result
-         versuffix=.$current.$age.$revision
-         verstring=$current.$age.$revision
-
-         # Add in all the interfaces that we are compatible with.
-         loop=$age
-         while test 0 -ne "$loop"; do
-           func_arith $current - $loop
-           iface=$func_arith_result
-           func_arith $loop - 1
-           loop=$func_arith_result
-           verstring=$verstring:$iface.0
-         done
-
-         # Make executables depend on our current version.
-         func_append verstring ":$current.0"
-         ;;
-
-       qnx)
-         major=.$current
-         versuffix=.$current
-         ;;
-
-       sco)
-         major=.$current
-         versuffix=.$current
-         ;;
-
-       sunos)
-         major=.$current
-         versuffix=.$current.$revision
-         ;;
-
-       windows)
-         # Use '-' rather than '.', since we only want one
-         # extension on DOS 8.3 file systems.
-         func_arith $current - $age
-         major=$func_arith_result
-         versuffix=-$major
-         ;;
-
-       *)
-         func_fatal_configuration "unknown library version type '$version_type'"
-         ;;
-       esac
-
-       # Clear the version info if we defaulted, and they specified a release.
-       if test -z "$vinfo" && test -n "$release"; then
-         major=
-         case $version_type in
-         darwin)
-           # we can't check for "0.0" in archive_cmds due to quoting
-           # problems, so we reset it completely
-           verstring=
-           ;;
-         *)
-           verstring=0.0
-           ;;
-         esac
-         if test no = "$need_version"; then
-           versuffix=
-         else
-           versuffix=.0.0
-         fi
-       fi
-
-       # Remove version info from name if versioning should be avoided
-       if test yes,no = "$avoid_version,$need_version"; then
-         major=
-         versuffix=
-         verstring=
-       fi
-
-       # Check to see if the archive will have undefined symbols.
-       if test yes = "$allow_undefined"; then
-         if test unsupported = "$allow_undefined_flag"; then
-           if test yes = "$build_old_libs"; then
-             func_warning "undefined symbols not allowed in $host shared libraries; building static only"
-             build_libtool_libs=no
-           else
-             func_fatal_error "can't build $host shared library unless -no-undefined is specified"
-           fi
-         fi
-       else
-         # Don't allow undefined symbols.
-         allow_undefined_flag=$no_undefined_flag
-       fi
-
-      fi
-
-      func_generate_dlsyms "$libname" "$libname" :
-      func_append libobjs " $symfileobj"
-      test " " = "$libobjs" && libobjs=
-
-      if test relink != "$opt_mode"; then
-       # Remove our outputs, but don't remove object files since they
-       # may have been created when compiling PIC objects.
-       removelist=
-       tempremovelist=`$ECHO "$output_objdir/*"`
-       for p in $tempremovelist; do
-         case $p in
-           *.$objext | *.gcno)
-              ;;
-           $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
-              if test -n "$precious_files_regex"; then
-                if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
-                then
-                  continue
-                fi
-              fi
-              func_append removelist " $p"
-              ;;
-           *) ;;
-         esac
-       done
-       test -n "$removelist" && \
-         func_show_eval "${RM}r \$removelist"
-      fi
-
-      # Now set the variables for building old libraries.
-      if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
-       func_append oldlibs " $output_objdir/$libname.$libext"
-
-       # Transform .lo files to .o files.
-       oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
-      fi
-
-      # Eliminate all temporary directories.
-      #for path in $notinst_path; do
-      #        lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
-      #        deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
-      #        dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
-      #done
-
-      if test -n "$xrpath"; then
-       # If the user specified any rpath flags, then add them.
-       temp_xrpath=
-       for libdir in $xrpath; do
-         func_replace_sysroot "$libdir"
-         func_append temp_xrpath " -R$func_replace_sysroot_result"
-         case "$finalize_rpath " in
-         *" $libdir "*) ;;
-         *) func_append finalize_rpath " $libdir" ;;
-         esac
-       done
-       if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
-         dependency_libs="$temp_xrpath $dependency_libs"
-       fi
-      fi
-
-      # Make sure dlfiles contains only unique files that won't be dlpreopened
-      old_dlfiles=$dlfiles
-      dlfiles=
-      for lib in $old_dlfiles; do
-       case " $dlprefiles $dlfiles " in
-       *" $lib "*) ;;
-       *) func_append dlfiles " $lib" ;;
-       esac
-      done
-
-      # Make sure dlprefiles contains only unique files
-      old_dlprefiles=$dlprefiles
-      dlprefiles=
-      for lib in $old_dlprefiles; do
-       case "$dlprefiles " in
-       *" $lib "*) ;;
-       *) func_append dlprefiles " $lib" ;;
-       esac
-      done
-
-      if test yes = "$build_libtool_libs"; then
-       if test -n "$rpath"; then
-         case $host in
-         *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
-           # these systems don't actually have a c library (as such)!
-           ;;
-         *-*-rhapsody* | *-*-darwin1.[012])
-           # Rhapsody C library is in the System framework
-           func_append deplibs " System.ltframework"
-           ;;
-         *-*-netbsd*)
-           # Don't link with libc until the a.out ld.so is fixed.
-           ;;
-         *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
-           # Do not include libc due to us having libc/libc_r.
-           ;;
-         *-*-sco3.2v5* | *-*-sco5v6*)
-           # Causes problems with __ctype
-           ;;
-         *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
-           # Compiler inserts libc in the correct place for threads to work
-           ;;
-         *)
-           # Add libc to deplibs on all other systems if necessary.
-           if test yes = "$build_libtool_need_lc"; then
-             func_append deplibs " -lc"
-           fi
-           ;;
-         esac
-       fi
-
-       # Transform deplibs into only deplibs that can be linked in shared.
-       name_save=$name
-       libname_save=$libname
-       release_save=$release
-       versuffix_save=$versuffix
-       major_save=$major
-       # I'm not sure if I'm treating the release correctly.  I think
-       # release should show up in the -l (ie -lgmp5) so we don't want to
-       # add it in twice.  Is that correct?
-       release=
-       versuffix=
-       major=
-       newdeplibs=
-       droppeddeps=no
-       case $deplibs_check_method in
-       pass_all)
-         # Don't check for shared/static.  Everything works.
-         # This might be a little naive.  We might want to check
-         # whether the library exists or not.  But this is on
-         # osf3 & osf4 and I'm not really sure... Just
-         # implementing what was already the behavior.
-         newdeplibs=$deplibs
-         ;;
-       test_compile)
-         # This code stresses the "libraries are programs" paradigm to its
-         # limits. Maybe even breaks it.  We compile a program, linking it
-         # against the deplibs as a proxy for the library.  Then we can check
-         # whether they linked in statically or dynamically with ldd.
-         $opt_dry_run || $RM conftest.c
-         cat > conftest.c <<EOF
-         int main() { return 0; }
-EOF
-         $opt_dry_run || $RM conftest
-         if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
-           ldd_output=`ldd conftest`
-           for i in $deplibs; do
-             case $i in
-             -l*)
-               func_stripname -l '' "$i"
-               name=$func_stripname_result
-               if test yes = "$allow_libtool_libs_with_static_runtimes"; then
-                 case " $predeps $postdeps " in
-                 *" $i "*)
-                   func_append newdeplibs " $i"
-                   i=
-                   ;;
-                 esac
-               fi
-               if test -n "$i"; then
-                 libname=`eval "\\$ECHO \"$libname_spec\""`
-                 deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
-                 set dummy $deplib_matches; shift
-                 deplib_match=$1
-                 if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
-                   func_append newdeplibs " $i"
-                 else
-                   droppeddeps=yes
-                   echo
-                   $ECHO "*** Warning: dynamic linker does not accept needed library $i."
-                   echo "*** I have the capability to make that library automatically link in when"
-                   echo "*** you link to this library.  But I can only do this if you have a"
-                   echo "*** shared version of the library, which I believe you do not have"
-                   echo "*** because a test_compile did reveal that the linker did not use it for"
-                   echo "*** its dynamic dependency list that programs get resolved with at runtime."
-                 fi
-               fi
-               ;;
-             *)
-               func_append newdeplibs " $i"
-               ;;
-             esac
-           done
-         else
-           # Error occurred in the first compile.  Let's try to salvage
-           # the situation: Compile a separate program for each library.
-           for i in $deplibs; do
-             case $i in
-             -l*)
-               func_stripname -l '' "$i"
-               name=$func_stripname_result
-               $opt_dry_run || $RM conftest
-               if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
-                 ldd_output=`ldd conftest`
-                 if test yes = "$allow_libtool_libs_with_static_runtimes"; then
-                   case " $predeps $postdeps " in
-                   *" $i "*)
-                     func_append newdeplibs " $i"
-                     i=
-                     ;;
-                   esac
-                 fi
-                 if test -n "$i"; then
-                   libname=`eval "\\$ECHO \"$libname_spec\""`
-                   deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
-                   set dummy $deplib_matches; shift
-                   deplib_match=$1
-                   if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
-                     func_append newdeplibs " $i"
-                   else
-                     droppeddeps=yes
-                     echo
-                     $ECHO "*** Warning: dynamic linker does not accept needed library $i."
-                     echo "*** I have the capability to make that library automatically link in when"
-                     echo "*** you link to this library.  But I can only do this if you have a"
-                     echo "*** shared version of the library, which you do not appear to have"
-                     echo "*** because a test_compile did reveal that the linker did not use this one"
-                     echo "*** as a dynamic dependency that programs can get resolved with at runtime."
-                   fi
-                 fi
-               else
-                 droppeddeps=yes
-                 echo
-                 $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
-                 echo "*** make it link in!  You will probably need to install it or some"
-                 echo "*** library that it depends on before this library will be fully"
-                 echo "*** functional.  Installing it before continuing would be even better."
-               fi
-               ;;
-             *)
-               func_append newdeplibs " $i"
-               ;;
-             esac
-           done
-         fi
-         ;;
-       file_magic*)
-         set dummy $deplibs_check_method; shift
-         file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
-         for a_deplib in $deplibs; do
-           case $a_deplib in
-           -l*)
-             func_stripname -l '' "$a_deplib"
-             name=$func_stripname_result
-             if test yes = "$allow_libtool_libs_with_static_runtimes"; then
-               case " $predeps $postdeps " in
-               *" $a_deplib "*)
-                 func_append newdeplibs " $a_deplib"
-                 a_deplib=
-                 ;;
-               esac
-             fi
-             if test -n "$a_deplib"; then
-               libname=`eval "\\$ECHO \"$libname_spec\""`
-               if test -n "$file_magic_glob"; then
-                 libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
-               else
-                 libnameglob=$libname
-               fi
-               test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
-               for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
-                 if test yes = "$want_nocaseglob"; then
-                   shopt -s nocaseglob
-                   potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
-                   $nocaseglob
-                 else
-                   potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
-                 fi
-                 for potent_lib in $potential_libs; do
-                     # Follow soft links.
-                     if ls -lLd "$potent_lib" 2>/dev/null |
-                        $GREP " -> " >/dev/null; then
-                       continue
-                     fi
-                     # The statement above tries to avoid entering an
-                     # endless loop below, in case of cyclic links.
-                     # We might still enter an endless loop, since a link
-                     # loop can be closed while we follow links,
-                     # but so what?
-                     potlib=$potent_lib
-                     while test -h "$potlib" 2>/dev/null; do
-                       potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
-                       case $potliblink in
-                       [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
-                       *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
-                       esac
-                     done
-                     if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
-                        $SED -e 10q |
-                        $EGREP "$file_magic_regex" > /dev/null; then
-                       func_append newdeplibs " $a_deplib"
-                       a_deplib=
-                       break 2
-                     fi
-                 done
-               done
-             fi
-             if test -n "$a_deplib"; then
-               droppeddeps=yes
-               echo
-               $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
-               echo "*** I have the capability to make that library automatically link in when"
-               echo "*** you link to this library.  But I can only do this if you have a"
-               echo "*** shared version of the library, which you do not appear to have"
-               echo "*** because I did check the linker path looking for a file starting"
-               if test -z "$potlib"; then
-                 $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
-               else
-                 $ECHO "*** with $libname and none of the candidates passed a file format test"
-                 $ECHO "*** using a file magic. Last file checked: $potlib"
-               fi
-             fi
-             ;;
-           *)
-             # Add a -L argument.
-             func_append newdeplibs " $a_deplib"
-             ;;
-           esac
-         done # Gone through all deplibs.
-         ;;
-       match_pattern*)
-         set dummy $deplibs_check_method; shift
-         match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
-         for a_deplib in $deplibs; do
-           case $a_deplib in
-           -l*)
-             func_stripname -l '' "$a_deplib"
-             name=$func_stripname_result
-             if test yes = "$allow_libtool_libs_with_static_runtimes"; then
-               case " $predeps $postdeps " in
-               *" $a_deplib "*)
-                 func_append newdeplibs " $a_deplib"
-                 a_deplib=
-                 ;;
-               esac
-             fi
-             if test -n "$a_deplib"; then
-               libname=`eval "\\$ECHO \"$libname_spec\""`
-               for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
-                 potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
-                 for potent_lib in $potential_libs; do
-                   potlib=$potent_lib # see symlink-check above in file_magic test
-                   if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
-                      $EGREP "$match_pattern_regex" > /dev/null; then
-                     func_append newdeplibs " $a_deplib"
-                     a_deplib=
-                     break 2
-                   fi
-                 done
-               done
-             fi
-             if test -n "$a_deplib"; then
-               droppeddeps=yes
-               echo
-               $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
-               echo "*** I have the capability to make that library automatically link in when"
-               echo "*** you link to this library.  But I can only do this if you have a"
-               echo "*** shared version of the library, which you do not appear to have"
-               echo "*** because I did check the linker path looking for a file starting"
-               if test -z "$potlib"; then
-                 $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
-               else
-                 $ECHO "*** with $libname and none of the candidates passed a file format test"
-                 $ECHO "*** using a regex pattern. Last file checked: $potlib"
-               fi
-             fi
-             ;;
-           *)
-             # Add a -L argument.
-             func_append newdeplibs " $a_deplib"
-             ;;
-           esac
-         done # Gone through all deplibs.
-         ;;
-       none | unknown | *)
-         newdeplibs=
-         tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
-         if test yes = "$allow_libtool_libs_with_static_runtimes"; then
-           for i in $predeps $postdeps; do
-             # can't use Xsed below, because $i might contain '/'
-             tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
-           done
-         fi
-         case $tmp_deplibs in
-         *[!\  \ ]*)
-           echo
-           if test none = "$deplibs_check_method"; then
-             echo "*** Warning: inter-library dependencies are not supported in this platform."
-           else
-             echo "*** Warning: inter-library dependencies are not known to be supported."
-           fi
-           echo "*** All declared inter-library dependencies are being dropped."
-           droppeddeps=yes
-           ;;
-         esac
-         ;;
-       esac
-       versuffix=$versuffix_save
-       major=$major_save
-       release=$release_save
-       libname=$libname_save
-       name=$name_save
-
-       case $host in
-       *-*-rhapsody* | *-*-darwin1.[012])
-         # On Rhapsody replace the C library with the System framework
-         newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
-         ;;
-       esac
-
-       if test yes = "$droppeddeps"; then
-         if test yes = "$module"; then
-           echo
-           echo "*** Warning: libtool could not satisfy all declared inter-library"
-           $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
-           echo "*** a static module, that should work as long as the dlopening"
-           echo "*** application is linked with the -dlopen flag."
-           if test -z "$global_symbol_pipe"; then
-             echo
-             echo "*** However, this would only work if libtool was able to extract symbol"
-             echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
-             echo "*** not find such a program.  So, this module is probably useless."
-             echo "*** 'nm' from GNU binutils and a full rebuild may help."
-           fi
-           if test no = "$build_old_libs"; then
-             oldlibs=$output_objdir/$libname.$libext
-             build_libtool_libs=module
-             build_old_libs=yes
-           else
-             build_libtool_libs=no
-           fi
-         else
-           echo "*** The inter-library dependencies that have been dropped here will be"
-           echo "*** automatically added whenever a program is linked with this library"
-           echo "*** or is declared to -dlopen it."
-
-           if test no = "$allow_undefined"; then
-             echo
-             echo "*** Since this library must not contain undefined symbols,"
-             echo "*** because either the platform does not support them or"
-             echo "*** it was explicitly requested with -no-undefined,"
-             echo "*** libtool will only create a static version of it."
-             if test no = "$build_old_libs"; then
-               oldlibs=$output_objdir/$libname.$libext
-               build_libtool_libs=module
-               build_old_libs=yes
-             else
-               build_libtool_libs=no
-             fi
-           fi
-         fi
-       fi
-       # Done checking deplibs!
-       deplibs=$newdeplibs
-      fi
-      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
-      case $host in
-       *-*-darwin*)
-         newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
-         new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
-         deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
-         ;;
-      esac
-
-      # move library search paths that coincide with paths to not yet
-      # installed libraries to the beginning of the library search list
-      new_libs=
-      for path in $notinst_path; do
-       case " $new_libs " in
-       *" -L$path/$objdir "*) ;;
-       *)
-         case " $deplibs " in
-         *" -L$path/$objdir "*)
-           func_append new_libs " -L$path/$objdir" ;;
-         esac
-         ;;
-       esac
-      done
-      for deplib in $deplibs; do
-       case $deplib in
-       -L*)
-         case " $new_libs " in
-         *" $deplib "*) ;;
-         *) func_append new_libs " $deplib" ;;
-         esac
-         ;;
-       *) func_append new_libs " $deplib" ;;
-       esac
-      done
-      deplibs=$new_libs
-
-      # All the library-specific variables (install_libdir is set above).
-      library_names=
-      old_library=
-      dlname=
-
-      # Test again, we may have decided not to build it any more
-      if test yes = "$build_libtool_libs"; then
-       # Remove $wl instances when linking with ld.
-       # FIXME: should test the right _cmds variable.
-       case $archive_cmds in
-         *\$LD\ *) wl= ;;
-        esac
-       if test yes = "$hardcode_into_libs"; then
-         # Hardcode the library paths
-         hardcode_libdirs=
-         dep_rpath=
-         rpath=$finalize_rpath
-         test relink = "$opt_mode" || rpath=$compile_rpath$rpath
-         for libdir in $rpath; do
-           if test -n "$hardcode_libdir_flag_spec"; then
-             if test -n "$hardcode_libdir_separator"; then
-               func_replace_sysroot "$libdir"
-               libdir=$func_replace_sysroot_result
-               if test -z "$hardcode_libdirs"; then
-                 hardcode_libdirs=$libdir
-               else
-                 # Just accumulate the unique libdirs.
-                 case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
-                 *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
-                   ;;
-                 *)
-                   func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
-                   ;;
-                 esac
-               fi
-             else
-               eval flag=\"$hardcode_libdir_flag_spec\"
-               func_append dep_rpath " $flag"
-             fi
-           elif test -n "$runpath_var"; then
-             case "$perm_rpath " in
-             *" $libdir "*) ;;
-             *) func_append perm_rpath " $libdir" ;;
-             esac
-           fi
-         done
-         # Substitute the hardcoded libdirs into the rpath.
-         if test -n "$hardcode_libdir_separator" &&
-            test -n "$hardcode_libdirs"; then
-           libdir=$hardcode_libdirs
-           eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
-         fi
-         if test -n "$runpath_var" && test -n "$perm_rpath"; then
-           # We should set the runpath_var.
-           rpath=
-           for dir in $perm_rpath; do
-             func_append rpath "$dir:"
-           done
-           eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
-         fi
-         test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
-       fi
-
-       shlibpath=$finalize_shlibpath
-       test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
-       if test -n "$shlibpath"; then
-         eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
-       fi
-
-       # Get the real and link names of the library.
-       eval shared_ext=\"$shrext_cmds\"
-       eval library_names=\"$library_names_spec\"
-       set dummy $library_names
-       shift
-       realname=$1
-       shift
-
-       if test -n "$soname_spec"; then
-         eval soname=\"$soname_spec\"
-       else
-         soname=$realname
-       fi
-       if test -z "$dlname"; then
-         dlname=$soname
-       fi
-
-       lib=$output_objdir/$realname
-       linknames=
-       for link
-       do
-         func_append linknames " $link"
-       done
-
-       # Use standard objects if they are pic
-       test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
-       test "X$libobjs" = "X " && libobjs=
-
-       delfiles=
-       if test -n "$export_symbols" && test -n "$include_expsyms"; then
-         $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
-         export_symbols=$output_objdir/$libname.uexp
-         func_append delfiles " $export_symbols"
-       fi
-
-       orig_export_symbols=
-       case $host_os in
-       cygwin* | mingw* | cegcc*)
-         if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
-           # exporting using user supplied symfile
-           func_dll_def_p "$export_symbols" || {
-             # and it's NOT already a .def file. Must figure out
-             # which of the given symbols are data symbols and tag
-             # them as such. So, trigger use of export_symbols_cmds.
-             # export_symbols gets reassigned inside the "prepare
-             # the list of exported symbols" if statement, so the
-             # include_expsyms logic still works.
-             orig_export_symbols=$export_symbols
-             export_symbols=
-             always_export_symbols=yes
-           }
-         fi
-         ;;
-       esac
-
-       # Prepare the list of exported symbols
-       if test -z "$export_symbols"; then
-         if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
-           func_verbose "generating symbol list for '$libname.la'"
-           export_symbols=$output_objdir/$libname.exp
-           $opt_dry_run || $RM $export_symbols
-           cmds=$export_symbols_cmds
-           save_ifs=$IFS; IFS='~'
-           for cmd1 in $cmds; do
-             IFS=$save_ifs
-             # Take the normal branch if the nm_file_list_spec branch
-             # doesn't work or if tool conversion is not needed.
-             case $nm_file_list_spec~$to_tool_file_cmd in
-               *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
-                 try_normal_branch=yes
-                 eval cmd=\"$cmd1\"
-                 func_len " $cmd"
-                 len=$func_len_result
-                 ;;
-               *)
-                 try_normal_branch=no
-                 ;;
-             esac
-             if test yes = "$try_normal_branch" \
-                && { test "$len" -lt "$max_cmd_len" \
-                     || test "$max_cmd_len" -le -1; }
-             then
-               func_show_eval "$cmd" 'exit $?'
-               skipped_export=false
-             elif test -n "$nm_file_list_spec"; then
-               func_basename "$output"
-               output_la=$func_basename_result
-               save_libobjs=$libobjs
-               save_output=$output
-               output=$output_objdir/$output_la.nm
-               func_to_tool_file "$output"
-               libobjs=$nm_file_list_spec$func_to_tool_file_result
-               func_append delfiles " $output"
-               func_verbose "creating $NM input file list: $output"
-               for obj in $save_libobjs; do
-                 func_to_tool_file "$obj"
-                 $ECHO "$func_to_tool_file_result"
-               done > "$output"
-               eval cmd=\"$cmd1\"
-               func_show_eval "$cmd" 'exit $?'
-               output=$save_output
-               libobjs=$save_libobjs
-               skipped_export=false
-             else
-               # The command line is too long to execute in one step.
-               func_verbose "using reloadable object file for export list..."
-               skipped_export=:
-               # Break out early, otherwise skipped_export may be
-               # set to false by a later but shorter cmd.
-               break
-             fi
-           done
-           IFS=$save_ifs
-           if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
-             func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
-             func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
-           fi
-         fi
-       fi
-
-       if test -n "$export_symbols" && test -n "$include_expsyms"; then
-         tmp_export_symbols=$export_symbols
-         test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
-         $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
-       fi
-
-       if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
-         # The given exports_symbols file has to be filtered, so filter it.
-         func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
-         # FIXME: $output_objdir/$libname.filter potentially contains lots of
-         # 's' commands, which not all seds can handle. GNU sed should be fine
-         # though. Also, the filter scales superlinearly with the number of
-         # global variables. join(1) would be nice here, but unfortunately
-         # isn't a blessed tool.
-         $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
-         func_append delfiles " $export_symbols $output_objdir/$libname.filter"
-         export_symbols=$output_objdir/$libname.def
-         $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
-       fi
-
-       tmp_deplibs=
-       for test_deplib in $deplibs; do
-         case " $convenience " in
-         *" $test_deplib "*) ;;
-         *)
-           func_append tmp_deplibs " $test_deplib"
-           ;;
-         esac
-       done
-       deplibs=$tmp_deplibs
-
-       if test -n "$convenience"; then
-         if test -n "$whole_archive_flag_spec" &&
-           test yes = "$compiler_needs_object" &&
-           test -z "$libobjs"; then
-           # extract the archives, so we have objects to list.
-           # TODO: could optimize this to just extract one archive.
-           whole_archive_flag_spec=
-         fi
-         if test -n "$whole_archive_flag_spec"; then
-           save_libobjs=$libobjs
-           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
-           test "X$libobjs" = "X " && libobjs=
-         else
-           gentop=$output_objdir/${outputname}x
-           func_append generated " $gentop"
-
-           func_extract_archives $gentop $convenience
-           func_append libobjs " $func_extract_archives_result"
-           test "X$libobjs" = "X " && libobjs=
-         fi
-       fi
-
-       if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
-         eval flag=\"$thread_safe_flag_spec\"
-         func_append linker_flags " $flag"
-       fi
-
-       # Make a backup of the uninstalled library when relinking
-       if test relink = "$opt_mode"; then
-         $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
-       fi
-
-       # Do each of the archive commands.
-       if test yes = "$module" && test -n "$module_cmds"; then
-         if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
-           eval test_cmds=\"$module_expsym_cmds\"
-           cmds=$module_expsym_cmds
-         else
-           eval test_cmds=\"$module_cmds\"
-           cmds=$module_cmds
-         fi
-       else
-         if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
-           eval test_cmds=\"$archive_expsym_cmds\"
-           cmds=$archive_expsym_cmds
-         else
-           eval test_cmds=\"$archive_cmds\"
-           cmds=$archive_cmds
-         fi
-       fi
-
-       if test : != "$skipped_export" &&
-          func_len " $test_cmds" &&
-          len=$func_len_result &&
-          test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
-         :
-       else
-         # The command line is too long to link in one step, link piecewise
-         # or, if using GNU ld and skipped_export is not :, use a linker
-         # script.
-
-         # Save the value of $output and $libobjs because we want to
-         # use them later.  If we have whole_archive_flag_spec, we
-         # want to use save_libobjs as it was before
-         # whole_archive_flag_spec was expanded, because we can't
-         # assume the linker understands whole_archive_flag_spec.
-         # This may have to be revisited, in case too many
-         # convenience libraries get linked in and end up exceeding
-         # the spec.
-         if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
-           save_libobjs=$libobjs
-         fi
-         save_output=$output
-         func_basename "$output"
-         output_la=$func_basename_result
-
-         # Clear the reloadable object creation command queue and
-         # initialize k to one.
-         test_cmds=
-         concat_cmds=
-         objlist=
-         last_robj=
-         k=1
-
-         if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
-           output=$output_objdir/$output_la.lnkscript
-           func_verbose "creating GNU ld script: $output"
-           echo 'INPUT (' > $output
-           for obj in $save_libobjs
-           do
-             func_to_tool_file "$obj"
-             $ECHO "$func_to_tool_file_result" >> $output
-           done
-           echo ')' >> $output
-           func_append delfiles " $output"
-           func_to_tool_file "$output"
-           output=$func_to_tool_file_result
-         elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
-           output=$output_objdir/$output_la.lnk
-           func_verbose "creating linker input file list: $output"
-           : > $output
-           set x $save_libobjs
-           shift
-           firstobj=
-           if test yes = "$compiler_needs_object"; then
-             firstobj="$1 "
-             shift
-           fi
-           for obj
-           do
-             func_to_tool_file "$obj"
-             $ECHO "$func_to_tool_file_result" >> $output
-           done
-           func_append delfiles " $output"
-           func_to_tool_file "$output"
-           output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
-         else
-           if test -n "$save_libobjs"; then
-             func_verbose "creating reloadable object files..."
-             output=$output_objdir/$output_la-$k.$objext
-             eval test_cmds=\"$reload_cmds\"
-             func_len " $test_cmds"
-             len0=$func_len_result
-             len=$len0
-
-             # Loop over the list of objects to be linked.
-             for obj in $save_libobjs
-             do
-               func_len " $obj"
-               func_arith $len + $func_len_result
-               len=$func_arith_result
-               if test -z "$objlist" ||
-                  test "$len" -lt "$max_cmd_len"; then
-                 func_append objlist " $obj"
-               else
-                 # The command $test_cmds is almost too long, add a
-                 # command to the queue.
-                 if test 1 -eq "$k"; then
-                   # The first file doesn't have a previous command to add.
-                   reload_objs=$objlist
-                   eval concat_cmds=\"$reload_cmds\"
-                 else
-                   # All subsequent reloadable object files will link in
-                   # the last one created.
-                   reload_objs="$objlist $last_robj"
-                   eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
-                 fi
-                 last_robj=$output_objdir/$output_la-$k.$objext
-                 func_arith $k + 1
-                 k=$func_arith_result
-                 output=$output_objdir/$output_la-$k.$objext
-                 objlist=" $obj"
-                 func_len " $last_robj"
-                 func_arith $len0 + $func_len_result
-                 len=$func_arith_result
-               fi
-             done
-             # Handle the remaining objects by creating one last
-             # reloadable object file.  All subsequent reloadable object
-             # files will link in the last one created.
-             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
-             reload_objs="$objlist $last_robj"
-             eval concat_cmds=\"\$concat_cmds$reload_cmds\"
-             if test -n "$last_robj"; then
-               eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
-             fi
-             func_append delfiles " $output"
-
-           else
-             output=
-           fi
-
-           ${skipped_export-false} && {
-             func_verbose "generating symbol list for '$libname.la'"
-             export_symbols=$output_objdir/$libname.exp
-             $opt_dry_run || $RM $export_symbols
-             libobjs=$output
-             # Append the command to create the export file.
-             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
-             eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
-             if test -n "$last_robj"; then
-               eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
-             fi
-           }
-
-           test -n "$save_libobjs" &&
-             func_verbose "creating a temporary reloadable object file: $output"
-
-           # Loop through the commands generated above and execute them.
-           save_ifs=$IFS; IFS='~'
-           for cmd in $concat_cmds; do
-             IFS=$save_ifs
-             $opt_quiet || {
-                 func_quote_for_expand "$cmd"
-                 eval "func_echo $func_quote_for_expand_result"
-             }
-             $opt_dry_run || eval "$cmd" || {
-               lt_exit=$?
-
-               # Restore the uninstalled library and exit
-               if test relink = "$opt_mode"; then
-                 ( cd "$output_objdir" && \
-                   $RM "${realname}T" && \
-                   $MV "${realname}U" "$realname" )
-               fi
-
-               exit $lt_exit
-             }
-           done
-           IFS=$save_ifs
-
-           if test -n "$export_symbols_regex" && ${skipped_export-false}; then
-             func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
-             func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
-           fi
-         fi
-
-          ${skipped_export-false} && {
-           if test -n "$export_symbols" && test -n "$include_expsyms"; then
-             tmp_export_symbols=$export_symbols
-             test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
-             $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
-           fi
-
-           if test -n "$orig_export_symbols"; then
-             # The given exports_symbols file has to be filtered, so filter it.
-             func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
-             # FIXME: $output_objdir/$libname.filter potentially contains lots of
-             # 's' commands, which not all seds can handle. GNU sed should be fine
-             # though. Also, the filter scales superlinearly with the number of
-             # global variables. join(1) would be nice here, but unfortunately
-             # isn't a blessed tool.
-             $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
-             func_append delfiles " $export_symbols $output_objdir/$libname.filter"
-             export_symbols=$output_objdir/$libname.def
-             $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
-           fi
-         }
-
-         libobjs=$output
-         # Restore the value of output.
-         output=$save_output
-
-         if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
-           eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
-           test "X$libobjs" = "X " && libobjs=
-         fi
-         # Expand the library linking commands again to reset the
-         # value of $libobjs for piecewise linking.
-
-         # Do each of the archive commands.
-         if test yes = "$module" && test -n "$module_cmds"; then
-           if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
-             cmds=$module_expsym_cmds
-           else
-             cmds=$module_cmds
-           fi
-         else
-           if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
-             cmds=$archive_expsym_cmds
-           else
-             cmds=$archive_cmds
-           fi
-         fi
-       fi
-
-       if test -n "$delfiles"; then
-         # Append the command to remove temporary files to $cmds.
-         eval cmds=\"\$cmds~\$RM $delfiles\"
-       fi
-
-       # Add any objects from preloaded convenience libraries
-       if test -n "$dlprefiles"; then
-         gentop=$output_objdir/${outputname}x
-         func_append generated " $gentop"
-
-         func_extract_archives $gentop $dlprefiles
-         func_append libobjs " $func_extract_archives_result"
-         test "X$libobjs" = "X " && libobjs=
-       fi
-
-       save_ifs=$IFS; IFS='~'
-       for cmd in $cmds; do
-         IFS=$sp$nl
-         eval cmd=\"$cmd\"
-         IFS=$save_ifs
-         $opt_quiet || {
-           func_quote_for_expand "$cmd"
-           eval "func_echo $func_quote_for_expand_result"
-         }
-         $opt_dry_run || eval "$cmd" || {
-           lt_exit=$?
-
-           # Restore the uninstalled library and exit
-           if test relink = "$opt_mode"; then
-             ( cd "$output_objdir" && \
-               $RM "${realname}T" && \
-               $MV "${realname}U" "$realname" )
-           fi
-
-           exit $lt_exit
-         }
-       done
-       IFS=$save_ifs
-
-       # Restore the uninstalled library and exit
-       if test relink = "$opt_mode"; then
-         $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
-
-         if test -n "$convenience"; then
-           if test -z "$whole_archive_flag_spec"; then
-             func_show_eval '${RM}r "$gentop"'
-           fi
-         fi
-
-         exit $EXIT_SUCCESS
-       fi
-
-       # Create links to the real library.
-       for linkname in $linknames; do
-         if test "$realname" != "$linkname"; then
-           func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
-         fi
-       done
-
-       # If -module or -export-dynamic was specified, set the dlname.
-       if test yes = "$module" || test yes = "$export_dynamic"; then
-         # On all known operating systems, these are identical.
-         dlname=$soname
-       fi
-      fi
-      ;;
-
-    obj)
-      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
-       func_warning "'-dlopen' is ignored for objects"
-      fi
-
-      case " $deplibs" in
-      *\ -l* | *\ -L*)
-       func_warning "'-l' and '-L' are ignored for objects" ;;
-      esac
-
-      test -n "$rpath" && \
-       func_warning "'-rpath' is ignored for objects"
-
-      test -n "$xrpath" && \
-       func_warning "'-R' is ignored for objects"
-
-      test -n "$vinfo" && \
-       func_warning "'-version-info' is ignored for objects"
-
-      test -n "$release" && \
-       func_warning "'-release' is ignored for objects"
-
-      case $output in
-      *.lo)
-       test -n "$objs$old_deplibs" && \
-         func_fatal_error "cannot build library object '$output' from non-libtool objects"
-
-       libobj=$output
-       func_lo2o "$libobj"
-       obj=$func_lo2o_result
-       ;;
-      *)
-       libobj=
-       obj=$output
-       ;;
-      esac
-
-      # Delete the old objects.
-      $opt_dry_run || $RM $obj $libobj
-
-      # Objects from convenience libraries.  This assumes
-      # single-version convenience libraries.  Whenever we create
-      # different ones for PIC/non-PIC, this we'll have to duplicate
-      # the extraction.
-      reload_conv_objs=
-      gentop=
-      # if reload_cmds runs $LD directly, get rid of -Wl from
-      # whole_archive_flag_spec and hope we can get by with turning comma
-      # into space.
-      case $reload_cmds in
-        *\$LD[\ \$]*) wl= ;;
-      esac
-      if test -n "$convenience"; then
-       if test -n "$whole_archive_flag_spec"; then
-         eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
-         test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
-         reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
-       else
-         gentop=$output_objdir/${obj}x
-         func_append generated " $gentop"
-
-         func_extract_archives $gentop $convenience
-         reload_conv_objs="$reload_objs $func_extract_archives_result"
-       fi
-      fi
-
-      # If we're not building shared, we need to use non_pic_objs
-      test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
-
-      # Create the old-style object.
-      reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
-
-      output=$obj
-      func_execute_cmds "$reload_cmds" 'exit $?'
-
-      # Exit if we aren't doing a library object file.
-      if test -z "$libobj"; then
-       if test -n "$gentop"; then
-         func_show_eval '${RM}r "$gentop"'
-       fi
-
-       exit $EXIT_SUCCESS
-      fi
-
-      test yes = "$build_libtool_libs" || {
-       if test -n "$gentop"; then
-         func_show_eval '${RM}r "$gentop"'
-       fi
-
-       # Create an invalid libtool object if no PIC, so that we don't
-       # accidentally link it into a program.
-       # $show "echo timestamp > $libobj"
-       # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
-       exit $EXIT_SUCCESS
-      }
-
-      if test -n "$pic_flag" || test default != "$pic_mode"; then
-       # Only do commands if we really have different PIC objects.
-       reload_objs="$libobjs $reload_conv_objs"
-       output=$libobj
-       func_execute_cmds "$reload_cmds" 'exit $?'
-      fi
-
-      if test -n "$gentop"; then
-       func_show_eval '${RM}r "$gentop"'
-      fi
-
-      exit $EXIT_SUCCESS
-      ;;
-
-    prog)
-      case $host in
-       *cygwin*) func_stripname '' '.exe' "$output"
-                 output=$func_stripname_result.exe;;
-      esac
-      test -n "$vinfo" && \
-       func_warning "'-version-info' is ignored for programs"
-
-      test -n "$release" && \
-       func_warning "'-release' is ignored for programs"
-
-      $preload \
-       && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
-       && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
-
-      case $host in
-      *-*-rhapsody* | *-*-darwin1.[012])
-       # On Rhapsody replace the C library is the System framework
-       compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
-       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
-       ;;
-      esac
-
-      case $host in
-      *-*-darwin*)
-       # Don't allow lazy linking, it breaks C++ global constructors
-       # But is supposedly fixed on 10.4 or later (yay!).
-       if test CXX = "$tagname"; then
-         case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
-           10.[0123])
-             func_append compile_command " $wl-bind_at_load"
-             func_append finalize_command " $wl-bind_at_load"
-           ;;
-         esac
-       fi
-       # Time to change all our "foo.ltframework" stuff back to "-framework foo"
-       compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
-       finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
-       ;;
-      esac
-
-
-      # move library search paths that coincide with paths to not yet
-      # installed libraries to the beginning of the library search list
-      new_libs=
-      for path in $notinst_path; do
-       case " $new_libs " in
-       *" -L$path/$objdir "*) ;;
-       *)
-         case " $compile_deplibs " in
-         *" -L$path/$objdir "*)
-           func_append new_libs " -L$path/$objdir" ;;
-         esac
-         ;;
-       esac
-      done
-      for deplib in $compile_deplibs; do
-       case $deplib in
-       -L*)
-         case " $new_libs " in
-         *" $deplib "*) ;;
-         *) func_append new_libs " $deplib" ;;
-         esac
-         ;;
-       *) func_append new_libs " $deplib" ;;
-       esac
-      done
-      compile_deplibs=$new_libs
-
-
-      func_append compile_command " $compile_deplibs"
-      func_append finalize_command " $finalize_deplibs"
-
-      if test -n "$rpath$xrpath"; then
-       # If the user specified any rpath flags, then add them.
-       for libdir in $rpath $xrpath; do
-         # This is the magic to use -rpath.
-         case "$finalize_rpath " in
-         *" $libdir "*) ;;
-         *) func_append finalize_rpath " $libdir" ;;
-         esac
-       done
-      fi
-
-      # Now hardcode the library paths
-      rpath=
-      hardcode_libdirs=
-      for libdir in $compile_rpath $finalize_rpath; do
-       if test -n "$hardcode_libdir_flag_spec"; then
-         if test -n "$hardcode_libdir_separator"; then
-           if test -z "$hardcode_libdirs"; then
-             hardcode_libdirs=$libdir
-           else
-             # Just accumulate the unique libdirs.
-             case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
-             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
-               ;;
-             *)
-               func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
-               ;;
-             esac
-           fi
-         else
-           eval flag=\"$hardcode_libdir_flag_spec\"
-           func_append rpath " $flag"
-         fi
-       elif test -n "$runpath_var"; then
-         case "$perm_rpath " in
-         *" $libdir "*) ;;
-         *) func_append perm_rpath " $libdir" ;;
-         esac
-       fi
-       case $host in
-       *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
-         testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
-         case :$dllsearchpath: in
-         *":$libdir:"*) ;;
-         ::) dllsearchpath=$libdir;;
-         *) func_append dllsearchpath ":$libdir";;
-         esac
-         case :$dllsearchpath: in
-         *":$testbindir:"*) ;;
-         ::) dllsearchpath=$testbindir;;
-         *) func_append dllsearchpath ":$testbindir";;
-         esac
-         ;;
-       esac
-      done
-      # Substitute the hardcoded libdirs into the rpath.
-      if test -n "$hardcode_libdir_separator" &&
-        test -n "$hardcode_libdirs"; then
-       libdir=$hardcode_libdirs
-       eval rpath=\" $hardcode_libdir_flag_spec\"
-      fi
-      compile_rpath=$rpath
-
-      rpath=
-      hardcode_libdirs=
-      for libdir in $finalize_rpath; do
-       if test -n "$hardcode_libdir_flag_spec"; then
-         if test -n "$hardcode_libdir_separator"; then
-           if test -z "$hardcode_libdirs"; then
-             hardcode_libdirs=$libdir
-           else
-             # Just accumulate the unique libdirs.
-             case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
-             *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
-               ;;
-             *)
-               func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
-               ;;
-             esac
-           fi
-         else
-           eval flag=\"$hardcode_libdir_flag_spec\"
-           func_append rpath " $flag"
-         fi
-       elif test -n "$runpath_var"; then
-         case "$finalize_perm_rpath " in
-         *" $libdir "*) ;;
-         *) func_append finalize_perm_rpath " $libdir" ;;
-         esac
-       fi
-      done
-      # Substitute the hardcoded libdirs into the rpath.
-      if test -n "$hardcode_libdir_separator" &&
-        test -n "$hardcode_libdirs"; then
-       libdir=$hardcode_libdirs
-       eval rpath=\" $hardcode_libdir_flag_spec\"
-      fi
-      finalize_rpath=$rpath
-
-      if test -n "$libobjs" && test yes = "$build_old_libs"; then
-       # Transform all the library objects into standard objects.
-       compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
-       finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
-      fi
-
-      func_generate_dlsyms "$outputname" "@PROGRAM@" false
-
-      # template prelinking step
-      if test -n "$prelink_cmds"; then
-       func_execute_cmds "$prelink_cmds" 'exit $?'
-      fi
-
-      wrappers_required=:
-      case $host in
-      *cegcc* | *mingw32ce*)
-        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
-        wrappers_required=false
-        ;;
-      *cygwin* | *mingw* )
-        test yes = "$build_libtool_libs" || wrappers_required=false
-        ;;
-      *)
-        if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
-          wrappers_required=false
-        fi
-        ;;
-      esac
-      $wrappers_required || {
-       # Replace the output file specification.
-       compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
-       link_command=$compile_command$compile_rpath
-
-       # We have no uninstalled library dependencies, so finalize right now.
-       exit_status=0
-       func_show_eval "$link_command" 'exit_status=$?'
-
-       if test -n "$postlink_cmds"; then
-         func_to_tool_file "$output"
-         postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
-         func_execute_cmds "$postlink_cmds" 'exit $?'
-       fi
-
-       # Delete the generated files.
-       if test -f "$output_objdir/${outputname}S.$objext"; then
-         func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
-       fi
-
-       exit $exit_status
-      }
-
-      if test -n "$compile_shlibpath$finalize_shlibpath"; then
-       compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
-      fi
-      if test -n "$finalize_shlibpath"; then
-       finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
-      fi
-
-      compile_var=
-      finalize_var=
-      if test -n "$runpath_var"; then
-       if test -n "$perm_rpath"; then
-         # We should set the runpath_var.
-         rpath=
-         for dir in $perm_rpath; do
-           func_append rpath "$dir:"
-         done
-         compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
-       fi
-       if test -n "$finalize_perm_rpath"; then
-         # We should set the runpath_var.
-         rpath=
-         for dir in $finalize_perm_rpath; do
-           func_append rpath "$dir:"
-         done
-         finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
-       fi
-      fi
-
-      if test yes = "$no_install"; then
-       # We don't need to create a wrapper script.
-       link_command=$compile_var$compile_command$compile_rpath
-       # Replace the output file specification.
-       link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
-       # Delete the old output file.
-       $opt_dry_run || $RM $output
-       # Link the executable and exit
-       func_show_eval "$link_command" 'exit $?'
-
-       if test -n "$postlink_cmds"; then
-         func_to_tool_file "$output"
-         postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
-         func_execute_cmds "$postlink_cmds" 'exit $?'
-       fi
-
-       exit $EXIT_SUCCESS
-      fi
-
-      case $hardcode_action,$fast_install in
-        relink,*)
-         # Fast installation is not supported
-         link_command=$compile_var$compile_command$compile_rpath
-         relink_command=$finalize_var$finalize_command$finalize_rpath
-
-         func_warning "this platform does not like uninstalled shared libraries"
-         func_warning "'$output' will be relinked during installation"
-         ;;
-        *,yes)
-         link_command=$finalize_var$compile_command$finalize_rpath
-         relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
-          ;;
-       *,no)
-         link_command=$compile_var$compile_command$compile_rpath
-         relink_command=$finalize_var$finalize_command$finalize_rpath
-          ;;
-       *,needless)
-         link_command=$finalize_var$compile_command$finalize_rpath
-         relink_command=
-          ;;
-      esac
-
-      # Replace the output file specification.
-      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
-
-      # Delete the old output files.
-      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
-
-      func_show_eval "$link_command" 'exit $?'
-
-      if test -n "$postlink_cmds"; then
-       func_to_tool_file "$output_objdir/$outputname"
-       postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
-       func_execute_cmds "$postlink_cmds" 'exit $?'
-      fi
-
-      # Now create the wrapper script.
-      func_verbose "creating $output"
-
-      # Quote the relink command for shipping.
-      if test -n "$relink_command"; then
-       # Preserve any variables that may affect compiler behavior
-       for var in $variables_saved_for_relink; do
-         if eval test -z \"\${$var+set}\"; then
-           relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
-         elif eval var_value=\$$var; test -z "$var_value"; then
-           relink_command="$var=; export $var; $relink_command"
-         else
-           func_quote_for_eval "$var_value"
-           relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
-         fi
-       done
-       relink_command="(cd `pwd`; $relink_command)"
-       relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
-      fi
-
-      # Only actually do things if not in dry run mode.
-      $opt_dry_run || {
-       # win32 will think the script is a binary if it has
-       # a .exe suffix, so we strip it off here.
-       case $output in
-         *.exe) func_stripname '' '.exe' "$output"
-                output=$func_stripname_result ;;
-       esac
-       # test for cygwin because mv fails w/o .exe extensions
-       case $host in
-         *cygwin*)
-           exeext=.exe
-           func_stripname '' '.exe' "$outputname"
-           outputname=$func_stripname_result ;;
-         *) exeext= ;;
-       esac
-       case $host in
-         *cygwin* | *mingw* )
-           func_dirname_and_basename "$output" "" "."
-           output_name=$func_basename_result
-           output_path=$func_dirname_result
-           cwrappersource=$output_path/$objdir/lt-$output_name.c
-           cwrapper=$output_path/$output_name.exe
-           $RM $cwrappersource $cwrapper
-           trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
-
-           func_emit_cwrapperexe_src > $cwrappersource
-
-           # The wrapper executable is built using the $host compiler,
-           # because it contains $host paths and files. If cross-
-           # compiling, it, like the target executable, must be
-           # executed on the $host or under an emulation environment.
-           $opt_dry_run || {
-             $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
-             $STRIP $cwrapper
-           }
-
-           # Now, create the wrapper script for func_source use:
-           func_ltwrapper_scriptname $cwrapper
-           $RM $func_ltwrapper_scriptname_result
-           trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
-           $opt_dry_run || {
-             # note: this script will not be executed, so do not chmod.
-             if test "x$build" = "x$host"; then
-               $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
-             else
-               func_emit_wrapper no > $func_ltwrapper_scriptname_result
-             fi
-           }
-         ;;
-         * )
-           $RM $output
-           trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
-
-           func_emit_wrapper no > $output
-           chmod +x $output
-         ;;
-       esac
-      }
-      exit $EXIT_SUCCESS
-      ;;
-    esac
-
-    # See if we need to build an old-fashioned archive.
-    for oldlib in $oldlibs; do
-
-      case $build_libtool_libs in
-        convenience)
-         oldobjs="$libobjs_save $symfileobj"
-         addlibs=$convenience
-         build_libtool_libs=no
-         ;;
-       module)
-         oldobjs=$libobjs_save
-         addlibs=$old_convenience
-         build_libtool_libs=no
-          ;;
-       *)
-         oldobjs="$old_deplibs $non_pic_objects"
-         $preload && test -f "$symfileobj" \
-           && func_append oldobjs " $symfileobj"
-         addlibs=$old_convenience
-         ;;
-      esac
-
-      if test -n "$addlibs"; then
-       gentop=$output_objdir/${outputname}x
-       func_append generated " $gentop"
-
-       func_extract_archives $gentop $addlibs
-       func_append oldobjs " $func_extract_archives_result"
-      fi
-
-      # Do each command in the archive commands.
-      if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
-       cmds=$old_archive_from_new_cmds
-      else
-
-       # Add any objects from preloaded convenience libraries
-       if test -n "$dlprefiles"; then
-         gentop=$output_objdir/${outputname}x
-         func_append generated " $gentop"
-
-         func_extract_archives $gentop $dlprefiles
-         func_append oldobjs " $func_extract_archives_result"
-       fi
-
-       # POSIX demands no paths to be encoded in archives.  We have
-       # to avoid creating archives with duplicate basenames if we
-       # might have to extract them afterwards, e.g., when creating a
-       # static archive out of a convenience library, or when linking
-       # the entirety of a libtool archive into another (currently
-       # not supported by libtool).
-       if (for obj in $oldobjs
-           do
-             func_basename "$obj"
-             $ECHO "$func_basename_result"
-           done | sort | sort -uc >/dev/null 2>&1); then
-         :
-       else
-         echo "copying selected object files to avoid basename conflicts..."
-         gentop=$output_objdir/${outputname}x
-         func_append generated " $gentop"
-         func_mkdir_p "$gentop"
-         save_oldobjs=$oldobjs
-         oldobjs=
-         counter=1
-         for obj in $save_oldobjs
-         do
-           func_basename "$obj"
-           objbase=$func_basename_result
-           case " $oldobjs " in
-           " ") oldobjs=$obj ;;
-           *[\ /]"$objbase "*)
-             while :; do
-               # Make sure we don't pick an alternate name that also
-               # overlaps.
-               newobj=lt$counter-$objbase
-               func_arith $counter + 1
-               counter=$func_arith_result
-               case " $oldobjs " in
-               *[\ /]"$newobj "*) ;;
-               *) if test ! -f "$gentop/$newobj"; then break; fi ;;
-               esac
-             done
-             func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
-             func_append oldobjs " $gentop/$newobj"
-             ;;
-           *) func_append oldobjs " $obj" ;;
-           esac
-         done
-       fi
-       func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
-       tool_oldlib=$func_to_tool_file_result
-       eval cmds=\"$old_archive_cmds\"
-
-       func_len " $cmds"
-       len=$func_len_result
-       if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
-         cmds=$old_archive_cmds
-       elif test -n "$archiver_list_spec"; then
-         func_verbose "using command file archive linking..."
-         for obj in $oldobjs
-         do
-           func_to_tool_file "$obj"
-           $ECHO "$func_to_tool_file_result"
-         done > $output_objdir/$libname.libcmd
-         func_to_tool_file "$output_objdir/$libname.libcmd"
-         oldobjs=" $archiver_list_spec$func_to_tool_file_result"
-         cmds=$old_archive_cmds
-       else
-         # the command line is too long to link in one step, link in parts
-         func_verbose "using piecewise archive linking..."
-         save_RANLIB=$RANLIB
-         RANLIB=:
-         objlist=
-         concat_cmds=
-         save_oldobjs=$oldobjs
-         oldobjs=
-         # Is there a better way of finding the last object in the list?
-         for obj in $save_oldobjs
-         do
-           last_oldobj=$obj
-         done
-         eval test_cmds=\"$old_archive_cmds\"
-         func_len " $test_cmds"
-         len0=$func_len_result
-         len=$len0
-         for obj in $save_oldobjs
-         do
-           func_len " $obj"
-           func_arith $len + $func_len_result
-           len=$func_arith_result
-           func_append objlist " $obj"
-           if test "$len" -lt "$max_cmd_len"; then
-             :
-           else
-             # the above command should be used before it gets too long
-             oldobjs=$objlist
-             if test "$obj" = "$last_oldobj"; then
-               RANLIB=$save_RANLIB
-             fi
-             test -z "$concat_cmds" || concat_cmds=$concat_cmds~
-             eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
-             objlist=
-             len=$len0
-           fi
-         done
-         RANLIB=$save_RANLIB
-         oldobjs=$objlist
-         if test -z "$oldobjs"; then
-           eval cmds=\"\$concat_cmds\"
-         else
-           eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
-         fi
-       fi
-      fi
-      func_execute_cmds "$cmds" 'exit $?'
-    done
-
-    test -n "$generated" && \
-      func_show_eval "${RM}r$generated"
-
-    # Now create the libtool archive.
-    case $output in
-    *.la)
-      old_library=
-      test yes = "$build_old_libs" && old_library=$libname.$libext
-      func_verbose "creating $output"
-
-      # Preserve any variables that may affect compiler behavior
-      for var in $variables_saved_for_relink; do
-       if eval test -z \"\${$var+set}\"; then
-         relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
-       elif eval var_value=\$$var; test -z "$var_value"; then
-         relink_command="$var=; export $var; $relink_command"
-       else
-         func_quote_for_eval "$var_value"
-         relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
-       fi
-      done
-      # Quote the link command for shipping.
-      relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
-      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
-      if test yes = "$hardcode_automatic"; then
-       relink_command=
-      fi
-
-      # Only create the output if not a dry run.
-      $opt_dry_run || {
-       for installed in no yes; do
-         if test yes = "$installed"; then
-           if test -z "$install_libdir"; then
-             break
-           fi
-           output=$output_objdir/${outputname}i
-           # Replace all uninstalled libtool libraries with the installed ones
-           newdependency_libs=
-           for deplib in $dependency_libs; do
-             case $deplib in
-             *.la)
-               func_basename "$deplib"
-               name=$func_basename_result
-               func_resolve_sysroot "$deplib"
-               eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
-               test -z "$libdir" && \
-                 func_fatal_error "'$deplib' is not a valid libtool archive"
-               func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
-               ;;
-             -L*)
-               func_stripname -L '' "$deplib"
-               func_replace_sysroot "$func_stripname_result"
-               func_append newdependency_libs " -L$func_replace_sysroot_result"
-               ;;
-             -R*)
-               func_stripname -R '' "$deplib"
-               func_replace_sysroot "$func_stripname_result"
-               func_append newdependency_libs " -R$func_replace_sysroot_result"
-               ;;
-             *) func_append newdependency_libs " $deplib" ;;
-             esac
-           done
-           dependency_libs=$newdependency_libs
-           newdlfiles=
-
-           for lib in $dlfiles; do
-             case $lib in
-             *.la)
-               func_basename "$lib"
-               name=$func_basename_result
-               eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
-               test -z "$libdir" && \
-                 func_fatal_error "'$lib' is not a valid libtool archive"
-               func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
-               ;;
-             *) func_append newdlfiles " $lib" ;;
-             esac
-           done
-           dlfiles=$newdlfiles
-           newdlprefiles=
-           for lib in $dlprefiles; do
-             case $lib in
-             *.la)
-               # Only pass preopened files to the pseudo-archive (for
-               # eventual linking with the app. that links it) if we
-               # didn't already link the preopened objects directly into
-               # the library:
-               func_basename "$lib"
-               name=$func_basename_result
-               eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
-               test -z "$libdir" && \
-                 func_fatal_error "'$lib' is not a valid libtool archive"
-               func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
-               ;;
-             esac
-           done
-           dlprefiles=$newdlprefiles
-         else
-           newdlfiles=
-           for lib in $dlfiles; do
-             case $lib in
-               [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
-               *) abs=`pwd`"/$lib" ;;
-             esac
-             func_append newdlfiles " $abs"
-           done
-           dlfiles=$newdlfiles
-           newdlprefiles=
-           for lib in $dlprefiles; do
-             case $lib in
-               [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
-               *) abs=`pwd`"/$lib" ;;
-             esac
-             func_append newdlprefiles " $abs"
-           done
-           dlprefiles=$newdlprefiles
-         fi
-         $RM $output
-         # place dlname in correct position for cygwin
-         # In fact, it would be nice if we could use this code for all target
-         # systems that can't hard-code library paths into their executables
-         # and that have no shared library path variable independent of PATH,
-         # but it turns out we can't easily determine that from inspecting
-         # libtool variables, so we have to hard-code the OSs to which it
-         # applies here; at the moment, that means platforms that use the PE
-         # object format with DLL files.  See the long comment at the top of
-         # tests/bindir.at for full details.
-         tdlname=$dlname
-         case $host,$output,$installed,$module,$dlname in
-           *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
-             # If a -bindir argument was supplied, place the dll there.
-             if test -n "$bindir"; then
-               func_relative_path "$install_libdir" "$bindir"
-               tdlname=$func_relative_path_result/$dlname
-             else
-               # Otherwise fall back on heuristic.
-               tdlname=../bin/$dlname
-             fi
-             ;;
-         esac
-         $ECHO > $output "\
-# $outputname - a libtool library file
-# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# The name that we can dlopen(3).
-dlname='$tdlname'
-
-# Names of this library.
-library_names='$library_names'
-
-# The name of the static archive.
-old_library='$old_library'
-
-# Linker flags that cannot go in dependency_libs.
-inherited_linker_flags='$new_inherited_linker_flags'
-
-# Libraries that this one depends upon.
-dependency_libs='$dependency_libs'
-
-# Names of additional weak libraries provided by this library
-weak_library_names='$weak_libs'
-
-# Version information for $libname.
-current=$current
-age=$age
-revision=$revision
-
-# Is this an already installed library?
-installed=$installed
-
-# Should we warn about portability when linking against -modules?
-shouldnotlink=$module
-
-# Files to dlopen/dlpreopen
-dlopen='$dlfiles'
-dlpreopen='$dlprefiles'
-
-# Directory that this library needs to be installed in:
-libdir='$install_libdir'"
-         if test no,yes = "$installed,$need_relink"; then
-           $ECHO >> $output "\
-relink_command=\"$relink_command\""
-         fi
-       done
-      }
-
-      # Do a symbolic link so that the libtool archive can be found in
-      # LD_LIBRARY_PATH before the program is installed.
-      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
-      ;;
-    esac
-    exit $EXIT_SUCCESS
-}
-
-if test link = "$opt_mode" || test relink = "$opt_mode"; then
-  func_mode_link ${1+"$@"}
-fi
-
-
-# func_mode_uninstall arg...
-func_mode_uninstall ()
-{
-    $debug_cmd
-
-    RM=$nonopt
-    files=
-    rmforce=false
-    exit_status=0
-
-    # This variable tells wrapper scripts just to set variables rather
-    # than running their programs.
-    libtool_install_magic=$magic
-
-    for arg
-    do
-      case $arg in
-      -f) func_append RM " $arg"; rmforce=: ;;
-      -*) func_append RM " $arg" ;;
-      *) func_append files " $arg" ;;
-      esac
-    done
-
-    test -z "$RM" && \
-      func_fatal_help "you must specify an RM program"
-
-    rmdirs=
-
-    for file in $files; do
-      func_dirname "$file" "" "."
-      dir=$func_dirname_result
-      if test . = "$dir"; then
-       odir=$objdir
-      else
-       odir=$dir/$objdir
-      fi
-      func_basename "$file"
-      name=$func_basename_result
-      test uninstall = "$opt_mode" && odir=$dir
-
-      # Remember odir for removal later, being careful to avoid duplicates
-      if test clean = "$opt_mode"; then
-       case " $rmdirs " in
-         *" $odir "*) ;;
-         *) func_append rmdirs " $odir" ;;
-       esac
-      fi
-
-      # Don't error if the file doesn't exist and rm -f was used.
-      if { test -L "$file"; } >/dev/null 2>&1 ||
-        { test -h "$file"; } >/dev/null 2>&1 ||
-        test -f "$file"; then
-       :
-      elif test -d "$file"; then
-       exit_status=1
-       continue
-      elif $rmforce; then
-       continue
-      fi
-
-      rmfiles=$file
-
-      case $name in
-      *.la)
-       # Possibly a libtool archive, so verify it.
-       if func_lalib_p "$file"; then
-         func_source $dir/$name
-
-         # Delete the libtool libraries and symlinks.
-         for n in $library_names; do
-           func_append rmfiles " $odir/$n"
-         done
-         test -n "$old_library" && func_append rmfiles " $odir/$old_library"
-
-         case $opt_mode in
-         clean)
-           case " $library_names " in
-           *" $dlname "*) ;;
-           *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
-           esac
-           test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
-           ;;
-         uninstall)
-           if test -n "$library_names"; then
-             # Do each command in the postuninstall commands.
-             func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
-           fi
-
-           if test -n "$old_library"; then
-             # Do each command in the old_postuninstall commands.
-             func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
-           fi
-           # FIXME: should reinstall the best remaining shared library.
-           ;;
-         esac
-       fi
-       ;;
-
-      *.lo)
-       # Possibly a libtool object, so verify it.
-       if func_lalib_p "$file"; then
-
-         # Read the .lo file
-         func_source $dir/$name
-
-         # Add PIC object to the list of files to remove.
-         if test -n "$pic_object" && test none != "$pic_object"; then
-           func_append rmfiles " $dir/$pic_object"
-         fi
-
-         # Add non-PIC object to the list of files to remove.
-         if test -n "$non_pic_object" && test none != "$non_pic_object"; then
-           func_append rmfiles " $dir/$non_pic_object"
-         fi
-       fi
-       ;;
-
-      *)
-       if test clean = "$opt_mode"; then
-         noexename=$name
-         case $file in
-         *.exe)
-           func_stripname '' '.exe' "$file"
-           file=$func_stripname_result
-           func_stripname '' '.exe' "$name"
-           noexename=$func_stripname_result
-           # $file with .exe has already been added to rmfiles,
-           # add $file without .exe
-           func_append rmfiles " $file"
-           ;;
-         esac
-         # Do a test to see if this is a libtool program.
-         if func_ltwrapper_p "$file"; then
-           if func_ltwrapper_executable_p "$file"; then
-             func_ltwrapper_scriptname "$file"
-             relink_command=
-             func_source $func_ltwrapper_scriptname_result
-             func_append rmfiles " $func_ltwrapper_scriptname_result"
-           else
-             relink_command=
-             func_source $dir/$noexename
-           fi
-
-           # note $name still contains .exe if it was in $file originally
-           # as does the version of $file that was added into $rmfiles
-           func_append rmfiles " $odir/$name $odir/${name}S.$objext"
-           if test yes = "$fast_install" && test -n "$relink_command"; then
-             func_append rmfiles " $odir/lt-$name"
-           fi
-           if test "X$noexename" != "X$name"; then
-             func_append rmfiles " $odir/lt-$noexename.c"
-           fi
-         fi
-       fi
-       ;;
-      esac
-      func_show_eval "$RM $rmfiles" 'exit_status=1'
-    done
-
-    # Try to remove the $objdir's in the directories where we deleted files
-    for dir in $rmdirs; do
-      if test -d "$dir"; then
-       func_show_eval "rmdir $dir >/dev/null 2>&1"
-      fi
-    done
-
-    exit $exit_status
-}
-
-if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
-  func_mode_uninstall ${1+"$@"}
-fi
-
-test -z "$opt_mode" && {
-  help=$generic_help
-  func_fatal_help "you must specify a MODE"
-}
-
-test -z "$exec_cmd" && \
-  func_fatal_help "invalid operation mode '$opt_mode'"
-
-if test -n "$exec_cmd"; then
-  eval exec "$exec_cmd"
-  exit $EXIT_FAILURE
-fi
-
-exit $exit_status
-
-
-# The TAGs below are defined such that we never get into a situation
-# where we disable both kinds of libraries.  Given conflicting
-# choices, we go for a static library, that is the most portable,
-# since we can't tell whether shared libraries were disabled because
-# the user asked for that or because the platform doesn't support
-# them.  This is particularly important on AIX, because we don't
-# support having both static and shared libraries enabled at the same
-# time on that platform, so we default to a shared-only configuration.
-# If a disable-shared tag is given, we'll fallback to a static-only
-# configuration.  But we'll never go from static-only to shared-only.
-
-# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
-build_libtool_libs=no
-build_old_libs=yes
-# ### END LIBTOOL TAG CONFIG: disable-shared
-
-# ### BEGIN LIBTOOL TAG CONFIG: disable-static
-build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
-# ### END LIBTOOL TAG CONFIG: disable-static
-
-# Local Variables:
-# mode:shell-script
-# sh-indentation:2
-# End:
diff --git a/zfs/config/ltoptions.m4 b/zfs/config/ltoptions.m4
deleted file mode 100644 (file)
index 94b0829..0000000
+++ /dev/null
@@ -1,437 +0,0 @@
-# Helper functions for option handling.                    -*- Autoconf -*-
-#
-#   Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
-#   Foundation, Inc.
-#   Written by Gary V. Vaughan, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 8 ltoptions.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
-
-
-# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
-# ------------------------------------------
-m4_define([_LT_MANGLE_OPTION],
-[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
-
-
-# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
-# ---------------------------------------
-# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
-# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
-# saved as a flag.
-m4_define([_LT_SET_OPTION],
-[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
-m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
-        _LT_MANGLE_DEFUN([$1], [$2]),
-    [m4_warning([Unknown $1 option '$2'])])[]dnl
-])
-
-
-# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
-# ------------------------------------------------------------
-# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
-m4_define([_LT_IF_OPTION],
-[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
-
-
-# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
-# -------------------------------------------------------
-# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
-# are set.
-m4_define([_LT_UNLESS_OPTIONS],
-[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
-           [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
-                     [m4_define([$0_found])])])[]dnl
-m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
-])[]dnl
-])
-
-
-# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
-# ----------------------------------------
-# OPTION-LIST is a space-separated list of Libtool options associated
-# with MACRO-NAME.  If any OPTION has a matching handler declared with
-# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
-# the unknown option and exit.
-m4_defun([_LT_SET_OPTIONS],
-[# Set options
-m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
-    [_LT_SET_OPTION([$1], _LT_Option)])
-
-m4_if([$1],[LT_INIT],[
-  dnl
-  dnl Simply set some default values (i.e off) if boolean options were not
-  dnl specified:
-  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
-  ])
-  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
-  ])
-  dnl
-  dnl If no reference was made to various pairs of opposing options, then
-  dnl we run the default mode handler for the pair.  For example, if neither
-  dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
-  dnl archives by default:
-  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
-  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
-  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
-  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
-                  [_LT_ENABLE_FAST_INSTALL])
-  _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
-                  [_LT_WITH_AIX_SONAME([aix])])
-  ])
-])# _LT_SET_OPTIONS
-
-
-## --------------------------------- ##
-## Macros to handle LT_INIT options. ##
-## --------------------------------- ##
-
-# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
-# -----------------------------------------
-m4_define([_LT_MANGLE_DEFUN],
-[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
-
-
-# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
-# -----------------------------------------------
-m4_define([LT_OPTION_DEFINE],
-[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
-])# LT_OPTION_DEFINE
-
-
-# dlopen
-# ------
-LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
-])
-
-AU_DEFUN([AC_LIBTOOL_DLOPEN],
-[_LT_SET_OPTION([LT_INIT], [dlopen])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the 'dlopen' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
-
-
-# win32-dll
-# ---------
-# Declare package support for building win32 dll's.
-LT_OPTION_DEFINE([LT_INIT], [win32-dll],
-[enable_win32_dll=yes
-
-case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
-  AC_CHECK_TOOL(AS, as, false)
-  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-  AC_CHECK_TOOL(OBJDUMP, objdump, false)
-  ;;
-esac
-
-test -z "$AS" && AS=as
-_LT_DECL([], [AS],      [1], [Assembler program])dnl
-
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
-
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
-])# win32-dll
-
-AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-_LT_SET_OPTION([LT_INIT], [win32-dll])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the 'win32-dll' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
-
-
-# _LT_ENABLE_SHARED([DEFAULT])
-# ----------------------------
-# implement the --enable-shared flag, and supports the 'shared' and
-# 'disable-shared' LT_INIT options.
-# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
-m4_define([_LT_ENABLE_SHARED],
-[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([shared],
-    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
-       [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_shared=yes ;;
-    no) enable_shared=no ;;
-    *)
-      enable_shared=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for pkg in $enableval; do
-       IFS=$lt_save_ifs
-       if test "X$pkg" = "X$p"; then
-         enable_shared=yes
-       fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac],
-    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
-
-    _LT_DECL([build_libtool_libs], [enable_shared], [0],
-       [Whether or not to build shared libraries])
-])# _LT_ENABLE_SHARED
-
-LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
-])
-
-AC_DEFUN([AC_DISABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], [disable-shared])
-])
-
-AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
-AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_SHARED], [])
-dnl AC_DEFUN([AM_DISABLE_SHARED], [])
-
-
-
-# _LT_ENABLE_STATIC([DEFAULT])
-# ----------------------------
-# implement the --enable-static flag, and support the 'static' and
-# 'disable-static' LT_INIT options.
-# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
-m4_define([_LT_ENABLE_STATIC],
-[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([static],
-    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
-       [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_static=yes ;;
-    no) enable_static=no ;;
-    *)
-     enable_static=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for pkg in $enableval; do
-       IFS=$lt_save_ifs
-       if test "X$pkg" = "X$p"; then
-         enable_static=yes
-       fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac],
-    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
-
-    _LT_DECL([build_old_libs], [enable_static], [0],
-       [Whether or not to build static libraries])
-])# _LT_ENABLE_STATIC
-
-LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
-])
-
-AC_DEFUN([AC_DISABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], [disable-static])
-])
-
-AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
-AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_STATIC], [])
-dnl AC_DEFUN([AM_DISABLE_STATIC], [])
-
-
-
-# _LT_ENABLE_FAST_INSTALL([DEFAULT])
-# ----------------------------------
-# implement the --enable-fast-install flag, and support the 'fast-install'
-# and 'disable-fast-install' LT_INIT options.
-# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
-m4_define([_LT_ENABLE_FAST_INSTALL],
-[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([fast-install],
-    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
-    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
-    [p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_fast_install=yes ;;
-    no) enable_fast_install=no ;;
-    *)
-      enable_fast_install=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for pkg in $enableval; do
-       IFS=$lt_save_ifs
-       if test "X$pkg" = "X$p"; then
-         enable_fast_install=yes
-       fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac],
-    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
-
-_LT_DECL([fast_install], [enable_fast_install], [0],
-        [Whether or not to optimize for fast installation])dnl
-])# _LT_ENABLE_FAST_INSTALL
-
-LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
-
-# Old names:
-AU_DEFUN([AC_ENABLE_FAST_INSTALL],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the 'fast-install' option into LT_INIT's first parameter.])
-])
-
-AU_DEFUN([AC_DISABLE_FAST_INSTALL],
-[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the 'disable-fast-install' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
-dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
-
-
-# _LT_WITH_AIX_SONAME([DEFAULT])
-# ----------------------------------
-# implement the --with-aix-soname flag, and support the `aix-soname=aix'
-# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
-# is either `aix', `both' or `svr4'.  If omitted, it defaults to `aix'.
-m4_define([_LT_WITH_AIX_SONAME],
-[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
-shared_archive_member_spec=
-case $host,$enable_shared in
-power*-*-aix[[5-9]]*,yes)
-  AC_MSG_CHECKING([which variant of shared library versioning to provide])
-  AC_ARG_WITH([aix-soname],
-    [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
-      [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
-    [case $withval in
-    aix|svr4|both)
-      ;;
-    *)
-      AC_MSG_ERROR([Unknown argument to --with-aix-soname])
-      ;;
-    esac
-    lt_cv_with_aix_soname=$with_aix_soname],
-    [AC_CACHE_VAL([lt_cv_with_aix_soname],
-      [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
-    with_aix_soname=$lt_cv_with_aix_soname])
-  AC_MSG_RESULT([$with_aix_soname])
-  if test aix != "$with_aix_soname"; then
-    # For the AIX way of multilib, we name the shared archive member
-    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
-    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
-    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
-    # the AIX toolchain works better with OBJECT_MODE set (default 32).
-    if test 64 = "${OBJECT_MODE-32}"; then
-      shared_archive_member_spec=shr_64
-    else
-      shared_archive_member_spec=shr
-    fi
-  fi
-  ;;
-*)
-  with_aix_soname=aix
-  ;;
-esac
-
-_LT_DECL([], [shared_archive_member_spec], [0],
-    [Shared archive member basename, for filename based shared library versioning on AIX])dnl
-])# _LT_WITH_AIX_SONAME
-
-LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
-LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
-LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
-
-
-# _LT_WITH_PIC([MODE])
-# --------------------
-# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
-# LT_INIT options.
-# MODE is either 'yes' or 'no'.  If omitted, it defaults to 'both'.
-m4_define([_LT_WITH_PIC],
-[AC_ARG_WITH([pic],
-    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
-       [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
-    [lt_p=${PACKAGE-default}
-    case $withval in
-    yes|no) pic_mode=$withval ;;
-    *)
-      pic_mode=default
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for lt_pkg in $withval; do
-       IFS=$lt_save_ifs
-       if test "X$lt_pkg" = "X$lt_p"; then
-         pic_mode=yes
-       fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac],
-    [pic_mode=m4_default([$1], [default])])
-
-_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
-])# _LT_WITH_PIC
-
-LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
-
-# Old name:
-AU_DEFUN([AC_LIBTOOL_PICMODE],
-[_LT_SET_OPTION([LT_INIT], [pic-only])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the 'pic-only' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
-
-## ----------------- ##
-## LTDL_INIT Options ##
-## ----------------- ##
-
-m4_define([_LTDL_MODE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
-                [m4_define([_LTDL_MODE], [nonrecursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [recursive],
-                [m4_define([_LTDL_MODE], [recursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [subproject],
-                [m4_define([_LTDL_MODE], [subproject])])
-
-m4_define([_LTDL_TYPE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [installable],
-                [m4_define([_LTDL_TYPE], [installable])])
-LT_OPTION_DEFINE([LTDL_INIT], [convenience],
-                [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/zfs/config/ltsugar.m4 b/zfs/config/ltsugar.m4
deleted file mode 100644 (file)
index 48bc934..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
-#
-# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
-# Foundation, Inc.
-# Written by Gary V. Vaughan, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 6 ltsugar.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
-
-
-# lt_join(SEP, ARG1, [ARG2...])
-# -----------------------------
-# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
-# associated separator.
-# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
-# versions in m4sugar had bugs.
-m4_define([lt_join],
-[m4_if([$#], [1], [],
-       [$#], [2], [[$2]],
-       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
-m4_define([_lt_join],
-[m4_if([$#$2], [2], [],
-       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
-
-
-# lt_car(LIST)
-# lt_cdr(LIST)
-# ------------
-# Manipulate m4 lists.
-# These macros are necessary as long as will still need to support
-# Autoconf-2.59, which quotes differently.
-m4_define([lt_car], [[$1]])
-m4_define([lt_cdr],
-[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
-       [$#], 1, [],
-       [m4_dquote(m4_shift($@))])])
-m4_define([lt_unquote], $1)
-
-
-# lt_append(MACRO-NAME, STRING, [SEPARATOR])
-# ------------------------------------------
-# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
-# Note that neither SEPARATOR nor STRING are expanded; they are appended
-# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
-# No SEPARATOR is output if MACRO-NAME was previously undefined (different
-# than defined and empty).
-#
-# This macro is needed until we can rely on Autoconf 2.62, since earlier
-# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
-m4_define([lt_append],
-[m4_define([$1],
-          m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
-
-
-
-# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
-# ----------------------------------------------------------
-# Produce a SEP delimited list of all paired combinations of elements of
-# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
-# has the form PREFIXmINFIXSUFFIXn.
-# Needed until we can rely on m4_combine added in Autoconf 2.62.
-m4_define([lt_combine],
-[m4_if(m4_eval([$# > 3]), [1],
-       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
-[[m4_foreach([_Lt_prefix], [$2],
-            [m4_foreach([_Lt_suffix],
-               ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
-       [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
-
-
-# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
-# -----------------------------------------------------------------------
-# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
-# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
-m4_define([lt_if_append_uniq],
-[m4_ifdef([$1],
-         [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
-                [lt_append([$1], [$2], [$3])$4],
-                [$5])],
-         [lt_append([$1], [$2], [$3])$4])])
-
-
-# lt_dict_add(DICT, KEY, VALUE)
-# -----------------------------
-m4_define([lt_dict_add],
-[m4_define([$1($2)], [$3])])
-
-
-# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
-# --------------------------------------------
-m4_define([lt_dict_add_subkey],
-[m4_define([$1($2:$3)], [$4])])
-
-
-# lt_dict_fetch(DICT, KEY, [SUBKEY])
-# ----------------------------------
-m4_define([lt_dict_fetch],
-[m4_ifval([$3],
-       m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
-    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
-
-
-# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
-# -----------------------------------------------------------------
-m4_define([lt_if_dict_fetch],
-[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
-       [$5],
-    [$6])])
-
-
-# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
-# --------------------------------------------------------------
-m4_define([lt_dict_filter],
-[m4_if([$5], [], [],
-  [lt_join(m4_quote(m4_default([$4], [[, ]])),
-           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
-                     [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
-])
diff --git a/zfs/config/ltversion.m4 b/zfs/config/ltversion.m4
deleted file mode 100644 (file)
index fa04b52..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-# ltversion.m4 -- version numbers                      -*- Autoconf -*-
-#
-#   Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
-#   Written by Scott James Remnant, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# @configure_input@
-
-# serial 4179 ltversion.m4
-# This file is part of GNU Libtool
-
-m4_define([LT_PACKAGE_VERSION], [2.4.6])
-m4_define([LT_PACKAGE_REVISION], [2.4.6])
-
-AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.6'
-macro_revision='2.4.6'
-_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
-_LT_DECL(, macro_revision, 0)
-])
diff --git a/zfs/config/lt~obsolete.m4 b/zfs/config/lt~obsolete.m4
deleted file mode 100644 (file)
index c6b26f8..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
-#
-#   Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
-#   Foundation, Inc.
-#   Written by Scott James Remnant, 2004.
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 5 lt~obsolete.m4
-
-# These exist entirely to fool aclocal when bootstrapping libtool.
-#
-# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
-# which have later been changed to m4_define as they aren't part of the
-# exported API, or moved to Autoconf or Automake where they belong.
-#
-# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
-# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
-# using a macro with the same name in our local m4/libtool.m4 it'll
-# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
-# and doesn't know about Autoconf macros at all.)
-#
-# So we provide this file, which has a silly filename so it's always
-# included after everything else.  This provides aclocal with the
-# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
-# because those macros already exist, or will be overwritten later.
-# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
-#
-# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
-# Yes, that means every name once taken will need to remain here until
-# we give up compatibility with versions before 1.7, at which point
-# we need to keep only those names which we still refer to.
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
-
-m4_ifndef([AC_LIBTOOL_LINKER_OPTION],  [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
-m4_ifndef([AC_PROG_EGREP],             [AC_DEFUN([AC_PROG_EGREP])])
-m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],        [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_AC_SHELL_INIT],         [AC_DEFUN([_LT_AC_SHELL_INIT])])
-m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],    [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
-m4_ifndef([_LT_PROG_LTMAIN],           [AC_DEFUN([_LT_PROG_LTMAIN])])
-m4_ifndef([_LT_AC_TAGVAR],             [AC_DEFUN([_LT_AC_TAGVAR])])
-m4_ifndef([AC_LTDL_ENABLE_INSTALL],    [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
-m4_ifndef([AC_LTDL_PREOPEN],           [AC_DEFUN([AC_LTDL_PREOPEN])])
-m4_ifndef([_LT_AC_SYS_COMPILER],       [AC_DEFUN([_LT_AC_SYS_COMPILER])])
-m4_ifndef([_LT_AC_LOCK],               [AC_DEFUN([_LT_AC_LOCK])])
-m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],        [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
-m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],    [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
-m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],    [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
-m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
-m4_ifndef([AC_LIBTOOL_OBJDIR],         [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
-m4_ifndef([AC_LTDL_OBJDIR],            [AC_DEFUN([AC_LTDL_OBJDIR])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
-m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],  [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
-m4_ifndef([AC_PATH_MAGIC],             [AC_DEFUN([AC_PATH_MAGIC])])
-m4_ifndef([AC_PROG_LD_GNU],            [AC_DEFUN([AC_PROG_LD_GNU])])
-m4_ifndef([AC_PROG_LD_RELOAD_FLAG],    [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
-m4_ifndef([AC_DEPLIBS_CHECK_METHOD],   [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
-m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
-m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
-m4_ifndef([LT_AC_PROG_EGREP],          [AC_DEFUN([LT_AC_PROG_EGREP])])
-m4_ifndef([LT_AC_PROG_SED],            [AC_DEFUN([LT_AC_PROG_SED])])
-m4_ifndef([_LT_CC_BASENAME],           [AC_DEFUN([_LT_CC_BASENAME])])
-m4_ifndef([_LT_COMPILER_BOILERPLATE],  [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
-m4_ifndef([_LT_LINKER_BOILERPLATE],    [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
-m4_ifndef([_AC_PROG_LIBTOOL],          [AC_DEFUN([_AC_PROG_LIBTOOL])])
-m4_ifndef([AC_LIBTOOL_SETUP],          [AC_DEFUN([AC_LIBTOOL_SETUP])])
-m4_ifndef([_LT_AC_CHECK_DLFCN],                [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
-m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],     [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
-m4_ifndef([_LT_AC_TAGCONFIG],          [AC_DEFUN([_LT_AC_TAGCONFIG])])
-m4_ifndef([AC_DISABLE_FAST_INSTALL],   [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
-m4_ifndef([_LT_AC_LANG_CXX],           [AC_DEFUN([_LT_AC_LANG_CXX])])
-m4_ifndef([_LT_AC_LANG_F77],           [AC_DEFUN([_LT_AC_LANG_F77])])
-m4_ifndef([_LT_AC_LANG_GCJ],           [AC_DEFUN([_LT_AC_LANG_GCJ])])
-m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],  [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
-m4_ifndef([_LT_AC_LANG_C_CONFIG],      [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
-m4_ifndef([_LT_AC_LANG_CXX_CONFIG],    [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
-m4_ifndef([_LT_AC_LANG_F77_CONFIG],    [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
-m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],    [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
-m4_ifndef([_LT_AC_LANG_RC_CONFIG],     [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
-m4_ifndef([AC_LIBTOOL_CONFIG],         [AC_DEFUN([AC_LIBTOOL_CONFIG])])
-m4_ifndef([_LT_AC_FILE_LTDLL_C],       [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
-m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],        [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
-m4_ifndef([_LT_AC_PROG_CXXCPP],                [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
-m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],        [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
-m4_ifndef([_LT_PROG_ECHO_BACKSLASH],   [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_PROG_F77],              [AC_DEFUN([_LT_PROG_F77])])
-m4_ifndef([_LT_PROG_FC],               [AC_DEFUN([_LT_PROG_FC])])
-m4_ifndef([_LT_PROG_CXX],              [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/zfs/config/missing b/zfs/config/missing
deleted file mode 100755 (executable)
index f62bbae..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-#! /bin/sh
-# Common wrapper for a few potentially missing GNU programs.
-
-scriptversion=2013-10-28.13; # UTC
-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
-# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-if test $# -eq 0; then
-  echo 1>&2 "Try '$0 --help' for more information"
-  exit 1
-fi
-
-case $1 in
-
-  --is-lightweight)
-    # Used by our autoconf macros to check whether the available missing
-    # script is modern enough.
-    exit 0
-    ;;
-
-  --run)
-    # Back-compat with the calling convention used by older automake.
-    shift
-    ;;
-
-  -h|--h|--he|--hel|--help)
-    echo "\
-$0 [OPTION]... PROGRAM [ARGUMENT]...
-
-Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
-to PROGRAM being missing or too old.
-
-Options:
-  -h, --help      display this help and exit
-  -v, --version   output version information and exit
-
-Supported PROGRAM values:
-  aclocal   autoconf  autoheader   autom4te  automake  makeinfo
-  bison     yacc      flex         lex       help2man
-
-Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
-'g' are ignored when checking the name.
-
-Send bug reports to <bug-automake@gnu.org>."
-    exit $?
-    ;;
-
-  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
-    echo "missing $scriptversion (GNU Automake)"
-    exit $?
-    ;;
-
-  -*)
-    echo 1>&2 "$0: unknown '$1' option"
-    echo 1>&2 "Try '$0 --help' for more information"
-    exit 1
-    ;;
-
-esac
-
-# Run the given program, remember its exit status.
-"$@"; st=$?
-
-# If it succeeded, we are done.
-test $st -eq 0 && exit 0
-
-# Also exit now if we it failed (or wasn't found), and '--version' was
-# passed; such an option is passed most likely to detect whether the
-# program is present and works.
-case $2 in --version|--help) exit $st;; esac
-
-# Exit code 63 means version mismatch.  This often happens when the user
-# tries to use an ancient version of a tool on a file that requires a
-# minimum version.
-if test $st -eq 63; then
-  msg="probably too old"
-elif test $st -eq 127; then
-  # Program was missing.
-  msg="missing on your system"
-else
-  # Program was found and executed, but failed.  Give up.
-  exit $st
-fi
-
-perl_URL=http://www.perl.org/
-flex_URL=http://flex.sourceforge.net/
-gnu_software_URL=http://www.gnu.org/software
-
-program_details ()
-{
-  case $1 in
-    aclocal|automake)
-      echo "The '$1' program is part of the GNU Automake package:"
-      echo "<$gnu_software_URL/automake>"
-      echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
-      echo "<$gnu_software_URL/autoconf>"
-      echo "<$gnu_software_URL/m4/>"
-      echo "<$perl_URL>"
-      ;;
-    autoconf|autom4te|autoheader)
-      echo "The '$1' program is part of the GNU Autoconf package:"
-      echo "<$gnu_software_URL/autoconf/>"
-      echo "It also requires GNU m4 and Perl in order to run:"
-      echo "<$gnu_software_URL/m4/>"
-      echo "<$perl_URL>"
-      ;;
-  esac
-}
-
-give_advice ()
-{
-  # Normalize program name to check for.
-  normalized_program=`echo "$1" | sed '
-    s/^gnu-//; t
-    s/^gnu//; t
-    s/^g//; t'`
-
-  printf '%s\n' "'$1' is $msg."
-
-  configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
-  case $normalized_program in
-    autoconf*)
-      echo "You should only need it if you modified 'configure.ac',"
-      echo "or m4 files included by it."
-      program_details 'autoconf'
-      ;;
-    autoheader*)
-      echo "You should only need it if you modified 'acconfig.h' or"
-      echo "$configure_deps."
-      program_details 'autoheader'
-      ;;
-    automake*)
-      echo "You should only need it if you modified 'Makefile.am' or"
-      echo "$configure_deps."
-      program_details 'automake'
-      ;;
-    aclocal*)
-      echo "You should only need it if you modified 'acinclude.m4' or"
-      echo "$configure_deps."
-      program_details 'aclocal'
-      ;;
-   autom4te*)
-      echo "You might have modified some maintainer files that require"
-      echo "the 'autom4te' program to be rebuilt."
-      program_details 'autom4te'
-      ;;
-    bison*|yacc*)
-      echo "You should only need it if you modified a '.y' file."
-      echo "You may want to install the GNU Bison package:"
-      echo "<$gnu_software_URL/bison/>"
-      ;;
-    lex*|flex*)
-      echo "You should only need it if you modified a '.l' file."
-      echo "You may want to install the Fast Lexical Analyzer package:"
-      echo "<$flex_URL>"
-      ;;
-    help2man*)
-      echo "You should only need it if you modified a dependency" \
-           "of a man page."
-      echo "You may want to install the GNU Help2man package:"
-      echo "<$gnu_software_URL/help2man/>"
-    ;;
-    makeinfo*)
-      echo "You should only need it if you modified a '.texi' file, or"
-      echo "any other file indirectly affecting the aspect of the manual."
-      echo "You might want to install the Texinfo package:"
-      echo "<$gnu_software_URL/texinfo/>"
-      echo "The spurious makeinfo call might also be the consequence of"
-      echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
-      echo "want to install GNU make:"
-      echo "<$gnu_software_URL/make/>"
-      ;;
-    *)
-      echo "You might have modified some files without having the proper"
-      echo "tools for further handling them.  Check the 'README' file, it"
-      echo "often tells you about the needed prerequisites for installing"
-      echo "this package.  You may also peek at any GNU archive site, in"
-      echo "case some other package contains this missing '$1' program."
-      ;;
-  esac
-}
-
-give_advice "$1" | sed -e '1s/^/WARNING: /' \
-                       -e '2,$s/^/         /' >&2
-
-# Propagate the correct exit status (expected to be 127 for a program
-# not found, 63 for a program that failed due to version mismatch).
-exit $st
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/zfs/config/suppressed-warnings.txt b/zfs/config/suppressed-warnings.txt
new file mode 100644 (file)
index 0000000..621e3cd
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Expected warnings which should be suppressed by buildbot
+#
+None : ^libtool: install: warning: relinking `.*'$
+None : ^libtool: install: warning: remember to run `libtool --finish .*'$
+None : ^libtool: install: warning: `.*' has not been installed in `.*'$
+None : ^warning: File listed twice:.*
diff --git a/zfs/config/toolchain-simd.m4 b/zfs/config/toolchain-simd.m4
new file mode 100644 (file)
index 0000000..29abbbb
--- /dev/null
@@ -0,0 +1,361 @@
+dnl #
+dnl # Checks if host toolchain supports SIMD instructions
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_TOOLCHAIN_SIMD], [
+       case "$host_cpu" in
+               x86_64 | x86 | i686)
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE2
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE3
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSSE3
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE4_1
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE4_2
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX2
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512F
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512CD
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512DQ
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512BW
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512IFMA
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512VBMI
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512PF
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512ER
+                       ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512VL
+                       ;;
+       esac
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE], [
+       AC_MSG_CHECKING([whether host toolchain supports SSE])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([[
+               void main()
+               {
+                       __asm__ __volatile__("xorps %xmm0, %xmm1");
+               }
+       ]])], [
+               AC_DEFINE([HAVE_SSE], 1, [Define if host toolchain supports SSE])
+               AC_MSG_RESULT([yes])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE2
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE2], [
+       AC_MSG_CHECKING([whether host toolchain supports SSE2])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([[
+               void main()
+               {
+                       __asm__ __volatile__("pxor %xmm0, %xmm1");
+               }
+       ]])], [
+               AC_DEFINE([HAVE_SSE2], 1, [Define if host toolchain supports SSE2])
+               AC_MSG_RESULT([yes])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE3
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE3], [
+       AC_MSG_CHECKING([whether host toolchain supports SSE3])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([[
+               void main()
+               {
+                       char v[16];
+                       __asm__ __volatile__("lddqu %0,%%xmm0" :: "m"(v[0]));
+               }
+       ]])], [
+               AC_DEFINE([HAVE_SSE3], 1, [Define if host toolchain supports SSE3])
+               AC_MSG_RESULT([yes])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSSE3
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSSE3], [
+       AC_MSG_CHECKING([whether host toolchain supports SSSE3])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([[
+               void main()
+               {
+                       __asm__ __volatile__("pshufb %xmm0,%xmm1");
+               }
+       ]])], [
+               AC_DEFINE([HAVE_SSSE3], 1, [Define if host toolchain supports SSSE3])
+               AC_MSG_RESULT([yes])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE4_1
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE4_1], [
+       AC_MSG_CHECKING([whether host toolchain supports SSE4.1])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([[
+               void main()
+               {
+                       __asm__ __volatile__("pmaxsb %xmm0,%xmm1");
+               }
+       ]])], [
+               AC_DEFINE([HAVE_SSE4_1], 1, [Define if host toolchain supports SSE4.1])
+               AC_MSG_RESULT([yes])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE4_2
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_SSE4_2], [
+       AC_MSG_CHECKING([whether host toolchain supports SSE4.2])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([[
+               void main()
+               {
+                       __asm__ __volatile__("pcmpgtq %xmm0, %xmm1");
+               }
+       ]])], [
+               AC_DEFINE([HAVE_SSE4_2], 1, [Define if host toolchain supports SSE4.2])
+               AC_MSG_RESULT([yes])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([[
+               void main()
+               {
+                       char v[32];
+                       __asm__ __volatile__("vmovdqa %0,%%ymm0" :: "m"(v[0]));
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX], 1, [Define if host toolchain supports AVX])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX2
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX2], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX2])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vpshufb %ymm0,%ymm1,%ymm2");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX2], 1, [Define if host toolchain supports AVX2])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512F
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512F], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512F])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vpandd %zmm0,%zmm1,%zmm2");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512F], 1, [Define if host toolchain supports AVX512F])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512CD
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512CD], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512CD])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vplzcntd %zmm0,%zmm1");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512CD], 1, [Define if host toolchain supports AVX512CD])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512DQ
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512DQ], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512DQ])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vandpd %zmm0,%zmm1,%zmm2");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512DQ], 1, [Define if host toolchain supports AVX512DQ])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512BW
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512BW], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512BW])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vpshufb %zmm0,%zmm1,%zmm2");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512BW], 1, [Define if host toolchain supports AVX512BW])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512IFMA
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512IFMA], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512IFMA])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vpmadd52luq %zmm0,%zmm1,%zmm2");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512IFMA], 1, [Define if host toolchain supports AVX512IFMA])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512VBMI
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512VBMI], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512VBMI])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vpermb %zmm0,%zmm1,%zmm2");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512VBMI], 1, [Define if host toolchain supports AVX512VBMI])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512PF
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512PF], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512PF])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vgatherpf0dps (%rsi,%zmm0,4){%k1}");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512PF], 1, [Define if host toolchain supports AVX512PF])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512ER
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512ER], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512ER])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vexp2pd %zmm0,%zmm1");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512ER], 1, [Define if host toolchain supports AVX512ER])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
+
+dnl #
+dnl # ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512VL
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_TOOLCHAIN_CAN_BUILD_AVX512VL], [
+       AC_MSG_CHECKING([whether host toolchain supports AVX512VL])
+
+       AC_LINK_IFELSE([AC_LANG_SOURCE([
+       [
+               void main()
+               {
+                       __asm__ __volatile__("vpabsq %zmm0,%zmm1");
+               }
+       ]])], [
+               AC_MSG_RESULT([yes])
+               AC_DEFINE([HAVE_AVX512VL], 1, [Define if host toolchain supports AVX512VL])
+       ], [
+               AC_MSG_RESULT([no])
+       ])
+])
diff --git a/zfs/config/user-arch.m4 b/zfs/config/user-arch.m4
deleted file mode 100644 (file)
index fcc566f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-dnl #
-dnl # Set the target arch for libspl atomic implementation
-dnl #
-AC_DEFUN([ZFS_AC_CONFIG_USER_ARCH], [
-       AC_MSG_CHECKING(for target asm dir)
-       TARGET_ARCH=`echo ${target_cpu} | sed -e s/i.86/i386/`
-
-       case $TARGET_ARCH in
-       i386|x86_64)
-               TARGET_ASM_DIR=asm-${TARGET_ARCH}
-               ;;
-       *)
-               TARGET_ASM_DIR=asm-generic
-               ;;
-       esac
-
-       AC_SUBST([TARGET_ASM_DIR])
-       AC_MSG_RESULT([$TARGET_ASM_DIR])
-])
diff --git a/zfs/config/user-commands.m4 b/zfs/config/user-commands.m4
new file mode 100644 (file)
index 0000000..d53bec4
--- /dev/null
@@ -0,0 +1,182 @@
+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(FALSE, false, "")
+       AC_PATH_TOOL(FDISK, fdisk, "")
+       AC_PATH_TOOL(FGREP, fgrep, "")
+       AC_PATH_TOOL(FILE, file, "")
+       AC_PATH_TOOL(FIND, find, "")
+       AC_PATH_TOOL(FIO, fio, "")
+       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(STAT, stat, "")
+       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(TIMEOUT, timeout, "")
+       AC_PATH_TOOL(TOUCH, touch, "")
+       AC_PATH_TOOL(TR, tr, "")
+       AC_PATH_TOOL(TRUNCATE, truncate, "")
+       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(UUIDGEN, uuidgen, "")
+       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(CHACL, chacl, "")
+       AC_PATH_TOOL(COMPRESS, gzip, "")
+       AC_PATH_TOOL(FORMAT, parted, "")
+       AC_PATH_TOOL(FREE, free, "")
+       AC_PATH_TOOL(GETFACL, getfacl, "")
+       AC_PATH_TOOL(IOSTAT, iostat, "")
+       AC_PATH_TOOL(LOCKFS, lsof, "")
+       AC_PATH_TOOL(LSBLK, lsblk, "")
+       AC_PATH_TOOL(MODUNLOAD, rmmod, "")
+       AC_PATH_TOOL(MPSTAT, mpstat, "")
+       AC_PATH_TOOL(NEWFS, mke2fs, "")
+       AC_PATH_TOOL(NPROC, nproc, "")
+       AC_PATH_TOOL(PFEXEC, sudo, "")
+       AC_PATH_TOOL(READLINK, readlink, "")
+       AC_PATH_TOOL(SETFACL, setfacl, "")
+       AC_PATH_TOOL(SHARE, exportfs, "")
+       AC_PATH_TOOL(SWAP, swapon, "")
+       AC_PATH_TOOL(SWAPADD, swapon, "")
+       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(VMSTAT, vmstat, "")
+
+       PAGESIZE=$($GETCONF PAGESIZE)
+       AC_SUBST(PAGESIZE)
+
+       MNTTAB=/proc/self/mounts
+       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
+       ])
+])
diff --git a/zfs/config/user-libattr.m4 b/zfs/config/user-libattr.m4
new file mode 100644 (file)
index 0000000..3298fd4
--- /dev/null
@@ -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])
+])
index 2dd26238c70eca8fcaeab8b217f622c614891cb2..5bc7f466ae7a6387e25ddd7bf382be7d54968765 100644 (file)
 dnl #
-dnl # Check for ZFS support in libblkid.  This test needs to check
-dnl # more than if the library exists because we expect there are
-dnl # at least 3 flavors of the library out in the wild:
-dnl #
-dnl #   1) blkid which has no ZFS support
-dnl #   2) blkid with ZFS support and a flawed method of probing
-dnl #   3) blkid with ZFS support and a working method of probing
-dnl #
-dnl # To handle this the check first validates that there is a version
-dnl # of the library installed.  If there is it creates a simulated
-dnl # ZFS filesystem and then links a small test app which attempts
-dnl # to detect the simualated filesystem type.  If it correctly
-dnl # identifies the filesystem as ZFS we can safely assume case 3).
-dnl # Otherwise we disable blkid support and resort to manual probing.
+dnl # Check for libblkid.  Basic support for detecting ZFS pools
+dnl # has existing in blkid since 2008.
 dnl #
 AC_DEFUN([ZFS_AC_CONFIG_USER_LIBBLKID], [
-       AC_ARG_WITH([blkid],
-               [AS_HELP_STRING([--with-blkid],
-               [support blkid caching @<:@default=check@:>@])],
-               [],
-               [with_blkid=check])
-
        LIBBLKID=
-       AS_IF([test "x$with_blkid" = xyes],
-       [
-               AC_SUBST([LIBBLKID], ["-lblkid"])
-               AC_DEFINE([HAVE_LIBBLKID], 1,
-                       [Define if you have libblkid])
-       ])
-
-       AS_IF([test "x$with_blkid" = xcheck],
-       [
-               AC_CHECK_LIB([blkid], [blkid_get_cache],
-               [
-                       AC_MSG_CHECKING([for blkid zfs support])
-
-                       ZFS_DEV=`mktemp`
-                       truncate -s 64M $ZFS_DEV
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=128 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=132 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=136 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=140 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-
-                       saved_LIBS="$LIBS"
-                       LIBS="-lblkid"
-
-                       AC_RUN_IFELSE([AC_LANG_PROGRAM(
-                       [
-                               #include <stdio.h>
-                               #include <stdlib.h>
-                               #include <blkid/blkid.h>
-                       ],
-                       [
-                               blkid_cache cache;
-                               char *value;
-
-                               if (blkid_get_cache(&cache, NULL) < 0)
-                                       return 1;
-
-                               value = blkid_get_tag_value(cache, "TYPE",
-                                                           "$ZFS_DEV");
-                               if (!value) {
-                                       blkid_put_cache(cache);
-                                       return 2;
-                               }
-
-                               if (strcmp(value, "zfs_member")) {
-                                       free(value);
-                                       blkid_put_cache(cache);
-                                       return 0;
-                               }
 
-                               free(value);
-                               blkid_put_cache(cache);
-                       ])],
-                       [
-                               rm -f $ZFS_DEV
-                               AC_MSG_RESULT([yes])
-                               AC_SUBST([LIBBLKID], ["-lblkid"])
-                               AC_DEFINE([HAVE_LIBBLKID], 1,
-                                       [Define if you have libblkid])
-                       ],
-                       [
-                               rm -f $ZFS_DEV
-                               AC_MSG_RESULT([no])
-                               AS_IF([test "x$with_blkid" != xcheck],
-                                       [AC_MSG_FAILURE(
-                                       [--with-blkid given but unavailable])])
-                       ])
+       AC_CHECK_HEADER([blkid/blkid.h], [], [AC_MSG_FAILURE([
+        *** blkid.h missing, libblkid-devel package required])])
 
-                       LIBS="$saved_LIBS"
-               ],
-               [
-                       AS_IF([test "x$with_blkid" != xcheck],
-                               [AC_MSG_FAILURE(
-                               [--with-blkid given but unavailable])])
-               ]
-               [])
-       ])
+       AC_SUBST([LIBBLKID], ["-lblkid"])
+       AC_DEFINE([HAVE_LIBBLKID], 1, [Define if you have libblkid])
 ])
diff --git a/zfs/config/user-libdevmapper.m4 b/zfs/config/user-libdevmapper.m4
new file mode 100644 (file)
index 0000000..af4dd41
--- /dev/null
@@ -0,0 +1,15 @@
+dnl #
+dnl # Check for libdevmapper.  libdevmapper is optional for building, but
+dnl # required for auto-online/auto-replace functionality for DM/multipath
+dnl # disks.
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_USER_LIBDEVMAPPER], [
+        AC_CHECK_HEADER([libdevmapper.h], [
+            AC_SUBST([LIBDEVMAPPER], ["-ldevmapper"])
+            AC_DEFINE([HAVE_LIBDEVMAPPER], 1, [Define if you have libdevmapper])
+
+           user_libdevmapper=yes
+        ], [
+           user_libdevmapper=no
+       ])
+])
diff --git a/zfs/config/user-libtirpc.m4 b/zfs/config/user-libtirpc.m4
new file mode 100644 (file)
index 0000000..5f92906
--- /dev/null
@@ -0,0 +1,30 @@
+dnl #
+dnl # Check for libtirpc - may be needed for xdr functionality
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_USER_LIBTIRPC], [
+       AC_ARG_WITH([tirpc],
+           [AS_HELP_STRING([--with-tirpc],
+               [use tirpc for xdr encoding @<:@default=check@:>@])],
+           [],
+           [with_tirpc=check])
+
+       LIBTIRPC=
+       LIBTIRPC_CFLAGS=
+
+       AS_IF([test "x$with_tirpc" != xno],
+           [AC_CHECK_LIB([tirpc], [xdrmem_create],
+               [AC_SUBST([LIBTIRPC], [-ltirpc])
+                AC_SUBST([LIBTIRPC_CFLAGS], [-I/usr/include/tirpc])
+                AC_DEFINE([HAVE_LIBTIRPC], [1], [Define if you have libtirpc])
+               ],
+               [if test "x$with_tirpc" != xcheck; then
+                   AC_MSG_FAILURE(
+                       [--with-tirpc was given, but test for tirpc failed])
+                fi
+               AC_SEARCH_LIBS([xdrmem_create], [tirpc], [], [
+                   AC_MSG_FAILURE([xdrmem_create() requires tirpc or libc])])
+               ])],
+           [AC_SEARCH_LIBS([xdrmem_create], [tirpc], [], [
+               AC_MSG_FAILURE([xdrmem_create() requires libc])])
+           ])
+])
diff --git a/zfs/config/user-libudev.m4 b/zfs/config/user-libudev.m4
new file mode 100644 (file)
index 0000000..9b74549
--- /dev/null
@@ -0,0 +1,19 @@
+dnl #
+dnl # Check for libudev - needed for vdev auto-online and auto-replace
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_USER_LIBUDEV], [
+       LIBUDEV=
+
+       AC_CHECK_HEADER([libudev.h], [
+           user_libudev=yes
+           AC_SUBST([LIBUDEV], ["-ludev"])
+           AC_DEFINE([HAVE_LIBUDEV], 1, [Define if you have libudev])
+       ], [
+           user_libudev=no
+       ])
+
+       AC_SEARCH_LIBS([udev_device_get_is_initialized], [udev], [
+           AC_DEFINE([HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED], 1, [
+           Define if udev_device_get_is_initialized is available])], [])
+
+])
index aba375a22820e7c2967438ca0904bbb31f1c1ec8..f0da671a3f612fed160dd370edad7031a6cd5f53 100644 (file)
@@ -7,10 +7,10 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_LIBUUID], [
        AC_CHECK_HEADER([uuid/uuid.h], [], [AC_MSG_FAILURE([
        *** uuid/uuid.h missing, libuuid-devel package required])])
 
-       AC_CHECK_LIB([uuid], [uuid_generate], [], [AC_MSG_FAILURE([
+       AC_SEARCH_LIBS([uuid_generate], [uuid], [], [AC_MSG_FAILURE([
        *** uuid_generate() missing, libuuid-devel package required])])
 
-       AC_CHECK_LIB([uuid], [uuid_is_null], [], [AC_MSG_FAILURE([
+       AC_SEARCH_LIBS([uuid_is_null], [uuid], [], [AC_MSG_FAILURE([
        *** uuid_is_null() missing, libuuid-devel package required])])
 
        AC_SUBST([LIBUUID], ["-luuid"])
index a48361662e4fa3b3daa9b19604969f94ee89101a..82c0962e4517d811972061a4287b3674d0cb2cf1 100644 (file)
@@ -7,13 +7,13 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_ZLIB], [
        AC_CHECK_HEADER([zlib.h], [], [AC_MSG_FAILURE([
        *** zlib.h missing, zlib-devel package required])])
 
-       AC_CHECK_LIB([z], [compress2], [], [AC_MSG_FAILURE([
+       AC_SEARCH_LIBS([compress2], [z], [], [AC_MSG_FAILURE([
        *** compress2() missing, zlib-devel package required])])
 
-       AC_CHECK_LIB([z], [uncompress], [], [AC_MSG_FAILURE([
+       AC_SEARCH_LIBS([uncompress], [z], [], [AC_MSG_FAILURE([
        *** uncompress() missing, zlib-devel package required])])
 
-       AC_CHECK_LIB([z], [crc32], [], [AC_MSG_FAILURE([
+       AC_SEARCH_LIBS([crc32], [z], [], [AC_MSG_FAILURE([
        *** crc32() missing, zlib-devel package required])])
 
        AC_SUBST([ZLIB], ["-lz"])
index a86b5524a4e8a51e76da183c9f35f21548ee752a..1d20642b81485153742c51dbfb31cc9e01fec143 100644 (file)
@@ -2,19 +2,35 @@ dnl #
 dnl # Default ZFS user configuration
 dnl #
 AC_DEFUN([ZFS_AC_CONFIG_USER], [
-       ZFS_AC_DKMS_INHIBIT
        ZFS_AC_CONFIG_USER_MOUNT_HELPER
        ZFS_AC_CONFIG_USER_UDEV
        ZFS_AC_CONFIG_USER_SYSTEMD
        ZFS_AC_CONFIG_USER_SYSVINIT
        ZFS_AC_CONFIG_USER_DRACUT
-       ZFS_AC_CONFIG_USER_ARCH
        ZFS_AC_CONFIG_USER_ZLIB
        ZFS_AC_CONFIG_USER_LIBUUID
+       ZFS_AC_CONFIG_USER_LIBTIRPC
        ZFS_AC_CONFIG_USER_LIBBLKID
+       ZFS_AC_CONFIG_USER_LIBATTR
+       ZFS_AC_CONFIG_USER_LIBDEVMAPPER
+       ZFS_AC_CONFIG_USER_LIBUDEV
        ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN
        ZFS_AC_CONFIG_USER_RUNSTATEDIR
-dnl #
-dnl #  Checks for library functions
+
+       ZFS_AC_CONFIG_USER_COMMANDS
+       ZFS_AC_TEST_FRAMEWORK
+
        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)
+])
index facd30282701a642e920d9e9e2a9568fa37a6029..8b969da36ff5c21c40df1192838def8c5547daaa 100644 (file)
@@ -63,12 +63,11 @@ AC_DEFUN([ZFS_AC_DEBUG_DMU_TX], [
 AC_DEFUN([ZFS_AC_CONFIG_ALWAYS], [
        ZFS_AC_CONFIG_ALWAYS_NO_UNUSED_BUT_SET_VARIABLE
        ZFS_AC_CONFIG_ALWAYS_NO_BOOL_COMPARE
+       ZFS_AC_CONFIG_ALWAYS_TOOLCHAIN_SIMD
+       ZFS_AC_CONFIG_ALWAYS_ARCH
 ])
 
 AC_DEFUN([ZFS_AC_CONFIG], [
-       TARGET_ASM_DIR=asm-generic
-       AC_SUBST(TARGET_ASM_DIR)
-
        ZFS_CONFIG=all
        AC_ARG_WITH([config],
                AS_HELP_STRING([--with-config=CONFIG],
@@ -87,10 +86,10 @@ AC_DEFUN([ZFS_AC_CONFIG], [
        ZFS_AC_CONFIG_ALWAYS
 
        case "$ZFS_CONFIG" in
-               user)   ZFS_AC_CONFIG_USER   ;;
                kernel) ZFS_AC_CONFIG_KERNEL ;;
-               all)    ZFS_AC_CONFIG_KERNEL
-                       ZFS_AC_CONFIG_USER   ;;
+               user)   ZFS_AC_CONFIG_USER   ;;
+               all)    ZFS_AC_CONFIG_USER
+                       ZFS_AC_CONFIG_KERNEL ;;
                srpm)                        ;;
                *)
                AC_MSG_RESULT([Error!])
@@ -99,10 +98,12 @@ AC_DEFUN([ZFS_AC_CONFIG], [
        esac
 
        AM_CONDITIONAL([CONFIG_USER],
-                      [test "$ZFS_CONFIG" = user -o "$ZFS_CONFIG" = all])
+           [test "$ZFS_CONFIG" = user -o "$ZFS_CONFIG" = all])
        AM_CONDITIONAL([CONFIG_KERNEL],
-                      [test "$ZFS_CONFIG" = kernel -o "$ZFS_CONFIG" = all] &&
-                      [test "x$enable_linux_builtin" != xyes ])
+           [test "$ZFS_CONFIG" = kernel -o "$ZFS_CONFIG" = all] &&
+           [test "x$enable_linux_builtin" != xyes ])
+       AM_CONDITIONAL([WANT_DEVNAME2DEVID],
+           [test "x$user_libudev" = xyes ])
 ])
 
 dnl #
@@ -266,6 +267,8 @@ AC_DEFUN([ZFS_AC_DEFAULT_PACKAGE], [
                VENDOR=ubuntu ;
        elif test -f /etc/debian_version ; then
                VENDOR=debian ;
+       elif test -f /etc/alpine-release ; then
+               VENDOR=alpine ;
        else
                VENDOR= ;
        fi
@@ -278,6 +281,7 @@ AC_DEFUN([ZFS_AC_DEFAULT_PACKAGE], [
                redhat)     DEFAULT_PACKAGE=rpm  ;;
                fedora)     DEFAULT_PACKAGE=rpm  ;;
                gentoo)     DEFAULT_PACKAGE=tgz  ;;
+               alpine)     DEFAULT_PACKAGE=tgz  ;;
                arch)       DEFAULT_PACKAGE=tgz  ;;
                sles)       DEFAULT_PACKAGE=rpm  ;;
                slackware)  DEFAULT_PACKAGE=tgz  ;;
@@ -299,7 +303,8 @@ AC_DEFUN([ZFS_AC_DEFAULT_PACKAGE], [
                toss)       DEFAULT_INIT_SCRIPT=redhat ;;
                redhat)     DEFAULT_INIT_SCRIPT=redhat ;;
                fedora)     DEFAULT_INIT_SCRIPT=fedora ;;
-               gentoo)     DEFAULT_INIT_SCRIPT=gentoo ;;
+               gentoo)     DEFAULT_INIT_SCRIPT=openrc ;;
+               alpine)     DEFAULT_INIT_SCRIPT=openrc ;;
                arch)       DEFAULT_INIT_SCRIPT=lsb    ;;
                sles)       DEFAULT_INIT_SCRIPT=lsb    ;;
                slackware)  DEFAULT_INIT_SCRIPT=lsb    ;;
@@ -313,6 +318,7 @@ AC_DEFUN([ZFS_AC_DEFAULT_PACKAGE], [
 
        AC_MSG_CHECKING([default init config direectory])
        case "$VENDOR" in
+               alpine)     DEFAULT_INITCONF_DIR=/etc/conf.d    ;;
                gentoo)     DEFAULT_INITCONF_DIR=/etc/conf.d    ;;
                toss)       DEFAULT_INITCONF_DIR=/etc/sysconfig ;;
                redhat)     DEFAULT_INITCONF_DIR=/etc/sysconfig ;;
index d174cccc7a1e98e501c7514ce00990e4ae20bbb6..3e1429d99d80c9a362125ebc6de01459d4a88e03 100644 (file)
@@ -1,10 +1,9 @@
 dnl #
 dnl # DESCRIPTION:
-dnl # Read meta data from the META file or the debian/changelog file if it
-dnl # exists.  When building from a git repository the ZFS_META_RELEASE field
-dnl # will be overwritten if there is an annotated tag matching the form
-dnl # ZFS_META_NAME-ZFS_META_VERSION-*.  This allows for working builds to be
-dnl # uniquely identified using the git commit hash.
+dnl # Read meta data from the META file.  When building from a git repository
+dnl # the ZFS_META_RELEASE field will be overwritten if there is an annotated
+dnl # tag matching the form ZFS_META_NAME-ZFS_META_VERSION-*.  This allows
+dnl # for working builds to be uniquely identified using the git commit hash.
 dnl #
 dnl #    The META file format is as follows:
 dnl #      ^[ ]*KEY:[ \t]+VALUE$
@@ -50,7 +49,6 @@ AC_DEFUN([ZFS_AC_META], [
        _zfs_ac_meta_type="none"
        if test -f "$META"; then
                _zfs_ac_meta_type="META file"
-               _dpkg_parsechangelog=$(dpkg-parsechangelog 2>/dev/null)
 
                ZFS_META_NAME=_ZFS_AC_META_GETVAL([(Name|Project|Package)]);
                if test -n "$ZFS_META_NAME"; then
@@ -68,36 +66,22 @@ AC_DEFUN([ZFS_AC_META], [
                        AC_SUBST([ZFS_META_VERSION])
                fi
 
-               if test -n "${_dpkg_parsechangelog}"; then
-                       _dpkg_version=$(echo "${_dpkg_parsechangelog}" \
-                               | $AWK '$[]1 == "Version:" { print $[]2; }' \
-                               | cut -d- -f1)
-                       if test "${_dpkg_version}" != "$ZFS_META_VERSION"; then
-                               AC_MSG_ERROR([
-       *** Version $ZFS_META_VERSION in the META file is different than
-       *** version $_dpkg_version in the debian/changelog file. DKMS and DEB
-       *** packaging require that these files have the same version.
-                               ])
-                       fi
-               fi
-
                ZFS_META_RELEASE=_ZFS_AC_META_GETVAL([Release]);
-
-               if test -n "${_dpkg_parsechangelog}"; then
-                       _dpkg_release=$(echo "${_dpkg_parsechangelog}" \
-                               | $AWK '$[]1 == "Version:" { print $[]2; }' \
-                               | cut -d- -f2-)
-                       if test -n "${_dpkg_release}"; then
-                               ZFS_META_RELEASE=${_dpkg_release}
-                               _zfs_ac_meta_type="dpkg-parsechangelog"
-                       fi
-               elif test ! -f ".nogitrelease" && git rev-parse --git-dir > /dev/null 2>&1; then
+               if test ! -f ".nogitrelease" && git rev-parse --git-dir > /dev/null 2>&1; then
                        _match="${ZFS_META_NAME}-${ZFS_META_VERSION}"
                        _alias=$(git describe --match=${_match} 2>/dev/null)
                        _release=$(echo ${_alias}|cut -f3- -d'-'|sed 's/-/_/g')
                        if test -n "${_release}"; then
                                ZFS_META_RELEASE=${_release}
                                _zfs_ac_meta_type="git describe"
+                       else
+                               _match="${ZFS_META_NAME}-${ZFS_META_VERSION}-${ZFS_META_RELEASE}"
+                               _alias=$(git describe --match=${_match} 2>/dev/null)
+                               _release=$(echo ${_alias}|cut -f3- -d'-'|sed 's/-/_/g')
+                               if test -n "${_release}"; then
+                                       ZFS_META_RELEASE=${_release}
+                                       _zfs_ac_meta_type="git describe"
+                               fi
                        fi
                fi
 
diff --git a/zfs/configure b/zfs/configure
deleted file mode 100755 (executable)
index 84f360b..0000000
+++ /dev/null
@@ -1,36357 +0,0 @@
-#! /bin/sh
-# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for zfs 0.6.5.8.
-#
-#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
-#
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-
-
-as_nl='
-'
-export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
-    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='print -r --'
-  as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='printf %s\n'
-  as_echo_n='printf %s'
-else
-  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
-    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
-    as_echo_n='/usr/ucb/echo -n'
-  else
-    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
-    as_echo_n_body='eval
-      arg=$1;
-      case $arg in #(
-      *"$as_nl"*)
-       expr "X$arg" : "X\\(.*\\)$as_nl";
-       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
-      esac;
-      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
-    '
-    export as_echo_n_body
-    as_echo_n='sh -c $as_echo_n_body as_echo'
-  fi
-  export as_echo_body
-  as_echo='sh -c $as_echo_body as_echo'
-fi
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  PATH_SEPARATOR=:
-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
-      PATH_SEPARATOR=';'
-  }
-fi
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.  Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" ""       $as_nl"
-
-# Find who we are.  Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
-  *[\\/]* ) as_myself=$0 ;;
-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-  done
-IFS=$as_save_IFS
-
-     ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
-  as_myself=$0
-fi
-if test ! -f "$as_myself"; then
-  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  exit 1
-fi
-
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there.  '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
-  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-# Use a proper internal environment variable to ensure we don't fall
-  # into an infinite loop, continuously re-executing ourselves.
-  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
-    _as_can_reexec=no; export _as_can_reexec;
-    # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
-  *v*x* | *x*v* ) as_opts=-vx ;;
-  *v* ) as_opts=-v ;;
-  *x* ) as_opts=-x ;;
-  * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
-  fi
-  # We don't want this to propagate to other subprocesses.
-          { _as_can_reexec=; unset _as_can_reexec;}
-if test "x$CONFIG_SHELL" = x; then
-  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '\${1+\"\$@\"}'='\"\$@\"'
-  setopt NO_GLOB_SUBST
-else
-  case \`(set -o) 2>/dev/null\` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-"
-  as_required="as_fn_return () { (exit \$1); }
-as_fn_success () { as_fn_return 0; }
-as_fn_failure () { as_fn_return 1; }
-as_fn_ret_success () { return 0; }
-as_fn_ret_failure () { return 1; }
-
-exitcode=0
-as_fn_success || { exitcode=1; echo as_fn_success failed.; }
-as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
-as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
-as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
-
-else
-  exitcode=1; echo positional parameters were not saved.
-fi
-test x\$exitcode = x0 || exit 1
-test -x / || exit 1"
-  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
-  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
-  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
-  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
-
-  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
-    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
-    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
-    PATH=/empty FPATH=/empty; export PATH FPATH
-    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
-      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
-test \$(( 1 + 1 )) = 2 || exit 1"
-  if (eval "$as_required") 2>/dev/null; then :
-  as_have_required=yes
-else
-  as_have_required=no
-fi
-  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
-
-else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  as_found=:
-  case $as_dir in #(
-        /*)
-          for as_base in sh bash ksh sh5; do
-            # Try only shells that exist, to save several forks.
-            as_shell=$as_dir/$as_base
-            if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
-                   { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
-  CONFIG_SHELL=$as_shell as_have_required=yes
-                  if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
-  break 2
-fi
-fi
-          done;;
-       esac
-  as_found=false
-done
-$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
-             { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
-  CONFIG_SHELL=$SHELL as_have_required=yes
-fi; }
-IFS=$as_save_IFS
-
-
-      if test "x$CONFIG_SHELL" != x; then :
-  export CONFIG_SHELL
-             # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
-  *v*x* | *x*v* ) as_opts=-vx ;;
-  *v* ) as_opts=-v ;;
-  *x* ) as_opts=-x ;;
-  * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
-fi
-
-    if test x$as_have_required = xno; then :
-  $as_echo "$0: This script requires a shell more modern than all"
-  $as_echo "$0: the shells that I found on your system."
-  if test x${ZSH_VERSION+set} = xset ; then
-    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
-    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
-  else
-    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
-$0: including any error possibly output before this
-$0: message. Then install a modern shell, or manually run
-$0: the script under such a shell if you do have one."
-  fi
-  exit 1
-fi
-fi
-fi
-SHELL=${CONFIG_SHELL-/bin/sh}
-export SHELL
-# Unset more variables known to interfere with behavior of common tools.
-CLICOLOR_FORCE= GREP_OPTIONS=
-unset CLICOLOR_FORCE GREP_OPTIONS
-
-## --------------------- ##
-## M4sh Shell Functions. ##
-## --------------------- ##
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
-  { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
-  return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
-  set +e
-  as_fn_set_status $1
-  exit $1
-} # as_fn_exit
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || eval $as_mkdir_p || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_dir" : 'X\(//\)[^/]' \| \
-        X"$as_dir" : 'X\(//\)$' \| \
-        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
-  eval 'as_fn_append ()
-  {
-    eval $1+=\$2
-  }'
-else
-  as_fn_append ()
-  {
-    eval $1=\$$1\$2
-  }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
-  eval 'as_fn_arith ()
-  {
-    as_val=$(( $* ))
-  }'
-else
-  as_fn_arith ()
-  {
-    as_val=`expr "$@" || test $? -eq 1`
-  }
-fi # as_fn_arith
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
-  as_status=$1; test $as_status -eq 0 && as_status=1
-  if test "$4"; then
-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
-  fi
-  $as_echo "$as_me: error: $2" >&2
-  as_fn_exit $as_status
-} # as_fn_error
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
-  as_basename=basename
-else
-  as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
-        X"$0" : 'X\(//\)$' \| \
-        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
-  as_lineno_1=$LINENO as_lineno_1a=$LINENO
-  as_lineno_2=$LINENO as_lineno_2a=$LINENO
-  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
-  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
-  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
-  sed -n '
-    p
-    /[$]LINENO/=
-  ' <$as_myself |
-    sed '
-      s/[$]LINENO.*/&-/
-      t lineno
-      b
-      :lineno
-      N
-      :loop
-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
-      t loop
-      s/-\n.*//
-    ' >$as_me.lineno &&
-  chmod +x "$as_me.lineno" ||
-    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
-
-  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
-  # already done that, so ensure we don't try to do so again and fall
-  # in an infinite loop.  This has already happened in practice.
-  _as_can_reexec=no; export _as_can_reexec
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensitive to this).
-  . "./$as_me.lineno"
-  # Exit status is that of the last command.
-  exit
-}
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
-  case `echo 'xy\c'` in
-  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  xy)  ECHO_C='\c';;
-  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
-       ECHO_T='        ';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
-  if ln -s conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s='ln -s'
-    # ... but there are two gotchas:
-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
-  elif ln conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s=ln
-  else
-    as_ln_s='cp -pR'
-  fi
-else
-  as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p='mkdir -p "$as_dir"'
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-
-test -n "$DJDIR" || exec 7<&0 </dev/null
-exec 6>&1
-
-# Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
-# so uname gets run too.
-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
-
-#
-# Initializations.
-#
-ac_default_prefix=/usr/local
-ac_clean_files=
-ac_config_libobj_dir=.
-LIBOBJS=
-cross_compiling=no
-subdirs=
-MFLAGS=
-MAKEFLAGS=
-
-# Identity of this package.
-PACKAGE_NAME='zfs'
-PACKAGE_TARNAME='zfs'
-PACKAGE_VERSION='0.6.5.8'
-PACKAGE_STRING='zfs 0.6.5.8'
-PACKAGE_BUGREPORT=''
-PACKAGE_URL=''
-
-# Factoring default headers for most tests.
-ac_includes_default="\
-#include <stdio.h>
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include <sys/stat.h>
-#endif
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-#  include <stdlib.h>
-# endif
-#endif
-#ifdef HAVE_STRING_H
-# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
-#  include <memory.h>
-# endif
-# include <string.h>
-#endif
-#ifdef HAVE_STRINGS_H
-# include <strings.h>
-#endif
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#ifdef HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif"
-
-ac_subst_vars='am__EXEEXT_FALSE
-am__EXEEXT_TRUE
-LTLIBOBJS
-LIBOBJS
-DEBUG_DMU_TX
-DEBUG_ZFS
-DEBUG_STACKFLAGS
-DEBUG_CFLAGS
-CONFIG_KERNEL_FALSE
-CONFIG_KERNEL_TRUE
-CONFIG_USER_FALSE
-CONFIG_USER_TRUE
-KERNELCPPFLAGS
-KERNELMAKE_PARAMS
-SPL_SYMBOLS
-SPL_VERSION
-SPL_OBJ
-SPL
-LINUX_SYMBOLS
-LINUX_VERSION
-LINUX_OBJ
-LINUX
-FRAME_LARGER_THAN
-LIBBLKID
-LIBUUID
-ZLIB
-dracutdir
-ZFS_INIT_SYSV
-modulesloaddir
-systemdpresetdir
-systemdunitdir
-ZFS_MODULE_LOAD
-ZFS_INIT_SYSTEMD
-udevruledir
-udevdir
-mounthelperdir
-NO_BOOL_COMPARE
-NO_UNUSED_BUT_SET_VARIABLE
-ZFS_CONFIG
-TARGET_ASM_DIR
-ALIEN_VERSION
-ALIEN
-HAVE_ALIEN
-DPKGBUILD_VERSION
-DPKGBUILD
-HAVE_DPKGBUILD
-DPKG_VERSION
-DPKG
-HAVE_DPKG
-SRPM_DEFINE_COMMON
-SRPM_DEFINE_DKMS
-SRPM_DEFINE_KMOD
-SRPM_DEFINE_UTIL
-RPM_DEFINE_COMMON
-RPM_DEFINE_DKMS
-RPM_DEFINE_KMOD
-RPM_DEFINE_UTIL
-RPM_SPEC_DIR
-RPMBUILD_VERSION
-RPMBUILD
-HAVE_RPMBUILD
-RPM_VERSION
-RPM
-HAVE_RPM
-DEFINE_INITRAMFS
-DEFAULT_INITCONF_DIR
-DEFAULT_INIT_SCRIPT
-DEFAULT_INIT_DIR
-DEFAULT_PACKAGE
-VENDOR
-am__fastdepCCAS_FALSE
-am__fastdepCCAS_TRUE
-CCASDEPMODE
-CCASFLAGS
-CCAS
-CPP
-LT_SYS_LIBRARY_PATH
-OTOOL64
-OTOOL
-LIPO
-NMEDIT
-DSYMUTIL
-MANIFEST_TOOL
-RANLIB
-ac_ct_AR
-AR
-DLLTOOL
-OBJDUMP
-LN_S
-NM
-ac_ct_DUMPBIN
-DUMPBIN
-LD
-FGREP
-EGREP
-GREP
-SED
-LIBTOOL
-am__fastdepCC_FALSE
-am__fastdepCC_TRUE
-CCDEPMODE
-am__nodep
-AMDEPBACKSLASH
-AMDEP_FALSE
-AMDEP_TRUE
-am__quote
-am__include
-DEPDIR
-OBJEXT
-EXEEXT
-ac_ct_CC
-CPPFLAGS
-LDFLAGS
-CFLAGS
-CC
-am__untar
-am__tar
-AMTAR
-am__leading_dot
-SET_MAKE
-mkdir_p
-MKDIR_P
-INSTALL_STRIP_PROGRAM
-STRIP
-install_sh
-MAKEINFO
-AUTOHEADER
-AUTOMAKE
-AUTOCONF
-ACLOCAL
-VERSION
-PACKAGE
-CYGPATH_W
-am__isrc
-INSTALL_DATA
-INSTALL_SCRIPT
-INSTALL_PROGRAM
-AM_BACKSLASH
-AM_DEFAULT_VERBOSITY
-AM_DEFAULT_V
-AM_V
-MAINT
-MAINTAINER_MODE_FALSE
-MAINTAINER_MODE_TRUE
-target_os
-target_vendor
-target_cpu
-target
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
-ZFS_META_LT_AGE
-ZFS_META_LT_REVISION
-ZFS_META_LT_CURRENT
-ZFS_META_AUTHOR
-ZFS_META_DATA
-ZFS_META_ALIAS
-ZFS_META_LICENSE
-RELEASE
-ZFS_META_RELEASE
-ZFS_META_VERSION
-ZFS_META_NAME
-AWK
-target_alias
-host_alias
-build_alias
-LIBS
-ECHO_T
-ECHO_N
-ECHO_C
-DEFS
-mandir
-localedir
-libdir
-psdir
-pdfdir
-dvidir
-htmldir
-infodir
-docdir
-oldincludedir
-includedir
-runstatedir
-localstatedir
-sharedstatedir
-sysconfdir
-datadir
-datarootdir
-libexecdir
-sbindir
-bindir
-program_transform_name
-prefix
-exec_prefix
-PACKAGE_URL
-PACKAGE_BUGREPORT
-PACKAGE_STRING
-PACKAGE_VERSION
-PACKAGE_TARNAME
-PACKAGE_NAME
-PATH_SEPARATOR
-SHELL'
-ac_subst_files=''
-ac_user_opts='
-enable_option_checking
-enable_maintainer_mode
-enable_silent_rules
-enable_dependency_tracking
-enable_shared
-enable_static
-with_pic
-enable_fast_install
-with_aix_soname
-with_gnu_ld
-with_sysroot
-enable_libtool_lock
-with_spec
-with_config
-enable_linux_builtin
-with_mounthelperdir
-with_udevdir
-with_udevruledir
-enable_systemd
-with_systemdunitdir
-with_systemdpresetdir
-with_systemdmodulesloaddir
-enable_sysvinit
-with_dracutdir
-with_blkid
-with_linux
-with_linux_obj
-with_spl
-with_spl_obj
-with_spl_timeout
-enable_debug
-enable_debug_dmu_tx
-'
-      ac_precious_vars='build_alias
-host_alias
-target_alias
-CC
-CFLAGS
-LDFLAGS
-LIBS
-CPPFLAGS
-LT_SYS_LIBRARY_PATH
-CPP
-CCAS
-CCASFLAGS'
-
-
-# Initialize some variables set by options.
-ac_init_help=
-ac_init_version=false
-ac_unrecognized_opts=
-ac_unrecognized_sep=
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-cache_file=/dev/null
-exec_prefix=NONE
-no_create=
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-verbose=
-x_includes=NONE
-x_libraries=NONE
-
-# Installation directory options.
-# These are left unexpanded so users can "make install exec_prefix=/foo"
-# and all the variables that are supposed to be based on exec_prefix
-# by default will actually change.
-# Use braces instead of parens because sh, perl, etc. also accept them.
-# (The list follows the same order as the GNU Coding Standards.)
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datarootdir='${prefix}/share'
-datadir='${datarootdir}'
-sysconfdir='${prefix}/etc'
-sharedstatedir='${prefix}/com'
-localstatedir='${prefix}/var'
-runstatedir='${localstatedir}/run'
-includedir='${prefix}/include'
-oldincludedir='/usr/include'
-docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
-infodir='${datarootdir}/info'
-htmldir='${docdir}'
-dvidir='${docdir}'
-pdfdir='${docdir}'
-psdir='${docdir}'
-libdir='${exec_prefix}/lib'
-localedir='${datarootdir}/locale'
-mandir='${datarootdir}/man'
-
-ac_prev=
-ac_dashdash=
-for ac_option
-do
-  # If the previous option needs an argument, assign it.
-  if test -n "$ac_prev"; then
-    eval $ac_prev=\$ac_option
-    ac_prev=
-    continue
-  fi
-
-  case $ac_option in
-  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
-  *=)   ac_optarg= ;;
-  *)    ac_optarg=yes ;;
-  esac
-
-  # Accept the important Cygnus configure options, so we can diagnose typos.
-
-  case $ac_dashdash$ac_option in
-  --)
-    ac_dashdash=yes ;;
-
-  -bindir | --bindir | --bindi | --bind | --bin | --bi)
-    ac_prev=bindir ;;
-  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
-    bindir=$ac_optarg ;;
-
-  -build | --build | --buil | --bui | --bu)
-    ac_prev=build_alias ;;
-  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
-    build_alias=$ac_optarg ;;
-
-  -cache-file | --cache-file | --cache-fil | --cache-fi \
-  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
-    ac_prev=cache_file ;;
-  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
-  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
-    cache_file=$ac_optarg ;;
-
-  --config-cache | -C)
-    cache_file=config.cache ;;
-
-  -datadir | --datadir | --datadi | --datad)
-    ac_prev=datadir ;;
-  -datadir=* | --datadir=* | --datadi=* | --datad=*)
-    datadir=$ac_optarg ;;
-
-  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
-  | --dataroo | --dataro | --datar)
-    ac_prev=datarootdir ;;
-  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
-  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
-    datarootdir=$ac_optarg ;;
-
-  -disable-* | --disable-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid feature name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"enable_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
-        ac_unrecognized_sep=', ';;
-    esac
-    eval enable_$ac_useropt=no ;;
-
-  -docdir | --docdir | --docdi | --doc | --do)
-    ac_prev=docdir ;;
-  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
-    docdir=$ac_optarg ;;
-
-  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
-    ac_prev=dvidir ;;
-  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
-    dvidir=$ac_optarg ;;
-
-  -enable-* | --enable-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid feature name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"enable_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
-        ac_unrecognized_sep=', ';;
-    esac
-    eval enable_$ac_useropt=\$ac_optarg ;;
-
-  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
-  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
-  | --exec | --exe | --ex)
-    ac_prev=exec_prefix ;;
-  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
-  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
-  | --exec=* | --exe=* | --ex=*)
-    exec_prefix=$ac_optarg ;;
-
-  -gas | --gas | --ga | --g)
-    # Obsolete; use --with-gas.
-    with_gas=yes ;;
-
-  -help | --help | --hel | --he | -h)
-    ac_init_help=long ;;
-  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
-    ac_init_help=recursive ;;
-  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
-    ac_init_help=short ;;
-
-  -host | --host | --hos | --ho)
-    ac_prev=host_alias ;;
-  -host=* | --host=* | --hos=* | --ho=*)
-    host_alias=$ac_optarg ;;
-
-  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
-    ac_prev=htmldir ;;
-  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
-  | --ht=*)
-    htmldir=$ac_optarg ;;
-
-  -includedir | --includedir | --includedi | --included | --include \
-  | --includ | --inclu | --incl | --inc)
-    ac_prev=includedir ;;
-  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
-  | --includ=* | --inclu=* | --incl=* | --inc=*)
-    includedir=$ac_optarg ;;
-
-  -infodir | --infodir | --infodi | --infod | --info | --inf)
-    ac_prev=infodir ;;
-  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
-    infodir=$ac_optarg ;;
-
-  -libdir | --libdir | --libdi | --libd)
-    ac_prev=libdir ;;
-  -libdir=* | --libdir=* | --libdi=* | --libd=*)
-    libdir=$ac_optarg ;;
-
-  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
-  | --libexe | --libex | --libe)
-    ac_prev=libexecdir ;;
-  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
-  | --libexe=* | --libex=* | --libe=*)
-    libexecdir=$ac_optarg ;;
-
-  -localedir | --localedir | --localedi | --localed | --locale)
-    ac_prev=localedir ;;
-  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
-    localedir=$ac_optarg ;;
-
-  -localstatedir | --localstatedir | --localstatedi | --localstated \
-  | --localstate | --localstat | --localsta | --localst | --locals)
-    ac_prev=localstatedir ;;
-  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
-  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
-    localstatedir=$ac_optarg ;;
-
-  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
-    ac_prev=mandir ;;
-  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
-    mandir=$ac_optarg ;;
-
-  -nfp | --nfp | --nf)
-    # Obsolete; use --without-fp.
-    with_fp=no ;;
-
-  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
-  | --no-cr | --no-c | -n)
-    no_create=yes ;;
-
-  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
-  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
-    no_recursion=yes ;;
-
-  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
-  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
-  | --oldin | --oldi | --old | --ol | --o)
-    ac_prev=oldincludedir ;;
-  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
-  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
-  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
-    oldincludedir=$ac_optarg ;;
-
-  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
-    ac_prev=prefix ;;
-  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
-    prefix=$ac_optarg ;;
-
-  -program-prefix | --program-prefix | --program-prefi | --program-pref \
-  | --program-pre | --program-pr | --program-p)
-    ac_prev=program_prefix ;;
-  -program-prefix=* | --program-prefix=* | --program-prefi=* \
-  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
-    program_prefix=$ac_optarg ;;
-
-  -program-suffix | --program-suffix | --program-suffi | --program-suff \
-  | --program-suf | --program-su | --program-s)
-    ac_prev=program_suffix ;;
-  -program-suffix=* | --program-suffix=* | --program-suffi=* \
-  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
-    program_suffix=$ac_optarg ;;
-
-  -program-transform-name | --program-transform-name \
-  | --program-transform-nam | --program-transform-na \
-  | --program-transform-n | --program-transform- \
-  | --program-transform | --program-transfor \
-  | --program-transfo | --program-transf \
-  | --program-trans | --program-tran \
-  | --progr-tra | --program-tr | --program-t)
-    ac_prev=program_transform_name ;;
-  -program-transform-name=* | --program-transform-name=* \
-  | --program-transform-nam=* | --program-transform-na=* \
-  | --program-transform-n=* | --program-transform-=* \
-  | --program-transform=* | --program-transfor=* \
-  | --program-transfo=* | --program-transf=* \
-  | --program-trans=* | --program-tran=* \
-  | --progr-tra=* | --program-tr=* | --program-t=*)
-    program_transform_name=$ac_optarg ;;
-
-  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
-    ac_prev=pdfdir ;;
-  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
-    pdfdir=$ac_optarg ;;
-
-  -psdir | --psdir | --psdi | --psd | --ps)
-    ac_prev=psdir ;;
-  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
-    psdir=$ac_optarg ;;
-
-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-  | -silent | --silent | --silen | --sile | --sil)
-    silent=yes ;;
-
-  -runstatedir | --runstatedir | --runstatedi | --runstated \
-  | --runstate | --runstat | --runsta | --runst | --runs \
-  | --run | --ru | --r)
-    ac_prev=runstatedir ;;
-  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
-  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
-  | --run=* | --ru=* | --r=*)
-    runstatedir=$ac_optarg ;;
-
-  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
-    ac_prev=sbindir ;;
-  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
-  | --sbi=* | --sb=*)
-    sbindir=$ac_optarg ;;
-
-  -sharedstatedir | --sharedstatedir | --sharedstatedi \
-  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
-  | --sharedst | --shareds | --shared | --share | --shar \
-  | --sha | --sh)
-    ac_prev=sharedstatedir ;;
-  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
-  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
-  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
-  | --sha=* | --sh=*)
-    sharedstatedir=$ac_optarg ;;
-
-  -site | --site | --sit)
-    ac_prev=site ;;
-  -site=* | --site=* | --sit=*)
-    site=$ac_optarg ;;
-
-  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
-    ac_prev=srcdir ;;
-  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
-    srcdir=$ac_optarg ;;
-
-  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
-  | --syscon | --sysco | --sysc | --sys | --sy)
-    ac_prev=sysconfdir ;;
-  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
-  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
-    sysconfdir=$ac_optarg ;;
-
-  -target | --target | --targe | --targ | --tar | --ta | --t)
-    ac_prev=target_alias ;;
-  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
-    target_alias=$ac_optarg ;;
-
-  -v | -verbose | --verbose | --verbos | --verbo | --verb)
-    verbose=yes ;;
-
-  -version | --version | --versio | --versi | --vers | -V)
-    ac_init_version=: ;;
-
-  -with-* | --with-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid package name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"with_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
-        ac_unrecognized_sep=', ';;
-    esac
-    eval with_$ac_useropt=\$ac_optarg ;;
-
-  -without-* | --without-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid package name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"with_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
-        ac_unrecognized_sep=', ';;
-    esac
-    eval with_$ac_useropt=no ;;
-
-  --x)
-    # Obsolete; use --with-x.
-    with_x=yes ;;
-
-  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
-  | --x-incl | --x-inc | --x-in | --x-i)
-    ac_prev=x_includes ;;
-  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
-  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
-    x_includes=$ac_optarg ;;
-
-  -x-libraries | --x-libraries | --x-librarie | --x-librari \
-  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
-    ac_prev=x_libraries ;;
-  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
-  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
-    x_libraries=$ac_optarg ;;
-
-  -*) as_fn_error $? "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information"
-    ;;
-
-  *=*)
-    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
-    # Reject names that are not valid shell variable names.
-    case $ac_envvar in #(
-      '' | [0-9]* | *[!_$as_cr_alnum]* )
-      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
-    esac
-    eval $ac_envvar=\$ac_optarg
-    export $ac_envvar ;;
-
-  *)
-    # FIXME: should be removed in autoconf 3.0.
-    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
-    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
-      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
-    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
-    ;;
-
-  esac
-done
-
-if test -n "$ac_prev"; then
-  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
-  as_fn_error $? "missing argument to $ac_option"
-fi
-
-if test -n "$ac_unrecognized_opts"; then
-  case $enable_option_checking in
-    no) ;;
-    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
-    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
-  esac
-fi
-
-# Check all directory arguments for consistency.
-for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
-               datadir sysconfdir sharedstatedir localstatedir includedir \
-               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-               libdir localedir mandir runstatedir
-do
-  eval ac_val=\$$ac_var
-  # Remove trailing slashes.
-  case $ac_val in
-    */ )
-      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
-      eval $ac_var=\$ac_val;;
-  esac
-  # Be sure to have absolute directory names.
-  case $ac_val in
-    [\\/$]* | ?:[\\/]* )  continue;;
-    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
-  esac
-  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
-done
-
-# There might be people who depend on the old broken behavior: `$host'
-# used to hold the argument of --host etc.
-# FIXME: To remove some day.
-build=$build_alias
-host=$host_alias
-target=$target_alias
-
-# FIXME: To remove some day.
-if test "x$host_alias" != x; then
-  if test "x$build_alias" = x; then
-    cross_compiling=maybe
-  elif test "x$build_alias" != "x$host_alias"; then
-    cross_compiling=yes
-  fi
-fi
-
-ac_tool_prefix=
-test -n "$host_alias" && ac_tool_prefix=$host_alias-
-
-test "$silent" = yes && exec 6>/dev/null
-
-
-ac_pwd=`pwd` && test -n "$ac_pwd" &&
-ac_ls_di=`ls -di .` &&
-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
-  as_fn_error $? "working directory cannot be determined"
-test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
-  as_fn_error $? "pwd does not report name of working directory"
-
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
-  ac_srcdir_defaulted=yes
-  # Try the directory containing this script, then the parent directory.
-  ac_confdir=`$as_dirname -- "$as_myself" ||
-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_myself" : 'X\(//\)[^/]' \| \
-        X"$as_myself" : 'X\(//\)$' \| \
-        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_myself" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-  srcdir=$ac_confdir
-  if test ! -r "$srcdir/$ac_unique_file"; then
-    srcdir=..
-  fi
-else
-  ac_srcdir_defaulted=no
-fi
-if test ! -r "$srcdir/$ac_unique_file"; then
-  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
-  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
-fi
-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
-ac_abs_confdir=`(
-       cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
-       pwd)`
-# When building in place, set srcdir=.
-if test "$ac_abs_confdir" = "$ac_pwd"; then
-  srcdir=.
-fi
-# Remove unnecessary trailing slashes from srcdir.
-# Double slashes in file names in object file debugging info
-# mess up M-x gdb in Emacs.
-case $srcdir in
-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
-esac
-for ac_var in $ac_precious_vars; do
-  eval ac_env_${ac_var}_set=\${${ac_var}+set}
-  eval ac_env_${ac_var}_value=\$${ac_var}
-  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
-  eval ac_cv_env_${ac_var}_value=\$${ac_var}
-done
-
-#
-# Report the --help message.
-#
-if test "$ac_init_help" = "long"; then
-  # Omit some internal or obsolete options to make the list less imposing.
-  # This message is too long to be a string in the A/UX 3.1 sh.
-  cat <<_ACEOF
-\`configure' configures zfs 0.6.5.8 to adapt to many kinds of systems.
-
-Usage: $0 [OPTION]... [VAR=VALUE]...
-
-To assign environment variables (e.g., CC, CFLAGS...), specify them as
-VAR=VALUE.  See below for descriptions of some of the useful variables.
-
-Defaults for the options are specified in brackets.
-
-Configuration:
-  -h, --help              display this help and exit
-      --help=short        display options specific to this package
-      --help=recursive    display the short help of all the included packages
-  -V, --version           display version information and exit
-  -q, --quiet, --silent   do not print \`checking ...' messages
-      --cache-file=FILE   cache test results in FILE [disabled]
-  -C, --config-cache      alias for \`--cache-file=config.cache'
-  -n, --no-create         do not create output files
-      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
-
-Installation directories:
-  --prefix=PREFIX         install architecture-independent files in PREFIX
-                          [$ac_default_prefix]
-  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
-                          [PREFIX]
-
-By default, \`make install' will install all the files in
-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
-an installation prefix other than \`$ac_default_prefix' using \`--prefix',
-for instance \`--prefix=\$HOME'.
-
-For better control, use the options below.
-
-Fine tuning of the installation directories:
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --docdir=DIR            documentation root [DATAROOTDIR/doc/zfs]
-  --htmldir=DIR           html documentation [DOCDIR]
-  --dvidir=DIR            dvi documentation [DOCDIR]
-  --pdfdir=DIR            pdf documentation [DOCDIR]
-  --psdir=DIR             ps documentation [DOCDIR]
-_ACEOF
-
-  cat <<\_ACEOF
-
-Program names:
-  --program-prefix=PREFIX            prepend PREFIX to installed program names
-  --program-suffix=SUFFIX            append SUFFIX to installed program names
-  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
-
-System types:
-  --build=BUILD     configure for building on BUILD [guessed]
-  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
-  --target=TARGET   configure for building compilers for TARGET [HOST]
-_ACEOF
-fi
-
-if test -n "$ac_init_help"; then
-  case $ac_init_help in
-     short | recursive ) echo "Configuration of zfs 0.6.5.8:";;
-   esac
-  cat <<\_ACEOF
-
-Optional Features:
-  --disable-option-checking  ignore unrecognized --enable/--with options
-  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
-  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
-  --enable-maintainer-mode
-                          enable make rules and dependencies not useful (and
-                          sometimes confusing) to the casual installer
-  --enable-silent-rules   less verbose build output (undo: "make V=1")
-  --disable-silent-rules  verbose build output (undo: "make V=0")
-  --enable-dependency-tracking
-                          do not reject slow dependency extractors
-  --disable-dependency-tracking
-                          speeds up one-time build
-  --enable-shared[=PKGS]  build shared libraries [default=yes]
-  --enable-static[=PKGS]  build static libraries [default=yes]
-  --enable-fast-install[=PKGS]
-                          optimize for fast installation [default=yes]
-  --disable-libtool-lock  avoid locking (might break parallel builds)
-  --enable-linux-builtin  Configure for builtin in-tree kernel modules
-                          [default=no]
-  --enable-systemd        install systemd unit/preset files [[default: yes]]
-  --enable-sysvinit       install SysV init scripts [default: yes]
-  --enable-debug          Enable generic debug support [default=no]
-  --enable-debug-dmu-tx   Enable dmu tx validation [default=no]
-
-Optional Packages:
-  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
-  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
-  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
-                          both]
-  --with-aix-soname=aix|svr4|both
-                          shared library versioning (aka "SONAME") variant to
-                          provide on AIX, [default=aix].
-  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
-  --with-sysroot[=DIR]    Search for dependent libraries within DIR (or the
-                          compiler's sysroot if not specified).
-  --with-spec=SPEC        Spec files 'generic|redhat'
-  --with-config=CONFIG    Config file 'kernel|user|all|srpm'
-  --with-mounthelperdir=DIR
-                          install mount.zfs in dir [[/sbin]]
-  --with-udevdir=DIR      install udev helpers [default=check]
-  --with-udevruledir=DIR  install udev rules [[UDEVDIR/rules.d]]
-  --with-systemdunitdir=DIR
-                          install systemd unit files in dir
-                          [[/usr/lib/systemd/system]]
-  --with-systemdpresetdir=DIR
-                          install systemd preset files in dir
-                          [[/usr/lib/systemd/system-preset]]
-  --with-systemdmodulesloaddir=DIR
-                          install systemd module load files into dir
-                          [[/usr/lib/modules-load.d]]
-  --with-dracutdir=DIR    install dracut helpers [default=check]
-  --with-blkid            support blkid caching [default=check]
-  --with-linux=PATH       Path to kernel source
-  --with-linux-obj=PATH   Path to kernel build objects
-  --with-spl=PATH         Path to spl source
-  --with-spl-obj=PATH     Path to spl build objects
-  --with-spl-timeout=SECS Wait SECS for SPL header and symver file [default=0]
-
-Some influential environment variables:
-  CC          C compiler command
-  CFLAGS      C compiler flags
-  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
-              nonstandard directory <lib dir>
-  LIBS        libraries to pass to the linker, e.g. -l<library>
-  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
-              you have headers in a nonstandard directory <include dir>
-  LT_SYS_LIBRARY_PATH
-              User-defined run-time library search path.
-  CPP         C preprocessor
-  CCAS        assembler compiler command (defaults to CC)
-  CCASFLAGS   assembler compiler flags (defaults to CFLAGS)
-
-Use these variables to override the choices made by `configure' or to help
-it to find libraries and programs with nonstandard names/locations.
-
-Report bugs to the package provider.
-_ACEOF
-ac_status=$?
-fi
-
-if test "$ac_init_help" = "recursive"; then
-  # If there are subdirs, report their specific --help.
-  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
-    test -d "$ac_dir" ||
-      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
-      continue
-    ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
-  # A ".." for each directory in $ac_dir_suffix.
-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
-  case $ac_top_builddir_sub in
-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
-  esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
-  .)  # We are building in place.
-    ac_srcdir=.
-    ac_top_srcdir=$ac_top_builddir_sub
-    ac_abs_top_srcdir=$ac_pwd ;;
-  [\\/]* | ?:[\\/]* )  # Absolute name.
-    ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir
-    ac_abs_top_srcdir=$srcdir ;;
-  *) # Relative name.
-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_build_prefix$srcdir
-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-    cd "$ac_dir" || { ac_status=$?; continue; }
-    # Check for guested configure.
-    if test -f "$ac_srcdir/configure.gnu"; then
-      echo &&
-      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
-    elif test -f "$ac_srcdir/configure"; then
-      echo &&
-      $SHELL "$ac_srcdir/configure" --help=recursive
-    else
-      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
-    fi || ac_status=$?
-    cd "$ac_pwd" || { ac_status=$?; break; }
-  done
-fi
-
-test -n "$ac_init_help" && exit $ac_status
-if $ac_init_version; then
-  cat <<\_ACEOF
-zfs configure 0.6.5.8
-generated by GNU Autoconf 2.69
-
-Copyright (C) 2012 Free Software Foundation, Inc.
-This configure script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it.
-_ACEOF
-  exit
-fi
-
-## ------------------------ ##
-## Autoconf initialization. ##
-## ------------------------ ##
-
-# ac_fn_c_try_compile LINENO
-# --------------------------
-# Try to compile conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_compile ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  rm -f conftest.$ac_objext
-  if { { ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_compile") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest.$ac_objext; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_retval=1
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_compile
-
-# ac_fn_c_try_link LINENO
-# -----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_link ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  rm -f conftest.$ac_objext conftest$ac_exeext
-  if { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && {
-        test -z "$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        test -x conftest$ac_exeext
-       }; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_retval=1
-fi
-  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
-  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
-  # interfere with the next link command; also delete a directory that is
-  # left behind by Apple's compiler.  We do this before executing the actions.
-  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_link
-
-# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists and can be compiled using the include files in
-# INCLUDES, setting the cache variable VAR accordingly.
-ac_fn_c_check_header_compile ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  eval "$3=yes"
-else
-  eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_compile
-
-# ac_fn_c_try_cpp LINENO
-# ----------------------
-# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_cpp ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if { { ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } > conftest.i && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-    ac_retval=1
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_cpp
-
-# ac_fn_c_try_run LINENO
-# ----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
-# that executables *can* be run.
-ac_fn_c_try_run ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
-  { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: program exited with status $ac_status" >&5
-       $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-       ac_retval=$ac_status
-fi
-  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_run
-
-# ac_fn_c_check_func LINENO FUNC VAR
-# ----------------------------------
-# Tests whether FUNC exists, setting the cache variable VAR accordingly
-ac_fn_c_check_func ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $2 innocuous_$2
-
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $2 (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
-
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-
-#undef $2
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $2 ();
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined __stub_$2 || defined __stub___$2
-choke me
-#endif
-
-int
-main ()
-{
-return $2 ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  eval "$3=yes"
-else
-  eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_func
-
-# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists, giving a warning if it cannot be compiled using
-# the include files in INCLUDES and setting the cache variable VAR
-# accordingly.
-ac_fn_c_check_header_mongrel ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if eval \${$3+:} false; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
-$as_echo_n "checking $2 usability... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_header_compiler=yes
-else
-  ac_header_compiler=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
-$as_echo_n "checking $2 presence... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <$2>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  ac_header_preproc=yes
-else
-  ac_header_preproc=no
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
-  yes:no: )
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-    ;;
-esac
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  eval "$3=\$ac_header_compiler"
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_mongrel
-cat >config.log <<_ACEOF
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-
-It was created by zfs $as_me 0.6.5.8, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
-
-  $ $0 $@
-
-_ACEOF
-exec 5>>config.log
-{
-cat <<_ASUNAME
-## --------- ##
-## Platform. ##
-## --------- ##
-
-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
-
-/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
-/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
-/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
-
-_ASUNAME
-
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    $as_echo "PATH: $as_dir"
-  done
-IFS=$as_save_IFS
-
-} >&5
-
-cat >&5 <<_ACEOF
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-_ACEOF
-
-
-# Keep a trace of the command line.
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Strip out --silent because we don't want to record it for future runs.
-# Also quote any args containing shell meta-characters.
-# Make two passes to allow for proper duplicate-argument suppression.
-ac_configure_args=
-ac_configure_args0=
-ac_configure_args1=
-ac_must_keep_next=false
-for ac_pass in 1 2
-do
-  for ac_arg
-  do
-    case $ac_arg in
-    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
-    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-    | -silent | --silent | --silen | --sile | --sil)
-      continue ;;
-    *\'*)
-      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    esac
-    case $ac_pass in
-    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
-    2)
-      as_fn_append ac_configure_args1 " '$ac_arg'"
-      if test $ac_must_keep_next = true; then
-       ac_must_keep_next=false # Got value, back to normal.
-      else
-       case $ac_arg in
-         *=* | --config-cache | -C | -disable-* | --disable-* \
-         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
-         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
-         | -with-* | --with-* | -without-* | --without-* | --x)
-           case "$ac_configure_args0 " in
-             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
-           esac
-           ;;
-         -* ) ac_must_keep_next=true ;;
-       esac
-      fi
-      as_fn_append ac_configure_args " '$ac_arg'"
-      ;;
-    esac
-  done
-done
-{ ac_configure_args0=; unset ac_configure_args0;}
-{ ac_configure_args1=; unset ac_configure_args1;}
-
-# When interrupted or exit'd, cleanup temporary files, and complete
-# config.log.  We remove comments because anyway the quotes in there
-# would cause problems or look ugly.
-# WARNING: Use '\'' to represent an apostrophe within the trap.
-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
-trap 'exit_status=$?
-  # Save into config.log some information that might help in debugging.
-  {
-    echo
-
-    $as_echo "## ---------------- ##
-## Cache variables. ##
-## ---------------- ##"
-    echo
-    # The following way of writing the cache mishandles newlines in values,
-(
-  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
-    eval ac_val=\$$ac_var
-    case $ac_val in #(
-    *${as_nl}*)
-      case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
-      esac
-      case $ac_var in #(
-      _ | IFS | as_nl) ;; #(
-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) { eval $ac_var=; unset $ac_var;} ;;
-      esac ;;
-    esac
-  done
-  (set) 2>&1 |
-    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
-    *${as_nl}ac_space=\ *)
-      sed -n \
-       "s/'\''/'\''\\\\'\'''\''/g;
-         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
-      ;; #(
-    *)
-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
-      ;;
-    esac |
-    sort
-)
-    echo
-
-    $as_echo "## ----------------- ##
-## Output variables. ##
-## ----------------- ##"
-    echo
-    for ac_var in $ac_subst_vars
-    do
-      eval ac_val=\$$ac_var
-      case $ac_val in
-      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
-      esac
-      $as_echo "$ac_var='\''$ac_val'\''"
-    done | sort
-    echo
-
-    if test -n "$ac_subst_files"; then
-      $as_echo "## ------------------- ##
-## File substitutions. ##
-## ------------------- ##"
-      echo
-      for ac_var in $ac_subst_files
-      do
-       eval ac_val=\$$ac_var
-       case $ac_val in
-       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
-       esac
-       $as_echo "$ac_var='\''$ac_val'\''"
-      done | sort
-      echo
-    fi
-
-    if test -s confdefs.h; then
-      $as_echo "## ----------- ##
-## confdefs.h. ##
-## ----------- ##"
-      echo
-      cat confdefs.h
-      echo
-    fi
-    test "$ac_signal" != 0 &&
-      $as_echo "$as_me: caught signal $ac_signal"
-    $as_echo "$as_me: exit $exit_status"
-  } >&5
-  rm -f core *.core core.conftest.* &&
-    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
-    exit $exit_status
-' 0
-for ac_signal in 1 2 13 15; do
-  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
-done
-ac_signal=0
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -f -r conftest* confdefs.h
-
-$as_echo "/* confdefs.h */" > confdefs.h
-
-# Predefined preprocessor variables.
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_NAME "$PACKAGE_NAME"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_VERSION "$PACKAGE_VERSION"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_STRING "$PACKAGE_STRING"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_URL "$PACKAGE_URL"
-_ACEOF
-
-
-# Let the site file select an alternate cache file if it wants to.
-# Prefer an explicitly selected file to automatically selected ones.
-ac_site_file1=NONE
-ac_site_file2=NONE
-if test -n "$CONFIG_SITE"; then
-  # We do not want a PATH search for config.site.
-  case $CONFIG_SITE in #((
-    -*)  ac_site_file1=./$CONFIG_SITE;;
-    */*) ac_site_file1=$CONFIG_SITE;;
-    *)   ac_site_file1=./$CONFIG_SITE;;
-  esac
-elif test "x$prefix" != xNONE; then
-  ac_site_file1=$prefix/share/config.site
-  ac_site_file2=$prefix/etc/config.site
-else
-  ac_site_file1=$ac_default_prefix/share/config.site
-  ac_site_file2=$ac_default_prefix/etc/config.site
-fi
-for ac_site_file in "$ac_site_file1" "$ac_site_file2"
-do
-  test "x$ac_site_file" = xNONE && continue
-  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-$as_echo "$as_me: loading site script $ac_site_file" >&6;}
-    sed 's/^/| /' "$ac_site_file" >&5
-    . "$ac_site_file" \
-      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
-  fi
-done
-
-if test -r "$cache_file"; then
-  # Some versions of bash will fail to source /dev/null (special files
-  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
-  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-$as_echo "$as_me: loading cache $cache_file" >&6;}
-    case $cache_file in
-      [\\/]* | ?:[\\/]* ) . "$cache_file";;
-      *)                      . "./$cache_file";;
-    esac
-  fi
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-$as_echo "$as_me: creating cache $cache_file" >&6;}
-  >$cache_file
-fi
-
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
-  eval ac_old_set=\$ac_cv_env_${ac_var}_set
-  eval ac_new_set=\$ac_env_${ac_var}_set
-  eval ac_old_val=\$ac_cv_env_${ac_var}_value
-  eval ac_new_val=\$ac_env_${ac_var}_value
-  case $ac_old_set,$ac_new_set in
-    set,)
-      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
-      ac_cache_corrupted=: ;;
-    ,set)
-      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
-      ac_cache_corrupted=: ;;
-    ,);;
-    *)
-      if test "x$ac_old_val" != "x$ac_new_val"; then
-       # differences in whitespace do not lead to failure.
-       ac_old_val_w=`echo x $ac_old_val`
-       ac_new_val_w=`echo x $ac_new_val`
-       if test "$ac_old_val_w" != "$ac_new_val_w"; then
-         { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
-         ac_cache_corrupted=:
-       else
-         { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
-         eval $ac_var=\$ac_old_val
-       fi
-       { $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
-$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
-       { $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
-$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
-      fi;;
-  esac
-  # Pass precious variables to config.status.
-  if test "$ac_new_set" = set; then
-    case $ac_new_val in
-    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
-    *) ac_arg=$ac_var=$ac_new_val ;;
-    esac
-    case " $ac_configure_args " in
-      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
-      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
-    esac
-  fi
-done
-if $ac_cache_corrupted; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
-  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
-fi
-## -------------------- ##
-## Main body of script. ##
-## -------------------- ##
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-
-
-
-       for ac_prog in gawk mawk nawk awk
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$AWK"; then
-  ac_cv_prog_AWK="$AWK" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_AWK="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-AWK=$ac_cv_prog_AWK
-if test -n "$AWK"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
-$as_echo "$AWK" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$AWK" && break
-done
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking metadata" >&5
-$as_echo_n "checking metadata... " >&6; }
-
-       META="$srcdir/META"
-       _zfs_ac_meta_type="none"
-       if test -f "$META"; then
-               _zfs_ac_meta_type="META file"
-               _dpkg_parsechangelog=$(dpkg-parsechangelog 2>/dev/null)
-
-               ZFS_META_NAME=`$AWK -F ':[ \t]+' '$1 ~ /^ *(Name|Project|Package)$/ { print $2; exit }' $META`;
-               if test -n "$ZFS_META_NAME"; then
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_NAME "$ZFS_META_NAME"
-_ACEOF
-
-
-               fi
-
-               ZFS_META_VERSION=`$AWK -F ':[ \t]+' '$1 ~ /^ *Version$/ { print $2; exit }' $META`;
-               if test -n "$ZFS_META_VERSION"; then
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_VERSION "$ZFS_META_VERSION"
-_ACEOF
-
-
-               fi
-
-               if test -n "${_dpkg_parsechangelog}"; then
-                       _dpkg_version=$(echo "${_dpkg_parsechangelog}" \
-                               | $AWK '$1 == "Version:" { print $2; }' \
-                               | cut -d- -f1)
-                       if test "${_dpkg_version}" != "$ZFS_META_VERSION"; then
-                               as_fn_error $? "
-       *** Version $ZFS_META_VERSION in the META file is different than
-       *** version $_dpkg_version in the debian/changelog file. DKMS and DEB
-       *** packaging require that these files have the same version.
-                               " "$LINENO" 5
-                       fi
-               fi
-
-               ZFS_META_RELEASE=`$AWK -F ':[ \t]+' '$1 ~ /^ *Release$/ { print $2; exit }' $META`;
-
-               if test -n "${_dpkg_parsechangelog}"; then
-                       _dpkg_release=$(echo "${_dpkg_parsechangelog}" \
-                               | $AWK '$1 == "Version:" { print $2; }' \
-                               | cut -d- -f2-)
-                       if test -n "${_dpkg_release}"; then
-                               ZFS_META_RELEASE=${_dpkg_release}
-                               _zfs_ac_meta_type="dpkg-parsechangelog"
-                       fi
-               elif test ! -f ".nogitrelease" && git rev-parse --git-dir > /dev/null 2>&1; then
-                       _match="${ZFS_META_NAME}-${ZFS_META_VERSION}"
-                       _alias=$(git describe --match=${_match} 2>/dev/null)
-                       _release=$(echo ${_alias}|cut -f3- -d'-'|sed 's/-/_/g')
-                       if test -n "${_release}"; then
-                               ZFS_META_RELEASE=${_release}
-                               _zfs_ac_meta_type="git describe"
-                       fi
-               fi
-
-               if test -n "$ZFS_META_RELEASE"; then
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_RELEASE "$ZFS_META_RELEASE"
-_ACEOF
-
-
-
-                       RELEASE="$ZFS_META_RELEASE"
-
-               fi
-
-               ZFS_META_LICENSE=`$AWK -F ':[ \t]+' '$1 ~ /^ *License$/ { print $2; exit }' $META`;
-               if test -n "$ZFS_META_LICENSE"; then
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_LICENSE "$ZFS_META_LICENSE"
-_ACEOF
-
-
-               fi
-
-               if test -n "$ZFS_META_NAME" -a -n "$ZFS_META_VERSION"; then
-                               ZFS_META_ALIAS="$ZFS_META_NAME-$ZFS_META_VERSION"
-                               test -n "$ZFS_META_RELEASE" &&
-                                       ZFS_META_ALIAS="$ZFS_META_ALIAS-$ZFS_META_RELEASE"
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_ALIAS "$ZFS_META_ALIAS"
-_ACEOF
-
-
-               fi
-
-               ZFS_META_DATA=`$AWK -F ':[ \t]+' '$1 ~ /^ *Date$/ { print $2; exit }' $META`;
-               if test -n "$ZFS_META_DATA"; then
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_DATA "$ZFS_META_DATA"
-_ACEOF
-
-
-               fi
-
-               ZFS_META_AUTHOR=`$AWK -F ':[ \t]+' '$1 ~ /^ *Author$/ { print $2; exit }' $META`;
-               if test -n "$ZFS_META_AUTHOR"; then
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_AUTHOR "$ZFS_META_AUTHOR"
-_ACEOF
-
-
-               fi
-
-
-               ZFS_META_LT_CURRENT=`$AWK -F ':[ \t]+' '$1 ~ /^ *LT_Current$/ { print $2; exit }' $META`;
-               ZFS_META_LT_REVISION=`$AWK -F ':[ \t]+' '$1 ~ /^ *LT_Revision$/ { print $2; exit }' $META`;
-               ZFS_META_LT_AGE=`$AWK -F ':[ \t]+' '$1 ~ /^ *LT_Age$/ { print $2; exit }' $META`;
-               if test -n "$ZFS_META_LT_CURRENT" \
-                                -o -n "$ZFS_META_LT_REVISION" \
-                                -o -n "$ZFS_META_LT_AGE"; then
-                       test -n "$ZFS_META_LT_CURRENT" || ZFS_META_LT_CURRENT="0"
-                       test -n "$ZFS_META_LT_REVISION" || ZFS_META_LT_REVISION="0"
-                       test -n "$ZFS_META_LT_AGE" || ZFS_META_LT_AGE="0"
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_LT_CURRENT "$ZFS_META_LT_CURRENT"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_LT_REVISION "$ZFS_META_LT_REVISION"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define ZFS_META_LT_AGE "$ZFS_META_LT_AGE"
-_ACEOF
-
-
-
-
-               fi
-       fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_zfs_ac_meta_type" >&5
-$as_echo "$_zfs_ac_meta_type" >&6; }
-
-
-ac_aux_dir=
-for ac_dir in config "$srcdir"/config; do
-  if test -f "$ac_dir/install-sh"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install-sh -c"
-    break
-  elif test -f "$ac_dir/install.sh"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install.sh -c"
-    break
-  elif test -f "$ac_dir/shtool"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/shtool install -c"
-    break
-  fi
-done
-if test -z "$ac_aux_dir"; then
-  as_fn_error $? "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5
-fi
-
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
-ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
-ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
-
-
-
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
-  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
-  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
-  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
-  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test "x$host_alias" = x; then
-  ac_cv_host=$ac_cv_build
-else
-  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
-    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
-$as_echo_n "checking target system type... " >&6; }
-if ${ac_cv_target+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test "x$target_alias" = x; then
-  ac_cv_target=$ac_cv_host
-else
-  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
-    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
-$as_echo "$ac_cv_target" >&6; }
-case $ac_cv_target in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
-esac
-target=$ac_cv_target
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_target
-shift
-target_cpu=$1
-target_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-target_os=$*
-IFS=$ac_save_IFS
-case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
-
-
-# The aliases save the names the user supplied, while $host etc.
-# will get canonicalized.
-test -n "$target_alias" &&
-  test "$program_prefix$program_suffix$program_transform_name" = \
-    NONENONEs,x,x, &&
-  program_prefix=${target_alias}-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
-$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
-    # Check whether --enable-maintainer-mode was given.
-if test "${enable_maintainer_mode+set}" = set; then :
-  enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
-else
-  USE_MAINTAINER_MODE=no
-fi
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
-$as_echo "$USE_MAINTAINER_MODE" >&6; }
-   if test $USE_MAINTAINER_MODE = yes; then
-  MAINTAINER_MODE_TRUE=
-  MAINTAINER_MODE_FALSE='#'
-else
-  MAINTAINER_MODE_TRUE='#'
-  MAINTAINER_MODE_FALSE=
-fi
-
-  MAINT=$MAINTAINER_MODE_TRUE
-
-
-# Check whether --enable-silent-rules was given.
-if test "${enable_silent_rules+set}" = set; then :
-  enableval=$enable_silent_rules;
-fi
-
-case $enable_silent_rules in # (((
-  yes) AM_DEFAULT_VERBOSITY=0;;
-   no) AM_DEFAULT_VERBOSITY=1;;
-    *) AM_DEFAULT_VERBOSITY=0;;
-esac
-am_make=${MAKE-make}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
-$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
-if ${am_cv_make_support_nested_variables+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if $as_echo 'TRUE=$(BAR$(V))
-BAR0=false
-BAR1=true
-V=1
-am__doit:
-       @$(TRUE)
-.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
-  am_cv_make_support_nested_variables=yes
-else
-  am_cv_make_support_nested_variables=no
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
-$as_echo "$am_cv_make_support_nested_variables" >&6; }
-if test $am_cv_make_support_nested_variables = yes; then
-    AM_V='$(V)'
-  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
-else
-  AM_V=$AM_DEFAULT_VERBOSITY
-  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
-fi
-AM_BACKSLASH='\'
-
-am__api_version='1.15'
-
-# Find a good install program.  We prefer a C program (faster),
-# so one script is as good as another.  But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AmigaOS /C/install, which installs bootblocks on floppy discs
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# OS/2's system install, which has a completely different semantic
-# ./install, which can be erroneously created by make from ./install.sh.
-# Reject install programs that cannot install multiple files.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-$as_echo_n "checking for a BSD-compatible install... " >&6; }
-if test -z "$INSTALL"; then
-if ${ac_cv_path_install+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in #((
-  ./ | .// | /[cC]/* | \
-  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
-  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
-  /usr/ucb/* ) ;;
-  *)
-    # OSF1 and SCO ODT 3.0 have their own names for install.
-    # Don't use installbsd from OSF since it installs stuff as root
-    # by default.
-    for ac_prog in ginstall scoinst install; do
-      for ac_exec_ext in '' $ac_executable_extensions; do
-       if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
-         if test $ac_prog = install &&
-           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
-           # AIX install.  It has an incompatible calling convention.
-           :
-         elif test $ac_prog = install &&
-           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
-           # program-specific install script used by HP pwplus--don't use.
-           :
-         else
-           rm -rf conftest.one conftest.two conftest.dir
-           echo one > conftest.one
-           echo two > conftest.two
-           mkdir conftest.dir
-           if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
-             test -s conftest.one && test -s conftest.two &&
-             test -s conftest.dir/conftest.one &&
-             test -s conftest.dir/conftest.two
-           then
-             ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
-             break 3
-           fi
-         fi
-       fi
-      done
-    done
-    ;;
-esac
-
-  done
-IFS=$as_save_IFS
-
-rm -rf conftest.one conftest.two conftest.dir
-
-fi
-  if test "${ac_cv_path_install+set}" = set; then
-    INSTALL=$ac_cv_path_install
-  else
-    # As a last resort, use the slow shell script.  Don't cache a
-    # value for INSTALL within a source directory, because that will
-    # break other packages using the cache if that directory is
-    # removed, or if the value is a relative name.
-    INSTALL=$ac_install_sh
-  fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-$as_echo "$INSTALL" >&6; }
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
-$as_echo_n "checking whether build environment is sane... " >&6; }
-# Reject unsafe characters in $srcdir or the absolute working directory
-# name.  Accept space and tab only in the latter.
-am_lf='
-'
-case `pwd` in
-  *[\\\"\#\$\&\'\`$am_lf]*)
-    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
-esac
-case $srcdir in
-  *[\\\"\#\$\&\'\`$am_lf\ \    ]*)
-    as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
-esac
-
-# Do 'set' in a subshell so we don't clobber the current shell's
-# arguments.  Must try -L first in case configure is actually a
-# symlink; some systems play weird games with the mod time of symlinks
-# (eg FreeBSD returns the mod time of the symlink's containing
-# directory).
-if (
-   am_has_slept=no
-   for am_try in 1 2; do
-     echo "timestamp, slept: $am_has_slept" > conftest.file
-     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
-     if test "$*" = "X"; then
-       # -L didn't work.
-       set X `ls -t "$srcdir/configure" conftest.file`
-     fi
-     if test "$*" != "X $srcdir/configure conftest.file" \
-       && test "$*" != "X conftest.file $srcdir/configure"; then
-
-       # If neither matched, then we have a broken ls.  This can happen
-       # if, for instance, CONFIG_SHELL is bash and it inherits a
-       # broken ls alias from the environment.  This has actually
-       # happened.  Such a system could not be considered "sane".
-       as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
-  alias in your environment" "$LINENO" 5
-     fi
-     if test "$2" = conftest.file || test $am_try -eq 2; then
-       break
-     fi
-     # Just in case.
-     sleep 1
-     am_has_slept=yes
-   done
-   test "$2" = conftest.file
-   )
-then
-   # Ok.
-   :
-else
-   as_fn_error $? "newly created file is older than distributed files!
-Check your system clock" "$LINENO" 5
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-# If we didn't sleep, we still need to ensure time stamps of config.status and
-# generated files are strictly newer.
-am_sleep_pid=
-if grep 'slept: no' conftest.file >/dev/null 2>&1; then
-  ( sleep 1 ) &
-  am_sleep_pid=$!
-fi
-
-rm -f conftest.file
-
-test "$program_prefix" != NONE &&
-  program_transform_name="s&^&$program_prefix&;$program_transform_name"
-# Use a double $ so make ignores it.
-test "$program_suffix" != NONE &&
-  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
-# Double any \ or $.
-# By default was `s,x,x', remove it if useless.
-ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
-program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
-
-# Expand $ac_aux_dir to an absolute path.
-am_aux_dir=`cd "$ac_aux_dir" && pwd`
-
-if test x"${MISSING+set}" != xset; then
-  case $am_aux_dir in
-  *\ * | *\    *)
-    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
-  *)
-    MISSING="\${SHELL} $am_aux_dir/missing" ;;
-  esac
-fi
-# Use eval to expand $SHELL
-if eval "$MISSING --is-lightweight"; then
-  am_missing_run="$MISSING "
-else
-  am_missing_run=
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
-$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
-fi
-
-if test x"${install_sh+set}" != xset; then
-  case $am_aux_dir in
-  *\ * | *\    *)
-    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
-  *)
-    install_sh="\${SHELL} $am_aux_dir/install-sh"
-  esac
-fi
-
-# Installed binaries are usually stripped using 'strip' when the user
-# run "make install-strip".  However 'strip' might not be the right
-# tool to use in cross-compilation environments, therefore Automake
-# will honor the 'STRIP' environment variable to overrule this program.
-if test "$cross_compiling" != no; then
-  if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
-set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_STRIP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$STRIP"; then
-  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-STRIP=$ac_cv_prog_STRIP
-if test -n "$STRIP"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
-$as_echo "$STRIP" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_STRIP"; then
-  ac_ct_STRIP=$STRIP
-  # Extract the first word of "strip", so it can be a program name with args.
-set dummy strip; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_STRIP"; then
-  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_STRIP="strip"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
-if test -n "$ac_ct_STRIP"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
-$as_echo "$ac_ct_STRIP" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_STRIP" = x; then
-    STRIP=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    STRIP=$ac_ct_STRIP
-  fi
-else
-  STRIP="$ac_cv_prog_STRIP"
-fi
-
-fi
-INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
-$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
-if test -z "$MKDIR_P"; then
-  if ${ac_cv_path_mkdir+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in mkdir gmkdir; do
-        for ac_exec_ext in '' $ac_executable_extensions; do
-          as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
-          case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
-            'mkdir (GNU coreutils) '* | \
-            'mkdir (coreutils) '* | \
-            'mkdir (fileutils) '4.1*)
-              ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
-              break 3;;
-          esac
-        done
-       done
-  done
-IFS=$as_save_IFS
-
-fi
-
-  test -d ./--version && rmdir ./--version
-  if test "${ac_cv_path_mkdir+set}" = set; then
-    MKDIR_P="$ac_cv_path_mkdir -p"
-  else
-    # As a last resort, use the slow shell script.  Don't cache a
-    # value for MKDIR_P within a source directory, because that will
-    # break other packages using the cache if that directory is
-    # removed, or if the value is a relative name.
-    MKDIR_P="$ac_install_sh -d"
-  fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
-$as_echo "$MKDIR_P" >&6; }
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
-$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
-set x ${MAKE-make}
-ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
-if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat >conftest.make <<\_ACEOF
-SHELL = /bin/sh
-all:
-       @echo '@@@%%%=$(MAKE)=@@@%%%'
-_ACEOF
-# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
-case `${MAKE-make} -f conftest.make 2>/dev/null` in
-  *@@@%%%=?*=@@@%%%*)
-    eval ac_cv_prog_make_${ac_make}_set=yes;;
-  *)
-    eval ac_cv_prog_make_${ac_make}_set=no;;
-esac
-rm -f conftest.make
-fi
-if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-  SET_MAKE=
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-  SET_MAKE="MAKE=${MAKE-make}"
-fi
-
-rm -rf .tst 2>/dev/null
-mkdir .tst 2>/dev/null
-if test -d .tst; then
-  am__leading_dot=.
-else
-  am__leading_dot=_
-fi
-rmdir .tst 2>/dev/null
-
-if test "`cd $srcdir && pwd`" != "`pwd`"; then
-  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
-  # is not polluted with repeated "-I."
-  am__isrc=' -I$(srcdir)'
-  # test to see if srcdir already configured
-  if test -f $srcdir/config.status; then
-    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
-  fi
-fi
-
-# test whether we have cygpath
-if test -z "$CYGPATH_W"; then
-  if (cygpath --version) >/dev/null 2>/dev/null; then
-    CYGPATH_W='cygpath -w'
-  else
-    CYGPATH_W=echo
-  fi
-fi
-
-
-# Define the identity of the package.
- PACKAGE='zfs'
- VERSION='0.6.5.8'
-
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE "$PACKAGE"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define VERSION "$VERSION"
-_ACEOF
-
-# Some tools Automake needs.
-
-ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
-
-
-AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
-
-
-AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
-
-
-AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
-
-
-MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
-
-# For better backward compatibility.  To be removed once Automake 1.9.x
-# dies out for good.  For more background, see:
-# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
-# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
-mkdir_p='$(MKDIR_P)'
-
-# We need awk for the "check" target (and possibly the TAP driver).  The
-# system "awk" is bad on some platforms.
-# Always define AMTAR for backward compatibility.  Yes, it's still used
-# in the wild :-(  We should find a proper way to deprecate it ...
-AMTAR='$${TAR-tar}'
-
-
-# We'll loop over all known methods to create a tar archive until one works.
-_am_tools='gnutar  pax cpio none'
-
-am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
-
-
-
-
-
-
-# POSIX will say in a future version that running "rm -f" with no argument
-# is OK; and we want to be able to make that assumption in our Makefile
-# recipes.  So use an aggressive probe to check that the usage we want is
-# actually supported "in the wild" to an acceptable degree.
-# See automake bug#10828.
-# To make any issue more visible, cause the running configure to be aborted
-# by default if the 'rm' program in use doesn't match our expectations; the
-# user can still override this though.
-if rm -f && rm -fr && rm -rf; then : OK; else
-  cat >&2 <<'END'
-Oops!
-
-Your 'rm' program seems unable to run without file operands specified
-on the command line, even when the '-f' option is present.  This is contrary
-to the behaviour of most rm programs out there, and not conforming with
-the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
-
-Please tell bug-automake@gnu.org about your system, including the value
-of your $PATH and any error possibly output before this message.  This
-can help us improve future automake versions.
-
-END
-  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
-    echo 'Configuration will proceed anyway, since you have set the' >&2
-    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
-    echo >&2
-  else
-    cat >&2 <<'END'
-Aborting the configuration process, to ensure you take notice of the issue.
-
-You can download and install GNU coreutils to get an 'rm' implementation
-that behaves properly: <http://www.gnu.org/software/coreutils/>.
-
-If you want to complete the configuration process using your problematic
-'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
-to "yes", and re-run configure.
-
-END
-    as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
-  fi
-fi
-
-ac_config_headers="$ac_config_headers zfs_config.h"
-
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_CC="${ac_tool_prefix}gcc"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
-  ac_ct_CC=$CC
-  # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_CC="gcc"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_CC" = x; then
-    CC=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    CC=$ac_ct_CC
-  fi
-else
-  CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
-          if test -n "$ac_tool_prefix"; then
-    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_CC="${ac_tool_prefix}cc"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  fi
-fi
-if test -z "$CC"; then
-  # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-  ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
-       ac_prog_rejected=yes
-       continue
-     fi
-    ac_cv_prog_CC="cc"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-if test $ac_prog_rejected = yes; then
-  # We found a bogon in the path, so make sure we never use it.
-  set dummy $ac_cv_prog_CC
-  shift
-  if test $# != 0; then
-    # We chose a different compiler from the bogus one.
-    # However, it has the same basename, so the bogon will be chosen
-    # first if we set CC to just the basename; use the full file name.
-    shift
-    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
-  fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$CC"; then
-  if test -n "$ac_tool_prefix"; then
-  for ac_prog in cl.exe
-  do
-    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$CC"; then
-  ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-    test -n "$CC" && break
-  done
-fi
-if test -z "$CC"; then
-  ac_ct_CC=$CC
-  for ac_prog in cl.exe
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_CC="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$ac_ct_CC" && break
-done
-
-  if test "x$ac_ct_CC" = x; then
-    CC=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    CC=$ac_ct_CC
-  fi
-fi
-
-fi
-
-
-test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
-
-# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
-  { { ac_try="$ac_compiler $ac_option >&5"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    sed '10a\
-... rest of stderr output deleted ...
-         10q' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-  fi
-  rm -f conftest.er1 conftest.err
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-done
-
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
-# Try to create an executable without -o first, disregard a.out.
-# It will help us diagnose broken compilers, and finding out an intuition
-# of exeext.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-
-# The possible output files:
-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
-
-ac_rmfiles=
-for ac_file in $ac_files
-do
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
-    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
-  esac
-done
-rm -f $ac_rmfiles
-
-if { { ac_try="$ac_link_default"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link_default") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then :
-  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
-# in a Makefile.  We should not override ac_cv_exeext if it was cached,
-# so that the user can short-circuit this test for compilers unknown to
-# Autoconf.
-for ac_file in $ac_files ''
-do
-  test -f "$ac_file" || continue
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
-       ;;
-    [ab].out )
-       # We found the default executable, but exeext='' is most
-       # certainly right.
-       break;;
-    *.* )
-       if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
-       then :; else
-          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
-       fi
-       # We set ac_cv_exeext here because the later test for it is not
-       # safe: cross compilers may not add the suffix if given an `-o'
-       # argument, so we may need to know it at that point already.
-       # Even if this section looks crufty: it has the advantage of
-       # actually working.
-       break;;
-    * )
-       break;;
-  esac
-done
-test "$ac_cv_exeext" = no && ac_cv_exeext=
-
-else
-  ac_file=''
-fi
-if test -z "$ac_file"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-$as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "C compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
-ac_exeext=$ac_cv_exeext
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
-ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-$as_echo_n "checking for suffix of executables... " >&6; }
-if { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then :
-  # If both `conftest.exe' and `conftest' are `present' (well, observable)
-# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
-# work properly (i.e., refer to `conftest.exe'), while it won't with
-# `rm'.
-for ac_file in conftest.exe conftest conftest.*; do
-  test -f "$ac_file" || continue
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
-    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
-         break;;
-    * ) break;;
-  esac
-done
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest conftest$ac_cv_exeext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-$as_echo "$ac_cv_exeext" >&6; }
-
-rm -f conftest.$ac_ext
-EXEEXT=$ac_cv_exeext
-ac_exeext=$EXEEXT
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdio.h>
-int
-main ()
-{
-FILE *f = fopen ("conftest.out", "w");
- return ferror (f) || fclose (f) != 0;
-
-  ;
-  return 0;
-}
-_ACEOF
-ac_clean_files="$ac_clean_files conftest.out"
-# Check that the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
-if test "$cross_compiling" != yes; then
-  { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-  if { ac_try='./conftest$ac_cv_exeext'
-  { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then
-    cross_compiling=no
-  else
-    if test "$cross_compiling" = maybe; then
-       cross_compiling=yes
-    else
-       { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
-    fi
-  fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
-
-rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
-ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-$as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.o conftest.obj
-if { { ac_try="$ac_compile"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_compile") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then :
-  for ac_file in conftest.o conftest.obj conftest.*; do
-  test -f "$ac_file" || continue;
-  case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
-    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
-       break;;
-  esac
-done
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest.$ac_cv_objext conftest.$ac_ext
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-$as_echo "$ac_cv_objext" >&6; }
-OBJEXT=$ac_cv_objext
-ac_objext=$OBJEXT
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-#ifndef __GNUC__
-       choke me
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_compiler_gnu=yes
-else
-  ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
-if test $ac_compiler_gnu = yes; then
-  GCC=yes
-else
-  GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_save_c_werror_flag=$ac_c_werror_flag
-   ac_c_werror_flag=yes
-   ac_cv_prog_cc_g=no
-   CFLAGS="-g"
-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_prog_cc_g=yes
-else
-  CFLAGS=""
-      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-else
-  ac_c_werror_flag=$ac_save_c_werror_flag
-        CFLAGS="-g"
-        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_prog_cc_g=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-   ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
-  CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
-  if test "$GCC" = yes; then
-    CFLAGS="-g -O2"
-  else
-    CFLAGS="-g"
-  fi
-else
-  if test "$GCC" = yes; then
-    CFLAGS="-O2"
-  else
-    CFLAGS=
-  fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
-     char **p;
-     int i;
-{
-  return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
-  char *s;
-  va_list v;
-  va_start (v,p);
-  s = g (p, va_arg (v,int));
-  va_end (v);
-  return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
-   function prototypes and stuff, but not '\xHH' hex character constants.
-   These don't provoke an error unfortunately, instead are silently treated
-   as 'x'.  The following induces an error, until -std is added to get
-   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
-   array size at least.  It's necessary to write '\x00'==0 to get something
-   that's true only with -std.  */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
-
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
-   inside strings and character constants.  */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
-  ;
-  return 0;
-}
-_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
-       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
-  CC="$ac_save_CC $ac_arg"
-  if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_prog_cc_c89=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext
-  test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-
-fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
-  x)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
-  xno)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
-  *)
-    CC="$CC $ac_cv_prog_cc_c89"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c89" != xno; then :
-
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
-$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
-if ${am_cv_prog_cc_c_o+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-  # Make sure it works both with $CC and with simple cc.
-  # Following AC_PROG_CC_C_O, we do the test twice because some
-  # compilers refuse to overwrite an existing .o file with -o,
-  # though they will create one.
-  am_cv_prog_cc_c_o=yes
-  for am_i in 1 2; do
-    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
-   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
-   ac_status=$?
-   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-   (exit $ac_status); } \
-         && test -f conftest2.$ac_objext; then
-      : OK
-    else
-      am_cv_prog_cc_c_o=no
-      break
-    fi
-  done
-  rm -f core conftest*
-  unset am_i
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
-$as_echo "$am_cv_prog_cc_c_o" >&6; }
-if test "$am_cv_prog_cc_c_o" != yes; then
-   # Losing compiler, so override with the script.
-   # FIXME: It is wrong to rewrite CC.
-   # But if we don't then we get into trouble of one sort or another.
-   # A longer-term fix would be to have automake use am__CC in this case,
-   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
-   CC="$am_aux_dir/compile $CC"
-fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-DEPDIR="${am__leading_dot}deps"
-
-ac_config_commands="$ac_config_commands depfiles"
-
-
-am_make=${MAKE-make}
-cat > confinc << 'END'
-am__doit:
-       @echo this is the am__doit target
-.PHONY: am__doit
-END
-# If we don't find an include directive, just comment out the code.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
-$as_echo_n "checking for style of include used by $am_make... " >&6; }
-am__include="#"
-am__quote=
-_am_result=none
-# First try GNU make style include.
-echo "include confinc" > confmf
-# Ignore all kinds of additional output from 'make'.
-case `$am_make -s -f confmf 2> /dev/null` in #(
-*the\ am__doit\ target*)
-  am__include=include
-  am__quote=
-  _am_result=GNU
-  ;;
-esac
-# Now try BSD make style include.
-if test "$am__include" = "#"; then
-   echo '.include "confinc"' > confmf
-   case `$am_make -s -f confmf 2> /dev/null` in #(
-   *the\ am__doit\ target*)
-     am__include=.include
-     am__quote="\""
-     _am_result=BSD
-     ;;
-   esac
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
-$as_echo "$_am_result" >&6; }
-rm -f confinc confmf
-
-# Check whether --enable-dependency-tracking was given.
-if test "${enable_dependency_tracking+set}" = set; then :
-  enableval=$enable_dependency_tracking;
-fi
-
-if test "x$enable_dependency_tracking" != xno; then
-  am_depcomp="$ac_aux_dir/depcomp"
-  AMDEPBACKSLASH='\'
-  am__nodep='_no'
-fi
- if test "x$enable_dependency_tracking" != xno; then
-  AMDEP_TRUE=
-  AMDEP_FALSE='#'
-else
-  AMDEP_TRUE='#'
-  AMDEP_FALSE=
-fi
-
-
-
-depcc="$CC"   am_compiler_list=
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
-$as_echo_n "checking dependency style of $depcc... " >&6; }
-if ${am_cv_CC_dependencies_compiler_type+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
-  # We make a subdir and do the tests there.  Otherwise we can end up
-  # making bogus files that we don't know about and never remove.  For
-  # instance it was reported that on HP-UX the gcc test will end up
-  # making a dummy file named 'D' -- because '-MD' means "put the output
-  # in D".
-  rm -rf conftest.dir
-  mkdir conftest.dir
-  # Copy depcomp to subdir because otherwise we won't find it if we're
-  # using a relative directory.
-  cp "$am_depcomp" conftest.dir
-  cd conftest.dir
-  # We will build objects and dependencies in a subdirectory because
-  # it helps to detect inapplicable dependency modes.  For instance
-  # both Tru64's cc and ICC support -MD to output dependencies as a
-  # side effect of compilation, but ICC will put the dependencies in
-  # the current directory while Tru64 will put them in the object
-  # directory.
-  mkdir sub
-
-  am_cv_CC_dependencies_compiler_type=none
-  if test "$am_compiler_list" = ""; then
-     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
-  fi
-  am__universal=false
-  case " $depcc " in #(
-     *\ -arch\ *\ -arch\ *) am__universal=true ;;
-     esac
-
-  for depmode in $am_compiler_list; do
-    # Setup a source with many dependencies, because some compilers
-    # like to wrap large dependency lists on column 80 (with \), and
-    # we should not choose a depcomp mode which is confused by this.
-    #
-    # We need to recreate these files for each test, as the compiler may
-    # overwrite some of them when testing with obscure command lines.
-    # This happens at least with the AIX C compiler.
-    : > sub/conftest.c
-    for i in 1 2 3 4 5 6; do
-      echo '#include "conftst'$i'.h"' >> sub/conftest.c
-      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
-      # Solaris 10 /bin/sh.
-      echo '/* dummy */' > sub/conftst$i.h
-    done
-    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
-
-    # We check with '-c' and '-o' for the sake of the "dashmstdout"
-    # mode.  It turns out that the SunPro C++ compiler does not properly
-    # handle '-M -o', and we need to detect this.  Also, some Intel
-    # versions had trouble with output in subdirs.
-    am__obj=sub/conftest.${OBJEXT-o}
-    am__minus_obj="-o $am__obj"
-    case $depmode in
-    gcc)
-      # This depmode causes a compiler race in universal mode.
-      test "$am__universal" = false || continue
-      ;;
-    nosideeffect)
-      # After this tag, mechanisms are not by side-effect, so they'll
-      # only be used when explicitly requested.
-      if test "x$enable_dependency_tracking" = xyes; then
-       continue
-      else
-       break
-      fi
-      ;;
-    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
-      # This compiler won't grok '-c -o', but also, the minuso test has
-      # not run yet.  These depmodes are late enough in the game, and
-      # so weak that their functioning should not be impacted.
-      am__obj=conftest.${OBJEXT-o}
-      am__minus_obj=
-      ;;
-    none) break ;;
-    esac
-    if depmode=$depmode \
-       source=sub/conftest.c object=$am__obj \
-       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
-       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
-         >/dev/null 2>conftest.err &&
-       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
-       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
-       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
-       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
-      # icc doesn't choke on unknown options, it will just issue warnings
-      # or remarks (even with -Werror).  So we grep stderr for any message
-      # that says an option was ignored or not supported.
-      # When given -MP, icc 7.0 and 7.1 complain thusly:
-      #   icc: Command line warning: ignoring option '-M'; no argument required
-      # The diagnosis changed in icc 8.0:
-      #   icc: Command line remark: option '-MP' not supported
-      if (grep 'ignoring option' conftest.err ||
-          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
-        am_cv_CC_dependencies_compiler_type=$depmode
-        break
-      fi
-    fi
-  done
-
-  cd ..
-  rm -rf conftest.dir
-else
-  am_cv_CC_dependencies_compiler_type=none
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
-$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
-CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
-
- if
-  test "x$enable_dependency_tracking" != xno \
-  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
-  am__fastdepCC_TRUE=
-  am__fastdepCC_FALSE='#'
-else
-  am__fastdepCC_TRUE='#'
-  am__fastdepCC_FALSE=
-fi
-
-
-case `pwd` in
-  *\ * | *\    *)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
-$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
-esac
-
-
-
-macro_version='2.4.6'
-macro_revision='2.4.6'
-
-
-
-
-
-
-
-
-
-
-
-
-
-ltmain=$ac_aux_dir/ltmain.sh
-
-# Backslashify metacharacters that are still active within
-# double-quoted strings.
-sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\(["`\\]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-
-ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
-$as_echo_n "checking how to print strings... " >&6; }
-# Test print first, because it will be a builtin if present.
-if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
-   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='print -r --'
-elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='printf %s\n'
-else
-  # Use this function as a fallback that always works.
-  func_fallback_echo ()
-  {
-    eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
-  }
-  ECHO='func_fallback_echo'
-fi
-
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
-    $ECHO ""
-}
-
-case $ECHO in
-  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
-$as_echo "printf" >&6; } ;;
-  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
-$as_echo "print -r" >&6; } ;;
-  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
-$as_echo "cat" >&6; } ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
-$as_echo_n "checking for a sed that does not truncate output... " >&6; }
-if ${ac_cv_path_SED+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
-     for ac_i in 1 2 3 4 5 6 7; do
-       ac_script="$ac_script$as_nl$ac_script"
-     done
-     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
-     { ac_script=; unset ac_script;}
-     if test -z "$SED"; then
-  ac_path_SED_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in sed gsed; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_SED" || continue
-# Check for GNU ac_path_SED and select it if it is found.
-  # Check for GNU $ac_path_SED
-case `"$ac_path_SED" --version 2>&1` in
-*GNU*)
-  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo '' >> "conftest.nl"
-    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_SED_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_SED="$ac_path_SED"
-      ac_path_SED_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_SED_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_SED"; then
-    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
-  fi
-else
-  ac_cv_path_SED=$SED
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
-$as_echo "$ac_cv_path_SED" >&6; }
- SED="$ac_cv_path_SED"
-  rm -f conftest.sed
-
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
-
-
-
-
-
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -z "$GREP"; then
-  ac_path_GREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in grep ggrep; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
-  # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'GREP' >> "conftest.nl"
-    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_GREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_GREP="$ac_path_GREP"
-      ac_path_GREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_GREP_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_GREP"; then
-    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
-else
-  ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
-   then ac_cv_path_EGREP="$GREP -E"
-   else
-     if test -z "$EGREP"; then
-  ac_path_EGREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in egrep; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
-  # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'EGREP' >> "conftest.nl"
-    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_EGREP="$ac_path_EGREP"
-      ac_path_EGREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_EGREP_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_EGREP"; then
-    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
-else
-  ac_cv_path_EGREP=$EGREP
-fi
-
-   fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-$as_echo "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
-$as_echo_n "checking for fgrep... " >&6; }
-if ${ac_cv_path_FGREP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
-   then ac_cv_path_FGREP="$GREP -F"
-   else
-     if test -z "$FGREP"; then
-  ac_path_FGREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in fgrep; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_FGREP" || continue
-# Check for GNU ac_path_FGREP and select it if it is found.
-  # Check for GNU $ac_path_FGREP
-case `"$ac_path_FGREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'FGREP' >> "conftest.nl"
-    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_FGREP="$ac_path_FGREP"
-      ac_path_FGREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_FGREP_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_FGREP"; then
-    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
-else
-  ac_cv_path_FGREP=$FGREP
-fi
-
-   fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
-$as_echo "$ac_cv_path_FGREP" >&6; }
- FGREP="$ac_cv_path_FGREP"
-
-
-test -z "$GREP" && GREP=grep
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# Check whether --with-gnu-ld was given.
-if test "${with_gnu_ld+set}" = set; then :
-  withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
-else
-  with_gnu_ld=no
-fi
-
-ac_prog=ld
-if test yes = "$GCC"; then
-  # Check if gcc -print-prog-name=ld gives a path.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
-$as_echo_n "checking for ld used by $CC... " >&6; }
-  case $host in
-  *-*-mingw*)
-    # gcc leaves a trailing carriage return, which upsets mingw
-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
-  *)
-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
-  esac
-  case $ac_prog in
-    # Accept absolute paths.
-    [\\/]* | ?:[\\/]*)
-      re_direlt='/[^/][^/]*/\.\./'
-      # Canonicalize the pathname of ld
-      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
-      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
-       ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
-      done
-      test -z "$LD" && LD=$ac_prog
-      ;;
-  "")
-    # If it fails, then pretend we aren't using GCC.
-    ac_prog=ld
-    ;;
-  *)
-    # If it is relative, then search for the first ld in PATH.
-    with_gnu_ld=unknown
-    ;;
-  esac
-elif test yes = "$with_gnu_ld"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
-$as_echo_n "checking for GNU ld... " >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
-$as_echo_n "checking for non-GNU ld... " >&6; }
-fi
-if ${lt_cv_path_LD+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -z "$LD"; then
-  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
-  for ac_dir in $PATH; do
-    IFS=$lt_save_ifs
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD=$ac_dir/$ac_prog
-      # Check to see if the program is GNU ld.  I'd rather use --version,
-      # but apparently some variants of GNU ld only accept -v.
-      # Break only if it was the GNU/non-GNU ld that we prefer.
-      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
-      *GNU* | *'with BFD'*)
-       test no != "$with_gnu_ld" && break
-       ;;
-      *)
-       test yes != "$with_gnu_ld" && break
-       ;;
-      esac
-    fi
-  done
-  IFS=$lt_save_ifs
-else
-  lt_cv_path_LD=$LD # Let the user override the test with a path.
-fi
-fi
-
-LD=$lt_cv_path_LD
-if test -n "$LD"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
-$as_echo "$LD" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
-$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if ${lt_cv_prog_gnu_ld+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  # I'd rather use --version here, but apparently some GNU lds only accept -v.
-case `$LD -v 2>&1 </dev/null` in
-*GNU* | *'with BFD'*)
-  lt_cv_prog_gnu_ld=yes
-  ;;
-*)
-  lt_cv_prog_gnu_ld=no
-  ;;
-esac
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
-$as_echo "$lt_cv_prog_gnu_ld" >&6; }
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-
-
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
-$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
-if ${lt_cv_path_NM+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$NM"; then
-  # Let the user override the test.
-  lt_cv_path_NM=$NM
-else
-  lt_nm_to_check=${ac_tool_prefix}nm
-  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
-    lt_nm_to_check="$lt_nm_to_check nm"
-  fi
-  for lt_tmp_nm in $lt_nm_to_check; do
-    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
-    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
-      IFS=$lt_save_ifs
-      test -z "$ac_dir" && ac_dir=.
-      tmp_nm=$ac_dir/$lt_tmp_nm
-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
-       # Check to see if the nm accepts a BSD-compat flag.
-       # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
-       #   nm: unknown option "B" ignored
-       # Tru64's nm complains that /dev/null is an invalid object file
-       # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
-       case $build_os in
-       mingw*) lt_bad_file=conftest.nm/nofile ;;
-       *) lt_bad_file=/dev/null ;;
-       esac
-       case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
-       *$lt_bad_file* | *'Invalid file or object type'*)
-         lt_cv_path_NM="$tmp_nm -B"
-         break 2
-         ;;
-       *)
-         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
-         */dev/null*)
-           lt_cv_path_NM="$tmp_nm -p"
-           break 2
-           ;;
-         *)
-           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
-           continue # so that we can try to find one that supports BSD flags
-           ;;
-         esac
-         ;;
-       esac
-      fi
-    done
-    IFS=$lt_save_ifs
-  done
-  : ${lt_cv_path_NM=no}
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
-$as_echo "$lt_cv_path_NM" >&6; }
-if test no != "$lt_cv_path_NM"; then
-  NM=$lt_cv_path_NM
-else
-  # Didn't find any BSD compatible name lister, look for dumpbin.
-  if test -n "$DUMPBIN"; then :
-    # Let the user override the test.
-  else
-    if test -n "$ac_tool_prefix"; then
-  for ac_prog in dumpbin "link -dump"
-  do
-    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DUMPBIN+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$DUMPBIN"; then
-  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-DUMPBIN=$ac_cv_prog_DUMPBIN
-if test -n "$DUMPBIN"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
-$as_echo "$DUMPBIN" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-    test -n "$DUMPBIN" && break
-  done
-fi
-if test -z "$DUMPBIN"; then
-  ac_ct_DUMPBIN=$DUMPBIN
-  for ac_prog in dumpbin "link -dump"
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_DUMPBIN"; then
-  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
-if test -n "$ac_ct_DUMPBIN"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
-$as_echo "$ac_ct_DUMPBIN" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$ac_ct_DUMPBIN" && break
-done
-
-  if test "x$ac_ct_DUMPBIN" = x; then
-    DUMPBIN=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    DUMPBIN=$ac_ct_DUMPBIN
-  fi
-fi
-
-    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
-    *COFF*)
-      DUMPBIN="$DUMPBIN -symbols -headers"
-      ;;
-    *)
-      DUMPBIN=:
-      ;;
-    esac
-  fi
-
-  if test : != "$DUMPBIN"; then
-    NM=$DUMPBIN
-  fi
-fi
-test -z "$NM" && NM=nm
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
-$as_echo_n "checking the name lister ($NM) interface... " >&6; }
-if ${lt_cv_nm_interface+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_nm_interface="BSD nm"
-  echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
-  (eval "$ac_compile" 2>conftest.err)
-  cat conftest.err >&5
-  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
-  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
-  cat conftest.err >&5
-  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
-  cat conftest.out >&5
-  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
-    lt_cv_nm_interface="MS dumpbin"
-  fi
-  rm -f conftest*
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
-$as_echo "$lt_cv_nm_interface" >&6; }
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
-$as_echo_n "checking whether ln -s works... " >&6; }
-LN_S=$as_ln_s
-if test "$LN_S" = "ln -s"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
-$as_echo "no, using $LN_S" >&6; }
-fi
-
-# find the maximum length of command line arguments
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
-$as_echo_n "checking the maximum length of command line arguments... " >&6; }
-if ${lt_cv_sys_max_cmd_len+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-    i=0
-  teststring=ABCD
-
-  case $build_os in
-  msdosdjgpp*)
-    # On DJGPP, this test can blow up pretty badly due to problems in libc
-    # (any single argument exceeding 2000 bytes causes a buffer overrun
-    # during glob expansion).  Even if it were fixed, the result of this
-    # check would be larger than it should be.
-    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
-    ;;
-
-  gnu*)
-    # Under GNU Hurd, this test is not required because there is
-    # no limit to the length of command line arguments.
-    # Libtool will interpret -1 as no limit whatsoever
-    lt_cv_sys_max_cmd_len=-1;
-    ;;
-
-  cygwin* | mingw* | cegcc*)
-    # On Win9x/ME, this test blows up -- it succeeds, but takes
-    # about 5 minutes as the teststring grows exponentially.
-    # Worse, since 9x/ME are not pre-emptively multitasking,
-    # you end up with a "frozen" computer, even though with patience
-    # the test eventually succeeds (with a max line length of 256k).
-    # Instead, let's just punt: use the minimum linelength reported by
-    # all of the supported platforms: 8192 (on NT/2K/XP).
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  mint*)
-    # On MiNT this can take a long time and run out of memory.
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  amigaos*)
-    # On AmigaOS with pdksh, this test takes hours, literally.
-    # So we just punt and use a minimum line length of 8192.
-    lt_cv_sys_max_cmd_len=8192;
-    ;;
-
-  bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
-    # This has been around since 386BSD, at least.  Likely further.
-    if test -x /sbin/sysctl; then
-      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
-    elif test -x /usr/sbin/sysctl; then
-      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
-    else
-      lt_cv_sys_max_cmd_len=65536      # usable default for all BSDs
-    fi
-    # And add a safety zone
-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
-    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
-    ;;
-
-  interix*)
-    # We know the value 262144 and hardcode it with a safety zone (like BSD)
-    lt_cv_sys_max_cmd_len=196608
-    ;;
-
-  os2*)
-    # The test takes a long time on OS/2.
-    lt_cv_sys_max_cmd_len=8192
-    ;;
-
-  osf*)
-    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
-    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
-    # nice to cause kernel panics so lets avoid the loop below.
-    # First set a reasonable default.
-    lt_cv_sys_max_cmd_len=16384
-    #
-    if test -x /sbin/sysconfig; then
-      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
-        *1*) lt_cv_sys_max_cmd_len=-1 ;;
-      esac
-    fi
-    ;;
-  sco3.2v5*)
-    lt_cv_sys_max_cmd_len=102400
-    ;;
-  sysv5* | sco5v6* | sysv4.2uw2*)
-    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
-    if test -n "$kargmax"; then
-      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[         ]//'`
-    else
-      lt_cv_sys_max_cmd_len=32768
-    fi
-    ;;
-  *)
-    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
-    if test -n "$lt_cv_sys_max_cmd_len" && \
-       test undefined != "$lt_cv_sys_max_cmd_len"; then
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
-    else
-      # Make teststring a little bigger before we do anything with it.
-      # a 1K string should be a reasonable start.
-      for i in 1 2 3 4 5 6 7 8; do
-        teststring=$teststring$teststring
-      done
-      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
-      # If test is not a shell built-in, we'll probably end up computing a
-      # maximum length that is only half of the actual maximum length, but
-      # we can't tell.
-      while { test X`env echo "$teststring$teststring" 2>/dev/null` \
-                = "X$teststring$teststring"; } >/dev/null 2>&1 &&
-             test 17 != "$i" # 1/2 MB should be enough
-      do
-        i=`expr $i + 1`
-        teststring=$teststring$teststring
-      done
-      # Only check the string length outside the loop.
-      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
-      teststring=
-      # Add a significant safety factor because C++ compilers can tack on
-      # massive amounts of additional arguments before passing them to the
-      # linker.  It appears as though 1/2 is a usable value.
-      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
-    fi
-    ;;
-  esac
-
-fi
-
-if test -n "$lt_cv_sys_max_cmd_len"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
-$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
-$as_echo "none" >&6; }
-fi
-max_cmd_len=$lt_cv_sys_max_cmd_len
-
-
-
-
-
-
-: ${CP="cp -f"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  lt_unset=unset
-else
-  lt_unset=false
-fi
-
-
-
-
-
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
-    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
-  lt_SP2NL='tr \040 \012'
-  lt_NL2SP='tr \015\012 \040\040'
-  ;;
- *) # EBCDIC based system
-  lt_SP2NL='tr \100 \n'
-  lt_NL2SP='tr \r\n \100\100'
-  ;;
-esac
-
-
-
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
-$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
-if ${lt_cv_to_host_file_cmd+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $host in
-  *-*-mingw* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
-        ;;
-      *-*-cygwin* )
-        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
-        ;;
-      * ) # otherwise, assume *nix
-        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
-        ;;
-    esac
-    ;;
-  *-*-cygwin* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
-        ;;
-      *-*-cygwin* )
-        lt_cv_to_host_file_cmd=func_convert_file_noop
-        ;;
-      * ) # otherwise, assume *nix
-        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
-        ;;
-    esac
-    ;;
-  * ) # unhandled hosts (and "normal" native builds)
-    lt_cv_to_host_file_cmd=func_convert_file_noop
-    ;;
-esac
-
-fi
-
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
-$as_echo "$lt_cv_to_host_file_cmd" >&6; }
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
-$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
-if ${lt_cv_to_tool_file_cmd+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  #assume ordinary cross tools, or native build.
-lt_cv_to_tool_file_cmd=func_convert_file_noop
-case $host in
-  *-*-mingw* )
-    case $build in
-      *-*-mingw* ) # actually msys
-        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
-        ;;
-    esac
-    ;;
-esac
-
-fi
-
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
-$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
-$as_echo_n "checking for $LD option to reload object files... " >&6; }
-if ${lt_cv_ld_reload_flag+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_ld_reload_flag='-r'
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
-$as_echo "$lt_cv_ld_reload_flag" >&6; }
-reload_flag=$lt_cv_ld_reload_flag
-case $reload_flag in
-"" | " "*) ;;
-*) reload_flag=" $reload_flag" ;;
-esac
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    if test yes != "$GCC"; then
-      reload_cmds=false
-    fi
-    ;;
-  darwin*)
-    if test yes = "$GCC"; then
-      reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
-    else
-      reload_cmds='$LD$reload_flag -o $output$reload_objs'
-    fi
-    ;;
-esac
-
-
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
-set dummy ${ac_tool_prefix}objdump; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OBJDUMP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$OBJDUMP"; then
-  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-OBJDUMP=$ac_cv_prog_OBJDUMP
-if test -n "$OBJDUMP"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
-$as_echo "$OBJDUMP" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_OBJDUMP"; then
-  ac_ct_OBJDUMP=$OBJDUMP
-  # Extract the first word of "objdump", so it can be a program name with args.
-set dummy objdump; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_OBJDUMP"; then
-  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_OBJDUMP="objdump"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
-if test -n "$ac_ct_OBJDUMP"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
-$as_echo "$ac_ct_OBJDUMP" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_OBJDUMP" = x; then
-    OBJDUMP="false"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    OBJDUMP=$ac_ct_OBJDUMP
-  fi
-else
-  OBJDUMP="$ac_cv_prog_OBJDUMP"
-fi
-
-test -z "$OBJDUMP" && OBJDUMP=objdump
-
-
-
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
-$as_echo_n "checking how to recognize dependent libraries... " >&6; }
-if ${lt_cv_deplibs_check_method+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# 'unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# that responds to the $file_magic_cmd with a given extended regex.
-# If you have 'file' or equivalent on your system and you're not sure
-# whether 'pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix[4-9]*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-beos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-bsdi[45]*)
-  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
-  lt_cv_file_magic_cmd='/usr/bin/file -L'
-  lt_cv_file_magic_test_file=/shlib/libc.so
-  ;;
-
-cygwin*)
-  # func_win32_libid is a shell function defined in ltmain.sh
-  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
-  lt_cv_file_magic_cmd='func_win32_libid'
-  ;;
-
-mingw* | pw32*)
-  # Base MSYS/MinGW do not provide the 'file' command needed by
-  # func_win32_libid shell function, so use a weaker test based on 'objdump',
-  # unless we find 'file', for example because we are cross-compiling.
-  if ( file / ) >/dev/null 2>&1; then
-    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
-    lt_cv_file_magic_cmd='func_win32_libid'
-  else
-    # Keep this pattern in sync with the one in func_win32_libid.
-    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
-    lt_cv_file_magic_cmd='$OBJDUMP -f'
-  fi
-  ;;
-
-cegcc*)
-  # use the weaker test based on 'objdump'. See mingw*.
-  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
-  lt_cv_file_magic_cmd='$OBJDUMP -f'
-  ;;
-
-darwin* | rhapsody*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-freebsd* | dragonfly*)
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
-    case $host_cpu in
-    i*86 )
-      # Not sure whether the presence of OpenBSD here was a mistake.
-      # Let's accept both of them until this is cleared up.
-      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
-      lt_cv_file_magic_cmd=/usr/bin/file
-      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
-      ;;
-    esac
-  else
-    lt_cv_deplibs_check_method=pass_all
-  fi
-  ;;
-
-haiku*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-hpux10.20* | hpux11*)
-  lt_cv_file_magic_cmd=/usr/bin/file
-  case $host_cpu in
-  ia64*)
-    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
-    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
-    ;;
-  hppa*64*)
-    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
-    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
-    ;;
-  *)
-    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
-    lt_cv_file_magic_test_file=/usr/lib/libc.sl
-    ;;
-  esac
-  ;;
-
-interix[3-9]*)
-  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
-  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
-  ;;
-
-irix5* | irix6* | nonstopux*)
-  case $LD in
-  *-32|*"-32 ") libmagic=32-bit;;
-  *-n32|*"-n32 ") libmagic=N32;;
-  *-64|*"-64 ") libmagic=64-bit;;
-  *) libmagic=never-match;;
-  esac
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-netbsd* | netbsdelf*-gnu)
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
-    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
-  fi
-  ;;
-
-newos6*)
-  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
-  lt_cv_file_magic_cmd=/usr/bin/file
-  lt_cv_file_magic_test_file=/usr/lib/libnls.so
-  ;;
-
-*nto* | *qnx*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-openbsd* | bitrig*)
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
-    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
-  else
-    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
-  fi
-  ;;
-
-osf3* | osf4* | osf5*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-rdos*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-solaris*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
-sysv4 | sysv4.3*)
-  case $host_vendor in
-  motorola)
-    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
-    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
-    ;;
-  ncr)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  sequent)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
-    ;;
-  sni)
-    lt_cv_file_magic_cmd='/bin/file'
-    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
-    lt_cv_file_magic_test_file=/lib/libc.so
-    ;;
-  siemens)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  pc)
-    lt_cv_deplibs_check_method=pass_all
-    ;;
-  esac
-  ;;
-
-tpf*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-os2*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-esac
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
-$as_echo "$lt_cv_deplibs_check_method" >&6; }
-
-file_magic_glob=
-want_nocaseglob=no
-if test "$build" = "$host"; then
-  case $host_os in
-  mingw* | pw32*)
-    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
-      want_nocaseglob=yes
-    else
-      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
-    fi
-    ;;
-  esac
-fi
-
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
-set dummy ${ac_tool_prefix}dlltool; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DLLTOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$DLLTOOL"; then
-  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-DLLTOOL=$ac_cv_prog_DLLTOOL
-if test -n "$DLLTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
-$as_echo "$DLLTOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_DLLTOOL"; then
-  ac_ct_DLLTOOL=$DLLTOOL
-  # Extract the first word of "dlltool", so it can be a program name with args.
-set dummy dlltool; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_DLLTOOL"; then
-  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
-if test -n "$ac_ct_DLLTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
-$as_echo "$ac_ct_DLLTOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_DLLTOOL" = x; then
-    DLLTOOL="false"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    DLLTOOL=$ac_ct_DLLTOOL
-  fi
-else
-  DLLTOOL="$ac_cv_prog_DLLTOOL"
-fi
-
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-
-
-
-
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
-$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
-if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_sharedlib_from_linklib_cmd='unknown'
-
-case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
-  # two different shell functions defined in ltmain.sh;
-  # decide which one to use based on capabilities of $DLLTOOL
-  case `$DLLTOOL --help 2>&1` in
-  *--identify-strict*)
-    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
-    ;;
-  *)
-    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
-    ;;
-  esac
-  ;;
-*)
-  # fallback: assume linklib IS sharedlib
-  lt_cv_sharedlib_from_linklib_cmd=$ECHO
-  ;;
-esac
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
-$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
-sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
-test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
-  for ac_prog in ar
-  do
-    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AR+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$AR"; then
-  ac_cv_prog_AR="$AR" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-AR=$ac_cv_prog_AR
-if test -n "$AR"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
-$as_echo "$AR" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-    test -n "$AR" && break
-  done
-fi
-if test -z "$AR"; then
-  ac_ct_AR=$AR
-  for ac_prog in ar
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_AR+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_AR"; then
-  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_AR="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_AR=$ac_cv_prog_ac_ct_AR
-if test -n "$ac_ct_AR"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
-$as_echo "$ac_ct_AR" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$ac_ct_AR" && break
-done
-
-  if test "x$ac_ct_AR" = x; then
-    AR="false"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    AR=$ac_ct_AR
-  fi
-fi
-
-: ${AR=ar}
-: ${AR_FLAGS=cru}
-
-
-
-
-
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
-$as_echo_n "checking for archiver @FILE support... " >&6; }
-if ${lt_cv_ar_at_file+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_ar_at_file=no
-   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  echo conftest.$ac_objext > conftest.lst
-      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
-      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
-  (eval $lt_ar_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-      if test 0 -eq "$ac_status"; then
-       # Ensure the archiver fails upon bogus file names.
-       rm -f conftest.$ac_objext libconftest.a
-       { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
-  (eval $lt_ar_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-       if test 0 -ne "$ac_status"; then
-          lt_cv_ar_at_file=@
-        fi
-      fi
-      rm -f conftest.* libconftest.a
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
-$as_echo "$lt_cv_ar_at_file" >&6; }
-
-if test no = "$lt_cv_ar_at_file"; then
-  archiver_list_spec=
-else
-  archiver_list_spec=$lt_cv_ar_at_file
-fi
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
-set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_STRIP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$STRIP"; then
-  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-STRIP=$ac_cv_prog_STRIP
-if test -n "$STRIP"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
-$as_echo "$STRIP" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_STRIP"; then
-  ac_ct_STRIP=$STRIP
-  # Extract the first word of "strip", so it can be a program name with args.
-set dummy strip; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_STRIP"; then
-  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_STRIP="strip"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
-if test -n "$ac_ct_STRIP"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
-$as_echo "$ac_ct_STRIP" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_STRIP" = x; then
-    STRIP=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    STRIP=$ac_ct_STRIP
-  fi
-else
-  STRIP="$ac_cv_prog_STRIP"
-fi
-
-test -z "$STRIP" && STRIP=:
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$RANLIB"; then
-  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-$as_echo "$RANLIB" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
-  ac_ct_RANLIB=$RANLIB
-  # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_RANLIB"; then
-  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_RANLIB="ranlib"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-$as_echo "$ac_ct_RANLIB" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_RANLIB" = x; then
-    RANLIB=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    RANLIB=$ac_ct_RANLIB
-  fi
-else
-  RANLIB="$ac_cv_prog_RANLIB"
-fi
-
-test -z "$RANLIB" && RANLIB=:
-
-
-
-
-
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
-  case $host_os in
-  bitrig* | openbsd*)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
-    ;;
-  *)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
-    ;;
-  esac
-  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
-fi
-
-case $host_os in
-  darwin*)
-    lock_old_archive_extraction=yes ;;
-  *)
-    lock_old_archive_extraction=no ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
-$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
-if ${lt_cv_sys_global_symbol_pipe+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[BCDEGRST]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
-
-# Define system-specific variables.
-case $host_os in
-aix*)
-  symcode='[BCDT]'
-  ;;
-cygwin* | mingw* | pw32* | cegcc*)
-  symcode='[ABCDGISTW]'
-  ;;
-hpux*)
-  if test ia64 = "$host_cpu"; then
-    symcode='[ABCDEGRST]'
-  fi
-  ;;
-irix* | nonstopux*)
-  symcode='[BCDEGRST]'
-  ;;
-osf*)
-  symcode='[BCDEGQRST]'
-  ;;
-solaris*)
-  symcode='[BDRT]'
-  ;;
-sco3.2v5*)
-  symcode='[DT]'
-  ;;
-sysv4.2uw2*)
-  symcode='[DT]'
-  ;;
-sysv5* | sco5v6* | unixware* | OpenUNIX*)
-  symcode='[ABDT]'
-  ;;
-sysv4)
-  symcode='[DFNSTU]'
-  ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-case `$NM -V 2>&1` in
-*GNU* | *'with BFD'*)
-  symcode='[ABCDGIRSTW]' ;;
-esac
-
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-  # Gets list of data symbols to import.
-  lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
-  # Adjust the below global symbol transforms to fixup imported variables.
-  lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
-  lt_c_name_hook=" -e 's/^I .* \(.*\)$/  {\"\1\", (void *) 0},/p'"
-  lt_c_name_lib_hook="\
-  -e 's/^I .* \(lib.*\)$/  {\"\1\", (void *) 0},/p'\
-  -e 's/^I .* \(.*\)$/  {\"lib\1\", (void *) 0},/p'"
-else
-  # Disable hooks by default.
-  lt_cv_sys_global_symbol_to_import=
-  lt_cdecl_hook=
-  lt_c_name_hook=
-  lt_c_name_lib_hook=
-fi
-
-# Transform an extracted symbol line into a proper C declaration.
-# Some systems (esp. on ia64) link data and code symbols differently,
-# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n"\
-$lt_cdecl_hook\
-" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
-$lt_c_name_hook\
-" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/p'"
-
-# Transform an extracted symbol line into symbol name with lib prefix and
-# symbol address.
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
-$lt_c_name_lib_hook\
-" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
-" -e 's/^$symcode$symcode* .* \(lib.*\)$/  {\"\1\", (void *) \&\1},/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"lib\1\", (void *) \&\1},/p'"
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $build_os in
-mingw*)
-  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
-  ;;
-esac
-
-# Try without a prefix underscore, then with it.
-for ac_symprfx in "" "_"; do
-
-  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
-  symxfrm="\\1 $ac_symprfx\\2 \\2"
-
-  # Write the raw and C identifiers.
-  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-    # Fake it for dumpbin and say T for any non-static function,
-    # D for any global variable and I for any imported variable.
-    # Also find C++ and __fastcall symbols from MSVC++,
-    # which start with @ or ?.
-    lt_cv_sys_global_symbol_pipe="$AWK '"\
-"     {last_section=section; section=\$ 3};"\
-"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
-"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
-"     /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
-"     /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
-"     /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
-"     \$ 0!~/External *\|/{next};"\
-"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
-"     {if(hide[section]) next};"\
-"     {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
-"     {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
-"     s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
-"     s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
-"     ' prfx=^$ac_symprfx"
-  else
-    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[     ]\($symcode$symcode*\)[         ][      ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
-  fi
-  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
-
-  # Check to see that the pipe works correctly.
-  pipe_works=no
-
-  rm -f conftest*
-  cat > conftest.$ac_ext <<_LT_EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(void);
-void nm_test_func(void){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-_LT_EOF
-
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
-  (eval $ac_compile) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-    # Now try to grab the symbols.
-    nlist=conftest.nm
-    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
-  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && test -s "$nlist"; then
-      # Try sorting and uniquifying the output.
-      if sort "$nlist" | uniq > "$nlist"T; then
-       mv -f "$nlist"T "$nlist"
-      else
-       rm -f "$nlist"T
-      fi
-
-      # Make sure that we snagged all the symbols we need.
-      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
-       if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
-         cat <<_LT_EOF > conftest.$ac_ext
-/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
-#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
-/* DATA imports from DLLs on WIN32 can't be const, because runtime
-   relocations are performed -- see ld's documentation on pseudo-relocs.  */
-# define LT_DLSYM_CONST
-#elif defined __osf__
-/* This system does not cope well with relocations in const data.  */
-# define LT_DLSYM_CONST
-#else
-# define LT_DLSYM_CONST const
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-_LT_EOF
-         # Now generate the symbol file.
-         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
-
-         cat <<_LT_EOF >> conftest.$ac_ext
-
-/* The mapping between symbol names and symbols.  */
-LT_DLSYM_CONST struct {
-  const char *name;
-  void       *address;
-}
-lt__PROGRAM__LTX_preloaded_symbols[] =
-{
-  { "@PROGRAM@", (void *) 0 },
-_LT_EOF
-         $SED "s/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
-         cat <<\_LT_EOF >> conftest.$ac_ext
-  {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
-  return lt__PROGRAM__LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-_LT_EOF
-         # Now try linking the two files.
-         mv conftest.$ac_objext conftstm.$ac_objext
-         lt_globsym_save_LIBS=$LIBS
-         lt_globsym_save_CFLAGS=$CFLAGS
-         LIBS=conftstm.$ac_objext
-         CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
-         if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
-  (eval $ac_link) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && test -s conftest$ac_exeext; then
-           pipe_works=yes
-         fi
-         LIBS=$lt_globsym_save_LIBS
-         CFLAGS=$lt_globsym_save_CFLAGS
-       else
-         echo "cannot find nm_test_func in $nlist" >&5
-       fi
-      else
-       echo "cannot find nm_test_var in $nlist" >&5
-      fi
-    else
-      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
-    fi
-  else
-    echo "$progname: failed program was:" >&5
-    cat conftest.$ac_ext >&5
-  fi
-  rm -rf conftest* conftst*
-
-  # Do not use the global_symbol_pipe unless it works.
-  if test yes = "$pipe_works"; then
-    break
-  else
-    lt_cv_sys_global_symbol_pipe=
-  fi
-done
-
-fi
-
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
-  lt_cv_sys_global_symbol_to_cdecl=
-fi
-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
-$as_echo "failed" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
-$as_echo "ok" >&6; }
-fi
-
-# Response file support.
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
-  nm_file_list_spec='@'
-elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
-  nm_file_list_spec='@'
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
-$as_echo_n "checking for sysroot... " >&6; }
-
-# Check whether --with-sysroot was given.
-if test "${with_sysroot+set}" = set; then :
-  withval=$with_sysroot;
-else
-  with_sysroot=no
-fi
-
-
-lt_sysroot=
-case $with_sysroot in #(
- yes)
-   if test yes = "$GCC"; then
-     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
-   fi
-   ;; #(
- /*)
-   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
-   ;; #(
- no|'')
-   ;; #(
- *)
-   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
-$as_echo "$with_sysroot" >&6; }
-   as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
-   ;;
-esac
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
-$as_echo "${lt_sysroot:-no}" >&6; }
-
-
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
-$as_echo_n "checking for a working dd... " >&6; }
-if ${ac_cv_path_lt_DD+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  printf 0123456789abcdef0123456789abcdef >conftest.i
-cat conftest.i conftest.i >conftest2.i
-: ${lt_DD:=$DD}
-if test -z "$lt_DD"; then
-  ac_path_lt_DD_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_prog in dd; do
-    for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_lt_DD" || continue
-if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
-  cmp -s conftest.i conftest.out \
-  && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
-fi
-      $ac_path_lt_DD_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_lt_DD"; then
-    :
-  fi
-else
-  ac_cv_path_lt_DD=$lt_DD
-fi
-
-rm -f conftest.i conftest2.i conftest.out
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
-$as_echo "$ac_cv_path_lt_DD" >&6; }
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
-$as_echo_n "checking how to truncate binary pipes... " >&6; }
-if ${lt_cv_truncate_bin+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  printf 0123456789abcdef0123456789abcdef >conftest.i
-cat conftest.i conftest.i >conftest2.i
-lt_cv_truncate_bin=
-if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
-  cmp -s conftest.i conftest.out \
-  && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
-fi
-rm -f conftest.i conftest2.i conftest.out
-test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
-$as_echo "$lt_cv_truncate_bin" >&6; }
-
-
-
-
-
-
-
-# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
-func_cc_basename ()
-{
-    for cc_temp in $*""; do
-      case $cc_temp in
-        compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
-        distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
-        \-*) ;;
-        *) break;;
-      esac
-    done
-    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
-}
-
-# Check whether --enable-libtool-lock was given.
-if test "${enable_libtool_lock+set}" = set; then :
-  enableval=$enable_libtool_lock;
-fi
-
-test no = "$enable_libtool_lock" || enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-ia64-*-hpux*)
-  # Find out what ABI is being produced by ac_compile, and set mode
-  # options accordingly.
-  echo 'int i;' > conftest.$ac_ext
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
-  (eval $ac_compile) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-    case `/usr/bin/file conftest.$ac_objext` in
-      *ELF-32*)
-       HPUX_IA64_MODE=32
-       ;;
-      *ELF-64*)
-       HPUX_IA64_MODE=64
-       ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-*-*-irix6*)
-  # Find out what ABI is being produced by ac_compile, and set linker
-  # options accordingly.
-  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
-  (eval $ac_compile) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-    if test yes = "$lt_cv_prog_gnu_ld"; then
-      case `/usr/bin/file conftest.$ac_objext` in
-       *32-bit*)
-         LD="${LD-ld} -melf32bsmip"
-         ;;
-       *N32*)
-         LD="${LD-ld} -melf32bmipn32"
-         ;;
-       *64-bit*)
-         LD="${LD-ld} -melf64bmip"
-       ;;
-      esac
-    else
-      case `/usr/bin/file conftest.$ac_objext` in
-       *32-bit*)
-         LD="${LD-ld} -32"
-         ;;
-       *N32*)
-         LD="${LD-ld} -n32"
-         ;;
-       *64-bit*)
-         LD="${LD-ld} -64"
-         ;;
-      esac
-    fi
-  fi
-  rm -rf conftest*
-  ;;
-
-mips64*-*linux*)
-  # Find out what ABI is being produced by ac_compile, and set linker
-  # options accordingly.
-  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
-  (eval $ac_compile) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-    emul=elf
-    case `/usr/bin/file conftest.$ac_objext` in
-      *32-bit*)
-       emul="${emul}32"
-       ;;
-      *64-bit*)
-       emul="${emul}64"
-       ;;
-    esac
-    case `/usr/bin/file conftest.$ac_objext` in
-      *MSB*)
-       emul="${emul}btsmip"
-       ;;
-      *LSB*)
-       emul="${emul}ltsmip"
-       ;;
-    esac
-    case `/usr/bin/file conftest.$ac_objext` in
-      *N32*)
-       emul="${emul}n32"
-       ;;
-    esac
-    LD="${LD-ld} -m $emul"
-  fi
-  rm -rf conftest*
-  ;;
-
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
-  # Find out what ABI is being produced by ac_compile, and set linker
-  # options accordingly.  Note that the listed cases only cover the
-  # situations where additional linker options are needed (such as when
-  # doing 32-bit compilation for a host where ld defaults to 64-bit, or
-  # vice versa); the common cases where no linker options are needed do
-  # not appear in the list.
-  echo 'int i;' > conftest.$ac_ext
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
-  (eval $ac_compile) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-    case `/usr/bin/file conftest.o` in
-      *32-bit*)
-       case $host in
-         x86_64-*kfreebsd*-gnu)
-           LD="${LD-ld} -m elf_i386_fbsd"
-           ;;
-         x86_64-*linux*)
-           case `/usr/bin/file conftest.o` in
-             *x86-64*)
-               LD="${LD-ld} -m elf32_x86_64"
-               ;;
-             *)
-               LD="${LD-ld} -m elf_i386"
-               ;;
-           esac
-           ;;
-         powerpc64le-*linux*)
-           LD="${LD-ld} -m elf32lppclinux"
-           ;;
-         powerpc64-*linux*)
-           LD="${LD-ld} -m elf32ppclinux"
-           ;;
-         s390x-*linux*)
-           LD="${LD-ld} -m elf_s390"
-           ;;
-         sparc64-*linux*)
-           LD="${LD-ld} -m elf32_sparc"
-           ;;
-       esac
-       ;;
-      *64-bit*)
-       case $host in
-         x86_64-*kfreebsd*-gnu)
-           LD="${LD-ld} -m elf_x86_64_fbsd"
-           ;;
-         x86_64-*linux*)
-           LD="${LD-ld} -m elf_x86_64"
-           ;;
-         powerpcle-*linux*)
-           LD="${LD-ld} -m elf64lppc"
-           ;;
-         powerpc-*linux*)
-           LD="${LD-ld} -m elf64ppc"
-           ;;
-         s390*-*linux*|s390*-*tpf*)
-           LD="${LD-ld} -m elf64_s390"
-           ;;
-         sparc*-*linux*)
-           LD="${LD-ld} -m elf64_sparc"
-           ;;
-       esac
-       ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-
-*-*-sco3.2v5*)
-  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
-  SAVE_CFLAGS=$CFLAGS
-  CFLAGS="$CFLAGS -belf"
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
-$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
-if ${lt_cv_cc_needs_belf+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  lt_cv_cc_needs_belf=yes
-else
-  lt_cv_cc_needs_belf=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-     ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
-$as_echo "$lt_cv_cc_needs_belf" >&6; }
-  if test yes != "$lt_cv_cc_needs_belf"; then
-    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
-    CFLAGS=$SAVE_CFLAGS
-  fi
-  ;;
-*-*solaris*)
-  # Find out what ABI is being produced by ac_compile, and set linker
-  # options accordingly.
-  echo 'int i;' > conftest.$ac_ext
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
-  (eval $ac_compile) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-    case `/usr/bin/file conftest.o` in
-    *64-bit*)
-      case $lt_cv_prog_gnu_ld in
-      yes*)
-        case $host in
-        i?86-*-solaris*|x86_64-*-solaris*)
-          LD="${LD-ld} -m elf_x86_64"
-          ;;
-        sparc*-*-solaris*)
-          LD="${LD-ld} -m elf64_sparc"
-          ;;
-        esac
-        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
-        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
-          LD=${LD-ld}_sol2
-        fi
-        ;;
-      *)
-       if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
-         LD="${LD-ld} -64"
-       fi
-       ;;
-      esac
-      ;;
-    esac
-  fi
-  rm -rf conftest*
-  ;;
-esac
-
-need_locks=$enable_libtool_lock
-
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
-set dummy ${ac_tool_prefix}mt; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$MANIFEST_TOOL"; then
-  ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
-if test -n "$MANIFEST_TOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
-$as_echo "$MANIFEST_TOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
-  ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
-  # Extract the first word of "mt", so it can be a program name with args.
-set dummy mt; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_MANIFEST_TOOL"; then
-  ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
-if test -n "$ac_ct_MANIFEST_TOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
-$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_MANIFEST_TOOL" = x; then
-    MANIFEST_TOOL=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
-  fi
-else
-  MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
-fi
-
-test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
-$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
-if ${lt_cv_path_mainfest_tool+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_path_mainfest_tool=no
-  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
-  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
-  cat conftest.err >&5
-  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
-    lt_cv_path_mainfest_tool=yes
-  fi
-  rm -f conftest*
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
-$as_echo "$lt_cv_path_mainfest_tool" >&6; }
-if test yes != "$lt_cv_path_mainfest_tool"; then
-  MANIFEST_TOOL=:
-fi
-
-
-
-
-
-
-  case $host_os in
-    rhapsody* | darwin*)
-    if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
-set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DSYMUTIL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$DSYMUTIL"; then
-  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-DSYMUTIL=$ac_cv_prog_DSYMUTIL
-if test -n "$DSYMUTIL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
-$as_echo "$DSYMUTIL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_DSYMUTIL"; then
-  ac_ct_DSYMUTIL=$DSYMUTIL
-  # Extract the first word of "dsymutil", so it can be a program name with args.
-set dummy dsymutil; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_DSYMUTIL"; then
-  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
-if test -n "$ac_ct_DSYMUTIL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
-$as_echo "$ac_ct_DSYMUTIL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_DSYMUTIL" = x; then
-    DSYMUTIL=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    DSYMUTIL=$ac_ct_DSYMUTIL
-  fi
-else
-  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
-fi
-
-    if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
-set dummy ${ac_tool_prefix}nmedit; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_NMEDIT+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$NMEDIT"; then
-  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-NMEDIT=$ac_cv_prog_NMEDIT
-if test -n "$NMEDIT"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
-$as_echo "$NMEDIT" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_NMEDIT"; then
-  ac_ct_NMEDIT=$NMEDIT
-  # Extract the first word of "nmedit", so it can be a program name with args.
-set dummy nmedit; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_NMEDIT"; then
-  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_NMEDIT="nmedit"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
-if test -n "$ac_ct_NMEDIT"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
-$as_echo "$ac_ct_NMEDIT" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_NMEDIT" = x; then
-    NMEDIT=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    NMEDIT=$ac_ct_NMEDIT
-  fi
-else
-  NMEDIT="$ac_cv_prog_NMEDIT"
-fi
-
-    if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
-set dummy ${ac_tool_prefix}lipo; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_LIPO+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$LIPO"; then
-  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-LIPO=$ac_cv_prog_LIPO
-if test -n "$LIPO"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
-$as_echo "$LIPO" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_LIPO"; then
-  ac_ct_LIPO=$LIPO
-  # Extract the first word of "lipo", so it can be a program name with args.
-set dummy lipo; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_LIPO"; then
-  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_LIPO="lipo"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
-if test -n "$ac_ct_LIPO"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
-$as_echo "$ac_ct_LIPO" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_LIPO" = x; then
-    LIPO=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    LIPO=$ac_ct_LIPO
-  fi
-else
-  LIPO="$ac_cv_prog_LIPO"
-fi
-
-    if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
-set dummy ${ac_tool_prefix}otool; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OTOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$OTOOL"; then
-  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-OTOOL=$ac_cv_prog_OTOOL
-if test -n "$OTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
-$as_echo "$OTOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_OTOOL"; then
-  ac_ct_OTOOL=$OTOOL
-  # Extract the first word of "otool", so it can be a program name with args.
-set dummy otool; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_OTOOL"; then
-  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_OTOOL="otool"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
-if test -n "$ac_ct_OTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
-$as_echo "$ac_ct_OTOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_OTOOL" = x; then
-    OTOOL=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    OTOOL=$ac_ct_OTOOL
-  fi
-else
-  OTOOL="$ac_cv_prog_OTOOL"
-fi
-
-    if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
-set dummy ${ac_tool_prefix}otool64; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OTOOL64+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$OTOOL64"; then
-  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-OTOOL64=$ac_cv_prog_OTOOL64
-if test -n "$OTOOL64"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
-$as_echo "$OTOOL64" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_OTOOL64"; then
-  ac_ct_OTOOL64=$OTOOL64
-  # Extract the first word of "otool64", so it can be a program name with args.
-set dummy otool64; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_OTOOL64"; then
-  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_OTOOL64="otool64"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
-if test -n "$ac_ct_OTOOL64"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
-$as_echo "$ac_ct_OTOOL64" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_OTOOL64" = x; then
-    OTOOL64=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    OTOOL64=$ac_ct_OTOOL64
-  fi
-else
-  OTOOL64="$ac_cv_prog_OTOOL64"
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
-$as_echo_n "checking for -single_module linker flag... " >&6; }
-if ${lt_cv_apple_cc_single_mod+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_apple_cc_single_mod=no
-      if test -z "$LT_MULTI_MODULE"; then
-       # By default we will add the -single_module flag. You can override
-       # by either setting the environment variable LT_MULTI_MODULE
-       # non-empty at configure time, or by adding -multi_module to the
-       # link flags.
-       rm -rf libconftest.dylib*
-       echo "int foo(void){return 1;}" > conftest.c
-       echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&5
-       $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
-         -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
-        _lt_result=$?
-       # If there is a non-empty error log, and "single_module"
-       # appears in it, assume the flag caused a linker warning
-        if test -s conftest.err && $GREP single_module conftest.err; then
-         cat conftest.err >&5
-       # Otherwise, if the output was created with a 0 exit code from
-       # the compiler, it worked.
-       elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
-         lt_cv_apple_cc_single_mod=yes
-       else
-         cat conftest.err >&5
-       fi
-       rm -rf libconftest.dylib*
-       rm -f conftest.*
-      fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
-$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
-$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
-if ${lt_cv_ld_exported_symbols_list+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_ld_exported_symbols_list=no
-      save_LDFLAGS=$LDFLAGS
-      echo "_main" > conftest.sym
-      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
-      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  lt_cv_ld_exported_symbols_list=yes
-else
-  lt_cv_ld_exported_symbols_list=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-       LDFLAGS=$save_LDFLAGS
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
-$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
-$as_echo_n "checking for -force_load linker flag... " >&6; }
-if ${lt_cv_ld_force_load+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_ld_force_load=no
-      cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
-      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
-      echo "$AR cru libconftest.a conftest.o" >&5
-      $AR cru libconftest.a conftest.o 2>&5
-      echo "$RANLIB libconftest.a" >&5
-      $RANLIB libconftest.a 2>&5
-      cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
-      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
-      _lt_result=$?
-      if test -s conftest.err && $GREP force_load conftest.err; then
-       cat conftest.err >&5
-      elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
-       lt_cv_ld_force_load=yes
-      else
-       cat conftest.err >&5
-      fi
-        rm -f conftest.err libconftest.a conftest conftest.c
-        rm -rf conftest.dSYM
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
-$as_echo "$lt_cv_ld_force_load" >&6; }
-    case $host_os in
-    rhapsody* | darwin1.[012])
-      _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
-    darwin1.*)
-      _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
-    darwin*) # darwin 5.x on
-      # if running on 10.5 or later, the deployment target defaults
-      # to the OS version, if on x86, and 10.4, the deployment
-      # target defaults to 10.4. Don't you love it?
-      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
-       10.0,*86*-darwin8*|10.0,*-darwin[91]*)
-         _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
-       10.[012][,.]*)
-         _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
-       10.*)
-         _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
-      esac
-    ;;
-  esac
-    if test yes = "$lt_cv_apple_cc_single_mod"; then
-      _lt_dar_single_mod='$single_module'
-    fi
-    if test yes = "$lt_cv_ld_exported_symbols_list"; then
-      _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
-    else
-      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
-    fi
-    if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
-      _lt_dsymutil='~$DSYMUTIL $lib || :'
-    else
-      _lt_dsymutil=
-    fi
-    ;;
-  esac
-
-# func_munge_path_list VARIABLE PATH
-# -----------------------------------
-# VARIABLE is name of variable containing _space_ separated list of
-# directories to be munged by the contents of PATH, which is string
-# having a format:
-# "DIR[:DIR]:"
-#       string "DIR[ DIR]" will be prepended to VARIABLE
-# ":DIR[:DIR]"
-#       string "DIR[ DIR]" will be appended to VARIABLE
-# "DIRP[:DIRP]::[DIRA:]DIRA"
-#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
-#       "DIRA[ DIRA]" will be appended to VARIABLE
-# "DIR[:DIR]"
-#       VARIABLE will be replaced by "DIR[ DIR]"
-func_munge_path_list ()
-{
-    case x$2 in
-    x)
-        ;;
-    *:)
-        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
-        ;;
-    x:*)
-        eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
-        ;;
-    *::*)
-        eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
-        eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
-        ;;
-    *)
-        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
-        ;;
-    esac
-}
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-$as_echo_n "checking how to run the C preprocessor... " >&6; }
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
-  CPP=
-fi
-if test -z "$CPP"; then
-  if ${ac_cv_prog_CPP+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-      # Double quotes because CPP needs to be expanded
-    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
-    do
-      ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
-  # Use a header file that comes with gcc, so configuring glibc
-  # with a fresh cross-compiler works.
-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-  # <limits.h> exists even on freestanding compilers.
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp. "Syntax error" is here to catch this case.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-                    Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-
-else
-  # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-  # OK, works on sane cases.  Now check whether nonexistent headers
-  # can be detected and how.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  # Broken: success on invalid input.
-continue
-else
-  # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
-  break
-fi
-
-    done
-    ac_cv_prog_CPP=$CPP
-
-fi
-  CPP=$ac_cv_prog_CPP
-else
-  ac_cv_prog_CPP=$CPP
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-$as_echo "$CPP" >&6; }
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
-do
-  # Use a header file that comes with gcc, so configuring glibc
-  # with a fresh cross-compiler works.
-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-  # <limits.h> exists even on freestanding compilers.
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp. "Syntax error" is here to catch this case.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-                    Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-
-else
-  # Broken: fails on valid input.
-continue
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-  # OK, works on sane cases.  Now check whether nonexistent headers
-  # can be detected and how.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  # Broken: success on invalid input.
-continue
-else
-  # Passes both tests.
-ac_preproc_ok=:
-break
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_header_stdc=yes
-else
-  ac_cv_header_stdc=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
-  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "memchr" >/dev/null 2>&1; then :
-
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "free" >/dev/null 2>&1; then :
-
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
-  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-  if test "$cross_compiling" = yes; then :
-  :
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
-                  (('a' <= (c) && (c) <= 'i') \
-                    || ('j' <= (c) && (c) <= 'r') \
-                    || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
-  int i;
-  for (i = 0; i < 256; i++)
-    if (XOR (islower (i), ISLOWER (i))
-       || toupper (i) != TOUPPER (i))
-      return 2;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-else
-  ac_cv_header_stdc=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-$as_echo "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
-                 inttypes.h stdint.h unistd.h
-do :
-  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
-done
-
-
-for ac_header in dlfcn.h
-do :
-  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
-"
-if test "x$ac_cv_header_dlfcn_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_DLFCN_H 1
-_ACEOF
-
-fi
-
-done
-
-
-
-
-
-# Set options
-
-
-
-        enable_dlopen=no
-
-
-  enable_win32_dll=no
-
-
-            # Check whether --enable-shared was given.
-if test "${enable_shared+set}" = set; then :
-  enableval=$enable_shared; p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_shared=yes ;;
-    no) enable_shared=no ;;
-    *)
-      enable_shared=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for pkg in $enableval; do
-       IFS=$lt_save_ifs
-       if test "X$pkg" = "X$p"; then
-         enable_shared=yes
-       fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac
-else
-  enable_shared=yes
-fi
-
-
-
-
-
-
-
-
-
-  # Check whether --enable-static was given.
-if test "${enable_static+set}" = set; then :
-  enableval=$enable_static; p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_static=yes ;;
-    no) enable_static=no ;;
-    *)
-     enable_static=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for pkg in $enableval; do
-       IFS=$lt_save_ifs
-       if test "X$pkg" = "X$p"; then
-         enable_static=yes
-       fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac
-else
-  enable_static=yes
-fi
-
-
-
-
-
-
-
-
-
-
-# Check whether --with-pic was given.
-if test "${with_pic+set}" = set; then :
-  withval=$with_pic; lt_p=${PACKAGE-default}
-    case $withval in
-    yes|no) pic_mode=$withval ;;
-    *)
-      pic_mode=default
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for lt_pkg in $withval; do
-       IFS=$lt_save_ifs
-       if test "X$lt_pkg" = "X$lt_p"; then
-         pic_mode=yes
-       fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac
-else
-  pic_mode=default
-fi
-
-
-
-
-
-
-
-
-  # Check whether --enable-fast-install was given.
-if test "${enable_fast_install+set}" = set; then :
-  enableval=$enable_fast_install; p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_fast_install=yes ;;
-    no) enable_fast_install=no ;;
-    *)
-      enable_fast_install=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
-      for pkg in $enableval; do
-       IFS=$lt_save_ifs
-       if test "X$pkg" = "X$p"; then
-         enable_fast_install=yes
-       fi
-      done
-      IFS=$lt_save_ifs
-      ;;
-    esac
-else
-  enable_fast_install=yes
-fi
-
-
-
-
-
-
-
-
-  shared_archive_member_spec=
-case $host,$enable_shared in
-power*-*-aix[5-9]*,yes)
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
-$as_echo_n "checking which variant of shared library versioning to provide... " >&6; }
-
-# Check whether --with-aix-soname was given.
-if test "${with_aix_soname+set}" = set; then :
-  withval=$with_aix_soname; case $withval in
-    aix|svr4|both)
-      ;;
-    *)
-      as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5
-      ;;
-    esac
-    lt_cv_with_aix_soname=$with_aix_soname
-else
-  if ${lt_cv_with_aix_soname+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_with_aix_soname=aix
-fi
-
-    with_aix_soname=$lt_cv_with_aix_soname
-fi
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
-$as_echo "$with_aix_soname" >&6; }
-  if test aix != "$with_aix_soname"; then
-    # For the AIX way of multilib, we name the shared archive member
-    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
-    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
-    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
-    # the AIX toolchain works better with OBJECT_MODE set (default 32).
-    if test 64 = "${OBJECT_MODE-32}"; then
-      shared_archive_member_spec=shr_64
-    else
-      shared_archive_member_spec=shr
-    fi
-  fi
-  ;;
-*)
-  with_aix_soname=aix
-  ;;
-esac
-
-
-
-
-
-
-
-
-
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS=$ltmain
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-test -z "$LN_S" && LN_S="ln -s"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-if test -n "${ZSH_VERSION+set}"; then
-   setopt NO_GLOB_SUBST
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
-$as_echo_n "checking for objdir... " >&6; }
-if ${lt_cv_objdir+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
-  lt_cv_objdir=.libs
-else
-  # MS-DOS does not allow filenames that begin with a dot.
-  lt_cv_objdir=_libs
-fi
-rmdir .libs 2>/dev/null
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
-$as_echo "$lt_cv_objdir" >&6; }
-objdir=$lt_cv_objdir
-
-
-
-
-
-cat >>confdefs.h <<_ACEOF
-#define LT_OBJDIR "$lt_cv_objdir/"
-_ACEOF
-
-
-
-
-case $host_os in
-aix3*)
-  # AIX sometimes has problems with the GCC collect2 program.  For some
-  # reason, if we set the COLLECT_NAMES environment variable, the problems
-  # vanish in a puff of smoke.
-  if test set != "${COLLECT_NAMES+set}"; then
-    COLLECT_NAMES=
-    export COLLECT_NAMES
-  fi
-  ;;
-esac
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a '.a' archive for static linking (except MSVC,
-# which needs '.lib').
-libext=a
-
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-old_CC=$CC
-old_CFLAGS=$CFLAGS
-
-# Set sane defaults for various variables
-test -z "$CC" && CC=cc
-test -z "$LTCC" && LTCC=$CC
-test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
-test -z "$LD" && LD=ld
-test -z "$ac_objext" && ac_objext=o
-
-func_cc_basename $compiler
-cc_basename=$func_cc_basename_result
-
-
-# Only perform the check for file, if the check method requires it
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-case $deplibs_check_method in
-file_magic*)
-  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
-$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
-if ${lt_cv_path_MAGIC_CMD+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $MAGIC_CMD in
-[\\/*] |  ?:[\\/]*)
-  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
-  ;;
-*)
-  lt_save_MAGIC_CMD=$MAGIC_CMD
-  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
-  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
-  for ac_dir in $ac_dummy; do
-    IFS=$lt_save_ifs
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/${ac_tool_prefix}file"; then
-      lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file"
-      if test -n "$file_magic_test_file"; then
-       case $deplibs_check_method in
-       "file_magic "*)
-         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
-         MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
-           $EGREP "$file_magic_regex" > /dev/null; then
-           :
-         else
-           cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such.  This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem.  Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
-         fi ;;
-       esac
-      fi
-      break
-    fi
-  done
-  IFS=$lt_save_ifs
-  MAGIC_CMD=$lt_save_MAGIC_CMD
-  ;;
-esac
-fi
-
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
-$as_echo "$MAGIC_CMD" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-
-
-
-if test -z "$lt_cv_path_MAGIC_CMD"; then
-  if test -n "$ac_tool_prefix"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
-$as_echo_n "checking for file... " >&6; }
-if ${lt_cv_path_MAGIC_CMD+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $MAGIC_CMD in
-[\\/*] |  ?:[\\/]*)
-  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
-  ;;
-*)
-  lt_save_MAGIC_CMD=$MAGIC_CMD
-  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
-  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
-  for ac_dir in $ac_dummy; do
-    IFS=$lt_save_ifs
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/file"; then
-      lt_cv_path_MAGIC_CMD=$ac_dir/"file"
-      if test -n "$file_magic_test_file"; then
-       case $deplibs_check_method in
-       "file_magic "*)
-         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
-         MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
-           $EGREP "$file_magic_regex" > /dev/null; then
-           :
-         else
-           cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such.  This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem.  Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
-         fi ;;
-       esac
-      fi
-      break
-    fi
-  done
-  IFS=$lt_save_ifs
-  MAGIC_CMD=$lt_save_MAGIC_CMD
-  ;;
-esac
-fi
-
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
-$as_echo "$MAGIC_CMD" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  else
-    MAGIC_CMD=:
-  fi
-fi
-
-  fi
-  ;;
-esac
-
-# Use C for the default configuration in the libtool script
-
-lt_save_CC=$CC
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-# Source file extension for C test sources.
-ac_ext=c
-
-# Object file extension for compiled C test sources.
-objext=o
-objext=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="int some_variable = 0;"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
-
-
-
-
-
-
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-
-# Save the default compiler, since it gets overwritten when the other
-# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
-compiler_DEFAULT=$CC
-
-# save warnings/boilerplate of simple test code
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_compile_test_code" >conftest.$ac_ext
-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_compiler_boilerplate=`cat conftest.err`
-$RM conftest*
-
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_link_test_code" >conftest.$ac_ext
-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_linker_boilerplate=`cat conftest.err`
-$RM -r conftest*
-
-
-## CAVEAT EMPTOR:
-## There is no encapsulation within the following macros, do not change
-## the running order or otherwise move them around unless you know exactly
-## what you are doing...
-if test -n "$compiler"; then
-
-lt_prog_compiler_no_builtin_flag=
-
-if test yes = "$GCC"; then
-  case $cc_basename in
-  nvcc*)
-    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
-  *)
-    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
-  esac
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
-$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
-if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_prog_compiler_rtti_exceptions=no
-   ac_outfile=conftest.$ac_objext
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="-fno-rtti -fno-exceptions"  ## exclude from sc_useless_quotes_in_assignment
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   # The option is referenced via a variable to avoid confusing sed.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
-   (eval "$lt_compile" 2>conftest.err)
-   ac_status=$?
-   cat conftest.err >&5
-   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-   if (exit $ac_status) && test -s "$ac_outfile"; then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings other than the usual output.
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
-     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
-       lt_cv_prog_compiler_rtti_exceptions=yes
-     fi
-   fi
-   $RM conftest*
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
-$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
-
-if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
-    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
-else
-    :
-fi
-
-fi
-
-
-
-
-
-
-  lt_prog_compiler_wl=
-lt_prog_compiler_pic=
-lt_prog_compiler_static=
-
-
-  if test yes = "$GCC"; then
-    lt_prog_compiler_wl='-Wl,'
-    lt_prog_compiler_static='-static'
-
-    case $host_os in
-      aix*)
-      # All AIX code is PIC.
-      if test ia64 = "$host_cpu"; then
-       # AIX 5 now supports IA64 processor
-       lt_prog_compiler_static='-Bstatic'
-      fi
-      lt_prog_compiler_pic='-fPIC'
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            lt_prog_compiler_pic='-fPIC'
-        ;;
-      m68k)
-            # FIXME: we need at least 68020 code to build shared libraries, but
-            # adding the '-m68020' flag to GCC prevents building anything better,
-            # like '-m68040'.
-            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
-        ;;
-      esac
-      ;;
-
-    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
-      # PIC is the default for these OSes.
-      ;;
-
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      # Although the cygwin gcc ignores -fPIC, still need this for old-style
-      # (--disable-auto-import) libraries
-      lt_prog_compiler_pic='-DDLL_EXPORT'
-      case $host_os in
-      os2*)
-       lt_prog_compiler_static='$wl-static'
-       ;;
-      esac
-      ;;
-
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      lt_prog_compiler_pic='-fno-common'
-      ;;
-
-    haiku*)
-      # PIC is the default for Haiku.
-      # The "-static" flag exists, but is broken.
-      lt_prog_compiler_static=
-      ;;
-
-    hpux*)
-      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
-      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
-      # sets the default TLS model and affects inlining.
-      case $host_cpu in
-      hppa*64*)
-       # +Z the default
-       ;;
-      *)
-       lt_prog_compiler_pic='-fPIC'
-       ;;
-      esac
-      ;;
-
-    interix[3-9]*)
-      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
-      # Instead, we relocate shared libraries at runtime.
-      ;;
-
-    msdosdjgpp*)
-      # Just because we use GCC doesn't mean we suddenly get shared libraries
-      # on systems that don't support them.
-      lt_prog_compiler_can_build_shared=no
-      enable_shared=no
-      ;;
-
-    *nto* | *qnx*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      lt_prog_compiler_pic='-fPIC -shared'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       lt_prog_compiler_pic=-Kconform_pic
-      fi
-      ;;
-
-    *)
-      lt_prog_compiler_pic='-fPIC'
-      ;;
-    esac
-
-    case $cc_basename in
-    nvcc*) # Cuda Compiler Driver 2.2
-      lt_prog_compiler_wl='-Xlinker '
-      if test -n "$lt_prog_compiler_pic"; then
-        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
-      fi
-      ;;
-    esac
-  else
-    # PORTME Check for flag to pass linker flags through the system compiler.
-    case $host_os in
-    aix*)
-      lt_prog_compiler_wl='-Wl,'
-      if test ia64 = "$host_cpu"; then
-       # AIX 5 now supports IA64 processor
-       lt_prog_compiler_static='-Bstatic'
-      else
-       lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
-      fi
-      ;;
-
-    darwin* | rhapsody*)
-      # PIC is the default on this platform
-      # Common symbols not allowed in MH_DYLIB files
-      lt_prog_compiler_pic='-fno-common'
-      case $cc_basename in
-      nagfor*)
-        # NAG Fortran compiler
-        lt_prog_compiler_wl='-Wl,-Wl,,'
-        lt_prog_compiler_pic='-PIC'
-        lt_prog_compiler_static='-Bstatic'
-        ;;
-      esac
-      ;;
-
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
-      # This hack is so that the source file can tell whether it is being
-      # built for inclusion in a dll (and should export symbols for example).
-      lt_prog_compiler_pic='-DDLL_EXPORT'
-      case $host_os in
-      os2*)
-       lt_prog_compiler_static='$wl-static'
-       ;;
-      esac
-      ;;
-
-    hpux9* | hpux10* | hpux11*)
-      lt_prog_compiler_wl='-Wl,'
-      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
-      # not for PA HP-UX.
-      case $host_cpu in
-      hppa*64*|ia64*)
-       # +Z the default
-       ;;
-      *)
-       lt_prog_compiler_pic='+Z'
-       ;;
-      esac
-      # Is there a better lt_prog_compiler_static that works with the bundled CC?
-      lt_prog_compiler_static='$wl-a ${wl}archive'
-      ;;
-
-    irix5* | irix6* | nonstopux*)
-      lt_prog_compiler_wl='-Wl,'
-      # PIC (with -KPIC) is the default.
-      lt_prog_compiler_static='-non_shared'
-      ;;
-
-    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-      case $cc_basename in
-      # old Intel for x86_64, which still supported -KPIC.
-      ecc*)
-       lt_prog_compiler_wl='-Wl,'
-       lt_prog_compiler_pic='-KPIC'
-       lt_prog_compiler_static='-static'
-        ;;
-      # icc used to be incompatible with GCC.
-      # ICC 10 doesn't accept -KPIC any more.
-      icc* | ifort*)
-       lt_prog_compiler_wl='-Wl,'
-       lt_prog_compiler_pic='-fPIC'
-       lt_prog_compiler_static='-static'
-        ;;
-      # Lahey Fortran 8.1.
-      lf95*)
-       lt_prog_compiler_wl='-Wl,'
-       lt_prog_compiler_pic='--shared'
-       lt_prog_compiler_static='--static'
-       ;;
-      nagfor*)
-       # NAG Fortran compiler
-       lt_prog_compiler_wl='-Wl,-Wl,,'
-       lt_prog_compiler_pic='-PIC'
-       lt_prog_compiler_static='-Bstatic'
-       ;;
-      tcc*)
-       # Fabrice Bellard et al's Tiny C Compiler
-       lt_prog_compiler_wl='-Wl,'
-       lt_prog_compiler_pic='-fPIC'
-       lt_prog_compiler_static='-static'
-       ;;
-      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
-        # Portland Group compilers (*not* the Pentium gcc compiler,
-       # which looks to be a dead project)
-       lt_prog_compiler_wl='-Wl,'
-       lt_prog_compiler_pic='-fpic'
-       lt_prog_compiler_static='-Bstatic'
-        ;;
-      ccc*)
-        lt_prog_compiler_wl='-Wl,'
-        # All Alpha code is PIC.
-        lt_prog_compiler_static='-non_shared'
-        ;;
-      xl* | bgxl* | bgf* | mpixl*)
-       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
-       lt_prog_compiler_wl='-Wl,'
-       lt_prog_compiler_pic='-qpic'
-       lt_prog_compiler_static='-qstaticlink'
-       ;;
-      *)
-       case `$CC -V 2>&1 | sed 5q` in
-       *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
-         # Sun Fortran 8.3 passes all unrecognized flags to the linker
-         lt_prog_compiler_pic='-KPIC'
-         lt_prog_compiler_static='-Bstatic'
-         lt_prog_compiler_wl=''
-         ;;
-       *Sun\ F* | *Sun*Fortran*)
-         lt_prog_compiler_pic='-KPIC'
-         lt_prog_compiler_static='-Bstatic'
-         lt_prog_compiler_wl='-Qoption ld '
-         ;;
-       *Sun\ C*)
-         # Sun C 5.9
-         lt_prog_compiler_pic='-KPIC'
-         lt_prog_compiler_static='-Bstatic'
-         lt_prog_compiler_wl='-Wl,'
-         ;;
-        *Intel*\ [CF]*Compiler*)
-         lt_prog_compiler_wl='-Wl,'
-         lt_prog_compiler_pic='-fPIC'
-         lt_prog_compiler_static='-static'
-         ;;
-       *Portland\ Group*)
-         lt_prog_compiler_wl='-Wl,'
-         lt_prog_compiler_pic='-fpic'
-         lt_prog_compiler_static='-Bstatic'
-         ;;
-       esac
-       ;;
-      esac
-      ;;
-
-    newsos6)
-      lt_prog_compiler_pic='-KPIC'
-      lt_prog_compiler_static='-Bstatic'
-      ;;
-
-    *nto* | *qnx*)
-      # QNX uses GNU C++, but need to define -shared option too, otherwise
-      # it will coredump.
-      lt_prog_compiler_pic='-fPIC -shared'
-      ;;
-
-    osf3* | osf4* | osf5*)
-      lt_prog_compiler_wl='-Wl,'
-      # All OSF/1 code is PIC.
-      lt_prog_compiler_static='-non_shared'
-      ;;
-
-    rdos*)
-      lt_prog_compiler_static='-non_shared'
-      ;;
-
-    solaris*)
-      lt_prog_compiler_pic='-KPIC'
-      lt_prog_compiler_static='-Bstatic'
-      case $cc_basename in
-      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
-       lt_prog_compiler_wl='-Qoption ld ';;
-      *)
-       lt_prog_compiler_wl='-Wl,';;
-      esac
-      ;;
-
-    sunos4*)
-      lt_prog_compiler_wl='-Qoption ld '
-      lt_prog_compiler_pic='-PIC'
-      lt_prog_compiler_static='-Bstatic'
-      ;;
-
-    sysv4 | sysv4.2uw2* | sysv4.3*)
-      lt_prog_compiler_wl='-Wl,'
-      lt_prog_compiler_pic='-KPIC'
-      lt_prog_compiler_static='-Bstatic'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       lt_prog_compiler_pic='-Kconform_pic'
-       lt_prog_compiler_static='-Bstatic'
-      fi
-      ;;
-
-    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
-      lt_prog_compiler_wl='-Wl,'
-      lt_prog_compiler_pic='-KPIC'
-      lt_prog_compiler_static='-Bstatic'
-      ;;
-
-    unicos*)
-      lt_prog_compiler_wl='-Wl,'
-      lt_prog_compiler_can_build_shared=no
-      ;;
-
-    uts4*)
-      lt_prog_compiler_pic='-pic'
-      lt_prog_compiler_static='-Bstatic'
-      ;;
-
-    *)
-      lt_prog_compiler_can_build_shared=no
-      ;;
-    esac
-  fi
-
-case $host_os in
-  # For platforms that do not support PIC, -DPIC is meaningless:
-  *djgpp*)
-    lt_prog_compiler_pic=
-    ;;
-  *)
-    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
-    ;;
-esac
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
-$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
-if ${lt_cv_prog_compiler_pic+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
-$as_echo "$lt_cv_prog_compiler_pic" >&6; }
-lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
-
-#
-# Check to make sure the PIC flag actually works.
-#
-if test -n "$lt_prog_compiler_pic"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
-$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
-if ${lt_cv_prog_compiler_pic_works+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_prog_compiler_pic_works=no
-   ac_outfile=conftest.$ac_objext
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"  ## exclude from sc_useless_quotes_in_assignment
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   # The option is referenced via a variable to avoid confusing sed.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
-   (eval "$lt_compile" 2>conftest.err)
-   ac_status=$?
-   cat conftest.err >&5
-   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-   if (exit $ac_status) && test -s "$ac_outfile"; then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings other than the usual output.
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
-     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
-       lt_cv_prog_compiler_pic_works=yes
-     fi
-   fi
-   $RM conftest*
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
-$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
-
-if test yes = "$lt_cv_prog_compiler_pic_works"; then
-    case $lt_prog_compiler_pic in
-     "" | " "*) ;;
-     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
-     esac
-else
-    lt_prog_compiler_pic=
-     lt_prog_compiler_can_build_shared=no
-fi
-
-fi
-
-
-
-
-
-
-
-
-
-
-
-#
-# Check to make sure the static flag actually works.
-#
-wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
-$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if ${lt_cv_prog_compiler_static_works+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_prog_compiler_static_works=no
-   save_LDFLAGS=$LDFLAGS
-   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
-   echo "$lt_simple_link_test_code" > conftest.$ac_ext
-   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
-     # The linker can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     if test -s conftest.err; then
-       # Append any errors to the config.log.
-       cat conftest.err 1>&5
-       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
-       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-       if diff conftest.exp conftest.er2 >/dev/null; then
-         lt_cv_prog_compiler_static_works=yes
-       fi
-     else
-       lt_cv_prog_compiler_static_works=yes
-     fi
-   fi
-   $RM -r conftest*
-   LDFLAGS=$save_LDFLAGS
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
-$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
-
-if test yes = "$lt_cv_prog_compiler_static_works"; then
-    :
-else
-    lt_prog_compiler_static=
-fi
-
-
-
-
-
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if ${lt_cv_prog_compiler_c_o+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_prog_compiler_c_o=no
-   $RM -r conftest 2>/dev/null
-   mkdir conftest
-   cd conftest
-   mkdir out
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-   lt_compiler_flag="-o out/conftest2.$ac_objext"
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
-   (eval "$lt_compile" 2>out/conftest.err)
-   ac_status=$?
-   cat out/conftest.err >&5
-   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-   if (exit $ac_status) && test -s out/conftest2.$ac_objext
-   then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
-     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
-     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
-       lt_cv_prog_compiler_c_o=yes
-     fi
-   fi
-   chmod u+w . 2>&5
-   $RM conftest*
-   # SGI C++ compiler will create directory out/ii_files/ for
-   # template instantiation
-   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
-   $RM out/* && rmdir out
-   cd ..
-   $RM -r conftest
-   $RM conftest*
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
-$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
-
-
-
-
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if ${lt_cv_prog_compiler_c_o+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_prog_compiler_c_o=no
-   $RM -r conftest 2>/dev/null
-   mkdir conftest
-   cd conftest
-   mkdir out
-   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-   lt_compiler_flag="-o out/conftest2.$ac_objext"
-   # Insert the option either (1) after the last *FLAGS variable, or
-   # (2) before a word containing "conftest.", or (3) at the end.
-   # Note that $ac_compile itself does not contain backslashes and begins
-   # with a dollar sign (not a hyphen), so the echo should work correctly.
-   lt_compile=`echo "$ac_compile" | $SED \
-   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-   -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
-   (eval "$lt_compile" 2>out/conftest.err)
-   ac_status=$?
-   cat out/conftest.err >&5
-   echo "$as_me:$LINENO: \$? = $ac_status" >&5
-   if (exit $ac_status) && test -s out/conftest2.$ac_objext
-   then
-     # The compiler can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
-     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
-     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
-       lt_cv_prog_compiler_c_o=yes
-     fi
-   fi
-   chmod u+w . 2>&5
-   $RM conftest*
-   # SGI C++ compiler will create directory out/ii_files/ for
-   # template instantiation
-   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
-   $RM out/* && rmdir out
-   cd ..
-   $RM -r conftest
-   $RM conftest*
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
-$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
-
-
-
-
-hard_links=nottested
-if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
-  # do not overwrite the value of need_locks provided by the user
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
-$as_echo_n "checking if we can lock with hard links... " >&6; }
-  hard_links=yes
-  $RM conftest*
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  touch conftest.a
-  ln conftest.a conftest.b 2>&5 || hard_links=no
-  ln conftest.a conftest.b 2>/dev/null && hard_links=no
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
-$as_echo "$hard_links" >&6; }
-  if test no = "$hard_links"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
-$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
-    need_locks=warn
-  fi
-else
-  need_locks=no
-fi
-
-
-
-
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
-$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
-
-  runpath_var=
-  allow_undefined_flag=
-  always_export_symbols=no
-  archive_cmds=
-  archive_expsym_cmds=
-  compiler_needs_object=no
-  enable_shared_with_static_runtimes=no
-  export_dynamic_flag_spec=
-  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
-  hardcode_automatic=no
-  hardcode_direct=no
-  hardcode_direct_absolute=no
-  hardcode_libdir_flag_spec=
-  hardcode_libdir_separator=
-  hardcode_minus_L=no
-  hardcode_shlibpath_var=unsupported
-  inherit_rpath=no
-  link_all_deplibs=unknown
-  module_cmds=
-  module_expsym_cmds=
-  old_archive_from_new_cmds=
-  old_archive_from_expsyms_cmds=
-  thread_safe_flag_spec=
-  whole_archive_flag_spec=
-  # include_expsyms should be a list of space-separated symbols to be *always*
-  # included in the symbol list
-  include_expsyms=
-  # exclude_expsyms can be an extended regexp of symbols to exclude
-  # it will be wrapped by ' (' and ')$', so one must not match beginning or
-  # end of line.  Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
-  # as well as any symbol that contains 'd'.
-  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
-  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
-  # platforms (ab)use it in PIC code, but their linkers get confused if
-  # the symbol is explicitly referenced.  Since portable code cannot
-  # rely on this symbol name, it's probably fine to never include it in
-  # preloaded symbol tables.
-  # Exclude shared library initialization/finalization symbols.
-  extract_expsyms_cmds=
-
-  case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    # FIXME: the MSVC++ port hasn't been tested in a loooong time
-    # When not using gcc, we currently assume that we are using
-    # Microsoft Visual C++.
-    if test yes != "$GCC"; then
-      with_gnu_ld=no
-    fi
-    ;;
-  interix*)
-    # we just hope/assume this is gcc and not c89 (= MSVC++)
-    with_gnu_ld=yes
-    ;;
-  openbsd* | bitrig*)
-    with_gnu_ld=no
-    ;;
-  linux* | k*bsd*-gnu | gnu*)
-    link_all_deplibs=no
-    ;;
-  esac
-
-  ld_shlibs=yes
-
-  # On some targets, GNU ld is compatible enough with the native linker
-  # that we're better off using the native interface for both.
-  lt_use_gnu_ld_interface=no
-  if test yes = "$with_gnu_ld"; then
-    case $host_os in
-      aix*)
-       # The AIX port of GNU ld has always aspired to compatibility
-       # with the native linker.  However, as the warning in the GNU ld
-       # block says, versions before 2.19.5* couldn't really create working
-       # shared libraries, regardless of the interface used.
-       case `$LD -v 2>&1` in
-         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
-         *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
-         *\ \(GNU\ Binutils\)\ [3-9]*) ;;
-         *)
-           lt_use_gnu_ld_interface=yes
-           ;;
-       esac
-       ;;
-      *)
-       lt_use_gnu_ld_interface=yes
-       ;;
-    esac
-  fi
-
-  if test yes = "$lt_use_gnu_ld_interface"; then
-    # If archive_cmds runs LD, not CC, wlarc should be empty
-    wlarc='$wl'
-
-    # Set some defaults for GNU ld with shared library support. These
-    # are reset later if shared libraries are not supported. Putting them
-    # here allows them to be overridden if necessary.
-    runpath_var=LD_RUN_PATH
-    hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
-    export_dynamic_flag_spec='$wl--export-dynamic'
-    # ancient GNU ld didn't support --whole-archive et. al.
-    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
-      whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
-    else
-      whole_archive_flag_spec=
-    fi
-    supports_anon_versioning=no
-    case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
-      *GNU\ gold*) supports_anon_versioning=yes ;;
-      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
-      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
-      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
-      *\ 2.11.*) ;; # other 2.11 versions
-      *) supports_anon_versioning=yes ;;
-    esac
-
-    # See if GNU ld supports shared libraries.
-    case $host_os in
-    aix[3-9]*)
-      # On AIX/PPC, the GNU linker is very broken
-      if test ia64 != "$host_cpu"; then
-       ld_shlibs=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.19, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support.  If you
-*** really care for shared libraries, you may want to install binutils
-*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
-*** You will then need to restart the configuration process.
-
-_LT_EOF
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-            archive_expsym_cmds=''
-        ;;
-      m68k)
-            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-            hardcode_libdir_flag_spec='-L$libdir'
-            hardcode_minus_L=yes
-        ;;
-      esac
-      ;;
-
-    beos*)
-      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       allow_undefined_flag=unsupported
-       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
-       # support --undefined.  This deserves some investigation.  FIXME
-       archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-      else
-       ld_shlibs=no
-      fi
-      ;;
-
-    cygwin* | mingw* | pw32* | cegcc*)
-      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
-      # as there is no search path for DLLs.
-      hardcode_libdir_flag_spec='-L$libdir'
-      export_dynamic_flag_spec='$wl--export-all-symbols'
-      allow_undefined_flag=unsupported
-      always_export_symbols=no
-      enable_shared_with_static_runtimes=yes
-      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
-      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
-
-      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
-        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-       # If the export-symbols file already is a .def file, use it as
-       # is; otherwise, prepend EXPORTS...
-       archive_expsym_cmds='if   test DEF = "`$SED -n     -e '\''s/^[   ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([     ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
-          cp $export_symbols $output_objdir/$soname.def;
-        else
-          echo EXPORTS > $output_objdir/$soname.def;
-          cat $export_symbols >> $output_objdir/$soname.def;
-        fi~
-        $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
-      else
-       ld_shlibs=no
-      fi
-      ;;
-
-    haiku*)
-      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-      link_all_deplibs=yes
-      ;;
-
-    os2*)
-      hardcode_libdir_flag_spec='-L$libdir'
-      hardcode_minus_L=yes
-      allow_undefined_flag=unsupported
-      shrext_cmds=.dll
-      archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-       $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-       $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-       $ECHO EXPORTS >> $output_objdir/$libname.def~
-       emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
-       $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-       emximp -o $lib $output_objdir/$libname.def'
-      archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-       $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-       $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-       $ECHO EXPORTS >> $output_objdir/$libname.def~
-       prefix_cmds="$SED"~
-       if test EXPORTS = "`$SED 1q $export_symbols`"; then
-         prefix_cmds="$prefix_cmds -e 1d";
-       fi~
-       prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
-       cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
-       $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-       emximp -o $lib $output_objdir/$libname.def'
-      old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
-      enable_shared_with_static_runtimes=yes
-      ;;
-
-    interix[3-9]*)
-      hardcode_direct=no
-      hardcode_shlibpath_var=no
-      hardcode_libdir_flag_spec='$wl-rpath,$libdir'
-      export_dynamic_flag_spec='$wl-E'
-      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
-      # Instead, shared libraries are loaded at an image base (0x10000000 by
-      # default) and relocated if they conflict, which is a slow very memory
-      # consuming and fragmenting process.  To avoid this, we pick a random,
-      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
-      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
-      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
-      ;;
-
-    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
-      tmp_diet=no
-      if test linux-dietlibc = "$host_os"; then
-       case $cc_basename in
-         diet\ *) tmp_diet=yes;;       # linux-dietlibc with static linking (!diet-dyn)
-       esac
-      fi
-      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
-        && test no = "$tmp_diet"
-      then
-       tmp_addflag=' $pic_flag'
-       tmp_sharedflag='-shared'
-       case $cc_basename,$host_cpu in
-        pgcc*)                         # Portland Group C compiler
-         whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-         tmp_addflag=' $pic_flag'
-         ;;
-       pgf77* | pgf90* | pgf95* | pgfortran*)
-                                       # Portland Group f77 and f90 compilers
-         whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-         tmp_addflag=' $pic_flag -Mnomain' ;;
-       ecc*,ia64* | icc*,ia64*)        # Intel C compiler on ia64
-         tmp_addflag=' -i_dynamic' ;;
-       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
-         tmp_addflag=' -i_dynamic -nofor_main' ;;
-       ifc* | ifort*)                  # Intel Fortran compiler
-         tmp_addflag=' -nofor_main' ;;
-       lf95*)                          # Lahey Fortran 8.1
-         whole_archive_flag_spec=
-         tmp_sharedflag='--shared' ;;
-        nagfor*)                        # NAGFOR 5.3
-          tmp_sharedflag='-Wl,-shared' ;;
-       xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
-         tmp_sharedflag='-qmkshrobj'
-         tmp_addflag= ;;
-       nvcc*)  # Cuda Compiler Driver 2.2
-         whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-         compiler_needs_object=yes
-         ;;
-       esac
-       case `$CC -V 2>&1 | sed 5q` in
-       *Sun\ C*)                       # Sun C 5.9
-         whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
-         compiler_needs_object=yes
-         tmp_sharedflag='-G' ;;
-       *Sun\ F*)                       # Sun Fortran 8.3
-         tmp_sharedflag='-G' ;;
-       esac
-       archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-
-        if test yes = "$supports_anon_versioning"; then
-          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
-            cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-            echo "local: *; };" >> $output_objdir/$libname.ver~
-            $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
-        fi
-
-       case $cc_basename in
-       tcc*)
-         export_dynamic_flag_spec='-rdynamic'
-         ;;
-       xlf* | bgf* | bgxlf* | mpixlf*)
-         # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
-         whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
-         hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
-         archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
-         if test yes = "$supports_anon_versioning"; then
-           archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
-              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
-              echo "local: *; };" >> $output_objdir/$libname.ver~
-              $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
-         fi
-         ;;
-       esac
-      else
-        ld_shlibs=no
-      fi
-      ;;
-
-    netbsd* | netbsdelf*-gnu)
-      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-       archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
-       wlarc=
-      else
-       archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-       archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-      fi
-      ;;
-
-    solaris*)
-      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
-       ld_shlibs=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
-      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-       archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-      else
-       ld_shlibs=no
-      fi
-      ;;
-
-    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
-      case `$LD -v 2>&1` in
-        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
-       ld_shlibs=no
-       cat <<_LT_EOF 1>&2
-
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
-*** reliably create shared libraries on SCO systems.  Therefore, libtool
-*** is disabling shared libraries support.  We urge you to upgrade GNU
-*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
-       ;;
-       *)
-         # For security reasons, it is highly recommended that you always
-         # use absolute paths for naming shared libraries, and exclude the
-         # DT_RUNPATH tag from executables and libraries.  But doing so
-         # requires that you compile everything twice, which is a pain.
-         if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-           hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
-           archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-           archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-         else
-           ld_shlibs=no
-         fi
-       ;;
-      esac
-      ;;
-
-    sunos4*)
-      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-      wlarc=
-      hardcode_direct=yes
-      hardcode_shlibpath_var=no
-      ;;
-
-    *)
-      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
-       archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-       archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-      else
-       ld_shlibs=no
-      fi
-      ;;
-    esac
-
-    if test no = "$ld_shlibs"; then
-      runpath_var=
-      hardcode_libdir_flag_spec=
-      export_dynamic_flag_spec=
-      whole_archive_flag_spec=
-    fi
-  else
-    # PORTME fill in a description of your system's linker (not GNU ld)
-    case $host_os in
-    aix3*)
-      allow_undefined_flag=unsupported
-      always_export_symbols=yes
-      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
-      # Note: this linker hardcodes the directories in LIBPATH if there
-      # are no directories specified by -L.
-      hardcode_minus_L=yes
-      if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
-       # Neither direct hardcoding nor static linking is supported with a
-       # broken collect2.
-       hardcode_direct=unsupported
-      fi
-      ;;
-
-    aix[4-9]*)
-      if test ia64 = "$host_cpu"; then
-       # On IA64, the linker does run time linking by default, so we don't
-       # have to do anything special.
-       aix_use_runtimelinking=no
-       exp_sym_flag='-Bexport'
-       no_entry_flag=
-      else
-       # If we're using GNU nm, then we don't want the "-C" option.
-       # -C means demangle to GNU nm, but means don't demangle to AIX nm.
-       # Without the "-l" option, or with the "-B" option, AIX nm treats
-       # weak defined symbols like other global defined symbols, whereas
-       # GNU nm marks them as "W".
-       # While the 'weak' keyword is ignored in the Export File, we need
-       # it in the Import File for the 'aix-soname' feature, so we have
-       # to replace the "-B" option with "-P" for AIX nm.
-       if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
-         export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
-       else
-         export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
-       fi
-       aix_use_runtimelinking=no
-
-       # Test if we are trying to use run time linking or normal
-       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
-       # have runtime linking enabled, and use it for executables.
-       # For shared libraries, we enable/disable runtime linking
-       # depending on the kind of the shared library created -
-       # when "with_aix_soname,aix_use_runtimelinking" is:
-       # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
-       # "aix,yes"  lib.so          shared, rtl:yes, for executables
-       #            lib.a           static archive
-       # "both,no"  lib.so.V(shr.o) shared, rtl:yes
-       #            lib.a(lib.so.V) shared, rtl:no,  for executables
-       # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
-       #            lib.a(lib.so.V) shared, rtl:no
-       # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
-       #            lib.a           static archive
-       case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
-         for ld_flag in $LDFLAGS; do
-         if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
-           aix_use_runtimelinking=yes
-           break
-         fi
-         done
-         if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
-           # With aix-soname=svr4, we create the lib.so.V shared archives only,
-           # so we don't have lib.a shared libs to link our executables.
-           # We have to force runtime linking in this case.
-           aix_use_runtimelinking=yes
-           LDFLAGS="$LDFLAGS -Wl,-brtl"
-         fi
-         ;;
-       esac
-
-       exp_sym_flag='-bexport'
-       no_entry_flag='-bnoentry'
-      fi
-
-      # When large executables or shared objects are built, AIX ld can
-      # have problems creating the table of contents.  If linking a library
-      # or program results in "error TOC overflow" add -mminimal-toc to
-      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
-      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
-      archive_cmds=''
-      hardcode_direct=yes
-      hardcode_direct_absolute=yes
-      hardcode_libdir_separator=':'
-      link_all_deplibs=yes
-      file_list_spec='$wl-f,'
-      case $with_aix_soname,$aix_use_runtimelinking in
-      aix,*) ;; # traditional, no import file
-      svr4,* | *,yes) # use import file
-       # The Import File defines what to hardcode.
-       hardcode_direct=no
-       hardcode_direct_absolute=no
-       ;;
-      esac
-
-      if test yes = "$GCC"; then
-       case $host_os in aix4.[012]|aix4.[012].*)
-       # We only want to do this on AIX 4.2 and lower, the check
-       # below for broken collect2 doesn't work under 4.3+
-         collect2name=`$CC -print-prog-name=collect2`
-         if test -f "$collect2name" &&
-          strings "$collect2name" | $GREP resolve_lib_name >/dev/null
-         then
-         # We have reworked collect2
-         :
-         else
-         # We have old collect2
-         hardcode_direct=unsupported
-         # It fails to find uninstalled libraries when the uninstalled
-         # path is not listed in the libpath.  Setting hardcode_minus_L
-         # to unsupported forces relinking
-         hardcode_minus_L=yes
-         hardcode_libdir_flag_spec='-L$libdir'
-         hardcode_libdir_separator=
-         fi
-         ;;
-       esac
-       shared_flag='-shared'
-       if test yes = "$aix_use_runtimelinking"; then
-         shared_flag="$shared_flag "'$wl-G'
-       fi
-       # Need to ensure runtime linking is disabled for the traditional
-       # shared library, or the linker may eventually find shared libraries
-       # /with/ Import File - we do not want to mix them.
-       shared_flag_aix='-shared'
-       shared_flag_svr4='-shared $wl-G'
-      else
-       # not using gcc
-       if test ia64 = "$host_cpu"; then
-       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
-       # chokes on -Wl,-G. The following line is correct:
-         shared_flag='-G'
-       else
-         if test yes = "$aix_use_runtimelinking"; then
-           shared_flag='$wl-G'
-         else
-           shared_flag='$wl-bM:SRE'
-         fi
-         shared_flag_aix='$wl-bM:SRE'
-         shared_flag_svr4='$wl-G'
-       fi
-      fi
-
-      export_dynamic_flag_spec='$wl-bexpall'
-      # It seems that -bexpall does not export symbols beginning with
-      # underscore (_), so it is better to generate a list of symbols to export.
-      always_export_symbols=yes
-      if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
-       # Warning - without using the other runtime loading flags (-brtl),
-       # -berok will link without error, but may produce a broken library.
-       allow_undefined_flag='-berok'
-        # Determine the default libpath from the value encoded in an
-        # empty executable.
-        if test set = "${lt_cv_aix_libpath+set}"; then
-  aix_libpath=$lt_cv_aix_libpath
-else
-  if ${lt_cv_aix_libpath_+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-
-  lt_aix_libpath_sed='
-      /Import File Strings/,/^$/ {
-         /^0/ {
-             s/^0  *\([^ ]*\) *$/\1/
-             p
-         }
-      }'
-  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  # Check for a 64-bit object if we didn't find anything.
-  if test -z "$lt_cv_aix_libpath_"; then
-    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  fi
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-  if test -z "$lt_cv_aix_libpath_"; then
-    lt_cv_aix_libpath_=/usr/lib:/lib
-  fi
-
-fi
-
-  aix_libpath=$lt_cv_aix_libpath_
-fi
-
-        hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
-        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
-      else
-       if test ia64 = "$host_cpu"; then
-         hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib'
-         allow_undefined_flag="-z nodefs"
-         archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
-       else
-        # Determine the default libpath from the value encoded in an
-        # empty executable.
-        if test set = "${lt_cv_aix_libpath+set}"; then
-  aix_libpath=$lt_cv_aix_libpath
-else
-  if ${lt_cv_aix_libpath_+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-
-  lt_aix_libpath_sed='
-      /Import File Strings/,/^$/ {
-         /^0/ {
-             s/^0  *\([^ ]*\) *$/\1/
-             p
-         }
-      }'
-  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  # Check for a 64-bit object if we didn't find anything.
-  if test -z "$lt_cv_aix_libpath_"; then
-    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
-  fi
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-  if test -z "$lt_cv_aix_libpath_"; then
-    lt_cv_aix_libpath_=/usr/lib:/lib
-  fi
-
-fi
-
-  aix_libpath=$lt_cv_aix_libpath_
-fi
-
-        hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
-         # Warning - without using the other run time loading flags,
-         # -berok will link without error, but may produce a broken library.
-         no_undefined_flag=' $wl-bernotok'
-         allow_undefined_flag=' $wl-berok'
-         if test yes = "$with_gnu_ld"; then
-           # We only use this code for GNU lds that support --whole-archive.
-           whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive'
-         else
-           # Exported symbols can be pulled into shared objects from archives
-           whole_archive_flag_spec='$convenience'
-         fi
-         archive_cmds_need_lc=yes
-         archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
-         # -brtl affects multiple linker settings, -berok does not and is overridden later
-         compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
-         if test svr4 != "$with_aix_soname"; then
-           # This is similar to how AIX traditionally builds its shared libraries.
-           archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
-         fi
-         if test aix != "$with_aix_soname"; then
-           archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
-         else
-           # used by -dlpreopen to get the symbols
-           archive_expsym_cmds="$archive_expsym_cmds"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
-         fi
-         archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d'
-       fi
-      fi
-      ;;
-
-    amigaos*)
-      case $host_cpu in
-      powerpc)
-            # see comment about AmigaOS4 .so support
-            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-            archive_expsym_cmds=''
-        ;;
-      m68k)
-            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
-            hardcode_libdir_flag_spec='-L$libdir'
-            hardcode_minus_L=yes
-        ;;
-      esac
-      ;;
-
-    bsdi[45]*)
-      export_dynamic_flag_spec=-rdynamic
-      ;;
-
-    cygwin* | mingw* | pw32* | cegcc*)
-      # When not using gcc, we currently assume that we are using
-      # Microsoft Visual C++.
-      # hardcode_libdir_flag_spec is actually meaningless, as there is
-      # no search path for DLLs.
-      case $cc_basename in
-      cl*)
-       # Native MSVC
-       hardcode_libdir_flag_spec=' '
-       allow_undefined_flag=unsupported
-       always_export_symbols=yes
-       file_list_spec='@'
-       # Tell ltmain to make .lib files, not .a files.
-       libext=lib
-       # Tell ltmain to make .dll files, not .so files.
-       shrext_cmds=.dll
-       # FIXME: Setting linknames here is a bad hack.
-       archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
-       archive_expsym_cmds='if   test DEF = "`$SED -n     -e '\''s/^[   ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([     ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
-            cp "$export_symbols" "$output_objdir/$soname.def";
-            echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
-          else
-            $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
-          fi~
-          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
-          linknames='
-       # The linker will not automatically build a static lib if we build a DLL.
-       # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
-       enable_shared_with_static_runtimes=yes
-       exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
-       export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
-       # Don't use ranlib
-       old_postinstall_cmds='chmod 644 $oldlib'
-       postlink_cmds='lt_outputfile="@OUTPUT@"~
-          lt_tool_outputfile="@TOOL_OUTPUT@"~
-          case $lt_outputfile in
-            *.exe|*.EXE) ;;
-            *)
-              lt_outputfile=$lt_outputfile.exe
-              lt_tool_outputfile=$lt_tool_outputfile.exe
-              ;;
-          esac~
-          if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
-            $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
-            $RM "$lt_outputfile.manifest";
-          fi'
-       ;;
-      *)
-       # Assume MSVC wrapper
-       hardcode_libdir_flag_spec=' '
-       allow_undefined_flag=unsupported
-       # Tell ltmain to make .lib files, not .a files.
-       libext=lib
-       # Tell ltmain to make .dll files, not .so files.
-       shrext_cmds=.dll
-       # FIXME: Setting linknames here is a bad hack.
-       archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
-       # The linker will automatically build a .lib file if we build a DLL.
-       old_archive_from_new_cmds='true'
-       # FIXME: Should let the user specify the lib program.
-       old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
-       enable_shared_with_static_runtimes=yes
-       ;;
-      esac
-      ;;
-
-    darwin* | rhapsody*)
-
-
-  archive_cmds_need_lc=no
-  hardcode_direct=no
-  hardcode_automatic=yes
-  hardcode_shlibpath_var=unsupported
-  if test yes = "$lt_cv_ld_force_load"; then
-    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
-
-  else
-    whole_archive_flag_spec=''
-  fi
-  link_all_deplibs=yes
-  allow_undefined_flag=$_lt_dar_allow_undefined
-  case $cc_basename in
-     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
-     *) _lt_dar_can_shared=$GCC ;;
-  esac
-  if test yes = "$_lt_dar_can_shared"; then
-    output_verbose_link_cmd=func_echo_all
-    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
-    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
-    archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
-    module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
-
-  else
-  ld_shlibs=no
-  fi
-
-      ;;
-
-    dgux*)
-      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_libdir_flag_spec='-L$libdir'
-      hardcode_shlibpath_var=no
-      ;;
-
-    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
-    # support.  Future versions do this automatically, but an explicit c++rt0.o
-    # does not break anything, and helps significantly (at the cost of a little
-    # extra space).
-    freebsd2.2*)
-      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
-      hardcode_libdir_flag_spec='-R$libdir'
-      hardcode_direct=yes
-      hardcode_shlibpath_var=no
-      ;;
-
-    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
-    freebsd2.*)
-      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_direct=yes
-      hardcode_minus_L=yes
-      hardcode_shlibpath_var=no
-      ;;
-
-    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
-    freebsd* | dragonfly*)
-      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-      hardcode_libdir_flag_spec='-R$libdir'
-      hardcode_direct=yes
-      hardcode_shlibpath_var=no
-      ;;
-
-    hpux9*)
-      if test yes = "$GCC"; then
-       archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
-      else
-       archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
-      fi
-      hardcode_libdir_flag_spec='$wl+b $wl$libdir'
-      hardcode_libdir_separator=:
-      hardcode_direct=yes
-
-      # hardcode_minus_L: Not really in the search PATH,
-      # but as the default location of the library.
-      hardcode_minus_L=yes
-      export_dynamic_flag_spec='$wl-E'
-      ;;
-
-    hpux10*)
-      if test yes,no = "$GCC,$with_gnu_ld"; then
-       archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
-      fi
-      if test no = "$with_gnu_ld"; then
-       hardcode_libdir_flag_spec='$wl+b $wl$libdir'
-       hardcode_libdir_separator=:
-       hardcode_direct=yes
-       hardcode_direct_absolute=yes
-       export_dynamic_flag_spec='$wl-E'
-       # hardcode_minus_L: Not really in the search PATH,
-       # but as the default location of the library.
-       hardcode_minus_L=yes
-      fi
-      ;;
-
-    hpux11*)
-      if test yes,no = "$GCC,$with_gnu_ld"; then
-       case $host_cpu in
-       hppa*64*)
-         archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       ia64*)
-         archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       *)
-         archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       esac
-      else
-       case $host_cpu in
-       hppa*64*)
-         archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       ia64*)
-         archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
-         ;;
-       *)
-
-         # Older versions of the 11.00 compiler do not understand -b yet
-         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
-         { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
-$as_echo_n "checking if $CC understands -b... " >&6; }
-if ${lt_cv_prog_compiler__b+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_prog_compiler__b=no
-   save_LDFLAGS=$LDFLAGS
-   LDFLAGS="$LDFLAGS -b"
-   echo "$lt_simple_link_test_code" > conftest.$ac_ext
-   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
-     # The linker can only warn and ignore the option if not recognized
-     # So say no if there are warnings
-     if test -s conftest.err; then
-       # Append any errors to the config.log.
-       cat conftest.err 1>&5
-       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
-       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
-       if diff conftest.exp conftest.er2 >/dev/null; then
-         lt_cv_prog_compiler__b=yes
-       fi
-     else
-       lt_cv_prog_compiler__b=yes
-     fi
-   fi
-   $RM -r conftest*
-   LDFLAGS=$save_LDFLAGS
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
-$as_echo "$lt_cv_prog_compiler__b" >&6; }
-
-if test yes = "$lt_cv_prog_compiler__b"; then
-    archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-else
-    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
-fi
-
-         ;;
-       esac
-      fi
-      if test no = "$with_gnu_ld"; then
-       hardcode_libdir_flag_spec='$wl+b $wl$libdir'
-       hardcode_libdir_separator=:
-
-       case $host_cpu in
-       hppa*64*|ia64*)
-         hardcode_direct=no
-         hardcode_shlibpath_var=no
-         ;;
-       *)
-         hardcode_direct=yes
-         hardcode_direct_absolute=yes
-         export_dynamic_flag_spec='$wl-E'
-
-         # hardcode_minus_L: Not really in the search PATH,
-         # but as the default location of the library.
-         hardcode_minus_L=yes
-         ;;
-       esac
-      fi
-      ;;
-
-    irix5* | irix6* | nonstopux*)
-      if test yes = "$GCC"; then
-       archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-       # Try to use the -exported_symbol ld option, if it does not
-       # work, assume that -exports_file does not work either and
-       # implicitly export all symbols.
-       # This should be the same for all languages, so no per-tag cache variable.
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
-$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
-if ${lt_cv_irix_exported_symbol+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  save_LDFLAGS=$LDFLAGS
-          LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
-          cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-int foo (void) { return 0; }
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  lt_cv_irix_exported_symbol=yes
-else
-  lt_cv_irix_exported_symbol=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-           LDFLAGS=$save_LDFLAGS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
-$as_echo "$lt_cv_irix_exported_symbol" >&6; }
-       if test yes = "$lt_cv_irix_exported_symbol"; then
-          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
-       fi
-       link_all_deplibs=no
-      else
-       archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-       archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
-      fi
-      archive_cmds_need_lc='no'
-      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
-      hardcode_libdir_separator=:
-      inherit_rpath=yes
-      link_all_deplibs=yes
-      ;;
-
-    linux*)
-      case $cc_basename in
-      tcc*)
-       # Fabrice Bellard et al's Tiny C Compiler
-       ld_shlibs=yes
-       archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-       ;;
-      esac
-      ;;
-
-    netbsd* | netbsdelf*-gnu)
-      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-       archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
-      else
-       archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
-      fi
-      hardcode_libdir_flag_spec='-R$libdir'
-      hardcode_direct=yes
-      hardcode_shlibpath_var=no
-      ;;
-
-    newsos6)
-      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_direct=yes
-      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
-      hardcode_libdir_separator=:
-      hardcode_shlibpath_var=no
-      ;;
-
-    *nto* | *qnx*)
-      ;;
-
-    openbsd* | bitrig*)
-      if test -f /usr/libexec/ld.so; then
-       hardcode_direct=yes
-       hardcode_shlibpath_var=no
-       hardcode_direct_absolute=yes
-       if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
-         archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-         archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
-         hardcode_libdir_flag_spec='$wl-rpath,$libdir'
-         export_dynamic_flag_spec='$wl-E'
-       else
-         archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
-         hardcode_libdir_flag_spec='$wl-rpath,$libdir'
-       fi
-      else
-       ld_shlibs=no
-      fi
-      ;;
-
-    os2*)
-      hardcode_libdir_flag_spec='-L$libdir'
-      hardcode_minus_L=yes
-      allow_undefined_flag=unsupported
-      shrext_cmds=.dll
-      archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-       $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-       $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-       $ECHO EXPORTS >> $output_objdir/$libname.def~
-       emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
-       $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-       emximp -o $lib $output_objdir/$libname.def'
-      archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
-       $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
-       $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
-       $ECHO EXPORTS >> $output_objdir/$libname.def~
-       prefix_cmds="$SED"~
-       if test EXPORTS = "`$SED 1q $export_symbols`"; then
-         prefix_cmds="$prefix_cmds -e 1d";
-       fi~
-       prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
-       cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
-       $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
-       emximp -o $lib $output_objdir/$libname.def'
-      old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
-      enable_shared_with_static_runtimes=yes
-      ;;
-
-    osf3*)
-      if test yes = "$GCC"; then
-       allow_undefined_flag=' $wl-expect_unresolved $wl\*'
-       archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-      else
-       allow_undefined_flag=' -expect_unresolved \*'
-       archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-      fi
-      archive_cmds_need_lc='no'
-      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
-      hardcode_libdir_separator=:
-      ;;
-
-    osf4* | osf5*)     # as osf3* with the addition of -msym flag
-      if test yes = "$GCC"; then
-       allow_undefined_flag=' $wl-expect_unresolved $wl\*'
-       archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
-       hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
-      else
-       allow_undefined_flag=' -expect_unresolved \*'
-       archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-       archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
-          $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
-
-       # Both c and cxx compiler support -rpath directly
-       hardcode_libdir_flag_spec='-rpath $libdir'
-      fi
-      archive_cmds_need_lc='no'
-      hardcode_libdir_separator=:
-      ;;
-
-    solaris*)
-      no_undefined_flag=' -z defs'
-      if test yes = "$GCC"; then
-       wlarc='$wl'
-       archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
-       archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-          $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
-      else
-       case `$CC -V 2>&1` in
-       *"Compilers 5.0"*)
-         wlarc=''
-         archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-            $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
-         ;;
-       *)
-         wlarc='$wl'
-         archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
-         archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
-            $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
-         ;;
-       esac
-      fi
-      hardcode_libdir_flag_spec='-R$libdir'
-      hardcode_shlibpath_var=no
-      case $host_os in
-      solaris2.[0-5] | solaris2.[0-5].*) ;;
-      *)
-       # The compiler driver will combine and reorder linker options,
-       # but understands '-z linker_flag'.  GCC discards it without '$wl',
-       # but is careful enough not to reorder.
-       # Supported since Solaris 2.6 (maybe 2.5.1?)
-       if test yes = "$GCC"; then
-         whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
-       else
-         whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
-       fi
-       ;;
-      esac
-      link_all_deplibs=yes
-      ;;
-
-    sunos4*)
-      if test sequent = "$host_vendor"; then
-       # Use $CC to link under sequent, because it throws in some extra .o
-       # files that make .init and .fini sections work.
-       archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
-      fi
-      hardcode_libdir_flag_spec='-L$libdir'
-      hardcode_direct=yes
-      hardcode_minus_L=yes
-      hardcode_shlibpath_var=no
-      ;;
-
-    sysv4)
-      case $host_vendor in
-       sni)
-         archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         hardcode_direct=yes # is this really true???
-       ;;
-       siemens)
-         ## LD is ld it makes a PLAMLIB
-         ## CC just makes a GrossModule.
-         archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
-         reload_cmds='$CC -r -o $output$reload_objs'
-         hardcode_direct=no
-        ;;
-       motorola)
-         archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-         hardcode_direct=no #Motorola manual says yes, but my tests say they lie
-       ;;
-      esac
-      runpath_var='LD_RUN_PATH'
-      hardcode_shlibpath_var=no
-      ;;
-
-    sysv4.3*)
-      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_shlibpath_var=no
-      export_dynamic_flag_spec='-Bexport'
-      ;;
-
-    sysv4*MP*)
-      if test -d /usr/nec; then
-       archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-       hardcode_shlibpath_var=no
-       runpath_var=LD_RUN_PATH
-       hardcode_runpath_var=yes
-       ld_shlibs=yes
-      fi
-      ;;
-
-    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
-      no_undefined_flag='$wl-z,text'
-      archive_cmds_need_lc=no
-      hardcode_shlibpath_var=no
-      runpath_var='LD_RUN_PATH'
-
-      if test yes = "$GCC"; then
-       archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      fi
-      ;;
-
-    sysv5* | sco3.2v5* | sco5v6*)
-      # Note: We CANNOT use -z defs as we might desire, because we do not
-      # link with -lc, and that would cause any symbols used from libc to
-      # always be unresolved, which means just about no library would
-      # ever link correctly.  If we're not using GNU ld we use -z text
-      # though, which does catch some bad symbols but isn't as heavy-handed
-      # as -z defs.
-      no_undefined_flag='$wl-z,text'
-      allow_undefined_flag='$wl-z,nodefs'
-      archive_cmds_need_lc=no
-      hardcode_shlibpath_var=no
-      hardcode_libdir_flag_spec='$wl-R,$libdir'
-      hardcode_libdir_separator=':'
-      link_all_deplibs=yes
-      export_dynamic_flag_spec='$wl-Bexport'
-      runpath_var='LD_RUN_PATH'
-
-      if test yes = "$GCC"; then
-       archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      else
-       archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-       archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
-      fi
-      ;;
-
-    uts4*)
-      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
-      hardcode_libdir_flag_spec='-L$libdir'
-      hardcode_shlibpath_var=no
-      ;;
-
-    *)
-      ld_shlibs=no
-      ;;
-    esac
-
-    if test sni = "$host_vendor"; then
-      case $host in
-      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
-       export_dynamic_flag_spec='$wl-Blargedynsym'
-       ;;
-      esac
-    fi
-  fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
-$as_echo "$ld_shlibs" >&6; }
-test no = "$ld_shlibs" && can_build_shared=no
-
-with_gnu_ld=$with_gnu_ld
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-#
-# Do we need to explicitly link libc?
-#
-case "x$archive_cmds_need_lc" in
-x|xyes)
-  # Assume -lc should be added
-  archive_cmds_need_lc=yes
-
-  if test yes,yes = "$GCC,$enable_shared"; then
-    case $archive_cmds in
-    *'~'*)
-      # FIXME: we may have to deal with multi-command sequences.
-      ;;
-    '$CC '*)
-      # Test whether the compiler implicitly links with -lc since on some
-      # systems, -lgcc has to come before -lc. If gcc already passes -lc
-      # to ld, don't add -lc before -lgcc.
-      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
-$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
-if ${lt_cv_archive_cmds_need_lc+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  $RM conftest*
-       echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
-       if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
-  (eval $ac_compile) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } 2>conftest.err; then
-         soname=conftest
-         lib=conftest
-         libobjs=conftest.$ac_objext
-         deplibs=
-         wl=$lt_prog_compiler_wl
-         pic_flag=$lt_prog_compiler_pic
-         compiler_flags=-v
-         linker_flags=-v
-         verstring=
-         output_objdir=.
-         libname=conftest
-         lt_save_allow_undefined_flag=$allow_undefined_flag
-         allow_undefined_flag=
-         if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
-  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-         then
-           lt_cv_archive_cmds_need_lc=no
-         else
-           lt_cv_archive_cmds_need_lc=yes
-         fi
-         allow_undefined_flag=$lt_save_allow_undefined_flag
-       else
-         cat conftest.err 1>&5
-       fi
-       $RM conftest*
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
-$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
-      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
-      ;;
-    esac
-  fi
-  ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
-$as_echo_n "checking dynamic linker characteristics... " >&6; }
-
-if test yes = "$GCC"; then
-  case $host_os in
-    darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
-    *) lt_awk_arg='/^libraries:/' ;;
-  esac
-  case $host_os in
-    mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
-    *) lt_sed_strip_eq='s|=/|/|g' ;;
-  esac
-  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
-  case $lt_search_path_spec in
-  *\;*)
-    # if the path contains ";" then we assume it to be the separator
-    # otherwise default to the standard path separator (i.e. ":") - it is
-    # assumed that no part of a normal pathname contains ";" but that should
-    # okay in the real world where ";" in dirpaths is itself problematic.
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
-    ;;
-  *)
-    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
-    ;;
-  esac
-  # Ok, now we have the path, separated by spaces, we can step through it
-  # and add multilib dir if necessary...
-  lt_tmp_lt_search_path_spec=
-  lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
-  # ...but if some path component already ends with the multilib dir we assume
-  # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
-  case "$lt_multi_os_dir; $lt_search_path_spec " in
-  "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
-    lt_multi_os_dir=
-    ;;
-  esac
-  for lt_sys_path in $lt_search_path_spec; do
-    if test -d "$lt_sys_path$lt_multi_os_dir"; then
-      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
-    elif test -n "$lt_multi_os_dir"; then
-      test -d "$lt_sys_path" && \
-       lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
-    fi
-  done
-  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS = " "; FS = "/|\n";} {
-  lt_foo = "";
-  lt_count = 0;
-  for (lt_i = NF; lt_i > 0; lt_i--) {
-    if ($lt_i != "" && $lt_i != ".") {
-      if ($lt_i == "..") {
-        lt_count++;
-      } else {
-        if (lt_count == 0) {
-          lt_foo = "/" $lt_i lt_foo;
-        } else {
-          lt_count--;
-        }
-      }
-    }
-  }
-  if (lt_foo != "") { lt_freq[lt_foo]++; }
-  if (lt_freq[lt_foo] == 1) { print lt_foo; }
-}'`
-  # AWK program above erroneously prepends '/' to C:/dos/paths
-  # for these hosts.
-  case $host_os in
-    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
-      $SED 's|/\([A-Za-z]:\)|\1|g'` ;;
-  esac
-  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
-else
-  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-fi
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-shrext_cmds=.so
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-need_lib_prefix=unknown
-hardcode_into_libs=no
-
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-need_version=unknown
-
-
-
-case $host_os in
-aix3*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
-  shlibpath_var=LIBPATH
-
-  # AIX 3 has no versioning support, so we append a major version to the name.
-  soname_spec='$libname$release$shared_ext$major'
-  ;;
-
-aix[4-9]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  hardcode_into_libs=yes
-  if test ia64 = "$host_cpu"; then
-    # AIX 5 supports IA64
-    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
-    shlibpath_var=LD_LIBRARY_PATH
-  else
-    # With GCC up to 2.95.x, collect2 would create an import file
-    # for dependence libraries.  The import file would start with
-    # the line '#! .'.  This would cause the generated library to
-    # depend on '.', always an invalid library.  This was fixed in
-    # development snapshots of GCC prior to 3.0.
-    case $host_os in
-      aix4 | aix4.[01] | aix4.[01].*)
-      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
-          echo ' yes '
-          echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
-       :
-      else
-       can_build_shared=no
-      fi
-      ;;
-    esac
-    # Using Import Files as archive members, it is possible to support
-    # filename-based versioning of shared library archives on AIX. While
-    # this would work for both with and without runtime linking, it will
-    # prevent static linking of such archives. So we do filename-based
-    # shared library versioning with .so extension only, which is used
-    # when both runtime linking and shared linking is enabled.
-    # Unfortunately, runtime linking may impact performance, so we do
-    # not want this to be the default eventually. Also, we use the
-    # versioned .so libs for executables only if there is the -brtl
-    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
-    # To allow for filename-based versioning support, we need to create
-    # libNAME.so.V as an archive file, containing:
-    # *) an Import File, referring to the versioned filename of the
-    #    archive as well as the shared archive member, telling the
-    #    bitwidth (32 or 64) of that shared object, and providing the
-    #    list of exported symbols of that shared object, eventually
-    #    decorated with the 'weak' keyword
-    # *) the shared object with the F_LOADONLY flag set, to really avoid
-    #    it being seen by the linker.
-    # At run time we better use the real file rather than another symlink,
-    # but for link time we create the symlink libNAME.so -> libNAME.so.V
-
-    case $with_aix_soname,$aix_use_runtimelinking in
-    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
-    # soname into executable. Probably we can add versioning support to
-    # collect2, so additional links can be useful in future.
-    aix,yes) # traditional libtool
-      dynamic_linker='AIX unversionable lib.so'
-      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
-      # instead of lib<name>.a to let people know that these are not
-      # typical AIX shared libraries.
-      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-      ;;
-    aix,no) # traditional AIX only
-      dynamic_linker='AIX lib.a(lib.so.V)'
-      # We preserve .a as extension for shared libraries through AIX4.2
-      # and later when we are not doing run time linking.
-      library_names_spec='$libname$release.a $libname.a'
-      soname_spec='$libname$release$shared_ext$major'
-      ;;
-    svr4,*) # full svr4 only
-      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
-      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
-      # We do not specify a path in Import Files, so LIBPATH fires.
-      shlibpath_overrides_runpath=yes
-      ;;
-    *,yes) # both, prefer svr4
-      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
-      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
-      # unpreferred sharedlib libNAME.a needs extra handling
-      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
-      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
-      # We do not specify a path in Import Files, so LIBPATH fires.
-      shlibpath_overrides_runpath=yes
-      ;;
-    *,no) # both, prefer aix
-      dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
-      library_names_spec='$libname$release.a $libname.a'
-      soname_spec='$libname$release$shared_ext$major'
-      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
-      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
-      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
-      ;;
-    esac
-    shlibpath_var=LIBPATH
-  fi
-  ;;
-
-amigaos*)
-  case $host_cpu in
-  powerpc)
-    # Since July 2007 AmigaOS4 officially supports .so libraries.
-    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    ;;
-  m68k)
-    library_names_spec='$libname.ixlibrary $libname.a'
-    # Create ${libname}_ixlibrary.a entries in /sys/libs.
-    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
-    ;;
-  esac
-  ;;
-
-beos*)
-  library_names_spec='$libname$shared_ext'
-  dynamic_linker="$host_os ld.so"
-  shlibpath_var=LIBRARY_PATH
-  ;;
-
-bsdi[45]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
-  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
-  # the default ld.so.conf also contains /usr/contrib/lib and
-  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
-  # libtool to hard-code these into programs
-  ;;
-
-cygwin* | mingw* | pw32* | cegcc*)
-  version_type=windows
-  shrext_cmds=.dll
-  need_version=no
-  need_lib_prefix=no
-
-  case $GCC,$cc_basename in
-  yes,*)
-    # gcc
-    library_names_spec='$libname.dll.a'
-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \$file`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog $dir/$dlname \$dldir/$dlname~
-      chmod a+x \$dldir/$dlname~
-      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
-        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
-      fi'
-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $RM \$dlpath'
-    shlibpath_overrides_runpath=yes
-
-    case $host_os in
-    cygwin*)
-      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
-      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
-
-      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
-      ;;
-    mingw* | cegcc*)
-      # MinGW DLLs use traditional 'lib' prefix
-      soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
-      ;;
-    pw32*)
-      # pw32 DLLs use 'pw' prefix rather than 'lib'
-      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
-      ;;
-    esac
-    dynamic_linker='Win32 ld.exe'
-    ;;
-
-  *,cl*)
-    # Native MSVC
-    libname_spec='$name'
-    soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
-    library_names_spec='$libname.dll.lib'
-
-    case $build_os in
-    mingw*)
-      sys_lib_search_path_spec=
-      lt_save_ifs=$IFS
-      IFS=';'
-      for lt_path in $LIB
-      do
-        IFS=$lt_save_ifs
-        # Let DOS variable expansion print the short 8.3 style file name.
-        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
-        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
-      done
-      IFS=$lt_save_ifs
-      # Convert to MSYS style.
-      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
-      ;;
-    cygwin*)
-      # Convert to unix form, then to dos form, then back to unix form
-      # but this time dos style (no spaces!) so that the unix form looks
-      # like /cygdrive/c/PROGRA~1:/cygdr...
-      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
-      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
-      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
-      ;;
-    *)
-      sys_lib_search_path_spec=$LIB
-      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
-        # It is most probably a Windows format PATH.
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
-      else
-        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
-      fi
-      # FIXME: find the short name or the path components, as spaces are
-      # common. (e.g. "Program Files" -> "PROGRA~1")
-      ;;
-    esac
-
-    # DLL is installed to $(libdir)/../bin by postinstall_cmds
-    postinstall_cmds='base_file=`basename \$file`~
-      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
-      dldir=$destdir/`dirname \$dlpath`~
-      test -d \$dldir || mkdir -p \$dldir~
-      $install_prog $dir/$dlname \$dldir/$dlname'
-    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
-      dlpath=$dir/\$dldll~
-       $RM \$dlpath'
-    shlibpath_overrides_runpath=yes
-    dynamic_linker='Win32 link.exe'
-    ;;
-
-  *)
-    # Assume MSVC wrapper
-    library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
-    dynamic_linker='Win32 ld.exe'
-    ;;
-  esac
-  # FIXME: first we should search . and the directory the executable is in
-  shlibpath_var=PATH
-  ;;
-
-darwin* | rhapsody*)
-  dynamic_linker="$host_os dyld"
-  version_type=darwin
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
-  soname_spec='$libname$release$major$shared_ext'
-  shlibpath_overrides_runpath=yes
-  shlibpath_var=DYLD_LIBRARY_PATH
-  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
-
-  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
-  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
-  ;;
-
-dgux*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-freebsd* | dragonfly*)
-  # DragonFly does not have aout.  When/if they implement a new
-  # versioning mechanism, adjust this.
-  if test -x /usr/bin/objformat; then
-    objformat=`/usr/bin/objformat`
-  else
-    case $host_os in
-    freebsd[23].*) objformat=aout ;;
-    *) objformat=elf ;;
-    esac
-  fi
-  version_type=freebsd-$objformat
-  case $version_type in
-    freebsd-elf*)
-      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-      soname_spec='$libname$release$shared_ext$major'
-      need_version=no
-      need_lib_prefix=no
-      ;;
-    freebsd-*)
-      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
-      need_version=yes
-      ;;
-  esac
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_os in
-  freebsd2.*)
-    shlibpath_overrides_runpath=yes
-    ;;
-  freebsd3.[01]* | freebsdelf3.[01]*)
-    shlibpath_overrides_runpath=yes
-    hardcode_into_libs=yes
-    ;;
-  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
-  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
-    shlibpath_overrides_runpath=no
-    hardcode_into_libs=yes
-    ;;
-  *) # from 4.6 on, and DragonFly
-    shlibpath_overrides_runpath=yes
-    hardcode_into_libs=yes
-    ;;
-  esac
-  ;;
-
-haiku*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  dynamic_linker="$host_os runtime_loader"
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
-  hardcode_into_libs=yes
-  ;;
-
-hpux9* | hpux10* | hpux11*)
-  # Give a soname corresponding to the major version so that dld.sl refuses to
-  # link against other versions.
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  case $host_cpu in
-  ia64*)
-    shrext_cmds='.so'
-    hardcode_into_libs=yes
-    dynamic_linker="$host_os dld.so"
-    shlibpath_var=LD_LIBRARY_PATH
-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    soname_spec='$libname$release$shared_ext$major'
-    if test 32 = "$HPUX_IA64_MODE"; then
-      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
-      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
-    else
-      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
-      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
-    fi
-    ;;
-  hppa*64*)
-    shrext_cmds='.sl'
-    hardcode_into_libs=yes
-    dynamic_linker="$host_os dld.sl"
-    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
-    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    soname_spec='$libname$release$shared_ext$major'
-    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
-    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-    ;;
-  *)
-    shrext_cmds='.sl'
-    dynamic_linker="$host_os dld.sl"
-    shlibpath_var=SHLIB_PATH
-    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    soname_spec='$libname$release$shared_ext$major'
-    ;;
-  esac
-  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
-  postinstall_cmds='chmod 555 $lib'
-  # or fails outright, so override atomically:
-  install_override_mode=555
-  ;;
-
-interix[3-9]*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
-irix5* | irix6* | nonstopux*)
-  case $host_os in
-    nonstopux*) version_type=nonstopux ;;
-    *)
-       if test yes = "$lt_cv_prog_gnu_ld"; then
-               version_type=linux # correct to gnu/linux during the next big refactor
-       else
-               version_type=irix
-       fi ;;
-  esac
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='$libname$release$shared_ext$major'
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
-  case $host_os in
-  irix5* | nonstopux*)
-    libsuff= shlibsuff=
-    ;;
-  *)
-    case $LD in # libtool.m4 will add one of these switches to LD
-    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
-      libsuff= shlibsuff= libmagic=32-bit;;
-    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
-      libsuff=32 shlibsuff=N32 libmagic=N32;;
-    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
-      libsuff=64 shlibsuff=64 libmagic=64-bit;;
-    *) libsuff= shlibsuff= libmagic=never-match;;
-    esac
-    ;;
-  esac
-  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
-  shlibpath_overrides_runpath=no
-  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
-  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
-  hardcode_into_libs=yes
-  ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux*oldld* | linux*aout* | linux*coff*)
-  dynamic_linker=no
-  ;;
-
-linux*android*)
-  version_type=none # Android doesn't support versioned libraries.
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext'
-  soname_spec='$libname$release$shared_ext'
-  finish_cmds=
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-
-  # This implies no fast_install, which is unacceptable.
-  # Some rework will be needed to allow for fast_install
-  # before this can be enabled.
-  hardcode_into_libs=yes
-
-  dynamic_linker='Android linker'
-  # Don't embed -rpath directories since the linker doesn't support them.
-  hardcode_libdir_flag_spec='-L$libdir'
-  ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-
-  # Some binutils ld are patched to set DT_RUNPATH
-  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_shlibpath_overrides_runpath=no
-    save_LDFLAGS=$LDFLAGS
-    save_libdir=$libdir
-    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
-        LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
-  lt_cv_shlibpath_overrides_runpath=yes
-fi
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-    LDFLAGS=$save_LDFLAGS
-    libdir=$save_libdir
-
-fi
-
-  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
-
-  # This implies no fast_install, which is unacceptable.
-  # Some rework will be needed to allow for fast_install
-  # before this can be enabled.
-  hardcode_into_libs=yes
-
-  # Ideally, we could use ldconfig to report *all* directores which are
-  # searched for libraries, however this is still not possible.  Aside from not
-  # being certain /sbin/ldconfig is available, command
-  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
-  # even though it is searched at run-time.  Try to do the best guess by
-  # appending ld.so.conf contents (and includes) to the search path.
-  if test -f /etc/ld.so.conf; then
-    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[      ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
-    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
-  fi
-
-  # We used to test for /lib/ld.so.1 and disable shared libraries on
-  # powerpc, because MkLinux only supported shared libraries with the
-  # GNU dynamic linker.  Since this was broken with cross compilers,
-  # most powerpc-linux boxes support dynamic linking these days and
-  # people can always --disable-shared, the test was removed, and we
-  # assume the GNU/Linux dynamic linker is in use.
-  dynamic_linker='GNU/Linux ld.so'
-  ;;
-
-netbsdelf*-gnu)
-  version_type=linux
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  dynamic_linker='NetBSD ld.elf_so'
-  ;;
-
-netbsd*)
-  version_type=sunos
-  need_lib_prefix=no
-  need_version=no
-  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
-    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-    dynamic_linker='NetBSD (a.out) ld.so'
-  else
-    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-    soname_spec='$libname$release$shared_ext$major'
-    dynamic_linker='NetBSD ld.elf_so'
-  fi
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  ;;
-
-newsos6)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  ;;
-
-*nto* | *qnx*)
-  version_type=qnx
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  dynamic_linker='ldqnx.so'
-  ;;
-
-openbsd* | bitrig*)
-  version_type=sunos
-  sys_lib_dlsearch_path_spec=/usr/lib
-  need_lib_prefix=no
-  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
-    need_version=no
-  else
-    need_version=yes
-  fi
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
-  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  ;;
-
-os2*)
-  libname_spec='$name'
-  version_type=windows
-  shrext_cmds=.dll
-  need_version=no
-  need_lib_prefix=no
-  # OS/2 can only load a DLL with a base name of 8 characters or less.
-  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
-    v=$($ECHO $release$versuffix | tr -d .-);
-    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
-    $ECHO $n$v`$shared_ext'
-  library_names_spec='${libname}_dll.$libext'
-  dynamic_linker='OS/2 ld.exe'
-  shlibpath_var=BEGINLIBPATH
-  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-  postinstall_cmds='base_file=`basename \$file`~
-    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
-    dldir=$destdir/`dirname \$dlpath`~
-    test -d \$dldir || mkdir -p \$dldir~
-    $install_prog $dir/$dlname \$dldir/$dlname~
-    chmod a+x \$dldir/$dlname~
-    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
-      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
-    fi'
-  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
-    dlpath=$dir/\$dldll~
-    $RM \$dlpath'
-  ;;
-
-osf3* | osf4* | osf5*)
-  version_type=osf
-  need_lib_prefix=no
-  need_version=no
-  soname_spec='$libname$release$shared_ext$major'
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  shlibpath_var=LD_LIBRARY_PATH
-  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
-  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
-  ;;
-
-rdos*)
-  dynamic_linker=no
-  ;;
-
-solaris*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  # ldd complains unless libraries are executable
-  postinstall_cmds='chmod +x $lib'
-  ;;
-
-sunos4*)
-  version_type=sunos
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
-  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  if test yes = "$with_gnu_ld"; then
-    need_lib_prefix=no
-  fi
-  need_version=yes
-  ;;
-
-sysv4 | sysv4.3*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  case $host_vendor in
-    sni)
-      shlibpath_overrides_runpath=no
-      need_lib_prefix=no
-      runpath_var=LD_RUN_PATH
-      ;;
-    siemens)
-      need_lib_prefix=no
-      ;;
-    motorola)
-      need_lib_prefix=no
-      need_version=no
-      shlibpath_overrides_runpath=no
-      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
-      ;;
-  esac
-  ;;
-
-sysv4*MP*)
-  if test -d /usr/nec; then
-    version_type=linux # correct to gnu/linux during the next big refactor
-    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
-    soname_spec='$libname$shared_ext.$major'
-    shlibpath_var=LD_LIBRARY_PATH
-  fi
-  ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
-  version_type=sco
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=yes
-  hardcode_into_libs=yes
-  if test yes = "$with_gnu_ld"; then
-    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
-  else
-    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
-    case $host_os in
-      sco3.2v5*)
-        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
-       ;;
-    esac
-  fi
-  sys_lib_dlsearch_path_spec='/usr/lib'
-  ;;
-
-tpf*)
-  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
-uts4*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
-  soname_spec='$libname$release$shared_ext$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  ;;
-
-*)
-  dynamic_linker=no
-  ;;
-esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
-$as_echo "$dynamic_linker" >&6; }
-test no = "$dynamic_linker" && can_build_shared=no
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test yes = "$GCC"; then
-  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
-  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
-fi
-
-if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
-  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
-fi
-
-# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
-configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
-
-# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
-func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
-
-# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
-configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
-$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
-hardcode_action=
-if test -n "$hardcode_libdir_flag_spec" ||
-   test -n "$runpath_var" ||
-   test yes = "$hardcode_automatic"; then
-
-  # We can hardcode non-existent directories.
-  if test no != "$hardcode_direct" &&
-     # If the only mechanism to avoid hardcoding is shlibpath_var, we
-     # have to relink, otherwise we might link with an installed library
-     # when we should be linking with a yet-to-be-installed one
-     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
-     test no != "$hardcode_minus_L"; then
-    # Linking always hardcodes the temporary library directory.
-    hardcode_action=relink
-  else
-    # We can link without hardcoding, and we can hardcode nonexisting dirs.
-    hardcode_action=immediate
-  fi
-else
-  # We cannot hardcode anything, or else we can only hardcode existing
-  # directories.
-  hardcode_action=unsupported
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
-$as_echo "$hardcode_action" >&6; }
-
-if test relink = "$hardcode_action" ||
-   test yes = "$inherit_rpath"; then
-  # Fast installation is not supported
-  enable_fast_install=no
-elif test yes = "$shlibpath_overrides_runpath" ||
-     test no = "$enable_shared"; then
-  # Fast installation is not necessary
-  enable_fast_install=needless
-fi
-
-
-
-
-
-
-  if test yes != "$enable_dlopen"; then
-  enable_dlopen=unknown
-  enable_dlopen_self=unknown
-  enable_dlopen_self_static=unknown
-else
-  lt_cv_dlopen=no
-  lt_cv_dlopen_libs=
-
-  case $host_os in
-  beos*)
-    lt_cv_dlopen=load_add_on
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=yes
-    ;;
-
-  mingw* | pw32* | cegcc*)
-    lt_cv_dlopen=LoadLibrary
-    lt_cv_dlopen_libs=
-    ;;
-
-  cygwin*)
-    lt_cv_dlopen=dlopen
-    lt_cv_dlopen_libs=
-    ;;
-
-  darwin*)
-    # if libdl is installed we need to link against it
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-$as_echo_n "checking for dlopen in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlopen+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dlopen ();
-int
-main ()
-{
-return dlopen ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_dl_dlopen=yes
-else
-  ac_cv_lib_dl_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
-  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
-else
-
-    lt_cv_dlopen=dyld
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=yes
-
-fi
-
-    ;;
-
-  tpf*)
-    # Don't try to run any link tests for TPF.  We know it's impossible
-    # because TPF is a cross-compiler, and we know how we open DSOs.
-    lt_cv_dlopen=dlopen
-    lt_cv_dlopen_libs=
-    lt_cv_dlopen_self=no
-    ;;
-
-  *)
-    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
-if test "x$ac_cv_func_shl_load" = xyes; then :
-  lt_cv_dlopen=shl_load
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
-$as_echo_n "checking for shl_load in -ldld... " >&6; }
-if ${ac_cv_lib_dld_shl_load+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char shl_load ();
-int
-main ()
-{
-return shl_load ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_dld_shl_load=yes
-else
-  ac_cv_lib_dld_shl_load=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
-$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
-if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
-  lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld
-else
-  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
-if test "x$ac_cv_func_dlopen" = xyes; then :
-  lt_cv_dlopen=dlopen
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-$as_echo_n "checking for dlopen in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlopen+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dlopen ();
-int
-main ()
-{
-return dlopen ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_dl_dlopen=yes
-else
-  ac_cv_lib_dl_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
-  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
-$as_echo_n "checking for dlopen in -lsvld... " >&6; }
-if ${ac_cv_lib_svld_dlopen+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsvld  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dlopen ();
-int
-main ()
-{
-return dlopen ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_svld_dlopen=yes
-else
-  ac_cv_lib_svld_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
-$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
-if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
-  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
-$as_echo_n "checking for dld_link in -ldld... " >&6; }
-if ${ac_cv_lib_dld_dld_link+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dld_link ();
-int
-main ()
-{
-return dld_link ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_dld_dld_link=yes
-else
-  ac_cv_lib_dld_dld_link=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
-$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
-if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
-  lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-    ;;
-  esac
-
-  if test no = "$lt_cv_dlopen"; then
-    enable_dlopen=no
-  else
-    enable_dlopen=yes
-  fi
-
-  case $lt_cv_dlopen in
-  dlopen)
-    save_CPPFLAGS=$CPPFLAGS
-    test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
-    save_LDFLAGS=$LDFLAGS
-    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
-    save_LIBS=$LIBS
-    LIBS="$lt_cv_dlopen_libs $LIBS"
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
-$as_echo_n "checking whether a program can dlopen itself... " >&6; }
-if ${lt_cv_dlopen_self+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-         if test yes = "$cross_compiling"; then :
-  lt_cv_dlopen_self=cross
-else
-  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
-  lt_status=$lt_dlunknown
-  cat > conftest.$ac_ext <<_LT_EOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-#  define LT_DLGLOBAL          RTLD_GLOBAL
-#else
-#  ifdef DL_GLOBAL
-#    define LT_DLGLOBAL                DL_GLOBAL
-#  else
-#    define LT_DLGLOBAL                0
-#  endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
-   find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-#  ifdef RTLD_LAZY
-#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
-#  else
-#    ifdef DL_LAZY
-#      define LT_DLLAZY_OR_NOW         DL_LAZY
-#    else
-#      ifdef RTLD_NOW
-#        define LT_DLLAZY_OR_NOW       RTLD_NOW
-#      else
-#        ifdef DL_NOW
-#          define LT_DLLAZY_OR_NOW     DL_NOW
-#        else
-#          define LT_DLLAZY_OR_NOW     0
-#        endif
-#      endif
-#    endif
-#  endif
-#endif
-
-/* When -fvisibility=hidden is used, assume the code has been annotated
-   correspondingly for the symbols needed.  */
-#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
-  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
-  int status = $lt_dlunknown;
-
-  if (self)
-    {
-      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
-      else
-        {
-         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
-          else puts (dlerror ());
-       }
-      /* dlclose (self); */
-    }
-  else
-    puts (dlerror ());
-
-  return status;
-}
-_LT_EOF
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
-  (eval $ac_link) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
-    (./conftest; exit; ) >&5 2>/dev/null
-    lt_status=$?
-    case x$lt_status in
-      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
-      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
-      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
-    esac
-  else :
-    # compilation failed
-    lt_cv_dlopen_self=no
-  fi
-fi
-rm -fr conftest*
-
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
-$as_echo "$lt_cv_dlopen_self" >&6; }
-
-    if test yes = "$lt_cv_dlopen_self"; then
-      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
-      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
-$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
-if ${lt_cv_dlopen_self_static+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-         if test yes = "$cross_compiling"; then :
-  lt_cv_dlopen_self_static=cross
-else
-  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
-  lt_status=$lt_dlunknown
-  cat > conftest.$ac_ext <<_LT_EOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef RTLD_GLOBAL
-#  define LT_DLGLOBAL          RTLD_GLOBAL
-#else
-#  ifdef DL_GLOBAL
-#    define LT_DLGLOBAL                DL_GLOBAL
-#  else
-#    define LT_DLGLOBAL                0
-#  endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
-   find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-#  ifdef RTLD_LAZY
-#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
-#  else
-#    ifdef DL_LAZY
-#      define LT_DLLAZY_OR_NOW         DL_LAZY
-#    else
-#      ifdef RTLD_NOW
-#        define LT_DLLAZY_OR_NOW       RTLD_NOW
-#      else
-#        ifdef DL_NOW
-#          define LT_DLLAZY_OR_NOW     DL_NOW
-#        else
-#          define LT_DLLAZY_OR_NOW     0
-#        endif
-#      endif
-#    endif
-#  endif
-#endif
-
-/* When -fvisibility=hidden is used, assume the code has been annotated
-   correspondingly for the symbols needed.  */
-#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
-  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
-  int status = $lt_dlunknown;
-
-  if (self)
-    {
-      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
-      else
-        {
-         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
-          else puts (dlerror ());
-       }
-      /* dlclose (self); */
-    }
-  else
-    puts (dlerror ());
-
-  return status;
-}
-_LT_EOF
-  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
-  (eval $ac_link) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
-    (./conftest; exit; ) >&5 2>/dev/null
-    lt_status=$?
-    case x$lt_status in
-      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
-      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
-      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
-    esac
-  else :
-    # compilation failed
-    lt_cv_dlopen_self_static=no
-  fi
-fi
-rm -fr conftest*
-
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
-$as_echo "$lt_cv_dlopen_self_static" >&6; }
-    fi
-
-    CPPFLAGS=$save_CPPFLAGS
-    LDFLAGS=$save_LDFLAGS
-    LIBS=$save_LIBS
-    ;;
-  esac
-
-  case $lt_cv_dlopen_self in
-  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
-  *) enable_dlopen_self=unknown ;;
-  esac
-
-  case $lt_cv_dlopen_self_static in
-  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
-  *) enable_dlopen_self_static=unknown ;;
-  esac
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-striplib=
-old_striplib=
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
-$as_echo_n "checking whether stripping libraries is possible... " >&6; }
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
-  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
-  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-else
-# FIXME - insert some real tests, host_os isn't really good enough
-  case $host_os in
-  darwin*)
-    if test -n "$STRIP"; then
-      striplib="$STRIP -x"
-      old_striplib="$STRIP -S"
-      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-    else
-      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-    fi
-    ;;
-  *)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-    ;;
-  esac
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-  # Report what library types will actually be built
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
-$as_echo_n "checking if libtool supports shared libraries... " >&6; }
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
-$as_echo "$can_build_shared" >&6; }
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
-$as_echo_n "checking whether to build shared libraries... " >&6; }
-  test no = "$can_build_shared" && enable_shared=no
-
-  # On AIX, shared libraries and static libraries use the same namespace, and
-  # are all built from PIC.
-  case $host_os in
-  aix3*)
-    test yes = "$enable_shared" && enable_static=no
-    if test -n "$RANLIB"; then
-      archive_cmds="$archive_cmds~\$RANLIB \$lib"
-      postinstall_cmds='$RANLIB $lib'
-    fi
-    ;;
-
-  aix[4-9]*)
-    if test ia64 != "$host_cpu"; then
-      case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
-      yes,aix,yes) ;;                  # shared object as lib.so file only
-      yes,svr4,*) ;;                   # shared object as lib.so archive member only
-      yes,*) enable_static=no ;;       # shared object in lib.a archive as well
-      esac
-    fi
-    ;;
-  esac
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
-$as_echo "$enable_shared" >&6; }
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
-$as_echo_n "checking whether to build static libraries... " >&6; }
-  # Make sure either enable_shared or enable_static is yes.
-  test yes = "$enable_shared" || enable_static=yes
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
-$as_echo "$enable_static" >&6; }
-
-
-
-
-fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-CC=$lt_save_CC
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-        ac_config_commands="$ac_config_commands libtool"
-
-
-
-
-# Only expand once:
-
-
-# By default we simply use the C compiler to build assembly code.
-
-test "${CCAS+set}" = set || CCAS=$CC
-test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS
-
-
-
-depcc="$CCAS"   am_compiler_list=
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
-$as_echo_n "checking dependency style of $depcc... " >&6; }
-if ${am_cv_CCAS_dependencies_compiler_type+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
-  # We make a subdir and do the tests there.  Otherwise we can end up
-  # making bogus files that we don't know about and never remove.  For
-  # instance it was reported that on HP-UX the gcc test will end up
-  # making a dummy file named 'D' -- because '-MD' means "put the output
-  # in D".
-  rm -rf conftest.dir
-  mkdir conftest.dir
-  # Copy depcomp to subdir because otherwise we won't find it if we're
-  # using a relative directory.
-  cp "$am_depcomp" conftest.dir
-  cd conftest.dir
-  # We will build objects and dependencies in a subdirectory because
-  # it helps to detect inapplicable dependency modes.  For instance
-  # both Tru64's cc and ICC support -MD to output dependencies as a
-  # side effect of compilation, but ICC will put the dependencies in
-  # the current directory while Tru64 will put them in the object
-  # directory.
-  mkdir sub
-
-  am_cv_CCAS_dependencies_compiler_type=none
-  if test "$am_compiler_list" = ""; then
-     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
-  fi
-  am__universal=false
-
-
-  for depmode in $am_compiler_list; do
-    # Setup a source with many dependencies, because some compilers
-    # like to wrap large dependency lists on column 80 (with \), and
-    # we should not choose a depcomp mode which is confused by this.
-    #
-    # We need to recreate these files for each test, as the compiler may
-    # overwrite some of them when testing with obscure command lines.
-    # This happens at least with the AIX C compiler.
-    : > sub/conftest.c
-    for i in 1 2 3 4 5 6; do
-      echo '#include "conftst'$i'.h"' >> sub/conftest.c
-      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
-      # Solaris 10 /bin/sh.
-      echo '/* dummy */' > sub/conftst$i.h
-    done
-    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
-
-    # We check with '-c' and '-o' for the sake of the "dashmstdout"
-    # mode.  It turns out that the SunPro C++ compiler does not properly
-    # handle '-M -o', and we need to detect this.  Also, some Intel
-    # versions had trouble with output in subdirs.
-    am__obj=sub/conftest.${OBJEXT-o}
-    am__minus_obj="-o $am__obj"
-    case $depmode in
-    gcc)
-      # This depmode causes a compiler race in universal mode.
-      test "$am__universal" = false || continue
-      ;;
-    nosideeffect)
-      # After this tag, mechanisms are not by side-effect, so they'll
-      # only be used when explicitly requested.
-      if test "x$enable_dependency_tracking" = xyes; then
-       continue
-      else
-       break
-      fi
-      ;;
-    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
-      # This compiler won't grok '-c -o', but also, the minuso test has
-      # not run yet.  These depmodes are late enough in the game, and
-      # so weak that their functioning should not be impacted.
-      am__obj=conftest.${OBJEXT-o}
-      am__minus_obj=
-      ;;
-    none) break ;;
-    esac
-    if depmode=$depmode \
-       source=sub/conftest.c object=$am__obj \
-       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
-       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
-         >/dev/null 2>conftest.err &&
-       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
-       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
-       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
-       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
-      # icc doesn't choke on unknown options, it will just issue warnings
-      # or remarks (even with -Werror).  So we grep stderr for any message
-      # that says an option was ignored or not supported.
-      # When given -MP, icc 7.0 and 7.1 complain thusly:
-      #   icc: Command line warning: ignoring option '-M'; no argument required
-      # The diagnosis changed in icc 8.0:
-      #   icc: Command line remark: option '-MP' not supported
-      if (grep 'ignoring option' conftest.err ||
-          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
-        am_cv_CCAS_dependencies_compiler_type=$depmode
-        break
-      fi
-    fi
-  done
-
-  cd ..
-  rm -rf conftest.dir
-else
-  am_cv_CCAS_dependencies_compiler_type=none
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CCAS_dependencies_compiler_type" >&5
-$as_echo "$am_cv_CCAS_dependencies_compiler_type" >&6; }
-CCASDEPMODE=depmode=$am_cv_CCAS_dependencies_compiler_type
-
- if
-  test "x$enable_dependency_tracking" != xno \
-  && test "$am_cv_CCAS_dependencies_compiler_type" = gcc3; then
-  am__fastdepCCAS_TRUE=
-  am__fastdepCCAS_FALSE='#'
-else
-  am__fastdepCCAS_TRUE='#'
-  am__fastdepCCAS_FALSE=
-fi
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking zfs author" >&5
-$as_echo_n "checking zfs author... " >&6; }
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZFS_META_AUTHOR" >&5
-$as_echo "$ZFS_META_AUTHOR" >&6; }
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking zfs license" >&5
-$as_echo_n "checking zfs license... " >&6; }
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZFS_META_LICENSE" >&5
-$as_echo "$ZFS_META_LICENSE" >&6; }
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking linux distribution" >&5
-$as_echo_n "checking linux distribution... " >&6; }
-       if test -f /etc/toss-release ; then
-               VENDOR=toss ;
-       elif test -f /etc/fedora-release ; then
-               VENDOR=fedora ;
-       elif test -f /etc/redhat-release ; then
-               VENDOR=redhat ;
-       elif test -f /etc/gentoo-release ; then
-               VENDOR=gentoo ;
-       elif test -f /etc/arch-release ; then
-               VENDOR=arch ;
-       elif test -f /etc/SuSE-release ; then
-               VENDOR=sles ;
-       elif test -f /etc/slackware-version ; then
-               VENDOR=slackware ;
-       elif test -f /etc/lunar.release ; then
-               VENDOR=lunar ;
-       elif test -f /etc/lsb-release ; then
-               VENDOR=ubuntu ;
-       elif test -f /etc/debian_version ; then
-               VENDOR=debian ;
-       else
-               VENDOR= ;
-       fi
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $VENDOR" >&5
-$as_echo "$VENDOR" >&6; }
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking default package type" >&5
-$as_echo_n "checking default package type... " >&6; }
-       case "$VENDOR" in
-               toss)       DEFAULT_PACKAGE=rpm  ;;
-               redhat)     DEFAULT_PACKAGE=rpm  ;;
-               fedora)     DEFAULT_PACKAGE=rpm  ;;
-               gentoo)     DEFAULT_PACKAGE=tgz  ;;
-               arch)       DEFAULT_PACKAGE=tgz  ;;
-               sles)       DEFAULT_PACKAGE=rpm  ;;
-               slackware)  DEFAULT_PACKAGE=tgz  ;;
-               lunar)      DEFAULT_PACKAGE=tgz  ;;
-               ubuntu)     DEFAULT_PACKAGE=deb  ;;
-               debian)     DEFAULT_PACKAGE=deb  ;;
-               *)          DEFAULT_PACKAGE=rpm  ;;
-       esac
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEFAULT_PACKAGE" >&5
-$as_echo "$DEFAULT_PACKAGE" >&6; }
-
-
-       DEFAULT_INIT_DIR=$sysconfdir/init.d
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking default init directory" >&5
-$as_echo_n "checking default init directory... " >&6; }
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEFAULT_INIT_DIR" >&5
-$as_echo "$DEFAULT_INIT_DIR" >&6; }
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking default init script type" >&5
-$as_echo_n "checking default init script type... " >&6; }
-       case "$VENDOR" in
-               toss)       DEFAULT_INIT_SCRIPT=redhat ;;
-               redhat)     DEFAULT_INIT_SCRIPT=redhat ;;
-               fedora)     DEFAULT_INIT_SCRIPT=fedora ;;
-               gentoo)     DEFAULT_INIT_SCRIPT=gentoo ;;
-               arch)       DEFAULT_INIT_SCRIPT=lsb    ;;
-               sles)       DEFAULT_INIT_SCRIPT=lsb    ;;
-               slackware)  DEFAULT_INIT_SCRIPT=lsb    ;;
-               lunar)      DEFAULT_INIT_SCRIPT=lunar  ;;
-               ubuntu)     DEFAULT_INIT_SCRIPT=lsb    ;;
-               debian)     DEFAULT_INIT_SCRIPT=lsb    ;;
-               *)          DEFAULT_INIT_SCRIPT=lsb    ;;
-       esac
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEFAULT_INIT_SCRIPT" >&5
-$as_echo "$DEFAULT_INIT_SCRIPT" >&6; }
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking default init config direectory" >&5
-$as_echo_n "checking default init config direectory... " >&6; }
-       case "$VENDOR" in
-               gentoo)     DEFAULT_INITCONF_DIR=/etc/conf.d    ;;
-               toss)       DEFAULT_INITCONF_DIR=/etc/sysconfig ;;
-               redhat)     DEFAULT_INITCONF_DIR=/etc/sysconfig ;;
-               fedora)     DEFAULT_INITCONF_DIR=/etc/sysconfig ;;
-               sles)       DEFAULT_INITCONF_DIR=/etc/sysconfig ;;
-               ubuntu)     DEFAULT_INITCONF_DIR=/etc/default   ;;
-               debian)     DEFAULT_INITCONF_DIR=/etc/default   ;;
-               *)          DEFAULT_INITCONF_DIR=/etc/default   ;;
-       esac
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DEFAULT_INITCONF_DIR" >&5
-$as_echo "$DEFAULT_INITCONF_DIR" >&6; }
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether initramfs-tools is available" >&5
-$as_echo_n "checking whether initramfs-tools is available... " >&6; }
-       if test -d /usr/share/initramfs-tools ; then
-               DEFINE_INITRAMFS='--define "_initramfs 1"'
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-       else
-               DEFINE_INITRAMFS=''
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-       fi
-
-
-
-       RPM=rpm
-       RPMBUILD=rpmbuild
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $RPM is available" >&5
-$as_echo_n "checking whether $RPM is available... " >&6; }
-       if tmp=$($RPM --version 2>/dev/null); then :
-
-               RPM_VERSION=$(echo $tmp | $AWK '/RPM/ { print $3 }')
-               HAVE_RPM=yes
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_RPM ($RPM_VERSION)" >&5
-$as_echo "$HAVE_RPM ($RPM_VERSION)" >&6; }
-
-else
-
-               HAVE_RPM=no
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_RPM" >&5
-$as_echo "$HAVE_RPM" >&6; }
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $RPMBUILD is available" >&5
-$as_echo_n "checking whether $RPMBUILD is available... " >&6; }
-       if tmp=$($RPMBUILD --version 2>/dev/null); then :
-
-               RPMBUILD_VERSION=$(echo $tmp | $AWK '/RPM/ { print $3 }')
-               HAVE_RPMBUILD=yes
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_RPMBUILD ($RPMBUILD_VERSION)" >&5
-$as_echo "$HAVE_RPMBUILD ($RPMBUILD_VERSION)" >&6; }
-
-else
-
-               HAVE_RPMBUILD=no
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_RPMBUILD" >&5
-$as_echo "$HAVE_RPMBUILD" >&6; }
-
-fi
-
-       RPM_DEFINE_COMMON='--define "$(DEBUG_ZFS) 1" --define "$(DEBUG_DMU_TX) 1"'
-       RPM_DEFINE_UTIL='--define "_dracutdir $(dracutdir)" --define "_udevdir $(udevdir)" --define "_udevruledir $(udevruledir)" --define "_initconfdir $(DEFAULT_INITCONF_DIR)" $(DEFINE_INITRAMFS)'
-       RPM_DEFINE_KMOD='--define "kernels $(LINUX_VERSION)" --define "require_spldir $(SPL)" --define "require_splobj $(SPL_OBJ)" --define "ksrc $(LINUX)" --define "kobj $(LINUX_OBJ)"'
-       RPM_DEFINE_DKMS=
-
-       SRPM_DEFINE_COMMON='--define "build_src_rpm 1"'
-       SRPM_DEFINE_UTIL=
-       SRPM_DEFINE_KMOD=
-       SRPM_DEFINE_DKMS=
-
-       RPM_SPEC_DIR="rpm/generic"
-
-# Check whether --with-spec was given.
-if test "${with_spec+set}" = set; then :
-  withval=$with_spec; RPM_SPEC_DIR="rpm/$withval"
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether spec files are available" >&5
-$as_echo_n "checking whether spec files are available... " >&6; }
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes ($RPM_SPEC_DIR/*.spec.in)" >&5
-$as_echo "yes ($RPM_SPEC_DIR/*.spec.in)" >&6; }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-       DPKG=dpkg
-       DPKGBUILD=dpkg-buildpackage
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $DPKG is available" >&5
-$as_echo_n "checking whether $DPKG is available... " >&6; }
-       if tmp=$($DPKG --version 2>/dev/null); then :
-
-               DPKG_VERSION=$(echo $tmp | $AWK '/Debian/ { print $7 }')
-               HAVE_DPKG=yes
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_DPKG ($DPKG_VERSION)" >&5
-$as_echo "$HAVE_DPKG ($DPKG_VERSION)" >&6; }
-
-else
-
-               HAVE_DPKG=no
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_DPKG" >&5
-$as_echo "$HAVE_DPKG" >&6; }
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $DPKGBUILD is available" >&5
-$as_echo_n "checking whether $DPKGBUILD is available... " >&6; }
-       if tmp=$($DPKGBUILD --version 2>/dev/null); then :
-
-               DPKGBUILD_VERSION=$(echo $tmp | \
-                   $AWK '/Debian/ { print $4 }' | cut -f-4 -d'.')
-               HAVE_DPKGBUILD=yes
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_DPKGBUILD ($DPKGBUILD_VERSION)" >&5
-$as_echo "$HAVE_DPKGBUILD ($DPKGBUILD_VERSION)" >&6; }
-
-else
-
-               HAVE_DPKGBUILD=no
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_DPKGBUILD" >&5
-$as_echo "$HAVE_DPKGBUILD" >&6; }
-
-fi
-
-
-
-
-
-
-
-
-
-
-       ALIEN=alien
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $ALIEN is available" >&5
-$as_echo_n "checking whether $ALIEN is available... " >&6; }
-       if tmp=$($ALIEN --version 2>/dev/null); then :
-
-               ALIEN_VERSION=$(echo $tmp | $AWK '{ print $3 }')
-               HAVE_ALIEN=yes
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_ALIEN ($ALIEN_VERSION)" >&5
-$as_echo "$HAVE_ALIEN ($ALIEN_VERSION)" >&6; }
-
-else
-
-               HAVE_ALIEN=no
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_ALIEN" >&5
-$as_echo "$HAVE_ALIEN" >&6; }
-
-fi
-
-
-
-
-
-
-
-       TARGET_ASM_DIR=asm-generic
-
-
-       ZFS_CONFIG=all
-
-# Check whether --with-config was given.
-if test "${with_config+set}" = set; then :
-  withval=$with_config; ZFS_CONFIG="$withval"
-fi
-
-       # Check whether --enable-linux-builtin was given.
-if test "${enable_linux_builtin+set}" = set; then :
-  enableval=$enable_linux_builtin;
-else
-  enable_linux_builtin=no
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking zfs config" >&5
-$as_echo_n "checking zfs config... " >&6; }
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ZFS_CONFIG" >&5
-$as_echo "$ZFS_CONFIG" >&6; };
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wno-unused-but-set-variable support" >&5
-$as_echo_n "checking for -Wno-unused-but-set-variable support... " >&6; }
-
-       saved_flags="$CFLAGS"
-       CFLAGS="$CFLAGS -Wunused-but-set-variable"
-
-       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-               NO_UNUSED_BUT_SET_VARIABLE=-Wno-unused-but-set-variable
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-else
-
-               NO_UNUSED_BUT_SET_VARIABLE=
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-       CFLAGS="$saved_flags"
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wno-bool-compare support" >&5
-$as_echo_n "checking for -Wno-bool-compare support... " >&6; }
-
-       saved_flags="$CFLAGS"
-       CFLAGS="$CFLAGS -Wbool-compare"
-
-       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-               NO_BOOL_COMPARE=-Wno-bool-compare
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-else
-
-               NO_BOOL_COMPARE=
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-       CFLAGS="$saved_flags"
-
-
-
-
-       case "$ZFS_CONFIG" in
-               user)
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dkms.conf file" >&5
-$as_echo_n "checking for dkms.conf file... " >&6; }
-        if test -e dkms.conf; then :
-
-               as_fn_error $? "
-       *** ZFS should not be manually built in the DKMS source tree.
-       *** Remove all ZFS packages before compiling the ZoL sources.
-       *** Running \"make install\" breaks ZFS packages." "$LINENO" 5
-
-else
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
-
-fi
-
-
-
-# Check whether --with-mounthelperdir was given.
-if test "${with_mounthelperdir+set}" = set; then :
-  withval=$with_mounthelperdir; mounthelperdir=$withval
-else
-  mounthelperdir=/sbin
-fi
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for udev directories" >&5
-$as_echo_n "checking for udev directories... " >&6; }
-
-# Check whether --with-udevdir was given.
-if test "${with_udevdir+set}" = set; then :
-  withval=$with_udevdir; udevdir=$withval
-else
-  udevdir=check
-fi
-
-
-       if test "x$udevdir" = xcheck; then :
-
-               path1=/lib/udev
-               path2=/usr/lib/udev
-               default=$path2
-
-               if test -d "$path1"; then :
-  udevdir="$path1"
-else
-
-                       if test -d "$path2"; then :
-  udevdir="$path2"
-else
-  udevdir="$default"
-fi
-
-fi
-
-fi
-
-
-# Check whether --with-udevruledir was given.
-if test "${with_udevruledir+set}" = set; then :
-  withval=$with_udevruledir; udevruledir=$withval
-else
-  udevruledir="${udevdir}/rules.d"
-fi
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $udevdir;$udevruledir" >&5
-$as_echo "$udevdir;$udevruledir" >&6; }
-
-
-       # Check whether --enable-systemd was given.
-if test "${enable_systemd+set}" = set; then :
-  enableval=$enable_systemd;
-else
-  enable_systemd=yes
-fi
-
-
-
-# Check whether --with-systemdunitdir was given.
-if test "${with_systemdunitdir+set}" = set; then :
-  withval=$with_systemdunitdir; systemdunitdir=$withval
-else
-  systemdunitdir=/usr/lib/systemd/system
-fi
-
-
-
-# Check whether --with-systemdpresetdir was given.
-if test "${with_systemdpresetdir+set}" = set; then :
-  withval=$with_systemdpresetdir; systemdpresetdir=$withval
-else
-  systemdpresetdir=/usr/lib/systemd/system-preset
-fi
-
-
-
-# Check whether --with-systemdmodulesloaddir was given.
-if test "${with_systemdmodulesloaddir+set}" = set; then :
-  withval=$with_systemdmodulesloaddir; systemdmoduleloaddir=$withval
-else
-  systemdmodulesloaddir=/usr/lib/modules-load.d
-fi
-
-
-
-       if test "x$enable_systemd" = xyes; then :
-
-               ZFS_INIT_SYSTEMD=systemd
-               ZFS_MODULE_LOAD=modules-load.d
-               modulesloaddir=$systemdmodulesloaddir
-
-fi
-
-
-
-
-
-
-
-
-       # Check whether --enable-sysvinit was given.
-if test "${enable_sysvinit+set}" = set; then :
-  enableval=$enable_sysvinit;
-else
-  enable_sysvinit=yes
-fi
-
-
-       if test "x$enable_sysvinit" = xyes; then :
-  ZFS_INIT_SYSV=init.d
-fi
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dracut directory" >&5
-$as_echo_n "checking for dracut directory... " >&6; }
-
-# Check whether --with-dracutdir was given.
-if test "${with_dracutdir+set}" = set; then :
-  withval=$with_dracutdir; dracutdir=$withval
-else
-  dracutdir=check
-fi
-
-
-       if test "x$dracutdir" = xcheck; then :
-
-               path1=/usr/share/dracut
-               path2=/usr/lib/dracut
-               default=$path2
-
-               if test -d "$path1"; then :
-  dracutdir="$path1"
-else
-
-                       if test -d "$path2"; then :
-  dracutdir="$path2"
-else
-  dracutdir="$default"
-fi
-
-fi
-
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dracutdir" >&5
-$as_echo "$dracutdir" >&6; }
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for target asm dir" >&5
-$as_echo_n "checking for target asm dir... " >&6; }
-       TARGET_ARCH=`echo ${target_cpu} | sed -e s/i.86/i386/`
-
-       case $TARGET_ARCH in
-       i386|x86_64)
-               TARGET_ASM_DIR=asm-${TARGET_ARCH}
-               ;;
-       *)
-               TARGET_ASM_DIR=asm-generic
-               ;;
-       esac
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TARGET_ASM_DIR" >&5
-$as_echo "$TARGET_ASM_DIR" >&6; }
-
-
-       ZLIB=
-
-       ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_zlib_h" = xyes; then :
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** zlib.h missing, zlib-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compress2 in -lz" >&5
-$as_echo_n "checking for compress2 in -lz... " >&6; }
-if ${ac_cv_lib_z_compress2+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lz  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char compress2 ();
-int
-main ()
-{
-return compress2 ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_z_compress2=yes
-else
-  ac_cv_lib_z_compress2=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compress2" >&5
-$as_echo "$ac_cv_lib_z_compress2" >&6; }
-if test "x$ac_cv_lib_z_compress2" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBZ 1
-_ACEOF
-
-  LIBS="-lz $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** compress2() missing, zlib-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uncompress in -lz" >&5
-$as_echo_n "checking for uncompress in -lz... " >&6; }
-if ${ac_cv_lib_z_uncompress+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lz  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char uncompress ();
-int
-main ()
-{
-return uncompress ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_z_uncompress=yes
-else
-  ac_cv_lib_z_uncompress=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_uncompress" >&5
-$as_echo "$ac_cv_lib_z_uncompress" >&6; }
-if test "x$ac_cv_lib_z_uncompress" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBZ 1
-_ACEOF
-
-  LIBS="-lz $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** uncompress() missing, zlib-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crc32 in -lz" >&5
-$as_echo_n "checking for crc32 in -lz... " >&6; }
-if ${ac_cv_lib_z_crc32+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lz  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char crc32 ();
-int
-main ()
-{
-return crc32 ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_z_crc32=yes
-else
-  ac_cv_lib_z_crc32=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_crc32" >&5
-$as_echo "$ac_cv_lib_z_crc32" >&6; }
-if test "x$ac_cv_lib_z_crc32" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBZ 1
-_ACEOF
-
-  LIBS="-lz $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** crc32() missing, zlib-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       ZLIB="-lz"
-
-
-$as_echo "#define HAVE_ZLIB 1" >>confdefs.h
-
-
-
-       LIBUUID=
-
-       ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default"
-if test "x$ac_cv_header_uuid_uuid_h" = xyes; then :
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** uuid/uuid.h missing, libuuid-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate in -luuid" >&5
-$as_echo_n "checking for uuid_generate in -luuid... " >&6; }
-if ${ac_cv_lib_uuid_uuid_generate+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-luuid  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char uuid_generate ();
-int
-main ()
-{
-return uuid_generate ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_uuid_uuid_generate=yes
-else
-  ac_cv_lib_uuid_uuid_generate=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate" >&5
-$as_echo "$ac_cv_lib_uuid_uuid_generate" >&6; }
-if test "x$ac_cv_lib_uuid_uuid_generate" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBUUID 1
-_ACEOF
-
-  LIBS="-luuid $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** uuid_generate() missing, libuuid-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_is_null in -luuid" >&5
-$as_echo_n "checking for uuid_is_null in -luuid... " >&6; }
-if ${ac_cv_lib_uuid_uuid_is_null+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-luuid  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char uuid_is_null ();
-int
-main ()
-{
-return uuid_is_null ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_uuid_uuid_is_null=yes
-else
-  ac_cv_lib_uuid_uuid_is_null=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_is_null" >&5
-$as_echo "$ac_cv_lib_uuid_uuid_is_null" >&6; }
-if test "x$ac_cv_lib_uuid_uuid_is_null" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBUUID 1
-_ACEOF
-
-  LIBS="-luuid $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** uuid_is_null() missing, libuuid-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       LIBUUID="-luuid"
-
-
-$as_echo "#define HAVE_LIBUUID 1" >>confdefs.h
-
-
-
-
-# Check whether --with-blkid was given.
-if test "${with_blkid+set}" = set; then :
-  withval=$with_blkid;
-else
-  with_blkid=check
-fi
-
-
-       LIBBLKID=
-       if test "x$with_blkid" = xyes; then :
-
-               LIBBLKID="-lblkid"
-
-
-$as_echo "#define HAVE_LIBBLKID 1" >>confdefs.h
-
-
-fi
-
-       if test "x$with_blkid" = xcheck; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for blkid_get_cache in -lblkid" >&5
-$as_echo_n "checking for blkid_get_cache in -lblkid... " >&6; }
-if ${ac_cv_lib_blkid_blkid_get_cache+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lblkid  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char blkid_get_cache ();
-int
-main ()
-{
-return blkid_get_cache ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_blkid_blkid_get_cache=yes
-else
-  ac_cv_lib_blkid_blkid_get_cache=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blkid_blkid_get_cache" >&5
-$as_echo "$ac_cv_lib_blkid_blkid_get_cache" >&6; }
-if test "x$ac_cv_lib_blkid_blkid_get_cache" = xyes; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for blkid zfs support" >&5
-$as_echo_n "checking for blkid zfs support... " >&6; }
-
-                       ZFS_DEV=`mktemp`
-                       truncate -s 64M $ZFS_DEV
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=128 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=132 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=136 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=140 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-
-                       saved_LIBS="$LIBS"
-                       LIBS="-lblkid"
-
-                       if test "$cross_compiling" = yes; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-                               #include <stdio.h>
-                               #include <stdlib.h>
-                               #include <blkid/blkid.h>
-
-int
-main ()
-{
-
-                               blkid_cache cache;
-                               char *value;
-
-                               if (blkid_get_cache(&cache, NULL) < 0)
-                                       return 1;
-
-                               value = blkid_get_tag_value(cache, "TYPE",
-                                                           "$ZFS_DEV");
-                               if (!value) {
-                                       blkid_put_cache(cache);
-                                       return 2;
-                               }
-
-                               if (strcmp(value, "zfs_member")) {
-                                       free(value);
-                                       blkid_put_cache(cache);
-                                       return 0;
-                               }
-
-                               free(value);
-                               blkid_put_cache(cache);
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-                               rm -f $ZFS_DEV
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-                               LIBBLKID="-lblkid"
-
-
-$as_echo "#define HAVE_LIBBLKID 1" >>confdefs.h
-
-
-else
-
-                               rm -f $ZFS_DEV
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                               if test "x$with_blkid" != xcheck; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "--with-blkid given but unavailable
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-
-                       LIBS="$saved_LIBS"
-
-else
-
-                       if test "x$with_blkid" != xcheck; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "--with-blkid given but unavailable
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-fi
-
-
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wframe-larger-than=<size> support" >&5
-$as_echo_n "checking for -Wframe-larger-than=<size> support... " >&6; }
-
-       saved_flags="$CFLAGS"
-       CFLAGS="$CFLAGS -Wframe-larger-than=1024"
-
-       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-               FRAME_LARGER_THAN=-Wframe-larger-than=1024
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-else
-
-               FRAME_LARGER_THAN=
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-       CFLAGS="$saved_flags"
-
-
-
-       if test "x$runstatedir" = x; then
-               runstatedir='${localstatedir}/run'
-
-       fi
-
-       for ac_func in mlockall
-do :
-  ac_fn_c_check_func "$LINENO" "mlockall" "ac_cv_func_mlockall"
-if test "x$ac_cv_func_mlockall" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_MLOCKALL 1
-_ACEOF
-
-fi
-done
-
-   ;;
-               kernel)
-
-
-# Check whether --with-linux was given.
-if test "${with_linux+set}" = set; then :
-  withval=$with_linux; kernelsrc="$withval"
-fi
-
-
-
-# Check whether --with-linux-obj was given.
-if test "${with_linux_obj+set}" = set; then :
-  withval=$with_linux_obj; kernelbuild="$withval"
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel source directory" >&5
-$as_echo_n "checking kernel source directory... " >&6; }
-       if test -z "$kernelsrc"; then :
-
-               if test -e "/lib/modules/$(uname -r)/source"; then :
-
-                       headersdir="/lib/modules/$(uname -r)/source"
-                       sourcelink=$(readlink -f "$headersdir")
-
-elif test -e "/lib/modules/$(uname -r)/build"; then :
-
-                       headersdir="/lib/modules/$(uname -r)/build"
-                       sourcelink=$(readlink -f "$headersdir")
-
-else
-
-                       sourcelink=$(ls -1d /usr/src/kernels/* \
-                                    /usr/src/linux-* \
-                                    2>/dev/null | grep -v obj | tail -1)
-
-fi
-
-               if test -n "$sourcelink" && test -e ${sourcelink}; then :
-
-                       kernelsrc=`readlink -f ${sourcelink}`
-
-else
-
-                       kernelsrc="Not found"
-
-fi
-
-else
-
-               if test "$kernelsrc" = "NONE"; then :
-
-                       kernsrcver=NONE
-
-fi
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $kernelsrc" >&5
-$as_echo "$kernelsrc" >&6; }
-       if test ! -d "$kernelsrc"; then :
-
-               as_fn_error $? "
-       *** Please make sure the kernel devel package for your distribution
-       *** is installed and then try again.  If that fails, you can specify the
-       *** location of the kernel source with the '--with-linux=PATH' option." "$LINENO" 5
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel build directory" >&5
-$as_echo_n "checking kernel build directory... " >&6; }
-       if test -z "$kernelbuild"; then :
-
-               if test -e "/lib/modules/$(uname -r)/build"; then :
-
-                       kernelbuild=`readlink -f /lib/modules/$(uname -r)/build`
-
-elif test -d ${kernelsrc}-obj/${target_cpu}/${target_cpu}; then :
-
-                       kernelbuild=${kernelsrc}-obj/${target_cpu}/${target_cpu}
-
-elif test -d ${kernelsrc}-obj/${target_cpu}/default; then :
-
-                       kernelbuild=${kernelsrc}-obj/${target_cpu}/default
-
-elif test -d `dirname ${kernelsrc}`/build-${target_cpu}; then :
-
-                       kernelbuild=`dirname ${kernelsrc}`/build-${target_cpu}
-
-else
-
-                       kernelbuild=${kernelsrc}
-
-fi
-
-fi
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $kernelbuild" >&5
-$as_echo "$kernelbuild" >&6; }
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel source version" >&5
-$as_echo_n "checking kernel source version... " >&6; }
-       utsrelease1=$kernelbuild/include/linux/version.h
-       utsrelease2=$kernelbuild/include/linux/utsrelease.h
-       utsrelease3=$kernelbuild/include/generated/utsrelease.h
-       if test -r $utsrelease1 && fgrep -q UTS_RELEASE $utsrelease1; then :
-
-               utsrelease=linux/version.h
-
-elif test -r $utsrelease2 && fgrep -q UTS_RELEASE $utsrelease2; then :
-
-               utsrelease=linux/utsrelease.h
-
-elif test -r $utsrelease3 && fgrep -q UTS_RELEASE $utsrelease3; then :
-
-               utsrelease=generated/utsrelease.h
-
-fi
-
-       if test "$utsrelease"; then :
-
-               kernsrcver=`(echo "#include <$utsrelease>";
-                            echo "kernsrcver=UTS_RELEASE") |
-                            cpp -I $kernelbuild/include |
-                            grep "^kernsrcver=" | cut -d \" -f 2`
-
-               if test -z "$kernsrcver"; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not found" >&5
-$as_echo "Not found" >&6; }
-                       as_fn_error $? "*** Cannot determine kernel version." "$LINENO" 5
-
-fi
-
-else
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not found" >&5
-$as_echo "Not found" >&6; }
-               if test "x$enable_linux_builtin" != xyes; then
-                       as_fn_error $? "*** Cannot find UTS_RELEASE definition." "$LINENO" 5
-               else
-                       as_fn_error $? "
-       *** Cannot find UTS_RELEASE definition.
-       *** Please run 'make prepare' inside the kernel source tree." "$LINENO" 5
-               fi
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $kernsrcver" >&5
-$as_echo "$kernsrcver" >&6; }
-
-       LINUX=${kernelsrc}
-       LINUX_OBJ=${kernelbuild}
-       LINUX_VERSION=${kernsrcver}
-
-
-
-
-
-
-       modpost=$LINUX/scripts/Makefile.modpost
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel file name for module symbols" >&5
-$as_echo_n "checking kernel file name for module symbols... " >&6; }
-       if test "x$enable_linux_builtin" != xyes -a -f "$modpost"; then :
-
-               if grep -q Modules.symvers $modpost; then :
-
-                       LINUX_SYMBOLS=Modules.symvers
-
-else
-
-                       LINUX_SYMBOLS=Module.symvers
-
-fi
-
-               if test ! -f "$LINUX_OBJ/$LINUX_SYMBOLS"; then :
-
-                       as_fn_error $? "
-       *** Please make sure the kernel devel package for your distribution
-       *** is installed.  If you are building with a custom kernel, make sure the
-       *** kernel is configured, built, and the '--with-linux=PATH' configure
-       *** option refers to the location of the kernel source." "$LINENO" 5
-
-fi
-
-else
-
-               LINUX_SYMBOLS=NONE
-
-fi
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINUX_SYMBOLS" >&5
-$as_echo "$LINUX_SYMBOLS" >&6; }
-
-
-
-
-
-# Check whether --with-spl was given.
-if test "${with_spl+set}" = set; then :
-  withval=$with_spl; splsrc="$withval"
-fi
-
-
-
-# Check whether --with-spl-obj was given.
-if test "${with_spl_obj+set}" = set; then :
-  withval=$with_spl_obj; splbuild="$withval"
-fi
-
-
-
-# Check whether --with-spl-timeout was given.
-if test "${with_spl_timeout+set}" = set; then :
-  withval=$with_spl_timeout; timeout="$withval"
-else
-  timeout=0
-fi
-
-
-                                       splsrc0="/var/lib/dkms/spl/${VERSION}/build"
-       splsrc1="/usr/local/src/spl-${VERSION}/${LINUX_VERSION}"
-       splsrc2="/usr/local/src/spl-${VERSION}"
-       splsrc3="/usr/src/spl-${VERSION}/${LINUX_VERSION}"
-       splsrc4="/usr/src/spl-${VERSION}"
-       splsrc5="../spl/"
-       splsrc6="$LINUX"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl source directory" >&5
-$as_echo_n "checking spl source directory... " >&6; }
-       if test -z "${splsrc}"; then :
-
-               if  test -e "${splsrc0}/spl.release.in"; then :
-
-                       splsrc=${splsrc0}
-
-elif  test -e "${splsrc1}/spl.release.in"; then :
-
-                       splsrc=${splsrc1}
-
-elif  test -e "${splsrc2}/spl.release.in"; then :
-
-                       splsrc=${splsrc2}
-
-elif  test -e "${splsrc3}/spl.release.in"; then :
-
-                       splsrc=$(readlink -f "${splsrc3}")
-
-elif  test -e "${splsrc4}/spl.release.in" ; then :
-
-                       splsrc=${splsrc4}
-
-elif  test -e "${splsrc5}/spl.release.in"; then :
-
-                       splsrc=$(readlink -f "${splsrc5}")
-
-elif  test -e "${splsrc6}/spl.release.in" ; then :
-
-                       splsrc=${splsrc6}
-
-else
-
-                       splsrc="Not found"
-
-fi
-
-else
-
-               if test "$splsrc" = "NONE"; then :
-
-                       splbuild=NONE
-                       splsrcver=NONE
-
-fi
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $splsrc" >&5
-$as_echo "$splsrc" >&6; }
-       if  test ! -e "$splsrc/spl.release.in"; then :
-
-               as_fn_error $? "
-       *** Please make sure the kmod spl devel package for your distribution
-       *** is installed then try again.  If that fails you can specify the
-       *** location of the spl source with the '--with-spl=PATH' option." "$LINENO" 5
-
-fi
-
-                                                                                                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl build directory" >&5
-$as_echo_n "checking spl build directory... " >&6; }
-       while true; do
-               if test -z "$splbuild"; then :
-
-                       if  test -e "${splsrc}/${LINUX_VERSION}/spl_config.h" ; then :
-
-                               splbuild="${splsrc}/${LINUX_VERSION}"
-
-elif  test -e "${splsrc}/spl_config.h" ; then :
-
-                               splbuild="${splsrc}"
-
-elif  find -L "${splsrc}" -name spl_config.h 2> /dev/null | grep -wq spl_config.h ; then :
-
-                               splbuild=$(find -L "${splsrc}" -name spl_config.h | sed 's,/spl_config.h,,')
-
-else
-
-                               splbuild="Not found"
-
-fi
-
-fi
-               if test -e "$splbuild/spl_config.h" -o $timeout -le 0; then :
-
-                       break;
-
-else
-
-                       sleep 1
-                       timeout=$((timeout-1))
-
-fi
-       done
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $splbuild" >&5
-$as_echo "$splbuild" >&6; }
-       if  ! test -e "$splbuild/spl_config.h"; then :
-
-               as_fn_error $? "
-       *** Please make sure the kmod spl devel <kernel> package for your
-       *** distribution is installed then try again.  If that fails you
-       *** can specify the location of the spl objects with the
-       *** '--with-spl-obj=PATH' option." "$LINENO" 5
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl source version" >&5
-$as_echo_n "checking spl source version... " >&6; }
-       if test -r $splbuild/spl_config.h &&
-               fgrep -q SPL_META_VERSION $splbuild/spl_config.h; then :
-
-
-               splsrcver=`(echo "#include <spl_config.h>";
-                           echo "splsrcver=SPL_META_VERSION-SPL_META_RELEASE") |
-                           cpp -I $splbuild |
-                           grep "^splsrcver=" | tr -d \" | cut -d= -f2`
-
-fi
-
-       if test -z "$splsrcver"; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not found" >&5
-$as_echo "Not found" >&6; }
-               as_fn_error $? "
-       *** Cannot determine the version of the spl source.
-       *** Please prepare the spl source before running this script" "$LINENO" 5
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $splsrcver" >&5
-$as_echo "$splsrcver" >&6; }
-
-       SPL=${splsrc}
-       SPL_OBJ=${splbuild}
-       SPL_VERSION=${splsrcver}
-
-
-
-
-
-                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl file name for module symbols" >&5
-$as_echo_n "checking spl file name for module symbols... " >&6; }
-       SPL_SYMBOLS=NONE
-
-       while true; do
-               if test -r $SPL_OBJ/Module.symvers; then :
-
-                       SPL_SYMBOLS=Module.symvers
-
-elif test -r $SPL_OBJ/Modules.symvers; then :
-
-                       SPL_SYMBOLS=Modules.symvers
-
-elif test -r $SPL_OBJ/module/Module.symvers; then :
-
-                       SPL_SYMBOLS=Module.symvers
-
-elif test -r $SPL_OBJ/module/Modules.symvers; then :
-
-                       SPL_SYMBOLS=Modules.symvers
-
-fi
-
-               if test $SPL_SYMBOLS != NONE -o $timeout -le 0; then :
-
-                       break;
-
-else
-
-                       sleep 1
-                       timeout=$((timeout-1))
-
-fi
-       done
-
-       if test "$SPL_SYMBOLS" = NONE; then :
-
-               SPL_SYMBOLS=$LINUX_SYMBOLS
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SPL_SYMBOLS" >&5
-$as_echo "$SPL_SYMBOLS" >&6; }
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether modules can be built" >&5
-$as_echo_n "checking whether modules can be built... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-int
-main (void)
-{
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               if test "x$enable_linux_builtin" != xyes; then
-                       as_fn_error $? "*** Unable to build an empty module." "$LINENO" 5
-               else
-                       as_fn_error $? "
-       *** Unable to build an empty module.
-       *** Please run 'make scripts' inside the kernel source tree." "$LINENO" 5
-               fi
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       if test "x$cross_compiling" != xyes; then :
-
-               if test "$cross_compiling" = yes; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-                               #include "$LINUX/include/linux/license.h"
-
-int
-main ()
-{
-
-                               return !license_is_gpl_compatible("$ZFS_META_LICENSE");
-
-  ;
-  return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-
-$as_echo "#define ZFS_IS_GPL_COMPATIBLE 1" >>confdefs.h
-
-
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-
-fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Linux was built with CONFIG_DEBUG_LOCK_ALLOC" >&5
-$as_echo_n "checking whether Linux was built with CONFIG_DEBUG_LOCK_ALLOC... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/module.h>
-
-int
-main (void)
-{
-
-               #ifndef CONFIG_DEBUG_LOCK_ALLOC
-               #error CONFIG_DEBUG_LOCK_ALLOC not #defined
-               #endif
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mutex_lock() is GPL-only" >&5
-$as_echo_n "checking whether mutex_lock() is GPL-only... " >&6; }
-               tmp_flags="$EXTRA_KCFLAGS"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/module.h>
-                       #include <linux/mutex.h>
-
-                       MODULE_LICENSE("$ZFS_META_LICENSE");
-
-int
-main (void)
-{
-
-                       struct mutex lock;
-
-                       mutex_init(&lock);
-                       mutex_lock(&lock);
-                       mutex_unlock(&lock);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-                       as_fn_error $? "
-       *** Kernel built with CONFIG_DEBUG_LOCK_ALLOC which is incompatible
-       *** with the CDDL license and will prevent the module linking stage
-       *** from succeeding.  You must rebuild your kernel without this
-       *** option enabled." "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-               EXTRA_KCFLAGS="$tmp_flags"
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="-I\$(src)"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether DECLARE_EVENT_CLASS() is available" >&5
-$as_echo_n "checking whether DECLARE_EVENT_CLASS() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/module.h>
-               MODULE_LICENSE(ZFS_META_LICENSE);
-
-               #define CREATE_TRACE_POINTS
-               #include "conftest.h"
-
-int
-main (void)
-{
-
-               trace_zfs_autoconf_event_one(1UL);
-               trace_zfs_autoconf_event_two(2UL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-               #if !defined(_CONFTEST_H) || defined(TRACE_HEADER_MULTI_READ)
-               #define _CONFTEST_H
-
-               #undef  TRACE_SYSTEM
-               #define TRACE_SYSTEM zfs
-               #include <linux/tracepoint.h>
-
-               DECLARE_EVENT_CLASS(zfs_autoconf_event_class,
-                       TP_PROTO(unsigned long i),
-                       TP_ARGS(i),
-                       TP_STRUCT__entry(
-                               __field(unsigned long, i)
-                       ),
-                       TP_fast_assign(
-                               __entry->i = i;
-                       ),
-                       TP_printk("i = %lu", __entry->i)
-               );
-
-               #define DEFINE_AUTOCONF_EVENT(name) \
-               DEFINE_EVENT(zfs_autoconf_event_class, name, \
-                       TP_PROTO(unsigned long i), \
-                       TP_ARGS(i))
-               DEFINE_AUTOCONF_EVENT(zfs_autoconf_event_one);
-               DEFINE_AUTOCONF_EVENT(zfs_autoconf_event_two);
-
-               #endif /* _CONFTEST_H */
-
-               #undef  TRACE_INCLUDE_PATH
-               #define TRACE_INCLUDE_PATH .
-               #define TRACE_INCLUDE_FILE conftest
-               #include <trace/define_trace.h>
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_DECLARE_EVENT_CLASS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether current->bio_tail exists" >&5
-$as_echo_n "checking whether current->bio_tail exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/sched.h>
-
-int
-main (void)
-{
-
-               current->bio_tail = (struct bio **) NULL;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CURRENT_BIO_TAIL 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether current->bio_list exists" >&5
-$as_echo_n "checking whether current->bio_list exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/sched.h>
-
-int
-main (void)
-{
-
-                       current->bio_list = (struct bio_list *) NULL;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CURRENT_BIO_LIST 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       as_fn_error $? "no - Please file a bug report at
-                           https://github.com/zfsonlinux/zfs/issues/new" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether submit_bio() wants 1 arg" >&5
-$as_echo_n "checking whether submit_bio() wants 1 arg... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               blk_qc_t blk_qc;
-               struct bio *bio = NULL;
-               blk_qc = submit_bio(bio);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_1ARG_SUBMIT_BIO 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking block device operation prototypes" >&5
-$as_echo_n "checking block device operation prototypes... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-               int blk_open(struct block_device *bdev, fmode_t mode)
-                   { return 0; }
-               int blk_ioctl(struct block_device *bdev, fmode_t mode,
-                   unsigned x, unsigned long y) { return 0; }
-               int blk_compat_ioctl(struct block_device * bdev, fmode_t mode,
-                   unsigned x, unsigned long y) { return 0; }
-
-               static const struct block_device_operations
-                   bops __attribute__ ((unused)) = {
-                       .open           = blk_open,
-                       .release        = NULL,
-                       .ioctl          = blk_ioctl,
-                       .compat_ioctl   = blk_compat_ioctl,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: struct block_device" >&5
-$as_echo "struct block_device" >&6; }
-
-$as_echo "#define HAVE_BDEV_BLOCK_DEVICE_OPERATIONS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: struct inode" >&5
-$as_echo "struct inode" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether block_device_operations.release is void" >&5
-$as_echo_n "checking whether block_device_operations.release is void... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-               void blk_release(struct gendisk *g, fmode_t mode) { return; }
-
-               static const struct block_device_operations
-                   bops __attribute__ ((unused)) = {
-                       .open           = NULL,
-                       .release        = blk_release,
-                       .ioctl          = NULL,
-                       .compat_ioctl   = NULL,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: void" >&5
-$as_echo "void" >&6; }
-
-$as_echo "#define HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: int" >&5
-$as_echo "int" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kernel defines fmode_t" >&5
-$as_echo_n "checking whether kernel defines fmode_t... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/types.h>
-
-int
-main (void)
-{
-
-               fmode_t *ptr __attribute__ ((unused));
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FMODE_T 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kernel defines KOBJ_NAME_LEN" >&5
-$as_echo_n "checking whether kernel defines KOBJ_NAME_LEN... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/kobject.h>
-
-int
-main (void)
-{
-
-               int val __attribute__ ((unused));
-               val = KOBJ_NAME_LEN;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_KOBJ_NAME_LEN 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blkdev_get() wants 3 args" >&5
-$as_echo_n "checking whether blkdev_get() wants 3 args... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct block_device *bdev = NULL;
-               (void) blkdev_get(bdev, 0, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_3ARG_BLKDEV_GET 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blkdev_get_by_path() is available" >&5
-$as_echo_n "checking whether blkdev_get_by_path() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               blkdev_get_by_path(NULL, 0, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]blkdev_get_by_path[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/block_dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(blkdev_get_by_path)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLKDEV_GET_BY_PATH 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether open_bdev_exclusive() is available" >&5
-$as_echo_n "checking whether open_bdev_exclusive() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               open_bdev_exclusive(NULL, 0, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]open_bdev_exclusive[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/block_dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(open_bdev_exclusive)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_OPEN_BDEV_EXCLUSIVE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lookup_bdev() is available" >&5
-$as_echo_n "checking whether lookup_bdev() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               lookup_bdev(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]lookup_bdev[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/block_dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(lookup_bdev)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_LOOKUP_BDEV 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether invalidate_bdev() wants 1 arg" >&5
-$as_echo_n "checking whether invalidate_bdev() wants 1 arg... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/buffer_head.h>
-
-int
-main (void)
-{
-
-               struct block_device *bdev = NULL;
-               invalidate_bdev(bdev);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_1ARG_INVALIDATE_BDEV 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdev_logical_block_size() is available" >&5
-$as_echo_n "checking whether bdev_logical_block_size() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct block_device *bdev = NULL;
-               bdev_logical_block_size(bdev);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BDEV_LOGICAL_BLOCK_SIZE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdev_physical_block_size() is available" >&5
-$as_echo_n "checking whether bdev_physical_block_size() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct block_device *bdev = NULL;
-               bdev_physical_block_size(bdev);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BDEV_PHYSICAL_BLOCK_SIZE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bio has bi_iter" >&5
-$as_echo_n "checking whether bio has bi_iter... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               struct bio bio;
-               bio.bi_iter.bi_sector = 0;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_BVEC_ITER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether BIO_RW_FAILFAST_* are defined" >&5
-$as_echo_n "checking whether BIO_RW_FAILFAST_* are defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               int flags __attribute__ ((unused));
-               flags = ((1 << BIO_RW_FAILFAST_DEV) |
-                        (1 << BIO_RW_FAILFAST_TRANSPORT) |
-                        (1 << BIO_RW_FAILFAST_DRIVER));
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_RW_FAILFAST_DTD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether REQ_FAILFAST_MASK is defined" >&5
-$as_echo_n "checking whether REQ_FAILFAST_MASK is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               int flags __attribute__ ((unused));
-               flags = REQ_FAILFAST_MASK;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_REQ_FAILFAST_MASK 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether REQ_OP_DISCARD is defined" >&5
-$as_echo_n "checking whether REQ_OP_DISCARD is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blk_types.h>
-
-int
-main (void)
-{
-
-               enum req_op op __attribute__ ((unused)) = REQ_OP_DISCARD;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_REQ_OP_DISCARD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether REQ_OP_SECURE_ERASE is defined" >&5
-$as_echo_n "checking whether REQ_OP_SECURE_ERASE is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blk_types.h>
-
-int
-main (void)
-{
-
-               enum req_op op __attribute__ ((unused)) = REQ_OP_SECURE_ERASE;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_REQ_OP_SECURE_DISCARD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether REQ_OP_FLUSH is defined" >&5
-$as_echo_n "checking whether REQ_OP_FLUSH is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blk_types.h>
-
-int
-main (void)
-{
-
-               enum req_op op __attribute__ ((unused)) = REQ_OP_FLUSH;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_REQ_OP_FLUSH 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bio->bi_opf is defined" >&5
-$as_echo_n "checking whether bio->bi_opf is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               struct bio bio __attribute__ ((unused));
-               bio.bi_opf = 0;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_BI_OPF 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bio_end_io_t wants 1 arg" >&5
-$as_echo_n "checking whether bio_end_io_t wants 1 arg... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-               void wanted_end_io(struct bio *bio) { return; }
-
-               bio_end_io_t *end_io __attribute__ ((unused)) = wanted_end_io;
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_1ARG_BIO_END_IO_T 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether BIO_RW_BARRIER is defined" >&5
-$as_echo_n "checking whether BIO_RW_BARRIER is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               int flags __attribute__ ((unused));
-               flags = BIO_RW_BARRIER;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_RW_BARRIER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether BIO_RW_DISCARD is defined" >&5
-$as_echo_n "checking whether BIO_RW_DISCARD is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               int flags __attribute__ ((unused));
-               flags = BIO_RW_DISCARD;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_RW_DISCARD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_flush() is available" >&5
-$as_echo_n "checking whether blk_queue_flush() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct request_queue *q = NULL;
-               (void) blk_queue_flush(q, REQ_FLUSH);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_FLUSH 1" >>confdefs.h
-
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_flush() is GPL-only" >&5
-$as_echo_n "checking whether blk_queue_flush() is GPL-only... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/module.h>
-                       #include <linux/blkdev.h>
-
-                       MODULE_LICENSE("$ZFS_META_LICENSE");
-
-int
-main (void)
-{
-
-                       struct request_queue *q = NULL;
-                       (void) blk_queue_flush(q, REQ_FLUSH);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_FLUSH_GPL_ONLY 1" >>confdefs.h
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_write_cache() exists" >&5
-$as_echo_n "checking whether blk_queue_write_cache() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/kernel.h>
-               #include <linux/blkdev.h>
-
-
-int
-main (void)
-{
-
-               struct request_queue *q = NULL;
-               blk_queue_write_cache(q, true, true);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_WRITE_CACHE 1" >>confdefs.h
-
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_write_cache() is GPL-only" >&5
-$as_echo_n "checking whether blk_queue_write_cache() is GPL-only... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/kernel.h>
-                       #include <linux/module.h>
-                       #include <linux/blkdev.h>
-
-                       MODULE_LICENSE("$ZFS_META_LICENSE");
-
-int
-main (void)
-{
-
-                       struct request_queue *q = NULL;
-                       blk_queue_write_cache(q, true, true);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_WRITE_CACHE_GPL_ONLY 1" >>confdefs.h
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_max_hw_sectors() is available" >&5
-$as_echo_n "checking whether blk_queue_max_hw_sectors() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct request_queue *q = NULL;
-               (void) blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_MAX_HW_SECTORS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_max_segments() is available" >&5
-$as_echo_n "checking whether blk_queue_max_segments() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct request_queue *q = NULL;
-               (void) blk_queue_max_segments(q, BLK_MAX_SEGMENTS);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_MAX_SEGMENTS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether get_disk_ro() is available" >&5
-$as_echo_n "checking whether get_disk_ro() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct gendisk *disk = NULL;
-               (void) get_disk_ro(disk);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_DISK_RO 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether get_gendisk() is available" >&5
-$as_echo_n "checking whether get_gendisk() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/genhd.h>
-
-int
-main (void)
-{
-
-               get_gendisk(0, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]get_gendisk[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in block/genhd.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(get_gendisk)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_GENDISK 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ql->discard_granularity is available" >&5
-$as_echo_n "checking whether ql->discard_granularity is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct queue_limits ql __attribute__ ((unused));
-
-               ql.discard_granularity = 0;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_DISCARD_GRANULARITY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether super_block uses const struct xattr_handler" >&5
-$as_echo_n "checking whether super_block uses const struct xattr_handler... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/xattr.h>
-
-               const struct xattr_handler xattr_test_handler = {
-                       .prefix = "test",
-                       .get    = NULL,
-                       .set    = NULL,
-               };
-
-               const struct xattr_handler *xattr_handlers[] = {
-                       &xattr_test_handler,
-               };
-
-               const struct super_block sb __attribute__ ((unused)) = {
-                       .s_xattr = xattr_handlers,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CONST_XATTR_HANDLER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler has name" >&5
-$as_echo_n "checking whether xattr_handler has name... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/xattr.h>
-
-               static const struct xattr_handler
-                   xops __attribute__ ((unused)) = {
-                       .name = XATTR_NAME_POSIX_ACL_ACCESS,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_HANDLER_NAME 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->get() wants both dentry and inode" >&5
-$as_echo_n "checking whether xattr_handler->get() wants both dentry and inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/xattr.h>
-
-               int get(const struct xattr_handler *handler,
-                   struct dentry *dentry, struct inode *inode,
-                   const char *name, void *buffer, size_t size) { return 0; }
-               static const struct xattr_handler
-                   xops __attribute__ ((unused)) = {
-                       .get = get,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_GET_DENTRY_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->get() wants xattr_handler" >&5
-$as_echo_n "checking whether xattr_handler->get() wants xattr_handler... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/xattr.h>
-
-                       int get(const struct xattr_handler *handler,
-                           struct dentry *dentry, const char *name,
-                           void *buffer, size_t size) { return 0; }
-                       static const struct xattr_handler
-                           xops __attribute__ ((unused)) = {
-                               .get = get,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_GET_HANDLER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                                                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->get() wants dentry" >&5
-$as_echo_n "checking whether xattr_handler->get() wants dentry... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/xattr.h>
-
-                               int get(struct dentry *dentry, const char *name,
-                                   void *buffer, size_t size, int handler_flags)
-                                   { return 0; }
-                               static const struct xattr_handler
-                                   xops __attribute__ ((unused)) = {
-                                       .get = get,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_GET_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->get() wants inode" >&5
-$as_echo_n "checking whether xattr_handler->get() wants inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                                       #include <linux/xattr.h>
-
-                                       int get(struct inode *ip, const char *name,
-                                           void *buffer, size_t size) { return 0; }
-                                       static const struct xattr_handler
-                                           xops __attribute__ ((unused)) = {
-                                               .get = get,
-                                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_GET_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                       as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->set() wants both dentry and inode" >&5
-$as_echo_n "checking whether xattr_handler->set() wants both dentry and inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/xattr.h>
-
-               int set(const struct xattr_handler *handler,
-                   struct dentry *dentry, struct inode *inode,
-                   const char *name, const void *buffer,
-                   size_t size, int flags)
-                   { return 0; }
-               static const struct xattr_handler
-                   xops __attribute__ ((unused)) = {
-                       .set = set,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_SET_DENTRY_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->set() wants xattr_handler" >&5
-$as_echo_n "checking whether xattr_handler->set() wants xattr_handler... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/xattr.h>
-
-                       int set(const struct xattr_handler *handler,
-                           struct dentry *dentry, const char *name,
-                           const void *buffer, size_t size, int flags)
-                           { return 0; }
-                       static const struct xattr_handler
-                           xops __attribute__ ((unused)) = {
-                               .set = set,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_SET_HANDLER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                                                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->set() wants dentry" >&5
-$as_echo_n "checking whether xattr_handler->set() wants dentry... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/xattr.h>
-
-                               int set(struct dentry *dentry, const char *name,
-                                   const void *buffer, size_t size, int flags,
-                                   int handler_flags) { return 0; }
-                               static const struct xattr_handler
-                                   xops __attribute__ ((unused)) = {
-                                       .set = set,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_SET_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->set() wants inode" >&5
-$as_echo_n "checking whether xattr_handler->set() wants inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                                       #include <linux/xattr.h>
-
-                                       int set(struct inode *ip, const char *name,
-                                           const void *buffer, size_t size, int flags)
-                                           { return 0; }
-                                       static const struct xattr_handler
-                                           xops __attribute__ ((unused)) = {
-                                               .set = set,
-                                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_SET_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                       as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->list() wants simple" >&5
-$as_echo_n "checking whether xattr_handler->list() wants simple... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/xattr.h>
-
-               bool list(struct dentry *dentry) { return 0; }
-               static const struct xattr_handler
-                   xops __attribute__ ((unused)) = {
-                       .list = list,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_LIST_SIMPLE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->list() wants xattr_handler" >&5
-$as_echo_n "checking whether xattr_handler->list() wants xattr_handler... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/xattr.h>
-
-                       size_t list(const struct xattr_handler *handler,
-                           struct dentry *dentry, char *list, size_t list_size,
-                           const char *name, size_t name_len) { return 0; }
-                       static const struct xattr_handler
-                           xops __attribute__ ((unused)) = {
-                               .list = list,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_LIST_HANDLER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                                                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->list() wants dentry" >&5
-$as_echo_n "checking whether xattr_handler->list() wants dentry... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/xattr.h>
-
-                               size_t list(struct dentry *dentry,
-                                   char *list, size_t list_size,
-                                   const char *name, size_t name_len,
-                                   int handler_flags) { return 0; }
-                               static const struct xattr_handler
-                                   xops __attribute__ ((unused)) = {
-                                       .list = list,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_LIST_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->list() wants inode" >&5
-$as_echo_n "checking whether xattr_handler->list() wants inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                                       #include <linux/xattr.h>
-
-                                       size_t list(struct inode *ip, char *lst,
-                                           size_t list_size, const char *name,
-                                           size_t name_len) { return 0; }
-                                       static const struct xattr_handler
-                                           xops __attribute__ ((unused)) = {
-                                               .list = list,
-                                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_LIST_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                       as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether inode_owner_or_capable() exists" >&5
-$as_echo_n "checking whether inode_owner_or_capable() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct inode *ip = NULL;
-               (void) inode_owner_or_capable(ip);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_INODE_OWNER_OR_CAPABLE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether is_owner_or_cap() exists" >&5
-$as_echo_n "checking whether is_owner_or_cap() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/fs.h>
-                       #include <linux/sched.h>
-
-int
-main (void)
-{
-
-                       struct inode *ip = NULL;
-                       (void) is_owner_or_cap(ip);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_IS_OWNER_OR_CAP 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       as_fn_error $? "no - Please file a bug report at
-                           https://github.com/zfsonlinux/zfs/issues/new" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_from_xattr() needs user_ns" >&5
-$as_echo_n "checking whether posix_acl_from_xattr() needs user_ns... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/cred.h>
-               #include <linux/fs.h>
-               #include <linux/posix_acl_xattr.h>
-
-int
-main (void)
-{
-
-               posix_acl_from_xattr(&init_user_ns, NULL, 0);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_FROM_XATTR_USERNS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_release() is available" >&5
-$as_echo_n "checking whether posix_acl_release() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/cred.h>
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               struct posix_acl* tmp = posix_acl_alloc(1, 0);
-               posix_acl_release(tmp);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_RELEASE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_release() is GPL-only" >&5
-$as_echo_n "checking whether posix_acl_release() is GPL-only... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/cred.h>
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-               MODULE_LICENSE("$ZFS_META_LICENSE");
-
-int
-main (void)
-{
-
-               struct posix_acl* tmp = posix_acl_alloc(1, 0);
-               posix_acl_release(tmp);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_RELEASE_GPL_ONLY 1" >>confdefs.h
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_chmod exists" >&5
-$as_echo_n "checking whether posix_acl_chmod exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               posix_acl_chmod(NULL, 0, 0)
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_CHMOD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __posix_acl_chmod exists" >&5
-$as_echo_n "checking whether __posix_acl_chmod exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               __posix_acl_chmod(NULL, 0, 0)
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE___POSIX_ACL_CHMOD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_equiv_mode() wants umode_t" >&5
-$as_echo_n "checking whether posix_acl_equiv_mode() wants umode_t... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               umode_t tmp;
-               posix_acl_equiv_mode(NULL,&tmp);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_EQUIV_MODE_UMODE_T 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_valid() wants user namespace" >&5
-$as_echo_n "checking whether posix_acl_valid() wants user namespace... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               struct user_namespace *user_ns = NULL;
-               const struct posix_acl *acl = NULL;
-               int error;
-
-               error = posix_acl_valid(user_ns, acl);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_VALID_WITH_NS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->permission() exists" >&5
-$as_echo_n "checking whether iops->permission() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int permission_fn(struct inode *inode, int mask) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .permission = permission_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PERMISSION 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->permission() wants nameidata" >&5
-$as_echo_n "checking whether iops->permission() wants nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int permission_fn(struct inode *inode, int mask,
-                   struct nameidata *nd) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .permission = permission_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PERMISSION 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_PERMISSION_WITH_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->check_acl() exists" >&5
-$as_echo_n "checking whether iops->check_acl() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int check_acl_fn(struct inode *inode, int mask) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .check_acl = check_acl_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CHECK_ACL 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->check_acl() wants flags" >&5
-$as_echo_n "checking whether iops->check_acl() wants flags... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int check_acl_fn(struct inode *inode, int mask,
-                   unsigned int flags) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .check_acl = check_acl_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CHECK_ACL 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_CHECK_ACL_WITH_FLAGS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->get_acl() exists" >&5
-$as_echo_n "checking whether iops->get_acl() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               struct posix_acl *get_acl_fn(struct inode *inode, int type)
-                   { return NULL; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .get_acl = get_acl_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_ACL 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether uncached_acl_sentinel() exists" >&5
-$as_echo_n "checking whether uncached_acl_sentinel() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               void *sentinel __attribute__ ((unused)) = uncached_acl_sentinel(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_KERNEL_GET_ACL_HANDLE_CACHE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->show_options() wants dentry" >&5
-$as_echo_n "checking whether sops->show_options() wants dentry... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int show_options (struct seq_file * x, struct dentry * y) { return 0; };
-               static struct super_operations sops __attribute__ ((unused)) = {
-                       .show_options = show_options,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_SHOW_OPTIONS_WITH_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether file_inode() is available" >&5
-$as_echo_n "checking whether file_inode() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct file *f = NULL;
-               file_inode(f);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FILE_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->fsync() wants" >&5
-$as_echo_n "checking whether fops->fsync() wants... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int test_fsync(struct file *f, struct dentry *dentry, int x)
-                   { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                       .fsync = test_fsync,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: dentry" >&5
-$as_echo "dentry" >&6; }
-
-$as_echo "#define HAVE_FSYNC_WITH_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int test_fsync(struct file *f, int x) { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                       .fsync = test_fsync,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no dentry" >&5
-$as_echo "no dentry" >&6; }
-
-$as_echo "#define HAVE_FSYNC_WITHOUT_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int test_fsync(struct file *f, loff_t a, loff_t b, int c)
-                   { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                       .fsync = test_fsync,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: range" >&5
-$as_echo "range" >&6; }
-
-$as_echo "#define HAVE_FSYNC_RANGE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->evict_inode() exists" >&5
-$as_echo_n "checking whether sops->evict_inode() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               void evict_inode (struct inode * t) { return; }
-               static struct super_operations sops __attribute__ ((unused)) = {
-                       .evict_inode = evict_inode,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_EVICT_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->dirty_inode() wants flags" >&5
-$as_echo_n "checking whether sops->dirty_inode() wants flags... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               void dirty_inode(struct inode *a, int b) { return; }
-
-               static const struct super_operations
-                   sops __attribute__ ((unused)) = {
-                       .dirty_inode = dirty_inode,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_DIRTY_INODE_WITH_FLAGS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->nr_cached_objects() exists" >&5
-$as_echo_n "checking whether sops->nr_cached_objects() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int nr_cached_objects(struct super_block *sb) { return 0; }
-
-               static const struct super_operations
-                   sops __attribute__ ((unused)) = {
-                       .nr_cached_objects = nr_cached_objects,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_NR_CACHED_OBJECTS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->free_cached_objects() exists" >&5
-$as_echo_n "checking whether sops->free_cached_objects() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               void free_cached_objects(struct super_block *sb, int x)
-                   { return; }
-
-               static const struct super_operations
-                   sops __attribute__ ((unused)) = {
-                       .free_cached_objects = free_cached_objects,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FREE_CACHED_OBJECTS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->fallocate() exists" >&5
-$as_echo_n "checking whether fops->fallocate() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               long test_fallocate(struct file *file, int mode,
-                   loff_t offset, loff_t len) { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                       .fallocate = test_fallocate,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FILE_FALLOCATE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->fallocate() exists" >&5
-$as_echo_n "checking whether iops->fallocate() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               long test_fallocate(struct inode *inode, int mode,
-                   loff_t offset, loff_t len) { return 0; }
-
-               static const struct inode_operations
-                   fops __attribute__ ((unused)) = {
-                       .fallocate = test_fallocate,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_INODE_FALLOCATE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->create()/mkdir()/mknod() take umode_t" >&5
-$as_echo_n "checking whether iops->create()/mkdir()/mknod() take umode_t... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int mkdir(struct inode *inode, struct dentry *dentry,
-                   umode_t umode) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .mkdir = mkdir,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_MKDIR_UMODE_T 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->lookup() passes nameidata" >&5
-$as_echo_n "checking whether iops->lookup() passes nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               struct dentry *inode_lookup(struct inode *inode,
-                   struct dentry *dentry, struct nameidata *nidata)
-                   { return NULL; }
-
-               static const struct inode_operations iops
-                   __attribute__ ((unused)) = {
-                       .lookup = inode_lookup,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_LOOKUP_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->create() passes nameidata" >&5
-$as_echo_n "checking whether iops->create() passes nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               #ifdef HAVE_MKDIR_UMODE_T
-               int inode_create(struct inode *inode ,struct dentry *dentry,
-                   umode_t umode, struct nameidata *nidata) { return 0; }
-               #else
-               int inode_create(struct inode *inode,struct dentry *dentry,
-                   int umode, struct nameidata * nidata) { return 0; }
-               #endif
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .create         = inode_create,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CREATE_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->get_link() passes delayed" >&5
-$as_echo_n "checking whether iops->get_link() passes delayed... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               const char *get_link(struct dentry *de, struct inode *ip,
-                   struct delayed_call *done) { return "symlink"; }
-               static struct inode_operations
-                    iops __attribute__ ((unused)) = {
-                       .get_link = get_link,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_LINK_DELAYED 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->get_link() passes cookie" >&5
-$as_echo_n "checking whether iops->get_link() passes cookie... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/fs.h>
-                       const char *get_link(struct dentry *de, struct
-                           inode *ip, void **cookie) { return "symlink"; }
-                       static struct inode_operations
-                            iops __attribute__ ((unused)) = {
-                               .get_link = get_link,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_LINK_COOKIE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->follow_link() passes cookie" >&5
-$as_echo_n "checking whether iops->follow_link() passes cookie... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               const char *follow_link(struct dentry *de,
-                   void **cookie) { return "symlink"; }
-               static struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .follow_link = follow_link,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FOLLOW_LINK_COOKIE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->follow_link() passes nameidata" >&5
-$as_echo_n "checking whether iops->follow_link() passes nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-                       void *follow_link(struct dentry *de, struct
-                           nameidata *nd) { return (void *)NULL; }
-                       static struct inode_operations
-                           iops __attribute__ ((unused)) = {
-                               .follow_link = follow_link,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FOLLOW_LINK_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                        as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #if !defined(HAVE_GET_LINK_DELAYED)
-               #error "Expecting get_link() delayed done"
-               #endif
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-
-$as_echo "#define HAVE_PUT_LINK_DELAYED 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->put_link() passes cookie" >&5
-$as_echo_n "checking whether iops->put_link() passes cookie... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/fs.h>
-                       void put_link(struct inode *ip, void *cookie)
-                           { return; }
-                       static struct inode_operations
-                           iops __attribute__ ((unused)) = {
-                               .put_link = put_link,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PUT_LINK_COOKIE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->put_link() passes nameidata" >&5
-$as_echo_n "checking whether iops->put_link() passes nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/fs.h>
-                               void put_link(struct dentry *de, struct
-                                   nameidata *nd, void *ptr) { return; }
-                               static struct inode_operations
-                                   iops __attribute__ ((unused)) = {
-                                       .put_link = put_link,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PUT_LINK_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                               as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->truncate_range() exists" >&5
-$as_echo_n "checking whether iops->truncate_range() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               void truncate_range(struct inode *inode, loff_t start,
-                                   loff_t end) { return; }
-               static struct inode_operations iops __attribute__ ((unused)) = {
-                       .truncate_range = truncate_range,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_INODE_TRUNCATE_RANGE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dops->d_automount() exists" >&5
-$as_echo_n "checking whether dops->d_automount() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-               struct vfsmount *d_automount(struct path *p) { return NULL; }
-               struct dentry_operations dops __attribute__ ((unused)) = {
-                       .d_automount = d_automount,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_AUTOMOUNT 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether eops->encode_fh() wants inode" >&5
-$as_echo_n "checking whether eops->encode_fh() wants inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/exportfs.h>
-               int encode_fh(struct inode *inode, __u32 *fh, int *max_len,
-                             struct inode *parent) { return 0; }
-               static struct export_operations eops __attribute__ ((unused))={
-                       .encode_fh = encode_fh,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_ENCODE_FH_WITH_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether eops->commit_metadata() exists" >&5
-$as_echo_n "checking whether eops->commit_metadata() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/exportfs.h>
-               int commit_metadata(struct inode *inode) { return 0; }
-               static struct export_operations eops __attribute__ ((unused))={
-                       .commit_metadata = commit_metadata,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_COMMIT_METADATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether clear_inode() is available" >&5
-$as_echo_n "checking whether clear_inode() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               clear_inode(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]clear_inode[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/inode.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(clear_inode)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CLEAR_INODE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether insert_inode_locked() is available" >&5
-$as_echo_n "checking whether insert_inode_locked() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               insert_inode_locked(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]insert_inode_locked[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/inode.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(insert_inode_locked)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_INSERT_INODE_LOCKED 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether d_make_root() is available" >&5
-$as_echo_n "checking whether d_make_root() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-int
-main (void)
-{
-
-               d_make_root(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]d_make_root[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/dcache.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(d_make_root)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_MAKE_ROOT 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether d_obtain_alias() is available" >&5
-$as_echo_n "checking whether d_obtain_alias() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-int
-main (void)
-{
-
-               d_obtain_alias(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]d_obtain_alias[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/dcache.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(d_obtain_alias)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_OBTAIN_ALIAS 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether d_prune_aliases() is available" >&5
-$as_echo_n "checking whether d_prune_aliases() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-int
-main (void)
-{
-
-               struct inode *ip = NULL;
-               d_prune_aliases(ip);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]d_prune_aliases[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/dcache.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(d_prune_aliases)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_PRUNE_ALIASES 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether d_set_d_op() is available" >&5
-$as_echo_n "checking whether d_set_d_op() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-int
-main (void)
-{
-
-               d_set_d_op(NULL, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]d_set_d_op[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/dcache.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(d_set_d_op)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_SET_D_OP 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dops->d_revalidate() takes struct nameidata" >&5
-$as_echo_n "checking whether dops->d_revalidate() takes struct nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-               int revalidate (struct dentry *dentry,
-                   struct nameidata *nidata) { return 0; }
-
-               static const struct dentry_operations
-                   dops __attribute__ ((unused)) = {
-                       .d_revalidate   = revalidate,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_REVALIDATE_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dentry uses const struct dentry_operations" >&5
-$as_echo_n "checking whether dentry uses const struct dentry_operations... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-               const struct dentry_operations test_d_op = {
-                       .d_revalidate = NULL,
-               };
-
-int
-main (void)
-{
-
-               struct dentry d __attribute__ ((unused));
-
-               d.d_op = &test_d_op;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CONST_DENTRY_OPERATIONS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether check_disk_size_change() is available" >&5
-$as_echo_n "checking whether check_disk_size_change() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               check_disk_size_change(NULL, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]check_disk_size_change[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/block_dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(check_disk_size_change)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CHECK_DISK_SIZE_CHANGE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether truncate_setsize() is available" >&5
-$as_echo_n "checking whether truncate_setsize() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/mm.h>
-
-int
-main (void)
-{
-
-               truncate_setsize(NULL, 0);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]truncate_setsize[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in mm/truncate.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(truncate_setsize)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_TRUNCATE_SETSIZE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether security_inode_init_security wants 6 args" >&5
-$as_echo_n "checking whether security_inode_init_security wants 6 args... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/security.h>
-
-int
-main (void)
-{
-
-               struct inode *ip __attribute__ ((unused)) = NULL;
-               struct inode *dip __attribute__ ((unused)) = NULL;
-               const struct qstr *str __attribute__ ((unused)) = NULL;
-               char *name __attribute__ ((unused)) = NULL;
-               void *value __attribute__ ((unused)) = NULL;
-               size_t len __attribute__ ((unused)) = 0;
-
-               security_inode_init_security(ip, dip, str, &name, &value, &len);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_6ARGS_SECURITY_INODE_INIT_SECURITY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether security_inode_init_security wants callback" >&5
-$as_echo_n "checking whether security_inode_init_security wants callback... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/security.h>
-
-int
-main (void)
-{
-
-               struct inode *ip __attribute__ ((unused)) = NULL;
-               struct inode *dip __attribute__ ((unused)) = NULL;
-               const struct qstr *str __attribute__ ((unused)) = NULL;
-               initxattrs func __attribute__ ((unused)) = NULL;
-
-               security_inode_init_security(ip, dip, str, func, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mount_nodev() is available" >&5
-$as_echo_n "checking whether mount_nodev() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               mount_nodev(NULL, 0, NULL, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]mount_nodev[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/super.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(mount_nodev)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_MOUNT_NODEV 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether super_block has s_shrink" >&5
-$as_echo_n "checking whether super_block has s_shrink... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int shrink(struct shrinker *s, struct shrink_control *sc)
-                   { return 0; }
-
-               static const struct super_block
-                   sb __attribute__ ((unused)) = {
-                       .s_shrink.shrink = shrink,
-                       .s_shrink.seeks = DEFAULT_SEEKS,
-                       .s_shrink.batch = 0,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_SHRINK 1" >>confdefs.h
-
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether shrink_control has nid" >&5
-$as_echo_n "checking whether shrink_control has nid... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct shrink_control sc __attribute__ ((unused));
-               unsigned long scnidsize __attribute__ ((unused)) =
-                   sizeof(sc.nid);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define SHRINK_CONTROL_HAS_NID 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether super_block has s_instances list_head" >&5
-$as_echo_n "checking whether super_block has s_instances list_head... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct super_block sb __attribute__ ((unused));
-
-               INIT_LIST_HEAD(&sb.s_instances);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_S_INSTANCES_LIST_HEAD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether super_block has s_d_op" >&5
-$as_echo_n "checking whether super_block has s_d_op... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct super_block sb __attribute__ ((unused));
-               sb.s_d_op = NULL;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_S_D_OP 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdi_setup_and_register() wants 2 args" >&5
-$as_echo_n "checking whether bdi_setup_and_register() wants 2 args... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/backing-dev.h>
-               struct backing_dev_info bdi;
-
-int
-main (void)
-{
-
-               char *name = "bdi";
-               int error __attribute__((unused)) =
-                   bdi_setup_and_register(&bdi, name);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdi_setup_and_register() wants 3 args" >&5
-$as_echo_n "checking whether bdi_setup_and_register() wants 3 args... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/backing-dev.h>
-                       struct backing_dev_info bdi;
-
-int
-main (void)
-{
-
-                       char *name = "bdi";
-                       unsigned int cap = BDI_CAP_MAP_COPY;
-                       int error __attribute__((unused)) =
-                           bdi_setup_and_register(&bdi, name, cap);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]bdi_setup_and_register[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in mm/backing-dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(bdi_setup_and_register)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_3ARGS_BDI_SETUP_AND_REGISTER 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]bdi_setup_and_register[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in mm/backing-dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(bdi_setup_and_register)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdi_setup_and_register() wants 3 args" >&5
-$as_echo_n "checking whether bdi_setup_and_register() wants 3 args... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/backing-dev.h>
-                       struct backing_dev_info bdi;
-
-int
-main (void)
-{
-
-                       char *name = "bdi";
-                       unsigned int cap = BDI_CAP_MAP_COPY;
-                       int error __attribute__((unused)) =
-                           bdi_setup_and_register(&bdi, name, cap);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]bdi_setup_and_register[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in mm/backing-dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(bdi_setup_and_register)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_3ARGS_BDI_SETUP_AND_REGISTER 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_2ARGS_BDI_SETUP_AND_REGISTER 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether set_nlink() is available" >&5
-$as_echo_n "checking whether set_nlink() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct inode node;
-               unsigned int link = 0;
-               (void) set_nlink(&node, link);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_SET_NLINK 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether elevator_change() is available" >&5
-$as_echo_n "checking whether elevator_change() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-               #include <linux/elevator.h>
-
-int
-main (void)
-{
-
-               int ret;
-               struct request_queue *q = NULL;
-               char *elevator = NULL;
-               ret = elevator_change(q, elevator);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_ELEVATOR_CHANGE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sget() wants 5 args" >&5
-$as_echo_n "checking whether sget() wants 5 args... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct file_system_type *type = NULL;
-               int (*test)(struct super_block *,void *) = NULL;
-               int (*set)(struct super_block *,void *) = NULL;
-               int flags = 0;
-               void *data = NULL;
-               (void) sget(type, test, set, flags, data);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_5ARG_SGET 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lseek_execute() is available" >&5
-$as_echo_n "checking whether lseek_execute() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct file *fp __attribute__ ((unused)) = NULL;
-               struct inode *ip __attribute__ ((unused)) = NULL;
-               loff_t offset __attribute__ ((unused)) = 0;
-               loff_t maxsize __attribute__ ((unused)) = 0;
-
-               lseek_execute(fp, ip, offset, maxsize);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]lseek_exclusive[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/read_write.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(lseek_exclusive)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_LSEEK_EXECUTE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->iterate_shared() is available" >&5
-$as_echo_n "checking whether fops->iterate_shared() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               int iterate(struct file *filp, struct dir_context * context)
-                   { return 0; }
-
-               static const struct file_operations fops
-                   __attribute__ ((unused)) = {
-                       .iterate_shared  = iterate,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_VFS_ITERATE_SHARED 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->iterate() is available" >&5
-$as_echo_n "checking whether fops->iterate() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/fs.h>
-                       int iterate(struct file *filp, struct dir_context * context)
-                           { return 0; }
-
-                       static const struct file_operations fops
-                           __attribute__ ((unused)) = {
-                               .iterate         = iterate,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_VFS_ITERATE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->readdir() is available" >&5
-$as_echo_n "checking whether fops->readdir() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/fs.h>
-                               int readdir(struct file *filp, void *entry, filldir_t func)
-                                   { return 0; }
-
-                               static const struct file_operations fops
-                                   __attribute__ ((unused)) = {
-                                       .readdir = readdir,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_VFS_READDIR 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                               as_fn_error $? "no; file a bug report with ZFSOnLinux" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->read/write_iter() are available" >&5
-$as_echo_n "checking whether fops->read/write_iter() are available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               ssize_t test_read(struct kiocb *kiocb, struct iov_iter *to)
-                   { return 0; }
-               ssize_t test_write(struct kiocb *kiocb, struct iov_iter *from)
-                   { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                   .read_iter = test_read,
-                   .write_iter = test_write,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_VFS_RW_ITERATE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kmap_atomic wants 1 args" >&5
-$as_echo_n "checking whether kmap_atomic wants 1 args... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/pagemap.h>
-
-int
-main (void)
-{
-
-               struct page page;
-               kmap_atomic(&page);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_1ARG_KMAP_ATOMIC 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether follow_down_one() is available" >&5
-$as_echo_n "checking whether follow_down_one() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/namei.h>
-
-int
-main (void)
-{
-
-               struct path *p = NULL;
-               follow_down_one(p);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FOLLOW_DOWN_ONE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether make_request_fn() returns int" >&5
-$as_echo_n "checking whether make_request_fn() returns int... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-               int make_request(struct request_queue *q, struct bio *bio)
-               {
-                       return (0);
-               }
-
-int
-main (void)
-{
-
-               blk_queue_make_request(NULL, &make_request);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define MAKE_REQUEST_FN_RET int" >>confdefs.h
-
-
-$as_echo "#define HAVE_MAKE_REQUEST_FN_RET_INT 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether make_request_fn() returns void" >&5
-$as_echo_n "checking whether make_request_fn() returns void... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/blkdev.h>
-
-                       void make_request(struct request_queue *q, struct bio *bio)
-                       {
-                               return;
-                       }
-
-int
-main (void)
-{
-
-                       blk_queue_make_request(NULL, &make_request);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define MAKE_REQUEST_FN_RET void" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether make_request_fn() returns blk_qc_t" >&5
-$as_echo_n "checking whether make_request_fn() returns blk_qc_t... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/blkdev.h>
-
-                               blk_qc_t make_request(struct request_queue *q, struct bio *bio)
-                               {
-                                       return (BLK_QC_T_NONE);
-                               }
-
-int
-main (void)
-{
-
-                               blk_queue_make_request(NULL, &make_request);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define MAKE_REQUEST_FN_RET blk_qc_t" >>confdefs.h
-
-
-$as_echo "#define HAVE_MAKE_REQUEST_FN_RET_QC 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                               as_fn_error $? "no - Please file a bug report at
-                                   https://github.com/zfsonlinux/zfs/issues/new" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether generic IO accounting symbols are avaliable" >&5
-$as_echo_n "checking whether generic IO accounting symbols are avaliable... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-               void (*generic_start_io_acct_f)(int, unsigned long,
-                   struct hd_struct *) = &generic_start_io_acct;
-               void (*generic_end_io_acct_f)(int, struct hd_struct *,
-                   unsigned long) = &generic_end_io_acct;
-
-int
-main (void)
-{
-
-               generic_start_io_acct(0, 0, NULL);
-               generic_end_io_acct(0, NULL, 0);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]generic_start_io_acct[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in block/bio.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(generic_start_io_acct)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GENERIC_IO_ACCT 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       if test "$LINUX_OBJ" != "$LINUX"; then :
-
-               KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
-
-fi
-
-
-
-                       KERNELCPPFLAGS="$KERNELCPPFLAGS $NO_UNUSED_BUT_SET_VARIABLE"
-       KERNELCPPFLAGS="$KERNELCPPFLAGS $NO_BOOL_COMPARE"
-       KERNELCPPFLAGS="$KERNELCPPFLAGS -DHAVE_SPL -D_KERNEL"
-       KERNELCPPFLAGS="$KERNELCPPFLAGS -DTEXT_DOMAIN=\\\"zfs-linux-kernel\\\""
-
-
- ;;
-               all)
-
-
-# Check whether --with-linux was given.
-if test "${with_linux+set}" = set; then :
-  withval=$with_linux; kernelsrc="$withval"
-fi
-
-
-
-# Check whether --with-linux-obj was given.
-if test "${with_linux_obj+set}" = set; then :
-  withval=$with_linux_obj; kernelbuild="$withval"
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel source directory" >&5
-$as_echo_n "checking kernel source directory... " >&6; }
-       if test -z "$kernelsrc"; then :
-
-               if test -e "/lib/modules/$(uname -r)/source"; then :
-
-                       headersdir="/lib/modules/$(uname -r)/source"
-                       sourcelink=$(readlink -f "$headersdir")
-
-elif test -e "/lib/modules/$(uname -r)/build"; then :
-
-                       headersdir="/lib/modules/$(uname -r)/build"
-                       sourcelink=$(readlink -f "$headersdir")
-
-else
-
-                       sourcelink=$(ls -1d /usr/src/kernels/* \
-                                    /usr/src/linux-* \
-                                    2>/dev/null | grep -v obj | tail -1)
-
-fi
-
-               if test -n "$sourcelink" && test -e ${sourcelink}; then :
-
-                       kernelsrc=`readlink -f ${sourcelink}`
-
-else
-
-                       kernelsrc="Not found"
-
-fi
-
-else
-
-               if test "$kernelsrc" = "NONE"; then :
-
-                       kernsrcver=NONE
-
-fi
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $kernelsrc" >&5
-$as_echo "$kernelsrc" >&6; }
-       if test ! -d "$kernelsrc"; then :
-
-               as_fn_error $? "
-       *** Please make sure the kernel devel package for your distribution
-       *** is installed and then try again.  If that fails, you can specify the
-       *** location of the kernel source with the '--with-linux=PATH' option." "$LINENO" 5
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel build directory" >&5
-$as_echo_n "checking kernel build directory... " >&6; }
-       if test -z "$kernelbuild"; then :
-
-               if test -e "/lib/modules/$(uname -r)/build"; then :
-
-                       kernelbuild=`readlink -f /lib/modules/$(uname -r)/build`
-
-elif test -d ${kernelsrc}-obj/${target_cpu}/${target_cpu}; then :
-
-                       kernelbuild=${kernelsrc}-obj/${target_cpu}/${target_cpu}
-
-elif test -d ${kernelsrc}-obj/${target_cpu}/default; then :
-
-                       kernelbuild=${kernelsrc}-obj/${target_cpu}/default
-
-elif test -d `dirname ${kernelsrc}`/build-${target_cpu}; then :
-
-                       kernelbuild=`dirname ${kernelsrc}`/build-${target_cpu}
-
-else
-
-                       kernelbuild=${kernelsrc}
-
-fi
-
-fi
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $kernelbuild" >&5
-$as_echo "$kernelbuild" >&6; }
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel source version" >&5
-$as_echo_n "checking kernel source version... " >&6; }
-       utsrelease1=$kernelbuild/include/linux/version.h
-       utsrelease2=$kernelbuild/include/linux/utsrelease.h
-       utsrelease3=$kernelbuild/include/generated/utsrelease.h
-       if test -r $utsrelease1 && fgrep -q UTS_RELEASE $utsrelease1; then :
-
-               utsrelease=linux/version.h
-
-elif test -r $utsrelease2 && fgrep -q UTS_RELEASE $utsrelease2; then :
-
-               utsrelease=linux/utsrelease.h
-
-elif test -r $utsrelease3 && fgrep -q UTS_RELEASE $utsrelease3; then :
-
-               utsrelease=generated/utsrelease.h
-
-fi
-
-       if test "$utsrelease"; then :
-
-               kernsrcver=`(echo "#include <$utsrelease>";
-                            echo "kernsrcver=UTS_RELEASE") |
-                            cpp -I $kernelbuild/include |
-                            grep "^kernsrcver=" | cut -d \" -f 2`
-
-               if test -z "$kernsrcver"; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not found" >&5
-$as_echo "Not found" >&6; }
-                       as_fn_error $? "*** Cannot determine kernel version." "$LINENO" 5
-
-fi
-
-else
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not found" >&5
-$as_echo "Not found" >&6; }
-               if test "x$enable_linux_builtin" != xyes; then
-                       as_fn_error $? "*** Cannot find UTS_RELEASE definition." "$LINENO" 5
-               else
-                       as_fn_error $? "
-       *** Cannot find UTS_RELEASE definition.
-       *** Please run 'make prepare' inside the kernel source tree." "$LINENO" 5
-               fi
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $kernsrcver" >&5
-$as_echo "$kernsrcver" >&6; }
-
-       LINUX=${kernelsrc}
-       LINUX_OBJ=${kernelbuild}
-       LINUX_VERSION=${kernsrcver}
-
-
-
-
-
-
-       modpost=$LINUX/scripts/Makefile.modpost
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking kernel file name for module symbols" >&5
-$as_echo_n "checking kernel file name for module symbols... " >&6; }
-       if test "x$enable_linux_builtin" != xyes -a -f "$modpost"; then :
-
-               if grep -q Modules.symvers $modpost; then :
-
-                       LINUX_SYMBOLS=Modules.symvers
-
-else
-
-                       LINUX_SYMBOLS=Module.symvers
-
-fi
-
-               if test ! -f "$LINUX_OBJ/$LINUX_SYMBOLS"; then :
-
-                       as_fn_error $? "
-       *** Please make sure the kernel devel package for your distribution
-       *** is installed.  If you are building with a custom kernel, make sure the
-       *** kernel is configured, built, and the '--with-linux=PATH' configure
-       *** option refers to the location of the kernel source." "$LINENO" 5
-
-fi
-
-else
-
-               LINUX_SYMBOLS=NONE
-
-fi
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINUX_SYMBOLS" >&5
-$as_echo "$LINUX_SYMBOLS" >&6; }
-
-
-
-
-
-# Check whether --with-spl was given.
-if test "${with_spl+set}" = set; then :
-  withval=$with_spl; splsrc="$withval"
-fi
-
-
-
-# Check whether --with-spl-obj was given.
-if test "${with_spl_obj+set}" = set; then :
-  withval=$with_spl_obj; splbuild="$withval"
-fi
-
-
-
-# Check whether --with-spl-timeout was given.
-if test "${with_spl_timeout+set}" = set; then :
-  withval=$with_spl_timeout; timeout="$withval"
-else
-  timeout=0
-fi
-
-
-                                       splsrc0="/var/lib/dkms/spl/${VERSION}/build"
-       splsrc1="/usr/local/src/spl-${VERSION}/${LINUX_VERSION}"
-       splsrc2="/usr/local/src/spl-${VERSION}"
-       splsrc3="/usr/src/spl-${VERSION}/${LINUX_VERSION}"
-       splsrc4="/usr/src/spl-${VERSION}"
-       splsrc5="../spl/"
-       splsrc6="$LINUX"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl source directory" >&5
-$as_echo_n "checking spl source directory... " >&6; }
-       if test -z "${splsrc}"; then :
-
-               if  test -e "${splsrc0}/spl.release.in"; then :
-
-                       splsrc=${splsrc0}
-
-elif  test -e "${splsrc1}/spl.release.in"; then :
-
-                       splsrc=${splsrc1}
-
-elif  test -e "${splsrc2}/spl.release.in"; then :
-
-                       splsrc=${splsrc2}
-
-elif  test -e "${splsrc3}/spl.release.in"; then :
-
-                       splsrc=$(readlink -f "${splsrc3}")
-
-elif  test -e "${splsrc4}/spl.release.in" ; then :
-
-                       splsrc=${splsrc4}
-
-elif  test -e "${splsrc5}/spl.release.in"; then :
-
-                       splsrc=$(readlink -f "${splsrc5}")
-
-elif  test -e "${splsrc6}/spl.release.in" ; then :
-
-                       splsrc=${splsrc6}
-
-else
-
-                       splsrc="Not found"
-
-fi
-
-else
-
-               if test "$splsrc" = "NONE"; then :
-
-                       splbuild=NONE
-                       splsrcver=NONE
-
-fi
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $splsrc" >&5
-$as_echo "$splsrc" >&6; }
-       if  test ! -e "$splsrc/spl.release.in"; then :
-
-               as_fn_error $? "
-       *** Please make sure the kmod spl devel package for your distribution
-       *** is installed then try again.  If that fails you can specify the
-       *** location of the spl source with the '--with-spl=PATH' option." "$LINENO" 5
-
-fi
-
-                                                                                                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl build directory" >&5
-$as_echo_n "checking spl build directory... " >&6; }
-       while true; do
-               if test -z "$splbuild"; then :
-
-                       if  test -e "${splsrc}/${LINUX_VERSION}/spl_config.h" ; then :
-
-                               splbuild="${splsrc}/${LINUX_VERSION}"
-
-elif  test -e "${splsrc}/spl_config.h" ; then :
-
-                               splbuild="${splsrc}"
-
-elif  find -L "${splsrc}" -name spl_config.h 2> /dev/null | grep -wq spl_config.h ; then :
-
-                               splbuild=$(find -L "${splsrc}" -name spl_config.h | sed 's,/spl_config.h,,')
-
-else
-
-                               splbuild="Not found"
-
-fi
-
-fi
-               if test -e "$splbuild/spl_config.h" -o $timeout -le 0; then :
-
-                       break;
-
-else
-
-                       sleep 1
-                       timeout=$((timeout-1))
-
-fi
-       done
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $splbuild" >&5
-$as_echo "$splbuild" >&6; }
-       if  ! test -e "$splbuild/spl_config.h"; then :
-
-               as_fn_error $? "
-       *** Please make sure the kmod spl devel <kernel> package for your
-       *** distribution is installed then try again.  If that fails you
-       *** can specify the location of the spl objects with the
-       *** '--with-spl-obj=PATH' option." "$LINENO" 5
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl source version" >&5
-$as_echo_n "checking spl source version... " >&6; }
-       if test -r $splbuild/spl_config.h &&
-               fgrep -q SPL_META_VERSION $splbuild/spl_config.h; then :
-
-
-               splsrcver=`(echo "#include <spl_config.h>";
-                           echo "splsrcver=SPL_META_VERSION-SPL_META_RELEASE") |
-                           cpp -I $splbuild |
-                           grep "^splsrcver=" | tr -d \" | cut -d= -f2`
-
-fi
-
-       if test -z "$splsrcver"; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not found" >&5
-$as_echo "Not found" >&6; }
-               as_fn_error $? "
-       *** Cannot determine the version of the spl source.
-       *** Please prepare the spl source before running this script" "$LINENO" 5
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $splsrcver" >&5
-$as_echo "$splsrcver" >&6; }
-
-       SPL=${splsrc}
-       SPL_OBJ=${splbuild}
-       SPL_VERSION=${splsrcver}
-
-
-
-
-
-                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking spl file name for module symbols" >&5
-$as_echo_n "checking spl file name for module symbols... " >&6; }
-       SPL_SYMBOLS=NONE
-
-       while true; do
-               if test -r $SPL_OBJ/Module.symvers; then :
-
-                       SPL_SYMBOLS=Module.symvers
-
-elif test -r $SPL_OBJ/Modules.symvers; then :
-
-                       SPL_SYMBOLS=Modules.symvers
-
-elif test -r $SPL_OBJ/module/Module.symvers; then :
-
-                       SPL_SYMBOLS=Module.symvers
-
-elif test -r $SPL_OBJ/module/Modules.symvers; then :
-
-                       SPL_SYMBOLS=Modules.symvers
-
-fi
-
-               if test $SPL_SYMBOLS != NONE -o $timeout -le 0; then :
-
-                       break;
-
-else
-
-                       sleep 1
-                       timeout=$((timeout-1))
-
-fi
-       done
-
-       if test "$SPL_SYMBOLS" = NONE; then :
-
-               SPL_SYMBOLS=$LINUX_SYMBOLS
-
-fi
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SPL_SYMBOLS" >&5
-$as_echo "$SPL_SYMBOLS" >&6; }
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether modules can be built" >&5
-$as_echo_n "checking whether modules can be built... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-int
-main (void)
-{
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               if test "x$enable_linux_builtin" != xyes; then
-                       as_fn_error $? "*** Unable to build an empty module." "$LINENO" 5
-               else
-                       as_fn_error $? "
-       *** Unable to build an empty module.
-       *** Please run 'make scripts' inside the kernel source tree." "$LINENO" 5
-               fi
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       if test "x$cross_compiling" != xyes; then :
-
-               if test "$cross_compiling" = yes; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-                               #include "$LINUX/include/linux/license.h"
-
-int
-main ()
-{
-
-                               return !license_is_gpl_compatible("$ZFS_META_LICENSE");
-
-  ;
-  return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-
-$as_echo "#define ZFS_IS_GPL_COMPATIBLE 1" >>confdefs.h
-
-
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-
-fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Linux was built with CONFIG_DEBUG_LOCK_ALLOC" >&5
-$as_echo_n "checking whether Linux was built with CONFIG_DEBUG_LOCK_ALLOC... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/module.h>
-
-int
-main (void)
-{
-
-               #ifndef CONFIG_DEBUG_LOCK_ALLOC
-               #error CONFIG_DEBUG_LOCK_ALLOC not #defined
-               #endif
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mutex_lock() is GPL-only" >&5
-$as_echo_n "checking whether mutex_lock() is GPL-only... " >&6; }
-               tmp_flags="$EXTRA_KCFLAGS"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/module.h>
-                       #include <linux/mutex.h>
-
-                       MODULE_LICENSE("$ZFS_META_LICENSE");
-
-int
-main (void)
-{
-
-                       struct mutex lock;
-
-                       mutex_init(&lock);
-                       mutex_lock(&lock);
-                       mutex_unlock(&lock);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-                       as_fn_error $? "
-       *** Kernel built with CONFIG_DEBUG_LOCK_ALLOC which is incompatible
-       *** with the CDDL license and will prevent the module linking stage
-       *** from succeeding.  You must rebuild your kernel without this
-       *** option enabled." "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-               EXTRA_KCFLAGS="$tmp_flags"
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="-I\$(src)"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether DECLARE_EVENT_CLASS() is available" >&5
-$as_echo_n "checking whether DECLARE_EVENT_CLASS() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/module.h>
-               MODULE_LICENSE(ZFS_META_LICENSE);
-
-               #define CREATE_TRACE_POINTS
-               #include "conftest.h"
-
-int
-main (void)
-{
-
-               trace_zfs_autoconf_event_one(1UL);
-               trace_zfs_autoconf_event_two(2UL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-               #if !defined(_CONFTEST_H) || defined(TRACE_HEADER_MULTI_READ)
-               #define _CONFTEST_H
-
-               #undef  TRACE_SYSTEM
-               #define TRACE_SYSTEM zfs
-               #include <linux/tracepoint.h>
-
-               DECLARE_EVENT_CLASS(zfs_autoconf_event_class,
-                       TP_PROTO(unsigned long i),
-                       TP_ARGS(i),
-                       TP_STRUCT__entry(
-                               __field(unsigned long, i)
-                       ),
-                       TP_fast_assign(
-                               __entry->i = i;
-                       ),
-                       TP_printk("i = %lu", __entry->i)
-               );
-
-               #define DEFINE_AUTOCONF_EVENT(name) \
-               DEFINE_EVENT(zfs_autoconf_event_class, name, \
-                       TP_PROTO(unsigned long i), \
-                       TP_ARGS(i))
-               DEFINE_AUTOCONF_EVENT(zfs_autoconf_event_one);
-               DEFINE_AUTOCONF_EVENT(zfs_autoconf_event_two);
-
-               #endif /* _CONFTEST_H */
-
-               #undef  TRACE_INCLUDE_PATH
-               #define TRACE_INCLUDE_PATH .
-               #define TRACE_INCLUDE_FILE conftest
-               #include <trace/define_trace.h>
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_DECLARE_EVENT_CLASS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether current->bio_tail exists" >&5
-$as_echo_n "checking whether current->bio_tail exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/sched.h>
-
-int
-main (void)
-{
-
-               current->bio_tail = (struct bio **) NULL;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CURRENT_BIO_TAIL 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether current->bio_list exists" >&5
-$as_echo_n "checking whether current->bio_list exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/sched.h>
-
-int
-main (void)
-{
-
-                       current->bio_list = (struct bio_list *) NULL;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CURRENT_BIO_LIST 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       as_fn_error $? "no - Please file a bug report at
-                           https://github.com/zfsonlinux/zfs/issues/new" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether submit_bio() wants 1 arg" >&5
-$as_echo_n "checking whether submit_bio() wants 1 arg... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               blk_qc_t blk_qc;
-               struct bio *bio = NULL;
-               blk_qc = submit_bio(bio);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_1ARG_SUBMIT_BIO 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking block device operation prototypes" >&5
-$as_echo_n "checking block device operation prototypes... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-               int blk_open(struct block_device *bdev, fmode_t mode)
-                   { return 0; }
-               int blk_ioctl(struct block_device *bdev, fmode_t mode,
-                   unsigned x, unsigned long y) { return 0; }
-               int blk_compat_ioctl(struct block_device * bdev, fmode_t mode,
-                   unsigned x, unsigned long y) { return 0; }
-
-               static const struct block_device_operations
-                   bops __attribute__ ((unused)) = {
-                       .open           = blk_open,
-                       .release        = NULL,
-                       .ioctl          = blk_ioctl,
-                       .compat_ioctl   = blk_compat_ioctl,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: struct block_device" >&5
-$as_echo "struct block_device" >&6; }
-
-$as_echo "#define HAVE_BDEV_BLOCK_DEVICE_OPERATIONS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: struct inode" >&5
-$as_echo "struct inode" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether block_device_operations.release is void" >&5
-$as_echo_n "checking whether block_device_operations.release is void... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-               void blk_release(struct gendisk *g, fmode_t mode) { return; }
-
-               static const struct block_device_operations
-                   bops __attribute__ ((unused)) = {
-                       .open           = NULL,
-                       .release        = blk_release,
-                       .ioctl          = NULL,
-                       .compat_ioctl   = NULL,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: void" >&5
-$as_echo "void" >&6; }
-
-$as_echo "#define HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: int" >&5
-$as_echo "int" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kernel defines fmode_t" >&5
-$as_echo_n "checking whether kernel defines fmode_t... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/types.h>
-
-int
-main (void)
-{
-
-               fmode_t *ptr __attribute__ ((unused));
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FMODE_T 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kernel defines KOBJ_NAME_LEN" >&5
-$as_echo_n "checking whether kernel defines KOBJ_NAME_LEN... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/kobject.h>
-
-int
-main (void)
-{
-
-               int val __attribute__ ((unused));
-               val = KOBJ_NAME_LEN;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_KOBJ_NAME_LEN 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blkdev_get() wants 3 args" >&5
-$as_echo_n "checking whether blkdev_get() wants 3 args... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct block_device *bdev = NULL;
-               (void) blkdev_get(bdev, 0, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_3ARG_BLKDEV_GET 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blkdev_get_by_path() is available" >&5
-$as_echo_n "checking whether blkdev_get_by_path() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               blkdev_get_by_path(NULL, 0, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]blkdev_get_by_path[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/block_dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(blkdev_get_by_path)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLKDEV_GET_BY_PATH 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether open_bdev_exclusive() is available" >&5
-$as_echo_n "checking whether open_bdev_exclusive() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               open_bdev_exclusive(NULL, 0, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]open_bdev_exclusive[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/block_dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(open_bdev_exclusive)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_OPEN_BDEV_EXCLUSIVE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lookup_bdev() is available" >&5
-$as_echo_n "checking whether lookup_bdev() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               lookup_bdev(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]lookup_bdev[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/block_dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(lookup_bdev)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_LOOKUP_BDEV 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether invalidate_bdev() wants 1 arg" >&5
-$as_echo_n "checking whether invalidate_bdev() wants 1 arg... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/buffer_head.h>
-
-int
-main (void)
-{
-
-               struct block_device *bdev = NULL;
-               invalidate_bdev(bdev);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_1ARG_INVALIDATE_BDEV 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdev_logical_block_size() is available" >&5
-$as_echo_n "checking whether bdev_logical_block_size() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct block_device *bdev = NULL;
-               bdev_logical_block_size(bdev);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BDEV_LOGICAL_BLOCK_SIZE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdev_physical_block_size() is available" >&5
-$as_echo_n "checking whether bdev_physical_block_size() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct block_device *bdev = NULL;
-               bdev_physical_block_size(bdev);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BDEV_PHYSICAL_BLOCK_SIZE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bio has bi_iter" >&5
-$as_echo_n "checking whether bio has bi_iter... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               struct bio bio;
-               bio.bi_iter.bi_sector = 0;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_BVEC_ITER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether BIO_RW_FAILFAST_* are defined" >&5
-$as_echo_n "checking whether BIO_RW_FAILFAST_* are defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               int flags __attribute__ ((unused));
-               flags = ((1 << BIO_RW_FAILFAST_DEV) |
-                        (1 << BIO_RW_FAILFAST_TRANSPORT) |
-                        (1 << BIO_RW_FAILFAST_DRIVER));
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_RW_FAILFAST_DTD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether REQ_FAILFAST_MASK is defined" >&5
-$as_echo_n "checking whether REQ_FAILFAST_MASK is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               int flags __attribute__ ((unused));
-               flags = REQ_FAILFAST_MASK;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_REQ_FAILFAST_MASK 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether REQ_OP_DISCARD is defined" >&5
-$as_echo_n "checking whether REQ_OP_DISCARD is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blk_types.h>
-
-int
-main (void)
-{
-
-               enum req_op op __attribute__ ((unused)) = REQ_OP_DISCARD;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_REQ_OP_DISCARD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether REQ_OP_SECURE_ERASE is defined" >&5
-$as_echo_n "checking whether REQ_OP_SECURE_ERASE is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blk_types.h>
-
-int
-main (void)
-{
-
-               enum req_op op __attribute__ ((unused)) = REQ_OP_SECURE_ERASE;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_REQ_OP_SECURE_DISCARD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether REQ_OP_FLUSH is defined" >&5
-$as_echo_n "checking whether REQ_OP_FLUSH is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blk_types.h>
-
-int
-main (void)
-{
-
-               enum req_op op __attribute__ ((unused)) = REQ_OP_FLUSH;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_REQ_OP_FLUSH 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bio->bi_opf is defined" >&5
-$as_echo_n "checking whether bio->bi_opf is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               struct bio bio __attribute__ ((unused));
-               bio.bi_opf = 0;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_BI_OPF 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bio_end_io_t wants 1 arg" >&5
-$as_echo_n "checking whether bio_end_io_t wants 1 arg... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-               void wanted_end_io(struct bio *bio) { return; }
-
-               bio_end_io_t *end_io __attribute__ ((unused)) = wanted_end_io;
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_1ARG_BIO_END_IO_T 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether BIO_RW_BARRIER is defined" >&5
-$as_echo_n "checking whether BIO_RW_BARRIER is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               int flags __attribute__ ((unused));
-               flags = BIO_RW_BARRIER;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_RW_BARRIER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether BIO_RW_DISCARD is defined" >&5
-$as_echo_n "checking whether BIO_RW_DISCARD is defined... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-int
-main (void)
-{
-
-               int flags __attribute__ ((unused));
-               flags = BIO_RW_DISCARD;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BIO_RW_DISCARD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_flush() is available" >&5
-$as_echo_n "checking whether blk_queue_flush() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct request_queue *q = NULL;
-               (void) blk_queue_flush(q, REQ_FLUSH);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_FLUSH 1" >>confdefs.h
-
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_flush() is GPL-only" >&5
-$as_echo_n "checking whether blk_queue_flush() is GPL-only... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/module.h>
-                       #include <linux/blkdev.h>
-
-                       MODULE_LICENSE("$ZFS_META_LICENSE");
-
-int
-main (void)
-{
-
-                       struct request_queue *q = NULL;
-                       (void) blk_queue_flush(q, REQ_FLUSH);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_FLUSH_GPL_ONLY 1" >>confdefs.h
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_write_cache() exists" >&5
-$as_echo_n "checking whether blk_queue_write_cache() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/kernel.h>
-               #include <linux/blkdev.h>
-
-
-int
-main (void)
-{
-
-               struct request_queue *q = NULL;
-               blk_queue_write_cache(q, true, true);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_WRITE_CACHE 1" >>confdefs.h
-
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_write_cache() is GPL-only" >&5
-$as_echo_n "checking whether blk_queue_write_cache() is GPL-only... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/kernel.h>
-                       #include <linux/module.h>
-                       #include <linux/blkdev.h>
-
-                       MODULE_LICENSE("$ZFS_META_LICENSE");
-
-int
-main (void)
-{
-
-                       struct request_queue *q = NULL;
-                       blk_queue_write_cache(q, true, true);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_WRITE_CACHE_GPL_ONLY 1" >>confdefs.h
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_max_hw_sectors() is available" >&5
-$as_echo_n "checking whether blk_queue_max_hw_sectors() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct request_queue *q = NULL;
-               (void) blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_MAX_HW_SECTORS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether blk_queue_max_segments() is available" >&5
-$as_echo_n "checking whether blk_queue_max_segments() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct request_queue *q = NULL;
-               (void) blk_queue_max_segments(q, BLK_MAX_SEGMENTS);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_BLK_QUEUE_MAX_SEGMENTS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether get_disk_ro() is available" >&5
-$as_echo_n "checking whether get_disk_ro() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct gendisk *disk = NULL;
-               (void) get_disk_ro(disk);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_DISK_RO 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether get_gendisk() is available" >&5
-$as_echo_n "checking whether get_gendisk() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/genhd.h>
-
-int
-main (void)
-{
-
-               get_gendisk(0, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]get_gendisk[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in block/genhd.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(get_gendisk)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_GENDISK 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ql->discard_granularity is available" >&5
-$as_echo_n "checking whether ql->discard_granularity is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-int
-main (void)
-{
-
-               struct queue_limits ql __attribute__ ((unused));
-
-               ql.discard_granularity = 0;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_DISCARD_GRANULARITY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether super_block uses const struct xattr_handler" >&5
-$as_echo_n "checking whether super_block uses const struct xattr_handler... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/xattr.h>
-
-               const struct xattr_handler xattr_test_handler = {
-                       .prefix = "test",
-                       .get    = NULL,
-                       .set    = NULL,
-               };
-
-               const struct xattr_handler *xattr_handlers[] = {
-                       &xattr_test_handler,
-               };
-
-               const struct super_block sb __attribute__ ((unused)) = {
-                       .s_xattr = xattr_handlers,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CONST_XATTR_HANDLER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler has name" >&5
-$as_echo_n "checking whether xattr_handler has name... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/xattr.h>
-
-               static const struct xattr_handler
-                   xops __attribute__ ((unused)) = {
-                       .name = XATTR_NAME_POSIX_ACL_ACCESS,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_HANDLER_NAME 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->get() wants both dentry and inode" >&5
-$as_echo_n "checking whether xattr_handler->get() wants both dentry and inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/xattr.h>
-
-               int get(const struct xattr_handler *handler,
-                   struct dentry *dentry, struct inode *inode,
-                   const char *name, void *buffer, size_t size) { return 0; }
-               static const struct xattr_handler
-                   xops __attribute__ ((unused)) = {
-                       .get = get,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_GET_DENTRY_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->get() wants xattr_handler" >&5
-$as_echo_n "checking whether xattr_handler->get() wants xattr_handler... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/xattr.h>
-
-                       int get(const struct xattr_handler *handler,
-                           struct dentry *dentry, const char *name,
-                           void *buffer, size_t size) { return 0; }
-                       static const struct xattr_handler
-                           xops __attribute__ ((unused)) = {
-                               .get = get,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_GET_HANDLER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                                                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->get() wants dentry" >&5
-$as_echo_n "checking whether xattr_handler->get() wants dentry... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/xattr.h>
-
-                               int get(struct dentry *dentry, const char *name,
-                                   void *buffer, size_t size, int handler_flags)
-                                   { return 0; }
-                               static const struct xattr_handler
-                                   xops __attribute__ ((unused)) = {
-                                       .get = get,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_GET_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->get() wants inode" >&5
-$as_echo_n "checking whether xattr_handler->get() wants inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                                       #include <linux/xattr.h>
-
-                                       int get(struct inode *ip, const char *name,
-                                           void *buffer, size_t size) { return 0; }
-                                       static const struct xattr_handler
-                                           xops __attribute__ ((unused)) = {
-                                               .get = get,
-                                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_GET_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                       as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->set() wants both dentry and inode" >&5
-$as_echo_n "checking whether xattr_handler->set() wants both dentry and inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/xattr.h>
-
-               int set(const struct xattr_handler *handler,
-                   struct dentry *dentry, struct inode *inode,
-                   const char *name, const void *buffer,
-                   size_t size, int flags)
-                   { return 0; }
-               static const struct xattr_handler
-                   xops __attribute__ ((unused)) = {
-                       .set = set,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_SET_DENTRY_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->set() wants xattr_handler" >&5
-$as_echo_n "checking whether xattr_handler->set() wants xattr_handler... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/xattr.h>
-
-                       int set(const struct xattr_handler *handler,
-                           struct dentry *dentry, const char *name,
-                           const void *buffer, size_t size, int flags)
-                           { return 0; }
-                       static const struct xattr_handler
-                           xops __attribute__ ((unused)) = {
-                               .set = set,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_SET_HANDLER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                                                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->set() wants dentry" >&5
-$as_echo_n "checking whether xattr_handler->set() wants dentry... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/xattr.h>
-
-                               int set(struct dentry *dentry, const char *name,
-                                   const void *buffer, size_t size, int flags,
-                                   int handler_flags) { return 0; }
-                               static const struct xattr_handler
-                                   xops __attribute__ ((unused)) = {
-                                       .set = set,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_SET_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->set() wants inode" >&5
-$as_echo_n "checking whether xattr_handler->set() wants inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                                       #include <linux/xattr.h>
-
-                                       int set(struct inode *ip, const char *name,
-                                           const void *buffer, size_t size, int flags)
-                                           { return 0; }
-                                       static const struct xattr_handler
-                                           xops __attribute__ ((unused)) = {
-                                               .set = set,
-                                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_SET_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                       as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->list() wants simple" >&5
-$as_echo_n "checking whether xattr_handler->list() wants simple... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/xattr.h>
-
-               bool list(struct dentry *dentry) { return 0; }
-               static const struct xattr_handler
-                   xops __attribute__ ((unused)) = {
-                       .list = list,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_LIST_SIMPLE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->list() wants xattr_handler" >&5
-$as_echo_n "checking whether xattr_handler->list() wants xattr_handler... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/xattr.h>
-
-                       size_t list(const struct xattr_handler *handler,
-                           struct dentry *dentry, char *list, size_t list_size,
-                           const char *name, size_t name_len) { return 0; }
-                       static const struct xattr_handler
-                           xops __attribute__ ((unused)) = {
-                               .list = list,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_LIST_HANDLER 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                                                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->list() wants dentry" >&5
-$as_echo_n "checking whether xattr_handler->list() wants dentry... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/xattr.h>
-
-                               size_t list(struct dentry *dentry,
-                                   char *list, size_t list_size,
-                                   const char *name, size_t name_len,
-                                   int handler_flags) { return 0; }
-                               static const struct xattr_handler
-                                   xops __attribute__ ((unused)) = {
-                                       .list = list,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_LIST_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether xattr_handler->list() wants inode" >&5
-$as_echo_n "checking whether xattr_handler->list() wants inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                                       #include <linux/xattr.h>
-
-                                       size_t list(struct inode *ip, char *lst,
-                                           size_t list_size, const char *name,
-                                           size_t name_len) { return 0; }
-                                       static const struct xattr_handler
-                                           xops __attribute__ ((unused)) = {
-                                               .list = list,
-                                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_XATTR_LIST_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                       as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether inode_owner_or_capable() exists" >&5
-$as_echo_n "checking whether inode_owner_or_capable() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct inode *ip = NULL;
-               (void) inode_owner_or_capable(ip);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_INODE_OWNER_OR_CAPABLE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether is_owner_or_cap() exists" >&5
-$as_echo_n "checking whether is_owner_or_cap() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/fs.h>
-                       #include <linux/sched.h>
-
-int
-main (void)
-{
-
-                       struct inode *ip = NULL;
-                       (void) is_owner_or_cap(ip);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_IS_OWNER_OR_CAP 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       as_fn_error $? "no - Please file a bug report at
-                           https://github.com/zfsonlinux/zfs/issues/new" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_from_xattr() needs user_ns" >&5
-$as_echo_n "checking whether posix_acl_from_xattr() needs user_ns... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/cred.h>
-               #include <linux/fs.h>
-               #include <linux/posix_acl_xattr.h>
-
-int
-main (void)
-{
-
-               posix_acl_from_xattr(&init_user_ns, NULL, 0);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_FROM_XATTR_USERNS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_release() is available" >&5
-$as_echo_n "checking whether posix_acl_release() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/cred.h>
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               struct posix_acl* tmp = posix_acl_alloc(1, 0);
-               posix_acl_release(tmp);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_RELEASE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_release() is GPL-only" >&5
-$as_echo_n "checking whether posix_acl_release() is GPL-only... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/cred.h>
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-               MODULE_LICENSE("$ZFS_META_LICENSE");
-
-int
-main (void)
-{
-
-               struct posix_acl* tmp = posix_acl_alloc(1, 0);
-               posix_acl_release(tmp);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_RELEASE_GPL_ONLY 1" >>confdefs.h
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_chmod exists" >&5
-$as_echo_n "checking whether posix_acl_chmod exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               posix_acl_chmod(NULL, 0, 0)
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_CHMOD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether __posix_acl_chmod exists" >&5
-$as_echo_n "checking whether __posix_acl_chmod exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               __posix_acl_chmod(NULL, 0, 0)
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE___POSIX_ACL_CHMOD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_equiv_mode() wants umode_t" >&5
-$as_echo_n "checking whether posix_acl_equiv_mode() wants umode_t... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               umode_t tmp;
-               posix_acl_equiv_mode(NULL,&tmp);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_EQUIV_MODE_UMODE_T 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether posix_acl_valid() wants user namespace" >&5
-$as_echo_n "checking whether posix_acl_valid() wants user namespace... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               #include <linux/posix_acl.h>
-
-int
-main (void)
-{
-
-               struct user_namespace *user_ns = NULL;
-               const struct posix_acl *acl = NULL;
-               int error;
-
-               error = posix_acl_valid(user_ns, acl);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_POSIX_ACL_VALID_WITH_NS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->permission() exists" >&5
-$as_echo_n "checking whether iops->permission() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int permission_fn(struct inode *inode, int mask) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .permission = permission_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PERMISSION 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->permission() wants nameidata" >&5
-$as_echo_n "checking whether iops->permission() wants nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int permission_fn(struct inode *inode, int mask,
-                   struct nameidata *nd) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .permission = permission_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PERMISSION 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_PERMISSION_WITH_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->check_acl() exists" >&5
-$as_echo_n "checking whether iops->check_acl() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int check_acl_fn(struct inode *inode, int mask) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .check_acl = check_acl_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CHECK_ACL 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->check_acl() wants flags" >&5
-$as_echo_n "checking whether iops->check_acl() wants flags... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int check_acl_fn(struct inode *inode, int mask,
-                   unsigned int flags) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .check_acl = check_acl_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CHECK_ACL 1" >>confdefs.h
-
-
-$as_echo "#define HAVE_CHECK_ACL_WITH_FLAGS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->get_acl() exists" >&5
-$as_echo_n "checking whether iops->get_acl() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               struct posix_acl *get_acl_fn(struct inode *inode, int type)
-                   { return NULL; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .get_acl = get_acl_fn,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_ACL 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether uncached_acl_sentinel() exists" >&5
-$as_echo_n "checking whether uncached_acl_sentinel() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               void *sentinel __attribute__ ((unused)) = uncached_acl_sentinel(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_KERNEL_GET_ACL_HANDLE_CACHE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->show_options() wants dentry" >&5
-$as_echo_n "checking whether sops->show_options() wants dentry... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int show_options (struct seq_file * x, struct dentry * y) { return 0; };
-               static struct super_operations sops __attribute__ ((unused)) = {
-                       .show_options = show_options,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_SHOW_OPTIONS_WITH_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether file_inode() is available" >&5
-$as_echo_n "checking whether file_inode() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct file *f = NULL;
-               file_inode(f);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FILE_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->fsync() wants" >&5
-$as_echo_n "checking whether fops->fsync() wants... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int test_fsync(struct file *f, struct dentry *dentry, int x)
-                   { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                       .fsync = test_fsync,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: dentry" >&5
-$as_echo "dentry" >&6; }
-
-$as_echo "#define HAVE_FSYNC_WITH_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int test_fsync(struct file *f, int x) { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                       .fsync = test_fsync,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no dentry" >&5
-$as_echo "no dentry" >&6; }
-
-$as_echo "#define HAVE_FSYNC_WITHOUT_DENTRY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int test_fsync(struct file *f, loff_t a, loff_t b, int c)
-                   { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                       .fsync = test_fsync,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: range" >&5
-$as_echo "range" >&6; }
-
-$as_echo "#define HAVE_FSYNC_RANGE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->evict_inode() exists" >&5
-$as_echo_n "checking whether sops->evict_inode() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               void evict_inode (struct inode * t) { return; }
-               static struct super_operations sops __attribute__ ((unused)) = {
-                       .evict_inode = evict_inode,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_EVICT_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->dirty_inode() wants flags" >&5
-$as_echo_n "checking whether sops->dirty_inode() wants flags... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               void dirty_inode(struct inode *a, int b) { return; }
-
-               static const struct super_operations
-                   sops __attribute__ ((unused)) = {
-                       .dirty_inode = dirty_inode,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_DIRTY_INODE_WITH_FLAGS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->nr_cached_objects() exists" >&5
-$as_echo_n "checking whether sops->nr_cached_objects() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int nr_cached_objects(struct super_block *sb) { return 0; }
-
-               static const struct super_operations
-                   sops __attribute__ ((unused)) = {
-                       .nr_cached_objects = nr_cached_objects,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_NR_CACHED_OBJECTS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sops->free_cached_objects() exists" >&5
-$as_echo_n "checking whether sops->free_cached_objects() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               void free_cached_objects(struct super_block *sb, int x)
-                   { return; }
-
-               static const struct super_operations
-                   sops __attribute__ ((unused)) = {
-                       .free_cached_objects = free_cached_objects,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FREE_CACHED_OBJECTS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->fallocate() exists" >&5
-$as_echo_n "checking whether fops->fallocate() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               long test_fallocate(struct file *file, int mode,
-                   loff_t offset, loff_t len) { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                       .fallocate = test_fallocate,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FILE_FALLOCATE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->fallocate() exists" >&5
-$as_echo_n "checking whether iops->fallocate() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               long test_fallocate(struct inode *inode, int mode,
-                   loff_t offset, loff_t len) { return 0; }
-
-               static const struct inode_operations
-                   fops __attribute__ ((unused)) = {
-                       .fallocate = test_fallocate,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_INODE_FALLOCATE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->create()/mkdir()/mknod() take umode_t" >&5
-$as_echo_n "checking whether iops->create()/mkdir()/mknod() take umode_t... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int mkdir(struct inode *inode, struct dentry *dentry,
-                   umode_t umode) { return 0; }
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .mkdir = mkdir,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_MKDIR_UMODE_T 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->lookup() passes nameidata" >&5
-$as_echo_n "checking whether iops->lookup() passes nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               struct dentry *inode_lookup(struct inode *inode,
-                   struct dentry *dentry, struct nameidata *nidata)
-                   { return NULL; }
-
-               static const struct inode_operations iops
-                   __attribute__ ((unused)) = {
-                       .lookup = inode_lookup,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_LOOKUP_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->create() passes nameidata" >&5
-$as_echo_n "checking whether iops->create() passes nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               #ifdef HAVE_MKDIR_UMODE_T
-               int inode_create(struct inode *inode ,struct dentry *dentry,
-                   umode_t umode, struct nameidata *nidata) { return 0; }
-               #else
-               int inode_create(struct inode *inode,struct dentry *dentry,
-                   int umode, struct nameidata * nidata) { return 0; }
-               #endif
-
-               static const struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .create         = inode_create,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CREATE_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->get_link() passes delayed" >&5
-$as_echo_n "checking whether iops->get_link() passes delayed... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               const char *get_link(struct dentry *de, struct inode *ip,
-                   struct delayed_call *done) { return "symlink"; }
-               static struct inode_operations
-                    iops __attribute__ ((unused)) = {
-                       .get_link = get_link,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_LINK_DELAYED 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->get_link() passes cookie" >&5
-$as_echo_n "checking whether iops->get_link() passes cookie... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/fs.h>
-                       const char *get_link(struct dentry *de, struct
-                           inode *ip, void **cookie) { return "symlink"; }
-                       static struct inode_operations
-                            iops __attribute__ ((unused)) = {
-                               .get_link = get_link,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GET_LINK_COOKIE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-                                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->follow_link() passes cookie" >&5
-$as_echo_n "checking whether iops->follow_link() passes cookie... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               const char *follow_link(struct dentry *de,
-                   void **cookie) { return "symlink"; }
-               static struct inode_operations
-                   iops __attribute__ ((unused)) = {
-                       .follow_link = follow_link,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FOLLOW_LINK_COOKIE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->follow_link() passes nameidata" >&5
-$as_echo_n "checking whether iops->follow_link() passes nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-                       void *follow_link(struct dentry *de, struct
-                           nameidata *nd) { return (void *)NULL; }
-                       static struct inode_operations
-                           iops __attribute__ ((unused)) = {
-                               .follow_link = follow_link,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FOLLOW_LINK_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                        as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #if !defined(HAVE_GET_LINK_DELAYED)
-               #error "Expecting get_link() delayed done"
-               #endif
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-
-$as_echo "#define HAVE_PUT_LINK_DELAYED 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->put_link() passes cookie" >&5
-$as_echo_n "checking whether iops->put_link() passes cookie... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/fs.h>
-                       void put_link(struct inode *ip, void *cookie)
-                           { return; }
-                       static struct inode_operations
-                           iops __attribute__ ((unused)) = {
-                               .put_link = put_link,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PUT_LINK_COOKIE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                                                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->put_link() passes nameidata" >&5
-$as_echo_n "checking whether iops->put_link() passes nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/fs.h>
-                               void put_link(struct dentry *de, struct
-                                   nameidata *nd, void *ptr) { return; }
-                               static struct inode_operations
-                                   iops __attribute__ ((unused)) = {
-                                       .put_link = put_link,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_PUT_LINK_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                               as_fn_error $? "no; please file a bug report" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether iops->truncate_range() exists" >&5
-$as_echo_n "checking whether iops->truncate_range() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               void truncate_range(struct inode *inode, loff_t start,
-                                   loff_t end) { return; }
-               static struct inode_operations iops __attribute__ ((unused)) = {
-                       .truncate_range = truncate_range,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_INODE_TRUNCATE_RANGE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dops->d_automount() exists" >&5
-$as_echo_n "checking whether dops->d_automount() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-               struct vfsmount *d_automount(struct path *p) { return NULL; }
-               struct dentry_operations dops __attribute__ ((unused)) = {
-                       .d_automount = d_automount,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_AUTOMOUNT 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether eops->encode_fh() wants inode" >&5
-$as_echo_n "checking whether eops->encode_fh() wants inode... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/exportfs.h>
-               int encode_fh(struct inode *inode, __u32 *fh, int *max_len,
-                             struct inode *parent) { return 0; }
-               static struct export_operations eops __attribute__ ((unused))={
-                       .encode_fh = encode_fh,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_ENCODE_FH_WITH_INODE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether eops->commit_metadata() exists" >&5
-$as_echo_n "checking whether eops->commit_metadata() exists... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/exportfs.h>
-               int commit_metadata(struct inode *inode) { return 0; }
-               static struct export_operations eops __attribute__ ((unused))={
-                       .commit_metadata = commit_metadata,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_COMMIT_METADATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether clear_inode() is available" >&5
-$as_echo_n "checking whether clear_inode() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               clear_inode(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]clear_inode[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/inode.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(clear_inode)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CLEAR_INODE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether insert_inode_locked() is available" >&5
-$as_echo_n "checking whether insert_inode_locked() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               insert_inode_locked(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]insert_inode_locked[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/inode.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(insert_inode_locked)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_INSERT_INODE_LOCKED 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether d_make_root() is available" >&5
-$as_echo_n "checking whether d_make_root() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-int
-main (void)
-{
-
-               d_make_root(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]d_make_root[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/dcache.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(d_make_root)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_MAKE_ROOT 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether d_obtain_alias() is available" >&5
-$as_echo_n "checking whether d_obtain_alias() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-int
-main (void)
-{
-
-               d_obtain_alias(NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]d_obtain_alias[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/dcache.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(d_obtain_alias)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_OBTAIN_ALIAS 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether d_prune_aliases() is available" >&5
-$as_echo_n "checking whether d_prune_aliases() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-int
-main (void)
-{
-
-               struct inode *ip = NULL;
-               d_prune_aliases(ip);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]d_prune_aliases[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/dcache.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(d_prune_aliases)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_PRUNE_ALIASES 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether d_set_d_op() is available" >&5
-$as_echo_n "checking whether d_set_d_op() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-int
-main (void)
-{
-
-               d_set_d_op(NULL, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]d_set_d_op[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/dcache.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(d_set_d_op)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_SET_D_OP 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dops->d_revalidate() takes struct nameidata" >&5
-$as_echo_n "checking whether dops->d_revalidate() takes struct nameidata... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-               int revalidate (struct dentry *dentry,
-                   struct nameidata *nidata) { return 0; }
-
-               static const struct dentry_operations
-                   dops __attribute__ ((unused)) = {
-                       .d_revalidate   = revalidate,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_D_REVALIDATE_NAMEIDATA 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dentry uses const struct dentry_operations" >&5
-$as_echo_n "checking whether dentry uses const struct dentry_operations... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/dcache.h>
-
-               const struct dentry_operations test_d_op = {
-                       .d_revalidate = NULL,
-               };
-
-int
-main (void)
-{
-
-               struct dentry d __attribute__ ((unused));
-
-               d.d_op = &test_d_op;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CONST_DENTRY_OPERATIONS 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether check_disk_size_change() is available" >&5
-$as_echo_n "checking whether check_disk_size_change() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               check_disk_size_change(NULL, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]check_disk_size_change[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/block_dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(check_disk_size_change)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CHECK_DISK_SIZE_CHANGE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether truncate_setsize() is available" >&5
-$as_echo_n "checking whether truncate_setsize() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/mm.h>
-
-int
-main (void)
-{
-
-               truncate_setsize(NULL, 0);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]truncate_setsize[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in mm/truncate.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(truncate_setsize)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_TRUNCATE_SETSIZE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether security_inode_init_security wants 6 args" >&5
-$as_echo_n "checking whether security_inode_init_security wants 6 args... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/security.h>
-
-int
-main (void)
-{
-
-               struct inode *ip __attribute__ ((unused)) = NULL;
-               struct inode *dip __attribute__ ((unused)) = NULL;
-               const struct qstr *str __attribute__ ((unused)) = NULL;
-               char *name __attribute__ ((unused)) = NULL;
-               void *value __attribute__ ((unused)) = NULL;
-               size_t len __attribute__ ((unused)) = 0;
-
-               security_inode_init_security(ip, dip, str, &name, &value, &len);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_6ARGS_SECURITY_INODE_INIT_SECURITY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether security_inode_init_security wants callback" >&5
-$as_echo_n "checking whether security_inode_init_security wants callback... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/security.h>
-
-int
-main (void)
-{
-
-               struct inode *ip __attribute__ ((unused)) = NULL;
-               struct inode *dip __attribute__ ((unused)) = NULL;
-               const struct qstr *str __attribute__ ((unused)) = NULL;
-               initxattrs func __attribute__ ((unused)) = NULL;
-
-               security_inode_init_security(ip, dip, str, func, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mount_nodev() is available" >&5
-$as_echo_n "checking whether mount_nodev() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               mount_nodev(NULL, 0, NULL, NULL);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]mount_nodev[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/super.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(mount_nodev)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_MOUNT_NODEV 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether super_block has s_shrink" >&5
-$as_echo_n "checking whether super_block has s_shrink... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               int shrink(struct shrinker *s, struct shrink_control *sc)
-                   { return 0; }
-
-               static const struct super_block
-                   sb __attribute__ ((unused)) = {
-                       .s_shrink.shrink = shrink,
-                       .s_shrink.seeks = DEFAULT_SEEKS,
-                       .s_shrink.batch = 0,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_SHRINK 1" >>confdefs.h
-
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether shrink_control has nid" >&5
-$as_echo_n "checking whether shrink_control has nid... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct shrink_control sc __attribute__ ((unused));
-               unsigned long scnidsize __attribute__ ((unused)) =
-                   sizeof(sc.nid);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define SHRINK_CONTROL_HAS_NID 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether super_block has s_instances list_head" >&5
-$as_echo_n "checking whether super_block has s_instances list_head... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct super_block sb __attribute__ ((unused));
-
-               INIT_LIST_HEAD(&sb.s_instances);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_S_INSTANCES_LIST_HEAD 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether super_block has s_d_op" >&5
-$as_echo_n "checking whether super_block has s_d_op... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct super_block sb __attribute__ ((unused));
-               sb.s_d_op = NULL;
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_S_D_OP 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdi_setup_and_register() wants 2 args" >&5
-$as_echo_n "checking whether bdi_setup_and_register() wants 2 args... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/backing-dev.h>
-               struct backing_dev_info bdi;
-
-int
-main (void)
-{
-
-               char *name = "bdi";
-               int error __attribute__((unused)) =
-                   bdi_setup_and_register(&bdi, name);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdi_setup_and_register() wants 3 args" >&5
-$as_echo_n "checking whether bdi_setup_and_register() wants 3 args... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/backing-dev.h>
-                       struct backing_dev_info bdi;
-
-int
-main (void)
-{
-
-                       char *name = "bdi";
-                       unsigned int cap = BDI_CAP_MAP_COPY;
-                       int error __attribute__((unused)) =
-                           bdi_setup_and_register(&bdi, name, cap);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]bdi_setup_and_register[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in mm/backing-dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(bdi_setup_and_register)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_3ARGS_BDI_SETUP_AND_REGISTER 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]bdi_setup_and_register[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in mm/backing-dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(bdi_setup_and_register)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether bdi_setup_and_register() wants 3 args" >&5
-$as_echo_n "checking whether bdi_setup_and_register() wants 3 args... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/backing-dev.h>
-                       struct backing_dev_info bdi;
-
-int
-main (void)
-{
-
-                       char *name = "bdi";
-                       unsigned int cap = BDI_CAP_MAP_COPY;
-                       int error __attribute__((unused)) =
-                           bdi_setup_and_register(&bdi, name, cap);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]bdi_setup_and_register[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in mm/backing-dev.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(bdi_setup_and_register)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_3ARGS_BDI_SETUP_AND_REGISTER 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_2ARGS_BDI_SETUP_AND_REGISTER 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether set_nlink() is available" >&5
-$as_echo_n "checking whether set_nlink() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct inode node;
-               unsigned int link = 0;
-               (void) set_nlink(&node, link);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_SET_NLINK 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether elevator_change() is available" >&5
-$as_echo_n "checking whether elevator_change() is available... " >&6; }
-       tmp_flags="$EXTRA_KCFLAGS"
-       EXTRA_KCFLAGS="${NO_UNUSED_BUT_SET_VARIABLE}"
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-               #include <linux/elevator.h>
-
-int
-main (void)
-{
-
-               int ret;
-               struct request_queue *q = NULL;
-               char *elevator = NULL;
-               ret = elevator_change(q, elevator);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_ELEVATOR_CHANGE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-       EXTRA_KCFLAGS="$tmp_flags"
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sget() wants 5 args" >&5
-$as_echo_n "checking whether sget() wants 5 args... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct file_system_type *type = NULL;
-               int (*test)(struct super_block *,void *) = NULL;
-               int (*set)(struct super_block *,void *) = NULL;
-               int flags = 0;
-               void *data = NULL;
-               (void) sget(type, test, set, flags, data);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_5ARG_SGET 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lseek_execute() is available" >&5
-$as_echo_n "checking whether lseek_execute() is available... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-int
-main (void)
-{
-
-               struct file *fp __attribute__ ((unused)) = NULL;
-               struct inode *ip __attribute__ ((unused)) = NULL;
-               loff_t offset __attribute__ ((unused)) = 0;
-               loff_t maxsize __attribute__ ((unused)) = 0;
-
-               lseek_execute(fp, ip, offset, maxsize);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]lseek_exclusive[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in fs/read_write.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(lseek_exclusive)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_LSEEK_EXECUTE 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->iterate_shared() is available" >&5
-$as_echo_n "checking whether fops->iterate_shared() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-               int iterate(struct file *filp, struct dir_context * context)
-                   { return 0; }
-
-               static const struct file_operations fops
-                   __attribute__ ((unused)) = {
-                       .iterate_shared  = iterate,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_VFS_ITERATE_SHARED 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-                                                               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->iterate() is available" >&5
-$as_echo_n "checking whether fops->iterate() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/fs.h>
-                       int iterate(struct file *filp, struct dir_context * context)
-                           { return 0; }
-
-                       static const struct file_operations fops
-                           __attribute__ ((unused)) = {
-                               .iterate         = iterate,
-                       };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_VFS_ITERATE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->readdir() is available" >&5
-$as_echo_n "checking whether fops->readdir() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/fs.h>
-                               int readdir(struct file *filp, void *entry, filldir_t func)
-                                   { return 0; }
-
-                               static const struct file_operations fops
-                                   __attribute__ ((unused)) = {
-                                       .readdir = readdir,
-                               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_VFS_READDIR 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                               as_fn_error $? "no; file a bug report with ZFSOnLinux" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether fops->read/write_iter() are available" >&5
-$as_echo_n "checking whether fops->read/write_iter() are available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/fs.h>
-
-               ssize_t test_read(struct kiocb *kiocb, struct iov_iter *to)
-                   { return 0; }
-               ssize_t test_write(struct kiocb *kiocb, struct iov_iter *from)
-                   { return 0; }
-
-               static const struct file_operations
-                   fops __attribute__ ((unused)) = {
-                   .read_iter = test_read,
-                   .write_iter = test_write,
-               };
-
-int
-main (void)
-{
-
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_VFS_RW_ITERATE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether kmap_atomic wants 1 args" >&5
-$as_echo_n "checking whether kmap_atomic wants 1 args... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/pagemap.h>
-
-int
-main (void)
-{
-
-               struct page page;
-               kmap_atomic(&page);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_1ARG_KMAP_ATOMIC 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether follow_down_one() is available" >&5
-$as_echo_n "checking whether follow_down_one() is available... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/namei.h>
-
-int
-main (void)
-{
-
-               struct path *p = NULL;
-               follow_down_one(p);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_FOLLOW_DOWN_ONE 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether make_request_fn() returns int" >&5
-$as_echo_n "checking whether make_request_fn() returns int... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/blkdev.h>
-
-               int make_request(struct request_queue *q, struct bio *bio)
-               {
-                       return (0);
-               }
-
-int
-main (void)
-{
-
-               blk_queue_make_request(NULL, &make_request);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define MAKE_REQUEST_FN_RET int" >>confdefs.h
-
-
-$as_echo "#define HAVE_MAKE_REQUEST_FN_RET_INT 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether make_request_fn() returns void" >&5
-$as_echo_n "checking whether make_request_fn() returns void... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                       #include <linux/blkdev.h>
-
-                       void make_request(struct request_queue *q, struct bio *bio)
-                       {
-                               return;
-                       }
-
-int
-main (void)
-{
-
-                       blk_queue_make_request(NULL, &make_request);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define MAKE_REQUEST_FN_RET void" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether make_request_fn() returns blk_qc_t" >&5
-$as_echo_n "checking whether make_request_fn() returns blk_qc_t... " >&6; }
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-                               #include <linux/blkdev.h>
-
-                               blk_qc_t make_request(struct request_queue *q, struct bio *bio)
-                               {
-                                       return (BLK_QC_T_NONE);
-                               }
-
-int
-main (void)
-{
-
-                               blk_queue_make_request(NULL, &make_request);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define MAKE_REQUEST_FN_RET blk_qc_t" >>confdefs.h
-
-
-$as_echo "#define HAVE_MAKE_REQUEST_FN_RET_QC 1" >>confdefs.h
-
-
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-                               as_fn_error $? "no - Please file a bug report at
-                                   https://github.com/zfsonlinux/zfs/issues/new" "$LINENO" 5
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-
-fi
-       rm -Rf build
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether generic IO accounting symbols are avaliable" >&5
-$as_echo_n "checking whether generic IO accounting symbols are avaliable... " >&6; }
-
-
-
-cat confdefs.h - <<_ACEOF >conftest.c
-
-
-               #include <linux/bio.h>
-
-               void (*generic_start_io_acct_f)(int, unsigned long,
-                   struct hd_struct *) = &generic_start_io_acct;
-               void (*generic_end_io_acct_f)(int, struct hd_struct *,
-                   unsigned long) = &generic_end_io_acct;
-
-int
-main (void)
-{
-
-               generic_start_io_acct(0, 0, NULL);
-               generic_end_io_acct(0, NULL, 0);
-
-  ;
-  return 0;
-}
-
-_ACEOF
-
-
-
-cat - <<_ACEOF >conftest.h
-
-_ACEOF
-
-
-       rm -Rf build && mkdir -p build && touch build/conftest.mod.c
-       echo "obj-m := conftest.o" >build/Makefile
-       modpost_flag=''
-       test "x$enable_linux_builtin" = xyes && modpost_flag='modpost=true' # fake modpost stage
-       if { ac_try='cp conftest.c conftest.h build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build $modpost_flag'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; } >/dev/null && { ac_try='test -s build/conftest.o'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  rc=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
- rc=1
-
-
-fi
-       rm -Rf build
-
-
-       if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-       else
-               if test "x$enable_linux_builtin" != xyes; then
-
-       grep -q -E '[[:space:]]generic_start_io_acct[[:space:]]' \
-               $LINUX_OBJ/$LINUX_SYMBOLS 2>/dev/null
-       rc=$?
-       if test $rc -ne 0; then
-               export=0
-               for file in block/bio.c; do
-                       grep -q -E "EXPORT_SYMBOL.*(generic_start_io_acct)" \
-                               "$LINUX/$file" 2>/dev/null
-                       rc=$?
-                       if test $rc -eq 0; then
-                               export=1
-                               break;
-                       fi
-               done
-               if test $export -eq 0; then :
-                       rc=1
-               else :
-                       rc=0
-               fi
-       else :
-               rc=0
-       fi
-
-               fi
-               if test $rc -ne 0; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-               else :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-$as_echo "#define HAVE_GENERIC_IO_ACCT 1" >>confdefs.h
-
-
-               fi
-       fi
-
-
-
-       if test "$LINUX_OBJ" != "$LINUX"; then :
-
-               KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ"
-
-fi
-
-
-
-                       KERNELCPPFLAGS="$KERNELCPPFLAGS $NO_UNUSED_BUT_SET_VARIABLE"
-       KERNELCPPFLAGS="$KERNELCPPFLAGS $NO_BOOL_COMPARE"
-       KERNELCPPFLAGS="$KERNELCPPFLAGS -DHAVE_SPL -D_KERNEL"
-       KERNELCPPFLAGS="$KERNELCPPFLAGS -DTEXT_DOMAIN=\\\"zfs-linux-kernel\\\""
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dkms.conf file" >&5
-$as_echo_n "checking for dkms.conf file... " >&6; }
-        if test -e dkms.conf; then :
-
-               as_fn_error $? "
-       *** ZFS should not be manually built in the DKMS source tree.
-       *** Remove all ZFS packages before compiling the ZoL sources.
-       *** Running \"make install\" breaks ZFS packages." "$LINENO" 5
-
-else
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
-
-fi
-
-
-
-# Check whether --with-mounthelperdir was given.
-if test "${with_mounthelperdir+set}" = set; then :
-  withval=$with_mounthelperdir; mounthelperdir=$withval
-else
-  mounthelperdir=/sbin
-fi
-
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for udev directories" >&5
-$as_echo_n "checking for udev directories... " >&6; }
-
-# Check whether --with-udevdir was given.
-if test "${with_udevdir+set}" = set; then :
-  withval=$with_udevdir; udevdir=$withval
-else
-  udevdir=check
-fi
-
-
-       if test "x$udevdir" = xcheck; then :
-
-               path1=/lib/udev
-               path2=/usr/lib/udev
-               default=$path2
-
-               if test -d "$path1"; then :
-  udevdir="$path1"
-else
-
-                       if test -d "$path2"; then :
-  udevdir="$path2"
-else
-  udevdir="$default"
-fi
-
-fi
-
-fi
-
-
-# Check whether --with-udevruledir was given.
-if test "${with_udevruledir+set}" = set; then :
-  withval=$with_udevruledir; udevruledir=$withval
-else
-  udevruledir="${udevdir}/rules.d"
-fi
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $udevdir;$udevruledir" >&5
-$as_echo "$udevdir;$udevruledir" >&6; }
-
-
-       # Check whether --enable-systemd was given.
-if test "${enable_systemd+set}" = set; then :
-  enableval=$enable_systemd;
-else
-  enable_systemd=yes
-fi
-
-
-
-# Check whether --with-systemdunitdir was given.
-if test "${with_systemdunitdir+set}" = set; then :
-  withval=$with_systemdunitdir; systemdunitdir=$withval
-else
-  systemdunitdir=/usr/lib/systemd/system
-fi
-
-
-
-# Check whether --with-systemdpresetdir was given.
-if test "${with_systemdpresetdir+set}" = set; then :
-  withval=$with_systemdpresetdir; systemdpresetdir=$withval
-else
-  systemdpresetdir=/usr/lib/systemd/system-preset
-fi
-
-
-
-# Check whether --with-systemdmodulesloaddir was given.
-if test "${with_systemdmodulesloaddir+set}" = set; then :
-  withval=$with_systemdmodulesloaddir; systemdmoduleloaddir=$withval
-else
-  systemdmodulesloaddir=/usr/lib/modules-load.d
-fi
-
-
-
-       if test "x$enable_systemd" = xyes; then :
-
-               ZFS_INIT_SYSTEMD=systemd
-               ZFS_MODULE_LOAD=modules-load.d
-               modulesloaddir=$systemdmodulesloaddir
-
-fi
-
-
-
-
-
-
-
-
-       # Check whether --enable-sysvinit was given.
-if test "${enable_sysvinit+set}" = set; then :
-  enableval=$enable_sysvinit;
-else
-  enable_sysvinit=yes
-fi
-
-
-       if test "x$enable_sysvinit" = xyes; then :
-  ZFS_INIT_SYSV=init.d
-fi
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dracut directory" >&5
-$as_echo_n "checking for dracut directory... " >&6; }
-
-# Check whether --with-dracutdir was given.
-if test "${with_dracutdir+set}" = set; then :
-  withval=$with_dracutdir; dracutdir=$withval
-else
-  dracutdir=check
-fi
-
-
-       if test "x$dracutdir" = xcheck; then :
-
-               path1=/usr/share/dracut
-               path2=/usr/lib/dracut
-               default=$path2
-
-               if test -d "$path1"; then :
-  dracutdir="$path1"
-else
-
-                       if test -d "$path2"; then :
-  dracutdir="$path2"
-else
-  dracutdir="$default"
-fi
-
-fi
-
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dracutdir" >&5
-$as_echo "$dracutdir" >&6; }
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for target asm dir" >&5
-$as_echo_n "checking for target asm dir... " >&6; }
-       TARGET_ARCH=`echo ${target_cpu} | sed -e s/i.86/i386/`
-
-       case $TARGET_ARCH in
-       i386|x86_64)
-               TARGET_ASM_DIR=asm-${TARGET_ARCH}
-               ;;
-       *)
-               TARGET_ASM_DIR=asm-generic
-               ;;
-       esac
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TARGET_ASM_DIR" >&5
-$as_echo "$TARGET_ASM_DIR" >&6; }
-
-
-       ZLIB=
-
-       ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_zlib_h" = xyes; then :
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** zlib.h missing, zlib-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for compress2 in -lz" >&5
-$as_echo_n "checking for compress2 in -lz... " >&6; }
-if ${ac_cv_lib_z_compress2+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lz  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char compress2 ();
-int
-main ()
-{
-return compress2 ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_z_compress2=yes
-else
-  ac_cv_lib_z_compress2=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compress2" >&5
-$as_echo "$ac_cv_lib_z_compress2" >&6; }
-if test "x$ac_cv_lib_z_compress2" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBZ 1
-_ACEOF
-
-  LIBS="-lz $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** compress2() missing, zlib-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uncompress in -lz" >&5
-$as_echo_n "checking for uncompress in -lz... " >&6; }
-if ${ac_cv_lib_z_uncompress+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lz  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char uncompress ();
-int
-main ()
-{
-return uncompress ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_z_uncompress=yes
-else
-  ac_cv_lib_z_uncompress=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_uncompress" >&5
-$as_echo "$ac_cv_lib_z_uncompress" >&6; }
-if test "x$ac_cv_lib_z_uncompress" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBZ 1
-_ACEOF
-
-  LIBS="-lz $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** uncompress() missing, zlib-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for crc32 in -lz" >&5
-$as_echo_n "checking for crc32 in -lz... " >&6; }
-if ${ac_cv_lib_z_crc32+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lz  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char crc32 ();
-int
-main ()
-{
-return crc32 ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_z_crc32=yes
-else
-  ac_cv_lib_z_crc32=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_crc32" >&5
-$as_echo "$ac_cv_lib_z_crc32" >&6; }
-if test "x$ac_cv_lib_z_crc32" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBZ 1
-_ACEOF
-
-  LIBS="-lz $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** crc32() missing, zlib-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       ZLIB="-lz"
-
-
-$as_echo "#define HAVE_ZLIB 1" >>confdefs.h
-
-
-
-       LIBUUID=
-
-       ac_fn_c_check_header_mongrel "$LINENO" "uuid/uuid.h" "ac_cv_header_uuid_uuid_h" "$ac_includes_default"
-if test "x$ac_cv_header_uuid_uuid_h" = xyes; then :
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** uuid/uuid.h missing, libuuid-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate in -luuid" >&5
-$as_echo_n "checking for uuid_generate in -luuid... " >&6; }
-if ${ac_cv_lib_uuid_uuid_generate+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-luuid  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char uuid_generate ();
-int
-main ()
-{
-return uuid_generate ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_uuid_uuid_generate=yes
-else
-  ac_cv_lib_uuid_uuid_generate=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate" >&5
-$as_echo "$ac_cv_lib_uuid_uuid_generate" >&6; }
-if test "x$ac_cv_lib_uuid_uuid_generate" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBUUID 1
-_ACEOF
-
-  LIBS="-luuid $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** uuid_generate() missing, libuuid-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_is_null in -luuid" >&5
-$as_echo_n "checking for uuid_is_null in -luuid... " >&6; }
-if ${ac_cv_lib_uuid_uuid_is_null+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-luuid  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char uuid_is_null ();
-int
-main ()
-{
-return uuid_is_null ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_uuid_uuid_is_null=yes
-else
-  ac_cv_lib_uuid_uuid_is_null=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_is_null" >&5
-$as_echo "$ac_cv_lib_uuid_uuid_is_null" >&6; }
-if test "x$ac_cv_lib_uuid_uuid_is_null" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBUUID 1
-_ACEOF
-
-  LIBS="-luuid $LIBS"
-
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "
-       *** uuid_is_null() missing, libuuid-devel package required
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-       LIBUUID="-luuid"
-
-
-$as_echo "#define HAVE_LIBUUID 1" >>confdefs.h
-
-
-
-
-# Check whether --with-blkid was given.
-if test "${with_blkid+set}" = set; then :
-  withval=$with_blkid;
-else
-  with_blkid=check
-fi
-
-
-       LIBBLKID=
-       if test "x$with_blkid" = xyes; then :
-
-               LIBBLKID="-lblkid"
-
-
-$as_echo "#define HAVE_LIBBLKID 1" >>confdefs.h
-
-
-fi
-
-       if test "x$with_blkid" = xcheck; then :
-
-               { $as_echo "$as_me:${as_lineno-$LINENO}: checking for blkid_get_cache in -lblkid" >&5
-$as_echo_n "checking for blkid_get_cache in -lblkid... " >&6; }
-if ${ac_cv_lib_blkid_blkid_get_cache+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lblkid  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char blkid_get_cache ();
-int
-main ()
-{
-return blkid_get_cache ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_blkid_blkid_get_cache=yes
-else
-  ac_cv_lib_blkid_blkid_get_cache=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blkid_blkid_get_cache" >&5
-$as_echo "$ac_cv_lib_blkid_blkid_get_cache" >&6; }
-if test "x$ac_cv_lib_blkid_blkid_get_cache" = xyes; then :
-
-                       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for blkid zfs support" >&5
-$as_echo_n "checking for blkid zfs support... " >&6; }
-
-                       ZFS_DEV=`mktemp`
-                       truncate -s 64M $ZFS_DEV
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=128 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=132 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=136 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-                       echo -en "\x0c\xb1\xba\0\0\0\0\0" | \
-                               dd of=$ZFS_DEV bs=1k count=8 \
-                               seek=140 conv=notrunc &>/dev/null \
-                               >/dev/null 2>/dev/null
-
-                       saved_LIBS="$LIBS"
-                       LIBS="-lblkid"
-
-                       if test "$cross_compiling" = yes; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run test program while cross compiling
-See \`config.log' for more details" "$LINENO" 5; }
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-                               #include <stdio.h>
-                               #include <stdlib.h>
-                               #include <blkid/blkid.h>
-
-int
-main ()
-{
-
-                               blkid_cache cache;
-                               char *value;
-
-                               if (blkid_get_cache(&cache, NULL) < 0)
-                                       return 1;
-
-                               value = blkid_get_tag_value(cache, "TYPE",
-                                                           "$ZFS_DEV");
-                               if (!value) {
-                                       blkid_put_cache(cache);
-                                       return 2;
-                               }
-
-                               if (strcmp(value, "zfs_member")) {
-                                       free(value);
-                                       blkid_put_cache(cache);
-                                       return 0;
-                               }
-
-                               free(value);
-                               blkid_put_cache(cache);
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-                               rm -f $ZFS_DEV
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-                               LIBBLKID="-lblkid"
-
-
-$as_echo "#define HAVE_LIBBLKID 1" >>confdefs.h
-
-
-else
-
-                               rm -f $ZFS_DEV
-                               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                               if test "x$with_blkid" != xcheck; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "--with-blkid given but unavailable
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-
-                       LIBS="$saved_LIBS"
-
-else
-
-                       if test "x$with_blkid" != xcheck; then :
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "--with-blkid given but unavailable
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-
-
-fi
-
-
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wframe-larger-than=<size> support" >&5
-$as_echo_n "checking for -Wframe-larger-than=<size> support... " >&6; }
-
-       saved_flags="$CFLAGS"
-       CFLAGS="$CFLAGS -Wframe-larger-than=1024"
-
-       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-               FRAME_LARGER_THAN=-Wframe-larger-than=1024
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-
-else
-
-               FRAME_LARGER_THAN=
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-       CFLAGS="$saved_flags"
-
-
-
-       if test "x$runstatedir" = x; then
-               runstatedir='${localstatedir}/run'
-
-       fi
-
-       for ac_func in mlockall
-do :
-  ac_fn_c_check_func "$LINENO" "mlockall" "ac_cv_func_mlockall"
-if test "x$ac_cv_func_mlockall" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_MLOCKALL 1
-_ACEOF
-
-fi
-done
-
-   ;;
-               srpm)                        ;;
-               *)
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: Error!" >&5
-$as_echo "Error!" >&6; }
-               as_fn_error $? "Bad value \"$ZFS_CONFIG\" for --with-config,
-                             user kernel|user|all|srpm" "$LINENO" 5 ;;
-       esac
-
-        if test "$ZFS_CONFIG" = user -o "$ZFS_CONFIG" = all; then
-  CONFIG_USER_TRUE=
-  CONFIG_USER_FALSE='#'
-else
-  CONFIG_USER_TRUE='#'
-  CONFIG_USER_FALSE=
-fi
-
-        if test "$ZFS_CONFIG" = kernel -o "$ZFS_CONFIG" = all &&
-                      test "x$enable_linux_builtin" != xyes ; then
-  CONFIG_KERNEL_TRUE=
-  CONFIG_KERNEL_FALSE='#'
-else
-  CONFIG_KERNEL_TRUE='#'
-  CONFIG_KERNEL_FALSE=
-fi
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether debugging is enabled" >&5
-$as_echo_n "checking whether debugging is enabled... " >&6; }
-       # Check whether --enable-debug was given.
-if test "${enable_debug+set}" = set; then :
-  enableval=$enable_debug;
-else
-  enable_debug=no
-fi
-
-
-       if test "x$enable_debug" = xyes; then :
-
-               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG -Werror"
-               HOSTCFLAGS="${HOSTCFLAGS} -DDEBUG -Werror"
-               DEBUG_CFLAGS="-DDEBUG -Werror"
-               DEBUG_STACKFLAGS="-fstack-check"
-               DEBUG_ZFS="_with_debug"
-
-$as_echo "#define ZFS_DEBUG 1" >>confdefs.h
-
-
-else
-
-               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DNDEBUG "
-               HOSTCFLAGS="${HOSTCFLAGS} -DNDEBUG "
-               DEBUG_CFLAGS="-DNDEBUG"
-               DEBUG_STACKFLAGS=""
-               DEBUG_ZFS="_without_debug"
-
-fi
-
-
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug" >&5
-$as_echo "$enable_debug" >&6; }
-
-
-       # Check whether --enable-debug-dmu-tx was given.
-if test "${enable_debug_dmu_tx+set}" = set; then :
-  enableval=$enable_debug_dmu_tx;
-else
-  enable_debug_dmu_tx=no
-fi
-
-
-       if test "x$enable_debug_dmu_tx" = xyes; then :
-
-               KERNELCPPFLAGS="${KERNELCPPFLAGS} -DDEBUG_DMU_TX"
-               DEBUG_DMU_TX="_with_debug_dmu_tx"
-
-$as_echo "#define DEBUG_DMU_TX 1" >>confdefs.h
-
-
-else
-
-               DEBUG_DMU_TX="_without_debug_dmu_tx"
-
-fi
-
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether dmu tx validation is enabled" >&5
-$as_echo_n "checking whether dmu tx validation is enabled... " >&6; }
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_debug_dmu_tx" >&5
-$as_echo "$enable_debug_dmu_tx" >&6; }
-
-
-ac_config_files="$ac_config_files Makefile udev/Makefile udev/rules.d/Makefile etc/Makefile etc/init.d/Makefile etc/zfs/Makefile etc/systemd/Makefile etc/systemd/system/Makefile etc/modules-load.d/Makefile man/Makefile man/man1/Makefile man/man5/Makefile man/man8/Makefile lib/Makefile lib/libspl/Makefile lib/libspl/asm-generic/Makefile lib/libspl/asm-i386/Makefile lib/libspl/asm-x86_64/Makefile lib/libspl/include/Makefile lib/libspl/include/ia32/Makefile lib/libspl/include/ia32/sys/Makefile lib/libspl/include/rpc/Makefile lib/libspl/include/sys/Makefile lib/libspl/include/sys/sysevent/Makefile lib/libspl/include/sys/dktp/Makefile lib/libspl/include/util/Makefile lib/libavl/Makefile lib/libefi/Makefile lib/libnvpair/Makefile lib/libunicode/Makefile lib/libuutil/Makefile lib/libzpool/Makefile lib/libzfs/libzfs.pc lib/libzfs/libzfs_core.pc lib/libzfs/Makefile lib/libzfs_core/Makefile lib/libshare/Makefile cmd/Makefile cmd/zdb/Makefile cmd/zhack/Makefile cmd/zfs/Makefile cmd/zinject/Makefile cmd/zpool/Makefile cmd/zstreamdump/Makefile cmd/ztest/Makefile cmd/zpios/Makefile cmd/mount_zfs/Makefile cmd/fsck_zfs/Makefile cmd/zvol_id/Makefile cmd/vdev_id/Makefile cmd/arcstat/Makefile cmd/dbufstat/Makefile cmd/arc_summary/Makefile cmd/zed/Makefile contrib/Makefile contrib/bash_completion.d/Makefile contrib/dracut/Makefile contrib/dracut/90zfs/Makefile contrib/initramfs/Makefile module/Makefile module/avl/Makefile module/nvpair/Makefile module/unicode/Makefile module/zcommon/Makefile module/zfs/Makefile module/zpios/Makefile include/Makefile include/linux/Makefile include/sys/Makefile include/sys/fs/Makefile include/sys/fm/Makefile include/sys/fm/fs/Makefile scripts/Makefile scripts/zpios-profile/Makefile scripts/zpios-test/Makefile scripts/zpool-config/Makefile scripts/common.sh rpm/Makefile rpm/redhat/Makefile rpm/redhat/zfs.spec rpm/redhat/zfs-kmod.spec rpm/redhat/zfs-dkms.spec rpm/generic/Makefile rpm/generic/zfs.spec rpm/generic/zfs-kmod.spec rpm/generic/zfs-dkms.spec zfs-script-config.sh zfs.release"
-
-
-cat >confcache <<\_ACEOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs, see configure's option --config-cache.
-# It is not useful on other systems.  If it contains results you don't
-# want to keep, you may remove or edit it.
-#
-# config.status only pays attention to the cache file if you give it
-# the --recheck option to rerun configure.
-#
-# `ac_cv_env_foo' variables (set or unset) will be overridden when
-# loading this file, other *unset* `ac_cv_foo' will be assigned the
-# following values.
-
-_ACEOF
-
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, we kill variables containing newlines.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(
-  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
-    eval ac_val=\$$ac_var
-    case $ac_val in #(
-    *${as_nl}*)
-      case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
-      esac
-      case $ac_var in #(
-      _ | IFS | as_nl) ;; #(
-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) { eval $ac_var=; unset $ac_var;} ;;
-      esac ;;
-    esac
-  done
-
-  (set) 2>&1 |
-    case $as_nl`(ac_space=' '; set) 2>&1` in #(
-    *${as_nl}ac_space=\ *)
-      # `set' does not quote correctly, so add quotes: double-quote
-      # substitution turns \\\\ into \\, and sed turns \\ into \.
-      sed -n \
-       "s/'/'\\\\''/g;
-         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
-      ;; #(
-    *)
-      # `set' quotes correctly as required by POSIX, so do not add quotes.
-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
-      ;;
-    esac |
-    sort
-) |
-  sed '
-     /^ac_cv_env_/b end
-     t clear
-     :clear
-     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
-     t end
-     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
-     :end' >>confcache
-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
-  if test -w "$cache_file"; then
-    if test "x$cache_file" != "x/dev/null"; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-$as_echo "$as_me: updating cache $cache_file" >&6;}
-      if test ! -f "$cache_file" || test -h "$cache_file"; then
-       cat confcache >"$cache_file"
-      else
-        case $cache_file in #(
-        */* | ?:*)
-         mv -f confcache "$cache_file"$$ &&
-         mv -f "$cache_file"$$ "$cache_file" ;; #(
-        *)
-         mv -f confcache "$cache_file" ;;
-       esac
-      fi
-    fi
-  else
-    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
-  fi
-fi
-rm -f confcache
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-DEFS=-DHAVE_CONFIG_H
-
-ac_libobjs=
-ac_ltlibobjs=
-U=
-for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
-  # 1. Remove the extension, and $U if already installed.
-  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
-  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
-  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
-  #    will be set to the directory where LIBOBJS objects are built.
-  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
-  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
-done
-LIBOBJS=$ac_libobjs
-
-LTLIBOBJS=$ac_ltlibobjs
-
-
-if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
-  as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
-$as_echo_n "checking that generated files are newer than configure... " >&6; }
-   if test -n "$am_sleep_pid"; then
-     # Hide warnings about reused PIDs.
-     wait $am_sleep_pid 2>/dev/null
-   fi
-   { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
-$as_echo "done" >&6; }
- if test -n "$EXEEXT"; then
-  am__EXEEXT_TRUE=
-  am__EXEEXT_FALSE='#'
-else
-  am__EXEEXT_TRUE='#'
-  am__EXEEXT_FALSE=
-fi
-
-if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
-  as_fn_error $? "conditional \"AMDEP\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
-  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then
-  as_fn_error $? "conditional \"am__fastdepCCAS\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${CONFIG_USER_TRUE}" && test -z "${CONFIG_USER_FALSE}"; then
-  as_fn_error $? "conditional \"CONFIG_USER\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${CONFIG_KERNEL_TRUE}" && test -z "${CONFIG_KERNEL_FALSE}"; then
-  as_fn_error $? "conditional \"CONFIG_KERNEL\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-
-: "${CONFIG_STATUS=./config.status}"
-ac_write_fail=0
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
-as_write_fail=0
-cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-
-debug=false
-ac_cs_recheck=false
-ac_cs_silent=false
-
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-
-
-as_nl='
-'
-export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
-    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='print -r --'
-  as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='printf %s\n'
-  as_echo_n='printf %s'
-else
-  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
-    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
-    as_echo_n='/usr/ucb/echo -n'
-  else
-    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
-    as_echo_n_body='eval
-      arg=$1;
-      case $arg in #(
-      *"$as_nl"*)
-       expr "X$arg" : "X\\(.*\\)$as_nl";
-       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
-      esac;
-      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
-    '
-    export as_echo_n_body
-    as_echo_n='sh -c $as_echo_n_body as_echo'
-  fi
-  export as_echo_body
-  as_echo='sh -c $as_echo_body as_echo'
-fi
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  PATH_SEPARATOR=:
-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
-      PATH_SEPARATOR=';'
-  }
-fi
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.  Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" ""       $as_nl"
-
-# Find who we are.  Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
-  *[\\/]* ) as_myself=$0 ;;
-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-  done
-IFS=$as_save_IFS
-
-     ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
-  as_myself=$0
-fi
-if test ! -f "$as_myself"; then
-  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  exit 1
-fi
-
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there.  '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
-  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
-  as_status=$1; test $as_status -eq 0 && as_status=1
-  if test "$4"; then
-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
-  fi
-  $as_echo "$as_me: error: $2" >&2
-  as_fn_exit $as_status
-} # as_fn_error
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
-  return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
-  set +e
-  as_fn_set_status $1
-  exit $1
-} # as_fn_exit
-
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
-  { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
-  eval 'as_fn_append ()
-  {
-    eval $1+=\$2
-  }'
-else
-  as_fn_append ()
-  {
-    eval $1=\$$1\$2
-  }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
-  eval 'as_fn_arith ()
-  {
-    as_val=$(( $* ))
-  }'
-else
-  as_fn_arith ()
-  {
-    as_val=`expr "$@" || test $? -eq 1`
-  }
-fi # as_fn_arith
-
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
-  as_basename=basename
-else
-  as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
-        X"$0" : 'X\(//\)$' \| \
-        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\/\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
-  case `echo 'xy\c'` in
-  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
-  xy)  ECHO_C='\c';;
-  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
-       ECHO_T='        ';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
-  if ln -s conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s='ln -s'
-    # ... but there are two gotchas:
-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
-  elif ln conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s=ln
-  else
-    as_ln_s='cp -pR'
-  fi
-else
-  as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || eval $as_mkdir_p || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$as_dir" : 'X\(//\)[^/]' \| \
-        X"$as_dir" : 'X\(//\)$' \| \
-        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p='mkdir -p "$as_dir"'
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-exec 6>&1
-## ----------------------------------- ##
-## Main body of $CONFIG_STATUS script. ##
-## ----------------------------------- ##
-_ASEOF
-test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# Save the log message, to keep $0 and so on meaningful, and to
-# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.
-ac_log="
-This file was extended by zfs $as_me 0.6.5.8, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
-
-  CONFIG_FILES    = $CONFIG_FILES
-  CONFIG_HEADERS  = $CONFIG_HEADERS
-  CONFIG_LINKS    = $CONFIG_LINKS
-  CONFIG_COMMANDS = $CONFIG_COMMANDS
-  $ $0 $@
-
-on `(hostname || uname -n) 2>/dev/null | sed 1q`
-"
-
-_ACEOF
-
-case $ac_config_files in *"
-"*) set x $ac_config_files; shift; ac_config_files=$*;;
-esac
-
-case $ac_config_headers in *"
-"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
-esac
-
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-# Files that config.status was made for.
-config_files="$ac_config_files"
-config_headers="$ac_config_headers"
-config_commands="$ac_config_commands"
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-ac_cs_usage="\
-\`$as_me' instantiates files and other configuration actions
-from templates according to the current configuration.  Unless the files
-and actions are specified as TAGs, all are instantiated by default.
-
-Usage: $0 [OPTION]... [TAG]...
-
-  -h, --help       print this help, then exit
-  -V, --version    print version number and configuration settings, then exit
-      --config     print configuration, then exit
-  -q, --quiet, --silent
-                   do not print progress messages
-  -d, --debug      don't remove temporary files
-      --recheck    update $as_me by reconfiguring in the same conditions
-      --file=FILE[:TEMPLATE]
-                   instantiate the configuration file FILE
-      --header=FILE[:TEMPLATE]
-                   instantiate the configuration header FILE
-
-Configuration files:
-$config_files
-
-Configuration headers:
-$config_headers
-
-Configuration commands:
-$config_commands
-
-Report bugs to the package provider."
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
-ac_cs_version="\\
-zfs config.status 0.6.5.8
-configured by $0, generated by GNU Autoconf 2.69,
-  with options \\"\$ac_cs_config\\"
-
-Copyright (C) 2012 Free Software Foundation, Inc.
-This config.status script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it."
-
-ac_pwd='$ac_pwd'
-srcdir='$srcdir'
-INSTALL='$INSTALL'
-MKDIR_P='$MKDIR_P'
-AWK='$AWK'
-test -n "\$AWK" || AWK=awk
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# The default lists apply if the user does not specify any file.
-ac_need_defaults=:
-while test $# != 0
-do
-  case $1 in
-  --*=?*)
-    ac_option=`expr "X$1" : 'X\([^=]*\)='`
-    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
-    ac_shift=:
-    ;;
-  --*=)
-    ac_option=`expr "X$1" : 'X\([^=]*\)='`
-    ac_optarg=
-    ac_shift=:
-    ;;
-  *)
-    ac_option=$1
-    ac_optarg=$2
-    ac_shift=shift
-    ;;
-  esac
-
-  case $ac_option in
-  # Handling of the options.
-  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
-    ac_cs_recheck=: ;;
-  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
-    $as_echo "$ac_cs_version"; exit ;;
-  --config | --confi | --conf | --con | --co | --c )
-    $as_echo "$ac_cs_config"; exit ;;
-  --debug | --debu | --deb | --de | --d | -d )
-    debug=: ;;
-  --file | --fil | --fi | --f )
-    $ac_shift
-    case $ac_optarg in
-    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    '') as_fn_error $? "missing file argument" ;;
-    esac
-    as_fn_append CONFIG_FILES " '$ac_optarg'"
-    ac_need_defaults=false;;
-  --header | --heade | --head | --hea )
-    $ac_shift
-    case $ac_optarg in
-    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    esac
-    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
-    ac_need_defaults=false;;
-  --he | --h)
-    # Conflict between --help and --header
-    as_fn_error $? "ambiguous option: \`$1'
-Try \`$0 --help' for more information.";;
-  --help | --hel | -h )
-    $as_echo "$ac_cs_usage"; exit ;;
-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-  | -silent | --silent | --silen | --sile | --sil | --si | --s)
-    ac_cs_silent=: ;;
-
-  # This is an error.
-  -*) as_fn_error $? "unrecognized option: \`$1'
-Try \`$0 --help' for more information." ;;
-
-  *) as_fn_append ac_config_targets " $1"
-     ac_need_defaults=false ;;
-
-  esac
-  shift
-done
-
-ac_configure_extra_args=
-
-if $ac_cs_silent; then
-  exec 6>/dev/null
-  ac_configure_extra_args="$ac_configure_extra_args --silent"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-if \$ac_cs_recheck; then
-  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
-  shift
-  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
-  CONFIG_SHELL='$SHELL'
-  export CONFIG_SHELL
-  exec "\$@"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-exec 5>>config.log
-{
-  echo
-  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
-  $as_echo "$ac_log"
-} >&5
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-#
-# INIT-COMMANDS
-#
-AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
-
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-sed_quote_subst='$sed_quote_subst'
-double_quote_subst='$double_quote_subst'
-delay_variable_subst='$delay_variable_subst'
-macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
-macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
-enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
-enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
-pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
-enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
-shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
-SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
-ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
-PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
-host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
-host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
-host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
-build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
-build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
-build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
-SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
-Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
-GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
-EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
-FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
-LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
-NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
-LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
-max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
-ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
-exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
-lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
-lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
-lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
-lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
-lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
-reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
-reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
-OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
-deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
-file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
-file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
-want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
-DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
-sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
-AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
-AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
-archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
-STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
-RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
-old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
-old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
-old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
-lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
-CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
-CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
-compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
-GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
-lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`'
-nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
-lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
-lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`'
-objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
-MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
-lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
-need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
-MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
-DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
-NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
-LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
-OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
-OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
-libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
-shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
-extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
-archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
-enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
-export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
-whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
-compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
-old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
-old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
-archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
-archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
-module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
-module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
-with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
-allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
-no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
-hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
-hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
-hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
-hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
-hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
-hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
-hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
-inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
-link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
-always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
-export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
-exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
-include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
-prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
-postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
-file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
-variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
-need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
-need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
-version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
-runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
-shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
-shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
-libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
-library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
-soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
-install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
-postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
-postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
-finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
-finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
-hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
-sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
-configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`'
-configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`'
-hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
-enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
-enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
-enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
-old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
-striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
-
-LTCC='$LTCC'
-LTCFLAGS='$LTCFLAGS'
-compiler='$compiler_DEFAULT'
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
-  eval 'cat <<_LTECHO_EOF
-\$1
-_LTECHO_EOF'
-}
-
-# Quote evaled strings.
-for var in SHELL \
-ECHO \
-PATH_SEPARATOR \
-SED \
-GREP \
-EGREP \
-FGREP \
-LD \
-NM \
-LN_S \
-lt_SP2NL \
-lt_NL2SP \
-reload_flag \
-OBJDUMP \
-deplibs_check_method \
-file_magic_cmd \
-file_magic_glob \
-want_nocaseglob \
-DLLTOOL \
-sharedlib_from_linklib_cmd \
-AR \
-AR_FLAGS \
-archiver_list_spec \
-STRIP \
-RANLIB \
-CC \
-CFLAGS \
-compiler \
-lt_cv_sys_global_symbol_pipe \
-lt_cv_sys_global_symbol_to_cdecl \
-lt_cv_sys_global_symbol_to_import \
-lt_cv_sys_global_symbol_to_c_name_address \
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
-lt_cv_nm_interface \
-nm_file_list_spec \
-lt_cv_truncate_bin \
-lt_prog_compiler_no_builtin_flag \
-lt_prog_compiler_pic \
-lt_prog_compiler_wl \
-lt_prog_compiler_static \
-lt_cv_prog_compiler_c_o \
-need_locks \
-MANIFEST_TOOL \
-DSYMUTIL \
-NMEDIT \
-LIPO \
-OTOOL \
-OTOOL64 \
-shrext_cmds \
-export_dynamic_flag_spec \
-whole_archive_flag_spec \
-compiler_needs_object \
-with_gnu_ld \
-allow_undefined_flag \
-no_undefined_flag \
-hardcode_libdir_flag_spec \
-hardcode_libdir_separator \
-exclude_expsyms \
-include_expsyms \
-file_list_spec \
-variables_saved_for_relink \
-libname_spec \
-library_names_spec \
-soname_spec \
-install_override_mode \
-finish_eval \
-old_striplib \
-striplib; do
-    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
-    *[\\\\\\\`\\"\\\$]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
-      ;;
-    *)
-      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
-      ;;
-    esac
-done
-
-# Double-quote double-evaled strings.
-for var in reload_cmds \
-old_postinstall_cmds \
-old_postuninstall_cmds \
-old_archive_cmds \
-extract_expsyms_cmds \
-old_archive_from_new_cmds \
-old_archive_from_expsyms_cmds \
-archive_cmds \
-archive_expsym_cmds \
-module_cmds \
-module_expsym_cmds \
-export_symbols_cmds \
-prelink_cmds \
-postlink_cmds \
-postinstall_cmds \
-postuninstall_cmds \
-finish_cmds \
-sys_lib_search_path_spec \
-configure_time_dlsearch_path \
-configure_time_lt_sys_library_path; do
-    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
-    *[\\\\\\\`\\"\\\$]*)
-      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
-      ;;
-    *)
-      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
-      ;;
-    esac
-done
-
-ac_aux_dir='$ac_aux_dir'
-
-# See if we are running on zsh, and set the options that allow our
-# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}"; then
-   setopt NO_GLOB_SUBST
-fi
-
-
-    PACKAGE='$PACKAGE'
-    VERSION='$VERSION'
-    RM='$RM'
-    ofile='$ofile'
-
-
-
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-
-# Handling of arguments.
-for ac_config_target in $ac_config_targets
-do
-  case $ac_config_target in
-    "zfs_config.h") CONFIG_HEADERS="$CONFIG_HEADERS zfs_config.h" ;;
-    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
-    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
-    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
-    "udev/Makefile") CONFIG_FILES="$CONFIG_FILES udev/Makefile" ;;
-    "udev/rules.d/Makefile") CONFIG_FILES="$CONFIG_FILES udev/rules.d/Makefile" ;;
-    "etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
-    "etc/init.d/Makefile") CONFIG_FILES="$CONFIG_FILES etc/init.d/Makefile" ;;
-    "etc/zfs/Makefile") CONFIG_FILES="$CONFIG_FILES etc/zfs/Makefile" ;;
-    "etc/systemd/Makefile") CONFIG_FILES="$CONFIG_FILES etc/systemd/Makefile" ;;
-    "etc/systemd/system/Makefile") CONFIG_FILES="$CONFIG_FILES etc/systemd/system/Makefile" ;;
-    "etc/modules-load.d/Makefile") CONFIG_FILES="$CONFIG_FILES etc/modules-load.d/Makefile" ;;
-    "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
-    "man/man1/Makefile") CONFIG_FILES="$CONFIG_FILES man/man1/Makefile" ;;
-    "man/man5/Makefile") CONFIG_FILES="$CONFIG_FILES man/man5/Makefile" ;;
-    "man/man8/Makefile") CONFIG_FILES="$CONFIG_FILES man/man8/Makefile" ;;
-    "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
-    "lib/libspl/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/Makefile" ;;
-    "lib/libspl/asm-generic/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/asm-generic/Makefile" ;;
-    "lib/libspl/asm-i386/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/asm-i386/Makefile" ;;
-    "lib/libspl/asm-x86_64/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/asm-x86_64/Makefile" ;;
-    "lib/libspl/include/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/include/Makefile" ;;
-    "lib/libspl/include/ia32/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/include/ia32/Makefile" ;;
-    "lib/libspl/include/ia32/sys/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/include/ia32/sys/Makefile" ;;
-    "lib/libspl/include/rpc/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/include/rpc/Makefile" ;;
-    "lib/libspl/include/sys/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/include/sys/Makefile" ;;
-    "lib/libspl/include/sys/sysevent/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/include/sys/sysevent/Makefile" ;;
-    "lib/libspl/include/sys/dktp/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/include/sys/dktp/Makefile" ;;
-    "lib/libspl/include/util/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libspl/include/util/Makefile" ;;
-    "lib/libavl/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libavl/Makefile" ;;
-    "lib/libefi/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libefi/Makefile" ;;
-    "lib/libnvpair/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libnvpair/Makefile" ;;
-    "lib/libunicode/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libunicode/Makefile" ;;
-    "lib/libuutil/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libuutil/Makefile" ;;
-    "lib/libzpool/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libzpool/Makefile" ;;
-    "lib/libzfs/libzfs.pc") CONFIG_FILES="$CONFIG_FILES lib/libzfs/libzfs.pc" ;;
-    "lib/libzfs/libzfs_core.pc") CONFIG_FILES="$CONFIG_FILES lib/libzfs/libzfs_core.pc" ;;
-    "lib/libzfs/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libzfs/Makefile" ;;
-    "lib/libzfs_core/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libzfs_core/Makefile" ;;
-    "lib/libshare/Makefile") CONFIG_FILES="$CONFIG_FILES lib/libshare/Makefile" ;;
-    "cmd/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/Makefile" ;;
-    "cmd/zdb/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zdb/Makefile" ;;
-    "cmd/zhack/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zhack/Makefile" ;;
-    "cmd/zfs/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zfs/Makefile" ;;
-    "cmd/zinject/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zinject/Makefile" ;;
-    "cmd/zpool/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zpool/Makefile" ;;
-    "cmd/zstreamdump/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zstreamdump/Makefile" ;;
-    "cmd/ztest/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/ztest/Makefile" ;;
-    "cmd/zpios/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zpios/Makefile" ;;
-    "cmd/mount_zfs/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/mount_zfs/Makefile" ;;
-    "cmd/fsck_zfs/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/fsck_zfs/Makefile" ;;
-    "cmd/zvol_id/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zvol_id/Makefile" ;;
-    "cmd/vdev_id/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/vdev_id/Makefile" ;;
-    "cmd/arcstat/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/arcstat/Makefile" ;;
-    "cmd/dbufstat/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/dbufstat/Makefile" ;;
-    "cmd/arc_summary/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/arc_summary/Makefile" ;;
-    "cmd/zed/Makefile") CONFIG_FILES="$CONFIG_FILES cmd/zed/Makefile" ;;
-    "contrib/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;;
-    "contrib/bash_completion.d/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/bash_completion.d/Makefile" ;;
-    "contrib/dracut/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/dracut/Makefile" ;;
-    "contrib/dracut/90zfs/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/dracut/90zfs/Makefile" ;;
-    "contrib/initramfs/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/initramfs/Makefile" ;;
-    "module/Makefile") CONFIG_FILES="$CONFIG_FILES module/Makefile" ;;
-    "module/avl/Makefile") CONFIG_FILES="$CONFIG_FILES module/avl/Makefile" ;;
-    "module/nvpair/Makefile") CONFIG_FILES="$CONFIG_FILES module/nvpair/Makefile" ;;
-    "module/unicode/Makefile") CONFIG_FILES="$CONFIG_FILES module/unicode/Makefile" ;;
-    "module/zcommon/Makefile") CONFIG_FILES="$CONFIG_FILES module/zcommon/Makefile" ;;
-    "module/zfs/Makefile") CONFIG_FILES="$CONFIG_FILES module/zfs/Makefile" ;;
-    "module/zpios/Makefile") CONFIG_FILES="$CONFIG_FILES module/zpios/Makefile" ;;
-    "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
-    "include/linux/Makefile") CONFIG_FILES="$CONFIG_FILES include/linux/Makefile" ;;
-    "include/sys/Makefile") CONFIG_FILES="$CONFIG_FILES include/sys/Makefile" ;;
-    "include/sys/fs/Makefile") CONFIG_FILES="$CONFIG_FILES include/sys/fs/Makefile" ;;
-    "include/sys/fm/Makefile") CONFIG_FILES="$CONFIG_FILES include/sys/fm/Makefile" ;;
-    "include/sys/fm/fs/Makefile") CONFIG_FILES="$CONFIG_FILES include/sys/fm/fs/Makefile" ;;
-    "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
-    "scripts/zpios-profile/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/zpios-profile/Makefile" ;;
-    "scripts/zpios-test/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/zpios-test/Makefile" ;;
-    "scripts/zpool-config/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/zpool-config/Makefile" ;;
-    "scripts/common.sh") CONFIG_FILES="$CONFIG_FILES scripts/common.sh" ;;
-    "rpm/Makefile") CONFIG_FILES="$CONFIG_FILES rpm/Makefile" ;;
-    "rpm/redhat/Makefile") CONFIG_FILES="$CONFIG_FILES rpm/redhat/Makefile" ;;
-    "rpm/redhat/zfs.spec") CONFIG_FILES="$CONFIG_FILES rpm/redhat/zfs.spec" ;;
-    "rpm/redhat/zfs-kmod.spec") CONFIG_FILES="$CONFIG_FILES rpm/redhat/zfs-kmod.spec" ;;
-    "rpm/redhat/zfs-dkms.spec") CONFIG_FILES="$CONFIG_FILES rpm/redhat/zfs-dkms.spec" ;;
-    "rpm/generic/Makefile") CONFIG_FILES="$CONFIG_FILES rpm/generic/Makefile" ;;
-    "rpm/generic/zfs.spec") CONFIG_FILES="$CONFIG_FILES rpm/generic/zfs.spec" ;;
-    "rpm/generic/zfs-kmod.spec") CONFIG_FILES="$CONFIG_FILES rpm/generic/zfs-kmod.spec" ;;
-    "rpm/generic/zfs-dkms.spec") CONFIG_FILES="$CONFIG_FILES rpm/generic/zfs-dkms.spec" ;;
-    "zfs-script-config.sh") CONFIG_FILES="$CONFIG_FILES zfs-script-config.sh" ;;
-    "zfs.release") CONFIG_FILES="$CONFIG_FILES zfs.release" ;;
-
-  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
-  esac
-done
-
-
-# If the user did not use the arguments to specify the items to instantiate,
-# then the envvar interface is used.  Set only those that are not.
-# We use the long form for the default assignment because of an extremely
-# bizarre bug on SunOS 4.1.3.
-if $ac_need_defaults; then
-  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
-  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
-  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
-fi
-
-# Have a temporary directory for convenience.  Make it in the build tree
-# simply because there is no reason against having it here, and in addition,
-# creating and moving files from /tmp can sometimes cause problems.
-# Hook for its removal unless debugging.
-# Note that there is a small window in which the directory will not be cleaned:
-# after its creation but before its name has been assigned to `$tmp'.
-$debug ||
-{
-  tmp= ac_tmp=
-  trap 'exit_status=$?
-  : "${ac_tmp:=$tmp}"
-  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
-' 0
-  trap 'as_fn_exit 1' 1 2 13 15
-}
-# Create a (secure) tmp directory for tmp files.
-
-{
-  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
-  test -d "$tmp"
-}  ||
-{
-  tmp=./conf$$-$RANDOM
-  (umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
-
-# Set up the scripts for CONFIG_FILES section.
-# No need to generate them if there are no CONFIG_FILES.
-# This happens for instance with `./config.status config.h'.
-if test -n "$CONFIG_FILES"; then
-
-
-ac_cr=`echo X | tr X '\015'`
-# On cygwin, bash can eat \r inside `` if the user requested igncr.
-# But we know of no other shell where ac_cr would be empty at this
-# point, so we can use a bashism as a fallback.
-if test "x$ac_cr" = x; then
-  eval ac_cr=\$\'\\r\'
-fi
-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
-  ac_cs_awk_cr='\\r'
-else
-  ac_cs_awk_cr=$ac_cr
-fi
-
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
-_ACEOF
-
-
-{
-  echo "cat >conf$$subs.awk <<_ACEOF" &&
-  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
-  echo "_ACEOF"
-} >conf$$subs.sh ||
-  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
-ac_delim='%!_!# '
-for ac_last_try in false false false false false :; do
-  . ./conf$$subs.sh ||
-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-
-  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
-  if test $ac_delim_n = $ac_delim_num; then
-    break
-  elif $ac_last_try; then
-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-  else
-    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
-  fi
-done
-rm -f conf$$subs.sh
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
-_ACEOF
-sed -n '
-h
-s/^/S["/; s/!.*/"]=/
-p
-g
-s/^[^!]*!//
-:repl
-t repl
-s/'"$ac_delim"'$//
-t delim
-:nl
-h
-s/\(.\{148\}\)..*/\1/
-t more1
-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
-p
-n
-b repl
-:more1
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t nl
-:delim
-h
-s/\(.\{148\}\)..*/\1/
-t more2
-s/["\\]/\\&/g; s/^/"/; s/$/"/
-p
-b
-:more2
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t delim
-' <conf$$subs.awk | sed '
-/^[^""]/{
-  N
-  s/\n//
-}
-' >>$CONFIG_STATUS || ac_write_fail=1
-rm -f conf$$subs.awk
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
-  for (key in S) S_is_set[key] = 1
-  FS = "\a"
-
-}
-{
-  line = $ 0
-  nfields = split(line, field, "@")
-  substed = 0
-  len = length(field[1])
-  for (i = 2; i < nfields; i++) {
-    key = field[i]
-    keylen = length(key)
-    if (S_is_set[key]) {
-      value = S[key]
-      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
-      len += length(value) + length(field[++i])
-      substed = 1
-    } else
-      len += 1 + keylen
-  }
-
-  print line
-}
-
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
-  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
-else
-  cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
-  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
-_ACEOF
-
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
-  ac_vpsub='/^[         ]*VPATH[        ]*=[    ]*/{
-h
-s///
-s/^/:/
-s/[     ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
-s/:*$//
-x
-s/\(=[  ]*\).*/\1/
-G
-s/\n//
-s/^[^=]*=[      ]*$//
-}'
-fi
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-fi # test -n "$CONFIG_FILES"
-
-# Set up the scripts for CONFIG_HEADERS section.
-# No need to generate them if there are no CONFIG_HEADERS.
-# This happens for instance with `./config.status Makefile'.
-if test -n "$CONFIG_HEADERS"; then
-cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
-BEGIN {
-_ACEOF
-
-# Transform confdefs.h into an awk script `defines.awk', embedded as
-# here-document in config.status, that substitutes the proper values into
-# config.h.in to produce config.h.
-
-# Create a delimiter string that does not exist in confdefs.h, to ease
-# handling of long lines.
-ac_delim='%!_!# '
-for ac_last_try in false false :; do
-  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
-  if test -z "$ac_tt"; then
-    break
-  elif $ac_last_try; then
-    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
-  else
-    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
-  fi
-done
-
-# For the awk script, D is an array of macro values keyed by name,
-# likewise P contains macro parameters if any.  Preserve backslash
-# newline sequences.
-
-ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
-sed -n '
-s/.\{148\}/&'"$ac_delim"'/g
-t rset
-:rset
-s/^[    ]*#[    ]*define[       ][      ]*/ /
-t def
-d
-:def
-s/\\$//
-t bsnl
-s/["\\]/\\&/g
-s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
-D["\1"]=" \3"/p
-s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2"/p
-d
-:bsnl
-s/["\\]/\\&/g
-s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
-D["\1"]=" \3\\\\\\n"\\/p
-t cont
-s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
-t cont
-d
-:cont
-n
-s/.\{148\}/&'"$ac_delim"'/g
-t clear
-:clear
-s/\\$//
-t bsnlc
-s/["\\]/\\&/g; s/^/"/; s/$/"/p
-d
-:bsnlc
-s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
-b cont
-' <confdefs.h | sed '
-s/'"$ac_delim"'/"\\\
-"/g' >>$CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-  for (key in D) D_is_set[key] = 1
-  FS = "\a"
-}
-/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
-  line = \$ 0
-  split(line, arg, " ")
-  if (arg[1] == "#") {
-    defundef = arg[2]
-    mac1 = arg[3]
-  } else {
-    defundef = substr(arg[1], 2)
-    mac1 = arg[2]
-  }
-  split(mac1, mac2, "(") #)
-  macro = mac2[1]
-  prefix = substr(line, 1, index(line, defundef) - 1)
-  if (D_is_set[macro]) {
-    # Preserve the white space surrounding the "#".
-    print prefix "define", macro P[macro] D[macro]
-    next
-  } else {
-    # Replace #undef with comments.  This is necessary, for example,
-    # in the case of _POSIX_SOURCE, which is predefined and required
-    # on some systems where configure will not decide to define it.
-    if (defundef == "undef") {
-      print "/*", prefix defundef, macro, "*/"
-      next
-    }
-  }
-}
-{ print }
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
-fi # test -n "$CONFIG_HEADERS"
-
-
-eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
-shift
-for ac_tag
-do
-  case $ac_tag in
-  :[FHLC]) ac_mode=$ac_tag; continue;;
-  esac
-  case $ac_mode$ac_tag in
-  :[FHL]*:*);;
-  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
-  :[FH]-) ac_tag=-:-;;
-  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
-  esac
-  ac_save_IFS=$IFS
-  IFS=:
-  set x $ac_tag
-  IFS=$ac_save_IFS
-  shift
-  ac_file=$1
-  shift
-
-  case $ac_mode in
-  :L) ac_source=$1;;
-  :[FH])
-    ac_file_inputs=
-    for ac_f
-    do
-      case $ac_f in
-      -) ac_f="$ac_tmp/stdin";;
-      *) # Look for the file first in the build tree, then in the source tree
-        # (if the path is not absolute).  The absolute path cannot be DOS-style,
-        # because $ac_f cannot contain `:'.
-        test -f "$ac_f" ||
-          case $ac_f in
-          [\\/$]*) false;;
-          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
-          esac ||
-          as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
-      esac
-      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
-      as_fn_append ac_file_inputs " '$ac_f'"
-    done
-
-    # Let's still pretend it is `configure' which instantiates (i.e., don't
-    # use $as_me), people would be surprised to read:
-    #    /* config.h.  Generated by config.status.  */
-    configure_input='Generated from '`
-         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
-       `' by configure.'
-    if test x"$ac_file" != x-; then
-      configure_input="$ac_file.  $configure_input"
-      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-$as_echo "$as_me: creating $ac_file" >&6;}
-    fi
-    # Neutralize special characters interpreted by sed in replacement strings.
-    case $configure_input in #(
-    *\&* | *\|* | *\\* )
-       ac_sed_conf_input=`$as_echo "$configure_input" |
-       sed 's/[\\\\&|]/\\\\&/g'`;; #(
-    *) ac_sed_conf_input=$configure_input;;
-    esac
-
-    case $ac_tag in
-    *:-:* | *:-) cat >"$ac_tmp/stdin" \
-      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
-    esac
-    ;;
-  esac
-
-  ac_dir=`$as_dirname -- "$ac_file" ||
-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$ac_file" : 'X\(//\)[^/]' \| \
-        X"$ac_file" : 'X\(//\)$' \| \
-        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$ac_file" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-  as_dir="$ac_dir"; as_fn_mkdir_p
-  ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
-  # A ".." for each directory in $ac_dir_suffix.
-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
-  case $ac_top_builddir_sub in
-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
-  esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
-  .)  # We are building in place.
-    ac_srcdir=.
-    ac_top_srcdir=$ac_top_builddir_sub
-    ac_abs_top_srcdir=$ac_pwd ;;
-  [\\/]* | ?:[\\/]* )  # Absolute name.
-    ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir
-    ac_abs_top_srcdir=$srcdir ;;
-  *) # Relative name.
-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_build_prefix$srcdir
-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-
-  case $ac_mode in
-  :F)
-  #
-  # CONFIG_FILE
-  #
-
-  case $INSTALL in
-  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
-  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
-  esac
-  ac_MKDIR_P=$MKDIR_P
-  case $MKDIR_P in
-  [\\/$]* | ?:[\\/]* ) ;;
-  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
-  esac
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# If the template does not know about datarootdir, expand it.
-# FIXME: This hack should be removed a few years after 2.60.
-ac_datarootdir_hack=; ac_datarootdir_seen=
-ac_sed_dataroot='
-/datarootdir/ {
-  p
-  q
-}
-/@datadir@/p
-/@docdir@/p
-/@infodir@/p
-/@localedir@/p
-/@mandir@/p'
-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
-*datarootdir*) ac_datarootdir_seen=yes;;
-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-  ac_datarootdir_hack='
-  s&@datadir@&$datadir&g
-  s&@docdir@&$docdir&g
-  s&@infodir@&$infodir&g
-  s&@localedir@&$localedir&g
-  s&@mandir@&$mandir&g
-  s&\\\${datarootdir}&$datarootdir&g' ;;
-esac
-_ACEOF
-
-# Neutralize VPATH when `$srcdir' = `.'.
-# Shell code in configure.ac might set extrasub.
-# FIXME: do we really want to maintain this feature?
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_sed_extra="$ac_vpsub
-$extrasub
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-:t
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s|@configure_input@|$ac_sed_conf_input|;t t
-s&@top_builddir@&$ac_top_builddir_sub&;t t
-s&@top_build_prefix@&$ac_top_build_prefix&;t t
-s&@srcdir@&$ac_srcdir&;t t
-s&@abs_srcdir@&$ac_abs_srcdir&;t t
-s&@top_srcdir@&$ac_top_srcdir&;t t
-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
-s&@builddir@&$ac_builddir&;t t
-s&@abs_builddir@&$ac_abs_builddir&;t t
-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
-s&@INSTALL@&$ac_INSTALL&;t t
-s&@MKDIR_P@&$ac_MKDIR_P&;t t
-$ac_datarootdir_hack
-"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
-  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-
-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
-  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
-  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' \
-      "$ac_tmp/out"`; test -z "$ac_out"; } &&
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined" >&5
-$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined" >&2;}
-
-  rm -f "$ac_tmp/stdin"
-  case $ac_file in
-  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
-  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
-  esac \
-  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- ;;
-  :H)
-  #
-  # CONFIG_HEADER
-  #
-  if test x"$ac_file" != x-; then
-    {
-      $as_echo "/* $configure_input  */" \
-      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
-    } >"$ac_tmp/config.h" \
-      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
-$as_echo "$as_me: $ac_file is unchanged" >&6;}
-    else
-      rm -f "$ac_file"
-      mv "$ac_tmp/config.h" "$ac_file" \
-       || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-    fi
-  else
-    $as_echo "/* $configure_input  */" \
-      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
-      || as_fn_error $? "could not create -" "$LINENO" 5
-  fi
-# Compute "$ac_file"'s index in $config_headers.
-_am_arg="$ac_file"
-_am_stamp_count=1
-for _am_header in $config_headers :; do
-  case $_am_header in
-    $_am_arg | $_am_arg:* )
-      break ;;
-    * )
-      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
-  esac
-done
-echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
-$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$_am_arg" : 'X\(//\)[^/]' \| \
-        X"$_am_arg" : 'X\(//\)$' \| \
-        X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$_am_arg" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`/stamp-h$_am_stamp_count
- ;;
-
-  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
-$as_echo "$as_me: executing $ac_file commands" >&6;}
- ;;
-  esac
-
-
-  case $ac_file$ac_mode in
-    "zfs_config.h":H)
-       (mv zfs_config.h zfs_config.h.tmp &&
-       awk -f ${ac_srcdir}/config/config.awk zfs_config.h.tmp >zfs_config.h &&
-       rm zfs_config.h.tmp) || exit 1 ;;
-    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
-  # Older Autoconf quotes --file arguments for eval, but not when files
-  # are listed without --file.  Let's play safe and only enable the eval
-  # if we detect the quoting.
-  case $CONFIG_FILES in
-  *\'*) eval set x "$CONFIG_FILES" ;;
-  *)   set x $CONFIG_FILES ;;
-  esac
-  shift
-  for mf
-  do
-    # Strip MF so we end up with the name of the file.
-    mf=`echo "$mf" | sed -e 's/:.*$//'`
-    # Check whether this is an Automake generated Makefile or not.
-    # We used to match only the files named 'Makefile.in', but
-    # some people rename them; so instead we look at the file content.
-    # Grep'ing the first line is not enough: some people post-process
-    # each Makefile.in and add a new line on top of each file to say so.
-    # Grep'ing the whole file is not good either: AIX grep has a line
-    # limit of 2048, but all sed's we know have understand at least 4000.
-    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
-      dirpart=`$as_dirname -- "$mf" ||
-$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$mf" : 'X\(//\)[^/]' \| \
-        X"$mf" : 'X\(//\)$' \| \
-        X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$mf" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-    else
-      continue
-    fi
-    # Extract the definition of DEPDIR, am__include, and am__quote
-    # from the Makefile without running 'make'.
-    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
-    test -z "$DEPDIR" && continue
-    am__include=`sed -n 's/^am__include = //p' < "$mf"`
-    test -z "$am__include" && continue
-    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
-    # Find all dependency output files, they are included files with
-    # $(DEPDIR) in their names.  We invoke sed twice because it is the
-    # simplest approach to changing $(DEPDIR) to its actual value in the
-    # expansion.
-    for file in `sed -n "
-      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
-        sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
-      # Make sure the directory exists.
-      test -f "$dirpart/$file" && continue
-      fdir=`$as_dirname -- "$file" ||
-$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-        X"$file" : 'X\(//\)[^/]' \| \
-        X"$file" : 'X\(//\)$' \| \
-        X"$file" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$file" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)[^/].*/{
-           s//\1/
-           q
-         }
-         /^X\(\/\/\)$/{
-           s//\1/
-           q
-         }
-         /^X\(\/\).*/{
-           s//\1/
-           q
-         }
-         s/.*/./; q'`
-      as_dir=$dirpart/$fdir; as_fn_mkdir_p
-      # echo "creating $dirpart/$file"
-      echo '# dummy' > "$dirpart/$file"
-    done
-  done
-}
- ;;
-    "libtool":C)
-
-    # See if we are running on zsh, and set the options that allow our
-    # commands through without removal of \ escapes.
-    if test -n "${ZSH_VERSION+set}"; then
-      setopt NO_GLOB_SUBST
-    fi
-
-    cfgfile=${ofile}T
-    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
-    $RM "$cfgfile"
-
-    cat <<_LT_EOF >> "$cfgfile"
-#! $SHELL
-# Generated automatically by $as_me ($PACKAGE) $VERSION
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-
-# Provide generalized library-building support services.
-# Written by Gordon Matzigkeit, 1996
-
-# Copyright (C) 2014 Free Software Foundation, Inc.
-# This is free software; see the source for copying conditions.  There is NO
-# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-# GNU Libtool is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of of the License, or
-# (at your option) any later version.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program or library that is built
-# using GNU Libtool, you may include this file under the  same
-# distribution terms that you use for the rest of that program.
-#
-# GNU Libtool is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-
-# The names of the tagged configurations supported by this script.
-available_tags=''
-
-# Configured defaults for sys_lib_dlsearch_path munging.
-: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
-
-# ### BEGIN LIBTOOL CONFIG
-
-# Which release of libtool.m4 was used?
-macro_version=$macro_version
-macro_revision=$macro_revision
-
-# Whether or not to build shared libraries.
-build_libtool_libs=$enable_shared
-
-# Whether or not to build static libraries.
-build_old_libs=$enable_static
-
-# What type of objects to build.
-pic_mode=$pic_mode
-
-# Whether or not to optimize for fast installation.
-fast_install=$enable_fast_install
-
-# Shared archive member basename,for filename based shared library versioning on AIX.
-shared_archive_member_spec=$shared_archive_member_spec
-
-# Shell to use when invoking shell scripts.
-SHELL=$lt_SHELL
-
-# An echo program that protects backslashes.
-ECHO=$lt_ECHO
-
-# The PATH separator for the build system.
-PATH_SEPARATOR=$lt_PATH_SEPARATOR
-
-# The host system.
-host_alias=$host_alias
-host=$host
-host_os=$host_os
-
-# The build system.
-build_alias=$build_alias
-build=$build
-build_os=$build_os
-
-# A sed program that does not truncate output.
-SED=$lt_SED
-
-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="\$SED -e 1s/^X//"
-
-# A grep program that handles long lines.
-GREP=$lt_GREP
-
-# An ERE matcher.
-EGREP=$lt_EGREP
-
-# A literal string matcher.
-FGREP=$lt_FGREP
-
-# A BSD- or MS-compatible name lister.
-NM=$lt_NM
-
-# Whether we need soft or hard links.
-LN_S=$lt_LN_S
-
-# What is the maximum length of a command?
-max_cmd_len=$max_cmd_len
-
-# Object file suffix (normally "o").
-objext=$ac_objext
-
-# Executable file suffix (normally "").
-exeext=$exeext
-
-# whether the shell understands "unset".
-lt_unset=$lt_unset
-
-# turn spaces into newlines.
-SP2NL=$lt_lt_SP2NL
-
-# turn newlines into spaces.
-NL2SP=$lt_lt_NL2SP
-
-# convert \$build file names to \$host format.
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-
-# convert \$build files to toolchain format.
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-
-# An object symbol dumper.
-OBJDUMP=$lt_OBJDUMP
-
-# Method to check whether dependent libraries are shared objects.
-deplibs_check_method=$lt_deplibs_check_method
-
-# Command to use when deplibs_check_method = "file_magic".
-file_magic_cmd=$lt_file_magic_cmd
-
-# How to find potential files when deplibs_check_method = "file_magic".
-file_magic_glob=$lt_file_magic_glob
-
-# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
-want_nocaseglob=$lt_want_nocaseglob
-
-# DLL creation program.
-DLLTOOL=$lt_DLLTOOL
-
-# Command to associate shared and link libraries.
-sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
-
-# The archiver.
-AR=$lt_AR
-
-# Flags to create an archive.
-AR_FLAGS=$lt_AR_FLAGS
-
-# How to feed a file listing to the archiver.
-archiver_list_spec=$lt_archiver_list_spec
-
-# A symbol stripping program.
-STRIP=$lt_STRIP
-
-# Commands used to install an old-style archive.
-RANLIB=$lt_RANLIB
-old_postinstall_cmds=$lt_old_postinstall_cmds
-old_postuninstall_cmds=$lt_old_postuninstall_cmds
-
-# Whether to use a lock for old archive extraction.
-lock_old_archive_extraction=$lock_old_archive_extraction
-
-# A C compiler.
-LTCC=$lt_CC
-
-# LTCC compiler flags.
-LTCFLAGS=$lt_CFLAGS
-
-# Take the output of nm and produce a listing of raw symbols and C names.
-global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
-
-# Transform the output of nm in a proper C declaration.
-global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
-
-# Transform the output of nm into a list of symbols to manually relocate.
-global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import
-
-# Transform the output of nm in a C name address pair.
-global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
-
-# Transform the output of nm in a C name address pair when lib prefix is needed.
-global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
-
-# The name lister interface.
-nm_interface=$lt_lt_cv_nm_interface
-
-# Specify filename containing input files for \$NM.
-nm_file_list_spec=$lt_nm_file_list_spec
-
-# The root where to search for dependent libraries,and where our libraries should be installed.
-lt_sysroot=$lt_sysroot
-
-# Command to truncate a binary pipe.
-lt_truncate_bin=$lt_lt_cv_truncate_bin
-
-# The name of the directory that contains temporary libtool files.
-objdir=$objdir
-
-# Used to examine libraries when file_magic_cmd begins with "file".
-MAGIC_CMD=$MAGIC_CMD
-
-# Must we lock files when doing compilation?
-need_locks=$lt_need_locks
-
-# Manifest tool.
-MANIFEST_TOOL=$lt_MANIFEST_TOOL
-
-# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
-DSYMUTIL=$lt_DSYMUTIL
-
-# Tool to change global to local symbols on Mac OS X.
-NMEDIT=$lt_NMEDIT
-
-# Tool to manipulate fat objects and archives on Mac OS X.
-LIPO=$lt_LIPO
-
-# ldd/readelf like tool for Mach-O binaries on Mac OS X.
-OTOOL=$lt_OTOOL
-
-# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
-OTOOL64=$lt_OTOOL64
-
-# Old archive suffix (normally "a").
-libext=$libext
-
-# Shared library suffix (normally ".so").
-shrext_cmds=$lt_shrext_cmds
-
-# The commands to extract the exported symbol list from a shared archive.
-extract_expsyms_cmds=$lt_extract_expsyms_cmds
-
-# Variables whose values should be saved in libtool wrapper scripts and
-# restored at link time.
-variables_saved_for_relink=$lt_variables_saved_for_relink
-
-# Do we need the "lib" prefix for modules?
-need_lib_prefix=$need_lib_prefix
-
-# Do we need a version for libraries?
-need_version=$need_version
-
-# Library versioning type.
-version_type=$version_type
-
-# Shared library runtime path variable.
-runpath_var=$runpath_var
-
-# Shared library path variable.
-shlibpath_var=$shlibpath_var
-
-# Is shlibpath searched before the hard-coded library search path?
-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
-
-# Format of library name prefix.
-libname_spec=$lt_libname_spec
-
-# List of archive names.  First name is the real one, the rest are links.
-# The last name is the one that the linker finds with -lNAME
-library_names_spec=$lt_library_names_spec
-
-# The coded name of the library, if different from the real name.
-soname_spec=$lt_soname_spec
-
-# Permission mode override for installation of shared libraries.
-install_override_mode=$lt_install_override_mode
-
-# Command to use after installation of a shared archive.
-postinstall_cmds=$lt_postinstall_cmds
-
-# Command to use after uninstallation of a shared archive.
-postuninstall_cmds=$lt_postuninstall_cmds
-
-# Commands used to finish a libtool library installation in a directory.
-finish_cmds=$lt_finish_cmds
-
-# As "finish_cmds", except a single script fragment to be evaled but
-# not shown.
-finish_eval=$lt_finish_eval
-
-# Whether we should hardcode library paths into libraries.
-hardcode_into_libs=$hardcode_into_libs
-
-# Compile-time system search path for libraries.
-sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
-
-# Detected run-time system search path for libraries.
-sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path
-
-# Explicit LT_SYS_LIBRARY_PATH set during ./configure time.
-configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path
-
-# Whether dlopen is supported.
-dlopen_support=$enable_dlopen
-
-# Whether dlopen of programs is supported.
-dlopen_self=$enable_dlopen_self
-
-# Whether dlopen of statically linked programs is supported.
-dlopen_self_static=$enable_dlopen_self_static
-
-# Commands to strip libraries.
-old_striplib=$lt_old_striplib
-striplib=$lt_striplib
-
-
-# The linker used to build libraries.
-LD=$lt_LD
-
-# How to create reloadable object files.
-reload_flag=$lt_reload_flag
-reload_cmds=$lt_reload_cmds
-
-# Commands used to build an old-style archive.
-old_archive_cmds=$lt_old_archive_cmds
-
-# A language specific compiler.
-CC=$lt_compiler
-
-# Is the compiler the GNU compiler?
-with_gcc=$GCC
-
-# Compiler flag to turn off builtin functions.
-no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
-
-# Additional compiler flags for building library objects.
-pic_flag=$lt_lt_prog_compiler_pic
-
-# How to pass a linker flag through the compiler.
-wl=$lt_lt_prog_compiler_wl
-
-# Compiler flag to prevent dynamic linking.
-link_static_flag=$lt_lt_prog_compiler_static
-
-# Does compiler simultaneously support -c and -o options?
-compiler_c_o=$lt_lt_cv_prog_compiler_c_o
-
-# Whether or not to add -lc for building shared libraries.
-build_libtool_need_lc=$archive_cmds_need_lc
-
-# Whether or not to disallow shared libs when runtime libs are static.
-allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
-
-# Compiler flag to allow reflexive dlopens.
-export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
-
-# Compiler flag to generate shared objects directly from archives.
-whole_archive_flag_spec=$lt_whole_archive_flag_spec
-
-# Whether the compiler copes with passing no objects directly.
-compiler_needs_object=$lt_compiler_needs_object
-
-# Create an old-style archive from a shared archive.
-old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
-
-# Create a temporary old-style archive to link instead of a shared archive.
-old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
-
-# Commands used to build a shared archive.
-archive_cmds=$lt_archive_cmds
-archive_expsym_cmds=$lt_archive_expsym_cmds
-
-# Commands used to build a loadable module if different from building
-# a shared archive.
-module_cmds=$lt_module_cmds
-module_expsym_cmds=$lt_module_expsym_cmds
-
-# Whether we are building with GNU ld or not.
-with_gnu_ld=$lt_with_gnu_ld
-
-# Flag that allows shared libraries with undefined symbols to be built.
-allow_undefined_flag=$lt_allow_undefined_flag
-
-# Flag that enforces no undefined symbols.
-no_undefined_flag=$lt_no_undefined_flag
-
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist
-hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
-
-# Whether we need a single "-rpath" flag with a separated argument.
-hardcode_libdir_separator=$lt_hardcode_libdir_separator
-
-# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
-# DIR into the resulting binary.
-hardcode_direct=$hardcode_direct
-
-# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
-# DIR into the resulting binary and the resulting library dependency is
-# "absolute",i.e impossible to change by setting \$shlibpath_var if the
-# library is relocated.
-hardcode_direct_absolute=$hardcode_direct_absolute
-
-# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
-# into the resulting binary.
-hardcode_minus_L=$hardcode_minus_L
-
-# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
-# into the resulting binary.
-hardcode_shlibpath_var=$hardcode_shlibpath_var
-
-# Set to "yes" if building a shared library automatically hardcodes DIR
-# into the library and all subsequent libraries and executables linked
-# against it.
-hardcode_automatic=$hardcode_automatic
-
-# Set to yes if linker adds runtime paths of dependent libraries
-# to runtime path list.
-inherit_rpath=$inherit_rpath
-
-# Whether libtool must link a program against all its dependency libraries.
-link_all_deplibs=$link_all_deplibs
-
-# Set to "yes" if exported symbols are required.
-always_export_symbols=$always_export_symbols
-
-# The commands to list exported symbols.
-export_symbols_cmds=$lt_export_symbols_cmds
-
-# Symbols that should not be listed in the preloaded symbols.
-exclude_expsyms=$lt_exclude_expsyms
-
-# Symbols that must always be exported.
-include_expsyms=$lt_include_expsyms
-
-# Commands necessary for linking programs (against libraries) with templates.
-prelink_cmds=$lt_prelink_cmds
-
-# Commands necessary for finishing linking programs.
-postlink_cmds=$lt_postlink_cmds
-
-# Specify filename containing input files.
-file_list_spec=$lt_file_list_spec
-
-# How to hardcode a shared library path into an executable.
-hardcode_action=$hardcode_action
-
-# ### END LIBTOOL CONFIG
-
-_LT_EOF
-
-    cat <<'_LT_EOF' >> "$cfgfile"
-
-# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
-
-# func_munge_path_list VARIABLE PATH
-# -----------------------------------
-# VARIABLE is name of variable containing _space_ separated list of
-# directories to be munged by the contents of PATH, which is string
-# having a format:
-# "DIR[:DIR]:"
-#       string "DIR[ DIR]" will be prepended to VARIABLE
-# ":DIR[:DIR]"
-#       string "DIR[ DIR]" will be appended to VARIABLE
-# "DIRP[:DIRP]::[DIRA:]DIRA"
-#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
-#       "DIRA[ DIRA]" will be appended to VARIABLE
-# "DIR[:DIR]"
-#       VARIABLE will be replaced by "DIR[ DIR]"
-func_munge_path_list ()
-{
-    case x$2 in
-    x)
-        ;;
-    *:)
-        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
-        ;;
-    x:*)
-        eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
-        ;;
-    *::*)
-        eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
-        eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
-        ;;
-    *)
-        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
-        ;;
-    esac
-}
-
-
-# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
-func_cc_basename ()
-{
-    for cc_temp in $*""; do
-      case $cc_temp in
-        compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
-        distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
-        \-*) ;;
-        *) break;;
-      esac
-    done
-    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
-}
-
-
-# ### END FUNCTIONS SHARED WITH CONFIGURE
-
-_LT_EOF
-
-  case $host_os in
-  aix3*)
-    cat <<\_LT_EOF >> "$cfgfile"
-# AIX sometimes has problems with the GCC collect2 program.  For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test set != "${COLLECT_NAMES+set}"; then
-  COLLECT_NAMES=
-  export COLLECT_NAMES
-fi
-_LT_EOF
-    ;;
-  esac
-
-
-ltmain=$ac_aux_dir/ltmain.sh
-
-
-  # We use sed instead of cat because bash on DJGPP gets confused if
-  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
-  # text mode, it properly converts lines to CR/LF.  This bash problem
-  # is reportedly fixed, but why not run on old versions too?
-  sed '$q' "$ltmain" >> "$cfgfile" \
-     || (rm -f "$cfgfile"; exit 1)
-
-   mv -f "$cfgfile" "$ofile" ||
-    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
-  chmod +x "$ofile"
-
- ;;
-
-  esac
-done # for ac_tag
-
-
-as_fn_exit 0
-_ACEOF
-ac_clean_files=$ac_clean_files_save
-
-test $ac_write_fail = 0 ||
-  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
-
-
-# configure is writing to config.log, and then calls config.status.
-# config.status does its own redirection, appending to config.log.
-# Unfortunately, on DOS this fails, as config.log is still kept open
-# by configure, so config.status won't be able to write to it; its
-# output is simply discarded.  So we exec the FD to /dev/null,
-# effectively closing config.log, so it can be properly (re)opened and
-# appended to by config.status.  When coming back to configure, we
-# need to make the FD available again.
-if test "$no_create" != yes; then
-  ac_cs_success=:
-  ac_config_status_args=
-  test "$silent" = yes &&
-    ac_config_status_args="$ac_config_status_args --quiet"
-  exec 5>/dev/null
-  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
-  exec 5>>config.log
-  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
-  # would make configure fail if this is the last instruction.
-  $ac_cs_success || as_fn_exit 1
-fi
-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
-fi
-
index 9907857e2e12844f78a26a61433f19a5827c2a3c..39bd54c17bcd0930b569fc33277f2de316fcea1e 100644 (file)
@@ -39,7 +39,7 @@ AC_CONFIG_MACRO_DIR([config])
 AC_CANONICAL_SYSTEM
 AM_MAINTAINER_MODE
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
-AM_INIT_AUTOMAKE
+AM_INIT_AUTOMAKE([subdir-objects])
 AC_CONFIG_HEADERS([zfs_config.h], [
        (mv zfs_config.h zfs_config.h.tmp &&
        awk -f ${ac_srcdir}/config/config.awk zfs_config.h.tmp >zfs_config.h &&
@@ -49,6 +49,7 @@ AC_PROG_INSTALL
 AC_PROG_CC
 AC_PROG_LIBTOOL
 AM_PROG_AS
+AM_PROG_CC_C_O
 
 ZFS_AC_LICENSE
 ZFS_AC_PACKAGE
@@ -56,7 +57,7 @@ ZFS_AC_CONFIG
 ZFS_AC_DEBUG
 ZFS_AC_DEBUG_DMU_TX
 
-AC_CONFIG_FILES([ 
+AC_CONFIG_FILES([
        Makefile
        udev/Makefile
        udev/rules.d/Makefile
@@ -80,11 +81,11 @@ AC_CONFIG_FILES([
        lib/libspl/include/ia32/sys/Makefile
        lib/libspl/include/rpc/Makefile
        lib/libspl/include/sys/Makefile
-       lib/libspl/include/sys/sysevent/Makefile
        lib/libspl/include/sys/dktp/Makefile
        lib/libspl/include/util/Makefile
        lib/libavl/Makefile
        lib/libefi/Makefile
+       lib/libicp/Makefile
        lib/libnvpair/Makefile
        lib/libunicode/Makefile
        lib/libuutil/Makefile
@@ -111,9 +112,11 @@ AC_CONFIG_FILES([
        cmd/dbufstat/Makefile
        cmd/arc_summary/Makefile
        cmd/zed/Makefile
+       cmd/raidz_test/Makefile
        contrib/Makefile
        contrib/bash_completion.d/Makefile
        contrib/dracut/Makefile
+       contrib/dracut/02zfsexpandknowledge/Makefile
        contrib/dracut/90zfs/Makefile
        contrib/initramfs/Makefile
        module/Makefile
@@ -123,17 +126,168 @@ AC_CONFIG_FILES([
        module/zcommon/Makefile
        module/zfs/Makefile
        module/zpios/Makefile
+       module/icp/Makefile
        include/Makefile
        include/linux/Makefile
        include/sys/Makefile
        include/sys/fs/Makefile
        include/sys/fm/Makefile
        include/sys/fm/fs/Makefile
+       include/sys/crypto/Makefile
+       include/sys/sysevent/Makefile
        scripts/Makefile
        scripts/zpios-profile/Makefile
        scripts/zpios-test/Makefile
        scripts/zpool-config/Makefile
        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/checksum/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/large_dnode/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/raidz/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/upgrade/Makefile
+       tests/zfs-tests/tests/functional/vdev_zaps/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/perf/Makefile
+       tests/zfs-tests/tests/perf/fio/Makefile
+       tests/zfs-tests/tests/perf/regression/Makefile
+       tests/zfs-tests/tests/perf/scripts/Makefile
+       tests/zfs-tests/tests/stress/Makefile
        rpm/Makefile
        rpm/redhat/Makefile
        rpm/redhat/zfs.spec
@@ -147,4 +301,10 @@ AC_CONFIG_FILES([
        zfs.release
 ])
 
+
 AC_OUTPUT
+
+AS_IF([test "x$user_libdevmapper" != xyes && test "$ZFS_CONFIG" != kernel ], [
+    AC_MSG_WARN([Building without libdevmapper.  Auto-replace, auto-online, \
+and statechange-led.sh may not work correctly with device mapper vdevs.])
+])
diff --git a/zfs/contrib/Makefile.in b/zfs/contrib/Makefile.in
deleted file mode 100644 (file)
index b110fed..0000000
+++ /dev/null
@@ -1,781 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = contrib
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-       ctags-recursive dvi-recursive html-recursive info-recursive \
-       install-data-recursive install-dvi-recursive \
-       install-exec-recursive install-html-recursive \
-       install-info-recursive install-pdf-recursive \
-       install-ps-recursive install-recursive installcheck-recursive \
-       installdirs-recursive pdf-recursive ps-recursive \
-       tags-recursive uninstall-recursive
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-       distdir
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-SUBDIRS = bash_completion.d dracut initramfs
-DIST_SUBDIRS = bash_completion.d dracut initramfs
-all: all-recursive
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu contrib/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-       @fail=; \
-       if $(am__make_keepgoing); then \
-         failcom='fail=yes'; \
-       else \
-         failcom='exit 1'; \
-       fi; \
-       dot_seen=no; \
-       target=`echo $@ | sed s/-recursive//`; \
-       case "$@" in \
-         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-         *) list='$(SUBDIRS)' ;; \
-       esac; \
-       for subdir in $$list; do \
-         echo "Making $$target in $$subdir"; \
-         if test "$$subdir" = "."; then \
-           dot_seen=yes; \
-           local_target="$$target-am"; \
-         else \
-           local_target="$$target"; \
-         fi; \
-         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-         || eval $$failcom; \
-       done; \
-       if test "$$dot_seen" = "no"; then \
-         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-       fi; test -z "$$fail"
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-         include_option=--etags-include; \
-         empty_fix=.; \
-       else \
-         include_option=--include; \
-         empty_fix=; \
-       fi; \
-       list='$(SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           test ! -f $$subdir/TAGS || \
-             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-         fi; \
-       done; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-ctags: ctags-recursive
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-recursive
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           $(am__make_dryrun) \
-             || test -d "$(distdir)/$$subdir" \
-             || $(MKDIR_P) "$(distdir)/$$subdir" \
-             || exit 1; \
-           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-           $(am__relativize); \
-           new_distdir=$$reldir; \
-           dir1=$$subdir; dir2="$(top_distdir)"; \
-           $(am__relativize); \
-           new_top_distdir=$$reldir; \
-           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-           ($(am__cd) $$subdir && \
-             $(MAKE) $(AM_MAKEFLAGS) \
-               top_distdir="$$new_top_distdir" \
-               distdir="$$new_distdir" \
-               am__remove_distdir=: \
-               am__skip_length_check=: \
-               am__skip_mode_fix=: \
-               distdir) \
-             || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-recursive
-all-am: Makefile
-installdirs: installdirs-recursive
-installdirs-am:
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-recursive
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-recursive
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-recursive
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-tags
-
-dvi: dvi-recursive
-
-dvi-am:
-
-html: html-recursive
-
-html-am:
-
-info: info-recursive
-
-info-am:
-
-install-data-am:
-
-install-dvi: install-dvi-recursive
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-recursive
-
-install-html-am:
-
-install-info: install-info-recursive
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-recursive
-
-install-pdf-am:
-
-install-ps: install-ps-recursive
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-recursive
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-recursive
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-recursive
-
-pdf-am:
-
-ps: ps-recursive
-
-ps-am:
-
-uninstall-am:
-
-.MAKE: $(am__recursive_targets) install-am install-strip
-
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
-       check-am clean clean-generic clean-libtool cscopelist-am ctags \
-       ctags-am distclean distclean-generic distclean-libtool \
-       distclean-tags distdir dvi dvi-am html html-am info info-am \
-       install install-am install-data install-data-am install-dvi \
-       install-dvi-am install-exec install-exec-am install-html \
-       install-html-am install-info install-info-am install-man \
-       install-pdf install-pdf-am install-ps install-ps-am \
-       install-strip installcheck installcheck-am installdirs \
-       installdirs-am maintainer-clean maintainer-clean-generic \
-       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
-       ps ps-am tags tags-am uninstall uninstall-am
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/zfs/contrib/bash_completion.d/Makefile.in b/zfs/contrib/bash_completion.d/Makefile.in
deleted file mode 100644 (file)
index e6faaee..0000000
+++ /dev/null
@@ -1,605 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = contrib/bash_completion.d
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-DATA = $(noinst_DATA)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-bashcompletiondir = $(sysconfdir)/bash_completion.d
-noinst_DATA = zfs
-EXTRA_DIST = $(noinst_DATA)
-all: all-am
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/bash_completion.d/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu contrib/bash_completion.d/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-tags TAGS:
-
-ctags CTAGS:
-
-cscope cscopelist:
-
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-am
-all-am: Makefile $(DATA)
-installdirs:
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-am
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am:
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am:
-
-.MAKE: install-am install-strip
-
-.PHONY: all all-am check check-am clean clean-generic clean-libtool \
-       cscopelist-am ctags-am distclean distclean-generic \
-       distclean-libtool distdir dvi dvi-am html html-am info info-am \
-       install install-am install-data install-data-am install-dvi \
-       install-dvi-am install-exec install-exec-am install-html \
-       install-html-am install-info install-info-am install-man \
-       install-pdf install-pdf-am install-ps install-ps-am \
-       install-strip installcheck installcheck-am installdirs \
-       maintainer-clean maintainer-clean-generic mostlyclean \
-       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-       tags-am uninstall uninstall-am
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/zfs/contrib/dracut/02zfsexpandknowledge/Makefile.am b/zfs/contrib/dracut/02zfsexpandknowledge/Makefile.am
new file mode 100644 (file)
index 0000000..a5c567c
--- /dev/null
@@ -0,0 +1,22 @@
+pkgdracutdir = $(dracutdir)/modules.d/02zfsexpandknowledge
+pkgdracut_SCRIPTS = \
+       module-setup.sh
+
+EXTRA_DIST = \
+       $(top_srcdir)/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in
+
+$(pkgdracut_SCRIPTS):%:%.in
+       -$(SED) -e 's,@bindir\@,$(bindir),g' \
+               -e 's,@sbindir\@,$(sbindir),g' \
+               -e 's,@datadir\@,$(datadir),g' \
+               -e 's,@dracutdir\@,$(dracutdir),g' \
+               -e 's,@udevdir\@,$(udevdir),g' \
+               -e 's,@udevruledir\@,$(udevruledir),g' \
+               -e 's,@sysconfdir\@,$(sysconfdir),g' \
+               $< >'$@'
+
+clean-local::
+       -$(RM) $(pkgdracut_SCRIPTS)
+
+distclean-local::
+       -$(RM) $(pkgdracut_SCRIPTS)
diff --git a/zfs/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in b/zfs/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in
new file mode 100755 (executable)
index 0000000..e694ae0
--- /dev/null
@@ -0,0 +1,135 @@
+#!/bin/sh
+
+get_devtype() {
+  local typ
+  typ=$(udevadm info --query=property --name="$1" | grep "^ID_FS_TYPE=" | sed 's|^ID_FS_TYPE=||')
+  if [ "$typ" = "" ] ; then
+     typ=$(blkid -c /dev/null "$1" -o value -s TYPE)
+  fi
+  echo "$typ"
+}
+
+get_pool_devices() {
+  # also present in 99zfssystemd
+  local poolconfigtemp
+  local poolconfigoutput
+  local pooldev
+  local prefix
+  local resolved
+  poolconfigtemp=`mktemp`
+  @sbindir@/zpool list -v -H -P "$1" > "$poolconfigtemp" 2>&1
+  if [ "$?" != "0" ] ; then
+    poolconfigoutput=$(cat "$poolconfigtemp")
+    dinfo "zfsexpandknowledge: pool $1 cannot be listed: $poolconfigoutput"
+  else
+    while read pooldev ; do
+        if [ -n "$pooldev" -a -e "$pooldev" ] ; then
+          if [ -h "$pooldev" ] ; then
+              resolved=`readlink -f "$pooldev"`
+          else
+              resolved="$pooldev"
+          fi
+          dinfo "zfsexpandknowledge: pool $1 has device $pooldev (which resolves to $resolved)"
+          echo "$resolved"
+        fi
+    done < <(cat "$poolconfigtemp" |  awk -F '\t' '/\t\/dev/ { print $2 }')
+  fi
+  rm -f "$poolconfigtemp"
+}
+
+find_zfs_block_devices() {
+    local dev
+    local blockdev
+    local mp
+    local fstype
+    local pool
+    local key
+    local n
+    local poolconfigoutput
+    numfields=`head -1 /proc/self/mountinfo | awk '{print NF}'`
+    if [ "$numfields" == "10" ] ; then
+        fields="n n n n mp n n fstype dev n"
+    else
+        fields="n n n n mp n n n fstype dev n"
+    fi
+    while read $fields ; do
+       if [ "$fstype" != "zfs" ]; then continue ; fi
+       if [ "$mp" == "$1" ]; then
+           pool=$(echo "$dev" | cut -d / -f 1)
+           get_pool_devices "$pool"
+       fi
+    done < /proc/self/mountinfo
+}
+
+array_contains () {
+  local e
+  for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
+  return 1
+}
+
+check() {
+    local mp
+    local dev
+    local blockdevs
+    local fstype
+    local majmin
+    local _slavedev
+    local _slavedevname
+    local _slavedevtype
+    local _slavemajmin
+    local _dev
+
+if [[ $hostonly ]]; then
+
+    for mp in \
+        "/" \
+        "/etc" \
+        "/bin" \
+        "/sbin" \
+        "/lib" \
+        "/lib64" \
+        "/usr" \
+        "/usr/bin" \
+        "/usr/sbin" \
+        "/usr/lib" \
+        "/usr/lib64" \
+        "/boot";
+    do
+        mp=$(readlink -f "$mp")
+        mountpoint "$mp" >/dev/null 2>&1 || continue
+        blockdevs=$(find_zfs_block_devices "$mp")
+        if [ -z "$blockdevs" ] ; then continue ; fi
+        dinfo "zfsexpandknowledge: block devices backing ZFS dataset $mp: $blockdevs"
+        for dev in $blockdevs
+        do
+            array_contains "$dev" "${host_devs[@]}" || host_devs+=("$dev")
+            fstype=$(get_devtype "$dev")
+            host_fs_types["$dev"]="$fstype"
+            majmin=$(get_maj_min "$dev")
+            if [[ -d /sys/dev/block/$majmin/slaves ]] ; then
+                for _slavedev in /sys/dev/block/$majmin/slaves/*; do
+                    [[ -f $_slavedev/dev ]] || continue
+                    _slavedev=/dev/$(basename "$_slavedev")
+                    _slavedevname=$(udevadm info --query=property --name="$_slavedev" | grep "^DEVNAME=" | sed 's|^DEVNAME=||')
+                    _slavedevtype=$(get_devtype "$_slavedevname")
+                    _slavemajmin=$(get_maj_min "$_slavedevname")
+                    dinfo "zfsexpandknowledge: slave block device backing ZFS dataset $mp: $_slavedevname"
+                    array_contains "$_slavedevname" "${host_devs[@]}" || host_devs+=("$_slavedevname")
+                    host_fs_types["$_slavedevname"]="$_slavedevtype"
+                done
+            fi
+        done
+    done
+    for a in "${host_devs[@]}"
+        do
+        dinfo "zfsexpandknowledge: host device $a"
+    done
+    for a in "${!host_fs_types[@]}"
+        do
+        dinfo "zfsexpandknowledge: device $a of type ${host_fs_types[$a]}"
+    done
+
+fi
+
+return 1
+}
index b778a274486e68b73e9278710b68d79449c9ddc2..243a5200fa1e9ffa3b50519bb785336e8e5bc507 100644 (file)
@@ -4,6 +4,8 @@ pkgdracut_SCRIPTS = \
        module-setup.sh \
        mount-zfs.sh \
        parse-zfs.sh \
+       zfs-generator.sh \
+       zfs-needshutdown.sh \
        zfs-lib.sh
 
 EXTRA_DIST = \
@@ -11,15 +13,18 @@ EXTRA_DIST = \
        $(top_srcdir)/contrib/dracut/90zfs/module-setup.sh.in \
        $(top_srcdir)/contrib/dracut/90zfs/mount-zfs.sh.in \
        $(top_srcdir)/contrib/dracut/90zfs/parse-zfs.sh.in \
+       $(top_srcdir)/contrib/dracut/90zfs/zfs-generator.sh.in \
+       $(top_srcdir)/contrib/dracut/90zfs/zfs-needshutdown.sh.in \
        $(top_srcdir)/contrib/dracut/90zfs/zfs-lib.sh.in
 
-$(pkgdracut_SCRIPTS):
+$(pkgdracut_SCRIPTS):%:%.in
        -$(SED) -e 's,@bindir\@,$(bindir),g' \
                -e 's,@sbindir\@,$(sbindir),g' \
                -e 's,@udevdir\@,$(udevdir),g' \
                -e 's,@udevruledir\@,$(udevruledir),g' \
                -e 's,@sysconfdir\@,$(sysconfdir),g' \
-               "$(top_srcdir)/contrib/dracut/90zfs/$@.in" >'$@'
+               -e 's,@systemdunitdir\@,$(systemdunitdir),g' \
+               $< >'$@'
 
 distclean-local::
        -$(RM) $(pkgdracut_SCRIPTS)
diff --git a/zfs/contrib/dracut/90zfs/Makefile.in b/zfs/contrib/dracut/90zfs/Makefile.in
deleted file mode 100644 (file)
index eee7e4c..0000000
+++ /dev/null
@@ -1,695 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = contrib/dracut/90zfs
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(pkgdracutdir)"
-SCRIPTS = $(pkgdracut_SCRIPTS)
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-pkgdracutdir = $(dracutdir)/modules.d/90zfs
-pkgdracut_SCRIPTS = \
-       export-zfs.sh \
-       module-setup.sh \
-       mount-zfs.sh \
-       parse-zfs.sh \
-       zfs-lib.sh
-
-EXTRA_DIST = \
-       $(top_srcdir)/contrib/dracut/90zfs/export-zfs.sh.in \
-       $(top_srcdir)/contrib/dracut/90zfs/module-setup.sh.in \
-       $(top_srcdir)/contrib/dracut/90zfs/mount-zfs.sh.in \
-       $(top_srcdir)/contrib/dracut/90zfs/parse-zfs.sh.in \
-       $(top_srcdir)/contrib/dracut/90zfs/zfs-lib.sh.in
-
-all: all-am
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/dracut/90zfs/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu contrib/dracut/90zfs/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-install-pkgdracutSCRIPTS: $(pkgdracut_SCRIPTS)
-       @$(NORMAL_INSTALL)
-       @list='$(pkgdracut_SCRIPTS)'; test -n "$(pkgdracutdir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(pkgdracutdir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(pkgdracutdir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
-       done | \
-       sed -e 'p;s,.*/,,;n' \
-           -e 'h;s|.*|.|' \
-           -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
-       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
-         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
-           if ($$2 == $$4) { files[d] = files[d] " " $$1; \
-             if (++n[d] == $(am__install_max)) { \
-               print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
-           else { print "f", d "/" $$4, $$1 } } \
-         END { for (d in files) print "f", d, files[d] }' | \
-       while read type dir files; do \
-            if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
-            test -z "$$files" || { \
-              echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pkgdracutdir)$$dir'"; \
-              $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pkgdracutdir)$$dir" || exit $$?; \
-            } \
-       ; done
-
-uninstall-pkgdracutSCRIPTS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(pkgdracut_SCRIPTS)'; test -n "$(pkgdracutdir)" || exit 0; \
-       files=`for p in $$list; do echo "$$p"; done | \
-              sed -e 's,.*/,,;$(transform)'`; \
-       dir='$(DESTDIR)$(pkgdracutdir)'; $(am__uninstall_files_from_dir)
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-tags TAGS:
-
-ctags CTAGS:
-
-cscope cscopelist:
-
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-am
-all-am: Makefile $(SCRIPTS)
-installdirs:
-       for dir in "$(DESTDIR)$(pkgdracutdir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-am
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-local
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-pkgdracutSCRIPTS
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-pkgdracutSCRIPTS
-
-.MAKE: install-am install-strip
-
-.PHONY: all all-am check check-am clean clean-generic clean-libtool \
-       cscopelist-am ctags-am distclean distclean-generic \
-       distclean-libtool distclean-local distdir dvi dvi-am html \
-       html-am info info-am install install-am install-data \
-       install-data-am install-dvi install-dvi-am install-exec \
-       install-exec-am install-html install-html-am install-info \
-       install-info-am install-man install-pdf install-pdf-am \
-       install-pkgdracutSCRIPTS install-ps install-ps-am \
-       install-strip installcheck installcheck-am installdirs \
-       maintainer-clean maintainer-clean-generic mostlyclean \
-       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-       tags-am uninstall uninstall-am uninstall-pkgdracutSCRIPTS
-
-.PRECIOUS: Makefile
-
-
-$(pkgdracut_SCRIPTS):
-       -$(SED) -e 's,@bindir\@,$(bindir),g' \
-               -e 's,@sbindir\@,$(sbindir),g' \
-               -e 's,@udevdir\@,$(udevdir),g' \
-               -e 's,@udevruledir\@,$(udevruledir),g' \
-               -e 's,@sysconfdir\@,$(sysconfdir),g' \
-               "$(top_srcdir)/contrib/dracut/90zfs/$@.in" >'$@'
-
-distclean-local::
-       -$(RM) $(pkgdracut_SCRIPTS)
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index 393753fbf6abe8017f4e476c79a86745136fa889..8747c1cbce79405ec9f4409a15a5eb553d7e188f 100755 (executable)
@@ -4,18 +4,19 @@
 
 _do_zpool_export() {
        local ret=0
+       local errs=""
        local final="${1}"
-       local opts=""
 
-       if [ "x${final}" != "x" ]; then
-               opts="-f"
+       info "ZFS: Exporting ZFS storage pools..."
+       errs=$(export_all -F 2>&1)
+       ret=$?
+       [ -z "${errs}" ] || echo "${errs}" | vwarn
+       if [ "x${ret}" != "x0" ]; then
+               info "ZFS: There was a problem exporting pools."
        fi
 
-       info "Exporting ZFS storage pools."
-       export_all ${opts} || ret=$?
-
        if [ "x${final}" != "x" ]; then
-               info "zpool list"
+               info "ZFS: pool list"
                zpool list 2>&1 | vinfo
        fi
 
index 9eb9f576521a1b7a71ab2c88e6c2b98a43e569f7..a653b50f4bc6d47b6b537ed04fe60e967be85cc1 100755 (executable)
@@ -5,8 +5,11 @@ check() {
        [ "${1}" = "-d" ] && return 0
 
        # Verify the zfs tool chain
-       which zpool >/dev/null 2>&1 || return 1
-       which zfs >/dev/null 2>&1 || return 1
+       for tool in "@sbindir@/zpool" "@sbindir@/zfs" "@sbindir@/mount.zfs" ; do
+               test -x "$tool" || return 1
+       done
+       # Verify grep exists
+       which grep >/dev/null 2>&1 || return 1
 
        return 0
 }
@@ -31,25 +34,42 @@ install() {
        inst_rules @udevruledir@/90-zfs.rules
        inst_rules @udevruledir@/69-vdev.rules
        inst_rules @udevruledir@/60-zvol.rules
+       dracut_install hostid
+       dracut_install grep
        dracut_install @sbindir@/zfs
        dracut_install @sbindir@/zpool
+       # Workaround for zfsonlinux/zfs#4749 by ensuring libgcc_s.so(.1) is included
+       if [[ -n "$(ldd @sbindir@/zpool | grep -F 'libgcc_s.so')" ]]; then
+               # Dracut will have already tracked and included it
+               :;
+       elif command -v gcc-config 2>&1 1>/dev/null; then
+               # On systems with gcc-config (Gentoo, Funtoo, etc.):
+               # Use the current profile to resolve the appropriate path
+               dracut_install "/usr/lib/gcc/$(s=$(gcc-config -c); echo ${s%-*}/${s##*-})/libgcc_s.so.1"
+       else
+               # Fallback: Guess the path and include all matches
+               dracut_install /usr/lib/gcc/*/*/libgcc_s.so*
+       fi
+       dracut_install @sbindir@/mount.zfs
        dracut_install @udevdir@/vdev_id
        dracut_install @udevdir@/zvol_id
-       dracut_install mount.zfs
-       dracut_install hostid
-       dracut_install awk
-       dracut_install head
        inst_hook cmdline 95 "${moddir}/parse-zfs.sh"
+       if [ -n "$systemdutildir" ] ; then
+               inst_script "${moddir}/zfs-generator.sh" "$systemdutildir"/system-generators/dracut-zfs-generator
+       fi
        inst_hook mount 98 "${moddir}/mount-zfs.sh"
-       inst_hook shutdown 30 "${moddir}/export-zfs.sh"
+       inst_hook cleanup 99 "${moddir}/zfs-needshutdown.sh"
+       inst_hook shutdown 20 "${moddir}/export-zfs.sh"
 
        inst_simple "${moddir}/zfs-lib.sh" "/lib/dracut-zfs-lib.sh"
        if [ -e @sysconfdir@/zfs/zpool.cache ]; then
                inst @sysconfdir@/zfs/zpool.cache
+               type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/zpool.cache
        fi
 
        if [ -e @sysconfdir@/zfs/vdev_id.conf ]; then
                inst @sysconfdir@/zfs/vdev_id.conf
+               type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/vdev_id.conf
        fi
 
        # Synchronize initramfs and system hostid
@@ -58,4 +78,15 @@ install() {
        CC=`hostid | cut -b 5,6`
        DD=`hostid | cut -b 7,8`
        printf "\x${DD}\x${CC}\x${BB}\x${AA}" > "${initdir}/etc/hostid"
+
+       if dracut_module_included "systemd"; then
+               mkdir -p "${initdir}/$systemdsystemunitdir/initrd.target.wants"
+               for _item in scan cache ; do
+                       dracut_install @systemdunitdir@/zfs-import-$_item.service
+                       if ! [ -L "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import-$_item.service ]; then
+                               ln -s ../zfs-import-$_item.service "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import-$_item.service
+                               type mark_hostonly >/dev/null 2>&1 && mark_hostonly @systemdunitdir@/zfs-import-$_item.service
+                       fi
+               done
+       fi
 }
index 2abc8766b512d3c01bc5e0410e4aa7ad6c21ac16..e7f217736e24b6ac391d44c7ffacc54579ef5f35 100755 (executable)
@@ -10,6 +10,29 @@ case "${root}" in
        *) return ;;
 esac
 
+GENERATOR_FILE=/run/systemd/generator/sysroot.mount
+GENERATOR_EXTENSION=/run/systemd/generator/sysroot.mount.d/zfs-enhancement.conf
+
+if [ -e "$GENERATOR_FILE" -a -e "$GENERATOR_EXTENSION" ] ; then
+       # If the ZFS sysroot.mount flag exists, the initial RAM disk configured
+       # it to mount ZFS on root.  In that case, we bail early.  This flag
+       # file gets created by the zfs-generator program upon successful run.
+       info "ZFS: There is a sysroot.mount and zfs-generator has extended it."
+       info "ZFS: Delegating root mount to sysroot.mount."
+       # Let us tell the initrd to run on shutdown.
+       # We have a shutdown hook to run
+       # because we imported the pool.
+       # We now prevent Dracut from running this thing again.
+       for zfsmounthook in "$hookdir"/mount/*zfs* ; do
+               if [ -f "$zfsmounthook" ] ; then
+                       rm -f "$zfsmounthook"
+               fi
+       done
+       return
+fi
+info "ZFS: No sysroot.mount exists or zfs-generator did not extend it."
+info "ZFS: Mounting root with the traditional mount-zfs.sh instead."
+
 # Delay until all required block devices are present.
 udevadm settle
 
@@ -20,7 +43,7 @@ if [ "${root}" = "zfs:AUTO" ] ; then
                ZFS_DATASET="$(find_bootfs)"
                if [ $? -ne 0 ] ; then
                        warn "ZFS: No bootfs attribute found in importable pools."
-                       export_all || export_all "-f"
+                       export_all -F
 
                        rootok=0
                        return 1
@@ -33,6 +56,9 @@ ZFS_DATASET="${ZFS_DATASET:-${root#zfs:}}"
 ZFS_POOL="${ZFS_DATASET%%/*}"
 
 if import_pool "${ZFS_POOL}" ; then
+       # Let us tell the initrd to run on shutdown.
+       # We have a shutdown hook to run
+       # because we imported the pool.
        info "ZFS: Mounting dataset ${ZFS_DATASET}..."
        if mount_dataset "${ZFS_DATASET}" ; then
                ROOTFS_MOUNTED=yes
@@ -41,4 +67,3 @@ if import_pool "${ZFS_POOL}" ; then
 fi
 
 rootok=0
-need_shutdown
index c305c782174b094b3aa1dd49a42f94efb819e706..6ca3165f45e4f130f4cd9fc1a062c9766addeeb8 100755 (executable)
@@ -55,5 +55,9 @@ esac
 # modules to settle before mounting.
 if [ ${wait_for_zfs} -eq 1 ]; then
        ln -s /dev/null /dev/root 2>/dev/null
-       echo '[ -e /dev/zfs ]' > "${hookdir}/initqueue/finished/zfs.sh"
+       initqueuedir="${hookdir}/initqueue/finished"
+       test -d "${initqueuedir}" || {
+               initqueuedir="${hookdir}/initqueue-finished"
+       }
+       echo '[ -e /dev/zfs ]' > "${initqueuedir}/zfs.sh"
 fi
diff --git a/zfs/contrib/dracut/90zfs/zfs-generator.sh.in b/zfs/contrib/dracut/90zfs/zfs-generator.sh.in
new file mode 100755 (executable)
index 0000000..c6384f5
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+echo "zfs-generator: starting" >> /dev/kmsg
+
+GENERATOR_DIR="$1"
+[ -n "$GENERATOR_DIR" ] || {
+    echo "zfs-generator: no generator directory specified, exiting" >> /dev/kmsg
+    exit 1
+}
+
+[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
+[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh
+
+type getarg >/dev/null 2>&1 || {
+    echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg
+    . "$dracutlib"
+}
+
+[ -z "$root" ]       && root=$(getarg root=)
+[ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=)
+[ -z "$rootflags" ]  && rootflags=$(getarg rootflags=)
+
+# If root is not ZFS= or zfs: or rootfstype is not zfs
+# then we are not supposed to handle it.
+[ "${root##zfs:}" = "${root}" -a "${root##ZFS=}" = "${root}" -a "$rootfstype" != "zfs" ] && exit 0
+# If root is set to zfs:AUTO, then we are also not
+# supposed to handle it, and it should be handled
+# by the traditional Dracut mount hook.
+# See https://github.com/zfsonlinux/zfs/pull/4558#discussion_r61118952
+if [ "${root}" = "zfs:AUTO" ] ; then
+  exit 0
+fi
+
+rootfstype=zfs
+if echo "${rootflags}" | grep -Eq '^zfsutil$|^zfsutil,|,zfsutil$|,zfsutil,' ; then
+    true
+elif test -n "${rootflags}" ; then
+    rootflags="zfsutil,${rootflags}"
+else
+    rootflags=zfsutil
+fi
+
+root="${root##zfs:}"
+root="${root##ZFS=}"
+
+echo "zfs-generator: writing extension for sysroot.mount to $GENERATOR_DIR"/sysroot.mount.d/zfs-enhancement.conf >> /dev/kmsg
+
+[ -d "$GENERATOR_DIR" ] || mkdir "$GENERATOR_DIR"
+[ -d "$GENERATOR_DIR"/sysroot.mount.d ] || mkdir "$GENERATOR_DIR"/sysroot.mount.d
+
+{
+    echo "[Unit]"
+    echo "Before=initrd-root-fs.target"
+    echo "After=zfs-import-scan.service"
+    echo "After=zfs-import-cache.service"
+    echo "[Mount]"
+    echo "What=${root}"
+    echo "Type=${rootfstype}"
+    echo "Options=${rootflags}"
+} > "$GENERATOR_DIR"/sysroot.mount.d/zfs-enhancement.conf
+
+[ -d "$GENERATOR_DIR"/initrd-root-fs.target.requires ] || mkdir -p "$GENERATOR_DIR"/initrd-root-fs.target.requires
+ln -s ../sysroot.mount "$GENERATOR_DIR"/initrd-root-fs.target.requires/sysroot.mount
+
+echo "zfs-generator: finished" >> /dev/kmsg
index 1c223befd0ed9a312aea464d4374de344d0e47a6..c988dfe606a53c2c7acaa70c83e0d38f6827b0d4 100755 (executable)
@@ -1,6 +1,24 @@
 #!/bin/sh
 
 command -v getarg >/dev/null || . /lib/dracut-lib.sh
+command -v getargbool >/dev/null || {
+    # Compatibility with older Dracut versions.
+    # With apologies to the Dracut developers.
+    getargbool() {
+        local _b
+        unset _b
+        local _default
+        _default="$1"; shift
+        _b=$(getarg "$@")
+        [ $? -ne 0 -a -z "$_b" ] && _b="$_default"
+        if [ -n "$_b" ]; then
+            [ $_b = "0" ] && return 1
+            [ $_b = "no" ] && return 1
+            [ $_b = "off" ] && return 1
+        fi
+        return 0
+    }
+}
 
 OLDIFS="${IFS}"
 NEWLINE="
@@ -72,7 +90,7 @@ mount_dataset() {
 # export_all OPTS
 #   exports all imported zfs pools.
 export_all() {
-       local opts="${1}"
+       local opts="${@}"
        local ret=0
 
        IFS="${NEWLINE}"
diff --git a/zfs/contrib/dracut/90zfs/zfs-needshutdown.sh.in b/zfs/contrib/dracut/90zfs/zfs-needshutdown.sh.in
new file mode 100644 (file)
index 0000000..e3d1b59
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
+
+if zpool list 2>&1 | grep -q 'no pools available' ; then
+    info "ZFS: No active pools, no need to export anything."
+else
+    info "ZFS: There is an active pool, will export it."
+    need_shutdown
+fi
index 35b88c36fbc0db018a698d775fae7f77402cc4db..1065e5e94f0ebdce83ee52f3d3ce04f2949f3225 100644 (file)
@@ -1,3 +1,3 @@
-SUBDIRS = 90zfs
+SUBDIRS = 02zfsexpandknowledge 90zfs
 
 EXTRA_DIST = README.dracut.markdown
diff --git a/zfs/contrib/dracut/Makefile.in b/zfs/contrib/dracut/Makefile.in
deleted file mode 100644 (file)
index 3a994b5..0000000
+++ /dev/null
@@ -1,782 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = contrib/dracut
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-       ctags-recursive dvi-recursive html-recursive info-recursive \
-       install-data-recursive install-dvi-recursive \
-       install-exec-recursive install-html-recursive \
-       install-info-recursive install-pdf-recursive \
-       install-ps-recursive install-recursive installcheck-recursive \
-       installdirs-recursive pdf-recursive ps-recursive \
-       tags-recursive uninstall-recursive
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-       distdir
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-SUBDIRS = 90zfs
-EXTRA_DIST = README.dracut.markdown
-all: all-recursive
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/dracut/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu contrib/dracut/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-       @fail=; \
-       if $(am__make_keepgoing); then \
-         failcom='fail=yes'; \
-       else \
-         failcom='exit 1'; \
-       fi; \
-       dot_seen=no; \
-       target=`echo $@ | sed s/-recursive//`; \
-       case "$@" in \
-         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-         *) list='$(SUBDIRS)' ;; \
-       esac; \
-       for subdir in $$list; do \
-         echo "Making $$target in $$subdir"; \
-         if test "$$subdir" = "."; then \
-           dot_seen=yes; \
-           local_target="$$target-am"; \
-         else \
-           local_target="$$target"; \
-         fi; \
-         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-         || eval $$failcom; \
-       done; \
-       if test "$$dot_seen" = "no"; then \
-         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-       fi; test -z "$$fail"
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-         include_option=--etags-include; \
-         empty_fix=.; \
-       else \
-         include_option=--include; \
-         empty_fix=; \
-       fi; \
-       list='$(SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           test ! -f $$subdir/TAGS || \
-             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-         fi; \
-       done; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-ctags: ctags-recursive
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-recursive
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           $(am__make_dryrun) \
-             || test -d "$(distdir)/$$subdir" \
-             || $(MKDIR_P) "$(distdir)/$$subdir" \
-             || exit 1; \
-           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-           $(am__relativize); \
-           new_distdir=$$reldir; \
-           dir1=$$subdir; dir2="$(top_distdir)"; \
-           $(am__relativize); \
-           new_top_distdir=$$reldir; \
-           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-           ($(am__cd) $$subdir && \
-             $(MAKE) $(AM_MAKEFLAGS) \
-               top_distdir="$$new_top_distdir" \
-               distdir="$$new_distdir" \
-               am__remove_distdir=: \
-               am__skip_length_check=: \
-               am__skip_mode_fix=: \
-               distdir) \
-             || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-recursive
-all-am: Makefile
-installdirs: installdirs-recursive
-installdirs-am:
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-recursive
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-recursive
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-recursive
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-tags
-
-dvi: dvi-recursive
-
-dvi-am:
-
-html: html-recursive
-
-html-am:
-
-info: info-recursive
-
-info-am:
-
-install-data-am:
-
-install-dvi: install-dvi-recursive
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-recursive
-
-install-html-am:
-
-install-info: install-info-recursive
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-recursive
-
-install-pdf-am:
-
-install-ps: install-ps-recursive
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-recursive
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-recursive
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-recursive
-
-pdf-am:
-
-ps: ps-recursive
-
-ps-am:
-
-uninstall-am:
-
-.MAKE: $(am__recursive_targets) install-am install-strip
-
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
-       check-am clean clean-generic clean-libtool cscopelist-am ctags \
-       ctags-am distclean distclean-generic distclean-libtool \
-       distclean-tags distdir dvi dvi-am html html-am info info-am \
-       install install-am install-data install-data-am install-dvi \
-       install-dvi-am install-exec install-exec-am install-html \
-       install-html-am install-info install-info-am install-man \
-       install-pdf install-pdf-am install-ps install-ps-am \
-       install-strip installcheck installcheck-am installdirs \
-       installdirs-am maintainer-clean maintainer-clean-generic \
-       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
-       ps ps-am tags tags-am uninstall uninstall-am
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index fa2b5a28364f490a533547deb13c42f084b686ce..998e588aba7209b444e06b5daf70341d8cd46dfd 100644 (file)
@@ -1,15 +1,16 @@
 initrddir = $(datarootdir)/initramfs-tools
 
-initrd_SCRIPTS = conf-hooks.d/zfs hooks/zfs scripts/zfs
+initrd_SCRIPTS = conf-hooks.d/zfs hooks/zfs scripts/zfs scripts/local-top/zfs
 
 EXTRA_DIST = \
        $(top_srcdir)/contrib/initramfs/conf-hooks.d/zfs \
        $(top_srcdir)/contrib/initramfs/hooks/zfs \
        $(top_srcdir)/contrib/initramfs/scripts/zfs \
+       $(top_srcdir)/contrib/initramfs/scripts/local-top/zfs \
        $(top_srcdir)/contrib/initramfs/README.initramfs.markdown
 
 install-initrdSCRIPTS: $(EXTRA_DIST)
-       for d in conf-hooks.d hooks scripts; do \
+       for d in conf-hooks.d hooks scripts scripts/local-top; do \
          $(MKDIR_P) $(DESTDIR)$(initrddir)/$$d; \
          cp $(top_srcdir)/contrib/initramfs/$$d/zfs \
            $(DESTDIR)$(initrddir)/$$d/; \
diff --git a/zfs/contrib/initramfs/Makefile.in b/zfs/contrib/initramfs/Makefile.in
deleted file mode 100644 (file)
index 12a2534..0000000
+++ /dev/null
@@ -1,661 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = contrib/initramfs
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(initrddir)"
-SCRIPTS = $(initrd_SCRIPTS)
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-initrddir = $(datarootdir)/initramfs-tools
-initrd_SCRIPTS = conf-hooks.d/zfs hooks/zfs scripts/zfs
-EXTRA_DIST = \
-       $(top_srcdir)/contrib/initramfs/conf-hooks.d/zfs \
-       $(top_srcdir)/contrib/initramfs/hooks/zfs \
-       $(top_srcdir)/contrib/initramfs/scripts/zfs \
-       $(top_srcdir)/contrib/initramfs/README.initramfs.markdown
-
-all: all-am
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu contrib/initramfs/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu contrib/initramfs/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-uninstall-initrdSCRIPTS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(initrd_SCRIPTS)'; test -n "$(initrddir)" || exit 0; \
-       files=`for p in $$list; do echo "$$p"; done | \
-              sed -e 's,.*/,,;$(transform)'`; \
-       dir='$(DESTDIR)$(initrddir)'; $(am__uninstall_files_from_dir)
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-tags TAGS:
-
-ctags CTAGS:
-
-cscope cscopelist:
-
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-am
-all-am: Makefile $(SCRIPTS)
-installdirs:
-       for dir in "$(DESTDIR)$(initrddir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-am
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-initrdSCRIPTS
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-initrdSCRIPTS
-
-.MAKE: install-am install-strip
-
-.PHONY: all all-am check check-am clean clean-generic clean-libtool \
-       cscopelist-am ctags-am distclean distclean-generic \
-       distclean-libtool distdir dvi dvi-am html html-am info info-am \
-       install install-am install-data install-data-am install-dvi \
-       install-dvi-am install-exec install-exec-am install-html \
-       install-html-am install-info install-info-am \
-       install-initrdSCRIPTS install-man install-pdf install-pdf-am \
-       install-ps install-ps-am install-strip installcheck \
-       installcheck-am installdirs maintainer-clean \
-       maintainer-clean-generic mostlyclean mostlyclean-generic \
-       mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
-       uninstall-am uninstall-initrdSCRIPTS
-
-.PRECIOUS: Makefile
-
-
-install-initrdSCRIPTS: $(EXTRA_DIST)
-       for d in conf-hooks.d hooks scripts; do \
-         $(MKDIR_P) $(DESTDIR)$(initrddir)/$$d; \
-         cp $(top_srcdir)/contrib/initramfs/$$d/zfs \
-           $(DESTDIR)$(initrddir)/$$d/; \
-       done
-       if [ -f etc/init.d/zfs ]; then \
-         $(MKDIR_P) $(DESTDIR)$(DEFAULT_INITCONF_DIR); \
-         cp $(top_srcdir)/etc/init.d/zfs \
-           $(DESTDIR)$(DEFAULT_INITCONF_DIR)/; \
-       fi
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/zfs/contrib/initramfs/scripts/local-top/zfs b/zfs/contrib/initramfs/scripts/local-top/zfs
new file mode 100755 (executable)
index 0000000..f09b2c8
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/sh
+PREREQ="mdadm mdrun multipath"
+
+prereqs()
+{
+        echo "$PREREQ"
+}
+
+case $1 in
+# get pre-requisites
+prereqs)
+        prereqs
+        exit 0
+        ;;
+esac
+
+
+#
+# Helper functions
+#
+message()
+{
+        if [ -x /bin/plymouth ] && plymouth --ping; then
+                plymouth message --text="$@"
+        else
+                echo "$@" >&2
+        fi
+        return 0
+}
+
+udev_settle()
+{
+        # Wait for udev to be ready, see https://launchpad.net/bugs/85640
+        if [ -x /sbin/udevadm ]; then
+                /sbin/udevadm settle --timeout=30
+        elif [ -x /sbin/udevsettle ]; then
+                /sbin/udevsettle --timeout=30
+        fi
+        return 0
+}
+
+
+activate_vg()
+{
+        # Sanity checks
+        if [ ! -x /sbin/lvm ]; then
+                message "lvm is not available"
+                return 1
+        fi
+
+        # Detect and activate available volume groups
+        /sbin/lvm vgscan
+        /sbin/lvm vgchange -a y --sysinit
+        return $?
+}
+
+udev_settle
+activate_vg
+
+exit 0
index 6a78a46d29a111e7cc206c10b3fec1cd0cd48cee..250dc57171898e225ae565d1b2dd8a8be240318c 100644 (file)
@@ -288,9 +288,8 @@ load_module_initrd()
                wait_for_dev
        fi
 
-       # zpool import refuse to import without a valid mtab
-       [ ! -f /proc/mounts ] && mount proc /proc
-       [ ! -f /etc/mtab ] && cat /proc/mounts > /etc/mtab
+       # zpool import refuse to import without a valid /proc/self/mounts
+       [ ! -f /proc/self/mounts ] && mount proc /proc
 
        # Load the module
        load_module "zfs" || return 1
@@ -919,7 +918,7 @@ mountroot()
        #
        #   but the MOUNTPOINT prefix is preserved on descendent filesystem
        #   after the pivot into the regular root, which later breaks things
-       #   like `zfs mount -a` and the /etc/mtab refresh.
+       #   like `zfs mount -a` and the /proc/self/mounts refresh.
        #
        # * Mount additional filesystems required
        #   Such as /usr, /var, /usr/local etc.
index 762a34f9db18e9c623b11bb1dad21cebcd35b369..716d2022c759b2872673c9e3b4d7182516de5258 100755 (executable)
@@ -34,27 +34,8 @@ cp --recursive include "$KERNEL_DIR/include/zfs"
 cp --recursive module "$KERNEL_DIR/fs/zfs"
 cp zfs_config.h "$KERNEL_DIR/"
 
-adjust_obj_paths()
-{
-       local FILE="$1"
-       local LINE OBJPATH
-
-       while IFS='' read -r LINE
-       do
-               OBJPATH="${LINE#\$(MODULE)-objs += }"
-               if [ "$OBJPATH" = "$LINE" ]
-               then
-                       echo "$LINE"
-               else
-                       echo "\$(MODULE)-objs += ${OBJPATH##*/}"
-               fi
-       done < "$FILE" > "$FILE.new"
-       mv "$FILE.new" "$FILE"
-}
-
 for MODULE in "${MODULES[@]}"
 do
-       adjust_obj_paths "$KERNEL_DIR/fs/zfs/$MODULE/Makefile"
        sed -i.bak '/obj =/d' "$KERNEL_DIR/fs/zfs/$MODULE/Makefile"
        sed -i.bak '/src =/d' "$KERNEL_DIR/fs/zfs/$MODULE/Makefile"
 done
diff --git a/zfs/cp b/zfs/cp
deleted file mode 100755 (executable)
index 46ff2c9..0000000
--- a/zfs/cp
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-cp "$@"
diff --git a/zfs/dkms.conf b/zfs/dkms.conf
deleted file mode 100644 (file)
index c9f31ae..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-BUILD_DEPENDS[0]="spl"
-AUTOINSTALL="yes"
-PACKAGE_NAME="zfs"
-PACKAGE_VERSION="0.6.5.8"
-PRE_BUILD="configure
-  --prefix=/usr
-  --with-config=kernel
-  --with-linux=$(
-    case `lsb_release -is` in
-      (Debian)
-        if [[ -e ${kernel_source_dir/%build/source} ]]
-        then
-          echo ${kernel_source_dir/%build/source}
-        else
-          # A kpkg exception for Proxmox 2.0
-          echo ${kernel_source_dir}
-        fi
-      ;;
-      (*)
-        echo ${kernel_source_dir}
-      ;;
-    esac
-  )
-  --with-linux-obj=${kernel_source_dir}
-  --with-spl=${source_tree}/spl-${PACKAGE_VERSION}
-  --with-spl-obj=${dkms_tree}/spl/${PACKAGE_VERSION}/${kernelver}/${arch}
-  $(
-    [[ -r /etc/default/zfs ]] \
-    && source /etc/default/zfs \
-    && shopt -q -s extglob \
-    && \
-    {
-      if [[ ${ZFS_DKMS_ENABLE_DEBUG,,} == @(y|yes) ]]
-      then
-        echo --enable-debug
-      fi
-      if [[ ${ZFS_DKMS_ENABLE_DEBUG_DMU_TX,,} == @(y|yes) ]]
-      then
-        echo --enable-debug-dmu-tx
-      fi
-    }
-  )
-"
-POST_BUILD="cp
-  ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/zfs_config.h
-  ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build/module/Module.symvers
-  ${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/${kernelver}/${arch}/
-"
-REMAKE_INITRD="$(
-  if [ -e /usr/share/initramfs-tools/hooks/zfs \
-       -o -e /usr/share/dracut/modules.d/90zfs ]
-  then
-    echo -n yes
-  else
-    echo -n no
-  fi
-)"
-MAKE[0]="make"
-STRIP[0]="$(
-  [[ -r /etc/default/zfs ]] \
-  && source /etc/default/zfs \
-  && shopt -q -s extglob \
-  && [[ ${ZFS_DKMS_DISABLE_STRIP,,} == @(y|yes) ]] \
-  && echo -n no
-)"
-STRIP[1]="${STRIP[0]}"
-STRIP[2]="${STRIP[0]}"
-STRIP[3]="${STRIP[0]}"
-STRIP[4]="${STRIP[0]}"
-STRIP[5]="${STRIP[0]}"
-BUILT_MODULE_NAME[0]="zavl"
-BUILT_MODULE_LOCATION[0]="module/avl/"
-DEST_MODULE_LOCATION[0]="/extra/zfs/zavl"
-BUILT_MODULE_NAME[1]="zcommon"
-BUILT_MODULE_LOCATION[1]="module/zcommon/"
-DEST_MODULE_LOCATION[1]="/extra/zfs/zcommon"
-BUILT_MODULE_NAME[2]="znvpair"
-BUILT_MODULE_LOCATION[2]="module/nvpair/"
-DEST_MODULE_LOCATION[2]="/extra/zfs/znvpair"
-BUILT_MODULE_NAME[3]="zpios"
-BUILT_MODULE_LOCATION[3]="module/zpios/"
-DEST_MODULE_LOCATION[3]="/extra/zfs/zpios"
-BUILT_MODULE_NAME[4]="zunicode"
-BUILT_MODULE_LOCATION[4]="module/unicode/"
-DEST_MODULE_LOCATION[4]="/extra/zfs/zunicode"
-BUILT_MODULE_NAME[5]="zfs"
-BUILT_MODULE_LOCATION[5]="module/zfs/"
-DEST_MODULE_LOCATION[5]="/extra/zfs/zfs"
diff --git a/zfs/etc/Makefile.am b/zfs/etc/Makefile.am
new file mode 100644 (file)
index 0000000..a62678b
--- /dev/null
@@ -0,0 +1,2 @@
+SUBDIRS = zfs $(ZFS_INIT_SYSTEMD) $(ZFS_INIT_SYSV) $(ZFS_MODULE_LOAD)
+DIST_SUBDIRS = init.d zfs systemd modules-load.d
diff --git a/zfs/etc/Makefile.in b/zfs/etc/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/etc/init.d/Makefile.am b/zfs/etc/init.d/Makefile.am
new file mode 100644 (file)
index 0000000..247db0a
--- /dev/null
@@ -0,0 +1,44 @@
+initdir = $(DEFAULT_INIT_DIR)
+init_SCRIPTS = zfs-import zfs-mount zfs-share zfs-zed
+
+initcommondir = $(sysconfdir)/zfs
+initcommon_SCRIPTS = zfs-functions
+
+initconfdir = $(DEFAULT_INITCONF_DIR)
+initconf_SCRIPTS = zfs
+
+EXTRA_DIST = \
+       $(top_srcdir)/etc/init.d/zfs-functions.in \
+       $(top_srcdir)/etc/init.d/zfs-share.in \
+       $(top_srcdir)/etc/init.d/zfs-import.in \
+       $(top_srcdir)/etc/init.d/zfs-mount.in \
+       $(top_srcdir)/etc/init.d/zfs-zed.in \
+       $(top_srcdir)/etc/init.d/zfs.in
+
+$(init_SCRIPTS) $(initconf_SCRIPTS) $(initcommon_SCRIPTS):%:%.in
+       -(if [ -e /etc/debian_version ]; then \
+               NFS_SRV=nfs-kernel-server; \
+         else \
+               NFS_SRV=nfs; \
+         fi; \
+         if [ -e /sbin/openrc-run ]; then \
+               SHELL=/sbin/runscript; \
+         else \
+               SHELL=/bin/sh; \
+         fi; \
+         $(SED) -e 's,@bindir\@,$(bindir),g' \
+                -e 's,@sbindir\@,$(sbindir),g' \
+                -e 's,@udevdir\@,$(udevdir),g' \
+                -e 's,@udevruledir\@,$(udevruledir),g' \
+                -e 's,@sysconfdir\@,$(sysconfdir),g' \
+                -e 's,@initconfdir\@,$(initconfdir),g' \
+                -e 's,@initdir\@,$(initdir),g' \
+                -e 's,@runstatedir\@,$(runstatedir),g' \
+                -e "s,@SHELL\@,$$SHELL,g" \
+                -e "s,@NFS_SRV\@,$$NFS_SRV,g" \
+                $< >'$@'; \
+         [ '$@' = 'zfs-functions' -o '$@' = 'zfs' ] || \
+               chmod +x '$@')
+
+distclean-local::
+       -$(RM) $(init_SCRIPTS) $(initcommon_SCRIPTS) $(initconf_SCRIPTS)
diff --git a/zfs/etc/init.d/Makefile.in b/zfs/etc/init.d/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/etc/init.d/README.md b/zfs/etc/init.d/README.md
new file mode 100644 (file)
index 0000000..89edb1d
--- /dev/null
@@ -0,0 +1,72 @@
+DESCRIPTION
+  These script were written with the primary intention of being portable and
+  usable on as many systems as possible.
+
+  This is, in practice, usually not possible. But the intention is there.
+  And it is a good one.
+
+  They have been tested successfully on:
+
+    * Debian GNU/Linux Wheezy
+    * Debian GNU/Linux Jessie
+    * Ubuntu Trusty
+    * CentOS 6.0
+    * CentOS 6.6
+    * Gentoo
+
+SUPPORT
+  If you find that they don't work for your platform, please report this
+  at the ZFS On Linux issue tracker at https://github.com/zfsonlinux/zfs/issues.
+
+  Please include:
+
+    * Distribution name
+    * Distribution version
+    * Where to find an install CD image
+    * Architecture
+
+  If you have code to share that fixes the problem, that is much better.
+  But please remember to try your best keep portability in mind. If you
+  suspect that what you're writing/modifying won't work on anything else
+  than your distribution, please make sure to put that code in appropriate
+  if/else/fi code.
+
+  It currently MUST be bash (or fully compatible) for this to work.
+
+  If you're making your own distribution and you want the scripts to
+  work on that, the biggest problem you'll (probably) have is the part
+  at the beginning of the "zfs-functions.in" file which sets up the
+  logging output.
+
+INSTALLING INIT SCRIPT LINKS
+  To setup the init script links in /etc/rc?.d manually on a Debian GNU/Linux
+  (or derived) system, run the following commands (the order is important!):
+
+    update-rc.d zfs-import start 07 S .       stop 07 0 1 6 .
+    update-rc.d zfs-mount  start 02 2 3 4 5 . stop 06 0 1 6 .
+    update-rc.d zfs-zed    start 07 2 3 4 5 . stop 08 0 1 6 .
+    update-rc.d zfs-share  start 27 2 3 4 5 . stop 05 0 1 6 .
+
+  To do the same on RedHat, Fedora and/or CentOS:
+
+    chkconfig zfs-import
+    chkconfig zfs-mount
+    chkconfig zfs-zed
+    chkconfig zfs-share
+
+  On Gentoo:
+
+    rc-update add zfs-import boot
+    rc-update add zfs-mount boot
+    rc-update add zfs-zed default
+    rc-update add zfs-share default
+
+  The idea here is to make sure all of the ZFS filesystems, including possibly
+  separate datasets like /var, are mounted before anything else is started.
+
+  Then, ZED, which depends on /var, can be started.  It will consume and act
+  on events that occurred before it started.  ZED may also play a role in
+  sharing filesystems in the future, so it is important to start before the
+  'share' service.
+
+  Finally, we share filesystems configured with the share\* property.
index b3e8c1303bda612cfbec58359220e20cc62e48d7..97f2ea039d7b0c57d477e513b448fa0103e6832f 100644 (file)
@@ -1,2 +1,429 @@
-%:
-       #
+# This is a script with common functions etc used by zfs-import, zfs-mount,
+# zfs-share and zfs-zed.
+#
+# It is _NOT_ to be called independently
+#
+# Released under the 2-clause BSD license.
+#
+# The original script that acted as a template for this script came from
+# the Debian GNU/Linux kFreeBSD ZFS packages (which did not include a
+# licensing stansa) in the commit dated Mar 24, 2011:
+#   https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a
+
+PATH=/sbin:/bin:/usr/bin:/usr/sbin
+
+# Source function library
+if [ -f /etc/rc.d/init.d/functions ]; then
+       # RedHat and derivates
+       . /etc/rc.d/init.d/functions
+elif [ -L /etc/init.d/functions.sh ]; then
+       # Gentoo
+       . /etc/init.d/functions.sh
+elif [ -f /lib/lsb/init-functions ]; then
+       # LSB, Debian GNU/Linux and derivates
+       . /lib/lsb/init-functions
+fi
+
+# Of course the functions we need are called differently
+# on different distributions - it would be way too easy
+# otherwise!!
+if type log_failure_msg > /dev/null 2>&1 ; then
+       # LSB functions - fall through
+       zfs_log_begin_msg() { log_begin_msg "$1"; }
+       zfs_log_end_msg() { log_end_msg "$1"; }
+       zfs_log_failure_msg() { log_failure_msg "$1"; }
+       zfs_log_progress_msg() { log_progress_msg "$1"; }
+elif type success > /dev/null 2>&1 ; then
+       # Fedora/RedHat functions
+       zfs_set_ifs() {
+               # For some reason, the init function library have a problem
+               # with a changed IFS, so this function goes around that.
+               local tIFS="$1"
+               if [ -n "$tIFS" ]
+               then
+                       TMP_IFS="$IFS"
+                       IFS="$tIFS"
+               fi
+       }
+
+       zfs_log_begin_msg() { echo -n "$1 "; }
+       zfs_log_end_msg() {
+               zfs_set_ifs "$OLD_IFS"
+               if [ "$1" -eq 0 ]; then
+                       success
+               else
+                       failure
+               fi
+               echo
+               zfs_set_ifs "$TMP_IFS"
+       }
+       zfs_log_failure_msg() {
+               zfs_set_ifs "$OLD_IFS"
+               failure
+               echo
+               zfs_set_ifs "$TMP_IFS"
+       }
+       zfs_log_progress_msg() { echo -n $"$1"; }
+elif type einfo > /dev/null 2>&1 ; then
+       # Gentoo functions
+       zfs_log_begin_msg() { ebegin "$1"; }
+       zfs_log_end_msg() { eend "$1"; }
+       zfs_log_failure_msg() { eend "$1"; }
+#      zfs_log_progress_msg() { echo -n "$1"; }
+       zfs_log_progress_msg() { echo -n; }
+else
+       # Unknown - simple substitues.
+       zfs_log_begin_msg() { echo -n "$1"; }
+       zfs_log_end_msg() {
+               ret=$1
+               if [ "$ret" -ge 1 ]; then
+                       echo " failed!"
+               else
+                       echo " success"
+               fi
+               return "$ret"
+       }
+       zfs_log_failure_msg() { echo "$1"; }
+       zfs_log_progress_msg() { echo -n "$1"; }
+fi
+
+# Paths to what we need
+ZFS="@sbindir@/zfs"
+ZED="@sbindir@/zed"
+ZPOOL="@sbindir@/zpool"
+ZPOOL_CACHE="@sysconfdir@/zfs/zpool.cache"
+
+# Sensible defaults
+ZFS_MOUNT='yes'
+ZFS_UNMOUNT='yes'
+
+export ZFS ZED ZPOOL ZPOOL_CACHE ZFS_MOUNT ZFS_UNMOUNT
+
+# Source zfs configuration, overriding the defaults
+if [ -f @initconfdir@/zfs ]; then
+       . @initconfdir@/zfs
+fi
+
+# ----------------------------------------------------
+
+zfs_action()
+{
+       local MSG="$1"; shift
+       local CMD="$*"
+       local ret
+
+       zfs_log_begin_msg "$MSG "
+       $CMD
+       ret=$?
+       if [ "$ret" -eq 0 ]; then
+               zfs_log_end_msg $ret
+       else
+               zfs_log_failure_msg $ret
+       fi
+
+       return $ret
+}
+
+# Returns
+#   0 if daemon has been started
+#   1 if daemon was already running
+#   2 if daemon could not be started
+#   3 if unsupported
+#
+zfs_daemon_start()
+{
+       local PIDFILE="$1";     shift
+       local DAEMON_BIN="$1";  shift
+       local DAEMON_ARGS="$*"
+
+       if type start-stop-daemon > /dev/null 2>&1 ; then
+               # LSB functions
+               start-stop-daemon --start --quiet --pidfile "$PIDFILE" \
+                   --exec "$DAEMON_BIN" --test > /dev/null || return 1
+
+               start-stop-daemon --start --quiet --exec "$DAEMON_BIN" -- \
+                   $DAEMON_ARGS || return 2
+
+               # On Debian GNU/Linux, there's a 'sendsigs' script that will
+               # kill basically everything quite early and zed is stopped
+               # much later than that. We don't want zed to be among them,
+               # so add the zed pid to list of pids to ignore.
+               if [ -f "$PIDFILE" -a -d /run/sendsigs.omit.d ]
+               then
+                       ln -sf "$PIDFILE" /run/sendsigs.omit.d/zed
+               fi
+       elif type daemon > /dev/null 2>&1 ; then
+               # Fedora/RedHat functions
+               daemon --pidfile "$PIDFILE" "$DAEMON_BIN" $DAEMON_ARGS
+               return $?
+       else
+               # Unsupported
+               return 3
+       fi
+
+       return 0
+}
+
+# Returns
+#   0 if daemon has been stopped
+#   1 if daemon was already stopped
+#   2 if daemon could not be stopped
+#   3 if unsupported
+#
+zfs_daemon_stop()
+{
+       local PIDFILE="$1"
+       local DAEMON_BIN="$2"
+       local DAEMON_NAME="$3"
+
+       if type start-stop-daemon > /dev/null 2>&1 ; then
+               # LSB functions
+               start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 \
+                   --pidfile "$PIDFILE" --name "$DAEMON_NAME"
+               [ "$?" = 0 ] && rm -f "$PIDFILE"
+
+               return $?
+       elif type killproc > /dev/null 2>&1 ; then
+               # Fedora/RedHat functions
+               killproc -p "$PIDFILE" "$DAEMON_NAME"
+               [ "$?" = 0 ] && rm -f "$PIDFILE"
+
+               return $?
+       else
+               # Unsupported
+               return 3
+       fi
+
+       return 0
+}
+
+# Returns status
+zfs_daemon_status()
+{
+       local PIDFILE="$1"
+       local DAEMON_BIN="$2"
+       local DAEMON_NAME="$3"
+
+       if type status_of_proc > /dev/null 2>&1 ; then
+               # LSB functions
+               status_of_proc "$DAEMON_NAME" "$DAEMON_BIN"
+               return $?
+       elif type status > /dev/null 2>&1 ; then
+               # Fedora/RedHat functions
+               status -p "$PIDFILE" "$DAEMON_NAME"
+               return $?
+       else
+               # Unsupported
+               return 3
+       fi
+
+       return 0
+}
+
+zfs_daemon_reload()
+{
+       local PIDFILE="$1"
+       local DAEMON_NAME="$2"
+
+       if type start-stop-daemon > /dev/null 2>&1 ; then
+               # LSB functions
+               start-stop-daemon --stop --signal 1 --quiet \
+                   --pidfile "$PIDFILE" --name "$DAEMON_NAME"
+               return $?
+       elif type killproc > /dev/null 2>&1 ; then
+               # Fedora/RedHat functions
+                killproc -p "$PIDFILE" "$DAEMON_NAME" -HUP
+               return $?
+       else
+               # Unsupported
+               return 3
+       fi
+
+       return 0
+}
+
+zfs_installed()
+{
+       if [ ! -x "$ZPOOL" ]; then
+               return 1
+       else
+               # Test if it works (will catch missing/broken libs etc)
+               "$ZPOOL" -? > /dev/null 2>&1
+               return $?
+       fi
+
+       if [ ! -x "$ZFS" ]; then
+               return 2
+       else
+               # Test if it works (will catch missing/broken libs etc)
+               "$ZFS" -? > /dev/null 2>&1
+               return $?
+       fi
+
+       return 0
+}
+
+# Trigger udev and wait for it to settle.
+udev_trigger()
+{
+       if [ -x /sbin/udevadm ]; then
+               /sbin/udevadm trigger --action=change --subsystem-match=block
+               /sbin/udevadm settle
+       elif [ -x /sbin/udevsettle ]; then
+               /sbin/udevtrigger
+               /sbin/udevsettle
+       fi
+}
+
+# Do a lot of checks to make sure it's 'safe' to continue with the import.
+checksystem()
+{
+       if grep -qiE '(^|[^\\](\\\\)* )zfs=(off|no|0)( |$)' /proc/cmdline;
+       then
+               # Called with zfs=(off|no|0) - bail because we don't
+               # want anything import, mounted or shared.
+               # HOWEVER, only do this if we're called at the boot up
+               # (from init), not if we're running interactivly (as in
+               # from the shell - we know what we're doing).
+               [ -n "$init" ] && exit 3
+       fi
+
+       # Check if ZFS is installed.
+       zfs_installed || return 5
+
+       # Just make sure that /dev/zfs is created.
+       udev_trigger
+
+       if ! [ "$(uname -m)" = "x86_64" ]; then
+               echo "Warning: You're not running 64bit. Currently native zfs in";
+               echo "         Linux is only supported and tested on 64bit.";
+               # should we break here? People doing this should know what they
+               # do, thus i'm not breaking here.
+       fi
+
+       return 0
+}
+
+get_root_pool()
+{
+       set -- $(mount | grep ' on / ')
+       [ "$5" = "zfs" ] && echo "${1%%/*}"
+}
+
+# Check if a variable is 'yes' (any case) or '1'
+# Returns TRUE if set.
+check_boolean()
+{
+       local var="$1"
+
+       echo "$var" | grep -Eiq "^yes$|^on$|^true$|^1$" && return 0 || return 1
+}
+
+check_module_loaded()
+{
+       module="$1"
+
+       [ -r "/sys/module/${module}/version" ] && return 0 || return 1
+}
+
+load_module()
+{
+       module="$1"
+
+       # Load the zfs module stack
+       if ! check_module_loaded "$module"; then
+               if ! /sbin/modprobe "$module"; then
+                       return 5
+               fi
+       fi
+       return 0
+}
+
+# first parameter is a regular expression that filters mtab
+read_mtab()
+{
+       local match="$1"
+       local fs mntpnt fstype opts rest TMPFILE
+
+       # Unset all MTAB_* variables
+       unset $(env | grep ^MTAB_ | sed 's,=.*,,')
+
+       while read -r fs mntpnt fstype opts rest; do
+               if echo "$fs $mntpnt $fstype $opts" | grep -qE "$match"; then
+                       # * Fix problems (!?) in the mounts file. It will record
+                       #   'rpool 1' as 'rpool\0401' instead of 'rpool\00401'
+                       #   which seems to be the correct (at least as far as
+                       #   'printf' is concerned).
+                       # * We need to use the external echo, because the
+                       #   internal one would interpret the backslash code
+                       #   (incorrectly), giving us a \ 1 instead.
+                       mntpnt=$(/bin/echo "$mntpnt" | sed "s,\\\0,\\\00,g")
+                       fs=$(/bin/echo "$fs" | sed "s,\\\0,\\\00,")
+
+                       # Remove 'unwanted' characters.
+                       mntpnt=$(printf '%b\n' "$mntpnt" | sed -e 's,/,,g' \
+                           -e 's,-,,g' -e 's,\.,,g' -e 's, ,,g')
+                       fs=$(printf '%b\n' "$fs")
+
+                       # Set the variable.
+                       eval export MTAB_$mntpnt=\"$fs\"
+               fi
+       done < /proc/self/mounts
+}
+
+in_mtab()
+{
+       local fs="$(echo "$1" | sed 's,/,_,g')"
+       local var
+
+       var="$(eval echo MTAB_$fs)"
+       [ "$(eval echo "$""$var")" != "" ]
+       return "$?"
+}
+
+# first parameter is a regular expression that filters fstab
+read_fstab()
+{
+       local match="$1"
+       local i var TMPFILE
+
+       # Unset all FSTAB_* variables
+       unset $(env | grep ^FSTAB_ | sed 's,=.*,,')
+
+       i=0
+       while read -r fs mntpnt fstype opts; do
+               echo "$fs" | egrep -qE '^#|^$' && continue
+
+               if echo "$fs $mntpnt $fstype $opts" | grep -qE "$match"; then
+                       eval export FSTAB_dev_$i="$fs"
+                       fs=$(printf '%b\n' "$fs" | sed 's,/,_,g')
+                       eval export FSTAB_$i="$mntpnt"
+
+                       i=$((i + 1))
+               fi
+       done < /etc/fstab
+}
+
+in_fstab()
+{
+       local var
+
+       var="$(eval echo FSTAB_$1)"
+       [ "${var}" != "" ]
+       return $?
+}
+
+is_mounted()
+{
+       local mntpt="$1"
+       local line
+
+       mount | \
+           while read line; do
+               if echo "$line" | grep -q " on $mntpt "; then
+                   return 0
+               fi
+           done
+
+       return 1
+}
old mode 100644 (file)
new mode 100755 (executable)
index b3e8c13..354bbc6
@@ -1,2 +1,339 @@
-%:
+#!@SHELL@
+#
+# zfs-import    This script will import ZFS pools
+#
+# chkconfig:    2345 01 99
+# description:  This script will perform a verbatim import of ZFS pools
+#               during system boot.
+# probe: true
+#
+### BEGIN INIT INFO
+# Provides:          zfs-import
+# Required-Start:    mtab
+# Required-Stop:     $local_fs mtab
+# Default-Start:     S
+# Default-Stop:      0 1 6
+# X-Start-Before:    checkfs
+# X-Stop-After:      zfs-mount
+# Short-Description: Import ZFS pools
+# Description: Run the `zpool import` command.
+### END INIT INFO
+#
+# NOTE: Not having '$local_fs' on Required-Start but only on Required-Stop
+#       is on purpose. If we have '$local_fs' in both (and X-Start-Before=checkfs)
+#       we get conflicts - import needs to be started extremely early,
+#       but not stopped too late.
+#
+# Released under the 2-clause BSD license.
+#
+# The original script that acted as a template for this script came from
+# the Debian GNU/Linux kFreeBSD ZFS packages (which did not include a
+# licensing stansa) in the commit dated Mar 24, 2011:
+#   https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a
+
+# Source the common init script
+. @sysconfdir@/zfs/zfs-functions
+
+# ----------------------------------------------------
+
+do_depend()
+{
+       after sysfs udev
+       keyword -lxc -openvz -prefix -vserver
+}
+
+# Use the zpool cache file to import pools
+do_verbatim_import()
+{
+       if [ -f "$ZPOOL_CACHE" ]
+       then
+               zfs_action "Importing ZFS pool(s)" \
+                       "$ZPOOL" import -c "$ZPOOL_CACHE" -N -a
+       fi
+}
+
+# Support function to get a list of all pools, separated with ';'
+find_pools()
+{
+       local CMD="$*"
+       local pools
+
+       pools=$($CMD 2> /dev/null | \
+               grep -E "pool:|^[a-zA-Z0-9]" | \
+               sed 's@.*: @@' | \
+               sort | \
+               while read pool; do \
+                   echo -n "$pool;"
+               done)
+
+       echo "${pools%%;}" # Return without the last ';'.
+}
+
+# Find and import all visible pools, even exported ones
+do_import_all_visible()
+{
+       local already_imported available_pools pool npools
+       local exception dir ZPOOL_IMPORT_PATH RET=0 r=1
+
+       # In case not shutdown cleanly.
+       [ -n "$init" ] && rm -f /etc/dfs/sharetab
+
+       # Just simplify code later on.
+       if [ -n "$USE_DISK_BY_ID" -a "$USE_DISK_BY_ID" != 'yes' ]
+       then
+               # It's something, but not 'yes' so it's no good to us.
+               unset USE_DISK_BY_ID
+       fi
+
+       # Find list of already imported pools.
+       already_imported=$(find_pools "$ZPOOL" list -H -oname)
+       available_pools=$(find_pools "$ZPOOL" import)
+
+       # Just in case - seen it happen (that a pool isn't visable/found
+       # with a simple "zpool import" but only when using the "-d"
+       # option or setting ZPOOL_IMPORT_PATH).
+       if [ -d "/dev/disk/by-id" ]
+       then
+               npools=$(find_pools "$ZPOOL" import -d /dev/disk/by-id)
+               if [ -n "$npools" ]
+               then
+                       # Because we have found extra pool(s) here, which wasn't
+                       # found 'normaly', we need to force USE_DISK_BY_ID to
+                       # make sure we're able to actually import it/them later.
+                       USE_DISK_BY_ID='yes'
+
+                       if [ -n "$available_pools" ]
+                       then
+                               # Filter out duplicates (pools found with the simpl
+                               # "zpool import" but which is also found with the
+                               # "zpool import -d ...").
+                               npools=$(echo "$npools" | sed "s,$available_pools,,")
+
+                               # Add the list to the existing list of
+                               # available pools
+                               available_pools="$available_pools;$npools"
+                       else
+                               available_pools="$npools"
+                       fi
+               fi
+       fi
+
+       # Filter out any exceptions...
+       if [ -n "$ZFS_POOL_EXCEPTIONS" ]
+       then
+               local found=""
+               local apools=""
+               OLD_IFS="$IFS" ; IFS=";"
+
+               for pool in $available_pools
+               do
+                       for exception in $ZFS_POOL_EXCEPTIONS
+                       do
+                               [ "$pool" = "$exception" ] && continue 2
+                               found="$pool"
+                       done
+
+                       if [ -n "$found" ]
+                       then
+                               if [ -n "$apools" ]
+                               then
+                                       apools="$apools;$pool"
+                               else
+                                       apools="$pool"
+                               fi
+                       fi
+               done
+
+               IFS="$OLD_IFS"
+               available_pools="$apools"
+       fi
+
+       # For backwards compability, make sure that ZPOOL_IMPORT_PATH is set
+       # to something we can use later with the real import(s). We want to
+       # make sure we find all by* dirs, BUT by-vdev should be first (if it
+       # exists).
+       if [ -n "$USE_DISK_BY_ID" -a -z "$ZPOOL_IMPORT_PATH" ]
+       then
+               local dirs
+               dirs="$(for dir in $(echo /dev/disk/by-*)
+               do
+                       # Ignore by-vdev here - we wan't it first!
+                       echo "$dir" | grep -q /by-vdev && continue
+                       [ ! -d "$dir" ] && continue
+
+                       echo -n "$dir:"
+               done | sed 's,:$,,g')"
+
+               if [ -d "/dev/disk/by-vdev" ]
+               then
+                       # Add by-vdev at the beginning.
+                       ZPOOL_IMPORT_PATH="/dev/disk/by-vdev:"
+               fi
+
+               # Help with getting LUKS partitions etc imported.
+               if [ -d "/dev/mapper" ]; then
+                       if [ -n "$ZPOOL_IMPORT_PATH" ]; then
+                               ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH:/dev/mapper:"
+                       else
+                               ZPOOL_IMPORT_PATH="/dev/mapper:"
+                       fi
+               fi
+
+               # ... and /dev at the very end, just for good measure.
+               ZPOOL_IMPORT_PATH="$ZPOOL_IMPORT_PATH$dirs:/dev"
+       fi
+
+       # Needs to be exported for "zpool" to catch it.
+       [ -n "$ZPOOL_IMPORT_PATH" ] && export ZPOOL_IMPORT_PATH
+
+       # Mount all availible pools (except those set in ZFS_POOL_EXCEPTIONS.
        #
+       # If not interactive (run from init - variable init='/sbin/init')
+       # we get ONE line for all pools being imported, with just a dot
+       # as status for each pool.
+       # Example: Importing ZFS pool(s)...                             [OK]
+       #
+       # If it IS interactive (started from the shell manually), then we
+       # get one line per pool importing.
+       # Example: Importing ZFS pool pool1                             [OK]
+       #          Importing ZFS pool pool2                             [OK]
+       #          [etc]
+       [ -n "$init" ] && zfs_log_begin_msg "Importing ZFS pool(s)"
+       OLD_IFS="$IFS" ; IFS=";"
+       for pool in $available_pools
+       do
+               [ -z "$pool" ] && continue
+
+               # We have pools that haven't been imported - import them
+               if [ -n "$init" ]
+               then
+                       # Not interactive - a dot for each pool.
+                       # Except on Gentoo where this doesn't work.
+                       zfs_log_progress_msg "."
+               else
+                       # Interactive - one 'Importing ...' line per pool
+                       zfs_log_begin_msg "Importing ZFS pool $pool"
+               fi
+
+               # Import by using ZPOOL_IMPORT_PATH (either set above or in
+               # the config file) _or_ with the 'built in' default search
+               # paths. This is the prefered way.
+               "$ZPOOL" import -N ${ZPOOL_IMPORT_OPTS} "$pool" 2> /dev/null
+               r="$?" ; RET=$((RET + r))
+               if [ "$r" -eq 0 ]
+               then
+                       # Output success and process the next pool
+                       [ -z "$init" ] && zfs_log_end_msg 0
+                       continue
+               fi
+               # We don't want a fail msg here, we're going to try import
+               # using the cache file soon and that might succeed.
+               [ ! -f "$ZPOOL_CACHE" ] && zfs_log_end_msg "$RET"
+
+               if [ "$r" -gt 0 -a -f "$ZPOOL_CACHE" ]
+               then
+                       # Failed to import without a cache file. Try WITH...
+                       if [ -z "$init" ] && check_boolean "$VERBOSE_MOUNT"
+                       then
+                               # Interactive + Verbose = more information
+                               zfs_log_progress_msg " using cache file"
+                       fi
+
+                       "$ZPOOL" import -c "$ZPOOL_CACHE" -N ${ZPOOL_IMPORT_OPTS} \
+                               "$pool" 2> /dev/null
+                       r="$?" ; RET=$((RET + r))
+                       if [ "$r" -eq 0 ]
+                       then
+                               [ -z "$init" ] && zfs_log_end_msg 0
+                               continue 3 # Next pool
+                       fi
+                       zfs_log_end_msg "$RET"
+               fi
+       done
+       [ -n "$init" ] && zfs_log_end_msg "$RET"
+
+       IFS="$OLD_IFS"
+       [ -n "$already_imported" -a -z "$available_pools" ] && return 0
+
+       return "$RET"
+}
+
+do_import()
+{
+       if check_boolean "$ZPOOL_IMPORT_ALL_VISIBLE"
+       then
+               do_import_all_visible
+       else
+               # This is the default option
+               do_verbatim_import
+       fi
+}
+
+# Output the status and list of pools
+do_status()
+{
+       check_module_loaded "zfs" || exit 0
+
+       "$ZPOOL" status && echo "" && "$ZPOOL" list
+}
+
+do_start()
+{
+       if check_boolean "$VERBOSE_MOUNT"
+       then
+           zfs_log_begin_msg "Checking if ZFS userspace tools present"
+       fi
+
+       if checksystem
+       then
+               check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0
+
+               check_boolean "$VERBOSE_MOUNT" && \
+                       zfs_log_begin_msg "Loading kernel ZFS infrastructure"
+
+               if ! load_module "zfs"
+               then
+                       check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 1
+                       return 5
+               fi
+               check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0
+
+               do_import && udev_trigger # just to make sure we get zvols.
+
+               return 0
+       else
+               return 1
+       fi
+}
+
+# ----------------------------------------------------
+
+if [ ! -e /sbin/openrc-run ]
+then
+       case "$1" in
+               start)
+                       do_start
+                       ;;
+               stop)
+                       # no-op
+                       ;;
+               status)
+                       do_status
+                       ;;
+               force-reload|condrestart|reload|restart)
+                       # no-op
+                       ;;
+               *)
+                       [ -n "$1" ] && echo "Error: Unknown command $1."
+                       echo "Usage: $0 {start|status}"
+                       exit 3
+                       ;;
+       esac
+
+       exit $?
+else
+       # Create wrapper functions since Gentoo don't use the case part.
+       depend() { do_depend; }
+       start() { do_start; }
+       status() { do_status; }
+fi
old mode 100644 (file)
new mode 100755 (executable)
index b3e8c13..2722a31
@@ -1,2 +1,227 @@
-%:
-       #
+#!@SHELL@
+#
+# zfs-mount     This script will mount/umount the zfs filesystems.
+#
+# chkconfig:    2345 06 99
+# description:  This script will mount/umount the zfs filesystems during
+#               system boot/shutdown. Configuration of which filesystems
+#               should be mounted is handled by the zfs 'mountpoint' and
+#               'canmount' properties. See the zfs(8) man page for details.
+#               It is also responsible for all userspace zfs services.
+# probe: true
+#
+### BEGIN INIT INFO
+# Provides:          zfs-mount
+# Required-Start:    $local_fs zfs-import
+# Required-Stop:     $local_fs zfs-import
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# X-Stop-After:      zfs-zed
+# Short-Description: Mount ZFS filesystems and volumes
+# Description: Run the `zfs mount -a` or `zfs umount -a` commands.
+### END INIT INFO
+#
+# Released under the 2-clause BSD license.
+#
+# The original script that acted as a template for this script came from
+# the Debian GNU/Linux kFreeBSD ZFS packages (which did not include a
+# licensing stansa) in the commit dated Mar 24, 2011:
+#   https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a
+
+# Source the common init script
+. @sysconfdir@/zfs/zfs-functions
+
+# ----------------------------------------------------
+
+chkroot() {
+       while read line; do
+               set -- $line
+               if [ "$2" = "/" ]; then
+                       return 0
+               fi
+       done < /proc/self/mounts
+
+       return 1
+}
+
+do_depend()
+{
+       # Try to allow people to mix and match fstab with ZFS in a way that makes sense.
+       if [ "$(mountinfo -s /)" = 'zfs' ]
+       then
+               before localmount
+       else
+               after localmount
+       fi
+
+       # bootmisc will log to /var which may be a different zfs than root.
+       before bootmisc logger
+
+       after zfs-import sysfs
+       use mtab
+       keyword -lxc -openvz -prefix -vserver
+}
+
+# Mount all datasets/filesystems
+do_mount()
+{
+       local verbose overlay i mntpt val
+
+       check_boolean "$VERBOSE_MOUNT" && verbose=v
+       check_boolean "$DO_OVERLAY_MOUNTS" && overlay=O
+
+       zfs_action "Mounting ZFS filesystem(s)" \
+           "$ZFS" mount -a$verbose$overlay "$MOUNT_EXTRA_OPTIONS"
+
+       # Require each volume/filesytem to have 'noauto' and no fsck
+       # option. This shouldn't really be necessary, as long as one
+       # can get zfs-import to run sufficiently early on in the boot
+       # process - before local mounts. This is just here in case/if
+       # this isn't possible.
+       check_boolean "$VERBOSE_MOUNT" && \
+           zfs_log_begin_msg "Mounting volumes and filesystems registered in fstab"
+
+       read_mtab  "^/dev/(zd|zvol)"
+       read_fstab "^/dev/(zd|zvol)"
+       i=0; var=$(eval echo FSTAB_$i)
+       while [ -n "$(eval echo "$""$var")" ]
+       do
+               mntpt=$(eval echo "$""$var")
+               dev=$(eval echo "$"FSTAB_dev_$i)
+               if ! in_mtab "$mntpt" && ! is_mounted "$mntpt" && [ -e "$dev" ]
+               then
+                       check_boolean "$VERBOSE_MOUNT" && \
+                               zfs_log_progress_msg "$mntpt "
+                       fsck "$dev" && mount "$mntpt"
+               fi
+
+               i=$((i + 1))
+               var=$(eval echo FSTAB_$i)
+       done
+
+       read_mtab  "[[:space:]]zfs[[:space:]]"
+       read_fstab "[[:space:]]zfs[[:space:]]"
+       i=0; var=$(eval echo FSTAB_$i)
+       while [ -n "$(eval echo "$""$var")" ]
+       do
+               mntpt=$(eval echo "$""$var")
+               if ! in_mtab "$mntpt" && ! is_mounted "$mntpt"
+               then
+                       check_boolean "$VERBOSE_MOUNT" && \
+                               zfs_log_progress_msg "$mntpt "
+                       mount "$mntpt"
+               fi
+
+               i=$((i + 1))
+               var=$(eval echo FSTAB_$i)
+       done
+       check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0
+
+       return 0
+}
+
+# Unmount all filesystems
+do_unmount()
+{
+       local i var mntpt
+
+       # This shouldn't really be necessary, as long as one can get
+       # zfs-import to run sufficiently late in the shutdown/reboot process
+       # - after unmounting local filesystems. This is just here in case/if
+       # this isn't possible.
+       zfs_action "Unmounting ZFS filesystems" "$ZFS" unmount -a
+
+       check_boolean "$VERBOSE_MOUNT" && \
+           zfs_log_begin_msg "Unmounting volumes and filesystems registered in fstab"
+
+       read_mtab  "^/dev/(zd|zvol)"
+       read_fstab "^/dev/(zd|zvol)"
+       i=0; var=$(eval echo FSTAB_$i)
+       while [ -n "$(eval echo "$""$var")" ]
+       do
+               mntpt=$(eval echo "$""$var")
+               dev=$(eval echo "$"FSTAB_dev_$i)
+               if in_mtab "$mntpt"
+               then
+                       check_boolean "$VERBOSE_MOUNT" && \
+                               zfs_log_progress_msg "$mntpt "
+                       umount "$mntpt"
+               fi
+
+               i=$((i + 1))
+               var=$(eval echo FSTAB_$i)
+       done
+
+       read_mtab  "[[:space:]]zfs[[:space:]]"
+       read_fstab "[[:space:]]zfs[[:space:]]"
+       i=0; var=$(eval echo FSTAB_$i)
+       while [ -n "$(eval echo "$""$var")" ]
+       do
+               mntpt=$(eval echo "$""$var")
+               if in_mtab "$mntpt"; then
+                       check_boolean "$VERBOSE_MOUNT" && \
+                           zfs_log_progress_msg "$mntpt "
+                       umount "$mntpt"
+               fi
+
+               i=$((i + 1))
+               var=$(eval echo FSTAB_$i)
+       done
+       check_boolean "$VERBOSE_MOUNT" && zfs_log_end_msg 0
+
+       return 0
+}
+
+do_start()
+{
+       check_boolean "$ZFS_MOUNT" || exit 0
+
+       check_module_loaded "zfs" || exit 0
+
+       # Ensure / exists in /proc/self/mounts.
+       # This should be handled by rc.sysinit but lets be paranoid.
+       if ! chkroot
+       then
+               mount -f /
+       fi
+
+       do_mount
+}
+
+do_stop()
+{
+       check_boolean "$ZFS_UNMOUNT" || exit 0
+
+       check_module_loaded "zfs" || exit 0
+
+       do_unmount
+}
+
+# ----------------------------------------------------
+
+if [ ! -e /sbin/openrc-run ]
+then
+       case "$1" in
+               start)
+                       do_start
+                       ;;
+               stop)
+                       do_stop
+                       ;;
+               force-reload|condrestart|reload|restart|status)
+                       # no-op
+                       ;;
+               *)
+                       [ -n "$1" ] && echo "Error: Unknown command $1."
+                       echo "Usage: $0 {start|stop}"
+                       exit 3
+                       ;;
+       esac
+
+       exit $?
+else
+       # Create wrapper functions since Gentoo don't use the case part.
+       depend() { do_depend; }
+       start() { do_start; }
+       stop() { do_stop; }
+fi
old mode 100644 (file)
new mode 100755 (executable)
index b3e8c13..ce3cc1c
@@ -1,2 +1,85 @@
-%:
-       #
+#!@SHELL@
+#
+# zfs-share     This script will network share zfs filesystems and volumes.
+#
+# chkconfig:    2345 30 99
+# description:  Run the `zfs share -a` or `zfs unshare -a` commands
+#               for controlling iSCSI, NFS, or CIFS network shares.
+# probe: true
+#
+### BEGIN INIT INFO
+# Provides:          zfs-share
+# Required-Start:    $local_fs $network $remote_fs zfs-mount zfs-zed
+# Required-Stop:     $local_fs $network $remote_fs zfs-mount zfs-zed
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Should-Start:      iscsi iscsitarget istgt scst @NFS_SRV@ samba samba4 zfs-mount zfs-zed
+# Should-Stop:       iscsi iscsitarget istgt scst @NFS_SRV@ samba samba4 zfs-mount zfs-zed
+# Short-Description: Network share ZFS datasets and volumes.
+# Description:       Run the `zfs share -a` or `zfs unshare -a` commands
+#                    for controlling iSCSI, NFS, or CIFS network shares.
+### END INIT INFO
+#
+# Released under the 2-clause BSD license.
+#
+# The original script that acted as a template for this script came from
+# the Debian GNU/Linux kFreeBSD ZFS packages (which did not include a
+# licensing stansa) in the commit dated Mar 24, 2011:
+#   https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a
+
+# Source the common init script
+. @sysconfdir@/zfs/zfs-functions
+
+# ----------------------------------------------------
+
+do_depend()
+{
+       after sysfs zfs-mount zfs-zed
+       keyword -lxc -openvz -prefix -vserver
+}
+
+do_start()
+{
+       check_boolean "$ZFS_SHARE" || exit 0
+
+       check_module_loaded "zfs" || exit 0
+
+       zfs_action "Sharing ZFS filesystems" "$ZFS" share -a
+}
+
+do_stop()
+{
+       check_boolean "$ZFS_UNSHARE" || exit 0
+
+       check_module_loaded "zfs" || exit 0
+
+       zfs_action "Unsharing ZFS filesystems" "$ZFS" unshare -a
+}
+
+# ----------------------------------------------------
+
+if [ ! -e /sbin/openrc-run ]; then
+       case "$1" in
+               start)
+                       do_start
+                       ;;
+               stop)
+                       do_stop
+                       ;;
+               force-reload|reload|restart|status)
+                       # no-op
+                       ;;
+               *)
+                       [ -n "$1" ] && echo "Error: Unknown command $1."
+                       echo "Usage: $0 {start|stop}"
+                       exit 3
+                       ;;
+       esac
+
+       exit $?
+else
+       # Create wrapper functions since Gentoo don't use the case part.
+       depend() { do_depend; }
+       start() { do_start; }
+       stop() { do_stop; }
+fi
old mode 100644 (file)
new mode 100755 (executable)
index b3e8c13..d0086ee
@@ -1,2 +1,134 @@
-%:
-       #
+#!@SHELL@
+#
+# zfs-zed
+#
+# chkconfig:    2345 29 99
+# description:  This script will start and stop the ZFS Event Daemon.
+# probe: true
+#
+### BEGIN INIT INFO
+# Provides:          zfs-zed
+# Required-Start:    zfs-mount
+# Required-Stop:     zfs-mount
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# X-Stop-After:      zfs-share
+# Short-Description: ZFS Event Daemon
+# Description:       zed monitors ZFS events. When a zevent is posted, zed
+#                    will run any scripts that have been enabled for the
+#                    corresponding zevent class.
+### END INIT INFO
+#
+# Released under the 2-clause BSD license.
+#
+# The original script that acted as a template for this script came from
+# the Debian GNU/Linux kFreeBSD ZFS packages (which did not include a
+# licensing stansa) in the commit dated Mar 24, 2011:
+#   https://github.com/zfsonlinux/pkg-zfs/commit/80a3ae582b59c0250d7912ba794dca9e669e605a
+
+# Source the common init script
+. @sysconfdir@/zfs/zfs-functions
+
+ZED_NAME="zed"
+ZED_PIDFILE="@runstatedir@/$ZED_NAME.pid"
+
+extra_started_commands="reload"
+
+# Exit if the package is not installed
+[ -x "$ZED" ] || exit 0
+
+# ----------------------------------------------------
+
+do_depend()
+{
+       after zfs-mount localmount
+}
+
+do_start()
+{
+       check_module_loaded "zfs" || exit 0
+
+       ZED_ARGS="$ZED_ARGS -p $ZED_PIDFILE"
+
+       zfs_action "Starting ZFS Event Daemon" zfs_daemon_start \
+           "$ZED_PIDFILE" "$ZED" "$ZED_ARGS"
+       return "$?"
+}
+
+do_stop()
+{
+       local pools RET
+       check_module_loaded "zfs" || exit 0
+
+       zfs_action "Stopping ZFS Event Daemon" zfs_daemon_stop \
+          "$ZED_PIDFILE" "$ZED" "$ZED_NAME"
+       if [ "$?" -eq "0" ]
+       then
+               # Let's see if we have any pools imported
+               pools=$("$ZPOOL" list -H -oname)
+               if [ -z "$pools" ]
+               then
+                       # No pools imported, it is/should be safe/possible to
+                       # unload modules.
+                       zfs_action "Unloading modules" rmmod zfs zunicode \
+                           zavl zcommon znvpair spl
+                       return "$?"
+               fi
+       else
+               return "$?"
+       fi
+}
+
+do_status()
+{
+       check_module_loaded "zfs" || exit 0
+
+       zfs_daemon_status "$ZED_PIDFILE" "$ZED" "$ZED_NAME"
+       return "$?"
+}
+
+do_reload()
+{
+       check_module_loaded "zfs" || exit 0
+
+       zfs_action "Reloading ZFS Event Daemon" zfs_daemon_reload \
+           "$ZED_PIDFILE" "$ZED_NAME"
+       return "$?"
+}
+
+# ----------------------------------------------------
+
+if [ ! -e /sbin/openrc-run ]; then
+       case "$1" in
+               start)
+                       do_start
+                       ;;
+               stop)
+                       do_stop
+                       ;;
+               status)
+                       do_status
+                       ;;
+               reload|force-reload)
+                       do_reload
+                       ;;
+               restart)
+                       do_stop
+                       do_start
+                       ;;
+               *)
+                       [ -n "$1" ] && echo "Error: Unknown command $1."
+                       echo "Usage: $0 {start|stop|status|reload|restart}"
+                       exit 1
+                       ;;
+       esac
+
+       exit $?
+else
+       # Create wrapper functions since Gentoo don't use the case part.
+       depend() { do_depend; }
+       start() { do_start; }
+       stop() { do_stop; }
+       status() { do_status; }
+       reload() { do_reload; }
+fi
index b3e8c1303bda612cfbec58359220e20cc62e48d7..d81ef22c807d5f1bc467948f79eac70b1e2b3edc 100644 (file)
@@ -1,2 +1,132 @@
-%:
-       #
+# ZoL userland configuration.
+
+# To enable a boolean setting, set it to yes, on, true, or 1.
+# Anything else will be interpreted as unset.
+
+# Run `zfs mount -a` during system start?
+ZFS_MOUNT='yes'
+
+# Run `zfs unmount -a` during system stop?
+ZFS_UNMOUNT='yes'
+
+# Run `zfs share -a` during system start?
+# nb: The shareiscsi, sharenfs, and sharesmb dataset properties.
+ZFS_SHARE='yes'
+
+# Run `zfs unshare -a` during system stop?
+ZFS_UNSHARE='yes'
+
+# By default, a verbatim import of all pools is performed at boot based on the
+# contents of the default zpool cache file.  The contents of the cache are
+# managed automatically by the 'zpool import' and 'zpool export' commands.
+#
+# By setting this to 'yes', the system will instead search all devices for
+# pools and attempt to import them all at boot, even those that have been
+# exported.  Under this mode, the search path can be controlled by the
+# ZPOOL_IMPORT_PATH variable and a list of pools that should not be imported
+# can be listed in the ZFS_POOL_EXCEPTIONS variable.
+#
+# Note that importing all visible pools may include pools that you don't
+# expect, such as those on removable devices and SANs, and those pools may
+# proceed to mount themselves in places you do not want them to.  The results
+# can be unpredictable and possibly dangerous.  Only enable this option if you
+# understand this risk and have complete physical control over your system and
+# SAN to prevent the insertion of malicious pools.
+ZPOOL_IMPORT_ALL_VISIBLE='no'
+
+# Specify specific path(s) to look for device nodes and/or links for the
+# pool import(s). See zpool(8) for more information about this variable.
+# It supersedes the old USE_DISK_BY_ID which indicated that it would only
+# try '/dev/disk/by-id'.
+# The old variable will still work in the code, but is deprecated.
+#ZPOOL_IMPORT_PATH="/dev/disk/by-vdev:/dev/disk/by-id"
+
+# List of pools that should NOT be imported at boot
+# when ZPOOL_IMPORT_ALL_VISIBLE is 'yes'.
+# This is a space separated list.
+#ZFS_POOL_EXCEPTIONS="test2"
+
+# List of pools that SHOULD be imported at boot by the initramfs
+# instead of trying to import all available pools.  If this is set
+# then ZFS_POOL_EXCEPTIONS is ignored.
+# Only applicable for Debian GNU/Linux {dkms,initramfs}.
+# This is a semi-colon separated list.
+#ZFS_POOL_IMPORT="pool1;pool2"
+
+# Should the datasets be mounted verbosely?
+# A mount counter will be used when mounting if set to 'yes'.
+VERBOSE_MOUNT='no'
+
+# Should we allow overlay mounts?
+# This is standard in Linux, but not ZFS which comes from Solaris where this
+# is not allowed).
+DO_OVERLAY_MOUNTS='no'
+
+# Any additional option to the 'zfs import' commandline?
+# Include '-o' for each option wanted.
+# You don't need to put '-f' in here, unless you want it ALL the time.
+# Using the option 'zfsforce=1' on the grub/kernel command line will
+# do the same, but on a case-to-case basis.
+ZPOOL_IMPORT_OPTS=""
+
+# Full path to the ZFS cache file?
+# See "cachefile" in zpool(8).
+# The default is "@sysconfdir@/zfs/zpool.cache".
+#ZPOOL_CACHE="@sysconfdir@/zfs/zpool.cache"
+#
+# Setting ZPOOL_CACHE to an empty string ('') AND setting ZPOOL_IMPORT_OPTS to
+# "-c @sysconfdir@/zfs/zpool.cache" will _enforce_ the use of a cache file.
+# This is needed in some cases (extreme amounts of VDEVs, multipath etc).
+# Generally, the use of a cache file is usually not recommended on Linux
+# because it sometimes is more trouble than it's worth (laptops with external
+# devices or when/if device nodes changes names).
+#ZPOOL_IMPORT_OPTS="-c @sysconfdir@/zfs/zpool.cache"
+#ZPOOL_CACHE=""
+
+# Any additional option to the 'zfs mount' command line?
+# Include '-o' for each option wanted.
+MOUNT_EXTRA_OPTIONS=""
+
+# Build kernel modules with the --enable-debug switch?
+# Only applicable for Debian GNU/Linux {dkms,initramfs}.
+ZFS_DKMS_ENABLE_DEBUG='no'
+
+# Build kernel modules with the --enable-debug-dmu-tx switch?
+# Only applicable for Debian GNU/Linux {dkms,initramfs}.
+ZFS_DKMS_ENABLE_DEBUG_DMU_TX='no'
+
+# Keep debugging symbols in kernel modules?
+# Only applicable for Debian GNU/Linux {dkms,initramfs}.
+ZFS_DKMS_DISABLE_STRIP='no'
+
+# Wait for this many seconds in the initrd pre_mountroot?
+# This delays startup and should be '0' on most systems.
+# Only applicable for Debian GNU/Linux {dkms,initramfs}.
+ZFS_INITRD_PRE_MOUNTROOT_SLEEP='0'
+
+# Wait for this many seconds in the initrd mountroot?
+# This delays startup and should be '0' on most systems. This might help on
+# systems which have their ZFS root on a USB disk that takes just a little
+# longer to be available
+# Only applicable for Debian GNU/Linux {dkms,initramfs}.
+ZFS_INITRD_POST_MODPROBE_SLEEP='0'
+
+# List of additional datasets to mount after the root dataset is mounted?
+#
+# The init script will use the mountpoint specified in the 'mountpoint'
+# property value in the dataset to determine where it should be mounted.
+#
+# This is a space separated list, and will be mounted in the order specified,
+# so if one filesystem depends on a previous mountpoint, make sure to put
+# them in the right order.
+#
+# It is not necessary to add filesystems below the root fs here. It is
+# taken care of by the initrd script automatically. These are only for
+# additional filesystems needed. Such as /opt, /usr/local which is not
+# located under the root fs.
+# Example: If root FS is 'rpool/ROOT/rootfs', this would make sense.
+#ZFS_INITRD_ADDITIONAL_DATASETS="rpool/ROOT/usr rpool/ROOT/var"
+
+# Optional arguments for the ZFS Event Daemon (ZED).
+# See zed(8) for more information on available options.
+#ZED_ARGS="-M"
diff --git a/zfs/etc/modules-load.d/Makefile.am b/zfs/etc/modules-load.d/Makefile.am
new file mode 100644 (file)
index 0000000..58c7acd
--- /dev/null
@@ -0,0 +1,13 @@
+modulesload_DATA = \
+       zfs.conf
+
+EXTRA_DIST = \
+       $(top_srcdir)/etc/modules-load.d/zfs.conf.in
+
+$(modulesload_DATA):%:%.in
+       -$(SED) \
+               -e '' \
+               $< >'$@'
+
+distclean-local::
+       -$(RM) $(modulesload_DATA)
diff --git a/zfs/etc/modules-load.d/Makefile.in b/zfs/etc/modules-load.d/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
index b3e8c1303bda612cfbec58359220e20cc62e48d7..8b41baa300cbfb80f1b68d324a993e683670ec45 100644 (file)
@@ -1,2 +1,3 @@
-%:
-       #
+# Always load kernel modules at boot.  The default behavior is to load the
+# kernel modules in the zfs-import-*.service or when blkid(8) detects a pool.
+#zfs
diff --git a/zfs/etc/systemd/Makefile.am b/zfs/etc/systemd/Makefile.am
new file mode 100644 (file)
index 0000000..d4008c0
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = system
diff --git a/zfs/etc/systemd/Makefile.in b/zfs/etc/systemd/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
index b3e8c1303bda612cfbec58359220e20cc62e48d7..4d82778e35ba7d60a76cb7c96f4f1465e13461e4 100644 (file)
@@ -1,2 +1,7 @@
-%:
-       #
+# ZFS is enabled by default
+enable zfs-import-cache.service
+disable zfs-import-scan.service
+enable zfs-mount.service
+enable zfs-share.service
+enable zfs-zed.service
+enable zfs.target
diff --git a/zfs/etc/systemd/system/Makefile.am b/zfs/etc/systemd/system/Makefile.am
new file mode 100644 (file)
index 0000000..b097497
--- /dev/null
@@ -0,0 +1,29 @@
+systemdpreset_DATA = \
+       50-zfs.preset
+
+systemdunit_DATA = \
+       zfs-zed.service \
+       zfs-import-cache.service \
+       zfs-import-scan.service \
+       zfs-mount.service \
+       zfs-share.service \
+       zfs.target
+
+EXTRA_DIST = \
+       $(top_srcdir)/etc/systemd/system/zfs-zed.service.in \
+       $(top_srcdir)/etc/systemd/system/zfs-import-cache.service.in \
+       $(top_srcdir)/etc/systemd/system/zfs-import-scan.service.in \
+       $(top_srcdir)/etc/systemd/system/zfs-mount.service.in \
+       $(top_srcdir)/etc/systemd/system/zfs-share.service.in \
+       $(top_srcdir)/etc/systemd/system/zfs.target.in \
+       $(top_srcdir)/etc/systemd/system/50-zfs.preset.in
+
+$(systemdunit_DATA) $(systemdpreset_DATA):%:%.in
+       -$(SED) -e 's,@bindir\@,$(bindir),g' \
+               -e 's,@runstatedir\@,$(runstatedir),g' \
+               -e 's,@sbindir\@,$(sbindir),g' \
+               -e 's,@sysconfdir\@,$(sysconfdir),g' \
+               $< >'$@'
+
+distclean-local::
+       -$(RM) $(systemdunit_DATA) $(systemdpreset_DATA)
diff --git a/zfs/etc/systemd/system/Makefile.in b/zfs/etc/systemd/system/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
index b3e8c1303bda612cfbec58359220e20cc62e48d7..02184a6027ff5a324cb9c93d625f2f25580eeb21 100644 (file)
@@ -1,2 +1,19 @@
-%:
-       #
+[Unit]
+Description=Import ZFS pools by cache file
+DefaultDependencies=no
+Requires=systemd-udev-settle.service
+After=systemd-udev-settle.service
+After=cryptsetup.target
+After=systemd-remount-fs.service
+Before=dracut-mount.service
+ConditionPathExists=@sysconfdir@/zfs/zpool.cache
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStartPre=/sbin/modprobe zfs
+ExecStart=@sbindir@/zpool import -c @sysconfdir@/zfs/zpool.cache -aN
+
+[Install]
+WantedBy=zfs-mount.service
+WantedBy=zfs.target
index b3e8c1303bda612cfbec58359220e20cc62e48d7..625f3a9553f84326c83883d8bd50f037b2770efb 100644 (file)
@@ -1,2 +1,18 @@
-%:
-       #
+[Unit]
+Description=Import ZFS pools by device scanning
+DefaultDependencies=no
+Requires=systemd-udev-settle.service
+After=systemd-udev-settle.service
+After=cryptsetup.target
+Before=dracut-mount.service
+ConditionPathExists=!@sysconfdir@/zfs/zpool.cache
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStartPre=/sbin/modprobe zfs
+ExecStart=@sbindir@/zpool import -aN -o cachefile=none
+
+[Install]
+WantedBy=zfs-mount.service
+WantedBy=zfs.target
index b3e8c1303bda612cfbec58359220e20cc62e48d7..0664fd9e7665ae55cd5cbf328d0c4937d046f224 100644 (file)
@@ -1,2 +1,17 @@
-%:
-       #
+[Unit]
+Description=Mount ZFS filesystems
+DefaultDependencies=no
+After=systemd-udev-settle.service
+After=zfs-import-cache.service
+After=zfs-import-scan.service
+After=systemd-remount-fs.service
+Before=local-fs.target
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=@sbindir@/zfs mount -a
+
+[Install]
+WantedBy=zfs-share.service
+WantedBy=zfs.target
index b3e8c1303bda612cfbec58359220e20cc62e48d7..688731ea3e273c8a7d778f30ddf41d8b4e13a68d 100644 (file)
@@ -1,2 +1,16 @@
-%:
-       #
+[Unit]
+Description=ZFS file system shares
+After=nfs-server.service nfs-kernel-server.service
+After=smb.service
+After=zfs-mount.service
+PartOf=nfs-server.service nfs-kernel-server.service
+PartOf=smb.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStartPre=-@bindir@/rm -f /etc/dfs/sharetab
+ExecStart=@sbindir@/zfs share -a
+
+[Install]
+WantedBy=zfs.target
index b3e8c1303bda612cfbec58359220e20cc62e48d7..e3dec3dca1b66da5e3f8a2e2eb9054532ed96377 100644 (file)
@@ -1,2 +1,13 @@
-%:
-       #
+[Unit]
+Description=ZFS Event Daemon (zed)
+Documentation=man:zed(8)
+After=zfs-import-cache.service
+After=zfs-import-scan.service
+
+[Service]
+ExecStart=@sbindir@/zed -F
+Restart=on-abort
+
+[Install]
+Alias=zed.service
+WantedBy=zfs.target
index b3e8c1303bda612cfbec58359220e20cc62e48d7..4699463b0ddf334430eafacb4d4d99d0144e49a1 100644 (file)
@@ -1,2 +1,5 @@
-%:
-       #
+[Unit]
+Description=ZFS startup target
+
+[Install]
+WantedBy=multi-user.target
diff --git a/zfs/etc/zfs/Makefile.am b/zfs/etc/zfs/Makefile.am
new file mode 100644 (file)
index 0000000..ff35469
--- /dev/null
@@ -0,0 +1,9 @@
+pkgsysconfdir = $(sysconfdir)/zfs
+
+pkgsysconf_DATA = \
+       vdev_id.conf.alias.example \
+       vdev_id.conf.sas_direct.example \
+       vdev_id.conf.sas_switch.example \
+       vdev_id.conf.multipath.example
+
+EXTRA_DIST = $(pkgsysconf_DATA)
diff --git a/zfs/etc/zfs/Makefile.in b/zfs/etc/zfs/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/etc/zfs/vdev_id.conf.alias.example b/zfs/etc/zfs/vdev_id.conf.alias.example
new file mode 100644 (file)
index 0000000..33735b0
--- /dev/null
@@ -0,0 +1,4 @@
+#     by-vdev
+#     name     fully qualified or base name of device link
+alias d1       /dev/disk/by-id/wwn-0x5000c5002de3b9ca
+alias d2       wwn-0x5000c5002def789e
diff --git a/zfs/etc/zfs/vdev_id.conf.multipath.example b/zfs/etc/zfs/vdev_id.conf.multipath.example
new file mode 100644 (file)
index 0000000..c1359d3
--- /dev/null
@@ -0,0 +1,7 @@
+multipath yes
+
+#       PCI_ID  HBA PORT  CHANNEL NAME
+channel 85:00.0 1         A
+channel 85:00.0 0         B
+channel 86:00.0 1         A
+channel 86:00.0 0         B
diff --git a/zfs/etc/zfs/vdev_id.conf.sas_direct.example b/zfs/etc/zfs/vdev_id.conf.sas_direct.example
new file mode 100644 (file)
index 0000000..115ebd8
--- /dev/null
@@ -0,0 +1,25 @@
+multipath     no
+topology      sas_direct
+phys_per_port 4
+
+#       PCI_ID  HBA PORT  CHANNEL NAME
+channel 85:00.0 1         A
+channel 85:00.0 0         B
+channel 86:00.0 1         C
+channel 86:00.0 0         D
+
+
+# Custom mapping for Channel A
+
+#    Linux      Mapped
+#    Slot       Slot      Channel
+slot 1          7         A
+slot 2          10        A
+slot 3          3         A
+slot 4          6         A
+
+# Default mapping for B, C, and D
+slot 1          4
+slot 2          2
+slot 3          1
+slot 4          3
diff --git a/zfs/etc/zfs/vdev_id.conf.sas_switch.example b/zfs/etc/zfs/vdev_id.conf.sas_switch.example
new file mode 100644 (file)
index 0000000..b87d655
--- /dev/null
@@ -0,0 +1,7 @@
+topology      sas_switch
+
+#       SWITCH PORT  CHANNEL NAME
+channel 1            A
+channel 2            B
+channel 3            C
+channel 4            D
diff --git a/zfs/include/Makefile.in b/zfs/include/Makefile.in
deleted file mode 100644 (file)
index b9ed979..0000000
+++ /dev/null
@@ -1,907 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = include
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__kernel_HEADERS_DIST) \
-       $(am__libzfs_HEADERS_DIST) $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-       ctags-recursive dvi-recursive html-recursive info-recursive \
-       install-data-recursive install-dvi-recursive \
-       install-exec-recursive install-html-recursive \
-       install-info-recursive install-pdf-recursive \
-       install-ps-recursive install-recursive installcheck-recursive \
-       installdirs-recursive pdf-recursive ps-recursive \
-       tags-recursive uninstall-recursive
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__kernel_HEADERS_DIST = $(top_srcdir)/include/zfeature_common.h \
-       $(top_srcdir)/include/zfs_comutil.h \
-       $(top_srcdir)/include/zfs_deleg.h \
-       $(top_srcdir)/include/zfs_fletcher.h \
-       $(top_srcdir)/include/zfs_namecheck.h \
-       $(top_srcdir)/include/zfs_prop.h \
-       $(top_srcdir)/include/zpios-ctl.h \
-       $(top_srcdir)/include/zpios-internal.h
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"
-am__libzfs_HEADERS_DIST = $(top_srcdir)/include/zfeature_common.h \
-       $(top_srcdir)/include/zfs_comutil.h \
-       $(top_srcdir)/include/zfs_deleg.h \
-       $(top_srcdir)/include/zfs_fletcher.h \
-       $(top_srcdir)/include/zfs_namecheck.h \
-       $(top_srcdir)/include/zfs_prop.h \
-       $(top_srcdir)/include/zpios-ctl.h \
-       $(top_srcdir)/include/libnvpair.h \
-       $(top_srcdir)/include/libuutil_common.h \
-       $(top_srcdir)/include/libuutil.h \
-       $(top_srcdir)/include/libuutil_impl.h \
-       $(top_srcdir)/include/libzfs.h \
-       $(top_srcdir)/include/libzfs_core.h \
-       $(top_srcdir)/include/libzfs_impl.h
-HEADERS = $(kernel_HEADERS) $(libzfs_HEADERS)
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-       distdir
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-SUBDIRS = linux sys
-COMMON_H = \
-       $(top_srcdir)/include/zfeature_common.h \
-       $(top_srcdir)/include/zfs_comutil.h \
-       $(top_srcdir)/include/zfs_deleg.h \
-       $(top_srcdir)/include/zfs_fletcher.h \
-       $(top_srcdir)/include/zfs_namecheck.h \
-       $(top_srcdir)/include/zfs_prop.h \
-       $(top_srcdir)/include/zpios-ctl.h
-
-KERNEL_H = \
-       $(top_srcdir)/include/zpios-internal.h
-
-USER_H = \
-       $(top_srcdir)/include/libnvpair.h \
-       $(top_srcdir)/include/libuutil_common.h \
-       $(top_srcdir)/include/libuutil.h \
-       $(top_srcdir)/include/libuutil_impl.h \
-       $(top_srcdir)/include/libzfs.h \
-       $(top_srcdir)/include/libzfs_core.h \
-       $(top_srcdir)/include/libzfs_impl.h
-
-EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
-@CONFIG_USER_TRUE@libzfsdir = $(includedir)/libzfs
-@CONFIG_USER_TRUE@libzfs_HEADERS = $(COMMON_H) $(USER_H)
-@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/zfs-$(VERSION)/include
-@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
-all: all-recursive
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu include/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-install-kernelHEADERS: $(kernel_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(kerneldir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(kerneldir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(kerneldir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(kerneldir)" || exit $$?; \
-       done
-
-uninstall-kernelHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(kerneldir)'; $(am__uninstall_files_from_dir)
-install-libzfsHEADERS: $(libzfs_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(libzfsdir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(libzfsdir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libzfsdir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(libzfsdir)" || exit $$?; \
-       done
-
-uninstall-libzfsHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(libzfsdir)'; $(am__uninstall_files_from_dir)
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-       @fail=; \
-       if $(am__make_keepgoing); then \
-         failcom='fail=yes'; \
-       else \
-         failcom='exit 1'; \
-       fi; \
-       dot_seen=no; \
-       target=`echo $@ | sed s/-recursive//`; \
-       case "$@" in \
-         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-         *) list='$(SUBDIRS)' ;; \
-       esac; \
-       for subdir in $$list; do \
-         echo "Making $$target in $$subdir"; \
-         if test "$$subdir" = "."; then \
-           dot_seen=yes; \
-           local_target="$$target-am"; \
-         else \
-           local_target="$$target"; \
-         fi; \
-         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-         || eval $$failcom; \
-       done; \
-       if test "$$dot_seen" = "no"; then \
-         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-       fi; test -z "$$fail"
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-         include_option=--etags-include; \
-         empty_fix=.; \
-       else \
-         include_option=--include; \
-         empty_fix=; \
-       fi; \
-       list='$(SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           test ! -f $$subdir/TAGS || \
-             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-         fi; \
-       done; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-ctags: ctags-recursive
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-recursive
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           $(am__make_dryrun) \
-             || test -d "$(distdir)/$$subdir" \
-             || $(MKDIR_P) "$(distdir)/$$subdir" \
-             || exit 1; \
-           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-           $(am__relativize); \
-           new_distdir=$$reldir; \
-           dir1=$$subdir; dir2="$(top_distdir)"; \
-           $(am__relativize); \
-           new_top_distdir=$$reldir; \
-           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-           ($(am__cd) $$subdir && \
-             $(MAKE) $(AM_MAKEFLAGS) \
-               top_distdir="$$new_top_distdir" \
-               distdir="$$new_distdir" \
-               am__remove_distdir=: \
-               am__skip_length_check=: \
-               am__skip_mode_fix=: \
-               distdir) \
-             || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-recursive
-all-am: Makefile $(HEADERS)
-installdirs: installdirs-recursive
-installdirs-am:
-       for dir in "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-recursive
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-recursive
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-recursive
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-tags
-
-dvi: dvi-recursive
-
-dvi-am:
-
-html: html-recursive
-
-html-am:
-
-info: info-recursive
-
-info-am:
-
-install-data-am: install-kernelHEADERS install-libzfsHEADERS
-
-install-dvi: install-dvi-recursive
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-recursive
-
-install-html-am:
-
-install-info: install-info-recursive
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-recursive
-
-install-pdf-am:
-
-install-ps: install-ps-recursive
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-recursive
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-recursive
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-recursive
-
-pdf-am:
-
-ps: ps-recursive
-
-ps-am:
-
-uninstall-am: uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.MAKE: $(am__recursive_targets) install-am install-strip
-
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
-       check-am clean clean-generic clean-libtool cscopelist-am ctags \
-       ctags-am distclean distclean-generic distclean-libtool \
-       distclean-tags distdir dvi dvi-am html html-am info info-am \
-       install install-am install-data install-data-am install-dvi \
-       install-dvi-am install-exec install-exec-am install-html \
-       install-html-am install-info install-info-am \
-       install-kernelHEADERS install-libzfsHEADERS install-man \
-       install-pdf install-pdf-am install-ps install-ps-am \
-       install-strip installcheck installcheck-am installdirs \
-       installdirs-am maintainer-clean maintainer-clean-generic \
-       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
-       ps ps-am tags tags-am uninstall uninstall-am \
-       uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index 26847e0653e0401e723bea0297025246696d6c88..d4962dec68c12a82ecd7a2d2dcb8ca43a1481df9 100644 (file)
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2016, Intel Corporation.
  */
 
 #ifndef        _LIBZFS_H
@@ -48,8 +49,6 @@ extern "C" {
 /*
  * Miscellaneous ZFS constants
  */
-#define        ZFS_MAXNAMELEN          MAXNAMELEN
-#define        ZPOOL_MAXNAMELEN        MAXNAMELEN
 #define        ZFS_MAXPROPLEN          MAXPATHLEN
 #define        ZPOOL_MAXPROPLEN        MAXPATHLEN
 
@@ -58,13 +57,14 @@ extern "C" {
  */
 #define        DISK_ROOT               "/dev"
 #define        UDISK_ROOT              "/dev/disk"
+#define        ZVOL_ROOT               "/dev/zvol"
 
 /*
  * Default wait time for a device name to be created.
  */
 #define        DISK_LABEL_WAIT         (30 * 1000)  /* 30 seconds */
 
-#define        DEFAULT_IMPORT_PATH_SIZE        7
+#define        DEFAULT_IMPORT_PATH_SIZE        9
 extern char *zpool_default_import_path[DEFAULT_IMPORT_PATH_SIZE];
 
 /*
@@ -280,13 +280,15 @@ extern nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
 extern int zpool_label_disk_wait(char *, int);
 extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, char *);
 
+int zfs_dev_is_dm(char *dev_name);
+char *zfs_get_underlying_path(char *dev_name);
+char *zfs_get_enclosure_sysfs_path(char *dev_name);
+
 /*
  * Functions to manage pool properties
  */
 extern int zpool_set_prop(zpool_handle_t *, const char *, const char *);
 extern int zpool_get_prop(zpool_handle_t *, zpool_prop_t, char *,
-    size_t proplen, zprop_source_t *);
-extern int zpool_get_prop_literal(zpool_handle_t *, zpool_prop_t, char *,
     size_t proplen, zprop_source_t *, boolean_t literal);
 extern uint64_t zpool_get_prop_int(zpool_handle_t *, zpool_prop_t,
     zprop_source_t *);
@@ -343,7 +345,7 @@ typedef enum {
        ZPOOL_STATUS_VERSION_OLDER,     /* older legacy on-disk version */
        ZPOOL_STATUS_FEAT_DISABLED,     /* supported features are disabled */
        ZPOOL_STATUS_RESILVERING,       /* device being resilvered */
-       ZPOOL_STATUS_OFFLINE_DEV,       /* device online */
+       ZPOOL_STATUS_OFFLINE_DEV,       /* device offline */
        ZPOOL_STATUS_REMOVED_DEV,       /* removed device */
 
        /*
@@ -391,6 +393,7 @@ typedef struct importargs {
        int can_be_active : 1;  /* can the pool be active?              */
        int unique : 1;         /* does 'poolname' already exist?       */
        int exists : 1;         /* set on return if pool already exists */
+       int scan : 1;           /* prefer scanning to libblkid cache    */
 } importargs_t;
 
 extern nvlist_t *zpool_search_import(libzfs_handle_t *, importargs_t *);
@@ -456,10 +459,11 @@ extern const char *zfs_prop_column_name(zfs_prop_t);
 extern boolean_t zfs_prop_align_right(zfs_prop_t);
 
 extern nvlist_t *zfs_valid_proplist(libzfs_handle_t *, zfs_type_t,
-    nvlist_t *, uint64_t, zfs_handle_t *, const char *);
+    nvlist_t *, uint64_t, zfs_handle_t *, zpool_handle_t *, const char *);
 
 extern const char *zfs_prop_to_name(zfs_prop_t);
 extern int zfs_prop_set(zfs_handle_t *, const char *, const char *);
+extern int zfs_prop_set_list(zfs_handle_t *, nvlist_t *);
 extern int zfs_prop_get(zfs_handle_t *, zfs_prop_t, char *, size_t,
     zprop_source_t *, char *, size_t, boolean_t);
 extern int zfs_prop_get_recvd(zfs_handle_t *, const char *, char *, size_t,
@@ -631,6 +635,9 @@ typedef struct sendflags {
 
        /* WRITE_EMBEDDED records of type DATA are permitted */
        boolean_t embed_data;
+
+       /* compressed WRITE records are permitted */
+       boolean_t compress;
 } sendflags_t;
 
 typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
@@ -638,6 +645,10 @@ typedef boolean_t (snapfilter_cb_t)(zfs_handle_t *, void *);
 extern int zfs_send(zfs_handle_t *, const char *, const char *,
     sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **);
 extern int zfs_send_one(zfs_handle_t *, const char *, int, enum lzc_send_flags);
+extern int zfs_send_resume(libzfs_handle_t *, sendflags_t *, int outfd,
+    const char *);
+extern nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl,
+    const char *token);
 
 extern int zfs_promote(zfs_handle_t *);
 extern int zfs_hold(zfs_handle_t *, const char *, const char *,
@@ -678,6 +689,12 @@ typedef struct recvflags {
        /* set "canmount=off" on all modified filesystems */
        boolean_t canmountoff;
 
+       /*
+        * Mark the file systems as "resumable" and do not destroy them if the
+        * receive is interrupted
+        */
+       boolean_t resumable;
+
        /* byteswap flag is used internally; callers need not specify */
        boolean_t byteswap;
 
@@ -685,8 +702,8 @@ typedef struct recvflags {
        boolean_t nomount;
 } recvflags_t;
 
-extern int zfs_receive(libzfs_handle_t *, const char *, recvflags_t *,
-    int, avl_tree_t *);
+extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *,
+    recvflags_t *, int, avl_tree_t *);
 
 typedef enum diff_flags {
        ZFS_DIFF_PARSEABLE = 0x1,
@@ -745,10 +762,21 @@ extern int zfs_unshareall(zfs_handle_t *);
 extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, char *,
     void *, void *, int, zfs_share_op_t);
 
+enum zfs_nicenum_format {
+       ZFS_NICENUM_1024 = 0,
+       ZFS_NICENUM_TIME = 1,
+       ZFS_NICENUM_RAW = 2
+};
+
 /*
  * Utility function to convert a number to a human-readable form.
  */
 extern void zfs_nicenum(uint64_t, char *, size_t);
+extern void zfs_nicenum_format(uint64_t num, char *buf, size_t buflen,
+    enum zfs_nicenum_format type);
+
+
+extern void zfs_nicetime(uint64_t, char *, size_t);
 extern int zfs_nicestrtonum(libzfs_handle_t *, const char *, uint64_t *);
 
 /*
@@ -798,6 +826,21 @@ extern boolean_t libzfs_fru_compare(libzfs_handle_t *, const char *,
 extern boolean_t libzfs_fru_notself(libzfs_handle_t *, const char *);
 extern int zpool_fru_set(zpool_handle_t *, uint64_t, const char *);
 
+/*
+ * Support for Linux libudev derived persistent device strings
+ */
+extern boolean_t is_mpath_whole_disk(const char *);
+extern void update_vdev_config_dev_strs(nvlist_t *);
+extern char *zfs_strip_partition(char *);
+
+#ifdef HAVE_LIBUDEV
+struct udev_device;
+
+extern boolean_t udev_is_mpath(struct udev_device *dev);
+extern int zfs_device_get_devid(struct udev_device *, char *, size_t);
+extern int zfs_device_get_physical(struct udev_device *, char *, size_t);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
index bdd6c951ee496dc1e21a297e7a69b1342aecf79b..bc0f115bbfdfb3cb83bb242099576b11c4d5f734 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  */
 
 #ifndef        _LIBZFS_CORE_H
@@ -54,12 +54,25 @@ int lzc_get_holds(const char *, nvlist_t **);
 
 enum lzc_send_flags {
        LZC_SEND_FLAG_EMBED_DATA = 1 << 0,
-       LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1
+       LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1,
+       LZC_SEND_FLAG_COMPRESS = 1 << 2
 };
 
 int lzc_send(const char *, const char *, int, enum lzc_send_flags);
+int lzc_send_resume(const char *, const char *, int,
+    enum lzc_send_flags, uint64_t, uint64_t);
+int lzc_send_space(const char *, const char *, enum lzc_send_flags, uint64_t *);
+
+struct dmu_replay_record;
+
 int lzc_receive(const char *, nvlist_t *, const char *, boolean_t, int);
-int lzc_send_space(const char *, const char *, uint64_t *);
+int lzc_receive_resumable(const char *, nvlist_t *, const char *,
+    boolean_t, int);
+int lzc_receive_with_header(const char *, nvlist_t *, const char *, boolean_t,
+    boolean_t, int, const struct dmu_replay_record *);
+int lzc_receive_one(const char *, nvlist_t *, const char *, boolean_t,
+    boolean_t, int, const struct dmu_replay_record *, int, uint64_t *,
+    uint64_t *, uint64_t *, nvlist_t **);
 
 boolean_t lzc_exists(const char *);
 
index e805e3ee70455f60b2ce76ff6f7b32dd84a5b136..36441ed7bb3ab5f7741866c5c73fa877f73b28b1 100644 (file)
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 #ifndef        _LIBZFS_IMPL_H
 #define        _LIBZFS_IMPL_H
 
-#include <sys/dmu.h>
 #include <sys/fs/zfs.h>
-#include <sys/zfs_ioctl.h>
 #include <sys/spa.h>
 #include <sys/nvpair.h>
+#include <sys/dmu.h>
+#include <sys/zfs_ioctl.h>
 
 #include <libuutil.h>
 #include <libzfs.h>
 extern "C" {
 #endif
 
-#ifdef VERIFY
-#undef VERIFY
-#endif
-#define        VERIFY  verify
-
 typedef struct libzfs_fru {
        char *zf_device;
        char *zf_fru;
@@ -90,7 +85,7 @@ struct libzfs_handle {
 struct zfs_handle {
        libzfs_handle_t *zfs_hdl;
        zpool_handle_t *zpool_hdl;
-       char zfs_name[ZFS_MAXNAMELEN];
+       char zfs_name[ZFS_MAX_DATASET_NAME_LEN];
        zfs_type_t zfs_type; /* type including snapshot */
        zfs_type_t zfs_head_type; /* type excluding snapshot */
        dmu_objset_stats_t zfs_dmustats;
@@ -111,7 +106,7 @@ struct zfs_handle {
 struct zpool_handle {
        libzfs_handle_t *zpool_hdl;
        zpool_handle_t *zpool_next;
-       char zpool_name[ZPOOL_MAXNAMELEN];
+       char zpool_name[ZFS_MAX_DATASET_NAME_LEN];
        int zpool_state;
        size_t zpool_config_size;
        nvlist_t *zpool_config;
@@ -150,8 +145,6 @@ int zfs_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
 int zpool_standard_error(libzfs_handle_t *, int, const char *);
 int zpool_standard_error_fmt(libzfs_handle_t *, int, const char *, ...);
 
-int get_dependents(libzfs_handle_t *, boolean_t, const char *, char ***,
-    size_t *);
 zfs_handle_t *make_dataset_handle_zc(libzfs_handle_t *, zfs_cmd_t *);
 zfs_handle_t *make_dataset_simple_handle_zc(zfs_handle_t *, zfs_cmd_t *);
 
index 595d1db01128d4176f8c2eb3869a66688e90b074..9bb0b3493e5d96e1c65c467943d751720783d553 100644 (file)
@@ -6,7 +6,10 @@ KERNEL_H = \
        $(top_srcdir)/include/linux/vfs_compat.h \
        $(top_srcdir)/include/linux/blkdev_compat.h \
        $(top_srcdir)/include/linux/utsname_compat.h \
-       $(top_srcdir)/include/linux/kmap_compat.h
+       $(top_srcdir)/include/linux/kmap_compat.h \
+       $(top_srcdir)/include/linux/simd_x86.h \
+       $(top_srcdir)/include/linux/simd_aarch64.h \
+       $(top_srcdir)/include/linux/mod_compat.h
 
 USER_H =
 
diff --git a/zfs/include/linux/Makefile.in b/zfs/include/linux/Makefile.in
deleted file mode 100644 (file)
index a887a65..0000000
+++ /dev/null
@@ -1,763 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = include/linux
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__kernel_HEADERS_DIST) \
-       $(libzfs_HEADERS) $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__kernel_HEADERS_DIST = $(top_srcdir)/include/linux/dcache_compat.h \
-       $(top_srcdir)/include/linux/xattr_compat.h \
-       $(top_srcdir)/include/linux/vfs_compat.h \
-       $(top_srcdir)/include/linux/blkdev_compat.h \
-       $(top_srcdir)/include/linux/utsname_compat.h \
-       $(top_srcdir)/include/linux/kmap_compat.h
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"
-HEADERS = $(kernel_HEADERS) $(libzfs_HEADERS)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-COMMON_H = 
-KERNEL_H = \
-       $(top_srcdir)/include/linux/dcache_compat.h \
-       $(top_srcdir)/include/linux/xattr_compat.h \
-       $(top_srcdir)/include/linux/vfs_compat.h \
-       $(top_srcdir)/include/linux/blkdev_compat.h \
-       $(top_srcdir)/include/linux/utsname_compat.h \
-       $(top_srcdir)/include/linux/kmap_compat.h
-
-USER_H = 
-EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
-@CONFIG_USER_TRUE@libzfsdir = $(includedir)/libzfs/linux
-@CONFIG_USER_TRUE@libzfs_HEADERS = $(COMMON_H) $(USER_H)
-@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/zfs-$(VERSION)/include/linux
-@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
-all: all-am
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/linux/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu include/linux/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-install-kernelHEADERS: $(kernel_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(kerneldir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(kerneldir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(kerneldir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(kerneldir)" || exit $$?; \
-       done
-
-uninstall-kernelHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(kerneldir)'; $(am__uninstall_files_from_dir)
-install-libzfsHEADERS: $(libzfs_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(libzfsdir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(libzfsdir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libzfsdir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(libzfsdir)" || exit $$?; \
-       done
-
-uninstall-libzfsHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(libzfsdir)'; $(am__uninstall_files_from_dir)
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-am
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-ctags: ctags-am
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-am
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-am
-all-am: Makefile $(HEADERS)
-installdirs:
-       for dir in "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-am
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-tags
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-kernelHEADERS install-libzfsHEADERS
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.MAKE: install-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
-       clean-libtool cscopelist-am ctags ctags-am distclean \
-       distclean-generic distclean-libtool distclean-tags distdir dvi \
-       dvi-am html html-am info info-am install install-am \
-       install-data install-data-am install-dvi install-dvi-am \
-       install-exec install-exec-am install-html install-html-am \
-       install-info install-info-am install-kernelHEADERS \
-       install-libzfsHEADERS install-man install-pdf install-pdf-am \
-       install-ps install-ps-am install-strip installcheck \
-       installcheck-am installdirs maintainer-clean \
-       maintainer-clean-generic mostlyclean mostlyclean-generic \
-       mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
-       uninstall-am uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index d26d242954c1121baccaea52c8932c969d7aa0c9..1f90b98254798921763c86f7690618cddd9b36b3 100644 (file)
@@ -145,6 +145,7 @@ get_disk_ro(struct gendisk *disk)
 #define        BIO_BI_SECTOR(bio)      (bio)->bi_iter.bi_sector
 #define        BIO_BI_SIZE(bio)        (bio)->bi_iter.bi_size
 #define        BIO_BI_IDX(bio)         (bio)->bi_iter.bi_idx
+#define        BIO_BI_SKIP(bio)        (bio)->bi_iter.bi_bvec_done
 #define        bio_for_each_segment4(bv, bvp, b, i)    \
        bio_for_each_segment((bv), (b), (i))
 typedef struct bvec_iter bvec_iterator_t;
@@ -152,6 +153,7 @@ typedef struct bvec_iter bvec_iterator_t;
 #define        BIO_BI_SECTOR(bio)      (bio)->bi_sector
 #define        BIO_BI_SIZE(bio)        (bio)->bi_size
 #define        BIO_BI_IDX(bio)         (bio)->bi_idx
+#define        BIO_BI_SKIP(bio)        (0)
 #define        bio_for_each_segment4(bv, bvp, b, i)    \
        bio_for_each_segment((bvp), (b), (i))
 typedef int bvec_iterator_t;
@@ -261,12 +263,21 @@ bio_set_flags_failfast(struct block_device *bdev, int *flags)
 
 /*
  * 2.6.27 API change
- * The function was exported for use, prior to this it existed by the
+ * The function was exported for use, prior to this it existed but the
  * symbol was not exported.
+ *
+ * 4.4.0-6.21 API change for Ubuntu
+ * lookup_bdev() gained a second argument, FMODE_*, to check inode permissions.
  */
-#ifndef HAVE_LOOKUP_BDEV
-#define        lookup_bdev(path)               ERR_PTR(-ENOTSUP)
-#endif
+#ifdef HAVE_1ARG_LOOKUP_BDEV
+#define        vdev_lookup_bdev(path)  lookup_bdev(path)
+#else
+#ifdef HAVE_2ARGS_LOOKUP_BDEV
+#define        vdev_lookup_bdev(path)  lookup_bdev(path, 0)
+#else
+#define        vdev_lookup_bdev(path)  ERR_PTR(-ENOTSUP)
+#endif /* HAVE_2ARGS_LOOKUP_BDEV */
+#endif /* HAVE_1ARG_LOOKUP_BDEV */
 
 /*
  * 2.6.30 API change
@@ -324,6 +335,10 @@ bio_set_flags_failfast(struct block_device *bdev, int *flags)
  * and the new preflush behavior introduced in Linux 4.8.  This is correct
  * in all cases but may have a performance impact for some kernels.  It
  * has the advantage of minimizing kernel specific changes in the zvol code.
+ *
+ * Note that 2.6.32 era kernels provide both BIO_RW_BARRIER and REQ_FLUSH,
+ * where BIO_RW_BARRIER is the correct interface.  Therefore, it is important
+ * that the HAVE_BIO_RW_BARRIER check occur before the REQ_FLUSH check.
  */
 static inline boolean_t
 bio_is_flush(struct bio *bio)
@@ -334,10 +349,10 @@ bio_is_flush(struct bio *bio)
        return (bio->bi_opf & REQ_PREFLUSH);
 #elif defined(REQ_PREFLUSH) && !defined(HAVE_BIO_BI_OPF)
        return (bio->bi_rw & REQ_PREFLUSH);
-#elif defined(REQ_FLUSH)
-       return (bio->bi_rw & REQ_FLUSH);
 #elif defined(HAVE_BIO_RW_BARRIER)
        return (bio->bi_rw & (1 << BIO_RW_BARRIER));
+#elif defined(REQ_FLUSH)
+       return (bio->bi_rw & REQ_FLUSH);
 #else
 #error "Allowing the build will cause flush requests to be ignored. Please "
        "file an issue report at: https://github.com/zfsonlinux/zfs/issues/new"
@@ -376,16 +391,20 @@ bio_is_fua(struct bio *bio)
  *
  * In all cases the normal I/O path is used for discards.  The only
  * difference is how the kernel tags individual I/Os as discards.
+ *
+ * Note that 2.6.32 era kernels provide both BIO_RW_DISCARD and REQ_DISCARD,
+ * where BIO_RW_DISCARD is the correct interface.  Therefore, it is important
+ * that the HAVE_BIO_RW_DISCARD check occur before the REQ_DISCARD check.
  */
 static inline boolean_t
 bio_is_discard(struct bio *bio)
 {
 #if defined(HAVE_REQ_OP_DISCARD)
        return (bio_op(bio) == REQ_OP_DISCARD);
-#elif defined(REQ_DISCARD)
-       return (bio->bi_rw & REQ_DISCARD);
 #elif defined(HAVE_BIO_RW_DISCARD)
        return (bio->bi_rw & (1 << BIO_RW_DISCARD));
+#elif defined(REQ_DISCARD)
+       return (bio->bi_rw & REQ_DISCARD);
 #else
 #error "Allowing the build will cause discard requests to become writes "
        "potentially triggering the DMU_MAX_ACCESS assertion. Please file "
diff --git a/zfs/include/linux/mod_compat.h b/zfs/include/linux/mod_compat.h
new file mode 100644 (file)
index 0000000..32aea44
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 (C) 2016 Gvozden Neskovic <neskovic@gmail.com>.
+ */
+
+#ifndef _MOD_COMPAT_H
+#define        _MOD_COMPAT_H
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+/* Grsecurity kernel API change */
+#ifdef MODULE_PARAM_CALL_CONST
+typedef const struct kernel_param zfs_kernel_param_t;
+#else
+typedef struct kernel_param zfs_kernel_param_t;
+#endif
+
+#endif /* _MOD_COMPAT_H */
diff --git a/zfs/include/linux/simd_aarch64.h b/zfs/include/linux/simd_aarch64.h
new file mode 100644 (file)
index 0000000..155ef62
--- /dev/null
@@ -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 (C) 2016 Romain Dolbeau <romain@dolbeau.org>.
+ */
+
+/*
+ * USER API:
+ *
+ * Kernel fpu methods:
+ *     kfpu_begin()
+ *     kfpu_end()
+ */
+
+#ifndef _SIMD_AARCH64_H
+#define        _SIMD_AARCH64_H
+
+#include <sys/isa_defs.h>
+
+#if defined(__aarch64__)
+
+#include <sys/types.h>
+
+#if defined(_KERNEL)
+#include <asm/neon.h>
+#define        kfpu_begin()            \
+{                                      \
+       kernel_neon_begin();            \
+}
+#define        kfpu_end()                      \
+{                                      \
+       kernel_neon_end();              \
+}
+#else
+/*
+ * fpu dummy methods for userspace
+ */
+#define        kfpu_begin()    do {} while (0)
+#define        kfpu_end()              do {} while (0)
+#endif /* defined(_KERNEL) */
+
+#endif /* __aarch64__ */
+
+#endif /* _SIMD_AARCH64_H */
diff --git a/zfs/include/linux/simd_x86.h b/zfs/include/linux/simd_x86.h
new file mode 100644 (file)
index 0000000..216dbed
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+ * 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 (C) 2016 Gvozden Neskovic <neskovic@compeng.uni-frankfurt.de>.
+ */
+
+/*
+ * USER API:
+ *
+ * Kernel fpu methods:
+ *     kfpu_begin()
+ *     kfpu_end()
+ *
+ * SIMD support:
+ *
+ * Following functions should be called to determine whether CPU feature
+ * is supported. All functions are usable in kernel and user space.
+ * If a SIMD algorithm is using more than one instruction set
+ * all relevant feature test functions should be called.
+ *
+ * Supported features:
+ *     zfs_sse_available()
+ *     zfs_sse2_available()
+ *     zfs_sse3_available()
+ *     zfs_ssse3_available()
+ *     zfs_sse4_1_available()
+ *     zfs_sse4_2_available()
+ *
+ *     zfs_avx_available()
+ *     zfs_avx2_available()
+ *
+ *     zfs_bmi1_available()
+ *     zfs_bmi2_available()
+ *
+ *     zfs_avx512f_available()
+ *     zfs_avx512cd_available()
+ *     zfs_avx512er_available()
+ *     zfs_avx512pf_available()
+ *     zfs_avx512bw_available()
+ *     zfs_avx512dq_available()
+ *     zfs_avx512vl_available()
+ *     zfs_avx512ifma_available()
+ *     zfs_avx512vbmi_available()
+ *
+ * NOTE(AVX-512VL):    If using AVX-512 instructions with 128Bit registers
+ *                     also add zfs_avx512vl_available() to feature check.
+ */
+
+#ifndef _SIMD_X86_H
+#define        _SIMD_X86_H
+
+#include <sys/isa_defs.h>
+
+/* only for __x86 */
+#if defined(__x86)
+
+#include <sys/types.h>
+
+#if defined(_KERNEL)
+#include <asm/cpufeature.h>
+#else
+#include <cpuid.h>
+#endif
+
+#if defined(_KERNEL)
+#if defined(HAVE_FPU_API_H)
+#include <asm/fpu/api.h>
+#include <asm/fpu/internal.h>
+#define        kfpu_begin()            \
+{                                                      \
+       preempt_disable();              \
+       __kernel_fpu_begin();   \
+}
+#define        kfpu_end()                      \
+{                                                      \
+       __kernel_fpu_end();             \
+       preempt_enable();               \
+}
+#else
+#include <asm/i387.h>
+#include <asm/xcr.h>
+#define        kfpu_begin()    kernel_fpu_begin()
+#define        kfpu_end()              kernel_fpu_end()
+#endif /* defined(HAVE_FPU_API_H) */
+#else
+/*
+ * fpu dummy methods for userspace
+ */
+#define        kfpu_begin()    do {} while (0)
+#define        kfpu_end()              do {} while (0)
+#endif /* defined(_KERNEL) */
+
+/*
+ * CPUID feature tests for user-space. Linux kernel provides an interface for
+ * CPU feature testing.
+ */
+#if !defined(_KERNEL)
+
+/*
+ * x86 registers used implicitly by CPUID
+ */
+typedef enum cpuid_regs {
+       EAX = 0,
+       EBX,
+       ECX,
+       EDX,
+       CPUID_REG_CNT = 4
+} cpuid_regs_t;
+
+/*
+ * List of instruction sets identified by CPUID
+ */
+typedef enum cpuid_inst_sets {
+       SSE = 0,
+       SSE2,
+       SSE3,
+       SSSE3,
+       SSE4_1,
+       SSE4_2,
+       OSXSAVE,
+       AVX,
+       AVX2,
+       BMI1,
+       BMI2,
+       AVX512F,
+       AVX512CD,
+       AVX512DQ,
+       AVX512BW,
+       AVX512IFMA,
+       AVX512VBMI,
+       AVX512PF,
+       AVX512ER,
+       AVX512VL
+} cpuid_inst_sets_t;
+
+/*
+ * Instruction set descriptor.
+ */
+typedef struct cpuid_feature_desc {
+       uint32_t leaf;          /* CPUID leaf */
+       uint32_t subleaf;       /* CPUID sub-leaf */
+       uint32_t flag;          /* bit mask of the feature */
+       cpuid_regs_t reg;       /* which CPUID return register to test */
+} cpuid_feature_desc_t;
+
+#define        _AVX512F_BIT            (1U << 16)
+#define        _AVX512CD_BIT           (_AVX512F_BIT | (1U << 28))
+#define        _AVX512DQ_BIT           (_AVX512F_BIT | (1U << 17))
+#define        _AVX512BW_BIT           (_AVX512F_BIT | (1U << 30))
+#define        _AVX512IFMA_BIT         (_AVX512F_BIT | (1U << 21))
+#define        _AVX512VBMI_BIT         (1U << 1) /* AVX512F_BIT is on another leaf  */
+#define        _AVX512PF_BIT           (_AVX512F_BIT | (1U << 26))
+#define        _AVX512ER_BIT           (_AVX512F_BIT | (1U << 27))
+#define        _AVX512VL_BIT           (1U << 31) /* if used also check other levels */
+
+/*
+ * Descriptions of supported instruction sets
+ */
+static const cpuid_feature_desc_t cpuid_features[] = {
+       [SSE]           = {1U, 0U,      1U << 25,       EDX     },
+       [SSE2]          = {1U, 0U,      1U << 26,       EDX     },
+       [SSE3]          = {1U, 0U,      1U << 0,        ECX     },
+       [SSSE3]         = {1U, 0U,      1U << 9,        ECX     },
+       [SSE4_1]        = {1U, 0U,      1U << 19,       ECX     },
+       [SSE4_2]        = {1U, 0U,      1U << 20,       ECX     },
+       [OSXSAVE]       = {1U, 0U,      1U << 27,       ECX     },
+       [AVX]           = {1U, 0U,      1U << 28,       ECX     },
+       [AVX2]          = {7U, 0U,      1U << 5,        EBX     },
+       [BMI1]          = {7U, 0U,      1U << 3,        EBX     },
+       [BMI2]          = {7U, 0U,      1U << 8,        EBX     },
+       [AVX512F]       = {7U, 0U, _AVX512F_BIT,        EBX     },
+       [AVX512CD]      = {7U, 0U, _AVX512CD_BIT,       EBX     },
+       [AVX512DQ]      = {7U, 0U, _AVX512DQ_BIT,       EBX     },
+       [AVX512BW]      = {7U, 0U, _AVX512BW_BIT,       EBX     },
+       [AVX512IFMA]    = {7U, 0U, _AVX512IFMA_BIT,     EBX     },
+       [AVX512VBMI]    = {7U, 0U, _AVX512VBMI_BIT,     ECX     },
+       [AVX512PF]      = {7U, 0U, _AVX512PF_BIT,       EBX     },
+       [AVX512ER]      = {7U, 0U, _AVX512ER_BIT,       EBX     },
+       [AVX512VL]      = {7U, 0U, _AVX512ER_BIT,       EBX     }
+};
+
+/*
+ * Check if OS supports AVX and AVX2 by checking XCR0
+ * Only call this function if CPUID indicates that AVX feature is
+ * supported by the CPU, otherwise it might be an illegal instruction.
+ */
+static inline uint64_t
+xgetbv(uint32_t index)
+{
+       uint32_t eax, edx;
+       /* xgetbv - instruction byte code */
+       __asm__ __volatile__(".byte 0x0f; .byte 0x01; .byte 0xd0"
+               : "=a" (eax), "=d" (edx)
+               : "c" (index));
+
+       return ((((uint64_t)edx)<<32) | (uint64_t)eax);
+}
+
+/*
+ * Check if CPU supports a feature
+ */
+static inline boolean_t
+__cpuid_check_feature(const cpuid_feature_desc_t *desc)
+{
+       uint32_t r[CPUID_REG_CNT];
+
+       if (__get_cpuid_max(0, NULL) >= desc->leaf) {
+               /*
+                * __cpuid_count is needed to properly check
+                * for AVX2. It is a macro, so return parameters
+                * are passed by value.
+                */
+               __cpuid_count(desc->leaf, desc->subleaf,
+                       r[EAX], r[EBX], r[ECX], r[EDX]);
+               return ((r[desc->reg] & desc->flag) == desc->flag);
+       }
+       return (B_FALSE);
+}
+
+#define        CPUID_FEATURE_CHECK(name, id)                           \
+static inline boolean_t                                                \
+__cpuid_has_ ## name(void)                                     \
+{                                                              \
+       return (__cpuid_check_feature(&cpuid_features[id]));    \
+}
+
+/*
+ * Define functions for user-space CPUID features testing
+ */
+CPUID_FEATURE_CHECK(sse, SSE);
+CPUID_FEATURE_CHECK(sse2, SSE2);
+CPUID_FEATURE_CHECK(sse3, SSE3);
+CPUID_FEATURE_CHECK(ssse3, SSSE3);
+CPUID_FEATURE_CHECK(sse4_1, SSE4_1);
+CPUID_FEATURE_CHECK(sse4_2, SSE4_2);
+CPUID_FEATURE_CHECK(avx, AVX);
+CPUID_FEATURE_CHECK(avx2, AVX2);
+CPUID_FEATURE_CHECK(osxsave, OSXSAVE);
+CPUID_FEATURE_CHECK(bmi1, BMI1);
+CPUID_FEATURE_CHECK(bmi2, BMI2);
+CPUID_FEATURE_CHECK(avx512f, AVX512F);
+CPUID_FEATURE_CHECK(avx512cd, AVX512CD);
+CPUID_FEATURE_CHECK(avx512dq, AVX512DQ);
+CPUID_FEATURE_CHECK(avx512bw, AVX512BW);
+CPUID_FEATURE_CHECK(avx512ifma, AVX512IFMA);
+CPUID_FEATURE_CHECK(avx512vbmi, AVX512VBMI);
+CPUID_FEATURE_CHECK(avx512pf, AVX512PF);
+CPUID_FEATURE_CHECK(avx512er, AVX512ER);
+CPUID_FEATURE_CHECK(avx512vl, AVX512VL);
+
+#endif /* !defined(_KERNEL) */
+
+
+/*
+ * Detect register set support
+ */
+static inline boolean_t
+__simd_state_enabled(const uint64_t state)
+{
+       boolean_t has_osxsave;
+       uint64_t xcr0;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_OSXSAVE)
+       has_osxsave = !!boot_cpu_has(X86_FEATURE_OSXSAVE);
+#elif defined(_KERNEL) && !defined(X86_FEATURE_OSXSAVE)
+       has_osxsave = B_FALSE;
+#else
+       has_osxsave = __cpuid_has_osxsave();
+#endif
+
+       if (!has_osxsave)
+               return (B_FALSE);
+
+       xcr0 = xgetbv(0);
+       return ((xcr0 & state) == state);
+}
+
+#define        _XSTATE_SSE_AVX         (0x2 | 0x4)
+#define        _XSTATE_AVX512          (0xE0 | _XSTATE_SSE_AVX)
+
+#define        __ymm_enabled() __simd_state_enabled(_XSTATE_SSE_AVX)
+#define        __zmm_enabled() __simd_state_enabled(_XSTATE_AVX512)
+
+
+/*
+ * Check if SSE instruction set is available
+ */
+static inline boolean_t
+zfs_sse_available(void)
+{
+#if defined(_KERNEL)
+       return (!!boot_cpu_has(X86_FEATURE_XMM));
+#else
+       return (__cpuid_has_sse());
+#endif
+}
+
+/*
+ * Check if SSE2 instruction set is available
+ */
+static inline boolean_t
+zfs_sse2_available(void)
+{
+#if defined(_KERNEL)
+       return (!!boot_cpu_has(X86_FEATURE_XMM2));
+#else
+       return (__cpuid_has_sse2());
+#endif
+}
+
+/*
+ * Check if SSE3 instruction set is available
+ */
+static inline boolean_t
+zfs_sse3_available(void)
+{
+#if defined(_KERNEL)
+       return (!!boot_cpu_has(X86_FEATURE_XMM3));
+#else
+       return (__cpuid_has_sse3());
+#endif
+}
+
+/*
+ * Check if SSSE3 instruction set is available
+ */
+static inline boolean_t
+zfs_ssse3_available(void)
+{
+#if defined(_KERNEL)
+       return (!!boot_cpu_has(X86_FEATURE_SSSE3));
+#else
+       return (__cpuid_has_ssse3());
+#endif
+}
+
+/*
+ * Check if SSE4.1 instruction set is available
+ */
+static inline boolean_t
+zfs_sse4_1_available(void)
+{
+#if defined(_KERNEL)
+       return (!!boot_cpu_has(X86_FEATURE_XMM4_1));
+#else
+       return (__cpuid_has_sse4_1());
+#endif
+}
+
+/*
+ * Check if SSE4.2 instruction set is available
+ */
+static inline boolean_t
+zfs_sse4_2_available(void)
+{
+#if defined(_KERNEL)
+       return (!!boot_cpu_has(X86_FEATURE_XMM4_2));
+#else
+       return (__cpuid_has_sse4_2());
+#endif
+}
+
+/*
+ * Check if AVX instruction set is available
+ */
+static inline boolean_t
+zfs_avx_available(void)
+{
+       boolean_t has_avx;
+#if defined(_KERNEL)
+       has_avx = !!boot_cpu_has(X86_FEATURE_AVX);
+#else
+       has_avx = __cpuid_has_avx();
+#endif
+
+       return (has_avx && __ymm_enabled());
+}
+
+/*
+ * Check if AVX2 instruction set is available
+ */
+static inline boolean_t
+zfs_avx2_available(void)
+{
+       boolean_t has_avx2;
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX2)
+       has_avx2 = !!boot_cpu_has(X86_FEATURE_AVX2);
+#elif defined(_KERNEL) && !defined(X86_FEATURE_AVX2)
+       has_avx2 = B_FALSE;
+#else
+       has_avx2 = __cpuid_has_avx2();
+#endif
+
+       return (has_avx2 && __ymm_enabled());
+}
+
+/*
+ * Check if BMI1 instruction set is available
+ */
+static inline boolean_t
+zfs_bmi1_available(void)
+{
+#if defined(_KERNEL) && defined(X86_FEATURE_BMI1)
+       return (!!boot_cpu_has(X86_FEATURE_BMI1));
+#elif defined(_KERNEL) && !defined(X86_FEATURE_BMI1)
+       return (B_FALSE);
+#else
+       return (__cpuid_has_bmi1());
+#endif
+}
+
+/*
+ * Check if BMI2 instruction set is available
+ */
+static inline boolean_t
+zfs_bmi2_available(void)
+{
+#if defined(_KERNEL) && defined(X86_FEATURE_BMI2)
+       return (!!boot_cpu_has(X86_FEATURE_BMI2));
+#elif defined(_KERNEL) && !defined(X86_FEATURE_BMI2)
+       return (B_FALSE);
+#else
+       return (__cpuid_has_bmi2());
+#endif
+}
+
+
+/*
+ * AVX-512 family of instruction sets:
+ *
+ * AVX512F     Foundation
+ * AVX512CD    Conflict Detection Instructions
+ * AVX512ER    Exponential and Reciprocal Instructions
+ * AVX512PF    Prefetch Instructions
+ *
+ * AVX512BW    Byte and Word Instructions
+ * AVX512DQ    Double-word and Quadword Instructions
+ * AVX512VL    Vector Length Extensions
+ *
+ * AVX512IFMA  Integer Fused Multiply Add (Not supported by kernel 4.4)
+ * AVX512VBMI  Vector Byte Manipulation Instructions
+ */
+
+
+/* Check if AVX512F instruction set is available */
+static inline boolean_t
+zfs_avx512f_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512F)
+       has_avx512 = !!boot_cpu_has(X86_FEATURE_AVX512F);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512f();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+/* Check if AVX512CD instruction set is available */
+static inline boolean_t
+zfs_avx512cd_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512CD)
+       has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+           boot_cpu_has(X86_FEATURE_AVX512CD);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512cd();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+/* Check if AVX512ER instruction set is available */
+static inline boolean_t
+zfs_avx512er_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512ER)
+       has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+           boot_cpu_has(X86_FEATURE_AVX512ER);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512er();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+/* Check if AVX512PF instruction set is available */
+static inline boolean_t
+zfs_avx512pf_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512PF)
+       has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+           boot_cpu_has(X86_FEATURE_AVX512PF);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512pf();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+/* Check if AVX512BW instruction set is available */
+static inline boolean_t
+zfs_avx512bw_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512BW)
+       has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+           boot_cpu_has(X86_FEATURE_AVX512BW);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512bw();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+/* Check if AVX512DQ instruction set is available */
+static inline boolean_t
+zfs_avx512dq_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512DQ)
+       has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+           boot_cpu_has(X86_FEATURE_AVX512DQ);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512dq();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+/* Check if AVX512VL instruction set is available */
+static inline boolean_t
+zfs_avx512vl_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512VL)
+       has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+           boot_cpu_has(X86_FEATURE_AVX512VL);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512vl();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+/* Check if AVX512IFMA instruction set is available */
+static inline boolean_t
+zfs_avx512ifma_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512IFMA)
+       has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+           boot_cpu_has(X86_FEATURE_AVX512IFMA);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512ifma();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+/* Check if AVX512VBMI instruction set is available */
+static inline boolean_t
+zfs_avx512vbmi_available(void)
+{
+       boolean_t has_avx512 = B_FALSE;
+
+#if defined(_KERNEL) && defined(X86_FEATURE_AVX512VBMI)
+       has_avx512 = boot_cpu_has(X86_FEATURE_AVX512F) &&
+           boot_cpu_has(X86_FEATURE_AVX512VBMI);
+#elif !defined(_KERNEL)
+       has_avx512 = __cpuid_has_avx512f() &&
+           __cpuid_has_avx512vbmi();
+#endif
+
+       return (has_avx512 && __zmm_enabled());
+}
+
+#endif /* defined(__x86) */
+
+#endif /* _SIMD_X86_H */
index b4881a6c67fdf768a2ba807ec771016c9107c5b7..989c237a34e5c815cb59481e1b87ab1b4ba8ca1e 100644 (file)
@@ -28,6 +28,7 @@
 #define        _ZFS_VFS_H
 
 #include <sys/taskq.h>
+#include <sys/cred.h>
 #include <linux/backing-dev.h>
 
 /*
@@ -351,6 +352,87 @@ static inline struct inode *file_inode(const struct file *f)
 }
 #endif /* HAVE_FILE_INODE */
 
+/*
+ * 4.1 API change
+ * struct access file->f_path.dentry was replaced by accessor function
+ * file_dentry(f)
+ */
+#ifndef HAVE_FILE_DENTRY
+static inline struct dentry *file_dentry(const struct file *f)
+{
+       return (f->f_path.dentry);
+}
+#endif /* HAVE_FILE_DENTRY */
+
+#ifdef HAVE_KUID_HELPERS
+static inline uid_t zfs_uid_read_impl(struct inode *ip)
+{
+#ifdef HAVE_SUPER_USER_NS
+       return (from_kuid(ip->i_sb->s_user_ns, ip->i_uid));
+#else
+       return (from_kuid(kcred->user_ns, ip->i_uid));
+#endif
+}
+
+static inline uid_t zfs_uid_read(struct inode *ip)
+{
+       return (zfs_uid_read_impl(ip));
+}
+
+static inline gid_t zfs_gid_read_impl(struct inode *ip)
+{
+#ifdef HAVE_SUPER_USER_NS
+       return (from_kgid(ip->i_sb->s_user_ns, ip->i_gid));
+#else
+       return (from_kgid(kcred->user_ns, ip->i_gid));
+#endif
+}
+
+static inline gid_t zfs_gid_read(struct inode *ip)
+{
+       return (zfs_gid_read_impl(ip));
+}
+
+static inline void zfs_uid_write(struct inode *ip, uid_t uid)
+{
+#ifdef HAVE_SUPER_USER_NS
+       ip->i_uid = make_kuid(ip->i_sb->s_user_ns, uid);
+#else
+       ip->i_uid = make_kuid(kcred->user_ns, uid);
+#endif
+}
+
+static inline void zfs_gid_write(struct inode *ip, gid_t gid)
+{
+#ifdef HAVE_SUPER_USER_NS
+       ip->i_gid = make_kgid(ip->i_sb->s_user_ns, gid);
+#else
+       ip->i_gid = make_kgid(kcred->user_ns, gid);
+#endif
+}
+
+#else
+static inline uid_t zfs_uid_read(struct inode *ip)
+{
+       return (ip->i_uid);
+}
+
+static inline gid_t zfs_gid_read(struct inode *ip)
+{
+       return (ip->i_gid);
+}
+
+static inline void zfs_uid_write(struct inode *ip, uid_t uid)
+{
+       ip->i_uid = uid;
+}
+
+static inline void zfs_gid_write(struct inode *ip, gid_t gid)
+{
+       ip->i_gid = gid;
+}
+#endif
+
 /*
  * 2.6.38 API change
  */
@@ -362,4 +444,15 @@ static inline struct inode *file_inode(const struct file *f)
 #define        zpl_follow_up(path)                     follow_up(path)
 #endif
 
+/*
+ * 4.9 API change
+ */
+#ifndef HAVE_SETATTR_PREPARE
+static inline int
+setattr_prepare(struct dentry *dentry, struct iattr *ia)
+{
+       return (inode_change_ok(dentry->d_inode, ia));
+}
+#endif
+
 #endif /* _ZFS_VFS_H */
index 77ecfb2dcf8e39eb4aafa0d38bf4cc9d9a121a7a..37df6e1d2ef09a7d4d7b9298738b8d7fa49c6c9f 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = fm fs
+SUBDIRS = fm fs crypto sysevent
 
 COMMON_H = \
        $(top_srcdir)/include/sys/arc.h \
@@ -9,6 +9,7 @@ COMMON_H = \
        $(top_srcdir)/include/sys/bplist.h \
        $(top_srcdir)/include/sys/bpobj.h \
        $(top_srcdir)/include/sys/bptree.h \
+       $(top_srcdir)/include/sys/bqueue.h \
        $(top_srcdir)/include/sys/dbuf.h \
        $(top_srcdir)/include/sys/ddt.h \
        $(top_srcdir)/include/sys/dmu.h \
@@ -30,6 +31,7 @@ COMMON_H = \
        $(top_srcdir)/include/sys/dsl_scan.h \
        $(top_srcdir)/include/sys/dsl_synctask.h \
        $(top_srcdir)/include/sys/dsl_userhold.h \
+       $(top_srcdir)/include/sys/edonr.h \
        $(top_srcdir)/include/sys/efi_partition.h \
        $(top_srcdir)/include/sys/metaslab.h \
        $(top_srcdir)/include/sys/metaslab_impl.h \
@@ -37,20 +39,27 @@ COMMON_H = \
        $(top_srcdir)/include/sys/multilist.h \
        $(top_srcdir)/include/sys/nvpair.h \
        $(top_srcdir)/include/sys/nvpair_impl.h \
+       $(top_srcdir)/include/sys/pathname.h \
+       $(top_srcdir)/include/sys/policy.h \
        $(top_srcdir)/include/sys/range_tree.h \
        $(top_srcdir)/include/sys/refcount.h \
        $(top_srcdir)/include/sys/rrwlock.h \
        $(top_srcdir)/include/sys/sa.h \
        $(top_srcdir)/include/sys/sa_impl.h \
        $(top_srcdir)/include/sys/sdt.h \
+       $(top_srcdir)/include/sys/sha2.h \
+       $(top_srcdir)/include/sys/skein.h \
        $(top_srcdir)/include/sys/spa_boot.h \
        $(top_srcdir)/include/sys/space_map.h \
        $(top_srcdir)/include/sys/space_reftree.h \
        $(top_srcdir)/include/sys/spa.h \
        $(top_srcdir)/include/sys/spa_impl.h \
+       $(top_srcdir)/include/sys/spa_checksum.h \
+       $(top_srcdir)/include/sys/sysevent.h \
        $(top_srcdir)/include/sys/trace.h \
        $(top_srcdir)/include/sys/trace_acl.h \
        $(top_srcdir)/include/sys/trace_arc.h \
+       $(top_srcdir)/include/sys/trace_common.h \
        $(top_srcdir)/include/sys/trace_dbgmsg.h \
        $(top_srcdir)/include/sys/trace_dbuf.h \
        $(top_srcdir)/include/sys/trace_dmu.h \
@@ -58,6 +67,7 @@ COMMON_H = \
        $(top_srcdir)/include/sys/trace_multilist.h \
        $(top_srcdir)/include/sys/trace_txg.h \
        $(top_srcdir)/include/sys/trace_zil.h \
+       $(top_srcdir)/include/sys/trace_zio.h \
        $(top_srcdir)/include/sys/trace_zrlock.h \
        $(top_srcdir)/include/sys/txg.h \
        $(top_srcdir)/include/sys/txg_impl.h \
@@ -72,6 +82,8 @@ COMMON_H = \
        $(top_srcdir)/include/sys/vdev_file.h \
        $(top_srcdir)/include/sys/vdev.h \
        $(top_srcdir)/include/sys/vdev_impl.h \
+       $(top_srcdir)/include/sys/vdev_raidz.h \
+       $(top_srcdir)/include/sys/vdev_raidz_impl.h \
        $(top_srcdir)/include/sys/xvattr.h \
        $(top_srcdir)/include/sys/zap.h \
        $(top_srcdir)/include/sys/zap_impl.h \
@@ -84,6 +96,7 @@ COMMON_H = \
        $(top_srcdir)/include/sys/zfs_delay.h \
        $(top_srcdir)/include/sys/zfs_dir.h \
        $(top_srcdir)/include/sys/zfs_fuid.h \
+       $(top_srcdir)/include/sys/zfs_ratelimit.h \
        $(top_srcdir)/include/sys/zfs_rlock.h \
        $(top_srcdir)/include/sys/zfs_sa.h \
        $(top_srcdir)/include/sys/zfs_stat.h \
@@ -96,6 +109,7 @@ COMMON_H = \
        $(top_srcdir)/include/sys/zio_compress.h \
        $(top_srcdir)/include/sys/zio.h \
        $(top_srcdir)/include/sys/zio_impl.h \
+       $(top_srcdir)/include/sys/zio_priority.h \
        $(top_srcdir)/include/sys/zrlock.h
 
 KERNEL_H = \
diff --git a/zfs/include/sys/Makefile.in b/zfs/include/sys/Makefile.in
deleted file mode 100644 (file)
index 2fc6db4..0000000
+++ /dev/null
@@ -1,1165 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = include/sys
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__kernel_HEADERS_DIST) \
-       $(am__libzfs_HEADERS_DIST) $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-       ctags-recursive dvi-recursive html-recursive info-recursive \
-       install-data-recursive install-dvi-recursive \
-       install-exec-recursive install-html-recursive \
-       install-info-recursive install-pdf-recursive \
-       install-ps-recursive install-recursive installcheck-recursive \
-       installdirs-recursive pdf-recursive ps-recursive \
-       tags-recursive uninstall-recursive
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__kernel_HEADERS_DIST = $(top_srcdir)/include/sys/arc.h \
-       $(top_srcdir)/include/sys/arc_impl.h \
-       $(top_srcdir)/include/sys/avl.h \
-       $(top_srcdir)/include/sys/avl_impl.h \
-       $(top_srcdir)/include/sys/blkptr.h \
-       $(top_srcdir)/include/sys/bplist.h \
-       $(top_srcdir)/include/sys/bpobj.h \
-       $(top_srcdir)/include/sys/bptree.h \
-       $(top_srcdir)/include/sys/dbuf.h \
-       $(top_srcdir)/include/sys/ddt.h \
-       $(top_srcdir)/include/sys/dmu.h \
-       $(top_srcdir)/include/sys/dmu_impl.h \
-       $(top_srcdir)/include/sys/dmu_objset.h \
-       $(top_srcdir)/include/sys/dmu_send.h \
-       $(top_srcdir)/include/sys/dmu_traverse.h \
-       $(top_srcdir)/include/sys/dmu_tx.h \
-       $(top_srcdir)/include/sys/dmu_zfetch.h \
-       $(top_srcdir)/include/sys/dnode.h \
-       $(top_srcdir)/include/sys/dsl_bookmark.h \
-       $(top_srcdir)/include/sys/dsl_dataset.h \
-       $(top_srcdir)/include/sys/dsl_deadlist.h \
-       $(top_srcdir)/include/sys/dsl_deleg.h \
-       $(top_srcdir)/include/sys/dsl_destroy.h \
-       $(top_srcdir)/include/sys/dsl_dir.h \
-       $(top_srcdir)/include/sys/dsl_pool.h \
-       $(top_srcdir)/include/sys/dsl_prop.h \
-       $(top_srcdir)/include/sys/dsl_scan.h \
-       $(top_srcdir)/include/sys/dsl_synctask.h \
-       $(top_srcdir)/include/sys/dsl_userhold.h \
-       $(top_srcdir)/include/sys/efi_partition.h \
-       $(top_srcdir)/include/sys/metaslab.h \
-       $(top_srcdir)/include/sys/metaslab_impl.h \
-       $(top_srcdir)/include/sys/mntent.h \
-       $(top_srcdir)/include/sys/multilist.h \
-       $(top_srcdir)/include/sys/nvpair.h \
-       $(top_srcdir)/include/sys/nvpair_impl.h \
-       $(top_srcdir)/include/sys/range_tree.h \
-       $(top_srcdir)/include/sys/refcount.h \
-       $(top_srcdir)/include/sys/rrwlock.h \
-       $(top_srcdir)/include/sys/sa.h \
-       $(top_srcdir)/include/sys/sa_impl.h \
-       $(top_srcdir)/include/sys/sdt.h \
-       $(top_srcdir)/include/sys/spa_boot.h \
-       $(top_srcdir)/include/sys/space_map.h \
-       $(top_srcdir)/include/sys/space_reftree.h \
-       $(top_srcdir)/include/sys/spa.h \
-       $(top_srcdir)/include/sys/spa_impl.h \
-       $(top_srcdir)/include/sys/trace.h \
-       $(top_srcdir)/include/sys/trace_acl.h \
-       $(top_srcdir)/include/sys/trace_arc.h \
-       $(top_srcdir)/include/sys/trace_dbgmsg.h \
-       $(top_srcdir)/include/sys/trace_dbuf.h \
-       $(top_srcdir)/include/sys/trace_dmu.h \
-       $(top_srcdir)/include/sys/trace_dnode.h \
-       $(top_srcdir)/include/sys/trace_multilist.h \
-       $(top_srcdir)/include/sys/trace_txg.h \
-       $(top_srcdir)/include/sys/trace_zil.h \
-       $(top_srcdir)/include/sys/trace_zrlock.h \
-       $(top_srcdir)/include/sys/txg.h \
-       $(top_srcdir)/include/sys/txg_impl.h \
-       $(top_srcdir)/include/sys/u8_textprep_data.h \
-       $(top_srcdir)/include/sys/u8_textprep.h \
-       $(top_srcdir)/include/sys/uberblock.h \
-       $(top_srcdir)/include/sys/uberblock_impl.h \
-       $(top_srcdir)/include/sys/uio_impl.h \
-       $(top_srcdir)/include/sys/unique.h \
-       $(top_srcdir)/include/sys/uuid.h \
-       $(top_srcdir)/include/sys/vdev_disk.h \
-       $(top_srcdir)/include/sys/vdev_file.h \
-       $(top_srcdir)/include/sys/vdev.h \
-       $(top_srcdir)/include/sys/vdev_impl.h \
-       $(top_srcdir)/include/sys/xvattr.h \
-       $(top_srcdir)/include/sys/zap.h \
-       $(top_srcdir)/include/sys/zap_impl.h \
-       $(top_srcdir)/include/sys/zap_leaf.h \
-       $(top_srcdir)/include/sys/zfeature.h \
-       $(top_srcdir)/include/sys/zfs_acl.h \
-       $(top_srcdir)/include/sys/zfs_context.h \
-       $(top_srcdir)/include/sys/zfs_ctldir.h \
-       $(top_srcdir)/include/sys/zfs_debug.h \
-       $(top_srcdir)/include/sys/zfs_delay.h \
-       $(top_srcdir)/include/sys/zfs_dir.h \
-       $(top_srcdir)/include/sys/zfs_fuid.h \
-       $(top_srcdir)/include/sys/zfs_rlock.h \
-       $(top_srcdir)/include/sys/zfs_sa.h \
-       $(top_srcdir)/include/sys/zfs_stat.h \
-       $(top_srcdir)/include/sys/zfs_vfsops.h \
-       $(top_srcdir)/include/sys/zfs_vnops.h \
-       $(top_srcdir)/include/sys/zfs_znode.h \
-       $(top_srcdir)/include/sys/zil.h \
-       $(top_srcdir)/include/sys/zil_impl.h \
-       $(top_srcdir)/include/sys/zio_checksum.h \
-       $(top_srcdir)/include/sys/zio_compress.h \
-       $(top_srcdir)/include/sys/zio.h \
-       $(top_srcdir)/include/sys/zio_impl.h \
-       $(top_srcdir)/include/sys/zrlock.h \
-       $(top_srcdir)/include/sys/zfs_ioctl.h \
-       $(top_srcdir)/include/sys/zfs_onexit.h \
-       ${top_srcdir}/include/sys/zpl.h \
-       $(top_srcdir)/include/sys/zvol.h
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"
-am__libzfs_HEADERS_DIST = $(top_srcdir)/include/sys/arc.h \
-       $(top_srcdir)/include/sys/arc_impl.h \
-       $(top_srcdir)/include/sys/avl.h \
-       $(top_srcdir)/include/sys/avl_impl.h \
-       $(top_srcdir)/include/sys/blkptr.h \
-       $(top_srcdir)/include/sys/bplist.h \
-       $(top_srcdir)/include/sys/bpobj.h \
-       $(top_srcdir)/include/sys/bptree.h \
-       $(top_srcdir)/include/sys/dbuf.h \
-       $(top_srcdir)/include/sys/ddt.h \
-       $(top_srcdir)/include/sys/dmu.h \
-       $(top_srcdir)/include/sys/dmu_impl.h \
-       $(top_srcdir)/include/sys/dmu_objset.h \
-       $(top_srcdir)/include/sys/dmu_send.h \
-       $(top_srcdir)/include/sys/dmu_traverse.h \
-       $(top_srcdir)/include/sys/dmu_tx.h \
-       $(top_srcdir)/include/sys/dmu_zfetch.h \
-       $(top_srcdir)/include/sys/dnode.h \
-       $(top_srcdir)/include/sys/dsl_bookmark.h \
-       $(top_srcdir)/include/sys/dsl_dataset.h \
-       $(top_srcdir)/include/sys/dsl_deadlist.h \
-       $(top_srcdir)/include/sys/dsl_deleg.h \
-       $(top_srcdir)/include/sys/dsl_destroy.h \
-       $(top_srcdir)/include/sys/dsl_dir.h \
-       $(top_srcdir)/include/sys/dsl_pool.h \
-       $(top_srcdir)/include/sys/dsl_prop.h \
-       $(top_srcdir)/include/sys/dsl_scan.h \
-       $(top_srcdir)/include/sys/dsl_synctask.h \
-       $(top_srcdir)/include/sys/dsl_userhold.h \
-       $(top_srcdir)/include/sys/efi_partition.h \
-       $(top_srcdir)/include/sys/metaslab.h \
-       $(top_srcdir)/include/sys/metaslab_impl.h \
-       $(top_srcdir)/include/sys/mntent.h \
-       $(top_srcdir)/include/sys/multilist.h \
-       $(top_srcdir)/include/sys/nvpair.h \
-       $(top_srcdir)/include/sys/nvpair_impl.h \
-       $(top_srcdir)/include/sys/range_tree.h \
-       $(top_srcdir)/include/sys/refcount.h \
-       $(top_srcdir)/include/sys/rrwlock.h \
-       $(top_srcdir)/include/sys/sa.h \
-       $(top_srcdir)/include/sys/sa_impl.h \
-       $(top_srcdir)/include/sys/sdt.h \
-       $(top_srcdir)/include/sys/spa_boot.h \
-       $(top_srcdir)/include/sys/space_map.h \
-       $(top_srcdir)/include/sys/space_reftree.h \
-       $(top_srcdir)/include/sys/spa.h \
-       $(top_srcdir)/include/sys/spa_impl.h \
-       $(top_srcdir)/include/sys/trace.h \
-       $(top_srcdir)/include/sys/trace_acl.h \
-       $(top_srcdir)/include/sys/trace_arc.h \
-       $(top_srcdir)/include/sys/trace_dbgmsg.h \
-       $(top_srcdir)/include/sys/trace_dbuf.h \
-       $(top_srcdir)/include/sys/trace_dmu.h \
-       $(top_srcdir)/include/sys/trace_dnode.h \
-       $(top_srcdir)/include/sys/trace_multilist.h \
-       $(top_srcdir)/include/sys/trace_txg.h \
-       $(top_srcdir)/include/sys/trace_zil.h \
-       $(top_srcdir)/include/sys/trace_zrlock.h \
-       $(top_srcdir)/include/sys/txg.h \
-       $(top_srcdir)/include/sys/txg_impl.h \
-       $(top_srcdir)/include/sys/u8_textprep_data.h \
-       $(top_srcdir)/include/sys/u8_textprep.h \
-       $(top_srcdir)/include/sys/uberblock.h \
-       $(top_srcdir)/include/sys/uberblock_impl.h \
-       $(top_srcdir)/include/sys/uio_impl.h \
-       $(top_srcdir)/include/sys/unique.h \
-       $(top_srcdir)/include/sys/uuid.h \
-       $(top_srcdir)/include/sys/vdev_disk.h \
-       $(top_srcdir)/include/sys/vdev_file.h \
-       $(top_srcdir)/include/sys/vdev.h \
-       $(top_srcdir)/include/sys/vdev_impl.h \
-       $(top_srcdir)/include/sys/xvattr.h \
-       $(top_srcdir)/include/sys/zap.h \
-       $(top_srcdir)/include/sys/zap_impl.h \
-       $(top_srcdir)/include/sys/zap_leaf.h \
-       $(top_srcdir)/include/sys/zfeature.h \
-       $(top_srcdir)/include/sys/zfs_acl.h \
-       $(top_srcdir)/include/sys/zfs_context.h \
-       $(top_srcdir)/include/sys/zfs_ctldir.h \
-       $(top_srcdir)/include/sys/zfs_debug.h \
-       $(top_srcdir)/include/sys/zfs_delay.h \
-       $(top_srcdir)/include/sys/zfs_dir.h \
-       $(top_srcdir)/include/sys/zfs_fuid.h \
-       $(top_srcdir)/include/sys/zfs_rlock.h \
-       $(top_srcdir)/include/sys/zfs_sa.h \
-       $(top_srcdir)/include/sys/zfs_stat.h \
-       $(top_srcdir)/include/sys/zfs_vfsops.h \
-       $(top_srcdir)/include/sys/zfs_vnops.h \
-       $(top_srcdir)/include/sys/zfs_znode.h \
-       $(top_srcdir)/include/sys/zil.h \
-       $(top_srcdir)/include/sys/zil_impl.h \
-       $(top_srcdir)/include/sys/zio_checksum.h \
-       $(top_srcdir)/include/sys/zio_compress.h \
-       $(top_srcdir)/include/sys/zio.h \
-       $(top_srcdir)/include/sys/zio_impl.h \
-       $(top_srcdir)/include/sys/zrlock.h
-HEADERS = $(kernel_HEADERS) $(libzfs_HEADERS)
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-       distdir
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-SUBDIRS = fm fs
-COMMON_H = \
-       $(top_srcdir)/include/sys/arc.h \
-       $(top_srcdir)/include/sys/arc_impl.h \
-       $(top_srcdir)/include/sys/avl.h \
-       $(top_srcdir)/include/sys/avl_impl.h \
-       $(top_srcdir)/include/sys/blkptr.h \
-       $(top_srcdir)/include/sys/bplist.h \
-       $(top_srcdir)/include/sys/bpobj.h \
-       $(top_srcdir)/include/sys/bptree.h \
-       $(top_srcdir)/include/sys/dbuf.h \
-       $(top_srcdir)/include/sys/ddt.h \
-       $(top_srcdir)/include/sys/dmu.h \
-       $(top_srcdir)/include/sys/dmu_impl.h \
-       $(top_srcdir)/include/sys/dmu_objset.h \
-       $(top_srcdir)/include/sys/dmu_send.h \
-       $(top_srcdir)/include/sys/dmu_traverse.h \
-       $(top_srcdir)/include/sys/dmu_tx.h \
-       $(top_srcdir)/include/sys/dmu_zfetch.h \
-       $(top_srcdir)/include/sys/dnode.h \
-       $(top_srcdir)/include/sys/dsl_bookmark.h \
-       $(top_srcdir)/include/sys/dsl_dataset.h \
-       $(top_srcdir)/include/sys/dsl_deadlist.h \
-       $(top_srcdir)/include/sys/dsl_deleg.h \
-       $(top_srcdir)/include/sys/dsl_destroy.h \
-       $(top_srcdir)/include/sys/dsl_dir.h \
-       $(top_srcdir)/include/sys/dsl_pool.h \
-       $(top_srcdir)/include/sys/dsl_prop.h \
-       $(top_srcdir)/include/sys/dsl_scan.h \
-       $(top_srcdir)/include/sys/dsl_synctask.h \
-       $(top_srcdir)/include/sys/dsl_userhold.h \
-       $(top_srcdir)/include/sys/efi_partition.h \
-       $(top_srcdir)/include/sys/metaslab.h \
-       $(top_srcdir)/include/sys/metaslab_impl.h \
-       $(top_srcdir)/include/sys/mntent.h \
-       $(top_srcdir)/include/sys/multilist.h \
-       $(top_srcdir)/include/sys/nvpair.h \
-       $(top_srcdir)/include/sys/nvpair_impl.h \
-       $(top_srcdir)/include/sys/range_tree.h \
-       $(top_srcdir)/include/sys/refcount.h \
-       $(top_srcdir)/include/sys/rrwlock.h \
-       $(top_srcdir)/include/sys/sa.h \
-       $(top_srcdir)/include/sys/sa_impl.h \
-       $(top_srcdir)/include/sys/sdt.h \
-       $(top_srcdir)/include/sys/spa_boot.h \
-       $(top_srcdir)/include/sys/space_map.h \
-       $(top_srcdir)/include/sys/space_reftree.h \
-       $(top_srcdir)/include/sys/spa.h \
-       $(top_srcdir)/include/sys/spa_impl.h \
-       $(top_srcdir)/include/sys/trace.h \
-       $(top_srcdir)/include/sys/trace_acl.h \
-       $(top_srcdir)/include/sys/trace_arc.h \
-       $(top_srcdir)/include/sys/trace_dbgmsg.h \
-       $(top_srcdir)/include/sys/trace_dbuf.h \
-       $(top_srcdir)/include/sys/trace_dmu.h \
-       $(top_srcdir)/include/sys/trace_dnode.h \
-       $(top_srcdir)/include/sys/trace_multilist.h \
-       $(top_srcdir)/include/sys/trace_txg.h \
-       $(top_srcdir)/include/sys/trace_zil.h \
-       $(top_srcdir)/include/sys/trace_zrlock.h \
-       $(top_srcdir)/include/sys/txg.h \
-       $(top_srcdir)/include/sys/txg_impl.h \
-       $(top_srcdir)/include/sys/u8_textprep_data.h \
-       $(top_srcdir)/include/sys/u8_textprep.h \
-       $(top_srcdir)/include/sys/uberblock.h \
-       $(top_srcdir)/include/sys/uberblock_impl.h \
-       $(top_srcdir)/include/sys/uio_impl.h \
-       $(top_srcdir)/include/sys/unique.h \
-       $(top_srcdir)/include/sys/uuid.h \
-       $(top_srcdir)/include/sys/vdev_disk.h \
-       $(top_srcdir)/include/sys/vdev_file.h \
-       $(top_srcdir)/include/sys/vdev.h \
-       $(top_srcdir)/include/sys/vdev_impl.h \
-       $(top_srcdir)/include/sys/xvattr.h \
-       $(top_srcdir)/include/sys/zap.h \
-       $(top_srcdir)/include/sys/zap_impl.h \
-       $(top_srcdir)/include/sys/zap_leaf.h \
-       $(top_srcdir)/include/sys/zfeature.h \
-       $(top_srcdir)/include/sys/zfs_acl.h \
-       $(top_srcdir)/include/sys/zfs_context.h \
-       $(top_srcdir)/include/sys/zfs_ctldir.h \
-       $(top_srcdir)/include/sys/zfs_debug.h \
-       $(top_srcdir)/include/sys/zfs_delay.h \
-       $(top_srcdir)/include/sys/zfs_dir.h \
-       $(top_srcdir)/include/sys/zfs_fuid.h \
-       $(top_srcdir)/include/sys/zfs_rlock.h \
-       $(top_srcdir)/include/sys/zfs_sa.h \
-       $(top_srcdir)/include/sys/zfs_stat.h \
-       $(top_srcdir)/include/sys/zfs_vfsops.h \
-       $(top_srcdir)/include/sys/zfs_vnops.h \
-       $(top_srcdir)/include/sys/zfs_znode.h \
-       $(top_srcdir)/include/sys/zil.h \
-       $(top_srcdir)/include/sys/zil_impl.h \
-       $(top_srcdir)/include/sys/zio_checksum.h \
-       $(top_srcdir)/include/sys/zio_compress.h \
-       $(top_srcdir)/include/sys/zio.h \
-       $(top_srcdir)/include/sys/zio_impl.h \
-       $(top_srcdir)/include/sys/zrlock.h
-
-KERNEL_H = \
-       $(top_srcdir)/include/sys/zfs_ioctl.h \
-       $(top_srcdir)/include/sys/zfs_onexit.h \
-       ${top_srcdir}/include/sys/zpl.h \
-       $(top_srcdir)/include/sys/zvol.h
-
-USER_H = 
-EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
-@CONFIG_USER_TRUE@libzfsdir = $(includedir)/libzfs/sys
-@CONFIG_USER_TRUE@libzfs_HEADERS = $(COMMON_H) $(USER_H)
-@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys
-@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
-all: all-recursive
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/sys/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu include/sys/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-install-kernelHEADERS: $(kernel_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(kerneldir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(kerneldir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(kerneldir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(kerneldir)" || exit $$?; \
-       done
-
-uninstall-kernelHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(kerneldir)'; $(am__uninstall_files_from_dir)
-install-libzfsHEADERS: $(libzfs_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(libzfsdir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(libzfsdir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libzfsdir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(libzfsdir)" || exit $$?; \
-       done
-
-uninstall-libzfsHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(libzfsdir)'; $(am__uninstall_files_from_dir)
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-       @fail=; \
-       if $(am__make_keepgoing); then \
-         failcom='fail=yes'; \
-       else \
-         failcom='exit 1'; \
-       fi; \
-       dot_seen=no; \
-       target=`echo $@ | sed s/-recursive//`; \
-       case "$@" in \
-         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-         *) list='$(SUBDIRS)' ;; \
-       esac; \
-       for subdir in $$list; do \
-         echo "Making $$target in $$subdir"; \
-         if test "$$subdir" = "."; then \
-           dot_seen=yes; \
-           local_target="$$target-am"; \
-         else \
-           local_target="$$target"; \
-         fi; \
-         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-         || eval $$failcom; \
-       done; \
-       if test "$$dot_seen" = "no"; then \
-         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-       fi; test -z "$$fail"
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-         include_option=--etags-include; \
-         empty_fix=.; \
-       else \
-         include_option=--include; \
-         empty_fix=; \
-       fi; \
-       list='$(SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           test ! -f $$subdir/TAGS || \
-             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-         fi; \
-       done; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-ctags: ctags-recursive
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-recursive
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           $(am__make_dryrun) \
-             || test -d "$(distdir)/$$subdir" \
-             || $(MKDIR_P) "$(distdir)/$$subdir" \
-             || exit 1; \
-           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-           $(am__relativize); \
-           new_distdir=$$reldir; \
-           dir1=$$subdir; dir2="$(top_distdir)"; \
-           $(am__relativize); \
-           new_top_distdir=$$reldir; \
-           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-           ($(am__cd) $$subdir && \
-             $(MAKE) $(AM_MAKEFLAGS) \
-               top_distdir="$$new_top_distdir" \
-               distdir="$$new_distdir" \
-               am__remove_distdir=: \
-               am__skip_length_check=: \
-               am__skip_mode_fix=: \
-               distdir) \
-             || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-recursive
-all-am: Makefile $(HEADERS)
-installdirs: installdirs-recursive
-installdirs-am:
-       for dir in "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-recursive
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-recursive
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-recursive
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-tags
-
-dvi: dvi-recursive
-
-dvi-am:
-
-html: html-recursive
-
-html-am:
-
-info: info-recursive
-
-info-am:
-
-install-data-am: install-kernelHEADERS install-libzfsHEADERS
-
-install-dvi: install-dvi-recursive
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-recursive
-
-install-html-am:
-
-install-info: install-info-recursive
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-recursive
-
-install-pdf-am:
-
-install-ps: install-ps-recursive
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-recursive
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-recursive
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-recursive
-
-pdf-am:
-
-ps: ps-recursive
-
-ps-am:
-
-uninstall-am: uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.MAKE: $(am__recursive_targets) install-am install-strip
-
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
-       check-am clean clean-generic clean-libtool cscopelist-am ctags \
-       ctags-am distclean distclean-generic distclean-libtool \
-       distclean-tags distdir dvi dvi-am html html-am info info-am \
-       install install-am install-data install-data-am install-dvi \
-       install-dvi-am install-exec install-exec-am install-html \
-       install-html-am install-info install-info-am \
-       install-kernelHEADERS install-libzfsHEADERS install-man \
-       install-pdf install-pdf-am install-ps install-ps-am \
-       install-strip installcheck installcheck-am installdirs \
-       installdirs-am maintainer-clean maintainer-clean-generic \
-       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
-       ps ps-am tags tags-am uninstall uninstall-am \
-       uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index db7a64aa2e22e43d7adccd3900e7e53abe51a6a3..e1422d2e10518c6aebbc3d5b351238bbe546da4c 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
@@ -44,12 +44,24 @@ extern "C" {
  */
 #define        ARC_EVICT_ALL   -1ULL
 
+#define        HDR_SET_LSIZE(hdr, x) do { \
+       ASSERT(IS_P2ALIGNED(x, 1U << SPA_MINBLOCKSHIFT)); \
+       (hdr)->b_lsize = ((x) >> SPA_MINBLOCKSHIFT); \
+_NOTE(CONSTCOND) } while (0)
+
+#define        HDR_SET_PSIZE(hdr, x) do { \
+       ASSERT(IS_P2ALIGNED((x), 1U << SPA_MINBLOCKSHIFT)); \
+       (hdr)->b_psize = ((x) >> SPA_MINBLOCKSHIFT); \
+_NOTE(CONSTCOND) } while (0)
+
+#define        HDR_GET_LSIZE(hdr)      ((hdr)->b_lsize << SPA_MINBLOCKSHIFT)
+#define        HDR_GET_PSIZE(hdr)      ((hdr)->b_psize << SPA_MINBLOCKSHIFT)
+
 typedef struct arc_buf_hdr arc_buf_hdr_t;
 typedef struct arc_buf arc_buf_t;
 typedef struct arc_prune arc_prune_t;
 typedef void arc_done_func_t(zio_t *zio, arc_buf_t *buf, void *private);
 typedef void arc_prune_func_t(int64_t bytes, void *private);
-typedef int arc_evict_func_t(void *private);
 
 /* Shared module parameters */
 extern int zfs_arc_average_blocksize;
@@ -58,6 +70,8 @@ extern int zfs_arc_average_blocksize;
 arc_done_func_t arc_bcopy_func;
 arc_done_func_t arc_getbuf_func;
 
+extern int zfs_arc_num_sublists_per_state;
+
 /* generic arc_prune_func_t wrapper for callbacks */
 struct arc_prune {
        arc_prune_func_t        *p_pfunc;
@@ -77,46 +91,72 @@ typedef enum arc_flags
        /*
         * Public flags that can be passed into the ARC by external consumers.
         */
-       ARC_FLAG_NONE                   = 1 << 0,       /* No flags set */
-       ARC_FLAG_WAIT                   = 1 << 1,       /* perform sync I/O */
-       ARC_FLAG_NOWAIT                 = 1 << 2,       /* perform async I/O */
-       ARC_FLAG_PREFETCH               = 1 << 3,       /* I/O is a prefetch */
-       ARC_FLAG_CACHED                 = 1 << 4,       /* I/O was in cache */
-       ARC_FLAG_L2CACHE                = 1 << 5,       /* cache in L2ARC */
-       ARC_FLAG_L2COMPRESS             = 1 << 6,       /* compress in L2ARC */
+       ARC_FLAG_WAIT                   = 1 << 0,       /* perform sync I/O */
+       ARC_FLAG_NOWAIT                 = 1 << 1,       /* perform async I/O */
+       ARC_FLAG_PREFETCH               = 1 << 2,       /* I/O is a prefetch */
+       ARC_FLAG_CACHED                 = 1 << 3,       /* I/O was in cache */
+       ARC_FLAG_L2CACHE                = 1 << 4,       /* cache in L2ARC */
+       ARC_FLAG_PREDICTIVE_PREFETCH    = 1 << 5,       /* I/O from zfetch */
 
        /*
         * Private ARC flags.  These flags are private ARC only flags that
         * will show up in b_flags in the arc_hdr_buf_t. These flags should
         * only be set by ARC code.
         */
-       ARC_FLAG_IN_HASH_TABLE          = 1 << 7,       /* buffer is hashed */
-       ARC_FLAG_IO_IN_PROGRESS         = 1 << 8,       /* I/O in progress */
-       ARC_FLAG_IO_ERROR               = 1 << 9,       /* I/O failed for buf */
-       ARC_FLAG_FREED_IN_READ          = 1 << 10,      /* freed during read */
-       ARC_FLAG_BUF_AVAILABLE          = 1 << 11,      /* block not in use */
-       ARC_FLAG_INDIRECT               = 1 << 12,      /* indirect block */
-       ARC_FLAG_L2_WRITING             = 1 << 13,      /* write in progress */
-       ARC_FLAG_L2_EVICTED             = 1 << 14,      /* evicted during I/O */
-       ARC_FLAG_L2_WRITE_HEAD          = 1 << 15,      /* head of write list */
+       ARC_FLAG_IN_HASH_TABLE          = 1 << 6,       /* buffer is hashed */
+       ARC_FLAG_IO_IN_PROGRESS         = 1 << 7,       /* I/O in progress */
+       ARC_FLAG_IO_ERROR               = 1 << 8,       /* I/O failed for buf */
+       ARC_FLAG_INDIRECT               = 1 << 9,       /* indirect block */
+       /* Indicates that block was read with ASYNC priority. */
+       ARC_FLAG_PRIO_ASYNC_READ        = 1 << 10,
+       ARC_FLAG_L2_WRITING             = 1 << 11,      /* write in progress */
+       ARC_FLAG_L2_EVICTED             = 1 << 12,      /* evicted during I/O */
+       ARC_FLAG_L2_WRITE_HEAD          = 1 << 13,      /* head of write list */
        /* indicates that the buffer contains metadata (otherwise, data) */
-       ARC_FLAG_BUFC_METADATA          = 1 << 16,
+       ARC_FLAG_BUFC_METADATA          = 1 << 14,
 
        /* Flags specifying whether optional hdr struct fields are defined */
-       ARC_FLAG_HAS_L1HDR              = 1 << 17,
-       ARC_FLAG_HAS_L2HDR              = 1 << 18,
+       ARC_FLAG_HAS_L1HDR              = 1 << 15,
+       ARC_FLAG_HAS_L2HDR              = 1 << 16,
+
+       /*
+        * Indicates the arc_buf_hdr_t's b_pdata matches the on-disk data.
+        * This allows the l2arc to use the blkptr's checksum to verify
+        * the data without having to store the checksum in the hdr.
+        */
+       ARC_FLAG_COMPRESSED_ARC         = 1 << 17,
+       ARC_FLAG_SHARED_DATA            = 1 << 18,
+
+       /*
+        * The arc buffer's compression mode is stored in the top 7 bits of the
+        * flags field, so these dummy flags are included so that MDB can
+        * interpret the enum properly.
+        */
+       ARC_FLAG_COMPRESS_0             = 1 << 24,
+       ARC_FLAG_COMPRESS_1             = 1 << 25,
+       ARC_FLAG_COMPRESS_2             = 1 << 26,
+       ARC_FLAG_COMPRESS_3             = 1 << 27,
+       ARC_FLAG_COMPRESS_4             = 1 << 28,
+       ARC_FLAG_COMPRESS_5             = 1 << 29,
+       ARC_FLAG_COMPRESS_6             = 1 << 30
+
 } arc_flags_t;
 
+typedef enum arc_buf_flags {
+       ARC_BUF_FLAG_SHARED             = 1 << 0,
+       ARC_BUF_FLAG_COMPRESSED         = 1 << 1
+} arc_buf_flags_t;
+
 struct arc_buf {
        arc_buf_hdr_t           *b_hdr;
        arc_buf_t               *b_next;
        kmutex_t                b_evict_lock;
        void                    *b_data;
-       arc_evict_func_t        *b_efunc;
-       void                    *b_private;
+       arc_buf_flags_t         b_flags;
 };
 
 typedef enum arc_buf_contents {
+       ARC_BUFC_INVALID,                       /* invalid type */
        ARC_BUFC_DATA,                          /* buffer contains data */
        ARC_BUFC_METADATA,                      /* buffer contains metadata */
        ARC_BUFC_NUMTYPES
@@ -130,7 +170,9 @@ typedef enum arc_space_type {
        ARC_SPACE_META,
        ARC_SPACE_HDRS,
        ARC_SPACE_L2HDRS,
-       ARC_SPACE_OTHER,
+       ARC_SPACE_DBUF,
+       ARC_SPACE_DNODE,
+       ARC_SPACE_BONUS,
        ARC_SPACE_NUMTYPES
 } arc_space_type_t;
 
@@ -148,7 +190,7 @@ typedef struct arc_buf_info {
        arc_state_type_t        abi_state_type;
        arc_buf_contents_t      abi_state_contents;
        uint32_t                abi_flags;
-       uint32_t                abi_datacnt;
+       uint32_t                abi_bufcnt;
        uint64_t                abi_size;
        uint64_t                abi_spa;
        uint64_t                abi_access;
@@ -165,21 +207,27 @@ typedef struct arc_buf_info {
 
 void arc_space_consume(uint64_t space, arc_space_type_t type);
 void arc_space_return(uint64_t space, arc_space_type_t type);
-arc_buf_t *arc_buf_alloc(spa_t *spa, uint64_t size, void *tag,
-    arc_buf_contents_t type);
-arc_buf_t *arc_loan_buf(spa_t *spa, uint64_t size);
+boolean_t arc_is_metadata(arc_buf_t *buf);
+enum zio_compress arc_get_compression(arc_buf_t *buf);
+int arc_decompress(arc_buf_t *buf);
+arc_buf_t *arc_alloc_buf(spa_t *spa, void *tag, arc_buf_contents_t type,
+    int32_t size);
+arc_buf_t *arc_alloc_compressed_buf(spa_t *spa, void *tag,
+    uint64_t psize, uint64_t lsize, enum zio_compress compression_type);
+arc_buf_t *arc_loan_buf(spa_t *spa, boolean_t is_metadata, int size);
+arc_buf_t *arc_loan_compressed_buf(spa_t *spa, uint64_t psize, uint64_t lsize,
+    enum zio_compress compression_type);
 void arc_return_buf(arc_buf_t *buf, void *tag);
 void arc_loan_inuse_buf(arc_buf_t *buf, void *tag);
-void arc_buf_add_ref(arc_buf_t *buf, void *tag);
-boolean_t arc_buf_remove_ref(arc_buf_t *buf, void *tag);
+void arc_buf_destroy(arc_buf_t *buf, void *tag);
 void arc_buf_info(arc_buf_t *buf, arc_buf_info_t *abi, int state_index);
 uint64_t arc_buf_size(arc_buf_t *buf);
+uint64_t arc_buf_lsize(arc_buf_t *buf);
 void arc_release(arc_buf_t *buf, void *tag);
 int arc_released(arc_buf_t *buf);
 void arc_buf_sigsegv(int sig, siginfo_t *si, void *unused);
 void arc_buf_freeze(arc_buf_t *buf);
 void arc_buf_thaw(arc_buf_t *buf);
-boolean_t arc_buf_eviction_needed(arc_buf_t *buf);
 #ifdef ZFS_DEBUG
 int arc_referenced(arc_buf_t *buf);
 #endif
@@ -188,22 +236,21 @@ int arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
     arc_done_func_t *done, void *private, zio_priority_t priority, int flags,
     arc_flags_t *arc_flags, const zbookmark_phys_t *zb);
 zio_t *arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
-    blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, boolean_t l2arc_compress,
-    const zio_prop_t *zp, arc_done_func_t *ready, arc_done_func_t *physdone,
-    arc_done_func_t *done, void *private, zio_priority_t priority,
-    int zio_flags, const zbookmark_phys_t *zb);
+    blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, const zio_prop_t *zp,
+    arc_done_func_t *ready, arc_done_func_t *child_ready,
+    arc_done_func_t *physdone, arc_done_func_t *done,
+    void *private, zio_priority_t priority, int zio_flags,
+    const zbookmark_phys_t *zb);
 
 arc_prune_t *arc_add_prune_callback(arc_prune_func_t *func, void *private);
 void arc_remove_prune_callback(arc_prune_t *p);
 void arc_freed(spa_t *spa, const blkptr_t *bp);
 
-void arc_set_callback(arc_buf_t *buf, arc_evict_func_t *func, void *private);
-boolean_t arc_clear_callback(arc_buf_t *buf);
-
 void arc_flush(spa_t *spa, boolean_t retry);
 void arc_tempreserve_clear(uint64_t reserve);
 int arc_tempreserve_space(uint64_t reserve, uint64_t txg);
 
+uint64_t arc_max_bytes(void);
 void arc_init(void);
 void arc_fini(void);
 
index a9dbfc8dd73e29dbbbff3afc0aae8d096d7d2f06..d2dc527feb4ed0f95c269c1c3be10d73a3460ca8 100644 (file)
@@ -74,7 +74,7 @@ typedef struct arc_state {
        /*
         * total amount of evictable data in this state
         */
-       uint64_t arcs_lsize[ARC_BUFC_NUMTYPES];
+       refcount_t arcs_esize[ARC_BUFC_NUMTYPES];
        /*
         * total amount of data in this state; this includes: evictable,
         * non-evictable, ARC_BUFC_DATA, and ARC_BUFC_METADATA.
@@ -92,6 +92,7 @@ struct arc_callback {
        void                    *acb_private;
        arc_done_func_t         *acb_done;
        arc_buf_t               *acb_buf;
+       boolean_t               acb_compressed;
        zio_t                   *acb_zio_dummy;
        arc_callback_t          *acb_next;
 };
@@ -101,6 +102,7 @@ typedef struct arc_write_callback arc_write_callback_t;
 struct arc_write_callback {
        void            *awcb_private;
        arc_done_func_t *awcb_ready;
+       arc_done_func_t *awcb_children_ready;
        arc_done_func_t *awcb_physdone;
        arc_done_func_t *awcb_done;
        arc_buf_t       *awcb_buf;
@@ -139,11 +141,13 @@ struct arc_write_callback {
  */
 typedef struct l1arc_buf_hdr {
        kmutex_t                b_freeze_lock;
+       zio_cksum_t             *b_freeze_cksum;
 
        arc_buf_t               *b_buf;
-       uint32_t                b_datacnt;
+       uint32_t                b_bufcnt;
        /* for waiting on writes to complete */
        kcondvar_t              b_cv;
+       uint8_t                 b_byteswap;
 
 
        /* protected by arc state mutex */
@@ -162,8 +166,7 @@ typedef struct l1arc_buf_hdr {
        refcount_t              b_refcnt;
 
        arc_callback_t          *b_acb;
-       /* temporary buffer holder for in-flight compressed data */
-       void                    *b_tmp_cdata;
+       void                    *b_pdata;
 } l1arc_buf_hdr_t;
 
 typedef struct l2arc_dev {
@@ -184,10 +187,7 @@ typedef struct l2arc_buf_hdr {
        /* protected by arc_buf_hdr mutex */
        l2arc_dev_t             *b_dev;         /* L2ARC device */
        uint64_t                b_daddr;        /* disk address, offset byte */
-       /* real alloc'd buffer size depending on b_compress applied */
        uint32_t                b_hits;
-       int32_t                 b_asize;
-       uint8_t                 b_compress;
 
        list_node_t             b_l2node;
 } l2arc_buf_hdr_t;
@@ -201,20 +201,37 @@ struct arc_buf_hdr {
        /* protected by hash lock */
        dva_t                   b_dva;
        uint64_t                b_birth;
-       /*
-        * Even though this checksum is only set/verified when a buffer is in
-        * the L1 cache, it needs to be in the set of common fields because it
-        * must be preserved from the time before a buffer is written out to
-        * L2ARC until after it is read back in.
-        */
-       zio_cksum_t             *b_freeze_cksum;
 
+       arc_buf_contents_t      b_type;
        arc_buf_hdr_t           *b_hash_next;
        arc_flags_t             b_flags;
 
-       /* immutable */
-       int32_t                 b_size;
-       uint64_t                b_spa;
+       /*
+        * This field stores the size of the data buffer after
+        * compression, and is set in the arc's zio completion handlers.
+        * It is in units of SPA_MINBLOCKSIZE (e.g. 1 == 512 bytes).
+        *
+        * While the block pointers can store up to 32MB in their psize
+        * field, we can only store up to 32MB minus 512B. This is due
+        * to the bp using a bias of 1, whereas we use a bias of 0 (i.e.
+        * a field of zeros represents 512B in the bp). We can't use a
+        * bias of 1 since we need to reserve a psize of zero, here, to
+        * represent holes and embedded blocks.
+        *
+        * This isn't a problem in practice, since the maximum size of a
+        * buffer is limited to 16MB, so we never need to store 32MB in
+        * this field. Even in the upstream illumos code base, the
+        * maximum size of a buffer is limited to 16MB.
+        */
+       uint16_t                b_psize;
+
+       /*
+        * This field stores the size of the data buffer before
+        * compression, and cannot change once set. It is in units
+        * of SPA_MINBLOCKSIZE (e.g. 2 == 1024 bytes)
+        */
+       uint16_t                b_lsize;        /* immutable */
+       uint64_t                b_spa;          /* immutable */
 
        /* L2ARC fields. Undefined when not in L2ARC. */
        l2arc_buf_hdr_t         b_l2hdr;
index 10e0ddaeef884244ac23b84399962651609ec14b..ba51e2a790f40799d81b026ceebf4988b8603e5d 100644 (file)
@@ -105,6 +105,13 @@ extern "C" {
  * as is needed for any linked list implementation.
  */
 
+/*
+ * AVL comparator helpers
+ */
+#define        AVL_ISIGN(a)    (((a) > 0) - ((a) < 0))
+#define        AVL_CMP(a, b)   (((a) > (b)) - ((a) < (b)))
+#define        AVL_PCMP(a, b)  \
+       (((uintptr_t)(a) > (uintptr_t)(b)) - ((uintptr_t)(a) < (uintptr_t)(b)))
 
 /*
  * Type used for the root of the AVL tree.
diff --git a/zfs/include/sys/bqueue.h b/zfs/include/sys/bqueue.h
new file mode 100644 (file)
index 0000000..63722df
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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.
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _BQUEUE_H
+#define        _BQUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include       <sys/zfs_context.h>
+
+typedef struct bqueue {
+       list_t bq_list;
+       kmutex_t bq_lock;
+       kcondvar_t bq_add_cv;
+       kcondvar_t bq_pop_cv;
+       uint64_t bq_size;
+       uint64_t bq_maxsize;
+       size_t bq_node_offset;
+} bqueue_t;
+
+typedef struct bqueue_node {
+       list_node_t bqn_node;
+       uint64_t bqn_size;
+} bqueue_node_t;
+
+
+int bqueue_init(bqueue_t *, uint64_t, size_t);
+void bqueue_destroy(bqueue_t *);
+void bqueue_enqueue(bqueue_t *, void *, uint64_t);
+void *bqueue_dequeue(bqueue_t *);
+boolean_t bqueue_empty(bqueue_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BQUEUE_H */
diff --git a/zfs/include/sys/crypto/Makefile.am b/zfs/include/sys/crypto/Makefile.am
new file mode 100644 (file)
index 0000000..7f8156b
--- /dev/null
@@ -0,0 +1,20 @@
+COMMON_H = \
+       $(top_srcdir)/include/sys/crypto/api.h \
+       $(top_srcdir)/include/sys/crypto/common.h \
+       $(top_srcdir)/include/sys/crypto/icp.h
+
+KERNEL_H =
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs/sys/crypto
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/crypto
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/zfs/include/sys/crypto/api.h b/zfs/include/sys/crypto/api.h
new file mode 100644 (file)
index 0000000..7c3c465
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SYS_CRYPTO_API_H
+#define        _SYS_CRYPTO_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+
+typedef long crypto_req_id_t;
+typedef void *crypto_bc_t;
+typedef void *crypto_context_t;
+typedef void *crypto_ctx_template_t;
+
+typedef uint32_t crypto_call_flag_t;
+
+/* crypto_call_flag's values */
+#define        CRYPTO_ALWAYS_QUEUE     0x00000001      /* ALWAYS queue the req. */
+#define        CRYPTO_NOTIFY_OPDONE    0x00000002      /* Notify intermediate steps */
+#define        CRYPTO_SKIP_REQID       0x00000004      /* Skip request ID generation */
+#define        CRYPTO_RESTRICTED       0x00000008      /* cannot use restricted prov */
+
+typedef struct {
+       crypto_call_flag_t      cr_flag;
+       void                    (*cr_callback_func)(void *, int);
+       void                    *cr_callback_arg;
+       crypto_req_id_t         cr_reqid;
+} crypto_call_req_t;
+
+/*
+ * Returns the mechanism type corresponding to a mechanism name.
+ */
+
+#define        CRYPTO_MECH_INVALID     ((uint64_t)-1)
+extern crypto_mech_type_t crypto_mech2id(crypto_mech_name_t name);
+
+/*
+ * Create and destroy context templates.
+ */
+extern int crypto_create_ctx_template(crypto_mechanism_t *mech,
+    crypto_key_t *key, crypto_ctx_template_t *tmpl, int kmflag);
+extern void crypto_destroy_ctx_template(crypto_ctx_template_t tmpl);
+
+/*
+ * Single and multi-part digest operations.
+ */
+extern int crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
+    crypto_data_t *digest, crypto_call_req_t *cr);
+extern int crypto_digest_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
+    crypto_call_req_t *);
+extern int crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
+    crypto_call_req_t *cr);
+extern int crypto_digest_init_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_context_t *, crypto_call_req_t *);
+extern int crypto_digest_update(crypto_context_t ctx, crypto_data_t *data,
+    crypto_call_req_t *cr);
+extern int crypto_digest_final(crypto_context_t ctx, crypto_data_t *digest,
+    crypto_call_req_t *cr);
+
+/*
+ * Single and multi-part MAC operations.
+ */
+extern int crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
+    crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
+    crypto_call_req_t *cr);
+extern int crypto_mac_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
+    crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data,
+    crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
+    crypto_call_req_t *cr);
+extern int crypto_mac_verify_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
+    crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
+extern int crypto_mac_init_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
+    crypto_context_t *, crypto_call_req_t *);
+extern int crypto_mac_update(crypto_context_t ctx, crypto_data_t *data,
+    crypto_call_req_t *cr);
+extern int crypto_mac_final(crypto_context_t ctx, crypto_data_t *data,
+    crypto_call_req_t *cr);
+
+/*
+ * Single and multi-part sign with private key operations.
+ */
+extern int crypto_sign(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_data_t *data, crypto_ctx_template_t tmpl,
+    crypto_data_t *signature, crypto_call_req_t *cr);
+extern int crypto_sign_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+    crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_sign_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
+extern int crypto_sign_init_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
+    crypto_context_t *, crypto_call_req_t *);
+extern int crypto_sign_update(crypto_context_t ctx, crypto_data_t *data,
+    crypto_call_req_t *cr);
+extern int crypto_sign_final(crypto_context_t ctx, crypto_data_t *signature,
+    crypto_call_req_t *cr);
+extern int crypto_sign_recover_init_prov(crypto_provider_t,
+    crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+    crypto_ctx_template_t tmpl, crypto_context_t *, crypto_call_req_t *);
+extern int crypto_sign_recover(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
+    crypto_call_req_t *cr);
+extern int crypto_sign_recover_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+    crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+
+/*
+ * Single and multi-part verify with public key operations.
+ */
+extern int crypto_verify(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
+    crypto_call_req_t *cr);
+extern int crypto_verify_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+    crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_verify_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
+extern int crypto_verify_init_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
+    crypto_context_t *, crypto_call_req_t *);
+extern int crypto_verify_update(crypto_context_t ctx, crypto_data_t *data,
+    crypto_call_req_t *cr);
+extern int crypto_verify_final(crypto_context_t ctx, crypto_data_t *signature,
+    crypto_call_req_t *cr);
+extern int crypto_verify_recover_init_prov(crypto_provider_t,
+    crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+    crypto_ctx_template_t tmpl, crypto_context_t *, crypto_call_req_t *);
+extern int crypto_verify_recover(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_data_t *signature, crypto_ctx_template_t tmpl, crypto_data_t *data,
+    crypto_call_req_t *cr);
+extern int crypto_verify_recover_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+    crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+
+/*
+ * Single and multi-part encryption operations.
+ */
+extern int crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
+    crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
+    crypto_call_req_t *cr);
+extern int crypto_encrypt_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
+    crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_encrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
+extern int crypto_encrypt_init_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
+    crypto_context_t *, crypto_call_req_t *);
+extern int crypto_encrypt_update(crypto_context_t ctx,
+    crypto_data_t *plaintext, crypto_data_t *ciphertext,
+    crypto_call_req_t *cr);
+extern int crypto_encrypt_final(crypto_context_t ctx,
+    crypto_data_t *ciphertext, crypto_call_req_t *cr);
+
+/*
+ * Single and multi-part decryption operations.
+ */
+extern int crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *ciphertext,
+    crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
+    crypto_call_req_t *cr);
+extern int crypto_decrypt_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
+    crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_decrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *cr);
+extern int crypto_decrypt_init_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
+    crypto_context_t *, crypto_call_req_t *);
+extern int crypto_decrypt_update(crypto_context_t ctx,
+    crypto_data_t *ciphertext, crypto_data_t *plaintext,
+    crypto_call_req_t *cr);
+extern int crypto_decrypt_final(crypto_context_t ctx, crypto_data_t *plaintext,
+    crypto_call_req_t *cr);
+
+/*
+ * Single and multi-part encrypt/MAC dual operations.
+ */
+extern int crypto_encrypt_mac(crypto_mechanism_t *encr_mech,
+    crypto_mechanism_t *mac_mech, crypto_data_t *pt,
+    crypto_key_t *encr_key, crypto_key_t *mac_key,
+    crypto_ctx_template_t encr_tmpl, crypto_ctx_template_t mac_tmpl,
+    crypto_dual_data_t *ct, crypto_data_t *mac, crypto_call_req_t *cr);
+extern int crypto_encrypt_mac_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_mechanism_t *, crypto_data_t *,
+    crypto_key_t *, crypto_key_t *, crypto_ctx_template_t,
+    crypto_ctx_template_t, crypto_dual_data_t *, crypto_data_t *,
+    crypto_call_req_t *);
+extern int crypto_encrypt_mac_init(crypto_mechanism_t *encr_mech,
+    crypto_mechanism_t *mac_mech, crypto_key_t *encr_key,
+    crypto_key_t *mac_key, crypto_ctx_template_t encr_tmpl,
+    crypto_ctx_template_t mac_tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *cr);
+extern int crypto_encrypt_mac_init_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_mechanism_t *, crypto_key_t *, crypto_key_t *,
+    crypto_ctx_template_t, crypto_ctx_template_t, crypto_context_t *,
+    crypto_call_req_t *);
+extern int crypto_encrypt_mac_update(crypto_context_t ctx,
+    crypto_data_t *pt, crypto_dual_data_t *ct, crypto_call_req_t *cr);
+extern int crypto_encrypt_mac_final(crypto_context_t ctx,
+    crypto_dual_data_t *ct, crypto_data_t *mac, crypto_call_req_t *cr);
+
+/*
+ * Single and multi-part MAC/decrypt dual operations.
+ */
+extern int crypto_mac_decrypt(crypto_mechanism_t *mac_mech,
+    crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
+    crypto_key_t *mac_key, crypto_key_t *decr_key,
+    crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
+    crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
+extern int crypto_mac_decrypt_prov(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *mac_mech, crypto_mechanism_t *decr_mech,
+    crypto_dual_data_t *ct, crypto_key_t *mac_key, crypto_key_t *decr_key,
+    crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
+    crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
+extern int crypto_mac_verify_decrypt(crypto_mechanism_t *mac_mech,
+    crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
+    crypto_key_t *mac_key, crypto_key_t *decr_key,
+    crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
+    crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
+extern int crypto_mac_verify_decrypt_prov(crypto_provider_t,
+    crypto_session_id_t, crypto_mechanism_t *mac_mech,
+    crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
+    crypto_key_t *mac_key, crypto_key_t *decr_key,
+    crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
+    crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
+extern int crypto_mac_decrypt_init(crypto_mechanism_t *mac_mech,
+    crypto_mechanism_t *decr_mech, crypto_key_t *mac_key,
+    crypto_key_t *decr_key, crypto_ctx_template_t mac_tmpl,
+    crypto_ctx_template_t decr_tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *cr);
+extern int crypto_mac_decrypt_init_prov(crypto_provider_t,
+    crypto_session_id_t, crypto_mechanism_t *mac_mech,
+    crypto_mechanism_t *decr_mech, crypto_key_t *mac_key,
+    crypto_key_t *decr_key, crypto_ctx_template_t mac_tmpl,
+    crypto_ctx_template_t decr_tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *cr);
+extern int crypto_mac_decrypt_update(crypto_context_t ctx,
+    crypto_dual_data_t *ct, crypto_data_t *pt, crypto_call_req_t *cr);
+extern int crypto_mac_decrypt_final(crypto_context_t ctx, crypto_data_t *mac,
+    crypto_data_t *pt, crypto_call_req_t *cr);
+
+/* Session Management */
+extern int crypto_session_open(crypto_provider_t, crypto_session_id_t *,
+    crypto_call_req_t *);
+extern int crypto_session_close(crypto_provider_t, crypto_session_id_t,
+    crypto_call_req_t *);
+extern int crypto_session_login(crypto_provider_t, crypto_session_id_t,
+    crypto_user_type_t, char *, size_t, crypto_call_req_t *);
+extern int crypto_session_logout(crypto_provider_t, crypto_session_id_t,
+    crypto_call_req_t *);
+
+/* Object Management */
+extern int crypto_object_copy(crypto_provider_t, crypto_session_id_t,
+    crypto_object_id_t, crypto_object_attribute_t *, uint_t,
+    crypto_object_id_t *, crypto_call_req_t *);
+extern int crypto_object_create(crypto_provider_t, crypto_session_id_t,
+    crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
+    crypto_call_req_t *);
+extern int crypto_object_destroy(crypto_provider_t, crypto_session_id_t,
+    crypto_object_id_t, crypto_call_req_t *);
+extern int crypto_object_get_attribute_value(crypto_provider_t,
+    crypto_session_id_t, crypto_object_id_t, crypto_object_attribute_t *,
+    uint_t, crypto_call_req_t *);
+extern int crypto_object_get_size(crypto_provider_t, crypto_session_id_t,
+    crypto_object_id_t, size_t *, crypto_call_req_t *);
+extern int crypto_object_find_final(crypto_provider_t, void *,
+    crypto_call_req_t *);
+extern int crypto_object_find_init(crypto_provider_t, crypto_session_id_t,
+    crypto_object_attribute_t *, uint_t, void **, crypto_call_req_t *);
+extern int crypto_object_find(crypto_provider_t, void *, crypto_object_id_t *,
+    uint_t *, uint_t, crypto_call_req_t *);
+extern int crypto_object_set_attribute_value(crypto_provider_t,
+    crypto_session_id_t, crypto_object_id_t, crypto_object_attribute_t *,
+    uint_t, crypto_call_req_t *);
+
+/* Key Management */
+extern int crypto_key_derive(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
+    uint_t, crypto_object_id_t *, crypto_call_req_t *);
+extern int crypto_key_generate(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
+    crypto_object_id_t *, crypto_call_req_t *);
+extern int crypto_key_generate_pair(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
+    crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
+    crypto_object_id_t *, crypto_call_req_t *);
+extern int crypto_key_unwrap(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, uchar_t *, size_t *,
+    crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
+    crypto_call_req_t *);
+extern int crypto_key_wrap(crypto_provider_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_object_id_t *, uchar_t *,
+    size_t *, crypto_call_req_t *);
+extern int crypto_key_check_prov(crypto_provider_t, crypto_mechanism_t *mech,
+    crypto_key_t *key);
+extern int crypto_key_check(crypto_mechanism_t *mech, crypto_key_t *key);
+
+
+/*
+ * Routines to cancel a single asynchronous request or all asynchronous
+ * requests associated with a particular context.
+ */
+extern void crypto_cancel_req(crypto_req_id_t req);
+extern void crypto_cancel_ctx(crypto_context_t ctx);
+
+/*
+ * crypto_get_mech_list(9F) allocates and returns the list of currently
+ * supported cryptographic mechanisms.
+ */
+extern crypto_mech_name_t *crypto_get_mech_list(uint_t *count, int kmflag);
+extern void crypto_free_mech_list(crypto_mech_name_t *mech_names,
+    uint_t count);
+
+extern crypto_provider_t crypto_get_provider(char *, char *, char *);
+extern int crypto_get_provinfo(crypto_provider_t, crypto_provider_ext_info_t *);
+extern void crypto_release_provider(crypto_provider_t);
+
+/*
+ * A kernel consumer can request to be notified when some particular event
+ * occurs. The valid events, callback function type, and functions to
+ * be called to register or unregister for notification are defined below.
+ */
+
+#define        CRYPTO_EVENT_MECHS_CHANGED              0x00000001
+#define        CRYPTO_EVENT_PROVIDER_REGISTERED        0x00000002
+#define        CRYPTO_EVENT_PROVIDER_UNREGISTERED      0x00000004
+
+typedef enum {
+       CRYPTO_MECH_ADDED = 1,
+       CRYPTO_MECH_REMOVED
+} crypto_event_change_t;
+
+/* The event_arg argument structure for CRYPTO_EVENT_PROVIDERS_CHANGE event */
+typedef struct crypto_notify_event_change {
+       crypto_mech_name_t ec_mech_name;
+       crypto_provider_type_t ec_provider_type;
+       crypto_event_change_t ec_change;
+} crypto_notify_event_change_t;
+
+typedef void *crypto_notify_handle_t;
+typedef void (*crypto_notify_callback_t)(uint32_t event_mask, void *event_arg);
+
+extern crypto_notify_handle_t crypto_notify_events(
+    crypto_notify_callback_t nf, uint32_t event_mask);
+extern void crypto_unnotify_events(crypto_notify_handle_t);
+
+/*
+ * crypto_bufcall(9F) group of routines.
+ */
+extern crypto_bc_t crypto_bufcall_alloc(void);
+extern int crypto_bufcall_free(crypto_bc_t bc);
+extern int crypto_bufcall(crypto_bc_t bc, void (*func)(void *arg), void *arg);
+extern int crypto_unbufcall(crypto_bc_t bc);
+
+/*
+ * To obtain the list of key size ranges supported by a mechanism.
+ */
+
+#define        CRYPTO_MECH_USAGE_ENCRYPT       0x00000001
+#define        CRYPTO_MECH_USAGE_DECRYPT       0x00000002
+#define        CRYPTO_MECH_USAGE_MAC           0x00000004
+
+typedef        uint32_t crypto_mech_usage_t;
+
+typedef struct crypto_mechanism_info {
+       size_t mi_min_key_size;
+       size_t mi_max_key_size;
+       crypto_keysize_unit_t mi_keysize_unit; /* for mi_xxx_key_size */
+       crypto_mech_usage_t mi_usage;
+} crypto_mechanism_info_t;
+
+#ifdef _SYSCALL32
+
+typedef struct crypto_mechanism_info32 {
+       size32_t mi_min_key_size;
+       size32_t mi_max_key_size;
+       crypto_keysize_unit_t mi_keysize_unit; /* for mi_xxx_key_size */
+       crypto_mech_usage_t mi_usage;
+} crypto_mechanism_info32_t;
+
+#endif /* _SYSCALL32 */
+
+extern int crypto_get_all_mech_info(crypto_mech_type_t,
+    crypto_mechanism_info_t **, uint_t *, int);
+extern void crypto_free_all_mech_info(crypto_mechanism_info_t *, uint_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_API_H */
diff --git a/zfs/include/sys/crypto/common.h b/zfs/include/sys/crypto/common.h
new file mode 100644 (file)
index 0000000..a4f9d98
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+/*
+ * Copyright 2013 Saso Kiselkov.  All rights reserved.
+ */
+
+#ifndef _SYS_CRYPTO_COMMON_H
+#define        _SYS_CRYPTO_COMMON_H
+
+/*
+ * Header file for the common data structures of the cryptographic framework
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+
+/* Cryptographic Mechanisms */
+
+#define        CRYPTO_MAX_MECH_NAME 32
+typedef char crypto_mech_name_t[CRYPTO_MAX_MECH_NAME];
+
+typedef uint64_t crypto_mech_type_t;
+
+typedef struct crypto_mechanism {
+       crypto_mech_type_t      cm_type;        /* mechanism type */
+       caddr_t                 cm_param;       /* mech. parameter */
+       size_t                  cm_param_len;   /* mech. parameter len */
+} crypto_mechanism_t;
+
+#ifdef  _SYSCALL32
+
+typedef struct crypto_mechanism32 {
+       crypto_mech_type_t      cm_type;        /* mechanism type */
+       caddr32_t               cm_param;       /* mech. parameter */
+       size32_t                cm_param_len;   /* mech. parameter len */
+} crypto_mechanism32_t;
+
+#endif  /* _SYSCALL32 */
+
+/* CK_AES_CTR_PARAMS provides parameters to the CKM_AES_CTR mechanism */
+typedef struct CK_AES_CTR_PARAMS {
+       ulong_t ulCounterBits;
+       uint8_t cb[16];
+} CK_AES_CTR_PARAMS;
+
+/* CK_AES_CCM_PARAMS provides parameters to the CKM_AES_CCM mechanism */
+typedef struct CK_AES_CCM_PARAMS {
+       ulong_t ulMACSize;
+       ulong_t ulNonceSize;
+       ulong_t ulAuthDataSize;
+       ulong_t ulDataSize; /* used for plaintext or ciphertext */
+       uchar_t *nonce;
+       uchar_t *authData;
+} CK_AES_CCM_PARAMS;
+
+/* CK_AES_GCM_PARAMS provides parameters to the CKM_AES_GCM mechanism */
+typedef struct CK_AES_GCM_PARAMS {
+       uchar_t *pIv;
+       ulong_t ulIvLen;
+       ulong_t ulIvBits;
+       uchar_t *pAAD;
+       ulong_t ulAADLen;
+       ulong_t ulTagBits;
+} CK_AES_GCM_PARAMS;
+
+/* CK_AES_GMAC_PARAMS provides parameters to the CKM_AES_GMAC mechanism */
+typedef struct CK_AES_GMAC_PARAMS {
+       uchar_t *pIv;
+       uchar_t *pAAD;
+       ulong_t ulAADLen;
+} CK_AES_GMAC_PARAMS;
+
+/*
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_KEY_DERIVE mechanism
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+       ulong_t         kdf;
+       ulong_t         ulSharedDataLen;
+       uchar_t         *pSharedData;
+       ulong_t         ulPublicDataLen;
+       uchar_t         *pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+#ifdef  _SYSCALL32
+
+/* needed for 32-bit applications running on 64-bit kernels */
+typedef struct CK_AES_CTR_PARAMS32 {
+       uint32_t ulCounterBits;
+       uint8_t cb[16];
+} CK_AES_CTR_PARAMS32;
+
+/* needed for 32-bit applications running on 64-bit kernels */
+typedef struct CK_AES_CCM_PARAMS32 {
+       uint32_t ulMACSize;
+       uint32_t ulNonceSize;
+       uint32_t ulAuthDataSize;
+       uint32_t ulDataSize;
+       caddr32_t nonce;
+       caddr32_t authData;
+} CK_AES_CCM_PARAMS32;
+
+/* needed for 32-bit applications running on 64-bit kernels */
+typedef struct CK_AES_GCM_PARAMS32 {
+       caddr32_t pIv;
+       uint32_t ulIvLen;
+       uint32_t ulIvBits;
+       caddr32_t pAAD;
+       uint32_t ulAADLen;
+       uint32_t ulTagBits;
+} CK_AES_GCM_PARAMS32;
+
+/* needed for 32-bit applications running on 64-bit kernels */
+typedef struct CK_AES_GMAC_PARAMS32 {
+       caddr32_t pIv;
+       caddr32_t pAAD;
+       uint32_t ulAADLen;
+} CK_AES_GMAC_PARAMS32;
+
+typedef struct CK_ECDH1_DERIVE_PARAMS32 {
+       uint32_t        kdf;
+       uint32_t        ulSharedDataLen;
+       caddr32_t       pSharedData;
+       uint32_t        ulPublicDataLen;
+       caddr32_t       pPublicData;
+} CK_ECDH1_DERIVE_PARAMS32;
+
+#endif  /* _SYSCALL32 */
+
+/*
+ * The measurement unit bit flag for a mechanism's minimum or maximum key size.
+ * The unit are mechanism dependent.  It can be in bits or in bytes.
+ */
+typedef uint32_t crypto_keysize_unit_t;
+
+/*
+ * The following bit flags are valid in cm_mech_flags field in
+ * the crypto_mech_info_t structure of the SPI.
+ *
+ * Only the first two bit flags are valid in mi_keysize_unit
+ * field in the crypto_mechanism_info_t structure of the API.
+ */
+#define        CRYPTO_KEYSIZE_UNIT_IN_BITS     0x00000001
+#define        CRYPTO_KEYSIZE_UNIT_IN_BYTES    0x00000002
+#define        CRYPTO_CAN_SHARE_OPSTATE        0x00000004 /* supports sharing */
+
+
+/* Mechanisms supported out-of-the-box */
+#define        SUN_CKM_MD4                     "CKM_MD4"
+#define        SUN_CKM_MD5                     "CKM_MD5"
+#define        SUN_CKM_MD5_HMAC                "CKM_MD5_HMAC"
+#define        SUN_CKM_MD5_HMAC_GENERAL        "CKM_MD5_HMAC_GENERAL"
+#define        SUN_CKM_SHA1                    "CKM_SHA_1"
+#define        SUN_CKM_SHA1_HMAC               "CKM_SHA_1_HMAC"
+#define        SUN_CKM_SHA1_HMAC_GENERAL       "CKM_SHA_1_HMAC_GENERAL"
+#define        SUN_CKM_SHA256                  "CKM_SHA256"
+#define        SUN_CKM_SHA256_HMAC             "CKM_SHA256_HMAC"
+#define        SUN_CKM_SHA256_HMAC_GENERAL     "CKM_SHA256_HMAC_GENERAL"
+#define        SUN_CKM_SHA384                  "CKM_SHA384"
+#define        SUN_CKM_SHA384_HMAC             "CKM_SHA384_HMAC"
+#define        SUN_CKM_SHA384_HMAC_GENERAL     "CKM_SHA384_HMAC_GENERAL"
+#define        SUN_CKM_SHA512                  "CKM_SHA512"
+#define        SUN_CKM_SHA512_HMAC             "CKM_SHA512_HMAC"
+#define        SUN_CKM_SHA512_HMAC_GENERAL     "CKM_SHA512_HMAC_GENERAL"
+#define        SUN_CKM_SHA512_224              "CKM_SHA512_224"
+#define        SUN_CKM_SHA512_256              "CKM_SHA512_256"
+#define        SUN_CKM_DES_CBC                 "CKM_DES_CBC"
+#define        SUN_CKM_DES3_CBC                "CKM_DES3_CBC"
+#define        SUN_CKM_DES_ECB                 "CKM_DES_ECB"
+#define        SUN_CKM_DES3_ECB                "CKM_DES3_ECB"
+#define        SUN_CKM_BLOWFISH_CBC            "CKM_BLOWFISH_CBC"
+#define        SUN_CKM_BLOWFISH_ECB            "CKM_BLOWFISH_ECB"
+#define        SUN_CKM_AES_CBC                 "CKM_AES_CBC"
+#define        SUN_CKM_AES_ECB                 "CKM_AES_ECB"
+#define        SUN_CKM_AES_CTR                 "CKM_AES_CTR"
+#define        SUN_CKM_AES_CCM                 "CKM_AES_CCM"
+#define        SUN_CKM_AES_GCM                 "CKM_AES_GCM"
+#define        SUN_CKM_AES_GMAC                "CKM_AES_GMAC"
+#define        SUN_CKM_AES_CFB128              "CKM_AES_CFB128"
+#define        SUN_CKM_RC4                     "CKM_RC4"
+#define        SUN_CKM_RSA_PKCS                "CKM_RSA_PKCS"
+#define        SUN_CKM_RSA_X_509               "CKM_RSA_X_509"
+#define        SUN_CKM_MD5_RSA_PKCS            "CKM_MD5_RSA_PKCS"
+#define        SUN_CKM_SHA1_RSA_PKCS           "CKM_SHA1_RSA_PKCS"
+#define        SUN_CKM_SHA256_RSA_PKCS         "CKM_SHA256_RSA_PKCS"
+#define        SUN_CKM_SHA384_RSA_PKCS         "CKM_SHA384_RSA_PKCS"
+#define        SUN_CKM_SHA512_RSA_PKCS         "CKM_SHA512_RSA_PKCS"
+#define        SUN_CKM_EC_KEY_PAIR_GEN         "CKM_EC_KEY_PAIR_GEN"
+#define        SUN_CKM_ECDH1_DERIVE            "CKM_ECDH1_DERIVE"
+#define        SUN_CKM_ECDSA_SHA1              "CKM_ECDSA_SHA1"
+#define        SUN_CKM_ECDSA                   "CKM_ECDSA"
+
+/* Shared operation context format for CKM_RC4 */
+typedef struct {
+#if defined(__amd64)
+       uint32_t        i, j;
+       uint32_t        arr[256];
+       uint32_t        flag;
+#else
+       uchar_t         arr[256];
+       uchar_t         i, j;
+#endif /* __amd64 */
+       uint64_t        pad;            /* For 64-bit alignment */
+} arcfour_state_t;
+
+/* Data arguments of cryptographic operations */
+
+typedef enum crypto_data_format {
+       CRYPTO_DATA_RAW = 1,
+       CRYPTO_DATA_UIO,
+} crypto_data_format_t;
+
+typedef struct crypto_data {
+       crypto_data_format_t    cd_format;      /* Format identifier    */
+       off_t                   cd_offset;      /* Offset from the beginning */
+       size_t                  cd_length;      /* # of bytes in use */
+       caddr_t                 cd_miscdata;    /* ancillary data */
+       union {
+               /* Raw format */
+               iovec_t cdu_raw;                /* Pointer and length       */
+
+               /* uio scatter-gather format */
+               uio_t   *cdu_uio;
+
+       } cdu;  /* Crypto Data Union */
+} crypto_data_t;
+
+#define        cd_raw          cdu.cdu_raw
+#define        cd_uio          cdu.cdu_uio
+#define        cd_mp           cdu.cdu_mp
+
+typedef struct crypto_dual_data {
+       crypto_data_t           dd_data;        /* The data */
+       off_t                   dd_offset2;     /* Used by dual operation */
+       size_t                  dd_len2;        /* # of bytes to take   */
+} crypto_dual_data_t;
+
+#define        dd_format       dd_data.cd_format
+#define        dd_offset1      dd_data.cd_offset
+#define        dd_len1         dd_data.cd_length
+#define        dd_miscdata     dd_data.cd_miscdata
+#define        dd_raw          dd_data.cd_raw
+#define        dd_uio          dd_data.cd_uio
+#define        dd_mp           dd_data.cd_mp
+
+/* The keys, and their contents */
+
+typedef enum {
+       CRYPTO_KEY_RAW = 1,     /* ck_data is a cleartext key */
+       CRYPTO_KEY_REFERENCE,   /* ck_obj_id is an opaque reference */
+       CRYPTO_KEY_ATTR_LIST    /* ck_attrs is a list of object attributes */
+} crypto_key_format_t;
+
+typedef uint64_t crypto_attr_type_t;
+
+/* Attribute types to use for passing a RSA public key or a private key. */
+#define        SUN_CKA_MODULUS                 0x00000120
+#define        SUN_CKA_MODULUS_BITS            0x00000121
+#define        SUN_CKA_PUBLIC_EXPONENT         0x00000122
+#define        SUN_CKA_PRIVATE_EXPONENT        0x00000123
+#define        SUN_CKA_PRIME_1                 0x00000124
+#define        SUN_CKA_PRIME_2                 0x00000125
+#define        SUN_CKA_EXPONENT_1              0x00000126
+#define        SUN_CKA_EXPONENT_2              0x00000127
+#define        SUN_CKA_COEFFICIENT             0x00000128
+#define        SUN_CKA_PRIME                   0x00000130
+#define        SUN_CKA_SUBPRIME                0x00000131
+#define        SUN_CKA_BASE                    0x00000132
+
+#define        CKK_EC                  0x00000003
+#define        CKK_GENERIC_SECRET      0x00000010
+#define        CKK_RC4                 0x00000012
+#define        CKK_AES                 0x0000001F
+#define        CKK_DES                 0x00000013
+#define        CKK_DES2                0x00000014
+#define        CKK_DES3                0x00000015
+
+#define        CKO_PUBLIC_KEY          0x00000002
+#define        CKO_PRIVATE_KEY         0x00000003
+#define        CKA_CLASS               0x00000000
+#define        CKA_VALUE               0x00000011
+#define        CKA_KEY_TYPE            0x00000100
+#define        CKA_VALUE_LEN           0x00000161
+#define        CKA_EC_PARAMS           0x00000180
+#define        CKA_EC_POINT            0x00000181
+
+typedef uint32_t       crypto_object_id_t;
+
+typedef struct crypto_object_attribute {
+       crypto_attr_type_t      oa_type;        /* attribute type */
+       caddr_t                 oa_value;       /* attribute value */
+       ssize_t                 oa_value_len;   /* length of attribute value */
+} crypto_object_attribute_t;
+
+typedef struct crypto_key {
+       crypto_key_format_t     ck_format;      /* format identifier */
+       union {
+               /* for CRYPTO_KEY_RAW ck_format */
+               struct {
+                       uint_t  cku_v_length;   /* # of bits in ck_data   */
+                       void    *cku_v_data;    /* ptr to key value */
+               } cku_key_value;
+
+               /* for CRYPTO_KEY_REFERENCE ck_format */
+               crypto_object_id_t cku_key_id;  /* reference to object key */
+
+               /* for CRYPTO_KEY_ATTR_LIST ck_format */
+               struct {
+                       uint_t cku_a_count;     /* number of attributes */
+                       crypto_object_attribute_t *cku_a_oattr;
+               } cku_key_attrs;
+       } cku_data;                             /* Crypto Key union */
+} crypto_key_t;
+
+#ifdef  _SYSCALL32
+
+typedef struct crypto_object_attribute32 {
+       uint64_t        oa_type;        /* attribute type */
+       caddr32_t       oa_value;       /* attribute value */
+       ssize32_t       oa_value_len;   /* length of attribute value */
+} crypto_object_attribute32_t;
+
+typedef struct crypto_key32 {
+       crypto_key_format_t     ck_format;      /* format identifier */
+       union {
+               /* for CRYPTO_KEY_RAW ck_format */
+               struct {
+                       uint32_t cku_v_length;  /* # of bytes in ck_data */
+                       caddr32_t cku_v_data;   /* ptr to key value */
+               } cku_key_value;
+
+               /* for CRYPTO_KEY_REFERENCE ck_format */
+               crypto_object_id_t cku_key_id; /* reference to object key */
+
+               /* for CRYPTO_KEY_ATTR_LIST ck_format */
+               struct {
+                       uint32_t cku_a_count;   /* number of attributes */
+                       caddr32_t cku_a_oattr;
+               } cku_key_attrs;
+       } cku_data;                             /* Crypto Key union */
+} crypto_key32_t;
+
+#endif  /* _SYSCALL32 */
+
+#define        ck_data         cku_data.cku_key_value.cku_v_data
+#define        ck_length       cku_data.cku_key_value.cku_v_length
+#define        ck_obj_id       cku_data.cku_key_id
+#define        ck_count        cku_data.cku_key_attrs.cku_a_count
+#define        ck_attrs        cku_data.cku_key_attrs.cku_a_oattr
+
+/*
+ * Raw key lengths are expressed in number of bits.
+ * The following macro returns the minimum number of
+ * bytes that can contain the specified number of bits.
+ * Round up without overflowing the integer type.
+ */
+#define        CRYPTO_BITS2BYTES(n) ((n) == 0 ? 0 : (((n) - 1) >> 3) + 1)
+#define        CRYPTO_BYTES2BITS(n) ((n) << 3)
+
+/* Providers */
+
+typedef enum {
+       CRYPTO_HW_PROVIDER = 0,
+       CRYPTO_SW_PROVIDER,
+       CRYPTO_LOGICAL_PROVIDER
+} crypto_provider_type_t;
+
+typedef uint32_t       crypto_provider_id_t;
+#define        KCF_PROVID_INVALID      ((uint32_t)-1)
+
+typedef struct crypto_provider_entry {
+       crypto_provider_id_t    pe_provider_id;
+       uint_t                  pe_mechanism_count;
+} crypto_provider_entry_t;
+
+typedef struct crypto_dev_list_entry {
+       char                    le_dev_name[MAXNAMELEN];
+       uint_t                  le_dev_instance;
+       uint_t                  le_mechanism_count;
+} crypto_dev_list_entry_t;
+
+/* User type for authentication ioctls and SPI entry points */
+
+typedef enum crypto_user_type {
+       CRYPTO_SO = 0,
+       CRYPTO_USER
+} crypto_user_type_t;
+
+/* Version for provider management ioctls and SPI entry points */
+
+typedef struct crypto_version {
+       uchar_t cv_major;
+       uchar_t cv_minor;
+} crypto_version_t;
+
+/* session data structure opaque to the consumer */
+typedef void *crypto_session_t;
+
+/* provider data structure opaque to the consumer */
+typedef void *crypto_provider_t;
+
+/* Limits used by both consumers and providers */
+#define        CRYPTO_EXT_SIZE_LABEL           32
+#define        CRYPTO_EXT_SIZE_MANUF           32
+#define        CRYPTO_EXT_SIZE_MODEL           16
+#define        CRYPTO_EXT_SIZE_SERIAL          16
+#define        CRYPTO_EXT_SIZE_TIME            16
+
+typedef struct crypto_provider_ext_info {
+       uchar_t                 ei_label[CRYPTO_EXT_SIZE_LABEL];
+       uchar_t                 ei_manufacturerID[CRYPTO_EXT_SIZE_MANUF];
+       uchar_t                 ei_model[CRYPTO_EXT_SIZE_MODEL];
+       uchar_t                 ei_serial_number[CRYPTO_EXT_SIZE_SERIAL];
+       ulong_t                 ei_flags;
+       ulong_t                 ei_max_session_count;
+       ulong_t                 ei_max_pin_len;
+       ulong_t                 ei_min_pin_len;
+       ulong_t                 ei_total_public_memory;
+       ulong_t                 ei_free_public_memory;
+       ulong_t                 ei_total_private_memory;
+       ulong_t                 ei_free_private_memory;
+       crypto_version_t        ei_hardware_version;
+       crypto_version_t        ei_firmware_version;
+       uchar_t                 ei_time[CRYPTO_EXT_SIZE_TIME];
+       int                     ei_hash_max_input_len;
+       int                     ei_hmac_max_input_len;
+} crypto_provider_ext_info_t;
+
+typedef uint_t         crypto_session_id_t;
+
+typedef enum cmd_type {
+       COPY_FROM_DATA,
+       COPY_TO_DATA,
+       COMPARE_TO_DATA,
+       MD5_DIGEST_DATA,
+       SHA1_DIGEST_DATA,
+       SHA2_DIGEST_DATA,
+       GHASH_DATA
+} cmd_type_t;
+
+#define        CRYPTO_DO_UPDATE        0x01
+#define        CRYPTO_DO_FINAL         0x02
+#define        CRYPTO_DO_MD5           0x04
+#define        CRYPTO_DO_SHA1          0x08
+#define        CRYPTO_DO_SIGN          0x10
+#define        CRYPTO_DO_VERIFY        0x20
+#define        CRYPTO_DO_SHA2          0x40
+
+#define        PROVIDER_OWNS_KEY_SCHEDULE      0x00000001
+
+/*
+ * Common cryptographic status and error codes.
+ */
+#define        CRYPTO_SUCCESS                          0x00000000
+#define        CRYPTO_CANCEL                           0x00000001
+#define        CRYPTO_HOST_MEMORY                      0x00000002
+#define        CRYPTO_GENERAL_ERROR                    0x00000003
+#define        CRYPTO_FAILED                           0x00000004
+#define        CRYPTO_ARGUMENTS_BAD                    0x00000005
+#define        CRYPTO_ATTRIBUTE_READ_ONLY              0x00000006
+#define        CRYPTO_ATTRIBUTE_SENSITIVE              0x00000007
+#define        CRYPTO_ATTRIBUTE_TYPE_INVALID           0x00000008
+#define        CRYPTO_ATTRIBUTE_VALUE_INVALID          0x00000009
+#define        CRYPTO_CANCELED                         0x0000000A
+#define        CRYPTO_DATA_INVALID                     0x0000000B
+#define        CRYPTO_DATA_LEN_RANGE                   0x0000000C
+#define        CRYPTO_DEVICE_ERROR                     0x0000000D
+#define        CRYPTO_DEVICE_MEMORY                    0x0000000E
+#define        CRYPTO_DEVICE_REMOVED                   0x0000000F
+#define        CRYPTO_ENCRYPTED_DATA_INVALID           0x00000010
+#define        CRYPTO_ENCRYPTED_DATA_LEN_RANGE         0x00000011
+#define        CRYPTO_KEY_HANDLE_INVALID               0x00000012
+#define        CRYPTO_KEY_SIZE_RANGE                   0x00000013
+#define        CRYPTO_KEY_TYPE_INCONSISTENT            0x00000014
+#define        CRYPTO_KEY_NOT_NEEDED                   0x00000015
+#define        CRYPTO_KEY_CHANGED                      0x00000016
+#define        CRYPTO_KEY_NEEDED                       0x00000017
+#define        CRYPTO_KEY_INDIGESTIBLE                 0x00000018
+#define        CRYPTO_KEY_FUNCTION_NOT_PERMITTED       0x00000019
+#define        CRYPTO_KEY_NOT_WRAPPABLE                0x0000001A
+#define        CRYPTO_KEY_UNEXTRACTABLE                0x0000001B
+#define        CRYPTO_MECHANISM_INVALID                0x0000001C
+#define        CRYPTO_MECHANISM_PARAM_INVALID          0x0000001D
+#define        CRYPTO_OBJECT_HANDLE_INVALID            0x0000001E
+#define        CRYPTO_OPERATION_IS_ACTIVE              0x0000001F
+#define        CRYPTO_OPERATION_NOT_INITIALIZED        0x00000020
+#define        CRYPTO_PIN_INCORRECT                    0x00000021
+#define        CRYPTO_PIN_INVALID                      0x00000022
+#define        CRYPTO_PIN_LEN_RANGE                    0x00000023
+#define        CRYPTO_PIN_EXPIRED                      0x00000024
+#define        CRYPTO_PIN_LOCKED                       0x00000025
+#define        CRYPTO_SESSION_CLOSED                   0x00000026
+#define        CRYPTO_SESSION_COUNT                    0x00000027
+#define        CRYPTO_SESSION_HANDLE_INVALID           0x00000028
+#define        CRYPTO_SESSION_READ_ONLY                0x00000029
+#define        CRYPTO_SESSION_EXISTS                   0x0000002A
+#define        CRYPTO_SESSION_READ_ONLY_EXISTS         0x0000002B
+#define        CRYPTO_SESSION_READ_WRITE_SO_EXISTS     0x0000002C
+#define        CRYPTO_SIGNATURE_INVALID                0x0000002D
+#define        CRYPTO_SIGNATURE_LEN_RANGE              0x0000002E
+#define        CRYPTO_TEMPLATE_INCOMPLETE              0x0000002F
+#define        CRYPTO_TEMPLATE_INCONSISTENT            0x00000030
+#define        CRYPTO_UNWRAPPING_KEY_HANDLE_INVALID    0x00000031
+#define        CRYPTO_UNWRAPPING_KEY_SIZE_RANGE        0x00000032
+#define        CRYPTO_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x00000033
+#define        CRYPTO_USER_ALREADY_LOGGED_IN           0x00000034
+#define        CRYPTO_USER_NOT_LOGGED_IN               0x00000035
+#define        CRYPTO_USER_PIN_NOT_INITIALIZED         0x00000036
+#define        CRYPTO_USER_TYPE_INVALID                0x00000037
+#define        CRYPTO_USER_ANOTHER_ALREADY_LOGGED_IN   0x00000038
+#define        CRYPTO_USER_TOO_MANY_TYPES              0x00000039
+#define        CRYPTO_WRAPPED_KEY_INVALID              0x0000003A
+#define        CRYPTO_WRAPPED_KEY_LEN_RANGE            0x0000003B
+#define        CRYPTO_WRAPPING_KEY_HANDLE_INVALID      0x0000003C
+#define        CRYPTO_WRAPPING_KEY_SIZE_RANGE          0x0000003D
+#define        CRYPTO_WRAPPING_KEY_TYPE_INCONSISTENT   0x0000003E
+#define        CRYPTO_RANDOM_SEED_NOT_SUPPORTED        0x0000003F
+#define        CRYPTO_RANDOM_NO_RNG                    0x00000040
+#define        CRYPTO_DOMAIN_PARAMS_INVALID            0x00000041
+#define        CRYPTO_BUFFER_TOO_SMALL                 0x00000042
+#define        CRYPTO_INFORMATION_SENSITIVE            0x00000043
+#define        CRYPTO_NOT_SUPPORTED                    0x00000044
+
+#define        CRYPTO_QUEUED                           0x00000045
+#define        CRYPTO_BUFFER_TOO_BIG                   0x00000046
+#define        CRYPTO_INVALID_CONTEXT                  0x00000047
+#define        CRYPTO_INVALID_MAC                      0x00000048
+#define        CRYPTO_MECH_NOT_SUPPORTED               0x00000049
+#define        CRYPTO_INCONSISTENT_ATTRIBUTE           0x0000004A
+#define        CRYPTO_NO_PERMISSION                    0x0000004B
+#define        CRYPTO_INVALID_PROVIDER_ID              0x0000004C
+#define        CRYPTO_VERSION_MISMATCH                 0x0000004D
+#define        CRYPTO_BUSY                             0x0000004E
+#define        CRYPTO_UNKNOWN_PROVIDER                 0x0000004F
+#define        CRYPTO_MODVERIFICATION_FAILED           0x00000050
+#define        CRYPTO_OLD_CTX_TEMPLATE                 0x00000051
+#define        CRYPTO_WEAK_KEY                         0x00000052
+#define        CRYPTO_FIPS140_ERROR                    0x00000053
+/*
+ * Don't forget to update CRYPTO_LAST_ERROR and the error_number_table[]
+ * in kernelUtil.c when new error code is added.
+ */
+#define        CRYPTO_LAST_ERROR                       0x00000053
+
+/*
+ * Special values that can be used to indicate that information is unavailable
+ * or that there is not practical limit. These values can be used
+ * by fields of the SPI crypto_provider_ext_info(9S) structure.
+ * The value of CRYPTO_UNAVAILABLE_INFO should be the same as
+ * CK_UNAVAILABLE_INFO in the PKCS#11 spec.
+ */
+#define        CRYPTO_UNAVAILABLE_INFO         ((ulong_t)(-1))
+#define        CRYPTO_EFFECTIVELY_INFINITE     0x0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_COMMON_H */
diff --git a/zfs/include/sys/crypto/icp.h b/zfs/include/sys/crypto/icp.h
new file mode 100644 (file)
index 0000000..d8948e0
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 (c) 2016, Datto, Inc. All rights reserved.
+ */
+
+#ifndef        _SYS_CRYPTO_ALGS_H
+#define        _SYS_CRYPTO_ALGS_H
+
+int aes_mod_init(void);
+int aes_mod_fini(void);
+
+int edonr_mod_init(void);
+int edonr_mod_fini(void);
+
+int sha1_mod_init(void);
+int sha1_mod_fini(void);
+
+int sha2_mod_init(void);
+int sha2_mod_fini(void);
+
+int skein_mod_init(void);
+int skein_mod_fini(void);
+
+int icp_init(void);
+void icp_fini(void);
+
+#endif /* _SYS_CRYPTO_ALGS_H */
index 0d262e87b5bc9fca09073783719b75eab25a83c5..6262f012e7ab64a498ce7340c0355faa3f919e2e 100644 (file)
@@ -36,6 +36,7 @@
 #include <sys/zfs_context.h>
 #include <sys/refcount.h>
 #include <sys/zrlock.h>
+#include <sys/multilist.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -121,6 +122,9 @@ typedef struct dbuf_dirty_record {
        /* How much space was changed to dsl_pool_dirty_space() for this? */
        unsigned int dr_accounted;
 
+       /* A copy of the bp that points to us */
+       blkptr_t dr_bp_copy;
+
        union dirty_types {
                struct dirty_indirect {
 
@@ -225,6 +229,11 @@ typedef struct dmu_buf_impl {
         */
        avl_node_t db_link;
 
+       /*
+        * Link in dbuf_cache.
+        */
+       multilist_node_t db_cache_link;
+
        /* Data which is unique to data (leaf) blocks: */
 
        /* User callback information. */
@@ -261,8 +270,8 @@ typedef struct dbuf_hash_table {
        kmutex_t hash_mutexes[DBUF_MUTEXES];
 } dbuf_hash_table_t;
 
-
-uint64_t dbuf_whichblock(struct dnode *di, uint64_t offset);
+uint64_t dbuf_whichblock(const struct dnode *di, const int64_t level,
+    const uint64_t offset);
 
 void dbuf_create_bonus(struct dnode *dn);
 int dbuf_spill_set_blksz(dmu_buf_t *db, uint64_t blksz, dmu_tx_t *tx);
@@ -272,10 +281,12 @@ void dbuf_rm_spill(struct dnode *dn, dmu_tx_t *tx);
 dmu_buf_impl_t *dbuf_hold(struct dnode *dn, uint64_t blkid, void *tag);
 dmu_buf_impl_t *dbuf_hold_level(struct dnode *dn, int level, uint64_t blkid,
     void *tag);
-int dbuf_hold_impl(struct dnode *dn, uint8_t level, uint64_t blkid, int create,
+int dbuf_hold_impl(struct dnode *dn, uint8_t level, uint64_t blkid,
+    boolean_t fail_sparse, boolean_t fail_uncached,
     void *tag, dmu_buf_impl_t **dbp);
 
-void dbuf_prefetch(struct dnode *dn, uint64_t blkid, zio_priority_t prio);
+void dbuf_prefetch(struct dnode *dn, int64_t level, uint64_t blkid,
+    zio_priority_t prio, arc_flags_t aflags);
 
 void dbuf_add_ref(dmu_buf_impl_t *db, void *tag);
 boolean_t dbuf_try_add_ref(dmu_buf_t *db, objset_t *os, uint64_t obj,
@@ -299,8 +310,7 @@ void dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data,
     bp_embedded_type_t etype, enum zio_compress comp,
     int uncompressed_size, int compressed_size, int byteorder, dmu_tx_t *tx);
 
-void dbuf_clear(dmu_buf_impl_t *db);
-void dbuf_evict(dmu_buf_impl_t *db);
+void dbuf_destroy(dmu_buf_impl_t *db);
 
 void dbuf_unoverride(dbuf_dirty_record_t *dr);
 void dbuf_sync_list(list_t *list, int level, dmu_tx_t *tx);
@@ -338,10 +348,6 @@ boolean_t dbuf_is_metadata(dmu_buf_impl_t *db);
        (dbuf_is_metadata(_db) &&                                       \
        ((_db)->db_objset->os_secondary_cache == ZFS_CACHE_METADATA)))
 
-#define        DBUF_IS_L2COMPRESSIBLE(_db)                                     \
-       ((_db)->db_objset->os_compress != ZIO_COMPRESS_OFF ||           \
-       (dbuf_is_metadata(_db) && zfs_mdcomp_disable == B_FALSE))
-
 #ifdef ZFS_DEBUG
 
 /*
index d9434db463831df9b04f2e4214c07cc084e01732..9d61d94ee02b7e26669a6af9f6e962b15a3a06b6 100644 (file)
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  * Copyright 2014 HybridCluster. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -44,6 +45,8 @@
 #include <sys/inttypes.h>
 #include <sys/cred.h>
 #include <sys/fs/zfs.h>
+#include <sys/zio_compress.h>
+#include <sys/zio_priority.h>
 #include <sys/uio.h>
 
 #ifdef __cplusplus
@@ -72,6 +75,7 @@ struct sa_handle;
 typedef struct objset objset_t;
 typedef struct dmu_tx dmu_tx_t;
 typedef struct dsl_dir dsl_dir_t;
+typedef struct dnode dnode_t;
 
 typedef enum dmu_object_byteswap {
        DMU_BSWAP_UINT8,
@@ -252,6 +256,12 @@ void zfs_znode_byteswap(void *buf, size_t size);
 #define        DMU_USERUSED_OBJECT     (-1ULL)
 #define        DMU_GROUPUSED_OBJECT    (-2ULL)
 
+/*
+ * Zap prefix for object accounting in DMU_{USER,GROUP}USED_OBJECT.
+ */
+#define        DMU_OBJACCT_PREFIX      "obj-"
+#define        DMU_OBJACCT_PREFIX_LEN  4
+
 /*
  * artificial blkids for bonus buffer and spill blocks
  */
@@ -314,6 +324,8 @@ typedef struct dmu_buf {
 #define        DMU_POOL_FREE_BPOBJ             "free_bpobj"
 #define        DMU_POOL_BPTREE_OBJ             "bptree_obj"
 #define        DMU_POOL_EMPTY_BPOBJ            "empty_bpobj"
+#define        DMU_POOL_CHECKSUM_SALT          "org.illumos:checksum_salt"
+#define        DMU_POOL_VDEV_ZAP_MAP           "com.delphix:vdev_zap_map"
 
 /*
  * Allocate an object from this objset.  The range of object numbers
@@ -332,10 +344,19 @@ typedef struct dmu_buf {
  */
 uint64_t dmu_object_alloc(objset_t *os, dmu_object_type_t ot,
     int blocksize, dmu_object_type_t bonus_type, int bonus_len, dmu_tx_t *tx);
+uint64_t dmu_object_alloc_dnsize(objset_t *os, dmu_object_type_t ot,
+    int blocksize, dmu_object_type_t bonus_type, int bonus_len,
+    int dnodesize, dmu_tx_t *tx);
 int dmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot,
     int blocksize, dmu_object_type_t bonus_type, int bonus_len, dmu_tx_t *tx);
+int dmu_object_claim_dnsize(objset_t *os, uint64_t object, dmu_object_type_t ot,
+    int blocksize, dmu_object_type_t bonus_type, int bonus_len,
+    int dnodesize, dmu_tx_t *tx);
 int dmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot,
     int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *txp);
+int dmu_object_reclaim_dnsize(objset_t *os, uint64_t object,
+    dmu_object_type_t ot, int blocksize, dmu_object_type_t bonustype,
+    int bonuslen, int dnodesize, dmu_tx_t *txp);
 
 /*
  * Free an object from this objset.
@@ -410,7 +431,7 @@ dmu_write_embedded(objset_t *os, uint64_t object, uint64_t offset,
 #define        WP_SPILL        0x4
 
 void dmu_write_policy(objset_t *os, struct dnode *dn, int level, int wp,
-    struct zio_prop *zp);
+    enum zio_compress compress_override, struct zio_prop *zp);
 /*
  * The bonus data is accessed more or less like a regular buffer.
  * You must dmu_bonus_hold() to get the buffer, which will give you a
@@ -435,7 +456,7 @@ int dmu_rm_spill(objset_t *, uint64_t, dmu_tx_t *);
  */
 
 int dmu_spill_hold_by_bonus(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp);
-int dmu_spill_hold_by_dnode(struct dnode *dn, uint32_t flags,
+int dmu_spill_hold_by_dnode(dnode_t *dn, uint32_t flags,
     void *tag, dmu_buf_t **dbp);
 int dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp);
 
@@ -455,6 +476,8 @@ int dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp);
  */
 int dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset,
     void *tag, dmu_buf_t **, int flags);
+int dmu_buf_hold_by_dnode(dnode_t *dn, uint64_t offset,
+    void *tag, dmu_buf_t **dbp, int flags);
 
 /*
  * Add a reference to a dmu buffer that has already been held via
@@ -486,7 +509,8 @@ uint64_t dmu_buf_refcount(dmu_buf_t *db);
  * individually with dmu_buf_rele.
  */
 int dmu_buf_hold_array_by_bonus(dmu_buf_t *db, uint64_t offset,
-    uint64_t length, int read, void *tag, int *numbufsp, dmu_buf_t ***dbpp);
+    uint64_t length, boolean_t read, void *tag,
+    int *numbufsp, dmu_buf_t ***dbpp);
 void dmu_buf_rele_array(dmu_buf_t **, int numbufs, void *tag);
 
 typedef void dmu_buf_evict_func_t(void *user_ptr);
@@ -546,12 +570,7 @@ typedef struct dmu_buf_user {
  * NOTE: This function should only be called once on a given dmu_buf_user_t.
  *       To allow enforcement of this, dbu must already be zeroed on entry.
  */
-#ifdef __lint
-/* Very ugly, but it beats issuing suppression directives in many Makefiles. */
-extern void
-dmu_buf_init_user(dmu_buf_user_t *dbu, dmu_buf_evict_func_t *evict_func,
-    dmu_buf_t **clear_on_evict_dbufp);
-#else /* __lint */
+/*ARGSUSED*/
 static inline void
 dmu_buf_init_user(dmu_buf_user_t *dbu, dmu_buf_evict_func_t *evict_func,
     dmu_buf_t **clear_on_evict_dbufp)
@@ -564,7 +583,6 @@ dmu_buf_init_user(dmu_buf_user_t *dbu, dmu_buf_evict_func_t *evict_func,
        dbu->dbu_clear_on_evict_dbufp = clear_on_evict_dbufp;
 #endif
 }
-#endif /* __lint */
 
 /*
  * Attach user data to a dbuf and mark it for normal (when the dbuf's
@@ -607,6 +625,10 @@ void *dmu_buf_remove_user(dmu_buf_t *db, dmu_buf_user_t *user);
  */
 void *dmu_buf_get_user(dmu_buf_t *db);
 
+objset_t *dmu_buf_get_objset(dmu_buf_t *db);
+dnode_t *dmu_buf_dnode_enter(dmu_buf_t *db);
+void dmu_buf_dnode_exit(dmu_buf_t *db);
+
 /* Block until any in-progress dmu buf user evictions complete. */
 void dmu_buf_user_evict_wait(void);
 
@@ -663,6 +685,7 @@ void dmu_tx_abort(dmu_tx_t *tx);
 int dmu_tx_assign(dmu_tx_t *tx, enum txg_how txg_how);
 void dmu_tx_wait(dmu_tx_t *tx);
 void dmu_tx_commit(dmu_tx_t *tx);
+void dmu_tx_mark_netfree(dmu_tx_t *tx);
 
 /*
  * To register a commit callback, dmu_tx_callback_register() must be called.
@@ -710,9 +733,6 @@ void dmu_prealloc(objset_t *os, uint64_t object, uint64_t offset, uint64_t size,
        dmu_tx_t *tx);
 #ifdef _KERNEL
 #include <linux/blkdev_compat.h>
-int dmu_read_bio(objset_t *os, uint64_t object, struct bio *bio);
-int dmu_write_bio(objset_t *os, uint64_t object, struct bio *bio,
-       dmu_tx_t *tx);
 int dmu_read_uio(objset_t *os, uint64_t object, struct uio *uio, uint64_t size);
 int dmu_read_uio_dbuf(dmu_buf_t *zdb, struct uio *uio, uint64_t size);
 int dmu_write_uio(objset_t *os, uint64_t object, struct uio *uio, uint64_t size,
@@ -724,6 +744,7 @@ struct arc_buf *dmu_request_arcbuf(dmu_buf_t *handle, int size);
 void dmu_return_arcbuf(struct arc_buf *buf);
 void dmu_assign_arcbuf(dmu_buf_t *handle, uint64_t offset, struct arc_buf *buf,
     dmu_tx_t *tx);
+#ifdef HAVE_UIO_ZEROCOPY
 int dmu_xuio_init(struct xuio *uio, int niov);
 void dmu_xuio_fini(struct xuio *uio);
 int dmu_xuio_add(struct xuio *uio, struct arc_buf *abuf, offset_t off,
@@ -731,6 +752,7 @@ int dmu_xuio_add(struct xuio *uio, struct arc_buf *abuf, offset_t off,
 int dmu_xuio_cnt(struct xuio *uio);
 struct arc_buf *dmu_xuio_arcbuf(struct xuio *uio, int i);
 void dmu_xuio_clear(struct xuio *uio, int i);
+#endif /* HAVE_UIO_ZEROCOPY */
 void xuio_stat_wbuf_copied(void);
 void xuio_stat_wbuf_nocopy(void);
 
@@ -740,8 +762,8 @@ extern int zfs_max_recordsize;
 /*
  * Asynchronously try to read in the data.
  */
-void dmu_prefetch(objset_t *os, uint64_t object, uint64_t offset,
-    uint64_t len);
+void dmu_prefetch(objset_t *os, uint64_t object, int64_t level, uint64_t offset,
+       uint64_t len, enum zio_priority pri);
 
 typedef struct dmu_object_info {
        /* All sizes are in bytes unless otherwise indicated. */
@@ -755,6 +777,7 @@ typedef struct dmu_object_info {
        uint8_t doi_compress;
        uint8_t doi_nblkptr;
        uint8_t doi_pad[4];
+       uint64_t doi_dnodesize;
        uint64_t doi_physical_blocks_512;       /* data + metadata, 512b blks */
        uint64_t doi_max_offset;
        uint64_t doi_fill_count;                /* number of non-empty blocks */
@@ -786,7 +809,7 @@ extern const dmu_object_byteswap_info_t dmu_ot_byteswap[DMU_BSWAP_NUMFUNCS];
 int dmu_object_info(objset_t *os, uint64_t object, dmu_object_info_t *doi);
 void __dmu_object_info_from_dnode(struct dnode *dn, dmu_object_info_t *doi);
 /* Like dmu_object_info, but faster if you have a held dnode in hand. */
-void dmu_object_info_from_dnode(struct dnode *dn, dmu_object_info_t *doi);
+void dmu_object_info_from_dnode(dnode_t *dn, dmu_object_info_t *doi);
 /* Like dmu_object_info, but faster if you have a held dbuf in hand. */
 void dmu_object_info_from_db(dmu_buf_t *db, dmu_object_info_t *doi);
 /*
@@ -796,6 +819,8 @@ void dmu_object_info_from_db(dmu_buf_t *db, dmu_object_info_t *doi);
 void dmu_object_size_from_db(dmu_buf_t *db, uint32_t *blksize,
     u_longlong_t *nblk512);
 
+void dmu_object_dnsize_from_db(dmu_buf_t *db, int *dnsize);
+
 typedef struct dmu_objset_stats {
        uint64_t dds_num_clones; /* number of clones of this */
        uint64_t dds_creation_txg;
@@ -803,7 +828,7 @@ typedef struct dmu_objset_stats {
        dmu_objset_type_t dds_type;
        uint8_t dds_is_snapshot;
        uint8_t dds_inconsistent;
-       char dds_origin[MAXNAMELEN];
+       char dds_origin[ZFS_MAX_DATASET_NAME_LEN];
 } dmu_objset_stats_t;
 
 /*
@@ -853,6 +878,7 @@ extern struct dsl_dataset *dmu_objset_ds(objset_t *os);
 extern void dmu_objset_name(objset_t *os, char *buf);
 extern dmu_objset_type_t dmu_objset_type(objset_t *os);
 extern uint64_t dmu_objset_id(objset_t *os);
+extern uint64_t dmu_objset_dnodesize(objset_t *os);
 extern zfs_sync_type_t dmu_objset_syncprop(objset_t *os);
 extern zfs_logbias_op_t dmu_objset_logbias(objset_t *os);
 extern int dmu_snapshot_list_next(objset_t *os, int namelen, char *name,
index 75d094f0812e9769bd3afe3202d4a6a17026f1fb..ae129b7cfa7f4458eaea08dc0f0b3d258634ff85 100644 (file)
@@ -24,7 +24,7 @@
  */
 /*
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  */
 
 #ifndef _SYS_DMU_IMPL_H
@@ -268,10 +268,13 @@ typedef struct dmu_sendarg {
        uint64_t dsa_toguid;
        int dsa_err;
        dmu_pendop_t dsa_pending_op;
-       boolean_t dsa_incremental;
        uint64_t dsa_featureflags;
        uint64_t dsa_last_data_object;
        uint64_t dsa_last_data_offset;
+       uint64_t dsa_resume_object;
+       uint64_t dsa_resume_offset;
+       boolean_t dsa_sent_begin;
+       boolean_t dsa_sent_end;
 } dmu_sendarg_t;
 
 void dmu_object_zapify(objset_t *, uint64_t, dmu_object_type_t, dmu_tx_t *);
index 837a0d5107b7f1aa636445a0ec1ebb281bd6167a..2ec1ec87d87f42e1dc8421ab0a312d139fc96275 100644 (file)
@@ -56,6 +56,7 @@ struct dmu_tx;
        (arc_buf_size(buf) > OBJSET_OLD_PHYS_SIZE)
 
 #define        OBJSET_FLAG_USERACCOUNTING_COMPLETE     (1ULL<<0)
+#define        OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE  (1ULL<<1)
 
 typedef struct objset_phys {
        dnode_phys_t os_meta_dnode;
@@ -68,6 +69,8 @@ typedef struct objset_phys {
        dnode_phys_t os_groupused_dnode;
 } objset_phys_t;
 
+typedef int (*dmu_objset_upgrade_cb_t)(objset_t *);
+
 struct objset {
        /* Immutable: */
        struct dsl_dataset *os_dsl_dataset;
@@ -88,6 +91,7 @@ struct objset {
        list_node_t os_evicting_node;
 
        /* can change, under dsl_dir's locks: */
+       uint64_t os_dnodesize; /* default dnode size for new objects */
        enum zio_checksum os_checksum;
        enum zio_compress os_compress;
        uint8_t os_copies;
@@ -106,6 +110,8 @@ struct objset {
        zil_header_t os_zil_header;
        list_t os_synced_dnodes;
        uint64_t os_flags;
+       uint64_t os_freed_dnodes;
+       boolean_t os_rescan_dnodes;
 
        /* Protected by os_obj_lock */
        kmutex_t os_obj_lock;
@@ -122,6 +128,13 @@ struct objset {
        kmutex_t os_user_ptr_lock;
        void *os_user_ptr;
        sa_os_t *os_sa;
+
+       /* kernel thread to upgrade this dataset */
+       kmutex_t os_upgrade_lock;
+       taskqid_t os_upgrade_id;
+       dmu_objset_upgrade_cb_t os_upgrade_cb;
+       boolean_t os_upgrade_exit;
+       int os_upgrade_status;
 };
 
 #define        DMU_META_OBJSET         0
@@ -135,8 +148,6 @@ struct objset {
        ((os)->os_secondary_cache == ZFS_CACHE_ALL ||           \
        (os)->os_secondary_cache == ZFS_CACHE_METADATA)
 
-#define        DMU_OS_IS_L2COMPRESSIBLE(os)    (zfs_mdcomp_disable == B_FALSE)
-
 /* called from zpl */
 int dmu_objset_hold(const char *name, void *tag, objset_t **osp);
 int dmu_objset_own(const char *name, dmu_objset_type_t type,
@@ -172,6 +183,18 @@ void dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx);
 boolean_t dmu_objset_userused_enabled(objset_t *os);
 int dmu_objset_userspace_upgrade(objset_t *os);
 boolean_t dmu_objset_userspace_present(objset_t *os);
+boolean_t dmu_objset_userobjused_enabled(objset_t *os);
+void dmu_objset_userobjspace_upgrade(objset_t *os);
+boolean_t dmu_objset_userobjspace_present(objset_t *os);
+
+static inline boolean_t dmu_objset_userobjspace_upgradable(objset_t *os)
+{
+       return (dmu_objset_type(os) == DMU_OST_ZFS &&
+           !dmu_objset_is_snapshot(os) &&
+           dmu_objset_userobjused_enabled(os) &&
+           !dmu_objset_userobjspace_present(os));
+}
+
 int dmu_fsname(const char *snapname, char *buf);
 
 void dmu_objset_evict_done(objset_t *os);
index 2442a1f8aab10b86a5eff4d89e02f1f3db4bb4b9..e9bef8bddb736e7bcdc9b0f0d9c26ffadb3c6570 100644 (file)
@@ -36,26 +36,31 @@ struct vnode;
 struct dsl_dataset;
 struct drr_begin;
 struct avl_tree;
+struct dmu_replay_record;
 
-int dmu_send(const char *tosnap, const char *fromsnap,
-    boolean_t embedok, boolean_t large_block_ok,
-    int outfd, struct vnode *vp, offset_t *off);
+extern const char *recv_clone_name;
+
+int dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
+    boolean_t large_block_ok, boolean_t compressok, int outfd,
+    uint64_t resumeobj, uint64_t resumeoff, struct vnode *vp, offset_t *off);
 int dmu_send_estimate(struct dsl_dataset *ds, struct dsl_dataset *fromds,
-    uint64_t *sizep);
+    boolean_t stream_compressed, uint64_t *sizep);
 int dmu_send_estimate_from_txg(struct dsl_dataset *ds, uint64_t fromtxg,
-    uint64_t *sizep);
+    boolean_t stream_compressed, uint64_t *sizep);
 int dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
-    boolean_t embedok, boolean_t large_block_ok,
+    boolean_t embedok, boolean_t large_block_ok, boolean_t compressok,
     int outfd, struct vnode *vp, offset_t *off);
 
 typedef struct dmu_recv_cookie {
        struct dsl_dataset *drc_ds;
+       struct dmu_replay_record *drc_drr_begin;
        struct drr_begin *drc_drrb;
        const char *drc_tofs;
        const char *drc_tosnap;
        boolean_t drc_newfs;
        boolean_t drc_byteswap;
        boolean_t drc_force;
+       boolean_t drc_resumable;
        struct avl_tree *drc_guid_to_ds_map;
        zio_cksum_t drc_cksum;
        uint64_t drc_newsnapobj;
@@ -63,8 +68,9 @@ typedef struct dmu_recv_cookie {
        cred_t *drc_cred;
 } dmu_recv_cookie_t;
 
-int dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
-    boolean_t force, char *origin, dmu_recv_cookie_t *drc);
+int dmu_recv_begin(char *tofs, char *tosnap,
+    struct dmu_replay_record *drr_begin,
+    boolean_t force, boolean_t resumable, char *origin, dmu_recv_cookie_t *drc);
 int dmu_recv_stream(dmu_recv_cookie_t *drc, struct vnode *vp, offset_t *voffp,
     int cleanup_fd, uint64_t *action_handlep);
 int dmu_recv_end(dmu_recv_cookie_t *drc, void *owner);
index 544b721e46129a06f5bc3d86ec8e9c3e6d685be1..c010edd440d95f974ba584be09365c672394ecbd 100644 (file)
@@ -54,6 +54,8 @@ typedef int (blkptr_cb_t)(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
 
 int traverse_dataset(struct dsl_dataset *ds,
     uint64_t txg_start, int flags, blkptr_cb_t func, void *arg);
+int traverse_dataset_resume(struct dsl_dataset *ds, uint64_t txg_start,
+    zbookmark_phys_t *resume, int flags, blkptr_cb_t func, void *arg);
 int traverse_dataset_destroyed(spa_t *spa, blkptr_t *blkptr,
     uint64_t txg_start, zbookmark_phys_t *resume, int flags,
     blkptr_cb_t func, void *arg);
index 38ed1d8721290db19719d2fd6ad0fe00e178db81..8125d07062398c6865747deba4ebdeec126894b2 100644 (file)
  * Use is subject to license terms.
  */
 
-#ifndef        _DFETCH_H
-#define        _DFETCH_H
+/*
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+#ifndef        _DMU_ZFETCH_H
+#define        _DMU_ZFETCH_H
 
 #include <sys/zfs_context.h>
 
@@ -36,41 +40,37 @@ extern unsigned long        zfetch_array_rd_sz;
 
 struct dnode;                          /* so we can reference dnode */
 
-typedef enum zfetch_dirn {
-       ZFETCH_FORWARD = 1,             /* prefetch increasing block numbers */
-       ZFETCH_BACKWARD = -1            /* prefetch decreasing block numbers */
-} zfetch_dirn_t;
-
 typedef struct zstream {
-       uint64_t        zst_offset;     /* offset of starting block in range */
-       uint64_t        zst_len;        /* length of range, in blocks */
-       zfetch_dirn_t   zst_direction;  /* direction of prefetch */
-       uint64_t        zst_stride;     /* length of stride, in blocks */
-       uint64_t        zst_ph_offset;  /* prefetch offset, in blocks */
-       uint64_t        zst_cap;        /* prefetch limit (cap), in blocks */
-       kmutex_t        zst_lock;       /* protects stream */
-       clock_t         zst_last;       /* lbolt of last prefetch */
-       list_node_t     zst_node;       /* next zstream here */
+       uint64_t        zs_blkid;       /* expect next access at this blkid */
+       uint64_t        zs_pf_blkid;    /* next block to prefetch */
+
+       /*
+        * We will next prefetch the L1 indirect block of this level-0
+        * block id.
+        */
+       uint64_t        zs_ipf_blkid;
+
+       kmutex_t        zs_lock;        /* protects stream */
+       hrtime_t        zs_atime;       /* time last prefetch issued */
+       list_node_t     zs_node;        /* link for zf_stream */
 } zstream_t;
 
 typedef struct zfetch {
        krwlock_t       zf_rwlock;      /* protects zfetch structure */
-       list_t          zf_stream;      /* AVL tree of zstream_t's */
+       list_t          zf_stream;      /* list of zstream_t's */
        struct dnode    *zf_dnode;      /* dnode that owns this zfetch */
-       uint32_t        zf_stream_cnt;  /* # of active streams */
-       uint64_t        zf_alloc_fail;  /* # of failed attempts to alloc strm */
 } zfetch_t;
 
 void           zfetch_init(void);
 void           zfetch_fini(void);
 
 void           dmu_zfetch_init(zfetch_t *, struct dnode *);
-void           dmu_zfetch_rele(zfetch_t *);
-void           dmu_zfetch(zfetch_t *, uint64_t, uint64_t, int);
+void           dmu_zfetch_fini(zfetch_t *);
+void           dmu_zfetch(zfetch_t *, uint64_t, uint64_t, boolean_t);
 
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* _DFETCH_H */
+#endif /* _DMU_ZFETCH_H */
index 50e01155903aa3e2b7b1be879dd31e62ddcba5e6..fe4cd3e4bf375338dde06a181dc5531b7ce1c34f 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
 
@@ -57,7 +57,13 @@ extern "C" {
  * Fixed constants.
  */
 #define        DNODE_SHIFT             9       /* 512 bytes */
-#define        DN_MIN_INDBLKSHIFT      10      /* 1k */
+#define        DN_MIN_INDBLKSHIFT      12      /* 4k */
+/*
+ * If we ever increase this value beyond 20, we need to revisit all logic that
+ * does x << level * ebps to handle overflow.  With a 1M indirect block size,
+ * 4 levels of indirect blocks would not be able to guarantee addressing an
+ * entire object, so 5 levels will be used, but 5 * (20 - 7) = 65.
+ */
 #define        DN_MAX_INDBLKSHIFT      14      /* 16k */
 #define        DNODE_BLOCK_SHIFT       14      /* 16k */
 #define        DNODE_CORE_SIZE         64      /* 64 bytes for dnode sans blkptrs */
@@ -79,11 +85,18 @@ extern "C" {
 /*
  * Derived constants.
  */
-#define        DNODE_SIZE      (1 << DNODE_SHIFT)
-#define        DN_MAX_NBLKPTR  ((DNODE_SIZE - DNODE_CORE_SIZE) >> SPA_BLKPTRSHIFT)
-#define        DN_MAX_BONUSLEN (DNODE_SIZE - DNODE_CORE_SIZE - (1 << SPA_BLKPTRSHIFT))
+#define        DNODE_MIN_SIZE          (1 << DNODE_SHIFT)
+#define        DNODE_MAX_SIZE          (1 << DNODE_BLOCK_SHIFT)
+#define        DNODE_BLOCK_SIZE        (1 << DNODE_BLOCK_SHIFT)
+#define        DNODE_MIN_SLOTS         (DNODE_MIN_SIZE >> DNODE_SHIFT)
+#define        DNODE_MAX_SLOTS         (DNODE_MAX_SIZE >> DNODE_SHIFT)
+#define        DN_BONUS_SIZE(dnsize)   ((dnsize) - DNODE_CORE_SIZE - \
+       (1 << SPA_BLKPTRSHIFT))
+#define        DN_SLOTS_TO_BONUSLEN(slots)     DN_BONUS_SIZE((slots) << DNODE_SHIFT)
+#define        DN_OLD_MAX_BONUSLEN     (DN_BONUS_SIZE(DNODE_MIN_SIZE))
+#define        DN_MAX_NBLKPTR  ((DNODE_MIN_SIZE - DNODE_CORE_SIZE) >> SPA_BLKPTRSHIFT)
 #define        DN_MAX_OBJECT   (1ULL << DN_MAX_OBJECT_SHIFT)
-#define        DN_ZERO_BONUSLEN        (DN_MAX_BONUSLEN + 1)
+#define        DN_ZERO_BONUSLEN        (DN_BONUS_SIZE(DNODE_MAX_SIZE) + 1)
 #define        DN_KILL_SPILLBLK (1)
 
 #define        DNODES_PER_BLOCK_SHIFT  (DNODE_BLOCK_SHIFT - DNODE_SHIFT)
@@ -91,9 +104,8 @@ extern "C" {
 #define        DNODES_PER_LEVEL_SHIFT  (DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT)
 #define        DNODES_PER_LEVEL        (1ULL << DNODES_PER_LEVEL_SHIFT)
 
-/* The +2 here is a cheesy way to round up */
-#define        DN_MAX_LEVELS   (2 + ((DN_MAX_OFFSET_SHIFT - SPA_MINBLOCKSHIFT) / \
-       (DN_MIN_INDBLKSHIFT - SPA_BLKPTRSHIFT)))
+#define        DN_MAX_LEVELS   (DIV_ROUND_UP(DN_MAX_OFFSET_SHIFT - SPA_MINBLOCKSHIFT, \
+       DN_MIN_INDBLKSHIFT - SPA_BLKPTRSHIFT) + 1)
 
 #define        DN_BONUS(dnp)   ((void*)((dnp)->dn_bonus + \
        (((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t))))
@@ -114,11 +126,14 @@ enum dnode_dirtycontext {
 };
 
 /* Is dn_used in bytes?  if not, it's in multiples of SPA_MINBLOCKSIZE */
-#define        DNODE_FLAG_USED_BYTES           (1<<0)
-#define        DNODE_FLAG_USERUSED_ACCOUNTED   (1<<1)
+#define        DNODE_FLAG_USED_BYTES                   (1 << 0)
+#define        DNODE_FLAG_USERUSED_ACCOUNTED           (1 << 1)
 
 /* Does dnode have a SA spill blkptr in bonus? */
-#define        DNODE_FLAG_SPILL_BLKPTR (1<<2)
+#define        DNODE_FLAG_SPILL_BLKPTR                 (1 << 2)
+
+/* User/Group dnode accounting */
+#define        DNODE_FLAG_USEROBJUSED_ACCOUNTED        (1 << 3)
 
 typedef struct dnode_phys {
        uint8_t dn_type;                /* dmu_object_type_t */
@@ -131,7 +146,8 @@ typedef struct dnode_phys {
        uint8_t dn_flags;               /* DNODE_FLAG_* */
        uint16_t dn_datablkszsec;       /* data block size in 512b sectors */
        uint16_t dn_bonuslen;           /* length of dn_bonus */
-       uint8_t dn_pad2[4];
+       uint8_t dn_extra_slots;         /* # of subsequent slots consumed */
+       uint8_t dn_pad2[3];
 
        /* accounting is protected by dn_dirty_mtx */
        uint64_t dn_maxblkid;           /* largest allocated block ID */
@@ -140,8 +156,11 @@ typedef struct dnode_phys {
        uint64_t dn_pad3[4];
 
        /*
-        * The tail region is 448 bytes, and there are three ways to
-        * look at it.
+        * The tail region is 448 bytes for a 512 byte dnode, and
+        * correspondingly larger for larger dnode sizes. The spill
+        * block pointer, when present, is always at the end of the tail
+        * region. There are three ways this space may be used, using
+        * a 512 byte dnode for this diagram:
         *
         * 0       64      128     192     256     320     384     448 (offset)
         * +---------------+---------------+---------------+-------+
@@ -149,24 +168,28 @@ typedef struct dnode_phys {
         * +---------------+---------------+---------------+-------+
         * | dn_blkptr[0]  | dn_bonus[0..319]                      |
         * +---------------+-----------------------+---------------+
-        * | dn_blkptr[0]  | /                     | dn_spill      |
+        * | dn_blkptr[0]  | dn_bonus[0..191]      | dn_spill      |
         * +---------------+-----------------------+---------------+
         */
        union {
-               blkptr_t dn_blkptr[1+DN_MAX_BONUSLEN/sizeof (blkptr_t)];
+               blkptr_t dn_blkptr[1+DN_OLD_MAX_BONUSLEN/sizeof (blkptr_t)];
                struct {
                        blkptr_t __dn_ignore1;
-                       uint8_t dn_bonus[DN_MAX_BONUSLEN];
+                       uint8_t dn_bonus[DN_OLD_MAX_BONUSLEN];
                };
                struct {
                        blkptr_t __dn_ignore2;
-                       uint8_t __dn_ignore3[DN_MAX_BONUSLEN-sizeof (blkptr_t)];
+                       uint8_t __dn_ignore3[DN_OLD_MAX_BONUSLEN -
+                           sizeof (blkptr_t)];
                        blkptr_t dn_spill;
                };
        };
 } dnode_phys_t;
 
-typedef struct dnode {
+#define        DN_SPILL_BLKPTR(dnp)    (blkptr_t *)((char *)(dnp) + \
+       (((dnp)->dn_extra_slots + 1) << DNODE_SHIFT) - (1 << SPA_BLKPTRSHIFT))
+
+struct dnode {
        /*
         * Protects the structure of the dnode, including the number of levels
         * of indirection (dn_nlevels), dn_maxblkid, and dn_next_*
@@ -202,6 +225,7 @@ typedef struct dnode {
        uint32_t dn_datablksz;          /* in bytes */
        uint64_t dn_maxblkid;
        uint8_t dn_next_type[TXG_SIZE];
+       uint8_t dn_num_slots;           /* metadnode slots consumed on disk */
        uint8_t dn_next_nblkptr[TXG_SIZE];
        uint8_t dn_next_nlevels[TXG_SIZE];
        uint8_t dn_next_indblkshift[TXG_SIZE];
@@ -264,7 +288,7 @@ typedef struct dnode {
 
        /* holds prefetch structure */
        struct zfetch   dn_zfetch;
-} dnode_t;
+};
 
 /*
  * Adds a level of indirection between the dbuf and the dnode to avoid
@@ -299,7 +323,7 @@ void dnode_rm_spill(dnode_t *dn, dmu_tx_t *tx);
 
 int dnode_hold(struct objset *dd, uint64_t object,
     void *ref, dnode_t **dnp);
-int dnode_hold_impl(struct objset *dd, uint64_t object, int flag,
+int dnode_hold_impl(struct objset *dd, uint64_t object, int flag, int dn_slots,
     void *ref, dnode_t **dnp);
 boolean_t dnode_add_ref(dnode_t *dn, void *ref);
 void dnode_rele(dnode_t *dn, void *ref);
@@ -307,9 +331,9 @@ void dnode_rele_and_unlock(dnode_t *dn, void *tag);
 void dnode_setdirty(dnode_t *dn, dmu_tx_t *tx);
 void dnode_sync(dnode_t *dn, dmu_tx_t *tx);
 void dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
-    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+    dmu_object_type_t bonustype, int bonuslen, int dn_slots, dmu_tx_t *tx);
 void dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
-    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+    dmu_object_type_t bonustype, int bonuslen, int dn_slots, dmu_tx_t *tx);
 void dnode_free(dnode_t *dn, dmu_tx_t *tx);
 void dnode_byteswap(dnode_phys_t *dnp);
 void dnode_buf_byteswap(void *buf, size_t size);
@@ -327,6 +351,15 @@ int dnode_next_offset(dnode_t *dn, int flags, uint64_t *off,
 void dnode_evict_dbufs(dnode_t *dn);
 void dnode_evict_bonus(dnode_t *dn);
 
+#define        DNODE_IS_CACHEABLE(_dn)                                         \
+       ((_dn)->dn_objset->os_primary_cache == ZFS_CACHE_ALL ||         \
+       (DMU_OT_IS_METADATA((_dn)->dn_type) &&                          \
+       (_dn)->dn_objset->os_primary_cache == ZFS_CACHE_METADATA))
+
+#define        DNODE_META_IS_CACHEABLE(_dn)                                    \
+       ((_dn)->dn_objset->os_primary_cache == ZFS_CACHE_ALL ||         \
+       (_dn)->dn_objset->os_primary_cache == ZFS_CACHE_METADATA)
+
 #ifdef ZFS_DEBUG
 
 /*
index da6f21c2eeff0012da8bb3434c3757e0dbd37db5..eb0c6838b95259725c9aab8dbdd51fbd38e4b2a4 100644 (file)
@@ -20,8 +20,8 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
- * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
@@ -38,6 +38,7 @@
 #include <sys/zfs_context.h>
 #include <sys/dsl_deadlist.h>
 #include <sys/refcount.h>
+#include <zfeature_common.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -90,6 +91,27 @@ struct dsl_pool;
  */
 #define        DS_FIELD_LARGE_BLOCKS "org.open-zfs:large_blocks"
 
+/*
+ * This field is present (with value=0) if this dataset may contain large
+ * dnodes (>512B).  If it is present, then this dataset is counted in the
+ * refcount of the SPA_FEATURE_LARGE_DNODE feature.
+ */
+#define        DS_FIELD_LARGE_DNODE "org.zfsonlinux:large_dnode"
+
+/*
+ * These fields are set on datasets that are in the middle of a resumable
+ * receive, and allow the sender to resume the send if it is interrupted.
+ */
+#define        DS_FIELD_RESUME_FROMGUID "com.delphix:resume_fromguid"
+#define        DS_FIELD_RESUME_TONAME "com.delphix:resume_toname"
+#define        DS_FIELD_RESUME_TOGUID "com.delphix:resume_toguid"
+#define        DS_FIELD_RESUME_OBJECT "com.delphix:resume_object"
+#define        DS_FIELD_RESUME_OFFSET "com.delphix:resume_offset"
+#define        DS_FIELD_RESUME_BYTES "com.delphix:resume_bytes"
+#define        DS_FIELD_RESUME_LARGEBLOCK "com.delphix:resume_largeblockok"
+#define        DS_FIELD_RESUME_EMBEDOK "com.delphix:resume_embedok"
+#define        DS_FIELD_RESUME_COMPRESSOK "com.delphix:resume_compressok"
+
 /*
  * DS_FLAG_CI_DATASET is set if the dataset contains a file system whose
  * name lookups should be performed case-insensitively.
@@ -145,8 +167,6 @@ typedef struct dsl_dataset {
        /* only used in syncing context, only valid for non-snapshots: */
        struct dsl_dataset *ds_prev;
        uint64_t ds_bookmarks;  /* DMU_OTN_ZAP_METADATA */
-       boolean_t ds_large_blocks;
-       boolean_t ds_need_large_blocks;
 
        /* has internal locking: */
        dsl_deadlist_t ds_deadlist;
@@ -185,8 +205,31 @@ typedef struct dsl_dataset {
        kmutex_t ds_sendstream_lock;
        list_t ds_sendstreams;
 
+       /*
+        * When in the middle of a resumable receive, tracks how much
+        * progress we have made.
+        */
+       uint64_t ds_resume_object[TXG_SIZE];
+       uint64_t ds_resume_offset[TXG_SIZE];
+       uint64_t ds_resume_bytes[TXG_SIZE];
+
+       /* Protected by our dsl_dir's dd_lock */
+       list_t ds_prop_cbs;
+
+       /*
+        * For ZFEATURE_FLAG_PER_DATASET features, set if this dataset
+        * uses this feature.
+        */
+       uint8_t ds_feature_inuse[SPA_FEATURES];
+
+       /*
+        * Set if we need to activate the feature on this dataset this txg
+        * (used only in syncing context).
+        */
+       uint8_t ds_feature_activation_needed[SPA_FEATURES];
+
        /* Protected by ds_lock; keep at end of struct for better locality */
-       char ds_snapname[MAXNAMELEN];
+       char ds_snapname[ZFS_MAX_DATASET_NAME_LEN];
 } dsl_dataset_t;
 
 static inline dsl_dataset_phys_t *
@@ -222,6 +265,7 @@ void dsl_dataset_disown(dsl_dataset_t *ds, void *tag);
 void dsl_dataset_name(dsl_dataset_t *ds, char *name);
 boolean_t dsl_dataset_tryown(dsl_dataset_t *ds, void *tag);
 int dsl_dataset_namelen(dsl_dataset_t *ds);
+boolean_t dsl_dataset_has_owner(dsl_dataset_t *ds);
 uint64_t dsl_dataset_create_sync(dsl_dir_t *pds, const char *lastname,
     dsl_dataset_t *origin, uint64_t flags, cred_t *, dmu_tx_t *);
 uint64_t dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
@@ -265,8 +309,6 @@ int dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
 int dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, dsl_dataset_t *last,
     uint64_t *usedp, uint64_t *compp, uint64_t *uncompp);
 boolean_t dsl_dataset_is_dirty(dsl_dataset_t *ds);
-int dsl_dataset_activate_large_blocks(const char *dsname);
-void dsl_dataset_activate_large_blocks_sync_impl(uint64_t dsobj, dmu_tx_t *tx);
 
 int dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf);
 
@@ -304,15 +346,20 @@ int dsl_dataset_snap_remove(dsl_dataset_t *ds, const char *name, dmu_tx_t *tx,
 void dsl_dataset_set_refreservation_sync_impl(dsl_dataset_t *ds,
     zprop_source_t source, uint64_t value, dmu_tx_t *tx);
 void dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx);
+boolean_t dsl_dataset_is_zapified(dsl_dataset_t *ds);
+boolean_t dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds);
 int dsl_dataset_rollback(const char *fsname, void *owner, nvlist_t *result);
 
+void dsl_dataset_deactivate_feature(uint64_t dsobj,
+    spa_feature_t f, dmu_tx_t *tx);
+
 #ifdef ZFS_DEBUG
 #define        dprintf_ds(ds, fmt, ...) do { \
        if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
-       char *__ds_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); \
+       char *__ds_name = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP); \
        dsl_dataset_name(ds, __ds_name); \
        dprintf("ds=%s " fmt, __ds_name, __VA_ARGS__); \
-       kmem_free(__ds_name, MAXNAMELEN); \
+       kmem_free(__ds_name, ZFS_MAX_DATASET_NAME_LEN); \
        } \
 _NOTE(CONSTCOND) } while (0)
 #else
index 59e8e055551ad0b5ca9ba447e3fa3361d00ca980..d399d1da973be0d0c488eac1af3786e8722ff3ed 100644 (file)
@@ -51,8 +51,12 @@ extern "C" {
 #define        ZFS_DELEG_PERM_VSCAN            "vscan"
 #define        ZFS_DELEG_PERM_USERQUOTA        "userquota"
 #define        ZFS_DELEG_PERM_GROUPQUOTA       "groupquota"
+#define        ZFS_DELEG_PERM_USEROBJQUOTA     "userobjquota"
+#define        ZFS_DELEG_PERM_GROUPOBJQUOTA    "groupobjquota"
 #define        ZFS_DELEG_PERM_USERUSED         "userused"
 #define        ZFS_DELEG_PERM_GROUPUSED        "groupused"
+#define        ZFS_DELEG_PERM_USEROBJUSED      "userobjused"
+#define        ZFS_DELEG_PERM_GROUPOBJUSED     "groupobjused"
 #define        ZFS_DELEG_PERM_HOLD             "hold"
 #define        ZFS_DELEG_PERM_RELEASE          "release"
 #define        ZFS_DELEG_PERM_DIFF             "diff"
index 55f3a8e5baa9317a7ea99f8455dabe8d20844136..fb299684c424fc1a8d7ec15a048121760d4b5969 100644 (file)
@@ -102,7 +102,7 @@ struct dsl_dir {
 
        /* Protected by dd_lock */
        kmutex_t dd_lock;
-       list_t dd_prop_cbs; /* list of dsl_prop_cb_record_t's */
+       list_t dd_props; /* list of dsl_prop_record_t's */
        timestruc_t dd_snap_cmtime; /* last time snapshot namespace changed */
        uint64_t dd_origin_txg;
 
@@ -112,7 +112,7 @@ struct dsl_dir {
        int64_t dd_space_towrite[TXG_SIZE];
 
        /* protected by dd_lock; keep at end of struct for better locality */
-       char dd_myname[MAXNAMELEN];
+       char dd_myname[ZFS_MAX_DATASET_NAME_LEN];
 };
 
 static inline dsl_dir_phys_t *
@@ -176,11 +176,10 @@ boolean_t dsl_dir_is_zapified(dsl_dir_t *dd);
 #ifdef ZFS_DEBUG
 #define        dprintf_dd(dd, fmt, ...) do { \
        if (zfs_flags & ZFS_DEBUG_DPRINTF) { \
-       char *__ds_name = kmem_alloc(MAXNAMELEN + strlen(MOS_DIR_NAME) + 1, \
-           KM_SLEEP); \
+       char *__ds_name = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP); \
        dsl_dir_name(dd, __ds_name); \
        dprintf("dd=%s " fmt, __ds_name, __VA_ARGS__); \
-       kmem_free(__ds_name, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1); \
+       kmem_free(__ds_name, ZFS_MAX_DATASET_NAME_LEN); \
        } \
 _NOTE(CONSTCOND) } while (0)
 #else
index 5fe18d6a7c550b621e9df0ff8458b703c6f1bcf3..62ef0ba67a6ceb5c1bfdab4fbabd4919f5328c75 100644 (file)
@@ -41,10 +41,17 @@ struct dsl_dir;
 /* The callback func may not call into the DMU or DSL! */
 typedef void (dsl_prop_changed_cb_t)(void *arg, uint64_t newval);
 
+typedef struct dsl_prop_record {
+       list_node_t pr_node; /* link on dd_props */
+       const char *pr_propname;
+       list_t pr_cbs;
+} dsl_prop_record_t;
+
 typedef struct dsl_prop_cb_record {
-       list_node_t cbr_node; /* link on dd_prop_cbs */
+       list_node_t cbr_pr_node; /* link on pr_cbs */
+       list_node_t cbr_ds_node; /* link on ds_prop_cbs */
+       dsl_prop_record_t *cbr_pr;
        struct dsl_dataset *cbr_ds;
-       const char *cbr_propname;
        dsl_prop_changed_cb_t *cbr_func;
        void *cbr_arg;
 } dsl_prop_cb_record_t;
@@ -54,10 +61,13 @@ typedef struct dsl_props_arg {
        zprop_source_t pa_source;
 } dsl_props_arg_t;
 
+void dsl_prop_init(dsl_dir_t *dd);
+void dsl_prop_fini(dsl_dir_t *dd);
 int dsl_prop_register(struct dsl_dataset *ds, const char *propname,
     dsl_prop_changed_cb_t *callback, void *cbarg);
 int dsl_prop_unregister(struct dsl_dataset *ds, const char *propname,
     dsl_prop_changed_cb_t *callback, void *cbarg);
+void dsl_prop_unregister_all(struct dsl_dataset *ds, void *cbarg);
 void dsl_prop_notify_all(struct dsl_dir *dd);
 boolean_t dsl_prop_hascb(struct dsl_dataset *ds);
 
diff --git a/zfs/include/sys/edonr.h b/zfs/include/sys/edonr.h
new file mode 100644 (file)
index 0000000..79b7cd8
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * IDI,NTNU
+ *
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 (C) 2009, 2010, Jorn Amundsen <jorn.amundsen@ntnu.no>
+ *
+ * Tweaked Edon-R implementation for SUPERCOP, based on NIST API.
+ *
+ * $Id: edonr.h 517 2013-02-17 20:34:39Z joern $
+ */
+/*
+ * Portions copyright (c) 2013, Saso Kiselkov, All rights reserved
+ */
+
+#ifndef        _SYS_EDONR_H_
+#define        _SYS_EDONR_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef  _KERNEL
+#include <sys/types.h>
+#else
+#include <stdint.h> /* uint32_t... */
+#include <stdlib.h> /* size_t ... */
+#endif
+
+/*
+ * EdonR allows to call EdonRUpdate() consecutively only if the total length
+ * of stored unprocessed data and the new supplied data is less than or equal
+ * to the BLOCK_SIZE on which the compression functions operates.
+ * Otherwise an assertion failure is invoked.
+ */
+
+/* Specific algorithm definitions */
+#define        EdonR224_DIGEST_SIZE    28
+#define        EdonR224_BLOCK_SIZE     64
+#define        EdonR256_DIGEST_SIZE    32
+#define        EdonR256_BLOCK_SIZE     64
+#define        EdonR384_DIGEST_SIZE    48
+#define        EdonR384_BLOCK_SIZE     128
+#define        EdonR512_DIGEST_SIZE    64
+#define        EdonR512_BLOCK_SIZE     128
+
+#define        EdonR256_BLOCK_BITSIZE  512
+#define        EdonR512_BLOCK_BITSIZE  1024
+
+typedef struct {
+       uint32_t DoublePipe[16];
+       uint8_t LastPart[EdonR256_BLOCK_SIZE * 2];
+} EdonRData256;
+typedef struct {
+       uint64_t DoublePipe[16];
+       uint8_t LastPart[EdonR512_BLOCK_SIZE * 2];
+} EdonRData512;
+
+typedef struct {
+       size_t hashbitlen;
+
+       /* + algorithm specific parameters */
+       int unprocessed_bits;
+       uint64_t bits_processed;
+       union {
+               EdonRData256 p256[1];
+               EdonRData512 p512[1];
+       } pipe[1];
+} EdonRState;
+
+void EdonRInit(EdonRState *state, size_t hashbitlen);
+void EdonRUpdate(EdonRState *state, const uint8_t *data, size_t databitlen);
+void EdonRFinal(EdonRState *state, uint8_t *hashval);
+void EdonRHash(size_t hashbitlen, const uint8_t *data, size_t databitlen,
+    uint8_t *hashval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_EDONR_H_ */
index ee367a574e46bf126c5d18957285e4eb1de74fe1..b8f33228143c768221bffba5f10e563bb0967d15 100644 (file)
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #ifndef        _SYS_EFI_PARTITION_H
@@ -86,54 +87,190 @@ typedef struct efi_gpe_Attrs {
  * 6a945a3b-1dd2-11b2-99a6-080020736631        V_CACHE
  */
 
-#define        EFI_UNUSED      { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
-                           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
-#define        EFI_RESV1       { 0x6a96237f, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_BOOT        { 0x6a82cb45, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_ROOT        { 0x6a85cf4d, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_SWAP        { 0x6a87c46f, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_USR         { 0x6a898cc3, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_BACKUP      { 0x6a8b642b, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_RESV2       { 0x6a8d2ac7, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_VAR         { 0x6a8ef2e9, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_HOME        { 0x6a90ba39, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_ALTSCTR     { 0x6a9283a5, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_RESERVED    { 0x6a945a3b, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_SYSTEM      { 0xC12A7328, 0xF81F, 0x11d2, 0xBA, 0x4B, \
-                           { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } }
-#define        EFI_LEGACY_MBR  { 0x024DEE41, 0x33E7, 0x11d3, 0x9D, 0x69, \
-                           { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F } }
-#define        EFI_SYMC_PUB    { 0x6a9630d1, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_SYMC_CDS    { 0x6a980767, 0x1dd2, 0x11b2, 0x99, 0xa6, \
-                           { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
-#define        EFI_MSFT_RESV   { 0xE3C9E316, 0x0B5C, 0x4DB8, 0x81, 0x7D, \
-                           { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } }
-#define        EFI_DELL_BASIC  { 0xebd0a0a2, 0xb9e5, 0x4433, 0x87, 0xc0, \
-                           { 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } }
-#define        EFI_DELL_RAID   { 0xa19d880f, 0x05fc, 0x4d3b, 0xa0, 0x06, \
-                           { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e } }
-#define        EFI_DELL_SWAP   { 0x0657fd6d, 0xa4ab, 0x43c4, 0x84, 0xe5, \
-                           { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f } }
-#define        EFI_DELL_LVM    { 0xe6d6d379, 0xf507, 0x44c2, 0xa2, 0x3c, \
-                           { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 } }
-#define        EFI_DELL_RESV   { 0x8da63339, 0x0007, 0x60c0, 0xc4, 0x36, \
-                           { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 } }
-#define        EFI_AAPL_HFS    { 0x48465300, 0x0000, 0x11aa, 0xaa, 0x11, \
-                           { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
-#define        EFI_AAPL_UFS    { 0x55465300, 0x0000, 0x11aa, 0xaa, 0x11, \
-                           { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_UNUSED              { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
+                                   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
+#define        EFI_RESV1               { 0x6a96237f, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_BOOT                { 0x6a82cb45, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_ROOT                { 0x6a85cf4d, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_SWAP                { 0x6a87c46f, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_USR                 { 0x6a898cc3, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_BACKUP              { 0x6a8b642b, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_RESV2               { 0x6a8d2ac7, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_VAR                 { 0x6a8ef2e9, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_HOME                { 0x6a90ba39, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_ALTSCTR             { 0x6a9283a5, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_RESERVED            { 0x6a945a3b, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_SYSTEM              { 0xC12A7328, 0xF81F, 0x11d2, 0xBA, 0x4B, \
+                                   { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B } }
+#define        EFI_LEGACY_MBR          { 0x024DEE41, 0x33E7, 0x11d3, 0x9D, 0x69, \
+                                   { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F } }
+#define        EFI_SYMC_PUB            { 0x6a9630d1, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_SYMC_CDS            { 0x6a980767, 0x1dd2, 0x11b2, 0x99, 0xa6, \
+                                   { 0x08, 0x00, 0x20, 0x73, 0x66, 0x31 } }
+#define        EFI_MSFT_RESV           { 0xE3C9E316, 0x0B5C, 0x4DB8, 0x81, 0x7D, \
+                                   { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE } }
+#define        EFI_DELL_BASIC          { 0xebd0a0a2, 0xb9e5, 0x4433, 0x87, 0xc0, \
+                                   { 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } }
+#define        EFI_DELL_RAID           { 0xa19d880f, 0x05fc, 0x4d3b, 0xa0, 0x06, \
+                                   { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e } }
+#define        EFI_DELL_SWAP           { 0x0657fd6d, 0xa4ab, 0x43c4, 0x84, 0xe5, \
+                                   { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f } }
+#define        EFI_DELL_LVM            { 0xe6d6d379, 0xf507, 0x44c2, 0xa2, 0x3c, \
+                                   { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 } }
+#define        EFI_DELL_RESV           { 0x8da63339, 0x0007, 0x60c0, 0xc4, 0x36, \
+                                   { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 } }
+#define        EFI_AAPL_HFS            { 0x48465300, 0x0000, 0x11aa, 0xaa, 0x11, \
+                                   { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_AAPL_UFS            { 0x55465300, 0x0000, 0x11aa, 0xaa, 0x11, \
+                                   { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_FREEBSD_BOOT        { 0x83bd6b9d, 0x7f41, 0x11dc, 0xbe, 0x0b, \
+                                   { 0x00, 0x15, 0x60, 0xb8, 0x4f, 0x0f } }
+#define        EFI_FREEBSD_SWAP        { 0x516e7cb5, 0x6ecf, 0x11d6, 0x8f, 0xf8, \
+                                   { 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b } }
+#define        EFI_FREEBSD_UFS         { 0x516e7cb6, 0x6ecf, 0x11d6, 0x8f, 0xf8, \
+                                   { 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b } }
+#define        EFI_FREEBSD_VINUM       { 0x516e7cb8, 0x6ecf, 0x11d6, 0x8f, 0xf8, \
+                                   { 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b } }
+#define        EFI_FREEBSD_ZFS         { 0x516e7cba, 0x6ecf, 0x11d6, 0x8f, 0xf8, \
+                                   { 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b } }
+
+/* From Wikipedia */
+
+#define        EFI_BIOS_BOOT           { 0x21686148, 0x6449, 0x6e6f, 0x74, 0x4e, \
+                                   { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } }
+#define        EFI_INTC_RS             { 0xd3bfe2de, 0x3daf, 0x11df, 0xba, 0x40, \
+                                   { 0xe3, 0xa5, 0x56, 0xd8, 0x95, 0x93 } }
+#define        EFI_SNE_BOOT            { 0xf4019732, 0x066e, 0x4e12, 0x82, 0x73, \
+                                   { 0x34, 0x6c, 0x56, 0x41, 0x49, 0x4f } }
+#define        EFI_LENOVO_BOOT         { 0xbfbfafe7, 0xa34f, 0x448a, 0x9a, 0x5b, \
+                                   { 0x62, 0x13, 0xeb, 0x73, 0x6c, 0x22 } }
+#define        EFI_MSFT_LDMM           { 0x5808c8aa, 0x7e8f, 0x42e0, 0x85, 0xd2, \
+                                   { 0xe1, 0xe9, 0x04, 0x34, 0xcf, 0xb3 } }
+#define        EFI_MSFT_LDMD           { 0xaf9b60a0, 0x1431, 0x4f62, 0xbc, 0x68, \
+                                   { 0x33, 0x11, 0x71, 0x4a, 0x69, 0xad } }
+#define        EFI_MSFT_RE             { 0xde94bba4, 0x06d1, 0x4d40, 0xa1, 0x6a, \
+                                   { 0xbf, 0xd5, 0x01, 0x79, 0xd6, 0xac } }
+#define        EFI_IBM_GPFS            { 0x37affc90, 0xef7d, 0x4e96, 0x91, 0xc3, \
+                                   { 0x2d, 0x7a, 0xe0, 0x55, 0xb1, 0x74 } }
+#define        EFI_MSFT_STORAGESPACES  { 0xe75caf8f, 0xf680, 0x4cee, 0xaf, 0xa3, \
+                                   { 0xb0, 0x01, 0xe5, 0x6e, 0xfc, 0x2d } }
+#define        EFI_HPQ_DATA            { 0x75894c1e, 0x3aeb, 0x11d3, 0xb7, 0xc1, \
+                                   { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 } }
+#define        EFI_HPQ_SVC             { 0xe2a1e728, 0x32e3, 0x11d6, 0xa6, 0x82, \
+                                   { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 } }
+#define        EFI_RHT_DATA            { 0x0fc63daf, 0x8483, 0x4772, 0x8e, 0x79, \
+                                   { 0x3d, 0x69, 0xd8, 0x47, 0x7d, 0xe4 } }
+#define        EFI_RHT_HOME            { 0x933ac7e1, 0x2eb4, 0x4f13, 0xb8, 0x44, \
+                                   { 0x0e, 0x14, 0xe2, 0xae, 0xf9, 0x15 } }
+#define        EFI_RHT_SRV             { 0x3b8f8425, 0x20e0, 0x4f3b, 0x90, 0x7f, \
+                                   { 0x1a, 0x25, 0xa7, 0x6f, 0x98, 0xe8 } }
+#define        EFI_RHT_DMCRYPT         { 0x7ffec5c9, 0x2d00, 0x49b7, 0x89, 0x41, \
+                                   { 0x3e, 0xa1, 0x0a, 0x55, 0x86, 0xb7 } }
+#define        EFI_RHT_LUKS            { 0xca7d7ccb, 0x63ed, 0x4c53, 0x86, 0x1c, \
+                                   { 0x17, 0x42, 0x53, 0x60, 0x59, 0xcc } }
+#define        EFI_FREEBSD_DISKLABEL   { 0x516e7cb4, 0x6ecf, 0x11d6, 0x8f, 0xf8, \
+                                   { 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b } }
+#define        EFI_AAPL_RAID           { 0x52414944, 0x0000, 0x11aa, 0xaa, 0x11, \
+                                   { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_AAPL_RAIDOFFLINE    { 0x52414944, 0x5f4f, 0x11aa, 0xaa, 0x11, \
+                                   { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_AAPL_BOOT           { 0x426f6f74, 0x0000, 0x11aa, 0xaa, 0x11, \
+                                   { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_AAPL_LABEL          { 0x4c616265, 0x6c00, 0x11aa, 0xaa, 0x11, \
+                                   { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_AAPL_TVRECOVERY     { 0x5265636f, 0x7665, 0x11aa, 0xaa, 0x11, \
+                                   { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_AAPL_CORESTORAGE    { 0x53746f72, 0x6167, 0x11aa, 0xaa, 0x11, \
+                                   { 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } }
+#define        EFI_NETBSD_SWAP         { 0x49f48d32, 0xb10e, 0x11dc, 0xb9, 0x9b, \
+                                   { 0x00, 0x19, 0xd1, 0x87, 0x96, 0x48 } }
+#define        EFI_NETBSD_FFS          { 0x49f48d5a, 0xb10e, 0x11dc, 0xb9, 0x9b, \
+                                   { 0x00, 0x19, 0xd1, 0x87, 0x96, 0x48 } }
+#define        EFI_NETBSD_LFS          { 0x49f48d82, 0xb10e, 0x11dc, 0xb9, 0x9b, \
+                                   { 0x00, 0x19, 0xd1, 0x87, 0x96, 0x48 } }
+#define        EFI_NETBSD_RAID         { 0x49f48daa, 0xb10e, 0x11dc, 0xb9, 0x9b, \
+                                   { 0x00, 0x19, 0xd1, 0x87, 0x96, 0x48 } }
+#define        EFI_NETBSD_CAT          { 0x2db519c4, 0xb10f, 0x11dc, 0xb9, 0x9b, \
+                                   { 0x00, 0x19, 0xd1, 0x87, 0x96, 0x48 } }
+#define        EFI_NETBSD_CRYPT        { 0x2db519ec, 0xb10f, 0x11dc, 0xb9, 0x9b, \
+                                   { 0x00, 0x19, 0xd1, 0x87, 0x96, 0x48 } }
+#define        EFI_GOOG_KERN           { 0xfe3a2a5d, 0x4f32, 0x41a7, 0xb7, 0x25, \
+                                   { 0xac, 0xcc, 0x32, 0x85, 0xa3, 0x09 } }
+#define        EFI_GOOG_ROOT           { 0x3cb8e202, 0x3b7e, 0x47dd, 0x8a, 0x3c, \
+                                   { 0x7f, 0xf2, 0xa1, 0x3c, 0xfc, 0xec } }
+#define        EFI_GOOG_RESV           { 0x2e0a753d, 0x9e48, 0x43b0, 0x83, 0x37, \
+                                   { 0xb1, 0x51, 0x92, 0xcb, 0x1b, 0x5e } }
+#define        EFI_HAIKU_BFS           { 0x42465331, 0x3ba3, 0x10f1, 0x80, 0x2a, \
+                                   { 0x48, 0x61, 0x69, 0x6b, 0x75, 0x21 } }
+#define        EFI_MIDNIGHTBSD_BOOT    { 0x85d5e45e, 0x237c, 0x11e1, 0xb4, 0xb3, \
+                                   { 0xe8, 0x9a, 0x8f, 0x7f, 0xc3, 0xa7 } }
+#define        EFI_MIDNIGHTBSD_DATA    { 0x85d5e45a, 0x237c, 0x11e1, 0xb4, 0xb3, \
+                                   { 0xe8, 0x9a, 0x8f, 0x7f, 0xc3, 0xa7 } }
+#define        EFI_MIDNIGHTBSD_SWAP    { 0x85d5e45b, 0x237c, 0x11e1, 0xb4, 0xb3, \
+                                   { 0xe8, 0x9a, 0x8f, 0x7f, 0xc3, 0xa7 } }
+#define        EFI_MIDNIGHTBSD_UFS     { 0x0394ef8b, 0x237e, 0x11e1, 0xb4, 0xb3, \
+                                   { 0xe8, 0x9a, 0x8f, 0x7f, 0xc3, 0xa7 } }
+#define        EFI_MIDNIGHTBSD_VINUM   { 0x85d5e45c, 0x237c, 0x11e1, 0xb4, 0xb3, \
+                                   { 0xe8, 0x9a, 0x8f, 0x7f, 0xc3, 0xa7 } }
+#define        EFI_MIDNIGHTBSD_ZFS     { 0x85d5e45d, 0x237c, 0x11e1, 0xb4, 0xb3, \
+                                   { 0xe8, 0x9a, 0x8f, 0x7f, 0xc3, 0xa7 } }
+#define        EFI_CEPH_JOURNAL        { 0x45b0969e, 0x9b03, 0x4f30, 0xb4, 0xc6, \
+                                   { 0xb4, 0xb8, 0x0c, 0xef, 0xf1, 0x06 } }
+#define        EFI_CEPH_DMCRYPTJOURNAL { 0x45b0969e, 0x9b03, 0x4f30, 0xb4, 0xc6, \
+                                   { 0x5e, 0xc0, 0x0c, 0xef, 0xf1, 0x06 } }
+#define        EFI_CEPH_OSD            { 0x4fbd7e29, 0x9d25, 0x41b8, 0xaf, 0xd0, \
+                                   { 0x06, 0x2c, 0x0c, 0xef, 0xf0, 0x5d } }
+#define        EFI_CEPH_DMCRYPTOSD     { 0x4fbd7e29, 0x9d25, 0x41b8, 0xaf, 0xd0, \
+                                   { 0x5e, 0xc0, 0x0c, 0xef, 0xf0, 0x5d } }
+#define        EFI_CEPH_CREATE         { 0x89c57f98, 0x2fe5, 0x4dc0, 0x89, 0xc1, \
+                                   { 0xf3, 0xad, 0x0c, 0xef, 0xf2, 0xbe } }
+#define        EFI_CEPH_DMCRYPTCREATE  { 0x89c57f98, 0x2fe5, 0x4dc0, 0x89, 0xc1, \
+                                   { 0x5e, 0xc0, 0x0c, 0xef, 0xf2, 0xbe } }
+#define        EFI_OPENBSD_DISKLABEL   { 0x824cc7a0, 0x36a8, 0x11e3, 0x89, 0x0a, \
+                                   { 0x95, 0x25, 0x19, 0xad, 0x3f, 0x61 } }
+#define        EFI_BBRY_QNX            { 0xcef5a9ad, 0x73bc, 0x4601, 0x89, 0xf3, \
+                                   { 0xcd, 0xee, 0xee, 0xe3, 0x21, 0xa1 } }
+#define        EFI_BELL_PLAN9          { 0xc91818f9, 0x8025, 0x47af, 0x89, 0xd2, \
+                                   { 0xf0, 0x30, 0xd7, 0x00, 0x0c, 0x2c } }
+#define        EFI_VMW_KCORE           { 0x9d275380, 0x40ad, 0x11db, 0xbf, 0x97, \
+                                   { 0x00, 0x0c, 0x29, 0x11, 0xd1, 0xb8 } }
+#define        EFI_VMW_VMFS            { 0xaa31e02a, 0x400f, 0x11db, 0x95, 0x90, \
+                                   { 0x00, 0x0c, 0x29, 0x11, 0xd1, 0xb8 } }
+#define        EFI_VMW_RESV            { 0x9198effc, 0x31c0, 0x11db, 0x8f, 0x78, \
+                                   { 0x00, 0x0c, 0x29, 0x11, 0xd1, 0xb8 } }
+
+/* From GPT fdisk */
+
+#define        EFI_RHT_ROOTX86         { 0x44479540, 0xf297, 0x41b2, 0x9a, 0xf7, \
+                                   { 0xd1, 0x31, 0xd5, 0xf0, 0x45, 0x8a } }
+#define        EFI_RHT_ROOTAMD64       { 0x4f68bce3, 0xe8cd, 0x4db1, 0x96, 0xe7, \
+                                   { 0xfb, 0xca, 0xf9, 0x84, 0xb7, 0x09 } }
+#define        EFI_RHT_ROOTARM         { 0x69dad710, 0x2ce4, 0x4e3c, 0xb1, 0x6c, \
+                                   { 0x21, 0xa1, 0xd4, 0x9a, 0xbe, 0xd3 } }
+#define        EFI_RHT_ROOTARM64       { 0xb921b045, 0x1df0, 0x41c3, 0xaf, 0x44, \
+                                   { 0x4c, 0x6f, 0x28, 0x0d, 0x3f, 0xae } }
+#define        EFI_ACRONIS_SECUREZONE  { 0x0311fc50, 0x01ca, 0x4725, 0xad, 0x77, \
+                                   { 0x9a, 0xdb, 0xb2, 0x0a, 0xce, 0x98 } }
+#define        EFI_ONIE_BOOT           { 0x7412f7d5, 0xa156, 0x4b13, 0x81, 0xdc, \
+                                   { 0x86, 0x71, 0x74, 0x92, 0x93, 0x25 } }
+#define        EFI_ONIE_CONFIG         { 0xd4e6e2cd, 0x4469, 0x46f3, 0xb5, 0xcb, \
+                                   { 0x1b, 0xff, 0x57, 0xaf, 0xc1, 0x49 } }
+#define        EFI_IBM_PPRPBOOT        { 0x9e1a2d38, 0xc612, 0x4316, 0xaa, 0x26, \
+                                   { 0x8b, 0x49, 0x52, 0x1e, 0x5a, 0x8b } }
+#define        EFI_FREEDESKTOP_BOOT    { 0xbc13c2ff, 0x59e6, 0x4262, 0xa3, 0x52, \
+                                   { 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 } }
 
 /* minimum # of bytes for partition table entires, per EFI spec */
 #define        EFI_MIN_ARRAY_SIZE      (16 * 1024)
diff --git a/zfs/include/sys/fm/Makefile.in b/zfs/include/sys/fm/Makefile.in
deleted file mode 100644 (file)
index 52ae096..0000000
+++ /dev/null
@@ -1,874 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = include/sys/fm
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__kernel_HEADERS_DIST) \
-       $(am__libzfs_HEADERS_DIST) $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
-       ctags-recursive dvi-recursive html-recursive info-recursive \
-       install-data-recursive install-dvi-recursive \
-       install-exec-recursive install-html-recursive \
-       install-info-recursive install-pdf-recursive \
-       install-ps-recursive install-recursive installcheck-recursive \
-       installdirs-recursive pdf-recursive ps-recursive \
-       tags-recursive uninstall-recursive
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__kernel_HEADERS_DIST = $(top_srcdir)/include/sys/fm/protocol.h \
-       $(top_srcdir)/include/sys/fm/util.h
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"
-am__libzfs_HEADERS_DIST = $(top_srcdir)/include/sys/fm/protocol.h \
-       $(top_srcdir)/include/sys/fm/util.h
-HEADERS = $(kernel_HEADERS) $(libzfs_HEADERS)
-RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
-  distclean-recursive maintainer-clean-recursive
-am__recursive_targets = \
-  $(RECURSIVE_TARGETS) \
-  $(RECURSIVE_CLEAN_TARGETS) \
-  $(am__extra_recursive_targets)
-AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
-       distdir
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-am__relativize = \
-  dir0=`pwd`; \
-  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
-  sed_rest='s,^[^/]*/*,,'; \
-  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
-  sed_butlast='s,/*[^/]*$$,,'; \
-  while test -n "$$dir1"; do \
-    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
-    if test "$$first" != "."; then \
-      if test "$$first" = ".."; then \
-        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
-        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
-      else \
-        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
-        if test "$$first2" = "$$first"; then \
-          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
-        else \
-          dir2="../$$dir2"; \
-        fi; \
-        dir0="$$dir0"/"$$first"; \
-      fi; \
-    fi; \
-    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
-  done; \
-  reldir="$$dir2"
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-SUBDIRS = fs
-COMMON_H = \
-       $(top_srcdir)/include/sys/fm/protocol.h \
-       $(top_srcdir)/include/sys/fm/util.h
-
-KERNEL_H = 
-USER_H = 
-EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
-@CONFIG_USER_TRUE@libzfsdir = $(includedir)/libzfs/sys/fm
-@CONFIG_USER_TRUE@libzfs_HEADERS = $(COMMON_H) $(USER_H)
-@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/fm
-@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
-all: all-recursive
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/sys/fm/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu include/sys/fm/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-install-kernelHEADERS: $(kernel_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(kerneldir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(kerneldir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(kerneldir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(kerneldir)" || exit $$?; \
-       done
-
-uninstall-kernelHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(kerneldir)'; $(am__uninstall_files_from_dir)
-install-libzfsHEADERS: $(libzfs_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(libzfsdir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(libzfsdir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libzfsdir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(libzfsdir)" || exit $$?; \
-       done
-
-uninstall-libzfsHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(libzfsdir)'; $(am__uninstall_files_from_dir)
-
-# This directory's subdirectories are mostly independent; you can cd
-# into them and run 'make' without going through this Makefile.
-# To change the values of 'make' variables: instead of editing Makefiles,
-# (1) if the variable is set in 'config.status', edit 'config.status'
-#     (which will cause the Makefiles to be regenerated when you run 'make');
-# (2) otherwise, pass the desired values on the 'make' command line.
-$(am__recursive_targets):
-       @fail=; \
-       if $(am__make_keepgoing); then \
-         failcom='fail=yes'; \
-       else \
-         failcom='exit 1'; \
-       fi; \
-       dot_seen=no; \
-       target=`echo $@ | sed s/-recursive//`; \
-       case "$@" in \
-         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
-         *) list='$(SUBDIRS)' ;; \
-       esac; \
-       for subdir in $$list; do \
-         echo "Making $$target in $$subdir"; \
-         if test "$$subdir" = "."; then \
-           dot_seen=yes; \
-           local_target="$$target-am"; \
-         else \
-           local_target="$$target"; \
-         fi; \
-         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
-         || eval $$failcom; \
-       done; \
-       if test "$$dot_seen" = "no"; then \
-         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
-       fi; test -z "$$fail"
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-recursive
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
-         include_option=--etags-include; \
-         empty_fix=.; \
-       else \
-         include_option=--include; \
-         empty_fix=; \
-       fi; \
-       list='$(SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           test ! -f $$subdir/TAGS || \
-             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
-         fi; \
-       done; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-ctags: ctags-recursive
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-recursive
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-         if test "$$subdir" = .; then :; else \
-           $(am__make_dryrun) \
-             || test -d "$(distdir)/$$subdir" \
-             || $(MKDIR_P) "$(distdir)/$$subdir" \
-             || exit 1; \
-           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
-           $(am__relativize); \
-           new_distdir=$$reldir; \
-           dir1=$$subdir; dir2="$(top_distdir)"; \
-           $(am__relativize); \
-           new_top_distdir=$$reldir; \
-           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
-           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
-           ($(am__cd) $$subdir && \
-             $(MAKE) $(AM_MAKEFLAGS) \
-               top_distdir="$$new_top_distdir" \
-               distdir="$$new_distdir" \
-               am__remove_distdir=: \
-               am__skip_length_check=: \
-               am__skip_mode_fix=: \
-               distdir) \
-             || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-recursive
-all-am: Makefile $(HEADERS)
-installdirs: installdirs-recursive
-installdirs-am:
-       for dir in "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-recursive
-install-exec: install-exec-recursive
-install-data: install-data-recursive
-uninstall: uninstall-recursive
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-recursive
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-recursive
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-recursive
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-tags
-
-dvi: dvi-recursive
-
-dvi-am:
-
-html: html-recursive
-
-html-am:
-
-info: info-recursive
-
-info-am:
-
-install-data-am: install-kernelHEADERS install-libzfsHEADERS
-
-install-dvi: install-dvi-recursive
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-recursive
-
-install-html-am:
-
-install-info: install-info-recursive
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-recursive
-
-install-pdf-am:
-
-install-ps: install-ps-recursive
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-recursive
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-recursive
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-recursive
-
-pdf-am:
-
-ps: ps-recursive
-
-ps-am:
-
-uninstall-am: uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.MAKE: $(am__recursive_targets) install-am install-strip
-
-.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
-       check-am clean clean-generic clean-libtool cscopelist-am ctags \
-       ctags-am distclean distclean-generic distclean-libtool \
-       distclean-tags distdir dvi dvi-am html html-am info info-am \
-       install install-am install-data install-data-am install-dvi \
-       install-dvi-am install-exec install-exec-am install-html \
-       install-html-am install-info install-info-am \
-       install-kernelHEADERS install-libzfsHEADERS install-man \
-       install-pdf install-pdf-am install-ps install-ps-am \
-       install-strip installcheck installcheck-am installdirs \
-       installdirs-am maintainer-clean maintainer-clean-generic \
-       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
-       ps ps-am tags tags-am uninstall uninstall-am \
-       uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/zfs/include/sys/fm/fs/Makefile.in b/zfs/include/sys/fm/fs/Makefile.in
deleted file mode 100644 (file)
index ff7e1d7..0000000
+++ /dev/null
@@ -1,754 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = include/sys/fm/fs
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__kernel_HEADERS_DIST) \
-       $(am__libzfs_HEADERS_DIST) $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__kernel_HEADERS_DIST = $(top_srcdir)/include/sys/fm/fs/zfs.h
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"
-am__libzfs_HEADERS_DIST = $(top_srcdir)/include/sys/fm/fs/zfs.h
-HEADERS = $(kernel_HEADERS) $(libzfs_HEADERS)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-COMMON_H = \
-       $(top_srcdir)/include/sys/fm/fs/zfs.h
-
-KERNEL_H = 
-USER_H = 
-EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
-@CONFIG_USER_TRUE@libzfsdir = $(includedir)/libzfs/sys/fm/fs
-@CONFIG_USER_TRUE@libzfs_HEADERS = $(COMMON_H) $(USER_H)
-@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/fm/fs
-@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
-all: all-am
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/sys/fm/fs/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu include/sys/fm/fs/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-install-kernelHEADERS: $(kernel_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(kerneldir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(kerneldir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(kerneldir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(kerneldir)" || exit $$?; \
-       done
-
-uninstall-kernelHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(kerneldir)'; $(am__uninstall_files_from_dir)
-install-libzfsHEADERS: $(libzfs_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(libzfsdir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(libzfsdir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libzfsdir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(libzfsdir)" || exit $$?; \
-       done
-
-uninstall-libzfsHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(libzfsdir)'; $(am__uninstall_files_from_dir)
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-am
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-ctags: ctags-am
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-am
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-am
-all-am: Makefile $(HEADERS)
-installdirs:
-       for dir in "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-am
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-tags
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-kernelHEADERS install-libzfsHEADERS
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.MAKE: install-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
-       clean-libtool cscopelist-am ctags ctags-am distclean \
-       distclean-generic distclean-libtool distclean-tags distdir dvi \
-       dvi-am html html-am info info-am install install-am \
-       install-data install-data-am install-dvi install-dvi-am \
-       install-exec install-exec-am install-html install-html-am \
-       install-info install-info-am install-kernelHEADERS \
-       install-libzfsHEADERS install-man install-pdf install-pdf-am \
-       install-ps install-ps-am install-strip installcheck \
-       installcheck-am installdirs maintainer-clean \
-       maintainer-clean-generic mostlyclean mostlyclean-generic \
-       mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
-       uninstall-am uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index 0d7eadd4f445903b6af4e2f046406252daa5ff3f..7a8c36ea274ebc86020f18b78fe68183282650f0 100644 (file)
@@ -36,10 +36,7 @@ extern "C" {
 #define        FM_EREPORT_ZFS_IO                       "io"
 #define        FM_EREPORT_ZFS_DATA                     "data"
 #define        FM_EREPORT_ZFS_DELAY                    "delay"
-#define        FM_EREPORT_ZFS_CONFIG_SYNC              "config.sync"
 #define        FM_EREPORT_ZFS_POOL                     "zpool"
-#define        FM_EREPORT_ZFS_POOL_DESTROY             "zpool.destroy"
-#define        FM_EREPORT_ZFS_POOL_REGUID              "zpool.reguid"
 #define        FM_EREPORT_ZFS_DEVICE_UNKNOWN           "vdev.unknown"
 #define        FM_EREPORT_ZFS_DEVICE_OPEN_FAILED       "vdev.open_failed"
 #define        FM_EREPORT_ZFS_DEVICE_CORRUPT_DATA      "vdev.corrupt_data"
@@ -48,19 +45,10 @@ extern "C" {
 #define        FM_EREPORT_ZFS_DEVICE_TOO_SMALL         "vdev.too_small"
 #define        FM_EREPORT_ZFS_DEVICE_BAD_LABEL         "vdev.bad_label"
 #define        FM_EREPORT_ZFS_DEVICE_BAD_ASHIFT        "vdev.bad_ashift"
-#define        FM_EREPORT_ZFS_DEVICE_REMOVE            "vdev.remove"
-#define        FM_EREPORT_ZFS_DEVICE_CLEAR             "vdev.clear"
-#define        FM_EREPORT_ZFS_DEVICE_CHECK             "vdev.check"
-#define        FM_EREPORT_ZFS_DEVICE_SPARE             "vdev.spare"
-#define        FM_EREPORT_ZFS_DEVICE_AUTOEXPAND        "vdev.autoexpand"
 #define        FM_EREPORT_ZFS_IO_FAILURE               "io_failure"
 #define        FM_EREPORT_ZFS_PROBE_FAILURE            "probe_failure"
 #define        FM_EREPORT_ZFS_LOG_REPLAY               "log_replay"
-#define        FM_EREPORT_ZFS_RESILVER_START           "resilver.start"
-#define        FM_EREPORT_ZFS_RESILVER_FINISH          "resilver.finish"
-#define        FM_EREPORT_ZFS_SCRUB_START              "scrub.start"
-#define        FM_EREPORT_ZFS_SCRUB_FINISH             "scrub.finish"
-#define        FM_EREPORT_ZFS_BOOTFS_VDEV_ATTACH       "bootfs.vdev.attach"
+#define        FM_EREPORT_ZFS_CONFIG_CACHE_WRITE       "config_cache_write"
 
 #define        FM_EREPORT_PAYLOAD_ZFS_POOL             "pool"
 #define        FM_EREPORT_PAYLOAD_ZFS_POOL_FAILMODE    "pool_failmode"
@@ -69,9 +57,12 @@ extern "C" {
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID        "vdev_guid"
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_TYPE        "vdev_type"
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH        "vdev_path"
+#define        FM_EREPORT_PAYLOAD_ZFS_VDEV_PHYSPATH    "vdev_physpath"
+#define        FM_EREPORT_PAYLOAD_ZFS_VDEV_ENC_SYSFS_PATH      "vdev_enc_sysfs_path"
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_DEVID       "vdev_devid"
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU         "vdev_fru"
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE       "vdev_state"
+#define        FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE   "vdev_laststate"
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_ASHIFT      "vdev_ashift"
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_COMP_TS     "vdev_complete_ts"
 #define        FM_EREPORT_PAYLOAD_ZFS_VDEV_DELTA_TS    "vdev_delta_ts"
@@ -115,9 +106,9 @@ extern "C" {
 #define        FM_EREPORT_FAILMODE_CONTINUE            "continue"
 #define        FM_EREPORT_FAILMODE_PANIC               "panic"
 
-#define        FM_EREPORT_RESOURCE_REMOVED             "removed"
-#define        FM_EREPORT_RESOURCE_AUTOREPLACE         "autoreplace"
-#define        FM_EREPORT_RESOURCE_STATECHANGE         "statechange"
+#define        FM_RESOURCE_REMOVED                     "removed"
+#define        FM_RESOURCE_AUTOREPLACE                 "autoreplace"
+#define        FM_RESOURCE_STATECHANGE                 "statechange"
 
 #ifdef __cplusplus
 }
index de05bb296741d396587b7626f21d96ff505d3e84..74aef3a92270e06356aaefd730f8eefc7e13efaf 100644 (file)
@@ -50,6 +50,7 @@ extern "C" {
 #define        FM_RSRC_CLASS                   "resource"
 #define        FM_LIST_EVENT                   "list"
 #define        FM_IREPORT_CLASS                "ireport"
+#define        FM_SYSEVENT_CLASS               "sysevent"
 
 /* FM list.* event class values */
 #define        FM_LIST_SUSPECT_CLASS           FM_LIST_EVENT ".suspect"
@@ -360,6 +361,7 @@ extern uint64_t fm_ena_generation_get(uint64_t);
 extern uchar_t fm_ena_format_get(uint64_t);
 extern uint64_t fm_ena_id_get(uint64_t);
 extern uint64_t fm_ena_time_get(uint64_t);
+extern void fm_erpt_dropped_increment(void);
 
 #ifdef __cplusplus
 }
diff --git a/zfs/include/sys/fs/Makefile.in b/zfs/include/sys/fs/Makefile.in
deleted file mode 100644 (file)
index 9799ebd..0000000
+++ /dev/null
@@ -1,754 +0,0 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
-# @configure_input@
-
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
-
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-@SET_MAKE@
-
-VPATH = @srcdir@
-am__is_gnu_make = { \
-  if test -z '$(MAKELEVEL)'; then \
-    false; \
-  elif test -n '$(MAKE_HOST)'; then \
-    true; \
-  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
-    true; \
-  else \
-    false; \
-  fi; \
-}
-am__make_running_with_option = \
-  case $${target_option-} in \
-      ?) ;; \
-      *) echo "am__make_running_with_option: internal error: invalid" \
-              "target option '$${target_option-}' specified" >&2; \
-         exit 1;; \
-  esac; \
-  has_opt=no; \
-  sane_makeflags=$$MAKEFLAGS; \
-  if $(am__is_gnu_make); then \
-    sane_makeflags=$$MFLAGS; \
-  else \
-    case $$MAKEFLAGS in \
-      *\\[\ \  ]*) \
-        bs=\\; \
-        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
-          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
-    esac; \
-  fi; \
-  skip_next=no; \
-  strip_trailopt () \
-  { \
-    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
-  }; \
-  for flg in $$sane_makeflags; do \
-    test $$skip_next = yes && { skip_next=no; continue; }; \
-    case $$flg in \
-      *=*|--*) continue;; \
-        -*I) strip_trailopt 'I'; skip_next=yes;; \
-      -*I?*) strip_trailopt 'I';; \
-        -*O) strip_trailopt 'O'; skip_next=yes;; \
-      -*O?*) strip_trailopt 'O';; \
-        -*l) strip_trailopt 'l'; skip_next=yes;; \
-      -*l?*) strip_trailopt 'l';; \
-      -[dEDm]) skip_next=yes;; \
-      -[JT]) skip_next=yes;; \
-    esac; \
-    case $$flg in \
-      *$$target_option*) has_opt=yes; break;; \
-    esac; \
-  done; \
-  test $$has_opt = yes
-am__make_dryrun = (target_option=n; $(am__make_running_with_option))
-am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
-pkgdatadir = $(datadir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
-install_sh_DATA = $(install_sh) -c -m 644
-install_sh_PROGRAM = $(install_sh) -c
-install_sh_SCRIPT = $(install_sh) -c
-INSTALL_HEADER = $(INSTALL_DATA)
-transform = $(program_transform_name)
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_triplet = @build@
-host_triplet = @host@
-target_triplet = @target@
-subdir = include/sys/fs
-ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/config/always-no-bool-compare.m4 \
-       $(top_srcdir)/config/always-no-unused-but-set-variable.m4 \
-       $(top_srcdir)/config/dkms.m4 \
-       $(top_srcdir)/config/kernel-acl.m4 \
-       $(top_srcdir)/config/kernel-automount.m4 \
-       $(top_srcdir)/config/kernel-bdev-block-device-operations.m4 \
-       $(top_srcdir)/config/kernel-bdev-logical-size.m4 \
-       $(top_srcdir)/config/kernel-bdev-physical-size.m4 \
-       $(top_srcdir)/config/kernel-bdi-setup-and-register.m4 \
-       $(top_srcdir)/config/kernel-bio-bvec-iter.m4 \
-       $(top_srcdir)/config/kernel-bio-end-io-t-args.m4 \
-       $(top_srcdir)/config/kernel-bio-failfast.m4 \
-       $(top_srcdir)/config/kernel-bio-op.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-barrier.m4 \
-       $(top_srcdir)/config/kernel-bio-rw-discard.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-flush.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-hw-sectors.m4 \
-       $(top_srcdir)/config/kernel-blk-queue-max-segments.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get-by-path.m4 \
-       $(top_srcdir)/config/kernel-blkdev-get.m4 \
-       $(top_srcdir)/config/kernel-block-device-operations-release-void.m4 \
-       $(top_srcdir)/config/kernel-check-disk-size-change.m4 \
-       $(top_srcdir)/config/kernel-clear-inode.m4 \
-       $(top_srcdir)/config/kernel-commit-metadata.m4 \
-       $(top_srcdir)/config/kernel-create-nameidata.m4 \
-       $(top_srcdir)/config/kernel-current_bio_tail.m4 \
-       $(top_srcdir)/config/kernel-d-make-root.m4 \
-       $(top_srcdir)/config/kernel-d-obtain-alias.m4 \
-       $(top_srcdir)/config/kernel-d-prune-aliases.m4 \
-       $(top_srcdir)/config/kernel-declare-event-class.m4 \
-       $(top_srcdir)/config/kernel-dentry-operations.m4 \
-       $(top_srcdir)/config/kernel-dirty-inode.m4 \
-       $(top_srcdir)/config/kernel-discard-granularity.m4 \
-       $(top_srcdir)/config/kernel-elevator-change.m4 \
-       $(top_srcdir)/config/kernel-encode-fh-inode.m4 \
-       $(top_srcdir)/config/kernel-evict-inode.m4 \
-       $(top_srcdir)/config/kernel-fallocate.m4 \
-       $(top_srcdir)/config/kernel-file-inode.m4 \
-       $(top_srcdir)/config/kernel-fmode-t.m4 \
-       $(top_srcdir)/config/kernel-follow-down-one.m4 \
-       $(top_srcdir)/config/kernel-fsync.m4 \
-       $(top_srcdir)/config/kernel-generic_io_acct.m4 \
-       $(top_srcdir)/config/kernel-get-disk-ro.m4 \
-       $(top_srcdir)/config/kernel-get-gendisk.m4 \
-       $(top_srcdir)/config/kernel-get-link.m4 \
-       $(top_srcdir)/config/kernel-insert-inode-locked.m4 \
-       $(top_srcdir)/config/kernel-invalidate-bdev-args.m4 \
-       $(top_srcdir)/config/kernel-is_owner_or_cap.m4 \
-       $(top_srcdir)/config/kernel-kmap-atomic-args.m4 \
-       $(top_srcdir)/config/kernel-kobj-name-len.m4 \
-       $(top_srcdir)/config/kernel-lookup-bdev.m4 \
-       $(top_srcdir)/config/kernel-lookup-nameidata.m4 \
-       $(top_srcdir)/config/kernel-lseek-execute.m4 \
-       $(top_srcdir)/config/kernel-mk-request-fn.m4 \
-       $(top_srcdir)/config/kernel-mkdir-umode-t.m4 \
-       $(top_srcdir)/config/kernel-mount-nodev.m4 \
-       $(top_srcdir)/config/kernel-open-bdev-exclusive.m4 \
-       $(top_srcdir)/config/kernel-put-link.m4 \
-       $(top_srcdir)/config/kernel-security-inode-init.m4 \
-       $(top_srcdir)/config/kernel-set-nlink.m4 \
-       $(top_srcdir)/config/kernel-sget-args.m4 \
-       $(top_srcdir)/config/kernel-show-options.m4 \
-       $(top_srcdir)/config/kernel-shrink.m4 \
-       $(top_srcdir)/config/kernel-submit_bio.m4 \
-       $(top_srcdir)/config/kernel-truncate-range.m4 \
-       $(top_srcdir)/config/kernel-truncate-setsize.m4 \
-       $(top_srcdir)/config/kernel-vfs-iterate.m4 \
-       $(top_srcdir)/config/kernel-vfs-rw-iterate.m4 \
-       $(top_srcdir)/config/kernel-xattr-handler.m4 \
-       $(top_srcdir)/config/kernel.m4 $(top_srcdir)/config/libtool.m4 \
-       $(top_srcdir)/config/ltoptions.m4 \
-       $(top_srcdir)/config/ltsugar.m4 \
-       $(top_srcdir)/config/ltversion.m4 \
-       $(top_srcdir)/config/lt~obsolete.m4 \
-       $(top_srcdir)/config/mount-helper.m4 \
-       $(top_srcdir)/config/user-arch.m4 \
-       $(top_srcdir)/config/user-dracut.m4 \
-       $(top_srcdir)/config/user-frame-larger-than.m4 \
-       $(top_srcdir)/config/user-libblkid.m4 \
-       $(top_srcdir)/config/user-libuuid.m4 \
-       $(top_srcdir)/config/user-runstatedir.m4 \
-       $(top_srcdir)/config/user-systemd.m4 \
-       $(top_srcdir)/config/user-sysvinit.m4 \
-       $(top_srcdir)/config/user-udev.m4 \
-       $(top_srcdir)/config/user-zlib.m4 $(top_srcdir)/config/user.m4 \
-       $(top_srcdir)/config/zfs-build.m4 \
-       $(top_srcdir)/config/zfs-meta.m4 $(top_srcdir)/configure.ac
-am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
-       $(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__kernel_HEADERS_DIST) \
-       $(am__libzfs_HEADERS_DIST) $(am__DIST_COMMON)
-mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/zfs_config.h
-CONFIG_CLEAN_FILES =
-CONFIG_CLEAN_VPATH_FILES =
-AM_V_P = $(am__v_P_@AM_V@)
-am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
-am__v_P_0 = false
-am__v_P_1 = :
-AM_V_GEN = $(am__v_GEN_@AM_V@)
-am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
-am__v_GEN_0 = @echo "  GEN     " $@;
-am__v_GEN_1 = 
-AM_V_at = $(am__v_at_@AM_V@)
-am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
-am__v_at_0 = @
-am__v_at_1 = 
-SOURCES =
-DIST_SOURCES =
-am__can_run_installinfo = \
-  case $$AM_UPDATE_INFO_DIR in \
-    n|no|NO) false;; \
-    *) (install-info --version) >/dev/null 2>&1;; \
-  esac
-am__kernel_HEADERS_DIST = $(top_srcdir)/include/sys/fs/zfs.h
-am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
-am__vpath_adj = case $$p in \
-    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
-    *) f=$$p;; \
-  esac;
-am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
-am__install_max = 40
-am__nobase_strip_setup = \
-  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
-am__nobase_strip = \
-  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
-am__nobase_list = $(am__nobase_strip_setup); \
-  for p in $$list; do echo "$$p $$p"; done | \
-  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
-  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
-    if (++n[$$2] == $(am__install_max)) \
-      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
-    END { for (dir in files) print dir, files[dir] }'
-am__base_list = \
-  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
-  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
-am__uninstall_files_from_dir = { \
-  test -z "$$files" \
-    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
-    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
-         $(am__cd) "$$dir" && rm -f $$files; }; \
-  }
-am__installdirs = "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"
-am__libzfs_HEADERS_DIST = $(top_srcdir)/include/sys/fs/zfs.h
-HEADERS = $(kernel_HEADERS) $(libzfs_HEADERS)
-am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
-# Read a list of newline-separated strings from the standard input,
-# and print each of them once, without duplicates.  Input order is
-# *not* preserved.
-am__uniquify_input = $(AWK) '\
-  BEGIN { nonempty = 0; } \
-  { items[$$0] = 1; nonempty = 1; } \
-  END { if (nonempty) { for (i in items) print i; }; } \
-'
-# Make sure the list of sources is unique.  This is necessary because,
-# e.g., the same source file might be shared among _SOURCES variables
-# for different programs/libraries.
-am__define_uniq_tagged_files = \
-  list='$(am__tagged_files)'; \
-  unique=`for i in $$list; do \
-    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
-  done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in
-DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
-ACLOCAL = @ACLOCAL@
-ALIEN = @ALIEN@
-ALIEN_VERSION = @ALIEN_VERSION@
-AMTAR = @AMTAR@
-AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
-AR = @AR@
-AUTOCONF = @AUTOCONF@
-AUTOHEADER = @AUTOHEADER@
-AUTOMAKE = @AUTOMAKE@
-AWK = @AWK@
-CC = @CC@
-CCAS = @CCAS@
-CCASDEPMODE = @CCASDEPMODE@
-CCASFLAGS = @CCASFLAGS@
-CCDEPMODE = @CCDEPMODE@
-CFLAGS = @CFLAGS@
-CPP = @CPP@
-CPPFLAGS = @CPPFLAGS@
-CYGPATH_W = @CYGPATH_W@
-DEBUG_CFLAGS = @DEBUG_CFLAGS@
-DEBUG_DMU_TX = @DEBUG_DMU_TX@
-DEBUG_STACKFLAGS = @DEBUG_STACKFLAGS@
-DEBUG_ZFS = @DEBUG_ZFS@
-DEFAULT_INITCONF_DIR = @DEFAULT_INITCONF_DIR@
-DEFAULT_INIT_DIR = @DEFAULT_INIT_DIR@
-DEFAULT_INIT_SCRIPT = @DEFAULT_INIT_SCRIPT@
-DEFAULT_PACKAGE = @DEFAULT_PACKAGE@
-DEFINE_INITRAMFS = @DEFINE_INITRAMFS@
-DEFS = @DEFS@
-DEPDIR = @DEPDIR@
-DLLTOOL = @DLLTOOL@
-DPKG = @DPKG@
-DPKGBUILD = @DPKGBUILD@
-DPKGBUILD_VERSION = @DPKGBUILD_VERSION@
-DPKG_VERSION = @DPKG_VERSION@
-DSYMUTIL = @DSYMUTIL@
-DUMPBIN = @DUMPBIN@
-ECHO_C = @ECHO_C@
-ECHO_N = @ECHO_N@
-ECHO_T = @ECHO_T@
-EGREP = @EGREP@
-EXEEXT = @EXEEXT@
-FGREP = @FGREP@
-FRAME_LARGER_THAN = @FRAME_LARGER_THAN@
-GREP = @GREP@
-HAVE_ALIEN = @HAVE_ALIEN@
-HAVE_DPKG = @HAVE_DPKG@
-HAVE_DPKGBUILD = @HAVE_DPKGBUILD@
-HAVE_RPM = @HAVE_RPM@
-HAVE_RPMBUILD = @HAVE_RPMBUILD@
-INSTALL = @INSTALL@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-KERNELCPPFLAGS = @KERNELCPPFLAGS@
-KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
-LD = @LD@
-LDFLAGS = @LDFLAGS@
-LIBBLKID = @LIBBLKID@
-LIBOBJS = @LIBOBJS@
-LIBS = @LIBS@
-LIBTOOL = @LIBTOOL@
-LIBUUID = @LIBUUID@
-LINUX = @LINUX@
-LINUX_OBJ = @LINUX_OBJ@
-LINUX_SYMBOLS = @LINUX_SYMBOLS@
-LINUX_VERSION = @LINUX_VERSION@
-LIPO = @LIPO@
-LN_S = @LN_S@
-LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-MAINT = @MAINT@
-MAKEINFO = @MAKEINFO@
-MANIFEST_TOOL = @MANIFEST_TOOL@
-MKDIR_P = @MKDIR_P@
-NM = @NM@
-NMEDIT = @NMEDIT@
-NO_BOOL_COMPARE = @NO_BOOL_COMPARE@
-NO_UNUSED_BUT_SET_VARIABLE = @NO_UNUSED_BUT_SET_VARIABLE@
-OBJDUMP = @OBJDUMP@
-OBJEXT = @OBJEXT@
-OTOOL = @OTOOL@
-OTOOL64 = @OTOOL64@
-PACKAGE = @PACKAGE@
-PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
-PACKAGE_NAME = @PACKAGE_NAME@
-PACKAGE_STRING = @PACKAGE_STRING@
-PACKAGE_TARNAME = @PACKAGE_TARNAME@
-PACKAGE_URL = @PACKAGE_URL@
-PACKAGE_VERSION = @PACKAGE_VERSION@
-PATH_SEPARATOR = @PATH_SEPARATOR@
-RANLIB = @RANLIB@
-RELEASE = @RELEASE@
-RPM = @RPM@
-RPMBUILD = @RPMBUILD@
-RPMBUILD_VERSION = @RPMBUILD_VERSION@
-RPM_DEFINE_COMMON = @RPM_DEFINE_COMMON@
-RPM_DEFINE_DKMS = @RPM_DEFINE_DKMS@
-RPM_DEFINE_KMOD = @RPM_DEFINE_KMOD@
-RPM_DEFINE_UTIL = @RPM_DEFINE_UTIL@
-RPM_SPEC_DIR = @RPM_SPEC_DIR@
-RPM_VERSION = @RPM_VERSION@
-SED = @SED@
-SET_MAKE = @SET_MAKE@
-SHELL = @SHELL@
-SPL = @SPL@
-SPL_OBJ = @SPL_OBJ@
-SPL_SYMBOLS = @SPL_SYMBOLS@
-SPL_VERSION = @SPL_VERSION@
-SRPM_DEFINE_COMMON = @SRPM_DEFINE_COMMON@
-SRPM_DEFINE_DKMS = @SRPM_DEFINE_DKMS@
-SRPM_DEFINE_KMOD = @SRPM_DEFINE_KMOD@
-SRPM_DEFINE_UTIL = @SRPM_DEFINE_UTIL@
-STRIP = @STRIP@
-TARGET_ASM_DIR = @TARGET_ASM_DIR@
-VENDOR = @VENDOR@
-VERSION = @VERSION@
-ZFS_CONFIG = @ZFS_CONFIG@
-ZFS_INIT_SYSTEMD = @ZFS_INIT_SYSTEMD@
-ZFS_INIT_SYSV = @ZFS_INIT_SYSV@
-ZFS_META_ALIAS = @ZFS_META_ALIAS@
-ZFS_META_AUTHOR = @ZFS_META_AUTHOR@
-ZFS_META_DATA = @ZFS_META_DATA@
-ZFS_META_LICENSE = @ZFS_META_LICENSE@
-ZFS_META_LT_AGE = @ZFS_META_LT_AGE@
-ZFS_META_LT_CURRENT = @ZFS_META_LT_CURRENT@
-ZFS_META_LT_REVISION = @ZFS_META_LT_REVISION@
-ZFS_META_NAME = @ZFS_META_NAME@
-ZFS_META_RELEASE = @ZFS_META_RELEASE@
-ZFS_META_VERSION = @ZFS_META_VERSION@
-ZFS_MODULE_LOAD = @ZFS_MODULE_LOAD@
-ZLIB = @ZLIB@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-abs_top_builddir = @abs_top_builddir@
-abs_top_srcdir = @abs_top_srcdir@
-ac_ct_AR = @ac_ct_AR@
-ac_ct_CC = @ac_ct_CC@
-ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
-am__include = @am__include@
-am__leading_dot = @am__leading_dot@
-am__quote = @am__quote@
-am__tar = @am__tar@
-am__untar = @am__untar@
-bindir = @bindir@
-build = @build@
-build_alias = @build_alias@
-build_cpu = @build_cpu@
-build_os = @build_os@
-build_vendor = @build_vendor@
-builddir = @builddir@
-datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dracutdir = @dracutdir@
-dvidir = @dvidir@
-exec_prefix = @exec_prefix@
-host = @host@
-host_alias = @host_alias@
-host_cpu = @host_cpu@
-host_os = @host_os@
-host_vendor = @host_vendor@
-htmldir = @htmldir@
-includedir = @includedir@
-infodir = @infodir@
-install_sh = @install_sh@
-libdir = @libdir@
-libexecdir = @libexecdir@
-localedir = @localedir@
-localstatedir = @localstatedir@
-mandir = @mandir@
-mkdir_p = @mkdir_p@
-modulesloaddir = @modulesloaddir@
-mounthelperdir = @mounthelperdir@
-oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
-prefix = @prefix@
-program_transform_name = @program_transform_name@
-psdir = @psdir@
-runstatedir = @runstatedir@
-sbindir = @sbindir@
-sharedstatedir = @sharedstatedir@
-srcdir = @srcdir@
-sysconfdir = @sysconfdir@
-systemdpresetdir = @systemdpresetdir@
-systemdunitdir = @systemdunitdir@
-target = @target@
-target_alias = @target_alias@
-target_cpu = @target_cpu@
-target_os = @target_os@
-target_vendor = @target_vendor@
-top_build_prefix = @top_build_prefix@
-top_builddir = @top_builddir@
-top_srcdir = @top_srcdir@
-udevdir = @udevdir@
-udevruledir = @udevruledir@
-COMMON_H = \
-       $(top_srcdir)/include/sys/fs/zfs.h
-
-KERNEL_H = 
-USER_H = 
-EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
-@CONFIG_USER_TRUE@libzfsdir = $(includedir)/libzfs/sys/fs
-@CONFIG_USER_TRUE@libzfs_HEADERS = $(COMMON_H) $(USER_H)
-@CONFIG_KERNEL_TRUE@kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/fs
-@CONFIG_KERNEL_TRUE@kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
-all: all-am
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
-       @for dep in $?; do \
-         case '$(am__configure_deps)' in \
-           *$$dep*) \
-             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
-               && { if test -f $@; then exit 0; else break; fi; }; \
-             exit 1;; \
-         esac; \
-       done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/sys/fs/Makefile'; \
-       $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu include/sys/fs/Makefile
-Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
-       @case '$?' in \
-         *config.status*) \
-           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
-         *) \
-           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
-           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
-       esac;
-
-$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
-       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(am__aclocal_m4_deps):
-
-mostlyclean-libtool:
-       -rm -f *.lo
-
-clean-libtool:
-       -rm -rf .libs _libs
-install-kernelHEADERS: $(kernel_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(kerneldir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(kerneldir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(kerneldir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(kerneldir)" || exit $$?; \
-       done
-
-uninstall-kernelHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(kernel_HEADERS)'; test -n "$(kerneldir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(kerneldir)'; $(am__uninstall_files_from_dir)
-install-libzfsHEADERS: $(libzfs_HEADERS)
-       @$(NORMAL_INSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       if test -n "$$list"; then \
-         echo " $(MKDIR_P) '$(DESTDIR)$(libzfsdir)'"; \
-         $(MKDIR_P) "$(DESTDIR)$(libzfsdir)" || exit 1; \
-       fi; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libzfsdir)'"; \
-         $(INSTALL_HEADER) $$files "$(DESTDIR)$(libzfsdir)" || exit $$?; \
-       done
-
-uninstall-libzfsHEADERS:
-       @$(NORMAL_UNINSTALL)
-       @list='$(libzfs_HEADERS)'; test -n "$(libzfsdir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(libzfsdir)'; $(am__uninstall_files_from_dir)
-
-ID: $(am__tagged_files)
-       $(am__define_uniq_tagged_files); mkid -fID $$unique
-tags: tags-am
-TAGS: tags
-
-tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       set x; \
-       here=`pwd`; \
-       $(am__define_uniq_tagged_files); \
-       shift; \
-       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
-         test -n "$$unique" || unique=$$empty_fix; \
-         if test $$# -gt 0; then \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             "$$@" $$unique; \
-         else \
-           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
-             $$unique; \
-         fi; \
-       fi
-ctags: ctags-am
-
-CTAGS: ctags
-ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
-       $(am__define_uniq_tagged_files); \
-       test -z "$(CTAGS_ARGS)$$unique" \
-         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
-            $$unique
-
-GTAGS:
-       here=`$(am__cd) $(top_builddir) && pwd` \
-         && $(am__cd) $(top_srcdir) \
-         && gtags -i $(GTAGS_ARGS) "$$here"
-cscopelist: cscopelist-am
-
-cscopelist-am: $(am__tagged_files)
-       list='$(am__tagged_files)'; \
-       case "$(srcdir)" in \
-         [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
-         *) sdir=$(subdir)/$(srcdir) ;; \
-       esac; \
-       for i in $$list; do \
-         if test -f "$$i"; then \
-           echo "$(subdir)/$$i"; \
-         else \
-           echo "$$sdir/$$i"; \
-         fi; \
-       done >> $(top_builddir)/cscope.files
-
-distclean-tags:
-       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
-distdir: $(DISTFILES)
-       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
-       list='$(DISTFILES)'; \
-         dist_files=`for file in $$list; do echo $$file; done | \
-         sed -e "s|^$$srcdirstrip/||;t" \
-             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
-       case $$dist_files in \
-         */*) $(MKDIR_P) `echo "$$dist_files" | \
-                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
-                          sort -u` ;; \
-       esac; \
-       for file in $$dist_files; do \
-         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
-         if test -d $$d/$$file; then \
-           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
-           if test -d "$(distdir)/$$file"; then \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
-             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
-             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
-           fi; \
-           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
-         else \
-           test -f "$(distdir)/$$file" \
-           || cp -p $$d/$$file "$(distdir)/$$file" \
-           || exit 1; \
-         fi; \
-       done
-check-am: all-am
-check: check-am
-all-am: Makefile $(HEADERS)
-installdirs:
-       for dir in "$(DESTDIR)$(kerneldir)" "$(DESTDIR)$(libzfsdir)"; do \
-         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
-       done
-install: install-am
-install-exec: install-exec-am
-install-data: install-data-am
-uninstall: uninstall-am
-
-install-am: all-am
-       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
-
-installcheck: installcheck-am
-install-strip:
-       if test -z '$(STRIP)'; then \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-             install; \
-       else \
-         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
-       fi
-mostlyclean-generic:
-
-clean-generic:
-
-distclean-generic:
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-
-maintainer-clean-generic:
-       @echo "This command is intended for maintainers to use"
-       @echo "it deletes files that may require special tools to rebuild."
-clean: clean-am
-
-clean-am: clean-generic clean-libtool mostlyclean-am
-
-distclean: distclean-am
-       -rm -f Makefile
-distclean-am: clean-am distclean-generic distclean-tags
-
-dvi: dvi-am
-
-dvi-am:
-
-html: html-am
-
-html-am:
-
-info: info-am
-
-info-am:
-
-install-data-am: install-kernelHEADERS install-libzfsHEADERS
-
-install-dvi: install-dvi-am
-
-install-dvi-am:
-
-install-exec-am:
-
-install-html: install-html-am
-
-install-html-am:
-
-install-info: install-info-am
-
-install-info-am:
-
-install-man:
-
-install-pdf: install-pdf-am
-
-install-pdf-am:
-
-install-ps: install-ps-am
-
-install-ps-am:
-
-installcheck-am:
-
-maintainer-clean: maintainer-clean-am
-       -rm -f Makefile
-maintainer-clean-am: distclean-am maintainer-clean-generic
-
-mostlyclean: mostlyclean-am
-
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
-
-pdf: pdf-am
-
-pdf-am:
-
-ps: ps-am
-
-ps-am:
-
-uninstall-am: uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.MAKE: install-am install-strip
-
-.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
-       clean-libtool cscopelist-am ctags ctags-am distclean \
-       distclean-generic distclean-libtool distclean-tags distdir dvi \
-       dvi-am html html-am info info-am install install-am \
-       install-data install-data-am install-dvi install-dvi-am \
-       install-exec install-exec-am install-html install-html-am \
-       install-info install-info-am install-kernelHEADERS \
-       install-libzfsHEADERS install-man install-pdf install-pdf-am \
-       install-ps install-ps-am install-strip installcheck \
-       installcheck-am installdirs maintainer-clean \
-       maintainer-clean-generic mostlyclean mostlyclean-generic \
-       mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
-       uninstall-am uninstall-kernelHEADERS uninstall-libzfsHEADERS
-
-.PRECIOUS: Makefile
-
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index 57bf55f9365f5a8ce20da4b5549c1d3b85f7d3bb..d1d0a275d1f56d13580ec3445113805da699aba2 100644 (file)
@@ -32,6 +32,7 @@
 #define        _SYS_FS_ZFS_H
 
 #include <sys/time.h>
+#include <sys/zio_priority.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -66,6 +67,9 @@ typedef enum dmu_objset_type {
 #define        ZFS_TYPE_DATASET        \
        (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME | ZFS_TYPE_SNAPSHOT)
 
+/*
+ * All of these include the terminating NUL byte.
+ */
 #define        ZAP_MAXNAMELEN 256
 #define        ZAP_MAXVALUELEN (1024 * 8)
 #define        ZAP_OLDMAXVALUELEN 1024
@@ -137,6 +141,7 @@ typedef enum {
        ZFS_PROP_DEDUP,
        ZFS_PROP_MLSLABEL,
        ZFS_PROP_SYNC,
+       ZFS_PROP_DNODESIZE,
        ZFS_PROP_REFRATIO,
        ZFS_PROP_WRITTEN,
        ZFS_PROP_CLONES,
@@ -156,6 +161,8 @@ typedef enum {
        ZFS_PROP_RELATIME,
        ZFS_PROP_REDUNDANT_METADATA,
        ZFS_PROP_OVERLAY,
+       ZFS_PROP_PREV_SNAP,
+       ZFS_PROP_RECEIVE_RESUME_TOKEN,
        ZFS_NUM_PROPS
 } zfs_prop_t;
 
@@ -164,6 +171,10 @@ typedef enum {
        ZFS_PROP_USERQUOTA,
        ZFS_PROP_GROUPUSED,
        ZFS_PROP_GROUPQUOTA,
+       ZFS_PROP_USEROBJUSED,
+       ZFS_PROP_USEROBJQUOTA,
+       ZFS_PROP_GROUPOBJUSED,
+       ZFS_PROP_GROUPOBJQUOTA,
        ZFS_NUM_USERQUOTA_PROPS
 } zfs_userquota_prop_t;
 
@@ -203,6 +214,7 @@ typedef enum {
        ZPOOL_PROP_LEAKED,
        ZPOOL_PROP_MAXBLOCKSIZE,
        ZPOOL_PROP_TNAME,
+       ZPOOL_PROP_MAXDNODESIZE,
        ZPOOL_NUM_PROPS
 } zpool_prop_t;
 
@@ -228,6 +240,7 @@ typedef enum {
 
 #define        ZPROP_SOURCE_VAL_RECVD  "$recvd"
 #define        ZPROP_N_MORE_ERRORS     "N_MORE_ERRORS"
+
 /*
  * Dataset flag implemented as a special entry in the props zap object
  * indicating that the dataset has received properties on or after
@@ -360,6 +373,16 @@ typedef enum {
        ZFS_XATTR_SA = 2
 } zfs_xattr_type_t;
 
+typedef enum {
+       ZFS_DNSIZE_LEGACY = 0,
+       ZFS_DNSIZE_AUTO = 1,
+       ZFS_DNSIZE_1K = 1024,
+       ZFS_DNSIZE_2K = 2048,
+       ZFS_DNSIZE_4K = 4096,
+       ZFS_DNSIZE_8K = 8192,
+       ZFS_DNSIZE_16K = 16384
+} zfs_dnsize_type_t;
+
 typedef enum {
        ZFS_REDUNDANT_METADATA_ALL,
        ZFS_REDUNDANT_METADATA_MOST
@@ -528,6 +551,50 @@ typedef struct zpool_rewind_policy {
 #define        ZPOOL_CONFIG_DTL                "DTL"
 #define        ZPOOL_CONFIG_SCAN_STATS         "scan_stats"    /* not stored on disk */
 #define        ZPOOL_CONFIG_VDEV_STATS         "vdev_stats"    /* not stored on disk */
+
+/* container nvlist of extended stats */
+#define        ZPOOL_CONFIG_VDEV_STATS_EX      "vdev_stats_ex"
+
+/* Active queue read/write stats */
+#define        ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE   "vdev_sync_r_active_queue"
+#define        ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE   "vdev_sync_w_active_queue"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE  "vdev_async_r_active_queue"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE  "vdev_async_w_active_queue"
+#define        ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE    "vdev_async_scrub_active_queue"
+
+/* Queue sizes */
+#define        ZPOOL_CONFIG_VDEV_SYNC_R_PEND_QUEUE     "vdev_sync_r_pend_queue"
+#define        ZPOOL_CONFIG_VDEV_SYNC_W_PEND_QUEUE     "vdev_sync_w_pend_queue"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_R_PEND_QUEUE    "vdev_async_r_pend_queue"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_W_PEND_QUEUE    "vdev_async_w_pend_queue"
+#define        ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE      "vdev_async_scrub_pend_queue"
+
+/* Latency read/write histogram stats */
+#define        ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO       "vdev_tot_r_lat_histo"
+#define        ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO       "vdev_tot_w_lat_histo"
+#define        ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO      "vdev_disk_r_lat_histo"
+#define        ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO      "vdev_disk_w_lat_histo"
+#define        ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO      "vdev_sync_r_lat_histo"
+#define        ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO      "vdev_sync_w_lat_histo"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO     "vdev_async_r_lat_histo"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO     "vdev_async_w_lat_histo"
+#define        ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO       "vdev_scrub_histo"
+
+/* Request size histograms */
+#define        ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO      "vdev_sync_ind_r_histo"
+#define        ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO      "vdev_sync_ind_w_histo"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO     "vdev_async_ind_r_histo"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO     "vdev_async_ind_w_histo"
+#define        ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO       "vdev_ind_scrub_histo"
+#define        ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO      "vdev_sync_agg_r_histo"
+#define        ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO      "vdev_sync_agg_w_histo"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO     "vdev_async_agg_r_histo"
+#define        ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO     "vdev_async_agg_w_histo"
+#define        ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO       "vdev_agg_scrub_histo"
+
+/* vdev enclosure sysfs path */
+#define        ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH        "vdev_enc_sysfs_path"
+
 #define        ZPOOL_CONFIG_WHOLE_DISK         "whole_disk"
 #define        ZPOOL_CONFIG_ERRCOUNT           "error_count"
 #define        ZPOOL_CONFIG_NOT_PRESENT        "not_present"
@@ -566,6 +633,9 @@ typedef struct zpool_rewind_policy {
 #define        ZPOOL_CONFIG_FEATURES_FOR_READ  "features_for_read"
 #define        ZPOOL_CONFIG_FEATURE_STATS      "feature_stats" /* not stored on disk */
 #define        ZPOOL_CONFIG_ERRATA             "errata"        /* not stored on disk */
+#define        ZPOOL_CONFIG_VDEV_TOP_ZAP       "com.delphix:vdev_zap_top"
+#define        ZPOOL_CONFIG_VDEV_LEAF_ZAP      "com.delphix:vdev_zap_leaf"
+#define        ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS  "com.delphix:has_per_vdev_zaps"
 /*
  * The persistent vdev state is stored as separate values rather than a single
  * 'vdev_state' entry.  This is because a device can be in multiple states, such
@@ -763,8 +833,62 @@ typedef struct vdev_stat {
        uint64_t        vs_scan_removing;       /* removing?    */
        uint64_t        vs_scan_processed;      /* scan processed bytes */
        uint64_t        vs_fragmentation;       /* device fragmentation */
+
 } vdev_stat_t;
 
+/*
+ * Extended stats
+ *
+ * These are stats which aren't included in the original iostat output.  For
+ * convenience, they are grouped together in vdev_stat_ex, although each stat
+ * is individually exported as an nvlist.
+ */
+typedef struct vdev_stat_ex {
+       /* Number of ZIOs issued to disk and waiting to finish */
+       uint64_t vsx_active_queue[ZIO_PRIORITY_NUM_QUEUEABLE];
+
+       /* Number of ZIOs pending to be issued to disk */
+       uint64_t vsx_pend_queue[ZIO_PRIORITY_NUM_QUEUEABLE];
+
+       /*
+        * Below are the histograms for various latencies. Buckets are in
+        * units of nanoseconds.
+        */
+
+       /*
+        * 2^37 nanoseconds = 134s. Timeouts will probably start kicking in
+        * before this.
+        */
+#define        VDEV_L_HISTO_BUCKETS 37         /* Latency histo buckets */
+#define        VDEV_RQ_HISTO_BUCKETS 25        /* Request size histo buckets */
+
+
+       /* Amount of time in ZIO queue (ns) */
+       uint64_t vsx_queue_histo[ZIO_PRIORITY_NUM_QUEUEABLE]
+           [VDEV_L_HISTO_BUCKETS];
+
+       /* Total ZIO latency (ns).  Includes queuing and disk access time */
+       uint64_t vsx_total_histo[ZIO_TYPES][VDEV_L_HISTO_BUCKETS];
+
+       /* Amount of time to read/write the disk (ns) */
+       uint64_t vsx_disk_histo[ZIO_TYPES][VDEV_L_HISTO_BUCKETS];
+
+       /* "lookup the bucket for a value" histogram macros */
+#define        HISTO(val, buckets) (val != 0 ? MIN(highbit64(val) - 1, \
+           buckets - 1) : 0)
+#define        L_HISTO(a) HISTO(a, VDEV_L_HISTO_BUCKETS)
+#define        RQ_HISTO(a) HISTO(a, VDEV_RQ_HISTO_BUCKETS)
+
+       /* Physical IO histogram */
+       uint64_t vsx_ind_histo[ZIO_PRIORITY_NUM_QUEUEABLE]
+           [VDEV_RQ_HISTO_BUCKETS];
+
+       /* Delegated (aggregated) physical IO histogram */
+       uint64_t vsx_agg_histo[ZIO_PRIORITY_NUM_QUEUEABLE]
+           [VDEV_RQ_HISTO_BUCKETS];
+
+} vdev_stat_ex_t;
+
 /*
  * DDT statistics.  Note: all fields should be 64-bit because this
  * is passed between kernel and userland as an nvlist uint64 array.
@@ -811,7 +935,7 @@ typedef struct ddt_histogram {
  */
 typedef enum zfs_ioc {
        /*
-        * Illumos - 70/128 numbers reserved.
+        * Illumos - 71/128 numbers reserved.
         */
        ZFS_IOC_FIRST = ('Z' << 8),
        ZFS_IOC = ZFS_IOC_FIRST,
@@ -885,6 +1009,7 @@ typedef enum zfs_ioc {
        ZFS_IOC_BOOKMARK,
        ZFS_IOC_GET_BOOKMARKS,
        ZFS_IOC_DESTROY_BOOKMARKS,
+       ZFS_IOC_RECV_NEW,
 
        /*
         * Linux - 3/64 numbers reserved.
@@ -905,7 +1030,7 @@ typedef enum zfs_ioc {
 /*
  * zvol ioctl to get dataset name
  */
-#define        BLKZNAME                _IOR(0x12, 125, char[ZFS_MAXNAMELEN])
+#define        BLKZNAME                _IOR(0x12, 125, char[ZFS_MAX_DATASET_NAME_LEN])
 
 /*
  * Internal SPA load state.  Used by FMA diagnosis engine.
@@ -916,7 +1041,8 @@ typedef enum {
        SPA_LOAD_IMPORT,        /* import in progress   */
        SPA_LOAD_TRYIMPORT,     /* tryimport in progress */
        SPA_LOAD_RECOVER,       /* recovery requested   */
-       SPA_LOAD_ERROR          /* load failed          */
+       SPA_LOAD_ERROR,         /* load failed          */
+       SPA_LOAD_CREATE         /* creation in progress */
 } spa_load_state_t;
 
 /*
index 5f831a1f5604d9602c78fb625a369b8b27d83b35..408f6d333fb452eff69c92d9d8bce6e30474f94f 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 #ifndef _SYS_METASLAB_H
@@ -55,15 +55,16 @@ void metaslab_sync_done(metaslab_t *, uint64_t);
 void metaslab_sync_reassess(metaslab_group_t *);
 uint64_t metaslab_block_maxsize(metaslab_t *);
 
-#define        METASLAB_HINTBP_FAVOR   0x0
-#define        METASLAB_HINTBP_AVOID   0x1
-#define        METASLAB_GANG_HEADER    0x2
-#define        METASLAB_GANG_CHILD     0x4
-#define        METASLAB_GANG_AVOID     0x8
-#define        METASLAB_FASTWRITE      0x10
+#define        METASLAB_HINTBP_FAVOR           0x0
+#define        METASLAB_HINTBP_AVOID           0x1
+#define        METASLAB_GANG_HEADER            0x2
+#define        METASLAB_GANG_CHILD             0x4
+#define        METASLAB_ASYNC_ALLOC            0x8
+#define        METASLAB_DONT_THROTTLE          0x10
+#define        METASLAB_FASTWRITE              0x20
 
 int metaslab_alloc(spa_t *, metaslab_class_t *, uint64_t,
-    blkptr_t *, int, uint64_t, blkptr_t *, int);
+    blkptr_t *, int, uint64_t, blkptr_t *, int, zio_t *);
 void metaslab_free(spa_t *, const blkptr_t *, uint64_t, boolean_t);
 int metaslab_claim(spa_t *, const blkptr_t *, uint64_t);
 void metaslab_check_free(spa_t *, const blkptr_t *);
@@ -76,6 +77,9 @@ int metaslab_class_validate(metaslab_class_t *);
 void metaslab_class_histogram_verify(metaslab_class_t *);
 uint64_t metaslab_class_fragmentation(metaslab_class_t *);
 uint64_t metaslab_class_expandable_space(metaslab_class_t *);
+boolean_t metaslab_class_throttle_reserve(metaslab_class_t *, int,
+    zio_t *, int);
+void metaslab_class_throttle_unreserve(metaslab_class_t *, int, zio_t *);
 
 void metaslab_class_space_update(metaslab_class_t *, int64_t, int64_t,
     int64_t, int64_t);
@@ -88,10 +92,13 @@ metaslab_group_t *metaslab_group_create(metaslab_class_t *, vdev_t *);
 void metaslab_group_destroy(metaslab_group_t *);
 void metaslab_group_activate(metaslab_group_t *);
 void metaslab_group_passivate(metaslab_group_t *);
+boolean_t metaslab_group_initialized(metaslab_group_t *);
 uint64_t metaslab_group_get_space(metaslab_group_t *);
 void metaslab_group_histogram_verify(metaslab_group_t *);
 uint64_t metaslab_group_fragmentation(metaslab_group_t *);
 void metaslab_group_histogram_remove(metaslab_group_t *, metaslab_t *);
+void metaslab_group_alloc_decrement(spa_t *, uint64_t, void *, int);
+void metaslab_group_alloc_verify(spa_t *, const blkptr_t *, void *);
 
 #ifdef __cplusplus
 }
index 88bda071fa739e424aad8518165b3712c686e332..1c8993aca55ab0e9ceec1e3f20ede2c679efa8e4 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 #ifndef _SYS_METASLAB_IMPL_H
@@ -59,17 +59,47 @@ extern "C" {
  * to use a block allocator that best suits that class.
  */
 struct metaslab_class {
+       kmutex_t                mc_lock;
        spa_t                   *mc_spa;
        metaslab_group_t        *mc_rotor;
        metaslab_ops_t          *mc_ops;
        uint64_t                mc_aliquot;
+
+       /*
+        * Track the number of metaslab groups that have been initialized
+        * and can accept allocations. An initialized metaslab group is
+        * one has been completely added to the config (i.e. we have
+        * updated the MOS config and the space has been added to the pool).
+        */
+       uint64_t                mc_groups;
+
+       /*
+        * Toggle to enable/disable the allocation throttle.
+        */
+       boolean_t               mc_alloc_throttle_enabled;
+
+       /*
+        * The allocation throttle works on a reservation system. Whenever
+        * an asynchronous zio wants to perform an allocation it must
+        * first reserve the number of blocks that it wants to allocate.
+        * If there aren't sufficient slots available for the pending zio
+        * then that I/O is throttled until more slots free up. The current
+        * number of reserved allocations is maintained by the mc_alloc_slots
+        * refcount. The mc_alloc_max_slots value determines the maximum
+        * number of allocations that the system allows. Gang blocks are
+        * allowed to reserve slots even if we've reached the maximum
+        * number of allocations allowed.
+        */
+       uint64_t                mc_alloc_max_slots;
+       refcount_t              mc_alloc_slots;
+
        uint64_t                mc_alloc_groups; /* # of allocatable groups */
+
        uint64_t                mc_alloc;       /* total allocated space */
        uint64_t                mc_deferred;    /* total deferred frees */
        uint64_t                mc_space;       /* total space (alloc + free) */
        uint64_t                mc_dspace;      /* total deflated space */
        uint64_t                mc_histogram[RANGE_TREE_HISTOGRAM_SIZE];
-       kmutex_t                mc_fastwrite_lock;
 };
 
 /*
@@ -86,6 +116,15 @@ struct metaslab_group {
        avl_tree_t              mg_metaslab_tree;
        uint64_t                mg_aliquot;
        boolean_t               mg_allocatable;         /* can we allocate? */
+
+       /*
+        * A metaslab group is considered to be initialized only after
+        * we have updated the MOS config and added the space to the pool.
+        * We only allow allocation attempts to a metaslab group if it
+        * has been initialized.
+        */
+       boolean_t               mg_initialized;
+
        uint64_t                mg_free_capacity;       /* percentage free */
        int64_t                 mg_bias;
        int64_t                 mg_activation_count;
@@ -94,6 +133,27 @@ struct metaslab_group {
        taskq_t                 *mg_taskq;
        metaslab_group_t        *mg_prev;
        metaslab_group_t        *mg_next;
+
+       /*
+        * Each metaslab group can handle mg_max_alloc_queue_depth allocations
+        * which are tracked by mg_alloc_queue_depth. It's possible for a
+        * metaslab group to handle more allocations than its max. This
+        * can occur when gang blocks are required or when other groups
+        * are unable to handle their share of allocations.
+        */
+       uint64_t                mg_max_alloc_queue_depth;
+       refcount_t              mg_alloc_queue_depth;
+
+       /*
+        * A metalab group that can no longer allocate the minimum block
+        * size will set mg_no_free_space. Once a metaslab group is out
+        * of space then its share of work must be distributed to other
+        * groups.
+        */
+       boolean_t               mg_no_free_space;
+
+       uint64_t                mg_allocations;
+       uint64_t                mg_failed_allocations;
        uint64_t                mg_fragmentation;
        uint64_t                mg_histogram[RANGE_TREE_HISTOGRAM_SIZE];
 };
index 7284f05b1db22120a523a5758c647826073f2aaf..fac751b462bc41bba65d384cd50c41f43545e725 100644 (file)
@@ -68,8 +68,9 @@
 #define        MNTOPT_NOFAIL   "nofail"        /* no failure */
 #define        MNTOPT_RELATIME "relatime"      /* allow relative time updates */
 #define        MNTOPT_NORELATIME "norelatime"  /* do not allow relative time updates */
-#define        MNTOPT_DFRATIME "strictatime"   /* Deferred access time updates */
-#define        MNTOPT_NODFRATIME "nostrictatime" /* No Deferred access time updates */
+#define        MNTOPT_STRICTATIME "strictatime" /* strict access time updates */
+#define        MNTOPT_NOSTRICTATIME "nostrictatime" /* No strict access time updates */
+#define        MNTOPT_LAZYTIME "lazytime"      /* Defer access time writing */
 #define        MNTOPT_SETUID   "suid"          /* Both setuid and devices allowed */
 #define        MNTOPT_NOSETUID "nosuid"        /* Neither setuid nor devices allowed */
 #define        MNTOPT_OWNER    "owner"         /* allow owner mount */
diff --git a/zfs/include/sys/pathname.h b/zfs/include/sys/pathname.h
new file mode 100644 (file)
index 0000000..5db69b1
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*     Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
+/*       All Rights Reserved   */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ifndef _SYS_PATHNAME_H
+#define        _SYS_PATHNAME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Pathname structure.
+ * System calls that operate on path names gather the path name
+ * from the system call into this structure and reduce it by
+ * peeling off translated components.  If a symbolic link is
+ * encountered the new path name to be translated is also
+ * assembled in this structure.
+ *
+ * By convention pn_buf is not changed once it's been set to point
+ * to the underlying storage; routines which manipulate the pathname
+ * do so by changing pn_path and pn_pathlen.  pn_pathlen is redundant
+ * since the path name is null-terminated, but is provided to make
+ * some computations faster.
+ */
+typedef struct pathname {
+       char    *pn_buf;                /* underlying storage */
+       char    *pn_path;               /* remaining pathname */
+       size_t  pn_pathlen;             /* remaining length */
+       size_t  pn_bufsize;             /* total size of pn_buf */
+} pathname_t;
+
+extern void    pn_alloc(struct pathname *);
+extern void    pn_alloc_sz(struct pathname *, size_t);
+extern void    pn_free(struct pathname *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_PATHNAME_H */
diff --git a/zfs/include/sys/policy.h b/zfs/include/sys/policy.h
new file mode 100644 (file)
index 0000000..23d7d4d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2016, Lawrence Livermore National Security, LLC.
+ */
+
+#ifndef _SYS_POLICY_H
+#define        _SYS_POLICY_H
+
+#ifdef _KERNEL
+
+#include <sys/cred.h>
+#include <sys/types.h>
+#include <sys/xvattr.h>
+#include <sys/zpl.h>
+
+int secpolicy_nfs(const cred_t *);
+int secpolicy_sys_config(const cred_t *, boolean_t);
+int secpolicy_vnode_access2(const cred_t *, struct inode *,
+    uid_t, mode_t, mode_t);
+int secpolicy_vnode_any_access(const cred_t *, struct inode *, uid_t);
+int secpolicy_vnode_chown(const cred_t *, uid_t);
+int secpolicy_vnode_create_gid(const cred_t *);
+int secpolicy_vnode_remove(const cred_t *);
+int secpolicy_vnode_setdac(const cred_t *, uid_t);
+int secpolicy_vnode_setid_retain(const cred_t *, boolean_t);
+int secpolicy_vnode_setids_setgids(const cred_t *, gid_t);
+int secpolicy_zinject(const cred_t *);
+int secpolicy_zfs(const cred_t *);
+void secpolicy_setid_clear(vattr_t *, cred_t *);
+int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *,
+    const vattr_t *, cred_t *);
+int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, vtype_t);
+int secpolicy_vnode_setattr(cred_t *, struct inode *, struct vattr *,
+    const struct vattr *, int, int (void *, int, cred_t *), void *);
+int secpolicy_basic_link(const cred_t *);
+
+#endif /* _KERNEL */
+#endif /* _SYS_POLICY_H */
index e767a2389dab1c38d027ef8235b046e19c4ec747..3f50cddb6f5114af8d0342adcb499c1ab4a0a1d0 100644 (file)
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #ifndef        _SYS_REFCOUNT_H
@@ -53,14 +54,15 @@ typedef struct refcount {
        boolean_t rc_tracked;
        list_t rc_list;
        list_t rc_removed;
-       int64_t rc_count;
-       int64_t rc_removed_count;
+       uint64_t rc_count;
+       uint64_t rc_removed_count;
 } refcount_t;
 
 /* Note: refcount_t must be initialized with refcount_create[_untracked]() */
 
 void refcount_create(refcount_t *rc);
 void refcount_create_untracked(refcount_t *rc);
+void refcount_create_tracked(refcount_t *rc);
 void refcount_destroy(refcount_t *rc);
 void refcount_destroy_many(refcount_t *rc, uint64_t number);
 int refcount_is_zero(refcount_t *rc);
@@ -70,6 +72,9 @@ int64_t refcount_remove(refcount_t *rc, void *holder_tag);
 int64_t refcount_add_many(refcount_t *rc, uint64_t number, void *holder_tag);
 int64_t refcount_remove_many(refcount_t *rc, uint64_t number, void *holder_tag);
 void refcount_transfer(refcount_t *dst, refcount_t *src);
+void refcount_transfer_ownership(refcount_t *, void *, void *);
+boolean_t refcount_held(refcount_t *, void *);
+boolean_t refcount_not_held(refcount_t *, void *);
 
 void refcount_init(void);
 void refcount_fini(void);
@@ -82,12 +87,13 @@ typedef struct refcount {
 
 #define        refcount_create(rc) ((rc)->rc_count = 0)
 #define        refcount_create_untracked(rc) ((rc)->rc_count = 0)
+#define        refcount_create_tracked(rc) ((rc)->rc_count = 0)
 #define        refcount_destroy(rc) ((rc)->rc_count = 0)
 #define        refcount_destroy_many(rc, number) ((rc)->rc_count = 0)
 #define        refcount_is_zero(rc) ((rc)->rc_count == 0)
 #define        refcount_count(rc) ((rc)->rc_count)
-#define        refcount_add(rc, holder) atomic_add_64_nv(&(rc)->rc_count, 1)
-#define        refcount_remove(rc, holder) atomic_add_64_nv(&(rc)->rc_count, -1)
+#define        refcount_add(rc, holder) atomic_inc_64_nv(&(rc)->rc_count)
+#define        refcount_remove(rc, holder) atomic_dec_64_nv(&(rc)->rc_count)
 #define        refcount_add_many(rc, number, holder) \
        atomic_add_64_nv(&(rc)->rc_count, number)
 #define        refcount_remove_many(rc, number, holder) \
@@ -97,6 +103,9 @@ typedef struct refcount {
        atomic_add_64(&(src)->rc_count, -__tmp); \
        atomic_add_64(&(dst)->rc_count, __tmp); \
 }
+#define        refcount_transfer_ownership(rc, current_holder, new_holder)     (void)0
+#define        refcount_held(rc, holder)               ((rc)->rc_count > 0)
+#define        refcount_not_held(rc, holder)           (B_TRUE)
 
 #define        refcount_init()
 #define        refcount_fini()
index 6f2f1db6dcf9fdce2d7c6e6769305c94ad5afc6c..b68b7610b25e2d82962807fa33923c72791badda 100644 (file)
@@ -235,7 +235,7 @@ struct sa_handle {
 #define        SA_BONUSTYPE_FROM_DB(db) \
        (dmu_get_bonustype((dmu_buf_t *)db))
 
-#define        SA_BLKPTR_SPACE (DN_MAX_BONUSLEN - sizeof (blkptr_t))
+#define        SA_BLKPTR_SPACE (DN_OLD_MAX_BONUSLEN - sizeof (blkptr_t))
 
 #define        SA_LAYOUT_NUM(x, type) \
        ((!IS_SA_BONUSTYPE(type) ? 0 : (((IS_SA_BONUSTYPE(type)) && \
diff --git a/zfs/include/sys/sha2.h b/zfs/include/sys/sha2.h
new file mode 100644 (file)
index 0000000..9039835
--- /dev/null
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright 2013 Saso Kiselkov.  All rights reserved. */
+
+#ifndef _SYS_SHA2_H
+#define        _SYS_SHA2_H
+
+#ifdef  _KERNEL
+#include <sys/types.h>         /* for uint_* */
+#else
+#include <stdint.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        SHA2_HMAC_MIN_KEY_LEN   1       /* SHA2-HMAC min key length in bytes */
+#define        SHA2_HMAC_MAX_KEY_LEN   INT_MAX /* SHA2-HMAC max key length in bytes */
+
+#define        SHA256_DIGEST_LENGTH    32      /* SHA256 digest length in bytes */
+#define        SHA384_DIGEST_LENGTH    48      /* SHA384 digest length in bytes */
+#define        SHA512_DIGEST_LENGTH    64      /* SHA512 digest length in bytes */
+
+/* Truncated versions of SHA-512 according to FIPS-180-4, section 5.3.6 */
+#define        SHA512_224_DIGEST_LENGTH        28      /* SHA512/224 digest length */
+#define        SHA512_256_DIGEST_LENGTH        32      /* SHA512/256 digest length */
+
+#define        SHA256_HMAC_BLOCK_SIZE  64      /* SHA256-HMAC block size */
+#define        SHA512_HMAC_BLOCK_SIZE  128     /* SHA512-HMAC block size */
+
+#define        SHA256                  0
+#define        SHA256_HMAC             1
+#define        SHA256_HMAC_GEN         2
+#define        SHA384                  3
+#define        SHA384_HMAC             4
+#define        SHA384_HMAC_GEN         5
+#define        SHA512                  6
+#define        SHA512_HMAC             7
+#define        SHA512_HMAC_GEN         8
+#define        SHA512_224              9
+#define        SHA512_256              10
+
+/*
+ * SHA2 context.
+ * The contents of this structure are a private interface between the
+ * Init/Update/Final calls of the functions defined below.
+ * Callers must never attempt to read or write any of the fields
+ * in this structure directly.
+ */
+typedef struct         {
+       uint32_t algotype;              /* Algorithm Type */
+
+       /* state (ABCDEFGH) */
+       union {
+               uint32_t s32[8];        /* for SHA256 */
+               uint64_t s64[8];        /* for SHA384/512 */
+       } state;
+       /* number of bits */
+       union {
+               uint32_t c32[2];        /* for SHA256 , modulo 2^64 */
+               uint64_t c64[2];        /* for SHA384/512, modulo 2^128 */
+       } count;
+       union {
+               uint8_t         buf8[128];      /* undigested input */
+               uint32_t        buf32[32];      /* realigned input */
+               uint64_t        buf64[16];      /* realigned input */
+       } buf_un;
+} SHA2_CTX;
+
+typedef SHA2_CTX SHA256_CTX;
+typedef SHA2_CTX SHA384_CTX;
+typedef SHA2_CTX SHA512_CTX;
+
+extern void SHA2Init(uint64_t mech, SHA2_CTX *);
+
+extern void SHA2Update(SHA2_CTX *, const void *, size_t);
+
+extern void SHA2Final(void *, SHA2_CTX *);
+
+extern void SHA256Init(SHA256_CTX *);
+
+extern void SHA256Update(SHA256_CTX *, const void *, size_t);
+
+extern void SHA256Final(void *, SHA256_CTX *);
+
+extern void SHA384Init(SHA384_CTX *);
+
+extern void SHA384Update(SHA384_CTX *, const void *, size_t);
+
+extern void SHA384Final(void *, SHA384_CTX *);
+
+extern void SHA512Init(SHA512_CTX *);
+
+extern void SHA512Update(SHA512_CTX *, const void *, size_t);
+
+extern void SHA512Final(void *, SHA512_CTX *);
+
+#ifdef _SHA2_IMPL
+/*
+ * The following types/functions are all private to the implementation
+ * of the SHA2 functions and must not be used by consumers of the interface
+ */
+
+/*
+ * List of support mechanisms in this module.
+ *
+ * It is important to note that in the module, division or modulus calculations
+ * are used on the enumerated type to determine which mechanism is being used;
+ * therefore, changing the order or additional mechanisms should be done
+ * carefully
+ */
+typedef enum sha2_mech_type {
+       SHA256_MECH_INFO_TYPE,          /* SUN_CKM_SHA256 */
+       SHA256_HMAC_MECH_INFO_TYPE,     /* SUN_CKM_SHA256_HMAC */
+       SHA256_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA256_HMAC_GENERAL */
+       SHA384_MECH_INFO_TYPE,          /* SUN_CKM_SHA384 */
+       SHA384_HMAC_MECH_INFO_TYPE,     /* SUN_CKM_SHA384_HMAC */
+       SHA384_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA384_HMAC_GENERAL */
+       SHA512_MECH_INFO_TYPE,          /* SUN_CKM_SHA512 */
+       SHA512_HMAC_MECH_INFO_TYPE,     /* SUN_CKM_SHA512_HMAC */
+       SHA512_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA512_HMAC_GENERAL */
+       SHA512_224_MECH_INFO_TYPE,      /* SUN_CKM_SHA512_224 */
+       SHA512_256_MECH_INFO_TYPE       /* SUN_CKM_SHA512_256 */
+} sha2_mech_type_t;
+
+#endif /* _SHA2_IMPL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SHA2_H */
diff --git a/zfs/include/sys/skein.h b/zfs/include/sys/skein.h
new file mode 100644 (file)
index 0000000..2f649d6
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Interface declarations for Skein hashing.
+ * Source code author: Doug Whiting, 2008.
+ * This algorithm and source code is released to the public domain.
+ *
+ * The following compile-time switches may be defined to control some
+ * tradeoffs between speed, code size, error checking, and security.
+ *
+ * The "default" note explains what happens when the switch is not defined.
+ *
+ *  SKEIN_DEBUG            -- make callouts from inside Skein code
+ *                            to examine/display intermediate values.
+ *                            [default: no callouts (no overhead)]
+ *
+ *  SKEIN_ERR_CHECK        -- how error checking is handled inside Skein
+ *                            code. If not defined, most error checking
+ *                            is disabled (for performance). Otherwise,
+ *                            the switch value is interpreted as:
+ *                                0: use assert()      to flag errors
+ *                                1: return SKEIN_FAIL to flag errors
+ */
+/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
+#ifndef        _SYS_SKEIN_H_
+#define        _SYS_SKEIN_H_
+
+#ifdef  _KERNEL
+#include <sys/types.h>         /* get size_t definition */
+#else
+#include <stdint.h>
+#include <stdlib.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+       SKEIN_SUCCESS = 0,      /* return codes from Skein calls */
+       SKEIN_FAIL = 1,
+       SKEIN_BAD_HASHLEN = 2
+};
+
+#define        SKEIN_MODIFIER_WORDS    (2)     /* number of modifier (tweak) words */
+
+#define        SKEIN_256_STATE_WORDS   (4)
+#define        SKEIN_512_STATE_WORDS   (8)
+#define        SKEIN1024_STATE_WORDS   (16)
+#define        SKEIN_MAX_STATE_WORDS   (16)
+
+#define        SKEIN_256_STATE_BYTES   (8 * SKEIN_256_STATE_WORDS)
+#define        SKEIN_512_STATE_BYTES   (8 * SKEIN_512_STATE_WORDS)
+#define        SKEIN1024_STATE_BYTES   (8 * SKEIN1024_STATE_WORDS)
+
+#define        SKEIN_256_STATE_BITS    (64 * SKEIN_256_STATE_WORDS)
+#define        SKEIN_512_STATE_BITS    (64 * SKEIN_512_STATE_WORDS)
+#define        SKEIN1024_STATE_BITS    (64 * SKEIN1024_STATE_WORDS)
+
+#define        SKEIN_256_BLOCK_BYTES   (8 * SKEIN_256_STATE_WORDS)
+#define        SKEIN_512_BLOCK_BYTES   (8 * SKEIN_512_STATE_WORDS)
+#define        SKEIN1024_BLOCK_BYTES   (8 * SKEIN1024_STATE_WORDS)
+
+typedef struct {
+       size_t hashBitLen;      /* size of hash result, in bits */
+       size_t bCnt;            /* current byte count in buffer b[] */
+       /* tweak words: T[0]=byte cnt, T[1]=flags */
+       uint64_t T[SKEIN_MODIFIER_WORDS];
+} Skein_Ctxt_Hdr_t;
+
+typedef struct {               /*  256-bit Skein hash context structure */
+       Skein_Ctxt_Hdr_t h;     /* common header context variables */
+       uint64_t X[SKEIN_256_STATE_WORDS];      /* chaining variables */
+       /* partial block buffer (8-byte aligned) */
+       uint8_t b[SKEIN_256_BLOCK_BYTES];
+} Skein_256_Ctxt_t;
+
+typedef struct {               /*  512-bit Skein hash context structure */
+       Skein_Ctxt_Hdr_t h;     /* common header context variables */
+       uint64_t X[SKEIN_512_STATE_WORDS];      /* chaining variables */
+       /* partial block buffer (8-byte aligned) */
+       uint8_t b[SKEIN_512_BLOCK_BYTES];
+} Skein_512_Ctxt_t;
+
+typedef struct {               /* 1024-bit Skein hash context structure */
+       Skein_Ctxt_Hdr_t h;     /* common header context variables */
+       uint64_t X[SKEIN1024_STATE_WORDS];      /* chaining variables */
+       /* partial block buffer (8-byte aligned) */
+       uint8_t b[SKEIN1024_BLOCK_BYTES];
+} Skein1024_Ctxt_t;
+
+/*   Skein APIs for (incremental) "straight hashing" */
+int Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen);
+int Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen);
+int Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen);
+
+int Skein_256_Update(Skein_256_Ctxt_t *ctx, const uint8_t *msg,
+    size_t msgByteCnt);
+int Skein_512_Update(Skein_512_Ctxt_t *ctx, const uint8_t *msg,
+    size_t msgByteCnt);
+int Skein1024_Update(Skein1024_Ctxt_t *ctx, const uint8_t *msg,
+    size_t msgByteCnt);
+
+int Skein_256_Final(Skein_256_Ctxt_t *ctx, uint8_t *hashVal);
+int Skein_512_Final(Skein_512_Ctxt_t *ctx, uint8_t *hashVal);
+int Skein1024_Final(Skein1024_Ctxt_t *ctx, uint8_t *hashVal);
+
+/*
+ * Skein APIs for "extended" initialization: MAC keys, tree hashing.
+ * After an InitExt() call, just use Update/Final calls as with Init().
+ *
+ * Notes: Same parameters as _Init() calls, plus treeInfo/key/keyBytes.
+ *          When keyBytes == 0 and treeInfo == SKEIN_SEQUENTIAL,
+ *              the results of InitExt() are identical to calling Init().
+ *          The function Init() may be called once to "precompute" the IV for
+ *              a given hashBitLen value, then by saving a copy of the context
+ *              the IV computation may be avoided in later calls.
+ *          Similarly, the function InitExt() may be called once per MAC key
+ *              to precompute the MAC IV, then a copy of the context saved and
+ *              reused for each new MAC computation.
+ */
+int Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen,
+    uint64_t treeInfo, const uint8_t *key, size_t keyBytes);
+int Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen,
+    uint64_t treeInfo, const uint8_t *key, size_t keyBytes);
+int Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen,
+    uint64_t treeInfo, const uint8_t *key, size_t keyBytes);
+
+/*
+ * Skein APIs for MAC and tree hash:
+ *     Final_Pad: pad, do final block, but no OUTPUT type
+ *     Output:    do just the output stage
+ */
+int Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, uint8_t *hashVal);
+int Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, uint8_t *hashVal);
+int Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, uint8_t *hashVal);
+
+#ifndef        SKEIN_TREE_HASH
+#define        SKEIN_TREE_HASH (1)
+#endif
+#if    SKEIN_TREE_HASH
+int Skein_256_Output(Skein_256_Ctxt_t *ctx, uint8_t *hashVal);
+int Skein_512_Output(Skein_512_Ctxt_t *ctx, uint8_t *hashVal);
+int Skein1024_Output(Skein1024_Ctxt_t *ctx, uint8_t *hashVal);
+#endif
+
+/*
+ * When you initialize a Skein KCF hashing method you can pass this param
+ * structure in cm_param to fine-tune the algorithm's defaults.
+ */
+typedef struct skein_param {
+       size_t  sp_digest_bitlen;               /* length of digest in bits */
+} skein_param_t;
+
+/* Module definitions */
+#ifdef SKEIN_MODULE_IMPL
+#define        CKM_SKEIN_256                           "CKM_SKEIN_256"
+#define        CKM_SKEIN_512                           "CKM_SKEIN_512"
+#define        CKM_SKEIN1024                           "CKM_SKEIN1024"
+#define        CKM_SKEIN_256_MAC                       "CKM_SKEIN_256_MAC"
+#define        CKM_SKEIN_512_MAC                       "CKM_SKEIN_512_MAC"
+#define        CKM_SKEIN1024_MAC                       "CKM_SKEIN1024_MAC"
+
+typedef enum skein_mech_type {
+       SKEIN_256_MECH_INFO_TYPE,
+       SKEIN_512_MECH_INFO_TYPE,
+       SKEIN1024_MECH_INFO_TYPE,
+       SKEIN_256_MAC_MECH_INFO_TYPE,
+       SKEIN_512_MAC_MECH_INFO_TYPE,
+       SKEIN1024_MAC_MECH_INFO_TYPE
+} skein_mech_type_t;
+
+#define        VALID_SKEIN_DIGEST_MECH(__mech)                         \
+       ((int)(__mech) >= SKEIN_256_MECH_INFO_TYPE &&           \
+       (__mech) <= SKEIN1024_MECH_INFO_TYPE)
+#define        VALID_SKEIN_MAC_MECH(__mech)                            \
+       ((int)(__mech) >= SKEIN_256_MAC_MECH_INFO_TYPE &&       \
+       (__mech) <= SKEIN1024_MAC_MECH_INFO_TYPE)
+#endif /* SKEIN_MODULE_IMPL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SKEIN_H_ */
index bfd2e7902ea3cc52178d8e122c1c013533cfa702..3d0b962e68895379b4867bcbb4e249a06b1ec49b 100644 (file)
@@ -23,6 +23,7 @@
  * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
  */
 
 #ifndef _SYS_SPA_H
@@ -35,6 +36,8 @@
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <sys/fs/zfs.h>
+#include <sys/spa_checksum.h>
+#include <sys/dmu.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -134,6 +137,8 @@ _NOTE(CONSTCOND) } while (0)
 #define        SPA_PSIZEBITS           16      /* PSIZE up to 32M (2^16 * 512) */
 #define        SPA_ASIZEBITS           24      /* ASIZE up to 64 times larger  */
 
+#define        SPA_COMPRESSBITS        7
+
 /*
  * All SPA data is represented by 128-bit data virtual addresses (DVAs).
  * The members of the dva_t should be considered opaque outside the SPA.
@@ -142,12 +147,14 @@ typedef struct dva {
        uint64_t        dva_word[2];
 } dva_t;
 
+
 /*
- * Each block has a 256-bit checksum -- strong enough for cryptographic hashes.
+ * Some checksums/hashes need a 256-bit initialization salt. This salt is kept
+ * secret and is suitable for use in MAC algorithms as the key.
  */
-typedef struct zio_cksum {
-       uint64_t        zc_word[4];
-} zio_cksum_t;
+typedef struct zio_cksum_salt {
+       uint8_t         zcs_bytes[32];
+} zio_cksum_salt_t;
 
 /*
  * Each block is described by its DVAs, time of birth, checksum, etc.
@@ -368,8 +375,10 @@ _NOTE(CONSTCOND) } while (0)
            16, SPA_PSIZEBITS, SPA_MINBLOCKSHIFT, 1, x); \
 _NOTE(CONSTCOND) } while (0)
 
-#define        BP_GET_COMPRESS(bp)             BF64_GET((bp)->blk_prop, 32, 7)
-#define        BP_SET_COMPRESS(bp, x)          BF64_SET((bp)->blk_prop, 32, 7, x)
+#define        BP_GET_COMPRESS(bp)             \
+       BF64_GET((bp)->blk_prop, 32, SPA_COMPRESSBITS)
+#define        BP_SET_COMPRESS(bp, x)          \
+       BF64_SET((bp)->blk_prop, 32, SPA_COMPRESSBITS, x)
 
 #define        BP_IS_EMBEDDED(bp)              BF64_GET((bp)->blk_prop, 39, 1)
 #define        BP_SET_EMBEDDED(bp, x)          BF64_SET((bp)->blk_prop, 39, 1, x)
@@ -440,26 +449,9 @@ _NOTE(CONSTCOND) } while (0)
        DVA_EQUAL(&(bp1)->blk_dva[1], &(bp2)->blk_dva[1]) &&    \
        DVA_EQUAL(&(bp1)->blk_dva[2], &(bp2)->blk_dva[2]))
 
-#define        ZIO_CHECKSUM_EQUAL(zc1, zc2) \
-       (0 == (((zc1).zc_word[0] - (zc2).zc_word[0]) | \
-       ((zc1).zc_word[1] - (zc2).zc_word[1]) | \
-       ((zc1).zc_word[2] - (zc2).zc_word[2]) | \
-       ((zc1).zc_word[3] - (zc2).zc_word[3])))
-
-#define        ZIO_CHECKSUM_IS_ZERO(zc) \
-       (0 == ((zc)->zc_word[0] | (zc)->zc_word[1] | \
-       (zc)->zc_word[2] | (zc)->zc_word[3]))
 
 #define        DVA_IS_VALID(dva)       (DVA_GET_ASIZE(dva) != 0)
 
-#define        ZIO_SET_CHECKSUM(zcp, w0, w1, w2, w3)   \
-{                                              \
-       (zcp)->zc_word[0] = w0;                 \
-       (zcp)->zc_word[1] = w1;                 \
-       (zcp)->zc_word[2] = w2;                 \
-       (zcp)->zc_word[3] = w3;                 \
-}
-
 #define        BP_IDENTITY(bp)         (ASSERT(!BP_IS_EMBEDDED(bp)), &(bp)->blk_dva[0])
 #define        BP_IS_GANG(bp)          \
        (BP_IS_EMBEDDED(bp) ? B_FALSE : DVA_GET_GANG(BP_IDENTITY(bp)))
@@ -576,8 +568,6 @@ _NOTE(CONSTCOND) } while (0)
        ASSERT(len < size);                                             \
 }
 
-#include <sys/dmu.h>
-
 #define        BP_GET_BUFC_TYPE(bp)                                            \
        (((BP_GET_LEVEL(bp) > 0) || (DMU_OT_IS_METADATA(BP_GET_TYPE(bp)))) ? \
        ARC_BUFC_METADATA : ARC_BUFC_DATA)
@@ -844,6 +834,7 @@ extern boolean_t spa_is_root(spa_t *spa);
 extern boolean_t spa_writeable(spa_t *spa);
 extern boolean_t spa_has_pending_synctask(spa_t *spa);
 extern int spa_maxblocksize(spa_t *spa);
+extern int spa_maxdnodesize(spa_t *spa);
 extern void zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp);
 
 extern int spa_mode(spa_t *spa);
@@ -870,8 +861,9 @@ extern void spa_log_error(spa_t *spa, zio_t *zio);
 extern void zfs_ereport_post(const char *class, spa_t *spa, vdev_t *vd,
     zio_t *zio, uint64_t stateoroffset, uint64_t length);
 extern void zfs_post_remove(spa_t *spa, vdev_t *vd);
-extern void zfs_post_state_change(spa_t *spa, vdev_t *vd);
+extern void zfs_post_state_change(spa_t *spa, vdev_t *vd, uint64_t laststate);
 extern void zfs_post_autoreplace(spa_t *spa, vdev_t *vd);
+extern void zfs_post_sysevent(spa_t *spa, vdev_t *vd, const char *name);
 extern uint64_t spa_get_errlog_size(spa_t *spa);
 extern int spa_get_errlog(spa_t *spa, void *uaddr, size_t *count);
 extern void spa_errlog_rotate(spa_t *spa);
diff --git a/zfs/include/sys/spa_checksum.h b/zfs/include/sys/spa_checksum.h
new file mode 100644 (file)
index 0000000..b879901
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SPA_CHECKSUM_H
+#define        _SPA_CHECKSUM_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Each block has a 256-bit checksum -- strong enough for cryptographic hashes.
+ */
+typedef struct zio_cksum {
+       uint64_t        zc_word[4];
+} zio_cksum_t;
+
+#define        ZIO_SET_CHECKSUM(zcp, w0, w1, w2, w3)   \
+{                                              \
+       (zcp)->zc_word[0] = w0;                 \
+       (zcp)->zc_word[1] = w1;                 \
+       (zcp)->zc_word[2] = w2;                 \
+       (zcp)->zc_word[3] = w3;                 \
+}
+
+#define        ZIO_CHECKSUM_EQUAL(zc1, zc2) \
+       (0 == (((zc1).zc_word[0] - (zc2).zc_word[0]) | \
+       ((zc1).zc_word[1] - (zc2).zc_word[1]) | \
+       ((zc1).zc_word[2] - (zc2).zc_word[2]) | \
+       ((zc1).zc_word[3] - (zc2).zc_word[3])))
+
+#define        ZIO_CHECKSUM_IS_ZERO(zc) \
+       (0 == ((zc)->zc_word[0] | (zc)->zc_word[1] | \
+       (zc)->zc_word[2] | (zc)->zc_word[3]))
+
+#define        ZIO_CHECKSUM_BSWAP(zcp)                                 \
+{                                                              \
+       (zcp)->zc_word[0] = BSWAP_64((zcp)->zc_word[0]);        \
+       (zcp)->zc_word[1] = BSWAP_64((zcp)->zc_word[1]);        \
+       (zcp)->zc_word[2] = BSWAP_64((zcp)->zc_word[2]);        \
+       (zcp)->zc_word[3] = BSWAP_64((zcp)->zc_word[3]);        \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index 5176eb84842cd109480c360622eebfcfeec8fcdd..88bde98dc5577b91f567d6e825752e9701cb7d93 100644 (file)
@@ -23,6 +23,7 @@
  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
@@ -116,11 +117,17 @@ typedef struct spa_taskqs {
        taskq_t **stqs_taskq;
 } spa_taskqs_t;
 
+typedef enum spa_all_vdev_zap_action {
+       AVZ_ACTION_NONE = 0,
+       AVZ_ACTION_DESTROY,     /* Destroy all per-vdev ZAPs and the AVZ. */
+       AVZ_ACTION_REBUILD      /* Populate the new AVZ, see spa_avz_rebuild */
+} spa_avz_action_t;
+
 struct spa {
        /*
         * Fields protected by spa_namespace_lock.
         */
-       char            spa_name[MAXNAMELEN];   /* pool name */
+       char            spa_name[ZFS_MAX_DATASET_NAME_LEN];     /* pool name */
        char            *spa_comment;           /* comment */
        avl_node_t      spa_avl;                /* node in spa_namespace_avl */
        nvlist_t        *spa_config;            /* last synced config */
@@ -158,6 +165,8 @@ struct spa {
        uint64_t        spa_last_synced_guid;   /* last synced guid */
        list_t          spa_config_dirty_list;  /* vdevs with dirty config */
        list_t          spa_state_dirty_list;   /* vdevs with dirty state */
+       kmutex_t        spa_alloc_lock;
+       avl_tree_t      spa_alloc_tree;
        spa_aux_vdev_t  spa_spares;             /* hot spares */
        spa_aux_vdev_t  spa_l2cache;            /* L2ARC cache devices */
        nvlist_t        *spa_label_features;    /* Features for reading MOS */
@@ -166,6 +175,10 @@ struct spa {
        uint64_t        spa_syncing_txg;        /* txg currently syncing */
        bpobj_t         spa_deferred_bpobj;     /* deferred-free bplist */
        bplist_t        spa_free_bplist[TXG_SIZE]; /* bplist of stuff to free */
+       zio_cksum_salt_t spa_cksum_salt;        /* secret salt for cksum */
+       /* checksum context templates */
+       kmutex_t        spa_cksum_tmpls_lock;
+       void            *spa_cksum_tmpls[ZIO_CHECKSUM_FUNCTIONS];
        uberblock_t     spa_ubsync;             /* last synced uberblock */
        uberblock_t     spa_uberblock;          /* current uberblock */
        boolean_t       spa_extreme_rewind;     /* rewind past deferred frees */
@@ -251,8 +264,11 @@ struct spa {
        uint64_t        spa_deadman_calls;      /* number of deadman calls */
        hrtime_t        spa_sync_starttime;     /* starting time of spa_sync */
        uint64_t        spa_deadman_synctime;   /* deadman expiration timer */
+       uint64_t        spa_all_vdev_zaps;      /* ZAP of per-vd ZAP obj #s */
+       spa_avz_action_t        spa_avz_action; /* destroy/rebuild AVZ? */
        uint64_t        spa_errata;             /* errata issues detected */
        spa_stats_t     spa_stats;              /* assorted spa statistics */
+       hrtime_t        spa_ccw_fail_time;      /* Conf cache write fail time */
        taskq_t         *spa_zvol_taskq;        /* Taskq for minor managment */
 
        /*
@@ -263,6 +279,8 @@ struct spa {
         */
        spa_config_lock_t spa_config_lock[SCL_LOCKS]; /* config changes */
        refcount_t      spa_refcount;           /* number of opens */
+
+       taskq_t         *spa_upgrade_taskq;     /* taskq for upgrade jobs */
 };
 
 extern char *spa_config_path;
diff --git a/zfs/include/sys/sysevent.h b/zfs/include/sys/sysevent.h
new file mode 100644 (file)
index 0000000..2922e30
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_SYSEVENT_H
+#define        _SYS_SYSEVENT_H
+
+#endif
diff --git a/zfs/include/sys/sysevent/Makefile.am b/zfs/include/sys/sysevent/Makefile.am
new file mode 100644 (file)
index 0000000..e9af268
--- /dev/null
@@ -0,0 +1,19 @@
+COMMON_H = \
+       $(top_srcdir)/include/sys/sysevent/eventdefs.h \
+       $(top_srcdir)/include/sys/sysevent/dev.h
+
+KERNEL_H =
+
+USER_H =
+
+EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
+
+if CONFIG_USER
+libzfsdir = $(includedir)/libzfs/sys/sysevent
+libzfs_HEADERS = $(COMMON_H) $(USER_H)
+endif
+
+if CONFIG_KERNEL
+kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/sysevent
+kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
+endif
diff --git a/zfs/include/sys/sysevent/dev.h b/zfs/include/sys/sysevent/dev.h
new file mode 100644 (file)
index 0000000..1117538
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_SYSEVENT_DEV_H
+#define        _SYS_SYSEVENT_DEV_H
+
+#include <sys/sysevent/eventdefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Event schema for EC_DEV_ADD/ESC_DISK
+ *
+ *     Event Class     - EC_DEV_ADD
+ *     Event Sub-Class - ESC_DISK
+ *
+ *     Attribute Name  - EV_VERSION
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - event version number
+ *
+ *     Attribute Name  - DEV_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - /dev name to the raw device.
+ *                       The name does not include the slice number component.
+ *
+ *     Attribute Name  - DEV_PHYS_PATH
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - physical path of the device without the "/devices"
+ *                       prefix.
+ *
+ *     Attribute Name  - DEV_DRIVER_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - driver name
+ *
+ *     Attribute Name  - DEV_INSTANCE
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - driver instance number
+ *
+ *     Attribute Name  - DEV_PROP_PREFIX<devinfo_node_property>
+ *     Attribute Type  - data type of the devinfo_node_property
+ *     Attribute Value - value of the devinfo_node_property
+ *
+ *
+ * Event schema for EC_DEV_ADD/ESC_NETWORK
+ *
+ *     Event Class     - EC_DEV_ADD
+ *     Event Sub-Class - ESC_NETWORK
+ *
+ *     Attribute Name  - EV_VERSION
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - event version number
+ *
+ *     Attribute Name  - DEV_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - /dev name associated with the device if exists.
+ *                       /dev name associated with the driver for DLPI
+ *                       Style-2 only drivers.
+ *
+ *     Attribute Name  - DEV_PHYS_PATH
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - physical path of the device without the "/devices"
+ *                       prefix.
+ *
+ *     Attribute Name  - DEV_DRIVER_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - driver name
+ *
+ *     Attribute Name  - DEV_INSTANCE
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - driver instance number
+ *
+ *     Attribute Name  - DEV_PROP_PREFIX<devinfo_node_property>
+ *     Attribute Type  - data type of the devinfo_node_property
+ *     Attribute Value - value of the devinfo_node_property
+ *
+ *
+ * Event schema for EC_DEV_ADD/ESC_PRINTER
+ *
+ *     Event Class     - EC_DEV_ADD
+ *     Event Sub-Class - ESC_PRINTER
+ *
+ *     Attribute Name  - EV_VERSION
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - event version number
+ *
+ *     Attribute Name  - DEV_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - /dev/printers name associated with the device
+ *                       if exists.
+ *                       /dev name associated with the device if it exists
+ *
+ *     Attribute Name  - DEV_PHYS_PATH
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - physical path of the device without the "/devices"
+ *                       prefix.
+ *
+ *     Attribute Name  - DEV_DRIVER_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - driver name
+ *
+ *     Attribute Name  - DEV_INSTANCE
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - driver instance number
+ *
+ *     Attribute Name  - DEV_PROP_PREFIX<devinfo_node_property>
+ *     Attribute Type  - data type of the devinfo_node_property
+ *     Attribute Value - value of the devinfo_node_property
+ *
+ *
+ * Event schema for EC_DEV_REMOVE/ESC_DISK
+ *
+ *     Event Class     - EC_DEV_REMOVE
+ *     Event Sub-Class - ESC_DISK
+ *
+ *     Attribute Name  - EV_VERSION
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - event version number
+ *
+ *     Attribute Name  - DEV_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - /dev name to the raw device.
+ *                       The name does not include the slice number component.
+ *
+ *     Attribute Name  - DEV_PHYS_PATH
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - physical path of the device without the "/devices"
+ *                       prefix.
+ *
+ *     Attribute Name  - DEV_DRIVER_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - driver name
+ *
+ *     Attribute Name  - DEV_INSTANCE
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - driver instance number
+ *
+ *
+ * Event schema for EC_DEV_REMOVE/ESC_NETWORK
+ *
+ *     Event Class     - EC_DEV_REMOVE
+ *     Event Sub-Class - ESC_NETWORK
+ *
+ *     Attribute Name  - EV_VERSION
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - event version number
+ *
+ *     Attribute Name  - DEV_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - /dev name associated with the device if exists.
+ *                       /dev name associated with the driver for DLPI
+ *                       Style-2 only drivers.
+ *
+ *     Attribute Name  - DEV_PHYS_PATH
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - physical path of the device without the "/devices"
+ *                       prefix.
+ *
+ *     Attribute Name  - DEV_DRIVER_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - driver name
+ *
+ *     Attribute Name  - DEV_INSTANCE
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - driver instance number
+ *
+ *
+ * Event schema for EC_DEV_REMOVE/ESC_PRINTER
+ *
+ *     Event Class     - EC_DEV_REMOVE
+ *     Event Sub-Class - ESC_PRINTER
+ *
+ *     Attribute Name  - EV_VERSION
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - event version number
+ *
+ *     Attribute Name  - DEV_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - /dev/printers name associated with the device
+ *                       if exists.
+ *                       /dev name associated with the device if it exists
+ *
+ *     Attribute Name  - DEV_PHYS_PATH
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - physical path of the device without the "/devices"
+ *                       prefix.
+ *
+ *     Attribute Name  - DEV_DRIVER_NAME
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - driver name
+ *
+ *     Attribute Name  - DEV_INSTANCE
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - driver instance number
+ *
+ *
+ * Event schema for EC_DEV_BRANCH/ESC_DEV_BRANCH_ADD or ESC_DEV_BRANCH_REMOVE
+ *
+ *     Event Class     - EC_DEV_BRANCH
+ *     Event Sub-Class - ESC_DEV_BRANCH_ADD or ESC_DEV_BRANCH_REMOVE
+ *
+ *     Attribute Name  - EV_VERSION
+ *     Attribute Type  - DATA_TYPE_INT32
+ *     Attribute Value - event version number
+ *
+ *     Attribute Name  - DEV_PHYS_PATH
+ *     Attribute Type  - DATA_TYPE_STRING
+ *     Attribute Value - physical path to the root node of the device subtree
+ *                       without the "/devices" prefix.
+ */
+
+#define        EV_VERSION              "version"
+#define        DEV_PHYS_PATH           "phys_path"
+#define        DEV_NAME                "dev_name"
+#define        DEV_DRIVER_NAME         "driver_name"
+#define        DEV_INSTANCE            "instance"
+#define        DEV_PROP_PREFIX         "prop-"
+
+#ifdef __linux__
+#define        DEV_IDENTIFIER          "devid"
+#define        DEV_PATH                "path"
+#define        DEV_IS_PART             "is_slice"
+#define        DEV_SIZE                "dev_size"
+#endif /* __linux__ */
+
+#define        EV_V1                   1
+
+/* maximum number of devinfo node properties added to the event */
+#define        MAX_PROP_COUNT          100
+
+/* only properties with size less than PROP_LEN_LIMIT are added to the event */
+#define        PROP_LEN_LIMIT          1024
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SYSEVENT_DEV_H */
diff --git a/zfs/include/sys/sysevent/eventdefs.h b/zfs/include/sys/sysevent/eventdefs.h
new file mode 100644 (file)
index 0000000..eadaaef
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+#ifndef        _SYS_SYSEVENT_EVENTDEFS_H
+#define        _SYS_SYSEVENT_EVENTDEFS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * eventdefs.h contains public definitions for sysevent types (classes
+ * and subclasses).  All additions/removal/changes are subject
+ * to PSARC approval.
+ */
+
+/* Sysevent Class definitions */
+#define        EC_NONE         "EC_none"
+#define        EC_PRIV         "EC_priv"
+#define        EC_PLATFORM     "EC_platform"   /* events private to platform */
+#define        EC_DR           "EC_dr" /* Dynamic reconfiguration event class */
+#define        EC_ENV          "EC_env"        /* Environmental monitor event class */
+#define        EC_DOMAIN       "EC_domain"     /* Domain event class */
+#define        EC_AP_DRIVER    "EC_ap_driver"  /* Alternate Pathing event class */
+#define        EC_IPMP         "EC_ipmp"       /* IP Multipathing event class */
+#define        EC_DEV_ADD      "EC_dev_add"    /* device add event class */
+#define        EC_DEV_REMOVE   "EC_dev_remove" /* device remove event class */
+#define        EC_DEV_BRANCH   "EC_dev_branch" /* device tree branch event class */
+#define        EC_DEV_STATUS   "EC_dev_status" /* device status event class */
+#define        EC_FM           "EC_fm"         /* FMA error report event */
+#define        EC_ZFS          "EC_zfs"        /* ZFS event */
+#define        EC_DATALINK     "EC_datalink"   /* datalink event */
+#define        EC_VRRP         "EC_vrrp"       /* VRRP event */
+
+/*
+ * EC_DEV_ADD and EC_DEV_REMOVE subclass definitions - supporting attributes
+ * (name/value pairs) are found in sys/sysevent/dev.h
+ */
+#define        ESC_DISK        "disk"          /* disk device */
+#define        ESC_NETWORK     "network"       /* network interface */
+#define        ESC_PRINTER     "printer"       /* printer device */
+#define        ESC_LOFI        "lofi"          /* lofi device */
+
+/*
+ * EC_DEV_BRANCH subclass definitions - supporting attributes (name/value pairs)
+ * are found in sys/sysevent/dev.h
+ */
+
+/* device tree branch added */
+#define        ESC_DEV_BRANCH_ADD      "dev_branch_add"
+
+/* device tree branch removed */
+#define        ESC_DEV_BRANCH_REMOVE   "dev_branch_remove"
+
+/*
+ * EC_DEV_STATUS subclass definitions
+ *
+ * device capacity dynamically changed
+ */
+#define        ESC_DEV_DLE             "dev_dle"
+
+/* LUN has received an eject request from the user */
+#define        ESC_DEV_EJECT_REQUEST   "dev_eject_request"
+
+/* FMA Fault and Error event protocol subclass */
+#define        ESC_FM_ERROR            "error"
+#define        ESC_FM_ERROR_REPLAY     "error_replay"
+
+/*
+ * ZFS subclass definitions.  supporting attributes (name/value paris) are found
+ * in sys/fs/zfs.h
+ */
+#define        ESC_ZFS_RESILVER_START          "resilver_start"
+#define        ESC_ZFS_RESILVER_FINISH         "resilver_finish"
+#define        ESC_ZFS_VDEV_REMOVE             "vdev_remove"
+#define        ESC_ZFS_VDEV_REMOVE_AUX         "vdev_remove_aux"
+#define        ESC_ZFS_VDEV_REMOVE_DEV         "vdev_remove_dev"
+#define        ESC_ZFS_POOL_CREATE             "pool_create"
+#define        ESC_ZFS_POOL_DESTROY            "pool_destroy"
+#define        ESC_ZFS_POOL_IMPORT             "pool_import"
+#define        ESC_ZFS_VDEV_ADD                "vdev_add"
+#define        ESC_ZFS_VDEV_ATTACH             "vdev_attach"
+#define        ESC_ZFS_VDEV_CLEAR              "vdev_clear"
+#define        ESC_ZFS_VDEV_CHECK              "vdev_check"
+#define        ESC_ZFS_VDEV_ONLINE             "vdev_online"
+#define        ESC_ZFS_CONFIG_SYNC             "config_sync"
+#define        ESC_ZFS_SCRUB_START             "scrub_start"
+#define        ESC_ZFS_SCRUB_FINISH            "scrub_finish"
+#define        ESC_ZFS_VDEV_SPARE              "vdev_spare"
+#define        ESC_ZFS_VDEV_AUTOEXPAND         "vdev_autoexpand"
+#define        ESC_ZFS_BOOTFS_VDEV_ATTACH      "bootfs_vdev_attach"
+#define        ESC_ZFS_POOL_REGUID             "pool_reguid"
+
+/*
+ * datalink subclass definitions.
+ */
+#define        ESC_DATALINK_PHYS_ADD   "datalink_phys_add"     /* new physical link */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SYSEVENT_EVENTDEFS_H */
index a656869cc684abd9309f75459ac95dc031875aec..a49e8b4c052d20a5364e194517c95076dab228a9 100644 (file)
@@ -31,6 +31,7 @@
 #define        _TRACE_ACL_H
 
 #include <linux/tracepoint.h>
+#include <linux/vfs_compat.h>
 #include <sys/types.h>
 
 /*
@@ -54,13 +55,8 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
            __field(uint_t,             z_blksz)
            __field(uint_t,             z_seq)
            __field(uint64_t,           z_mapcnt)
-           __field(uint64_t,           z_gen)
            __field(uint64_t,           z_size)
-           __array(uint64_t,           z_atime, 2)
-           __field(uint64_t,           z_links)
            __field(uint64_t,           z_pflags)
-           __field(uint64_t,           z_uid)
-           __field(uint64_t,           z_gid)
            __field(uint32_t,           z_sync_cnt)
            __field(mode_t,             z_mode)
            __field(boolean_t,          z_is_sa)
@@ -68,6 +64,8 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
            __field(boolean_t,          z_is_ctldir)
            __field(boolean_t,          z_is_stale)
 
+           __field(uint32_t,           i_uid)
+           __field(uint32_t,           i_gid)
            __field(unsigned long,      i_ino)
            __field(unsigned int,       i_nlink)
            __field(u64,                i_version)
@@ -92,14 +90,8 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
            __entry->z_blksz            = zn->z_blksz;
            __entry->z_seq              = zn->z_seq;
            __entry->z_mapcnt           = zn->z_mapcnt;
-           __entry->z_gen              = zn->z_gen;
            __entry->z_size             = zn->z_size;
-           __entry->z_atime[0]         = zn->z_atime[0];
-           __entry->z_atime[1]         = zn->z_atime[1];
-           __entry->z_links            = zn->z_links;
            __entry->z_pflags           = zn->z_pflags;
-           __entry->z_uid              = zn->z_uid;
-           __entry->z_gid              = zn->z_gid;
            __entry->z_sync_cnt         = zn->z_sync_cnt;
            __entry->z_mode             = zn->z_mode;
            __entry->z_is_sa            = zn->z_is_sa;
@@ -107,6 +99,8 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
            __entry->z_is_ctldir        = zn->z_is_ctldir;
            __entry->z_is_stale         = zn->z_is_stale;
 
+           __entry->i_uid              = KUID_TO_SUID(ZTOI(zn)->i_uid);
+           __entry->i_gid              = KGID_TO_SGID(ZTOI(zn)->i_gid);
            __entry->i_ino              = zn->z_inode.i_ino;
            __entry->i_nlink            = zn->z_inode.i_nlink;
            __entry->i_version          = zn->z_inode.i_version;
@@ -124,25 +118,23 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
        ),
        TP_printk("zn { id %llu unlinked %u atime_dirty %u "
            "zn_prefetch %u moved %u blksz %u seq %u "
-           "mapcnt %llu gen %llu size %llu atime 0x%llx:0x%llx "
-           "links %llu pflags %llu uid %llu gid %llu "
+           "mapcnt %llu size %llu pflags %llu "
            "sync_cnt %u mode 0x%x is_sa %d "
            "is_mapped %d is_ctldir %d is_stale %d inode { "
-           "ino %lu nlink %u version %llu size %lli blkbits %u "
-           "bytes %u mode 0x%x generation %x } } ace { type %u "
-           "flags %u access_mask %u } mask_matched %u",
+           "uid %u gid %u ino %lu nlink %u version %llu size %lli "
+           "blkbits %u bytes %u mode 0x%x generation %x } } "
+           "ace { type %u flags %u access_mask %u } mask_matched %u",
            __entry->z_id, __entry->z_unlinked, __entry->z_atime_dirty,
            __entry->z_zn_prefetch, __entry->z_moved, __entry->z_blksz,
-           __entry->z_seq, __entry->z_mapcnt, __entry->z_gen,
-           __entry->z_size, __entry->z_atime[0], __entry->z_atime[1],
-           __entry->z_links, __entry->z_pflags, __entry->z_uid,
-           __entry->z_gid, __entry->z_sync_cnt, __entry->z_mode,
+           __entry->z_seq, __entry->z_mapcnt, __entry->z_size,
+           __entry->z_pflags, __entry->z_sync_cnt, __entry->z_mode,
            __entry->z_is_sa, __entry->z_is_mapped,
-           __entry->z_is_ctldir, __entry->z_is_stale, __entry->i_ino,
-           __entry->i_nlink, __entry->i_version, __entry->i_size,
-           __entry->i_blkbits, __entry->i_bytes, __entry->i_mode,
-           __entry->i_generation, __entry->z_type, __entry->z_flags,
-           __entry->z_access_mask, __entry->mask_matched)
+           __entry->z_is_ctldir, __entry->z_is_stale, __entry->i_uid,
+           __entry->i_gid, __entry->i_ino, __entry->i_nlink,
+           __entry->i_version, __entry->i_size, __entry->i_blkbits,
+           __entry->i_bytes, __entry->i_mode, __entry->i_generation,
+           __entry->z_type, __entry->z_flags, __entry->z_access_mask,
+           __entry->mask_matched)
 );
 
 #define        DEFINE_ACE_EVENT(name) \
index 31c3cdcb9b21f088e59aff7efbc91939b7f73528..0384a44ab36d9192a85295cb5d71afc47f85f62c 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <linux/tracepoint.h>
 #include <sys/types.h>
+#include <sys/trace_common.h> /* For ZIO macros */
 
 /*
  * Generic support for one argument tracepoints of the form:
@@ -49,9 +50,10 @@ DECLARE_EVENT_CLASS(zfs_arc_buf_hdr_class,
            __array(uint64_t,           hdr_dva_word, 2)
            __field(uint64_t,           hdr_birth)
            __field(uint32_t,           hdr_flags)
-           __field(uint32_t,           hdr_datacnt)
+           __field(uint32_t,           hdr_bufcnt)
            __field(arc_buf_contents_t, hdr_type)
-           __field(uint64_t,           hdr_size)
+           __field(uint16_t,           hdr_psize)
+           __field(uint16_t,           hdr_lsize)
            __field(uint64_t,           hdr_spa)
            __field(arc_state_type_t,   hdr_state_type)
            __field(clock_t,            hdr_access)
@@ -67,8 +69,9 @@ DECLARE_EVENT_CLASS(zfs_arc_buf_hdr_class,
            __entry->hdr_dva_word[1]    = ab->b_dva.dva_word[1];
            __entry->hdr_birth          = ab->b_birth;
            __entry->hdr_flags          = ab->b_flags;
-           __entry->hdr_datacnt        = ab->b_l1hdr.b_datacnt;
-           __entry->hdr_size           = ab->b_size;
+           __entry->hdr_bufcnt = ab->b_l1hdr.b_bufcnt;
+           __entry->hdr_psize          = ab->b_psize;
+           __entry->hdr_lsize          = ab->b_lsize;
            __entry->hdr_spa            = ab->b_spa;
            __entry->hdr_state_type     = ab->b_l1hdr.b_state->arcs_state;
            __entry->hdr_access         = ab->b_l1hdr.b_arc_access;
@@ -80,13 +83,13 @@ DECLARE_EVENT_CLASS(zfs_arc_buf_hdr_class,
            __entry->hdr_refcount       = ab->b_l1hdr.b_refcnt.rc_count;
        ),
        TP_printk("hdr { dva 0x%llx:0x%llx birth %llu "
-           "flags 0x%x datacnt %u type %u size %llu spa %llu "
+           "flags 0x%x bufcnt %u type %u psize %u lsize %u spa %llu "
            "state_type %u access %lu mru_hits %u mru_ghost_hits %u "
            "mfu_hits %u mfu_ghost_hits %u l2_hits %u refcount %lli }",
            __entry->hdr_dva_word[0], __entry->hdr_dva_word[1],
            __entry->hdr_birth, __entry->hdr_flags,
-           __entry->hdr_datacnt, __entry->hdr_type, __entry->hdr_size,
-           __entry->hdr_spa, __entry->hdr_state_type,
+           __entry->hdr_bufcnt, __entry->hdr_type, __entry->hdr_psize,
+           __entry->hdr_lsize, __entry->hdr_spa, __entry->hdr_state_type,
            __entry->hdr_access, __entry->hdr_mru_hits,
            __entry->hdr_mru_ghost_hits, __entry->hdr_mfu_hits,
            __entry->hdr_mfu_ghost_hits, __entry->hdr_l2_hits,
@@ -102,6 +105,8 @@ DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__evict);
 DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__delete);
 DEFINE_ARC_BUF_HDR_EVENT(zfs_new_state__mru);
 DEFINE_ARC_BUF_HDR_EVENT(zfs_new_state__mfu);
+DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__sync__wait__for__async);
+DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__demand__hit__predictive__prefetch);
 DEFINE_ARC_BUF_HDR_EVENT(zfs_l2arc__hit);
 DEFINE_ARC_BUF_HDR_EVENT(zfs_l2arc__miss);
 
@@ -113,86 +118,6 @@ DEFINE_ARC_BUF_HDR_EVENT(zfs_l2arc__miss);
  *     zio_t *, ...);
  */
 
-#define        ZIO_TP_STRUCT_ENTRY                                             \
-               __field(zio_type_t,             zio_type)               \
-               __field(int,                    zio_cmd)                \
-               __field(zio_priority_t,         zio_priority)           \
-               __field(uint64_t,               zio_size)               \
-               __field(uint64_t,               zio_orig_size)          \
-               __field(uint64_t,               zio_offset)             \
-               __field(hrtime_t,               zio_timestamp)          \
-               __field(hrtime_t,               zio_delta)              \
-               __field(uint64_t,               zio_delay)              \
-               __field(enum zio_flag,          zio_flags)              \
-               __field(enum zio_stage,         zio_stage)              \
-               __field(enum zio_stage,         zio_pipeline)           \
-               __field(enum zio_flag,          zio_orig_flags)         \
-               __field(enum zio_stage,         zio_orig_stage)         \
-               __field(enum zio_stage,         zio_orig_pipeline)      \
-               __field(uint8_t,                zio_reexecute)          \
-               __field(uint64_t,               zio_txg)                \
-               __field(int,                    zio_error)              \
-               __field(uint64_t,               zio_ena)                \
-                                                                       \
-               __field(enum zio_checksum,      zp_checksum)            \
-               __field(enum zio_compress,      zp_compress)            \
-               __field(dmu_object_type_t,      zp_type)                \
-               __field(uint8_t,                zp_level)               \
-               __field(uint8_t,                zp_copies)              \
-               __field(boolean_t,              zp_dedup)               \
-               __field(boolean_t,              zp_dedup_verify)        \
-               __field(boolean_t,              zp_nopwrite)
-
-#define        ZIO_TP_FAST_ASSIGN                                                  \
-               __entry->zio_type               = zio->io_type;             \
-               __entry->zio_cmd                = zio->io_cmd;              \
-               __entry->zio_priority           = zio->io_priority;         \
-               __entry->zio_size               = zio->io_size;             \
-               __entry->zio_orig_size          = zio->io_orig_size;        \
-               __entry->zio_offset             = zio->io_offset;           \
-               __entry->zio_timestamp          = zio->io_timestamp;        \
-               __entry->zio_delta              = zio->io_delta;            \
-               __entry->zio_delay              = zio->io_delay;            \
-               __entry->zio_flags              = zio->io_flags;            \
-               __entry->zio_stage              = zio->io_stage;            \
-               __entry->zio_pipeline           = zio->io_pipeline;         \
-               __entry->zio_orig_flags         = zio->io_orig_flags;       \
-               __entry->zio_orig_stage         = zio->io_orig_stage;       \
-               __entry->zio_orig_pipeline      = zio->io_orig_pipeline;    \
-               __entry->zio_reexecute          = zio->io_reexecute;        \
-               __entry->zio_txg                = zio->io_txg;              \
-               __entry->zio_error              = zio->io_error;            \
-               __entry->zio_ena                = zio->io_ena;              \
-                                                                           \
-               __entry->zp_checksum            = zio->io_prop.zp_checksum; \
-               __entry->zp_compress            = zio->io_prop.zp_compress; \
-               __entry->zp_type                = zio->io_prop.zp_type;     \
-               __entry->zp_level               = zio->io_prop.zp_level;    \
-               __entry->zp_copies              = zio->io_prop.zp_copies;   \
-               __entry->zp_dedup               = zio->io_prop.zp_dedup;    \
-               __entry->zp_nopwrite            = zio->io_prop.zp_nopwrite; \
-               __entry->zp_dedup_verify        = zio->io_prop.zp_dedup_verify;
-
-#define        ZIO_TP_PRINTK_FMT                                               \
-       "zio { type %u cmd %i prio %u size %llu orig_size %llu "        \
-       "offset %llu timestamp %llu delta %llu delay %llu "             \
-       "flags 0x%x stage 0x%x pipeline 0x%x orig_flags 0x%x "          \
-       "orig_stage 0x%x orig_pipeline 0x%x reexecute %u "              \
-       "txg %llu error %d ena %llu prop { checksum %u compress %u "    \
-       "type %u level %u copies %u dedup %u dedup_verify %u nopwrite %u } }"
-
-#define        ZIO_TP_PRINTK_ARGS                                              \
-       __entry->zio_type, __entry->zio_cmd, __entry->zio_priority,     \
-       __entry->zio_size, __entry->zio_orig_size, __entry->zio_offset, \
-       __entry->zio_timestamp, __entry->zio_delta, __entry->zio_delay, \
-       __entry->zio_flags, __entry->zio_stage, __entry->zio_pipeline,  \
-       __entry->zio_orig_flags, __entry->zio_orig_stage,               \
-       __entry->zio_orig_pipeline, __entry->zio_reexecute,             \
-       __entry->zio_txg, __entry->zio_error, __entry->zio_ena,         \
-       __entry->zp_checksum, __entry->zp_compress, __entry->zp_type,   \
-       __entry->zp_level, __entry->zp_copies, __entry->zp_dedup,       \
-       __entry->zp_dedup_verify, __entry->zp_nopwrite
-
 DECLARE_EVENT_CLASS(zfs_l2arc_rw_class,
        TP_PROTO(vdev_t *vd, zio_t *zio),
        TP_ARGS(vd, zio),
@@ -262,9 +187,10 @@ DECLARE_EVENT_CLASS(zfs_arc_miss_class,
            __array(uint64_t,           hdr_dva_word, 2)
            __field(uint64_t,           hdr_birth)
            __field(uint32_t,           hdr_flags)
-           __field(uint32_t,           hdr_datacnt)
+           __field(uint32_t,           hdr_bufcnt)
            __field(arc_buf_contents_t, hdr_type)
-           __field(uint64_t,           hdr_size)
+           __field(uint16_t,           hdr_psize)
+           __field(uint16_t,           hdr_lsize)
            __field(uint64_t,           hdr_spa)
            __field(arc_state_type_t,   hdr_state_type)
            __field(clock_t,            hdr_access)
@@ -292,8 +218,9 @@ DECLARE_EVENT_CLASS(zfs_arc_miss_class,
            __entry->hdr_dva_word[1]    = hdr->b_dva.dva_word[1];
            __entry->hdr_birth          = hdr->b_birth;
            __entry->hdr_flags          = hdr->b_flags;
-           __entry->hdr_datacnt        = hdr->b_l1hdr.b_datacnt;
-           __entry->hdr_size           = hdr->b_size;
+           __entry->hdr_bufcnt         = hdr->b_l1hdr.b_bufcnt;
+           __entry->hdr_psize          = hdr->b_psize;
+           __entry->hdr_lsize          = hdr->b_lsize;
            __entry->hdr_spa            = hdr->b_spa;
            __entry->hdr_state_type     = hdr->b_l1hdr.b_state->arcs_state;
            __entry->hdr_access         = hdr->b_l1hdr.b_arc_access;
@@ -323,7 +250,7 @@ DECLARE_EVENT_CLASS(zfs_arc_miss_class,
            __entry->zb_blkid           = zb->zb_blkid;
        ),
        TP_printk("hdr { dva 0x%llx:0x%llx birth %llu "
-           "flags 0x%x datacnt %u size %llu spa %llu state_type %u "
+           "flags 0x%x bufcnt %u psize %u lsize %u spa %llu state_type %u "
            "access %lu mru_hits %u mru_ghost_hits %u mfu_hits %u "
            "mfu_ghost_hits %u l2_hits %u refcount %lli } "
            "bp { dva0 0x%llx:0x%llx dva1 0x%llx:0x%llx dva2 "
@@ -332,7 +259,7 @@ DECLARE_EVENT_CLASS(zfs_arc_miss_class,
            "blkid %llu }",
            __entry->hdr_dva_word[0], __entry->hdr_dva_word[1],
            __entry->hdr_birth, __entry->hdr_flags,
-           __entry->hdr_datacnt, __entry->hdr_size,
+           __entry->hdr_bufcnt, __entry->hdr_psize, __entry->hdr_lsize,
            __entry->hdr_spa, __entry->hdr_state_type, __entry->hdr_access,
            __entry->hdr_mru_hits, __entry->hdr_mru_ghost_hits,
            __entry->hdr_mfu_hits, __entry->hdr_mfu_ghost_hits,
diff --git a/zfs/include/sys/trace_common.h b/zfs/include/sys/trace_common.h
new file mode 100644 (file)
index 0000000..6922d1a
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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
+ */
+
+/*
+ * This file contains commonly used trace macros.  Feel free to add and use
+ * them in your tracepoint headers.
+ */
+
+#ifndef        _SYS_TRACE_COMMON_H
+#define        _SYS_TRACE_COMMON_H
+#include <linux/tracepoint.h>
+
+/* ZIO macros */
+#define        ZIO_TP_STRUCT_ENTRY                                             \
+               __field(zio_type_t,             zio_type)               \
+               __field(int,                    zio_cmd)                \
+               __field(zio_priority_t,         zio_priority)           \
+               __field(uint64_t,               zio_size)               \
+               __field(uint64_t,               zio_orig_size)          \
+               __field(uint64_t,               zio_offset)             \
+               __field(hrtime_t,               zio_timestamp)          \
+               __field(hrtime_t,               zio_delta)              \
+               __field(uint64_t,               zio_delay)              \
+               __field(enum zio_flag,          zio_flags)              \
+               __field(enum zio_stage,         zio_stage)              \
+               __field(enum zio_stage,         zio_pipeline)           \
+               __field(enum zio_flag,          zio_orig_flags)         \
+               __field(enum zio_stage,         zio_orig_stage)         \
+               __field(enum zio_stage,         zio_orig_pipeline)      \
+               __field(uint8_t,                zio_reexecute)          \
+               __field(uint64_t,               zio_txg)                \
+               __field(int,                    zio_error)              \
+               __field(uint64_t,               zio_ena)                \
+                                                                       \
+               __field(enum zio_checksum,      zp_checksum)            \
+               __field(enum zio_compress,      zp_compress)            \
+               __field(dmu_object_type_t,      zp_type)                \
+               __field(uint8_t,                zp_level)               \
+               __field(uint8_t,                zp_copies)              \
+               __field(boolean_t,              zp_dedup)               \
+               __field(boolean_t,              zp_dedup_verify)        \
+               __field(boolean_t,              zp_nopwrite)
+
+#define        ZIO_TP_FAST_ASSIGN                                                  \
+               __entry->zio_type               = zio->io_type;             \
+               __entry->zio_cmd                = zio->io_cmd;              \
+               __entry->zio_priority           = zio->io_priority;         \
+               __entry->zio_size               = zio->io_size;             \
+               __entry->zio_orig_size          = zio->io_orig_size;        \
+               __entry->zio_offset             = zio->io_offset;           \
+               __entry->zio_timestamp          = zio->io_timestamp;        \
+               __entry->zio_delta              = zio->io_delta;            \
+               __entry->zio_delay              = zio->io_delay;            \
+               __entry->zio_flags              = zio->io_flags;            \
+               __entry->zio_stage              = zio->io_stage;            \
+               __entry->zio_pipeline           = zio->io_pipeline;         \
+               __entry->zio_orig_flags         = zio->io_orig_flags;       \
+               __entry->zio_orig_stage         = zio->io_orig_stage;       \
+               __entry->zio_orig_pipeline      = zio->io_orig_pipeline;    \
+               __entry->zio_reexecute          = zio->io_reexecute;        \
+               __entry->zio_txg                = zio->io_txg;              \
+               __entry->zio_error              = zio->io_error;            \
+               __entry->zio_ena                = zio->io_ena;              \
+                                                                           \
+               __entry->zp_checksum            = zio->io_prop.zp_checksum; \
+               __entry->zp_compress            = zio->io_prop.zp_compress; \
+               __entry->zp_type                = zio->io_prop.zp_type;     \
+               __entry->zp_level               = zio->io_prop.zp_level;    \
+               __entry->zp_copies              = zio->io_prop.zp_copies;   \
+               __entry->zp_dedup               = zio->io_prop.zp_dedup;    \
+               __entry->zp_nopwrite            = zio->io_prop.zp_nopwrite; \
+               __entry->zp_dedup_verify        = zio->io_prop.zp_dedup_verify;
+
+#define        ZIO_TP_PRINTK_FMT                                               \
+       "zio { type %u cmd %i prio %u size %llu orig_size %llu "        \
+       "offset %llu timestamp %llu delta %llu delay %llu "             \
+       "flags 0x%x stage 0x%x pipeline 0x%x orig_flags 0x%x "          \
+       "orig_stage 0x%x orig_pipeline 0x%x reexecute %u "              \
+       "txg %llu error %d ena %llu prop { checksum %u compress %u "    \
+       "type %u level %u copies %u dedup %u dedup_verify %u nopwrite %u } }"
+
+#define        ZIO_TP_PRINTK_ARGS                                              \
+       __entry->zio_type, __entry->zio_cmd, __entry->zio_priority,     \
+       __entry->zio_size, __entry->zio_orig_size, __entry->zio_offset, \
+       __entry->zio_timestamp, __entry->zio_delta, __entry->zio_delay, \
+       __entry->zio_flags, __entry->zio_stage, __entry->zio_pipeline,  \
+       __entry->zio_orig_flags, __entry->zio_orig_stage,               \
+       __entry->zio_orig_pipeline, __entry->zio_reexecute,             \
+       __entry->zio_txg, __entry->zio_error, __entry->zio_ena,         \
+       __entry->zp_checksum, __entry->zp_compress, __entry->zp_type,   \
+       __entry->zp_level, __entry->zp_copies, __entry->zp_dedup,       \
+       __entry->zp_dedup_verify, __entry->zp_nopwrite
+
+#endif /* _SYS_TRACE_COMMON_H */
index e493a45802ed8cb8646e0e51b6e384c8a9d608d3..22f7fd9868ba94b9417bd7848d6cedaeacd04c12 100644 (file)
@@ -51,19 +51,20 @@ DECLARE_EVENT_CLASS(zfs_dprintf_class,
            const char *msg),
        TP_ARGS(file, function, line, msg),
        TP_STRUCT__entry(
-           __field(const char *,       file)
-           __field(const char *,       function)
+           __string(file, file)
+           __string(function, function)
            __field(int,                line)
            __string(msg, msg)
        ),
        TP_fast_assign(
-           __entry->file               = file;
-           __entry->function           = function;
+           __assign_str(file, strchr(file, '/') ?
+               strrchr(file, '/') + 1 : file)
+           __assign_str(function, function);
            __entry->line               = line;
            __assign_str(msg, msg);
        ),
-       TP_printk("%s:%d:%s(): %s", __entry->file, __entry->line,
-           __entry->function, __get_str(msg))
+       TP_printk("%s:%d:%s(): %s", __get_str(file), __entry->line,
+           __get_str(function), __get_str(msg))
 );
 
 #define        DEFINE_DPRINTF_EVENT(name) \
@@ -88,24 +89,34 @@ DECLARE_EVENT_CLASS(zfs_set_error_class,
            uintptr_t error),
        TP_ARGS(file, function, line, error),
        TP_STRUCT__entry(
-           __field(const char *,       file)
-           __field(const char *,       function)
+           __string(file, file)
+           __string(function, function)
            __field(int,                line)
            __field(uintptr_t,          error)
        ),
        TP_fast_assign(
-           __entry->file = strchr(file, '/') ? strrchr(file, '/') + 1 : file;
-           __entry->function           = function;
+           __assign_str(file, strchr(file, '/') ?
+               strrchr(file, '/') + 1 : file)
+           __assign_str(function, function);
            __entry->line               = line;
            __entry->error              = error;
        ),
-       TP_printk("%s:%d:%s(): error 0x%lx", __entry->file, __entry->line,
-           __entry->function, __entry->error)
+       TP_printk("%s:%d:%s(): error 0x%lx", __get_str(file), __entry->line,
+           __get_str(function), __entry->error)
 );
 
+#ifdef TP_CONDITION
+#define        DEFINE_SET_ERROR_EVENT(name) \
+DEFINE_EVENT_CONDITION(zfs_set_error_class, name, \
+       TP_PROTO(const char *file, const char *function, int line, \
+           uintptr_t error), \
+       TP_ARGS(file, function, line, error), \
+       TP_CONDITION(error))
+#else
 #define        DEFINE_SET_ERROR_EVENT(name) \
 DEFINE_EVENT(zfs_set_error_class, name, \
        TP_PROTO(const char *file, const char *function, int line, \
            uintptr_t error), \
        TP_ARGS(file, function, line, error))
+#endif
 DEFINE_SET_ERROR_EVENT(zfs_set__error);
index 49e35e3dcbfe2bd32a54deea7480b135d9f9dba2..76274d15257530b8427f5a1e02dd1300805482e8 100644 (file)
@@ -42,7 +42,8 @@
  */
 
 #define        DBUF_TP_STRUCT_ENTRY                                    \
-       __field(const char *,   os_spa)                         \
+       __string(os_spa,                                        \
+           spa_name(DB_DNODE(db)->dn_objset->os_spa))          \
        __field(uint64_t,       ds_object)                      \
        __field(uint64_t,       db_object)                      \
        __field(uint64_t,       db_level)                       \
@@ -53,8 +54,8 @@
        __field(int64_t,        db_holds)                       \
 
 #define        DBUF_TP_FAST_ASSIGN                                     \
-       __entry->os_spa =                                       \
-           spa_name(DB_DNODE(db)->dn_objset->os_spa)         \
+       __assign_str(os_spa,                                    \
+           spa_name(DB_DNODE(db)->dn_objset->os_spa));         \
                                                                \
        __entry->ds_object = db->db_objset->os_dsl_dataset ?    \
            db->db_objset->os_dsl_dataset->ds_object : 0;       \
@@ -72,7 +73,7 @@
        "blkid %llu offset %llu size %llu state %llu holds %lld }"
 
 #define        DBUF_TP_PRINTK_ARGS                                     \
-       __entry->os_spa, __entry->ds_object,                    \
+       __get_str(os_spa), __entry->ds_object,                  \
        __entry->db_object, __entry->db_level,                  \
        __entry->db_blkid, __entry->db_offset,                  \
        __entry->db_size, __entry->db_state, __entry->db_holds
@@ -91,6 +92,20 @@ DEFINE_EVENT(zfs_dbuf_class, name, \
        TP_ARGS(db, zio))
 DEFINE_DBUF_EVENT(zfs_blocked__read);
 
+DECLARE_EVENT_CLASS(zfs_dbuf_evict_one_class,
+       TP_PROTO(dmu_buf_impl_t *db, multilist_sublist_t *mls),
+       TP_ARGS(db, mls),
+       TP_STRUCT__entry(DBUF_TP_STRUCT_ENTRY),
+       TP_fast_assign(DBUF_TP_FAST_ASSIGN),
+       TP_printk(DBUF_TP_PRINTK_FMT, DBUF_TP_PRINTK_ARGS)
+);
+
+#define        DEFINE_DBUF_EVICT_ONE_EVENT(name) \
+DEFINE_EVENT(zfs_dbuf_evict_one_class, name, \
+       TP_PROTO(dmu_buf_impl_t *db, multilist_sublist_t *mls), \
+       TP_ARGS(db, mls))
+DEFINE_DBUF_EVICT_ONE_EVENT(zfs_dbuf__evict__one);
+
 #endif /* _TRACE_DBUF_H */
 
 #undef TRACE_INCLUDE_PATH
diff --git a/zfs/include/sys/trace_zio.h b/zfs/include/sys/trace_zio.h
new file mode 100644 (file)
index 0000000..6db6cef
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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
+ */
+
+#include <sys/list.h>
+
+#if defined(_KERNEL) && defined(HAVE_DECLARE_EVENT_CLASS)
+
+#undef TRACE_SYSTEM
+#define        TRACE_SYSTEM zfs
+
+#undef TRACE_SYSTEM_VAR
+#define        TRACE_SYSTEM_VAR zfs_zio
+
+#if !defined(_TRACE_ZIO_H) || defined(TRACE_HEADER_MULTI_READ)
+#define        _TRACE_ZIO_H
+
+#include <linux/tracepoint.h>
+#include <sys/types.h>
+#include <sys/trace_common.h> /* For ZIO macros */
+
+TRACE_EVENT(zfs_zio__delay__miss,
+       TP_PROTO(zio_t *zio, hrtime_t now),
+       TP_ARGS(zio, now),
+       TP_STRUCT__entry(
+           ZIO_TP_STRUCT_ENTRY
+           __field(hrtime_t, now)
+       ),
+       TP_fast_assign(
+           ZIO_TP_FAST_ASSIGN
+           __entry->now = now;
+       ),
+       TP_printk("now %llu " ZIO_TP_PRINTK_FMT, __entry->now,
+           ZIO_TP_PRINTK_ARGS)
+);
+
+TRACE_EVENT(zfs_zio__delay__hit,
+       TP_PROTO(zio_t *zio, hrtime_t now, hrtime_t diff),
+       TP_ARGS(zio, now, diff),
+       TP_STRUCT__entry(
+           ZIO_TP_STRUCT_ENTRY
+           __field(hrtime_t, now)
+           __field(hrtime_t, diff)
+       ),
+       TP_fast_assign(
+           ZIO_TP_FAST_ASSIGN
+           __entry->now = now;
+           __entry->diff = diff;
+       ),
+       TP_printk("now %llu diff %llu " ZIO_TP_PRINTK_FMT, __entry->now,
+           __entry->diff, ZIO_TP_PRINTK_ARGS)
+);
+
+TRACE_EVENT(zfs_zio__delay__skip,
+       TP_PROTO(zio_t *zio),
+       TP_ARGS(zio),
+       TP_STRUCT__entry(ZIO_TP_STRUCT_ENTRY),
+       TP_fast_assign(ZIO_TP_FAST_ASSIGN),
+       TP_printk(ZIO_TP_PRINTK_FMT, ZIO_TP_PRINTK_ARGS)
+);
+
+#endif /* _TRACE_ZIO_H */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define        TRACE_INCLUDE_PATH sys
+#define        TRACE_INCLUDE_FILE trace_zio
+#include <trace/define_trace.h>
+
+#endif /* _KERNEL && HAVE_DECLARE_EVENT_CLASS */
index e1399c468a74ad6e19b8621d14175aa926f4824f..356a86a6bb6e7e72f6a13583460cc3048a735fe1 100644 (file)
@@ -48,7 +48,7 @@ DECLARE_EVENT_CLASS(zfs_zrlock_class,
            __field(int32_t,            refcount)
 #ifdef ZFS_DEBUG
            __field(pid_t,              owner_pid)
-           __field(const char *,       caller)
+           __string(caller, zrl->zr_caller)
 #endif
            __field(uint32_t,           n)
        ),
@@ -56,13 +56,13 @@ DECLARE_EVENT_CLASS(zfs_zrlock_class,
            __entry->refcount   = zrl->zr_refcount;
 #ifdef ZFS_DEBUG
            __entry->owner_pid  = zrl->zr_owner ? zrl->zr_owner->pid : 0;
-           __entry->caller     = zrl->zr_caller;
+           __assign_str(caller, zrl->zr_caller);
 #endif
            __entry->n          = n;
        ),
 #ifdef ZFS_DEBUG
        TP_printk("zrl { refcount %d owner_pid %d caller %s } n %u",
-           __entry->refcount, __entry->owner_pid, __entry->caller,
+           __entry->refcount, __entry->owner_pid, __get_str(caller),
            __entry->n)
 #else
        TP_printk("zrl { refcount %d } n %u",
index 365789e524d6d3375f831f253a7bee20cc1bb65c..4f54b1707c54383f6e6f34e16aa527a54861afa2 100644 (file)
@@ -70,6 +70,10 @@ extern void vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg,
 extern boolean_t vdev_dtl_required(vdev_t *vd);
 extern boolean_t vdev_resilver_needed(vdev_t *vd,
     uint64_t *minp, uint64_t *maxp);
+extern void vdev_destroy_unlink_zap(vdev_t *vd, uint64_t zapobj,
+    dmu_tx_t *tx);
+extern uint64_t vdev_create_link_zap(vdev_t *vd, dmu_tx_t *tx);
+extern void vdev_construct_zaps(vdev_t *vd, dmu_tx_t *tx);
 
 extern void vdev_hold(vdev_t *);
 extern void vdev_rele(vdev_t *);
@@ -81,7 +85,7 @@ extern void vdev_expand(vdev_t *vd, uint64_t txg);
 extern void vdev_split(vdev_t *vd);
 extern void vdev_deadman(vdev_t *vd);
 
-
+extern void vdev_get_stats_ex(vdev_t *vd, vdev_stat_t *vs, vdev_stat_ex_t *vsx);
 extern void vdev_get_stats(vdev_t *vd, vdev_stat_t *vs);
 extern void vdev_clear_stats(vdev_t *vd);
 extern void vdev_stat_update(zio_t *zio, uint64_t psize);
@@ -119,10 +123,13 @@ extern void vdev_queue_fini(vdev_t *vd);
 extern zio_t *vdev_queue_io(zio_t *zio);
 extern void vdev_queue_io_done(zio_t *zio);
 
+extern int vdev_queue_length(vdev_t *vd);
+extern uint64_t vdev_queue_lastoffset(vdev_t *vd);
+extern void vdev_queue_register_lastoffset(vdev_t *vd, zio_t *zio);
+
 extern void vdev_config_dirty(vdev_t *vd);
 extern void vdev_config_clean(vdev_t *vd);
-extern int vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg,
-    boolean_t);
+extern int vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg);
 
 extern void vdev_state_dirty(vdev_t *vd);
 extern void vdev_state_clean(vdev_t *vd);
@@ -130,7 +137,8 @@ extern void vdev_state_clean(vdev_t *vd);
 typedef enum vdev_config_flag {
        VDEV_CONFIG_SPARE = 1 << 0,
        VDEV_CONFIG_L2CACHE = 1 << 1,
-       VDEV_CONFIG_REMOVING = 1 << 2
+       VDEV_CONFIG_REMOVING = 1 << 2,
+       VDEV_CONFIG_MOS = 1 << 3
 } vdev_config_flag_t;
 
 extern void vdev_top_config_generate(spa_t *spa, nvlist_t *config);
@@ -145,6 +153,7 @@ extern uint64_t vdev_label_offset(uint64_t psize, int l, uint64_t offset);
 extern int vdev_label_number(uint64_t psise, uint64_t offset);
 extern nvlist_t *vdev_label_read_config(vdev_t *vd, uint64_t txg);
 extern void vdev_uberblock_load(vdev_t *, struct uberblock *, nvlist_t **);
+extern void vdev_config_generate_stats(vdev_t *vd, nvlist_t *nv);
 
 typedef enum {
        VDEV_LABEL_CREATE,      /* create/add a new device */
index cf8028d2aca53caec52315da76ea4d18253aef48..15570b10553f4cd68c535c4fb20e929040d1dc64 100644 (file)
@@ -37,9 +37,5 @@ typedef struct vdev_disk {
        struct block_device     *vd_bdev;
 } vdev_disk_t;
 
-extern int vdev_disk_physio(struct block_device *, caddr_t,
-                           size_t, uint64_t, int, int);
-extern int vdev_disk_read_rootlabel(char *, char *, nvlist_t **);
-
 #endif /* _KERNEL */
 #endif /* _SYS_VDEV_DISK_H */
index 1371a3f0391f17c1e3fd072bbdc67d40405040e0..b9a2d181b968f21ef08d68a7d6a8fa0a5ef1bbd7 100644 (file)
@@ -34,6 +34,7 @@
 #include <sys/vdev.h>
 #include <sys/dkio.h>
 #include <sys/uberblock_impl.h>
+#include <sys/zfs_ratelimit.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -53,6 +54,9 @@ typedef struct vdev_queue vdev_queue_t;
 typedef struct vdev_cache vdev_cache_t;
 typedef struct vdev_cache_entry vdev_cache_entry_t;
 
+extern int zfs_vdev_queue_depth_pct;
+extern uint32_t zfs_vdev_async_write_max_active;
+
 /*
  * Virtual device operations
  */
@@ -120,6 +124,7 @@ struct vdev_queue {
        hrtime_t        vq_io_delta_ts;
        zio_t           vq_io_search; /* used as local for stack reduction */
        kmutex_t        vq_lock;
+       uint64_t        vq_lastoffset;
 };
 
 /*
@@ -149,6 +154,7 @@ struct vdev {
        vdev_t          **vdev_child;   /* array of children            */
        uint64_t        vdev_children;  /* number of children           */
        vdev_stat_t     vdev_stat;      /* virtual device statistics    */
+       vdev_stat_ex_t  vdev_stat_ex;   /* extended statistics          */
        boolean_t       vdev_expanding; /* expand the vdev?             */
        boolean_t       vdev_reopening; /* reopen in progress?          */
        boolean_t       vdev_nonrot;    /* true if solid state          */
@@ -175,7 +181,19 @@ struct vdev {
        uint64_t        vdev_deflate_ratio; /* deflation ratio (x512)   */
        uint64_t        vdev_islog;     /* is an intent log device      */
        uint64_t        vdev_removing;  /* device is being removed?     */
-       boolean_t       vdev_ishole;    /* is a hole in the namespace   */
+       boolean_t       vdev_ishole;    /* is a hole in the namespace   */
+       kmutex_t        vdev_queue_lock; /* protects vdev_queue_depth   */
+       uint64_t        vdev_top_zap;
+
+       /*
+        * The queue depth parameters determine how many async writes are
+        * still pending (i.e. allocated by net yet issued to disk) per
+        * top-level (vdev_async_write_queue_depth) and the maximum allowed
+        * (vdev_max_async_write_queue_depth). These values only apply to
+        * top-level vdevs.
+        */
+       uint64_t        vdev_async_write_queue_depth;
+       uint64_t        vdev_max_async_write_queue_depth;
 
        /*
         * Leaf vdev state.
@@ -195,6 +213,7 @@ struct vdev {
        char            *vdev_path;     /* vdev path (if any)           */
        char            *vdev_devid;    /* vdev devid (if any)          */
        char            *vdev_physpath; /* vdev device path (if any)    */
+       char            *vdev_enc_sysfs_path;   /* enclosure sysfs path */
        char            *vdev_fru;      /* physical FRU location        */
        uint64_t        vdev_not_present; /* not present during import  */
        uint64_t        vdev_unspare;   /* unspare when resilvering done */
@@ -214,6 +233,7 @@ struct vdev {
        spa_aux_vdev_t  *vdev_aux;      /* for l2cache and spares vdevs */
        zio_t           *vdev_probe_zio; /* root of current probe       */
        vdev_aux_t      vdev_label_aux; /* on-disk aux state            */
+       uint64_t        vdev_leaf_zap;
 
        /*
         * For DTrace to work in userland (libzpool) context, these fields must
@@ -225,6 +245,15 @@ struct vdev {
        kmutex_t        vdev_dtl_lock;  /* vdev_dtl_{map,resilver}      */
        kmutex_t        vdev_stat_lock; /* vdev_stat                    */
        kmutex_t        vdev_probe_lock; /* protects vdev_probe_zio     */
+
+       /*
+        * We rate limit ZIO delay and ZIO checksum events, since they
+        * can flood ZED with tons of events when a drive is acting up.
+        */
+#define        DELAYS_PER_SECOND 5
+#define        CHECKSUMS_PER_SECOND 5
+       zfs_ratelimit_t vdev_delay_rl;
+       zfs_ratelimit_t vdev_checksum_rl;
 };
 
 #define        VDEV_RAIDZ_MAXPARITY    3
diff --git a/zfs/include/sys/vdev_raidz.h b/zfs/include/sys/vdev_raidz.h
new file mode 100644 (file)
index 0000000..06e21af
--- /dev/null
@@ -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 (C) 2016 Gvozden Neskovic <neskovic@compeng.uni-frankfurt.de>.
+ */
+
+#ifndef _SYS_VDEV_RAIDZ_H
+#define        _SYS_VDEV_RAIDZ_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct zio;
+struct raidz_map;
+#if !defined(_KERNEL)
+struct kernel_param {};
+#endif
+
+/*
+ * vdev_raidz interface
+ */
+struct raidz_map * vdev_raidz_map_alloc(struct zio *, uint64_t, uint64_t,
+    uint64_t);
+void           vdev_raidz_map_free(struct raidz_map *);
+void           vdev_raidz_generate_parity(struct raidz_map *);
+int            vdev_raidz_reconstruct(struct raidz_map *, const int *, int);
+
+/*
+ * vdev_raidz_math interface
+ */
+void                   vdev_raidz_math_init(void);
+void                   vdev_raidz_math_fini(void);
+struct raidz_impl_ops *        vdev_raidz_math_get_ops(void);
+int                    vdev_raidz_math_generate(struct raidz_map *);
+int                    vdev_raidz_math_reconstruct(struct raidz_map *,
+                           const int *, const int *, const int);
+int                    vdev_raidz_impl_set(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VDEV_RAIDZ_H */
diff --git a/zfs/include/sys/vdev_raidz_impl.h b/zfs/include/sys/vdev_raidz_impl.h
new file mode 100644 (file)
index 0000000..ca902f1
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#ifndef _VDEV_RAIDZ_H
+#define        _VDEV_RAIDZ_H
+
+#include <sys/types.h>
+#include <sys/debug.h>
+#include <sys/kstat.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define        CODE_P          (0U)
+#define        CODE_Q          (1U)
+#define        CODE_R          (2U)
+
+#define        PARITY_P        (1U)
+#define        PARITY_PQ       (2U)
+#define        PARITY_PQR      (3U)
+
+#define        TARGET_X        (0U)
+#define        TARGET_Y        (1U)
+#define        TARGET_Z        (2U)
+
+/*
+ * Parity generation methods indexes
+ */
+enum raidz_math_gen_op {
+       RAIDZ_GEN_P = 0,
+       RAIDZ_GEN_PQ,
+       RAIDZ_GEN_PQR,
+       RAIDZ_GEN_NUM = 3
+};
+/*
+ * Data reconstruction methods indexes
+ */
+enum raidz_rec_op {
+       RAIDZ_REC_P = 0,
+       RAIDZ_REC_Q,
+       RAIDZ_REC_R,
+       RAIDZ_REC_PQ,
+       RAIDZ_REC_PR,
+       RAIDZ_REC_QR,
+       RAIDZ_REC_PQR,
+       RAIDZ_REC_NUM = 7
+};
+
+extern const char *raidz_gen_name[RAIDZ_GEN_NUM];
+extern const char *raidz_rec_name[RAIDZ_REC_NUM];
+
+/*
+ * Methods used to define raidz implementation
+ *
+ * @raidz_gen_f        Parity generation function
+ *     @par1   pointer to raidz_map
+ * @raidz_rec_f        Data reconstruction function
+ *     @par1   pointer to raidz_map
+ *     @par2   array of reconstruction targets
+ * @will_work_f Function returns TRUE if impl. is supported on the system
+ * @init_impl_f Function is called once on init
+ * @fini_impl_f Function is called once on fini
+ */
+typedef void           (*raidz_gen_f)(void *);
+typedef int            (*raidz_rec_f)(void *, const int *);
+typedef boolean_t      (*will_work_f)(void);
+typedef void           (*init_impl_f)(void);
+typedef void           (*fini_impl_f)(void);
+
+#define        RAIDZ_IMPL_NAME_MAX     (16)
+
+typedef struct raidz_impl_ops {
+       init_impl_f init;
+       fini_impl_f fini;
+       raidz_gen_f gen[RAIDZ_GEN_NUM]; /* Parity generate functions */
+       raidz_rec_f rec[RAIDZ_REC_NUM]; /* Data reconstruction functions */
+       will_work_f is_supported;       /* Support check function */
+       char name[RAIDZ_IMPL_NAME_MAX]; /* Name of the implementation */
+} raidz_impl_ops_t;
+
+typedef struct raidz_col {
+       size_t rc_devidx;               /* child device index for I/O */
+       size_t rc_offset;               /* device offset */
+       size_t rc_size;                 /* I/O size */
+       void *rc_data;                  /* I/O data */
+       void *rc_gdata;                 /* used to store the "good" version */
+       int rc_error;                   /* I/O error for this device */
+       unsigned int rc_tried;          /* Did we attempt this I/O column? */
+       unsigned int rc_skipped;        /* Did we skip this I/O column? */
+} raidz_col_t;
+
+typedef struct raidz_map {
+       size_t rm_cols;                 /* Regular column count */
+       size_t rm_scols;                /* Count including skipped columns */
+       size_t rm_bigcols;              /* Number of oversized columns */
+       size_t rm_asize;                /* Actual total I/O size */
+       size_t rm_missingdata;          /* Count of missing data devices */
+       size_t rm_missingparity;        /* Count of missing parity devices */
+       size_t rm_firstdatacol;         /* First data column/parity count */
+       size_t rm_nskip;                /* Skipped sectors for padding */
+       size_t rm_skipstart;            /* Column index of padding start */
+       void *rm_datacopy;              /* rm_asize-buffer of copied data */
+       size_t rm_reports;              /* # of referencing checksum reports */
+       unsigned int rm_freed;          /* map no longer has referencing ZIO */
+       unsigned int rm_ecksuminjected; /* checksum error was injected */
+       raidz_impl_ops_t *rm_ops;       /* RAIDZ math operations */
+       raidz_col_t rm_col[1];          /* Flexible array of I/O columns */
+} raidz_map_t;
+
+#define        RAIDZ_ORIGINAL_IMPL     (INT_MAX)
+
+extern const raidz_impl_ops_t vdev_raidz_scalar_impl;
+#if defined(__x86_64) && defined(HAVE_SSE2)    /* only x86_64 for now */
+extern const raidz_impl_ops_t vdev_raidz_sse2_impl;
+#endif
+#if defined(__x86_64) && defined(HAVE_SSSE3)   /* only x86_64 for now */
+extern const raidz_impl_ops_t vdev_raidz_ssse3_impl;
+#endif
+#if defined(__x86_64) && defined(HAVE_AVX2)    /* only x86_64 for now */
+extern const raidz_impl_ops_t vdev_raidz_avx2_impl;
+#endif
+#if defined(__aarch64__)
+extern const raidz_impl_ops_t vdev_raidz_aarch64_neon_impl;
+extern const raidz_impl_ops_t vdev_raidz_aarch64_neonx2_impl;
+#endif
+
+/*
+ * Commonly used raidz_map helpers
+ *
+ * raidz_parity                Returns parity of the RAIDZ block
+ * raidz_ncols         Returns number of columns the block spans
+ * raidz_nbigcols      Returns number of big columns columns
+ * raidz_col_p         Returns pointer to a column
+ * raidz_col_size      Returns size of a column
+ * raidz_big_size      Returns size of big columns
+ * raidz_short_size    Returns size of short columns
+ */
+#define        raidz_parity(rm)        ((rm)->rm_firstdatacol)
+#define        raidz_ncols(rm)         ((rm)->rm_cols)
+#define        raidz_nbigcols(rm)      ((rm)->rm_bigcols)
+#define        raidz_col_p(rm, c)      ((rm)->rm_col + (c))
+#define        raidz_col_size(rm, c)   ((rm)->rm_col[c].rc_size)
+#define        raidz_big_size(rm)      (raidz_col_size(rm, CODE_P))
+#define        raidz_short_size(rm)    (raidz_col_size(rm, raidz_ncols(rm)-1))
+
+/*
+ * Macro defines an RAIDZ parity generation method
+ *
+ * @code       parity the function produce
+ * @impl       name of the implementation
+ */
+#define        _RAIDZ_GEN_WRAP(code, impl)                                     \
+static void                                                            \
+impl ## _gen_ ## code(void *rmp)                                       \
+{                                                                      \
+       raidz_map_t *rm = (raidz_map_t *) rmp;                          \
+       raidz_generate_## code ## _impl(rm);                            \
+}
+
+/*
+ * Macro defines an RAIDZ data reconstruction method
+ *
+ * @code       parity the function produce
+ * @impl       name of the implementation
+ */
+#define        _RAIDZ_REC_WRAP(code, impl)                                     \
+static int                                                             \
+impl ## _rec_ ## code(void *rmp, const int *tgtidx)                    \
+{                                                                      \
+       raidz_map_t *rm = (raidz_map_t *) rmp;                          \
+       return (raidz_reconstruct_## code ## _impl(rm, tgtidx));        \
+}
+
+/*
+ * Define all gen methods for an implementation
+ *
+ * @impl       name of the implementation
+ */
+#define        DEFINE_GEN_METHODS(impl)                                        \
+       _RAIDZ_GEN_WRAP(p, impl);                                       \
+       _RAIDZ_GEN_WRAP(pq, impl);                                      \
+       _RAIDZ_GEN_WRAP(pqr, impl)
+
+/*
+ * Define all rec functions for an implementation
+ *
+ * @impl       name of the implementation
+ */
+#define        DEFINE_REC_METHODS(impl)                                        \
+       _RAIDZ_REC_WRAP(p, impl);                                       \
+       _RAIDZ_REC_WRAP(q, impl);                                       \
+       _RAIDZ_REC_WRAP(r, impl);                                       \
+       _RAIDZ_REC_WRAP(pq, impl);                                      \
+       _RAIDZ_REC_WRAP(pr, impl);                                      \
+       _RAIDZ_REC_WRAP(qr, impl);                                      \
+       _RAIDZ_REC_WRAP(pqr, impl)
+
+#define        RAIDZ_GEN_METHODS(impl)                                         \
+{                                                                      \
+       [RAIDZ_GEN_P] = & impl ## _gen_p,                               \
+       [RAIDZ_GEN_PQ] = & impl ## _gen_pq,                             \
+       [RAIDZ_GEN_PQR] = & impl ## _gen_pqr                            \
+}
+
+#define        RAIDZ_REC_METHODS(impl)                                         \
+{                                                                      \
+       [RAIDZ_REC_P] = & impl ## _rec_p,                               \
+       [RAIDZ_REC_Q] = & impl ## _rec_q,                               \
+       [RAIDZ_REC_R] = & impl ## _rec_r,                               \
+       [RAIDZ_REC_PQ] = & impl ## _rec_pq,                             \
+       [RAIDZ_REC_PR] = & impl ## _rec_pr,                             \
+       [RAIDZ_REC_QR] = & impl ## _rec_qr,                             \
+       [RAIDZ_REC_PQR] = & impl ## _rec_pqr                            \
+}
+
+
+typedef struct raidz_impl_kstat {
+       uint64_t gen[RAIDZ_GEN_NUM];    /* gen method speed B/s */
+       uint64_t rec[RAIDZ_REC_NUM];    /* rec method speed B/s */
+} raidz_impl_kstat_t;
+
+/*
+ * Enumerate various multiplication constants
+ * used in reconstruction methods
+ */
+typedef enum raidz_mul_info {
+       /* Reconstruct Q */
+       MUL_Q_X         = 0,
+       /* Reconstruct R */
+       MUL_R_X         = 0,
+       /* Reconstruct PQ */
+       MUL_PQ_X        = 0,
+       MUL_PQ_Y        = 1,
+       /* Reconstruct PR */
+       MUL_PR_X        = 0,
+       MUL_PR_Y        = 1,
+       /* Reconstruct QR */
+       MUL_QR_XQ       = 0,
+       MUL_QR_X        = 1,
+       MUL_QR_YQ       = 2,
+       MUL_QR_Y        = 3,
+       /* Reconstruct PQR */
+       MUL_PQR_XP      = 0,
+       MUL_PQR_XQ      = 1,
+       MUL_PQR_XR      = 2,
+       MUL_PQR_YU      = 3,
+       MUL_PQR_YP      = 4,
+       MUL_PQR_YQ      = 5,
+
+       MUL_CNT         = 6
+} raidz_mul_info_t;
+
+/*
+ * Powers of 2 in the Galois field.
+ */
+extern const uint8_t vdev_raidz_pow2[256] __attribute__((aligned(256)));
+/* Logs of 2 in the Galois field defined above. */
+extern const uint8_t vdev_raidz_log2[256] __attribute__((aligned(256)));
+
+/*
+ * Multiply a given number by 2 raised to the given power.
+ */
+static inline uint8_t
+vdev_raidz_exp2(const uint8_t a, const unsigned exp)
+{
+       if (a == 0)
+               return (0);
+
+       return (vdev_raidz_pow2[(exp + (unsigned) vdev_raidz_log2[a]) % 255]);
+}
+
+/*
+ * Galois Field operations.
+ *
+ * gf_exp2     - computes 2 raised to the given power
+ * gf_exp2     - computes 4 raised to the given power
+ * gf_mul      - multiplication
+ * gf_div      - division
+ * gf_inv      - multiplicative inverse
+ */
+typedef unsigned gf_t;
+typedef unsigned gf_log_t;
+
+static inline gf_t
+gf_mul(const gf_t a, const gf_t b)
+{
+       gf_log_t logsum;
+
+       if (a == 0 || b == 0)
+               return (0);
+
+       logsum = (gf_log_t) vdev_raidz_log2[a] + (gf_log_t) vdev_raidz_log2[b];
+
+       return ((gf_t) vdev_raidz_pow2[logsum % 255]);
+}
+
+static inline gf_t
+gf_div(const gf_t  a, const gf_t b)
+{
+       gf_log_t logsum;
+
+       ASSERT3U(b, >, 0);
+       if (a == 0)
+               return (0);
+
+       logsum = (gf_log_t) 255 + (gf_log_t) vdev_raidz_log2[a] -
+           (gf_log_t) vdev_raidz_log2[b];
+
+       return ((gf_t) vdev_raidz_pow2[logsum % 255]);
+}
+
+static inline gf_t
+gf_inv(const gf_t a)
+{
+       gf_log_t logsum;
+
+       ASSERT3U(a, >, 0);
+
+       logsum = (gf_log_t) 255 - (gf_log_t) vdev_raidz_log2[a];
+
+       return ((gf_t) vdev_raidz_pow2[logsum]);
+}
+
+static inline gf_t
+gf_exp2(gf_log_t exp)
+{
+       return (vdev_raidz_pow2[exp % 255]);
+}
+
+static inline gf_t
+gf_exp4(gf_log_t exp)
+{
+       ASSERT3U(exp, <=, 255);
+       return ((gf_t) vdev_raidz_pow2[(2 * exp) % 255]);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _VDEV_RAIDZ_H */
index ed60b86dbd71b900955e0a5e1ae1dc85b1ada283..c4169029adf8eee131fe8e3ac978ae0f24fe1fa3 100644 (file)
@@ -129,16 +129,30 @@ typedef enum zap_flags {
  *     MT_FIRST/MT_BEST matching will find entries that match without
  *     regard to case (eg. looking for "foo" can find an entry "Foo").
  * Eventually, other flags will permit unicode normalization as well.
+ *
+ * dnodesize specifies the on-disk size of the dnode for the new zapobj.
+ * Valid values are multiples of 512 up to DNODE_MAX_SIZE.
  */
 uint64_t zap_create(objset_t *ds, dmu_object_type_t ot,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+uint64_t zap_create_dnsize(objset_t *ds, dmu_object_type_t ot,
+    dmu_object_type_t bonustype, int bonuslen, int dnodesize, dmu_tx_t *tx);
 uint64_t zap_create_norm(objset_t *ds, int normflags, dmu_object_type_t ot,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+uint64_t zap_create_norm_dnsize(objset_t *ds, int normflags,
+    dmu_object_type_t ot, dmu_object_type_t bonustype, int bonuslen,
+    int dnodesize, dmu_tx_t *tx);
 uint64_t zap_create_flags(objset_t *os, int normflags, zap_flags_t flags,
     dmu_object_type_t ot, int leaf_blockshift, int indirect_blockshift,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+uint64_t zap_create_flags_dnsize(objset_t *os, int normflags,
+    zap_flags_t flags, dmu_object_type_t ot, int leaf_blockshift,
+    int indirect_blockshift, dmu_object_type_t bonustype, int bonuslen,
+    int dnodesize, dmu_tx_t *tx);
 uint64_t zap_create_link(objset_t *os, dmu_object_type_t ot,
     uint64_t parent_obj, const char *name, dmu_tx_t *tx);
+uint64_t zap_create_link_dnsize(objset_t *os, dmu_object_type_t ot,
+    uint64_t parent_obj, const char *name, int dnodesize, dmu_tx_t *tx);
 
 /*
  * Initialize an already-allocated object.
@@ -152,9 +166,14 @@ void mzap_create_impl(objset_t *os, uint64_t obj, int normflags,
  */
 int zap_create_claim(objset_t *ds, uint64_t obj, dmu_object_type_t ot,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+int zap_create_claim_dnsize(objset_t *ds, uint64_t obj, dmu_object_type_t ot,
+    dmu_object_type_t bonustype, int bonuslen, int dnodesize, dmu_tx_t *tx);
 int zap_create_claim_norm(objset_t *ds, uint64_t obj,
     int normflags, dmu_object_type_t ot,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx);
+int zap_create_claim_norm_dnsize(objset_t *ds, uint64_t obj,
+    int normflags, dmu_object_type_t ot,
+    dmu_object_type_t bonustype, int bonuslen, int dnodesize, dmu_tx_t *tx);
 
 /*
  * The zapobj passed in must be a valid ZAP object for all of the
@@ -217,7 +236,14 @@ int zap_prefetch(objset_t *os, uint64_t zapobj, const char *name);
 int zap_prefetch_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
     int key_numints);
 
-int zap_count_write(objset_t *os, uint64_t zapobj, const char *name,
+int zap_lookup_by_dnode(dnode_t *dn, const char *name,
+    uint64_t integer_size, uint64_t num_integers, void *buf);
+int zap_lookup_norm_by_dnode(dnode_t *dn, const char *name,
+    uint64_t integer_size, uint64_t num_integers, void *buf,
+    matchtype_t mt, char *realname, int rn_len,
+    boolean_t *ncp);
+
+int zap_count_write_by_dnode(dnode_t *dn, const char *name,
     int add, uint64_t *towrite, uint64_t *tooverwrite);
 
 /*
@@ -344,7 +370,7 @@ typedef struct {
        boolean_t za_normalization_conflict;
        uint64_t za_num_integers;
        uint64_t za_first_integer;      /* no sign extension for <8byte ints */
-       char za_name[MAXNAMELEN];
+       char za_name[ZAP_MAXNAMELEN];
 } zap_attribute_t;
 
 /*
index bfd43e31da80043dfb93c0d23dc3da4117f22339..7b6d1b553b8052f67f1c1f1d3b991d152b334ee6 100644 (file)
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright (c) 2013, 2016 by Delphix. All rights reserved.
  */
 
 #ifndef        _SYS_ZAP_IMPL_H
@@ -195,8 +196,8 @@ typedef struct zap_name {
 
 boolean_t zap_match(zap_name_t *zn, const char *matchname);
 int zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
-    krw_t lti, boolean_t fatreader, boolean_t adding, zap_t **zapp);
-void zap_unlockdir(zap_t *zap);
+    krw_t lti, boolean_t fatreader, boolean_t adding, void *tag, zap_t **zapp);
+void zap_unlockdir(zap_t *zap, void *tag);
 void zap_evict(void *dbu);
 zap_name_t *zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt);
 void zap_name_free(zap_name_t *zn);
@@ -215,9 +216,10 @@ void fzap_prefetch(zap_name_t *zn);
 int fzap_count_write(zap_name_t *zn, int add, uint64_t *towrite,
     uint64_t *tooverwrite);
 int fzap_add(zap_name_t *zn, uint64_t integer_size, uint64_t num_integers,
-    const void *val, dmu_tx_t *tx);
+    const void *val, void *tag, dmu_tx_t *tx);
 int fzap_update(zap_name_t *zn,
-    int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx);
+    int integer_size, uint64_t num_integers, const void *val,
+    void *tag, dmu_tx_t *tx);
 int fzap_length(zap_name_t *zn,
     uint64_t *integer_size, uint64_t *num_integers);
 int fzap_remove(zap_name_t *zn, dmu_tx_t *tx);
@@ -227,7 +229,7 @@ void zap_put_leaf(struct zap_leaf *l);
 
 int fzap_add_cd(zap_name_t *zn,
     uint64_t integer_size, uint64_t num_integers,
-    const void *val, uint32_t cd, dmu_tx_t *tx);
+    const void *val, uint32_t cd, void *tag, dmu_tx_t *tx);
 void fzap_upgrade(zap_t *zap, dmu_tx_t *tx, zap_flags_t flags);
 
 #ifdef __cplusplus
index 4f7e3287f3da3fea051acdab27943771f6b1e28c..bc508755150da9954793c3d755727004082371c2 100644 (file)
@@ -25,7 +25,7 @@
 /*
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #ifndef _SYS_ZFS_CONTEXT_H
 #include <vm/seg_kmem.h>
 #include <sys/zone.h>
 #include <sys/sdt.h>
+#include <sys/kstat.h>
 #include <sys/zfs_debug.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/eventdefs.h>
 #include <sys/zfs_delay.h>
-#include <sys/fm/fs/zfs.h>
 #include <sys/sunddi.h>
 #include <sys/ctype.h>
 #include <sys/disp.h>
 #include <sys/sdt.h>
 #include <sys/kstat.h>
 #include <sys/u8_textprep.h>
-#include <sys/fm/fs/zfs.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/eventdefs.h>
 #include <sys/sunddi.h>
 #include <sys/debug.h>
 #include <sys/utsname.h>
  */
 
 #define        noinline        __attribute__((noinline))
+#define        likely(x)       __builtin_expect((x), 1)
 
 /*
  * Debugging
@@ -160,8 +164,18 @@ extern int aok;
 
 /*
  * DTrace SDT probes have different signatures in userland than they do in
- * kernel.  If they're being used in kernel code, re-define them out of
+ * the kernel.  If they're being used in kernel code, re-define them out of
  * existence for their counterparts in libzpool.
+ *
+ * Here's an example of how to use the set-error probes in userland:
+ * zfs$target:::set-error /arg0 == EBUSY/ {stack();}
+ *
+ * Here's an example of how to use DTRACE_PROBE probes in userland:
+ * If there is a probe declared as follows:
+ * DTRACE_PROBE2(zfs__probe_name, uint64_t, blkid, dnode_t *, dn);
+ * Then you can use it as follows:
+ * zfs$target:::probe2 /copyinstr(arg0) == "zfs__probe_name"/
+ *     {printf("%u %p\n", arg1, arg2);}
  */
 
 #ifdef DTRACE_PROBE
@@ -212,7 +226,7 @@ extern int aok;
  */
 #define        TS_MAGIC                0x72f158ab4261e538ull
 #define        TS_RUN                  0x00000002
-#define        TS_STACK_MIN            PTHREAD_STACK_MIN
+#define        TS_STACK_MIN            MAX(PTHREAD_STACK_MIN, 32768)
 #define        TS_STACK_MAX            (256 * 1024)
 
 /* in libzpool, p0 exists only to have its address taken */
@@ -274,6 +288,7 @@ typedef struct kmutex {
 } kmutex_t;
 
 #define        MUTEX_DEFAULT   0
+#define        MUTEX_NOLOCKDEP MUTEX_DEFAULT
 #define        MUTEX_HELD(m)   ((m)->m_owner == curthread)
 #define        MUTEX_NOT_HELD(m) (!MUTEX_HELD(m))
 
@@ -305,6 +320,7 @@ typedef int krw_t;
 #define        RW_READER       0
 #define        RW_WRITER       1
 #define        RW_DEFAULT      RW_READER
+#define        RW_NOLOCKDEP    RW_READER
 
 #define        RW_READ_HELD(x)         ((x)->rw_readers > 0)
 #define        RW_WRITE_HELD(x)        ((x)->rw_wr_owner == curthread)
@@ -341,6 +357,7 @@ typedef struct kcondvar {
 } kcondvar_t;
 
 #define        CV_DEFAULT      0
+#define        CALLOUT_FLAG_ABSOLUTE   0x2
 
 extern void cv_init(kcondvar_t *cv, char *name, int type, void *arg);
 extern void cv_destroy(kcondvar_t *cv);
@@ -353,6 +370,8 @@ extern void cv_broadcast(kcondvar_t *cv);
 #define        cv_timedwait_sig(cv, mp, at)            cv_timedwait(cv, mp, at)
 #define        cv_wait_sig(cv, mp)                     cv_wait(cv, mp)
 #define        cv_wait_io(cv, mp)                      cv_wait(cv, mp)
+#define        cv_timedwait_sig_hires(cv, mp, t, r, f) \
+       cv_timedwait_hires(cv, mp, t, r, f)
 
 /*
  * Thread-specific data
@@ -430,7 +449,9 @@ typedef enum kmem_cbrc {
 /*
  * Task queues
  */
-typedef struct taskq taskq_t;
+
+#define        TASKQ_NAMELEN   31
+
 typedef uintptr_t taskqid_t;
 typedef void (task_func_t)(void *);
 
@@ -442,6 +463,25 @@ typedef struct taskq_ent {
        uintptr_t               tqent_flags;
 } taskq_ent_t;
 
+typedef struct taskq {
+       char            tq_name[TASKQ_NAMELEN + 1];
+       kmutex_t        tq_lock;
+       krwlock_t       tq_threadlock;
+       kcondvar_t      tq_dispatch_cv;
+       kcondvar_t      tq_wait_cv;
+       kthread_t       **tq_threadlist;
+       int             tq_flags;
+       int             tq_active;
+       int             tq_nthreads;
+       int             tq_nalloc;
+       int             tq_minalloc;
+       int             tq_maxalloc;
+       kcondvar_t      tq_maxalloc_cv;
+       int             tq_maxalloc_wait;
+       taskq_ent_t     *tq_freelist;
+       taskq_ent_t     tq_task;
+} taskq_t;
+
 #define        TQENT_FLAG_PREALLOC     0x1     /* taskq_dispatch_ent used */
 
 #define        TASKQ_PREPOPULATE       0x0001
@@ -488,8 +528,10 @@ typedef struct vnode {
        uint64_t        v_size;
        int             v_fd;
        char            *v_path;
+       int             v_dump_fd;
 } vnode_t;
 
+extern char *vn_dumpdir;
 #define        AV_SCANSTAMP_SZ 32              /* length of anti-virus scanstamp */
 
 typedef struct xoptattr {
@@ -623,7 +665,7 @@ extern void delay(clock_t ticks);
 #define        maxclsyspri     -20
 #define        defclsyspri     0
 
-#define        CPU_SEQID       (pthread_self() & (max_ncpus - 1))
+#define        CPU_SEQID       ((uintptr_t)pthread_self() & (max_ncpus - 1))
 
 #define        kcred           NULL
 #define        CRED()          NULL
@@ -633,11 +675,18 @@ extern void delay(clock_t ticks);
 extern uint64_t physmem;
 
 extern int highbit64(uint64_t i);
+extern int lowbit64(uint64_t i);
+extern int highbit(ulong_t i);
+extern int lowbit(ulong_t i);
 extern int random_get_bytes(uint8_t *ptr, size_t len);
 extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
 
 extern void kernel_init(int);
 extern void kernel_fini(void);
+extern void thread_init(void);
+extern void thread_fini(void);
+extern void random_init(void);
+extern void random_fini(void);
 
 struct spa;
 extern void nicenum(uint64_t num, char *buf);
@@ -718,6 +767,7 @@ extern int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr);
 extern int zfs_secpolicy_rename_perms(const char *from, const char *to,
     cred_t *cr);
 extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
+extern int secpolicy_zfs(const cred_t *cr);
 extern zoneid_t getzoneid(void);
 
 /* SID stuff */
index 65c44f3cca549017bd8d7ba591915810189189a8..26f0122ff7eb6b08d6d27400d714a7fa2b5eaa9f 100644 (file)
@@ -74,7 +74,6 @@ extern int zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr,
     int flags);
 extern int zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
     struct inode **ipp, cred_t *cr, int flags);
-extern void zfsctl_snapdir_inactive(struct inode *ip);
 extern int zfsctl_snapshot_mount(struct path *path, int flags);
 extern int zfsctl_snapshot_unmount(char *snapname, int flags);
 extern int zfsctl_snapshot_unmount_delay(spa_t *spa, uint64_t objsetid,
index 09a96c043bf0e234f7973fc051f535d215135616..3ec812ac0f514fb9b0218cb7ea26285465601f81 100644 (file)
@@ -20,7 +20,8 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright 2016 RackTop Systems.
  */
 
 #ifndef        _SYS_ZFS_IOCTL_H
@@ -90,26 +91,34 @@ typedef enum drr_headertype {
  * Feature flags for zfs send streams (flags in drr_versioninfo)
  */
 
-#define        DMU_BACKUP_FEATURE_DEDUP                (1<<0)
-#define        DMU_BACKUP_FEATURE_DEDUPPROPS           (1<<1)
-#define        DMU_BACKUP_FEATURE_SA_SPILL             (1<<2)
+#define        DMU_BACKUP_FEATURE_DEDUP                (1 << 0)
+#define        DMU_BACKUP_FEATURE_DEDUPPROPS           (1 << 1)
+#define        DMU_BACKUP_FEATURE_SA_SPILL             (1 << 2)
 /* flags #3 - #15 are reserved for incompatible closed-source implementations */
-#define        DMU_BACKUP_FEATURE_EMBED_DATA           (1<<16)
-#define        DMU_BACKUP_FEATURE_EMBED_DATA_LZ4       (1<<17)
+#define        DMU_BACKUP_FEATURE_EMBED_DATA           (1 << 16)
+#define        DMU_BACKUP_FEATURE_LZ4                  (1 << 17)
 /* flag #18 is reserved for a Delphix feature */
-#define        DMU_BACKUP_FEATURE_LARGE_BLOCKS         (1<<19)
+#define        DMU_BACKUP_FEATURE_LARGE_BLOCKS         (1 << 19)
+#define        DMU_BACKUP_FEATURE_RESUMING             (1 << 20)
+#define        DMU_BACKUP_FEATURE_LARGE_DNODE          (1 << 21)
+#define        DMU_BACKUP_FEATURE_COMPRESSED           (1 << 22)
 
 /*
  * Mask of all supported backup features
  */
 #define        DMU_BACKUP_FEATURE_MASK (DMU_BACKUP_FEATURE_DEDUP | \
     DMU_BACKUP_FEATURE_DEDUPPROPS | DMU_BACKUP_FEATURE_SA_SPILL | \
-    DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_EMBED_DATA_LZ4 | \
-    DMU_BACKUP_FEATURE_LARGE_BLOCKS)
+    DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_LZ4 | \
+    DMU_BACKUP_FEATURE_RESUMING | DMU_BACKUP_FEATURE_LARGE_BLOCKS | \
+    DMU_BACKUP_FEATURE_COMPRESSED | DMU_BACKUP_FEATURE_LARGE_DNODE)
 
 /* Are all features in the given flag word currently supported? */
 #define        DMU_STREAM_SUPPORTED(x) (!((x) & ~DMU_BACKUP_FEATURE_MASK))
 
+typedef enum dmu_send_resume_token_version {
+       ZFS_SEND_RESUME_TOKEN_VERSION = 1
+} dmu_send_resume_token_version_t;
+
 /*
  * The drr_versioninfo field of the dmu_replay_record has the
  * following layout:
@@ -129,8 +138,22 @@ typedef enum drr_headertype {
 
 #define        DMU_BACKUP_MAGIC 0x2F5bacbacULL
 
+/*
+ * Send stream flags.  Bits 24-31 are reserved for vendor-specific
+ * implementations and should not be used.
+ */
 #define        DRR_FLAG_CLONE          (1<<0)
 #define        DRR_FLAG_CI_DATA        (1<<1)
+/*
+ * This send stream, if it is a full send, includes the FREE and FREEOBJECT
+ * records that are created by the sending process.  This means that the send
+ * stream can be received as a clone, even though it is not an incremental.
+ * This is not implemented as a feature flag, because the receiving side does
+ * not need to have implemented it to receive this stream; it is fully backwards
+ * compatible.  We need a flag, though, because full send streams without it
+ * cannot necessarily be received as a clone correctly.
+ */
+#define        DRR_FLAG_FREERECORDS    (1<<2)
 
 /*
  * flags in the drr_checksumflags field in the DRR_WRITE and
@@ -140,6 +163,12 @@ typedef enum drr_headertype {
 
 #define        DRR_IS_DEDUP_CAPABLE(flags)     ((flags) & DRR_CHECKSUM_DEDUP)
 
+/* deal with compressed drr_write replay records */
+#define        DRR_WRITE_COMPRESSED(drrw)      ((drrw)->drr_compressiontype != 0)
+#define        DRR_WRITE_PAYLOAD_SIZE(drrw) \
+       (DRR_WRITE_COMPRESSED(drrw) ? (drrw)->drr_compressed_size : \
+       (drrw)->drr_logical_size)
+
 /*
  * zfs ioctl command structure
  */
@@ -173,7 +202,8 @@ typedef struct dmu_replay_record {
                        uint32_t drr_bonuslen;
                        uint8_t drr_checksumtype;
                        uint8_t drr_compress;
-                       uint8_t drr_pad[6];
+                       uint8_t drr_dn_slots;
+                       uint8_t drr_pad[5];
                        uint64_t drr_toguid;
                        /* bonus content follows */
                } drr_object;
@@ -187,12 +217,16 @@ typedef struct dmu_replay_record {
                        dmu_object_type_t drr_type;
                        uint32_t drr_pad;
                        uint64_t drr_offset;
-                       uint64_t drr_length;
+                       uint64_t drr_logical_size;
                        uint64_t drr_toguid;
                        uint8_t drr_checksumtype;
                        uint8_t drr_checksumflags;
-                       uint8_t drr_pad2[6];
-                       ddt_key_t drr_key; /* deduplication key */
+                       uint8_t drr_compressiontype;
+                       uint8_t drr_pad2[5];
+                       /* deduplication key */
+                       ddt_key_t drr_key;
+                       /* only nonzero if drr_compressiontype is not 0 */
+                       uint64_t drr_compressed_size;
                        /* content follows */
                } drr_write;
                struct drr_free {
@@ -237,6 +271,22 @@ typedef struct dmu_replay_record {
                        uint32_t drr_psize; /* compr. (real) size of payload */
                        /* (possibly compressed) content follows */
                } drr_write_embedded;
+
+               /*
+                * Nore: drr_checksum is overlaid with all record types
+                * except DRR_BEGIN.  Therefore its (non-pad) members
+                * must not overlap with members from the other structs.
+                * We accomplish this by putting its members at the very
+                * end of the struct.
+                */
+               struct drr_checksum {
+                       uint64_t drr_pad[34];
+                       /*
+                        * fletcher-4 checksum of everything preceding the
+                        * checksum.
+                        */
+                       zio_cksum_t drr_checksum;
+               } drr_checksum;
        } drr_u;
 } dmu_replay_record_t;
 
@@ -271,6 +321,7 @@ typedef struct zinject_record {
        uint32_t        zi_iotype;
        int32_t         zi_duration;
        uint64_t        zi_timer;
+       uint64_t        zi_nlanes;
        uint32_t        zi_cmd;
        uint32_t        zi_pad;
 } zinject_record_t;
@@ -315,6 +366,12 @@ typedef enum zfs_case {
        ZFS_CASE_MIXED
 } zfs_case_t;
 
+/*
+ * Note: this struct must have the same layout in 32-bit and 64-bit, so
+ * that 32-bit processes (like /sbin/zfs) can pass it to the 64-bit
+ * kernel.  Therefore, we add padding to it so that no "hidden" padding
+ * is automatically added on 64-bit (but not on 32-bit).
+ */
 typedef struct zfs_cmd {
        char            zc_name[MAXPATHLEN];    /* name of pool or dataset */
        uint64_t        zc_nvlist_src;          /* really (char *) */
diff --git a/zfs/include/sys/zfs_ratelimit.h b/zfs/include/sys/zfs_ratelimit.h
new file mode 100644 (file)
index 0000000..b9f9f73
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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.
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2016, Lawrence Livermore National Security, LLC.
+ */
+
+#ifndef _SYS_ZFS_RATELIMIT_H
+#define        _SYS_ZFS_RATELIMIT_H
+
+#include <sys/zfs_context.h>
+
+typedef struct {
+       hrtime_t start;
+       unsigned int count;
+       unsigned int burst;             /* Number to allow per interval */
+       unsigned int interval;          /* Interval length in seconds */
+       kmutex_t lock;
+} zfs_ratelimit_t;
+
+int zfs_ratelimit(zfs_ratelimit_t *rl);
+void zfs_ratelimit_init(zfs_ratelimit_t *rl, unsigned int burst,
+    unsigned int interval);
+
+#endif /* _SYS_ZFS_RATELIMIT_H */
index 5322f3bc73af3350a46a824d0561c5fcd26ceb47..5373f0d57320c0617f6066c218291db5bd71b8e9 100644 (file)
 extern "C" {
 #endif
 
-#ifdef _KERNEL
-
 #include <sys/list.h>
 #include <sys/avl.h>
+
+#ifdef _KERNEL
 #include <sys/condvar.h>
+#else
+#include <sys/zfs_context.h>
+#endif
 
 typedef enum {
        RL_READER,
@@ -106,7 +109,6 @@ zfs_rlock_destroy(zfs_rlock_t *zrl)
        avl_destroy(&zrl->zr_avl);
        mutex_destroy(&zrl->zr_mutex);
 }
-#endif /* _KERNEL */
 
 #ifdef __cplusplus
 }
index efaefdaccbc11bdf420da417deac59db1bcd3ee3..b59ace5b1996b151ee06ea0e4ad7b0384d8e1ee9 100644 (file)
@@ -110,6 +110,8 @@ typedef struct zfs_sb {
        kmutex_t        z_lock;
        uint64_t        z_userquota_obj;
        uint64_t        z_groupquota_obj;
+       uint64_t        z_userobjquota_obj;
+       uint64_t        z_groupobjquota_obj;
        uint64_t        z_replay_eof;   /* New end of file - replay only */
        sa_attr_type_t  *z_attr_table;  /* SA attr mapping->id */
        uint64_t        z_hold_size;    /* znode hold array size */
@@ -190,6 +192,8 @@ extern boolean_t zfs_owner_overquota(zfs_sb_t *zsb, struct znode *,
     boolean_t isgroup);
 extern boolean_t zfs_fuid_overquota(zfs_sb_t *zsb, boolean_t isgroup,
     uint64_t fuid);
+extern boolean_t zfs_fuid_overobjquota(zfs_sb_t *zsb, boolean_t isgroup,
+    uint64_t fuid);
 extern int zfs_set_version(zfs_sb_t *zsb, uint64_t newvers);
 extern int zfs_get_zplprop(objset_t *os, zfs_prop_t prop,
     uint64_t *value);
index c331035c544a71475912be9d4beb36a75356b922..157e7f9d5ec68395b4dfb032a3393847bf530782 100644 (file)
@@ -47,7 +47,7 @@ extern int zfs_lookup(struct inode *dip, char *nm, struct inode **ipp,
     int flags, cred_t *cr, int *direntflags, pathname_t *realpnp);
 extern int zfs_create(struct inode *dip, char *name, vattr_t *vap, int excl,
     int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp);
-extern int zfs_remove(struct inode *dip, char *name, cred_t *cr);
+extern int zfs_remove(struct inode *dip, char *name, cred_t *cr, int flags);
 extern int zfs_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
     struct inode **ipp, cred_t *cr, int flags, vsecattr_t *vsecp);
 extern int zfs_rmdir(struct inode *dip, char *name, struct inode *cwd,
@@ -64,7 +64,7 @@ extern int zfs_symlink(struct inode *dip, char *name, vattr_t *vap,
 extern int zfs_follow_link(struct dentry *dentry, struct nameidata *nd);
 extern int zfs_readlink(struct inode *ip, uio_t *uio, cred_t *cr);
 extern int zfs_link(struct inode *tdip, struct inode *sip,
-    char *name, cred_t *cr);
+    char *name, cred_t *cr, int flags);
 extern void zfs_inactive(struct inode *ip);
 extern int zfs_space(struct inode *ip, int cmd, flock64_t *bfp, int flag,
     offset_t offset, cred_t *cr);
index 32ffe07d28563558282e6da0e4c00d2c25ee4164..a12675d6f5839dee793c767fa5039c328451c98d 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #ifndef        _SYS_FS_ZFS_ZNODE_H
@@ -138,17 +138,6 @@ extern "C" {
 #define        ZFS_SHARES_DIR          "SHARES"
 #define        ZFS_SA_ATTRS            "SA_ATTRS"
 
-/*
- * Path component length
- *
- * The generic fs code uses MAXNAMELEN to represent
- * what the largest component length is.  Unfortunately,
- * this length includes the terminating NULL.  ZFS needs
- * to tell the users via pathconf() and statvfs() what the
- * true maximum length of a component is, excluding the NULL.
- */
-#define        ZFS_MAXNAMELEN  (MAXNAMELEN - 1)
-
 /*
  * Convert mode bits (zp_mode) to BSD-style DT_* values for storing in
  * the directory entries.  On Linux systems this value is already
@@ -196,13 +185,9 @@ typedef struct znode {
        uint_t          z_blksz;        /* block size in bytes */
        uint_t          z_seq;          /* modification sequence number */
        uint64_t        z_mapcnt;       /* number of pages mapped to file */
-       uint64_t        z_gen;          /* generation (cached) */
+       uint64_t        z_dnodesize;    /* dnode size */
        uint64_t        z_size;         /* file size (cached) */
-       uint64_t        z_atime[2];     /* atime (cached) */
-       uint64_t        z_links;        /* file links (cached) */
        uint64_t        z_pflags;       /* pflags (cached) */
-       uint64_t        z_uid;          /* uid fuid (cached) */
-       uint64_t        z_gid;          /* gid fuid (cached) */
        uint32_t        z_sync_cnt;     /* synchronous open count */
        mode_t          z_mode;         /* mode (cached) */
        kmutex_t        z_acl_lock;     /* acl data lock */
@@ -304,16 +289,12 @@ extern unsigned int zfs_object_mutex_size;
 #define        STATE_CHANGED           (ATTR_CTIME)
 #define        CONTENT_MODIFIED        (ATTR_MTIME | ATTR_CTIME)
 
-#define        ZFS_ACCESSTIME_STAMP(zsb, zp) \
-       if ((zsb)->z_atime && !(zfs_is_readonly(zsb))) \
-               zfs_tstamp_update_setup(zp, ACCESSED, NULL, NULL, B_FALSE);
-
 extern int     zfs_init_fs(zfs_sb_t *, znode_t **);
 extern void    zfs_set_dataprop(objset_t *);
 extern void    zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *,
     dmu_tx_t *tx);
 extern void    zfs_tstamp_update_setup(znode_t *, uint_t, uint64_t [2],
-    uint64_t [2], boolean_t);
+    uint64_t [2]);
 extern void    zfs_grow_blocksize(znode_t *, uint64_t, dmu_tx_t *);
 extern int     zfs_freesp(znode_t *, uint64_t, uint64_t, int, boolean_t);
 extern void    zfs_znode_init(void);
index 65b14f1cd6a23cc72ecab7b6cbcbcad07a4e7546..ed0810aa1a9efdaa232735acdba86bf7f68e1491 100644 (file)
@@ -172,6 +172,19 @@ typedef enum zil_create {
        (txtype) == TX_ACL ||           \
        (txtype) == TX_WRITE2)
 
+/*
+ * The number of dnode slots consumed by the object is stored in the 8
+ * unused upper bits of the object ID. We subtract 1 from the value
+ * stored on disk for compatibility with implementations that don't
+ * support large dnodes. The slot count for a single-slot dnode will
+ * contain 0 for those bits to preserve the log record format for
+ * "small" dnodes.
+ */
+#define        LR_FOID_GET_SLOTS(oid) (BF64_GET((oid), 56, 8) + 1)
+#define        LR_FOID_SET_SLOTS(oid, x) BF64_SET((oid), 56, 8, (x) - 1)
+#define        LR_FOID_GET_OBJ(oid) BF64_GET((oid), 0, DN_MAX_OBJECT_SHIFT)
+#define        LR_FOID_SET_OBJ(oid, x) BF64_SET((oid), 0, DN_MAX_OBJECT_SHIFT, (x))
+
 /*
  * Format of log records.
  * The fields are carefully defined to allow them to be aligned
@@ -348,7 +361,7 @@ typedef struct {
  *     - the write occupies only one block
  * WR_COPIED:
  *    If we know we'll immediately be committing the
- *    transaction (FSYNC or FDSYNC), the we allocate a larger
+ *    transaction (FSYNC or FDSYNC), then we allocate a larger
  *    log record here for the data and copy the data in.
  * WR_NEED_COPY:
  *    Otherwise we don't allocate a buffer, and *if* we need to
index 4916d87249eaa668fca4024953dc569362dc7314..864e8b2bec8d4f8b60bae86411b1262636781807 100644 (file)
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
 #ifndef _ZIO_H
 #define        _ZIO_H
 
+#include <sys/zio_priority.h>
 #include <sys/zfs_context.h>
 #include <sys/spa.h>
 #include <sys/txg.h>
@@ -79,6 +80,10 @@ enum zio_checksum {
        ZIO_CHECKSUM_FLETCHER_4,
        ZIO_CHECKSUM_SHA256,
        ZIO_CHECKSUM_ZILOG2,
+       ZIO_CHECKSUM_NOPARITY,
+       ZIO_CHECKSUM_SHA512,
+       ZIO_CHECKSUM_SKEIN,
+       ZIO_CHECKSUM_EDONR,
        ZIO_CHECKSUM_FUNCTIONS
 };
 
@@ -97,26 +102,6 @@ enum zio_checksum {
 #define        ZIO_DEDUPCHECKSUM       ZIO_CHECKSUM_SHA256
 #define        ZIO_DEDUPDITTO_MIN      100
 
-enum zio_compress {
-       ZIO_COMPRESS_INHERIT = 0,
-       ZIO_COMPRESS_ON,
-       ZIO_COMPRESS_OFF,
-       ZIO_COMPRESS_LZJB,
-       ZIO_COMPRESS_EMPTY,
-       ZIO_COMPRESS_GZIP_1,
-       ZIO_COMPRESS_GZIP_2,
-       ZIO_COMPRESS_GZIP_3,
-       ZIO_COMPRESS_GZIP_4,
-       ZIO_COMPRESS_GZIP_5,
-       ZIO_COMPRESS_GZIP_6,
-       ZIO_COMPRESS_GZIP_7,
-       ZIO_COMPRESS_GZIP_8,
-       ZIO_COMPRESS_GZIP_9,
-       ZIO_COMPRESS_ZLE,
-       ZIO_COMPRESS_LZ4,
-       ZIO_COMPRESS_FUNCTIONS
-};
-
 /*
  * The number of "legacy" compression functions which can be set on individual
  * objects.
@@ -147,17 +132,6 @@ enum zio_compress {
 #define        ZIO_FAILURE_MODE_CONTINUE       1
 #define        ZIO_FAILURE_MODE_PANIC          2
 
-typedef enum zio_priority {
-       ZIO_PRIORITY_SYNC_READ,
-       ZIO_PRIORITY_SYNC_WRITE,        /* ZIL */
-       ZIO_PRIORITY_ASYNC_READ,        /* prefetch */
-       ZIO_PRIORITY_ASYNC_WRITE,       /* spa_sync() */
-       ZIO_PRIORITY_SCRUB,             /* asynchronous scrub/resilver reads */
-       ZIO_PRIORITY_NUM_QUEUEABLE,
-
-       ZIO_PRIORITY_NOW                /* non-queued i/os (e.g. free) */
-} zio_priority_t;
-
 enum zio_flag {
        /*
         * Flags inherited by gang, ddt, and vdev children,
@@ -183,6 +157,7 @@ enum zio_flag {
        ZIO_FLAG_DONT_CACHE     = 1 << 11,
        ZIO_FLAG_NODATA         = 1 << 12,
        ZIO_FLAG_INDUCE_DAMAGE  = 1 << 13,
+       ZIO_FLAG_IO_ALLOCATING  = 1 << 14,
 
 #define        ZIO_FLAG_DDT_INHERIT    (ZIO_FLAG_IO_RETRY - 1)
 #define        ZIO_FLAG_GANG_INHERIT   (ZIO_FLAG_IO_RETRY - 1)
@@ -190,28 +165,28 @@ enum zio_flag {
        /*
         * Flags inherited by vdev children.
         */
-       ZIO_FLAG_IO_RETRY       = 1 << 14,      /* must be first for INHERIT */
-       ZIO_FLAG_PROBE          = 1 << 15,
-       ZIO_FLAG_TRYHARD        = 1 << 16,
-       ZIO_FLAG_OPTIONAL       = 1 << 17,
+       ZIO_FLAG_IO_RETRY       = 1 << 15,      /* must be first for INHERIT */
+       ZIO_FLAG_PROBE          = 1 << 16,
+       ZIO_FLAG_TRYHARD        = 1 << 17,
+       ZIO_FLAG_OPTIONAL       = 1 << 18,
 
 #define        ZIO_FLAG_VDEV_INHERIT   (ZIO_FLAG_DONT_QUEUE - 1)
 
        /*
         * Flags not inherited by any children.
         */
-       ZIO_FLAG_DONT_QUEUE     = 1 << 18,      /* must be first for INHERIT */
-       ZIO_FLAG_DONT_PROPAGATE = 1 << 19,
-       ZIO_FLAG_IO_BYPASS      = 1 << 20,
-       ZIO_FLAG_IO_REWRITE     = 1 << 21,
-       ZIO_FLAG_RAW            = 1 << 22,
-       ZIO_FLAG_GANG_CHILD     = 1 << 23,
-       ZIO_FLAG_DDT_CHILD      = 1 << 24,
-       ZIO_FLAG_GODFATHER      = 1 << 25,
-       ZIO_FLAG_NOPWRITE       = 1 << 26,
-       ZIO_FLAG_REEXECUTED     = 1 << 27,
-       ZIO_FLAG_DELEGATED      = 1 << 28,
-       ZIO_FLAG_FASTWRITE      = 1 << 29,
+       ZIO_FLAG_DONT_QUEUE     = 1 << 19,      /* must be first for INHERIT */
+       ZIO_FLAG_DONT_PROPAGATE = 1 << 20,
+       ZIO_FLAG_IO_BYPASS      = 1 << 21,
+       ZIO_FLAG_IO_REWRITE     = 1 << 22,
+       ZIO_FLAG_RAW            = 1 << 23,
+       ZIO_FLAG_GANG_CHILD     = 1 << 24,
+       ZIO_FLAG_DDT_CHILD      = 1 << 25,
+       ZIO_FLAG_GODFATHER      = 1 << 26,
+       ZIO_FLAG_NOPWRITE       = 1 << 27,
+       ZIO_FLAG_REEXECUTED     = 1 << 28,
+       ZIO_FLAG_DELEGATED      = 1 << 29,
+       ZIO_FLAG_FASTWRITE      = 1 << 30
 };
 
 #define        ZIO_FLAG_MUSTSUCCEED            0
@@ -251,6 +226,7 @@ enum zio_wait_type {
 
 typedef void zio_done_func_t(zio_t *zio);
 
+extern int zio_dva_throttle_enabled;
 extern const char *zio_type_name[ZIO_TYPES];
 
 /*
@@ -262,6 +238,7 @@ extern const char *zio_type_name[ZIO_TYPES];
  * Root blocks (objset_phys_t) are object 0, level -1:  <objset, 0, -1, 0>.
  * ZIL blocks are bookmarked <objset, 0, -2, blkid == ZIL sequence number>.
  * dmu_sync()ed ZIL data blocks are bookmarked <objset, object, -2, blkid>.
+ * dnode visit bookmarks are <objset, object id of dnode, -3, 0>.
  *
  * Note: this structure is called a bookmark because its original purpose
  * was to remember where to resume a pool-wide traverse.
@@ -294,6 +271,9 @@ struct zbookmark_phys {
 #define        ZB_ZIL_OBJECT           (0ULL)
 #define        ZB_ZIL_LEVEL            (-2LL)
 
+#define        ZB_DNODE_LEVEL          (-3LL)
+#define        ZB_DNODE_BLKID          (0ULL)
+
 #define        ZB_IS_ZERO(zb)                                          \
        ((zb)->zb_objset == 0 && (zb)->zb_object == 0 &&        \
        (zb)->zb_level == 0 && (zb)->zb_blkid == 0)
@@ -401,17 +381,19 @@ struct zio {
        blkptr_t        io_bp_copy;
        list_t          io_parent_list;
        list_t          io_child_list;
-       zio_link_t      *io_walk_link;
        zio_t           *io_logical;
        zio_transform_t *io_transform_stack;
 
        /* Callback info */
-       zio_done_func_t *io_ready;
+       zio_done_func_t *io_ready;
+       zio_done_func_t *io_children_ready;
        zio_done_func_t *io_physdone;
        zio_done_func_t *io_done;
        void            *io_private;
        int64_t         io_prev_space_delta;    /* DMU private */
        blkptr_t        io_bp_orig;
+       /* io_lsize != io_orig_size iff this is a raw write */
+       uint64_t        io_lsize;
 
        /* Data represented by this I/O */
        void            *io_data;
@@ -426,10 +408,14 @@ struct zio {
 
        uint64_t        io_offset;
        hrtime_t        io_timestamp;   /* submitted at */
+       hrtime_t        io_queued_timestamp;
+       hrtime_t        io_target_timestamp;
        hrtime_t        io_delta;       /* vdev queue service delta */
-       uint64_t        io_delay;       /* vdev disk service delta (ticks) */
+       hrtime_t        io_delay;       /* Device access time (disk or */
+                                       /* file). */
        avl_node_t      io_queue_node;
        avl_node_t      io_offset_node;
+       avl_node_t      io_alloc_node;
 
        /* Internal pipeline state */
        enum zio_flag   io_flags;
@@ -438,6 +424,7 @@ struct zio {
        enum zio_flag   io_orig_flags;
        enum zio_stage  io_orig_stage;
        enum zio_stage  io_orig_pipeline;
+       enum zio_stage  io_pipeline_trace;
        int             io_error;
        int             io_child_error[ZIO_CHILD_TYPES];
        uint64_t        io_children[ZIO_CHILD_TYPES][ZIO_WAIT_TYPES];
@@ -460,6 +447,8 @@ struct zio {
        taskq_ent_t     io_tqent;
 };
 
+extern int zio_timestamp_compare(const void *, const void *);
+
 extern zio_t *zio_null(zio_t *pio, spa_t *spa, vdev_t *vd,
     zio_done_func_t *done, void *private, enum zio_flag flags);
 
@@ -467,14 +456,15 @@ extern zio_t *zio_root(spa_t *spa,
     zio_done_func_t *done, void *private, enum zio_flag flags);
 
 extern zio_t *zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, void *data,
-    uint64_t size, zio_done_func_t *done, void *private,
+    uint64_t lsize, zio_done_func_t *done, void *private,
     zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb);
 
 extern zio_t *zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
-    void *data, uint64_t size, const zio_prop_t *zp,
-    zio_done_func_t *ready, zio_done_func_t *physdone, zio_done_func_t *done,
-    void *private,
-    zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb);
+    void *data, uint64_t size, uint64_t psize, const zio_prop_t *zp,
+    zio_done_func_t *ready, zio_done_func_t *children_ready,
+    zio_done_func_t *physdone, zio_done_func_t *done,
+    void *private, zio_priority_t priority, enum zio_flag flags,
+    const zbookmark_phys_t *zb);
 
 extern zio_t *zio_rewrite(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
     void *data, uint64_t size, zio_done_func_t *done, void *private,
@@ -515,9 +505,11 @@ extern int zio_wait(zio_t *zio);
 extern void zio_nowait(zio_t *zio);
 extern void zio_execute(zio_t *zio);
 extern void zio_interrupt(zio_t *zio);
+extern void zio_delay_init(zio_t *zio);
+extern void zio_delay_interrupt(zio_t *zio);
 
-extern zio_t *zio_walk_parents(zio_t *cio);
-extern zio_t *zio_walk_children(zio_t *pio);
+extern zio_t *zio_walk_parents(zio_t *cio, zio_link_t **);
+extern zio_t *zio_walk_children(zio_t *pio, zio_link_t **);
 extern zio_t *zio_unique_parent(zio_t *cio);
 extern void zio_add_child(zio_t *pio, zio_t *cio);
 
@@ -527,6 +519,10 @@ extern void *zio_data_buf_alloc(size_t size);
 extern void zio_data_buf_free(void *buf, size_t size);
 extern void *zio_buf_alloc_flags(size_t size, int flags);
 
+extern void zio_push_transform(zio_t *zio, void *data, uint64_t size,
+    uint64_t bufsize, zio_transform_func_t *transform);
+extern void zio_pop_transforms(zio_t *zio);
+
 extern void zio_resubmit_stage_async(void *);
 
 extern zio_t *zio_vdev_child_io(zio_t *zio, blkptr_t *bp, vdev_t *vd,
@@ -577,7 +573,7 @@ extern int zio_handle_fault_injection(zio_t *zio, int error);
 extern int zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error);
 extern int zio_handle_label_injection(zio_t *zio, int error);
 extern void zio_handle_ignored_writes(zio_t *zio);
-extern uint64_t zio_handle_io_delay(zio_t *zio);
+extern hrtime_t zio_handle_io_delay(zio_t *zio);
 
 /*
  * Checksum ereport functions
@@ -587,7 +583,6 @@ extern void zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd, struct zio *zio,
 extern void zfs_ereport_finish_checksum(zio_cksum_report_t *report,
     const void *good_data, const void *bad_data, boolean_t drop_if_identical);
 
-extern void zfs_ereport_send_interim_checksum(zio_cksum_report_t *report);
 extern void zfs_ereport_free_checksum(zio_cksum_report_t *report);
 
 /* If we have the good data in hand, this function can be used */
@@ -599,8 +594,10 @@ extern void zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd,
 extern void spa_handle_ignored_writes(spa_t *spa);
 
 /* zbookmark_phys functions */
-boolean_t zbookmark_is_before(const struct dnode_phys *dnp,
-    const zbookmark_phys_t *zb1, const zbookmark_phys_t *zb2);
+boolean_t zbookmark_subtree_completed(const struct dnode_phys *dnp,
+    const zbookmark_phys_t *subtree_root, const zbookmark_phys_t *last_block);
+int zbookmark_compare(uint16_t dbss1, uint8_t ibs1, uint16_t dbss2,
+    uint8_t ibs2, const zbookmark_phys_t *zb1, const zbookmark_phys_t *zb2);
 
 #ifdef __cplusplus
 }
index de89bc9a796726cffe2b51005f63d9f3a6810776..b4c2c8c08305bb15379433bda5afa713c0ac659e 100644 (file)
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015 by Delphix. All rights reserved.
+ * Copyright Saso Kiselkov 2013, All rights reserved.
  */
 
 #ifndef _SYS_ZIO_CHECKSUM_H
 #define        _SYS_ZIO_CHECKSUM_H
 
 #include <sys/zio.h>
+#include <zfeature_common.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -34,17 +37,36 @@ extern "C" {
 /*
  * Signature for checksum functions.
  */
-typedef void zio_checksum_t(const void *data, uint64_t size, zio_cksum_t *zcp);
+typedef void zio_checksum_func_t(const void *, uint64_t, const void *,
+    zio_cksum_t *);
+typedef void zio_checksum_t(const void *data, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp);
+typedef void *zio_checksum_tmpl_init_t(const zio_cksum_salt_t *salt);
+typedef void zio_checksum_tmpl_free_t(void *ctx_template);
+
+typedef enum zio_checksum_flags {
+       /* Strong enough for metadata? */
+       ZCHECKSUM_FLAG_METADATA = (1 << 1),
+       /* ZIO embedded checksum */
+       ZCHECKSUM_FLAG_EMBEDDED = (1 << 2),
+       /* Strong enough for dedup (without verification)? */
+       ZCHECKSUM_FLAG_DEDUP = (1 << 3),
+       /* Uses salt value */
+       ZCHECKSUM_FLAG_SALTED = (1 << 4),
+       /* Strong enough for nopwrite? */
+       ZCHECKSUM_FLAG_NOPWRITE = (1 << 5)
+} zio_checksum_flags_t;
 
 /*
  * Information about each checksum function.
  */
 typedef const struct zio_checksum_info {
-       zio_checksum_t  *ci_func[2]; /* checksum function for each byteorder */
-       int             ci_correctable; /* number of correctable bits   */
-       int             ci_eck;         /* uses zio embedded checksum? */
-       int             ci_dedup;       /* strong enough for dedup? */
-       char            *ci_name;       /* descriptive name */
+       /* checksum function for each byteorder */
+       zio_checksum_t                  *ci_func[2];
+       zio_checksum_tmpl_init_t        *ci_tmpl_init;
+       zio_checksum_tmpl_free_t        *ci_tmpl_free;
+       zio_checksum_flags_t            ci_flags;
+       char                            *ci_name;       /* descriptive name */
 } zio_checksum_info_t;
 
 typedef struct zio_bad_cksum {
@@ -62,11 +84,31 @@ extern zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS];
  * Checksum routines.
  */
 extern zio_checksum_t zio_checksum_SHA256;
+extern zio_checksum_t zio_checksum_SHA512_native;
+extern zio_checksum_t zio_checksum_SHA512_byteswap;
+
+/* Skein */
+extern zio_checksum_t zio_checksum_skein_native;
+extern zio_checksum_t zio_checksum_skein_byteswap;
+extern zio_checksum_tmpl_init_t zio_checksum_skein_tmpl_init;
+extern zio_checksum_tmpl_free_t zio_checksum_skein_tmpl_free;
+
+/* Edon-R */
+extern zio_checksum_t zio_checksum_edonr_native;
+extern zio_checksum_t zio_checksum_edonr_byteswap;
+extern zio_checksum_tmpl_init_t zio_checksum_edonr_tmpl_init;
+extern zio_checksum_tmpl_free_t zio_checksum_edonr_tmpl_free;
 
+extern int zio_checksum_equal(spa_t *, blkptr_t *, enum zio_checksum,
+    void *, uint64_t, uint64_t, zio_bad_cksum_t *);
 extern void zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
     void *data, uint64_t size);
+extern int zio_checksum_error_impl(spa_t *, blkptr_t *, enum zio_checksum,
+    void *, uint64_t, uint64_t, zio_bad_cksum_t *);
 extern int zio_checksum_error(zio_t *zio, zio_bad_cksum_t *out);
 extern enum zio_checksum spa_dedup_checksum(spa_t *spa);
+extern void zio_checksum_templates_free(spa_t *spa);
+extern spa_feature_t zio_checksum_to_feature(enum zio_checksum cksum);
 
 #ifdef __cplusplus
 }
index 63863c713c18bb9a608a74a9f0465b20aea52bdb..da58ef7aa5ececa89487b86dcbe6fbc453729081 100644 (file)
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2015 by Delphix. All rights reserved.
  */
 
 #ifndef _SYS_ZIO_COMPRESS_H
 #define        _SYS_ZIO_COMPRESS_H
 
-#include <sys/zio.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+enum zio_compress {
+       ZIO_COMPRESS_INHERIT = 0,
+       ZIO_COMPRESS_ON,
+       ZIO_COMPRESS_OFF,
+       ZIO_COMPRESS_LZJB,
+       ZIO_COMPRESS_EMPTY,
+       ZIO_COMPRESS_GZIP_1,
+       ZIO_COMPRESS_GZIP_2,
+       ZIO_COMPRESS_GZIP_3,
+       ZIO_COMPRESS_GZIP_4,
+       ZIO_COMPRESS_GZIP_5,
+       ZIO_COMPRESS_GZIP_6,
+       ZIO_COMPRESS_GZIP_7,
+       ZIO_COMPRESS_GZIP_8,
+       ZIO_COMPRESS_GZIP_9,
+       ZIO_COMPRESS_ZLE,
+       ZIO_COMPRESS_LZ4,
+       ZIO_COMPRESS_FUNCTIONS
+};
+
 /* Common signature for all zio compress functions. */
 typedef size_t zio_compress_func_t(void *src, void *dst,
     size_t s_len, size_t d_len, int);
index 08f820103e823681031100c8b2f65f8661e8293e..a36749a308d675fb77fae43923304a954d97c086 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #ifndef _ZIO_IMPL_H
@@ -108,35 +108,37 @@ enum zio_stage {
        ZIO_STAGE_OPEN                  = 1 << 0,       /* RWFCI */
 
        ZIO_STAGE_READ_BP_INIT          = 1 << 1,       /* R---- */
-       ZIO_STAGE_FREE_BP_INIT          = 1 << 2,       /* --F-- */
-       ZIO_STAGE_ISSUE_ASYNC           = 1 << 3,       /* RWF-- */
-       ZIO_STAGE_WRITE_BP_INIT         = 1 << 4,       /* -W--- */
+       ZIO_STAGE_WRITE_BP_INIT         = 1 << 2,       /* -W--- */
+       ZIO_STAGE_FREE_BP_INIT          = 1 << 3,       /* --F-- */
+       ZIO_STAGE_ISSUE_ASYNC           = 1 << 4,       /* RWF-- */
+       ZIO_STAGE_WRITE_COMPRESS        = 1 << 5,       /* -W--- */
 
-       ZIO_STAGE_CHECKSUM_GENERATE     = 1 << 5,       /* -W--- */
+       ZIO_STAGE_CHECKSUM_GENERATE     = 1 << 6,       /* -W--- */
 
-       ZIO_STAGE_NOP_WRITE             = 1 << 6,       /* -W--- */
+       ZIO_STAGE_NOP_WRITE             = 1 << 7,       /* -W--- */
 
-       ZIO_STAGE_DDT_READ_START        = 1 << 7,       /* R---- */
-       ZIO_STAGE_DDT_READ_DONE         = 1 << 8,       /* R---- */
-       ZIO_STAGE_DDT_WRITE             = 1 << 9,       /* -W--- */
-       ZIO_STAGE_DDT_FREE              = 1 << 10,      /* --F-- */
+       ZIO_STAGE_DDT_READ_START        = 1 << 8,       /* R---- */
+       ZIO_STAGE_DDT_READ_DONE         = 1 << 9,       /* R---- */
+       ZIO_STAGE_DDT_WRITE             = 1 << 10,      /* -W--- */
+       ZIO_STAGE_DDT_FREE              = 1 << 11,      /* --F-- */
 
-       ZIO_STAGE_GANG_ASSEMBLE         = 1 << 11,      /* RWFC- */
-       ZIO_STAGE_GANG_ISSUE            = 1 << 12,      /* RWFC- */
+       ZIO_STAGE_GANG_ASSEMBLE         = 1 << 12,      /* RWFC- */
+       ZIO_STAGE_GANG_ISSUE            = 1 << 13,      /* RWFC- */
 
-       ZIO_STAGE_DVA_ALLOCATE          = 1 << 13,      /* -W--- */
-       ZIO_STAGE_DVA_FREE              = 1 << 14,      /* --F-- */
-       ZIO_STAGE_DVA_CLAIM             = 1 << 15,      /* ---C- */
+       ZIO_STAGE_DVA_THROTTLE          = 1 << 14,      /* -W--- */
+       ZIO_STAGE_DVA_ALLOCATE          = 1 << 15,      /* -W--- */
+       ZIO_STAGE_DVA_FREE              = 1 << 16,      /* --F-- */
+       ZIO_STAGE_DVA_CLAIM             = 1 << 17,      /* ---C- */
 
-       ZIO_STAGE_READY                 = 1 << 16,      /* RWFCI */
+       ZIO_STAGE_READY                 = 1 << 18,      /* RWFCI */
 
-       ZIO_STAGE_VDEV_IO_START         = 1 << 17,      /* RW--I */
-       ZIO_STAGE_VDEV_IO_DONE          = 1 << 18,      /* RW--I */
-       ZIO_STAGE_VDEV_IO_ASSESS        = 1 << 19,      /* RW--I */
+       ZIO_STAGE_VDEV_IO_START         = 1 << 19,      /* RW--I */
+       ZIO_STAGE_VDEV_IO_DONE          = 1 << 20,      /* RW--I */
+       ZIO_STAGE_VDEV_IO_ASSESS        = 1 << 21,      /* RW--I */
 
-       ZIO_STAGE_CHECKSUM_VERIFY       = 1 << 20,      /* R---- */
+       ZIO_STAGE_CHECKSUM_VERIFY       = 1 << 22,      /* R---- */
 
-       ZIO_STAGE_DONE                  = 1 << 21       /* RWFCI */
+       ZIO_STAGE_DONE                  = 1 << 23       /* RWFCI */
 };
 
 #define        ZIO_INTERLOCK_STAGES                    \
@@ -187,22 +189,27 @@ enum zio_stage {
 
 #define        ZIO_REWRITE_PIPELINE                    \
        (ZIO_WRITE_COMMON_STAGES |              \
+       ZIO_STAGE_WRITE_COMPRESS |              \
        ZIO_STAGE_WRITE_BP_INIT)
 
 #define        ZIO_WRITE_PIPELINE                      \
        (ZIO_WRITE_COMMON_STAGES |              \
        ZIO_STAGE_WRITE_BP_INIT |               \
+       ZIO_STAGE_WRITE_COMPRESS |              \
+       ZIO_STAGE_DVA_THROTTLE |                \
        ZIO_STAGE_DVA_ALLOCATE)
 
 #define        ZIO_DDT_CHILD_WRITE_PIPELINE            \
        (ZIO_INTERLOCK_STAGES |                 \
        ZIO_VDEV_IO_STAGES |                    \
+       ZIO_STAGE_DVA_THROTTLE |                \
        ZIO_STAGE_DVA_ALLOCATE)
 
 #define        ZIO_DDT_WRITE_PIPELINE                  \
        (ZIO_INTERLOCK_STAGES |                 \
-       ZIO_STAGE_ISSUE_ASYNC |                 \
        ZIO_STAGE_WRITE_BP_INIT |               \
+       ZIO_STAGE_ISSUE_ASYNC |                 \
+       ZIO_STAGE_WRITE_COMPRESS |              \
        ZIO_STAGE_CHECKSUM_GENERATE |           \
        ZIO_STAGE_DDT_WRITE)
 
diff --git a/zfs/include/sys/zio_priority.h b/zfs/include/sys/zio_priority.h
new file mode 100644 (file)
index 0000000..3fc3589
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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.
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+#ifndef        _ZIO_PRIORITY_H
+#define        _ZIO_PRIORITY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum zio_priority {
+       ZIO_PRIORITY_SYNC_READ,
+       ZIO_PRIORITY_SYNC_WRITE,        /* ZIL */
+       ZIO_PRIORITY_ASYNC_READ,        /* prefetch */
+       ZIO_PRIORITY_ASYNC_WRITE,       /* spa_sync() */
+       ZIO_PRIORITY_SCRUB,             /* asynchronous scrub/resilver reads */
+       ZIO_PRIORITY_NUM_QUEUEABLE,
+       ZIO_PRIORITY_NOW,               /* non-queued i/os (e.g. free) */
+} zio_priority_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIO_PRIORITY_H */
index c6085481bb32c62a953f023944b92d3f22a9d37b..386cf6d09af31c4ec6019b0c574e267911d22bde 100644 (file)
@@ -156,14 +156,14 @@ static inline bool
 dir_emit_dot(struct file *file, struct dir_context *ctx)
 {
        return (ctx->actor(ctx->dirent, ".", 1, ctx->pos,
-           file->f_path.dentry->d_inode->i_ino, DT_DIR) == 0);
+           file_inode(file)->i_ino, DT_DIR) == 0);
 }
 
 static inline bool
 dir_emit_dotdot(struct file *file, struct dir_context *ctx)
 {
        return (ctx->actor(ctx->dirent, "..", 2, ctx->pos,
-           parent_ino(file->f_path.dentry), DT_DIR) == 0);
+           parent_ino(file_dentry(file)), DT_DIR) == 0);
 }
 
 static inline bool
index c3e386f0b79e2e222c2944be53d895055737993b..00ed220d3b1776527833aef75aa65e6d30c06c17 100644 (file)
@@ -32,6 +32,8 @@
 #define        ZVOL_OBJ                1ULL
 #define        ZVOL_ZAP_OBJ            2ULL
 
+extern void *zvol_tag;
+
 extern void zvol_create_minors(spa_t *spa, const char *name, boolean_t async);
 extern void zvol_remove_minors(spa_t *spa, const char *name, boolean_t async);
 extern void zvol_rename_minors(spa_t *spa, const char *oldname,
index e383c4ff7887a7bb6b0d585e3fe47174d4379882..acf76381b7c075af9b6fb265c2993c64efc50fac 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
@@ -50,20 +50,33 @@ typedef enum spa_feature {
        SPA_FEATURE_BOOKMARKS,
        SPA_FEATURE_FS_SS_LIMIT,
        SPA_FEATURE_LARGE_BLOCKS,
+       SPA_FEATURE_LARGE_DNODE,
+       SPA_FEATURE_SHA512,
+       SPA_FEATURE_SKEIN,
+       SPA_FEATURE_EDONR,
+       SPA_FEATURE_USEROBJ_ACCOUNTING,
        SPA_FEATURES
 } spa_feature_t;
 
 #define        SPA_FEATURE_DISABLED    (-1ULL)
 
+typedef enum zfeature_flags {
+       /* Can open pool readonly even if this feature is not supported. */
+       ZFEATURE_FLAG_READONLY_COMPAT =         (1 << 0),
+       /* Is this feature necessary to read the MOS? */
+       ZFEATURE_FLAG_MOS =                     (1 << 1),
+       /* Activate this feature at the same time it is enabled. */
+       ZFEATURE_FLAG_ACTIVATE_ON_ENABLE =      (1 << 2),
+       /* Each dataset has a field set if it has ever used this feature. */
+       ZFEATURE_FLAG_PER_DATASET =             (1 << 3)
+} zfeature_flags_t;
+
 typedef struct zfeature_info {
        spa_feature_t fi_feature;
        const char *fi_uname;   /* User-facing feature name */
        const char *fi_guid;    /* On-disk feature identifier */
        const char *fi_desc;    /* Feature description */
-       boolean_t fi_can_readonly; /* Can open pool readonly w/o support? */
-       boolean_t fi_mos;       /* Is the feature necessary to read the MOS? */
-       /* Activate this feature at the same time it is enabled */
-       boolean_t fi_activate_on_enable;
+       zfeature_flags_t fi_flags;
        /* array of dependencies, terminated by SPA_FEATURE_NONE */
        const spa_feature_t *fi_depends;
 } zfeature_info_t;
index 16133c59f33f395b2efb12013e5b88069f9d2c12..95db9921f574b57d2e36cec5b30d386e9db9189d 100644 (file)
@@ -63,6 +63,10 @@ typedef enum {
        ZFS_DELEG_NOTE_GROUPQUOTA,
        ZFS_DELEG_NOTE_USERUSED,
        ZFS_DELEG_NOTE_GROUPUSED,
+       ZFS_DELEG_NOTE_USEROBJQUOTA,
+       ZFS_DELEG_NOTE_GROUPOBJQUOTA,
+       ZFS_DELEG_NOTE_USEROBJUSED,
+       ZFS_DELEG_NOTE_GROUPOBJUSED,
        ZFS_DELEG_NOTE_HOLD,
        ZFS_DELEG_NOTE_RELEASE,
        ZFS_DELEG_NOTE_DIFF,
index b49df0cf4f0fd2d613d9da1a1d93a68ab19dbb1a..1f113ae2f863d2ed13a569a282f398a2aecaefd7 100644 (file)
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
+ */
 
 #ifndef        _ZFS_FLETCHER_H
 #define        _ZFS_FLETCHER_H
 
 #include <sys/types.h>
-#include <sys/spa.h>
+#include <sys/spa_checksum.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -35,16 +38,106 @@ extern "C" {
 
 /*
  * fletcher checksum functions
+ *
+ * Note: Fletcher checksum methods expect buffer size to be 4B aligned. This
+ * limitation stems from the algorithm design. Performing incremental checksum
+ * without said alignment would yield different results. Therefore, the code
+ * includes assertions for the size alignment.
+ * For compatibility, it is required that some code paths calculate checksum of
+ * non-aligned buffer sizes. For this purpose, `fletcher_4_native_varsize()`
+ * checksum method is added. This method will ignore last (size % 4) bytes of
+ * the data buffer.
  */
-
-void fletcher_2_native(const void *, uint64_t, zio_cksum_t *);
-void fletcher_2_byteswap(const void *, uint64_t, zio_cksum_t *);
-void fletcher_4_native(const void *, uint64_t, zio_cksum_t *);
-void fletcher_4_byteswap(const void *, uint64_t, zio_cksum_t *);
+void fletcher_2_native(const void *, uint64_t, const void *, zio_cksum_t *);
+void fletcher_2_byteswap(const void *, uint64_t, const void *, zio_cksum_t *);
+void fletcher_4_native(const void *, uint64_t, const void *, zio_cksum_t *);
+void fletcher_4_native_varsize(const void *, uint64_t, zio_cksum_t *);
+void fletcher_4_byteswap(const void *, uint64_t, const void *, zio_cksum_t *);
 void fletcher_4_incremental_native(const void *, uint64_t,
     zio_cksum_t *);
 void fletcher_4_incremental_byteswap(const void *, uint64_t,
     zio_cksum_t *);
+int fletcher_4_impl_set(const char *selector);
+void fletcher_4_init(void);
+void fletcher_4_fini(void);
+
+
+
+/* Internal fletcher ctx */
+
+typedef struct zfs_fletcher_sse {
+       uint64_t v[2] __attribute__((aligned(16)));
+} zfs_fletcher_sse_t;
+
+typedef struct zfs_fletcher_avx {
+       uint64_t v[4] __attribute__((aligned(32)));
+} zfs_fletcher_avx_t;
+
+typedef struct zfs_fletcher_avx512 {
+       uint64_t v[8] __attribute__((aligned(64)));
+} zfs_fletcher_avx512_t;
+
+typedef struct zfs_fletcher_aarch64_neon {
+       uint64_t v[2] __attribute__((aligned(16)));
+} zfs_fletcher_aarch64_neon_t;
+
+
+typedef union fletcher_4_ctx {
+       zio_cksum_t scalar;
+
+#if defined(HAVE_SSE2) || (defined(HAVE_SSE2) && defined(HAVE_SSSE3))
+       zfs_fletcher_sse_t sse[4];
+#endif
+#if defined(HAVE_AVX) && defined(HAVE_AVX2)
+       zfs_fletcher_avx_t avx[4];
+#endif
+#if defined(__x86_64) && defined(HAVE_AVX512F)
+       zfs_fletcher_avx512_t avx512[4];
+#endif
+#if defined(__aarch64__)
+       zfs_fletcher_aarch64_neon_t aarch64_neon[4];
+#endif
+} fletcher_4_ctx_t;
+
+/*
+ * fletcher checksum struct
+ */
+typedef void (*fletcher_4_init_f)(fletcher_4_ctx_t *);
+typedef void (*fletcher_4_fini_f)(fletcher_4_ctx_t *, zio_cksum_t *);
+typedef void (*fletcher_4_compute_f)(fletcher_4_ctx_t *,
+    const void *, uint64_t);
+
+typedef struct fletcher_4_func {
+       fletcher_4_init_f init_native;
+       fletcher_4_fini_f fini_native;
+       fletcher_4_compute_f compute_native;
+       fletcher_4_init_f init_byteswap;
+       fletcher_4_fini_f fini_byteswap;
+       fletcher_4_compute_f compute_byteswap;
+       boolean_t (*valid)(void);
+       const char *name;
+} fletcher_4_ops_t;
+
+
+#if defined(HAVE_SSE2)
+extern const fletcher_4_ops_t fletcher_4_sse2_ops;
+#endif
+
+#if defined(HAVE_SSE2) && defined(HAVE_SSSE3)
+extern const fletcher_4_ops_t fletcher_4_ssse3_ops;
+#endif
+
+#if defined(HAVE_AVX) && defined(HAVE_AVX2)
+extern const fletcher_4_ops_t fletcher_4_avx2_ops;
+#endif
+
+#if defined(__x86_64) && defined(HAVE_AVX512F)
+extern const fletcher_4_ops_t fletcher_4_avx512f_ops;
+#endif
+
+#if defined(__aarch64__)
+extern const fletcher_4_ops_t fletcher_4_aarch64_neon_ops;
+#endif
 
 #ifdef __cplusplus
 }
index 9a47ff91d55c037ed5694ddb0d989e5a7f72d7c6..aee4f0a50125ac02fe29b1800c26940cc9f4aee2 100644 (file)
@@ -29,6 +29,8 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with ZPIOS.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Copyright (c) 2015, Intel Corporation.
  */
 
 #ifndef _ZPIOS_CTL_H
@@ -116,6 +118,7 @@ typedef struct zpios_cmd {
        uint32_t cmd_chunk_noise;       /* Chunk noise */
        uint32_t cmd_thread_delay;      /* Thread delay */
        uint32_t cmd_flags;             /* Test flags */
+       uint32_t cmd_block_size;        /* ZFS block size */
        char cmd_pre[ZPIOS_PATH_SIZE];  /* Pre-exec hook */
        char cmd_post[ZPIOS_PATH_SIZE]; /* Post-exec hook */
        char cmd_log[ZPIOS_PATH_SIZE];  /* Requested log dir */
index 4b99b4ce31f37a3c72f7768ea1e4989d5542311b..dd2bd2343a42ed3f11babba942ab0b298ca172a2 100644 (file)
@@ -29,6 +29,8 @@
  *
  *  You should have received a copy of the GNU General Public License along
  *  with ZPIOS.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Copyright (c) 2015, Intel Corporation.
  */
 
 #ifndef _ZPIOS_INTERNAL_H
@@ -79,6 +81,7 @@ typedef struct run_args {
        __u32 chunk_noise;
        __u32 thread_delay;
        __u32 flags;
+       __u32 block_size;
        char pre[ZPIOS_PATH_SIZE];
        char post[ZPIOS_PATH_SIZE];
        char log[ZPIOS_PATH_SIZE];
diff --git a/zfs/lib/Makefile.am b/zfs/lib/Makefile.am
new file mode 100644 (file)
index 0000000..3aec922
--- /dev/null
@@ -0,0 +1,7 @@
+# NB: GNU Automake Manual, Chapter 8.3.5: Libtool Convenience Libraries
+# These six libraries are intermediary build components.
+SUBDIRS = libspl libavl libefi libshare libunicode libicp
+
+# These four libraries, which are installed as the final build product,
+# incorporate the six convenience libraries given above.
+SUBDIRS += libuutil libnvpair libzpool libzfs_core libzfs
diff --git a/zfs/lib/Makefile.in b/zfs/lib/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libavl/Makefile.am b/zfs/lib/libavl/Makefile.am
new file mode 100644 (file)
index 0000000..6a42649
--- /dev/null
@@ -0,0 +1,22 @@
+include $(top_srcdir)/config/Rules.am
+
+VPATH = $(top_srcdir)/module/avl/
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+noinst_LTLIBRARIES = libavl.la
+
+USER_C =
+
+KERNEL_C = \
+       avl.c
+
+nodist_libavl_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libavl/Makefile.in b/zfs/lib/libavl/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libefi/Makefile.am b/zfs/lib/libefi/Makefile.am
new file mode 100644 (file)
index 0000000..f0c05ee
--- /dev/null
@@ -0,0 +1,22 @@
+include $(top_srcdir)/config/Rules.am
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+noinst_LTLIBRARIES = libefi.la
+
+USER_C = \
+       rdwr_efi.c
+
+KERNEL_C =
+
+nodist_libefi_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+libefi_la_LIBADD = $(LIBUUID)
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libefi/Makefile.in b/zfs/lib/libefi/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libefi/rdwr_efi.c b/zfs/lib/libefi/rdwr_efi.c
new file mode 100644 (file)
index 0000000..e9fb15e
--- /dev/null
@@ -0,0 +1,1569 @@
+/*
+ * 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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+#include <zlib.h>
+#include <libintl.h>
+#include <sys/types.h>
+#include <sys/dkio.h>
+#include <sys/vtoc.h>
+#include <sys/mhd.h>
+#include <sys/param.h>
+#include <sys/dktp/fdisk.h>
+#include <sys/efi_partition.h>
+#include <sys/byteorder.h>
+#if defined(__linux__)
+#include <linux/fs.h>
+#endif
+
+static struct uuid_to_ptag {
+       struct uuid     uuid;
+} conversion_array[] = {
+       { EFI_UNUSED },
+       { EFI_BOOT },
+       { EFI_ROOT },
+       { EFI_SWAP },
+       { EFI_USR },
+       { EFI_BACKUP },
+       { EFI_UNUSED },         /* STAND is never used */
+       { EFI_VAR },
+       { EFI_HOME },
+       { EFI_ALTSCTR },
+       { EFI_UNUSED },         /* CACHE (cachefs) is never used */
+       { EFI_RESERVED },
+       { EFI_SYSTEM },
+       { EFI_LEGACY_MBR },
+       { EFI_SYMC_PUB },
+       { EFI_SYMC_CDS },
+       { EFI_MSFT_RESV },
+       { EFI_DELL_BASIC },
+       { EFI_DELL_RAID },
+       { EFI_DELL_SWAP },
+       { EFI_DELL_LVM },
+       { EFI_DELL_RESV },
+       { EFI_AAPL_HFS },
+       { EFI_AAPL_UFS },
+       { EFI_FREEBSD_BOOT },
+       { EFI_FREEBSD_SWAP },
+       { EFI_FREEBSD_UFS },
+       { EFI_FREEBSD_VINUM },
+       { EFI_FREEBSD_ZFS },
+       { EFI_BIOS_BOOT },
+       { EFI_INTC_RS },
+       { EFI_SNE_BOOT },
+       { EFI_LENOVO_BOOT },
+       { EFI_MSFT_LDMM },
+       { EFI_MSFT_LDMD },
+       { EFI_MSFT_RE },
+       { EFI_IBM_GPFS },
+       { EFI_MSFT_STORAGESPACES },
+       { EFI_HPQ_DATA },
+       { EFI_HPQ_SVC },
+       { EFI_RHT_DATA },
+       { EFI_RHT_HOME },
+       { EFI_RHT_SRV },
+       { EFI_RHT_DMCRYPT },
+       { EFI_RHT_LUKS },
+       { EFI_FREEBSD_DISKLABEL },
+       { EFI_AAPL_RAID },
+       { EFI_AAPL_RAIDOFFLINE },
+       { EFI_AAPL_BOOT },
+       { EFI_AAPL_LABEL },
+       { EFI_AAPL_TVRECOVERY },
+       { EFI_AAPL_CORESTORAGE },
+       { EFI_NETBSD_SWAP },
+       { EFI_NETBSD_FFS },
+       { EFI_NETBSD_LFS },
+       { EFI_NETBSD_RAID },
+       { EFI_NETBSD_CAT },
+       { EFI_NETBSD_CRYPT },
+       { EFI_GOOG_KERN },
+       { EFI_GOOG_ROOT },
+       { EFI_GOOG_RESV },
+       { EFI_HAIKU_BFS },
+       { EFI_MIDNIGHTBSD_BOOT },
+       { EFI_MIDNIGHTBSD_DATA },
+       { EFI_MIDNIGHTBSD_SWAP },
+       { EFI_MIDNIGHTBSD_UFS },
+       { EFI_MIDNIGHTBSD_VINUM },
+       { EFI_MIDNIGHTBSD_ZFS },
+       { EFI_CEPH_JOURNAL },
+       { EFI_CEPH_DMCRYPTJOURNAL },
+       { EFI_CEPH_OSD },
+       { EFI_CEPH_DMCRYPTOSD },
+       { EFI_CEPH_CREATE },
+       { EFI_CEPH_DMCRYPTCREATE },
+       { EFI_OPENBSD_DISKLABEL },
+       { EFI_BBRY_QNX },
+       { EFI_BELL_PLAN9 },
+       { EFI_VMW_KCORE },
+       { EFI_VMW_VMFS },
+       { EFI_VMW_RESV },
+       { EFI_RHT_ROOTX86 },
+       { EFI_RHT_ROOTAMD64 },
+       { EFI_RHT_ROOTARM },
+       { EFI_RHT_ROOTARM64 },
+       { EFI_ACRONIS_SECUREZONE },
+       { EFI_ONIE_BOOT },
+       { EFI_ONIE_CONFIG },
+       { EFI_IBM_PPRPBOOT },
+       { EFI_FREEDESKTOP_BOOT }
+};
+
+/*
+ * Default vtoc information for non-SVr4 partitions
+ */
+struct dk_map2  default_vtoc_map[NDKMAP] = {
+       {       V_ROOT,         0       },              /* a - 0 */
+       {       V_SWAP,         V_UNMNT },              /* b - 1 */
+       {       V_BACKUP,       V_UNMNT },              /* c - 2 */
+       {       V_UNASSIGNED,   0       },              /* d - 3 */
+       {       V_UNASSIGNED,   0       },              /* e - 4 */
+       {       V_UNASSIGNED,   0       },              /* f - 5 */
+       {       V_USR,          0       },              /* g - 6 */
+       {       V_UNASSIGNED,   0       },              /* h - 7 */
+
+#if defined(_SUNOS_VTOC_16)
+
+#if defined(i386) || defined(__amd64) || defined(__arm) || \
+    defined(__powerpc) || defined(__sparc) || defined(__s390__) || \
+    defined(__mips__)
+       {       V_BOOT,         V_UNMNT },              /* i - 8 */
+       {       V_ALTSCTR,      0       },              /* j - 9 */
+
+#else
+#error No VTOC format defined.
+#endif                 /* defined(i386) */
+
+       {       V_UNASSIGNED,   0       },              /* k - 10 */
+       {       V_UNASSIGNED,   0       },              /* l - 11 */
+       {       V_UNASSIGNED,   0       },              /* m - 12 */
+       {       V_UNASSIGNED,   0       },              /* n - 13 */
+       {       V_UNASSIGNED,   0       },              /* o - 14 */
+       {       V_UNASSIGNED,   0       },              /* p - 15 */
+#endif                 /* defined(_SUNOS_VTOC_16) */
+};
+
+int efi_debug = 0;
+
+static int efi_read(int, struct dk_gpt *);
+
+/*
+ * Return a 32-bit CRC of the contents of the buffer.  Pre-and-post
+ * one's conditioning will be handled by crc32() internally.
+ */
+static uint32_t
+efi_crc32(const unsigned char *buf, unsigned int size)
+{
+       uint32_t crc = crc32(0, Z_NULL, 0);
+
+       crc = crc32(crc, buf, size);
+
+       return (crc);
+}
+
+static int
+read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize)
+{
+       int sector_size;
+       unsigned long long capacity_size;
+
+       if (ioctl(fd, BLKSSZGET, &sector_size) < 0)
+               return (-1);
+
+       if (ioctl(fd, BLKGETSIZE64, &capacity_size) < 0)
+               return (-1);
+
+       *lbsize = (uint_t)sector_size;
+       *capacity = (diskaddr_t)(capacity_size / sector_size);
+
+       return (0);
+}
+
+static int
+efi_get_info(int fd, struct dk_cinfo *dki_info)
+{
+#if defined(__linux__)
+       char *path;
+       char *dev_path;
+       int rval = 0;
+
+       memset(dki_info, 0, sizeof (*dki_info));
+
+       path = calloc(PATH_MAX, 1);
+       if (path == NULL)
+               goto error;
+
+       /*
+        * The simplest way to get the partition number under linux is
+        * to parse it out of the /dev/<disk><parition> block device name.
+        * The kernel creates this using the partition number when it
+        * populates /dev/ so it may be trusted.  The tricky bit here is
+        * that the naming convention is based on the block device type.
+        * So we need to take this in to account when parsing out the
+        * partition information.  Another issue is that the libefi API
+        * API only provides the open fd and not the file path.  To handle
+        * this realpath(3) is used to resolve the block device name from
+        * /proc/self/fd/<fd>.  Aside from the partition number we collect
+        * some additional device info.
+        */
+       (void) sprintf(path, "/proc/self/fd/%d", fd);
+       dev_path = realpath(path, NULL);
+       free(path);
+
+       if (dev_path == NULL)
+               goto error;
+
+       if ((strncmp(dev_path, "/dev/sd", 7) == 0)) {
+               strcpy(dki_info->dki_cname, "sd");
+               dki_info->dki_ctype = DKC_SCSI_CCS;
+               rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+                   dki_info->dki_dname,
+                   &dki_info->dki_partition);
+       } else if ((strncmp(dev_path, "/dev/hd", 7) == 0)) {
+               strcpy(dki_info->dki_cname, "hd");
+               dki_info->dki_ctype = DKC_DIRECT;
+               rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+                   dki_info->dki_dname,
+                   &dki_info->dki_partition);
+       } else if ((strncmp(dev_path, "/dev/md", 7) == 0)) {
+               strcpy(dki_info->dki_cname, "pseudo");
+               dki_info->dki_ctype = DKC_MD;
+               strcpy(dki_info->dki_dname, "md");
+               rval = sscanf(dev_path, "/dev/md%[0-9]p%hu",
+                   dki_info->dki_dname + 2,
+                   &dki_info->dki_partition);
+       } else if ((strncmp(dev_path, "/dev/vd", 7) == 0)) {
+               strcpy(dki_info->dki_cname, "vd");
+               dki_info->dki_ctype = DKC_MD;
+               rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+                   dki_info->dki_dname,
+                   &dki_info->dki_partition);
+       } else if ((strncmp(dev_path, "/dev/xvd", 8) == 0)) {
+               strcpy(dki_info->dki_cname, "xvd");
+               dki_info->dki_ctype = DKC_MD;
+               rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+                   dki_info->dki_dname,
+                   &dki_info->dki_partition);
+       } else if ((strncmp(dev_path, "/dev/zd", 7) == 0)) {
+               strcpy(dki_info->dki_cname, "zd");
+               dki_info->dki_ctype = DKC_MD;
+               rval = sscanf(dev_path, "/dev/%[a-zA-Z]%hu",
+                   dki_info->dki_dname,
+                   &dki_info->dki_partition);
+       } else if ((strncmp(dev_path, "/dev/dm-", 8) == 0)) {
+               strcpy(dki_info->dki_cname, "pseudo");
+               dki_info->dki_ctype = DKC_VBD;
+               strcpy(dki_info->dki_dname, "dm-");
+               rval = sscanf(dev_path, "/dev/dm-%[0-9]p%hu",
+                   dki_info->dki_dname + 3,
+                   &dki_info->dki_partition);
+       } else if ((strncmp(dev_path, "/dev/ram", 8) == 0)) {
+               strcpy(dki_info->dki_cname, "pseudo");
+               dki_info->dki_ctype = DKC_PCMCIA_MEM;
+               strcpy(dki_info->dki_dname, "ram");
+               rval = sscanf(dev_path, "/dev/ram%[0-9]p%hu",
+                   dki_info->dki_dname + 3,
+                   &dki_info->dki_partition);
+       } else if ((strncmp(dev_path, "/dev/loop", 9) == 0)) {
+               strcpy(dki_info->dki_cname, "pseudo");
+               dki_info->dki_ctype = DKC_VBD;
+               strcpy(dki_info->dki_dname, "loop");
+               rval = sscanf(dev_path, "/dev/loop%[0-9]p%hu",
+                   dki_info->dki_dname + 4,
+                   &dki_info->dki_partition);
+       } else {
+               strcpy(dki_info->dki_dname, "unknown");
+               strcpy(dki_info->dki_cname, "unknown");
+               dki_info->dki_ctype = DKC_UNKNOWN;
+       }
+
+       switch (rval) {
+       case 0:
+               errno = EINVAL;
+               goto error;
+       case 1:
+               dki_info->dki_partition = 0;
+       }
+
+       free(dev_path);
+#else
+       if (ioctl(fd, DKIOCINFO, (caddr_t)dki_info) == -1)
+               goto error;
+#endif
+       return (0);
+error:
+       if (efi_debug)
+               (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno);
+
+       switch (errno) {
+       case EIO:
+               return (VT_EIO);
+       case EINVAL:
+               return (VT_EINVAL);
+       default:
+               return (VT_ERROR);
+       }
+}
+
+/*
+ * the number of blocks the EFI label takes up (round up to nearest
+ * block)
+ */
+#define        NBLOCKS(p, l)   (1 + ((((p) * (int)sizeof (efi_gpe_t))  + \
+                               ((l) - 1)) / (l)))
+/* number of partitions -- limited by what we can malloc */
+#define        MAX_PARTS       ((4294967295UL - sizeof (struct dk_gpt)) / \
+                           sizeof (struct dk_part))
+
+int
+efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc)
+{
+       diskaddr_t      capacity = 0;
+       uint_t          lbsize = 0;
+       uint_t          nblocks;
+       size_t          length;
+       struct dk_gpt   *vptr;
+       struct uuid     uuid;
+       struct dk_cinfo dki_info;
+
+       if (read_disk_info(fd, &capacity, &lbsize) != 0)
+               return (-1);
+
+#if defined(__linux__)
+       if (efi_get_info(fd, &dki_info) != 0)
+               return (-1);
+
+       if (dki_info.dki_partition != 0)
+               return (-1);
+
+       if ((dki_info.dki_ctype == DKC_PCMCIA_MEM) ||
+           (dki_info.dki_ctype == DKC_VBD) ||
+           (dki_info.dki_ctype == DKC_UNKNOWN))
+               return (-1);
+#endif
+
+       nblocks = NBLOCKS(nparts, lbsize);
+       if ((nblocks * lbsize) < EFI_MIN_ARRAY_SIZE + lbsize) {
+               /* 16K plus one block for the GPT */
+               nblocks = EFI_MIN_ARRAY_SIZE / lbsize + 1;
+       }
+
+       if (nparts > MAX_PARTS) {
+               if (efi_debug) {
+                       (void) fprintf(stderr,
+                       "the maximum number of partitions supported is %lu\n",
+                           MAX_PARTS);
+               }
+               return (-1);
+       }
+
+       length = sizeof (struct dk_gpt) +
+           sizeof (struct dk_part) * (nparts - 1);
+
+       if ((*vtoc = calloc(length, 1)) == NULL)
+               return (-1);
+
+       vptr = *vtoc;
+
+       vptr->efi_version = EFI_VERSION_CURRENT;
+       vptr->efi_lbasize = lbsize;
+       vptr->efi_nparts = nparts;
+       /*
+        * add one block here for the PMBR; on disks with a 512 byte
+        * block size and 128 or fewer partitions, efi_first_u_lba
+        * should work out to "34"
+        */
+       vptr->efi_first_u_lba = nblocks + 1;
+       vptr->efi_last_lba = capacity - 1;
+       vptr->efi_altern_lba = capacity -1;
+       vptr->efi_last_u_lba = vptr->efi_last_lba - nblocks;
+
+       (void) uuid_generate((uchar_t *)&uuid);
+       UUID_LE_CONVERT(vptr->efi_disk_uguid, uuid);
+       return (0);
+}
+
+/*
+ * Read EFI - return partition number upon success.
+ */
+int
+efi_alloc_and_read(int fd, struct dk_gpt **vtoc)
+{
+       int                     rval;
+       uint32_t                nparts;
+       int                     length;
+
+       /* figure out the number of entries that would fit into 16K */
+       nparts = EFI_MIN_ARRAY_SIZE / sizeof (efi_gpe_t);
+       length = (int) sizeof (struct dk_gpt) +
+           (int) sizeof (struct dk_part) * (nparts - 1);
+       if ((*vtoc = calloc(length, 1)) == NULL)
+               return (VT_ERROR);
+
+       (*vtoc)->efi_nparts = nparts;
+       rval = efi_read(fd, *vtoc);
+
+       if ((rval == VT_EINVAL) && (*vtoc)->efi_nparts > nparts) {
+               void *tmp;
+               length = (int) sizeof (struct dk_gpt) +
+                   (int) sizeof (struct dk_part) *
+                   ((*vtoc)->efi_nparts - 1);
+               nparts = (*vtoc)->efi_nparts;
+               if ((tmp = realloc(*vtoc, length)) == NULL) {
+                       free (*vtoc);
+                       *vtoc = NULL;
+                       return (VT_ERROR);
+               } else {
+                       *vtoc = tmp;
+                       rval = efi_read(fd, *vtoc);
+               }
+       }
+
+       if (rval < 0) {
+               if (efi_debug) {
+                       (void) fprintf(stderr,
+                           "read of EFI table failed, rval=%d\n", rval);
+               }
+               free (*vtoc);
+               *vtoc = NULL;
+       }
+
+       return (rval);
+}
+
+static int
+efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
+{
+       void *data = dk_ioc->dki_data;
+       int error;
+#if defined(__linux__)
+       diskaddr_t capacity;
+       uint_t lbsize;
+
+       /*
+        * When the IO is not being performed in kernel as an ioctl we need
+        * to know the sector size so we can seek to the proper byte offset.
+        */
+       if (read_disk_info(fd, &capacity, &lbsize) == -1) {
+               if (efi_debug)
+                       fprintf(stderr, "unable to read disk info: %d", errno);
+
+               errno = EIO;
+               return (-1);
+       }
+
+       switch (cmd) {
+       case DKIOCGETEFI:
+               if (lbsize == 0) {
+                       if (efi_debug)
+                               (void) fprintf(stderr, "DKIOCGETEFI assuming "
+                                   "LBA %d bytes\n", DEV_BSIZE);
+
+                       lbsize = DEV_BSIZE;
+               }
+
+               error = lseek(fd, dk_ioc->dki_lba * lbsize, SEEK_SET);
+               if (error == -1) {
+                       if (efi_debug)
+                               (void) fprintf(stderr, "DKIOCGETEFI lseek "
+                                   "error: %d\n", errno);
+                       return (error);
+               }
+
+               error = read(fd, data, dk_ioc->dki_length);
+               if (error == -1) {
+                       if (efi_debug)
+                               (void) fprintf(stderr, "DKIOCGETEFI read "
+                                   "error: %d\n", errno);
+                       return (error);
+               }
+
+               if (error != dk_ioc->dki_length) {
+                       if (efi_debug)
+                               (void) fprintf(stderr, "DKIOCGETEFI short "
+                                   "read of %d bytes\n", error);
+                       errno = EIO;
+                       return (-1);
+               }
+               error = 0;
+               break;
+
+       case DKIOCSETEFI:
+               if (lbsize == 0) {
+                       if (efi_debug)
+                               (void) fprintf(stderr, "DKIOCSETEFI unknown "
+                                   "LBA size\n");
+                       errno = EIO;
+                       return (-1);
+               }
+
+               error = lseek(fd, dk_ioc->dki_lba * lbsize, SEEK_SET);
+               if (error == -1) {
+                       if (efi_debug)
+                               (void) fprintf(stderr, "DKIOCSETEFI lseek "
+                                   "error: %d\n", errno);
+                       return (error);
+               }
+
+               error = write(fd, data, dk_ioc->dki_length);
+               if (error == -1) {
+                       if (efi_debug)
+                               (void) fprintf(stderr, "DKIOCSETEFI write "
+                                   "error: %d\n", errno);
+                       return (error);
+               }
+
+               if (error != dk_ioc->dki_length) {
+                       if (efi_debug)
+                               (void) fprintf(stderr, "DKIOCSETEFI short "
+                                   "write of %d bytes\n", error);
+                       errno = EIO;
+                       return (-1);
+               }
+
+               /* Sync the new EFI table to disk */
+               error = fsync(fd);
+               if (error == -1)
+                       return (error);
+
+               /* Ensure any local disk cache is also flushed */
+               if (ioctl(fd, BLKFLSBUF, 0) == -1)
+                       return (error);
+
+               error = 0;
+               break;
+
+       default:
+               if (efi_debug)
+                       (void) fprintf(stderr, "unsupported ioctl()\n");
+
+               errno = EIO;
+               return (-1);
+       }
+#else
+       dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data;
+       error = ioctl(fd, cmd, (void *)dk_ioc);
+       dk_ioc->dki_data = data;
+#endif
+       return (error);
+}
+
+int
+efi_rescan(int fd)
+{
+#if defined(__linux__)
+       int retry = 10;
+       int error;
+
+       /* Notify the kernel a devices partition table has been updated */
+       while ((error = ioctl(fd, BLKRRPART)) != 0) {
+               if ((--retry == 0) || (errno != EBUSY)) {
+                       (void) fprintf(stderr, "the kernel failed to rescan "
+                           "the partition table: %d\n", errno);
+                       return (-1);
+               }
+               usleep(50000);
+       }
+#endif
+
+       return (0);
+}
+
+static int
+check_label(int fd, dk_efi_t *dk_ioc)
+{
+       efi_gpt_t               *efi;
+       uint_t                  crc;
+
+       if (efi_ioctl(fd, DKIOCGETEFI, dk_ioc) == -1) {
+               switch (errno) {
+               case EIO:
+                       return (VT_EIO);
+               default:
+                       return (VT_ERROR);
+               }
+       }
+       efi = dk_ioc->dki_data;
+       if (efi->efi_gpt_Signature != LE_64(EFI_SIGNATURE)) {
+               if (efi_debug)
+                       (void) fprintf(stderr,
+                           "Bad EFI signature: 0x%llx != 0x%llx\n",
+                           (long long)efi->efi_gpt_Signature,
+                           (long long)LE_64(EFI_SIGNATURE));
+               return (VT_EINVAL);
+       }
+
+       /*
+        * check CRC of the header; the size of the header should
+        * never be larger than one block
+        */
+       crc = efi->efi_gpt_HeaderCRC32;
+       efi->efi_gpt_HeaderCRC32 = 0;
+       len_t headerSize = (len_t)LE_32(efi->efi_gpt_HeaderSize);
+
+       if (headerSize < EFI_MIN_LABEL_SIZE || headerSize > EFI_LABEL_SIZE) {
+               if (efi_debug)
+                       (void) fprintf(stderr,
+                           "Invalid EFI HeaderSize %llu.  Assuming %d.\n",
+                           headerSize, EFI_MIN_LABEL_SIZE);
+       }
+
+       if ((headerSize > dk_ioc->dki_length) ||
+           crc != LE_32(efi_crc32((unsigned char *)efi, headerSize))) {
+               if (efi_debug)
+                       (void) fprintf(stderr,
+                           "Bad EFI CRC: 0x%x != 0x%x\n",
+                           crc, LE_32(efi_crc32((unsigned char *)efi,
+                           headerSize)));
+               return (VT_EINVAL);
+       }
+
+       return (0);
+}
+
+static int
+efi_read(int fd, struct dk_gpt *vtoc)
+{
+       int                     i, j;
+       int                     label_len;
+       int                     rval = 0;
+       int                     md_flag = 0;
+       int                     vdc_flag = 0;
+       diskaddr_t              capacity = 0;
+       uint_t                  lbsize = 0;
+       struct dk_minfo         disk_info;
+       dk_efi_t                dk_ioc;
+       efi_gpt_t               *efi;
+       efi_gpe_t               *efi_parts;
+       struct dk_cinfo         dki_info;
+       uint32_t                user_length;
+       boolean_t               legacy_label = B_FALSE;
+
+       /*
+        * get the partition number for this file descriptor.
+        */
+       if ((rval = efi_get_info(fd, &dki_info)) != 0)
+               return (rval);
+
+       if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
+           (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
+               md_flag++;
+       } else if ((strncmp(dki_info.dki_cname, "vdc", 4) == 0) &&
+           (strncmp(dki_info.dki_dname, "vdc", 4) == 0)) {
+               /*
+                * The controller and drive name "vdc" (virtual disk client)
+                * indicates a LDoms virtual disk.
+                */
+               vdc_flag++;
+       }
+
+       /* get the LBA size */
+       if (read_disk_info(fd, &capacity, &lbsize) == -1) {
+               if (efi_debug) {
+                       (void) fprintf(stderr,
+                           "unable to read disk info: %d",
+                           errno);
+               }
+               return (VT_EINVAL);
+       }
+
+       disk_info.dki_lbsize = lbsize;
+       disk_info.dki_capacity = capacity;
+
+       if (disk_info.dki_lbsize == 0) {
+               if (efi_debug) {
+                       (void) fprintf(stderr,
+                           "efi_read: assuming LBA 512 bytes\n");
+               }
+               disk_info.dki_lbsize = DEV_BSIZE;
+       }
+       /*
+        * Read the EFI GPT to figure out how many partitions we need
+        * to deal with.
+        */
+       dk_ioc.dki_lba = 1;
+       if (NBLOCKS(vtoc->efi_nparts, disk_info.dki_lbsize) < 34) {
+               label_len = EFI_MIN_ARRAY_SIZE + disk_info.dki_lbsize;
+       } else {
+               label_len = vtoc->efi_nparts * (int) sizeof (efi_gpe_t) +
+                   disk_info.dki_lbsize;
+               if (label_len % disk_info.dki_lbsize) {
+                       /* pad to physical sector size */
+                       label_len += disk_info.dki_lbsize;
+                       label_len &= ~(disk_info.dki_lbsize - 1);
+               }
+       }
+
+       if (posix_memalign((void **)&dk_ioc.dki_data,
+           disk_info.dki_lbsize, label_len))
+               return (VT_ERROR);
+
+       memset(dk_ioc.dki_data, 0, label_len);
+       dk_ioc.dki_length = disk_info.dki_lbsize;
+       user_length = vtoc->efi_nparts;
+       efi = dk_ioc.dki_data;
+       if (md_flag) {
+               dk_ioc.dki_length = label_len;
+               if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
+                       switch (errno) {
+                       case EIO:
+                               return (VT_EIO);
+                       default:
+                               return (VT_ERROR);
+                       }
+               }
+       } else if ((rval = check_label(fd, &dk_ioc)) == VT_EINVAL) {
+               /*
+                * No valid label here; try the alternate. Note that here
+                * we just read GPT header and save it into dk_ioc.data,
+                * Later, we will read GUID partition entry array if we
+                * can get valid GPT header.
+                */
+
+               /*
+                * This is a workaround for legacy systems. In the past, the
+                * last sector of SCSI disk was invisible on x86 platform. At
+                * that time, backup label was saved on the next to the last
+                * sector. It is possible for users to move a disk from previous
+                * solaris system to present system. Here, we attempt to search
+                * legacy backup EFI label first.
+                */
+               dk_ioc.dki_lba = disk_info.dki_capacity - 2;
+               dk_ioc.dki_length = disk_info.dki_lbsize;
+               rval = check_label(fd, &dk_ioc);
+               if (rval == VT_EINVAL) {
+                       /*
+                        * we didn't find legacy backup EFI label, try to
+                        * search backup EFI label in the last block.
+                        */
+                       dk_ioc.dki_lba = disk_info.dki_capacity - 1;
+                       dk_ioc.dki_length = disk_info.dki_lbsize;
+                       rval = check_label(fd, &dk_ioc);
+                       if (rval == 0) {
+                               legacy_label = B_TRUE;
+                               if (efi_debug)
+                                       (void) fprintf(stderr,
+                                           "efi_read: primary label corrupt; "
+                                           "using EFI backup label located on"
+                                           " the last block\n");
+                       }
+               } else {
+                       if ((efi_debug) && (rval == 0))
+                               (void) fprintf(stderr, "efi_read: primary label"
+                                   " corrupt; using legacy EFI backup label "
+                                   " located on the next to last block\n");
+               }
+
+               if (rval == 0) {
+                       dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
+                       vtoc->efi_flags |= EFI_GPT_PRIMARY_CORRUPT;
+                       vtoc->efi_nparts =
+                           LE_32(efi->efi_gpt_NumberOfPartitionEntries);
+                       /*
+                        * Partition tables are between backup GPT header
+                        * table and ParitionEntryLBA (the starting LBA of
+                        * the GUID partition entries array). Now that we
+                        * already got valid GPT header and saved it in
+                        * dk_ioc.dki_data, we try to get GUID partition
+                        * entry array here.
+                        */
+                       /* LINTED */
+                       dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
+                           + disk_info.dki_lbsize);
+                       if (legacy_label)
+                               dk_ioc.dki_length = disk_info.dki_capacity - 1 -
+                                   dk_ioc.dki_lba;
+                       else
+                               dk_ioc.dki_length = disk_info.dki_capacity - 2 -
+                                   dk_ioc.dki_lba;
+                       dk_ioc.dki_length *= disk_info.dki_lbsize;
+                       if (dk_ioc.dki_length >
+                           ((len_t)label_len - sizeof (*dk_ioc.dki_data))) {
+                               rval = VT_EINVAL;
+                       } else {
+                               /*
+                                * read GUID partition entry array
+                                */
+                               rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
+                       }
+               }
+
+       } else if (rval == 0) {
+
+               dk_ioc.dki_lba = LE_64(efi->efi_gpt_PartitionEntryLBA);
+               /* LINTED */
+               dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data
+                   + disk_info.dki_lbsize);
+               dk_ioc.dki_length = label_len - disk_info.dki_lbsize;
+               rval = efi_ioctl(fd, DKIOCGETEFI, &dk_ioc);
+
+       } else if (vdc_flag && rval == VT_ERROR && errno == EINVAL) {
+               /*
+                * When the device is a LDoms virtual disk, the DKIOCGETEFI
+                * ioctl can fail with EINVAL if the virtual disk backend
+                * is a ZFS volume serviced by a domain running an old version
+                * of Solaris. This is because the DKIOCGETEFI ioctl was
+                * initially incorrectly implemented for a ZFS volume and it
+                * expected the GPT and GPE to be retrieved with a single ioctl.
+                * So we try to read the GPT and the GPE using that old style
+                * ioctl.
+                */
+               dk_ioc.dki_lba = 1;
+               dk_ioc.dki_length = label_len;
+               rval = check_label(fd, &dk_ioc);
+       }
+
+       if (rval < 0) {
+               free(efi);
+               return (rval);
+       }
+
+       /* LINTED -- always longlong aligned */
+       efi_parts = (efi_gpe_t *)(((char *)efi) + disk_info.dki_lbsize);
+
+       /*
+        * Assemble this into a "dk_gpt" struct for easier
+        * digestibility by applications.
+        */
+       vtoc->efi_version = LE_32(efi->efi_gpt_Revision);
+       vtoc->efi_nparts = LE_32(efi->efi_gpt_NumberOfPartitionEntries);
+       vtoc->efi_part_size = LE_32(efi->efi_gpt_SizeOfPartitionEntry);
+       vtoc->efi_lbasize = disk_info.dki_lbsize;
+       vtoc->efi_last_lba = disk_info.dki_capacity - 1;
+       vtoc->efi_first_u_lba = LE_64(efi->efi_gpt_FirstUsableLBA);
+       vtoc->efi_last_u_lba = LE_64(efi->efi_gpt_LastUsableLBA);
+       vtoc->efi_altern_lba = LE_64(efi->efi_gpt_AlternateLBA);
+       UUID_LE_CONVERT(vtoc->efi_disk_uguid, efi->efi_gpt_DiskGUID);
+
+       /*
+        * If the array the user passed in is too small, set the length
+        * to what it needs to be and return
+        */
+       if (user_length < vtoc->efi_nparts) {
+               return (VT_EINVAL);
+       }
+
+       for (i = 0; i < vtoc->efi_nparts; i++) {
+
+               UUID_LE_CONVERT(vtoc->efi_parts[i].p_guid,
+                   efi_parts[i].efi_gpe_PartitionTypeGUID);
+
+               for (j = 0;
+                   j < sizeof (conversion_array)
+                   / sizeof (struct uuid_to_ptag); j++) {
+
+                       if (bcmp(&vtoc->efi_parts[i].p_guid,
+                           &conversion_array[j].uuid,
+                           sizeof (struct uuid)) == 0) {
+                               vtoc->efi_parts[i].p_tag = j;
+                               break;
+                       }
+               }
+               if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
+                       continue;
+               vtoc->efi_parts[i].p_flag =
+                   LE_16(efi_parts[i].efi_gpe_Attributes.PartitionAttrs);
+               vtoc->efi_parts[i].p_start =
+                   LE_64(efi_parts[i].efi_gpe_StartingLBA);
+               vtoc->efi_parts[i].p_size =
+                   LE_64(efi_parts[i].efi_gpe_EndingLBA) -
+                   vtoc->efi_parts[i].p_start + 1;
+               for (j = 0; j < EFI_PART_NAME_LEN; j++) {
+                       vtoc->efi_parts[i].p_name[j] =
+                           (uchar_t)LE_16(
+                           efi_parts[i].efi_gpe_PartitionName[j]);
+               }
+
+               UUID_LE_CONVERT(vtoc->efi_parts[i].p_uguid,
+                   efi_parts[i].efi_gpe_UniquePartitionGUID);
+       }
+       free(efi);
+
+       return (dki_info.dki_partition);
+}
+
+/* writes a "protective" MBR */
+static int
+write_pmbr(int fd, struct dk_gpt *vtoc)
+{
+       dk_efi_t        dk_ioc;
+       struct mboot    mb;
+       uchar_t         *cp;
+       diskaddr_t      size_in_lba;
+       uchar_t         *buf;
+       int             len;
+
+       len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize;
+       if (posix_memalign((void **)&buf, len, len))
+               return (VT_ERROR);
+
+       /*
+        * Preserve any boot code and disk signature if the first block is
+        * already an MBR.
+        */
+       memset(buf, 0, len);
+       dk_ioc.dki_lba = 0;
+       dk_ioc.dki_length = len;
+       /* LINTED -- always longlong aligned */
+       dk_ioc.dki_data = (efi_gpt_t *)buf;
+       if (efi_ioctl(fd, DKIOCGETEFI, &dk_ioc) == -1) {
+               (void) memcpy(&mb, buf, sizeof (mb));
+               bzero(&mb, sizeof (mb));
+               mb.signature = LE_16(MBB_MAGIC);
+       } else {
+               (void) memcpy(&mb, buf, sizeof (mb));
+               if (mb.signature != LE_16(MBB_MAGIC)) {
+                       bzero(&mb, sizeof (mb));
+                       mb.signature = LE_16(MBB_MAGIC);
+               }
+       }
+
+       bzero(&mb.parts, sizeof (mb.parts));
+       cp = (uchar_t *)&mb.parts[0];
+       /* bootable or not */
+       *cp++ = 0;
+       /* beginning CHS; 0xffffff if not representable */
+       *cp++ = 0xff;
+       *cp++ = 0xff;
+       *cp++ = 0xff;
+       /* OS type */
+       *cp++ = EFI_PMBR;
+       /* ending CHS; 0xffffff if not representable */
+       *cp++ = 0xff;
+       *cp++ = 0xff;
+       *cp++ = 0xff;
+       /* starting LBA: 1 (little endian format) by EFI definition */
+       *cp++ = 0x01;
+       *cp++ = 0x00;
+       *cp++ = 0x00;
+       *cp++ = 0x00;
+       /* ending LBA: last block on the disk (little endian format) */
+       size_in_lba = vtoc->efi_last_lba;
+       if (size_in_lba < 0xffffffff) {
+               *cp++ = (size_in_lba & 0x000000ff);
+               *cp++ = (size_in_lba & 0x0000ff00) >> 8;
+               *cp++ = (size_in_lba & 0x00ff0000) >> 16;
+               *cp++ = (size_in_lba & 0xff000000) >> 24;
+       } else {
+               *cp++ = 0xff;
+               *cp++ = 0xff;
+               *cp++ = 0xff;
+               *cp++ = 0xff;
+       }
+
+       (void) memcpy(buf, &mb, sizeof (mb));
+       /* LINTED -- always longlong aligned */
+       dk_ioc.dki_data = (efi_gpt_t *)buf;
+       dk_ioc.dki_lba = 0;
+       dk_ioc.dki_length = len;
+       if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
+               free(buf);
+               switch (errno) {
+               case EIO:
+                       return (VT_EIO);
+               case EINVAL:
+                       return (VT_EINVAL);
+               default:
+                       return (VT_ERROR);
+               }
+       }
+       free(buf);
+       return (0);
+}
+
+/* make sure the user specified something reasonable */
+static int
+check_input(struct dk_gpt *vtoc)
+{
+       int                     resv_part = -1;
+       int                     i, j;
+       diskaddr_t              istart, jstart, isize, jsize, endsect;
+
+       /*
+        * Sanity-check the input (make sure no partitions overlap)
+        */
+       for (i = 0; i < vtoc->efi_nparts; i++) {
+               /* It can't be unassigned and have an actual size */
+               if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
+                   (vtoc->efi_parts[i].p_size != 0)) {
+                       if (efi_debug) {
+                               (void) fprintf(stderr, "partition %d is "
+                                   "\"unassigned\" but has a size of %llu",
+                                   i, vtoc->efi_parts[i].p_size);
+                       }
+                       return (VT_EINVAL);
+               }
+               if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
+                       if (uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_guid))
+                               continue;
+                       /* we have encountered an unknown uuid */
+                       vtoc->efi_parts[i].p_tag = 0xff;
+               }
+               if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
+                       if (resv_part != -1) {
+                               if (efi_debug) {
+                                       (void) fprintf(stderr, "found "
+                                           "duplicate reserved partition "
+                                           "at %d\n", i);
+                               }
+                               return (VT_EINVAL);
+                       }
+                       resv_part = i;
+               }
+               if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
+                   (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
+                       if (efi_debug) {
+                               (void) fprintf(stderr,
+                                   "Partition %d starts at %llu.  ",
+                                   i,
+                                   vtoc->efi_parts[i].p_start);
+                               (void) fprintf(stderr,
+                                   "It must be between %llu and %llu.\n",
+                                   vtoc->efi_first_u_lba,
+                                   vtoc->efi_last_u_lba);
+                       }
+                       return (VT_EINVAL);
+               }
+               if ((vtoc->efi_parts[i].p_start +
+                   vtoc->efi_parts[i].p_size <
+                   vtoc->efi_first_u_lba) ||
+                   (vtoc->efi_parts[i].p_start +
+                   vtoc->efi_parts[i].p_size >
+                   vtoc->efi_last_u_lba + 1)) {
+                       if (efi_debug) {
+                               (void) fprintf(stderr,
+                                   "Partition %d ends at %llu.  ",
+                                   i,
+                                   vtoc->efi_parts[i].p_start +
+                                   vtoc->efi_parts[i].p_size);
+                               (void) fprintf(stderr,
+                                   "It must be between %llu and %llu.\n",
+                                   vtoc->efi_first_u_lba,
+                                   vtoc->efi_last_u_lba);
+                       }
+                       return (VT_EINVAL);
+               }
+
+               for (j = 0; j < vtoc->efi_nparts; j++) {
+                       isize = vtoc->efi_parts[i].p_size;
+                       jsize = vtoc->efi_parts[j].p_size;
+                       istart = vtoc->efi_parts[i].p_start;
+                       jstart = vtoc->efi_parts[j].p_start;
+                       if ((i != j) && (isize != 0) && (jsize != 0)) {
+                               endsect = jstart + jsize -1;
+                               if ((jstart <= istart) &&
+                                   (istart <= endsect)) {
+                                       if (efi_debug) {
+                                               (void) fprintf(stderr,
+                                                   "Partition %d overlaps "
+                                                   "partition %d.", i, j);
+                                       }
+                                       return (VT_EINVAL);
+                               }
+                       }
+               }
+       }
+       /* just a warning for now */
+       if ((resv_part == -1) && efi_debug) {
+               (void) fprintf(stderr,
+                   "no reserved partition found\n");
+       }
+       return (0);
+}
+
+/*
+ * add all the unallocated space to the current label
+ */
+int
+efi_use_whole_disk(int fd)
+{
+       struct dk_gpt           *efi_label = NULL;
+       int                     rval;
+       int                     i;
+       uint_t                  resv_index = 0, data_index = 0;
+       diskaddr_t              resv_start = 0, data_start = 0;
+       diskaddr_t              difference;
+
+       rval = efi_alloc_and_read(fd, &efi_label);
+       if (rval < 0) {
+               if (efi_label != NULL)
+                       efi_free(efi_label);
+               return (rval);
+       }
+
+       /*
+        * If alter_lba is 1, we are using the backup label.
+        * Since we can locate the backup label by disk capacity,
+        * there must be no unallocated space.
+        */
+       if ((efi_label->efi_altern_lba == 1) || (efi_label->efi_altern_lba
+           >= efi_label->efi_last_lba)) {
+               if (efi_debug) {
+                       (void) fprintf(stderr,
+                           "efi_use_whole_disk: requested space not found\n");
+               }
+               efi_free(efi_label);
+               return (VT_ENOSPC);
+       }
+
+       difference = efi_label->efi_last_lba - efi_label->efi_altern_lba;
+
+       /*
+        * Find the last physically non-zero partition.
+        * This is the reserved partition.
+        */
+       for (i = 0; i < efi_label->efi_nparts; i ++) {
+               if (resv_start < efi_label->efi_parts[i].p_start) {
+                       resv_start = efi_label->efi_parts[i].p_start;
+                       resv_index = i;
+               }
+       }
+
+       /*
+        * Find the last physically non-zero partition before that.
+        * This is the data partition.
+        */
+       for (i = 0; i < resv_index; i ++) {
+               if (data_start < efi_label->efi_parts[i].p_start) {
+                       data_start = efi_label->efi_parts[i].p_start;
+                       data_index = i;
+               }
+       }
+
+       /*
+        * Move the reserved partition. There is currently no data in
+        * here except fabricated devids (which get generated via
+        * efi_write()). So there is no need to copy data.
+        */
+       efi_label->efi_parts[data_index].p_size += difference;
+       efi_label->efi_parts[resv_index].p_start += difference;
+       efi_label->efi_last_u_lba += difference;
+
+       rval = efi_write(fd, efi_label);
+       if (rval < 0) {
+               if (efi_debug) {
+                       (void) fprintf(stderr,
+                           "efi_use_whole_disk:fail to write label, rval=%d\n",
+                           rval);
+               }
+               efi_free(efi_label);
+               return (rval);
+       }
+
+       efi_free(efi_label);
+       return (0);
+}
+
+
+/*
+ * write EFI label and backup label
+ */
+int
+efi_write(int fd, struct dk_gpt *vtoc)
+{
+       dk_efi_t                dk_ioc;
+       efi_gpt_t               *efi;
+       efi_gpe_t               *efi_parts;
+       int                     i, j;
+       struct dk_cinfo         dki_info;
+       int                     rval;
+       int                     md_flag = 0;
+       int                     nblocks;
+       diskaddr_t              lba_backup_gpt_hdr;
+
+       if ((rval = efi_get_info(fd, &dki_info)) != 0)
+               return (rval);
+
+       /* check if we are dealing wih a metadevice */
+       if ((strncmp(dki_info.dki_cname, "pseudo", 7) == 0) &&
+           (strncmp(dki_info.dki_dname, "md", 3) == 0)) {
+               md_flag = 1;
+       }
+
+       if (check_input(vtoc)) {
+               /*
+                * not valid; if it's a metadevice just pass it down
+                * because SVM will do its own checking
+                */
+               if (md_flag == 0) {
+                       return (VT_EINVAL);
+               }
+       }
+
+       dk_ioc.dki_lba = 1;
+       if (NBLOCKS(vtoc->efi_nparts, vtoc->efi_lbasize) < 34) {
+               dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + vtoc->efi_lbasize;
+       } else {
+               dk_ioc.dki_length = NBLOCKS(vtoc->efi_nparts,
+                   vtoc->efi_lbasize) *
+                   vtoc->efi_lbasize;
+       }
+
+       /*
+        * the number of blocks occupied by GUID partition entry array
+        */
+       nblocks = dk_ioc.dki_length / vtoc->efi_lbasize - 1;
+
+       /*
+        * Backup GPT header is located on the block after GUID
+        * partition entry array. Here, we calculate the address
+        * for backup GPT header.
+        */
+       lba_backup_gpt_hdr = vtoc->efi_last_u_lba + 1 + nblocks;
+       if (posix_memalign((void **)&dk_ioc.dki_data,
+           vtoc->efi_lbasize, dk_ioc.dki_length))
+               return (VT_ERROR);
+
+       memset(dk_ioc.dki_data, 0, dk_ioc.dki_length);
+       efi = dk_ioc.dki_data;
+
+       /* stuff user's input into EFI struct */
+       efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE);
+       efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */
+       efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt) - LEN_EFI_PAD);
+       efi->efi_gpt_Reserved1 = 0;
+       efi->efi_gpt_MyLBA = LE_64(1ULL);
+       efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr);
+       efi->efi_gpt_FirstUsableLBA = LE_64(vtoc->efi_first_u_lba);
+       efi->efi_gpt_LastUsableLBA = LE_64(vtoc->efi_last_u_lba);
+       efi->efi_gpt_PartitionEntryLBA = LE_64(2ULL);
+       efi->efi_gpt_NumberOfPartitionEntries = LE_32(vtoc->efi_nparts);
+       efi->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (struct efi_gpe));
+       UUID_LE_CONVERT(efi->efi_gpt_DiskGUID, vtoc->efi_disk_uguid);
+
+       /* LINTED -- always longlong aligned */
+       efi_parts = (efi_gpe_t *)((char *)dk_ioc.dki_data + vtoc->efi_lbasize);
+
+       for (i = 0; i < vtoc->efi_nparts; i++) {
+               for (j = 0;
+                   j < sizeof (conversion_array) /
+                   sizeof (struct uuid_to_ptag); j++) {
+
+                       if (vtoc->efi_parts[i].p_tag == j) {
+                               UUID_LE_CONVERT(
+                                   efi_parts[i].efi_gpe_PartitionTypeGUID,
+                                   conversion_array[j].uuid);
+                               break;
+                       }
+               }
+
+               if (j == sizeof (conversion_array) /
+                   sizeof (struct uuid_to_ptag)) {
+                       /*
+                        * If we didn't have a matching uuid match, bail here.
+                        * Don't write a label with unknown uuid.
+                        */
+                       if (efi_debug) {
+                               (void) fprintf(stderr,
+                                   "Unknown uuid for p_tag %d\n",
+                                   vtoc->efi_parts[i].p_tag);
+                       }
+                       return (VT_EINVAL);
+               }
+
+               /* Zero's should be written for empty partitions */
+               if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED)
+                       continue;
+
+               efi_parts[i].efi_gpe_StartingLBA =
+                   LE_64(vtoc->efi_parts[i].p_start);
+               efi_parts[i].efi_gpe_EndingLBA =
+                   LE_64(vtoc->efi_parts[i].p_start +
+                   vtoc->efi_parts[i].p_size - 1);
+               efi_parts[i].efi_gpe_Attributes.PartitionAttrs =
+                   LE_16(vtoc->efi_parts[i].p_flag);
+               for (j = 0; j < EFI_PART_NAME_LEN; j++) {
+                       efi_parts[i].efi_gpe_PartitionName[j] =
+                           LE_16((ushort_t)vtoc->efi_parts[i].p_name[j]);
+               }
+               if ((vtoc->efi_parts[i].p_tag != V_UNASSIGNED) &&
+                   uuid_is_null((uchar_t *)&vtoc->efi_parts[i].p_uguid)) {
+                       (void) uuid_generate((uchar_t *)
+                           &vtoc->efi_parts[i].p_uguid);
+               }
+               bcopy(&vtoc->efi_parts[i].p_uguid,
+                   &efi_parts[i].efi_gpe_UniquePartitionGUID,
+                   sizeof (uuid_t));
+       }
+       efi->efi_gpt_PartitionEntryArrayCRC32 =
+           LE_32(efi_crc32((unsigned char *)efi_parts,
+           vtoc->efi_nparts * (int)sizeof (struct efi_gpe)));
+       efi->efi_gpt_HeaderCRC32 =
+           LE_32(efi_crc32((unsigned char *)efi,
+           LE_32(efi->efi_gpt_HeaderSize)));
+
+       if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
+               free(dk_ioc.dki_data);
+               switch (errno) {
+               case EIO:
+                       return (VT_EIO);
+               case EINVAL:
+                       return (VT_EINVAL);
+               default:
+                       return (VT_ERROR);
+               }
+       }
+       /* if it's a metadevice we're done */
+       if (md_flag) {
+               free(dk_ioc.dki_data);
+               return (0);
+       }
+
+       /* write backup partition array */
+       dk_ioc.dki_lba = vtoc->efi_last_u_lba + 1;
+       dk_ioc.dki_length -= vtoc->efi_lbasize;
+       /* LINTED */
+       dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
+           vtoc->efi_lbasize);
+
+       if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
+               /*
+                * we wrote the primary label okay, so don't fail
+                */
+               if (efi_debug) {
+                       (void) fprintf(stderr,
+                           "write of backup partitions to block %llu "
+                           "failed, errno %d\n",
+                           vtoc->efi_last_u_lba + 1,
+                           errno);
+               }
+       }
+       /*
+        * now swap MyLBA and AlternateLBA fields and write backup
+        * partition table header
+        */
+       dk_ioc.dki_lba = lba_backup_gpt_hdr;
+       dk_ioc.dki_length = vtoc->efi_lbasize;
+       /* LINTED */
+       dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
+           vtoc->efi_lbasize);
+       efi->efi_gpt_AlternateLBA = LE_64(1ULL);
+       efi->efi_gpt_MyLBA = LE_64(lba_backup_gpt_hdr);
+       efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1);
+       efi->efi_gpt_HeaderCRC32 = 0;
+       efi->efi_gpt_HeaderCRC32 =
+           LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data,
+           LE_32(efi->efi_gpt_HeaderSize)));
+
+       if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) {
+               if (efi_debug) {
+                       (void) fprintf(stderr,
+                           "write of backup header to block %llu failed, "
+                           "errno %d\n",
+                           lba_backup_gpt_hdr,
+                           errno);
+               }
+       }
+       /* write the PMBR */
+       (void) write_pmbr(fd, vtoc);
+       free(dk_ioc.dki_data);
+
+       return (0);
+}
+
+void
+efi_free(struct dk_gpt *ptr)
+{
+       free(ptr);
+}
+
+/*
+ * Input: File descriptor
+ * Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR.
+ * Otherwise 0.
+ */
+int
+efi_type(int fd)
+{
+#if 0
+       struct vtoc vtoc;
+       struct extvtoc extvtoc;
+
+       if (ioctl(fd, DKIOCGEXTVTOC, &extvtoc) == -1) {
+               if (errno == ENOTSUP)
+                       return (1);
+               else if (errno == ENOTTY) {
+                       if (ioctl(fd, DKIOCGVTOC, &vtoc) == -1)
+                               if (errno == ENOTSUP)
+                                       return (1);
+               }
+       }
+       return (0);
+#else
+       return (ENOSYS);
+#endif
+}
+
+void
+efi_err_check(struct dk_gpt *vtoc)
+{
+       int                     resv_part = -1;
+       int                     i, j;
+       diskaddr_t              istart, jstart, isize, jsize, endsect;
+       int                     overlap = 0;
+
+       /*
+        * make sure no partitions overlap
+        */
+       for (i = 0; i < vtoc->efi_nparts; i++) {
+               /* It can't be unassigned and have an actual size */
+               if ((vtoc->efi_parts[i].p_tag == V_UNASSIGNED) &&
+                   (vtoc->efi_parts[i].p_size != 0)) {
+                       (void) fprintf(stderr,
+                           "partition %d is \"unassigned\" but has a size "
+                           "of %llu\n", i, vtoc->efi_parts[i].p_size);
+               }
+               if (vtoc->efi_parts[i].p_tag == V_UNASSIGNED) {
+                       continue;
+               }
+               if (vtoc->efi_parts[i].p_tag == V_RESERVED) {
+                       if (resv_part != -1) {
+                               (void) fprintf(stderr,
+                                   "found duplicate reserved partition at "
+                                   "%d\n", i);
+                       }
+                       resv_part = i;
+                       if (vtoc->efi_parts[i].p_size != EFI_MIN_RESV_SIZE)
+                               (void) fprintf(stderr,
+                                   "Warning: reserved partition size must "
+                                   "be %d sectors\n", EFI_MIN_RESV_SIZE);
+               }
+               if ((vtoc->efi_parts[i].p_start < vtoc->efi_first_u_lba) ||
+                   (vtoc->efi_parts[i].p_start > vtoc->efi_last_u_lba)) {
+                       (void) fprintf(stderr,
+                           "Partition %d starts at %llu\n",
+                           i,
+                           vtoc->efi_parts[i].p_start);
+                       (void) fprintf(stderr,
+                           "It must be between %llu and %llu.\n",
+                           vtoc->efi_first_u_lba,
+                           vtoc->efi_last_u_lba);
+               }
+               if ((vtoc->efi_parts[i].p_start +
+                   vtoc->efi_parts[i].p_size <
+                   vtoc->efi_first_u_lba) ||
+                   (vtoc->efi_parts[i].p_start +
+                   vtoc->efi_parts[i].p_size >
+                   vtoc->efi_last_u_lba + 1)) {
+                       (void) fprintf(stderr,
+                           "Partition %d ends at %llu\n",
+                           i,
+                           vtoc->efi_parts[i].p_start +
+                           vtoc->efi_parts[i].p_size);
+                       (void) fprintf(stderr,
+                           "It must be between %llu and %llu.\n",
+                           vtoc->efi_first_u_lba,
+                           vtoc->efi_last_u_lba);
+               }
+
+               for (j = 0; j < vtoc->efi_nparts; j++) {
+                       isize = vtoc->efi_parts[i].p_size;
+                       jsize = vtoc->efi_parts[j].p_size;
+                       istart = vtoc->efi_parts[i].p_start;
+                       jstart = vtoc->efi_parts[j].p_start;
+                       if ((i != j) && (isize != 0) && (jsize != 0)) {
+                               endsect = jstart + jsize -1;
+                               if ((jstart <= istart) &&
+                                   (istart <= endsect)) {
+                                       if (!overlap) {
+                                       (void) fprintf(stderr,
+                                           "label error: EFI Labels do not "
+                                           "support overlapping partitions\n");
+                                       }
+                                       (void) fprintf(stderr,
+                                           "Partition %d overlaps partition "
+                                           "%d.\n", i, j);
+                                       overlap = 1;
+                               }
+                       }
+               }
+       }
+       /* make sure there is a reserved partition */
+       if (resv_part == -1) {
+               (void) fprintf(stderr,
+                   "no reserved partition found\n");
+       }
+}
+
+/*
+ * We need to get information necessary to construct a *new* efi
+ * label type
+ */
+int
+efi_auto_sense(int fd, struct dk_gpt **vtoc)
+{
+
+       int     i;
+
+       /*
+        * Now build the default partition table
+        */
+       if (efi_alloc_and_init(fd, EFI_NUMPAR, vtoc) != 0) {
+               if (efi_debug) {
+                       (void) fprintf(stderr, "efi_alloc_and_init failed.\n");
+               }
+               return (-1);
+       }
+
+       for (i = 0; i < MIN((*vtoc)->efi_nparts, V_NUMPAR); i++) {
+               (*vtoc)->efi_parts[i].p_tag = default_vtoc_map[i].p_tag;
+               (*vtoc)->efi_parts[i].p_flag = default_vtoc_map[i].p_flag;
+               (*vtoc)->efi_parts[i].p_start = 0;
+               (*vtoc)->efi_parts[i].p_size = 0;
+       }
+       /*
+        * Make constants first
+        * and variable partitions later
+        */
+
+       /* root partition - s0 128 MB */
+       (*vtoc)->efi_parts[0].p_start = 34;
+       (*vtoc)->efi_parts[0].p_size = 262144;
+
+       /* partition - s1  128 MB */
+       (*vtoc)->efi_parts[1].p_start = 262178;
+       (*vtoc)->efi_parts[1].p_size = 262144;
+
+       /* partition -s2 is NOT the Backup disk */
+       (*vtoc)->efi_parts[2].p_tag = V_UNASSIGNED;
+
+       /* partition -s6 /usr partition - HOG */
+       (*vtoc)->efi_parts[6].p_start = 524322;
+       (*vtoc)->efi_parts[6].p_size = (*vtoc)->efi_last_u_lba - 524322
+           - (1024 * 16);
+
+       /* efi reserved partition - s9 16K */
+       (*vtoc)->efi_parts[8].p_start = (*vtoc)->efi_last_u_lba - (1024 * 16);
+       (*vtoc)->efi_parts[8].p_size = (1024 * 16);
+       (*vtoc)->efi_parts[8].p_tag = V_RESERVED;
+       return (0);
+}
diff --git a/zfs/lib/libicp/Makefile.am b/zfs/lib/libicp/Makefile.am
new file mode 100644 (file)
index 0000000..0852a58
--- /dev/null
@@ -0,0 +1,85 @@
+include $(top_srcdir)/config/Rules.am
+
+VPATH = \
+       $(top_srcdir)/module/icp \
+       $(top_srcdir)/lib/libicp
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/module/icp/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+noinst_LTLIBRARIES = libicp.la
+
+if TARGET_ASM_X86_64
+ASM_SOURCES_C = asm-x86_64/aes/aeskey.c
+ASM_SOURCES_AS = \
+       asm-x86_64/aes/aes_amd64.S \
+       asm-x86_64/aes/aes_intel.S \
+       asm-x86_64/modes/gcm_intel.S \
+       asm-x86_64/sha1/sha1-x86_64.S \
+       asm-x86_64/sha2/sha256_impl.S \
+       asm-x86_64/sha2/sha512_impl.S
+endif
+
+if TARGET_ASM_I386
+ASM_SOURCES_C =
+ASM_SOURCES_AS =
+endif
+       
+if TARGET_ASM_GENERIC
+ASM_SOURCES_C =
+ASM_SOURCES_AS =
+endif
+
+USER_C =
+
+USER_ASM =
+
+KERNEL_C = \
+       spi/kcf_spi.c \
+       api/kcf_ctxops.c \
+       api/kcf_digest.c \
+       api/kcf_cipher.c \
+       api/kcf_miscapi.c \
+       api/kcf_mac.c \
+       algs/aes/aes_impl.c \
+       algs/aes/aes_modes.c \
+       algs/edonr/edonr.c \
+       algs/modes/modes.c \
+       algs/modes/cbc.c \
+       algs/modes/gcm.c \
+       algs/modes/ctr.c \
+       algs/modes/ccm.c \
+       algs/modes/ecb.c \
+       algs/sha1/sha1.c \
+       algs/sha2/sha2.c \
+       algs/skein/skein.c \
+       algs/skein/skein_block.c \
+       algs/skein/skein_iv.c \
+       illumos-crypto.c \
+       io/aes.c \
+       io/edonr_mod.c \
+       io/sha1_mod.c \
+       io/sha2_mod.c \
+       io/skein_mod.c \
+       os/modhash.c \
+       os/modconf.c \
+       core/kcf_sched.c \
+       core/kcf_prov_lib.c \
+       core/kcf_callprov.c \
+       core/kcf_mech_tabs.c \
+       core/kcf_prov_tabs.c \
+       $(ASM_SOURCES_C)
+
+KERNEL_ASM = $(ASM_SOURCES_AS)
+
+nodist_libicp_la_SOURCES = \
+       $(USER_C) \
+       $(USER_ASM) \
+       $(KERNEL_C) \
+       $(KERNEL_ASM)
+       
+libicp_la_LIBADD = -lrt
diff --git a/zfs/lib/libnvpair/Makefile.am b/zfs/lib/libnvpair/Makefile.am
new file mode 100644 (file)
index 0000000..2833557
--- /dev/null
@@ -0,0 +1,33 @@
+include $(top_srcdir)/config/Rules.am
+
+VPATH = \
+       $(top_srcdir)/module/nvpair \
+       $(top_srcdir)/lib/libnvpair
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN) $(LIBTIRPC_CFLAGS)
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+lib_LTLIBRARIES = libnvpair.la
+
+USER_C = \
+       libnvpair.c \
+       nvpair_alloc_system.c
+
+KERNEL_C = \
+       nvpair_alloc_fixed.c \
+       nvpair.c \
+       fnvpair.c
+
+nodist_libnvpair_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+libnvpair_la_LIBADD = \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(LIBTIRPC)
+libnvpair_la_LDFLAGS = -version-info 1:1:0
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libnvpair/Makefile.in b/zfs/lib/libnvpair/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libnvpair/libnvpair.c b/zfs/lib/libnvpair/libnvpair.c
new file mode 100644 (file)
index 0000000..b852cb6
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+ * 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 (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ */
+
+#include <unistd.h>
+#include <strings.h>
+#include <libintl.h>
+#include <sys/types.h>
+#include <sys/inttypes.h>
+#include <stdarg.h>
+#include <note.h>
+#include "libnvpair.h"
+
+/*
+ * libnvpair - A tools library for manipulating <name, value> pairs.
+ *
+ *     This library provides routines packing an unpacking nv pairs
+ *     for transporting data across process boundaries, transporting
+ *     between kernel and userland, and possibly saving onto disk files.
+ */
+
+/*
+ * Print control structure.
+ */
+
+#define        DEFINEOP(opname, vtype) \
+       struct { \
+               int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
+                   const char *, vtype); \
+               void *arg; \
+       } opname
+
+#define        DEFINEARROP(opname, vtype) \
+       struct { \
+               int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
+                   const char *, vtype, uint_t); \
+               void *arg; \
+       } opname
+
+struct nvlist_printops {
+       DEFINEOP(print_boolean, int);
+       DEFINEOP(print_boolean_value, boolean_t);
+       DEFINEOP(print_byte, uchar_t);
+       DEFINEOP(print_int8, int8_t);
+       DEFINEOP(print_uint8, uint8_t);
+       DEFINEOP(print_int16, int16_t);
+       DEFINEOP(print_uint16, uint16_t);
+       DEFINEOP(print_int32, int32_t);
+       DEFINEOP(print_uint32, uint32_t);
+       DEFINEOP(print_int64, int64_t);
+       DEFINEOP(print_uint64, uint64_t);
+       DEFINEOP(print_double, double);
+       DEFINEOP(print_string, char *);
+       DEFINEOP(print_hrtime, hrtime_t);
+       DEFINEOP(print_nvlist, nvlist_t *);
+       DEFINEARROP(print_boolean_array, boolean_t *);
+       DEFINEARROP(print_byte_array, uchar_t *);
+       DEFINEARROP(print_int8_array, int8_t *);
+       DEFINEARROP(print_uint8_array, uint8_t *);
+       DEFINEARROP(print_int16_array, int16_t *);
+       DEFINEARROP(print_uint16_array, uint16_t *);
+       DEFINEARROP(print_int32_array, int32_t *);
+       DEFINEARROP(print_uint32_array, uint32_t *);
+       DEFINEARROP(print_int64_array, int64_t *);
+       DEFINEARROP(print_uint64_array, uint64_t *);
+       DEFINEARROP(print_string_array, char **);
+       DEFINEARROP(print_nvlist_array, nvlist_t **);
+};
+
+struct nvlist_prtctl {
+       FILE *nvprt_fp;                 /* output destination */
+       enum nvlist_indent_mode nvprt_indent_mode; /* see above */
+       int nvprt_indent;               /* absolute indent, or tab depth */
+       int nvprt_indentinc;            /* indent or tab increment */
+       const char *nvprt_nmfmt;        /* member name format, max one %s */
+       const char *nvprt_eomfmt;       /* after member format, e.g. "\n" */
+       const char *nvprt_btwnarrfmt;   /* between array members */
+       int nvprt_btwnarrfmt_nl;        /* nvprt_eoamfmt includes newline? */
+       struct nvlist_printops *nvprt_dfltops;
+       struct nvlist_printops *nvprt_custops;
+};
+
+#define        DFLTPRTOP(pctl, type) \
+       ((pctl)->nvprt_dfltops->print_##type.op)
+
+#define        DFLTPRTOPARG(pctl, type) \
+       ((pctl)->nvprt_dfltops->print_##type.arg)
+
+#define        CUSTPRTOP(pctl, type) \
+       ((pctl)->nvprt_custops->print_##type.op)
+
+#define        CUSTPRTOPARG(pctl, type) \
+       ((pctl)->nvprt_custops->print_##type.arg)
+
+#define        RENDER(pctl, type, nvl, name, val) \
+       { \
+               int done = 0; \
+               if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
+                       done = CUSTPRTOP(pctl, type)(pctl, \
+                           CUSTPRTOPARG(pctl, type), nvl, name, val); \
+               } \
+               if (!done) { \
+                       (void) DFLTPRTOP(pctl, type)(pctl, \
+                           DFLTPRTOPARG(pctl, type), nvl, name, val); \
+               } \
+               (void) fprintf(pctl->nvprt_fp, "%s", pctl->nvprt_eomfmt); \
+       }
+
+#define        ARENDER(pctl, type, nvl, name, arrp, count) \
+       { \
+               int done = 0; \
+               if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
+                       done = CUSTPRTOP(pctl, type)(pctl, \
+                           CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \
+               } \
+               if (!done) { \
+                       (void) DFLTPRTOP(pctl, type)(pctl, \
+                           DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \
+               } \
+               (void) fprintf(pctl->nvprt_fp, "%s", pctl->nvprt_eomfmt); \
+       }
+
+static void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t);
+
+/*
+ * ======================================================================
+ * |                                                                   |
+ * | Indentation                                                       |
+ * |                                                                   |
+ * ======================================================================
+ */
+
+static void
+indent(nvlist_prtctl_t pctl, int onemore)
+{
+       int depth;
+
+       switch (pctl->nvprt_indent_mode) {
+       case NVLIST_INDENT_ABS:
+               (void) fprintf(pctl->nvprt_fp, "%*s",
+                   pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, "");
+               break;
+
+       case NVLIST_INDENT_TABBED:
+               depth = pctl->nvprt_indent + onemore;
+               while (depth-- > 0)
+                       (void) fprintf(pctl->nvprt_fp, "\t");
+       }
+}
+
+/*
+ * ======================================================================
+ * |                                                                   |
+ * | Default nvlist member rendering functions.                                |
+ * |                                                                   |
+ * ======================================================================
+ */
+
+/*
+ * Generate functions to print single-valued nvlist members.
+ *
+ * type_and_variant - suffix to form function name
+ * vtype - C type for the member value
+ * ptype - C type to cast value to for printing
+ * vfmt - format string for pair value, e.g "%d" or "0x%llx"
+ */
+
+#define        NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \
+static int \
+nvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
+    nvlist_t *nvl, const char *name, vtype value) \
+{ \
+       FILE *fp = pctl->nvprt_fp; \
+       NOTE(ARGUNUSED(private)) \
+       NOTE(ARGUNUSED(nvl)) \
+       indent(pctl, 1); \
+       (void) fprintf(fp, pctl->nvprt_nmfmt, name); \
+       (void) fprintf(fp, vfmt, (ptype)value); \
+       return (1); \
+}
+
+NVLIST_PRTFUNC(boolean, int, int, "%d")
+NVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d")
+NVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x")
+NVLIST_PRTFUNC(int8, int8_t, int, "%d")
+NVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x")
+NVLIST_PRTFUNC(int16, int16_t, int16_t, "%d")
+NVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x")
+NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d")
+NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")
+NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")
+NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")
+NVLIST_PRTFUNC(double, double, double, "0x%f")
+NVLIST_PRTFUNC(string, char *, char *, "%s")
+NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")
+
+/*
+ * Generate functions to print array-valued nvlist members.
+ */
+
+#define        NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \
+static int \
+nvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
+    nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \
+{ \
+       FILE *fp = pctl->nvprt_fp; \
+       uint_t i; \
+       NOTE(ARGUNUSED(private)) \
+       NOTE(ARGUNUSED(nvl)) \
+       for (i = 0; i < count; i++) { \
+               if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \
+                       indent(pctl, 1); \
+                       (void) fprintf(fp, pctl->nvprt_nmfmt, name); \
+                       if (pctl->nvprt_btwnarrfmt_nl) \
+                               (void) fprintf(fp, "[%d]: ", i); \
+               } \
+               if (i != 0) \
+                       (void) fprintf(fp, "%s", pctl->nvprt_btwnarrfmt); \
+               (void) fprintf(fp, vfmt, (ptype)valuep[i]); \
+       } \
+       return (1); \
+}
+
+NVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d")
+NVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x")
+NVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d")
+NVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x")
+NVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d")
+NVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x")
+NVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d")
+NVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x")
+NVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld")
+NVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx")
+NVLIST_ARRPRTFUNC(string_array, char *, char *, "%s")
+
+/*ARGSUSED*/
+static int
+nvprint_nvlist(nvlist_prtctl_t pctl, void *private,
+    nvlist_t *nvl, const char *name, nvlist_t *value)
+{
+       FILE *fp = pctl->nvprt_fp;
+
+       indent(pctl, 1);
+       (void) fprintf(fp, "%s = (embedded nvlist)\n", name);
+
+       pctl->nvprt_indent += pctl->nvprt_indentinc;
+       nvlist_print_with_indent(value, pctl);
+       pctl->nvprt_indent -= pctl->nvprt_indentinc;
+
+       indent(pctl, 1);
+       (void) fprintf(fp, "(end %s)\n", name);
+
+       return (1);
+}
+
+/*ARGSUSED*/
+static int
+nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private,
+    nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count)
+{
+       FILE *fp = pctl->nvprt_fp;
+       uint_t i;
+
+       indent(pctl, 1);
+       (void) fprintf(fp, "%s = (array of embedded nvlists)\n", name);
+
+       for (i = 0; i < count; i++) {
+               indent(pctl, 1);
+               (void) fprintf(fp, "(start %s[%d])\n", name, i);
+
+               pctl->nvprt_indent += pctl->nvprt_indentinc;
+               nvlist_print_with_indent(valuep[i], pctl);
+               pctl->nvprt_indent -= pctl->nvprt_indentinc;
+
+               indent(pctl, 1);
+               (void) fprintf(fp, "(end %s[%d])\n", name, i);
+       }
+
+       return (1);
+}
+
+/*
+ * ======================================================================
+ * |                                                                   |
+ * | Interfaces that allow control over formatting.                    |
+ * |                                                                   |
+ * ======================================================================
+ */
+
+void
+nvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp)
+{
+       pctl->nvprt_fp = fp;
+}
+
+FILE *
+nvlist_prtctl_getdest(nvlist_prtctl_t pctl)
+{
+       return (pctl->nvprt_fp);
+}
+
+
+void
+nvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode,
+    int start, int inc)
+{
+       if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED)
+               mode = NVLIST_INDENT_TABBED;
+
+       if (start < 0)
+               start = 0;
+
+       if (inc < 0)
+               inc = 1;
+
+       pctl->nvprt_indent_mode = mode;
+       pctl->nvprt_indent = start;
+       pctl->nvprt_indentinc = inc;
+}
+
+void
+nvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore)
+{
+       indent(pctl, onemore);
+}
+
+
+void
+nvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which,
+    const char *fmt)
+{
+       switch (which) {
+       case NVLIST_FMT_MEMBER_NAME:
+               if (fmt == NULL)
+                       fmt = "%s = ";
+               pctl->nvprt_nmfmt = fmt;
+               break;
+
+       case NVLIST_FMT_MEMBER_POSTAMBLE:
+               if (fmt == NULL)
+                       fmt = "\n";
+               pctl->nvprt_eomfmt = fmt;
+               break;
+
+       case NVLIST_FMT_BTWN_ARRAY:
+               if (fmt == NULL) {
+                       pctl->nvprt_btwnarrfmt = " ";
+                       pctl->nvprt_btwnarrfmt_nl = 0;
+               } else {
+                       pctl->nvprt_btwnarrfmt = fmt;
+                       pctl->nvprt_btwnarrfmt_nl = (strstr(fmt, "\n") != NULL);
+               }
+               break;
+
+       default:
+               break;
+       }
+}
+
+
+void
+nvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...)
+{
+       FILE *fp = pctl->nvprt_fp;
+       va_list ap;
+       char *name;
+
+       va_start(ap, which);
+
+       switch (which) {
+       case NVLIST_FMT_MEMBER_NAME:
+               name = va_arg(ap, char *);
+               (void) fprintf(fp, pctl->nvprt_nmfmt, name);
+               break;
+
+       case NVLIST_FMT_MEMBER_POSTAMBLE:
+               (void) fprintf(fp, "%s", pctl->nvprt_eomfmt);
+               break;
+
+       case NVLIST_FMT_BTWN_ARRAY:
+               (void) fprintf(fp, "%s", pctl->nvprt_btwnarrfmt);
+               break;
+
+       default:
+               break;
+       }
+
+       va_end(ap);
+}
+
+/*
+ * ======================================================================
+ * |                                                                   |
+ * | Interfaces to allow appointment of replacement rendering functions.|
+ * |                                                                   |
+ * ======================================================================
+ */
+
+#define        NVLIST_PRINTCTL_REPLACE(type, vtype) \
+void \
+nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
+    int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \
+    void *private) \
+{ \
+       CUSTPRTOP(pctl, type) = func; \
+       CUSTPRTOPARG(pctl, type) = private; \
+}
+
+NVLIST_PRINTCTL_REPLACE(boolean, int)
+NVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t)
+NVLIST_PRINTCTL_REPLACE(byte, uchar_t)
+NVLIST_PRINTCTL_REPLACE(int8, int8_t)
+NVLIST_PRINTCTL_REPLACE(uint8, uint8_t)
+NVLIST_PRINTCTL_REPLACE(int16, int16_t)
+NVLIST_PRINTCTL_REPLACE(uint16, uint16_t)
+NVLIST_PRINTCTL_REPLACE(int32, int32_t)
+NVLIST_PRINTCTL_REPLACE(uint32, uint32_t)
+NVLIST_PRINTCTL_REPLACE(int64, int64_t)
+NVLIST_PRINTCTL_REPLACE(uint64, uint64_t)
+NVLIST_PRINTCTL_REPLACE(double, double)
+NVLIST_PRINTCTL_REPLACE(string, char *)
+NVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t)
+NVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *)
+
+#define        NVLIST_PRINTCTL_AREPLACE(type, vtype) \
+void \
+nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
+    int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \
+    uint_t), void *private) \
+{ \
+       CUSTPRTOP(pctl, type) = func; \
+       CUSTPRTOPARG(pctl, type) = private; \
+}
+
+NVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *)
+NVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *)
+NVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *)
+NVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *)
+NVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *)
+NVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *)
+NVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *)
+NVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *)
+NVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *)
+NVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *)
+NVLIST_PRINTCTL_AREPLACE(string_array, char **)
+NVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **)
+
+/*
+ * ======================================================================
+ * |                                                                   |
+ * | Interfaces to manage nvlist_prtctl_t cookies.                     |
+ * |                                                                   |
+ * ======================================================================
+ */
+
+
+static const struct nvlist_printops defprtops = {
+       { nvprint_boolean, NULL },
+       { nvprint_boolean_value, NULL },
+       { nvprint_byte, NULL },
+       { nvprint_int8, NULL },
+       { nvprint_uint8, NULL },
+       { nvprint_int16, NULL },
+       { nvprint_uint16, NULL },
+       { nvprint_int32, NULL },
+       { nvprint_uint32, NULL },
+       { nvprint_int64, NULL },
+       { nvprint_uint64, NULL },
+       { nvprint_double, NULL },
+       { nvprint_string, NULL },
+       { nvprint_hrtime, NULL },
+       { nvprint_nvlist, NULL },
+       { nvaprint_boolean_array, NULL },
+       { nvaprint_byte_array, NULL },
+       { nvaprint_int8_array, NULL },
+       { nvaprint_uint8_array, NULL },
+       { nvaprint_int16_array, NULL },
+       { nvaprint_uint16_array, NULL },
+       { nvaprint_int32_array, NULL },
+       { nvaprint_uint32_array, NULL },
+       { nvaprint_int64_array, NULL },
+       { nvaprint_uint64_array, NULL },
+       { nvaprint_string_array, NULL },
+       { nvaprint_nvlist_array, NULL },
+};
+
+static void
+prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl,
+    struct nvlist_printops *ops)
+{
+       pctl->nvprt_fp = fp;
+       pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED;
+       pctl->nvprt_indent = 0;
+       pctl->nvprt_indentinc = 1;
+       pctl->nvprt_nmfmt = "%s = ";
+       pctl->nvprt_eomfmt = "\n";
+       pctl->nvprt_btwnarrfmt = " ";
+       pctl->nvprt_btwnarrfmt_nl = 0;
+
+       pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops;
+       pctl->nvprt_custops = ops;
+}
+
+nvlist_prtctl_t
+nvlist_prtctl_alloc(void)
+{
+       struct nvlist_prtctl *pctl;
+       struct nvlist_printops *ops;
+
+       if ((pctl = malloc(sizeof (*pctl))) == NULL)
+               return (NULL);
+
+       if ((ops = calloc(1, sizeof (*ops))) == NULL) {
+               free(pctl);
+               return (NULL);
+       }
+
+       prtctl_defaults(stdout, pctl, ops);
+
+       return (pctl);
+}
+
+void
+nvlist_prtctl_free(nvlist_prtctl_t pctl)
+{
+       if (pctl != NULL) {
+               free(pctl->nvprt_custops);
+               free(pctl);
+       }
+}
+
+/*
+ * ======================================================================
+ * |                                                                   |
+ * | Top-level print request interfaces.                               |
+ * |                                                                   |
+ * ======================================================================
+ */
+
+/*
+ * nvlist_print - Prints elements in an event buffer
+ */
+static void
+nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl)
+{
+       FILE *fp = pctl->nvprt_fp;
+       char *name;
+       uint_t nelem;
+       nvpair_t *nvp;
+
+       if (nvl == NULL)
+               return;
+
+       indent(pctl, 0);
+       (void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
+
+       nvp = nvlist_next_nvpair(nvl, NULL);
+
+       while (nvp) {
+               data_type_t type = nvpair_type(nvp);
+
+               name = nvpair_name(nvp);
+               nelem = 0;
+
+               switch (type) {
+               case DATA_TYPE_BOOLEAN: {
+                       RENDER(pctl, boolean, nvl, name, 1);
+                       break;
+               }
+               case DATA_TYPE_BOOLEAN_VALUE: {
+                       boolean_t val;
+                       (void) nvpair_value_boolean_value(nvp, &val);
+                       RENDER(pctl, boolean_value, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_BYTE: {
+                       uchar_t val;
+                       (void) nvpair_value_byte(nvp, &val);
+                       RENDER(pctl, byte, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_INT8: {
+                       int8_t val;
+                       (void) nvpair_value_int8(nvp, &val);
+                       RENDER(pctl, int8, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_UINT8: {
+                       uint8_t val;
+                       (void) nvpair_value_uint8(nvp, &val);
+                       RENDER(pctl, uint8, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_INT16: {
+                       int16_t val;
+                       (void) nvpair_value_int16(nvp, &val);
+                       RENDER(pctl, int16, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_UINT16: {
+                       uint16_t val;
+                       (void) nvpair_value_uint16(nvp, &val);
+                       RENDER(pctl, uint16, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_INT32: {
+                       int32_t val;
+                       (void) nvpair_value_int32(nvp, &val);
+                       RENDER(pctl, int32, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_UINT32: {
+                       uint32_t val;
+                       (void) nvpair_value_uint32(nvp, &val);
+                       RENDER(pctl, uint32, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_INT64: {
+                       int64_t val;
+                       (void) nvpair_value_int64(nvp, &val);
+                       RENDER(pctl, int64, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_UINT64: {
+                       uint64_t val;
+                       (void) nvpair_value_uint64(nvp, &val);
+                       RENDER(pctl, uint64, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_DOUBLE: {
+                       double val;
+                       (void) nvpair_value_double(nvp, &val);
+                       RENDER(pctl, double, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_STRING: {
+                       char *val;
+                       (void) nvpair_value_string(nvp, &val);
+                       RENDER(pctl, string, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_BOOLEAN_ARRAY: {
+                       boolean_t *val;
+                       (void) nvpair_value_boolean_array(nvp, &val, &nelem);
+                       ARENDER(pctl, boolean_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_BYTE_ARRAY: {
+                       uchar_t *val;
+                       (void) nvpair_value_byte_array(nvp, &val, &nelem);
+                       ARENDER(pctl, byte_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_INT8_ARRAY: {
+                       int8_t *val;
+                       (void) nvpair_value_int8_array(nvp, &val, &nelem);
+                       ARENDER(pctl, int8_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_UINT8_ARRAY: {
+                       uint8_t *val;
+                       (void) nvpair_value_uint8_array(nvp, &val, &nelem);
+                       ARENDER(pctl, uint8_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_INT16_ARRAY: {
+                       int16_t *val;
+                       (void) nvpair_value_int16_array(nvp, &val, &nelem);
+                       ARENDER(pctl, int16_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_UINT16_ARRAY: {
+                       uint16_t *val;
+                       (void) nvpair_value_uint16_array(nvp, &val, &nelem);
+                       ARENDER(pctl, uint16_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_INT32_ARRAY: {
+                       int32_t *val;
+                       (void) nvpair_value_int32_array(nvp, &val, &nelem);
+                       ARENDER(pctl, int32_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_UINT32_ARRAY: {
+                       uint32_t *val;
+                       (void) nvpair_value_uint32_array(nvp, &val, &nelem);
+                       ARENDER(pctl, uint32_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_INT64_ARRAY: {
+                       int64_t *val;
+                       (void) nvpair_value_int64_array(nvp, &val, &nelem);
+                       ARENDER(pctl, int64_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_UINT64_ARRAY: {
+                       uint64_t *val;
+                       (void) nvpair_value_uint64_array(nvp, &val, &nelem);
+                       ARENDER(pctl, uint64_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_STRING_ARRAY: {
+                       char **val;
+                       (void) nvpair_value_string_array(nvp, &val, &nelem);
+                       ARENDER(pctl, string_array, nvl, name, val, nelem);
+                       break;
+               }
+               case DATA_TYPE_HRTIME: {
+                       hrtime_t val;
+                       (void) nvpair_value_hrtime(nvp, &val);
+                       RENDER(pctl, hrtime, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_NVLIST: {
+                       nvlist_t *val;
+                       (void) nvpair_value_nvlist(nvp, &val);
+                       RENDER(pctl, nvlist, nvl, name, val);
+                       break;
+               }
+               case DATA_TYPE_NVLIST_ARRAY: {
+                       nvlist_t **val;
+                       (void) nvpair_value_nvlist_array(nvp, &val, &nelem);
+                       ARENDER(pctl, nvlist_array, nvl, name, val, nelem);
+                       break;
+               }
+               default:
+                       (void) fprintf(fp, " unknown data type (%d)", type);
+                       break;
+               }
+               nvp = nvlist_next_nvpair(nvl, nvp);
+       }
+}
+
+void
+nvlist_print(FILE *fp, nvlist_t *nvl)
+{
+       struct nvlist_prtctl pc;
+
+       prtctl_defaults(fp, &pc, NULL);
+       nvlist_print_with_indent(nvl, &pc);
+}
+
+void
+nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl)
+{
+       nvlist_print_with_indent(nvl, pctl);
+}
+
+#define        NVP(elem, type, vtype, ptype, format) { \
+       vtype   value; \
+\
+       (void) nvpair_value_##type(elem, &value); \
+       (void) printf("%*s%s: " format "\n", indent, "", \
+           nvpair_name(elem), (ptype)value); \
+}
+
+#define        NVPA(elem, type, vtype, ptype, format) { \
+       uint_t  i, count; \
+       vtype   *value;  \
+\
+       (void) nvpair_value_##type(elem, &value, &count); \
+       for (i = 0; i < count; i++) { \
+               (void) printf("%*s%s[%d]: " format "\n", indent, "", \
+                   nvpair_name(elem), i, (ptype)value[i]); \
+       } \
+}
+
+/*
+ * Similar to nvlist_print() but handles arrays slightly differently.
+ */
+void
+dump_nvlist(nvlist_t *list, int indent)
+{
+       nvpair_t        *elem = NULL;
+       boolean_t       bool_value;
+       nvlist_t        *nvlist_value;
+       nvlist_t        **nvlist_array_value;
+       uint_t          i, count;
+
+       if (list == NULL) {
+               return;
+       }
+
+       while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
+               switch (nvpair_type(elem)) {
+               case DATA_TYPE_BOOLEAN:
+                       (void) printf("%*s%s\n", indent, "", nvpair_name(elem));
+                       break;
+
+               case DATA_TYPE_BOOLEAN_VALUE:
+                       (void) nvpair_value_boolean_value(elem, &bool_value);
+                       (void) printf("%*s%s: %s\n", indent, "",
+                           nvpair_name(elem), bool_value ? "true" : "false");
+                       break;
+
+               case DATA_TYPE_BYTE:
+                       NVP(elem, byte, uchar_t, int, "%u");
+                       break;
+
+               case DATA_TYPE_INT8:
+                       NVP(elem, int8, int8_t, int, "%d");
+                       break;
+
+               case DATA_TYPE_UINT8:
+                       NVP(elem, uint8, uint8_t, int, "%u");
+                       break;
+
+               case DATA_TYPE_INT16:
+                       NVP(elem, int16, int16_t, int, "%d");
+                       break;
+
+               case DATA_TYPE_UINT16:
+                       NVP(elem, uint16, uint16_t, int, "%u");
+                       break;
+
+               case DATA_TYPE_INT32:
+                       NVP(elem, int32, int32_t, long, "%ld");
+                       break;
+
+               case DATA_TYPE_UINT32:
+                       NVP(elem, uint32, uint32_t, ulong_t, "%lu");
+                       break;
+
+               case DATA_TYPE_INT64:
+                       NVP(elem, int64, int64_t, longlong_t, "%lld");
+                       break;
+
+               case DATA_TYPE_UINT64:
+                       NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
+                       break;
+
+               case DATA_TYPE_STRING:
+                       NVP(elem, string, char *, char *, "'%s'");
+                       break;
+
+               case DATA_TYPE_BYTE_ARRAY:
+                       NVPA(elem, byte_array, uchar_t, int, "%u");
+                       break;
+
+               case DATA_TYPE_INT8_ARRAY:
+                       NVPA(elem, int8_array, int8_t, int, "%d");
+                       break;
+
+               case DATA_TYPE_UINT8_ARRAY:
+                       NVPA(elem, uint8_array, uint8_t, int, "%u");
+                       break;
+
+               case DATA_TYPE_INT16_ARRAY:
+                       NVPA(elem, int16_array, int16_t, int, "%d");
+                       break;
+
+               case DATA_TYPE_UINT16_ARRAY:
+                       NVPA(elem, uint16_array, uint16_t, int, "%u");
+                       break;
+
+               case DATA_TYPE_INT32_ARRAY:
+                       NVPA(elem, int32_array, int32_t, long, "%ld");
+                       break;
+
+               case DATA_TYPE_UINT32_ARRAY:
+                       NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
+                       break;
+
+               case DATA_TYPE_INT64_ARRAY:
+                       NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
+                       break;
+
+               case DATA_TYPE_UINT64_ARRAY:
+                       NVPA(elem, uint64_array, uint64_t, u_longlong_t,
+                           "%llu");
+                       break;
+
+               case DATA_TYPE_STRING_ARRAY:
+                       NVPA(elem, string_array, char *, char *, "'%s'");
+                       break;
+
+               case DATA_TYPE_NVLIST:
+                       (void) nvpair_value_nvlist(elem, &nvlist_value);
+                       (void) printf("%*s%s:\n", indent, "",
+                           nvpair_name(elem));
+                       dump_nvlist(nvlist_value, indent + 4);
+                       break;
+
+               case DATA_TYPE_NVLIST_ARRAY:
+                       (void) nvpair_value_nvlist_array(elem,
+                           &nvlist_array_value, &count);
+                       for (i = 0; i < count; i++) {
+                               (void) printf("%*s%s[%u]:\n", indent, "",
+                                   nvpair_name(elem), i);
+                               dump_nvlist(nvlist_array_value[i], indent + 4);
+                       }
+                       break;
+
+               default:
+                       (void) printf(dgettext(TEXT_DOMAIN, "bad config type "
+                           "%d for %s\n"), nvpair_type(elem),
+                           nvpair_name(elem));
+               }
+       }
+}
+
+/*
+ * ======================================================================
+ * |                                                                   |
+ * | Misc private interface.                                           |
+ * |                                                                   |
+ * ======================================================================
+ */
+
+/*
+ * Determine if string 'value' matches 'nvp' value.  The 'value' string is
+ * converted, depending on the type of 'nvp', prior to match.  For numeric
+ * types, a radix independent sscanf conversion of 'value' is used. If 'nvp'
+ * is an array type, 'ai' is the index into the array against which we are
+ * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass
+ * in a regex_t compilation of value in 'value_regex' to trigger regular
+ * expression string match instead of simple strcmp().
+ *
+ * Return 1 on match, 0 on no-match, and -1 on error.  If the error is
+ * related to value syntax error and 'ep' is non-NULL, *ep will point into
+ * the 'value' string at the location where the error exists.
+ *
+ * NOTE: It may be possible to move the non-regex_t version of this into
+ * common code used by library/kernel/boot.
+ */
+int
+nvpair_value_match_regex(nvpair_t *nvp, int ai,
+    char *value, regex_t *value_regex, char **ep)
+{
+       char    *evalue;
+       uint_t  a_len;
+       int     sr;
+
+       if (ep)
+               *ep = NULL;
+
+       if ((nvp == NULL) || (value == NULL))
+               return (-1);            /* error fail match - invalid args */
+
+       /* make sure array and index combination make sense */
+       if ((nvpair_type_is_array(nvp) && (ai < 0)) ||
+           (!nvpair_type_is_array(nvp) && (ai >= 0)))
+               return (-1);            /* error fail match - bad index */
+
+       /* non-string values should be single 'chunk' */
+       if ((nvpair_type(nvp) != DATA_TYPE_STRING) &&
+           (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) {
+               value += strspn(value, " \t");
+               evalue = value + strcspn(value, " \t");
+               if (*evalue) {
+                       if (ep)
+                               *ep = evalue;
+                       return (-1);    /* error fail match - syntax */
+               }
+       }
+
+       sr = EOF;
+       switch (nvpair_type(nvp)) {
+       case DATA_TYPE_STRING: {
+               char    *val;
+
+               /* check string value for match */
+               if (nvpair_value_string(nvp, &val) == 0) {
+                       if (value_regex) {
+                               if (regexec(value_regex, val,
+                                   (size_t)0, NULL, 0) == 0)
+                                       return (1);     /* match */
+                       } else {
+                               if (strcmp(value, val) == 0)
+                                       return (1);     /* match */
+                       }
+               }
+               break;
+       }
+       case DATA_TYPE_STRING_ARRAY: {
+               char **val_array;
+
+               /* check indexed string value of array for match */
+               if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len)) {
+                       if (value_regex) {
+                               if (regexec(value_regex, val_array[ai],
+                                   (size_t)0, NULL, 0) == 0)
+                                       return (1);
+                       } else {
+                               if (strcmp(value, val_array[ai]) == 0)
+                                       return (1);
+                       }
+               }
+               break;
+       }
+       case DATA_TYPE_BYTE: {
+               uchar_t val, val_arg;
+
+               /* scanf uchar_t from value and check for match */
+               sr = sscanf(value, "%c", &val_arg);
+               if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_BYTE_ARRAY: {
+               uchar_t *val_array, val_arg;
+
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%c", &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_INT8: {
+               int8_t val, val_arg;
+
+               /* scanf int8_t from value and check for match */
+               sr = sscanf(value, "%"SCNi8, &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_int8(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_INT8_ARRAY: {
+               int8_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi8, &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_UINT8: {
+               uint8_t val, val_arg;
+
+               /* scanf uint8_t from value and check for match */
+               sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_uint8(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_UINT8_ARRAY: {
+               uint8_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_INT16: {
+               int16_t val, val_arg;
+
+               /* scanf int16_t from value and check for match */
+               sr = sscanf(value, "%"SCNi16, &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_int16(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_INT16_ARRAY: {
+               int16_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi16, &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_UINT16: {
+               uint16_t val, val_arg;
+
+               /* scanf uint16_t from value and check for match */
+               sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_uint16(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_UINT16_ARRAY: {
+               uint16_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_INT32: {
+               int32_t val, val_arg;
+
+               /* scanf int32_t from value and check for match */
+               sr = sscanf(value, "%"SCNi32, &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_int32(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_INT32_ARRAY: {
+               int32_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi32, &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_UINT32: {
+               uint32_t val, val_arg;
+
+               /* scanf uint32_t from value and check for match */
+               sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_uint32(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_UINT32_ARRAY: {
+               uint32_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_INT64: {
+               int64_t val, val_arg;
+
+               /* scanf int64_t from value and check for match */
+               sr = sscanf(value, "%"SCNi64, &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_int64(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_INT64_ARRAY: {
+               int64_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi64, &val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                               return (1);
+               break;
+       }
+       case DATA_TYPE_UINT64: {
+               uint64_t val_arg, val;
+
+               /* scanf uint64_t from value and check for match */
+               sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_uint64(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_UINT64_ARRAY: {
+               uint64_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_BOOLEAN_VALUE: {
+               boolean_t val, val_arg;
+
+               /* scanf boolean_t from value and check for match */
+               sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_boolean_value(nvp, &val) == 0) &&
+                   (val == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_BOOLEAN_ARRAY: {
+               boolean_t *val_array, val_arg;
+
+               /* check indexed value of array for match */
+               sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
+               if ((sr == 1) &&
+                   (nvpair_value_boolean_array(nvp,
+                   &val_array, &a_len) == 0) &&
+                   (ai < a_len) &&
+                   (val_array[ai] == val_arg))
+                       return (1);
+               break;
+       }
+       case DATA_TYPE_HRTIME:
+       case DATA_TYPE_NVLIST:
+       case DATA_TYPE_NVLIST_ARRAY:
+       case DATA_TYPE_BOOLEAN:
+       case DATA_TYPE_DOUBLE:
+       case DATA_TYPE_UNKNOWN:
+       default:
+               /*
+                * unknown/unsupported data type
+                */
+               return (-1);            /* error fail match */
+       }
+
+       /*
+        * check to see if sscanf failed conversion, return approximate
+        * pointer to problem
+        */
+       if (sr != 1) {
+               if (ep)
+                       *ep = value;
+               return (-1);            /* error fail match  - syntax */
+       }
+
+       return (0);                     /* fail match */
+}
+
+int
+nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep)
+{
+       return (nvpair_value_match_regex(nvp, ai, value, NULL, ep));
+}
diff --git a/zfs/lib/libnvpair/nvpair_alloc_system.c b/zfs/lib/libnvpair/nvpair_alloc_system.c
new file mode 100644 (file)
index 0000000..54dde1e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+#include <rpc/types.h>
+#include <sys/kmem.h>
+#include <sys/nvpair.h>
+
+static void *
+nv_alloc_sys(nv_alloc_t *nva, size_t size)
+{
+       return (kmem_alloc(size, (int)(uintptr_t)nva->nva_arg));
+}
+
+/*ARGSUSED*/
+static void
+nv_free_sys(nv_alloc_t *nva, void *buf, size_t size)
+{
+       kmem_free(buf, size);
+}
+
+static const nv_alloc_ops_t system_ops = {
+       NULL,                   /* nv_ao_init() */
+       NULL,                   /* nv_ao_fini() */
+       nv_alloc_sys,           /* nv_ao_alloc() */
+       nv_free_sys,            /* nv_ao_free() */
+       NULL                    /* nv_ao_reset() */
+};
+
+nv_alloc_t nv_alloc_sleep_def = {
+       &system_ops,
+       (void *)KM_SLEEP
+};
+
+nv_alloc_t nv_alloc_nosleep_def = {
+       &system_ops,
+       (void *)KM_NOSLEEP
+};
+
+nv_alloc_t *nv_alloc_sleep = &nv_alloc_sleep_def;
+nv_alloc_t *nv_alloc_nosleep = &nv_alloc_nosleep_def;
diff --git a/zfs/lib/libshare/Makefile.am b/zfs/lib/libshare/Makefile.am
new file mode 100644 (file)
index 0000000..42bd207
--- /dev/null
@@ -0,0 +1,23 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+noinst_LTLIBRARIES = libshare.la
+
+USER_C = \
+       libshare_impl.h \
+       libshare.c \
+       nfs.c \
+       nfs.h \
+       smb.c \
+       smb.h
+
+KERNEL_C =
+
+nodist_libshare_la_SOURCES = \
+       $(USER_C)
+       $(KERNEL_C)
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libshare/Makefile.in b/zfs/lib/libshare/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libshare/libshare.c b/zfs/lib/libshare/libshare.c
new file mode 100644 (file)
index 0000000..89a4fe9
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+ * 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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Gunnar Beutner
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <libintl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libzfs.h>
+#include <libshare.h>
+#include "libshare_impl.h"
+#include "nfs.h"
+#include "smb.h"
+
+static sa_share_impl_t find_share(sa_handle_impl_t handle,
+    const char *sharepath);
+static sa_share_impl_t alloc_share(const char *sharepath);
+static void free_share(sa_share_impl_t share);
+
+static void parse_sharetab(sa_handle_impl_t impl_handle);
+static int process_share(sa_handle_impl_t impl_handle,
+    sa_share_impl_t impl_share, char *pathname, char *resource,
+    char *fstype, char *options, char *description,
+    char *dataset, boolean_t from_sharetab);
+static void update_sharetab(sa_handle_impl_t impl_handle);
+
+static int update_zfs_share(sa_share_impl_t impl_handle, const char *proto);
+static int update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto);
+
+static int fstypes_count;
+static sa_fstype_t *fstypes;
+
+sa_fstype_t *
+register_fstype(const char *name, const sa_share_ops_t *ops)
+{
+       sa_fstype_t *fstype;
+
+       fstype = calloc(sizeof (sa_fstype_t), 1);
+
+       if (fstype == NULL)
+               return (NULL);
+
+       fstype->name = name;
+       fstype->ops = ops;
+       fstype->fsinfo_index = fstypes_count;
+
+       fstypes_count++;
+
+       fstype->next = fstypes;
+       fstypes = fstype;
+
+       return (fstype);
+}
+
+sa_handle_t
+sa_init(int init_service)
+{
+       sa_handle_impl_t impl_handle;
+
+       impl_handle = calloc(sizeof (struct sa_handle_impl), 1);
+
+       if (impl_handle == NULL)
+               return (NULL);
+
+       impl_handle->zfs_libhandle = libzfs_init();
+
+       if (impl_handle->zfs_libhandle != NULL) {
+               libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
+       }
+
+       parse_sharetab(impl_handle);
+       update_zfs_shares(impl_handle, NULL);
+
+       return ((sa_handle_t)impl_handle);
+}
+
+__attribute__((constructor)) static void
+libshare_init(void)
+{
+       libshare_nfs_init();
+       libshare_smb_init();
+}
+
+static void
+parse_sharetab(sa_handle_impl_t impl_handle) {
+       FILE *fp;
+       char line[512];
+       char *eol, *pathname, *resource, *fstype, *options, *description;
+
+       fp = fopen("/etc/dfs/sharetab", "r");
+
+       if (fp == NULL)
+               return;
+
+       while (fgets(line, sizeof (line), fp) != NULL) {
+               eol = line + strlen(line) - 1;
+
+               while (eol >= line) {
+                       if (*eol != '\r' && *eol != '\n')
+                               break;
+
+                       *eol = '\0';
+                       eol--;
+               }
+
+               pathname = line;
+
+               if ((resource = strchr(pathname, '\t')) == NULL)
+                       continue;
+
+               *resource = '\0';
+               resource++;
+
+               if ((fstype = strchr(resource, '\t')) == NULL)
+                       continue;
+
+               *fstype = '\0';
+               fstype++;
+
+               if ((options = strchr(fstype, '\t')) == NULL)
+                       continue;
+
+               *options = '\0';
+               options++;
+
+               if ((description = strchr(fstype, '\t')) != NULL) {
+                       *description = '\0';
+                       description++;
+               }
+
+               if (strcmp(resource, "-") == 0)
+                       resource = NULL;
+
+               (void) process_share(impl_handle, NULL, pathname, resource,
+                   fstype, options, description, NULL, B_TRUE);
+       }
+
+       fclose(fp);
+}
+
+static void
+update_sharetab(sa_handle_impl_t impl_handle)
+{
+       sa_share_impl_t impl_share;
+       int temp_fd;
+       FILE *temp_fp;
+       char tempfile[] = "/etc/dfs/sharetab.XXXXXX";
+       sa_fstype_t *fstype;
+       const char *resource;
+
+       if (mkdir("/etc/dfs", 0755) < 0 && errno != EEXIST) {
+               return;
+       }
+
+       temp_fd = mkstemp(tempfile);
+
+       if (temp_fd < 0)
+               return;
+
+       temp_fp = fdopen(temp_fd, "w");
+
+       if (temp_fp == NULL)
+               return;
+
+       impl_share = impl_handle->shares;
+       while (impl_share != NULL) {
+               fstype = fstypes;
+               while (fstype != NULL) {
+                       if (FSINFO(impl_share, fstype)->active &&
+                           FSINFO(impl_share, fstype)->shareopts != NULL) {
+                               resource = FSINFO(impl_share, fstype)->resource;
+
+                               if (resource == NULL)
+                                       resource = "-";
+
+                               fprintf(temp_fp, "%s\t%s\t%s\t%s\n",
+                                   impl_share->sharepath, resource,
+                                   fstype->name,
+                                   FSINFO(impl_share, fstype)->shareopts);
+                       }
+
+                       fstype = fstype->next;
+               }
+
+               impl_share = impl_share->next;
+       }
+
+       fflush(temp_fp);
+       fsync(temp_fd);
+       fclose(temp_fp);
+
+       (void) rename(tempfile, "/etc/dfs/sharetab");
+}
+
+typedef struct update_cookie_s {
+       sa_handle_impl_t handle;
+       const char *proto;
+} update_cookie_t;
+
+static int
+update_zfs_shares_cb(zfs_handle_t *zhp, void *pcookie)
+{
+       update_cookie_t *udata = (update_cookie_t *)pcookie;
+       char mountpoint[ZFS_MAXPROPLEN];
+       char shareopts[ZFS_MAXPROPLEN];
+       char *dataset;
+       zfs_type_t type = zfs_get_type(zhp);
+
+       if (type == ZFS_TYPE_FILESYSTEM &&
+           zfs_iter_filesystems(zhp, update_zfs_shares_cb, pcookie) != 0) {
+               zfs_close(zhp);
+               return (1);
+       }
+
+       if (type != ZFS_TYPE_FILESYSTEM) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
+           sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       dataset = (char *)zfs_get_name(zhp);
+
+       if (dataset == NULL) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if (!zfs_is_mounted(zhp, NULL)) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if ((udata->proto == NULL || strcmp(udata->proto, "nfs") == 0) &&
+           zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts,
+           sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
+           strcmp(shareopts, "off") != 0) {
+               (void) process_share(udata->handle, NULL, mountpoint, NULL,
+                   "nfs", shareopts, NULL, dataset, B_FALSE);
+       }
+
+       if ((udata->proto == NULL || strcmp(udata->proto, "smb") == 0) &&
+           zfs_prop_get(zhp, ZFS_PROP_SHARESMB, shareopts,
+           sizeof (shareopts), NULL, NULL, 0, B_FALSE) == 0 &&
+           strcmp(shareopts, "off") != 0) {
+               (void) process_share(udata->handle, NULL, mountpoint, NULL,
+                   "smb", shareopts, NULL, dataset, B_FALSE);
+       }
+
+       zfs_close(zhp);
+
+       return (0);
+}
+
+static int
+update_zfs_share(sa_share_impl_t impl_share, const char *proto)
+{
+       sa_handle_impl_t impl_handle = impl_share->handle;
+       zfs_handle_t *zhp;
+       update_cookie_t udata;
+
+       if (impl_handle->zfs_libhandle == NULL)
+                       return (SA_SYSTEM_ERR);
+
+       assert(impl_share->dataset != NULL);
+
+       zhp = zfs_open(impl_share->handle->zfs_libhandle, impl_share->dataset,
+           ZFS_TYPE_FILESYSTEM);
+
+       if (zhp == NULL)
+               return (SA_SYSTEM_ERR);
+
+       udata.handle = impl_handle;
+       udata.proto = proto;
+       (void) update_zfs_shares_cb(zhp, &udata);
+
+       return (SA_OK);
+}
+
+static int
+update_zfs_shares(sa_handle_impl_t impl_handle, const char *proto)
+{
+       update_cookie_t udata;
+
+       if (impl_handle->zfs_libhandle == NULL)
+               return (SA_SYSTEM_ERR);
+
+       udata.handle = impl_handle;
+       udata.proto = proto;
+       (void) zfs_iter_root(impl_handle->zfs_libhandle, update_zfs_shares_cb,
+           &udata);
+
+       return (SA_OK);
+}
+
+static int
+process_share(sa_handle_impl_t impl_handle, sa_share_impl_t impl_share,
+    char *pathname, char *resource, char *proto,
+    char *options, char *description, char *dataset,
+    boolean_t from_sharetab)
+{
+       struct stat statbuf;
+       int rc;
+       char *resource_dup = NULL, *dataset_dup = NULL;
+       boolean_t new_share;
+       sa_fstype_t *fstype;
+
+       new_share = B_FALSE;
+
+       if (impl_share == NULL)
+               impl_share = find_share(impl_handle, pathname);
+
+       if (impl_share == NULL) {
+               if (lstat(pathname, &statbuf) != 0 ||
+                   !S_ISDIR(statbuf.st_mode))
+                       return (SA_BAD_PATH);
+
+               impl_share = alloc_share(pathname);
+
+               if (impl_share == NULL) {
+                       rc = SA_NO_MEMORY;
+                       goto err;
+               }
+
+               new_share = B_TRUE;
+       }
+
+       if (dataset != NULL) {
+               dataset_dup = strdup(dataset);
+
+               if (dataset_dup == NULL) {
+                       rc = SA_NO_MEMORY;
+                       goto err;
+               }
+       }
+
+       free(impl_share->dataset);
+       impl_share->dataset = dataset_dup;
+
+       rc = SA_INVALID_PROTOCOL;
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               if (strcmp(fstype->name, proto) == 0) {
+                       if (resource != NULL) {
+                               resource_dup = strdup(resource);
+
+                               if (resource_dup == NULL) {
+                                       rc = SA_NO_MEMORY;
+                                       goto err;
+                               }
+                       }
+
+                       free(FSINFO(impl_share, fstype)->resource);
+                       FSINFO(impl_share, fstype)->resource = resource_dup;
+
+                       rc = fstype->ops->update_shareopts(impl_share,
+                           resource, options);
+
+                       if (rc == SA_OK && from_sharetab)
+                               FSINFO(impl_share, fstype)->active = B_TRUE;
+
+                       break;
+               }
+
+               fstype = fstype->next;
+       }
+
+       if (rc != SA_OK)
+               goto err;
+
+       if (new_share) {
+               impl_share->handle = impl_handle;
+
+               impl_share->next = impl_handle->shares;
+               impl_handle->shares = impl_share;
+
+       }
+
+err:
+       if (rc != SA_OK) {
+               if (new_share)
+                       free_share(impl_share);
+       }
+
+       return (rc);
+}
+
+void
+sa_fini(sa_handle_t handle)
+{
+       sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+       sa_share_impl_t impl_share, next;
+       sa_share_impl_t *pcurr;
+
+       if (impl_handle == NULL)
+               return;
+
+       /*
+        * clean up shares which don't have a non-NULL dataset property,
+        * which means they're in sharetab but we couldn't find their
+        * ZFS dataset.
+        */
+       pcurr = &(impl_handle->shares);
+       impl_share = *pcurr;
+       while (impl_share != NULL) {
+               next = impl_share->next;
+
+               if (impl_share->dataset == NULL) {
+                       /* remove item from the linked list */
+                       *pcurr = next;
+
+                       sa_disable_share(impl_share, NULL);
+
+                       free_share(impl_share);
+               } else {
+                       pcurr = &(impl_share->next);
+               }
+
+               impl_share = next;
+       }
+
+       update_sharetab(impl_handle);
+
+       if (impl_handle->zfs_libhandle != NULL)
+               libzfs_fini(impl_handle->zfs_libhandle);
+
+       impl_share = impl_handle->shares;
+       while (impl_share != NULL) {
+               next = impl_share->next;
+               free_share(impl_share);
+               impl_share = next;
+       }
+
+       free(impl_handle);
+}
+
+static sa_share_impl_t
+find_share(sa_handle_impl_t impl_handle, const char *sharepath)
+{
+       sa_share_impl_t impl_share;
+
+       impl_share = impl_handle->shares;
+       while (impl_share != NULL) {
+               if (strcmp(impl_share->sharepath, sharepath) == 0) {
+                       break;
+               }
+
+               impl_share = impl_share->next;
+       }
+
+       return (impl_share);
+}
+
+sa_share_t
+sa_find_share(sa_handle_t handle, char *sharepath)
+{
+       return ((sa_share_t)find_share((sa_handle_impl_t)handle, sharepath));
+}
+
+int
+sa_enable_share(sa_share_t share, char *protocol)
+{
+       sa_share_impl_t impl_share = (sa_share_impl_t)share;
+       int rc, ret;
+       boolean_t found_protocol;
+       sa_fstype_t *fstype;
+
+#ifdef DEBUG
+       fprintf(stderr, "sa_enable_share: share->sharepath=%s, protocol=%s\n",
+               impl_share->sharepath, protocol);
+#endif
+
+       assert(impl_share->handle != NULL);
+
+       ret = SA_OK;
+       found_protocol = B_FALSE;
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
+                       update_zfs_share(impl_share, fstype->name);
+
+                       rc = fstype->ops->enable_share(impl_share);
+
+                       if (rc != SA_OK)
+                               ret = rc;
+                       else
+                               FSINFO(impl_share, fstype)->active = B_TRUE;
+
+                       found_protocol = B_TRUE;
+               }
+
+               fstype = fstype->next;
+       }
+
+       update_sharetab(impl_share->handle);
+
+       return (found_protocol ? ret : SA_INVALID_PROTOCOL);
+}
+
+int
+sa_disable_share(sa_share_t share, char *protocol)
+{
+       sa_share_impl_t impl_share = (sa_share_impl_t)share;
+       int rc, ret;
+       boolean_t found_protocol;
+       sa_fstype_t *fstype;
+
+#ifdef DEBUG
+       fprintf(stderr, "sa_disable_share: share->sharepath=%s, protocol=%s\n",
+               impl_share->sharepath, protocol);
+#endif
+
+       ret = SA_OK;
+       found_protocol = B_FALSE;
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               if (protocol == NULL || strcmp(fstype->name, protocol) == 0) {
+                       rc = fstype->ops->disable_share(impl_share);
+
+                       if (rc == SA_OK) {
+                               fstype->ops->clear_shareopts(impl_share);
+
+                               FSINFO(impl_share, fstype)->active = B_FALSE;
+                       } else
+                               ret = rc;
+
+                       found_protocol = B_TRUE;
+               }
+
+               fstype = fstype->next;
+       }
+
+       update_sharetab(impl_share->handle);
+
+       return (found_protocol ? ret : SA_INVALID_PROTOCOL);
+}
+
+/*
+ * sa_errorstr(err)
+ *
+ * convert an error value to an error string
+ */
+char *
+sa_errorstr(int err)
+{
+       static char errstr[32];
+       char *ret = NULL;
+
+       switch (err) {
+       case SA_OK:
+               ret = dgettext(TEXT_DOMAIN, "ok");
+               break;
+       case SA_NO_SUCH_PATH:
+               ret = dgettext(TEXT_DOMAIN, "path doesn't exist");
+               break;
+       case SA_NO_MEMORY:
+               ret = dgettext(TEXT_DOMAIN, "no memory");
+               break;
+       case SA_DUPLICATE_NAME:
+               ret = dgettext(TEXT_DOMAIN, "name in use");
+               break;
+       case SA_BAD_PATH:
+               ret = dgettext(TEXT_DOMAIN, "bad path");
+               break;
+       case SA_NO_SUCH_GROUP:
+               ret = dgettext(TEXT_DOMAIN, "no such group");
+               break;
+       case SA_CONFIG_ERR:
+               ret = dgettext(TEXT_DOMAIN, "configuration error");
+               break;
+       case SA_SYSTEM_ERR:
+               ret = dgettext(TEXT_DOMAIN, "system error");
+               break;
+       case SA_SYNTAX_ERR:
+               ret = dgettext(TEXT_DOMAIN, "syntax error");
+               break;
+       case SA_NO_PERMISSION:
+               ret = dgettext(TEXT_DOMAIN, "no permission");
+               break;
+       case SA_BUSY:
+               ret = dgettext(TEXT_DOMAIN, "busy");
+               break;
+       case SA_NO_SUCH_PROP:
+               ret = dgettext(TEXT_DOMAIN, "no such property");
+               break;
+       case SA_INVALID_NAME:
+               ret = dgettext(TEXT_DOMAIN, "invalid name");
+               break;
+       case SA_INVALID_PROTOCOL:
+               ret = dgettext(TEXT_DOMAIN, "invalid protocol");
+               break;
+       case SA_NOT_ALLOWED:
+               ret = dgettext(TEXT_DOMAIN, "operation not allowed");
+               break;
+       case SA_BAD_VALUE:
+               ret = dgettext(TEXT_DOMAIN, "bad property value");
+               break;
+       case SA_INVALID_SECURITY:
+               ret = dgettext(TEXT_DOMAIN, "invalid security type");
+               break;
+       case SA_NO_SUCH_SECURITY:
+               ret = dgettext(TEXT_DOMAIN, "security type not found");
+               break;
+       case SA_VALUE_CONFLICT:
+               ret = dgettext(TEXT_DOMAIN, "property value conflict");
+               break;
+       case SA_NOT_IMPLEMENTED:
+               ret = dgettext(TEXT_DOMAIN, "not implemented");
+               break;
+       case SA_INVALID_PATH:
+               ret = dgettext(TEXT_DOMAIN, "invalid path");
+               break;
+       case SA_NOT_SUPPORTED:
+               ret = dgettext(TEXT_DOMAIN, "operation not supported");
+               break;
+       case SA_PROP_SHARE_ONLY:
+               ret = dgettext(TEXT_DOMAIN, "property not valid for group");
+               break;
+       case SA_NOT_SHARED:
+               ret = dgettext(TEXT_DOMAIN, "not shared");
+               break;
+       case SA_NO_SUCH_RESOURCE:
+               ret = dgettext(TEXT_DOMAIN, "no such resource");
+               break;
+       case SA_RESOURCE_REQUIRED:
+               ret = dgettext(TEXT_DOMAIN, "resource name required");
+               break;
+       case SA_MULTIPLE_ERROR:
+               ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols");
+               break;
+       case SA_PATH_IS_SUBDIR:
+               ret = dgettext(TEXT_DOMAIN, "path is a subpath of share");
+               break;
+       case SA_PATH_IS_PARENTDIR:
+               ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
+               break;
+       case SA_NO_SECTION:
+               ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
+               break;
+       case SA_NO_PROPERTIES:
+               ret = dgettext(TEXT_DOMAIN, "properties not found");
+               break;
+       case SA_NO_SUCH_SECTION:
+               ret = dgettext(TEXT_DOMAIN, "section not found");
+               break;
+       case SA_PASSWORD_ENC:
+               ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
+               break;
+       case SA_SHARE_EXISTS:
+               ret = dgettext(TEXT_DOMAIN, "path or file is already shared");
+               break;
+       default:
+               (void) snprintf(errstr, sizeof (errstr),
+                   dgettext(TEXT_DOMAIN, "unknown %d"), err);
+               ret = errstr;
+       }
+       return (ret);
+}
+
+int
+sa_parse_legacy_options(sa_group_t group, char *options, char *proto)
+{
+       sa_fstype_t *fstype;
+
+#ifdef DEBUG
+       fprintf(stderr, "sa_parse_legacy_options: options=%s, proto=%s\n",
+               options, proto);
+#endif
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               if (strcmp(fstype->name, proto) != 0) {
+                       fstype = fstype->next;
+                       continue;
+               }
+
+               return (fstype->ops->validate_shareopts(options));
+       }
+
+       return (SA_INVALID_PROTOCOL);
+}
+
+boolean_t
+sa_needs_refresh(sa_handle_t handle)
+{
+       return (B_TRUE);
+}
+
+libzfs_handle_t *
+sa_get_zfs_handle(sa_handle_t handle)
+{
+       sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+
+       if (impl_handle == NULL)
+               return (NULL);
+
+       return (impl_handle->zfs_libhandle);
+}
+
+static sa_share_impl_t
+alloc_share(const char *sharepath)
+{
+       sa_share_impl_t impl_share;
+
+       impl_share = calloc(sizeof (struct sa_share_impl), 1);
+
+       if (impl_share == NULL)
+               return (NULL);
+
+       impl_share->sharepath = strdup(sharepath);
+
+       if (impl_share->sharepath == NULL) {
+               free(impl_share);
+               return (NULL);
+       }
+
+       impl_share->fsinfo = calloc(sizeof (sa_share_fsinfo_t), fstypes_count);
+
+       if (impl_share->fsinfo == NULL) {
+               free(impl_share->sharepath);
+               free(impl_share);
+               return (NULL);
+       }
+
+       return (impl_share);
+}
+
+static void
+free_share(sa_share_impl_t impl_share) {
+       sa_fstype_t *fstype;
+
+       fstype = fstypes;
+       while (fstype != NULL) {
+               fstype->ops->clear_shareopts(impl_share);
+
+               free(FSINFO(impl_share, fstype)->resource);
+
+               fstype = fstype->next;
+       }
+
+       free(impl_share->sharepath);
+       free(impl_share->dataset);
+       free(impl_share->fsinfo);
+       free(impl_share);
+}
+
+int
+sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
+    char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
+    char *sourcestr, char *dataset)
+{
+       sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+       sa_share_impl_t impl_share = (sa_share_impl_t)share;
+
+#ifdef DEBUG
+       fprintf(stderr, "sa_zfs_process_share: mountpoint=%s, proto=%s, "
+           "shareopts=%s, sourcestr=%s, dataset=%s\n", mountpoint, proto,
+           shareopts, sourcestr, dataset);
+#endif
+
+       return (process_share(impl_handle, impl_share, mountpoint, NULL,
+           proto, shareopts, NULL, dataset, B_FALSE));
+}
+
+void
+sa_update_sharetab_ts(sa_handle_t handle)
+{
+       sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle;
+
+       update_sharetab(impl_handle);
+}
diff --git a/zfs/lib/libshare/libshare_impl.h b/zfs/lib/libshare/libshare_impl.h
new file mode 100644 (file)
index 0000000..18d619b
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Gunnar Beutner
+ */
+
+struct sa_handle_impl;
+
+typedef struct sa_share_fsinfo {
+       boolean_t active;
+       char *resource;
+       char *shareopts;
+} sa_share_fsinfo_t;
+
+typedef struct sa_share_impl {
+       struct sa_share_impl *next;
+
+       struct sa_handle_impl *handle;
+
+       char *sharepath;
+       char *dataset;
+
+       sa_share_fsinfo_t *fsinfo; /* per-fstype information */
+} *sa_share_impl_t;
+
+#define        FSINFO(impl_share, fstype) (&(impl_share->fsinfo[fstype->fsinfo_index]))
+
+typedef struct sa_share_ops {
+       int (*enable_share)(sa_share_impl_t share);
+       int (*disable_share)(sa_share_impl_t share);
+       int (*validate_shareopts)(const char *shareopts);
+       int (*update_shareopts)(sa_share_impl_t impl_share,
+           const char *resource, const char *shareopts);
+       void (*clear_shareopts)(sa_share_impl_t impl_share);
+} sa_share_ops_t;
+
+typedef struct sa_fstype {
+       struct sa_fstype *next;
+
+       const char *name;
+       const sa_share_ops_t *ops;
+       int fsinfo_index;
+} sa_fstype_t;
+
+typedef struct sa_handle_impl {
+       libzfs_handle_t *zfs_libhandle;
+       sa_share_impl_t shares;
+} *sa_handle_impl_t;
+
+sa_fstype_t *register_fstype(const char *name, const sa_share_ops_t *ops);
diff --git a/zfs/lib/libshare/nfs.c b/zfs/lib/libshare/nfs.c
new file mode 100644 (file)
index 0000000..9d548dc
--- /dev/null
@@ -0,0 +1,743 @@
+/*
+ * 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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Gunnar Beutner
+ * Copyright (c) 2012 Cyril Plisko. All rights reserved.
+ */
+
+#include <stdio.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <libzfs.h>
+#include <libshare.h>
+#include "libshare_impl.h"
+
+static boolean_t nfs_available(void);
+
+static sa_fstype_t *nfs_fstype;
+
+/*
+ * nfs_exportfs_temp_fd refers to a temporary copy of the output
+ * from exportfs -v.
+ */
+static int nfs_exportfs_temp_fd = -1;
+
+typedef int (*nfs_shareopt_callback_t)(const char *opt, const char *value,
+    void *cookie);
+
+typedef int (*nfs_host_callback_t)(const char *sharepath, const char *host,
+    const char *security, const char *access, void *cookie);
+
+/*
+ * Invokes the specified callback function for each Solaris share option
+ * listed in the specified string.
+ */
+static int
+foreach_nfs_shareopt(const char *shareopts,
+    nfs_shareopt_callback_t callback, void *cookie)
+{
+       char *shareopts_dup, *opt, *cur, *value;
+       int was_nul, rc;
+
+       if (shareopts == NULL)
+               return (SA_OK);
+
+       shareopts_dup = strdup(shareopts);
+
+       if (shareopts_dup == NULL)
+               return (SA_NO_MEMORY);
+
+       opt = shareopts_dup;
+       was_nul = 0;
+
+       while (1) {
+               cur = opt;
+
+               while (*cur != ',' && *cur != '\0')
+                       cur++;
+
+               if (*cur == '\0')
+                       was_nul = 1;
+
+               *cur = '\0';
+
+               if (cur > opt) {
+                       value = strchr(opt, '=');
+
+                       if (value != NULL) {
+                               *value = '\0';
+                               value++;
+                       }
+
+                       rc = callback(opt, value, cookie);
+
+                       if (rc != SA_OK) {
+                               free(shareopts_dup);
+                               return (rc);
+                       }
+               }
+
+               opt = cur + 1;
+
+               if (was_nul)
+                       break;
+       }
+
+       free(shareopts_dup);
+
+       return (0);
+}
+
+typedef struct nfs_host_cookie_s {
+       nfs_host_callback_t callback;
+       const char *sharepath;
+       void *cookie;
+       const char *security;
+} nfs_host_cookie_t;
+
+/*
+ * Helper function for foreach_nfs_host. This function checks whether the
+ * current share option is a host specification and invokes a callback
+ * function with information about the host.
+ */
+static int
+foreach_nfs_host_cb(const char *opt, const char *value, void *pcookie)
+{
+       int rc;
+       const char *access;
+       char *host_dup, *host, *next;
+       nfs_host_cookie_t *udata = (nfs_host_cookie_t *)pcookie;
+
+#ifdef DEBUG
+       fprintf(stderr, "foreach_nfs_host_cb: key=%s, value=%s\n", opt, value);
+#endif
+
+       if (strcmp(opt, "sec") == 0)
+               udata->security = value;
+
+       if (strcmp(opt, "rw") == 0 || strcmp(opt, "ro") == 0) {
+               if (value == NULL)
+                       value = "*";
+
+               access = opt;
+
+               host_dup = strdup(value);
+
+               if (host_dup == NULL)
+                       return (SA_NO_MEMORY);
+
+               host = host_dup;
+
+               do {
+                       next = strchr(host, ':');
+                       if (next != NULL) {
+                               *next = '\0';
+                               next++;
+                       }
+
+                       rc = udata->callback(udata->sharepath, host,
+                           udata->security, access, udata->cookie);
+
+                       if (rc != SA_OK) {
+                               free(host_dup);
+
+                               return (rc);
+                       }
+
+                       host = next;
+               } while (host != NULL);
+
+               free(host_dup);
+       }
+
+       return (SA_OK);
+}
+
+/*
+ * Invokes a callback function for all NFS hosts that are set for a share.
+ */
+static int
+foreach_nfs_host(sa_share_impl_t impl_share, nfs_host_callback_t callback,
+    void *cookie)
+{
+       nfs_host_cookie_t udata;
+       char *shareopts;
+
+       udata.callback = callback;
+       udata.sharepath = impl_share->sharepath;
+       udata.cookie = cookie;
+       udata.security = "sys";
+
+       shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
+
+       return foreach_nfs_shareopt(shareopts, foreach_nfs_host_cb,
+           &udata);
+}
+
+/*
+ * Converts a Solaris NFS host specification to its Linux equivalent.
+ */
+static int
+get_linux_hostspec(const char *solaris_hostspec, char **plinux_hostspec)
+{
+       /*
+        * For now we just support CIDR masks (e.g. @192.168.0.0/16) and host
+        * wildcards (e.g. *.example.org).
+        */
+       if (solaris_hostspec[0] == '@') {
+               /*
+                * Solaris host specifier, e.g. @192.168.0.0/16; we just need
+                * to skip the @ in this case
+                */
+               *plinux_hostspec = strdup(solaris_hostspec + 1);
+       } else {
+               *plinux_hostspec = strdup(solaris_hostspec);
+       }
+
+       if (*plinux_hostspec == NULL) {
+               return (SA_NO_MEMORY);
+       }
+
+       return (SA_OK);
+}
+
+/*
+ * Used internally by nfs_enable_share to enable sharing for a single host.
+ */
+static int
+nfs_enable_share_one(const char *sharepath, const char *host,
+    const char *security, const char *access, void *pcookie)
+{
+       int rc;
+       char *linuxhost, *hostpath, *opts;
+       const char *linux_opts = (const char *)pcookie;
+       char *argv[6];
+
+       /* exportfs -i -o sec=XX,rX,<opts> <host>:<sharepath> */
+
+       rc = get_linux_hostspec(host, &linuxhost);
+
+       if (rc < 0)
+               exit(1);
+
+       hostpath = malloc(strlen(linuxhost) + 1 + strlen(sharepath) + 1);
+
+       if (hostpath == NULL) {
+               free(linuxhost);
+
+               exit(1);
+       }
+
+       sprintf(hostpath, "%s:%s", linuxhost, sharepath);
+
+       free(linuxhost);
+
+       if (linux_opts == NULL)
+               linux_opts = "";
+
+       opts = malloc(4 + strlen(security) + 4 + strlen(linux_opts) + 1);
+
+       if (opts == NULL)
+               exit(1);
+
+       sprintf(opts, "sec=%s,%s,%s", security, access, linux_opts);
+
+#ifdef DEBUG
+       fprintf(stderr, "sharing %s with opts %s\n", hostpath, opts);
+#endif
+
+       argv[0] = "/usr/sbin/exportfs";
+       argv[1] = "-i";
+       argv[2] = "-o";
+       argv[3] = opts;
+       argv[4] = hostpath;
+       argv[5] = NULL;
+
+       rc = libzfs_run_process(argv[0], argv, 0);
+
+       free(hostpath);
+       free(opts);
+
+       if (rc < 0)
+               return (SA_SYSTEM_ERR);
+       else
+               return (SA_OK);
+}
+
+/*
+ * Adds a Linux share option to an array of NFS options.
+ */
+static int
+add_linux_shareopt(char **plinux_opts, const char *key, const char *value)
+{
+       size_t len = 0;
+       char *new_linux_opts;
+
+       if (*plinux_opts != NULL)
+               len = strlen(*plinux_opts);
+
+       new_linux_opts = realloc(*plinux_opts, len + 1 + strlen(key) +
+           (value ? 1 + strlen(value) : 0) + 1);
+
+       if (new_linux_opts == NULL)
+               return (SA_NO_MEMORY);
+
+       new_linux_opts[len] = '\0';
+
+       if (len > 0)
+               strcat(new_linux_opts, ",");
+
+       strcat(new_linux_opts, key);
+
+       if (value != NULL) {
+               strcat(new_linux_opts, "=");
+               strcat(new_linux_opts, value);
+       }
+
+       *plinux_opts = new_linux_opts;
+
+       return (SA_OK);
+}
+
+/*
+ * Validates and converts a single Solaris share option to its Linux
+ * equivalent.
+ */
+static int
+get_linux_shareopts_cb(const char *key, const char *value, void *cookie)
+{
+       char **plinux_opts = (char **)cookie;
+
+       /* host-specific options, these are taken care of elsewhere */
+       if (strcmp(key, "ro") == 0 || strcmp(key, "rw") == 0 ||
+           strcmp(key, "sec") == 0)
+               return (SA_OK);
+
+       if (strcmp(key, "anon") == 0)
+               key = "anonuid";
+
+       if (strcmp(key, "root_mapping") == 0) {
+               (void) add_linux_shareopt(plinux_opts, "root_squash", NULL);
+               key = "anonuid";
+       }
+
+       if (strcmp(key, "nosub") == 0)
+               key = "subtree_check";
+
+       if (strcmp(key, "insecure") != 0 && strcmp(key, "secure") != 0 &&
+           strcmp(key, "async") != 0 && strcmp(key, "sync") != 0 &&
+           strcmp(key, "no_wdelay") != 0 && strcmp(key, "wdelay") != 0 &&
+           strcmp(key, "nohide") != 0 && strcmp(key, "hide") != 0 &&
+           strcmp(key, "crossmnt") != 0 &&
+           strcmp(key, "no_subtree_check") != 0 &&
+           strcmp(key, "subtree_check") != 0 &&
+           strcmp(key, "insecure_locks") != 0 &&
+           strcmp(key, "secure_locks") != 0 &&
+           strcmp(key, "no_auth_nlm") != 0 && strcmp(key, "auth_nlm") != 0 &&
+           strcmp(key, "no_acl") != 0 && strcmp(key, "mountpoint") != 0 &&
+           strcmp(key, "mp") != 0 && strcmp(key, "fsuid") != 0 &&
+           strcmp(key, "refer") != 0 && strcmp(key, "replicas") != 0 &&
+           strcmp(key, "root_squash") != 0 &&
+           strcmp(key, "no_root_squash") != 0 &&
+           strcmp(key, "all_squash") != 0 &&
+           strcmp(key, "no_all_squash") != 0 && strcmp(key, "fsid") != 0 &&
+           strcmp(key, "anonuid") != 0 && strcmp(key, "anongid") != 0) {
+               return (SA_SYNTAX_ERR);
+       }
+
+       (void) add_linux_shareopt(plinux_opts, key, value);
+
+       return (SA_OK);
+}
+
+/*
+ * Takes a string containing Solaris share options (e.g. "sync,no_acl") and
+ * converts them to a NULL-terminated array of Linux NFS options.
+ */
+static int
+get_linux_shareopts(const char *shareopts, char **plinux_opts)
+{
+       int rc;
+
+       assert(plinux_opts != NULL);
+
+       *plinux_opts = NULL;
+
+       /* default options for Solaris shares */
+       (void) add_linux_shareopt(plinux_opts, "no_subtree_check", NULL);
+       (void) add_linux_shareopt(plinux_opts, "no_root_squash", NULL);
+       (void) add_linux_shareopt(plinux_opts, "mountpoint", NULL);
+
+       rc = foreach_nfs_shareopt(shareopts, get_linux_shareopts_cb,
+           plinux_opts);
+
+       if (rc != SA_OK) {
+               free(*plinux_opts);
+               *plinux_opts = NULL;
+       }
+
+       return (rc);
+}
+
+/*
+ * Enables NFS sharing for the specified share.
+ */
+static int
+nfs_enable_share(sa_share_impl_t impl_share)
+{
+       char *shareopts, *linux_opts;
+       int rc;
+
+       if (!nfs_available()) {
+               return (SA_SYSTEM_ERR);
+       }
+
+       shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
+
+       if (shareopts == NULL)
+               return (SA_OK);
+
+       rc = get_linux_shareopts(shareopts, &linux_opts);
+
+       if (rc != SA_OK)
+               return (rc);
+
+       rc = foreach_nfs_host(impl_share, nfs_enable_share_one, linux_opts);
+
+       free(linux_opts);
+
+       return (rc);
+}
+
+/*
+ * Used internally by nfs_disable_share to disable sharing for a single host.
+ */
+static int
+nfs_disable_share_one(const char *sharepath, const char *host,
+    const char *security, const char *access, void *cookie)
+{
+       int rc;
+       char *linuxhost, *hostpath;
+       char *argv[4];
+
+       rc = get_linux_hostspec(host, &linuxhost);
+
+       if (rc < 0)
+               exit(1);
+
+       hostpath = malloc(strlen(linuxhost) + 1 + strlen(sharepath) + 1);
+
+       if (hostpath == NULL) {
+               free(linuxhost);
+               exit(1);
+       }
+
+       sprintf(hostpath, "%s:%s", linuxhost, sharepath);
+
+       free(linuxhost);
+
+#ifdef DEBUG
+       fprintf(stderr, "unsharing %s\n", hostpath);
+#endif
+
+       argv[0] = "/usr/sbin/exportfs";
+       argv[1] = "-u";
+       argv[2] = hostpath;
+       argv[3] = NULL;
+
+       rc = libzfs_run_process(argv[0], argv, 0);
+
+       free(hostpath);
+
+       if (rc < 0)
+               return (SA_SYSTEM_ERR);
+       else
+               return (SA_OK);
+}
+
+/*
+ * Disables NFS sharing for the specified share.
+ */
+static int
+nfs_disable_share(sa_share_impl_t impl_share)
+{
+       if (!nfs_available()) {
+               /*
+                * The share can't possibly be active, so nothing
+                * needs to be done to disable it.
+                */
+               return (SA_OK);
+       }
+
+       return (foreach_nfs_host(impl_share, nfs_disable_share_one, NULL));
+}
+
+/*
+ * Checks whether the specified NFS share options are syntactically correct.
+ */
+static int
+nfs_validate_shareopts(const char *shareopts)
+{
+       char *linux_opts;
+       int rc;
+
+       rc = get_linux_shareopts(shareopts, &linux_opts);
+
+       if (rc != SA_OK)
+               return (rc);
+
+       free(linux_opts);
+
+       return (SA_OK);
+}
+
+/*
+ * Checks whether a share is currently active.
+ */
+static boolean_t
+nfs_is_share_active(sa_share_impl_t impl_share)
+{
+       int fd;
+       char line[512];
+       char *tab, *cur;
+       FILE *nfs_exportfs_temp_fp;
+
+       if (!nfs_available())
+               return (B_FALSE);
+
+       if ((fd = dup(nfs_exportfs_temp_fd)) == -1)
+               return (B_FALSE);
+
+       nfs_exportfs_temp_fp = fdopen(fd, "r");
+
+       if (nfs_exportfs_temp_fp == NULL)
+               return (B_FALSE);
+
+       if (fseek(nfs_exportfs_temp_fp, 0, SEEK_SET) < 0) {
+               fclose(nfs_exportfs_temp_fp);
+               return (B_FALSE);
+       }
+
+       while (fgets(line, sizeof (line), nfs_exportfs_temp_fp) != NULL) {
+               /*
+                * exportfs uses separate lines for the share path
+                * and the export options when the share path is longer
+                * than a certain amount of characters; this ignores
+                * the option lines
+                */
+               if (line[0] == '\t')
+                       continue;
+
+               tab = strchr(line, '\t');
+
+               if (tab != NULL) {
+                       *tab = '\0';
+                       cur = tab - 1;
+               } else {
+                       /*
+                        * there's no tab character, which means the
+                        * NFS options are on a separate line; we just
+                        * need to remove the new-line character
+                        * at the end of the line
+                        */
+                       cur = line + strlen(line) - 1;
+               }
+
+               /* remove trailing spaces and new-line characters */
+               while (cur >= line && (*cur == ' ' || *cur == '\n'))
+                       *cur-- = '\0';
+
+               if (strcmp(line, impl_share->sharepath) == 0) {
+                       fclose(nfs_exportfs_temp_fp);
+                       return (B_TRUE);
+               }
+       }
+
+       fclose(nfs_exportfs_temp_fp);
+
+       return (B_FALSE);
+}
+
+/*
+ * Called to update a share's options. A share's options might be out of
+ * date if the share was loaded from disk (i.e. /etc/dfs/sharetab) and the
+ * "sharenfs" dataset property has changed in the meantime. This function
+ * also takes care of re-enabling the share if necessary.
+ */
+static int
+nfs_update_shareopts(sa_share_impl_t impl_share, const char *resource,
+    const char *shareopts)
+{
+       char *shareopts_dup;
+       boolean_t needs_reshare = B_FALSE;
+       char *old_shareopts;
+
+       FSINFO(impl_share, nfs_fstype)->active =
+           nfs_is_share_active(impl_share);
+
+       old_shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
+
+       if (strcmp(shareopts, "on") == 0)
+               shareopts = "rw";
+
+       if (FSINFO(impl_share, nfs_fstype)->active && old_shareopts != NULL &&
+           strcmp(old_shareopts, shareopts) != 0) {
+               needs_reshare = B_TRUE;
+               nfs_disable_share(impl_share);
+       }
+
+       shareopts_dup = strdup(shareopts);
+
+       if (shareopts_dup == NULL)
+               return (SA_NO_MEMORY);
+
+       if (old_shareopts != NULL)
+               free(old_shareopts);
+
+       FSINFO(impl_share, nfs_fstype)->shareopts = shareopts_dup;
+
+       if (needs_reshare)
+               nfs_enable_share(impl_share);
+
+       return (SA_OK);
+}
+
+/*
+ * Clears a share's NFS options. Used by libshare to
+ * clean up shares that are about to be free()'d.
+ */
+static void
+nfs_clear_shareopts(sa_share_impl_t impl_share)
+{
+       free(FSINFO(impl_share, nfs_fstype)->shareopts);
+       FSINFO(impl_share, nfs_fstype)->shareopts = NULL;
+}
+
+static const sa_share_ops_t nfs_shareops = {
+       .enable_share = nfs_enable_share,
+       .disable_share = nfs_disable_share,
+
+       .validate_shareopts = nfs_validate_shareopts,
+       .update_shareopts = nfs_update_shareopts,
+       .clear_shareopts = nfs_clear_shareopts,
+};
+
+/*
+ * nfs_check_exportfs() checks that the exportfs command runs
+ * and also maintains a temporary copy of the output from
+ * exportfs -v.
+ * To update this temporary copy simply call this function again.
+ *
+ * TODO : Use /var/lib/nfs/etab instead of our private copy.
+ *        But must implement locking to prevent concurrent access.
+ *
+ * TODO : The temporary file descriptor is never closed since
+ *        there is no libshare_nfs_fini() function.
+ */
+static int
+nfs_check_exportfs(void)
+{
+       pid_t pid;
+       int rc, status;
+       static char nfs_exportfs_tempfile[] = "/tmp/exportfs.XXXXXX";
+
+       /*
+        * Close any existing temporary copies of output from exportfs.
+        * We have already called unlink() so file will be deleted.
+        */
+       if (nfs_exportfs_temp_fd >= 0)
+               close(nfs_exportfs_temp_fd);
+
+       nfs_exportfs_temp_fd = mkstemp(nfs_exportfs_tempfile);
+
+       if (nfs_exportfs_temp_fd < 0)
+               return (SA_SYSTEM_ERR);
+
+       unlink(nfs_exportfs_tempfile);
+
+       (void) fcntl(nfs_exportfs_temp_fd, F_SETFD, FD_CLOEXEC);
+
+       pid = fork();
+
+       if (pid < 0) {
+               (void) close(nfs_exportfs_temp_fd);
+               nfs_exportfs_temp_fd = -1;
+               return (SA_SYSTEM_ERR);
+       }
+
+       if (pid > 0) {
+               while ((rc = waitpid(pid, &status, 0)) <= 0 && errno == EINTR);
+
+               if (rc <= 0) {
+                       (void) close(nfs_exportfs_temp_fd);
+                       nfs_exportfs_temp_fd = -1;
+                       return (SA_SYSTEM_ERR);
+               }
+
+               if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+                       (void) close(nfs_exportfs_temp_fd);
+                       nfs_exportfs_temp_fd = -1;
+                       return (SA_CONFIG_ERR);
+               }
+
+               return (SA_OK);
+       }
+
+       /* child */
+
+       /* exportfs -v */
+
+       if (dup2(nfs_exportfs_temp_fd, STDOUT_FILENO) < 0)
+               exit(1);
+
+       rc = execlp("/usr/sbin/exportfs", "exportfs", "-v", NULL);
+
+       if (rc < 0) {
+               exit(1);
+       }
+
+       exit(0);
+}
+
+/*
+ * Provides a convenient wrapper for determing nfs availability
+ */
+static boolean_t
+nfs_available(void)
+{
+       if (nfs_exportfs_temp_fd == -1)
+               (void) nfs_check_exportfs();
+
+       return ((nfs_exportfs_temp_fd != -1) ? B_TRUE : B_FALSE);
+}
+
+/*
+ * Initializes the NFS functionality of libshare.
+ */
+void
+libshare_nfs_init(void)
+{
+       nfs_fstype = register_fstype("nfs", &nfs_shareops);
+}
diff --git a/zfs/lib/libshare/nfs.h b/zfs/lib/libshare/nfs.h
new file mode 100644 (file)
index 0000000..b9ea6ee
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 Gunnar Beutner
+ */
+
+void libshare_nfs_init(void);
diff --git a/zfs/lib/libshare/smb.c b/zfs/lib/libshare/smb.c
new file mode 100644 (file)
index 0000000..f8b7118
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * 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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011,2012 Turbo Fredriksson <turbo@bayour.com>, based on nfs.c
+ *                         by Gunnar Beutner
+ *
+ * This is an addition to the zfs device driver to add, modify and remove SMB
+ * shares using the 'net share' command that comes with Samba.
+ *
+ * TESTING
+ * Make sure that samba listens to 'localhost' (127.0.0.1) and that the options
+ * 'usershare max shares' and 'usershare owner only' have been rewied/set
+ * accordingly (see zfs(8) for information).
+ *
+ * Once configuration in samba have been done, test that this
+ * works with the following three commands (in this case, my ZFS
+ * filesystem is called 'share/Test1'):
+ *
+ *     (root)# net -U root -S 127.0.0.1 usershare add Test1 /share/Test1 \
+ *             "Comment: /share/Test1" "Everyone:F"
+ *     (root)# net usershare list | grep -i test
+ *     (root)# net -U root -S 127.0.0.1 usershare delete Test1
+ *
+ * The first command will create a user share that gives everyone full access.
+ * To limit the access below that, use normal UNIX commands (chmod, chown etc).
+ */
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libzfs.h>
+#include <libshare.h>
+#include "libshare_impl.h"
+#include "smb.h"
+
+static boolean_t smb_available(void);
+
+static sa_fstype_t *smb_fstype;
+
+/*
+ * Retrieve the list of SMB shares.
+ */
+static int
+smb_retrieve_shares(void)
+{
+       int rc = SA_OK;
+       char file_path[PATH_MAX], line[512], *token, *key, *value;
+       char *dup_value = NULL, *path = NULL, *comment = NULL, *name = NULL;
+       char *guest_ok = NULL;
+       DIR *shares_dir;
+       FILE *share_file_fp = NULL;
+       struct dirent *directory;
+       struct stat eStat;
+       smb_share_t *shares, *new_shares = NULL;
+
+       /* opendir(), stat() */
+       shares_dir = opendir(SHARE_DIR);
+       if (shares_dir == NULL)
+               return (SA_SYSTEM_ERR);
+
+       /* Go through the directory, looking for shares */
+       while ((directory = readdir(shares_dir))) {
+               if (directory->d_name[0] == '.')
+                       continue;
+
+               snprintf(file_path, sizeof (file_path),
+                   "%s/%s", SHARE_DIR, directory->d_name);
+
+               if (stat(file_path, &eStat) == -1) {
+                       rc = SA_SYSTEM_ERR;
+                       goto out;
+               }
+
+               if (!S_ISREG(eStat.st_mode))
+                       continue;
+
+               if ((share_file_fp = fopen(file_path, "r")) == NULL) {
+                       rc = SA_SYSTEM_ERR;
+                       goto out;
+               }
+
+               name = strdup(directory->d_name);
+               if (name == NULL) {
+                       rc = SA_NO_MEMORY;
+                       goto out;
+               }
+
+               while (fgets(line, sizeof (line), share_file_fp)) {
+                       if (line[0] == '#')
+                               continue;
+
+                       /* Trim trailing new-line character(s). */
+                       while (line[strlen(line) - 1] == '\r' ||
+                           line[strlen(line) - 1] == '\n')
+                               line[strlen(line) - 1] = '\0';
+
+                       /* Split the line in two, separated by '=' */
+                       token = strchr(line, '=');
+                       if (token == NULL)
+                               continue;
+
+                       key = line;
+                       value = token + 1;
+                       *token = '\0';
+
+                       dup_value = strdup(value);
+                       if (dup_value == NULL) {
+                               rc = SA_NO_MEMORY;
+                               goto out;
+                       }
+
+                       if (strcmp(key, "path") == 0) {
+                               free(path);
+                               path = dup_value;
+                       } else if (strcmp(key, "comment") == 0) {
+                               free(comment);
+                               comment = dup_value;
+                       } else if (strcmp(key, "guest_ok") == 0) {
+                               free(guest_ok);
+                               guest_ok = dup_value;
+                       } else
+                               free(dup_value);
+
+                       dup_value = NULL;
+
+                       if (path == NULL || comment == NULL || guest_ok == NULL)
+                               continue; /* Incomplete share definition */
+                       else {
+                               shares = (smb_share_t *)
+                                               malloc(sizeof (smb_share_t));
+                               if (shares == NULL) {
+                                       rc = SA_NO_MEMORY;
+                                       goto out;
+                               }
+
+                               (void) strlcpy(shares->name, name,
+                                   sizeof (shares->name));
+
+                               (void) strlcpy(shares->path, path,
+                                   sizeof (shares->path));
+
+                               (void) strlcpy(shares->comment, comment,
+                                   sizeof (shares->comment));
+
+                               shares->guest_ok = atoi(guest_ok);
+
+                               shares->next = new_shares;
+                               new_shares = shares;
+
+                               free(path);
+                               free(comment);
+                               free(guest_ok);
+
+                               path = NULL;
+                               comment = NULL;
+                               guest_ok = NULL;
+                       }
+               }
+
+out:
+               if (share_file_fp != NULL) {
+                       fclose(share_file_fp);
+                       share_file_fp = NULL;
+               }
+
+               free(name);
+               free(path);
+               free(comment);
+               free(guest_ok);
+
+               name = NULL;
+               path = NULL;
+               comment = NULL;
+               guest_ok = NULL;
+       }
+       closedir(shares_dir);
+
+       smb_shares = new_shares;
+
+       return (rc);
+}
+
+/*
+ * Used internally by smb_enable_share to enable sharing for a single host.
+ */
+static int
+smb_enable_share_one(const char *sharename, const char *sharepath)
+{
+       char *argv[10], *pos;
+       char name[SMB_NAME_MAX], comment[SMB_COMMENT_MAX];
+       int rc;
+
+       /* Support ZFS share name regexp '[[:alnum:]_-.: ]' */
+       strncpy(name, sharename, sizeof (name));
+       name [sizeof (name)-1] = '\0';
+
+       pos = name;
+       while (*pos != '\0') {
+               switch (*pos) {
+               case '/':
+               case '-':
+               case ':':
+               case ' ':
+                       *pos = '_';
+               }
+
+               ++pos;
+       }
+
+       /*
+        * CMD: net -S NET_CMD_ARG_HOST usershare add Test1 /share/Test1 \
+        *      "Comment" "Everyone:F"
+        */
+       snprintf(comment, sizeof (comment), "Comment: %s", sharepath);
+
+       argv[0] = NET_CMD_PATH;
+       argv[1] = (char *)"-S";
+       argv[2] = NET_CMD_ARG_HOST;
+       argv[3] = (char *)"usershare";
+       argv[4] = (char *)"add";
+       argv[5] = (char *)name;
+       argv[6] = (char *)sharepath;
+       argv[7] = (char *)comment;
+       argv[8] = "Everyone:F";
+       argv[9] = NULL;
+
+       rc = libzfs_run_process(argv[0], argv, 0);
+       if (rc < 0)
+               return (SA_SYSTEM_ERR);
+
+       /* Reload the share file */
+       (void) smb_retrieve_shares();
+
+       return (SA_OK);
+}
+
+/*
+ * Enables SMB sharing for the specified share.
+ */
+static int
+smb_enable_share(sa_share_impl_t impl_share)
+{
+       char *shareopts;
+
+       if (!smb_available())
+               return (SA_SYSTEM_ERR);
+
+       shareopts = FSINFO(impl_share, smb_fstype)->shareopts;
+       if (shareopts == NULL) /* on/off */
+               return (SA_SYSTEM_ERR);
+
+       if (strcmp(shareopts, "off") == 0)
+               return (SA_OK);
+
+       /* Magic: Enable (i.e., 'create new') share */
+       return (smb_enable_share_one(impl_share->dataset,
+           impl_share->sharepath));
+}
+
+/*
+ * Used internally by smb_disable_share to disable sharing for a single host.
+ */
+static int
+smb_disable_share_one(const char *sharename)
+{
+       int rc;
+       char *argv[7];
+
+       /* CMD: net -S NET_CMD_ARG_HOST usershare delete Test1 */
+       argv[0] = NET_CMD_PATH;
+       argv[1] = (char *)"-S";
+       argv[2] = NET_CMD_ARG_HOST;
+       argv[3] = (char *)"usershare";
+       argv[4] = (char *)"delete";
+       argv[5] = strdup(sharename);
+       argv[6] = NULL;
+
+       rc = libzfs_run_process(argv[0], argv, 0);
+       if (rc < 0)
+               return (SA_SYSTEM_ERR);
+       else
+               return (SA_OK);
+}
+
+/*
+ * Disables SMB sharing for the specified share.
+ */
+static int
+smb_disable_share(sa_share_impl_t impl_share)
+{
+       smb_share_t *shares = smb_shares;
+
+       if (!smb_available()) {
+               /*
+                * The share can't possibly be active, so nothing
+                * needs to be done to disable it.
+                */
+               return (SA_OK);
+       }
+
+       while (shares != NULL) {
+               if (strcmp(impl_share->sharepath, shares->path) == 0)
+                       return (smb_disable_share_one(shares->name));
+
+               shares = shares->next;
+       }
+
+       return (SA_OK);
+}
+
+/*
+ * Checks whether the specified SMB share options are syntactically correct.
+ */
+static int
+smb_validate_shareopts(const char *shareopts)
+{
+       /* TODO: Accept 'name' and sec/acl (?) */
+       if ((strcmp(shareopts, "off") == 0) || (strcmp(shareopts, "on") == 0))
+               return (SA_OK);
+
+       return (SA_SYNTAX_ERR);
+}
+
+/*
+ * Checks whether a share is currently active.
+ */
+static boolean_t
+smb_is_share_active(sa_share_impl_t impl_share)
+{
+       if (!smb_available())
+               return (B_FALSE);
+
+       /* Retrieve the list of (possible) active shares */
+       smb_retrieve_shares();
+
+       while (smb_shares != NULL) {
+               if (strcmp(impl_share->sharepath, smb_shares->path) == 0)
+                       return (B_TRUE);
+
+               smb_shares = smb_shares->next;
+       }
+
+       return (B_FALSE);
+}
+
+/*
+ * Called to update a share's options. A share's options might be out of
+ * date if the share was loaded from disk and the "sharesmb" dataset
+ * property has changed in the meantime. This function also takes care
+ * of re-enabling the share if necessary.
+ */
+static int
+smb_update_shareopts(sa_share_impl_t impl_share, const char *resource,
+    const char *shareopts)
+{
+       char *shareopts_dup;
+       boolean_t needs_reshare = B_FALSE;
+       char *old_shareopts;
+
+       if (!impl_share)
+               return (SA_SYSTEM_ERR);
+
+       FSINFO(impl_share, smb_fstype)->active =
+           smb_is_share_active(impl_share);
+
+       old_shareopts = FSINFO(impl_share, smb_fstype)->shareopts;
+
+       if (FSINFO(impl_share, smb_fstype)->active && old_shareopts != NULL &&
+               strcmp(old_shareopts, shareopts) != 0) {
+               needs_reshare = B_TRUE;
+               smb_disable_share(impl_share);
+       }
+
+       shareopts_dup = strdup(shareopts);
+
+       if (shareopts_dup == NULL)
+               return (SA_NO_MEMORY);
+
+       if (old_shareopts != NULL)
+               free(old_shareopts);
+
+       FSINFO(impl_share, smb_fstype)->shareopts = shareopts_dup;
+
+       if (needs_reshare)
+               smb_enable_share(impl_share);
+
+       return (SA_OK);
+}
+
+/*
+ * Clears a share's SMB options. Used by libshare to
+ * clean up shares that are about to be free()'d.
+ */
+static void
+smb_clear_shareopts(sa_share_impl_t impl_share)
+{
+       free(FSINFO(impl_share, smb_fstype)->shareopts);
+       FSINFO(impl_share, smb_fstype)->shareopts = NULL;
+}
+
+static const sa_share_ops_t smb_shareops = {
+       .enable_share = smb_enable_share,
+       .disable_share = smb_disable_share,
+
+       .validate_shareopts = smb_validate_shareopts,
+       .update_shareopts = smb_update_shareopts,
+       .clear_shareopts = smb_clear_shareopts,
+};
+
+/*
+ * Provides a convenient wrapper for determining SMB availability
+ */
+static boolean_t
+smb_available(void)
+{
+       struct stat statbuf;
+
+       if (lstat(SHARE_DIR, &statbuf) != 0 ||
+           !S_ISDIR(statbuf.st_mode))
+               return (B_FALSE);
+
+       if (access(NET_CMD_PATH, F_OK) != 0)
+               return (B_FALSE);
+
+       return (B_TRUE);
+}
+
+/*
+ * Initializes the SMB functionality of libshare.
+ */
+void
+libshare_smb_init(void)
+{
+       smb_fstype = register_fstype("smb", &smb_shareops);
+}
diff --git a/zfs/lib/libshare/smb.h b/zfs/lib/libshare/smb.h
new file mode 100644 (file)
index 0000000..7a0c0fd
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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 (c) 2011 Turbo Fredriksson <turbo@bayour.com>.
+ */
+
+/*
+ * The maximum SMB share name seems to be 254 characters, though good
+ * references are hard to find.
+ */
+
+#define        SMB_NAME_MAX            255
+#define        SMB_COMMENT_MAX         255
+
+#define        SHARE_DIR               "/var/lib/samba/usershares"
+#define        NET_CMD_PATH            "/usr/bin/net"
+#define        NET_CMD_ARG_HOST        "127.0.0.1"
+
+typedef struct smb_share_s {
+       char name[SMB_NAME_MAX];        /* Share name */
+       char path[PATH_MAX];            /* Share path */
+       char comment[SMB_COMMENT_MAX];  /* Share's comment */
+       boolean_t guest_ok;             /* 'y' or 'n' */
+
+       struct smb_share_s *next;
+} smb_share_t;
+
+smb_share_t *smb_shares;
+
+void libshare_smb_init(void);
diff --git a/zfs/lib/libspl/Makefile.am b/zfs/lib/libspl/Makefile.am
new file mode 100644 (file)
index 0000000..afd64fc
--- /dev/null
@@ -0,0 +1,46 @@
+include $(top_srcdir)/config/Rules.am
+
+VPATH = \
+       $(top_srcdir)/lib/libspl \
+       $(top_srcdir)/lib/libspl/$(TARGET_ASM_DIR)
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+
+SUBDIRS = include $(TARGET_ASM_DIR)
+DIST_SUBDIRS = include asm-generic asm-i386 asm-x86_64
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/lib/libspl/include
+
+AM_CCASFLAGS = \
+       -I$(top_srcdir)/lib/libspl/include
+
+noinst_LTLIBRARIES = libspl.la
+
+USER_C = \
+       getexecname.c \
+       gethrtime.c \
+       gethrestime.c \
+       getmntany.c \
+       list.c \
+       mkdirp.c \
+       strlcat.c \
+       strlcpy.c \
+       strnlen.c \
+       timestamp.c \
+       zone.c \
+       include/sys/list.h \
+       include/sys/list_impl.h
+
+USER_ASM = atomic.S
+
+KERNEL_C =
+
+nodist_libspl_la_SOURCES = \
+       $(USER_C) \
+       $(USER_ASM) \
+       $(KERNEL_C)
+
+libspl_la_LIBADD = -lrt
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libspl/Makefile.in b/zfs/lib/libspl/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/asm-generic/Makefile.am b/zfs/lib/libspl/asm-generic/Makefile.am
new file mode 100644 (file)
index 0000000..17fe501
--- /dev/null
@@ -0,0 +1,18 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+        -I$(top_srcdir)/lib/libspl/include
+
+atomic_SOURCE = atomic.c
+atomic_ASM = atomic.S
+
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+         $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -fPIC
+EXTRA_DIST = $(atomic_SOURCE)
+
+# Generates assembly to simplify inclusion in ../Makefile.am
+all-am:
+       $(COMPILE) -c -S $(atomic_SOURCE) -o $(atomic_ASM)
+
+clean-generic:
+       $(RM) $(atomic_ASM)
diff --git a/zfs/lib/libspl/asm-generic/Makefile.in b/zfs/lib/libspl/asm-generic/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/asm-generic/atomic.c b/zfs/lib/libspl/asm-generic/atomic.c
new file mode 100644 (file)
index 0000000..f5eb4f3
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * 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 (c) 2009 by Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <atomic.h>
+#include <assert.h>
+#include <pthread.h>
+
+/*
+ * All operations are implemented by serializing them through a global
+ * pthread mutex.  This provides a correct generic implementation.
+ * However all supported architectures are encouraged to provide a
+ * native implementation is assembly for performance reasons.
+ */
+pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Theses are the void returning variants
+ */
+
+#define        ATOMIC_INC(name, type) \
+       void atomic_inc_##name(volatile type *target)                   \
+       {                                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               (*target)++;                                            \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+       }
+
+ATOMIC_INC(long, unsigned long)
+ATOMIC_INC(8, uint8_t)
+ATOMIC_INC(uchar, uchar_t)
+ATOMIC_INC(16, uint16_t)
+ATOMIC_INC(ushort, ushort_t)
+ATOMIC_INC(32, uint32_t)
+ATOMIC_INC(uint, uint_t)
+ATOMIC_INC(ulong, ulong_t)
+ATOMIC_INC(64, uint64_t)
+
+
+#define        ATOMIC_DEC(name, type) \
+       void atomic_dec_##name(volatile type *target)                   \
+       {                                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               (*target)--;                                            \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+       }
+
+ATOMIC_DEC(long, unsigned long)
+ATOMIC_DEC(8, uint8_t)
+ATOMIC_DEC(uchar, uchar_t)
+ATOMIC_DEC(16, uint16_t)
+ATOMIC_DEC(ushort, ushort_t)
+ATOMIC_DEC(32, uint32_t)
+ATOMIC_DEC(uint, uint_t)
+ATOMIC_DEC(ulong, ulong_t)
+ATOMIC_DEC(64, uint64_t)
+
+
+#define        ATOMIC_ADD(name, type1, type2) \
+       void atomic_add_##name(volatile type1 *target, type2 bits)      \
+       {                                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               *target += bits;                                        \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+       }
+
+ATOMIC_ADD(8, uint8_t, int8_t)
+ATOMIC_ADD(char, uchar_t, signed char)
+ATOMIC_ADD(16, uint16_t, int16_t)
+ATOMIC_ADD(short, ushort_t, short)
+ATOMIC_ADD(32, uint32_t, int32_t)
+ATOMIC_ADD(int, uint_t, int)
+ATOMIC_ADD(long, ulong_t, long)
+ATOMIC_ADD(64, uint64_t, int64_t)
+
+void
+atomic_add_ptr(volatile void *target, ssize_t bits)
+{
+       VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);
+       *(caddr_t *)target += bits;
+       VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+}
+
+
+#define        ATOMIC_SUB(name, type1, type2) \
+       void atomic_sub_##name(volatile type1 *target, type2 bits)      \
+       {                                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               *target -= bits;                                        \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+       }
+
+ATOMIC_SUB(8, uint8_t, int8_t)
+ATOMIC_SUB(char, uchar_t, signed char)
+ATOMIC_SUB(16, uint16_t, int16_t)
+ATOMIC_SUB(short, ushort_t, short)
+ATOMIC_SUB(32, uint32_t, int32_t)
+ATOMIC_SUB(int, uint_t, int)
+ATOMIC_SUB(long, ulong_t, long)
+ATOMIC_SUB(64, uint64_t, int64_t)
+
+void
+atomic_sub_ptr(volatile void *target, ssize_t bits)
+{
+       VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);
+       *(caddr_t *)target -= bits;
+       VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+}
+
+
+#define        ATOMIC_OR(name, type) \
+       void atomic_or_##name(volatile type *target, type bits)         \
+       {                                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               *target |= bits;                                        \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+       }
+
+ATOMIC_OR(8, uint8_t)
+ATOMIC_OR(uchar, uchar_t)
+ATOMIC_OR(16, uint16_t)
+ATOMIC_OR(ushort, ushort_t)
+ATOMIC_OR(32, uint32_t)
+ATOMIC_OR(uint, uint_t)
+ATOMIC_OR(ulong, ulong_t)
+ATOMIC_OR(64, uint64_t)
+
+
+#define        ATOMIC_AND(name, type) \
+       void atomic_and_##name(volatile type *target, type bits)        \
+       {                                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               *target &= bits;                                        \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+       }
+
+ATOMIC_AND(8, uint8_t)
+ATOMIC_AND(uchar, uchar_t)
+ATOMIC_AND(16, uint16_t)
+ATOMIC_AND(ushort, ushort_t)
+ATOMIC_AND(32, uint32_t)
+ATOMIC_AND(uint, uint_t)
+ATOMIC_AND(ulong, ulong_t)
+ATOMIC_AND(64, uint64_t)
+
+
+/*
+ * New value returning variants
+ */
+
+#define        ATOMIC_INC_NV(name, type) \
+       type atomic_inc_##name##_nv(volatile type *target)              \
+       {                                                               \
+               type rc;                                                \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               rc = (++(*target));                                     \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+               return (rc);                                            \
+       }
+
+ATOMIC_INC_NV(long, unsigned long)
+ATOMIC_INC_NV(8, uint8_t)
+ATOMIC_INC_NV(uchar, uchar_t)
+ATOMIC_INC_NV(16, uint16_t)
+ATOMIC_INC_NV(ushort, ushort_t)
+ATOMIC_INC_NV(32, uint32_t)
+ATOMIC_INC_NV(uint, uint_t)
+ATOMIC_INC_NV(ulong, ulong_t)
+ATOMIC_INC_NV(64, uint64_t)
+
+
+#define        ATOMIC_DEC_NV(name, type) \
+       type atomic_dec_##name##_nv(volatile type *target)              \
+       {                                                               \
+               type rc;                                                \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               rc = (--(*target));                                     \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+               return (rc);                                            \
+       }
+
+ATOMIC_DEC_NV(long, unsigned long)
+ATOMIC_DEC_NV(8, uint8_t)
+ATOMIC_DEC_NV(uchar, uchar_t)
+ATOMIC_DEC_NV(16, uint16_t)
+ATOMIC_DEC_NV(ushort, ushort_t)
+ATOMIC_DEC_NV(32, uint32_t)
+ATOMIC_DEC_NV(uint, uint_t)
+ATOMIC_DEC_NV(ulong, ulong_t)
+ATOMIC_DEC_NV(64, uint64_t)
+
+
+#define        ATOMIC_ADD_NV(name, type1, type2) \
+       type1 atomic_add_##name##_nv(volatile type1 *target, type2 bits)\
+       {                                                               \
+               type1 rc;                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               rc = (*target += bits);                                 \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+               return (rc);                                            \
+       }
+
+ATOMIC_ADD_NV(8, uint8_t, int8_t)
+ATOMIC_ADD_NV(char, uchar_t, signed char)
+ATOMIC_ADD_NV(16, uint16_t, int16_t)
+ATOMIC_ADD_NV(short, ushort_t, short)
+ATOMIC_ADD_NV(32, uint32_t, int32_t)
+ATOMIC_ADD_NV(int, uint_t, int)
+ATOMIC_ADD_NV(long, ulong_t, long)
+ATOMIC_ADD_NV(64, uint64_t, int64_t)
+
+void *
+atomic_add_ptr_nv(volatile void *target, ssize_t bits)
+{
+       void *ptr;
+
+       VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);
+       ptr = (*(caddr_t *)target += bits);
+       VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+
+       return (ptr);
+}
+
+
+#define        ATOMIC_SUB_NV(name, type1, type2) \
+       type1 atomic_sub_##name##_nv(volatile type1 *target, type2 bits)\
+       {                                                               \
+               type1 rc;                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               rc = (*target -= bits);                                 \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+               return (rc);                                            \
+       }
+
+ATOMIC_SUB_NV(8, uint8_t, int8_t)
+ATOMIC_SUB_NV(char, uchar_t, signed char)
+ATOMIC_SUB_NV(16, uint16_t, int16_t)
+ATOMIC_SUB_NV(short, ushort_t, short)
+ATOMIC_SUB_NV(32, uint32_t, int32_t)
+ATOMIC_SUB_NV(int, uint_t, int)
+ATOMIC_SUB_NV(long, ulong_t, long)
+ATOMIC_SUB_NV(64, uint64_t, int64_t)
+
+void *
+atomic_sub_ptr_nv(volatile void *target, ssize_t bits)
+{
+       void *ptr;
+
+       VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);
+       ptr = (*(caddr_t *)target -= bits);
+       VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+
+       return (ptr);
+}
+
+
+#define        ATOMIC_OR_NV(name, type) \
+       type atomic_or_##name##_nv(volatile type *target, type bits)    \
+       {                                                               \
+               type rc;                                                \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               rc = (*target |= bits);                                 \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+               return (rc);                                            \
+       }
+
+ATOMIC_OR_NV(long, unsigned long)
+ATOMIC_OR_NV(8, uint8_t)
+ATOMIC_OR_NV(uchar, uchar_t)
+ATOMIC_OR_NV(16, uint16_t)
+ATOMIC_OR_NV(ushort, ushort_t)
+ATOMIC_OR_NV(32, uint32_t)
+ATOMIC_OR_NV(uint, uint_t)
+ATOMIC_OR_NV(ulong, ulong_t)
+ATOMIC_OR_NV(64, uint64_t)
+
+
+#define        ATOMIC_AND_NV(name, type) \
+       type atomic_and_##name##_nv(volatile type *target, type bits)   \
+       {                                                               \
+               type rc;                                                \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               rc = (*target &= bits);                                 \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+               return (rc);                                            \
+       }
+
+ATOMIC_AND_NV(long, unsigned long)
+ATOMIC_AND_NV(8, uint8_t)
+ATOMIC_AND_NV(uchar, uchar_t)
+ATOMIC_AND_NV(16, uint16_t)
+ATOMIC_AND_NV(ushort, ushort_t)
+ATOMIC_AND_NV(32, uint32_t)
+ATOMIC_AND_NV(uint, uint_t)
+ATOMIC_AND_NV(ulong, ulong_t)
+ATOMIC_AND_NV(64, uint64_t)
+
+
+/*
+ *  If *arg1 == arg2, set *arg1 = arg3; return old value
+ */
+
+#define        ATOMIC_CAS(name, type) \
+       type atomic_cas_##name(volatile type *target, type arg1, type arg2) \
+       {                                                               \
+               type old;                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               old = *target;                                          \
+               if (old == arg1)                                        \
+                       *target = arg2;                                 \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+               return (old);                                           \
+       }
+
+ATOMIC_CAS(8, uint8_t)
+ATOMIC_CAS(uchar, uchar_t)
+ATOMIC_CAS(16, uint16_t)
+ATOMIC_CAS(ushort, ushort_t)
+ATOMIC_CAS(32, uint32_t)
+ATOMIC_CAS(uint, uint_t)
+ATOMIC_CAS(ulong, ulong_t)
+ATOMIC_CAS(64, uint64_t)
+
+void *
+atomic_cas_ptr(volatile void *target, void *arg1, void *arg2)
+{
+       void *old;
+
+       VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);
+       old = *(void **)target;
+       if (old == arg1)
+               *(void **)target = arg2;
+       VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+
+       return (old);
+}
+
+
+/*
+ * Swap target and return old value
+ */
+
+#define        ATOMIC_SWAP(name, type) \
+       type atomic_swap_##name(volatile type *target, type bits)       \
+       {                                                               \
+               type old;                                               \
+               VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);      \
+               old = *target;                                          \
+               *target = bits;                                         \
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);    \
+               return (old);                                           \
+       }
+
+ATOMIC_SWAP(8, uint8_t)
+ATOMIC_SWAP(uchar, uchar_t)
+ATOMIC_SWAP(16, uint16_t)
+ATOMIC_SWAP(ushort, ushort_t)
+ATOMIC_SWAP(32, uint32_t)
+ATOMIC_SWAP(uint, uint_t)
+ATOMIC_SWAP(ulong, ulong_t)
+ATOMIC_SWAP(64, uint64_t)
+
+void *
+atomic_swap_ptr(volatile void *target, void *bits)
+{
+       void *old;
+
+       VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);
+       old = *(void **)target;
+       *(void **)target = bits;
+       VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+
+       return (old);
+}
+
+
+int
+atomic_set_long_excl(volatile ulong_t *target, uint_t value)
+{
+       ulong_t bit;
+
+       VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);
+       bit = (1UL << value);
+       if ((*target & bit) != 0) {
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+               return (-1);
+       }
+       *target |= bit;
+       VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+
+       return (0);
+}
+
+int
+atomic_clear_long_excl(volatile ulong_t *target, uint_t value)
+{
+       ulong_t bit;
+
+       VERIFY3S(pthread_mutex_lock(&atomic_lock), ==, 0);
+       bit = (1UL << value);
+       if ((*target & bit) != 0) {
+               VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+               return (-1);
+       }
+       *target &= ~bit;
+       VERIFY3S(pthread_mutex_unlock(&atomic_lock), ==, 0);
+
+       return (0);
+}
+
+void
+membar_enter(void)
+{
+       /* XXX - Implement me */
+}
+
+void
+membar_exit(void)
+{
+       /* XXX - Implement me */
+}
+
+void
+membar_producer(void)
+{
+       /* XXX - Implement me */
+}
+
+void
+membar_consumer(void)
+{
+       /* XXX - Implement me */
+}
+
+/* Legacy kernel interfaces; they will go away (eventually). */
+
+uint8_t
+cas8(uint8_t *target, uint8_t arg1, uint8_t arg2)
+{
+       return (atomic_cas_8(target, arg1, arg2));
+}
+
+uint32_t
+cas32(uint32_t *target, uint32_t arg1, uint32_t arg2)
+{
+       return (atomic_cas_32(target, arg1, arg2));
+}
+
+uint64_t
+cas64(uint64_t *target, uint64_t arg1, uint64_t arg2)
+{
+       return (atomic_cas_64(target, arg1, arg2));
+}
+
+ulong_t
+caslong(ulong_t *target, ulong_t arg1, ulong_t arg2)
+{
+       return (atomic_cas_ulong(target, arg1, arg2));
+}
+
+void *
+casptr(void *target, void *arg1, void *arg2)
+{
+       return (atomic_cas_ptr(target, arg1, arg2));
+}
+
+void
+atomic_and_long(ulong_t *target, ulong_t bits)
+{
+       return (atomic_and_ulong(target, bits));
+}
+
+void
+atomic_or_long(ulong_t *target, ulong_t bits)
+{
+       return (atomic_or_ulong(target, bits));
+}
diff --git a/zfs/lib/libspl/asm-i386/Makefile.am b/zfs/lib/libspl/asm-i386/Makefile.am
new file mode 100644 (file)
index 0000000..e112610
--- /dev/null
@@ -0,0 +1 @@
+noinst_HEADERS = atomic.S
diff --git a/zfs/lib/libspl/asm-i386/Makefile.in b/zfs/lib/libspl/asm-i386/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/asm-i386/atomic.S b/zfs/lib/libspl/asm-i386/atomic.S
new file mode 100644 (file)
index 0000000..d3d4250
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+ * 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.
+ */
+
+       .ident  "%Z%%M% %I%     %E% SMI"
+
+       .file   "%M%"
+
+#define _ASM
+#include <ia32/sys/asm_linkage.h>
+
+       ENTRY(atomic_inc_8)
+       ALTENTRY(atomic_inc_uchar)
+       movl    4(%esp), %eax
+       lock
+       incb    (%eax)
+       ret
+       SET_SIZE(atomic_inc_uchar)
+       SET_SIZE(atomic_inc_8)
+
+       ENTRY(atomic_inc_16)
+       ALTENTRY(atomic_inc_ushort)
+       movl    4(%esp), %eax
+       lock
+       incw    (%eax)
+       ret
+       SET_SIZE(atomic_inc_ushort)
+       SET_SIZE(atomic_inc_16)
+
+       ENTRY(atomic_inc_32)
+       ALTENTRY(atomic_inc_uint)
+       ALTENTRY(atomic_inc_ulong)
+       movl    4(%esp), %eax
+       lock
+       incl    (%eax)
+       ret
+       SET_SIZE(atomic_inc_ulong)
+       SET_SIZE(atomic_inc_uint)
+       SET_SIZE(atomic_inc_32)
+
+       ENTRY(atomic_inc_8_nv)
+       ALTENTRY(atomic_inc_uchar_nv)
+       movl    4(%esp), %edx
+       movb    (%edx), %al
+1:
+       leal    1(%eax), %ecx
+       lock
+       cmpxchgb %cl, (%edx)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_inc_uchar_nv)
+       SET_SIZE(atomic_inc_8_nv)
+
+       ENTRY(atomic_inc_16_nv)
+       ALTENTRY(atomic_inc_ushort_nv)
+       movl    4(%esp), %edx
+       movw    (%edx), %ax
+1:
+       leal    1(%eax), %ecx
+       lock
+       cmpxchgw %cx, (%edx)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_inc_ushort_nv)
+       SET_SIZE(atomic_inc_16_nv)
+
+       ENTRY(atomic_inc_32_nv)
+       ALTENTRY(atomic_inc_uint_nv)
+       ALTENTRY(atomic_inc_ulong_nv)
+       movl    4(%esp), %edx
+       movl    (%edx), %eax
+1:
+       leal    1(%eax), %ecx
+       lock
+       cmpxchgl %ecx, (%edx)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_inc_ulong_nv)
+       SET_SIZE(atomic_inc_uint_nv)
+       SET_SIZE(atomic_inc_32_nv)
+
+       /*
+        * NOTE: If atomic_inc_64 and atomic_inc_64_nv are ever
+        * separated, you need to also edit the libc i386 platform
+        * specific mapfile and remove the NODYNSORT attribute
+        * from atomic_inc_64_nv.
+        */
+       ENTRY(atomic_inc_64)
+       ALTENTRY(atomic_inc_64_nv)
+       pushl   %edi
+       pushl   %ebx
+       movl    12(%esp), %edi
+       movl    (%edi), %eax
+       movl    4(%edi), %edx
+1:
+       xorl    %ebx, %ebx
+       xorl    %ecx, %ecx
+       incl    %ebx
+       addl    %eax, %ebx
+       adcl    %edx, %ecx
+       lock
+       cmpxchg8b (%edi)
+       jne     1b
+       movl    %ebx, %eax
+       movl    %ecx, %edx
+       popl    %ebx
+       popl    %edi
+       ret
+       SET_SIZE(atomic_inc_64_nv)
+       SET_SIZE(atomic_inc_64)
+
+       ENTRY(atomic_dec_8)
+       ALTENTRY(atomic_dec_uchar)
+       movl    4(%esp), %eax
+       lock
+       decb    (%eax)
+       ret
+       SET_SIZE(atomic_dec_uchar)
+       SET_SIZE(atomic_dec_8)
+
+       ENTRY(atomic_dec_16)
+       ALTENTRY(atomic_dec_ushort)
+       movl    4(%esp), %eax
+       lock
+       decw    (%eax)
+       ret
+       SET_SIZE(atomic_dec_ushort)
+       SET_SIZE(atomic_dec_16)
+
+       ENTRY(atomic_dec_32)
+       ALTENTRY(atomic_dec_uint)
+       ALTENTRY(atomic_dec_ulong)
+       movl    4(%esp), %eax
+       lock
+       decl    (%eax)
+       ret
+       SET_SIZE(atomic_dec_ulong)
+       SET_SIZE(atomic_dec_uint)
+       SET_SIZE(atomic_dec_32)
+
+       ENTRY(atomic_dec_8_nv)
+       ALTENTRY(atomic_dec_uchar_nv)
+       movl    4(%esp), %edx
+       movb    (%edx), %al
+1:
+       leal    -1(%eax), %ecx
+       lock
+       cmpxchgb %cl, (%edx)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_dec_uchar_nv)
+       SET_SIZE(atomic_dec_8_nv)
+
+       ENTRY(atomic_dec_16_nv)
+       ALTENTRY(atomic_dec_ushort_nv)
+       movl    4(%esp), %edx
+       movw    (%edx), %ax
+1:
+       leal    -1(%eax), %ecx
+       lock
+       cmpxchgw %cx, (%edx)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_dec_ushort_nv)
+       SET_SIZE(atomic_dec_16_nv)
+
+       ENTRY(atomic_dec_32_nv)
+       ALTENTRY(atomic_dec_uint_nv)
+       ALTENTRY(atomic_dec_ulong_nv)
+       movl    4(%esp), %edx
+       movl    (%edx), %eax
+1:
+       leal    -1(%eax), %ecx
+       lock
+       cmpxchgl %ecx, (%edx)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_dec_ulong_nv)
+       SET_SIZE(atomic_dec_uint_nv)
+       SET_SIZE(atomic_dec_32_nv)
+
+       /*
+        * NOTE: If atomic_dec_64 and atomic_dec_64_nv are ever
+        * separated, it is important to edit the libc i386 platform
+        * specific mapfile and remove the NODYNSORT attribute
+        * from atomic_dec_64_nv.
+        */
+       ENTRY(atomic_dec_64)
+       ALTENTRY(atomic_dec_64_nv)
+       pushl   %edi
+       pushl   %ebx
+       movl    12(%esp), %edi
+       movl    (%edi), %eax
+       movl    4(%edi), %edx
+1:
+       xorl    %ebx, %ebx
+       xorl    %ecx, %ecx
+       not     %ecx
+       not     %ebx
+       addl    %eax, %ebx
+       adcl    %edx, %ecx
+       lock
+       cmpxchg8b (%edi)
+       jne     1b
+       movl    %ebx, %eax
+       movl    %ecx, %edx
+       popl    %ebx
+       popl    %edi
+       ret
+       SET_SIZE(atomic_dec_64_nv)
+       SET_SIZE(atomic_dec_64)
+
+       ENTRY(atomic_add_8)
+       ALTENTRY(atomic_add_char)
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       lock
+       addb    %cl, (%eax)
+       ret
+       SET_SIZE(atomic_add_char)
+       SET_SIZE(atomic_add_8)
+
+       ENTRY(atomic_add_16)
+       ALTENTRY(atomic_add_short)
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       lock
+       addw    %cx, (%eax)
+       ret
+       SET_SIZE(atomic_add_short)
+       SET_SIZE(atomic_add_16)
+
+       ENTRY(atomic_add_32)
+       ALTENTRY(atomic_add_int)
+       ALTENTRY(atomic_add_ptr)
+       ALTENTRY(atomic_add_long)
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       lock
+       addl    %ecx, (%eax)
+       ret
+       SET_SIZE(atomic_add_long)
+       SET_SIZE(atomic_add_ptr)
+       SET_SIZE(atomic_add_int)
+       SET_SIZE(atomic_add_32)
+
+       ENTRY(atomic_sub_8)
+       ALTENTRY(atomic_sub_char)
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       lock
+       subb    %cl, (%eax)
+       ret
+       SET_SIZE(atomic_sub_char)
+       SET_SIZE(atomic_sub_8)
+
+       ENTRY(atomic_sub_16)
+       ALTENTRY(atomic_sub_short)
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       lock
+       subw    %cx, (%eax)
+       ret
+       SET_SIZE(atomic_sub_short)
+       SET_SIZE(atomic_sub_16)
+
+       ENTRY(atomic_sub_32)
+       ALTENTRY(atomic_sub_int)
+       ALTENTRY(atomic_sub_ptr)
+       ALTENTRY(atomic_sub_long)
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       lock
+       subl    %ecx, (%eax)
+       ret
+       SET_SIZE(atomic_sub_long)
+       SET_SIZE(atomic_sub_ptr)
+       SET_SIZE(atomic_sub_int)
+       SET_SIZE(atomic_sub_32)
+
+       ENTRY(atomic_or_8)
+       ALTENTRY(atomic_or_uchar)
+       movl    4(%esp), %eax
+       movb    8(%esp), %cl
+       lock
+       orb     %cl, (%eax)
+       ret
+       SET_SIZE(atomic_or_uchar)
+       SET_SIZE(atomic_or_8)
+
+       ENTRY(atomic_or_16)
+       ALTENTRY(atomic_or_ushort)
+       movl    4(%esp), %eax
+       movw    8(%esp), %cx
+       lock
+       orw     %cx, (%eax)
+       ret
+       SET_SIZE(atomic_or_ushort)
+       SET_SIZE(atomic_or_16)
+
+       ENTRY(atomic_or_32)
+       ALTENTRY(atomic_or_uint)
+       ALTENTRY(atomic_or_ulong)
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       lock
+       orl     %ecx, (%eax)
+       ret
+       SET_SIZE(atomic_or_ulong)
+       SET_SIZE(atomic_or_uint)
+       SET_SIZE(atomic_or_32)
+
+       ENTRY(atomic_and_8)
+       ALTENTRY(atomic_and_uchar)
+       movl    4(%esp), %eax
+       movb    8(%esp), %cl
+       lock
+       andb    %cl, (%eax)
+       ret
+       SET_SIZE(atomic_and_uchar)
+       SET_SIZE(atomic_and_8)
+
+       ENTRY(atomic_and_16)
+       ALTENTRY(atomic_and_ushort)
+       movl    4(%esp), %eax
+       movw    8(%esp), %cx
+       lock
+       andw    %cx, (%eax)
+       ret
+       SET_SIZE(atomic_and_ushort)
+       SET_SIZE(atomic_and_16)
+
+       ENTRY(atomic_and_32)
+       ALTENTRY(atomic_and_uint)
+       ALTENTRY(atomic_and_ulong)
+       movl    4(%esp), %eax
+       movl    8(%esp), %ecx
+       lock
+       andl    %ecx, (%eax)
+       ret
+       SET_SIZE(atomic_and_ulong)
+       SET_SIZE(atomic_and_uint)
+       SET_SIZE(atomic_and_32)
+
+       ENTRY(atomic_add_8_nv)
+       ALTENTRY(atomic_add_char_nv)
+       movl    4(%esp), %edx
+       movb    (%edx), %al
+1:
+       movl    8(%esp), %ecx
+       addb    %al, %cl
+       lock
+       cmpxchgb %cl, (%edx)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_add_char_nv)
+       SET_SIZE(atomic_add_8_nv)
+
+       ENTRY(atomic_add_16_nv)
+       ALTENTRY(atomic_add_short_nv)
+       movl    4(%esp), %edx
+       movw    (%edx), %ax
+1:
+       movl    8(%esp), %ecx
+       addw    %ax, %cx
+       lock
+       cmpxchgw %cx, (%edx)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_add_short_nv)
+       SET_SIZE(atomic_add_16_nv)
+
+       ENTRY(atomic_add_32_nv)
+       ALTENTRY(atomic_add_int_nv)
+       ALTENTRY(atomic_add_ptr_nv)
+       ALTENTRY(atomic_add_long_nv)
+       movl    4(%esp), %edx
+       movl    (%edx), %eax
+1:
+       movl    8(%esp), %ecx
+       addl    %eax, %ecx
+       lock
+       cmpxchgl %ecx, (%edx)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_add_long_nv)
+       SET_SIZE(atomic_add_ptr_nv)
+       SET_SIZE(atomic_add_int_nv)
+       SET_SIZE(atomic_add_32_nv)
+
+       ENTRY(atomic_sub_8_nv)
+       ALTENTRY(atomic_sub_char_nv)
+       movl    4(%esp), %edx
+       movb    (%edx), %al
+1:
+       movl    8(%esp), %ecx
+       subb    %al, %cl
+       lock
+       cmpxchgb %cl, (%edx)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_sub_char_nv)
+       SET_SIZE(atomic_sub_8_nv)
+
+       ENTRY(atomic_sub_16_nv)
+       ALTENTRY(atomic_sub_short_nv)
+       movl    4(%esp), %edx
+       movw    (%edx), %ax
+1:
+       movl    8(%esp), %ecx
+       subw    %ax, %cx
+       lock
+       cmpxchgw %cx, (%edx)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_sub_short_nv)
+       SET_SIZE(atomic_sub_16_nv)
+
+       ENTRY(atomic_sub_32_nv)
+       ALTENTRY(atomic_sub_int_nv)
+       ALTENTRY(atomic_sub_ptr_nv)
+       ALTENTRY(atomic_sub_long_nv)
+       movl    4(%esp), %edx
+       movl    (%edx), %eax
+1:
+       movl    8(%esp), %ecx
+       subl    %eax, %ecx
+       lock
+       cmpxchgl %ecx, (%edx)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_sub_long_nv)
+       SET_SIZE(atomic_sub_ptr_nv)
+       SET_SIZE(atomic_sub_int_nv)
+       SET_SIZE(atomic_sub_32_nv)
+
+       /*
+        * NOTE: If atomic_add_64 and atomic_add_64_nv are ever
+        * separated, it is important to edit the libc i386 platform
+        * specific mapfile and remove the NODYNSORT attribute
+        * from atomic_add_64_nv.
+        */
+       ENTRY(atomic_add_64)
+       ALTENTRY(atomic_add_64_nv)
+       pushl   %edi
+       pushl   %ebx
+       movl    12(%esp), %edi
+       movl    (%edi), %eax
+       movl    4(%edi), %edx
+1:
+       movl    16(%esp), %ebx
+       movl    20(%esp), %ecx
+       addl    %eax, %ebx
+       adcl    %edx, %ecx
+       lock
+       cmpxchg8b (%edi)
+       jne     1b
+       movl    %ebx, %eax
+       movl    %ecx, %edx
+       popl    %ebx
+       popl    %edi
+       ret
+       SET_SIZE(atomic_add_64_nv)
+       SET_SIZE(atomic_add_64)
+
+       ENTRY(atomic_sub_64)
+       ALTENTRY(atomic_sub_64_nv)
+       pushl   %edi
+       pushl   %ebx
+       movl    12(%esp), %edi
+       movl    (%edi), %eax
+       movl    4(%edi), %edx
+1:
+       movl    16(%esp), %ebx
+       movl    20(%esp), %ecx
+       subl    %eax, %ebx
+       adcl    %edx, %ecx
+       lock
+       cmpxchg8b (%edi)
+       jne     1b
+       movl    %ebx, %eax
+       movl    %ecx, %edx
+       popl    %ebx
+       popl    %edi
+       ret
+       SET_SIZE(atomic_sub_64_nv)
+       SET_SIZE(atomic_sub_64)
+
+       ENTRY(atomic_or_8_nv)
+       ALTENTRY(atomic_or_uchar_nv)
+       movl    4(%esp), %edx
+       movb    (%edx), %al
+1:
+       movl    8(%esp), %ecx
+       orb     %al, %cl
+       lock
+       cmpxchgb %cl, (%edx)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_or_uchar_nv)
+       SET_SIZE(atomic_or_8_nv)
+
+       ENTRY(atomic_or_16_nv)
+       ALTENTRY(atomic_or_ushort_nv)
+       movl    4(%esp), %edx
+       movw    (%edx), %ax
+1:
+       movl    8(%esp), %ecx
+       orw     %ax, %cx
+       lock
+       cmpxchgw %cx, (%edx)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_or_ushort_nv)
+       SET_SIZE(atomic_or_16_nv)
+
+       ENTRY(atomic_or_32_nv)
+       ALTENTRY(atomic_or_uint_nv)
+       ALTENTRY(atomic_or_ulong_nv)
+       movl    4(%esp), %edx
+       movl    (%edx), %eax
+1:
+       movl    8(%esp), %ecx
+       orl     %eax, %ecx
+       lock
+       cmpxchgl %ecx, (%edx)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_or_ulong_nv)
+       SET_SIZE(atomic_or_uint_nv)
+       SET_SIZE(atomic_or_32_nv)
+
+       /*
+        * NOTE: If atomic_or_64 and atomic_or_64_nv are ever
+        * separated, it is important to edit the libc i386 platform
+        * specific mapfile and remove the NODYNSORT attribute
+        * from atomic_or_64_nv.
+        */
+       ENTRY(atomic_or_64)
+       ALTENTRY(atomic_or_64_nv)
+       pushl   %edi
+       pushl   %ebx
+       movl    12(%esp), %edi
+       movl    (%edi), %eax
+       movl    4(%edi), %edx
+1:
+       movl    16(%esp), %ebx
+       movl    20(%esp), %ecx
+       orl     %eax, %ebx
+       orl     %edx, %ecx
+       lock
+       cmpxchg8b (%edi)
+       jne     1b
+       movl    %ebx, %eax
+       movl    %ecx, %edx
+       popl    %ebx
+       popl    %edi
+       ret
+       SET_SIZE(atomic_or_64_nv)
+       SET_SIZE(atomic_or_64)
+
+       ENTRY(atomic_and_8_nv)
+       ALTENTRY(atomic_and_uchar_nv)
+       movl    4(%esp), %edx
+       movb    (%edx), %al
+1:
+       movl    8(%esp), %ecx
+       andb    %al, %cl
+       lock
+       cmpxchgb %cl, (%edx)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_and_uchar_nv)
+       SET_SIZE(atomic_and_8_nv)
+
+       ENTRY(atomic_and_16_nv)
+       ALTENTRY(atomic_and_ushort_nv)
+       movl    4(%esp), %edx
+       movw    (%edx), %ax
+1:
+       movl    8(%esp), %ecx
+       andw    %ax, %cx
+       lock
+       cmpxchgw %cx, (%edx)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_and_ushort_nv)
+       SET_SIZE(atomic_and_16_nv)
+
+       ENTRY(atomic_and_32_nv)
+       ALTENTRY(atomic_and_uint_nv)
+       ALTENTRY(atomic_and_ulong_nv)
+       movl    4(%esp), %edx
+       movl    (%edx), %eax
+1:
+       movl    8(%esp), %ecx
+       andl    %eax, %ecx
+       lock
+       cmpxchgl %ecx, (%edx)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_and_ulong_nv)
+       SET_SIZE(atomic_and_uint_nv)
+       SET_SIZE(atomic_and_32_nv)
+
+       /*
+        * NOTE: If atomic_and_64 and atomic_and_64_nv are ever
+        * separated, it is important to edit the libc i386 platform
+        * specific mapfile and remove the NODYNSORT attribute
+        * from atomic_and_64_nv.
+        */
+       ENTRY(atomic_and_64)
+       ALTENTRY(atomic_and_64_nv)
+       pushl   %edi
+       pushl   %ebx
+       movl    12(%esp), %edi
+       movl    (%edi), %eax
+       movl    4(%edi), %edx
+1:
+       movl    16(%esp), %ebx
+       movl    20(%esp), %ecx
+       andl    %eax, %ebx
+       andl    %edx, %ecx
+       lock
+       cmpxchg8b (%edi)
+       jne     1b
+       movl    %ebx, %eax
+       movl    %ecx, %edx
+       popl    %ebx
+       popl    %edi
+       ret
+       SET_SIZE(atomic_and_64_nv)
+       SET_SIZE(atomic_and_64)
+
+       ENTRY(atomic_cas_8)
+       ALTENTRY(atomic_cas_uchar)
+       movl    4(%esp), %edx
+       movzbl  8(%esp), %eax
+       movb    12(%esp), %cl
+       lock
+       cmpxchgb %cl, (%edx)
+       ret
+       SET_SIZE(atomic_cas_uchar)
+       SET_SIZE(atomic_cas_8)
+
+       ENTRY(atomic_cas_16)
+       ALTENTRY(atomic_cas_ushort)
+       movl    4(%esp), %edx
+       movzwl  8(%esp), %eax
+       movw    12(%esp), %cx
+       lock
+       cmpxchgw %cx, (%edx)
+       ret
+       SET_SIZE(atomic_cas_ushort)
+       SET_SIZE(atomic_cas_16)
+
+       ENTRY(atomic_cas_32)
+       ALTENTRY(atomic_cas_uint)
+       ALTENTRY(atomic_cas_ulong)
+       ALTENTRY(atomic_cas_ptr)
+       movl    4(%esp), %edx
+       movl    8(%esp), %eax
+       movl    12(%esp), %ecx
+       lock
+       cmpxchgl %ecx, (%edx)
+       ret
+       SET_SIZE(atomic_cas_ptr)
+       SET_SIZE(atomic_cas_ulong)
+       SET_SIZE(atomic_cas_uint)
+       SET_SIZE(atomic_cas_32)
+
+       ENTRY(atomic_cas_64)
+       pushl   %ebx
+       pushl   %esi
+       movl    12(%esp), %esi
+       movl    16(%esp), %eax
+       movl    20(%esp), %edx
+       movl    24(%esp), %ebx
+       movl    28(%esp), %ecx
+       lock
+       cmpxchg8b (%esi)
+       popl    %esi
+       popl    %ebx
+       ret
+       SET_SIZE(atomic_cas_64)
+
+       ENTRY(atomic_swap_8)
+       ALTENTRY(atomic_swap_uchar)
+       movl    4(%esp), %edx
+       movzbl  8(%esp), %eax
+       lock
+       xchgb   %al, (%edx)
+       ret
+       SET_SIZE(atomic_swap_uchar)
+       SET_SIZE(atomic_swap_8)
+
+       ENTRY(atomic_swap_16)
+       ALTENTRY(atomic_swap_ushort)
+       movl    4(%esp), %edx
+       movzwl  8(%esp), %eax
+       lock
+       xchgw   %ax, (%edx)
+       ret
+       SET_SIZE(atomic_swap_ushort)
+       SET_SIZE(atomic_swap_16)
+
+       ENTRY(atomic_swap_32)
+       ALTENTRY(atomic_swap_uint)
+       ALTENTRY(atomic_swap_ptr)
+       ALTENTRY(atomic_swap_ulong)
+       movl    4(%esp), %edx
+       movl    8(%esp), %eax
+       lock
+       xchgl   %eax, (%edx)
+       ret
+       SET_SIZE(atomic_swap_ulong)
+       SET_SIZE(atomic_swap_ptr)
+       SET_SIZE(atomic_swap_uint)
+       SET_SIZE(atomic_swap_32)
+
+       ENTRY(atomic_swap_64)
+       pushl   %esi
+       pushl   %ebx
+       movl    12(%esp), %esi
+       movl    16(%esp), %ebx
+       movl    20(%esp), %ecx
+       movl    (%esi), %eax
+       movl    4(%esi), %edx
+1:
+       lock
+       cmpxchg8b (%esi)
+       jne     1b
+       popl    %ebx
+       popl    %esi
+       ret
+       SET_SIZE(atomic_swap_64)
+
+       ENTRY(atomic_set_long_excl)
+       movl    4(%esp), %edx
+       movl    8(%esp), %ecx
+       xorl    %eax, %eax
+       lock
+       btsl    %ecx, (%edx)
+       jnc     1f
+       decl    %eax
+1:
+       ret
+       SET_SIZE(atomic_set_long_excl)
+
+       ENTRY(atomic_clear_long_excl)
+       movl    4(%esp), %edx
+       movl    8(%esp), %ecx
+       xorl    %eax, %eax
+       lock
+       btrl    %ecx, (%edx)
+       jc      1f
+       decl    %eax
+1:
+       ret
+       SET_SIZE(atomic_clear_long_excl)
+
+       /*
+        * NOTE: membar_enter, membar_exit, membar_producer, and 
+        * membar_consumer are all identical routines. We define them
+        * separately, instead of using ALTENTRY definitions to alias them
+        * together, so that DTrace and debuggers will see a unique address
+        * for them, allowing more accurate tracing.
+       */
+
+
+       ENTRY(membar_enter)
+       lock
+       xorl    $0, (%esp)
+       ret
+       SET_SIZE(membar_enter)
+
+       ENTRY(membar_exit)
+       lock
+       xorl    $0, (%esp)
+       ret
+       SET_SIZE(membar_exit)
+
+       ENTRY(membar_producer)
+       lock
+       xorl    $0, (%esp)
+       ret
+       SET_SIZE(membar_producer)
+
+       ENTRY(membar_consumer)
+       lock
+       xorl    $0, (%esp)
+       ret
+       SET_SIZE(membar_consumer)
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/zfs/lib/libspl/asm-x86_64/Makefile.am b/zfs/lib/libspl/asm-x86_64/Makefile.am
new file mode 100644 (file)
index 0000000..e112610
--- /dev/null
@@ -0,0 +1 @@
+noinst_HEADERS = atomic.S
diff --git a/zfs/lib/libspl/asm-x86_64/Makefile.in b/zfs/lib/libspl/asm-x86_64/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/asm-x86_64/atomic.S b/zfs/lib/libspl/asm-x86_64/atomic.S
new file mode 100644 (file)
index 0000000..49c9b2a
--- /dev/null
@@ -0,0 +1,687 @@
+/*
+ * 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.
+ */
+
+       .ident  "%Z%%M% %I%     %E% SMI"
+
+       .file   "%M%"
+
+#define _ASM
+#include <ia32/sys/asm_linkage.h>
+
+       ENTRY(atomic_inc_8)
+       ALTENTRY(atomic_inc_uchar)
+       lock
+       incb    (%rdi)
+       ret
+       SET_SIZE(atomic_inc_uchar)
+       SET_SIZE(atomic_inc_8)
+
+       ENTRY(atomic_inc_16)
+       ALTENTRY(atomic_inc_ushort)
+       lock
+       incw    (%rdi)
+       ret
+       SET_SIZE(atomic_inc_ushort)
+       SET_SIZE(atomic_inc_16)
+
+       ENTRY(atomic_inc_32)
+       ALTENTRY(atomic_inc_uint)
+       lock
+       incl    (%rdi)
+       ret
+       SET_SIZE(atomic_inc_uint)
+       SET_SIZE(atomic_inc_32)
+
+       ENTRY(atomic_inc_64)
+       ALTENTRY(atomic_inc_ulong)
+       lock
+       incq    (%rdi)
+       ret
+       SET_SIZE(atomic_inc_ulong)
+       SET_SIZE(atomic_inc_64)
+
+       ENTRY(atomic_inc_8_nv)
+       ALTENTRY(atomic_inc_uchar_nv)
+       movb    (%rdi), %al
+1:
+       leaq    1(%rax), %rcx
+       lock
+       cmpxchgb %cl, (%rdi)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_inc_uchar_nv)
+       SET_SIZE(atomic_inc_8_nv)
+
+       ENTRY(atomic_inc_16_nv)
+       ALTENTRY(atomic_inc_ushort_nv)
+       movw    (%rdi), %ax
+1:
+       leaq    1(%rax), %rcx
+       lock
+       cmpxchgw %cx, (%rdi)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_inc_ushort_nv)
+       SET_SIZE(atomic_inc_16_nv)
+
+       ENTRY(atomic_inc_32_nv)
+       ALTENTRY(atomic_inc_uint_nv)
+       movl    (%rdi), %eax
+1:
+       leaq    1(%rax), %rcx
+       lock
+       cmpxchgl %ecx, (%rdi)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_inc_uint_nv)
+       SET_SIZE(atomic_inc_32_nv)
+
+       ENTRY(atomic_inc_64_nv)
+       ALTENTRY(atomic_inc_ulong_nv)
+       movq    (%rdi), %rax
+1:
+       leaq    1(%rax), %rcx
+       lock
+       cmpxchgq %rcx, (%rdi)
+       jne     1b
+       movq    %rcx, %rax
+       ret
+       SET_SIZE(atomic_inc_ulong_nv)
+       SET_SIZE(atomic_inc_64_nv)
+
+       ENTRY(atomic_dec_8)
+       ALTENTRY(atomic_dec_uchar)
+       lock
+       decb    (%rdi)
+       ret
+       SET_SIZE(atomic_dec_uchar)
+       SET_SIZE(atomic_dec_8)
+
+       ENTRY(atomic_dec_16)
+       ALTENTRY(atomic_dec_ushort)
+       lock
+       decw    (%rdi)
+       ret
+       SET_SIZE(atomic_dec_ushort)
+       SET_SIZE(atomic_dec_16)
+
+       ENTRY(atomic_dec_32)
+       ALTENTRY(atomic_dec_uint)
+       lock
+       decl    (%rdi)
+       ret
+       SET_SIZE(atomic_dec_uint)
+       SET_SIZE(atomic_dec_32)
+
+       ENTRY(atomic_dec_64)
+       ALTENTRY(atomic_dec_ulong)
+       lock
+       decq    (%rdi)
+       ret
+       SET_SIZE(atomic_dec_ulong)
+       SET_SIZE(atomic_dec_64)
+
+       ENTRY(atomic_dec_8_nv)
+       ALTENTRY(atomic_dec_uchar_nv)
+       movb    (%rdi), %al
+1:
+       leaq    -1(%rax), %rcx
+       lock
+       cmpxchgb %cl, (%rdi)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_dec_uchar_nv)
+       SET_SIZE(atomic_dec_8_nv)
+
+       ENTRY(atomic_dec_16_nv)
+       ALTENTRY(atomic_dec_ushort_nv)
+       movw    (%rdi), %ax
+1:
+       leaq    -1(%rax), %rcx
+       lock
+       cmpxchgw %cx, (%rdi)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_dec_ushort_nv)
+       SET_SIZE(atomic_dec_16_nv)
+
+       ENTRY(atomic_dec_32_nv)
+       ALTENTRY(atomic_dec_uint_nv)
+       movl    (%rdi), %eax
+1:
+       leaq    -1(%rax), %rcx
+       lock
+       cmpxchgl %ecx, (%rdi)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_dec_uint_nv)
+       SET_SIZE(atomic_dec_32_nv)
+
+       ENTRY(atomic_dec_64_nv)
+       ALTENTRY(atomic_dec_ulong_nv)
+       movq    (%rdi), %rax
+1:
+       leaq    -1(%rax), %rcx
+       lock
+       cmpxchgq %rcx, (%rdi)
+       jne     1b
+       movq    %rcx, %rax
+       ret
+       SET_SIZE(atomic_dec_ulong_nv)
+       SET_SIZE(atomic_dec_64_nv)
+
+       ENTRY(atomic_add_8)
+       ALTENTRY(atomic_add_char)
+       lock
+       addb    %sil, (%rdi)
+       ret
+       SET_SIZE(atomic_add_char)
+       SET_SIZE(atomic_add_8)
+
+       ENTRY(atomic_add_16)
+       ALTENTRY(atomic_add_short)
+       lock
+       addw    %si, (%rdi)
+       ret
+       SET_SIZE(atomic_add_short)
+       SET_SIZE(atomic_add_16)
+
+       ENTRY(atomic_add_32)
+       ALTENTRY(atomic_add_int)
+       lock
+       addl    %esi, (%rdi)
+       ret
+       SET_SIZE(atomic_add_int)
+       SET_SIZE(atomic_add_32)
+
+       ENTRY(atomic_add_64)
+       ALTENTRY(atomic_add_ptr)
+       ALTENTRY(atomic_add_long)
+       lock
+       addq    %rsi, (%rdi)
+       ret
+       SET_SIZE(atomic_add_long)
+       SET_SIZE(atomic_add_ptr)
+       SET_SIZE(atomic_add_64)
+
+       ENTRY(atomic_sub_8)
+       ALTENTRY(atomic_sub_char)
+       lock
+       subb    %sil, (%rdi)
+       ret
+       SET_SIZE(atomic_sub_char)
+       SET_SIZE(atomic_sub_8)
+
+       ENTRY(atomic_sub_16)
+       ALTENTRY(atomic_sub_short)
+       lock
+       subw    %si, (%rdi)
+       ret
+       SET_SIZE(atomic_sub_short)
+       SET_SIZE(atomic_sub_16)
+
+       ENTRY(atomic_sub_32)
+       ALTENTRY(atomic_sub_int)
+       lock
+       subl    %esi, (%rdi)
+       ret
+       SET_SIZE(atomic_sub_int)
+       SET_SIZE(atomic_sub_32)
+
+       ENTRY(atomic_sub_64)
+       ALTENTRY(atomic_sub_ptr)
+       ALTENTRY(atomic_sub_long)
+       lock
+       subq    %rsi, (%rdi)
+       ret
+       SET_SIZE(atomic_sub_long)
+       SET_SIZE(atomic_sub_ptr)
+       SET_SIZE(atomic_sub_64)
+
+       ENTRY(atomic_or_8)
+       ALTENTRY(atomic_or_uchar)
+       lock
+       orb     %sil, (%rdi)
+       ret
+       SET_SIZE(atomic_or_uchar)
+       SET_SIZE(atomic_or_8)
+
+       ENTRY(atomic_or_16)
+       ALTENTRY(atomic_or_ushort)
+       lock
+       orw     %si, (%rdi)
+       ret
+       SET_SIZE(atomic_or_ushort)
+       SET_SIZE(atomic_or_16)
+
+       ENTRY(atomic_or_32)
+       ALTENTRY(atomic_or_uint)
+       lock
+       orl     %esi, (%rdi)
+       ret
+       SET_SIZE(atomic_or_uint)
+       SET_SIZE(atomic_or_32)
+
+       ENTRY(atomic_or_64)
+       ALTENTRY(atomic_or_ulong)
+       lock
+       orq     %rsi, (%rdi)
+       ret
+       SET_SIZE(atomic_or_ulong)
+       SET_SIZE(atomic_or_64)
+
+       ENTRY(atomic_and_8)
+       ALTENTRY(atomic_and_uchar)
+       lock
+       andb    %sil, (%rdi)
+       ret
+       SET_SIZE(atomic_and_uchar)
+       SET_SIZE(atomic_and_8)
+
+       ENTRY(atomic_and_16)
+       ALTENTRY(atomic_and_ushort)
+       lock
+       andw    %si, (%rdi)
+       ret
+       SET_SIZE(atomic_and_ushort)
+       SET_SIZE(atomic_and_16)
+
+       ENTRY(atomic_and_32)
+       ALTENTRY(atomic_and_uint)
+       lock
+       andl    %esi, (%rdi)
+       ret
+       SET_SIZE(atomic_and_uint)
+       SET_SIZE(atomic_and_32)
+
+       ENTRY(atomic_and_64)
+       ALTENTRY(atomic_and_ulong)
+       lock
+       andq    %rsi, (%rdi)
+       ret
+       SET_SIZE(atomic_and_ulong)
+       SET_SIZE(atomic_and_64)
+
+       ENTRY(atomic_add_8_nv)
+       ALTENTRY(atomic_add_char_nv)
+       movb    (%rdi), %al
+1:
+       movb    %sil, %cl
+       addb    %al, %cl
+       lock
+       cmpxchgb %cl, (%rdi)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_add_char_nv)
+       SET_SIZE(atomic_add_8_nv)
+
+       ENTRY(atomic_add_16_nv)
+       ALTENTRY(atomic_add_short_nv)
+       movw    (%rdi), %ax
+1:
+       movw    %si, %cx
+       addw    %ax, %cx
+       lock
+       cmpxchgw %cx, (%rdi)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_add_short_nv)
+       SET_SIZE(atomic_add_16_nv)
+
+       ENTRY(atomic_add_32_nv)
+       ALTENTRY(atomic_add_int_nv)
+       movl    (%rdi), %eax
+1:
+       movl    %esi, %ecx
+       addl    %eax, %ecx
+       lock
+       cmpxchgl %ecx, (%rdi)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_add_int_nv)
+       SET_SIZE(atomic_add_32_nv)
+
+       ENTRY(atomic_add_64_nv)
+       ALTENTRY(atomic_add_ptr_nv)
+       ALTENTRY(atomic_add_long_nv)
+       movq    (%rdi), %rax
+1:
+       movq    %rsi, %rcx
+       addq    %rax, %rcx
+       lock
+       cmpxchgq %rcx, (%rdi)
+       jne     1b
+       movq    %rcx, %rax
+       ret
+       SET_SIZE(atomic_add_long_nv)
+       SET_SIZE(atomic_add_ptr_nv)
+       SET_SIZE(atomic_add_64_nv)
+
+       ENTRY(atomic_sub_8_nv)
+       ALTENTRY(atomic_sub_char_nv)
+       movb    (%rdi), %al
+1:
+       movb    %sil, %cl
+       subb    %al, %cl
+       lock
+       cmpxchgb %cl, (%rdi)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_sub_char_nv)
+       SET_SIZE(atomic_sub_8_nv)
+
+       ENTRY(atomic_sub_16_nv)
+       ALTENTRY(atomic_sub_short_nv)
+       movw    (%rdi), %ax
+1:
+       movw    %si, %cx
+       subw    %ax, %cx
+       lock
+       cmpxchgw %cx, (%rdi)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_sub_short_nv)
+       SET_SIZE(atomic_sub_16_nv)
+
+       ENTRY(atomic_sub_32_nv)
+       ALTENTRY(atomic_sub_int_nv)
+       movl    (%rdi), %eax
+1:
+       movl    %esi, %ecx
+       subl    %eax, %ecx
+       lock
+       cmpxchgl %ecx, (%rdi)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_sub_int_nv)
+       SET_SIZE(atomic_sub_32_nv)
+
+       ENTRY(atomic_sub_64_nv)
+       ALTENTRY(atomic_sub_ptr_nv)
+       ALTENTRY(atomic_sub_long_nv)
+       movq    (%rdi), %rax
+1:
+       movq    %rsi, %rcx
+       subq    %rax, %rcx
+       lock
+       cmpxchgq %rcx, (%rdi)
+       jne     1b
+       movq    %rcx, %rax
+       ret
+       SET_SIZE(atomic_sub_long_nv)
+       SET_SIZE(atomic_sub_ptr_nv)
+       SET_SIZE(atomic_sub_64_nv)
+
+       ENTRY(atomic_and_8_nv)
+       ALTENTRY(atomic_and_uchar_nv)
+       movb    (%rdi), %al
+1:
+       movb    %sil, %cl
+       andb    %al, %cl
+       lock
+       cmpxchgb %cl, (%rdi)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_and_uchar_nv)
+       SET_SIZE(atomic_and_8_nv)
+
+       ENTRY(atomic_and_16_nv)
+       ALTENTRY(atomic_and_ushort_nv)
+       movw    (%rdi), %ax
+1:
+       movw    %si, %cx
+       andw    %ax, %cx
+       lock
+       cmpxchgw %cx, (%rdi)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_and_ushort_nv)
+       SET_SIZE(atomic_and_16_nv)
+
+       ENTRY(atomic_and_32_nv)
+       ALTENTRY(atomic_and_uint_nv)
+       movl    (%rdi), %eax
+1:
+       movl    %esi, %ecx
+       andl    %eax, %ecx
+       lock
+       cmpxchgl %ecx, (%rdi)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_and_uint_nv)
+       SET_SIZE(atomic_and_32_nv)
+
+       ENTRY(atomic_and_64_nv)
+       ALTENTRY(atomic_and_ulong_nv)
+       movq    (%rdi), %rax
+1:
+       movq    %rsi, %rcx
+       andq    %rax, %rcx
+       lock
+       cmpxchgq %rcx, (%rdi)
+       jne     1b
+       movq    %rcx, %rax
+       ret
+       SET_SIZE(atomic_and_ulong_nv)
+       SET_SIZE(atomic_and_64_nv)
+
+       ENTRY(atomic_or_8_nv)
+       ALTENTRY(atomic_or_uchar_nv)
+       movb    (%rdi), %al
+1:
+       movb    %sil, %cl
+       orb     %al, %cl
+       lock
+       cmpxchgb %cl, (%rdi)
+       jne     1b
+       movzbl  %cl, %eax
+       ret
+       SET_SIZE(atomic_and_uchar_nv)
+       SET_SIZE(atomic_and_8_nv)
+
+       ENTRY(atomic_or_16_nv)
+       ALTENTRY(atomic_or_ushort_nv)
+       movw    (%rdi), %ax
+1:
+       movw    %si, %cx
+       orw     %ax, %cx
+       lock
+       cmpxchgw %cx, (%rdi)
+       jne     1b
+       movzwl  %cx, %eax
+       ret
+       SET_SIZE(atomic_or_ushort_nv)
+       SET_SIZE(atomic_or_16_nv)
+
+       ENTRY(atomic_or_32_nv)
+       ALTENTRY(atomic_or_uint_nv)
+       movl    (%rdi), %eax
+1:
+       movl    %esi, %ecx
+       orl     %eax, %ecx
+       lock
+       cmpxchgl %ecx, (%rdi)
+       jne     1b
+       movl    %ecx, %eax
+       ret
+       SET_SIZE(atomic_or_uint_nv)
+       SET_SIZE(atomic_or_32_nv)
+
+       ENTRY(atomic_or_64_nv)
+       ALTENTRY(atomic_or_ulong_nv)
+       movq    (%rdi), %rax
+1:
+       movq    %rsi, %rcx
+       orq     %rax, %rcx
+       lock
+       cmpxchgq %rcx, (%rdi)
+       jne     1b
+       movq    %rcx, %rax
+       ret
+       SET_SIZE(atomic_or_ulong_nv)
+       SET_SIZE(atomic_or_64_nv)
+
+       ENTRY(atomic_cas_8)
+       ALTENTRY(atomic_cas_uchar)
+       movzbl  %sil, %eax
+       lock
+       cmpxchgb %dl, (%rdi)
+       ret
+       SET_SIZE(atomic_cas_uchar)
+       SET_SIZE(atomic_cas_8)
+
+       ENTRY(atomic_cas_16)
+       ALTENTRY(atomic_cas_ushort)
+       movzwl  %si, %eax
+       lock
+       cmpxchgw %dx, (%rdi)
+       ret
+       SET_SIZE(atomic_cas_ushort)
+       SET_SIZE(atomic_cas_16)
+
+       ENTRY(atomic_cas_32)
+       ALTENTRY(atomic_cas_uint)
+       movl    %esi, %eax
+       lock
+       cmpxchgl %edx, (%rdi)
+       ret
+       SET_SIZE(atomic_cas_uint)
+       SET_SIZE(atomic_cas_32)
+
+       ENTRY(atomic_cas_64)
+       ALTENTRY(atomic_cas_ulong)
+       ALTENTRY(atomic_cas_ptr)
+       movq    %rsi, %rax
+       lock
+       cmpxchgq %rdx, (%rdi)
+       ret
+       SET_SIZE(atomic_cas_ptr)
+       SET_SIZE(atomic_cas_ulong)
+       SET_SIZE(atomic_cas_64)
+
+       ENTRY(atomic_swap_8)
+       ALTENTRY(atomic_swap_uchar)
+       movzbl  %sil, %eax
+       lock
+       xchgb %al, (%rdi)
+       ret
+       SET_SIZE(atomic_swap_uchar)
+       SET_SIZE(atomic_swap_8)
+
+       ENTRY(atomic_swap_16)
+       ALTENTRY(atomic_swap_ushort)
+       movzwl  %si, %eax
+       lock
+       xchgw %ax, (%rdi)
+       ret
+       SET_SIZE(atomic_swap_ushort)
+       SET_SIZE(atomic_swap_16)
+
+       ENTRY(atomic_swap_32)
+       ALTENTRY(atomic_swap_uint)
+       movl    %esi, %eax
+       lock
+       xchgl %eax, (%rdi)
+       ret
+       SET_SIZE(atomic_swap_uint)
+       SET_SIZE(atomic_swap_32)
+
+       ENTRY(atomic_swap_64)
+       ALTENTRY(atomic_swap_ulong)
+       ALTENTRY(atomic_swap_ptr)
+       movq    %rsi, %rax
+       lock
+       xchgq %rax, (%rdi)
+       ret
+       SET_SIZE(atomic_swap_ptr)
+       SET_SIZE(atomic_swap_ulong)
+       SET_SIZE(atomic_swap_64)
+
+       ENTRY(atomic_set_long_excl)
+       xorl    %eax, %eax
+       lock
+       btsq    %rsi, (%rdi)
+       jnc     1f
+       decl    %eax
+1:
+       ret
+       SET_SIZE(atomic_set_long_excl)
+
+       ENTRY(atomic_clear_long_excl)
+       xorl    %eax, %eax
+       lock
+       btrq    %rsi, (%rdi)
+       jc      1f
+       decl    %eax
+1:
+       ret
+       SET_SIZE(atomic_clear_long_excl)
+
+       /*
+        * NOTE: membar_enter, and membar_exit are identical routines. 
+        * We define them separately, instead of using an ALTENTRY
+        * definitions to alias them together, so that DTrace and
+        * debuggers will see a unique address for them, allowing 
+        * more accurate tracing.
+       */
+
+       ENTRY(membar_enter)
+       mfence
+       ret
+       SET_SIZE(membar_enter)
+
+       ENTRY(membar_exit)
+       mfence
+       ret
+       SET_SIZE(membar_exit)
+
+       ENTRY(membar_producer)
+       sfence
+       ret
+       SET_SIZE(membar_producer)
+
+       ENTRY(membar_consumer)
+       lfence
+       ret
+       SET_SIZE(membar_consumer)
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/zfs/lib/libspl/getexecname.c b/zfs/lib/libspl/getexecname.c
new file mode 100644 (file)
index 0000000..c21a110
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <limits.h>
+
+const char *
+getexecname(void)
+{
+       static char execname[PATH_MAX + 1] = "";
+       static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+       char *ptr = NULL;
+       ssize_t rc;
+
+       (void) pthread_mutex_lock(&mtx);
+
+       if (strlen(execname) == 0) {
+               rc = readlink("/proc/self/exe",
+                   execname, sizeof (execname) - 1);
+               if (rc == -1) {
+                       execname[0] = '\0';
+               } else {
+                       execname[rc] = '\0';
+                       ptr = execname;
+               }
+       } else {
+               ptr = execname;
+       }
+
+       (void) pthread_mutex_unlock(&mtx);
+       return (ptr);
+}
diff --git a/zfs/lib/libspl/gethrestime.c b/zfs/lib/libspl/gethrestime.c
new file mode 100644 (file)
index 0000000..d37cc2d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include <time.h>
+#include <sys/time.h>
+
+void
+gethrestime(timestruc_t *ts)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       ts->tv_sec = tv.tv_sec;
+       ts->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
+}
diff --git a/zfs/lib/libspl/gethrtime.c b/zfs/lib/libspl/gethrtime.c
new file mode 100644 (file)
index 0000000..95ceb18
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#include <time.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+hrtime_t
+gethrtime(void)
+{
+       struct timespec ts;
+       int rc;
+
+       rc = clock_gettime(CLOCK_MONOTONIC, &ts);
+       if (rc) {
+               fprintf(stderr, "Error: clock_gettime() = %d\n", rc);
+               abort();
+       }
+
+       return ((((u_int64_t)ts.tv_sec) * NANOSEC) + ts.tv_nsec);
+}
diff --git a/zfs/lib/libspl/getmntany.c b/zfs/lib/libspl/getmntany.c
new file mode 100644 (file)
index 0000000..d78357a
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ * Copyright 2006 Ricardo Correia.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*     Copyright (c) 1988 AT&T */
+/*       All Rights Reserved   */
+
+#include <stdio.h>
+#include <string.h>
+#include <mntent.h>
+#include <sys/mnttab.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define        BUFSIZE (MNT_LINE_MAX + 2)
+
+__thread char buf[BUFSIZE];
+
+#define        DIFF(xx)        ( \
+           (mrefp->xx != NULL) && \
+           (mgetp->xx == NULL || strcmp(mrefp->xx, mgetp->xx) != 0))
+
+int
+getmntany(FILE *fp, struct mnttab *mgetp, struct mnttab *mrefp)
+{
+       int ret;
+
+       while (
+           ((ret = _sol_getmntent(fp, mgetp)) == 0) && (
+           DIFF(mnt_special) || DIFF(mnt_mountp) ||
+           DIFF(mnt_fstype) || DIFF(mnt_mntopts)));
+
+       return (ret);
+}
+
+int
+_sol_getmntent(FILE *fp, struct mnttab *mgetp)
+{
+       struct mntent mntbuf;
+       struct mntent *ret;
+
+       ret = getmntent_r(fp, &mntbuf, buf, BUFSIZE);
+
+       if (ret != NULL) {
+               mgetp->mnt_special = mntbuf.mnt_fsname;
+               mgetp->mnt_mountp = mntbuf.mnt_dir;
+               mgetp->mnt_fstype = mntbuf.mnt_type;
+               mgetp->mnt_mntopts = mntbuf.mnt_opts;
+               return (0);
+       }
+
+       if (feof(fp))
+               return (-1);
+
+       return (MNT_TOOLONG);
+}
+
+int
+getextmntent(FILE *fp, struct extmnttab *mp, int len)
+{
+       int ret;
+       struct stat64 st;
+
+       ret = _sol_getmntent(fp, (struct mnttab *) mp);
+       if (ret == 0) {
+               if (stat64(mp->mnt_mountp, &st) != 0) {
+                       mp->mnt_major = 0;
+                       mp->mnt_minor = 0;
+                       return (ret);
+               }
+               mp->mnt_major = major(st.st_dev);
+               mp->mnt_minor = minor(st.st_dev);
+       }
+
+       return (ret);
+}
diff --git a/zfs/lib/libspl/include/Makefile.am b/zfs/lib/libspl/include/Makefile.am
new file mode 100644 (file)
index 0000000..7882c1b
--- /dev/null
@@ -0,0 +1,27 @@
+SUBDIRS = ia32 rpc sys util
+
+libspldir = $(includedir)/libspl
+libspl_HEADERS = \
+       $(top_srcdir)/lib/libspl/include/assert.h \
+       $(top_srcdir)/lib/libspl/include/atomic.h \
+       $(top_srcdir)/lib/libspl/include/attr.h \
+       $(top_srcdir)/lib/libspl/include/devid.h \
+       $(top_srcdir)/lib/libspl/include/libdevinfo.h \
+       $(top_srcdir)/lib/libspl/include/libgen.h \
+       $(top_srcdir)/lib/libspl/include/libshare.h \
+       $(top_srcdir)/lib/libspl/include/limits.h \
+       $(top_srcdir)/lib/libspl/include/locale.h \
+       $(top_srcdir)/lib/libspl/include/note.h \
+       $(top_srcdir)/lib/libspl/include/statcommon.h \
+       $(top_srcdir)/lib/libspl/include/stdio.h \
+       $(top_srcdir)/lib/libspl/include/stdlib.h \
+       $(top_srcdir)/lib/libspl/include/string.h \
+       $(top_srcdir)/lib/libspl/include/strings.h \
+       $(top_srcdir)/lib/libspl/include/stropts.h \
+       $(top_srcdir)/lib/libspl/include/synch.h \
+       $(top_srcdir)/lib/libspl/include/thread.h \
+       $(top_srcdir)/lib/libspl/include/tzfile.h \
+       $(top_srcdir)/lib/libspl/include/ucred.h \
+       $(top_srcdir)/lib/libspl/include/umem.h \
+       $(top_srcdir)/lib/libspl/include/unistd.h \
+       $(top_srcdir)/lib/libspl/include/zone.h
diff --git a/zfs/lib/libspl/include/Makefile.in b/zfs/lib/libspl/include/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/include/assert.h b/zfs/lib/libspl/include/assert.h
new file mode 100644 (file)
index 0000000..bd89ad9
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include_next <assert.h>
+
+#ifndef _LIBSPL_ASSERT_H
+#define        _LIBSPL_ASSERT_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static inline int
+libspl_assert(const char *buf, const char *file, const char *func, int line)
+{
+       fprintf(stderr, "%s\n", buf);
+       fprintf(stderr, "ASSERT at %s:%d:%s()", file, line, func);
+       abort();
+}
+
+#ifdef verify
+#undef verify
+#endif
+
+#define        VERIFY(cond)                                                    \
+       (void) ((!(cond)) &&                                            \
+           libspl_assert(#cond, __FILE__, __FUNCTION__, __LINE__))
+#define        verify(cond)                                                    \
+       (void) ((!(cond)) &&                                            \
+           libspl_assert(#cond, __FILE__, __FUNCTION__, __LINE__))
+
+#define        VERIFY3_IMPL(LEFT, OP, RIGHT, TYPE)                             \
+do {                                                                   \
+       const TYPE __left = (TYPE)(LEFT);                               \
+       const TYPE __right = (TYPE)(RIGHT);                             \
+       if (!(__left OP __right)) {                                     \
+               char *__buf = alloca(256);                              \
+               (void) snprintf(__buf, 256,                             \
+                   "%s %s %s (0x%llx %s 0x%llx)", #LEFT, #OP, #RIGHT,  \
+                   (u_longlong_t)__left, #OP, (u_longlong_t)__right);  \
+               libspl_assert(__buf, __FILE__, __FUNCTION__, __LINE__); \
+       }                                                               \
+} while (0)
+
+#define        VERIFY3S(x, y, z)       VERIFY3_IMPL(x, y, z, int64_t)
+#define        VERIFY3U(x, y, z)       VERIFY3_IMPL(x, y, z, uint64_t)
+#define        VERIFY3P(x, y, z)       VERIFY3_IMPL(x, y, z, uintptr_t)
+#define        VERIFY0(x)              VERIFY3_IMPL(x, ==, 0, uint64_t)
+
+#ifdef assert
+#undef assert
+#endif
+
+/* Compile time assert */
+#define        CTASSERT_GLOBAL(x)              _CTASSERT(x, __LINE__)
+#define        CTASSERT(x)                     { _CTASSERT(x, __LINE__); }
+#define        _CTASSERT(x, y)                 __CTASSERT(x, y)
+#define        __CTASSERT(x, y)                                                \
+       typedef char __attribute__((unused))                            \
+       __compile_time_assertion__ ## y[(x) ? 1 : -1]
+
+#ifdef NDEBUG
+#define        ASSERT3S(x, y, z)       ((void)0)
+#define        ASSERT3U(x, y, z)       ((void)0)
+#define        ASSERT3P(x, y, z)       ((void)0)
+#define        ASSERT0(x)              ((void)0)
+#define        ASSERT(x)               ((void)0)
+#define        assert(x)               ((void)0)
+#define        ASSERTV(x)
+#define        IMPLY(A, B)             ((void)0)
+#define        EQUIV(A, B)             ((void)0)
+#else
+#define        ASSERT3S(x, y, z)       VERIFY3S(x, y, z)
+#define        ASSERT3U(x, y, z)       VERIFY3U(x, y, z)
+#define        ASSERT3P(x, y, z)       VERIFY3P(x, y, z)
+#define        ASSERT0(x)              VERIFY0(x)
+#define        ASSERT(x)               VERIFY(x)
+#define        assert(x)               VERIFY(x)
+#define        ASSERTV(x)              x
+#define        IMPLY(A, B) \
+       ((void)(((!(A)) || (B)) || \
+           libspl_assert("(" #A ") implies (" #B ")", \
+           __FILE__, __FUNCTION__, __LINE__)))
+#define        EQUIV(A, B) \
+       ((void)((!!(A) == !!(B)) || \
+           libspl_assert("(" #A ") is equivalent to (" #B ")", \
+           __FILE__, __FUNCTION__, __LINE__)))
+
+#endif  /* NDEBUG */
+
+#endif  /* _LIBSPL_ASSERT_H */
diff --git a/zfs/lib/libspl/include/atomic.h b/zfs/lib/libspl/include/atomic.h
new file mode 100644 (file)
index 0000000..9b0775b
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * 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 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_ATOMIC_H
+#define        _SYS_ATOMIC_H
+
+#include <sys/types.h>
+#include <sys/inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__STDC__)
+/*
+ * Increment target.
+ */
+extern void atomic_inc_8(volatile uint8_t *);
+extern void atomic_inc_uchar(volatile uchar_t *);
+extern void atomic_inc_16(volatile uint16_t *);
+extern void atomic_inc_ushort(volatile ushort_t *);
+extern void atomic_inc_32(volatile uint32_t *);
+extern void atomic_inc_uint(volatile uint_t *);
+extern void atomic_inc_ulong(volatile ulong_t *);
+#if defined(_INT64_TYPE)
+extern void atomic_inc_64(volatile uint64_t *);
+#endif
+
+/*
+ * Decrement target
+ */
+extern void atomic_dec_8(volatile uint8_t *);
+extern void atomic_dec_uchar(volatile uchar_t *);
+extern void atomic_dec_16(volatile uint16_t *);
+extern void atomic_dec_ushort(volatile ushort_t *);
+extern void atomic_dec_32(volatile uint32_t *);
+extern void atomic_dec_uint(volatile uint_t *);
+extern void atomic_dec_ulong(volatile ulong_t *);
+#if defined(_INT64_TYPE)
+extern void atomic_dec_64(volatile uint64_t *);
+#endif
+
+/*
+ * Add delta to target
+ */
+extern void atomic_add_8(volatile uint8_t *, int8_t);
+extern void atomic_add_char(volatile uchar_t *, signed char);
+extern void atomic_add_16(volatile uint16_t *, int16_t);
+extern void atomic_add_short(volatile ushort_t *, short);
+extern void atomic_add_32(volatile uint32_t *, int32_t);
+extern void atomic_add_int(volatile uint_t *, int);
+extern void atomic_add_ptr(volatile void *, ssize_t);
+extern void atomic_add_long(volatile ulong_t *, long);
+#if defined(_INT64_TYPE)
+extern void atomic_add_64(volatile uint64_t *, int64_t);
+#endif
+
+/*
+ * Substract delta from target
+ */
+extern void atomic_sub_8(volatile uint8_t *, int8_t);
+extern void atomic_sub_char(volatile uchar_t *, signed char);
+extern void atomic_sub_16(volatile uint16_t *, int16_t);
+extern void atomic_sub_short(volatile ushort_t *, short);
+extern void atomic_sub_32(volatile uint32_t *, int32_t);
+extern void atomic_sub_int(volatile uint_t *, int);
+extern void atomic_sub_ptr(volatile void *, ssize_t);
+extern void atomic_sub_long(volatile ulong_t *, long);
+#if defined(_INT64_TYPE)
+extern void atomic_sub_64(volatile uint64_t *, int64_t);
+#endif
+
+/*
+ * logical OR bits with target
+ */
+extern void atomic_or_8(volatile uint8_t *, uint8_t);
+extern void atomic_or_uchar(volatile uchar_t *, uchar_t);
+extern void atomic_or_16(volatile uint16_t *, uint16_t);
+extern void atomic_or_ushort(volatile ushort_t *, ushort_t);
+extern void atomic_or_32(volatile uint32_t *, uint32_t);
+extern void atomic_or_uint(volatile uint_t *, uint_t);
+extern void atomic_or_ulong(volatile ulong_t *, ulong_t);
+#if defined(_INT64_TYPE)
+extern void atomic_or_64(volatile uint64_t *, uint64_t);
+#endif
+
+/*
+ * logical AND bits with target
+ */
+extern void atomic_and_8(volatile uint8_t *, uint8_t);
+extern void atomic_and_uchar(volatile uchar_t *, uchar_t);
+extern void atomic_and_16(volatile uint16_t *, uint16_t);
+extern void atomic_and_ushort(volatile ushort_t *, ushort_t);
+extern void atomic_and_32(volatile uint32_t *, uint32_t);
+extern void atomic_and_uint(volatile uint_t *, uint_t);
+extern void atomic_and_ulong(volatile ulong_t *, ulong_t);
+#if defined(_INT64_TYPE)
+extern void atomic_and_64(volatile uint64_t *, uint64_t);
+#endif
+
+/*
+ * As above, but return the new value.  Note that these _nv() variants are
+ * substantially more expensive on some platforms than the no-return-value
+ * versions above, so don't use them unless you really need to know the
+ * new value *atomically* (e.g. when decrementing a reference count and
+ * checking whether it went to zero).
+ */
+
+/*
+ * Increment target and return new value.
+ */
+extern uint8_t atomic_inc_8_nv(volatile uint8_t *);
+extern uchar_t atomic_inc_uchar_nv(volatile uchar_t *);
+extern uint16_t atomic_inc_16_nv(volatile uint16_t *);
+extern ushort_t atomic_inc_ushort_nv(volatile ushort_t *);
+extern uint32_t atomic_inc_32_nv(volatile uint32_t *);
+extern uint_t atomic_inc_uint_nv(volatile uint_t *);
+extern ulong_t atomic_inc_ulong_nv(volatile ulong_t *);
+#if defined(_INT64_TYPE)
+extern uint64_t atomic_inc_64_nv(volatile uint64_t *);
+#endif
+
+/*
+ * Decrement target and return new value.
+ */
+extern uint8_t atomic_dec_8_nv(volatile uint8_t *);
+extern uchar_t atomic_dec_uchar_nv(volatile uchar_t *);
+extern uint16_t atomic_dec_16_nv(volatile uint16_t *);
+extern ushort_t atomic_dec_ushort_nv(volatile ushort_t *);
+extern uint32_t atomic_dec_32_nv(volatile uint32_t *);
+extern uint_t atomic_dec_uint_nv(volatile uint_t *);
+extern ulong_t atomic_dec_ulong_nv(volatile ulong_t *);
+#if defined(_INT64_TYPE)
+extern uint64_t atomic_dec_64_nv(volatile uint64_t *);
+#endif
+
+/*
+ * Add delta to target
+ */
+extern uint8_t atomic_add_8_nv(volatile uint8_t *, int8_t);
+extern uchar_t atomic_add_char_nv(volatile uchar_t *, signed char);
+extern uint16_t atomic_add_16_nv(volatile uint16_t *, int16_t);
+extern ushort_t atomic_add_short_nv(volatile ushort_t *, short);
+extern uint32_t atomic_add_32_nv(volatile uint32_t *, int32_t);
+extern uint_t atomic_add_int_nv(volatile uint_t *, int);
+extern void *atomic_add_ptr_nv(volatile void *, ssize_t);
+extern ulong_t atomic_add_long_nv(volatile ulong_t *, long);
+#if defined(_INT64_TYPE)
+extern uint64_t atomic_add_64_nv(volatile uint64_t *, int64_t);
+#endif
+
+/*
+ * Substract delta from target
+ */
+extern uint8_t atomic_sub_8_nv(volatile uint8_t *, int8_t);
+extern uchar_t atomic_sub_char_nv(volatile uchar_t *, signed char);
+extern uint16_t atomic_sub_16_nv(volatile uint16_t *, int16_t);
+extern ushort_t atomic_sub_short_nv(volatile ushort_t *, short);
+extern uint32_t atomic_sub_32_nv(volatile uint32_t *, int32_t);
+extern uint_t atomic_sub_int_nv(volatile uint_t *, int);
+extern void *atomic_sub_ptr_nv(volatile void *, ssize_t);
+extern ulong_t atomic_sub_long_nv(volatile ulong_t *, long);
+#if defined(_INT64_TYPE)
+extern uint64_t atomic_sub_64_nv(volatile uint64_t *, int64_t);
+#endif
+
+/*
+ * logical OR bits with target and return new value.
+ */
+extern uint8_t atomic_or_8_nv(volatile uint8_t *, uint8_t);
+extern uchar_t atomic_or_uchar_nv(volatile uchar_t *, uchar_t);
+extern uint16_t atomic_or_16_nv(volatile uint16_t *, uint16_t);
+extern ushort_t atomic_or_ushort_nv(volatile ushort_t *, ushort_t);
+extern uint32_t atomic_or_32_nv(volatile uint32_t *, uint32_t);
+extern uint_t atomic_or_uint_nv(volatile uint_t *, uint_t);
+extern ulong_t atomic_or_ulong_nv(volatile ulong_t *, ulong_t);
+#if defined(_INT64_TYPE)
+extern uint64_t atomic_or_64_nv(volatile uint64_t *, uint64_t);
+#endif
+
+/*
+ * logical AND bits with target and return new value.
+ */
+extern uint8_t atomic_and_8_nv(volatile uint8_t *, uint8_t);
+extern uchar_t atomic_and_uchar_nv(volatile uchar_t *, uchar_t);
+extern uint16_t atomic_and_16_nv(volatile uint16_t *, uint16_t);
+extern ushort_t atomic_and_ushort_nv(volatile ushort_t *, ushort_t);
+extern uint32_t atomic_and_32_nv(volatile uint32_t *, uint32_t);
+extern uint_t atomic_and_uint_nv(volatile uint_t *, uint_t);
+extern ulong_t atomic_and_ulong_nv(volatile ulong_t *, ulong_t);
+#if defined(_INT64_TYPE)
+extern uint64_t atomic_and_64_nv(volatile uint64_t *, uint64_t);
+#endif
+
+/*
+ * If *arg1 == arg2, set *arg1 = arg3; return old value
+ */
+extern uint8_t atomic_cas_8(volatile uint8_t *, uint8_t, uint8_t);
+extern uchar_t atomic_cas_uchar(volatile uchar_t *, uchar_t, uchar_t);
+extern uint16_t atomic_cas_16(volatile uint16_t *, uint16_t, uint16_t);
+extern ushort_t atomic_cas_ushort(volatile ushort_t *, ushort_t, ushort_t);
+extern uint32_t atomic_cas_32(volatile uint32_t *, uint32_t, uint32_t);
+extern uint_t atomic_cas_uint(volatile uint_t *, uint_t, uint_t);
+extern void *atomic_cas_ptr(volatile void *, void *, void *);
+extern ulong_t atomic_cas_ulong(volatile ulong_t *, ulong_t, ulong_t);
+#if defined(_INT64_TYPE)
+extern uint64_t atomic_cas_64(volatile uint64_t *, uint64_t, uint64_t);
+#endif
+
+/*
+ * Swap target and return old value
+ */
+extern uint8_t atomic_swap_8(volatile uint8_t *, uint8_t);
+extern uchar_t atomic_swap_uchar(volatile uchar_t *, uchar_t);
+extern uint16_t atomic_swap_16(volatile uint16_t *, uint16_t);
+extern ushort_t atomic_swap_ushort(volatile ushort_t *, ushort_t);
+extern uint32_t atomic_swap_32(volatile uint32_t *, uint32_t);
+extern uint_t atomic_swap_uint(volatile uint_t *, uint_t);
+extern void *atomic_swap_ptr(volatile void *, void *);
+extern ulong_t atomic_swap_ulong(volatile ulong_t *, ulong_t);
+#if defined(_INT64_TYPE)
+extern uint64_t atomic_swap_64(volatile uint64_t *, uint64_t);
+#endif
+
+/*
+ * Perform an exclusive atomic bit set/clear on a target.
+ * Returns 0 if bit was sucessfully set/cleared, or -1
+ * if the bit was already set/cleared.
+ */
+extern int atomic_set_long_excl(volatile ulong_t *, uint_t);
+extern int atomic_clear_long_excl(volatile ulong_t *, uint_t);
+
+/*
+ * Generic memory barrier used during lock entry, placed after the
+ * memory operation that acquires the lock to guarantee that the lock
+ * protects its data.  No stores from after the memory barrier will
+ * reach visibility, and no loads from after the barrier will be
+ * resolved, before the lock acquisition reaches global visibility.
+ */
+extern void membar_enter(void);
+
+/*
+ * Generic memory barrier used during lock exit, placed before the
+ * memory operation that releases the lock to guarantee that the lock
+ * protects its data.  All loads and stores issued before the barrier
+ * will be resolved before the subsequent lock update reaches visibility.
+ */
+extern void membar_exit(void);
+
+/*
+ * Arrange that all stores issued before this point in the code reach
+ * global visibility before any stores that follow; useful in producer
+ * modules that update a data item, then set a flag that it is available.
+ * The memory barrier guarantees that the available flag is not visible
+ * earlier than the updated data, i.e. it imposes store ordering.
+ */
+extern void membar_producer(void);
+
+/*
+ * Arrange that all loads issued before this point in the code are
+ * completed before any subsequent loads; useful in consumer modules
+ * that check to see if data is available and read the data.
+ * The memory barrier guarantees that the data is not sampled until
+ * after the available flag has been seen, i.e. it imposes load ordering.
+ */
+extern void membar_consumer(void);
+#endif  /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ATOMIC_H */
diff --git a/zfs/lib/libspl/include/attr.h b/zfs/lib/libspl/include/attr.h
new file mode 100644 (file)
index 0000000..da1671a
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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
+ */
+
+#ifndef _LIBSPL_ATTR_H
+#define        _LIBSPL_ATTR_H
+
+#endif /* _LIBSPL_ATTR_H */
diff --git a/zfs/lib/libspl/include/devid.h b/zfs/lib/libspl/include/devid.h
new file mode 100644 (file)
index 0000000..8e48328
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_DEVID_H
+#define        _LIBSPL_DEVID_H
+
+#include <sys/types.h>
+
+#endif
diff --git a/zfs/lib/libspl/include/ia32/Makefile.am b/zfs/lib/libspl/include/ia32/Makefile.am
new file mode 100644 (file)
index 0000000..081839c
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = sys
diff --git a/zfs/lib/libspl/include/ia32/Makefile.in b/zfs/lib/libspl/include/ia32/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/include/ia32/sys/Makefile.am b/zfs/lib/libspl/include/ia32/sys/Makefile.am
new file mode 100644 (file)
index 0000000..c8136ee
--- /dev/null
@@ -0,0 +1,3 @@
+libspldir = $(includedir)/libspl/ia32/sys
+libspl_HEADERS = \
+        $(top_srcdir)/lib/libspl/include/ia32/sys/asm_linkage.h
diff --git a/zfs/lib/libspl/include/ia32/sys/Makefile.in b/zfs/lib/libspl/include/ia32/sys/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/include/ia32/sys/asm_linkage.h b/zfs/lib/libspl/include/ia32/sys/asm_linkage.h
new file mode 100644 (file)
index 0000000..61c4d1a
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IA32_SYS_ASM_LINKAGE_H
+#define        _IA32_SYS_ASM_LINKAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _ASM    /* The remainder of this file is only for assembly files */
+
+/*
+ * make annoying differences in assembler syntax go away
+ */
+
+/*
+ * D16 and A16 are used to insert instructions prefixes; the
+ * macros help the assembler code be slightly more portable.
+ */
+#if !defined(__GNUC_AS__)
+/*
+ * /usr/ccs/bin/as prefixes are parsed as separate instructions
+ */
+#define        D16     data16;
+#define        A16     addr16;
+
+/*
+ * (There are some weird constructs in constant expressions)
+ */
+#define        _CONST(const)           [const]
+#define        _BITNOT(const)          -1!_CONST(const)
+#define        _MUL(a, b)              _CONST(a \* b)
+
+#else
+/*
+ * Why not use the 'data16' and 'addr16' prefixes .. well, the
+ * assembler doesn't quite believe in real mode, and thus argues with
+ * us about what we're trying to do.
+ */
+#define        D16     .byte   0x66;
+#define        A16     .byte   0x67;
+
+#define        _CONST(const)           (const)
+#define        _BITNOT(const)          ~_CONST(const)
+#define        _MUL(a, b)              _CONST(a * b)
+
+#endif
+
+/*
+ * C pointers are different sizes between i386 and amd64.
+ * These constants can be used to compute offsets into pointer arrays.
+ */
+#if defined(__amd64)
+#define        CLONGSHIFT      3
+#define        CLONGSIZE       8
+#define        CLONGMASK       7
+#elif defined(__i386)
+#define        CLONGSHIFT      2
+#define        CLONGSIZE       4
+#define        CLONGMASK       3
+#endif
+
+/*
+ * Since we know we're either ILP32 or LP64 ..
+ */
+#define        CPTRSHIFT       CLONGSHIFT
+#define        CPTRSIZE        CLONGSIZE
+#define        CPTRMASK        CLONGMASK
+
+#if CPTRSIZE != (1 << CPTRSHIFT) || CLONGSIZE != (1 << CLONGSHIFT)
+#error "inconsistent shift constants"
+#endif
+
+#if CPTRMASK != (CPTRSIZE - 1) || CLONGMASK != (CLONGSIZE - 1)
+#error "inconsistent mask constants"
+#endif
+
+#define        ASM_ENTRY_ALIGN 16
+
+/*
+ * SSE register alignment and save areas
+ */
+
+#define        XMM_SIZE        16
+#define        XMM_ALIGN       16
+
+#if defined(__amd64)
+
+#define        SAVE_XMM_PROLOG(sreg, nreg)                             \
+       subq    $_CONST(_MUL(XMM_SIZE, nreg)), %rsp;            \
+       movq    %rsp, sreg
+
+#define        RSTOR_XMM_EPILOG(sreg, nreg)                            \
+       addq    $_CONST(_MUL(XMM_SIZE, nreg)), %rsp
+
+#elif defined(__i386)
+
+#define        SAVE_XMM_PROLOG(sreg, nreg)                             \
+       subl    $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp; \
+       movl    %esp, sreg;                                     \
+       addl    $XMM_ALIGN, sreg;                               \
+       andl    $_BITNOT(XMM_ALIGN-1), sreg
+
+#define        RSTOR_XMM_EPILOG(sreg, nreg)                            \
+       addl    $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp;
+
+#endif /* __i386 */
+
+/*
+ * profiling causes definitions of the MCOUNT and RTMCOUNT
+ * particular to the type
+ */
+#ifdef GPROF
+
+#define        MCOUNT(x) \
+       pushl   %ebp; \
+       movl    %esp, %ebp; \
+       call    _mcount; \
+       popl    %ebp
+
+#endif /* GPROF */
+
+#ifdef PROF
+
+#define        MCOUNT(x) \
+/* CSTYLED */ \
+       .lcomm .L_/**/x/**/1, 4, 4; \
+       pushl   %ebp; \
+       movl    %esp, %ebp; \
+/* CSTYLED */ \
+       movl    $.L_/**/x/**/1, %edx; \
+       call    _mcount; \
+       popl    %ebp
+
+#endif /* PROF */
+
+/*
+ * if we are not profiling, MCOUNT should be defined to nothing
+ */
+#if !defined(PROF) && !defined(GPROF)
+#define        MCOUNT(x)
+#endif /* !defined(PROF) && !defined(GPROF) */
+
+#define        RTMCOUNT(x)     MCOUNT(x)
+
+/*
+ * Macro to define weak symbol aliases. These are similar to the ANSI-C
+ *     #pragma weak name = _name
+ * except a compiler can determine type. The assembler must be told. Hence,
+ * the second parameter must be the type of the symbol (i.e.: function,...)
+ */
+#define        ANSI_PRAGMA_WEAK(sym, stype)    \
+       .weak   sym; \
+       .type sym, @stype; \
+/* CSTYLED */ \
+sym    = _/**/sym
+
+/*
+ * Like ANSI_PRAGMA_WEAK(), but for unrelated names, as in:
+ *     #pragma weak sym1 = sym2
+ */
+#define        ANSI_PRAGMA_WEAK2(sym1, sym2, stype)    \
+       .weak   sym1; \
+       .type sym1, @stype; \
+sym1   = sym2
+
+/*
+ * ENTRY provides the standard procedure entry code and an easy way to
+ * insert the calls to mcount for profiling. ENTRY_NP is identical, but
+ * never calls mcount.
+ */
+#define        ENTRY(x) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x; \
+       .type   x, @function; \
+x:     MCOUNT(x)
+
+#define        ENTRY_NP(x) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x; \
+       .type   x, @function; \
+x:
+
+#define        RTENTRY(x) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x; \
+       .type   x, @function; \
+x:     RTMCOUNT(x)
+
+/*
+ * ENTRY2 is identical to ENTRY but provides two labels for the entry point.
+ */
+#define        ENTRY2(x, y) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x, y; \
+       .type   x, @function; \
+       .type   y, @function; \
+/* CSTYLED */ \
+x:     ; \
+y:     MCOUNT(x)
+
+#define        ENTRY_NP2(x, y) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x, y; \
+       .type   x, @function; \
+       .type   y, @function; \
+/* CSTYLED */ \
+x:     ; \
+y:
+
+
+/*
+ * ALTENTRY provides for additional entry points.
+ */
+#define        ALTENTRY(x) \
+       .globl x; \
+       .type   x, @function; \
+x:
+
+/*
+ * DGDEF and DGDEF2 provide global data declarations.
+ *
+ * DGDEF provides a word aligned word of storage.
+ *
+ * DGDEF2 allocates "sz" bytes of storage with **NO** alignment.  This
+ * implies this macro is best used for byte arrays.
+ *
+ * DGDEF3 allocates "sz" bytes of storage with "algn" alignment.
+ */
+#define        DGDEF2(name, sz) \
+       .data; \
+       .globl  name; \
+       .type   name, @object; \
+       .size   name, sz; \
+name:
+
+#define        DGDEF3(name, sz, algn) \
+       .data; \
+       .align  algn; \
+       .globl  name; \
+       .type   name, @object; \
+       .size   name, sz; \
+name:
+
+#define        DGDEF(name)     DGDEF3(name, 4, 4)
+
+/*
+ * SET_SIZE trails a function and set the size for the ELF symbol table.
+ */
+#define        SET_SIZE(x) \
+       .size   x, [.-x]
+
+/*
+ * NWORD provides native word value.
+ */
+#if defined(__amd64)
+
+/*CSTYLED*/
+#define        NWORD   quad
+
+#elif defined(__i386)
+
+#define        NWORD   long
+
+#endif  /* __i386 */
+
+#endif /* _ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IA32_SYS_ASM_LINKAGE_H */
diff --git a/zfs/lib/libspl/include/libdevinfo.h b/zfs/lib/libspl/include/libdevinfo.h
new file mode 100644 (file)
index 0000000..be1d291
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_LIBDEVINFO_H
+#define        _LIBSPL_LIBDEVINFO_H
+
+#endif /* _LIBSPL_LIBDEVINFO_H */
diff --git a/zfs/lib/libspl/include/libgen.h b/zfs/lib/libspl/include/libgen.h
new file mode 100644 (file)
index 0000000..7c03d81
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_LIBGEN_H
+#define        _LIBSPL_LIBGEN_H
+
+#include <sys/types.h>
+
+extern int mkdirp(const char *, mode_t);
+
+#endif /* _LIBSPL_LIBGEN_H */
diff --git a/zfs/lib/libspl/include/libshare.h b/zfs/lib/libspl/include/libshare.h
new file mode 100644 (file)
index 0000000..4016ff0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+#ifndef _LIBSPL_LIBSHARE_H
+#define        _LIBSPL_LIBSHARE_H
+
+typedef void *sa_handle_t;     /* opaque handle to access core functions */
+typedef void *sa_group_t;
+typedef void *sa_share_t;
+
+/* API Initialization */
+#define        SA_INIT_SHARE_API       0x0001  /* init share specific interface */
+#define        SA_INIT_CONTROL_API     0x0002  /* init control specific interface */
+
+/*
+ * defined error values
+ */
+
+#define        SA_OK                   0
+#define        SA_NO_SUCH_PATH         1       /* provided path doesn't exist */
+#define        SA_NO_MEMORY            2       /* no memory for data structures */
+#define        SA_DUPLICATE_NAME       3       /* object name is already in use */
+#define        SA_BAD_PATH             4       /* not a full path */
+#define        SA_NO_SUCH_GROUP        5       /* group is not defined */
+#define        SA_CONFIG_ERR           6       /* system configuration error */
+#define        SA_SYSTEM_ERR           7       /* system error, use errno */
+#define        SA_SYNTAX_ERR           8       /* syntax error on command line */
+#define        SA_NO_PERMISSION        9       /* no permission for operation */
+#define        SA_BUSY                 10      /* resource is busy */
+#define        SA_NO_SUCH_PROP         11      /* property doesn't exist */
+#define        SA_INVALID_NAME         12      /* name of object is invalid */
+#define        SA_INVALID_PROTOCOL     13      /* specified protocol not valid */
+#define        SA_NOT_ALLOWED          14      /* operation not allowed */
+#define        SA_BAD_VALUE            15      /* bad value for property */
+#define        SA_INVALID_SECURITY     16      /* invalid security type */
+#define        SA_NO_SUCH_SECURITY     17      /* security set not found */
+#define        SA_VALUE_CONFLICT       18      /* property value conflict */
+#define        SA_NOT_IMPLEMENTED      19      /* plugin interface not implemented */
+#define        SA_INVALID_PATH         20      /* path is sub-dir of existing share */
+#define        SA_NOT_SUPPORTED        21      /* operation not supported for proto */
+#define        SA_PROP_SHARE_ONLY      22      /* property valid on share only */
+#define        SA_NOT_SHARED           23      /* path is not shared */
+#define        SA_NO_SUCH_RESOURCE     24      /* resource not found */
+#define        SA_RESOURCE_REQUIRED    25      /* resource name is required  */
+#define        SA_MULTIPLE_ERROR       26      /* multiple protocols reported error */
+#define        SA_PATH_IS_SUBDIR       27      /* check_path found path is subdir */
+#define        SA_PATH_IS_PARENTDIR    28      /* check_path found path is parent */
+#define        SA_NO_SECTION           29      /* protocol requires section info */
+#define        SA_NO_SUCH_SECTION      30      /* no section found */
+#define        SA_NO_PROPERTIES        31      /* no properties found */
+#define        SA_PASSWORD_ENC         32      /* passwords must be encrypted */
+#define        SA_SHARE_EXISTS         33      /* path or file is already shared */
+
+/* initialization */
+extern sa_handle_t sa_init(int);
+extern void sa_fini(sa_handle_t);
+extern char *sa_errorstr(int);
+
+/* share control */
+extern sa_share_t sa_find_share(sa_handle_t, char *);
+extern int sa_enable_share(sa_group_t, char *);
+extern int sa_disable_share(sa_share_t, char *);
+
+/* protocol specific interfaces */
+extern int sa_parse_legacy_options(sa_group_t, char *, char *);
+
+/* ZFS functions */
+extern boolean_t sa_needs_refresh(sa_handle_t handle);
+libzfs_handle_t *sa_get_zfs_handle(sa_handle_t handle);
+extern int sa_zfs_process_share(sa_handle_t handle, sa_group_t group,
+    sa_share_t share, char *mountpoint, char *proto, zprop_source_t source,
+    char *shareopts, char *sourcestr, char *dataset);
+
+#endif /* _LIBSPL_LIBSHARE_H */
diff --git a/zfs/lib/libspl/include/limits.h b/zfs/lib/libspl/include/limits.h
new file mode 100644 (file)
index 0000000..1a42cfe
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include_next <limits.h>
+
+#ifndef _LIBSPL_LIMITS_H
+#define        _LIBSPL_LIMITS_H
+
+#define        DBL_DIG         15
+#define        DBL_MAX         1.7976931348623157081452E+308
+#define        DBL_MIN         2.2250738585072013830903E-308
+
+#define        FLT_DIG         6
+#define        FLT_MAX         3.4028234663852885981170E+38F
+#define        FLT_MIN         1.1754943508222875079688E-38F
+
+#endif /* _LIBSPL_LIMITS_H */
diff --git a/zfs/lib/libspl/include/locale.h b/zfs/lib/libspl/include/locale.h
new file mode 100644 (file)
index 0000000..6c74df7
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include_next <locale.h>
+
+#ifndef _LIBSPL_LOCALE_H
+#define        _LIBSPL_LOCALE_H
+
+#include <time.h>
+#include <sys/time.h>
+
+#endif
diff --git a/zfs/lib/libspl/include/note.h b/zfs/lib/libspl/include/note.h
new file mode 100644 (file)
index 0000000..cb6b33e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 (c) 1994 by Sun Microsystems, Inc.
+ */
+
+/*
+ * note.h:      interface for annotating source with info for tools
+ *
+ * NOTE is the default interface, but if the identifier NOTE is in use for
+ * some other purpose, you may prepare a similar header file using your own
+ * identifier, mapping that identifier to _NOTE.  Also, exported header
+ * files should *not* use NOTE, since the name may already be in use in
+ * a program's namespace.  Rather, exported header files should include
+ * sys/note.h directly and use _NOTE.  For consistency, all kernel source
+ * should use _NOTE.
+ */
+
+#ifndef _NOTE_H
+#define        _NOTE_H
+
+#include <sys/note.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define        NOTE    _NOTE
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* _NOTE_H */
diff --git a/zfs/lib/libspl/include/rpc/Makefile.am b/zfs/lib/libspl/include/rpc/Makefile.am
new file mode 100644 (file)
index 0000000..78ee5a2
--- /dev/null
@@ -0,0 +1,3 @@
+libspldir = $(includedir)/libspl/rpc
+libspl_HEADERS = \
+       $(top_srcdir)/lib/libspl/include/rpc/xdr.h
diff --git a/zfs/lib/libspl/include/rpc/Makefile.in b/zfs/lib/libspl/include/rpc/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/include/rpc/xdr.h b/zfs/lib/libspl/include/rpc/xdr.h
new file mode 100644 (file)
index 0000000..3c7c53f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ *
+ *     Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
+ *       All Rights Reserved
+ *
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#ifndef LIBSPL_RPC_XDR_H
+#define        LIBSPL_RPC_XDR_H
+
+/*
+ * When available prefer libtirpc for xdr functionality.  This library is
+ * mandatory when compiling with musl libc because it does not provide xdr.
+ */
+#if defined(HAVE_LIBTIRPC)
+
+#include <tirpc/rpc/xdr.h>
+#ifdef xdr_control
+#undef xdr_control
+#endif
+
+#else
+#include_next <rpc/xdr.h>
+#endif /* HAVE_LIBTIRPC */
+
+#define        XDR_GET_BYTES_AVAIL 1
+
+typedef struct xdr_bytesrec {
+       bool_t xc_is_last_record;
+       size_t xc_num_avail;
+} xdr_bytesrec_t;
+
+/*
+ * This functionality is not required and is disabled in user space.
+ */
+static inline bool_t
+xdr_control(XDR *xdrs, int request, void *info)
+{
+       xdr_bytesrec_t *xptr;
+
+       ASSERT3U(request, ==, XDR_GET_BYTES_AVAIL);
+
+       xptr = (xdr_bytesrec_t *)info;
+       xptr->xc_is_last_record = TRUE;
+       xptr->xc_num_avail = xdrs->x_handy;
+
+       return (TRUE);
+}
+
+#endif /* LIBSPL_RPC_XDR_H */
diff --git a/zfs/lib/libspl/include/statcommon.h b/zfs/lib/libspl/include/statcommon.h
new file mode 100644 (file)
index 0000000..1f376f5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ *
+ * Common routines for acquiring snapshots of kstats for
+ * iostat, mpstat, and vmstat.
+ */
+
+#ifndef        _STATCOMMON_H
+#define        _STATCOMMON_H
+
+#include <sys/types.h>
+
+#define        NODATE  0       /* Default:  No time stamp */
+#define        DDATE   1       /* Standard date format */
+#define        UDATE   2       /* Internal representation of Unix time */
+
+/* Print a timestamp in either Unix or standard format. */
+void print_timestamp(uint_t);
+
+#endif /* _STATCOMMON_H */
diff --git a/zfs/lib/libspl/include/stdio.h b/zfs/lib/libspl/include/stdio.h
new file mode 100644 (file)
index 0000000..6152b09
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include_next <stdio.h>
+
+#ifndef _LIBSPL_STDIO_H
+#define        _LIBSPL_STDIO_H
+
+#define        enable_extended_FILE_stdio(fd, sig)     ((void) 0)
+
+#endif
diff --git a/zfs/lib/libspl/include/stdlib.h b/zfs/lib/libspl/include/stdlib.h
new file mode 100644 (file)
index 0000000..a4ce4f7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include_next <stdlib.h>
+
+#ifndef _LIBSPL_STDLIB_H
+#define        _LIBSPL_STDLIB_H
+
+extern const char *getexecname(void);
+
+#endif
diff --git a/zfs/lib/libspl/include/string.h b/zfs/lib/libspl/include/string.h
new file mode 100644 (file)
index 0000000..9e5133e
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_STRING_H
+#define        _LIBSPL_STRING_H
+
+#include_next <string.h>
+
+extern size_t strlcat(char *dst, const char *src, size_t dstsize);
+extern size_t strlcpy(char *dst, const char *src, size_t len);
+extern size_t strnlen(const char *str, size_t maxlen);
+
+#endif
diff --git a/zfs/lib/libspl/include/strings.h b/zfs/lib/libspl/include/strings.h
new file mode 100644 (file)
index 0000000..3f35af4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_STRINGS_H
+#define        _LIBSPL_STRINGS_H
+
+#include <string.h>
+#include_next <strings.h>
+
+#endif
diff --git a/zfs/lib/libspl/include/stropts.h b/zfs/lib/libspl/include/stropts.h
new file mode 100644 (file)
index 0000000..37acd40
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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
+ */
+
+#ifndef _LIBSPL_STROPTS_H
+#define        _LIBSPL_STROPTS_H
+
+#endif /* _LIBSPL_STROPTS_H */
diff --git a/zfs/lib/libspl/include/synch.h b/zfs/lib/libspl/include/synch.h
new file mode 100644 (file)
index 0000000..93d2314
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2014 Zettabyte Software, LLC.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYNCH_H
+#define        _LIBSPL_SYNCH_H
+
+#ifndef __sun__
+
+#include <assert.h>
+#include <pthread.h>
+
+/*
+ * Definitions of synchronization types.
+ */
+#define        USYNC_THREAD    0x00            /* private to a process */
+#define        USYNC_PROCESS   0x01            /* shared by processes */
+
+typedef pthread_rwlock_t rwlock_t;
+
+#define        DEFAULTRWLOCK           PTHREAD_RWLOCK_INITIALIZER
+
+static inline int
+rwlock_init(rwlock_t *rwlp, int type, void *arg)
+{
+       pthread_rwlockattr_t attr;
+       int err = 0;
+
+       VERIFY0(pthread_rwlockattr_init(&attr));
+       switch (type) {
+       case USYNC_THREAD:
+               VERIFY0(pthread_rwlockattr_setpshared(&attr,
+                       PTHREAD_PROCESS_PRIVATE));
+               break;
+       case USYNC_PROCESS:
+               VERIFY0(pthread_rwlockattr_setpshared(&attr,
+                       PTHREAD_PROCESS_SHARED));
+               break;
+       default:
+               VERIFY0(1);
+       }
+
+       err = pthread_rwlock_init(rwlp, &attr);
+       VERIFY0(pthread_rwlockattr_destroy(&attr));
+
+       return (err);
+}
+
+#define        rwlock_destroy(x)       pthread_rwlock_destroy((x))
+#define        rw_rdlock(x)            pthread_rwlock_rdlock((x))
+#define        rw_wrlock(x)            pthread_rwlock_wrlock((x))
+#define        rw_unlock(x)            pthread_rwlock_unlock((x))
+#define        rw_tryrdlock(x)         pthread_rwlock_tryrdlock((x))
+#define        rw_trywrlock(x)         pthread_rwlock_trywrlock((x))
+
+#endif /* __sun__ */
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/Makefile.am b/zfs/lib/libspl/include/sys/Makefile.am
new file mode 100644 (file)
index 0000000..ca29634
--- /dev/null
@@ -0,0 +1,52 @@
+SUBDIRS = dktp
+
+libspldir = $(includedir)/libspl/sys
+libspl_HEADERS = \
+       $(top_srcdir)/lib/libspl/include/sys/acl.h \
+       $(top_srcdir)/lib/libspl/include/sys/acl_impl.h \
+       $(top_srcdir)/lib/libspl/include/sys/bitmap.h \
+       $(top_srcdir)/lib/libspl/include/sys/byteorder.h \
+       $(top_srcdir)/lib/libspl/include/sys/callb.h \
+       $(top_srcdir)/lib/libspl/include/sys/cmn_err.h \
+       $(top_srcdir)/lib/libspl/include/sys/compress.h \
+       $(top_srcdir)/lib/libspl/include/sys/cred.h \
+       $(top_srcdir)/lib/libspl/include/sys/debug.h \
+       $(top_srcdir)/lib/libspl/include/sys/dkio.h \
+       $(top_srcdir)/lib/libspl/include/sys/dklabel.h \
+       $(top_srcdir)/lib/libspl/include/sys/feature_tests.h \
+       $(top_srcdir)/lib/libspl/include/sys/file.h \
+       $(top_srcdir)/lib/libspl/include/sys/frame.h \
+       $(top_srcdir)/lib/libspl/include/sys/int_limits.h \
+       $(top_srcdir)/lib/libspl/include/sys/int_types.h \
+       $(top_srcdir)/lib/libspl/include/sys/inttypes.h \
+       $(top_srcdir)/lib/libspl/include/sys/isa_defs.h \
+       $(top_srcdir)/lib/libspl/include/sys/kmem.h \
+       $(top_srcdir)/lib/libspl/include/sys/kstat.h \
+       $(top_srcdir)/lib/libspl/include/sys/list.h \
+       $(top_srcdir)/lib/libspl/include/sys/list_impl.h \
+       $(top_srcdir)/lib/libspl/include/sys/mhd.h \
+       $(top_srcdir)/lib/libspl/include/sys/mkdev.h \
+       $(top_srcdir)/lib/libspl/include/sys/mnttab.h \
+       $(top_srcdir)/lib/libspl/include/sys/mount.h \
+       $(top_srcdir)/lib/libspl/include/sys/note.h \
+       $(top_srcdir)/lib/libspl/include/sys/param.h \
+       $(top_srcdir)/lib/libspl/include/sys/policy.h \
+       $(top_srcdir)/lib/libspl/include/sys/priv.h \
+       $(top_srcdir)/lib/libspl/include/sys/processor.h \
+       $(top_srcdir)/lib/libspl/include/sys/stack.h \
+       $(top_srcdir)/lib/libspl/include/sys/stat.h \
+       $(top_srcdir)/lib/libspl/include/sys/stropts.h \
+       $(top_srcdir)/lib/libspl/include/sys/sunddi.h \
+       $(top_srcdir)/lib/libspl/include/sys/sysmacros.h \
+       $(top_srcdir)/lib/libspl/include/sys/systeminfo.h \
+       $(top_srcdir)/lib/libspl/include/sys/systm.h \
+       $(top_srcdir)/lib/libspl/include/sys/time.h \
+       $(top_srcdir)/lib/libspl/include/sys/types32.h \
+       $(top_srcdir)/lib/libspl/include/sys/types.h \
+       $(top_srcdir)/lib/libspl/include/sys/tzfile.h \
+       $(top_srcdir)/lib/libspl/include/sys/uio.h \
+       $(top_srcdir)/lib/libspl/include/sys/va_list.h \
+       $(top_srcdir)/lib/libspl/include/sys/varargs.h \
+       $(top_srcdir)/lib/libspl/include/sys/vnode.h \
+       $(top_srcdir)/lib/libspl/include/sys/vtoc.h \
+       $(top_srcdir)/lib/libspl/include/sys/zone.h
diff --git a/zfs/lib/libspl/include/sys/Makefile.in b/zfs/lib/libspl/include/sys/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/include/sys/acl.h b/zfs/lib/libspl/include/sys/acl.h
new file mode 100644 (file)
index 0000000..e6df864
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * 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 _SYS_ACL_H
+#define        _SYS_ACL_H
+
+#include <sys/types.h>
+#include <sys/acl_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        MAX_ACL_ENTRIES         (1024)  /* max entries of each type */
+typedef struct acl {
+       int             a_type;         /* the type of ACL entry */
+       uid_t           a_id;           /* the entry in -uid or gid */
+       o_mode_t        a_perm;         /* the permission field */
+} aclent_t;
+
+typedef struct ace {
+       uid_t           a_who;          /* uid or gid */
+       uint32_t        a_access_mask;  /* read,write,... */
+       uint16_t        a_flags;        /* see below */
+       uint16_t        a_type;         /* allow or deny */
+} ace_t;
+
+typedef struct acl_info acl_t;
+
+/*
+ * The following are Defined types for an aclent_t.
+ */
+#define        USER_OBJ        (0x01)          /* object owner */
+#define        USER            (0x02)          /* additional users */
+#define        GROUP_OBJ       (0x04)          /* owning group of the object */
+#define        GROUP           (0x08)          /* additional groups */
+#define        CLASS_OBJ       (0x10)          /* file group class and mask entry */
+#define        OTHER_OBJ       (0x20)          /* other entry for the object */
+#define        ACL_DEFAULT     (0x1000)        /* default flag */
+/* default object owner */
+#define        DEF_USER_OBJ    (ACL_DEFAULT | USER_OBJ)
+/* default additional users */
+#define        DEF_USER        (ACL_DEFAULT | USER)
+/* default owning group */
+#define        DEF_GROUP_OBJ   (ACL_DEFAULT | GROUP_OBJ)
+/* default additional groups */
+#define        DEF_GROUP       (ACL_DEFAULT | GROUP)
+/* default mask entry */
+#define        DEF_CLASS_OBJ   (ACL_DEFAULT | CLASS_OBJ)
+/* default other entry */
+#define        DEF_OTHER_OBJ   (ACL_DEFAULT | OTHER_OBJ)
+
+/*
+ * The following are defined for ace_t.
+ */
+#define        ACE_READ_DATA           0x00000001
+#define        ACE_LIST_DIRECTORY      0x00000001
+#define        ACE_WRITE_DATA          0x00000002
+#define        ACE_ADD_FILE            0x00000002
+#define        ACE_APPEND_DATA         0x00000004
+#define        ACE_ADD_SUBDIRECTORY    0x00000004
+#define        ACE_READ_NAMED_ATTRS    0x00000008
+#define        ACE_WRITE_NAMED_ATTRS   0x00000010
+#define        ACE_EXECUTE             0x00000020
+#define        ACE_DELETE_CHILD        0x00000040
+#define        ACE_READ_ATTRIBUTES     0x00000080
+#define        ACE_WRITE_ATTRIBUTES    0x00000100
+#define        ACE_DELETE              0x00010000
+#define        ACE_READ_ACL            0x00020000
+#define        ACE_WRITE_ACL           0x00040000
+#define        ACE_WRITE_OWNER         0x00080000
+#define        ACE_SYNCHRONIZE         0x00100000
+
+#define        ACE_FILE_INHERIT_ACE            0x0001
+#define        ACE_DIRECTORY_INHERIT_ACE       0x0002
+#define        ACE_NO_PROPAGATE_INHERIT_ACE    0x0004
+#define        ACE_INHERIT_ONLY_ACE            0x0008
+#define        ACE_SUCCESSFUL_ACCESS_ACE_FLAG  0x0010
+#define        ACE_FAILED_ACCESS_ACE_FLAG      0x0020
+#define        ACE_IDENTIFIER_GROUP            0x0040
+#define        ACE_INHERITED_ACE               0x0080
+#define        ACE_OWNER                       0x1000
+#define        ACE_GROUP                       0x2000
+#define        ACE_EVERYONE                    0x4000
+
+#define        ACE_ACCESS_ALLOWED_ACE_TYPE     0x0000
+#define        ACE_ACCESS_DENIED_ACE_TYPE      0x0001
+#define        ACE_SYSTEM_AUDIT_ACE_TYPE       0x0002
+#define        ACE_SYSTEM_ALARM_ACE_TYPE       0x0003
+
+#define        ACL_AUTO_INHERIT                0x0001
+#define        ACL_PROTECTED                   0x0002
+#define        ACL_DEFAULTED                   0x0004
+#define        ACL_FLAGS_ALL                   (ACL_AUTO_INHERIT|ACL_PROTECTED| \
+    ACL_DEFAULTED)
+
+#ifdef _KERNEL
+
+/*
+ * These are only applicable in a CIFS context.
+ */
+#define        ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE            0x04
+#define        ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE              0x05
+#define        ACE_ACCESS_DENIED_OBJECT_ACE_TYPE               0x06
+#define        ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE                0x07
+#define        ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE                0x08
+#define        ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE            0x09
+#define        ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE             0x0A
+#define        ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE     0x0B
+#define        ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE      0x0C
+#define        ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE              0x0D
+#define        ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE              0x0E
+#define        ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE       0x0F
+#define        ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE       0x10
+
+#define        ACE_ALL_TYPES   0x001F
+
+typedef struct ace_object {
+       uid_t           a_who;          /* uid or gid */
+       uint32_t        a_access_mask;  /* read,write,... */
+       uint16_t        a_flags;        /* see below */
+       uint16_t        a_type;         /* allow or deny */
+       uint8_t         a_obj_type[16]; /* obj type */
+       uint8_t         a_inherit_obj_type[16];  /* inherit obj */
+} ace_object_t;
+
+#endif
+
+#define        ACE_ALL_PERMS   (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \
+    ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS| \
+    ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES| \
+    ACE_WRITE_ATTRIBUTES|ACE_DELETE|ACE_READ_ACL|ACE_WRITE_ACL| \
+    ACE_WRITE_OWNER|ACE_SYNCHRONIZE)
+
+/*
+ * The following flags are supported by both NFSv4 ACLs and ace_t.
+ */
+#define        ACE_NFSV4_SUP_FLAGS (ACE_FILE_INHERIT_ACE | \
+    ACE_DIRECTORY_INHERIT_ACE | \
+    ACE_NO_PROPAGATE_INHERIT_ACE | \
+    ACE_INHERIT_ONLY_ACE | \
+    ACE_IDENTIFIER_GROUP)
+
+#define        ACE_TYPE_FLAGS          (ACE_OWNER|ACE_GROUP|ACE_EVERYONE| \
+    ACE_IDENTIFIER_GROUP)
+#define        ACE_INHERIT_FLAGS       (ACE_FILE_INHERIT_ACE| \
+    ACE_DIRECTORY_INHERIT_ACE|ACE_NO_PROPAGATE_INHERIT_ACE|ACE_INHERIT_ONLY_ACE)
+
+/* cmd args to acl(2) for aclent_t  */
+#define        GETACL                  1
+#define        SETACL                  2
+#define        GETACLCNT               3
+
+/* cmd's to manipulate ace acls. */
+#define        ACE_GETACL              4
+#define        ACE_SETACL              5
+#define        ACE_GETACLCNT           6
+
+/* minimal acl entries from GETACLCNT */
+#define        MIN_ACL_ENTRIES         4
+
+#if !defined(_KERNEL)
+
+/* acl check errors */
+#define        GRP_ERROR               1
+#define        USER_ERROR              2
+#define        OTHER_ERROR             3
+#define        CLASS_ERROR             4
+#define        DUPLICATE_ERROR         5
+#define        MISS_ERROR              6
+#define        MEM_ERROR               7
+#define        ENTRY_ERROR             8
+
+
+/*
+ * similar to ufs_acl.h: changed to char type for user commands (tar, cpio)
+ * Attribute types
+ */
+#define        UFSD_FREE       ('0')   /* Free entry */
+#define        UFSD_ACL        ('1')   /* Access Control Lists */
+#define        UFSD_DFACL      ('2')   /* reserved for future use */
+#define        ACE_ACL         ('3')   /* ace_t style acls */
+
+/*
+ * flag to [f]acl_get()
+ * controls whether a trivial acl should be returned.
+ */
+#define        ACL_NO_TRIVIAL  0x2
+
+
+/*
+ * Flags to control acl_totext()
+ */
+
+#define        ACL_APPEND_ID   0x1     /* append uid/gid to user/group entries */
+#define        ACL_COMPACT_FMT 0x2     /* build ACL in ls -V format */
+#define        ACL_NORESOLVE   0x4     /* don't do name service lookups */
+
+/*
+ * Legacy aclcheck errors for aclent_t ACLs
+ */
+#define        EACL_GRP_ERROR          GRP_ERROR
+#define        EACL_USER_ERROR         USER_ERROR
+#define        EACL_OTHER_ERROR        OTHER_ERROR
+#define        EACL_CLASS_ERROR        CLASS_ERROR
+#define        EACL_DUPLICATE_ERROR    DUPLICATE_ERROR
+#define        EACL_MISS_ERROR         MISS_ERROR
+#define        EACL_MEM_ERROR          MEM_ERROR
+#define        EACL_ENTRY_ERROR        ENTRY_ERROR
+
+#define        EACL_INHERIT_ERROR      9               /* invalid inherit flags */
+#define        EACL_FLAGS_ERROR        10              /* unknown flag value */
+#define        EACL_PERM_MASK_ERROR    11              /* unknown permission */
+#define        EACL_COUNT_ERROR        12              /* invalid acl count */
+
+#define        EACL_INVALID_SLOT       13              /* invalid acl slot */
+#define        EACL_NO_ACL_ENTRY       14              /* Entry doesn't exist */
+#define        EACL_DIFF_TYPE          15              /* acls aren't same type */
+
+#define        EACL_INVALID_USER_GROUP 16              /* need user/group name */
+#define        EACL_INVALID_STR        17              /* invalid acl string */
+#define        EACL_FIELD_NOT_BLANK    18              /* can't have blank field */
+#define        EACL_INVALID_ACCESS_TYPE 19             /* invalid access type */
+#define        EACL_UNKNOWN_DATA       20              /* Unrecognized data in ACL */
+#define        EACL_MISSING_FIELDS     21              /* missing fields in acl */
+
+#define        EACL_INHERIT_NOTDIR     22              /* Need dir for inheritance */
+
+extern int aclcheck(aclent_t *, int, int *);
+extern int acltomode(aclent_t *, int, mode_t *);
+extern int aclfrommode(aclent_t *, int, mode_t *);
+extern int aclsort(int, int, aclent_t *);
+extern char *acltotext(aclent_t *, int);
+extern aclent_t *aclfromtext(char *, int *);
+extern void acl_free(acl_t *);
+extern int acl_get(const char *, int, acl_t **);
+extern int facl_get(int, int, acl_t **);
+extern int acl_set(const char *, acl_t *acl);
+extern int facl_set(int, acl_t *acl);
+extern int acl_strip(const char *, uid_t, gid_t, mode_t);
+extern int acl_trivial(const char *);
+extern char *acl_totext(acl_t *, int);
+extern int acl_fromtext(const char *, acl_t **);
+extern int acl_check(acl_t *, int);
+
+#else  /* !defined(_KERNEL) */
+
+extern void ksort(caddr_t, int, int, int (*)(void *, void *));
+extern int cmp2acls(void *, void *);
+
+#endif /* !defined(_KERNEL) */
+
+#if defined(__STDC__)
+extern int acl(const char *path, int cmd, int cnt, void *buf);
+extern int facl(int fd, int cmd, int cnt, void *buf);
+#else  /* !__STDC__ */
+extern int acl();
+extern int facl();
+#endif /* defined(__STDC__) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ACL_H */
diff --git a/zfs/lib/libspl/include/sys/acl_impl.h b/zfs/lib/libspl/include/sys/acl_impl.h
new file mode 100644 (file)
index 0000000..7173349
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 _SYS_ACL_IMPL_H
+#define        _SYS_ACL_IMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * acl flags
+ *
+ * ACL_AUTO_INHERIT, ACL_PROTECTED and ACL_DEFAULTED
+ * flags can also be stored in this field.
+ */
+#define        ACL_IS_TRIVIAL  0x10000
+#define        ACL_IS_DIR      0x20000
+
+typedef enum acl_type {
+       ACLENT_T = 0,
+       ACE_T = 1
+} acl_type_t;
+
+struct acl_info {
+       acl_type_t acl_type;            /* style of acl */
+       int acl_cnt;                    /* number of acl entries */
+       int acl_entry_size;             /* sizeof acl entry */
+       int acl_flags;                  /* special flags about acl */
+       void *acl_aclp;                 /* the acl */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ACL_IMPL_H */
diff --git a/zfs/lib/libspl/include/sys/bitmap.h b/zfs/lib/libspl/include/sys/bitmap.h
new file mode 100644 (file)
index 0000000..95122ab
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_BITMAP_H
+#define        _LIBSPL_SYS_BITMAP_H
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/byteorder.h b/zfs/lib/libspl/include/sys/byteorder.h
new file mode 100644 (file)
index 0000000..7ef1c42
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * 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) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
+/*       All Rights Reserved   */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#ifndef _SYS_BYTEORDER_H
+#define        _SYS_BYTEORDER_H
+
+
+
+#include <sys/isa_defs.h>
+#include <sys/int_types.h>
+
+#if defined(__GNUC__) && defined(_ASM_INLINES) && \
+       (defined(__i386) || defined(__amd64))
+#include <asm/byteorder.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * macros for conversion between host and (internet) network byte order
+ */
+
+#if defined(_BIG_ENDIAN) && !defined(ntohl) && !defined(__lint)
+/* big-endian */
+#define        ntohl(x)        (x)
+#define        ntohs(x)        (x)
+#define        htonl(x)        (x)
+#define        htons(x)        (x)
+
+#elif !defined(ntohl) /* little-endian */
+
+#ifndef        _IN_PORT_T
+#define        _IN_PORT_T
+typedef uint16_t in_port_t;
+#endif
+
+#ifndef        _IN_ADDR_T
+#define        _IN_ADDR_T
+typedef uint32_t in_addr_t;
+#endif
+
+#if !defined(_XPG4_2) || defined(__EXTENSIONS__) || defined(_XPG5)
+extern uint32_t htonl(uint32_t);
+extern uint16_t htons(uint16_t);
+extern         uint32_t ntohl(uint32_t);
+extern uint16_t ntohs(uint16_t);
+#else
+extern in_addr_t htonl(in_addr_t);
+extern in_port_t htons(in_port_t);
+extern         in_addr_t ntohl(in_addr_t);
+extern in_port_t ntohs(in_port_t);
+#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) || defined(_XPG5) */
+#endif
+
+#if !defined(_XPG4_2) || defined(__EXTENSIONS__)
+
+/*
+ * Macros to reverse byte order
+ */
+#define        BSWAP_8(x)      ((x) & 0xff)
+#define        BSWAP_16(x)     ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
+#define        BSWAP_32(x)     ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
+#define        BSWAP_64(x)     ((BSWAP_32(x) << 32) | BSWAP_32((x) >> 32))
+
+#define        BMASK_8(x)      ((x) & 0xff)
+#define        BMASK_16(x)     ((x) & 0xffff)
+#define        BMASK_32(x)     ((x) & 0xffffffff)
+#define        BMASK_64(x)     (x)
+
+/*
+ * Macros to convert from a specific byte order to/from native byte order
+ */
+#ifdef _BIG_ENDIAN
+#define        BE_8(x)         BMASK_8(x)
+#define        BE_16(x)        BMASK_16(x)
+#define        BE_32(x)        BMASK_32(x)
+#define        BE_64(x)        BMASK_64(x)
+#define        LE_8(x)         BSWAP_8(x)
+#define        LE_16(x)        BSWAP_16(x)
+#define        LE_32(x)        BSWAP_32(x)
+#define        LE_64(x)        BSWAP_64(x)
+#else
+#define        LE_8(x)         BMASK_8(x)
+#define        LE_16(x)        BMASK_16(x)
+#define        LE_32(x)        BMASK_32(x)
+#define        LE_64(x)        BMASK_64(x)
+#define        BE_8(x)         BSWAP_8(x)
+#define        BE_16(x)        BSWAP_16(x)
+#define        BE_32(x)        BSWAP_32(x)
+#define        BE_64(x)        BSWAP_64(x)
+#endif
+
+#ifdef _BIG_ENDIAN
+static __inline__ uint64_t
+htonll(uint64_t n) {
+       return (n);
+}
+
+static __inline__ uint64_t
+ntohll(uint64_t n) {
+       return (n);
+}
+#else
+static __inline__ uint64_t
+htonll(uint64_t n) {
+       return ((((uint64_t)htonl(n)) << 32) + htonl(n >> 32));
+}
+
+static __inline__ uint64_t
+ntohll(uint64_t n) {
+       return ((((uint64_t)ntohl(n)) << 32) + ntohl(n >> 32));
+}
+#endif
+
+/*
+ * Macros to read unaligned values from a specific byte order to
+ * native byte order
+ */
+
+#define        BE_IN8(xa) \
+       *((uint8_t *)(xa))
+
+#define        BE_IN16(xa) \
+       (((uint16_t)BE_IN8(xa) << 8) | BE_IN8((uint8_t *)(xa)+1))
+
+#define        BE_IN32(xa) \
+       (((uint32_t)BE_IN16(xa) << 16) | BE_IN16((uint8_t *)(xa)+2))
+
+#define        BE_IN64(xa) \
+       (((uint64_t)BE_IN32(xa) << 32) | BE_IN32((uint8_t *)(xa)+4))
+
+#define        LE_IN8(xa) \
+       *((uint8_t *)(xa))
+
+#define        LE_IN16(xa) \
+       (((uint16_t)LE_IN8((uint8_t *)(xa) + 1) << 8) | LE_IN8(xa))
+
+#define        LE_IN32(xa) \
+       (((uint32_t)LE_IN16((uint8_t *)(xa) + 2) << 16) | LE_IN16(xa))
+
+#define        LE_IN64(xa) \
+       (((uint64_t)LE_IN32((uint8_t *)(xa) + 4) << 32) | LE_IN32(xa))
+
+/*
+ * Macros to write unaligned values from native byte order to a specific byte
+ * order.
+ */
+
+#define        BE_OUT8(xa, yv) *((uint8_t *)(xa)) = (uint8_t)(yv);
+
+#define        BE_OUT16(xa, yv) \
+       BE_OUT8((uint8_t *)(xa) + 1, yv); \
+       BE_OUT8((uint8_t *)(xa), (yv) >> 8);
+
+#define        BE_OUT32(xa, yv) \
+       BE_OUT16((uint8_t *)(xa) + 2, yv); \
+       BE_OUT16((uint8_t *)(xa), (yv) >> 16);
+
+#define        BE_OUT64(xa, yv) \
+       BE_OUT32((uint8_t *)(xa) + 4, yv); \
+       BE_OUT32((uint8_t *)(xa), (yv) >> 32);
+
+#define        LE_OUT8(xa, yv) *((uint8_t *)(xa)) = (uint8_t)(yv);
+
+#define        LE_OUT16(xa, yv) \
+       LE_OUT8((uint8_t *)(xa), yv); \
+       LE_OUT8((uint8_t *)(xa) + 1, (yv) >> 8);
+
+#define        LE_OUT32(xa, yv) \
+       LE_OUT16((uint8_t *)(xa), yv); \
+       LE_OUT16((uint8_t *)(xa) + 2, (yv) >> 16);
+
+#define        LE_OUT64(xa, yv) \
+       LE_OUT32((uint8_t *)(xa), yv); \
+       LE_OUT32((uint8_t *)(xa) + 4, (yv) >> 32);
+
+#endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_BYTEORDER_H */
diff --git a/zfs/lib/libspl/include/sys/callb.h b/zfs/lib/libspl/include/sys/callb.h
new file mode 100644 (file)
index 0000000..8ffd187
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_CALLB_H
+#define        _SYS_CALLB_H
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/cmn_err.h b/zfs/lib/libspl/include/sys/cmn_err.h
new file mode 100644 (file)
index 0000000..63ff4eb
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_CMN_ERR_H
+#define        _LIBSPL_SYS_CMN_ERR_H
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/compress.h b/zfs/lib/libspl/include/sys/compress.h
new file mode 100644 (file)
index 0000000..282f178
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_COMPRESS_H
+#define        _LIBSPL_SYS_COMPRESS_H
+
+#endif /* _LIBSPL_SYS_COMPRESS_H */
diff --git a/zfs/lib/libspl/include/sys/cred.h b/zfs/lib/libspl/include/sys/cred.h
new file mode 100644 (file)
index 0000000..463b3ab
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_CRED_H
+#define        _LIBSPL_SYS_CRED_H
+
+typedef struct cred cred_t;
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/debug.h b/zfs/lib/libspl/include/sys/debug.h
new file mode 100644 (file)
index 0000000..fde4a01
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_DEBUG_H
+#define        _LIBSPL_SYS_DEBUG_H
+
+#include <assert.h>
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/dkio.h b/zfs/lib/libspl/include/sys/dkio.h
new file mode 100644 (file)
index 0000000..6b430b8
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * 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 _SYS_DKIO_H
+#define        _SYS_DKIO_H
+
+
+
+#include <sys/dklabel.h>       /* Needed for NDKMAP define */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Structures and definitions for disk io control commands
+ */
+
+/*
+ * Structures used as data by ioctl calls.
+ */
+
+#define        DK_DEVLEN       16              /* device name max length, including */
+                                       /* unit # & NULL (ie - "xyc1") */
+
+/*
+ * Used for controller info
+ */
+struct dk_cinfo {
+       char    dki_cname[DK_DEVLEN];   /* controller name (no unit #) */
+       ushort_t dki_ctype;             /* controller type */
+       ushort_t dki_flags;             /* flags */
+       ushort_t dki_cnum;              /* controller number */
+       uint_t  dki_addr;               /* controller address */
+       uint_t  dki_space;              /* controller bus type */
+       uint_t  dki_prio;               /* interrupt priority */
+       uint_t  dki_vec;                /* interrupt vector */
+       char    dki_dname[DK_DEVLEN];   /* drive name (no unit #) */
+       uint_t  dki_unit;               /* unit number */
+       uint_t  dki_slave;              /* slave number */
+       ushort_t dki_partition;         /* partition number */
+       ushort_t dki_maxtransfer;       /* max. transfer size in DEV_BSIZE */
+};
+
+/*
+ * Controller types
+ */
+#define        DKC_UNKNOWN     0
+#define        DKC_CDROM       1       /* CD-ROM, SCSI or otherwise */
+#define        DKC_WDC2880     2
+#define        DKC_XXX_0       3       /* unassigned */
+#define        DKC_XXX_1       4       /* unassigned */
+#define        DKC_DSD5215     5
+#define        DKC_ACB4000     7
+#define        DKC_MD21        8
+#define        DKC_XXX_2       9       /* unassigned */
+#define        DKC_NCRFLOPPY   10
+#define        DKC_SMSFLOPPY   12
+#define        DKC_SCSI_CCS    13      /* SCSI CCS compatible */
+#define        DKC_INTEL82072  14      /* native floppy chip */
+#define        DKC_MD          16      /* meta-disk (virtual-disk) driver */
+#define        DKC_INTEL82077  19      /* 82077 floppy disk controller */
+#define        DKC_DIRECT      20      /* Intel direct attached device i.e. IDE */
+#define        DKC_PCMCIA_MEM  21      /* PCMCIA memory disk-like type */
+#define        DKC_PCMCIA_ATA  22      /* PCMCIA AT Attached type */
+#define        DKC_VBD         23      /* virtual block device */
+
+/*
+ * Sun reserves up through 1023
+ */
+
+#define        DKC_CUSTOMER_BASE       1024
+
+/*
+ * Flags
+ */
+#define        DKI_BAD144      0x01    /* use DEC std 144 bad sector fwding */
+#define        DKI_MAPTRK      0x02    /* controller does track mapping */
+#define        DKI_FMTTRK      0x04    /* formats only full track at a time */
+#define        DKI_FMTVOL      0x08    /* formats only full volume at a time */
+#define        DKI_FMTCYL      0x10    /* formats only full cylinders at a time */
+#define        DKI_HEXUNIT     0x20    /* unit number is printed as 3 hex digits */
+#define        DKI_PCMCIA_PFD  0x40    /* PCMCIA pseudo-floppy memory card */
+
+/*
+ * Used for all partitions
+ */
+struct dk_allmap {
+       struct dk_map   dka_map[NDKMAP];
+};
+
+#if defined(_SYSCALL32)
+struct dk_allmap32 {
+       struct dk_map32 dka_map[NDKMAP];
+};
+#endif /* _SYSCALL32 */
+
+/*
+ * Definition of a disk's geometry
+ */
+struct dk_geom {
+       unsigned short  dkg_ncyl;       /* # of data cylinders */
+       unsigned short  dkg_acyl;       /* # of alternate cylinders */
+       unsigned short  dkg_bcyl;       /* cyl offset (for fixed head area) */
+       unsigned short  dkg_nhead;      /* # of heads */
+       unsigned short  dkg_obs1;       /* obsolete */
+       unsigned short  dkg_nsect;      /* # of data sectors per track */
+       unsigned short  dkg_intrlv;     /* interleave factor */
+       unsigned short  dkg_obs2;       /* obsolete */
+       unsigned short  dkg_obs3;       /* obsolete */
+       unsigned short  dkg_apc;        /* alternates per cyl (SCSI only) */
+       unsigned short  dkg_rpm;        /* revolutions per minute */
+       unsigned short  dkg_pcyl;       /* # of physical cylinders */
+       unsigned short  dkg_write_reinstruct;   /* # sectors to skip, writes */
+       unsigned short  dkg_read_reinstruct;    /* # sectors to skip, reads */
+       unsigned short  dkg_extra[7];   /* for compatible expansion */
+};
+
+/*
+ * These defines are for historic compatibility with old drivers.
+ */
+#define        dkg_bhead       dkg_obs1        /* used to be head offset */
+#define        dkg_gap1        dkg_obs2        /* used to be gap1 */
+#define        dkg_gap2        dkg_obs3        /* used to be gap2 */
+
+/*
+ * Disk io control commands
+ * Warning: some other ioctls with the DIOC prefix exist elsewhere.
+ * The Generic DKIOC numbers are from  0   -  50.
+ *     The Floppy Driver uses          51  - 100.
+ *     The Hard Disk (except SCSI)     101 - 106.      (these are obsolete)
+ *     The CDROM Driver                151 - 200.
+ *     The USCSI ioctl                 201 - 250.
+ */
+#define        DKIOC           (0x04 << 8)
+
+/*
+ * The following ioctls are generic in nature and need to be
+ * suported as appropriate by all disk drivers
+ */
+#define        DKIOCGGEOM      (DKIOC|1)               /* Get geometry */
+#define        DKIOCINFO       (DKIOC|3)               /* Get info */
+#define        DKIOCEJECT      (DKIOC|6)               /* Generic 'eject' */
+#define        DKIOCGVTOC      (DKIOC|11)              /* Get VTOC */
+#define        DKIOCSVTOC      (DKIOC|12)              /* Set VTOC & Write to Disk */
+
+/*
+ * Disk Cache Controls.  These ioctls should be supported by
+ * all disk drivers.
+ *
+ * DKIOCFLUSHWRITECACHE when used from user-mode ignores the ioctl
+ * argument, but it should be passed as NULL to allow for future
+ * reinterpretation.  From user-mode, this ioctl request is synchronous.
+ *
+ * When invoked from within the kernel, the arg can be NULL to indicate
+ * a synchronous request or can be the address of a struct dk_callback
+ * to request an asynchronous callback when the flush request is complete.
+ * In this case, the flag to the ioctl must include FKIOCTL and the
+ * dkc_callback field of the pointed to struct must be non-null or the
+ * request is made synchronously.
+ *
+ * In the callback case: if the ioctl returns 0, a callback WILL be performed.
+ * If the ioctl returns non-zero, a callback will NOT be performed.
+ * NOTE: In some cases, the callback may be done BEFORE the ioctl call
+ * returns.  The caller's locking strategy should be prepared for this case.
+ */
+#define        DKIOCFLUSHWRITECACHE    (DKIOC|34)      /* flush cache to phys medium */
+
+struct dk_callback {
+       void (*dkc_callback)(void *dkc_cookie, int error);
+       void *dkc_cookie;
+       int dkc_flag;
+};
+
+/* bit flag definitions for dkc_flag */
+#define        FLUSH_VOLATILE          0x1     /* Bit 0: if set, only flush */
+                                       /* volatile cache; otherwise, flush */
+                                       /* volatile and non-volatile cache */
+
+#define        DKIOCGETWCE             (DKIOC|36)      /* Get current write cache */
+                                               /* enablement status */
+#define        DKIOCSETWCE             (DKIOC|37)      /* Enable/Disable write cache */
+
+/*
+ * The following ioctls are used by Sun drivers to communicate
+ * with their associated format routines. Support of these ioctls
+ * is not required of foreign drivers
+ */
+#define        DKIOCSGEOM      (DKIOC|2)               /* Set geometry */
+#define        DKIOCSAPART     (DKIOC|4)               /* Set all partitions */
+#define        DKIOCGAPART     (DKIOC|5)               /* Get all partitions */
+#define        DKIOCG_PHYGEOM  (DKIOC|32)              /* get physical geometry */
+#define        DKIOCG_VIRTGEOM (DKIOC|33)              /* get virtual geometry */
+
+/*
+ * The following ioctl's are removable media support
+ */
+#define        DKIOCLOCK       (DKIOC|7)       /* Generic 'lock' */
+#define        DKIOCUNLOCK     (DKIOC|8)       /* Generic 'unlock' */
+#define        DKIOCSTATE      (DKIOC|13)      /* Inquire insert/eject state */
+#define        DKIOCREMOVABLE  (DKIOC|16)      /* is media removable */
+
+
+/*
+ * ioctl for hotpluggable devices
+ */
+#define        DKIOCHOTPLUGGABLE       (DKIOC|35)      /* is hotpluggable */
+
+/*
+ * Ioctl to force driver to re-read the alternate partition and rebuild
+ * the internal defect map.
+ */
+#define        DKIOCADDBAD     (DKIOC|20)      /* Re-read the alternate map (IDE) */
+#define        DKIOCGETDEF     (DKIOC|21)      /* read defect list (IDE)          */
+
+/*
+ * Used by applications to get disk defect information from IDE
+ * drives.
+ */
+#ifdef _SYSCALL32
+struct defect_header32 {
+       int             head;
+       caddr32_t       buffer;
+};
+#endif /* _SYSCALL32 */
+
+struct defect_header {
+       int             head;
+       caddr_t         buffer;
+};
+
+#define        DKIOCPARTINFO   (DKIOC|22)      /* Get partition or slice parameters */
+
+/*
+ * Used by applications to get partition or slice information
+ */
+#ifdef _SYSCALL32
+struct part_info32 {
+       uint32_t        p_start;
+       int             p_length;
+};
+#endif /* _SYSCALL32 */
+
+struct part_info {
+       uint64_t        p_start;
+       int             p_length;
+};
+
+/* The following ioctls are for Optical Memory Device */
+#define        DKIOC_EBP_ENABLE  (DKIOC|40)    /* enable by pass erase on write */
+#define        DKIOC_EBP_DISABLE (DKIOC|41)    /* disable by pass erase on write */
+
+/*
+ * This state enum is the argument passed to the DKIOCSTATE ioctl.
+ */
+enum dkio_state { DKIO_NONE, DKIO_EJECTED, DKIO_INSERTED, DKIO_DEV_GONE };
+
+#define        DKIOCGMEDIAINFO (DKIOC|42)      /* get information about the media */
+
+/*
+ * ioctls to read/write mboot info.
+ */
+#define        DKIOCGMBOOT     (DKIOC|43)      /* get mboot info */
+#define        DKIOCSMBOOT     (DKIOC|44)      /* set mboot info */
+
+/*
+ * ioctl to get the device temperature.
+ */
+#define        DKIOCGTEMPERATURE       (DKIOC|45)      /* get temperature */
+
+/*
+ * Used for providing the temperature.
+ */
+
+struct dk_temperature  {
+       uint_t          dkt_flags;      /* Flags */
+       short           dkt_cur_temp;   /* Current disk temperature */
+       short           dkt_ref_temp;   /* reference disk temperature */
+};
+
+#define        DKT_BYPASS_PM           0x1
+#define        DKT_INVALID_TEMP        0xFFFF
+
+
+/*
+ * Used for Media info or the current profile info
+ */
+struct dk_minfo {
+       uint_t          dki_media_type; /* Media type or profile info */
+       uint_t          dki_lbsize;     /* Logical blocksize of media */
+       diskaddr_t      dki_capacity;   /* Capacity as # of dki_lbsize blks */
+};
+
+/*
+ * Media types or profiles known
+ */
+#define        DK_UNKNOWN              0x00    /* Media inserted - type unknown */
+
+
+/*
+ * SFF 8090 Specification Version 3, media types 0x01 - 0xfffe are retained to
+ * maintain compatibility with SFF8090.  The following define the
+ * optical media type.
+ */
+#define        DK_REMOVABLE_DISK       0x02 /* Removable Disk */
+#define        DK_MO_ERASABLE          0x03 /* MO Erasable */
+#define        DK_MO_WRITEONCE         0x04 /* MO Write once */
+#define        DK_AS_MO                0x05 /* AS MO */
+#define        DK_CDROM                0x08 /* CDROM */
+#define        DK_CDR                  0x09 /* CD-R */
+#define        DK_CDRW                 0x0A /* CD-RW */
+#define        DK_DVDROM               0x10 /* DVD-ROM */
+#define        DK_DVDR                 0x11 /* DVD-R */
+#define        DK_DVDRAM               0x12 /* DVD_RAM or DVD-RW */
+
+/*
+ * Media types for other rewritable magnetic media
+ */
+#define        DK_FIXED_DISK           0x10001 /* Fixed disk SCSI or otherwise */
+#define        DK_FLOPPY               0x10002 /* Floppy media */
+#define        DK_ZIP                  0x10003 /* IOMEGA ZIP media */
+#define        DK_JAZ                  0x10004 /* IOMEGA JAZ media */
+
+#define        DKIOCSETEFI     (DKIOC|17)              /* Set EFI info */
+#define        DKIOCGETEFI     (DKIOC|18)              /* Get EFI info */
+
+#define        DKIOCPARTITION  (DKIOC|9)               /* Get partition info */
+
+/*
+ * Ioctls to get/set volume capabilities related to Logical Volume Managers.
+ * They include the ability to get/set capabilities and to issue a read to a
+ * specific underlying device of a replicated device.
+ */
+
+#define        DKIOCGETVOLCAP  (DKIOC | 25)    /* Get volume capabilities */
+#define        DKIOCSETVOLCAP  (DKIOC | 26)    /* Set volume capabilities */
+#define        DKIOCDMR        (DKIOC | 27)    /* Issue a directed read */
+
+typedef uint_t volcapinfo_t;
+
+typedef uint_t volcapset_t;
+
+#define        DKV_ABR_CAP 0x00000001          /* Support Appl.Based Recovery */
+#define        DKV_DMR_CAP 0x00000002          /* Support Directed  Mirror Read */
+
+typedef struct volcap {
+       volcapinfo_t vc_info;   /* Capabilities available */
+       volcapset_t vc_set;     /* Capabilities set */
+} volcap_t;
+
+#define        VOL_SIDENAME 256
+
+typedef struct vol_directed_rd {
+       int             vdr_flags;
+       offset_t        vdr_offset;
+       size_t          vdr_nbytes;
+       size_t          vdr_bytesread;
+       void            *vdr_data;
+       int             vdr_side;
+       char            vdr_side_name[VOL_SIDENAME];
+} vol_directed_rd_t;
+
+#define        DKV_SIDE_INIT           (-1)
+#define        DKV_DMR_NEXT_SIDE       0x00000001
+#define        DKV_DMR_DONE            0x00000002
+#define        DKV_DMR_ERROR           0x00000004
+#define        DKV_DMR_SUCCESS         0x00000008
+#define        DKV_DMR_SHORT           0x00000010
+
+#ifdef _MULTI_DATAMODEL
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+typedef struct vol_directed_rd32 {
+       int32_t         vdr_flags;
+       offset_t        vdr_offset;     /* 64-bit element on 32-bit alignment */
+       size32_t        vdr_nbytes;
+       size32_t        vdr_bytesread;
+       caddr32_t       vdr_data;
+       int32_t         vdr_side;
+       char            vdr_side_name[VOL_SIDENAME];
+} vol_directed_rd32_t;
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+#endif /* _MULTI_DATAMODEL */
+
+/*
+ * The ioctl is used to fetch disk's device type, vendor ID,
+ * model number/product ID, firmware revision and serial number together.
+ *
+ * Currently there are two device types - DKD_ATA_TYPE which means the
+ * disk is driven by cmdk/ata or dad/uata driver, and DKD_SCSI_TYPE
+ * which means the disk is driven by sd/scsi hba driver.
+ */
+#define        DKIOC_GETDISKID (DKIOC|46)
+
+/* These two labels are for dkd_dtype of dk_disk_id_t */
+#define        DKD_ATA_TYPE    0x01 /* ATA disk or legacy mode SATA disk */
+#define        DKD_SCSI_TYPE   0x02 /* SCSI disk or native mode SATA disk */
+
+#define        DKD_ATA_MODEL   40      /* model number length */
+#define        DKD_ATA_FWVER   8       /* firmware revision length */
+#define        DKD_ATA_SERIAL  20      /* serial number length */
+
+#define        DKD_SCSI_VENDOR 8       /* vendor ID length */
+#define        DKD_SCSI_PRODUCT 16     /* product ID length */
+#define        DKD_SCSI_REVLEVEL 4     /* revision level length */
+#define        DKD_SCSI_SERIAL 12      /* serial number length */
+
+/*
+ * The argument type for DKIOC_GETDISKID ioctl.
+ */
+typedef struct dk_disk_id {
+       uint_t  dkd_dtype;
+       union {
+               struct {
+                       char dkd_amodel[DKD_ATA_MODEL];         /* 40 bytes */
+                       char dkd_afwver[DKD_ATA_FWVER];         /* 8 bytes */
+                       char dkd_aserial[DKD_ATA_SERIAL];       /* 20 bytes */
+               } ata_disk_id;
+               struct {
+                       char dkd_svendor[DKD_SCSI_VENDOR];      /* 8 bytes */
+                       char dkd_sproduct[DKD_SCSI_PRODUCT];    /* 16 bytes */
+                       char dkd_sfwver[DKD_SCSI_REVLEVEL];     /* 4 bytes */
+                       char dkd_sserial[DKD_SCSI_SERIAL];      /* 12 bytes */
+               } scsi_disk_id;
+       } disk_id;
+} dk_disk_id_t;
+
+/*
+ * The ioctl is used to update the firmware of device.
+ */
+#define        DKIOC_UPDATEFW          (DKIOC|47)
+
+/* The argument type for DKIOC_UPDATEFW ioctl */
+typedef struct dk_updatefw {
+       caddr_t         dku_ptrbuf;     /* pointer to firmware buf */
+       uint_t          dku_size;       /* firmware buf length */
+       uint8_t         dku_type;       /* firmware update type */
+} dk_updatefw_t;
+
+#ifdef _SYSCALL32
+typedef struct dk_updatefw_32 {
+       caddr32_t       dku_ptrbuf;     /* pointer to firmware buf */
+       uint_t          dku_size;       /* firmware buf length */
+       uint8_t         dku_type;       /* firmware update type */
+} dk_updatefw_32_t;
+#endif /* _SYSCALL32 */
+
+/*
+ * firmware update type - temporary or permanent use
+ */
+#define        FW_TYPE_TEMP    0x0             /* temporary use */
+#define        FW_TYPE_PERM    0x1             /* permanent use */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DKIO_H */
diff --git a/zfs/lib/libspl/include/sys/dklabel.h b/zfs/lib/libspl/include/sys/dklabel.h
new file mode 100644 (file)
index 0000000..8772e4a
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * 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 1990-2002 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_DKLABEL_H
+#define        _SYS_DKLABEL_H
+
+
+
+#include <sys/isa_defs.h>
+#include <sys/types32.h>
+#include <sys/isa_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Miscellaneous defines
+ */
+#define        DKL_MAGIC       0xDABE          /* magic number */
+#define        FKL_MAGIC       0xff            /* magic number for DOS floppies */
+
+#if defined(_SUNOS_VTOC_16)
+#define        NDKMAP          16              /* # of logical partitions */
+#define        DK_LABEL_LOC    1               /* location of disk label */
+#elif defined(_SUNOS_VTOC_8)
+#define        NDKMAP          8               /* # of logical partitions */
+#define        DK_LABEL_LOC    0               /* location of disk label */
+#else
+#error "No VTOC format defined."
+#endif
+
+#define        LEN_DKL_ASCII   128             /* length of dkl_asciilabel */
+#define        LEN_DKL_VVOL    8               /* length of v_volume */
+#define        DK_LABEL_SIZE   512             /* size of disk label */
+#define        DK_MAX_BLOCKS   0x7fffffff      /* max # of blocks handled */
+
+/*
+ * Reserve two cylinders on SCSI disks.
+ * One is for the backup disk label and the other is for the deviceid.
+ *
+ * IPI disks only reserve one cylinder, but they will go away soon.
+ * CDROMs do not reserve any cylinders.
+ */
+#define        DK_ACYL         2
+
+/*
+ * Format of a Sun disk label.
+ * Resides in cylinder 0, head 0, sector 0.
+ *
+ * sizeof (struct dk_label) should be 512 (the current sector size),
+ * but should the sector size increase, this structure should remain
+ * at the beginning of the sector.
+ */
+
+/*
+ * partition headers:  section 1
+ * Returned in struct dk_allmap by ioctl DKIOC[SG]APART (dkio(7I))
+ */
+struct dk_map {
+       uint64_t        dkl_cylno;      /* starting cylinder */
+       uint64_t        dkl_nblk;       /* number of blocks;  if == 0, */
+                                       /* partition is undefined */
+};
+
+/*
+ * partition headers:  section 1
+ * Fixed size for on-disk dk_label
+ */
+struct dk_map32 {
+       daddr32_t       dkl_cylno;      /* starting cylinder */
+       daddr32_t       dkl_nblk;       /* number of blocks;  if == 0, */
+                                       /* partition is undefined */
+};
+
+/*
+ * partition headers:  section 2,
+ * brought over from AT&T SVr4 vtoc structure.
+ */
+struct dk_map2 {
+       uint16_t        p_tag;          /* ID tag of partition */
+       uint16_t        p_flag;         /* permission flag */
+};
+
+struct dkl_partition    {
+       uint16_t        p_tag;          /* ID tag of partition */
+       uint16_t        p_flag;         /* permision flags */
+       daddr32_t       p_start;        /* start sector no of partition */
+       int32_t         p_size;         /* # of blocks in partition */
+};
+
+
+/*
+ * VTOC inclusions from AT&T SVr4
+ * Fixed sized types for on-disk VTOC
+ */
+
+struct dk_vtoc {
+#if defined(_SUNOS_VTOC_16)
+       uint32_t v_bootinfo[3];         /* info for mboot (unsupported) */
+       uint32_t v_sanity;              /* to verify vtoc sanity */
+       uint32_t v_version;             /* layout version */
+       char    v_volume[LEN_DKL_VVOL]; /* volume name */
+       uint16_t v_sectorsz;            /* sector size in bytes */
+       uint16_t v_nparts;              /* number of partitions */
+       uint32_t v_reserved[10];        /* free space */
+       struct dkl_partition v_part[NDKMAP];    /* partition headers */
+       time32_t timestamp[NDKMAP];     /* partition timestamp (unsupported) */
+       char    v_asciilabel[LEN_DKL_ASCII];    /* for compatibility    */
+#elif defined(_SUNOS_VTOC_8)
+       uint32_t        v_version;              /* layout version */
+       char            v_volume[LEN_DKL_VVOL]; /* volume name */
+       uint16_t        v_nparts;               /* number of partitions  */
+       struct dk_map2  v_part[NDKMAP];         /* partition hdrs, sec 2 */
+       uint32_t        v_bootinfo[3];          /* info needed by mboot */
+       uint32_t        v_sanity;               /* to verify vtoc sanity */
+       uint32_t        v_reserved[10];         /* free space */
+       time32_t        v_timestamp[NDKMAP];    /* partition timestamp */
+#else
+#error "No VTOC format defined."
+#endif
+};
+
+/*
+ * define the amount of disk label padding needed to make
+ * the entire structure occupy 512 bytes.
+ */
+#if defined(_SUNOS_VTOC_16)
+#define        LEN_DKL_PAD     (DK_LABEL_SIZE - \
+                           ((sizeof (struct dk_vtoc) + \
+                           (4 * sizeof (uint32_t)) + \
+                           (12 * sizeof (uint16_t)) + \
+                           (2 * (sizeof (uint16_t))))))
+#elif defined(_SUNOS_VTOC_8)
+#define        LEN_DKL_PAD     (DK_LABEL_SIZE \
+                           - ((LEN_DKL_ASCII) + \
+                           (sizeof (struct dk_vtoc)) + \
+                           (sizeof (struct dk_map32)  * NDKMAP) + \
+                           (14 * (sizeof (uint16_t))) + \
+                           (2 * (sizeof (uint16_t)))))
+#else
+#error "No VTOC format defined."
+#endif
+
+
+struct dk_label {
+#if defined(_SUNOS_VTOC_16)
+       struct  dk_vtoc dkl_vtoc;       /* vtoc inclusions from AT&T SVr4 */
+       uint32_t        dkl_pcyl;       /* # of physical cylinders */
+       uint32_t        dkl_ncyl;       /* # of data cylinders */
+       uint16_t        dkl_acyl;       /* # of alternate cylinders */
+       uint16_t        dkl_bcyl;       /* cyl offset (for fixed head area) */
+       uint32_t        dkl_nhead;      /* # of heads */
+       uint32_t        dkl_nsect;      /* # of data sectors per track */
+       uint16_t        dkl_intrlv;     /* interleave factor */
+       uint16_t        dkl_skew;       /* skew factor */
+       uint16_t        dkl_apc;        /* alternates per cyl (SCSI only)   */
+       uint16_t        dkl_rpm;        /* revolutions per minute */
+       uint16_t        dkl_write_reinstruct;   /* # sectors to skip, writes */
+       uint16_t        dkl_read_reinstruct;    /* # sectors to skip, reads  */
+       uint16_t        dkl_extra[4];   /* for compatible expansion */
+       char            dkl_pad[LEN_DKL_PAD];   /* unused part of 512 bytes */
+#elif defined(_SUNOS_VTOC_8)
+       char            dkl_asciilabel[LEN_DKL_ASCII]; /* for compatibility */
+       struct dk_vtoc  dkl_vtoc;       /* vtoc inclusions from AT&T SVr4 */
+       uint16_t        dkl_write_reinstruct;   /* # sectors to skip, writes */
+       uint16_t        dkl_read_reinstruct;    /* # sectors to skip, reads */
+       char            dkl_pad[LEN_DKL_PAD]; /* unused part of 512 bytes */
+       uint16_t        dkl_rpm;        /* rotations per minute */
+       uint16_t        dkl_pcyl;       /* # physical cylinders */
+       uint16_t        dkl_apc;        /* alternates per cylinder */
+       uint16_t        dkl_obs1;       /* obsolete */
+       uint16_t        dkl_obs2;       /* obsolete */
+       uint16_t        dkl_intrlv;     /* interleave factor */
+       uint16_t        dkl_ncyl;       /* # of data cylinders */
+       uint16_t        dkl_acyl;       /* # of alternate cylinders */
+       uint16_t        dkl_nhead;      /* # of heads in this partition */
+       uint16_t        dkl_nsect;      /* # of 512 byte sectors per track */
+       uint16_t        dkl_obs3;       /* obsolete */
+       uint16_t        dkl_obs4;       /* obsolete */
+       struct dk_map32 dkl_map[NDKMAP]; /* logical partition headers */
+#else
+#error "No VTOC format defined."
+#endif
+       uint16_t        dkl_magic;      /* identifies this label format */
+       uint16_t        dkl_cksum;      /* xor checksum of sector */
+};
+
+#if defined(_SUNOS_VTOC_16)
+#define        dkl_asciilabel  dkl_vtoc.v_asciilabel
+#define        v_timestamp     timestamp
+
+#elif defined(_SUNOS_VTOC_8)
+
+/*
+ * These defines are for historic compatibility with old drivers.
+ */
+#define        dkl_gap1        dkl_obs1        /* used to be gap1 */
+#define        dkl_gap2        dkl_obs2        /* used to be gap2 */
+#define        dkl_bhead       dkl_obs3        /* used to be label head offset */
+#define        dkl_ppart       dkl_obs4        /* used to by physical partition */
+#else
+#error "No VTOC format defined."
+#endif
+
+struct fk_label {                      /* DOS floppy label */
+       uchar_t  fkl_type;
+       uchar_t  fkl_magich;
+       uchar_t  fkl_magicl;
+       uchar_t  filler;
+};
+
+/*
+ * Layout of stored fabricated device id  (on-disk)
+ */
+#define        DK_DEVID_BLKSIZE        (512)
+#define        DK_DEVID_SIZE           (DK_DEVID_BLKSIZE - ((sizeof (uchar_t) * 7)))
+#define        DK_DEVID_REV_MSB        (0)
+#define        DK_DEVID_REV_LSB        (1)
+
+struct dk_devid {
+       uchar_t dkd_rev_hi;                     /* revision (MSB) */
+       uchar_t dkd_rev_lo;                     /* revision (LSB) */
+       uchar_t dkd_flags;                      /* flags (not used yet) */
+       uchar_t dkd_devid[DK_DEVID_SIZE];       /* devid stored here */
+       uchar_t dkd_checksum3;                  /* checksum (MSB) */
+       uchar_t dkd_checksum2;
+       uchar_t dkd_checksum1;
+       uchar_t dkd_checksum0;                  /* checksum (LSB) */
+};
+
+#define        DKD_GETCHKSUM(dkd)      ((dkd)->dkd_checksum3 << 24) + \
+                               ((dkd)->dkd_checksum2 << 16) + \
+                               ((dkd)->dkd_checksum1 << 8)  + \
+                               ((dkd)->dkd_checksum0)
+
+#define        DKD_FORMCHKSUM(c, dkd)  (dkd)->dkd_checksum3 = hibyte(hiword((c))); \
+                               (dkd)->dkd_checksum2 = lobyte(hiword((c))); \
+                               (dkd)->dkd_checksum1 = hibyte(loword((c))); \
+                               (dkd)->dkd_checksum0 = lobyte(loword((c)));
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DKLABEL_H */
diff --git a/zfs/lib/libspl/include/sys/dktp/Makefile.am b/zfs/lib/libspl/include/sys/dktp/Makefile.am
new file mode 100644 (file)
index 0000000..9887675
--- /dev/null
@@ -0,0 +1,4 @@
+libspldir = $(includedir)/libspl/sys/dktp
+libspl_HEADERS = \
+       $(top_srcdir)/lib/libspl/include/sys/dktp/fdisk.h
+
diff --git a/zfs/lib/libspl/include/sys/dktp/Makefile.in b/zfs/lib/libspl/include/sys/dktp/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/include/sys/dktp/fdisk.h b/zfs/lib/libspl/include/sys/dktp/fdisk.h
new file mode 100644 (file)
index 0000000..e90135f
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+/*     Copyright (c) 1984, 1986, 1987, 1988 AT&T       */
+/*       All Rights Reserved   */
+
+
+#ifndef _SYS_DKTP_FDISK_H
+#define        _SYS_DKTP_FDISK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * fdisk.h
+ * This file defines the structure of physical disk sector 0 for use on
+ * AT386 systems.  The format of this sector is constrained by the ROM
+ * BIOS and MS-DOS conventions.
+ * Note that this block does not define the partitions used by the unix
+ * driver.  The unix partitions are obtained from the VTOC.
+ */
+
+/*
+ * the MAX values are the maximum usable values for BIOS chs values
+ * The MAX_CYL value of 1022 is the maximum usable value
+ *   the value of 1023 is a fence value,
+ *   indicating no CHS geometry exists for the corresponding LBA value.
+ * HEAD range [ 0 .. MAX_HEAD ], so number of heads is (MAX_HEAD + 1)
+ * SECT range [ 1 .. MAX_SECT ], so number of sectors is (MAX_SECT)
+ */
+#define        MAX_SECT        (63)
+#define        MAX_CYL         (1022)
+#define        MAX_HEAD        (254)
+
+/*
+ * BOOTSZ was reduced from 446 to 440 bytes to NOT overwrite the Windows
+ * Vista DISKID. Otherwise Vista won't boot from Solaris GRUB in a dual-boot
+ * setup.
+ * The actual size of mboot code is 425 bytes while that of GRUB stage1 is
+ * 423 bytes. So this changes does not harm them.
+ */
+#define        BOOTSZ          440     /* size of boot code in master boot block */
+#define        FD_NUMPART      4       /* number of 'partitions' in fdisk table */
+#define        MBB_MAGIC       0xAA55  /* magic number for mboot.signature */
+#define        DEFAULT_INTLV   4       /* default interleave for testing tracks */
+#define        MINPSIZE        4       /* minimum number of cylinders in a partition */
+#define        TSTPAT          0xE5    /* test pattern for verifying disk */
+
+/*
+ * structure to hold the fdisk partition table
+ */
+struct ipart {
+       unsigned char bootid;   /* bootable or not */
+       unsigned char beghead;  /* beginning head, sector, cylinder */
+       unsigned char begsect;  /* begcyl is a 10-bit number. High 2 bits */
+       unsigned char begcyl;   /*      are in begsect. */
+       unsigned char systid;   /* OS type */
+       unsigned char endhead;  /* ending head, sector, cylinder */
+       unsigned char endsect;  /* endcyl is a 10-bit number.  High 2 bits */
+       unsigned char endcyl;   /*      are in endsect. */
+       uint32_t relsect;       /* first sector relative to start of disk */
+       uint32_t numsect;       /* number of sectors in partition */
+};
+/*
+ * Values for bootid.
+ */
+#define        NOTACTIVE       0
+#define        ACTIVE          128
+/*
+ * Values for systid.
+ */
+#define        UNUSED          0       /* Empty Partition */
+#define        DOSOS12         1       /* DOS partition, 12-bit FAT */
+#define        PCIXOS          2       /* PC/IX partition */
+#define        DOSOS16         4       /* DOS partition, 16-bit FAT */
+#define        EXTDOS          5       /* EXT-DOS partition */
+#define        DOSHUGE         6       /* Huge DOS partition  > 32MB */
+#define        FDISK_IFS       7       /* Installable File System (IFS): HPFS & NTFS */
+#define        FDISK_AIXBOOT   8       /* AIX Boot */
+#define        FDISK_AIXDATA   9       /* AIX Data */
+#define        FDISK_OS2BOOT   10      /* OS/2 Boot Manager */
+#define        FDISK_WINDOWS   11      /* Windows 95 FAT32 (up to 2047GB) */
+#define        FDISK_EXT_WIN   12      /* Windows 95 FAT32 (extended-INT13) */
+#define        FDISK_FAT95     14      /* DOS 16-bit FAT, LBA-mapped */
+#define        FDISK_EXTLBA    15      /* Extended partition, LBA-mapped */
+#define        DIAGPART        18      /* Diagnostic boot partition (OS independent) */
+#define        FDISK_LINUX     65      /* Linux */
+#define        FDISK_LINUXDSWAP        66      /* Linux swap (sharing disk w/ DRDOS) */
+#define        FDISK_LINUXDNAT 67      /* Linux native (sharing disk with DRDOS) */
+#define        FDISK_CPM       82      /* CP/M */
+#define        DOSDATA         86      /* DOS data partition */
+#define        OTHEROS         98      /* part. type for appl. (DB?) needs */
+                               /* raw partition.  ID was 0 but conflicted */
+                               /* with DOS 3.3 fdisk    */
+#define        UNIXOS          99      /* UNIX V.x partition */
+#define        FDISK_NOVELL2   100     /* Novell Netware 286 */
+#define        FDISK_NOVELL3   101     /* Novell Netware 3.x and later */
+#define        FDISK_QNX4      119     /* QNX 4.x */
+#define        FDISK_QNX42     120     /* QNX 4.x 2nd part */
+#define        FDISK_QNX43     121     /* QNX 4.x 3rd part */
+#define        SUNIXOS         130     /* Solaris UNIX partition */
+#define        FDISK_LINUXNAT  131     /* Linux native */
+#define        FDISK_NTFSVOL1  134     /* NTFS volume set 1 */
+#define        FDISK_NTFSVOL2  135     /* NTFS volume set 2 */
+#define        FDISK_BSD       165     /* BSD/386, 386BSD, NetBSD, FreeBSD, OpenBSD */
+#define        FDISK_NEXTSTEP  167     /* NeXTSTEP */
+#define        FDISK_BSDIFS    183     /* BSDI file system */
+#define        FDISK_BSDISWAP  184     /* BSDI swap */
+#define        X86BOOT         190     /* x86 Solaris boot partition */
+#define        SUNIXOS2        191     /* Solaris UNIX partition */
+#define        EFI_PMBR        238     /* EFI PMBR */
+#define        EFI_FS          239     /* EFI File System (System Partition) */
+#define        MAXDOS          65535L  /* max size (sectors) for DOS partition */
+
+/*
+ * structure to hold master boot block in physical sector 0 of the disk.
+ * Note that partitions stuff can't be directly included in the structure
+ * because of lameo '386 compiler alignment design.
+ * Alignment issues also force us to have 2 16bit entities for a single
+ * 32bit win_volserno. It is not used anywhere anyway.
+ */
+
+struct mboot { /* master boot block */
+       char    bootinst[BOOTSZ];
+       uint16_t win_volserno_lo;
+       uint16_t win_volserno_hi;
+       uint16_t reserved;
+       char    parts[FD_NUMPART * sizeof (struct ipart)];
+       ushort_t signature;
+};
+
+#if defined(__i386) || defined(__amd64)
+
+/* Byte offset of the start of the partition table within the sector */
+#define        FDISK_PART_TABLE_START  446
+
+/* Maximum number of valid partitions assumed as 32 */
+#define        MAX_EXT_PARTS   32
+
+#else
+
+#define        MAX_EXT_PARTS   0
+
+#endif /* if defined(__i386) || defined(__amd64) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_DKTP_FDISK_H */
diff --git a/zfs/lib/libspl/include/sys/feature_tests.h b/zfs/lib/libspl/include/sys/feature_tests.h
new file mode 100644 (file)
index 0000000..1a68b75
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_FEATURE_TESTS_H
+#define        _SYS_FEATURE_TESTS_H
+
+#define        __NORETURN      __attribute__((__noreturn__))
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/file.h b/zfs/lib/libspl/include/sys/file.h
new file mode 100644 (file)
index 0000000..b5d985b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_FILE_H
+#define        _LIBSPL_SYS_FILE_H
+
+#include_next <sys/file.h>
+
+#include <sys/user.h>
+
+#define        FREAD   1
+#define        FWRITE  2
+// #define     FAPPEND  8
+
+#define        FCREAT  O_CREAT
+#define        FTRUNC  O_TRUNC
+#define        FOFFMAX O_LARGEFILE
+#define        FSYNC   O_SYNC
+#define        FDSYNC  O_DSYNC
+#define        FRSYNC  O_RSYNC
+#define        FEXCL   O_EXCL
+
+#define        FNODSYNC        0x10000 /* fsync pseudo flag */
+#define        FNOFOLLOW       0x20000 /* don't follow symlinks */
+#define        FIGNORECASE     0x80000 /* request case-insensitive lookups */
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/frame.h b/zfs/lib/libspl/include/sys/frame.h
new file mode 100644 (file)
index 0000000..a4c7d8b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_FRAME_H
+#define        _SYS_FRAME_H
+
+#include <sys/types.h>
+
+#if defined(_LP64) || defined(_I32LPx)
+typedef long   greg_t;
+#else
+typedef int    greg_t;
+#endif
+
+struct frame {
+       greg_t fr_savfp;  /* saved frame pointer */
+       greg_t fr_savpc;  /* saved program counter */
+};
+
+
+/*
+ * In the x86 world, a stack frame looks like this:
+ *
+ *             |--------------------------|
+ * 4n+8(%ebp) ->| argument word n         |
+ *             | ...                      |    (Previous frame)
+ *    8(%ebp) ->| argument word 0         |
+ *             |--------------------------|--------------------
+ *    4(%ebp) ->| return address          |
+ *             |--------------------------|
+ *    0(%ebp) ->| previous %ebp (optional) |
+ *             |--------------------------|
+ *   -4(%ebp) ->| unspecified             |    (Current frame)
+ *             | ...                      |
+ *    0(%esp) ->| variable size                   |
+ *             |--------------------------|
+ */
+
+/*
+ * Stack alignment macros.
+ */
+
+#define        STACK_ALIGN32           4
+#define        STACK_ENTRY_ALIGN32     4
+#define        STACK_BIAS32            0
+#define        SA32(x)                 (((x)+(STACK_ALIGN32-1)) & ~(STACK_ALIGN32-1))
+#define        STACK_RESERVE32         0
+#define        MINFRAME32              0
+
+#if defined(__amd64)
+
+/*
+ * In the amd64 world, a stack frame looks like this:
+ *
+ *             |--------------------------|
+ * 8n+16(%rbp)->| argument word n         |
+ *             | ...                      |    (Previous frame)
+ *   16(%rbp) ->| argument word 0         |
+ *             |--------------------------|--------------------
+ *    8(%rbp) ->| return address          |
+ *             |--------------------------|
+ *    0(%rbp) ->| previous %rbp            |
+ *             |--------------------------|
+ *   -8(%rbp) ->| unspecified             |    (Current frame)
+ *             | ...                      |
+ *    0(%rsp) ->| variable size                   |
+ *             |--------------------------|
+ * -128(%rsp) ->| reserved for function           |
+ *             |--------------------------|
+ *
+ * The end of the input argument area must be aligned on a 16-byte
+ * boundary; i.e. (%rsp - 8) % 16 == 0 at function entry.
+ *
+ * The 128-byte location beyond %rsp is considered to be reserved for
+ * functions and is NOT modified by signal handlers.  It can be used
+ * to store temporary data that is not needed across function calls.
+ */
+
+/*
+ * Stack alignment macros.
+ */
+
+#define        STACK_ALIGN64           16
+#define        STACK_ENTRY_ALIGN64     8
+#define        STACK_BIAS64            0
+#define        SA64(x)                 (((x)+(STACK_ALIGN64-1)) & ~(STACK_ALIGN64-1))
+#define        STACK_RESERVE64         128
+#define        MINFRAME64              0
+
+#define        STACK_ALIGN             STACK_ALIGN64
+#define        STACK_ENTRY_ALIGN       STACK_ENTRY_ALIGN64
+#define        STACK_BIAS              STACK_BIAS64
+#define        SA(x)                   SA64(x)
+#define        STACK_RESERVE           STACK_RESERVE64
+#define        MINFRAME                MINFRAME64
+
+#elif defined(__i386)
+
+#define        STACK_ALIGN             STACK_ALIGN32
+#define        STACK_ENTRY_ALIGN       STACK_ENTRY_ALIGN32
+#define        STACK_BIAS              STACK_BIAS32
+#define        SA(x)                   SA32(x)
+#define        STACK_RESERVE           STACK_RESERVE32
+#define        MINFRAME                MINFRAME32
+
+#endif /* __i386 */
+
+#endif /* _SYS_FRAME_H */
diff --git a/zfs/lib/libspl/include/sys/int_limits.h b/zfs/lib/libspl/include/sys/int_limits.h
new file mode 100644 (file)
index 0000000..7af68cd
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_INT_LIMITS_H
+#define        _LIBSPL_SYS_INT_LIMITS_H
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/int_types.h b/zfs/lib/libspl/include/sys/int_types.h
new file mode 100644 (file)
index 0000000..51e9e02
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SOL_SYS_INT_TYPES_H
+#define        _SOL_SYS_INT_TYPES_H
+
+#include <inttypes.h>
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/inttypes.h b/zfs/lib/libspl/include/sys/inttypes.h
new file mode 100644 (file)
index 0000000..d7d0639
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SOL_SYS_INTTYPES_H
+#define        _SOL_SYS_INTTYPES_H
+
+#include <inttypes.h>
+
+#define        _INT64_TYPE
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/isa_defs.h b/zfs/lib/libspl/include/sys/isa_defs.h
new file mode 100644 (file)
index 0000000..3bca5cf
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * 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        _SYS_ISA_DEFS_H
+#define        _SYS_ISA_DEFS_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* x86_64 arch specific defines */
+#if defined(__x86_64) || defined(__x86_64__)
+
+#if !defined(__x86_64)
+#define        __x86_64
+#endif
+
+#if !defined(__amd64)
+#define        __amd64
+#endif
+
+#if !defined(__x86)
+#define        __x86
+#endif
+
+#if !defined(_LP64)
+#define        _LP64
+#endif
+
+#if !defined(_LITTLE_ENDIAN)
+#define        _LITTLE_ENDIAN
+#endif
+
+#define        _SUNOS_VTOC_16
+
+/* i386 arch specific defines */
+#elif defined(__i386) || defined(__i386__)
+
+#if !defined(__i386)
+#define        __i386
+#endif
+
+#if !defined(__x86)
+#define        __x86
+#endif
+
+#if !defined(_ILP32)
+#define        _ILP32
+#endif
+
+#if !defined(_LITTLE_ENDIAN)
+#define        _LITTLE_ENDIAN
+#endif
+
+#define        _SUNOS_VTOC_16
+
+/* powerpc arch specific defines */
+#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__)
+
+#if !defined(__powerpc)
+#define        __powerpc
+#endif
+
+#if !defined(__powerpc__)
+#define        __powerpc__
+#endif
+
+#if defined(__powerpc64__)
+#if !defined(_LP64)
+#define        _LP64
+#endif
+#else
+#if !defined(_ILP32)
+#define        _ILP32
+#endif
+#endif
+
+#if !defined(_BIG_ENDIAN)
+#define        _BIG_ENDIAN
+#endif
+
+#define        _SUNOS_VTOC_16
+
+/* arm arch specific defines */
+#elif defined(__arm) || defined(__arm__) || defined(__aarch64__)
+
+#if !defined(__arm)
+#define        __arm
+#endif
+
+#if !defined(__arm__)
+#define        __arm__
+#endif
+
+#if defined(__aarch64__)
+#if !defined(_LP64)
+#define        _LP64
+#endif
+#else
+#if !defined(_ILP32)
+#define        _ILP32
+#endif
+#endif
+
+#if defined(__ARMEL__) || defined(__AARCH64EL__)
+#define        _LITTLE_ENDIAN
+#else
+#define        _BIG_ENDIAN
+#endif
+
+#define        _SUNOS_VTOC_16
+
+/* sparc arch specific defines */
+#elif defined(__sparc) || defined(__sparc__) || defined(__sparc64__)
+
+#if !defined(__sparc)
+#define        __sparc
+#endif
+
+#if !defined(__sparc__)
+#define        __sparc__
+#endif
+
+#define        _BIG_ENDIAN
+#define        _SUNOS_VTOC_16
+
+#if defined(__sparc64__)
+#if !defined(_LP64)
+#define        _LP64
+#endif
+#else
+#if !defined(_ILP32)
+#define        _ILP32
+#endif
+#endif
+
+/* s390 arch specific defines */
+#elif defined(__s390__)
+#if defined(__s390x__)
+#if !defined(_LP64)
+#define        _LP64
+#endif
+#else
+#if !defined(_ILP32)
+#define        _ILP32
+#endif
+#endif
+
+#define        _BIG_ENDIAN
+#define        _SUNOS_VTOC_16
+
+/* MIPS arch specific defines */
+#elif defined(__mips__)
+
+#if defined(__MIPSEB__)
+#define        _BIG_ENDIAN
+#elif defined(__MIPSEL__)
+#define        _LITTLE_ENDIAN
+#else
+#error MIPS no endian specified
+#endif
+
+#ifndef _LP64
+#define        _ILP32
+#endif
+
+#define        _SUNOS_VTOC_16
+
+#else
+/*
+ * Currently supported:
+ * x86_64, i386, arm, powerpc, s390, sparc, and mips
+ */
+#error "Unsupported ISA type"
+#endif
+
+#if defined(_ILP32) && defined(_LP64)
+#error "Both _ILP32 and _LP64 are defined"
+#endif
+
+#if !defined(_ILP32) && !defined(_LP64)
+#error "Neither _ILP32 or _LP64 are defined"
+#endif
+
+#if defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)
+#error "Both _LITTLE_ENDIAN and _BIG_ENDIAN are defined"
+#endif
+
+#if !defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+#error "Neither _LITTLE_ENDIAN nor _BIG_ENDIAN are defined"
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _SYS_ISA_DEFS_H */
diff --git a/zfs/lib/libspl/include/sys/kmem.h b/zfs/lib/libspl/include/sys/kmem.h
new file mode 100644 (file)
index 0000000..83d4756
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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 _SYS_KMEM_H
+#define        _SYS_KMEM_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        KM_SLEEP        0x00000000      /* same as KM_SLEEP */
+#define        KM_NOSLEEP      0x00000001      /* same as KM_NOSLEEP */
+
+#define        kmem_alloc(size, flags)         malloc(size)
+#define        kmem_free(ptr, size)            free(ptr)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_KMEM_H */
diff --git a/zfs/lib/libspl/include/sys/kstat.h b/zfs/lib/libspl/include/sys/kstat.h
new file mode 100644 (file)
index 0000000..fcd3ed9
--- /dev/null
@@ -0,0 +1,820 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_KSTAT_H
+#define        _SYS_KSTAT_H
+
+
+
+/*
+ * Definition of general kernel statistics structures and /dev/kstat ioctls
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int    kid_t;          /* unique kstat id */
+
+/*
+ * Kernel statistics driver (/dev/kstat) ioctls
+ */
+
+#define        KSTAT_IOC_BASE          ('K' << 8)
+
+#define        KSTAT_IOC_CHAIN_ID      KSTAT_IOC_BASE | 0x01
+#define        KSTAT_IOC_READ          KSTAT_IOC_BASE | 0x02
+#define        KSTAT_IOC_WRITE         KSTAT_IOC_BASE | 0x03
+
+/*
+ * /dev/kstat ioctl usage (kd denotes /dev/kstat descriptor):
+ *
+ *     kcid = ioctl(kd, KSTAT_IOC_CHAIN_ID, NULL);
+ *     kcid = ioctl(kd, KSTAT_IOC_READ, kstat_t *);
+ *     kcid = ioctl(kd, KSTAT_IOC_WRITE, kstat_t *);
+ */
+
+#define        KSTAT_STRLEN    31      /* 30 chars + NULL; must be 16 * n - 1 */
+
+/*
+ * The generic kstat header
+ */
+
+typedef struct kstat {
+       /*
+        * Fields relevant to both kernel and user
+        */
+       hrtime_t        ks_crtime;      /* creation time (from gethrtime()) */
+       struct kstat    *ks_next;       /* kstat chain linkage */
+       kid_t           ks_kid;         /* unique kstat ID */
+       char            ks_module[KSTAT_STRLEN]; /* provider module name */
+       uchar_t         ks_resv;        /* reserved, currently just padding */
+       int             ks_instance;    /* provider module's instance */
+       char            ks_name[KSTAT_STRLEN]; /* kstat name */
+       uchar_t         ks_type;        /* kstat data type */
+       char            ks_class[KSTAT_STRLEN]; /* kstat class */
+       uchar_t         ks_flags;       /* kstat flags */
+       void            *ks_data;       /* kstat type-specific data */
+       uint_t          ks_ndata;       /* # of type-specific data records */
+       size_t          ks_data_size;   /* total size of kstat data section */
+       hrtime_t        ks_snaptime;    /* time of last data shapshot */
+       /*
+        * Fields relevant to kernel only
+        */
+       int             (*ks_update)(struct kstat *, int); /* dynamic update */
+       void            *ks_private;    /* arbitrary provider-private data */
+       int             (*ks_snapshot)(struct kstat *, void *, int);
+       void            *ks_lock;       /* protects this kstat's data */
+} kstat_t;
+
+#ifdef _SYSCALL32
+
+typedef int32_t kid32_t;
+
+typedef struct kstat32 {
+       /*
+        * Fields relevant to both kernel and user
+        */
+       hrtime_t        ks_crtime;
+       caddr32_t       ks_next;                /* struct kstat pointer */
+       kid32_t         ks_kid;
+       char            ks_module[KSTAT_STRLEN];
+       uint8_t         ks_resv;
+       int32_t         ks_instance;
+       char            ks_name[KSTAT_STRLEN];
+       uint8_t         ks_type;
+       char            ks_class[KSTAT_STRLEN];
+       uint8_t         ks_flags;
+       caddr32_t       ks_data;                /* type-specific data */
+       uint32_t        ks_ndata;
+       size32_t        ks_data_size;
+       hrtime_t        ks_snaptime;
+       /*
+        * Fields relevant to kernel only (only needed here for padding)
+        */
+       int32_t         _ks_update;
+       caddr32_t       _ks_private;
+       int32_t         _ks_snapshot;
+       caddr32_t       _ks_lock;
+} kstat32_t;
+
+#endif /* _SYSCALL32 */
+
+/*
+ * kstat structure and locking strategy
+ *
+ * Each kstat consists of a header section (a kstat_t) and a data section.
+ * The system maintains a set of kstats, protected by kstat_chain_lock.
+ * kstat_chain_lock protects all additions to/deletions from this set,
+ * as well as all changes to kstat headers.  kstat data sections are
+ * *optionally* protected by the per-kstat ks_lock.  If ks_lock is non-NULL,
+ * kstat clients (e.g. /dev/kstat) will acquire this lock for all of their
+ * operations on that kstat.  It is up to the kstat provider to decide whether
+ * guaranteeing consistent data to kstat clients is sufficiently important
+ * to justify the locking cost.  Note, however, that most statistic updates
+ * already occur under one of the provider's mutexes, so if the provider sets
+ * ks_lock to point to that mutex, then kstat data locking is free.
+ *
+ * NOTE: variable-size kstats MUST employ kstat data locking, to prevent
+ * data-size races with kstat clients.
+ *
+ * NOTE: ks_lock is really of type (kmutex_t *); it is declared as (void *)
+ * in the kstat header so that users don't have to be exposed to all of the
+ * kernel's lock-related data structures.
+ */
+
+#if    defined(_KERNEL)
+
+#define        KSTAT_ENTER(k)  \
+       { kmutex_t *lp = (k)->ks_lock; if (lp) mutex_enter(lp); }
+
+#define        KSTAT_EXIT(k)   \
+       { kmutex_t *lp = (k)->ks_lock; if (lp) mutex_exit(lp); }
+
+#define        KSTAT_UPDATE(k, rw)             (*(k)->ks_update)((k), (rw))
+
+#define        KSTAT_SNAPSHOT(k, buf, rw)      (*(k)->ks_snapshot)((k), (buf), (rw))
+
+#endif /* defined(_KERNEL) */
+
+/*
+ * kstat time
+ *
+ * All times associated with kstats (e.g. creation time, snapshot time,
+ * kstat_timer_t and kstat_io_t timestamps, etc.) are 64-bit nanosecond values,
+ * as returned by gethrtime().  The accuracy of these timestamps is machine
+ * dependent, but the precision (units) is the same across all platforms.
+ */
+
+/*
+ * kstat identity (KID)
+ *
+ * Each kstat is assigned a unique KID (kstat ID) when it is added to the
+ * global kstat chain.  The KID is used as a cookie by /dev/kstat to
+ * request information about the corresponding kstat.  There is also
+ * an identity associated with the entire kstat chain, kstat_chain_id,
+ * which is bumped each time a kstat is added or deleted.  /dev/kstat uses
+ * the chain ID to detect changes in the kstat chain (e.g., a new disk
+ * coming online) between ioctl()s.
+ */
+
+/*
+ * kstat module, kstat instance
+ *
+ * ks_module and ks_instance contain the name and instance of the module
+ * that created the kstat.  In cases where there can only be one instance,
+ * ks_instance is 0.  The kernel proper (/kernel/unix) uses "unix" as its
+ * module name.
+ */
+
+/*
+ * kstat name
+ *
+ * ks_name gives a meaningful name to a kstat.  The full kstat namespace
+ * is module.instance.name, so the name only need be unique within a
+ * module.  kstat_create() will fail if you try to create a kstat with
+ * an already-used (ks_module, ks_instance, ks_name) triplet.  Spaces are
+ * allowed in kstat names, but strongly discouraged, since they hinder
+ * awk-style processing at user level.
+ */
+
+/*
+ * kstat type
+ *
+ * The kstat mechanism provides several flavors of kstat data, defined
+ * below.  The "raw" kstat type is just treated as an array of bytes; you
+ * can use this to export any kind of data you want.
+ *
+ * Some kstat types allow multiple data structures per kstat, e.g.
+ * KSTAT_TYPE_NAMED; others do not.  This is part of the spec for each
+ * kstat data type.
+ *
+ * User-level tools should *not* rely on the #define KSTAT_NUM_TYPES.  To
+ * get this information, read out the standard system kstat "kstat_types".
+ */
+
+#define        KSTAT_TYPE_RAW          0       /* can be anything */
+                                       /* ks_ndata >= 1 */
+#define        KSTAT_TYPE_NAMED        1       /* name/value pair */
+                                       /* ks_ndata >= 1 */
+#define        KSTAT_TYPE_INTR         2       /* interrupt statistics */
+                                       /* ks_ndata == 1 */
+#define        KSTAT_TYPE_IO           3       /* I/O statistics */
+                                       /* ks_ndata == 1 */
+#define        KSTAT_TYPE_TIMER        4       /* event timer */
+                                       /* ks_ndata >= 1 */
+
+#define        KSTAT_NUM_TYPES         5
+
+/*
+ * kstat class
+ *
+ * Each kstat can be characterized as belonging to some broad class
+ * of statistics, e.g. disk, tape, net, vm, streams, etc.  This field
+ * can be used as a filter to extract related kstats.  The following
+ * values are currently in use: disk, tape, net, controller, vm, kvm,
+ * hat, streams, kstat, and misc.  (The kstat class encompasses things
+ * like kstat_types.)
+ */
+
+/*
+ * kstat flags
+ *
+ * Any of the following flags may be passed to kstat_create().  They are
+ * all zero by default.
+ *
+ *     KSTAT_FLAG_VIRTUAL:
+ *
+ *             Tells kstat_create() not to allocate memory for the
+ *             kstat data section; instead, you will set the ks_data
+ *             field to point to the data you wish to export.  This
+ *             provides a convenient way to export existing data
+ *             structures.
+ *
+ *     KSTAT_FLAG_VAR_SIZE:
+ *
+ *             The size of the kstat you are creating will vary over time.
+ *             For example, you may want to use the kstat mechanism to
+ *             export a linked list.  NOTE: The kstat framework does not
+ *             manage the data section, so all variable-size kstats must be
+ *             virtual kstats.  Moreover, variable-size kstats MUST employ
+ *             kstat data locking to prevent data-size races with kstat
+ *             clients.  See the section on "kstat snapshot" for details.
+ *
+ *     KSTAT_FLAG_WRITABLE:
+ *
+ *             Makes the kstat's data section writable by root.
+ *             The ks_snapshot routine (see below) does not need to check for
+ *             this; permission checking is handled in the kstat driver.
+ *
+ *     KSTAT_FLAG_PERSISTENT:
+ *
+ *             Indicates that this kstat is to be persistent over time.
+ *             For persistent kstats, kstat_delete() simply marks the
+ *             kstat as dormant; a subsequent kstat_create() reactivates
+ *             the kstat.  This feature is provided so that statistics
+ *             are not lost across driver close/open (e.g., raw disk I/O
+ *             on a disk with no mounted partitions.)
+ *             NOTE: Persistent kstats cannot be virtual, since ks_data
+ *             points to garbage as soon as the driver goes away.
+ *
+ * The following flags are maintained by the kstat framework:
+ *
+ *     KSTAT_FLAG_DORMANT:
+ *
+ *             For persistent kstats, indicates that the kstat is in the
+ *             dormant state (e.g., the corresponding device is closed).
+ *
+ *     KSTAT_FLAG_INVALID:
+ *
+ *             This flag is set when a kstat is in a transitional state,
+ *             e.g. between kstat_create() and kstat_install().
+ *             kstat clients must not attempt to access the kstat's data
+ *             if this flag is set.
+ */
+
+#define        KSTAT_FLAG_VIRTUAL              0x01
+#define        KSTAT_FLAG_VAR_SIZE             0x02
+#define        KSTAT_FLAG_WRITABLE             0x04
+#define        KSTAT_FLAG_PERSISTENT           0x08
+#define        KSTAT_FLAG_DORMANT              0x10
+#define        KSTAT_FLAG_INVALID              0x20
+
+/*
+ * Dynamic update support
+ *
+ * The kstat mechanism allows for an optional ks_update function to update
+ * kstat data.  This is useful for drivers where the underlying device
+ * keeps cheap hardware stats, but extraction is expensive.  Instead of
+ * constantly keeping the kstat data section up to date, you can supply a
+ * ks_update function which updates the kstat's data section on demand.
+ * To take advantage of this feature, simply set the ks_update field before
+ * calling kstat_install().
+ *
+ * The ks_update function, if supplied, must have the following structure:
+ *
+ *     int
+ *     foo_kstat_update(kstat_t *ksp, int rw)
+ *     {
+ *             if (rw == KSTAT_WRITE) {
+ *                     ... update the native stats from ksp->ks_data;
+ *                             return EACCES if you don't support this
+ *             } else {
+ *                     ... update ksp->ks_data from the native stats
+ *             }
+ *     }
+ *
+ * The ks_update return codes are: 0 for success, EACCES if you don't allow
+ * KSTAT_WRITE, and EIO for any other type of error.
+ *
+ * In general, the ks_update function may need to refer to provider-private
+ * data; for example, it may need a pointer to the provider's raw statistics.
+ * The ks_private field is available for this purpose.  Its use is entirely
+ * at the provider's discretion.
+ *
+ * All variable-size kstats MUST supply a ks_update routine, which computes
+ * and sets ks_data_size (and ks_ndata if that is meaningful), since these
+ * are needed to perform kstat snapshots (see below).
+ *
+ * No kstat locking should be done inside the ks_update routine.  The caller
+ * will already be holding the kstat's ks_lock (to ensure consistent data).
+ */
+
+#define        KSTAT_READ      0
+#define        KSTAT_WRITE     1
+
+/*
+ * Kstat snapshot
+ *
+ * In order to get a consistent view of a kstat's data, clients must obey
+ * the kstat's locking strategy.  However, these clients may need to perform
+ * operations on the data which could cause a fault (e.g. copyout()), or
+ * operations which are simply expensive.  Doing so could cause deadlock
+ * (e.g. if you're holding a disk's kstat lock which is ultimately required
+ * to resolve a copyout() fault), performance degradation (since the providers'
+ * activity is serialized at the kstat lock), device timing problems, etc.
+ *
+ * To avoid these problems, kstat data is provided via snapshots.  Taking
+ * a snapshot is a simple process: allocate a wired-down kernel buffer,
+ * acquire the kstat's data lock, copy the data into the buffer ("take the
+ * snapshot"), and release the lock.  This ensures that the kstat's data lock
+ * will be held as briefly as possible, and that no faults will occur while
+ * the lock is held.
+ *
+ * Normally, the snapshot is taken by default_kstat_snapshot(), which
+ * timestamps the data (sets ks_snaptime), copies it, and does a little
+ * massaging to deal with incomplete transactions on i/o kstats.  However,
+ * this routine only works for kstats with contiguous data (the typical case).
+ * If you create a kstat whose data is, say, a linked list, you must provide
+ * your own ks_snapshot routine.  The routine you supply must have the
+ * following prototype (replace "foo" with something appropriate):
+ *
+ *     int foo_kstat_snapshot(kstat_t *ksp, void *buf, int rw);
+ *
+ * The minimal snapshot routine -- one which copies contiguous data that
+ * doesn't need any massaging -- would be this:
+ *
+ *     ksp->ks_snaptime = gethrtime();
+ *     if (rw == KSTAT_WRITE)
+ *             bcopy(buf, ksp->ks_data, ksp->ks_data_size);
+ *     else
+ *             bcopy(ksp->ks_data, buf, ksp->ks_data_size);
+ *     return (0);
+ *
+ * A more illuminating example is taking a snapshot of a linked list:
+ *
+ *     ksp->ks_snaptime = gethrtime();
+ *     if (rw == KSTAT_WRITE)
+ *             return (EACCES);                ... See below ...
+ *     for (foo = first_foo; foo; foo = foo->next) {
+ *             bcopy((char *) foo, (char *) buf, sizeof (struct foo));
+ *             buf = ((struct foo *) buf) + 1;
+ *     }
+ *     return (0);
+ *
+ * In the example above, we have decided that we don't want to allow
+ * KSTAT_WRITE access, so we return EACCES if this is attempted.
+ *
+ * The key points are:
+ *
+ *     (1) ks_snaptime must be set (via gethrtime()) to timestamp the data.
+ *     (2) Data gets copied from the kstat to the buffer on KSTAT_READ,
+ *             and from the buffer to the kstat on KSTAT_WRITE.
+ *     (3) ks_snapshot return values are: 0 for success, EACCES if you
+ *             don't allow KSTAT_WRITE, and EIO for any other type of error.
+ *
+ * Named kstats (see section on "Named statistics" below) containing long
+ * strings (KSTAT_DATA_STRING) need special handling.  The kstat driver
+ * assumes that all strings are copied into the buffer after the array of
+ * named kstats, and the pointers (KSTAT_NAMED_STR_PTR()) are updated to point
+ * into the copy within the buffer. The default snapshot routine does this,
+ * but overriding routines should contain at least the following:
+ *
+ * if (rw == KSTAT_READ) {
+ *     kstat_named_t *knp = buf;
+ *     char *end = knp + ksp->ks_ndata;
+ *     uint_t i;
+ *
+ *     ... Do the regular copy ...
+ *     bcopy(ksp->ks_data, buf, sizeof (kstat_named_t) * ksp->ks_ndata);
+ *
+ *     for (i = 0; i < ksp->ks_ndata; i++, knp++) {
+ *             if (knp[i].data_type == KSTAT_DATA_STRING &&
+ *                 KSTAT_NAMED_STR_PTR(knp) != NULL) {
+ *                     bcopy(KSTAT_NAMED_STR_PTR(knp), end,
+ *                         KSTAT_NAMED_STR_BUFLEN(knp));
+ *                     KSTAT_NAMED_STR_PTR(knp) = end;
+ *                     end += KSTAT_NAMED_STR_BUFLEN(knp);
+ *             }
+ *     }
+ */
+
+/*
+ * Named statistics.
+ *
+ * List of arbitrary name=value statistics.
+ */
+
+typedef struct kstat_named {
+       char    name[KSTAT_STRLEN];     /* name of counter */
+       uchar_t data_type;              /* data type */
+       union {
+               char            c[16];  /* enough for 128-bit ints */
+               int32_t         i32;
+               uint32_t        ui32;
+               struct {
+                       union {
+                               char            *ptr;   /* NULL-term string */
+#if defined(_KERNEL) && defined(_MULTI_DATAMODEL)
+                               caddr32_t       ptr32;
+#endif
+                               char            __pad[8]; /* 64-bit padding */
+                       } addr;
+                       uint32_t        len;    /* # bytes for strlen + '\0' */
+               } str;
+/*
+ * The int64_t and uint64_t types are not valid for a maximally conformant
+ * 32-bit compilation environment (cc -Xc) using compilers prior to the
+ * introduction of C99 conforming compiler (reference ISO/IEC 9899:1990).
+ * In these cases, the visibility of i64 and ui64 is only permitted for
+ * 64-bit compilation environments or 32-bit non-maximally conformant
+ * C89 or C90 ANSI C compilation environments (cc -Xt and cc -Xa). In the
+ * C99 ANSI C compilation environment, the long long type is supported.
+ * The _INT64_TYPE is defined by the implementation (see sys/int_types.h).
+ */
+#if defined(_INT64_TYPE)
+               int64_t         i64;
+               uint64_t        ui64;
+#endif
+               long            l;
+               ulong_t         ul;
+
+               /* These structure members are obsolete */
+
+               longlong_t      ll;
+               u_longlong_t    ull;
+               float           f;
+               double          d;
+       } value;                        /* value of counter */
+} kstat_named_t;
+
+#define        KSTAT_DATA_CHAR         0
+#define        KSTAT_DATA_INT32        1
+#define        KSTAT_DATA_UINT32       2
+#define        KSTAT_DATA_INT64        3
+#define        KSTAT_DATA_UINT64       4
+
+#if !defined(_LP64)
+#define        KSTAT_DATA_LONG         KSTAT_DATA_INT32
+#define        KSTAT_DATA_ULONG        KSTAT_DATA_UINT32
+#else
+#if !defined(_KERNEL)
+#define        KSTAT_DATA_LONG         KSTAT_DATA_INT64
+#define        KSTAT_DATA_ULONG        KSTAT_DATA_UINT64
+#else
+#define        KSTAT_DATA_LONG         7       /* only visible to the kernel */
+#define        KSTAT_DATA_ULONG        8       /* only visible to the kernel */
+#endif /* !_KERNEL */
+#endif /* !_LP64 */
+
+/*
+ * Statistics exporting named kstats with long strings (KSTAT_DATA_STRING)
+ * may not make the assumption that ks_data_size is equal to (ks_ndata * sizeof
+ * (kstat_named_t)).  ks_data_size in these cases is equal to the sum of the
+ * amount of space required to store the strings (ie, the sum of
+ * KSTAT_NAMED_STR_BUFLEN() for all KSTAT_DATA_STRING statistics) plus the
+ * space required to store the kstat_named_t's.
+ *
+ * The default update routine will update ks_data_size automatically for
+ * variable-length kstats containing long strings (using the default update
+ * routine only makes sense if the string is the only thing that is changing
+ * in size, and ks_ndata is constant).  Fixed-length kstats containing long
+ * strings must explicitly change ks_data_size (after creation but before
+ * initialization) to reflect the correct amount of space required for the
+ * long strings and the kstat_named_t's.
+ */
+#define        KSTAT_DATA_STRING       9
+
+/* These types are obsolete */
+
+#define        KSTAT_DATA_LONGLONG     KSTAT_DATA_INT64
+#define        KSTAT_DATA_ULONGLONG    KSTAT_DATA_UINT64
+#define        KSTAT_DATA_FLOAT        5
+#define        KSTAT_DATA_DOUBLE       6
+
+#define        KSTAT_NAMED_PTR(kptr)   ((kstat_named_t *)(kptr)->ks_data)
+
+/*
+ * Retrieve the pointer of the string contained in the given named kstat.
+ */
+#define        KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.str.addr.ptr)
+
+/*
+ * Retrieve the length of the buffer required to store the string in the given
+ * named kstat.
+ */
+#define        KSTAT_NAMED_STR_BUFLEN(knptr) ((knptr)->value.str.len)
+
+/*
+ * Interrupt statistics.
+ *
+ * An interrupt is a hard interrupt (sourced from the hardware device
+ * itself), a soft interrupt (induced by the system via the use of
+ * some system interrupt source), a watchdog interrupt (induced by
+ * a periodic timer call), spurious (an interrupt entry point was
+ * entered but there was no interrupt condition to service),
+ * or multiple service (an interrupt condition was detected and
+ * serviced just prior to returning from any of the other types).
+ *
+ * Measurement of the spurious class of interrupts is useful for
+ * autovectored devices in order to pinpoint any interrupt latency
+ * problems in a particular system configuration.
+ *
+ * Devices that have more than one interrupt of the same
+ * type should use multiple structures.
+ */
+
+#define        KSTAT_INTR_HARD                 0
+#define        KSTAT_INTR_SOFT                 1
+#define        KSTAT_INTR_WATCHDOG             2
+#define        KSTAT_INTR_SPURIOUS             3
+#define        KSTAT_INTR_MULTSVC              4
+
+#define        KSTAT_NUM_INTRS                 5
+
+typedef struct kstat_intr {
+       uint_t  intrs[KSTAT_NUM_INTRS]; /* interrupt counters */
+} kstat_intr_t;
+
+#define        KSTAT_INTR_PTR(kptr)    ((kstat_intr_t *)(kptr)->ks_data)
+
+/*
+ * I/O statistics.
+ */
+
+typedef struct kstat_io {
+
+       /*
+        * Basic counters.
+        *
+        * The counters should be updated at the end of service
+        * (e.g., just prior to calling biodone()).
+        */
+
+       u_longlong_t    nread;          /* number of bytes read */
+       u_longlong_t    nwritten;       /* number of bytes written */
+       uint_t          reads;          /* number of read operations */
+       uint_t          writes;         /* number of write operations */
+
+       /*
+        * Accumulated time and queue length statistics.
+        *
+        * Accumulated time statistics are kept as a running sum
+        * of "active" time.  Queue length statistics are kept as a
+        * running sum of the product of queue length and elapsed time
+        * at that length -- i.e., a Riemann sum for queue length
+        * integrated against time.  (You can also think of the active time
+        * as a Riemann sum, for the boolean function (queue_length > 0)
+        * integrated against time, or you can think of it as the
+        * Lebesgue measure of the set on which queue_length > 0.)
+        *
+        *              ^
+        *              |                       _________
+        *              8                       | i4    |
+        *              |                       |       |
+        *      Queue   6                       |       |
+        *      Length  |       _________       |       |
+        *              4       | i2    |_______|       |
+        *              |       |           i3          |
+        *              2_______|                       |
+        *              |    i1                         |
+        *              |_______________________________|
+        *              Time->  t1      t2      t3      t4
+        *
+        * At each change of state (entry or exit from the queue),
+        * we add the elapsed time (since the previous state change)
+        * to the active time if the queue length was non-zero during
+        * that interval; and we add the product of the elapsed time
+        * times the queue length to the running length*time sum.
+        *
+        * This method is generalizable to measuring residency
+        * in any defined system: instead of queue lengths, think
+        * of "outstanding RPC calls to server X".
+        *
+        * A large number of I/O subsystems have at least two basic
+        * "lists" of transactions they manage: one for transactions
+        * that have been accepted for processing but for which processing
+        * has yet to begin, and one for transactions which are actively
+        * being processed (but not done). For this reason, two cumulative
+        * time statistics are defined here: wait (pre-service) time,
+        * and run (service) time.
+        *
+        * All times are 64-bit nanoseconds (hrtime_t), as returned by
+        * gethrtime().
+        *
+        * The units of cumulative busy time are accumulated nanoseconds.
+        * The units of cumulative length*time products are elapsed time
+        * times queue length.
+        *
+        * Updates to the fields below are performed implicitly by calls to
+        * these five functions:
+        *
+        *      kstat_waitq_enter()
+        *      kstat_waitq_exit()
+        *      kstat_runq_enter()
+        *      kstat_runq_exit()
+        *
+        *      kstat_waitq_to_runq()           (see below)
+        *      kstat_runq_back_to_waitq()      (see below)
+        *
+        * Since kstat_waitq_exit() is typically followed immediately
+        * by kstat_runq_enter(), there is a single kstat_waitq_to_runq()
+        * function which performs both operations.  This is a performance
+        * win since only one timestamp is required.
+        *
+        * In some instances, it may be necessary to move a request from
+        * the run queue back to the wait queue, e.g. for write throttling.
+        * For these situations, call kstat_runq_back_to_waitq().
+        *
+        * These fields should never be updated by any other means.
+        */
+
+       hrtime_t wtime;         /* cumulative wait (pre-service) time */
+       hrtime_t wlentime;      /* cumulative wait length*time product */
+       hrtime_t wlastupdate;   /* last time wait queue changed */
+       hrtime_t rtime;         /* cumulative run (service) time */
+       hrtime_t rlentime;      /* cumulative run length*time product */
+       hrtime_t rlastupdate;   /* last time run queue changed */
+
+       uint_t  wcnt;           /* count of elements in wait state */
+       uint_t  rcnt;           /* count of elements in run state */
+
+} kstat_io_t;
+
+#define        KSTAT_IO_PTR(kptr)      ((kstat_io_t *)(kptr)->ks_data)
+
+/*
+ * Event timer statistics - cumulative elapsed time and number of events.
+ *
+ * Updates to these fields are performed implicitly by calls to
+ * kstat_timer_start() and kstat_timer_stop().
+ */
+
+typedef struct kstat_timer {
+       char            name[KSTAT_STRLEN];     /* event name */
+       uchar_t         resv;                   /* reserved */
+       u_longlong_t    num_events;             /* number of events */
+       hrtime_t        elapsed_time;           /* cumulative elapsed time */
+       hrtime_t        min_time;               /* shortest event duration */
+       hrtime_t        max_time;               /* longest event duration */
+       hrtime_t        start_time;             /* previous event start time */
+       hrtime_t        stop_time;              /* previous event stop time */
+} kstat_timer_t;
+
+#define        KSTAT_TIMER_PTR(kptr)   ((kstat_timer_t *)(kptr)->ks_data)
+
+#if    defined(_KERNEL)
+
+#include <sys/t_lock.h>
+
+extern kid_t   kstat_chain_id;         /* bumped at each state change */
+extern void    kstat_init(void);       /* initialize kstat framework */
+
+/*
+ * Adding and deleting kstats.
+ *
+ * The typical sequence to add a kstat is:
+ *
+ *     ksp = kstat_create(module, instance, name, class, type, ndata, flags);
+ *     if (ksp) {
+ *             ... provider initialization, if necessary
+ *             kstat_install(ksp);
+ *     }
+ *
+ * There are three logically distinct steps here:
+ *
+ * Step 1: System Initialization (kstat_create)
+ *
+ * kstat_create() performs system initialization.  kstat_create()
+ * allocates memory for the entire kstat (header plus data), initializes
+ * all header fields, initializes the data section to all zeroes, assigns
+ * a unique KID, and puts the kstat onto the system's kstat chain.
+ * The returned kstat is marked invalid (KSTAT_FLAG_INVALID is set),
+ * because the provider (caller) has not yet had a chance to initialize
+ * the data section.
+ *
+ * By default, kstats are exported to all zones on the system.  A kstat may be
+ * created via kstat_create_zone() to specify a zone to which the statistics
+ * should be exported.  kstat_zone_add() may be used to specify additional
+ * zones to which the statistics are to be exported.
+ *
+ * Step 2: Provider Initialization
+ *
+ * The provider performs any necessary initialization of the data section,
+ * e.g. setting the name fields in a KSTAT_TYPE_NAMED.  Virtual kstats set
+ * the ks_data field at this time.  The provider may also set the ks_update,
+ * ks_snapshot, ks_private, and ks_lock fields if necessary.
+ *
+ * Step 3: Installation (kstat_install)
+ *
+ * Once the kstat is completely initialized, kstat_install() clears the
+ * INVALID flag, thus making the kstat accessible to the outside world.
+ * kstat_install() also clears the DORMANT flag for persistent kstats.
+ *
+ * Removing a kstat from the system
+ *
+ * kstat_delete(ksp) removes ksp from the kstat chain and frees all
+ * associated system resources.  NOTE: When you call kstat_delete(),
+ * you must NOT be holding that kstat's ks_lock.  Otherwise, you may
+ * deadlock with a kstat reader.
+ *
+ * Persistent kstats
+ *
+ * From the provider's point of view, persistence is transparent.  The only
+ * difference between ephemeral (normal) kstats and persistent kstats
+ * is that you pass KSTAT_FLAG_PERSISTENT to kstat_create().  Magically,
+ * this has the effect of making your data visible even when you're
+ * not home.  Persistence is important to tools like iostat, which want
+ * to get a meaningful picture of disk activity.  Without persistence,
+ * raw disk i/o statistics could never accumulate: they would come and
+ * go with each open/close of the raw device.
+ *
+ * The magic of persistence works by slightly altering the behavior of
+ * kstat_create() and kstat_delete().  The first call to kstat_create()
+ * creates a new kstat, as usual.  However, kstat_delete() does not
+ * actually delete the kstat: it performs one final update of the data
+ * (i.e., calls the ks_update routine), marks the kstat as dormant, and
+ * sets the ks_lock, ks_update, ks_private, and ks_snapshot fields back
+ * to their default values (since they might otherwise point to garbage,
+ * e.g. if the provider is going away).  kstat clients can still access
+ * the dormant kstat just like a live kstat; they just continue to see
+ * the final data values as long as the kstat remains dormant.
+ * All subsequent kstat_create() calls simply find the already-existing,
+ * dormant kstat and return a pointer to it, without altering any fields.
+ * The provider then performs its usual initialization sequence, and
+ * calls kstat_install().  kstat_install() uses the old data values to
+ * initialize the native data (i.e., ks_update is called with KSTAT_WRITE),
+ * thus making it seem like you were never gone.
+ */
+
+extern kstat_t *kstat_create(const char *, int, const char *, const char *,
+    uchar_t, uint_t, uchar_t);
+extern kstat_t *kstat_create_zone(const char *, int, const char *,
+    const char *, uchar_t, uint_t, uchar_t, zoneid_t);
+extern void kstat_install(kstat_t *);
+extern void kstat_delete(kstat_t *);
+extern void kstat_named_setstr(kstat_named_t *knp, const char *src);
+extern void kstat_set_string(char *, const char *);
+extern void kstat_delete_byname(const char *, int, const char *);
+extern void kstat_delete_byname_zone(const char *, int, const char *, zoneid_t);
+extern void kstat_named_init(kstat_named_t *, const char *, uchar_t);
+extern void kstat_timer_init(kstat_timer_t *, const char *);
+extern void kstat_waitq_enter(kstat_io_t *);
+extern void kstat_waitq_exit(kstat_io_t *);
+extern void kstat_runq_enter(kstat_io_t *);
+extern void kstat_runq_exit(kstat_io_t *);
+extern void kstat_waitq_to_runq(kstat_io_t *);
+extern void kstat_runq_back_to_waitq(kstat_io_t *);
+extern void kstat_timer_start(kstat_timer_t *);
+extern void kstat_timer_stop(kstat_timer_t *);
+
+extern void kstat_zone_add(kstat_t *, zoneid_t);
+extern void kstat_zone_remove(kstat_t *, zoneid_t);
+extern int kstat_zone_find(kstat_t *, zoneid_t);
+
+extern kstat_t *kstat_hold_bykid(kid_t kid, zoneid_t);
+extern kstat_t *kstat_hold_byname(const char *, int, const char *, zoneid_t);
+extern void kstat_rele(kstat_t *);
+
+#endif /* defined(_KERNEL) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_KSTAT_H */
diff --git a/zfs/lib/libspl/include/sys/list.h b/zfs/lib/libspl/include/sys/list.h
new file mode 100644 (file)
index 0000000..6db92ed
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SYS_LIST_H
+#define        _SYS_LIST_H
+
+#include <sys/list_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct list_node list_node_t;
+typedef struct list list_t;
+
+void list_create(list_t *, size_t, size_t);
+void list_destroy(list_t *);
+
+void list_insert_after(list_t *, void *, void *);
+void list_insert_before(list_t *, void *, void *);
+void list_insert_head(list_t *, void *);
+void list_insert_tail(list_t *, void *);
+void list_remove(list_t *, void *);
+void *list_remove_head(list_t *);
+void *list_remove_tail(list_t *);
+void list_move_tail(list_t *, list_t *);
+
+void *list_head(list_t *);
+void *list_tail(list_t *);
+void *list_next(list_t *, void *);
+void *list_prev(list_t *, void *);
+int list_is_empty(list_t *);
+
+void list_link_init(list_node_t *);
+void list_link_replace(list_node_t *, list_node_t *);
+
+int list_link_active(list_node_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LIST_H */
diff --git a/zfs/lib/libspl/include/sys/list_impl.h b/zfs/lib/libspl/include/sys/list_impl.h
new file mode 100644 (file)
index 0000000..a6614f9
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SYS_LIST_IMPL_H
+#define        _SYS_LIST_IMPL_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct list_node {
+       struct list_node *list_next;
+       struct list_node *list_prev;
+};
+
+struct list {
+       size_t  list_size;
+       size_t  list_offset;
+       struct list_node list_head;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_LIST_IMPL_H */
diff --git a/zfs/lib/libspl/include/sys/mhd.h b/zfs/lib/libspl/include/sys/mhd.h
new file mode 100644 (file)
index 0000000..fcc062d
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_MHD_H
+#define        _SYS_MHD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Definitions for multi-host device I/O control commands
+ */
+#define        MHIOC                           ('M'<<8)
+#define        MHIOCENFAILFAST                 (MHIOC|1)
+#define        MHIOCTKOWN                      (MHIOC|2)
+#define        MHIOCRELEASE                    (MHIOC|3)
+#define        MHIOCSTATUS                     (MHIOC|4)
+#define        MHIOCGRP_INKEYS                 (MHIOC|5)
+#define        MHIOCGRP_INRESV                 (MHIOC|6)
+#define        MHIOCGRP_REGISTER               (MHIOC|7)
+#define        MHIOCGRP_RESERVE                (MHIOC|8)
+#define        MHIOCGRP_PREEMPTANDABORT        (MHIOC|9)
+#define        MHIOCGRP_PREEMPT                (MHIOC|10)
+#define        MHIOCGRP_CLEAR                  (MHIOC|11)
+#define        MHIOCGRP_REGISTERANDIGNOREKEY   (MHIOC|14)
+#define        MHIOCQRESERVE                   (MHIOC|12)
+#define        MHIOCREREGISTERDEVID            (MHIOC|13)
+
+/*
+ * Following is the structure to specify the delay parameters in
+ * milliseconds, via the MHIOCTKOWN ioctl.
+ */
+struct mhioctkown {
+       int reinstate_resv_delay;
+       int min_ownership_delay;
+       int max_ownership_delay;
+};
+
+#define        MHIOC_RESV_KEY_SIZE     8
+typedef struct mhioc_resv_key {
+       uchar_t key[MHIOC_RESV_KEY_SIZE];
+} mhioc_resv_key_t;
+
+typedef struct mhioc_key_list {
+       uint32_t                listsize;
+       uint32_t                listlen;
+       mhioc_resv_key_t        *list;
+} mhioc_key_list_t;
+
+typedef struct mhioc_inkeys {
+       uint32_t                generation;
+       mhioc_key_list_t        *li;
+} mhioc_inkeys_t;
+
+#if defined(_SYSCALL32)
+struct mhioc_key_list32 {
+       uint32_t                listsize;
+       uint32_t                listlen;
+       caddr32_t               list;
+} mhioc_key_list32_t;
+
+struct mhioc_inkeys32 {
+       uint32_t                generation;
+       caddr32_t               li;
+} mhioc_inkeys32_t;
+#endif
+
+typedef struct mhioc_resv_desc {
+       mhioc_resv_key_t        key;
+       uint8_t                 type;
+       uint8_t                 scope;
+       uint32_t                scope_specific_addr;
+} mhioc_resv_desc_t;
+
+typedef struct mhioc_resv_desc_list {
+       uint32_t                listsize;
+       uint32_t                listlen;
+       mhioc_resv_desc_t       *list;
+} mhioc_resv_desc_list_t;
+
+typedef struct mhioc_inresvs {
+       uint32_t                generation;
+       mhioc_resv_desc_list_t  *li;
+} mhioc_inresvs_t;
+
+#if defined(_SYSCALL32)
+struct mhioc_resv_desc_list32 {
+       uint32_t                listsize;
+       uint32_t                listlen;
+       caddr32_t               list;
+} mhioc_resv_desc_list32_t;
+
+typedef struct mhioc_inresvs32 {
+       uint32_t                generation;
+       caddr32_t               li;
+} mhioc_inresvs32_t;
+#endif
+
+typedef struct mhioc_register {
+    mhioc_resv_key_t   oldkey;
+    mhioc_resv_key_t   newkey;
+    boolean_t          aptpl;  /* True if persistent across power failures */
+} mhioc_register_t;
+
+typedef struct mhioc_preemptandabort {
+    mhioc_resv_desc_t  resvdesc;
+    mhioc_resv_key_t   victim_key;
+} mhioc_preemptandabort_t;
+
+typedef struct mhioc_registerandignorekey {
+    mhioc_resv_key_t   newkey;
+    boolean_t          aptpl;  /* True if persistent across power failures */
+} mhioc_registerandignorekey_t;
+
+/*
+ * SCSI-3 PGR Reservation Type Codes.  Codes with the _OBSOLETE suffix
+ * have been removed from the SCSI3 PGR standard.
+ */
+#define        SCSI3_RESV_READSHARED_OBSOLETE                  0
+#define        SCSI3_RESV_WRITEEXCLUSIVE                       1
+#define        SCSI3_RESV_READEXCLUSIVE_OBSOLETE               2
+#define        SCSI3_RESV_EXCLUSIVEACCESS                      3
+#define        SCSI3_RESV_SHAREDACCESS_OBSOLETE                4
+#define        SCSI3_RESV_WRITEEXCLUSIVEREGISTRANTSONLY        5
+#define        SCSI3_RESV_EXCLUSIVEACCESSREGISTRANTSONLY       6
+
+#define        SCSI3_SCOPE_LOGICALUNIT                         0
+#define        SCSI3_SCOPE_EXTENT_OBSOLETE                     1
+#define        SCSI3_SCOPE_ELEMENT                             2
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MHD_H */
diff --git a/zfs/lib/libspl/include/sys/mkdev.h b/zfs/lib/libspl/include/sys/mkdev.h
new file mode 100644 (file)
index 0000000..5978de6
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_MKDEV_H
+#define        _LIBSPL_SYS_MKDEV_H
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/mnttab.h b/zfs/lib/libspl/include/sys/mnttab.h
new file mode 100644 (file)
index 0000000..026a8fa
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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 (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/*  All Rights Reserved  */
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright 2006 Ricardo Correia */
+
+#ifndef _SYS_MNTTAB_H
+#define        _SYS_MNTTAB_H
+
+#include <stdio.h>
+#include <mntent.h>
+#include <sys/types.h>
+
+#ifdef MNTTAB
+#undef MNTTAB
+#endif /* MNTTAB */
+
+#define        MNTTAB          "/proc/self/mounts"
+#define        MNT_LINE_MAX    4096
+
+#define        MNT_TOOLONG     1       /* entry exceeds MNT_LINE_MAX */
+#define        MNT_TOOMANY     2       /* too many fields in line */
+#define        MNT_TOOFEW      3       /* too few fields in line */
+
+struct mnttab {
+       char *mnt_special;
+       char *mnt_mountp;
+       char *mnt_fstype;
+       char *mnt_mntopts;
+};
+
+/*
+ * NOTE: fields in extmnttab should match struct mnttab till new fields
+ * are encountered, this allows hasmntopt to work properly when its arg is
+ * a pointer to an extmnttab struct cast to a mnttab struct pointer.
+ */
+
+struct extmnttab {
+       char *mnt_special;
+       char *mnt_mountp;
+       char *mnt_fstype;
+       char *mnt_mntopts;
+       uint_t mnt_major;
+       uint_t mnt_minor;
+};
+
+extern int getmntany(FILE *fp, struct mnttab *mp, struct mnttab *mpref);
+extern int _sol_getmntent(FILE *fp, struct mnttab *mp);
+extern int getextmntent(FILE *fp, struct extmnttab *mp, int len);
+
+static inline char *_sol_hasmntopt(struct mnttab *mnt, char *opt)
+{
+       struct mntent mnt_new;
+
+       mnt_new.mnt_opts = mnt->mnt_mntopts;
+
+       return (hasmntopt(&mnt_new, opt));
+}
+
+#define        hasmntopt       _sol_hasmntopt
+#define        getmntent       _sol_getmntent
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/mount.h b/zfs/lib/libspl/include/sys/mount.h
new file mode 100644 (file)
index 0000000..ad1fa38
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include_next <sys/mount.h>
+
+#ifndef _LIBSPL_SYS_MOUNT_H
+#define        _LIBSPL_SYS_MOUNT_H
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * Some old glibc headers don't define BLKGETSIZE64
+ * and we don't want to require the kernel headers
+ */
+#if !defined(BLKGETSIZE64)
+#define        BLKGETSIZE64            _IOR(0x12, 114, size_t)
+#endif
+
+/*
+ * Some old glibc headers don't correctly define MS_DIRSYNC and
+ * instead use the enum name S_WRITE.  When using these older
+ * headers define MS_DIRSYNC to be S_WRITE.
+ */
+#if !defined(MS_DIRSYNC)
+#define        MS_DIRSYNC              S_WRITE
+#endif
+
+/*
+ * Some old glibc headers don't correctly define MS_POSIXACL and
+ * instead leave it undefined.  When using these older headers define
+ * MS_POSIXACL to the reserved value of (1<<16).
+ */
+#if !defined(MS_POSIXACL)
+#define        MS_POSIXACL             (1<<16)
+#endif
+
+#define        MS_USERS        (MS_NOEXEC|MS_NOSUID|MS_NODEV)
+#define        MS_OWNER        (MS_NOSUID|MS_NODEV)
+#define        MS_GROUP        (MS_NOSUID|MS_NODEV)
+#define        MS_COMMENT      0
+
+/*
+ * Older glibc <sys/mount.h> headers did not define all the available
+ * umount2(2) flags.  Both MNT_FORCE and MNT_DETACH are supported in the
+ * kernel back to 2.4.11 so we define them correctly if they are missing.
+ */
+#ifdef MNT_FORCE
+#define        MS_FORCE        MNT_FORCE
+#else
+#define        MS_FORCE        0x00000001
+#endif /* MNT_FORCE */
+
+#ifdef MNT_DETACH
+#define        MS_DETACH       MNT_DETACH
+#else
+#define        MS_DETACH       0x00000002
+#endif /* MNT_DETACH */
+
+/*
+ * Overlay mount is default in Linux, but for solaris/zfs
+ * compatibility, MS_OVERLAY is defined to explicitly have the user
+ * provide a flag (-O) to mount over a non empty directory.
+ */
+#define        MS_OVERLAY      0x00000004
+
+#endif /* _LIBSPL_SYS_MOUNT_H */
diff --git a/zfs/lib/libspl/include/sys/note.h b/zfs/lib/libspl/include/sys/note.h
new file mode 100644 (file)
index 0000000..6625b68
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 (c) 1994 by Sun Microsystems, Inc.
+ */
+
+/*
+ * sys/note.h: interface for annotating source with info for tools
+ *
+ * This is the underlying interface; NOTE (/usr/include/note.h) is the
+ * preferred interface, but all exported header files should include this
+ * file directly and use _NOTE so as not to take "NOTE" from the user's
+ * namespace.  For consistency, *all* kernel source should use _NOTE.
+ *
+ * By default, annotations expand to nothing.  This file implements
+ * that.  Tools using annotations will interpose a different version
+ * of this file that will expand annotations as needed.
+ */
+
+#ifndef        _SYS_NOTE_H
+#define        _SYS_NOTE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _NOTE
+#define        _NOTE(s)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_NOTE_H */
diff --git a/zfs/lib/libspl/include/sys/param.h b/zfs/lib/libspl/include/sys/param.h
new file mode 100644 (file)
index 0000000..9f362dd
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_PARAM_H
+#define        _LIBSPL_SYS_PARAM_H
+
+#include_next <sys/param.h>
+#include <unistd.h>
+
+/*
+ * File system parameters and macros.
+ *
+ * The file system is made out of blocks of at most MAXBSIZE units,
+ * with smaller units (fragments) only in the last direct block.
+ * MAXBSIZE primarily determines the size of buffers in the buffer
+ * pool. It may be made larger without any effect on existing
+ * file systems; however making it smaller make make some file
+ * systems unmountable.
+ *
+ * Note that the blocked devices are assumed to have DEV_BSIZE
+ * "sectors" and that fragments must be some multiple of this size.
+ */
+#define        MAXBSIZE        8192
+#define        DEV_BSIZE       512
+#define        DEV_BSHIFT      9               /* log2(DEV_BSIZE) */
+
+#define        MAXNAMELEN      256
+#define        MAXOFFSET_T     LLONG_MAX
+
+#define        UID_NOBODY      60001           /* user ID no body */
+#define        GID_NOBODY      UID_NOBODY
+#define        UID_NOACCESS    60002           /* user ID no access */
+
+#define        MAXUID          UINT32_MAX      /* max user id */
+#define        MAXPROJID       MAXUID          /* max project id */
+
+#ifndef        PAGESIZE
+#define        PAGESIZE        (sysconf(_SC_PAGESIZE))
+#endif /* PAGESIZE */
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/policy.h b/zfs/lib/libspl/include/sys/policy.h
new file mode 100644 (file)
index 0000000..2f695b3
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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
+ */
+
+#ifndef        _LIBSYS_SYS_POLICY_H
+#define        _LIBSYS_SYS_POLICY_H
+
+#endif /* _LIBSYS_SYS_POLICY_H */
diff --git a/zfs/lib/libspl/include/sys/priv.h b/zfs/lib/libspl/include/sys/priv.h
new file mode 100644 (file)
index 0000000..76c76d1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_PRIV_H
+#define        _LIBSPL_SYS_PRIV_H
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/processor.h b/zfs/lib/libspl/include/sys/processor.h
new file mode 100644 (file)
index 0000000..78e95d0
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_PROCESSOR_H
+#define        _LIBSPL_SYS_PROCESSOR_H
+
+#define        getcpuid() (-1)
+
+typedef int    processorid_t;
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/stack.h b/zfs/lib/libspl/include/sys/stack.h
new file mode 100644 (file)
index 0000000..59807e9
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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
+ */
+/*
+ * This header file distributed under the terms of the CDDL.
+ * Portions Copyright 2008 Sun Microsystems, Inc. All Rights reserved.
+ */
+#ifndef _SYS_STACK_H
+#define        _SYS_STACK_H
+
+#include <pthread.h>
+
+#define        STACK_BIAS      0
+
+#ifdef __USE_GNU
+
+static inline int
+stack_getbounds(stack_t *sp)
+{
+       pthread_attr_t attr;
+       int rc;
+
+       rc = pthread_getattr_np(pthread_self(), &attr);
+       if (rc)
+               return (rc);
+
+       rc = pthread_attr_getstack(&attr, &sp->ss_sp, &sp->ss_size);
+       if (rc == 0)
+               sp->ss_flags = 0;
+
+       pthread_attr_destroy(&attr);
+
+       return (rc);
+}
+
+static inline int
+thr_stksegment(stack_t *sp)
+{
+       int rc;
+
+       rc = stack_getbounds(sp);
+       if (rc)
+               return (rc);
+
+       /*
+        * thr_stksegment() is expected to set sp.ss_sp to the high stack
+        * address, but the stack_getbounds() interface is expected to
+        * set sp.ss_sp to the low address.  Adjust accordingly.
+        */
+       sp->ss_sp = (void *)(((uintptr_t)sp->ss_sp) + sp->ss_size);
+       sp->ss_flags = 0;
+
+       return (rc);
+}
+
+#endif /* __USE_GNU */
+#endif /* _SYS_STACK_H */
diff --git a/zfs/lib/libspl/include/sys/stat.h b/zfs/lib/libspl/include/sys/stat.h
new file mode 100644 (file)
index 0000000..3e8d27e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef _LIBSPL_SYS_STAT_H
+#define        _LIBSPL_SYS_STAT_H
+
+#include_next <sys/stat.h>
+
+#include <sys/mount.h> /* for BLKGETSIZE64 */
+
+/*
+ * Emulate Solaris' behavior of returning the block device size in fstat64().
+ */
+static inline int
+fstat64_blk(int fd, struct stat64 *st)
+{
+       if (fstat64(fd, st) == -1)
+               return (-1);
+
+       /* In Linux we need to use an ioctl to get the size of a block device */
+       if (S_ISBLK(st->st_mode)) {
+               if (ioctl(fd, BLKGETSIZE64, &st->st_size) != 0)
+                       return (-1);
+       }
+
+       return (0);
+}
+#endif /* _LIBSPL_SYS_STAT_H */
diff --git a/zfs/lib/libspl/include/sys/stropts.h b/zfs/lib/libspl/include/sys/stropts.h
new file mode 100644 (file)
index 0000000..08c2e79
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_STROPTS_H
+#define        _LIBSPL_SYS_STROPTS_H
+
+#endif /* _LIBSPL_SYS_STROPTS_H */
diff --git a/zfs/lib/libspl/include/sys/sunddi.h b/zfs/lib/libspl/include/sys/sunddi.h
new file mode 100644 (file)
index 0000000..ccd2b29
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 (c) 2008 by Sun Microsystems, Inc.
+ */
+
+#ifndef        _SYS_SUNDDI_H
+#define        _SYS_SUNDDI_H
+
+#endif /* _SYS_SUNDDI_H */
diff --git a/zfs/lib/libspl/include/sys/sysevent/Makefile.in b/zfs/lib/libspl/include/sys/sysevent/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/include/sys/sysmacros.h b/zfs/lib/libspl/include/sys/sysmacros.h
new file mode 100644 (file)
index 0000000..f99b4d6
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_SYSMACROS_H
+#define        _LIBSPL_SYS_SYSMACROS_H
+
+#include_next <sys/sysmacros.h>
+
+/* common macros */
+#ifndef MIN
+#define        MIN(a, b)       ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define        MAX(a, b)       ((a) < (b) ? (b) : (a))
+#endif
+#ifndef ABS
+#define        ABS(a)          ((a) < 0 ? -(a) : (a))
+#endif
+#ifndef ARRAY_SIZE
+#define        ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0]))
+#endif
+#ifndef        DIV_ROUND_UP
+#define        DIV_ROUND_UP(n, d)      (((n) + (d) - 1) / (d))
+#endif
+
+#define        makedevice(maj, min)    makedev(maj, min)
+#define        _sysconf(a)             sysconf(a)
+#define        __NORETURN              __attribute__((noreturn))
+
+/*
+ * Compatibility macros/typedefs needed for Solaris -> Linux port
+ */
+#define        P2ALIGN(x, align)       ((x) & -(align))
+#define        P2CROSS(x, y, align)    (((x) ^ (y)) > (align) - 1)
+#define        P2ROUNDUP(x, align)     ((((x) - 1) | ((align) - 1)) + 1)
+#define        P2BOUNDARY(off, len, align) \
+                               (((off) ^ ((off) + (len) - 1)) > (align) - 1)
+#define        P2PHASE(x, align)       ((x) & ((align) - 1))
+#define        P2NPHASE(x, align)      (-(x) & ((align) - 1))
+#define        P2NPHASE_TYPED(x, align, type) \
+                               (-(type)(x) & ((type)(align) - 1))
+#define        ISP2(x)                 (((x) & ((x) - 1)) == 0)
+#define        IS_P2ALIGNED(v, a)      ((((uintptr_t)(v)) & ((uintptr_t)(a) - 1)) == 0)
+
+/*
+ * Typed version of the P2* macros.  These macros should be used to ensure
+ * that the result is correctly calculated based on the data type of (x),
+ * which is passed in as the last argument, regardless of the data
+ * type of the alignment.  For example, if (x) is of type uint64_t,
+ * and we want to round it up to a page boundary using "PAGESIZE" as
+ * the alignment, we can do either
+ *      P2ROUNDUP(x, (uint64_t)PAGESIZE)
+ * or
+ *      P2ROUNDUP_TYPED(x, PAGESIZE, uint64_t)
+ */
+#define        P2ALIGN_TYPED(x, align, type)           \
+       ((type)(x) & -(type)(align))
+#define        P2PHASE_TYPED(x, align, type)           \
+       ((type)(x) & ((type)(align) - 1))
+#define        P2NPHASE_TYPED(x, align, type)          \
+       (-(type)(x) & ((type)(align) - 1))
+#define        P2ROUNDUP_TYPED(x, align, type)         \
+       ((((type)(x) - 1) | ((type)(align) - 1)) + 1)
+#define        P2END_TYPED(x, align, type)             \
+       (-(~(type)(x) & -(type)(align)))
+#define        P2PHASEUP_TYPED(x, align, phase, type)  \
+       ((type)(phase) - (((type)(phase) - (type)(x)) & -(type)(align)))
+#define        P2CROSS_TYPED(x, y, align, type)        \
+       (((type)(x) ^ (type)(y)) > (type)(align) - 1)
+#define        P2SAMEHIGHBIT_TYPED(x, y, type)         \
+       (((type)(x) ^ (type)(y)) < ((type)(x) & (type)(y)))
+
+
+/* avoid any possibility of clashing with <stddef.h> version */
+#if defined(_KERNEL) && !defined(_KMEMUSER) && !defined(offsetof)
+#define        offsetof(s, m)  ((size_t)(&(((s *)0)->m)))
+#endif
+
+#endif /* _LIBSPL_SYS_SYSMACROS_H */
diff --git a/zfs/lib/libspl/include/sys/systeminfo.h b/zfs/lib/libspl/include/sys/systeminfo.h
new file mode 100644 (file)
index 0000000..3f7cef5
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_SYSTEMINFO_H
+#define        _LIBSPL_SYS_SYSTEMINFO_H
+
+#define        HW_INVALID_HOSTID       0xFFFFFFFF      /* an invalid hostid */
+#define        HW_HOSTID_LEN           11              /* minimum buffer size needed */
+                                               /* to hold a decimal or hex */
+                                               /* hostid string */
+
+#define        sysinfo(cmd, buf, cnt)          (-1)
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/systm.h b/zfs/lib/libspl/include/sys/systm.h
new file mode 100644 (file)
index 0000000..1ed031d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_SYSTM_H
+#define        _LIBSPL_SYS_SYSTM_H
+
+#endif /* _LIBSPL_SYS_SYSTM_H */
diff --git a/zfs/lib/libspl/include/sys/time.h b/zfs/lib/libspl/include/sys/time.h
new file mode 100644 (file)
index 0000000..f05fcaa
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_TIME_H
+#define        _LIBSPL_SYS_TIME_H
+
+#include_next <sys/time.h>
+#include <sys/types.h>
+
+#ifndef SEC
+#define        SEC             1
+#endif
+
+#ifndef MILLISEC
+#define        MILLISEC        1000
+#endif
+
+#ifndef MICROSEC
+#define        MICROSEC        1000000
+#endif
+
+#ifndef NANOSEC
+#define        NANOSEC         1000000000
+#endif
+
+#ifndef NSEC_PER_USEC
+#define        NSEC_PER_USEC   1000L
+#endif
+
+#ifndef MSEC2NSEC
+#define        MSEC2NSEC(m)    ((hrtime_t)(m) * (NANOSEC / MILLISEC))
+#endif
+
+#ifndef NSEC2MSEC
+#define        NSEC2MSEC(n)    ((n) / (NANOSEC / MILLISEC))
+#endif
+
+#ifndef        NSEC2SEC
+#define        NSEC2SEC(n)     ((n) / (NANOSEC / SEC))
+#endif
+
+#ifndef SEC2NSEC
+#define        SEC2NSEC(m)     ((hrtime_t)(m) * (NANOSEC / SEC))
+#endif
+
+
+typedef        long long               hrtime_t;
+typedef        struct  timespec        timestruc_t;
+typedef        struct  timespec        timespec_t;
+
+
+extern hrtime_t gethrtime(void);
+extern void gethrestime(timestruc_t *);
+
+#endif /* _LIBSPL_SYS_TIME_H */
diff --git a/zfs/lib/libspl/include/sys/types.h b/zfs/lib/libspl/include/sys/types.h
new file mode 100644 (file)
index 0000000..c58b2d5
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_TYPES_H
+#define        _LIBSPL_SYS_TYPES_H
+
+#include <sys/isa_defs.h>
+#include <sys/feature_tests.h>
+#include_next <sys/types.h>
+#include <sys/types32.h>
+#include <sys/va_list.h>
+
+#ifndef HAVE_INTTYPES
+#include <inttypes.h>
+
+typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
+
+typedef unsigned char  uchar_t;
+typedef unsigned short ushort_t;
+typedef unsigned int   uint_t;
+typedef unsigned long  ulong_t;
+
+typedef long long      longlong_t;
+typedef unsigned long long u_longlong_t;
+#endif /* HAVE_INTTYPES */
+
+typedef longlong_t     offset_t;
+typedef u_longlong_t   u_offset_t;
+typedef u_longlong_t   len_t;
+typedef longlong_t     diskaddr_t;
+
+typedef ulong_t                pgcnt_t;        /* number of pages */
+typedef long           spgcnt_t;       /* signed number of pages */
+
+typedef short          pri_t;
+
+typedef int            zoneid_t;
+typedef int            projid_t;
+
+typedef int            major_t;
+typedef int            minor_t;
+
+typedef ushort_t o_mode_t; /* old file attribute type */
+typedef short          index_t;
+
+/*
+ * Definitions remaining from previous partial support for 64-bit file
+ * offsets.  This partial support for devices greater than 2gb requires
+ * compiler support for long long.
+ */
+#ifdef _LONG_LONG_LTOH
+typedef union {
+       offset_t _f;    /* Full 64 bit offset value */
+       struct {
+               int32_t _l; /* lower 32 bits of offset value */
+               int32_t _u; /* upper 32 bits of offset value */
+       } _p;
+} lloff_t;
+#endif
+
+#ifdef _LONG_LONG_HTOL
+typedef union {
+       offset_t _f;    /* Full 64 bit offset value */
+       struct {
+               int32_t _u; /* upper 32 bits of offset value */
+               int32_t _l; /* lower 32 bits of offset value */
+       } _p;
+} lloff_t;
+#endif
+
+#include <sys/param.h> /* for NBBY */
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/types32.h b/zfs/lib/libspl/include/sys/types32.h
new file mode 100644 (file)
index 0000000..9ab3b07
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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 _SYS_TYPES32_H
+#define        _SYS_TYPES32_H
+
+
+
+#include <sys/inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Interoperability types for programs. Used for:
+ *
+ * Crossing between 32-bit and 64-bit domains.
+ *
+ * On disk data formats such as filesystem meta data
+ * and disk label.
+ *
+ * Note: Applications should never include this
+ *       header file.
+ */
+typedef        uint32_t        caddr32_t;
+typedef        int32_t         daddr32_t;
+typedef        int32_t         off32_t;
+typedef        uint32_t        ino32_t;
+typedef        int32_t         blkcnt32_t;
+typedef uint32_t       fsblkcnt32_t;
+typedef        uint32_t        fsfilcnt32_t;
+typedef        int32_t         id32_t;
+typedef        uint32_t        major32_t;
+typedef        uint32_t        minor32_t;
+typedef        int32_t         key32_t;
+typedef        uint32_t        mode32_t;
+typedef        uint32_t        uid32_t;
+typedef        uint32_t        gid32_t;
+typedef        uint32_t        nlink32_t;
+typedef        uint32_t        dev32_t;
+typedef        int32_t         pid32_t;
+typedef        uint32_t        size32_t;
+typedef        int32_t         ssize32_t;
+typedef        int32_t         time32_t;
+typedef        int32_t         clock32_t;
+
+struct timeval32 {
+       time32_t        tv_sec;         /* seconds */
+       int32_t         tv_usec;        /* and microseconds */
+};
+
+typedef struct timespec32 {
+       time32_t        tv_sec;         /* seconds */
+       int32_t         tv_nsec;        /* and nanoseconds */
+} timespec32_t;
+
+typedef struct timespec32 timestruc32_t;
+
+typedef        struct itimerspec32 {
+       struct timespec32 it_interval;
+       struct timespec32 it_value;
+} itimerspec32_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_TYPES32_H */
diff --git a/zfs/lib/libspl/include/sys/tzfile.h b/zfs/lib/libspl/include/sys/tzfile.h
new file mode 100644 (file)
index 0000000..e30e756
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+/*
+ *     from Arthur Olson's 6.1
+ */
+
+#ifndef _LIBSPL_SYS_TZFILE_H
+#define        _LIBSPL_SYS_TZFILE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Information about time zone files.
+ */
+
+#define        TZDIR   "/usr/share/lib/zoneinfo" /* Time zone object file directory */
+
+#define        TZDEFAULT       (getenv("TZ"))
+
+#define        TZDEFRULES      "posixrules"
+
+/*
+ * Each file begins with. . .
+ */
+
+struct tzhead {
+       char    tzh_reserved[24];       /* reserved for future use */
+       char    tzh_ttisstdcnt[4];      /* coded number of trans. time flags */
+       char    tzh_leapcnt[4];         /* coded number of leap seconds */
+       char    tzh_timecnt[4];         /* coded number of transition times */
+       char    tzh_typecnt[4];         /* coded number of local time types */
+       char    tzh_charcnt[4];         /* coded number of abbr. chars */
+};
+
+/*
+ * . . .followed by. . .
+ *
+ *     tzh_timecnt (char [4])s         coded transition times a la time(2)
+ *     tzh_timecnt (unsigned char)s    types of local time starting at above
+ *     tzh_typecnt repetitions of
+ *             one (char [4])          coded GMT offset in seconds
+ *             one (unsigned char)     used to set tm_isdst
+ *             one (unsigned char)     that's an abbreviation list index
+ *     tzh_charcnt (char)s             '\0'-terminated zone abbreviations
+ *     tzh_leapcnt repetitions of
+ *             one (char [4])          coded leap second transition times
+ *             one (char [4])          total correction after above
+ *     tzh_ttisstdcnt (char)s          indexed by type; if TRUE, transition
+ *                                     time is standard time, if FALSE,
+ *                                     transition time is wall clock time
+ *                                     if absent, transition times are
+ *                                     assumed to be wall clock time
+ */
+
+/*
+ * In the current implementation, "tzset()" refuses to deal with files that
+ * exceed any of the limits below.
+ */
+
+/*
+ * The TZ_MAX_TIMES value below is enough to handle a bit more than a
+ * year's worth of solar time (corrected daily to the nearest second) or
+ * 138 years of Pacific Presidential Election time
+ * (where there are three time zone transitions every fourth year).
+ */
+#define        TZ_MAX_TIMES    370
+
+#define        TZ_MAX_TYPES    256     /* Limited by what (unsigned char)'s can hold */
+
+#define        TZ_MAX_CHARS    50      /* Maximum number of abbreviation characters */
+
+#define        TZ_MAX_LEAPS    50      /* Maximum number of leap second corrections */
+
+#define        SECSPERMIN      60
+#define        MINSPERHOUR     60
+#define        HOURSPERDAY     24
+#define        DAYSPERWEEK     7
+#define        DAYSPERNYEAR    365
+#define        DAYSPERLYEAR    366
+#define        SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
+#define        SECSPERDAY      ((long)SECSPERHOUR * HOURSPERDAY)
+#define        MONSPERYEAR     12
+
+#define        TM_SUNDAY       0
+#define        TM_MONDAY       1
+#define        TM_TUESDAY      2
+#define        TM_WEDNESDAY    3
+#define        TM_THURSDAY     4
+#define        TM_FRIDAY       5
+#define        TM_SATURDAY     6
+
+#define        TM_JANUARY      0
+#define        TM_FEBRUARY     1
+#define        TM_MARCH        2
+#define        TM_APRIL        3
+#define        TM_MAY          4
+#define        TM_JUNE         5
+#define        TM_JULY         6
+#define        TM_AUGUST       7
+#define        TM_SEPTEMBER    8
+#define        TM_OCTOBER      9
+#define        TM_NOVEMBER     10
+#define        TM_DECEMBER     11
+
+#define        TM_YEAR_BASE    1900
+
+#define        EPOCH_YEAR      1970
+#define        EPOCH_WDAY      TM_THURSDAY
+
+/*
+ * Accurate only for the past couple of centuries;
+ * that will probably do.
+ */
+
+#define        isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
+
+/*
+ * Use of the underscored variants may cause problems if you move your code to
+ * certain System-V-based systems; for maximum portability, use the
+ * underscore-free variants.  The underscored variants are provided for
+ * backward compatibility only; they may disappear from future versions of
+ * this file.
+ */
+
+#define        SECS_PER_MIN    SECSPERMIN
+#define        MINS_PER_HOUR   MINSPERHOUR
+#define        HOURS_PER_DAY   HOURSPERDAY
+#define        DAYS_PER_WEEK   DAYSPERWEEK
+#define        DAYS_PER_NYEAR  DAYSPERNYEAR
+#define        DAYS_PER_LYEAR  DAYSPERLYEAR
+#define        SECS_PER_HOUR   SECSPERHOUR
+#define        SECS_PER_DAY    SECSPERDAY
+#define        MONS_PER_YEAR   MONSPERYEAR
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSPL_SYS_TZFILE_H */
diff --git a/zfs/lib/libspl/include/sys/uio.h b/zfs/lib/libspl/include/sys/uio.h
new file mode 100644 (file)
index 0000000..97e8412
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+/*     Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/*       All Rights Reserved   */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#ifndef        _LIBSPL_SYS_UIO_H
+#define        _LIBSPL_SYS_UIO_H
+
+#include_next <sys/uio.h>
+
+typedef struct iovec iovec_t;
+
+typedef enum uio_rw {
+       UIO_READ =      0,
+       UIO_WRITE =     1,
+} uio_rw_t;
+
+typedef enum uio_seg {
+       UIO_USERSPACE = 0,
+       UIO_SYSSPACE =  1,
+       UIO_USERISPACE = 2,
+} uio_seg_t;
+
+typedef struct uio {
+       struct iovec    *uio_iov;       /* pointer to array of iovecs */
+       int             uio_iovcnt;     /* number of iovecs */
+       offset_t        uio_loffset;    /* file offset */
+       uio_seg_t       uio_segflg;     /* address space (kernel or user) */
+       uint16_t        uio_fmode;      /* file mode flags */
+       uint16_t        uio_extflg;     /* extended flags */
+       offset_t        uio_limit;      /* u-limit (maximum byte offset) */
+       ssize_t         uio_resid;      /* residual count */
+} uio_t;
+
+typedef enum xuio_type {
+       UIOTYPE_ASYNCIO,
+       UIOTYPE_ZEROCOPY,
+} xuio_type_t;
+
+#define        UIOA_IOV_MAX    16
+
+typedef struct uioa_page_s {           /* locked uio_iov state */
+       int     uioa_pfncnt;            /* count of pfn_t(s) in *uioa_ppp */
+       void    **uioa_ppp;             /* page_t or pfn_t arrary */
+       caddr_t uioa_base;              /* address base */
+       size_t  uioa_len;               /* span length */
+} uioa_page_t;
+
+typedef struct xuio {
+       uio_t xu_uio;                           /* embedded UIO structure */
+
+       /* Extended uio fields */
+       enum xuio_type xu_type;                 /* uio type */
+       union {
+               struct {
+                       uint32_t xu_a_state;    /* state of async i/o */
+                       ssize_t xu_a_mbytes;    /* bytes moved */
+                       uioa_page_t *xu_a_lcur; /* uioa_locked[] pointer */
+                       void **xu_a_lppp;       /* lcur->uioa_pppp[] pointer */
+                       void *xu_a_hwst[4];     /* opaque hardware state */
+                       uioa_page_t xu_a_locked[UIOA_IOV_MAX];
+               } xu_aio;
+
+               struct {
+                       int xu_zc_rw;           /* read or write buffer */
+                       void *xu_zc_priv;       /* fs specific */
+               } xu_zc;
+       } xu_ext;
+} xuio_t;
+
+#define        XUIO_XUZC_PRIV(xuio)    xuio->xu_ext.xu_zc.xu_zc_priv
+#define        XUIO_XUZC_RW(xuio)      xuio->xu_ext.xu_zc.xu_zc_rw
+
+#endif /* _SYS_UIO_H */
diff --git a/zfs/lib/libspl/include/sys/va_list.h b/zfs/lib/libspl/include/sys/va_list.h
new file mode 100644 (file)
index 0000000..a36f5c7
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_VA_LIST_H
+#define        _SYS_VA_LIST_H
+
+#include <stdarg.h>
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/varargs.h b/zfs/lib/libspl/include/sys/varargs.h
new file mode 100644 (file)
index 0000000..3d00a33
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_VARARGS_H
+#define        _LIBSPL_SYS_VARARGS_H
+
+#endif
diff --git a/zfs/lib/libspl/include/sys/vnode.h b/zfs/lib/libspl/include/sys/vnode.h
new file mode 100644 (file)
index 0000000..efcdd2c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_VNODE_H
+#define        _LIBSPL_SYS_VNODE_H
+
+#endif /* _LIBSPL_SYS_VNODE_H */
diff --git a/zfs/lib/libspl/include/sys/vtoc.h b/zfs/lib/libspl/include/sys/vtoc.h
new file mode 100644 (file)
index 0000000..22a652b
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * 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.
+ */
+
+
+/*     Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/*       All Rights Reserved   */
+
+
+#ifndef _SYS_VTOC_H
+#define        _SYS_VTOC_H
+
+#include <sys/dklabel.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *     Note:  the VTOC is not implemented fully, nor in the manner
+ *     that AT&T implements it.  AT&T puts the vtoc structure
+ *     into a sector, usually the second sector (pdsector is first).
+ *
+ *     Sun incorporates the tag, flag, version, and volume vtoc fields into
+ *     its Disk Label, which already has some vtoc-equivalent fields.
+ *     Upon reading the vtoc with read_vtoc(), the following exceptions
+ *     occur:
+ *             v_bootinfo [all]        returned as zero
+ *             v_sanity                returned as VTOC_SANE
+ *                                             if Disk Label was sane
+ *             v_sectorsz              returned as 512
+ *             v_reserved [all]        retunred as zero
+ *             timestamp [all]         returned as zero
+ *
+ *     See  dklabel.h, read_vtoc(), and write_vtoc().
+ */
+
+#define        V_NUMPAR        NDKMAP          /* The number of partitions */
+                                       /* (from dkio.h) */
+
+#define        VTOC_SANE       0x600DDEEE      /* Indicates a sane VTOC */
+#define        V_VERSION       0x01            /* layout version number */
+#define        V_EXTVERSION    V_VERSION       /* extvtoc layout version number */
+
+/*
+ * Partition identification tags
+ */
+#define        V_UNASSIGNED    0x00            /* unassigned partition */
+#define        V_BOOT          0x01            /* Boot partition */
+#define        V_ROOT          0x02            /* Root filesystem */
+#define        V_SWAP          0x03            /* Swap filesystem */
+#define        V_USR           0x04            /* Usr filesystem */
+#define        V_BACKUP        0x05            /* full disk */
+#define        V_STAND         0x06            /* Stand partition */
+#define        V_VAR           0x07            /* Var partition */
+#define        V_HOME          0x08            /* Home partition */
+#define        V_ALTSCTR       0x09            /* Alternate sector partition */
+#define        V_CACHE         0x0a            /* Cache (cachefs) partition */
+#define        V_RESERVED      0x0b            /* SMI reserved data */
+
+/*
+ * Partition permission flags
+ */
+#define        V_UNMNT         0x01            /* Unmountable partition */
+#define        V_RONLY         0x10            /* Read only */
+
+/*
+ * error codes for reading & writing vtoc
+ */
+#define        VT_ERROR        (-2)            /* errno supplies specific error */
+#define        VT_EIO          (-3)            /* I/O error accessing vtoc */
+#define        VT_EINVAL       (-4)            /* illegal value in vtoc or request */
+#define        VT_ENOTSUP      (-5)            /* VTOC op. not supported */
+#define        VT_ENOSPC       (-6)            /* requested space not found */
+#define        VT_EOVERFLOW    (-7)            /* VTOC op. data struct limited */
+
+struct partition       {
+       ushort_t        p_tag;          /* ID tag of partition */
+       ushort_t        p_flag;         /* permission flags */
+       uint64_t        p_start;        /* start sector no of partition */
+       long            p_size;         /* # of blocks in partition */
+};
+
+struct vtoc {
+       unsigned long   v_bootinfo[3];  /* info needed by mboot (unsupported) */
+       unsigned long   v_sanity;       /* to verify vtoc sanity */
+       unsigned long   v_version;      /* layout version */
+       char    v_volume[LEN_DKL_VVOL]; /* volume name */
+       ushort_t        v_sectorsz;     /* sector size in bytes */
+       ushort_t        v_nparts;       /* number of partitions */
+       unsigned long   v_reserved[10]; /* free space */
+       struct partition v_part[V_NUMPAR]; /* partition headers */
+       time_t  timestamp[V_NUMPAR];    /* partition timestamp (unsupported) */
+       char    v_asciilabel[LEN_DKL_ASCII];    /* for compatibility */
+};
+
+struct extpartition {
+       ushort_t p_tag;                 /* ID tag of partition */
+       ushort_t p_flag;                /* permission flags */
+       ushort_t p_pad[2];
+       diskaddr_t p_start;             /* start sector no of partition */
+       diskaddr_t p_size;              /* # of blocks in partition */
+};
+
+
+struct extvtoc {
+       uint64_t        v_bootinfo[3];  /* info needed by mboot (unsupported) */
+       uint64_t        v_sanity;       /* to verify vtoc sanity */
+       uint64_t        v_version;      /* layout version */
+       char    v_volume[LEN_DKL_VVOL]; /* volume name */
+       ushort_t        v_sectorsz;     /* sector size in bytes */
+       ushort_t        v_nparts;       /* number of partitions */
+       ushort_t        pad[2];
+       uint64_t        v_reserved[10];
+       struct extpartition v_part[V_NUMPAR]; /* partition headers */
+       uint64_t timestamp[V_NUMPAR];   /* partition timestamp (unsupported) */
+       char    v_asciilabel[LEN_DKL_ASCII];    /* for compatibility */
+};
+
+#ifdef _KERNEL
+#define        extvtoctovtoc(extv, v)                                          \
+       {                                                               \
+       int i;                                                          \
+       v.v_bootinfo[0]         = (unsigned long)extv.v_bootinfo[0];    \
+       v.v_bootinfo[1]         = (unsigned long)extv.v_bootinfo[1];    \
+       v.v_bootinfo[2]         = (unsigned long)extv.v_bootinfo[2];    \
+       v.v_sanity              = (unsigned long)extv.v_sanity;         \
+       v.v_version             = (unsigned long)extv.v_version;        \
+       bcopy(extv.v_volume, v.v_volume, LEN_DKL_VVOL);                 \
+       v.v_sectorsz            = extv.v_sectorsz;                      \
+       v.v_nparts              = extv.v_nparts;                        \
+       for (i = 0; i < 10; i++)                                        \
+               v.v_reserved[i] = (unsigned long)extv.v_reserved[i];    \
+       for (i = 0; i < V_NUMPAR; i++) {                                \
+               v.v_part[i].p_tag = extv.v_part[i].p_tag;               \
+               v.v_part[i].p_flag = extv.v_part[i].p_flag;             \
+               v.v_part[i].p_start = (uint64_t)extv.v_part[i].p_start; \
+               v.v_part[i].p_size = (long)extv.v_part[i].p_size;       \
+               v.timestamp[i] = (time_t)extv.timestamp[i];             \
+       }                                                               \
+       bcopy(extv.v_asciilabel, v.v_asciilabel, LEN_DKL_ASCII);        \
+       }
+
+#define        vtoctoextvtoc(v, extv)                                          \
+       {                                                               \
+       int i;                                                          \
+       extv.v_bootinfo[0]      = (uint64_t)v.v_bootinfo[0];            \
+       extv.v_bootinfo[1]      = (uint64_t)v.v_bootinfo[1];            \
+       extv.v_bootinfo[2]      = (uint64_t)v.v_bootinfo[2];            \
+       extv.v_sanity           = (uint64_t)v.v_sanity;                 \
+       extv.v_version          = (uint64_t)v.v_version;                \
+       bcopy(v.v_volume, extv.v_volume, LEN_DKL_VVOL);                 \
+       extv.v_sectorsz         = v.v_sectorsz;                         \
+       extv.v_nparts           = v.v_nparts;                           \
+       for (i = 0; i < 10; i++)                                        \
+               extv.v_reserved[i] = (uint64_t)v.v_reserved[i];         \
+       for (i = 0; i < V_NUMPAR; i++) {                                \
+               extv.v_part[i].p_tag = v.v_part[i].p_tag;               \
+               extv.v_part[i].p_flag = v.v_part[i].p_flag;             \
+               extv.v_part[i].p_start =                                \
+                   (diskaddr_t)(unsigned long)v.v_part[i].p_start;     \
+               extv.v_part[i].p_size =                                 \
+                   (diskaddr_t)(unsigned long)v.v_part[i].p_size;      \
+               extv.timestamp[i] = (uint64_t)v.timestamp[i];           \
+       }                                                               \
+       bcopy(v.v_asciilabel, extv.v_asciilabel, LEN_DKL_ASCII);        \
+       }
+#endif /* _KERNEL */
+
+#if defined(_SYSCALL32)
+struct partition32     {
+       uint16_t        p_tag;          /* ID tag of partition */
+       uint16_t        p_flag;         /* permission flags */
+       daddr32_t       p_start;        /* start sector no of partition */
+       int32_t         p_size;         /* # of blocks in partition */
+};
+
+struct vtoc32 {
+       uint32_t        v_bootinfo[3];  /* info needed by mboot (unsupported) */
+       uint32_t        v_sanity;       /* to verify vtoc sanity */
+       uint32_t        v_version;      /* layout version */
+       char    v_volume[LEN_DKL_VVOL]; /* volume name */
+       uint16_t        v_sectorsz;     /* sector size in bytes */
+       uint16_t        v_nparts;       /* number of partitions */
+       uint32_t        v_reserved[10]; /* free space */
+       struct partition32 v_part[V_NUMPAR]; /* partition headers */
+       time32_t timestamp[V_NUMPAR];   /* partition timestamp (unsupported) */
+       char    v_asciilabel[LEN_DKL_ASCII];    /* for compatibility */
+};
+
+#define        vtoc32tovtoc(v32, v)                            \
+       {                                               \
+       int i;                                          \
+       v.v_bootinfo[0]         = v32.v_bootinfo[0];    \
+       v.v_bootinfo[1]         = v32.v_bootinfo[1];    \
+       v.v_bootinfo[2]         = v32.v_bootinfo[2];    \
+       v.v_sanity              = v32.v_sanity;         \
+       v.v_version             = v32.v_version;        \
+       bcopy(v32.v_volume, v.v_volume, LEN_DKL_VVOL);  \
+       v.v_sectorsz            = v32.v_sectorsz;       \
+       v.v_nparts              = v32.v_nparts;         \
+       v.v_version             = v32.v_version;        \
+       for (i = 0; i < 10; i++)                        \
+               v.v_reserved[i] = v32.v_reserved[i];    \
+       for (i = 0; i < V_NUMPAR; i++) {                \
+               v.v_part[i].p_tag = (ushort_t)v32.v_part[i].p_tag;      \
+               v.v_part[i].p_flag = (ushort_t)v32.v_part[i].p_flag;    \
+               v.v_part[i].p_start = (unsigned)v32.v_part[i].p_start;  \
+               v.v_part[i].p_size = (unsigned)v32.v_part[i].p_size;    \
+       }                                               \
+       for (i = 0; i < V_NUMPAR; i++)                  \
+               v.timestamp[i] = (time_t)v32.timestamp[i];              \
+       bcopy(v32.v_asciilabel, v.v_asciilabel, LEN_DKL_ASCII);         \
+       }
+
+#define        vtoc32toextvtoc(v32, extv)                                      \
+       {                                                               \
+       int i;                                                          \
+       extv.v_bootinfo[0]              = v32.v_bootinfo[0];            \
+       extv.v_bootinfo[1]              = v32.v_bootinfo[1];            \
+       extv.v_bootinfo[2]              = v32.v_bootinfo[2];            \
+       extv.v_sanity           = v32.v_sanity;                         \
+       extv.v_version          = v32.v_version;                        \
+       bcopy(v32.v_volume, extv.v_volume, LEN_DKL_VVOL);               \
+       extv.v_sectorsz         = v32.v_sectorsz;                       \
+       extv.v_nparts           = v32.v_nparts;                         \
+       extv.v_version          = v32.v_version;                        \
+       for (i = 0; i < 10; i++)                                        \
+               extv.v_reserved[i] = v32.v_reserved[i];                 \
+       for (i = 0; i < V_NUMPAR; i++) {                                \
+               extv.v_part[i].p_tag = (ushort_t)v32.v_part[i].p_tag;   \
+               extv.v_part[i].p_flag = (ushort_t)v32.v_part[i].p_flag; \
+               extv.v_part[i].p_start = (diskaddr_t)v32.v_part[i].p_start; \
+               extv.v_part[i].p_size = (diskaddr_t)v32.v_part[i].p_size; \
+               extv.timestamp[i] = (time_t)v32.timestamp[i];           \
+       }                                                               \
+       bcopy(v32.v_asciilabel, extv.v_asciilabel, LEN_DKL_ASCII);      \
+       }
+
+
+#define        vtoctovtoc32(v, v32)                            \
+       {                                               \
+       int i;                                          \
+       v32.v_bootinfo[0]       = v.v_bootinfo[0];      \
+       v32.v_bootinfo[1]       = v.v_bootinfo[1];      \
+       v32.v_bootinfo[2]       = v.v_bootinfo[2];      \
+       v32.v_sanity            = v.v_sanity;           \
+       v32.v_version           = v.v_version;          \
+       bcopy(v.v_volume, v32.v_volume, LEN_DKL_VVOL);  \
+       v32.v_sectorsz          = v.v_sectorsz;         \
+       v32.v_nparts            = v.v_nparts;           \
+       v32.v_version           = v.v_version;          \
+       for (i = 0; i < 10; i++)                        \
+               v32.v_reserved[i] = v.v_reserved[i];    \
+       for (i = 0; i < V_NUMPAR; i++) {                \
+               v32.v_part[i].p_tag = (ushort_t)v.v_part[i].p_tag;      \
+               v32.v_part[i].p_flag = (ushort_t)v.v_part[i].p_flag;    \
+               v32.v_part[i].p_start = (unsigned)v.v_part[i].p_start;  \
+               v32.v_part[i].p_size = (unsigned)v.v_part[i].p_size;    \
+       }                                               \
+       for (i = 0; i < V_NUMPAR; i++) {                \
+               if (v.timestamp[i] > TIME32_MAX)        \
+                       v32.timestamp[i] = TIME32_MAX;  \
+               else                                    \
+                       v32.timestamp[i] = (time32_t)v.timestamp[i];    \
+       }                                               \
+       bcopy(v.v_asciilabel, v32.v_asciilabel, LEN_DKL_ASCII);         \
+       }
+
+#define        extvtoctovtoc32(extv, v32)                              \
+       {                                               \
+       int i;                                          \
+       v32.v_bootinfo[0]       = extv.v_bootinfo[0];   \
+       v32.v_bootinfo[1]       = extv.v_bootinfo[1];   \
+       v32.v_bootinfo[2]       = extv.v_bootinfo[2];   \
+       v32.v_sanity            = extv.v_sanity;                \
+       v32.v_version           = extv.v_version;               \
+       bcopy(extv.v_volume, v32.v_volume, LEN_DKL_VVOL);       \
+       v32.v_sectorsz          = extv.v_sectorsz;              \
+       v32.v_nparts            = extv.v_nparts;                \
+       v32.v_version           = extv.v_version;               \
+       for (i = 0; i < 10; i++)                        \
+               v32.v_reserved[i] = extv.v_reserved[i]; \
+       for (i = 0; i < V_NUMPAR; i++) {                \
+               v32.v_part[i].p_tag = (ushort_t)extv.v_part[i].p_tag;   \
+               v32.v_part[i].p_flag = (ushort_t)extv.v_part[i].p_flag; \
+               v32.v_part[i].p_start = (unsigned)extv.v_part[i].p_start; \
+               v32.v_part[i].p_size = (unsigned)extv.v_part[i].p_size; \
+       }                                               \
+       for (i = 0; i < V_NUMPAR; i++) {                \
+               if (extv.timestamp[i] > TIME32_MAX)     \
+                       v32.timestamp[i] = TIME32_MAX;  \
+               else                                    \
+                       v32.timestamp[i] = (time32_t)extv.timestamp[i]; \
+       }                                               \
+       bcopy(extv.v_asciilabel, v32.v_asciilabel, LEN_DKL_ASCII);      \
+       }
+
+
+#endif /* _SYSCALL32 */
+
+/*
+ * These defines are the mode parameter for the checksum routines.
+ */
+#define        CK_CHECKSUM     0       /* check checksum */
+#define        CK_MAKESUM      1       /* generate checksum */
+
+#if defined(__STDC__)
+
+extern int     read_vtoc(int, struct vtoc *);
+extern int     write_vtoc(int, struct vtoc *);
+extern int     read_extvtoc(int, struct extvtoc *);
+extern int     write_extvtoc(int, struct extvtoc *);
+
+#else
+
+extern int     read_vtoc();
+extern int     write_vtoc();
+extern int     read_extvtoc();
+extern int     write_extvtoc();
+
+#endif         /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_VTOC_H */
diff --git a/zfs/lib/libspl/include/sys/zone.h b/zfs/lib/libspl/include/sys/zone.h
new file mode 100644 (file)
index 0000000..bbb964d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_SYS_ZONE_H
+#define        _LIBSPL_SYS_ZONE_H
+
+#endif
diff --git a/zfs/lib/libspl/include/thread.h b/zfs/lib/libspl/include/thread.h
new file mode 100644 (file)
index 0000000..74694e2
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_THREAD_H
+#define        _LIBSPL_THREAD_H
+
+#endif /* _LIBSPL_THREAD_H */
diff --git a/zfs/lib/libspl/include/tzfile.h b/zfs/lib/libspl/include/tzfile.h
new file mode 100644 (file)
index 0000000..7bd4087
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_TZFILE_H
+#define        _LIBSPL_TZFILE_H
+
+#include <sys/tzfile.h>
+
+#endif /* _LIBSPL_TZFILE_H */
diff --git a/zfs/lib/libspl/include/ucred.h b/zfs/lib/libspl/include/ucred.h
new file mode 100644 (file)
index 0000000..8178fde
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_UCRED_H
+#define        _LIBSPL_UCRED_H
+
+typedef int ucred_t;
+
+#endif
diff --git a/zfs/lib/libspl/include/umem.h b/zfs/lib/libspl/include/umem.h
new file mode 100644 (file)
index 0000000..a89cb49
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_UMEM_H
+#define        _LIBSPL_UMEM_H
+
+/*
+ * XXX: We should use the real portable umem library if it is detected
+ * at configure time.  However, if the library is not available, we can
+ * use a trivial malloc based implementation.  This obviously impacts
+ * performance, but unless you are using a full userspace build of zpool for
+ * something other than ztest, you are likely not going to notice or care.
+ *
+ * https://labs.omniti.com/trac/portableumem
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef void vmem_t;
+
+/*
+ * Flags for umem_alloc/umem_free
+ */
+#define        UMEM_DEFAULT            0x0000  /* normal -- may fail */
+#define        UMEM_NOFAIL             0x0100  /* Never fails */
+
+/*
+ * Flags for umem_cache_create()
+ */
+#define        UMC_NOTOUCH             0x00010000
+#define        UMC_NODEBUG             0x00020000
+#define        UMC_NOMAGAZINE          0x00040000
+#define        UMC_NOHASH              0x00080000
+
+#define        UMEM_CACHE_NAMELEN      31
+
+typedef int umem_nofail_callback_t(void);
+typedef int umem_constructor_t(void *, void *, int);
+typedef void umem_destructor_t(void *, void *);
+typedef void umem_reclaim_t(void *);
+
+typedef struct umem_cache {
+       char                    cache_name[UMEM_CACHE_NAMELEN + 1];
+       size_t                  cache_bufsize;
+       size_t                  cache_align;
+       umem_constructor_t      *cache_constructor;
+       umem_destructor_t       *cache_destructor;
+       umem_reclaim_t          *cache_reclaim;
+       void                    *cache_private;
+       void                    *cache_arena;
+       int                     cache_cflags;
+} umem_cache_t;
+
+static inline void *
+umem_alloc(size_t size, int flags)
+{
+       void *ptr = NULL;
+
+       do {
+               ptr = malloc(size);
+       } while (ptr == NULL && (flags & UMEM_NOFAIL));
+
+       return (ptr);
+}
+
+static inline void *
+umem_alloc_aligned(size_t size, size_t align, int flags)
+{
+       void *ptr = NULL;
+       int rc = EINVAL;
+
+       do {
+               rc = posix_memalign(&ptr, align, size);
+       } while (rc == ENOMEM && (flags & UMEM_NOFAIL));
+
+       if (rc == EINVAL) {
+               fprintf(stderr, "%s: invalid memory alignment (%zd)\n",
+                   __func__, align);
+               if (flags & UMEM_NOFAIL)
+                       abort();
+               return (NULL);
+       }
+
+       return (ptr);
+}
+
+static inline void *
+umem_zalloc(size_t size, int flags)
+{
+       void *ptr = NULL;
+
+       ptr = umem_alloc(size, flags);
+       if (ptr)
+               memset(ptr, 0, size);
+
+       return (ptr);
+}
+
+static inline void
+umem_free(void *ptr, size_t size)
+{
+       free(ptr);
+}
+
+static inline void
+umem_nofail_callback(umem_nofail_callback_t *cb) {}
+
+static inline umem_cache_t *
+umem_cache_create(
+    char *name, size_t bufsize, size_t align,
+    umem_constructor_t *constructor,
+    umem_destructor_t *destructor,
+    umem_reclaim_t *reclaim,
+    void *priv, void *vmp, int cflags)
+{
+       umem_cache_t *cp;
+
+       cp = umem_alloc(sizeof (umem_cache_t), UMEM_DEFAULT);
+       if (cp) {
+               strncpy(cp->cache_name, name, UMEM_CACHE_NAMELEN);
+               cp->cache_bufsize = bufsize;
+               cp->cache_align = align;
+               cp->cache_constructor = constructor;
+               cp->cache_destructor = destructor;
+               cp->cache_reclaim = reclaim;
+               cp->cache_private = priv;
+               cp->cache_arena = vmp;
+               cp->cache_cflags = cflags;
+       }
+
+       return (cp);
+}
+
+static inline void
+umem_cache_destroy(umem_cache_t *cp)
+{
+       umem_free(cp, sizeof (umem_cache_t));
+}
+
+static inline void *
+umem_cache_alloc(umem_cache_t *cp, int flags)
+{
+       void *ptr = NULL;
+
+       if (cp->cache_align != 0)
+               ptr = umem_alloc_aligned(
+                   cp->cache_bufsize, cp->cache_align, flags);
+       else
+               ptr = umem_alloc(cp->cache_bufsize, flags);
+
+       if (ptr && cp->cache_constructor)
+               cp->cache_constructor(ptr, cp->cache_private, UMEM_DEFAULT);
+
+       return (ptr);
+}
+
+static inline void
+umem_cache_free(umem_cache_t *cp, void *ptr)
+{
+       if (cp->cache_destructor)
+               cp->cache_destructor(ptr, cp->cache_private);
+
+       umem_free(ptr, cp->cache_bufsize);
+}
+
+static inline void
+umem_cache_reap_now(umem_cache_t *cp)
+{
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/zfs/lib/libspl/include/unistd.h b/zfs/lib/libspl/include/unistd.h
new file mode 100644 (file)
index 0000000..0246991
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include_next <unistd.h>
+
+#ifndef _LIBSPL_UNISTD_H
+#define        _LIBSPL_UNISTD_H
+
+#include <sys/ioctl.h>
+
+#if !defined(HAVE_ISSETUGID)
+#include <sys/types.h>
+#define        issetugid() (geteuid() == 0 || getegid() == 0)
+#endif
+
+#endif /* _LIBSPL_UNISTD_H */
diff --git a/zfs/lib/libspl/include/util/Makefile.am b/zfs/lib/libspl/include/util/Makefile.am
new file mode 100644 (file)
index 0000000..060e143
--- /dev/null
@@ -0,0 +1,3 @@
+libspldir = $(includedir)/libspl
+libspl_HEADERS = \
+       $(top_srcdir)/lib/libspl/include/util/sscanf.h
diff --git a/zfs/lib/libspl/include/util/Makefile.in b/zfs/lib/libspl/include/util/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libspl/include/util/sscanf.h b/zfs/lib/libspl/include/util/sscanf.h
new file mode 100644 (file)
index 0000000..ead36ac
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBSPL_UTIL_SSCANF_H
+#define        _LIBSPL_UTIL_SSCANF_H
+
+#endif
diff --git a/zfs/lib/libspl/include/zone.h b/zfs/lib/libspl/include/zone.h
new file mode 100644 (file)
index 0000000..b4a6deb
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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 _LIBSPL_ZONE_H
+#define        _LIBSPL_ZONE_H
+
+
+
+#include <sys/types.h>
+#include <sys/zone.h>
+#include <sys/priv.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        GLOBAL_ZONEID           0
+#define        GLOBAL_ZONEID_NAME      "global"
+
+/*
+ * Functions for mapping between id and name for active zones.
+ */
+extern zoneid_t                getzoneid(void);
+extern zoneid_t                getzoneidbyname(const char *);
+extern ssize_t         getzonenamebyid(zoneid_t, char *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBSPL_ZONE_H */
diff --git a/zfs/lib/libspl/list.c b/zfs/lib/libspl/list.c
new file mode 100644 (file)
index 0000000..b29dc8a
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * 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.
+ */
+
+/*
+ * Generic doubly-linked list implementation
+ */
+
+#include <sys/list.h>
+#include <sys/list_impl.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/debug.h>
+
+#define        list_d2l(a, obj) ((list_node_t *)(((char *)obj) + (a)->list_offset))
+#define        list_object(a, node) ((void *)(((char *)node) - (a)->list_offset))
+#define        list_empty(a) ((a)->list_head.list_next == &(a)->list_head)
+
+#define        list_insert_after_node(list, node, object) {    \
+       list_node_t *lnew = list_d2l(list, object);     \
+       lnew->list_prev = (node);                       \
+       lnew->list_next = (node)->list_next;            \
+       (node)->list_next->list_prev = lnew;            \
+       (node)->list_next = lnew;                       \
+}
+
+#define        list_insert_before_node(list, node, object) {   \
+       list_node_t *lnew = list_d2l(list, object);     \
+       lnew->list_next = (node);                       \
+       lnew->list_prev = (node)->list_prev;            \
+       (node)->list_prev->list_next = lnew;            \
+       (node)->list_prev = lnew;                       \
+}
+
+#define        list_remove_node(node)                                  \
+       (node)->list_prev->list_next = (node)->list_next;       \
+       (node)->list_next->list_prev = (node)->list_prev;       \
+       (node)->list_next = (node)->list_prev = NULL
+
+void
+list_create(list_t *list, size_t size, size_t offset)
+{
+       ASSERT(list);
+       ASSERT(size > 0);
+       ASSERT(size >= offset + sizeof (list_node_t));
+
+       list->list_size = size;
+       list->list_offset = offset;
+       list->list_head.list_next = list->list_head.list_prev =
+           &list->list_head;
+}
+
+void
+list_destroy(list_t *list)
+{
+       list_node_t *node = &list->list_head;
+
+       ASSERT(list);
+       ASSERT(list->list_head.list_next == node);
+       ASSERT(list->list_head.list_prev == node);
+
+       node->list_next = node->list_prev = NULL;
+}
+
+void
+list_insert_after(list_t *list, void *object, void *nobject)
+{
+       if (object == NULL) {
+               list_insert_head(list, nobject);
+       } else {
+               list_node_t *lold = list_d2l(list, object);
+               list_insert_after_node(list, lold, nobject);
+       }
+}
+
+void
+list_insert_before(list_t *list, void *object, void *nobject)
+{
+       if (object == NULL) {
+               list_insert_tail(list, nobject);
+       } else {
+               list_node_t *lold = list_d2l(list, object);
+               list_insert_before_node(list, lold, nobject);
+       }
+}
+
+void
+list_insert_head(list_t *list, void *object)
+{
+       list_node_t *lold = &list->list_head;
+       list_insert_after_node(list, lold, object);
+}
+
+void
+list_insert_tail(list_t *list, void *object)
+{
+       list_node_t *lold = &list->list_head;
+       list_insert_before_node(list, lold, object);
+}
+
+void
+list_remove(list_t *list, void *object)
+{
+       list_node_t *lold = list_d2l(list, object);
+       ASSERT(!list_empty(list));
+       ASSERT(lold->list_next != NULL);
+       list_remove_node(lold);
+}
+
+void *
+list_remove_head(list_t *list)
+{
+       list_node_t *head = list->list_head.list_next;
+       if (head == &list->list_head)
+               return (NULL);
+       list_remove_node(head);
+       return (list_object(list, head));
+}
+
+void *
+list_remove_tail(list_t *list)
+{
+       list_node_t *tail = list->list_head.list_prev;
+       if (tail == &list->list_head)
+               return (NULL);
+       list_remove_node(tail);
+       return (list_object(list, tail));
+}
+
+void *
+list_head(list_t *list)
+{
+       if (list_empty(list))
+               return (NULL);
+       return (list_object(list, list->list_head.list_next));
+}
+
+void *
+list_tail(list_t *list)
+{
+       if (list_empty(list))
+               return (NULL);
+       return (list_object(list, list->list_head.list_prev));
+}
+
+void *
+list_next(list_t *list, void *object)
+{
+       list_node_t *node = list_d2l(list, object);
+
+       if (node->list_next != &list->list_head)
+               return (list_object(list, node->list_next));
+
+       return (NULL);
+}
+
+void *
+list_prev(list_t *list, void *object)
+{
+       list_node_t *node = list_d2l(list, object);
+
+       if (node->list_prev != &list->list_head)
+               return (list_object(list, node->list_prev));
+
+       return (NULL);
+}
+
+/*
+ *  Insert src list after dst list. Empty src list thereafter.
+ */
+void
+list_move_tail(list_t *dst, list_t *src)
+{
+       list_node_t *dstnode = &dst->list_head;
+       list_node_t *srcnode = &src->list_head;
+
+       ASSERT(dst->list_size == src->list_size);
+       ASSERT(dst->list_offset == src->list_offset);
+
+       if (list_empty(src))
+               return;
+
+       dstnode->list_prev->list_next = srcnode->list_next;
+       srcnode->list_next->list_prev = dstnode->list_prev;
+       dstnode->list_prev = srcnode->list_prev;
+       srcnode->list_prev->list_next = dstnode;
+
+       /* empty src list */
+       srcnode->list_next = srcnode->list_prev = srcnode;
+}
+
+void
+list_link_replace(list_node_t *lold, list_node_t *lnew)
+{
+       ASSERT(list_link_active(lold));
+       ASSERT(!list_link_active(lnew));
+
+       lnew->list_next = lold->list_next;
+       lnew->list_prev = lold->list_prev;
+       lold->list_prev->list_next = lnew;
+       lold->list_next->list_prev = lnew;
+       lold->list_next = lold->list_prev = NULL;
+}
+
+void
+list_link_init(list_node_t *ln)
+{
+       ln->list_next = NULL;
+       ln->list_prev = NULL;
+}
+
+int
+list_link_active(list_node_t *ln)
+{
+       return (ln->list_next != NULL);
+}
+
+int
+list_is_empty(list_t *list)
+{
+       return (list_empty(list));
+}
diff --git a/zfs/lib/libspl/mkdirp.c b/zfs/lib/libspl/mkdirp.c
new file mode 100644 (file)
index 0000000..2f09188
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * 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) 1988 AT&T */
+/*       All Rights Reserved   */
+
+/*
+ * Creates directory and it's parents if the parents do not
+ * exist yet.
+ *
+ * Returns -1 if fails for reasons other than non-existing
+ * parents.
+ * Does NOT simplify pathnames with . or .. in them.
+ */
+
+#include <sys/types.h>
+#include <libgen.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+
+static char *simplify(const char *str);
+
+int
+mkdirp(const char *d, mode_t mode)
+{
+       char  *endptr, *ptr, *slash, *str;
+
+       str = simplify(d);
+
+       /* If space couldn't be allocated for the simplified names, return. */
+
+       if (str == NULL)
+               return (-1);
+
+               /* Try to make the directory */
+
+       if (mkdir(str, mode) == 0) {
+               free(str);
+               return (0);
+       }
+       if (errno != ENOENT) {
+               free(str);
+               return (-1);
+       }
+       endptr = strrchr(str, '\0');
+       slash = strrchr(str, '/');
+
+               /* Search upward for the non-existing parent */
+
+       while (slash != NULL) {
+
+               ptr = slash;
+               *ptr = '\0';
+
+                       /* If reached an existing parent, break */
+
+               if (access(str, F_OK) == 0)
+                       break;
+
+                       /* If non-existing parent */
+
+               else {
+                       slash = strrchr(str, '/');
+
+                               /* If under / or current directory, make it. */
+
+                       if (slash == NULL || slash == str) {
+                               if (mkdir(str, mode) != 0 && errno != EEXIST) {
+                                       free(str);
+                                       return (-1);
+                               }
+                               break;
+                       }
+               }
+       }
+
+       /* Create directories starting from upmost non-existing parent */
+
+       while ((ptr = strchr(str, '\0')) != endptr) {
+               *ptr = '/';
+               if (mkdir(str, mode) != 0 && errno != EEXIST) {
+                       /*
+                        *  If the mkdir fails because str already
+                        *  exists (EEXIST), then str has the form
+                        *  "existing-dir/..", and this is really
+                        *  ok. (Remember, this loop is creating the
+                        *  portion of the path that didn't exist)
+                        */
+                       free(str);
+                       return (-1);
+               }
+       }
+       free(str);
+       return (0);
+}
+
+/*
+ *     simplify - given a pathname, simplify that path by removing
+ *                duplicate contiguous slashes.
+ *
+ *                A simplified copy of the argument is returned to the
+ *                caller, or NULL is returned on error.
+ *
+ *                The caller should handle error reporting based upon the
+ *                returned vlaue, and should free the returned value,
+ *                when appropriate.
+ */
+
+static char *
+simplify(const char *str)
+{
+       int i;
+       size_t mbPathlen;       /* length of multi-byte path */
+       size_t wcPathlen;       /* length of wide-character path */
+       wchar_t *wptr;          /* scratch pointer */
+       wchar_t *wcPath;        /* wide-character version of the path */
+       char *mbPath;           /* The copy fo the path to be returned */
+
+       /*
+        *  bail out if there is nothing there.
+        */
+
+       if (!str) {
+               errno = ENOENT;
+               return (NULL);
+       }
+
+       /*
+        *  Get a copy of the argument.
+        */
+
+       if ((mbPath = strdup(str)) == NULL) {
+               return (NULL);
+       }
+
+       /*
+        *  convert the multi-byte version of the path to a
+        *  wide-character rendering, for doing our figuring.
+        */
+
+       mbPathlen = strlen(mbPath);
+
+       if ((wcPath = calloc(sizeof (wchar_t), mbPathlen+1)) == NULL) {
+               free(mbPath);
+               return (NULL);
+       }
+
+       if ((wcPathlen = mbstowcs(wcPath, mbPath, mbPathlen)) == (size_t)-1) {
+               free(mbPath);
+               free(wcPath);
+               return (NULL);
+       }
+
+       /*
+        *  remove duplicate slashes first ("//../" -> "/")
+        */
+
+       for (wptr = wcPath, i = 0; i < wcPathlen; i++) {
+               *wptr++ = wcPath[i];
+
+               if (wcPath[i] == '/') {
+                       i++;
+
+                       while (wcPath[i] == '/') {
+                               i++;
+                       }
+
+                       i--;
+               }
+       }
+
+       *wptr = '\0';
+
+       /*
+        *  now convert back to the multi-byte format.
+        */
+
+       if (wcstombs(mbPath, wcPath, mbPathlen) == (size_t)-1) {
+               free(mbPath);
+               free(wcPath);
+               return (NULL);
+       }
+
+       free(wcPath);
+       return (mbPath);
+}
diff --git a/zfs/lib/libspl/strlcat.c b/zfs/lib/libspl/strlcat.c
new file mode 100644 (file)
index 0000000..a001df7
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+/*
+ * Appends src to the dstsize buffer at dst. The append will never
+ * overflow the destination buffer and the buffer will always be null
+ * terminated. Never reference beyond &dst[dstsize-1] when computing
+ * the length of the pre-existing string.
+ */
+
+size_t
+strlcat(char *dst, const char *src, size_t dstsize)
+{
+       char *df = dst;
+       size_t left = dstsize;
+       size_t l1;
+       size_t l2 = strlen(src);
+       size_t copied;
+
+       while (left-- != 0 && *df != '\0')
+               df++;
+       l1 = df - dst;
+       if (dstsize == l1)
+               return (l1 + l2);
+
+       copied = l1 + l2 >= dstsize ? dstsize - l1 - 1 : l2;
+       (void) memcpy(dst + l1, src, copied);
+       dst[l1+copied] = '\0';
+       return (l1 + l2);
+}
diff --git a/zfs/lib/libspl/strlcpy.c b/zfs/lib/libspl/strlcpy.c
new file mode 100644 (file)
index 0000000..2d0daae
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+/*
+ * Copies src to the dstsize buffer at dst. The copy will never
+ * overflow the destination buffer and the buffer will always be null
+ * terminated.
+ */
+
+size_t
+strlcpy(char *dst, const char *src, size_t len)
+{
+       size_t slen = strlen(src);
+       size_t copied;
+
+       if (len == 0)
+               return (slen);
+
+       if (slen >= len)
+               copied = len - 1;
+       else
+               copied = slen;
+       (void) memcpy(dst, src, copied);
+       dst[copied] = '\0';
+       return (slen);
+}
diff --git a/zfs/lib/libspl/strnlen.c b/zfs/lib/libspl/strnlen.c
new file mode 100644 (file)
index 0000000..9fb8227
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+
+/*
+ * Returns the number of non-NULL bytes in string argument,
+ * but not more than maxlen.  Does not look past str + maxlen.
+ */
+size_t
+strnlen(const char *str, size_t maxlen)
+{
+       const char *ptr;
+
+       ptr = memchr(str, 0, maxlen);
+       if (ptr == NULL)
+               return (maxlen);
+
+       return (ptr - str);
+}
diff --git a/zfs/lib/libspl/timestamp.c b/zfs/lib/libspl/timestamp.c
new file mode 100644 (file)
index 0000000..e2838da
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <langinfo.h>
+#include "statcommon.h"
+
+#ifndef _DATE_FMT
+#define        _DATE_FMT "%+"
+#endif
+
+/*
+ * Print timestamp as decimal reprentation of time_t value (-T u was specified)
+ * or in date(1) format (-T d was specified).
+ */
+void
+print_timestamp(uint_t timestamp_fmt)
+{
+       time_t t = time(NULL);
+       static char *fmt = NULL;
+
+       /* We only need to retrieve this once per invocation */
+       if (fmt == NULL)
+               fmt = nl_langinfo(_DATE_FMT);
+
+       if (timestamp_fmt == UDATE) {
+               (void) printf("%ld\n", t);
+       } else if (timestamp_fmt == DDATE) {
+               char dstr[64];
+               int len;
+
+               len = strftime(dstr, sizeof (dstr), fmt, localtime(&t));
+               if (len > 0)
+                       (void) printf("%s\n", dstr);
+       }
+}
diff --git a/zfs/lib/libspl/zone.c b/zfs/lib/libspl/zone.c
new file mode 100644 (file)
index 0000000..5ca93b2
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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 2006 Ricardo Correia.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <zone.h>
+#include <string.h>
+#include <errno.h>
+
+zoneid_t
+getzoneid()
+{
+       return (GLOBAL_ZONEID);
+}
+
+zoneid_t
+getzoneidbyname(const char *name)
+{
+       if (name == NULL)
+               return (GLOBAL_ZONEID);
+
+       if (strcmp(name, GLOBAL_ZONEID_NAME) == 0)
+               return (GLOBAL_ZONEID);
+
+       return (EINVAL);
+}
+
+ssize_t
+getzonenamebyid(zoneid_t id, char *buf, size_t buflen)
+{
+       if (id != GLOBAL_ZONEID)
+               return (EINVAL);
+
+       ssize_t ret = strlen(GLOBAL_ZONEID_NAME) + 1;
+
+       if (buf == NULL || buflen == 0)
+               return (ret);
+
+       strncpy(buf, GLOBAL_ZONEID_NAME, buflen);
+       buf[buflen - 1] = '\0';
+
+       return (ret);
+}
diff --git a/zfs/lib/libunicode/Makefile.am b/zfs/lib/libunicode/Makefile.am
new file mode 100644 (file)
index 0000000..9bacae2
--- /dev/null
@@ -0,0 +1,23 @@
+include $(top_srcdir)/config/Rules.am
+
+VPATH = $(top_srcdir)/module/unicode
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+noinst_LTLIBRARIES = libunicode.la
+
+USER_C =
+
+KERNEL_C = \
+       u8_textprep.c \
+       uconv.c
+
+nodist_libunicode_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libunicode/Makefile.in b/zfs/lib/libunicode/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libuutil/Makefile.am b/zfs/lib/libuutil/Makefile.am
new file mode 100644 (file)
index 0000000..4d54485
--- /dev/null
@@ -0,0 +1,36 @@
+include $(top_srcdir)/config/Rules.am
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+lib_LTLIBRARIES = libuutil.la
+
+USER_C = \
+       uu_alloc.c \
+       uu_avl.c \
+       uu_dprintf.c \
+       uu_ident.c \
+       uu_list.c \
+       uu_misc.c \
+       uu_open.c \
+       uu_pname.c \
+       uu_string.c \
+       uu_strtoint.c
+
+KERNEL_C =
+
+nodist_libuutil_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+libuutil_la_LIBADD = \
+       $(top_builddir)/lib/libavl/libavl.la \
+       $(top_builddir)/lib/libspl/libspl.la \
+       $(top_builddir)/lib/libefi/libefi.la
+
+libuutil_la_LDFLAGS = -pthread -version-info 1:1:0
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libuutil/Makefile.in b/zfs/lib/libuutil/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libuutil/uu_alloc.c b/zfs/lib/libuutil/uu_alloc.c
new file mode 100644 (file)
index 0000000..2bef759
--- /dev/null
@@ -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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "libuutil_common.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *
+uu_zalloc(size_t n)
+{
+       void *p = malloc(n);
+
+       if (p == NULL) {
+               uu_set_error(UU_ERROR_SYSTEM);
+               return (NULL);
+       }
+
+       (void) memset(p, 0, n);
+
+       return (p);
+}
+
+void
+uu_free(void *p)
+{
+       free(p);
+}
+
+char *
+uu_strdup(const char *str)
+{
+       char *buf = NULL;
+
+       if (str != NULL) {
+               size_t sz;
+
+               sz = strlen(str) + 1;
+               buf = uu_zalloc(sz);
+               if (buf != NULL)
+                       (void) memcpy(buf, str, sz);
+       }
+       return (buf);
+}
+
+/*
+ * Duplicate up to n bytes of a string.  Kind of sort of like
+ * strdup(strlcpy(s, n)).
+ */
+char *
+uu_strndup(const char *s, size_t n)
+{
+       size_t len;
+       char *p;
+
+       len = strnlen(s, n);
+       p = uu_zalloc(len + 1);
+       if (p == NULL)
+               return (NULL);
+
+       if (len > 0)
+               (void) memcpy(p, s, len);
+       p[len] = '\0';
+
+       return (p);
+}
+
+/*
+ * Duplicate a block of memory.  Combines malloc with memcpy, much as
+ * strdup combines malloc, strlen, and strcpy.
+ */
+void *
+uu_memdup(const void *buf, size_t sz)
+{
+       void *p;
+
+       p = uu_zalloc(sz);
+       if (p == NULL)
+               return (NULL);
+       (void) memcpy(p, buf, sz);
+       return (p);
+}
+
+char *
+uu_msprintf(const char *format, ...)
+{
+       va_list args;
+       char attic[1];
+       uint_t M, m;
+       char *b;
+
+       va_start(args, format);
+       M = vsnprintf(attic, 1, format, args);
+       va_end(args);
+
+       for (;;) {
+               m = M;
+               if ((b = uu_zalloc(m + 1)) == NULL)
+                       return (NULL);
+
+               va_start(args, format);
+               M = vsnprintf(b, m + 1, format, args);
+               va_end(args);
+
+               if (M == m)
+                       break;          /* sizes match */
+
+               uu_free(b);
+       }
+
+       return (b);
+}
diff --git a/zfs/lib/libuutil/uu_avl.c b/zfs/lib/libuutil/uu_avl.c
new file mode 100644 (file)
index 0000000..0400088
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ * 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.
+ */
+
+
+
+#include "libuutil_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/avl.h>
+
+static uu_avl_pool_t   uu_null_apool = { &uu_null_apool, &uu_null_apool };
+static pthread_mutex_t uu_apool_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * The index mark change on every insert and delete, to catch stale
+ * references.
+ *
+ * We leave the low bit alone, since the avl code uses it.
+ */
+#define        INDEX_MAX               (sizeof (uintptr_t) - 2)
+#define        INDEX_NEXT(m)           (((m) == INDEX_MAX)? 2 : ((m) + 2) & INDEX_MAX)
+
+#define        INDEX_DECODE(i)         ((i) & ~INDEX_MAX)
+#define        INDEX_ENCODE(p, n)      (((n) & ~INDEX_MAX) | (p)->ua_index)
+#define        INDEX_VALID(p, i)       (((i) & INDEX_MAX) == (p)->ua_index)
+#define        INDEX_CHECK(i)          (((i) & INDEX_MAX) != 0)
+
+/*
+ * When an element is inactive (not in a tree), we keep a marked pointer to
+ * its containing pool in its first word, and a NULL pointer in its second.
+ *
+ * On insert, we use these to verify that it comes from the correct pool.
+ */
+#define        NODE_ARRAY(p, n)        ((uintptr_t *)((uintptr_t)(n) + \
+                                   (pp)->uap_nodeoffset))
+
+#define        POOL_TO_MARKER(pp) (((uintptr_t)(pp) | 1))
+
+#define        DEAD_MARKER             0xc4
+
+uu_avl_pool_t *
+uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset,
+    uu_compare_fn_t *compare_func, uint32_t flags)
+{
+       uu_avl_pool_t *pp, *next, *prev;
+
+       if (name == NULL ||
+           uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
+           nodeoffset + sizeof (uu_avl_node_t) > objsize ||
+           compare_func == NULL) {
+               uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+               return (NULL);
+       }
+
+       if (flags & ~UU_AVL_POOL_DEBUG) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (NULL);
+       }
+
+       pp = uu_zalloc(sizeof (uu_avl_pool_t));
+       if (pp == NULL) {
+               uu_set_error(UU_ERROR_NO_MEMORY);
+               return (NULL);
+       }
+
+       (void) strlcpy(pp->uap_name, name, sizeof (pp->uap_name));
+       pp->uap_nodeoffset = nodeoffset;
+       pp->uap_objsize = objsize;
+       pp->uap_cmp = compare_func;
+       if (flags & UU_AVL_POOL_DEBUG)
+               pp->uap_debug = 1;
+       pp->uap_last_index = 0;
+
+       (void) pthread_mutex_init(&pp->uap_lock, NULL);
+
+       pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
+       pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl);
+
+       (void) pthread_mutex_lock(&uu_apool_list_lock);
+       pp->uap_next = next = &uu_null_apool;
+       pp->uap_prev = prev = next->uap_prev;
+       next->uap_prev = pp;
+       prev->uap_next = pp;
+       (void) pthread_mutex_unlock(&uu_apool_list_lock);
+
+       return (pp);
+}
+
+void
+uu_avl_pool_destroy(uu_avl_pool_t *pp)
+{
+       if (pp->uap_debug) {
+               if (pp->uap_null_avl.ua_next_enc !=
+                   UU_PTR_ENCODE(&pp->uap_null_avl) ||
+                   pp->uap_null_avl.ua_prev_enc !=
+                   UU_PTR_ENCODE(&pp->uap_null_avl)) {
+                       uu_panic("uu_avl_pool_destroy: Pool \"%.*s\" (%p) has "
+                           "outstanding avls, or is corrupt.\n",
+                           (int)sizeof (pp->uap_name), pp->uap_name,
+                           (void *)pp);
+               }
+       }
+       (void) pthread_mutex_lock(&uu_apool_list_lock);
+       pp->uap_next->uap_prev = pp->uap_prev;
+       pp->uap_prev->uap_next = pp->uap_next;
+       (void) pthread_mutex_unlock(&uu_apool_list_lock);
+       pp->uap_prev = NULL;
+       pp->uap_next = NULL;
+       uu_free(pp);
+}
+
+void
+uu_avl_node_init(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
+{
+       uintptr_t *na = (uintptr_t *)np;
+
+       if (pp->uap_debug) {
+               uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
+               if (offset + sizeof (*np) > pp->uap_objsize) {
+                       uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
+                           "offset %ld doesn't fit in object (size %ld)\n",
+                           base, (void *)np, (void *)pp, pp->uap_name,
+                           (long)offset, (long)pp->uap_objsize);
+               }
+               if (offset != pp->uap_nodeoffset) {
+                       uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): "
+                           "offset %ld doesn't match pool's offset (%ld)\n",
+                           base, (void *)np, (void *)pp, pp->uap_name,
+                           (long)offset, (long)pp->uap_objsize);
+               }
+       }
+
+       na[0] = POOL_TO_MARKER(pp);
+       na[1] = 0;
+}
+
+void
+uu_avl_node_fini(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp)
+{
+       uintptr_t *na = (uintptr_t *)np;
+
+       if (pp->uap_debug) {
+               if (na[0] == DEAD_MARKER && na[1] == DEAD_MARKER) {
+                       uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
+                           "node already finied\n",
+                           base, (void *)np, (void *)pp, pp->uap_name);
+               }
+               if (na[0] != POOL_TO_MARKER(pp) || na[1] != 0) {
+                       uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): "
+                           "node corrupt, in tree, or in different pool\n",
+                           base, (void *)np, (void *)pp, pp->uap_name);
+               }
+       }
+
+       na[0] = DEAD_MARKER;
+       na[1] = DEAD_MARKER;
+       na[2] = DEAD_MARKER;
+}
+
+struct uu_avl_node_compare_info {
+       uu_compare_fn_t *ac_compare;
+       void            *ac_private;
+       void            *ac_right;
+       void            *ac_found;
+};
+
+static int
+uu_avl_node_compare(const void *l, const void *r)
+{
+       struct uu_avl_node_compare_info *info =
+           (struct uu_avl_node_compare_info *)l;
+
+       int res = info->ac_compare(r, info->ac_right, info->ac_private);
+
+       if (res == 0) {
+               if (info->ac_found == NULL)
+                       info->ac_found = (void *)r;
+               return (-1);
+       }
+       if (res < 0)
+               return (1);
+       return (-1);
+}
+
+uu_avl_t *
+uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags)
+{
+       uu_avl_t *ap, *next, *prev;
+
+       if (flags & ~UU_AVL_DEBUG) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (NULL);
+       }
+
+       ap = uu_zalloc(sizeof (*ap));
+       if (ap == NULL) {
+               uu_set_error(UU_ERROR_NO_MEMORY);
+               return (NULL);
+       }
+
+       ap->ua_pool = pp;
+       ap->ua_parent_enc = UU_PTR_ENCODE(parent);
+       ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG);
+       ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index));
+
+       avl_create(&ap->ua_tree, &uu_avl_node_compare, pp->uap_objsize,
+           pp->uap_nodeoffset);
+
+       ap->ua_null_walk.uaw_next = &ap->ua_null_walk;
+       ap->ua_null_walk.uaw_prev = &ap->ua_null_walk;
+
+       (void) pthread_mutex_lock(&pp->uap_lock);
+       next = &pp->uap_null_avl;
+       prev = UU_PTR_DECODE(next->ua_prev_enc);
+       ap->ua_next_enc = UU_PTR_ENCODE(next);
+       ap->ua_prev_enc = UU_PTR_ENCODE(prev);
+       next->ua_prev_enc = UU_PTR_ENCODE(ap);
+       prev->ua_next_enc = UU_PTR_ENCODE(ap);
+       (void) pthread_mutex_unlock(&pp->uap_lock);
+
+       return (ap);
+}
+
+void
+uu_avl_destroy(uu_avl_t *ap)
+{
+       uu_avl_pool_t *pp = ap->ua_pool;
+
+       if (ap->ua_debug) {
+               if (avl_numnodes(&ap->ua_tree) != 0) {
+                       uu_panic("uu_avl_destroy(%p): tree not empty\n",
+                           (void *)ap);
+               }
+               if (ap->ua_null_walk.uaw_next != &ap->ua_null_walk ||
+                   ap->ua_null_walk.uaw_prev != &ap->ua_null_walk) {
+                       uu_panic("uu_avl_destroy(%p):  outstanding walkers\n",
+                           (void *)ap);
+               }
+       }
+       (void) pthread_mutex_lock(&pp->uap_lock);
+       UU_AVL_PTR(ap->ua_next_enc)->ua_prev_enc = ap->ua_prev_enc;
+       UU_AVL_PTR(ap->ua_prev_enc)->ua_next_enc = ap->ua_next_enc;
+       (void) pthread_mutex_unlock(&pp->uap_lock);
+       ap->ua_prev_enc = UU_PTR_ENCODE(NULL);
+       ap->ua_next_enc = UU_PTR_ENCODE(NULL);
+
+       ap->ua_pool = NULL;
+       avl_destroy(&ap->ua_tree);
+
+       uu_free(ap);
+}
+
+size_t
+uu_avl_numnodes(uu_avl_t *ap)
+{
+       return (avl_numnodes(&ap->ua_tree));
+}
+
+void *
+uu_avl_first(uu_avl_t *ap)
+{
+       return (avl_first(&ap->ua_tree));
+}
+
+void *
+uu_avl_last(uu_avl_t *ap)
+{
+       return (avl_last(&ap->ua_tree));
+}
+
+void *
+uu_avl_next(uu_avl_t *ap, void *node)
+{
+       return (AVL_NEXT(&ap->ua_tree, node));
+}
+
+void *
+uu_avl_prev(uu_avl_t *ap, void *node)
+{
+       return (AVL_PREV(&ap->ua_tree, node));
+}
+
+static void
+_avl_walk_init(uu_avl_walk_t *wp, uu_avl_t *ap, uint32_t flags)
+{
+       uu_avl_walk_t *next, *prev;
+
+       int robust = (flags & UU_WALK_ROBUST);
+       int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
+
+       (void) memset(wp, 0, sizeof (*wp));
+       wp->uaw_avl = ap;
+       wp->uaw_robust = robust;
+       wp->uaw_dir = direction;
+
+       if (direction > 0)
+               wp->uaw_next_result = avl_first(&ap->ua_tree);
+       else
+               wp->uaw_next_result = avl_last(&ap->ua_tree);
+
+       if (ap->ua_debug || robust) {
+               wp->uaw_next = next = &ap->ua_null_walk;
+               wp->uaw_prev = prev = next->uaw_prev;
+               next->uaw_prev = wp;
+               prev->uaw_next = wp;
+       }
+}
+
+static void *
+_avl_walk_advance(uu_avl_walk_t *wp, uu_avl_t *ap)
+{
+       void *np = wp->uaw_next_result;
+
+       avl_tree_t *t = &ap->ua_tree;
+
+       if (np == NULL)
+               return (NULL);
+
+       wp->uaw_next_result = (wp->uaw_dir > 0)? AVL_NEXT(t, np) :
+           AVL_PREV(t, np);
+
+       return (np);
+}
+
+static void
+_avl_walk_fini(uu_avl_walk_t *wp)
+{
+       if (wp->uaw_next != NULL) {
+               wp->uaw_next->uaw_prev = wp->uaw_prev;
+               wp->uaw_prev->uaw_next = wp->uaw_next;
+               wp->uaw_next = NULL;
+               wp->uaw_prev = NULL;
+       }
+       wp->uaw_avl = NULL;
+       wp->uaw_next_result = NULL;
+}
+
+uu_avl_walk_t *
+uu_avl_walk_start(uu_avl_t *ap, uint32_t flags)
+{
+       uu_avl_walk_t *wp;
+
+       if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (NULL);
+       }
+
+       wp = uu_zalloc(sizeof (*wp));
+       if (wp == NULL) {
+               uu_set_error(UU_ERROR_NO_MEMORY);
+               return (NULL);
+       }
+
+       _avl_walk_init(wp, ap, flags);
+       return (wp);
+}
+
+void *
+uu_avl_walk_next(uu_avl_walk_t *wp)
+{
+       return (_avl_walk_advance(wp, wp->uaw_avl));
+}
+
+void
+uu_avl_walk_end(uu_avl_walk_t *wp)
+{
+       _avl_walk_fini(wp);
+       uu_free(wp);
+}
+
+int
+uu_avl_walk(uu_avl_t *ap, uu_walk_fn_t *func, void *private, uint32_t flags)
+{
+       void *e;
+       uu_avl_walk_t my_walk;
+
+       int status = UU_WALK_NEXT;
+
+       if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (-1);
+       }
+
+       _avl_walk_init(&my_walk, ap, flags);
+       while (status == UU_WALK_NEXT &&
+           (e = _avl_walk_advance(&my_walk, ap)) != NULL)
+               status = (*func)(e, private);
+       _avl_walk_fini(&my_walk);
+
+       if (status >= 0)
+               return (0);
+       uu_set_error(UU_ERROR_CALLBACK_FAILED);
+       return (-1);
+}
+
+void
+uu_avl_remove(uu_avl_t *ap, void *elem)
+{
+       uu_avl_walk_t *wp;
+       uu_avl_pool_t *pp = ap->ua_pool;
+       uintptr_t *na = NODE_ARRAY(pp, elem);
+
+       if (ap->ua_debug) {
+               /*
+                * invalidate outstanding uu_avl_index_ts.
+                */
+               ap->ua_index = INDEX_NEXT(ap->ua_index);
+       }
+
+       /*
+        * Robust walkers most be advanced, if we are removing the node
+        * they are currently using.  In debug mode, non-robust walkers
+        * are also on the walker list.
+        */
+       for (wp = ap->ua_null_walk.uaw_next; wp != &ap->ua_null_walk;
+           wp = wp->uaw_next) {
+               if (wp->uaw_robust) {
+                       if (elem == wp->uaw_next_result)
+                               (void) _avl_walk_advance(wp, ap);
+               } else if (wp->uaw_next_result != NULL) {
+                       uu_panic("uu_avl_remove(%p, %p): active non-robust "
+                           "walker\n", (void *)ap, elem);
+               }
+       }
+
+       avl_remove(&ap->ua_tree, elem);
+
+       na[0] = POOL_TO_MARKER(pp);
+       na[1] = 0;
+}
+
+void *
+uu_avl_teardown(uu_avl_t *ap, void **cookie)
+{
+       void *elem = avl_destroy_nodes(&ap->ua_tree, cookie);
+
+       if (elem != NULL) {
+               uu_avl_pool_t *pp = ap->ua_pool;
+               uintptr_t *na = NODE_ARRAY(pp, elem);
+
+               na[0] = POOL_TO_MARKER(pp);
+               na[1] = 0;
+       }
+       return (elem);
+}
+
+void *
+uu_avl_find(uu_avl_t *ap, void *elem, void *private, uu_avl_index_t *out)
+{
+       struct uu_avl_node_compare_info info;
+       void *result;
+
+       info.ac_compare = ap->ua_pool->uap_cmp;
+       info.ac_private = private;
+       info.ac_right = elem;
+       info.ac_found = NULL;
+
+       result = avl_find(&ap->ua_tree, &info, out);
+       if (out != NULL)
+               *out = INDEX_ENCODE(ap, *out);
+
+       if (ap->ua_debug && result != NULL)
+               uu_panic("uu_avl_find: internal error: avl_find succeeded\n");
+
+       return (info.ac_found);
+}
+
+void
+uu_avl_insert(uu_avl_t *ap, void *elem, uu_avl_index_t idx)
+{
+       if (ap->ua_debug) {
+               uu_avl_pool_t *pp = ap->ua_pool;
+               uintptr_t *na = NODE_ARRAY(pp, elem);
+
+               if (na[1] != 0)
+                       uu_panic("uu_avl_insert(%p, %p, %p): node already "
+                           "in tree, or corrupt\n",
+                           (void *)ap, elem, (void *)idx);
+               if (na[0] == 0)
+                       uu_panic("uu_avl_insert(%p, %p, %p): node not "
+                           "initialized\n",
+                           (void *)ap, elem, (void *)idx);
+               if (na[0] != POOL_TO_MARKER(pp))
+                       uu_panic("uu_avl_insert(%p, %p, %p): node from "
+                           "other pool, or corrupt\n",
+                           (void *)ap, elem, (void *)idx);
+
+               if (!INDEX_VALID(ap, idx))
+                       uu_panic("uu_avl_insert(%p, %p, %p): %s\n",
+                           (void *)ap, elem, (void *)idx,
+                           INDEX_CHECK(idx)? "outdated index" :
+                           "invalid index");
+
+               /*
+                * invalidate outstanding uu_avl_index_ts.
+                */
+               ap->ua_index = INDEX_NEXT(ap->ua_index);
+       }
+       avl_insert(&ap->ua_tree, elem, INDEX_DECODE(idx));
+}
+
+void *
+uu_avl_nearest_next(uu_avl_t *ap, uu_avl_index_t idx)
+{
+       if (ap->ua_debug && !INDEX_VALID(ap, idx))
+               uu_panic("uu_avl_nearest_next(%p, %p): %s\n",
+                   (void *)ap, (void *)idx, INDEX_CHECK(idx)?
+                   "outdated index" : "invalid index");
+       return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_AFTER));
+}
+
+void *
+uu_avl_nearest_prev(uu_avl_t *ap, uu_avl_index_t idx)
+{
+       if (ap->ua_debug && !INDEX_VALID(ap, idx))
+               uu_panic("uu_avl_nearest_prev(%p, %p): %s\n",
+                   (void *)ap, (void *)idx, INDEX_CHECK(idx)?
+                   "outdated index" : "invalid index");
+       return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_BEFORE));
+}
+
+/*
+ * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
+ */
+void
+uu_avl_lockup(void)
+{
+       uu_avl_pool_t *pp;
+
+       (void) pthread_mutex_lock(&uu_apool_list_lock);
+       for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
+           pp = pp->uap_next)
+               (void) pthread_mutex_lock(&pp->uap_lock);
+}
+
+void
+uu_avl_release(void)
+{
+       uu_avl_pool_t *pp;
+
+       for (pp = uu_null_apool.uap_next; pp != &uu_null_apool;
+           pp = pp->uap_next)
+               (void) pthread_mutex_unlock(&pp->uap_lock);
+       (void) pthread_mutex_unlock(&uu_apool_list_lock);
+}
diff --git a/zfs/lib/libuutil/uu_dprintf.c b/zfs/lib/libuutil/uu_dprintf.c
new file mode 100644 (file)
index 0000000..5d5fb84
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+#include "libuutil_common.h"
+
+#include <errno.h>
+#include <libintl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#define        FACILITY_FMT    "%s (%s): "
+
+#if !defined(TEXT_DOMAIN)
+#define        TEXT_DOMAIN "SYS_TEST"
+#endif
+
+static const char *
+strseverity(uu_dprintf_severity_t severity)
+{
+       switch (severity) {
+       case UU_DPRINTF_SILENT:
+               return (dgettext(TEXT_DOMAIN, "silent"));
+       case UU_DPRINTF_FATAL:
+               return (dgettext(TEXT_DOMAIN, "FATAL"));
+       case UU_DPRINTF_WARNING:
+               return (dgettext(TEXT_DOMAIN, "WARNING"));
+       case UU_DPRINTF_NOTICE:
+               return (dgettext(TEXT_DOMAIN, "note"));
+       case UU_DPRINTF_INFO:
+               return (dgettext(TEXT_DOMAIN, "info"));
+       case UU_DPRINTF_DEBUG:
+               return (dgettext(TEXT_DOMAIN, "debug"));
+       default:
+               return (dgettext(TEXT_DOMAIN, "unspecified"));
+       }
+}
+
+uu_dprintf_t *
+uu_dprintf_create(const char *name, uu_dprintf_severity_t severity,
+    uint_t flags)
+{
+       uu_dprintf_t *D;
+
+       if (uu_check_name(name, UU_NAME_DOMAIN) == -1) {
+               uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+               return (NULL);
+       }
+
+       if ((D = uu_zalloc(sizeof (uu_dprintf_t))) == NULL)
+               return (NULL);
+
+       if (name != NULL) {
+               D->uud_name = strdup(name);
+               if (D->uud_name == NULL) {
+                       uu_free(D);
+                       return (NULL);
+               }
+       } else {
+               D->uud_name = NULL;
+       }
+
+       D->uud_severity = severity;
+       D->uud_flags = flags;
+
+       return (D);
+}
+
+/*PRINTFLIKE3*/
+void
+uu_dprintf(uu_dprintf_t *D, uu_dprintf_severity_t severity,
+    const char *format, ...)
+{
+       va_list alist;
+
+       /* XXX Assert that severity is not UU_DPRINTF_SILENT. */
+
+       if (severity > D->uud_severity)
+               return;
+
+       (void) fprintf(stderr, FACILITY_FMT, D->uud_name,
+           strseverity(severity));
+
+       va_start(alist, format);
+       (void) vfprintf(stderr, format, alist);
+       va_end(alist);
+}
+
+void
+uu_dprintf_destroy(uu_dprintf_t *D)
+{
+       if (D->uud_name)
+               free(D->uud_name);
+
+       uu_free(D);
+}
+
+const char *
+uu_dprintf_getname(uu_dprintf_t *D)
+{
+       return (D->uud_name);
+}
diff --git a/zfs/lib/libuutil/uu_ident.c b/zfs/lib/libuutil/uu_ident.c
new file mode 100644 (file)
index 0000000..3821393
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+#include "libuutil_common.h"
+
+#include <string.h>
+
+/*
+ * We require names of the form:
+ *     [provider,]identifier[/[provider,]identifier]...
+ *
+ * Where provider is either a stock symbol (SUNW) or a java-style reversed
+ * domain name (com.sun).
+ *
+ * Both providers and identifiers must start with a letter, and may
+ * only contain alphanumerics, dashes, and underlines.  Providers
+ * may also contain periods.
+ *
+ * Note that we do _not_ use the macros in <ctype.h>, since they are affected
+ * by the current locale settings.
+ */
+
+#define        IS_ALPHA(c) \
+       (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+
+#define        IS_DIGIT(c) \
+       ((c) >= '0' && (c) <= '9')
+
+static int
+is_valid_ident(const char *s, const char *e, int allowdot)
+{
+       char c;
+
+       if (s >= e)
+               return (0);             /* name is empty */
+
+       c = *s++;
+       if (!IS_ALPHA(c))
+               return (0);             /* does not start with letter */
+
+       while (s < e && (c = *s++) != 0) {
+               if (IS_ALPHA(c) || IS_DIGIT(c) || c == '-' || c == '_' ||
+                   (allowdot && c == '.'))
+                       continue;
+               return (0);             /* invalid character */
+       }
+       return (1);
+}
+
+static int
+is_valid_component(const char *b, const char *e, uint_t flags)
+{
+       char *sp;
+
+       if (flags & UU_NAME_DOMAIN) {
+               sp = strchr(b, ',');
+               if (sp != NULL && sp < e) {
+                       if (!is_valid_ident(b, sp, 1))
+                               return (0);
+                       b = sp + 1;
+               }
+       }
+
+       return (is_valid_ident(b, e, 0));
+}
+
+int
+uu_check_name(const char *name, uint_t flags)
+{
+       const char *end = name + strlen(name);
+       const char *p;
+
+       if (flags & ~(UU_NAME_DOMAIN | UU_NAME_PATH)) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (-1);
+       }
+
+       if (!(flags & UU_NAME_PATH)) {
+               if (!is_valid_component(name, end, flags))
+                       goto bad;
+               return (0);
+       }
+
+       while ((p = strchr(name, '/')) != NULL) {
+               if (!is_valid_component(name, p - 1, flags))
+                       goto bad;
+               name = p + 1;
+       }
+       if (!is_valid_component(name, end, flags))
+               goto bad;
+
+       return (0);
+
+bad:
+       uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+       return (-1);
+}
diff --git a/zfs/lib/libuutil/uu_list.c b/zfs/lib/libuutil/uu_list.c
new file mode 100644 (file)
index 0000000..c3a447d
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * 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.
+ */
+
+
+
+#include "libuutil_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#define        ELEM_TO_NODE(lp, e) \
+       ((uu_list_node_impl_t *)((uintptr_t)(e) + (lp)->ul_offset))
+
+#define        NODE_TO_ELEM(lp, n) \
+       ((void *)((uintptr_t)(n) - (lp)->ul_offset))
+
+/*
+ * uu_list_index_ts define a location for insertion.  They are simply a
+ * pointer to the object after the insertion point.  We store a mark
+ * in the low-bits of the index, to help prevent mistakes.
+ *
+ * When debugging, the index mark changes on every insert and delete, to
+ * catch stale references.
+ */
+#define        INDEX_MAX               (sizeof (uintptr_t) - 1)
+#define        INDEX_NEXT(m)           (((m) == INDEX_MAX)? 1 : ((m) + 1) & INDEX_MAX)
+
+#define        INDEX_TO_NODE(i)        ((uu_list_node_impl_t *)((i) & ~INDEX_MAX))
+#define        NODE_TO_INDEX(p, n)     (((uintptr_t)(n) & ~INDEX_MAX) | (p)->ul_index)
+#define        INDEX_VALID(p, i)       (((i) & INDEX_MAX) == (p)->ul_index)
+#define        INDEX_CHECK(i)          (((i) & INDEX_MAX) != 0)
+
+#define        POOL_TO_MARKER(pp) ((void *)((uintptr_t)(pp) | 1))
+
+static uu_list_pool_t  uu_null_lpool = { &uu_null_lpool, &uu_null_lpool };
+static pthread_mutex_t uu_lpool_list_lock = PTHREAD_MUTEX_INITIALIZER;
+
+uu_list_pool_t *
+uu_list_pool_create(const char *name, size_t objsize,
+    size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags)
+{
+       uu_list_pool_t *pp, *next, *prev;
+
+       if (name == NULL ||
+           uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
+           nodeoffset + sizeof (uu_list_node_t) > objsize) {
+               uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+               return (NULL);
+       }
+
+       if (flags & ~UU_LIST_POOL_DEBUG) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (NULL);
+       }
+
+       pp = uu_zalloc(sizeof (uu_list_pool_t));
+       if (pp == NULL) {
+               uu_set_error(UU_ERROR_NO_MEMORY);
+               return (NULL);
+       }
+
+       (void) strlcpy(pp->ulp_name, name, sizeof (pp->ulp_name));
+       pp->ulp_nodeoffset = nodeoffset;
+       pp->ulp_objsize = objsize;
+       pp->ulp_cmp = compare_func;
+       if (flags & UU_LIST_POOL_DEBUG)
+               pp->ulp_debug = 1;
+       pp->ulp_last_index = 0;
+
+       (void) pthread_mutex_init(&pp->ulp_lock, NULL);
+
+       pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
+       pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
+
+       (void) pthread_mutex_lock(&uu_lpool_list_lock);
+       pp->ulp_next = next = &uu_null_lpool;
+       pp->ulp_prev = prev = next->ulp_prev;
+       next->ulp_prev = pp;
+       prev->ulp_next = pp;
+       (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+
+       return (pp);
+}
+
+void
+uu_list_pool_destroy(uu_list_pool_t *pp)
+{
+       if (pp->ulp_debug) {
+               if (pp->ulp_null_list.ul_next_enc !=
+                   UU_PTR_ENCODE(&pp->ulp_null_list) ||
+                   pp->ulp_null_list.ul_prev_enc !=
+                   UU_PTR_ENCODE(&pp->ulp_null_list)) {
+                       uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
+                           "outstanding lists, or is corrupt.\n",
+                           (int)sizeof (pp->ulp_name), pp->ulp_name,
+                           (void *)pp);
+               }
+       }
+       (void) pthread_mutex_lock(&uu_lpool_list_lock);
+       pp->ulp_next->ulp_prev = pp->ulp_prev;
+       pp->ulp_prev->ulp_next = pp->ulp_next;
+       (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+       pp->ulp_prev = NULL;
+       pp->ulp_next = NULL;
+       uu_free(pp);
+}
+
+void
+uu_list_node_init(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
+{
+       uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
+
+       if (pp->ulp_debug) {
+               uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
+               if (offset + sizeof (*np) > pp->ulp_objsize) {
+                       uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
+                           "offset %ld doesn't fit in object (size %ld)\n",
+                           base, (void *)np, (void *)pp, pp->ulp_name,
+                           (long)offset, (long)pp->ulp_objsize);
+               }
+               if (offset != pp->ulp_nodeoffset) {
+                       uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
+                           "offset %ld doesn't match pool's offset (%ld)\n",
+                           base, (void *)np, (void *)pp, pp->ulp_name,
+                           (long)offset, (long)pp->ulp_objsize);
+               }
+       }
+       np->uln_next = POOL_TO_MARKER(pp);
+       np->uln_prev = NULL;
+}
+
+void
+uu_list_node_fini(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
+{
+       uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
+
+       if (pp->ulp_debug) {
+               if (np->uln_next == NULL &&
+                   np->uln_prev == NULL) {
+                       uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
+                           "node already finied\n",
+                           base, (void *)np_arg, (void *)pp, pp->ulp_name);
+               }
+               if (np->uln_next != POOL_TO_MARKER(pp) ||
+                   np->uln_prev != NULL) {
+                       uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
+                           "node corrupt or on list\n",
+                           base, (void *)np_arg, (void *)pp, pp->ulp_name);
+               }
+       }
+       np->uln_next = NULL;
+       np->uln_prev = NULL;
+}
+
+uu_list_t *
+uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
+{
+       uu_list_t *lp, *next, *prev;
+
+       if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (NULL);
+       }
+
+       if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) {
+               if (pp->ulp_debug)
+                       uu_panic("uu_list_create(%p, ...): requested "
+                           "UU_LIST_SORTED, but pool has no comparison func\n",
+                           (void *)pp);
+               uu_set_error(UU_ERROR_NOT_SUPPORTED);
+               return (NULL);
+       }
+
+       lp = uu_zalloc(sizeof (*lp));
+       if (lp == NULL) {
+               uu_set_error(UU_ERROR_NO_MEMORY);
+               return (NULL);
+       }
+
+       lp->ul_pool = pp;
+       lp->ul_parent_enc = UU_PTR_ENCODE(parent);
+       lp->ul_offset = pp->ulp_nodeoffset;
+       lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
+       lp->ul_sorted = (flags & UU_LIST_SORTED);
+       lp->ul_numnodes = 0;
+       lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index));
+
+       lp->ul_null_node.uln_next = &lp->ul_null_node;
+       lp->ul_null_node.uln_prev = &lp->ul_null_node;
+
+       lp->ul_null_walk.ulw_next = &lp->ul_null_walk;
+       lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
+
+       (void) pthread_mutex_lock(&pp->ulp_lock);
+       next = &pp->ulp_null_list;
+       prev = UU_PTR_DECODE(next->ul_prev_enc);
+       lp->ul_next_enc = UU_PTR_ENCODE(next);
+       lp->ul_prev_enc = UU_PTR_ENCODE(prev);
+       next->ul_prev_enc = UU_PTR_ENCODE(lp);
+       prev->ul_next_enc = UU_PTR_ENCODE(lp);
+       (void) pthread_mutex_unlock(&pp->ulp_lock);
+
+       return (lp);
+}
+
+void
+uu_list_destroy(uu_list_t *lp)
+{
+       uu_list_pool_t *pp = lp->ul_pool;
+
+       if (lp->ul_debug) {
+               if (lp->ul_null_node.uln_next != &lp->ul_null_node ||
+                   lp->ul_null_node.uln_prev != &lp->ul_null_node) {
+                       uu_panic("uu_list_destroy(%p):  list not empty\n",
+                           (void *)lp);
+               }
+               if (lp->ul_numnodes != 0) {
+                       uu_panic("uu_list_destroy(%p):  numnodes is nonzero, "
+                           "but list is empty\n", (void *)lp);
+               }
+               if (lp->ul_null_walk.ulw_next != &lp->ul_null_walk ||
+                   lp->ul_null_walk.ulw_prev != &lp->ul_null_walk) {
+                       uu_panic("uu_list_destroy(%p):  outstanding walkers\n",
+                           (void *)lp);
+               }
+       }
+
+       (void) pthread_mutex_lock(&pp->ulp_lock);
+       UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc;
+       UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc;
+       (void) pthread_mutex_unlock(&pp->ulp_lock);
+       lp->ul_prev_enc = UU_PTR_ENCODE(NULL);
+       lp->ul_next_enc = UU_PTR_ENCODE(NULL);
+       lp->ul_pool = NULL;
+       uu_free(lp);
+}
+
+static void
+list_insert(uu_list_t *lp, uu_list_node_impl_t *np, uu_list_node_impl_t *prev,
+    uu_list_node_impl_t *next)
+{
+       if (lp->ul_debug) {
+               if (next->uln_prev != prev || prev->uln_next != next)
+                       uu_panic("insert(%p): internal error: %p and %p not "
+                           "neighbors\n", (void *)lp, (void *)next,
+                           (void *)prev);
+
+               if (np->uln_next != POOL_TO_MARKER(lp->ul_pool) ||
+                   np->uln_prev != NULL) {
+                       uu_panic("insert(%p): elem %p node %p corrupt, "
+                           "not initialized, or already in a list.\n",
+                           (void *)lp, NODE_TO_ELEM(lp, np), (void *)np);
+               }
+               /*
+                * invalidate outstanding uu_list_index_ts.
+                */
+               lp->ul_index = INDEX_NEXT(lp->ul_index);
+       }
+       np->uln_next = next;
+       np->uln_prev = prev;
+       next->uln_prev = np;
+       prev->uln_next = np;
+
+       lp->ul_numnodes++;
+}
+
+void
+uu_list_insert(uu_list_t *lp, void *elem, uu_list_index_t idx)
+{
+       uu_list_node_impl_t *np;
+
+       np = INDEX_TO_NODE(idx);
+       if (np == NULL)
+               np = &lp->ul_null_node;
+
+       if (lp->ul_debug) {
+               if (!INDEX_VALID(lp, idx))
+                       uu_panic("uu_list_insert(%p, %p, %p): %s\n",
+                           (void *)lp, elem, (void *)idx,
+                           INDEX_CHECK(idx)? "outdated index" :
+                           "invalid index");
+               if (np->uln_prev == NULL)
+                       uu_panic("uu_list_insert(%p, %p, %p): out-of-date "
+                           "index\n", (void *)lp, elem, (void *)idx);
+       }
+
+       list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
+}
+
+void *
+uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out)
+{
+       int sorted = lp->ul_sorted;
+       uu_compare_fn_t *func = lp->ul_pool->ulp_cmp;
+       uu_list_node_impl_t *np;
+
+       if (func == NULL) {
+               if (out != NULL)
+                       *out = 0;
+               uu_set_error(UU_ERROR_NOT_SUPPORTED);
+               return (NULL);
+       }
+       for (np = lp->ul_null_node.uln_next; np != &lp->ul_null_node;
+           np = np->uln_next) {
+               void *ep = NODE_TO_ELEM(lp, np);
+               int cmp = func(ep, elem, private);
+               if (cmp == 0) {
+                       if (out != NULL)
+                               *out = NODE_TO_INDEX(lp, np);
+                       return (ep);
+               }
+               if (sorted && cmp > 0) {
+                       if (out != NULL)
+                               *out = NODE_TO_INDEX(lp, np);
+                       return (NULL);
+               }
+       }
+       if (out != NULL)
+               *out = NODE_TO_INDEX(lp, 0);
+       return (NULL);
+}
+
+void *
+uu_list_nearest_next(uu_list_t *lp, uu_list_index_t idx)
+{
+       uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
+
+       if (np == NULL)
+               np = &lp->ul_null_node;
+
+       if (lp->ul_debug) {
+               if (!INDEX_VALID(lp, idx))
+                       uu_panic("uu_list_nearest_next(%p, %p): %s\n",
+                           (void *)lp, (void *)idx,
+                           INDEX_CHECK(idx)? "outdated index" :
+                           "invalid index");
+               if (np->uln_prev == NULL)
+                       uu_panic("uu_list_nearest_next(%p, %p): out-of-date "
+                           "index\n", (void *)lp, (void *)idx);
+       }
+
+       if (np == &lp->ul_null_node)
+               return (NULL);
+       else
+               return (NODE_TO_ELEM(lp, np));
+}
+
+void *
+uu_list_nearest_prev(uu_list_t *lp, uu_list_index_t idx)
+{
+       uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
+
+       if (np == NULL)
+               np = &lp->ul_null_node;
+
+       if (lp->ul_debug) {
+               if (!INDEX_VALID(lp, idx))
+                       uu_panic("uu_list_nearest_prev(%p, %p): %s\n",
+                           (void *)lp, (void *)idx, INDEX_CHECK(idx)?
+                           "outdated index" : "invalid index");
+               if (np->uln_prev == NULL)
+                       uu_panic("uu_list_nearest_prev(%p, %p): out-of-date "
+                           "index\n", (void *)lp, (void *)idx);
+       }
+
+       if ((np = np->uln_prev) == &lp->ul_null_node)
+               return (NULL);
+       else
+               return (NODE_TO_ELEM(lp, np));
+}
+
+static void
+list_walk_init(uu_list_walk_t *wp, uu_list_t *lp, uint32_t flags)
+{
+       uu_list_walk_t *next, *prev;
+
+       int robust = (flags & UU_WALK_ROBUST);
+       int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
+
+       (void) memset(wp, 0, sizeof (*wp));
+       wp->ulw_list = lp;
+       wp->ulw_robust = robust;
+       wp->ulw_dir = direction;
+       if (direction > 0)
+               wp->ulw_next_result = lp->ul_null_node.uln_next;
+       else
+               wp->ulw_next_result = lp->ul_null_node.uln_prev;
+
+       if (lp->ul_debug || robust) {
+               /*
+                * Add this walker to the list's list of walkers so
+                * uu_list_remove() can advance us if somebody tries to
+                * remove ulw_next_result.
+                */
+               wp->ulw_next = next = &lp->ul_null_walk;
+               wp->ulw_prev = prev = next->ulw_prev;
+               next->ulw_prev = wp;
+               prev->ulw_next = wp;
+       }
+}
+
+static uu_list_node_impl_t *
+list_walk_advance(uu_list_walk_t *wp, uu_list_t *lp)
+{
+       uu_list_node_impl_t *np = wp->ulw_next_result;
+       uu_list_node_impl_t *next;
+
+       if (np == &lp->ul_null_node)
+               return (NULL);
+
+       next = (wp->ulw_dir > 0)? np->uln_next : np->uln_prev;
+
+       wp->ulw_next_result = next;
+       return (np);
+}
+
+static void
+list_walk_fini(uu_list_walk_t *wp)
+{
+       /* GLXXX debugging? */
+       if (wp->ulw_next != NULL) {
+               wp->ulw_next->ulw_prev = wp->ulw_prev;
+               wp->ulw_prev->ulw_next = wp->ulw_next;
+               wp->ulw_next = NULL;
+               wp->ulw_prev = NULL;
+       }
+       wp->ulw_list = NULL;
+       wp->ulw_next_result = NULL;
+}
+
+uu_list_walk_t *
+uu_list_walk_start(uu_list_t *lp, uint32_t flags)
+{
+       uu_list_walk_t *wp;
+
+       if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (NULL);
+       }
+
+       wp = uu_zalloc(sizeof (*wp));
+       if (wp == NULL) {
+               uu_set_error(UU_ERROR_NO_MEMORY);
+               return (NULL);
+       }
+
+       list_walk_init(wp, lp, flags);
+       return (wp);
+}
+
+void *
+uu_list_walk_next(uu_list_walk_t *wp)
+{
+       uu_list_t *lp = wp->ulw_list;
+       uu_list_node_impl_t *np = list_walk_advance(wp, lp);
+
+       if (np == NULL)
+               return (NULL);
+
+       return (NODE_TO_ELEM(lp, np));
+}
+
+void
+uu_list_walk_end(uu_list_walk_t *wp)
+{
+       list_walk_fini(wp);
+       uu_free(wp);
+}
+
+int
+uu_list_walk(uu_list_t *lp, uu_walk_fn_t *func, void *private, uint32_t flags)
+{
+       uu_list_node_impl_t *np;
+
+       int status = UU_WALK_NEXT;
+
+       int robust = (flags & UU_WALK_ROBUST);
+       int reverse = (flags & UU_WALK_REVERSE);
+
+       if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
+               uu_set_error(UU_ERROR_UNKNOWN_FLAG);
+               return (-1);
+       }
+
+       if (lp->ul_debug || robust) {
+               uu_list_walk_t my_walk;
+               void *e;
+
+               list_walk_init(&my_walk, lp, flags);
+               while (status == UU_WALK_NEXT &&
+                   (e = uu_list_walk_next(&my_walk)) != NULL)
+                       status = (*func)(e, private);
+               list_walk_fini(&my_walk);
+       } else {
+               if (!reverse) {
+                       for (np = lp->ul_null_node.uln_next;
+                           status == UU_WALK_NEXT && np != &lp->ul_null_node;
+                           np = np->uln_next) {
+                               status = (*func)(NODE_TO_ELEM(lp, np), private);
+                       }
+               } else {
+                       for (np = lp->ul_null_node.uln_prev;
+                           status == UU_WALK_NEXT && np != &lp->ul_null_node;
+                           np = np->uln_prev) {
+                               status = (*func)(NODE_TO_ELEM(lp, np), private);
+                       }
+               }
+       }
+       if (status >= 0)
+               return (0);
+       uu_set_error(UU_ERROR_CALLBACK_FAILED);
+       return (-1);
+}
+
+void
+uu_list_remove(uu_list_t *lp, void *elem)
+{
+       uu_list_node_impl_t *np = ELEM_TO_NODE(lp, elem);
+       uu_list_walk_t *wp;
+
+       if (lp->ul_debug) {
+               if (np->uln_prev == NULL)
+                       uu_panic("uu_list_remove(%p, %p): elem not on list\n",
+                           (void *)lp, elem);
+               /*
+                * invalidate outstanding uu_list_index_ts.
+                */
+               lp->ul_index = INDEX_NEXT(lp->ul_index);
+       }
+
+       /*
+        * robust walkers must be advanced.  In debug mode, non-robust
+        * walkers are also on the list.  If there are any, it's an error.
+        */
+       for (wp = lp->ul_null_walk.ulw_next; wp != &lp->ul_null_walk;
+           wp = wp->ulw_next) {
+               if (wp->ulw_robust) {
+                       if (np == wp->ulw_next_result)
+                               (void) list_walk_advance(wp, lp);
+               } else if (wp->ulw_next_result != NULL) {
+                       uu_panic("uu_list_remove(%p, %p): active non-robust "
+                           "walker\n", (void *)lp, elem);
+               }
+       }
+
+       np->uln_next->uln_prev = np->uln_prev;
+       np->uln_prev->uln_next = np->uln_next;
+
+       lp->ul_numnodes--;
+
+       np->uln_next = POOL_TO_MARKER(lp->ul_pool);
+       np->uln_prev = NULL;
+}
+
+void *
+uu_list_teardown(uu_list_t *lp, void **cookie)
+{
+       void *ep;
+
+       /*
+        * XXX: disable list modification until list is empty
+        */
+       if (lp->ul_debug && *cookie != NULL)
+               uu_panic("uu_list_teardown(%p, %p): unexpected cookie\n",
+                   (void *)lp, (void *)cookie);
+
+       ep = uu_list_first(lp);
+       if (ep)
+               uu_list_remove(lp, ep);
+       return (ep);
+}
+
+int
+uu_list_insert_before(uu_list_t *lp, void *target, void *elem)
+{
+       uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
+
+       if (target == NULL)
+               np = &lp->ul_null_node;
+
+       if (lp->ul_debug) {
+               if (np->uln_prev == NULL)
+                       uu_panic("uu_list_insert_before(%p, %p, %p): %p is "
+                           "not currently on a list\n",
+                           (void *)lp, target, elem, target);
+       }
+       if (lp->ul_sorted) {
+               if (lp->ul_debug)
+                       uu_panic("uu_list_insert_before(%p, ...): list is "
+                           "UU_LIST_SORTED\n", (void *)lp);
+               uu_set_error(UU_ERROR_NOT_SUPPORTED);
+               return (-1);
+       }
+
+       list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
+       return (0);
+}
+
+int
+uu_list_insert_after(uu_list_t *lp, void *target, void *elem)
+{
+       uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
+
+       if (target == NULL)
+               np = &lp->ul_null_node;
+
+       if (lp->ul_debug) {
+               if (np->uln_prev == NULL)
+                       uu_panic("uu_list_insert_after(%p, %p, %p): %p is "
+                           "not currently on a list\n",
+                           (void *)lp, target, elem, target);
+       }
+       if (lp->ul_sorted) {
+               if (lp->ul_debug)
+                       uu_panic("uu_list_insert_after(%p, ...): list is "
+                           "UU_LIST_SORTED\n", (void *)lp);
+               uu_set_error(UU_ERROR_NOT_SUPPORTED);
+               return (-1);
+       }
+
+       list_insert(lp, ELEM_TO_NODE(lp, elem), np, np->uln_next);
+       return (0);
+}
+
+size_t
+uu_list_numnodes(uu_list_t *lp)
+{
+       return (lp->ul_numnodes);
+}
+
+void *
+uu_list_first(uu_list_t *lp)
+{
+       uu_list_node_impl_t *n = lp->ul_null_node.uln_next;
+       if (n == &lp->ul_null_node)
+               return (NULL);
+       return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_last(uu_list_t *lp)
+{
+       uu_list_node_impl_t *n = lp->ul_null_node.uln_prev;
+       if (n == &lp->ul_null_node)
+               return (NULL);
+       return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_next(uu_list_t *lp, void *elem)
+{
+       uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
+
+       n = n->uln_next;
+       if (n == &lp->ul_null_node)
+               return (NULL);
+       return (NODE_TO_ELEM(lp, n));
+}
+
+void *
+uu_list_prev(uu_list_t *lp, void *elem)
+{
+       uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
+
+       n = n->uln_prev;
+       if (n == &lp->ul_null_node)
+               return (NULL);
+       return (NODE_TO_ELEM(lp, n));
+}
+
+/*
+ * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
+ */
+void
+uu_list_lockup(void)
+{
+       uu_list_pool_t *pp;
+
+       (void) pthread_mutex_lock(&uu_lpool_list_lock);
+       for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
+           pp = pp->ulp_next)
+               (void) pthread_mutex_lock(&pp->ulp_lock);
+}
+
+void
+uu_list_release(void)
+{
+       uu_list_pool_t *pp;
+
+       for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
+           pp = pp->ulp_next)
+               (void) pthread_mutex_unlock(&pp->ulp_lock);
+       (void) pthread_mutex_unlock(&uu_lpool_list_lock);
+}
diff --git a/zfs/lib/libuutil/uu_misc.c b/zfs/lib/libuutil/uu_misc.c
new file mode 100644 (file)
index 0000000..b10afd8
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * 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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "libuutil_common.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <libintl.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/debug.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#if !defined(TEXT_DOMAIN)
+#define        TEXT_DOMAIN "SYS_TEST"
+#endif
+
+/*
+ * All of the old code under !defined(PTHREAD_ONCE_KEY_NP)
+ * is here to enable the building of a native version of
+ * libuutil.so when the build machine has not yet been upgraded
+ * to a version of libc that provides pthread_key_create_once_np().
+ * It should all be deleted when solaris_nevada ships.
+ * The code is not MT-safe in a relaxed memory model.
+ */
+
+#if defined(PTHREAD_ONCE_KEY_NP)
+static pthread_key_t   uu_error_key = PTHREAD_ONCE_KEY_NP;
+#else  /* PTHREAD_ONCE_KEY_NP */
+static pthread_key_t   uu_error_key = 0;
+static pthread_mutex_t uu_key_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif /* PTHREAD_ONCE_KEY_NP */
+
+static int             uu_error_key_setup = 0;
+
+static pthread_mutex_t uu_panic_lock = PTHREAD_MUTEX_INITIALIZER;
+/* LINTED static unused */
+static const char      *uu_panic_format;
+/* LINTED static unused */
+static va_list         uu_panic_args;
+static pthread_t       uu_panic_thread;
+
+static uint32_t                _uu_main_error;
+static __thread int    _uu_main_thread = 0;
+
+void
+uu_set_error(uint_t code)
+{
+       if (_uu_main_thread) {
+               _uu_main_error = code;
+               return;
+       }
+#if defined(PTHREAD_ONCE_KEY_NP)
+       if (pthread_key_create_once_np(&uu_error_key, NULL) != 0)
+               uu_error_key_setup = -1;
+       else
+               uu_error_key_setup = 1;
+#else  /* PTHREAD_ONCE_KEY_NP */
+       if (uu_error_key_setup == 0) {
+               (void) pthread_mutex_lock(&uu_key_lock);
+               if (uu_error_key_setup == 0) {
+                       if (pthread_key_create(&uu_error_key, NULL) != 0)
+                               uu_error_key_setup = -1;
+                       else
+                               uu_error_key_setup = 1;
+               }
+               (void) pthread_mutex_unlock(&uu_key_lock);
+       }
+#endif /* PTHREAD_ONCE_KEY_NP */
+       if (uu_error_key_setup > 0)
+               (void) pthread_setspecific(uu_error_key,
+                   (void *)(uintptr_t)code);
+}
+
+uint32_t
+uu_error(void)
+{
+       if (_uu_main_thread)
+               return (_uu_main_error);
+
+       if (uu_error_key_setup < 0)     /* can't happen? */
+               return (UU_ERROR_UNKNOWN);
+
+       /*
+        * Because UU_ERROR_NONE == 0, if uu_set_error() was
+        * never called, then this will return UU_ERROR_NONE:
+        */
+       return ((uint32_t)(uintptr_t)pthread_getspecific(uu_error_key));
+}
+
+const char *
+uu_strerror(uint32_t code)
+{
+       const char *str;
+
+       switch (code) {
+       case UU_ERROR_NONE:
+               str = dgettext(TEXT_DOMAIN, "No error");
+               break;
+
+       case UU_ERROR_INVALID_ARGUMENT:
+               str = dgettext(TEXT_DOMAIN, "Invalid argument");
+               break;
+
+       case UU_ERROR_UNKNOWN_FLAG:
+               str = dgettext(TEXT_DOMAIN, "Unknown flag passed");
+               break;
+
+       case UU_ERROR_NO_MEMORY:
+               str = dgettext(TEXT_DOMAIN, "Out of memory");
+               break;
+
+       case UU_ERROR_CALLBACK_FAILED:
+               str = dgettext(TEXT_DOMAIN, "Callback-initiated failure");
+               break;
+
+       case UU_ERROR_NOT_SUPPORTED:
+               str = dgettext(TEXT_DOMAIN, "Operation not supported");
+               break;
+
+       case UU_ERROR_EMPTY:
+               str = dgettext(TEXT_DOMAIN, "No value provided");
+               break;
+
+       case UU_ERROR_UNDERFLOW:
+               str = dgettext(TEXT_DOMAIN, "Value too small");
+               break;
+
+       case UU_ERROR_OVERFLOW:
+               str = dgettext(TEXT_DOMAIN, "Value too large");
+               break;
+
+       case UU_ERROR_INVALID_CHAR:
+               str = dgettext(TEXT_DOMAIN,
+                   "Value contains unexpected character");
+               break;
+
+       case UU_ERROR_INVALID_DIGIT:
+               str = dgettext(TEXT_DOMAIN,
+                   "Value contains digit not in base");
+               break;
+
+       case UU_ERROR_SYSTEM:
+               str = dgettext(TEXT_DOMAIN, "Underlying system error");
+               break;
+
+       case UU_ERROR_UNKNOWN:
+               str = dgettext(TEXT_DOMAIN, "Error status not known");
+               break;
+
+       default:
+               errno = ESRCH;
+               str = NULL;
+               break;
+       }
+       return (str);
+}
+
+void
+uu_panic(const char *format, ...)
+{
+       va_list args;
+
+       va_start(args, format);
+
+       (void) pthread_mutex_lock(&uu_panic_lock);
+       if (uu_panic_thread == 0) {
+               uu_panic_thread = pthread_self();
+               uu_panic_format = format;
+               va_copy(uu_panic_args, args);
+       }
+       (void) pthread_mutex_unlock(&uu_panic_lock);
+
+       (void) vfprintf(stderr, format, args);
+
+       va_end(args);
+
+       if (uu_panic_thread == pthread_self())
+               abort();
+       else
+               for (;;)
+                       (void) pause();
+}
+
+static void
+uu_lockup(void)
+{
+       (void) pthread_mutex_lock(&uu_panic_lock);
+#if !defined(PTHREAD_ONCE_KEY_NP)
+       (void) pthread_mutex_lock(&uu_key_lock);
+#endif
+       uu_avl_lockup();
+       uu_list_lockup();
+}
+
+static void
+uu_release(void)
+{
+       (void) pthread_mutex_unlock(&uu_panic_lock);
+#if !defined(PTHREAD_ONCE_KEY_NP)
+       (void) pthread_mutex_unlock(&uu_key_lock);
+#endif
+       uu_avl_release();
+       uu_list_release();
+}
+
+static void
+uu_release_child(void)
+{
+       uu_panic_format = NULL;
+       uu_panic_thread = 0;
+
+       uu_release();
+}
+
+#ifdef __GNUC__
+static void
+uu_init(void) __attribute__((constructor));
+#else
+#pragma init(uu_init)
+#endif
+
+static void
+uu_init(void)
+{
+       _uu_main_thread = 1;
+       (void) pthread_atfork(uu_lockup, uu_release, uu_release_child);
+}
+
+/*
+ * Dump a block of memory in hex+ascii, for debugging
+ */
+void
+uu_dump(FILE *out, const char *prefix, const void *buf, size_t len)
+{
+       const unsigned char *p = buf;
+       int i;
+
+       for (i = 0; i < len; i += 16) {
+               int j;
+
+               (void) fprintf(out, "%s", prefix);
+               for (j = 0; j < 16 && i + j < len; j++) {
+                       (void) fprintf(out, "%2.2x ", p[i + j]);
+               }
+               for (; j < 16; j++) {
+                       (void) fprintf(out, "   ");
+               }
+               for (j = 0; j < 16 && i + j < len; j++) {
+                       (void) fprintf(out, "%c",
+                           isprint(p[i + j]) ? p[i + j] : '.');
+               }
+               (void) fprintf(out, "\n");
+       }
+}
diff --git a/zfs/lib/libuutil/uu_open.c b/zfs/lib/libuutil/uu_open.c
new file mode 100644 (file)
index 0000000..cf5c545
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+#include "libuutil_common.h"
+
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef _LP64
+#define        TMPPATHFMT      "%s/uu%ld"
+#else /* _LP64 */
+#define        TMPPATHFMT      "%s/uu%lld"
+#endif /* _LP64 */
+
+/*ARGSUSED*/
+int
+uu_open_tmp(const char *dir, uint_t uflags)
+{
+       int f;
+       char *fname = uu_zalloc(PATH_MAX);
+
+       if (fname == NULL)
+               return (-1);
+
+       for (;;) {
+               (void) snprintf(fname, PATH_MAX, "%s/uu%lld", dir, gethrtime());
+
+               f = open(fname, O_CREAT | O_EXCL | O_RDWR, 0600);
+
+               if (f >= 0 || errno != EEXIST)
+                       break;
+       }
+
+       if (f >= 0)
+               (void) unlink(fname);
+
+       uu_free(fname);
+
+       return (f);
+}
diff --git a/zfs/lib/libuutil/uu_pname.c b/zfs/lib/libuutil/uu_pname.c
new file mode 100644 (file)
index 0000000..a6a0f22
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * 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 "libuutil_common.h"
+
+#include <libintl.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <wchar.h>
+#include <unistd.h>
+
+static const char PNAME_FMT[] = "%s: ";
+static const char ERRNO_FMT[] = ": %s\n";
+
+static const char *pname;
+
+static void
+uu_die_internal(int status, const char *format, va_list alist) __NORETURN;
+
+int uu_exit_ok_value = EXIT_SUCCESS;
+int uu_exit_fatal_value = EXIT_FAILURE;
+int uu_exit_usage_value = 2;
+
+int *
+uu_exit_ok(void)
+{
+       return (&uu_exit_ok_value);
+}
+
+int *
+uu_exit_fatal(void)
+{
+       return (&uu_exit_fatal_value);
+}
+
+int *
+uu_exit_usage(void)
+{
+       return (&uu_exit_usage_value);
+}
+
+void
+uu_alt_exit(int profile)
+{
+       switch (profile) {
+       case UU_PROFILE_DEFAULT:
+               uu_exit_ok_value = EXIT_SUCCESS;
+               uu_exit_fatal_value = EXIT_FAILURE;
+               uu_exit_usage_value = 2;
+               break;
+       case UU_PROFILE_LAUNCHER:
+               uu_exit_ok_value = EXIT_SUCCESS;
+               uu_exit_fatal_value = 124;
+               uu_exit_usage_value = 125;
+               break;
+       }
+}
+
+static void
+uu_warn_internal(int err, const char *format, va_list alist)
+{
+       if (pname != NULL)
+               (void) fprintf(stderr, PNAME_FMT, pname);
+
+       (void) vfprintf(stderr, format, alist);
+
+       if (strrchr(format, '\n') == NULL)
+               (void) fprintf(stderr, ERRNO_FMT, strerror(err));
+}
+
+void
+uu_vwarn(const char *format, va_list alist)
+{
+       uu_warn_internal(errno, format, alist);
+}
+
+/*PRINTFLIKE1*/
+void
+uu_warn(const char *format, ...)
+{
+       va_list alist;
+       va_start(alist, format);
+       uu_warn_internal(errno, format, alist);
+       va_end(alist);
+}
+
+static void
+uu_die_internal(int status, const char *format, va_list alist)
+{
+       uu_warn_internal(errno, format, alist);
+#ifdef DEBUG
+       {
+               char *cp;
+
+               if (!issetugid()) {
+                       cp = getenv("UU_DIE_ABORTS");
+                       if (cp != NULL && *cp != '\0')
+                               abort();
+               }
+       }
+#endif
+       exit(status);
+}
+
+void
+uu_vdie(const char *format, va_list alist)
+{
+       uu_die_internal(UU_EXIT_FATAL, format, alist);
+}
+
+/*PRINTFLIKE1*/
+void
+uu_die(const char *format, ...)
+{
+       va_list alist;
+       va_start(alist, format);
+       uu_die_internal(UU_EXIT_FATAL, format, alist);
+       va_end(alist);
+}
+
+void
+uu_vxdie(int status, const char *format, va_list alist)
+{
+       uu_die_internal(status, format, alist);
+}
+
+/*PRINTFLIKE2*/
+void
+uu_xdie(int status, const char *format, ...)
+{
+       va_list alist;
+       va_start(alist, format);
+       uu_die_internal(status, format, alist);
+       va_end(alist);
+}
+
+const char *
+uu_setpname(char *arg0)
+{
+       /*
+        * Having a NULL argv[0], while uncommon, is possible.  It
+        * makes more sense to handle this event in uu_setpname rather
+        * than in each of its consumers.
+        */
+       if (arg0 == NULL) {
+               pname = getexecname();
+               if (pname == NULL)
+                       pname = "unknown_command";
+               return (pname);
+       }
+
+       /*
+        * Guard against '/' at end of command invocation.
+        */
+       for (;;) {
+               char *p = strrchr(arg0, '/');
+               if (p == NULL) {
+                       pname = arg0;
+                       break;
+               } else {
+                       if (*(p + 1) == '\0') {
+                               *p = '\0';
+                               continue;
+                       }
+
+                       pname = p + 1;
+                       break;
+               }
+       }
+
+       return (pname);
+}
+
+const char *
+uu_getpname(void)
+{
+       return (pname);
+}
diff --git a/zfs/lib/libuutil/uu_string.c b/zfs/lib/libuutil/uu_string.c
new file mode 100644 (file)
index 0000000..66afba0
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * String helper functions
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include "libuutil.h"
+
+/* Return true if strings are equal */
+boolean_t
+uu_streq(const char *a, const char *b)
+{
+       return (strcmp(a, b) == 0);
+}
+
+/* Return true if strings are equal, case-insensitively */
+boolean_t
+uu_strcaseeq(const char *a, const char *b)
+{
+       return (strcasecmp(a, b) == 0);
+}
+
+/* Return true if string a Begins With string b */
+boolean_t
+uu_strbw(const char *a, const char *b)
+{
+       return (strncmp(a, b, strlen(b)) == 0);
+}
diff --git a/zfs/lib/libuutil/uu_strtoint.c b/zfs/lib/libuutil/uu_strtoint.c
new file mode 100644 (file)
index 0000000..494e0a5
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+
+#include "libuutil_common.h"
+
+#include <limits.h>
+#include <ctype.h>
+
+#define        MAX_BASE        36
+
+#define        IS_DIGIT(x)     ((x) >= '0' && (x) <= '9')
+
+#define        CTOI(x) (((x) >= '0' && (x) <= '9') ? (x) - '0' : \
+           ((x) >= 'a' && (x) <= 'z') ? (x) + 10 - 'a' : (x) + 10 - 'A')
+
+static int
+strtoint(const char *s_arg, uint64_t *out, uint32_t base, int sign)
+{
+       const unsigned char *s = (const unsigned char *)s_arg;
+
+       uint64_t val = 0;
+       uint64_t multmax;
+
+       unsigned c, i;
+
+       int neg = 0;
+
+       int bad_digit = 0;
+       int bad_char = 0;
+       int overflow = 0;
+
+       if (s == NULL || base == 1 || base > MAX_BASE) {
+               uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+               return (-1);
+       }
+
+       while ((c = *s) != 0 && isspace(c))
+               s++;
+
+       switch (c) {
+       case '-':
+               if (!sign)
+                       overflow = 1;           /* becomes underflow below */
+               neg = 1;
+               /*FALLTHRU*/
+       case '+':
+               c = *++s;
+               break;
+       default:
+               break;
+       }
+
+       if (c == '\0') {
+               uu_set_error(UU_ERROR_EMPTY);
+               return (-1);
+       }
+
+       if (base == 0) {
+               if (c != '0')
+                       base = 10;
+               else if (s[1] == 'x' || s[1] == 'X')
+                       base = 16;
+               else
+                       base = 8;
+       }
+
+       if (base == 16 && c == '0' && (s[1] == 'x' || s[1] == 'X'))
+               c = *(s += 2);
+
+       if ((val = CTOI(c)) >= base) {
+               if (IS_DIGIT(c))
+                       bad_digit = 1;
+               else
+                       bad_char = 1;
+               val = 0;
+       }
+
+       multmax = (uint64_t)UINT64_MAX / (uint64_t)base;
+
+       for (c = *++s; c != '\0'; c = *++s) {
+               if ((i = CTOI(c)) >= base) {
+                       if (isspace(c))
+                               break;
+                       if (IS_DIGIT(c))
+                               bad_digit = 1;
+                       else
+                               bad_char = 1;
+                       i = 0;
+               }
+
+               if (val > multmax)
+                       overflow = 1;
+
+               val *= base;
+               if ((uint64_t)UINT64_MAX - val < (uint64_t)i)
+                       overflow = 1;
+
+               val += i;
+       }
+
+       while ((c = *s) != 0) {
+               if (!isspace(c))
+                       bad_char = 1;
+               s++;
+       }
+
+       if (sign) {
+               if (neg) {
+                       if (val > -(uint64_t)INT64_MIN)
+                               overflow = 1;
+               } else {
+                       if (val > INT64_MAX)
+                               overflow = 1;
+               }
+       }
+
+       if (neg)
+               val = -val;
+
+       if (bad_char | bad_digit | overflow) {
+               if (bad_char)
+                       uu_set_error(UU_ERROR_INVALID_CHAR);
+               else if (bad_digit)
+                       uu_set_error(UU_ERROR_INVALID_DIGIT);
+               else if (overflow) {
+                       if (neg)
+                               uu_set_error(UU_ERROR_UNDERFLOW);
+                       else
+                               uu_set_error(UU_ERROR_OVERFLOW);
+               }
+               return (-1);
+       }
+
+       *out = val;
+       return (0);
+}
+
+int
+uu_strtoint(const char *s, void *v, size_t sz, int base,
+    int64_t min, int64_t max)
+{
+       uint64_t val_u;
+       int64_t val;
+
+       if (min > max)
+               goto bad_argument;
+
+       switch (sz) {
+       case 1:
+               if (max > INT8_MAX || min < INT8_MIN)
+                       goto bad_argument;
+               break;
+       case 2:
+               if (max > INT16_MAX || min < INT16_MIN)
+                       goto bad_argument;
+               break;
+       case 4:
+               if (max > INT32_MAX || min < INT32_MIN)
+                       goto bad_argument;
+               break;
+       case 8:
+               if (max > INT64_MAX || min < INT64_MIN)
+                       goto bad_argument;
+               break;
+       default:
+               goto bad_argument;
+       }
+
+       if (min == 0 && max == 0) {
+               min = -(1ULL << (8 * sz - 1));
+               max = (1ULL << (8 * sz - 1)) - 1;
+       }
+
+       if (strtoint(s, &val_u, base, 1) == -1)
+               return (-1);
+
+       val = (int64_t)val_u;
+
+       if (val < min) {
+               uu_set_error(UU_ERROR_UNDERFLOW);
+               return (-1);
+       } else if (val > max) {
+               uu_set_error(UU_ERROR_OVERFLOW);
+               return (-1);
+       }
+
+       switch (sz) {
+       case 1:
+               *(int8_t *)v = val;
+               return (0);
+       case 2:
+               *(int16_t *)v = val;
+               return (0);
+       case 4:
+               *(int32_t *)v = val;
+               return (0);
+       case 8:
+               *(int64_t *)v = val;
+               return (0);
+       default:
+               break;          /* fall through to bad_argument */
+       }
+
+bad_argument:
+       uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+       return (-1);
+}
+
+int
+uu_strtouint(const char *s, void *v, size_t sz, int base,
+    uint64_t min, uint64_t max)
+{
+       uint64_t val;
+
+       if (min > max)
+               goto bad_argument;
+
+       switch (sz) {
+       case 1:
+               if (max > UINT8_MAX)
+                       goto bad_argument;
+               break;
+       case 2:
+               if (max > UINT16_MAX)
+                       goto bad_argument;
+               break;
+       case 4:
+               if (max > UINT32_MAX)
+                       goto bad_argument;
+               break;
+       case 8:
+               if (max > UINT64_MAX)
+                       goto bad_argument;
+               break;
+       default:
+               goto bad_argument;
+       }
+
+       if (min == 0 && max == 0) {
+               /* we have to be careful, since << can overflow */
+               max = (1ULL << (8 * sz - 1)) * 2 - 1;
+       }
+
+       if (strtoint(s, &val, base, 0) == -1)
+               return (-1);
+
+       if (val < min) {
+               uu_set_error(UU_ERROR_UNDERFLOW);
+               return (-1);
+       } else if (val > max) {
+               uu_set_error(UU_ERROR_OVERFLOW);
+               return (-1);
+       }
+
+       switch (sz) {
+       case 1:
+               *(uint8_t *)v = val;
+               return (0);
+       case 2:
+               *(uint16_t *)v = val;
+               return (0);
+       case 4:
+               *(uint32_t *)v = val;
+               return (0);
+       case 8:
+               *(uint64_t *)v = val;
+               return (0);
+       default:
+               break;          /* shouldn't happen, fall through */
+       }
+
+bad_argument:
+       uu_set_error(UU_ERROR_INVALID_ARGUMENT);
+       return (-1);
+}
diff --git a/zfs/lib/libzfs/Makefile.am b/zfs/lib/libzfs/Makefile.am
new file mode 100644 (file)
index 0000000..8e596b0
--- /dev/null
@@ -0,0 +1,41 @@
+include $(top_srcdir)/config/Rules.am
+
+libzfs_pcdir = $(datarootdir)/pkgconfig
+libzfs_pc_DATA = libzfs.pc libzfs_core.pc
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+lib_LTLIBRARIES = libzfs.la
+
+USER_C = \
+       libzfs_changelist.c \
+       libzfs_config.c \
+       libzfs_dataset.c \
+       libzfs_diff.c \
+       libzfs_fru.c \
+       libzfs_import.c \
+       libzfs_iter.c \
+       libzfs_mount.c \
+       libzfs_pool.c \
+       libzfs_sendrecv.c \
+       libzfs_status.c \
+       libzfs_util.c
+
+KERNEL_C =
+
+nodist_libzfs_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+libzfs_la_LIBADD = \
+       $(top_builddir)/lib/libzfs_core/libzfs_core.la \
+       $(top_builddir)/lib/libshare/libshare.la \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libzpool/libzpool.la
+
+libzfs_la_LIBADD += -lm $(LIBBLKID) $(LIBUDEV) $(LIBDEVMAPPER)
+libzfs_la_LDFLAGS = -version-info 2:0:0
+
+EXTRA_DIST = $(libzfs_pc_DATA) $(USER_C)
diff --git a/zfs/lib/libzfs/Makefile.in b/zfs/lib/libzfs/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
index b3e8c1303bda612cfbec58359220e20cc62e48d7..0e83f7a64be00e61c95d4a432457b6f080c94f56 100644 (file)
@@ -1,2 +1,12 @@
-%:
-       #
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libzfs
+Description: LibZFS library
+Version: @VERSION@
+URL: http://zfsonlinux.org
+Requires: libzfs_core
+Cflags: -I${includedir}/libzfs -I${includedir}/libspl
+Libs: -L${libdir} -lzfs
diff --git a/zfs/lib/libzfs/libzfs_changelist.c b/zfs/lib/libzfs/libzfs_changelist.c
new file mode 100644 (file)
index 0000000..397f278
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Portions Copyright 2007 Ramprakash Jelari
+ * Copyright (c) 2014, 2015 by Delphix. All rights reserved.
+ */
+
+#include <libintl.h>
+#include <libuutil.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <zone.h>
+
+#include <libzfs.h>
+
+#include "libzfs_impl.h"
+
+/*
+ * Structure to keep track of dataset state.  Before changing the 'sharenfs' or
+ * 'mountpoint' property, we record whether the filesystem was previously
+ * mounted/shared.  This prior state dictates whether we remount/reshare the
+ * dataset after the property has been changed.
+ *
+ * The interface consists of the following sequence of functions:
+ *
+ *     changelist_gather()
+ *     changelist_prefix()
+ *     < change property >
+ *     changelist_postfix()
+ *     changelist_free()
+ *
+ * Other interfaces:
+ *
+ * changelist_remove() - remove a node from a gathered list
+ * changelist_rename() - renames all datasets appropriately when doing a rename
+ * changelist_unshare() - unshares all the nodes in a given changelist
+ * changelist_haszonedchild() - check if there is any child exported to
+ *                             a local zone
+ */
+typedef struct prop_changenode {
+       zfs_handle_t            *cn_handle;
+       int                     cn_shared;
+       int                     cn_mounted;
+       int                     cn_zoned;
+       boolean_t               cn_needpost;    /* is postfix() needed? */
+       uu_list_node_t          cn_listnode;
+} prop_changenode_t;
+
+struct prop_changelist {
+       zfs_prop_t              cl_prop;
+       zfs_prop_t              cl_realprop;
+       zfs_prop_t              cl_shareprop;  /* used with sharenfs/sharesmb */
+       uu_list_pool_t          *cl_pool;
+       uu_list_t               *cl_list;
+       boolean_t               cl_waslegacy;
+       boolean_t               cl_allchildren;
+       boolean_t               cl_alldependents;
+       int                     cl_mflags;      /* Mount flags */
+       int                     cl_gflags;      /* Gather request flags */
+       boolean_t               cl_haszonedchild;
+       boolean_t               cl_sorted;
+};
+
+/*
+ * If the property is 'mountpoint', go through and unmount filesystems as
+ * necessary.  We don't do the same for 'sharenfs', because we can just re-share
+ * with different options without interrupting service. We do handle 'sharesmb'
+ * since there may be old resource names that need to be removed.
+ */
+int
+changelist_prefix(prop_changelist_t *clp)
+{
+       prop_changenode_t *cn;
+       int ret = 0;
+
+       if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
+           clp->cl_prop != ZFS_PROP_SHARESMB)
+               return (0);
+
+       for (cn = uu_list_first(clp->cl_list); cn != NULL;
+           cn = uu_list_next(clp->cl_list, cn)) {
+
+               /* if a previous loop failed, set the remaining to false */
+               if (ret == -1) {
+                       cn->cn_needpost = B_FALSE;
+                       continue;
+               }
+
+               /*
+                * If we are in the global zone, but this dataset is exported
+                * to a local zone, do nothing.
+                */
+               if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
+                       continue;
+
+               if (!ZFS_IS_VOLUME(cn->cn_handle)) {
+                       /*
+                        * Do the property specific processing.
+                        */
+                       switch (clp->cl_prop) {
+                       case ZFS_PROP_MOUNTPOINT:
+                               if (zfs_unmount(cn->cn_handle, NULL,
+                                   clp->cl_mflags) != 0) {
+                                       ret = -1;
+                                       cn->cn_needpost = B_FALSE;
+                               }
+                               break;
+                       case ZFS_PROP_SHARESMB:
+                               (void) zfs_unshare_smb(cn->cn_handle, NULL);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       if (ret == -1)
+               (void) changelist_postfix(clp);
+
+       return (ret);
+}
+
+/*
+ * If the property is 'mountpoint' or 'sharenfs', go through and remount and/or
+ * reshare the filesystems as necessary.  In changelist_gather() we recorded
+ * whether the filesystem was previously shared or mounted.  The action we take
+ * depends on the previous state, and whether the value was previously 'legacy'.
+ * For non-legacy properties, we only remount/reshare the filesystem if it was
+ * previously mounted/shared.  Otherwise, we always remount/reshare the
+ * filesystem.
+ */
+int
+changelist_postfix(prop_changelist_t *clp)
+{
+       prop_changenode_t *cn;
+       char shareopts[ZFS_MAXPROPLEN];
+       int errors = 0;
+       libzfs_handle_t *hdl;
+
+       /*
+        * If we're changing the mountpoint, attempt to destroy the underlying
+        * mountpoint.  All other datasets will have inherited from this dataset
+        * (in which case their mountpoints exist in the filesystem in the new
+        * location), or have explicit mountpoints set (in which case they won't
+        * be in the changelist).
+        */
+       if ((cn = uu_list_last(clp->cl_list)) == NULL)
+               return (0);
+
+       if (clp->cl_prop == ZFS_PROP_MOUNTPOINT)
+               remove_mountpoint(cn->cn_handle);
+
+       /*
+        * It is possible that the changelist_prefix() used libshare
+        * to unshare some entries. Since libshare caches data, an
+        * attempt to reshare during postfix can fail unless libshare
+        * is uninitialized here so that it will reinitialize later.
+        */
+       if (cn->cn_handle != NULL) {
+               hdl = cn->cn_handle->zfs_hdl;
+               assert(hdl != NULL);
+               zfs_uninit_libshare(hdl);
+       }
+
+       /*
+        * We walk the datasets in reverse, because we want to mount any parent
+        * datasets before mounting the children.  We walk all datasets even if
+        * there are errors.
+        */
+       for (cn = uu_list_last(clp->cl_list); cn != NULL;
+           cn = uu_list_prev(clp->cl_list, cn)) {
+
+               boolean_t sharenfs;
+               boolean_t sharesmb;
+               boolean_t mounted;
+
+               /*
+                * If we are in the global zone, but this dataset is exported
+                * to a local zone, do nothing.
+                */
+               if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
+                       continue;
+
+               /* Only do post-processing if it's required */
+               if (!cn->cn_needpost)
+                       continue;
+               cn->cn_needpost = B_FALSE;
+
+               zfs_refresh_properties(cn->cn_handle);
+
+               if (ZFS_IS_VOLUME(cn->cn_handle))
+                       continue;
+
+               /*
+                * Remount if previously mounted or mountpoint was legacy,
+                * or sharenfs or sharesmb  property is set.
+                */
+               sharenfs = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARENFS,
+                   shareopts, sizeof (shareopts), NULL, NULL, 0,
+                   B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
+
+               sharesmb = ((zfs_prop_get(cn->cn_handle, ZFS_PROP_SHARESMB,
+                   shareopts, sizeof (shareopts), NULL, NULL, 0,
+                   B_FALSE) == 0) && (strcmp(shareopts, "off") != 0));
+
+               mounted = zfs_is_mounted(cn->cn_handle, NULL);
+
+               if (!mounted && (cn->cn_mounted ||
+                   ((sharenfs || sharesmb || clp->cl_waslegacy) &&
+                   (zfs_prop_get_int(cn->cn_handle,
+                   ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON)))) {
+
+                       if (zfs_mount(cn->cn_handle, NULL, 0) != 0)
+                               errors++;
+                       else
+                               mounted = TRUE;
+               }
+
+               /*
+                * If the file system is mounted we always re-share even
+                * if the filesystem is currently shared, so that we can
+                * adopt any new options.
+                */
+               if (sharenfs && mounted)
+                       errors += zfs_share_nfs(cn->cn_handle);
+               else if (cn->cn_shared || clp->cl_waslegacy)
+                       errors += zfs_unshare_nfs(cn->cn_handle, NULL);
+               if (sharesmb && mounted)
+                       errors += zfs_share_smb(cn->cn_handle);
+               else if (cn->cn_shared || clp->cl_waslegacy)
+                       errors += zfs_unshare_smb(cn->cn_handle, NULL);
+       }
+
+       return (errors ? -1 : 0);
+}
+
+/*
+ * Is this "dataset" a child of "parent"?
+ */
+boolean_t
+isa_child_of(const char *dataset, const char *parent)
+{
+       int len;
+
+       len = strlen(parent);
+
+       if (strncmp(dataset, parent, len) == 0 &&
+           (dataset[len] == '@' || dataset[len] == '/' ||
+           dataset[len] == '\0'))
+               return (B_TRUE);
+       else
+               return (B_FALSE);
+
+}
+
+/*
+ * If we rename a filesystem, child filesystem handles are no longer valid
+ * since we identify each dataset by its name in the ZFS namespace.  As a
+ * result, we have to go through and fix up all the names appropriately.  We
+ * could do this automatically if libzfs kept track of all open handles, but
+ * this is a lot less work.
+ */
+void
+changelist_rename(prop_changelist_t *clp, const char *src, const char *dst)
+{
+       prop_changenode_t *cn;
+       char newname[ZFS_MAX_DATASET_NAME_LEN];
+
+       for (cn = uu_list_first(clp->cl_list); cn != NULL;
+           cn = uu_list_next(clp->cl_list, cn)) {
+               /*
+                * Do not rename a clone that's not in the source hierarchy.
+                */
+               if (!isa_child_of(cn->cn_handle->zfs_name, src))
+                       continue;
+
+               /*
+                * Destroy the previous mountpoint if needed.
+                */
+               remove_mountpoint(cn->cn_handle);
+
+               (void) strlcpy(newname, dst, sizeof (newname));
+               (void) strlcat(newname, cn->cn_handle->zfs_name + strlen(src),
+                   sizeof (newname));
+
+               (void) strlcpy(cn->cn_handle->zfs_name, newname,
+                   sizeof (cn->cn_handle->zfs_name));
+       }
+}
+
+/*
+ * Given a gathered changelist for the 'sharenfs' or 'sharesmb' property,
+ * unshare all the datasets in the list.
+ */
+int
+changelist_unshare(prop_changelist_t *clp, zfs_share_proto_t *proto)
+{
+       prop_changenode_t *cn;
+       int ret = 0;
+
+       if (clp->cl_prop != ZFS_PROP_SHARENFS &&
+           clp->cl_prop != ZFS_PROP_SHARESMB)
+               return (0);
+
+       for (cn = uu_list_first(clp->cl_list); cn != NULL;
+           cn = uu_list_next(clp->cl_list, cn)) {
+               if (zfs_unshare_proto(cn->cn_handle, NULL, proto) != 0)
+                       ret = -1;
+       }
+
+       return (ret);
+}
+
+/*
+ * Check if there is any child exported to a local zone in a given changelist.
+ * This information has already been recorded while gathering the changelist
+ * via changelist_gather().
+ */
+int
+changelist_haszonedchild(prop_changelist_t *clp)
+{
+       return (clp->cl_haszonedchild);
+}
+
+/*
+ * Remove a node from a gathered list.
+ */
+void
+changelist_remove(prop_changelist_t *clp, const char *name)
+{
+       prop_changenode_t *cn;
+
+       for (cn = uu_list_first(clp->cl_list); cn != NULL;
+           cn = uu_list_next(clp->cl_list, cn)) {
+
+               if (strcmp(cn->cn_handle->zfs_name, name) == 0) {
+                       uu_list_remove(clp->cl_list, cn);
+                       zfs_close(cn->cn_handle);
+                       free(cn);
+                       return;
+               }
+       }
+}
+
+/*
+ * Release any memory associated with a changelist.
+ */
+void
+changelist_free(prop_changelist_t *clp)
+{
+       prop_changenode_t *cn;
+       void *cookie;
+
+       if (clp->cl_list) {
+               cookie = NULL;
+               while ((cn = uu_list_teardown(clp->cl_list, &cookie)) != NULL) {
+                       zfs_close(cn->cn_handle);
+                       free(cn);
+               }
+
+               uu_list_destroy(clp->cl_list);
+       }
+       if (clp->cl_pool)
+               uu_list_pool_destroy(clp->cl_pool);
+
+       free(clp);
+}
+
+static int
+change_one(zfs_handle_t *zhp, void *data)
+{
+       prop_changelist_t *clp = data;
+       char property[ZFS_MAXPROPLEN];
+       char where[64];
+       prop_changenode_t *cn;
+       zprop_source_t sourcetype = ZPROP_SRC_NONE;
+       zprop_source_t share_sourcetype = ZPROP_SRC_NONE;
+
+       /*
+        * We only want to unmount/unshare those filesystems that may inherit
+        * from the target filesystem.  If we find any filesystem with a
+        * locally set mountpoint, we ignore any children since changing the
+        * property will not affect them.  If this is a rename, we iterate
+        * over all children regardless, since we need them unmounted in
+        * order to do the rename.  Also, if this is a volume and we're doing
+        * a rename, then always add it to the changelist.
+        */
+
+       if (!(ZFS_IS_VOLUME(zhp) && clp->cl_realprop == ZFS_PROP_NAME) &&
+           zfs_prop_get(zhp, clp->cl_prop, property,
+           sizeof (property), &sourcetype, where, sizeof (where),
+           B_FALSE) != 0) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       /*
+        * If we are "watching" sharenfs or sharesmb
+        * then check out the companion property which is tracked
+        * in cl_shareprop
+        */
+       if (clp->cl_shareprop != ZPROP_INVAL &&
+           zfs_prop_get(zhp, clp->cl_shareprop, property,
+           sizeof (property), &share_sourcetype, where, sizeof (where),
+           B_FALSE) != 0) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if (clp->cl_alldependents || clp->cl_allchildren ||
+           sourcetype == ZPROP_SRC_DEFAULT ||
+           sourcetype == ZPROP_SRC_INHERITED ||
+           (clp->cl_shareprop != ZPROP_INVAL &&
+           (share_sourcetype == ZPROP_SRC_DEFAULT ||
+           share_sourcetype == ZPROP_SRC_INHERITED))) {
+               if ((cn = zfs_alloc(zfs_get_handle(zhp),
+                   sizeof (prop_changenode_t))) == NULL) {
+                       zfs_close(zhp);
+                       return (-1);
+               }
+
+               cn->cn_handle = zhp;
+               cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
+                   zfs_is_mounted(zhp, NULL);
+               cn->cn_shared = zfs_is_shared(zhp);
+               cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+               cn->cn_needpost = B_TRUE;
+
+               /* Indicate if any child is exported to a local zone. */
+               if (getzoneid() == GLOBAL_ZONEID && cn->cn_zoned)
+                       clp->cl_haszonedchild = B_TRUE;
+
+               uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
+
+               if (clp->cl_sorted) {
+                       uu_list_index_t idx;
+
+                       (void) uu_list_find(clp->cl_list, cn, NULL,
+                           &idx);
+                       uu_list_insert(clp->cl_list, cn, idx);
+               } else {
+                       /*
+                        * Add this child to beginning of the list. Children
+                        * below this one in the hierarchy will get added above
+                        * this one in the list. This produces a list in
+                        * reverse dataset name order.
+                        * This is necessary when the original mountpoint
+                        * is legacy or none.
+                        */
+                       ASSERT(!clp->cl_alldependents);
+                       verify(uu_list_insert_before(clp->cl_list,
+                           uu_list_first(clp->cl_list), cn) == 0);
+               }
+
+               if (!clp->cl_alldependents)
+                       return (zfs_iter_children(zhp, change_one, data));
+       } else {
+               zfs_close(zhp);
+       }
+
+       return (0);
+}
+
+/*ARGSUSED*/
+static int
+compare_mountpoints(const void *a, const void *b, void *unused)
+{
+       const prop_changenode_t *ca = a;
+       const prop_changenode_t *cb = b;
+
+       char mounta[MAXPATHLEN];
+       char mountb[MAXPATHLEN];
+
+       boolean_t hasmounta, hasmountb;
+
+       /*
+        * When unsharing or unmounting filesystems, we need to do it in
+        * mountpoint order.  This allows the user to have a mountpoint
+        * hierarchy that is different from the dataset hierarchy, and still
+        * allow it to be changed.  However, if either dataset doesn't have a
+        * mountpoint (because it is a volume or a snapshot), we place it at the
+        * end of the list, because it doesn't affect our change at all.
+        */
+       hasmounta = (zfs_prop_get(ca->cn_handle, ZFS_PROP_MOUNTPOINT, mounta,
+           sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
+       hasmountb = (zfs_prop_get(cb->cn_handle, ZFS_PROP_MOUNTPOINT, mountb,
+           sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
+
+       if (!hasmounta && hasmountb)
+               return (-1);
+       else if (hasmounta && !hasmountb)
+               return (1);
+       else if (!hasmounta && !hasmountb)
+               return (0);
+       else
+               return (strcmp(mountb, mounta));
+}
+
+/*
+ * Given a ZFS handle and a property, construct a complete list of datasets
+ * that need to be modified as part of this process.  For anything but the
+ * 'mountpoint' and 'sharenfs' properties, this just returns an empty list.
+ * Otherwise, we iterate over all children and look for any datasets that
+ * inherit the property.  For each such dataset, we add it to the list and
+ * mark whether it was shared beforehand.
+ */
+prop_changelist_t *
+changelist_gather(zfs_handle_t *zhp, zfs_prop_t prop, int gather_flags,
+    int mnt_flags)
+{
+       prop_changelist_t *clp;
+       prop_changenode_t *cn;
+       zfs_handle_t *temp;
+       char property[ZFS_MAXPROPLEN];
+       uu_compare_fn_t *compare = NULL;
+       boolean_t legacy = B_FALSE;
+
+       if ((clp = zfs_alloc(zhp->zfs_hdl, sizeof (prop_changelist_t))) == NULL)
+               return (NULL);
+
+       /*
+        * For mountpoint-related tasks, we want to sort everything by
+        * mountpoint, so that we mount and unmount them in the appropriate
+        * order, regardless of their position in the hierarchy.
+        */
+       if (prop == ZFS_PROP_NAME || prop == ZFS_PROP_ZONED ||
+           prop == ZFS_PROP_MOUNTPOINT || prop == ZFS_PROP_SHARENFS ||
+           prop == ZFS_PROP_SHARESMB) {
+
+               if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT,
+                   property, sizeof (property),
+                   NULL, NULL, 0, B_FALSE) == 0 &&
+                   (strcmp(property, "legacy") == 0 ||
+                   strcmp(property, "none") == 0)) {
+
+                       legacy = B_TRUE;
+               }
+               if (!legacy) {
+                       compare = compare_mountpoints;
+                       clp->cl_sorted = B_TRUE;
+               }
+       }
+
+       clp->cl_pool = uu_list_pool_create("changelist_pool",
+           sizeof (prop_changenode_t),
+           offsetof(prop_changenode_t, cn_listnode),
+           compare, 0);
+       if (clp->cl_pool == NULL) {
+               assert(uu_error() == UU_ERROR_NO_MEMORY);
+               (void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
+               changelist_free(clp);
+               return (NULL);
+       }
+
+       clp->cl_list = uu_list_create(clp->cl_pool, NULL,
+           clp->cl_sorted ? UU_LIST_SORTED : 0);
+       clp->cl_gflags = gather_flags;
+       clp->cl_mflags = mnt_flags;
+
+       if (clp->cl_list == NULL) {
+               assert(uu_error() == UU_ERROR_NO_MEMORY);
+               (void) zfs_error(zhp->zfs_hdl, EZFS_NOMEM, "internal error");
+               changelist_free(clp);
+               return (NULL);
+       }
+
+       /*
+        * If this is a rename or the 'zoned' property, we pretend we're
+        * changing the mountpoint and flag it so we can catch all children in
+        * change_one().
+        *
+        * Flag cl_alldependents to catch all children plus the dependents
+        * (clones) that are not in the hierarchy.
+        */
+       if (prop == ZFS_PROP_NAME) {
+               clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+               clp->cl_alldependents = B_TRUE;
+       } else if (prop == ZFS_PROP_ZONED) {
+               clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+               clp->cl_allchildren = B_TRUE;
+       } else if (prop == ZFS_PROP_CANMOUNT) {
+               clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+       } else if (prop == ZFS_PROP_VOLSIZE) {
+               clp->cl_prop = ZFS_PROP_MOUNTPOINT;
+       } else {
+               clp->cl_prop = prop;
+       }
+       clp->cl_realprop = prop;
+
+       if (clp->cl_prop != ZFS_PROP_MOUNTPOINT &&
+           clp->cl_prop != ZFS_PROP_SHARENFS &&
+           clp->cl_prop != ZFS_PROP_SHARESMB)
+               return (clp);
+
+       /*
+        * If watching SHARENFS or SHARESMB then
+        * also watch its companion property.
+        */
+       if (clp->cl_prop == ZFS_PROP_SHARENFS)
+               clp->cl_shareprop = ZFS_PROP_SHARESMB;
+       else if (clp->cl_prop == ZFS_PROP_SHARESMB)
+               clp->cl_shareprop = ZFS_PROP_SHARENFS;
+
+       if (clp->cl_alldependents) {
+               if (zfs_iter_dependents(zhp, B_TRUE, change_one, clp) != 0) {
+                       changelist_free(clp);
+                       return (NULL);
+               }
+       } else if (zfs_iter_children(zhp, change_one, clp) != 0) {
+               changelist_free(clp);
+               return (NULL);
+       }
+
+       /*
+        * We have to re-open ourselves because we auto-close all the handles
+        * and can't tell the difference.
+        */
+       if ((temp = zfs_open(zhp->zfs_hdl, zfs_get_name(zhp),
+           ZFS_TYPE_DATASET)) == NULL) {
+               changelist_free(clp);
+               return (NULL);
+       }
+
+       /*
+        * Always add ourself to the list.  We add ourselves to the end so that
+        * we're the last to be unmounted.
+        */
+       if ((cn = zfs_alloc(zhp->zfs_hdl,
+           sizeof (prop_changenode_t))) == NULL) {
+               zfs_close(temp);
+               changelist_free(clp);
+               return (NULL);
+       }
+
+       cn->cn_handle = temp;
+       cn->cn_mounted = (clp->cl_gflags & CL_GATHER_MOUNT_ALWAYS) ||
+           zfs_is_mounted(temp, NULL);
+       cn->cn_shared = zfs_is_shared(temp);
+       cn->cn_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+       cn->cn_needpost = B_TRUE;
+
+       uu_list_node_init(cn, &cn->cn_listnode, clp->cl_pool);
+       if (clp->cl_sorted) {
+               uu_list_index_t idx;
+               (void) uu_list_find(clp->cl_list, cn, NULL, &idx);
+               uu_list_insert(clp->cl_list, cn, idx);
+       } else {
+               /*
+                * Add the target dataset to the end of the list.
+                * The list is not really unsorted. The list will be
+                * in reverse dataset name order. This is necessary
+                * when the original mountpoint is legacy or none.
+                */
+               verify(uu_list_insert_after(clp->cl_list,
+                   uu_list_last(clp->cl_list), cn) == 0);
+       }
+
+       /*
+        * If the mountpoint property was previously 'legacy', or 'none',
+        * record it as the behavior of changelist_postfix() will be different.
+        */
+       if ((clp->cl_prop == ZFS_PROP_MOUNTPOINT) && legacy) {
+               /*
+                * do not automatically mount ex-legacy datasets if
+                * we specifically set canmount to noauto
+                */
+               if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) !=
+                   ZFS_CANMOUNT_NOAUTO)
+                       clp->cl_waslegacy = B_TRUE;
+       }
+
+       return (clp);
+}
diff --git a/zfs/lib/libzfs/libzfs_config.c b/zfs/lib/libzfs/libzfs_config.c
new file mode 100644 (file)
index 0000000..4585a2b
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * 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.
+ */
+
+/*
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2015 by Syneto S.R.L. All rights reserved.
+ */
+
+/*
+ * The pool configuration repository is stored in /etc/zfs/zpool.cache as a
+ * single packed nvlist.  While it would be nice to just read in this
+ * file from userland, this wouldn't work from a local zone.  So we have to have
+ * a zpool ioctl to return the complete configuration for all pools.  In the
+ * global zone, this will be identical to reading the file and unpacking it in
+ * userland.
+ */
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <libuutil.h>
+
+#include "libzfs_impl.h"
+
+typedef struct config_node {
+       char            *cn_name;
+       nvlist_t        *cn_config;
+       uu_avl_node_t   cn_avl;
+} config_node_t;
+
+/* ARGSUSED */
+static int
+config_node_compare(const void *a, const void *b, void *unused)
+{
+       int ret;
+
+       const config_node_t *ca = (config_node_t *)a;
+       const config_node_t *cb = (config_node_t *)b;
+
+       ret = strcmp(ca->cn_name, cb->cn_name);
+
+       if (ret < 0)
+               return (-1);
+       else if (ret > 0)
+               return (1);
+       else
+               return (0);
+}
+
+void
+namespace_clear(libzfs_handle_t *hdl)
+{
+       if (hdl->libzfs_ns_avl) {
+               config_node_t *cn;
+               void *cookie = NULL;
+
+               while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl,
+                   &cookie)) != NULL) {
+                       nvlist_free(cn->cn_config);
+                       free(cn->cn_name);
+                       free(cn);
+               }
+
+               uu_avl_destroy(hdl->libzfs_ns_avl);
+               hdl->libzfs_ns_avl = NULL;
+       }
+
+       if (hdl->libzfs_ns_avlpool) {
+               uu_avl_pool_destroy(hdl->libzfs_ns_avlpool);
+               hdl->libzfs_ns_avlpool = NULL;
+       }
+}
+
+/*
+ * Loads the pool namespace, or re-loads it if the cache has changed.
+ */
+static int
+namespace_reload(libzfs_handle_t *hdl)
+{
+       nvlist_t *config;
+       config_node_t *cn;
+       nvpair_t *elem;
+       zfs_cmd_t zc = {"\0"};
+       void *cookie;
+
+       if (hdl->libzfs_ns_gen == 0) {
+               /*
+                * This is the first time we've accessed the configuration
+                * cache.  Initialize the AVL tree and then fall through to the
+                * common code.
+                */
+               if ((hdl->libzfs_ns_avlpool = uu_avl_pool_create("config_pool",
+                   sizeof (config_node_t),
+                   offsetof(config_node_t, cn_avl),
+                   config_node_compare, UU_DEFAULT)) == NULL)
+                       return (no_memory(hdl));
+
+               if ((hdl->libzfs_ns_avl = uu_avl_create(hdl->libzfs_ns_avlpool,
+                   NULL, UU_DEFAULT)) == NULL)
+                       return (no_memory(hdl));
+       }
+
+       if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
+               return (-1);
+
+       for (;;) {
+               zc.zc_cookie = hdl->libzfs_ns_gen;
+               if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_CONFIGS, &zc) != 0) {
+                       switch (errno) {
+                       case EEXIST:
+                               /*
+                                * The namespace hasn't changed.
+                                */
+                               zcmd_free_nvlists(&zc);
+                               return (0);
+
+                       case ENOMEM:
+                               if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+                                       zcmd_free_nvlists(&zc);
+                                       return (-1);
+                               }
+                               break;
+
+                       default:
+                               zcmd_free_nvlists(&zc);
+                               return (zfs_standard_error(hdl, errno,
+                                   dgettext(TEXT_DOMAIN, "failed to read "
+                                   "pool configuration")));
+                       }
+               } else {
+                       hdl->libzfs_ns_gen = zc.zc_cookie;
+                       break;
+               }
+       }
+
+       if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
+               zcmd_free_nvlists(&zc);
+               return (-1);
+       }
+
+       zcmd_free_nvlists(&zc);
+
+       /*
+        * Clear out any existing configuration information.
+        */
+       cookie = NULL;
+       while ((cn = uu_avl_teardown(hdl->libzfs_ns_avl, &cookie)) != NULL) {
+               nvlist_free(cn->cn_config);
+               free(cn->cn_name);
+               free(cn);
+       }
+
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(config, elem)) != NULL) {
+               nvlist_t *child;
+               uu_avl_index_t where;
+
+               if ((cn = zfs_alloc(hdl, sizeof (config_node_t))) == NULL) {
+                       nvlist_free(config);
+                       return (-1);
+               }
+
+               if ((cn->cn_name = zfs_strdup(hdl,
+                   nvpair_name(elem))) == NULL) {
+                       free(cn);
+                       nvlist_free(config);
+                       return (-1);
+               }
+
+               verify(nvpair_value_nvlist(elem, &child) == 0);
+               if (nvlist_dup(child, &cn->cn_config, 0) != 0) {
+                       free(cn->cn_name);
+                       free(cn);
+                       nvlist_free(config);
+                       return (no_memory(hdl));
+               }
+               verify(uu_avl_find(hdl->libzfs_ns_avl, cn, NULL, &where)
+                   == NULL);
+
+               uu_avl_insert(hdl->libzfs_ns_avl, cn, where);
+       }
+
+       nvlist_free(config);
+       return (0);
+}
+
+/*
+ * Retrieve the configuration for the given pool. The configuration is an nvlist
+ * describing the vdevs, as well as the statistics associated with each one.
+ */
+nvlist_t *
+zpool_get_config(zpool_handle_t *zhp, nvlist_t **oldconfig)
+{
+       if (oldconfig)
+               *oldconfig = zhp->zpool_old_config;
+       return (zhp->zpool_config);
+}
+
+/*
+ * Retrieves a list of enabled features and their refcounts and caches it in
+ * the pool handle.
+ */
+nvlist_t *
+zpool_get_features(zpool_handle_t *zhp)
+{
+       nvlist_t *config, *features;
+
+       config = zpool_get_config(zhp, NULL);
+
+       if (config == NULL || !nvlist_exists(config,
+           ZPOOL_CONFIG_FEATURE_STATS)) {
+               int error;
+               boolean_t missing = B_FALSE;
+
+               error = zpool_refresh_stats(zhp, &missing);
+
+               if (error != 0 || missing)
+                       return (NULL);
+
+               config = zpool_get_config(zhp, NULL);
+       }
+
+       if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_FEATURE_STATS,
+           &features) != 0)
+               return (NULL);
+
+       return (features);
+}
+
+/*
+ * Refresh the vdev statistics associated with the given pool.  This is used in
+ * iostat to show configuration changes and determine the delta from the last
+ * time the function was called.  This function can fail, in case the pool has
+ * been destroyed.
+ */
+int
+zpool_refresh_stats(zpool_handle_t *zhp, boolean_t *missing)
+{
+       zfs_cmd_t zc = {"\0"};
+       int error;
+       nvlist_t *config;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       *missing = B_FALSE;
+       (void) strcpy(zc.zc_name, zhp->zpool_name);
+
+       if (zhp->zpool_config_size == 0)
+               zhp->zpool_config_size = 1 << 16;
+
+       if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size) != 0)
+               return (-1);
+
+       for (;;) {
+               if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_POOL_STATS,
+                   &zc) == 0) {
+                       /*
+                        * The real error is returned in the zc_cookie field.
+                        */
+                       error = zc.zc_cookie;
+                       break;
+               }
+
+               if (errno == ENOMEM) {
+                       if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+                               zcmd_free_nvlists(&zc);
+                               return (-1);
+                       }
+               } else {
+                       zcmd_free_nvlists(&zc);
+                       if (errno == ENOENT || errno == EINVAL)
+                               *missing = B_TRUE;
+                       zhp->zpool_state = POOL_STATE_UNAVAIL;
+                       return (0);
+               }
+       }
+
+       if (zcmd_read_dst_nvlist(hdl, &zc, &config) != 0) {
+               zcmd_free_nvlists(&zc);
+               return (-1);
+       }
+
+       zcmd_free_nvlists(&zc);
+
+       zhp->zpool_config_size = zc.zc_nvlist_dst_size;
+
+       if (zhp->zpool_config != NULL) {
+               nvlist_free(zhp->zpool_old_config);
+
+               zhp->zpool_old_config = zhp->zpool_config;
+       }
+
+       zhp->zpool_config = config;
+       if (error)
+               zhp->zpool_state = POOL_STATE_UNAVAIL;
+       else
+               zhp->zpool_state = POOL_STATE_ACTIVE;
+
+       return (0);
+}
+
+/*
+ * If the __ZFS_POOL_RESTRICT environment variable is set we only iterate over
+ * pools it lists.
+ *
+ * This is an undocumented feature for use during testing only.
+ *
+ * This function returns B_TRUE if the pool should be skipped
+ * during iteration.
+ */
+static boolean_t
+check_restricted(const char *poolname)
+{
+       static boolean_t initialized = B_FALSE;
+       static char *restricted = NULL;
+
+       const char *cur, *end;
+       int len, namelen;
+
+       if (!initialized) {
+               initialized = B_TRUE;
+               restricted = getenv("__ZFS_POOL_RESTRICT");
+       }
+
+       if (NULL == restricted)
+               return (B_FALSE);
+
+       cur = restricted;
+       namelen = strlen(poolname);
+       do {
+               end = strchr(cur, ' ');
+               len = (NULL == end) ? strlen(cur) : (end - cur);
+
+               if (len == namelen && 0 == strncmp(cur, poolname, len)) {
+                       return (B_FALSE);
+               }
+
+               cur += (len + 1);
+       } while (NULL != end);
+
+       return (B_TRUE);
+}
+
+/*
+ * Iterate over all pools in the system.
+ */
+int
+zpool_iter(libzfs_handle_t *hdl, zpool_iter_f func, void *data)
+{
+       config_node_t *cn;
+       zpool_handle_t *zhp;
+       int ret;
+
+       /*
+        * If someone makes a recursive call to zpool_iter(), we want to avoid
+        * refreshing the namespace because that will invalidate the parent
+        * context.  We allow recursive calls, but simply re-use the same
+        * namespace AVL tree.
+        */
+       if (!hdl->libzfs_pool_iter && namespace_reload(hdl) != 0)
+               return (-1);
+
+       hdl->libzfs_pool_iter++;
+       for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
+           cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
+
+               if (check_restricted(cn->cn_name))
+                       continue;
+
+               if (zpool_open_silent(hdl, cn->cn_name, &zhp) != 0) {
+                       hdl->libzfs_pool_iter--;
+                       return (-1);
+               }
+
+               if (zhp == NULL)
+                       continue;
+
+               if ((ret = func(zhp, data)) != 0) {
+                       hdl->libzfs_pool_iter--;
+                       return (ret);
+               }
+       }
+       hdl->libzfs_pool_iter--;
+
+       return (0);
+}
+
+/*
+ * Iterate over root datasets, calling the given function for each.  The zfs
+ * handle passed each time must be explicitly closed by the callback.
+ */
+int
+zfs_iter_root(libzfs_handle_t *hdl, zfs_iter_f func, void *data)
+{
+       config_node_t *cn;
+       zfs_handle_t *zhp;
+       int ret;
+
+       if (namespace_reload(hdl) != 0)
+               return (-1);
+
+       for (cn = uu_avl_first(hdl->libzfs_ns_avl); cn != NULL;
+           cn = uu_avl_next(hdl->libzfs_ns_avl, cn)) {
+
+               if (check_restricted(cn->cn_name))
+                       continue;
+
+               if ((zhp = make_dataset_handle(hdl, cn->cn_name)) == NULL)
+                       continue;
+
+               if ((ret = func(zhp, data)) != 0)
+                       return (ret);
+       }
+
+       return (0);
+}
index b3e8c1303bda612cfbec58359220e20cc62e48d7..2b6a86bfa4e8fe13298aeeb0c5f50d1ec966ee48 100644 (file)
@@ -1,2 +1,11 @@
-%:
-       #
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libzfs_core
+Description: LibZFS core library
+Version: @VERSION@
+URL: http://zfsonlinux.org
+Cflags: -I${includedir}/libzfs -I${includedir}/libspl
+Libs: -L${libdir} -lzfs_core
diff --git a/zfs/lib/libzfs/libzfs_dataset.c b/zfs/lib/libzfs/libzfs_dataset.c
new file mode 100644 (file)
index 0000000..e0f84af
--- /dev/null
@@ -0,0 +1,4806 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
+ * Copyright (c) 2013 Martin Matuska. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <libintl.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <zone.h>
+#include <fcntl.h>
+#include <sys/mntent.h>
+#include <sys/mount.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stddef.h>
+#include <ucred.h>
+#ifdef HAVE_IDMAP
+#include <idmap.h>
+#include <aclutils.h>
+#include <directory.h>
+#endif /* HAVE_IDMAP */
+
+#include <sys/dnode.h>
+#include <sys/spa.h>
+#include <sys/zap.h>
+#include <libzfs.h>
+
+#include "zfs_namecheck.h"
+#include "zfs_prop.h"
+#include "libzfs_impl.h"
+#include "zfs_deleg.h"
+
+static int userquota_propname_decode(const char *propname, boolean_t zoned,
+    zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
+
+/*
+ * Given a single type (not a mask of types), return the type in a human
+ * readable form.
+ */
+const char *
+zfs_type_to_name(zfs_type_t type)
+{
+       switch (type) {
+       case ZFS_TYPE_FILESYSTEM:
+               return (dgettext(TEXT_DOMAIN, "filesystem"));
+       case ZFS_TYPE_SNAPSHOT:
+               return (dgettext(TEXT_DOMAIN, "snapshot"));
+       case ZFS_TYPE_VOLUME:
+               return (dgettext(TEXT_DOMAIN, "volume"));
+       default:
+               break;
+       }
+
+       return (NULL);
+}
+
+/*
+ * Validate a ZFS path.  This is used even before trying to open the dataset, to
+ * provide a more meaningful error message.  We call zfs_error_aux() to
+ * explain exactly why the name was not valid.
+ */
+int
+zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
+    boolean_t modifying)
+{
+       namecheck_err_t why;
+       char what;
+
+       (void) zfs_prop_get_table();
+       if (dataset_namecheck(path, &why, &what) != 0) {
+               if (hdl != NULL) {
+                       switch (why) {
+                       case NAME_ERR_TOOLONG:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "name is too long"));
+                               break;
+
+                       case NAME_ERR_LEADING_SLASH:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "leading slash in name"));
+                               break;
+
+                       case NAME_ERR_EMPTY_COMPONENT:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "empty component in name"));
+                               break;
+
+                       case NAME_ERR_TRAILING_SLASH:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "trailing slash in name"));
+                               break;
+
+                       case NAME_ERR_INVALCHAR:
+                               zfs_error_aux(hdl,
+                                   dgettext(TEXT_DOMAIN, "invalid character "
+                                   "'%c' in name"), what);
+                               break;
+
+                       case NAME_ERR_MULTIPLE_AT:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "multiple '@' delimiters in name"));
+                               break;
+
+                       case NAME_ERR_NOLETTER:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "pool doesn't begin with a letter"));
+                               break;
+
+                       case NAME_ERR_RESERVED:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "name is reserved"));
+                               break;
+
+                       case NAME_ERR_DISKLIKE:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "reserved disk name"));
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               return (0);
+       }
+
+       if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
+               if (hdl != NULL)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "snapshot delimiter '@' in filesystem name"));
+               return (0);
+       }
+
+       if (type == ZFS_TYPE_SNAPSHOT && strchr(path, '@') == NULL) {
+               if (hdl != NULL)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "missing '@' delimiter in snapshot name"));
+               return (0);
+       }
+
+       if (modifying && strchr(path, '%') != NULL) {
+               if (hdl != NULL)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "invalid character %c in name"), '%');
+               return (0);
+       }
+
+       return (-1);
+}
+
+int
+zfs_name_valid(const char *name, zfs_type_t type)
+{
+       if (type == ZFS_TYPE_POOL)
+               return (zpool_name_valid(NULL, B_FALSE, name));
+       return (zfs_validate_name(NULL, name, type, B_FALSE));
+}
+
+/*
+ * This function takes the raw DSL properties, and filters out the user-defined
+ * properties into a separate nvlist.
+ */
+static nvlist_t *
+process_user_props(zfs_handle_t *zhp, nvlist_t *props)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       nvpair_t *elem;
+       nvlist_t *propval;
+       nvlist_t *nvl;
+
+       if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
+               (void) no_memory(hdl);
+               return (NULL);
+       }
+
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
+               if (!zfs_prop_user(nvpair_name(elem)))
+                       continue;
+
+               verify(nvpair_value_nvlist(elem, &propval) == 0);
+               if (nvlist_add_nvlist(nvl, nvpair_name(elem), propval) != 0) {
+                       nvlist_free(nvl);
+                       (void) no_memory(hdl);
+                       return (NULL);
+               }
+       }
+
+       return (nvl);
+}
+
+static zpool_handle_t *
+zpool_add_handle(zfs_handle_t *zhp, const char *pool_name)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       zpool_handle_t *zph;
+
+       if ((zph = zpool_open_canfail(hdl, pool_name)) != NULL) {
+               if (hdl->libzfs_pool_handles != NULL)
+                       zph->zpool_next = hdl->libzfs_pool_handles;
+               hdl->libzfs_pool_handles = zph;
+       }
+       return (zph);
+}
+
+static zpool_handle_t *
+zpool_find_handle(zfs_handle_t *zhp, const char *pool_name, int len)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       zpool_handle_t *zph = hdl->libzfs_pool_handles;
+
+       while ((zph != NULL) &&
+           (strncmp(pool_name, zpool_get_name(zph), len) != 0))
+               zph = zph->zpool_next;
+       return (zph);
+}
+
+/*
+ * Returns a handle to the pool that contains the provided dataset.
+ * If a handle to that pool already exists then that handle is returned.
+ * Otherwise, a new handle is created and added to the list of handles.
+ */
+static zpool_handle_t *
+zpool_handle(zfs_handle_t *zhp)
+{
+       char *pool_name;
+       int len;
+       zpool_handle_t *zph;
+
+       len = strcspn(zhp->zfs_name, "/@#") + 1;
+       pool_name = zfs_alloc(zhp->zfs_hdl, len);
+       (void) strlcpy(pool_name, zhp->zfs_name, len);
+
+       zph = zpool_find_handle(zhp, pool_name, len);
+       if (zph == NULL)
+               zph = zpool_add_handle(zhp, pool_name);
+
+       free(pool_name);
+       return (zph);
+}
+
+void
+zpool_free_handles(libzfs_handle_t *hdl)
+{
+       zpool_handle_t *next, *zph = hdl->libzfs_pool_handles;
+
+       while (zph != NULL) {
+               next = zph->zpool_next;
+               zpool_close(zph);
+               zph = next;
+       }
+       hdl->libzfs_pool_handles = NULL;
+}
+
+/*
+ * Utility function to gather stats (objset and zpl) for the given object.
+ */
+static int
+get_stats_ioctl(zfs_handle_t *zhp, zfs_cmd_t *zc)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+       (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
+
+       while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, zc) != 0) {
+               if (errno == ENOMEM) {
+                       if (zcmd_expand_dst_nvlist(hdl, zc) != 0) {
+                               return (-1);
+                       }
+               } else {
+                       return (-1);
+               }
+       }
+       return (0);
+}
+
+/*
+ * Utility function to get the received properties of the given object.
+ */
+static int
+get_recvd_props_ioctl(zfs_handle_t *zhp)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       nvlist_t *recvdprops;
+       zfs_cmd_t zc = {"\0"};
+       int err;
+
+       if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
+               return (-1);
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       while (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_RECVD_PROPS, &zc) != 0) {
+               if (errno == ENOMEM) {
+                       if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+                               return (-1);
+                       }
+               } else {
+                       zcmd_free_nvlists(&zc);
+                       return (-1);
+               }
+       }
+
+       err = zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &recvdprops);
+       zcmd_free_nvlists(&zc);
+       if (err != 0)
+               return (-1);
+
+       nvlist_free(zhp->zfs_recvd_props);
+       zhp->zfs_recvd_props = recvdprops;
+
+       return (0);
+}
+
+static int
+put_stats_zhdl(zfs_handle_t *zhp, zfs_cmd_t *zc)
+{
+       nvlist_t *allprops, *userprops;
+
+       zhp->zfs_dmustats = zc->zc_objset_stats; /* structure assignment */
+
+       if (zcmd_read_dst_nvlist(zhp->zfs_hdl, zc, &allprops) != 0) {
+               return (-1);
+       }
+
+       /*
+        * XXX Why do we store the user props separately, in addition to
+        * storing them in zfs_props?
+        */
+       if ((userprops = process_user_props(zhp, allprops)) == NULL) {
+               nvlist_free(allprops);
+               return (-1);
+       }
+
+       nvlist_free(zhp->zfs_props);
+       nvlist_free(zhp->zfs_user_props);
+
+       zhp->zfs_props = allprops;
+       zhp->zfs_user_props = userprops;
+
+       return (0);
+}
+
+static int
+get_stats(zfs_handle_t *zhp)
+{
+       int rc = 0;
+       zfs_cmd_t zc = {"\0"};
+
+       if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+               return (-1);
+       if (get_stats_ioctl(zhp, &zc) != 0)
+               rc = -1;
+       else if (put_stats_zhdl(zhp, &zc) != 0)
+               rc = -1;
+       zcmd_free_nvlists(&zc);
+       return (rc);
+}
+
+/*
+ * Refresh the properties currently stored in the handle.
+ */
+void
+zfs_refresh_properties(zfs_handle_t *zhp)
+{
+       (void) get_stats(zhp);
+}
+
+/*
+ * Makes a handle from the given dataset name.  Used by zfs_open() and
+ * zfs_iter_* to create child handles on the fly.
+ */
+static int
+make_dataset_handle_common(zfs_handle_t *zhp, zfs_cmd_t *zc)
+{
+       if (put_stats_zhdl(zhp, zc) != 0)
+               return (-1);
+
+       /*
+        * We've managed to open the dataset and gather statistics.  Determine
+        * the high-level type.
+        */
+       if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
+               zhp->zfs_head_type = ZFS_TYPE_VOLUME;
+       else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
+               zhp->zfs_head_type = ZFS_TYPE_FILESYSTEM;
+       else if (zhp->zfs_dmustats.dds_type == DMU_OST_OTHER)
+               return (-1);
+       else
+               abort();
+
+       if (zhp->zfs_dmustats.dds_is_snapshot)
+               zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
+       else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
+               zhp->zfs_type = ZFS_TYPE_VOLUME;
+       else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZFS)
+               zhp->zfs_type = ZFS_TYPE_FILESYSTEM;
+       else
+               abort();        /* we should never see any other types */
+
+       if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL)
+               return (-1);
+
+       return (0);
+}
+
+zfs_handle_t *
+make_dataset_handle(libzfs_handle_t *hdl, const char *path)
+{
+       zfs_cmd_t zc = {"\0"};
+
+       zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+       if (zhp == NULL)
+               return (NULL);
+
+       zhp->zfs_hdl = hdl;
+       (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
+       if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0) {
+               free(zhp);
+               return (NULL);
+       }
+       if (get_stats_ioctl(zhp, &zc) == -1) {
+               zcmd_free_nvlists(&zc);
+               free(zhp);
+               return (NULL);
+       }
+       if (make_dataset_handle_common(zhp, &zc) == -1) {
+               free(zhp);
+               zhp = NULL;
+       }
+       zcmd_free_nvlists(&zc);
+       return (zhp);
+}
+
+zfs_handle_t *
+make_dataset_handle_zc(libzfs_handle_t *hdl, zfs_cmd_t *zc)
+{
+       zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+       if (zhp == NULL)
+               return (NULL);
+
+       zhp->zfs_hdl = hdl;
+       (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
+       if (make_dataset_handle_common(zhp, zc) == -1) {
+               free(zhp);
+               return (NULL);
+       }
+       return (zhp);
+}
+
+zfs_handle_t *
+make_dataset_simple_handle_zc(zfs_handle_t *pzhp, zfs_cmd_t *zc)
+{
+       zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+       if (zhp == NULL)
+               return (NULL);
+
+       zhp->zfs_hdl = pzhp->zfs_hdl;
+       (void) strlcpy(zhp->zfs_name, zc->zc_name, sizeof (zhp->zfs_name));
+       zhp->zfs_head_type = pzhp->zfs_type;
+       zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
+       zhp->zpool_hdl = zpool_handle(zhp);
+
+       return (zhp);
+}
+
+zfs_handle_t *
+zfs_handle_dup(zfs_handle_t *zhp_orig)
+{
+       zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+       if (zhp == NULL)
+               return (NULL);
+
+       zhp->zfs_hdl = zhp_orig->zfs_hdl;
+       zhp->zpool_hdl = zhp_orig->zpool_hdl;
+       (void) strlcpy(zhp->zfs_name, zhp_orig->zfs_name,
+           sizeof (zhp->zfs_name));
+       zhp->zfs_type = zhp_orig->zfs_type;
+       zhp->zfs_head_type = zhp_orig->zfs_head_type;
+       zhp->zfs_dmustats = zhp_orig->zfs_dmustats;
+       if (zhp_orig->zfs_props != NULL) {
+               if (nvlist_dup(zhp_orig->zfs_props, &zhp->zfs_props, 0) != 0) {
+                       (void) no_memory(zhp->zfs_hdl);
+                       zfs_close(zhp);
+                       return (NULL);
+               }
+       }
+       if (zhp_orig->zfs_user_props != NULL) {
+               if (nvlist_dup(zhp_orig->zfs_user_props,
+                   &zhp->zfs_user_props, 0) != 0) {
+                       (void) no_memory(zhp->zfs_hdl);
+                       zfs_close(zhp);
+                       return (NULL);
+               }
+       }
+       if (zhp_orig->zfs_recvd_props != NULL) {
+               if (nvlist_dup(zhp_orig->zfs_recvd_props,
+                   &zhp->zfs_recvd_props, 0)) {
+                       (void) no_memory(zhp->zfs_hdl);
+                       zfs_close(zhp);
+                       return (NULL);
+               }
+       }
+       zhp->zfs_mntcheck = zhp_orig->zfs_mntcheck;
+       if (zhp_orig->zfs_mntopts != NULL) {
+               zhp->zfs_mntopts = zfs_strdup(zhp_orig->zfs_hdl,
+                   zhp_orig->zfs_mntopts);
+       }
+       zhp->zfs_props_table = zhp_orig->zfs_props_table;
+       return (zhp);
+}
+
+boolean_t
+zfs_bookmark_exists(const char *path)
+{
+       nvlist_t *bmarks;
+       nvlist_t *props;
+       char fsname[ZFS_MAX_DATASET_NAME_LEN];
+       char *bmark_name;
+       char *pound;
+       int err;
+       boolean_t rv;
+
+
+       (void) strlcpy(fsname, path, sizeof (fsname));
+       pound = strchr(fsname, '#');
+       if (pound == NULL)
+               return (B_FALSE);
+
+       *pound = '\0';
+       bmark_name = pound + 1;
+       props = fnvlist_alloc();
+       err = lzc_get_bookmarks(fsname, props, &bmarks);
+       nvlist_free(props);
+       if (err != 0) {
+               nvlist_free(bmarks);
+               return (B_FALSE);
+       }
+
+       rv = nvlist_exists(bmarks, bmark_name);
+       nvlist_free(bmarks);
+       return (rv);
+}
+
+zfs_handle_t *
+make_bookmark_handle(zfs_handle_t *parent, const char *path,
+    nvlist_t *bmark_props)
+{
+       zfs_handle_t *zhp = calloc(sizeof (zfs_handle_t), 1);
+
+       if (zhp == NULL)
+               return (NULL);
+
+       /* Fill in the name. */
+       zhp->zfs_hdl = parent->zfs_hdl;
+       (void) strlcpy(zhp->zfs_name, path, sizeof (zhp->zfs_name));
+
+       /* Set the property lists. */
+       if (nvlist_dup(bmark_props, &zhp->zfs_props, 0) != 0) {
+               free(zhp);
+               return (NULL);
+       }
+
+       /* Set the types. */
+       zhp->zfs_head_type = parent->zfs_head_type;
+       zhp->zfs_type = ZFS_TYPE_BOOKMARK;
+
+       if ((zhp->zpool_hdl = zpool_handle(zhp)) == NULL) {
+               nvlist_free(zhp->zfs_props);
+               free(zhp);
+               return (NULL);
+       }
+
+       return (zhp);
+}
+
+/*
+ * Opens the given snapshot, filesystem, or volume.   The 'types'
+ * argument is a mask of acceptable types.  The function will print an
+ * appropriate error message and return NULL if it can't be opened.
+ */
+zfs_handle_t *
+zfs_open(libzfs_handle_t *hdl, const char *path, int types)
+{
+       zfs_handle_t *zhp;
+       char errbuf[1024];
+
+       (void) snprintf(errbuf, sizeof (errbuf),
+           dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
+
+       /*
+        * Validate the name before we even try to open it.
+        */
+       if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "invalid dataset name"));
+               (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+               return (NULL);
+       }
+
+       /*
+        * Try to get stats for the dataset, which will tell us if it exists.
+        */
+       errno = 0;
+       if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
+               (void) zfs_standard_error(hdl, errno, errbuf);
+               return (NULL);
+       }
+
+       if (!(types & zhp->zfs_type)) {
+               (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+               zfs_close(zhp);
+               return (NULL);
+       }
+
+       return (zhp);
+}
+
+/*
+ * Release a ZFS handle.  Nothing to do but free the associated memory.
+ */
+void
+zfs_close(zfs_handle_t *zhp)
+{
+       if (zhp->zfs_mntopts)
+               free(zhp->zfs_mntopts);
+       nvlist_free(zhp->zfs_props);
+       nvlist_free(zhp->zfs_user_props);
+       nvlist_free(zhp->zfs_recvd_props);
+       free(zhp);
+}
+
+typedef struct mnttab_node {
+       struct mnttab mtn_mt;
+       avl_node_t mtn_node;
+} mnttab_node_t;
+
+static int
+libzfs_mnttab_cache_compare(const void *arg1, const void *arg2)
+{
+       const mnttab_node_t *mtn1 = (const mnttab_node_t *)arg1;
+       const mnttab_node_t *mtn2 = (const mnttab_node_t *)arg2;
+       int rv;
+
+       rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
+
+       return (AVL_ISIGN(rv));
+}
+
+void
+libzfs_mnttab_init(libzfs_handle_t *hdl)
+{
+       assert(avl_numnodes(&hdl->libzfs_mnttab_cache) == 0);
+       avl_create(&hdl->libzfs_mnttab_cache, libzfs_mnttab_cache_compare,
+           sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
+}
+
+int
+libzfs_mnttab_update(libzfs_handle_t *hdl)
+{
+       struct mnttab entry;
+
+       /* Reopen MNTTAB to prevent reading stale data from open file */
+       if (freopen(MNTTAB, "r", hdl->libzfs_mnttab) == NULL)
+               return (ENOENT);
+
+       while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
+               mnttab_node_t *mtn;
+               avl_index_t where;
+
+               if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
+                       continue;
+
+               mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
+               mtn->mtn_mt.mnt_special = zfs_strdup(hdl, entry.mnt_special);
+               mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, entry.mnt_mountp);
+               mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, entry.mnt_fstype);
+               mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, entry.mnt_mntopts);
+
+               /* Exclude duplicate mounts */
+               if (avl_find(&hdl->libzfs_mnttab_cache, mtn, &where) != NULL) {
+                       free(mtn->mtn_mt.mnt_special);
+                       free(mtn->mtn_mt.mnt_mountp);
+                       free(mtn->mtn_mt.mnt_fstype);
+                       free(mtn->mtn_mt.mnt_mntopts);
+                       free(mtn);
+                       continue;
+               }
+
+               avl_add(&hdl->libzfs_mnttab_cache, mtn);
+       }
+
+       return (0);
+}
+
+void
+libzfs_mnttab_fini(libzfs_handle_t *hdl)
+{
+       void *cookie = NULL;
+       mnttab_node_t *mtn;
+
+       while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie))) {
+               free(mtn->mtn_mt.mnt_special);
+               free(mtn->mtn_mt.mnt_mountp);
+               free(mtn->mtn_mt.mnt_fstype);
+               free(mtn->mtn_mt.mnt_mntopts);
+               free(mtn);
+       }
+       avl_destroy(&hdl->libzfs_mnttab_cache);
+}
+
+void
+libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
+{
+       hdl->libzfs_mnttab_enable = enable;
+}
+
+int
+libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
+    struct mnttab *entry)
+{
+       mnttab_node_t find;
+       mnttab_node_t *mtn;
+       int error;
+
+       if (!hdl->libzfs_mnttab_enable) {
+               struct mnttab srch = { 0 };
+
+               if (avl_numnodes(&hdl->libzfs_mnttab_cache))
+                       libzfs_mnttab_fini(hdl);
+
+               /* Reopen MNTTAB to prevent reading stale data from open file */
+               if (freopen(MNTTAB, "r", hdl->libzfs_mnttab) == NULL)
+                       return (ENOENT);
+
+               srch.mnt_special = (char *)fsname;
+               srch.mnt_fstype = MNTTYPE_ZFS;
+               if (getmntany(hdl->libzfs_mnttab, entry, &srch) == 0)
+                       return (0);
+               else
+                       return (ENOENT);
+       }
+
+       if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
+               if ((error = libzfs_mnttab_update(hdl)) != 0)
+                       return (error);
+
+       find.mtn_mt.mnt_special = (char *)fsname;
+       mtn = avl_find(&hdl->libzfs_mnttab_cache, &find, NULL);
+       if (mtn) {
+               *entry = mtn->mtn_mt;
+               return (0);
+       }
+       return (ENOENT);
+}
+
+void
+libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
+    const char *mountp, const char *mntopts)
+{
+       mnttab_node_t *mtn;
+
+       if (avl_numnodes(&hdl->libzfs_mnttab_cache) == 0)
+               return;
+       mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
+       mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
+       mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
+       mtn->mtn_mt.mnt_fstype = zfs_strdup(hdl, MNTTYPE_ZFS);
+       mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
+       avl_add(&hdl->libzfs_mnttab_cache, mtn);
+}
+
+void
+libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
+{
+       mnttab_node_t find;
+       mnttab_node_t *ret;
+
+       find.mtn_mt.mnt_special = (char *)fsname;
+       if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))) {
+               avl_remove(&hdl->libzfs_mnttab_cache, ret);
+               free(ret->mtn_mt.mnt_special);
+               free(ret->mtn_mt.mnt_mountp);
+               free(ret->mtn_mt.mnt_fstype);
+               free(ret->mtn_mt.mnt_mntopts);
+               free(ret);
+       }
+}
+
+int
+zfs_spa_version(zfs_handle_t *zhp, int *spa_version)
+{
+       zpool_handle_t *zpool_handle = zhp->zpool_hdl;
+
+       if (zpool_handle == NULL)
+               return (-1);
+
+       *spa_version = zpool_get_prop_int(zpool_handle,
+           ZPOOL_PROP_VERSION, NULL);
+       return (0);
+}
+
+/*
+ * The choice of reservation property depends on the SPA version.
+ */
+static int
+zfs_which_resv_prop(zfs_handle_t *zhp, zfs_prop_t *resv_prop)
+{
+       int spa_version;
+
+       if (zfs_spa_version(zhp, &spa_version) < 0)
+               return (-1);
+
+       if (spa_version >= SPA_VERSION_REFRESERVATION)
+               *resv_prop = ZFS_PROP_REFRESERVATION;
+       else
+               *resv_prop = ZFS_PROP_RESERVATION;
+
+       return (0);
+}
+
+/*
+ * Given an nvlist of properties to set, validates that they are correct, and
+ * parses any numeric properties (index, boolean, etc) if they are specified as
+ * strings.
+ */
+nvlist_t *
+zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
+    uint64_t zoned, zfs_handle_t *zhp, zpool_handle_t *zpool_hdl,
+    const char *errbuf)
+{
+       nvpair_t *elem;
+       uint64_t intval;
+       char *strval;
+       zfs_prop_t prop;
+       nvlist_t *ret;
+       int chosen_normal = -1;
+       int chosen_utf = -1;
+
+       if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
+               (void) no_memory(hdl);
+               return (NULL);
+       }
+
+       /*
+        * Make sure this property is valid and applies to this type.
+        */
+
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(nvl, elem)) != NULL) {
+               const char *propname = nvpair_name(elem);
+
+               prop = zfs_name_to_prop(propname);
+               if (prop == ZPROP_INVAL && zfs_prop_user(propname)) {
+                       /*
+                        * This is a user property: make sure it's a
+                        * string, and that it's less than ZAP_MAXNAMELEN.
+                        */
+                       if (nvpair_type(elem) != DATA_TYPE_STRING) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "'%s' must be a string"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       if (strlen(nvpair_name(elem)) >= ZAP_MAXNAMELEN) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property name '%s' is too long"),
+                                   propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       (void) nvpair_value_string(elem, &strval);
+                       if (nvlist_add_string(ret, propname, strval) != 0) {
+                               (void) no_memory(hdl);
+                               goto error;
+                       }
+                       continue;
+               }
+
+               /*
+                * Currently, only user properties can be modified on
+                * snapshots.
+                */
+               if (type == ZFS_TYPE_SNAPSHOT) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "this property can not be modified for snapshots"));
+                       (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
+                       goto error;
+               }
+
+               if (prop == ZPROP_INVAL && zfs_prop_userquota(propname)) {
+                       zfs_userquota_prop_t uqtype;
+                       char newpropname[128];
+                       char domain[128];
+                       uint64_t rid;
+                       uint64_t valary[3];
+
+                       if (userquota_propname_decode(propname, zoned,
+                           &uqtype, domain, sizeof (domain), &rid) != 0) {
+                               zfs_error_aux(hdl,
+                                   dgettext(TEXT_DOMAIN,
+                                   "'%s' has an invalid user/group name"),
+                                   propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       if (uqtype != ZFS_PROP_USERQUOTA &&
+                           uqtype != ZFS_PROP_GROUPQUOTA &&
+                           uqtype != ZFS_PROP_USEROBJQUOTA &&
+                           uqtype != ZFS_PROP_GROUPOBJQUOTA) {
+                               zfs_error_aux(hdl,
+                                   dgettext(TEXT_DOMAIN, "'%s' is readonly"),
+                                   propname);
+                               (void) zfs_error(hdl, EZFS_PROPREADONLY,
+                                   errbuf);
+                               goto error;
+                       }
+
+                       if (nvpair_type(elem) == DATA_TYPE_STRING) {
+                               (void) nvpair_value_string(elem, &strval);
+                               if (strcmp(strval, "none") == 0) {
+                                       intval = 0;
+                               } else if (zfs_nicestrtonum(hdl,
+                                   strval, &intval) != 0) {
+                                       (void) zfs_error(hdl,
+                                           EZFS_BADPROP, errbuf);
+                                       goto error;
+                               }
+                       } else if (nvpair_type(elem) ==
+                           DATA_TYPE_UINT64) {
+                               (void) nvpair_value_uint64(elem, &intval);
+                               if (intval == 0) {
+                                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                           "use 'none' to disable "
+                                           "userquota/groupquota"));
+                                       goto error;
+                               }
+                       } else {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "'%s' must be a number"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       /*
+                        * Encode the prop name as
+                        * userquota@<hex-rid>-domain, to make it easy
+                        * for the kernel to decode.
+                        */
+                       (void) snprintf(newpropname, sizeof (newpropname),
+                           "%s%llx-%s", zfs_userquota_prop_prefixes[uqtype],
+                           (longlong_t)rid, domain);
+                       valary[0] = uqtype;
+                       valary[1] = rid;
+                       valary[2] = intval;
+                       if (nvlist_add_uint64_array(ret, newpropname,
+                           valary, 3) != 0) {
+                               (void) no_memory(hdl);
+                               goto error;
+                       }
+                       continue;
+               } else if (prop == ZPROP_INVAL && zfs_prop_written(propname)) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' is readonly"),
+                           propname);
+                       (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
+                       goto error;
+               }
+
+               if (prop == ZPROP_INVAL) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "invalid property '%s'"), propname);
+                       (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                       goto error;
+               }
+
+               if (!zfs_prop_valid_for_type(prop, type, B_FALSE)) {
+                       zfs_error_aux(hdl,
+                           dgettext(TEXT_DOMAIN, "'%s' does not "
+                           "apply to datasets of this type"), propname);
+                       (void) zfs_error(hdl, EZFS_PROPTYPE, errbuf);
+                       goto error;
+               }
+
+               if (zfs_prop_readonly(prop) &&
+                   (!zfs_prop_setonce(prop) || zhp != NULL)) {
+                       zfs_error_aux(hdl,
+                           dgettext(TEXT_DOMAIN, "'%s' is readonly"),
+                           propname);
+                       (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
+                       goto error;
+               }
+
+               if (zprop_parse_value(hdl, elem, prop, type, ret,
+                   &strval, &intval, errbuf) != 0)
+                       goto error;
+
+               /*
+                * Perform some additional checks for specific properties.
+                */
+               switch (prop) {
+               case ZFS_PROP_VERSION:
+               {
+                       int version;
+
+                       if (zhp == NULL)
+                               break;
+                       version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+                       if (intval < version) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "Can not downgrade; already at version %u"),
+                                   version);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+                       break;
+               }
+
+               case ZFS_PROP_VOLBLOCKSIZE:
+               case ZFS_PROP_RECORDSIZE:
+               {
+                       int maxbs = SPA_MAXBLOCKSIZE;
+                       char buf[64];
+
+                       if (zpool_hdl != NULL) {
+                               maxbs = zpool_get_prop_int(zpool_hdl,
+                                   ZPOOL_PROP_MAXBLOCKSIZE, NULL);
+                       }
+                       /*
+                        * The value must be a power of two between
+                        * SPA_MINBLOCKSIZE and maxbs.
+                        */
+                       if (intval < SPA_MINBLOCKSIZE ||
+                           intval > maxbs || !ISP2(intval)) {
+                               zfs_nicenum(maxbs, buf, sizeof (buf));
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "'%s' must be power of 2 from 512B "
+                                   "to %s"), propname, buf);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+                       break;
+               }
+               case ZFS_PROP_MLSLABEL:
+               {
+#ifdef HAVE_MLSLABEL
+                       /*
+                        * Verify the mlslabel string and convert to
+                        * internal hex label string.
+                        */
+
+                       m_label_t *new_sl;
+                       char *hex = NULL;       /* internal label string */
+
+                       /* Default value is already OK. */
+                       if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
+                               break;
+
+                       /* Verify the label can be converted to binary form */
+                       if (((new_sl = m_label_alloc(MAC_LABEL)) == NULL) ||
+                           (str_to_label(strval, &new_sl, MAC_LABEL,
+                           L_NO_CORRECTION, NULL) == -1)) {
+                               goto badlabel;
+                       }
+
+                       /* Now translate to hex internal label string */
+                       if (label_to_str(new_sl, &hex, M_INTERNAL,
+                           DEF_NAMES) != 0) {
+                               if (hex)
+                                       free(hex);
+                               goto badlabel;
+                       }
+                       m_label_free(new_sl);
+
+                       /* If string is already in internal form, we're done. */
+                       if (strcmp(strval, hex) == 0) {
+                               free(hex);
+                               break;
+                       }
+
+                       /* Replace the label string with the internal form. */
+                       (void) nvlist_remove(ret, zfs_prop_to_name(prop),
+                           DATA_TYPE_STRING);
+                       verify(nvlist_add_string(ret, zfs_prop_to_name(prop),
+                           hex) == 0);
+                       free(hex);
+
+                       break;
+
+badlabel:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "invalid mlslabel '%s'"), strval);
+                       (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                       m_label_free(new_sl);   /* OK if null */
+                       goto error;
+#else
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "mlslabels are unsupported"));
+                       (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                       goto error;
+#endif /* HAVE_MLSLABEL */
+               }
+
+               case ZFS_PROP_MOUNTPOINT:
+               {
+                       namecheck_err_t why;
+
+                       if (strcmp(strval, ZFS_MOUNTPOINT_NONE) == 0 ||
+                           strcmp(strval, ZFS_MOUNTPOINT_LEGACY) == 0)
+                               break;
+
+                       if (mountpoint_namecheck(strval, &why)) {
+                               switch (why) {
+                               case NAME_ERR_LEADING_SLASH:
+                                       zfs_error_aux(hdl,
+                                           dgettext(TEXT_DOMAIN,
+                                           "'%s' must be an absolute path, "
+                                           "'none', or 'legacy'"), propname);
+                                       break;
+                               case NAME_ERR_TOOLONG:
+                                       zfs_error_aux(hdl,
+                                           dgettext(TEXT_DOMAIN,
+                                           "component of '%s' is too long"),
+                                           propname);
+                                       break;
+                               default:
+                                       break;
+                               }
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+               }
+
+                       /*FALLTHRU*/
+
+               case ZFS_PROP_SHARESMB:
+               case ZFS_PROP_SHARENFS:
+                       /*
+                        * For the mountpoint and sharenfs or sharesmb
+                        * properties, check if it can be set in a
+                        * global/non-global zone based on
+                        * the zoned property value:
+                        *
+                        *              global zone         non-global zone
+                        * --------------------------------------------------
+                        * zoned=on     mountpoint (no)     mountpoint (yes)
+                        *              sharenfs (no)       sharenfs (no)
+                        *              sharesmb (no)       sharesmb (no)
+                        *
+                        * zoned=off    mountpoint (yes)        N/A
+                        *              sharenfs (yes)
+                        *              sharesmb (yes)
+                        */
+                       if (zoned) {
+                               if (getzoneid() == GLOBAL_ZONEID) {
+                                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                           "'%s' cannot be set on "
+                                           "dataset in a non-global zone"),
+                                           propname);
+                                       (void) zfs_error(hdl, EZFS_ZONED,
+                                           errbuf);
+                                       goto error;
+                               } else if (prop == ZFS_PROP_SHARENFS ||
+                                   prop == ZFS_PROP_SHARESMB) {
+                                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                           "'%s' cannot be set in "
+                                           "a non-global zone"), propname);
+                                       (void) zfs_error(hdl, EZFS_ZONED,
+                                           errbuf);
+                                       goto error;
+                               }
+                       } else if (getzoneid() != GLOBAL_ZONEID) {
+                               /*
+                                * If zoned property is 'off', this must be in
+                                * a global zone. If not, something is wrong.
+                                */
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "'%s' cannot be set while dataset "
+                                   "'zoned' property is set"), propname);
+                               (void) zfs_error(hdl, EZFS_ZONED, errbuf);
+                               goto error;
+                       }
+
+                       /*
+                        * At this point, it is legitimate to set the
+                        * property. Now we want to make sure that the
+                        * property value is valid if it is sharenfs.
+                        */
+                       if ((prop == ZFS_PROP_SHARENFS ||
+                           prop == ZFS_PROP_SHARESMB) &&
+                           strcmp(strval, "on") != 0 &&
+                           strcmp(strval, "off") != 0) {
+                               zfs_share_proto_t proto;
+
+                               if (prop == ZFS_PROP_SHARESMB)
+                                       proto = PROTO_SMB;
+                               else
+                                       proto = PROTO_NFS;
+
+                               /*
+                                * Must be an valid sharing protocol
+                                * option string so init the libshare
+                                * in order to enable the parser and
+                                * then parse the options. We use the
+                                * control API since we don't care about
+                                * the current configuration and don't
+                                * want the overhead of loading it
+                                * until we actually do something.
+                                */
+
+                               if (zfs_init_libshare(hdl,
+                                   SA_INIT_CONTROL_API) != SA_OK) {
+                                       /*
+                                        * An error occurred so we can't do
+                                        * anything
+                                        */
+                                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                           "'%s' cannot be set: problem "
+                                           "in share initialization"),
+                                           propname);
+                                       (void) zfs_error(hdl, EZFS_BADPROP,
+                                           errbuf);
+                                       goto error;
+                               }
+
+                               if (zfs_parse_options(strval, proto) != SA_OK) {
+                                       /*
+                                        * There was an error in parsing so
+                                        * deal with it by issuing an error
+                                        * message and leaving after
+                                        * uninitializing the the libshare
+                                        * interface.
+                                        */
+                                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                           "'%s' cannot be set to invalid "
+                                           "options"), propname);
+                                       (void) zfs_error(hdl, EZFS_BADPROP,
+                                           errbuf);
+                                       zfs_uninit_libshare(hdl);
+                                       goto error;
+                               }
+                               zfs_uninit_libshare(hdl);
+                       }
+
+                       break;
+               case ZFS_PROP_UTF8ONLY:
+                       chosen_utf = (int)intval;
+                       break;
+               case ZFS_PROP_NORMALIZE:
+                       chosen_normal = (int)intval;
+                       break;
+               default:
+                       break;
+               }
+
+               /*
+                * For changes to existing volumes, we have some additional
+                * checks to enforce.
+                */
+               if (type == ZFS_TYPE_VOLUME && zhp != NULL) {
+                       uint64_t volsize = zfs_prop_get_int(zhp,
+                           ZFS_PROP_VOLSIZE);
+                       uint64_t blocksize = zfs_prop_get_int(zhp,
+                           ZFS_PROP_VOLBLOCKSIZE);
+                       char buf[64];
+
+                       switch (prop) {
+                       case ZFS_PROP_RESERVATION:
+                       case ZFS_PROP_REFRESERVATION:
+                               if (intval > volsize) {
+                                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                           "'%s' is greater than current "
+                                           "volume size"), propname);
+                                       (void) zfs_error(hdl, EZFS_BADPROP,
+                                           errbuf);
+                                       goto error;
+                               }
+                               break;
+
+                       case ZFS_PROP_VOLSIZE:
+                               if (intval % blocksize != 0) {
+                                       zfs_nicenum(blocksize, buf,
+                                           sizeof (buf));
+                                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                           "'%s' must be a multiple of "
+                                           "volume block size (%s)"),
+                                           propname, buf);
+                                       (void) zfs_error(hdl, EZFS_BADPROP,
+                                           errbuf);
+                                       goto error;
+                               }
+
+                               if (intval == 0) {
+                                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                           "'%s' cannot be zero"),
+                                           propname);
+                                       (void) zfs_error(hdl, EZFS_BADPROP,
+                                           errbuf);
+                                       goto error;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * If normalization was chosen, but no UTF8 choice was made,
+        * enforce rejection of non-UTF8 names.
+        *
+        * If normalization was chosen, but rejecting non-UTF8 names
+        * was explicitly not chosen, it is an error.
+        */
+       if (chosen_normal > 0 && chosen_utf < 0) {
+               if (nvlist_add_uint64(ret,
+                   zfs_prop_to_name(ZFS_PROP_UTF8ONLY), 1) != 0) {
+                       (void) no_memory(hdl);
+                       goto error;
+               }
+       } else if (chosen_normal > 0 && chosen_utf == 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "'%s' must be set 'on' if normalization chosen"),
+                   zfs_prop_to_name(ZFS_PROP_UTF8ONLY));
+               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+               goto error;
+       }
+       return (ret);
+
+error:
+       nvlist_free(ret);
+       return (NULL);
+}
+
+int
+zfs_add_synthetic_resv(zfs_handle_t *zhp, nvlist_t *nvl)
+{
+       uint64_t old_volsize;
+       uint64_t new_volsize;
+       uint64_t old_reservation;
+       uint64_t new_reservation;
+       zfs_prop_t resv_prop;
+       nvlist_t *props;
+
+       /*
+        * If this is an existing volume, and someone is setting the volsize,
+        * make sure that it matches the reservation, or add it if necessary.
+        */
+       old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
+       if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
+               return (-1);
+       old_reservation = zfs_prop_get_int(zhp, resv_prop);
+
+       props = fnvlist_alloc();
+       fnvlist_add_uint64(props, zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+           zfs_prop_get_int(zhp, ZFS_PROP_VOLBLOCKSIZE));
+
+       if ((zvol_volsize_to_reservation(old_volsize, props) !=
+           old_reservation) || nvlist_exists(nvl,
+           zfs_prop_to_name(resv_prop))) {
+               fnvlist_free(props);
+               return (0);
+       }
+       if (nvlist_lookup_uint64(nvl, zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+           &new_volsize) != 0) {
+               fnvlist_free(props);
+               return (-1);
+       }
+       new_reservation = zvol_volsize_to_reservation(new_volsize, props);
+       fnvlist_free(props);
+
+       if (nvlist_add_uint64(nvl, zfs_prop_to_name(resv_prop),
+           new_reservation) != 0) {
+               (void) no_memory(zhp->zfs_hdl);
+               return (-1);
+       }
+       return (1);
+}
+
+void
+zfs_setprop_error(libzfs_handle_t *hdl, zfs_prop_t prop, int err,
+    char *errbuf)
+{
+       switch (err) {
+
+       case ENOSPC:
+               /*
+                * For quotas and reservations, ENOSPC indicates
+                * something different; setting a quota or reservation
+                * doesn't use any disk space.
+                */
+               switch (prop) {
+               case ZFS_PROP_QUOTA:
+               case ZFS_PROP_REFQUOTA:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "size is less than current used or "
+                           "reserved space"));
+                       (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
+                       break;
+
+               case ZFS_PROP_RESERVATION:
+               case ZFS_PROP_REFRESERVATION:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "size is greater than available space"));
+                       (void) zfs_error(hdl, EZFS_PROPSPACE, errbuf);
+                       break;
+
+               default:
+                       (void) zfs_standard_error(hdl, err, errbuf);
+                       break;
+               }
+               break;
+
+       case EBUSY:
+               (void) zfs_standard_error(hdl, EBUSY, errbuf);
+               break;
+
+       case EROFS:
+               (void) zfs_error(hdl, EZFS_DSREADONLY, errbuf);
+               break;
+
+       case E2BIG:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "property value too long"));
+               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+               break;
+
+       case ENOTSUP:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "pool and or dataset must be upgraded to set this "
+                   "property or value"));
+               (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+               break;
+
+       case ERANGE:
+               if (prop == ZFS_PROP_COMPRESSION ||
+                   prop == ZFS_PROP_DNODESIZE ||
+                   prop == ZFS_PROP_RECORDSIZE) {
+                       (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "property setting is not allowed on "
+                           "bootable datasets"));
+                       (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
+               } else if (prop == ZFS_PROP_CHECKSUM ||
+                   prop == ZFS_PROP_DEDUP) {
+                       (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "property setting is not allowed on "
+                           "root pools"));
+                       (void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
+               } else {
+                       (void) zfs_standard_error(hdl, err, errbuf);
+               }
+               break;
+
+       case EINVAL:
+               if (prop == ZPROP_INVAL) {
+                       (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+               } else {
+                       (void) zfs_standard_error(hdl, err, errbuf);
+               }
+               break;
+
+       case EOVERFLOW:
+               /*
+                * This platform can't address a volume this big.
+                */
+#ifdef _ILP32
+               if (prop == ZFS_PROP_VOLSIZE) {
+                       (void) zfs_error(hdl, EZFS_VOLTOOBIG, errbuf);
+                       break;
+               }
+#endif
+               /* FALLTHROUGH */
+       default:
+               (void) zfs_standard_error(hdl, err, errbuf);
+       }
+}
+
+static boolean_t
+zfs_is_namespace_prop(zfs_prop_t prop)
+{
+       switch (prop) {
+
+       case ZFS_PROP_ATIME:
+       case ZFS_PROP_RELATIME:
+       case ZFS_PROP_DEVICES:
+       case ZFS_PROP_EXEC:
+       case ZFS_PROP_SETUID:
+       case ZFS_PROP_READONLY:
+       case ZFS_PROP_XATTR:
+       case ZFS_PROP_NBMAND:
+               return (B_TRUE);
+
+       default:
+               return (B_FALSE);
+       }
+}
+
+/*
+ * Given a property name and value, set the property for the given dataset.
+ */
+int
+zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval)
+{
+       int ret = -1;
+       char errbuf[1024];
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       nvlist_t *nvl = NULL;
+
+       (void) snprintf(errbuf, sizeof (errbuf),
+           dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
+           zhp->zfs_name);
+
+       if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
+           nvlist_add_string(nvl, propname, propval) != 0) {
+               (void) no_memory(hdl);
+               goto error;
+       }
+
+       ret = zfs_prop_set_list(zhp, nvl);
+
+error:
+       nvlist_free(nvl);
+       return (ret);
+}
+
+
+
+/*
+ * Given an nvlist of property names and values, set the properties for the
+ * given dataset.
+ */
+int
+zfs_prop_set_list(zfs_handle_t *zhp, nvlist_t *props)
+{
+       zfs_cmd_t zc = {"\0"};
+       int ret = -1;
+       prop_changelist_t **cls = NULL;
+       int cl_idx;
+       char errbuf[1024];
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       nvlist_t *nvl;
+       int nvl_len = 0;
+       int added_resv = 0;
+       zfs_prop_t prop = 0;
+       nvpair_t *elem;
+
+       (void) snprintf(errbuf, sizeof (errbuf),
+           dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
+           zhp->zfs_name);
+
+       if ((nvl = zfs_valid_proplist(hdl, zhp->zfs_type, props,
+           zfs_prop_get_int(zhp, ZFS_PROP_ZONED), zhp, zhp->zpool_hdl,
+           errbuf)) == NULL)
+               goto error;
+
+       /*
+        * We have to check for any extra properties which need to be added
+        * before computing the length of the nvlist.
+        */
+       for (elem = nvlist_next_nvpair(nvl, NULL);
+           elem != NULL;
+           elem = nvlist_next_nvpair(nvl, elem)) {
+               if (zfs_name_to_prop(nvpair_name(elem)) == ZFS_PROP_VOLSIZE &&
+                   (added_resv = zfs_add_synthetic_resv(zhp, nvl)) == -1) {
+                       goto error;
+               }
+       }
+       /*
+        * Check how many properties we're setting and allocate an array to
+        * store changelist pointers for postfix().
+        */
+       for (elem = nvlist_next_nvpair(nvl, NULL);
+           elem != NULL;
+           elem = nvlist_next_nvpair(nvl, elem))
+               nvl_len++;
+       if ((cls = calloc(nvl_len, sizeof (prop_changelist_t *))) == NULL)
+               goto error;
+
+       cl_idx = 0;
+       for (elem = nvlist_next_nvpair(nvl, NULL);
+           elem != NULL;
+           elem = nvlist_next_nvpair(nvl, elem)) {
+
+               prop = zfs_name_to_prop(nvpair_name(elem));
+
+               assert(cl_idx < nvl_len);
+               /*
+                * We don't want to unmount & remount the dataset when changing
+                * its canmount property to 'on' or 'noauto'.  We only use
+                * the changelist logic to unmount when setting canmount=off.
+                */
+               if (!(prop == ZFS_PROP_CANMOUNT &&
+                   fnvpair_value_uint64(elem) != ZFS_CANMOUNT_OFF)) {
+                       cls[cl_idx] = changelist_gather(zhp, prop, 0, 0);
+                       if (cls[cl_idx] == NULL)
+                               goto error;
+               }
+
+               if (prop == ZFS_PROP_MOUNTPOINT &&
+                   changelist_haszonedchild(cls[cl_idx])) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "child dataset with inherited mountpoint is used "
+                           "in a non-global zone"));
+                       ret = zfs_error(hdl, EZFS_ZONED, errbuf);
+                       goto error;
+               }
+
+               if (cls[cl_idx] != NULL &&
+                   (ret = changelist_prefix(cls[cl_idx])) != 0)
+                       goto error;
+
+               cl_idx++;
+       }
+       assert(cl_idx == nvl_len);
+
+       /*
+        * Execute the corresponding ioctl() to set this list of properties.
+        */
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       if ((ret = zcmd_write_src_nvlist(hdl, &zc, nvl)) != 0 ||
+           (ret = zcmd_alloc_dst_nvlist(hdl, &zc, 0)) != 0)
+               goto error;
+
+       ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
+
+       if (ret != 0) {
+               /* Get the list of unset properties back and report them. */
+               nvlist_t *errorprops = NULL;
+               if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
+                       goto error;
+               for (elem = nvlist_next_nvpair(nvl, NULL);
+                   elem != NULL;
+                   elem = nvlist_next_nvpair(nvl, elem)) {
+                       prop = zfs_name_to_prop(nvpair_name(elem));
+                       zfs_setprop_error(hdl, prop, errno, errbuf);
+               }
+               nvlist_free(errorprops);
+
+               if (added_resv && errno == ENOSPC) {
+                       /* clean up the volsize property we tried to set */
+                       uint64_t old_volsize = zfs_prop_get_int(zhp,
+                           ZFS_PROP_VOLSIZE);
+                       nvlist_free(nvl);
+                       nvl = NULL;
+                       zcmd_free_nvlists(&zc);
+
+                       if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+                               goto error;
+                       if (nvlist_add_uint64(nvl,
+                           zfs_prop_to_name(ZFS_PROP_VOLSIZE),
+                           old_volsize) != 0)
+                               goto error;
+                       if (zcmd_write_src_nvlist(hdl, &zc, nvl) != 0)
+                               goto error;
+                       (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
+               }
+       } else {
+               for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
+                       if (cls[cl_idx] != NULL) {
+                               int clp_err = changelist_postfix(cls[cl_idx]);
+                               if (clp_err != 0)
+                                       ret = clp_err;
+                       }
+               }
+
+               if (ret == 0) {
+                       /*
+                        * Refresh the statistics so the new property
+                        * value is reflected.
+                        */
+                       (void) get_stats(zhp);
+
+                       /*
+                        * Remount the filesystem to propagate the change
+                        * if one of the options handled by the generic
+                        * Linux namespace layer has been modified.
+                        */
+                       if (zfs_is_namespace_prop(prop) &&
+                           zfs_is_mounted(zhp, NULL))
+                               ret = zfs_mount(zhp, MNTOPT_REMOUNT, 0);
+               }
+       }
+
+error:
+       nvlist_free(nvl);
+       zcmd_free_nvlists(&zc);
+       if (cls != NULL) {
+               for (cl_idx = 0; cl_idx < nvl_len; cl_idx++) {
+                       if (cls[cl_idx] != NULL)
+                               changelist_free(cls[cl_idx]);
+               }
+               free(cls);
+       }
+       return (ret);
+}
+
+/*
+ * Given a property, inherit the value from the parent dataset, or if received
+ * is TRUE, revert to the received value, if any.
+ */
+int
+zfs_prop_inherit(zfs_handle_t *zhp, const char *propname, boolean_t received)
+{
+       zfs_cmd_t zc = {"\0"};
+       int ret;
+       prop_changelist_t *cl;
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       char errbuf[1024];
+       zfs_prop_t prop;
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot inherit %s for '%s'"), propname, zhp->zfs_name);
+
+       zc.zc_cookie = received;
+       if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL) {
+               /*
+                * For user properties, the amount of work we have to do is very
+                * small, so just do it here.
+                */
+               if (!zfs_prop_user(propname)) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "invalid property"));
+                       return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+               }
+
+               (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+               (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
+
+               if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc) != 0)
+                       return (zfs_standard_error(hdl, errno, errbuf));
+
+               return (0);
+       }
+
+       /*
+        * Verify that this property is inheritable.
+        */
+       if (zfs_prop_readonly(prop))
+               return (zfs_error(hdl, EZFS_PROPREADONLY, errbuf));
+
+       if (!zfs_prop_inheritable(prop) && !received)
+               return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
+
+       /*
+        * Check to see if the value applies to this type
+        */
+       if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE))
+               return (zfs_error(hdl, EZFS_PROPTYPE, errbuf));
+
+       /*
+        * Normalize the name, to get rid of shorthand abbreviations.
+        */
+       propname = zfs_prop_to_name(prop);
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+       (void) strlcpy(zc.zc_value, propname, sizeof (zc.zc_value));
+
+       if (prop == ZFS_PROP_MOUNTPOINT && getzoneid() == GLOBAL_ZONEID &&
+           zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "dataset is used in a non-global zone"));
+               return (zfs_error(hdl, EZFS_ZONED, errbuf));
+       }
+
+       /*
+        * Determine datasets which will be affected by this change, if any.
+        */
+       if ((cl = changelist_gather(zhp, prop, 0, 0)) == NULL)
+               return (-1);
+
+       if (prop == ZFS_PROP_MOUNTPOINT && changelist_haszonedchild(cl)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "child dataset with inherited mountpoint is used "
+                   "in a non-global zone"));
+               ret = zfs_error(hdl, EZFS_ZONED, errbuf);
+               goto error;
+       }
+
+       if ((ret = changelist_prefix(cl)) != 0)
+               goto error;
+
+       if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_INHERIT_PROP, &zc)) != 0) {
+               return (zfs_standard_error(hdl, errno, errbuf));
+       } else {
+
+               if ((ret = changelist_postfix(cl)) != 0)
+                       goto error;
+
+               /*
+                * Refresh the statistics so the new property is reflected.
+                */
+               (void) get_stats(zhp);
+
+               /*
+                * Remount the filesystem to propagate the change
+                * if one of the options handled by the generic
+                * Linux namespace layer has been modified.
+                */
+               if (zfs_is_namespace_prop(prop) &&
+                   zfs_is_mounted(zhp, NULL))
+                       ret = zfs_mount(zhp, MNTOPT_REMOUNT, 0);
+       }
+
+error:
+       changelist_free(cl);
+       return (ret);
+}
+
+/*
+ * True DSL properties are stored in an nvlist.  The following two functions
+ * extract them appropriately.
+ */
+uint64_t
+getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
+{
+       nvlist_t *nv;
+       uint64_t value;
+
+       *source = NULL;
+       if (nvlist_lookup_nvlist(zhp->zfs_props,
+           zfs_prop_to_name(prop), &nv) == 0) {
+               verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
+               (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
+       } else {
+               verify(!zhp->zfs_props_table ||
+                   zhp->zfs_props_table[prop] == B_TRUE);
+               value = zfs_prop_default_numeric(prop);
+               *source = "";
+       }
+
+       return (value);
+}
+
+static const char *
+getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
+{
+       nvlist_t *nv;
+       const char *value;
+
+       *source = NULL;
+       if (nvlist_lookup_nvlist(zhp->zfs_props,
+           zfs_prop_to_name(prop), &nv) == 0) {
+               value = fnvlist_lookup_string(nv, ZPROP_VALUE);
+               (void) nvlist_lookup_string(nv, ZPROP_SOURCE, source);
+       } else {
+               verify(!zhp->zfs_props_table ||
+                   zhp->zfs_props_table[prop] == B_TRUE);
+               value = zfs_prop_default_string(prop);
+               *source = "";
+       }
+
+       return (value);
+}
+
+static boolean_t
+zfs_is_recvd_props_mode(zfs_handle_t *zhp)
+{
+       return (zhp->zfs_props == zhp->zfs_recvd_props);
+}
+
+static void
+zfs_set_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
+{
+       *cookie = (uint64_t)(uintptr_t)zhp->zfs_props;
+       zhp->zfs_props = zhp->zfs_recvd_props;
+}
+
+static void
+zfs_unset_recvd_props_mode(zfs_handle_t *zhp, uint64_t *cookie)
+{
+       zhp->zfs_props = (nvlist_t *)(uintptr_t)*cookie;
+       *cookie = 0;
+}
+
+/*
+ * Internal function for getting a numeric property.  Both zfs_prop_get() and
+ * zfs_prop_get_int() are built using this interface.
+ *
+ * Certain properties can be overridden using 'mount -o'.  In this case, scan
+ * the contents of the /proc/self/mounts entry, searching for the
+ * appropriate options. If they differ from the on-disk values, report the
+ * current values and mark the source "temporary".
+ */
+static int
+get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
+    char **source, uint64_t *val)
+{
+       zfs_cmd_t zc = {"\0"};
+       nvlist_t *zplprops = NULL;
+       struct mnttab mnt;
+       char *mntopt_on = NULL;
+       char *mntopt_off = NULL;
+       boolean_t received = zfs_is_recvd_props_mode(zhp);
+
+       *source = NULL;
+
+       /*
+        * If the property is being fetched for a snapshot, check whether
+        * the property is valid for the snapshot's head dataset type.
+        */
+       if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT &&
+               !zfs_prop_valid_for_type(prop, zhp->zfs_head_type, B_TRUE)) {
+                       *val = zfs_prop_default_numeric(prop);
+                       return (-1);
+       }
+
+       switch (prop) {
+       case ZFS_PROP_ATIME:
+               mntopt_on = MNTOPT_ATIME;
+               mntopt_off = MNTOPT_NOATIME;
+               break;
+
+       case ZFS_PROP_RELATIME:
+               mntopt_on = MNTOPT_RELATIME;
+               mntopt_off = MNTOPT_NORELATIME;
+               break;
+
+       case ZFS_PROP_DEVICES:
+               mntopt_on = MNTOPT_DEVICES;
+               mntopt_off = MNTOPT_NODEVICES;
+               break;
+
+       case ZFS_PROP_EXEC:
+               mntopt_on = MNTOPT_EXEC;
+               mntopt_off = MNTOPT_NOEXEC;
+               break;
+
+       case ZFS_PROP_READONLY:
+               mntopt_on = MNTOPT_RO;
+               mntopt_off = MNTOPT_RW;
+               break;
+
+       case ZFS_PROP_SETUID:
+               mntopt_on = MNTOPT_SETUID;
+               mntopt_off = MNTOPT_NOSETUID;
+               break;
+
+       case ZFS_PROP_XATTR:
+               mntopt_on = MNTOPT_XATTR;
+               mntopt_off = MNTOPT_NOXATTR;
+               break;
+
+       case ZFS_PROP_NBMAND:
+               mntopt_on = MNTOPT_NBMAND;
+               mntopt_off = MNTOPT_NONBMAND;
+               break;
+       default:
+               break;
+       }
+
+       /*
+        * Because looking up the mount options is potentially expensive
+        * (iterating over all of /proc/self/mounts), we defer its
+        * calculation until we're looking up a property which requires
+        * its presence.
+        */
+       if (!zhp->zfs_mntcheck &&
+           (mntopt_on != NULL || prop == ZFS_PROP_MOUNTED)) {
+               libzfs_handle_t *hdl = zhp->zfs_hdl;
+               struct mnttab entry;
+
+               if (libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0) {
+                       zhp->zfs_mntopts = zfs_strdup(hdl,
+                           entry.mnt_mntopts);
+                       if (zhp->zfs_mntopts == NULL)
+                               return (-1);
+               }
+
+               zhp->zfs_mntcheck = B_TRUE;
+       }
+
+       if (zhp->zfs_mntopts == NULL)
+               mnt.mnt_mntopts = "";
+       else
+               mnt.mnt_mntopts = zhp->zfs_mntopts;
+
+       switch (prop) {
+       case ZFS_PROP_ATIME:
+       case ZFS_PROP_RELATIME:
+       case ZFS_PROP_DEVICES:
+       case ZFS_PROP_EXEC:
+       case ZFS_PROP_READONLY:
+       case ZFS_PROP_SETUID:
+       case ZFS_PROP_XATTR:
+       case ZFS_PROP_NBMAND:
+               *val = getprop_uint64(zhp, prop, source);
+
+               if (received)
+                       break;
+
+               if (hasmntopt(&mnt, mntopt_on) && !*val) {
+                       *val = B_TRUE;
+                       if (src)
+                               *src = ZPROP_SRC_TEMPORARY;
+               } else if (hasmntopt(&mnt, mntopt_off) && *val) {
+                       *val = B_FALSE;
+                       if (src)
+                               *src = ZPROP_SRC_TEMPORARY;
+               }
+               break;
+
+       case ZFS_PROP_CANMOUNT:
+       case ZFS_PROP_VOLSIZE:
+       case ZFS_PROP_QUOTA:
+       case ZFS_PROP_REFQUOTA:
+       case ZFS_PROP_RESERVATION:
+       case ZFS_PROP_REFRESERVATION:
+       case ZFS_PROP_FILESYSTEM_LIMIT:
+       case ZFS_PROP_SNAPSHOT_LIMIT:
+       case ZFS_PROP_FILESYSTEM_COUNT:
+       case ZFS_PROP_SNAPSHOT_COUNT:
+               *val = getprop_uint64(zhp, prop, source);
+
+               if (*source == NULL) {
+                       /* not default, must be local */
+                       *source = zhp->zfs_name;
+               }
+               break;
+
+       case ZFS_PROP_MOUNTED:
+               *val = (zhp->zfs_mntopts != NULL);
+               break;
+
+       case ZFS_PROP_NUMCLONES:
+               *val = zhp->zfs_dmustats.dds_num_clones;
+               break;
+
+       case ZFS_PROP_VERSION:
+       case ZFS_PROP_NORMALIZE:
+       case ZFS_PROP_UTF8ONLY:
+       case ZFS_PROP_CASE:
+               if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+                       return (-1);
+               (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+               if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_OBJSET_ZPLPROPS, &zc)) {
+                       zcmd_free_nvlists(&zc);
+                       if (prop == ZFS_PROP_VERSION &&
+                           zhp->zfs_type == ZFS_TYPE_VOLUME)
+                               *val = zfs_prop_default_numeric(prop);
+                       return (-1);
+               }
+               if (zcmd_read_dst_nvlist(zhp->zfs_hdl, &zc, &zplprops) != 0 ||
+                   nvlist_lookup_uint64(zplprops, zfs_prop_to_name(prop),
+                   val) != 0) {
+                       zcmd_free_nvlists(&zc);
+                       return (-1);
+               }
+               nvlist_free(zplprops);
+               zcmd_free_nvlists(&zc);
+               break;
+
+       case ZFS_PROP_INCONSISTENT:
+               *val = zhp->zfs_dmustats.dds_inconsistent;
+               break;
+
+       default:
+               switch (zfs_prop_get_type(prop)) {
+               case PROP_TYPE_NUMBER:
+               case PROP_TYPE_INDEX:
+                       *val = getprop_uint64(zhp, prop, source);
+                       /*
+                        * If we tried to use a default value for a
+                        * readonly property, it means that it was not
+                        * present.
+                        */
+                       if (zfs_prop_readonly(prop) &&
+                           *source != NULL && (*source)[0] == '\0') {
+                               *source = NULL;
+                       }
+                       break;
+
+               case PROP_TYPE_STRING:
+               default:
+                       zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+                           "cannot get non-numeric property"));
+                       return (zfs_error(zhp->zfs_hdl, EZFS_BADPROP,
+                           dgettext(TEXT_DOMAIN, "internal error")));
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * Calculate the source type, given the raw source string.
+ */
+static void
+get_source(zfs_handle_t *zhp, zprop_source_t *srctype, char *source,
+    char *statbuf, size_t statlen)
+{
+       if (statbuf == NULL || *srctype == ZPROP_SRC_TEMPORARY)
+               return;
+
+       if (source == NULL) {
+               *srctype = ZPROP_SRC_NONE;
+       } else if (source[0] == '\0') {
+               *srctype = ZPROP_SRC_DEFAULT;
+       } else if (strstr(source, ZPROP_SOURCE_VAL_RECVD) != NULL) {
+               *srctype = ZPROP_SRC_RECEIVED;
+       } else {
+               if (strcmp(source, zhp->zfs_name) == 0) {
+                       *srctype = ZPROP_SRC_LOCAL;
+               } else {
+                       (void) strlcpy(statbuf, source, statlen);
+                       *srctype = ZPROP_SRC_INHERITED;
+               }
+       }
+
+}
+
+int
+zfs_prop_get_recvd(zfs_handle_t *zhp, const char *propname, char *propbuf,
+    size_t proplen, boolean_t literal)
+{
+       zfs_prop_t prop;
+       int err = 0;
+
+       if (zhp->zfs_recvd_props == NULL)
+               if (get_recvd_props_ioctl(zhp) != 0)
+                       return (-1);
+
+       prop = zfs_name_to_prop(propname);
+
+       if (prop != ZPROP_INVAL) {
+               uint64_t cookie;
+               if (!nvlist_exists(zhp->zfs_recvd_props, propname))
+                       return (-1);
+               zfs_set_recvd_props_mode(zhp, &cookie);
+               err = zfs_prop_get(zhp, prop, propbuf, proplen,
+                   NULL, NULL, 0, literal);
+               zfs_unset_recvd_props_mode(zhp, &cookie);
+       } else {
+               nvlist_t *propval;
+               char *recvdval;
+               if (nvlist_lookup_nvlist(zhp->zfs_recvd_props,
+                   propname, &propval) != 0)
+                       return (-1);
+               verify(nvlist_lookup_string(propval, ZPROP_VALUE,
+                   &recvdval) == 0);
+               (void) strlcpy(propbuf, recvdval, proplen);
+       }
+
+       return (err == 0 ? 0 : -1);
+}
+
+static int
+get_clones_string(zfs_handle_t *zhp, char *propbuf, size_t proplen)
+{
+       nvlist_t *value;
+       nvpair_t *pair;
+
+       value = zfs_get_clones_nvl(zhp);
+       if (value == NULL)
+               return (-1);
+
+       propbuf[0] = '\0';
+       for (pair = nvlist_next_nvpair(value, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(value, pair)) {
+               if (propbuf[0] != '\0')
+                       (void) strlcat(propbuf, ",", proplen);
+               (void) strlcat(propbuf, nvpair_name(pair), proplen);
+       }
+
+       return (0);
+}
+
+struct get_clones_arg {
+       uint64_t numclones;
+       nvlist_t *value;
+       const char *origin;
+       char buf[ZFS_MAX_DATASET_NAME_LEN];
+};
+
+int
+get_clones_cb(zfs_handle_t *zhp, void *arg)
+{
+       struct get_clones_arg *gca = arg;
+
+       if (gca->numclones == 0) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, gca->buf, sizeof (gca->buf),
+           NULL, NULL, 0, B_TRUE) != 0)
+               goto out;
+       if (strcmp(gca->buf, gca->origin) == 0) {
+               fnvlist_add_boolean(gca->value, zfs_get_name(zhp));
+               gca->numclones--;
+       }
+
+out:
+       (void) zfs_iter_children(zhp, get_clones_cb, gca);
+       zfs_close(zhp);
+       return (0);
+}
+
+nvlist_t *
+zfs_get_clones_nvl(zfs_handle_t *zhp)
+{
+       nvlist_t *nv, *value;
+
+       if (nvlist_lookup_nvlist(zhp->zfs_props,
+           zfs_prop_to_name(ZFS_PROP_CLONES), &nv) != 0) {
+               struct get_clones_arg gca;
+
+               /*
+                * if this is a snapshot, then the kernel wasn't able
+                * to get the clones.  Do it by slowly iterating.
+                */
+               if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT)
+                       return (NULL);
+               if (nvlist_alloc(&nv, NV_UNIQUE_NAME, 0) != 0)
+                       return (NULL);
+               if (nvlist_alloc(&value, NV_UNIQUE_NAME, 0) != 0) {
+                       nvlist_free(nv);
+                       return (NULL);
+               }
+
+               gca.numclones = zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES);
+               gca.value = value;
+               gca.origin = zhp->zfs_name;
+
+               if (gca.numclones != 0) {
+                       zfs_handle_t *root;
+                       char pool[ZFS_MAX_DATASET_NAME_LEN];
+                       char *cp = pool;
+
+                       /* get the pool name */
+                       (void) strlcpy(pool, zhp->zfs_name, sizeof (pool));
+                       (void) strsep(&cp, "/@");
+                       root = zfs_open(zhp->zfs_hdl, pool,
+                           ZFS_TYPE_FILESYSTEM);
+                       if (root == NULL) {
+                               nvlist_free(nv);
+                               nvlist_free(value);
+                               return (NULL);
+                       }
+
+                       (void) get_clones_cb(root, &gca);
+               }
+
+               if (gca.numclones != 0 ||
+                   nvlist_add_nvlist(nv, ZPROP_VALUE, value) != 0 ||
+                   nvlist_add_nvlist(zhp->zfs_props,
+                   zfs_prop_to_name(ZFS_PROP_CLONES), nv) != 0) {
+                       nvlist_free(nv);
+                       nvlist_free(value);
+                       return (NULL);
+               }
+               nvlist_free(nv);
+               nvlist_free(value);
+               verify(0 == nvlist_lookup_nvlist(zhp->zfs_props,
+                   zfs_prop_to_name(ZFS_PROP_CLONES), &nv));
+       }
+
+       verify(nvlist_lookup_nvlist(nv, ZPROP_VALUE, &value) == 0);
+
+       return (value);
+}
+
+/*
+ * Retrieve a property from the given object.  If 'literal' is specified, then
+ * numbers are left as exact values.  Otherwise, numbers are converted to a
+ * human-readable form.
+ *
+ * Returns 0 on success, or -1 on error.
+ */
+int
+zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
+    zprop_source_t *src, char *statbuf, size_t statlen, boolean_t literal)
+{
+       char *source = NULL;
+       uint64_t val;
+       const char *str;
+       const char *strval;
+       boolean_t received = zfs_is_recvd_props_mode(zhp);
+
+       /*
+        * Check to see if this property applies to our object
+        */
+       if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE))
+               return (-1);
+
+       if (received && zfs_prop_readonly(prop))
+               return (-1);
+
+       if (src)
+               *src = ZPROP_SRC_NONE;
+
+       switch (prop) {
+       case ZFS_PROP_CREATION:
+               /*
+                * 'creation' is a time_t stored in the statistics.  We convert
+                * this into a string unless 'literal' is specified.
+                */
+               {
+                       val = getprop_uint64(zhp, prop, &source);
+                       time_t time = (time_t)val;
+                       struct tm t;
+
+                       if (literal ||
+                           localtime_r(&time, &t) == NULL ||
+                           strftime(propbuf, proplen, "%a %b %e %k:%M %Y",
+                           &t) == 0)
+                               (void) snprintf(propbuf, proplen, "%llu",
+                                   (u_longlong_t) val);
+               }
+               break;
+
+       case ZFS_PROP_MOUNTPOINT:
+               /*
+                * Getting the precise mountpoint can be tricky.
+                *
+                *  - for 'none' or 'legacy', return those values.
+                *  - for inherited mountpoints, we want to take everything
+                *    after our ancestor and append it to the inherited value.
+                *
+                * If the pool has an alternate root, we want to prepend that
+                * root to any values we return.
+                */
+
+               str = getprop_string(zhp, prop, &source);
+
+               if (str[0] == '/') {
+                       char buf[MAXPATHLEN];
+                       char *root = buf;
+                       const char *relpath;
+
+                       /*
+                        * If we inherit the mountpoint, even from a dataset
+                        * with a received value, the source will be the path of
+                        * the dataset we inherit from. If source is
+                        * ZPROP_SOURCE_VAL_RECVD, the received value is not
+                        * inherited.
+                        */
+                       if (strcmp(source, ZPROP_SOURCE_VAL_RECVD) == 0) {
+                               relpath = "";
+                       } else {
+                               relpath = zhp->zfs_name + strlen(source);
+                               if (relpath[0] == '/')
+                                       relpath++;
+                       }
+
+                       if ((zpool_get_prop(zhp->zpool_hdl,
+                           ZPOOL_PROP_ALTROOT, buf, MAXPATHLEN, NULL,
+                           B_FALSE)) || (strcmp(root, "-") == 0))
+                               root[0] = '\0';
+                       /*
+                        * Special case an alternate root of '/'. This will
+                        * avoid having multiple leading slashes in the
+                        * mountpoint path.
+                        */
+                       if (strcmp(root, "/") == 0)
+                               root++;
+
+                       /*
+                        * If the mountpoint is '/' then skip over this
+                        * if we are obtaining either an alternate root or
+                        * an inherited mountpoint.
+                        */
+                       if (str[1] == '\0' && (root[0] != '\0' ||
+                           relpath[0] != '\0'))
+                               str++;
+
+                       if (relpath[0] == '\0')
+                               (void) snprintf(propbuf, proplen, "%s%s",
+                                   root, str);
+                       else
+                               (void) snprintf(propbuf, proplen, "%s%s%s%s",
+                                   root, str, relpath[0] == '@' ? "" : "/",
+                                   relpath);
+               } else {
+                       /* 'legacy' or 'none' */
+                       (void) strlcpy(propbuf, str, proplen);
+               }
+
+               break;
+
+       case ZFS_PROP_ORIGIN:
+               str = getprop_string(zhp, prop, &source);
+               if (str == NULL)
+                       return (-1);
+               (void) strlcpy(propbuf, str, proplen);
+               break;
+
+       case ZFS_PROP_CLONES:
+               if (get_clones_string(zhp, propbuf, proplen) != 0)
+                       return (-1);
+               break;
+
+       case ZFS_PROP_QUOTA:
+       case ZFS_PROP_REFQUOTA:
+       case ZFS_PROP_RESERVATION:
+       case ZFS_PROP_REFRESERVATION:
+
+               if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+                       return (-1);
+
+               /*
+                * If quota or reservation is 0, we translate this into 'none'
+                * (unless literal is set), and indicate that it's the default
+                * value.  Otherwise, we print the number nicely and indicate
+                * that its set locally.
+                */
+               if (val == 0) {
+                       if (literal)
+                               (void) strlcpy(propbuf, "0", proplen);
+                       else
+                               (void) strlcpy(propbuf, "none", proplen);
+               } else {
+                       if (literal)
+                               (void) snprintf(propbuf, proplen, "%llu",
+                                   (u_longlong_t)val);
+                       else
+                               zfs_nicenum(val, propbuf, proplen);
+               }
+               break;
+
+       case ZFS_PROP_FILESYSTEM_LIMIT:
+       case ZFS_PROP_SNAPSHOT_LIMIT:
+       case ZFS_PROP_FILESYSTEM_COUNT:
+       case ZFS_PROP_SNAPSHOT_COUNT:
+
+               if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+                       return (-1);
+
+               /*
+                * If limit is UINT64_MAX, we translate this into 'none' (unless
+                * literal is set), and indicate that it's the default value.
+                * Otherwise, we print the number nicely and indicate that it's
+                * set locally.
+                */
+               if (literal) {
+                       (void) snprintf(propbuf, proplen, "%llu",
+                           (u_longlong_t)val);
+               } else if (val == UINT64_MAX) {
+                       (void) strlcpy(propbuf, "none", proplen);
+               } else {
+                       zfs_nicenum(val, propbuf, proplen);
+               }
+               break;
+
+       case ZFS_PROP_REFRATIO:
+       case ZFS_PROP_COMPRESSRATIO:
+               if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+                       return (-1);
+               (void) snprintf(propbuf, proplen, "%llu.%02llux",
+                   (u_longlong_t)(val / 100),
+                   (u_longlong_t)(val % 100));
+               break;
+
+       case ZFS_PROP_TYPE:
+               switch (zhp->zfs_type) {
+               case ZFS_TYPE_FILESYSTEM:
+                       str = "filesystem";
+                       break;
+               case ZFS_TYPE_VOLUME:
+                       str = "volume";
+                       break;
+               case ZFS_TYPE_SNAPSHOT:
+                       str = "snapshot";
+                       break;
+               case ZFS_TYPE_BOOKMARK:
+                       str = "bookmark";
+                       break;
+               default:
+                       abort();
+               }
+               (void) snprintf(propbuf, proplen, "%s", str);
+               break;
+
+       case ZFS_PROP_MOUNTED:
+               /*
+                * The 'mounted' property is a pseudo-property that described
+                * whether the filesystem is currently mounted.  Even though
+                * it's a boolean value, the typical values of "on" and "off"
+                * don't make sense, so we translate to "yes" and "no".
+                */
+               if (get_numeric_property(zhp, ZFS_PROP_MOUNTED,
+                   src, &source, &val) != 0)
+                       return (-1);
+               if (val)
+                       (void) strlcpy(propbuf, "yes", proplen);
+               else
+                       (void) strlcpy(propbuf, "no", proplen);
+               break;
+
+       case ZFS_PROP_NAME:
+               /*
+                * The 'name' property is a pseudo-property derived from the
+                * dataset name.  It is presented as a real property to simplify
+                * consumers.
+                */
+               (void) strlcpy(propbuf, zhp->zfs_name, proplen);
+               break;
+
+       case ZFS_PROP_MLSLABEL:
+               {
+#ifdef HAVE_MLSLABEL
+                       m_label_t *new_sl = NULL;
+                       char *ascii = NULL;     /* human readable label */
+
+                       (void) strlcpy(propbuf,
+                           getprop_string(zhp, prop, &source), proplen);
+
+                       if (literal || (strcasecmp(propbuf,
+                           ZFS_MLSLABEL_DEFAULT) == 0))
+                               break;
+
+                       /*
+                        * Try to translate the internal hex string to
+                        * human-readable output.  If there are any
+                        * problems just use the hex string.
+                        */
+
+                       if (str_to_label(propbuf, &new_sl, MAC_LABEL,
+                           L_NO_CORRECTION, NULL) == -1) {
+                               m_label_free(new_sl);
+                               break;
+                       }
+
+                       if (label_to_str(new_sl, &ascii, M_LABEL,
+                           DEF_NAMES) != 0) {
+                               if (ascii)
+                                       free(ascii);
+                               m_label_free(new_sl);
+                               break;
+                       }
+                       m_label_free(new_sl);
+
+                       (void) strlcpy(propbuf, ascii, proplen);
+                       free(ascii);
+#else
+                       (void) strlcpy(propbuf,
+                           getprop_string(zhp, prop, &source), proplen);
+#endif /* HAVE_MLSLABEL */
+               }
+               break;
+
+       case ZFS_PROP_GUID:
+               /*
+                * GUIDs are stored as numbers, but they are identifiers.
+                * We don't want them to be pretty printed, because pretty
+                * printing mangles the ID into a truncated and useless value.
+                */
+               if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+                       return (-1);
+               (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
+               break;
+
+       default:
+               switch (zfs_prop_get_type(prop)) {
+               case PROP_TYPE_NUMBER:
+                       if (get_numeric_property(zhp, prop, src,
+                           &source, &val) != 0)
+                               return (-1);
+                       if (literal)
+                               (void) snprintf(propbuf, proplen, "%llu",
+                                   (u_longlong_t)val);
+                       else
+                               zfs_nicenum(val, propbuf, proplen);
+                       break;
+
+               case PROP_TYPE_STRING:
+                       str = getprop_string(zhp, prop, &source);
+                       if (str == NULL)
+                               return (-1);
+                       (void) strlcpy(propbuf, str, proplen);
+                       break;
+
+               case PROP_TYPE_INDEX:
+                       if (get_numeric_property(zhp, prop, src,
+                           &source, &val) != 0)
+                               return (-1);
+                       if (zfs_prop_index_to_string(prop, val, &strval) != 0)
+                               return (-1);
+                       (void) strlcpy(propbuf, strval, proplen);
+                       break;
+
+               default:
+                       abort();
+               }
+       }
+
+       get_source(zhp, src, source, statbuf, statlen);
+
+       return (0);
+}
+
+/*
+ * Utility function to get the given numeric property.  Does no validation that
+ * the given property is the appropriate type; should only be used with
+ * hard-coded property types.
+ */
+uint64_t
+zfs_prop_get_int(zfs_handle_t *zhp, zfs_prop_t prop)
+{
+       char *source;
+       uint64_t val = 0;
+
+       (void) get_numeric_property(zhp, prop, NULL, &source, &val);
+
+       return (val);
+}
+
+int
+zfs_prop_set_int(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t val)
+{
+       char buf[64];
+
+       (void) snprintf(buf, sizeof (buf), "%llu", (longlong_t)val);
+       return (zfs_prop_set(zhp, zfs_prop_to_name(prop), buf));
+}
+
+/*
+ * Similar to zfs_prop_get(), but returns the value as an integer.
+ */
+int
+zfs_prop_get_numeric(zfs_handle_t *zhp, zfs_prop_t prop, uint64_t *value,
+    zprop_source_t *src, char *statbuf, size_t statlen)
+{
+       char *source;
+
+       /*
+        * Check to see if this property applies to our object
+        */
+       if (!zfs_prop_valid_for_type(prop, zhp->zfs_type, B_FALSE)) {
+               return (zfs_error_fmt(zhp->zfs_hdl, EZFS_PROPTYPE,
+                   dgettext(TEXT_DOMAIN, "cannot get property '%s'"),
+                   zfs_prop_to_name(prop)));
+       }
+
+       if (src)
+               *src = ZPROP_SRC_NONE;
+
+       if (get_numeric_property(zhp, prop, src, &source, value) != 0)
+               return (-1);
+
+       get_source(zhp, src, source, statbuf, statlen);
+
+       return (0);
+}
+
+#ifdef HAVE_IDMAP
+static int
+idmap_id_to_numeric_domain_rid(uid_t id, boolean_t isuser,
+    char **domainp, idmap_rid_t *ridp)
+{
+       idmap_get_handle_t *get_hdl = NULL;
+       idmap_stat status;
+       int err = EINVAL;
+
+       if (idmap_get_create(&get_hdl) != IDMAP_SUCCESS)
+               goto out;
+
+       if (isuser) {
+               err = idmap_get_sidbyuid(get_hdl, id,
+                   IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
+       } else {
+               err = idmap_get_sidbygid(get_hdl, id,
+                   IDMAP_REQ_FLG_USE_CACHE, domainp, ridp, &status);
+       }
+       if (err == IDMAP_SUCCESS &&
+           idmap_get_mappings(get_hdl) == IDMAP_SUCCESS &&
+           status == IDMAP_SUCCESS)
+               err = 0;
+       else
+               err = EINVAL;
+out:
+       if (get_hdl)
+               idmap_get_destroy(get_hdl);
+       return (err);
+}
+#endif /* HAVE_IDMAP */
+
+/*
+ * convert the propname into parameters needed by kernel
+ * Eg: userquota@ahrens -> ZFS_PROP_USERQUOTA, "", 126829
+ * Eg: userused@matt@domain -> ZFS_PROP_USERUSED, "S-1-123-456", 789
+ * Eg: groupquota@staff -> ZFS_PROP_GROUPQUOTA, "", 1234
+ * Eg: groupused@staff -> ZFS_PROP_GROUPUSED, "", 1234
+ */
+static int
+userquota_propname_decode(const char *propname, boolean_t zoned,
+    zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp)
+{
+       zfs_userquota_prop_t type;
+       char *cp;
+       boolean_t isuser;
+       boolean_t isgroup;
+       struct passwd *pw;
+       struct group *gr;
+
+       domain[0] = '\0';
+
+       /* Figure out the property type ({user|group}{quota|space}) */
+       for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) {
+               if (strncmp(propname, zfs_userquota_prop_prefixes[type],
+                   strlen(zfs_userquota_prop_prefixes[type])) == 0)
+                       break;
+       }
+       if (type == ZFS_NUM_USERQUOTA_PROPS)
+               return (EINVAL);
+       *typep = type;
+
+       isuser = (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_USERUSED ||
+                   type == ZFS_PROP_USEROBJQUOTA ||
+                   type == ZFS_PROP_USEROBJUSED);
+       isgroup = (type == ZFS_PROP_GROUPQUOTA || type == ZFS_PROP_GROUPUSED ||
+                   type == ZFS_PROP_GROUPOBJQUOTA ||
+                   type == ZFS_PROP_GROUPOBJUSED);
+
+       cp = strchr(propname, '@') + 1;
+
+       if (isuser && (pw = getpwnam(cp)) != NULL) {
+               if (zoned && getzoneid() == GLOBAL_ZONEID)
+                       return (ENOENT);
+               *ridp = pw->pw_uid;
+       } else if (isgroup && (gr = getgrnam(cp)) != NULL) {
+               if (zoned && getzoneid() == GLOBAL_ZONEID)
+                       return (ENOENT);
+               *ridp = gr->gr_gid;
+       } else if (strchr(cp, '@')) {
+#ifdef HAVE_IDMAP
+               /*
+                * It's a SID name (eg "user@domain") that needs to be
+                * turned into S-1-domainID-RID.
+                */
+               directory_error_t e;
+               char *numericsid = NULL;
+               char *end;
+
+               if (zoned && getzoneid() == GLOBAL_ZONEID)
+                       return (ENOENT);
+               if (isuser) {
+                       e = directory_sid_from_user_name(NULL,
+                           cp, &numericsid);
+               } else {
+                       e = directory_sid_from_group_name(NULL,
+                           cp, &numericsid);
+               }
+               if (e != NULL) {
+                       directory_error_free(e);
+                       return (ENOENT);
+               }
+               if (numericsid == NULL)
+                       return (ENOENT);
+               cp = numericsid;
+               (void) strlcpy(domain, cp, domainlen);
+               cp = strrchr(domain, '-');
+               *cp = '\0';
+               cp++;
+
+               errno = 0;
+               *ridp = strtoull(cp, &end, 10);
+               free(numericsid);
+
+               if (errno != 0 || *end != '\0')
+                       return (EINVAL);
+#else
+               return (ENOSYS);
+#endif /* HAVE_IDMAP */
+       } else {
+               /* It's a user/group ID (eg "12345"). */
+               uid_t id;
+               char *end;
+               id = strtoul(cp, &end, 10);
+               if (*end != '\0')
+                       return (EINVAL);
+               if (id > MAXUID) {
+#ifdef HAVE_IDMAP
+                       /* It's an ephemeral ID. */
+                       idmap_rid_t rid;
+                       char *mapdomain;
+
+                       if (idmap_id_to_numeric_domain_rid(id, isuser,
+                           &mapdomain, &rid) != 0)
+                               return (ENOENT);
+                       (void) strlcpy(domain, mapdomain, domainlen);
+                       *ridp = rid;
+#else
+                       return (ENOSYS);
+#endif /* HAVE_IDMAP */
+               } else {
+                       *ridp = id;
+               }
+       }
+
+       return (0);
+}
+
+static int
+zfs_prop_get_userquota_common(zfs_handle_t *zhp, const char *propname,
+    uint64_t *propvalue, zfs_userquota_prop_t *typep)
+{
+       int err;
+       zfs_cmd_t zc = {"\0"};
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       err = userquota_propname_decode(propname,
+           zfs_prop_get_int(zhp, ZFS_PROP_ZONED),
+           typep, zc.zc_value, sizeof (zc.zc_value), &zc.zc_guid);
+       zc.zc_objset_type = *typep;
+       if (err)
+               return (err);
+
+       err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_USERSPACE_ONE, &zc);
+       if (err)
+               return (err);
+
+       *propvalue = zc.zc_cookie;
+       return (0);
+}
+
+int
+zfs_prop_get_userquota_int(zfs_handle_t *zhp, const char *propname,
+    uint64_t *propvalue)
+{
+       zfs_userquota_prop_t type;
+
+       return (zfs_prop_get_userquota_common(zhp, propname, propvalue,
+           &type));
+}
+
+int
+zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
+    char *propbuf, int proplen, boolean_t literal)
+{
+       int err;
+       uint64_t propvalue;
+       zfs_userquota_prop_t type;
+
+       err = zfs_prop_get_userquota_common(zhp, propname, &propvalue,
+           &type);
+
+       if (err)
+               return (err);
+
+       if (literal) {
+               (void) snprintf(propbuf, proplen, "%llu",
+                   (u_longlong_t)propvalue);
+       } else if (propvalue == 0 &&
+           (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA ||
+           type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA)) {
+               (void) strlcpy(propbuf, "none", proplen);
+       } else {
+               zfs_nicenum(propvalue, propbuf, proplen);
+       }
+       return (0);
+}
+
+int
+zfs_prop_get_written_int(zfs_handle_t *zhp, const char *propname,
+    uint64_t *propvalue)
+{
+       int err;
+       zfs_cmd_t zc = {"\0"};
+       const char *snapname;
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       snapname = strchr(propname, '@') + 1;
+       if (strchr(snapname, '@')) {
+               (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
+       } else {
+               /* snapname is the short name, append it to zhp's fsname */
+               char *cp;
+
+               (void) strlcpy(zc.zc_value, zhp->zfs_name,
+                   sizeof (zc.zc_value));
+               cp = strchr(zc.zc_value, '@');
+               if (cp != NULL)
+                       *cp = '\0';
+               (void) strlcat(zc.zc_value, "@", sizeof (zc.zc_value));
+               (void) strlcat(zc.zc_value, snapname, sizeof (zc.zc_value));
+       }
+
+       err = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_SPACE_WRITTEN, &zc);
+       if (err)
+               return (err);
+
+       *propvalue = zc.zc_cookie;
+       return (0);
+}
+
+int
+zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
+    char *propbuf, int proplen, boolean_t literal)
+{
+       int err;
+       uint64_t propvalue;
+
+       err = zfs_prop_get_written_int(zhp, propname, &propvalue);
+
+       if (err)
+               return (err);
+
+       if (literal) {
+               (void) snprintf(propbuf, proplen, "%llu",
+                   (u_longlong_t)propvalue);
+       } else {
+               zfs_nicenum(propvalue, propbuf, proplen);
+       }
+
+       return (0);
+}
+
+/*
+ * Returns the name of the given zfs handle.
+ */
+const char *
+zfs_get_name(const zfs_handle_t *zhp)
+{
+       return (zhp->zfs_name);
+}
+
+/*
+ * Returns the type of the given zfs handle.
+ */
+zfs_type_t
+zfs_get_type(const zfs_handle_t *zhp)
+{
+       return (zhp->zfs_type);
+}
+
+/*
+ * Is one dataset name a child dataset of another?
+ *
+ * Needs to handle these cases:
+ * Dataset 1   "a/foo"         "a/foo"         "a/foo"         "a/foo"
+ * Dataset 2   "a/fo"          "a/foobar"      "a/bar/baz"     "a/foo/bar"
+ * Descendant? No.             No.             No.             Yes.
+ */
+static boolean_t
+is_descendant(const char *ds1, const char *ds2)
+{
+       size_t d1len = strlen(ds1);
+
+       /* ds2 can't be a descendant if it's smaller */
+       if (strlen(ds2) < d1len)
+               return (B_FALSE);
+
+       /* otherwise, compare strings and verify that there's a '/' char */
+       return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
+}
+
+/*
+ * Given a complete name, return just the portion that refers to the parent.
+ * Will return -1 if there is no parent (path is just the name of the
+ * pool).
+ */
+static int
+parent_name(const char *path, char *buf, size_t buflen)
+{
+       char *slashp;
+
+       (void) strlcpy(buf, path, buflen);
+
+       if ((slashp = strrchr(buf, '/')) == NULL)
+               return (-1);
+       *slashp = '\0';
+
+       return (0);
+}
+
+/*
+ * If accept_ancestor is false, then check to make sure that the given path has
+ * a parent, and that it exists.  If accept_ancestor is true, then find the
+ * closest existing ancestor for the given path.  In prefixlen return the
+ * length of already existing prefix of the given path.  We also fetch the
+ * 'zoned' property, which is used to validate property settings when creating
+ * new datasets.
+ */
+static int
+check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
+    boolean_t accept_ancestor, int *prefixlen)
+{
+       zfs_cmd_t zc = {"\0"};
+       char parent[ZFS_MAX_DATASET_NAME_LEN];
+       char *slash;
+       zfs_handle_t *zhp;
+       char errbuf[1024];
+       uint64_t is_zoned;
+
+       (void) snprintf(errbuf, sizeof (errbuf),
+           dgettext(TEXT_DOMAIN, "cannot create '%s'"), path);
+
+       /* get parent, and check to see if this is just a pool */
+       if (parent_name(path, parent, sizeof (parent)) != 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "missing dataset name"));
+               return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+       }
+
+       /* check to see if the pool exists */
+       if ((slash = strchr(parent, '/')) == NULL)
+               slash = parent + strlen(parent);
+       (void) strncpy(zc.zc_name, parent, slash - parent);
+       zc.zc_name[slash - parent] = '\0';
+       if (ioctl(hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0 &&
+           errno == ENOENT) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "no such pool '%s'"), zc.zc_name);
+               return (zfs_error(hdl, EZFS_NOENT, errbuf));
+       }
+
+       /* check to see if the parent dataset exists */
+       while ((zhp = make_dataset_handle(hdl, parent)) == NULL) {
+               if (errno == ENOENT && accept_ancestor) {
+                       /*
+                        * Go deeper to find an ancestor, give up on top level.
+                        */
+                       if (parent_name(parent, parent, sizeof (parent)) != 0) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "no such pool '%s'"), zc.zc_name);
+                               return (zfs_error(hdl, EZFS_NOENT, errbuf));
+                       }
+               } else if (errno == ENOENT) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "parent does not exist"));
+                       return (zfs_error(hdl, EZFS_NOENT, errbuf));
+               } else
+                       return (zfs_standard_error(hdl, errno, errbuf));
+       }
+
+       is_zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED);
+       if (zoned != NULL)
+               *zoned = is_zoned;
+
+       /* we are in a non-global zone, but parent is in the global zone */
+       if (getzoneid() != GLOBAL_ZONEID && !is_zoned) {
+               (void) zfs_standard_error(hdl, EPERM, errbuf);
+               zfs_close(zhp);
+               return (-1);
+       }
+
+       /* make sure parent is a filesystem */
+       if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "parent is not a filesystem"));
+               (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+               zfs_close(zhp);
+               return (-1);
+       }
+
+       zfs_close(zhp);
+       if (prefixlen != NULL)
+               *prefixlen = strlen(parent);
+       return (0);
+}
+
+/*
+ * Finds whether the dataset of the given type(s) exists.
+ */
+boolean_t
+zfs_dataset_exists(libzfs_handle_t *hdl, const char *path, zfs_type_t types)
+{
+       zfs_handle_t *zhp;
+
+       if (!zfs_validate_name(hdl, path, types, B_FALSE))
+               return (B_FALSE);
+
+       /*
+        * Try to get stats for the dataset, which will tell us if it exists.
+        */
+       if ((zhp = make_dataset_handle(hdl, path)) != NULL) {
+               int ds_type = zhp->zfs_type;
+
+               zfs_close(zhp);
+               if (types & ds_type)
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+/*
+ * Given a path to 'target', create all the ancestors between
+ * the prefixlen portion of the path, and the target itself.
+ * Fail if the initial prefixlen-ancestor does not already exist.
+ */
+int
+create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
+{
+       zfs_handle_t *h;
+       char *cp;
+       const char *opname;
+
+       /* make sure prefix exists */
+       cp = target + prefixlen;
+       if (*cp != '/') {
+               assert(strchr(cp, '/') == NULL);
+               h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
+       } else {
+               *cp = '\0';
+               h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
+               *cp = '/';
+       }
+       if (h == NULL)
+               return (-1);
+       zfs_close(h);
+
+       /*
+        * Attempt to create, mount, and share any ancestor filesystems,
+        * up to the prefixlen-long one.
+        */
+       for (cp = target + prefixlen + 1;
+           (cp = strchr(cp, '/')); *cp = '/', cp++) {
+
+               *cp = '\0';
+
+               h = make_dataset_handle(hdl, target);
+               if (h) {
+                       /* it already exists, nothing to do here */
+                       zfs_close(h);
+                       continue;
+               }
+
+               if (zfs_create(hdl, target, ZFS_TYPE_FILESYSTEM,
+                   NULL) != 0) {
+                       opname = dgettext(TEXT_DOMAIN, "create");
+                       goto ancestorerr;
+               }
+
+               h = zfs_open(hdl, target, ZFS_TYPE_FILESYSTEM);
+               if (h == NULL) {
+                       opname = dgettext(TEXT_DOMAIN, "open");
+                       goto ancestorerr;
+               }
+
+               if (zfs_mount(h, NULL, 0) != 0) {
+                       opname = dgettext(TEXT_DOMAIN, "mount");
+                       goto ancestorerr;
+               }
+
+               if (zfs_share(h) != 0) {
+                       opname = dgettext(TEXT_DOMAIN, "share");
+                       goto ancestorerr;
+               }
+
+               zfs_close(h);
+       }
+
+       return (0);
+
+ancestorerr:
+       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+           "failed to %s ancestor '%s'"), opname, target);
+       return (-1);
+}
+
+/*
+ * Creates non-existing ancestors of the given path.
+ */
+int
+zfs_create_ancestors(libzfs_handle_t *hdl, const char *path)
+{
+       int prefix;
+       char *path_copy;
+       int rc = 0;
+
+       if (check_parents(hdl, path, NULL, B_TRUE, &prefix) != 0)
+               return (-1);
+
+       if ((path_copy = strdup(path)) != NULL) {
+               rc = create_parents(hdl, path_copy, prefix);
+               free(path_copy);
+       }
+       if (path_copy == NULL || rc != 0)
+               return (-1);
+
+       return (0);
+}
+
+/*
+ * Create a new filesystem or volume.
+ */
+int
+zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
+    nvlist_t *props)
+{
+       int ret;
+       uint64_t size = 0;
+       uint64_t blocksize = zfs_prop_default_numeric(ZFS_PROP_VOLBLOCKSIZE);
+       char errbuf[1024];
+       uint64_t zoned;
+       dmu_objset_type_t ost;
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot create '%s'"), path);
+
+       /* validate the path, taking care to note the extended error message */
+       if (!zfs_validate_name(hdl, path, type, B_TRUE))
+               return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+       /* validate parents exist */
+       if (check_parents(hdl, path, &zoned, B_FALSE, NULL) != 0)
+               return (-1);
+
+       /*
+        * The failure modes when creating a dataset of a different type over
+        * one that already exists is a little strange.  In particular, if you
+        * try to create a dataset on top of an existing dataset, the ioctl()
+        * will return ENOENT, not EEXIST.  To prevent this from happening, we
+        * first try to see if the dataset exists.
+        */
+       if (zfs_dataset_exists(hdl, path, ZFS_TYPE_DATASET)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "dataset already exists"));
+               return (zfs_error(hdl, EZFS_EXISTS, errbuf));
+       }
+
+       if (type == ZFS_TYPE_VOLUME)
+               ost = DMU_OST_ZVOL;
+       else
+               ost = DMU_OST_ZFS;
+
+       /* open zpool handle for prop validation */
+       char pool_path[ZFS_MAX_DATASET_NAME_LEN];
+       (void) strlcpy(pool_path, path, sizeof (pool_path));
+
+       /* truncate pool_path at first slash */
+       char *p = strchr(pool_path, '/');
+       if (p != NULL)
+               *p = '\0';
+
+       zpool_handle_t *zpool_handle = zpool_open(hdl, pool_path);
+
+       if (props && (props = zfs_valid_proplist(hdl, type, props,
+           zoned, NULL, zpool_handle, errbuf)) == 0) {
+               zpool_close(zpool_handle);
+               return (-1);
+       }
+       zpool_close(zpool_handle);
+
+       if (type == ZFS_TYPE_VOLUME) {
+               /*
+                * If we are creating a volume, the size and block size must
+                * satisfy a few restraints.  First, the blocksize must be a
+                * valid block size between SPA_{MIN,MAX}BLOCKSIZE.  Second, the
+                * volsize must be a multiple of the block size, and cannot be
+                * zero.
+                */
+               if (props == NULL || nvlist_lookup_uint64(props,
+                   zfs_prop_to_name(ZFS_PROP_VOLSIZE), &size) != 0) {
+                       nvlist_free(props);
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "missing volume size"));
+                       return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+               }
+
+               if ((ret = nvlist_lookup_uint64(props,
+                   zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+                   &blocksize)) != 0) {
+                       if (ret == ENOENT) {
+                               blocksize = zfs_prop_default_numeric(
+                                   ZFS_PROP_VOLBLOCKSIZE);
+                       } else {
+                               nvlist_free(props);
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "missing volume block size"));
+                               return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+                       }
+               }
+
+               if (size == 0) {
+                       nvlist_free(props);
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "volume size cannot be zero"));
+                       return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+               }
+
+               if (size % blocksize != 0) {
+                       nvlist_free(props);
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "volume size must be a multiple of volume block "
+                           "size"));
+                       return (zfs_error(hdl, EZFS_BADPROP, errbuf));
+               }
+       }
+
+       /* create the dataset */
+       ret = lzc_create(path, ost, props);
+       nvlist_free(props);
+
+       /* check for failure */
+       if (ret != 0) {
+               char parent[ZFS_MAX_DATASET_NAME_LEN];
+               (void) parent_name(path, parent, sizeof (parent));
+
+               switch (errno) {
+               case ENOENT:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "no such parent '%s'"), parent);
+                       return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+               case EINVAL:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "parent '%s' is not a filesystem"), parent);
+                       return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+
+               case ENOTSUP:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "pool must be upgraded to set this "
+                           "property or value"));
+                       return (zfs_error(hdl, EZFS_BADVERSION, errbuf));
+#ifdef _ILP32
+               case EOVERFLOW:
+                       /*
+                        * This platform can't address a volume this big.
+                        */
+                       if (type == ZFS_TYPE_VOLUME)
+                               return (zfs_error(hdl, EZFS_VOLTOOBIG,
+                                   errbuf));
+#endif
+                       /* FALLTHROUGH */
+               default:
+                       return (zfs_standard_error(hdl, errno, errbuf));
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * Destroys the given dataset.  The caller must make sure that the filesystem
+ * isn't mounted, and that there are no active dependents. If the file system
+ * does not exist this function does nothing.
+ */
+int
+zfs_destroy(zfs_handle_t *zhp, boolean_t defer)
+{
+       zfs_cmd_t zc = {"\0"};
+
+       if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
+               nvlist_t *nv = fnvlist_alloc();
+               fnvlist_add_boolean(nv, zhp->zfs_name);
+               int error = lzc_destroy_bookmarks(nv, NULL);
+               fnvlist_free(nv);
+               if (error != 0) {
+                       return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
+                           dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+                           zhp->zfs_name));
+               }
+               return (0);
+       }
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       if (ZFS_IS_VOLUME(zhp)) {
+               zc.zc_objset_type = DMU_OST_ZVOL;
+       } else {
+               zc.zc_objset_type = DMU_OST_ZFS;
+       }
+
+       zc.zc_defer_destroy = defer;
+       if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 &&
+           errno != ENOENT) {
+               return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
+                   dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+                   zhp->zfs_name));
+       }
+
+       remove_mountpoint(zhp);
+
+       return (0);
+}
+
+struct destroydata {
+       nvlist_t *nvl;
+       const char *snapname;
+};
+
+static int
+zfs_check_snap_cb(zfs_handle_t *zhp, void *arg)
+{
+       struct destroydata *dd = arg;
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       int rv = 0;
+
+       (void) snprintf(name, sizeof (name),
+           "%s@%s", zhp->zfs_name, dd->snapname);
+
+       if (lzc_exists(name))
+               verify(nvlist_add_boolean(dd->nvl, name) == 0);
+
+       rv = zfs_iter_filesystems(zhp, zfs_check_snap_cb, dd);
+       zfs_close(zhp);
+       return (rv);
+}
+
+/*
+ * Destroys all snapshots with the given name in zhp & descendants.
+ */
+int
+zfs_destroy_snaps(zfs_handle_t *zhp, char *snapname, boolean_t defer)
+{
+       int ret;
+       struct destroydata dd = { 0 };
+
+       dd.snapname = snapname;
+       verify(nvlist_alloc(&dd.nvl, NV_UNIQUE_NAME, 0) == 0);
+       (void) zfs_check_snap_cb(zfs_handle_dup(zhp), &dd);
+
+       if (nvlist_empty(dd.nvl)) {
+               ret = zfs_standard_error_fmt(zhp->zfs_hdl, ENOENT,
+                   dgettext(TEXT_DOMAIN, "cannot destroy '%s@%s'"),
+                   zhp->zfs_name, snapname);
+       } else {
+               ret = zfs_destroy_snaps_nvl(zhp->zfs_hdl, dd.nvl, defer);
+       }
+       nvlist_free(dd.nvl);
+       return (ret);
+}
+
+/*
+ * Destroys all the snapshots named in the nvlist.
+ */
+int
+zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
+{
+       int ret;
+       nvlist_t *errlist = NULL;
+       nvpair_t *pair;
+
+       ret = lzc_destroy_snaps(snaps, defer, &errlist);
+
+       if (ret == 0) {
+               nvlist_free(errlist);
+               return (0);
+       }
+
+       if (nvlist_empty(errlist)) {
+               char errbuf[1024];
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN, "cannot destroy snapshots"));
+
+               ret = zfs_standard_error(hdl, ret, errbuf);
+       }
+       for (pair = nvlist_next_nvpair(errlist, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(errlist, pair)) {
+               char errbuf[1024];
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN, "cannot destroy snapshot %s"),
+                   nvpair_name(pair));
+
+               switch (fnvpair_value_int32(pair)) {
+               case EEXIST:
+                       zfs_error_aux(hdl,
+                           dgettext(TEXT_DOMAIN, "snapshot is cloned"));
+                       ret = zfs_error(hdl, EZFS_EXISTS, errbuf);
+                       break;
+               default:
+                       ret = zfs_standard_error(hdl, errno, errbuf);
+                       break;
+               }
+       }
+
+       nvlist_free(errlist);
+       return (ret);
+}
+
+/*
+ * Clones the given dataset.  The target must be of the same type as the source.
+ */
+int
+zfs_clone(zfs_handle_t *zhp, const char *target, nvlist_t *props)
+{
+       char parent[ZFS_MAX_DATASET_NAME_LEN];
+       int ret;
+       char errbuf[1024];
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       uint64_t zoned;
+
+       assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot create '%s'"), target);
+
+       /* validate the target/clone name */
+       if (!zfs_validate_name(hdl, target, ZFS_TYPE_FILESYSTEM, B_TRUE))
+               return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+       /* validate parents exist */
+       if (check_parents(hdl, target, &zoned, B_FALSE, NULL) != 0)
+               return (-1);
+
+       (void) parent_name(target, parent, sizeof (parent));
+
+       /* do the clone */
+
+       if (props) {
+               zfs_type_t type;
+               if (ZFS_IS_VOLUME(zhp)) {
+                       type = ZFS_TYPE_VOLUME;
+               } else {
+                       type = ZFS_TYPE_FILESYSTEM;
+               }
+               if ((props = zfs_valid_proplist(hdl, type, props, zoned,
+                   zhp, zhp->zpool_hdl, errbuf)) == NULL)
+                       return (-1);
+       }
+
+       ret = lzc_clone(target, zhp->zfs_name, props);
+       nvlist_free(props);
+
+       if (ret != 0) {
+               switch (errno) {
+
+               case ENOENT:
+                       /*
+                        * The parent doesn't exist.  We should have caught this
+                        * above, but there may a race condition that has since
+                        * destroyed the parent.
+                        *
+                        * At this point, we don't know whether it's the source
+                        * that doesn't exist anymore, or whether the target
+                        * dataset doesn't exist.
+                        */
+                       zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+                           "no such parent '%s'"), parent);
+                       return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
+
+               case EXDEV:
+                       zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+                           "source and target pools differ"));
+                       return (zfs_error(zhp->zfs_hdl, EZFS_CROSSTARGET,
+                           errbuf));
+
+               default:
+                       return (zfs_standard_error(zhp->zfs_hdl, errno,
+                           errbuf));
+               }
+       }
+
+       return (ret);
+}
+
+/*
+ * Promotes the given clone fs to be the clone parent.
+ */
+int
+zfs_promote(zfs_handle_t *zhp)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       zfs_cmd_t zc = {"\0"};
+       char parent[MAXPATHLEN];
+       int ret;
+       char errbuf[1024];
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot promote '%s'"), zhp->zfs_name);
+
+       if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "snapshots can not be promoted"));
+               return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+       }
+
+       (void) strlcpy(parent, zhp->zfs_dmustats.dds_origin, sizeof (parent));
+       if (parent[0] == '\0') {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "not a cloned filesystem"));
+               return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+       }
+
+       (void) strlcpy(zc.zc_value, zhp->zfs_dmustats.dds_origin,
+           sizeof (zc.zc_value));
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+       ret = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
+
+       if (ret != 0) {
+               int save_errno = errno;
+
+               switch (save_errno) {
+               case EEXIST:
+                       /* There is a conflicting snapshot name. */
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "conflicting snapshot '%s' from parent '%s'"),
+                           zc.zc_string, parent);
+                       return (zfs_error(hdl, EZFS_EXISTS, errbuf));
+
+               default:
+                       return (zfs_standard_error(hdl, save_errno, errbuf));
+               }
+       }
+       return (ret);
+}
+
+typedef struct snapdata {
+       nvlist_t *sd_nvl;
+       const char *sd_snapname;
+} snapdata_t;
+
+static int
+zfs_snapshot_cb(zfs_handle_t *zhp, void *arg)
+{
+       snapdata_t *sd = arg;
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       int rv = 0;
+
+       if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) == 0) {
+               (void) snprintf(name, sizeof (name),
+                   "%s@%s", zfs_get_name(zhp), sd->sd_snapname);
+
+               fnvlist_add_boolean(sd->sd_nvl, name);
+
+               rv = zfs_iter_filesystems(zhp, zfs_snapshot_cb, sd);
+       }
+       zfs_close(zhp);
+
+       return (rv);
+}
+
+/*
+ * Creates snapshots.  The keys in the snaps nvlist are the snapshots to be
+ * created.
+ */
+int
+zfs_snapshot_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, nvlist_t *props)
+{
+       int ret;
+       char errbuf[1024];
+       nvpair_t *elem;
+       nvlist_t *errors;
+       zpool_handle_t *zpool_hdl;
+       char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot create snapshots "));
+
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(snaps, elem)) != NULL) {
+               const char *snapname = nvpair_name(elem);
+
+               /* validate the target name */
+               if (!zfs_validate_name(hdl, snapname, ZFS_TYPE_SNAPSHOT,
+                   B_TRUE)) {
+                       (void) snprintf(errbuf, sizeof (errbuf),
+                           dgettext(TEXT_DOMAIN,
+                           "cannot create snapshot '%s'"), snapname);
+                       return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+               }
+       }
+
+       /*
+        * get pool handle for prop validation. assumes all snaps are in the
+        * same pool, as does lzc_snapshot (below).
+        */
+       elem = nvlist_next_nvpair(snaps, NULL);
+       (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+       pool[strcspn(pool, "/@")] = '\0';
+       zpool_hdl = zpool_open(hdl, pool);
+       if (zpool_hdl == NULL)
+               return (-1);
+
+       if (props != NULL &&
+           (props = zfs_valid_proplist(hdl, ZFS_TYPE_SNAPSHOT,
+           props, B_FALSE, NULL, zpool_hdl, errbuf)) == NULL) {
+               zpool_close(zpool_hdl);
+               return (-1);
+       }
+       zpool_close(zpool_hdl);
+
+       ret = lzc_snapshot(snaps, props, &errors);
+
+       if (ret != 0) {
+               boolean_t printed = B_FALSE;
+               for (elem = nvlist_next_nvpair(errors, NULL);
+                   elem != NULL;
+                   elem = nvlist_next_nvpair(errors, elem)) {
+                       (void) snprintf(errbuf, sizeof (errbuf),
+                           dgettext(TEXT_DOMAIN,
+                           "cannot create snapshot '%s'"), nvpair_name(elem));
+                       (void) zfs_standard_error(hdl,
+                           fnvpair_value_int32(elem), errbuf);
+                       printed = B_TRUE;
+               }
+               if (!printed) {
+                       switch (ret) {
+                       case EXDEV:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "multiple snapshots of same "
+                                   "fs not allowed"));
+                               (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
+
+                               break;
+                       default:
+                               (void) zfs_standard_error(hdl, ret, errbuf);
+                       }
+               }
+       }
+
+       nvlist_free(props);
+       nvlist_free(errors);
+       return (ret);
+}
+
+int
+zfs_snapshot(libzfs_handle_t *hdl, const char *path, boolean_t recursive,
+    nvlist_t *props)
+{
+       int ret;
+       snapdata_t sd = { 0 };
+       char fsname[ZFS_MAX_DATASET_NAME_LEN];
+       char *cp;
+       zfs_handle_t *zhp;
+       char errbuf[1024];
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot snapshot %s"), path);
+
+       if (!zfs_validate_name(hdl, path, ZFS_TYPE_SNAPSHOT, B_TRUE))
+               return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+       (void) strlcpy(fsname, path, sizeof (fsname));
+       cp = strchr(fsname, '@');
+       *cp = '\0';
+       sd.sd_snapname = cp + 1;
+
+       if ((zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM |
+           ZFS_TYPE_VOLUME)) == NULL) {
+               return (-1);
+       }
+
+       verify(nvlist_alloc(&sd.sd_nvl, NV_UNIQUE_NAME, 0) == 0);
+       if (recursive) {
+               (void) zfs_snapshot_cb(zfs_handle_dup(zhp), &sd);
+       } else {
+               fnvlist_add_boolean(sd.sd_nvl, path);
+       }
+
+       ret = zfs_snapshot_nvl(hdl, sd.sd_nvl, props);
+       nvlist_free(sd.sd_nvl);
+       zfs_close(zhp);
+       return (ret);
+}
+
+/*
+ * Destroy any more recent snapshots.  We invoke this callback on any dependents
+ * of the snapshot first.  If the 'cb_dependent' member is non-zero, then this
+ * is a dependent and we should just destroy it without checking the transaction
+ * group.
+ */
+typedef struct rollback_data {
+       const char      *cb_target;             /* the snapshot */
+       uint64_t        cb_create;              /* creation time reference */
+       boolean_t       cb_error;
+       boolean_t       cb_force;
+} rollback_data_t;
+
+static int
+rollback_destroy_dependent(zfs_handle_t *zhp, void *data)
+{
+       rollback_data_t *cbp = data;
+       prop_changelist_t *clp;
+
+       /* We must destroy this clone; first unmount it */
+       clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+           cbp->cb_force ? MS_FORCE: 0);
+       if (clp == NULL || changelist_prefix(clp) != 0) {
+               cbp->cb_error = B_TRUE;
+               zfs_close(zhp);
+               return (0);
+       }
+       if (zfs_destroy(zhp, B_FALSE) != 0)
+               cbp->cb_error = B_TRUE;
+       else
+               changelist_remove(clp, zhp->zfs_name);
+       (void) changelist_postfix(clp);
+       changelist_free(clp);
+
+       zfs_close(zhp);
+       return (0);
+}
+
+static int
+rollback_destroy(zfs_handle_t *zhp, void *data)
+{
+       rollback_data_t *cbp = data;
+
+       if (zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG) > cbp->cb_create) {
+               cbp->cb_error |= zfs_iter_dependents(zhp, B_FALSE,
+                   rollback_destroy_dependent, cbp);
+
+               cbp->cb_error |= zfs_destroy(zhp, B_FALSE);
+       }
+
+       zfs_close(zhp);
+       return (0);
+}
+
+/*
+ * Given a dataset, rollback to a specific snapshot, discarding any
+ * data changes since then and making it the active dataset.
+ *
+ * Any snapshots and bookmarks more recent than the target are
+ * destroyed, along with their dependents (i.e. clones).
+ */
+int
+zfs_rollback(zfs_handle_t *zhp, zfs_handle_t *snap, boolean_t force)
+{
+       rollback_data_t cb = { 0 };
+       int err;
+       boolean_t restore_resv = 0;
+       uint64_t old_volsize = 0, new_volsize;
+       zfs_prop_t resv_prop = { 0 };
+
+       assert(zhp->zfs_type == ZFS_TYPE_FILESYSTEM ||
+           zhp->zfs_type == ZFS_TYPE_VOLUME);
+
+       /*
+        * Destroy all recent snapshots and their dependents.
+        */
+       cb.cb_force = force;
+       cb.cb_target = snap->zfs_name;
+       cb.cb_create = zfs_prop_get_int(snap, ZFS_PROP_CREATETXG);
+       (void) zfs_iter_snapshots(zhp, B_FALSE, rollback_destroy, &cb);
+       (void) zfs_iter_bookmarks(zhp, rollback_destroy, &cb);
+
+       if (cb.cb_error)
+               return (-1);
+
+       /*
+        * Now that we have verified that the snapshot is the latest,
+        * rollback to the given snapshot.
+        */
+
+       if (zhp->zfs_type == ZFS_TYPE_VOLUME) {
+               if (zfs_which_resv_prop(zhp, &resv_prop) < 0)
+                       return (-1);
+               old_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
+               restore_resv =
+                   (old_volsize == zfs_prop_get_int(zhp, resv_prop));
+       }
+
+       /*
+        * We rely on zfs_iter_children() to verify that there are no
+        * newer snapshots for the given dataset.  Therefore, we can
+        * simply pass the name on to the ioctl() call.  There is still
+        * an unlikely race condition where the user has taken a
+        * snapshot since we verified that this was the most recent.
+        */
+       err = lzc_rollback(zhp->zfs_name, NULL, 0);
+       if (err != 0) {
+               (void) zfs_standard_error_fmt(zhp->zfs_hdl, errno,
+                   dgettext(TEXT_DOMAIN, "cannot rollback '%s'"),
+                   zhp->zfs_name);
+               return (err);
+       }
+
+       /*
+        * For volumes, if the pre-rollback volsize matched the pre-
+        * rollback reservation and the volsize has changed then set
+        * the reservation property to the post-rollback volsize.
+        * Make a new handle since the rollback closed the dataset.
+        */
+       if ((zhp->zfs_type == ZFS_TYPE_VOLUME) &&
+           (zhp = make_dataset_handle(zhp->zfs_hdl, zhp->zfs_name))) {
+               if (restore_resv) {
+                       new_volsize = zfs_prop_get_int(zhp, ZFS_PROP_VOLSIZE);
+                       if (old_volsize != new_volsize)
+                               err = zfs_prop_set_int(zhp, resv_prop,
+                                   new_volsize);
+               }
+               zfs_close(zhp);
+       }
+       return (err);
+}
+
+/*
+ * Renames the given dataset.
+ */
+int
+zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
+    boolean_t force_unmount)
+{
+       int ret;
+       zfs_cmd_t zc = {"\0"};
+       char *delim;
+       prop_changelist_t *cl = NULL;
+       zfs_handle_t *zhrp = NULL;
+       char *parentname = NULL;
+       char parent[ZFS_MAX_DATASET_NAME_LEN];
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       char errbuf[1024];
+
+       /* if we have the same exact name, just return success */
+       if (strcmp(zhp->zfs_name, target) == 0)
+               return (0);
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot rename to '%s'"), target);
+
+       /*
+        * Make sure the target name is valid
+        */
+       if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+               if ((strchr(target, '@') == NULL) ||
+                   *target == '@') {
+                       /*
+                        * Snapshot target name is abbreviated,
+                        * reconstruct full dataset name
+                        */
+                       (void) strlcpy(parent, zhp->zfs_name,
+                           sizeof (parent));
+                       delim = strchr(parent, '@');
+                       if (strchr(target, '@') == NULL)
+                               *(++delim) = '\0';
+                       else
+                               *delim = '\0';
+                       (void) strlcat(parent, target, sizeof (parent));
+                       target = parent;
+               } else {
+                       /*
+                        * Make sure we're renaming within the same dataset.
+                        */
+                       delim = strchr(target, '@');
+                       if (strncmp(zhp->zfs_name, target, delim - target)
+                           != 0 || zhp->zfs_name[delim - target] != '@') {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "snapshots must be part of same "
+                                   "dataset"));
+                               return (zfs_error(hdl, EZFS_CROSSTARGET,
+                                   errbuf));
+                       }
+               }
+               if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
+                       return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+       } else {
+               if (recursive) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "recursive rename must be a snapshot"));
+                       return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
+               }
+
+               if (!zfs_validate_name(hdl, target, zhp->zfs_type, B_TRUE))
+                       return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+
+               /* validate parents */
+               if (check_parents(hdl, target, NULL, B_FALSE, NULL) != 0)
+                       return (-1);
+
+               /* make sure we're in the same pool */
+               verify((delim = strchr(target, '/')) != NULL);
+               if (strncmp(zhp->zfs_name, target, delim - target) != 0 ||
+                   zhp->zfs_name[delim - target] != '/') {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "datasets must be within same pool"));
+                       return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+               }
+
+               /* new name cannot be a child of the current dataset name */
+               if (is_descendant(zhp->zfs_name, target)) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "New dataset name cannot be a descendant of "
+                           "current dataset name"));
+                       return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+               }
+       }
+
+       (void) snprintf(errbuf, sizeof (errbuf),
+           dgettext(TEXT_DOMAIN, "cannot rename '%s'"), zhp->zfs_name);
+
+       if (getzoneid() == GLOBAL_ZONEID &&
+           zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "dataset is used in a non-global zone"));
+               return (zfs_error(hdl, EZFS_ZONED, errbuf));
+       }
+
+       if (recursive) {
+               parentname = zfs_strdup(zhp->zfs_hdl, zhp->zfs_name);
+               if (parentname == NULL) {
+                       ret = -1;
+                       goto error;
+               }
+               delim = strchr(parentname, '@');
+               *delim = '\0';
+               zhrp = zfs_open(zhp->zfs_hdl, parentname, ZFS_TYPE_DATASET);
+               if (zhrp == NULL) {
+                       ret = -1;
+                       goto error;
+               }
+       } else if (zhp->zfs_type != ZFS_TYPE_SNAPSHOT) {
+               if ((cl = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+                   force_unmount ? MS_FORCE : 0)) == NULL)
+                       return (-1);
+
+               if (changelist_haszonedchild(cl)) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "child dataset with inherited mountpoint is used "
+                           "in a non-global zone"));
+                       (void) zfs_error(hdl, EZFS_ZONED, errbuf);
+                       ret = -1;
+                       goto error;
+               }
+
+               if ((ret = changelist_prefix(cl)) != 0)
+                       goto error;
+       }
+
+       if (ZFS_IS_VOLUME(zhp))
+               zc.zc_objset_type = DMU_OST_ZVOL;
+       else
+               zc.zc_objset_type = DMU_OST_ZFS;
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+       (void) strlcpy(zc.zc_value, target, sizeof (zc.zc_value));
+
+       zc.zc_cookie = recursive;
+
+       if ((ret = zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_RENAME, &zc)) != 0) {
+               /*
+                * if it was recursive, the one that actually failed will
+                * be in zc.zc_name
+                */
+               (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+                   "cannot rename '%s'"), zc.zc_name);
+
+               if (recursive && errno == EEXIST) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "a child dataset already has a snapshot "
+                           "with the new name"));
+                       (void) zfs_error(hdl, EZFS_EXISTS, errbuf);
+               } else {
+                       (void) zfs_standard_error(zhp->zfs_hdl, errno, errbuf);
+               }
+
+               /*
+                * On failure, we still want to remount any filesystems that
+                * were previously mounted, so we don't alter the system state.
+                */
+               if (cl != NULL)
+                       (void) changelist_postfix(cl);
+       } else {
+               if (cl != NULL) {
+                       changelist_rename(cl, zfs_get_name(zhp), target);
+                       ret = changelist_postfix(cl);
+               }
+       }
+
+error:
+       if (parentname != NULL) {
+               free(parentname);
+       }
+       if (zhrp != NULL) {
+               zfs_close(zhrp);
+       }
+       if (cl != NULL) {
+               changelist_free(cl);
+       }
+       return (ret);
+}
+
+nvlist_t *
+zfs_get_user_props(zfs_handle_t *zhp)
+{
+       return (zhp->zfs_user_props);
+}
+
+/*
+ * This function is used by 'zfs list' to determine the exact set of columns to
+ * display, and their maximum widths.  This does two main things:
+ *
+ *      - If this is a list of all properties, then expand the list to include
+ *        all native properties, and set a flag so that for each dataset we look
+ *        for new unique user properties and add them to the list.
+ *
+ *      - For non fixed-width properties, keep track of the maximum width seen
+ *        so that we can size the column appropriately. If the user has
+ *        requested received property values, we also need to compute the width
+ *        of the RECEIVED column.
+ */
+int
+zfs_expand_proplist(zfs_handle_t *zhp, zprop_list_t **plp, boolean_t received,
+    boolean_t literal)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       zprop_list_t *entry;
+       zprop_list_t **last, **start;
+       nvlist_t *userprops, *propval;
+       nvpair_t *elem;
+       char *strval;
+       char buf[ZFS_MAXPROPLEN];
+
+       if (zprop_expand_list(hdl, plp, ZFS_TYPE_DATASET) != 0)
+               return (-1);
+
+       userprops = zfs_get_user_props(zhp);
+
+       entry = *plp;
+       if (entry->pl_all && nvlist_next_nvpair(userprops, NULL) != NULL) {
+               /*
+                * Go through and add any user properties as necessary.  We
+                * start by incrementing our list pointer to the first
+                * non-native property.
+                */
+               start = plp;
+               while (*start != NULL) {
+                       if ((*start)->pl_prop == ZPROP_INVAL)
+                               break;
+                       start = &(*start)->pl_next;
+               }
+
+               elem = NULL;
+               while ((elem = nvlist_next_nvpair(userprops, elem)) != NULL) {
+                       /*
+                        * See if we've already found this property in our list.
+                        */
+                       for (last = start; *last != NULL;
+                           last = &(*last)->pl_next) {
+                               if (strcmp((*last)->pl_user_prop,
+                                   nvpair_name(elem)) == 0)
+                                       break;
+                       }
+
+                       if (*last == NULL) {
+                               if ((entry = zfs_alloc(hdl,
+                                   sizeof (zprop_list_t))) == NULL ||
+                                   ((entry->pl_user_prop = zfs_strdup(hdl,
+                                   nvpair_name(elem)))) == NULL) {
+                                       free(entry);
+                                       return (-1);
+                               }
+
+                               entry->pl_prop = ZPROP_INVAL;
+                               entry->pl_width = strlen(nvpair_name(elem));
+                               entry->pl_all = B_TRUE;
+                               *last = entry;
+                       }
+               }
+       }
+
+       /*
+        * Now go through and check the width of any non-fixed columns
+        */
+       for (entry = *plp; entry != NULL; entry = entry->pl_next) {
+               if (entry->pl_fixed && !literal)
+                       continue;
+
+               if (entry->pl_prop != ZPROP_INVAL) {
+                       if (zfs_prop_get(zhp, entry->pl_prop,
+                           buf, sizeof (buf), NULL, NULL, 0, literal) == 0) {
+                               if (strlen(buf) > entry->pl_width)
+                                       entry->pl_width = strlen(buf);
+                       }
+                       if (received && zfs_prop_get_recvd(zhp,
+                           zfs_prop_to_name(entry->pl_prop),
+                           buf, sizeof (buf), literal) == 0)
+                               if (strlen(buf) > entry->pl_recvd_width)
+                                       entry->pl_recvd_width = strlen(buf);
+               } else {
+                       if (nvlist_lookup_nvlist(userprops, entry->pl_user_prop,
+                           &propval) == 0) {
+                               verify(nvlist_lookup_string(propval,
+                                   ZPROP_VALUE, &strval) == 0);
+                               if (strlen(strval) > entry->pl_width)
+                                       entry->pl_width = strlen(strval);
+                       }
+                       if (received && zfs_prop_get_recvd(zhp,
+                           entry->pl_user_prop,
+                           buf, sizeof (buf), literal) == 0)
+                               if (strlen(buf) > entry->pl_recvd_width)
+                                       entry->pl_recvd_width = strlen(buf);
+               }
+       }
+
+       return (0);
+}
+
+void
+zfs_prune_proplist(zfs_handle_t *zhp, uint8_t *props)
+{
+       nvpair_t *curr;
+       nvpair_t *next;
+
+       /*
+        * Keep a reference to the props-table against which we prune the
+        * properties.
+        */
+       zhp->zfs_props_table = props;
+
+       curr = nvlist_next_nvpair(zhp->zfs_props, NULL);
+
+       while (curr) {
+               zfs_prop_t zfs_prop = zfs_name_to_prop(nvpair_name(curr));
+               next = nvlist_next_nvpair(zhp->zfs_props, curr);
+
+               /*
+                * User properties will result in ZPROP_INVAL, and since we
+                * only know how to prune standard ZFS properties, we always
+                * leave these in the list.  This can also happen if we
+                * encounter an unknown DSL property (when running older
+                * software, for example).
+                */
+               if (zfs_prop != ZPROP_INVAL && props[zfs_prop] == B_FALSE)
+                       (void) nvlist_remove(zhp->zfs_props,
+                           nvpair_name(curr), nvpair_type(curr));
+               curr = next;
+       }
+}
+
+static int
+zfs_smb_acl_mgmt(libzfs_handle_t *hdl, char *dataset, char *path,
+    zfs_smb_acl_op_t cmd, char *resource1, char *resource2)
+{
+       zfs_cmd_t zc = {"\0"};
+       nvlist_t *nvlist = NULL;
+       int error;
+
+       (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
+       (void) strlcpy(zc.zc_value, path, sizeof (zc.zc_value));
+       zc.zc_cookie = (uint64_t)cmd;
+
+       if (cmd == ZFS_SMB_ACL_RENAME) {
+               if (nvlist_alloc(&nvlist, NV_UNIQUE_NAME, 0) != 0) {
+                       (void) no_memory(hdl);
+                       return (0);
+               }
+       }
+
+       switch (cmd) {
+       case ZFS_SMB_ACL_ADD:
+       case ZFS_SMB_ACL_REMOVE:
+               (void) strlcpy(zc.zc_string, resource1, sizeof (zc.zc_string));
+               break;
+       case ZFS_SMB_ACL_RENAME:
+               if (nvlist_add_string(nvlist, ZFS_SMB_ACL_SRC,
+                   resource1) != 0) {
+                               (void) no_memory(hdl);
+                               return (-1);
+               }
+               if (nvlist_add_string(nvlist, ZFS_SMB_ACL_TARGET,
+                   resource2) != 0) {
+                               (void) no_memory(hdl);
+                               return (-1);
+               }
+               if (zcmd_write_src_nvlist(hdl, &zc, nvlist) != 0) {
+                       nvlist_free(nvlist);
+                       return (-1);
+               }
+               break;
+       case ZFS_SMB_ACL_PURGE:
+               break;
+       default:
+               return (-1);
+       }
+       error = ioctl(hdl->libzfs_fd, ZFS_IOC_SMB_ACL, &zc);
+       nvlist_free(nvlist);
+       return (error);
+}
+
+int
+zfs_smb_acl_add(libzfs_handle_t *hdl, char *dataset,
+    char *path, char *resource)
+{
+       return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_ADD,
+           resource, NULL));
+}
+
+int
+zfs_smb_acl_remove(libzfs_handle_t *hdl, char *dataset,
+    char *path, char *resource)
+{
+       return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_REMOVE,
+           resource, NULL));
+}
+
+int
+zfs_smb_acl_purge(libzfs_handle_t *hdl, char *dataset, char *path)
+{
+       return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_PURGE,
+           NULL, NULL));
+}
+
+int
+zfs_smb_acl_rename(libzfs_handle_t *hdl, char *dataset, char *path,
+    char *oldname, char *newname)
+{
+       return (zfs_smb_acl_mgmt(hdl, dataset, path, ZFS_SMB_ACL_RENAME,
+           oldname, newname));
+}
+
+int
+zfs_userspace(zfs_handle_t *zhp, zfs_userquota_prop_t type,
+    zfs_userspace_cb_t func, void *arg)
+{
+       zfs_cmd_t zc = {"\0"};
+       zfs_useracct_t buf[100];
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       int ret;
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       zc.zc_objset_type = type;
+       zc.zc_nvlist_dst = (uintptr_t)buf;
+
+       for (;;) {
+               zfs_useracct_t *zua = buf;
+
+               zc.zc_nvlist_dst_size = sizeof (buf);
+               if (zfs_ioctl(hdl, ZFS_IOC_USERSPACE_MANY, &zc) != 0) {
+                       char errbuf[1024];
+
+                       if ((errno == ENOTSUP &&
+                           (type == ZFS_PROP_USEROBJUSED ||
+                           type == ZFS_PROP_GROUPOBJUSED ||
+                           type == ZFS_PROP_USEROBJQUOTA ||
+                           type == ZFS_PROP_GROUPOBJQUOTA)))
+                               break;
+
+                       (void) snprintf(errbuf, sizeof (errbuf),
+                           dgettext(TEXT_DOMAIN,
+                           "cannot get used/quota for %s"), zc.zc_name);
+                       return (zfs_standard_error_fmt(hdl, errno, errbuf));
+               }
+               if (zc.zc_nvlist_dst_size == 0)
+                       break;
+
+               while (zc.zc_nvlist_dst_size > 0) {
+                       if ((ret = func(arg, zua->zu_domain, zua->zu_rid,
+                           zua->zu_space)) != 0)
+                               return (ret);
+                       zua++;
+                       zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
+               }
+       }
+
+       return (0);
+}
+
+struct holdarg {
+       nvlist_t *nvl;
+       const char *snapname;
+       const char *tag;
+       boolean_t recursive;
+       int error;
+};
+
+static int
+zfs_hold_one(zfs_handle_t *zhp, void *arg)
+{
+       struct holdarg *ha = arg;
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       int rv = 0;
+
+       (void) snprintf(name, sizeof (name),
+           "%s@%s", zhp->zfs_name, ha->snapname);
+
+       if (lzc_exists(name))
+               fnvlist_add_string(ha->nvl, name, ha->tag);
+
+       if (ha->recursive)
+               rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
+       zfs_close(zhp);
+       return (rv);
+}
+
+int
+zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
+    boolean_t recursive, int cleanup_fd)
+{
+       int ret;
+       struct holdarg ha;
+
+       ha.nvl = fnvlist_alloc();
+       ha.snapname = snapname;
+       ha.tag = tag;
+       ha.recursive = recursive;
+       (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
+
+       if (nvlist_empty(ha.nvl)) {
+               char errbuf[1024];
+
+               fnvlist_free(ha.nvl);
+               ret = ENOENT;
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "cannot hold snapshot '%s@%s'"),
+                   zhp->zfs_name, snapname);
+               (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
+               return (ret);
+       }
+
+       ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
+       fnvlist_free(ha.nvl);
+
+       return (ret);
+}
+
+int
+zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
+{
+       int ret;
+       nvlist_t *errors;
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       char errbuf[1024];
+       nvpair_t *elem;
+
+       errors = NULL;
+       ret = lzc_hold(holds, cleanup_fd, &errors);
+
+       if (ret == 0) {
+               /* There may be errors even in the success case. */
+               fnvlist_free(errors);
+               return (0);
+       }
+
+       if (nvlist_empty(errors)) {
+               /* no hold-specific errors */
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN, "cannot hold"));
+               switch (ret) {
+               case ENOTSUP:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "pool must be upgraded"));
+                       (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+                       break;
+               case EINVAL:
+                       (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+                       break;
+               default:
+                       (void) zfs_standard_error(hdl, ret, errbuf);
+               }
+       }
+
+       for (elem = nvlist_next_nvpair(errors, NULL);
+           elem != NULL;
+           elem = nvlist_next_nvpair(errors, elem)) {
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "cannot hold snapshot '%s'"), nvpair_name(elem));
+               switch (fnvpair_value_int32(elem)) {
+               case E2BIG:
+                       /*
+                        * Temporary tags wind up having the ds object id
+                        * prepended. So even if we passed the length check
+                        * above, it's still possible for the tag to wind
+                        * up being slightly too long.
+                        */
+                       (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
+                       break;
+               case EINVAL:
+                       (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+                       break;
+               case EEXIST:
+                       (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
+                       break;
+               default:
+                       (void) zfs_standard_error(hdl,
+                           fnvpair_value_int32(elem), errbuf);
+               }
+       }
+
+       fnvlist_free(errors);
+       return (ret);
+}
+
+static int
+zfs_release_one(zfs_handle_t *zhp, void *arg)
+{
+       struct holdarg *ha = arg;
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       int rv = 0;
+       nvlist_t *existing_holds;
+
+       (void) snprintf(name, sizeof (name),
+           "%s@%s", zhp->zfs_name, ha->snapname);
+
+       if (lzc_get_holds(name, &existing_holds) != 0) {
+               ha->error = ENOENT;
+       } else if (!nvlist_exists(existing_holds, ha->tag)) {
+               ha->error = ESRCH;
+       } else {
+               nvlist_t *torelease = fnvlist_alloc();
+               fnvlist_add_boolean(torelease, ha->tag);
+               fnvlist_add_nvlist(ha->nvl, name, torelease);
+               fnvlist_free(torelease);
+       }
+
+       if (ha->recursive)
+               rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
+       zfs_close(zhp);
+       return (rv);
+}
+
+int
+zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
+    boolean_t recursive)
+{
+       int ret;
+       struct holdarg ha;
+       nvlist_t *errors = NULL;
+       nvpair_t *elem;
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       char errbuf[1024];
+
+       ha.nvl = fnvlist_alloc();
+       ha.snapname = snapname;
+       ha.tag = tag;
+       ha.recursive = recursive;
+       ha.error = 0;
+       (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
+
+       if (nvlist_empty(ha.nvl)) {
+               fnvlist_free(ha.nvl);
+               ret = ha.error;
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "cannot release hold from snapshot '%s@%s'"),
+                   zhp->zfs_name, snapname);
+               if (ret == ESRCH) {
+                       (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
+               } else {
+                       (void) zfs_standard_error(hdl, ret, errbuf);
+               }
+               return (ret);
+       }
+
+       ret = lzc_release(ha.nvl, &errors);
+       fnvlist_free(ha.nvl);
+
+       if (ret == 0) {
+               /* There may be errors even in the success case. */
+               fnvlist_free(errors);
+               return (0);
+       }
+
+       if (nvlist_empty(errors)) {
+               /* no hold-specific errors */
+               (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+                   "cannot release"));
+               switch (errno) {
+               case ENOTSUP:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "pool must be upgraded"));
+                       (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+                       break;
+               default:
+                       (void) zfs_standard_error_fmt(hdl, errno, errbuf);
+               }
+       }
+
+       for (elem = nvlist_next_nvpair(errors, NULL);
+           elem != NULL;
+           elem = nvlist_next_nvpair(errors, elem)) {
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "cannot release hold from snapshot '%s'"),
+                   nvpair_name(elem));
+               switch (fnvpair_value_int32(elem)) {
+               case ESRCH:
+                       (void) zfs_error(hdl, EZFS_REFTAG_RELE, errbuf);
+                       break;
+               case EINVAL:
+                       (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
+                       break;
+               default:
+                       (void) zfs_standard_error_fmt(hdl,
+                           fnvpair_value_int32(elem), errbuf);
+               }
+       }
+
+       fnvlist_free(errors);
+       return (ret);
+}
+
+int
+zfs_get_fsacl(zfs_handle_t *zhp, nvlist_t **nvl)
+{
+       zfs_cmd_t zc = {"\0"};
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       int nvsz = 2048;
+       void *nvbuf;
+       int err = 0;
+       char errbuf[1024];
+
+       assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
+           zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
+
+tryagain:
+
+       nvbuf = malloc(nvsz);
+       if (nvbuf == NULL) {
+               err = (zfs_error(hdl, EZFS_NOMEM, strerror(errno)));
+               goto out;
+       }
+
+       zc.zc_nvlist_dst_size = nvsz;
+       zc.zc_nvlist_dst = (uintptr_t)nvbuf;
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       if (ioctl(hdl->libzfs_fd, ZFS_IOC_GET_FSACL, &zc) != 0) {
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN, "cannot get permissions on '%s'"),
+                   zc.zc_name);
+               switch (errno) {
+               case ENOMEM:
+                       free(nvbuf);
+                       nvsz = zc.zc_nvlist_dst_size;
+                       goto tryagain;
+
+               case ENOTSUP:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "pool must be upgraded"));
+                       err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
+                       break;
+               case EINVAL:
+                       err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
+                       break;
+               case ENOENT:
+                       err = zfs_error(hdl, EZFS_NOENT, errbuf);
+                       break;
+               default:
+                       err = zfs_standard_error_fmt(hdl, errno, errbuf);
+                       break;
+               }
+       } else {
+               /* success */
+               int rc = nvlist_unpack(nvbuf, zc.zc_nvlist_dst_size, nvl, 0);
+               if (rc) {
+                       (void) snprintf(errbuf, sizeof (errbuf), dgettext(
+                           TEXT_DOMAIN, "cannot get permissions on '%s'"),
+                           zc.zc_name);
+                       err = zfs_standard_error_fmt(hdl, rc, errbuf);
+               }
+       }
+
+       free(nvbuf);
+out:
+       return (err);
+}
+
+int
+zfs_set_fsacl(zfs_handle_t *zhp, boolean_t un, nvlist_t *nvl)
+{
+       zfs_cmd_t zc = {"\0"};
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       char *nvbuf;
+       char errbuf[1024];
+       size_t nvsz;
+       int err;
+
+       assert(zhp->zfs_type == ZFS_TYPE_VOLUME ||
+           zhp->zfs_type == ZFS_TYPE_FILESYSTEM);
+
+       err = nvlist_size(nvl, &nvsz, NV_ENCODE_NATIVE);
+       assert(err == 0);
+
+       nvbuf = malloc(nvsz);
+
+       err = nvlist_pack(nvl, &nvbuf, &nvsz, NV_ENCODE_NATIVE, 0);
+       assert(err == 0);
+
+       zc.zc_nvlist_src_size = nvsz;
+       zc.zc_nvlist_src = (uintptr_t)nvbuf;
+       zc.zc_perm_action = un;
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       if (zfs_ioctl(hdl, ZFS_IOC_SET_FSACL, &zc) != 0) {
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN, "cannot set permissions on '%s'"),
+                   zc.zc_name);
+               switch (errno) {
+               case ENOTSUP:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "pool must be upgraded"));
+                       err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
+                       break;
+               case EINVAL:
+                       err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
+                       break;
+               case ENOENT:
+                       err = zfs_error(hdl, EZFS_NOENT, errbuf);
+                       break;
+               default:
+                       err = zfs_standard_error_fmt(hdl, errno, errbuf);
+                       break;
+               }
+       }
+
+       free(nvbuf);
+
+       return (err);
+}
+
+int
+zfs_get_holds(zfs_handle_t *zhp, nvlist_t **nvl)
+{
+       int err;
+       char errbuf[1024];
+
+       err = lzc_get_holds(zhp->zfs_name, nvl);
+
+       if (err != 0) {
+               libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN, "cannot get holds for '%s'"),
+                   zhp->zfs_name);
+               switch (err) {
+               case ENOTSUP:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "pool must be upgraded"));
+                       err = zfs_error(hdl, EZFS_BADVERSION, errbuf);
+                       break;
+               case EINVAL:
+                       err = zfs_error(hdl, EZFS_BADTYPE, errbuf);
+                       break;
+               case ENOENT:
+                       err = zfs_error(hdl, EZFS_NOENT, errbuf);
+                       break;
+               default:
+                       err = zfs_standard_error_fmt(hdl, errno, errbuf);
+                       break;
+               }
+       }
+
+       return (err);
+}
+
+/*
+ * Convert the zvol's volume size to an appropriate reservation.
+ * Note: If this routine is updated, it is necessary to update the ZFS test
+ * suite's shell version in reservation.kshlib.
+ */
+uint64_t
+zvol_volsize_to_reservation(uint64_t volsize, nvlist_t *props)
+{
+       uint64_t numdb;
+       uint64_t nblocks, volblocksize;
+       int ncopies;
+       char *strval;
+
+       if (nvlist_lookup_string(props,
+           zfs_prop_to_name(ZFS_PROP_COPIES), &strval) == 0)
+               ncopies = atoi(strval);
+       else
+               ncopies = 1;
+       if (nvlist_lookup_uint64(props,
+           zfs_prop_to_name(ZFS_PROP_VOLBLOCKSIZE),
+           &volblocksize) != 0)
+               volblocksize = ZVOL_DEFAULT_BLOCKSIZE;
+       nblocks = volsize/volblocksize;
+       /* start with metadnode L0-L6 */
+       numdb = 7;
+       /* calculate number of indirects */
+       while (nblocks > 1) {
+               nblocks += DNODES_PER_LEVEL - 1;
+               nblocks /= DNODES_PER_LEVEL;
+               numdb += nblocks;
+       }
+       numdb *= MIN(SPA_DVAS_PER_BP, ncopies + 1);
+       volsize *= ncopies;
+       /*
+        * this is exactly DN_MAX_INDBLKSHIFT when metadata isn't
+        * compressed, but in practice they compress down to about
+        * 1100 bytes
+        */
+       numdb *= 1ULL << DN_MAX_INDBLKSHIFT;
+       volsize += numdb;
+       return (volsize);
+}
diff --git a/zfs/lib/libzfs/libzfs_diff.c b/zfs/lib/libzfs/libzfs_diff.c
new file mode 100644 (file)
index 0000000..419189a
--- /dev/null
@@ -0,0 +1,828 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2015 by Delphix. All rights reserved.
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * zfs diff support
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <libintl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <attr.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stropts.h>
+#include <pthread.h>
+#include <sys/zfs_ioctl.h>
+#include <libzfs.h>
+#include "libzfs_impl.h"
+
+#define        ZDIFF_SNAPDIR           "/.zfs/snapshot/"
+#define        ZDIFF_SHARESDIR         "/.zfs/shares/"
+#define        ZDIFF_PREFIX            "zfs-diff-%d"
+
+#define        ZDIFF_ADDED     '+'
+#define        ZDIFF_MODIFIED  'M'
+#define        ZDIFF_REMOVED   '-'
+#define        ZDIFF_RENAMED   'R'
+
+typedef struct differ_info {
+       zfs_handle_t *zhp;
+       char *fromsnap;
+       char *frommnt;
+       char *tosnap;
+       char *tomnt;
+       char *ds;
+       char *dsmnt;
+       char *tmpsnap;
+       char errbuf[1024];
+       boolean_t isclone;
+       boolean_t scripted;
+       boolean_t classify;
+       boolean_t timestamped;
+       uint64_t shares;
+       int zerr;
+       int cleanupfd;
+       int outputfd;
+       int datafd;
+} differ_info_t;
+
+/*
+ * Given a {dsname, object id}, get the object path
+ */
+static int
+get_stats_for_obj(differ_info_t *di, const char *dsname, uint64_t obj,
+    char *pn, int maxlen, zfs_stat_t *sb)
+{
+       zfs_cmd_t zc = {"\0"};
+       int error;
+
+       (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
+       zc.zc_obj = obj;
+
+       errno = 0;
+       error = ioctl(di->zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_STATS, &zc);
+       di->zerr = errno;
+
+       /* we can get stats even if we failed to get a path */
+       (void) memcpy(sb, &zc.zc_stat, sizeof (zfs_stat_t));
+       if (error == 0) {
+               ASSERT(di->zerr == 0);
+               (void) strlcpy(pn, zc.zc_value, maxlen);
+               return (0);
+       }
+
+       if (di->zerr == EPERM) {
+               (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "The sys_config privilege or diff delegated permission "
+                   "is needed\nto discover path names"));
+               return (-1);
+       } else {
+               (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "Unable to determine path or stats for "
+                   "object %lld in %s"), (longlong_t)obj, dsname);
+               return (-1);
+       }
+}
+
+/*
+ * stream_bytes
+ *
+ * Prints a file name out a character at a time.  If the character is
+ * not in the range of what we consider "printable" ASCII, display it
+ * as an escaped 4-digit octal value.  ASCII values less than a space
+ * are all control characters and we declare the upper end as the
+ * DELete character.  This also is the last 7-bit ASCII character.
+ * We choose to treat all 8-bit ASCII as not printable for this
+ * application.
+ */
+static void
+stream_bytes(FILE *fp, const char *string)
+{
+       char c;
+
+       while ((c = *string++) != '\0') {
+               if (c > ' ' && c != '\\' && c < '\177') {
+                       (void) fprintf(fp, "%c", c);
+               } else {
+                       (void) fprintf(fp, "\\%04o", (uint8_t)c);
+               }
+       }
+}
+
+static void
+print_what(FILE *fp, mode_t what)
+{
+       char symbol;
+
+       switch (what & S_IFMT) {
+       case S_IFBLK:
+               symbol = 'B';
+               break;
+       case S_IFCHR:
+               symbol = 'C';
+               break;
+       case S_IFDIR:
+               symbol = '/';
+               break;
+#ifdef S_IFDOOR
+       case S_IFDOOR:
+               symbol = '>';
+               break;
+#endif
+       case S_IFIFO:
+               symbol = '|';
+               break;
+       case S_IFLNK:
+               symbol = '@';
+               break;
+#ifdef S_IFPORT
+       case S_IFPORT:
+               symbol = 'P';
+               break;
+#endif
+       case S_IFSOCK:
+               symbol = '=';
+               break;
+       case S_IFREG:
+               symbol = 'F';
+               break;
+       default:
+               symbol = '?';
+               break;
+       }
+       (void) fprintf(fp, "%c", symbol);
+}
+
+static void
+print_cmn(FILE *fp, differ_info_t *di, const char *file)
+{
+       stream_bytes(fp, di->dsmnt);
+       stream_bytes(fp, file);
+}
+
+static void
+print_rename(FILE *fp, differ_info_t *di, const char *old, const char *new,
+    zfs_stat_t *isb)
+{
+       if (di->timestamped)
+               (void) fprintf(fp, "%10lld.%09lld\t",
+                   (longlong_t)isb->zs_ctime[0],
+                   (longlong_t)isb->zs_ctime[1]);
+       (void) fprintf(fp, "%c\t", ZDIFF_RENAMED);
+       if (di->classify) {
+               print_what(fp, isb->zs_mode);
+               (void) fprintf(fp, "\t");
+       }
+       print_cmn(fp, di, old);
+       if (di->scripted)
+               (void) fprintf(fp, "\t");
+       else
+               (void) fprintf(fp, " -> ");
+       print_cmn(fp, di, new);
+       (void) fprintf(fp, "\n");
+}
+
+static void
+print_link_change(FILE *fp, differ_info_t *di, int delta, const char *file,
+    zfs_stat_t *isb)
+{
+       if (di->timestamped)
+               (void) fprintf(fp, "%10lld.%09lld\t",
+                   (longlong_t)isb->zs_ctime[0],
+                   (longlong_t)isb->zs_ctime[1]);
+       (void) fprintf(fp, "%c\t", ZDIFF_MODIFIED);
+       if (di->classify) {
+               print_what(fp, isb->zs_mode);
+               (void) fprintf(fp, "\t");
+       }
+       print_cmn(fp, di, file);
+       (void) fprintf(fp, "\t(%+d)", delta);
+       (void) fprintf(fp, "\n");
+}
+
+static void
+print_file(FILE *fp, differ_info_t *di, char type, const char *file,
+    zfs_stat_t *isb)
+{
+       if (di->timestamped)
+               (void) fprintf(fp, "%10lld.%09lld\t",
+                   (longlong_t)isb->zs_ctime[0],
+                   (longlong_t)isb->zs_ctime[1]);
+       (void) fprintf(fp, "%c\t", type);
+       if (di->classify) {
+               print_what(fp, isb->zs_mode);
+               (void) fprintf(fp, "\t");
+       }
+       print_cmn(fp, di, file);
+       (void) fprintf(fp, "\n");
+}
+
+static int
+write_inuse_diffs_one(FILE *fp, differ_info_t *di, uint64_t dobj)
+{
+       struct zfs_stat fsb, tsb;
+       mode_t fmode, tmode;
+       char fobjname[MAXPATHLEN], tobjname[MAXPATHLEN];
+       int fobjerr, tobjerr;
+       int change;
+
+       if (dobj == di->shares)
+               return (0);
+
+       /*
+        * Check the from and to snapshots for info on the object. If
+        * we get ENOENT, then the object just didn't exist in that
+        * snapshot.  If we get ENOTSUP, then we tried to get
+        * info on a non-ZPL object, which we don't care about anyway.
+        */
+       fobjerr = get_stats_for_obj(di, di->fromsnap, dobj, fobjname,
+           MAXPATHLEN, &fsb);
+       if (fobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
+               return (-1);
+
+       tobjerr = get_stats_for_obj(di, di->tosnap, dobj, tobjname,
+           MAXPATHLEN, &tsb);
+       if (tobjerr && di->zerr != ENOENT && di->zerr != ENOTSUP)
+               return (-1);
+
+       /*
+        * Unallocated object sharing the same meta dnode block
+        */
+       if (fobjerr && tobjerr) {
+               ASSERT(di->zerr == ENOENT || di->zerr == ENOTSUP);
+               di->zerr = 0;
+               return (0);
+       }
+
+       di->zerr = 0; /* negate get_stats_for_obj() from side that failed */
+       fmode = fsb.zs_mode & S_IFMT;
+       tmode = tsb.zs_mode & S_IFMT;
+       if (fmode == S_IFDIR || tmode == S_IFDIR || fsb.zs_links == 0 ||
+           tsb.zs_links == 0)
+               change = 0;
+       else
+               change = tsb.zs_links - fsb.zs_links;
+
+       if (fobjerr) {
+               if (change) {
+                       print_link_change(fp, di, change, tobjname, &tsb);
+                       return (0);
+               }
+               print_file(fp, di, ZDIFF_ADDED, tobjname, &tsb);
+               return (0);
+       } else if (tobjerr) {
+               if (change) {
+                       print_link_change(fp, di, change, fobjname, &fsb);
+                       return (0);
+               }
+               print_file(fp, di, ZDIFF_REMOVED, fobjname, &fsb);
+               return (0);
+       }
+
+       if (fmode != tmode && fsb.zs_gen == tsb.zs_gen)
+               tsb.zs_gen++;   /* Force a generational difference */
+
+       /* Simple modification or no change */
+       if (fsb.zs_gen == tsb.zs_gen) {
+               /* No apparent changes.  Could we assert !this?  */
+               if (fsb.zs_ctime[0] == tsb.zs_ctime[0] &&
+                   fsb.zs_ctime[1] == tsb.zs_ctime[1])
+                       return (0);
+               if (change) {
+                       print_link_change(fp, di, change,
+                           change > 0 ? fobjname : tobjname, &tsb);
+               } else if (strcmp(fobjname, tobjname) == 0) {
+                       print_file(fp, di, ZDIFF_MODIFIED, fobjname, &tsb);
+               } else {
+                       print_rename(fp, di, fobjname, tobjname, &tsb);
+               }
+               return (0);
+       } else {
+               /* file re-created or object re-used */
+               print_file(fp, di, ZDIFF_REMOVED, fobjname, &fsb);
+               print_file(fp, di, ZDIFF_ADDED, tobjname, &tsb);
+               return (0);
+       }
+}
+
+static int
+write_inuse_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
+{
+       uint64_t o;
+       int err;
+
+       for (o = dr->ddr_first; o <= dr->ddr_last; o++) {
+               if ((err = write_inuse_diffs_one(fp, di, o)))
+                       return (err);
+       }
+       return (0);
+}
+
+static int
+describe_free(FILE *fp, differ_info_t *di, uint64_t object, char *namebuf,
+    int maxlen)
+{
+       struct zfs_stat sb;
+
+       if (get_stats_for_obj(di, di->fromsnap, object, namebuf,
+           maxlen, &sb) != 0) {
+               /* Let it slide, if in the delete queue on from side */
+               if (di->zerr == ENOENT && sb.zs_links == 0) {
+                       di->zerr = 0;
+                       return (0);
+               }
+               return (-1);
+       }
+
+       print_file(fp, di, ZDIFF_REMOVED, namebuf, &sb);
+       return (0);
+}
+
+static int
+write_free_diffs(FILE *fp, differ_info_t *di, dmu_diff_record_t *dr)
+{
+       zfs_cmd_t zc = {"\0"};
+       libzfs_handle_t *lhdl = di->zhp->zfs_hdl;
+       char fobjname[MAXPATHLEN];
+
+       (void) strlcpy(zc.zc_name, di->fromsnap, sizeof (zc.zc_name));
+       zc.zc_obj = dr->ddr_first - 1;
+
+       ASSERT(di->zerr == 0);
+
+       while (zc.zc_obj < dr->ddr_last) {
+               int err;
+
+               err = ioctl(lhdl->libzfs_fd, ZFS_IOC_NEXT_OBJ, &zc);
+               if (err == 0) {
+                       if (zc.zc_obj == di->shares) {
+                               zc.zc_obj++;
+                               continue;
+                       }
+                       if (zc.zc_obj > dr->ddr_last) {
+                               break;
+                       }
+                       err = describe_free(fp, di, zc.zc_obj, fobjname,
+                           MAXPATHLEN);
+                       if (err)
+                               break;
+               } else if (errno == ESRCH) {
+                       break;
+               } else {
+                       (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                           dgettext(TEXT_DOMAIN,
+                           "next allocated object (> %lld) find failure"),
+                           (longlong_t)zc.zc_obj);
+                       di->zerr = errno;
+                       break;
+               }
+       }
+       if (di->zerr)
+               return (-1);
+       return (0);
+}
+
+static void *
+differ(void *arg)
+{
+       differ_info_t *di = arg;
+       dmu_diff_record_t dr;
+       FILE *ofp;
+       int err = 0;
+
+       if ((ofp = fdopen(di->outputfd, "w")) == NULL) {
+               di->zerr = errno;
+               strlcpy(di->errbuf, strerror(errno), sizeof (di->errbuf));
+               (void) close(di->datafd);
+               return ((void *)-1);
+       }
+
+       for (;;) {
+               char *cp = (char *)&dr;
+               int len = sizeof (dr);
+               int rv;
+
+               do {
+                       rv = read(di->datafd, cp, len);
+                       cp += rv;
+                       len -= rv;
+               } while (len > 0 && rv > 0);
+
+               if (rv < 0 || (rv == 0 && len != sizeof (dr))) {
+                       di->zerr = EPIPE;
+                       break;
+               } else if (rv == 0) {
+                       /* end of file at a natural breaking point */
+                       break;
+               }
+
+               switch (dr.ddr_type) {
+               case DDR_FREE:
+                       err = write_free_diffs(ofp, di, &dr);
+                       break;
+               case DDR_INUSE:
+                       err = write_inuse_diffs(ofp, di, &dr);
+                       break;
+               default:
+                       di->zerr = EPIPE;
+                       break;
+               }
+
+               if (err || di->zerr)
+                       break;
+       }
+
+       (void) fclose(ofp);
+       (void) close(di->datafd);
+       if (err)
+               return ((void *)-1);
+       if (di->zerr) {
+               ASSERT(di->zerr == EINVAL);
+               (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "Internal error: bad data from diff IOCTL"));
+               return ((void *)-1);
+       }
+       return ((void *)0);
+}
+
+static int
+find_shares_object(differ_info_t *di)
+{
+       char fullpath[MAXPATHLEN];
+       struct stat64 sb = { 0 };
+
+       (void) strlcpy(fullpath, di->dsmnt, MAXPATHLEN);
+       (void) strlcat(fullpath, ZDIFF_SHARESDIR, MAXPATHLEN);
+
+       if (stat64(fullpath, &sb) != 0) {
+               (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                   dgettext(TEXT_DOMAIN, "Cannot stat %s"), fullpath);
+               return (zfs_error(di->zhp->zfs_hdl, EZFS_DIFF, di->errbuf));
+       }
+
+       di->shares = (uint64_t)sb.st_ino;
+       return (0);
+}
+
+static int
+make_temp_snapshot(differ_info_t *di)
+{
+       libzfs_handle_t *hdl = di->zhp->zfs_hdl;
+       zfs_cmd_t zc = {"\0"};
+
+       (void) snprintf(zc.zc_value, sizeof (zc.zc_value),
+           ZDIFF_PREFIX, getpid());
+       (void) strlcpy(zc.zc_name, di->ds, sizeof (zc.zc_name));
+       zc.zc_cleanup_fd = di->cleanupfd;
+
+       if (ioctl(hdl->libzfs_fd, ZFS_IOC_TMP_SNAPSHOT, &zc) != 0) {
+               int err = errno;
+               if (err == EPERM) {
+                       (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                           dgettext(TEXT_DOMAIN, "The diff delegated "
+                           "permission is needed in order\nto create a "
+                           "just-in-time snapshot for diffing\n"));
+                       return (zfs_error(hdl, EZFS_DIFF, di->errbuf));
+               } else {
+                       (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                           dgettext(TEXT_DOMAIN, "Cannot create just-in-time "
+                           "snapshot of '%s'"), zc.zc_name);
+                       return (zfs_standard_error(hdl, err, di->errbuf));
+               }
+       }
+
+       di->tmpsnap = zfs_strdup(hdl, zc.zc_value);
+       di->tosnap = zfs_asprintf(hdl, "%s@%s", di->ds, di->tmpsnap);
+       return (0);
+}
+
+static void
+teardown_differ_info(differ_info_t *di)
+{
+       free(di->ds);
+       free(di->dsmnt);
+       free(di->fromsnap);
+       free(di->frommnt);
+       free(di->tosnap);
+       free(di->tmpsnap);
+       free(di->tomnt);
+       (void) close(di->cleanupfd);
+}
+
+static int
+get_snapshot_names(differ_info_t *di, const char *fromsnap,
+    const char *tosnap)
+{
+       libzfs_handle_t *hdl = di->zhp->zfs_hdl;
+       char *atptrf = NULL;
+       char *atptrt = NULL;
+       int fdslen, fsnlen;
+       int tdslen, tsnlen;
+
+       /*
+        * Can accept
+        *    dataset@snap1
+        *    dataset@snap1 dataset@snap2
+        *    dataset@snap1 @snap2
+        *    dataset@snap1 dataset
+        *    @snap1 dataset@snap2
+        */
+       if (tosnap == NULL) {
+               /* only a from snapshot given, must be valid */
+               (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "Badly formed snapshot name %s"), fromsnap);
+
+               if (!zfs_validate_name(hdl, fromsnap, ZFS_TYPE_SNAPSHOT,
+                   B_FALSE)) {
+                       return (zfs_error(hdl, EZFS_INVALIDNAME,
+                           di->errbuf));
+               }
+
+               atptrf = strchr(fromsnap, '@');
+               ASSERT(atptrf != NULL);
+               fdslen = atptrf - fromsnap;
+
+               di->fromsnap = zfs_strdup(hdl, fromsnap);
+               di->ds = zfs_strdup(hdl, fromsnap);
+               di->ds[fdslen] = '\0';
+
+               /* the to snap will be a just-in-time snap of the head */
+               return (make_temp_snapshot(di));
+       }
+
+       (void) snprintf(di->errbuf, sizeof (di->errbuf),
+           dgettext(TEXT_DOMAIN,
+           "Unable to determine which snapshots to compare"));
+
+       atptrf = strchr(fromsnap, '@');
+       atptrt = strchr(tosnap, '@');
+       fdslen = atptrf ? atptrf - fromsnap : strlen(fromsnap);
+       tdslen = atptrt ? atptrt - tosnap : strlen(tosnap);
+       fsnlen = strlen(fromsnap) - fdslen;     /* includes @ sign */
+       tsnlen = strlen(tosnap) - tdslen;       /* includes @ sign */
+
+       if (fsnlen <= 1 || tsnlen == 1 || (fdslen == 0 && tdslen == 0) ||
+           (fsnlen == 0 && tsnlen == 0)) {
+               return (zfs_error(hdl, EZFS_INVALIDNAME, di->errbuf));
+       } else if ((fdslen > 0 && tdslen > 0) &&
+           ((tdslen != fdslen || strncmp(fromsnap, tosnap, fdslen) != 0))) {
+               /*
+                * not the same dataset name, might be okay if
+                * tosnap is a clone of a fromsnap descendant.
+                */
+               char origin[ZFS_MAX_DATASET_NAME_LEN];
+               zprop_source_t src;
+               zfs_handle_t *zhp;
+
+               di->ds = zfs_alloc(di->zhp->zfs_hdl, tdslen + 1);
+               (void) strncpy(di->ds, tosnap, tdslen);
+               di->ds[tdslen] = '\0';
+
+               zhp = zfs_open(hdl, di->ds, ZFS_TYPE_FILESYSTEM);
+               while (zhp != NULL) {
+                       if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
+                           sizeof (origin), &src, NULL, 0, B_FALSE) != 0) {
+                               (void) zfs_close(zhp);
+                               zhp = NULL;
+                               break;
+                       }
+                       if (strncmp(origin, fromsnap, fsnlen) == 0)
+                               break;
+
+                       (void) zfs_close(zhp);
+                       zhp = zfs_open(hdl, origin, ZFS_TYPE_FILESYSTEM);
+               }
+
+               if (zhp == NULL) {
+                       (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                           dgettext(TEXT_DOMAIN,
+                           "Not an earlier snapshot from the same fs"));
+                       return (zfs_error(hdl, EZFS_INVALIDNAME, di->errbuf));
+               } else {
+                       (void) zfs_close(zhp);
+               }
+
+               di->isclone = B_TRUE;
+               di->fromsnap = zfs_strdup(hdl, fromsnap);
+               if (tsnlen) {
+                       di->tosnap = zfs_strdup(hdl, tosnap);
+               } else {
+                       return (make_temp_snapshot(di));
+               }
+       } else {
+               int dslen = fdslen ? fdslen : tdslen;
+
+               di->ds = zfs_alloc(hdl, dslen + 1);
+               (void) strncpy(di->ds, fdslen ? fromsnap : tosnap, dslen);
+               di->ds[dslen] = '\0';
+
+               di->fromsnap = zfs_asprintf(hdl, "%s%s", di->ds, atptrf);
+               if (tsnlen) {
+                       di->tosnap = zfs_asprintf(hdl, "%s%s", di->ds, atptrt);
+               } else {
+                       return (make_temp_snapshot(di));
+               }
+       }
+       return (0);
+}
+
+static int
+get_mountpoint(differ_info_t *di, char *dsnm, char **mntpt)
+{
+       boolean_t mounted;
+
+       mounted = is_mounted(di->zhp->zfs_hdl, dsnm, mntpt);
+       if (mounted == B_FALSE) {
+               (void) snprintf(di->errbuf, sizeof (di->errbuf),
+                   dgettext(TEXT_DOMAIN,
+                   "Cannot diff an unmounted snapshot"));
+               return (zfs_error(di->zhp->zfs_hdl, EZFS_BADTYPE, di->errbuf));
+       }
+
+       /* Avoid a double slash at the beginning of root-mounted datasets */
+       if (**mntpt == '/' && *(*mntpt + 1) == '\0')
+               **mntpt = '\0';
+       return (0);
+}
+
+static int
+get_mountpoints(differ_info_t *di)
+{
+       char *strptr;
+       char *frommntpt;
+
+       /*
+        * first get the mountpoint for the parent dataset
+        */
+       if (get_mountpoint(di, di->ds, &di->dsmnt) != 0)
+               return (-1);
+
+       strptr = strchr(di->tosnap, '@');
+       ASSERT3P(strptr, !=, NULL);
+       di->tomnt = zfs_asprintf(di->zhp->zfs_hdl, "%s%s%s", di->dsmnt,
+           ZDIFF_SNAPDIR, ++strptr);
+
+       strptr = strchr(di->fromsnap, '@');
+       ASSERT3P(strptr, !=, NULL);
+
+       frommntpt = di->dsmnt;
+       if (di->isclone) {
+               char *mntpt;
+               int err;
+
+               *strptr = '\0';
+               err = get_mountpoint(di, di->fromsnap, &mntpt);
+               *strptr = '@';
+               if (err != 0)
+                       return (-1);
+               frommntpt = mntpt;
+       }
+
+       di->frommnt = zfs_asprintf(di->zhp->zfs_hdl, "%s%s%s", frommntpt,
+           ZDIFF_SNAPDIR, ++strptr);
+
+       if (di->isclone)
+               free(frommntpt);
+
+       return (0);
+}
+
+static int
+setup_differ_info(zfs_handle_t *zhp, const char *fromsnap,
+    const char *tosnap, differ_info_t *di)
+{
+       di->zhp = zhp;
+
+       di->cleanupfd = open(ZFS_DEV, O_RDWR);
+       VERIFY(di->cleanupfd >= 0);
+
+       if (get_snapshot_names(di, fromsnap, tosnap) != 0)
+               return (-1);
+
+       if (get_mountpoints(di) != 0)
+               return (-1);
+
+       if (find_shares_object(di) != 0)
+               return (-1);
+
+       return (0);
+}
+
+int
+zfs_show_diffs(zfs_handle_t *zhp, int outfd, const char *fromsnap,
+    const char *tosnap, int flags)
+{
+       zfs_cmd_t zc = {"\0"};
+       char errbuf[1024];
+       differ_info_t di = { 0 };
+       pthread_t tid;
+       int pipefd[2];
+       int iocerr;
+
+       (void) snprintf(errbuf, sizeof (errbuf),
+           dgettext(TEXT_DOMAIN, "zfs diff failed"));
+
+       if (setup_differ_info(zhp, fromsnap, tosnap, &di)) {
+               teardown_differ_info(&di);
+               return (-1);
+       }
+
+       if (pipe(pipefd)) {
+               zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+               teardown_differ_info(&di);
+               return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED, errbuf));
+       }
+
+       di.scripted = (flags & ZFS_DIFF_PARSEABLE);
+       di.classify = (flags & ZFS_DIFF_CLASSIFY);
+       di.timestamped = (flags & ZFS_DIFF_TIMESTAMP);
+
+       di.outputfd = outfd;
+       di.datafd = pipefd[0];
+
+       if (pthread_create(&tid, NULL, differ, &di)) {
+               zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+               (void) close(pipefd[0]);
+               (void) close(pipefd[1]);
+               teardown_differ_info(&di);
+               return (zfs_error(zhp->zfs_hdl,
+                   EZFS_THREADCREATEFAILED, errbuf));
+       }
+
+       /* do the ioctl() */
+       (void) strlcpy(zc.zc_value, di.fromsnap, strlen(di.fromsnap) + 1);
+       (void) strlcpy(zc.zc_name, di.tosnap, strlen(di.tosnap) + 1);
+       zc.zc_cookie = pipefd[1];
+
+       iocerr = ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_DIFF, &zc);
+       if (iocerr != 0) {
+               (void) snprintf(errbuf, sizeof (errbuf),
+                   dgettext(TEXT_DOMAIN, "Unable to obtain diffs"));
+               if (errno == EPERM) {
+                       zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+                           "\n   The sys_mount privilege or diff delegated "
+                           "permission is needed\n   to execute the "
+                           "diff ioctl"));
+               } else if (errno == EXDEV) {
+                       zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+                           "\n   Not an earlier snapshot from the same fs"));
+               } else if (errno != EPIPE || di.zerr == 0) {
+                       zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+               }
+               (void) close(pipefd[1]);
+               (void) pthread_cancel(tid);
+               (void) pthread_join(tid, NULL);
+               teardown_differ_info(&di);
+               if (di.zerr != 0 && di.zerr != EPIPE) {
+                       zfs_error_aux(zhp->zfs_hdl, strerror(di.zerr));
+                       return (zfs_error(zhp->zfs_hdl, EZFS_DIFF, di.errbuf));
+               } else {
+                       return (zfs_error(zhp->zfs_hdl, EZFS_DIFFDATA, errbuf));
+               }
+       }
+
+       (void) close(pipefd[1]);
+       (void) pthread_join(tid, NULL);
+
+       if (di.zerr != 0) {
+               zfs_error_aux(zhp->zfs_hdl, strerror(di.zerr));
+               return (zfs_error(zhp->zfs_hdl, EZFS_DIFF, di.errbuf));
+       }
+       teardown_differ_info(&di);
+       return (0);
+}
diff --git a/zfs/lib/libzfs/libzfs_fru.c b/zfs/lib/libzfs/libzfs_fru.c
new file mode 100644 (file)
index 0000000..6be927f
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * 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.
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <libintl.h>
+#include <link.h>
+#include <pthread.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <libzfs.h>
+
+#if defined(HAVE_LIBTOPO)
+
+#include <fm/libtopo.h>
+#include <sys/fm/protocol.h>
+#include <sys/systeminfo.h>
+
+#include "libzfs_impl.h"
+
+/*
+ * This file is responsible for determining the relationship between I/O
+ * devices paths and physical locations.  In the world of MPxIO and external
+ * enclosures, the device path is not synonymous with the physical location.
+ * If you remove a drive and insert it into a different slot, it will end up
+ * with the same path under MPxIO.  If you recable storage enclosures, the
+ * device paths may change.  All of this makes it difficult to implement the
+ * 'autoreplace' property, which is supposed to automatically manage disk
+ * replacement based on physical slot.
+ *
+ * In order to work around these limitations, we have a per-vdev FRU property
+ * that is the libtopo path (minus disk-specific authority information) to the
+ * physical location of the device on the system.  This is an optional
+ * property, and is only needed when using the 'autoreplace' property or when
+ * generating FMA faults against vdevs.
+ */
+
+/*
+ * Because the FMA packages depend on ZFS, we have to dlopen() libtopo in case
+ * it is not present.  We only need this once per library instance, so it is
+ * not part of the libzfs handle.
+ */
+static void *_topo_dlhandle;
+static topo_hdl_t *(*_topo_open)(int, const char *, int *);
+static void (*_topo_close)(topo_hdl_t *);
+static char *(*_topo_snap_hold)(topo_hdl_t *, const char *, int *);
+static void (*_topo_snap_release)(topo_hdl_t *);
+static topo_walk_t *(*_topo_walk_init)(topo_hdl_t *, const char *,
+    topo_walk_cb_t, void *, int *);
+static int (*_topo_walk_step)(topo_walk_t *, int);
+static void (*_topo_walk_fini)(topo_walk_t *);
+static void (*_topo_hdl_strfree)(topo_hdl_t *, char *);
+static char *(*_topo_node_name)(tnode_t *);
+static int (*_topo_prop_get_string)(tnode_t *, const char *, const char *,
+    char **, int *);
+static int (*_topo_node_fru)(tnode_t *, nvlist_t **, nvlist_t *, int *);
+static int (*_topo_fmri_nvl2str)(topo_hdl_t *, nvlist_t *, char **, int *);
+static int (*_topo_fmri_strcmp_noauth)(topo_hdl_t *, const char *,
+    const char *);
+
+#define        ZFS_FRU_HASH_SIZE       257
+
+static size_t
+fru_strhash(const char *key)
+{
+       ulong_t g, h = 0;
+       const char *p;
+
+       for (p = key; *p != '\0'; p++) {
+               h = (h << 4) + *p;
+
+               if ((g = (h & 0xf0000000)) != 0) {
+                       h ^= (g >> 24);
+                       h ^= g;
+               }
+       }
+
+       return (h % ZFS_FRU_HASH_SIZE);
+}
+
+static int
+libzfs_fru_gather(topo_hdl_t *thp, tnode_t *tn, void *arg)
+{
+       libzfs_handle_t *hdl = arg;
+       nvlist_t *fru;
+       char *devpath, *frustr;
+       int err;
+       libzfs_fru_t *frup;
+       size_t idx;
+
+       /*
+        * If this is the chassis node, and we don't yet have the system
+        * chassis ID, then fill in this value now.
+        */
+       if (hdl->libzfs_chassis_id[0] == '\0' &&
+           strcmp(_topo_node_name(tn), "chassis") == 0) {
+               if (_topo_prop_get_string(tn, FM_FMRI_AUTHORITY,
+                   FM_FMRI_AUTH_CHASSIS, &devpath, &err) == 0)
+                       (void) strlcpy(hdl->libzfs_chassis_id, devpath,
+                           sizeof (hdl->libzfs_chassis_id));
+       }
+
+       /*
+        * Skip non-disk nodes.
+        */
+       if (strcmp(_topo_node_name(tn), "disk") != 0)
+               return (TOPO_WALK_NEXT);
+
+       /*
+        * Get the devfs path and FRU.
+        */
+       if (_topo_prop_get_string(tn, "io", "devfs-path", &devpath, &err) != 0)
+               return (TOPO_WALK_NEXT);
+
+       if (libzfs_fru_lookup(hdl, devpath) != NULL) {
+               _topo_hdl_strfree(thp, devpath);
+               return (TOPO_WALK_NEXT);
+       }
+
+       if (_topo_node_fru(tn, &fru, NULL, &err) != 0) {
+               _topo_hdl_strfree(thp, devpath);
+               return (TOPO_WALK_NEXT);
+       }
+
+       /*
+        * Convert the FRU into a string.
+        */
+       if (_topo_fmri_nvl2str(thp, fru, &frustr, &err) != 0) {
+               nvlist_free(fru);
+               _topo_hdl_strfree(thp, devpath);
+               return (TOPO_WALK_NEXT);
+       }
+
+       nvlist_free(fru);
+
+       /*
+        * Finally, we have a FRU string and device path.  Add it to the hash.
+        */
+       if ((frup = calloc(sizeof (libzfs_fru_t), 1)) == NULL) {
+               _topo_hdl_strfree(thp, devpath);
+               _topo_hdl_strfree(thp, frustr);
+               return (TOPO_WALK_NEXT);
+       }
+
+       if ((frup->zf_device = strdup(devpath)) == NULL ||
+           (frup->zf_fru = strdup(frustr)) == NULL) {
+               free(frup->zf_device);
+               free(frup);
+               _topo_hdl_strfree(thp, devpath);
+               _topo_hdl_strfree(thp, frustr);
+               return (TOPO_WALK_NEXT);
+       }
+
+       _topo_hdl_strfree(thp, devpath);
+       _topo_hdl_strfree(thp, frustr);
+
+       idx = fru_strhash(frup->zf_device);
+       frup->zf_chain = hdl->libzfs_fru_hash[idx];
+       hdl->libzfs_fru_hash[idx] = frup;
+       frup->zf_next = hdl->libzfs_fru_list;
+       hdl->libzfs_fru_list = frup;
+
+       return (TOPO_WALK_NEXT);
+}
+
+/*
+ * Called during initialization to setup the dynamic libtopo connection.
+ */
+#pragma init(libzfs_init_fru)
+static void
+libzfs_init_fru(void)
+{
+       char path[MAXPATHLEN];
+       char isa[257];
+
+#if defined(_LP64)
+       if (sysinfo(SI_ARCHITECTURE_64, isa, sizeof (isa)) < 0)
+               isa[0] = '\0';
+#else
+       isa[0] = '\0';
+#endif
+       (void) snprintf(path, sizeof (path),
+           "/usr/lib/fm/%s/libtopo.so", isa);
+
+       if ((_topo_dlhandle = dlopen(path, RTLD_LAZY)) == NULL)
+               return;
+
+       _topo_open = (topo_hdl_t *(*)())
+           dlsym(_topo_dlhandle, "topo_open");
+       _topo_close = (void (*)())
+           dlsym(_topo_dlhandle, "topo_close");
+       _topo_snap_hold = (char *(*)())
+           dlsym(_topo_dlhandle, "topo_snap_hold");
+       _topo_snap_release = (void (*)())
+           dlsym(_topo_dlhandle, "topo_snap_release");
+       _topo_walk_init = (topo_walk_t *(*)())
+           dlsym(_topo_dlhandle, "topo_walk_init");
+       _topo_walk_step = (int (*)())
+           dlsym(_topo_dlhandle, "topo_walk_step");
+       _topo_walk_fini = (void (*)())
+           dlsym(_topo_dlhandle, "topo_walk_fini");
+       _topo_hdl_strfree = (void (*)())
+           dlsym(_topo_dlhandle, "topo_hdl_strfree");
+       _topo_node_name = (char *(*)())
+           dlsym(_topo_dlhandle, "topo_node_name");
+       _topo_prop_get_string = (int (*)())
+           dlsym(_topo_dlhandle, "topo_prop_get_string");
+       _topo_node_fru = (int (*)())
+           dlsym(_topo_dlhandle, "topo_node_fru");
+       _topo_fmri_nvl2str = (int (*)())
+           dlsym(_topo_dlhandle, "topo_fmri_nvl2str");
+       _topo_fmri_strcmp_noauth = (int (*)())
+           dlsym(_topo_dlhandle, "topo_fmri_strcmp_noauth");
+
+       if (_topo_open == NULL || _topo_close == NULL ||
+           _topo_snap_hold == NULL || _topo_snap_release == NULL ||
+           _topo_walk_init == NULL || _topo_walk_step == NULL ||
+           _topo_walk_fini == NULL || _topo_hdl_strfree == NULL ||
+           _topo_node_name == NULL || _topo_prop_get_string == NULL ||
+           _topo_node_fru == NULL || _topo_fmri_nvl2str == NULL ||
+           _topo_fmri_strcmp_noauth == NULL) {
+               (void) dlclose(_topo_dlhandle);
+               _topo_dlhandle = NULL;
+       }
+}
+
+/*
+ * Refresh the mappings from device path -> FMRI.  We do this by walking the
+ * hc topology looking for disk nodes, and recording the io/devfs-path and FRU.
+ * Note that we strip out the disk-specific authority information (serial,
+ * part, revision, etc) so that we are left with only the identifying
+ * characteristics of the slot (hc path and chassis-id).
+ */
+void
+libzfs_fru_refresh(libzfs_handle_t *hdl)
+{
+       int err;
+       char *uuid;
+       topo_hdl_t *thp;
+       topo_walk_t *twp;
+
+       if (_topo_dlhandle == NULL)
+               return;
+
+       /*
+        * Clear the FRU hash and initialize our basic structures.
+        */
+       libzfs_fru_clear(hdl, B_FALSE);
+
+       if ((hdl->libzfs_topo_hdl = _topo_open(TOPO_VERSION,
+           NULL, &err)) == NULL)
+               return;
+
+       thp = hdl->libzfs_topo_hdl;
+
+       if ((uuid = _topo_snap_hold(thp, NULL, &err)) == NULL)
+               return;
+
+       _topo_hdl_strfree(thp, uuid);
+
+       if (hdl->libzfs_fru_hash == NULL &&
+           (hdl->libzfs_fru_hash =
+           calloc(ZFS_FRU_HASH_SIZE * sizeof (void *), 1)) == NULL)
+               return;
+
+       /*
+        * We now have a topo snapshot, so iterate over the hc topology looking
+        * for disks to add to the hash.
+        */
+       twp = _topo_walk_init(thp, FM_FMRI_SCHEME_HC,
+           libzfs_fru_gather, hdl, &err);
+       if (twp != NULL) {
+               (void) _topo_walk_step(twp, TOPO_WALK_CHILD);
+               _topo_walk_fini(twp);
+       }
+}
+
+/*
+ * Given a devfs path, return the FRU for the device, if known.  This will
+ * automatically call libzfs_fru_refresh() if it hasn't already been called by
+ * the consumer.  The string returned is valid until the next call to
+ * libzfs_fru_refresh().
+ */
+const char *
+libzfs_fru_lookup(libzfs_handle_t *hdl, const char *devpath)
+{
+       size_t idx = fru_strhash(devpath);
+       libzfs_fru_t *frup;
+
+       if (hdl->libzfs_fru_hash == NULL)
+               libzfs_fru_refresh(hdl);
+
+       if (hdl->libzfs_fru_hash == NULL)
+               return (NULL);
+
+       for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
+           frup = frup->zf_chain) {
+               if (strcmp(devpath, frup->zf_device) == 0)
+                       return (frup->zf_fru);
+       }
+
+       return (NULL);
+}
+
+/*
+ * Given a fru path, return the device path.  This will automatically call
+ * libzfs_fru_refresh() if it hasn't already been called by the consumer.  The
+ * string returned is valid until the next call to libzfs_fru_refresh().
+ */
+const char *
+libzfs_fru_devpath(libzfs_handle_t *hdl, const char *fru)
+{
+       libzfs_fru_t *frup;
+       size_t idx;
+
+       if (hdl->libzfs_fru_hash == NULL)
+               libzfs_fru_refresh(hdl);
+
+       if (hdl->libzfs_fru_hash == NULL)
+               return (NULL);
+
+       for (idx = 0; idx < ZFS_FRU_HASH_SIZE; idx++) {
+               for (frup = hdl->libzfs_fru_hash[idx]; frup != NULL;
+                   frup = frup->zf_next) {
+                       if (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl,
+                           fru, frup->zf_fru))
+                               return (frup->zf_device);
+               }
+       }
+
+       return (NULL);
+}
+
+/*
+ * Change the stored FRU for the given vdev.
+ */
+int
+zpool_fru_set(zpool_handle_t *zhp, uint64_t vdev_guid, const char *fru)
+{
+       zfs_cmd_t zc = {"\0"};
+
+       (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       (void) strncpy(zc.zc_value, fru, sizeof (zc.zc_value));
+       zc.zc_guid = vdev_guid;
+
+       if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_VDEV_SETFRU, &zc) != 0)
+               return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
+                   dgettext(TEXT_DOMAIN, "cannot set FRU")));
+
+       return (0);
+}
+
+/*
+ * Compare to two FRUs, ignoring any authority information.
+ */
+boolean_t
+libzfs_fru_compare(libzfs_handle_t *hdl, const char *a, const char *b)
+{
+       if (hdl->libzfs_fru_hash == NULL)
+               libzfs_fru_refresh(hdl);
+
+       if (hdl->libzfs_fru_hash == NULL)
+               return (strcmp(a, b) == 0);
+
+       return (_topo_fmri_strcmp_noauth(hdl->libzfs_topo_hdl, a, b));
+}
+
+/*
+ * This special function checks to see whether the FRU indicates it's supposed
+ * to be in the system chassis, but the chassis-id doesn't match.  This can
+ * happen in a clustered case, where both head nodes have the same logical
+ * disk, but opening the device on the other head node is meaningless.
+ */
+boolean_t
+libzfs_fru_notself(libzfs_handle_t *hdl, const char *fru)
+{
+       const char *chassisid;
+       size_t len;
+
+       if (hdl->libzfs_fru_hash == NULL)
+               libzfs_fru_refresh(hdl);
+
+       if (hdl->libzfs_chassis_id[0] == '\0')
+               return (B_FALSE);
+
+       if (strstr(fru, "/chassis=0/") == NULL)
+               return (B_FALSE);
+
+       if ((chassisid = strstr(fru, ":chassis-id=")) == NULL)
+               return (B_FALSE);
+
+       chassisid += 12;
+       len = strlen(hdl->libzfs_chassis_id);
+       if (strncmp(chassisid, hdl->libzfs_chassis_id, len) == 0 &&
+           (chassisid[len] == '/' || chassisid[len] == ':'))
+               return (B_FALSE);
+
+       return (B_TRUE);
+}
+
+/*
+ * Clear memory associated with the FRU hash.
+ */
+void
+libzfs_fru_clear(libzfs_handle_t *hdl, boolean_t final)
+{
+       libzfs_fru_t *frup;
+
+       while ((frup = hdl->libzfs_fru_list) != NULL) {
+               hdl->libzfs_fru_list = frup->zf_next;
+               free(frup->zf_device);
+               free(frup->zf_fru);
+               free(frup);
+       }
+
+       hdl->libzfs_fru_list = NULL;
+
+       if (hdl->libzfs_topo_hdl != NULL) {
+               _topo_snap_release(hdl->libzfs_topo_hdl);
+               _topo_close(hdl->libzfs_topo_hdl);
+               hdl->libzfs_topo_hdl = NULL;
+       }
+
+       if (final) {
+               free(hdl->libzfs_fru_hash);
+       } else if (hdl->libzfs_fru_hash != NULL) {
+               bzero(hdl->libzfs_fru_hash,
+                   ZFS_FRU_HASH_SIZE * sizeof (void *));
+       }
+}
+
+#else /* HAVE_LIBTOPO */
+
+/*
+ * Clear memory associated with the FRU hash.
+ */
+void
+libzfs_fru_clear(libzfs_handle_t *hdl, boolean_t final)
+{
+}
+
+#endif /* HAVE_LIBTOPO */
diff --git a/zfs/lib/libzfs/libzfs_import.c b/zfs/lib/libzfs/libzfs_import.c
new file mode 100644 (file)
index 0000000..3de7fd7
--- /dev/null
@@ -0,0 +1,2335 @@
+/*
+ * 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 2015 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright 2015 RackTop Systems.
+ * Copyright (c) 2016, Intel Corporation.
+ */
+
+/*
+ * Pool import support functions.
+ *
+ * To import a pool, we rely on reading the configuration information from the
+ * ZFS label of each device.  If we successfully read the label, then we
+ * organize the configuration information in the following hierarchy:
+ *
+ *     pool guid -> toplevel vdev guid -> label txg
+ *
+ * Duplicate entries matching this same tuple will be discarded.  Once we have
+ * examined every device, we pick the best label txg config for each toplevel
+ * vdev.  We then arrange these toplevel vdevs into a complete pool config, and
+ * update any paths that have changed.  Finally, we attempt to import the pool
+ * using our derived config, and record the results.
+ */
+
+#include <ctype.h>
+#include <devid.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libintl.h>
+#ifdef HAVE_LIBUDEV
+#include <libudev.h>
+#include <sched.h>
+#endif
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/vtoc.h>
+#include <sys/dktp/fdisk.h>
+#include <sys/efi_partition.h>
+#include <sys/vdev_impl.h>
+#include <blkid/blkid.h>
+#include "libzfs.h"
+#include "libzfs_impl.h"
+#include <libzfs.h>
+
+/*
+ * Intermediate structures used to gather configuration information.
+ */
+typedef struct config_entry {
+       uint64_t                ce_txg;
+       nvlist_t                *ce_config;
+       struct config_entry     *ce_next;
+} config_entry_t;
+
+typedef struct vdev_entry {
+       uint64_t                ve_guid;
+       config_entry_t          *ve_configs;
+       struct vdev_entry       *ve_next;
+} vdev_entry_t;
+
+typedef struct pool_entry {
+       uint64_t                pe_guid;
+       vdev_entry_t            *pe_vdevs;
+       struct pool_entry       *pe_next;
+} pool_entry_t;
+
+typedef struct name_entry {
+       char                    *ne_name;
+       uint64_t                ne_guid;
+       uint64_t                ne_order;
+       uint64_t                ne_num_labels;
+       struct name_entry       *ne_next;
+} name_entry_t;
+
+typedef struct pool_list {
+       pool_entry_t            *pools;
+       name_entry_t            *names;
+} pool_list_t;
+
+#define        DEV_BYID_PATH   "/dev/disk/by-id/"
+
+/*
+ * Linux persistent device strings for vdev labels
+ *
+ * based on libudev for consistency with libudev disk add/remove events
+ */
+#ifdef HAVE_LIBUDEV
+
+typedef struct vdev_dev_strs {
+       char    vds_devid[128];
+       char    vds_devphys[128];
+} vdev_dev_strs_t;
+
+/*
+ * Obtain the persistent device id string (describes what)
+ *
+ * used by ZED vdev matching for auto-{online,expand,replace}
+ */
+int
+zfs_device_get_devid(struct udev_device *dev, char *bufptr, size_t buflen)
+{
+       struct udev_list_entry *entry;
+       const char *bus;
+       char devbyid[MAXPATHLEN];
+
+       /* The bus based by-id path is preferred */
+       bus = udev_device_get_property_value(dev, "ID_BUS");
+
+       if (bus == NULL) {
+               const char *dm_uuid;
+
+               /*
+                * For multipath nodes use the persistent uuid based identifier
+                *
+                * Example: /dev/disk/by-id/dm-uuid-mpath-35000c5006304de3f
+                */
+               dm_uuid = udev_device_get_property_value(dev, "DM_UUID");
+               if (dm_uuid != NULL) {
+                       (void) snprintf(bufptr, buflen, "dm-uuid-%s", dm_uuid);
+                       return (0);
+               }
+               return (ENODATA);
+       }
+
+       /*
+        * locate the bus specific by-id link
+        */
+       (void) snprintf(devbyid, sizeof (devbyid), "%s%s-", DEV_BYID_PATH, bus);
+       entry = udev_device_get_devlinks_list_entry(dev);
+       while (entry != NULL) {
+               const char *name;
+
+               name = udev_list_entry_get_name(entry);
+               if (strncmp(name, devbyid, strlen(devbyid)) == 0) {
+                       name += strlen(DEV_BYID_PATH);
+                       (void) strlcpy(bufptr, name, buflen);
+                       return (0);
+               }
+               entry = udev_list_entry_get_next(entry);
+       }
+
+       return (ENODATA);
+}
+
+/*
+ * Obtain the persistent physical location string (describes where)
+ *
+ * used by ZED vdev matching for auto-{online,expand,replace}
+ */
+int
+zfs_device_get_physical(struct udev_device *dev, char *bufptr, size_t buflen)
+{
+       const char *physpath = NULL;
+
+       /*
+        * Normal disks use ID_PATH for their physical path.  Device mapper
+        * devices are virtual and don't have a physical path.  For them we
+        * use ID_VDEV instead, which is setup via the /etc/vdev_id.conf file.
+        * ID_VDEV provides a persistent path to a virtual device.  If you
+        * don't have vdev_id.conf setup, you cannot use multipath autoreplace.
+        */
+       if (!((physpath = udev_device_get_property_value(dev, "ID_PATH")) &&
+           physpath[0])) {
+               if (!((physpath =
+                   udev_device_get_property_value(dev, "ID_VDEV")) &&
+                   physpath[0])) {
+                       return (ENODATA);
+               }
+       }
+
+       (void) strlcpy(bufptr, physpath, buflen);
+
+       return (0);
+}
+
+boolean_t
+udev_is_mpath(struct udev_device *dev)
+{
+       return udev_device_get_property_value(dev, "DM_UUID") &&
+       udev_device_get_property_value(dev, "MPATH_SBIN_PATH");
+}
+
+/*
+ * A disk is considered a multipath whole disk when:
+ *     DEVNAME key value has "dm-"
+ *     DM_NAME key value has "mpath" prefix
+ *     DM_UUID key exists
+ *     ID_PART_TABLE_TYPE key does not exist or is not gpt
+ */
+static boolean_t
+udev_mpath_whole_disk(struct udev_device *dev)
+{
+       const char *devname, *type, *uuid;
+
+       devname = udev_device_get_property_value(dev, "DEVNAME");
+       type = udev_device_get_property_value(dev, "ID_PART_TABLE_TYPE");
+       uuid = udev_device_get_property_value(dev, "DM_UUID");
+
+       if ((devname != NULL && strncmp(devname, "/dev/dm-", 8) == 0) &&
+           ((type == NULL) || (strcmp(type, "gpt") != 0)) &&
+           (uuid != NULL)) {
+               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+/*
+ * Check if a disk is effectively a multipath whole disk
+ */
+boolean_t
+is_mpath_whole_disk(const char *path)
+{
+       struct udev *udev;
+       struct udev_device *dev = NULL;
+       char nodepath[MAXPATHLEN];
+       char *sysname;
+       boolean_t wholedisk = B_FALSE;
+
+       if (realpath(path, nodepath) == NULL)
+               return (B_FALSE);
+       sysname = strrchr(nodepath, '/') + 1;
+       if (strncmp(sysname, "dm-", 3) != 0)
+               return (B_FALSE);
+       if ((udev = udev_new()) == NULL)
+               return (B_FALSE);
+       if ((dev = udev_device_new_from_subsystem_sysname(udev, "block",
+           sysname)) == NULL) {
+               udev_device_unref(dev);
+               return (B_FALSE);
+       }
+
+       wholedisk = udev_mpath_whole_disk(dev);
+
+       udev_device_unref(dev);
+       return (wholedisk);
+}
+
+static int
+udev_device_is_ready(struct udev_device *dev)
+{
+#ifdef HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED
+       return (udev_device_get_is_initialized(dev));
+#else
+       /* wait for DEVLINKS property to be initialized */
+       return (udev_device_get_property_value(dev, "DEVLINKS") != NULL);
+#endif
+}
+
+/*
+ * Wait up to timeout_ms for udev to set up the device node.  The device is
+ * considered ready when libudev determines it has been initialized, all of
+ * the device links have been verified to exist, and it has been allowed to
+ * settle.  At this point the device the device can be accessed reliably.
+ * Depending on the complexity of the udev rules this process could take
+ * several seconds.
+ */
+int
+zpool_label_disk_wait(char *path, int timeout_ms)
+{
+       struct udev *udev;
+       struct udev_device *dev = NULL;
+       char nodepath[MAXPATHLEN];
+       char *sysname = NULL;
+       int ret = ENODEV;
+       int settle_ms = 50;
+       long sleep_ms = 10;
+       hrtime_t start, settle;
+
+       if ((udev = udev_new()) == NULL)
+               return (ENXIO);
+
+       start = gethrtime();
+       settle = 0;
+
+       do {
+               if (sysname == NULL) {
+                       if (realpath(path, nodepath) != NULL) {
+                               sysname = strrchr(nodepath, '/') + 1;
+                       } else {
+                               (void) usleep(sleep_ms * MILLISEC);
+                               continue;
+                       }
+               }
+
+               dev = udev_device_new_from_subsystem_sysname(udev,
+                   "block", sysname);
+               if ((dev != NULL) && udev_device_is_ready(dev)) {
+                       struct udev_list_entry *links, *link;
+
+                       ret = 0;
+                       links = udev_device_get_devlinks_list_entry(dev);
+
+                       udev_list_entry_foreach(link, links) {
+                               struct stat64 statbuf;
+                               const char *name;
+
+                               name = udev_list_entry_get_name(link);
+                               errno = 0;
+                               if (stat64(name, &statbuf) == 0 && errno == 0)
+                                       continue;
+
+                               settle = 0;
+                               ret = ENODEV;
+                               break;
+                       }
+
+                       if (ret == 0) {
+                               if (settle == 0) {
+                                       settle = gethrtime();
+                               } else if (NSEC2MSEC(gethrtime() - settle) >=
+                                   settle_ms) {
+                                       udev_device_unref(dev);
+                                       break;
+                               }
+                       }
+               }
+
+               udev_device_unref(dev);
+               (void) usleep(sleep_ms * MILLISEC);
+
+       } while (NSEC2MSEC(gethrtime() - start) < timeout_ms);
+
+       udev_unref(udev);
+
+       return (ret);
+}
+
+
+/*
+ * Encode the persistent devices strings
+ * used for the vdev disk label
+ */
+static int
+encode_device_strings(const char *path, vdev_dev_strs_t *ds,
+    boolean_t wholedisk)
+{
+       struct udev *udev;
+       struct udev_device *dev = NULL;
+       char nodepath[MAXPATHLEN];
+       char *sysname;
+       int ret = ENODEV;
+       hrtime_t start;
+
+       if ((udev = udev_new()) == NULL)
+               return (ENXIO);
+
+       /* resolve path to a runtime device node instance */
+       if (realpath(path, nodepath) == NULL)
+               goto no_dev;
+
+       sysname = strrchr(nodepath, '/') + 1;
+
+       /*
+        * Wait up to 3 seconds for udev to set up the device node context
+        */
+       start = gethrtime();
+       do {
+               dev = udev_device_new_from_subsystem_sysname(udev, "block",
+                   sysname);
+               if (dev == NULL)
+                       goto no_dev;
+               if (udev_device_is_ready(dev))
+                       break;  /* udev ready */
+
+               udev_device_unref(dev);
+               dev = NULL;
+
+               if (NSEC2MSEC(gethrtime() - start) < 10)
+                       (void) sched_yield();   /* yield/busy wait up to 10ms */
+               else
+                       (void) usleep(10 * MILLISEC);
+
+       } while (NSEC2MSEC(gethrtime() - start) < (3 * MILLISEC));
+
+       if (dev == NULL)
+               goto no_dev;
+
+       /*
+        * Only whole disks require extra device strings
+        */
+       if (!wholedisk && !udev_mpath_whole_disk(dev))
+               goto no_dev;
+
+       ret = zfs_device_get_devid(dev, ds->vds_devid, sizeof (ds->vds_devid));
+       if (ret != 0)
+               goto no_dev_ref;
+
+       /* physical location string (optional) */
+       if (zfs_device_get_physical(dev, ds->vds_devphys,
+           sizeof (ds->vds_devphys)) != 0) {
+               ds->vds_devphys[0] = '\0'; /* empty string --> not available */
+       }
+
+no_dev_ref:
+       udev_device_unref(dev);
+no_dev:
+       udev_unref(udev);
+
+       return (ret);
+}
+
+/*
+ * Update a leaf vdev's persistent device strings (Linux only)
+ *
+ * - only applies for a dedicated leaf vdev (aka whole disk)
+ * - updated during pool create|add|attach|import
+ * - used for matching device matching during auto-{online,expand,replace}
+ * - stored in a leaf disk config label (i.e. alongside 'path' NVP)
+ * - these strings are currently not used in kernel (i.e. for vdev_disk_open)
+ *
+ * single device node example:
+ *     devid:          'scsi-MG03SCA300_350000494a8cb3d67-part1'
+ *     phys_path:      'pci-0000:04:00.0-sas-0x50000394a8cb3d67-lun-0'
+ *
+ * multipath device node example:
+ *     devid:          'dm-uuid-mpath-35000c5006304de3f'
+ *
+ * We also store the enclosure sysfs path for turning on enclosure LEDs
+ * (if applicable):
+ *     vdev_enc_sysfs_path: '/sys/class/enclosure/11:0:1:0/SLOT 4'
+ */
+void
+update_vdev_config_dev_strs(nvlist_t *nv)
+{
+       vdev_dev_strs_t vds;
+       char *env, *type, *path;
+       uint64_t wholedisk = 0;
+       char *upath, *spath;
+
+       /*
+        * For the benefit of legacy ZFS implementations, allow
+        * for opting out of devid strings in the vdev label.
+        *
+        * example use:
+        *      env ZFS_VDEV_DEVID_OPT_OUT=YES zpool import dozer
+        *
+        * explanation:
+        * Older ZFS on Linux implementations had issues when attempting to
+        * display pool config VDEV names if a "devid" NVP value is present
+        * in the pool's config.
+        *
+        * For example, a pool that originated on illumos platform would
+        * have a devid value in the config and "zpool status" would fail
+        * when listing the config.
+        *
+        * A pool can be stripped of any "devid" values on import or
+        * prevented from adding them on zpool create|add by setting
+        * ZFS_VDEV_DEVID_OPT_OUT.
+        */
+       env = getenv("ZFS_VDEV_DEVID_OPT_OUT");
+       if (env && (strtoul(env, NULL, 0) > 0 ||
+           !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2))) {
+               (void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
+               (void) nvlist_remove_all(nv, ZPOOL_CONFIG_PHYS_PATH);
+               (void) nvlist_remove_all(nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH);
+               return;
+       }
+
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0 ||
+           strcmp(type, VDEV_TYPE_DISK) != 0) {
+               return;
+       }
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
+               return;
+       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk);
+
+       /*
+        * Update device string values in config nvlist
+        */
+       if (encode_device_strings(path, &vds, (boolean_t)wholedisk) == 0) {
+               (void) nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, vds.vds_devid);
+               if (vds.vds_devphys[0] != '\0') {
+                       (void) nvlist_add_string(nv, ZPOOL_CONFIG_PHYS_PATH,
+                           vds.vds_devphys);
+               }
+
+               /* Add enclosure sysfs path (if disk is in an enclosure) */
+               upath = zfs_get_underlying_path(path);
+               spath = zfs_get_enclosure_sysfs_path(upath);
+               if (spath)
+                       nvlist_add_string(nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
+                           spath);
+               free(upath);
+               free(spath);
+       } else {
+               /* clear out any stale entries */
+               (void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
+               (void) nvlist_remove_all(nv, ZPOOL_CONFIG_PHYS_PATH);
+               (void) nvlist_remove_all(nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH);
+       }
+}
+#else
+
+boolean_t
+is_mpath_whole_disk(const char *path)
+{
+       return (B_FALSE);
+}
+
+/*
+ * Wait up to timeout_ms for udev to set up the device node.  The device is
+ * considered ready when the provided path have been verified to exist and
+ * it has been allowed to settle.  At this point the device the device can
+ * be accessed reliably.  Depending on the complexity of the udev rules thisi
+ * process could take several seconds.
+ */
+int
+zpool_label_disk_wait(char *path, int timeout_ms)
+{
+       int settle_ms = 50;
+       long sleep_ms = 10;
+       hrtime_t start, settle;
+       struct stat64 statbuf;
+
+       start = gethrtime();
+       settle = 0;
+
+       do {
+               errno = 0;
+               if ((stat64(path, &statbuf) == 0) && (errno == 0)) {
+                       if (settle == 0)
+                               settle = gethrtime();
+                       else if (NSEC2MSEC(gethrtime() - settle) >= settle_ms)
+                               return (0);
+               } else if (errno != ENOENT) {
+                       return (errno);
+               }
+
+               usleep(sleep_ms * MILLISEC);
+       } while (NSEC2MSEC(gethrtime() - start) < timeout_ms);
+
+       return (ENODEV);
+}
+
+void
+update_vdev_config_dev_strs(nvlist_t *nv)
+{
+}
+
+#endif /* HAVE_LIBUDEV */
+
+/*
+ * Go through and fix up any path and/or devid information for the given vdev
+ * configuration.
+ */
+static int
+fix_paths(nvlist_t *nv, name_entry_t *names)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       uint64_t guid;
+       name_entry_t *ne, *best;
+       char *path;
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if (fix_paths(child[c], names) != 0)
+                               return (-1);
+               return (0);
+       }
+
+       /*
+        * This is a leaf (file or disk) vdev.  In either case, go through
+        * the name list and see if we find a matching guid.  If so, replace
+        * the path and see if we can calculate a new devid.
+        *
+        * There may be multiple names associated with a particular guid, in
+        * which case we have overlapping partitions or multiple paths to the
+        * same disk.  In this case we prefer to use the path name which
+        * matches the ZPOOL_CONFIG_PATH.  If no matching entry is found we
+        * use the lowest order device which corresponds to the first match
+        * while traversing the ZPOOL_IMPORT_PATH search path.
+        */
+       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0);
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
+               path = NULL;
+
+       best = NULL;
+       for (ne = names; ne != NULL; ne = ne->ne_next) {
+               if (ne->ne_guid == guid) {
+                       if (path == NULL) {
+                               best = ne;
+                               break;
+                       }
+
+                       if ((strlen(path) == strlen(ne->ne_name)) &&
+                           strncmp(path, ne->ne_name, strlen(path)) == 0) {
+                               best = ne;
+                               break;
+                       }
+
+                       if (best == NULL) {
+                               best = ne;
+                               continue;
+                       }
+
+                       /* Prefer paths with move vdev labels. */
+                       if (ne->ne_num_labels > best->ne_num_labels) {
+                               best = ne;
+                               continue;
+                       }
+
+                       /* Prefer paths earlier in the search order. */
+                       if (ne->ne_num_labels == best->ne_num_labels &&
+                           ne->ne_order < best->ne_order) {
+                               best = ne;
+                               continue;
+                       }
+               }
+       }
+
+       if (best == NULL)
+               return (0);
+
+       if (nvlist_add_string(nv, ZPOOL_CONFIG_PATH, best->ne_name) != 0)
+               return (-1);
+
+       /* Linux only - update ZPOOL_CONFIG_DEVID and ZPOOL_CONFIG_PHYS_PATH */
+       update_vdev_config_dev_strs(nv);
+
+       return (0);
+}
+
+/*
+ * Add the given configuration to the list of known devices.
+ */
+static int
+add_config(libzfs_handle_t *hdl, pool_list_t *pl, const char *path,
+    int order, int num_labels, nvlist_t *config)
+{
+       uint64_t pool_guid, vdev_guid, top_guid, txg, state;
+       pool_entry_t *pe;
+       vdev_entry_t *ve;
+       config_entry_t *ce;
+       name_entry_t *ne;
+
+       /*
+        * If this is a hot spare not currently in use or level 2 cache
+        * device, add it to the list of names to translate, but don't do
+        * anything else.
+        */
+       if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+           &state) == 0 &&
+           (state == POOL_STATE_SPARE || state == POOL_STATE_L2CACHE) &&
+           nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, &vdev_guid) == 0) {
+               if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL) {
+                       nvlist_free(config);
+                       return (-1);
+               }
+
+               if ((ne->ne_name = zfs_strdup(hdl, path)) == NULL) {
+                       free(ne);
+                       nvlist_free(config);
+                       return (-1);
+               }
+               ne->ne_guid = vdev_guid;
+               ne->ne_order = order;
+               ne->ne_num_labels = num_labels;
+               ne->ne_next = pl->names;
+               pl->names = ne;
+               nvlist_free(config);
+               return (0);
+       }
+
+       /*
+        * If we have a valid config but cannot read any of these fields, then
+        * it means we have a half-initialized label.  In vdev_label_init()
+        * we write a label with txg == 0 so that we can identify the device
+        * in case the user refers to the same disk later on.  If we fail to
+        * create the pool, we'll be left with a label in this state
+        * which should not be considered part of a valid pool.
+        */
+       if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+           &pool_guid) != 0 ||
+           nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
+           &vdev_guid) != 0 ||
+           nvlist_lookup_uint64(config, ZPOOL_CONFIG_TOP_GUID,
+           &top_guid) != 0 ||
+           nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG,
+           &txg) != 0 || txg == 0) {
+               nvlist_free(config);
+               return (0);
+       }
+
+       /*
+        * First, see if we know about this pool.  If not, then add it to the
+        * list of known pools.
+        */
+       for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
+               if (pe->pe_guid == pool_guid)
+                       break;
+       }
+
+       if (pe == NULL) {
+               if ((pe = zfs_alloc(hdl, sizeof (pool_entry_t))) == NULL) {
+                       nvlist_free(config);
+                       return (-1);
+               }
+               pe->pe_guid = pool_guid;
+               pe->pe_next = pl->pools;
+               pl->pools = pe;
+       }
+
+       /*
+        * Second, see if we know about this toplevel vdev.  Add it if its
+        * missing.
+        */
+       for (ve = pe->pe_vdevs; ve != NULL; ve = ve->ve_next) {
+               if (ve->ve_guid == top_guid)
+                       break;
+       }
+
+       if (ve == NULL) {
+               if ((ve = zfs_alloc(hdl, sizeof (vdev_entry_t))) == NULL) {
+                       nvlist_free(config);
+                       return (-1);
+               }
+               ve->ve_guid = top_guid;
+               ve->ve_next = pe->pe_vdevs;
+               pe->pe_vdevs = ve;
+       }
+
+       /*
+        * Third, see if we have a config with a matching transaction group.  If
+        * so, then we do nothing.  Otherwise, add it to the list of known
+        * configs.
+        */
+       for (ce = ve->ve_configs; ce != NULL; ce = ce->ce_next) {
+               if (ce->ce_txg == txg)
+                       break;
+       }
+
+       if (ce == NULL) {
+               if ((ce = zfs_alloc(hdl, sizeof (config_entry_t))) == NULL) {
+                       nvlist_free(config);
+                       return (-1);
+               }
+               ce->ce_txg = txg;
+               ce->ce_config = config;
+               ce->ce_next = ve->ve_configs;
+               ve->ve_configs = ce;
+       } else {
+               nvlist_free(config);
+       }
+
+       /*
+        * At this point we've successfully added our config to the list of
+        * known configs.  The last thing to do is add the vdev guid -> path
+        * mappings so that we can fix up the configuration as necessary before
+        * doing the import.
+        */
+       if ((ne = zfs_alloc(hdl, sizeof (name_entry_t))) == NULL)
+               return (-1);
+
+       if ((ne->ne_name = zfs_strdup(hdl, path)) == NULL) {
+               free(ne);
+               return (-1);
+       }
+
+       ne->ne_guid = vdev_guid;
+       ne->ne_order = order;
+       ne->ne_num_labels = num_labels;
+       ne->ne_next = pl->names;
+       pl->names = ne;
+
+       return (0);
+}
+
+/*
+ * Returns true if the named pool matches the given GUID.
+ */
+static int
+pool_active(libzfs_handle_t *hdl, const char *name, uint64_t guid,
+    boolean_t *isactive)
+{
+       zpool_handle_t *zhp;
+       uint64_t theguid;
+
+       if (zpool_open_silent(hdl, name, &zhp) != 0)
+               return (-1);
+
+       if (zhp == NULL) {
+               *isactive = B_FALSE;
+               return (0);
+       }
+
+       verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_POOL_GUID,
+           &theguid) == 0);
+
+       zpool_close(zhp);
+
+       *isactive = (theguid == guid);
+       return (0);
+}
+
+static nvlist_t *
+refresh_config(libzfs_handle_t *hdl, nvlist_t *config)
+{
+       nvlist_t *nvl;
+       zfs_cmd_t zc = {"\0"};
+       int err;
+
+       if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0)
+               return (NULL);
+
+       if (zcmd_alloc_dst_nvlist(hdl, &zc,
+           zc.zc_nvlist_conf_size * 2) != 0) {
+               zcmd_free_nvlists(&zc);
+               return (NULL);
+       }
+
+       while ((err = ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_TRYIMPORT,
+           &zc)) != 0 && errno == ENOMEM) {
+               if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+                       zcmd_free_nvlists(&zc);
+                       return (NULL);
+               }
+       }
+
+       if (err) {
+               zcmd_free_nvlists(&zc);
+               return (NULL);
+       }
+
+       if (zcmd_read_dst_nvlist(hdl, &zc, &nvl) != 0) {
+               zcmd_free_nvlists(&zc);
+               return (NULL);
+       }
+
+       zcmd_free_nvlists(&zc);
+       return (nvl);
+}
+
+/*
+ * Determine if the vdev id is a hole in the namespace.
+ */
+boolean_t
+vdev_is_hole(uint64_t *hole_array, uint_t holes, uint_t id)
+{
+       int c;
+
+       for (c = 0; c < holes; c++) {
+
+               /* Top-level is a hole */
+               if (hole_array[c] == id)
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+
+/*
+ * Convert our list of pools into the definitive set of configurations.  We
+ * start by picking the best config for each toplevel vdev.  Once that's done,
+ * we assemble the toplevel vdevs into a full config for the pool.  We make a
+ * pass to fix up any incorrect paths, and then add it to the main list to
+ * return to the user.
+ */
+static nvlist_t *
+get_configs(libzfs_handle_t *hdl, pool_list_t *pl, boolean_t active_ok)
+{
+       pool_entry_t *pe;
+       vdev_entry_t *ve;
+       config_entry_t *ce;
+       nvlist_t *ret = NULL, *config = NULL, *tmp = NULL, *nvtop, *nvroot;
+       nvlist_t **spares, **l2cache;
+       uint_t i, nspares, nl2cache;
+       boolean_t config_seen;
+       uint64_t best_txg;
+       char *name, *hostname = NULL;
+       uint64_t guid;
+       uint_t children = 0;
+       nvlist_t **child = NULL;
+       uint_t holes;
+       uint64_t *hole_array, max_id;
+       uint_t c;
+       boolean_t isactive;
+       uint64_t hostid;
+       nvlist_t *nvl;
+       boolean_t valid_top_config = B_FALSE;
+
+       if (nvlist_alloc(&ret, 0, 0) != 0)
+               goto nomem;
+
+       for (pe = pl->pools; pe != NULL; pe = pe->pe_next) {
+               uint64_t id, max_txg = 0;
+
+               if (nvlist_alloc(&config, NV_UNIQUE_NAME, 0) != 0)
+                       goto nomem;
+               config_seen = B_FALSE;
+
+               /*
+                * Iterate over all toplevel vdevs.  Grab the pool configuration
+                * from the first one we find, and then go through the rest and
+                * add them as necessary to the 'vdevs' member of the config.
+                */
+               for (ve = pe->pe_vdevs; ve != NULL; ve = ve->ve_next) {
+
+                       /*
+                        * Determine the best configuration for this vdev by
+                        * selecting the config with the latest transaction
+                        * group.
+                        */
+                       best_txg = 0;
+                       for (ce = ve->ve_configs; ce != NULL;
+                           ce = ce->ce_next) {
+
+                               if (ce->ce_txg > best_txg) {
+                                       tmp = ce->ce_config;
+                                       best_txg = ce->ce_txg;
+                               }
+                       }
+
+                       /*
+                        * We rely on the fact that the max txg for the
+                        * pool will contain the most up-to-date information
+                        * about the valid top-levels in the vdev namespace.
+                        */
+                       if (best_txg > max_txg) {
+                               (void) nvlist_remove(config,
+                                   ZPOOL_CONFIG_VDEV_CHILDREN,
+                                   DATA_TYPE_UINT64);
+                               (void) nvlist_remove(config,
+                                   ZPOOL_CONFIG_HOLE_ARRAY,
+                                   DATA_TYPE_UINT64_ARRAY);
+
+                               max_txg = best_txg;
+                               hole_array = NULL;
+                               holes = 0;
+                               max_id = 0;
+                               valid_top_config = B_FALSE;
+
+                               if (nvlist_lookup_uint64(tmp,
+                                   ZPOOL_CONFIG_VDEV_CHILDREN, &max_id) == 0) {
+                                       verify(nvlist_add_uint64(config,
+                                           ZPOOL_CONFIG_VDEV_CHILDREN,
+                                           max_id) == 0);
+                                       valid_top_config = B_TRUE;
+                               }
+
+                               if (nvlist_lookup_uint64_array(tmp,
+                                   ZPOOL_CONFIG_HOLE_ARRAY, &hole_array,
+                                   &holes) == 0) {
+                                       verify(nvlist_add_uint64_array(config,
+                                           ZPOOL_CONFIG_HOLE_ARRAY,
+                                           hole_array, holes) == 0);
+                               }
+                       }
+
+                       if (!config_seen) {
+                               /*
+                                * Copy the relevant pieces of data to the pool
+                                * configuration:
+                                *
+                                *      version
+                                *      pool guid
+                                *      name
+                                *      comment (if available)
+                                *      pool state
+                                *      hostid (if available)
+                                *      hostname (if available)
+                                */
+                               uint64_t state, version;
+                               char *comment = NULL;
+
+                               version = fnvlist_lookup_uint64(tmp,
+                                   ZPOOL_CONFIG_VERSION);
+                               fnvlist_add_uint64(config,
+                                   ZPOOL_CONFIG_VERSION, version);
+                               guid = fnvlist_lookup_uint64(tmp,
+                                   ZPOOL_CONFIG_POOL_GUID);
+                               fnvlist_add_uint64(config,
+                                   ZPOOL_CONFIG_POOL_GUID, guid);
+                               name = fnvlist_lookup_string(tmp,
+                                   ZPOOL_CONFIG_POOL_NAME);
+                               fnvlist_add_string(config,
+                                   ZPOOL_CONFIG_POOL_NAME, name);
+
+                               if (nvlist_lookup_string(tmp,
+                                   ZPOOL_CONFIG_COMMENT, &comment) == 0)
+                                       fnvlist_add_string(config,
+                                           ZPOOL_CONFIG_COMMENT, comment);
+
+                               state = fnvlist_lookup_uint64(tmp,
+                                   ZPOOL_CONFIG_POOL_STATE);
+                               fnvlist_add_uint64(config,
+                                   ZPOOL_CONFIG_POOL_STATE, state);
+
+                               hostid = 0;
+                               if (nvlist_lookup_uint64(tmp,
+                                   ZPOOL_CONFIG_HOSTID, &hostid) == 0) {
+                                       fnvlist_add_uint64(config,
+                                           ZPOOL_CONFIG_HOSTID, hostid);
+                                       hostname = fnvlist_lookup_string(tmp,
+                                           ZPOOL_CONFIG_HOSTNAME);
+                                       fnvlist_add_string(config,
+                                           ZPOOL_CONFIG_HOSTNAME, hostname);
+                               }
+
+                               config_seen = B_TRUE;
+                       }
+
+                       /*
+                        * Add this top-level vdev to the child array.
+                        */
+                       verify(nvlist_lookup_nvlist(tmp,
+                           ZPOOL_CONFIG_VDEV_TREE, &nvtop) == 0);
+                       verify(nvlist_lookup_uint64(nvtop, ZPOOL_CONFIG_ID,
+                           &id) == 0);
+
+                       if (id >= children) {
+                               nvlist_t **newchild;
+
+                               newchild = zfs_alloc(hdl, (id + 1) *
+                                   sizeof (nvlist_t *));
+                               if (newchild == NULL)
+                                       goto nomem;
+
+                               for (c = 0; c < children; c++)
+                                       newchild[c] = child[c];
+
+                               free(child);
+                               child = newchild;
+                               children = id + 1;
+                       }
+                       if (nvlist_dup(nvtop, &child[id], 0) != 0)
+                               goto nomem;
+
+               }
+
+               /*
+                * If we have information about all the top-levels then
+                * clean up the nvlist which we've constructed. This
+                * means removing any extraneous devices that are
+                * beyond the valid range or adding devices to the end
+                * of our array which appear to be missing.
+                */
+               if (valid_top_config) {
+                       if (max_id < children) {
+                               for (c = max_id; c < children; c++)
+                                       nvlist_free(child[c]);
+                               children = max_id;
+                       } else if (max_id > children) {
+                               nvlist_t **newchild;
+
+                               newchild = zfs_alloc(hdl, (max_id) *
+                                   sizeof (nvlist_t *));
+                               if (newchild == NULL)
+                                       goto nomem;
+
+                               for (c = 0; c < children; c++)
+                                       newchild[c] = child[c];
+
+                               free(child);
+                               child = newchild;
+                               children = max_id;
+                       }
+               }
+
+               verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+                   &guid) == 0);
+
+               /*
+                * The vdev namespace may contain holes as a result of
+                * device removal. We must add them back into the vdev
+                * tree before we process any missing devices.
+                */
+               if (holes > 0) {
+                       ASSERT(valid_top_config);
+
+                       for (c = 0; c < children; c++) {
+                               nvlist_t *holey;
+
+                               if (child[c] != NULL ||
+                                   !vdev_is_hole(hole_array, holes, c))
+                                       continue;
+
+                               if (nvlist_alloc(&holey, NV_UNIQUE_NAME,
+                                   0) != 0)
+                                       goto nomem;
+
+                               /*
+                                * Holes in the namespace are treated as
+                                * "hole" top-level vdevs and have a
+                                * special flag set on them.
+                                */
+                               if (nvlist_add_string(holey,
+                                   ZPOOL_CONFIG_TYPE,
+                                   VDEV_TYPE_HOLE) != 0 ||
+                                   nvlist_add_uint64(holey,
+                                   ZPOOL_CONFIG_ID, c) != 0 ||
+                                   nvlist_add_uint64(holey,
+                                   ZPOOL_CONFIG_GUID, 0ULL) != 0) {
+                                       nvlist_free(holey);
+                                       goto nomem;
+                               }
+                               child[c] = holey;
+                       }
+               }
+
+               /*
+                * Look for any missing top-level vdevs.  If this is the case,
+                * create a faked up 'missing' vdev as a placeholder.  We cannot
+                * simply compress the child array, because the kernel performs
+                * certain checks to make sure the vdev IDs match their location
+                * in the configuration.
+                */
+               for (c = 0; c < children; c++) {
+                       if (child[c] == NULL) {
+                               nvlist_t *missing;
+                               if (nvlist_alloc(&missing, NV_UNIQUE_NAME,
+                                   0) != 0)
+                                       goto nomem;
+                               if (nvlist_add_string(missing,
+                                   ZPOOL_CONFIG_TYPE,
+                                   VDEV_TYPE_MISSING) != 0 ||
+                                   nvlist_add_uint64(missing,
+                                   ZPOOL_CONFIG_ID, c) != 0 ||
+                                   nvlist_add_uint64(missing,
+                                   ZPOOL_CONFIG_GUID, 0ULL) != 0) {
+                                       nvlist_free(missing);
+                                       goto nomem;
+                               }
+                               child[c] = missing;
+                       }
+               }
+
+               /*
+                * Put all of this pool's top-level vdevs into a root vdev.
+                */
+               if (nvlist_alloc(&nvroot, NV_UNIQUE_NAME, 0) != 0)
+                       goto nomem;
+               if (nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
+                   VDEV_TYPE_ROOT) != 0 ||
+                   nvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL) != 0 ||
+                   nvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, guid) != 0 ||
+                   nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+                   child, children) != 0) {
+                       nvlist_free(nvroot);
+                       goto nomem;
+               }
+
+               for (c = 0; c < children; c++)
+                       nvlist_free(child[c]);
+               free(child);
+               children = 0;
+               child = NULL;
+
+               /*
+                * Go through and fix up any paths and/or devids based on our
+                * known list of vdev GUID -> path mappings.
+                */
+               if (fix_paths(nvroot, pl->names) != 0) {
+                       nvlist_free(nvroot);
+                       goto nomem;
+               }
+
+               /*
+                * Add the root vdev to this pool's configuration.
+                */
+               if (nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+                   nvroot) != 0) {
+                       nvlist_free(nvroot);
+                       goto nomem;
+               }
+               nvlist_free(nvroot);
+
+               /*
+                * zdb uses this path to report on active pools that were
+                * imported or created using -R.
+                */
+               if (active_ok)
+                       goto add_pool;
+
+               /*
+                * Determine if this pool is currently active, in which case we
+                * can't actually import it.
+                */
+               verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+                   &name) == 0);
+               verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+                   &guid) == 0);
+
+               if (pool_active(hdl, name, guid, &isactive) != 0)
+                       goto error;
+
+               if (isactive) {
+                       nvlist_free(config);
+                       config = NULL;
+                       continue;
+               }
+
+               if ((nvl = refresh_config(hdl, config)) == NULL) {
+                       nvlist_free(config);
+                       config = NULL;
+                       continue;
+               }
+
+               nvlist_free(config);
+               config = nvl;
+
+               /*
+                * Go through and update the paths for spares, now that we have
+                * them.
+                */
+               verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+                   &nvroot) == 0);
+               if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+                   &spares, &nspares) == 0) {
+                       for (i = 0; i < nspares; i++) {
+                               if (fix_paths(spares[i], pl->names) != 0)
+                                       goto nomem;
+                       }
+               }
+
+               /*
+                * Update the paths for l2cache devices.
+                */
+               if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+                   &l2cache, &nl2cache) == 0) {
+                       for (i = 0; i < nl2cache; i++) {
+                               if (fix_paths(l2cache[i], pl->names) != 0)
+                                       goto nomem;
+                       }
+               }
+
+               /*
+                * Restore the original information read from the actual label.
+                */
+               (void) nvlist_remove(config, ZPOOL_CONFIG_HOSTID,
+                   DATA_TYPE_UINT64);
+               (void) nvlist_remove(config, ZPOOL_CONFIG_HOSTNAME,
+                   DATA_TYPE_STRING);
+               if (hostid != 0) {
+                       verify(nvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID,
+                           hostid) == 0);
+                       verify(nvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME,
+                           hostname) == 0);
+               }
+
+add_pool:
+               /*
+                * Add this pool to the list of configs.
+                */
+               verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+                   &name) == 0);
+               if (nvlist_add_nvlist(ret, name, config) != 0)
+                       goto nomem;
+
+               nvlist_free(config);
+               config = NULL;
+       }
+
+       return (ret);
+
+nomem:
+       (void) no_memory(hdl);
+error:
+       nvlist_free(config);
+       nvlist_free(ret);
+       for (c = 0; c < children; c++)
+               nvlist_free(child[c]);
+       free(child);
+
+       return (NULL);
+}
+
+/*
+ * Return the offset of the given label.
+ */
+static uint64_t
+label_offset(uint64_t size, int l)
+{
+       ASSERT(P2PHASE_TYPED(size, sizeof (vdev_label_t), uint64_t) == 0);
+       return (l * sizeof (vdev_label_t) + (l < VDEV_LABELS / 2 ?
+           0 : size - VDEV_LABELS * sizeof (vdev_label_t)));
+}
+
+/*
+ * Given a file descriptor, read the label information and return an nvlist
+ * describing the configuration, if there is one.  The number of valid
+ * labels found will be returned in num_labels when non-NULL.
+ */
+int
+zpool_read_label(int fd, nvlist_t **config, int *num_labels)
+{
+       struct stat64 statbuf;
+       int l, count = 0;
+       vdev_label_t *label;
+       nvlist_t *expected_config = NULL;
+       uint64_t expected_guid = 0, size;
+
+       *config = NULL;
+
+       if (fstat64_blk(fd, &statbuf) == -1)
+               return (0);
+       size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
+
+       if ((label = malloc(sizeof (vdev_label_t))) == NULL)
+               return (-1);
+
+       for (l = 0; l < VDEV_LABELS; l++) {
+               uint64_t state, guid, txg;
+
+               if (pread64(fd, label, sizeof (vdev_label_t),
+                   label_offset(size, l)) != sizeof (vdev_label_t))
+                       continue;
+
+               if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist,
+                   sizeof (label->vl_vdev_phys.vp_nvlist), config, 0) != 0)
+                       continue;
+
+               if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_GUID,
+                   &guid) != 0 || guid == 0) {
+                       nvlist_free(*config);
+                       continue;
+               }
+
+               if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE,
+                   &state) != 0 || state > POOL_STATE_L2CACHE) {
+                       nvlist_free(*config);
+                       continue;
+               }
+
+               if (state != POOL_STATE_SPARE && state != POOL_STATE_L2CACHE &&
+                   (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_TXG,
+                   &txg) != 0 || txg == 0)) {
+                       nvlist_free(*config);
+                       continue;
+               }
+
+               if (expected_guid) {
+                       if (expected_guid == guid)
+                               count++;
+
+                       nvlist_free(*config);
+               } else {
+                       expected_config = *config;
+                       expected_guid = guid;
+                       count++;
+               }
+       }
+
+       if (num_labels != NULL)
+               *num_labels = count;
+
+       free(label);
+       *config = expected_config;
+
+       return (0);
+}
+
+typedef struct rdsk_node {
+       char *rn_name;                  /* Full path to device */
+       int rn_order;                   /* Preferred order (low to high) */
+       int rn_num_labels;              /* Number of valid labels */
+       libzfs_handle_t *rn_hdl;
+       nvlist_t *rn_config;            /* Label config */
+       avl_tree_t *rn_avl;
+       avl_node_t rn_node;
+       kmutex_t *rn_lock;
+       boolean_t rn_labelpaths;
+} rdsk_node_t;
+
+static int
+slice_cache_compare(const void *arg1, const void *arg2)
+{
+       const char  *nm1 = ((rdsk_node_t *)arg1)->rn_name;
+       const char  *nm2 = ((rdsk_node_t *)arg2)->rn_name;
+       char *nm1slice, *nm2slice;
+       int rv;
+
+       /*
+        * partitions one and three (slices zero and two) are the most
+        * likely to provide results, so put those first
+        */
+       nm1slice = strstr(nm1, "part1");
+       nm2slice = strstr(nm2, "part1");
+       if (nm1slice && !nm2slice) {
+               return (-1);
+       }
+       if (!nm1slice && nm2slice) {
+               return (1);
+       }
+       nm1slice = strstr(nm1, "part3");
+       nm2slice = strstr(nm2, "part3");
+       if (nm1slice && !nm2slice) {
+               return (-1);
+       }
+       if (!nm1slice && nm2slice) {
+               return (1);
+       }
+
+       rv = strcmp(nm1, nm2);
+       if (rv == 0)
+               return (0);
+       return (rv > 0 ? 1 : -1);
+}
+
+static boolean_t
+is_watchdog_dev(char *dev)
+{
+       /* For 'watchdog' dev */
+       if (strcmp(dev, "watchdog") == 0)
+               return (B_TRUE);
+
+       /* For 'watchdog<digit><whatever> */
+       if (strstr(dev, "watchdog") == dev && isdigit(dev[8]))
+               return (B_TRUE);
+
+       return (B_FALSE);
+}
+
+static int
+label_paths_impl(libzfs_handle_t *hdl, nvlist_t *nvroot, uint64_t pool_guid,
+    uint64_t vdev_guid, char **path, char **devid)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       uint64_t guid;
+       char *val;
+       int error;
+
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++) {
+                       error  = label_paths_impl(hdl, child[c],
+                           pool_guid, vdev_guid, path, devid);
+                       if (error)
+                               return (error);
+               }
+               return (0);
+       }
+
+       if (nvroot == NULL)
+               return (0);
+
+       error = nvlist_lookup_uint64(nvroot, ZPOOL_CONFIG_GUID, &guid);
+       if ((error != 0) || (guid != vdev_guid))
+               return (0);
+
+       error = nvlist_lookup_string(nvroot, ZPOOL_CONFIG_PATH, &val);
+       if (error == 0)
+               *path = val;
+
+       error = nvlist_lookup_string(nvroot, ZPOOL_CONFIG_DEVID, &val);
+       if (error == 0)
+               *devid = val;
+
+       return (0);
+}
+
+/*
+ * Given a disk label fetch the ZPOOL_CONFIG_PATH and ZPOOL_CONFIG_DEVID
+ * and store these strings as config_path and devid_path respectively.
+ * The returned pointers are only valid as long as label remains valid.
+ */
+static int
+label_paths(libzfs_handle_t *hdl, nvlist_t *label, char **path, char **devid)
+{
+       nvlist_t *nvroot;
+       uint64_t pool_guid;
+       uint64_t vdev_guid;
+
+       *path = NULL;
+       *devid = NULL;
+
+       if (nvlist_lookup_nvlist(label, ZPOOL_CONFIG_VDEV_TREE, &nvroot) ||
+           nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_GUID, &pool_guid) ||
+           nvlist_lookup_uint64(label, ZPOOL_CONFIG_GUID, &vdev_guid))
+               return (ENOENT);
+
+       return (label_paths_impl(hdl, nvroot, pool_guid, vdev_guid, path,
+           devid));
+}
+
+static void
+zpool_open_func(void *arg)
+{
+       rdsk_node_t *rn = arg;
+       libzfs_handle_t *hdl = rn->rn_hdl;
+       struct stat64 statbuf;
+       nvlist_t *config;
+       char *bname, *dupname;
+       int error;
+       int num_labels;
+       int fd;
+
+       /*
+        * Skip devices with well known prefixes there can be side effects
+        * when opening devices which need to be avoided.
+        *
+        * hpet     - High Precision Event Timer
+        * watchdog - Watchdog must be closed in a special way.
+        */
+       dupname = zfs_strdup(hdl, rn->rn_name);
+       bname = basename(dupname);
+       error = ((strcmp(bname, "hpet") == 0) || is_watchdog_dev(bname));
+       free(dupname);
+       if (error)
+               return;
+
+       /*
+        * Ignore failed stats.  We only want regular files and block devices.
+        */
+       if (stat64(rn->rn_name, &statbuf) != 0 ||
+           (!S_ISREG(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode)))
+               return;
+
+       if ((fd = open(rn->rn_name, O_RDONLY)) < 0)
+               return;
+
+       /*
+        * This file is too small to hold a zpool
+        */
+       if (S_ISREG(statbuf.st_mode) &&
+           statbuf.st_size < SPA_MINDEVSIZE) {
+               (void) close(fd);
+               return;
+       }
+
+       if ((zpool_read_label(fd, &config, &num_labels)) != 0) {
+               (void) close(fd);
+               return;
+       }
+
+       if (num_labels == 0) {
+               (void) close(fd);
+               nvlist_free(config);
+               return;
+       }
+
+       (void) close(fd);
+
+       rn->rn_config = config;
+       rn->rn_num_labels = num_labels;
+
+       /*
+        * Add additional entries for paths described by this label.
+        */
+       if (rn->rn_labelpaths) {
+               char *path = NULL;
+               char *devid = NULL;
+               rdsk_node_t *slice;
+               avl_index_t where;
+               int error;
+
+               if (label_paths(rn->rn_hdl, rn->rn_config, &path, &devid))
+                       return;
+
+               /*
+                * Allow devlinks to stabilize so all paths are available.
+                */
+               zpool_label_disk_wait(rn->rn_name, DISK_LABEL_WAIT);
+
+               if (path != NULL) {
+                       slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
+                       slice->rn_name = zfs_strdup(hdl, path);
+                       slice->rn_avl = rn->rn_avl;
+                       slice->rn_hdl = hdl;
+                       slice->rn_order = 1;
+                       slice->rn_labelpaths = B_FALSE;
+                       mutex_enter(rn->rn_lock);
+                       if (avl_find(rn->rn_avl, slice, &where)) {
+                       mutex_exit(rn->rn_lock);
+                               free(slice->rn_name);
+                               free(slice);
+                       } else {
+                               avl_insert(rn->rn_avl, slice, where);
+                               mutex_exit(rn->rn_lock);
+                               zpool_open_func(slice);
+                       }
+               }
+
+               if (devid != NULL) {
+                       slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
+                       error = asprintf(&slice->rn_name, "%s%s",
+                           DEV_BYID_PATH, devid);
+                       if (error == -1) {
+                               free(slice);
+                               return;
+                       }
+
+                       slice->rn_avl = rn->rn_avl;
+                       slice->rn_hdl = hdl;
+                       slice->rn_order = 2;
+                       slice->rn_labelpaths = B_FALSE;
+                       mutex_enter(rn->rn_lock);
+                       if (avl_find(rn->rn_avl, slice, &where)) {
+                               mutex_exit(rn->rn_lock);
+                               free(slice->rn_name);
+                               free(slice);
+                       } else {
+                               avl_insert(rn->rn_avl, slice, where);
+                               mutex_exit(rn->rn_lock);
+                               zpool_open_func(slice);
+                       }
+               }
+       }
+}
+
+/*
+ * Given a file descriptor, clear (zero) the label information.  This function
+ * is used in the appliance stack as part of the ZFS sysevent module and
+ * to implement the "zpool labelclear" command.
+ */
+int
+zpool_clear_label(int fd)
+{
+       struct stat64 statbuf;
+       int l;
+       vdev_label_t *label;
+       uint64_t size;
+
+       if (fstat64_blk(fd, &statbuf) == -1)
+               return (0);
+       size = P2ALIGN_TYPED(statbuf.st_size, sizeof (vdev_label_t), uint64_t);
+
+       if ((label = calloc(sizeof (vdev_label_t), 1)) == NULL)
+               return (-1);
+
+       for (l = 0; l < VDEV_LABELS; l++) {
+               if (pwrite64(fd, label, sizeof (vdev_label_t),
+                   label_offset(size, l)) != sizeof (vdev_label_t)) {
+                       free(label);
+                       return (-1);
+               }
+       }
+
+       free(label);
+       return (0);
+}
+
+/*
+ * Scan a list of directories for zfs devices.
+ */
+static int
+zpool_find_import_scan(libzfs_handle_t *hdl, kmutex_t *lock,
+    avl_tree_t **slice_cache, char **dir, int dirs)
+{
+       avl_tree_t *cache;
+       rdsk_node_t *slice;
+       void *cookie;
+       int i, error;
+
+       *slice_cache = NULL;
+       cache = zfs_alloc(hdl, sizeof (avl_tree_t));
+       avl_create(cache, slice_cache_compare, sizeof (rdsk_node_t),
+           offsetof(rdsk_node_t, rn_node));
+
+       for (i = 0; i < dirs; i++) {
+               char path[MAXPATHLEN];
+               struct dirent64 *dp;
+               DIR *dirp;
+
+               if (realpath(dir[i], path) == NULL) {
+                       error = errno;
+                       if (error == ENOENT)
+                               continue;
+
+                       zfs_error_aux(hdl, strerror(error));
+                       (void) zfs_error_fmt(hdl, EZFS_BADPATH, dgettext(
+                           TEXT_DOMAIN, "cannot resolve path '%s'"), dir[i]);
+                       goto error;
+               }
+
+               dirp = opendir(path);
+               if (dirp == NULL) {
+                       error = errno;
+                       zfs_error_aux(hdl, strerror(error));
+                       (void) zfs_error_fmt(hdl, EZFS_BADPATH,
+                           dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
+                       goto error;
+               }
+
+               while ((dp = readdir64(dirp)) != NULL) {
+                       const char *name = dp->d_name;
+                       if (name[0] == '.' &&
+                           (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
+                               continue;
+
+                       slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
+                       error = asprintf(&slice->rn_name, "%s/%s", path, name);
+                       if (error == -1) {
+                               free(slice);
+                               continue;
+                       }
+                       slice->rn_lock = lock;
+                       slice->rn_avl = cache;
+                       slice->rn_hdl = hdl;
+                       slice->rn_order = i+1;
+                       slice->rn_labelpaths = B_FALSE;
+                       mutex_enter(lock);
+                       avl_add(cache, slice);
+                       mutex_exit(lock);
+               }
+
+               (void) closedir(dirp);
+       }
+
+       *slice_cache = cache;
+       return (0);
+
+error:
+       cookie = NULL;
+       while ((slice = avl_destroy_nodes(cache, &cookie)) != NULL) {
+               free(slice->rn_name);
+               free(slice);
+       }
+       free(cache);
+
+       return (error);
+}
+
+/*
+ * Use libblkid to quickly enumerate all known zfs devices.
+ */
+static int
+zpool_find_import_blkid(libzfs_handle_t *hdl, kmutex_t *lock,
+    avl_tree_t **slice_cache)
+{
+       rdsk_node_t *slice;
+       blkid_cache cache;
+       blkid_dev_iterate iter;
+       blkid_dev dev;
+       int error;
+
+       *slice_cache = NULL;
+
+       error = blkid_get_cache(&cache, NULL);
+       if (error != 0)
+               return (error);
+
+       error = blkid_probe_all_new(cache);
+       if (error != 0) {
+               blkid_put_cache(cache);
+               return (error);
+       }
+
+       iter = blkid_dev_iterate_begin(cache);
+       if (iter == NULL) {
+               blkid_put_cache(cache);
+               return (EINVAL);
+       }
+
+       error = blkid_dev_set_search(iter, "TYPE", "zfs_member");
+       if (error != 0) {
+               blkid_dev_iterate_end(iter);
+               blkid_put_cache(cache);
+               return (error);
+       }
+
+       *slice_cache = zfs_alloc(hdl, sizeof (avl_tree_t));
+       avl_create(*slice_cache, slice_cache_compare, sizeof (rdsk_node_t),
+           offsetof(rdsk_node_t, rn_node));
+
+       while (blkid_dev_next(iter, &dev) == 0) {
+               slice = zfs_alloc(hdl, sizeof (rdsk_node_t));
+               slice->rn_name = zfs_strdup(hdl, blkid_dev_devname(dev));
+               slice->rn_lock = lock;
+               slice->rn_avl = *slice_cache;
+               slice->rn_hdl = hdl;
+               slice->rn_order = 100;
+               slice->rn_labelpaths = B_TRUE;
+               mutex_enter(lock);
+               avl_add(*slice_cache, slice);
+               mutex_exit(lock);
+       }
+
+       blkid_dev_iterate_end(iter);
+       blkid_put_cache(cache);
+
+       return (0);
+}
+
+char *
+zpool_default_import_path[DEFAULT_IMPORT_PATH_SIZE] = {
+       "/dev/disk/by-vdev",    /* Custom rules, use first if they exist */
+       "/dev/mapper",          /* Use multipath devices before components */
+       "/dev/disk/by-partlabel", /* Single unique entry set by user */
+       "/dev/disk/by-partuuid", /* Generated partition uuid */
+       "/dev/disk/by-label",   /* Custom persistent labels */
+       "/dev/disk/by-uuid",    /* Single unique entry and persistent */
+       "/dev/disk/by-id",      /* May be multiple entries and persistent */
+       "/dev/disk/by-path",    /* Encodes physical location and persistent */
+       "/dev"                  /* UNSAFE device names will change */
+};
+
+/*
+ * Given a list of directories to search, find all pools stored on disk.  This
+ * includes partial pools which are not available to import.  If no args are
+ * given (argc is 0), then the default directory (/dev/dsk) is searched.
+ * poolname or guid (but not both) are provided by the caller when trying
+ * to import a specific pool.
+ */
+static nvlist_t *
+zpool_find_import_impl(libzfs_handle_t *hdl, importargs_t *iarg)
+{
+       nvlist_t *ret = NULL;
+       pool_list_t pools = { 0 };
+       pool_entry_t *pe, *penext;
+       vdev_entry_t *ve, *venext;
+       config_entry_t *ce, *cenext;
+       name_entry_t *ne, *nenext;
+       kmutex_t lock;
+       avl_tree_t *cache;
+       rdsk_node_t *slice;
+       void *cookie;
+       taskq_t *t;
+
+       verify(iarg->poolname == NULL || iarg->guid == 0);
+       mutex_init(&lock, NULL, MUTEX_DEFAULT, NULL);
+
+       /*
+        * Locate pool member vdevs using libblkid or by directory scanning.
+        * On success a newly allocated AVL tree which is populated with an
+        * entry for each discovered vdev will be returned as the cache.
+        * It's the callers responsibility to consume and destroy this tree.
+        */
+       if (iarg->scan || iarg->paths != 0) {
+               int dirs = iarg->paths;
+               char **dir = iarg->path;
+
+               if (dirs == 0) {
+                       dir = zpool_default_import_path;
+                       dirs = DEFAULT_IMPORT_PATH_SIZE;
+               }
+
+               if (zpool_find_import_scan(hdl, &lock, &cache, dir,  dirs) != 0)
+                       return (NULL);
+       } else {
+               if (zpool_find_import_blkid(hdl, &lock, &cache) != 0)
+                       return (NULL);
+       }
+
+       /*
+        * Create a thread pool to parallelize the process of reading and
+        * validating labels, a large number of threads can be used due to
+        * minimal contention.
+        */
+       t = taskq_create("z_import", 2 * boot_ncpus, defclsyspri,
+           2 * boot_ncpus, INT_MAX, TASKQ_PREPOPULATE);
+
+       for (slice = avl_first(cache); slice;
+           (slice = avl_walk(cache, slice, AVL_AFTER)))
+               (void) taskq_dispatch(t, zpool_open_func, slice, TQ_SLEEP);
+
+       taskq_wait(t);
+       taskq_destroy(t);
+
+       /*
+        * Process the cache filtering out any entries which are not
+        * for the specificed pool then adding matching label configs.
+        */
+       cookie = NULL;
+       while ((slice = avl_destroy_nodes(cache, &cookie)) != NULL) {
+               if (slice->rn_config != NULL) {
+                       nvlist_t *config = slice->rn_config;
+                       boolean_t matched = B_TRUE;
+
+                       if (iarg->poolname != NULL) {
+                               char *pname;
+
+                               matched = nvlist_lookup_string(config,
+                                   ZPOOL_CONFIG_POOL_NAME, &pname) == 0 &&
+                                   strcmp(iarg->poolname, pname) == 0;
+                       } else if (iarg->guid != 0) {
+                               uint64_t this_guid;
+
+                               matched = nvlist_lookup_uint64(config,
+                                   ZPOOL_CONFIG_POOL_GUID, &this_guid) == 0 &&
+                                   iarg->guid == this_guid;
+                       }
+                       if (!matched) {
+                               nvlist_free(config);
+                       } else {
+                               add_config(hdl, &pools,
+                                   slice->rn_name, slice->rn_order,
+                                   slice->rn_num_labels, config);
+                       }
+               }
+               free(slice->rn_name);
+               free(slice);
+       }
+       avl_destroy(cache);
+       free(cache);
+       mutex_destroy(&lock);
+
+       ret = get_configs(hdl, &pools, iarg->can_be_active);
+
+       for (pe = pools.pools; pe != NULL; pe = penext) {
+               penext = pe->pe_next;
+               for (ve = pe->pe_vdevs; ve != NULL; ve = venext) {
+                       venext = ve->ve_next;
+                       for (ce = ve->ve_configs; ce != NULL; ce = cenext) {
+                               cenext = ce->ce_next;
+                               nvlist_free(ce->ce_config);
+                               free(ce);
+                       }
+                       free(ve);
+               }
+               free(pe);
+       }
+
+       for (ne = pools.names; ne != NULL; ne = nenext) {
+               nenext = ne->ne_next;
+               free(ne->ne_name);
+               free(ne);
+       }
+
+       return (ret);
+}
+
+nvlist_t *
+zpool_find_import(libzfs_handle_t *hdl, int argc, char **argv)
+{
+       importargs_t iarg = { 0 };
+
+       iarg.paths = argc;
+       iarg.path = argv;
+
+       return (zpool_find_import_impl(hdl, &iarg));
+}
+
+/*
+ * Given a cache file, return the contents as a list of importable pools.
+ * poolname or guid (but not both) are provided by the caller when trying
+ * to import a specific pool.
+ */
+nvlist_t *
+zpool_find_import_cached(libzfs_handle_t *hdl, const char *cachefile,
+    char *poolname, uint64_t guid)
+{
+       char *buf;
+       int fd;
+       struct stat64 statbuf;
+       nvlist_t *raw, *src, *dst;
+       nvlist_t *pools;
+       nvpair_t *elem;
+       char *name;
+       uint64_t this_guid;
+       boolean_t active;
+
+       verify(poolname == NULL || guid == 0);
+
+       if ((fd = open(cachefile, O_RDONLY)) < 0) {
+               zfs_error_aux(hdl, "%s", strerror(errno));
+               (void) zfs_error(hdl, EZFS_BADCACHE,
+                   dgettext(TEXT_DOMAIN, "failed to open cache file"));
+               return (NULL);
+       }
+
+       if (fstat64(fd, &statbuf) != 0) {
+               zfs_error_aux(hdl, "%s", strerror(errno));
+               (void) close(fd);
+               (void) zfs_error(hdl, EZFS_BADCACHE,
+                   dgettext(TEXT_DOMAIN, "failed to get size of cache file"));
+               return (NULL);
+       }
+
+       if ((buf = zfs_alloc(hdl, statbuf.st_size)) == NULL) {
+               (void) close(fd);
+               return (NULL);
+       }
+
+       if (read(fd, buf, statbuf.st_size) != statbuf.st_size) {
+               (void) close(fd);
+               free(buf);
+               (void) zfs_error(hdl, EZFS_BADCACHE,
+                   dgettext(TEXT_DOMAIN,
+                   "failed to read cache file contents"));
+               return (NULL);
+       }
+
+       (void) close(fd);
+
+       if (nvlist_unpack(buf, statbuf.st_size, &raw, 0) != 0) {
+               free(buf);
+               (void) zfs_error(hdl, EZFS_BADCACHE,
+                   dgettext(TEXT_DOMAIN,
+                   "invalid or corrupt cache file contents"));
+               return (NULL);
+       }
+
+       free(buf);
+
+       /*
+        * Go through and get the current state of the pools and refresh their
+        * state.
+        */
+       if (nvlist_alloc(&pools, 0, 0) != 0) {
+               (void) no_memory(hdl);
+               nvlist_free(raw);
+               return (NULL);
+       }
+
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(raw, elem)) != NULL) {
+               src = fnvpair_value_nvlist(elem);
+
+               name = fnvlist_lookup_string(src, ZPOOL_CONFIG_POOL_NAME);
+               if (poolname != NULL && strcmp(poolname, name) != 0)
+                       continue;
+
+               this_guid = fnvlist_lookup_uint64(src, ZPOOL_CONFIG_POOL_GUID);
+               if (guid != 0 && guid != this_guid)
+                       continue;
+
+               if (pool_active(hdl, name, this_guid, &active) != 0) {
+                       nvlist_free(raw);
+                       nvlist_free(pools);
+                       return (NULL);
+               }
+
+               if (active)
+                       continue;
+
+               if ((dst = refresh_config(hdl, src)) == NULL) {
+                       nvlist_free(raw);
+                       nvlist_free(pools);
+                       return (NULL);
+               }
+
+               if (nvlist_add_nvlist(pools, nvpair_name(elem), dst) != 0) {
+                       (void) no_memory(hdl);
+                       nvlist_free(dst);
+                       nvlist_free(raw);
+                       nvlist_free(pools);
+                       return (NULL);
+               }
+               nvlist_free(dst);
+       }
+
+       nvlist_free(raw);
+       return (pools);
+}
+
+static int
+name_or_guid_exists(zpool_handle_t *zhp, void *data)
+{
+       importargs_t *import = data;
+       int found = 0;
+
+       if (import->poolname != NULL) {
+               char *pool_name;
+
+               verify(nvlist_lookup_string(zhp->zpool_config,
+                   ZPOOL_CONFIG_POOL_NAME, &pool_name) == 0);
+               if (strcmp(pool_name, import->poolname) == 0)
+                       found = 1;
+       } else {
+               uint64_t pool_guid;
+
+               verify(nvlist_lookup_uint64(zhp->zpool_config,
+                   ZPOOL_CONFIG_POOL_GUID, &pool_guid) == 0);
+               if (pool_guid == import->guid)
+                       found = 1;
+       }
+
+       zpool_close(zhp);
+       return (found);
+}
+
+nvlist_t *
+zpool_search_import(libzfs_handle_t *hdl, importargs_t *import)
+{
+       verify(import->poolname == NULL || import->guid == 0);
+
+       if (import->unique)
+               import->exists = zpool_iter(hdl, name_or_guid_exists, import);
+
+       if (import->cachefile != NULL)
+               return (zpool_find_import_cached(hdl, import->cachefile,
+                   import->poolname, import->guid));
+
+       return (zpool_find_import_impl(hdl, import));
+}
+
+boolean_t
+find_guid(nvlist_t *nv, uint64_t guid)
+{
+       uint64_t tmp;
+       nvlist_t **child;
+       uint_t c, children;
+
+       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &tmp) == 0);
+       if (tmp == guid)
+               return (B_TRUE);
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if (find_guid(child[c], guid))
+                               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+typedef struct aux_cbdata {
+       const char      *cb_type;
+       uint64_t        cb_guid;
+       zpool_handle_t  *cb_zhp;
+} aux_cbdata_t;
+
+static int
+find_aux(zpool_handle_t *zhp, void *data)
+{
+       aux_cbdata_t *cbp = data;
+       nvlist_t **list;
+       uint_t i, count;
+       uint64_t guid;
+       nvlist_t *nvroot;
+
+       verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+
+       if (nvlist_lookup_nvlist_array(nvroot, cbp->cb_type,
+           &list, &count) == 0) {
+               for (i = 0; i < count; i++) {
+                       verify(nvlist_lookup_uint64(list[i],
+                           ZPOOL_CONFIG_GUID, &guid) == 0);
+                       if (guid == cbp->cb_guid) {
+                               cbp->cb_zhp = zhp;
+                               return (1);
+                       }
+               }
+       }
+
+       zpool_close(zhp);
+       return (0);
+}
+
+/*
+ * Determines if the pool is in use.  If so, it returns true and the state of
+ * the pool as well as the name of the pool.  Both strings are allocated and
+ * must be freed by the caller.
+ */
+int
+zpool_in_use(libzfs_handle_t *hdl, int fd, pool_state_t *state, char **namestr,
+    boolean_t *inuse)
+{
+       nvlist_t *config;
+       char *name;
+       boolean_t ret;
+       uint64_t guid, vdev_guid;
+       zpool_handle_t *zhp;
+       nvlist_t *pool_config;
+       uint64_t stateval, isspare;
+       aux_cbdata_t cb = { 0 };
+       boolean_t isactive;
+
+       *inuse = B_FALSE;
+
+       if (zpool_read_label(fd, &config, NULL) != 0) {
+               (void) no_memory(hdl);
+               return (-1);
+       }
+
+       if (config == NULL)
+               return (0);
+
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+           &stateval) == 0);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID,
+           &vdev_guid) == 0);
+
+       if (stateval != POOL_STATE_SPARE && stateval != POOL_STATE_L2CACHE) {
+               verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+                   &name) == 0);
+               verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+                   &guid) == 0);
+       }
+
+       switch (stateval) {
+       case POOL_STATE_EXPORTED:
+               /*
+                * A pool with an exported state may in fact be imported
+                * read-only, so check the in-core state to see if it's
+                * active and imported read-only.  If it is, set
+                * its state to active.
+                */
+               if (pool_active(hdl, name, guid, &isactive) == 0 && isactive &&
+                   (zhp = zpool_open_canfail(hdl, name)) != NULL) {
+                       if (zpool_get_prop_int(zhp, ZPOOL_PROP_READONLY, NULL))
+                               stateval = POOL_STATE_ACTIVE;
+
+                       /*
+                        * All we needed the zpool handle for is the
+                        * readonly prop check.
+                        */
+                       zpool_close(zhp);
+               }
+
+               ret = B_TRUE;
+               break;
+
+       case POOL_STATE_ACTIVE:
+               /*
+                * For an active pool, we have to determine if it's really part
+                * of a currently active pool (in which case the pool will exist
+                * and the guid will be the same), or whether it's part of an
+                * active pool that was disconnected without being explicitly
+                * exported.
+                */
+               if (pool_active(hdl, name, guid, &isactive) != 0) {
+                       nvlist_free(config);
+                       return (-1);
+               }
+
+               if (isactive) {
+                       /*
+                        * Because the device may have been removed while
+                        * offlined, we only report it as active if the vdev is
+                        * still present in the config.  Otherwise, pretend like
+                        * it's not in use.
+                        */
+                       if ((zhp = zpool_open_canfail(hdl, name)) != NULL &&
+                           (pool_config = zpool_get_config(zhp, NULL))
+                           != NULL) {
+                               nvlist_t *nvroot;
+
+                               verify(nvlist_lookup_nvlist(pool_config,
+                                   ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+                               ret = find_guid(nvroot, vdev_guid);
+                       } else {
+                               ret = B_FALSE;
+                       }
+
+                       /*
+                        * If this is an active spare within another pool, we
+                        * treat it like an unused hot spare.  This allows the
+                        * user to create a pool with a hot spare that currently
+                        * in use within another pool.  Since we return B_TRUE,
+                        * libdiskmgt will continue to prevent generic consumers
+                        * from using the device.
+                        */
+                       if (ret && nvlist_lookup_uint64(config,
+                           ZPOOL_CONFIG_IS_SPARE, &isspare) == 0 && isspare)
+                               stateval = POOL_STATE_SPARE;
+
+                       if (zhp != NULL)
+                               zpool_close(zhp);
+               } else {
+                       stateval = POOL_STATE_POTENTIALLY_ACTIVE;
+                       ret = B_TRUE;
+               }
+               break;
+
+       case POOL_STATE_SPARE:
+               /*
+                * For a hot spare, it can be either definitively in use, or
+                * potentially active.  To determine if it's in use, we iterate
+                * over all pools in the system and search for one with a spare
+                * with a matching guid.
+                *
+                * Due to the shared nature of spares, we don't actually report
+                * the potentially active case as in use.  This means the user
+                * can freely create pools on the hot spares of exported pools,
+                * but to do otherwise makes the resulting code complicated, and
+                * we end up having to deal with this case anyway.
+                */
+               cb.cb_zhp = NULL;
+               cb.cb_guid = vdev_guid;
+               cb.cb_type = ZPOOL_CONFIG_SPARES;
+               if (zpool_iter(hdl, find_aux, &cb) == 1) {
+                       name = (char *)zpool_get_name(cb.cb_zhp);
+                       ret = B_TRUE;
+               } else {
+                       ret = B_FALSE;
+               }
+               break;
+
+       case POOL_STATE_L2CACHE:
+
+               /*
+                * Check if any pool is currently using this l2cache device.
+                */
+               cb.cb_zhp = NULL;
+               cb.cb_guid = vdev_guid;
+               cb.cb_type = ZPOOL_CONFIG_L2CACHE;
+               if (zpool_iter(hdl, find_aux, &cb) == 1) {
+                       name = (char *)zpool_get_name(cb.cb_zhp);
+                       ret = B_TRUE;
+               } else {
+                       ret = B_FALSE;
+               }
+               break;
+
+       default:
+               ret = B_FALSE;
+       }
+
+
+       if (ret) {
+               if ((*namestr = zfs_strdup(hdl, name)) == NULL) {
+                       if (cb.cb_zhp)
+                               zpool_close(cb.cb_zhp);
+                       nvlist_free(config);
+                       return (-1);
+               }
+               *state = (pool_state_t)stateval;
+       }
+
+       if (cb.cb_zhp)
+               zpool_close(cb.cb_zhp);
+
+       nvlist_free(config);
+       *inuse = ret;
+       return (0);
+}
diff --git a/zfs/lib/libzfs/libzfs_iter.c b/zfs/lib/libzfs/libzfs_iter.c
new file mode 100644 (file)
index 0000000..c656db6
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <libintl.h>
+#include <libzfs.h>
+
+#include "libzfs_impl.h"
+
+int
+zfs_iter_clones(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+       nvlist_t *nvl = zfs_get_clones_nvl(zhp);
+       nvpair_t *pair;
+
+       if (nvl == NULL)
+               return (0);
+
+       for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(nvl, pair)) {
+               zfs_handle_t *clone = zfs_open(zhp->zfs_hdl, nvpair_name(pair),
+                   ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+               if (clone != NULL) {
+                       int err = func(clone, data);
+                       if (err != 0)
+                               return (err);
+               }
+       }
+       return (0);
+}
+
+static int
+zfs_do_list_ioctl(zfs_handle_t *zhp, int arg, zfs_cmd_t *zc)
+{
+       int rc;
+       uint64_t        orig_cookie;
+
+       orig_cookie = zc->zc_cookie;
+top:
+       (void) strlcpy(zc->zc_name, zhp->zfs_name, sizeof (zc->zc_name));
+       rc = ioctl(zhp->zfs_hdl->libzfs_fd, arg, zc);
+
+       if (rc == -1) {
+               switch (errno) {
+               case ENOMEM:
+                       /* expand nvlist memory and try again */
+                       if (zcmd_expand_dst_nvlist(zhp->zfs_hdl, zc) != 0) {
+                               zcmd_free_nvlists(zc);
+                               return (-1);
+                       }
+                       zc->zc_cookie = orig_cookie;
+                       goto top;
+               /*
+                * An errno value of ESRCH indicates normal completion.
+                * If ENOENT is returned, then the underlying dataset
+                * has been removed since we obtained the handle.
+                */
+               case ESRCH:
+               case ENOENT:
+                       rc = 1;
+                       break;
+               default:
+                       rc = zfs_standard_error(zhp->zfs_hdl, errno,
+                           dgettext(TEXT_DOMAIN,
+                           "cannot iterate filesystems"));
+                       break;
+               }
+       }
+       return (rc);
+}
+
+/*
+ * Iterate over all child filesystems
+ */
+int
+zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+       zfs_cmd_t zc = {"\0"};
+       zfs_handle_t *nzhp;
+       int ret;
+
+       if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM)
+               return (0);
+
+       if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+               return (-1);
+
+       while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_DATASET_LIST_NEXT,
+           &zc)) == 0) {
+               /*
+                * Silently ignore errors, as the only plausible explanation is
+                * that the pool has since been removed.
+                */
+               if ((nzhp = make_dataset_handle_zc(zhp->zfs_hdl,
+                   &zc)) == NULL) {
+                       continue;
+               }
+
+               if ((ret = func(nzhp, data)) != 0) {
+                       zcmd_free_nvlists(&zc);
+                       return (ret);
+               }
+       }
+       zcmd_free_nvlists(&zc);
+       return ((ret < 0) ? ret : 0);
+}
+
+/*
+ * Iterate over all snapshots
+ */
+int
+zfs_iter_snapshots(zfs_handle_t *zhp, boolean_t simple, zfs_iter_f func,
+    void *data)
+{
+       zfs_cmd_t zc = {"\0"};
+       zfs_handle_t *nzhp;
+       int ret;
+
+       if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT ||
+           zhp->zfs_type == ZFS_TYPE_BOOKMARK)
+               return (0);
+
+       zc.zc_simple = simple;
+
+       if (zcmd_alloc_dst_nvlist(zhp->zfs_hdl, &zc, 0) != 0)
+               return (-1);
+       while ((ret = zfs_do_list_ioctl(zhp, ZFS_IOC_SNAPSHOT_LIST_NEXT,
+           &zc)) == 0) {
+
+               if (simple)
+                       nzhp = make_dataset_simple_handle_zc(zhp, &zc);
+               else
+                       nzhp = make_dataset_handle_zc(zhp->zfs_hdl, &zc);
+               if (nzhp == NULL)
+                       continue;
+
+               if ((ret = func(nzhp, data)) != 0) {
+                       zcmd_free_nvlists(&zc);
+                       return (ret);
+               }
+       }
+       zcmd_free_nvlists(&zc);
+       return ((ret < 0) ? ret : 0);
+}
+
+/*
+ * Iterate over all bookmarks
+ */
+int
+zfs_iter_bookmarks(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+       zfs_handle_t *nzhp;
+       nvlist_t *props = NULL;
+       nvlist_t *bmarks = NULL;
+       int err;
+       nvpair_t *pair;
+
+       if ((zfs_get_type(zhp) & (ZFS_TYPE_SNAPSHOT | ZFS_TYPE_BOOKMARK)) != 0)
+               return (0);
+
+       /* Setup the requested properties nvlist. */
+       props = fnvlist_alloc();
+       fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_GUID));
+       fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATETXG));
+       fnvlist_add_boolean(props, zfs_prop_to_name(ZFS_PROP_CREATION));
+
+       if ((err = lzc_get_bookmarks(zhp->zfs_name, props, &bmarks)) != 0)
+               goto out;
+
+       for (pair = nvlist_next_nvpair(bmarks, NULL);
+           pair != NULL; pair = nvlist_next_nvpair(bmarks, pair)) {
+               char name[ZFS_MAX_DATASET_NAME_LEN];
+               char *bmark_name;
+               nvlist_t *bmark_props;
+
+               bmark_name = nvpair_name(pair);
+               bmark_props = fnvpair_value_nvlist(pair);
+
+               (void) snprintf(name, sizeof (name), "%s#%s", zhp->zfs_name,
+                   bmark_name);
+
+               nzhp = make_bookmark_handle(zhp, name, bmark_props);
+               if (nzhp == NULL)
+                       continue;
+
+               if ((err = func(nzhp, data)) != 0)
+                       goto out;
+       }
+
+out:
+       fnvlist_free(props);
+       fnvlist_free(bmarks);
+
+       return (err);
+}
+
+/*
+ * Routines for dealing with the sorted snapshot functionality
+ */
+typedef struct zfs_node {
+       zfs_handle_t    *zn_handle;
+       avl_node_t      zn_avlnode;
+} zfs_node_t;
+
+static int
+zfs_sort_snaps(zfs_handle_t *zhp, void *data)
+{
+       avl_tree_t *avl = data;
+       zfs_node_t *node;
+       zfs_node_t search;
+
+       search.zn_handle = zhp;
+       node = avl_find(avl, &search, NULL);
+       if (node) {
+               /*
+                * If this snapshot was renamed while we were creating the
+                * AVL tree, it's possible that we already inserted it under
+                * its old name. Remove the old handle before adding the new
+                * one.
+                */
+               zfs_close(node->zn_handle);
+               avl_remove(avl, node);
+               free(node);
+       }
+
+       node = zfs_alloc(zhp->zfs_hdl, sizeof (zfs_node_t));
+       node->zn_handle = zhp;
+       avl_add(avl, node);
+
+       return (0);
+}
+
+static int
+zfs_snapshot_compare(const void *larg, const void *rarg)
+{
+       zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle;
+       zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle;
+       uint64_t lcreate, rcreate;
+
+       /*
+        * Sort them according to creation time.  We use the hidden
+        * CREATETXG property to get an absolute ordering of snapshots.
+        */
+       lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG);
+       rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG);
+
+       return (AVL_CMP(lcreate, rcreate));
+}
+
+int
+zfs_iter_snapshots_sorted(zfs_handle_t *zhp, zfs_iter_f callback, void *data)
+{
+       int ret = 0;
+       zfs_node_t *node;
+       avl_tree_t avl;
+       void *cookie = NULL;
+
+       avl_create(&avl, zfs_snapshot_compare,
+           sizeof (zfs_node_t), offsetof(zfs_node_t, zn_avlnode));
+
+       ret = zfs_iter_snapshots(zhp, B_FALSE, zfs_sort_snaps, &avl);
+
+       for (node = avl_first(&avl); node != NULL; node = AVL_NEXT(&avl, node))
+               ret |= callback(node->zn_handle, data);
+
+       while ((node = avl_destroy_nodes(&avl, &cookie)) != NULL)
+               free(node);
+
+       avl_destroy(&avl);
+
+       return (ret);
+}
+
+typedef struct {
+       char *ssa_first;
+       char *ssa_last;
+       boolean_t ssa_seenfirst;
+       boolean_t ssa_seenlast;
+       zfs_iter_f ssa_func;
+       void *ssa_arg;
+} snapspec_arg_t;
+
+static int
+snapspec_cb(zfs_handle_t *zhp, void *arg) {
+       snapspec_arg_t *ssa = arg;
+       char *shortsnapname;
+       int err = 0;
+
+       if (ssa->ssa_seenlast)
+               return (0);
+       shortsnapname = zfs_strdup(zhp->zfs_hdl,
+           strchr(zfs_get_name(zhp), '@') + 1);
+
+       if (!ssa->ssa_seenfirst && strcmp(shortsnapname, ssa->ssa_first) == 0)
+               ssa->ssa_seenfirst = B_TRUE;
+
+       if (ssa->ssa_seenfirst) {
+               err = ssa->ssa_func(zhp, ssa->ssa_arg);
+       } else {
+               zfs_close(zhp);
+       }
+
+       if (strcmp(shortsnapname, ssa->ssa_last) == 0)
+               ssa->ssa_seenlast = B_TRUE;
+       free(shortsnapname);
+
+       return (err);
+}
+
+/*
+ * spec is a string like "A,B%C,D"
+ *
+ * <snaps>, where <snaps> can be:
+ *      <snap>          (single snapshot)
+ *      <snap>%<snap>   (range of snapshots, inclusive)
+ *      %<snap>         (range of snapshots, starting with earliest)
+ *      <snap>%         (range of snapshots, ending with last)
+ *      %               (all snapshots)
+ *      <snaps>[,...]   (comma separated list of the above)
+ *
+ * If a snapshot can not be opened, continue trying to open the others, but
+ * return ENOENT at the end.
+ */
+int
+zfs_iter_snapspec(zfs_handle_t *fs_zhp, const char *spec_orig,
+    zfs_iter_f func, void *arg)
+{
+       char *buf, *comma_separated, *cp;
+       int err = 0;
+       int ret = 0;
+
+       buf = zfs_strdup(fs_zhp->zfs_hdl, spec_orig);
+       cp = buf;
+
+       while ((comma_separated = strsep(&cp, ",")) != NULL) {
+               char *pct = strchr(comma_separated, '%');
+               if (pct != NULL) {
+                       snapspec_arg_t ssa = { 0 };
+                       ssa.ssa_func = func;
+                       ssa.ssa_arg = arg;
+
+                       if (pct == comma_separated)
+                               ssa.ssa_seenfirst = B_TRUE;
+                       else
+                               ssa.ssa_first = comma_separated;
+                       *pct = '\0';
+                       ssa.ssa_last = pct + 1;
+
+                       /*
+                        * If there is a lastname specified, make sure it
+                        * exists.
+                        */
+                       if (ssa.ssa_last[0] != '\0') {
+                               char snapname[ZFS_MAX_DATASET_NAME_LEN];
+                               (void) snprintf(snapname, sizeof (snapname),
+                                   "%s@%s", zfs_get_name(fs_zhp),
+                                   ssa.ssa_last);
+                               if (!zfs_dataset_exists(fs_zhp->zfs_hdl,
+                                   snapname, ZFS_TYPE_SNAPSHOT)) {
+                                       ret = ENOENT;
+                                       continue;
+                               }
+                       }
+
+                       err = zfs_iter_snapshots_sorted(fs_zhp,
+                           snapspec_cb, &ssa);
+                       if (ret == 0)
+                               ret = err;
+                       if (ret == 0 && (!ssa.ssa_seenfirst ||
+                           (ssa.ssa_last[0] != '\0' && !ssa.ssa_seenlast))) {
+                               ret = ENOENT;
+                       }
+               } else {
+                       char snapname[ZFS_MAX_DATASET_NAME_LEN];
+                       zfs_handle_t *snap_zhp;
+                       (void) snprintf(snapname, sizeof (snapname), "%s@%s",
+                           zfs_get_name(fs_zhp), comma_separated);
+                       snap_zhp = make_dataset_handle(fs_zhp->zfs_hdl,
+                           snapname);
+                       if (snap_zhp == NULL) {
+                               ret = ENOENT;
+                               continue;
+                       }
+                       err = func(snap_zhp, arg);
+                       if (ret == 0)
+                               ret = err;
+               }
+       }
+
+       free(buf);
+       return (ret);
+}
+
+/*
+ * Iterate over all children, snapshots and filesystems
+ */
+int
+zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+       int ret;
+
+       if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
+               return (ret);
+
+       return (zfs_iter_snapshots(zhp, B_FALSE, func, data));
+}
+
+
+typedef struct iter_stack_frame {
+       struct iter_stack_frame *next;
+       zfs_handle_t *zhp;
+} iter_stack_frame_t;
+
+typedef struct iter_dependents_arg {
+       boolean_t first;
+       boolean_t allowrecursion;
+       iter_stack_frame_t *stack;
+       zfs_iter_f func;
+       void *data;
+} iter_dependents_arg_t;
+
+static int
+iter_dependents_cb(zfs_handle_t *zhp, void *arg)
+{
+       iter_dependents_arg_t *ida = arg;
+       int err = 0;
+       boolean_t first = ida->first;
+       ida->first = B_FALSE;
+
+       if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT) {
+               err = zfs_iter_clones(zhp, iter_dependents_cb, ida);
+       } else if (zhp->zfs_type != ZFS_TYPE_BOOKMARK) {
+               iter_stack_frame_t isf;
+               iter_stack_frame_t *f;
+
+               /*
+                * check if there is a cycle by seeing if this fs is already
+                * on the stack.
+                */
+               for (f = ida->stack; f != NULL; f = f->next) {
+                       if (f->zhp->zfs_dmustats.dds_guid ==
+                           zhp->zfs_dmustats.dds_guid) {
+                               if (ida->allowrecursion) {
+                                       zfs_close(zhp);
+                                       return (0);
+                               } else {
+                                       zfs_error_aux(zhp->zfs_hdl,
+                                           dgettext(TEXT_DOMAIN,
+                                           "recursive dependency at '%s'"),
+                                           zfs_get_name(zhp));
+                                       err = zfs_error(zhp->zfs_hdl,
+                                           EZFS_RECURSIVE,
+                                           dgettext(TEXT_DOMAIN,
+                                           "cannot determine dependent "
+                                           "datasets"));
+                                       zfs_close(zhp);
+                                       return (err);
+                               }
+                       }
+               }
+
+               isf.zhp = zhp;
+               isf.next = ida->stack;
+               ida->stack = &isf;
+               err = zfs_iter_filesystems(zhp, iter_dependents_cb, ida);
+               if (err == 0)
+                       err = zfs_iter_snapshots(zhp, B_FALSE,
+                           iter_dependents_cb, ida);
+               ida->stack = isf.next;
+       }
+
+       if (!first && err == 0)
+               err = ida->func(zhp, ida->data);
+       else
+               zfs_close(zhp);
+
+       return (err);
+}
+
+int
+zfs_iter_dependents(zfs_handle_t *zhp, boolean_t allowrecursion,
+    zfs_iter_f func, void *data)
+{
+       iter_dependents_arg_t ida;
+       ida.allowrecursion = allowrecursion;
+       ida.stack = NULL;
+       ida.func = func;
+       ida.data = data;
+       ida.first = B_TRUE;
+       return (iter_dependents_cb(zfs_handle_dup(zhp), &ida));
+}
diff --git a/zfs/lib/libzfs/libzfs_mount.c b/zfs/lib/libzfs/libzfs_mount.c
new file mode 100644 (file)
index 0000000..4478167
--- /dev/null
@@ -0,0 +1,1320 @@
+/*
+ * 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 2015 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * Routines to manage ZFS mounts.  We separate all the nasty routines that have
+ * to deal with the OS.  The following functions are the main entry points --
+ * they are used by mount and unmount and when changing a filesystem's
+ * mountpoint.
+ *
+ *     zfs_is_mounted()
+ *     zfs_mount()
+ *     zfs_unmount()
+ *     zfs_unmountall()
+ *
+ * This file also contains the functions used to manage sharing filesystems via
+ * NFS and iSCSI:
+ *
+ *     zfs_is_shared()
+ *     zfs_share()
+ *     zfs_unshare()
+ *
+ *     zfs_is_shared_nfs()
+ *     zfs_is_shared_smb()
+ *     zfs_share_proto()
+ *     zfs_shareall();
+ *     zfs_unshare_nfs()
+ *     zfs_unshare_smb()
+ *     zfs_unshareall_nfs()
+ *     zfs_unshareall_smb()
+ *     zfs_unshareall()
+ *     zfs_unshareall_bypath()
+ *
+ * The following functions are available for pool consumers, and will
+ * mount/unmount and share/unshare all datasets within pool:
+ *
+ *     zpool_enable_datasets()
+ *     zpool_disable_datasets()
+ */
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <libgen.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <zone.h>
+#include <sys/mntent.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <libzfs.h>
+
+#include "libzfs_impl.h"
+
+#include <libshare.h>
+#include <sys/systeminfo.h>
+#define        MAXISALEN       257     /* based on sysinfo(2) man page */
+
+static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
+zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
+    zfs_share_proto_t);
+
+/*
+ * The share protocols table must be in the same order as the zfs_share_prot_t
+ * enum in libzfs_impl.h
+ */
+typedef struct {
+       zfs_prop_t p_prop;
+       char *p_name;
+       int p_share_err;
+       int p_unshare_err;
+} proto_table_t;
+
+proto_table_t proto_table[PROTO_END] = {
+       {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
+       {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
+};
+
+zfs_share_proto_t nfs_only[] = {
+       PROTO_NFS,
+       PROTO_END
+};
+
+zfs_share_proto_t smb_only[] = {
+       PROTO_SMB,
+       PROTO_END
+};
+zfs_share_proto_t share_all_proto[] = {
+       PROTO_NFS,
+       PROTO_SMB,
+       PROTO_END
+};
+
+/*
+ * Search the sharetab for the given mountpoint and protocol, returning
+ * a zfs_share_type_t value.
+ */
+static zfs_share_type_t
+is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
+{
+       char buf[MAXPATHLEN], *tab;
+       char *ptr;
+
+       if (hdl->libzfs_sharetab == NULL)
+               return (SHARED_NOT_SHARED);
+
+       (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
+
+       while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
+
+               /* the mountpoint is the first entry on each line */
+               if ((tab = strchr(buf, '\t')) == NULL)
+                       continue;
+
+               *tab = '\0';
+               if (strcmp(buf, mountpoint) == 0) {
+                       /*
+                        * the protocol field is the third field
+                        * skip over second field
+                        */
+                       ptr = ++tab;
+                       if ((tab = strchr(ptr, '\t')) == NULL)
+                               continue;
+                       ptr = ++tab;
+                       if ((tab = strchr(ptr, '\t')) == NULL)
+                               continue;
+                       *tab = '\0';
+                       if (strcmp(ptr,
+                           proto_table[proto].p_name) == 0) {
+                               switch (proto) {
+                               case PROTO_NFS:
+                                       return (SHARED_NFS);
+                               case PROTO_SMB:
+                                       return (SHARED_SMB);
+                               default:
+                                       return (0);
+                               }
+                       }
+               }
+       }
+
+       return (SHARED_NOT_SHARED);
+}
+
+/*
+ * Returns true if the specified directory is empty.  If we can't open the
+ * directory at all, return true so that the mount can fail with a more
+ * informative error message.
+ */
+static boolean_t
+dir_is_empty(const char *dirname)
+{
+       DIR *dirp;
+       struct dirent64 *dp;
+
+       if ((dirp = opendir(dirname)) == NULL)
+               return (B_TRUE);
+
+       while ((dp = readdir64(dirp)) != NULL) {
+
+               if (strcmp(dp->d_name, ".") == 0 ||
+                   strcmp(dp->d_name, "..") == 0)
+                       continue;
+
+               (void) closedir(dirp);
+               return (B_FALSE);
+       }
+
+       (void) closedir(dirp);
+       return (B_TRUE);
+}
+
+/*
+ * Checks to see if the mount is active.  If the filesystem is mounted, we fill
+ * in 'where' with the current mountpoint, and return 1.  Otherwise, we return
+ * 0.
+ */
+boolean_t
+is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
+{
+       struct mnttab entry;
+
+       if (libzfs_mnttab_find(zfs_hdl, special, &entry) != 0)
+               return (B_FALSE);
+
+       if (where != NULL)
+               *where = zfs_strdup(zfs_hdl, entry.mnt_mountp);
+
+       return (B_TRUE);
+}
+
+boolean_t
+zfs_is_mounted(zfs_handle_t *zhp, char **where)
+{
+       return (is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where));
+}
+
+/*
+ * Returns true if the given dataset is mountable, false otherwise.  Returns the
+ * mountpoint in 'buf'.
+ */
+static boolean_t
+zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
+    zprop_source_t *source)
+{
+       char sourceloc[MAXNAMELEN];
+       zprop_source_t sourcetype;
+
+       if (!zfs_prop_valid_for_type(ZFS_PROP_MOUNTPOINT, zhp->zfs_type,
+           B_FALSE))
+               return (B_FALSE);
+
+       verify(zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, buf, buflen,
+           &sourcetype, sourceloc, sizeof (sourceloc), B_FALSE) == 0);
+
+       if (strcmp(buf, ZFS_MOUNTPOINT_NONE) == 0 ||
+           strcmp(buf, ZFS_MOUNTPOINT_LEGACY) == 0)
+               return (B_FALSE);
+
+       if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_OFF)
+               return (B_FALSE);
+
+       if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) &&
+           getzoneid() == GLOBAL_ZONEID)
+               return (B_FALSE);
+
+       if (source)
+               *source = sourcetype;
+
+       return (B_TRUE);
+}
+
+/*
+ * The filesystem is mounted by invoking the system mount utility rather
+ * than by the system call mount(2).  This ensures that the /etc/mtab
+ * file is correctly locked for the update.  Performing our own locking
+ * and /etc/mtab update requires making an unsafe assumption about how
+ * the mount utility performs its locking.  Unfortunately, this also means
+ * in the case of a mount failure we do not have the exact errno.  We must
+ * make due with return value from the mount process.
+ *
+ * In the long term a shared library called libmount is under development
+ * which provides a common API to address the locking and errno issues.
+ * Once the standard mount utility has been updated to use this library
+ * we can add an autoconf check to conditionally use it.
+ *
+ * http://www.kernel.org/pub/linux/utils/util-linux/libmount-docs/index.html
+ */
+
+static int
+do_mount(const char *src, const char *mntpt, char *opts)
+{
+       char *argv[8] = {
+           "/bin/mount",
+           "-t", MNTTYPE_ZFS,
+           "-o", opts,
+           (char *)src,
+           (char *)mntpt,
+           (char *)NULL };
+       int rc;
+
+       /* Return only the most critical mount error */
+       rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE);
+       if (rc) {
+               if (rc & MOUNT_FILEIO)
+                       return (EIO);
+               if (rc & MOUNT_USER)
+                       return (EINTR);
+               if (rc & MOUNT_SOFTWARE)
+                       return (EPIPE);
+               if (rc & MOUNT_BUSY)
+                       return (EBUSY);
+               if (rc & MOUNT_SYSERR)
+                       return (EAGAIN);
+               if (rc & MOUNT_USAGE)
+                       return (EINVAL);
+
+               return (ENXIO); /* Generic error */
+       }
+
+       return (0);
+}
+
+static int
+do_unmount(const char *mntpt, int flags)
+{
+       char force_opt[] = "-f";
+       char lazy_opt[] = "-l";
+       char *argv[7] = {
+           "/bin/umount",
+           "-t", MNTTYPE_ZFS,
+           NULL, NULL, NULL, NULL };
+       int rc, count = 3;
+
+       if (flags & MS_FORCE) {
+               argv[count] = force_opt;
+               count++;
+       }
+
+       if (flags & MS_DETACH) {
+               argv[count] = lazy_opt;
+               count++;
+       }
+
+       argv[count] = (char *)mntpt;
+       rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE);
+
+       return (rc ? EINVAL : 0);
+}
+
+static int
+zfs_add_option(zfs_handle_t *zhp, char *options, int len,
+    zfs_prop_t prop, char *on, char *off)
+{
+       char *source;
+       uint64_t value;
+
+       /* Skip adding duplicate default options */
+       if ((strstr(options, on) != NULL) || (strstr(options, off) != NULL))
+               return (0);
+
+       /*
+        * zfs_prop_get_int() is not used to ensure our mount options
+        * are not influenced by the current /proc/self/mounts contents.
+        */
+       value = getprop_uint64(zhp, prop, &source);
+
+       (void) strlcat(options, ",", len);
+       (void) strlcat(options, value ? on : off, len);
+
+       return (0);
+}
+
+static int
+zfs_add_options(zfs_handle_t *zhp, char *options, int len)
+{
+       int error = 0;
+
+       error = zfs_add_option(zhp, options, len,
+           ZFS_PROP_ATIME, MNTOPT_ATIME, MNTOPT_NOATIME);
+       /*
+        * don't add relatime/strictatime when atime=off, otherwise strictatime
+        * will force atime=on
+        */
+       if (strstr(options, MNTOPT_NOATIME) == NULL) {
+               error = zfs_add_option(zhp, options, len,
+                   ZFS_PROP_RELATIME, MNTOPT_RELATIME, MNTOPT_STRICTATIME);
+       }
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_DEVICES, MNTOPT_DEVICES, MNTOPT_NODEVICES);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_EXEC, MNTOPT_EXEC, MNTOPT_NOEXEC);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_READONLY, MNTOPT_RO, MNTOPT_RW);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_SETUID, MNTOPT_SETUID, MNTOPT_NOSETUID);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_NBMAND, MNTOPT_NBMAND, MNTOPT_NONBMAND);
+
+       return (error);
+}
+
+/*
+ * Mount the given filesystem.
+ */
+int
+zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
+{
+       struct stat buf;
+       char mountpoint[ZFS_MAXPROPLEN];
+       char mntopts[MNT_LINE_MAX];
+       char overlay[ZFS_MAXPROPLEN];
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       int remount = 0, rc;
+
+       if (options == NULL) {
+               (void) strlcpy(mntopts, MNTOPT_DEFAULTS, sizeof (mntopts));
+       } else {
+               (void) strlcpy(mntopts, options, sizeof (mntopts));
+       }
+
+       if (strstr(mntopts, MNTOPT_REMOUNT) != NULL)
+               remount = 1;
+
+       /*
+        * If the pool is imported read-only then all mounts must be read-only
+        */
+       if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
+               (void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts));
+
+       if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
+               return (0);
+
+       /*
+        * Append default mount options which apply to the mount point.
+        * This is done because under Linux (unlike Solaris) multiple mount
+        * points may reference a single super block.  This means that just
+        * given a super block there is no back reference to update the per
+        * mount point options.
+        */
+       rc = zfs_add_options(zhp, mntopts, sizeof (mntopts));
+       if (rc) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "default options unavailable"));
+               return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+                   dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+                   mountpoint));
+       }
+
+       /*
+        * Append zfsutil option so the mount helper allow the mount
+        */
+       strlcat(mntopts, "," MNTOPT_ZFSUTIL, sizeof (mntopts));
+
+       /* Create the directory if it doesn't already exist */
+       if (lstat(mountpoint, &buf) != 0) {
+               if (mkdirp(mountpoint, 0755) != 0) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "failed to create mountpoint"));
+                       return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+                           dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+                           mountpoint));
+               }
+       }
+
+       /*
+        * Overlay mounts are disabled by default but may be enabled
+        * via the 'overlay' property or the 'zfs mount -O' option.
+        */
+       if (!(flags & MS_OVERLAY)) {
+               if (zfs_prop_get(zhp, ZFS_PROP_OVERLAY, overlay,
+                           sizeof (overlay), NULL, NULL, 0, B_FALSE) == 0) {
+                       if (strcmp(overlay, "on") == 0) {
+                               flags |= MS_OVERLAY;
+                       }
+               }
+       }
+
+       /*
+        * Determine if the mountpoint is empty.  If so, refuse to perform the
+        * mount.  We don't perform this check if 'remount' is
+        * specified or if overlay option(-O) is given
+        */
+       if ((flags & MS_OVERLAY) == 0 && !remount &&
+           !dir_is_empty(mountpoint)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "directory is not empty"));
+               return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+                   dgettext(TEXT_DOMAIN, "cannot mount '%s'"), mountpoint));
+       }
+
+       /* perform the mount */
+       rc = do_mount(zfs_get_name(zhp), mountpoint, mntopts);
+       if (rc) {
+               /*
+                * Generic errors are nasty, but there are just way too many
+                * from mount(), and they're well-understood.  We pick a few
+                * common ones to improve upon.
+                */
+               if (rc == EBUSY) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "mountpoint or dataset is busy"));
+               } else if (rc == EPERM) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "Insufficient privileges"));
+               } else if (rc == ENOTSUP) {
+                       char buf[256];
+                       int spa_version;
+
+                       VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
+                       (void) snprintf(buf, sizeof (buf),
+                           dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
+                           "file system on a version %d pool. Pool must be"
+                           " upgraded to mount this file system."),
+                           (u_longlong_t)zfs_prop_get_int(zhp,
+                           ZFS_PROP_VERSION), spa_version);
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
+               } else {
+                       zfs_error_aux(hdl, strerror(rc));
+               }
+               return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+                   dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+                   zhp->zfs_name));
+       }
+
+       /* remove the mounted entry before re-adding on remount */
+       if (remount)
+               libzfs_mnttab_remove(hdl, zhp->zfs_name);
+
+       /* add the mounted entry into our cache */
+       libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, mntopts);
+       return (0);
+}
+
+/*
+ * Unmount a single filesystem.
+ */
+static int
+unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
+{
+       int error;
+
+       error = do_unmount(mountpoint, flags);
+       if (error != 0) {
+               return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
+                   dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
+                   mountpoint));
+       }
+
+       return (0);
+}
+
+/*
+ * Unmount the given filesystem.
+ */
+int
+zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       struct mnttab entry;
+       char *mntpt = NULL;
+
+       /* check to see if we need to unmount the filesystem */
+       if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
+           libzfs_mnttab_find(hdl, zhp->zfs_name, &entry) == 0)) {
+               /*
+                * mountpoint may have come from a call to
+                * getmnt/getmntany if it isn't NULL. If it is NULL,
+                * we know it comes from libzfs_mnttab_find which can
+                * then get freed later. We strdup it to play it safe.
+                */
+               if (mountpoint == NULL)
+                       mntpt = zfs_strdup(hdl, entry.mnt_mountp);
+               else
+                       mntpt = zfs_strdup(hdl, mountpoint);
+
+               /*
+                * Unshare and unmount the filesystem
+                */
+               if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0) {
+                       free(mntpt);
+                       return (-1);
+               }
+
+               if (unmount_one(hdl, mntpt, flags) != 0) {
+                       free(mntpt);
+                       (void) zfs_shareall(zhp);
+                       return (-1);
+               }
+               libzfs_mnttab_remove(hdl, zhp->zfs_name);
+               free(mntpt);
+       }
+
+       return (0);
+}
+
+/*
+ * Unmount this filesystem and any children inheriting the mountpoint property.
+ * To do this, just act like we're changing the mountpoint property, but don't
+ * remount the filesystems afterwards.
+ */
+int
+zfs_unmountall(zfs_handle_t *zhp, int flags)
+{
+       prop_changelist_t *clp;
+       int ret;
+
+       clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT, 0, flags);
+       if (clp == NULL)
+               return (-1);
+
+       ret = changelist_prefix(clp);
+       changelist_free(clp);
+
+       return (ret);
+}
+
+boolean_t
+zfs_is_shared(zfs_handle_t *zhp)
+{
+       zfs_share_type_t rc = 0;
+       zfs_share_proto_t *curr_proto;
+
+       if (ZFS_IS_VOLUME(zhp))
+               return (B_FALSE);
+
+       for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+           curr_proto++)
+               rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto);
+
+       return (rc ? B_TRUE : B_FALSE);
+}
+
+int
+zfs_share(zfs_handle_t *zhp)
+{
+       assert(!ZFS_IS_VOLUME(zhp));
+       return (zfs_share_proto(zhp, share_all_proto));
+}
+
+int
+zfs_unshare(zfs_handle_t *zhp)
+{
+       assert(!ZFS_IS_VOLUME(zhp));
+       return (zfs_unshareall(zhp));
+}
+
+/*
+ * Check to see if the filesystem is currently shared.
+ */
+zfs_share_type_t
+zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
+{
+       char *mountpoint;
+       zfs_share_type_t rc;
+
+       if (!zfs_is_mounted(zhp, &mountpoint))
+               return (SHARED_NOT_SHARED);
+
+       if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))) {
+               if (where != NULL)
+                       *where = mountpoint;
+               else
+                       free(mountpoint);
+               return (rc);
+       } else {
+               free(mountpoint);
+               return (SHARED_NOT_SHARED);
+       }
+}
+
+boolean_t
+zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
+{
+       return (zfs_is_shared_proto(zhp, where,
+           PROTO_NFS) != SHARED_NOT_SHARED);
+}
+
+boolean_t
+zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
+{
+       return (zfs_is_shared_proto(zhp, where,
+           PROTO_SMB) != SHARED_NOT_SHARED);
+}
+
+/*
+ * zfs_init_libshare(zhandle, service)
+ *
+ * Initialize the libshare API if it hasn't already been initialized.
+ * In all cases it returns 0 if it succeeded and an error if not. The
+ * service value is which part(s) of the API to initialize and is a
+ * direct map to the libshare sa_init(service) interface.
+ */
+int
+zfs_init_libshare(libzfs_handle_t *zhandle, int service)
+{
+       int ret = SA_OK;
+
+       if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) {
+               /*
+                * We had a cache miss. Most likely it is a new ZFS
+                * dataset that was just created. We want to make sure
+                * so check timestamps to see if a different process
+                * has updated any of the configuration. If there was
+                * some non-ZFS change, we need to re-initialize the
+                * internal cache.
+                */
+               zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS;
+               if (sa_needs_refresh(zhandle->libzfs_sharehdl)) {
+                       zfs_uninit_libshare(zhandle);
+                       zhandle->libzfs_sharehdl = sa_init(service);
+               }
+       }
+
+       if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL)
+               zhandle->libzfs_sharehdl = sa_init(service);
+
+       if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL)
+               ret = SA_NO_MEMORY;
+
+       return (ret);
+}
+
+/*
+ * zfs_uninit_libshare(zhandle)
+ *
+ * Uninitialize the libshare API if it hasn't already been
+ * uninitialized. It is OK to call multiple times.
+ */
+void
+zfs_uninit_libshare(libzfs_handle_t *zhandle)
+{
+       if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
+               sa_fini(zhandle->libzfs_sharehdl);
+               zhandle->libzfs_sharehdl = NULL;
+       }
+}
+
+/*
+ * zfs_parse_options(options, proto)
+ *
+ * Call the legacy parse interface to get the protocol specific
+ * options using the NULL arg to indicate that this is a "parse" only.
+ */
+int
+zfs_parse_options(char *options, zfs_share_proto_t proto)
+{
+       return (sa_parse_legacy_options(NULL, options,
+           proto_table[proto].p_name));
+}
+
+/*
+ * Share the given filesystem according to the options in the specified
+ * protocol specific properties (sharenfs, sharesmb).  We rely
+ * on "libshare" to do the dirty work for us.
+ */
+static int
+zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
+{
+       char mountpoint[ZFS_MAXPROPLEN];
+       char shareopts[ZFS_MAXPROPLEN];
+       char sourcestr[ZFS_MAXPROPLEN];
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       sa_share_t share;
+       zfs_share_proto_t *curr_proto;
+       zprop_source_t sourcetype;
+       int ret;
+
+       if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
+               return (0);
+
+       for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
+               /*
+                * Return success if there are no share options.
+                */
+               if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
+                   shareopts, sizeof (shareopts), &sourcetype, sourcestr,
+                   ZFS_MAXPROPLEN, B_FALSE) != 0 ||
+                   strcmp(shareopts, "off") == 0)
+                       continue;
+
+               ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API);
+               if (ret != SA_OK) {
+                       (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
+                           dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
+                           zfs_get_name(zhp), sa_errorstr(ret));
+                       return (-1);
+               }
+
+               /*
+                * If the 'zoned' property is set, then zfs_is_mountable()
+                * will have already bailed out if we are in the global zone.
+                * But local zones cannot be NFS servers, so we ignore it for
+                * local zones as well.
+                */
+               if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
+                       continue;
+
+               share = sa_find_share(hdl->libzfs_sharehdl, mountpoint);
+               if (share == NULL) {
+                       /*
+                        * This may be a new file system that was just
+                        * created so isn't in the internal cache
+                        * (second time through). Rather than
+                        * reloading the entire configuration, we can
+                        * assume ZFS has done the checking and it is
+                        * safe to add this to the internal
+                        * configuration.
+                        */
+                       if (sa_zfs_process_share(hdl->libzfs_sharehdl,
+                           NULL, NULL, mountpoint,
+                           proto_table[*curr_proto].p_name, sourcetype,
+                           shareopts, sourcestr, zhp->zfs_name) != SA_OK) {
+                               (void) zfs_error_fmt(hdl,
+                                   proto_table[*curr_proto].p_share_err,
+                                   dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+                                   zfs_get_name(zhp));
+                               return (-1);
+                       }
+                       hdl->libzfs_shareflags |= ZFSSHARE_MISS;
+                       share = sa_find_share(hdl->libzfs_sharehdl,
+                           mountpoint);
+               }
+               if (share != NULL) {
+                       int err;
+                       err = sa_enable_share(share,
+                           proto_table[*curr_proto].p_name);
+                       if (err != SA_OK) {
+                               (void) zfs_error_fmt(hdl,
+                                   proto_table[*curr_proto].p_share_err,
+                                   dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+                                   zfs_get_name(zhp));
+                               return (-1);
+                       }
+               } else {
+                       (void) zfs_error_fmt(hdl,
+                           proto_table[*curr_proto].p_share_err,
+                           dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+                           zfs_get_name(zhp));
+                       return (-1);
+               }
+
+       }
+       return (0);
+}
+
+
+int
+zfs_share_nfs(zfs_handle_t *zhp)
+{
+       return (zfs_share_proto(zhp, nfs_only));
+}
+
+int
+zfs_share_smb(zfs_handle_t *zhp)
+{
+       return (zfs_share_proto(zhp, smb_only));
+}
+
+int
+zfs_shareall(zfs_handle_t *zhp)
+{
+       return (zfs_share_proto(zhp, share_all_proto));
+}
+
+/*
+ * Unshare a filesystem by mountpoint.
+ */
+static int
+unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
+    zfs_share_proto_t proto)
+{
+       sa_share_t share;
+       int err;
+       char *mntpt;
+       /*
+        * Mountpoint could get trashed if libshare calls getmntany
+        * which it does during API initialization, so strdup the
+        * value.
+        */
+       mntpt = zfs_strdup(hdl, mountpoint);
+
+       /* make sure libshare initialized */
+       if ((err = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
+               free(mntpt);    /* don't need the copy anymore */
+               return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
+                   dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
+                   name, sa_errorstr(err)));
+       }
+
+       share = sa_find_share(hdl->libzfs_sharehdl, mntpt);
+       free(mntpt);    /* don't need the copy anymore */
+
+       if (share != NULL) {
+               err = sa_disable_share(share, proto_table[proto].p_name);
+               if (err != SA_OK) {
+                       return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
+                           dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
+                           name, sa_errorstr(err)));
+               }
+       } else {
+               return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
+                   dgettext(TEXT_DOMAIN, "cannot unshare '%s': not found"),
+                   name));
+       }
+       return (0);
+}
+
+/*
+ * Unshare the given filesystem.
+ */
+int
+zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
+    zfs_share_proto_t *proto)
+{
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       struct mnttab entry;
+       char *mntpt = NULL;
+
+       /* check to see if need to unmount the filesystem */
+       if (mountpoint != NULL)
+               mntpt = zfs_strdup(hdl, mountpoint);
+
+       if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
+           libzfs_mnttab_find(hdl, zfs_get_name(zhp), &entry) == 0)) {
+               zfs_share_proto_t *curr_proto;
+
+               if (mountpoint == NULL)
+                       mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
+
+               for (curr_proto = proto; *curr_proto != PROTO_END;
+                   curr_proto++) {
+
+                       if (is_shared(hdl, mntpt, *curr_proto) &&
+                           unshare_one(hdl, zhp->zfs_name,
+                           mntpt, *curr_proto) != 0) {
+                               if (mntpt != NULL)
+                                       free(mntpt);
+                               return (-1);
+                       }
+               }
+       }
+       if (mntpt != NULL)
+               free(mntpt);
+
+       return (0);
+}
+
+int
+zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
+{
+       return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
+}
+
+int
+zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
+{
+       return (zfs_unshare_proto(zhp, mountpoint, smb_only));
+}
+
+/*
+ * Same as zfs_unmountall(), but for NFS and SMB unshares.
+ */
+int
+zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
+{
+       prop_changelist_t *clp;
+       int ret;
+
+       clp = changelist_gather(zhp, ZFS_PROP_SHARENFS, 0, 0);
+       if (clp == NULL)
+               return (-1);
+
+       ret = changelist_unshare(clp, proto);
+       changelist_free(clp);
+
+       return (ret);
+}
+
+int
+zfs_unshareall_nfs(zfs_handle_t *zhp)
+{
+       return (zfs_unshareall_proto(zhp, nfs_only));
+}
+
+int
+zfs_unshareall_smb(zfs_handle_t *zhp)
+{
+       return (zfs_unshareall_proto(zhp, smb_only));
+}
+
+int
+zfs_unshareall(zfs_handle_t *zhp)
+{
+       return (zfs_unshareall_proto(zhp, share_all_proto));
+}
+
+int
+zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
+{
+       return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
+}
+
+/*
+ * Remove the mountpoint associated with the current dataset, if necessary.
+ * We only remove the underlying directory if:
+ *
+ *     - The mountpoint is not 'none' or 'legacy'
+ *     - The mountpoint is non-empty
+ *     - The mountpoint is the default or inherited
+ *     - The 'zoned' property is set, or we're in a local zone
+ *
+ * Any other directories we leave alone.
+ */
+void
+remove_mountpoint(zfs_handle_t *zhp)
+{
+       char mountpoint[ZFS_MAXPROPLEN];
+       zprop_source_t source;
+
+       if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
+           &source))
+               return;
+
+       if (source == ZPROP_SRC_DEFAULT ||
+           source == ZPROP_SRC_INHERITED) {
+               /*
+                * Try to remove the directory, silently ignoring any errors.
+                * The filesystem may have since been removed or moved around,
+                * and this error isn't really useful to the administrator in
+                * any way.
+                */
+               (void) rmdir(mountpoint);
+       }
+}
+
+void
+libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
+{
+       if (cbp->cb_alloc == cbp->cb_used) {
+               size_t newsz;
+               void *ptr;
+
+               newsz = cbp->cb_alloc ? cbp->cb_alloc * 2 : 64;
+               ptr = zfs_realloc(zhp->zfs_hdl,
+                   cbp->cb_handles, cbp->cb_alloc * sizeof (void *),
+                   newsz * sizeof (void *));
+               cbp->cb_handles = ptr;
+               cbp->cb_alloc = newsz;
+       }
+       cbp->cb_handles[cbp->cb_used++] = zhp;
+}
+
+static int
+mount_cb(zfs_handle_t *zhp, void *data)
+{
+       get_all_cb_t *cbp = data;
+
+       if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       /*
+        * If this filesystem is inconsistent and has a receive resume
+        * token, we can not mount it.
+        */
+       if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
+           zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+           NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       libzfs_add_handle(cbp, zhp);
+       if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
+               zfs_close(zhp);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+libzfs_dataset_cmp(const void *a, const void *b)
+{
+       zfs_handle_t **za = (zfs_handle_t **)a;
+       zfs_handle_t **zb = (zfs_handle_t **)b;
+       char mounta[MAXPATHLEN];
+       char mountb[MAXPATHLEN];
+       boolean_t gota, gotb;
+
+       if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
+               verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
+                   sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
+       if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
+               verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
+                   sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
+
+       if (gota && gotb)
+               return (strcmp(mounta, mountb));
+
+       if (gota)
+               return (-1);
+       if (gotb)
+               return (1);
+
+       return (strcmp(zfs_get_name(*za), zfs_get_name(*zb)));
+}
+
+/*
+ * Mount and share all datasets within the given pool.  This assumes that no
+ * datasets within the pool are currently mounted.  Because users can create
+ * complicated nested hierarchies of mountpoints, we first gather all the
+ * datasets and mountpoints within the pool, and sort them by mountpoint.  Once
+ * we have the list of all filesystems, we iterate over them in order and mount
+ * and/or share each one.
+ */
+#pragma weak zpool_mount_datasets = zpool_enable_datasets
+int
+zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
+{
+       get_all_cb_t cb = { 0 };
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       zfs_handle_t *zfsp;
+       int i, ret = -1;
+       int *good;
+
+       /*
+        * Gather all non-snap datasets within the pool.
+        */
+       if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL)
+               goto out;
+
+       libzfs_add_handle(&cb, zfsp);
+       if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0)
+               goto out;
+       /*
+        * Sort the datasets by mountpoint.
+        */
+       qsort(cb.cb_handles, cb.cb_used, sizeof (void *),
+           libzfs_dataset_cmp);
+
+       /*
+        * And mount all the datasets, keeping track of which ones
+        * succeeded or failed.
+        */
+       if ((good = zfs_alloc(zhp->zpool_hdl,
+           cb.cb_used * sizeof (int))) == NULL)
+               goto out;
+
+       ret = 0;
+       for (i = 0; i < cb.cb_used; i++) {
+               if (zfs_mount(cb.cb_handles[i], mntopts, flags) != 0)
+                       ret = -1;
+               else
+                       good[i] = 1;
+       }
+
+       /*
+        * Then share all the ones that need to be shared. This needs
+        * to be a separate pass in order to avoid excessive reloading
+        * of the configuration. Good should never be NULL since
+        * zfs_alloc is supposed to exit if memory isn't available.
+        */
+       for (i = 0; i < cb.cb_used; i++) {
+               if (good[i] && zfs_share(cb.cb_handles[i]) != 0)
+                       ret = -1;
+       }
+
+       free(good);
+
+out:
+       for (i = 0; i < cb.cb_used; i++)
+               zfs_close(cb.cb_handles[i]);
+       free(cb.cb_handles);
+
+       return (ret);
+}
+
+static int
+mountpoint_compare(const void *a, const void *b)
+{
+       const char *mounta = *((char **)a);
+       const char *mountb = *((char **)b);
+
+       return (strcmp(mountb, mounta));
+}
+
+/* alias for 2002/240 */
+#pragma weak zpool_unmount_datasets = zpool_disable_datasets
+/*
+ * Unshare and unmount all datasets within the given pool.  We don't want to
+ * rely on traversing the DSL to discover the filesystems within the pool,
+ * because this may be expensive (if not all of them are mounted), and can fail
+ * arbitrarily (on I/O error, for example).  Instead, we walk /proc/self/mounts
+ * and gather all the filesystems that are currently mounted.
+ */
+int
+zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
+{
+       int used, alloc;
+       struct mnttab entry;
+       size_t namelen;
+       char **mountpoints = NULL;
+       zfs_handle_t **datasets = NULL;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       int i;
+       int ret = -1;
+       int flags = (force ? MS_FORCE : 0);
+
+       namelen = strlen(zhp->zpool_name);
+
+       /* Reopen MNTTAB to prevent reading stale data from open file */
+       if (freopen(MNTTAB, "r", hdl->libzfs_mnttab) == NULL)
+               return (ENOENT);
+
+       used = alloc = 0;
+       while (getmntent(hdl->libzfs_mnttab, &entry) == 0) {
+               /*
+                * Ignore non-ZFS entries.
+                */
+               if (entry.mnt_fstype == NULL ||
+                   strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
+                       continue;
+
+               /*
+                * Ignore filesystems not within this pool.
+                */
+               if (entry.mnt_mountp == NULL ||
+                   strncmp(entry.mnt_special, zhp->zpool_name, namelen) != 0 ||
+                   (entry.mnt_special[namelen] != '/' &&
+                   entry.mnt_special[namelen] != '\0'))
+                       continue;
+
+               /*
+                * At this point we've found a filesystem within our pool.  Add
+                * it to our growing list.
+                */
+               if (used == alloc) {
+                       if (alloc == 0) {
+                               if ((mountpoints = zfs_alloc(hdl,
+                                   8 * sizeof (void *))) == NULL)
+                                       goto out;
+
+                               if ((datasets = zfs_alloc(hdl,
+                                   8 * sizeof (void *))) == NULL)
+                                       goto out;
+
+                               alloc = 8;
+                       } else {
+                               void *ptr;
+
+                               if ((ptr = zfs_realloc(hdl, mountpoints,
+                                   alloc * sizeof (void *),
+                                   alloc * 2 * sizeof (void *))) == NULL)
+                                       goto out;
+                               mountpoints = ptr;
+
+                               if ((ptr = zfs_realloc(hdl, datasets,
+                                   alloc * sizeof (void *),
+                                   alloc * 2 * sizeof (void *))) == NULL)
+                                       goto out;
+                               datasets = ptr;
+
+                               alloc *= 2;
+                       }
+               }
+
+               if ((mountpoints[used] = zfs_strdup(hdl,
+                   entry.mnt_mountp)) == NULL)
+                       goto out;
+
+               /*
+                * This is allowed to fail, in case there is some I/O error.  It
+                * is only used to determine if we need to remove the underlying
+                * mountpoint, so failure is not fatal.
+                */
+               datasets[used] = make_dataset_handle(hdl, entry.mnt_special);
+
+               used++;
+       }
+
+       /*
+        * At this point, we have the entire list of filesystems, so sort it by
+        * mountpoint.
+        */
+       qsort(mountpoints, used, sizeof (char *), mountpoint_compare);
+
+       /*
+        * Walk through and first unshare everything.
+        */
+       for (i = 0; i < used; i++) {
+               zfs_share_proto_t *curr_proto;
+               for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+                   curr_proto++) {
+                       if (is_shared(hdl, mountpoints[i], *curr_proto) &&
+                           unshare_one(hdl, mountpoints[i],
+                           mountpoints[i], *curr_proto) != 0)
+                               goto out;
+               }
+       }
+
+       /*
+        * Now unmount everything, removing the underlying directories as
+        * appropriate.
+        */
+       for (i = 0; i < used; i++) {
+               if (unmount_one(hdl, mountpoints[i], flags) != 0)
+                       goto out;
+       }
+
+       for (i = 0; i < used; i++) {
+               if (datasets[i])
+                       remove_mountpoint(datasets[i]);
+       }
+
+       ret = 0;
+out:
+       for (i = 0; i < used; i++) {
+               if (datasets[i])
+                       zfs_close(datasets[i]);
+               free(mountpoints[i]);
+       }
+       free(datasets);
+       free(mountpoints);
+
+       return (ret);
+}
diff --git a/zfs/lib/libzfs/libzfs_pool.c b/zfs/lib/libzfs/libzfs_pool.c
new file mode 100644 (file)
index 0000000..6727a77
--- /dev/null
@@ -0,0 +1,4612 @@
+/*
+ * 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 2015 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <devid.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <zone.h>
+#include <sys/stat.h>
+#include <sys/efi_partition.h>
+#include <sys/vtoc.h>
+#include <sys/zfs_ioctl.h>
+#include <dlfcn.h>
+#if HAVE_LIBDEVMAPPER
+#include <libdevmapper.h>
+#endif
+
+#include "zfs_namecheck.h"
+#include "zfs_prop.h"
+#include "libzfs_impl.h"
+#include "zfs_comutil.h"
+#include "zfeature_common.h"
+
+static int read_efi_label(nvlist_t *config, diskaddr_t *sb);
+
+typedef struct prop_flags {
+       int create:1;   /* Validate property on creation */
+       int import:1;   /* Validate property on import */
+} prop_flags_t;
+
+/*
+ * ====================================================================
+ *   zpool property functions
+ * ====================================================================
+ */
+
+static int
+zpool_get_all_props(zpool_handle_t *zhp)
+{
+       zfs_cmd_t zc = {"\0"};
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+
+       if (zcmd_alloc_dst_nvlist(hdl, &zc, 0) != 0)
+               return (-1);
+
+       while (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_PROPS, &zc) != 0) {
+               if (errno == ENOMEM) {
+                       if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+                               zcmd_free_nvlists(&zc);
+                               return (-1);
+                       }
+               } else {
+                       zcmd_free_nvlists(&zc);
+                       return (-1);
+               }
+       }
+
+       if (zcmd_read_dst_nvlist(hdl, &zc, &zhp->zpool_props) != 0) {
+               zcmd_free_nvlists(&zc);
+               return (-1);
+       }
+
+       zcmd_free_nvlists(&zc);
+
+       return (0);
+}
+
+static int
+zpool_props_refresh(zpool_handle_t *zhp)
+{
+       nvlist_t *old_props;
+
+       old_props = zhp->zpool_props;
+
+       if (zpool_get_all_props(zhp) != 0)
+               return (-1);
+
+       nvlist_free(old_props);
+       return (0);
+}
+
+static char *
+zpool_get_prop_string(zpool_handle_t *zhp, zpool_prop_t prop,
+    zprop_source_t *src)
+{
+       nvlist_t *nv, *nvl;
+       uint64_t ival;
+       char *value;
+       zprop_source_t source;
+
+       nvl = zhp->zpool_props;
+       if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
+               verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &ival) == 0);
+               source = ival;
+               verify(nvlist_lookup_string(nv, ZPROP_VALUE, &value) == 0);
+       } else {
+               source = ZPROP_SRC_DEFAULT;
+               if ((value = (char *)zpool_prop_default_string(prop)) == NULL)
+                       value = "-";
+       }
+
+       if (src)
+               *src = source;
+
+       return (value);
+}
+
+uint64_t
+zpool_get_prop_int(zpool_handle_t *zhp, zpool_prop_t prop, zprop_source_t *src)
+{
+       nvlist_t *nv, *nvl;
+       uint64_t value;
+       zprop_source_t source;
+
+       if (zhp->zpool_props == NULL && zpool_get_all_props(zhp)) {
+               /*
+                * zpool_get_all_props() has most likely failed because
+                * the pool is faulted, but if all we need is the top level
+                * vdev's guid then get it from the zhp config nvlist.
+                */
+               if ((prop == ZPOOL_PROP_GUID) &&
+                   (nvlist_lookup_nvlist(zhp->zpool_config,
+                   ZPOOL_CONFIG_VDEV_TREE, &nv) == 0) &&
+                   (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value)
+                   == 0)) {
+                       return (value);
+               }
+               return (zpool_prop_default_numeric(prop));
+       }
+
+       nvl = zhp->zpool_props;
+       if (nvlist_lookup_nvlist(nvl, zpool_prop_to_name(prop), &nv) == 0) {
+               verify(nvlist_lookup_uint64(nv, ZPROP_SOURCE, &value) == 0);
+               source = value;
+               verify(nvlist_lookup_uint64(nv, ZPROP_VALUE, &value) == 0);
+       } else {
+               source = ZPROP_SRC_DEFAULT;
+               value = zpool_prop_default_numeric(prop);
+       }
+
+       if (src)
+               *src = source;
+
+       return (value);
+}
+
+/*
+ * Map VDEV STATE to printed strings.
+ */
+char *
+zpool_state_to_name(vdev_state_t state, vdev_aux_t aux)
+{
+       switch (state) {
+       default:
+               break;
+       case VDEV_STATE_CLOSED:
+       case VDEV_STATE_OFFLINE:
+               return (gettext("OFFLINE"));
+       case VDEV_STATE_REMOVED:
+               return (gettext("REMOVED"));
+       case VDEV_STATE_CANT_OPEN:
+               if (aux == VDEV_AUX_CORRUPT_DATA || aux == VDEV_AUX_BAD_LOG)
+                       return (gettext("FAULTED"));
+               else if (aux == VDEV_AUX_SPLIT_POOL)
+                       return (gettext("SPLIT"));
+               else
+                       return (gettext("UNAVAIL"));
+       case VDEV_STATE_FAULTED:
+               return (gettext("FAULTED"));
+       case VDEV_STATE_DEGRADED:
+               return (gettext("DEGRADED"));
+       case VDEV_STATE_HEALTHY:
+               return (gettext("ONLINE"));
+       }
+
+       return (gettext("UNKNOWN"));
+}
+
+/*
+ * Map POOL STATE to printed strings.
+ */
+const char *
+zpool_pool_state_to_name(pool_state_t state)
+{
+       switch (state) {
+       default:
+               break;
+       case POOL_STATE_ACTIVE:
+               return (gettext("ACTIVE"));
+       case POOL_STATE_EXPORTED:
+               return (gettext("EXPORTED"));
+       case POOL_STATE_DESTROYED:
+               return (gettext("DESTROYED"));
+       case POOL_STATE_SPARE:
+               return (gettext("SPARE"));
+       case POOL_STATE_L2CACHE:
+               return (gettext("L2CACHE"));
+       case POOL_STATE_UNINITIALIZED:
+               return (gettext("UNINITIALIZED"));
+       case POOL_STATE_UNAVAIL:
+               return (gettext("UNAVAIL"));
+       case POOL_STATE_POTENTIALLY_ACTIVE:
+               return (gettext("POTENTIALLY_ACTIVE"));
+       }
+
+       return (gettext("UNKNOWN"));
+}
+
+/*
+ * Get a zpool property value for 'prop' and return the value in
+ * a pre-allocated buffer.
+ */
+int
+zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf,
+    size_t len, zprop_source_t *srctype, boolean_t literal)
+{
+       uint64_t intval;
+       const char *strval;
+       zprop_source_t src = ZPROP_SRC_NONE;
+       nvlist_t *nvroot;
+       vdev_stat_t *vs;
+       uint_t vsc;
+
+       if (zpool_get_state(zhp) == POOL_STATE_UNAVAIL) {
+               switch (prop) {
+               case ZPOOL_PROP_NAME:
+                       (void) strlcpy(buf, zpool_get_name(zhp), len);
+                       break;
+
+               case ZPOOL_PROP_HEALTH:
+                       (void) strlcpy(buf, "FAULTED", len);
+                       break;
+
+               case ZPOOL_PROP_GUID:
+                       intval = zpool_get_prop_int(zhp, prop, &src);
+                       (void) snprintf(buf, len, "%llu", (u_longlong_t)intval);
+                       break;
+
+               case ZPOOL_PROP_ALTROOT:
+               case ZPOOL_PROP_CACHEFILE:
+               case ZPOOL_PROP_COMMENT:
+                       if (zhp->zpool_props != NULL ||
+                           zpool_get_all_props(zhp) == 0) {
+                               (void) strlcpy(buf,
+                                   zpool_get_prop_string(zhp, prop, &src),
+                                   len);
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       (void) strlcpy(buf, "-", len);
+                       break;
+               }
+
+               if (srctype != NULL)
+                       *srctype = src;
+               return (0);
+       }
+
+       if (zhp->zpool_props == NULL && zpool_get_all_props(zhp) &&
+           prop != ZPOOL_PROP_NAME)
+               return (-1);
+
+       switch (zpool_prop_get_type(prop)) {
+       case PROP_TYPE_STRING:
+               (void) strlcpy(buf, zpool_get_prop_string(zhp, prop, &src),
+                   len);
+               break;
+
+       case PROP_TYPE_NUMBER:
+               intval = zpool_get_prop_int(zhp, prop, &src);
+
+               switch (prop) {
+               case ZPOOL_PROP_SIZE:
+               case ZPOOL_PROP_ALLOCATED:
+               case ZPOOL_PROP_FREE:
+               case ZPOOL_PROP_FREEING:
+               case ZPOOL_PROP_LEAKED:
+               case ZPOOL_PROP_ASHIFT:
+                       if (literal)
+                               (void) snprintf(buf, len, "%llu",
+                                       (u_longlong_t)intval);
+                       else
+                               (void) zfs_nicenum(intval, buf, len);
+                       break;
+
+               case ZPOOL_PROP_EXPANDSZ:
+                       if (intval == 0) {
+                               (void) strlcpy(buf, "-", len);
+                       } else if (literal) {
+                               (void) snprintf(buf, len, "%llu",
+                                   (u_longlong_t)intval);
+                       } else {
+                               (void) zfs_nicenum(intval, buf, len);
+                       }
+                       break;
+
+               case ZPOOL_PROP_CAPACITY:
+                       if (literal) {
+                               (void) snprintf(buf, len, "%llu",
+                                   (u_longlong_t)intval);
+                       } else {
+                               (void) snprintf(buf, len, "%llu%%",
+                                   (u_longlong_t)intval);
+                       }
+                       break;
+
+               case ZPOOL_PROP_FRAGMENTATION:
+                       if (intval == UINT64_MAX) {
+                               (void) strlcpy(buf, "-", len);
+                       } else if (literal) {
+                               (void) snprintf(buf, len, "%llu",
+                                   (u_longlong_t)intval);
+                       } else {
+                               (void) snprintf(buf, len, "%llu%%",
+                                   (u_longlong_t)intval);
+                       }
+                       break;
+
+               case ZPOOL_PROP_DEDUPRATIO:
+                       if (literal)
+                               (void) snprintf(buf, len, "%llu.%02llu",
+                                   (u_longlong_t)(intval / 100),
+                                   (u_longlong_t)(intval % 100));
+                       else
+                               (void) snprintf(buf, len, "%llu.%02llux",
+                                   (u_longlong_t)(intval / 100),
+                                   (u_longlong_t)(intval % 100));
+                       break;
+
+               case ZPOOL_PROP_HEALTH:
+                       verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
+                           ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+                       verify(nvlist_lookup_uint64_array(nvroot,
+                           ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
+                           == 0);
+
+                       (void) strlcpy(buf, zpool_state_to_name(intval,
+                           vs->vs_aux), len);
+                       break;
+               case ZPOOL_PROP_VERSION:
+                       if (intval >= SPA_VERSION_FEATURES) {
+                               (void) snprintf(buf, len, "-");
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       (void) snprintf(buf, len, "%llu", (u_longlong_t)intval);
+               }
+               break;
+
+       case PROP_TYPE_INDEX:
+               intval = zpool_get_prop_int(zhp, prop, &src);
+               if (zpool_prop_index_to_string(prop, intval, &strval)
+                   != 0)
+                       return (-1);
+               (void) strlcpy(buf, strval, len);
+               break;
+
+       default:
+               abort();
+       }
+
+       if (srctype)
+               *srctype = src;
+
+       return (0);
+}
+
+/*
+ * Check if the bootfs name has the same pool name as it is set to.
+ * Assuming bootfs is a valid dataset name.
+ */
+static boolean_t
+bootfs_name_valid(const char *pool, char *bootfs)
+{
+       int len = strlen(pool);
+
+       if (!zfs_name_valid(bootfs, ZFS_TYPE_FILESYSTEM|ZFS_TYPE_SNAPSHOT))
+               return (B_FALSE);
+
+       if (strncmp(pool, bootfs, len) == 0 &&
+           (bootfs[len] == '/' || bootfs[len] == '\0'))
+               return (B_TRUE);
+
+       return (B_FALSE);
+}
+
+#if defined(__sun__) || defined(__sun)
+/*
+ * Inspect the configuration to determine if any of the devices contain
+ * an EFI label.
+ */
+static boolean_t
+pool_uses_efi(nvlist_t *config)
+{
+       nvlist_t **child;
+       uint_t c, children;
+
+       if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               return (read_efi_label(config, NULL) >= 0);
+
+       for (c = 0; c < children; c++) {
+               if (pool_uses_efi(child[c]))
+                       return (B_TRUE);
+       }
+       return (B_FALSE);
+}
+#endif
+
+boolean_t
+zpool_is_bootable(zpool_handle_t *zhp)
+{
+       char bootfs[ZFS_MAX_DATASET_NAME_LEN];
+
+       return (zpool_get_prop(zhp, ZPOOL_PROP_BOOTFS, bootfs,
+           sizeof (bootfs), NULL, B_FALSE) == 0 && strncmp(bootfs, "-",
+           sizeof (bootfs)) != 0);
+}
+
+
+/*
+ * Given an nvlist of zpool properties to be set, validate that they are
+ * correct, and parse any numeric properties (index, boolean, etc) if they are
+ * specified as strings.
+ */
+static nvlist_t *
+zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname,
+    nvlist_t *props, uint64_t version, prop_flags_t flags, char *errbuf)
+{
+       nvpair_t *elem;
+       nvlist_t *retprops;
+       zpool_prop_t prop;
+       char *strval;
+       uint64_t intval;
+       char *slash, *check;
+       struct stat64 statbuf;
+       zpool_handle_t *zhp;
+       nvlist_t *nvroot;
+
+       if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) {
+               (void) no_memory(hdl);
+               return (NULL);
+       }
+
+       elem = NULL;
+       while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {
+               const char *propname = nvpair_name(elem);
+
+               prop = zpool_name_to_prop(propname);
+               if (prop == ZPROP_INVAL && zpool_prop_feature(propname)) {
+                       int err;
+                       char *fname = strchr(propname, '@') + 1;
+
+                       err = zfeature_lookup_name(fname, NULL);
+                       if (err != 0) {
+                               ASSERT3U(err, ==, ENOENT);
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "invalid feature '%s'"), fname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       if (nvpair_type(elem) != DATA_TYPE_STRING) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "'%s' must be a string"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       (void) nvpair_value_string(elem, &strval);
+                       if (strcmp(strval, ZFS_FEATURE_ENABLED) != 0 &&
+                           strcmp(strval, ZFS_FEATURE_DISABLED) != 0) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' can only be set to "
+                                   "'enabled' or 'disabled'"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       if (nvlist_add_uint64(retprops, propname, 0) != 0) {
+                               (void) no_memory(hdl);
+                               goto error;
+                       }
+                       continue;
+               }
+
+               /*
+                * Make sure this property is valid and applies to this type.
+                */
+               if (prop == ZPROP_INVAL) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "invalid property '%s'"), propname);
+                       (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                       goto error;
+               }
+
+               if (zpool_prop_readonly(prop)) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
+                           "is readonly"), propname);
+                       (void) zfs_error(hdl, EZFS_PROPREADONLY, errbuf);
+                       goto error;
+               }
+
+               if (zprop_parse_value(hdl, elem, prop, ZFS_TYPE_POOL, retprops,
+                   &strval, &intval, errbuf) != 0)
+                       goto error;
+
+               /*
+                * Perform additional checking for specific properties.
+                */
+               switch (prop) {
+               default:
+                       break;
+               case ZPOOL_PROP_VERSION:
+                       if (intval < version ||
+                           !SPA_VERSION_IS_SUPPORTED(intval)) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' number %d is invalid."),
+                                   propname, intval);
+                               (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+                               goto error;
+                       }
+                       break;
+
+               case ZPOOL_PROP_ASHIFT:
+                       if (!flags.create) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' can only be set at "
+                                   "creation time"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       if (intval != 0 && (intval < 9 || intval > 13)) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' number %d is invalid."),
+                                   propname, intval);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+                       break;
+
+               case ZPOOL_PROP_BOOTFS:
+                       if (flags.create || flags.import) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' cannot be set at creation "
+                                   "or import time"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       if (version < SPA_VERSION_BOOTFS) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "pool must be upgraded to support "
+                                   "'%s' property"), propname);
+                               (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+                               goto error;
+                       }
+
+                       /*
+                        * bootfs property value has to be a dataset name and
+                        * the dataset has to be in the same pool as it sets to.
+                        */
+                       if (strval[0] != '\0' && !bootfs_name_valid(poolname,
+                           strval)) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "'%s' "
+                                   "is an invalid name"), strval);
+                               (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+                               goto error;
+                       }
+
+                       if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "could not open pool '%s'"), poolname);
+                               (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf);
+                               goto error;
+                       }
+                       verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
+                           ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+
+#if defined(__sun__) || defined(__sun)
+                       /*
+                        * bootfs property cannot be set on a disk which has
+                        * been EFI labeled.
+                        */
+                       if (pool_uses_efi(nvroot)) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' not supported on "
+                                   "EFI labeled devices"), propname);
+                               (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf);
+                               zpool_close(zhp);
+                               goto error;
+                       }
+#endif
+                       zpool_close(zhp);
+                       break;
+
+               case ZPOOL_PROP_ALTROOT:
+                       if (!flags.create && !flags.import) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' can only be set during pool "
+                                   "creation or import"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+
+                       if (strval[0] != '/') {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "bad alternate root '%s'"), strval);
+                               (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
+                               goto error;
+                       }
+                       break;
+
+               case ZPOOL_PROP_CACHEFILE:
+                       if (strval[0] == '\0')
+                               break;
+
+                       if (strcmp(strval, "none") == 0)
+                               break;
+
+                       if (strval[0] != '/') {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' must be empty, an "
+                                   "absolute path, or 'none'"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
+                               goto error;
+                       }
+
+                       slash = strrchr(strval, '/');
+
+                       if (slash[1] == '\0' || strcmp(slash, "/.") == 0 ||
+                           strcmp(slash, "/..") == 0) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "'%s' is not a valid file"), strval);
+                               (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
+                               goto error;
+                       }
+
+                       *slash = '\0';
+
+                       if (strval[0] != '\0' &&
+                           (stat64(strval, &statbuf) != 0 ||
+                           !S_ISDIR(statbuf.st_mode))) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "'%s' is not a valid directory"),
+                                   strval);
+                               (void) zfs_error(hdl, EZFS_BADPATH, errbuf);
+                               goto error;
+                       }
+
+                       *slash = '/';
+                       break;
+
+               case ZPOOL_PROP_COMMENT:
+                       for (check = strval; *check != '\0'; check++) {
+                               if (!isprint(*check)) {
+                                       zfs_error_aux(hdl,
+                                           dgettext(TEXT_DOMAIN,
+                                           "comment may only have printable "
+                                           "characters"));
+                                       (void) zfs_error(hdl, EZFS_BADPROP,
+                                           errbuf);
+                                       goto error;
+                               }
+                       }
+                       if (strlen(strval) > ZPROP_MAX_COMMENT) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "comment must not exceed %d characters"),
+                                   ZPROP_MAX_COMMENT);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+                       break;
+               case ZPOOL_PROP_READONLY:
+                       if (!flags.import) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' can only be set at "
+                                   "import time"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+                       break;
+               case ZPOOL_PROP_TNAME:
+                       if (!flags.create) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "property '%s' can only be set at "
+                                   "creation time"), propname);
+                               (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+                               goto error;
+                       }
+                       break;
+               }
+       }
+
+       return (retprops);
+error:
+       nvlist_free(retprops);
+       return (NULL);
+}
+
+/*
+ * Set zpool property : propname=propval.
+ */
+int
+zpool_set_prop(zpool_handle_t *zhp, const char *propname, const char *propval)
+{
+       zfs_cmd_t zc = {"\0"};
+       int ret = -1;
+       char errbuf[1024];
+       nvlist_t *nvl = NULL;
+       nvlist_t *realprops;
+       uint64_t version;
+       prop_flags_t flags = { 0 };
+
+       (void) snprintf(errbuf, sizeof (errbuf),
+           dgettext(TEXT_DOMAIN, "cannot set property for '%s'"),
+           zhp->zpool_name);
+
+       if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+               return (no_memory(zhp->zpool_hdl));
+
+       if (nvlist_add_string(nvl, propname, propval) != 0) {
+               nvlist_free(nvl);
+               return (no_memory(zhp->zpool_hdl));
+       }
+
+       version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
+       if ((realprops = zpool_valid_proplist(zhp->zpool_hdl,
+           zhp->zpool_name, nvl, version, flags, errbuf)) == NULL) {
+               nvlist_free(nvl);
+               return (-1);
+       }
+
+       nvlist_free(nvl);
+       nvl = realprops;
+
+       /*
+        * Execute the corresponding ioctl() to set this property.
+        */
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+
+       if (zcmd_write_src_nvlist(zhp->zpool_hdl, &zc, nvl) != 0) {
+               nvlist_free(nvl);
+               return (-1);
+       }
+
+       ret = zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_SET_PROPS, &zc);
+
+       zcmd_free_nvlists(&zc);
+       nvlist_free(nvl);
+
+       if (ret)
+               (void) zpool_standard_error(zhp->zpool_hdl, errno, errbuf);
+       else
+               (void) zpool_props_refresh(zhp);
+
+       return (ret);
+}
+
+int
+zpool_expand_proplist(zpool_handle_t *zhp, zprop_list_t **plp)
+{
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       zprop_list_t *entry;
+       char buf[ZFS_MAXPROPLEN];
+       nvlist_t *features = NULL;
+       nvpair_t *nvp;
+       zprop_list_t **last;
+       boolean_t firstexpand = (NULL == *plp);
+       int i;
+
+       if (zprop_expand_list(hdl, plp, ZFS_TYPE_POOL) != 0)
+               return (-1);
+
+       last = plp;
+       while (*last != NULL)
+               last = &(*last)->pl_next;
+
+       if ((*plp)->pl_all)
+               features = zpool_get_features(zhp);
+
+       if ((*plp)->pl_all && firstexpand) {
+               for (i = 0; i < SPA_FEATURES; i++) {
+                       zprop_list_t *entry = zfs_alloc(hdl,
+                           sizeof (zprop_list_t));
+                       entry->pl_prop = ZPROP_INVAL;
+                       entry->pl_user_prop = zfs_asprintf(hdl, "feature@%s",
+                           spa_feature_table[i].fi_uname);
+                       entry->pl_width = strlen(entry->pl_user_prop);
+                       entry->pl_all = B_TRUE;
+
+                       *last = entry;
+                       last = &entry->pl_next;
+               }
+       }
+
+       /* add any unsupported features */
+       for (nvp = nvlist_next_nvpair(features, NULL);
+           nvp != NULL; nvp = nvlist_next_nvpair(features, nvp)) {
+               char *propname;
+               boolean_t found;
+               zprop_list_t *entry;
+
+               if (zfeature_is_supported(nvpair_name(nvp)))
+                       continue;
+
+               propname = zfs_asprintf(hdl, "unsupported@%s",
+                   nvpair_name(nvp));
+
+               /*
+                * Before adding the property to the list make sure that no
+                * other pool already added the same property.
+                */
+               found = B_FALSE;
+               entry = *plp;
+               while (entry != NULL) {
+                       if (entry->pl_user_prop != NULL &&
+                           strcmp(propname, entry->pl_user_prop) == 0) {
+                               found = B_TRUE;
+                               break;
+                       }
+                       entry = entry->pl_next;
+               }
+               if (found) {
+                       free(propname);
+                       continue;
+               }
+
+               entry = zfs_alloc(hdl, sizeof (zprop_list_t));
+               entry->pl_prop = ZPROP_INVAL;
+               entry->pl_user_prop = propname;
+               entry->pl_width = strlen(entry->pl_user_prop);
+               entry->pl_all = B_TRUE;
+
+               *last = entry;
+               last = &entry->pl_next;
+       }
+
+       for (entry = *plp; entry != NULL; entry = entry->pl_next) {
+
+               if (entry->pl_fixed)
+                       continue;
+
+               if (entry->pl_prop != ZPROP_INVAL &&
+                   zpool_get_prop(zhp, entry->pl_prop, buf, sizeof (buf),
+                   NULL, B_FALSE) == 0) {
+                       if (strlen(buf) > entry->pl_width)
+                               entry->pl_width = strlen(buf);
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * Get the state for the given feature on the given ZFS pool.
+ */
+int
+zpool_prop_get_feature(zpool_handle_t *zhp, const char *propname, char *buf,
+    size_t len)
+{
+       uint64_t refcount;
+       boolean_t found = B_FALSE;
+       nvlist_t *features = zpool_get_features(zhp);
+       boolean_t supported;
+       const char *feature = strchr(propname, '@') + 1;
+
+       supported = zpool_prop_feature(propname);
+       ASSERT(supported || zpool_prop_unsupported(propname));
+
+       /*
+        * Convert from feature name to feature guid. This conversion is
+        * unecessary for unsupported@... properties because they already
+        * use guids.
+        */
+       if (supported) {
+               int ret;
+               spa_feature_t fid;
+
+               ret = zfeature_lookup_name(feature, &fid);
+               if (ret != 0) {
+                       (void) strlcpy(buf, "-", len);
+                       return (ENOTSUP);
+               }
+               feature = spa_feature_table[fid].fi_guid;
+       }
+
+       if (nvlist_lookup_uint64(features, feature, &refcount) == 0)
+               found = B_TRUE;
+
+       if (supported) {
+               if (!found) {
+                       (void) strlcpy(buf, ZFS_FEATURE_DISABLED, len);
+               } else  {
+                       if (refcount == 0)
+                               (void) strlcpy(buf, ZFS_FEATURE_ENABLED, len);
+                       else
+                               (void) strlcpy(buf, ZFS_FEATURE_ACTIVE, len);
+               }
+       } else {
+               if (found) {
+                       if (refcount == 0) {
+                               (void) strcpy(buf, ZFS_UNSUPPORTED_INACTIVE);
+                       } else {
+                               (void) strcpy(buf, ZFS_UNSUPPORTED_READONLY);
+                       }
+               } else {
+                       (void) strlcpy(buf, "-", len);
+                       return (ENOTSUP);
+               }
+       }
+
+       return (0);
+}
+
+/*
+ * Don't start the slice at the default block of 34; many storage
+ * devices will use a stripe width of 128k, other vendors prefer a 1m
+ * alignment.  It is best to play it safe and ensure a 1m alignment
+ * given 512B blocks.  When the block size is larger by a power of 2
+ * we will still be 1m aligned.  Some devices are sensitive to the
+ * partition ending alignment as well.
+ */
+#define        NEW_START_BLOCK         2048
+#define        PARTITION_END_ALIGNMENT 2048
+
+/*
+ * Validate the given pool name, optionally putting an extended error message in
+ * 'buf'.
+ */
+boolean_t
+zpool_name_valid(libzfs_handle_t *hdl, boolean_t isopen, const char *pool)
+{
+       namecheck_err_t why;
+       char what;
+       int ret;
+
+       ret = pool_namecheck(pool, &why, &what);
+
+       /*
+        * The rules for reserved pool names were extended at a later point.
+        * But we need to support users with existing pools that may now be
+        * invalid.  So we only check for this expanded set of names during a
+        * create (or import), and only in userland.
+        */
+       if (ret == 0 && !isopen &&
+           (strncmp(pool, "mirror", 6) == 0 ||
+           strncmp(pool, "raidz", 5) == 0 ||
+           strncmp(pool, "spare", 5) == 0 ||
+           strcmp(pool, "log") == 0)) {
+               if (hdl != NULL)
+                       zfs_error_aux(hdl,
+                           dgettext(TEXT_DOMAIN, "name is reserved"));
+               return (B_FALSE);
+       }
+
+
+       if (ret != 0) {
+               if (hdl != NULL) {
+                       switch (why) {
+                       case NAME_ERR_TOOLONG:
+                               zfs_error_aux(hdl,
+                                   dgettext(TEXT_DOMAIN, "name is too long"));
+                               break;
+
+                       case NAME_ERR_INVALCHAR:
+                               zfs_error_aux(hdl,
+                                   dgettext(TEXT_DOMAIN, "invalid character "
+                                   "'%c' in pool name"), what);
+                               break;
+
+                       case NAME_ERR_NOLETTER:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "name must begin with a letter"));
+                               break;
+
+                       case NAME_ERR_RESERVED:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "name is reserved"));
+                               break;
+
+                       case NAME_ERR_DISKLIKE:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "pool name is reserved"));
+                               break;
+
+                       case NAME_ERR_LEADING_SLASH:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "leading slash in name"));
+                               break;
+
+                       case NAME_ERR_EMPTY_COMPONENT:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "empty component in name"));
+                               break;
+
+                       case NAME_ERR_TRAILING_SLASH:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "trailing slash in name"));
+                               break;
+
+                       case NAME_ERR_MULTIPLE_AT:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "multiple '@' delimiters in name"));
+                               break;
+                       case NAME_ERR_NO_AT:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "permission set is missing '@'"));
+                               break;
+                       }
+               }
+               return (B_FALSE);
+       }
+
+       return (B_TRUE);
+}
+
+/*
+ * Open a handle to the given pool, even if the pool is currently in the FAULTED
+ * state.
+ */
+zpool_handle_t *
+zpool_open_canfail(libzfs_handle_t *hdl, const char *pool)
+{
+       zpool_handle_t *zhp;
+       boolean_t missing;
+
+       /*
+        * Make sure the pool name is valid.
+        */
+       if (!zpool_name_valid(hdl, B_TRUE, pool)) {
+               (void) zfs_error_fmt(hdl, EZFS_INVALIDNAME,
+                   dgettext(TEXT_DOMAIN, "cannot open '%s'"),
+                   pool);
+               return (NULL);
+       }
+
+       if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
+               return (NULL);
+
+       zhp->zpool_hdl = hdl;
+       (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
+
+       if (zpool_refresh_stats(zhp, &missing) != 0) {
+               zpool_close(zhp);
+               return (NULL);
+       }
+
+       if (missing) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "no such pool"));
+               (void) zfs_error_fmt(hdl, EZFS_NOENT,
+                   dgettext(TEXT_DOMAIN, "cannot open '%s'"), pool);
+               zpool_close(zhp);
+               return (NULL);
+       }
+
+       return (zhp);
+}
+
+/*
+ * Like the above, but silent on error.  Used when iterating over pools (because
+ * the configuration cache may be out of date).
+ */
+int
+zpool_open_silent(libzfs_handle_t *hdl, const char *pool, zpool_handle_t **ret)
+{
+       zpool_handle_t *zhp;
+       boolean_t missing;
+
+       if ((zhp = zfs_alloc(hdl, sizeof (zpool_handle_t))) == NULL)
+               return (-1);
+
+       zhp->zpool_hdl = hdl;
+       (void) strlcpy(zhp->zpool_name, pool, sizeof (zhp->zpool_name));
+
+       if (zpool_refresh_stats(zhp, &missing) != 0) {
+               zpool_close(zhp);
+               return (-1);
+       }
+
+       if (missing) {
+               zpool_close(zhp);
+               *ret = NULL;
+               return (0);
+       }
+
+       *ret = zhp;
+       return (0);
+}
+
+/*
+ * Similar to zpool_open_canfail(), but refuses to open pools in the faulted
+ * state.
+ */
+zpool_handle_t *
+zpool_open(libzfs_handle_t *hdl, const char *pool)
+{
+       zpool_handle_t *zhp;
+
+       if ((zhp = zpool_open_canfail(hdl, pool)) == NULL)
+               return (NULL);
+
+       if (zhp->zpool_state == POOL_STATE_UNAVAIL) {
+               (void) zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
+                   dgettext(TEXT_DOMAIN, "cannot open '%s'"), zhp->zpool_name);
+               zpool_close(zhp);
+               return (NULL);
+       }
+
+       return (zhp);
+}
+
+/*
+ * Close the handle.  Simply frees the memory associated with the handle.
+ */
+void
+zpool_close(zpool_handle_t *zhp)
+{
+       nvlist_free(zhp->zpool_config);
+       nvlist_free(zhp->zpool_old_config);
+       nvlist_free(zhp->zpool_props);
+       free(zhp);
+}
+
+/*
+ * Return the name of the pool.
+ */
+const char *
+zpool_get_name(zpool_handle_t *zhp)
+{
+       return (zhp->zpool_name);
+}
+
+
+/*
+ * Return the state of the pool (ACTIVE or UNAVAILABLE)
+ */
+int
+zpool_get_state(zpool_handle_t *zhp)
+{
+       return (zhp->zpool_state);
+}
+
+/*
+ * Create the named pool, using the provided vdev list.  It is assumed
+ * that the consumer has already validated the contents of the nvlist, so we
+ * don't have to worry about error semantics.
+ */
+int
+zpool_create(libzfs_handle_t *hdl, const char *pool, nvlist_t *nvroot,
+    nvlist_t *props, nvlist_t *fsprops)
+{
+       zfs_cmd_t zc = {"\0"};
+       nvlist_t *zc_fsprops = NULL;
+       nvlist_t *zc_props = NULL;
+       char msg[1024];
+       int ret = -1;
+
+       (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+           "cannot create '%s'"), pool);
+
+       if (!zpool_name_valid(hdl, B_FALSE, pool))
+               return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
+
+       if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
+               return (-1);
+
+       if (props) {
+               prop_flags_t flags = { .create = B_TRUE, .import = B_FALSE };
+
+               if ((zc_props = zpool_valid_proplist(hdl, pool, props,
+                   SPA_VERSION_1, flags, msg)) == NULL) {
+                       goto create_failed;
+               }
+       }
+
+       if (fsprops) {
+               uint64_t zoned;
+               char *zonestr;
+
+               zoned = ((nvlist_lookup_string(fsprops,
+                   zfs_prop_to_name(ZFS_PROP_ZONED), &zonestr) == 0) &&
+                   strcmp(zonestr, "on") == 0);
+
+               if ((zc_fsprops = zfs_valid_proplist(hdl, ZFS_TYPE_FILESYSTEM,
+                   fsprops, zoned, NULL, NULL, msg)) == NULL) {
+                       goto create_failed;
+               }
+               if (!zc_props &&
+                   (nvlist_alloc(&zc_props, NV_UNIQUE_NAME, 0) != 0)) {
+                       goto create_failed;
+               }
+               if (nvlist_add_nvlist(zc_props,
+                   ZPOOL_ROOTFS_PROPS, zc_fsprops) != 0) {
+                       goto create_failed;
+               }
+       }
+
+       if (zc_props && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
+               goto create_failed;
+
+       (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
+
+       if ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_CREATE, &zc)) != 0) {
+
+               zcmd_free_nvlists(&zc);
+               nvlist_free(zc_props);
+               nvlist_free(zc_fsprops);
+
+               switch (errno) {
+               case EBUSY:
+                       /*
+                        * This can happen if the user has specified the same
+                        * device multiple times.  We can't reliably detect this
+                        * until we try to add it and see we already have a
+                        * label.  This can also happen under if the device is
+                        * part of an active md or lvm device.
+                        */
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "one or more vdevs refer to the same device, or "
+                           "one of\nthe devices is part of an active md or "
+                           "lvm device"));
+                       return (zfs_error(hdl, EZFS_BADDEV, msg));
+
+               case ERANGE:
+                       /*
+                        * This happens if the record size is smaller or larger
+                        * than the allowed size range, or not a power of 2.
+                        *
+                        * NOTE: although zfs_valid_proplist is called earlier,
+                        * this case may have slipped through since the
+                        * pool does not exist yet and it is therefore
+                        * impossible to read properties e.g. max blocksize
+                        * from the pool.
+                        */
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "record size invalid"));
+                       return (zfs_error(hdl, EZFS_BADPROP, msg));
+
+               case EOVERFLOW:
+                       /*
+                        * This occurs when one of the devices is below
+                        * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
+                        * device was the problem device since there's no
+                        * reliable way to determine device size from userland.
+                        */
+                       {
+                               char buf[64];
+
+                               zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
+
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "one or more devices is less than the "
+                                   "minimum size (%s)"), buf);
+                       }
+                       return (zfs_error(hdl, EZFS_BADDEV, msg));
+
+               case ENOSPC:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "one or more devices is out of space"));
+                       return (zfs_error(hdl, EZFS_BADDEV, msg));
+
+               case ENOTBLK:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "cache device must be a disk or disk slice"));
+                       return (zfs_error(hdl, EZFS_BADDEV, msg));
+
+               default:
+                       return (zpool_standard_error(hdl, errno, msg));
+               }
+       }
+
+create_failed:
+       zcmd_free_nvlists(&zc);
+       nvlist_free(zc_props);
+       nvlist_free(zc_fsprops);
+       return (ret);
+}
+
+/*
+ * Destroy the given pool.  It is up to the caller to ensure that there are no
+ * datasets left in the pool.
+ */
+int
+zpool_destroy(zpool_handle_t *zhp, const char *log_str)
+{
+       zfs_cmd_t zc = {"\0"};
+       zfs_handle_t *zfp = NULL;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       char msg[1024];
+
+       if (zhp->zpool_state == POOL_STATE_ACTIVE &&
+           (zfp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_FILESYSTEM)) == NULL)
+               return (-1);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       zc.zc_history = (uint64_t)(uintptr_t)log_str;
+
+       if (zfs_ioctl(hdl, ZFS_IOC_POOL_DESTROY, &zc) != 0) {
+               (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+                   "cannot destroy '%s'"), zhp->zpool_name);
+
+               if (errno == EROFS) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "one or more devices is read only"));
+                       (void) zfs_error(hdl, EZFS_BADDEV, msg);
+               } else {
+                       (void) zpool_standard_error(hdl, errno, msg);
+               }
+
+               if (zfp)
+                       zfs_close(zfp);
+               return (-1);
+       }
+
+       if (zfp) {
+               remove_mountpoint(zfp);
+               zfs_close(zfp);
+       }
+
+       return (0);
+}
+
+/*
+ * Add the given vdevs to the pool.  The caller must have already performed the
+ * necessary verification to ensure that the vdev specification is well-formed.
+ */
+int
+zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
+{
+       zfs_cmd_t zc = {"\0"};
+       int ret;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       char msg[1024];
+       nvlist_t **spares, **l2cache;
+       uint_t nspares, nl2cache;
+
+       (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+           "cannot add to '%s'"), zhp->zpool_name);
+
+       if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
+           SPA_VERSION_SPARES &&
+           nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
+           &spares, &nspares) == 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
+                   "upgraded to add hot spares"));
+               return (zfs_error(hdl, EZFS_BADVERSION, msg));
+       }
+
+#if defined(__sun__) || defined(__sun)
+       if (zpool_is_bootable(zhp) && nvlist_lookup_nvlist_array(nvroot,
+           ZPOOL_CONFIG_SPARES, &spares, &nspares) == 0) {
+               uint64_t s;
+
+               for (s = 0; s < nspares; s++) {
+                       char *path;
+
+                       if (nvlist_lookup_string(spares[s], ZPOOL_CONFIG_PATH,
+                           &path) == 0 && pool_uses_efi(spares[s])) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "device '%s' contains an EFI label and "
+                                   "cannot be used on root pools."),
+                                   zpool_vdev_name(hdl, NULL, spares[s], 0));
+                               return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
+                       }
+               }
+       }
+#endif
+
+       if (zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL) <
+           SPA_VERSION_L2CACHE &&
+           nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
+           &l2cache, &nl2cache) == 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool must be "
+                   "upgraded to add cache devices"));
+               return (zfs_error(hdl, EZFS_BADVERSION, msg));
+       }
+
+       if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
+               return (-1);
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+
+       if (zfs_ioctl(hdl, ZFS_IOC_VDEV_ADD, &zc) != 0) {
+               switch (errno) {
+               case EBUSY:
+                       /*
+                        * This can happen if the user has specified the same
+                        * device multiple times.  We can't reliably detect this
+                        * until we try to add it and see we already have a
+                        * label.
+                        */
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "one or more vdevs refer to the same device"));
+                       (void) zfs_error(hdl, EZFS_BADDEV, msg);
+                       break;
+
+               case EOVERFLOW:
+                       /*
+                        * This occurrs when one of the devices is below
+                        * SPA_MINDEVSIZE.  Unfortunately, we can't detect which
+                        * device was the problem device since there's no
+                        * reliable way to determine device size from userland.
+                        */
+                       {
+                               char buf[64];
+
+                               zfs_nicenum(SPA_MINDEVSIZE, buf, sizeof (buf));
+
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "device is less than the minimum "
+                                   "size (%s)"), buf);
+                       }
+                       (void) zfs_error(hdl, EZFS_BADDEV, msg);
+                       break;
+
+               case ENOTSUP:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "pool must be upgraded to add these vdevs"));
+                       (void) zfs_error(hdl, EZFS_BADVERSION, msg);
+                       break;
+
+               case ENOTBLK:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "cache device must be a disk or disk slice"));
+                       (void) zfs_error(hdl, EZFS_BADDEV, msg);
+                       break;
+
+               default:
+                       (void) zpool_standard_error(hdl, errno, msg);
+               }
+
+               ret = -1;
+       } else {
+               ret = 0;
+       }
+
+       zcmd_free_nvlists(&zc);
+
+       return (ret);
+}
+
+/*
+ * Exports the pool from the system.  The caller must ensure that there are no
+ * mounted datasets in the pool.
+ */
+static int
+zpool_export_common(zpool_handle_t *zhp, boolean_t force, boolean_t hardforce,
+    const char *log_str)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+
+       (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+           "cannot export '%s'"), zhp->zpool_name);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       zc.zc_cookie = force;
+       zc.zc_guid = hardforce;
+       zc.zc_history = (uint64_t)(uintptr_t)log_str;
+
+       if (zfs_ioctl(zhp->zpool_hdl, ZFS_IOC_POOL_EXPORT, &zc) != 0) {
+               switch (errno) {
+               case EXDEV:
+                       zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
+                           "use '-f' to override the following errors:\n"
+                           "'%s' has an active shared spare which could be"
+                           " used by other pools once '%s' is exported."),
+                           zhp->zpool_name, zhp->zpool_name);
+                       return (zfs_error(zhp->zpool_hdl, EZFS_ACTIVE_SPARE,
+                           msg));
+               default:
+                       return (zpool_standard_error_fmt(zhp->zpool_hdl, errno,
+                           msg));
+               }
+       }
+
+       return (0);
+}
+
+int
+zpool_export(zpool_handle_t *zhp, boolean_t force, const char *log_str)
+{
+       return (zpool_export_common(zhp, force, B_FALSE, log_str));
+}
+
+int
+zpool_export_force(zpool_handle_t *zhp, const char *log_str)
+{
+       return (zpool_export_common(zhp, B_TRUE, B_TRUE, log_str));
+}
+
+static void
+zpool_rewind_exclaim(libzfs_handle_t *hdl, const char *name, boolean_t dryrun,
+    nvlist_t *config)
+{
+       nvlist_t *nv = NULL;
+       uint64_t rewindto;
+       int64_t loss = -1;
+       struct tm t;
+       char timestr[128];
+
+       if (!hdl->libzfs_printerr || config == NULL)
+               return;
+
+       if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
+           nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0) {
+               return;
+       }
+
+       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
+               return;
+       (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
+
+       if (localtime_r((time_t *)&rewindto, &t) != NULL &&
+           strftime(timestr, 128, "%c", &t) != 0) {
+               if (dryrun) {
+                       (void) printf(dgettext(TEXT_DOMAIN,
+                           "Would be able to return %s "
+                           "to its state as of %s.\n"),
+                           name, timestr);
+               } else {
+                       (void) printf(dgettext(TEXT_DOMAIN,
+                           "Pool %s returned to its state as of %s.\n"),
+                           name, timestr);
+               }
+               if (loss > 120) {
+                       (void) printf(dgettext(TEXT_DOMAIN,
+                           "%s approximately %lld "),
+                           dryrun ? "Would discard" : "Discarded",
+                           ((longlong_t)loss + 30) / 60);
+                       (void) printf(dgettext(TEXT_DOMAIN,
+                           "minutes of transactions.\n"));
+               } else if (loss > 0) {
+                       (void) printf(dgettext(TEXT_DOMAIN,
+                           "%s approximately %lld "),
+                           dryrun ? "Would discard" : "Discarded",
+                           (longlong_t)loss);
+                       (void) printf(dgettext(TEXT_DOMAIN,
+                           "seconds of transactions.\n"));
+               }
+       }
+}
+
+void
+zpool_explain_recover(libzfs_handle_t *hdl, const char *name, int reason,
+    nvlist_t *config)
+{
+       nvlist_t *nv = NULL;
+       int64_t loss = -1;
+       uint64_t edata = UINT64_MAX;
+       uint64_t rewindto;
+       struct tm t;
+       char timestr[128];
+
+       if (!hdl->libzfs_printerr)
+               return;
+
+       if (reason >= 0)
+               (void) printf(dgettext(TEXT_DOMAIN, "action: "));
+       else
+               (void) printf(dgettext(TEXT_DOMAIN, "\t"));
+
+       /* All attempted rewinds failed if ZPOOL_CONFIG_LOAD_TIME missing */
+       if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nv) != 0 ||
+           nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_REWIND_INFO, &nv) != 0 ||
+           nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_TIME, &rewindto) != 0)
+               goto no_info;
+
+       (void) nvlist_lookup_int64(nv, ZPOOL_CONFIG_REWIND_TIME, &loss);
+       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_LOAD_DATA_ERRORS,
+           &edata);
+
+       (void) printf(dgettext(TEXT_DOMAIN,
+           "Recovery is possible, but will result in some data loss.\n"));
+
+       if (localtime_r((time_t *)&rewindto, &t) != NULL &&
+           strftime(timestr, 128, "%c", &t) != 0) {
+               (void) printf(dgettext(TEXT_DOMAIN,
+                   "\tReturning the pool to its state as of %s\n"
+                   "\tshould correct the problem.  "),
+                   timestr);
+       } else {
+               (void) printf(dgettext(TEXT_DOMAIN,
+                   "\tReverting the pool to an earlier state "
+                   "should correct the problem.\n\t"));
+       }
+
+       if (loss > 120) {
+               (void) printf(dgettext(TEXT_DOMAIN,
+                   "Approximately %lld minutes of data\n"
+                   "\tmust be discarded, irreversibly.  "),
+                   ((longlong_t)loss + 30) / 60);
+       } else if (loss > 0) {
+               (void) printf(dgettext(TEXT_DOMAIN,
+                   "Approximately %lld seconds of data\n"
+                   "\tmust be discarded, irreversibly.  "),
+                   (longlong_t)loss);
+       }
+       if (edata != 0 && edata != UINT64_MAX) {
+               if (edata == 1) {
+                       (void) printf(dgettext(TEXT_DOMAIN,
+                           "After rewind, at least\n"
+                           "\tone persistent user-data error will remain.  "));
+               } else {
+                       (void) printf(dgettext(TEXT_DOMAIN,
+                           "After rewind, several\n"
+                           "\tpersistent user-data errors will remain.  "));
+               }
+       }
+       (void) printf(dgettext(TEXT_DOMAIN,
+           "Recovery can be attempted\n\tby executing 'zpool %s -F %s'.  "),
+           reason >= 0 ? "clear" : "import", name);
+
+       (void) printf(dgettext(TEXT_DOMAIN,
+           "A scrub of the pool\n"
+           "\tis strongly recommended after recovery.\n"));
+       return;
+
+no_info:
+       (void) printf(dgettext(TEXT_DOMAIN,
+           "Destroy and re-create the pool from\n\ta backup source.\n"));
+}
+
+/*
+ * zpool_import() is a contracted interface. Should be kept the same
+ * if possible.
+ *
+ * Applications should use zpool_import_props() to import a pool with
+ * new properties value to be set.
+ */
+int
+zpool_import(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
+    char *altroot)
+{
+       nvlist_t *props = NULL;
+       int ret;
+
+       if (altroot != NULL) {
+               if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
+                       return (zfs_error_fmt(hdl, EZFS_NOMEM,
+                           dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+                           newname));
+               }
+
+               if (nvlist_add_string(props,
+                   zpool_prop_to_name(ZPOOL_PROP_ALTROOT), altroot) != 0 ||
+                   nvlist_add_string(props,
+                   zpool_prop_to_name(ZPOOL_PROP_CACHEFILE), "none") != 0) {
+                       nvlist_free(props);
+                       return (zfs_error_fmt(hdl, EZFS_NOMEM,
+                           dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+                           newname));
+               }
+       }
+
+       ret = zpool_import_props(hdl, config, newname, props,
+           ZFS_IMPORT_NORMAL);
+       nvlist_free(props);
+       return (ret);
+}
+
+static void
+print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv,
+    int indent)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       char *vname;
+       uint64_t is_log = 0;
+
+       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG,
+           &is_log);
+
+       if (name != NULL)
+               (void) printf("\t%*s%s%s\n", indent, "", name,
+                   is_log ? " [log]" : "");
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               return;
+
+       for (c = 0; c < children; c++) {
+               vname = zpool_vdev_name(hdl, NULL, child[c], VDEV_NAME_TYPE_ID);
+               print_vdev_tree(hdl, vname, child[c], indent + 2);
+               free(vname);
+       }
+}
+
+void
+zpool_print_unsup_feat(nvlist_t *config)
+{
+       nvlist_t *nvinfo, *unsup_feat;
+       nvpair_t *nvp;
+
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO, &nvinfo) ==
+           0);
+       verify(nvlist_lookup_nvlist(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT,
+           &unsup_feat) == 0);
+
+       for (nvp = nvlist_next_nvpair(unsup_feat, NULL); nvp != NULL;
+           nvp = nvlist_next_nvpair(unsup_feat, nvp)) {
+               char *desc;
+
+               verify(nvpair_type(nvp) == DATA_TYPE_STRING);
+               verify(nvpair_value_string(nvp, &desc) == 0);
+
+               if (strlen(desc) > 0)
+                       (void) printf("\t%s (%s)\n", nvpair_name(nvp), desc);
+               else
+                       (void) printf("\t%s\n", nvpair_name(nvp));
+       }
+}
+
+/*
+ * Import the given pool using the known configuration and a list of
+ * properties to be set. The configuration should have come from
+ * zpool_find_import(). The 'newname' parameters control whether the pool
+ * is imported with a different name.
+ */
+int
+zpool_import_props(libzfs_handle_t *hdl, nvlist_t *config, const char *newname,
+    nvlist_t *props, int flags)
+{
+       zfs_cmd_t zc = {"\0"};
+       zpool_rewind_policy_t policy;
+       nvlist_t *nv = NULL;
+       nvlist_t *nvinfo = NULL;
+       nvlist_t *missing = NULL;
+       char *thename;
+       char *origname;
+       int ret;
+       int error = 0;
+       char errbuf[1024];
+
+       verify(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+           &origname) == 0);
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot import pool '%s'"), origname);
+
+       if (newname != NULL) {
+               if (!zpool_name_valid(hdl, B_FALSE, newname))
+                       return (zfs_error_fmt(hdl, EZFS_INVALIDNAME,
+                           dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+                           newname));
+               thename = (char *)newname;
+       } else {
+               thename = origname;
+       }
+
+       if (props != NULL) {
+               uint64_t version;
+               prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE };
+
+               verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+                   &version) == 0);
+
+               if ((props = zpool_valid_proplist(hdl, origname,
+                   props, version, flags, errbuf)) == NULL)
+                       return (-1);
+               if (zcmd_write_src_nvlist(hdl, &zc, props) != 0) {
+                       nvlist_free(props);
+                       return (-1);
+               }
+               nvlist_free(props);
+       }
+
+       (void) strlcpy(zc.zc_name, thename, sizeof (zc.zc_name));
+
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
+           &zc.zc_guid) == 0);
+
+       if (zcmd_write_conf_nvlist(hdl, &zc, config) != 0) {
+               zcmd_free_nvlists(&zc);
+               return (-1);
+       }
+       if (zcmd_alloc_dst_nvlist(hdl, &zc, zc.zc_nvlist_conf_size * 2) != 0) {
+               zcmd_free_nvlists(&zc);
+               return (-1);
+       }
+
+       zc.zc_cookie = flags;
+       while ((ret = zfs_ioctl(hdl, ZFS_IOC_POOL_IMPORT, &zc)) != 0 &&
+           errno == ENOMEM) {
+               if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+                       zcmd_free_nvlists(&zc);
+                       return (-1);
+               }
+       }
+       if (ret != 0)
+               error = errno;
+
+       (void) zcmd_read_dst_nvlist(hdl, &zc, &nv);
+
+       zcmd_free_nvlists(&zc);
+
+       zpool_get_rewind_policy(config, &policy);
+
+       if (error) {
+               char desc[1024];
+
+               /*
+                * Dry-run failed, but we print out what success
+                * looks like if we found a best txg
+                */
+               if (policy.zrp_request & ZPOOL_TRY_REWIND) {
+                       zpool_rewind_exclaim(hdl, newname ? origname : thename,
+                           B_TRUE, nv);
+                       nvlist_free(nv);
+                       return (-1);
+               }
+
+               if (newname == NULL)
+                       (void) snprintf(desc, sizeof (desc),
+                           dgettext(TEXT_DOMAIN, "cannot import '%s'"),
+                           thename);
+               else
+                       (void) snprintf(desc, sizeof (desc),
+                           dgettext(TEXT_DOMAIN, "cannot import '%s' as '%s'"),
+                           origname, thename);
+
+               switch (error) {
+               case ENOTSUP:
+                       if (nv != NULL && nvlist_lookup_nvlist(nv,
+                           ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
+                           nvlist_exists(nvinfo, ZPOOL_CONFIG_UNSUP_FEAT)) {
+                               (void) printf(dgettext(TEXT_DOMAIN, "This "
+                                   "pool uses the following feature(s) not "
+                                   "supported by this system:\n"));
+                               zpool_print_unsup_feat(nv);
+                               if (nvlist_exists(nvinfo,
+                                   ZPOOL_CONFIG_CAN_RDONLY)) {
+                                       (void) printf(dgettext(TEXT_DOMAIN,
+                                           "All unsupported features are only "
+                                           "required for writing to the pool."
+                                           "\nThe pool can be imported using "
+                                           "'-o readonly=on'.\n"));
+                               }
+                       }
+                       /*
+                        * Unsupported version.
+                        */
+                       (void) zfs_error(hdl, EZFS_BADVERSION, desc);
+                       break;
+
+               case EINVAL:
+                       (void) zfs_error(hdl, EZFS_INVALCONFIG, desc);
+                       break;
+
+               case EROFS:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "one or more devices is read only"));
+                       (void) zfs_error(hdl, EZFS_BADDEV, desc);
+                       break;
+
+               case ENXIO:
+                       if (nv && nvlist_lookup_nvlist(nv,
+                           ZPOOL_CONFIG_LOAD_INFO, &nvinfo) == 0 &&
+                           nvlist_lookup_nvlist(nvinfo,
+                           ZPOOL_CONFIG_MISSING_DEVICES, &missing) == 0) {
+                               (void) printf(dgettext(TEXT_DOMAIN,
+                                   "The devices below are missing, use "
+                                   "'-m' to import the pool anyway:\n"));
+                               print_vdev_tree(hdl, NULL, missing, 2);
+                               (void) printf("\n");
+                       }
+                       (void) zpool_standard_error(hdl, error, desc);
+                       break;
+
+               case EEXIST:
+                       (void) zpool_standard_error(hdl, error, desc);
+                       break;
+
+               case EBUSY:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "one or more devices are already in use\n"));
+                       (void) zfs_error(hdl, EZFS_BADDEV, desc);
+                       break;
+               case ENAMETOOLONG:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "new name of at least one dataset is longer than "
+                           "the maximum allowable length"));
+                       (void) zfs_error(hdl, EZFS_NAMETOOLONG, desc);
+                       break;
+               default:
+                       (void) zpool_standard_error(hdl, error, desc);
+                       zpool_explain_recover(hdl,
+                           newname ? origname : thename, -error, nv);
+                       break;
+               }
+
+               nvlist_free(nv);
+               ret = -1;
+       } else {
+               zpool_handle_t *zhp;
+
+               /*
+                * This should never fail, but play it safe anyway.
+                */
+               if (zpool_open_silent(hdl, thename, &zhp) != 0)
+                       ret = -1;
+               else if (zhp != NULL)
+                       zpool_close(zhp);
+               if (policy.zrp_request &
+                   (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
+                       zpool_rewind_exclaim(hdl, newname ? origname : thename,
+                           ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0), nv);
+               }
+               nvlist_free(nv);
+               return (0);
+       }
+
+       return (ret);
+}
+
+/*
+ * Scan the pool.
+ */
+int
+zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       zc.zc_cookie = func;
+
+       if (zfs_ioctl(hdl, ZFS_IOC_POOL_SCAN, &zc) == 0 ||
+           (errno == ENOENT && func != POOL_SCAN_NONE))
+               return (0);
+
+       if (func == POOL_SCAN_SCRUB) {
+               (void) snprintf(msg, sizeof (msg),
+                   dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name);
+       } else if (func == POOL_SCAN_NONE) {
+               (void) snprintf(msg, sizeof (msg),
+                   dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"),
+                   zc.zc_name);
+       } else {
+               assert(!"unexpected result");
+       }
+
+       if (errno == EBUSY) {
+               nvlist_t *nvroot;
+               pool_scan_stat_t *ps = NULL;
+               uint_t psc;
+
+               verify(nvlist_lookup_nvlist(zhp->zpool_config,
+                   ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+               (void) nvlist_lookup_uint64_array(nvroot,
+                   ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &psc);
+               if (ps && ps->pss_func == POOL_SCAN_SCRUB)
+                       return (zfs_error(hdl, EZFS_SCRUBBING, msg));
+               else
+                       return (zfs_error(hdl, EZFS_RESILVERING, msg));
+       } else if (errno == ENOENT) {
+               return (zfs_error(hdl, EZFS_NO_SCRUB, msg));
+       } else {
+               return (zpool_standard_error(hdl, errno, msg));
+       }
+}
+
+/*
+ * Find a vdev that matches the search criteria specified. We use the
+ * the nvpair name to determine how we should look for the device.
+ * 'avail_spare' is set to TRUE if the provided guid refers to an AVAIL
+ * spare; but FALSE if its an INUSE spare.
+ */
+static nvlist_t *
+vdev_to_nvlist_iter(nvlist_t *nv, nvlist_t *search, boolean_t *avail_spare,
+    boolean_t *l2cache, boolean_t *log)
+{
+       uint_t c, children;
+       nvlist_t **child;
+       nvlist_t *ret;
+       uint64_t is_log;
+       char *srchkey;
+       nvpair_t *pair = nvlist_next_nvpair(search, NULL);
+
+       /* Nothing to look for */
+       if (search == NULL || pair == NULL)
+               return (NULL);
+
+       /* Obtain the key we will use to search */
+       srchkey = nvpair_name(pair);
+
+       switch (nvpair_type(pair)) {
+       case DATA_TYPE_UINT64:
+               if (strcmp(srchkey, ZPOOL_CONFIG_GUID) == 0) {
+                       uint64_t srchval, theguid;
+
+                       verify(nvpair_value_uint64(pair, &srchval) == 0);
+                       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
+                           &theguid) == 0);
+                       if (theguid == srchval)
+                               return (nv);
+               }
+               break;
+
+       case DATA_TYPE_STRING: {
+               char *srchval, *val;
+
+               verify(nvpair_value_string(pair, &srchval) == 0);
+               if (nvlist_lookup_string(nv, srchkey, &val) != 0)
+                       break;
+
+               /*
+                * Search for the requested value. Special cases:
+                *
+                * - ZPOOL_CONFIG_PATH for whole disk entries.  These end in
+                *   "-part1", or "p1".  The suffix is hidden from the user,
+                *   but included in the string, so this matches around it.
+                * - ZPOOL_CONFIG_PATH for short names zfs_strcmp_shortname()
+                *   is used to check all possible expanded paths.
+                * - looking for a top-level vdev name (i.e. ZPOOL_CONFIG_TYPE).
+                *
+                * Otherwise, all other searches are simple string compares.
+                */
+               if (strcmp(srchkey, ZPOOL_CONFIG_PATH) == 0) {
+                       uint64_t wholedisk = 0;
+
+                       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
+                           &wholedisk);
+                       if (zfs_strcmp_pathname(srchval, val, wholedisk) == 0)
+                               return (nv);
+
+               } else if (strcmp(srchkey, ZPOOL_CONFIG_TYPE) == 0 && val) {
+                       char *type, *idx, *end, *p;
+                       uint64_t id, vdev_id;
+
+                       /*
+                        * Determine our vdev type, keeping in mind
+                        * that the srchval is composed of a type and
+                        * vdev id pair (i.e. mirror-4).
+                        */
+                       if ((type = strdup(srchval)) == NULL)
+                               return (NULL);
+
+                       if ((p = strrchr(type, '-')) == NULL) {
+                               free(type);
+                               break;
+                       }
+                       idx = p + 1;
+                       *p = '\0';
+
+                       /*
+                        * If the types don't match then keep looking.
+                        */
+                       if (strncmp(val, type, strlen(val)) != 0) {
+                               free(type);
+                               break;
+                       }
+
+                       verify(strncmp(type, VDEV_TYPE_RAIDZ,
+                           strlen(VDEV_TYPE_RAIDZ)) == 0 ||
+                           strncmp(type, VDEV_TYPE_MIRROR,
+                           strlen(VDEV_TYPE_MIRROR)) == 0);
+                       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
+                           &id) == 0);
+
+                       errno = 0;
+                       vdev_id = strtoull(idx, &end, 10);
+
+                       free(type);
+                       if (errno != 0)
+                               return (NULL);
+
+                       /*
+                        * Now verify that we have the correct vdev id.
+                        */
+                       if (vdev_id == id)
+                               return (nv);
+               }
+
+               /*
+                * Common case
+                */
+               if (strcmp(srchval, val) == 0)
+                       return (nv);
+               break;
+       }
+
+       default:
+               break;
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0)
+               return (NULL);
+
+       for (c = 0; c < children; c++) {
+               if ((ret = vdev_to_nvlist_iter(child[c], search,
+                   avail_spare, l2cache, NULL)) != NULL) {
+                       /*
+                        * The 'is_log' value is only set for the toplevel
+                        * vdev, not the leaf vdevs.  So we always lookup the
+                        * log device from the root of the vdev tree (where
+                        * 'log' is non-NULL).
+                        */
+                       if (log != NULL &&
+                           nvlist_lookup_uint64(child[c],
+                           ZPOOL_CONFIG_IS_LOG, &is_log) == 0 &&
+                           is_log) {
+                               *log = B_TRUE;
+                       }
+                       return (ret);
+               }
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++) {
+                       if ((ret = vdev_to_nvlist_iter(child[c], search,
+                           avail_spare, l2cache, NULL)) != NULL) {
+                               *avail_spare = B_TRUE;
+                               return (ret);
+                       }
+               }
+       }
+
+       if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
+           &child, &children) == 0) {
+               for (c = 0; c < children; c++) {
+                       if ((ret = vdev_to_nvlist_iter(child[c], search,
+                           avail_spare, l2cache, NULL)) != NULL) {
+                               *l2cache = B_TRUE;
+                               return (ret);
+                       }
+               }
+       }
+
+       return (NULL);
+}
+
+/*
+ * Given a physical path (minus the "/devices" prefix), find the
+ * associated vdev.
+ */
+nvlist_t *
+zpool_find_vdev_by_physpath(zpool_handle_t *zhp, const char *ppath,
+    boolean_t *avail_spare, boolean_t *l2cache, boolean_t *log)
+{
+       nvlist_t *search, *nvroot, *ret;
+
+       verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+       verify(nvlist_add_string(search, ZPOOL_CONFIG_PHYS_PATH, ppath) == 0);
+
+       verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+
+       *avail_spare = B_FALSE;
+       *l2cache = B_FALSE;
+       if (log != NULL)
+               *log = B_FALSE;
+       ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
+       nvlist_free(search);
+
+       return (ret);
+}
+
+/*
+ * Determine if we have an "interior" top-level vdev (i.e mirror/raidz).
+ */
+boolean_t
+zpool_vdev_is_interior(const char *name)
+{
+       if (strncmp(name, VDEV_TYPE_RAIDZ, strlen(VDEV_TYPE_RAIDZ)) == 0 ||
+           strncmp(name, VDEV_TYPE_MIRROR, strlen(VDEV_TYPE_MIRROR)) == 0)
+               return (B_TRUE);
+       return (B_FALSE);
+}
+
+nvlist_t *
+zpool_find_vdev(zpool_handle_t *zhp, const char *path, boolean_t *avail_spare,
+    boolean_t *l2cache, boolean_t *log)
+{
+       char *end;
+       nvlist_t *nvroot, *search, *ret;
+       uint64_t guid;
+
+       verify(nvlist_alloc(&search, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+       guid = strtoull(path, &end, 0);
+       if (guid != 0 && *end == '\0') {
+               verify(nvlist_add_uint64(search, ZPOOL_CONFIG_GUID, guid) == 0);
+       } else if (zpool_vdev_is_interior(path)) {
+               verify(nvlist_add_string(search, ZPOOL_CONFIG_TYPE, path) == 0);
+       } else {
+               verify(nvlist_add_string(search, ZPOOL_CONFIG_PATH, path) == 0);
+       }
+
+       verify(nvlist_lookup_nvlist(zhp->zpool_config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+
+       *avail_spare = B_FALSE;
+       *l2cache = B_FALSE;
+       if (log != NULL)
+               *log = B_FALSE;
+       ret = vdev_to_nvlist_iter(nvroot, search, avail_spare, l2cache, log);
+       nvlist_free(search);
+
+       return (ret);
+}
+
+static int
+vdev_online(nvlist_t *nv)
+{
+       uint64_t ival;
+
+       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_OFFLINE, &ival) == 0 ||
+           nvlist_lookup_uint64(nv, ZPOOL_CONFIG_FAULTED, &ival) == 0 ||
+           nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVED, &ival) == 0)
+               return (0);
+
+       return (1);
+}
+
+/*
+ * Helper function for zpool_get_physpaths().
+ */
+static int
+vdev_get_one_physpath(nvlist_t *config, char *physpath, size_t physpath_size,
+    size_t *bytes_written)
+{
+       size_t bytes_left, pos, rsz;
+       char *tmppath;
+       const char *format;
+
+       if (nvlist_lookup_string(config, ZPOOL_CONFIG_PHYS_PATH,
+           &tmppath) != 0)
+               return (EZFS_NODEVICE);
+
+       pos = *bytes_written;
+       bytes_left = physpath_size - pos;
+       format = (pos == 0) ? "%s" : " %s";
+
+       rsz = snprintf(physpath + pos, bytes_left, format, tmppath);
+       *bytes_written += rsz;
+
+       if (rsz >= bytes_left) {
+               /* if physpath was not copied properly, clear it */
+               if (bytes_left != 0) {
+                       physpath[pos] = 0;
+               }
+               return (EZFS_NOSPC);
+       }
+       return (0);
+}
+
+static int
+vdev_get_physpaths(nvlist_t *nv, char *physpath, size_t phypath_size,
+    size_t *rsz, boolean_t is_spare)
+{
+       char *type;
+       int ret;
+
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) != 0)
+               return (EZFS_INVALCONFIG);
+
+       if (strcmp(type, VDEV_TYPE_DISK) == 0) {
+               /*
+                * An active spare device has ZPOOL_CONFIG_IS_SPARE set.
+                * For a spare vdev, we only want to boot from the active
+                * spare device.
+                */
+               if (is_spare) {
+                       uint64_t spare = 0;
+                       (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_SPARE,
+                           &spare);
+                       if (!spare)
+                               return (EZFS_INVALCONFIG);
+               }
+
+               if (vdev_online(nv)) {
+                       if ((ret = vdev_get_one_physpath(nv, physpath,
+                           phypath_size, rsz)) != 0)
+                               return (ret);
+               }
+       } else if (strcmp(type, VDEV_TYPE_MIRROR) == 0 ||
+           strcmp(type, VDEV_TYPE_REPLACING) == 0 ||
+           (is_spare = (strcmp(type, VDEV_TYPE_SPARE) == 0))) {
+               nvlist_t **child;
+               uint_t count;
+               int i, ret;
+
+               if (nvlist_lookup_nvlist_array(nv,
+                   ZPOOL_CONFIG_CHILDREN, &child, &count) != 0)
+                       return (EZFS_INVALCONFIG);
+
+               for (i = 0; i < count; i++) {
+                       ret = vdev_get_physpaths(child[i], physpath,
+                           phypath_size, rsz, is_spare);
+                       if (ret == EZFS_NOSPC)
+                               return (ret);
+               }
+       }
+
+       return (EZFS_POOL_INVALARG);
+}
+
+/*
+ * Get phys_path for a root pool config.
+ * Return 0 on success; non-zero on failure.
+ */
+static int
+zpool_get_config_physpath(nvlist_t *config, char *physpath, size_t phypath_size)
+{
+       size_t rsz;
+       nvlist_t *vdev_root;
+       nvlist_t **child;
+       uint_t count;
+       char *type;
+
+       rsz = 0;
+
+       if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &vdev_root) != 0)
+               return (EZFS_INVALCONFIG);
+
+       if (nvlist_lookup_string(vdev_root, ZPOOL_CONFIG_TYPE, &type) != 0 ||
+           nvlist_lookup_nvlist_array(vdev_root, ZPOOL_CONFIG_CHILDREN,
+           &child, &count) != 0)
+               return (EZFS_INVALCONFIG);
+
+#if defined(__sun__) || defined(__sun)
+       /*
+        * root pool can not have EFI labeled disks and can only have
+        * a single top-level vdev.
+        */
+       if (strcmp(type, VDEV_TYPE_ROOT) != 0 || count != 1 ||
+           pool_uses_efi(vdev_root))
+               return (EZFS_POOL_INVALARG);
+#endif
+
+       (void) vdev_get_physpaths(child[0], physpath, phypath_size, &rsz,
+           B_FALSE);
+
+       /* No online devices */
+       if (rsz == 0)
+               return (EZFS_NODEVICE);
+
+       return (0);
+}
+
+/*
+ * Get phys_path for a root pool
+ * Return 0 on success; non-zero on failure.
+ */
+int
+zpool_get_physpath(zpool_handle_t *zhp, char *physpath, size_t phypath_size)
+{
+       return (zpool_get_config_physpath(zhp->zpool_config, physpath,
+           phypath_size));
+}
+
+/*
+ * If the device has being dynamically expanded then we need to relabel
+ * the disk to use the new unallocated space.
+ */
+static int
+zpool_relabel_disk(libzfs_handle_t *hdl, const char *path, const char *msg)
+{
+       int fd, error;
+
+       if ((fd = open(path, O_RDWR|O_DIRECT)) < 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
+                   "relabel '%s': unable to open device: %d"), path, errno);
+               return (zfs_error(hdl, EZFS_OPENFAILED, msg));
+       }
+
+       /*
+        * It's possible that we might encounter an error if the device
+        * does not have any unallocated space left. If so, we simply
+        * ignore that error and continue on.
+        *
+        * Also, we don't call efi_rescan() - that would just return EBUSY.
+        * The module will do it for us in vdev_disk_open().
+        */
+       error = efi_use_whole_disk(fd);
+       (void) close(fd);
+       if (error && error != VT_ENOSPC) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
+                   "relabel '%s': unable to read disk capacity"), path);
+               return (zfs_error(hdl, EZFS_NOCAP, msg));
+       }
+       return (0);
+}
+
+/*
+ * Bring the specified vdev online.   The 'flags' parameter is a set of the
+ * ZFS_ONLINE_* flags.
+ */
+int
+zpool_vdev_online(zpool_handle_t *zhp, const char *path, int flags,
+    vdev_state_t *newstate)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       nvlist_t *tgt;
+       boolean_t avail_spare, l2cache, islog;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       int error;
+
+       if (flags & ZFS_ONLINE_EXPAND) {
+               (void) snprintf(msg, sizeof (msg),
+                   dgettext(TEXT_DOMAIN, "cannot expand %s"), path);
+       } else {
+               (void) snprintf(msg, sizeof (msg),
+                   dgettext(TEXT_DOMAIN, "cannot online %s"), path);
+       }
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+           &islog)) == NULL)
+               return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+       verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+       if (avail_spare)
+               return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+       if (flags & ZFS_ONLINE_EXPAND ||
+           zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOEXPAND, NULL)) {
+               uint64_t wholedisk = 0;
+
+               (void) nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
+                   &wholedisk);
+
+               /*
+                * XXX - L2ARC 1.0 devices can't support expansion.
+                */
+               if (l2cache) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "cannot expand cache devices"));
+                       return (zfs_error(hdl, EZFS_VDEVNOTSUP, msg));
+               }
+
+               if (wholedisk) {
+                       const char *fullpath = path;
+                       char buf[MAXPATHLEN];
+
+                       if (path[0] != '/') {
+                               error = zfs_resolve_shortname(path, buf,
+                                   sizeof (buf));
+                               if (error != 0)
+                                       return (zfs_error(hdl, EZFS_NODEVICE,
+                                           msg));
+
+                               fullpath = buf;
+                       }
+
+                       error = zpool_relabel_disk(hdl, fullpath, msg);
+                       if (error != 0)
+                               return (error);
+               }
+       }
+
+       zc.zc_cookie = VDEV_STATE_ONLINE;
+       zc.zc_obj = flags;
+
+       if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) != 0) {
+               if (errno == EINVAL) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "was split "
+                           "from this pool into a new one.  Use '%s' "
+                           "instead"), "zpool detach");
+                       return (zfs_error(hdl, EZFS_POSTSPLIT_ONLINE, msg));
+               }
+               return (zpool_standard_error(hdl, errno, msg));
+       }
+
+       *newstate = zc.zc_cookie;
+       return (0);
+}
+
+/*
+ * Take the specified vdev offline
+ */
+int
+zpool_vdev_offline(zpool_handle_t *zhp, const char *path, boolean_t istmp)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       nvlist_t *tgt;
+       boolean_t avail_spare, l2cache;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "cannot offline %s"), path);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+           NULL)) == NULL)
+               return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+       verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+       if (avail_spare)
+               return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+       zc.zc_cookie = VDEV_STATE_OFFLINE;
+       zc.zc_obj = istmp ? ZFS_OFFLINE_TEMPORARY : 0;
+
+       if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+               return (0);
+
+       switch (errno) {
+       case EBUSY:
+
+               /*
+                * There are no other replicas of this device.
+                */
+               return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
+
+       case EEXIST:
+               /*
+                * The log device has unplayed logs
+                */
+               return (zfs_error(hdl, EZFS_UNPLAYED_LOGS, msg));
+
+       default:
+               return (zpool_standard_error(hdl, errno, msg));
+       }
+}
+
+/*
+ * Mark the given vdev faulted.
+ */
+int
+zpool_vdev_fault(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "cannot fault %llu"), (u_longlong_t)guid);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       zc.zc_guid = guid;
+       zc.zc_cookie = VDEV_STATE_FAULTED;
+       zc.zc_obj = aux;
+
+       if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+               return (0);
+
+       switch (errno) {
+       case EBUSY:
+
+               /*
+                * There are no other replicas of this device.
+                */
+               return (zfs_error(hdl, EZFS_NOREPLICAS, msg));
+
+       default:
+               return (zpool_standard_error(hdl, errno, msg));
+       }
+
+}
+
+/*
+ * Mark the given vdev degraded.
+ */
+int
+zpool_vdev_degrade(zpool_handle_t *zhp, uint64_t guid, vdev_aux_t aux)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "cannot degrade %llu"), (u_longlong_t)guid);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       zc.zc_guid = guid;
+       zc.zc_cookie = VDEV_STATE_DEGRADED;
+       zc.zc_obj = aux;
+
+       if (ioctl(hdl->libzfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
+               return (0);
+
+       return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Returns TRUE if the given nvlist is a vdev that was originally swapped in as
+ * a hot spare.
+ */
+static boolean_t
+is_replacing_spare(nvlist_t *search, nvlist_t *tgt, int which)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       char *type;
+
+       if (nvlist_lookup_nvlist_array(search, ZPOOL_CONFIG_CHILDREN, &child,
+           &children) == 0) {
+               verify(nvlist_lookup_string(search, ZPOOL_CONFIG_TYPE,
+                   &type) == 0);
+
+               if (strcmp(type, VDEV_TYPE_SPARE) == 0 &&
+                   children == 2 && child[which] == tgt)
+                       return (B_TRUE);
+
+               for (c = 0; c < children; c++)
+                       if (is_replacing_spare(child[c], tgt, which))
+                               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+/*
+ * Attach new_disk (fully described by nvroot) to old_disk.
+ * If 'replacing' is specified, the new disk will replace the old one.
+ */
+int
+zpool_vdev_attach(zpool_handle_t *zhp,
+    const char *old_disk, const char *new_disk, nvlist_t *nvroot, int replacing)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       int ret;
+       nvlist_t *tgt;
+       boolean_t avail_spare, l2cache, islog;
+       uint64_t val;
+       char *newname;
+       nvlist_t **child;
+       uint_t children;
+       nvlist_t *config_root;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       boolean_t rootpool = zpool_is_bootable(zhp);
+
+       if (replacing)
+               (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+                   "cannot replace %s with %s"), old_disk, new_disk);
+       else
+               (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+                   "cannot attach %s to %s"), new_disk, old_disk);
+
+#if defined(__sun__) || defined(__sun)
+       /*
+        * If this is a root pool, make sure that we're not attaching an
+        * EFI labeled device.
+        */
+       if (rootpool && pool_uses_efi(nvroot)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "EFI labeled devices are not supported on root pools."));
+               return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
+       }
+#endif
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       if ((tgt = zpool_find_vdev(zhp, old_disk, &avail_spare, &l2cache,
+           &islog)) == 0)
+               return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+       if (avail_spare)
+               return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+       if (l2cache)
+               return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
+
+       verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+       zc.zc_cookie = replacing;
+
+       if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
+           &child, &children) != 0 || children != 1) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "new device must be a single disk"));
+               return (zfs_error(hdl, EZFS_INVALCONFIG, msg));
+       }
+
+       verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
+           ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
+
+       if ((newname = zpool_vdev_name(NULL, NULL, child[0], 0)) == NULL)
+               return (-1);
+
+       /*
+        * If the target is a hot spare that has been swapped in, we can only
+        * replace it with another hot spare.
+        */
+       if (replacing &&
+           nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_IS_SPARE, &val) == 0 &&
+           (zpool_find_vdev(zhp, newname, &avail_spare, &l2cache,
+           NULL) == NULL || !avail_spare) &&
+           is_replacing_spare(config_root, tgt, 1)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "can only be replaced by another hot spare"));
+               free(newname);
+               return (zfs_error(hdl, EZFS_BADTARGET, msg));
+       }
+
+       free(newname);
+
+       if (zcmd_write_conf_nvlist(hdl, &zc, nvroot) != 0)
+               return (-1);
+
+       ret = zfs_ioctl(hdl, ZFS_IOC_VDEV_ATTACH, &zc);
+
+       zcmd_free_nvlists(&zc);
+
+       if (ret == 0) {
+               if (rootpool) {
+                       /*
+                        * XXX need a better way to prevent user from
+                        * booting up a half-baked vdev.
+                        */
+                       (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Make "
+                           "sure to wait until resilver is done "
+                           "before rebooting.\n"));
+               }
+               return (0);
+       }
+
+       switch (errno) {
+       case ENOTSUP:
+               /*
+                * Can't attach to or replace this type of vdev.
+                */
+               if (replacing) {
+                       uint64_t version = zpool_get_prop_int(zhp,
+                           ZPOOL_PROP_VERSION, NULL);
+
+                       if (islog)
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "cannot replace a log with a spare"));
+                       else if (version >= SPA_VERSION_MULTI_REPLACE)
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "already in replacing/spare config; wait "
+                                   "for completion or use 'zpool detach'"));
+                       else
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "cannot replace a replacing device"));
+               } else {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "can only attach to mirrors and top-level "
+                           "disks"));
+               }
+               (void) zfs_error(hdl, EZFS_BADTARGET, msg);
+               break;
+
+       case EINVAL:
+               /*
+                * The new device must be a single disk.
+                */
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "new device must be a single disk"));
+               (void) zfs_error(hdl, EZFS_INVALCONFIG, msg);
+               break;
+
+       case EBUSY:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s is busy"),
+                   new_disk);
+               (void) zfs_error(hdl, EZFS_BADDEV, msg);
+               break;
+
+       case EOVERFLOW:
+               /*
+                * The new device is too small.
+                */
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "device is too small"));
+               (void) zfs_error(hdl, EZFS_BADDEV, msg);
+               break;
+
+       case EDOM:
+               /*
+                * The new device has a different optimal sector size.
+                */
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "new device has a different optimal sector size; use the "
+                   "option '-o ashift=N' to override the optimal size"));
+               (void) zfs_error(hdl, EZFS_BADDEV, msg);
+               break;
+
+       case ENAMETOOLONG:
+               /*
+                * The resulting top-level vdev spec won't fit in the label.
+                */
+               (void) zfs_error(hdl, EZFS_DEVOVERFLOW, msg);
+               break;
+
+       default:
+               (void) zpool_standard_error(hdl, errno, msg);
+       }
+
+       return (-1);
+}
+
+/*
+ * Detach the specified device.
+ */
+int
+zpool_vdev_detach(zpool_handle_t *zhp, const char *path)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       nvlist_t *tgt;
+       boolean_t avail_spare, l2cache;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "cannot detach %s"), path);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+           NULL)) == 0)
+               return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+       if (avail_spare)
+               return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+       if (l2cache)
+               return (zfs_error(hdl, EZFS_ISL2CACHE, msg));
+
+       verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+       if (zfs_ioctl(hdl, ZFS_IOC_VDEV_DETACH, &zc) == 0)
+               return (0);
+
+       switch (errno) {
+
+       case ENOTSUP:
+               /*
+                * Can't detach from this type of vdev.
+                */
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "only "
+                   "applicable to mirror and replacing vdevs"));
+               (void) zfs_error(hdl, EZFS_BADTARGET, msg);
+               break;
+
+       case EBUSY:
+               /*
+                * There are no other replicas of this device.
+                */
+               (void) zfs_error(hdl, EZFS_NOREPLICAS, msg);
+               break;
+
+       default:
+               (void) zpool_standard_error(hdl, errno, msg);
+       }
+
+       return (-1);
+}
+
+/*
+ * Find a mirror vdev in the source nvlist.
+ *
+ * The mchild array contains a list of disks in one of the top-level mirrors
+ * of the source pool.  The schild array contains a list of disks that the
+ * user specified on the command line.  We loop over the mchild array to
+ * see if any entry in the schild array matches.
+ *
+ * If a disk in the mchild array is found in the schild array, we return
+ * the index of that entry.  Otherwise we return -1.
+ */
+static int
+find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren,
+    nvlist_t **schild, uint_t schildren)
+{
+       uint_t mc;
+
+       for (mc = 0; mc < mchildren; mc++) {
+               uint_t sc;
+               char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp,
+                   mchild[mc], 0);
+
+               for (sc = 0; sc < schildren; sc++) {
+                       char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp,
+                           schild[sc], 0);
+                       boolean_t result = (strcmp(mpath, spath) == 0);
+
+                       free(spath);
+                       if (result) {
+                               free(mpath);
+                               return (mc);
+                       }
+               }
+
+               free(mpath);
+       }
+
+       return (-1);
+}
+
+/*
+ * Split a mirror pool.  If newroot points to null, then a new nvlist
+ * is generated and it is the responsibility of the caller to free it.
+ */
+int
+zpool_vdev_split(zpool_handle_t *zhp, char *newname, nvlist_t **newroot,
+    nvlist_t *props, splitflags_t flags)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       nvlist_t *tree, *config, **child, **newchild, *newconfig = NULL;
+       nvlist_t **varray = NULL, *zc_props = NULL;
+       uint_t c, children, newchildren, lastlog = 0, vcount, found = 0;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       uint64_t vers;
+       boolean_t freelist = B_FALSE, memory_err = B_TRUE;
+       int retval = 0;
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "Unable to split %s"), zhp->zpool_name);
+
+       if (!zpool_name_valid(hdl, B_FALSE, newname))
+               return (zfs_error(hdl, EZFS_INVALIDNAME, msg));
+
+       if ((config = zpool_get_config(zhp, NULL)) == NULL) {
+               (void) fprintf(stderr, gettext("Internal error: unable to "
+                   "retrieve pool configuration\n"));
+               return (-1);
+       }
+
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &tree)
+           == 0);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION, &vers) == 0);
+
+       if (props) {
+               prop_flags_t flags = { .create = B_FALSE, .import = B_TRUE };
+               if ((zc_props = zpool_valid_proplist(hdl, zhp->zpool_name,
+                   props, vers, flags, msg)) == NULL)
+                       return (-1);
+       }
+
+       if (nvlist_lookup_nvlist_array(tree, ZPOOL_CONFIG_CHILDREN, &child,
+           &children) != 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "Source pool is missing vdev tree"));
+               nvlist_free(zc_props);
+               return (-1);
+       }
+
+       varray = zfs_alloc(hdl, children * sizeof (nvlist_t *));
+       vcount = 0;
+
+       if (*newroot == NULL ||
+           nvlist_lookup_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN,
+           &newchild, &newchildren) != 0)
+               newchildren = 0;
+
+       for (c = 0; c < children; c++) {
+               uint64_t is_log = B_FALSE, is_hole = B_FALSE;
+               char *type;
+               nvlist_t **mchild, *vdev;
+               uint_t mchildren;
+               int entry;
+
+               /*
+                * Unlike cache & spares, slogs are stored in the
+                * ZPOOL_CONFIG_CHILDREN array.  We filter them out here.
+                */
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+                   &is_log);
+               (void) nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_HOLE,
+                   &is_hole);
+               if (is_log || is_hole) {
+                       /*
+                        * Create a hole vdev and put it in the config.
+                        */
+                       if (nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) != 0)
+                               goto out;
+                       if (nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE,
+                           VDEV_TYPE_HOLE) != 0)
+                               goto out;
+                       if (nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_HOLE,
+                           1) != 0)
+                               goto out;
+                       if (lastlog == 0)
+                               lastlog = vcount;
+                       varray[vcount++] = vdev;
+                       continue;
+               }
+               lastlog = 0;
+               verify(nvlist_lookup_string(child[c], ZPOOL_CONFIG_TYPE, &type)
+                   == 0);
+               if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "Source pool must be composed only of mirrors\n"));
+                       retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
+                       goto out;
+               }
+
+               verify(nvlist_lookup_nvlist_array(child[c],
+                   ZPOOL_CONFIG_CHILDREN, &mchild, &mchildren) == 0);
+
+               /* find or add an entry for this top-level vdev */
+               if (newchildren > 0 &&
+                   (entry = find_vdev_entry(zhp, mchild, mchildren,
+                   newchild, newchildren)) >= 0) {
+                       /* We found a disk that the user specified. */
+                       vdev = mchild[entry];
+                       ++found;
+               } else {
+                       /* User didn't specify a disk for this vdev. */
+                       vdev = mchild[mchildren - 1];
+               }
+
+               if (nvlist_dup(vdev, &varray[vcount++], 0) != 0)
+                       goto out;
+       }
+
+       /* did we find every disk the user specified? */
+       if (found != newchildren) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Device list must "
+                   "include at most one disk from each mirror"));
+               retval = zfs_error(hdl, EZFS_INVALCONFIG, msg);
+               goto out;
+       }
+
+       /* Prepare the nvlist for populating. */
+       if (*newroot == NULL) {
+               if (nvlist_alloc(newroot, NV_UNIQUE_NAME, 0) != 0)
+                       goto out;
+               freelist = B_TRUE;
+               if (nvlist_add_string(*newroot, ZPOOL_CONFIG_TYPE,
+                   VDEV_TYPE_ROOT) != 0)
+                       goto out;
+       } else {
+               verify(nvlist_remove_all(*newroot, ZPOOL_CONFIG_CHILDREN) == 0);
+       }
+
+       /* Add all the children we found */
+       if (nvlist_add_nvlist_array(*newroot, ZPOOL_CONFIG_CHILDREN, varray,
+           lastlog == 0 ? vcount : lastlog) != 0)
+               goto out;
+
+       /*
+        * If we're just doing a dry run, exit now with success.
+        */
+       if (flags.dryrun) {
+               memory_err = B_FALSE;
+               freelist = B_FALSE;
+               goto out;
+       }
+
+       /* now build up the config list & call the ioctl */
+       if (nvlist_alloc(&newconfig, NV_UNIQUE_NAME, 0) != 0)
+               goto out;
+
+       if (nvlist_add_nvlist(newconfig,
+           ZPOOL_CONFIG_VDEV_TREE, *newroot) != 0 ||
+           nvlist_add_string(newconfig,
+           ZPOOL_CONFIG_POOL_NAME, newname) != 0 ||
+           nvlist_add_uint64(newconfig, ZPOOL_CONFIG_VERSION, vers) != 0)
+               goto out;
+
+       /*
+        * The new pool is automatically part of the namespace unless we
+        * explicitly export it.
+        */
+       if (!flags.import)
+               zc.zc_cookie = ZPOOL_EXPORT_AFTER_SPLIT;
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       (void) strlcpy(zc.zc_string, newname, sizeof (zc.zc_string));
+       if (zcmd_write_conf_nvlist(hdl, &zc, newconfig) != 0)
+               goto out;
+       if (zc_props != NULL && zcmd_write_src_nvlist(hdl, &zc, zc_props) != 0)
+               goto out;
+
+       if (zfs_ioctl(hdl, ZFS_IOC_VDEV_SPLIT, &zc) != 0) {
+               retval = zpool_standard_error(hdl, errno, msg);
+               goto out;
+       }
+
+       freelist = B_FALSE;
+       memory_err = B_FALSE;
+
+out:
+       if (varray != NULL) {
+               int v;
+
+               for (v = 0; v < vcount; v++)
+                       nvlist_free(varray[v]);
+               free(varray);
+       }
+       zcmd_free_nvlists(&zc);
+       nvlist_free(zc_props);
+       nvlist_free(newconfig);
+       if (freelist) {
+               nvlist_free(*newroot);
+               *newroot = NULL;
+       }
+
+       if (retval != 0)
+               return (retval);
+
+       if (memory_err)
+               return (no_memory(hdl));
+
+       return (0);
+}
+
+/*
+ * Remove the given device.  Currently, this is supported only for hot spares,
+ * cache, and log devices.
+ */
+int
+zpool_vdev_remove(zpool_handle_t *zhp, const char *path)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       nvlist_t *tgt;
+       boolean_t avail_spare, l2cache, islog;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       uint64_t version;
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "cannot remove %s"), path);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       if ((tgt = zpool_find_vdev(zhp, path, &avail_spare, &l2cache,
+           &islog)) == 0)
+               return (zfs_error(hdl, EZFS_NODEVICE, msg));
+       /*
+        * XXX - this should just go away.
+        */
+       if (!avail_spare && !l2cache && !islog) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "only inactive hot spares, cache, "
+                   "or log devices can be removed"));
+               return (zfs_error(hdl, EZFS_NODEVICE, msg));
+       }
+
+       version = zpool_get_prop_int(zhp, ZPOOL_PROP_VERSION, NULL);
+       if (islog && version < SPA_VERSION_HOLES) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "pool must be upgrade to support log removal"));
+               return (zfs_error(hdl, EZFS_BADVERSION, msg));
+       }
+
+       verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID, &zc.zc_guid) == 0);
+
+       if (zfs_ioctl(hdl, ZFS_IOC_VDEV_REMOVE, &zc) == 0)
+               return (0);
+
+       return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Clear the errors for the pool, or the particular device if specified.
+ */
+int
+zpool_clear(zpool_handle_t *zhp, const char *path, nvlist_t *rewindnvl)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       nvlist_t *tgt;
+       zpool_rewind_policy_t policy;
+       boolean_t avail_spare, l2cache;
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       nvlist_t *nvi = NULL;
+       int error;
+
+       if (path)
+               (void) snprintf(msg, sizeof (msg),
+                   dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
+                   path);
+       else
+               (void) snprintf(msg, sizeof (msg),
+                   dgettext(TEXT_DOMAIN, "cannot clear errors for %s"),
+                   zhp->zpool_name);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       if (path) {
+               if ((tgt = zpool_find_vdev(zhp, path, &avail_spare,
+                   &l2cache, NULL)) == 0)
+                       return (zfs_error(hdl, EZFS_NODEVICE, msg));
+
+               /*
+                * Don't allow error clearing for hot spares.  Do allow
+                * error clearing for l2cache devices.
+                */
+               if (avail_spare)
+                       return (zfs_error(hdl, EZFS_ISSPARE, msg));
+
+               verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_GUID,
+                   &zc.zc_guid) == 0);
+       }
+
+       zpool_get_rewind_policy(rewindnvl, &policy);
+       zc.zc_cookie = policy.zrp_request;
+
+       if (zcmd_alloc_dst_nvlist(hdl, &zc, zhp->zpool_config_size * 2) != 0)
+               return (-1);
+
+       if (zcmd_write_src_nvlist(hdl, &zc, rewindnvl) != 0)
+               return (-1);
+
+       while ((error = zfs_ioctl(hdl, ZFS_IOC_CLEAR, &zc)) != 0 &&
+           errno == ENOMEM) {
+               if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+                       zcmd_free_nvlists(&zc);
+                       return (-1);
+               }
+       }
+
+       if (!error || ((policy.zrp_request & ZPOOL_TRY_REWIND) &&
+           errno != EPERM && errno != EACCES)) {
+               if (policy.zrp_request &
+                   (ZPOOL_DO_REWIND | ZPOOL_TRY_REWIND)) {
+                       (void) zcmd_read_dst_nvlist(hdl, &zc, &nvi);
+                       zpool_rewind_exclaim(hdl, zc.zc_name,
+                           ((policy.zrp_request & ZPOOL_TRY_REWIND) != 0),
+                           nvi);
+                       nvlist_free(nvi);
+               }
+               zcmd_free_nvlists(&zc);
+               return (0);
+       }
+
+       zcmd_free_nvlists(&zc);
+       return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Similar to zpool_clear(), but takes a GUID (used by fmd).
+ */
+int
+zpool_vdev_clear(zpool_handle_t *zhp, uint64_t guid)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "cannot clear errors for %llx"),
+           (u_longlong_t)guid);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       zc.zc_guid = guid;
+       zc.zc_cookie = ZPOOL_NO_REWIND;
+
+       if (ioctl(hdl->libzfs_fd, ZFS_IOC_CLEAR, &zc) == 0)
+               return (0);
+
+       return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Change the GUID for a pool.
+ */
+int
+zpool_reguid(zpool_handle_t *zhp)
+{
+       char msg[1024];
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+       zfs_cmd_t zc = {"\0"};
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "cannot reguid '%s'"), zhp->zpool_name);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       if (zfs_ioctl(hdl, ZFS_IOC_POOL_REGUID, &zc) == 0)
+               return (0);
+
+       return (zpool_standard_error(hdl, errno, msg));
+}
+
+/*
+ * Reopen the pool.
+ */
+int
+zpool_reopen(zpool_handle_t *zhp)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) snprintf(msg, sizeof (msg),
+           dgettext(TEXT_DOMAIN, "cannot reopen '%s'"),
+           zhp->zpool_name);
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       if (zfs_ioctl(hdl, ZFS_IOC_POOL_REOPEN, &zc) == 0)
+               return (0);
+       return (zpool_standard_error(hdl, errno, msg));
+}
+
+#if defined(__sun__) || defined(__sun)
+/*
+ * Convert from a devid string to a path.
+ */
+static char *
+devid_to_path(char *devid_str)
+{
+       ddi_devid_t devid;
+       char *minor;
+       char *path;
+       devid_nmlist_t *list = NULL;
+       int ret;
+
+       if (devid_str_decode(devid_str, &devid, &minor) != 0)
+               return (NULL);
+
+       ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
+
+       devid_str_free(minor);
+       devid_free(devid);
+
+       if (ret != 0)
+               return (NULL);
+
+       /*
+        * In a case the strdup() fails, we will just return NULL below.
+        */
+       path = strdup(list[0].devname);
+
+       devid_free_nmlist(list);
+
+       return (path);
+}
+
+/*
+ * Convert from a path to a devid string.
+ */
+static char *
+path_to_devid(const char *path)
+{
+       int fd;
+       ddi_devid_t devid;
+       char *minor, *ret;
+
+       if ((fd = open(path, O_RDONLY)) < 0)
+               return (NULL);
+
+       minor = NULL;
+       ret = NULL;
+       if (devid_get(fd, &devid) == 0) {
+               if (devid_get_minor_name(fd, &minor) == 0)
+                       ret = devid_str_encode(devid, minor);
+               if (minor != NULL)
+                       devid_str_free(minor);
+               devid_free(devid);
+       }
+       (void) close(fd);
+
+       return (ret);
+}
+
+/*
+ * Issue the necessary ioctl() to update the stored path value for the vdev.  We
+ * ignore any failure here, since a common case is for an unprivileged user to
+ * type 'zpool status', and we'll display the correct information anyway.
+ */
+static void
+set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
+{
+       zfs_cmd_t zc = {"\0"};
+
+       (void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       (void) strncpy(zc.zc_value, path, sizeof (zc.zc_value));
+       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
+           &zc.zc_guid) == 0);
+
+       (void) ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
+}
+#endif /* sun */
+
+/*
+ * Remove partition suffix from a vdev path.  Partition suffixes may take three
+ * forms: "-partX", "pX", or "X", where X is a string of digits.  The second
+ * case only occurs when the suffix is preceded by a digit, i.e. "md0p0" The
+ * third case only occurs when preceded by a string matching the regular
+ * expression "^([hsv]|xv)d[a-z]+", i.e. a scsi, ide, virtio or xen disk.
+ *
+ * caller must free the returned string
+ */
+char *
+zfs_strip_partition(char *path)
+{
+       char *tmp = strdup(path);
+       char *part = NULL, *d = NULL;
+       if (!tmp)
+               return (NULL);
+
+       if ((part = strstr(tmp, "-part")) && part != tmp) {
+               d = part + 5;
+       } else if ((part = strrchr(tmp, 'p')) &&
+           part > tmp + 1 && isdigit(*(part-1))) {
+               d = part + 1;
+       } else if ((tmp[0] == 'h' || tmp[0] == 's' || tmp[0] == 'v') &&
+           tmp[1] == 'd') {
+               for (d = &tmp[2]; isalpha(*d); part = ++d);
+       } else if (strncmp("xvd", tmp, 3) == 0) {
+               for (d = &tmp[3]; isalpha(*d); part = ++d);
+       }
+       if (part && d && *d != '\0') {
+               for (; isdigit(*d); d++);
+               if (*d == '\0')
+                       *part = '\0';
+       }
+
+       return (tmp);
+}
+
+#define        PATH_BUF_LEN    64
+
+/*
+ * Given a vdev, return the name to display in iostat.  If the vdev has a path,
+ * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
+ * We also check if this is a whole disk, in which case we strip off the
+ * trailing 's0' slice name.
+ *
+ * This routine is also responsible for identifying when disks have been
+ * reconfigured in a new location.  The kernel will have opened the device by
+ * devid, but the path will still refer to the old location.  To catch this, we
+ * first do a path -> devid translation (which is fast for the common case).  If
+ * the devid matches, we're done.  If not, we do a reverse devid -> path
+ * translation and issue the appropriate ioctl() to update the path of the vdev.
+ * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
+ * of these checks.
+ */
+char *
+zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
+    int name_flags)
+{
+       char *path, *type, *env;
+       uint64_t value;
+       char buf[PATH_BUF_LEN];
+       char tmpbuf[PATH_BUF_LEN];
+
+       env = getenv("ZPOOL_VDEV_NAME_PATH");
+       if (env && (strtoul(env, NULL, 0) > 0 ||
+           !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+               name_flags |= VDEV_NAME_PATH;
+
+       env = getenv("ZPOOL_VDEV_NAME_GUID");
+       if (env && (strtoul(env, NULL, 0) > 0 ||
+           !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+               name_flags |= VDEV_NAME_GUID;
+
+       env = getenv("ZPOOL_VDEV_NAME_FOLLOW_LINKS");
+       if (env && (strtoul(env, NULL, 0) > 0 ||
+           !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+               name_flags |= VDEV_NAME_FOLLOW_LINKS;
+
+       if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &value) == 0 ||
+           name_flags & VDEV_NAME_GUID) {
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value);
+               (void) snprintf(buf, sizeof (buf), "%llu", (u_longlong_t)value);
+               path = buf;
+       } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
+#if defined(__sun__) || defined(__sun)
+               /*
+                * Live VDEV path updates to a kernel VDEV during a
+                * zpool_vdev_name lookup are not supported on Linux.
+                */
+               char *devid;
+               vdev_stat_t *vs;
+               uint_t vsc;
+
+               /*
+                * If the device is dead (faulted, offline, etc) then don't
+                * bother opening it.  Otherwise we may be forcing the user to
+                * open a misbehaving device, which can have undesirable
+                * effects.
+                */
+               if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+                   (uint64_t **)&vs, &vsc) != 0 ||
+                   vs->vs_state >= VDEV_STATE_DEGRADED) &&
+                   zhp != NULL &&
+                   nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
+                       /*
+                        * Determine if the current path is correct.
+                        */
+                       char *newdevid = path_to_devid(path);
+
+                       if (newdevid == NULL ||
+                           strcmp(devid, newdevid) != 0) {
+                               char *newpath;
+
+                               if ((newpath = devid_to_path(devid)) != NULL) {
+                                       /*
+                                        * Update the path appropriately.
+                                        */
+                                       set_path(zhp, nv, newpath);
+                                       if (nvlist_add_string(nv,
+                                           ZPOOL_CONFIG_PATH, newpath) == 0)
+                                               verify(nvlist_lookup_string(nv,
+                                                   ZPOOL_CONFIG_PATH,
+                                                   &path) == 0);
+                                       free(newpath);
+                               }
+                       }
+
+                       if (newdevid)
+                               devid_str_free(newdevid);
+               }
+#endif /* sun */
+
+               if (name_flags & VDEV_NAME_FOLLOW_LINKS) {
+                       char *rp = realpath(path, NULL);
+                       if (rp) {
+                               strlcpy(buf, rp, sizeof (buf));
+                               path = buf;
+                               free(rp);
+                       }
+               }
+
+               /*
+                * For a block device only use the name.
+                */
+               verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
+               if ((strcmp(type, VDEV_TYPE_DISK) == 0) &&
+                   !(name_flags & VDEV_NAME_PATH)) {
+                       path = strrchr(path, '/');
+                       path++;
+               }
+
+               /*
+                * Remove the partition from the path it this is a whole disk.
+                */
+               if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, &value)
+                   == 0 && value && !(name_flags & VDEV_NAME_PATH)) {
+                       return (zfs_strip_partition(path));
+               }
+       } else {
+               verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
+
+               /*
+                * If it's a raidz device, we need to stick in the parity level.
+                */
+               if (strcmp(path, VDEV_TYPE_RAIDZ) == 0) {
+                       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NPARITY,
+                           &value) == 0);
+                       (void) snprintf(buf, sizeof (buf), "%s%llu", path,
+                           (u_longlong_t)value);
+                       path = buf;
+               }
+
+               /*
+                * We identify each top-level vdev by using a <type-id>
+                * naming convention.
+                */
+               if (name_flags & VDEV_NAME_TYPE_ID) {
+                       uint64_t id;
+                       verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
+                           &id) == 0);
+                       (void) snprintf(tmpbuf, sizeof (tmpbuf), "%s-%llu",
+                           path, (u_longlong_t)id);
+                       path = tmpbuf;
+               }
+       }
+
+       return (zfs_strdup(hdl, path));
+}
+
+static int
+zbookmark_mem_compare(const void *a, const void *b)
+{
+       return (memcmp(a, b, sizeof (zbookmark_phys_t)));
+}
+
+/*
+ * Retrieve the persistent error log, uniquify the members, and return to the
+ * caller.
+ */
+int
+zpool_get_errlog(zpool_handle_t *zhp, nvlist_t **nverrlistp)
+{
+       zfs_cmd_t zc = {"\0"};
+       uint64_t count;
+       zbookmark_phys_t *zb = NULL;
+       int i;
+
+       /*
+        * Retrieve the raw error list from the kernel.  If the number of errors
+        * has increased, allocate more space and continue until we get the
+        * entire list.
+        */
+       verify(nvlist_lookup_uint64(zhp->zpool_config, ZPOOL_CONFIG_ERRCOUNT,
+           &count) == 0);
+       if (count == 0)
+               return (0);
+       if ((zc.zc_nvlist_dst = (uintptr_t)zfs_alloc(zhp->zpool_hdl,
+           count * sizeof (zbookmark_phys_t))) == (uintptr_t)NULL)
+               return (-1);
+       zc.zc_nvlist_dst_size = count;
+       (void) strcpy(zc.zc_name, zhp->zpool_name);
+       for (;;) {
+               if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_ERROR_LOG,
+                   &zc) != 0) {
+                       free((void *)(uintptr_t)zc.zc_nvlist_dst);
+                       if (errno == ENOMEM) {
+                               void *dst;
+
+                               count = zc.zc_nvlist_dst_size;
+                               dst = zfs_alloc(zhp->zpool_hdl, count *
+                                   sizeof (zbookmark_phys_t));
+                               if (dst == NULL)
+                                       return (-1);
+                               zc.zc_nvlist_dst = (uintptr_t)dst;
+                       } else {
+                               return (-1);
+                       }
+               } else {
+                       break;
+               }
+       }
+
+       /*
+        * Sort the resulting bookmarks.  This is a little confusing due to the
+        * implementation of ZFS_IOC_ERROR_LOG.  The bookmarks are copied last
+        * to first, and 'zc_nvlist_dst_size' indicates the number of boomarks
+        * _not_ copied as part of the process.  So we point the start of our
+        * array appropriate and decrement the total number of elements.
+        */
+       zb = ((zbookmark_phys_t *)(uintptr_t)zc.zc_nvlist_dst) +
+           zc.zc_nvlist_dst_size;
+       count -= zc.zc_nvlist_dst_size;
+
+       qsort(zb, count, sizeof (zbookmark_phys_t), zbookmark_mem_compare);
+
+       verify(nvlist_alloc(nverrlistp, 0, KM_SLEEP) == 0);
+
+       /*
+        * Fill in the nverrlistp with nvlist's of dataset and object numbers.
+        */
+       for (i = 0; i < count; i++) {
+               nvlist_t *nv;
+
+               /* ignoring zb_blkid and zb_level for now */
+               if (i > 0 && zb[i-1].zb_objset == zb[i].zb_objset &&
+                   zb[i-1].zb_object == zb[i].zb_object)
+                       continue;
+
+               if (nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) != 0)
+                       goto nomem;
+               if (nvlist_add_uint64(nv, ZPOOL_ERR_DATASET,
+                   zb[i].zb_objset) != 0) {
+                       nvlist_free(nv);
+                       goto nomem;
+               }
+               if (nvlist_add_uint64(nv, ZPOOL_ERR_OBJECT,
+                   zb[i].zb_object) != 0) {
+                       nvlist_free(nv);
+                       goto nomem;
+               }
+               if (nvlist_add_nvlist(*nverrlistp, "ejk", nv) != 0) {
+                       nvlist_free(nv);
+                       goto nomem;
+               }
+               nvlist_free(nv);
+       }
+
+       free((void *)(uintptr_t)zc.zc_nvlist_dst);
+       return (0);
+
+nomem:
+       free((void *)(uintptr_t)zc.zc_nvlist_dst);
+       return (no_memory(zhp->zpool_hdl));
+}
+
+/*
+ * Upgrade a ZFS pool to the latest on-disk version.
+ */
+int
+zpool_upgrade(zpool_handle_t *zhp, uint64_t new_version)
+{
+       zfs_cmd_t zc = {"\0"};
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) strcpy(zc.zc_name, zhp->zpool_name);
+       zc.zc_cookie = new_version;
+
+       if (zfs_ioctl(hdl, ZFS_IOC_POOL_UPGRADE, &zc) != 0)
+               return (zpool_standard_error_fmt(hdl, errno,
+                   dgettext(TEXT_DOMAIN, "cannot upgrade '%s'"),
+                   zhp->zpool_name));
+       return (0);
+}
+
+void
+zfs_save_arguments(int argc, char **argv, char *string, int len)
+{
+       int i;
+
+       (void) strlcpy(string, basename(argv[0]), len);
+       for (i = 1; i < argc; i++) {
+               (void) strlcat(string, " ", len);
+               (void) strlcat(string, argv[i], len);
+       }
+}
+
+int
+zpool_log_history(libzfs_handle_t *hdl, const char *message)
+{
+       zfs_cmd_t zc = {"\0"};
+       nvlist_t *args;
+       int err;
+
+       args = fnvlist_alloc();
+       fnvlist_add_string(args, "message", message);
+       err = zcmd_write_src_nvlist(hdl, &zc, args);
+       if (err == 0)
+               err = ioctl(hdl->libzfs_fd, ZFS_IOC_LOG_HISTORY, &zc);
+       nvlist_free(args);
+       zcmd_free_nvlists(&zc);
+       return (err);
+}
+
+/*
+ * Perform ioctl to get some command history of a pool.
+ *
+ * 'buf' is the buffer to fill up to 'len' bytes.  'off' is the
+ * logical offset of the history buffer to start reading from.
+ *
+ * Upon return, 'off' is the next logical offset to read from and
+ * 'len' is the actual amount of bytes read into 'buf'.
+ */
+static int
+get_history(zpool_handle_t *zhp, char *buf, uint64_t *off, uint64_t *len)
+{
+       zfs_cmd_t zc = {"\0"};
+       libzfs_handle_t *hdl = zhp->zpool_hdl;
+
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+
+       zc.zc_history = (uint64_t)(uintptr_t)buf;
+       zc.zc_history_len = *len;
+       zc.zc_history_offset = *off;
+
+       if (ioctl(hdl->libzfs_fd, ZFS_IOC_POOL_GET_HISTORY, &zc) != 0) {
+               switch (errno) {
+               case EPERM:
+                       return (zfs_error_fmt(hdl, EZFS_PERM,
+                           dgettext(TEXT_DOMAIN,
+                           "cannot show history for pool '%s'"),
+                           zhp->zpool_name));
+               case ENOENT:
+                       return (zfs_error_fmt(hdl, EZFS_NOHISTORY,
+                           dgettext(TEXT_DOMAIN, "cannot get history for pool "
+                           "'%s'"), zhp->zpool_name));
+               case ENOTSUP:
+                       return (zfs_error_fmt(hdl, EZFS_BADVERSION,
+                           dgettext(TEXT_DOMAIN, "cannot get history for pool "
+                           "'%s', pool must be upgraded"), zhp->zpool_name));
+               default:
+                       return (zpool_standard_error_fmt(hdl, errno,
+                           dgettext(TEXT_DOMAIN,
+                           "cannot get history for '%s'"), zhp->zpool_name));
+               }
+       }
+
+       *len = zc.zc_history_len;
+       *off = zc.zc_history_offset;
+
+       return (0);
+}
+
+/*
+ * Process the buffer of nvlists, unpacking and storing each nvlist record
+ * into 'records'.  'leftover' is set to the number of bytes that weren't
+ * processed as there wasn't a complete record.
+ */
+int
+zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
+    nvlist_t ***records, uint_t *numrecords)
+{
+       uint64_t reclen;
+       nvlist_t *nv;
+       int i;
+
+       while (bytes_read > sizeof (reclen)) {
+
+               /* get length of packed record (stored as little endian) */
+               for (i = 0, reclen = 0; i < sizeof (reclen); i++)
+                       reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
+
+               if (bytes_read < sizeof (reclen) + reclen)
+                       break;
+
+               /* unpack record */
+               if (nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0) != 0)
+                       return (ENOMEM);
+               bytes_read -= sizeof (reclen) + reclen;
+               buf += sizeof (reclen) + reclen;
+
+               /* add record to nvlist array */
+               (*numrecords)++;
+               if (ISP2(*numrecords + 1)) {
+                       *records = realloc(*records,
+                           *numrecords * 2 * sizeof (nvlist_t *));
+               }
+               (*records)[*numrecords - 1] = nv;
+       }
+
+       *leftover = bytes_read;
+       return (0);
+}
+
+/*
+ * Retrieve the command history of a pool.
+ */
+int
+zpool_get_history(zpool_handle_t *zhp, nvlist_t **nvhisp)
+{
+       char *buf;
+       int buflen = 128 * 1024;
+       uint64_t off = 0;
+       nvlist_t **records = NULL;
+       uint_t numrecords = 0;
+       int err, i;
+
+       buf = malloc(buflen);
+       if (buf == NULL)
+               return (ENOMEM);
+       do {
+               uint64_t bytes_read = buflen;
+               uint64_t leftover;
+
+               if ((err = get_history(zhp, buf, &off, &bytes_read)) != 0)
+                       break;
+
+               /* if nothing else was read in, we're at EOF, just return */
+               if (!bytes_read)
+                       break;
+
+               if ((err = zpool_history_unpack(buf, bytes_read,
+                   &leftover, &records, &numrecords)) != 0)
+                       break;
+               off -= leftover;
+               if (leftover == bytes_read) {
+                       /*
+                        * no progress made, because buffer is not big enough
+                        * to hold this record; resize and retry.
+                        */
+                       buflen *= 2;
+                       free(buf);
+                       buf = malloc(buflen);
+                       if (buf == NULL)
+                               return (ENOMEM);
+               }
+
+               /* CONSTCOND */
+       } while (1);
+
+       free(buf);
+
+       if (!err) {
+               verify(nvlist_alloc(nvhisp, NV_UNIQUE_NAME, 0) == 0);
+               verify(nvlist_add_nvlist_array(*nvhisp, ZPOOL_HIST_RECORD,
+                   records, numrecords) == 0);
+       }
+       for (i = 0; i < numrecords; i++)
+               nvlist_free(records[i]);
+       free(records);
+
+       return (err);
+}
+
+/*
+ * Retrieve the next event given the passed 'zevent_fd' file descriptor.
+ * If there is a new event available 'nvp' will contain a newly allocated
+ * nvlist and 'dropped' will be set to the number of missed events since
+ * the last call to this function.  When 'nvp' is set to NULL it indicates
+ * no new events are available.  In either case the function returns 0 and
+ * it is up to the caller to free 'nvp'.  In the case of a fatal error the
+ * function will return a non-zero value.  When the function is called in
+ * blocking mode (the default, unless the ZEVENT_NONBLOCK flag is passed),
+ * it will not return until a new event is available.
+ */
+int
+zpool_events_next(libzfs_handle_t *hdl, nvlist_t **nvp,
+    int *dropped, unsigned flags, int zevent_fd)
+{
+       zfs_cmd_t zc = {"\0"};
+       int error = 0;
+
+       *nvp = NULL;
+       *dropped = 0;
+       zc.zc_cleanup_fd = zevent_fd;
+
+       if (flags & ZEVENT_NONBLOCK)
+               zc.zc_guid = ZEVENT_NONBLOCK;
+
+       if (zcmd_alloc_dst_nvlist(hdl, &zc, ZEVENT_SIZE) != 0)
+               return (-1);
+
+retry:
+       if (zfs_ioctl(hdl, ZFS_IOC_EVENTS_NEXT, &zc) != 0) {
+               switch (errno) {
+               case ESHUTDOWN:
+                       error = zfs_error_fmt(hdl, EZFS_POOLUNAVAIL,
+                           dgettext(TEXT_DOMAIN, "zfs shutdown"));
+                       goto out;
+               case ENOENT:
+                       /* Blocking error case should not occur */
+                       if (!(flags & ZEVENT_NONBLOCK))
+                               error = zpool_standard_error_fmt(hdl, errno,
+                                   dgettext(TEXT_DOMAIN, "cannot get event"));
+
+                       goto out;
+               case ENOMEM:
+                       if (zcmd_expand_dst_nvlist(hdl, &zc) != 0) {
+                               error = zfs_error_fmt(hdl, EZFS_NOMEM,
+                                   dgettext(TEXT_DOMAIN, "cannot get event"));
+                               goto out;
+                       } else {
+                               goto retry;
+                       }
+               default:
+                       error = zpool_standard_error_fmt(hdl, errno,
+                           dgettext(TEXT_DOMAIN, "cannot get event"));
+                       goto out;
+               }
+       }
+
+       error = zcmd_read_dst_nvlist(hdl, &zc, nvp);
+       if (error != 0)
+               goto out;
+
+       *dropped = (int)zc.zc_cookie;
+out:
+       zcmd_free_nvlists(&zc);
+
+       return (error);
+}
+
+/*
+ * Clear all events.
+ */
+int
+zpool_events_clear(libzfs_handle_t *hdl, int *count)
+{
+       zfs_cmd_t zc = {"\0"};
+       char msg[1024];
+
+       (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN,
+           "cannot clear events"));
+
+       if (zfs_ioctl(hdl, ZFS_IOC_EVENTS_CLEAR, &zc) != 0)
+               return (zpool_standard_error_fmt(hdl, errno, msg));
+
+       if (count != NULL)
+               *count = (int)zc.zc_cookie; /* # of events cleared */
+
+       return (0);
+}
+
+/*
+ * Seek to a specific EID, ZEVENT_SEEK_START, or ZEVENT_SEEK_END for
+ * the passed zevent_fd file handle.  On success zero is returned,
+ * otherwise -1 is returned and hdl->libzfs_error is set to the errno.
+ */
+int
+zpool_events_seek(libzfs_handle_t *hdl, uint64_t eid, int zevent_fd)
+{
+       zfs_cmd_t zc = {"\0"};
+       int error = 0;
+
+       zc.zc_guid = eid;
+       zc.zc_cleanup_fd = zevent_fd;
+
+       if (zfs_ioctl(hdl, ZFS_IOC_EVENTS_SEEK, &zc) != 0) {
+               switch (errno) {
+               case ENOENT:
+                       error = zfs_error_fmt(hdl, EZFS_NOENT,
+                           dgettext(TEXT_DOMAIN, "cannot get event"));
+                       break;
+
+               case ENOMEM:
+                       error = zfs_error_fmt(hdl, EZFS_NOMEM,
+                           dgettext(TEXT_DOMAIN, "cannot get event"));
+                       break;
+
+               default:
+                       error = zpool_standard_error_fmt(hdl, errno,
+                           dgettext(TEXT_DOMAIN, "cannot get event"));
+                       break;
+               }
+       }
+
+       return (error);
+}
+
+void
+zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj,
+    char *pathname, size_t len)
+{
+       zfs_cmd_t zc = {"\0"};
+       boolean_t mounted = B_FALSE;
+       char *mntpnt = NULL;
+       char dsname[ZFS_MAX_DATASET_NAME_LEN];
+
+       if (dsobj == 0) {
+               /* special case for the MOS */
+               (void) snprintf(pathname, len, "<metadata>:<0x%llx>",
+                   (longlong_t)obj);
+               return;
+       }
+
+       /* get the dataset's name */
+       (void) strlcpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+       zc.zc_obj = dsobj;
+       if (ioctl(zhp->zpool_hdl->libzfs_fd,
+           ZFS_IOC_DSOBJ_TO_DSNAME, &zc) != 0) {
+               /* just write out a path of two object numbers */
+               (void) snprintf(pathname, len, "<0x%llx>:<0x%llx>",
+                   (longlong_t)dsobj, (longlong_t)obj);
+               return;
+       }
+       (void) strlcpy(dsname, zc.zc_value, sizeof (dsname));
+
+       /* find out if the dataset is mounted */
+       mounted = is_mounted(zhp->zpool_hdl, dsname, &mntpnt);
+
+       /* get the corrupted object's path */
+       (void) strlcpy(zc.zc_name, dsname, sizeof (zc.zc_name));
+       zc.zc_obj = obj;
+       if (ioctl(zhp->zpool_hdl->libzfs_fd, ZFS_IOC_OBJ_TO_PATH,
+           &zc) == 0) {
+               if (mounted) {
+                       (void) snprintf(pathname, len, "%s%s", mntpnt,
+                           zc.zc_value);
+               } else {
+                       (void) snprintf(pathname, len, "%s:%s",
+                           dsname, zc.zc_value);
+               }
+       } else {
+               (void) snprintf(pathname, len, "%s:<0x%llx>", dsname,
+                   (longlong_t)obj);
+       }
+       free(mntpnt);
+}
+
+/*
+ * Read the EFI label from the config, if a label does not exist then
+ * pass back the error to the caller. If the caller has passed a non-NULL
+ * diskaddr argument then we set it to the starting address of the EFI
+ * partition.
+ */
+static int
+read_efi_label(nvlist_t *config, diskaddr_t *sb)
+{
+       char *path;
+       int fd;
+       char diskname[MAXPATHLEN];
+       int err = -1;
+
+       if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0)
+               return (err);
+
+       (void) snprintf(diskname, sizeof (diskname), "%s%s", DISK_ROOT,
+           strrchr(path, '/'));
+       if ((fd = open(diskname, O_RDWR|O_DIRECT)) >= 0) {
+               struct dk_gpt *vtoc;
+
+               if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) {
+                       if (sb != NULL)
+                               *sb = vtoc->efi_parts[0].p_start;
+                       efi_free(vtoc);
+               }
+               (void) close(fd);
+       }
+       return (err);
+}
+
+/*
+ * determine where a partition starts on a disk in the current
+ * configuration
+ */
+static diskaddr_t
+find_start_block(nvlist_t *config)
+{
+       nvlist_t **child;
+       uint_t c, children;
+       diskaddr_t sb = MAXOFFSET_T;
+       uint64_t wholedisk;
+
+       if (nvlist_lookup_nvlist_array(config,
+           ZPOOL_CONFIG_CHILDREN, &child, &children) != 0) {
+               if (nvlist_lookup_uint64(config,
+                   ZPOOL_CONFIG_WHOLE_DISK,
+                   &wholedisk) != 0 || !wholedisk) {
+                       return (MAXOFFSET_T);
+               }
+               if (read_efi_label(config, &sb) < 0)
+                       sb = MAXOFFSET_T;
+               return (sb);
+       }
+
+       for (c = 0; c < children; c++) {
+               sb = find_start_block(child[c]);
+               if (sb != MAXOFFSET_T) {
+                       return (sb);
+               }
+       }
+       return (MAXOFFSET_T);
+}
+
+static int
+zpool_label_disk_check(char *path)
+{
+       struct dk_gpt *vtoc;
+       int fd, err;
+
+       if ((fd = open(path, O_RDWR|O_DIRECT)) < 0)
+               return (errno);
+
+       if ((err = efi_alloc_and_read(fd, &vtoc)) != 0) {
+               (void) close(fd);
+               return (err);
+       }
+
+       if (vtoc->efi_flags & EFI_GPT_PRIMARY_CORRUPT) {
+               efi_free(vtoc);
+               (void) close(fd);
+               return (EIDRM);
+       }
+
+       efi_free(vtoc);
+       (void) close(fd);
+       return (0);
+}
+
+/*
+ * Generate a unique partition name for the ZFS member.  Partitions must
+ * have unique names to ensure udev will be able to create symlinks under
+ * /dev/disk/by-partlabel/ for all pool members.  The partition names are
+ * of the form <pool>-<unique-id>.
+ */
+static void
+zpool_label_name(char *label_name, int label_size)
+{
+       uint64_t id = 0;
+       int fd;
+
+       fd = open("/dev/urandom", O_RDONLY);
+       if (fd >= 0) {
+               if (read(fd, &id, sizeof (id)) != sizeof (id))
+                       id = 0;
+
+               close(fd);
+       }
+
+       if (id == 0)
+               id = (((uint64_t)rand()) << 32) | (uint64_t)rand();
+
+       snprintf(label_name, label_size, "zfs-%016llx", (u_longlong_t) id);
+}
+
+/*
+ * Label an individual disk.  The name provided is the short name,
+ * stripped of any leading /dev path.
+ */
+int
+zpool_label_disk(libzfs_handle_t *hdl, zpool_handle_t *zhp, char *name)
+{
+       char path[MAXPATHLEN];
+       struct dk_gpt *vtoc;
+       int rval, fd;
+       size_t resv = EFI_MIN_RESV_SIZE;
+       uint64_t slice_size;
+       diskaddr_t start_block;
+       char errbuf[1024];
+
+       /* prepare an error message just in case */
+       (void) snprintf(errbuf, sizeof (errbuf),
+           dgettext(TEXT_DOMAIN, "cannot label '%s'"), name);
+
+       if (zhp) {
+               nvlist_t *nvroot;
+
+#if defined(__sun__) || defined(__sun)
+               if (zpool_is_bootable(zhp)) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "EFI labeled devices are not supported on root "
+                           "pools."));
+                       return (zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf));
+               }
+#endif
+
+               verify(nvlist_lookup_nvlist(zhp->zpool_config,
+                   ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0);
+
+               if (zhp->zpool_start_block == 0)
+                       start_block = find_start_block(nvroot);
+               else
+                       start_block = zhp->zpool_start_block;
+               zhp->zpool_start_block = start_block;
+       } else {
+               /* new pool */
+               start_block = NEW_START_BLOCK;
+       }
+
+       (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, name);
+
+       if ((fd = open(path, O_RDWR|O_DIRECT|O_EXCL)) < 0) {
+               /*
+                * This shouldn't happen.  We've long since verified that this
+                * is a valid device.
+                */
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
+                   "label '%s': unable to open device: %d"), path, errno);
+               return (zfs_error(hdl, EZFS_OPENFAILED, errbuf));
+       }
+
+       if (efi_alloc_and_init(fd, EFI_NUMPAR, &vtoc) != 0) {
+               /*
+                * The only way this can fail is if we run out of memory, or we
+                * were unable to read the disk's capacity
+                */
+               if (errno == ENOMEM)
+                       (void) no_memory(hdl);
+
+               (void) close(fd);
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "cannot "
+                   "label '%s': unable to read disk capacity"), path);
+
+               return (zfs_error(hdl, EZFS_NOCAP, errbuf));
+       }
+
+       slice_size = vtoc->efi_last_u_lba + 1;
+       slice_size -= EFI_MIN_RESV_SIZE;
+       if (start_block == MAXOFFSET_T)
+               start_block = NEW_START_BLOCK;
+       slice_size -= start_block;
+       slice_size = P2ALIGN(slice_size, PARTITION_END_ALIGNMENT);
+
+       vtoc->efi_parts[0].p_start = start_block;
+       vtoc->efi_parts[0].p_size = slice_size;
+
+       /*
+        * Why we use V_USR: V_BACKUP confuses users, and is considered
+        * disposable by some EFI utilities (since EFI doesn't have a backup
+        * slice).  V_UNASSIGNED is supposed to be used only for zero size
+        * partitions, and efi_write() will fail if we use it.  V_ROOT, V_BOOT,
+        * etc. were all pretty specific.  V_USR is as close to reality as we
+        * can get, in the absence of V_OTHER.
+        */
+       vtoc->efi_parts[0].p_tag = V_USR;
+       zpool_label_name(vtoc->efi_parts[0].p_name, EFI_PART_NAME_LEN);
+
+       vtoc->efi_parts[8].p_start = slice_size + start_block;
+       vtoc->efi_parts[8].p_size = resv;
+       vtoc->efi_parts[8].p_tag = V_RESERVED;
+
+       if ((rval = efi_write(fd, vtoc)) != 0 || (rval = efi_rescan(fd)) != 0) {
+               /*
+                * Some block drivers (like pcata) may not support EFI
+                * GPT labels.  Print out a helpful error message dir-
+                * ecting the user to manually label the disk and give
+                * a specific slice.
+                */
+               (void) close(fd);
+               efi_free(vtoc);
+
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "try using "
+                   "parted(8) and then provide a specific slice: %d"), rval);
+               return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
+       }
+
+       (void) close(fd);
+       efi_free(vtoc);
+
+       (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, name);
+       (void) zfs_append_partition(path, MAXPATHLEN);
+
+       /* Wait to udev to signal use the device has settled. */
+       rval = zpool_label_disk_wait(path, DISK_LABEL_WAIT);
+       if (rval) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "failed to "
+                   "detect device partitions on '%s': %d"), path, rval);
+               return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
+       }
+
+       /* We can't be to paranoid.  Read the label back and verify it. */
+       (void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT, name);
+       rval = zpool_label_disk_check(path);
+       if (rval) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "freshly written "
+                   "EFI label on '%s' is damaged.  Ensure\nthis device "
+                   "is not in in use, and is functioning properly: %d"),
+                   path, rval);
+               return (zfs_error(hdl, EZFS_LABELFAILED, errbuf));
+       }
+
+       return (0);
+}
+
+#if HAVE_LIBDEVMAPPER
+static void libdevmapper_dummy_log(int level, const char *file, int line,
+    int dm_errno_or_class, const char *f, ...) {}
+
+/* Disable libdevmapper error logging */
+static void disable_libdevmapper_errors(void) {
+       dm_log_with_errno_init(libdevmapper_dummy_log);
+}
+/* Enable libdevmapper error logging */
+static void enable_libdevmapper_errors(void) {
+       dm_log_with_errno_init(NULL);
+}
+#endif
+
+/*
+ * Allocate and return the underlying device name for a device mapper device.
+ * If a device mapper device maps to multiple devices, return the first device.
+ *
+ * For example, dm_name = "/dev/dm-0" could return "/dev/sda"
+ *
+ * dm_name should include the "/dev[/mapper]" prefix.
+ *
+ * Returns device name, or NULL on error or no match.  If dm_name is not a DM
+ * device then return NULL.
+ *
+ * NOTE: The returned name string must be *freed*.
+ */
+static char * dm_get_underlying_path(char *dm_name)
+{
+       char *name = NULL;
+#if HAVE_LIBDEVMAPPER
+       char *tmp;
+       struct dm_task *dmt = NULL;
+       struct dm_tree *dt = NULL;
+       struct dm_tree_node *root, *child;
+       void *handle = NULL;
+       struct dm_info info;
+       const struct dm_info *child_info;
+
+       /*
+        * Disable libdevmapper errors.  It's entirely possible user is not
+        * running devmapper, or that dm_name is not a devmapper device.
+        * That's totally ok, we will just harmlessly and silently return NULL.
+        */
+       disable_libdevmapper_errors();
+
+       /*
+        * libdevmapper tutorial
+        *
+        * libdevmapper is basically a fancy wrapper for its ioctls.  You
+        * create a "task", fill in the needed info to the task (fill in the
+        * ioctl fields), then run the task (call the ioctl).
+        *
+        * First we need the major/minor number for our DM device.
+        */
+       if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
+               goto end;
+
+       /* Lookup the name in libdevmapper */
+       if (!dm_task_set_name(dmt, dm_name)) {
+               enable_libdevmapper_errors();
+               goto end;
+       }
+
+       if (!dm_task_run(dmt))
+               goto end;
+
+       /* Get DM device's major/minor */
+       if (!dm_task_get_info(dmt, &info))
+               goto end;
+
+       /* We have major/minor number.  Lookup the dm device's children */
+       if (!(dt = dm_tree_create()))
+               goto end;
+
+       /* We add the device into the tree and its children get populated */
+       if (!dm_tree_add_dev(dt, info.major, info.minor))
+               goto end;
+
+       if (!(root = dm_tree_find_node(dt, 0, 0)))
+               goto end;
+
+       if (!(child = dm_tree_next_child(&handle, root, 1)))
+               goto end;
+
+       /* Get child's major/minor numbers */
+       if (!(child_info = dm_tree_node_get_info(child)))
+               goto end;
+
+       if ((asprintf(&tmp, "/dev/block/%d:%d", child_info->major,
+           child_info->minor) == -1) || tmp == NULL)
+               goto end;
+
+       /* Further translate /dev/block/ name into the normal name */
+       name = realpath(tmp, NULL);
+       free(tmp);
+
+end:
+       if (dmt)
+               dm_task_destroy(dmt);
+       if (dt)
+               dm_tree_free(dt);
+       enable_libdevmapper_errors();
+#endif /* HAVE_LIBDEVMAPPER */
+
+       return (name);
+}
+
+/*
+ * Return 1 if device is a device mapper or multipath device.
+ * Return 0 if not.
+ */
+int
+zfs_dev_is_dm(char *dev_name)
+{
+
+       char *tmp;
+       tmp = dm_get_underlying_path(dev_name);
+       if (!tmp)
+               return (0);
+
+       free(tmp);
+       return (1);
+}
+
+/*
+ * Lookup the underlying device for a device name
+ *
+ * Often you'll have a symlink to a device, a partition device,
+ * or a multipath device, and want to look up the underlying device.
+ * This function returns the underlying device name.  If the device
+ * name is already the underlying device, then just return the same
+ * name.  If the device is a DM device with multiple underlying devices
+ * then return the first one.
+ *
+ * For example:
+ *
+ * 1. /dev/disk/by-id/ata-QEMU_HARDDISK_QM00001 -> ../../sda
+ * dev_name:   /dev/disk/by-id/ata-QEMU_HARDDISK_QM00001
+ * returns:    /dev/sda
+ *
+ * 2. /dev/mapper/mpatha (made up of /dev/sda and /dev/sdb)
+ * dev_name:   /dev/mapper/mpatha
+ * returns:    /dev/sda (first device)
+ *
+ * 3. /dev/sda (already the underlying device)
+ * dev_name:   /dev/sda
+ * returns:    /dev/sda
+ *
+ * 4. /dev/dm-3 (mapped to /dev/sda)
+ * dev_name:   /dev/dm-3
+ * returns:    /dev/sda
+ *
+ * 5. /dev/disk/by-id/scsi-0QEMU_drive-scsi0-0-0-0-part9 -> ../../sdb9
+ * dev_name:   /dev/disk/by-id/scsi-0QEMU_drive-scsi0-0-0-0-part9
+ * returns:    /dev/sdb
+ *
+ * 6. /dev/disk/by-uuid/5df030cf-3cd9-46e4-8e99-3ccb462a4e9a -> ../dev/sda2
+ * dev_name:   /dev/disk/by-uuid/5df030cf-3cd9-46e4-8e99-3ccb462a4e9a
+ * returns:    /dev/sda
+ *
+ * Returns underlying device name, or NULL on error or no match.
+ *
+ * NOTE: The returned name string must be *freed*.
+ */
+char *
+zfs_get_underlying_path(char *dev_name)
+{
+       char *name = NULL;
+       char *tmp;
+
+       if (!dev_name)
+               return (NULL);
+
+       tmp = dm_get_underlying_path(dev_name);
+
+       /* dev_name not a DM device, so just un-symlinkize it */
+       if (!tmp)
+               tmp = realpath(dev_name, NULL);
+
+       if (tmp) {
+               name = zfs_strip_partition(tmp);
+               free(tmp);
+       }
+
+       return (name);
+}
+
+/*
+ * Given a dev name like "sda", return the full enclosure sysfs path to
+ * the disk.  You can also pass in the name with "/dev" prepended
+ * to it (like /dev/sda).
+ *
+ * For example, disk "sda" in enclosure slot 1:
+ *     dev:            "sda"
+ *     returns:        "/sys/class/enclosure/1:0:3:0/Slot 1"
+ *
+ * 'dev' must be a non-devicemapper device.
+ *
+ * Returned string must be freed.
+ */
+char *
+zfs_get_enclosure_sysfs_path(char *dev_name)
+{
+       DIR *dp = NULL;
+       struct dirent *ep;
+       char buf[MAXPATHLEN];
+       char *tmp1 = NULL;
+       char *tmp2 = NULL;
+       char *tmp3 = NULL;
+       char *path = NULL;
+       size_t size;
+       int tmpsize;
+
+       if (!dev_name)
+               return (NULL);
+
+       /* If they preface 'dev' with a path (like "/dev") then strip it off */
+       tmp1 = strrchr(dev_name, '/');
+       if (tmp1)
+               dev_name = tmp1 + 1;    /* +1 since we want the chr after '/' */
+
+       tmpsize = asprintf(&tmp1, "/sys/block/%s/device", dev_name);
+       if (tmpsize == -1 || tmp1 == NULL) {
+               tmp1 = NULL;
+               goto end;
+       }
+
+       dp = opendir(tmp1);
+       if (dp == NULL) {
+               tmp1 = NULL;    /* To make free() at the end a NOP */
+               goto end;
+       }
+
+       /*
+        * Look though all sysfs entries in /sys/block/<dev>/device for
+        * the enclosure symlink.
+        */
+       while ((ep = readdir(dp))) {
+               /* Ignore everything that's not our enclosure_device link */
+               if (!strstr(ep->d_name, "enclosure_device"))
+                       continue;
+
+               if (asprintf(&tmp2, "%s/%s", tmp1, ep->d_name) == -1 ||
+                   tmp2 == NULL)
+                       break;
+
+               size = readlink(tmp2, buf, sizeof (buf));
+
+               /* Did readlink fail or crop the link name? */
+               if (size == -1 || size >= sizeof (buf)) {
+                       free(tmp2);
+                       tmp2 = NULL;    /* To make free() at the end a NOP */
+                       break;
+               }
+
+               /*
+                * We got a valid link.  readlink() doesn't terminate strings
+                * so we have to do it.
+                */
+               buf[size] = '\0';
+
+               /*
+                * Our link will look like:
+                *
+                * "../../../../port-11:1:2/..STUFF../enclosure/1:0:3:0/SLOT 1"
+                *
+                * We want to grab the "enclosure/1:0:3:0/SLOT 1" part
+                */
+               tmp3 = strstr(buf, "enclosure");
+               if (tmp3 == NULL)
+                       break;
+
+               if (asprintf(&path, "/sys/class/%s", tmp3) == -1) {
+                       /* If asprintf() fails, 'path' is undefined */
+                       path = NULL;
+                       break;
+               }
+
+               if (path == NULL)
+                       break;
+       }
+
+end:
+       free(tmp2);
+       free(tmp1);
+
+       if (dp)
+               closedir(dp);
+
+       return (path);
+}
diff --git a/zfs/lib/libzfs/libzfs_sendrecv.c b/zfs/lib/libzfs/libzfs_sendrecv.c
new file mode 100644 (file)
index 0000000..21d67e7
--- /dev/null
@@ -0,0 +1,3857 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
+ * All rights reserved
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+#include <sys/avl.h>
+#include <sys/debug.h>
+#include <sys/stat.h>
+#include <stddef.h>
+#include <pthread.h>
+#include <umem.h>
+#include <time.h>
+
+#include <libzfs.h>
+#include <libzfs_core.h>
+
+#include "zfs_namecheck.h"
+#include "zfs_prop.h"
+#include "zfs_fletcher.h"
+#include "libzfs_impl.h"
+#include <zlib.h>
+#include <sys/zio_checksum.h>
+#include <sys/ddt.h>
+#include <sys/socket.h>
+#include <sys/sha2.h>
+
+/* in libzfs_dataset.c */
+extern void zfs_setprop_error(libzfs_handle_t *, zfs_prop_t, int, char *);
+
+static int zfs_receive_impl(libzfs_handle_t *, const char *, const char *,
+    recvflags_t *, int, const char *, nvlist_t *, avl_tree_t *, char **, int,
+    uint64_t *, const char *);
+static int guid_to_name(libzfs_handle_t *, const char *,
+    uint64_t, boolean_t, char *);
+
+static const zio_cksum_t zero_cksum = { { 0 } };
+
+typedef struct dedup_arg {
+       int     inputfd;
+       int     outputfd;
+       libzfs_handle_t  *dedup_hdl;
+} dedup_arg_t;
+
+typedef struct progress_arg {
+       zfs_handle_t *pa_zhp;
+       int pa_fd;
+       boolean_t pa_parsable;
+} progress_arg_t;
+
+typedef struct dataref {
+       uint64_t ref_guid;
+       uint64_t ref_object;
+       uint64_t ref_offset;
+} dataref_t;
+
+typedef struct dedup_entry {
+       struct dedup_entry      *dde_next;
+       zio_cksum_t dde_chksum;
+       uint64_t dde_prop;
+       dataref_t dde_ref;
+} dedup_entry_t;
+
+#define        MAX_DDT_PHYSMEM_PERCENT         20
+#define        SMALLEST_POSSIBLE_MAX_DDT_MB            128
+
+typedef struct dedup_table {
+       dedup_entry_t   **dedup_hash_array;
+       umem_cache_t    *ddecache;
+       uint64_t        max_ddt_size;  /* max dedup table size in bytes */
+       uint64_t        cur_ddt_size;  /* current dedup table size in bytes */
+       uint64_t        ddt_count;
+       int             numhashbits;
+       boolean_t       ddt_full;
+} dedup_table_t;
+
+static int
+high_order_bit(uint64_t n)
+{
+       int count;
+
+       for (count = 0; n != 0; count++)
+               n >>= 1;
+       return (count);
+}
+
+static size_t
+ssread(void *buf, size_t len, FILE *stream)
+{
+       size_t outlen;
+
+       if ((outlen = fread(buf, len, 1, stream)) == 0)
+               return (0);
+
+       return (outlen);
+}
+
+static void
+ddt_hash_append(libzfs_handle_t *hdl, dedup_table_t *ddt, dedup_entry_t **ddepp,
+    zio_cksum_t *cs, uint64_t prop, dataref_t *dr)
+{
+       dedup_entry_t   *dde;
+
+       if (ddt->cur_ddt_size >= ddt->max_ddt_size) {
+               if (ddt->ddt_full == B_FALSE) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "Dedup table full.  Deduplication will continue "
+                           "with existing table entries"));
+                       ddt->ddt_full = B_TRUE;
+               }
+               return;
+       }
+
+       if ((dde = umem_cache_alloc(ddt->ddecache, UMEM_DEFAULT))
+           != NULL) {
+               assert(*ddepp == NULL);
+               dde->dde_next = NULL;
+               dde->dde_chksum = *cs;
+               dde->dde_prop = prop;
+               dde->dde_ref = *dr;
+               *ddepp = dde;
+               ddt->cur_ddt_size += sizeof (dedup_entry_t);
+               ddt->ddt_count++;
+       }
+}
+
+/*
+ * Using the specified dedup table, do a lookup for an entry with
+ * the checksum cs.  If found, return the block's reference info
+ * in *dr. Otherwise, insert a new entry in the dedup table, using
+ * the reference information specified by *dr.
+ *
+ * return value:  true - entry was found
+ *               false - entry was not found
+ */
+static boolean_t
+ddt_update(libzfs_handle_t *hdl, dedup_table_t *ddt, zio_cksum_t *cs,
+    uint64_t prop, dataref_t *dr)
+{
+       uint32_t hashcode;
+       dedup_entry_t **ddepp;
+
+       hashcode = BF64_GET(cs->zc_word[0], 0, ddt->numhashbits);
+
+       for (ddepp = &(ddt->dedup_hash_array[hashcode]); *ddepp != NULL;
+           ddepp = &((*ddepp)->dde_next)) {
+               if (ZIO_CHECKSUM_EQUAL(((*ddepp)->dde_chksum), *cs) &&
+                   (*ddepp)->dde_prop == prop) {
+                       *dr = (*ddepp)->dde_ref;
+                       return (B_TRUE);
+               }
+       }
+       ddt_hash_append(hdl, ddt, ddepp, cs, prop, dr);
+       return (B_FALSE);
+}
+
+static int
+dump_record(dmu_replay_record_t *drr, void *payload, int payload_len,
+    zio_cksum_t *zc, int outfd)
+{
+       ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+           ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
+       fletcher_4_incremental_native(drr,
+           offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum), zc);
+       if (drr->drr_type != DRR_BEGIN) {
+               ASSERT(ZIO_CHECKSUM_IS_ZERO(&drr->drr_u.
+                   drr_checksum.drr_checksum));
+               drr->drr_u.drr_checksum.drr_checksum = *zc;
+       }
+       fletcher_4_incremental_native(&drr->drr_u.drr_checksum.drr_checksum,
+           sizeof (zio_cksum_t), zc);
+       if (write(outfd, drr, sizeof (*drr)) == -1)
+               return (errno);
+       if (payload_len != 0) {
+               fletcher_4_incremental_native(payload, payload_len, zc);
+               if (write(outfd, payload, payload_len) == -1)
+                       return (errno);
+       }
+       return (0);
+}
+
+/*
+ * This function is started in a separate thread when the dedup option
+ * has been requested.  The main send thread determines the list of
+ * snapshots to be included in the send stream and makes the ioctl calls
+ * for each one.  But instead of having the ioctl send the output to the
+ * the output fd specified by the caller of zfs_send()), the
+ * ioctl is told to direct the output to a pipe, which is read by the
+ * alternate thread running THIS function.  This function does the
+ * dedup'ing by:
+ *  1. building a dedup table (the DDT)
+ *  2. doing checksums on each data block and inserting a record in the DDT
+ *  3. looking for matching checksums, and
+ *  4.  sending a DRR_WRITE_BYREF record instead of a write record whenever
+ *      a duplicate block is found.
+ * The output of this function then goes to the output fd requested
+ * by the caller of zfs_send().
+ */
+static void *
+cksummer(void *arg)
+{
+       dedup_arg_t *dda = arg;
+       char *buf = zfs_alloc(dda->dedup_hdl, SPA_MAXBLOCKSIZE);
+       dmu_replay_record_t thedrr = { 0 };
+       dmu_replay_record_t *drr = &thedrr;
+       FILE *ofp;
+       int outfd;
+       dedup_table_t ddt;
+       zio_cksum_t stream_cksum;
+       uint64_t physmem = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
+       uint64_t numbuckets;
+
+       ddt.max_ddt_size =
+           MAX((physmem * MAX_DDT_PHYSMEM_PERCENT) / 100,
+           SMALLEST_POSSIBLE_MAX_DDT_MB << 20);
+
+       numbuckets = ddt.max_ddt_size / (sizeof (dedup_entry_t));
+
+       /*
+        * numbuckets must be a power of 2.  Increase number to
+        * a power of 2 if necessary.
+        */
+       if (!ISP2(numbuckets))
+               numbuckets = 1 << high_order_bit(numbuckets);
+
+       ddt.dedup_hash_array = calloc(numbuckets, sizeof (dedup_entry_t *));
+       ddt.ddecache = umem_cache_create("dde", sizeof (dedup_entry_t), 0,
+           NULL, NULL, NULL, NULL, NULL, 0);
+       ddt.cur_ddt_size = numbuckets * sizeof (dedup_entry_t *);
+       ddt.numhashbits = high_order_bit(numbuckets) - 1;
+       ddt.ddt_full = B_FALSE;
+
+       outfd = dda->outputfd;
+       ofp = fdopen(dda->inputfd, "r");
+       while (ssread(drr, sizeof (*drr), ofp) != 0) {
+
+               switch (drr->drr_type) {
+               case DRR_BEGIN:
+               {
+                       struct drr_begin *drrb = &drr->drr_u.drr_begin;
+                       int fflags;
+                       int sz = 0;
+                       ZIO_SET_CHECKSUM(&stream_cksum, 0, 0, 0, 0);
+
+                       ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
+
+                       /* set the DEDUP feature flag for this stream */
+                       fflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+                       fflags |= (DMU_BACKUP_FEATURE_DEDUP |
+                           DMU_BACKUP_FEATURE_DEDUPPROPS);
+                       DMU_SET_FEATUREFLAGS(drrb->drr_versioninfo, fflags);
+
+                       if (drr->drr_payloadlen != 0) {
+                               sz = drr->drr_payloadlen;
+
+                               if (sz > SPA_MAXBLOCKSIZE) {
+                                       buf = zfs_realloc(dda->dedup_hdl, buf,
+                                           SPA_MAXBLOCKSIZE, sz);
+                               }
+                               (void) ssread(buf, sz, ofp);
+                               if (ferror(stdin))
+                                       perror("fread");
+                       }
+                       if (dump_record(drr, buf, sz, &stream_cksum,
+                           outfd) != 0)
+                               goto out;
+                       break;
+               }
+
+               case DRR_END:
+               {
+                       struct drr_end *drre = &drr->drr_u.drr_end;
+                       /* use the recalculated checksum */
+                       drre->drr_checksum = stream_cksum;
+                       if (dump_record(drr, NULL, 0, &stream_cksum,
+                           outfd) != 0)
+                               goto out;
+                       break;
+               }
+
+               case DRR_OBJECT:
+               {
+                       struct drr_object *drro = &drr->drr_u.drr_object;
+                       if (drro->drr_bonuslen > 0) {
+                               (void) ssread(buf,
+                                   P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
+                                   ofp);
+                       }
+                       if (dump_record(drr, buf,
+                           P2ROUNDUP((uint64_t)drro->drr_bonuslen, 8),
+                           &stream_cksum, outfd) != 0)
+                               goto out;
+                       break;
+               }
+
+               case DRR_SPILL:
+               {
+                       struct drr_spill *drrs = &drr->drr_u.drr_spill;
+                       (void) ssread(buf, drrs->drr_length, ofp);
+                       if (dump_record(drr, buf, drrs->drr_length,
+                           &stream_cksum, outfd) != 0)
+                               goto out;
+                       break;
+               }
+
+               case DRR_FREEOBJECTS:
+               {
+                       if (dump_record(drr, NULL, 0, &stream_cksum,
+                           outfd) != 0)
+                               goto out;
+                       break;
+               }
+
+               case DRR_WRITE:
+               {
+                       struct drr_write *drrw = &drr->drr_u.drr_write;
+                       dataref_t       dataref;
+                       uint64_t        payload_size;
+
+                       payload_size = DRR_WRITE_PAYLOAD_SIZE(drrw);
+                       (void) ssread(buf, payload_size, ofp);
+
+                       /*
+                        * Use the existing checksum if it's dedup-capable,
+                        * else calculate a SHA256 checksum for it.
+                        */
+
+                       if (ZIO_CHECKSUM_EQUAL(drrw->drr_key.ddk_cksum,
+                           zero_cksum) ||
+                           !DRR_IS_DEDUP_CAPABLE(drrw->drr_checksumflags)) {
+                               SHA256_CTX ctx;
+                               zio_cksum_t tmpsha256;
+
+                               zio_checksum_SHA256(buf,
+                                   payload_size, &ctx, &tmpsha256);
+
+                               drrw->drr_key.ddk_cksum.zc_word[0] =
+                                   BE_64(tmpsha256.zc_word[0]);
+                               drrw->drr_key.ddk_cksum.zc_word[1] =
+                                   BE_64(tmpsha256.zc_word[1]);
+                               drrw->drr_key.ddk_cksum.zc_word[2] =
+                                   BE_64(tmpsha256.zc_word[2]);
+                               drrw->drr_key.ddk_cksum.zc_word[3] =
+                                   BE_64(tmpsha256.zc_word[3]);
+                               drrw->drr_checksumtype = ZIO_CHECKSUM_SHA256;
+                               drrw->drr_checksumflags = DRR_CHECKSUM_DEDUP;
+                       }
+
+                       dataref.ref_guid = drrw->drr_toguid;
+                       dataref.ref_object = drrw->drr_object;
+                       dataref.ref_offset = drrw->drr_offset;
+
+                       if (ddt_update(dda->dedup_hdl, &ddt,
+                           &drrw->drr_key.ddk_cksum, drrw->drr_key.ddk_prop,
+                           &dataref)) {
+                               dmu_replay_record_t wbr_drr = {0};
+                               struct drr_write_byref *wbr_drrr =
+                                   &wbr_drr.drr_u.drr_write_byref;
+
+                               /* block already present in stream */
+                               wbr_drr.drr_type = DRR_WRITE_BYREF;
+
+                               wbr_drrr->drr_object = drrw->drr_object;
+                               wbr_drrr->drr_offset = drrw->drr_offset;
+                               wbr_drrr->drr_length = drrw->drr_logical_size;
+                               wbr_drrr->drr_toguid = drrw->drr_toguid;
+                               wbr_drrr->drr_refguid = dataref.ref_guid;
+                               wbr_drrr->drr_refobject =
+                                   dataref.ref_object;
+                               wbr_drrr->drr_refoffset =
+                                   dataref.ref_offset;
+
+                               wbr_drrr->drr_checksumtype =
+                                   drrw->drr_checksumtype;
+                               wbr_drrr->drr_checksumflags =
+                                   drrw->drr_checksumtype;
+                               wbr_drrr->drr_key.ddk_cksum =
+                                   drrw->drr_key.ddk_cksum;
+                               wbr_drrr->drr_key.ddk_prop =
+                                   drrw->drr_key.ddk_prop;
+
+                               if (dump_record(&wbr_drr, NULL, 0,
+                                   &stream_cksum, outfd) != 0)
+                                       goto out;
+                       } else {
+                               /* block not previously seen */
+                               if (dump_record(drr, buf, payload_size,
+                                   &stream_cksum, outfd) != 0)
+                                       goto out;
+                       }
+                       break;
+               }
+
+               case DRR_WRITE_EMBEDDED:
+               {
+                       struct drr_write_embedded *drrwe =
+                           &drr->drr_u.drr_write_embedded;
+                       (void) ssread(buf,
+                           P2ROUNDUP((uint64_t)drrwe->drr_psize, 8), ofp);
+                       if (dump_record(drr, buf,
+                           P2ROUNDUP((uint64_t)drrwe->drr_psize, 8),
+                           &stream_cksum, outfd) != 0)
+                               goto out;
+                       break;
+               }
+
+               case DRR_FREE:
+               {
+                       if (dump_record(drr, NULL, 0, &stream_cksum,
+                           outfd) != 0)
+                               goto out;
+                       break;
+               }
+
+               default:
+                       (void) fprintf(stderr, "INVALID record type 0x%x\n",
+                           drr->drr_type);
+                       /* should never happen, so assert */
+                       assert(B_FALSE);
+               }
+       }
+out:
+       umem_cache_destroy(ddt.ddecache);
+       free(ddt.dedup_hash_array);
+       free(buf);
+       (void) fclose(ofp);
+
+       return (NULL);
+}
+
+/*
+ * Routines for dealing with the AVL tree of fs-nvlists
+ */
+typedef struct fsavl_node {
+       avl_node_t fn_node;
+       nvlist_t *fn_nvfs;
+       char *fn_snapname;
+       uint64_t fn_guid;
+} fsavl_node_t;
+
+static int
+fsavl_compare(const void *arg1, const void *arg2)
+{
+       const fsavl_node_t *fn1 = (const fsavl_node_t *)arg1;
+       const fsavl_node_t *fn2 = (const fsavl_node_t *)arg2;
+
+       return (AVL_CMP(fn1->fn_guid, fn2->fn_guid));
+}
+
+/*
+ * Given the GUID of a snapshot, find its containing filesystem and
+ * (optionally) name.
+ */
+static nvlist_t *
+fsavl_find(avl_tree_t *avl, uint64_t snapguid, char **snapname)
+{
+       fsavl_node_t fn_find;
+       fsavl_node_t *fn;
+
+       fn_find.fn_guid = snapguid;
+
+       fn = avl_find(avl, &fn_find, NULL);
+       if (fn) {
+               if (snapname)
+                       *snapname = fn->fn_snapname;
+               return (fn->fn_nvfs);
+       }
+       return (NULL);
+}
+
+static void
+fsavl_destroy(avl_tree_t *avl)
+{
+       fsavl_node_t *fn;
+       void *cookie;
+
+       if (avl == NULL)
+               return;
+
+       cookie = NULL;
+       while ((fn = avl_destroy_nodes(avl, &cookie)) != NULL)
+               free(fn);
+       avl_destroy(avl);
+       free(avl);
+}
+
+/*
+ * Given an nvlist, produce an avl tree of snapshots, ordered by guid
+ */
+static avl_tree_t *
+fsavl_create(nvlist_t *fss)
+{
+       avl_tree_t *fsavl;
+       nvpair_t *fselem = NULL;
+
+       if ((fsavl = malloc(sizeof (avl_tree_t))) == NULL)
+               return (NULL);
+
+       avl_create(fsavl, fsavl_compare, sizeof (fsavl_node_t),
+           offsetof(fsavl_node_t, fn_node));
+
+       while ((fselem = nvlist_next_nvpair(fss, fselem)) != NULL) {
+               nvlist_t *nvfs, *snaps;
+               nvpair_t *snapelem = NULL;
+
+               VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs));
+               VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps));
+
+               while ((snapelem =
+                   nvlist_next_nvpair(snaps, snapelem)) != NULL) {
+                       fsavl_node_t *fn;
+                       uint64_t guid;
+
+                       VERIFY(0 == nvpair_value_uint64(snapelem, &guid));
+                       if ((fn = malloc(sizeof (fsavl_node_t))) == NULL) {
+                               fsavl_destroy(fsavl);
+                               return (NULL);
+                       }
+                       fn->fn_nvfs = nvfs;
+                       fn->fn_snapname = nvpair_name(snapelem);
+                       fn->fn_guid = guid;
+
+                       /*
+                        * Note: if there are multiple snaps with the
+                        * same GUID, we ignore all but one.
+                        */
+                       if (avl_find(fsavl, fn, NULL) == NULL)
+                               avl_add(fsavl, fn);
+                       else
+                               free(fn);
+               }
+       }
+
+       return (fsavl);
+}
+
+/*
+ * Routines for dealing with the giant nvlist of fs-nvlists, etc.
+ */
+typedef struct send_data {
+       /*
+        * assigned inside every recursive call,
+        * restored from *_save on return:
+        *
+        * guid of fromsnap snapshot in parent dataset
+        * txg of fromsnap snapshot in current dataset
+        * txg of tosnap snapshot in current dataset
+        */
+
+       uint64_t parent_fromsnap_guid;
+       uint64_t fromsnap_txg;
+       uint64_t tosnap_txg;
+
+       /* the nvlists get accumulated during depth-first traversal */
+       nvlist_t *parent_snaps;
+       nvlist_t *fss;
+       nvlist_t *snapprops;
+
+       /* send-receive configuration, does not change during traversal */
+       const char *fsname;
+       const char *fromsnap;
+       const char *tosnap;
+       boolean_t recursive;
+       boolean_t verbose;
+       boolean_t seenfrom;
+       boolean_t seento;
+
+       /*
+        * The header nvlist is of the following format:
+        * {
+        *   "tosnap" -> string
+        *   "fromsnap" -> string (if incremental)
+        *   "fss" -> {
+        *      id -> {
+        *
+        *       "name" -> string (full name; for debugging)
+        *       "parentfromsnap" -> number (guid of fromsnap in parent)
+        *
+        *       "props" -> { name -> value (only if set here) }
+        *       "snaps" -> { name (lastname) -> number (guid) }
+        *       "snapprops" -> { name (lastname) -> { name -> value } }
+        *
+        *       "origin" -> number (guid) (if clone)
+        *       "sent" -> boolean (not on-disk)
+        *      }
+        *   }
+        * }
+        *
+        */
+} send_data_t;
+
+static void send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv);
+
+static int
+send_iterate_snap(zfs_handle_t *zhp, void *arg)
+{
+       send_data_t *sd = arg;
+       uint64_t guid = zhp->zfs_dmustats.dds_guid;
+       uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;
+       char *snapname;
+       nvlist_t *nv;
+       boolean_t isfromsnap, istosnap, istosnapwithnofrom;
+
+       snapname = strrchr(zhp->zfs_name, '@')+1;
+       isfromsnap = (sd->fromsnap != NULL &&
+           strcmp(sd->fromsnap, snapname) == 0);
+       istosnap = (sd->tosnap != NULL && (strcmp(sd->tosnap, snapname) == 0));
+       istosnapwithnofrom = (istosnap && sd->fromsnap == NULL);
+
+       if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
+               if (sd->verbose) {
+                       (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                           "skipping snapshot %s because it was created "
+                           "after the destination snapshot (%s)\n"),
+                           zhp->zfs_name, sd->tosnap);
+               }
+               zfs_close(zhp);
+               return (0);
+       }
+
+       VERIFY(0 == nvlist_add_uint64(sd->parent_snaps, snapname, guid));
+       /*
+        * NB: if there is no fromsnap here (it's a newly created fs in
+        * an incremental replication), we will substitute the tosnap.
+        */
+       if (isfromsnap || (sd->parent_fromsnap_guid == 0 && istosnap)) {
+               sd->parent_fromsnap_guid = guid;
+       }
+
+       if (!sd->recursive) {
+               if (!sd->seenfrom && isfromsnap) {
+                       sd->seenfrom = B_TRUE;
+                       zfs_close(zhp);
+                       return (0);
+               }
+
+               if ((sd->seento || !sd->seenfrom) && !istosnapwithnofrom) {
+                       zfs_close(zhp);
+                       return (0);
+               }
+
+               if (istosnap)
+                       sd->seento = B_TRUE;
+       }
+
+       VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
+       send_iterate_prop(zhp, nv);
+       VERIFY(0 == nvlist_add_nvlist(sd->snapprops, snapname, nv));
+       nvlist_free(nv);
+
+       zfs_close(zhp);
+       return (0);
+}
+
+static void
+send_iterate_prop(zfs_handle_t *zhp, nvlist_t *nv)
+{
+       nvpair_t *elem = NULL;
+
+       while ((elem = nvlist_next_nvpair(zhp->zfs_props, elem)) != NULL) {
+               char *propname = nvpair_name(elem);
+               zfs_prop_t prop = zfs_name_to_prop(propname);
+               nvlist_t *propnv;
+
+               if (!zfs_prop_user(propname)) {
+                       /*
+                        * Realistically, this should never happen.  However,
+                        * we want the ability to add DSL properties without
+                        * needing to make incompatible version changes.  We
+                        * need to ignore unknown properties to allow older
+                        * software to still send datasets containing these
+                        * properties, with the unknown properties elided.
+                        */
+                       if (prop == ZPROP_INVAL)
+                               continue;
+
+                       if (zfs_prop_readonly(prop))
+                               continue;
+               }
+
+               verify(nvpair_value_nvlist(elem, &propnv) == 0);
+               if (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_RESERVATION ||
+                   prop == ZFS_PROP_REFQUOTA ||
+                   prop == ZFS_PROP_REFRESERVATION) {
+                       char *source;
+                       uint64_t value;
+                       verify(nvlist_lookup_uint64(propnv,
+                           ZPROP_VALUE, &value) == 0);
+                       if (zhp->zfs_type == ZFS_TYPE_SNAPSHOT)
+                               continue;
+                       /*
+                        * May have no source before SPA_VERSION_RECVD_PROPS,
+                        * but is still modifiable.
+                        */
+                       if (nvlist_lookup_string(propnv,
+                           ZPROP_SOURCE, &source) == 0) {
+                               if ((strcmp(source, zhp->zfs_name) != 0) &&
+                                   (strcmp(source,
+                                   ZPROP_SOURCE_VAL_RECVD) != 0))
+                                       continue;
+                       }
+               } else {
+                       char *source;
+                       if (nvlist_lookup_string(propnv,
+                           ZPROP_SOURCE, &source) != 0)
+                               continue;
+                       if ((strcmp(source, zhp->zfs_name) != 0) &&
+                           (strcmp(source, ZPROP_SOURCE_VAL_RECVD) != 0))
+                               continue;
+               }
+
+               if (zfs_prop_user(propname) ||
+                   zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
+                       char *value;
+                       verify(nvlist_lookup_string(propnv,
+                           ZPROP_VALUE, &value) == 0);
+                       VERIFY(0 == nvlist_add_string(nv, propname, value));
+               } else {
+                       uint64_t value;
+                       verify(nvlist_lookup_uint64(propnv,
+                           ZPROP_VALUE, &value) == 0);
+                       VERIFY(0 == nvlist_add_uint64(nv, propname, value));
+               }
+       }
+}
+
+/*
+ * returns snapshot creation txg
+ * and returns 0 if the snapshot does not exist
+ */
+static uint64_t
+get_snap_txg(libzfs_handle_t *hdl, const char *fs, const char *snap)
+{
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       uint64_t txg = 0;
+
+       if (fs == NULL || fs[0] == '\0' || snap == NULL || snap[0] == '\0')
+               return (txg);
+
+       (void) snprintf(name, sizeof (name), "%s@%s", fs, snap);
+       if (zfs_dataset_exists(hdl, name, ZFS_TYPE_SNAPSHOT)) {
+               zfs_handle_t *zhp = zfs_open(hdl, name, ZFS_TYPE_SNAPSHOT);
+               if (zhp != NULL) {
+                       txg = zfs_prop_get_int(zhp, ZFS_PROP_CREATETXG);
+                       zfs_close(zhp);
+               }
+       }
+
+       return (txg);
+}
+
+/*
+ * recursively generate nvlists describing datasets.  See comment
+ * for the data structure send_data_t above for description of contents
+ * of the nvlist.
+ */
+static int
+send_iterate_fs(zfs_handle_t *zhp, void *arg)
+{
+       send_data_t *sd = arg;
+       nvlist_t *nvfs, *nv;
+       int rv = 0;
+       uint64_t parent_fromsnap_guid_save = sd->parent_fromsnap_guid;
+       uint64_t fromsnap_txg_save = sd->fromsnap_txg;
+       uint64_t tosnap_txg_save = sd->tosnap_txg;
+       uint64_t txg = zhp->zfs_dmustats.dds_creation_txg;
+       uint64_t guid = zhp->zfs_dmustats.dds_guid;
+       uint64_t fromsnap_txg, tosnap_txg;
+       char guidstring[64];
+
+       fromsnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->fromsnap);
+       if (fromsnap_txg != 0)
+               sd->fromsnap_txg = fromsnap_txg;
+
+       tosnap_txg = get_snap_txg(zhp->zfs_hdl, zhp->zfs_name, sd->tosnap);
+       if (tosnap_txg != 0)
+               sd->tosnap_txg = tosnap_txg;
+
+       /*
+        * on the send side, if the current dataset does not have tosnap,
+        * perform two additional checks:
+        *
+        * - skip sending the current dataset if it was created later than
+        *   the parent tosnap
+        * - return error if the current dataset was created earlier than
+        *   the parent tosnap
+        */
+       if (sd->tosnap != NULL && tosnap_txg == 0) {
+               if (sd->tosnap_txg != 0 && txg > sd->tosnap_txg) {
+                       if (sd->verbose) {
+                               (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                                   "skipping dataset %s: snapshot %s does "
+                                   "not exist\n"), zhp->zfs_name, sd->tosnap);
+                       }
+               } else {
+                       (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                           "cannot send %s@%s%s: snapshot %s@%s does not "
+                           "exist\n"), sd->fsname, sd->tosnap, sd->recursive ?
+                           dgettext(TEXT_DOMAIN, " recursively") : "",
+                           zhp->zfs_name, sd->tosnap);
+                       rv = -1;
+               }
+               goto out;
+       }
+
+       VERIFY(0 == nvlist_alloc(&nvfs, NV_UNIQUE_NAME, 0));
+       VERIFY(0 == nvlist_add_string(nvfs, "name", zhp->zfs_name));
+       VERIFY(0 == nvlist_add_uint64(nvfs, "parentfromsnap",
+           sd->parent_fromsnap_guid));
+
+       if (zhp->zfs_dmustats.dds_origin[0]) {
+               zfs_handle_t *origin = zfs_open(zhp->zfs_hdl,
+                   zhp->zfs_dmustats.dds_origin, ZFS_TYPE_SNAPSHOT);
+               if (origin == NULL) {
+                       rv = -1;
+                       goto out;
+               }
+               VERIFY(0 == nvlist_add_uint64(nvfs, "origin",
+                   origin->zfs_dmustats.dds_guid));
+       }
+
+       /* iterate over props */
+       VERIFY(0 == nvlist_alloc(&nv, NV_UNIQUE_NAME, 0));
+       send_iterate_prop(zhp, nv);
+       VERIFY(0 == nvlist_add_nvlist(nvfs, "props", nv));
+       nvlist_free(nv);
+
+       /* iterate over snaps, and set sd->parent_fromsnap_guid */
+       sd->parent_fromsnap_guid = 0;
+       VERIFY(0 == nvlist_alloc(&sd->parent_snaps, NV_UNIQUE_NAME, 0));
+       VERIFY(0 == nvlist_alloc(&sd->snapprops, NV_UNIQUE_NAME, 0));
+       (void) zfs_iter_snapshots_sorted(zhp, send_iterate_snap, sd);
+       VERIFY(0 == nvlist_add_nvlist(nvfs, "snaps", sd->parent_snaps));
+       VERIFY(0 == nvlist_add_nvlist(nvfs, "snapprops", sd->snapprops));
+       nvlist_free(sd->parent_snaps);
+       nvlist_free(sd->snapprops);
+
+       /* add this fs to nvlist */
+       (void) snprintf(guidstring, sizeof (guidstring),
+           "0x%llx", (longlong_t)guid);
+       VERIFY(0 == nvlist_add_nvlist(sd->fss, guidstring, nvfs));
+       nvlist_free(nvfs);
+
+       /* iterate over children */
+       if (sd->recursive)
+               rv = zfs_iter_filesystems(zhp, send_iterate_fs, sd);
+
+out:
+       sd->parent_fromsnap_guid = parent_fromsnap_guid_save;
+       sd->fromsnap_txg = fromsnap_txg_save;
+       sd->tosnap_txg = tosnap_txg_save;
+
+       zfs_close(zhp);
+       return (rv);
+}
+
+static int
+gather_nvlist(libzfs_handle_t *hdl, const char *fsname, const char *fromsnap,
+    const char *tosnap, boolean_t recursive, boolean_t verbose,
+    nvlist_t **nvlp, avl_tree_t **avlp)
+{
+       zfs_handle_t *zhp;
+       send_data_t sd = { 0 };
+       int error;
+
+       zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+       if (zhp == NULL)
+               return (EZFS_BADTYPE);
+
+       VERIFY(0 == nvlist_alloc(&sd.fss, NV_UNIQUE_NAME, 0));
+       sd.fsname = fsname;
+       sd.fromsnap = fromsnap;
+       sd.tosnap = tosnap;
+       sd.recursive = recursive;
+       sd.verbose = verbose;
+
+       if ((error = send_iterate_fs(zhp, &sd)) != 0) {
+               nvlist_free(sd.fss);
+               if (avlp != NULL)
+                       *avlp = NULL;
+               *nvlp = NULL;
+               return (error);
+       }
+
+       if (avlp != NULL && (*avlp = fsavl_create(sd.fss)) == NULL) {
+               nvlist_free(sd.fss);
+               *nvlp = NULL;
+               return (EZFS_NOMEM);
+       }
+
+       *nvlp = sd.fss;
+       return (0);
+}
+
+/*
+ * Routines specific to "zfs send"
+ */
+typedef struct send_dump_data {
+       /* these are all just the short snapname (the part after the @) */
+       const char *fromsnap;
+       const char *tosnap;
+       char prevsnap[ZFS_MAX_DATASET_NAME_LEN];
+       uint64_t prevsnap_obj;
+       boolean_t seenfrom, seento, replicate, doall, fromorigin;
+       boolean_t verbose, dryrun, parsable, progress, embed_data, std_out;
+       boolean_t large_block, compress;
+       int outfd;
+       boolean_t err;
+       nvlist_t *fss;
+       nvlist_t *snapholds;
+       avl_tree_t *fsavl;
+       snapfilter_cb_t *filter_cb;
+       void *filter_cb_arg;
+       nvlist_t *debugnv;
+       char holdtag[ZFS_MAX_DATASET_NAME_LEN];
+       int cleanup_fd;
+       uint64_t size;
+} send_dump_data_t;
+
+static int
+estimate_ioctl(zfs_handle_t *zhp, uint64_t fromsnap_obj,
+    boolean_t fromorigin, enum lzc_send_flags flags, uint64_t *sizep)
+{
+       zfs_cmd_t zc = {"\0"};
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+       assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+       assert(fromsnap_obj == 0 || !fromorigin);
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+       zc.zc_obj = fromorigin;
+       zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
+       zc.zc_fromobj = fromsnap_obj;
+       zc.zc_guid = 1;  /* estimate flag */
+       zc.zc_flags = flags;
+
+       if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
+               char errbuf[1024];
+               (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+                   "warning: cannot estimate space for '%s'"), zhp->zfs_name);
+
+               switch (errno) {
+               case EXDEV:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "not an earlier snapshot from the same fs"));
+                       return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+               case ENOENT:
+                       if (zfs_dataset_exists(hdl, zc.zc_name,
+                           ZFS_TYPE_SNAPSHOT)) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "incremental source (@%s) does not exist"),
+                                   zc.zc_value);
+                       }
+                       return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+               case EDQUOT:
+               case EFBIG:
+               case EIO:
+               case ENOLINK:
+               case ENOSPC:
+               case ENOSTR:
+               case ENXIO:
+               case EPIPE:
+               case ERANGE:
+               case EFAULT:
+               case EROFS:
+                       zfs_error_aux(hdl, strerror(errno));
+                       return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+               default:
+                       return (zfs_standard_error(hdl, errno, errbuf));
+               }
+       }
+
+       *sizep = zc.zc_objset_type;
+
+       return (0);
+}
+
+/*
+ * Dumps a backup of the given snapshot (incremental from fromsnap if it's not
+ * NULL) to the file descriptor specified by outfd.
+ */
+static int
+dump_ioctl(zfs_handle_t *zhp, const char *fromsnap, uint64_t fromsnap_obj,
+    boolean_t fromorigin, int outfd, enum lzc_send_flags flags,
+    nvlist_t *debugnv)
+{
+       zfs_cmd_t zc = {"\0"};
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       nvlist_t *thisdbg;
+
+       assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+       assert(fromsnap_obj == 0 || !fromorigin);
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+       zc.zc_cookie = outfd;
+       zc.zc_obj = fromorigin;
+       zc.zc_sendobj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
+       zc.zc_fromobj = fromsnap_obj;
+       zc.zc_flags = flags;
+
+       VERIFY(0 == nvlist_alloc(&thisdbg, NV_UNIQUE_NAME, 0));
+       if (fromsnap && fromsnap[0] != '\0') {
+               VERIFY(0 == nvlist_add_string(thisdbg,
+                   "fromsnap", fromsnap));
+       }
+
+       if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_SEND, &zc) != 0) {
+               char errbuf[1024];
+               (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+                   "warning: cannot send '%s'"), zhp->zfs_name);
+
+               VERIFY(0 == nvlist_add_uint64(thisdbg, "error", errno));
+               if (debugnv) {
+                       VERIFY(0 == nvlist_add_nvlist(debugnv,
+                           zhp->zfs_name, thisdbg));
+               }
+               nvlist_free(thisdbg);
+
+               switch (errno) {
+               case EXDEV:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "not an earlier snapshot from the same fs"));
+                       return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+               case ENOENT:
+                       if (zfs_dataset_exists(hdl, zc.zc_name,
+                           ZFS_TYPE_SNAPSHOT)) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "incremental source (@%s) does not exist"),
+                                   zc.zc_value);
+                       }
+                       return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+               case EDQUOT:
+               case EFBIG:
+               case EIO:
+               case ENOLINK:
+               case ENOSPC:
+               case ENOSTR:
+               case ENXIO:
+               case EPIPE:
+               case ERANGE:
+               case EFAULT:
+               case EROFS:
+                       zfs_error_aux(hdl, strerror(errno));
+                       return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+               default:
+                       return (zfs_standard_error(hdl, errno, errbuf));
+               }
+       }
+
+       if (debugnv)
+               VERIFY(0 == nvlist_add_nvlist(debugnv, zhp->zfs_name, thisdbg));
+       nvlist_free(thisdbg);
+
+       return (0);
+}
+
+static void
+gather_holds(zfs_handle_t *zhp, send_dump_data_t *sdd)
+{
+       assert(zhp->zfs_type == ZFS_TYPE_SNAPSHOT);
+
+       /*
+        * zfs_send() only sets snapholds for sends that need them,
+        * e.g. replication and doall.
+        */
+       if (sdd->snapholds == NULL)
+               return;
+
+       fnvlist_add_string(sdd->snapholds, zhp->zfs_name, sdd->holdtag);
+}
+
+static void *
+send_progress_thread(void *arg)
+{
+       progress_arg_t *pa = arg;
+       zfs_cmd_t zc = {"\0"};
+       zfs_handle_t *zhp = pa->pa_zhp;
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+       unsigned long long bytes;
+       char buf[16];
+       time_t t;
+       struct tm *tm;
+
+       (void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+       if (!pa->pa_parsable)
+               (void) fprintf(stderr, "TIME        SENT   SNAPSHOT\n");
+
+       /*
+        * Print the progress from ZFS_IOC_SEND_PROGRESS every second.
+        */
+       for (;;) {
+               (void) sleep(1);
+
+               zc.zc_cookie = pa->pa_fd;
+               if (zfs_ioctl(hdl, ZFS_IOC_SEND_PROGRESS, &zc) != 0)
+                       return ((void *)-1);
+
+               (void) time(&t);
+               tm = localtime(&t);
+               bytes = zc.zc_cookie;
+
+               if (pa->pa_parsable) {
+                       (void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n",
+                           tm->tm_hour, tm->tm_min, tm->tm_sec,
+                           bytes, zhp->zfs_name);
+               } else {
+                       zfs_nicenum(bytes, buf, sizeof (buf));
+                       (void) fprintf(stderr, "%02d:%02d:%02d   %5s   %s\n",
+                           tm->tm_hour, tm->tm_min, tm->tm_sec,
+                           buf, zhp->zfs_name);
+               }
+       }
+}
+
+static void
+send_print_verbose(FILE *fout, const char *tosnap, const char *fromsnap,
+    uint64_t size, boolean_t parsable)
+{
+       if (parsable) {
+               if (fromsnap != NULL) {
+                       (void) fprintf(fout, "incremental\t%s\t%s",
+                           fromsnap, tosnap);
+               } else {
+                       (void) fprintf(fout, "full\t%s",
+                           tosnap);
+               }
+       } else {
+               if (fromsnap != NULL) {
+                       if (strchr(fromsnap, '@') == NULL &&
+                           strchr(fromsnap, '#') == NULL) {
+                               (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+                                   "send from @%s to %s"),
+                                   fromsnap, tosnap);
+                       } else {
+                               (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+                                   "send from %s to %s"),
+                                   fromsnap, tosnap);
+                       }
+               } else {
+                       (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+                           "full send of %s"),
+                           tosnap);
+               }
+       }
+
+       if (size != 0) {
+               if (parsable) {
+                       (void) fprintf(fout, "\t%llu",
+                           (longlong_t)size);
+               } else {
+                       char buf[16];
+                       zfs_nicenum(size, buf, sizeof (buf));
+                       (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+                           " estimated size is %s"), buf);
+               }
+       }
+       (void) fprintf(fout, "\n");
+}
+
+static int
+dump_snapshot(zfs_handle_t *zhp, void *arg)
+{
+       send_dump_data_t *sdd = arg;
+       progress_arg_t pa = { 0 };
+       pthread_t tid;
+       char *thissnap;
+       enum lzc_send_flags flags = 0;
+       int err;
+       boolean_t isfromsnap, istosnap, fromorigin;
+       boolean_t exclude = B_FALSE;
+       FILE *fout = sdd->std_out ? stdout : stderr;
+
+       err = 0;
+       thissnap = strchr(zhp->zfs_name, '@') + 1;
+       isfromsnap = (sdd->fromsnap != NULL &&
+           strcmp(sdd->fromsnap, thissnap) == 0);
+
+       if (!sdd->seenfrom && isfromsnap) {
+               gather_holds(zhp, sdd);
+               sdd->seenfrom = B_TRUE;
+               (void) strlcpy(sdd->prevsnap, thissnap,
+                   sizeof (sdd->prevsnap));
+               sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if (sdd->seento || !sdd->seenfrom) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       istosnap = (strcmp(sdd->tosnap, thissnap) == 0);
+       if (istosnap)
+               sdd->seento = B_TRUE;
+
+       if (sdd->large_block)
+               flags |= LZC_SEND_FLAG_LARGE_BLOCK;
+       if (sdd->embed_data)
+               flags |= LZC_SEND_FLAG_EMBED_DATA;
+       if (sdd->compress)
+               flags |= LZC_SEND_FLAG_COMPRESS;
+
+       if (!sdd->doall && !isfromsnap && !istosnap) {
+               if (sdd->replicate) {
+                       char *snapname;
+                       nvlist_t *snapprops;
+                       /*
+                        * Filter out all intermediate snapshots except origin
+                        * snapshots needed to replicate clones.
+                        */
+                       nvlist_t *nvfs = fsavl_find(sdd->fsavl,
+                           zhp->zfs_dmustats.dds_guid, &snapname);
+
+                       VERIFY(0 == nvlist_lookup_nvlist(nvfs,
+                           "snapprops", &snapprops));
+                       VERIFY(0 == nvlist_lookup_nvlist(snapprops,
+                           thissnap, &snapprops));
+                       exclude = !nvlist_exists(snapprops, "is_clone_origin");
+               } else {
+                       exclude = B_TRUE;
+               }
+       }
+
+       /*
+        * If a filter function exists, call it to determine whether
+        * this snapshot will be sent.
+        */
+       if (exclude || (sdd->filter_cb != NULL &&
+           sdd->filter_cb(zhp, sdd->filter_cb_arg) == B_FALSE)) {
+               /*
+                * This snapshot is filtered out.  Don't send it, and don't
+                * set prevsnap_obj, so it will be as if this snapshot didn't
+                * exist, and the next accepted snapshot will be sent as
+                * an incremental from the last accepted one, or as the
+                * first (and full) snapshot in the case of a replication,
+                * non-incremental send.
+                */
+               zfs_close(zhp);
+               return (0);
+       }
+
+       gather_holds(zhp, sdd);
+       fromorigin = sdd->prevsnap[0] == '\0' &&
+           (sdd->fromorigin || sdd->replicate);
+
+       if (sdd->verbose) {
+               uint64_t size = 0;
+               (void) estimate_ioctl(zhp, sdd->prevsnap_obj,
+                   fromorigin, flags, &size);
+
+               send_print_verbose(fout, zhp->zfs_name,
+                   sdd->prevsnap[0] ? sdd->prevsnap : NULL,
+                   size, sdd->parsable);
+               sdd->size += size;
+       }
+
+       if (!sdd->dryrun) {
+               /*
+                * If progress reporting is requested, spawn a new thread to
+                * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
+                */
+               if (sdd->progress) {
+                       pa.pa_zhp = zhp;
+                       pa.pa_fd = sdd->outfd;
+                       pa.pa_parsable = sdd->parsable;
+
+                       if ((err = pthread_create(&tid, NULL,
+                           send_progress_thread, &pa))) {
+                               zfs_close(zhp);
+                               return (err);
+                       }
+               }
+
+               err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj,
+                   fromorigin, sdd->outfd, flags, sdd->debugnv);
+
+               if (sdd->progress) {
+                       (void) pthread_cancel(tid);
+                       (void) pthread_join(tid, NULL);
+               }
+       }
+
+       (void) strcpy(sdd->prevsnap, thissnap);
+       sdd->prevsnap_obj = zfs_prop_get_int(zhp, ZFS_PROP_OBJSETID);
+       zfs_close(zhp);
+       return (err);
+}
+
+static int
+dump_filesystem(zfs_handle_t *zhp, void *arg)
+{
+       int rv = 0;
+       send_dump_data_t *sdd = arg;
+       boolean_t missingfrom = B_FALSE;
+       zfs_cmd_t zc = {"\0"};
+
+       (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
+           zhp->zfs_name, sdd->tosnap);
+       if (ioctl(zhp->zfs_hdl->libzfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
+               (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                   "WARNING: could not send %s@%s: does not exist\n"),
+                   zhp->zfs_name, sdd->tosnap);
+               sdd->err = B_TRUE;
+               return (0);
+       }
+
+       if (sdd->replicate && sdd->fromsnap) {
+               /*
+                * If this fs does not have fromsnap, and we're doing
+                * recursive, we need to send a full stream from the
+                * beginning (or an incremental from the origin if this
+                * is a clone).  If we're doing non-recursive, then let
+                * them get the error.
+                */
+               (void) snprintf(zc.zc_name, sizeof (zc.zc_name), "%s@%s",
+                   zhp->zfs_name, sdd->fromsnap);
+               if (ioctl(zhp->zfs_hdl->libzfs_fd,
+                   ZFS_IOC_OBJSET_STATS, &zc) != 0) {
+                       missingfrom = B_TRUE;
+               }
+       }
+
+       sdd->seenfrom = sdd->seento = sdd->prevsnap[0] = 0;
+       sdd->prevsnap_obj = 0;
+       if (sdd->fromsnap == NULL || missingfrom)
+               sdd->seenfrom = B_TRUE;
+
+       rv = zfs_iter_snapshots_sorted(zhp, dump_snapshot, arg);
+       if (!sdd->seenfrom) {
+               (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                   "WARNING: could not send %s@%s:\n"
+                   "incremental source (%s@%s) does not exist\n"),
+                   zhp->zfs_name, sdd->tosnap,
+                   zhp->zfs_name, sdd->fromsnap);
+               sdd->err = B_TRUE;
+       } else if (!sdd->seento) {
+               if (sdd->fromsnap) {
+                       (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                           "WARNING: could not send %s@%s:\n"
+                           "incremental source (%s@%s) "
+                           "is not earlier than it\n"),
+                           zhp->zfs_name, sdd->tosnap,
+                           zhp->zfs_name, sdd->fromsnap);
+               } else {
+                       (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                           "WARNING: "
+                           "could not send %s@%s: does not exist\n"),
+                           zhp->zfs_name, sdd->tosnap);
+               }
+               sdd->err = B_TRUE;
+       }
+
+       return (rv);
+}
+
+static int
+dump_filesystems(zfs_handle_t *rzhp, void *arg)
+{
+       send_dump_data_t *sdd = arg;
+       nvpair_t *fspair;
+       boolean_t needagain, progress;
+
+       if (!sdd->replicate)
+               return (dump_filesystem(rzhp, sdd));
+
+       /* Mark the clone origin snapshots. */
+       for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
+           fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
+               nvlist_t *nvfs;
+               uint64_t origin_guid = 0;
+
+               VERIFY(0 == nvpair_value_nvlist(fspair, &nvfs));
+               (void) nvlist_lookup_uint64(nvfs, "origin", &origin_guid);
+               if (origin_guid != 0) {
+                       char *snapname;
+                       nvlist_t *origin_nv = fsavl_find(sdd->fsavl,
+                           origin_guid, &snapname);
+                       if (origin_nv != NULL) {
+                               nvlist_t *snapprops;
+                               VERIFY(0 == nvlist_lookup_nvlist(origin_nv,
+                                   "snapprops", &snapprops));
+                               VERIFY(0 == nvlist_lookup_nvlist(snapprops,
+                                   snapname, &snapprops));
+                               VERIFY(0 == nvlist_add_boolean(
+                                   snapprops, "is_clone_origin"));
+                       }
+               }
+       }
+again:
+       needagain = progress = B_FALSE;
+       for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
+           fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
+               nvlist_t *fslist, *parent_nv;
+               char *fsname;
+               zfs_handle_t *zhp;
+               int err;
+               uint64_t origin_guid = 0;
+               uint64_t parent_guid = 0;
+
+               VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0);
+               if (nvlist_lookup_boolean(fslist, "sent") == 0)
+                       continue;
+
+               VERIFY(nvlist_lookup_string(fslist, "name", &fsname) == 0);
+               (void) nvlist_lookup_uint64(fslist, "origin", &origin_guid);
+               (void) nvlist_lookup_uint64(fslist, "parentfromsnap",
+                   &parent_guid);
+
+               if (parent_guid != 0) {
+                       parent_nv = fsavl_find(sdd->fsavl, parent_guid, NULL);
+                       if (!nvlist_exists(parent_nv, "sent")) {
+                               /* parent has not been sent; skip this one */
+                               needagain = B_TRUE;
+                               continue;
+                       }
+               }
+
+               if (origin_guid != 0) {
+                       nvlist_t *origin_nv = fsavl_find(sdd->fsavl,
+                           origin_guid, NULL);
+                       if (origin_nv != NULL &&
+                           !nvlist_exists(origin_nv, "sent")) {
+                               /*
+                                * origin has not been sent yet;
+                                * skip this clone.
+                                */
+                               needagain = B_TRUE;
+                               continue;
+                       }
+               }
+
+               zhp = zfs_open(rzhp->zfs_hdl, fsname, ZFS_TYPE_DATASET);
+               if (zhp == NULL)
+                       return (-1);
+               err = dump_filesystem(zhp, sdd);
+               VERIFY(nvlist_add_boolean(fslist, "sent") == 0);
+               progress = B_TRUE;
+               zfs_close(zhp);
+               if (err)
+                       return (err);
+       }
+       if (needagain) {
+               assert(progress);
+               goto again;
+       }
+
+       /* clean out the sent flags in case we reuse this fss */
+       for (fspair = nvlist_next_nvpair(sdd->fss, NULL); fspair;
+           fspair = nvlist_next_nvpair(sdd->fss, fspair)) {
+               nvlist_t *fslist;
+
+               VERIFY(nvpair_value_nvlist(fspair, &fslist) == 0);
+               (void) nvlist_remove_all(fslist, "sent");
+       }
+
+       return (0);
+}
+
+nvlist_t *
+zfs_send_resume_token_to_nvlist(libzfs_handle_t *hdl, const char *token)
+{
+       unsigned int version;
+       int nread, i;
+       unsigned long long checksum, packed_len;
+
+       /*
+        * Decode token header, which is:
+        *   <token version>-<checksum of payload>-<uncompressed payload length>
+        * Note that the only supported token version is 1.
+        */
+       nread = sscanf(token, "%u-%llx-%llx-",
+           &version, &checksum, &packed_len);
+       if (nread != 3) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "resume token is corrupt (invalid format)"));
+               return (NULL);
+       }
+
+       if (version != ZFS_SEND_RESUME_TOKEN_VERSION) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "resume token is corrupt (invalid version %u)"),
+                   version);
+               return (NULL);
+       }
+
+       /* convert hexadecimal representation to binary */
+       token = strrchr(token, '-') + 1;
+       int len = strlen(token) / 2;
+       unsigned char *compressed = zfs_alloc(hdl, len);
+       for (i = 0; i < len; i++) {
+               nread = sscanf(token + i * 2, "%2hhx", compressed + i);
+               if (nread != 1) {
+                       free(compressed);
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "resume token is corrupt "
+                           "(payload is not hex-encoded)"));
+                       return (NULL);
+               }
+       }
+
+       /* verify checksum */
+       zio_cksum_t cksum;
+       fletcher_4_native_varsize(compressed, len, &cksum);
+       if (cksum.zc_word[0] != checksum) {
+               free(compressed);
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "resume token is corrupt (incorrect checksum)"));
+               return (NULL);
+       }
+
+       /* uncompress */
+       void *packed = zfs_alloc(hdl, packed_len);
+       uLongf packed_len_long = packed_len;
+       if (uncompress(packed, &packed_len_long, compressed, len) != Z_OK ||
+           packed_len_long != packed_len) {
+               free(packed);
+               free(compressed);
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "resume token is corrupt (decompression failed)"));
+               return (NULL);
+       }
+
+       /* unpack nvlist */
+       nvlist_t *nv;
+       int error = nvlist_unpack(packed, packed_len, &nv, KM_SLEEP);
+       free(packed);
+       free(compressed);
+       if (error != 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "resume token is corrupt (nvlist_unpack failed)"));
+               return (NULL);
+       }
+       return (nv);
+}
+
+int
+zfs_send_resume(libzfs_handle_t *hdl, sendflags_t *flags, int outfd,
+    const char *resume_token)
+{
+       char errbuf[1024];
+       char *toname;
+       char *fromname = NULL;
+       uint64_t resumeobj, resumeoff, toguid, fromguid, bytes;
+       zfs_handle_t *zhp;
+       int error = 0;
+       char name[ZFS_MAX_DATASET_NAME_LEN];
+       enum lzc_send_flags lzc_flags = 0;
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot resume send"));
+
+       nvlist_t *resume_nvl =
+           zfs_send_resume_token_to_nvlist(hdl, resume_token);
+       if (resume_nvl == NULL) {
+               /*
+                * zfs_error_aux has already been set by
+                * zfs_send_resume_token_to_nvlist
+                */
+               return (zfs_error(hdl, EZFS_FAULT, errbuf));
+       }
+       if (flags->verbose) {
+               (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                   "resume token contents:\n"));
+               nvlist_print(stderr, resume_nvl);
+       }
+
+       if (nvlist_lookup_string(resume_nvl, "toname", &toname) != 0 ||
+           nvlist_lookup_uint64(resume_nvl, "object", &resumeobj) != 0 ||
+           nvlist_lookup_uint64(resume_nvl, "offset", &resumeoff) != 0 ||
+           nvlist_lookup_uint64(resume_nvl, "bytes", &bytes) != 0 ||
+           nvlist_lookup_uint64(resume_nvl, "toguid", &toguid) != 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "resume token is corrupt"));
+               return (zfs_error(hdl, EZFS_FAULT, errbuf));
+       }
+       fromguid = 0;
+       (void) nvlist_lookup_uint64(resume_nvl, "fromguid", &fromguid);
+
+       if (flags->largeblock || nvlist_exists(resume_nvl, "largeblockok"))
+               lzc_flags |= LZC_SEND_FLAG_LARGE_BLOCK;
+       if (flags->embed_data || nvlist_exists(resume_nvl, "embedok"))
+               lzc_flags |= LZC_SEND_FLAG_EMBED_DATA;
+       if (flags->compress || nvlist_exists(resume_nvl, "compressok"))
+               lzc_flags |= LZC_SEND_FLAG_COMPRESS;
+
+       if (guid_to_name(hdl, toname, toguid, B_FALSE, name) != 0) {
+               if (zfs_dataset_exists(hdl, toname, ZFS_TYPE_DATASET)) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' is no longer the same snapshot used in "
+                           "the initial send"), toname);
+               } else {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' used in the initial send no longer exists"),
+                           toname);
+               }
+               return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+       }
+       zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
+       if (zhp == NULL) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "unable to access '%s'"), name);
+               return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+       }
+
+       if (fromguid != 0) {
+               if (guid_to_name(hdl, toname, fromguid, B_TRUE, name) != 0) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "incremental source %#llx no longer exists"),
+                           (longlong_t)fromguid);
+                       return (zfs_error(hdl, EZFS_BADPATH, errbuf));
+               }
+               fromname = name;
+       }
+
+       if (flags->verbose) {
+               uint64_t size = 0;
+               error = lzc_send_space(zhp->zfs_name, fromname,
+                   lzc_flags, &size);
+               if (error == 0)
+                       size = MAX(0, (int64_t)(size - bytes));
+               send_print_verbose(stderr, zhp->zfs_name, fromname,
+                   size, flags->parsable);
+       }
+
+       if (!flags->dryrun) {
+               progress_arg_t pa = { 0 };
+               pthread_t tid;
+               /*
+                * If progress reporting is requested, spawn a new thread to
+                * poll ZFS_IOC_SEND_PROGRESS at a regular interval.
+                */
+               if (flags->progress) {
+                       pa.pa_zhp = zhp;
+                       pa.pa_fd = outfd;
+                       pa.pa_parsable = flags->parsable;
+
+                       error = pthread_create(&tid, NULL,
+                           send_progress_thread, &pa);
+                       if (error != 0) {
+                               zfs_close(zhp);
+                               return (error);
+                       }
+               }
+
+               error = lzc_send_resume(zhp->zfs_name, fromname, outfd,
+                   lzc_flags, resumeobj, resumeoff);
+
+               if (flags->progress) {
+                       (void) pthread_cancel(tid);
+                       (void) pthread_join(tid, NULL);
+               }
+
+               char errbuf[1024];
+               (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+                   "warning: cannot send '%s'"), zhp->zfs_name);
+
+               zfs_close(zhp);
+
+               switch (error) {
+               case 0:
+                       return (0);
+               case EXDEV:
+               case ENOENT:
+               case EDQUOT:
+               case EFBIG:
+               case EIO:
+               case ENOLINK:
+               case ENOSPC:
+               case ENOSTR:
+               case ENXIO:
+               case EPIPE:
+               case ERANGE:
+               case EFAULT:
+               case EROFS:
+                       zfs_error_aux(hdl, strerror(errno));
+                       return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+               default:
+                       return (zfs_standard_error(hdl, errno, errbuf));
+               }
+       }
+
+
+       zfs_close(zhp);
+
+       return (error);
+}
+
+/*
+ * Generate a send stream for the dataset identified by the argument zhp.
+ *
+ * The content of the send stream is the snapshot identified by
+ * 'tosnap'.  Incremental streams are requested in two ways:
+ *     - from the snapshot identified by "fromsnap" (if non-null) or
+ *     - from the origin of the dataset identified by zhp, which must
+ *      be a clone.  In this case, "fromsnap" is null and "fromorigin"
+ *      is TRUE.
+ *
+ * The send stream is recursive (i.e. dumps a hierarchy of snapshots) and
+ * uses a special header (with a hdrtype field of DMU_COMPOUNDSTREAM)
+ * if "replicate" is set.  If "doall" is set, dump all the intermediate
+ * snapshots. The DMU_COMPOUNDSTREAM header is used in the "doall"
+ * case too. If "props" is set, send properties.
+ */
+int
+zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
+    sendflags_t *flags, int outfd, snapfilter_cb_t filter_func,
+    void *cb_arg, nvlist_t **debugnvp)
+{
+       char errbuf[1024];
+       send_dump_data_t sdd = { 0 };
+       int err = 0;
+       nvlist_t *fss = NULL;
+       avl_tree_t *fsavl = NULL;
+       static uint64_t holdseq;
+       int spa_version;
+       pthread_t tid = 0;
+       int pipefd[2];
+       dedup_arg_t dda = { 0 };
+       int featureflags = 0;
+       FILE *fout;
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot send '%s'"), zhp->zfs_name);
+
+       if (fromsnap && fromsnap[0] == '\0') {
+               zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
+                   "zero-length incremental source"));
+               return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
+       }
+
+       if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM) {
+               uint64_t version;
+               version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
+               if (version >= ZPL_VERSION_SA) {
+                       featureflags |= DMU_BACKUP_FEATURE_SA_SPILL;
+               }
+       }
+
+       if (flags->dedup && !flags->dryrun) {
+               featureflags |= (DMU_BACKUP_FEATURE_DEDUP |
+                   DMU_BACKUP_FEATURE_DEDUPPROPS);
+               if ((err = socketpair(AF_UNIX, SOCK_STREAM, 0, pipefd))) {
+                       zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+                       return (zfs_error(zhp->zfs_hdl, EZFS_PIPEFAILED,
+                           errbuf));
+               }
+               dda.outputfd = outfd;
+               dda.inputfd = pipefd[1];
+               dda.dedup_hdl = zhp->zfs_hdl;
+               if ((err = pthread_create(&tid, NULL, cksummer, &dda))) {
+                       (void) close(pipefd[0]);
+                       (void) close(pipefd[1]);
+                       zfs_error_aux(zhp->zfs_hdl, strerror(errno));
+                       return (zfs_error(zhp->zfs_hdl,
+                           EZFS_THREADCREATEFAILED, errbuf));
+               }
+       }
+
+       if (flags->replicate || flags->doall || flags->props) {
+               dmu_replay_record_t drr = { 0 };
+               char *packbuf = NULL;
+               size_t buflen = 0;
+               zio_cksum_t zc;
+
+               ZIO_SET_CHECKSUM(&zc, 0, 0, 0, 0);
+
+               if (flags->replicate || flags->props) {
+                       nvlist_t *hdrnv;
+
+                       VERIFY(0 == nvlist_alloc(&hdrnv, NV_UNIQUE_NAME, 0));
+                       if (fromsnap) {
+                               VERIFY(0 == nvlist_add_string(hdrnv,
+                                   "fromsnap", fromsnap));
+                       }
+                       VERIFY(0 == nvlist_add_string(hdrnv, "tosnap", tosnap));
+                       if (!flags->replicate) {
+                               VERIFY(0 == nvlist_add_boolean(hdrnv,
+                                   "not_recursive"));
+                       }
+
+                       err = gather_nvlist(zhp->zfs_hdl, zhp->zfs_name,
+                           fromsnap, tosnap, flags->replicate, flags->verbose,
+                           &fss, &fsavl);
+                       if (err)
+                               goto err_out;
+                       VERIFY(0 == nvlist_add_nvlist(hdrnv, "fss", fss));
+                       err = nvlist_pack(hdrnv, &packbuf, &buflen,
+                           NV_ENCODE_XDR, 0);
+                       if (debugnvp)
+                               *debugnvp = hdrnv;
+                       else
+                               nvlist_free(hdrnv);
+                       if (err)
+                               goto stderr_out;
+               }
+
+               if (!flags->dryrun) {
+                       /* write first begin record */
+                       drr.drr_type = DRR_BEGIN;
+                       drr.drr_u.drr_begin.drr_magic = DMU_BACKUP_MAGIC;
+                       DMU_SET_STREAM_HDRTYPE(drr.drr_u.drr_begin.
+                           drr_versioninfo, DMU_COMPOUNDSTREAM);
+                       DMU_SET_FEATUREFLAGS(drr.drr_u.drr_begin.
+                           drr_versioninfo, featureflags);
+                       (void) snprintf(drr.drr_u.drr_begin.drr_toname,
+                           sizeof (drr.drr_u.drr_begin.drr_toname),
+                           "%s@%s", zhp->zfs_name, tosnap);
+                       drr.drr_payloadlen = buflen;
+
+                       err = dump_record(&drr, packbuf, buflen, &zc, outfd);
+                       free(packbuf);
+                       if (err != 0)
+                               goto stderr_out;
+
+                       /* write end record */
+                       bzero(&drr, sizeof (drr));
+                       drr.drr_type = DRR_END;
+                       drr.drr_u.drr_end.drr_checksum = zc;
+                       err = write(outfd, &drr, sizeof (drr));
+                       if (err == -1) {
+                               err = errno;
+                               goto stderr_out;
+                       }
+
+                       err = 0;
+               }
+       }
+
+       /* dump each stream */
+       sdd.fromsnap = fromsnap;
+       sdd.tosnap = tosnap;
+       if (tid != 0)
+               sdd.outfd = pipefd[0];
+       else
+               sdd.outfd = outfd;
+       sdd.replicate = flags->replicate;
+       sdd.doall = flags->doall;
+       sdd.fromorigin = flags->fromorigin;
+       sdd.fss = fss;
+       sdd.fsavl = fsavl;
+       sdd.verbose = flags->verbose;
+       sdd.parsable = flags->parsable;
+       sdd.progress = flags->progress;
+       sdd.dryrun = flags->dryrun;
+       sdd.large_block = flags->largeblock;
+       sdd.embed_data = flags->embed_data;
+       sdd.compress = flags->compress;
+       sdd.filter_cb = filter_func;
+       sdd.filter_cb_arg = cb_arg;
+       if (debugnvp)
+               sdd.debugnv = *debugnvp;
+       if (sdd.verbose && sdd.dryrun)
+               sdd.std_out = B_TRUE;
+       fout = sdd.std_out ? stdout : stderr;
+
+       /*
+        * Some flags require that we place user holds on the datasets that are
+        * being sent so they don't get destroyed during the send. We can skip
+        * this step if the pool is imported read-only since the datasets cannot
+        * be destroyed.
+        */
+       if (!flags->dryrun && !zpool_get_prop_int(zfs_get_pool_handle(zhp),
+           ZPOOL_PROP_READONLY, NULL) &&
+           zfs_spa_version(zhp, &spa_version) == 0 &&
+           spa_version >= SPA_VERSION_USERREFS &&
+           (flags->doall || flags->replicate)) {
+               ++holdseq;
+               (void) snprintf(sdd.holdtag, sizeof (sdd.holdtag),
+                   ".send-%d-%llu", getpid(), (u_longlong_t)holdseq);
+               sdd.cleanup_fd = open(ZFS_DEV, O_RDWR);
+               if (sdd.cleanup_fd < 0) {
+                       err = errno;
+                       goto stderr_out;
+               }
+               sdd.snapholds = fnvlist_alloc();
+       } else {
+               sdd.cleanup_fd = -1;
+               sdd.snapholds = NULL;
+       }
+       if (flags->verbose || sdd.snapholds != NULL) {
+               /*
+                * Do a verbose no-op dry run to get all the verbose output
+                * or to gather snapshot hold's before generating any data,
+                * then do a non-verbose real run to generate the streams.
+                */
+               sdd.dryrun = B_TRUE;
+               err = dump_filesystems(zhp, &sdd);
+
+               if (err != 0)
+                       goto stderr_out;
+
+               if (flags->verbose) {
+                       if (flags->parsable) {
+                               (void) fprintf(fout, "size\t%llu\n",
+                                   (longlong_t)sdd.size);
+                       } else {
+                               char buf[16];
+                               zfs_nicenum(sdd.size, buf, sizeof (buf));
+                               (void) fprintf(fout, dgettext(TEXT_DOMAIN,
+                                   "total estimated size is %s\n"), buf);
+                       }
+               }
+
+               /* Ensure no snaps found is treated as an error. */
+               if (!sdd.seento) {
+                       err = ENOENT;
+                       goto err_out;
+               }
+
+               /* Skip the second run if dryrun was requested. */
+               if (flags->dryrun)
+                       goto err_out;
+
+               if (sdd.snapholds != NULL) {
+                       err = zfs_hold_nvl(zhp, sdd.cleanup_fd, sdd.snapholds);
+                       if (err != 0)
+                               goto stderr_out;
+
+                       fnvlist_free(sdd.snapholds);
+                       sdd.snapholds = NULL;
+               }
+
+               sdd.dryrun = B_FALSE;
+               sdd.verbose = B_FALSE;
+       }
+
+       err = dump_filesystems(zhp, &sdd);
+       fsavl_destroy(fsavl);
+       nvlist_free(fss);
+
+       /* Ensure no snaps found is treated as an error. */
+       if (err == 0 && !sdd.seento)
+               err = ENOENT;
+
+       if (tid != 0) {
+               if (err != 0)
+                       (void) pthread_cancel(tid);
+               (void) close(pipefd[0]);
+               (void) pthread_join(tid, NULL);
+       }
+
+       if (sdd.cleanup_fd != -1) {
+               VERIFY(0 == close(sdd.cleanup_fd));
+               sdd.cleanup_fd = -1;
+       }
+
+       if (!flags->dryrun && (flags->replicate || flags->doall ||
+           flags->props)) {
+               /*
+                * write final end record.  NB: want to do this even if
+                * there was some error, because it might not be totally
+                * failed.
+                */
+               dmu_replay_record_t drr = { 0 };
+               drr.drr_type = DRR_END;
+               if (write(outfd, &drr, sizeof (drr)) == -1) {
+                       return (zfs_standard_error(zhp->zfs_hdl,
+                           errno, errbuf));
+               }
+       }
+
+       return (err || sdd.err);
+
+stderr_out:
+       err = zfs_standard_error(zhp->zfs_hdl, err, errbuf);
+err_out:
+       fsavl_destroy(fsavl);
+       nvlist_free(fss);
+       fnvlist_free(sdd.snapholds);
+
+       if (sdd.cleanup_fd != -1)
+               VERIFY(0 == close(sdd.cleanup_fd));
+       if (tid != 0) {
+               (void) pthread_cancel(tid);
+               (void) close(pipefd[0]);
+               (void) pthread_join(tid, NULL);
+       }
+       return (err);
+}
+
+int
+zfs_send_one(zfs_handle_t *zhp, const char *from, int fd,
+    enum lzc_send_flags flags)
+{
+       int err;
+       libzfs_handle_t *hdl = zhp->zfs_hdl;
+
+       char errbuf[1024];
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "warning: cannot send '%s'"), zhp->zfs_name);
+
+       err = lzc_send(zhp->zfs_name, from, fd, flags);
+       if (err != 0) {
+               switch (errno) {
+               case EXDEV:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "not an earlier snapshot from the same fs"));
+                       return (zfs_error(hdl, EZFS_CROSSTARGET, errbuf));
+
+               case ENOENT:
+               case ESRCH:
+                       if (lzc_exists(zhp->zfs_name)) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "incremental source (%s) does not exist"),
+                                   from);
+                       }
+                       return (zfs_error(hdl, EZFS_NOENT, errbuf));
+
+               case EBUSY:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "target is busy; if a filesystem, "
+                           "it must not be mounted"));
+                       return (zfs_error(hdl, EZFS_BUSY, errbuf));
+
+               case EDQUOT:
+               case EFBIG:
+               case EIO:
+               case ENOLINK:
+               case ENOSPC:
+               case ENOSTR:
+               case ENXIO:
+               case EPIPE:
+               case ERANGE:
+               case EFAULT:
+               case EROFS:
+                       zfs_error_aux(hdl, strerror(errno));
+                       return (zfs_error(hdl, EZFS_BADBACKUP, errbuf));
+
+               default:
+                       return (zfs_standard_error(hdl, errno, errbuf));
+               }
+       }
+       return (err != 0);
+}
+
+/*
+ * Routines specific to "zfs recv"
+ */
+
+static int
+recv_read(libzfs_handle_t *hdl, int fd, void *buf, int ilen,
+    boolean_t byteswap, zio_cksum_t *zc)
+{
+       char *cp = buf;
+       int rv;
+       int len = ilen;
+
+       assert(ilen <= SPA_MAXBLOCKSIZE);
+
+       do {
+               rv = read(fd, cp, len);
+               cp += rv;
+               len -= rv;
+       } while (rv > 0);
+
+       if (rv < 0 || len != 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "failed to read from stream"));
+               return (zfs_error(hdl, EZFS_BADSTREAM, dgettext(TEXT_DOMAIN,
+                   "cannot receive")));
+       }
+
+       if (zc) {
+               if (byteswap)
+                       fletcher_4_incremental_byteswap(buf, ilen, zc);
+               else
+                       fletcher_4_incremental_native(buf, ilen, zc);
+       }
+       return (0);
+}
+
+static int
+recv_read_nvlist(libzfs_handle_t *hdl, int fd, int len, nvlist_t **nvp,
+    boolean_t byteswap, zio_cksum_t *zc)
+{
+       char *buf;
+       int err;
+
+       buf = zfs_alloc(hdl, len);
+       if (buf == NULL)
+               return (ENOMEM);
+
+       err = recv_read(hdl, fd, buf, len, byteswap, zc);
+       if (err != 0) {
+               free(buf);
+               return (err);
+       }
+
+       err = nvlist_unpack(buf, len, nvp, 0);
+       free(buf);
+       if (err != 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+                   "stream (malformed nvlist)"));
+               return (EINVAL);
+       }
+       return (0);
+}
+
+static int
+recv_rename(libzfs_handle_t *hdl, const char *name, const char *tryname,
+    int baselen, char *newname, recvflags_t *flags)
+{
+       static int seq;
+       zfs_cmd_t zc = {"\0"};
+       int err;
+       prop_changelist_t *clp;
+       zfs_handle_t *zhp;
+
+       zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
+       if (zhp == NULL)
+               return (-1);
+       clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+           flags->force ? MS_FORCE : 0);
+       zfs_close(zhp);
+       if (clp == NULL)
+               return (-1);
+       err = changelist_prefix(clp);
+       if (err)
+               return (err);
+
+       zc.zc_objset_type = DMU_OST_ZFS;
+       (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+
+       if (tryname) {
+               (void) strcpy(newname, tryname);
+
+               (void) strlcpy(zc.zc_value, tryname, sizeof (zc.zc_value));
+
+               if (flags->verbose) {
+                       (void) printf("attempting rename %s to %s\n",
+                           zc.zc_name, zc.zc_value);
+               }
+               err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc);
+               if (err == 0)
+                       changelist_rename(clp, name, tryname);
+       } else {
+               err = ENOENT;
+       }
+
+       if (err != 0 && strncmp(name + baselen, "recv-", 5) != 0) {
+               seq++;
+
+               (void) snprintf(newname, ZFS_MAX_DATASET_NAME_LEN,
+                   "%.*srecv-%u-%u", baselen, name, getpid(), seq);
+               (void) strlcpy(zc.zc_value, newname, sizeof (zc.zc_value));
+
+               if (flags->verbose) {
+                       (void) printf("failed - trying rename %s to %s\n",
+                           zc.zc_name, zc.zc_value);
+               }
+               err = ioctl(hdl->libzfs_fd, ZFS_IOC_RENAME, &zc);
+               if (err == 0)
+                       changelist_rename(clp, name, newname);
+               if (err && flags->verbose) {
+                       (void) printf("failed (%u) - "
+                           "will try again on next pass\n", errno);
+               }
+               err = EAGAIN;
+       } else if (flags->verbose) {
+               if (err == 0)
+                       (void) printf("success\n");
+               else
+                       (void) printf("failed (%u)\n", errno);
+       }
+
+       (void) changelist_postfix(clp);
+       changelist_free(clp);
+
+       return (err);
+}
+
+static int
+recv_destroy(libzfs_handle_t *hdl, const char *name, int baselen,
+    char *newname, recvflags_t *flags)
+{
+       zfs_cmd_t zc = {"\0"};
+       int err = 0;
+       prop_changelist_t *clp;
+       zfs_handle_t *zhp;
+       boolean_t defer = B_FALSE;
+       int spa_version;
+
+       zhp = zfs_open(hdl, name, ZFS_TYPE_DATASET);
+       if (zhp == NULL)
+               return (-1);
+       clp = changelist_gather(zhp, ZFS_PROP_NAME, 0,
+           flags->force ? MS_FORCE : 0);
+       if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT &&
+           zfs_spa_version(zhp, &spa_version) == 0 &&
+           spa_version >= SPA_VERSION_USERREFS)
+               defer = B_TRUE;
+       zfs_close(zhp);
+       if (clp == NULL)
+               return (-1);
+       err = changelist_prefix(clp);
+       if (err)
+               return (err);
+
+       zc.zc_objset_type = DMU_OST_ZFS;
+       zc.zc_defer_destroy = defer;
+       (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+
+       if (flags->verbose)
+               (void) printf("attempting destroy %s\n", zc.zc_name);
+       err = ioctl(hdl->libzfs_fd, ZFS_IOC_DESTROY, &zc);
+       if (err == 0) {
+               if (flags->verbose)
+                       (void) printf("success\n");
+               changelist_remove(clp, zc.zc_name);
+       }
+
+       (void) changelist_postfix(clp);
+       changelist_free(clp);
+
+       /*
+        * Deferred destroy might destroy the snapshot or only mark it to be
+        * destroyed later, and it returns success in either case.
+        */
+       if (err != 0 || (defer && zfs_dataset_exists(hdl, name,
+           ZFS_TYPE_SNAPSHOT))) {
+               err = recv_rename(hdl, name, NULL, baselen, newname, flags);
+       }
+
+       return (err);
+}
+
+typedef struct guid_to_name_data {
+       uint64_t guid;
+       boolean_t bookmark_ok;
+       char *name;
+       char *skip;
+} guid_to_name_data_t;
+
+static int
+guid_to_name_cb(zfs_handle_t *zhp, void *arg)
+{
+       guid_to_name_data_t *gtnd = arg;
+       const char *slash;
+       int err;
+
+       if (gtnd->skip != NULL &&
+           (slash = strrchr(zhp->zfs_name, '/')) != NULL &&
+           strcmp(slash + 1, gtnd->skip) == 0) {
+               zfs_close(zhp);
+               return (0);
+       }
+
+       if (zfs_prop_get_int(zhp, ZFS_PROP_GUID) == gtnd->guid) {
+               (void) strcpy(gtnd->name, zhp->zfs_name);
+               zfs_close(zhp);
+               return (EEXIST);
+       }
+
+       err = zfs_iter_children(zhp, guid_to_name_cb, gtnd);
+       if (err != EEXIST && gtnd->bookmark_ok)
+               err = zfs_iter_bookmarks(zhp, guid_to_name_cb, gtnd);
+       zfs_close(zhp);
+       return (err);
+}
+
+/*
+ * Attempt to find the local dataset associated with this guid.  In the case of
+ * multiple matches, we attempt to find the "best" match by searching
+ * progressively larger portions of the hierarchy.  This allows one to send a
+ * tree of datasets individually and guarantee that we will find the source
+ * guid within that hierarchy, even if there are multiple matches elsewhere.
+ */
+static int
+guid_to_name(libzfs_handle_t *hdl, const char *parent, uint64_t guid,
+    boolean_t bookmark_ok, char *name)
+{
+       char pname[ZFS_MAX_DATASET_NAME_LEN];
+       guid_to_name_data_t gtnd;
+
+       gtnd.guid = guid;
+       gtnd.bookmark_ok = bookmark_ok;
+       gtnd.name = name;
+       gtnd.skip = NULL;
+
+       /*
+        * Search progressively larger portions of the hierarchy, starting
+        * with the filesystem specified by 'parent'.  This will
+        * select the "most local" version of the origin snapshot in the case
+        * that there are multiple matching snapshots in the system.
+        */
+       (void) strlcpy(pname, parent, sizeof (pname));
+       char *cp = strrchr(pname, '@');
+       if (cp == NULL)
+               cp = strchr(pname, '\0');
+       for (; cp != NULL; cp = strrchr(pname, '/')) {
+               /* Chop off the last component and open the parent */
+               *cp = '\0';
+               zfs_handle_t *zhp = make_dataset_handle(hdl, pname);
+
+               if (zhp == NULL)
+                       continue;
+               int err = guid_to_name_cb(zfs_handle_dup(zhp), &gtnd);
+               if (err != EEXIST)
+                       err = zfs_iter_children(zhp, guid_to_name_cb, &gtnd);
+               if (err != EEXIST && bookmark_ok)
+                       err = zfs_iter_bookmarks(zhp, guid_to_name_cb, &gtnd);
+               zfs_close(zhp);
+               if (err == EEXIST)
+                       return (0);
+
+               /*
+                * Remember the last portion of the dataset so we skip it next
+                * time through (as we've already searched that portion of the
+                * hierarchy).
+                */
+               gtnd.skip = strrchr(pname, '/') + 1;
+       }
+
+       return (ENOENT);
+}
+
+/*
+ * Return +1 if guid1 is before guid2, 0 if they are the same, and -1 if
+ * guid1 is after guid2.
+ */
+static int
+created_before(libzfs_handle_t *hdl, avl_tree_t *avl,
+    uint64_t guid1, uint64_t guid2)
+{
+       nvlist_t *nvfs;
+       char *fsname = NULL, *snapname = NULL;
+       char buf[ZFS_MAX_DATASET_NAME_LEN];
+       int rv;
+       zfs_handle_t *guid1hdl, *guid2hdl;
+       uint64_t create1, create2;
+
+       if (guid2 == 0)
+               return (0);
+       if (guid1 == 0)
+               return (1);
+
+       nvfs = fsavl_find(avl, guid1, &snapname);
+       VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
+       (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);
+       guid1hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
+       if (guid1hdl == NULL)
+               return (-1);
+
+       nvfs = fsavl_find(avl, guid2, &snapname);
+       VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
+       (void) snprintf(buf, sizeof (buf), "%s@%s", fsname, snapname);
+       guid2hdl = zfs_open(hdl, buf, ZFS_TYPE_SNAPSHOT);
+       if (guid2hdl == NULL) {
+               zfs_close(guid1hdl);
+               return (-1);
+       }
+
+       create1 = zfs_prop_get_int(guid1hdl, ZFS_PROP_CREATETXG);
+       create2 = zfs_prop_get_int(guid2hdl, ZFS_PROP_CREATETXG);
+
+       if (create1 < create2)
+               rv = -1;
+       else if (create1 > create2)
+               rv = +1;
+       else
+               rv = 0;
+
+       zfs_close(guid1hdl);
+       zfs_close(guid2hdl);
+
+       return (rv);
+}
+
+static int
+recv_incremental_replication(libzfs_handle_t *hdl, const char *tofs,
+    recvflags_t *flags, nvlist_t *stream_nv, avl_tree_t *stream_avl,
+    nvlist_t *renamed)
+{
+       nvlist_t *local_nv, *deleted = NULL;
+       avl_tree_t *local_avl;
+       nvpair_t *fselem, *nextfselem;
+       char *fromsnap;
+       char newname[ZFS_MAX_DATASET_NAME_LEN];
+       char guidname[32];
+       int error;
+       boolean_t needagain, progress, recursive;
+       char *s1, *s2;
+
+       VERIFY(0 == nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap));
+
+       recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
+           ENOENT);
+
+       if (flags->dryrun)
+               return (0);
+
+again:
+       needagain = progress = B_FALSE;
+
+       VERIFY(0 == nvlist_alloc(&deleted, NV_UNIQUE_NAME, 0));
+
+       if ((error = gather_nvlist(hdl, tofs, fromsnap, NULL,
+           recursive, B_FALSE, &local_nv, &local_avl)) != 0)
+               return (error);
+
+       /*
+        * Process deletes and renames
+        */
+       for (fselem = nvlist_next_nvpair(local_nv, NULL);
+           fselem; fselem = nextfselem) {
+               nvlist_t *nvfs, *snaps;
+               nvlist_t *stream_nvfs = NULL;
+               nvpair_t *snapelem, *nextsnapelem;
+               uint64_t fromguid = 0;
+               uint64_t originguid = 0;
+               uint64_t stream_originguid = 0;
+               uint64_t parent_fromsnap_guid, stream_parent_fromsnap_guid;
+               char *fsname, *stream_fsname;
+
+               nextfselem = nvlist_next_nvpair(local_nv, fselem);
+
+               VERIFY(0 == nvpair_value_nvlist(fselem, &nvfs));
+               VERIFY(0 == nvlist_lookup_nvlist(nvfs, "snaps", &snaps));
+               VERIFY(0 == nvlist_lookup_string(nvfs, "name", &fsname));
+               VERIFY(0 == nvlist_lookup_uint64(nvfs, "parentfromsnap",
+                   &parent_fromsnap_guid));
+               (void) nvlist_lookup_uint64(nvfs, "origin", &originguid);
+
+               /*
+                * First find the stream's fs, so we can check for
+                * a different origin (due to "zfs promote")
+                */
+               for (snapelem = nvlist_next_nvpair(snaps, NULL);
+                   snapelem; snapelem = nvlist_next_nvpair(snaps, snapelem)) {
+                       uint64_t thisguid;
+
+                       VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid));
+                       stream_nvfs = fsavl_find(stream_avl, thisguid, NULL);
+
+                       if (stream_nvfs != NULL)
+                               break;
+               }
+
+               /* check for promote */
+               (void) nvlist_lookup_uint64(stream_nvfs, "origin",
+                   &stream_originguid);
+               if (stream_nvfs && originguid != stream_originguid) {
+                       switch (created_before(hdl, local_avl,
+                           stream_originguid, originguid)) {
+                       case 1: {
+                               /* promote it! */
+                               zfs_cmd_t zc = {"\0"};
+                               nvlist_t *origin_nvfs;
+                               char *origin_fsname;
+
+                               if (flags->verbose)
+                                       (void) printf("promoting %s\n", fsname);
+
+                               origin_nvfs = fsavl_find(local_avl, originguid,
+                                   NULL);
+                               VERIFY(0 == nvlist_lookup_string(origin_nvfs,
+                                   "name", &origin_fsname));
+                               (void) strlcpy(zc.zc_value, origin_fsname,
+                                   sizeof (zc.zc_value));
+                               (void) strlcpy(zc.zc_name, fsname,
+                                   sizeof (zc.zc_name));
+                               error = zfs_ioctl(hdl, ZFS_IOC_PROMOTE, &zc);
+                               if (error == 0)
+                                       progress = B_TRUE;
+                               break;
+                       }
+                       default:
+                               break;
+                       case -1:
+                               fsavl_destroy(local_avl);
+                               nvlist_free(local_nv);
+                               return (-1);
+                       }
+                       /*
+                        * We had/have the wrong origin, therefore our
+                        * list of snapshots is wrong.  Need to handle
+                        * them on the next pass.
+                        */
+                       needagain = B_TRUE;
+                       continue;
+               }
+
+               for (snapelem = nvlist_next_nvpair(snaps, NULL);
+                   snapelem; snapelem = nextsnapelem) {
+                       uint64_t thisguid;
+                       char *stream_snapname;
+                       nvlist_t *found, *props;
+
+                       nextsnapelem = nvlist_next_nvpair(snaps, snapelem);
+
+                       VERIFY(0 == nvpair_value_uint64(snapelem, &thisguid));
+                       found = fsavl_find(stream_avl, thisguid,
+                           &stream_snapname);
+
+                       /* check for delete */
+                       if (found == NULL) {
+                               char name[ZFS_MAX_DATASET_NAME_LEN];
+
+                               if (!flags->force)
+                                       continue;
+
+                               (void) snprintf(name, sizeof (name), "%s@%s",
+                                   fsname, nvpair_name(snapelem));
+
+                               error = recv_destroy(hdl, name,
+                                   strlen(fsname)+1, newname, flags);
+                               if (error)
+                                       needagain = B_TRUE;
+                               else
+                                       progress = B_TRUE;
+                               sprintf(guidname, "%llu",
+                                   (u_longlong_t)thisguid);
+                               nvlist_add_boolean(deleted, guidname);
+                               continue;
+                       }
+
+                       stream_nvfs = found;
+
+                       if (0 == nvlist_lookup_nvlist(stream_nvfs, "snapprops",
+                           &props) && 0 == nvlist_lookup_nvlist(props,
+                           stream_snapname, &props)) {
+                               zfs_cmd_t zc = {"\0"};
+
+                               zc.zc_cookie = B_TRUE; /* received */
+                               (void) snprintf(zc.zc_name, sizeof (zc.zc_name),
+                                   "%s@%s", fsname, nvpair_name(snapelem));
+                               if (zcmd_write_src_nvlist(hdl, &zc,
+                                   props) == 0) {
+                                       (void) zfs_ioctl(hdl,
+                                           ZFS_IOC_SET_PROP, &zc);
+                                       zcmd_free_nvlists(&zc);
+                               }
+                       }
+
+                       /* check for different snapname */
+                       if (strcmp(nvpair_name(snapelem),
+                           stream_snapname) != 0) {
+                               char name[ZFS_MAX_DATASET_NAME_LEN];
+                               char tryname[ZFS_MAX_DATASET_NAME_LEN];
+
+                               (void) snprintf(name, sizeof (name), "%s@%s",
+                                   fsname, nvpair_name(snapelem));
+                               (void) snprintf(tryname, sizeof (name), "%s@%s",
+                                   fsname, stream_snapname);
+
+                               error = recv_rename(hdl, name, tryname,
+                                   strlen(fsname)+1, newname, flags);
+                               if (error)
+                                       needagain = B_TRUE;
+                               else
+                                       progress = B_TRUE;
+                       }
+
+                       if (strcmp(stream_snapname, fromsnap) == 0)
+                               fromguid = thisguid;
+               }
+
+               /* check for delete */
+               if (stream_nvfs == NULL) {
+                       if (!flags->force)
+                               continue;
+
+                       error = recv_destroy(hdl, fsname, strlen(tofs)+1,
+                           newname, flags);
+                       if (error)
+                               needagain = B_TRUE;
+                       else
+                               progress = B_TRUE;
+                       sprintf(guidname, "%llu",
+                           (u_longlong_t) parent_fromsnap_guid);
+                       nvlist_add_boolean(deleted, guidname);
+                       continue;
+               }
+
+               if (fromguid == 0) {
+                       if (flags->verbose) {
+                               (void) printf("local fs %s does not have "
+                                   "fromsnap (%s in stream); must have "
+                                   "been deleted locally; ignoring\n",
+                                   fsname, fromsnap);
+                       }
+                       continue;
+               }
+
+               VERIFY(0 == nvlist_lookup_string(stream_nvfs,
+                   "name", &stream_fsname));
+               VERIFY(0 == nvlist_lookup_uint64(stream_nvfs,
+                   "parentfromsnap", &stream_parent_fromsnap_guid));
+
+               s1 = strrchr(fsname, '/');
+               s2 = strrchr(stream_fsname, '/');
+
+               /*
+                * Check if we're going to rename based on parent guid change
+                * and the current parent guid was also deleted. If it was then
+                * rename will fail and is likely unneeded, so avoid this and
+                * force an early retry to determine the new
+                * parent_fromsnap_guid.
+                */
+               if (stream_parent_fromsnap_guid != 0 &&
+                   parent_fromsnap_guid != 0 &&
+                   stream_parent_fromsnap_guid != parent_fromsnap_guid) {
+                       sprintf(guidname, "%llu",
+                           (u_longlong_t) parent_fromsnap_guid);
+                       if (nvlist_exists(deleted, guidname)) {
+                               progress = B_TRUE;
+                               needagain = B_TRUE;
+                               goto doagain;
+                       }
+               }
+
+               /*
+                * Check for rename. If the exact receive path is specified, it
+                * does not count as a rename, but we still need to check the
+                * datasets beneath it.
+                */
+               if ((stream_parent_fromsnap_guid != 0 &&
+                   parent_fromsnap_guid != 0 &&
+                   stream_parent_fromsnap_guid != parent_fromsnap_guid) ||
+                   ((flags->isprefix || strcmp(tofs, fsname) != 0) &&
+                   (s1 != NULL) && (s2 != NULL) && strcmp(s1, s2) != 0)) {
+                       nvlist_t *parent;
+                       char tryname[ZFS_MAX_DATASET_NAME_LEN];
+
+                       parent = fsavl_find(local_avl,
+                           stream_parent_fromsnap_guid, NULL);
+                       /*
+                        * NB: parent might not be found if we used the
+                        * tosnap for stream_parent_fromsnap_guid,
+                        * because the parent is a newly-created fs;
+                        * we'll be able to rename it after we recv the
+                        * new fs.
+                        */
+                       if (parent != NULL) {
+                               char *pname;
+
+                               VERIFY(0 == nvlist_lookup_string(parent, "name",
+                                   &pname));
+                               (void) snprintf(tryname, sizeof (tryname),
+                                   "%s%s", pname, strrchr(stream_fsname, '/'));
+                       } else {
+                               tryname[0] = '\0';
+                               if (flags->verbose) {
+                                       (void) printf("local fs %s new parent "
+                                           "not found\n", fsname);
+                               }
+                       }
+
+                       newname[0] = '\0';
+
+                       error = recv_rename(hdl, fsname, tryname,
+                           strlen(tofs)+1, newname, flags);
+
+                       if (renamed != NULL && newname[0] != '\0') {
+                               VERIFY(0 == nvlist_add_boolean(renamed,
+                                   newname));
+                       }
+
+                       if (error)
+                               needagain = B_TRUE;
+                       else
+                               progress = B_TRUE;
+               }
+       }
+
+doagain:
+       fsavl_destroy(local_avl);
+       nvlist_free(local_nv);
+       nvlist_free(deleted);
+
+       if (needagain && progress) {
+               /* do another pass to fix up temporary names */
+               if (flags->verbose)
+                       (void) printf("another pass:\n");
+               goto again;
+       }
+
+       return (needagain);
+}
+
+static int
+zfs_receive_package(libzfs_handle_t *hdl, int fd, const char *destname,
+    recvflags_t *flags, dmu_replay_record_t *drr, zio_cksum_t *zc,
+    char **top_zfs, int cleanup_fd, uint64_t *action_handlep)
+{
+       nvlist_t *stream_nv = NULL;
+       avl_tree_t *stream_avl = NULL;
+       char *fromsnap = NULL;
+       char *sendsnap = NULL;
+       char *cp;
+       char tofs[ZFS_MAX_DATASET_NAME_LEN];
+       char sendfs[ZFS_MAX_DATASET_NAME_LEN];
+       char errbuf[1024];
+       dmu_replay_record_t drre;
+       int error;
+       boolean_t anyerr = B_FALSE;
+       boolean_t softerr = B_FALSE;
+       boolean_t recursive;
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot receive"));
+
+       assert(drr->drr_type == DRR_BEGIN);
+       assert(drr->drr_u.drr_begin.drr_magic == DMU_BACKUP_MAGIC);
+       assert(DMU_GET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo) ==
+           DMU_COMPOUNDSTREAM);
+
+       /*
+        * Read in the nvlist from the stream.
+        */
+       if (drr->drr_payloadlen != 0) {
+               error = recv_read_nvlist(hdl, fd, drr->drr_payloadlen,
+                   &stream_nv, flags->byteswap, zc);
+               if (error) {
+                       error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+                       goto out;
+               }
+       }
+
+       recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
+           ENOENT);
+
+       if (recursive && strchr(destname, '@')) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "cannot specify snapshot name for multi-snapshot stream"));
+               error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+               goto out;
+       }
+
+       /*
+        * Read in the end record and verify checksum.
+        */
+       if (0 != (error = recv_read(hdl, fd, &drre, sizeof (drre),
+           flags->byteswap, NULL)))
+               goto out;
+       if (flags->byteswap) {
+               drre.drr_type = BSWAP_32(drre.drr_type);
+               drre.drr_u.drr_end.drr_checksum.zc_word[0] =
+                   BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[0]);
+               drre.drr_u.drr_end.drr_checksum.zc_word[1] =
+                   BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[1]);
+               drre.drr_u.drr_end.drr_checksum.zc_word[2] =
+                   BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[2]);
+               drre.drr_u.drr_end.drr_checksum.zc_word[3] =
+                   BSWAP_64(drre.drr_u.drr_end.drr_checksum.zc_word[3]);
+       }
+       if (drre.drr_type != DRR_END) {
+               error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+               goto out;
+       }
+       if (!ZIO_CHECKSUM_EQUAL(drre.drr_u.drr_end.drr_checksum, *zc)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "incorrect header checksum"));
+               error = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+               goto out;
+       }
+
+       (void) nvlist_lookup_string(stream_nv, "fromsnap", &fromsnap);
+
+       if (drr->drr_payloadlen != 0) {
+               nvlist_t *stream_fss;
+
+               VERIFY(0 == nvlist_lookup_nvlist(stream_nv, "fss",
+                   &stream_fss));
+               if ((stream_avl = fsavl_create(stream_fss)) == NULL) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "couldn't allocate avl tree"));
+                       error = zfs_error(hdl, EZFS_NOMEM, errbuf);
+                       goto out;
+               }
+
+               if (fromsnap != NULL) {
+                       nvlist_t *renamed = NULL;
+                       nvpair_t *pair = NULL;
+
+                       (void) strlcpy(tofs, destname, sizeof (tofs));
+                       if (flags->isprefix) {
+                               struct drr_begin *drrb = &drr->drr_u.drr_begin;
+                               int i;
+
+                               if (flags->istail) {
+                                       cp = strrchr(drrb->drr_toname, '/');
+                                       if (cp == NULL) {
+                                               (void) strlcat(tofs, "/",
+                                                   sizeof (tofs));
+                                               i = 0;
+                                       } else {
+                                               i = (cp - drrb->drr_toname);
+                                       }
+                               } else {
+                                       i = strcspn(drrb->drr_toname, "/@");
+                               }
+                               /* zfs_receive_one() will create_parents() */
+                               (void) strlcat(tofs, &drrb->drr_toname[i],
+                                   sizeof (tofs));
+                               *strchr(tofs, '@') = '\0';
+                       }
+
+                       if (recursive && !flags->dryrun && !flags->nomount) {
+                               VERIFY(0 == nvlist_alloc(&renamed,
+                                   NV_UNIQUE_NAME, 0));
+                       }
+
+                       softerr = recv_incremental_replication(hdl, tofs, flags,
+                           stream_nv, stream_avl, renamed);
+
+                       /* Unmount renamed filesystems before receiving. */
+                       while ((pair = nvlist_next_nvpair(renamed,
+                           pair)) != NULL) {
+                               zfs_handle_t *zhp;
+                               prop_changelist_t *clp = NULL;
+
+                               zhp = zfs_open(hdl, nvpair_name(pair),
+                                   ZFS_TYPE_FILESYSTEM);
+                               if (zhp != NULL) {
+                                       clp = changelist_gather(zhp,
+                                           ZFS_PROP_MOUNTPOINT, 0, 0);
+                                       zfs_close(zhp);
+                                       if (clp != NULL) {
+                                               softerr |=
+                                                   changelist_prefix(clp);
+                                               changelist_free(clp);
+                                       }
+                               }
+                       }
+
+                       nvlist_free(renamed);
+               }
+       }
+
+       /*
+        * Get the fs specified by the first path in the stream (the top level
+        * specified by 'zfs send') and pass it to each invocation of
+        * zfs_receive_one().
+        */
+       (void) strlcpy(sendfs, drr->drr_u.drr_begin.drr_toname,
+           sizeof (sendfs));
+       if ((cp = strchr(sendfs, '@')) != NULL) {
+               *cp = '\0';
+               /*
+                * Find the "sendsnap", the final snapshot in a replication
+                * stream.  zfs_receive_one() handles certain errors
+                * differently, depending on if the contained stream is the
+                * last one or not.
+                */
+               sendsnap = (cp + 1);
+       }
+
+       /* Finally, receive each contained stream */
+       do {
+               /*
+                * we should figure out if it has a recoverable
+                * error, in which case do a recv_skip() and drive on.
+                * Note, if we fail due to already having this guid,
+                * zfs_receive_one() will take care of it (ie,
+                * recv_skip() and return 0).
+                */
+               error = zfs_receive_impl(hdl, destname, NULL, flags, fd,
+                   sendfs, stream_nv, stream_avl, top_zfs, cleanup_fd,
+                   action_handlep, sendsnap);
+               if (error == ENODATA) {
+                       error = 0;
+                       break;
+               }
+               anyerr |= error;
+       } while (error == 0);
+
+       if (drr->drr_payloadlen != 0 && fromsnap != NULL) {
+               /*
+                * Now that we have the fs's they sent us, try the
+                * renames again.
+                */
+               softerr = recv_incremental_replication(hdl, tofs, flags,
+                   stream_nv, stream_avl, NULL);
+       }
+
+out:
+       fsavl_destroy(stream_avl);
+       nvlist_free(stream_nv);
+       if (softerr)
+               error = -2;
+       if (anyerr)
+               error = -1;
+       return (error);
+}
+
+static void
+trunc_prop_errs(int truncated)
+{
+       ASSERT(truncated != 0);
+
+       if (truncated == 1)
+               (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                   "1 more property could not be set\n"));
+       else
+               (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+                   "%d more properties could not be set\n"), truncated);
+}
+
+static int
+recv_skip(libzfs_handle_t *hdl, int fd, boolean_t byteswap)
+{
+       dmu_replay_record_t *drr;
+       void *buf = zfs_alloc(hdl, SPA_MAXBLOCKSIZE);
+       char errbuf[1024];
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot receive:"));
+
+       /* XXX would be great to use lseek if possible... */
+       drr = buf;
+
+       while (recv_read(hdl, fd, drr, sizeof (dmu_replay_record_t),
+           byteswap, NULL) == 0) {
+               if (byteswap)
+                       drr->drr_type = BSWAP_32(drr->drr_type);
+
+               switch (drr->drr_type) {
+               case DRR_BEGIN:
+                       if (drr->drr_payloadlen != 0) {
+                               (void) recv_read(hdl, fd, buf,
+                                   drr->drr_payloadlen, B_FALSE, NULL);
+                       }
+                       break;
+
+               case DRR_END:
+                       free(buf);
+                       return (0);
+
+               case DRR_OBJECT:
+                       if (byteswap) {
+                               drr->drr_u.drr_object.drr_bonuslen =
+                                   BSWAP_32(drr->drr_u.drr_object.
+                                   drr_bonuslen);
+                       }
+                       (void) recv_read(hdl, fd, buf,
+                           P2ROUNDUP(drr->drr_u.drr_object.drr_bonuslen, 8),
+                           B_FALSE, NULL);
+                       break;
+
+               case DRR_WRITE:
+                       if (byteswap) {
+                               drr->drr_u.drr_write.drr_logical_size =
+                                   BSWAP_64(
+                                   drr->drr_u.drr_write.drr_logical_size);
+                               drr->drr_u.drr_write.drr_compressed_size =
+                                   BSWAP_64(
+                                   drr->drr_u.drr_write.drr_compressed_size);
+                       }
+                       uint64_t payload_size =
+                           DRR_WRITE_PAYLOAD_SIZE(&drr->drr_u.drr_write);
+                       (void) recv_read(hdl, fd, buf,
+                           payload_size, B_FALSE, NULL);
+                       break;
+               case DRR_SPILL:
+                       if (byteswap) {
+                               drr->drr_u.drr_spill.drr_length =
+                                   BSWAP_64(drr->drr_u.drr_spill.drr_length);
+                       }
+                       (void) recv_read(hdl, fd, buf,
+                           drr->drr_u.drr_spill.drr_length, B_FALSE, NULL);
+                       break;
+               case DRR_WRITE_EMBEDDED:
+                       if (byteswap) {
+                               drr->drr_u.drr_write_embedded.drr_psize =
+                                   BSWAP_32(drr->drr_u.drr_write_embedded.
+                                   drr_psize);
+                       }
+                       (void) recv_read(hdl, fd, buf,
+                           P2ROUNDUP(drr->drr_u.drr_write_embedded.drr_psize,
+                           8), B_FALSE, NULL);
+                       break;
+               case DRR_WRITE_BYREF:
+               case DRR_FREEOBJECTS:
+               case DRR_FREE:
+                       break;
+
+               default:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "invalid record type"));
+                       free(buf);
+                       return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+               }
+       }
+
+       free(buf);
+       return (-1);
+}
+
+static void
+recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap,
+    boolean_t resumable)
+{
+       char target_fs[ZFS_MAX_DATASET_NAME_LEN];
+
+       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+           "checksum mismatch or incomplete stream"));
+
+       if (!resumable)
+               return;
+       (void) strlcpy(target_fs, target_snap, sizeof (target_fs));
+       *strchr(target_fs, '@') = '\0';
+       zfs_handle_t *zhp = zfs_open(hdl, target_fs,
+           ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+       if (zhp == NULL)
+               return;
+
+       char token_buf[ZFS_MAXPROPLEN];
+       int error = zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
+           token_buf, sizeof (token_buf),
+           NULL, NULL, 0, B_TRUE);
+       if (error == 0) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "checksum mismatch or incomplete stream.\n"
+                   "Partially received snapshot is saved.\n"
+                   "A resuming stream can be generated on the sending "
+                   "system by running:\n"
+                   "    zfs send -t %s"),
+                   token_buf);
+       }
+       zfs_close(zhp);
+}
+
+/*
+ * Restores a backup of tosnap from the file descriptor specified by infd.
+ */
+static int
+zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap,
+    const char *originsnap, recvflags_t *flags, dmu_replay_record_t *drr,
+    dmu_replay_record_t *drr_noswap, const char *sendfs, nvlist_t *stream_nv,
+    avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
+    uint64_t *action_handlep, const char *finalsnap)
+{
+       time_t begin_time;
+       int ioctl_err, ioctl_errno, err;
+       char *cp;
+       struct drr_begin *drrb = &drr->drr_u.drr_begin;
+       char errbuf[1024];
+       const char *chopprefix;
+       boolean_t newfs = B_FALSE;
+       boolean_t stream_wantsnewfs;
+       boolean_t newprops = B_FALSE;
+       uint64_t read_bytes = 0;
+       uint64_t errflags = 0;
+       uint64_t parent_snapguid = 0;
+       prop_changelist_t *clp = NULL;
+       nvlist_t *snapprops_nvlist = NULL;
+       zprop_errflags_t prop_errflags;
+       nvlist_t *prop_errors = NULL;
+       boolean_t recursive;
+       char *snapname = NULL;
+       char destsnap[MAXPATHLEN * 2];
+       char origin[MAXNAMELEN];
+       char name[MAXPATHLEN];
+       nvlist_t *props = NULL;
+
+       begin_time = time(NULL);
+       bzero(origin, MAXNAMELEN);
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot receive"));
+
+       recursive = (nvlist_lookup_boolean(stream_nv, "not_recursive") ==
+           ENOENT);
+
+       if (stream_avl != NULL) {
+               nvlist_t *lookup = NULL;
+               nvlist_t *fs = fsavl_find(stream_avl, drrb->drr_toguid,
+                   &snapname);
+
+               (void) nvlist_lookup_uint64(fs, "parentfromsnap",
+                   &parent_snapguid);
+               err = nvlist_lookup_nvlist(fs, "props", &props);
+               if (err) {
+                       VERIFY(0 == nvlist_alloc(&props, NV_UNIQUE_NAME, 0));
+                       newprops = B_TRUE;
+               }
+
+               if (flags->canmountoff) {
+                       VERIFY(0 == nvlist_add_uint64(props,
+                           zfs_prop_to_name(ZFS_PROP_CANMOUNT), 0));
+               }
+               if (0 == nvlist_lookup_nvlist(fs, "snapprops", &lookup)) {
+                       VERIFY(0 == nvlist_lookup_nvlist(lookup,
+                           snapname, &snapprops_nvlist));
+               }
+       }
+
+       cp = NULL;
+
+       /*
+        * Determine how much of the snapshot name stored in the stream
+        * we are going to tack on to the name they specified on the
+        * command line, and how much we are going to chop off.
+        *
+        * If they specified a snapshot, chop the entire name stored in
+        * the stream.
+        */
+       if (flags->istail) {
+               /*
+                * A filesystem was specified with -e. We want to tack on only
+                * the tail of the sent snapshot path.
+                */
+               if (strchr(tosnap, '@')) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+                           "argument - snapshot not allowed with -e"));
+                       err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+                       goto out;
+               }
+
+               chopprefix = strrchr(sendfs, '/');
+
+               if (chopprefix == NULL) {
+                       /*
+                        * The tail is the poolname, so we need to
+                        * prepend a path separator.
+                        */
+                       int len = strlen(drrb->drr_toname);
+                       cp = malloc(len + 2);
+                       cp[0] = '/';
+                       (void) strcpy(&cp[1], drrb->drr_toname);
+                       chopprefix = cp;
+               } else {
+                       chopprefix = drrb->drr_toname + (chopprefix - sendfs);
+               }
+       } else if (flags->isprefix) {
+               /*
+                * A filesystem was specified with -d. We want to tack on
+                * everything but the first element of the sent snapshot path
+                * (all but the pool name).
+                */
+               if (strchr(tosnap, '@')) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+                           "argument - snapshot not allowed with -d"));
+                       err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+                       goto out;
+               }
+
+               chopprefix = strchr(drrb->drr_toname, '/');
+               if (chopprefix == NULL)
+                       chopprefix = strchr(drrb->drr_toname, '@');
+       } else if (strchr(tosnap, '@') == NULL) {
+               /*
+                * If a filesystem was specified without -d or -e, we want to
+                * tack on everything after the fs specified by 'zfs send'.
+                */
+               chopprefix = drrb->drr_toname + strlen(sendfs);
+       } else {
+               /* A snapshot was specified as an exact path (no -d or -e). */
+               if (recursive) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "cannot specify snapshot name for multi-snapshot "
+                           "stream"));
+                       err = zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+                       goto out;
+               }
+               chopprefix = drrb->drr_toname + strlen(drrb->drr_toname);
+       }
+
+       ASSERT(strstr(drrb->drr_toname, sendfs) == drrb->drr_toname);
+       ASSERT(chopprefix > drrb->drr_toname);
+       ASSERT(chopprefix <= drrb->drr_toname + strlen(drrb->drr_toname));
+       ASSERT(chopprefix[0] == '/' || chopprefix[0] == '@' ||
+           chopprefix[0] == '\0');
+
+       /*
+        * Determine name of destination snapshot.
+        */
+       (void) strlcpy(destsnap, tosnap, sizeof (destsnap));
+       (void) strlcat(destsnap, chopprefix, sizeof (destsnap));
+       free(cp);
+       if (!zfs_name_valid(destsnap, ZFS_TYPE_SNAPSHOT)) {
+               err = zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
+               goto out;
+       }
+
+       /*
+        * Determine the name of the origin snapshot.
+        */
+       if (drrb->drr_flags & DRR_FLAG_CLONE) {
+               if (guid_to_name(hdl, destsnap,
+                   drrb->drr_fromguid, B_FALSE, origin) != 0) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "local origin for clone %s does not exist"),
+                           destsnap);
+                       err = zfs_error(hdl, EZFS_NOENT, errbuf);
+                       goto out;
+               }
+               if (flags->verbose)
+                       (void) printf("found clone origin %s\n", origin);
+       } else if (originsnap) {
+               (void) strncpy(origin, originsnap, sizeof (origin));
+               if (flags->verbose)
+                       (void) printf("using provided clone origin %s\n",
+                           origin);
+       }
+
+       boolean_t resuming = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+           DMU_BACKUP_FEATURE_RESUMING;
+       stream_wantsnewfs = (drrb->drr_fromguid == 0 ||
+           (drrb->drr_flags & DRR_FLAG_CLONE) || originsnap) && !resuming;
+
+       if (stream_wantsnewfs) {
+               /*
+                * if the parent fs does not exist, look for it based on
+                * the parent snap GUID
+                */
+               (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+                   "cannot receive new filesystem stream"));
+
+               (void) strcpy(name, destsnap);
+               cp = strrchr(name, '/');
+               if (cp)
+                       *cp = '\0';
+               if (cp &&
+                   !zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {
+                       char suffix[ZFS_MAX_DATASET_NAME_LEN];
+                       (void) strcpy(suffix, strrchr(destsnap, '/'));
+                       if (guid_to_name(hdl, name, parent_snapguid,
+                           B_FALSE, destsnap) == 0) {
+                               *strchr(destsnap, '@') = '\0';
+                               (void) strcat(destsnap, suffix);
+                       }
+               }
+       } else {
+               /*
+                * if the fs does not exist, look for it based on the
+                * fromsnap GUID
+                */
+               (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+                   "cannot receive incremental stream"));
+
+               (void) strcpy(name, destsnap);
+               *strchr(name, '@') = '\0';
+
+               /*
+                * If the exact receive path was specified and this is the
+                * topmost path in the stream, then if the fs does not exist we
+                * should look no further.
+                */
+               if ((flags->isprefix || (*(chopprefix = drrb->drr_toname +
+                   strlen(sendfs)) != '\0' && *chopprefix != '@')) &&
+                   !zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {
+                       char snap[ZFS_MAX_DATASET_NAME_LEN];
+                       (void) strcpy(snap, strchr(destsnap, '@'));
+                       if (guid_to_name(hdl, name, drrb->drr_fromguid,
+                           B_FALSE, destsnap) == 0) {
+                               *strchr(destsnap, '@') = '\0';
+                               (void) strcat(destsnap, snap);
+                       }
+               }
+       }
+
+       (void) strcpy(name, destsnap);
+       *strchr(name, '@') = '\0';
+
+       if (zfs_dataset_exists(hdl, name, ZFS_TYPE_DATASET)) {
+               zfs_cmd_t zc = {"\0"};
+               zfs_handle_t *zhp;
+
+               (void) strcpy(zc.zc_name, name);
+
+               /*
+                * Destination fs exists.  It must be one of these cases:
+                *  - an incremental send stream
+                *  - the stream specifies a new fs (full stream or clone)
+                *    and they want us to blow away the existing fs (and
+                *    have therefore specified -F and removed any snapshots)
+                *  - we are resuming a failed receive.
+                */
+               if (stream_wantsnewfs) {
+                       if (!flags->force) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "destination '%s' exists\n"
+                                   "must specify -F to overwrite it"), name);
+                               err = zfs_error(hdl, EZFS_EXISTS, errbuf);
+                               goto out;
+                       }
+                       if (ioctl(hdl->libzfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT,
+                           &zc) == 0) {
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "destination has snapshots (eg. %s)\n"
+                                   "must destroy them to overwrite it"),
+                                   name);
+                               err = zfs_error(hdl, EZFS_EXISTS, errbuf);
+                               goto out;
+                       }
+               }
+
+               if ((zhp = zfs_open(hdl, name,
+                   ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
+                       err = -1;
+                       goto out;
+               }
+
+               if (stream_wantsnewfs &&
+                   zhp->zfs_dmustats.dds_origin[0]) {
+                       zfs_close(zhp);
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "destination '%s' is a clone\n"
+                           "must destroy it to overwrite it"), name);
+                       err = zfs_error(hdl, EZFS_EXISTS, errbuf);
+                       goto out;
+               }
+
+               if (!flags->dryrun && zhp->zfs_type == ZFS_TYPE_FILESYSTEM &&
+                   stream_wantsnewfs) {
+                       /* We can't do online recv in this case */
+                       clp = changelist_gather(zhp, ZFS_PROP_NAME, 0, 0);
+                       if (clp == NULL) {
+                               zfs_close(zhp);
+                               err = -1;
+                               goto out;
+                       }
+                       if (changelist_prefix(clp) != 0) {
+                               changelist_free(clp);
+                               zfs_close(zhp);
+                               err = -1;
+                               goto out;
+                       }
+               }
+
+               /*
+                * If we are resuming a newfs, set newfs here so that we will
+                * mount it if the recv succeeds this time.  We can tell
+                * that it was a newfs on the first recv because the fs
+                * itself will be inconsistent (if the fs existed when we
+                * did the first recv, we would have received it into
+                * .../%recv).
+                */
+               if (resuming && zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT))
+                       newfs = B_TRUE;
+
+               zfs_close(zhp);
+       } else {
+               /*
+                * Destination filesystem does not exist.  Therefore we better
+                * be creating a new filesystem (either from a full backup, or
+                * a clone).  It would therefore be invalid if the user
+                * specified only the pool name (i.e. if the destination name
+                * contained no slash character).
+                */
+               cp = strrchr(name, '/');
+
+               if (!stream_wantsnewfs || cp == NULL) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "destination '%s' does not exist"), name);
+                       err = zfs_error(hdl, EZFS_NOENT, errbuf);
+                       goto out;
+               }
+
+               /*
+                * Trim off the final dataset component so we perform the
+                * recvbackup ioctl to the filesystems's parent.
+                */
+               *cp = '\0';
+
+               if (flags->isprefix && !flags->istail && !flags->dryrun &&
+                   create_parents(hdl, destsnap, strlen(tosnap)) != 0) {
+                       err = zfs_error(hdl, EZFS_BADRESTORE, errbuf);
+                       goto out;
+               }
+
+               newfs = B_TRUE;
+       }
+
+       if (flags->verbose) {
+               (void) printf("%s %s stream of %s into %s\n",
+                   flags->dryrun ? "would receive" : "receiving",
+                   drrb->drr_fromguid ? "incremental" : "full",
+                   drrb->drr_toname, destsnap);
+               (void) fflush(stdout);
+       }
+
+       if (flags->dryrun) {
+               err = recv_skip(hdl, infd, flags->byteswap);
+               goto out;
+       }
+
+       err = ioctl_err = lzc_receive_one(destsnap, props, origin,
+           flags->force, flags->resumable, infd, drr_noswap, cleanup_fd,
+           &read_bytes, &errflags, action_handlep, &prop_errors);
+       ioctl_errno = ioctl_err;
+       prop_errflags = errflags;
+
+       if (err == 0) {
+               nvpair_t *prop_err = NULL;
+
+               while ((prop_err = nvlist_next_nvpair(prop_errors,
+                   prop_err)) != NULL) {
+                       char tbuf[1024];
+                       zfs_prop_t prop;
+                       int intval;
+
+                       prop = zfs_name_to_prop(nvpair_name(prop_err));
+                       (void) nvpair_value_int32(prop_err, &intval);
+                       if (strcmp(nvpair_name(prop_err),
+                           ZPROP_N_MORE_ERRORS) == 0) {
+                               trunc_prop_errs(intval);
+                               break;
+                       } else if (snapname == NULL || finalsnap == NULL ||
+                           strcmp(finalsnap, snapname) == 0 ||
+                           strcmp(nvpair_name(prop_err),
+                           zfs_prop_to_name(ZFS_PROP_REFQUOTA)) != 0) {
+                               /*
+                                * Skip the special case of, for example,
+                                * "refquota", errors on intermediate
+                                * snapshots leading up to a final one.
+                                * That's why we have all of the checks above.
+                                *
+                                * See zfs_ioctl.c's extract_delay_props() for
+                                * a list of props which can fail on
+                                * intermediate snapshots, but shouldn't
+                                * affect the overall receive.
+                                */
+                               (void) snprintf(tbuf, sizeof (tbuf),
+                                   dgettext(TEXT_DOMAIN,
+                                   "cannot receive %s property on %s"),
+                                   nvpair_name(prop_err), name);
+                               zfs_setprop_error(hdl, prop, intval, tbuf);
+                       }
+               }
+       }
+
+       if (err == 0 && snapprops_nvlist) {
+               zfs_cmd_t zc = {"\0"};
+
+               (void) strcpy(zc.zc_name, destsnap);
+               zc.zc_cookie = B_TRUE; /* received */
+               if (zcmd_write_src_nvlist(hdl, &zc, snapprops_nvlist) == 0) {
+                       (void) zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
+                       zcmd_free_nvlists(&zc);
+               }
+       }
+
+       if (err && (ioctl_errno == ENOENT || ioctl_errno == EEXIST)) {
+               /*
+                * It may be that this snapshot already exists,
+                * in which case we want to consume & ignore it
+                * rather than failing.
+                */
+               avl_tree_t *local_avl;
+               nvlist_t *local_nv, *fs;
+               cp = strchr(destsnap, '@');
+
+               /*
+                * XXX Do this faster by just iterating over snaps in
+                * this fs.  Also if zc_value does not exist, we will
+                * get a strange "does not exist" error message.
+                */
+               *cp = '\0';
+               if (gather_nvlist(hdl, destsnap, NULL, NULL, B_FALSE,
+                   B_FALSE, &local_nv, &local_avl) == 0) {
+                       *cp = '@';
+                       fs = fsavl_find(local_avl, drrb->drr_toguid, NULL);
+                       fsavl_destroy(local_avl);
+                       nvlist_free(local_nv);
+
+                       if (fs != NULL) {
+                               if (flags->verbose) {
+                                       (void) printf("snap %s already exists; "
+                                           "ignoring\n", destsnap);
+                               }
+                               err = ioctl_err = recv_skip(hdl, infd,
+                                   flags->byteswap);
+                       }
+               }
+               *cp = '@';
+       }
+
+       if (ioctl_err != 0) {
+               switch (ioctl_errno) {
+               case ENODEV:
+                       cp = strchr(destsnap, '@');
+                       *cp = '\0';
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "most recent snapshot of %s does not\n"
+                           "match incremental source"), destsnap);
+                       (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
+                       *cp = '@';
+                       break;
+               case ETXTBSY:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "destination %s has been modified\n"
+                           "since most recent snapshot"), name);
+                       (void) zfs_error(hdl, EZFS_BADRESTORE, errbuf);
+                       break;
+               case EEXIST:
+                       cp = strchr(destsnap, '@');
+                       if (newfs) {
+                               /* it's the containing fs that exists */
+                               *cp = '\0';
+                       }
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "destination already exists"));
+                       (void) zfs_error_fmt(hdl, EZFS_EXISTS,
+                           dgettext(TEXT_DOMAIN, "cannot restore to %s"),
+                           destsnap);
+                       *cp = '@';
+                       break;
+               case EINVAL:
+                       if (flags->resumable)
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "kernel modules must be upgraded to "
+                                   "receive this stream."));
+                       (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+                       break;
+               case ECKSUM:
+                       recv_ecksum_set_aux(hdl, destsnap, flags->resumable);
+                       (void) zfs_error(hdl, EZFS_BADSTREAM, errbuf);
+                       break;
+               case ENOTSUP:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "pool must be upgraded to receive this stream."));
+                       (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
+                       break;
+               case EDQUOT:
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "destination %s space quota exceeded"), name);
+                       (void) zfs_error(hdl, EZFS_NOSPC, errbuf);
+                       break;
+               default:
+                       (void) zfs_standard_error(hdl, ioctl_errno, errbuf);
+               }
+       }
+
+       /*
+        * Mount the target filesystem (if created).  Also mount any
+        * children of the target filesystem if we did a replication
+        * receive (indicated by stream_avl being non-NULL).
+        */
+       cp = strchr(destsnap, '@');
+       if (cp && (ioctl_err == 0 || !newfs)) {
+               zfs_handle_t *h;
+
+               *cp = '\0';
+               h = zfs_open(hdl, destsnap,
+                   ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);
+               if (h != NULL) {
+                       if (h->zfs_type == ZFS_TYPE_VOLUME) {
+                               *cp = '@';
+                       } else if (newfs || stream_avl) {
+                               /*
+                                * Track the first/top of hierarchy fs,
+                                * for mounting and sharing later.
+                                */
+                               if (top_zfs && *top_zfs == NULL)
+                                       *top_zfs = zfs_strdup(hdl, destsnap);
+                       }
+                       zfs_close(h);
+               }
+               *cp = '@';
+       }
+
+       if (clp) {
+               err |= changelist_postfix(clp);
+               changelist_free(clp);
+       }
+
+       if (prop_errflags & ZPROP_ERR_NOCLEAR) {
+               (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "
+                   "failed to clear unreceived properties on %s"), name);
+               (void) fprintf(stderr, "\n");
+       }
+       if (prop_errflags & ZPROP_ERR_NORESTORE) {
+               (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: "
+                   "failed to restore original properties on %s"), name);
+               (void) fprintf(stderr, "\n");
+       }
+
+       if (err || ioctl_err) {
+               err = -1;
+               goto out;
+       }
+
+       if (flags->verbose) {
+               char buf1[64];
+               char buf2[64];
+               uint64_t bytes = read_bytes;
+               time_t delta = time(NULL) - begin_time;
+               if (delta == 0)
+                       delta = 1;
+               zfs_nicenum(bytes, buf1, sizeof (buf1));
+               zfs_nicenum(bytes/delta, buf2, sizeof (buf1));
+
+               (void) printf("received %sB stream in %lu seconds (%sB/sec)\n",
+                   buf1, delta, buf2);
+       }
+
+       err = 0;
+out:
+       if (prop_errors != NULL)
+               nvlist_free(prop_errors);
+
+       if (newprops)
+               nvlist_free(props);
+
+       return (err);
+}
+
+static int
+zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap,
+    const char *originsnap, recvflags_t *flags, int infd, const char *sendfs,
+    nvlist_t *stream_nv, avl_tree_t *stream_avl, char **top_zfs, int cleanup_fd,
+    uint64_t *action_handlep, const char *finalsnap)
+{
+       int err;
+       dmu_replay_record_t drr, drr_noswap;
+       struct drr_begin *drrb = &drr.drr_u.drr_begin;
+       char errbuf[1024];
+       zio_cksum_t zcksum = { { 0 } };
+       uint64_t featureflags;
+       int hdrtype;
+
+       (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
+           "cannot receive"));
+
+       if (flags->isprefix &&
+           !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs "
+                   "(%s) does not exist"), tosnap);
+               return (zfs_error(hdl, EZFS_NOENT, errbuf));
+       }
+       if (originsnap &&
+           !zfs_dataset_exists(hdl, originsnap, ZFS_TYPE_DATASET)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified origin fs "
+                   "(%s) does not exist"), originsnap);
+               return (zfs_error(hdl, EZFS_NOENT, errbuf));
+       }
+
+       /* read in the BEGIN record */
+       if (0 != (err = recv_read(hdl, infd, &drr, sizeof (drr), B_FALSE,
+           &zcksum)))
+               return (err);
+
+       if (drr.drr_type == DRR_END || drr.drr_type == BSWAP_32(DRR_END)) {
+               /* It's the double end record at the end of a package */
+               return (ENODATA);
+       }
+
+       /* the kernel needs the non-byteswapped begin record */
+       drr_noswap = drr;
+
+       flags->byteswap = B_FALSE;
+       if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
+               /*
+                * We computed the checksum in the wrong byteorder in
+                * recv_read() above; do it again correctly.
+                */
+               bzero(&zcksum, sizeof (zio_cksum_t));
+               fletcher_4_incremental_byteswap(&drr, sizeof (drr), &zcksum);
+               flags->byteswap = B_TRUE;
+
+               drr.drr_type = BSWAP_32(drr.drr_type);
+               drr.drr_payloadlen = BSWAP_32(drr.drr_payloadlen);
+               drrb->drr_magic = BSWAP_64(drrb->drr_magic);
+               drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo);
+               drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
+               drrb->drr_type = BSWAP_32(drrb->drr_type);
+               drrb->drr_flags = BSWAP_32(drrb->drr_flags);
+               drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
+               drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
+       }
+
+       if (drrb->drr_magic != DMU_BACKUP_MAGIC || drr.drr_type != DRR_BEGIN) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+                   "stream (bad magic number)"));
+               return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+       }
+
+       featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+       hdrtype = DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo);
+
+       if (!DMU_STREAM_SUPPORTED(featureflags) ||
+           (hdrtype != DMU_SUBSTREAM && hdrtype != DMU_COMPOUNDSTREAM)) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "stream has unsupported feature, feature flags = %lx"),
+                   featureflags);
+               return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+       }
+
+       if (strchr(drrb->drr_toname, '@') == NULL) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "invalid "
+                   "stream (bad snapshot name)"));
+               return (zfs_error(hdl, EZFS_BADSTREAM, errbuf));
+       }
+
+       if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) == DMU_SUBSTREAM) {
+               char nonpackage_sendfs[ZFS_MAX_DATASET_NAME_LEN];
+               if (sendfs == NULL) {
+                       /*
+                        * We were not called from zfs_receive_package(). Get
+                        * the fs specified by 'zfs send'.
+                        */
+                       char *cp;
+                       (void) strlcpy(nonpackage_sendfs,
+                           drr.drr_u.drr_begin.drr_toname,
+                           sizeof (nonpackage_sendfs));
+                       if ((cp = strchr(nonpackage_sendfs, '@')) != NULL)
+                               *cp = '\0';
+                       sendfs = nonpackage_sendfs;
+                       VERIFY(finalsnap == NULL);
+               }
+               return (zfs_receive_one(hdl, infd, tosnap, originsnap, flags,
+                   &drr, &drr_noswap, sendfs, stream_nv, stream_avl, top_zfs,
+                   cleanup_fd, action_handlep, finalsnap));
+       } else {
+               assert(DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
+                   DMU_COMPOUNDSTREAM);
+               return (zfs_receive_package(hdl, infd, tosnap, flags, &drr,
+                   &zcksum, top_zfs, cleanup_fd, action_handlep));
+       }
+}
+
+/*
+ * Restores a backup of tosnap from the file descriptor specified by infd.
+ * Return 0 on total success, -2 if some things couldn't be
+ * destroyed/renamed/promoted, -1 if some things couldn't be received.
+ * (-1 will override -2, if -1 and the resumable flag was specified the
+ * transfer can be resumed if the sending side supports it).
+ */
+int
+zfs_receive(libzfs_handle_t *hdl, const char *tosnap, nvlist_t *props,
+    recvflags_t *flags, int infd, avl_tree_t *stream_avl)
+{
+       char *top_zfs = NULL;
+       int err;
+       int cleanup_fd;
+       uint64_t action_handle = 0;
+       struct stat sb;
+       char *originsnap = NULL;
+
+       /*
+        * The only way fstat can fail is if we do not have a valid file
+        * descriptor.
+        */
+       if (fstat(infd, &sb) == -1) {
+               perror("fstat");
+               return (-2);
+       }
+
+#ifdef __linux__
+#ifndef F_SETPIPE_SZ
+#define        F_SETPIPE_SZ (F_SETLEASE + 7)
+#endif /* F_SETPIPE_SZ */
+
+#ifndef F_GETPIPE_SZ
+#define        F_GETPIPE_SZ (F_GETLEASE + 7)
+#endif /* F_GETPIPE_SZ */
+
+       /*
+        * It is not uncommon for gigabytes to be processed in zfs receive.
+        * Speculatively increase the buffer size via Linux-specific fcntl()
+        * call.
+        */
+       if (S_ISFIFO(sb.st_mode)) {
+               FILE *procf = fopen("/proc/sys/fs/pipe-max-size", "r");
+
+               if (procf != NULL) {
+                       unsigned long max_psize;
+                       long cur_psize;
+                       if (fscanf(procf, "%lu", &max_psize) > 0) {
+                               cur_psize = fcntl(infd, F_GETPIPE_SZ);
+                               if (cur_psize > 0 &&
+                                   max_psize > (unsigned long) cur_psize)
+                                       (void) fcntl(infd, F_SETPIPE_SZ,
+                                           max_psize);
+                       }
+                       fclose(procf);
+               }
+       }
+#endif /* __linux__ */
+
+       if (props) {
+               err = nvlist_lookup_string(props, "origin", &originsnap);
+               if (err && err != ENOENT)
+                       return (err);
+       }
+
+       cleanup_fd = open(ZFS_DEV, O_RDWR);
+       VERIFY(cleanup_fd >= 0);
+
+       err = zfs_receive_impl(hdl, tosnap, originsnap, flags, infd, NULL, NULL,
+           stream_avl, &top_zfs, cleanup_fd, &action_handle, NULL);
+
+       VERIFY(0 == close(cleanup_fd));
+
+       if (err == 0 && !flags->nomount && top_zfs) {
+               zfs_handle_t *zhp = NULL;
+               prop_changelist_t *clp = NULL;
+
+               zhp = zfs_open(hdl, top_zfs, ZFS_TYPE_FILESYSTEM);
+               if (zhp != NULL) {
+                       clp = changelist_gather(zhp, ZFS_PROP_MOUNTPOINT,
+                           CL_GATHER_MOUNT_ALWAYS, 0);
+                       zfs_close(zhp);
+                       if (clp != NULL) {
+                               /* mount and share received datasets */
+                               err = changelist_postfix(clp);
+                               changelist_free(clp);
+                       }
+               }
+               if (zhp == NULL || clp == NULL || err)
+                       err = -1;
+       }
+       if (top_zfs)
+               free(top_zfs);
+
+       return (err);
+}
diff --git a/zfs/lib/libzfs/libzfs_status.c b/zfs/lib/libzfs/libzfs_status.c
new file mode 100644 (file)
index 0000000..f69bd45
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ */
+
+/*
+ * This file contains the functions which analyze the status of a pool.  This
+ * include both the status of an active pool, as well as the status exported
+ * pools.  Returns one of the ZPOOL_STATUS_* defines describing the status of
+ * the pool.  This status is independent (to a certain degree) from the state of
+ * the pool.  A pool's state describes only whether or not it is capable of
+ * providing the necessary fault tolerance for data.  The status describes the
+ * overall status of devices.  A pool that is online can still have a device
+ * that is experiencing errors.
+ *
+ * Only a subset of the possible faults can be detected using 'zpool status',
+ * and not all possible errors correspond to a FMA message ID.  The explanation
+ * is left up to the caller, depending on whether it is a live pool or an
+ * import.
+ */
+
+#include <libzfs.h>
+#include <string.h>
+#include <unistd.h>
+#include "libzfs_impl.h"
+#include "zfeature_common.h"
+
+/*
+ * Message ID table.  This must be kept in sync with the ZPOOL_STATUS_* defines
+ * in libzfs.h.  Note that there are some status results which go past the end
+ * of this table, and hence have no associated message ID.
+ */
+static char *zfs_msgid_table[] = {
+       "ZFS-8000-14",
+       "ZFS-8000-2Q",
+       "ZFS-8000-3C",
+       "ZFS-8000-4J",
+       "ZFS-8000-5E",
+       "ZFS-8000-6X",
+       "ZFS-8000-72",
+       "ZFS-8000-8A",
+       "ZFS-8000-9P",
+       "ZFS-8000-A5",
+       "ZFS-8000-EY",
+       "ZFS-8000-HC",
+       "ZFS-8000-JQ",
+       "ZFS-8000-K4",
+       "ZFS-8000-ER",
+};
+
+#define        NMSGID  (sizeof (zfs_msgid_table) / sizeof (zfs_msgid_table[0]))
+
+/* ARGSUSED */
+static int
+vdev_missing(uint64_t state, uint64_t aux, uint64_t errs)
+{
+       return (state == VDEV_STATE_CANT_OPEN &&
+           aux == VDEV_AUX_OPEN_FAILED);
+}
+
+/* ARGSUSED */
+static int
+vdev_faulted(uint64_t state, uint64_t aux, uint64_t errs)
+{
+       return (state == VDEV_STATE_FAULTED);
+}
+
+/* ARGSUSED */
+static int
+vdev_errors(uint64_t state, uint64_t aux, uint64_t errs)
+{
+       return (state == VDEV_STATE_DEGRADED || errs != 0);
+}
+
+/* ARGSUSED */
+static int
+vdev_broken(uint64_t state, uint64_t aux, uint64_t errs)
+{
+       return (state == VDEV_STATE_CANT_OPEN);
+}
+
+/* ARGSUSED */
+static int
+vdev_offlined(uint64_t state, uint64_t aux, uint64_t errs)
+{
+       return (state == VDEV_STATE_OFFLINE);
+}
+
+/* ARGSUSED */
+static int
+vdev_removed(uint64_t state, uint64_t aux, uint64_t errs)
+{
+       return (state == VDEV_STATE_REMOVED);
+}
+
+/*
+ * Detect if any leaf devices that have seen errors or could not be opened.
+ */
+static boolean_t
+find_vdev_problem(nvlist_t *vdev, int (*func)(uint64_t, uint64_t, uint64_t))
+{
+       nvlist_t **child;
+       vdev_stat_t *vs;
+       uint_t c, children;
+       char *type;
+
+       /*
+        * Ignore problems within a 'replacing' vdev, since we're presumably in
+        * the process of repairing any such errors, and don't want to call them
+        * out again.  We'll pick up the fact that a resilver is happening
+        * later.
+        */
+       verify(nvlist_lookup_string(vdev, ZPOOL_CONFIG_TYPE, &type) == 0);
+       if (strcmp(type, VDEV_TYPE_REPLACING) == 0)
+               return (B_FALSE);
+
+       if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_CHILDREN, &child,
+           &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if (find_vdev_problem(child[c], func))
+                               return (B_TRUE);
+       } else {
+               verify(nvlist_lookup_uint64_array(vdev, ZPOOL_CONFIG_VDEV_STATS,
+                   (uint64_t **)&vs, &c) == 0);
+
+               if (func(vs->vs_state, vs->vs_aux,
+                   vs->vs_read_errors +
+                   vs->vs_write_errors +
+                   vs->vs_checksum_errors))
+                       return (B_TRUE);
+       }
+
+       /*
+        * Check any L2 cache devs
+        */
+       if (nvlist_lookup_nvlist_array(vdev, ZPOOL_CONFIG_L2CACHE, &child,
+           &children) == 0) {
+               for (c = 0; c < children; c++)
+                       if (find_vdev_problem(child[c], func))
+                               return (B_TRUE);
+       }
+
+       return (B_FALSE);
+}
+
+/*
+ * Active pool health status.
+ *
+ * To determine the status for a pool, we make several passes over the config,
+ * picking the most egregious error we find.  In order of importance, we do the
+ * following:
+ *
+ *     - Check for a complete and valid configuration
+ *     - Look for any faulted or missing devices in a non-replicated config
+ *     - Check for any data errors
+ *     - Check for any faulted or missing devices in a replicated config
+ *     - Look for any devices showing errors
+ *     - Check for any resilvering devices
+ *
+ * There can obviously be multiple errors within a single pool, so this routine
+ * only picks the most damaging of all the current errors to report.
+ */
+static zpool_status_t
+check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap)
+{
+       nvlist_t *nvroot;
+       vdev_stat_t *vs;
+       pool_scan_stat_t *ps = NULL;
+       uint_t vsc, psc;
+       uint64_t nerr;
+       uint64_t version;
+       uint64_t stateval;
+       uint64_t suspended;
+       uint64_t hostid = 0;
+       uint64_t errata = 0;
+       unsigned long system_hostid = get_system_hostid();
+
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_VERSION,
+           &version) == 0);
+       verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+       verify(nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t **)&vs, &vsc) == 0);
+       verify(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_STATE,
+           &stateval) == 0);
+
+       /*
+        * Currently resilvering a vdev
+        */
+       (void) nvlist_lookup_uint64_array(nvroot, ZPOOL_CONFIG_SCAN_STATS,
+           (uint64_t **)&ps, &psc);
+       if (ps && ps->pss_func == POOL_SCAN_RESILVER &&
+           ps->pss_state == DSS_SCANNING)
+               return (ZPOOL_STATUS_RESILVERING);
+
+       /*
+        * Pool last accessed by another system.
+        */
+       (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_HOSTID, &hostid);
+       if (hostid != 0 && (unsigned long)hostid != system_hostid &&
+           stateval == POOL_STATE_ACTIVE)
+               return (ZPOOL_STATUS_HOSTID_MISMATCH);
+
+       /*
+        * Newer on-disk version.
+        */
+       if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+           vs->vs_aux == VDEV_AUX_VERSION_NEWER)
+               return (ZPOOL_STATUS_VERSION_NEWER);
+
+       /*
+        * Unsupported feature(s).
+        */
+       if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+           vs->vs_aux == VDEV_AUX_UNSUP_FEAT) {
+               nvlist_t *nvinfo;
+
+               verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_LOAD_INFO,
+                   &nvinfo) == 0);
+               if (nvlist_exists(nvinfo, ZPOOL_CONFIG_CAN_RDONLY))
+                       return (ZPOOL_STATUS_UNSUP_FEAT_WRITE);
+               return (ZPOOL_STATUS_UNSUP_FEAT_READ);
+       }
+
+       /*
+        * Check that the config is complete.
+        */
+       if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+           vs->vs_aux == VDEV_AUX_BAD_GUID_SUM)
+               return (ZPOOL_STATUS_BAD_GUID_SUM);
+
+       /*
+        * Check whether the pool has suspended due to failed I/O.
+        */
+       if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_SUSPENDED,
+           &suspended) == 0) {
+               if (suspended == ZIO_FAILURE_MODE_CONTINUE)
+                       return (ZPOOL_STATUS_IO_FAILURE_CONTINUE);
+               return (ZPOOL_STATUS_IO_FAILURE_WAIT);
+       }
+
+       /*
+        * Could not read a log.
+        */
+       if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+           vs->vs_aux == VDEV_AUX_BAD_LOG) {
+               return (ZPOOL_STATUS_BAD_LOG);
+       }
+
+       /*
+        * Bad devices in non-replicated config.
+        */
+       if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+           find_vdev_problem(nvroot, vdev_faulted))
+               return (ZPOOL_STATUS_FAULTED_DEV_NR);
+
+       if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+           find_vdev_problem(nvroot, vdev_missing))
+               return (ZPOOL_STATUS_MISSING_DEV_NR);
+
+       if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+           find_vdev_problem(nvroot, vdev_broken))
+               return (ZPOOL_STATUS_CORRUPT_LABEL_NR);
+
+       /*
+        * Corrupted pool metadata
+        */
+       if (vs->vs_state == VDEV_STATE_CANT_OPEN &&
+           vs->vs_aux == VDEV_AUX_CORRUPT_DATA)
+               return (ZPOOL_STATUS_CORRUPT_POOL);
+
+       /*
+        * Persistent data errors.
+        */
+       if (!isimport) {
+               if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
+                   &nerr) == 0 && nerr != 0)
+                       return (ZPOOL_STATUS_CORRUPT_DATA);
+       }
+
+       /*
+        * Missing devices in a replicated config.
+        */
+       if (find_vdev_problem(nvroot, vdev_faulted))
+               return (ZPOOL_STATUS_FAULTED_DEV_R);
+       if (find_vdev_problem(nvroot, vdev_missing))
+               return (ZPOOL_STATUS_MISSING_DEV_R);
+       if (find_vdev_problem(nvroot, vdev_broken))
+               return (ZPOOL_STATUS_CORRUPT_LABEL_R);
+
+       /*
+        * Devices with errors
+        */
+       if (!isimport && find_vdev_problem(nvroot, vdev_errors))
+               return (ZPOOL_STATUS_FAILING_DEV);
+
+       /*
+        * Offlined devices
+        */
+       if (find_vdev_problem(nvroot, vdev_offlined))
+               return (ZPOOL_STATUS_OFFLINE_DEV);
+
+       /*
+        * Removed device
+        */
+       if (find_vdev_problem(nvroot, vdev_removed))
+               return (ZPOOL_STATUS_REMOVED_DEV);
+
+       /*
+        * Outdated, but usable, version
+        */
+       if (SPA_VERSION_IS_SUPPORTED(version) && version != SPA_VERSION)
+               return (ZPOOL_STATUS_VERSION_OLDER);
+
+       /*
+        * Usable pool with disabled features
+        */
+       if (version >= SPA_VERSION_FEATURES) {
+               int i;
+               nvlist_t *feat;
+
+               if (isimport) {
+                       feat = fnvlist_lookup_nvlist(config,
+                           ZPOOL_CONFIG_LOAD_INFO);
+                       feat = fnvlist_lookup_nvlist(feat,
+                           ZPOOL_CONFIG_ENABLED_FEAT);
+               } else {
+                       feat = fnvlist_lookup_nvlist(config,
+                           ZPOOL_CONFIG_FEATURE_STATS);
+               }
+
+               for (i = 0; i < SPA_FEATURES; i++) {
+                       zfeature_info_t *fi = &spa_feature_table[i];
+                       if (!nvlist_exists(feat, fi->fi_guid))
+                               return (ZPOOL_STATUS_FEAT_DISABLED);
+               }
+       }
+
+       /*
+        * Informational errata available.
+        */
+       (void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRATA, &errata);
+       if (errata) {
+               *erratap = errata;
+               return (ZPOOL_STATUS_ERRATA);
+       }
+
+       return (ZPOOL_STATUS_OK);
+}
+
+zpool_status_t
+zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata)
+{
+       zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata);
+
+       if (ret >= NMSGID)
+               *msgid = NULL;
+       else
+               *msgid = zfs_msgid_table[ret];
+
+       return (ret);
+}
+
+zpool_status_t
+zpool_import_status(nvlist_t *config, char **msgid, zpool_errata_t *errata)
+{
+       zpool_status_t ret = check_status(config, B_TRUE, errata);
+
+       if (ret >= NMSGID)
+               *msgid = NULL;
+       else
+               *msgid = zfs_msgid_table[ret];
+
+       return (ret);
+}
+
+static void
+dump_ddt_stat(const ddt_stat_t *dds, int h)
+{
+       char refcnt[6];
+       char blocks[6], lsize[6], psize[6], dsize[6];
+       char ref_blocks[6], ref_lsize[6], ref_psize[6], ref_dsize[6];
+
+       if (dds == NULL || dds->dds_blocks == 0)
+               return;
+
+       if (h == -1)
+               (void) strcpy(refcnt, "Total");
+       else
+               zfs_nicenum(1ULL << h, refcnt, sizeof (refcnt));
+
+       zfs_nicenum(dds->dds_blocks, blocks, sizeof (blocks));
+       zfs_nicenum(dds->dds_lsize, lsize, sizeof (lsize));
+       zfs_nicenum(dds->dds_psize, psize, sizeof (psize));
+       zfs_nicenum(dds->dds_dsize, dsize, sizeof (dsize));
+       zfs_nicenum(dds->dds_ref_blocks, ref_blocks, sizeof (ref_blocks));
+       zfs_nicenum(dds->dds_ref_lsize, ref_lsize, sizeof (ref_lsize));
+       zfs_nicenum(dds->dds_ref_psize, ref_psize, sizeof (ref_psize));
+       zfs_nicenum(dds->dds_ref_dsize, ref_dsize, sizeof (ref_dsize));
+
+       (void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
+           refcnt,
+           blocks, lsize, psize, dsize,
+           ref_blocks, ref_lsize, ref_psize, ref_dsize);
+}
+
+/*
+ * Print the DDT histogram and the column totals.
+ */
+void
+zpool_dump_ddt(const ddt_stat_t *dds_total, const ddt_histogram_t *ddh)
+{
+       int h;
+
+       (void) printf("\n");
+
+       (void) printf("bucket   "
+           "           allocated             "
+           "          referenced          \n");
+       (void) printf("______   "
+           "______________________________   "
+           "______________________________\n");
+
+       (void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
+           "refcnt",
+           "blocks", "LSIZE", "PSIZE", "DSIZE",
+           "blocks", "LSIZE", "PSIZE", "DSIZE");
+
+       (void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
+           "------",
+           "------", "-----", "-----", "-----",
+           "------", "-----", "-----", "-----");
+
+       for (h = 0; h < 64; h++)
+               dump_ddt_stat(&ddh->ddh_stat[h], h);
+
+       dump_ddt_stat(dds_total, -1);
+
+       (void) printf("\n");
+}
diff --git a/zfs/lib/libzfs/libzfs_util.c b/zfs/lib/libzfs/libzfs_util.c
new file mode 100644 (file)
index 0000000..ca32e7a
--- /dev/null
@@ -0,0 +1,1924 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ */
+
+/*
+ * Internal utility routines for the ZFS library.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <math.h>
+#include <sys/stat.h>
+#include <sys/mnttab.h>
+#include <sys/mntent.h>
+#include <sys/types.h>
+#include <wait.h>
+
+#include <libzfs.h>
+#include <libzfs_core.h>
+
+#include "libzfs_impl.h"
+#include "zfs_prop.h"
+#include "zfeature_common.h"
+#include <zfs_fletcher.h>
+
+int
+libzfs_errno(libzfs_handle_t *hdl)
+{
+       return (hdl->libzfs_error);
+}
+
+const char *
+libzfs_error_init(int error)
+{
+       switch (error) {
+       case ENXIO:
+               return (dgettext(TEXT_DOMAIN, "The ZFS modules are not "
+                   "loaded.\nTry running '/sbin/modprobe zfs' as root "
+                   "to load them.\n"));
+       case ENOENT:
+               return (dgettext(TEXT_DOMAIN, "/dev/zfs and /proc/self/mounts "
+                   "are required.\nTry running 'udevadm trigger' and 'mount "
+                   "-t proc proc /proc' as root.\n"));
+       case ENOEXEC:
+               return (dgettext(TEXT_DOMAIN, "The ZFS modules cannot be "
+                   "auto-loaded.\nTry running '/sbin/modprobe zfs' as "
+                   "root to manually load them.\n"));
+       case EACCES:
+               return (dgettext(TEXT_DOMAIN, "Permission denied the "
+                   "ZFS utilities must be run as root.\n"));
+       default:
+               return (dgettext(TEXT_DOMAIN, "Failed to initialize the "
+                   "libzfs library.\n"));
+       }
+}
+
+const char *
+libzfs_error_action(libzfs_handle_t *hdl)
+{
+       return (hdl->libzfs_action);
+}
+
+const char *
+libzfs_error_description(libzfs_handle_t *hdl)
+{
+       if (hdl->libzfs_desc[0] != '\0')
+               return (hdl->libzfs_desc);
+
+       switch (hdl->libzfs_error) {
+       case EZFS_NOMEM:
+               return (dgettext(TEXT_DOMAIN, "out of memory"));
+       case EZFS_BADPROP:
+               return (dgettext(TEXT_DOMAIN, "invalid property value"));
+       case EZFS_PROPREADONLY:
+               return (dgettext(TEXT_DOMAIN, "read-only property"));
+       case EZFS_PROPTYPE:
+               return (dgettext(TEXT_DOMAIN, "property doesn't apply to "
+                   "datasets of this type"));
+       case EZFS_PROPNONINHERIT:
+               return (dgettext(TEXT_DOMAIN, "property cannot be inherited"));
+       case EZFS_PROPSPACE:
+               return (dgettext(TEXT_DOMAIN, "invalid quota or reservation"));
+       case EZFS_BADTYPE:
+               return (dgettext(TEXT_DOMAIN, "operation not applicable to "
+                   "datasets of this type"));
+       case EZFS_BUSY:
+               return (dgettext(TEXT_DOMAIN, "pool or dataset is busy"));
+       case EZFS_EXISTS:
+               return (dgettext(TEXT_DOMAIN, "pool or dataset exists"));
+       case EZFS_NOENT:
+               return (dgettext(TEXT_DOMAIN, "no such pool or dataset"));
+       case EZFS_BADSTREAM:
+               return (dgettext(TEXT_DOMAIN, "invalid backup stream"));
+       case EZFS_DSREADONLY:
+               return (dgettext(TEXT_DOMAIN, "dataset is read-only"));
+       case EZFS_VOLTOOBIG:
+               return (dgettext(TEXT_DOMAIN, "volume size exceeds limit for "
+                   "this system"));
+       case EZFS_INVALIDNAME:
+               return (dgettext(TEXT_DOMAIN, "invalid name"));
+       case EZFS_BADRESTORE:
+               return (dgettext(TEXT_DOMAIN, "unable to restore to "
+                   "destination"));
+       case EZFS_BADBACKUP:
+               return (dgettext(TEXT_DOMAIN, "backup failed"));
+       case EZFS_BADTARGET:
+               return (dgettext(TEXT_DOMAIN, "invalid target vdev"));
+       case EZFS_NODEVICE:
+               return (dgettext(TEXT_DOMAIN, "no such device in pool"));
+       case EZFS_BADDEV:
+               return (dgettext(TEXT_DOMAIN, "invalid device"));
+       case EZFS_NOREPLICAS:
+               return (dgettext(TEXT_DOMAIN, "no valid replicas"));
+       case EZFS_RESILVERING:
+               return (dgettext(TEXT_DOMAIN, "currently resilvering"));
+       case EZFS_BADVERSION:
+               return (dgettext(TEXT_DOMAIN, "unsupported version or "
+                   "feature"));
+       case EZFS_POOLUNAVAIL:
+               return (dgettext(TEXT_DOMAIN, "pool is unavailable"));
+       case EZFS_DEVOVERFLOW:
+               return (dgettext(TEXT_DOMAIN, "too many devices in one vdev"));
+       case EZFS_BADPATH:
+               return (dgettext(TEXT_DOMAIN, "must be an absolute path"));
+       case EZFS_CROSSTARGET:
+               return (dgettext(TEXT_DOMAIN, "operation crosses datasets or "
+                   "pools"));
+       case EZFS_ZONED:
+               return (dgettext(TEXT_DOMAIN, "dataset in use by local zone"));
+       case EZFS_MOUNTFAILED:
+               return (dgettext(TEXT_DOMAIN, "mount failed"));
+       case EZFS_UMOUNTFAILED:
+               return (dgettext(TEXT_DOMAIN, "umount failed"));
+       case EZFS_UNSHARENFSFAILED:
+               return (dgettext(TEXT_DOMAIN, "unshare(1M) failed"));
+       case EZFS_SHARENFSFAILED:
+               return (dgettext(TEXT_DOMAIN, "share(1M) failed"));
+       case EZFS_UNSHARESMBFAILED:
+               return (dgettext(TEXT_DOMAIN, "smb remove share failed"));
+       case EZFS_SHARESMBFAILED:
+               return (dgettext(TEXT_DOMAIN, "smb add share failed"));
+       case EZFS_PERM:
+               return (dgettext(TEXT_DOMAIN, "permission denied"));
+       case EZFS_NOSPC:
+               return (dgettext(TEXT_DOMAIN, "out of space"));
+       case EZFS_FAULT:
+               return (dgettext(TEXT_DOMAIN, "bad address"));
+       case EZFS_IO:
+               return (dgettext(TEXT_DOMAIN, "I/O error"));
+       case EZFS_INTR:
+               return (dgettext(TEXT_DOMAIN, "signal received"));
+       case EZFS_ISSPARE:
+               return (dgettext(TEXT_DOMAIN, "device is reserved as a hot "
+                   "spare"));
+       case EZFS_INVALCONFIG:
+               return (dgettext(TEXT_DOMAIN, "invalid vdev configuration"));
+       case EZFS_RECURSIVE:
+               return (dgettext(TEXT_DOMAIN, "recursive dataset dependency"));
+       case EZFS_NOHISTORY:
+               return (dgettext(TEXT_DOMAIN, "no history available"));
+       case EZFS_POOLPROPS:
+               return (dgettext(TEXT_DOMAIN, "failed to retrieve "
+                   "pool properties"));
+       case EZFS_POOL_NOTSUP:
+               return (dgettext(TEXT_DOMAIN, "operation not supported "
+                   "on this type of pool"));
+       case EZFS_POOL_INVALARG:
+               return (dgettext(TEXT_DOMAIN, "invalid argument for "
+                   "this pool operation"));
+       case EZFS_NAMETOOLONG:
+               return (dgettext(TEXT_DOMAIN, "dataset name is too long"));
+       case EZFS_OPENFAILED:
+               return (dgettext(TEXT_DOMAIN, "open failed"));
+       case EZFS_NOCAP:
+               return (dgettext(TEXT_DOMAIN,
+                   "disk capacity information could not be retrieved"));
+       case EZFS_LABELFAILED:
+               return (dgettext(TEXT_DOMAIN, "write of label failed"));
+       case EZFS_BADWHO:
+               return (dgettext(TEXT_DOMAIN, "invalid user/group"));
+       case EZFS_BADPERM:
+               return (dgettext(TEXT_DOMAIN, "invalid permission"));
+       case EZFS_BADPERMSET:
+               return (dgettext(TEXT_DOMAIN, "invalid permission set name"));
+       case EZFS_NODELEGATION:
+               return (dgettext(TEXT_DOMAIN, "delegated administration is "
+                   "disabled on pool"));
+       case EZFS_BADCACHE:
+               return (dgettext(TEXT_DOMAIN, "invalid or missing cache file"));
+       case EZFS_ISL2CACHE:
+               return (dgettext(TEXT_DOMAIN, "device is in use as a cache"));
+       case EZFS_VDEVNOTSUP:
+               return (dgettext(TEXT_DOMAIN, "vdev specification is not "
+                   "supported"));
+       case EZFS_NOTSUP:
+               return (dgettext(TEXT_DOMAIN, "operation not supported "
+                   "on this dataset"));
+       case EZFS_ACTIVE_SPARE:
+               return (dgettext(TEXT_DOMAIN, "pool has active shared spare "
+                   "device"));
+       case EZFS_UNPLAYED_LOGS:
+               return (dgettext(TEXT_DOMAIN, "log device has unplayed intent "
+                   "logs"));
+       case EZFS_REFTAG_RELE:
+               return (dgettext(TEXT_DOMAIN, "no such tag on this dataset"));
+       case EZFS_REFTAG_HOLD:
+               return (dgettext(TEXT_DOMAIN, "tag already exists on this "
+                   "dataset"));
+       case EZFS_TAGTOOLONG:
+               return (dgettext(TEXT_DOMAIN, "tag too long"));
+       case EZFS_PIPEFAILED:
+               return (dgettext(TEXT_DOMAIN, "pipe create failed"));
+       case EZFS_THREADCREATEFAILED:
+               return (dgettext(TEXT_DOMAIN, "thread create failed"));
+       case EZFS_POSTSPLIT_ONLINE:
+               return (dgettext(TEXT_DOMAIN, "disk was split from this pool "
+                   "into a new one"));
+       case EZFS_SCRUBBING:
+               return (dgettext(TEXT_DOMAIN, "currently scrubbing; "
+                   "use 'zpool scrub -s' to cancel current scrub"));
+       case EZFS_NO_SCRUB:
+               return (dgettext(TEXT_DOMAIN, "there is no active scrub"));
+       case EZFS_DIFF:
+               return (dgettext(TEXT_DOMAIN, "unable to generate diffs"));
+       case EZFS_DIFFDATA:
+               return (dgettext(TEXT_DOMAIN, "invalid diff data"));
+       case EZFS_POOLREADONLY:
+               return (dgettext(TEXT_DOMAIN, "pool is read-only"));
+       case EZFS_UNKNOWN:
+               return (dgettext(TEXT_DOMAIN, "unknown error"));
+       default:
+               assert(hdl->libzfs_error == 0);
+               return (dgettext(TEXT_DOMAIN, "no error"));
+       }
+}
+
+/*PRINTFLIKE2*/
+void
+zfs_error_aux(libzfs_handle_t *hdl, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+
+       (void) vsnprintf(hdl->libzfs_desc, sizeof (hdl->libzfs_desc),
+           fmt, ap);
+       hdl->libzfs_desc_active = 1;
+
+       va_end(ap);
+}
+
+static void
+zfs_verror(libzfs_handle_t *hdl, int error, const char *fmt, va_list ap)
+{
+       (void) vsnprintf(hdl->libzfs_action, sizeof (hdl->libzfs_action),
+           fmt, ap);
+       hdl->libzfs_error = error;
+
+       if (hdl->libzfs_desc_active)
+               hdl->libzfs_desc_active = 0;
+       else
+               hdl->libzfs_desc[0] = '\0';
+
+       if (hdl->libzfs_printerr) {
+               if (error == EZFS_UNKNOWN) {
+                       (void) fprintf(stderr, dgettext(TEXT_DOMAIN, "internal "
+                           "error: %s\n"), libzfs_error_description(hdl));
+                       abort();
+               }
+
+               (void) fprintf(stderr, "%s: %s\n", hdl->libzfs_action,
+                   libzfs_error_description(hdl));
+               if (error == EZFS_NOMEM)
+                       exit(1);
+       }
+}
+
+int
+zfs_error(libzfs_handle_t *hdl, int error, const char *msg)
+{
+       return (zfs_error_fmt(hdl, error, "%s", msg));
+}
+
+/*PRINTFLIKE3*/
+int
+zfs_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+
+       zfs_verror(hdl, error, fmt, ap);
+
+       va_end(ap);
+
+       return (-1);
+}
+
+static int
+zfs_common_error(libzfs_handle_t *hdl, int error, const char *fmt,
+    va_list ap)
+{
+       switch (error) {
+       case EPERM:
+       case EACCES:
+               zfs_verror(hdl, EZFS_PERM, fmt, ap);
+               return (-1);
+
+       case ECANCELED:
+               zfs_verror(hdl, EZFS_NODELEGATION, fmt, ap);
+               return (-1);
+
+       case EIO:
+               zfs_verror(hdl, EZFS_IO, fmt, ap);
+               return (-1);
+
+       case EFAULT:
+               zfs_verror(hdl, EZFS_FAULT, fmt, ap);
+               return (-1);
+
+       case EINTR:
+               zfs_verror(hdl, EZFS_INTR, fmt, ap);
+               return (-1);
+       }
+
+       return (0);
+}
+
+int
+zfs_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
+{
+       return (zfs_standard_error_fmt(hdl, error, "%s", msg));
+}
+
+/*PRINTFLIKE3*/
+int
+zfs_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+
+       if (zfs_common_error(hdl, error, fmt, ap) != 0) {
+               va_end(ap);
+               return (-1);
+       }
+
+       switch (error) {
+       case ENXIO:
+       case ENODEV:
+       case EPIPE:
+               zfs_verror(hdl, EZFS_IO, fmt, ap);
+               break;
+
+       case ENOENT:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "dataset does not exist"));
+               zfs_verror(hdl, EZFS_NOENT, fmt, ap);
+               break;
+
+       case ENOSPC:
+       case EDQUOT:
+               zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
+               break;
+
+       case EEXIST:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "dataset already exists"));
+               zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
+               break;
+
+       case EBUSY:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "dataset is busy"));
+               zfs_verror(hdl, EZFS_BUSY, fmt, ap);
+               break;
+       case EROFS:
+               zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
+               break;
+       case ENAMETOOLONG:
+               zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap);
+               break;
+       case ENOTSUP:
+               zfs_verror(hdl, EZFS_BADVERSION, fmt, ap);
+               break;
+       case EAGAIN:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "pool I/O is currently suspended"));
+               zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
+               break;
+       default:
+               zfs_error_aux(hdl, strerror(error));
+               zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
+               break;
+       }
+
+       va_end(ap);
+       return (-1);
+}
+
+int
+zpool_standard_error(libzfs_handle_t *hdl, int error, const char *msg)
+{
+       return (zpool_standard_error_fmt(hdl, error, "%s", msg));
+}
+
+/*PRINTFLIKE3*/
+int
+zpool_standard_error_fmt(libzfs_handle_t *hdl, int error, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+
+       if (zfs_common_error(hdl, error, fmt, ap) != 0) {
+               va_end(ap);
+               return (-1);
+       }
+
+       switch (error) {
+       case ENODEV:
+               zfs_verror(hdl, EZFS_NODEVICE, fmt, ap);
+               break;
+
+       case ENOENT:
+               zfs_error_aux(hdl,
+                   dgettext(TEXT_DOMAIN, "no such pool or dataset"));
+               zfs_verror(hdl, EZFS_NOENT, fmt, ap);
+               break;
+
+       case EEXIST:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "pool already exists"));
+               zfs_verror(hdl, EZFS_EXISTS, fmt, ap);
+               break;
+
+       case EBUSY:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "pool is busy"));
+               zfs_verror(hdl, EZFS_BUSY, fmt, ap);
+               break;
+
+       case ENXIO:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "one or more devices is currently unavailable"));
+               zfs_verror(hdl, EZFS_BADDEV, fmt, ap);
+               break;
+
+       case ENAMETOOLONG:
+               zfs_verror(hdl, EZFS_DEVOVERFLOW, fmt, ap);
+               break;
+
+       case ENOTSUP:
+               zfs_verror(hdl, EZFS_POOL_NOTSUP, fmt, ap);
+               break;
+
+       case EINVAL:
+               zfs_verror(hdl, EZFS_POOL_INVALARG, fmt, ap);
+               break;
+
+       case ENOSPC:
+       case EDQUOT:
+               zfs_verror(hdl, EZFS_NOSPC, fmt, ap);
+               return (-1);
+
+       case EAGAIN:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "pool I/O is currently suspended"));
+               zfs_verror(hdl, EZFS_POOLUNAVAIL, fmt, ap);
+               break;
+
+       case EROFS:
+               zfs_verror(hdl, EZFS_POOLREADONLY, fmt, ap);
+               break;
+       case EDOM:
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "block size out of range or does not match"));
+               zfs_verror(hdl, EZFS_BADPROP, fmt, ap);
+               break;
+
+       default:
+               zfs_error_aux(hdl, strerror(error));
+               zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
+       }
+
+       va_end(ap);
+       return (-1);
+}
+
+/*
+ * Display an out of memory error message and abort the current program.
+ */
+int
+no_memory(libzfs_handle_t *hdl)
+{
+       return (zfs_error(hdl, EZFS_NOMEM, "internal error"));
+}
+
+/*
+ * A safe form of malloc() which will die if the allocation fails.
+ */
+void *
+zfs_alloc(libzfs_handle_t *hdl, size_t size)
+{
+       void *data;
+
+       if ((data = calloc(1, size)) == NULL)
+               (void) no_memory(hdl);
+
+       return (data);
+}
+
+/*
+ * A safe form of asprintf() which will die if the allocation fails.
+ */
+/*PRINTFLIKE2*/
+char *
+zfs_asprintf(libzfs_handle_t *hdl, const char *fmt, ...)
+{
+       va_list ap;
+       char *ret;
+       int err;
+
+       va_start(ap, fmt);
+
+       err = vasprintf(&ret, fmt, ap);
+
+       va_end(ap);
+
+       if (err < 0)
+               (void) no_memory(hdl);
+
+       return (ret);
+}
+
+/*
+ * A safe form of realloc(), which also zeroes newly allocated space.
+ */
+void *
+zfs_realloc(libzfs_handle_t *hdl, void *ptr, size_t oldsize, size_t newsize)
+{
+       void *ret;
+
+       if ((ret = realloc(ptr, newsize)) == NULL) {
+               (void) no_memory(hdl);
+               return (NULL);
+       }
+
+       bzero((char *)ret + oldsize, (newsize - oldsize));
+       return (ret);
+}
+
+/*
+ * A safe form of strdup() which will die if the allocation fails.
+ */
+char *
+zfs_strdup(libzfs_handle_t *hdl, const char *str)
+{
+       char *ret;
+
+       if ((ret = strdup(str)) == NULL)
+               (void) no_memory(hdl);
+
+       return (ret);
+}
+
+/*
+ * Convert a number to an appropriately human-readable output.
+ */
+void
+zfs_nicenum_format(uint64_t num, char *buf, size_t buflen,
+    enum zfs_nicenum_format format)
+{
+       uint64_t n = num;
+       int index = 0;
+       const char *u;
+       const char *units[3][7] = {
+           [ZFS_NICENUM_1024] = {"", "K", "M", "G", "T", "P", "E"},
+           [ZFS_NICENUM_TIME] = {"ns", "us", "ms", "s", "?", "?", "?"}
+       };
+
+       const int units_len[] = {[ZFS_NICENUM_1024] = 6,
+           [ZFS_NICENUM_TIME] = 4};
+
+       const int k_unit[] = {  [ZFS_NICENUM_1024] = 1024,
+           [ZFS_NICENUM_TIME] = 1000};
+
+       double val;
+
+       if (format == ZFS_NICENUM_RAW) {
+               snprintf(buf, buflen, "%llu", (u_longlong_t) num);
+               return;
+       }
+
+
+       while (n >= k_unit[format] && index < units_len[format]) {
+               n /= k_unit[format];
+               index++;
+       }
+
+       u = units[format][index];
+
+       /* Don't print 0ns times */
+       if ((format == ZFS_NICENUM_TIME) && (num == 0)) {
+               (void) snprintf(buf, buflen, "-");
+       } else if ((index == 0) || ((num %
+           (uint64_t) powl(k_unit[format], index)) == 0)) {
+               /*
+                * If this is an even multiple of the base, always display
+                * without any decimal precision.
+                */
+               (void) snprintf(buf, buflen, "%llu%s", (u_longlong_t) n, u);
+
+       } else {
+               /*
+                * We want to choose a precision that reflects the best choice
+                * for fitting in 5 characters.  This can get rather tricky when
+                * we have numbers that are very close to an order of magnitude.
+                * For example, when displaying 10239 (which is really 9.999K),
+                * we want only a single place of precision for 10.0K.  We could
+                * develop some complex heuristics for this, but it's much
+                * easier just to try each combination in turn.
+                */
+               int i;
+               for (i = 2; i >= 0; i--) {
+                       val = (double) num /
+                           (uint64_t) powl(k_unit[format], index);
+
+                       /*
+                        * Don't print floating point values for time.  Note,
+                        * we use floor() instead of round() here, since
+                        * round can result in undesirable results.  For
+                        * example, if "num" is in the range of
+                        * 999500-999999, it will print out "1000us".  This
+                        * doesn't happen if we use floor().
+                        */
+                       if (format == ZFS_NICENUM_TIME) {
+                               if (snprintf(buf, buflen, "%d%s",
+                                   (unsigned int) floor(val), u) <= 5)
+                                       break;
+
+                       } else {
+                               if (snprintf(buf, buflen, "%.*f%s", i,
+                                   val, u) <= 5)
+                                       break;
+                       }
+               }
+       }
+}
+
+/*
+ * Convert a number to an appropriately human-readable output.
+ */
+void
+zfs_nicenum(uint64_t num, char *buf, size_t buflen)
+{
+       zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_1024);
+}
+
+/*
+ * Convert a time to an appropriately human-readable output.
+ * @num:       Time in nanoseconds
+ */
+void
+zfs_nicetime(uint64_t num, char *buf, size_t buflen)
+{
+       zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_TIME);
+}
+
+/*
+ * Print out a raw number with correct column spacing
+ */
+void
+zfs_niceraw(uint64_t num, char *buf, size_t buflen)
+{
+       zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_RAW);
+}
+
+
+
+void
+libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr)
+{
+       hdl->libzfs_printerr = printerr;
+}
+
+static int
+libzfs_module_loaded(const char *module)
+{
+       const char path_prefix[] = "/sys/module/";
+       char path[256];
+
+       memcpy(path, path_prefix, sizeof (path_prefix) - 1);
+       strcpy(path + sizeof (path_prefix) - 1, module);
+
+       return (access(path, F_OK) == 0);
+}
+
+int
+libzfs_run_process(const char *path, char *argv[], int flags)
+{
+       pid_t pid;
+       int error, devnull_fd;
+
+       pid = vfork();
+       if (pid == 0) {
+               devnull_fd = open("/dev/null", O_WRONLY);
+
+               if (devnull_fd < 0)
+                       _exit(-1);
+
+               if (!(flags & STDOUT_VERBOSE))
+                       (void) dup2(devnull_fd, STDOUT_FILENO);
+
+               if (!(flags & STDERR_VERBOSE))
+                       (void) dup2(devnull_fd, STDERR_FILENO);
+
+               close(devnull_fd);
+
+               (void) execvp(path, argv);
+               _exit(-1);
+       } else if (pid > 0) {
+               int status;
+
+               while ((error = waitpid(pid, &status, 0)) == -1 &&
+                       errno == EINTR);
+               if (error < 0 || !WIFEXITED(status))
+                       return (-1);
+
+               return (WEXITSTATUS(status));
+       }
+
+       return (-1);
+}
+
+/*
+ * Verify the required ZFS_DEV device is available and optionally attempt
+ * to load the ZFS modules.  Under normal circumstances the modules
+ * should already have been loaded by some external mechanism.
+ *
+ * Environment variables:
+ * - ZFS_MODULE_LOADING="YES|yes|ON|on" - Attempt to load modules.
+ * - ZFS_MODULE_TIMEOUT="<seconds>"     - Seconds to wait for ZFS_DEV
+ */
+static int
+libzfs_load_module(const char *module)
+{
+       char *argv[4] = {"/sbin/modprobe", "-q", (char *)module, (char *)0};
+       char *load_str, *timeout_str;
+       long timeout = 10; /* seconds */
+       long busy_timeout = 10; /* milliseconds */
+       int load = 0, fd;
+       hrtime_t start;
+
+       /* Optionally request module loading */
+       if (!libzfs_module_loaded(module)) {
+               load_str = getenv("ZFS_MODULE_LOADING");
+               if (load_str) {
+                       if (!strncasecmp(load_str, "YES", strlen("YES")) ||
+                           !strncasecmp(load_str, "ON", strlen("ON")))
+                               load = 1;
+                       else
+                               load = 0;
+               }
+
+               if (load && libzfs_run_process("/sbin/modprobe", argv, 0))
+                       return (ENOEXEC);
+       }
+
+       /* Module loading is synchronous it must be available */
+       if (!libzfs_module_loaded(module))
+               return (ENXIO);
+
+       /*
+        * Device creation by udev is asynchronous and waiting may be
+        * required.  Busy wait for 10ms and then fall back to polling every
+        * 10ms for the allowed timeout (default 10s, max 10m).  This is
+        * done to optimize for the common case where the device is
+        * immediately available and to avoid penalizing the possible
+        * case where udev is slow or unable to create the device.
+        */
+       timeout_str = getenv("ZFS_MODULE_TIMEOUT");
+       if (timeout_str) {
+               timeout = strtol(timeout_str, NULL, 0);
+               timeout = MAX(MIN(timeout, (10 * 60)), 0); /* 0 <= N <= 600 */
+       }
+
+       start = gethrtime();
+       do {
+               fd = open(ZFS_DEV, O_RDWR);
+               if (fd >= 0) {
+                       (void) close(fd);
+                       return (0);
+               } else if (errno != ENOENT) {
+                       return (errno);
+               } else if (NSEC2MSEC(gethrtime() - start) < busy_timeout) {
+                       sched_yield();
+               } else {
+                       usleep(10 * MILLISEC);
+               }
+       } while (NSEC2MSEC(gethrtime() - start) < (timeout * MILLISEC));
+
+       return (ENOENT);
+}
+
+libzfs_handle_t *
+libzfs_init(void)
+{
+       libzfs_handle_t *hdl;
+       int error;
+
+       error = libzfs_load_module(ZFS_DRIVER);
+       if (error) {
+               errno = error;
+               return (NULL);
+       }
+
+       if ((hdl = calloc(1, sizeof (libzfs_handle_t))) == NULL) {
+               return (NULL);
+       }
+
+       if ((hdl->libzfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
+               free(hdl);
+               return (NULL);
+       }
+
+#ifdef HAVE_SETMNTENT
+       if ((hdl->libzfs_mnttab = setmntent(MNTTAB, "r")) == NULL) {
+#else
+       if ((hdl->libzfs_mnttab = fopen(MNTTAB, "r")) == NULL) {
+#endif
+               (void) close(hdl->libzfs_fd);
+               free(hdl);
+               return (NULL);
+       }
+
+       hdl->libzfs_sharetab = fopen("/etc/dfs/sharetab", "r");
+
+       if (libzfs_core_init() != 0) {
+               (void) close(hdl->libzfs_fd);
+               (void) fclose(hdl->libzfs_mnttab);
+               (void) fclose(hdl->libzfs_sharetab);
+               free(hdl);
+               return (NULL);
+       }
+
+       zfs_prop_init();
+       zpool_prop_init();
+       zpool_feature_init();
+       libzfs_mnttab_init(hdl);
+       fletcher_4_init();
+
+       return (hdl);
+}
+
+void
+libzfs_fini(libzfs_handle_t *hdl)
+{
+       (void) close(hdl->libzfs_fd);
+       if (hdl->libzfs_mnttab)
+#ifdef HAVE_SETMNTENT
+               (void) endmntent(hdl->libzfs_mnttab);
+#else
+               (void) fclose(hdl->libzfs_mnttab);
+#endif
+       if (hdl->libzfs_sharetab)
+               (void) fclose(hdl->libzfs_sharetab);
+       zfs_uninit_libshare(hdl);
+       zpool_free_handles(hdl);
+       libzfs_fru_clear(hdl, B_TRUE);
+       namespace_clear(hdl);
+       libzfs_mnttab_fini(hdl);
+       libzfs_core_fini();
+       fletcher_4_fini();
+       free(hdl);
+}
+
+libzfs_handle_t *
+zpool_get_handle(zpool_handle_t *zhp)
+{
+       return (zhp->zpool_hdl);
+}
+
+libzfs_handle_t *
+zfs_get_handle(zfs_handle_t *zhp)
+{
+       return (zhp->zfs_hdl);
+}
+
+zpool_handle_t *
+zfs_get_pool_handle(const zfs_handle_t *zhp)
+{
+       return (zhp->zpool_hdl);
+}
+
+/*
+ * Given a name, determine whether or not it's a valid path
+ * (starts with '/' or "./").  If so, walk the mnttab trying
+ * to match the device number.  If not, treat the path as an
+ * fs/vol/snap name.
+ */
+zfs_handle_t *
+zfs_path_to_zhandle(libzfs_handle_t *hdl, char *path, zfs_type_t argtype)
+{
+       struct stat64 statbuf;
+       struct extmnttab entry;
+       int ret;
+
+       if (path[0] != '/' && strncmp(path, "./", strlen("./")) != 0) {
+               /*
+                * It's not a valid path, assume it's a name of type 'argtype'.
+                */
+               return (zfs_open(hdl, path, argtype));
+       }
+
+       if (stat64(path, &statbuf) != 0) {
+               (void) fprintf(stderr, "%s: %s\n", path, strerror(errno));
+               return (NULL);
+       }
+
+       /* Reopen MNTTAB to prevent reading stale data from open file */
+       if (freopen(MNTTAB, "r", hdl->libzfs_mnttab) == NULL)
+               return (NULL);
+
+       while ((ret = getextmntent(hdl->libzfs_mnttab, &entry, 0)) == 0) {
+               if (makedevice(entry.mnt_major, entry.mnt_minor) ==
+                   statbuf.st_dev) {
+                       break;
+               }
+       }
+       if (ret != 0) {
+               return (NULL);
+       }
+
+       if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) {
+               (void) fprintf(stderr, gettext("'%s': not a ZFS filesystem\n"),
+                   path);
+               return (NULL);
+       }
+
+       return (zfs_open(hdl, entry.mnt_special, ZFS_TYPE_FILESYSTEM));
+}
+
+/*
+ * Append partition suffix to an otherwise fully qualified device path.
+ * This is used to generate the name the full path as its stored in
+ * ZPOOL_CONFIG_PATH for whole disk devices.  On success the new length
+ * of 'path' will be returned on error a negative value is returned.
+ */
+int
+zfs_append_partition(char *path, size_t max_len)
+{
+       int len = strlen(path);
+
+       if ((strncmp(path, UDISK_ROOT, strlen(UDISK_ROOT)) == 0) ||
+           (strncmp(path, ZVOL_ROOT, strlen(ZVOL_ROOT)) == 0)) {
+               if (len + 6 >= max_len)
+                       return (-1);
+
+               (void) strcat(path, "-part1");
+               len += 6;
+       } else {
+               if (len + 2 >= max_len)
+                       return (-1);
+
+               if (isdigit(path[len-1])) {
+                       (void) strcat(path, "p1");
+                       len += 2;
+               } else {
+                       (void) strcat(path, "1");
+                       len += 1;
+               }
+       }
+
+       return (len);
+}
+
+/*
+ * Given a shorthand device name check if a file by that name exists in any
+ * of the 'zpool_default_import_path' or ZPOOL_IMPORT_PATH directories.  If
+ * one is found, store its fully qualified path in the 'path' buffer passed
+ * by the caller and return 0, otherwise return an error.
+ */
+int
+zfs_resolve_shortname(const char *name, char *path, size_t len)
+{
+       int i, error = -1;
+       char *dir, *env, *envdup;
+
+       env = getenv("ZPOOL_IMPORT_PATH");
+       errno = ENOENT;
+
+       if (env) {
+               envdup = strdup(env);
+               dir = strtok(envdup, ":");
+               while (dir && error) {
+                       (void) snprintf(path, len, "%s/%s", dir, name);
+                       error = access(path, F_OK);
+                       dir = strtok(NULL, ":");
+               }
+               free(envdup);
+       } else {
+               for (i = 0; i < DEFAULT_IMPORT_PATH_SIZE && error < 0; i++) {
+                       (void) snprintf(path, len, "%s/%s",
+                           zpool_default_import_path[i], name);
+                       error = access(path, F_OK);
+               }
+       }
+
+       return (error ? ENOENT : 0);
+}
+
+/*
+ * Given a shorthand device name look for a match against 'cmp_name'.  This
+ * is done by checking all prefix expansions using either the default
+ * 'zpool_default_import_paths' or the ZPOOL_IMPORT_PATH environment
+ * variable.  Proper partition suffixes will be appended if this is a
+ * whole disk.  When a match is found 0 is returned otherwise ENOENT.
+ */
+static int
+zfs_strcmp_shortname(char *name, char *cmp_name, int wholedisk)
+{
+       int path_len, cmp_len, i = 0, error = ENOENT;
+       char *dir, *env, *envdup = NULL;
+       char path_name[MAXPATHLEN];
+
+       cmp_len = strlen(cmp_name);
+       env = getenv("ZPOOL_IMPORT_PATH");
+
+       if (env) {
+               envdup = strdup(env);
+               dir = strtok(envdup, ":");
+       } else {
+               dir =  zpool_default_import_path[i];
+       }
+
+       while (dir) {
+               /* Trim trailing directory slashes from ZPOOL_IMPORT_PATH */
+               while (dir[strlen(dir)-1] == '/')
+                       dir[strlen(dir)-1] = '\0';
+
+               path_len = snprintf(path_name, MAXPATHLEN, "%s/%s", dir, name);
+               if (wholedisk)
+                       path_len = zfs_append_partition(path_name, MAXPATHLEN);
+
+               if ((path_len == cmp_len) && strcmp(path_name, cmp_name) == 0) {
+                       error = 0;
+                       break;
+               }
+
+               if (env) {
+                       dir = strtok(NULL, ":");
+               } else if (++i < DEFAULT_IMPORT_PATH_SIZE) {
+                       dir = zpool_default_import_path[i];
+               } else {
+                       dir = NULL;
+               }
+       }
+
+       if (env)
+               free(envdup);
+
+       return (error);
+}
+
+/*
+ * Given either a shorthand or fully qualified path name look for a match
+ * against 'cmp'.  The passed name will be expanded as needed for comparison
+ * purposes and redundant slashes stripped to ensure an accurate match.
+ */
+int
+zfs_strcmp_pathname(char *name, char *cmp, int wholedisk)
+{
+       int path_len, cmp_len;
+       char path_name[MAXPATHLEN];
+       char cmp_name[MAXPATHLEN];
+       char *dir, *dup;
+
+       /* Strip redundant slashes if one exists due to ZPOOL_IMPORT_PATH */
+       memset(cmp_name, 0, MAXPATHLEN);
+       dup = strdup(cmp);
+       dir = strtok(dup, "/");
+       while (dir) {
+               strlcat(cmp_name, "/", sizeof (cmp_name));
+               strlcat(cmp_name, dir, sizeof (cmp_name));
+               dir = strtok(NULL, "/");
+       }
+       free(dup);
+
+       if (name[0] != '/')
+               return (zfs_strcmp_shortname(name, cmp_name, wholedisk));
+
+       (void) strlcpy(path_name, name, MAXPATHLEN);
+       path_len = strlen(path_name);
+       cmp_len = strlen(cmp_name);
+
+       if (wholedisk) {
+               path_len = zfs_append_partition(path_name, MAXPATHLEN);
+               if (path_len == -1)
+                       return (ENOMEM);
+       }
+
+       if ((path_len != cmp_len) || strcmp(path_name, cmp_name))
+               return (ENOENT);
+
+       return (0);
+}
+
+/*
+ * Initialize the zc_nvlist_dst member to prepare for receiving an nvlist from
+ * an ioctl().
+ */
+int
+zcmd_alloc_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, size_t len)
+{
+       if (len == 0)
+               len = 16 * 1024;
+       zc->zc_nvlist_dst_size = len;
+       zc->zc_nvlist_dst =
+           (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
+       if (zc->zc_nvlist_dst == 0)
+               return (-1);
+
+       return (0);
+}
+
+/*
+ * Called when an ioctl() which returns an nvlist fails with ENOMEM.  This will
+ * expand the nvlist to the size specified in 'zc_nvlist_dst_size', which was
+ * filled in by the kernel to indicate the actual required size.
+ */
+int
+zcmd_expand_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc)
+{
+       free((void *)(uintptr_t)zc->zc_nvlist_dst);
+       zc->zc_nvlist_dst =
+           (uint64_t)(uintptr_t)zfs_alloc(hdl, zc->zc_nvlist_dst_size);
+       if (zc->zc_nvlist_dst == 0)
+               return (-1);
+
+       return (0);
+}
+
+/*
+ * Called to free the src and dst nvlists stored in the command structure.
+ */
+void
+zcmd_free_nvlists(zfs_cmd_t *zc)
+{
+       free((void *)(uintptr_t)zc->zc_nvlist_conf);
+       free((void *)(uintptr_t)zc->zc_nvlist_src);
+       free((void *)(uintptr_t)zc->zc_nvlist_dst);
+       zc->zc_nvlist_conf = 0;
+       zc->zc_nvlist_src = 0;
+       zc->zc_nvlist_dst = 0;
+}
+
+static int
+zcmd_write_nvlist_com(libzfs_handle_t *hdl, uint64_t *outnv, uint64_t *outlen,
+    nvlist_t *nvl)
+{
+       char *packed;
+       size_t len;
+
+       verify(nvlist_size(nvl, &len, NV_ENCODE_NATIVE) == 0);
+
+       if ((packed = zfs_alloc(hdl, len)) == NULL)
+               return (-1);
+
+       verify(nvlist_pack(nvl, &packed, &len, NV_ENCODE_NATIVE, 0) == 0);
+
+       *outnv = (uint64_t)(uintptr_t)packed;
+       *outlen = len;
+
+       return (0);
+}
+
+int
+zcmd_write_conf_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl)
+{
+       return (zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_conf,
+           &zc->zc_nvlist_conf_size, nvl));
+}
+
+int
+zcmd_write_src_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t *nvl)
+{
+       return (zcmd_write_nvlist_com(hdl, &zc->zc_nvlist_src,
+           &zc->zc_nvlist_src_size, nvl));
+}
+
+/*
+ * Unpacks an nvlist from the ZFS ioctl command structure.
+ */
+int
+zcmd_read_dst_nvlist(libzfs_handle_t *hdl, zfs_cmd_t *zc, nvlist_t **nvlp)
+{
+       if (nvlist_unpack((void *)(uintptr_t)zc->zc_nvlist_dst,
+           zc->zc_nvlist_dst_size, nvlp, 0) != 0)
+               return (no_memory(hdl));
+
+       return (0);
+}
+
+int
+zfs_ioctl(libzfs_handle_t *hdl, int request, zfs_cmd_t *zc)
+{
+       return (ioctl(hdl->libzfs_fd, request, zc));
+}
+
+/*
+ * ================================================================
+ * API shared by zfs and zpool property management
+ * ================================================================
+ */
+
+static void
+zprop_print_headers(zprop_get_cbdata_t *cbp, zfs_type_t type)
+{
+       zprop_list_t *pl = cbp->cb_proplist;
+       int i;
+       char *title;
+       size_t len;
+
+       cbp->cb_first = B_FALSE;
+       if (cbp->cb_scripted)
+               return;
+
+       /*
+        * Start with the length of the column headers.
+        */
+       cbp->cb_colwidths[GET_COL_NAME] = strlen(dgettext(TEXT_DOMAIN, "NAME"));
+       cbp->cb_colwidths[GET_COL_PROPERTY] = strlen(dgettext(TEXT_DOMAIN,
+           "PROPERTY"));
+       cbp->cb_colwidths[GET_COL_VALUE] = strlen(dgettext(TEXT_DOMAIN,
+           "VALUE"));
+       cbp->cb_colwidths[GET_COL_RECVD] = strlen(dgettext(TEXT_DOMAIN,
+           "RECEIVED"));
+       cbp->cb_colwidths[GET_COL_SOURCE] = strlen(dgettext(TEXT_DOMAIN,
+           "SOURCE"));
+
+       /* first property is always NAME */
+       assert(cbp->cb_proplist->pl_prop ==
+           ((type == ZFS_TYPE_POOL) ?  ZPOOL_PROP_NAME : ZFS_PROP_NAME));
+
+       /*
+        * Go through and calculate the widths for each column.  For the
+        * 'source' column, we kludge it up by taking the worst-case scenario of
+        * inheriting from the longest name.  This is acceptable because in the
+        * majority of cases 'SOURCE' is the last column displayed, and we don't
+        * use the width anyway.  Note that the 'VALUE' column can be oversized,
+        * if the name of the property is much longer than any values we find.
+        */
+       for (pl = cbp->cb_proplist; pl != NULL; pl = pl->pl_next) {
+               /*
+                * 'PROPERTY' column
+                */
+               if (pl->pl_prop != ZPROP_INVAL) {
+                       const char *propname = (type == ZFS_TYPE_POOL) ?
+                           zpool_prop_to_name(pl->pl_prop) :
+                           zfs_prop_to_name(pl->pl_prop);
+
+                       len = strlen(propname);
+                       if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
+                               cbp->cb_colwidths[GET_COL_PROPERTY] = len;
+               } else {
+                       len = strlen(pl->pl_user_prop);
+                       if (len > cbp->cb_colwidths[GET_COL_PROPERTY])
+                               cbp->cb_colwidths[GET_COL_PROPERTY] = len;
+               }
+
+               /*
+                * 'VALUE' column.  The first property is always the 'name'
+                * property that was tacked on either by /sbin/zfs's
+                * zfs_do_get() or when calling zprop_expand_list(), so we
+                * ignore its width.  If the user specified the name property
+                * to display, then it will be later in the list in any case.
+                */
+               if (pl != cbp->cb_proplist &&
+                   pl->pl_width > cbp->cb_colwidths[GET_COL_VALUE])
+                       cbp->cb_colwidths[GET_COL_VALUE] = pl->pl_width;
+
+               /* 'RECEIVED' column. */
+               if (pl != cbp->cb_proplist &&
+                   pl->pl_recvd_width > cbp->cb_colwidths[GET_COL_RECVD])
+                       cbp->cb_colwidths[GET_COL_RECVD] = pl->pl_recvd_width;
+
+               /*
+                * 'NAME' and 'SOURCE' columns
+                */
+               if (pl->pl_prop == (type == ZFS_TYPE_POOL ? ZPOOL_PROP_NAME :
+                   ZFS_PROP_NAME) &&
+                   pl->pl_width > cbp->cb_colwidths[GET_COL_NAME]) {
+                       cbp->cb_colwidths[GET_COL_NAME] = pl->pl_width;
+                       cbp->cb_colwidths[GET_COL_SOURCE] = pl->pl_width +
+                           strlen(dgettext(TEXT_DOMAIN, "inherited from"));
+               }
+       }
+
+       /*
+        * Now go through and print the headers.
+        */
+       for (i = 0; i < ZFS_GET_NCOLS; i++) {
+               switch (cbp->cb_columns[i]) {
+               case GET_COL_NAME:
+                       title = dgettext(TEXT_DOMAIN, "NAME");
+                       break;
+               case GET_COL_PROPERTY:
+                       title = dgettext(TEXT_DOMAIN, "PROPERTY");
+                       break;
+               case GET_COL_VALUE:
+                       title = dgettext(TEXT_DOMAIN, "VALUE");
+                       break;
+               case GET_COL_RECVD:
+                       title = dgettext(TEXT_DOMAIN, "RECEIVED");
+                       break;
+               case GET_COL_SOURCE:
+                       title = dgettext(TEXT_DOMAIN, "SOURCE");
+                       break;
+               default:
+                       title = NULL;
+               }
+
+               if (title != NULL) {
+                       if (i == (ZFS_GET_NCOLS - 1) ||
+                           cbp->cb_columns[i + 1] == GET_COL_NONE)
+                               (void) printf("%s", title);
+                       else
+                               (void) printf("%-*s  ",
+                                   cbp->cb_colwidths[cbp->cb_columns[i]],
+                                   title);
+               }
+       }
+       (void) printf("\n");
+}
+
+/*
+ * Display a single line of output, according to the settings in the callback
+ * structure.
+ */
+void
+zprop_print_one_property(const char *name, zprop_get_cbdata_t *cbp,
+    const char *propname, const char *value, zprop_source_t sourcetype,
+    const char *source, const char *recvd_value)
+{
+       int i;
+       const char *str = NULL;
+       char buf[128];
+
+       /*
+        * Ignore those source types that the user has chosen to ignore.
+        */
+       if ((sourcetype & cbp->cb_sources) == 0)
+               return;
+
+       if (cbp->cb_first)
+               zprop_print_headers(cbp, cbp->cb_type);
+
+       for (i = 0; i < ZFS_GET_NCOLS; i++) {
+               switch (cbp->cb_columns[i]) {
+               case GET_COL_NAME:
+                       str = name;
+                       break;
+
+               case GET_COL_PROPERTY:
+                       str = propname;
+                       break;
+
+               case GET_COL_VALUE:
+                       str = value;
+                       break;
+
+               case GET_COL_SOURCE:
+                       switch (sourcetype) {
+                       case ZPROP_SRC_NONE:
+                               str = "-";
+                               break;
+
+                       case ZPROP_SRC_DEFAULT:
+                               str = "default";
+                               break;
+
+                       case ZPROP_SRC_LOCAL:
+                               str = "local";
+                               break;
+
+                       case ZPROP_SRC_TEMPORARY:
+                               str = "temporary";
+                               break;
+
+                       case ZPROP_SRC_INHERITED:
+                               (void) snprintf(buf, sizeof (buf),
+                                   "inherited from %s", source);
+                               str = buf;
+                               break;
+                       case ZPROP_SRC_RECEIVED:
+                               str = "received";
+                               break;
+                       }
+                       break;
+
+               case GET_COL_RECVD:
+                       str = (recvd_value == NULL ? "-" : recvd_value);
+                       break;
+
+               default:
+                       continue;
+               }
+
+               if (i == (ZFS_GET_NCOLS - 1) ||
+                   cbp->cb_columns[i + 1] == GET_COL_NONE)
+                       (void) printf("%s", str);
+               else if (cbp->cb_scripted)
+                       (void) printf("%s\t", str);
+               else
+                       (void) printf("%-*s  ",
+                           cbp->cb_colwidths[cbp->cb_columns[i]],
+                           str);
+       }
+
+       (void) printf("\n");
+}
+
+/*
+ * Given a numeric suffix, convert the value into a number of bits that the
+ * resulting value must be shifted.
+ */
+static int
+str2shift(libzfs_handle_t *hdl, const char *buf)
+{
+       const char *ends = "BKMGTPEZ";
+       int i;
+
+       if (buf[0] == '\0')
+               return (0);
+       for (i = 0; i < strlen(ends); i++) {
+               if (toupper(buf[0]) == ends[i])
+                       break;
+       }
+       if (i == strlen(ends)) {
+               if (hdl)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "invalid numeric suffix '%s'"), buf);
+               return (-1);
+       }
+
+       /*
+        * Allow 'G' = 'GB' = 'GiB', case-insensitively.
+        * However, 'BB' and 'BiB' are disallowed.
+        */
+       if (buf[1] == '\0' ||
+           (toupper(buf[0]) != 'B' &&
+           ((toupper(buf[1]) == 'B' && buf[2] == '\0') ||
+           (toupper(buf[1]) == 'I' && toupper(buf[2]) == 'B' &&
+           buf[3] == '\0'))))
+               return (10 * i);
+
+       if (hdl)
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "invalid numeric suffix '%s'"), buf);
+       return (-1);
+}
+
+/*
+ * Convert a string of the form '100G' into a real number.  Used when setting
+ * properties or creating a volume.  'buf' is used to place an extended error
+ * message for the caller to use.
+ */
+int
+zfs_nicestrtonum(libzfs_handle_t *hdl, const char *value, uint64_t *num)
+{
+       char *end;
+       int shift;
+
+       *num = 0;
+
+       /* Check to see if this looks like a number.  */
+       if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
+               if (hdl)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "bad numeric value '%s'"), value);
+               return (-1);
+       }
+
+       /* Rely on strtoull() to process the numeric portion.  */
+       errno = 0;
+       *num = strtoull(value, &end, 10);
+
+       /*
+        * Check for ERANGE, which indicates that the value is too large to fit
+        * in a 64-bit value.
+        */
+       if (errno == ERANGE) {
+               if (hdl)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "numeric value is too large"));
+               return (-1);
+       }
+
+       /*
+        * If we have a decimal value, then do the computation with floating
+        * point arithmetic.  Otherwise, use standard arithmetic.
+        */
+       if (*end == '.') {
+               double fval = strtod(value, &end);
+
+               if ((shift = str2shift(hdl, end)) == -1)
+                       return (-1);
+
+               fval *= pow(2, shift);
+
+               if (fval > UINT64_MAX) {
+                       if (hdl)
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "numeric value is too large"));
+                       return (-1);
+               }
+
+               *num = (uint64_t)fval;
+       } else {
+               if ((shift = str2shift(hdl, end)) == -1)
+                       return (-1);
+
+               /* Check for overflow */
+               if (shift >= 64 || (*num << shift) >> shift != *num) {
+                       if (hdl)
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "numeric value is too large"));
+                       return (-1);
+               }
+
+               *num <<= shift;
+       }
+
+       return (0);
+}
+
+/*
+ * Given a propname=value nvpair to set, parse any numeric properties
+ * (index, boolean, etc) if they are specified as strings and add the
+ * resulting nvpair to the returned nvlist.
+ *
+ * At the DSL layer, all properties are either 64-bit numbers or strings.
+ * We want the user to be able to ignore this fact and specify properties
+ * as native values (numbers, for example) or as strings (to simplify
+ * command line utilities).  This also handles converting index types
+ * (compression, checksum, etc) from strings to their on-disk index.
+ */
+int
+zprop_parse_value(libzfs_handle_t *hdl, nvpair_t *elem, int prop,
+    zfs_type_t type, nvlist_t *ret, char **svalp, uint64_t *ivalp,
+    const char *errbuf)
+{
+       data_type_t datatype = nvpair_type(elem);
+       zprop_type_t proptype;
+       const char *propname;
+       char *value;
+       boolean_t isnone = B_FALSE;
+       int err = 0;
+
+       if (type == ZFS_TYPE_POOL) {
+               proptype = zpool_prop_get_type(prop);
+               propname = zpool_prop_to_name(prop);
+       } else {
+               proptype = zfs_prop_get_type(prop);
+               propname = zfs_prop_to_name(prop);
+       }
+
+       /*
+        * Convert any properties to the internal DSL value types.
+        */
+       *svalp = NULL;
+       *ivalp = 0;
+
+       switch (proptype) {
+       case PROP_TYPE_STRING:
+               if (datatype != DATA_TYPE_STRING) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' must be a string"), nvpair_name(elem));
+                       goto error;
+               }
+               err = nvpair_value_string(elem, svalp);
+               if (err != 0) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' is invalid"), nvpair_name(elem));
+                       goto error;
+               }
+               if (strlen(*svalp) >= ZFS_MAXPROPLEN) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' is too long"), nvpair_name(elem));
+                       goto error;
+               }
+               break;
+
+       case PROP_TYPE_NUMBER:
+               if (datatype == DATA_TYPE_STRING) {
+                       (void) nvpair_value_string(elem, &value);
+                       if (strcmp(value, "none") == 0) {
+                               isnone = B_TRUE;
+                       } else if (zfs_nicestrtonum(hdl, value, ivalp)
+                           != 0) {
+                               goto error;
+                       }
+               } else if (datatype == DATA_TYPE_UINT64) {
+                       (void) nvpair_value_uint64(elem, ivalp);
+               } else {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' must be a number"), nvpair_name(elem));
+                       goto error;
+               }
+
+               /*
+                * Quota special: force 'none' and don't allow 0.
+                */
+               if ((type & ZFS_TYPE_DATASET) && *ivalp == 0 && !isnone &&
+                   (prop == ZFS_PROP_QUOTA || prop == ZFS_PROP_REFQUOTA)) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "use 'none' to disable quota/refquota"));
+                       goto error;
+               }
+
+               /*
+                * Special handling for "*_limit=none". In this case it's not
+                * 0 but UINT64_MAX.
+                */
+               if ((type & ZFS_TYPE_DATASET) && isnone &&
+                   (prop == ZFS_PROP_FILESYSTEM_LIMIT ||
+                   prop == ZFS_PROP_SNAPSHOT_LIMIT)) {
+                       *ivalp = UINT64_MAX;
+               }
+               break;
+
+       case PROP_TYPE_INDEX:
+               if (datatype != DATA_TYPE_STRING) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' must be a string"), nvpair_name(elem));
+                       goto error;
+               }
+
+               (void) nvpair_value_string(elem, &value);
+
+               if (zprop_string_to_index(prop, value, ivalp, type) != 0) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "'%s' must be one of '%s'"), propname,
+                           zprop_values(prop, type));
+                       goto error;
+               }
+               break;
+
+       default:
+               abort();
+       }
+
+       /*
+        * Add the result to our return set of properties.
+        */
+       if (*svalp != NULL) {
+               if (nvlist_add_string(ret, propname, *svalp) != 0) {
+                       (void) no_memory(hdl);
+                       return (-1);
+               }
+       } else {
+               if (nvlist_add_uint64(ret, propname, *ivalp) != 0) {
+                       (void) no_memory(hdl);
+                       return (-1);
+               }
+       }
+
+       return (0);
+error:
+       (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
+       return (-1);
+}
+
+static int
+addlist(libzfs_handle_t *hdl, char *propname, zprop_list_t **listp,
+    zfs_type_t type)
+{
+       int prop;
+       zprop_list_t *entry;
+
+       prop = zprop_name_to_prop(propname, type);
+
+       if (prop != ZPROP_INVAL && !zprop_valid_for_type(prop, type, B_FALSE))
+               prop = ZPROP_INVAL;
+
+       /*
+        * When no property table entry can be found, return failure if
+        * this is a pool property or if this isn't a user-defined
+        * dataset property,
+        */
+       if (prop == ZPROP_INVAL && ((type == ZFS_TYPE_POOL &&
+           !zpool_prop_feature(propname) &&
+           !zpool_prop_unsupported(propname)) ||
+           (type == ZFS_TYPE_DATASET && !zfs_prop_user(propname) &&
+           !zfs_prop_userquota(propname) && !zfs_prop_written(propname)))) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "invalid property '%s'"), propname);
+               return (zfs_error(hdl, EZFS_BADPROP,
+                   dgettext(TEXT_DOMAIN, "bad property list")));
+       }
+
+       if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
+               return (-1);
+
+       entry->pl_prop = prop;
+       if (prop == ZPROP_INVAL) {
+               if ((entry->pl_user_prop = zfs_strdup(hdl, propname)) ==
+                   NULL) {
+                       free(entry);
+                       return (-1);
+               }
+               entry->pl_width = strlen(propname);
+       } else {
+               entry->pl_width = zprop_width(prop, &entry->pl_fixed,
+                   type);
+       }
+
+       *listp = entry;
+
+       return (0);
+}
+
+/*
+ * Given a comma-separated list of properties, construct a property list
+ * containing both user-defined and native properties.  This function will
+ * return a NULL list if 'all' is specified, which can later be expanded
+ * by zprop_expand_list().
+ */
+int
+zprop_get_list(libzfs_handle_t *hdl, char *props, zprop_list_t **listp,
+    zfs_type_t type)
+{
+       *listp = NULL;
+
+       /*
+        * If 'all' is specified, return a NULL list.
+        */
+       if (strcmp(props, "all") == 0)
+               return (0);
+
+       /*
+        * If no props were specified, return an error.
+        */
+       if (props[0] == '\0') {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "no properties specified"));
+               return (zfs_error(hdl, EZFS_BADPROP, dgettext(TEXT_DOMAIN,
+                   "bad property list")));
+       }
+
+       /*
+        * It would be nice to use getsubopt() here, but the inclusion of column
+        * aliases makes this more effort than it's worth.
+        */
+       while (*props != '\0') {
+               size_t len;
+               char *p;
+               char c;
+
+               if ((p = strchr(props, ',')) == NULL) {
+                       len = strlen(props);
+                       p = props + len;
+               } else {
+                       len = p - props;
+               }
+
+               /*
+                * Check for empty options.
+                */
+               if (len == 0) {
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "empty property name"));
+                       return (zfs_error(hdl, EZFS_BADPROP,
+                           dgettext(TEXT_DOMAIN, "bad property list")));
+               }
+
+               /*
+                * Check all regular property names.
+                */
+               c = props[len];
+               props[len] = '\0';
+
+               if (strcmp(props, "space") == 0) {
+                       static char *spaceprops[] = {
+                               "name", "avail", "used", "usedbysnapshots",
+                               "usedbydataset", "usedbyrefreservation",
+                               "usedbychildren", NULL
+                       };
+                       int i;
+
+                       for (i = 0; spaceprops[i]; i++) {
+                               if (addlist(hdl, spaceprops[i], listp, type))
+                                       return (-1);
+                               listp = &(*listp)->pl_next;
+                       }
+               } else {
+                       if (addlist(hdl, props, listp, type))
+                               return (-1);
+                       listp = &(*listp)->pl_next;
+               }
+
+               props = p;
+               if (c == ',')
+                       props++;
+       }
+
+       return (0);
+}
+
+void
+zprop_free_list(zprop_list_t *pl)
+{
+       zprop_list_t *next;
+
+       while (pl != NULL) {
+               next = pl->pl_next;
+               free(pl->pl_user_prop);
+               free(pl);
+               pl = next;
+       }
+}
+
+typedef struct expand_data {
+       zprop_list_t    **last;
+       libzfs_handle_t *hdl;
+       zfs_type_t type;
+} expand_data_t;
+
+int
+zprop_expand_list_cb(int prop, void *cb)
+{
+       zprop_list_t *entry;
+       expand_data_t *edp = cb;
+
+       if ((entry = zfs_alloc(edp->hdl, sizeof (zprop_list_t))) == NULL)
+               return (ZPROP_INVAL);
+
+       entry->pl_prop = prop;
+       entry->pl_width = zprop_width(prop, &entry->pl_fixed, edp->type);
+       entry->pl_all = B_TRUE;
+
+       *(edp->last) = entry;
+       edp->last = &entry->pl_next;
+
+       return (ZPROP_CONT);
+}
+
+int
+zprop_expand_list(libzfs_handle_t *hdl, zprop_list_t **plp, zfs_type_t type)
+{
+       zprop_list_t *entry;
+       zprop_list_t **last;
+       expand_data_t exp;
+
+       if (*plp == NULL) {
+               /*
+                * If this is the very first time we've been called for an 'all'
+                * specification, expand the list to include all native
+                * properties.
+                */
+               last = plp;
+
+               exp.last = last;
+               exp.hdl = hdl;
+               exp.type = type;
+
+               if (zprop_iter_common(zprop_expand_list_cb, &exp, B_FALSE,
+                   B_FALSE, type) == ZPROP_INVAL)
+                       return (-1);
+
+               /*
+                * Add 'name' to the beginning of the list, which is handled
+                * specially.
+                */
+               if ((entry = zfs_alloc(hdl, sizeof (zprop_list_t))) == NULL)
+                       return (-1);
+
+               entry->pl_prop = (type == ZFS_TYPE_POOL) ?  ZPOOL_PROP_NAME :
+                   ZFS_PROP_NAME;
+               entry->pl_width = zprop_width(entry->pl_prop,
+                   &entry->pl_fixed, type);
+               entry->pl_all = B_TRUE;
+               entry->pl_next = *plp;
+               *plp = entry;
+       }
+       return (0);
+}
+
+int
+zprop_iter(zprop_func func, void *cb, boolean_t show_all, boolean_t ordered,
+    zfs_type_t type)
+{
+       return (zprop_iter_common(func, cb, show_all, ordered, type));
+}
diff --git a/zfs/lib/libzfs_core/Makefile.am b/zfs/lib/libzfs_core/Makefile.am
new file mode 100644 (file)
index 0000000..5eafc25
--- /dev/null
@@ -0,0 +1,23 @@
+include $(top_srcdir)/config/Rules.am
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+lib_LTLIBRARIES = libzfs_core.la
+
+USER_C = \
+       libzfs_core.c
+
+KERNEL_C =
+
+nodist_libzfs_core_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+libzfs_core_la_LIBADD = \
+       $(top_builddir)/lib/libnvpair/libnvpair.la
+
+libzfs_core_la_LDFLAGS = -version-info 1:0:0
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libzfs_core/Makefile.in b/zfs/lib/libzfs_core/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libzfs_core/libzfs_core.c b/zfs/lib/libzfs_core/libzfs_core.c
new file mode 100644 (file)
index 0000000..4fad64e
--- /dev/null
@@ -0,0 +1,928 @@
+/*
+ * 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 (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013 Steven Hartland. All rights reserved.
+ */
+
+/*
+ * LibZFS_Core (lzc) is intended to replace most functionality in libzfs.
+ * It has the following characteristics:
+ *
+ *  - Thread Safe.  libzfs_core is accessible concurrently from multiple
+ *  threads.  This is accomplished primarily by avoiding global data
+ *  (e.g. caching).  Since it's thread-safe, there is no reason for a
+ *  process to have multiple libzfs "instances".  Therefore, we store
+ *  our few pieces of data (e.g. the file descriptor) in global
+ *  variables.  The fd is reference-counted so that the libzfs_core
+ *  library can be "initialized" multiple times (e.g. by different
+ *  consumers within the same process).
+ *
+ *  - Committed Interface.  The libzfs_core interface will be committed,
+ *  therefore consumers can compile against it and be confident that
+ *  their code will continue to work on future releases of this code.
+ *  Currently, the interface is Evolving (not Committed), but we intend
+ *  to commit to it once it is more complete and we determine that it
+ *  meets the needs of all consumers.
+ *
+ *  - Programmatic Error Handling.  libzfs_core communicates errors with
+ *  defined error numbers, and doesn't print anything to stdout/stderr.
+ *
+ *  - Thin Layer.  libzfs_core is a thin layer, marshaling arguments
+ *  to/from the kernel ioctls.  There is generally a 1:1 correspondence
+ *  between libzfs_core functions and ioctls to /dev/zfs.
+ *
+ *  - Clear Atomicity.  Because libzfs_core functions are generally 1:1
+ *  with kernel ioctls, and kernel ioctls are general atomic, each
+ *  libzfs_core function is atomic.  For example, creating multiple
+ *  snapshots with a single call to lzc_snapshot() is atomic -- it
+ *  can't fail with only some of the requested snapshots created, even
+ *  in the event of power loss or system crash.
+ *
+ *  - Continued libzfs Support.  Some higher-level operations (e.g.
+ *  support for "zfs send -R") are too complicated to fit the scope of
+ *  libzfs_core.  This functionality will continue to live in libzfs.
+ *  Where appropriate, libzfs will use the underlying atomic operations
+ *  of libzfs_core.  For example, libzfs may implement "zfs send -R |
+ *  zfs receive" by using individual "send one snapshot", rename,
+ *  destroy, and "receive one snapshot" operations in libzfs_core.
+ *  /sbin/zfs and /zbin/zpool will link with both libzfs and
+ *  libzfs_core.  Other consumers should aim to use only libzfs_core,
+ *  since that will be the supported, stable interface going forwards.
+ */
+
+#include <libzfs_core.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/nvpair.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/zfs_ioctl.h>
+
+static int g_fd;
+static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
+static int g_refcount;
+
+int
+libzfs_core_init(void)
+{
+       (void) pthread_mutex_lock(&g_lock);
+       if (g_refcount == 0) {
+               g_fd = open("/dev/zfs", O_RDWR);
+               if (g_fd < 0) {
+                       (void) pthread_mutex_unlock(&g_lock);
+                       return (errno);
+               }
+       }
+       g_refcount++;
+       (void) pthread_mutex_unlock(&g_lock);
+       return (0);
+}
+
+void
+libzfs_core_fini(void)
+{
+       (void) pthread_mutex_lock(&g_lock);
+       ASSERT3S(g_refcount, >, 0);
+       g_refcount--;
+       if (g_refcount == 0)
+               (void) close(g_fd);
+       (void) pthread_mutex_unlock(&g_lock);
+}
+
+static int
+lzc_ioctl(zfs_ioc_t ioc, const char *name,
+    nvlist_t *source, nvlist_t **resultp)
+{
+       zfs_cmd_t zc = {"\0"};
+       int error = 0;
+       char *packed;
+       size_t size;
+
+       ASSERT3S(g_refcount, >, 0);
+
+       (void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));
+
+       packed = fnvlist_pack(source, &size);
+       zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
+       zc.zc_nvlist_src_size = size;
+
+       if (resultp != NULL) {
+               *resultp = NULL;
+               zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
+               zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
+                   malloc(zc.zc_nvlist_dst_size);
+               if (zc.zc_nvlist_dst == (uint64_t)0) {
+                       error = ENOMEM;
+                       goto out;
+               }
+       }
+
+       while (ioctl(g_fd, ioc, &zc) != 0) {
+               if (errno == ENOMEM && resultp != NULL) {
+                       free((void *)(uintptr_t)zc.zc_nvlist_dst);
+                       zc.zc_nvlist_dst_size *= 2;
+                       zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
+                           malloc(zc.zc_nvlist_dst_size);
+                       if (zc.zc_nvlist_dst == (uint64_t)0) {
+                               error = ENOMEM;
+                               goto out;
+                       }
+               } else {
+                       error = errno;
+                       break;
+               }
+       }
+       if (zc.zc_nvlist_dst_filled) {
+               *resultp = fnvlist_unpack((void *)(uintptr_t)zc.zc_nvlist_dst,
+                   zc.zc_nvlist_dst_size);
+       }
+
+out:
+       fnvlist_pack_free(packed, size);
+       free((void *)(uintptr_t)zc.zc_nvlist_dst);
+       return (error);
+}
+
+int
+lzc_create(const char *fsname, dmu_objset_type_t type, nvlist_t *props)
+{
+       int error;
+       nvlist_t *args = fnvlist_alloc();
+       fnvlist_add_int32(args, "type", type);
+       if (props != NULL)
+               fnvlist_add_nvlist(args, "props", props);
+       error = lzc_ioctl(ZFS_IOC_CREATE, fsname, args, NULL);
+       nvlist_free(args);
+       return (error);
+}
+
+int
+lzc_clone(const char *fsname, const char *origin,
+    nvlist_t *props)
+{
+       int error;
+       nvlist_t *args = fnvlist_alloc();
+       fnvlist_add_string(args, "origin", origin);
+       if (props != NULL)
+               fnvlist_add_nvlist(args, "props", props);
+       error = lzc_ioctl(ZFS_IOC_CLONE, fsname, args, NULL);
+       nvlist_free(args);
+       return (error);
+}
+
+/*
+ * Creates snapshots.
+ *
+ * The keys in the snaps nvlist are the snapshots to be created.
+ * They must all be in the same pool.
+ *
+ * The props nvlist is properties to set.  Currently only user properties
+ * are supported.  { user:prop_name -> string value }
+ *
+ * The returned results nvlist will have an entry for each snapshot that failed.
+ * The value will be the (int32) error code.
+ *
+ * The return value will be 0 if all snapshots were created, otherwise it will
+ * be the errno of a (unspecified) snapshot that failed.
+ */
+int
+lzc_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t **errlist)
+{
+       nvpair_t *elem;
+       nvlist_t *args;
+       int error;
+       char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+       *errlist = NULL;
+
+       /* determine the pool name */
+       elem = nvlist_next_nvpair(snaps, NULL);
+       if (elem == NULL)
+               return (0);
+       (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+       pool[strcspn(pool, "/@")] = '\0';
+
+       args = fnvlist_alloc();
+       fnvlist_add_nvlist(args, "snaps", snaps);
+       if (props != NULL)
+               fnvlist_add_nvlist(args, "props", props);
+
+       error = lzc_ioctl(ZFS_IOC_SNAPSHOT, pool, args, errlist);
+       nvlist_free(args);
+
+       return (error);
+}
+
+/*
+ * Destroys snapshots.
+ *
+ * The keys in the snaps nvlist are the snapshots to be destroyed.
+ * They must all be in the same pool.
+ *
+ * Snapshots that do not exist will be silently ignored.
+ *
+ * If 'defer' is not set, and a snapshot has user holds or clones, the
+ * destroy operation will fail and none of the snapshots will be
+ * destroyed.
+ *
+ * If 'defer' is set, and a snapshot has user holds or clones, it will be
+ * marked for deferred destruction, and will be destroyed when the last hold
+ * or clone is removed/destroyed.
+ *
+ * The return value will be 0 if all snapshots were destroyed (or marked for
+ * later destruction if 'defer' is set) or didn't exist to begin with.
+ *
+ * Otherwise the return value will be the errno of a (unspecified) snapshot
+ * that failed, no snapshots will be destroyed, and the errlist will have an
+ * entry for each snapshot that failed.  The value in the errlist will be
+ * the (int32) error code.
+ */
+int
+lzc_destroy_snaps(nvlist_t *snaps, boolean_t defer, nvlist_t **errlist)
+{
+       nvpair_t *elem;
+       nvlist_t *args;
+       int error;
+       char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+       /* determine the pool name */
+       elem = nvlist_next_nvpair(snaps, NULL);
+       if (elem == NULL)
+               return (0);
+       (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+       pool[strcspn(pool, "/@")] = '\0';
+
+       args = fnvlist_alloc();
+       fnvlist_add_nvlist(args, "snaps", snaps);
+       if (defer)
+               fnvlist_add_boolean(args, "defer");
+
+       error = lzc_ioctl(ZFS_IOC_DESTROY_SNAPS, pool, args, errlist);
+       nvlist_free(args);
+
+       return (error);
+}
+
+int
+lzc_snaprange_space(const char *firstsnap, const char *lastsnap,
+    uint64_t *usedp)
+{
+       nvlist_t *args;
+       nvlist_t *result;
+       int err;
+       char fs[ZFS_MAX_DATASET_NAME_LEN];
+       char *atp;
+
+       /* determine the fs name */
+       (void) strlcpy(fs, firstsnap, sizeof (fs));
+       atp = strchr(fs, '@');
+       if (atp == NULL)
+               return (EINVAL);
+       *atp = '\0';
+
+       args = fnvlist_alloc();
+       fnvlist_add_string(args, "firstsnap", firstsnap);
+
+       err = lzc_ioctl(ZFS_IOC_SPACE_SNAPS, lastsnap, args, &result);
+       nvlist_free(args);
+       if (err == 0)
+               *usedp = fnvlist_lookup_uint64(result, "used");
+       fnvlist_free(result);
+
+       return (err);
+}
+
+boolean_t
+lzc_exists(const char *dataset)
+{
+       /*
+        * The objset_stats ioctl is still legacy, so we need to construct our
+        * own zfs_cmd_t rather than using zfsc_ioctl().
+        */
+       zfs_cmd_t zc = {"\0"};
+
+       (void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));
+       return (ioctl(g_fd, ZFS_IOC_OBJSET_STATS, &zc) == 0);
+}
+
+/*
+ * Create "user holds" on snapshots.  If there is a hold on a snapshot,
+ * the snapshot can not be destroyed.  (However, it can be marked for deletion
+ * by lzc_destroy_snaps(defer=B_TRUE).)
+ *
+ * The keys in the nvlist are snapshot names.
+ * The snapshots must all be in the same pool.
+ * The value is the name of the hold (string type).
+ *
+ * If cleanup_fd is not -1, it must be the result of open("/dev/zfs", O_EXCL).
+ * In this case, when the cleanup_fd is closed (including on process
+ * termination), the holds will be released.  If the system is shut down
+ * uncleanly, the holds will be released when the pool is next opened
+ * or imported.
+ *
+ * Holds for snapshots which don't exist will be skipped and have an entry
+ * added to errlist, but will not cause an overall failure.
+ *
+ * The return value will be 0 if all holds, for snapshots that existed,
+ * were successfully created.
+ *
+ * Otherwise the return value will be the errno of a (unspecified) hold that
+ * failed and no holds will be created.
+ *
+ * In all cases the errlist will have an entry for each hold that failed
+ * (name = snapshot), with its value being the error code (int32).
+ */
+int
+lzc_hold(nvlist_t *holds, int cleanup_fd, nvlist_t **errlist)
+{
+       char pool[ZFS_MAX_DATASET_NAME_LEN];
+       nvlist_t *args;
+       nvpair_t *elem;
+       int error;
+
+       /* determine the pool name */
+       elem = nvlist_next_nvpair(holds, NULL);
+       if (elem == NULL)
+               return (0);
+       (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+       pool[strcspn(pool, "/@")] = '\0';
+
+       args = fnvlist_alloc();
+       fnvlist_add_nvlist(args, "holds", holds);
+       if (cleanup_fd != -1)
+               fnvlist_add_int32(args, "cleanup_fd", cleanup_fd);
+
+       error = lzc_ioctl(ZFS_IOC_HOLD, pool, args, errlist);
+       nvlist_free(args);
+       return (error);
+}
+
+/*
+ * Release "user holds" on snapshots.  If the snapshot has been marked for
+ * deferred destroy (by lzc_destroy_snaps(defer=B_TRUE)), it does not have
+ * any clones, and all the user holds are removed, then the snapshot will be
+ * destroyed.
+ *
+ * The keys in the nvlist are snapshot names.
+ * The snapshots must all be in the same pool.
+ * The value is an nvlist whose keys are the holds to remove.
+ *
+ * Holds which failed to release because they didn't exist will have an entry
+ * added to errlist, but will not cause an overall failure.
+ *
+ * The return value will be 0 if the nvl holds was empty or all holds that
+ * existed, were successfully removed.
+ *
+ * Otherwise the return value will be the errno of a (unspecified) hold that
+ * failed to release and no holds will be released.
+ *
+ * In all cases the errlist will have an entry for each hold that failed to
+ * to release.
+ */
+int
+lzc_release(nvlist_t *holds, nvlist_t **errlist)
+{
+       char pool[ZFS_MAX_DATASET_NAME_LEN];
+       nvpair_t *elem;
+
+       /* determine the pool name */
+       elem = nvlist_next_nvpair(holds, NULL);
+       if (elem == NULL)
+               return (0);
+       (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+       pool[strcspn(pool, "/@")] = '\0';
+
+       return (lzc_ioctl(ZFS_IOC_RELEASE, pool, holds, errlist));
+}
+
+/*
+ * Retrieve list of user holds on the specified snapshot.
+ *
+ * On success, *holdsp will be set to an nvlist which the caller must free.
+ * The keys are the names of the holds, and the value is the creation time
+ * of the hold (uint64) in seconds since the epoch.
+ */
+int
+lzc_get_holds(const char *snapname, nvlist_t **holdsp)
+{
+       int error;
+       nvlist_t *innvl = fnvlist_alloc();
+       error = lzc_ioctl(ZFS_IOC_GET_HOLDS, snapname, innvl, holdsp);
+       fnvlist_free(innvl);
+       return (error);
+}
+
+/*
+ * Generate a zfs send stream for the specified snapshot and write it to
+ * the specified file descriptor.
+ *
+ * "snapname" is the full name of the snapshot to send (e.g. "pool/fs@snap")
+ *
+ * If "from" is NULL, a full (non-incremental) stream will be sent.
+ * If "from" is non-NULL, it must be the full name of a snapshot or
+ * bookmark to send an incremental from (e.g. "pool/fs@earlier_snap" or
+ * "pool/fs#earlier_bmark").  If non-NULL, the specified snapshot or
+ * bookmark must represent an earlier point in the history of "snapname").
+ * It can be an earlier snapshot in the same filesystem or zvol as "snapname",
+ * or it can be the origin of "snapname"'s filesystem, or an earlier
+ * snapshot in the origin, etc.
+ *
+ * "fd" is the file descriptor to write the send stream to.
+ *
+ * If "flags" contains LZC_SEND_FLAG_LARGE_BLOCK, the stream is permitted
+ * to contain DRR_WRITE records with drr_length > 128K, and DRR_OBJECT
+ * records with drr_blksz > 128K.
+ *
+ * If "flags" contains LZC_SEND_FLAG_EMBED_DATA, the stream is permitted
+ * to contain DRR_WRITE_EMBEDDED records with drr_etype==BP_EMBEDDED_TYPE_DATA,
+ * which the receiving system must support (as indicated by support
+ * for the "embedded_data" feature).
+ */
+int
+lzc_send(const char *snapname, const char *from, int fd,
+    enum lzc_send_flags flags)
+{
+       return (lzc_send_resume(snapname, from, fd, flags, 0, 0));
+}
+
+int
+lzc_send_resume(const char *snapname, const char *from, int fd,
+    enum lzc_send_flags flags, uint64_t resumeobj, uint64_t resumeoff)
+{
+       nvlist_t *args;
+       int err;
+
+       args = fnvlist_alloc();
+       fnvlist_add_int32(args, "fd", fd);
+       if (from != NULL)
+               fnvlist_add_string(args, "fromsnap", from);
+       if (flags & LZC_SEND_FLAG_LARGE_BLOCK)
+               fnvlist_add_boolean(args, "largeblockok");
+       if (flags & LZC_SEND_FLAG_COMPRESS)
+               fnvlist_add_boolean(args, "compressok");
+       if (flags & LZC_SEND_FLAG_EMBED_DATA)
+               fnvlist_add_boolean(args, "embedok");
+       if (resumeobj != 0 || resumeoff != 0) {
+               fnvlist_add_uint64(args, "resume_object", resumeobj);
+               fnvlist_add_uint64(args, "resume_offset", resumeoff);
+       }
+       err = lzc_ioctl(ZFS_IOC_SEND_NEW, snapname, args, NULL);
+       nvlist_free(args);
+       return (err);
+}
+
+/*
+ * "from" can be NULL, a snapshot, or a bookmark.
+ *
+ * If from is NULL, a full (non-incremental) stream will be estimated.  This
+ * is calculated very efficiently.
+ *
+ * If from is a snapshot, lzc_send_space uses the deadlists attached to
+ * each snapshot to efficiently estimate the stream size.
+ *
+ * If from is a bookmark, the indirect blocks in the destination snapshot
+ * are traversed, looking for blocks with a birth time since the creation TXG of
+ * the snapshot this bookmark was created from.  This will result in
+ * significantly more I/O and be less efficient than a send space estimation on
+ * an equivalent snapshot.
+ */
+int
+lzc_send_space(const char *snapname, const char *from,
+    enum lzc_send_flags flags, uint64_t *spacep)
+{
+       nvlist_t *args;
+       nvlist_t *result;
+       int err;
+
+       args = fnvlist_alloc();
+       if (from != NULL)
+               fnvlist_add_string(args, "from", from);
+       if (flags & LZC_SEND_FLAG_LARGE_BLOCK)
+               fnvlist_add_boolean(args, "largeblockok");
+       if (flags & LZC_SEND_FLAG_EMBED_DATA)
+               fnvlist_add_boolean(args, "embedok");
+       if (flags & LZC_SEND_FLAG_COMPRESS)
+               fnvlist_add_boolean(args, "compressok");
+       err = lzc_ioctl(ZFS_IOC_SEND_SPACE, snapname, args, &result);
+       nvlist_free(args);
+       if (err == 0)
+               *spacep = fnvlist_lookup_uint64(result, "space");
+       nvlist_free(result);
+       return (err);
+}
+
+static int
+recv_read(int fd, void *buf, int ilen)
+{
+       char *cp = buf;
+       int rv;
+       int len = ilen;
+
+       do {
+               rv = read(fd, cp, len);
+               cp += rv;
+               len -= rv;
+       } while (rv > 0);
+
+       if (rv < 0 || len != 0)
+               return (EIO);
+
+       return (0);
+}
+
+/*
+ * Linux adds ZFS_IOC_RECV_NEW for resumable streams and preserves the legacy
+ * ZFS_IOC_RECV user/kernel interface.  The new interface supports all stream
+ * options but is currently only used for resumable streams.  This way updated
+ * user space utilities will interoperate with older kernel modules.
+ *
+ * Non-Linux OpenZFS platforms have opted to modify the legacy interface.
+ */
+static int
+recv_impl(const char *snapname, nvlist_t *props, const char *origin,
+    boolean_t force, boolean_t resumable, int input_fd,
+    const dmu_replay_record_t *begin_record, int cleanup_fd,
+    uint64_t *read_bytes, uint64_t *errflags, uint64_t *action_handle,
+    nvlist_t **errors)
+{
+       dmu_replay_record_t drr;
+       char fsname[MAXPATHLEN];
+       char *atp;
+       int error;
+
+       /* Set 'fsname' to the name of containing filesystem */
+       (void) strlcpy(fsname, snapname, sizeof (fsname));
+       atp = strchr(fsname, '@');
+       if (atp == NULL)
+               return (EINVAL);
+       *atp = '\0';
+
+       /* If the fs does not exist, try its parent. */
+       if (!lzc_exists(fsname)) {
+               char *slashp = strrchr(fsname, '/');
+               if (slashp == NULL)
+                       return (ENOENT);
+               *slashp = '\0';
+       }
+
+       /*
+        * The begin_record is normally a non-byteswapped BEGIN record.
+        * For resumable streams it may be set to any non-byteswapped
+        * dmu_replay_record_t.
+        */
+       if (begin_record == NULL) {
+               error = recv_read(input_fd, &drr, sizeof (drr));
+               if (error != 0)
+                       return (error);
+       } else {
+               drr = *begin_record;
+       }
+
+       if (resumable) {
+               nvlist_t *outnvl = NULL;
+               nvlist_t *innvl = fnvlist_alloc();
+
+               fnvlist_add_string(innvl, "snapname", snapname);
+
+               if (props != NULL)
+                       fnvlist_add_nvlist(innvl, "props", props);
+
+               if (origin != NULL && strlen(origin))
+                       fnvlist_add_string(innvl, "origin", origin);
+
+               fnvlist_add_byte_array(innvl, "begin_record",
+                   (uchar_t *) &drr, sizeof (drr));
+
+               fnvlist_add_int32(innvl, "input_fd", input_fd);
+
+               if (force)
+                       fnvlist_add_boolean(innvl, "force");
+
+               if (resumable)
+                       fnvlist_add_boolean(innvl, "resumable");
+
+               if (cleanup_fd >= 0)
+                       fnvlist_add_int32(innvl, "cleanup_fd", cleanup_fd);
+
+               if (action_handle != NULL)
+                       fnvlist_add_uint64(innvl, "action_handle",
+                           *action_handle);
+
+               error = lzc_ioctl(ZFS_IOC_RECV_NEW, fsname, innvl, &outnvl);
+
+               if (error == 0 && read_bytes != NULL)
+                       error = nvlist_lookup_uint64(outnvl, "read_bytes",
+                           read_bytes);
+
+               if (error == 0 && errflags != NULL)
+                       error = nvlist_lookup_uint64(outnvl, "error_flags",
+                           errflags);
+
+               if (error == 0 && action_handle != NULL)
+                       error = nvlist_lookup_uint64(outnvl, "action_handle",
+                           action_handle);
+
+               if (error == 0 && errors != NULL) {
+                       nvlist_t *nvl;
+                       error = nvlist_lookup_nvlist(outnvl, "errors", &nvl);
+                       if (error == 0)
+                               *errors = fnvlist_dup(nvl);
+               }
+
+               fnvlist_free(innvl);
+               fnvlist_free(outnvl);
+       } else {
+               zfs_cmd_t zc = {"\0"};
+               char *packed = NULL;
+               size_t size;
+
+               ASSERT3S(g_refcount, >, 0);
+
+               (void) strlcpy(zc.zc_name, fsname, sizeof (zc.zc_value));
+               (void) strlcpy(zc.zc_value, snapname, sizeof (zc.zc_value));
+
+               if (props != NULL) {
+                       packed = fnvlist_pack(props, &size);
+                       zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
+                       zc.zc_nvlist_src_size = size;
+               }
+
+               if (origin != NULL)
+                       (void) strlcpy(zc.zc_string, origin,
+                           sizeof (zc.zc_string));
+
+               ASSERT3S(drr.drr_type, ==, DRR_BEGIN);
+               zc.zc_begin_record = drr.drr_u.drr_begin;
+               zc.zc_guid = force;
+               zc.zc_cookie = input_fd;
+               zc.zc_cleanup_fd = -1;
+               zc.zc_action_handle = 0;
+
+               if (cleanup_fd >= 0)
+                       zc.zc_cleanup_fd = cleanup_fd;
+
+               if (action_handle != NULL)
+                       zc.zc_action_handle = *action_handle;
+
+               zc.zc_nvlist_dst_size = 128 * 1024;
+               zc.zc_nvlist_dst = (uint64_t)(uintptr_t)
+                   malloc(zc.zc_nvlist_dst_size);
+
+               error = ioctl(g_fd, ZFS_IOC_RECV, &zc);
+               if (error != 0) {
+                       error = errno;
+               } else {
+                       if (read_bytes != NULL)
+                               *read_bytes = zc.zc_cookie;
+
+                       if (errflags != NULL)
+                               *errflags = zc.zc_obj;
+
+                       if (action_handle != NULL)
+                               *action_handle = zc.zc_action_handle;
+
+                       if (errors != NULL)
+                               VERIFY0(nvlist_unpack(
+                                   (void *)(uintptr_t)zc.zc_nvlist_dst,
+                                   zc.zc_nvlist_dst_size, errors, KM_SLEEP));
+               }
+
+               if (packed != NULL)
+                       fnvlist_pack_free(packed, size);
+               free((void *)(uintptr_t)zc.zc_nvlist_dst);
+       }
+
+       return (error);
+}
+
+/*
+ * The simplest receive case: receive from the specified fd, creating the
+ * specified snapshot.  Apply the specified properties as "received" properties
+ * (which can be overridden by locally-set properties).  If the stream is a
+ * clone, its origin snapshot must be specified by 'origin'.  The 'force'
+ * flag will cause the target filesystem to be rolled back or destroyed if
+ * necessary to receive.
+ *
+ * Return 0 on success or an errno on failure.
+ *
+ * Note: this interface does not work on dedup'd streams
+ * (those with DMU_BACKUP_FEATURE_DEDUP).
+ */
+int
+lzc_receive(const char *snapname, nvlist_t *props, const char *origin,
+    boolean_t force, int fd)
+{
+       return (recv_impl(snapname, props, origin, force, B_FALSE, fd,
+           NULL, -1, NULL, NULL, NULL, NULL));
+}
+
+/*
+ * Like lzc_receive, but if the receive fails due to premature stream
+ * termination, the intermediate state will be preserved on disk.  In this
+ * case, ECKSUM will be returned.  The receive may subsequently be resumed
+ * with a resuming send stream generated by lzc_send_resume().
+ */
+int
+lzc_receive_resumable(const char *snapname, nvlist_t *props, const char *origin,
+    boolean_t force, int fd)
+{
+       return (recv_impl(snapname, props, origin, force, B_TRUE, fd,
+           NULL, -1, NULL, NULL, NULL, NULL));
+}
+
+/*
+ * Like lzc_receive, but allows the caller to read the begin record and then to
+ * pass it in.  That could be useful if the caller wants to derive, for example,
+ * the snapname or the origin parameters based on the information contained in
+ * the begin record.
+ * The begin record must be in its original form as read from the stream,
+ * in other words, it should not be byteswapped.
+ *
+ * The 'resumable' parameter allows to obtain the same behavior as with
+ * lzc_receive_resumable.
+ */
+int
+lzc_receive_with_header(const char *snapname, nvlist_t *props,
+    const char *origin, boolean_t force, boolean_t resumable, int fd,
+    const dmu_replay_record_t *begin_record)
+{
+       if (begin_record == NULL)
+               return (EINVAL);
+       return (recv_impl(snapname, props, origin, force, resumable, fd,
+           begin_record, -1, NULL, NULL, NULL, NULL));
+}
+
+/*
+ * Like lzc_receive, but allows the caller to pass all supported arguments
+ * and retrieve all values returned.  The only additional input parameter
+ * is 'cleanup_fd' which is used to set a cleanup-on-exit file descriptor.
+ *
+ * The following parameters all provide return values.  Several may be set
+ * in the failure case and will contain additional information.
+ *
+ * The 'read_bytes' value will be set to the total number of bytes read.
+ *
+ * The 'errflags' value will contain zprop_errflags_t flags which are
+ * used to describe any failures.
+ *
+ * The 'action_handle' is used to pass the handle for this guid/ds mapping.
+ * It should be set to zero on first call and will contain an updated handle
+ * on success, it should be passed in subsequent calls.
+ *
+ * The 'errors' nvlist contains an entry for each unapplied received
+ * property.  Callers are responsible for freeing this nvlist.
+ */
+int lzc_receive_one(const char *snapname, nvlist_t *props,
+    const char *origin, boolean_t force, boolean_t resumable, int input_fd,
+    const dmu_replay_record_t *begin_record, int cleanup_fd,
+    uint64_t *read_bytes, uint64_t *errflags, uint64_t *action_handle,
+    nvlist_t **errors)
+{
+       return (recv_impl(snapname, props, origin, force, resumable,
+           input_fd, begin_record, cleanup_fd, read_bytes, errflags,
+           action_handle, errors));
+}
+
+/*
+ * Roll back this filesystem or volume to its most recent snapshot.
+ * If snapnamebuf is not NULL, it will be filled in with the name
+ * of the most recent snapshot.
+ *
+ * Return 0 on success or an errno on failure.
+ */
+int
+lzc_rollback(const char *fsname, char *snapnamebuf, int snapnamelen)
+{
+       nvlist_t *args;
+       nvlist_t *result;
+       int err;
+
+       args = fnvlist_alloc();
+       err = lzc_ioctl(ZFS_IOC_ROLLBACK, fsname, args, &result);
+       nvlist_free(args);
+       if (err == 0 && snapnamebuf != NULL) {
+               const char *snapname = fnvlist_lookup_string(result, "target");
+               (void) strlcpy(snapnamebuf, snapname, snapnamelen);
+       }
+       return (err);
+}
+
+/*
+ * Creates bookmarks.
+ *
+ * The bookmarks nvlist maps from name of the bookmark (e.g. "pool/fs#bmark") to
+ * the name of the snapshot (e.g. "pool/fs@snap").  All the bookmarks and
+ * snapshots must be in the same pool.
+ *
+ * The returned results nvlist will have an entry for each bookmark that failed.
+ * The value will be the (int32) error code.
+ *
+ * The return value will be 0 if all bookmarks were created, otherwise it will
+ * be the errno of a (undetermined) bookmarks that failed.
+ */
+int
+lzc_bookmark(nvlist_t *bookmarks, nvlist_t **errlist)
+{
+       nvpair_t *elem;
+       int error;
+       char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+       /* determine the pool name */
+       elem = nvlist_next_nvpair(bookmarks, NULL);
+       if (elem == NULL)
+               return (0);
+       (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+       pool[strcspn(pool, "/#")] = '\0';
+
+       error = lzc_ioctl(ZFS_IOC_BOOKMARK, pool, bookmarks, errlist);
+
+       return (error);
+}
+
+/*
+ * Retrieve bookmarks.
+ *
+ * Retrieve the list of bookmarks for the given file system. The props
+ * parameter is an nvlist of property names (with no values) that will be
+ * returned for each bookmark.
+ *
+ * The following are valid properties on bookmarks, all of which are numbers
+ * (represented as uint64 in the nvlist)
+ *
+ * "guid" - globally unique identifier of the snapshot it refers to
+ * "createtxg" - txg when the snapshot it refers to was created
+ * "creation" - timestamp when the snapshot it refers to was created
+ *
+ * The format of the returned nvlist as follows:
+ * <short name of bookmark> -> {
+ *     <name of property> -> {
+ *         "value" -> uint64
+ *     }
+ *  }
+ */
+int
+lzc_get_bookmarks(const char *fsname, nvlist_t *props, nvlist_t **bmarks)
+{
+       return (lzc_ioctl(ZFS_IOC_GET_BOOKMARKS, fsname, props, bmarks));
+}
+
+/*
+ * Destroys bookmarks.
+ *
+ * The keys in the bmarks nvlist are the bookmarks to be destroyed.
+ * They must all be in the same pool.  Bookmarks are specified as
+ * <fs>#<bmark>.
+ *
+ * Bookmarks that do not exist will be silently ignored.
+ *
+ * The return value will be 0 if all bookmarks that existed were destroyed.
+ *
+ * Otherwise the return value will be the errno of a (undetermined) bookmark
+ * that failed, no bookmarks will be destroyed, and the errlist will have an
+ * entry for each bookmarks that failed.  The value in the errlist will be
+ * the (int32) error code.
+ */
+int
+lzc_destroy_bookmarks(nvlist_t *bmarks, nvlist_t **errlist)
+{
+       nvpair_t *elem;
+       int error;
+       char pool[ZFS_MAX_DATASET_NAME_LEN];
+
+       /* determine the pool name */
+       elem = nvlist_next_nvpair(bmarks, NULL);
+       if (elem == NULL)
+               return (0);
+       (void) strlcpy(pool, nvpair_name(elem), sizeof (pool));
+       pool[strcspn(pool, "/#")] = '\0';
+
+       error = lzc_ioctl(ZFS_IOC_DESTROY_BOOKMARKS, pool, bmarks, errlist);
+
+       return (error);
+}
diff --git a/zfs/lib/libzpool/Makefile.am b/zfs/lib/libzpool/Makefile.am
new file mode 100644 (file)
index 0000000..13353a5
--- /dev/null
@@ -0,0 +1,141 @@
+include $(top_srcdir)/config/Rules.am
+
+VPATH = \
+       $(top_srcdir)/module/zfs \
+       $(top_srcdir)/module/zcommon \
+       $(top_srcdir)/lib/libzpool
+
+AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN)
+
+DEFAULT_INCLUDES += \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/lib/libspl/include
+
+lib_LTLIBRARIES = libzpool.la
+
+USER_C = \
+       kernel.c \
+       taskq.c \
+       util.c
+
+KERNEL_C = \
+       zfs_comutil.c \
+       zfs_deleg.c \
+       zfs_fletcher.c \
+       zfs_fletcher_intel.c \
+       zfs_fletcher_sse.c \
+       zfs_fletcher_avx512.c \
+       zfs_fletcher_aarch64_neon.c \
+       zfs_namecheck.c \
+       zfs_prop.c \
+       zfs_uio.c \
+       zpool_prop.c \
+       zprop_common.c \
+       arc.c \
+       blkptr.c \
+       bplist.c \
+       bpobj.c \
+       bptree.c \
+       bqueue.c \
+       dbuf.c \
+       dbuf_stats.c \
+       ddt.c \
+       ddt_zap.c \
+       dmu.c \
+       dmu_diff.c \
+       dmu_object.c \
+       dmu_objset.c \
+       dmu_send.c \
+       dmu_traverse.c \
+       dmu_tx.c \
+       dmu_zfetch.c \
+       dnode.c \
+       dnode_sync.c \
+       dsl_bookmark.c \
+       dsl_dataset.c \
+       dsl_deadlist.c \
+       dsl_deleg.c \
+       dsl_dir.c \
+       dsl_pool.c \
+       dsl_prop.c \
+       dsl_scan.c \
+       dsl_synctask.c \
+       dsl_destroy.c \
+       dsl_userhold.c \
+       edonr_zfs.c \
+       fm.c \
+       gzip.c \
+       lzjb.c \
+       lz4.c \
+       metaslab.c \
+       multilist.c \
+       pathname.c \
+       range_tree.c \
+       refcount.c \
+       rrwlock.c \
+       sa.c \
+       sha256.c \
+       skein_zfs.c \
+       spa.c \
+       spa_boot.c \
+       spa_config.c \
+       spa_errlog.c \
+       spa_history.c \
+       spa_misc.c \
+       spa_stats.c \
+       space_map.c \
+       space_reftree.c \
+       txg.c \
+       trace.c \
+       uberblock.c \
+       unique.c \
+       vdev.c \
+       vdev_cache.c \
+       vdev_file.c \
+       vdev_label.c \
+       vdev_mirror.c \
+       vdev_missing.c \
+       vdev_queue.c \
+       vdev_raidz.c \
+       vdev_raidz_math.c \
+       vdev_raidz_math_scalar.c \
+       vdev_raidz_math_sse2.c \
+       vdev_raidz_math_ssse3.c \
+       vdev_raidz_math_avx2.c \
+       vdev_raidz_math_aarch64_neon.c \
+       vdev_raidz_math_aarch64_neonx2.c \
+       vdev_root.c \
+       zap.c \
+       zap_leaf.c \
+       zap_micro.c \
+       zfeature.c \
+       zfeature_common.c \
+       zfs_byteswap.c \
+       zfs_debug.c \
+       zfs_fm.c \
+       zfs_fuid.c \
+       zfs_sa.c \
+       zfs_znode.c \
+       zfs_rlock.c \
+       zil.c \
+       zio.c \
+       zio_checksum.c \
+       zio_compress.c \
+       zio_inject.c \
+       zle.c \
+       zrlock.c
+
+nodist_libzpool_la_SOURCES = \
+       $(USER_C) \
+       $(KERNEL_C)
+
+libzpool_la_LIBADD = \
+       $(top_builddir)/lib/libunicode/libunicode.la \
+       $(top_builddir)/lib/libuutil/libuutil.la \
+       $(top_builddir)/lib/libnvpair/libnvpair.la \
+       $(top_builddir)/lib/libicp/libicp.la
+
+libzpool_la_LIBADD += $(ZLIB)
+libzpool_la_LDFLAGS = -version-info 2:0:0
+
+EXTRA_DIST = $(USER_C)
diff --git a/zfs/lib/libzpool/Makefile.in b/zfs/lib/libzpool/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/lib/libzpool/kernel.c b/zfs/lib/libzpool/kernel.c
new file mode 100644 (file)
index 0000000..f4bda8a
--- /dev/null
@@ -0,0 +1,1528 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>
+#include <libgen.h>
+#include <sys/signal.h>
+#include <sys/spa.h>
+#include <sys/stat.h>
+#include <sys/processor.h>
+#include <sys/zfs_context.h>
+#include <sys/rrwlock.h>
+#include <sys/utsname.h>
+#include <sys/time.h>
+#include <sys/systeminfo.h>
+#include <zfs_fletcher.h>
+#include <sys/crypto/icp.h>
+
+/*
+ * Emulation of kernel services in userland.
+ */
+
+int aok;
+uint64_t physmem;
+vnode_t *rootdir = (vnode_t *)0xabcd1234;
+char hw_serial[HW_HOSTID_LEN];
+struct utsname hw_utsname;
+vmem_t *zio_arena = NULL;
+
+/* If set, all blocks read will be copied to the specified directory. */
+char *vn_dumpdir = NULL;
+
+/* this only exists to have its address taken */
+struct proc p0;
+
+/*
+ * =========================================================================
+ * threads
+ * =========================================================================
+ */
+
+pthread_cond_t kthread_cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t kthread_lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_key_t kthread_key;
+int kthread_nr = 0;
+
+void
+thread_init(void)
+{
+       kthread_t *kt;
+
+       VERIFY3S(pthread_key_create(&kthread_key, NULL), ==, 0);
+
+       /* Create entry for primary kthread */
+       kt = umem_zalloc(sizeof (kthread_t), UMEM_NOFAIL);
+       kt->t_tid = pthread_self();
+       kt->t_func = NULL;
+
+       VERIFY3S(pthread_setspecific(kthread_key, kt), ==, 0);
+
+       /* Only the main thread should be running at the moment */
+       ASSERT3S(kthread_nr, ==, 0);
+       kthread_nr = 1;
+}
+
+void
+thread_fini(void)
+{
+       kthread_t *kt = curthread;
+
+       ASSERT(pthread_equal(kt->t_tid, pthread_self()));
+       ASSERT3P(kt->t_func, ==, NULL);
+
+       umem_free(kt, sizeof (kthread_t));
+
+       /* Wait for all threads to exit via thread_exit() */
+       VERIFY3S(pthread_mutex_lock(&kthread_lock), ==, 0);
+
+       kthread_nr--; /* Main thread is exiting */
+
+       while (kthread_nr > 0)
+               VERIFY0(pthread_cond_wait(&kthread_cond, &kthread_lock));
+
+       ASSERT3S(kthread_nr, ==, 0);
+       VERIFY3S(pthread_mutex_unlock(&kthread_lock), ==, 0);
+
+       VERIFY3S(pthread_key_delete(kthread_key), ==, 0);
+}
+
+kthread_t *
+zk_thread_current(void)
+{
+       kthread_t *kt = pthread_getspecific(kthread_key);
+
+       ASSERT3P(kt, !=, NULL);
+
+       return (kt);
+}
+
+void *
+zk_thread_helper(void *arg)
+{
+       kthread_t *kt = (kthread_t *) arg;
+
+       VERIFY3S(pthread_setspecific(kthread_key, kt), ==, 0);
+
+       VERIFY3S(pthread_mutex_lock(&kthread_lock), ==, 0);
+       kthread_nr++;
+       VERIFY3S(pthread_mutex_unlock(&kthread_lock), ==, 0);
+       (void) setpriority(PRIO_PROCESS, 0, kt->t_pri);
+
+       kt->t_tid = pthread_self();
+       ((thread_func_arg_t) kt->t_func)(kt->t_arg);
+
+       /* Unreachable, thread must exit with thread_exit() */
+       abort();
+
+       return (NULL);
+}
+
+kthread_t *
+zk_thread_create(caddr_t stk, size_t stksize, thread_func_t func, void *arg,
+    size_t len, proc_t *pp, int state, pri_t pri, int detachstate)
+{
+       kthread_t *kt;
+       pthread_attr_t attr;
+       char *stkstr;
+
+       ASSERT0(state & ~TS_RUN);
+
+       kt = umem_zalloc(sizeof (kthread_t), UMEM_NOFAIL);
+       kt->t_func = func;
+       kt->t_arg = arg;
+       kt->t_pri = pri;
+
+       VERIFY0(pthread_attr_init(&attr));
+       VERIFY0(pthread_attr_setdetachstate(&attr, detachstate));
+
+       /*
+        * We allow the default stack size in user space to be specified by
+        * setting the ZFS_STACK_SIZE environment variable.  This allows us
+        * the convenience of observing and debugging stack overruns in
+        * user space.  Explicitly specified stack sizes will be honored.
+        * The usage of ZFS_STACK_SIZE is discussed further in the
+        * ENVIRONMENT VARIABLES sections of the ztest(1) man page.
+        */
+       if (stksize == 0) {
+               stkstr = getenv("ZFS_STACK_SIZE");
+
+               if (stkstr == NULL)
+                       stksize = TS_STACK_MAX;
+               else
+                       stksize = MAX(atoi(stkstr), TS_STACK_MIN);
+       }
+
+       VERIFY3S(stksize, >, 0);
+       stksize = P2ROUNDUP(MAX(stksize, TS_STACK_MIN), PAGESIZE);
+       /*
+        * If this ever fails, it may be because the stack size is not a
+        * multiple of system page size.
+        */
+       VERIFY0(pthread_attr_setstacksize(&attr, stksize));
+       VERIFY0(pthread_attr_setguardsize(&attr, PAGESIZE));
+
+       VERIFY0(pthread_create(&kt->t_tid, &attr, &zk_thread_helper, kt));
+       VERIFY0(pthread_attr_destroy(&attr));
+
+       return (kt);
+}
+
+void
+zk_thread_exit(void)
+{
+       kthread_t *kt = curthread;
+
+       ASSERT(pthread_equal(kt->t_tid, pthread_self()));
+
+       umem_free(kt, sizeof (kthread_t));
+
+       VERIFY0(pthread_mutex_lock(&kthread_lock));
+       kthread_nr--;
+       VERIFY0(pthread_mutex_unlock(&kthread_lock));
+
+       VERIFY0(pthread_cond_broadcast(&kthread_cond));
+       pthread_exit((void *)TS_MAGIC);
+}
+
+void
+zk_thread_join(kt_did_t tid)
+{
+       void *ret;
+
+       pthread_join((pthread_t)tid, &ret);
+       VERIFY3P(ret, ==, (void *)TS_MAGIC);
+}
+
+/*
+ * =========================================================================
+ * kstats
+ * =========================================================================
+ */
+/*ARGSUSED*/
+kstat_t *
+kstat_create(const char *module, int instance, const char *name,
+    const char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag)
+{
+       return (NULL);
+}
+
+/*ARGSUSED*/
+void
+kstat_install(kstat_t *ksp)
+{}
+
+/*ARGSUSED*/
+void
+kstat_delete(kstat_t *ksp)
+{}
+
+/*ARGSUSED*/
+void
+kstat_waitq_enter(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_waitq_exit(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_runq_enter(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_runq_exit(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_waitq_to_runq(kstat_io_t *kiop)
+{}
+
+/*ARGSUSED*/
+void
+kstat_runq_back_to_waitq(kstat_io_t *kiop)
+{}
+
+void
+kstat_set_raw_ops(kstat_t *ksp,
+    int (*headers)(char *buf, size_t size),
+    int (*data)(char *buf, size_t size, void *data),
+    void *(*addr)(kstat_t *ksp, loff_t index))
+{}
+
+/*
+ * =========================================================================
+ * mutexes
+ * =========================================================================
+ */
+
+void
+mutex_init(kmutex_t *mp, char *name, int type, void *cookie)
+{
+       ASSERT3S(type, ==, MUTEX_DEFAULT);
+       ASSERT3P(cookie, ==, NULL);
+       mp->m_owner = MTX_INIT;
+       mp->m_magic = MTX_MAGIC;
+       VERIFY3S(pthread_mutex_init(&mp->m_lock, NULL), ==, 0);
+}
+
+void
+mutex_destroy(kmutex_t *mp)
+{
+       ASSERT3U(mp->m_magic, ==, MTX_MAGIC);
+       ASSERT3P(mp->m_owner, ==, MTX_INIT);
+       ASSERT0(pthread_mutex_destroy(&(mp)->m_lock));
+       mp->m_owner = MTX_DEST;
+       mp->m_magic = 0;
+}
+
+void
+mutex_enter(kmutex_t *mp)
+{
+       ASSERT3U(mp->m_magic, ==, MTX_MAGIC);
+       ASSERT3P(mp->m_owner, !=, MTX_DEST);
+       ASSERT3P(mp->m_owner, !=, curthread);
+       VERIFY3S(pthread_mutex_lock(&mp->m_lock), ==, 0);
+       ASSERT3P(mp->m_owner, ==, MTX_INIT);
+       mp->m_owner = curthread;
+}
+
+int
+mutex_tryenter(kmutex_t *mp)
+{
+       int err;
+       ASSERT3U(mp->m_magic, ==, MTX_MAGIC);
+       ASSERT3P(mp->m_owner, !=, MTX_DEST);
+       if (0 == (err = pthread_mutex_trylock(&mp->m_lock))) {
+               ASSERT3P(mp->m_owner, ==, MTX_INIT);
+               mp->m_owner = curthread;
+               return (1);
+       } else {
+               VERIFY3S(err, ==, EBUSY);
+               return (0);
+       }
+}
+
+void
+mutex_exit(kmutex_t *mp)
+{
+       ASSERT3U(mp->m_magic, ==, MTX_MAGIC);
+       ASSERT3P(mutex_owner(mp), ==, curthread);
+       mp->m_owner = MTX_INIT;
+       VERIFY3S(pthread_mutex_unlock(&mp->m_lock), ==, 0);
+}
+
+void *
+mutex_owner(kmutex_t *mp)
+{
+       ASSERT3U(mp->m_magic, ==, MTX_MAGIC);
+       return (mp->m_owner);
+}
+
+int
+mutex_held(kmutex_t *mp)
+{
+       return (mp->m_owner == curthread);
+}
+
+/*
+ * =========================================================================
+ * rwlocks
+ * =========================================================================
+ */
+
+void
+rw_init(krwlock_t *rwlp, char *name, int type, void *arg)
+{
+       ASSERT3S(type, ==, RW_DEFAULT);
+       ASSERT3P(arg, ==, NULL);
+       VERIFY3S(pthread_rwlock_init(&rwlp->rw_lock, NULL), ==, 0);
+       rwlp->rw_owner = RW_INIT;
+       rwlp->rw_wr_owner = RW_INIT;
+       rwlp->rw_readers = 0;
+       rwlp->rw_magic = RW_MAGIC;
+}
+
+void
+rw_destroy(krwlock_t *rwlp)
+{
+       ASSERT3U(rwlp->rw_magic, ==, RW_MAGIC);
+       ASSERT(rwlp->rw_readers == 0 && rwlp->rw_wr_owner == RW_INIT);
+       VERIFY3S(pthread_rwlock_destroy(&rwlp->rw_lock), ==, 0);
+       rwlp->rw_magic = 0;
+}
+
+void
+rw_enter(krwlock_t *rwlp, krw_t rw)
+{
+       ASSERT3U(rwlp->rw_magic, ==, RW_MAGIC);
+       ASSERT3P(rwlp->rw_owner, !=, curthread);
+       ASSERT3P(rwlp->rw_wr_owner, !=, curthread);
+
+       if (rw == RW_READER) {
+               VERIFY3S(pthread_rwlock_rdlock(&rwlp->rw_lock), ==, 0);
+               ASSERT3P(rwlp->rw_wr_owner, ==, RW_INIT);
+
+               atomic_inc_uint(&rwlp->rw_readers);
+       } else {
+               VERIFY3S(pthread_rwlock_wrlock(&rwlp->rw_lock), ==, 0);
+               ASSERT3P(rwlp->rw_wr_owner, ==, RW_INIT);
+               ASSERT3U(rwlp->rw_readers, ==, 0);
+
+               rwlp->rw_wr_owner = curthread;
+       }
+
+       rwlp->rw_owner = curthread;
+}
+
+void
+rw_exit(krwlock_t *rwlp)
+{
+       ASSERT3U(rwlp->rw_magic, ==, RW_MAGIC);
+       ASSERT(RW_LOCK_HELD(rwlp));
+
+       if (RW_READ_HELD(rwlp))
+               atomic_dec_uint(&rwlp->rw_readers);
+       else
+               rwlp->rw_wr_owner = RW_INIT;
+
+       rwlp->rw_owner = RW_INIT;
+       VERIFY3S(pthread_rwlock_unlock(&rwlp->rw_lock), ==, 0);
+}
+
+int
+rw_tryenter(krwlock_t *rwlp, krw_t rw)
+{
+       int rv;
+
+       ASSERT3U(rwlp->rw_magic, ==, RW_MAGIC);
+
+       if (rw == RW_READER)
+               rv = pthread_rwlock_tryrdlock(&rwlp->rw_lock);
+       else
+               rv = pthread_rwlock_trywrlock(&rwlp->rw_lock);
+
+       if (rv == 0) {
+               ASSERT3P(rwlp->rw_wr_owner, ==, RW_INIT);
+
+               if (rw == RW_READER)
+                       atomic_inc_uint(&rwlp->rw_readers);
+               else {
+                       ASSERT3U(rwlp->rw_readers, ==, 0);
+                       rwlp->rw_wr_owner = curthread;
+               }
+
+               rwlp->rw_owner = curthread;
+               return (1);
+       }
+
+       VERIFY3S(rv, ==, EBUSY);
+
+       return (0);
+}
+
+int
+rw_tryupgrade(krwlock_t *rwlp)
+{
+       ASSERT3U(rwlp->rw_magic, ==, RW_MAGIC);
+
+       return (0);
+}
+
+/*
+ * =========================================================================
+ * condition variables
+ * =========================================================================
+ */
+
+void
+cv_init(kcondvar_t *cv, char *name, int type, void *arg)
+{
+       ASSERT3S(type, ==, CV_DEFAULT);
+       cv->cv_magic = CV_MAGIC;
+       VERIFY0(pthread_cond_init(&cv->cv, NULL));
+}
+
+void
+cv_destroy(kcondvar_t *cv)
+{
+       ASSERT3U(cv->cv_magic, ==, CV_MAGIC);
+       VERIFY0(pthread_cond_destroy(&cv->cv));
+       cv->cv_magic = 0;
+}
+
+void
+cv_wait(kcondvar_t *cv, kmutex_t *mp)
+{
+       ASSERT3U(cv->cv_magic, ==, CV_MAGIC);
+       ASSERT3P(mutex_owner(mp), ==, curthread);
+       mp->m_owner = MTX_INIT;
+       VERIFY0(pthread_cond_wait(&cv->cv, &mp->m_lock));
+       mp->m_owner = curthread;
+}
+
+clock_t
+cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime)
+{
+       int error;
+       struct timeval tv;
+       timestruc_t ts;
+       clock_t delta;
+
+       ASSERT3U(cv->cv_magic, ==, CV_MAGIC);
+
+       delta = abstime - ddi_get_lbolt();
+       if (delta <= 0)
+               return (-1);
+
+       VERIFY(gettimeofday(&tv, NULL) == 0);
+
+       ts.tv_sec = tv.tv_sec + delta / hz;
+       ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % hz) * (NANOSEC / hz);
+       if (ts.tv_nsec >= NANOSEC) {
+               ts.tv_sec++;
+               ts.tv_nsec -= NANOSEC;
+       }
+
+       ASSERT3P(mutex_owner(mp), ==, curthread);
+       mp->m_owner = MTX_INIT;
+       error = pthread_cond_timedwait(&cv->cv, &mp->m_lock, &ts);
+       mp->m_owner = curthread;
+
+       if (error == ETIMEDOUT)
+               return (-1);
+
+       VERIFY0(error);
+
+       return (1);
+}
+
+/*ARGSUSED*/
+clock_t
+cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res,
+    int flag)
+{
+       int error;
+       struct timeval tv;
+       timestruc_t ts;
+       hrtime_t delta;
+
+       ASSERT(flag == 0 || flag == CALLOUT_FLAG_ABSOLUTE);
+
+       delta = tim;
+       if (flag & CALLOUT_FLAG_ABSOLUTE)
+               delta -= gethrtime();
+
+       if (delta <= 0)
+               return (-1);
+
+       VERIFY(gettimeofday(&tv, NULL) == 0);
+
+       ts.tv_sec = tv.tv_sec + delta / NANOSEC;
+       ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % NANOSEC);
+       if (ts.tv_nsec >= NANOSEC) {
+               ts.tv_sec++;
+               ts.tv_nsec -= NANOSEC;
+       }
+
+       ASSERT(mutex_owner(mp) == curthread);
+       mp->m_owner = MTX_INIT;
+       error = pthread_cond_timedwait(&cv->cv, &mp->m_lock, &ts);
+       mp->m_owner = curthread;
+
+       if (error == ETIMEDOUT)
+               return (-1);
+
+       VERIFY0(error);
+
+       return (1);
+}
+
+void
+cv_signal(kcondvar_t *cv)
+{
+       ASSERT3U(cv->cv_magic, ==, CV_MAGIC);
+       VERIFY0(pthread_cond_signal(&cv->cv));
+}
+
+void
+cv_broadcast(kcondvar_t *cv)
+{
+       ASSERT3U(cv->cv_magic, ==, CV_MAGIC);
+       VERIFY0(pthread_cond_broadcast(&cv->cv));
+}
+
+/*
+ * =========================================================================
+ * vnode operations
+ * =========================================================================
+ */
+/*
+ * Note: for the xxxat() versions of these functions, we assume that the
+ * starting vp is always rootdir (which is true for spa_directory.c, the only
+ * ZFS consumer of these interfaces).  We assert this is true, and then emulate
+ * them by adding '/' in front of the path.
+ */
+
+/*ARGSUSED*/
+int
+vn_open(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2, int x3)
+{
+       int fd = -1;
+       int dump_fd = -1;
+       vnode_t *vp;
+       int old_umask = 0;
+       char *realpath;
+       struct stat64 st;
+       int err;
+
+       realpath = umem_alloc(MAXPATHLEN, UMEM_NOFAIL);
+
+       /*
+        * If we're accessing a real disk from userland, we need to use
+        * the character interface to avoid caching.  This is particularly
+        * important if we're trying to look at a real in-kernel storage
+        * pool from userland, e.g. via zdb, because otherwise we won't
+        * see the changes occurring under the segmap cache.
+        * On the other hand, the stupid character device returns zero
+        * for its size.  So -- gag -- we open the block device to get
+        * its size, and remember it for subsequent VOP_GETATTR().
+        */
+#if defined(__sun__) || defined(__sun)
+       if (strncmp(path, "/dev/", 5) == 0) {
+#else
+       if (0) {
+#endif
+               char *dsk;
+               fd = open64(path, O_RDONLY);
+               if (fd == -1) {
+                       err = errno;
+                       free(realpath);
+                       return (err);
+               }
+               if (fstat64(fd, &st) == -1) {
+                       err = errno;
+                       close(fd);
+                       free(realpath);
+                       return (err);
+               }
+               close(fd);
+               (void) sprintf(realpath, "%s", path);
+               dsk = strstr(path, "/dsk/");
+               if (dsk != NULL)
+                       (void) sprintf(realpath + (dsk - path) + 1, "r%s",
+                           dsk + 1);
+       } else {
+               (void) sprintf(realpath, "%s", path);
+               if (!(flags & FCREAT) && stat64(realpath, &st) == -1) {
+                       err = errno;
+                       free(realpath);
+                       return (err);
+               }
+       }
+
+       if (!(flags & FCREAT) && S_ISBLK(st.st_mode)) {
+#ifdef __linux__
+               flags |= O_DIRECT;
+#endif
+               /* We shouldn't be writing to block devices in userspace */
+               VERIFY(!(flags & FWRITE));
+       }
+
+       if (flags & FCREAT)
+               old_umask = umask(0);
+
+       /*
+        * The construct 'flags - FREAD' conveniently maps combinations of
+        * FREAD and FWRITE to the corresponding O_RDONLY, O_WRONLY, and O_RDWR.
+        */
+       fd = open64(realpath, flags - FREAD, mode);
+       if (fd == -1) {
+               err = errno;
+               free(realpath);
+               return (err);
+       }
+
+       if (flags & FCREAT)
+               (void) umask(old_umask);
+
+       if (vn_dumpdir != NULL) {
+               char *dumppath = umem_zalloc(MAXPATHLEN, UMEM_NOFAIL);
+               (void) snprintf(dumppath, MAXPATHLEN,
+                   "%s/%s", vn_dumpdir, basename(realpath));
+               dump_fd = open64(dumppath, O_CREAT | O_WRONLY, 0666);
+               umem_free(dumppath, MAXPATHLEN);
+               if (dump_fd == -1) {
+                       err = errno;
+                       free(realpath);
+                       close(fd);
+                       return (err);
+               }
+       } else {
+               dump_fd = -1;
+       }
+
+       free(realpath);
+
+       if (fstat64_blk(fd, &st) == -1) {
+               err = errno;
+               close(fd);
+               if (dump_fd != -1)
+                       close(dump_fd);
+               return (err);
+       }
+
+       (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+       *vpp = vp = umem_zalloc(sizeof (vnode_t), UMEM_NOFAIL);
+
+       vp->v_fd = fd;
+       vp->v_size = st.st_size;
+       vp->v_path = spa_strdup(path);
+       vp->v_dump_fd = dump_fd;
+
+       return (0);
+}
+
+/*ARGSUSED*/
+int
+vn_openat(char *path, int x1, int flags, int mode, vnode_t **vpp, int x2,
+    int x3, vnode_t *startvp, int fd)
+{
+       char *realpath = umem_alloc(strlen(path) + 2, UMEM_NOFAIL);
+       int ret;
+
+       ASSERT(startvp == rootdir);
+       (void) sprintf(realpath, "/%s", path);
+
+       /* fd ignored for now, need if want to simulate nbmand support */
+       ret = vn_open(realpath, x1, flags, mode, vpp, x2, x3);
+
+       umem_free(realpath, strlen(path) + 2);
+
+       return (ret);
+}
+
+/*ARGSUSED*/
+int
+vn_rdwr(int uio, vnode_t *vp, void *addr, ssize_t len, offset_t offset,
+       int x1, int x2, rlim64_t x3, void *x4, ssize_t *residp)
+{
+       ssize_t rc, done = 0, split;
+
+       if (uio == UIO_READ) {
+               rc = pread64(vp->v_fd, addr, len, offset);
+               if (vp->v_dump_fd != -1 && rc != -1) {
+                       int status;
+                       status = pwrite64(vp->v_dump_fd, addr, rc, offset);
+                       ASSERT(status != -1);
+               }
+       } else {
+               /*
+                * To simulate partial disk writes, we split writes into two
+                * system calls so that the process can be killed in between.
+                */
+               int sectors = len >> SPA_MINBLOCKSHIFT;
+               split = (sectors > 0 ? rand() % sectors : 0) <<
+                   SPA_MINBLOCKSHIFT;
+               rc = pwrite64(vp->v_fd, addr, split, offset);
+               if (rc != -1) {
+                       done = rc;
+                       rc = pwrite64(vp->v_fd, (char *)addr + split,
+                           len - split, offset + split);
+               }
+       }
+
+#ifdef __linux__
+       if (rc == -1 && errno == EINVAL) {
+               /*
+                * Under Linux, this most likely means an alignment issue
+                * (memory or disk) due to O_DIRECT, so we abort() in order to
+                * catch the offender.
+                */
+               abort();
+       }
+#endif
+       if (rc == -1)
+               return (errno);
+
+       done += rc;
+
+       if (residp)
+               *residp = len - done;
+       else if (done != len)
+               return (EIO);
+       return (0);
+}
+
+void
+vn_close(vnode_t *vp)
+{
+       close(vp->v_fd);
+       if (vp->v_dump_fd != -1)
+               close(vp->v_dump_fd);
+       spa_strfree(vp->v_path);
+       umem_free(vp, sizeof (vnode_t));
+}
+
+/*
+ * At a minimum we need to update the size since vdev_reopen()
+ * will no longer call vn_openat().
+ */
+int
+fop_getattr(vnode_t *vp, vattr_t *vap)
+{
+       struct stat64 st;
+       int err;
+
+       if (fstat64_blk(vp->v_fd, &st) == -1) {
+               err = errno;
+               close(vp->v_fd);
+               return (err);
+       }
+
+       vap->va_size = st.st_size;
+       return (0);
+}
+
+/*
+ * =========================================================================
+ * Figure out which debugging statements to print
+ * =========================================================================
+ */
+
+static char *dprintf_string;
+static int dprintf_print_all;
+
+int
+dprintf_find_string(const char *string)
+{
+       char *tmp_str = dprintf_string;
+       int len = strlen(string);
+
+       /*
+        * Find out if this is a string we want to print.
+        * String format: file1.c,function_name1,file2.c,file3.c
+        */
+
+       while (tmp_str != NULL) {
+               if (strncmp(tmp_str, string, len) == 0 &&
+                   (tmp_str[len] == ',' || tmp_str[len] == '\0'))
+                       return (1);
+               tmp_str = strchr(tmp_str, ',');
+               if (tmp_str != NULL)
+                       tmp_str++; /* Get rid of , */
+       }
+       return (0);
+}
+
+void
+dprintf_setup(int *argc, char **argv)
+{
+       int i, j;
+
+       /*
+        * Debugging can be specified two ways: by setting the
+        * environment variable ZFS_DEBUG, or by including a
+        * "debug=..."  argument on the command line.  The command
+        * line setting overrides the environment variable.
+        */
+
+       for (i = 1; i < *argc; i++) {
+               int len = strlen("debug=");
+               /* First look for a command line argument */
+               if (strncmp("debug=", argv[i], len) == 0) {
+                       dprintf_string = argv[i] + len;
+                       /* Remove from args */
+                       for (j = i; j < *argc; j++)
+                               argv[j] = argv[j+1];
+                       argv[j] = NULL;
+                       (*argc)--;
+               }
+       }
+
+       if (dprintf_string == NULL) {
+               /* Look for ZFS_DEBUG environment variable */
+               dprintf_string = getenv("ZFS_DEBUG");
+       }
+
+       /*
+        * Are we just turning on all debugging?
+        */
+       if (dprintf_find_string("on"))
+               dprintf_print_all = 1;
+
+       if (dprintf_string != NULL)
+               zfs_flags |= ZFS_DEBUG_DPRINTF;
+}
+
+/*
+ * =========================================================================
+ * debug printfs
+ * =========================================================================
+ */
+void
+__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
+{
+       const char *newfile;
+       va_list adx;
+
+       /*
+        * Get rid of annoying "../common/" prefix to filename.
+        */
+       newfile = strrchr(file, '/');
+       if (newfile != NULL) {
+               newfile = newfile + 1; /* Get rid of leading / */
+       } else {
+               newfile = file;
+       }
+
+       if (dprintf_print_all ||
+           dprintf_find_string(newfile) ||
+           dprintf_find_string(func)) {
+               /* Print out just the function name if requested */
+               flockfile(stdout);
+               if (dprintf_find_string("pid"))
+                       (void) printf("%d ", getpid());
+               if (dprintf_find_string("tid"))
+                       (void) printf("%u ", (uint_t) pthread_self());
+               if (dprintf_find_string("cpu"))
+                       (void) printf("%u ", getcpuid());
+               if (dprintf_find_string("time"))
+                       (void) printf("%llu ", gethrtime());
+               if (dprintf_find_string("long"))
+                       (void) printf("%s, line %d: ", newfile, line);
+               (void) printf("%s: ", func);
+               va_start(adx, fmt);
+               (void) vprintf(fmt, adx);
+               va_end(adx);
+               funlockfile(stdout);
+       }
+}
+
+/*
+ * =========================================================================
+ * cmn_err() and panic()
+ * =========================================================================
+ */
+static char ce_prefix[CE_IGNORE][10] = { "", "NOTICE: ", "WARNING: ", "" };
+static char ce_suffix[CE_IGNORE][2] = { "", "\n", "\n", "" };
+
+void
+vpanic(const char *fmt, va_list adx)
+{
+       (void) fprintf(stderr, "error: ");
+       (void) vfprintf(stderr, fmt, adx);
+       (void) fprintf(stderr, "\n");
+
+       abort();        /* think of it as a "user-level crash dump" */
+}
+
+void
+panic(const char *fmt, ...)
+{
+       va_list adx;
+
+       va_start(adx, fmt);
+       vpanic(fmt, adx);
+       va_end(adx);
+}
+
+void
+vcmn_err(int ce, const char *fmt, va_list adx)
+{
+       if (ce == CE_PANIC)
+               vpanic(fmt, adx);
+       if (ce != CE_NOTE) {    /* suppress noise in userland stress testing */
+               (void) fprintf(stderr, "%s", ce_prefix[ce]);
+               (void) vfprintf(stderr, fmt, adx);
+               (void) fprintf(stderr, "%s", ce_suffix[ce]);
+       }
+}
+
+/*PRINTFLIKE2*/
+void
+cmn_err(int ce, const char *fmt, ...)
+{
+       va_list adx;
+
+       va_start(adx, fmt);
+       vcmn_err(ce, fmt, adx);
+       va_end(adx);
+}
+
+/*
+ * =========================================================================
+ * kobj interfaces
+ * =========================================================================
+ */
+struct _buf *
+kobj_open_file(char *name)
+{
+       struct _buf *file;
+       vnode_t *vp;
+
+       /* set vp as the _fd field of the file */
+       if (vn_openat(name, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0, rootdir,
+           -1) != 0)
+               return ((void *)-1UL);
+
+       file = umem_zalloc(sizeof (struct _buf), UMEM_NOFAIL);
+       file->_fd = (intptr_t)vp;
+       return (file);
+}
+
+int
+kobj_read_file(struct _buf *file, char *buf, unsigned size, unsigned off)
+{
+       ssize_t resid = 0;
+
+       if (vn_rdwr(UIO_READ, (vnode_t *)file->_fd, buf, size, (offset_t)off,
+           UIO_SYSSPACE, 0, 0, 0, &resid) != 0)
+               return (-1);
+
+       return (size - resid);
+}
+
+void
+kobj_close_file(struct _buf *file)
+{
+       vn_close((vnode_t *)file->_fd);
+       umem_free(file, sizeof (struct _buf));
+}
+
+int
+kobj_get_filesize(struct _buf *file, uint64_t *size)
+{
+       struct stat64 st;
+       vnode_t *vp = (vnode_t *)file->_fd;
+
+       if (fstat64(vp->v_fd, &st) == -1) {
+               vn_close(vp);
+               return (errno);
+       }
+       *size = st.st_size;
+       return (0);
+}
+
+/*
+ * =========================================================================
+ * misc routines
+ * =========================================================================
+ */
+
+void
+delay(clock_t ticks)
+{
+       (void) poll(0, 0, ticks * (1000 / hz));
+}
+
+/*
+ * Find highest one bit set.
+ *     Returns bit number + 1 of highest bit that is set, otherwise returns 0.
+ * High order bit is 31 (or 63 in _LP64 kernel).
+ */
+int
+highbit64(uint64_t i)
+{
+       register int h = 1;
+
+       if (i == 0)
+               return (0);
+       if (i & 0xffffffff00000000ULL) {
+               h += 32; i >>= 32;
+       }
+       if (i & 0xffff0000) {
+               h += 16; i >>= 16;
+       }
+       if (i & 0xff00) {
+               h += 8; i >>= 8;
+       }
+       if (i & 0xf0) {
+               h += 4; i >>= 4;
+       }
+       if (i & 0xc) {
+               h += 2; i >>= 2;
+       }
+       if (i & 0x2) {
+               h += 1;
+       }
+       return (h);
+}
+
+/*
+ * Find lowest one bit set.
+ * Returns bit number + 1 of lowest bit that is set, otherwise returns 0.
+ * This is basically a reimplementation of ffsll(), which is GNU specific.
+ */
+int
+lowbit64(uint64_t i)
+{
+       register int h = 64;
+       if (i == 0)
+               return (0);
+
+       if (i & 0x00000000ffffffffULL)
+               h -= 32;
+       else
+               i >>= 32;
+
+       if (i & 0x0000ffff)
+               h -= 16;
+       else
+               i >>= 16;
+
+       if (i & 0x00ff)
+               h -= 8;
+       else
+               i >>= 8;
+
+       if (i & 0x0f)
+               h -= 4;
+       else
+               i >>= 4;
+
+       if (i & 0x3)
+               h -= 2;
+       else
+               i >>= 2;
+
+       if (i & 0x1)
+               h -= 1;
+
+       return (h);
+}
+
+/*
+ * Find highest one bit set.
+ * Returns bit number + 1 of highest bit that is set, otherwise returns 0.
+ * High order bit is 31 (or 63 in _LP64 kernel).
+ */
+int
+highbit(ulong_t i)
+{
+register int h = 1;
+
+       if (i == 0)
+               return (0);
+#ifdef _LP64
+       if (i & 0xffffffff00000000ul) {
+               h += 32; i >>= 32;
+       }
+#endif
+       if (i & 0xffff0000) {
+               h += 16; i >>= 16;
+       }
+       if (i & 0xff00) {
+               h += 8; i >>= 8;
+       }
+       if (i & 0xf0) {
+               h += 4; i >>= 4;
+       }
+       if (i & 0xc) {
+               h += 2; i >>= 2;
+       }
+       if (i & 0x2) {
+               h += 1;
+       }
+       return (h);
+}
+
+/*
+ * Find lowest one bit set.
+ *     Returns bit number + 1 of lowest bit that is set, otherwise returns 0.
+ * Low order bit is 0.
+ */
+int
+lowbit(ulong_t i)
+{
+       register int h = 1;
+
+       if (i == 0)
+               return (0);
+
+#ifdef _LP64
+       if (!(i & 0xffffffff)) {
+               h += 32; i >>= 32;
+       }
+#endif
+       if (!(i & 0xffff)) {
+               h += 16; i >>= 16;
+       }
+       if (!(i & 0xff)) {
+               h += 8; i >>= 8;
+       }
+       if (!(i & 0xf)) {
+               h += 4; i >>= 4;
+       }
+       if (!(i & 0x3)) {
+               h += 2; i >>= 2;
+       }
+       if (!(i & 0x1)) {
+               h += 1;
+       }
+       return (h);
+}
+
+static int random_fd = -1, urandom_fd = -1;
+
+void
+random_init(void)
+{
+       VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1);
+       VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1);
+}
+
+void
+random_fini(void)
+{
+       close(random_fd);
+       close(urandom_fd);
+
+       random_fd = -1;
+       urandom_fd = -1;
+}
+
+static int
+random_get_bytes_common(uint8_t *ptr, size_t len, int fd)
+{
+       size_t resid = len;
+       ssize_t bytes;
+
+       ASSERT(fd != -1);
+
+       while (resid != 0) {
+               bytes = read(fd, ptr, resid);
+               ASSERT3S(bytes, >=, 0);
+               ptr += bytes;
+               resid -= bytes;
+       }
+
+       return (0);
+}
+
+int
+random_get_bytes(uint8_t *ptr, size_t len)
+{
+       return (random_get_bytes_common(ptr, len, random_fd));
+}
+
+int
+random_get_pseudo_bytes(uint8_t *ptr, size_t len)
+{
+       return (random_get_bytes_common(ptr, len, urandom_fd));
+}
+
+int
+ddi_strtoul(const char *hw_serial, char **nptr, int base, unsigned long *result)
+{
+       char *end;
+
+       *result = strtoul(hw_serial, &end, base);
+       if (*result == 0)
+               return (errno);
+       return (0);
+}
+
+int
+ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result)
+{
+       char *end;
+
+       *result = strtoull(str, &end, base);
+       if (*result == 0)
+               return (errno);
+       return (0);
+}
+
+utsname_t *
+utsname(void)
+{
+       return (&hw_utsname);
+}
+
+/*
+ * =========================================================================
+ * kernel emulation setup & teardown
+ * =========================================================================
+ */
+static int
+umem_out_of_memory(void)
+{
+       char errmsg[] = "out of memory -- generating core dump\n";
+
+       (void) fprintf(stderr, "%s", errmsg);
+       abort();
+       return (0);
+}
+
+static unsigned long
+get_spl_hostid(void)
+{
+       FILE *f;
+       unsigned long hostid;
+
+       f = fopen("/sys/module/spl/parameters/spl_hostid", "r");
+       if (!f)
+               return (0);
+       if (fscanf(f, "%lu", &hostid) != 1)
+               hostid = 0;
+       fclose(f);
+       return (hostid & 0xffffffff);
+}
+
+unsigned long
+get_system_hostid(void)
+{
+       unsigned long system_hostid = get_spl_hostid();
+       if (system_hostid == 0)
+               system_hostid = gethostid() & 0xffffffff;
+       return (system_hostid);
+}
+
+void
+kernel_init(int mode)
+{
+       extern uint_t rrw_tsd_key;
+
+       umem_nofail_callback(umem_out_of_memory);
+
+       physmem = sysconf(_SC_PHYS_PAGES);
+
+       dprintf("physmem = %llu pages (%.2f GB)\n", physmem,
+           (double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30));
+
+       (void) snprintf(hw_serial, sizeof (hw_serial), "%ld",
+           (mode & FWRITE) ? get_system_hostid() : 0);
+
+       random_init();
+
+       VERIFY0(uname(&hw_utsname));
+
+       thread_init();
+       system_taskq_init();
+       icp_init();
+
+       spa_init(mode);
+
+       fletcher_4_init();
+
+       tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
+}
+
+void
+kernel_fini(void)
+{
+       fletcher_4_fini();
+       spa_fini();
+
+       icp_fini();
+       system_taskq_fini();
+       thread_fini();
+
+       random_fini();
+}
+
+uid_t
+crgetuid(cred_t *cr)
+{
+       return (0);
+}
+
+uid_t
+crgetruid(cred_t *cr)
+{
+       return (0);
+}
+
+gid_t
+crgetgid(cred_t *cr)
+{
+       return (0);
+}
+
+int
+crgetngroups(cred_t *cr)
+{
+       return (0);
+}
+
+gid_t *
+crgetgroups(cred_t *cr)
+{
+       return (NULL);
+}
+
+int
+zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
+{
+       return (0);
+}
+
+int
+zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
+{
+       return (0);
+}
+
+int
+zfs_secpolicy_destroy_perms(const char *name, cred_t *cr)
+{
+       return (0);
+}
+
+int
+secpolicy_zfs(const cred_t *cr)
+{
+       return (0);
+}
+
+ksiddomain_t *
+ksid_lookupdomain(const char *dom)
+{
+       ksiddomain_t *kd;
+
+       kd = umem_zalloc(sizeof (ksiddomain_t), UMEM_NOFAIL);
+       kd->kd_name = spa_strdup(dom);
+       return (kd);
+}
+
+void
+ksiddomain_rele(ksiddomain_t *ksid)
+{
+       spa_strfree(ksid->kd_name);
+       umem_free(ksid, sizeof (ksiddomain_t));
+}
+
+char *
+kmem_vasprintf(const char *fmt, va_list adx)
+{
+       char *buf = NULL;
+       va_list adx_copy;
+
+       va_copy(adx_copy, adx);
+       VERIFY(vasprintf(&buf, fmt, adx_copy) != -1);
+       va_end(adx_copy);
+
+       return (buf);
+}
+
+char *
+kmem_asprintf(const char *fmt, ...)
+{
+       char *buf = NULL;
+       va_list adx;
+
+       va_start(adx, fmt);
+       VERIFY(vasprintf(&buf, fmt, adx) != -1);
+       va_end(adx);
+
+       return (buf);
+}
+
+/* ARGSUSED */
+int
+zfs_onexit_fd_hold(int fd, minor_t *minorp)
+{
+       *minorp = 0;
+       return (0);
+}
+
+/* ARGSUSED */
+void
+zfs_onexit_fd_rele(int fd)
+{
+}
+
+/* ARGSUSED */
+int
+zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data,
+    uint64_t *action_handle)
+{
+       return (0);
+}
+
+/* ARGSUSED */
+int
+zfs_onexit_del_cb(minor_t minor, uint64_t action_handle, boolean_t fire)
+{
+       return (0);
+}
+
+/* ARGSUSED */
+int
+zfs_onexit_cb_data(minor_t minor, uint64_t action_handle, void **data)
+{
+       return (0);
+}
+
+fstrans_cookie_t
+spl_fstrans_mark(void)
+{
+       return ((fstrans_cookie_t) 0);
+}
+
+void
+spl_fstrans_unmark(fstrans_cookie_t cookie)
+{
+}
+
+int
+spl_fstrans_check(void)
+{
+       return (0);
+}
+
+void *zvol_tag = "zvol_tag";
+
+void
+zvol_create_minors(spa_t *spa, const char *name, boolean_t async)
+{
+}
+
+void
+zvol_remove_minor(spa_t *spa, const char *name, boolean_t async)
+{
+}
+
+void
+zvol_remove_minors(spa_t *spa, const char *name, boolean_t async)
+{
+}
+
+void
+zvol_rename_minors(spa_t *spa, const char *oldname, const char *newname,
+    boolean_t async)
+{
+}
diff --git a/zfs/lib/libzpool/taskq.c b/zfs/lib/libzpool/taskq.c
new file mode 100644 (file)
index 0000000..c1f87e1
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+
+int taskq_now;
+taskq_t *system_taskq;
+
+#define        TASKQ_ACTIVE    0x00010000
+
+static taskq_ent_t *
+task_alloc(taskq_t *tq, int tqflags)
+{
+       taskq_ent_t *t;
+       int rv;
+
+again: if ((t = tq->tq_freelist) != NULL && tq->tq_nalloc >= tq->tq_minalloc) {
+               ASSERT(!(t->tqent_flags & TQENT_FLAG_PREALLOC));
+               tq->tq_freelist = t->tqent_next;
+       } else {
+               if (tq->tq_nalloc >= tq->tq_maxalloc) {
+                       if (!(tqflags & KM_SLEEP))
+                               return (NULL);
+
+                       /*
+                        * We don't want to exceed tq_maxalloc, but we can't
+                        * wait for other tasks to complete (and thus free up
+                        * task structures) without risking deadlock with
+                        * the caller.  So, we just delay for one second
+                        * to throttle the allocation rate. If we have tasks
+                        * complete before one second timeout expires then
+                        * taskq_ent_free will signal us and we will
+                        * immediately retry the allocation.
+                        */
+                       tq->tq_maxalloc_wait++;
+                       rv = cv_timedwait(&tq->tq_maxalloc_cv,
+                           &tq->tq_lock, ddi_get_lbolt() + hz);
+                       tq->tq_maxalloc_wait--;
+                       if (rv > 0)
+                               goto again;             /* signaled */
+               }
+               mutex_exit(&tq->tq_lock);
+
+               t = kmem_alloc(sizeof (taskq_ent_t), tqflags);
+
+               mutex_enter(&tq->tq_lock);
+               if (t != NULL) {
+                       /* Make sure we start without any flags */
+                       t->tqent_flags = 0;
+                       tq->tq_nalloc++;
+               }
+       }
+       return (t);
+}
+
+static void
+task_free(taskq_t *tq, taskq_ent_t *t)
+{
+       if (tq->tq_nalloc <= tq->tq_minalloc) {
+               t->tqent_next = tq->tq_freelist;
+               tq->tq_freelist = t;
+       } else {
+               tq->tq_nalloc--;
+               mutex_exit(&tq->tq_lock);
+               kmem_free(t, sizeof (taskq_ent_t));
+               mutex_enter(&tq->tq_lock);
+       }
+
+       if (tq->tq_maxalloc_wait)
+               cv_signal(&tq->tq_maxalloc_cv);
+}
+
+taskqid_t
+taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags)
+{
+       taskq_ent_t *t;
+
+       if (taskq_now) {
+               func(arg);
+               return (1);
+       }
+
+       mutex_enter(&tq->tq_lock);
+       ASSERT(tq->tq_flags & TASKQ_ACTIVE);
+       if ((t = task_alloc(tq, tqflags)) == NULL) {
+               mutex_exit(&tq->tq_lock);
+               return (0);
+       }
+       if (tqflags & TQ_FRONT) {
+               t->tqent_next = tq->tq_task.tqent_next;
+               t->tqent_prev = &tq->tq_task;
+       } else {
+               t->tqent_next = &tq->tq_task;
+               t->tqent_prev = tq->tq_task.tqent_prev;
+       }
+       t->tqent_next->tqent_prev = t;
+       t->tqent_prev->tqent_next = t;
+       t->tqent_func = func;
+       t->tqent_arg = arg;
+       t->tqent_flags = 0;
+       cv_signal(&tq->tq_dispatch_cv);
+       mutex_exit(&tq->tq_lock);
+       return (1);
+}
+
+taskqid_t
+taskq_dispatch_delay(taskq_t *tq,  task_func_t func, void *arg, uint_t tqflags,
+    clock_t expire_time)
+{
+       return (0);
+}
+
+int
+taskq_empty_ent(taskq_ent_t *t)
+{
+       return (t->tqent_next == NULL);
+}
+
+void
+taskq_init_ent(taskq_ent_t *t)
+{
+       t->tqent_next = NULL;
+       t->tqent_prev = NULL;
+       t->tqent_func = NULL;
+       t->tqent_arg = NULL;
+       t->tqent_flags = 0;
+}
+
+void
+taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags,
+    taskq_ent_t *t)
+{
+       ASSERT(func != NULL);
+
+       /*
+        * Mark it as a prealloc'd task.  This is important
+        * to ensure that we don't free it later.
+        */
+       t->tqent_flags |= TQENT_FLAG_PREALLOC;
+       /*
+        * Enqueue the task to the underlying queue.
+        */
+       mutex_enter(&tq->tq_lock);
+
+       if (flags & TQ_FRONT) {
+               t->tqent_next = tq->tq_task.tqent_next;
+               t->tqent_prev = &tq->tq_task;
+       } else {
+               t->tqent_next = &tq->tq_task;
+               t->tqent_prev = tq->tq_task.tqent_prev;
+       }
+       t->tqent_next->tqent_prev = t;
+       t->tqent_prev->tqent_next = t;
+       t->tqent_func = func;
+       t->tqent_arg = arg;
+       cv_signal(&tq->tq_dispatch_cv);
+       mutex_exit(&tq->tq_lock);
+}
+
+void
+taskq_wait(taskq_t *tq)
+{
+       mutex_enter(&tq->tq_lock);
+       while (tq->tq_task.tqent_next != &tq->tq_task || tq->tq_active != 0)
+               cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
+       mutex_exit(&tq->tq_lock);
+}
+
+void
+taskq_wait_id(taskq_t *tq, taskqid_t id)
+{
+       taskq_wait(tq);
+}
+
+void
+taskq_wait_outstanding(taskq_t *tq, taskqid_t id)
+{
+       taskq_wait(tq);
+}
+
+static void
+taskq_thread(void *arg)
+{
+       taskq_t *tq = arg;
+       taskq_ent_t *t;
+       boolean_t prealloc;
+
+       mutex_enter(&tq->tq_lock);
+       while (tq->tq_flags & TASKQ_ACTIVE) {
+               if ((t = tq->tq_task.tqent_next) == &tq->tq_task) {
+                       if (--tq->tq_active == 0)
+                               cv_broadcast(&tq->tq_wait_cv);
+                       cv_wait(&tq->tq_dispatch_cv, &tq->tq_lock);
+                       tq->tq_active++;
+                       continue;
+               }
+               t->tqent_prev->tqent_next = t->tqent_next;
+               t->tqent_next->tqent_prev = t->tqent_prev;
+               t->tqent_next = NULL;
+               t->tqent_prev = NULL;
+               prealloc = t->tqent_flags & TQENT_FLAG_PREALLOC;
+               mutex_exit(&tq->tq_lock);
+
+               rw_enter(&tq->tq_threadlock, RW_READER);
+               t->tqent_func(t->tqent_arg);
+               rw_exit(&tq->tq_threadlock);
+
+               mutex_enter(&tq->tq_lock);
+               if (!prealloc)
+                       task_free(tq, t);
+       }
+       tq->tq_nthreads--;
+       cv_broadcast(&tq->tq_wait_cv);
+       mutex_exit(&tq->tq_lock);
+       thread_exit();
+}
+
+/*ARGSUSED*/
+taskq_t *
+taskq_create(const char *name, int nthreads, pri_t pri,
+       int minalloc, int maxalloc, uint_t flags)
+{
+       taskq_t *tq = kmem_zalloc(sizeof (taskq_t), KM_SLEEP);
+       int t;
+
+       if (flags & TASKQ_THREADS_CPU_PCT) {
+               int pct;
+               ASSERT3S(nthreads, >=, 0);
+               ASSERT3S(nthreads, <=, 100);
+               pct = MIN(nthreads, 100);
+               pct = MAX(pct, 0);
+
+               nthreads = (sysconf(_SC_NPROCESSORS_ONLN) * pct) / 100;
+               nthreads = MAX(nthreads, 1);    /* need at least 1 thread */
+       } else {
+               ASSERT3S(nthreads, >=, 1);
+       }
+
+       rw_init(&tq->tq_threadlock, NULL, RW_DEFAULT, NULL);
+       mutex_init(&tq->tq_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&tq->tq_dispatch_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&tq->tq_wait_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&tq->tq_maxalloc_cv, NULL, CV_DEFAULT, NULL);
+       (void) strncpy(tq->tq_name, name, TASKQ_NAMELEN);
+       tq->tq_flags = flags | TASKQ_ACTIVE;
+       tq->tq_active = nthreads;
+       tq->tq_nthreads = nthreads;
+       tq->tq_minalloc = minalloc;
+       tq->tq_maxalloc = maxalloc;
+       tq->tq_task.tqent_next = &tq->tq_task;
+       tq->tq_task.tqent_prev = &tq->tq_task;
+       tq->tq_threadlist = kmem_alloc(nthreads * sizeof (kthread_t *),
+           KM_SLEEP);
+
+       if (flags & TASKQ_PREPOPULATE) {
+               mutex_enter(&tq->tq_lock);
+               while (minalloc-- > 0)
+                       task_free(tq, task_alloc(tq, KM_SLEEP));
+               mutex_exit(&tq->tq_lock);
+       }
+
+       for (t = 0; t < nthreads; t++)
+               VERIFY((tq->tq_threadlist[t] = thread_create(NULL, 0,
+                   taskq_thread, tq, 0, &p0, TS_RUN, pri)) != NULL);
+
+       return (tq);
+}
+
+void
+taskq_destroy(taskq_t *tq)
+{
+       int nthreads = tq->tq_nthreads;
+
+       taskq_wait(tq);
+
+       mutex_enter(&tq->tq_lock);
+
+       tq->tq_flags &= ~TASKQ_ACTIVE;
+       cv_broadcast(&tq->tq_dispatch_cv);
+
+       while (tq->tq_nthreads != 0)
+               cv_wait(&tq->tq_wait_cv, &tq->tq_lock);
+
+       tq->tq_minalloc = 0;
+       while (tq->tq_nalloc != 0) {
+               ASSERT(tq->tq_freelist != NULL);
+               task_free(tq, task_alloc(tq, KM_SLEEP));
+       }
+
+       mutex_exit(&tq->tq_lock);
+
+       kmem_free(tq->tq_threadlist, nthreads * sizeof (kthread_t *));
+
+       rw_destroy(&tq->tq_threadlock);
+       mutex_destroy(&tq->tq_lock);
+       cv_destroy(&tq->tq_dispatch_cv);
+       cv_destroy(&tq->tq_wait_cv);
+       cv_destroy(&tq->tq_maxalloc_cv);
+
+       kmem_free(tq, sizeof (taskq_t));
+}
+
+int
+taskq_member(taskq_t *tq, kthread_t *t)
+{
+       int i;
+
+       if (taskq_now)
+               return (1);
+
+       for (i = 0; i < tq->tq_nthreads; i++)
+               if (tq->tq_threadlist[i] == t)
+                       return (1);
+
+       return (0);
+}
+
+int
+taskq_cancel_id(taskq_t *tq, taskqid_t id)
+{
+       return (ENOENT);
+}
+
+void
+system_taskq_init(void)
+{
+       system_taskq = taskq_create("system_taskq", 64, maxclsyspri, 4, 512,
+           TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
+}
+
+void
+system_taskq_fini(void)
+{
+       taskq_destroy(system_taskq);
+       system_taskq = NULL; /* defensive */
+}
diff --git a/zfs/lib/libzpool/util.c b/zfs/lib/libzpool/util.c
new file mode 100644 (file)
index 0000000..bc3bcbe
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <assert.h>
+#include <sys/zfs_context.h>
+#include <sys/avl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/spa.h>
+#include <sys/fs/zfs.h>
+#include <sys/refcount.h>
+
+/*
+ * Routines needed by more than one client of libzpool.
+ */
+
+void
+nicenum(uint64_t num, char *buf)
+{
+       uint64_t n = num;
+       int index = 0;
+       char u;
+
+       while (n >= 1024) {
+               n = (n + (1024 / 2)) / 1024; /* Round up or down */
+               index++;
+       }
+
+       u = " KMGTPE"[index];
+
+       if (index == 0) {
+               (void) sprintf(buf, "%llu", (u_longlong_t)n);
+       } else if (n < 10 && (num & (num - 1)) != 0) {
+               (void) sprintf(buf, "%.2f%c",
+                   (double)num / (1ULL << 10 * index), u);
+       } else if (n < 100 && (num & (num - 1)) != 0) {
+               (void) sprintf(buf, "%.1f%c",
+                   (double)num / (1ULL << 10 * index), u);
+       } else {
+               (void) sprintf(buf, "%llu%c", (u_longlong_t)n, u);
+       }
+}
+
+static void
+show_vdev_stats(const char *desc, const char *ctype, nvlist_t *nv, int indent)
+{
+       vdev_stat_t *vs;
+       vdev_stat_t *v0 = { 0 };
+       uint64_t sec;
+       uint64_t is_log = 0;
+       nvlist_t **child;
+       uint_t c, children;
+       char used[6], avail[6];
+       char rops[6], wops[6], rbytes[6], wbytes[6], rerr[6], werr[6], cerr[6];
+       char *prefix = "";
+
+       v0 = umem_zalloc(sizeof (*v0), UMEM_NOFAIL);
+
+       if (indent == 0 && desc != NULL) {
+               (void) printf("                           "
+                   " capacity   operations   bandwidth  ---- errors ----\n");
+               (void) printf("description                "
+                   "used avail  read write  read write  read write cksum\n");
+       }
+
+       if (desc != NULL) {
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &is_log);
+
+               if (is_log)
+                       prefix = "log ";
+
+               if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+                   (uint64_t **)&vs, &c) != 0)
+                       vs = v0;
+
+               sec = MAX(1, vs->vs_timestamp / NANOSEC);
+
+               nicenum(vs->vs_alloc, used);
+               nicenum(vs->vs_space - vs->vs_alloc, avail);
+               nicenum(vs->vs_ops[ZIO_TYPE_READ] / sec, rops);
+               nicenum(vs->vs_ops[ZIO_TYPE_WRITE] / sec, wops);
+               nicenum(vs->vs_bytes[ZIO_TYPE_READ] / sec, rbytes);
+               nicenum(vs->vs_bytes[ZIO_TYPE_WRITE] / sec, wbytes);
+               nicenum(vs->vs_read_errors, rerr);
+               nicenum(vs->vs_write_errors, werr);
+               nicenum(vs->vs_checksum_errors, cerr);
+
+               (void) printf("%*s%s%*s%*s%*s %5s %5s %5s %5s %5s %5s %5s\n",
+                   indent, "",
+                   prefix,
+                   (int)(indent+strlen(prefix)-25-(vs->vs_space ? 0 : 12)),
+                   desc,
+                   vs->vs_space ? 6 : 0, vs->vs_space ? used : "",
+                   vs->vs_space ? 6 : 0, vs->vs_space ? avail : "",
+                   rops, wops, rbytes, wbytes, rerr, werr, cerr);
+       }
+       free(v0);
+
+       if (nvlist_lookup_nvlist_array(nv, ctype, &child, &children) != 0)
+               return;
+
+       for (c = 0; c < children; c++) {
+               nvlist_t *cnv = child[c];
+               char *cname = NULL, *tname;
+               uint64_t np;
+               int len;
+               if (nvlist_lookup_string(cnv, ZPOOL_CONFIG_PATH, &cname) &&
+                   nvlist_lookup_string(cnv, ZPOOL_CONFIG_TYPE, &cname))
+                       cname = "<unknown>";
+               len = strlen(cname) + 2;
+               tname = umem_zalloc(len, UMEM_NOFAIL);
+               (void) strlcpy(tname, cname, len);
+               if (nvlist_lookup_uint64(cnv, ZPOOL_CONFIG_NPARITY, &np) == 0)
+                       tname[strlen(tname)] = '0' + np;
+               show_vdev_stats(tname, ctype, cnv, indent + 2);
+               free(tname);
+       }
+}
+
+void
+show_pool_stats(spa_t *spa)
+{
+       nvlist_t *config, *nvroot;
+       char *name;
+
+       VERIFY(spa_get_stats(spa_name(spa), &config, NULL, 0) == 0);
+
+       VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
+           &nvroot) == 0);
+       VERIFY(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
+           &name) == 0);
+
+       show_vdev_stats(name, ZPOOL_CONFIG_CHILDREN, nvroot, 0);
+       show_vdev_stats(NULL, ZPOOL_CONFIG_L2CACHE, nvroot, 0);
+       show_vdev_stats(NULL, ZPOOL_CONFIG_SPARES, nvroot, 0);
+
+       nvlist_free(config);
+}
diff --git a/zfs/man/Makefile.am b/zfs/man/Makefile.am
new file mode 100644 (file)
index 0000000..841cb9c
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = man1 man5 man8
diff --git a/zfs/man/Makefile.in b/zfs/man/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/man/man1/Makefile.am b/zfs/man/man1/Makefile.am
new file mode 100644 (file)
index 0000000..5f18d1e
--- /dev/null
@@ -0,0 +1,5 @@
+dist_man_MANS = zhack.1 zpios.1 ztest.1 raidz_test.1
+EXTRA_DIST = cstyle.1
+
+install-data-local:
+       $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man1"
diff --git a/zfs/man/man1/Makefile.in b/zfs/man/man1/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/man/man1/cstyle.1 b/zfs/man/man1/cstyle.1
new file mode 100644 (file)
index 0000000..f2b637d
--- /dev/null
@@ -0,0 +1,167 @@
+.\" Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+.\" Use is subject to license terms.
+.\"
+.\" 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
+.\"
+.TH cstyle 1 "28 March 2005"
+.SH NAME
+.I cstyle
+\- check for some common stylistic errors in C source files
+.SH SYNOPSIS
+\fBcstyle [-chpvCP] [-o constructs] [file...]\fP
+.LP
+.SH DESCRIPTION
+.IX "OS-Net build tools" "cstyle" "" "\fBcstyle\fP"
+.LP
+.I cstyle
+inspects C source files (*.c and *.h) for common sylistic errors.  It
+attempts to check for the cstyle documented in
+\fIhttp://www.cis.upenn.edu/~lee/06cse480/data/cstyle.ms.pdf\fP.
+Note that there is much in that document that
+.I cannot
+be checked for; just because your code is \fBcstyle(1)\fP clean does not
+mean that you've followed Sun's C style.  \fICaveat emptor\fP.
+.LP
+.SH OPTIONS
+.LP
+The following options are supported:
+.TP 4
+.B \-c
+Check continuation line indentation inside of functions.  Sun's C style
+states that all statements must be indented to an appropriate tab stop,
+and any continuation lines after them must be indented \fIexactly\fP four
+spaces from the start line.  This option enables a series of checks
+designed to find continuation line problems within functions only.  The
+checks have some limitations;  see CONTINUATION CHECKING, below.
+.LP
+.TP 4
+.B \-h
+Performs heuristic checks that are sometimes wrong.  Not generally used.
+.LP
+.TP 4
+.B \-p
+Performs some of the more picky checks.  Includes ANSI #else and #endif
+rules, and tries to detect spaces after casts.  Used as part of the
+putback checks.
+.LP
+.TP 4
+.B \-v
+Verbose output;  includes the text of the line of error, and, for
+\fB-c\fP, the first statement in the current continuation block.
+.LP
+.TP 4
+.B \-C
+Ignore errors in header comments (i.e. block comments starting in the
+first column).  Not generally used.
+.LP
+.TP 4
+.B \-P
+Check for use of non-POSIX types.  Historically, types like "u_int" and
+"u_long" were used, but they are now deprecated in favor of the POSIX
+types uint_t, ulong_t, etc.  This detects any use of the deprecated
+types.  Used as part of the putback checks.
+.LP
+.TP 4
+.B \-o \fIconstructs\fP
+Allow a comma-separated list of additional constructs.  Available
+constructs include:
+.LP
+.TP 10
+.B doxygen
+Allow doxygen-style block comments (\fB/**\fP and \fB/*!\fP)
+.LP
+.TP 10
+.B splint
+Allow splint-style lint comments (\fB/*@...@*/\fP)
+.LP
+.SH NOTES
+.LP
+The cstyle rule for the OS/Net consolidation is that all new files must
+be \fB-pP\fP clean.  For existing files, the following invocations are
+run against both the old and new files:
+.LP
+.TP 4
+\fBcstyle file\fB
+.LP
+.TP 4
+\fBcstyle -p file\fB
+.LP
+.TP 4
+\fBcstyle -pP file\fB
+.LP
+If the old file gave no errors for one of the invocations, the new file
+must also give no errors.  This way, files can only become more clean.
+.LP
+.SH CONTINUATION CHECKING
+.LP
+The continuation checker is a reasonably simple state machine that knows
+something about how C is laid out, and can match parenthesis, etc. over
+multiple lines.  It does have some limitations:
+.LP
+.TP 4
+.B 1.
+Preprocessor macros which cause unmatched parenthesis will confuse the
+checker for that line.  To fix this, you'll need to make sure that each
+branch of the #if statement has balanced parenthesis.
+.LP
+.TP 4
+.B 2.
+Some \fBcpp\fP macros do not require ;s after them.  Any such macros
+*must* be ALL_CAPS; any lower case letters will cause bad output.
+.LP
+The bad output will generally be corrected after the next \fB;\fP,
+\fB{\fP, or \fB}\fP.
+.LP
+Some continuation error messages deserve some additional explanation
+.LP
+.TP 4
+.B
+multiple statements continued over multiple lines
+A multi-line statement which is not broken at statement
+boundaries.  For example:
+.RS 4
+.HP 4
+if (this_is_a_long_variable == another_variable) a =
+.br
+b + c;
+.LP
+Will trigger this error.  Instead, do:
+.HP 8
+if (this_is_a_long_variable == another_variable)
+.br
+a = b + c;
+.RE
+.LP
+.TP 4
+.B
+empty if/for/while body not on its own line
+For visibility, empty bodies for if, for, and while statements should be
+on their own line.  For example:
+.RS 4
+.HP 4
+while (do_something(&x) == 0);
+.LP
+Will trigger this error.  Instead, do:
+.HP 8
+while (do_something(&x) == 0)
+.br
+;
+.RE
+
diff --git a/zfs/man/man1/raidz_test.1 b/zfs/man/man1/raidz_test.1
new file mode 100644 (file)
index 0000000..90d858d
--- /dev/null
@@ -0,0 +1,97 @@
+'\" t
+.\"
+.\" 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 (c) 2016 Gvozden Nešković. All rights reserved.
+.\"
+.TH raidz_test 1 "2016" "ZFS on Linux" "User Commands"
+
+.SH NAME
+\fBraidz_test\fR \- raidz implementation verification and bencmarking tool
+.SH SYNOPSIS
+.LP
+.BI "raidz_test <options>"
+.SH DESCRIPTION
+.LP
+This manual page documents briefly the \fBraidz_test\fR command.
+.LP
+Purpose of this tool is to run all supported raidz implementation and verify
+results of all methods. Tool also contains a parameter sweep option where all
+parameters affecting RAIDZ block are verified (like ashift size, data offset,
+data size, etc...).
+The tool also supports a benchmarking mode using -B option.
+.SH OPTION
+.HP
+.BI "\-h" ""
+.IP
+Print a help summary.
+.HP
+.BI "\-a" " ashift (default: 9)"
+.IP
+Ashift value.
+.HP
+.BI "\-o" " zio_off_shift" " (default: 0)"
+.IP
+Zio offset for raidz block. Offset value is 1 << (zio_off_shift)
+.HP
+.BI "\-d" " raidz_data_disks" " (default: 8)"
+.IP
+Number of raidz data disks to use. Additional disks for parity will be used
+during testing.
+.HP
+.BI "\-s" " zio_size_shift" " (default: 19)"
+.IP
+Size of data for raidz block. Size is 1 << (zio_size_shift).
+.HP
+.BI "\-S(weep)"
+.IP
+Sweep parameter space while verifying the raidz implementations. This option
+will exhaust all most of valid values for -a -o -d -s options. Runtime using
+this option will be long.
+.HP
+.BI "\-t(imeout)"
+.IP
+Wall time for sweep test in seconds. The actual runtime could be longer.
+.HP
+.BI "\-B(enchmark)"
+.IP
+This options starts the benchmark mode. All implementations are benchmarked
+using increasing per disk data size. Results are given as throughput per disk,
+measured in MiB/s.
+.HP
+.BI "\-v(erbose)"
+.IP
+Increase verbosity.
+.HP
+.BI "\-T(est the test)"
+.IP
+Debugging option. When this option is specified tool is supposed to fail
+all tests. This is to check if tests would properly verify bit-exactness.
+.HP
+.BI "\-D(ebug)"
+.IP
+Debugging option. Specify to attach gdb when SIGSEGV or SIGABRT are received.
+.HP
+
+.SH "SEE ALSO"
+.BR "ztest (1)"
+.SH "AUTHORS"
+vdev_raidz, created for ZFS on Linux by Gvozden Nešković <neskovic@gmail.com>
diff --git a/zfs/man/man1/zhack.1 b/zfs/man/man1/zhack.1
new file mode 100644 (file)
index 0000000..007be77
--- /dev/null
@@ -0,0 +1,100 @@
+'\" t
+.\"
+.\" 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 2013 Darik Horn <dajhorn@vanadac.com>. All rights reserved.
+.\"
+.TH zhack 1 "2013 MAR 16" "ZFS on Linux" "User Commands"
+
+.SH NAME
+zhack \- libzpool debugging tool
+.SH DESCRIPTION
+This utility pokes configuration changes directly into a ZFS pool,
+which is dangerous and can cause data corruption.
+.SH SYNOPSIS
+.LP
+.BI "zhack [\-c " "cachefile" "] [\-d " "dir" "] <" "subcommand" "> [" "arguments" "]"
+.SH OPTIONS
+.HP
+.BI "\-c" " cachefile"
+.IP
+Read the \fIpool\fR configuration from the \fIcachefile\fR, which is
+/etc/zfs/zpool.cache by default.
+.HP
+.BI "\-d" " dir"
+.IP
+Search for \fIpool\fR members in the \fIdir\fR path. Can be specified
+more than once.
+.SH SUBCOMMANDS
+.LP
+.BI "feature stat " "pool"
+.IP
+List feature flags.
+.LP
+.BI "feature enable [\-d " "description" "] [\-r] " "pool guid"
+.IP
+Add a new feature to \fIpool\fR that is uniquely identified by
+\fIguid\fR, which is specified in the same form as a zfs(8) user
+property.
+.IP
+The \fIdescription\fR is a short human readable explanation of the new
+feature.
+.IP
+The \fB\-r\fR switch indicates that \fIpool\fR can be safely opened
+in read-only mode by a system that does not have the \fIguid\fR
+feature.
+.LP
+.BI "feature ref [\-d|\-m] " "pool guid"
+.IP
+Increment the reference count of the \fIguid\fR feature in \fIpool\fR.
+.IP
+The \fB\-d\fR switch decrements the reference count of the \fIguid\fR
+feature in \fIpool\fR.
+.IP
+The \fB\-m\fR switch indicates that the \fIguid\fR feature is now
+required to read the pool MOS.
+.SH EXAMPLES
+.LP
+.nf
+# zhack feature stat tank
+
+for_read_obj:
+       org.illumos:lz4_compress = 0
+for_write_obj:
+       com.delphix:async_destroy = 0
+       com.delphix:empty_bpobj = 0
+descriptions_obj:
+       com.delphix:async_destroy = Destroy filesystems asynchronously.
+       com.delphix:empty_bpobj = Snapshots use less space.
+       org.illumos:lz4_compress = LZ4 compression algorithm support.
+.LP
+# zhack feature enable -d 'Predict future disk failures.' \\
+    tank com.example:clairvoyance
+.LP
+# zhack feature ref tank com.example:clairvoyance
+.SH AUTHORS
+This man page was written by Darik Horn <dajhorn@vanadac.com>.
+.SH SEE ALSO
+.BR splat (1),
+.BR zfs (8),
+.BR zpios (1),
+.BR zpool-features (5),
+.BR ztest (1)
diff --git a/zfs/man/man1/zpios.1 b/zfs/man/man1/zpios.1
new file mode 100644 (file)
index 0000000..4334c03
--- /dev/null
@@ -0,0 +1,241 @@
+'\" t
+.\"
+.\" 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 2013 Darik Horn <dajhorn@vanadac.com>. All rights reserved.
+.\"
+.\" Copyright (c) 2015, Intel Corporation.
+.\"
+.TH zpios 1 "2013 FEB 28" "ZFS on Linux" "User Commands"
+
+.SH NAME
+zpios \- Directly test the DMU.
+.SH SYNOPSIS
+.LP
+.BI "zpios [options] <\-p " pool ">"
+
+.SH DESCRIPTION
+This utility runs in-kernel DMU performance and stress tests that do
+not depend on the ZFS Posix Layer ("ZPL").
+
+.SH OPTIONS
+.HP
+.BI "\-t" " regex" ", \-\-threadcount" " regex"
+.IP
+Start this many threads for each test series, specified as a comma
+delimited regular expression. (eg: "-t 1,2,3")
+.IP
+This option is mutually exclusive with the \fBthreadcount_*\fR
+options.
+.HP
+.BI "\-l" " regex_low" ", \-\-threadcount_low" " regex_low"
+.HP
+.BI "\-h" " regex_high" ", \-\-threadcount_high" " regex_high"
+.HP
+.BI "\-e" " regex_incr" ", \-\-threadcount_incr" " regex_incr"
+.IP
+Start \fIregex_low\fR threads for the first test,
+add \fIregex_incr\fR threads for each subsequent test,
+and start \fIregex_high\fR threads for the last test.
+.IP
+These three options must be specified together and are mutually
+exclusive with the \fBthreadcount\fR option.
+.HP
+.BI "\-n" " regex" ", \-\-regioncount" " regex"
+.IP
+Create this many regions for each test series, specified as a comma
+delimited regular expression. (eg: "-n 512,4096,65536")
+.IP
+This option is mutually exclusive with the \fBregioncount_*\fR
+options.
+.HP
+.BI "\-i" " regex_low" ", \-\-regioncount_low" " regex_low"
+.HP
+.BI "\-j" " regex_high" ", \-\-regioncount_high" " regex_high"
+.HP
+.BI "\-k" " regex_incr" ", \-\-regioncount_incr" " regex_incr"
+.IP
+Create \fIregex_low\fR regions for the first test,
+add \fIregex_incr\fR regions for each subsequent test, and
+create \fIregex_high\fR regions for the last test.
+.IP
+These three options must be specified together and are mutually
+exclusive with the \fBregioncount\fR option.
+.HP
+.BI "\-o" " size" ", \-\-offset" " size"
+.IP
+Create regions at \fIsize\fR offset for each test series, specified as
+a comma delimited regular expression with an optional unit suffix.
+(eg: "-o 4M" means four megabytes.)
+.IP
+This option is mutually exclusive with the \fBoffset_*\fR options.
+.HP
+.BI "\-m" " size_low" ", \-\-offset_low" " size_low"
+.HP
+.BI "\-q" " size_high" ", \-\-offset_high" " size_high"
+.HP
+.BI "\-r" " size_incr" ", \-\-offset_incr" " size_incr"
+.IP
+Create a region at \fIsize_low\fR offset for the first test, add
+\fIsize_incr\fR to the offset for each subsequent test, and create
+a region at \fIsize_high\fR offset for the last test.
+.IP
+These three options must be specified together and are mutually
+exclusive with the \fBoffset\fR option.
+.HP
+.BI "\-c" " size" ", \-\-chunksize" " size"
+.IP
+Use \fIsize\fR chunks for each test, specified as a comma delimited
+regular expression with an optional unit suffix. (eg: "-c 1M" means
+one megabyte.) The chunk size must be at least the region size.
+.IP
+This option is mutually exclusive with the \fBchunksize_*\fB options.
+.HP
+.BI "\-a" " size_low" ", \-\-chunksize_low" " size_low"
+.HP
+.BI "\-b" " size_high" ", \-\-chunksize_high" " size_high"
+.HP
+.BI "\-g" " size_incr" ", \-\-chunksize_incr" " size_incr"
+.IP
+Use a \fIsize_low\fR chunk size for the first test, add \fIsize_incr\fR
+to the chunk size for each subsequent test, and use a \fIsize_high\fR
+chunk size for the last test.
+.IP
+These three options must be specified together and are mutually
+exclusive with the \fBchunksize\fR option.
+.HP
+.BI "\-s" " size" ", \-\-regionsize" " size"
+.IP
+Use \fIsize\fR regions for each test, specified as a comma delimited
+regular expression with an optional unit suffix. (eg: "-s 1M" means
+one megabyte.)
+.IP
+This option is mutually exclusive with the \fBregionsize_*\fB options.
+.HP
+.BI "\-A" " size_low" ", \-\-regionsize_low" " size_low"
+.HP
+.BI "\-B" " size_high" ", \-\-regionsize_high" " size_high"
+.HP
+.BI "\-C" " size_incr" ", \-\-regionsize_incr" " size_incr"
+.IP
+Use a \fIsize_low\fR region size for the first test, add \fIsize_incr\fR
+to the region size for each subsequent test, and use a \fIsize_high\fR
+region size for the last test.
+.IP
+These three options must be specified together and are mutually
+exclusive with the \fBregionsize\fR option.
+.HP
+.BI "\-S" " size | sizes" ", \-\-blocksize" " size | sizes"
+.IP
+Use \fIsize\fR ZFS blocks for each test, specified as a comma delimited
+regular expression with an optional unit suffix. (eg: "-S 1M" means
+one megabyte.) The supported range is powers of two from 128K through 16M.
+A range of blocks can be tested as follows: "-S 128K,256K,512K,1M".
+.IP
+.HP
+.BI "\-L" " dmu_flags" ", \-\-load" " dmu_flags"
+.IP
+Specify \fIdmuio\fR for regular DMU_IO, \fIssf\fR for single shared
+file access, or \fIfpp\fR for per thread access. Use commas to delimit
+multiple flags. (eg: "-L dmuio,ssf")
+.HP
+.BI "\-p" " name" ", \-\-pool" " name"
+.IP
+The pool name, which is mandatory.
+.HP
+.BI "\-M" " test" ", \-\-name" " test"
+.IP
+An arbitrary string that appears in the program output.
+.HP
+.BI "-x, \-\-cleanup"
+.IP
+Enable the DMU_REMOVE flag.
+.HP
+.BI "\-P" " command" ", \-\-prerun" " command"
+.IP
+Invoke \fIcommand\fR from the kernel before running the test. Shell
+expansion is not performed and the environment is set to
+HOME=/; TERM=linux; PATH=/sbin:/usr/sbin:/bin:/usr/bin.
+.HP
+.BI "\-R" " command" ", \-\-postrun" " command"
+.IP
+Invoke \fIcommand\fR from the kernel after running the test. Shell
+expansion is not performed and the environment is set to
+HOME=/; TERM=linux; PATH=/sbin:/usr/sbin:/bin:/usr/bin.
+.HP
+.BI "\-G" " directory" ", \-\-log" " directory"
+.IP
+Put logging output in this directory.
+.HP
+.BI "\-I" " size" ", \-\-regionnoise" " size"
+.IP
+Randomly vary the \fBregionsize\fR parameter for each test
+modulo \fIsize\fR bytes.
+.HP
+.BI "\-N" " size" ", \-\-chunknoise" " size"
+.IP
+Randomly vary the \fBchunksize\fR parameter for each test
+modulo \fIsize\fR bytes.
+.HP
+.BI "\-T" " time" ", \-\-threaddelay" " time"
+.IP
+Randomly vary the execution time for each test
+modulo \fItime\fR kernel jiffies.
+.HP
+.BI "\-V" "" ", \-\-verify" ""
+.IP
+Enable the DMU_VERIFY flag for trivial data verification.
+.HP
+.BI "\-z" "" ", \-\-zerocopy" ""
+.IP
+Enable the DMU_READ_ZC and DMU_WRITE_ZC flags, which are
+currently unimplemented for Linux.
+.IP
+.HP
+.BI "\-O" "" ", \-\-nowait" ""
+.IP
+Enable the DMU_WRITE_NOWAIT flag.
+.HP
+.BI "\-f" "" ", \-\-noprefetch" ""
+.IP
+Enable the DMU_READ_NOPF flag.
+.HP
+.BI "\-H" "" ", \-\-human\-readable" ""
+.IP
+Print PASS and FAIL results explicitly and put unit suffixes on large
+numbers.
+.HP
+.BI "\-v" "" ", \-\-verbose" ""
+.IP
+Increase output verbosity.
+.HP
+.BI "\-?" " " ", \-\-help" " "
+.IP
+Print the usage message.
+.SH "AUTHORS"
+The original zpios implementation was created by Cluster File Systems
+Inc and adapted to ZFS on Linux by Brian Behlendorf
+<behlendorf1@llnl.gov>.
+
+This man page was written by Darik Horn <dajhorn@vanadac.com>.
+.SH "SEE ALSO"
+.BR zpool (8),
+.BR zfs (8)
diff --git a/zfs/man/man1/ztest.1 b/zfs/man/man1/ztest.1
new file mode 100644 (file)
index 0000000..ebfacd4
--- /dev/null
@@ -0,0 +1,168 @@
+'\" t
+.\"
+.\" 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 (c) 2009 Oracle and/or its affiliates. All rights reserved.
+.\" Copyright (c) 2009 Michael Gebetsroither <michael.geb@gmx.at>. All rights
+.\" reserved.
+.\"
+.TH ztest 1 "2009 NOV 01" "ZFS on Linux" "User Commands"
+
+.SH NAME
+\fBztest\fR \- was written by the ZFS Developers as a ZFS unit test.
+.SH SYNOPSIS
+.LP
+.BI "ztest <options>"
+.SH DESCRIPTION
+.LP
+This manual page documents briefly the \fBztest\fR command.
+.LP
+\fBztest\fR was written by the ZFS Developers as a ZFS unit test. The
+tool was developed in tandem with the ZFS functionality and was
+executed nightly as one of the many regression test against the daily
+build. As features were added to ZFS, unit tests were also added to
+\fBztest\fR.  In addition, a separate test development team wrote and
+executed more functional and stress tests.
+.LP
+By default \fBztest\fR runs for ten minutes and uses block files
+(stored in /tmp) to create pools rather than using physical disks.
+Block files afford \fBztest\fR its flexibility to play around with
+zpool components without requiring large hardware configurations.
+However, storing the block files in /tmp may not work for you if you
+have a small tmp directory.
+.LP
+By default is non-verbose. This is why entering the command above will
+result in \fBztest\fR quietly executing for 5 minutes. The -V option
+can be used to increase the verbosity of the tool. Adding multiple -V
+option is allowed and the more you add the more chatty \fBztest\fR
+becomes.
+.LP
+After the \fBztest\fR run completes, you should notice many ztest.*
+files lying around. Once the run completes you can safely remove these
+files. Note that you shouldn't remove these files during a run. You
+can re-use these files in your next \fBztest\fR run by using the -E
+option.
+.SH OPTIONS
+.HP
+.BI "\-?" ""
+.IP
+Print a help summary.
+.HP
+.BI "\-v" " vdevs" " (default: 5)
+.IP
+Number of vdevs.
+.HP
+.BI "\-s" " size_of_each_vdev" " (default: 64M)"
+.IP
+Size of each vdev.
+.HP
+.BI "\-a" " alignment_shift" " (default: 9) (use 0 for random)"
+.IP
+Used alignment in test.
+.HP
+.BI "\-m" " mirror_copies" " (default: 2)"
+.IP
+Number of mirror copies.
+.HP
+.BI "\-r" " raidz_disks" " (default: 4)"
+.IP
+Number of raidz disks.
+.HP
+.BI "\-R" " raidz_parity" " (default: 1)"
+.IP
+Raidz parity.
+.HP
+.BI "\-d" " datasets" " (default: 7)"
+.IP
+Number of datasets.
+.HP
+.BI "\-t" " threads" " (default: 23)"
+.IP
+Number of threads.
+.HP
+.BI "\-g" " gang_block_threshold" " (default: 32K)"
+.IP
+Gang block threshold.
+.HP
+.BI "\-i" " initialize_pool_i_times" " (default: 1)"
+.IP
+Number of pool initialisations.
+.HP
+.BI "\-k" " kill_percentage" " (default: 70%)"
+.IP
+Kill percentage.
+.HP
+.BI "\-p" " pool_name" " (default: ztest)"
+.IP
+Pool name.
+.HP
+.BI "\-V(erbose)"
+.IP
+Verbose (use multiple times for ever more blather).
+.HP
+.BI "\-E(xisting)"
+.IP
+Use existing pool (use existing pool instead of creating new one).
+.HP
+.BI "\-T" " time" " (default: 300 sec)"
+.IP
+Total test run time.
+.HP
+.BI "\-z" " zil_failure_rate" " (default: fail every 2^5 allocs)
+.IP
+Injected failure rate.
+.SH "EXAMPLES"
+.LP
+To override /tmp as your location for block files, you can use the -f
+option:
+.IP
+ztest -f /
+.LP
+To get an idea of what ztest is actually testing try this:
+.IP
+ztest -f / -VVV
+.LP
+Maybe you'd like to run ztest for longer? To do so simply use the -T
+option and specify the runlength in seconds like so:
+.IP
+ztest -f / -V -T 120
+
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.B "ZFS_STACK_SIZE=stacksize"
+Limit the default stack size to \fBstacksize\fR bytes for the purpose of
+detecting and debugging kernel stack overflows.  This value defaults to
+\fB32K\fR which is double the default \fB16K\fR Linux kernel stack size.
+
+In practice, setting the stack size slightly higher is needed because
+differences in stack usage between kernel and user space can lead to spurious
+stack overflows (especially when debugging is enabled).  The specified value
+will be rounded up to a floor of PTHREAD_STACK_MIN which is the minimum stack
+required for a NULL procedure in user space.
+
+By default the stack size is limited to 256K.
+.SH "SEE ALSO"
+.BR "zpool (1)" ","
+.BR "zfs (1)" ","
+.BR "zdb (1)" ","
+.SH "AUTHOR"
+This manual page was transvered to asciidoc by Michael Gebetsroither
+<gebi@grml.org> from http://opensolaris.org/os/community/zfs/ztest/
diff --git a/zfs/man/man5/Makefile.am b/zfs/man/man5/Makefile.am
new file mode 100644 (file)
index 0000000..4746914
--- /dev/null
@@ -0,0 +1,4 @@
+dist_man_MANS = vdev_id.conf.5 zpool-features.5 zfs-module-parameters.5 zfs-events.5
+
+install-data-local:
+       $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man5"
diff --git a/zfs/man/man5/Makefile.in b/zfs/man/man5/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/man/man5/vdev_id.conf.5 b/zfs/man/man5/vdev_id.conf.5
new file mode 100644 (file)
index 0000000..4fea831
--- /dev/null
@@ -0,0 +1,180 @@
+.TH vdev_id.conf 5
+.SH NAME
+vdev_id.conf \- Configuration file for vdev_id
+.SH DESCRIPTION
+.I vdev_id.conf
+is the configuration file for
+.BR vdev_id (8).
+It controls the default behavior of
+.BR vdev_id (8)
+while it is mapping a disk device name to an alias.
+.PP
+The
+.I vdev_id.conf
+file uses a simple format consisting of a keyword followed by one or
+more values on a single line.  Any line not beginning with a recognized
+keyword is ignored.  Comments may optionally begin with a hash
+character.
+
+The following keywords and values are used.
+.TP
+\fIalias\fR <name> <devlink>
+Maps a device link in the /dev directory hierarchy to a new device
+name.  The udev rule defining the device link must have run prior to
+.BR vdev_id (8).
+A defined alias takes precedence over a topology-derived name, but the
+two naming methods can otherwise coexist.  For example, one might name
+drives in a JBOD with the sas_direct topology while naming an internal
+L2ARC device with an alias.
+
+\fIname\fR - the name of the link to the device that will by created in
+/dev/disk/by-vdev.
+
+\fIdevlink\fR - the name of the device link that has already been
+defined by udev.  This may be an absolute path or the base filename.
+
+.TP
+\fIchannel\fR [pci_slot] <port> <name>
+Maps a physical path to a channel name (typically representing a single
+disk enclosure).
+
+\fIpci_slot\fR - specifies the PCI SLOT of the HBA
+hosting the disk enclosure being mapped, as found in the output of
+.BR lspci (8).
+This argument is not used in sas_switch mode.
+
+\fIport\fR - specifies the numeric identifier of the HBA or SAS switch port
+connected to the disk enclosure being mapped.
+
+\fIname\fR - specifies the name of the channel.
+
+.TP
+\fIslot\fR <old> <new> [channel]
+Maps a disk slot number as reported by the operating system to an
+alternative slot number.  If the \fIchannel\fR parameter is specified
+then the mapping is only applied to slots in the named channel,
+otherwise the mapping is applied to all channels. The first-specified
+\fIslot\fR rule that can match a slot takes precedence.  Therefore a
+channel-specific mapping for a given slot should generally appear before
+a generic mapping for the same slot.  In this way a custom mapping may
+be applied to a particular channel and a default mapping applied to the
+others.
+
+.TP
+\fImultipath\fR <yes|no>
+Specifies whether
+.BR vdev_id (8)
+will handle only dm-multipath devices.  If set to "yes" then
+.BR vdev_id (8)
+will examine the first running component disk of a dm-multipath
+device as listed by the
+.BR multipath (8)
+command to determine the physical path.
+.TP
+\fItopology\fR <sas_direct|sas_switch>
+Identifies a physical topology that governs how physical paths are
+mapped to channels.
+
+\fIsas_direct\fR - in this mode a channel is uniquely identified by
+a PCI slot and a HBA port number
+
+\fIsas_switch\fR - in this mode a channel is uniquely identified by
+a SAS switch port number
+
+.TP
+\fIphys_per_port\fR <num>
+Specifies the number of PHY devices associated with a SAS HBA port or SAS
+switch port.
+.BR vdev_id (8)
+internally uses this value to determine which HBA or switch port a
+device is connected to.  The default is 4.
+
+.TP
+\fIslot\fR <bay|phy|id|lun>
+Specifies from which element of a SAS identifier the slot number is
+taken.  The default is bay.
+
+\fIbay\fR - read the slot number from the bay identifier.
+
+\fIphy\fR - read the slot number from the phy identifier.
+
+\fIid\fR - use the scsi id as the slot number.
+
+\fIlun\fR - use the scsi lun as the slot number.
+.SH EXAMPLES
+A non-multipath configuration with direct-attached SAS enclosures and an
+arbitrary slot re-mapping.
+.P
+.nf
+       multipath     no
+       topology      sas_direct
+       phys_per_port 4
+       slot          bay
+
+       #       PCI_SLOT HBA PORT  CHANNEL NAME
+       channel 85:00.0  1         A
+       channel 85:00.0  0         B
+       channel 86:00.0  1         C
+       channel 86:00.0  0         D
+
+       # Custom mapping for Channel A
+
+       #    Linux      Mapped
+       #    Slot       Slot      Channel
+       slot 1          7         A
+       slot 2          10        A
+       slot 3          3         A
+       slot 4          6         A
+
+       # Default mapping for B, C, and D
+
+       slot 1          4
+       slot 2          2
+       slot 3          1
+       slot 4          3
+.fi
+.P
+A SAS-switch topology.  Note that the
+.I channel
+keyword takes only two arguments in this example.
+.P
+.nf
+       topology      sas_switch
+
+       #       SWITCH PORT  CHANNEL NAME
+       channel 1            A
+       channel 2            B
+       channel 3            C
+       channel 4            D
+.fi
+.P
+A multipath configuration.  Note that channel names have multiple
+definitions - one per physical path.
+.P
+.nf
+       multipath yes
+
+       #       PCI_SLOT HBA PORT  CHANNEL NAME
+       channel 85:00.0  1         A
+       channel 85:00.0  0         B
+       channel 86:00.0  1         A
+       channel 86:00.0  0         B
+.fi
+.P
+A configuration using device link aliases.
+.P
+.nf
+       #     by-vdev
+       #     name     fully qualified or base name of device link
+       alias d1       /dev/disk/by-id/wwn-0x5000c5002de3b9ca
+       alias d2       wwn-0x5000c5002def789e
+.fi
+.P
+
+.SH FILES
+.TP
+.I /etc/zfs/vdev_id.conf
+The configuration file for
+.BR vdev_id (8).
+.SH SEE ALSO
+.BR vdev_id (8)
diff --git a/zfs/man/man5/zfs-events.5 b/zfs/man/man5/zfs-events.5
new file mode 100644 (file)
index 0000000..398ea8a
--- /dev/null
@@ -0,0 +1,889 @@
+'\" te
+.\" Copyright (c) 2013 by Turbo Fredriksson <turbo@bayour.com>. All rights reserved.
+.\" 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]
+.TH ZFS-EVENTS 5 "Jun 6, 2015"
+.SH NAME
+zfs\-events \- Events created by the ZFS filesystem.
+.SH DESCRIPTION
+.sp
+.LP
+Description of the different events generated by the ZFS stack.
+.sp
+Most of these don't have any description. The events generated by ZFS
+have never been publicly documented.  What is here is intended as a
+starting point to provide documentation for all possible events.
+.sp
+To view all events created since the loading of the ZFS infrastructure
+(i.e, "the module"), run
+.P
+.nf
+\fBzpool events\fR
+.fi
+.P
+to get a short list, and
+.P
+.nf
+\fBzpool events -v\fR
+.fi
+.P
+to get a full detail of the events and what information
+is available about it.
+.sp
+This man page lists the different subclasses that are issued
+in the case of an event. The full event name would be
+\fIereport.fs.zfs.SUBCLASS\fR, but we only list the last
+part here.
+
+.SS "EVENTS (SUBCLASS)"
+.sp
+.LP
+
+.sp
+.ne 2
+.na
+\fBchecksum\fR
+.ad
+.RS 12n
+Issued when a checksum error have been detected.
+.RE
+
+.sp
+.ne 2
+.na
+\fBio\fR
+.ad
+.RS 12n
+Issued when there is an I/O error in a vdev in the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fBdata\fR
+.ad
+.RS 12n
+Issued when there have been data errors in the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fBdelay\fR
+.ad
+.RS 12n
+Issued when an I/O was slow to complete as defined by the zio_delay_max module
+option.
+.RE
+
+.sp
+.ne 2
+.na
+\fBconfig.sync\fR
+.ad
+.RS 12n
+Issued every time a vdev change have been done to the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzpool\fR
+.ad
+.RS 12n
+Issued when a pool cannot be imported.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzpool.destroy\fR
+.ad
+.RS 12n
+Issued when a pool is destroyed.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzpool.export\fR
+.ad
+.RS 12n
+Issued when a pool is exported.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzpool.import\fR
+.ad
+.RS 12n
+Issued when a pool is imported.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzpool.reguid\fR
+.ad
+.RS 12n
+Issued when a REGUID (new unique identifier for the pool have been regenerated) have been detected.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.unknown\fR
+.ad
+.RS 12n
+Issued when the vdev is unknown. Such as trying to clear device
+errors on a vdev that have failed/been kicked from the system/pool
+and is no longer available.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.open_failed\fR
+.ad
+.RS 12n
+Issued when a vdev could not be opened (because it didn't exist for example).
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.corrupt_data\fR
+.ad
+.RS 12n
+Issued when corrupt data have been detected on a vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.no_replicas\fR
+.ad
+.RS 12n
+Issued when there are no more replicas to sustain the pool.
+This would lead to the pool being \fIDEGRADED\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.bad_guid_sum\fR
+.ad
+.RS 12n
+Issued when a missing device in the pool have been detected.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.too_small\fR
+.ad
+.RS 12n
+Issued when the system (kernel) have removed a device, and ZFS
+notices that the device isn't there any more. This is usually
+followed by a \fBprobe_failure\fR event.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.bad_label\fR
+.ad
+.RS 12n
+Issued when the label is OK but invalid.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.bad_ashift\fR
+.ad
+.RS 12n
+Issued when the ashift alignment requirement has increased.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.remove\fR
+.ad
+.RS 12n
+Issued when a vdev is detached from a mirror (or a spare detached from a
+vdev where it have been used to replace a failed drive - only works if
+the original drive have been readded).
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.clear\fR
+.ad
+.RS 12n
+Issued when clearing device errors in a pool. Such as running \fBzpool clear\fR
+on a device in the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.check\fR
+.ad
+.RS 12n
+Issued when a check to see if a given vdev could be opened is started.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.spare\fR
+.ad
+.RS 12n
+Issued when a spare have kicked in to replace a failed device.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev.autoexpand\fR
+.ad
+.RS 12n
+Issued when a vdev can be automatically expanded.
+.RE
+
+.sp
+.ne 2
+.na
+\fBio_failure\fR
+.ad
+.RS 12n
+Issued when there is an I/O failure in a vdev in the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fBprobe_failure\fR
+.ad
+.RS 12n
+Issued when a probe fails on a vdev. This would occur if a vdev
+have been kicked from the system outside of ZFS (such as the kernel
+have removed the device).
+.RE
+
+.sp
+.ne 2
+.na
+\fBlog_replay\fR
+.ad
+.RS 12n
+Issued when the intent log cannot be replayed.  The can occur in the case
+of a missing or damaged log device.
+.RE
+
+.sp
+.ne 2
+.na
+\fBresilver.start\fR
+.ad
+.RS 12n
+Issued when a resilver is started.
+.RE
+
+.sp
+.ne 2
+.na
+\fBresilver.finish\fR
+.ad
+.RS 12n
+Issued when the running resilver have finished.
+.RE
+
+.sp
+.ne 2
+.na
+\fBscrub.start\fR
+.ad
+.RS 12n
+Issued when a scrub is started on a pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fBscrub.finish\fR
+.ad
+.RS 12n
+Issued when a pool have finished scrubbing.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbootfs.vdev.attach\fR
+.ad
+.RS 12n
+.RE
+
+.SS "PAYLOADS"
+.sp
+.LP
+This is the payload (data, information) that accompanies an
+event.
+.sp
+For
+.BR zed (8),
+these are set to uppercase and prefixed with \fBZEVENT_\fR.
+
+.sp
+.ne 2
+.na
+\fBpool\fR
+.ad
+.RS 12n
+Pool name.
+.RE
+
+.sp
+.ne 2
+.na
+\fBpool_failmode\fR
+.ad
+.RS 12n
+Failmode - \fBwait\fR, \fBcontinue\fR or \fBpanic\fR.
+See
+.BR pool (8)
+(\fIfailmode\fR property) for more information.
+.RE
+
+.sp
+.ne 2
+.na
+\fBpool_guid\fR
+.ad
+.RS 12n
+The GUID of the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fBpool_context\fR
+.ad
+.RS 12n
+The load state for the pool (0=none, 1=open, 2=import, 3=tryimport, 4=recover
+5=error).
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_guid\fR
+.ad
+.RS 12n
+The GUID of the vdev in question (the vdev failing or operated upon with
+\fBzpool clear\fR etc).
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_type\fR
+.ad
+.RS 12n
+Type of vdev - \fBdisk\fR, \fBfile\fR, \fBmirror\fR etc. See
+.BR zpool (8)
+under \fBVirtual Devices\fR for more information on possible values.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_path\fR
+.ad
+.RS 12n
+Full path of the vdev, including any \fI-partX\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_devid\fR
+.ad
+.RS 12n
+ID of vdev (if any).
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_fru\fR
+.ad
+.RS 12n
+Physical FRU location.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_state\fR
+.ad
+.RS 12n
+State of vdev (0=uninitialized, 1=closed, 2=offline, 3=removed, 4=failed to open, 5=faulted, 6=degraded, 7=healthy).
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_ashift\fR
+.ad
+.RS 12n
+The ashift value of the vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_complete_ts\fR
+.ad
+.RS 12n
+The time the last I/O completed for the specified vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_delta_ts\fR
+.ad
+.RS 12n
+The time since the last I/O completed for the specified vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_spare_paths\fR
+.ad
+.RS 12n
+List of spares, including full path and any \fI-partX\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_spare_guids\fR
+.ad
+.RS 12n
+GUID(s) of spares.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_read_errors\fR
+.ad
+.RS 12n
+How many read errors that have been detected on the vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_write_errors\fR
+.ad
+.RS 12n
+How many write errors that have been detected on the vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBvdev_cksum_errors\fR
+.ad
+.RS 12n
+How many checkum errors that have been detected on the vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBparent_guid\fR
+.ad
+.RS 12n
+GUID of the vdev parent.
+.RE
+
+.sp
+.ne 2
+.na
+\fBparent_type\fR
+.ad
+.RS 12n
+Type of parent. See \fBvdev_type\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBparent_path\fR
+.ad
+.RS 12n
+Path of the vdev parent (if any).
+.RE
+
+.sp
+.ne 2
+.na
+\fBparent_devid\fR
+.ad
+.RS 12n
+ID of the vdev parent (if any).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_objset\fR
+.ad
+.RS 12n
+The object set number for a given I/O.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_object\fR
+.ad
+.RS 12n
+The object number for a given I/O.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_level\fR
+.ad
+.RS 12n
+The block level for a given I/O.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_blkid\fR
+.ad
+.RS 12n
+The block ID for a given I/O.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_err\fR
+.ad
+.RS 12n
+The errno for a failure when handling a given I/O.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_offset\fR
+.ad
+.RS 12n
+The offset in bytes of where to write the I/O for the specified vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_size\fR
+.ad
+.RS 12n
+The size in bytes of the I/O.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_flags\fR
+.ad
+.RS 12n
+The current flags describing how the I/O should be handled.  See the
+\fBI/O FLAGS\fR section for the full list of I/O flags.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_stage\fR
+.ad
+.RS 12n
+The current stage of the I/O in the pipeline.  See the \fBI/O STAGES\fR
+section for a full list of all the I/O stages.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_pipeline\fR
+.ad
+.RS 12n
+The valid pipeline stages for the I/O.  See the \fBI/O STAGES\fR section for a
+full list of all the I/O stages.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_delay\fR
+.ad
+.RS 12n
+The time in ticks (HZ) required for the block layer to service the I/O.  Unlike
+\fBzio_delta\fR this does not include any vdev queuing time and is therefore
+solely a measure of the block layer performance.  On most modern Linux systems
+HZ is defined as 1000 making a tick equivalent to 1 millisecond.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_timestamp\fR
+.ad
+.RS 12n
+The time when a given I/O was submitted.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_delta\fR
+.ad
+.RS 12n
+The time required to service a given I/O.
+.RE
+
+.sp
+.ne 2
+.na
+\fBprev_state\fR
+.ad
+.RS 12n
+The previous state of the vdev.
+.RE
+
+.sp
+.ne 2
+.na
+\fBcksum_expected\fR
+.ad
+.RS 12n
+The expected checksum value.
+.RE
+
+.sp
+.ne 2
+.na
+\fBcksum_actual\fR
+.ad
+.RS 12n
+The actual/current checksum value.
+.RE
+
+.sp
+.ne 2
+.na
+\fBcksum_algorithm\fR
+.ad
+.RS 12n
+Checksum algorithm used. See \fBzfs\fR(8) for more information on checksum algorithms available.
+.RE
+
+.sp
+.ne 2
+.na
+\fBcksum_byteswap\fR
+.ad
+.RS 12n
+Checksum value is byte swapped.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbad_ranges\fR
+.ad
+.RS 12n
+Checksum bad offset ranges.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbad_ranges_min_gap\fR
+.ad
+.RS 12n
+Checksum allowed minimum gap.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbad_range_sets\fR
+.ad
+.RS 12n
+Checksum for each range the number of bits set.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbad_range_clears\fR
+.ad
+.RS 12n
+Checksum for each range the number of bits cleared.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbad_set_bits\fR
+.ad
+.RS 12n
+Checksum array of bits set.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbad_cleared_bits\fR
+.ad
+.RS 12n
+Checksum array of bits cleared.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbad_set_histogram\fR
+.ad
+.RS 12n
+Checksum histogram of set bits by bit number in a 64-bit word.
+.RE
+
+.sp
+.ne 2
+.na
+\fBbad_cleared_histogram\fR
+.ad
+.RS 12n
+Checksum histogram of cleared bits by bit number in a 64-bit word.
+.RE
+
+.SS "I/O STAGES"
+.sp
+.LP
+The ZFS I/O pipeline is comprised of various stages which are defined
+below.  The individual stages are used to construct these basic I/O
+operations: Read, Write, Free, Claim, and Ioctl.  These stages may be
+set on an event to describe the life cycle of a given I/O.
+
+.TS
+tab(:);
+l l l .
+Stage:Bit Mask:Operations
+_:_:_
+ZIO_STAGE_OPEN:0x00000001:RWFCI
+
+ZIO_STAGE_READ_BP_INIT:0x00000002:R----
+ZIO_STAGE_FREE_BP_INIT:0x00000004:--F--
+ZIO_STAGE_ISSUE_ASYNC:0x00000008:RWF--
+ZIO_STAGE_WRITE_BP_INIT:0x00000010:-W---
+
+ZIO_STAGE_CHECKSUM_GENERATE:0x00000020:-W---
+
+ZIO_STAGE_NOP_WRITE:0x00000040:-W---
+
+ZIO_STAGE_DDT_READ_START:0x00000080:R----
+ZIO_STAGE_DDT_READ_DONE:0x00000100:R----
+ZIO_STAGE_DDT_WRITE:0x00000200:-W---
+ZIO_STAGE_DDT_FREE:0x00000400:--F--
+
+ZIO_STAGE_GANG_ASSEMBLE:0x00000800:RWFC-
+ZIO_STAGE_GANG_ISSUE:0x00001000:RWFC-
+
+ZIO_STAGE_DVA_ALLOCATE:0x00002000:-W---
+ZIO_STAGE_DVA_FREE:0x00004000:--F--
+ZIO_STAGE_DVA_CLAIM:0x00008000:---C-
+
+ZIO_STAGE_READY:0x00010000:RWFCI
+
+ZIO_STAGE_VDEV_IO_START:0x00020000:RW--I
+ZIO_STAGE_VDEV_IO_DONE:0x00040000:RW--I
+ZIO_STAGE_VDEV_IO_ASSESS:0x00080000:RW--I
+
+ZIO_STAGE_CHECKSUM_VERIFY0:0x00100000:R----
+
+ZIO_STAGE_DONE:0x00200000:RWFCI
+.TE
+
+.SS "I/O FLAGS"
+.sp
+.LP
+Every I/O in the pipeline contains a set of flags which describe its
+function and are used to govern its behavior.  These flags will be set
+in an event as an \fBzio_flags\fR payload entry.
+
+.TS
+tab(:);
+l l .
+Flag:Bit Mask
+_:_
+ZIO_FLAG_DONT_AGGREGATE:0x00000001
+ZIO_FLAG_IO_REPAIR:0x00000002
+ZIO_FLAG_SELF_HEAL:0x00000004
+ZIO_FLAG_RESILVER:0x00000008
+ZIO_FLAG_SCRUB:0x00000010
+ZIO_FLAG_SCAN_THREAD:0x00000020
+ZIO_FLAG_PHYSICAL:0x00000040
+
+ZIO_FLAG_CANFAIL:0x00000080
+ZIO_FLAG_SPECULATIVE:0x00000100
+ZIO_FLAG_CONFIG_WRITER:0x00000200
+ZIO_FLAG_DONT_RETRY:0x00000400
+ZIO_FLAG_DONT_CACHE:0x00000800
+ZIO_FLAG_NODATA:0x00001000
+ZIO_FLAG_INDUCE_DAMAGE:0x00002000
+
+ZIO_FLAG_IO_RETRY:0x00004000
+ZIO_FLAG_PROBE:0x00008000
+ZIO_FLAG_TRYHARD:0x00010000
+ZIO_FLAG_OPTIONAL:0x00020000
+
+ZIO_FLAG_DONT_QUEUE:0x00040000
+ZIO_FLAG_DONT_PROPAGATE:0x00080000
+ZIO_FLAG_IO_BYPASS:0x00100000
+ZIO_FLAG_IO_REWRITE:0x00200000
+ZIO_FLAG_RAW:0x00400000
+ZIO_FLAG_GANG_CHILD:0x00800000
+ZIO_FLAG_DDT_CHILD:0x01000000
+ZIO_FLAG_GODFATHER:0x02000000
+ZIO_FLAG_NOPWRITE:0x04000000
+ZIO_FLAG_REEXECUTED:0x08000000
+ZIO_FLAG_DELEGATED:0x10000000
+ZIO_FLAG_FASTWRITE:0x20000000
+.TE
diff --git a/zfs/man/man5/zfs-module-parameters.5 b/zfs/man/man5/zfs-module-parameters.5
new file mode 100644 (file)
index 0000000..8e37a97
--- /dev/null
@@ -0,0 +1,2128 @@
+'\" te
+.\" Copyright (c) 2013 by Turbo Fredriksson <turbo@bayour.com>. All rights reserved.
+.\" 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]
+.TH ZFS-MODULE-PARAMETERS 5 "Nov 16, 2013"
+.SH NAME
+zfs\-module\-parameters \- ZFS module parameters
+.SH DESCRIPTION
+.sp
+.LP
+Description of the different parameters to the ZFS module.
+
+.SS "Module parameters"
+.sp
+.LP
+
+.sp
+.ne 2
+.na
+\fBignore_hole_birth\fR (int)
+.ad
+.RS 12n
+When set, the hole_birth optimization will not be used, and all holes will
+always be sent on zfs send. Useful if you suspect your datasets are affected
+by a bug in hole_birth.
+.sp
+Use \fB1\fR for on (default) and \fB0\fR for off.
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_feed_again\fR (int)
+.ad
+.RS 12n
+Turbo L2ARC warm-up. When the L2ARC is cold the fill interval will be set as
+fast as possible.
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR to disable.
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_feed_min_ms\fR (ulong)
+.ad
+.RS 12n
+Min feed interval in milliseconds. Requires \fBl2arc_feed_again=1\fR and only
+applicable in related situations.
+.sp
+Default value: \fB200\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_feed_secs\fR (ulong)
+.ad
+.RS 12n
+Seconds between L2ARC writing
+.sp
+Default value: \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_headroom\fR (ulong)
+.ad
+.RS 12n
+How far through the ARC lists to search for L2ARC cacheable content, expressed
+as a multiplier of \fBl2arc_write_max\fR
+.sp
+Default value: \fB2\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_headroom_boost\fR (ulong)
+.ad
+.RS 12n
+Scales \fBl2arc_headroom\fR by this percentage when L2ARC contents are being
+successfully compressed before writing. A value of 100 disables this feature.
+.sp
+Default value: \fB200\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_nocompress\fR (int)
+.ad
+.RS 12n
+Skip compressing L2ARC buffers
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_noprefetch\fR (int)
+.ad
+.RS 12n
+Do not write buffers to L2ARC if they were prefetched but not used by
+applications
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR to disable.
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_norw\fR (int)
+.ad
+.RS 12n
+No reads during writes
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_write_boost\fR (ulong)
+.ad
+.RS 12n
+Cold L2ARC devices will have \fBl2arc_write_nax\fR increased by this amount
+while they remain cold.
+.sp
+Default value: \fB8,388,608\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBl2arc_write_max\fR (ulong)
+.ad
+.RS 12n
+Max write bytes per interval
+.sp
+Default value: \fB8,388,608\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBmetaslab_aliquot\fR (ulong)
+.ad
+.RS 12n
+Metaslab granularity, in bytes. This is roughly similar to what would be
+referred to as the "stripe size" in traditional RAID arrays. In normal
+operation, ZFS will try to write this amount of data to a top-level vdev
+before moving on to the next one.
+.sp
+Default value: \fB524,288\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBmetaslab_bias_enabled\fR (int)
+.ad
+.RS 12n
+Enable metaslab group biasing based on its vdev's over- or under-utilization
+relative to the pool.
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR for no.
+.RE
+
+.sp
+.ne 2
+.na
+\fBmetaslab_debug_load\fR (int)
+.ad
+.RS 12n
+Load all metaslabs during pool import.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBmetaslab_debug_unload\fR (int)
+.ad
+.RS 12n
+Prevent metaslabs from being unloaded.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBmetaslab_fragmentation_factor_enabled\fR (int)
+.ad
+.RS 12n
+Enable use of the fragmentation metric in computing metaslab weights.
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR for no.
+.RE
+
+.sp
+.ne 2
+.na
+\fBmetaslabs_per_vdev\fR (int)
+.ad
+.RS 12n
+When a vdev is added, it will be divided into approximately (but no more than) this number of metaslabs.
+.sp
+Default value: \fB200\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBmetaslab_preload_enabled\fR (int)
+.ad
+.RS 12n
+Enable metaslab group preloading.
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR for no.
+.RE
+
+.sp
+.ne 2
+.na
+\fBmetaslab_lba_weighting_enabled\fR (int)
+.ad
+.RS 12n
+Give more weight to metaslabs with lower LBAs, assuming they have
+greater bandwidth as is typically the case on a modern constant
+angular velocity disk drive.
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR for no.
+.RE
+
+.sp
+.ne 2
+.na
+\fBspa_config_path\fR (charp)
+.ad
+.RS 12n
+SPA config file
+.sp
+Default value: \fB/etc/zfs/zpool.cache\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBspa_asize_inflation\fR (int)
+.ad
+.RS 12n
+Multiplication factor used to estimate actual disk consumption from the
+size of data being written. The default value is a worst case estimate,
+but lower values may be valid for a given pool depending on its
+configuration.  Pool administrators who understand the factors involved
+may wish to specify a more realistic inflation factor, particularly if
+they operate close to quota or capacity limits.
+.sp
+Default value: \fB24\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBspa_load_verify_data\fR (int)
+.ad
+.RS 12n
+Whether to traverse data blocks during an "extreme rewind" (\fB-X\fR)
+import.  Use 0 to disable and 1 to enable.
+
+An extreme rewind import normally performs a full traversal of all
+blocks in the pool for verification.  If this parameter is set to 0,
+the traversal skips non-metadata blocks.  It can be toggled once the
+import has started to stop or start the traversal of non-metadata blocks.
+.sp
+Default value: \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBspa_load_verify_metadata\fR (int)
+.ad
+.RS 12n
+Whether to traverse blocks during an "extreme rewind" (\fB-X\fR)
+pool import.  Use 0 to disable and 1 to enable.
+
+An extreme rewind import normally performs a full traversal of all
+blocks in the pool for verification.  If this parameter is set to 0,
+the traversal is not performed.  It can be toggled once the import has
+started to stop or start the traversal.
+.sp
+Default value: \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBspa_load_verify_maxinflight\fR (int)
+.ad
+.RS 12n
+Maximum concurrent I/Os during the traversal performed during an "extreme
+rewind" (\fB-X\fR) pool import.
+.sp
+Default value: \fB10000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBspa_slop_shift\fR (int)
+.ad
+.RS 12n
+Normally, we don't allow the last 3.2% (1/(2^spa_slop_shift)) of space
+in the pool to be consumed.  This ensures that we don't run the pool
+completely out of space, due to unaccounted changes (e.g. to the MOS).
+It also limits the worst-case time to allocate space.  If we have
+less than this amount of free space, most ZPL operations (e.g. write,
+create) will return ENOSPC.
+.sp
+Default value: \fB5\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfetch_array_rd_sz\fR (ulong)
+.ad
+.RS 12n
+If prefetching is enabled, disable prefetching for reads larger than this size.
+.sp
+Default value: \fB1,048,576\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfetch_max_distance\fR (uint)
+.ad
+.RS 12n
+Max bytes to prefetch per stream (default 8MB).
+.sp
+Default value: \fB8,388,608\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfetch_max_streams\fR (uint)
+.ad
+.RS 12n
+Max number of streams per zfetch (prefetch streams per file).
+.sp
+Default value: \fB8\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfetch_min_sec_reap\fR (uint)
+.ad
+.RS 12n
+Min time before an active prefetch stream can be reclaimed
+.sp
+Default value: \fB2\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_dnode_limit\fR (ulong)
+.ad
+.RS 12n
+When the number of bytes consumed by dnodes in the ARC exceeds this number of
+bytes, try to unpin some of it in response to demand for non-metadata. This
+value acts as a floor to the amount of dnode metadata, and defaults to 0 which
+indicates that a percent which is based on \fBzfs_arc_dnode_limit_percent\fR of
+the ARC meta buffers that may be used for dnodes.
+
+See also \fBzfs_arc_meta_prune\fR which serves a similar purpose but is used
+when the amount of metadata in the ARC exceeds \fBzfs_arc_meta_limit\fR rather
+than in response to overall demand for non-metadata.
+
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_dnode_limit_percent\fR (ulong)
+.ad
+.RS 12n
+Percentage that can be consumed by dnodes of ARC meta buffers.
+.sp
+See also \fBzfs_arc_dnode_limit\fR which serves a similar purpose but has a
+higher priority if set to nonzero value.
+.sp
+Default value: \fB10\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_dnode_reduce_percent\fR (ulong)
+.ad
+.RS 12n
+Percentage of ARC dnodes to try to scan in response to demand for non-metadata
+when the number of bytes consumed by dnodes exceeds \fBzfs_arc_dnode_limit\fB.
+
+.sp
+Default value: \fB10% of the number of dnodes in the ARC\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_average_blocksize\fR (int)
+.ad
+.RS 12n
+The ARC's buffer hash table is sized based on the assumption of an average
+block size of \fBzfs_arc_average_blocksize\fR (default 8K).  This works out
+to roughly 1MB of hash table per 1GB of physical memory with 8-byte pointers.
+For configurations with a known larger average block size this value can be
+increased to reduce the memory footprint.
+
+.sp
+Default value: \fB8192\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_evict_batch_limit\fR (int)
+.ad
+.RS 12n
+Number ARC headers to evict per sub-list before proceeding to another sub-list.
+This batch-style operation prevents entire sub-lists from being evicted at once
+but comes at a cost of additional unlocking and locking.
+.sp
+Default value: \fB10\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_grow_retry\fR (int)
+.ad
+.RS 12n
+After a memory pressure event the ARC will wait this many seconds before trying
+to resume growth
+.sp
+Default value: \fB5\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_lotsfree_percent\fR (int)
+.ad
+.RS 12n
+Throttle I/O when free system memory drops below this percentage of total
+system memory.  Setting this value to 0 will disable the throttle.
+.sp
+Default value: \fB10\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_max\fR (ulong)
+.ad
+.RS 12n
+Max arc size of ARC in bytes. If set to 0 then it will consume 1/2 of system
+RAM. This value must be at least 67108864 (64 megabytes).
+.sp
+This value can be changed dynamically with some caveats. It cannot be set back
+to 0 while running and reducing it below the current ARC size will not cause
+the ARC to shrink without memory pressure to induce shrinking.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_meta_limit\fR (ulong)
+.ad
+.RS 12n
+The maximum allowed size in bytes that meta data buffers are allowed to
+consume in the ARC.  When this limit is reached meta data buffers will
+be reclaimed even if the overall arc_c_max has not been reached.  This
+value defaults to 0 which indicates that a percent which is based on
+\fBzfs_arc_meta_limit_percent\fR of the ARC may be used for meta data.
+.sp
+This value my be changed dynamically except that it cannot be set back to 0
+for a specific percent of the ARC; it must be set to an explicit value.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_meta_limit_percent\fR (ulong)
+.ad
+.RS 12n
+Percentage of ARC buffers that can be used for meta data.
+
+See also \fBzfs_arc_meta_limit\fR which serves a similar purpose but has a
+higher priority if set to nonzero value.
+
+.sp
+Default value: \fB75\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_meta_min\fR (ulong)
+.ad
+.RS 12n
+The minimum allowed size in bytes that meta data buffers may consume in
+the ARC.  This value defaults to 0 which disables a floor on the amount
+of the ARC devoted meta data.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_meta_prune\fR (int)
+.ad
+.RS 12n
+The number of dentries and inodes to be scanned looking for entries
+which can be dropped.  This may be required when the ARC reaches the
+\fBzfs_arc_meta_limit\fR because dentries and inodes can pin buffers
+in the ARC.  Increasing this value will cause to dentry and inode caches
+to be pruned more aggressively.  Setting this value to 0 will disable
+pruning the inode and dentry caches.
+.sp
+Default value: \fB10,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_meta_adjust_restarts\fR (ulong)
+.ad
+.RS 12n
+The number of restart passes to make while scanning the ARC attempting
+the free buffers in order to stay below the \fBzfs_arc_meta_limit\fR.
+This value should not need to be tuned but is available to facilitate
+performance analysis.
+.sp
+Default value: \fB4096\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_min\fR (ulong)
+.ad
+.RS 12n
+Min arc size
+.sp
+Default value: \fB100\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_min_prefetch_lifespan\fR (int)
+.ad
+.RS 12n
+Minimum time prefetched blocks are locked in the ARC, specified in jiffies.
+A value of 0 will default to 1 second.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_num_sublists_per_state\fR (int)
+.ad
+.RS 12n
+To allow more fine-grained locking, each ARC state contains a series
+of lists for both data and meta data objects.  Locking is performed at
+the level of these "sub-lists".  This parameters controls the number of
+sub-lists per ARC state.
+.sp
+Default value: \fR1\fB or the number of online CPUs, whichever is greater
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_overflow_shift\fR (int)
+.ad
+.RS 12n
+The ARC size is considered to be overflowing if it exceeds the current
+ARC target size (arc_c) by a threshold determined by this parameter.
+The threshold is calculated as a fraction of arc_c using the formula
+"arc_c >> \fBzfs_arc_overflow_shift\fR".
+
+The default value of 8 causes the ARC to be considered to be overflowing
+if it exceeds the target size by 1/256th (0.3%) of the target size.
+
+When the ARC is overflowing, new buffer allocations are stalled until
+the reclaim thread catches up and the overflow condition no longer exists.
+.sp
+Default value: \fB8\fR.
+.RE
+
+.sp
+.ne 2
+.na
+
+\fBzfs_arc_p_min_shift\fR (int)
+.ad
+.RS 12n
+arc_c shift to calc min/max arc_p
+.sp
+Default value: \fB4\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_p_aggressive_disable\fR (int)
+.ad
+.RS 12n
+Disable aggressive arc_p growth
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR to disable.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_p_dampener_disable\fR (int)
+.ad
+.RS 12n
+Disable arc_p adapt dampener
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR to disable.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_shrink_shift\fR (int)
+.ad
+.RS 12n
+log2(fraction of arc to reclaim)
+.sp
+Default value: \fB5\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_arc_sys_free\fR (ulong)
+.ad
+.RS 12n
+The target number of bytes the ARC should leave as free memory on the system.
+Defaults to the larger of 1/64 of physical memory or 512K.  Setting this
+option to a non-zero value will override the default.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_autoimport_disable\fR (int)
+.ad
+.RS 12n
+Disable pool import at module load by ignoring the cache file (typically \fB/etc/zfs/zpool.cache\fR).
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR for no.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dbgmsg_enable\fR (int)
+.ad
+.RS 12n
+Internally ZFS keeps a small log to facilitate debugging.  By default the log
+is disabled, to enable it set this option to 1.  The contents of the log can
+be accessed by reading the /proc/spl/kstat/zfs/dbgmsg file.  Writing 0 to
+this proc file clears the log.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dbgmsg_maxsize\fR (int)
+.ad
+.RS 12n
+The maximum size in bytes of the internal ZFS debug log.
+.sp
+Default value: \fB4M\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dbuf_state_index\fR (int)
+.ad
+.RS 12n
+This feature is currently unused. It is normally used for controlling what
+reporting is available under /proc/spl/kstat/zfs.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_deadman_enabled\fR (int)
+.ad
+.RS 12n
+Enable deadman timer. See description below.
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR to disable.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_deadman_synctime_ms\fR (ulong)
+.ad
+.RS 12n
+Expiration time in milliseconds. This value has two meanings. First it is
+used to determine when the spa_deadman() logic should fire. By default the
+spa_deadman() will fire if spa_sync() has not completed in 1000 seconds.
+Secondly, the value determines if an I/O is considered "hung". Any I/O that
+has not completed in zfs_deadman_synctime_ms is considered "hung" resulting
+in a zevent being logged.
+.sp
+Default value: \fB1,000,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dedup_prefetch\fR (int)
+.ad
+.RS 12n
+Enable prefetching dedup-ed blks
+.sp
+Use \fB1\fR for yes and \fB0\fR to disable (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_delay_min_dirty_percent\fR (int)
+.ad
+.RS 12n
+Start to delay each transaction once there is this amount of dirty data,
+expressed as a percentage of \fBzfs_dirty_data_max\fR.
+This value should be >= zfs_vdev_async_write_active_max_dirty_percent.
+See the section "ZFS TRANSACTION DELAY".
+.sp
+Default value: \fB60\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_delay_scale\fR (int)
+.ad
+.RS 12n
+This controls how quickly the transaction delay approaches infinity.
+Larger values cause longer delays for a given amount of dirty data.
+.sp
+For the smoothest delay, this value should be about 1 billion divided
+by the maximum number of operations per second.  This will smoothly
+handle between 10x and 1/10th this number.
+.sp
+See the section "ZFS TRANSACTION DELAY".
+.sp
+Note: \fBzfs_delay_scale\fR * \fBzfs_dirty_data_max\fR must be < 2^64.
+.sp
+Default value: \fB500,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_delete_blocks\fR (ulong)
+.ad
+.RS 12n
+This is the used to define a large file for the purposes of delete.  Files
+containing more than \fBzfs_delete_blocks\fR will be deleted asynchronously
+while smaller files are deleted synchronously.  Decreasing this value will
+reduce the time spent in an unlink(2) system call at the expense of a longer
+delay before the freed space is available.
+.sp
+Default value: \fB20,480\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dirty_data_max\fR (int)
+.ad
+.RS 12n
+Determines the dirty space limit in bytes.  Once this limit is exceeded, new
+writes are halted until space frees up. This parameter takes precedence
+over \fBzfs_dirty_data_max_percent\fR.
+See the section "ZFS TRANSACTION DELAY".
+.sp
+Default value: 10 percent of all memory, capped at \fBzfs_dirty_data_max_max\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dirty_data_max_max\fR (int)
+.ad
+.RS 12n
+Maximum allowable value of \fBzfs_dirty_data_max\fR, expressed in bytes.
+This limit is only enforced at module load time, and will be ignored if
+\fBzfs_dirty_data_max\fR is later changed.  This parameter takes
+precedence over \fBzfs_dirty_data_max_max_percent\fR. See the section
+"ZFS TRANSACTION DELAY".
+.sp
+Default value: 25% of physical RAM.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dirty_data_max_max_percent\fR (int)
+.ad
+.RS 12n
+Maximum allowable value of \fBzfs_dirty_data_max\fR, expressed as a
+percentage of physical RAM.  This limit is only enforced at module load
+time, and will be ignored if \fBzfs_dirty_data_max\fR is later changed.
+The parameter \fBzfs_dirty_data_max_max\fR takes precedence over this
+one. See the section "ZFS TRANSACTION DELAY".
+.sp
+Default value: \fN25\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dirty_data_max_percent\fR (int)
+.ad
+.RS 12n
+Determines the dirty space limit, expressed as a percentage of all
+memory.  Once this limit is exceeded, new writes are halted until space frees
+up.  The parameter \fBzfs_dirty_data_max\fR takes precedence over this
+one.  See the section "ZFS TRANSACTION DELAY".
+.sp
+Default value: 10%, subject to \fBzfs_dirty_data_max_max\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_dirty_data_sync\fR (int)
+.ad
+.RS 12n
+Start syncing out a transaction group if there is at least this much dirty data.
+.sp
+Default value: \fB67,108,864\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_fletcher_4_impl\fR (string)
+.ad
+.RS 12n
+Select a fletcher 4 implementation.
+.sp
+Supported selectors are: \fBfastest\fR, \fBscalar\fR, \fBsse2\fR, \fBssse3\fR,
+\fBavx2\fR, \fBavx512f\fR, and \fBaarch64_neon\fR.
+All of the selectors except \fBfastest\fR and \fBscalar\fR require instruction
+set extensions to be available and will only appear if ZFS detects that they are
+present at runtime. If multiple implementations of fletcher 4 are available,
+the \fBfastest\fR will be chosen using a micro benchmark. Selecting \fBscalar\fR
+results in the original, CPU based calculation, being used. Selecting any option
+other than \fBfastest\fR and \fBscalar\fR results in vector instructions from
+the respective CPU instruction set being used.
+.sp
+Default value: \fBfastest\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_free_bpobj_enabled\fR (int)
+.ad
+.RS 12n
+Enable/disable the processing of the free_bpobj object.
+.sp
+Default value: \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_free_max_blocks\fR (ulong)
+.ad
+.RS 12n
+Maximum number of blocks freed in a single txg.
+.sp
+Default value: \fB100,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_async_read_max_active\fR (int)
+.ad
+.RS 12n
+Maximum asynchronous read I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB3\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_async_read_min_active\fR (int)
+.ad
+.RS 12n
+Minimum asynchronous read I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_async_write_active_max_dirty_percent\fR (int)
+.ad
+.RS 12n
+When the pool has more than
+\fBzfs_vdev_async_write_active_max_dirty_percent\fR dirty data, use
+\fBzfs_vdev_async_write_max_active\fR to limit active async writes.  If
+the dirty data is between min and max, the active I/O limit is linearly
+interpolated. See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB60\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_async_write_active_min_dirty_percent\fR (int)
+.ad
+.RS 12n
+When the pool has less than
+\fBzfs_vdev_async_write_active_min_dirty_percent\fR dirty data, use
+\fBzfs_vdev_async_write_min_active\fR to limit active async writes.  If
+the dirty data is between min and max, the active I/O limit is linearly
+interpolated. See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB30\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_async_write_max_active\fR (int)
+.ad
+.RS 12n
+Maximum asynchronous write I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB10\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_async_write_min_active\fR (int)
+.ad
+.RS 12n
+Minimum asynchronous write I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_max_active\fR (int)
+.ad
+.RS 12n
+The maximum number of I/Os active to each device.  Ideally, this will be >=
+the sum of each queue's max_active.  It must be at least the sum of each
+queue's min_active.  See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB1,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_scrub_max_active\fR (int)
+.ad
+.RS 12n
+Maximum scrub I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB2\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_scrub_min_active\fR (int)
+.ad
+.RS 12n
+Minimum scrub I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_sync_read_max_active\fR (int)
+.ad
+.RS 12n
+Maximum synchronous read I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB10\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_sync_read_min_active\fR (int)
+.ad
+.RS 12n
+Minimum synchronous read I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB10\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_sync_write_max_active\fR (int)
+.ad
+.RS 12n
+Maximum synchronous write I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB10\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_sync_write_min_active\fR (int)
+.ad
+.RS 12n
+Minimum synchronous write I/Os active to each device.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB10\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_queue_depth_pct\fR (int)
+.ad
+.RS 12n
+The queue depth percentage for each top-level virtual device.
+Used in conjunction with zfs_vdev_async_max_active.
+.sp
+Default value: \fB1000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_disable_dup_eviction\fR (int)
+.ad
+.RS 12n
+Disable duplicate buffer eviction
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_expire_snapshot\fR (int)
+.ad
+.RS 12n
+Seconds to expire .zfs/snapshot
+.sp
+Default value: \fB300\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_admin_snapshot\fR (int)
+.ad
+.RS 12n
+Allow the creation, removal, or renaming of entries in the .zfs/snapshot
+directory to cause the creation, destruction, or renaming of snapshots.
+When enabled this functionality works both locally and over NFS exports
+which have the 'no_root_squash' option set. This functionality is disabled
+by default.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_flags\fR (int)
+.ad
+.RS 12n
+Set additional debugging flags. The following flags may be bitwise-or'd
+together.
+.sp
+.TS
+box;
+rB lB
+lB lB
+r l.
+Value  Symbolic Name
+       Description
+_
+1      ZFS_DEBUG_DPRINTF
+       Enable dprintf entries in the debug log.
+_
+2      ZFS_DEBUG_DBUF_VERIFY *
+       Enable extra dbuf verifications.
+_
+4      ZFS_DEBUG_DNODE_VERIFY *
+       Enable extra dnode verifications.
+_
+8      ZFS_DEBUG_SNAPNAMES
+       Enable snapshot name verification.
+_
+16     ZFS_DEBUG_MODIFY
+       Check for illegally modified ARC buffers.
+_
+32     ZFS_DEBUG_SPA
+       Enable spa_dbgmsg entries in the debug log.
+_
+64     ZFS_DEBUG_ZIO_FREE
+       Enable verification of block frees.
+_
+128    ZFS_DEBUG_HISTOGRAM_VERIFY
+       Enable extra spacemap histogram verifications.
+.TE
+.sp
+* Requires debug build.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_free_leak_on_eio\fR (int)
+.ad
+.RS 12n
+If destroy encounters an EIO while reading metadata (e.g. indirect
+blocks), space referenced by the missing metadata can not be freed.
+Normally this causes the background destroy to become "stalled", as
+it is unable to make forward progress.  While in this stalled state,
+all remaining space to free from the error-encountering filesystem is
+"temporarily leaked".  Set this flag to cause it to ignore the EIO,
+permanently leak the space from indirect blocks that can not be read,
+and continue to free everything else that it can.
+
+The default, "stalling" behavior is useful if the storage partially
+fails (i.e. some but not all i/os fail), and then later recovers.  In
+this case, we will be able to continue pool operations while it is
+partially failed, and when it recovers, we can continue to free the
+space, with no leaks.  However, note that this case is actually
+fairly rare.
+
+Typically pools either (a) fail completely (but perhaps temporarily,
+e.g. a top-level vdev going offline), or (b) have localized,
+permanent errors (e.g. disk returns the wrong data due to bit flip or
+firmware bug).  In case (a), this setting does not matter because the
+pool will be suspended and the sync thread will not be able to make
+forward progress regardless.  In case (b), because the error is
+permanent, the best we can do is leak the minimum amount of space,
+which is what setting this flag will do.  Therefore, it is reasonable
+for this flag to normally be set, but we chose the more conservative
+approach of not setting it, so that there is no possibility of
+leaking space in the "partial temporary" failure case.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_free_min_time_ms\fR (int)
+.ad
+.RS 12n
+During a \fRzfs destroy\fB operation using \fRfeature@async_destroy\fB a minimum
+of this much time will be spent working on freeing blocks per txg.
+.sp
+Default value: \fB1,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_immediate_write_sz\fR (long)
+.ad
+.RS 12n
+Largest data block to write to zil. Larger blocks will be treated as if the
+dataset being written to had the property setting \fRlogbias=throughput\fB.
+.sp
+Default value: \fB32,768\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_max_recordsize\fR (int)
+.ad
+.RS 12n
+We currently support block sizes from 512 bytes to 16MB.  The benefits of
+larger blocks, and thus larger IO, need to be weighed against the cost of
+COWing a giant block to modify one byte.  Additionally, very large blocks
+can have an impact on i/o latency, and also potentially on the memory
+allocator.  Therefore, we do not allow the recordsize to be set larger than
+zfs_max_recordsize (default 1MB).  Larger blocks can be created by changing
+this tunable, and pools with larger blocks can always be imported and used,
+regardless of this setting.
+.sp
+Default value: \fB1,048,576\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_mdcomp_disable\fR (int)
+.ad
+.RS 12n
+Disable meta data compression
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_metaslab_fragmentation_threshold\fR (int)
+.ad
+.RS 12n
+Allow metaslabs to keep their active state as long as their fragmentation
+percentage is less than or equal to this value. An active metaslab that
+exceeds this threshold will no longer keep its active status allowing
+better metaslabs to be selected.
+.sp
+Default value: \fB70\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_mg_fragmentation_threshold\fR (int)
+.ad
+.RS 12n
+Metaslab groups are considered eligible for allocations if their
+fragmentation metric (measured as a percentage) is less than or equal to
+this value. If a metaslab group exceeds this threshold then it will be
+skipped unless all metaslab groups within the metaslab class have also
+crossed this threshold.
+.sp
+Default value: \fB85\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_mg_noalloc_threshold\fR (int)
+.ad
+.RS 12n
+Defines a threshold at which metaslab groups should be eligible for
+allocations.  The value is expressed as a percentage of free space
+beyond which a metaslab group is always eligible for allocations.
+If a metaslab group's free space is less than or equal to the
+threshold, the allocator will avoid allocating to that group
+unless all groups in the pool have reached the threshold.  Once all
+groups have reached the threshold, all groups are allowed to accept
+allocations.  The default value of 0 disables the feature and causes
+all metaslab groups to be eligible for allocations.
+
+This parameter allows to deal with pools having heavily imbalanced
+vdevs such as would be the case when a new vdev has been added.
+Setting the threshold to a non-zero percentage will stop allocations
+from being made to vdevs that aren't filled to the specified percentage
+and allow lesser filled vdevs to acquire more allocations than they
+otherwise would under the old \fBzfs_mg_alloc_failures\fR facility.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_no_scrub_io\fR (int)
+.ad
+.RS 12n
+Set for no scrub I/O. This results in scrubs not actually scrubbing data and
+simply doing a metadata crawl of the pool instead.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_no_scrub_prefetch\fR (int)
+.ad
+.RS 12n
+Set to disable block prefetching for scrubs.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_nocacheflush\fR (int)
+.ad
+.RS 12n
+Disable cache flush operations on disks when writing. Beware, this may cause
+corruption if disks re-order writes.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_nopwrite_enabled\fR (int)
+.ad
+.RS 12n
+Enable NOP writes
+.sp
+Use \fB1\fR for yes (default) and \fB0\fR to disable.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_pd_bytes_max\fR (int)
+.ad
+.RS 12n
+The number of bytes which should be prefetched during a pool traversal
+(eg: \fRzfs send\fB or other data crawling operations)
+.sp
+Default value: \fB52,428,800\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_prefetch_disable\fR (int)
+.ad
+.RS 12n
+This tunable disables predictive prefetch.  Note that it leaves "prescient"
+prefetch (e.g. prefetch for zfs send) intact.  Unlike predictive prefetch,
+prescient prefetch never issues i/os that end up not being needed, so it
+can't hurt performance.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_read_chunk_size\fR (long)
+.ad
+.RS 12n
+Bytes to read per chunk
+.sp
+Default value: \fB1,048,576\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_read_history\fR (int)
+.ad
+.RS 12n
+Historic statistics for the last N reads will be available in
+\fR/proc/spl/kstat/zfs/POOLNAME/reads\fB
+.sp
+Default value: \fB0\fR (no data is kept).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_read_history_hits\fR (int)
+.ad
+.RS 12n
+Include cache hits in read history
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_recover\fR (int)
+.ad
+.RS 12n
+Set to attempt to recover from fatal errors. This should only be used as a
+last resort, as it typically results in leaked space, or worse.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_resilver_delay\fR (int)
+.ad
+.RS 12n
+Number of ticks to delay prior to issuing a resilver I/O operation when
+a non-resilver or non-scrub I/O operation has occurred within the past
+\fBzfs_scan_idle\fR ticks.
+.sp
+Default value: \fB2\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_resilver_min_time_ms\fR (int)
+.ad
+.RS 12n
+Resilvers are processed by the sync thread. While resilvering it will spend
+at least this much time working on a resilver between txg flushes.
+.sp
+Default value: \fB3,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_scan_idle\fR (int)
+.ad
+.RS 12n
+Idle window in clock ticks.  During a scrub or a resilver, if
+a non-scrub or non-resilver I/O operation has occurred during this
+window, the next scrub or resilver operation is delayed by, respectively
+\fBzfs_scrub_delay\fR or \fBzfs_resilver_delay\fR ticks.
+.sp
+Default value: \fB50\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_scan_min_time_ms\fR (int)
+.ad
+.RS 12n
+Scrubs are processed by the sync thread. While scrubbing it will spend
+at least this much time working on a scrub between txg flushes.
+.sp
+Default value: \fB1,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_scrub_delay\fR (int)
+.ad
+.RS 12n
+Number of ticks to delay prior to issuing a scrub I/O operation when
+a non-scrub or non-resilver I/O operation has occurred within the past
+\fBzfs_scan_idle\fR ticks.
+.sp
+Default value: \fB4\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_send_corrupt_data\fR (int)
+.ad
+.RS 12n
+Allow sending of corrupt data (ignore read/checksum errors when sending data)
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_sync_pass_deferred_free\fR (int)
+.ad
+.RS 12n
+Flushing of data to disk is done in passes. Defer frees starting in this pass
+.sp
+Default value: \fB2\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_sync_pass_dont_compress\fR (int)
+.ad
+.RS 12n
+Don't compress starting in this pass
+.sp
+Default value: \fB5\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_sync_pass_rewrite\fR (int)
+.ad
+.RS 12n
+Rewrite new block pointers starting in this pass
+.sp
+Default value: \fB2\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_top_maxinflight\fR (int)
+.ad
+.RS 12n
+Max concurrent I/Os per top-level vdev (mirrors or raidz arrays) allowed during
+scrub or resilver operations.
+.sp
+Default value: \fB32\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_txg_history\fR (int)
+.ad
+.RS 12n
+Historic statistics for the last N txgs will be available in
+\fR/proc/spl/kstat/zfs/POOLNAME/txgs\fB
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_txg_timeout\fR (int)
+.ad
+.RS 12n
+Flush dirty data to disk at least every N seconds (maximum txg duration)
+.sp
+Default value: \fB5\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_aggregation_limit\fR (int)
+.ad
+.RS 12n
+Max vdev I/O aggregation size
+.sp
+Default value: \fB131,072\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_cache_bshift\fR (int)
+.ad
+.RS 12n
+Shift size to inflate reads too
+.sp
+Default value: \fB16\fR (effectively 65536).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_cache_max\fR (int)
+.ad
+.RS 12n
+Inflate reads small than this value to meet the \fBzfs_vdev_cache_bshift\fR
+size.
+.sp
+Default value: \fB16384\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_cache_size\fR (int)
+.ad
+.RS 12n
+Total size of the per-disk cache in bytes.
+.sp
+Currently this feature is disabled as it has been found to not be helpful
+for performance and in some cases harmful.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_mirror_rotating_inc\fR (int)
+.ad
+.RS 12n
+A number by which the balancing algorithm increments the load calculation for
+the purpose of selecting the least busy mirror member when an I/O immediately
+follows its predecessor on rotational vdevs for the purpose of making decisions
+based on load.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_mirror_rotating_seek_inc\fR (int)
+.ad
+.RS 12n
+A number by which the balancing algorithm increments the load calculation for
+the purpose of selecting the least busy mirror member when an I/O lacks
+locality as defined by the zfs_vdev_mirror_rotating_seek_offset.  I/Os within
+this that are not immediately following the previous I/O are incremented by
+half.
+.sp
+Default value: \fB5\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_mirror_rotating_seek_offset\fR (int)
+.ad
+.RS 12n
+The maximum distance for the last queued I/O in which the balancing algorithm
+considers an I/O to have locality.
+See the section "ZFS I/O SCHEDULER".
+.sp
+Default value: \fB1048576\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_mirror_non_rotating_inc\fR (int)
+.ad
+.RS 12n
+A number by which the balancing algorithm increments the load calculation for
+the purpose of selecting the least busy mirror member on non-rotational vdevs
+when I/Os do not immediately follow one another.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_mirror_non_rotating_seek_inc\fR (int)
+.ad
+.RS 12n
+A number by which the balancing algorithm increments the load calculation for
+the purpose of selecting the least busy mirror member when an I/O lacks
+locality as defined by the zfs_vdev_mirror_rotating_seek_offset. I/Os within
+this that are not immediately following the previous I/O are incremented by
+half.
+.sp
+Default value: \fB1\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_read_gap_limit\fR (int)
+.ad
+.RS 12n
+Aggregate read I/O operations if the gap on-disk between them is within this
+threshold.
+.sp
+Default value: \fB32,768\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_scheduler\fR (charp)
+.ad
+.RS 12n
+Set the Linux I/O scheduler on whole disk vdevs to this scheduler
+.sp
+Default value: \fBnoop\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_write_gap_limit\fR (int)
+.ad
+.RS 12n
+Aggregate write I/O over gap
+.sp
+Default value: \fB4,096\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_vdev_raidz_impl\fR (string)
+.ad
+.RS 12n
+Parameter for selecting raidz parity implementation to use.
+
+Options marked (always) below may be selected on module load as they are
+supported on all systems.
+The remaining options may only be set after the module is loaded, as they
+are available only if the implementations are compiled in and supported
+on the running system.
+
+Once the module is loaded, the content of
+/sys/module/zfs/parameters/zfs_vdev_raidz_impl will show available options
+with the currently selected one enclosed in [].
+Possible options are:
+  fastest  - (always) implementation selected using built-in benchmark
+  original - (always) original raidz implementation
+  scalar   - (always) scalar raidz implementation
+  sse2     - implementation using SSE2 instruction set (64bit x86 only)
+  ssse3    - implementation using SSSE3 instruction set (64bit x86 only)
+  avx2     - implementation using AVX2 instruction set (64bit x86 only)
+  aarch64_neon - implementation using NEON (Aarch64/64 bit ARMv8 only)
+  aarch64_neonx2 - implementation using NEON with more unrolling (Aarch64/64 bit ARMv8 only)
+.sp
+Default value: \fBfastest\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_zevent_cols\fR (int)
+.ad
+.RS 12n
+When zevents are logged to the console use this as the word wrap width.
+.sp
+Default value: \fB80\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_zevent_console\fR (int)
+.ad
+.RS 12n
+Log events to the console
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs_zevent_len_max\fR (int)
+.ad
+.RS 12n
+Max event queue length. A value of 0 will result in a calculated value which
+increases with the number of CPUs in the system (minimum 64 events). Events
+in the queue can be viewed with the \fBzpool events\fR command.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzil_replay_disable\fR (int)
+.ad
+.RS 12n
+Disable intent logging replay. Can be disabled for recovery from corrupted
+ZIL
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzil_slog_limit\fR (ulong)
+.ad
+.RS 12n
+Max commit bytes to separate log device
+.sp
+Default value: \fB1,048,576\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_delay_max\fR (int)
+.ad
+.RS 12n
+A zevent will be logged if a ZIO operation takes more than N milliseconds to
+complete. Note that this is only a logging facility, not a timeout on
+operations.
+.sp
+Default value: \fB30,000\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_dva_throttle_enabled\fR (int)
+.ad
+.RS 12n
+Throttle block allocations in the ZIO pipeline. This allows for
+dynamic allocation distribution when devices are imbalanced.
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_requeue_io_start_cut_in_line\fR (int)
+.ad
+.RS 12n
+Prioritize requeued I/O
+.sp
+Default value: \fB0\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzio_taskq_batch_pct\fR (uint)
+.ad
+.RS 12n
+Percentage of online CPUs (or CPU cores, etc) which will run a worker thread
+for IO. These workers are responsible for IO work such as compression and
+checksum calculations. Fractional number of CPUs will be rounded down.
+.sp
+The default value of 75 was chosen to avoid using all CPUs which can result in
+latency issues and inconsistent application performance, especially when high
+compression is enabled.
+.sp
+Default value: \fB75\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzvol_inhibit_dev\fR (uint)
+.ad
+.RS 12n
+Do not create zvol device nodes. This may slightly improve startup time on
+systems with a very large number of zvols.
+.sp
+Use \fB1\fR for yes and \fB0\fR for no (default).
+.RE
+
+.sp
+.ne 2
+.na
+\fBzvol_major\fR (uint)
+.ad
+.RS 12n
+Major number for zvol block devices
+.sp
+Default value: \fB230\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzvol_max_discard_blocks\fR (ulong)
+.ad
+.RS 12n
+Discard (aka TRIM) operations done on zvols will be done in batches of this
+many blocks, where block size is determined by the \fBvolblocksize\fR property
+of a zvol.
+.sp
+Default value: \fB16,384\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzvol_prefetch_bytes\fR (uint)
+.ad
+.RS 12n
+When adding a zvol to the system prefetch \fBzvol_prefetch_bytes\fR
+from the start and end of the volume.  Prefetching these regions
+of the volume is desirable because they are likely to be accessed
+immediately by \fBblkid(8)\fR or by the kernel scanning for a partition
+table.
+.sp
+Default value: \fB131,072\fR.
+.RE
+
+.SH ZFS I/O SCHEDULER
+ZFS issues I/O operations to leaf vdevs to satisfy and complete I/Os.
+The I/O scheduler determines when and in what order those operations are
+issued.  The I/O scheduler divides operations into five I/O classes
+prioritized in the following order: sync read, sync write, async read,
+async write, and scrub/resilver.  Each queue defines the minimum and
+maximum number of concurrent operations that may be issued to the
+device.  In addition, the device has an aggregate maximum,
+\fBzfs_vdev_max_active\fR. Note that the sum of the per-queue minimums
+must not exceed the aggregate maximum.  If the sum of the per-queue
+maximums exceeds the aggregate maximum, then the number of active I/Os
+may reach \fBzfs_vdev_max_active\fR, in which case no further I/Os will
+be issued regardless of whether all per-queue minimums have been met.
+.sp
+For many physical devices, throughput increases with the number of
+concurrent operations, but latency typically suffers. Further, physical
+devices typically have a limit at which more concurrent operations have no
+effect on throughput or can actually cause it to decrease.
+.sp
+The scheduler selects the next operation to issue by first looking for an
+I/O class whose minimum has not been satisfied. Once all are satisfied and
+the aggregate maximum has not been hit, the scheduler looks for classes
+whose maximum has not been satisfied. Iteration through the I/O classes is
+done in the order specified above. No further operations are issued if the
+aggregate maximum number of concurrent operations has been hit or if there
+are no operations queued for an I/O class that has not hit its maximum.
+Every time an I/O is queued or an operation completes, the I/O scheduler
+looks for new operations to issue.
+.sp
+In general, smaller max_active's will lead to lower latency of synchronous
+operations.  Larger max_active's may lead to higher overall throughput,
+depending on underlying storage.
+.sp
+The ratio of the queues' max_actives determines the balance of performance
+between reads, writes, and scrubs.  E.g., increasing
+\fBzfs_vdev_scrub_max_active\fR will cause the scrub or resilver to complete
+more quickly, but reads and writes to have higher latency and lower throughput.
+.sp
+All I/O classes have a fixed maximum number of outstanding operations
+except for the async write class. Asynchronous writes represent the data
+that is committed to stable storage during the syncing stage for
+transaction groups. Transaction groups enter the syncing state
+periodically so the number of queued async writes will quickly burst up
+and then bleed down to zero. Rather than servicing them as quickly as
+possible, the I/O scheduler changes the maximum number of active async
+write I/Os according to the amount of dirty data in the pool.  Since
+both throughput and latency typically increase with the number of
+concurrent operations issued to physical devices, reducing the
+burstiness in the number of concurrent operations also stabilizes the
+response time of operations from other -- and in particular synchronous
+-- queues. In broad strokes, the I/O scheduler will issue more
+concurrent operations from the async write queue as there's more dirty
+data in the pool.
+.sp
+Async Writes
+.sp
+The number of concurrent operations issued for the async write I/O class
+follows a piece-wise linear function defined by a few adjustable points.
+.nf
+
+       |              o---------| <-- zfs_vdev_async_write_max_active
+  ^    |             /^         |
+  |    |            / |         |
+active |           /  |         |
+ I/O   |          /   |         |
+count  |         /    |         |
+       |        /     |         |
+       |-------o      |         | <-- zfs_vdev_async_write_min_active
+      0|_______^______|_________|
+       0%      |      |       100% of zfs_dirty_data_max
+               |      |
+               |      `-- zfs_vdev_async_write_active_max_dirty_percent
+               `--------- zfs_vdev_async_write_active_min_dirty_percent
+
+.fi
+Until the amount of dirty data exceeds a minimum percentage of the dirty
+data allowed in the pool, the I/O scheduler will limit the number of
+concurrent operations to the minimum. As that threshold is crossed, the
+number of concurrent operations issued increases linearly to the maximum at
+the specified maximum percentage of the dirty data allowed in the pool.
+.sp
+Ideally, the amount of dirty data on a busy pool will stay in the sloped
+part of the function between \fBzfs_vdev_async_write_active_min_dirty_percent\fR
+and \fBzfs_vdev_async_write_active_max_dirty_percent\fR. If it exceeds the
+maximum percentage, this indicates that the rate of incoming data is
+greater than the rate that the backend storage can handle. In this case, we
+must further throttle incoming writes, as described in the next section.
+
+.SH ZFS TRANSACTION DELAY
+We delay transactions when we've determined that the backend storage
+isn't able to accommodate the rate of incoming writes.
+.sp
+If there is already a transaction waiting, we delay relative to when
+that transaction will finish waiting.  This way the calculated delay time
+is independent of the number of threads concurrently executing
+transactions.
+.sp
+If we are the only waiter, wait relative to when the transaction
+started, rather than the current time.  This credits the transaction for
+"time already served", e.g. reading indirect blocks.
+.sp
+The minimum time for a transaction to take is calculated as:
+.nf
+    min_time = zfs_delay_scale * (dirty - min) / (max - dirty)
+    min_time is then capped at 100 milliseconds.
+.fi
+.sp
+The delay has two degrees of freedom that can be adjusted via tunables.  The
+percentage of dirty data at which we start to delay is defined by
+\fBzfs_delay_min_dirty_percent\fR. This should typically be at or above
+\fBzfs_vdev_async_write_active_max_dirty_percent\fR so that we only start to
+delay after writing at full speed has failed to keep up with the incoming write
+rate. The scale of the curve is defined by \fBzfs_delay_scale\fR. Roughly speaking,
+this variable determines the amount of delay at the midpoint of the curve.
+.sp
+.nf
+delay
+ 10ms +-------------------------------------------------------------*+
+      |                                                             *|
+  9ms +                                                             *+
+      |                                                             *|
+  8ms +                                                             *+
+      |                                                            * |
+  7ms +                                                            * +
+      |                                                            * |
+  6ms +                                                            * +
+      |                                                            * |
+  5ms +                                                           *  +
+      |                                                           *  |
+  4ms +                                                           *  +
+      |                                                           *  |
+  3ms +                                                          *   +
+      |                                                          *   |
+  2ms +                                              (midpoint) *    +
+      |                                                  |    **     |
+  1ms +                                                  v ***       +
+      |             zfs_delay_scale ---------->     ********         |
+    0 +-------------------------------------*********----------------+
+      0%                    <- zfs_dirty_data_max ->               100%
+.fi
+.sp
+Note that since the delay is added to the outstanding time remaining on the
+most recent transaction, the delay is effectively the inverse of IOPS.
+Here the midpoint of 500us translates to 2000 IOPS. The shape of the curve
+was chosen such that small changes in the amount of accumulated dirty data
+in the first 3/4 of the curve yield relatively small differences in the
+amount of delay.
+.sp
+The effects can be easier to understand when the amount of delay is
+represented on a log scale:
+.sp
+.nf
+delay
+100ms +-------------------------------------------------------------++
+      +                                                              +
+      |                                                              |
+      +                                                             *+
+ 10ms +                                                             *+
+      +                                                           ** +
+      |                                              (midpoint)  **  |
+      +                                                  |     **    +
+  1ms +                                                  v ****      +
+      +             zfs_delay_scale ---------->        *****         +
+      |                                             ****             |
+      +                                          ****                +
+100us +                                        **                    +
+      +                                       *                      +
+      |                                      *                       |
+      +                                     *                        +
+ 10us +                                     *                        +
+      +                                                              +
+      |                                                              |
+      +                                                              +
+      +--------------------------------------------------------------+
+      0%                    <- zfs_dirty_data_max ->               100%
+.fi
+.sp
+Note here that only as the amount of dirty data approaches its limit does
+the delay start to increase rapidly. The goal of a properly tuned system
+should be to keep the amount of dirty data out of that range by first
+ensuring that the appropriate limits are set for the I/O scheduler to reach
+optimal throughput on the backend storage, and then by changing the value
+of \fBzfs_delay_scale\fR to increase the steepness of the curve.
diff --git a/zfs/man/man5/zpool-features.5 b/zfs/man/man5/zpool-features.5
new file mode 100644 (file)
index 0000000..ccc7ab4
--- /dev/null
@@ -0,0 +1,593 @@
+'\" te
+.\" Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+.\" Copyright (c) 2014, Joyent, Inc. All rights reserved.
+.\" 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]
+.TH ZPOOL-FEATURES 5 "Aug 27, 2013"
+.SH NAME
+zpool\-features \- ZFS pool feature descriptions
+.SH DESCRIPTION
+.sp
+.LP
+ZFS pool on\-disk format versions are specified via "features" which replace
+the old on\-disk format numbers (the last supported on\-disk format number is
+28). To enable a feature on a pool use the \fBupgrade\fR subcommand of the
+\fBzpool\fR(8) command, or set the \fBfeature@\fR\fIfeature_name\fR property
+to \fBenabled\fR.
+.sp
+.LP
+The pool format does not affect file system version compatibility or the ability
+to send file systems between pools.
+.sp
+.LP
+Since most features can be enabled independently of each other the on\-disk
+format of the pool is specified by the set of all features marked as
+\fBactive\fR on the pool. If the pool was created by another software version
+this set may include unsupported features.
+.SS "Identifying features"
+.sp
+.LP
+Every feature has a guid of the form \fIcom.example:feature_name\fR. The reverse
+DNS name ensures that the feature's guid is unique across all ZFS
+implementations. When unsupported features are encountered on a pool they will
+be identified by their guids. Refer to the documentation for the ZFS
+implementation that created the pool for information about those features.
+.sp
+.LP
+Each supported feature also has a short name. By convention a feature's short
+name is the portion of its guid which follows the ':' (e.g.
+\fIcom.example:feature_name\fR would have the short name \fIfeature_name\fR),
+however a feature's short name may differ across ZFS implementations if
+following the convention would result in name conflicts.
+.SS "Feature states"
+.sp
+.LP
+Features can be in one of three states:
+.sp
+.ne 2
+.na
+\fB\fBactive\fR\fR
+.ad
+.RS 12n
+This feature's on\-disk format changes are in effect on the pool. Support for
+this feature is required to import the pool in read\-write mode. If this
+feature is not read-only compatible, support is also required to import the pool
+in read\-only mode (see "Read\-only compatibility").
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBenabled\fR\fR
+.ad
+.RS 12n
+An administrator has marked this feature as enabled on the pool, but the
+feature's on\-disk format changes have not been made yet. The pool can still be
+imported by software that does not support this feature, but changes may be made
+to the on\-disk format at any time which will move the feature to the
+\fBactive\fR state. Some features may support returning to the \fBenabled\fR
+state after becoming \fBactive\fR. See feature\-specific documentation for
+details.
+.RE
+
+.sp
+.ne 2
+.na
+\fBdisabled\fR
+.ad
+.RS 12n
+This feature's on\-disk format changes have not been made and will not be made
+unless an administrator moves the feature to the \fBenabled\fR state. Features
+cannot be disabled once they have been enabled.
+.RE
+
+.sp
+.LP
+The state of supported features is exposed through pool properties of the form
+\fIfeature@short_name\fR.
+.SS "Read\-only compatibility"
+.sp
+.LP
+Some features may make on\-disk format changes that do not interfere with other
+software's ability to read from the pool. These features are referred to as
+"read\-only compatible". If all unsupported features on a pool are read\-only
+compatible, the pool can be imported in read\-only mode by setting the
+\fBreadonly\fR property during import (see \fBzpool\fR(8) for details on
+importing pools).
+.SS "Unsupported features"
+.sp
+.LP
+For each unsupported feature enabled on an imported pool a pool property
+named \fIunsupported@feature_guid\fR will indicate why the import was allowed
+despite the unsupported feature. Possible values for this property are:
+
+.sp
+.ne 2
+.na
+\fB\fBinactive\fR\fR
+.ad
+.RS 12n
+The feature is in the \fBenabled\fR state and therefore the pool's on\-disk
+format is still compatible with software that does not support this feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBreadonly\fR\fR
+.ad
+.RS 12n
+The feature is read\-only compatible and the pool has been imported in
+read\-only mode.
+.RE
+
+.SS "Feature dependencies"
+.sp
+.LP
+Some features depend on other features being enabled in order to function
+properly. Enabling a feature will automatically enable any features it
+depends on.
+.SH FEATURES
+.sp
+.LP
+The following features are supported on this system:
+.sp
+.ne 2
+.na
+\fB\fBasync_destroy\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.delphix:async_destroy
+READ\-ONLY COMPATIBLE  yes
+DEPENDENCIES   none
+.TE
+
+Destroying a file system requires traversing all of its data in order to
+return its used space to the pool. Without \fBasync_destroy\fR the file system
+is not fully removed until all space has been reclaimed. If the destroy
+operation is interrupted by a reboot or power outage the next attempt to open
+the pool will need to complete the destroy operation synchronously.
+
+When \fBasync_destroy\fR is enabled the file system's data will be reclaimed
+by a background process, allowing the destroy operation to complete without
+traversing the entire file system. The background process is able to resume
+interrupted destroys after the pool has been opened, eliminating the need
+to finish interrupted destroys as part of the open operation. The amount
+of space remaining to be reclaimed by the background process is available
+through the \fBfreeing\fR property.
+
+This feature is only \fBactive\fR while \fBfreeing\fR is non\-zero.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBempty_bpobj\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.delphix:empty_bpobj
+READ\-ONLY COMPATIBLE  yes
+DEPENDENCIES   none
+.TE
+
+This feature increases the performance of creating and using a large
+number of snapshots of a single filesystem or volume, and also reduces
+the disk space required.
+
+When there are many snapshots, each snapshot uses many Block Pointer
+Objects (bpobj's) to track blocks associated with that snapshot.
+However, in common use cases, most of these bpobj's are empty.  This
+feature allows us to create each bpobj on-demand, thus eliminating the
+empty bpobjs.
+
+This feature is \fBactive\fR while there are any filesystems, volumes,
+or snapshots which were created after enabling this feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfilesystem_limits\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.joyent:filesystem_limits
+READ\-ONLY COMPATIBLE  yes
+DEPENDENCIES   extensible_dataset
+.TE
+
+This feature enables filesystem and snapshot limits. These limits can be used
+to control how many filesystems and/or snapshots can be created at the point in
+the tree on which the limits are set.
+
+This feature is \fBactive\fR once either of the limit properties has been
+set on a dataset. Once activated the feature is never deactivated.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlz4_compress\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   org.illumos:lz4_compress
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   none
+.TE
+
+\fBlz4\fR is a high-performance real-time compression algorithm that
+features significantly faster compression and decompression as well as a
+higher compression ratio than the older \fBlzjb\fR compression.
+Typically, \fBlz4\fR compression is approximately 50% faster on
+compressible data and 200% faster on incompressible data than
+\fBlzjb\fR. It is also approximately 80% faster on decompression, while
+giving approximately 10% better compression ratio.
+
+When the \fBlz4_compress\fR feature is set to \fBenabled\fR, the
+administrator can turn on \fBlz4\fR compression on any dataset on the
+pool using the \fBzfs\fR(8) command. Please note that doing so will
+immediately activate the \fBlz4_compress\fR feature on the underlying
+pool using the \fBzfs\fR(1M) command. Also, all newly written metadata
+will be compressed with \fBlz4\fR algorithm. Since this feature is not
+read-only compatible, this operation will render the pool unimportable
+on systems without support for the \fBlz4_compress\fR feature. Booting
+off of \fBlz4\fR-compressed root pools is supported.
+
+This feature becomes \fBactive\fR as soon as it is enabled and will
+never return to being \fBenabled\fB.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBspacemap_histogram\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.delphix:spacemap_histogram
+READ\-ONLY COMPATIBLE  yes
+DEPENDENCIES   none
+.TE
+
+This features allows ZFS to maintain more information about how free space
+is organized within the pool. If this feature is \fBenabled\fR, ZFS will
+set this feature to \fBactive\fR when a new space map object is created or
+an existing space map is upgraded to the new format. Once the feature is
+\fBactive\fR, it will remain in that state until the pool is destroyed.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBextensible_dataset\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.delphix:extensible_dataset
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   none
+.TE
+
+This feature allows more flexible use of internal ZFS data structures,
+and exists for other features to depend on.
+
+This feature will be \fBactive\fR when the first dependent feature uses it,
+and will be returned to the \fBenabled\fR state when all datasets that use
+this feature are destroyed.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBbookmarks\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.delphix:bookmarks
+READ\-ONLY COMPATIBLE  yes
+DEPENDENCIES   extensible_dataset
+.TE
+
+This feature enables use of the \fBzfs bookmark\fR subcommand.
+
+This feature is \fBactive\fR while any bookmarks exist in the pool.
+All bookmarks in the pool can be listed by running
+\fBzfs list -t bookmark -r \fIpoolname\fR\fR.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBenabled_txg\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.delphix:enabled_txg
+READ\-ONLY COMPATIBLE  yes
+DEPENDENCIES   none
+.TE
+
+Once this feature is enabled ZFS records the transaction group number
+in which new features are enabled. This has no user-visible impact,
+but other features may depend on this feature.
+
+This feature becomes \fBactive\fR as soon as it is enabled and will
+never return to being \fBenabled\fB.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBhole_birth\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.delphix:hole_birth
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   enabled_txg
+.TE
+
+This feature improves performance of incremental sends ("zfs send -i")
+and receives for objects with many holes. The most common case of
+hole-filled objects is zvols.
+
+An incremental send stream from snapshot \fBA\fR to snapshot \fBB\fR
+contains information about every block that changed between \fBA\fR and
+\fBB\fR. Blocks which did not change between those snapshots can be
+identified and omitted from the stream using a piece of metadata called
+the 'block birth time', but birth times are not recorded for holes (blocks
+filled only with zeroes). Since holes created after \fBA\fR cannot be
+distinguished from holes created before \fBA\fR, information about every
+hole in the entire filesystem or zvol is included in the send stream.
+
+For workloads where holes are rare this is not a problem. However, when
+incrementally replicating filesystems or zvols with many holes (for
+example a zvol formatted with another filesystem) a lot of time will
+be spent sending and receiving unnecessary information about holes that
+already exist on the receiving side.
+
+Once the \fBhole_birth\fR feature has been enabled the block birth times
+of all new holes will be recorded. Incremental sends between snapshots
+created after this feature is enabled will use this new metadata to avoid
+sending information about holes that already exist on the receiving side.
+
+This feature becomes \fBactive\fR as soon as it is enabled and will
+never return to being \fBenabled\fB.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBembedded_data\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   com.delphix:embedded_data
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   none
+.TE
+
+This feature improves the performance and compression ratio of
+highly-compressible blocks.  Blocks whose contents can compress to 112 bytes
+or smaller can take advantage of this feature.
+
+When this feature is enabled, the contents of highly-compressible blocks are
+stored in the block "pointer" itself (a misnomer in this case, as it contains
+the compressed data, rather than a pointer to its location on disk).  Thus
+the space of the block (one sector, typically 512 bytes or 4KB) is saved,
+and no additional i/o is needed to read and write the data block.
+
+This feature becomes \fBactive\fR as soon as it is enabled and will
+never return to being \fBenabled\fR.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlarge_blocks\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   org.open-zfs:large_block
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   extensible_dataset
+.TE
+
+The \fBlarge_block\fR feature allows the record size on a dataset to be
+set larger than 128KB.
+
+This feature becomes \fBactive\fR once a \fBrecordsize\fR property has been
+set larger than 128KB, and will return to being \fBenabled\fR once all
+filesystems that have ever had their recordsize larger than 128KB are destroyed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlarge_dnode\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   org.zfsonlinux:large_dnode
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   extensible_dataset
+.TE
+
+The \fBlarge_dnode\fR feature allows the size of dnodes in a dataset to be
+set larger than 512B.
+
+This feature becomes \fBactive\fR once a dataset contains an object with
+a dnode larger than 512B, which occurs as a result of setting the
+\fBdnodesize\fR dataset property to a value other than \fBlegacy\fR. The
+feature will return to being \fBenabled\fR once all filesystems that
+have ever contained a dnode larger than 512B are destroyed. Large dnodes
+allow more data to be stored in the bonus buffer, thus potentially
+improving performance by avoiding the use of spill blocks.
+.RE
+
+\fB\fBsha512\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   org.illumos:sha512
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   extensible_dataset
+.TE
+
+This feature enables the use of the SHA-512/256 truncated hash algorithm
+(FIPS 180-4) for checksum and dedup. The native 64-bit arithmetic of
+SHA-512 provides an approximate 50% performance boost over SHA-256 on
+64-bit hardware and is thus a good minimum-change replacement candidate
+for systems where hash performance is important, but these systems
+cannot for whatever reason utilize the faster \fBskein\fR and
+\fBedonr\fR algorithms.
+
+When the \fBsha512\fR feature is set to \fBenabled\fR, the administrator
+can turn on the \fBsha512\fR checksum on any dataset using the
+\fBzfs set checksum=sha512\fR(1M) command.  This feature becomes
+\fBactive\fR once a \fBchecksum\fR property has been set to \fBsha512\fR,
+and will return to being \fBenabled\fR once all filesystems that have
+ever had their checksum set to \fBsha512\fR are destroyed.
+
+Booting off of pools utilizing SHA-512/256 is supported (provided that
+the updated GRUB stage2 module is installed).
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBskein\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   org.illumos:skein
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   extensible_dataset
+.TE
+
+This feature enables the use of the Skein hash algorithm for checksum
+and dedup. Skein is a high-performance secure hash algorithm that was a
+finalist in the NIST SHA-3 competition. It provides a very high security
+margin and high performance on 64-bit hardware (80% faster than
+SHA-256). This implementation also utilizes the new salted checksumming
+functionality in ZFS, which means that the checksum is pre-seeded with a
+secret 256-bit random key (stored on the pool) before being fed the data
+block to be checksummed. Thus the produced checksums are unique to a
+given pool, preventing hash collision attacks on systems with dedup.
+
+When the \fBskein\fR feature is set to \fBenabled\fR, the administrator
+can turn on the \fBskein\fR checksum on any dataset using the
+\fBzfs set checksum=skein\fR(1M) command.  This feature becomes
+\fBactive\fR once a \fBchecksum\fR property has been set to \fBskein\fR,
+and will return to being \fBenabled\fR once all filesystems that have
+ever had their checksum set to \fBskein\fR are destroyed.
+
+Booting off of pools using \fBskein\fR is \fBNOT\fR supported
+-- any attempt to enable \fBskein\fR on a root pool will fail with an
+error.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBedonr\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   org.illumos:edonr
+READ\-ONLY COMPATIBLE  no
+DEPENDENCIES   extensible_dataset
+.TE
+
+This feature enables the use of the Edon-R hash algorithm for checksum,
+including for nopwrite (if compression is also enabled, an overwrite of
+a block whose checksum matches the data being written will be ignored).
+In an abundance of caution, Edon-R can not be used with dedup
+(without verification).
+
+Edon-R is a very high-performance hash algorithm that was part
+of the NIST SHA-3 competition. It provides extremely high hash
+performance (over 350% faster than SHA-256), but was not selected
+because of its unsuitability as a general purpose secure hash algorithm.
+This implementation utilizes the new salted checksumming functionality
+in ZFS, which means that the checksum is pre-seeded with a secret
+256-bit random key (stored on the pool) before being fed the data block
+to be checksummed. Thus the produced checksums are unique to a given
+pool.
+
+When the \fBedonr\fR feature is set to \fBenabled\fR, the administrator
+can turn on the \fBedonr\fR checksum on any dataset using the
+\fBzfs set checksum=edonr\fR(1M) command.  This feature becomes
+\fBactive\fR once a \fBchecksum\fR property has been set to \fBedonr\fR,
+and will return to being \fBenabled\fR once all filesystems that have
+ever had their checksum set to \fBedonr\fR are destroyed.
+
+Booting off of pools using \fBedonr\fR is \fBNOT\fR supported
+-- any attempt to enable \fBedonr\fR on a root pool will fail with an
+error.
+
+.sp
+.ne 2
+.na
+\fB\fBuserobj_accounting\fR\fR
+.ad
+.RS 4n
+.TS
+l l .
+GUID   org.zfsonlinux:userobj_accounting
+READ\-ONLY COMPATIBLE  yes
+DEPENDENCIES   extensible_dataset
+.TE
+
+This feature allows administrators to account the object usage information
+by user and group.
+
+This feature becomes \fBactive\fR as soon as it is enabled and will never
+return to being \fBenabled\fR. Each filesystem will be upgraded automatically
+when remounted, or when new files are created under that filesystem.
+The upgrade can also be started manually on filesystems by running
+`zfs set version=current <pool/fs>`. The upgrade process runs in the background
+and may take a while to complete for filesystems containing a large number of
+files.
+
+.RE
+
+.SH "SEE ALSO"
+\fBzpool\fR(8)
diff --git a/zfs/man/man8/Makefile.am b/zfs/man/man8/Makefile.am
new file mode 100644 (file)
index 0000000..b89e34d
--- /dev/null
@@ -0,0 +1,35 @@
+dist_man_MANS = \
+       fsck.zfs.8 \
+       mount.zfs.8 \
+       vdev_id.8 \
+       zdb.8 \
+       zfs.8 \
+       zinject.8 \
+       zpool.8 \
+       zstreamdump.8
+
+nodist_man_MANS = \
+       zed.8
+
+EXTRA_DIST = \
+       zed.8.in
+
+zed.8: $(srcdir)/zed.8.in
+
+do_subst = $(SED) \
+       -e 's|@libexecdir[@]|$(libexecdir)|g' \
+       -e 's|@runstatedir[@]|$(runstatedir)|g' \
+       -e 's|@sysconfdir[@]|$(sysconfdir)|g'
+
+$(nodist_man_MANS): Makefile
+       $(RM) $@ $@.tmp
+       srcdir=''; \
+         test -f ./$@.in || srcdir=$(srcdir)/; \
+         $(do_subst) $${srcdir}$@.in >$@.tmp
+       mv $@.tmp $@
+
+install-data-local:
+       $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man8"
+
+CLEANFILES = \
+       $(nodist_man_MANS)
diff --git a/zfs/man/man8/Makefile.in b/zfs/man/man8/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/man/man8/fsck.zfs.8 b/zfs/man/man8/fsck.zfs.8
new file mode 100644 (file)
index 0000000..baa8c33
--- /dev/null
@@ -0,0 +1,67 @@
+'\" t
+.\"
+.\" 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 2013 Darik Horn <dajhorn@vanadac.com>. All rights reserved.
+.\"
+.TH fsck.zfs 8 "2013 MAR 16" "ZFS on Linux" "System Administration Commands"
+
+.SH NAME
+fsck.zfs \- Dummy ZFS filesystem checker.
+
+.SH SYNOPSIS
+.LP
+.BI "fsck.zfs [" "options" "] <" "dataset" ">"
+
+.SH DESCRIPTION
+.LP
+\fBfsck.zfs\fR is a shell stub that does nothing and always returns
+true. It is installed by ZoL because some Linux distributions expect
+a fsck helper for all filesystems.
+
+.SH OPTIONS
+.HP
+All \fIoptions\fR and the \fIdataset\fR are ignored.
+
+.SH "NOTES"
+.LP
+ZFS datasets are checked by running \fBzpool scrub\fR on the
+containing pool. An individual ZFS dataset is never checked
+independently of its pool, which is unlike a regular filesystem.
+
+.SH "BUGS"
+.LP
+On some systems, if the \fIdataset\fR is in a degraded pool, then it
+might be appropriate for \fBfsck.zfs\fR to return exit code 4 to
+indicate an uncorrected filesystem error.
+.LP
+Similarly, if the \fIdataset\fR is in a faulted pool and has a legacy
+/etc/fstab record, then \fBfsck.zfs\fR should return exit code 8 to
+indicate a fatal operational error.
+
+.SH "AUTHORS"
+.LP
+Darik Horn <dajhorn@vanadac.com>.
+
+.SH "SEE ALSO"
+.BR fsck (8),
+.BR fstab (5),
+.BR zpool (8)
diff --git a/zfs/man/man8/mount.zfs.8 b/zfs/man/man8/mount.zfs.8
new file mode 100644 (file)
index 0000000..4b71367
--- /dev/null
@@ -0,0 +1,144 @@
+'\" t
+.\"
+.\" 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 2013 Darik Horn <dajhorn@vanadac.com>. All rights reserved.
+.\"
+.TH mount.zfs 8 "2013 FEB 28" "ZFS on Linux" "System Administration Commands"
+
+.SH NAME
+mount.zfs \- mount a ZFS filesystem
+.SH SYNOPSIS
+.LP
+.BI "mount.zfs [\-sfnvh] [\-o " options "]" " dataset mountpoint
+
+.SH DESCRIPTION
+.BR mount.zfs
+is part of the zfsutils package for Linux. It is a helper program that
+is usually invoked by the
+.BR mount (8)
+or
+.BR zfs (8)
+commands to mount a ZFS dataset.
+
+All
+.I options
+are handled according to the FILESYSTEM INDEPENDENT MOUNT OPTIONS
+section in the
+.BR mount (8)
+manual, except for those described below.
+
+The
+.I dataset
+parameter is a ZFS filesystem name, as output by the
+.B "zfs list -H -o name
+command. This parameter never has a leading slash character and is
+not a device name.
+
+The
+.I mountpoint
+parameter is the path name of a directory.
+
+
+.SH OPTIONS
+.TP
+.BI "\-s"
+Ignore bad or sloppy mount options.
+.TP
+.BI "\-f"
+Do a fake mount; do not perform the mount operation.
+.TP
+.BI "\-n"
+Do not update the /etc/mtab file.
+.TP
+.BI "\-v"
+Increase verbosity.
+.TP
+.BI "\-h"
+Print the usage message.
+.TP
+.BI "\-o context"
+This flag sets the SELinux context for all files in the filesystem
+under that mountpoint.
+.TP
+.BI "\-o fscontext"
+This flag sets the SELinux context for the filesystem being mounted.
+.TP
+.BI "\-o defcontext"
+This flag sets the SELinux context for unlabeled files.
+.TP
+.BI "\-o rootcontext"
+This flag sets the SELinux context for the root inode of the filesystem.
+.TP
+.BI "\-o legacy"
+This private flag indicates that the
+.I dataset
+has an entry in the /etc/fstab file.
+.TP
+.BI "\-o noxattr"
+This private flag disables extended attributes.
+.TP
+.BI "\-o xattr
+This private flag enables directory-based extended attributes and, if
+appropriate, adds a ZFS context to the selinux system policy.
+.TP
+.BI "\-o saxattr
+This private flag enables system attributed-based extended attributes and, if
+appropriate, adds a ZFS context to the selinux system policy.
+.TP
+.BI "\-o dirxattr
+Equivalent to
+.BR xattr .
+.TP
+.BI "\-o zfsutil"
+This private flag indicates that
+.BR mount (8)
+is being called by the
+.BR zfs (8)
+command.
+
+.SH NOTES
+ZFS conventionally requires that the
+.I mountpoint
+be an empty directory, but the Linux implementation inconsistently
+enforces the requirement.
+
+The
+.BR mount.zfs
+helper does not mount the contents of zvols.
+
+.SH FILES
+.TP 18n
+.I /etc/fstab
+The static filesystem table.
+.TP
+.I /etc/mtab
+The mounted filesystem table.
+.SH "AUTHORS"
+The primary author of
+.BR mount.zfs
+is Brian Behlendorf <behlendorf1@llnl.gov>.
+
+This man page was written by Darik Horn <dajhorn@vanadac.com>.
+.SH "SEE ALSO"
+.BR fstab (5),
+.BR mount (8),
+.BR zfs (8)
diff --git a/zfs/man/man8/vdev_id.8 b/zfs/man/man8/vdev_id.8
new file mode 100644 (file)
index 0000000..70956c6
--- /dev/null
@@ -0,0 +1,77 @@
+.TH vdev_id 8
+.SH NAME
+vdev_id \- generate user-friendly names for JBOD disks
+.SH SYNOPSIS
+.LP
+.nf
+\fBvdev_id\fR <-d dev> [-c config_file] [-g sas_direct|sas_switch]
+                 [-m] [-p phys_per_port]
+\fBvdev_id\fR -h
+.fi
+.SH DESCRIPTION
+The \fBvdev_id\fR command is a udev helper which parses the file
+.BR /etc/zfs/vdev_id.conf (5)
+to map a physical path in a storage topology to a channel name.  The
+channel name is combined with a disk enclosure slot number to create an
+alias that reflects the physical location of the drive.  This is
+particularly helpful when it comes to tasks like replacing failed
+drives.  Slot numbers may also be re-mapped in case the default
+numbering is unsatisfactory.  The drive aliases will be created as
+symbolic links in /dev/disk/by-vdev.
+
+The currently supported topologies are sas_direct and sas_switch.  A
+multipath mode is supported in which dm-mpath devices are handled by
+examining the first-listed running component disk as reported by the
+.BR multipath (8)
+command.  In multipath mode the configuration file should contain a
+channel definition with the same name for each path to a given
+enclosure.
+
+.BR vdev_id
+also supports creating aliases based on existing udev links in the /dev
+hierarchy using the \fIalias\fR configuration file keyword.  See the
+.BR vdev_id.conf (5)
+man page for details.
+
+.SH OPTIONS
+.TP
+\fB\-c\fR <config_file>
+Specifies the path to an alternate configuration file.  The default is
+/etc/zfs/vdev_id.conf.
+.TP
+\fB\-d\fR <device>
+This is the only mandatory argument.  Specifies the name of a device
+in /dev, i.e. "sda".
+.TP
+\fB\-g\fR <sas_direct|sas_switch>
+Identifies a physical topology that governs how physical paths are
+mapped to channels.
+
+\fIsas_direct\fR - in this mode a channel is uniquely identified by
+a PCI slot and a HBA port number
+
+\fIsas_switch\fR - in this mode a channel is uniquely identified by
+a SAS switch port number
+.TP
+\fB\-m\fR
+Specifies that
+.BR vdev_id (8)
+will handle only dm-multipath devices.  If set to "yes" then
+.BR vdev_id (8)
+will examine the first running component disk of a dm-multipath
+device as listed by the
+.BR multipath (8)
+command to determine the physical path.
+.TP
+\fB\-p\fR <phys_per_port>
+Specifies the number of PHY devices associated with a SAS HBA port or SAS
+switch port.
+.BR vdev_id (8)
+internally uses this value to determine which HBA or switch port a
+device is connected to.  The default is 4.
+.TP
+\fB\-h\fR
+Print a usage summary.
+.SH SEE ALSO
+.LP
+\fBvdev_id.conf\fR(5)
diff --git a/zfs/man/man8/zdb.8 b/zfs/man/man8/zdb.8
new file mode 100644 (file)
index 0000000..efa1f41
--- /dev/null
@@ -0,0 +1,554 @@
+'\" t
+.\"
+.\" 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 2012, Richard Lowe.
+.\" Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+.\"
+.TH "ZDB" "8" "February 15, 2012" "" ""
+
+.SH "NAME"
+\fBzdb\fR - Display zpool debugging and consistency information
+
+.SH "SYNOPSIS"
+\fBzdb\fR [-CumdibcsDvhLMXFPA] [-e [-p \fIpath\fR...]] [-t \fItxg\fR]
+    [-U \fIcache\fR] [-I \fIinflight I/Os\fR] [-x \fIdumpdir\fR]
+    [\fIpoolname\fR [\fIobject\fR ...]]
+
+.P
+\fBzdb\fR [-divPA] [-e [-p \fIpath\fR...]] [-U \fIcache\fR]
+    \fIdataset\fR [\fIobject\fR ...]
+
+.P
+\fBzdb\fR -m [-MLXFPA] [-t \fItxg\fR] [-e [-p \fIpath\fR...]] [-U \fIcache\fR]
+    \fIpoolname\fR [\fIvdev\fR [\fImetaslab\fR ...]]
+
+.P
+\fBzdb\fR -R [-A] [-e [-p \fIpath\fR...]] [-U \fIcache\fR] \fIpoolname\fR
+    \fIvdev\fR:\fIoffset\fR:\fIsize\fR[:\fIflags\fR]
+
+.P
+\fBzdb\fR -S [-AP] [-e [-p \fIpath\fR...]] [-U \fIcache\fR] \fIpoolname\fR
+
+.P
+\fBzdb\fR -l [-uA] \fIdevice\fR
+
+.P
+\fBzdb\fR -C [-A] [-U \fIcache\fR]
+
+.SH "DESCRIPTION"
+The \fBzdb\fR utility displays information about a ZFS pool useful for
+debugging and performs some amount of consistency checking. It is a not a
+general purpose tool and options (and facilities) may change. This is neither
+a fsck(8) nor an fsdb(8) utility.
+
+.P
+The output of this command in general reflects the on-disk structure of a ZFS
+pool, and is inherently unstable. The precise output of most invocations is
+not documented, a knowledge of ZFS internals is assumed.
+
+.P
+If the \fIdataset\fR argument does not contain any \fB/\fR or \fB@\fR
+characters, it is interpreted as a pool name.  The root dataset can be
+specified as \fIpool\fB/\fR (pool name followed by a slash).
+
+.P
+When operating on an imported and active pool it is possible, though unlikely,
+that zdb may interpret inconsistent pool data and behave erratically.
+
+.SH "OPTIONS"
+Display options:
+
+.sp
+.ne 2
+.na
+\fB-b\fR
+.ad
+.sp .6
+.RS 4n
+Display statistics regarding the number, size (logical, physical and
+allocated) and deduplication of blocks.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-c\fR
+.ad
+.sp .6
+.RS 4n
+Verify the checksum of all metadata blocks while printing block statistics
+(see \fB-b\fR).
+.sp
+If specified multiple times, verify the checksums of all blocks.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-C\fR
+.ad
+.sp .6
+.RS 4n
+Display information about the configuration. If specified with no other
+options, instead display information about the cache file
+(\fB/etc/zfs/zpool.cache\fR). To specify the cache file to display, see
+\fB-U\fR.
+.P
+If specified multiple times, and a pool name is also specified display both
+the cached configuration and the on-disk configuration.  If specified multiple
+times with \fB-e\fR also display the configuration that would be used were the
+pool to be imported.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-d\fR
+.ad
+.sp .6
+.RS 4n
+Display information about datasets. Specified once, displays basic dataset
+information: ID, create transaction, size, and object count.
+.sp
+If specified multiple times provides greater and greater verbosity.
+.sp
+If object IDs are specified, display information about those specific objects only.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-D\fR
+.ad
+.sp .6
+.RS 4n
+Display deduplication statistics, including the deduplication ratio (dedup),
+compression ratio (compress), inflation due to the zfs copies property
+(copies), and an overall effective ratio (dedup * compress / copies).
+.sp
+If specified twice, display a histogram of deduplication statistics, showing
+the allocated (physically present on disk) and referenced (logically
+referenced in the pool) block counts and sizes by reference count.
+.sp
+If specified a third time, display the statistics independently for each deduplication table.
+.sp
+If specified a fourth time, dump the contents of the deduplication tables describing duplicate blocks.
+.sp
+If specified a fifth time, also dump the contents of the deduplication tables describing unique blocks.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-h\fR
+.ad
+.sp .6
+.RS 4n
+Display pool history similar to \fBzpool history\fR, but include internal
+changes, transaction, and dataset information.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-i\fR
+.ad
+.sp .6
+.RS 4n
+Display information about intent log (ZIL) entries relating to each
+dataset. If specified multiple times, display counts of each intent log
+transaction type.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-l\fR \fIdevice\fR
+.ad
+.sp .6
+.RS 4n
+Display the vdev labels from the specified device. If the \fB-u\fR option is
+also specified, also display the uberblocks on this device.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-L\fR
+.ad
+.sp .6
+.RS 4n
+Disable leak tracing and the loading of space maps.  By default, \fBzdb\fR
+verifies that all non-free blocks are referenced, which can be very expensive.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-m\fR
+.ad
+.sp .6
+.RS 4n
+Display the offset, spacemap, and free space of each metaslab.
+When specified twice, also display information about the on-disk free
+space histogram associated with each metaslab. When specified three time,
+display the maximum contiguous free space, the in-core free space histogram,
+and the percentage of free space in each space map.  When specified
+four times display every spacemap record.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-M\fR
+.ad
+.sp .6
+.RS 4n
+Display the offset, spacemap, and free space of each metaslab.
+When specified twice, also display information about the maximum contiguous
+free space and the percentage of free space in each space map.  When specified
+three times display every spacemap record.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-R\fR \fIpoolname\fR \fIvdev\fR:\fIoffset\fR:\fIsize\fR[:\fIflags\fR]
+.ad
+.sp .6
+.RS 4n
+Read and display a block from the specified device. By default the block is
+displayed as a hex dump, but see the description of the \'r\' flag, below.
+.sp
+The block is specified in terms of a colon-separated tuple \fIvdev\fR (an
+integer vdev identifier) \fIoffset\fR (the offset within the vdev) \fIsize\fR
+(the size of the block to read) and, optionally, \fIflags\fR (a set of flags,
+described below).
+
+.sp
+.ne 2
+.na
+\fBb\fR \fIoffset\fR
+.ad
+.sp .6
+.RS 4n
+Print block pointer
+.RE
+
+.sp
+.ne 2
+.na
+\fBd\fR
+.ad
+.sp .6
+.RS 4n
+Decompress the block
+.RE
+
+.sp
+.ne 2
+.na
+\fBe\fR
+.ad
+.sp .6
+.RS 4n
+Byte swap the block
+.RE
+
+.sp
+.ne 2
+.na
+\fBg\fR
+.ad
+.sp .6
+.RS 4n
+Dump gang block header
+.RE
+
+.sp
+.ne 2
+.na
+\fBi\fR
+.ad
+.sp .6
+.RS 4n
+Dump indirect block
+.RE
+
+.sp
+.ne 2
+.na
+\fBr\fR
+.ad
+.sp .6
+.RS 4n
+Dump raw uninterpreted block data
+.RE
+.RE
+
+.sp
+.ne 2
+.na
+\fB-s\fR
+.ad
+.sp .6
+.RS 4n
+Report statistics on \fBzdb\fR\'s I/O. Display operation counts, bandwidth,
+and error counts of I/O to the pool from \fBzdb\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-S\fR
+.ad
+.sp .6
+.RS 4n
+Simulate the effects of deduplication, constructing a DDT and then display
+that DDT as with \fB-DD\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-u\fR
+.ad
+.sp .6
+.RS 4n
+Display the current uberblock.
+.RE
+
+.P
+Other options:
+
+.sp
+.ne 2
+.na
+\fB-A\fR
+.ad
+.sp .6
+.RS 4n
+Do not abort should any assertion fail.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-AA\fR
+.ad
+.sp .6
+.RS 4n
+Enable panic recovery, certain errors which would otherwise be fatal are
+demoted to warnings.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-AAA\fR
+.ad
+.sp .6
+.RS 4n
+Do not abort if asserts fail and also enable panic recovery.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-e\fR [-p \fIpath\fR]...
+.ad
+.sp .6
+.RS 4n
+Operate on an exported pool, not present in \fB/etc/zfs/zpool.cache\fR. The
+\fB-p\fR flag specifies the path under which devices are to be searched.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-x\fR \fIdumpdir\fR
+.ad
+.sp .6
+.RS 4n
+All blocks accessed will be copied to files in the specified directory.
+The blocks will be placed in sparse files whose name is the same as
+that of the file or device read.  zdb can be then run on the generated files.
+Note that the \fB-bbc\fR flags are sufficient to access (and thus copy)
+all metadata on the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-F\fR
+.ad
+.sp .6
+.RS 4n
+Attempt to make an unreadable pool readable by trying progressively older
+transactions.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-I \fIinflight I/Os\fR \fR
+.ad
+.sp .6
+.RS 4n
+Limit the number of outstanding checksum I/Os to the specified value. The
+default value is 200. This option affects the performance of the \fB-c\fR
+option.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-P\fR
+.ad
+.sp .6
+.RS 4n
+Print numbers in an unscaled form more amenable to parsing, eg. 1000000 rather
+than 1M.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-t\fR \fItransaction\fR
+.ad
+.sp .6
+.RS 4n
+Specify the highest transaction to use when searching for uberblocks. See also
+the \fB-u\fR and \fB-l\fR options for a means to see the available uberblocks
+and their associated transaction numbers.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-U\fR \fIcachefile\fR
+.ad
+.sp .6
+.RS 4n
+Use a cache file other than \fB/etc/zfs/zpool.cache\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-v\fR
+.ad
+.sp .6
+.RS 4n
+Enable verbosity. Specify multiple times for increased verbosity.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-X\fR
+.ad
+.sp .6
+.RS 4n
+Attempt \'extreme\' transaction rewind, that is attempt the same recovery as
+\fB-F\fR but read transactions otherwise deemed too old.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-V\fR
+.ad
+.sp .6
+.RS 4n
+Attempt a verbatim import. This mimics the behavior of the kernel when loading
+a pool from a cachefile.
+.RE
+
+.P
+Specifying a display option more than once enables verbosity for only that
+option, with more occurrences enabling more verbosity.
+.P
+If no options are specified, all information about the named pool will be
+displayed at default verbosity.
+
+.SH "EXAMPLES"
+.LP
+\fBExample 1 \fRDisplay the configuration of imported pool 'rpool'
+.sp
+.in +2
+.nf
+# zdb -C rpool
+
+MOS Configuration:
+        version: 28
+        name: 'rpool'
+ ...
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 2 \fRDisplay basic dataset information about 'rpool'
+.sp
+.in +2
+.nf
+# zdb -d rpool
+Dataset mos [META], ID 0, cr_txg 4, 26.9M, 1051 objects
+Dataset rpool/swap [ZVOL], ID 59, cr_txg 356, 486M, 2 objects
+ ...
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 3 \fRDisplay basic information about object 0
+in 'rpool/export/home'
+.sp
+.in +2
+.nf
+# zdb -d rpool/export/home 0
+Dataset rpool/export/home [ZPL], ID 137, cr_txg 1546, 32K, 8 objects
+
+    Object  lvl   iblk   dblk  dsize  lsize   %full  type
+         0    7    16K    16K  15.0K    16K   25.00  DMU dnode
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 4 \fRDisplay the predicted effect of enabling deduplication on 'rpool'
+.sp
+.in +2
+.nf
+# zdb -S rpool
+Simulated DDT histogram:
+
+bucket              allocated                       referenced
+______   ______________________________   ______________________________
+refcnt   blocks   LSIZE   PSIZE   DSIZE   blocks   LSIZE   PSIZE   DSIZE
+------   ------   -----   -----   -----   ------   -----   -----   -----
+     1     694K   27.1G   15.0G   15.0G     694K   27.1G   15.0G   15.0G
+     2    35.0K   1.33G    699M    699M    74.7K   2.79G   1.45G   1.45G
+ ...
+dedup = 1.11, compress = 1.80, copies = 1.00, dedup * compress / copies = 2.00
+.fi
+.in -2
+.sp
+
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.B "SPA_CONFIG_PATH"
+Override the default \fBspa_config_path\fR (\fI/etc/zfs/zpool.cache\fR) setting. If \fB-U\fR flag is specified it will override this environment variable settings once again.
+
+.SH "SEE ALSO"
+zfs(8), zpool(8)
index b3e8c1303bda612cfbec58359220e20cc62e48d7..2ab088d98a3c621590690889f917bf0705a47dc7 100644 (file)
@@ -1,2 +1,252 @@
-%:
-       #
+.\"
+.\" This file is part of the ZFS Event Daemon (ZED)
+.\" for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
+.\" Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
+.\" Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
+.\" Refer to the ZoL git commit log for authoritative copyright attribution.
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License Version 1.0 (CDDL-1.0).
+.\" You can obtain a copy of the license from the top-level file
+.\" "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
+.\" You may not use this file except in compliance with the license.
+.\"
+.TH ZED 8 "Octember 1, 2013" "ZFS on Linux" "System Administration Commands"
+
+.SH NAME
+ZED \- ZFS Event Daemon
+
+.SH SYNOPSIS
+.HP
+.B zed
+.\" [\fB\-c\fR \fIconfigfile\fR]
+[\fB\-d\fR \fIzedletdir\fR]
+[\fB\-f\fR]
+[\fB\-F\fR]
+[\fB\-h\fR]
+[\fB\-L\fR]
+[\fB\-M\fR]
+[\fB\-p\fR \fIpidfile\fR]
+[\fB\-s\fR \fIstatefile\fR]
+[\fB\-v\fR]
+[\fB\-V\fR]
+[\fB\-Z\fR]
+
+.SH DESCRIPTION
+.PP
+\fBZED\fR (ZFS Event Daemon) monitors events generated by the ZFS kernel
+module.  When a zevent (ZFS Event) is posted, \fBZED\fR will run any ZEDLETs
+(ZFS Event Daemon Linkage for Executable Tasks) that have been enabled for the
+corresponding zevent class.
+
+.SH OPTIONS
+.TP
+.BI \-h
+Display a summary of the command-line options.
+.TP
+.BI \-L
+Display license information.
+.TP
+.BI \-V
+Display version information.
+.TP
+.BI \-v
+Be verbose.
+.TP
+.BI \-f
+Force the daemon to run if at all possible, disabling security checks and
+throwing caution to the wind.  Not recommended for use in production.
+.TP
+.BI \-F
+Run the daemon in the foreground.
+.TP
+.BI \-M
+Lock all current and future pages in the virtual memory address space.
+This may help the daemon remain responsive when the system is under heavy
+memory pressure.
+.TP
+.BI \-Z
+Zero the daemon's state, thereby allowing zevents still within the kernel
+to be reprocessed.
+.\" .TP
+.\" .BI \-c\  configfile
+.\" Read the configuration from the specified file.
+.TP
+.BI \-d\  zedletdir
+Read the enabled ZEDLETs from the specified directory.
+.TP
+.BI \-p\  pidfile
+Write the daemon's process ID to the specified file.
+.TP
+.BI \-s\  statefile
+Write the daemon's state to the specified file.
+
+.SH ZEVENTS
+.PP
+A zevent is comprised of a list of nvpairs (name/value pairs).  Each zevent
+contains an EID (Event IDentifier) that uniquely identifies it throughout
+the lifetime of the loaded ZFS kernel module; this EID is a monotonically
+increasing integer that resets to 1 each time the kernel module is loaded.
+Each zevent also contains a class string that identifies the type of event.
+For brevity, a subclass string is defined that omits the leading components
+of the class string.  Additional nvpairs exist to provide event details.
+.PP
+The kernel maintains a list of recent zevents that can be viewed (along with
+their associated lists of nvpairs) using the "\fBzpool events \-v\fR" command.
+
+.SH CONFIGURATION
+.PP
+ZEDLETs to be invoked in response to zevents are located in the
+\fIenabled-zedlets\fR directory.  These can be symlinked or copied from the
+\fIinstalled-zedlets\fR directory; symlinks allow for automatic updates
+from the installed ZEDLETs, whereas copies preserve local modifications.
+As a security measure, ZEDLETs must be owned by root.  They must have
+execute permissions for the user, but they must not have write permissions
+for group or other.  Dotfiles are ignored.
+.PP
+ZEDLETs are named after the zevent class for which they should be invoked.
+In particular, a ZEDLET will be invoked for a given zevent if either its
+class or subclass string is a prefix of its filename (and is followed by
+a non-alphabetic character).  As a special case, the prefix "all" matches
+all zevents.  Multiple ZEDLETs may be invoked for a given zevent.
+
+.SH ZEDLETS
+.PP
+ZEDLETs are executables invoked by the ZED in response to a given zevent.
+They should be written under the presumption they can be invoked concurrently,
+and they should use appropriate locking to access any shared resources.
+Common variables used by ZEDLETs can be stored in the default rc file which
+is sourced by scripts; these variables should be prefixed with "ZED_".
+.PP
+The zevent nvpairs are passed to ZEDLETs as environment variables.
+Each nvpair name is converted to an environment variable in the following
+manner: 1) it is prefixed with "ZEVENT_", 2) it is converted to uppercase,
+and 3) each non-alphanumeric character is converted to an underscore.
+Some additional environment variables have been defined to present certain
+nvpair values in a more convenient form.  An incomplete list of zevent
+environment variables is as follows:
+.TP
+.B
+ZEVENT_EID
+The Event IDentifier.
+.TP
+.B
+ZEVENT_CLASS
+The zevent class string.
+.TP
+.B
+ZEVENT_SUBCLASS
+The zevent subclass string.
+.TP
+.B
+ZEVENT_TIME
+The time at which the zevent was posted as
+"\fIseconds\fR\ \fInanoseconds\fR" since the Epoch.
+.TP
+.B
+ZEVENT_TIME_SECS
+The \fIseconds\fR component of ZEVENT_TIME.
+.TP
+.B
+ZEVENT_TIME_NSECS
+The \fInanoseconds\fR component of ZEVENT_TIME.
+.TP
+.B
+ZEVENT_TIME_STRING
+An almost-RFC3339-compliant string for ZEVENT_TIME.
+.PP
+Additionally, the following ZED & ZFS variables are defined:
+.TP
+.B
+ZED_PID
+The daemon's process ID.
+.TP
+.B
+ZED_ZEDLET_DIR
+The daemon's current \fIenabled-zedlets\fR directory.
+.TP
+.B
+ZFS_ALIAS
+The ZFS alias (\fIname-version-release\fR) string used to build the daemon.
+.TP
+.B
+ZFS_VERSION
+The ZFS version used to build the daemon.
+.TP
+.B
+ZFS_RELEASE
+The ZFS release used to build the daemon.
+.PP
+ZEDLETs may need to call other ZFS commands.  The installation paths of
+the following executables are defined: \fBZDB\fR, \fBZED\fR, \fBZFS\fR,
+\fBZINJECT\fR, and \fBZPOOL\fR.  These variables can be overridden in the
+rc file if needed.
+
+.SH FILES
+.\" .TP
+.\" @sysconfdir@/zfs/zed.conf
+.\" The default configuration file for the daemon.
+.TP
+.I @sysconfdir@/zfs/zed.d
+The default directory for enabled ZEDLETs.
+.TP
+.I @sysconfdir@/zfs/zed.d/zed.rc
+The default rc file for common variables used by ZEDLETs.
+.TP
+.I @libexecdir@/zfs/zed.d
+The default directory for installed ZEDLETs.
+.TP
+.I @runstatedir@/zed.pid
+The default file containing the daemon's process ID.
+.TP
+.I @runstatedir@/zed.state
+The default file containing the daemon's state.
+
+.SH SIGNALS
+.TP
+.B HUP
+Reconfigure the daemon and rescan the directory for enabled ZEDLETs.
+.TP
+.B TERM
+Terminate the daemon.
+
+.SH NOTES
+.PP
+\fBZED\fR requires root privileges.
+.\" Do not taunt zed.
+
+.SH BUGS
+.PP
+Events are processed synchronously by a single thread.  This can delay the
+processing of simultaneous zevents.
+.PP
+There is no maximum timeout for ZEDLET execution.  Consequently, a misbehaving
+ZEDLET can delay the processing of subsequent zevents.
+.PP
+The ownership and permissions of the \fIenabled-zedlets\fR directory (along
+with all parent directories) are not checked.  If any of these directories
+are improperly owned or permissioned, an unprivileged user could insert a
+ZEDLET to be executed as root.  The requirement that ZEDLETs be owned by
+root mitigates this to some extent.
+.PP
+ZEDLETs are unable to return state/status information to the kernel.
+.PP
+Some zevent nvpair types are not handled.  These are denoted by zevent
+environment variables having a "_NOT_IMPLEMENTED_" value.
+.PP
+Internationalization support via gettext has not been added.
+.PP
+The configuration file is not yet implemented.
+.PP
+The diagnosis engine is not yet implemented.
+
+.SH LICENSE
+.PP
+\fBZED\fR (ZFS Event Daemon) is distributed under the terms of the
+Common Development and Distribution License Version 1.0 (CDDL\-1.0).
+.PP
+Developed at Lawrence Livermore National Laboratory (LLNL\-CODE\-403049).
+
+.SH SEE ALSO
+.BR zfs (8),
+.BR zpool (8)
diff --git a/zfs/man/man8/zfs.8 b/zfs/man/man8/zfs.8
new file mode 100644 (file)
index 0000000..d8c1506
--- /dev/null
@@ -0,0 +1,3949 @@
+'\" t
+.\"
+.\" 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 (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org>
+.\" Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+.\" Copyright (c) 2014, Joyent, Inc. All rights reserved.
+.\" Copyright 2012 Nexenta Systems, Inc. All Rights Reserved.
+.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+.\" Copyright 2016 Richard Laager. All rights reserved.
+.\"
+.TH zfs 8 "May 11, 2016" "ZFS pool 28, filesystem 5" "System Administration Commands"
+.SH NAME
+zfs \- configures ZFS file systems
+.SH SYNOPSIS
+.LP
+.nf
+\fBzfs\fR [\fB-?\fR]
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBcreate\fR [\fB-p\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ... \fIfilesystem\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBcreate\fR [\fB-ps\fR] [\fB-b\fR \fIblocksize\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ... \fB-V\fR \fIsize\fR \fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBdestroy\fR [\fB-fnpRrv\fR] \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBdestroy\fR [\fB-dnpRrv\fR] \fIfilesystem\fR|\fIvolume\fR@\fIsnap\fR[%\fIsnap\fR][,...]
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBdestroy\fR \fIfilesystem\fR|\fIvolume\fR#\fIbookmark\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBsnapshot | snap\fR [\fB-r\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ...
+      \fIfilesystem@snapname\fR|\fIvolume@snapname\fR ...
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBrollback\fR [\fB-rRf\fR] \fIsnapshot\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBclone\fR [\fB-p\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ... \fIsnapshot\fR \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBpromote\fR \fIclone-filesystem\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBrename\fR [\fB-f\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR
+     \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBrename\fR [\fB-fp\fR] \fIfilesystem\fR|\fIvolume\fR \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBrename\fR \fB-r\fR \fIsnapshot\fR \fIsnapshot\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBlist\fR [\fB-r\fR|\fB-d\fR \fIdepth\fR][\fB-Hp\fR][\fB-o\fR \fIproperty\fR[,\fIproperty\fR]...] [\fB-t\fR \fItype\fR[,\fItype\fR]..]
+     [\fB-s\fR \fIproperty\fR] ... [\fB-S\fR \fIproperty\fR] ... [\fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR|\fImountpoint\fR] ...
+.fi
+
+.LP
+.nf
++\fBzfs\fR \fBset\fR \fIproperty\fR=\fIvalue\fR... \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR...
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBget\fR [\fB-r\fR|\fB-d\fR \fIdepth\fR][\fB-Hp\fR][\fB-o\fR \fIfield\fR[,...]] [\fB-t\fR \fItype\fR[,...]]
+    [\fB-s\fR \fIsource\fR[,...]] "\fIall\fR" | \fIproperty\fR[,...] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR|\fImountpoint\fR ...
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBinherit\fR [\fB-rS\fR] \fIproperty\fR \fIfilesystem\fR|\fIvolume|snapshot\fR ...
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBupgrade\fR [\fB-v\fR]
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBupgrade\fR [\fB-r\fR] [\fB-V\fR \fIversion\fR] \fB-a\fR | \fIfilesystem\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBuserspace\fR [\fB-Hinp\fR] [\fB-o\fR \fIfield\fR[,...]] [\fB-s\fR \fIfield\fR] ...
+    [\fB-S\fR \fIfield\fR] ... [\fB-t\fR \fItype\fR[,...]] \fIfilesystem\fR|\fIsnapshot\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBgroupspace\fR [\fB-Hinp\fR] [\fB-o\fR \fIfield\fR[,...]] [\fB-s\fR \fIfield\fR] ...
+    [\fB-S\fR \fIfield\fR] ... [\fB-t\fR \fItype\fR[,...]] \fIfilesystem\fR|\fIsnapshot\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBmount\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBmount\fR [\fB-vO\fR] [\fB-o \fIoptions\fR\fR] \fB-a\fR | \fIfilesystem\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBunmount | umount\fR [\fB-f\fR] \fB-a\fR | \fIfilesystem\fR|\fImountpoint\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBshare\fR \fB-a\fR | \fIfilesystem\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBunshare\fR \fB-a\fR \fIfilesystem\fR|\fImountpoint\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBbookmark\fR \fIsnapshot\fR \fIbookmark\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBsend\fR [\fB-DnPpRveLc\fR] [\fB-\fR[\fBiI\fR] \fIsnapshot\fR] \fIsnapshot\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBsend\fR [\fB-Le\fR] [\fB-i \fIsnapshot\fR|\fIbookmark\fR]\fR \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBsend\fR [\fB-Penv\fR] \fB-t\fR \fIreceive_resume_token\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBreceive\fR [\fB-Fnsuv\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBreceive\fR [\fB-Fnsuv\fR] [\fB-d\fR|\fB-e\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBreceive\fR \fB-A\fR \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBallow\fR \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBallow\fR [\fB-ldug\fR] "\fIeveryone\fR"|\fIuser\fR|\fIgroup\fR[,...] \fIperm\fR|\fI@setname\fR[,...]
+     \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBallow\fR [\fB-ld\fR] \fB-e\fR \fIperm\fR|@\fIsetname\fR[,...] \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBallow\fR \fB-c\fR \fIperm\fR|@\fIsetname\fR[,...] \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBallow\fR \fB-s\fR @\fIsetname\fR \fIperm\fR|@\fIsetname\fR[,...] \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBunallow\fR [\fB-rldug\fR] "\fIeveryone\fR"|\fIuser\fR|\fIgroup\fR[,...] [\fIperm\fR|@\fIsetname\fR[,... ]]
+     \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBunallow\fR [\fB-rld\fR] \fB-e\fR [\fIperm\fR|@\fIsetname\fR[,... ]] \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBunallow\fR [\fB-r\fR] \fB-c\fR [\fIperm\fR|@\fIsetname\fR[ ... ]] \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBunallow\fR [\fB-r\fR] \fB-s\fR @\fIsetname\fR [\fIperm\fR|@\fIsetname\fR[,... ]] \fIfilesystem\fR|\fIvolume\fR
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBhold\fR [\fB-r\fR] \fItag\fR \fIsnapshot\fR...
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBholds\fR [\fB-r\fR] \fIsnapshot\fR...
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBrelease\fR [\fB-r\fR] \fItag\fR \fIsnapshot\fR...
+.fi
+
+.LP
+.nf
+\fBzfs\fR \fBdiff\fR [\fB-FHt\fR] \fIsnapshot\fR \fIsnapshot|filesystem\fR
+
+.SH DESCRIPTION
+.LP
+The \fBzfs\fR command configures \fBZFS\fR datasets within a \fBZFS\fR storage pool, as described in \fBzpool\fR(8). A dataset is identified by a unique path within the \fBZFS\fR namespace. For example:
+.sp
+.in +2
+.nf
+pool/{filesystem,volume,snapshot}
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+where the maximum length of a dataset name is \fBMAXNAMELEN\fR (256 bytes).
+.sp
+.LP
+A dataset can be one of the following:
+.sp
+.ne 2
+.na
+\fB\fIfilesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+A \fBZFS\fR dataset of type \fBfilesystem\fR can be mounted within the standard system namespace and behaves like other file systems. While \fBZFS\fR file systems are designed to be \fBPOSIX\fR compliant, known issues exist that prevent compliance in some cases. Applications that depend on standards conformance might fail due to nonstandard behavior when checking file system free space.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+A logical volume exported as a raw or block device. This type of dataset should only be used under special circumstances. File systems are typically used in most environments.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIsnapshot\fR\fR
+.ad
+.sp .6
+.RS 4n
+A read-only version of a file system or volume at a given point in time. It is specified as \fIfilesystem@name\fR or \fIvolume@name\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIbookmark\fR\fR
+.ad
+.sp .6
+.RS 4n
+Much like a \fIsnapshot\fR, but without the hold on on-disk data. It can be used as the source of a send (but not for a receive).
+It is specified as \fIfilesystem#name\fR or \fIvolume#name\fR.
+.RE
+
+.SS "ZFS File System Hierarchy"
+.LP
+A \fBZFS\fR storage pool is a logical collection of devices that provide space for datasets. A storage pool is also the root of the \fBZFS\fR file system hierarchy.
+.sp
+.LP
+The root of the pool can be accessed as a file system, such as mounting and unmounting, taking snapshots, and setting properties. The physical storage characteristics, however, are managed by the \fBzpool\fR(8) command.
+.sp
+.LP
+See \fBzpool\fR(8) for more information on creating and administering pools.
+.SS "Snapshots"
+.LP
+A snapshot is a read-only copy of a file system or volume. Snapshots can be created extremely quickly, and initially consume no additional space within the pool. As data within the active dataset changes, the snapshot consumes more data than would otherwise be shared with the active dataset.
+.sp
+.LP
+Snapshots can have arbitrary names. Snapshots of volumes can be cloned or rolled back.  Visibility is determined by the \fBsnapdev\fR property of the parent volume.
+.sp
+.LP
+File system snapshots can be accessed under the \fB\&.zfs/snapshot\fR directory in the root of the file system. Snapshots are automatically mounted on demand and may be unmounted at regular intervals. The visibility of the \fB\&.zfs\fR directory can be controlled by the \fBsnapdir\fR property.
+.SS "Bookmarks"
+.LP
+A bookmark is like a snapshot, a read-only copy of a file system or volume. Bookmarks can be created extremely quickly, compared to snapshots, and they consume no additional space within the pool.  Bookmarks can also have arbitrary names, much like snapshots.
+.sp
+.LP
+Unlike snapshots, bookmarks can not be accessed through the filesystem in any way. From a storage standpoint a bookmark just provides a way to reference when a snapshot was created as a distinct object.  Bookmarks are initially tied to a snapshot, not the filesystem/volume, and they will survive if the snapshot itself is destroyed.  Since they are very light weight there's little incentive to destroy them.
+.SS "Clones"
+.LP
+A clone is a writable volume or file system whose initial contents are the same as another dataset. As with snapshots, creating a clone is nearly instantaneous, and initially consumes no additional space.
+.sp
+.LP
+Clones can only be created from a snapshot. When a snapshot is cloned, it creates an implicit dependency between the parent and child. Even though the clone is created somewhere else in the dataset hierarchy, the original snapshot cannot be destroyed as long as a clone exists. The \fBorigin\fR property exposes this dependency, and the \fBdestroy\fR command lists any such dependencies, if they exist.
+.sp
+.LP
+The clone parent-child dependency relationship can be reversed by using the \fBpromote\fR subcommand. This causes the "origin" file system to become a clone of the specified file system, which makes it possible to destroy the file system that the clone was created from.
+.SS "Mount Points"
+.LP
+Creating a \fBZFS\fR file system is a simple operation, so the number of file systems per system is likely to be numerous. To cope with this, \fBZFS\fR automatically manages mounting and unmounting file systems without the need to edit the \fB/etc/fstab\fR file. All automatically managed file systems are mounted by \fBZFS\fR at boot time.
+.sp
+.LP
+By default, file systems are mounted under \fB/\fIpath\fR\fR, where \fIpath\fR is the name of the file system in the \fBZFS\fR namespace. Directories are created and destroyed as needed.
+.sp
+.LP
+A file system can also have a mount point set in the \fBmountpoint\fR property. This directory is created as needed, and \fBZFS\fR automatically mounts the file system when the \fBzfs mount -a\fR command is invoked (without editing \fB/etc/fstab\fR). The \fBmountpoint\fR property can be inherited, so if \fBpool/home\fR has a mount point of \fB/export/stuff\fR, then \fBpool/home/user\fR automatically inherits a mount point of \fB/export/stuff/user\fR.
+.sp
+.LP
+A file system \fBmountpoint\fR property of \fBnone\fR prevents the file system from being mounted.
+.sp
+.LP
+If needed, \fBZFS\fR file systems can also be managed with traditional tools (\fBmount\fR, \fBumount\fR, \fB/etc/fstab\fR). If a file system's mount point is set to \fBlegacy\fR, \fBZFS\fR makes no attempt to manage the file system, and the administrator is responsible for mounting and unmounting the file system.
+.SS "Deduplication"
+.LP
+Deduplication is the process for removing redundant data at the block-level, reducing the total amount of data stored. If a file system has the \fBdedup\fR property enabled, duplicate data blocks are removed synchronously.  The result is that only unique data is stored and common components are shared among files.
+.sp
+\fBWARNING: DO NOT ENABLE DEDUPLICATION UNLESS YOU NEED IT AND KNOW EXACTLY WHAT YOU ARE DOING!\fR
+.sp
+Deduplicating data is a very resource-intensive operation. It is generally recommended that you have \fIat least\fR 1.25 GiB of RAM per 1 TiB of storage when you enable deduplication. But calculating the exact requirements is a somewhat complicated affair.
+.sp
+Enabling deduplication on an improperly-designed system will result in extreme performance issues (extremely slow filesystem and snapshot deletions etc.) and can potentially lead to data loss (i.e. unimportable pool due to memory exhaustion) if your system is not built for this purpose. Deduplication affects the processing power (CPU), disks (and the controller) as well as primary (real) memory.
+.sp
+Before creating a pool with deduplication enabled, ensure that you have planned your hardware requirements appropriately and implemented appropriate recovery practices, such as regular backups.
+.sp
+Unless necessary, deduplication should NOT be enabled on a system. Instead, consider using \fIcompression=lz4\fR, as a less resource-intensive alternative.
+.SS "Properties"
+.sp
+.LP
+Properties are divided into two types: native properties and user-defined (or "user") properties. Native properties either export internal statistics or control \fBZFS\fR behavior. User properties have no effect on \fBZFS\fR behavior, but you can use them to annotate datasets and snapshots in a way that is meaningful in your environment.
+.sp
+.LP
+Properties are generally inherited from the parent unless overridden by the child. See the documentation below for exceptions.
+.sp
+.LP
+.SS "Native Properties"
+Native properties apply to all dataset types unless otherwise noted. However, native properties cannot be edited on snapshots.
+.sp
+.LP
+The values of numeric native properties can be specified using human-readable abbreviations (\fBK\fR, \fBM\fR, \fBG\fR, \fBT\fR, \fBP\fR, \fBE\fR, and \fBZ\fR). These abbreviations can optionally use the IEC binary prefixes (e.g. GiB) or SI decimal prefixes (e.g. GB), though the SI prefixes are treated as binary prefixes. Abbreviations are case-insensitive. The following are all valid (and equal) specifications:
+.sp
+.in +2
+.nf
+1536M, 1.5g, 1.50GB, 1.5GiB
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+The values of non-numeric native properties are case-sensitive and must be lowercase, except for \fBmountpoint\fR, \fBsharenfs\fR, and \fBsharesmb\fR.
+.sp
+.LP
+The following native properties consist of read-only statistics about the dataset. These properties can be neither set, nor inherited.
+.sp
+.ne 2
+.na
+\fB\fBavailable\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space available to the dataset and all its children, assuming that there is no other activity in the pool. Because space is shared within a pool, availability can be limited by any number of factors, including physical pool size, quotas, reservations, or other datasets within the pool.
+.sp
+This property can also be referred to by its shortened column name, \fBavail\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcompressratio\fR\fR
+.ad
+.sp .6
+.RS 4n
+For non-snapshots, the compression ratio achieved for the \fBused\fR space of this dataset, expressed as a multiplier.  The \fBused\fR property includes descendant datasets, and, for clones, does not include the space shared with the origin snapshot.  For snapshots, the \fBcompressratio\fR is the same as the \fBrefcompressratio\fR property.  The \fBcompression\fR property controls whether compression is enabled on a dataset.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcreation\fR\fR
+.ad
+.sp .6
+.RS 4n
+The time this dataset was created.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBclones\fR\fR
+.ad
+.sp .6
+.RS 4n
+For snapshots, this property is a comma-separated list of filesystems or
+volumes which are clones of this snapshot.  The clones' \fBorigin\fR property
+is this snapshot.  If the \fBclones\fR property is not empty, then this
+snapshot can not be destroyed (even with the \fB-r\fR or \fB-f\fR options). The
+roles of origin and clone can be swapped by promoting the clone with the
+\fBzfs promote\fR command.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdefer_destroy\fR\fR
+.ad
+.sp .6
+.RS 4n
+This property is \fBon\fR if the snapshot has been marked for deferred destruction by using the \fBzfs destroy\fR \fB-d\fR command. Otherwise, the property is \fBoff\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfilesystem_count\fR
+.ad
+.sp .6
+.RS 4n
+The total number of filesystems and volumes that exist under this location in the
+dataset tree.  This value is only available when a \fBfilesystem_limit\fR has
+been set somewhere in the tree under which the dataset resides.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlogicalreferenced\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space that is "logically" accessible by this dataset.  See
+the \fBreferenced\fR property.  The logical space ignores the effect of
+the \fBcompression\fR and \fBcopies\fR properties, giving a quantity
+closer to the amount of data that applications see.  However, it does
+include space consumed by metadata.
+.sp
+This property can also be referred to by its shortened column name,
+\fBlrefer\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlogicalused\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space that is "logically" consumed by this dataset and all
+its descendents.  See the \fBused\fR property.  The logical space
+ignores the effect of the \fBcompression\fR and \fBcopies\fR properties,
+giving a quantity closer to the amount of data that applications see.
+However, it does include space consumed by metadata.
+.sp
+This property can also be referred to by its shortened column name,
+\fBlused\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmounted\fR\fR
+.ad
+.sp .6
+.RS 4n
+For file systems, indicates whether the file system is currently mounted. This property can be either \fByes\fR or \fBno\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBorigin\fR\fR
+.ad
+.sp .6
+.RS 4n
+For cloned file systems or volumes, the snapshot from which the clone was created. The origin cannot be destroyed (even with the \fB-r\fR or \fB-f\fR options) so long as a clone exists. See also the \fBclones\fR property.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBreceive_resume_token\fR\fR
+.ad
+.sp .6
+.RS 4n
+For filesystems or volumes which have saved partially-completed state from \fBzfs receive -s\fR , this opaque token can be provided to \fBzfs send -t\fR to resume and complete the \fBzfs receive\fR.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fBreferenced\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of data that is accessible by this dataset, which may or may not be shared with other datasets in the pool. When a snapshot or clone is created, it initially references the same amount of space as the file system or snapshot it was created from, since its contents are identical.
+.sp
+This property can also be referred to by its shortened column name, \fBrefer\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBrefcompressratio\fR\fR
+.ad
+.sp .6
+.RS 4n
+The compression ratio achieved for the \fBreferenced\fR space of this
+dataset, expressed as a multiplier.  See also the \fBcompressratio\fR
+property.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsnapshot_count\fR
+.ad
+.sp .6
+.RS 4n
+The total number of snapshots that exist under this location in the dataset tree.
+This value is only available when a \fBsnapshot_limit\fR has been set somewhere
+in the tree under which the dataset resides.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBtype\fR\fR
+.ad
+.sp .6
+.RS 4n
+The type of dataset: \fBfilesystem\fR, \fBvolume\fR, or \fBsnapshot\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBused\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space consumed by this dataset and all its descendents. This is the value that is checked against this dataset's quota and reservation. The space used does not include this dataset's reservation, but does take into account the reservations of any descendent datasets. The amount of space that a dataset consumes from its parent, as well as the amount of space that are freed if this dataset is recursively destroyed, is the greater of its space used and its reservation.
+.sp
+When snapshots (see the "Snapshots" section) are created, their space is initially shared between the snapshot and the file system, and possibly with previous snapshots. As the file system changes, space that was previously shared becomes unique to the snapshot, and counted in the snapshot's space used. Additionally, deleting snapshots can increase the amount of space unique to (and used by) other snapshots.
+.sp
+The amount of space used, available, or referenced does not take into account pending changes. Pending changes are generally accounted for within a few seconds. Committing a change to a disk using \fBfsync\fR(2) or \fBO_SYNC\fR (see \fBopen\fR(2)) does not necessarily guarantee that the space usage information is updated immediately.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBusedby*\fR\fR
+.ad
+.sp .6
+.RS 4n
+The \fBusedby*\fR properties decompose the \fBused\fR properties into the various reasons that space is used. Specifically, \fBused\fR = \fBusedbychildren\fR + \fBusedbydataset\fR + \fBusedbyrefreservation\fR + \fBusedbysnapshots\fR. These properties are only available for datasets created on \fBzpool\fR version 13 or higher pools.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBusedbychildren\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space used by children of this dataset, which would be freed if all the dataset's children were destroyed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBusedbydataset\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space used by this dataset itself, which would be freed if the dataset were destroyed (after first removing any \fBrefreservation\fR and destroying any necessary snapshots or descendents).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBusedbyrefreservation\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space used by a \fBrefreservation\fR set on this dataset, which would be freed if the \fBrefreservation\fR was removed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBusedbysnapshots\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space consumed by snapshots of this dataset. In particular, it is the amount of space that would be freed if all of this dataset's snapshots were destroyed. Note that this is not simply the sum of the snapshots' \fBused\fR properties because space can be shared by multiple snapshots.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBuserobjused@\fR\fIuser\fR\fR
+.br
+\fB\fBuserused@\fR\fIuser\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space consumed by the specified user in this dataset. Space is charged to the owner of each file, as displayed by \fBls\fR \fB-l\fR. The amount of space charged is displayed by \fBdu\fR and \fBls\fR \fB-s\fR. See the \fBzfs userspace\fR subcommand for more information.
+.sp
+Unprivileged users can access only their own space usage. The root user, or a user who has been granted the \fBuserused\fR privilege with \fBzfs allow\fR, can access everyone's usage.
+.sp
+The \fBuserused@\fR... properties are not displayed by \fBzfs get all\fR. The user's name must be appended after the \fB@\fR symbol, using one of the following forms:
+.RS +4
+.TP
+.ie t \(bu
+.el o
+\fIPOSIX name\fR (for example, \fBjoe\fR)
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+\fIPOSIX numeric ID\fR (for example, \fB789\fR)
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+\fISID name\fR (for example, \fBjoe.smith@mydomain\fR)
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+\fISID numeric ID\fR (for example, \fBS-1-123-456-789\fR)
+.RE
+.RE
+Files created on Linux always have POSIX owners.
+
+.RS 4n
+The \fBuserobjused\fR is similar to \fBuserused\fR but instead it counts the number of objects consumed by \fIuser\fR. This feature doesn't count the internal objects used by ZFS, therefore it may under count a few objects comparing with the results of third-party tool such as \fBdfs -i\fR.
+When the property \fBxattr=on\fR is set on a fileset, ZFS will create additional objects per-file to store extended attributes. These additional objects are reflected in the \fBuserobjused\fR value and are counted against the user's \fBuserobjquota\fR. When a filesystem is configured to use \fBxattr=sa\fR no additional internal objects are required.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBuserrefs\fR\fR
+.ad
+.sp .6
+.RS 4n
+This property is set to the number of user holds on this snapshot. User holds are set by using the \fBzfs hold\fR command.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBgroupused@\fR\fIgroup\fR\fR
+.br
+\fB\fBgroupobjused@\fR\fIgroup\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of space consumed by the specified group in this dataset. Space is charged to the group of each file, as displayed by \fBls\fR \fB-l\fR. See the \fBuserused@\fR\fIuser\fR property for more information.
+.sp
+Unprivileged users can only access their own groups' space usage. The root user, or a user who has been granted the \fBgroupused\fR privilege with \fBzfs allow\fR, can access all groups' usage.
+.RE
+
+.RS 4n
+The \fBgroupobjused\fR is similar to \fBgroupused\fR but instead it counts the number of objects consumed by \fIgroup\fR.
+When the property \fBxattr=on\fR is set on a fileset, ZFS will create additional objects per-file to store extended attributes. These additional objects are reflected in the \fBgroupobjused\fR value and are counted against the group's \fBgroupobjquota.\fR. When a filesystem is configured to use \fBxattr=sa\fR no additional internal objects are required.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBvolblocksize\fR=\fIblocksize\fR\fR
+.ad
+.sp .6
+.RS 4n
+This property, which is only valid on volumes, specifies the block size of the volume. Any power of two from 512B to 128KiB is valid. The default is 8KiB.
+.sp
+This property cannot be changed after the volume is created.
+.sp
+This property can also be referred to by its shortened column name, \fBvolblock\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBwritten\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of \fBreferenced\fR space written to this dataset since the
+previous snapshot.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBwritten@\fR\fIsnapshot\fR\fR
+.ad
+.sp .6
+.RS 4n
+The amount of \fBreferenced\fR space written to this dataset since the
+specified snapshot.  This is the space that is referenced by this dataset
+but was not referenced by the specified snapshot.
+.sp
+The \fIsnapshot\fR may be specified as a short snapshot name (just the part
+after the \fB@\fR), in which case it will be interpreted as a snapshot in
+the same filesystem as this dataset.
+The \fIsnapshot\fR be a full snapshot name (\fIfilesystem\fR@\fIsnapshot\fR),
+which for clones may be a snapshot in the origin's filesystem (or the origin
+of the origin's filesystem, etc).
+.RE
+
+.sp
+.LP
+The following native properties can be used to change the behavior of a \fBZFS\fR dataset.
+.sp
+.ne 2
+.na
+\fB\fBaclinherit\fR=\fBrestricted\fR | \fBdiscard\fR | \fBnoallow\fR | \fBpassthrough\fR | \fBpassthrough-x\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls how \fBACL\fR entries are inherited when files and directories are created. A file system with an \fBaclinherit\fR property of \fBdiscard\fR does not inherit any \fBACL\fR entries. A file system with an \fBaclinherit\fR property value of \fBnoallow\fR only inherits inheritable \fBACL\fR entries that specify "deny" permissions. The property value \fBrestricted\fR (the default) removes the \fBwrite_acl\fR and \fBwrite_owner\fR permissions when the \fBACL\fR entry is inherited. A file system with an \fBaclinherit\fR property value of \fBpassthrough\fR inherits all inheritable \fBACL\fR entries without any modifications made to the \fBACL\fR entries when they are inherited. A file system with an \fBaclinherit\fR property value of \fBpassthrough-x\fR has the same meaning as \fBpassthrough\fR, except that the \fBowner@\fR, \fBgroup@\fR, and \fBeveryone@\fR \fBACE\fRs inherit the execute permission only if the file creation mode also requests the execute bit.
+.sp
+When the property value is set to \fBpassthrough\fR, files are created with a mode determined by the inheritable \fBACE\fRs. If no inheritable \fBACE\fRs exist that affect the mode, then the mode is set in accordance to the requested mode from the application.
+.sp
+The \fBaclinherit\fR property does not apply to Posix ACLs.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBacltype\fR=\fBoff\fR | \fBnoacl\fR | \fBposixacl\fR \fR
+.ad
+.sp .6
+.RS 4n
+Controls whether ACLs are enabled and if so what type of ACL to use.  When
+a file system has the \fBacltype\fR property set to \fBoff\fR (the default)
+then ACLs are disabled.  Setting the \fBacltype\fR property to \fBposixacl\fR
+indicates Posix ACLs should be used.  Posix ACLs are specific to Linux and
+are not functional on other platforms.  Posix ACLs are stored as an xattr and
+therefore will not overwrite any existing ZFS/NFSv4 ACLs which may be set.
+Currently only \fBposixacls\fR are supported on Linux.
+.sp
+To obtain the best performance when setting \fBposixacl\fR users are strongly
+encouraged to set the \fBxattr=sa\fR property.  This will result in the
+Posix ACL being stored more efficiently on disk.  But as a consequence of this
+all new xattrs will only be accessible from ZFS implementations which support
+the \fBxattr=sa\fR property.  See the \fBxattr\fR property for more details.
+.sp
+The value \fBnoacl\fR is an alias for \fBoff\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBatime\fR=\fBon\fR | \fBoff\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether the access time for files is updated when they are read. Setting this property to \fBoff\fR avoids producing write traffic when reading files and can result in significant performance gains, though it might confuse mailers and other similar utilities. The default value is \fBon\fR.  See also \fBrelatime\fR below.
+.sp
+The values \fBon\fR and \fBoff\fR are equivalent to the \fBatime\fR and \fBnoatime\fR mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcanmount\fR=\fBon\fR | \fBoff\fR | \fBnoauto\fR\fR
+.ad
+.sp .6
+.RS 4n
+If this property is set to \fBoff\fR, the file system cannot be mounted, and is ignored by \fBzfs mount -a\fR. Setting this property to \fBoff\fR is similar to setting the \fBmountpoint\fR property to \fBnone\fR, except that the dataset still has a normal \fBmountpoint\fR property, which can be inherited. Setting this property to \fBoff\fR allows datasets to be used solely as a mechanism to inherit properties. One example of setting \fBcanmount=\fR\fBoff\fR is to have two datasets with the same \fBmountpoint\fR, so that the children of both datasets appear in the same directory, but might have different inherited characteristics.
+.sp
+When the \fBnoauto\fR option is set, a dataset can only be mounted and unmounted explicitly. The dataset is not mounted automatically when the dataset is created or imported, nor is it mounted by the \fBzfs mount -a\fR command or unmounted by the \fBzfs unmount -a\fR command.
+.sp
+This property is not inherited. Every dataset defaults to \fBon\fR independently.
+.sp
+The values \fBon\fR and \fBnoauto\fR are equivalent to the \fBauto\fR and \fBnoauto\fR mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBchecksum\fR=\fBon\fR | \fBoff\fR | \fBfletcher2\fR | \fBfletcher4\fR | \fBsha256\fR | \fBnoparity\fR | \fBsha512\fR | \fBskein\fR | \fBedonr\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the checksum used to verify data integrity. The default value is
+\fBon\fR, which automatically selects an appropriate algorithm (currently,
+\fBfletcher4\fR, but this may change in future releases). The value \fBoff\fR
+disables integrity checking on user data.  The value \fBnoparity\fR not only
+disables integrity but also disables maintaining parity for user data.
+This setting is used internally by a dump device residing on a RAID-Z pool and
+should not be used by any other dataset.  Disabling checksums is \fBNOT\fR a
+recommended practice.
+.sp
+The \fBsha512\fR, \fBskein\fR, and \fBedonr\fR checksum algorithms require
+enabling the appropriate features on the pool. Please see zpool-features for
+more information on these algorithms.
+
+Changing this property affects only newly-written data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcompression\fR=\fBoff\fR | \fBon\fR | \fBlzjb\fR | \fBlz4\fR |
+\fBgzip\fR | \fBgzip-\fR\fIN\fR | \fBzle\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the compression algorithm used for this dataset.
+.sp
+Setting compression to \fBon\fR indicates that the current default
+compression algorithm should be used.  The default balances compression
+and decompression speed, with compression ratio and is expected to
+work well on a wide variety of workloads.  Unlike all other settings for
+this property, \fBon\fR does not select a fixed compression type.  As
+new compression algorithms are added to ZFS and enabled on a pool, the
+default compression algorithm may change.  The current default compression
+algorithm is either \fBlzjb\fR or, if the \fBlz4_compress\fR feature is
+enabled, \fBlz4\fR.
+.sp
+The \fBlzjb\fR compression algorithm is optimized for performance while
+providing decent data compression.
+.sp
+The \fBlz4\fR compression algorithm is a high-performance replacement
+for the \fBlzjb\fR algorithm. It features significantly faster
+compression and decompression, as well as a moderately higher
+compression ratio than \fBlzjb\fR, but can only be used on pools with
+the \fBlz4_compress\fR feature set to \fIenabled\fR. See
+\fBzpool-features\fR(5) for details on ZFS feature flags and the
+\fBlz4_compress\fR feature.
+.sp
+The \fBgzip\fR compression algorithm uses the same compression as
+the \fBgzip\fR(1) command. You can specify the \fBgzip\fR level by using the
+value \fBgzip-\fR\fIN\fR where \fIN\fR is an integer from 1 (fastest) to 9
+(best compression ratio). Currently, \fBgzip\fR is equivalent to \fBgzip-6\fR
+(which is also the default for \fBgzip\fR(1)). The \fBzle\fR compression
+algorithm compresses runs of zeros.
+.sp
+This property can also be referred to by its shortened column name
+\fBcompress\fR. Changing this property affects only newly-written data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcopies\fR=\fB1\fR | \fB2\fR | \fB3\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the number of copies of data stored for this dataset. These copies are in addition to any redundancy provided by the pool, for example, mirroring or RAID-Z. The copies are stored on different disks, if possible. The space used by multiple copies is charged to the associated file and dataset, changing the \fBused\fR property and counting against quotas and reservations.
+.sp
+Changing this property only affects newly-written data.
+.sp
+Remember that \fBZFS\fR will not import a pool with a missing top-level vdev. Do NOT create, for example, a two-disk, striped pool and set \fBcopies=\fR\fI2\fR on some datasets thinking you have setup redundancy for them. When one disk dies, you will not be able to import the pool and will have lost all of your data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdedup\fR=\fBoff\fR | \fBon\fR | \fBverify\fR | \fBsha256\fR[,\fBverify\fR]\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether deduplication is in effect for a dataset. The default value is \fBoff\fR. The default checksum used for deduplication is \fBsha256\fR (subject to change). When \fBdedup\fR is enabled, the \fBdedup\fR checksum algorithm overrides the \fBchecksum\fR property. Setting the value to \fBverify\fR is equivalent to specifying \fBsha256,verify\fR.
+.sp
+If the property is set to \fBverify\fR, then, whenever two blocks have the same signature, ZFS will do a byte-for-byte comparison with the existing block to ensure that the contents are identical.
+.sp
+Unless necessary, deduplication should NOT be enabled on a system. See \fBDeduplication\fR above.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdevices\fR=\fBon\fR | \fBoff\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether device nodes can be opened on this file system. The default value is \fBon\fR.
+.sp
+The values \fBon\fR and \fBoff\fR are equivalent to the \fBdev\fR and \fBnodev\fR mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdnodesize\fR=\fBlegacy\fR | \fBauto\fR | \fB1k\fR | \fB2k\fR | \fB4k\fR | \fB8k\fR | \fB16k\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specifies a compatibility mode or literal value for the size of dnodes
+in the file system. The default value is \fBlegacy\fR. Setting this
+property to a value other than \fBlegacy\fR requires the
+\fBlarge_dnode\fR pool feature to be enabled.
+.sp
+Consider setting \fBdnodesize\fR to \fBauto\fR if the dataset uses the
+\fBxattr=sa\fR property setting and the workload makes heavy use of
+extended attributes. This may be applicable to SELinux-enabled systems,
+Lustre servers, and Samba servers, for example. Literal values are
+supported for cases where the optimal size is known in advance and for
+performance testing.
+.sp
+Leave \fBdnodesize\fR set to \fBlegacy\fR if you need to receive
+a \fBzfs send\fR stream of this dataset on a pool that doesn't enable
+the \fBlarge_dnode\fR feature, or if you need to import this pool on a
+system that doesn't support the \fBlarge_dnode\fR feature.
+.sp
+This property can also be referred to by its shortened column name,
+\fBdnsize\fR.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fBexec\fR=\fBon\fR | \fBoff\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether processes can be executed from within this file system. The default value is \fBon\fR.
+.sp
+The values \fBon\fR and \fBoff\fR are equivalent to the \fBexec\fR and \fBnoexec\fR mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmlslabel\fR=\fBnone\fR\fR | \fIlabel\fR
+.ad
+.sp .6
+.RS 4n
+The \fBmlslabel\fR property is a sensitivity label that determines if a dataset  can be mounted in a zone on a system with Trusted Extensions enabled. If the labeled dataset matches the labeled zone, the dataset can be mounted  and accessed from the labeled zone.
+.sp
+When the \fBmlslabel\fR property is not set, the default value is \fBnone\fR. Setting the  \fBmlslabel\fR property to \fBnone\fR is equivalent to removing the property.
+.sp
+The \fBmlslabel\fR property can be modified only when Trusted Extensions is enabled and only with appropriate privilege. Rights to modify it cannot be delegated. When changing a label to a higher label or setting the initial dataset label, the \fB{PRIV_FILE_UPGRADE_SL}\fR privilege is required. When changing a label to a lower label or the default (\fBnone\fR), the \fB{PRIV_FILE_DOWNGRADE_SL}\fR privilege is required. Changing the dataset to labels other than the default can be done only when the dataset is not mounted. When a dataset with the default label is mounted into a labeled-zone, the mount operation automatically sets the \fBmlslabel\fR property to the label of that zone.
+.sp
+When Trusted Extensions is \fBnot\fR enabled, only datasets with the default label (\fBnone\fR) can be mounted.
+.sp
+Zones are a Solaris feature and are not relevant on Linux.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfilesystem_limit\fR=\fBnone\fR\fR | \fIcount\fR
+.ad
+.sp .6
+.RS 4n
+Limits the number of filesystems and volumes that can exist under this point in
+the dataset tree.  The limit is not enforced if the user is allowed to change
+the limit. Setting a filesystem_limit on a descendent of a filesystem that
+already has a filesystem_limit does not override the ancestor's filesystem_limit,
+but rather imposes an additional limit. This feature must be enabled to be used
+(see \fBzpool-features\fR(5)).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmountpoint\fR=\fIpath\fR | \fBnone\fR | \fBlegacy\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the mount point used for this file system. See the "Mount Points" section for more information on how this property is used.
+.sp
+When the \fBmountpoint\fR property is changed for a file system, the file system and any children that inherit the mount point are unmounted. If the new value is \fBlegacy\fR, then they remain unmounted. Otherwise, they are automatically remounted in the new location if the property was previously \fBlegacy\fR or \fBnone\fR, or if they were mounted before the property was changed. In addition, any shared file systems are unshared and shared in the new location.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBnbmand\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether the file system should be mounted with \fBnbmand\fR (Non Blocking mandatory locks). This is used for \fBCIFS\fR clients. Changes to this property only take effect when the file system is umounted and remounted. See \fBmount\fR(1M) on a Solaris system for more information on \fBnbmand\fR mounts.
+.sp
+The values \fBon\fR and \fBoff\fR are equivalent to the \fBnbmand\fR and \fBnonbmand\fR mount options.
+.sp
+This property is not used on Linux.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBprimarycache\fR=\fBall\fR | \fBnone\fR | \fBmetadata\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls what is cached in the primary cache (ARC). If this property is set to \fBall\fR, then both user data and metadata is cached. If this property is set to \fBnone\fR, then neither user data nor metadata is cached. If this property is set to \fBmetadata\fR, then only metadata is cached. The default value is \fBall\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBquota\fR=\fBnone\fR | \fIsize\fR\fR
+.ad
+.sp .6
+.RS 4n
+Limits the amount of space a dataset and its descendents can consume. This property enforces a hard limit on the amount of space used. This includes all space consumed by descendents, including file systems and snapshots. Setting a quota on a descendent of a dataset that already has a quota does not override the ancestor's quota, but rather imposes an additional limit.
+.sp
+Quotas cannot be set on volumes, as the \fBvolsize\fR property acts as an implicit quota.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsnapshot_limit\fR=\fBnone\fR\fR | \fIcount\fR
+.ad
+.sp .6
+.RS 4n
+Limits the number of snapshots that can be created on a dataset and its
+descendents. Setting a snapshot_limit on a descendent of a dataset that already
+has a snapshot_limit does not override the ancestor's snapshot_limit, but
+rather imposes an additional limit. The limit is not enforced if the user is
+allowed to change the limit. For example, this means that recursive snapshots
+taken from the global zone are counted against each delegated dataset within
+a zone. This feature must be enabled to be used (see \fBzpool-features\fR(5)).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBuserquota@\fR\fIuser\fR=\fBnone\fR | \fIsize\fR\fR
+.br
+\fB\fBuserobjquota@\fR\fIuser\fR=\fBnone\fR | \fIcount\fR\fR
+.ad
+.sp .6
+.RS 4n
+Limits the amount of space consumed by the specified user. Similar to the \fBrefquota\fR property, the \fBuserquota\fR space calculation does not include space that is used by descendent datasets, such as snapshots and clones. User space consumption is identified by the \fBuserspace@\fR\fIuser\fR property. See the \fBzfs userspace\fR subcommand for more information.
+.sp
+Enforcement of user quotas may be delayed by several seconds. This delay means that a user might exceed their quota before the system notices that they are over quota and begins to refuse additional writes with the \fBEDQUOT\fR error message.
+.sp
+Unprivileged users can only access their own groups' space usage. The root user, or a user who has been granted the \fBuserquota\fR privilege with \fBzfs allow\fR, can get and set everyone's quota.
+.sp
+This property is not available on volumes, on file systems before version 4, or on pools before version 15. The \fBuserquota@\fR... properties are not displayed by \fBzfs get all\fR. The user's name must be appended after the \fB@\fR symbol, using one of the following forms:
+.RS +4
+.TP
+.ie t \(bu
+.el o
+\fIPOSIX name\fR (for example, \fBjoe\fR)
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+\fIPOSIX numeric ID\fR (for example, \fB789\fR)
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+\fISID name\fR (for example, \fBjoe.smith@mydomain\fR)
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+\fISID numeric ID\fR (for example, \fBS-1-123-456-789\fR)
+.RE
+.RE
+Files created on Linux always have POSIX owners.
+
+.RS 4
+The \fBuserobjquota\fR is similar to \fBuserquota\fR but it limits the number of objects a \fIuser\fR can create.
+Please refer to \fBuserobjused\fR for more information about how ZFS counts object usage.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBgroupquota@\fR\fIgroup\fR=\fBnone\fR\fR | \fIsize\fR
+.br
+\fB\fBgroupobjquota@\fR\fIgroup\fR=\fBnone\fR\fR | \fIcount\fR
+.ad
+.sp .6
+.RS 4n
+Limits the amount of space consumed by the specified group. Group space consumption is identified by the \fBuserquota@\fR\fIuser\fR property.
+.sp
+Unprivileged users can access only their own groups' space usage. The root user, or a user who has been granted the \fBgroupquota\fR privilege with \fBzfs allow\fR, can get and set all groups' quotas.
+
+The \fBgroupobjquota\fR is similar to \fBgroupquota\fR but it limits that the \fIgroup\fR can consume \fIcount\fR number of objects at most.
+Please refer to \fBuserobjused\fR for more information about how zfs counts object usage.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBreadonly\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether this dataset can be modified. The default value is \fBoff\fR.
+.sp
+This property can also be referred to by its shortened column name, \fBrdonly\fR.
+.sp
+The values \fBon\fR and \fBoff\fR are equivalent to the \fBro\fR and \fBrw\fR mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBrecordsize\fR=\fIsize\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specifies a suggested block size for files in the file system. This property is designed solely for use with database workloads that access files in fixed-size records. \fBZFS\fR automatically tunes block sizes according to internal algorithms optimized for typical access patterns.
+.sp
+For databases that create very large files but access them in small random chunks, these algorithms may be suboptimal. Specifying a \fBrecordsize\fR greater than or equal to the record size of the database can result in significant performance gains. Use of this property for general purpose file systems is strongly discouraged, and may adversely affect performance.
+.sp
+Any power of two from 512B to 1MiB is valid. The default is 128KiB. Values larger than 128KiB require the pool have the \fBlarge_blocks\fR feature enabled. See \fBzpool-features\fR(5) for details on ZFS feature flags and the \fBlarge_blocks\fR feature.
+.sp
+Changing the file system's \fBrecordsize\fR affects only files created afterward; existing files are unaffected.
+.sp
+This property can also be referred to by its shortened column name, \fBrecsize\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBredundant_metadata\fR=\fBall\fR | \fBmost\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls what types of metadata are stored redundantly.  ZFS stores an
+extra copy of metadata, so that if a single block is corrupted, the
+amount of user data lost is limited.  This extra copy is in addition to
+any redundancy provided at the pool level (e.g. by mirroring or RAID-Z),
+and is in addition to an extra copy specified by the \fBcopies\fR
+property (up to a total of 3 copies).  For example if the pool is
+mirrored, \fBcopies\fR=2, and \fBredundant_metadata\fR=most, then ZFS
+stores 6 copies of most metadata, and 4 copies of data and some
+metadata.
+.sp
+When set to \fBall\fR, ZFS stores an extra copy of all metadata.  If a
+single on-disk block is corrupt, at worst a single block of user data
+(which is \fBrecordsize\fR bytes long) can be lost.
+.sp
+When set to \fBmost\fR, ZFS stores an extra copy of most types of
+metadata.  This can improve performance of random writes, because less
+metadata must be written.  In practice, at worst about 100 blocks (of
+\fBrecordsize\fR bytes each) of user data can be lost if a single
+on-disk block is corrupt.  The exact behavior of which metadata blocks
+are stored redundantly may change in future releases.
+.sp
+The default value is \fBall\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBrefquota\fR=\fBnone\fR | \fIsize\fR\fR
+.ad
+.sp .6
+.RS 4n
+Limits the amount of space a dataset can consume. This property enforces a hard limit on the amount of space used. This hard limit does not include space used by descendents, including file systems and snapshots.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBrefreservation\fR=\fBnone\fR | \fIsize\fR\fR
+.ad
+.sp .6
+.RS 4n
+The minimum amount of space guaranteed to a dataset, not including its descendents. When the amount of space used is below this value, the dataset is treated as if it were taking up the amount of space specified by \fBrefreservation\fR. The \fBrefreservation\fR reservation is accounted for in the parent datasets' space used, and counts against the parent datasets' quotas and reservations.
+.sp
+If \fBrefreservation\fR is set, a snapshot is only allowed if there is enough free pool space outside of this reservation to accommodate the current number of \fBreferenced\fR bytes in the dataset (which are the bytes to be referenced by the snapshot). This is necessary to continue to provide the \fBrefreservation\fRguarantee to the dataset.
+.sp
+For volumes, see also \fBvolsize\fR.
+.sp
+This property can also be referred to by its shortened column name, \fBrefreserv\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBrelatime\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the manner in which the access time is updated when \fBatime=on\fR is set.  Turning this property \fBon\fR causes the access time to be updated relative to the modify or change time.  Access time is only updated if the previous access time was earlier than the current modify or change time or if the existing access time hasn't been updated within the past 24 hours.  The default value is \fBoff\fR.
+.sp
+The values \fBon\fR and \fBoff\fR are equivalent to the \fBrelatime\fR and \fBnorelatime\fR mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBreservation\fR=\fBnone\fR | \fIsize\fR\fR
+.ad
+.sp .6
+.RS 4n
+The minimum amount of space guaranteed to a dataset and its descendents. When the amount of space used is below this value, the dataset is treated as if it were taking up the amount of space specified by its reservation. Reservations are accounted for in the parent datasets' space used, and count against the parent datasets' quotas and reservations.
+.sp
+This property can also be referred to by its shortened column name, \fBreserv\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsecondarycache\fR=\fBall\fR | \fBnone\fR | \fBmetadata\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls what is cached in the secondary cache (L2ARC). If this property is set to \fBall\fR, then both user data and metadata is cached. If this property is set to \fBnone\fR, then neither user data nor metadata is cached. If this property is set to \fBmetadata\fR, then only metadata is cached. The default value is \fBall\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsetuid\fR=\fBon\fR | \fBoff\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether the setuid bit is respected for the file system. The default value is \fBon\fR.
+.sp
+The values \fBon\fR and \fBoff\fR are equivalent to the \fBsuid\fR and \fBnosuid\fR mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsharesmb\fR=\fBoff\fR | \fBon\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether the file system is shared by using \fBSamba USERSHARES\fR, and what options are to be used. Otherwise, the file system is automatically shared and unshared with the \fBzfs share\fR and \fBzfs unshare\fR commands. If the property is set to \fBon\fR, the \fBnet\fR(8) command is invoked to create a \fBUSERSHARE\fR.
+.sp
+Because \fBSMB\fR shares requires a resource name, a unique resource name is constructed from the dataset name. The constructed name is a copy of the dataset name except that the characters in the dataset name, which would be invalid in the resource name, are replaced with underscore (\fB_\fR) characters. Linux does not currently support additional options which might be available on Solaris.
+.sp
+If the \fBsharesmb\fR property is set to \fBoff\fR, the file systems are unshared.
+.sp
+In Linux, the share is created with the ACL (Access Control List) "Everyone:F" ("F" stands for "full permissions", ie. read and write permissions) and no guest access (which means Samba must be able to authenticate a real user, system passwd/shadow, LDAP or smbpasswd based) by default. This means that any additional access control (disallow specific user specific access etc) must be done on the underlaying filesystem.
+.sp
+.in +2
+Example to mount a SMB filesystem shared through ZFS (share/tmp):
+Note that a user and his/her password \fBmust\fR be given!
+.sp
+.in +2
+smbmount //127.0.0.1/share_tmp /mnt/tmp -o user=workgroup/turbo,password=obrut,uid=1000
+.in -2
+.in -2
+.sp
+.ne 2
+.na
+\fBMinimal /etc/samba/smb.conf configuration\fR
+.sp
+.in +2
+* Samba will need to listen to 'localhost' (127.0.0.1) for the zfs utilities to communicate with Samba.  This is the default behavior for most Linux distributions.
+.sp
+* Samba must be able to authenticate a user. This can be done in a number of ways, depending on if using the system password file, LDAP or the Samba specific smbpasswd file. How to do this is outside the scope of this manual. Please refer to the smb.conf(5) manpage for more information.
+.sp
+* See the \fBUSERSHARE\fR section of the \fBsmb.conf\fR(5) man page for all configuration options in case you need to modify any options to the share afterwards. Do note that any changes done with the 'net' command will be undone if the share is every unshared (such as at a reboot etc). In the future, ZoL will be able to set specific options directly using sharesmb=<option>.
+.sp
+.in -2
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsharenfs\fR=\fBoff\fR | \fBon\fR | \fIopts\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether the file system is shared via \fBNFS\fR, and what options are used. A file system with a \fBsharenfs\fR property of \fBoff\fR is managed with the \fBexportfs\fR(8) command and entries in \fB/etc/exports\fR file. Otherwise, the file system is automatically shared and unshared with the \fBzfs share\fR and \fBzfs unshare\fR commands. If the property is set to \fBon\fR, the dataset is shared using the \fBexportfs\fR(8) command in the following manner (see \fBexportfs\fR(8) for the meaning of the different options):
+.sp
+.in +4
+.nf
+/usr/sbin/exportfs -i -o sec=sys,rw,no_subtree_check,no_root_squash,mountpoint *:<mountpoint of dataset>
+.fi
+.in -4
+.sp
+Otherwise, the \fBexportfs\fR(8) command is invoked with options equivalent to the contents of this property.
+.sp
+When the \fBsharenfs\fR property is changed for a dataset, the dataset and any children inheriting the property are re-shared with the new options, only if the property was previously \fBoff\fR, or if they were shared before the property was changed. If the new property is \fBoff\fR, the file systems are unshared.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlogbias\fR=\fBlatency\fR | \fBthroughput\fR\fR
+.ad
+.sp .6
+.RS 4n
+Provide a hint to ZFS about handling of synchronous requests in this dataset. If \fBlogbias\fR is set to \fBlatency\fR (the default), ZFS will use pool log devices (if configured) to handle the requests at low latency. If \fBlogbias\fR is set to \fBthroughput\fR, ZFS will not use configured pool log devices. ZFS will instead optimize synchronous operations for global pool throughput and efficient use of resources.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsnapdev\fR=\fBhidden\fR | \fBvisible\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether the snapshots devices of zvol's are hidden or visible. The default value is \fBhidden\fR.
+.sp
+In this context, hidden does not refer to the concept of hiding files or directories by starting their name with a "." character. Even with \fBvisible\fR, the directory is still named \fB\&.zfs\fR. Instead, \fBhidden\fR means that the directory is not returned by \fBreaddir\fR(3), so it doesn't show up in directory listings done by any program, including \fBls\fR \fB-a\fR. It is still possible to chdir(2) into the directory, so \fBcd\fR \fB\&.zfs\fR works even with \fBhidden\fR. This unusual behavior is to protect against unwanted effects from applications recursing into the special \fB\&.zfs\fR directory.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsnapdir\fR=\fBhidden\fR | \fBvisible\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether the \fB\&.zfs\fR directory is hidden or visible in the root of the file system as discussed in the "Snapshots" section. The default value is \fBhidden\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsync\fR=\fBstandard\fR | \fBalways\fR | \fBdisabled\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the behavior of synchronous requests (e.g. fsync, O_DSYNC).
+\fBstandard\fR is the POSIX specified behavior of ensuring all synchronous
+requests are written to stable storage and all devices are flushed to ensure
+data is not cached by device controllers (this is the default). \fBalways\fR
+causes every file system transaction to be written and flushed before its
+system call returns. This has a large performance penalty. \fBdisabled\fR
+disables synchronous requests. File system transactions are only committed to
+stable storage periodically. This option will give the highest performance.
+However, it is very dangerous as ZFS would be ignoring the synchronous
+transaction demands of applications such as databases or NFS.  Administrators
+should only use this option when the risks are understood.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBversion\fR=\fB5\fR | \fB4\fR | \fB3\fR | \fB2\fR | \fB1\fR | \fBcurrent\fR\fR
+.ad
+.sp .6
+.RS 4n
+The on-disk version of this file system, which is independent of the pool version. This property can only be set to later supported versions. The value \fBcurrent\fR automatically selects the latest supported version. See the \fBzfs upgrade\fR command.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBvolsize\fR=\fIsize\fR\fR
+.ad
+.sp .6
+.RS 4n
+For volumes, specifies the logical size of the volume. By default, creating a volume establishes a \fBrefreservation\fR equal to the volume size plus the metadata required for a fully-written volume. (For pool version 8 or lower, a \fBreservation\fR is set instead.) Any changes to \fBvolsize\fR are reflected in an equivalent change to the \fBrefreservation\fR. The \fBvolsize\fR can only be set to a multiple of \fBvolblocksize\fR, and cannot be zero.
+.sp
+Without the reservation, the volume could run out of space, resulting in undefined behavior or data corruption, depending on how the volume is used. These effects can also occur when the volume size is changed while it is in use (particularly when shrinking the size). Extreme care should be used when adjusting the volume size.
+.sp
+A "sparse volume" (also known as "thin provisioning") can be created by specifying the \fB-s\fR option to the \fBzfs create -V\fR command, or by removing (or changing) the \fBrefreservation\fR after the volume has been created. A "sparse volume" is a volume where the \fBrefreservation\fR is unset or less then the volume size. Consequently, writes to a sparse volume can fail with \fBENOSPC\fR when the pool is low on space. For a sparse volume, changes to \fBvolsize\fR are not reflected in the reservation.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBvscan\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether regular files should be scanned for viruses when a file is opened and closed. In addition to enabling this property, the virus scan service must also be enabled for virus scanning to occur. The default value is \fBoff\fR.
+.sp
+This property is not used on Linux.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBxattr\fR=\fBon\fR | \fBoff\fR | \fBsa\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether extended attributes are enabled for this file system.  Two
+styles of extended attributes are supported either directory based or system
+attribute based.
+.sp
+The default value of \fBon\fR enables directory based extended attributes.
+This style of xattr imposes no practical limit on either the size or number of
+xattrs which may be set on a file.  Although under Linux the \fBgetxattr\fR(2)
+and \fBsetxattr\fR(2) system calls limit the maximum xattr size to 64K.  This
+is the most compatible style of xattr and it is supported by the majority of
+ZFS implementations.
+.sp
+System attribute based xattrs may be enabled by setting the value to \fBsa\fR.
+The key advantage of this type of xattr is improved performance.  Storing
+xattrs as system attributes significantly decreases the amount of disk IO
+required.  Up to 64K of xattr data may be stored per file in the space reserved
+for system attributes.  If there is not enough space available for an xattr then
+it will be automatically written as a directory based xattr.  System attribute
+based xattrs are not accessible on platforms which do not support the
+\fBxattr=sa\fR feature.
+.sp
+The use of system attribute based xattrs is strongly encouraged for users of
+SELinux or Posix ACLs.  Both of these features heavily rely of xattrs and
+benefit significantly from the reduced xattr access time.
+.sp
+The values \fBon\fR and \fBoff\fR are equivalent to the \fBxattr\fR and \fBnoxattr\fR mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzoned\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether the dataset is managed from a non-global zone. Zones are a Solaris feature and are not relevant on Linux. The default value is \fBoff\fR.
+.RE
+
+.sp
+.LP
+The following three properties cannot be changed after the file system is created, and therefore, should be set when the file system is created. If the properties are not set with the \fBzfs create\fR or \fBzpool create\fR commands, these properties are inherited from the parent dataset. If the parent dataset lacks these properties due to having been created prior to these features being supported, the new file system will have the default values for these properties.
+.sp
+.ne 2
+.na
+\fB\fBcasesensitivity\fR=\fBsensitive\fR | \fBinsensitive\fR | \fBmixed\fR\fR
+.ad
+.sp .6
+.RS 4n
+Indicates whether the file name matching algorithm used by the file system should be case-sensitive, case-insensitive, or allow a combination of both styles of matching. The default value for the \fBcasesensitivity\fR property is \fBsensitive\fR. Traditionally, UNIX and POSIX file systems have case-sensitive file names.
+.sp
+The \fBmixed\fR value for the \fBcasesensitivity\fR property indicates that the file system can support requests for both case-sensitive and case-insensitive matching behavior. Currently, case-insensitive matching behavior on a file system that supports mixed behavior is limited to the Solaris CIFS server product.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBnormalization\fR = \fBnone\fR | \fBformC\fR | \fBformD\fR | \fBformKC\fR | \fBformKD\fR\fR
+.ad
+.sp .6
+.RS 4n
+Indicates whether the file system should perform a Unicode normalization of file names whenever two file names are compared, and which normalization algorithm should be used.
+.sp
+If this property is set to a value other than \fBnone\fR (the default), and the \fButf8only\fR property was left unspecified, the \fButf8only\fR property is automatically set to \fBon\fR. See the cautionary note in the \fButf8only\fR section before modifying \fBnormalization\fR.
+.sp
+File names are always stored unmodified; names are normalized as part of any comparison process. Thus, \fBformC\fR and \fBformD\fR are equivalent, as are \fBformKC\fR and \fBformKD\fR. Given that, only \fBformD\fR and \fBformKD\fR make sense, as they are slightly faster because they avoid the additional canonical composition step.
+.\" unicode.org says it's possible to quickly detect if a string is already in a given form. Since most text (basically everything but OS X) is already in NFC, this means formC could potentially be made faster. But the additional complexity probably isn't worth the likely undetectable in practice speed improvement.
+.sp
+The practical impact of this property is: \fBnone\fR (like traditional filesystems) allows a directory to contain two files that appear (to humans) to have the same name. The other options solve this problem, for different definitions of "the same". If you need to solve this problem and are not sure what to choose,\fBformD\fR.
+.sp
+This property cannot be changed after the file system is created.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fButf8only\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Indicates whether the file system should reject file names that include characters that are not present in the \fBUTF-8\fR character set. If this property is explicitly set to \fBoff\fR, the \fBnormalization\fR property must either not be explicitly set or be set to \fBnone\fR. The default value for the \fButf8only\fR property is \fBoff\fR.
+.sp
+Note that forcing the use of \fBUTF-8\fR filenames may cause pain for users. For example, extracting files from an archive will fail if the filenames within the archive are encoded in another character set.
+.sp
+If you are thinking of setting this (to \fBon\fR), you probably want to set \fBnormalization\fR=\fBformD\fR which will set this property to \fBon\fR implicitly.
+.sp
+This property cannot be changed after the file system is created.
+.RE
+
+.sp
+.LP
+The \fBcasesensitivity\fR, \fBnormalization\fR, and \fButf8only\fR properties are also permissions that can be assigned to non-privileged users by using the \fBZFS\fR delegated administration feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcontext\fR=\fBnone\fR | \fISELinux_User:SElinux_Role:Selinux_Type:Sensitivity_Level\fR\fR
+.ad
+.sp .6
+.RS 4n
+This flag sets the SELinux context for all files in the filesystem under the mountpoint for that filesystem.  See \fBselinux\fR(8) for more information.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfscontext\fR=\fBnone\fR | \fISELinux_User:SElinux_Role:Selinux_Type:Sensitivity_Level\fR\fR
+.ad
+.sp .6
+.RS 4n
+This flag sets the SELinux context for the filesystem being mounted.  See \fBselinux\fR(8) for more information.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdefcontext\fR=\fBnone\fR | \fISELinux_User:SElinux_Role:Selinux_Type:Sensitivity_Level\fR\fR
+.ad
+.sp .6
+.RS 4n
+This flag sets the SELinux context for unlabeled files.  See \fBselinux\fR(8) for more information.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBrootcontext\fR=\fBnone\fR | \fISELinux_User:SElinux_Role:Selinux_Type:Sensitivity_Level\fR\fR
+.ad
+.sp .6
+.RS 4n
+This flag sets the SELinux context for the root inode of the filesystem.  See \fBselinux\fR(8) for more information.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBoverlay\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Allow mounting on a busy directory or a directory which already contains files/directories. This is the default mount behavior for Linux filesystems.  However, for consistency with ZFS on other platforms overlay mounts are disabled by default.  Set \fBoverlay=on\fR to enable overlay mounts.
+.RE
+
+.SS "Temporary Mount Point Properties"
+.LP
+When a file system is mounted, either through \fBmount\fR(8) for legacy mounts or the \fBzfs mount\fR command for normal file systems, its mount options are set according to its properties. The correlation between properties and mount options is as follows:
+.sp
+.in +2
+.nf
+    PROPERTY                MOUNT OPTION
+     atime                   atime/noatime
+     canmount                auto/noauto
+     devices                 devices/nodevices
+     exec                    exec/noexec
+     readonly                ro/rw
+     relatime                relatime/norelatime
+     setuid                  suid/nosuid
+     xattr                   xattr/noxattr
+     nbmand                  nbmand/nonbmand (Solaris)
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+In addition, these options can be set on a per-mount basis using the \fB-o\fR option, without affecting the property that is stored on disk. The values specified on the command line override the values stored in the dataset. The \fB-nosuid\fR option is an alias for \fBnodevices,nosetuid\fR. These properties are reported as "temporary" by the \fBzfs get\fR command. If the properties are changed while the dataset is mounted, the new setting overrides any temporary settings.
+.SS "User Properties"
+.LP
+In addition to the standard native properties, \fBZFS\fR supports arbitrary user properties. User properties have no effect on \fBZFS\fR behavior, but applications or administrators can use them to annotate datasets (file systems, volumes, and snapshots). Unlike native properties, user properties are editable on snapshots.
+.sp
+.LP
+User property names must contain a colon (\fB:\fR) character to distinguish them from native properties. They may contain lowercase letters, numbers, and the following punctuation characters: colon (\fB:\fR), dash (\fB-\fR), period (\fB\&.\fR), and underscore (\fB_\fR). The expected convention is that the property name is divided into two portions such as \fImodule\fR\fB:\fR\fIproperty\fR, but this namespace is not enforced by \fBZFS\fR. User property names can be at most 256 characters, and cannot begin with a dash (\fB-\fR).
+.sp
+.LP
+When making programmatic use of user properties, it is strongly suggested to use a reversed \fBDNS\fR domain name for the \fImodule\fR component of property names to reduce the chance that two independently-developed packages use the same property name for different purposes. For example, property names beginning with \fBcom.sun\fR. are reserved for definition by Oracle Corporation (which acquired Sun Microsystems).
+.sp
+.LP
+The values of user properties are arbitrary strings, are always inherited, and are never validated. All of the commands that operate on properties (\fBzfs list\fR, \fBzfs get\fR, \fBzfs set\fR, and so forth) can be used to manipulate both native properties and user properties. Use the \fBzfs inherit\fR command to clear a user property. If the property is not defined in any parent dataset, it is removed entirely. Property values are limited to 1024 characters.
+.SS "ZFS Volumes as Swap"
+.LP
+\fBZFS\fR volumes may be used as Linux swap devices.  After creating the volume
+with the \fBzfs create\fR command set up and enable the swap area using the
+\fBmkswap\fR(8) and \fBswapon\fR(8) commands.  Do not swap to a file on a
+\fBZFS\fR file system. A \fBZFS\fR swap file configuration is not supported.
+.SH SUBCOMMANDS
+.LP
+All subcommands that modify state are logged persistently to the pool in their original form. The log can be viewed with \fBzpool history\fR.
+.sp
+.ne 2
+.na
+\fB\fBzfs ?\fR\fR
+.ad
+.sp .6
+.RS 4n
+Displays a help message.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs create\fR [\fB-p\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ... \fIfilesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates a new \fBZFS\fR file system. The file system is automatically mounted according to the \fBmountpoint\fR and \fBcanmount\fR properties.
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates all the non-existing parent datasets. Datasets created in this manner inherit their properties; any property specified on the command line using the \fB-o\fR option applies only to the final child file system. If the target filesystem already exists, the operation completes successfully and no properties are changed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty\fR=\fIvalue\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the specified property as if the command \fBzfs set\fR \fIproperty\fR=\fIvalue\fR was invoked at the same time the dataset was created. Any editable \fBZFS\fR property can also be set at creation time. Multiple \fB-o\fR options can be specified. An error results if the same property is specified in multiple \fB-o\fR options.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs create\fR [\fB-ps\fR] [\fB-b\fR \fIblocksize\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ... \fB-V\fR \fIsize\fR \fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates a volume of the given size. The volume is exported as a block device in \fB/dev/zvol/\fR\fIpath\fR, where \fIpath\fR is the name of the volume in the \fBZFS\fR namespace. The size represents the logical size as exported by the device. By default, a \fBrefreservation\fR is created.
+.sp
+\fIsize\fR is automatically rounded up to the nearest 128KiB to ensure that the volume has an integral number of blocks regardless of \fIblocksize\fR.
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates all the non-existing parent datasets as file systems. Datasets created in this manner inherit their properties; any property specified on the command line using the \fB-o\fR option applies only to the final child volume. If the target volume already exists, the operation completes successfully and no properties are changed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-s\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates a sparse volume by omitting the automatic creation of a \fBrefreservation\fR. See \fBvolsize\fR in the Native Properties section for more information about sparse volumes. If this option is specified in conjunction with \fB-o\fR \fBrefreservation\fR, the \fBrefreservation\fR will be honored; this allows for a partial reservation on a sparse volume.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty\fR=\fIvalue\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the specified property as if the \fBzfs set\fR \fIproperty\fR=\fIvalue\fR command was invoked at the same time the dataset was created. Any editable \fBZFS\fR property can also be set at creation time. Multiple \fB-o\fR options can be specified. An error results if the same property is specified in multiple \fB-o\fR options.
+.sp
+If \fB-o\fR \fBvolsize\fR is provided, the resulting behavior is undefined; it conflicts with the -V option, which is required in this mode.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-b\fR \fIblocksize\fR\fR
+.ad
+.sp .6
+.RS 4n
+Equivalent to \fB-o\fR \fBvolblocksize\fR=\fIblocksize\fR. If this option is specified in conjunction with \fB-o\fR \fBvolblocksize\fR, the resulting behavior is undefined.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs destroy\fR [\fB-fnpRrv\fR] \fIfilesystem\fR|\fIvolume\fR
+.ad
+.sp .6
+.RS 4n
+Destroys the given dataset. By default, the command unshares any file systems that are currently shared, unmounts any file systems that are currently mounted, and refuses to destroy a dataset that has active dependents (children or clones).
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively destroy all children.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-R\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively destroy all dependents, including cloned file systems outside the target hierarchy.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.sp .6
+.RS 4n
+Force an unmount of any file systems using the \fBzfs unmount -f\fR command. This option has no effect on non-file systems or unmounted file systems.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do a dry-run ("No-op") deletion.  No data will be deleted.  This is
+useful in conjunction with the \fB-v\fR or \fB-p\fR flags to determine what
+data would be deleted.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print machine-parsable verbose information about the deleted data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print verbose information about the deleted data.
+.RE
+.sp
+
+Extreme care should be taken when applying either the \fB-r\fR or the \fB-R\fR options, as they can destroy large portions of a pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs destroy\fR [\fB-dnpRrv\fR] \fIfilesystem\fR|\fIvolume\fR@\fIsnap\fR[%\fIsnap\fR][,...]
+.ad
+.sp .6
+.RS 4n
+The specified snapshots are destroyed immediately if they have no clones and the user-initiated reference count is zero (i.e. there are no holds set with \fBzfs hold\fR). If these conditions are not met, this command returns an error, unless \fB-d\fR is supplied.
+.sp
+An inclusive range of snapshots may be specified by separating the
+first and last snapshots with a percent sign.
+The first and/or last snapshots may be left blank, in which case the
+filesystem's oldest or newest snapshot will be implied.
+.sp
+Multiple snapshots
+(or ranges of snapshots) of the same filesystem or volume may be specified
+in a comma-separated list of snapshots.
+Only the snapshot's short name (the
+part after the \fB@\fR) should be specified when using a range or
+comma-separated list to identify multiple snapshots.
+.sp
+.ne 2
+.na
+\fB\fB-d\fR\fR
+.ad
+.sp .6
+.RS 4n
+If a snapshot does not qualify for immediate destruction, rather than returning an error, it is marked for deferred destruction. In this state, it exists as a usable, visible snapshot until both of the preconditions listed above are met, at which point it is destroyed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Destroy (or mark for deferred destruction) all snapshots with this name in descendent file systems.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-R\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively destroy all clones of these snapshots, including the clones,
+snapshots, and children.  If this flag is specified, the \fB-d\fR flag will
+have no effect.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do a dry-run ("No-op") deletion.  No data will be deleted.  This is
+useful in conjunction with the \fB-v\fR or \fB-p\fR flags to determine what
+data would be deleted.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print machine-parsable verbose information about the deleted data.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print verbose information about the deleted data.
+.RE
+
+.sp
+Extreme care should be taken when applying either the \fB-r\fR or the \fB-R\fR
+options, as they can destroy large portions of a pool and cause unexpected
+behavior for mounted file systems in use.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs destroy\fR \fIfilesystem\fR|\fIvolume\fR#\fIbookmark\fR
+.ad
+.sp .6
+.RS 4n
+The given bookmark is destroyed.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs snapshot\fR [\fB-r\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ... \fIfilesystem@snapname\fR|\fIvolume@snapname\fR\fR ...
+.ad
+.sp .6
+.RS 4n
+Creates snapshots with the given names. All previous modifications by successful system calls to the file system are part of the snapshots. Snapshots are taken atomically, so that all snapshots correspond to the same moment in time. See the "Snapshots" section for details.
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively create snapshots of all descendent datasets.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty\fR=\fIvalue\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the specified property; see \fBzfs set\fR for details.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs rollback\fR [\fB-rRf\fR] \fIsnapshot\fR\fR
+.ad
+.sp .6
+.RS 4n
+Roll back the given dataset to a previous snapshot. When a dataset is rolled back, all data that has changed since the snapshot is discarded, and the dataset reverts to the state at the time of the snapshot. By default, the command refuses to roll back to a snapshot other than the most recent one. In order to do so, all intermediate snapshots and bookmarks must be destroyed by specifying the \fB-r\fR option.
+.sp
+The \fB-rR\fR options do not recursively destroy the child snapshots of a recursive snapshot. Only direct snapshots of the specified filesystem are destroyed by either of these options. To completely roll back a recursive snapshot, you must rollback the individual child snapshots.
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Destroy any snapshots and bookmarks more recent than the one specified.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-R\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively destroy any more recent snapshots and bookmarks, as well as any clones of those snapshots.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.sp .6
+.RS 4n
+Used with the \fB-R\fR option to force an unmount (see \fBzfs unmount -f\fR) of any clone file systems that are to be destroyed.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs clone\fR [\fB-p\fR] [\fB-o\fR \fIproperty\fR=\fIvalue\fR] ... \fIsnapshot\fR \fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates a clone of the given snapshot. See the "Clones" section for details. The target dataset can be located anywhere in the \fBZFS\fR hierarchy, and is created as the same type as the original.
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates all the non-existing parent datasets; see \fBzfs create\fR for details.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty\fR=\fIvalue\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the specified property; see \fBzfs set\fR for details.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs promote\fR \fIclone-filesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+Promotes a clone file system to no longer be dependent on its "origin" snapshot. This makes it possible to destroy the file system that the clone was created from. The clone parent-child dependency relationship is reversed, so that the origin file system becomes a clone of the specified file system.
+.sp
+The snapshot that was cloned, and any snapshots previous to this snapshot, are now owned by the promoted clone. The space they use moves from the origin file system to the promoted clone, so enough space must be available to accommodate these snapshots. No new space is consumed by this operation, but the space accounting is adjusted. The promoted clone must not have any conflicting snapshot names of its own. The \fBzfs rename\fR command can be used to rename any conflicting snapshots.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs rename\fR [\fB-f\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR\fR
+.ad
+.br
+.na
+\fB\fBzfs rename\fR [\fB-fp\fR] \fIfilesystem\fR|\fIvolume\fR \fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Renames the given dataset. The new target can be located anywhere in the \fBZFS\fR hierarchy, with the exception of snapshots. Snapshots can only be renamed within the parent file system or volume. When renaming a snapshot, the parent file system of the snapshot does not need to be specified as part of the second argument. Renamed file systems can inherit new mount points, in which case they are unmounted and remounted at the new mount point.
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates all the nonexistent parent datasets; see \fBzfs create\fR for details.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.sp .6
+.RS 4n
+Force unmount any filesystems that need to be unmounted in the process.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs rename\fR \fB-r\fR \fIsnapshot\fR \fIsnapshot\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively rename the snapshots of all descendent datasets. Snapshots are the only dataset that can be renamed recursively.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs\fR \fBlist\fR [\fB-r\fR|\fB-d\fR \fIdepth\fR] [\fB-Hp\fR] [\fB-o\fR \fIproperty\fR[,\fI\&...\fR]] [ \fB-t\fR \fItype\fR[,\fI\&...\fR]] [ \fB-s\fR \fIproperty\fR ] ... [ \fB-S\fR \fIproperty\fR ] ... [\fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR|\fImountpoint\fR] ...\fR
+.ad
+.sp .6
+.RS 4n
+Lists the property information for the given datasets in tabular form. If a mount point is specified, it can be an absolute pathname or a relative pathname starting with "./"  (e.g. \fBzfs list ./\fR). By default, all file systems and volumes are displayed. Snapshots are displayed if the pool's \fBlistsnapshots\fR property is \fBon\fR (the default is \fBoff\fR). When listing hundreds or thousands of snapshots performance can be improved by restricting the output to only the name.  In that case, it is recommended to use \fB-o name -s name\fR. The following fields are displayed by default: \fBname, used, available, referenced, mountpoint\fR
+.sp
+.ne 2
+.na
+\fB\fB-H\fR\fR
+.ad
+.sp .6
+.RS 4n
+Used for scripting mode. Do not print headers and separate fields by a single tab instead of arbitrary white space.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.sp .6
+.RS 4n
+Display numbers in parsable (exact) values.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively display any children of the dataset on the command line.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-d\fR \fIdepth\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively display any children of the dataset, limiting the recursion to \fIdepth\fR. A depth of \fB1\fR will display only the dataset and its direct children.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty\fR\fR
+.ad
+.sp .6
+.RS 4n
+A comma-separated list of properties to display. The property must be:
+.RS +4
+.TP
+.ie t \(bu
+.el o
+One of the properties described in the "Native Properties" section
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+A user property
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+The value \fBname\fR to display the dataset name
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+The value \fBspace\fR to display space usage properties on file systems and volumes. This is a shortcut for specifying \fB-o name,avail,used,usedsnap,usedds,usedrefreserv,usedchild\fR \fB-t filesystem,volume\fR syntax.
+.RE
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-s\fR \fIproperty\fR\fR
+.ad
+.sp .6
+.RS 4n
+A property for sorting the output by column in ascending order based on the value of the property. The property must be one of the properties described in the "Properties" section, or the special value \fBname\fR to sort by the dataset name. Multiple properties can be specified at one time using multiple \fB-s\fR property options. Multiple \fB-s\fR options are evaluated from left to right in decreasing order of importance.
+.sp
+The following is a list of sorting criteria:
+.RS +4
+.TP
+.ie t \(bu
+.el o
+Numeric types sort in numeric order.
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+String types sort in alphabetical order.
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+Types inappropriate for a row sort that row to the literal bottom, regardless of the specified ordering.
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+If no sorting options are specified the existing behavior of \fBzfs list\fR is preserved.
+.RE
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-S\fR \fIproperty\fR\fR
+.ad
+.sp .6
+.RS 4n
+Same as the \fB-s\fR option, but sorts by property in descending order.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-t\fR \fItype\fR\fR
+.ad
+.sp .6
+.RS 4n
+A comma-separated list of types to display, where \fItype\fR is one of \fBfilesystem\fR, \fBsnapshot\fR, \fBsnap\fR, \fBvolume\fR, \fBbookmark\fR, or \fBall\fR. For example, specifying \fB-t snapshot\fR displays only snapshots.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs set\fR \fIproperty\fR=\fIvalue\fR[ \fIproperty\fR=\fIvalue\fR]...
+\fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Sets the property or list of properties to the given value(s) for each dataset.
+Only some properties can be edited. See the "Properties" section for more
+information on which properties can be set and acceptable values. User properties
+can be set on snapshots. For more information, see the "User Properties" section.
+.RE
+
+.sp
+.ne 2
+\fB\fBzfs get\fR [\fB-r\fR|\fB-d\fR \fIdepth\fR] [\fB-Hp\fR] [\fB-o\fR \fIfield\fR[,...] [\fB-t\fR \fItype\fR[,...]] [\fB-s\fR \fIsource\fR[,...] "\fIall\fR" | \fIproperty\fR[,...] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Displays properties for the given datasets. If no datasets are specified, then the command displays properties for all datasets on the system. For each property, the following columns are displayed:
+.sp
+.in +2
+.nf
+    name      Dataset name
+     property  Property name
+     value     Property value
+     source    Property source. Can either be local, default,
+               temporary, inherited, received, or none (-).
+.fi
+.in -2
+.sp
+
+All columns are displayed by default, though this can be controlled by using the \fB-o\fR option. This command takes a comma-separated list of properties as described in the "Native Properties" and "User Properties" sections.
+.sp
+The special value \fBall\fR can be used to display all properties that apply to the given dataset's type (filesystem, volume snapshot, or bookmark).
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively display properties for any children.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-d\fR \fIdepth\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively display any children of the dataset, limiting the recursion to \fIdepth\fR. A depth of \fB1\fR will display only the dataset and its direct children.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-H\fR\fR
+.ad
+.sp .6
+.RS 4n
+Display output in a form more easily parsed by scripts. Any headers are omitted, and fields are explicitly separated by a single tab instead of an arbitrary amount of space.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIfield\fR\fR
+.ad
+.sp .6
+.RS 4n
+A comma-separated list of columns to display. \fBname,property,value,source\fR is the default value.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-s\fR \fIsource\fR\fR
+.ad
+.sp .6
+.RS 4n
+A comma-separated list of sources to display. Those properties coming from a source other than those in this list are ignored. Each source must be one of the following: \fBlocal,default,inherited,received,temporary,none\fR. The default value is all sources.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Display numbers in parsable (exact) values.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs inherit\fR [\fB-rS\fR] \fIproperty\fR \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Clears the specified property, causing it to be inherited from an ancestor, restored to default if no ancestor has the property set, or with the \fB-S\fR option reverted to the received value if one exists.  See the "Properties" section for a listing of default values, and details on which properties can be inherited.
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively inherit the given property for all children.
+.RE
+.sp
+.ne 2
+.na
+\fB\fB-S\fR\fR
+.ad
+.sp .6
+.RS 4n
+Revert the property to the received value if one exists; otherwise operate as
+if the \fB-S\fR option was not specified.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs upgrade\fR
+.ad
+.sp .6
+.RS 4n
+Displays a list of file systems that are not the most recent version.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs upgrade\fR \fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Displays a list of file system versions.
+.RE
+
+
+.sp
+.ne 2
+.na
+\fB\fBzfs upgrade\fR [\fB-r\fR] [\fB-V\fR \fIversion\fR] [\fB-a\fR | \fIfilesystem\fR]\fR
+.ad
+.sp .6
+.RS 4n
+Upgrades file systems to a new on-disk version. Once this is done, the file systems will no longer be accessible on systems running older versions of the software. \fBzfs send\fR streams generated from new snapshots of these file systems cannot be accessed on systems running older versions of the software.
+.sp
+In general, the file system version is independent of the pool version. See \fBzpool\fR(8) for information on the \fBzpool upgrade\fR command.
+.sp
+In some cases, the file system version and the pool version are interrelated and the pool version must be upgraded before the file system version can be upgraded.
+.sp
+.ne 2
+.na
+\fB\fB-a\fR\fR
+.ad
+.sp .6
+.RS 4n
+Upgrades all file systems on all imported pools.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIfilesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+Upgrades the specified file system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Upgrades the specified file system and all descendent file systems
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-V\fR \fIversion\fR\fR
+.ad
+.sp .6
+.RS 4n
+Upgrades to the specified \fIversion\fR. If the \fB-V\fR flag is not specified, this command upgrades to the most recent version. This option can only be used to increase the version number, and only up to the most recent version supported by this software.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs\fR \fBuserspace\fR [\fB-Hinp\fR] [\fB-o\fR \fIfield\fR[,...]]
+[\fB-s\fR \fIfield\fR] ...
+[\fB-S\fR \fIfield\fR] ...
+[\fB-t\fR \fItype\fR[,...]] \fIfilesystem\fR|\fIsnapshot\fR
+.ad
+.sp .6
+.RS 4n
+Displays space consumed by, and quotas on, each user in the specified
+filesystem or snapshot. This corresponds to the \fBuserused@\fR\fIuser\fR, \fBuserobjused@\fR\fIuser\fR,
+\fBuserquota@\fR\fIuser\fR, and \fBuserobjquota@\fR\fIuser\fR properties.
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print numeric ID instead of user/group name.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-H\fR\fR
+.ad
+.sp .6
+.RS 4n
+Display output in a form more easily parsed by scripts. Any headers are omitted, and fields are explicitly separated by a single tab instead of an arbitrary amount of space.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Use exact (parsable) numeric output.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIfield\fR[,...]\fR
+.ad
+.sp .6
+.RS 4n
+Display only the specified fields from the following
+set: \fBtype, name, used, quota\fR. The default is to display all fields.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-s\fR \fIfield\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sort output by this field. The \fIs\fR and \fIS\fR flags may be specified
+multiple times to sort first by one field, then by another. The default is
+\fB-s type\fR \fB-s name\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-S\fR \fIfield\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sort by this field in reverse order. See \fB-s\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-t\fR \fItype\fR[,...]\fR
+.ad
+.sp .6
+.RS 4n
+Print only the specified types from the following
+set: \fBall, posixuser, smbuser, posixgroup, smbgroup\fR. The default
+is \fB-t posixuser,smbuser\fR. The default can be changed to include group
+types.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-i\fR\fR
+.ad
+.sp .6
+.RS 4n
+Translate SID to POSIX ID. The POSIX ID may be ephemeral if no mapping exists.
+Normal POSIX interfaces (for example, \fBstat\fR(2), \fBls\fR(1) \fB-l\fR) perform
+this translation, so the \fB-i\fR option allows the output from \fBzfs
+userspace\fR to be compared directly with those utilities. However, \fB-i\fR
+may lead to confusion if some files were created by an SMB user before a
+SMB-to-POSIX name mapping was established. In such a case, some files will be owned
+by the SMB entity and some by the POSIX entity. However, the \fB-i\fR option
+will report that the POSIX entity has the total usage and quota for both.
+.sp
+This option is not useful on Linux.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fBzfs\fR \fBgroupspace\fR [\fB-Hinp\fR] [\fB-o\fR \fIfield\fR[,...]]
+[\fB-s\fR \fIfield\fR] ...
+[\fB-S\fR \fIfield\fR] ...
+[\fB-t\fR \fItype\fR[,...]] \fIfilesystem\fR|\fIsnapshot\fR
+.ad
+.sp .6
+.RS 4n
+Displays space consumed by, and quotas on, each group in the specified
+filesystem or snapshot. This subcommand is identical to \fBzfs userspace\fR,
+except that the default types to display are \fB-t posixgroup,smbgroup\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs mount\fR\fR
+.ad
+.sp .6
+.RS 4n
+Displays all \fBZFS\fR file systems currently mounted.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs mount\fR [\fB-vO\fR] [\fB-o\fR \fIoptions\fR] \fB-a\fR | \fIfilesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+Mounts \fBZFS\fR file systems. This is invoked automatically as part of the boot process.
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIoptions\fR\fR
+.ad
+.sp .6
+.RS 4n
+An optional, comma-separated list of mount options to use temporarily for the
+duration of the mount. See the "Temporary Mount Point Properties" section for
+details.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-O\fR\fR
+.ad
+.sp .6
+.RS 4n
+Allow mounting the filesystem even if the target directory is not empty.
+.sp
+On Solaris, the behavior of \fBzfs mount\fR matches \fBmount\fR and \fBzfs mount -O\fR matches \fBmount -O\fR. See \fBmount\fR(1M).
+.sp
+On Linux, this is the default for \fBmount\fR(8). In other words, \fBzfs mount -O\fR matches \fBmount\fR and there is no \fBmount\fR equivalent to a plain \fBzfs mount\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Report mount progress. This is intended for use with \fBzfs mount -a\fR on a system with a significant number of filesystems.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-a\fR\fR
+.ad
+.sp .6
+.RS 4n
+Mount all available \fBZFS\fR file systems. Invoked automatically as part of
+the boot process.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIfilesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+Mount the specified filesystem.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs unmount\fR [\fB-f\fR] \fB-a\fR | \fIfilesystem\fR|\fImountpoint\fR\fR
+.ad
+.sp .6
+.RS 4n
+Unmounts currently mounted \fBZFS\fR file systems. Invoked automatically as part of the shutdown process.
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.sp .6
+.RS 4n
+Forcefully unmount the file system, even if it is currently in use.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-a\fR\fR
+.ad
+.sp .6
+.RS 4n
+Unmount all available \fBZFS\fR file systems. Invoked automatically as part of the shutdown process.
+.RE
+
+.sp
+.ne 2
+.na
+\fIfilesystem\fR|\fImountpoint\fR
+.ad
+.sp .6
+.RS 4n
+Unmount the specified filesystem. The command can also be given a path to a \fBZFS\fR file system mount point on the system.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs share\fR \fB-a\fR | \fIfilesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+Shares available \fBZFS\fR file systems.
+.sp
+.ne 2
+.na
+\fB\fB-a\fR\fR
+.ad
+.sp .6
+.RS 4n
+Share all available \fBZFS\fR file systems. Invoked automatically as part of the boot process.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIfilesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+Share the specified filesystem according to the \fBsharenfs\fR and \fBsharesmb\fR properties. File systems are shared when the \fBsharenfs\fR or \fBsharesmb\fR property is set.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs unshare\fR \fB-a\fR | \fIfilesystem\fR|\fImountpoint\fR\fR
+.ad
+.sp .6
+.RS 4n
+Unshares currently shared \fBZFS\fR file systems. This is invoked automatically as part of the shutdown process.
+.sp
+.ne 2
+.na
+\fB\fB-a\fR\fR
+.ad
+.sp .6
+.RS 4n
+Unshare all available \fBZFS\fR file systems. Invoked automatically as part of the boot process.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fIfilesystem\fR|\fImountpoint\fR\fR
+.ad
+.sp .6
+.RS 4n
+Unshare the specified filesystem. The command can also be given a path to a \fBZFS\fR file system shared on the system.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs bookmark\fR \fIsnapshot\fR \fIbookmark\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates a bookmark of the given snapshot.  Bookmarks mark the point in time
+when the snapshot was created, and can be used as the incremental source for
+a \fBzfs send\fR command.
+.sp
+This feature must be enabled to be used.
+See \fBzpool-features\fR(5) for details on ZFS feature flags and the
+\fBbookmarks\fR feature.
+.RE
+
+
+.RE
+.sp
+.ne 2
+.na
+\fBzfs send\fR [\fB-DnPpRveLc\fR] [\fB-\fR[\fBiI\fR] \fIsnapshot\fR] \fIsnapshot\fR
+.ad
+.sp .6
+.RS 4n
+Creates a stream representation of the (second, if \fB-i\fR is specified) \fIsnapshot\fR, which is written to standard output. The output can be redirected to a file or to a pipe (for example, using \fBssh\fR(1) to send it to a different system with \fBzfs receive\fR). By default, a full stream is generated; specifying \fB-i\fR or \fB-I\fR changes this behavior.
+.sp
+.ne 2
+.na
+\fB\fB-i\fR \fIsnapshot\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate an incremental stream from the first \fIsnapshot\fR (the incremental source) to the second \fIsnapshot\fR (the incremental target).  The incremental source can be specified as the last component of the snapshot name (the \fB@\fR character and following) and it is assumed to be from the same file system as the incremental target.
+.sp
+If the destination is a clone, the source may be the origin snapshot, which must be fully specified (for example, \fBpool/fs@origin\fR, not just \fB@origin\fR).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-I\fR \fIsnapshot\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a stream package that sends all intermediary snapshots from the first snapshot to the second snapshot. For example, \fB-I @a fs@d\fR is similar to \fB-i @a fs@b; -i @b fs@c; -i @c fs@d\fR. The incremental source may be specified as with the \fB-i\fR option.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-R\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a replication stream package, which will replicate the specified filesystem, and all descendent file systems, up to the named snapshot. When received, all properties, snapshots, descendent file systems, and clones are preserved.
+.sp
+If the \fB-i\fR or \fB-I\fR flags are used in conjunction with the \fB-R\fR flag, an incremental replication stream is generated. The current values of properties, and current snapshot and file system names are set when the stream is received. If the \fB-F\fR flag is specified when this stream is received, snapshots and file systems that do not exist on the sending side are destroyed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-D\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a deduplicated stream. Blocks which would have been sent multiple times in the send stream will only be sent once. The receiving system must also support this feature to receive a deduplicated stream.  This flag can be used regardless of the dataset's dedup  property, but performance will be much better if the filesystem uses a dedup-capable checksum (eg.  sha256).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-L\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a stream which may contain blocks larger than 128KiB.  This flag
+has no effect if the \fBlarge_blocks\fR pool feature is disabled, or if
+the \fRrecordsize\fR property of this filesystem has never been set above
+128KiB.  The receiving system must have the \fBlarge_blocks\fR pool feature
+enabled as well.  See \fBzpool-features\fR(5) for details on ZFS feature
+flags and the \fBlarge_blocks\fR feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-e\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a more compact stream by using WRITE_EMBEDDED records for blocks
+which are stored more compactly on disk by the \fBembedded_data\fR pool
+feature.  This flag has no effect if the \fBembedded_data\fR feature is
+disabled.  The receiving system must have the \fBembedded_data\fR feature
+enabled.  If the \fBlz4_compress\fR feature is active on the sending system,
+then the receiving system must have that feature enabled as well. See
+\fBzpool-features\fR(5) for details on ZFS feature flags and the
+\fBembedded_data\fR feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-c\fR, \fB--compressed\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a more compact stream by using compressed WRITE records for blocks
+which are compressed on disk and in memory (see the \fBcompression\fR property
+for details).  If the \fBlz4_compress\fR feature is active on the sending
+system, then the receiving system must have that feature enabled as well.  If
+the \fBlarge_blocks\fR feature is enabled on the sending system but the \fB-L\fR
+option is not supplied in conjunction with \fB-c\fR, then the data will be
+decompressed before sending so it can be split into smaller block sizes.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.sp .6
+.RS 4n
+Include the dataset's properties in the stream.  This flag is implicit when -R is specified.  The receiving system must also support this feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do a dry-run ("No-op") send.  Do not generate any actual send data.  This is
+useful in conjunction with the \fB-v\fR or \fB-P\fR flags to determine what
+data will be sent.  In this case, the verbose output will be written to
+standard output (contrast with a non-dry-run, where the stream is written
+to standard output and the verbose output goes to standard error).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-P\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print machine-parsable verbose information about the stream package generated.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print verbose information about the stream package generated.  This information
+includes a per-second report of how much data has been sent.
+.RE
+
+The format of the stream is committed. You will be able to receive your streams on future versions of \fBZFS\fR.
+.RE
+
+.RE
+.sp
+.ne 2
+.na
+\fBzfs send\fR [\fB-Lec\fR] [\fB-i\fR \fIsnapshot\fR|\fIbookmark\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR
+.ad
+.sp .6
+.RS 4n
+Generate a send stream, which may be of a filesystem, and may be
+incremental from a bookmark.  If the destination is a filesystem or volume,
+the pool must be read-only, or the filesystem must not be mounted.  When the
+stream generated from a filesystem or volume is received, the default snapshot
+name will be "--head--".
+
+.sp
+.ne 2
+.na
+\fB\fB-L\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a stream which may contain blocks larger than 128KiB.  This flag
+has no effect if the \fBlarge_blocks\fR pool feature is disabled, or if
+the \fRrecordsize\fR property of this filesystem has never been set above
+128KiB.  The receiving system must have the \fBlarge_blocks\fR pool feature
+enabled as well.  See \fBzpool-features\fR(5) for details on ZFS feature
+flags and the \fBlarge_blocks\fR feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-e\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a more compact stream by using WRITE_EMBEDDED records for blocks
+which are stored more compactly on disk by the \fBembedded_data\fR pool
+feature.  This flag has no effect if the \fBembedded_data\fR feature is
+disabled.  The receiving system must have the \fBembedded_data\fR feature
+enabled.  If the \fBlz4_compress\fR feature is active on the sending system,
+then the receiving system must have that feature enabled as well. See
+\fBzpool-features\fR(5) for details on ZFS feature flags and the
+\fBembedded_data\fR feature.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-c\fR, \fB--compressed\fR\fR
+.ad
+.sp .6
+.RS 4n
+Generate a more compact stream by using compressed WRITE records for blocks
+which are compressed on disk and in memory (see the \fBcompression\fR property
+for details).  If the \fBlz4_compress\fR feature is active on the sending
+system, then the receiving system must have that feature enabled as well.  If
+the \fBlarge_blocks\fR feature is enabled on the sending system but the \fB-L\fR
+option is not supplied in conjunction with \fB-c\fR, then the data will be
+decompressed before sending so it can be split into smaller block sizes.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-i\fR \fIsnapshot\fR|\fIbookmark\fR
+.ad
+.sp .6
+.RS 4n
+Generate an incremental send stream.  The incremental source must be an earlier snapshot in the destination's history. It will commonly be an earlier snapshot in the destination's filesystem, in which case it can be specified as the last component of the name (the \fB#\fR or \fB@\fR character and following).
+.sp
+If the incremental target is a clone, the incremental source can be the origin snapshot, or an earlier snapshot in the origin's filesystem, or the origin's origin, etc.
+.RE
+
+.RE
+.sp
+.ne 2
+.na
+\fB\fBzfs send\fR [\fB-Penv\fR] \fB-t\fR \fIreceive_resume_token\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates a send stream which resumes an interrupted receive. The \fIreceive_resume_token\fR is the value of this property on the filesystem or volume that was being received into. See the documentation for \fBzfs receive -s\fR for more details.
+
+.RE
+
+.RE
+.sp
+.ne 2
+.na
+\fB\fBzfs receive\fR [\fB-Fnsuv\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR|\fIvolume\fR|\fIsnapshot\fR\fR
+.ad
+.br
+.na
+\fB\fBzfs receive\fR [\fB-Fnsuv\fR] [\fB-d\fR|\fB-e\fR] [\fB-o origin\fR=\fIsnapshot\fR] \fIfilesystem\fR\fR
+.ad
+.sp .6
+.RS 4n
+Creates a snapshot whose contents are as specified in the stream provided on standard input. If a full stream is received, then a new file system is created as well. Streams are created using the \fBzfs send\fR subcommand, which by default creates a full stream. \fBzfs recv\fR can be used as an alias for \fBzfs receive\fR.
+.sp
+If an incremental stream is received, then the destination file system must already exist, and its most recent snapshot must match the incremental stream's source. For \fBzvols\fR, the destination device link is destroyed and recreated, which means the \fBzvol\fR cannot be accessed during the \fBreceive\fR operation.
+.sp
+When a snapshot replication package stream that is generated by using the \fBzfs send\fR \fB-R\fR command is received, any snapshots that do not exist on the sending location are destroyed by using the \fBzfs destroy\fR \fB-d\fR command.
+.sp
+The name of the snapshot (and file system, if a full stream is received) that this subcommand creates depends on the argument type and the use of the \fB-d\fR or \fB-e\fR options.
+.sp
+If the argument is a snapshot name, the specified \fIsnapshot\fR is created. If the argument is a file system or volume name, a snapshot with the same name as the sent snapshot is created within the specified \fIfilesystem\fR or \fIvolume\fR.  If neither of the \fB-d\fR or \fB-e\fR options are specified, the provided target snapshot name is used exactly as provided.
+.sp
+The \fB-d\fR and \fB-e\fR options cause the file system name of the target snapshot to be determined by appending a portion of the sent snapshot's name to the specified target \fIfilesystem\fR. If the \fB-d\fR option is specified, all but the first element of the sent snapshot's file system path (usually the pool name) is used and any required intermediate file systems within the specified one are created.  If the \fB-e\fR option is specified, then only the last element of the sent snapshot's file system name (i.e. the name of the source file system itself) is used as the target file system name.
+.sp
+.ne 2
+.na
+\fB\fB-F\fR\fR
+.ad
+.sp .6
+.RS 4n
+Force a rollback of the file system to the most recent snapshot before performing the receive operation. If receiving an incremental replication stream (for example, one generated by \fBzfs send -R -[iI]\fR), destroy snapshots and file systems that do not exist on the sending side.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do not actually receive the stream. This can be useful in conjunction with the \fB-v\fR option to verify the name the receive operation would use.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-s\fR\fR
+.ad
+.sp .6
+.RS 4n
+If the receive is interrupted, save the partially received state, rather than deleting it. Interruption may be due to premature termination of the stream (e.g. due to network failure or failure of the remote system if the stream is being read over a network connection), a checksum error in the stream, termination of the \fBzfs receive\fR process, or unclean shutdown of the system.
+.sp
+The receive can be resumed with a stream generated by \fBzfs send -t\fR token, where the \fItoken\fR is the value of the \fBreceive_resume_token\fR property of the filesystem or volume which is received into.
+.sp
+To use this flag, the storage pool must have the \fBextensible_dataset\fR feature enabled.  See \fBzpool-features\fR(5) for details on ZFS feature flags.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-u\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do not mount the file system that is associated with the received stream.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Print verbose information about the stream and the time required to perform the receive operation.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-d\fR\fR
+.ad
+.sp .6
+.RS 4n
+Discard the first element of the sent snapshot's file system name, using the remaining elements to determine the name of the target file system for the new snapshot as described in the paragraph above.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-e\fR\fR
+.ad
+.sp .6
+.RS 4n
+Discard all but the last element of the sent snapshot's file system name, using that element to determine the name of the target file system for the new snapshot as described in the paragraph above.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fBorigin\fR=\fIsnapshot\fR
+.ad
+.sp .6
+.RS 4n
+Forces the stream to be received as a clone of the given snapshot.
+If the stream is a full send stream, this will create the filesystem
+described by the stream as a clone of the specified snapshot. Which
+snapshot was specified will not affect the success or failure of the
+receive, as long as the snapshot does exist.  If the stream is an
+incremental send stream, all the normal verification will be performed.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs receive\fR [\fB-A\fR] \fIfilesystem\fR|\fIvolume\fR
+.ad
+.sp .6
+.RS 4n
+Abort an interrupted \fBzfs receive \fB-s\fR\fR, deleting its saved partially received state.
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs allow\fR \fIfilesystem\fR | \fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Displays permissions that have been delegated on the specified filesystem or volume. See the other forms of \fBzfs allow\fR for more information.
+.sp
+Delegations are supported under Linux with the exception of \fBmount\fR,
+\fBunmount\fR, \fBmountpoint\fR, \fBcanmount\fR, \fBrename\fR, and \fBshare\fR.
+These permissions cannot be delegated because the Linux \fBmount(8)\fR command
+restricts modifications of the global namespace to the root user.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs allow\fR [\fB-ldug\fR] "\fIeveryone\fR"|\fIuser\fR|\fIgroup\fR[,...] \fIperm\fR|@\fIsetname\fR[,...] \fIfilesystem\fR| \fIvolume\fR\fR
+.ad
+.br
+.na
+\fB\fBzfs allow\fR [\fB-ld\fR] \fB-e\fR \fIperm\fR|@\fIsetname\fR[,...] \fIfilesystem\fR | \fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Delegates \fBZFS\fR administration permission for the file systems to non-privileged users.
+.sp
+.ne 2
+.na
+\fB[\fB-ug\fR] "\fIeveryone\fR"|\fIuser\fR|\fIgroup\fR[,...]\fR
+.ad
+.sp .6
+.RS 4n
+Specifies to whom the permissions are delegated. Multiple entities can be specified as a comma-separated list. If neither of the \fB-ug\fR options are specified, then the argument is interpreted preferentially as the keyword "everyone", then as a user name, and lastly as a group name. To specify a user or group named "everyone", use the \fB-u\fR or \fB-g\fR options. To specify a group with the same name as a user, use the \fB-g\fR options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB[\fB-e\fR] \fIperm\fR|@\fIsetname\fR[,...]\fR
+.ad
+.sp .6
+.RS 4n
+Specifies that the permissions be delegated to "everyone." Multiple permissions may be specified as a comma-separated list. Permission names are the same as \fBZFS\fR subcommand and property names. See the property list below. Property set names, which begin with an at sign (\fB@\fR) , may be specified. See the \fB-s\fR form below for details.
+.RE
+
+.sp
+.ne 2
+.na
+\fB[\fB-ld\fR] \fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specifies where the permissions are delegated. If neither of the \fB-ld\fR options are specified, or both are, then the permissions are allowed for the file system or volume, and all of its descendents. If only the \fB-l\fR option is used, then is allowed "locally" only for the specified file system. If only the \fB-d\fR option is used, then is allowed only for the descendent file systems.
+.RE
+
+.RE
+
+.sp
+.LP
+Permissions are generally the ability to use a \fBzfs\fR subcommand or change a property. The following permissions are available:
+.sp
+.in +2
+.nf
+NAME             TYPE           NOTES
+allow            subcommand     Must also have the permission that is being
+                                allowed
+clone            subcommand     Must also have the 'create' ability and 'mount'
+                                ability in the origin file system
+create           subcommand     Must also have the 'mount' ability
+destroy          subcommand     Must also have the 'mount' ability
+diff             subcommand     Allows lookup of paths within a dataset
+                                given an object number, and the ability to
+                                create snapshots necessary to 'zfs diff'.
+mount            subcommand     Allows mount/umount of ZFS datasets
+promote          subcommand     Must also have the 'mount'
+                                and 'promote' ability in the origin file system
+receive          subcommand     Must also have the 'mount' and 'create' ability
+rename           subcommand     Must also have the 'mount' and 'create'
+                                ability in the new parent
+rollback         subcommand     Must also have the 'mount' ability
+send             subcommand
+share            subcommand     Allows sharing file systems over NFS or SMB
+                                protocols
+snapshot         subcommand     Must also have the 'mount' ability
+groupobjquota    other          Allows accessing any groupobjquota@... property
+groupquota       other          Allows accessing any groupquota@... property
+groupobjused     other          Allows reading any groupobjused@... property
+groupused        other          Allows reading any groupused@... property
+userprop         other          Allows changing any user property
+userobjquota     other          Allows accessing any userobjquota@... property
+userquota        other          Allows accessing any userquota@... property
+userobjused      other          Allows reading any userobjused@... property
+userused         other          Allows reading any userused@... property
+
+acltype          property
+aclinherit       property
+atime            property
+canmount         property
+casesensitivity  property
+checksum         property
+compression      property
+copies           property
+dedup            property
+devices          property
+exec             property
+filesystem_limit property
+logbias          property
+mlslabel         property
+mountpoint       property
+nbmand           property
+normalization    property
+primarycache     property
+quota            property
+readonly         property
+recordsize       property
+refquota         property
+refreservation   property
+reservation      property
+secondarycache   property
+setuid           property
+sharenfs         property
+sharesmb         property
+snapdir          property
+snapshot_limit   property
+utf8only         property
+version          property
+volblocksize     property
+volsize          property
+vscan            property
+xattr            property
+zoned            property
+.fi
+.in -2
+.sp
+
+.sp
+.ne 2
+.na
+\fB\fBzfs allow\fR \fB-c\fR \fIperm\fR|@\fIsetname\fR[,...] \fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets "create time" permissions. These permissions are granted (locally) to the creator of any newly-created descendent file system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs allow\fR \fB-s\fR @\fIsetname\fR \fIperm\fR|@\fIsetname\fR[,...] \fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Defines or adds permissions to a permission set. The set can be used by other \fBzfs allow\fR commands for the specified file system and its descendents. Sets are evaluated dynamically, so changes to a set are immediately reflected. Permission sets follow the same naming restrictions as ZFS file systems, but the name must begin with an "at sign" (\fB@\fR), and can be no more than 64 characters long.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs unallow\fR [\fB-rldug\fR] "\fIeveryone\fR"|\fIuser\fR|\fIgroup\fR[,...] [\fIperm\fR|@\fIsetname\fR[, ...]] \fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.br
+.na
+\fB\fBzfs unallow\fR [\fB-rld\fR] \fB-e\fR [\fIperm\fR|@\fIsetname\fR [,...]] \fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.br
+.na
+\fB\fBzfs unallow\fR [\fB-r\fR] \fB-c\fR [\fIperm\fR|@\fIsetname\fR[,...]]\fR \fB\fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Removes permissions that were granted with the \fBzfs allow\fR command. No permissions are explicitly denied, so other permissions granted are still in effect. For example, if the permission is granted by an ancestor. If no permissions are specified, then all permissions for the specified \fIuser\fR, \fIgroup\fR, or \fIeveryone\fR are removed. Specifying "everyone" (or using the \fB-e\fR option) only removes the permissions that were granted to "everyone", not all permissions for every user and group. See the \fBzfs allow\fR command for a description of the \fB-ldugec\fR options.
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively remove the permissions from this file system and all descendents.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs unallow\fR [\fB-r\fR] \fB-s\fR @\fIsetname\fR [\fIperm\fR|@\fIsetname\fR[,...]]\fR \fB\fIfilesystem\fR|\fIvolume\fR\fR
+.ad
+.sp .6
+.RS 4n
+Removes permissions from a permission set. If no permissions are specified, then all permissions are removed, thus removing the set entirely.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs hold\fR [\fB-r\fR] \fItag\fR \fIsnapshot\fR...\fR
+.ad
+.sp .6
+.RS 4n
+Adds a single reference, named with the \fItag\fR argument, to the specified snapshot or snapshots. Each snapshot has its own tag namespace, and tags must be unique within that space.
+.sp
+If a hold exists on a snapshot, attempts to destroy that snapshot by using the \fBzfs destroy\fR command return \fBEBUSY\fR.
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specifies that a hold with the given tag is applied recursively to the snapshots of all descendent file systems.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs holds\fR [\fB-r\fR] \fIsnapshot\fR...\fR
+.ad
+.sp .6
+.RS 4n
+Lists all existing user references for the given snapshot or snapshots.
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Lists the holds that are set on the named descendent snapshots, in addition to listing the holds on the named snapshot.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs release\fR [\fB-r\fR] \fItag\fR \fIsnapshot\fR...\fR
+.ad
+.sp .6
+.RS 4n
+Removes a single reference, named with the \fItag\fR argument, from the specified snapshot or snapshots. The tag must already exist for each snapshot.
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recursively releases a hold with the given tag on the snapshots of all descendent file systems.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzfs diff\fR [\fB-FHt\fR] \fIsnapshot\fR \fIsnapshot|filesystem\fR
+.ad
+.sp .6
+.RS 4n
+Display the difference between a snapshot of a given filesystem and another
+snapshot of that filesystem from a later time or the current contents of the
+filesystem.  The first column is a character indicating the type of change,
+the other columns indicate pathname, new pathname (in case of rename), change
+in link count, and optionally file type and/or change time.
+
+The types of change are:
+.in +2
+.nf
+-       The path has been removed
++       The path has been created
+M       The path has been modified
+R       The path has been renamed
+.fi
+.in -2
+.sp
+.ne 2
+.na
+\fB-F\fR
+.ad
+.sp .6
+.RS 4n
+Display an indication of the type of file, in a manner similar to the \fB-F\fR
+option of \fBls\fR(1).
+.in +2
+.nf
+B       Block device
+C       Character device
+/       Directory
+>       Door
+|       Named pipe
+@       Symbolic link
+P       Event port
+=       Socket
+F       Regular file
+.fi
+.in -2
+.RE
+.sp
+.ne 2
+.na
+\fB-H\fR
+.ad
+.sp .6
+.RS 4n
+Give more parsable tab-separated output, without header lines and without arrows.
+.RE
+.sp
+.ne 2
+.na
+\fB-t\fR
+.ad
+.sp .6
+.RS 4n
+Display the path's inode change time as the first column of output.
+.RE
+
+.SH EXAMPLES
+.LP
+\fBExample 1 \fRCreating a ZFS File System Hierarchy
+.sp
+.LP
+The following commands create a file system named \fBpool/home\fR and a file system named \fBpool/home/bob\fR. The mount point \fB/export/home\fR is set for the parent file system, and is automatically inherited by the child file system.
+
+.sp
+.in +2
+.nf
+# \fBzfs create pool/home\fR
+# \fBzfs set mountpoint=/export/home pool/home\fR
+# \fBzfs create pool/home/bob\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 2 \fRCreating a ZFS Snapshot
+.sp
+.LP
+The following command creates a snapshot named \fBbackup\fR. This snapshot is mounted on demand in the \fB\&.zfs/snapshot\fR directory at the root of the \fBpool/home/bob\fR file system.
+
+.sp
+.in +2
+.nf
+# \fBzfs snapshot pool/home/bob@backup\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 3 \fRCreating and Destroying Multiple Snapshots
+.sp
+.LP
+The following command creates snapshots named \fBbackup\fR of \fBpool/home\fR and all of its descendent file systems. Each snapshot is mounted on demand in the \fB\&.zfs/snapshot\fR directory at the root of its file system. The second command destroys the newly created snapshots.
+
+.sp
+.in +2
+.nf
+# \fBzfs snapshot -r pool/home@backup\fR
+# \fBzfs destroy -r pool/home@backup\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 4 \fRDisabling and Enabling File System Compression
+.sp
+.LP
+The following command disables the \fBcompression\fR property for all file systems under \fBpool/home\fR. The next command explicitly enables \fBcompression\fR for \fBpool/home/anne\fR.
+
+.sp
+.in +2
+.nf
+# \fBzfs set compression=off pool/home\fR
+# \fBzfs set compression=on pool/home/anne\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 5 \fRListing ZFS Datasets
+.sp
+.LP
+The following command lists all active file systems and volumes in the system. Snapshots are displayed if the pool's \fBlistsnapshots\fR property is \fBon\fR (the default is \fBoff\fR). See \fBzpool\fR(8) for more information on pool properties.
+
+.sp
+.in +2
+.nf
+# \fBzfs list\fR
+   NAME                      USED  AVAIL  REFER  MOUNTPOINT
+   pool                      450K   457G    18K  /pool
+   pool/home                 315K   457G    21K  /export/home
+   pool/home/anne             18K   457G    18K  /export/home/anne
+   pool/home/bob             276K   457G   276K  /export/home/bob
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 6 \fRSetting a Quota on a ZFS File System
+.sp
+.LP
+The following command sets a quota of 50 GiB for \fBpool/home/bob\fR.
+
+.sp
+.in +2
+.nf
+# \fBzfs set quota=50G pool/home/bob\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 7 \fRListing ZFS Properties
+.sp
+.LP
+The following command lists all properties for \fBpool/home/bob\fR.
+
+.sp
+.in +2
+.nf
+# \fBzfs get all pool/home/bob\fR
+NAME           PROPERTY              VALUE                  SOURCE
+pool/home/bob  type                  filesystem             -
+pool/home/bob  creation              Tue Jul 21 15:53 2009  -
+pool/home/bob  used                  21K                    -
+pool/home/bob  available             20.0G                  -
+pool/home/bob  referenced            21K                    -
+pool/home/bob  compressratio         1.00x                  -
+pool/home/bob  mounted               yes                    -
+pool/home/bob  quota                 20G                    local
+pool/home/bob  reservation           none                   default
+pool/home/bob  recordsize            128K                   default
+pool/home/bob  mountpoint            /pool/home/bob         default
+pool/home/bob  sharenfs              off                    default
+pool/home/bob  checksum              on                     default
+pool/home/bob  compression           on                     local
+pool/home/bob  atime                 on                     default
+pool/home/bob  devices               on                     default
+pool/home/bob  exec                  on                     default
+pool/home/bob  setuid                on                     default
+pool/home/bob  readonly              off                    default
+pool/home/bob  zoned                 off                    default
+pool/home/bob  snapdir               hidden                 default
+pool/home/bob  acltype               off                    default
+pool/home/bob  aclinherit            restricted             default
+pool/home/bob  canmount              on                     default
+pool/home/bob  xattr                 on                     default
+pool/home/bob  copies                1                      default
+pool/home/bob  version               4                      -
+pool/home/bob  utf8only              off                    -
+pool/home/bob  normalization         none                   -
+pool/home/bob  casesensitivity       sensitive              -
+pool/home/bob  vscan                 off                    default
+pool/home/bob  nbmand                off                    default
+pool/home/bob  sharesmb              off                    default
+pool/home/bob  refquota              none                   default
+pool/home/bob  refreservation        none                   default
+pool/home/bob  primarycache          all                    default
+pool/home/bob  secondarycache        all                    default
+pool/home/bob  usedbysnapshots       0                      -
+pool/home/bob  usedbydataset         21K                    -
+pool/home/bob  usedbychildren        0                      -
+pool/home/bob  usedbyrefreservation  0                      -
+pool/home/bob  logbias               latency                default
+pool/home/bob  dedup                 off                    default
+pool/home/bob  mlslabel              none                   default
+pool/home/bob  relatime              off                    default
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+The following command gets a single property value.
+
+.sp
+.in +2
+.nf
+# \fBzfs get -H -o value compression pool/home/bob\fR
+on
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+The following command lists all properties with local settings for \fBpool/home/bob\fR.
+
+.sp
+.in +2
+.nf
+# \fBzfs get -r -s local -o name,property,value all pool/home/bob\fR
+NAME           PROPERTY              VALUE
+pool/home/bob  quota                 20G
+pool/home/bob  compression           on
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 8 \fRRolling Back a ZFS File System
+.sp
+.LP
+The following command reverts the contents of \fBpool/home/anne\fR to the snapshot named \fByesterday\fR, deleting all intermediate snapshots.
+
+.sp
+.in +2
+.nf
+# \fBzfs rollback -r pool/home/anne@yesterday\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 9 \fRCreating a ZFS Clone
+.sp
+.LP
+The following command creates a writable file system whose initial contents are the same as \fBpool/home/bob@yesterday\fR.
+
+.sp
+.in +2
+.nf
+# \fBzfs clone pool/home/bob@yesterday pool/clone\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 10 \fRPromoting a ZFS Clone
+.sp
+.LP
+The following commands illustrate how to test out changes to a file system, and then replace the original file system with the changed one, using clones, clone promotion, and renaming:
+
+.sp
+.in +2
+.nf
+# \fBzfs create pool/project/production\fR
+  populate /pool/project/production with data
+# \fBzfs snapshot pool/project/production@today\fR
+# \fBzfs clone pool/project/production@today pool/project/beta\fR
+make changes to /pool/project/beta and test them
+# \fBzfs promote pool/project/beta\fR
+# \fBzfs rename pool/project/production pool/project/legacy\fR
+# \fBzfs rename pool/project/beta pool/project/production\fR
+once the legacy version is no longer needed, it can be destroyed
+# \fBzfs destroy pool/project/legacy\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 11 \fRInheriting ZFS Properties
+.sp
+.LP
+The following command causes \fBpool/home/bob\fR and \fBpool/home/anne\fR to inherit the \fBchecksum\fR property from their parent.
+
+.sp
+.in +2
+.nf
+# \fBzfs inherit checksum pool/home/bob pool/home/anne\fR
+.fi
+.in -2
+.sp
+.LP
+The following command causes \fBpool/home/bob\fR to revert to the received
+value for the \fBquota\fR property if it exists.
+
+.sp
+.in +2
+.nf
+# \fBzfs inherit -S quota pool/home/bob
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 12 \fRRemotely Replicating ZFS Data
+.sp
+.LP
+The following commands send a full stream and then an incremental stream to a remote machine, restoring them into \fBpoolB/received/fs@a\fRand \fBpoolB/received/fs@b\fR, respectively. \fBpoolB\fR must contain the file system \fBpoolB/received\fR, and must not initially contain \fBpoolB/received/fs\fR.
+
+.sp
+.in +2
+.nf
+# \fBzfs send pool/fs@a | \e\fR
+   \fBssh host zfs receive poolB/received/fs@a\fR
+# \fBzfs send -i a pool/fs@b | ssh host \e\fR
+   \fBzfs receive poolB/received/fs\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 13 \fRUsing the \fBzfs receive\fR \fB-d\fR Option
+.sp
+.LP
+The following command sends a full stream of \fBpoolA/fsA/fsB@snap\fR to a remote machine, receiving it into \fBpoolB/received/fsA/fsB@snap\fR. The \fBfsA/fsB@snap\fR portion of the received snapshot's name is determined from the name of the sent snapshot. \fBpoolB\fR must contain the file system \fBpoolB/received\fR. If \fBpoolB/received/fsA\fR does not exist, it is created as an empty file system.
+
+.sp
+.in +2
+.nf
+# \fBzfs send poolA/fsA/fsB@snap | \e
+   ssh host zfs receive -d poolB/received\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 14 \fRSetting User Properties
+.sp
+.LP
+The following example sets the user-defined \fBcom.example:department\fR property for a dataset.
+
+.sp
+.in +2
+.nf
+# \fBzfs set com.example:department=12345 tank/accounting\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 15 \fRPerforming a Rolling Snapshot
+.sp
+.LP
+The following example shows how to maintain a history of snapshots with a consistent naming scheme. To keep a week's worth of snapshots, the user destroys the oldest snapshot, renames the remaining snapshots, and then creates a new snapshot, as follows:
+
+.sp
+.in +2
+.nf
+# \fBzfs destroy -r pool/users@7daysago\fR
+# \fBzfs rename -r pool/users@6daysago @7daysago\fR
+# \fBzfs rename -r pool/users@5daysago @6daysago\fR
+# \fBzfs rename -r pool/users@4daysago @5daysago\fR
+# \fBzfs rename -r pool/users@3daysago @4daysago\fR
+# \fBzfs rename -r pool/users@2daysago @3daysago\fR
+# \fBzfs rename -r pool/users@yesterday @2daysago\fR
+# \fBzfs rename -r pool/users@today @yesterday\fR
+# \fBzfs snapshot -r pool/users@today\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 16 \fRSetting \fBsharenfs\fR Property Options on a ZFS File System
+.sp
+.LP
+The following commands show how to set \fBsharenfs\fR property options to enable \fBrw\fR access for a set of \fBIP\fR addresses and to enable root access for system \fBneo\fR on the \fBtank/home\fR file system.
+
+.sp
+.in +2
+.nf
+# \fBzfs set sharenfs='rw=@123.123.0.0/16,root=neo' tank/home\fR
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+If you are using \fBDNS\fR for host name resolution, specify the fully qualified hostname.
+
+.LP
+\fBExample 17 \fRDelegating ZFS Administration Permissions on a ZFS Dataset
+.sp
+The following example shows how to set permissions so that user \fBcindys\fR can create, destroy, mount, and take snapshots on \fBtank/cindys\fR. The permissions on \fBtank/cindys\fR are also displayed.
+
+.sp
+.in +2
+.nf
+# \fBzfs allow cindys create,destroy,mount,snapshot tank/cindys\fR
+# \fBzfs allow tank/cindys\fR
+-------------------------------------------------------------
+Local+Descendent permissions on (tank/cindys)
+          user cindys create,destroy,mount,snapshot
+-------------------------------------------------------------
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+Because the \fBtank/cindys\fR mount point permission is set to 755 by default, user \fBcindys\fR will be unable to mount file systems under \fBtank/cindys\fR. Set an \fBACL\fR similar to the following syntax to provide mount point access:
+.sp
+.in +2
+.nf
+# \fBchmod A+user:cindys:add_subdirectory:allow /tank/cindys\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 18 \fRDelegating Create Time Permissions on a ZFS Dataset
+.sp
+.LP
+The following example shows how to grant anyone in the group \fBstaff\fR to create file systems in \fBtank/users\fR. This syntax also allows staff members to destroy their own file systems, but not destroy anyone else's file system. The permissions on \fBtank/users\fR are also displayed.
+
+.sp
+.in +2
+.nf
+# \fBzfs allow staff create,mount tank/users\fR
+# \fBzfs allow -c destroy tank/users\fR
+# \fBzfs allow tank/users\fR
+-------------------------------------------------------------
+Create time permissions on (tank/users)
+          create,destroy
+Local+Descendent permissions on (tank/users)
+          group staff create,mount
+-------------------------------------------------------------
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 19 \fRDefining and Granting a Permission Set on a ZFS Dataset
+.sp
+.LP
+The following example shows how to define and grant a permission set on the \fBtank/users\fR file system. The permissions on \fBtank/users\fR are also displayed.
+
+.sp
+.in +2
+.nf
+# \fBzfs allow -s @pset create,destroy,snapshot,mount tank/users\fR
+# \fBzfs allow staff @pset tank/users\fR
+# \fBzfs allow tank/users\fR
+-------------------------------------------------------------
+Permission sets on (tank/users)
+        @pset create,destroy,mount,snapshot
+Create time permissions on (tank/users)
+        create,destroy
+Local+Descendent permissions on (tank/users)
+        group staff @pset,create,mount
+-------------------------------------------------------------
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 20 \fRDelegating Property Permissions on a ZFS Dataset
+.sp
+.LP
+The following example shows to grant the ability to set quotas and reservations on the \fBusers/home\fR file system. The permissions on \fBusers/home\fR are also displayed.
+
+.sp
+.in +2
+.nf
+# \fBzfs allow cindys quota,reservation users/home\fR
+# \fBzfs allow users/home\fR
+-------------------------------------------------------------
+Local+Descendent permissions on (users/home)
+        user cindys quota,reservation
+-------------------------------------------------------------
+cindys% \fBzfs set quota=10G users/home/marks\fR
+cindys% \fBzfs get quota users/home/marks\fR
+NAME              PROPERTY  VALUE             SOURCE
+users/home/marks  quota     10G               local
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 21 \fRRemoving ZFS Delegated Permissions on a ZFS Dataset
+.sp
+.LP
+The following example shows how to remove the snapshot permission from the \fBstaff\fR group on the \fBtank/users\fR file system. The permissions on \fBtank/users\fR are also displayed.
+
+.sp
+.in +2
+.nf
+# \fBzfs unallow staff snapshot tank/users\fR
+# \fBzfs allow tank/users\fR
+-------------------------------------------------------------
+Permission sets on (tank/users)
+        @pset create,destroy,mount,snapshot
+Create time permissions on (tank/users)
+        create,destroy
+Local+Descendent permissions on (tank/users)
+        group staff @pset,create,mount
+-------------------------------------------------------------
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 22\fR Showing the differences between a snapshot and a ZFS Dataset
+.sp
+.LP
+The following example shows how to see what has changed between a prior
+snapshot of a ZFS Dataset and its current state.  The \fB-F\fR option is used
+to indicate type information for the files affected.
+
+.sp
+.in +2
+.nf
+# zfs diff -F tank/test@before tank/test
+M       /       /tank/test/
+M       F       /tank/test/linked      (+1)
+R       F       /tank/test/oldname -> /tank/test/newname
+-       F       /tank/test/deleted
++       F       /tank/test/created
+M       F       /tank/test/modified
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 23\fR Creating a bookmark
+.sp
+.LP
+The following example create a bookmark to a snapshot. This bookmark can then
+be used instead of snapshot in send streams.
+
+.sp
+.in +2
+.nf
+# zfs bookmark rpool@snapshot rpool#bookmark
+.fi
+.in -2
+.sp
+
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.B "ZFS_ABORT
+Cause \fBzfs\fR to dump core on exit for the purposes of running \fB::findleaks\fR.
+
+.SH EXIT STATUS
+.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
+
+.sp
+.ne 2
+.na
+\fB\fB2\fR\fR
+.ad
+.sp .6
+.RS 4n
+Invalid command line options were specified.
+.RE
+
+.SH SEE ALSO
+.LP
+\fBchmod\fR(2), \fBfsync\fR(2), \fBgzip\fR(1), \fBls\fR(1), \fBmount\fR(8), \fBopen\fR(2), \fBreaddir\fR(3), \fBssh\fR(1), \fBstat\fR(2), \fBwrite\fR(2), \fBzpool\fR(8), \fBzfs-module-parameters\fR(5)
+.sp
+On Solaris: \fBdfstab(4)\fR, \fBiscsitadm(1M)\fR, \fBmount(1M)\fR, \fBshare(1M)\fR, \fBsharemgr(1M)\fR, \fBunshare(1M)\fR
diff --git a/zfs/man/man8/zinject.8 b/zfs/man/man8/zinject.8
new file mode 100644 (file)
index 0000000..90df4fb
--- /dev/null
@@ -0,0 +1,184 @@
+'\" t
+.\"
+.\" 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 2013 Darik Horn <dajhorn@vanadac.com>. All rights reserved.
+.\"
+.TH zinject 8 "2013 FEB 28" "ZFS on Linux" "System Administration Commands"
+
+.SH NAME
+zinject \- ZFS Fault Injector
+.SH DESCRIPTION
+.BR zinject
+creates artificial problems in a ZFS pool by simulating data corruption or device failures. This program is dangerous.
+.SH SYNOPSIS
+.TP
+.B "zinject"
+List injection records.
+.TP
+.B "zinject \-b \fIobjset:object:level:blkd\fB [\-f \fIfrequency\fB] [\-amu] \fIpool\fB"
+Force an error into the pool at a bookmark.
+.TP
+.B "zinject \-c <\fIid\fB | all>
+Cancel injection records.
+.TP
+.B "zinject \-d \fIvdev\fB \-A <degrade|fault> \fIpool\fB
+Force a vdev into the DEGRADED or FAULTED state.
+.TP
+.B "zinject -d \fIvdev\fB -D latency:lanes \fIpool\fB
+
+Add an artificial delay to IO requests on a particular
+device, such that the requests take a minimum of 'latency'
+milliseconds to complete. Each delay has an associated
+number of 'lanes' which defines the number of concurrent
+IO requests that can be processed.
+
+For example, with a single lane delay of 10 ms (-D 10:1),
+the device will only be able to service a single IO request
+at a time with each request taking 10 ms to complete. So,
+if only a single request is submitted every 10 ms, the
+average latency will be 10 ms; but if more than one request
+is submitted every 10 ms, the average latency will be more
+than 10 ms.
+
+Similarly, if a delay of 10 ms is specified to have two
+lanes (-D 10:2), then the device will be able to service
+two requests at a time, each with a minimum latency of
+10 ms. So, if two requests are submitted every 10 ms, then
+the average latency will be 10 ms; but if more than two
+requests are submitted every 10 ms, the average latency
+will be more than 10 ms.
+
+Also note, these delays are additive. So two invocations
+of '-D 10:1', is roughly equivalent to a single invocation
+of '-D 10:2'. This also means, one can specify multiple
+lanes with differing target latencies. For example, an
+invocation of '-D 10:1' followed by '-D 25:2' will
+create 3 lanes on the device; one lane with a latency
+of 10 ms and two lanes with a 25 ms latency.
+
+.TP
+.B "zinject \-d \fIvdev\fB [\-e \fIdevice_error\fB] [\-L \fIlabel_error\fB] [\-T \fIfailure\fB] [\-F] \fIpool\fB"
+Force a vdev error.
+.TP
+.B "zinject \-I [\-s \fIseconds\fB | \-g \fItxgs\fB] \fIpool\fB"
+Simulate a hardware failure that fails to honor a cache flush.
+.TP
+.B "zinject \-p \fIfunction\fB \fIpool\fB
+Panic inside the specified function.
+.TP
+.B "zinject \-t data [\-e \fIdevice_error\fB] [\-f \fIfrequency\fB] [\-l \fIlevel\fB] [\-r \fIrange\fB] [\-amq] \fIpath\fB"
+Force an error into the contents of a file.
+.TP
+.B "zinject \-t dnode [\-e \fIdevice_error\fB] [\-f \fIfrequency\fB] [\-l \fIlevel\fB] [\-amq] \fIpath\fB"
+Force an error into the metadnode for a file or directory.
+.TP
+.B "zinject \-t \fImos_type\fB [\-e \fIdevice_error\fB] [\-f \fIfrequency\fB] [\-l \fIlevel\fB] [\-r \fIrange\fB] [\-amqu] \fIpool\fB"
+Force an error into the MOS of a pool.
+.SH OPTIONS
+.TP
+.BI "\-a"
+Flush the ARC before injection.
+.TP
+.BI "\-b" " objset:object:level:start:end"
+Force an error into the pool at this bookmark tuple. Each number is
+in hexidecimal, and only one block can be specified.
+.TP
+.BI "\-d" " vdev"
+A vdev specified by path or GUID.
+.TP
+.BI "\-e" " device_error"
+Specify
+.BR "checksum" " for an ECKSUM error,"
+.BR "dtl" " for an ECHILD error,"
+.BR "io" " for an EIO error where reopening the device will succeed, or"
+.BR "nxio" " for an ENXIO error where reopening the device will fail."
+.TP
+.BI "\-f" " frequency"
+Only inject errors a fraction of the time. Expressed as an integer
+percentage between 1 and 100.
+.TP
+.BI "\-F"
+Fail faster. Do fewer checks.
+.TP
+.BI "\-g" " txgs"
+Run for this many transaction groups before reporting failure.
+.TP
+.BI "\-h"
+Print the usage message.
+.TP
+.BI "\-l" " level"
+Inject an error at a particular block level. The default is 0.
+.TP
+.BI "\-L" " label_error"
+Set the label error region to one of
+.BR " nvlist" ","
+.BR " pad1" ","
+.BR " pad2" ", or"
+.BR " uber" "."
+.TP
+.BI "\-m"
+Automatically remount the underlying filesystem.
+.TP
+.BI "\-q"
+Quiet mode. Only print the handler number added.
+.TP
+.BI "\-r" " range"
+Inject an error over a particular logical range of an object, which
+will be translated to the appropriate blkid range according to the
+object's properties.
+.TP
+.BI "\-s" " seconds"
+Run for this many seconds before reporting failure.
+.TP
+.BI "\-T" " failure"
+Set the failure type to one of
+.BR " all" ","
+.BR " claim" ","
+.BR " free" ","
+.BR " read" ", or"
+.BR " write" "."
+.TP
+.BI "\-t" " mos_type"
+Set this to
+.BR "mos " "for any data in the MOS,"
+.BR "mosdir " "for an object directory,"
+.BR "config " "for the pool configuration,"
+.BR "bpobj " "for the block pointer list,"
+.BR "spacemap " "for the space map,"
+.BR "metaslab " "for the metaslab, or"
+.BR "errlog " "for the persistent error log."
+.TP
+.BI "\-u"
+Unload the pool after injection.
+
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.B "ZINJECT_DEBUG"
+Run \fBzinject\fR in debug mode.
+
+.SH "AUTHORS"
+This man page was written by Darik Horn <dajhorn@vanadac.com>
+excerpting the \fBzinject\fR usage message and source code.
+
+.SH "SEE ALSO"
+.BR zpool (8),
+.BR zfs (8)
diff --git a/zfs/man/man8/zpool.8 b/zfs/man/man8/zpool.8
new file mode 100644 (file)
index 0000000..43dccc0
--- /dev/null
@@ -0,0 +1,2585 @@
+'\" te
+.\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved.
+.\" Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+.\" Copyright (c) 2013 by Delphix. All rights reserved.
+.\" Copyright (c) 2012 Cyril Plisko. All Rights Reserved.
+.\" 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]
+.TH zpool 8 "May 11, 2016" "ZFS pool 28, filesystem 5" "System Administration Commands"
+.SH NAME
+zpool \- configures ZFS storage pools
+.SH SYNOPSIS
+.LP
+.nf
+\fBzpool\fR [\fB-?\fR]
+.fi
+
+.LP
+.nf
+\fBzpool add\fR [\fB-fgLnP\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIvdev\fR ...
+.fi
+
+.LP
+.nf
+\fBzpool attach\fR [\fB-f\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIdevice\fR \fInew_device\fR
+.fi
+
+.LP
+.nf
+\fBzpool clear\fR \fIpool\fR [\fIdevice\fR]
+.fi
+
+.LP
+.nf
+\fBzpool create\fR [\fB-fnd\fR] [\fB-o\fR \fIproperty=value\fR] ... [\fB-o\fR feature@\fIfeature=value\fR]
+     ... [\fB-O\fR \fIfile-system-property=value\fR] ... [\fB-m\fR \fImountpoint\fR] [\fB-R\fR \fIroot\fR]
+     ... [\fB-t\fR \fItname\fR] \fIpool\fR \fIvdev\fR ...
+.fi
+
+.LP
+.nf
+\fBzpool destroy\fR [\fB-f\fR] \fIpool\fR
+.fi
+
+.LP
+.nf
+\fBzpool detach\fR \fIpool\fR \fIdevice\fR
+.fi
+
+.LP
+.nf
+\fBzpool events\fR [\fB-vHfc\fR] [\fIpool\fR] ...
+.fi
+
+.LP
+.nf
+\fBzpool export\fR [\fB-a\fR] [\fB-f\fR] \fIpool\fR ...
+.fi
+
+.LP
+.nf
+\fBzpool get\fR [\fB-Hp\fR] [\fB-o \fR\fIfield\fR[,...]] "\fIall\fR" | \fIproperty\fR[,...] \fIpool\fR ...
+.fi
+
+.LP
+.nf
+\fBzpool history\fR [\fB-il\fR] [\fIpool\fR] ...
+.fi
+
+.LP
+.nf
+\fBzpool import\fR [\fB-d\fR \fIdir\fR] [\fB-D\fR]
+.fi
+
+.LP
+.nf
+\fBzpool import\fR [\fB-o \fImntopts\fR\fR] [\fB-o\fR \fIproperty=value\fR] ... [\fB-d\fR \fIdir\fR | \fB-c\fR \fIcachefile\fR]
+     [\fB-D\fR] [\fB-f\fR] [\fB-m\fR] [\fB-N\fR] [\fB-R\fR \fIroot\fR] [\fB-F\fR [\fB-n\fR] [\fB-X\fR\] [\fB-T\fR\]] [\fB-s\fR] \fB-a\fR
+.fi
+
+.LP
+.nf
+\fBzpool import\fR [\fB-o \fImntopts\fR\fR] [\fB-o\fR \fIproperty=value\fR] ... [\fB-d\fR \fIdir\fR | \fB-c\fR \fIcachefile\fR]
+     [\fB-D\fR] [\fB-f\fR] [\fB-m\fR] [\fB-R\fR \fIroot\fR] [\fB-F\fR [\fB-n\fR] [\fB-X\fR] [\fB-T\fR\]] [\fB-t\fR]] [\fB-s\fR]
+     \fIpool\fR | \fIid\fR [\fInewpool\fR]
+.fi
+
+.LP
+.nf
+\fB\fBzpool iostat\fR [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-ghHLpPvy\fR] [\fB-lq\fR]|[\fB-r\fR|-\fBw\fR]]
+     [[\fIpool\fR ...]|[\fIpool vdev\fR ...]|[\fIvdev\fR ...]] [\fIinterval\fR[\fIcount\fR]]\fR
+
+.fi
+
+.LP
+.nf
+\fBzpool labelclear\fR [\fB-f\fR] \fIdevice\fR
+.fi
+
+.LP
+.nf
+\fBzpool list\fR [\fB-T\fR d | u ] [\fB-HgLpPv\fR] [\fB-o\fR \fIproperty\fR[,...]] [\fIpool\fR] ...
+     [\fIinterval\fR[\fIcount\fR]]
+.fi
+
+.LP
+.nf
+\fBzpool offline\fR [\fB-t\fR] \fIpool\fR \fIdevice\fR ...
+.fi
+
+.LP
+.nf
+\fBzpool online\fR \fIpool\fR \fIdevice\fR ...
+.fi
+
+.LP
+.nf
+\fBzpool reguid\fR \fIpool\fR
+.fi
+
+.LP
+.nf
+\fBzpool reopen\fR \fIpool\fR
+.fi
+
+.LP
+.nf
+\fBzpool remove\fR \fIpool\fR \fIdevice\fR ...
+.fi
+
+.LP
+.nf
+\fBzpool replace\fR [\fB-f\fR] [\fB-o\fR \fIproperty=value\fR]  \fIpool\fR \fIdevice\fR [\fInew_device\fR]
+.fi
+
+.LP
+.nf
+\fBzpool scrub\fR [\fB-s\fR] \fIpool\fR ...
+.fi
+
+.LP
+.nf
+\fBzpool set\fR \fIproperty\fR=\fIvalue\fR \fIpool\fR
+.fi
+
+.LP
+.nf
+\fBzpool split\fR [\fB-gLnP\fR] [\fB-R\fR \fIaltroot\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fInewpool\fR [\fIdevice\fR ...]
+.fi
+
+.LP
+.nf
+\fBzpool status\fR [\fB-gLPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]]
+.fi
+
+.LP
+.nf
+\fBzpool upgrade\fR
+.fi
+
+.LP
+.nf
+\fBzpool upgrade\fR \fB-v\fR
+.fi
+
+.LP
+.nf
+\fBzpool upgrade\fR [\fB-V\fR \fIversion\fR] \fB-a\fR | \fIpool\fR ...
+.fi
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBzpool\fR command configures \fBZFS\fR storage pools. A storage pool is a collection of devices that provides physical storage and data replication for \fBZFS\fR datasets.
+.sp
+.LP
+All datasets within a storage pool share the same space. See \fBzfs\fR(8) for information on managing datasets.
+.SS "Virtual Devices (\fBvdev\fRs)"
+.sp
+.LP
+A "virtual device" describes a single device or a collection of devices organized according to certain performance and fault characteristics. The following virtual devices are supported:
+.sp
+.ne 2
+.na
+\fB\fBdisk\fR\fR
+.ad
+.RS 10n
+A block device, typically located under \fB/dev\fR. \fBZFS\fR can use individual partitions, though the recommended mode of operation is to use whole disks. A disk can be specified by a full path, or it can be a shorthand name (the relative portion of the path under "/dev"). For example, "sda" is equivalent to "/dev/sda". A whole disk can be specified by omitting the partition designation. When given a whole disk, \fBZFS\fR automatically labels the disk, if necessary.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfile\fR\fR
+.ad
+.RS 10n
+A regular file. The use of files as a backing store is strongly discouraged. It is designed primarily for experimental purposes, as the fault tolerance of a file is only as good as the file system of which it is a part. A file must be specified by a full path.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBmirror\fR\fR
+.ad
+.RS 10n
+A mirror of two or more devices. Data is replicated in an identical fashion across all components of a mirror. A mirror with \fIN\fR disks of size \fIX\fR can hold \fIX\fR bytes and can withstand (\fIN-1\fR) devices failing before data integrity is compromised.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBraidz\fR\fR
+.ad
+.br
+.na
+\fB\fBraidz1\fR\fR
+.ad
+.br
+.na
+\fB\fBraidz2\fR\fR
+.ad
+.br
+.na
+\fB\fBraidz3\fR\fR
+.ad
+.RS 10n
+A variation on \fBRAID-5\fR that allows for better distribution of parity and eliminates the "\fBRAID-5\fR write hole" (in which data and parity become inconsistent after a power loss). Data and parity is striped across all disks within a \fBraidz\fR group.
+.sp
+A \fBraidz\fR group can have single-, double- , or triple parity, meaning that the \fBraidz\fR group can sustain one, two, or three failures, respectively, without losing any data. The \fBraidz1\fR \fBvdev\fR type specifies a single-parity \fBraidz\fR group; the \fBraidz2\fR \fBvdev\fR type specifies a double-parity \fBraidz\fR group; and the \fBraidz3\fR \fBvdev\fR type specifies a triple-parity \fBraidz\fR group. The \fBraidz\fR \fBvdev\fR type is an alias for \fBraidz1\fR.
+.sp
+A \fBraidz\fR group with \fIN\fR disks of size \fIX\fR with \fIP\fR parity disks can hold approximately (\fIN-P\fR)*\fIX\fR bytes and can withstand \fIP\fR device(s) failing before data integrity is compromised. The minimum number of devices in a \fBraidz\fR group is one more than the number of parity disks. The recommended number is between 3 and 9 to help increase performance.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBspare\fR\fR
+.ad
+.RS 10n
+A special pseudo-\fBvdev\fR which keeps track of available hot spares for a pool. For more information, see the "Hot Spares" section.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlog\fR\fR
+.ad
+.RS 10n
+A separate-intent log device. If more than one log device is specified, then writes are load-balanced between devices. Log devices can be mirrored. However, \fBraidz\fR \fBvdev\fR types are not supported for the intent log. For more information, see the "Intent Log" section.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcache\fR\fR
+.ad
+.RS 10n
+A device used to cache storage pool data. A cache device cannot be configured as a mirror or \fBraidz\fR group. For more information, see the "Cache Devices" section.
+.RE
+
+.sp
+.LP
+Virtual devices cannot be nested, so a mirror or \fBraidz\fR virtual device can only contain files or disks. Mirrors of mirrors (or other combinations) are not allowed.
+.sp
+.LP
+A pool can have any number of virtual devices at the top of the configuration (known as "root vdevs"). Data is dynamically distributed across all top-level devices to balance data among devices. As new virtual devices are added, \fBZFS\fR automatically places data on the newly available devices.
+.sp
+.LP
+Virtual devices are specified one at a time on the command line, separated by whitespace. The keywords "mirror" and "raidz" are used to distinguish where a group ends and another begins. For example, the following creates two root vdevs, each a mirror of two disks:
+.sp
+.in +2
+.nf
+# \fBzpool create mypool mirror sda sdb mirror sdc sdd\fR
+.fi
+.in -2
+.sp
+
+.SS "Device Failure and Recovery"
+.sp
+.LP
+\fBZFS\fR supports a rich set of mechanisms for handling device failure and data corruption. All metadata and data is checksummed, and \fBZFS\fR automatically repairs bad data from a good copy when corruption is detected.
+.sp
+.LP
+In order to take advantage of these features, a pool must make use of some form of redundancy, using either mirrored or \fBraidz\fR groups. While \fBZFS\fR supports running in a non-redundant configuration, where each root vdev is simply a disk or file, this is strongly discouraged. A single case of bit corruption can render some or all of your data unavailable.
+.sp
+.LP
+A pool's health status is described by one of three states: online, degraded, or faulted. An online pool has all devices operating normally. A degraded pool is one in which one or more devices have failed, but the data is still available due to a redundant configuration. A faulted pool has corrupted metadata, or one or more faulted devices, and insufficient replicas to continue functioning.
+.sp
+.LP
+The health of the top-level vdev, such as mirror or \fBraidz\fR device, is potentially impacted by the state of its associated vdevs, or component devices. A top-level vdev or component device is in one of the following states:
+.sp
+.ne 2
+.na
+\fB\fBDEGRADED\fR\fR
+.ad
+.RS 12n
+One or more top-level vdevs is in the degraded state because one or more component devices are offline. Sufficient replicas exist to continue functioning.
+.sp
+One or more component devices is in the degraded or faulted state, but sufficient replicas exist to continue functioning. The underlying conditions are as follows:
+.RS +4
+.TP
+.ie t \(bu
+.el o
+The number of checksum errors exceeds acceptable levels and the device is degraded as an indication that something may be wrong. \fBZFS\fR continues to use the device as necessary.
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+The number of I/O errors exceeds acceptable levels. The device could not be marked as faulted because there are insufficient replicas to continue functioning.
+.RE
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBFAULTED\fR\fR
+.ad
+.RS 12n
+One or more top-level vdevs is in the faulted state because one or more component devices are offline. Insufficient replicas exist to continue functioning.
+.sp
+One or more component devices is in the faulted state, and insufficient replicas exist to continue functioning. The underlying conditions are as follows:
+.RS +4
+.TP
+.ie t \(bu
+.el o
+The device could be opened, but the contents did not match expected values.
+.RE
+.RS +4
+.TP
+.ie t \(bu
+.el o
+The number of I/O errors exceeds acceptable levels and the device is faulted to prevent further use of the device.
+.RE
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBOFFLINE\fR\fR
+.ad
+.RS 12n
+The device was explicitly taken offline by the "\fBzpool offline\fR" command.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBONLINE\fR\fR
+.ad
+.RS 12n
+The device is online and functioning.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBREMOVED\fR\fR
+.ad
+.RS 12n
+The device was physically removed while the system was running. Device removal detection is hardware-dependent and may not be supported on all platforms.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBUNAVAIL\fR\fR
+.ad
+.RS 12n
+The device could not be opened. If a pool is imported when a device was unavailable, then the device will be identified by a unique identifier instead of its path since the path was never correct in the first place.
+.RE
+
+.sp
+.LP
+If a device is removed and later re-attached to the system, \fBZFS\fR attempts to put the device online automatically. Device attach detection is hardware-dependent and might not be supported on all platforms.
+.SS "Hot Spares"
+.sp
+.LP
+\fBZFS\fR allows devices to be associated with pools as "hot spares". These devices are not actively used in the pool, but when an active device fails, it is automatically replaced by a hot spare. To create a pool with hot spares, specify a "spare" \fBvdev\fR with any number of devices. For example,
+.sp
+.in +2
+.nf
+# zpool create pool mirror sda sdb spare sdc sdd
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+Spares can be shared across multiple pools, and can be added with the "\fBzpool add\fR" command and removed with the "\fBzpool remove\fR" command. Once a spare replacement is initiated, a new "spare" \fBvdev\fR is created within the configuration that will remain there until the original device is replaced. At this point, the hot spare becomes available again.
+.sp
+.LP
+If a pool has a shared spare that is currently being used, the pool can not be exported since other pools may use this shared spare, which may lead to potential data corruption.
+.sp
+.LP
+An in-progress spare replacement can be cancelled by detaching the hot spare. If the original faulted device is detached, then the hot spare assumes its place in the configuration, and is removed from the spare list of all active pools.
+.sp
+.LP
+Spares cannot replace log devices.
+.SS "Intent Log"
+.sp
+.LP
+The \fBZFS\fR Intent Log (\fBZIL\fR) satisfies \fBPOSIX\fR requirements for synchronous transactions. For instance, databases often require their transactions to be on stable storage devices when returning from a system call. \fBNFS\fR and other applications can also use \fBfsync\fR() to ensure data stability. By default, the intent log is allocated from blocks within the main pool. However, it might be possible to get better performance using separate intent log devices such as \fBNVRAM\fR or a dedicated disk. For example:
+.sp
+.in +2
+.nf
+\fB# zpool create pool sda sdb log sdc\fR
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+Multiple log devices can also be specified, and they can be mirrored. See the EXAMPLES section for an example of mirroring multiple log devices.
+.sp
+.LP
+Log devices can be added, replaced, attached, detached, and imported and exported as part of the larger pool. Mirrored log devices can be removed by specifying the top-level mirror for the log.
+.SS "Cache Devices"
+.sp
+.LP
+Devices can be added to a storage pool as "cache devices." These devices provide an additional layer of caching between main memory and disk. For read-heavy workloads, where the working set size is much larger than what can be cached in main memory, using cache devices allow much more of this working set to be served from low latency media. Using cache devices provides the greatest performance improvement for random read-workloads of mostly static content.
+.sp
+.LP
+To create a pool with cache devices, specify a "cache" \fBvdev\fR with any number of devices. For example:
+.sp
+.in +2
+.nf
+\fB# zpool create pool sda sdb cache sdc sdd\fR
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+Cache devices cannot be mirrored or part of a \fBraidz\fR configuration. If a read error is encountered on a cache device, that read \fBI/O\fR is reissued to the original storage pool device, which might be part of a mirrored or \fBraidz\fR configuration.
+.sp
+.LP
+The content of the cache devices is considered volatile, as is the case with other system caches.
+.SS "Properties"
+.sp
+.LP
+Each pool has several properties associated with it. Some properties are read-only statistics while others are configurable and change the behavior of the pool. The following are read-only properties:
+.sp
+.ne 2
+.na
+\fB\fBavailable\fR\fR
+.ad
+.RS 20n
+Amount of storage available within the pool. This property can also be referred to by its shortened column name, "avail".
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcapacity\fR\fR
+.ad
+.RS 20n
+Percentage of pool space used. This property can also be referred to by its shortened column name, "cap".
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBexpandsize\fR\fR
+.ad
+.RS 20n
+Amount of uninitialized space within the pool or device that can be used to
+increase the total capacity of the pool.  Uninitialized space consists of
+any space on an EFI labeled vdev which has not been brought online
+(i.e. zpool online -e).  This space occurs when a LUN is dynamically expanded.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfragmentation\fR\fR
+.ad
+.RS 20n
+The amount of fragmentation in the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfree\fR\fR
+.ad
+.RS 20n
+The amount of free space available in the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfreeing\fR\fR
+.ad
+.RS 20n
+After a file system or snapshot is destroyed, the space it was using is
+returned to the pool asynchronously. \fB\fBfreeing\fR\fR is the amount of
+space remaining to be reclaimed. Over time \fB\fBfreeing\fR\fR will decrease
+while \fB\fBfree\fR\fR increases.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBhealth\fR\fR
+.ad
+.RS 20n
+The current health of the pool. Health can be "\fBONLINE\fR", "\fBDEGRADED\fR", "\fBFAULTED\fR", " \fBOFFLINE\fR", "\fBREMOVED\fR", or "\fBUNAVAIL\fR".
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBguid\fR\fR
+.ad
+.RS 20n
+A unique identifier for the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBsize\fR\fR
+.ad
+.RS 20n
+Total size of the storage pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBunsupported@\fR\fIfeature_guid\fR\fR
+.ad
+.RS 20n
+.sp
+Information about unsupported features that are enabled on the pool. See
+\fBzpool-features\fR(5) for details.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBused\fR\fR
+.ad
+.RS 20n
+Amount of storage space used within the pool.
+.RE
+
+.sp
+.LP
+The space usage properties report actual physical space available to the storage pool. The physical space can be different from the total amount of space that any contained datasets can actually use. The amount of space used in a \fBraidz\fR configuration depends on the characteristics of the data being written. In addition, \fBZFS\fR reserves some space for internal accounting that the \fBzfs\fR(8) command takes into account, but the \fBzpool\fR command does not. For non-full pools of a reasonable size, these effects should be invisible. For small pools, or pools that are close to being completely full, these discrepancies may become more noticeable.
+
+.sp
+.LP
+The following property can be set at creation time:
+.sp
+.ne 2
+.na
+\fB\fBashift\fR=\fIashift\fR\fR
+.ad
+.sp .6
+.RS 4n
+Pool sector size exponent, to the power of 2 (internally referred to as "ashift"). Values from 9 to 13, inclusive, are valid; also, the special value 0 (the default) means to auto-detect using the kernel's block layer and a ZFS internal exception list. I/O operations will be aligned to the specified size boundaries. Additionally, the minimum (disk) write size will be set to the specified size, so this represents a space vs. performance trade-off. The typical case for setting this property is when performance is important and the underlying disks use 4KiB sectors but report 512B sectors to the OS (for compatibility reasons); in that case, set \fBashift=12\fR (which is 1<<12 = 4096).
+.LP
+For optimal performance, the pool sector size should be greater than or equal to the sector size of the underlying disks. Since the property cannot be changed after pool creation, if in a given pool, you \fIever\fR want to use drives that \fIreport\fR 4KiB sectors, you must set \fBashift=12\fR at pool creation time.
+.LP
+Keep in mind is that the \fBashift\fR is \fIvdev\fR specific and is not a \fIpool\fR global.  This means that when adding new vdevs to an existing pool you may need to specify the \fBashift\fR.
+.RE
+
+.sp
+.LP
+The following property can be set at creation time and import time:
+.sp
+.ne 2
+.na
+\fB\fBaltroot\fR=(unset) | \fIpath\fR\fR
+.ad
+.sp .6
+.RS 4n
+Alternate root directory. If set, this directory is prepended to any mount points within the pool. This can be used when examining an unknown pool where the mount points cannot be trusted, or in an alternate boot environment, where the typical paths are not valid. \fBaltroot\fR is not a persistent property. It is valid only while the system is up. Setting \fBaltroot\fR defaults to using \fBcachefile\fR=none, though this may be overridden using an explicit setting.
+.RE
+
+.sp
+.LP
+The following property can only be set at import time:
+.sp
+.ne 2
+.na
+\fB\fBreadonly\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+If set to \fBon\fR, the pool will be imported in read-only mode: Synchronous data in the intent log will not be accessible, properties of the pool can not be changed and datasets of the pool can only be mounted read-only.  The \fBreadonly\fR property of its datasets will be implicitly set to \fBon\fR.
+
+It can also be specified by its column name of \fBrdonly\fR.
+
+To write to a read-only pool, a export and import of the pool is required.
+.RE
+
+.sp
+.LP
+The following properties can be set at creation time and import time, and later changed with the \fBzpool set\fR command:
+.sp
+.ne 2
+.na
+\fB\fBautoexpand\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls automatic pool expansion when the underlying LUN is grown. If set to \fBon\fR, the pool will be resized according to the size of the expanded device. If the device is part of a mirror or \fBraidz\fR then all devices within that mirror/\fBraidz\fR group must be expanded before the new space is made available to the pool. The default behavior is \fBoff\fR. This property can also be referred to by its shortened column name, \fBexpand\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBautoreplace\fR=\fBoff\fR | \fBon\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls automatic device replacement. If set to "\fBoff\fR", device replacement must be initiated by the administrator by using the "\fBzpool replace\fR" command. If set to "\fBon\fR", any new device, found in the same physical location as a device that previously belonged to the pool, is automatically formatted and replaced. The default behavior is "\fBoff\fR". This property can also be referred to by its shortened column name, "replace".  Autoreplace can also be used with virtual disks (like device mapper) provided that you use the /dev/disk/by-vdev paths setup by vdev_id.conf.  See the vdev_id.conf man page for more details.  Autoreplace and autoonline require libudev to be present at build time.  If you're using device mapper disks, you must have libdevmapper installed at build time as well.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBbootfs\fR=(unset) | \fIpool\fR/\fIdataset\fR\fR
+.ad
+.sp .6
+.RS 4n
+Identifies the default bootable dataset for the root pool. This property is expected to be set mainly by the installation and upgrade programs. Not all Linux distribution boot processes use the \fBbootfs\fR property.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcachefile\fR=fBnone\fR | \fIpath\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the location of where the pool configuration is cached. Discovering all pools on system startup requires a cached copy of the configuration data that is stored on the root file system. All pools in this cache are automatically imported when the system boots. Some environments, such as install and clustering, need to cache this information in a different location so that pools are not automatically imported. Setting this property caches the pool configuration in a different location that can later be imported with "\fBzpool import -c\fR". Setting it to the special value "\fBnone\fR" creates a temporary pool that is never cached, and the special value \fB\&''\fR (empty string) uses the default location.
+.sp
+Multiple pools can share the same cache file. Because the kernel destroys and recreates this file when pools are added and removed, care should be taken when attempting to access this file. When the last pool using a \fBcachefile\fR is exported or destroyed, the file is removed.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcomment\fR=(unset) | \fB\fItext\fR\fR
+.ad
+.sp .6
+.RS 4n
+A text string consisting of printable ASCII characters that will be stored such that it is available even if the pool becomes faulted.  An administrator can provide additional information about a pool using this property.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdedupditto\fR=\fB\fInumber\fR\fR
+.ad
+.sp .6
+.RS 4n
+Threshold for the number of block ditto copies. If the reference count for a deduplicated block increases above this number, a new ditto copy of this block is automatically stored. The default setting is 0 which causes no ditto copies to be created for deduplicated blocks.  The minimum valid nonzero setting is 100.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdelegation\fR=\fBon\fR | \fBoff\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether a non-privileged user is granted access based on the dataset permissions defined on the dataset. See \fBzfs\fR(8) for more information on \fBZFS\fR delegated administration.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfailmode\fR=\fBwait\fR | \fBcontinue\fR | \fBpanic\fR\fR
+.ad
+.sp .6
+.RS 4n
+Controls the system behavior in the event of catastrophic pool failure. This condition is typically a result of a loss of connectivity to the underlying storage device(s) or a failure of all devices within the pool. The behavior of such an event is determined as follows:
+.sp
+.ne 2
+.na
+\fB\fBwait\fR\fR
+.ad
+.RS 12n
+Blocks all \fBI/O\fR access until the device connectivity is recovered and the errors are cleared. This is the default behavior.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBcontinue\fR\fR
+.ad
+.RS 12n
+Returns \fBEIO\fR to any new write \fBI/O\fR requests but allows reads to any of the remaining healthy devices. Any write requests that have yet to be committed to disk would be blocked.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBpanic\fR\fR
+.ad
+.RS 12n
+Prints out a message to the console and generates a system crash dump.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBfeature@\fR\fIfeature_name\fR=\fBenabled\fR\fR
+.ad
+.RS 4n
+The value of this property is the current state of \fIfeature_name\fR. The
+only valid value when setting this property is \fBenabled\fR which moves
+\fIfeature_name\fR to the enabled state. See \fBzpool-features\fR(5) for
+details on feature states.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBlistsnapshots\fR=on | off\fR
+.ad
+.sp .6
+.RS 4n
+Controls whether information about snapshots associated with this pool is output when "\fBzfs list\fR" is run without the \fB-t\fR option. The default value is "off".
+.sp
+This property can also be referred to by its shortened name, \fBlistsnaps\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBversion\fR=(unset) | \fIversion\fR\fR
+.ad
+.sp .6
+.RS 4n
+The current on-disk version of the pool. This can be increased, but never decreased. The preferred method of updating pools is with the "\fBzpool upgrade\fR" command, though this property can be used when a specific version is needed for backwards compatibility. Once feature flags are enabled on a pool this property will no longer have a value.
+.RE
+
+.SS "Subcommands"
+.sp
+.LP
+All subcommands that modify state are logged persistently to the pool in their original form.
+.sp
+.LP
+The \fBzpool\fR command provides subcommands to create and destroy storage pools, add capacity to storage pools, and provide information about the storage pools. The following subcommands are supported:
+.sp
+.ne 2
+.na
+\fB\fBzpool\fR \fB-?\fR\fR
+.ad
+.sp .6
+.RS 4n
+Displays a help message.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool add\fR [\fB-fgLnP\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIvdev\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Adds the specified virtual devices to the given pool. The \fIvdev\fR specification is described in the "Virtual Devices" section. The behavior of the \fB-f\fR option, and the device checks performed are described in the "zpool create" subcommand.
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.RS 6n
+Forces use of \fBvdev\fRs, even if they appear in use or specify a conflicting replication level. Not all devices can be overridden in this manner.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-g\fR\fR
+.ad
+.RS 6n
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 6n
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.RS 6n
+Displays the configuration that would be used without actually adding the \fBvdev\fRs. The actual pool creation can still fail due to insufficient privileges or device sharing.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-P\fR\fR
+.ad
+.RS 6n
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty=value\fR
+.ad
+.sp .6
+.RS 4n
+Sets the given pool properties. See the "Properties" section for a list of valid properties that can be set. The only property supported at the moment is \fBashift\fR.  \fBDo note\fR that some properties (among them \fBashift\fR) are \fInot\fR inherited from a previous vdev. They are vdev specific, not pool specific.
+.RE
+
+Do not add a disk that is currently configured as a quorum device to a zpool. After a disk is in the pool, that disk can then be configured as a quorum device.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool attach\fR [\fB-f\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIdevice\fR \fInew_device\fR\fR
+.ad
+.sp .6
+.RS 4n
+Attaches \fInew_device\fR to an existing \fBzpool\fR device. The existing device cannot be part of a \fBraidz\fR configuration. If \fIdevice\fR is not currently part of a mirrored configuration, \fIdevice\fR automatically transforms into a two-way mirror of \fIdevice\fR and \fInew_device\fR. If \fIdevice\fR is part of a two-way mirror, attaching \fInew_device\fR creates a three-way mirror, and so on. In either case, \fInew_device\fR begins to resilver immediately.
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.RS 6n
+Forces use of \fInew_device\fR, even if its appears to be in use. Not all devices can be overridden in this manner.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty=value\fR
+.ad
+.sp .6
+.RS 4n
+Sets the given pool properties. See the "Properties" section for a list of valid properties that can be set. The only property supported at the moment is "ashift".
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool clear\fR \fIpool\fR [\fIdevice\fR] ...\fR
+.ad
+.sp .6
+.RS 4n
+Clears device errors in a pool. If no arguments are specified, all device errors within the pool are cleared. If one or more devices is specified, only those errors associated with the specified device or devices are cleared.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool create\fR [\fB-fnd\fR] [\fB-o\fR \fIproperty=value\fR] ... [\fB-o\fR feature@\fIfeature=value\fR] ... [\fB-O\fR \fIfile-system-property=value\fR] ... [\fB-m\fR \fImountpoint\fR] [\fB-R\fR \fIroot\fR] [\fB-t\fR \fItname\fR] \fIpool\fR \fIvdev\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Creates a new storage pool containing the virtual devices specified on the command line. The pool name must begin with a letter, and can only contain alphanumeric characters as well as underscore ("_"), dash ("-"), period ("."), colon (":"), and space (" "). The pool names "mirror", "raidz", "spare" and "log" are reserved, as are names beginning with the pattern "c[0-9]". The \fBvdev\fR specification is described in the "Virtual Devices" section.
+.sp
+The command verifies that each device specified is accessible and not currently in use by another subsystem. There are some uses, such as being currently mounted, or specified as the dedicated dump device, that prevents a device from ever being used by \fBZFS\fR. Other uses, such as having a preexisting \fBUFS\fR file system, can be overridden with the \fB-f\fR option.
+.sp
+The command also checks that the replication strategy for the pool is consistent. An attempt to combine redundant and non-redundant storage in a single pool, or to mix disks and files, results in an error unless \fB-f\fR is specified. The use of differently sized devices within a single \fBraidz\fR or mirror group is also flagged as an error unless \fB-f\fR is specified.
+.sp
+Unless the \fB-R\fR option is specified, the default mount point is "/\fIpool\fR". The mount point must not exist or must be empty, or else the root dataset cannot be mounted. This can be overridden with the \fB-m\fR option.
+.sp
+By default all supported features are enabled on the new pool unless the \fB-d\fR option is specified.
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.sp .6
+.RS 4n
+Forces use of \fBvdev\fRs, even if they appear in use or specify a conflicting replication level. Not all devices can be overridden in this manner.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Displays the configuration that would be used without actually creating the pool. The actual pool creation can still fail due to insufficient privileges or device sharing.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-d\fR\fR
+.ad
+.sp .6
+.RS 4n
+Do not enable any features on the new pool. Individual features can be enabled by setting their corresponding properties to \fBenabled\fR with the \fB-o\fR option. See \fBzpool-features\fR(5) for details about feature properties.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty=value\fR [\fB-o\fR \fIproperty=value\fR] ...\fR
+.ad
+.sp .6
+.RS 4n
+Sets the given pool properties. See the "Properties" section for a list of valid properties that can be set.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR feature@\fIfeature=value\fR [\fB-o\fR feature@\fIfeature=value\fR] ...\fR
+.ad
+.sp .6
+.RS 4n
+Sets the given pool feature. See \fBzpool-features(5)\fR for a list of valid features that can be set.
+.sp
+Value can be either \fBdisabled\fR or \fBenabled\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-O\fR \fIfile-system-property=value\fR\fR
+.ad
+.br
+.na
+\fB[\fB-O\fR \fIfile-system-property=value\fR] ...\fR
+.ad
+.sp .6
+.RS 4n
+Sets the given file system properties in the root file system of the pool. See the "Properties" section of \fBzfs\fR(8) for a list of valid properties that can be set.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-R\fR \fIroot\fR\fR
+.ad
+.sp .6
+.RS 4n
+Equivalent to "-o cachefile=none,altroot=\fIroot\fR"
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-m\fR \fImountpoint\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the mount point for the root dataset. The default mount point is "/\fIpool\fR" or "\fBaltroot\fR/\fIpool\fR" if \fBaltroot\fR is specified. The mount point must be an absolute path, "\fBlegacy\fR", or "\fBnone\fR". For more information on dataset mount points, see \fBzfs\fR(8).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-t\fR \fItname\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the in-core pool name to "\fBtname\fR" while the on-disk name will be the name specified as the pool name "\fBpool\fR". This will set the default cachefile property to none. This is intended to handle name space collisions when creating pools for other systems, such as virtual machines or physical machines whose pools live on network block devices.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool destroy\fR [\fB-f\fR] \fIpool\fR\fR
+.ad
+.sp .6
+.RS 4n
+Destroys the given pool, freeing up any devices for other use. This command tries to unmount any active datasets before destroying the pool.
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.RS 6n
+Forces any active datasets contained within the pool to be unmounted.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool detach\fR \fIpool\fR \fIdevice\fR\fR
+.ad
+.sp .6
+.RS 4n
+Detaches \fIdevice\fR from a mirror. The operation is refused if there are no other valid replicas of the data.  If \fIdevice\fR may be re-added to the pool later on then consider the "\fBzpool offline\fR" command instead.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fBzpool events\fR [\fB-vHfc\fR] [\fIpool\fR] ...
+.ad
+.sp .6
+.RS 4n
+Description of the different events generated by the ZFS kernel modules. See \fBzfs-events\fR(5) for more information about the subclasses and event payloads that can be generated.
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.RS 6n
+Get a full detail of the events and what information is available about it.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-H\fR\fR
+.ad
+.RS 6n
+Scripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.RS 6n
+Follow mode.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-c\fR\fR
+.ad
+.RS 6n
+Clear all previous events.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool export\fR [\fB-a\fR] [\fB-f\fR] \fIpool\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Exports the given pools from the system. All devices are marked as exported, but are still considered in use by other subsystems. The devices can be moved between systems (even those of different endianness) and imported as long as a sufficient number of devices are present.
+.sp
+Before exporting the pool, all datasets within the pool are unmounted. A pool can not be exported if it has a shared spare that is currently being used.
+.sp
+For pools to be portable, you must give the \fBzpool\fR command whole disks, not just partitions, so that \fBZFS\fR can label the disks with portable \fBEFI\fR labels. Otherwise, disk drivers on platforms of different endianness will not recognize the disks.
+.sp
+.ne 2
+.na
+\fB\fB-a\fR\fR
+.ad
+.RS 6n
+Exports all pools imported on the system.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.RS 6n
+Forcefully unmount all datasets, using the "\fBunmount -f\fR" command.
+.sp
+This command will forcefully export the pool even if it has a shared spare that is currently being used. This may lead to potential data corruption.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool get\fR [\fB-Hp\fR] [\fB-o \fR\fIfield\fR[,...]]  "\fIall\fR" | \fIproperty\fR[,...]
+\fIpool\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Retrieves the given list of properties (or all properties if "\fBall\fR" is used) for the specified storage pool(s). These properties are displayed with the following fields:
+.sp
+.in +2
+.nf
+        name          Name of storage pool
+        property      Property name
+        value         Property value
+        source        Property source, either 'default' or 'local'.
+.fi
+.in -2
+.sp
+
+See the "Properties" section for more information on the available pool properties.
+
+.sp
+.ne 2
+.na
+\fB\fB-H\fR\fR
+.ad
+.RS 6n
+Scripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.RS 6n
+Display numbers in parsable (exact) values.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIfield\fR\fR
+.ad
+.RS 12n
+A comma-separated list of columns to display. \fBname,property,value,source\fR
+is the default value.
+.RE
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool history\fR [\fB-il\fR] [\fIpool\fR] ...\fR
+.ad
+.sp .6
+.RS 4n
+Displays the command history of the specified pools or all pools if no pool is specified.
+.sp
+.ne 2
+.na
+\fB\fB-i\fR\fR
+.ad
+.RS 6n
+Displays internally logged \fBZFS\fR events in addition to user initiated events.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-l\fR\fR
+.ad
+.RS 6n
+Displays log records in long format, which in addition to standard format includes, the user name, the hostname, and the zone in which the operation was performed.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool import\fR [\fB-d\fR \fIdir\fR | \fB-c\fR \fIcachefile\fR] [\fB-D\fR]\fR
+.ad
+.sp .6
+.RS 4n
+Lists pools available to import. If the \fB-d\fR option is not specified, this command searches for devices in "/dev". The \fB-d\fR option can be specified multiple times, and all directories are searched. If the device appears to be part of an exported pool, this command displays a summary of the pool with the name of the pool, a numeric identifier, as well as the \fIvdev\fR layout and current health of the device for each device or file. Destroyed pools, pools that were previously destroyed with the "\fBzpool destroy\fR" command, are not listed unless the \fB-D\fR option is specified.
+.sp
+The numeric identifier is unique, and can be used instead of the pool name when multiple exported pools of the same name are available.
+.sp
+.ne 2
+.na
+\fB\fB-c\fR \fIcachefile\fR\fR
+.ad
+.RS 16n
+Reads configuration from the given \fBcachefile\fR that was created with the "\fBcachefile\fR" pool property. This \fBcachefile\fR is used instead of searching for devices.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-d\fR \fIdir\fR\fR
+.ad
+.RS 16n
+Searches for devices or files in \fIdir\fR. The \fB-d\fR option can be specified multiple times.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-D\fR\fR
+.ad
+.RS 16n
+Lists destroyed pools only.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool import\fR [\fB-o\fR \fImntopts\fR] [ \fB-o\fR \fIproperty\fR=\fIvalue\fR] ... [\fB-d\fR \fIdir\fR | \fB-c\fR \fIcachefile\fR] [\fB-D\fR] [\fB-f\fR] [\fB-m\fR] [\fB-N\fR] [\fB-R\fR \fIroot\fR] [\fB-F\fR [\fB-n\fR]] [\fB-s\fR] \fB-a\fR\fR
+.ad
+.sp .6
+.RS 4n
+Imports all pools found in the search directories. Identical to the previous command, except that all pools with a sufficient number of devices available are imported. Destroyed pools, pools that were previously destroyed with the "\fBzpool destroy\fR" command, will not be imported unless the \fB-D\fR option is specified.
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fImntopts\fR\fR
+.ad
+.RS 21n
+Comma-separated list of mount options to use when mounting datasets within the pool. See \fBzfs\fR(8) for a description of dataset properties and mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty=value\fR\fR
+.ad
+.RS 21n
+Sets the specified property on the imported pool. See the "Properties" section for more information on the available pool properties.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-c\fR \fIcachefile\fR\fR
+.ad
+.RS 21n
+Reads configuration from the given \fBcachefile\fR that was created with the "\fBcachefile\fR" pool property. This \fBcachefile\fR is used instead of searching for devices.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-d\fR \fIdir\fR\fR
+.ad
+.RS 21n
+Searches for devices or files in \fIdir\fR. The \fB-d\fR option can be specified multiple times. This option is incompatible with the \fB-c\fR option.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-D\fR\fR
+.ad
+.RS 21n
+Imports destroyed pools only. The \fB-f\fR option is also required.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.RS 21n
+Forces import, even if the pool appears to be potentially active.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-F\fR\fR
+.ad
+.RS 21n
+Recovery mode for a non-importable pool. Attempt to return the pool to an importable state by discarding the last few transactions. Not all damaged pools can be recovered by using this option. If successful, the data from the discarded transactions is irretrievably lost. This option is ignored if the pool is importable or already imported.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-a\fR\fR
+.ad
+.RS 21n
+Searches for and imports all pools found.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-m\fR\fR
+.ad
+.RS 21n
+Allows a pool to import when there is a missing log device.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-R\fR \fIroot\fR\fR
+.ad
+.RS 21n
+Sets the "\fBcachefile\fR" property to "\fBnone\fR" and the "\fIaltroot\fR" property to "\fIroot\fR".
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-N\fR\fR
+.ad
+.RS 21n
+Import the pool without mounting any file systems.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.RS 21n
+Used with the \fB-F\fR recovery option. Determines whether a non-importable pool can be made importable again, but does not actually perform the pool recovery. For more details about pool recovery mode, see the \fB-F\fR option, above.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-X\fR\fR
+.ad
+.RS 21n
+Used with the \fB-F\fR recovery option. Determines whether extreme measures to find a valid txg should take place.  This allows the pool to be rolled back to a txg which is no longer guaranteed to be consistent.  Pools imported at an inconsistent txg may contain uncorrectable checksum errors.  For more details about pool recovery mode, see the \fB-F\fR option, above.
+\fBWARNING\fR: This option can be extremely hazardous to the health of your pool and should only be used as a last resort.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-T\fR\fR
+.ad
+.RS 21n
+Specify the txg to use for rollback.  Implies \fB-FX\fR. For more details about pool recovery mode, see the \fB-X\fR option, above.
+\fBWARNING\fR: This option can be extremely hazardous to the health of your pool and should only be used as a last resort.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-s\fR
+.ad
+.RS 21n
+Scan using the default search path, the libblkid cache will not be consulted.  A custom search path may be specified by setting the \fBZPOOL_IMPORT_PATH\fR environment variable.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool import\fR [\fB-o\fR \fImntopts\fR] [ \fB-o\fR \fIproperty\fR=\fIvalue\fR] ... [\fB-d\fR \fIdir\fR | \fB-c\fR \fIcachefile\fR] [\fB-D\fR] [\fB-f\fR] [\fB-m\fR] [\fB-R\fR \fIroot\fR] [\fB-F\fR [\fB-n\fR]] [\fB-t\fR]] [\fB-s\fR] \fIpool\fR | \fIid\fR [\fInewpool\fR]\fR
+.ad
+.sp .6
+.RS 4n
+Imports a specific pool. A pool can be identified by its name or the numeric identifier. If \fInewpool\fR is specified, the pool is imported using the name \fInewpool\fR. Otherwise, it is imported with the same name as its exported name.
+.sp
+If a device is removed from a system without running "\fBzpool export\fR" first, the device appears as potentially active. It cannot be determined if this was a failed export, or whether the device is really in use from another host. To import a pool in this state, the \fB-f\fR option is required.
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fImntopts\fR\fR
+.ad
+.sp .6
+.RS 4n
+Comma-separated list of mount options to use when mounting datasets within the pool. See \fBzfs\fR(8) for a description of dataset properties and mount options.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty=value\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the specified property on the imported pool. See the "Properties" section for more information on the available pool properties.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-c\fR \fIcachefile\fR\fR
+.ad
+.sp .6
+.RS 4n
+Reads configuration from the given \fBcachefile\fR that was created with the "\fBcachefile\fR" pool property. This \fBcachefile\fR is used instead of searching for devices.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-d\fR \fIdir\fR\fR
+.ad
+.sp .6
+.RS 4n
+Searches for devices or files in \fIdir\fR. The \fB-d\fR option can be specified multiple times. This option is incompatible with the \fB-c\fR option.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-D\fR\fR
+.ad
+.sp .6
+.RS 4n
+Imports destroyed pool. The \fB-f\fR option is also required.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.sp .6
+.RS 4n
+Forces import, even if the pool appears to be potentially active.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-F\fR\fR
+.ad
+.sp .6
+.RS 4n
+Recovery mode for a non-importable pool. Attempt to return the pool to an importable state by discarding the last few transactions. Not all damaged pools can be recovered by using this option. If successful, the data from the discarded transactions is irretrievably lost. This option is ignored if the pool is importable or already imported.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-R\fR \fIroot\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the "\fBcachefile\fR" property to "\fBnone\fR" and the "\fIaltroot\fR" property to "\fIroot\fR".
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR\fR
+.ad
+.sp .6
+.RS 4n
+Used with the \fB-F\fR recovery option. Determines whether a non-importable pool can be made importable again, but does not actually perform the pool recovery. For more details about pool recovery mode, see the \fB-F\fR option, above.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-X\fR\fR
+.ad
+.sp .6
+.RS 4n
+Used with the \fB-F\fR recovery option. Determines whether extreme measures to find a valid txg should take place.  This allows the pool to be rolled back to a txg which is no longer guaranteed to be consistent.  Pools imported at an inconsistent txg may contain uncorrectable checksum errors.  For more details about pool recovery mode, see the \fB-F\fR option, above.
+\fBWARNING\fR: This option can be extremely hazardous to the health of your pool and should only be used as a last resort.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-T\fR\fR
+.ad
+.sp .6
+.RS 4n
+Specify the txg to use for rollback.  Implies \fB-FX\fR. For more details about pool recovery mode, see the \fB-X\fR option, above.
+\fBWARNING\fR: This option can be extremely hazardous to the health of your pool and should only be used as a last resort.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-t\fR\fR
+.ad
+.sp .6
+.RS 4n
+Used with "\fBnewpool\fR". Specifies that "\fBnewpool\fR" is temporary. Temporary pool names last until export. Ensures that the original pool name will be used in all label updates and therefore is retained upon export. Will also set -o cachefile=none when not explicitly specified.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-m\fR\fR
+.ad
+.sp .6
+.RS 4n
+Allows a pool to import when there is a missing log device.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-s\fR
+.ad
+.sp .6
+.RS 4n
+Scan using the default search path, the libblkid cache will not be consulted.  A custom search path may be specified by setting the \fBZPOOL_IMPORT_PATH\fR environment variable.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool iostat\fR [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-ghHLpPvy\fR] [[\fB-lq\fR]|[\fB-r\fR|\fB-w\fR]] [[\fIpool\fR ...]|[\fIpool vdev\fR ...]|[\fIvdev\fR ...]] [\fIinterval\fR[\fIcount\fR]]\fR
+
+.ad
+.sp .6
+.RS 4n
+Displays \fBI/O\fR statistics for the given \fIpool\fRs/\fIvdev\fRs. You can
+pass in a list of \fIpool\fRs, a \fIpool\fR and list of \fIvdev\fRs in that
+\fIpool\fR, or a list of any \fIvdev\fRs from any \fIpool\fR. If no items are
+specified, statistics for every pool in the system are shown.  When given an
+interval, the statistics are printed every \fIinterval\fR seconds until
+\fBCtrl-C\fR is pressed. If \fIcount\fR is specified, the command exits after
+\fIcount\fR reports are printed.  The first report printed is always the
+statistics since boot regardless of whether \fIinterval\fR and \fIcount\fR
+are passed.  However, this behavior can be suppressed with the -y flag.  Also
+note that the units of 'K', 'M', 'G'...  that are printed in the report are in
+base 1024.  To get the raw values, use the \fB-p\fR flag.
+.sp
+.ne 2
+.na
+\fB\fB-T\fR \fBu\fR | \fBd\fR\fR
+.ad
+.RS 12n
+Display a time stamp.
+.sp
+Specify \fBu\fR for a printed representation of the internal representation of time. See \fBtime\fR(2). Specify \fBd\fR for standard date format. See \fBdate\fR(1).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-g\fR\fR
+.ad
+.RS 12n
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-H\fR\fR
+.ad
+.RS 12n
+Scripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 12n
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.RS 12n
+Display numbers in parsable (exact) values.  Time values are in nanoseconds.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-P\fR\fR
+.ad
+.RS 12n
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-r\fR\fR
+.ad
+.RS 12n
+Print request size histograms for the leaf ZIOs.  This includes histograms of
+individual ZIOs ("ind") and aggregate ZIOs ("agg").  These stats can be useful
+for seeing how well the ZFS IO aggregator is working.  Do not confuse these
+request size stats with the block layer requests; it's possible ZIOs can
+be broken up before being sent to the block device.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.RS 12n
+Verbose statistics. Reports usage statistics for individual \fIvdevs\fR within the pool, in addition to the pool-wide statistics.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-y\fR\fR
+.ad
+.RS 12n
+Omit statistics since boot.  Normally the first line of output reports the statistics since boot.  This option suppresses that first line of output.
+.RE
+.sp
+.ne 2
+.na
+\fB\fB-w\fR\fR
+.ad
+.RS 12n
+Display latency histograms:
+
+.sp
+.ne 2
+.na
+total_wait:
+.ad
+.RS 20n
+Total IO time (queuing + disk IO time).
+.RE
+.ne 2
+.na
+disk_wait:
+.ad
+.RS 20n
+Disk IO time (time reading/writing the disk).
+.RE
+.ne 2
+.na
+syncq_wait:
+.ad
+.RS 20n
+Amount of time IO spent in synchronous priority queues.  Does not include
+disk time.
+.RE
+.ne 2
+.na
+asyncq_wait:
+.ad
+.RS 20n
+Amount of time IO spent in asynchronous priority queues.  Does not include
+disk time.
+.RE
+.ne 2
+.na
+scrub:
+.ad
+.RS 20n
+Amount of time IO spent in scrub queue. Does not include disk time.
+
+
+.RE
+
+All histogram buckets are power-of-two sized.  The time labels are the end
+ranges of the buckets, so for example, a 15ns bucket stores latencies from
+8-15ns.  The last bucket is also a catch-all for latencies higher than the
+maximum.
+.RE
+.sp
+.ne 2
+.na
+\fB\fB-l\fR\fR
+.ad
+.RS 12n
+Include average latency statistics:
+
+.sp
+.ne 2
+.na
+total_wait:
+.ad
+.RS 20n
+Average total IO time (queuing + disk IO time).
+.RE
+.ne 2
+.na
+disk_wait:
+.ad
+.RS 20n
+Average disk IO time (time reading/writing the disk).
+.RE
+.ne 2
+.na
+syncq_wait:
+.ad
+.RS 20n
+Average amount of time IO spent in synchronous priority queues.  Does not
+include disk time.
+.RE
+.ne 2
+.na
+asyncq_wait:
+.ad
+.RS 20n
+Average amount of time IO spent in asynchronous priority queues.  Does not
+include disk time.
+.RE
+.ne 2
+.na
+scrub:
+.ad
+.RS 20n
+Average queuing time in scrub queue.  Does not include disk time.
+.RE
+
+.RE
+.sp
+.ne 2
+.na
+\fB\fB-q\fR\fR
+.ad
+.RS 12n
+Include active queue statistics.  Each priority queue has both pending ("pend")
+and active ("activ") IOs.  Pending IOs are waiting to be issued to the disk, and
+active IOs have been issued to disk and are waiting for completion.  These stats
+are broken out by priority queue:
+.sp
+.ne 2
+.na
+syncq_read/write:
+.ad
+.RS 20n
+Current number of entries in synchronous priority queues.
+.RE
+.ne 2
+.na
+asyncq_read/write:
+.ad
+.RS 20n
+Current number of entries in asynchronous priority queues.
+.RE
+.ne 2
+.na
+scrubq_read:
+.ad
+.RS 20n
+Current number of entries in scrub queue.
+.RE
+
+All queue statistics are instantaneous measurements of the number of entries
+in the queues.  If you specify an interval, the measurements will be sampled
+from the end of the interval.
+.RE
+.sp
+.ne 2
+.na
+\fB\fBzpool labelclear\fR [\fB-f\fR] \fIdevice\fR
+.ad
+.sp .6
+.RS 4n
+Removes ZFS label information from the specified device. The device must not be part of an active pool configuration.
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.RS 12n
+Treat exported or foreign devices as inactive.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool list\fR [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-HgLpPv\fR] [\fB-o\fR \fIprops\fR[,...]] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]]\fR
+.ad
+.sp .6
+.RS 4n
+Lists the given pools along with a health status and space usage. If no \fIpools\fR are specified, all pools in the system are listed. When given an \fIinterval\fR, the information is printed every \fIinterval\fR seconds until \fBCtrl-C\fR is pressed. If \fIcount\fR is specified, the command exits after \fIcount\fR reports are printed.
+.sp
+.ne 2
+.na
+\fB\fB-H\fR\fR
+.ad
+.RS 12n
+Scripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-g\fR\fR
+.ad
+.RS 12n
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 12n
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-p\fR\fR
+.ad
+.RS 12n
+Display numbers in parsable (exact) values.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-P\fR\fR
+.ad
+.RS 12n
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-T\fR \fBd\fR | \fBu\fR\fR
+.ad
+.RS 12n
+Display a time stamp.
+.sp
+Specify \fBu\fR for a printed representation of the internal representation of time. See \fBtime\fR(2). Specify \fBd\fR for standard date format. See \fBdate\fR(1).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIprops\fR\fR
+.ad
+.RS 12n
+Comma-separated list of properties to display. See the "Properties" section for a list of valid properties. The default list is "name, size, used, available, fragmentation, expandsize, capacity, dedupratio, health, altroot"
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.RS 12n
+Verbose statistics. Reports usage statistics for individual \fIvdevs\fR within the pool, in addition to the pool-wise statistics.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool offline\fR [\fB-t\fR] \fIpool\fR \fIdevice\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Takes the specified physical device offline. While the \fIdevice\fR is offline, no attempt is made to read or write to the device.
+.sp
+This command is not applicable to spares or cache devices.
+.sp
+.ne 2
+.na
+\fB\fB-t\fR\fR
+.ad
+.RS 6n
+Temporary. Upon reboot, the specified physical device reverts to its previous state.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool online\fR [\fB-e\fR] \fIpool\fR \fIdevice\fR...\fR
+.ad
+.sp .6
+.RS 4n
+Brings the specified physical device online.
+.sp
+This command is not applicable to spares or cache devices.
+.sp
+.ne 2
+.na
+\fB\fB-e\fR\fR
+.ad
+.RS 6n
+Expand the device to use all available space. If the device is part of a mirror or \fBraidz\fR then all devices must be expanded before the new space will become available to the pool.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool reguid\fR \fIpool\fR
+.ad
+.sp .6
+.RS 4n
+Generates a new unique identifier for the pool. You must ensure that all
+devices in this pool are online and healthy before performing this action.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool reopen\fR \fIpool\fR
+.ad
+.sp .6
+.RS 4n
+Reopen all the vdevs associated with the pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool remove\fR \fIpool\fR \fIdevice\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Removes the specified device from the pool. This command currently only supports removing hot spares, cache, and log devices. A mirrored log device can be removed by specifying the top-level mirror for the log. Non-log devices that are part of a mirrored configuration can be removed using the \fBzpool detach\fR command. Non-redundant and \fBraidz\fR devices cannot be removed from a pool.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool replace\fR [\fB-f\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIold_device\fR [\fInew_device\fR]\fR
+.ad
+.sp .6
+.RS 4n
+Replaces \fIold_device\fR with \fInew_device\fR. This is equivalent to attaching \fInew_device\fR, waiting for it to resilver, and then detaching \fIold_device\fR.
+.sp
+The size of \fInew_device\fR must be greater than or equal to the minimum size of all the devices in a mirror or \fBraidz\fR configuration.
+.sp
+\fInew_device\fR is required if the pool is not redundant. If \fInew_device\fR is not specified, it defaults to \fIold_device\fR. This form of replacement is useful after an existing disk has failed and has been physically replaced. In this case, the new disk may have the same \fB/dev\fR path as the old device, even though it is actually a different disk. \fBZFS\fR recognizes this.
+.sp
+.ne 2
+.na
+\fB\fB-f\fR\fR
+.ad
+.RS 6n
+Forces use of \fInew_device\fR, even if its appears to be in use. Not all devices can be overridden in this manner.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty=value\fR
+.ad
+.sp .6n
+.RS 6n
+Sets the given pool properties. See the "Properties" section for a list of valid properties that can be set. The only property supported at the moment is \fBashift\fR.  \fBDo note\fR that some properties (among them \fBashift\fR) are \fInot\fR inherited from a previous vdev. They are vdev specific, not pool specific.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool scrub\fR [\fB-s\fR] \fIpool\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Begins a scrub. The scrub examines all data in the specified pools to verify that it checksums correctly. For replicated (mirror or \fBraidz\fR) devices, \fBZFS\fR automatically repairs any damage discovered during the scrub. The "\fBzpool status\fR" command reports the progress of the scrub and summarizes the results of the scrub upon completion.
+.sp
+Scrubbing and resilvering are very similar operations. The difference is that resilvering only examines data that \fBZFS\fR knows to be out of date (for example, when attaching a new device to a mirror or replacing an existing device), whereas scrubbing examines all data to discover silent errors due to hardware faults or disk failure.
+.sp
+Because scrubbing and resilvering are \fBI/O\fR-intensive operations, \fBZFS\fR only allows one at a time. If a scrub is already in progress, the "\fBzpool scrub\fR" command terminates it and starts a new scrub. If a resilver is in progress, \fBZFS\fR does not allow a scrub to be started until the resilver completes.
+.sp
+.ne 2
+.na
+\fB\fB-s\fR\fR
+.ad
+.RS 6n
+Stop scrubbing.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool set\fR \fIproperty\fR=\fIvalue\fR \fIpool\fR\fR
+.ad
+.sp .6
+.RS 4n
+Sets the given property on the specified pool. See the "Properties" section for more information on what properties can be set and acceptable values.
+.RE
+
+.sp
+.ne 2
+.na
+\fBzpool split\fR [\fB-gLnP\fR] [\fB-R\fR \fIaltroot\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fInewpool\fR [\fIdevice\fR ...]
+.ad
+.sp .6
+.RS 4n
+Split devices off \fIpool\fR creating \fInewpool\fR. All \fBvdev\fRs in \fIpool\fR must be mirrors and the pool must not be in the process of resilvering. At the time of the split, \fInewpool\fR will be a replica of \fIpool\fR. By default, the last device in each mirror is split from \fIpool\fR to create \fInewpool\fR.
+
+The optional \fIdevice\fR specification causes the specified device(s) to be included in the new pool and, should any devices remain unspecified, the last device in each mirror is used as would be by default.
+
+.sp
+.ne 2
+.na
+\fB\fB-g\fR\fR
+.ad
+.RS 6n
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 6n
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-n\fR \fR
+.ad
+.sp .6
+.RS 4n
+Do dry run, do not actually perform the split. Print out the expected configuration of \fInewpool\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-P\fR\fR
+.ad
+.RS 6n
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-R\fR \fIaltroot\fR \fR
+.ad
+.sp .6
+.RS 4n
+Set \fIaltroot\fR for \fInewpool\fR and automatically import it.  This can be useful to avoid mountpoint collisions if \fInewpool\fR is imported on the same filesystem as \fIpool\fR.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIproperty=value\fR \fR
+.ad
+.sp .6
+.RS 4n
+Sets the specified property for \fInewpool\fR. See the “Properties” section for more information on the available pool properties.
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fBzpool status\fR [\fB-gLPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]]
+.ad
+.sp .6
+.RS 4n
+Displays the detailed health status for the given pools. If no \fIpool\fR is specified, then the status of each pool in the system is displayed. For more information on pool and device health, see the "Device Failure and Recovery" section.
+.sp
+If a scrub or resilver is in progress, this command reports the percentage done and the estimated time to completion. Both of these are only approximate, because the amount of data in the pool and the other workloads on the system can change.
+
+.sp
+.ne 2
+.na
+\fB\fB-g\fR\fR
+.ad
+.RS 12n
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used innplace of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 12n
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-P\fR\fR
+.ad
+.RS 12n
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.RS 12n
+Displays verbose data error information, printing out a complete list of all data errors since the last complete pool scrub.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-x\fR\fR
+.ad
+.RS 12n
+Only display status for pools that are exhibiting errors or are otherwise unavailable. Warnings about pools not using the latest on-disk format will not be included.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-D\fR\fR
+.ad
+.RS 12n
+Display a histogram of deduplication statistics, showing the allocated (physically present on disk) and
+referenced (logically referenced in the pool) block counts and sizes by reference count.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-T\fR \fBd\fR | \fBu\fR\fR
+.ad
+.RS 12n
+Display a time stamp.
+.sp
+Specify \fBu\fR for a printed representation of the internal representation of time. See \fBtime\fR(2). Specify \fBd\fR for standard date format. See \fBdate\fR(1).
+.RE
+
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool upgrade\fR\fR
+.ad
+.sp .6
+.RS 4n
+Displays pools which do not have all supported features enabled and pools formatted using a legacy ZFS version number. These pools can continue to be used, but some features may not be available. Use "\fBzpool upgrade -a\fR" to enable all features on all pools.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool upgrade\fR \fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Displays legacy \fBZFS\fR versions supported by the current software. See \fBzfs-features\fR(5) for a description of feature flags features supported by the current software.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBzpool upgrade\fR [\fB-V\fR \fIversion\fR] \fB-a\fR | \fIpool\fR ...\fR
+.ad
+.sp .6
+.RS 4n
+Enables all supported features on the given pool. Once this is done, the pool will no longer be accessible on systems that do not support feature flags. See \fBzfs-features\fR(5) for details on compatibility with systems that support feature flags, but do not support all features enabled on the pool.
+.sp
+.ne 2
+.na
+\fB\fB-a\fR\fR
+.ad
+.RS 14n
+Enables all supported features on all pools.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-V\fR \fIversion\fR\fR
+.ad
+.RS 14n
+Upgrade to the specified legacy version. If the \fB-V\fR flag is specified, no features will be enabled on the pool. This option can only be used to increase the version number up to the last supported legacy version number.
+.RE
+
+.RE
+
+.SH EXAMPLES
+.LP
+\fBExample 1 \fRCreating a RAID-Z Storage Pool
+.sp
+.LP
+The following command creates a pool with a single \fBraidz\fR root \fIvdev\fR that consists of six disks.
+
+.sp
+.in +2
+.nf
+# \fBzpool create tank raidz sda sdb sdc sdd sde sdf\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 2 \fRCreating a Mirrored Storage Pool
+.sp
+.LP
+The following command creates a pool with two mirrors, where each mirror contains two disks.
+
+.sp
+.in +2
+.nf
+# \fBzpool create tank mirror sda sdb mirror sdc sdd\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 3 \fRCreating a ZFS Storage Pool by Using Partitions
+.sp
+.LP
+The following command creates an unmirrored pool using two disk partitions.
+
+.sp
+.in +2
+.nf
+# \fBzpool create tank sda1 sdb2\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 4 \fRCreating a ZFS Storage Pool by Using Files
+.sp
+.LP
+The following command creates an unmirrored pool using files. While not recommended, a pool based on files can be useful for experimental purposes.
+
+.sp
+.in +2
+.nf
+# \fBzpool create tank /path/to/file/a /path/to/file/b\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 5 \fRAdding a Mirror to a ZFS Storage Pool
+.sp
+.LP
+The following command adds two mirrored disks to the pool \fItank\fR, assuming the pool is already made up of two-way mirrors. The additional space is immediately available to any datasets within the pool.
+
+.sp
+.in +2
+.nf
+# \fBzpool add tank mirror sda sdb\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 6 \fRListing Available ZFS Storage Pools
+.sp
+.LP
+The following command lists all available pools on the system. In this case, the pool \fIzion\fR is faulted due to a missing device.
+
+.sp
+.LP
+The results from this command are similar to the following:
+
+.sp
+.in +2
+.nf
+# \fBzpool list\fR
+NAME    SIZE  ALLOC   FREE   FRAG  EXPANDSZ    CAP  DEDUP  HEALTH  ALTROOT
+rpool  19.9G  8.43G  11.4G    33%         -    42%  1.00x  ONLINE  -
+tank   61.5G  20.0G  41.5G    48%         -    32%  1.00x  ONLINE  -
+zion       -      -      -      -         -      -      -  FAULTED -
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 7 \fRDestroying a ZFS Storage Pool
+.sp
+.LP
+The following command destroys the pool \fItank\fR and any datasets contained within.
+
+.sp
+.in +2
+.nf
+# \fBzpool destroy -f tank\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 8 \fRExporting a ZFS Storage Pool
+.sp
+.LP
+The following command exports the devices in pool \fItank\fR so that they can be relocated or later imported.
+
+.sp
+.in +2
+.nf
+# \fBzpool export tank\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 9 \fRImporting a ZFS Storage Pool
+.sp
+.LP
+The following command displays available pools, and then imports the pool \fItank\fR for use on the system.
+
+.sp
+.LP
+The results from this command are similar to the following:
+
+.sp
+.in +2
+.nf
+# \fBzpool import\fR
+  pool: tank
+    id: 15451357997522795478
+ state: ONLINE
+action: The pool can be imported using its name or numeric identifier.
+config:
+
+        tank        ONLINE
+          mirror    ONLINE
+            sda     ONLINE
+            sdb     ONLINE
+
+# \fBzpool import tank\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 10 \fRUpgrading All ZFS Storage Pools to the Current Version
+.sp
+.LP
+The following command upgrades all ZFS Storage pools to the current version of the software.
+
+.sp
+.in +2
+.nf
+# \fBzpool upgrade -a\fR
+This system is currently running ZFS pool version 28.
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 11 \fRManaging Hot Spares
+.sp
+.LP
+The following command creates a new pool with an available hot spare:
+
+.sp
+.in +2
+.nf
+# \fBzpool create tank mirror sda sdb spare sdc\fR
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+If one of the disks were to fail, the pool would be reduced to the degraded state. The failed device can be replaced using the following command:
+
+.sp
+.in +2
+.nf
+# \fBzpool replace tank sda sdd\fR
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+Once the data has been resilvered, the spare is automatically removed and is made available for use should another device fails. The hot spare can be permanently removed from the pool using the following command:
+
+.sp
+.in +2
+.nf
+# \fBzpool remove tank sdc\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 12 \fRCreating a ZFS Pool with Mirrored Separate Intent Logs
+.sp
+.LP
+The following command creates a ZFS storage pool consisting of two, two-way mirrors and mirrored log devices:
+
+.sp
+.in +2
+.nf
+# \fBzpool create pool mirror sda sdb mirror sdc sdd log mirror \e
+   sde sdf\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 13 \fRAdding Cache Devices to a ZFS Pool
+.sp
+.LP
+The following command adds two disks for use as cache devices to a ZFS storage pool:
+
+.sp
+.in +2
+.nf
+# \fBzpool add pool cache sdc sdd\fR
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+Once added, the cache devices gradually fill with content from main memory. Depending on the size of your cache devices, it could take over an hour for them to fill. Capacity and reads can be monitored using the \fBiostat\fR option as follows:
+
+.sp
+.in +2
+.nf
+# \fBzpool iostat -v pool 5\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 14 \fRRemoving a Mirrored Log Device
+.sp
+.LP
+The following command removes the mirrored log device \fBmirror-2\fR.
+
+.sp
+.LP
+Given this configuration:
+
+.sp
+.in +2
+.nf
+   pool: tank
+  state: ONLINE
+  scrub: none requested
+config:
+
+         NAME        STATE     READ WRITE CKSUM
+         tank        ONLINE       0     0     0
+           mirror-0  ONLINE       0     0     0
+             sda     ONLINE       0     0     0
+             sdb     ONLINE       0     0     0
+           mirror-1  ONLINE       0     0     0
+             sdc     ONLINE       0     0     0
+             sdd     ONLINE       0     0     0
+         logs
+           mirror-2  ONLINE       0     0     0
+             sde     ONLINE       0     0     0
+             sdf     ONLINE       0     0     0
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+The command to remove the mirrored log \fBmirror-2\fR is:
+
+.sp
+.in +2
+.nf
+# \fBzpool remove tank mirror-2\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 15 \fRDisplaying expanded space on a device
+.sp
+.LP
+The following command displays the detailed information for the \fIdata\fR
+pool. This pool is comprised of a single \fIraidz\fR vdev where one of its
+devices increased its capacity by 10GB. In this example, the pool will not
+be able to utilized this extra capacity until all the devices under the
+\fIraidz\fR vdev have been expanded.
+
+.sp
+.in +2
+.nf
+# \fBzpool list -v data\fR
+NAME         SIZE  ALLOC   FREE   FRAG  EXPANDSZ    CAP  DEDUP  HEALTH  ALTROOT
+data        23.9G  14.6G  9.30G    48%         -    61%  1.00x  ONLINE  -
+  raidz1    23.9G  14.6G  9.30G    48%         -
+    c1t1d0      -      -      -      -         -
+    c1t2d0      -      -      -      -       10G
+    c1t3d0      -      -      -      -         -
+.fi
+.in -2
+
+.SH EXIT STATUS
+.sp
+.LP
+The following exit values are returned:
+.sp
+.ne 2
+.na
+\fB\fB0\fR\fR
+.ad
+.RS 5n
+Successful completion.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB1\fR\fR
+.ad
+.RS 5n
+An error occurred.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB2\fR\fR
+.ad
+.RS 5n
+Invalid command line options were specified.
+.RE
+
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.B "ZFS_ABORT
+Cause \fBzpool\fR to dump core on exit for the purposes of running \fB::findleaks\fR.
+.TP
+.B "ZPOOL_IMPORT_PATH"
+The search path for devices or files to use with the pool. This is a colon-separated list of directories in which \fBzpool\fR looks for device nodes and files.
+Similar to the \fB-d\fR option in \fIzpool import\fR.
+.TP
+.B "ZPOOL_VDEV_NAME_GUID"
+Cause \fBzpool\fR subcommands to output vdev guids by default.  This behavior
+is identical to the \fBzpool status -g\fR command line option.
+.TP
+.B "ZPOOL_VDEV_NAME_FOLLOW_LINKS"
+Cause \fBzpool\fR subcommands to follow links for vdev names by default.  This behavior is identical to the \fBzpool status -L\fR command line option.
+.TP
+.B "ZPOOL_VDEV_NAME_PATH"
+Cause \fBzpool\fR subcommands to output full vdev path names by default.  This
+behavior is identical to the \fBzpool status -p\fR command line option.
+.TP
+.B "ZFS_VDEV_DEVID_OPT_OUT"
+Older ZFS on Linux implementations had issues when attempting to display pool
+config VDEV names if a "devid" NVP value is present in the pool's config.
+
+For example, a pool that originated on illumos platform would have a devid
+value in the config and \fBzpool status\fR would fail when listing the config.
+This would also be true for future Linux based pools.
+
+A pool can be stripped of any "devid" values on import or prevented from adding
+them on \fBzpool create\fR or \fBzpool add\fR by setting ZFS_VDEV_DEVID_OPT_OUT.
+
+.SH SEE ALSO
+.sp
+.LP
+\fBzfs\fR(8), \fBzpool-features\fR(5), \fBzfs-events\fR(5), \fBzfs-module-parameters\fR(5)
diff --git a/zfs/man/man8/zstreamdump.8 b/zfs/man/man8/zstreamdump.8
new file mode 100644 (file)
index 0000000..dc88dfb
--- /dev/null
@@ -0,0 +1,48 @@
+'\" te
+.\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved
+.\" 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]
+.TH zstreamdump 8 "29 Aug 2012" "ZFS pool 28, filesystem 5" "System Administration Commands"
+.SH NAME
+zstreamdump \- filter data in zfs send stream
+.SH SYNOPSIS
+.LP
+.nf
+\fBzstreamdump\fR [\fB-C\fR] [\fB-v\fR]
+.fi
+
+.SH DESCRIPTION
+.sp
+.LP
+The \fBzstreamdump\fR utility reads from the output of the \fBzfs send\fR
+command, then displays headers and some statistics from that output.  See
+\fBzfs\fR(1M).
+.SH OPTIONS
+.sp
+.LP
+The following options are supported:
+.sp
+.ne 2
+.na
+\fB\fB-C\fR\fR
+.ad
+.sp .6
+.RS 4n
+Suppress the validation of checksums.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-v\fR\fR
+.ad
+.sp .6
+.RS 4n
+Verbose. Dump all headers, not only begin and end headers.
+.RE
+
+.SH SEE ALSO
+.sp
+.LP
+\fBzfs\fR(8)
index d4ddee2f429f9b5eca4770457fab606bf590cf56..e4f06a6e867af51959fa4250d1fa6c70968a7db2 100644 (file)
@@ -4,6 +4,7 @@ subdir-m += unicode
 subdir-m += zcommon
 subdir-m += zfs
 subdir-m += zpios
+subdir-m += icp
 
 INSTALL_MOD_DIR ?= extra
 
@@ -12,6 +13,8 @@ ZFS_MODULE_CFLAGS += -include @abs_top_builddir@/zfs_config.h
 ZFS_MODULE_CFLAGS += -I@abs_top_srcdir@/include -I@SPL@/include -I@SPL@
 export ZFS_MODULE_CFLAGS
 
+SUBDIR_TARGETS = icp
+
 modules:
        @# Make the exported SPL symbols available to these modules.
        @# They may be in the root of SPL_OBJ when building against
@@ -28,6 +31,9 @@ modules:
                "*** - @SPL_OBJ@/module/@SPL_SYMBOLS@\n"; \
                exit 1; \
        fi
+       list='$(SUBDIR_TARGETS)'; for targetdir in $$list; do \
+               $(MAKE) -C $$targetdir; \
+       done
        $(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ CONFIG_ZFS=m $@
 
 clean:
@@ -64,8 +70,8 @@ modules_uninstall:
 
 distdir:
        list='$(subdir-m)'; for subdir in $$list; do \
-               (find @top_srcdir@/module/$$subdir -name '*.c' -o -name '*.h' |\
-               xargs /bin/cp -t $$distdir/$$subdir); \
+               (cd @top_srcdir@/module && find $$subdir -name '*.c' -o -name '*.h' -o -name '*.S' |\
+               xargs /bin/cp --parents -t $$distdir); \
        done
 
 distclean maintainer-clean: clean
index abf74bf7242ff2ec99147a8aa82a8af3e38e5890..86183fea01bd6c61a11f089c0865223d147a343e 100644 (file)
@@ -630,7 +630,7 @@ avl_insert_here(
 void
 avl_add(avl_tree_t *tree, void *new_node)
 {
-       avl_index_t where;
+       avl_index_t where = 0;
 
        /*
         * This is unfortunate.  We want to call panic() here, even for
diff --git a/zfs/module/icp/Makefile.in b/zfs/module/icp/Makefile.in
new file mode 100644 (file)
index 0000000..b822635
--- /dev/null
@@ -0,0 +1,92 @@
+src = @abs_top_srcdir@/module/icp
+obj = @abs_builddir@
+
+MODULE := icp
+
+TARGET_ASM_DIR = @TARGET_ASM_DIR@
+
+ifeq ($(TARGET_ASM_DIR), asm-x86_64)
+ASM_SOURCES := asm-x86_64/aes/aeskey.o
+ASM_SOURCES += asm-x86_64/aes/aes_amd64.o
+ASM_SOURCES += asm-x86_64/aes/aes_intel.o
+ASM_SOURCES += asm-x86_64/modes/gcm_intel.o
+ASM_SOURCES += asm-x86_64/sha1/sha1-x86_64.o
+ASM_SOURCES += asm-x86_64/sha2/sha256_impl.o
+ASM_SOURCES += asm-x86_64/sha2/sha512_impl.o
+endif
+
+ifeq ($(TARGET_ASM_DIR), asm-i386)
+ASM_SOURCES :=
+endif
+       
+ifeq ($(TARGET_ASM_DIR), asm-generic)
+ASM_SOURCES :=
+endif
+
+EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@
+
+obj-$(CONFIG_ZFS) := $(MODULE).o
+
+ccflags-y += -I$(src)/include
+asflags-y += -I$(src)/include
+asflags-y += $(ZFS_MODULE_CFLAGS)
+
+$(MODULE)-objs += illumos-crypto.o
+$(MODULE)-objs += api/kcf_cipher.o
+$(MODULE)-objs += api/kcf_digest.o
+$(MODULE)-objs += api/kcf_mac.o
+$(MODULE)-objs += api/kcf_miscapi.o
+$(MODULE)-objs += api/kcf_ctxops.o
+$(MODULE)-objs += core/kcf_callprov.o
+$(MODULE)-objs += core/kcf_prov_tabs.o
+$(MODULE)-objs += core/kcf_sched.o
+$(MODULE)-objs += core/kcf_mech_tabs.o
+$(MODULE)-objs += core/kcf_prov_lib.o
+$(MODULE)-objs += spi/kcf_spi.o
+$(MODULE)-objs += io/aes.o
+$(MODULE)-objs += io/edonr_mod.o
+$(MODULE)-objs += io/sha1_mod.o
+$(MODULE)-objs += io/sha2_mod.o
+$(MODULE)-objs += io/skein_mod.o
+$(MODULE)-objs += os/modhash.o
+$(MODULE)-objs += os/modconf.o
+$(MODULE)-objs += algs/modes/cbc.o
+$(MODULE)-objs += algs/modes/ccm.o
+$(MODULE)-objs += algs/modes/ctr.o
+$(MODULE)-objs += algs/modes/ecb.o
+$(MODULE)-objs += algs/modes/gcm.o
+$(MODULE)-objs += algs/modes/modes.o
+$(MODULE)-objs += algs/aes/aes_impl.o
+$(MODULE)-objs += algs/aes/aes_modes.o
+$(MODULE)-objs += algs/edonr/edonr.o
+$(MODULE)-objs += algs/sha1/sha1.o
+$(MODULE)-objs += algs/sha2/sha2.o
+$(MODULE)-objs += algs/sha1/sha1.o
+$(MODULE)-objs += algs/skein/skein.o
+$(MODULE)-objs += algs/skein/skein_block.o
+$(MODULE)-objs += algs/skein/skein_iv.o
+$(MODULE)-objs += $(ASM_SOURCES)
+
+ICP_DIRS = \
+       api \
+       core \
+       spi \
+       io \
+       os \
+       algs \
+       algs/aes \
+       algs/edonr \
+       algs/modes \
+       algs/sha1 \
+       algs/sha2 \
+       algs/skein \
+       asm-x86_64 \
+       asm-x86_64/aes \
+       asm-x86_64/modes \
+       asm-x86_64/sha1 \
+       asm-x86_64/sha2 \
+       asm-i386 \
+       asm-generic
+
+all:
+       mkdir -p $(ICP_DIRS)
diff --git a/zfs/module/icp/algs/aes/aes_impl.c b/zfs/module/icp/algs/aes/aes_impl.c
new file mode 100644 (file)
index 0000000..9c53964
--- /dev/null
@@ -0,0 +1,1618 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/spi.h>
+#include <modes/modes.h>
+#include <aes/aes_impl.h>
+
+#ifdef __amd64
+
+#ifdef _KERNEL
+/* Workaround for no XMM kernel thread save/restore */
+#define        KPREEMPT_DISABLE        kpreempt_disable()
+#define        KPREEMPT_ENABLE         kpreempt_enable()
+
+#else
+#define        KPREEMPT_DISABLE
+#define        KPREEMPT_ENABLE
+#endif /* _KERNEL */
+#endif  /* __amd64 */
+
+
+/*
+ * This file is derived from the file  rijndael-alg-fst.c  taken from the
+ * "optimized C code v3.0" on the "rijndael home page"
+ * http://www.iaik.tu-graz.ac.at/research/krypto/AES/old/~rijmen/rijndael/
+ * pointed by the NIST web-site http://csrc.nist.gov/archive/aes/
+ *
+ * The following note is from the original file:
+ */
+
+/*
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(__amd64)
+
+/* These functions are used to execute amd64 instructions for AMD or Intel: */
+extern int rijndael_key_setup_enc_amd64(uint32_t rk[],
+       const uint32_t cipherKey[], int keyBits);
+extern int rijndael_key_setup_dec_amd64(uint32_t rk[],
+       const uint32_t cipherKey[], int keyBits);
+extern void aes_encrypt_amd64(const uint32_t rk[], int Nr,
+       const uint32_t pt[4], uint32_t ct[4]);
+extern void aes_decrypt_amd64(const uint32_t rk[], int Nr,
+       const uint32_t ct[4], uint32_t pt[4]);
+
+/* These functions are used to execute Intel-specific AES-NI instructions: */
+extern int rijndael_key_setup_enc_intel(uint32_t rk[],
+       const uint32_t cipherKey[], uint64_t keyBits);
+extern int rijndael_key_setup_dec_intel(uint32_t rk[],
+       const uint32_t cipherKey[], uint64_t keyBits);
+extern void aes_encrypt_intel(const uint32_t rk[], int Nr,
+       const uint32_t pt[4], uint32_t ct[4]);
+extern void aes_decrypt_intel(const uint32_t rk[], int Nr,
+       const uint32_t ct[4], uint32_t pt[4]);
+
+static int intel_aes_instructions_present(void);
+
+#define        AES_ENCRYPT_IMPL(a, b, c, d, e) rijndael_encrypt(a, b, c, d, e)
+#define        AES_DECRYPT_IMPL(a, b, c, d, e) rijndael_decrypt(a, b, c, d, e)
+
+#else /* Generic C implementation */
+
+#define        AES_ENCRYPT_IMPL(a, b, c, d, e) rijndael_encrypt(a, b, c, d)
+#define        AES_DECRYPT_IMPL(a, b, c, d, e) rijndael_decrypt(a, b, c, d)
+#define        rijndael_key_setup_enc_raw      rijndael_key_setup_enc
+#endif /* __amd64 */
+
+#if defined(_LITTLE_ENDIAN) && !defined(__amd64)
+#define        AES_BYTE_SWAP
+#endif
+
+
+#if !defined(__amd64)
+/*
+ *  Constant tables
+ */
+
+/*
+ * Te0[x] = S [x].[02, 01, 01, 03];
+ * Te1[x] = S [x].[03, 02, 01, 01];
+ * Te2[x] = S [x].[01, 03, 02, 01];
+ * Te3[x] = S [x].[01, 01, 03, 02];
+ * Te4[x] = S [x].[01, 01, 01, 01];
+ *
+ * Td0[x] = Si[x].[0e, 09, 0d, 0b];
+ * Td1[x] = Si[x].[0b, 0e, 09, 0d];
+ * Td2[x] = Si[x].[0d, 0b, 0e, 09];
+ * Td3[x] = Si[x].[09, 0d, 0b, 0e];
+ * Td4[x] = Si[x].[01, 01, 01, 01];
+ */
+
+/* Encrypt Sbox constants (for the substitute bytes operation) */
+
+static const uint32_t Te0[256] =
+{
+       0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+       0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+       0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+       0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+       0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+       0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+       0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+       0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+       0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+       0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+       0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+       0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+       0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+       0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+       0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+       0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+       0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+       0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+       0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+       0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+       0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+       0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+       0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+       0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+       0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+       0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+       0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+       0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+       0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+       0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+       0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+       0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+       0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+       0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+       0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+       0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+       0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+       0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+       0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+       0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+       0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+       0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+       0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+       0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+       0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+       0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+       0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+       0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+       0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+       0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+       0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+       0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+       0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+       0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+       0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+       0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+       0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+       0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+       0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+       0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+       0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+       0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+       0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+       0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU
+};
+
+
+static const uint32_t Te1[256] =
+{
+       0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+       0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+       0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+       0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+       0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+       0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+       0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+       0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+       0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+       0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+       0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+       0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+       0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+       0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+       0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+       0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+       0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+       0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+       0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+       0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+       0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+       0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+       0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+       0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+       0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+       0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+       0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+       0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+       0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+       0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+       0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+       0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+       0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+       0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+       0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+       0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+       0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+       0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+       0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+       0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+       0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+       0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+       0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+       0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+       0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+       0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+       0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+       0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+       0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+       0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+       0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+       0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+       0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+       0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+       0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+       0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+       0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+       0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+       0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+       0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+       0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+       0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+       0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+       0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U
+};
+
+
+static const uint32_t Te2[256] =
+{
+       0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+       0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+       0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+       0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+       0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+       0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+       0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+       0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+       0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+       0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+       0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+       0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+       0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+       0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+       0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+       0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+       0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+       0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+       0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+       0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+       0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+       0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+       0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+       0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+       0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+       0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+       0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+       0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+       0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+       0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+       0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+       0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+       0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+       0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+       0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+       0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+       0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+       0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+       0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+       0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+       0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+       0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+       0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+       0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+       0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+       0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+       0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+       0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+       0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+       0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+       0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+       0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+       0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+       0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+       0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+       0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+       0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+       0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+       0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+       0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+       0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+       0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+       0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+       0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U
+};
+
+
+static const uint32_t Te3[256] =
+{
+       0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+       0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+       0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+       0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+       0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+       0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+       0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+       0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+       0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+       0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+       0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+       0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+       0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+       0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+       0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+       0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+       0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+       0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+       0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+       0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+       0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+       0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+       0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+       0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+       0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+       0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+       0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+       0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+       0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+       0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+       0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+       0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+       0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+       0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+       0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+       0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+       0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+       0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+       0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+       0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+       0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+       0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+       0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+       0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+       0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+       0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+       0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+       0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+       0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+       0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+       0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+       0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+       0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+       0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+       0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+       0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+       0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+       0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+       0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+       0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+       0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+       0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+       0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+       0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU
+};
+
+static const uint32_t Te4[256] =
+{
+       0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+       0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+       0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+       0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+       0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+       0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+       0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+       0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+       0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+       0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+       0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+       0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+       0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+       0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+       0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+       0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+       0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+       0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+       0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+       0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+       0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+       0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+       0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+       0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+       0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+       0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+       0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+       0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+       0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+       0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+       0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+       0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+       0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+       0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+       0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+       0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+       0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+       0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+       0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+       0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+       0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+       0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+       0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+       0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+       0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+       0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+       0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+       0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+       0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+       0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+       0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+       0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+       0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+       0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+       0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+       0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+       0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+       0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+       0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+       0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+       0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+       0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+       0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+       0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U
+};
+
+/* Decrypt Sbox constants (for the substitute bytes operation) */
+
+static const uint32_t Td0[256] =
+{
+       0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+       0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+       0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+       0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+       0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+       0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+       0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+       0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+       0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+       0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+       0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+       0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+       0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+       0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+       0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+       0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+       0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+       0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+       0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+       0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+       0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+       0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+       0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+       0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+       0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+       0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+       0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+       0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+       0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+       0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+       0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+       0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+       0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+       0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+       0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+       0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+       0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+       0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+       0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+       0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+       0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+       0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+       0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+       0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+       0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+       0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+       0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+       0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+       0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+       0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+       0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+       0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+       0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+       0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+       0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+       0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+       0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+       0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+       0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+       0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+       0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+       0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+       0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+       0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U
+};
+
+static const uint32_t Td1[256] =
+{
+       0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+       0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+       0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+       0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+       0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+       0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+       0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+       0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+       0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+       0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+       0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+       0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+       0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+       0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+       0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+       0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+       0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+       0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+       0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+       0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+       0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+       0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+       0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+       0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+       0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+       0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+       0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+       0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+       0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+       0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+       0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+       0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+       0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+       0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+       0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+       0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+       0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+       0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+       0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+       0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+       0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+       0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+       0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+       0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+       0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+       0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+       0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+       0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+       0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+       0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+       0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+       0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+       0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+       0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+       0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+       0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+       0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+       0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+       0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+       0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+       0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+       0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+       0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+       0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U
+};
+
+static const uint32_t Td2[256] =
+{
+       0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+       0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+       0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+       0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+       0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+       0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+       0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+       0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+       0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+       0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+       0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+       0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+       0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+       0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+       0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+       0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+       0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+       0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+       0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+       0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+       0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+       0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+       0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+       0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+       0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+       0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+       0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+       0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+       0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+       0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+       0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+       0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+       0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+       0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+       0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+       0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+       0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+       0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+       0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+       0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+       0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+       0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+       0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+       0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+       0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+       0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+       0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+       0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+       0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+       0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+       0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+       0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+       0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+       0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+       0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+       0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+       0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+       0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+       0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+       0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+       0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+       0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+       0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+       0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U
+};
+
+static const uint32_t Td3[256] =
+{
+       0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+       0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+       0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+       0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+       0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+       0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+       0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+       0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+       0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+       0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+       0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+       0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+       0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+       0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+       0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+       0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+       0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+       0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+       0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+       0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+       0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+       0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+       0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+       0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+       0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+       0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+       0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+       0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+       0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+       0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+       0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+       0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+       0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+       0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+       0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+       0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+       0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+       0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+       0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+       0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+       0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+       0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+       0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+       0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+       0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+       0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+       0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+       0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+       0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+       0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+       0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+       0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+       0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+       0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+       0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+       0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+       0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+       0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+       0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+       0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+       0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+       0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+       0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+       0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U
+};
+
+static const uint32_t Td4[256] =
+{
+       0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+       0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+       0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+       0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+       0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+       0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+       0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+       0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+       0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+       0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+       0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+       0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+       0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+       0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+       0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+       0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+       0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+       0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+       0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+       0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+       0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+       0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+       0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+       0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+       0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+       0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+       0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+       0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+       0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+       0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+       0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+       0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+       0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+       0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+       0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+       0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+       0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+       0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+       0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+       0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+       0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+       0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+       0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+       0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+       0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+       0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+       0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+       0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+       0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+       0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+       0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+       0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+       0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+       0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+       0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+       0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+       0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+       0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+       0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+       0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+       0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+       0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+       0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+       0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU
+};
+
+/* Rcon is Round Constant; used for encryption key expansion */
+static const uint32_t rcon[RC_LENGTH] =
+{
+       /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+       0x01000000, 0x02000000, 0x04000000, 0x08000000,
+       0x10000000, 0x20000000, 0x40000000, 0x80000000,
+       0x1B000000, 0x36000000
+};
+
+
+/*
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * Return the number of rounds for the given cipher key size.
+ * The size of the key schedule depends on the number of rounds
+ * (which can be computed from the size of the key), i.e. 4*(Nr + 1).
+ *
+ * Parameters:
+ * rk          AES key schedule 32-bit array to be initialized
+ * cipherKey   User key
+ * keyBits     AES key size (128, 192, or 256 bits)
+ */
+static int
+rijndael_key_setup_enc_raw(uint32_t rk[], const uint32_t cipherKey[],
+    int keyBits)
+{
+       int             i = 0;
+       uint32_t        temp;
+
+       rk[0] = cipherKey[0];
+       rk[1] = cipherKey[1];
+       rk[2] = cipherKey[2];
+       rk[3] = cipherKey[3];
+
+       if (keyBits == 128) {
+               for (;;) {
+                       temp  = rk[3];
+                       rk[4] = rk[0] ^
+                           (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                           (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+                           (Te4[temp & 0xff] & 0x0000ff00) ^
+                           (Te4[temp >> 24] & 0x000000ff) ^
+                           rcon[i];
+                       rk[5] = rk[1] ^ rk[4];
+                       rk[6] = rk[2] ^ rk[5];
+                       rk[7] = rk[3] ^ rk[6];
+
+                       if (++i == 10) {
+                               return (10);
+                       }
+                       rk += 4;
+               }
+       }
+
+       rk[4] = cipherKey[4];
+       rk[5] = cipherKey[5];
+
+       if (keyBits == 192) {
+               for (;;) {
+                       temp = rk[5];
+                       rk[6] = rk[0] ^
+                           (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                           (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+                           (Te4[temp & 0xff] & 0x0000ff00) ^
+                           (Te4[temp >> 24] & 0x000000ff) ^
+                           rcon[i];
+                       rk[7] = rk[1] ^ rk[6];
+                       rk[8] = rk[2] ^ rk[7];
+                       rk[9] = rk[3] ^ rk[8];
+
+                       if (++i == 8) {
+                               return (12);
+                       }
+
+                       rk[10] = rk[4] ^ rk[9];
+                       rk[11] = rk[5] ^ rk[10];
+                       rk += 6;
+               }
+       }
+
+       rk[6] = cipherKey[6];
+       rk[7] = cipherKey[7];
+
+       if (keyBits == 256) {
+               for (;;) {
+                       temp = rk[7];
+                       rk[8] = rk[0] ^
+                           (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                           (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
+                           (Te4[temp & 0xff] & 0x0000ff00) ^
+                           (Te4[temp >> 24] & 0x000000ff) ^
+                           rcon[i];
+                       rk[9] = rk[1] ^ rk[8];
+                       rk[10] = rk[2] ^ rk[9];
+                       rk[11] = rk[3] ^ rk[10];
+
+                       if (++i == 7) {
+                               return (14);
+                       }
+                       temp = rk[11];
+                       rk[12] = rk[4] ^
+                           (Te4[temp >> 24] & 0xff000000) ^
+                           (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+                           (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
+                           (Te4[temp & 0xff] & 0x000000ff);
+                       rk[13] = rk[5] ^ rk[12];
+                       rk[14] = rk[6] ^ rk[13];
+                       rk[15] = rk[7] ^ rk[14];
+
+                       rk += 8;
+               }
+       }
+
+       return (0);
+}
+#endif /* !__amd64 */
+
+#if defined(__amd64)
+
+/*
+ * Expand the 32-bit AES cipher key array into the encryption and decryption
+ * key schedules.
+ *
+ * Parameters:
+ * key         AES key schedule to be initialized
+ * keyarr32    User key
+ * keyBits     AES key size (128, 192, or 256 bits)
+ */
+static void
+aes_setupkeys(aes_key_t *key, const uint32_t *keyarr32, int keybits)
+{
+       if (intel_aes_instructions_present()) {
+               key->flags = INTEL_AES_NI_CAPABLE;
+               KPREEMPT_DISABLE;
+               key->nr = rijndael_key_setup_enc_intel(&(key->encr_ks.ks32[0]),
+                   keyarr32, keybits);
+               key->nr = rijndael_key_setup_dec_intel(&(key->decr_ks.ks32[0]),
+                   keyarr32, keybits);
+               KPREEMPT_ENABLE;
+       } else {
+               key->flags = 0;
+               key->nr = rijndael_key_setup_enc_amd64(&(key->encr_ks.ks32[0]),
+                   keyarr32, keybits);
+               key->nr = rijndael_key_setup_dec_amd64(&(key->decr_ks.ks32[0]),
+                   keyarr32, keybits);
+       }
+
+       key->type = AES_32BIT_KS;
+}
+
+/*
+ * Encrypt one block of data. The block is assumed to be an array
+ * of four uint32_t values, so copy for alignment (and byte-order
+ * reversal for little endian systems might be necessary on the
+ * input and output byte streams.
+ * The size of the key schedule depends on the number of rounds
+ * (which can be computed from the size of the key), i.e. 4*(Nr + 1).
+ *
+ * Parameters:
+ * rk          Key schedule, of aes_ks_t (60 32-bit integers)
+ * Nr          Number of rounds
+ * pt          Input block (plain text)
+ * ct          Output block (crypto text).  Can overlap with pt
+ * flags       Indicates whether we're on Intel AES-NI-capable hardware
+ */
+static void
+rijndael_encrypt(const uint32_t rk[], int Nr, const uint32_t pt[4],
+    uint32_t ct[4], int flags) {
+       if (flags & INTEL_AES_NI_CAPABLE) {
+               KPREEMPT_DISABLE;
+               aes_encrypt_intel(rk, Nr, pt, ct);
+               KPREEMPT_ENABLE;
+       } else {
+               aes_encrypt_amd64(rk, Nr, pt, ct);
+       }
+}
+
+/*
+ * Decrypt one block of data. The block is assumed to be an array
+ * of four uint32_t values, so copy for alignment (and byte-order
+ * reversal for little endian systems might be necessary on the
+ * input and output byte streams.
+ * The size of the key schedule depends on the number of rounds
+ * (which can be computed from the size of the key), i.e. 4*(Nr + 1).
+ *
+ * Parameters:
+ * rk          Key schedule, of aes_ks_t (60 32-bit integers)
+ * Nr          Number of rounds
+ * ct          Input block (crypto text)
+ * pt          Output block (plain text). Can overlap with pt
+ * flags       Indicates whether we're on Intel AES-NI-capable hardware
+ */
+static void
+rijndael_decrypt(const uint32_t rk[], int Nr, const uint32_t ct[4],
+    uint32_t pt[4], int flags) {
+       if (flags & INTEL_AES_NI_CAPABLE) {
+               KPREEMPT_DISABLE;
+               aes_decrypt_intel(rk, Nr, ct, pt);
+               KPREEMPT_ENABLE;
+       } else {
+               aes_decrypt_amd64(rk, Nr, ct, pt);
+       }
+}
+
+
+#else /* generic C implementation */
+
+/*
+ *  Expand the cipher key into the decryption key schedule.
+ *  Return the number of rounds for the given cipher key size.
+ *  The size of the key schedule depends on the number of rounds
+ *  (which can be computed from the size of the key), i.e. 4*(Nr + 1).
+ *
+ * Parameters:
+ * rk          AES key schedule 32-bit array to be initialized
+ * cipherKey   User key
+ * keyBits     AES key size (128, 192, or 256 bits)
+ */
+static int
+rijndael_key_setup_dec(uint32_t rk[], const uint32_t cipherKey[], int keyBits)
+{
+       int      Nr, i, j;
+       uint32_t temp;
+
+       /* expand the cipher key: */
+       Nr = rijndael_key_setup_enc_raw(rk, cipherKey, keyBits);
+
+       /* invert the order of the round keys: */
+       for (i = 0, j = 4 * Nr; i < j; i += 4, j -= 4) {
+               temp = rk[i];
+               rk[i] = rk[j];
+               rk[j] = temp;
+               temp = rk[i + 1];
+               rk[i + 1] = rk[j + 1];
+               rk[j + 1] = temp;
+               temp = rk[i + 2];
+               rk[i + 2] = rk[j + 2];
+               rk[j + 2] = temp;
+               temp = rk[i + 3];
+               rk[i + 3] = rk[j + 3];
+               rk[j + 3] = temp;
+       }
+
+       /*
+        * apply the inverse MixColumn transform to all
+        * round keys but the first and the last:
+        */
+       for (i = 1; i < Nr; i++) {
+               rk += 4;
+               rk[0] = Td0[Te4[rk[0] >> 24] & 0xff] ^
+                   Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+                   Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
+                   Td3[Te4[rk[0] & 0xff] & 0xff];
+               rk[1] = Td0[Te4[rk[1] >> 24] & 0xff] ^
+                   Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+                   Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
+                   Td3[Te4[rk[1] & 0xff] & 0xff];
+               rk[2] = Td0[Te4[rk[2] >> 24] & 0xff] ^
+                   Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+                   Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
+                   Td3[Te4[rk[2] & 0xff] & 0xff];
+               rk[3] = Td0[Te4[rk[3] >> 24] & 0xff] ^
+                   Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+                   Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
+                   Td3[Te4[rk[3] & 0xff] & 0xff];
+       }
+
+       return (Nr);
+}
+
+
+/*
+ * Expand the 32-bit AES cipher key array into the encryption and decryption
+ * key schedules.
+ *
+ * Parameters:
+ * key         AES key schedule to be initialized
+ * keyarr32    User key
+ * keyBits     AES key size (128, 192, or 256 bits)
+ */
+static void
+aes_setupkeys(aes_key_t *key, const uint32_t *keyarr32, int keybits)
+{
+       key->nr = rijndael_key_setup_enc(&(key->encr_ks.ks32[0]), keyarr32,
+           keybits);
+       key->nr = rijndael_key_setup_dec(&(key->decr_ks.ks32[0]), keyarr32,
+           keybits);
+       key->type = AES_32BIT_KS;
+}
+
+
+/*
+ * Encrypt one block of data. The block is assumed to be an array
+ * of four uint32_t values, so copy for alignment (and byte-order
+ * reversal for little endian systems might be necessary on the
+ * input and output byte streams.
+ * The size of the key schedule depends on the number of rounds
+ * (which can be computed from the size of the key), i.e. 4*(Nr + 1).
+ *
+ * Parameters:
+ * rk  Key schedule, of aes_ks_t (60 32-bit integers)
+ * Nr  Number of rounds
+ * pt  Input block (plain text)
+ * ct  Output block (crypto text).  Can overlap with pt
+ */
+static void
+rijndael_encrypt(const uint32_t rk[], int Nr, const uint32_t pt[4],
+    uint32_t ct[4])
+{
+       uint32_t        s0, s1, s2, s3, t0, t1, t2, t3;
+       int             r;
+
+       /*
+        * map byte array block to cipher state
+        * and add initial round key:
+        */
+
+       s0 = pt[0] ^ rk[0];
+       s1 = pt[1] ^ rk[1];
+       s2 = pt[2] ^ rk[2];
+       s3 = pt[3] ^ rk[3];
+
+       /*
+        * Nr - 1 full rounds:
+        */
+
+       r = Nr >> 1;
+
+       for (;;) {
+               t0 = Te0[s0 >> 24] ^
+                   Te1[(s1 >> 16) & 0xff] ^
+                   Te2[(s2 >>  8) & 0xff] ^
+                   Te3[s3 & 0xff] ^
+                   rk[4];
+
+               t1 = Te0[s1 >> 24] ^
+                   Te1[(s2 >> 16) & 0xff] ^
+                   Te2[(s3 >>  8) & 0xff] ^
+                   Te3[s0 & 0xff] ^
+                   rk[5];
+
+               t2 = Te0[s2 >> 24] ^
+                   Te1[(s3 >> 16) & 0xff] ^
+                   Te2[(s0 >>  8) & 0xff] ^
+                   Te3[s1 & 0xff] ^
+                   rk[6];
+
+               t3 = Te0[s3 >> 24] ^
+                   Te1[(s0 >> 16) & 0xff] ^
+                   Te2[(s1 >>  8) & 0xff] ^
+                   Te3[s2 & 0xff] ^
+                   rk[7];
+
+               rk += 8;
+
+               if (--r == 0) {
+                       break;
+               }
+
+               s0 = Te0[t0 >> 24] ^
+                   Te1[(t1 >> 16) & 0xff] ^
+                   Te2[(t2 >>  8) & 0xff] ^
+                   Te3[t3 & 0xff] ^
+                   rk[0];
+
+               s1 = Te0[t1 >> 24] ^
+                   Te1[(t2 >> 16) & 0xff] ^
+                   Te2[(t3 >>  8) & 0xff] ^
+                   Te3[t0 & 0xff] ^
+                   rk[1];
+
+               s2 = Te0[t2 >> 24] ^
+                   Te1[(t3 >> 16) & 0xff] ^
+                   Te2[(t0 >>  8) & 0xff] ^
+                   Te3[t1 & 0xff] ^
+                   rk[2];
+
+               s3 = Te0[t3 >> 24] ^
+                   Te1[(t0 >> 16) & 0xff] ^
+                   Te2[(t1 >>  8) & 0xff] ^
+                   Te3[t2 & 0xff] ^
+                   rk[3];
+       }
+
+       /*
+        * apply last round and
+        * map cipher state to byte array block:
+        */
+
+       s0 = (Te4[(t0 >> 24)] & 0xff000000) ^
+           (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+           (Te4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+           (Te4[t3 & 0xff] & 0x000000ff) ^
+           rk[0];
+       ct[0] = s0;
+
+       s1 = (Te4[(t1 >> 24)] & 0xff000000) ^
+           (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+           (Te4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+           (Te4[t0 & 0xff] & 0x000000ff) ^
+           rk[1];
+       ct[1] = s1;
+
+       s2 = (Te4[(t2 >> 24)] & 0xff000000) ^
+           (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+           (Te4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+           (Te4[t1 & 0xff] & 0x000000ff) ^
+           rk[2];
+       ct[2] = s2;
+
+       s3 = (Te4[(t3 >> 24)] & 0xff000000) ^
+           (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+           (Te4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+           (Te4[t2 & 0xff] & 0x000000ff) ^
+           rk[3];
+       ct[3] = s3;
+}
+
+
+/*
+ * Decrypt one block of data. The block is assumed to be an array
+ * of four uint32_t values, so copy for alignment (and byte-order
+ * reversal for little endian systems might be necessary on the
+ * input and output byte streams.
+ * The size of the key schedule depends on the number of rounds
+ * (which can be computed from the size of the key), i.e. 4*(Nr + 1).
+ *
+ * Parameters:
+ * rk  Key schedule, of aes_ks_t (60 32-bit integers)
+ * Nr  Number of rounds
+ * ct  Input block (crypto text)
+ * pt  Output block (plain text). Can overlap with pt
+ */
+static void
+rijndael_decrypt(const uint32_t rk[], int Nr, const uint32_t ct[4],
+    uint32_t pt[4])
+{
+       uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
+       int      r;
+
+       /*
+        * map byte array block to cipher state
+        * and add initial round key:
+        */
+       s0 = ct[0] ^ rk[0];
+       s1 = ct[1] ^ rk[1];
+       s2 = ct[2] ^ rk[2];
+       s3 = ct[3] ^ rk[3];
+
+       /*
+        * Nr - 1 full rounds:
+        */
+
+       r = Nr >> 1;
+
+       for (;;) {
+               t0 = Td0[s0 >> 24] ^
+                   Td1[(s3 >> 16) & 0xff] ^
+                   Td2[(s2 >> 8) & 0xff] ^
+                   Td3[s1 & 0xff] ^
+                   rk[4];
+
+               t1 = Td0[s1 >> 24] ^
+                   Td1[(s0 >> 16) & 0xff] ^
+                   Td2[(s3 >>  8) & 0xff] ^
+                   Td3[s2 & 0xff] ^
+                   rk[5];
+
+               t2 = Td0[s2 >> 24] ^
+                   Td1[(s1 >> 16) & 0xff] ^
+                   Td2[(s0 >>  8) & 0xff] ^
+                   Td3[s3 & 0xff] ^
+                   rk[6];
+
+               t3 = Td0[s3 >> 24] ^
+                   Td1[(s2 >> 16) & 0xff] ^
+                   Td2[(s1 >> 8) & 0xff] ^
+                   Td3[s0 & 0xff] ^
+                   rk[7];
+
+               rk += 8;
+
+               if (--r == 0) {
+                       break;
+               }
+
+               s0 = Td0[t0 >> 24] ^
+                   Td1[(t3 >> 16) & 0xff] ^
+                   Td2[(t2 >> 8) & 0xff] ^
+                   Td3[t1 & 0xff] ^
+                   rk[0];
+
+               s1 = Td0[t1 >> 24] ^
+                   Td1[(t0 >> 16) & 0xff] ^
+                   Td2[(t3 >> 8) & 0xff] ^
+                   Td3[t2 & 0xff] ^
+                   rk[1];
+
+               s2 = Td0[t2 >> 24] ^
+                   Td1[(t1 >> 16) & 0xff] ^
+                   Td2[(t0 >> 8) & 0xff] ^
+                   Td3[t3 & 0xff] ^
+                   rk[2];
+
+               s3 = Td0[t3 >> 24] ^
+                   Td1[(t2 >> 16) & 0xff] ^
+                   Td2[(t1 >> 8) & 0xff] ^
+                   Td3[t0 & 0xff] ^
+                   rk[3];
+       }
+
+       /*
+        * apply last round and
+        * map cipher state to byte array block:
+        */
+
+       s0 = (Td4[t0 >> 24] & 0xff000000) ^
+           (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+           (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
+           (Td4[t1 & 0xff] & 0x000000ff) ^
+           rk[0];
+       pt[0] = s0;
+
+       s1 = (Td4[t1 >> 24] & 0xff000000) ^
+           (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+           (Td4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+           (Td4[t2 & 0xff] & 0x000000ff) ^
+           rk[1];
+       pt[1] = s1;
+
+       s2 = (Td4[t2 >> 24] & 0xff000000) ^
+           (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+           (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
+           (Td4[t3 & 0xff] & 0x000000ff) ^
+           rk[2];
+       pt[2] = s2;
+
+       s3 = (Td4[t3 >> 24] & 0xff000000) ^
+           (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+           (Td4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+           (Td4[t0 & 0xff] & 0x000000ff) ^
+           rk[3];
+       pt[3] = s3;
+}
+#endif /* __amd64 */
+
+
+/*
+ * Initialize AES encryption and decryption key schedules.
+ *
+ * Parameters:
+ * cipherKey   User key
+ * keyBits     AES key size (128, 192, or 256 bits)
+ * keysched    AES key schedule to be initialized, of type aes_key_t.
+ *             Allocated by aes_alloc_keysched().
+ */
+void
+aes_init_keysched(const uint8_t *cipherKey, uint_t keyBits, void *keysched)
+{
+       aes_key_t       *newbie = keysched;
+       uint_t          keysize, i, j;
+       union {
+               uint64_t        ka64[4];
+               uint32_t        ka32[8];
+               } keyarr;
+
+       switch (keyBits) {
+       case 128:
+               newbie->nr = 10;
+               break;
+
+       case 192:
+               newbie->nr = 12;
+               break;
+
+       case 256:
+               newbie->nr = 14;
+               break;
+
+       default:
+               /* should never get here */
+               return;
+       }
+       keysize = CRYPTO_BITS2BYTES(keyBits);
+
+       /*
+        * For _LITTLE_ENDIAN machines (except AMD64), reverse every
+        * 4 bytes in the key.  On _BIG_ENDIAN and AMD64, copy the key
+        * without reversing bytes.
+        * For AMD64, do not byte swap for aes_setupkeys().
+        *
+        * SPARCv8/v9 uses a key schedule array with 64-bit elements.
+        * X86/AMD64  uses a key schedule array with 32-bit elements.
+        */
+#ifndef        AES_BYTE_SWAP
+       if (IS_P2ALIGNED(cipherKey, sizeof (uint64_t))) {
+               for (i = 0, j = 0; j < keysize; i++, j += 8) {
+                       /* LINTED: pointer alignment */
+                       keyarr.ka64[i] = *((uint64_t *)&cipherKey[j]);
+               }
+       } else {
+               bcopy(cipherKey, keyarr.ka32, keysize);
+       }
+
+#else  /* byte swap */
+       for (i = 0, j = 0; j < keysize; i++, j += 4) {
+               keyarr.ka32[i] = htonl(*(uint32_t *)(void *)&cipherKey[j]);
+       }
+#endif
+
+       aes_setupkeys(newbie, keyarr.ka32, keyBits);
+}
+
+
+/*
+ * Encrypt one block using AES.
+ * Align if needed and (for x86 32-bit only) byte-swap.
+ *
+ * Parameters:
+ * ks  Key schedule, of type aes_key_t
+ * pt  Input block (plain text)
+ * ct  Output block (crypto text).  Can overlap with pt
+ */
+int
+aes_encrypt_block(const void *ks, const uint8_t *pt, uint8_t *ct)
+{
+       aes_key_t       *ksch = (aes_key_t *)ks;
+
+#ifndef        AES_BYTE_SWAP
+       if (IS_P2ALIGNED2(pt, ct, sizeof (uint32_t))) {
+               /* LINTED:  pointer alignment */
+               AES_ENCRYPT_IMPL(&ksch->encr_ks.ks32[0], ksch->nr,
+                   /* LINTED:  pointer alignment */
+                   (uint32_t *)pt, (uint32_t *)ct, ksch->flags);
+       } else {
+#endif
+               uint32_t buffer[AES_BLOCK_LEN / sizeof (uint32_t)];
+
+               /* Copy input block into buffer */
+#ifndef        AES_BYTE_SWAP
+               bcopy(pt, &buffer, AES_BLOCK_LEN);
+
+#else  /* byte swap */
+               buffer[0] = htonl(*(uint32_t *)(void *)&pt[0]);
+               buffer[1] = htonl(*(uint32_t *)(void *)&pt[4]);
+               buffer[2] = htonl(*(uint32_t *)(void *)&pt[8]);
+               buffer[3] = htonl(*(uint32_t *)(void *)&pt[12]);
+#endif
+
+               AES_ENCRYPT_IMPL(&ksch->encr_ks.ks32[0], ksch->nr,
+                   buffer, buffer, ksch->flags);
+
+               /* Copy result from buffer to output block */
+#ifndef        AES_BYTE_SWAP
+               bcopy(&buffer, ct, AES_BLOCK_LEN);
+       }
+
+#else  /* byte swap */
+               *(uint32_t *)(void *)&ct[0] = htonl(buffer[0]);
+               *(uint32_t *)(void *)&ct[4] = htonl(buffer[1]);
+               *(uint32_t *)(void *)&ct[8] = htonl(buffer[2]);
+               *(uint32_t *)(void *)&ct[12] = htonl(buffer[3]);
+#endif
+       return (CRYPTO_SUCCESS);
+}
+
+
+/*
+ * Decrypt one block using AES.
+ * Align and byte-swap if needed.
+ *
+ * Parameters:
+ * ks  Key schedule, of type aes_key_t
+ * ct  Input block (crypto text)
+ * pt  Output block (plain text). Can overlap with pt
+ */
+int
+aes_decrypt_block(const void *ks, const uint8_t *ct, uint8_t *pt)
+{
+       aes_key_t       *ksch = (aes_key_t *)ks;
+
+#ifndef        AES_BYTE_SWAP
+       if (IS_P2ALIGNED2(ct, pt, sizeof (uint32_t))) {
+               /* LINTED:  pointer alignment */
+               AES_DECRYPT_IMPL(&ksch->decr_ks.ks32[0], ksch->nr,
+                   /* LINTED:  pointer alignment */
+                   (uint32_t *)ct, (uint32_t *)pt, ksch->flags);
+       } else {
+#endif
+               uint32_t buffer[AES_BLOCK_LEN / sizeof (uint32_t)];
+
+               /* Copy input block into buffer */
+#ifndef        AES_BYTE_SWAP
+               bcopy(ct, &buffer, AES_BLOCK_LEN);
+
+#else  /* byte swap */
+               buffer[0] = htonl(*(uint32_t *)(void *)&ct[0]);
+               buffer[1] = htonl(*(uint32_t *)(void *)&ct[4]);
+               buffer[2] = htonl(*(uint32_t *)(void *)&ct[8]);
+               buffer[3] = htonl(*(uint32_t *)(void *)&ct[12]);
+#endif
+
+               AES_DECRYPT_IMPL(&ksch->decr_ks.ks32[0], ksch->nr,
+                   buffer, buffer, ksch->flags);
+
+               /* Copy result from buffer to output block */
+#ifndef        AES_BYTE_SWAP
+               bcopy(&buffer, pt, AES_BLOCK_LEN);
+       }
+
+#else  /* byte swap */
+       *(uint32_t *)(void *)&pt[0] = htonl(buffer[0]);
+       *(uint32_t *)(void *)&pt[4] = htonl(buffer[1]);
+       *(uint32_t *)(void *)&pt[8] = htonl(buffer[2]);
+       *(uint32_t *)(void *)&pt[12] = htonl(buffer[3]);
+#endif
+
+       return (CRYPTO_SUCCESS);
+}
+
+
+/*
+ * Allocate key schedule for AES.
+ *
+ * Return the pointer and set size to the number of bytes allocated.
+ * Memory allocated must be freed by the caller when done.
+ *
+ * Parameters:
+ * size                Size of key schedule allocated, in bytes
+ * kmflag      Flag passed to kmem_alloc(9F); ignored in userland.
+ */
+/* ARGSUSED */
+void *
+aes_alloc_keysched(size_t *size, int kmflag)
+{
+       aes_key_t *keysched;
+
+       keysched = (aes_key_t *)kmem_alloc(sizeof (aes_key_t), kmflag);
+       if (keysched != NULL) {
+               *size = sizeof (aes_key_t);
+               return (keysched);
+       }
+       return (NULL);
+}
+
+
+#ifdef __amd64
+
+#define        INTEL_AESNI_FLAG (1 << 25)
+
+/*
+ * Return 1 if executing on Intel with AES-NI instructions,
+ * otherwise 0 (i.e., Intel without AES-NI or AMD64).
+ * Cache the result, as the CPU can't change.
+ */
+static int
+intel_aes_instructions_present(void)
+{
+       static int cached_result = -1;
+       unsigned eax, ebx, ecx, edx;
+       unsigned func, subfunc;
+
+       if (cached_result == -1) { /* first time */
+               /* check for an intel cpu */
+               func = 0;
+               subfunc = 0;
+
+               __asm__ __volatile__(
+                   "cpuid"
+                   : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+                   : "a"(func), "c"(subfunc));
+
+               if (memcmp((char *) (&ebx), "Genu", 4) == 0 &&
+                   memcmp((char *) (&edx), "ineI", 4) == 0 &&
+                       memcmp((char *) (&ecx), "ntel", 4) == 0) {
+
+                       func = 1;
+                       subfunc = 0;
+
+                       /* check for aes-ni instruction set */
+                       __asm__ __volatile__(
+                               "cpuid"
+                               : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+                               : "a"(func), "c"(subfunc));
+
+                       cached_result = !!(ecx & INTEL_AESNI_FLAG);
+               } else {
+                       cached_result = 0;
+               }
+       }
+
+       return (cached_result);
+}
+
+#endif /* __amd64 */
diff --git a/zfs/module/icp/algs/aes/aes_modes.c b/zfs/module/icp/algs/aes/aes_modes.c
new file mode 100644 (file)
index 0000000..9e4b498
--- /dev/null
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/zfs_context.h>
+#include <modes/modes.h>
+#include <aes/aes_impl.h>
+
+/* Copy a 16-byte AES block from "in" to "out" */
+void
+aes_copy_block(uint8_t *in, uint8_t *out)
+{
+       if (IS_P2ALIGNED2(in, out, sizeof (uint32_t))) {
+               /* LINTED: pointer alignment */
+               *(uint32_t *)&out[0] = *(uint32_t *)&in[0];
+               /* LINTED: pointer alignment */
+               *(uint32_t *)&out[4] = *(uint32_t *)&in[4];
+               /* LINTED: pointer alignment */
+               *(uint32_t *)&out[8] = *(uint32_t *)&in[8];
+               /* LINTED: pointer alignment */
+               *(uint32_t *)&out[12] = *(uint32_t *)&in[12];
+       } else {
+               AES_COPY_BLOCK(in, out);
+       }
+}
+
+
+/* XOR a 16-byte AES block of data into dst */
+void
+aes_xor_block(uint8_t *data, uint8_t *dst)
+{
+       if (IS_P2ALIGNED2(dst, data, sizeof (uint32_t))) {
+               /* LINTED: pointer alignment */
+               *(uint32_t *)&dst[0] ^= *(uint32_t *)&data[0];
+               /* LINTED: pointer alignment */
+               *(uint32_t *)&dst[4] ^= *(uint32_t *)&data[4];
+               /* LINTED: pointer alignment */
+               *(uint32_t *)&dst[8] ^= *(uint32_t *)&data[8];
+               /* LINTED: pointer alignment */
+               *(uint32_t *)&dst[12] ^= *(uint32_t *)&data[12];
+       } else {
+               AES_XOR_BLOCK(data, dst);
+       }
+}
+
+
+/*
+ * Encrypt multiple blocks of data according to mode.
+ */
+int
+aes_encrypt_contiguous_blocks(void *ctx, char *data, size_t length,
+    crypto_data_t *out)
+{
+       aes_ctx_t *aes_ctx = ctx;
+       int rv;
+
+       if (aes_ctx->ac_flags & CTR_MODE) {
+               rv = ctr_mode_contiguous_blocks(ctx, data, length, out,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+       } else if (aes_ctx->ac_flags & CCM_MODE) {
+               rv = ccm_mode_encrypt_contiguous_blocks(ctx, data, length,
+                   out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+       } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
+               rv = gcm_mode_encrypt_contiguous_blocks(ctx, data, length,
+                   out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+       } else if (aes_ctx->ac_flags & CBC_MODE) {
+               rv = cbc_encrypt_contiguous_blocks(ctx,
+                   data, length, out, AES_BLOCK_LEN, aes_encrypt_block,
+                   aes_copy_block, aes_xor_block);
+       } else {
+               rv = ecb_cipher_contiguous_blocks(ctx, data, length, out,
+                   AES_BLOCK_LEN, aes_encrypt_block);
+       }
+       return (rv);
+}
+
+
+/*
+ * Decrypt multiple blocks of data according to mode.
+ */
+int
+aes_decrypt_contiguous_blocks(void *ctx, char *data, size_t length,
+    crypto_data_t *out)
+{
+       aes_ctx_t *aes_ctx = ctx;
+       int rv;
+
+       if (aes_ctx->ac_flags & CTR_MODE) {
+               rv = ctr_mode_contiguous_blocks(ctx, data, length, out,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+               if (rv == CRYPTO_DATA_LEN_RANGE)
+                       rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
+       } else if (aes_ctx->ac_flags & CCM_MODE) {
+               rv = ccm_mode_decrypt_contiguous_blocks(ctx, data, length,
+                   out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+       } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
+               rv = gcm_mode_decrypt_contiguous_blocks(ctx, data, length,
+                   out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+       } else if (aes_ctx->ac_flags & CBC_MODE) {
+               rv = cbc_decrypt_contiguous_blocks(ctx, data, length, out,
+                   AES_BLOCK_LEN, aes_decrypt_block, aes_copy_block,
+                   aes_xor_block);
+       } else {
+               rv = ecb_cipher_contiguous_blocks(ctx, data, length, out,
+                   AES_BLOCK_LEN, aes_decrypt_block);
+               if (rv == CRYPTO_DATA_LEN_RANGE)
+                       rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
+       }
+       return (rv);
+}
diff --git a/zfs/module/icp/algs/edonr/edonr.c b/zfs/module/icp/algs/edonr/edonr.c
new file mode 100644 (file)
index 0000000..8ae9898
--- /dev/null
@@ -0,0 +1,751 @@
+/*
+ * IDI,NTNU
+ *
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 (C) 2009, 2010, Jorn Amundsen <jorn.amundsen@ntnu.no>
+ * Tweaked Edon-R implementation for SUPERCOP, based on NIST API.
+ *
+ * $Id: edonr.c 517 2013-02-17 20:34:39Z joern $
+ */
+/*
+ * Portions copyright (c) 2013, Saso Kiselkov, All rights reserved
+ */
+
+/* determine where we can get bcopy/bzero declarations */
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <strings.h>
+#endif
+#include <sys/edonr.h>
+#include <sys/debug.h>
+
+/* big endian support, provides no-op's if run on little endian hosts */
+#include "edonr_byteorder.h"
+
+#define        hashState224(x) ((x)->pipe->p256)
+#define        hashState256(x) ((x)->pipe->p256)
+#define        hashState384(x) ((x)->pipe->p512)
+#define        hashState512(x) ((x)->pipe->p512)
+
+/* shift and rotate shortcuts */
+#define        shl(x, n)       ((x) << n)
+#define        shr(x, n)       ((x) >> n)
+
+#define        rotl32(x, n)    (((x) << (n)) | ((x) >> (32 - (n))))
+#define        rotr32(x, n)    (((x) >> (n)) | ((x) << (32 - (n))))
+
+#define        rotl64(x, n)    (((x) << (n)) | ((x) >> (64 - (n))))
+#define        rotr64(x, n)    (((x) >> (n)) | ((x) << (64 - (n))))
+
+#if !defined(__C99_RESTRICT)
+#define        restrict        /* restrict */
+#endif
+
+#define        EDONR_VALID_HASHBITLEN(x) \
+       ((x) == 512 || (x) == 384 || (x) == 256 || (x) == 224)
+
+/* EdonR224 initial double chaining pipe */
+static const uint32_t i224p2[16] = {
+       0x00010203ul, 0x04050607ul, 0x08090a0bul, 0x0c0d0e0ful,
+       0x10111213ul, 0x14151617ul, 0x18191a1bul, 0x1c1d1e1ful,
+       0x20212223ul, 0x24252627ul, 0x28292a2bul, 0x2c2d2e2ful,
+       0x30313233ul, 0x34353637ul, 0x38393a3bul, 0x3c3d3e3ful,
+};
+
+/* EdonR256 initial double chaining pipe */
+static const uint32_t i256p2[16] = {
+       0x40414243ul, 0x44454647ul, 0x48494a4bul, 0x4c4d4e4ful,
+       0x50515253ul, 0x54555657ul, 0x58595a5bul, 0x5c5d5e5ful,
+       0x60616263ul, 0x64656667ul, 0x68696a6bul, 0x6c6d6e6ful,
+       0x70717273ul, 0x74757677ul, 0x78797a7bul, 0x7c7d7e7ful,
+};
+
+/* EdonR384 initial double chaining pipe */
+static const uint64_t i384p2[16] = {
+       0x0001020304050607ull, 0x08090a0b0c0d0e0full,
+       0x1011121314151617ull, 0x18191a1b1c1d1e1full,
+       0x2021222324252627ull, 0x28292a2b2c2d2e2full,
+       0x3031323334353637ull, 0x38393a3b3c3d3e3full,
+       0x4041424344454647ull, 0x48494a4b4c4d4e4full,
+       0x5051525354555657ull, 0x58595a5b5c5d5e5full,
+       0x6061626364656667ull, 0x68696a6b6c6d6e6full,
+       0x7071727374757677ull, 0x78797a7b7c7d7e7full
+};
+
+/* EdonR512 initial double chaining pipe */
+static const uint64_t i512p2[16] = {
+       0x8081828384858687ull, 0x88898a8b8c8d8e8full,
+       0x9091929394959697ull, 0x98999a9b9c9d9e9full,
+       0xa0a1a2a3a4a5a6a7ull, 0xa8a9aaabacadaeafull,
+       0xb0b1b2b3b4b5b6b7ull, 0xb8b9babbbcbdbebfull,
+       0xc0c1c2c3c4c5c6c7ull, 0xc8c9cacbcccdcecfull,
+       0xd0d1d2d3d4d5d6d7ull, 0xd8d9dadbdcdddedfull,
+       0xe0e1e2e3e4e5e6e7ull, 0xe8e9eaebecedeeefull,
+       0xf0f1f2f3f4f5f6f7ull, 0xf8f9fafbfcfdfeffull
+};
+
+/*
+ * First Latin Square
+ * 0   7   1   3   2   4   6   5
+ * 4   1   7   6   3   0   5   2
+ * 7   0   4   2   5   3   1   6
+ * 1   4   0   5   6   2   7   3
+ * 2   3   6   7   1   5   0   4
+ * 5   2   3   1   7   6   4   0
+ * 3   6   5   0   4   7   2   1
+ * 6   5   2   4   0   1   3   7
+ */
+#define        LS1_256(c, x0, x1, x2, x3, x4, x5, x6, x7)                      \
+{                                                                      \
+       uint32_t x04, x17, x23, x56, x07, x26;                          \
+       x04 = x0+x4, x17 = x1+x7, x07 = x04+x17;                        \
+       s0 = c + x07 + x2;                                              \
+       s1 = rotl32(x07 + x3, 4);                                       \
+       s2 = rotl32(x07 + x6, 8);                                       \
+       x23 = x2 + x3;                                                  \
+       s5 = rotl32(x04 + x23 + x5, 22);                                \
+       x56 = x5 + x6;                                                  \
+       s6 = rotl32(x17 + x56 + x0, 24);                                \
+       x26 = x23+x56;                                                  \
+       s3 = rotl32(x26 + x7, 13);                                      \
+       s4 = rotl32(x26 + x1, 17);                                      \
+       s7 = rotl32(x26 + x4, 29);                                      \
+}
+
+#define        LS1_512(c, x0, x1, x2, x3, x4, x5, x6, x7)                      \
+{                                                                      \
+       uint64_t x04, x17, x23, x56, x07, x26;                          \
+       x04 = x0+x4, x17 = x1+x7, x07 = x04+x17;                        \
+       s0 = c + x07 + x2;                                              \
+       s1 = rotl64(x07 + x3, 5);                                       \
+       s2 = rotl64(x07 + x6, 15);                                      \
+       x23 = x2 + x3;                                                  \
+       s5 = rotl64(x04 + x23 + x5, 40);                                \
+       x56 = x5 + x6;                                                  \
+       s6 = rotl64(x17 + x56 + x0, 50);                                \
+       x26 = x23+x56;                                                  \
+       s3 = rotl64(x26 + x7, 22);                                      \
+       s4 = rotl64(x26 + x1, 31);                                      \
+       s7 = rotl64(x26 + x4, 59);                                      \
+}
+
+/*
+ * Second Orthogonal Latin Square
+ * 0   4   2   3   1   6   5   7
+ * 7   6   3   2   5   4   1   0
+ * 5   3   1   6   0   2   7   4
+ * 1   0   5   4   3   7   2   6
+ * 2   1   0   7   4   5   6   3
+ * 3   5   7   0   6   1   4   2
+ * 4   7   6   1   2   0   3   5
+ * 6   2   4   5   7   3   0   1
+ */
+#define        LS2_256(c, y0, y1, y2, y3, y4, y5, y6, y7)                      \
+{                                                                      \
+       uint32_t y01, y25, y34, y67, y04, y05, y27, y37;                \
+       y01 = y0+y1, y25 = y2+y5, y05 = y01+y25;                        \
+       t0  = ~c + y05 + y7;                                            \
+       t2 = rotl32(y05 + y3, 9);                                       \
+       y34 = y3+y4, y04 = y01+y34;                                     \
+       t1 = rotl32(y04 + y6, 5);                                       \
+       t4 = rotl32(y04 + y5, 15);                                      \
+       y67 = y6+y7, y37 = y34+y67;                                     \
+       t3 = rotl32(y37 + y2, 11);                                      \
+       t7 = rotl32(y37 + y0, 27);                                      \
+       y27 = y25+y67;                                                  \
+       t5 = rotl32(y27 + y4, 20);                                      \
+       t6 = rotl32(y27 + y1, 25);                                      \
+}
+
+#define        LS2_512(c, y0, y1, y2, y3, y4, y5, y6, y7)                      \
+{                                                                      \
+       uint64_t y01, y25, y34, y67, y04, y05, y27, y37;                \
+       y01 = y0+y1, y25 = y2+y5, y05 = y01+y25;                        \
+       t0  = ~c + y05 + y7;                                            \
+       t2 = rotl64(y05 + y3, 19);                                      \
+       y34 = y3+y4, y04 = y01+y34;                                     \
+       t1 = rotl64(y04 + y6, 10);                                      \
+       t4 = rotl64(y04 + y5, 36);                                      \
+       y67 = y6+y7, y37 = y34+y67;                                     \
+       t3 = rotl64(y37 + y2, 29);                                      \
+       t7 = rotl64(y37 + y0, 55);                                      \
+       y27 = y25+y67;                                                  \
+       t5 = rotl64(y27 + y4, 44);                                      \
+       t6 = rotl64(y27 + y1, 48);                                      \
+}
+
+#define        quasi_exform256(r0, r1, r2, r3, r4, r5, r6, r7)                 \
+{                                                                      \
+       uint32_t s04, s17, s23, s56, t01, t25, t34, t67;                \
+       s04 = s0 ^ s4, t01 = t0 ^ t1;                                   \
+       r0 = (s04 ^ s1) + (t01 ^ t5);                                   \
+       t67 = t6 ^ t7;                                                  \
+       r1 = (s04 ^ s7) + (t2 ^ t67);                                   \
+       s23 = s2 ^ s3;                                                  \
+       r7 = (s23 ^ s5) + (t4 ^ t67);                                   \
+       t34 = t3 ^ t4;                                                  \
+       r3 = (s23 ^ s4) + (t0 ^ t34);                                   \
+       s56 = s5 ^ s6;                                                  \
+       r5 = (s3 ^ s56) + (t34 ^ t6);                                   \
+       t25 = t2 ^ t5;                                                  \
+       r6 = (s2 ^ s56) + (t25 ^ t7);                                   \
+       s17 = s1 ^ s7;                                                  \
+       r4 = (s0 ^ s17) + (t1 ^ t25);                                   \
+       r2 = (s17 ^ s6) + (t01 ^ t3);                                   \
+}
+
+#define        quasi_exform512(r0, r1, r2, r3, r4, r5, r6, r7)                 \
+{                                                                      \
+       uint64_t s04, s17, s23, s56, t01, t25, t34, t67;                \
+       s04 = s0 ^ s4, t01 = t0 ^ t1;                                   \
+       r0 = (s04 ^ s1) + (t01 ^ t5);                                   \
+       t67 = t6 ^ t7;                                                  \
+       r1 = (s04 ^ s7) + (t2 ^ t67);                                   \
+       s23 = s2 ^ s3;                                                  \
+       r7 = (s23 ^ s5) + (t4 ^ t67);                                   \
+       t34 = t3 ^ t4;                                                  \
+       r3 = (s23 ^ s4) + (t0 ^ t34);                                   \
+       s56 = s5 ^ s6;                                                  \
+       r5 = (s3 ^ s56) + (t34 ^ t6);                                   \
+       t25 = t2 ^ t5;                                                  \
+       r6 = (s2 ^ s56) + (t25 ^ t7);                                   \
+       s17 = s1 ^ s7;                                                  \
+       r4 = (s0 ^ s17) + (t1 ^ t25);                                   \
+       r2 = (s17 ^ s6) + (t01 ^ t3);                                   \
+}
+
+static size_t
+Q256(size_t bitlen, const uint32_t *data, uint32_t *restrict p)
+{
+       size_t bl;
+
+       for (bl = bitlen; bl >= EdonR256_BLOCK_BITSIZE;
+           bl -= EdonR256_BLOCK_BITSIZE, data += 16) {
+               uint32_t s0, s1, s2, s3, s4, s5, s6, s7, t0, t1, t2, t3, t4,
+                   t5, t6, t7;
+               uint32_t p0, p1, p2, p3, p4, p5, p6, p7, q0, q1, q2, q3, q4,
+                   q5, q6, q7;
+               const uint32_t defix = 0xaaaaaaaa;
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               uint32_t swp0, swp1, swp2, swp3, swp4, swp5, swp6, swp7, swp8,
+                   swp9, swp10, swp11, swp12, swp13, swp14, swp15;
+#define        d(j)    swp ## j
+#define        s32(j)  ld_swap32((uint32_t *)data + j, swp ## j)
+#else
+#define        d(j)    data[j]
+#endif
+
+               /* First row of quasigroup e-transformations */
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               s32(8);
+               s32(9);
+               s32(10);
+               s32(11);
+               s32(12);
+               s32(13);
+               s32(14);
+               s32(15);
+#endif
+               LS1_256(defix, d(15), d(14), d(13), d(12), d(11), d(10), d(9),
+                   d(8));
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               s32(0);
+               s32(1);
+               s32(2);
+               s32(3);
+               s32(4);
+               s32(5);
+               s32(6);
+               s32(7);
+#undef s32
+#endif
+               LS2_256(defix, d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7));
+               quasi_exform256(p0, p1, p2, p3, p4, p5, p6, p7);
+
+               LS1_256(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               LS2_256(defix, d(8), d(9), d(10), d(11), d(12), d(13), d(14),
+                   d(15));
+               quasi_exform256(q0, q1, q2, q3, q4, q5, q6, q7);
+
+               /* Second row of quasigroup e-transformations */
+               LS1_256(defix, p[8], p[9], p[10], p[11], p[12], p[13], p[14],
+                   p[15]);
+               LS2_256(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               quasi_exform256(p0, p1, p2, p3, p4, p5, p6, p7);
+
+               LS1_256(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               LS2_256(defix, q0, q1, q2, q3, q4, q5, q6, q7);
+               quasi_exform256(q0, q1, q2, q3, q4, q5, q6, q7);
+
+               /* Third row of quasigroup e-transformations */
+               LS1_256(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               LS2_256(defix, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+               quasi_exform256(p0, p1, p2, p3, p4, p5, p6, p7);
+
+               LS1_256(defix, q0, q1, q2, q3, q4, q5, q6, q7);
+               LS2_256(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               quasi_exform256(q0, q1, q2, q3, q4, q5, q6, q7);
+
+               /* Fourth row of quasigroup e-transformations */
+               LS1_256(defix, d(7), d(6), d(5), d(4), d(3), d(2), d(1), d(0));
+               LS2_256(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               quasi_exform256(p0, p1, p2, p3, p4, p5, p6, p7);
+
+               LS1_256(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               LS2_256(defix, q0, q1, q2, q3, q4, q5, q6, q7);
+               quasi_exform256(q0, q1, q2, q3, q4, q5, q6, q7);
+
+               /* Edon-R tweak on the original SHA-3 Edon-R submission. */
+               p[0] ^= d(8) ^ p0;
+               p[1] ^= d(9) ^ p1;
+               p[2] ^= d(10) ^ p2;
+               p[3] ^= d(11) ^ p3;
+               p[4] ^= d(12) ^ p4;
+               p[5] ^= d(13) ^ p5;
+               p[6] ^= d(14) ^ p6;
+               p[7] ^= d(15) ^ p7;
+               p[8] ^= d(0) ^ q0;
+               p[9] ^= d(1) ^ q1;
+               p[10] ^= d(2) ^ q2;
+               p[11] ^= d(3) ^ q3;
+               p[12] ^= d(4) ^ q4;
+               p[13] ^= d(5) ^ q5;
+               p[14] ^= d(6) ^ q6;
+               p[15] ^= d(7) ^ q7;
+       }
+
+#undef d
+       return (bitlen - bl);
+}
+
+/*
+ * Why is this #pragma here?
+ *
+ * Checksum functions like this one can go over the stack frame size check
+ * Linux imposes on 32-bit platforms (-Wframe-larger-than=1024).  We can
+ * safely ignore the compiler error since we know that in ZoL, that
+ * the function will be called from a worker thread that won't be using
+ * much stack.  The only function that goes over the 1k limit is Q512(),
+ * which only goes over it by a hair (1248 bytes on ARM32).
+ */
+#include <sys/isa_defs.h>      /* for _ILP32 */
+#ifdef _ILP32   /* We're 32-bit, assume small stack frames */
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+#endif
+
+#if defined(__IBMC__) && defined(_AIX) && defined(__64BIT__)
+static inline size_t
+#else
+static size_t
+#endif
+Q512(size_t bitlen, const uint64_t *data, uint64_t *restrict p)
+{
+       size_t bl;
+
+       for (bl = bitlen; bl >= EdonR512_BLOCK_BITSIZE;
+           bl -= EdonR512_BLOCK_BITSIZE, data += 16) {
+               uint64_t s0, s1, s2, s3, s4, s5, s6, s7, t0, t1, t2, t3, t4,
+                   t5, t6, t7;
+               uint64_t p0, p1, p2, p3, p4, p5, p6, p7, q0, q1, q2, q3, q4,
+                   q5, q6, q7;
+               const uint64_t defix = 0xaaaaaaaaaaaaaaaaull;
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               uint64_t swp0, swp1, swp2, swp3, swp4, swp5, swp6, swp7, swp8,
+                   swp9, swp10, swp11, swp12, swp13, swp14, swp15;
+#define        d(j)    swp##j
+#define        s64(j)  ld_swap64((uint64_t *)data+j, swp##j)
+#else
+#define        d(j)    data[j]
+#endif
+
+               /* First row of quasigroup e-transformations */
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               s64(8);
+               s64(9);
+               s64(10);
+               s64(11);
+               s64(12);
+               s64(13);
+               s64(14);
+               s64(15);
+#endif
+               LS1_512(defix, d(15), d(14), d(13), d(12), d(11), d(10), d(9),
+                   d(8));
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               s64(0);
+               s64(1);
+               s64(2);
+               s64(3);
+               s64(4);
+               s64(5);
+               s64(6);
+               s64(7);
+#undef s64
+#endif
+               LS2_512(defix, d(0), d(1), d(2), d(3), d(4), d(5), d(6), d(7));
+               quasi_exform512(p0, p1, p2, p3, p4, p5, p6, p7);
+
+               LS1_512(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               LS2_512(defix, d(8), d(9), d(10), d(11), d(12), d(13), d(14),
+                   d(15));
+               quasi_exform512(q0, q1, q2, q3, q4, q5, q6, q7);
+
+               /* Second row of quasigroup e-transformations */
+               LS1_512(defix, p[8], p[9], p[10], p[11], p[12], p[13], p[14],
+                   p[15]);
+               LS2_512(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               quasi_exform512(p0, p1, p2, p3, p4, p5, p6, p7);
+
+               LS1_512(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               LS2_512(defix, q0, q1, q2, q3, q4, q5, q6, q7);
+               quasi_exform512(q0, q1, q2, q3, q4, q5, q6, q7);
+
+               /* Third row of quasigroup e-transformations */
+               LS1_512(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               LS2_512(defix, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+               quasi_exform512(p0, p1, p2, p3, p4, p5, p6, p7);
+
+               LS1_512(defix, q0, q1, q2, q3, q4, q5, q6, q7);
+               LS2_512(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               quasi_exform512(q0, q1, q2, q3, q4, q5, q6, q7);
+
+               /* Fourth row of quasigroup e-transformations */
+               LS1_512(defix, d(7), d(6), d(5), d(4), d(3), d(2), d(1), d(0));
+               LS2_512(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               quasi_exform512(p0, p1, p2, p3, p4, p5, p6, p7);
+
+               LS1_512(defix, p0, p1, p2, p3, p4, p5, p6, p7);
+               LS2_512(defix, q0, q1, q2, q3, q4, q5, q6, q7);
+               quasi_exform512(q0, q1, q2, q3, q4, q5, q6, q7);
+
+               /* Edon-R tweak on the original SHA-3 Edon-R submission. */
+               p[0] ^= d(8) ^ p0;
+               p[1] ^= d(9) ^ p1;
+               p[2] ^= d(10) ^ p2;
+               p[3] ^= d(11) ^ p3;
+               p[4] ^= d(12) ^ p4;
+               p[5] ^= d(13) ^ p5;
+               p[6] ^= d(14) ^ p6;
+               p[7] ^= d(15) ^ p7;
+               p[8] ^= d(0) ^ q0;
+               p[9] ^= d(1) ^ q1;
+               p[10] ^= d(2) ^ q2;
+               p[11] ^= d(3) ^ q3;
+               p[12] ^= d(4) ^ q4;
+               p[13] ^= d(5) ^ q5;
+               p[14] ^= d(6) ^ q6;
+               p[15] ^= d(7) ^ q7;
+       }
+
+#undef d
+       return (bitlen - bl);
+}
+
+void
+EdonRInit(EdonRState *state, size_t hashbitlen)
+{
+       ASSERT(EDONR_VALID_HASHBITLEN(hashbitlen));
+       switch (hashbitlen) {
+       case 224:
+               state->hashbitlen = 224;
+               state->bits_processed = 0;
+               state->unprocessed_bits = 0;
+               bcopy(i224p2, hashState224(state)->DoublePipe,
+                   16 * sizeof (uint32_t));
+               break;
+
+       case 256:
+               state->hashbitlen = 256;
+               state->bits_processed = 0;
+               state->unprocessed_bits = 0;
+               bcopy(i256p2, hashState256(state)->DoublePipe,
+                   16 * sizeof (uint32_t));
+               break;
+
+       case 384:
+               state->hashbitlen = 384;
+               state->bits_processed = 0;
+               state->unprocessed_bits = 0;
+               bcopy(i384p2, hashState384(state)->DoublePipe,
+                   16 * sizeof (uint64_t));
+               break;
+
+       case 512:
+               state->hashbitlen = 512;
+               state->bits_processed = 0;
+               state->unprocessed_bits = 0;
+               bcopy(i512p2, hashState224(state)->DoublePipe,
+                   16 * sizeof (uint64_t));
+               break;
+       }
+}
+
+
+void
+EdonRUpdate(EdonRState *state, const uint8_t *data, size_t databitlen)
+{
+       uint32_t *data32;
+       uint64_t *data64;
+
+       size_t bits_processed;
+
+       ASSERT(EDONR_VALID_HASHBITLEN(state->hashbitlen));
+       switch (state->hashbitlen) {
+       case 224:
+       case 256:
+               if (state->unprocessed_bits > 0) {
+                       /* LastBytes = databitlen / 8 */
+                       int LastBytes = (int)databitlen >> 3;
+
+                       ASSERT(state->unprocessed_bits + databitlen <=
+                           EdonR256_BLOCK_SIZE * 8);
+
+                       bcopy(data, hashState256(state)->LastPart
+                           + (state->unprocessed_bits >> 3), LastBytes);
+                       state->unprocessed_bits += (int)databitlen;
+                       databitlen = state->unprocessed_bits;
+                       /* LINTED E_BAD_PTR_CAST_ALIGN */
+                       data32 = (uint32_t *)hashState256(state)->LastPart;
+               } else
+                       /* LINTED E_BAD_PTR_CAST_ALIGN */
+                       data32 = (uint32_t *)data;
+
+               bits_processed = Q256(databitlen, data32,
+                   hashState256(state)->DoublePipe);
+               state->bits_processed += bits_processed;
+               databitlen -= bits_processed;
+               state->unprocessed_bits = (int)databitlen;
+               if (databitlen > 0) {
+                       /* LastBytes = Ceil(databitlen / 8) */
+                       int LastBytes =
+                           ((~(((-(int)databitlen) >> 3) & 0x01ff)) +
+                           1) & 0x01ff;
+
+                       data32 += bits_processed >> 5;  /* byte size update */
+                       bcopy(data32, hashState256(state)->LastPart, LastBytes);
+               }
+               break;
+
+       case 384:
+       case 512:
+               if (state->unprocessed_bits > 0) {
+                       /* LastBytes = databitlen / 8 */
+                       int LastBytes = (int)databitlen >> 3;
+
+                       ASSERT(state->unprocessed_bits + databitlen <=
+                           EdonR512_BLOCK_SIZE * 8);
+
+                       bcopy(data, hashState512(state)->LastPart
+                           + (state->unprocessed_bits >> 3), LastBytes);
+                       state->unprocessed_bits += (int)databitlen;
+                       databitlen = state->unprocessed_bits;
+                       /* LINTED E_BAD_PTR_CAST_ALIGN */
+                       data64 = (uint64_t *)hashState512(state)->LastPart;
+               } else
+                       /* LINTED E_BAD_PTR_CAST_ALIGN */
+                       data64 = (uint64_t *)data;
+
+               bits_processed = Q512(databitlen, data64,
+                   hashState512(state)->DoublePipe);
+               state->bits_processed += bits_processed;
+               databitlen -= bits_processed;
+               state->unprocessed_bits = (int)databitlen;
+               if (databitlen > 0) {
+                       /* LastBytes = Ceil(databitlen / 8) */
+                       int LastBytes =
+                           ((~(((-(int)databitlen) >> 3) & 0x03ff)) +
+                           1) & 0x03ff;
+
+                       data64 += bits_processed >> 6;  /* byte size update */
+                       bcopy(data64, hashState512(state)->LastPart, LastBytes);
+               }
+               break;
+       }
+}
+
+void
+EdonRFinal(EdonRState *state, uint8_t *hashval)
+{
+       uint32_t *data32;
+       uint64_t *data64, num_bits;
+
+       size_t databitlen;
+       int LastByte, PadOnePosition;
+
+       num_bits = state->bits_processed + state->unprocessed_bits;
+       ASSERT(EDONR_VALID_HASHBITLEN(state->hashbitlen));
+       switch (state->hashbitlen) {
+       case 224:
+       case 256:
+               LastByte = (int)state->unprocessed_bits >> 3;
+               PadOnePosition = 7 - (state->unprocessed_bits & 0x07);
+               hashState256(state)->LastPart[LastByte] =
+                   (hashState256(state)->LastPart[LastByte]
+                   & (0xff << (PadOnePosition + 1))) ^
+                   (0x01 << PadOnePosition);
+               /* LINTED E_BAD_PTR_CAST_ALIGN */
+               data64 = (uint64_t *)hashState256(state)->LastPart;
+
+               if (state->unprocessed_bits < 448) {
+                       (void) memset((hashState256(state)->LastPart) +
+                           LastByte + 1, 0x00,
+                           EdonR256_BLOCK_SIZE - LastByte - 9);
+                       databitlen = EdonR256_BLOCK_SIZE * 8;
+#if defined(MACHINE_IS_BIG_ENDIAN)
+                       st_swap64(num_bits, data64 + 7);
+#else
+                       data64[7] = num_bits;
+#endif
+               } else {
+                       (void) memset((hashState256(state)->LastPart) +
+                           LastByte + 1, 0x00,
+                           EdonR256_BLOCK_SIZE * 2 - LastByte - 9);
+                       databitlen = EdonR256_BLOCK_SIZE * 16;
+#if defined(MACHINE_IS_BIG_ENDIAN)
+                       st_swap64(num_bits, data64 + 15);
+#else
+                       data64[15] = num_bits;
+#endif
+               }
+
+               /* LINTED E_BAD_PTR_CAST_ALIGN */
+               data32 = (uint32_t *)hashState256(state)->LastPart;
+               state->bits_processed += Q256(databitlen, data32,
+                   hashState256(state)->DoublePipe);
+               break;
+
+       case 384:
+       case 512:
+               LastByte = (int)state->unprocessed_bits >> 3;
+               PadOnePosition = 7 - (state->unprocessed_bits & 0x07);
+               hashState512(state)->LastPart[LastByte] =
+                   (hashState512(state)->LastPart[LastByte]
+                   & (0xff << (PadOnePosition + 1))) ^
+                   (0x01 << PadOnePosition);
+               /* LINTED E_BAD_PTR_CAST_ALIGN */
+               data64 = (uint64_t *)hashState512(state)->LastPart;
+
+               if (state->unprocessed_bits < 960) {
+                       (void) memset((hashState512(state)->LastPart) +
+                           LastByte + 1, 0x00,
+                           EdonR512_BLOCK_SIZE - LastByte - 9);
+                       databitlen = EdonR512_BLOCK_SIZE * 8;
+#if defined(MACHINE_IS_BIG_ENDIAN)
+                       st_swap64(num_bits, data64 + 15);
+#else
+                       data64[15] = num_bits;
+#endif
+               } else {
+                       (void) memset((hashState512(state)->LastPart) +
+                           LastByte + 1, 0x00,
+                           EdonR512_BLOCK_SIZE * 2 - LastByte - 9);
+                       databitlen = EdonR512_BLOCK_SIZE * 16;
+#if defined(MACHINE_IS_BIG_ENDIAN)
+                       st_swap64(num_bits, data64 + 31);
+#else
+                       data64[31] = num_bits;
+#endif
+               }
+
+               state->bits_processed += Q512(databitlen, data64,
+                   hashState512(state)->DoublePipe);
+               break;
+       }
+
+       switch (state->hashbitlen) {
+       case 224: {
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               uint32_t *d32 = (uint32_t *)hashval;
+               uint32_t *s32 = hashState224(state)->DoublePipe + 9;
+               int j;
+
+               for (j = 0; j < EdonR224_DIGEST_SIZE >> 2; j++)
+                       st_swap32(s32[j], d32 + j);
+#else
+               bcopy(hashState256(state)->DoublePipe + 9, hashval,
+                   EdonR224_DIGEST_SIZE);
+#endif
+               break;
+       }
+       case 256: {
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               uint32_t *d32 = (uint32_t *)hashval;
+               uint32_t *s32 = hashState224(state)->DoublePipe + 8;
+               int j;
+
+               for (j = 0; j < EdonR256_DIGEST_SIZE >> 2; j++)
+                       st_swap32(s32[j], d32 + j);
+#else
+               bcopy(hashState256(state)->DoublePipe + 8, hashval,
+                   EdonR256_DIGEST_SIZE);
+#endif
+               break;
+       }
+       case 384: {
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               uint64_t *d64 = (uint64_t *)hashval;
+               uint64_t *s64 = hashState384(state)->DoublePipe + 10;
+               int j;
+
+               for (j = 0; j < EdonR384_DIGEST_SIZE >> 3; j++)
+                       st_swap64(s64[j], d64 + j);
+#else
+               bcopy(hashState384(state)->DoublePipe + 10, hashval,
+                   EdonR384_DIGEST_SIZE);
+#endif
+               break;
+       }
+       case 512: {
+#if defined(MACHINE_IS_BIG_ENDIAN)
+               uint64_t *d64 = (uint64_t *)hashval;
+               uint64_t *s64 = hashState512(state)->DoublePipe + 8;
+               int j;
+
+               for (j = 0; j < EdonR512_DIGEST_SIZE >> 3; j++)
+                       st_swap64(s64[j], d64 + j);
+#else
+               bcopy(hashState512(state)->DoublePipe + 8, hashval,
+                   EdonR512_DIGEST_SIZE);
+#endif
+               break;
+       }
+       }
+}
+
+
+void
+EdonRHash(size_t hashbitlen, const uint8_t *data, size_t databitlen,
+    uint8_t *hashval)
+{
+       EdonRState state;
+
+       EdonRInit(&state, hashbitlen);
+       EdonRUpdate(&state, data, databitlen);
+       EdonRFinal(&state, hashval);
+}
+
+#ifdef _KERNEL
+EXPORT_SYMBOL(EdonRInit);
+EXPORT_SYMBOL(EdonRUpdate);
+EXPORT_SYMBOL(EdonRHash);
+EXPORT_SYMBOL(EdonRFinal);
+#endif
diff --git a/zfs/module/icp/algs/edonr/edonr_byteorder.h b/zfs/module/icp/algs/edonr/edonr_byteorder.h
new file mode 100644 (file)
index 0000000..d17e8f1
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * IDI,NTNU
+ *
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 (C) 2009, 2010, Jorn Amundsen <jorn.amundsen@ntnu.no>
+ *
+ * C header file to determine compile machine byte order. Take care when cross
+ * compiling.
+ *
+ * $Id: byteorder.h 517 2013-02-17 20:34:39Z joern $
+ */
+/*
+ * Portions copyright (c) 2013, Saso Kiselkov, All rights reserved
+ */
+
+#ifndef _CRYPTO_EDONR_BYTEORDER_H
+#define        _CRYPTO_EDONR_BYTEORDER_H
+
+
+#include <sys/param.h>
+
+#if defined(__BYTE_ORDER)
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+#define        MACHINE_IS_BIG_ENDIAN
+#elif (__BYTE_ORDER == __LITTLE_ENDIAN)
+#define        MACHINE_IS_LITTLE_ENDIAN
+#endif
+#elif defined(BYTE_ORDER)
+#if (BYTE_ORDER == BIG_ENDIAN)
+#define        MACHINE_IS_BIG_ENDIAN
+#elif (BYTE_ORDER == LITTLE_ENDIAN)
+#define        MACHINE_IS_LITTLE_ENDIAN
+#endif
+#endif /* __BYTE_ORDER || BYTE_ORDER */
+
+#if !defined(MACHINE_IS_BIG_ENDIAN) && !defined(MACHINE_IS_LITTLE_ENDIAN)
+#if defined(_BIG_ENDIAN) || defined(_MIPSEB)
+#define        MACHINE_IS_BIG_ENDIAN
+#endif
+#if defined(_LITTLE_ENDIAN) || defined(_MIPSEL)
+#define        MACHINE_IS_LITTLE_ENDIAN
+#endif
+#endif /* !MACHINE_IS_BIG_ENDIAN && !MACHINE_IS_LITTLE_ENDIAN */
+
+#if !defined(MACHINE_IS_BIG_ENDIAN) && !defined(MACHINE_IS_LITTLE_ENDIAN)
+#error unknown machine byte sex
+#endif
+
+#define        BYTEORDER_INCLUDED
+
+#if defined(MACHINE_IS_BIG_ENDIAN)
+/*
+ * Byte swapping macros for big endian architectures and compilers,
+ * add as appropriate for other architectures and/or compilers.
+ *
+ *     ld_swap64(src,dst) : uint64_t dst = *(src)
+ *     st_swap64(src,dst) : *(dst)       = uint64_t src
+ */
+
+#if defined(__PPC__) || defined(_ARCH_PPC)
+
+#if defined(__64BIT__)
+#if defined(_ARCH_PWR7)
+#define        aix_ld_swap64(s64, d64)\
+       __asm__("ldbrx %0,0,%1" : "=r"(d64) : "r"(s64))
+#define        aix_st_swap64(s64, d64)\
+       __asm__ volatile("stdbrx %1,0,%0" : : "r"(d64), "r"(s64))
+#else
+#define        aix_ld_swap64(s64, d64)                                         \
+{                                                                      \
+       uint64_t *s4 = 0, h; /* initialize to zero for gcc warning */   \
+                                                                       \
+       __asm__("addi %0,%3,4;lwbrx %1,0,%3;lwbrx %2,0,%0;rldimi %1,%2,32,0"\
+               : "+r"(s4), "=r"(d64), "=r"(h) : "b"(s64));             \
+}
+
+#define        aix_st_swap64(s64, d64)                                         \
+{                                                                      \
+       uint64_t *s4 = 0, h; /* initialize to zero for gcc warning */   \
+       h = (s64) >> 32;                                                \
+       __asm__ volatile("addi %0,%3,4;stwbrx %1,0,%3;stwbrx %2,0,%0"   \
+               : "+r"(s4) : "r"(s64), "r"(h), "b"(d64));               \
+}
+#endif /* 64BIT && PWR7 */
+#else
+#define        aix_ld_swap64(s64, d64)                                         \
+{                                                                      \
+       uint32_t *s4 = 0, h, l; /* initialize to zero for gcc warning */\
+       __asm__("addi %0,%3,4;lwbrx %1,0,%3;lwbrx %2,0,%0"              \
+               : "+r"(s4), "=r"(l), "=r"(h) : "b"(s64));               \
+       d64 = ((uint64_t)h<<32) | l;                                    \
+}
+
+#define        aix_st_swap64(s64, d64)                                         \
+{                                                                      \
+       uint32_t *s4 = 0, h, l; /* initialize to zero for gcc warning */\
+       l = (s64) & 0xfffffffful, h = (s64) >> 32;                      \
+       __asm__ volatile("addi %0,%3,4;stwbrx %1,0,%3;stwbrx %2,0,%0"   \
+               : "+r"(s4) : "r"(l), "r"(h), "b"(d64));                 \
+}
+#endif /* __64BIT__ */
+#define        aix_ld_swap32(s32, d32)\
+       __asm__("lwbrx %0,0,%1" : "=r"(d32) : "r"(s32))
+#define        aix_st_swap32(s32, d32)\
+       __asm__ volatile("stwbrx %1,0,%0" : : "r"(d32), "r"(s32))
+#define        ld_swap32(s, d) aix_ld_swap32(s, d)
+#define        st_swap32(s, d) aix_st_swap32(s, d)
+#define        ld_swap64(s, d) aix_ld_swap64(s, d)
+#define        st_swap64(s, d) aix_st_swap64(s, d)
+#endif /* __PPC__ || _ARCH_PPC */
+
+#if defined(__sparc)
+#if !defined(__arch64__) && !defined(__sparcv8) && defined(__sparcv9)
+#define        __arch64__
+#endif
+#if defined(__GNUC__) || (defined(__SUNPRO_C) && __SUNPRO_C > 0x590)
+/* need Sun Studio C 5.10 and above for GNU inline assembly */
+#if defined(__arch64__)
+#define        sparc_ld_swap64(s64, d64)                                       \
+       __asm__("ldxa [%1]0x88,%0" : "=r"(d64) : "r"(s64))
+#define        sparc_st_swap64(s64, d64)                                       \
+       __asm__ volatile("stxa %0,[%1]0x88" : : "r"(s64), "r"(d64))
+#define        st_swap64(s, d) sparc_st_swap64(s, d)
+#else
+#define        sparc_ld_swap64(s64, d64)                                       \
+{                                                                      \
+       uint32_t *s4, h, l;                                             \
+       __asm__("add %3,4,%0\n\tlda [%3]0x88,%1\n\tlda [%0]0x88,%2"     \
+               : "+r"(s4), "=r"(l), "=r"(h) : "r"(s64));               \
+       d64 = ((uint64_t)h<<32) | l;                                    \
+}
+#define        sparc_st_swap64(s64, d64)                                       \
+{                                                                      \
+       uint32_t *s4, h, l;                                             \
+       l = (s64) & 0xfffffffful, h = (s64) >> 32;                      \
+       __asm__ volatile("add %3,4,%0\n\tsta %1,[%3]0x88\n\tsta %2,[%0]0x88"\
+               : "+r"(s4) : "r"(l), "r"(h), "r"(d64));                 \
+}
+#endif /* sparc64 */
+#define        sparc_ld_swap32(s32, d32)\
+       __asm__("lda [%1]0x88,%0" : "=r"(d32) : "r"(s32))
+#define        sparc_st_swap32(s32, d32)\
+       __asm__ volatile("sta %0,[%1]0x88" : : "r"(s32), "r"(d32))
+#define        ld_swap32(s, d) sparc_ld_swap32(s, d)
+#define        st_swap32(s, d) sparc_st_swap32(s, d)
+#define        ld_swap64(s, d) sparc_ld_swap64(s, d)
+#define        st_swap64(s, d) sparc_st_swap64(s, d)
+#endif /* GCC || Sun Studio C > 5.9 */
+#endif /* sparc */
+
+/* GCC fallback */
+#if ((__GNUC__ >= 4) || defined(__PGIC__)) && !defined(ld_swap32)
+#define        ld_swap32(s, d) (d = __builtin_bswap32(*(s)))
+#define        st_swap32(s, d) (*(d) = __builtin_bswap32(s))
+#endif /* GCC4/PGIC && !swap32 */
+#if ((__GNUC__ >= 4) || defined(__PGIC__)) && !defined(ld_swap64)
+#define        ld_swap64(s, d) (d = __builtin_bswap64(*(s)))
+#define        st_swap64(s, d) (*(d) = __builtin_bswap64(s))
+#endif /* GCC4/PGIC && !swap64 */
+
+/* generic fallback */
+#if !defined(ld_swap32)
+#define        ld_swap32(s, d)                                                 \
+       (d = (*(s) >> 24) | (*(s) >> 8 & 0xff00) |                      \
+       (*(s) << 8 & 0xff0000) | (*(s) << 24))
+#define        st_swap32(s, d)                                                 \
+       (*(d) = ((s) >> 24) | ((s) >> 8 & 0xff00) |                     \
+       ((s) << 8 & 0xff0000) | ((s) << 24))
+#endif
+#if !defined(ld_swap64)
+#define        ld_swap64(s, d)                                                 \
+       (d = (*(s) >> 56) | (*(s) >> 40 & 0xff00) |                     \
+       (*(s) >> 24 & 0xff0000) | (*(s) >> 8 & 0xff000000) |            \
+       (*(s) & 0xff000000) << 8 | (*(s) & 0xff0000) << 24 |            \
+       (*(s) & 0xff00) << 40 | *(s) << 56)
+#define        st_swap64(s, d)                                                 \
+       (*(d) = ((s) >> 56) | ((s) >> 40 & 0xff00) |                    \
+       ((s) >> 24 & 0xff0000) | ((s) >> 8 & 0xff000000) |              \
+       ((s) & 0xff000000) << 8 | ((s) & 0xff0000) << 24 |              \
+       ((s) & 0xff00) << 40 | (s) << 56)
+#endif
+
+#endif /* MACHINE_IS_BIG_ENDIAN */
+
+
+#if defined(MACHINE_IS_LITTLE_ENDIAN)
+/* replace swaps with simple assignments on little endian systems */
+#undef ld_swap32
+#undef st_swap32
+#define        ld_swap32(s, d) (d = *(s))
+#define        st_swap32(s, d) (*(d) = s)
+#undef ld_swap64
+#undef st_swap64
+#define        ld_swap64(s, d) (d = *(s))
+#define        st_swap64(s, d) (*(d) = s)
+#endif /* MACHINE_IS_LITTLE_ENDIAN */
+
+#endif /* _CRYPTO_EDONR_BYTEORDER_H */
diff --git a/zfs/module/icp/algs/modes/cbc.c b/zfs/module/icp/algs/modes/cbc.c
new file mode 100644 (file)
index 0000000..2cc94ec
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <modes/modes.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+
+/*
+ * Algorithm independent CBC functions.
+ */
+int
+cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
+    crypto_data_t *out, size_t block_size,
+    int (*encrypt)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t remainder = length;
+       size_t need = 0;
+       uint8_t *datap = (uint8_t *)data;
+       uint8_t *blockp;
+       uint8_t *lastp;
+       void *iov_or_mp;
+       offset_t offset;
+       uint8_t *out_data_1;
+       uint8_t *out_data_2;
+       size_t out_data_1_len;
+
+       if (length + ctx->cbc_remainder_len < block_size) {
+               /* accumulate bytes here and return */
+               bcopy(datap,
+                   (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
+                   length);
+               ctx->cbc_remainder_len += length;
+               ctx->cbc_copy_to = datap;
+               return (CRYPTO_SUCCESS);
+       }
+
+       lastp = (uint8_t *)ctx->cbc_iv;
+       if (out != NULL)
+               crypto_init_ptrs(out, &iov_or_mp, &offset);
+
+       do {
+               /* Unprocessed data from last call. */
+               if (ctx->cbc_remainder_len > 0) {
+                       need = block_size - ctx->cbc_remainder_len;
+
+                       if (need > remainder)
+                               return (CRYPTO_DATA_LEN_RANGE);
+
+                       bcopy(datap, &((uint8_t *)ctx->cbc_remainder)
+                           [ctx->cbc_remainder_len], need);
+
+                       blockp = (uint8_t *)ctx->cbc_remainder;
+               } else {
+                       blockp = datap;
+               }
+
+               if (out == NULL) {
+                       /*
+                        * XOR the previous cipher block or IV with the
+                        * current clear block.
+                        */
+                       xor_block(lastp, blockp);
+                       encrypt(ctx->cbc_keysched, blockp, blockp);
+
+                       ctx->cbc_lastp = blockp;
+                       lastp = blockp;
+
+                       if (ctx->cbc_remainder_len > 0) {
+                               bcopy(blockp, ctx->cbc_copy_to,
+                                   ctx->cbc_remainder_len);
+                               bcopy(blockp + ctx->cbc_remainder_len, datap,
+                                   need);
+                       }
+               } else {
+                       /*
+                        * XOR the previous cipher block or IV with the
+                        * current clear block.
+                        */
+                       xor_block(blockp, lastp);
+                       encrypt(ctx->cbc_keysched, lastp, lastp);
+                       crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
+                           &out_data_1_len, &out_data_2, block_size);
+
+                       /* copy block to where it belongs */
+                       if (out_data_1_len == block_size) {
+                               copy_block(lastp, out_data_1);
+                       } else {
+                               bcopy(lastp, out_data_1, out_data_1_len);
+                               if (out_data_2 != NULL) {
+                                       bcopy(lastp + out_data_1_len,
+                                           out_data_2,
+                                           block_size - out_data_1_len);
+                               }
+                       }
+                       /* update offset */
+                       out->cd_offset += block_size;
+               }
+
+               /* Update pointer to next block of data to be processed. */
+               if (ctx->cbc_remainder_len != 0) {
+                       datap += need;
+                       ctx->cbc_remainder_len = 0;
+               } else {
+                       datap += block_size;
+               }
+
+               remainder = (size_t)&data[length] - (size_t)datap;
+
+               /* Incomplete last block. */
+               if (remainder > 0 && remainder < block_size) {
+                       bcopy(datap, ctx->cbc_remainder, remainder);
+                       ctx->cbc_remainder_len = remainder;
+                       ctx->cbc_copy_to = datap;
+                       goto out;
+               }
+               ctx->cbc_copy_to = NULL;
+
+       } while (remainder > 0);
+
+out:
+       /*
+        * Save the last encrypted block in the context.
+        */
+       if (ctx->cbc_lastp != NULL) {
+               copy_block((uint8_t *)ctx->cbc_lastp, (uint8_t *)ctx->cbc_iv);
+               ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv;
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+#define        OTHER(a, ctx) \
+       (((a) == (ctx)->cbc_lastblock) ? (ctx)->cbc_iv : (ctx)->cbc_lastblock)
+
+/* ARGSUSED */
+int
+cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length,
+    crypto_data_t *out, size_t block_size,
+    int (*decrypt)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t remainder = length;
+       size_t need = 0;
+       uint8_t *datap = (uint8_t *)data;
+       uint8_t *blockp;
+       uint8_t *lastp;
+       void *iov_or_mp;
+       offset_t offset;
+       uint8_t *out_data_1;
+       uint8_t *out_data_2;
+       size_t out_data_1_len;
+
+       if (length + ctx->cbc_remainder_len < block_size) {
+               /* accumulate bytes here and return */
+               bcopy(datap,
+                   (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len,
+                   length);
+               ctx->cbc_remainder_len += length;
+               ctx->cbc_copy_to = datap;
+               return (CRYPTO_SUCCESS);
+       }
+
+       lastp = ctx->cbc_lastp;
+       if (out != NULL)
+               crypto_init_ptrs(out, &iov_or_mp, &offset);
+
+       do {
+               /* Unprocessed data from last call. */
+               if (ctx->cbc_remainder_len > 0) {
+                       need = block_size - ctx->cbc_remainder_len;
+
+                       if (need > remainder)
+                               return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
+
+                       bcopy(datap, &((uint8_t *)ctx->cbc_remainder)
+                           [ctx->cbc_remainder_len], need);
+
+                       blockp = (uint8_t *)ctx->cbc_remainder;
+               } else {
+                       blockp = datap;
+               }
+
+               /* LINTED: pointer alignment */
+               copy_block(blockp, (uint8_t *)OTHER((uint64_t *)lastp, ctx));
+
+               if (out != NULL) {
+                       decrypt(ctx->cbc_keysched, blockp,
+                           (uint8_t *)ctx->cbc_remainder);
+                       blockp = (uint8_t *)ctx->cbc_remainder;
+               } else {
+                       decrypt(ctx->cbc_keysched, blockp, blockp);
+               }
+
+               /*
+                * XOR the previous cipher block or IV with the
+                * currently decrypted block.
+                */
+               xor_block(lastp, blockp);
+
+               /* LINTED: pointer alignment */
+               lastp = (uint8_t *)OTHER((uint64_t *)lastp, ctx);
+
+               if (out != NULL) {
+                       crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
+                           &out_data_1_len, &out_data_2, block_size);
+
+                       bcopy(blockp, out_data_1, out_data_1_len);
+                       if (out_data_2 != NULL) {
+                               bcopy(blockp + out_data_1_len, out_data_2,
+                                   block_size - out_data_1_len);
+                       }
+
+                       /* update offset */
+                       out->cd_offset += block_size;
+
+               } else if (ctx->cbc_remainder_len > 0) {
+                       /* copy temporary block to where it belongs */
+                       bcopy(blockp, ctx->cbc_copy_to, ctx->cbc_remainder_len);
+                       bcopy(blockp + ctx->cbc_remainder_len, datap, need);
+               }
+
+               /* Update pointer to next block of data to be processed. */
+               if (ctx->cbc_remainder_len != 0) {
+                       datap += need;
+                       ctx->cbc_remainder_len = 0;
+               } else {
+                       datap += block_size;
+               }
+
+               remainder = (size_t)&data[length] - (size_t)datap;
+
+               /* Incomplete last block. */
+               if (remainder > 0 && remainder < block_size) {
+                       bcopy(datap, ctx->cbc_remainder, remainder);
+                       ctx->cbc_remainder_len = remainder;
+                       ctx->cbc_lastp = lastp;
+                       ctx->cbc_copy_to = datap;
+                       return (CRYPTO_SUCCESS);
+               }
+               ctx->cbc_copy_to = NULL;
+
+       } while (remainder > 0);
+
+       ctx->cbc_lastp = lastp;
+       return (CRYPTO_SUCCESS);
+}
+
+int
+cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len,
+    size_t block_size, void (*copy_block)(uint8_t *, uint64_t *))
+{
+       /*
+        * Copy IV into context.
+        *
+        * If cm_param == NULL then the IV comes from the
+        * cd_miscdata field in the crypto_data structure.
+        */
+       if (param != NULL) {
+               ASSERT(param_len == block_size);
+               copy_block((uchar_t *)param, cbc_ctx->cbc_iv);
+       }
+
+       cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0];
+       cbc_ctx->cbc_flags |= CBC_MODE;
+       return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+void *
+cbc_alloc_ctx(int kmflag)
+{
+       cbc_ctx_t *cbc_ctx;
+
+       if ((cbc_ctx = kmem_zalloc(sizeof (cbc_ctx_t), kmflag)) == NULL)
+               return (NULL);
+
+       cbc_ctx->cbc_flags = CBC_MODE;
+       return (cbc_ctx);
+}
diff --git a/zfs/module/icp/algs/modes/ccm.c b/zfs/module/icp/algs/modes/ccm.c
new file mode 100644 (file)
index 0000000..22aeb0a
--- /dev/null
@@ -0,0 +1,920 @@
+/*
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <modes/modes.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+
+#if defined(__i386) || defined(__amd64)
+#include <sys/byteorder.h>
+#define        UNALIGNED_POINTERS_PERMITTED
+#endif
+
+/*
+ * Encrypt multiple blocks of data in CCM mode.  Decrypt for CCM mode
+ * is done in another function.
+ */
+int
+ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length,
+    crypto_data_t *out, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t remainder = length;
+       size_t need = 0;
+       uint8_t *datap = (uint8_t *)data;
+       uint8_t *blockp;
+       uint8_t *lastp;
+       void *iov_or_mp;
+       offset_t offset;
+       uint8_t *out_data_1;
+       uint8_t *out_data_2;
+       size_t out_data_1_len;
+       uint64_t counter;
+       uint8_t *mac_buf;
+
+       if (length + ctx->ccm_remainder_len < block_size) {
+               /* accumulate bytes here and return */
+               bcopy(datap,
+                   (uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len,
+                   length);
+               ctx->ccm_remainder_len += length;
+               ctx->ccm_copy_to = datap;
+               return (CRYPTO_SUCCESS);
+       }
+
+       lastp = (uint8_t *)ctx->ccm_cb;
+       if (out != NULL)
+               crypto_init_ptrs(out, &iov_or_mp, &offset);
+
+       mac_buf = (uint8_t *)ctx->ccm_mac_buf;
+
+       do {
+               /* Unprocessed data from last call. */
+               if (ctx->ccm_remainder_len > 0) {
+                       need = block_size - ctx->ccm_remainder_len;
+
+                       if (need > remainder)
+                               return (CRYPTO_DATA_LEN_RANGE);
+
+                       bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
+                           [ctx->ccm_remainder_len], need);
+
+                       blockp = (uint8_t *)ctx->ccm_remainder;
+               } else {
+                       blockp = datap;
+               }
+
+               /*
+                * do CBC MAC
+                *
+                * XOR the previous cipher block current clear block.
+                * mac_buf always contain previous cipher block.
+                */
+               xor_block(blockp, mac_buf);
+               encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
+
+               /* ccm_cb is the counter block */
+               encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb,
+                   (uint8_t *)ctx->ccm_tmp);
+
+               lastp = (uint8_t *)ctx->ccm_tmp;
+
+               /*
+                * Increment counter. Counter bits are confined
+                * to the bottom 64 bits of the counter block.
+                */
+#ifdef _LITTLE_ENDIAN
+               counter = ntohll(ctx->ccm_cb[1] & ctx->ccm_counter_mask);
+               counter = htonll(counter + 1);
+#else
+               counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask;
+               counter++;
+#endif /* _LITTLE_ENDIAN */
+               counter &= ctx->ccm_counter_mask;
+               ctx->ccm_cb[1] =
+                   (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
+
+               /*
+                * XOR encrypted counter block with the current clear block.
+                */
+               xor_block(blockp, lastp);
+
+               ctx->ccm_processed_data_len += block_size;
+
+               if (out == NULL) {
+                       if (ctx->ccm_remainder_len > 0) {
+                               bcopy(blockp, ctx->ccm_copy_to,
+                                   ctx->ccm_remainder_len);
+                               bcopy(blockp + ctx->ccm_remainder_len, datap,
+                                   need);
+                       }
+               } else {
+                       crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
+                           &out_data_1_len, &out_data_2, block_size);
+
+                       /* copy block to where it belongs */
+                       if (out_data_1_len == block_size) {
+                               copy_block(lastp, out_data_1);
+                       } else {
+                               bcopy(lastp, out_data_1, out_data_1_len);
+                               if (out_data_2 != NULL) {
+                                       bcopy(lastp + out_data_1_len,
+                                           out_data_2,
+                                           block_size - out_data_1_len);
+                               }
+                       }
+                       /* update offset */
+                       out->cd_offset += block_size;
+               }
+
+               /* Update pointer to next block of data to be processed. */
+               if (ctx->ccm_remainder_len != 0) {
+                       datap += need;
+                       ctx->ccm_remainder_len = 0;
+               } else {
+                       datap += block_size;
+               }
+
+               remainder = (size_t)&data[length] - (size_t)datap;
+
+               /* Incomplete last block. */
+               if (remainder > 0 && remainder < block_size) {
+                       bcopy(datap, ctx->ccm_remainder, remainder);
+                       ctx->ccm_remainder_len = remainder;
+                       ctx->ccm_copy_to = datap;
+                       goto out;
+               }
+               ctx->ccm_copy_to = NULL;
+
+       } while (remainder > 0);
+
+out:
+       return (CRYPTO_SUCCESS);
+}
+
+void
+calculate_ccm_mac(ccm_ctx_t *ctx, uint8_t *ccm_mac,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
+{
+       uint64_t counter;
+       uint8_t *counterp, *mac_buf;
+       int i;
+
+       mac_buf = (uint8_t *)ctx->ccm_mac_buf;
+
+       /* first counter block start with index 0 */
+       counter = 0;
+       ctx->ccm_cb[1] = (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
+
+       counterp = (uint8_t *)ctx->ccm_tmp;
+       encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp);
+
+       /* calculate XOR of MAC with first counter block */
+       for (i = 0; i < ctx->ccm_mac_len; i++) {
+               ccm_mac[i] = mac_buf[i] ^ counterp[i];
+       }
+}
+
+/* ARGSUSED */
+int
+ccm_encrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       uint8_t *lastp, *mac_buf, *ccm_mac_p, *macp = NULL;
+       void *iov_or_mp;
+       offset_t offset;
+       uint8_t *out_data_1;
+       uint8_t *out_data_2;
+       size_t out_data_1_len;
+       int i;
+
+       if (out->cd_length < (ctx->ccm_remainder_len + ctx->ccm_mac_len)) {
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       /*
+        * When we get here, the number of bytes of payload processed
+        * plus whatever data remains, if any,
+        * should be the same as the number of bytes that's being
+        * passed in the argument during init time.
+        */
+       if ((ctx->ccm_processed_data_len + ctx->ccm_remainder_len)
+           != (ctx->ccm_data_len)) {
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       mac_buf = (uint8_t *)ctx->ccm_mac_buf;
+
+       if (ctx->ccm_remainder_len > 0) {
+
+               /* ccm_mac_input_buf is not used for encryption */
+               macp = (uint8_t *)ctx->ccm_mac_input_buf;
+               bzero(macp, block_size);
+
+               /* copy remainder to temporary buffer */
+               bcopy(ctx->ccm_remainder, macp, ctx->ccm_remainder_len);
+
+               /* calculate the CBC MAC */
+               xor_block(macp, mac_buf);
+               encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
+
+               /* calculate the counter mode */
+               lastp = (uint8_t *)ctx->ccm_tmp;
+               encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, lastp);
+
+               /* XOR with counter block */
+               for (i = 0; i < ctx->ccm_remainder_len; i++) {
+                       macp[i] ^= lastp[i];
+               }
+               ctx->ccm_processed_data_len += ctx->ccm_remainder_len;
+       }
+
+       /* Calculate the CCM MAC */
+       ccm_mac_p = (uint8_t *)ctx->ccm_tmp;
+       calculate_ccm_mac(ctx, ccm_mac_p, encrypt_block);
+
+       crypto_init_ptrs(out, &iov_or_mp, &offset);
+       crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
+           &out_data_1_len, &out_data_2,
+           ctx->ccm_remainder_len + ctx->ccm_mac_len);
+
+       if (ctx->ccm_remainder_len > 0) {
+
+               /* copy temporary block to where it belongs */
+               if (out_data_2 == NULL) {
+                       /* everything will fit in out_data_1 */
+                       bcopy(macp, out_data_1, ctx->ccm_remainder_len);
+                       bcopy(ccm_mac_p, out_data_1 + ctx->ccm_remainder_len,
+                           ctx->ccm_mac_len);
+               } else {
+
+                       if (out_data_1_len < ctx->ccm_remainder_len) {
+
+                               size_t data_2_len_used;
+
+                               bcopy(macp, out_data_1, out_data_1_len);
+
+                               data_2_len_used = ctx->ccm_remainder_len
+                                   - out_data_1_len;
+
+                               bcopy((uint8_t *)macp + out_data_1_len,
+                                   out_data_2, data_2_len_used);
+                               bcopy(ccm_mac_p, out_data_2 + data_2_len_used,
+                                   ctx->ccm_mac_len);
+                       } else {
+                               bcopy(macp, out_data_1, out_data_1_len);
+                               if (out_data_1_len == ctx->ccm_remainder_len) {
+                                       /* mac will be in out_data_2 */
+                                       bcopy(ccm_mac_p, out_data_2,
+                                           ctx->ccm_mac_len);
+                               } else {
+                                       size_t len_not_used = out_data_1_len -
+                                           ctx->ccm_remainder_len;
+                                       /*
+                                        * part of mac in will be in
+                                        * out_data_1, part of the mac will be
+                                        * in out_data_2
+                                        */
+                                       bcopy(ccm_mac_p,
+                                           out_data_1 + ctx->ccm_remainder_len,
+                                           len_not_used);
+                                       bcopy(ccm_mac_p + len_not_used,
+                                           out_data_2,
+                                           ctx->ccm_mac_len - len_not_used);
+
+                               }
+                       }
+               }
+       } else {
+               /* copy block to where it belongs */
+               bcopy(ccm_mac_p, out_data_1, out_data_1_len);
+               if (out_data_2 != NULL) {
+                       bcopy(ccm_mac_p + out_data_1_len, out_data_2,
+                           block_size - out_data_1_len);
+               }
+       }
+       out->cd_offset += ctx->ccm_remainder_len + ctx->ccm_mac_len;
+       ctx->ccm_remainder_len = 0;
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * This will only deal with decrypting the last block of the input that
+ * might not be a multiple of block length.
+ */
+void
+ccm_decrypt_incomplete_block(ccm_ctx_t *ctx,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
+{
+       uint8_t *datap, *outp, *counterp;
+       int i;
+
+       datap = (uint8_t *)ctx->ccm_remainder;
+       outp = &((ctx->ccm_pt_buf)[ctx->ccm_processed_data_len]);
+
+       counterp = (uint8_t *)ctx->ccm_tmp;
+       encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp);
+
+       /* XOR with counter block */
+       for (i = 0; i < ctx->ccm_remainder_len; i++) {
+               outp[i] = datap[i] ^ counterp[i];
+       }
+}
+
+/*
+ * This will decrypt the cipher text.  However, the plaintext won't be
+ * returned to the caller.  It will be returned when decrypt_final() is
+ * called if the MAC matches
+ */
+/* ARGSUSED */
+int
+ccm_mode_decrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length,
+    crypto_data_t *out, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t remainder = length;
+       size_t need = 0;
+       uint8_t *datap = (uint8_t *)data;
+       uint8_t *blockp;
+       uint8_t *cbp;
+       uint64_t counter;
+       size_t pt_len, total_decrypted_len, mac_len, pm_len, pd_len;
+       uint8_t *resultp;
+
+
+       pm_len = ctx->ccm_processed_mac_len;
+
+       if (pm_len > 0) {
+               uint8_t *tmp;
+               /*
+                * all ciphertext has been processed, just waiting for
+                * part of the value of the mac
+                */
+               if ((pm_len + length) > ctx->ccm_mac_len) {
+                       return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
+               }
+               tmp = (uint8_t *)ctx->ccm_mac_input_buf;
+
+               bcopy(datap, tmp + pm_len, length);
+
+               ctx->ccm_processed_mac_len += length;
+               return (CRYPTO_SUCCESS);
+       }
+
+       /*
+        * If we decrypt the given data, what total amount of data would
+        * have been decrypted?
+        */
+       pd_len = ctx->ccm_processed_data_len;
+       total_decrypted_len = pd_len + length + ctx->ccm_remainder_len;
+
+       if (total_decrypted_len >
+           (ctx->ccm_data_len + ctx->ccm_mac_len)) {
+               return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
+       }
+
+       pt_len = ctx->ccm_data_len;
+
+       if (total_decrypted_len > pt_len) {
+               /*
+                * part of the input will be the MAC, need to isolate that
+                * to be dealt with later.  The left-over data in
+                * ccm_remainder_len from last time will not be part of the
+                * MAC.  Otherwise, it would have already been taken out
+                * when this call is made last time.
+                */
+               size_t pt_part = pt_len - pd_len - ctx->ccm_remainder_len;
+
+               mac_len = length - pt_part;
+
+               ctx->ccm_processed_mac_len = mac_len;
+               bcopy(data + pt_part, ctx->ccm_mac_input_buf, mac_len);
+
+               if (pt_part + ctx->ccm_remainder_len < block_size) {
+                       /*
+                        * since this is last of the ciphertext, will
+                        * just decrypt with it here
+                        */
+                       bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
+                           [ctx->ccm_remainder_len], pt_part);
+                       ctx->ccm_remainder_len += pt_part;
+                       ccm_decrypt_incomplete_block(ctx, encrypt_block);
+                       ctx->ccm_processed_data_len += ctx->ccm_remainder_len;
+                       ctx->ccm_remainder_len = 0;
+                       return (CRYPTO_SUCCESS);
+               } else {
+                       /* let rest of the code handle this */
+                       length = pt_part;
+               }
+       } else if (length + ctx->ccm_remainder_len < block_size) {
+                       /* accumulate bytes here and return */
+               bcopy(datap,
+                   (uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len,
+                   length);
+               ctx->ccm_remainder_len += length;
+               ctx->ccm_copy_to = datap;
+               return (CRYPTO_SUCCESS);
+       }
+
+       do {
+               /* Unprocessed data from last call. */
+               if (ctx->ccm_remainder_len > 0) {
+                       need = block_size - ctx->ccm_remainder_len;
+
+                       if (need > remainder)
+                               return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
+
+                       bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
+                           [ctx->ccm_remainder_len], need);
+
+                       blockp = (uint8_t *)ctx->ccm_remainder;
+               } else {
+                       blockp = datap;
+               }
+
+               /* Calculate the counter mode, ccm_cb is the counter block */
+               cbp = (uint8_t *)ctx->ccm_tmp;
+               encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, cbp);
+
+               /*
+                * Increment counter.
+                * Counter bits are confined to the bottom 64 bits
+                */
+#ifdef _LITTLE_ENDIAN
+               counter = ntohll(ctx->ccm_cb[1] & ctx->ccm_counter_mask);
+               counter = htonll(counter + 1);
+#else
+               counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask;
+               counter++;
+#endif /* _LITTLE_ENDIAN */
+               counter &= ctx->ccm_counter_mask;
+               ctx->ccm_cb[1] =
+                   (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
+
+               /* XOR with the ciphertext */
+               xor_block(blockp, cbp);
+
+               /* Copy the plaintext to the "holding buffer" */
+               resultp = (uint8_t *)ctx->ccm_pt_buf +
+                   ctx->ccm_processed_data_len;
+               copy_block(cbp, resultp);
+
+               ctx->ccm_processed_data_len += block_size;
+
+               ctx->ccm_lastp = blockp;
+
+               /* Update pointer to next block of data to be processed. */
+               if (ctx->ccm_remainder_len != 0) {
+                       datap += need;
+                       ctx->ccm_remainder_len = 0;
+               } else {
+                       datap += block_size;
+               }
+
+               remainder = (size_t)&data[length] - (size_t)datap;
+
+               /* Incomplete last block */
+               if (remainder > 0 && remainder < block_size) {
+                       bcopy(datap, ctx->ccm_remainder, remainder);
+                       ctx->ccm_remainder_len = remainder;
+                       ctx->ccm_copy_to = datap;
+                       if (ctx->ccm_processed_mac_len > 0) {
+                               /*
+                                * not expecting anymore ciphertext, just
+                                * compute plaintext for the remaining input
+                                */
+                               ccm_decrypt_incomplete_block(ctx,
+                                   encrypt_block);
+                               ctx->ccm_processed_data_len += remainder;
+                               ctx->ccm_remainder_len = 0;
+                       }
+                       goto out;
+               }
+               ctx->ccm_copy_to = NULL;
+
+       } while (remainder > 0);
+
+out:
+       return (CRYPTO_SUCCESS);
+}
+
+int
+ccm_decrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t mac_remain, pt_len;
+       uint8_t *pt, *mac_buf, *macp, *ccm_mac_p;
+       int rv;
+
+       pt_len = ctx->ccm_data_len;
+
+       /* Make sure output buffer can fit all of the plaintext */
+       if (out->cd_length < pt_len) {
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       pt = ctx->ccm_pt_buf;
+       mac_remain = ctx->ccm_processed_data_len;
+       mac_buf = (uint8_t *)ctx->ccm_mac_buf;
+
+       macp = (uint8_t *)ctx->ccm_tmp;
+
+       while (mac_remain > 0) {
+
+               if (mac_remain < block_size) {
+                       bzero(macp, block_size);
+                       bcopy(pt, macp, mac_remain);
+                       mac_remain = 0;
+               } else {
+                       copy_block(pt, macp);
+                       mac_remain -= block_size;
+                       pt += block_size;
+               }
+
+               /* calculate the CBC MAC */
+               xor_block(macp, mac_buf);
+               encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
+       }
+
+       /* Calculate the CCM MAC */
+       ccm_mac_p = (uint8_t *)ctx->ccm_tmp;
+       calculate_ccm_mac((ccm_ctx_t *)ctx, ccm_mac_p, encrypt_block);
+
+       /* compare the input CCM MAC value with what we calculated */
+       if (bcmp(ctx->ccm_mac_input_buf, ccm_mac_p, ctx->ccm_mac_len)) {
+               /* They don't match */
+               return (CRYPTO_INVALID_MAC);
+       } else {
+               rv = crypto_put_output_data(ctx->ccm_pt_buf, out, pt_len);
+               if (rv != CRYPTO_SUCCESS)
+                       return (rv);
+               out->cd_offset += pt_len;
+       }
+       return (CRYPTO_SUCCESS);
+}
+
+int
+ccm_validate_args(CK_AES_CCM_PARAMS *ccm_param, boolean_t is_encrypt_init)
+{
+       size_t macSize, nonceSize;
+       uint8_t q;
+       uint64_t maxValue;
+
+       /*
+        * Check the length of the MAC.  The only valid
+        * lengths for the MAC are: 4, 6, 8, 10, 12, 14, 16
+        */
+       macSize = ccm_param->ulMACSize;
+       if ((macSize < 4) || (macSize > 16) || ((macSize % 2) != 0)) {
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+       }
+
+       /* Check the nonce length.  Valid values are 7, 8, 9, 10, 11, 12, 13 */
+       nonceSize = ccm_param->ulNonceSize;
+       if ((nonceSize < 7) || (nonceSize > 13)) {
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+       }
+
+       /* q is the length of the field storing the length, in bytes */
+       q = (uint8_t)((15 - nonceSize) & 0xFF);
+
+
+       /*
+        * If it is decrypt, need to make sure size of ciphertext is at least
+        * bigger than MAC len
+        */
+       if ((!is_encrypt_init) && (ccm_param->ulDataSize < macSize)) {
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+       }
+
+       /*
+        * Check to make sure the length of the payload is within the
+        * range of values allowed by q
+        */
+       if (q < 8) {
+               maxValue = (1ULL << (q * 8)) - 1;
+       } else {
+               maxValue = ULONG_MAX;
+       }
+
+       if (ccm_param->ulDataSize > maxValue) {
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+       }
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Format the first block used in CBC-MAC (B0) and the initial counter
+ * block based on formatting functions and counter generation functions
+ * specified in RFC 3610 and NIST publication 800-38C, appendix A
+ *
+ * b0 is the first block used in CBC-MAC
+ * cb0 is the first counter block
+ *
+ * It's assumed that the arguments b0 and cb0 are preallocated AES blocks
+ *
+ */
+static void
+ccm_format_initial_blocks(uchar_t *nonce, ulong_t nonceSize,
+    ulong_t authDataSize, uint8_t *b0, ccm_ctx_t *aes_ctx)
+{
+       uint64_t payloadSize;
+       uint8_t t, q, have_adata = 0;
+       size_t limit;
+       int i, j, k;
+       uint64_t mask = 0;
+       uint8_t *cb;
+
+       q = (uint8_t)((15 - nonceSize) & 0xFF);
+       t = (uint8_t)((aes_ctx->ccm_mac_len) & 0xFF);
+
+       /* Construct the first octet of b0 */
+       if (authDataSize > 0) {
+               have_adata = 1;
+       }
+       b0[0] = (have_adata << 6) | (((t - 2)  / 2) << 3) | (q - 1);
+
+       /* copy the nonce value into b0 */
+       bcopy(nonce, &(b0[1]), nonceSize);
+
+       /* store the length of the payload into b0 */
+       bzero(&(b0[1+nonceSize]), q);
+
+       payloadSize = aes_ctx->ccm_data_len;
+       limit = 8 < q ? 8 : q;
+
+       for (i = 0, j = 0, k = 15; i < limit; i++, j += 8, k--) {
+               b0[k] = (uint8_t)((payloadSize >> j) & 0xFF);
+       }
+
+       /* format the counter block */
+
+       cb = (uint8_t *)aes_ctx->ccm_cb;
+
+       cb[0] = 0x07 & (q-1); /* first byte */
+
+       /* copy the nonce value into the counter block */
+       bcopy(nonce, &(cb[1]), nonceSize);
+
+       bzero(&(cb[1+nonceSize]), q);
+
+       /* Create the mask for the counter field based on the size of nonce */
+       q <<= 3;
+       while (q-- > 0) {
+               mask |= (1ULL << q);
+       }
+
+#ifdef _LITTLE_ENDIAN
+       mask = htonll(mask);
+#endif
+       aes_ctx->ccm_counter_mask = mask;
+
+       /*
+        * During calculation, we start using counter block 1, we will
+        * set it up right here.
+        * We can just set the last byte to have the value 1, because
+        * even with the biggest nonce of 13, the last byte of the
+        * counter block will be used for the counter value.
+        */
+       cb[15] = 0x01;
+}
+
+/*
+ * Encode the length of the associated data as
+ * specified in RFC 3610 and NIST publication 800-38C, appendix A
+ */
+static void
+encode_adata_len(ulong_t auth_data_len, uint8_t *encoded, size_t *encoded_len)
+{
+#ifdef UNALIGNED_POINTERS_PERMITTED
+       uint32_t        *lencoded_ptr;
+#ifdef _LP64
+       uint64_t        *llencoded_ptr;
+#endif
+#endif /* UNALIGNED_POINTERS_PERMITTED */
+
+       if (auth_data_len < ((1ULL<<16) - (1ULL<<8))) {
+               /* 0 < a < (2^16-2^8) */
+               *encoded_len = 2;
+               encoded[0] = (auth_data_len & 0xff00) >> 8;
+               encoded[1] = auth_data_len & 0xff;
+
+       } else if ((auth_data_len >= ((1ULL<<16) - (1ULL<<8))) &&
+           (auth_data_len < (1ULL << 31))) {
+               /* (2^16-2^8) <= a < 2^32 */
+               *encoded_len = 6;
+               encoded[0] = 0xff;
+               encoded[1] = 0xfe;
+#ifdef UNALIGNED_POINTERS_PERMITTED
+               lencoded_ptr = (uint32_t *)&encoded[2];
+               *lencoded_ptr = htonl(auth_data_len);
+#else
+               encoded[2] = (auth_data_len & 0xff000000) >> 24;
+               encoded[3] = (auth_data_len & 0xff0000) >> 16;
+               encoded[4] = (auth_data_len & 0xff00) >> 8;
+               encoded[5] = auth_data_len & 0xff;
+#endif /* UNALIGNED_POINTERS_PERMITTED */
+
+#ifdef _LP64
+       } else {
+               /* 2^32 <= a < 2^64 */
+               *encoded_len = 10;
+               encoded[0] = 0xff;
+               encoded[1] = 0xff;
+#ifdef UNALIGNED_POINTERS_PERMITTED
+               llencoded_ptr = (uint64_t *)&encoded[2];
+               *llencoded_ptr = htonl(auth_data_len);
+#else
+               encoded[2] = (auth_data_len & 0xff00000000000000) >> 56;
+               encoded[3] = (auth_data_len & 0xff000000000000) >> 48;
+               encoded[4] = (auth_data_len & 0xff0000000000) >> 40;
+               encoded[5] = (auth_data_len & 0xff00000000) >> 32;
+               encoded[6] = (auth_data_len & 0xff000000) >> 24;
+               encoded[7] = (auth_data_len & 0xff0000) >> 16;
+               encoded[8] = (auth_data_len & 0xff00) >> 8;
+               encoded[9] = auth_data_len & 0xff;
+#endif /* UNALIGNED_POINTERS_PERMITTED */
+#endif /* _LP64 */
+       }
+}
+
+/*
+ * The following function should be call at encrypt or decrypt init time
+ * for AES CCM mode.
+ */
+int
+ccm_init(ccm_ctx_t *ctx, unsigned char *nonce, size_t nonce_len,
+    unsigned char *auth_data, size_t auth_data_len, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       uint8_t *mac_buf, *datap, *ivp, *authp;
+       size_t remainder, processed;
+       uint8_t encoded_a[10]; /* max encoded auth data length is 10 octets */
+       size_t encoded_a_len = 0;
+
+       mac_buf = (uint8_t *)&(ctx->ccm_mac_buf);
+
+       /*
+        * Format the 1st block for CBC-MAC and construct the
+        * 1st counter block.
+        *
+        * aes_ctx->ccm_iv is used for storing the counter block
+        * mac_buf will store b0 at this time.
+        */
+       ccm_format_initial_blocks(nonce, nonce_len,
+           auth_data_len, mac_buf, ctx);
+
+       /* The IV for CBC MAC for AES CCM mode is always zero */
+       ivp = (uint8_t *)ctx->ccm_tmp;
+       bzero(ivp, block_size);
+
+       xor_block(ivp, mac_buf);
+
+       /* encrypt the nonce */
+       encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
+
+       /* take care of the associated data, if any */
+       if (auth_data_len == 0) {
+               return (CRYPTO_SUCCESS);
+       }
+
+       encode_adata_len(auth_data_len, encoded_a, &encoded_a_len);
+
+       remainder = auth_data_len;
+
+       /* 1st block: it contains encoded associated data, and some data */
+       authp = (uint8_t *)ctx->ccm_tmp;
+       bzero(authp, block_size);
+       bcopy(encoded_a, authp, encoded_a_len);
+       processed = block_size - encoded_a_len;
+       if (processed > auth_data_len) {
+               /* in case auth_data is very small */
+               processed = auth_data_len;
+       }
+       bcopy(auth_data, authp+encoded_a_len, processed);
+       /* xor with previous buffer */
+       xor_block(authp, mac_buf);
+       encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
+       remainder -= processed;
+       if (remainder == 0) {
+               /* a small amount of associated data, it's all done now */
+               return (CRYPTO_SUCCESS);
+       }
+
+       do {
+               if (remainder < block_size) {
+                       /*
+                        * There's not a block full of data, pad rest of
+                        * buffer with zero
+                        */
+                       bzero(authp, block_size);
+                       bcopy(&(auth_data[processed]), authp, remainder);
+                       datap = (uint8_t *)authp;
+                       remainder = 0;
+               } else {
+                       datap = (uint8_t *)(&(auth_data[processed]));
+                       processed += block_size;
+                       remainder -= block_size;
+               }
+
+               xor_block(datap, mac_buf);
+               encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
+
+       } while (remainder > 0);
+
+       return (CRYPTO_SUCCESS);
+}
+
+int
+ccm_init_ctx(ccm_ctx_t *ccm_ctx, char *param, int kmflag,
+    boolean_t is_encrypt_init, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       int rv;
+       CK_AES_CCM_PARAMS *ccm_param;
+
+       if (param != NULL) {
+               ccm_param = (CK_AES_CCM_PARAMS *)param;
+
+               if ((rv = ccm_validate_args(ccm_param,
+                   is_encrypt_init)) != 0) {
+                       return (rv);
+               }
+
+               ccm_ctx->ccm_mac_len = ccm_param->ulMACSize;
+               if (is_encrypt_init) {
+                       ccm_ctx->ccm_data_len = ccm_param->ulDataSize;
+               } else {
+                       ccm_ctx->ccm_data_len =
+                           ccm_param->ulDataSize - ccm_ctx->ccm_mac_len;
+                       ccm_ctx->ccm_processed_mac_len = 0;
+               }
+               ccm_ctx->ccm_processed_data_len = 0;
+
+               ccm_ctx->ccm_flags |= CCM_MODE;
+       } else {
+               rv = CRYPTO_MECHANISM_PARAM_INVALID;
+               goto out;
+       }
+
+       if (ccm_init(ccm_ctx, ccm_param->nonce, ccm_param->ulNonceSize,
+           ccm_param->authData, ccm_param->ulAuthDataSize, block_size,
+           encrypt_block, xor_block) != 0) {
+               rv = CRYPTO_MECHANISM_PARAM_INVALID;
+               goto out;
+       }
+       if (!is_encrypt_init) {
+               /* allocate buffer for storing decrypted plaintext */
+               ccm_ctx->ccm_pt_buf = vmem_alloc(ccm_ctx->ccm_data_len,
+                   kmflag);
+               if (ccm_ctx->ccm_pt_buf == NULL) {
+                       rv = CRYPTO_HOST_MEMORY;
+               }
+       }
+out:
+       return (rv);
+}
+
+void *
+ccm_alloc_ctx(int kmflag)
+{
+       ccm_ctx_t *ccm_ctx;
+
+       if ((ccm_ctx = kmem_zalloc(sizeof (ccm_ctx_t), kmflag)) == NULL)
+               return (NULL);
+
+       ccm_ctx->ccm_flags = CCM_MODE;
+       return (ccm_ctx);
+}
diff --git a/zfs/module/icp/algs/modes/ctr.c b/zfs/module/icp/algs/modes/ctr.c
new file mode 100644 (file)
index 0000000..77ba28d
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <modes/modes.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/byteorder.h>
+
+/*
+ * Encrypt and decrypt multiple blocks of data in counter mode.
+ */
+int
+ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length,
+    crypto_data_t *out, size_t block_size,
+    int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t remainder = length;
+       size_t need = 0;
+       uint8_t *datap = (uint8_t *)data;
+       uint8_t *blockp;
+       uint8_t *lastp;
+       void *iov_or_mp;
+       offset_t offset;
+       uint8_t *out_data_1;
+       uint8_t *out_data_2;
+       size_t out_data_1_len;
+       uint64_t lower_counter, upper_counter;
+
+       if (length + ctx->ctr_remainder_len < block_size) {
+               /* accumulate bytes here and return */
+               bcopy(datap,
+                   (uint8_t *)ctx->ctr_remainder + ctx->ctr_remainder_len,
+                   length);
+               ctx->ctr_remainder_len += length;
+               ctx->ctr_copy_to = datap;
+               return (CRYPTO_SUCCESS);
+       }
+
+       lastp = (uint8_t *)ctx->ctr_cb;
+       if (out != NULL)
+               crypto_init_ptrs(out, &iov_or_mp, &offset);
+
+       do {
+               /* Unprocessed data from last call. */
+               if (ctx->ctr_remainder_len > 0) {
+                       need = block_size - ctx->ctr_remainder_len;
+
+                       if (need > remainder)
+                               return (CRYPTO_DATA_LEN_RANGE);
+
+                       bcopy(datap, &((uint8_t *)ctx->ctr_remainder)
+                           [ctx->ctr_remainder_len], need);
+
+                       blockp = (uint8_t *)ctx->ctr_remainder;
+               } else {
+                       blockp = datap;
+               }
+
+               /* ctr_cb is the counter block */
+               cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
+                   (uint8_t *)ctx->ctr_tmp);
+
+               lastp = (uint8_t *)ctx->ctr_tmp;
+
+               /*
+                * Increment Counter.
+                */
+               lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask);
+               lower_counter = htonll(lower_counter + 1);
+               lower_counter &= ctx->ctr_lower_mask;
+               ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) |
+                   lower_counter;
+
+               /* wrap around */
+               if (lower_counter == 0) {
+                       upper_counter =
+                           ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask);
+                       upper_counter = htonll(upper_counter + 1);
+                       upper_counter &= ctx->ctr_upper_mask;
+                       ctx->ctr_cb[0] =
+                           (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) |
+                           upper_counter;
+               }
+
+               /*
+                * XOR encrypted counter block with the current clear block.
+                */
+               xor_block(blockp, lastp);
+
+               if (out == NULL) {
+                       if (ctx->ctr_remainder_len > 0) {
+                               bcopy(lastp, ctx->ctr_copy_to,
+                                   ctx->ctr_remainder_len);
+                               bcopy(lastp + ctx->ctr_remainder_len, datap,
+                                   need);
+                       }
+               } else {
+                       crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
+                           &out_data_1_len, &out_data_2, block_size);
+
+                       /* copy block to where it belongs */
+                       bcopy(lastp, out_data_1, out_data_1_len);
+                       if (out_data_2 != NULL) {
+                               bcopy(lastp + out_data_1_len, out_data_2,
+                                   block_size - out_data_1_len);
+                       }
+                       /* update offset */
+                       out->cd_offset += block_size;
+               }
+
+               /* Update pointer to next block of data to be processed. */
+               if (ctx->ctr_remainder_len != 0) {
+                       datap += need;
+                       ctx->ctr_remainder_len = 0;
+               } else {
+                       datap += block_size;
+               }
+
+               remainder = (size_t)&data[length] - (size_t)datap;
+
+               /* Incomplete last block. */
+               if (remainder > 0 && remainder < block_size) {
+                       bcopy(datap, ctx->ctr_remainder, remainder);
+                       ctx->ctr_remainder_len = remainder;
+                       ctx->ctr_copy_to = datap;
+                       goto out;
+               }
+               ctx->ctr_copy_to = NULL;
+
+       } while (remainder > 0);
+
+out:
+       return (CRYPTO_SUCCESS);
+}
+
+int
+ctr_mode_final(ctr_ctx_t *ctx, crypto_data_t *out,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
+{
+       uint8_t *lastp;
+       void *iov_or_mp;
+       offset_t offset;
+       uint8_t *out_data_1;
+       uint8_t *out_data_2;
+       size_t out_data_1_len;
+       uint8_t *p;
+       int i;
+
+       if (out->cd_length < ctx->ctr_remainder_len)
+               return (CRYPTO_DATA_LEN_RANGE);
+
+       encrypt_block(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb,
+           (uint8_t *)ctx->ctr_tmp);
+
+       lastp = (uint8_t *)ctx->ctr_tmp;
+       p = (uint8_t *)ctx->ctr_remainder;
+       for (i = 0; i < ctx->ctr_remainder_len; i++) {
+               p[i] ^= lastp[i];
+       }
+
+       crypto_init_ptrs(out, &iov_or_mp, &offset);
+       crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
+           &out_data_1_len, &out_data_2, ctx->ctr_remainder_len);
+
+       bcopy(p, out_data_1, out_data_1_len);
+       if (out_data_2 != NULL) {
+               bcopy((uint8_t *)p + out_data_1_len,
+                   out_data_2, ctx->ctr_remainder_len - out_data_1_len);
+       }
+       out->cd_offset += ctx->ctr_remainder_len;
+       ctx->ctr_remainder_len = 0;
+       return (CRYPTO_SUCCESS);
+}
+
+int
+ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb,
+void (*copy_block)(uint8_t *, uint8_t *))
+{
+       uint64_t upper_mask = 0;
+       uint64_t lower_mask = 0;
+
+       if (count == 0 || count > 128) {
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+       }
+       /* upper 64 bits of the mask */
+       if (count >= 64) {
+               count -= 64;
+               upper_mask = (count == 64) ? UINT64_MAX : (1ULL << count) - 1;
+               lower_mask = UINT64_MAX;
+       } else {
+               /* now the lower 63 bits */
+               lower_mask = (1ULL << count) - 1;
+       }
+       ctr_ctx->ctr_lower_mask = htonll(lower_mask);
+       ctr_ctx->ctr_upper_mask = htonll(upper_mask);
+
+       copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb);
+       ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0];
+       ctr_ctx->ctr_flags |= CTR_MODE;
+       return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+void *
+ctr_alloc_ctx(int kmflag)
+{
+       ctr_ctx_t *ctr_ctx;
+
+       if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL)
+               return (NULL);
+
+       ctr_ctx->ctr_flags = CTR_MODE;
+       return (ctr_ctx);
+}
diff --git a/zfs/module/icp/algs/modes/ecb.c b/zfs/module/icp/algs/modes/ecb.c
new file mode 100644 (file)
index 0000000..04e6c5e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <modes/modes.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+
+/*
+ * Algorithm independent ECB functions.
+ */
+int
+ecb_cipher_contiguous_blocks(ecb_ctx_t *ctx, char *data, size_t length,
+    crypto_data_t *out, size_t block_size,
+    int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct))
+{
+       size_t remainder = length;
+       size_t need = 0;
+       uint8_t *datap = (uint8_t *)data;
+       uint8_t *blockp;
+       uint8_t *lastp;
+       void *iov_or_mp;
+       offset_t offset;
+       uint8_t *out_data_1;
+       uint8_t *out_data_2;
+       size_t out_data_1_len;
+
+       if (length + ctx->ecb_remainder_len < block_size) {
+               /* accumulate bytes here and return */
+               bcopy(datap,
+                   (uint8_t *)ctx->ecb_remainder + ctx->ecb_remainder_len,
+                   length);
+               ctx->ecb_remainder_len += length;
+               ctx->ecb_copy_to = datap;
+               return (CRYPTO_SUCCESS);
+       }
+
+       lastp = (uint8_t *)ctx->ecb_iv;
+       if (out != NULL)
+               crypto_init_ptrs(out, &iov_or_mp, &offset);
+
+       do {
+               /* Unprocessed data from last call. */
+               if (ctx->ecb_remainder_len > 0) {
+                       need = block_size - ctx->ecb_remainder_len;
+
+                       if (need > remainder)
+                               return (CRYPTO_DATA_LEN_RANGE);
+
+                       bcopy(datap, &((uint8_t *)ctx->ecb_remainder)
+                           [ctx->ecb_remainder_len], need);
+
+                       blockp = (uint8_t *)ctx->ecb_remainder;
+               } else {
+                       blockp = datap;
+               }
+
+               if (out == NULL) {
+                       cipher(ctx->ecb_keysched, blockp, blockp);
+
+                       ctx->ecb_lastp = blockp;
+                       lastp = blockp;
+
+                       if (ctx->ecb_remainder_len > 0) {
+                               bcopy(blockp, ctx->ecb_copy_to,
+                                   ctx->ecb_remainder_len);
+                               bcopy(blockp + ctx->ecb_remainder_len, datap,
+                                   need);
+                       }
+               } else {
+                       cipher(ctx->ecb_keysched, blockp, lastp);
+                       crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
+                           &out_data_1_len, &out_data_2, block_size);
+
+                       /* copy block to where it belongs */
+                       bcopy(lastp, out_data_1, out_data_1_len);
+                       if (out_data_2 != NULL) {
+                               bcopy(lastp + out_data_1_len, out_data_2,
+                                   block_size - out_data_1_len);
+                       }
+                       /* update offset */
+                       out->cd_offset += block_size;
+               }
+
+               /* Update pointer to next block of data to be processed. */
+               if (ctx->ecb_remainder_len != 0) {
+                       datap += need;
+                       ctx->ecb_remainder_len = 0;
+               } else {
+                       datap += block_size;
+               }
+
+               remainder = (size_t)&data[length] - (size_t)datap;
+
+               /* Incomplete last block. */
+               if (remainder > 0 && remainder < block_size) {
+                       bcopy(datap, ctx->ecb_remainder, remainder);
+                       ctx->ecb_remainder_len = remainder;
+                       ctx->ecb_copy_to = datap;
+                       goto out;
+               }
+               ctx->ecb_copy_to = NULL;
+
+       } while (remainder > 0);
+
+out:
+       return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+void *
+ecb_alloc_ctx(int kmflag)
+{
+       ecb_ctx_t *ecb_ctx;
+
+       if ((ecb_ctx = kmem_zalloc(sizeof (ecb_ctx_t), kmflag)) == NULL)
+               return (NULL);
+
+       ecb_ctx->ecb_flags = ECB_MODE;
+       return (ecb_ctx);
+}
diff --git a/zfs/module/icp/algs/modes/gcm.c b/zfs/module/icp/algs/modes/gcm.c
new file mode 100644 (file)
index 0000000..9cd8ab1
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+ * 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <modes/modes.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/byteorder.h>
+
+#ifdef __amd64
+
+#ifdef _KERNEL
+/* Workaround for no XMM kernel thread save/restore */
+#define        KPREEMPT_DISABLE        kpreempt_disable()
+#define        KPREEMPT_ENABLE         kpreempt_enable()
+
+#else
+#define        KPREEMPT_DISABLE
+#define        KPREEMPT_ENABLE
+#endif /* _KERNEL */
+
+extern void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res);
+static int intel_pclmulqdq_instruction_present(void);
+#endif /* __amd64 */
+
+struct aes_block {
+       uint64_t a;
+       uint64_t b;
+};
+
+
+/*
+ * gcm_mul()
+ * Perform a carry-less multiplication (that is, use XOR instead of the
+ * multiply operator) on *x_in and *y and place the result in *res.
+ *
+ * Byte swap the input (*x_in and *y) and the output (*res).
+ *
+ * Note: x_in, y, and res all point to 16-byte numbers (an array of two
+ * 64-bit integers).
+ */
+void
+gcm_mul(uint64_t *x_in, uint64_t *y, uint64_t *res)
+{
+#ifdef __amd64
+       if (intel_pclmulqdq_instruction_present()) {
+               KPREEMPT_DISABLE;
+               gcm_mul_pclmulqdq(x_in, y, res);
+               KPREEMPT_ENABLE;
+       } else
+#endif /* __amd64 */
+       {
+               static const uint64_t R = 0xe100000000000000ULL;
+               struct aes_block z = {0, 0};
+               struct aes_block v;
+               uint64_t x;
+               int i, j;
+
+               v.a = ntohll(y[0]);
+               v.b = ntohll(y[1]);
+
+               for (j = 0; j < 2; j++) {
+                       x = ntohll(x_in[j]);
+                       for (i = 0; i < 64; i++, x <<= 1) {
+                               if (x & 0x8000000000000000ULL) {
+                                       z.a ^= v.a;
+                                       z.b ^= v.b;
+                               }
+                               if (v.b & 1ULL) {
+                                       v.b = (v.a << 63)|(v.b >> 1);
+                                       v.a = (v.a >> 1) ^ R;
+                               } else {
+                                       v.b = (v.a << 63)|(v.b >> 1);
+                                       v.a = v.a >> 1;
+                               }
+                       }
+               }
+               res[0] = htonll(z.a);
+               res[1] = htonll(z.b);
+       }
+}
+
+
+#define        GHASH(c, d, t) \
+       xor_block((uint8_t *)(d), (uint8_t *)(c)->gcm_ghash); \
+       gcm_mul((uint64_t *)(void *)(c)->gcm_ghash, (c)->gcm_H, \
+       (uint64_t *)(void *)(t));
+
+
+/*
+ * Encrypt multiple blocks of data in GCM mode.  Decrypt for GCM mode
+ * is done in another function.
+ */
+int
+gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
+    crypto_data_t *out, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t remainder = length;
+       size_t need = 0;
+       uint8_t *datap = (uint8_t *)data;
+       uint8_t *blockp;
+       uint8_t *lastp;
+       void *iov_or_mp;
+       offset_t offset;
+       uint8_t *out_data_1;
+       uint8_t *out_data_2;
+       size_t out_data_1_len;
+       uint64_t counter;
+       uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
+
+       if (length + ctx->gcm_remainder_len < block_size) {
+               /* accumulate bytes here and return */
+               bcopy(datap,
+                   (uint8_t *)ctx->gcm_remainder + ctx->gcm_remainder_len,
+                   length);
+               ctx->gcm_remainder_len += length;
+               ctx->gcm_copy_to = datap;
+               return (CRYPTO_SUCCESS);
+       }
+
+       lastp = (uint8_t *)ctx->gcm_cb;
+       if (out != NULL)
+               crypto_init_ptrs(out, &iov_or_mp, &offset);
+
+       do {
+               /* Unprocessed data from last call. */
+               if (ctx->gcm_remainder_len > 0) {
+                       need = block_size - ctx->gcm_remainder_len;
+
+                       if (need > remainder)
+                               return (CRYPTO_DATA_LEN_RANGE);
+
+                       bcopy(datap, &((uint8_t *)ctx->gcm_remainder)
+                           [ctx->gcm_remainder_len], need);
+
+                       blockp = (uint8_t *)ctx->gcm_remainder;
+               } else {
+                       blockp = datap;
+               }
+
+               /*
+                * Increment counter. Counter bits are confined
+                * to the bottom 32 bits of the counter block.
+                */
+               counter = ntohll(ctx->gcm_cb[1] & counter_mask);
+               counter = htonll(counter + 1);
+               counter &= counter_mask;
+               ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
+
+               encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb,
+                   (uint8_t *)ctx->gcm_tmp);
+               xor_block(blockp, (uint8_t *)ctx->gcm_tmp);
+
+               lastp = (uint8_t *)ctx->gcm_tmp;
+
+               ctx->gcm_processed_data_len += block_size;
+
+               if (out == NULL) {
+                       if (ctx->gcm_remainder_len > 0) {
+                               bcopy(blockp, ctx->gcm_copy_to,
+                                   ctx->gcm_remainder_len);
+                               bcopy(blockp + ctx->gcm_remainder_len, datap,
+                                   need);
+                       }
+               } else {
+                       crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
+                           &out_data_1_len, &out_data_2, block_size);
+
+                       /* copy block to where it belongs */
+                       if (out_data_1_len == block_size) {
+                               copy_block(lastp, out_data_1);
+                       } else {
+                               bcopy(lastp, out_data_1, out_data_1_len);
+                               if (out_data_2 != NULL) {
+                                       bcopy(lastp + out_data_1_len,
+                                           out_data_2,
+                                           block_size - out_data_1_len);
+                               }
+                       }
+                       /* update offset */
+                       out->cd_offset += block_size;
+               }
+
+               /* add ciphertext to the hash */
+               GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash);
+
+               /* Update pointer to next block of data to be processed. */
+               if (ctx->gcm_remainder_len != 0) {
+                       datap += need;
+                       ctx->gcm_remainder_len = 0;
+               } else {
+                       datap += block_size;
+               }
+
+               remainder = (size_t)&data[length] - (size_t)datap;
+
+               /* Incomplete last block. */
+               if (remainder > 0 && remainder < block_size) {
+                       bcopy(datap, ctx->gcm_remainder, remainder);
+                       ctx->gcm_remainder_len = remainder;
+                       ctx->gcm_copy_to = datap;
+                       goto out;
+               }
+               ctx->gcm_copy_to = NULL;
+
+       } while (remainder > 0);
+out:
+       return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+int
+gcm_encrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
+       uint8_t *ghash, *macp = NULL;
+       int i, rv;
+
+       if (out->cd_length <
+           (ctx->gcm_remainder_len + ctx->gcm_tag_len)) {
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       ghash = (uint8_t *)ctx->gcm_ghash;
+
+       if (ctx->gcm_remainder_len > 0) {
+               uint64_t counter;
+               uint8_t *tmpp = (uint8_t *)ctx->gcm_tmp;
+
+               /*
+                * Here is where we deal with data that is not a
+                * multiple of the block size.
+                */
+
+               /*
+                * Increment counter.
+                */
+               counter = ntohll(ctx->gcm_cb[1] & counter_mask);
+               counter = htonll(counter + 1);
+               counter &= counter_mask;
+               ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
+
+               encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb,
+                   (uint8_t *)ctx->gcm_tmp);
+
+               macp = (uint8_t *)ctx->gcm_remainder;
+               bzero(macp + ctx->gcm_remainder_len,
+                   block_size - ctx->gcm_remainder_len);
+
+               /* XOR with counter block */
+               for (i = 0; i < ctx->gcm_remainder_len; i++) {
+                       macp[i] ^= tmpp[i];
+               }
+
+               /* add ciphertext to the hash */
+               GHASH(ctx, macp, ghash);
+
+               ctx->gcm_processed_data_len += ctx->gcm_remainder_len;
+       }
+
+       ctx->gcm_len_a_len_c[1] =
+           htonll(CRYPTO_BYTES2BITS(ctx->gcm_processed_data_len));
+       GHASH(ctx, ctx->gcm_len_a_len_c, ghash);
+       encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0,
+           (uint8_t *)ctx->gcm_J0);
+       xor_block((uint8_t *)ctx->gcm_J0, ghash);
+
+       if (ctx->gcm_remainder_len > 0) {
+               rv = crypto_put_output_data(macp, out, ctx->gcm_remainder_len);
+               if (rv != CRYPTO_SUCCESS)
+                       return (rv);
+       }
+       out->cd_offset += ctx->gcm_remainder_len;
+       ctx->gcm_remainder_len = 0;
+       rv = crypto_put_output_data(ghash, out, ctx->gcm_tag_len);
+       if (rv != CRYPTO_SUCCESS)
+               return (rv);
+       out->cd_offset += ctx->gcm_tag_len;
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * This will only deal with decrypting the last block of the input that
+ * might not be a multiple of block length.
+ */
+static void
+gcm_decrypt_incomplete_block(gcm_ctx_t *ctx, size_t block_size, size_t index,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       uint8_t *datap, *outp, *counterp;
+       uint64_t counter;
+       uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
+       int i;
+
+       /*
+        * Increment counter.
+        * Counter bits are confined to the bottom 32 bits
+        */
+       counter = ntohll(ctx->gcm_cb[1] & counter_mask);
+       counter = htonll(counter + 1);
+       counter &= counter_mask;
+       ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
+
+       datap = (uint8_t *)ctx->gcm_remainder;
+       outp = &((ctx->gcm_pt_buf)[index]);
+       counterp = (uint8_t *)ctx->gcm_tmp;
+
+       /* authentication tag */
+       bzero((uint8_t *)ctx->gcm_tmp, block_size);
+       bcopy(datap, (uint8_t *)ctx->gcm_tmp, ctx->gcm_remainder_len);
+
+       /* add ciphertext to the hash */
+       GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash);
+
+       /* decrypt remaining ciphertext */
+       encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, counterp);
+
+       /* XOR with counter block */
+       for (i = 0; i < ctx->gcm_remainder_len; i++) {
+               outp[i] = datap[i] ^ counterp[i];
+       }
+}
+
+/* ARGSUSED */
+int
+gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
+    crypto_data_t *out, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t new_len;
+       uint8_t *new;
+
+       /*
+        * Copy contiguous ciphertext input blocks to plaintext buffer.
+        * Ciphertext will be decrypted in the final.
+        */
+       if (length > 0) {
+               new_len = ctx->gcm_pt_buf_len + length;
+               new = vmem_alloc(new_len, ctx->gcm_kmflag);
+               bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len);
+               vmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len);
+               if (new == NULL)
+                       return (CRYPTO_HOST_MEMORY);
+
+               ctx->gcm_pt_buf = new;
+               ctx->gcm_pt_buf_len = new_len;
+               bcopy(data, &ctx->gcm_pt_buf[ctx->gcm_processed_data_len],
+                   length);
+               ctx->gcm_processed_data_len += length;
+       }
+
+       ctx->gcm_remainder_len = 0;
+       return (CRYPTO_SUCCESS);
+}
+
+int
+gcm_decrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       size_t pt_len;
+       size_t remainder;
+       uint8_t *ghash;
+       uint8_t *blockp;
+       uint8_t *cbp;
+       uint64_t counter;
+       uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
+       int processed = 0, rv;
+
+       ASSERT(ctx->gcm_processed_data_len == ctx->gcm_pt_buf_len);
+
+       pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
+       ghash = (uint8_t *)ctx->gcm_ghash;
+       blockp = ctx->gcm_pt_buf;
+       remainder = pt_len;
+       while (remainder > 0) {
+               /* Incomplete last block */
+               if (remainder < block_size) {
+                       bcopy(blockp, ctx->gcm_remainder, remainder);
+                       ctx->gcm_remainder_len = remainder;
+                       /*
+                        * not expecting anymore ciphertext, just
+                        * compute plaintext for the remaining input
+                        */
+                       gcm_decrypt_incomplete_block(ctx, block_size,
+                           processed, encrypt_block, xor_block);
+                       ctx->gcm_remainder_len = 0;
+                       goto out;
+               }
+               /* add ciphertext to the hash */
+               GHASH(ctx, blockp, ghash);
+
+               /*
+                * Increment counter.
+                * Counter bits are confined to the bottom 32 bits
+                */
+               counter = ntohll(ctx->gcm_cb[1] & counter_mask);
+               counter = htonll(counter + 1);
+               counter &= counter_mask;
+               ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
+
+               cbp = (uint8_t *)ctx->gcm_tmp;
+               encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, cbp);
+
+               /* XOR with ciphertext */
+               xor_block(cbp, blockp);
+
+               processed += block_size;
+               blockp += block_size;
+               remainder -= block_size;
+       }
+out:
+       ctx->gcm_len_a_len_c[1] = htonll(CRYPTO_BYTES2BITS(pt_len));
+       GHASH(ctx, ctx->gcm_len_a_len_c, ghash);
+       encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0,
+           (uint8_t *)ctx->gcm_J0);
+       xor_block((uint8_t *)ctx->gcm_J0, ghash);
+
+       /* compare the input authentication tag with what we calculated */
+       if (bcmp(&ctx->gcm_pt_buf[pt_len], ghash, ctx->gcm_tag_len)) {
+               /* They don't match */
+               return (CRYPTO_INVALID_MAC);
+       } else {
+               rv = crypto_put_output_data(ctx->gcm_pt_buf, out, pt_len);
+               if (rv != CRYPTO_SUCCESS)
+                       return (rv);
+               out->cd_offset += pt_len;
+       }
+       return (CRYPTO_SUCCESS);
+}
+
+static int
+gcm_validate_args(CK_AES_GCM_PARAMS *gcm_param)
+{
+       size_t tag_len;
+
+       /*
+        * Check the length of the authentication tag (in bits).
+        */
+       tag_len = gcm_param->ulTagBits;
+       switch (tag_len) {
+       case 32:
+       case 64:
+       case 96:
+       case 104:
+       case 112:
+       case 120:
+       case 128:
+               break;
+       default:
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+       }
+
+       if (gcm_param->ulIvLen == 0)
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+
+       return (CRYPTO_SUCCESS);
+}
+
+static void
+gcm_format_initial_blocks(uchar_t *iv, ulong_t iv_len,
+    gcm_ctx_t *ctx, size_t block_size,
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       uint8_t *cb;
+       ulong_t remainder = iv_len;
+       ulong_t processed = 0;
+       uint8_t *datap, *ghash;
+       uint64_t len_a_len_c[2];
+
+       ghash = (uint8_t *)ctx->gcm_ghash;
+       cb = (uint8_t *)ctx->gcm_cb;
+       if (iv_len == 12) {
+               bcopy(iv, cb, 12);
+               cb[12] = 0;
+               cb[13] = 0;
+               cb[14] = 0;
+               cb[15] = 1;
+               /* J0 will be used again in the final */
+               copy_block(cb, (uint8_t *)ctx->gcm_J0);
+       } else {
+               /* GHASH the IV */
+               do {
+                       if (remainder < block_size) {
+                               bzero(cb, block_size);
+                               bcopy(&(iv[processed]), cb, remainder);
+                               datap = (uint8_t *)cb;
+                               remainder = 0;
+                       } else {
+                               datap = (uint8_t *)(&(iv[processed]));
+                               processed += block_size;
+                               remainder -= block_size;
+                       }
+                       GHASH(ctx, datap, ghash);
+               } while (remainder > 0);
+
+               len_a_len_c[0] = 0;
+               len_a_len_c[1] = htonll(CRYPTO_BYTES2BITS(iv_len));
+               GHASH(ctx, len_a_len_c, ctx->gcm_J0);
+
+               /* J0 will be used again in the final */
+               copy_block((uint8_t *)ctx->gcm_J0, (uint8_t *)cb);
+       }
+}
+
+/*
+ * The following function is called at encrypt or decrypt init time
+ * for AES GCM mode.
+ */
+int
+gcm_init(gcm_ctx_t *ctx, unsigned char *iv, size_t iv_len,
+    unsigned char *auth_data, size_t auth_data_len, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       uint8_t *ghash, *datap, *authp;
+       size_t remainder, processed;
+
+       /* encrypt zero block to get subkey H */
+       bzero(ctx->gcm_H, sizeof (ctx->gcm_H));
+       encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_H,
+           (uint8_t *)ctx->gcm_H);
+
+       gcm_format_initial_blocks(iv, iv_len, ctx, block_size,
+           copy_block, xor_block);
+
+       authp = (uint8_t *)ctx->gcm_tmp;
+       ghash = (uint8_t *)ctx->gcm_ghash;
+       bzero(authp, block_size);
+       bzero(ghash, block_size);
+
+       processed = 0;
+       remainder = auth_data_len;
+       do {
+               if (remainder < block_size) {
+                       /*
+                        * There's not a block full of data, pad rest of
+                        * buffer with zero
+                        */
+                       bzero(authp, block_size);
+                       bcopy(&(auth_data[processed]), authp, remainder);
+                       datap = (uint8_t *)authp;
+                       remainder = 0;
+               } else {
+                       datap = (uint8_t *)(&(auth_data[processed]));
+                       processed += block_size;
+                       remainder -= block_size;
+               }
+
+               /* add auth data to the hash */
+               GHASH(ctx, datap, ghash);
+
+       } while (remainder > 0);
+
+       return (CRYPTO_SUCCESS);
+}
+
+int
+gcm_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       int rv;
+       CK_AES_GCM_PARAMS *gcm_param;
+
+       if (param != NULL) {
+               gcm_param = (CK_AES_GCM_PARAMS *)(void *)param;
+
+               if ((rv = gcm_validate_args(gcm_param)) != 0) {
+                       return (rv);
+               }
+
+               gcm_ctx->gcm_tag_len = gcm_param->ulTagBits;
+               gcm_ctx->gcm_tag_len >>= 3;
+               gcm_ctx->gcm_processed_data_len = 0;
+
+               /* these values are in bits */
+               gcm_ctx->gcm_len_a_len_c[0]
+                   = htonll(CRYPTO_BYTES2BITS(gcm_param->ulAADLen));
+
+               rv = CRYPTO_SUCCESS;
+               gcm_ctx->gcm_flags |= GCM_MODE;
+       } else {
+               rv = CRYPTO_MECHANISM_PARAM_INVALID;
+               goto out;
+       }
+
+       if (gcm_init(gcm_ctx, gcm_param->pIv, gcm_param->ulIvLen,
+           gcm_param->pAAD, gcm_param->ulAADLen, block_size,
+           encrypt_block, copy_block, xor_block) != 0) {
+               rv = CRYPTO_MECHANISM_PARAM_INVALID;
+       }
+out:
+       return (rv);
+}
+
+int
+gmac_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *))
+{
+       int rv;
+       CK_AES_GMAC_PARAMS *gmac_param;
+
+       if (param != NULL) {
+               gmac_param = (CK_AES_GMAC_PARAMS *)(void *)param;
+
+               gcm_ctx->gcm_tag_len = CRYPTO_BITS2BYTES(AES_GMAC_TAG_BITS);
+               gcm_ctx->gcm_processed_data_len = 0;
+
+               /* these values are in bits */
+               gcm_ctx->gcm_len_a_len_c[0]
+                   = htonll(CRYPTO_BYTES2BITS(gmac_param->ulAADLen));
+
+               rv = CRYPTO_SUCCESS;
+               gcm_ctx->gcm_flags |= GMAC_MODE;
+       } else {
+               rv = CRYPTO_MECHANISM_PARAM_INVALID;
+               goto out;
+       }
+
+       if (gcm_init(gcm_ctx, gmac_param->pIv, AES_GMAC_IV_LEN,
+           gmac_param->pAAD, gmac_param->ulAADLen, block_size,
+           encrypt_block, copy_block, xor_block) != 0) {
+               rv = CRYPTO_MECHANISM_PARAM_INVALID;
+       }
+out:
+       return (rv);
+}
+
+void *
+gcm_alloc_ctx(int kmflag)
+{
+       gcm_ctx_t *gcm_ctx;
+
+       if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL)
+               return (NULL);
+
+       gcm_ctx->gcm_flags = GCM_MODE;
+       return (gcm_ctx);
+}
+
+void *
+gmac_alloc_ctx(int kmflag)
+{
+       gcm_ctx_t *gcm_ctx;
+
+       if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL)
+               return (NULL);
+
+       gcm_ctx->gcm_flags = GMAC_MODE;
+       return (gcm_ctx);
+}
+
+void
+gcm_set_kmflag(gcm_ctx_t *ctx, int kmflag)
+{
+       ctx->gcm_kmflag = kmflag;
+}
+
+
+#ifdef __amd64
+
+#define        INTEL_PCLMULQDQ_FLAG (1 << 1)
+
+/*
+ * Return 1 if executing on Intel with PCLMULQDQ instructions,
+ * otherwise 0 (i.e., Intel without PCLMULQDQ or AMD64).
+ * Cache the result, as the CPU can't change.
+ *
+ * Note: the userland version uses getisax().  The kernel version uses
+ * is_x86_featureset().
+ */
+static int
+intel_pclmulqdq_instruction_present(void)
+{
+       static int cached_result = -1;
+       unsigned eax, ebx, ecx, edx;
+       unsigned func, subfunc;
+
+       if (cached_result == -1) { /* first time */
+               /* check for an intel cpu */
+               func = 0;
+               subfunc = 0;
+
+               __asm__ __volatile__(
+                   "cpuid"
+                   : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+                   : "a"(func), "c"(subfunc));
+
+               if (memcmp((char *) (&ebx), "Genu", 4) == 0 &&
+                   memcmp((char *) (&edx), "ineI", 4) == 0 &&
+                       memcmp((char *) (&ecx), "ntel", 4) == 0) {
+
+                       func = 1;
+                       subfunc = 0;
+
+                       /* check for aes-ni instruction set */
+                       __asm__ __volatile__(
+                               "cpuid"
+                               : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+                               : "a"(func), "c"(subfunc));
+
+                       cached_result = !!(ecx & INTEL_PCLMULQDQ_FLAG);
+               } else {
+                       cached_result = 0;
+               }
+       }
+
+       return (cached_result);
+}
+
+#endif /* __amd64 */
diff --git a/zfs/module/icp/algs/modes/modes.c b/zfs/module/icp/algs/modes/modes.c
new file mode 100644 (file)
index 0000000..1d33c42
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <modes/modes.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+
+/*
+ * Initialize by setting iov_or_mp to point to the current iovec or mp,
+ * and by setting current_offset to an offset within the current iovec or mp.
+ */
+void
+crypto_init_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset)
+{
+       offset_t offset;
+
+       switch (out->cd_format) {
+       case CRYPTO_DATA_RAW:
+               *current_offset = out->cd_offset;
+               break;
+
+       case CRYPTO_DATA_UIO: {
+               uio_t *uiop = out->cd_uio;
+               uintptr_t vec_idx;
+
+               offset = out->cd_offset;
+               for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
+                   offset >= uiop->uio_iov[vec_idx].iov_len;
+                   offset -= uiop->uio_iov[vec_idx++].iov_len)
+                       ;
+
+               *current_offset = offset;
+               *iov_or_mp = (void *)vec_idx;
+               break;
+       }
+       } /* end switch */
+}
+
+/*
+ * Get pointers for where in the output to copy a block of encrypted or
+ * decrypted data.  The iov_or_mp argument stores a pointer to the current
+ * iovec or mp, and offset stores an offset into the current iovec or mp.
+ */
+void
+crypto_get_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset,
+    uint8_t **out_data_1, size_t *out_data_1_len, uint8_t **out_data_2,
+    size_t amt)
+{
+       offset_t offset;
+
+       switch (out->cd_format) {
+       case CRYPTO_DATA_RAW: {
+               iovec_t *iov;
+
+               offset = *current_offset;
+               iov = &out->cd_raw;
+               if ((offset + amt) <= iov->iov_len) {
+                       /* one block fits */
+                       *out_data_1 = (uint8_t *)iov->iov_base + offset;
+                       *out_data_1_len = amt;
+                       *out_data_2 = NULL;
+                       *current_offset = offset + amt;
+               }
+               break;
+       }
+
+       case CRYPTO_DATA_UIO: {
+               uio_t *uio = out->cd_uio;
+               iovec_t *iov;
+               offset_t offset;
+               uintptr_t vec_idx;
+               uint8_t *p;
+
+               offset = *current_offset;
+               vec_idx = (uintptr_t)(*iov_or_mp);
+               iov = (iovec_t *)&uio->uio_iov[vec_idx];
+               p = (uint8_t *)iov->iov_base + offset;
+               *out_data_1 = p;
+
+               if (offset + amt <= iov->iov_len) {
+                       /* can fit one block into this iov */
+                       *out_data_1_len = amt;
+                       *out_data_2 = NULL;
+                       *current_offset = offset + amt;
+               } else {
+                       /* one block spans two iovecs */
+                       *out_data_1_len = iov->iov_len - offset;
+                       if (vec_idx == uio->uio_iovcnt)
+                               return;
+                       vec_idx++;
+                       iov = (iovec_t *)&uio->uio_iov[vec_idx];
+                       *out_data_2 = (uint8_t *)iov->iov_base;
+                       *current_offset = amt - *out_data_1_len;
+               }
+               *iov_or_mp = (void *)vec_idx;
+               break;
+       }
+       } /* end switch */
+}
+
+void
+crypto_free_mode_ctx(void *ctx)
+{
+       common_ctx_t *common_ctx = (common_ctx_t *)ctx;
+
+       switch (common_ctx->cc_flags &
+           (ECB_MODE|CBC_MODE|CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) {
+       case ECB_MODE:
+               kmem_free(common_ctx, sizeof (ecb_ctx_t));
+               break;
+
+       case CBC_MODE:
+               kmem_free(common_ctx, sizeof (cbc_ctx_t));
+               break;
+
+       case CTR_MODE:
+               kmem_free(common_ctx, sizeof (ctr_ctx_t));
+               break;
+
+       case CCM_MODE:
+               if (((ccm_ctx_t *)ctx)->ccm_pt_buf != NULL)
+                       vmem_free(((ccm_ctx_t *)ctx)->ccm_pt_buf,
+                           ((ccm_ctx_t *)ctx)->ccm_data_len);
+
+               kmem_free(ctx, sizeof (ccm_ctx_t));
+               break;
+
+       case GCM_MODE:
+       case GMAC_MODE:
+               if (((gcm_ctx_t *)ctx)->gcm_pt_buf != NULL)
+                       vmem_free(((gcm_ctx_t *)ctx)->gcm_pt_buf,
+                           ((gcm_ctx_t *)ctx)->gcm_pt_buf_len);
+
+               kmem_free(ctx, sizeof (gcm_ctx_t));
+       }
+}
diff --git a/zfs/module/icp/algs/sha1/sha1.c b/zfs/module/icp/algs/sha1/sha1.c
new file mode 100644 (file)
index 0000000..b826c54
--- /dev/null
@@ -0,0 +1,663 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * The basic framework for this code came from the reference
+ * implementation for MD5.  That implementation is Copyright (C)
+ * 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * NOTE: Cleaned-up and optimized, version of SHA1, based on the FIPS 180-1
+ * standard, available at http://www.itl.nist.gov/fipspubs/fip180-1.htm
+ * Not as fast as one would like -- further optimizations are encouraged
+ * and appreciated.
+ */
+
+#include <sys/zfs_context.h>
+#include <sha1/sha1.h>
+#include <sha1/sha1_consts.h>
+
+#ifdef _LITTLE_ENDIAN
+#include <sys/byteorder.h>
+#define        HAVE_HTONL
+#endif
+
+#define        _RESTRICT_KYWD
+
+static void Encode(uint8_t *, const uint32_t *, size_t);
+
+#if    defined(__amd64)
+
+#define        SHA1_TRANSFORM(ctx, in) sha1_block_data_order((ctx), (in), 1)
+#define        SHA1_TRANSFORM_BLOCKS(ctx, in, num) sha1_block_data_order((ctx), \
+               (in), (num))
+
+void sha1_block_data_order(SHA1_CTX *ctx, const void *inpp, size_t num_blocks);
+
+#else
+
+#define        SHA1_TRANSFORM(ctx, in) SHA1Transform((ctx), (in))
+
+static void SHA1Transform(SHA1_CTX *, const uint8_t *);
+
+#endif
+
+
+static uint8_t PADDING[64] = { 0x80, /* all zeros */ };
+
+/*
+ * F, G, and H are the basic SHA1 functions.
+ */
+#define        F(b, c, d)      (((b) & (c)) | ((~b) & (d)))
+#define        G(b, c, d)      ((b) ^ (c) ^ (d))
+#define        H(b, c, d)      (((b) & (c)) | (((b)|(c)) & (d)))
+
+/*
+ * ROTATE_LEFT rotates x left n bits.
+ */
+
+#if    defined(__GNUC__) && defined(_LP64)
+static __inline__ uint64_t
+ROTATE_LEFT(uint64_t value, uint32_t n)
+{
+       uint32_t t32;
+
+       t32 = (uint32_t)value;
+       return ((t32 << n) | (t32 >> (32 - n)));
+}
+
+#else
+
+#define        ROTATE_LEFT(x, n)       \
+       (((x) << (n)) | ((x) >> ((sizeof (x) * NBBY)-(n))))
+
+#endif
+
+
+/*
+ * SHA1Init()
+ *
+ * purpose: initializes the sha1 context and begins and sha1 digest operation
+ *   input: SHA1_CTX * : the context to initializes.
+ *  output: void
+ */
+
+void
+SHA1Init(SHA1_CTX *ctx)
+{
+       ctx->count[0] = ctx->count[1] = 0;
+
+       /*
+        * load magic initialization constants. Tell lint
+        * that these constants are unsigned by using U.
+        */
+
+       ctx->state[0] = 0x67452301U;
+       ctx->state[1] = 0xefcdab89U;
+       ctx->state[2] = 0x98badcfeU;
+       ctx->state[3] = 0x10325476U;
+       ctx->state[4] = 0xc3d2e1f0U;
+}
+
+void
+SHA1Update(SHA1_CTX *ctx, const void *inptr, size_t input_len)
+{
+       uint32_t i, buf_index, buf_len;
+       const uint8_t *input = inptr;
+#if defined(__amd64)
+       uint32_t        block_count;
+#endif /* __amd64 */
+
+       /* check for noop */
+       if (input_len == 0)
+               return;
+
+       /* compute number of bytes mod 64 */
+       buf_index = (ctx->count[1] >> 3) & 0x3F;
+
+       /* update number of bits */
+       if ((ctx->count[1] += (input_len << 3)) < (input_len << 3))
+               ctx->count[0]++;
+
+       ctx->count[0] += (input_len >> 29);
+
+       buf_len = 64 - buf_index;
+
+       /* transform as many times as possible */
+       i = 0;
+       if (input_len >= buf_len) {
+
+               /*
+                * general optimization:
+                *
+                * only do initial bcopy() and SHA1Transform() if
+                * buf_index != 0.  if buf_index == 0, we're just
+                * wasting our time doing the bcopy() since there
+                * wasn't any data left over from a previous call to
+                * SHA1Update().
+                */
+
+               if (buf_index) {
+                       bcopy(input, &ctx->buf_un.buf8[buf_index], buf_len);
+                       SHA1_TRANSFORM(ctx, ctx->buf_un.buf8);
+                       i = buf_len;
+               }
+
+#if !defined(__amd64)
+               for (; i + 63 < input_len; i += 64)
+                       SHA1_TRANSFORM(ctx, &input[i]);
+#else
+               block_count = (input_len - i) >> 6;
+               if (block_count > 0) {
+                       SHA1_TRANSFORM_BLOCKS(ctx, &input[i], block_count);
+                       i += block_count << 6;
+               }
+#endif /* !__amd64 */
+
+               /*
+                * general optimization:
+                *
+                * if i and input_len are the same, return now instead
+                * of calling bcopy(), since the bcopy() in this case
+                * will be an expensive nop.
+                */
+
+               if (input_len == i)
+                       return;
+
+               buf_index = 0;
+       }
+
+       /* buffer remaining input */
+       bcopy(&input[i], &ctx->buf_un.buf8[buf_index], input_len - i);
+}
+
+/*
+ * SHA1Final()
+ *
+ * purpose: ends an sha1 digest operation, finalizing the message digest and
+ *          zeroing the context.
+ *   input: uchar_t *  : A buffer to store the digest.
+ *                     : The function actually uses void* because many
+ *                     : callers pass things other than uchar_t here.
+ *          SHA1_CTX *  : the context to finalize, save, and zero
+ *  output: void
+ */
+
+void
+SHA1Final(void *digest, SHA1_CTX *ctx)
+{
+       uint8_t         bitcount_be[sizeof (ctx->count)];
+       uint32_t        index = (ctx->count[1] >> 3) & 0x3f;
+
+       /* store bit count, big endian */
+       Encode(bitcount_be, ctx->count, sizeof (bitcount_be));
+
+       /* pad out to 56 mod 64 */
+       SHA1Update(ctx, PADDING, ((index < 56) ? 56 : 120) - index);
+
+       /* append length (before padding) */
+       SHA1Update(ctx, bitcount_be, sizeof (bitcount_be));
+
+       /* store state in digest */
+       Encode(digest, ctx->state, sizeof (ctx->state));
+
+       /* zeroize sensitive information */
+       bzero(ctx, sizeof (*ctx));
+}
+
+
+#if !defined(__amd64)
+
+typedef uint32_t sha1word;
+
+/*
+ * sparc optimization:
+ *
+ * on the sparc, we can load big endian 32-bit data easily.  note that
+ * special care must be taken to ensure the address is 32-bit aligned.
+ * in the interest of speed, we don't check to make sure, since
+ * careful programming can guarantee this for us.
+ */
+
+#if    defined(_BIG_ENDIAN)
+#define        LOAD_BIG_32(addr)       (*(uint32_t *)(addr))
+
+#elif  defined(HAVE_HTONL)
+#define        LOAD_BIG_32(addr) htonl(*((uint32_t *)(addr)))
+
+#else
+/* little endian -- will work on big endian, but slowly */
+#define        LOAD_BIG_32(addr)       \
+       (((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
+#endif /* _BIG_ENDIAN */
+
+/*
+ * SHA1Transform()
+ */
+#if    defined(W_ARRAY)
+#define        W(n) w[n]
+#else  /* !defined(W_ARRAY) */
+#define        W(n) w_ ## n
+#endif /* !defined(W_ARRAY) */
+
+void /* CSTYLED */
+SHA1Transform(SHA1_CTX *ctx, const uint8_t blk[64])
+{
+       /* CSTYLED */
+       sha1word a = ctx->state[0];
+       sha1word b = ctx->state[1];
+       sha1word c = ctx->state[2];
+       sha1word d = ctx->state[3];
+       sha1word e = ctx->state[4];
+
+#if    defined(W_ARRAY)
+       sha1word        w[16];
+#else  /* !defined(W_ARRAY) */
+       sha1word        w_0, w_1, w_2,  w_3,  w_4,  w_5,  w_6,  w_7;
+       sha1word        w_8, w_9, w_10, w_11, w_12, w_13, w_14, w_15;
+#endif /* !defined(W_ARRAY) */
+
+       W(0)  = LOAD_BIG_32((void *)(blk +  0));
+       W(1)  = LOAD_BIG_32((void *)(blk +  4));
+       W(2)  = LOAD_BIG_32((void *)(blk +  8));
+       W(3)  = LOAD_BIG_32((void *)(blk + 12));
+       W(4)  = LOAD_BIG_32((void *)(blk + 16));
+       W(5)  = LOAD_BIG_32((void *)(blk + 20));
+       W(6)  = LOAD_BIG_32((void *)(blk + 24));
+       W(7)  = LOAD_BIG_32((void *)(blk + 28));
+       W(8)  = LOAD_BIG_32((void *)(blk + 32));
+       W(9)  = LOAD_BIG_32((void *)(blk + 36));
+       W(10) = LOAD_BIG_32((void *)(blk + 40));
+       W(11) = LOAD_BIG_32((void *)(blk + 44));
+       W(12) = LOAD_BIG_32((void *)(blk + 48));
+       W(13) = LOAD_BIG_32((void *)(blk + 52));
+       W(14) = LOAD_BIG_32((void *)(blk + 56));
+       W(15) = LOAD_BIG_32((void *)(blk + 60));
+
+       /*
+        * general optimization:
+        *
+        * even though this approach is described in the standard as
+        * being slower algorithmically, it is 30-40% faster than the
+        * "faster" version under SPARC, because this version has more
+        * of the constraints specified at compile-time and uses fewer
+        * variables (and therefore has better register utilization)
+        * than its "speedier" brother.  (i've tried both, trust me)
+        *
+        * for either method given in the spec, there is an "assignment"
+        * phase where the following takes place:
+        *
+        *      tmp = (main_computation);
+        *      e = d; d = c; c = rotate_left(b, 30); b = a; a = tmp;
+        *
+        * we can make the algorithm go faster by not doing this work,
+        * but just pretending that `d' is now `e', etc. this works
+        * really well and obviates the need for a temporary variable.
+        * however, we still explicitly perform the rotate action,
+        * since it is cheaper on SPARC to do it once than to have to
+        * do it over and over again.
+        */
+
+       /* round 1 */
+       e = ROTATE_LEFT(a, 5) + F(b, c, d) + e + W(0) + SHA1_CONST(0); /* 0 */
+       b = ROTATE_LEFT(b, 30);
+
+       d = ROTATE_LEFT(e, 5) + F(a, b, c) + d + W(1) + SHA1_CONST(0); /* 1 */
+       a = ROTATE_LEFT(a, 30);
+
+       c = ROTATE_LEFT(d, 5) + F(e, a, b) + c + W(2) + SHA1_CONST(0); /* 2 */
+       e = ROTATE_LEFT(e, 30);
+
+       b = ROTATE_LEFT(c, 5) + F(d, e, a) + b + W(3) + SHA1_CONST(0); /* 3 */
+       d = ROTATE_LEFT(d, 30);
+
+       a = ROTATE_LEFT(b, 5) + F(c, d, e) + a + W(4) + SHA1_CONST(0); /* 4 */
+       c = ROTATE_LEFT(c, 30);
+
+       e = ROTATE_LEFT(a, 5) + F(b, c, d) + e + W(5) + SHA1_CONST(0); /* 5 */
+       b = ROTATE_LEFT(b, 30);
+
+       d = ROTATE_LEFT(e, 5) + F(a, b, c) + d + W(6) + SHA1_CONST(0); /* 6 */
+       a = ROTATE_LEFT(a, 30);
+
+       c = ROTATE_LEFT(d, 5) + F(e, a, b) + c + W(7) + SHA1_CONST(0); /* 7 */
+       e = ROTATE_LEFT(e, 30);
+
+       b = ROTATE_LEFT(c, 5) + F(d, e, a) + b + W(8) + SHA1_CONST(0); /* 8 */
+       d = ROTATE_LEFT(d, 30);
+
+       a = ROTATE_LEFT(b, 5) + F(c, d, e) + a + W(9) + SHA1_CONST(0); /* 9 */
+       c = ROTATE_LEFT(c, 30);
+
+       e = ROTATE_LEFT(a, 5) + F(b, c, d) + e + W(10) + SHA1_CONST(0); /* 10 */
+       b = ROTATE_LEFT(b, 30);
+
+       d = ROTATE_LEFT(e, 5) + F(a, b, c) + d + W(11) + SHA1_CONST(0); /* 11 */
+       a = ROTATE_LEFT(a, 30);
+
+       c = ROTATE_LEFT(d, 5) + F(e, a, b) + c + W(12) + SHA1_CONST(0); /* 12 */
+       e = ROTATE_LEFT(e, 30);
+
+       b = ROTATE_LEFT(c, 5) + F(d, e, a) + b + W(13) + SHA1_CONST(0); /* 13 */
+       d = ROTATE_LEFT(d, 30);
+
+       a = ROTATE_LEFT(b, 5) + F(c, d, e) + a + W(14) + SHA1_CONST(0); /* 14 */
+       c = ROTATE_LEFT(c, 30);
+
+       e = ROTATE_LEFT(a, 5) + F(b, c, d) + e + W(15) + SHA1_CONST(0); /* 15 */
+       b = ROTATE_LEFT(b, 30);
+
+       W(0) = ROTATE_LEFT((W(13) ^ W(8) ^ W(2) ^ W(0)), 1);            /* 16 */
+       d = ROTATE_LEFT(e, 5) + F(a, b, c) + d + W(0) + SHA1_CONST(0);
+       a = ROTATE_LEFT(a, 30);
+
+       W(1) = ROTATE_LEFT((W(14) ^ W(9) ^ W(3) ^ W(1)), 1);            /* 17 */
+       c = ROTATE_LEFT(d, 5) + F(e, a, b) + c + W(1) + SHA1_CONST(0);
+       e = ROTATE_LEFT(e, 30);
+
+       W(2) = ROTATE_LEFT((W(15) ^ W(10) ^ W(4) ^ W(2)), 1);   /* 18 */
+       b = ROTATE_LEFT(c, 5) + F(d, e, a) + b + W(2) + SHA1_CONST(0);
+       d = ROTATE_LEFT(d, 30);
+
+       W(3) = ROTATE_LEFT((W(0) ^ W(11) ^ W(5) ^ W(3)), 1);            /* 19 */
+       a = ROTATE_LEFT(b, 5) + F(c, d, e) + a + W(3) + SHA1_CONST(0);
+       c = ROTATE_LEFT(c, 30);
+
+       /* round 2 */
+       W(4) = ROTATE_LEFT((W(1) ^ W(12) ^ W(6) ^ W(4)), 1);            /* 20 */
+       e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(4) + SHA1_CONST(1);
+       b = ROTATE_LEFT(b, 30);
+
+       W(5) = ROTATE_LEFT((W(2) ^ W(13) ^ W(7) ^ W(5)), 1);            /* 21 */
+       d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(5) + SHA1_CONST(1);
+       a = ROTATE_LEFT(a, 30);
+
+       W(6) = ROTATE_LEFT((W(3) ^ W(14) ^ W(8) ^ W(6)), 1);            /* 22 */
+       c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(6) + SHA1_CONST(1);
+       e = ROTATE_LEFT(e, 30);
+
+       W(7) = ROTATE_LEFT((W(4) ^ W(15) ^ W(9) ^ W(7)), 1);            /* 23 */
+       b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(7) + SHA1_CONST(1);
+       d = ROTATE_LEFT(d, 30);
+
+       W(8) = ROTATE_LEFT((W(5) ^ W(0) ^ W(10) ^ W(8)), 1);            /* 24 */
+       a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(8) + SHA1_CONST(1);
+       c = ROTATE_LEFT(c, 30);
+
+       W(9) = ROTATE_LEFT((W(6) ^ W(1) ^ W(11) ^ W(9)), 1);            /* 25 */
+       e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(9) + SHA1_CONST(1);
+       b = ROTATE_LEFT(b, 30);
+
+       W(10) = ROTATE_LEFT((W(7) ^ W(2) ^ W(12) ^ W(10)), 1);  /* 26 */
+       d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(10) + SHA1_CONST(1);
+       a = ROTATE_LEFT(a, 30);
+
+       W(11) = ROTATE_LEFT((W(8) ^ W(3) ^ W(13) ^ W(11)), 1);  /* 27 */
+       c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(11) + SHA1_CONST(1);
+       e = ROTATE_LEFT(e, 30);
+
+       W(12) = ROTATE_LEFT((W(9) ^ W(4) ^ W(14) ^ W(12)), 1);  /* 28 */
+       b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(12) + SHA1_CONST(1);
+       d = ROTATE_LEFT(d, 30);
+
+       W(13) = ROTATE_LEFT((W(10) ^ W(5) ^ W(15) ^ W(13)), 1); /* 29 */
+       a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(13) + SHA1_CONST(1);
+       c = ROTATE_LEFT(c, 30);
+
+       W(14) = ROTATE_LEFT((W(11) ^ W(6) ^ W(0) ^ W(14)), 1);  /* 30 */
+       e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(14) + SHA1_CONST(1);
+       b = ROTATE_LEFT(b, 30);
+
+       W(15) = ROTATE_LEFT((W(12) ^ W(7) ^ W(1) ^ W(15)), 1);  /* 31 */
+       d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(15) + SHA1_CONST(1);
+       a = ROTATE_LEFT(a, 30);
+
+       W(0) = ROTATE_LEFT((W(13) ^ W(8) ^ W(2) ^ W(0)), 1);            /* 32 */
+       c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(0) + SHA1_CONST(1);
+       e = ROTATE_LEFT(e, 30);
+
+       W(1) = ROTATE_LEFT((W(14) ^ W(9) ^ W(3) ^ W(1)), 1);            /* 33 */
+       b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(1) + SHA1_CONST(1);
+       d = ROTATE_LEFT(d, 30);
+
+       W(2) = ROTATE_LEFT((W(15) ^ W(10) ^ W(4) ^ W(2)), 1);   /* 34 */
+       a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(2) + SHA1_CONST(1);
+       c = ROTATE_LEFT(c, 30);
+
+       W(3) = ROTATE_LEFT((W(0) ^ W(11) ^ W(5) ^ W(3)), 1);            /* 35 */
+       e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(3) + SHA1_CONST(1);
+       b = ROTATE_LEFT(b, 30);
+
+       W(4) = ROTATE_LEFT((W(1) ^ W(12) ^ W(6) ^ W(4)), 1);            /* 36 */
+       d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(4) + SHA1_CONST(1);
+       a = ROTATE_LEFT(a, 30);
+
+       W(5) = ROTATE_LEFT((W(2) ^ W(13) ^ W(7) ^ W(5)), 1);            /* 37 */
+       c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(5) + SHA1_CONST(1);
+       e = ROTATE_LEFT(e, 30);
+
+       W(6) = ROTATE_LEFT((W(3) ^ W(14) ^ W(8) ^ W(6)), 1);            /* 38 */
+       b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(6) + SHA1_CONST(1);
+       d = ROTATE_LEFT(d, 30);
+
+       W(7) = ROTATE_LEFT((W(4) ^ W(15) ^ W(9) ^ W(7)), 1);            /* 39 */
+       a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(7) + SHA1_CONST(1);
+       c = ROTATE_LEFT(c, 30);
+
+       /* round 3 */
+       W(8) = ROTATE_LEFT((W(5) ^ W(0) ^ W(10) ^ W(8)), 1);            /* 40 */
+       e = ROTATE_LEFT(a, 5) + H(b, c, d) + e + W(8) + SHA1_CONST(2);
+       b = ROTATE_LEFT(b, 30);
+
+       W(9) = ROTATE_LEFT((W(6) ^ W(1) ^ W(11) ^ W(9)), 1);            /* 41 */
+       d = ROTATE_LEFT(e, 5) + H(a, b, c) + d + W(9) + SHA1_CONST(2);
+       a = ROTATE_LEFT(a, 30);
+
+       W(10) = ROTATE_LEFT((W(7) ^ W(2) ^ W(12) ^ W(10)), 1);  /* 42 */
+       c = ROTATE_LEFT(d, 5) + H(e, a, b) + c + W(10) + SHA1_CONST(2);
+       e = ROTATE_LEFT(e, 30);
+
+       W(11) = ROTATE_LEFT((W(8) ^ W(3) ^ W(13) ^ W(11)), 1);  /* 43 */
+       b = ROTATE_LEFT(c, 5) + H(d, e, a) + b + W(11) + SHA1_CONST(2);
+       d = ROTATE_LEFT(d, 30);
+
+       W(12) = ROTATE_LEFT((W(9) ^ W(4) ^ W(14) ^ W(12)), 1);  /* 44 */
+       a = ROTATE_LEFT(b, 5) + H(c, d, e) + a + W(12) + SHA1_CONST(2);
+       c = ROTATE_LEFT(c, 30);
+
+       W(13) = ROTATE_LEFT((W(10) ^ W(5) ^ W(15) ^ W(13)), 1); /* 45 */
+       e = ROTATE_LEFT(a, 5) + H(b, c, d) + e + W(13) + SHA1_CONST(2);
+       b = ROTATE_LEFT(b, 30);
+
+       W(14) = ROTATE_LEFT((W(11) ^ W(6) ^ W(0) ^ W(14)), 1);  /* 46 */
+       d = ROTATE_LEFT(e, 5) + H(a, b, c) + d + W(14) + SHA1_CONST(2);
+       a = ROTATE_LEFT(a, 30);
+
+       W(15) = ROTATE_LEFT((W(12) ^ W(7) ^ W(1) ^ W(15)), 1);  /* 47 */
+       c = ROTATE_LEFT(d, 5) + H(e, a, b) + c + W(15) + SHA1_CONST(2);
+       e = ROTATE_LEFT(e, 30);
+
+       W(0) = ROTATE_LEFT((W(13) ^ W(8) ^ W(2) ^ W(0)), 1);            /* 48 */
+       b = ROTATE_LEFT(c, 5) + H(d, e, a) + b + W(0) + SHA1_CONST(2);
+       d = ROTATE_LEFT(d, 30);
+
+       W(1) = ROTATE_LEFT((W(14) ^ W(9) ^ W(3) ^ W(1)), 1);            /* 49 */
+       a = ROTATE_LEFT(b, 5) + H(c, d, e) + a + W(1) + SHA1_CONST(2);
+       c = ROTATE_LEFT(c, 30);
+
+       W(2) = ROTATE_LEFT((W(15) ^ W(10) ^ W(4) ^ W(2)), 1);   /* 50 */
+       e = ROTATE_LEFT(a, 5) + H(b, c, d) + e + W(2) + SHA1_CONST(2);
+       b = ROTATE_LEFT(b, 30);
+
+       W(3) = ROTATE_LEFT((W(0) ^ W(11) ^ W(5) ^ W(3)), 1);            /* 51 */
+       d = ROTATE_LEFT(e, 5) + H(a, b, c) + d + W(3) + SHA1_CONST(2);
+       a = ROTATE_LEFT(a, 30);
+
+       W(4) = ROTATE_LEFT((W(1) ^ W(12) ^ W(6) ^ W(4)), 1);            /* 52 */
+       c = ROTATE_LEFT(d, 5) + H(e, a, b) + c + W(4) + SHA1_CONST(2);
+       e = ROTATE_LEFT(e, 30);
+
+       W(5) = ROTATE_LEFT((W(2) ^ W(13) ^ W(7) ^ W(5)), 1);            /* 53 */
+       b = ROTATE_LEFT(c, 5) + H(d, e, a) + b + W(5) + SHA1_CONST(2);
+       d = ROTATE_LEFT(d, 30);
+
+       W(6) = ROTATE_LEFT((W(3) ^ W(14) ^ W(8) ^ W(6)), 1);            /* 54 */
+       a = ROTATE_LEFT(b, 5) + H(c, d, e) + a + W(6) + SHA1_CONST(2);
+       c = ROTATE_LEFT(c, 30);
+
+       W(7) = ROTATE_LEFT((W(4) ^ W(15) ^ W(9) ^ W(7)), 1);            /* 55 */
+       e = ROTATE_LEFT(a, 5) + H(b, c, d) + e + W(7) + SHA1_CONST(2);
+       b = ROTATE_LEFT(b, 30);
+
+       W(8) = ROTATE_LEFT((W(5) ^ W(0) ^ W(10) ^ W(8)), 1);            /* 56 */
+       d = ROTATE_LEFT(e, 5) + H(a, b, c) + d + W(8) + SHA1_CONST(2);
+       a = ROTATE_LEFT(a, 30);
+
+       W(9) = ROTATE_LEFT((W(6) ^ W(1) ^ W(11) ^ W(9)), 1);            /* 57 */
+       c = ROTATE_LEFT(d, 5) + H(e, a, b) + c + W(9) + SHA1_CONST(2);
+       e = ROTATE_LEFT(e, 30);
+
+       W(10) = ROTATE_LEFT((W(7) ^ W(2) ^ W(12) ^ W(10)), 1);  /* 58 */
+       b = ROTATE_LEFT(c, 5) + H(d, e, a) + b + W(10) + SHA1_CONST(2);
+       d = ROTATE_LEFT(d, 30);
+
+       W(11) = ROTATE_LEFT((W(8) ^ W(3) ^ W(13) ^ W(11)), 1);  /* 59 */
+       a = ROTATE_LEFT(b, 5) + H(c, d, e) + a + W(11) + SHA1_CONST(2);
+       c = ROTATE_LEFT(c, 30);
+
+       /* round 4 */
+       W(12) = ROTATE_LEFT((W(9) ^ W(4) ^ W(14) ^ W(12)), 1);  /* 60 */
+       e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(12) + SHA1_CONST(3);
+       b = ROTATE_LEFT(b, 30);
+
+       W(13) = ROTATE_LEFT((W(10) ^ W(5) ^ W(15) ^ W(13)), 1); /* 61 */
+       d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(13) + SHA1_CONST(3);
+       a = ROTATE_LEFT(a, 30);
+
+       W(14) = ROTATE_LEFT((W(11) ^ W(6) ^ W(0) ^ W(14)), 1);  /* 62 */
+       c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(14) + SHA1_CONST(3);
+       e = ROTATE_LEFT(e, 30);
+
+       W(15) = ROTATE_LEFT((W(12) ^ W(7) ^ W(1) ^ W(15)), 1);  /* 63 */
+       b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(15) + SHA1_CONST(3);
+       d = ROTATE_LEFT(d, 30);
+
+       W(0) = ROTATE_LEFT((W(13) ^ W(8) ^ W(2) ^ W(0)), 1);            /* 64 */
+       a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(0) + SHA1_CONST(3);
+       c = ROTATE_LEFT(c, 30);
+
+       W(1) = ROTATE_LEFT((W(14) ^ W(9) ^ W(3) ^ W(1)), 1);            /* 65 */
+       e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(1) + SHA1_CONST(3);
+       b = ROTATE_LEFT(b, 30);
+
+       W(2) = ROTATE_LEFT((W(15) ^ W(10) ^ W(4) ^ W(2)), 1);   /* 66 */
+       d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(2) + SHA1_CONST(3);
+       a = ROTATE_LEFT(a, 30);
+
+       W(3) = ROTATE_LEFT((W(0) ^ W(11) ^ W(5) ^ W(3)), 1);            /* 67 */
+       c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(3) + SHA1_CONST(3);
+       e = ROTATE_LEFT(e, 30);
+
+       W(4) = ROTATE_LEFT((W(1) ^ W(12) ^ W(6) ^ W(4)), 1);            /* 68 */
+       b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(4) + SHA1_CONST(3);
+       d = ROTATE_LEFT(d, 30);
+
+       W(5) = ROTATE_LEFT((W(2) ^ W(13) ^ W(7) ^ W(5)), 1);            /* 69 */
+       a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(5) + SHA1_CONST(3);
+       c = ROTATE_LEFT(c, 30);
+
+       W(6) = ROTATE_LEFT((W(3) ^ W(14) ^ W(8) ^ W(6)), 1);            /* 70 */
+       e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(6) + SHA1_CONST(3);
+       b = ROTATE_LEFT(b, 30);
+
+       W(7) = ROTATE_LEFT((W(4) ^ W(15) ^ W(9) ^ W(7)), 1);            /* 71 */
+       d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(7) + SHA1_CONST(3);
+       a = ROTATE_LEFT(a, 30);
+
+       W(8) = ROTATE_LEFT((W(5) ^ W(0) ^ W(10) ^ W(8)), 1);            /* 72 */
+       c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(8) + SHA1_CONST(3);
+       e = ROTATE_LEFT(e, 30);
+
+       W(9) = ROTATE_LEFT((W(6) ^ W(1) ^ W(11) ^ W(9)), 1);            /* 73 */
+       b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(9) + SHA1_CONST(3);
+       d = ROTATE_LEFT(d, 30);
+
+       W(10) = ROTATE_LEFT((W(7) ^ W(2) ^ W(12) ^ W(10)), 1);  /* 74 */
+       a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(10) + SHA1_CONST(3);
+       c = ROTATE_LEFT(c, 30);
+
+       W(11) = ROTATE_LEFT((W(8) ^ W(3) ^ W(13) ^ W(11)), 1);  /* 75 */
+       e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(11) + SHA1_CONST(3);
+       b = ROTATE_LEFT(b, 30);
+
+       W(12) = ROTATE_LEFT((W(9) ^ W(4) ^ W(14) ^ W(12)), 1);  /* 76 */
+       d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(12) + SHA1_CONST(3);
+       a = ROTATE_LEFT(a, 30);
+
+       W(13) = ROTATE_LEFT((W(10) ^ W(5) ^ W(15) ^ W(13)), 1); /* 77 */
+       c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(13) + SHA1_CONST(3);
+       e = ROTATE_LEFT(e, 30);
+
+       W(14) = ROTATE_LEFT((W(11) ^ W(6) ^ W(0) ^ W(14)), 1);  /* 78 */
+       b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(14) + SHA1_CONST(3);
+       d = ROTATE_LEFT(d, 30);
+
+       W(15) = ROTATE_LEFT((W(12) ^ W(7) ^ W(1) ^ W(15)), 1);  /* 79 */
+
+       ctx->state[0] += ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(15) +
+           SHA1_CONST(3);
+       ctx->state[1] += b;
+       ctx->state[2] += ROTATE_LEFT(c, 30);
+       ctx->state[3] += d;
+       ctx->state[4] += e;
+
+       /* zeroize sensitive information */
+       W(0) = W(1) = W(2) = W(3) = W(4) = W(5) = W(6) = W(7) = W(8) = 0;
+       W(9) = W(10) = W(11) = W(12) = W(13) = W(14) = W(15) = 0;
+}
+#endif /* !__amd64 */
+
+
+/*
+ * Encode()
+ *
+ * purpose: to convert a list of numbers from little endian to big endian
+ *   input: uint8_t *  : place to store the converted big endian numbers
+ *         uint32_t *  : place to get numbers to convert from
+ *          size_t     : the length of the input in bytes
+ *  output: void
+ */
+
+static void
+Encode(uint8_t *_RESTRICT_KYWD output, const uint32_t *_RESTRICT_KYWD input,
+    size_t len)
+{
+       size_t          i, j;
+
+       for (i = 0, j = 0; j < len; i++, j += 4) {
+               output[j]       = (input[i] >> 24) & 0xff;
+               output[j + 1]   = (input[i] >> 16) & 0xff;
+               output[j + 2]   = (input[i] >>  8) & 0xff;
+               output[j + 3]   = input[i] & 0xff;
+       }
+}
diff --git a/zfs/module/icp/algs/sha2/sha2.c b/zfs/module/icp/algs/sha2/sha2.c
new file mode 100644 (file)
index 0000000..dbe0081
--- /dev/null
@@ -0,0 +1,960 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2013 Saso Kiselkov.  All rights reserved.
+ */
+
+/*
+ * The basic framework for this code came from the reference
+ * implementation for MD5.  That implementation is Copyright (C)
+ * 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * NOTE: Cleaned-up and optimized, version of SHA2, based on the FIPS 180-2
+ * standard, available at
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ * Not as fast as one would like -- further optimizations are encouraged
+ * and appreciated.
+ */
+
+#include <sys/zfs_context.h>
+#define        _SHA2_IMPL
+#include <sys/sha2.h>
+#include <sha2/sha2_consts.h>
+
+#define        _RESTRICT_KYWD
+
+#ifdef _LITTLE_ENDIAN
+#include <sys/byteorder.h>
+#define        HAVE_HTONL
+#endif
+#include <sys/isa_defs.h>      /* for _ILP32 */
+
+static void Encode(uint8_t *, uint32_t *, size_t);
+static void Encode64(uint8_t *, uint64_t *, size_t);
+
+#if    defined(__amd64)
+#define        SHA512Transform(ctx, in) SHA512TransformBlocks((ctx), (in), 1)
+#define        SHA256Transform(ctx, in) SHA256TransformBlocks((ctx), (in), 1)
+
+void SHA512TransformBlocks(SHA2_CTX *ctx, const void *in, size_t num);
+void SHA256TransformBlocks(SHA2_CTX *ctx, const void *in, size_t num);
+
+#else
+static void SHA256Transform(SHA2_CTX *, const uint8_t *);
+static void SHA512Transform(SHA2_CTX *, const uint8_t *);
+#endif /* __amd64 */
+
+static uint8_t PADDING[128] = { 0x80, /* all zeros */ };
+
+/*
+ * The low-level checksum routines use a lot of stack space. On systems where
+ * small stacks are enforced (like 32-bit kernel builds), insert compiler memory
+ * barriers to reduce stack frame size. This can reduce the SHA512Transform()
+ * stack frame usage from 3k to <1k on ARM32, for example.
+ */
+#if defined(_ILP32) || defined(__powerpc)      /* small stack */
+#define        SMALL_STACK_MEMORY_BARRIER      asm volatile("": : :"memory");
+#else
+#define        SMALL_STACK_MEMORY_BARRIER
+#endif
+
+/* Ch and Maj are the basic SHA2 functions. */
+#define        Ch(b, c, d)     (((b) & (c)) ^ ((~b) & (d)))
+#define        Maj(b, c, d)    (((b) & (c)) ^ ((b) & (d)) ^ ((c) & (d)))
+
+/* Rotates x right n bits. */
+#define        ROTR(x, n)      \
+       (((x) >> (n)) | ((x) << ((sizeof (x) * NBBY)-(n))))
+
+/* Shift x right n bits */
+#define        SHR(x, n)       ((x) >> (n))
+
+/* SHA256 Functions */
+#define        BIGSIGMA0_256(x)        (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22))
+#define        BIGSIGMA1_256(x)        (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25))
+#define        SIGMA0_256(x)           (ROTR((x), 7) ^ ROTR((x), 18) ^ SHR((x), 3))
+#define        SIGMA1_256(x)           (ROTR((x), 17) ^ ROTR((x), 19) ^ SHR((x), 10))
+
+#define        SHA256ROUND(a, b, c, d, e, f, g, h, i, w)                       \
+       T1 = h + BIGSIGMA1_256(e) + Ch(e, f, g) + SHA256_CONST(i) + w;  \
+       d += T1;                                                        \
+       T2 = BIGSIGMA0_256(a) + Maj(a, b, c);                           \
+       h = T1 + T2
+
+/* SHA384/512 Functions */
+#define        BIGSIGMA0(x)    (ROTR((x), 28) ^ ROTR((x), 34) ^ ROTR((x), 39))
+#define        BIGSIGMA1(x)    (ROTR((x), 14) ^ ROTR((x), 18) ^ ROTR((x), 41))
+#define        SIGMA0(x)       (ROTR((x), 1) ^ ROTR((x), 8) ^ SHR((x), 7))
+#define        SIGMA1(x)       (ROTR((x), 19) ^ ROTR((x), 61) ^ SHR((x), 6))
+#define        SHA512ROUND(a, b, c, d, e, f, g, h, i, w)                       \
+       T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + SHA512_CONST(i) + w;      \
+       d += T1;                                                        \
+       T2 = BIGSIGMA0(a) + Maj(a, b, c);                               \
+       h = T1 + T2;                                                    \
+       SMALL_STACK_MEMORY_BARRIER;
+
+/*
+ * sparc optimization:
+ *
+ * on the sparc, we can load big endian 32-bit data easily.  note that
+ * special care must be taken to ensure the address is 32-bit aligned.
+ * in the interest of speed, we don't check to make sure, since
+ * careful programming can guarantee this for us.
+ */
+
+#if    defined(_BIG_ENDIAN)
+#define        LOAD_BIG_32(addr)       (*(uint32_t *)(addr))
+#define        LOAD_BIG_64(addr)       (*(uint64_t *)(addr))
+
+#elif  defined(HAVE_HTONL)
+#define        LOAD_BIG_32(addr) htonl(*((uint32_t *)(addr)))
+#define        LOAD_BIG_64(addr) htonll(*((uint64_t *)(addr)))
+
+#else
+/* little endian -- will work on big endian, but slowly */
+#define        LOAD_BIG_32(addr)       \
+       (((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
+#define        LOAD_BIG_64(addr)       \
+       (((uint64_t)(addr)[0] << 56) | ((uint64_t)(addr)[1] << 48) |    \
+           ((uint64_t)(addr)[2] << 40) | ((uint64_t)(addr)[3] << 32) | \
+           ((uint64_t)(addr)[4] << 24) | ((uint64_t)(addr)[5] << 16) | \
+           ((uint64_t)(addr)[6] << 8) | (uint64_t)(addr)[7])
+#endif /* _BIG_ENDIAN */
+
+
+#if    !defined(__amd64)
+/* SHA256 Transform */
+
+static void
+SHA256Transform(SHA2_CTX *ctx, const uint8_t *blk)
+{
+       uint32_t a = ctx->state.s32[0];
+       uint32_t b = ctx->state.s32[1];
+       uint32_t c = ctx->state.s32[2];
+       uint32_t d = ctx->state.s32[3];
+       uint32_t e = ctx->state.s32[4];
+       uint32_t f = ctx->state.s32[5];
+       uint32_t g = ctx->state.s32[6];
+       uint32_t h = ctx->state.s32[7];
+
+       uint32_t w0, w1, w2, w3, w4, w5, w6, w7;
+       uint32_t w8, w9, w10, w11, w12, w13, w14, w15;
+       uint32_t T1, T2;
+
+#if    defined(__sparc)
+       static const uint32_t sha256_consts[] = {
+               SHA256_CONST_0, SHA256_CONST_1, SHA256_CONST_2,
+               SHA256_CONST_3, SHA256_CONST_4, SHA256_CONST_5,
+               SHA256_CONST_6, SHA256_CONST_7, SHA256_CONST_8,
+               SHA256_CONST_9, SHA256_CONST_10, SHA256_CONST_11,
+               SHA256_CONST_12, SHA256_CONST_13, SHA256_CONST_14,
+               SHA256_CONST_15, SHA256_CONST_16, SHA256_CONST_17,
+               SHA256_CONST_18, SHA256_CONST_19, SHA256_CONST_20,
+               SHA256_CONST_21, SHA256_CONST_22, SHA256_CONST_23,
+               SHA256_CONST_24, SHA256_CONST_25, SHA256_CONST_26,
+               SHA256_CONST_27, SHA256_CONST_28, SHA256_CONST_29,
+               SHA256_CONST_30, SHA256_CONST_31, SHA256_CONST_32,
+               SHA256_CONST_33, SHA256_CONST_34, SHA256_CONST_35,
+               SHA256_CONST_36, SHA256_CONST_37, SHA256_CONST_38,
+               SHA256_CONST_39, SHA256_CONST_40, SHA256_CONST_41,
+               SHA256_CONST_42, SHA256_CONST_43, SHA256_CONST_44,
+               SHA256_CONST_45, SHA256_CONST_46, SHA256_CONST_47,
+               SHA256_CONST_48, SHA256_CONST_49, SHA256_CONST_50,
+               SHA256_CONST_51, SHA256_CONST_52, SHA256_CONST_53,
+               SHA256_CONST_54, SHA256_CONST_55, SHA256_CONST_56,
+               SHA256_CONST_57, SHA256_CONST_58, SHA256_CONST_59,
+               SHA256_CONST_60, SHA256_CONST_61, SHA256_CONST_62,
+               SHA256_CONST_63
+       };
+#endif /* __sparc */
+
+       if ((uintptr_t)blk & 0x3) {             /* not 4-byte aligned? */
+               bcopy(blk, ctx->buf_un.buf32,  sizeof (ctx->buf_un.buf32));
+               blk = (uint8_t *)ctx->buf_un.buf32;
+       }
+
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w0 =  LOAD_BIG_32(blk + 4 * 0);
+       SHA256ROUND(a, b, c, d, e, f, g, h, 0, w0);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w1 =  LOAD_BIG_32(blk + 4 * 1);
+       SHA256ROUND(h, a, b, c, d, e, f, g, 1, w1);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w2 =  LOAD_BIG_32(blk + 4 * 2);
+       SHA256ROUND(g, h, a, b, c, d, e, f, 2, w2);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w3 =  LOAD_BIG_32(blk + 4 * 3);
+       SHA256ROUND(f, g, h, a, b, c, d, e, 3, w3);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w4 =  LOAD_BIG_32(blk + 4 * 4);
+       SHA256ROUND(e, f, g, h, a, b, c, d, 4, w4);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w5 =  LOAD_BIG_32(blk + 4 * 5);
+       SHA256ROUND(d, e, f, g, h, a, b, c, 5, w5);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w6 =  LOAD_BIG_32(blk + 4 * 6);
+       SHA256ROUND(c, d, e, f, g, h, a, b, 6, w6);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w7 =  LOAD_BIG_32(blk + 4 * 7);
+       SHA256ROUND(b, c, d, e, f, g, h, a, 7, w7);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w8 =  LOAD_BIG_32(blk + 4 * 8);
+       SHA256ROUND(a, b, c, d, e, f, g, h, 8, w8);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w9 =  LOAD_BIG_32(blk + 4 * 9);
+       SHA256ROUND(h, a, b, c, d, e, f, g, 9, w9);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w10 =  LOAD_BIG_32(blk + 4 * 10);
+       SHA256ROUND(g, h, a, b, c, d, e, f, 10, w10);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w11 =  LOAD_BIG_32(blk + 4 * 11);
+       SHA256ROUND(f, g, h, a, b, c, d, e, 11, w11);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w12 =  LOAD_BIG_32(blk + 4 * 12);
+       SHA256ROUND(e, f, g, h, a, b, c, d, 12, w12);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w13 =  LOAD_BIG_32(blk + 4 * 13);
+       SHA256ROUND(d, e, f, g, h, a, b, c, 13, w13);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w14 =  LOAD_BIG_32(blk + 4 * 14);
+       SHA256ROUND(c, d, e, f, g, h, a, b, 14, w14);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w15 =  LOAD_BIG_32(blk + 4 * 15);
+       SHA256ROUND(b, c, d, e, f, g, h, a, 15, w15);
+
+       w0 = SIGMA1_256(w14) + w9 + SIGMA0_256(w1) + w0;
+       SHA256ROUND(a, b, c, d, e, f, g, h, 16, w0);
+       w1 = SIGMA1_256(w15) + w10 + SIGMA0_256(w2) + w1;
+       SHA256ROUND(h, a, b, c, d, e, f, g, 17, w1);
+       w2 = SIGMA1_256(w0) + w11 + SIGMA0_256(w3) + w2;
+       SHA256ROUND(g, h, a, b, c, d, e, f, 18, w2);
+       w3 = SIGMA1_256(w1) + w12 + SIGMA0_256(w4) + w3;
+       SHA256ROUND(f, g, h, a, b, c, d, e, 19, w3);
+       w4 = SIGMA1_256(w2) + w13 + SIGMA0_256(w5) + w4;
+       SHA256ROUND(e, f, g, h, a, b, c, d, 20, w4);
+       w5 = SIGMA1_256(w3) + w14 + SIGMA0_256(w6) + w5;
+       SHA256ROUND(d, e, f, g, h, a, b, c, 21, w5);
+       w6 = SIGMA1_256(w4) + w15 + SIGMA0_256(w7) + w6;
+       SHA256ROUND(c, d, e, f, g, h, a, b, 22, w6);
+       w7 = SIGMA1_256(w5) + w0 + SIGMA0_256(w8) + w7;
+       SHA256ROUND(b, c, d, e, f, g, h, a, 23, w7);
+       w8 = SIGMA1_256(w6) + w1 + SIGMA0_256(w9) + w8;
+       SHA256ROUND(a, b, c, d, e, f, g, h, 24, w8);
+       w9 = SIGMA1_256(w7) + w2 + SIGMA0_256(w10) + w9;
+       SHA256ROUND(h, a, b, c, d, e, f, g, 25, w9);
+       w10 = SIGMA1_256(w8) + w3 + SIGMA0_256(w11) + w10;
+       SHA256ROUND(g, h, a, b, c, d, e, f, 26, w10);
+       w11 = SIGMA1_256(w9) + w4 + SIGMA0_256(w12) + w11;
+       SHA256ROUND(f, g, h, a, b, c, d, e, 27, w11);
+       w12 = SIGMA1_256(w10) + w5 + SIGMA0_256(w13) + w12;
+       SHA256ROUND(e, f, g, h, a, b, c, d, 28, w12);
+       w13 = SIGMA1_256(w11) + w6 + SIGMA0_256(w14) + w13;
+       SHA256ROUND(d, e, f, g, h, a, b, c, 29, w13);
+       w14 = SIGMA1_256(w12) + w7 + SIGMA0_256(w15) + w14;
+       SHA256ROUND(c, d, e, f, g, h, a, b, 30, w14);
+       w15 = SIGMA1_256(w13) + w8 + SIGMA0_256(w0) + w15;
+       SHA256ROUND(b, c, d, e, f, g, h, a, 31, w15);
+
+       w0 = SIGMA1_256(w14) + w9 + SIGMA0_256(w1) + w0;
+       SHA256ROUND(a, b, c, d, e, f, g, h, 32, w0);
+       w1 = SIGMA1_256(w15) + w10 + SIGMA0_256(w2) + w1;
+       SHA256ROUND(h, a, b, c, d, e, f, g, 33, w1);
+       w2 = SIGMA1_256(w0) + w11 + SIGMA0_256(w3) + w2;
+       SHA256ROUND(g, h, a, b, c, d, e, f, 34, w2);
+       w3 = SIGMA1_256(w1) + w12 + SIGMA0_256(w4) + w3;
+       SHA256ROUND(f, g, h, a, b, c, d, e, 35, w3);
+       w4 = SIGMA1_256(w2) + w13 + SIGMA0_256(w5) + w4;
+       SHA256ROUND(e, f, g, h, a, b, c, d, 36, w4);
+       w5 = SIGMA1_256(w3) + w14 + SIGMA0_256(w6) + w5;
+       SHA256ROUND(d, e, f, g, h, a, b, c, 37, w5);
+       w6 = SIGMA1_256(w4) + w15 + SIGMA0_256(w7) + w6;
+       SHA256ROUND(c, d, e, f, g, h, a, b, 38, w6);
+       w7 = SIGMA1_256(w5) + w0 + SIGMA0_256(w8) + w7;
+       SHA256ROUND(b, c, d, e, f, g, h, a, 39, w7);
+       w8 = SIGMA1_256(w6) + w1 + SIGMA0_256(w9) + w8;
+       SHA256ROUND(a, b, c, d, e, f, g, h, 40, w8);
+       w9 = SIGMA1_256(w7) + w2 + SIGMA0_256(w10) + w9;
+       SHA256ROUND(h, a, b, c, d, e, f, g, 41, w9);
+       w10 = SIGMA1_256(w8) + w3 + SIGMA0_256(w11) + w10;
+       SHA256ROUND(g, h, a, b, c, d, e, f, 42, w10);
+       w11 = SIGMA1_256(w9) + w4 + SIGMA0_256(w12) + w11;
+       SHA256ROUND(f, g, h, a, b, c, d, e, 43, w11);
+       w12 = SIGMA1_256(w10) + w5 + SIGMA0_256(w13) + w12;
+       SHA256ROUND(e, f, g, h, a, b, c, d, 44, w12);
+       w13 = SIGMA1_256(w11) + w6 + SIGMA0_256(w14) + w13;
+       SHA256ROUND(d, e, f, g, h, a, b, c, 45, w13);
+       w14 = SIGMA1_256(w12) + w7 + SIGMA0_256(w15) + w14;
+       SHA256ROUND(c, d, e, f, g, h, a, b, 46, w14);
+       w15 = SIGMA1_256(w13) + w8 + SIGMA0_256(w0) + w15;
+       SHA256ROUND(b, c, d, e, f, g, h, a, 47, w15);
+
+       w0 = SIGMA1_256(w14) + w9 + SIGMA0_256(w1) + w0;
+       SHA256ROUND(a, b, c, d, e, f, g, h, 48, w0);
+       w1 = SIGMA1_256(w15) + w10 + SIGMA0_256(w2) + w1;
+       SHA256ROUND(h, a, b, c, d, e, f, g, 49, w1);
+       w2 = SIGMA1_256(w0) + w11 + SIGMA0_256(w3) + w2;
+       SHA256ROUND(g, h, a, b, c, d, e, f, 50, w2);
+       w3 = SIGMA1_256(w1) + w12 + SIGMA0_256(w4) + w3;
+       SHA256ROUND(f, g, h, a, b, c, d, e, 51, w3);
+       w4 = SIGMA1_256(w2) + w13 + SIGMA0_256(w5) + w4;
+       SHA256ROUND(e, f, g, h, a, b, c, d, 52, w4);
+       w5 = SIGMA1_256(w3) + w14 + SIGMA0_256(w6) + w5;
+       SHA256ROUND(d, e, f, g, h, a, b, c, 53, w5);
+       w6 = SIGMA1_256(w4) + w15 + SIGMA0_256(w7) + w6;
+       SHA256ROUND(c, d, e, f, g, h, a, b, 54, w6);
+       w7 = SIGMA1_256(w5) + w0 + SIGMA0_256(w8) + w7;
+       SHA256ROUND(b, c, d, e, f, g, h, a, 55, w7);
+       w8 = SIGMA1_256(w6) + w1 + SIGMA0_256(w9) + w8;
+       SHA256ROUND(a, b, c, d, e, f, g, h, 56, w8);
+       w9 = SIGMA1_256(w7) + w2 + SIGMA0_256(w10) + w9;
+       SHA256ROUND(h, a, b, c, d, e, f, g, 57, w9);
+       w10 = SIGMA1_256(w8) + w3 + SIGMA0_256(w11) + w10;
+       SHA256ROUND(g, h, a, b, c, d, e, f, 58, w10);
+       w11 = SIGMA1_256(w9) + w4 + SIGMA0_256(w12) + w11;
+       SHA256ROUND(f, g, h, a, b, c, d, e, 59, w11);
+       w12 = SIGMA1_256(w10) + w5 + SIGMA0_256(w13) + w12;
+       SHA256ROUND(e, f, g, h, a, b, c, d, 60, w12);
+       w13 = SIGMA1_256(w11) + w6 + SIGMA0_256(w14) + w13;
+       SHA256ROUND(d, e, f, g, h, a, b, c, 61, w13);
+       w14 = SIGMA1_256(w12) + w7 + SIGMA0_256(w15) + w14;
+       SHA256ROUND(c, d, e, f, g, h, a, b, 62, w14);
+       w15 = SIGMA1_256(w13) + w8 + SIGMA0_256(w0) + w15;
+       SHA256ROUND(b, c, d, e, f, g, h, a, 63, w15);
+
+       ctx->state.s32[0] += a;
+       ctx->state.s32[1] += b;
+       ctx->state.s32[2] += c;
+       ctx->state.s32[3] += d;
+       ctx->state.s32[4] += e;
+       ctx->state.s32[5] += f;
+       ctx->state.s32[6] += g;
+       ctx->state.s32[7] += h;
+}
+
+
+/* SHA384 and SHA512 Transform */
+
+static void
+SHA512Transform(SHA2_CTX *ctx, const uint8_t *blk)
+{
+
+       uint64_t a = ctx->state.s64[0];
+       uint64_t b = ctx->state.s64[1];
+       uint64_t c = ctx->state.s64[2];
+       uint64_t d = ctx->state.s64[3];
+       uint64_t e = ctx->state.s64[4];
+       uint64_t f = ctx->state.s64[5];
+       uint64_t g = ctx->state.s64[6];
+       uint64_t h = ctx->state.s64[7];
+
+       uint64_t w0, w1, w2, w3, w4, w5, w6, w7;
+       uint64_t w8, w9, w10, w11, w12, w13, w14, w15;
+       uint64_t T1, T2;
+
+#if    defined(__sparc)
+       static const uint64_t sha512_consts[] = {
+               SHA512_CONST_0, SHA512_CONST_1, SHA512_CONST_2,
+               SHA512_CONST_3, SHA512_CONST_4, SHA512_CONST_5,
+               SHA512_CONST_6, SHA512_CONST_7, SHA512_CONST_8,
+               SHA512_CONST_9, SHA512_CONST_10, SHA512_CONST_11,
+               SHA512_CONST_12, SHA512_CONST_13, SHA512_CONST_14,
+               SHA512_CONST_15, SHA512_CONST_16, SHA512_CONST_17,
+               SHA512_CONST_18, SHA512_CONST_19, SHA512_CONST_20,
+               SHA512_CONST_21, SHA512_CONST_22, SHA512_CONST_23,
+               SHA512_CONST_24, SHA512_CONST_25, SHA512_CONST_26,
+               SHA512_CONST_27, SHA512_CONST_28, SHA512_CONST_29,
+               SHA512_CONST_30, SHA512_CONST_31, SHA512_CONST_32,
+               SHA512_CONST_33, SHA512_CONST_34, SHA512_CONST_35,
+               SHA512_CONST_36, SHA512_CONST_37, SHA512_CONST_38,
+               SHA512_CONST_39, SHA512_CONST_40, SHA512_CONST_41,
+               SHA512_CONST_42, SHA512_CONST_43, SHA512_CONST_44,
+               SHA512_CONST_45, SHA512_CONST_46, SHA512_CONST_47,
+               SHA512_CONST_48, SHA512_CONST_49, SHA512_CONST_50,
+               SHA512_CONST_51, SHA512_CONST_52, SHA512_CONST_53,
+               SHA512_CONST_54, SHA512_CONST_55, SHA512_CONST_56,
+               SHA512_CONST_57, SHA512_CONST_58, SHA512_CONST_59,
+               SHA512_CONST_60, SHA512_CONST_61, SHA512_CONST_62,
+               SHA512_CONST_63, SHA512_CONST_64, SHA512_CONST_65,
+               SHA512_CONST_66, SHA512_CONST_67, SHA512_CONST_68,
+               SHA512_CONST_69, SHA512_CONST_70, SHA512_CONST_71,
+               SHA512_CONST_72, SHA512_CONST_73, SHA512_CONST_74,
+               SHA512_CONST_75, SHA512_CONST_76, SHA512_CONST_77,
+               SHA512_CONST_78, SHA512_CONST_79
+       };
+#endif /* __sparc */
+
+
+       if ((uintptr_t)blk & 0x7) {             /* not 8-byte aligned? */
+               bcopy(blk, ctx->buf_un.buf64,  sizeof (ctx->buf_un.buf64));
+               blk = (uint8_t *)ctx->buf_un.buf64;
+       }
+
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w0 =  LOAD_BIG_64(blk + 8 * 0);
+       SHA512ROUND(a, b, c, d, e, f, g, h, 0, w0);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w1 =  LOAD_BIG_64(blk + 8 * 1);
+       SHA512ROUND(h, a, b, c, d, e, f, g, 1, w1);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w2 =  LOAD_BIG_64(blk + 8 * 2);
+       SHA512ROUND(g, h, a, b, c, d, e, f, 2, w2);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w3 =  LOAD_BIG_64(blk + 8 * 3);
+       SHA512ROUND(f, g, h, a, b, c, d, e, 3, w3);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w4 =  LOAD_BIG_64(blk + 8 * 4);
+       SHA512ROUND(e, f, g, h, a, b, c, d, 4, w4);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w5 =  LOAD_BIG_64(blk + 8 * 5);
+       SHA512ROUND(d, e, f, g, h, a, b, c, 5, w5);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w6 =  LOAD_BIG_64(blk + 8 * 6);
+       SHA512ROUND(c, d, e, f, g, h, a, b, 6, w6);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w7 =  LOAD_BIG_64(blk + 8 * 7);
+       SHA512ROUND(b, c, d, e, f, g, h, a, 7, w7);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w8 =  LOAD_BIG_64(blk + 8 * 8);
+       SHA512ROUND(a, b, c, d, e, f, g, h, 8, w8);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w9 =  LOAD_BIG_64(blk + 8 * 9);
+       SHA512ROUND(h, a, b, c, d, e, f, g, 9, w9);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w10 =  LOAD_BIG_64(blk + 8 * 10);
+       SHA512ROUND(g, h, a, b, c, d, e, f, 10, w10);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w11 =  LOAD_BIG_64(blk + 8 * 11);
+       SHA512ROUND(f, g, h, a, b, c, d, e, 11, w11);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w12 =  LOAD_BIG_64(blk + 8 * 12);
+       SHA512ROUND(e, f, g, h, a, b, c, d, 12, w12);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w13 =  LOAD_BIG_64(blk + 8 * 13);
+       SHA512ROUND(d, e, f, g, h, a, b, c, 13, w13);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w14 =  LOAD_BIG_64(blk + 8 * 14);
+       SHA512ROUND(c, d, e, f, g, h, a, b, 14, w14);
+       /* LINTED E_BAD_PTR_CAST_ALIGN */
+       w15 =  LOAD_BIG_64(blk + 8 * 15);
+       SHA512ROUND(b, c, d, e, f, g, h, a, 15, w15);
+
+       w0 = SIGMA1(w14) + w9 + SIGMA0(w1) + w0;
+       SHA512ROUND(a, b, c, d, e, f, g, h, 16, w0);
+       w1 = SIGMA1(w15) + w10 + SIGMA0(w2) + w1;
+       SHA512ROUND(h, a, b, c, d, e, f, g, 17, w1);
+       w2 = SIGMA1(w0) + w11 + SIGMA0(w3) + w2;
+       SHA512ROUND(g, h, a, b, c, d, e, f, 18, w2);
+       w3 = SIGMA1(w1) + w12 + SIGMA0(w4) + w3;
+       SHA512ROUND(f, g, h, a, b, c, d, e, 19, w3);
+       w4 = SIGMA1(w2) + w13 + SIGMA0(w5) + w4;
+       SHA512ROUND(e, f, g, h, a, b, c, d, 20, w4);
+       w5 = SIGMA1(w3) + w14 + SIGMA0(w6) + w5;
+       SHA512ROUND(d, e, f, g, h, a, b, c, 21, w5);
+       w6 = SIGMA1(w4) + w15 + SIGMA0(w7) + w6;
+       SHA512ROUND(c, d, e, f, g, h, a, b, 22, w6);
+       w7 = SIGMA1(w5) + w0 + SIGMA0(w8) + w7;
+       SHA512ROUND(b, c, d, e, f, g, h, a, 23, w7);
+       w8 = SIGMA1(w6) + w1 + SIGMA0(w9) + w8;
+       SHA512ROUND(a, b, c, d, e, f, g, h, 24, w8);
+       w9 = SIGMA1(w7) + w2 + SIGMA0(w10) + w9;
+       SHA512ROUND(h, a, b, c, d, e, f, g, 25, w9);
+       w10 = SIGMA1(w8) + w3 + SIGMA0(w11) + w10;
+       SHA512ROUND(g, h, a, b, c, d, e, f, 26, w10);
+       w11 = SIGMA1(w9) + w4 + SIGMA0(w12) + w11;
+       SHA512ROUND(f, g, h, a, b, c, d, e, 27, w11);
+       w12 = SIGMA1(w10) + w5 + SIGMA0(w13) + w12;
+       SHA512ROUND(e, f, g, h, a, b, c, d, 28, w12);
+       w13 = SIGMA1(w11) + w6 + SIGMA0(w14) + w13;
+       SHA512ROUND(d, e, f, g, h, a, b, c, 29, w13);
+       w14 = SIGMA1(w12) + w7 + SIGMA0(w15) + w14;
+       SHA512ROUND(c, d, e, f, g, h, a, b, 30, w14);
+       w15 = SIGMA1(w13) + w8 + SIGMA0(w0) + w15;
+       SHA512ROUND(b, c, d, e, f, g, h, a, 31, w15);
+
+       w0 = SIGMA1(w14) + w9 + SIGMA0(w1) + w0;
+       SHA512ROUND(a, b, c, d, e, f, g, h, 32, w0);
+       w1 = SIGMA1(w15) + w10 + SIGMA0(w2) + w1;
+       SHA512ROUND(h, a, b, c, d, e, f, g, 33, w1);
+       w2 = SIGMA1(w0) + w11 + SIGMA0(w3) + w2;
+       SHA512ROUND(g, h, a, b, c, d, e, f, 34, w2);
+       w3 = SIGMA1(w1) + w12 + SIGMA0(w4) + w3;
+       SHA512ROUND(f, g, h, a, b, c, d, e, 35, w3);
+       w4 = SIGMA1(w2) + w13 + SIGMA0(w5) + w4;
+       SHA512ROUND(e, f, g, h, a, b, c, d, 36, w4);
+       w5 = SIGMA1(w3) + w14 + SIGMA0(w6) + w5;
+       SHA512ROUND(d, e, f, g, h, a, b, c, 37, w5);
+       w6 = SIGMA1(w4) + w15 + SIGMA0(w7) + w6;
+       SHA512ROUND(c, d, e, f, g, h, a, b, 38, w6);
+       w7 = SIGMA1(w5) + w0 + SIGMA0(w8) + w7;
+       SHA512ROUND(b, c, d, e, f, g, h, a, 39, w7);
+       w8 = SIGMA1(w6) + w1 + SIGMA0(w9) + w8;
+       SHA512ROUND(a, b, c, d, e, f, g, h, 40, w8);
+       w9 = SIGMA1(w7) + w2 + SIGMA0(w10) + w9;
+       SHA512ROUND(h, a, b, c, d, e, f, g, 41, w9);
+       w10 = SIGMA1(w8) + w3 + SIGMA0(w11) + w10;
+       SHA512ROUND(g, h, a, b, c, d, e, f, 42, w10);
+       w11 = SIGMA1(w9) + w4 + SIGMA0(w12) + w11;
+       SHA512ROUND(f, g, h, a, b, c, d, e, 43, w11);
+       w12 = SIGMA1(w10) + w5 + SIGMA0(w13) + w12;
+       SHA512ROUND(e, f, g, h, a, b, c, d, 44, w12);
+       w13 = SIGMA1(w11) + w6 + SIGMA0(w14) + w13;
+       SHA512ROUND(d, e, f, g, h, a, b, c, 45, w13);
+       w14 = SIGMA1(w12) + w7 + SIGMA0(w15) + w14;
+       SHA512ROUND(c, d, e, f, g, h, a, b, 46, w14);
+       w15 = SIGMA1(w13) + w8 + SIGMA0(w0) + w15;
+       SHA512ROUND(b, c, d, e, f, g, h, a, 47, w15);
+
+       w0 = SIGMA1(w14) + w9 + SIGMA0(w1) + w0;
+       SHA512ROUND(a, b, c, d, e, f, g, h, 48, w0);
+       w1 = SIGMA1(w15) + w10 + SIGMA0(w2) + w1;
+       SHA512ROUND(h, a, b, c, d, e, f, g, 49, w1);
+       w2 = SIGMA1(w0) + w11 + SIGMA0(w3) + w2;
+       SHA512ROUND(g, h, a, b, c, d, e, f, 50, w2);
+       w3 = SIGMA1(w1) + w12 + SIGMA0(w4) + w3;
+       SHA512ROUND(f, g, h, a, b, c, d, e, 51, w3);
+       w4 = SIGMA1(w2) + w13 + SIGMA0(w5) + w4;
+       SHA512ROUND(e, f, g, h, a, b, c, d, 52, w4);
+       w5 = SIGMA1(w3) + w14 + SIGMA0(w6) + w5;
+       SHA512ROUND(d, e, f, g, h, a, b, c, 53, w5);
+       w6 = SIGMA1(w4) + w15 + SIGMA0(w7) + w6;
+       SHA512ROUND(c, d, e, f, g, h, a, b, 54, w6);
+       w7 = SIGMA1(w5) + w0 + SIGMA0(w8) + w7;
+       SHA512ROUND(b, c, d, e, f, g, h, a, 55, w7);
+       w8 = SIGMA1(w6) + w1 + SIGMA0(w9) + w8;
+       SHA512ROUND(a, b, c, d, e, f, g, h, 56, w8);
+       w9 = SIGMA1(w7) + w2 + SIGMA0(w10) + w9;
+       SHA512ROUND(h, a, b, c, d, e, f, g, 57, w9);
+       w10 = SIGMA1(w8) + w3 + SIGMA0(w11) + w10;
+       SHA512ROUND(g, h, a, b, c, d, e, f, 58, w10);
+       w11 = SIGMA1(w9) + w4 + SIGMA0(w12) + w11;
+       SHA512ROUND(f, g, h, a, b, c, d, e, 59, w11);
+       w12 = SIGMA1(w10) + w5 + SIGMA0(w13) + w12;
+       SHA512ROUND(e, f, g, h, a, b, c, d, 60, w12);
+       w13 = SIGMA1(w11) + w6 + SIGMA0(w14) + w13;
+       SHA512ROUND(d, e, f, g, h, a, b, c, 61, w13);
+       w14 = SIGMA1(w12) + w7 + SIGMA0(w15) + w14;
+       SHA512ROUND(c, d, e, f, g, h, a, b, 62, w14);
+       w15 = SIGMA1(w13) + w8 + SIGMA0(w0) + w15;
+       SHA512ROUND(b, c, d, e, f, g, h, a, 63, w15);
+
+       w0 = SIGMA1(w14) + w9 + SIGMA0(w1) + w0;
+       SHA512ROUND(a, b, c, d, e, f, g, h, 64, w0);
+       w1 = SIGMA1(w15) + w10 + SIGMA0(w2) + w1;
+       SHA512ROUND(h, a, b, c, d, e, f, g, 65, w1);
+       w2 = SIGMA1(w0) + w11 + SIGMA0(w3) + w2;
+       SHA512ROUND(g, h, a, b, c, d, e, f, 66, w2);
+       w3 = SIGMA1(w1) + w12 + SIGMA0(w4) + w3;
+       SHA512ROUND(f, g, h, a, b, c, d, e, 67, w3);
+       w4 = SIGMA1(w2) + w13 + SIGMA0(w5) + w4;
+       SHA512ROUND(e, f, g, h, a, b, c, d, 68, w4);
+       w5 = SIGMA1(w3) + w14 + SIGMA0(w6) + w5;
+       SHA512ROUND(d, e, f, g, h, a, b, c, 69, w5);
+       w6 = SIGMA1(w4) + w15 + SIGMA0(w7) + w6;
+       SHA512ROUND(c, d, e, f, g, h, a, b, 70, w6);
+       w7 = SIGMA1(w5) + w0 + SIGMA0(w8) + w7;
+       SHA512ROUND(b, c, d, e, f, g, h, a, 71, w7);
+       w8 = SIGMA1(w6) + w1 + SIGMA0(w9) + w8;
+       SHA512ROUND(a, b, c, d, e, f, g, h, 72, w8);
+       w9 = SIGMA1(w7) + w2 + SIGMA0(w10) + w9;
+       SHA512ROUND(h, a, b, c, d, e, f, g, 73, w9);
+       w10 = SIGMA1(w8) + w3 + SIGMA0(w11) + w10;
+       SHA512ROUND(g, h, a, b, c, d, e, f, 74, w10);
+       w11 = SIGMA1(w9) + w4 + SIGMA0(w12) + w11;
+       SHA512ROUND(f, g, h, a, b, c, d, e, 75, w11);
+       w12 = SIGMA1(w10) + w5 + SIGMA0(w13) + w12;
+       SHA512ROUND(e, f, g, h, a, b, c, d, 76, w12);
+       w13 = SIGMA1(w11) + w6 + SIGMA0(w14) + w13;
+       SHA512ROUND(d, e, f, g, h, a, b, c, 77, w13);
+       w14 = SIGMA1(w12) + w7 + SIGMA0(w15) + w14;
+       SHA512ROUND(c, d, e, f, g, h, a, b, 78, w14);
+       w15 = SIGMA1(w13) + w8 + SIGMA0(w0) + w15;
+       SHA512ROUND(b, c, d, e, f, g, h, a, 79, w15);
+
+       ctx->state.s64[0] += a;
+       ctx->state.s64[1] += b;
+       ctx->state.s64[2] += c;
+       ctx->state.s64[3] += d;
+       ctx->state.s64[4] += e;
+       ctx->state.s64[5] += f;
+       ctx->state.s64[6] += g;
+       ctx->state.s64[7] += h;
+
+}
+#endif /* !__amd64 */
+
+
+/*
+ * Encode()
+ *
+ * purpose: to convert a list of numbers from little endian to big endian
+ *   input: uint8_t *  : place to store the converted big endian numbers
+ *         uint32_t *  : place to get numbers to convert from
+ *          size_t     : the length of the input in bytes
+ *  output: void
+ */
+
+static void
+Encode(uint8_t *_RESTRICT_KYWD output, uint32_t *_RESTRICT_KYWD input,
+    size_t len)
+{
+       size_t          i, j;
+
+#if    defined(__sparc)
+       if (IS_P2ALIGNED(output, sizeof (uint32_t))) {
+               for (i = 0, j = 0; j < len; i++, j += 4) {
+                       /* LINTED E_BAD_PTR_CAST_ALIGN */
+                       *((uint32_t *)(output + j)) = input[i];
+               }
+       } else {
+#endif /* little endian -- will work on big endian, but slowly */
+               for (i = 0, j = 0; j < len; i++, j += 4) {
+                       output[j]       = (input[i] >> 24) & 0xff;
+                       output[j + 1]   = (input[i] >> 16) & 0xff;
+                       output[j + 2]   = (input[i] >>  8) & 0xff;
+                       output[j + 3]   = input[i] & 0xff;
+               }
+#if    defined(__sparc)
+       }
+#endif
+}
+
+static void
+Encode64(uint8_t *_RESTRICT_KYWD output, uint64_t *_RESTRICT_KYWD input,
+    size_t len)
+{
+       size_t          i, j;
+
+#if    defined(__sparc)
+       if (IS_P2ALIGNED(output, sizeof (uint64_t))) {
+               for (i = 0, j = 0; j < len; i++, j += 8) {
+                       /* LINTED E_BAD_PTR_CAST_ALIGN */
+                       *((uint64_t *)(output + j)) = input[i];
+               }
+       } else {
+#endif /* little endian -- will work on big endian, but slowly */
+               for (i = 0, j = 0; j < len; i++, j += 8) {
+
+                       output[j]       = (input[i] >> 56) & 0xff;
+                       output[j + 1]   = (input[i] >> 48) & 0xff;
+                       output[j + 2]   = (input[i] >> 40) & 0xff;
+                       output[j + 3]   = (input[i] >> 32) & 0xff;
+                       output[j + 4]   = (input[i] >> 24) & 0xff;
+                       output[j + 5]   = (input[i] >> 16) & 0xff;
+                       output[j + 6]   = (input[i] >>  8) & 0xff;
+                       output[j + 7]   = input[i] & 0xff;
+               }
+#if    defined(__sparc)
+       }
+#endif
+}
+
+
+void
+SHA2Init(uint64_t mech, SHA2_CTX *ctx)
+{
+
+       switch (mech) {
+       case SHA256_MECH_INFO_TYPE:
+       case SHA256_HMAC_MECH_INFO_TYPE:
+       case SHA256_HMAC_GEN_MECH_INFO_TYPE:
+               ctx->state.s32[0] = 0x6a09e667U;
+               ctx->state.s32[1] = 0xbb67ae85U;
+               ctx->state.s32[2] = 0x3c6ef372U;
+               ctx->state.s32[3] = 0xa54ff53aU;
+               ctx->state.s32[4] = 0x510e527fU;
+               ctx->state.s32[5] = 0x9b05688cU;
+               ctx->state.s32[6] = 0x1f83d9abU;
+               ctx->state.s32[7] = 0x5be0cd19U;
+               break;
+       case SHA384_MECH_INFO_TYPE:
+       case SHA384_HMAC_MECH_INFO_TYPE:
+       case SHA384_HMAC_GEN_MECH_INFO_TYPE:
+               ctx->state.s64[0] = 0xcbbb9d5dc1059ed8ULL;
+               ctx->state.s64[1] = 0x629a292a367cd507ULL;
+               ctx->state.s64[2] = 0x9159015a3070dd17ULL;
+               ctx->state.s64[3] = 0x152fecd8f70e5939ULL;
+               ctx->state.s64[4] = 0x67332667ffc00b31ULL;
+               ctx->state.s64[5] = 0x8eb44a8768581511ULL;
+               ctx->state.s64[6] = 0xdb0c2e0d64f98fa7ULL;
+               ctx->state.s64[7] = 0x47b5481dbefa4fa4ULL;
+               break;
+       case SHA512_MECH_INFO_TYPE:
+       case SHA512_HMAC_MECH_INFO_TYPE:
+       case SHA512_HMAC_GEN_MECH_INFO_TYPE:
+               ctx->state.s64[0] = 0x6a09e667f3bcc908ULL;
+               ctx->state.s64[1] = 0xbb67ae8584caa73bULL;
+               ctx->state.s64[2] = 0x3c6ef372fe94f82bULL;
+               ctx->state.s64[3] = 0xa54ff53a5f1d36f1ULL;
+               ctx->state.s64[4] = 0x510e527fade682d1ULL;
+               ctx->state.s64[5] = 0x9b05688c2b3e6c1fULL;
+               ctx->state.s64[6] = 0x1f83d9abfb41bd6bULL;
+               ctx->state.s64[7] = 0x5be0cd19137e2179ULL;
+               break;
+       case SHA512_224_MECH_INFO_TYPE:
+               ctx->state.s64[0] = 0x8C3D37C819544DA2ULL;
+               ctx->state.s64[1] = 0x73E1996689DCD4D6ULL;
+               ctx->state.s64[2] = 0x1DFAB7AE32FF9C82ULL;
+               ctx->state.s64[3] = 0x679DD514582F9FCFULL;
+               ctx->state.s64[4] = 0x0F6D2B697BD44DA8ULL;
+               ctx->state.s64[5] = 0x77E36F7304C48942ULL;
+               ctx->state.s64[6] = 0x3F9D85A86A1D36C8ULL;
+               ctx->state.s64[7] = 0x1112E6AD91D692A1ULL;
+               break;
+       case SHA512_256_MECH_INFO_TYPE:
+               ctx->state.s64[0] = 0x22312194FC2BF72CULL;
+               ctx->state.s64[1] = 0x9F555FA3C84C64C2ULL;
+               ctx->state.s64[2] = 0x2393B86B6F53B151ULL;
+               ctx->state.s64[3] = 0x963877195940EABDULL;
+               ctx->state.s64[4] = 0x96283EE2A88EFFE3ULL;
+               ctx->state.s64[5] = 0xBE5E1E2553863992ULL;
+               ctx->state.s64[6] = 0x2B0199FC2C85B8AAULL;
+               ctx->state.s64[7] = 0x0EB72DDC81C52CA2ULL;
+               break;
+#ifdef _KERNEL
+       default:
+               cmn_err(CE_PANIC,
+                   "sha2_init: failed to find a supported algorithm: 0x%x",
+                   (uint32_t)mech);
+
+#endif /* _KERNEL */
+       }
+
+       ctx->algotype = (uint32_t)mech;
+       ctx->count.c64[0] = ctx->count.c64[1] = 0;
+}
+
+#ifndef _KERNEL
+
+// #pragma inline(SHA256Init, SHA384Init, SHA512Init)
+void
+SHA256Init(SHA256_CTX *ctx)
+{
+       SHA2Init(SHA256, ctx);
+}
+
+void
+SHA384Init(SHA384_CTX *ctx)
+{
+       SHA2Init(SHA384, ctx);
+}
+
+void
+SHA512Init(SHA512_CTX *ctx)
+{
+       SHA2Init(SHA512, ctx);
+}
+
+#endif /* _KERNEL */
+
+/*
+ * SHA2Update()
+ *
+ * purpose: continues an sha2 digest operation, using the message block
+ *          to update the context.
+ *   input: SHA2_CTX * : the context to update
+ *          void *     : the message block
+ *          size_t      : the length of the message block, in bytes
+ *  output: void
+ */
+
+void
+SHA2Update(SHA2_CTX *ctx, const void *inptr, size_t input_len)
+{
+       uint32_t        i, buf_index, buf_len, buf_limit;
+       const uint8_t   *input = inptr;
+       uint32_t        algotype = ctx->algotype;
+#if defined(__amd64)
+       uint32_t        block_count;
+#endif /* !__amd64 */
+
+
+       /* check for noop */
+       if (input_len == 0)
+               return;
+
+       if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
+               buf_limit = 64;
+
+               /* compute number of bytes mod 64 */
+               buf_index = (ctx->count.c32[1] >> 3) & 0x3F;
+
+               /* update number of bits */
+               if ((ctx->count.c32[1] += (input_len << 3)) < (input_len << 3))
+                       ctx->count.c32[0]++;
+
+               ctx->count.c32[0] += (input_len >> 29);
+
+       } else {
+               buf_limit = 128;
+
+               /* compute number of bytes mod 128 */
+               buf_index = (ctx->count.c64[1] >> 3) & 0x7F;
+
+               /* update number of bits */
+               if ((ctx->count.c64[1] += (input_len << 3)) < (input_len << 3))
+                       ctx->count.c64[0]++;
+
+               ctx->count.c64[0] += (input_len >> 29);
+       }
+
+       buf_len = buf_limit - buf_index;
+
+       /* transform as many times as possible */
+       i = 0;
+       if (input_len >= buf_len) {
+
+               /*
+                * general optimization:
+                *
+                * only do initial bcopy() and SHA2Transform() if
+                * buf_index != 0.  if buf_index == 0, we're just
+                * wasting our time doing the bcopy() since there
+                * wasn't any data left over from a previous call to
+                * SHA2Update().
+                */
+               if (buf_index) {
+                       bcopy(input, &ctx->buf_un.buf8[buf_index], buf_len);
+                       if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE)
+                               SHA256Transform(ctx, ctx->buf_un.buf8);
+                       else
+                               SHA512Transform(ctx, ctx->buf_un.buf8);
+
+                       i = buf_len;
+               }
+
+#if !defined(__amd64)
+               if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
+                       for (; i + buf_limit - 1 < input_len; i += buf_limit) {
+                               SHA256Transform(ctx, &input[i]);
+                       }
+               } else {
+                       for (; i + buf_limit - 1 < input_len; i += buf_limit) {
+                               SHA512Transform(ctx, &input[i]);
+                       }
+               }
+
+#else
+               if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
+                       block_count = (input_len - i) >> 6;
+                       if (block_count > 0) {
+                               SHA256TransformBlocks(ctx, &input[i],
+                                   block_count);
+                               i += block_count << 6;
+                       }
+               } else {
+                       block_count = (input_len - i) >> 7;
+                       if (block_count > 0) {
+                               SHA512TransformBlocks(ctx, &input[i],
+                                   block_count);
+                               i += block_count << 7;
+                       }
+               }
+#endif /* !__amd64 */
+
+               /*
+                * general optimization:
+                *
+                * if i and input_len are the same, return now instead
+                * of calling bcopy(), since the bcopy() in this case
+                * will be an expensive noop.
+                */
+
+               if (input_len == i)
+                       return;
+
+               buf_index = 0;
+       }
+
+       /* buffer remaining input */
+       bcopy(&input[i], &ctx->buf_un.buf8[buf_index], input_len - i);
+}
+
+
+/*
+ * SHA2Final()
+ *
+ * purpose: ends an sha2 digest operation, finalizing the message digest and
+ *          zeroing the context.
+ *   input: uchar_t *  : a buffer to store the digest
+ *                     : The function actually uses void* because many
+ *                     : callers pass things other than uchar_t here.
+ *          SHA2_CTX *  : the context to finalize, save, and zero
+ *  output: void
+ */
+
+void
+SHA2Final(void *digest, SHA2_CTX *ctx)
+{
+       uint8_t         bitcount_be[sizeof (ctx->count.c32)];
+       uint8_t         bitcount_be64[sizeof (ctx->count.c64)];
+       uint32_t        index;
+       uint32_t        algotype = ctx->algotype;
+
+       if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
+               index  = (ctx->count.c32[1] >> 3) & 0x3f;
+               Encode(bitcount_be, ctx->count.c32, sizeof (bitcount_be));
+               SHA2Update(ctx, PADDING, ((index < 56) ? 56 : 120) - index);
+               SHA2Update(ctx, bitcount_be, sizeof (bitcount_be));
+               Encode(digest, ctx->state.s32, sizeof (ctx->state.s32));
+       } else {
+               index  = (ctx->count.c64[1] >> 3) & 0x7f;
+               Encode64(bitcount_be64, ctx->count.c64,
+                   sizeof (bitcount_be64));
+               SHA2Update(ctx, PADDING, ((index < 112) ? 112 : 240) - index);
+               SHA2Update(ctx, bitcount_be64, sizeof (bitcount_be64));
+               if (algotype <= SHA384_HMAC_GEN_MECH_INFO_TYPE) {
+                       ctx->state.s64[6] = ctx->state.s64[7] = 0;
+                       Encode64(digest, ctx->state.s64,
+                           sizeof (uint64_t) * 6);
+               } else if (algotype == SHA512_224_MECH_INFO_TYPE) {
+                       uint8_t last[sizeof (uint64_t)];
+                       /*
+                        * Since SHA-512/224 doesn't align well to 64-bit
+                        * boundaries, we must do the encoding in three steps:
+                        * 1) encode the three 64-bit words that fit neatly
+                        * 2) encode the last 64-bit word to a temp buffer
+                        * 3) chop out the lower 32-bits from the temp buffer
+                        *    and append them to the digest
+                        */
+                       Encode64(digest, ctx->state.s64, sizeof (uint64_t) * 3);
+                       Encode64(last, &ctx->state.s64[3], sizeof (uint64_t));
+                       bcopy(last, (uint8_t *)digest + 24, 4);
+               } else if (algotype == SHA512_256_MECH_INFO_TYPE) {
+                       Encode64(digest, ctx->state.s64, sizeof (uint64_t) * 4);
+               } else {
+                       Encode64(digest, ctx->state.s64,
+                           sizeof (ctx->state.s64));
+               }
+       }
+
+       /* zeroize sensitive information */
+       bzero(ctx, sizeof (*ctx));
+}
+
+
+
+#ifdef _KERNEL
+EXPORT_SYMBOL(SHA2Init);
+EXPORT_SYMBOL(SHA2Update);
+EXPORT_SYMBOL(SHA2Final);
+#endif
diff --git a/zfs/module/icp/algs/skein/THIRDPARTYLICENSE b/zfs/module/icp/algs/skein/THIRDPARTYLICENSE
new file mode 100644 (file)
index 0000000..b7434fd
--- /dev/null
@@ -0,0 +1,3 @@
+Implementation of the Skein hash function.
+Source code author: Doug Whiting, 2008.
+This algorithm and source code is released to the public domain.
diff --git a/zfs/module/icp/algs/skein/THIRDPARTYLICENSE.descrip b/zfs/module/icp/algs/skein/THIRDPARTYLICENSE.descrip
new file mode 100644 (file)
index 0000000..0ae89cf
--- /dev/null
@@ -0,0 +1 @@
+LICENSE TERMS OF SKEIN HASH ALGORITHM IMPLEMENTATION
diff --git a/zfs/module/icp/algs/skein/skein.c b/zfs/module/icp/algs/skein/skein.c
new file mode 100644 (file)
index 0000000..0981eee
--- /dev/null
@@ -0,0 +1,921 @@
+/*
+ * Implementation of the Skein hash function.
+ * Source code author: Doug Whiting, 2008.
+ * This algorithm and source code is released to the public domain.
+ */
+/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
+
+#define        SKEIN_PORT_CODE         /* instantiate any code in skein_port.h */
+
+#include <sys/types.h>
+#include <sys/note.h>
+#include <sys/skein.h>         /* get the Skein API definitions   */
+#include "skein_impl.h"                /* get internal definitions */
+
+/* External function to process blkCnt (nonzero) full block(s) of data. */
+void Skein_256_Process_Block(Skein_256_Ctxt_t *ctx, const uint8_t *blkPtr,
+    size_t blkCnt, size_t byteCntAdd);
+void Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
+    size_t blkCnt, size_t byteCntAdd);
+void Skein1024_Process_Block(Skein1024_Ctxt_t *ctx, const uint8_t *blkPtr,
+    size_t blkCnt, size_t byteCntAdd);
+
+/* 256-bit Skein */
+/* init the context for a straight hashing operation  */
+int
+Skein_256_Init(Skein_256_Ctxt_t *ctx, size_t hashBitLen)
+{
+       union {
+               uint8_t b[SKEIN_256_STATE_BYTES];
+               uint64_t w[SKEIN_256_STATE_WORDS];
+       } cfg;                  /* config block */
+
+       Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
+       ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
+
+       switch (hashBitLen) {   /* use pre-computed values, where available */
+#ifndef        SKEIN_NO_PRECOMP
+       case 256:
+               bcopy(SKEIN_256_IV_256, ctx->X, sizeof (ctx->X));
+               break;
+       case 224:
+               bcopy(SKEIN_256_IV_224, ctx->X, sizeof (ctx->X));
+               break;
+       case 160:
+               bcopy(SKEIN_256_IV_160, ctx->X, sizeof (ctx->X));
+               break;
+       case 128:
+               bcopy(SKEIN_256_IV_128, ctx->X, sizeof (ctx->X));
+               break;
+#endif
+       default:
+               /* here if there is no precomputed IV value available */
+               /*
+                * build/process the config block, type == CONFIG (could be
+                * precomputed)
+                */
+               /* set tweaks: T0=0; T1=CFG | FINAL */
+               Skein_Start_New_Type(ctx, CFG_FINAL);
+
+               /* set the schema, version */
+               cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+               /* hash result length in bits */
+               cfg.w[1] = Skein_Swap64(hashBitLen);
+               cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
+               /* zero pad config block */
+               bzero(&cfg.w[3], sizeof (cfg) - 3 * sizeof (cfg.w[0]));
+
+               /* compute the initial chaining values from config block */
+               /* zero the chaining variables */
+               bzero(ctx->X, sizeof (ctx->X));
+               Skein_256_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
+               break;
+       }
+       /*
+        * The chaining vars ctx->X are now initialized for the given
+        * hashBitLen.
+        * Set up to process the data message portion of the hash (default)
+        */
+       Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */
+
+       return (SKEIN_SUCCESS);
+}
+
+/* init the context for a MAC and/or tree hash operation */
+/*
+ * [identical to Skein_256_Init() when keyBytes == 0 &&
+ * treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL]
+ */
+int
+Skein_256_InitExt(Skein_256_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
+    const uint8_t *key, size_t keyBytes)
+{
+       union {
+               uint8_t b[SKEIN_256_STATE_BYTES];
+               uint64_t w[SKEIN_256_STATE_WORDS];
+       } cfg;                  /* config block */
+
+       Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
+       Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL);
+
+       /* compute the initial chaining values ctx->X[], based on key */
+       if (keyBytes == 0) {    /* is there a key? */
+               /* no key: use all zeroes as key for config block */
+               bzero(ctx->X, sizeof (ctx->X));
+       } else {                /* here to pre-process a key */
+
+               Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));
+               /* do a mini-Init right here */
+               /* set output hash bit count = state size */
+               ctx->h.hashBitLen = 8 * sizeof (ctx->X);
+               /* set tweaks: T0 = 0; T1 = KEY type */
+               Skein_Start_New_Type(ctx, KEY);
+               /* zero the initial chaining variables */
+               bzero(ctx->X, sizeof (ctx->X));
+               /* hash the key */
+               (void) Skein_256_Update(ctx, key, keyBytes);
+               /* put result into cfg.b[] */
+               (void) Skein_256_Final_Pad(ctx, cfg.b);
+               /* copy over into ctx->X[] */
+               bcopy(cfg.b, ctx->X, sizeof (cfg.b));
+#if    SKEIN_NEED_SWAP
+               {
+                       uint_t i;
+                       /* convert key bytes to context words */
+                       for (i = 0; i < SKEIN_256_STATE_WORDS; i++)
+                               ctx->X[i] = Skein_Swap64(ctx->X[i]);
+               }
+#endif
+       }
+       /*
+        * build/process the config block, type == CONFIG (could be
+        * precomputed for each key)
+        */
+       ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
+       Skein_Start_New_Type(ctx, CFG_FINAL);
+
+       bzero(&cfg.w, sizeof (cfg.w));  /* pre-pad cfg.w[] with zeroes */
+       cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+       cfg.w[1] = Skein_Swap64(hashBitLen);    /* hash result length in bits */
+       /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
+       cfg.w[2] = Skein_Swap64(treeInfo);
+
+       Skein_Show_Key(256, &ctx->h, key, keyBytes);
+
+       /* compute the initial chaining values from config block */
+       Skein_256_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
+
+       /* The chaining vars ctx->X are now initialized */
+       /* Set up to process the data message portion of the hash (default) */
+       ctx->h.bCnt = 0;        /* buffer b[] starts out empty */
+       Skein_Start_New_Type(ctx, MSG);
+
+       return (SKEIN_SUCCESS);
+}
+
+/* process the input bytes */
+int
+Skein_256_Update(Skein_256_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)
+{
+       size_t n;
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
+
+       /* process full blocks, if any */
+       if (msgByteCnt + ctx->h.bCnt > SKEIN_256_BLOCK_BYTES) {
+               /* finish up any buffered message data */
+               if (ctx->h.bCnt) {
+                       /* # bytes free in buffer b[] */
+                       n = SKEIN_256_BLOCK_BYTES - ctx->h.bCnt;
+                       if (n) {
+                               /* check on our logic here */
+                               Skein_assert(n < msgByteCnt);
+                               bcopy(msg, &ctx->b[ctx->h.bCnt], n);
+                               msgByteCnt -= n;
+                               msg += n;
+                               ctx->h.bCnt += n;
+                       }
+                       Skein_assert(ctx->h.bCnt == SKEIN_256_BLOCK_BYTES);
+                       Skein_256_Process_Block(ctx, ctx->b, 1,
+                           SKEIN_256_BLOCK_BYTES);
+                       ctx->h.bCnt = 0;
+               }
+               /*
+                * now process any remaining full blocks, directly from input
+                * message data
+                */
+               if (msgByteCnt > SKEIN_256_BLOCK_BYTES) {
+                       /* number of full blocks to process */
+                       n = (msgByteCnt - 1) / SKEIN_256_BLOCK_BYTES;
+                       Skein_256_Process_Block(ctx, msg, n,
+                           SKEIN_256_BLOCK_BYTES);
+                       msgByteCnt -= n * SKEIN_256_BLOCK_BYTES;
+                       msg += n * SKEIN_256_BLOCK_BYTES;
+               }
+               Skein_assert(ctx->h.bCnt == 0);
+       }
+
+       /* copy any remaining source message data bytes into b[] */
+       if (msgByteCnt) {
+               Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES);
+               bcopy(msg, &ctx->b[ctx->h.bCnt], msgByteCnt);
+               ctx->h.bCnt += msgByteCnt;
+       }
+
+       return (SKEIN_SUCCESS);
+}
+
+/* finalize the hash computation and output the result */
+int
+Skein_256_Final(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       size_t i, n, byteCnt;
+       uint64_t X[SKEIN_256_STATE_WORDS];
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
+
+       ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;     /* tag as the final block */
+       /* zero pad b[] if necessary */
+       if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)
+               bzero(&ctx->b[ctx->h.bCnt],
+                   SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
+
+       /* process the final block */
+       Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
+
+       /* now output the result */
+       /* total number of output bytes */
+       byteCnt = (ctx->h.hashBitLen + 7) >> 3;
+
+       /* run Threefish in "counter mode" to generate output */
+       /* zero out b[], so it can hold the counter */
+       bzero(ctx->b, sizeof (ctx->b));
+       /* keep a local copy of counter mode "key" */
+       bcopy(ctx->X, X, sizeof (X));
+       for (i = 0; i * SKEIN_256_BLOCK_BYTES < byteCnt; i++) {
+               /* build the counter block */
+               uint64_t tmp = Skein_Swap64((uint64_t)i);
+               bcopy(&tmp, ctx->b, sizeof (tmp));
+               Skein_Start_New_Type(ctx, OUT_FINAL);
+               /* run "counter mode" */
+               Skein_256_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
+               /* number of output bytes left to go */
+               n = byteCnt - i * SKEIN_256_BLOCK_BYTES;
+               if (n >= SKEIN_256_BLOCK_BYTES)
+                       n = SKEIN_256_BLOCK_BYTES;
+               Skein_Put64_LSB_First(hashVal + i * SKEIN_256_BLOCK_BYTES,
+                   ctx->X, n); /* "output" the ctr mode bytes */
+               Skein_Show_Final(256, &ctx->h, n,
+                   hashVal + i * SKEIN_256_BLOCK_BYTES);
+               /* restore the counter mode key for next time */
+               bcopy(X, ctx->X, sizeof (X));
+       }
+       return (SKEIN_SUCCESS);
+}
+
+/* 512-bit Skein */
+
+/* init the context for a straight hashing operation  */
+int
+Skein_512_Init(Skein_512_Ctxt_t *ctx, size_t hashBitLen)
+{
+       union {
+               uint8_t b[SKEIN_512_STATE_BYTES];
+               uint64_t w[SKEIN_512_STATE_WORDS];
+       } cfg;                  /* config block */
+
+       Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
+       ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
+
+       switch (hashBitLen) {   /* use pre-computed values, where available */
+#ifndef        SKEIN_NO_PRECOMP
+       case 512:
+               bcopy(SKEIN_512_IV_512, ctx->X, sizeof (ctx->X));
+               break;
+       case 384:
+               bcopy(SKEIN_512_IV_384, ctx->X, sizeof (ctx->X));
+               break;
+       case 256:
+               bcopy(SKEIN_512_IV_256, ctx->X, sizeof (ctx->X));
+               break;
+       case 224:
+               bcopy(SKEIN_512_IV_224, ctx->X, sizeof (ctx->X));
+               break;
+#endif
+       default:
+               /*
+                * here if there is no precomputed IV value available
+                * build/process the config block, type == CONFIG (could be
+                * precomputed)
+                */
+               /* set tweaks: T0=0; T1=CFG | FINAL */
+               Skein_Start_New_Type(ctx, CFG_FINAL);
+
+               /* set the schema, version */
+               cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+               /* hash result length in bits */
+               cfg.w[1] = Skein_Swap64(hashBitLen);
+               cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
+               /* zero pad config block */
+               bzero(&cfg.w[3], sizeof (cfg) - 3 * sizeof (cfg.w[0]));
+
+               /* compute the initial chaining values from config block */
+               /* zero the chaining variables */
+               bzero(ctx->X, sizeof (ctx->X));
+               Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
+               break;
+       }
+
+       /*
+        * The chaining vars ctx->X are now initialized for the given
+        * hashBitLen. Set up to process the data message portion of the
+        * hash (default)
+        */
+       Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */
+
+       return (SKEIN_SUCCESS);
+}
+
+/* init the context for a MAC and/or tree hash operation */
+/*
+ * [identical to Skein_512_Init() when keyBytes == 0 &&
+ * treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL]
+ */
+int
+Skein_512_InitExt(Skein_512_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
+    const uint8_t *key, size_t keyBytes)
+{
+       union {
+               uint8_t b[SKEIN_512_STATE_BYTES];
+               uint64_t w[SKEIN_512_STATE_WORDS];
+       } cfg;                  /* config block */
+
+       Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
+       Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL);
+
+       /* compute the initial chaining values ctx->X[], based on key */
+       if (keyBytes == 0) {    /* is there a key? */
+               /* no key: use all zeroes as key for config block */
+               bzero(ctx->X, sizeof (ctx->X));
+       } else {                /* here to pre-process a key */
+
+               Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));
+               /* do a mini-Init right here */
+               /* set output hash bit count = state size */
+               ctx->h.hashBitLen = 8 * sizeof (ctx->X);
+               /* set tweaks: T0 = 0; T1 = KEY type */
+               Skein_Start_New_Type(ctx, KEY);
+               /* zero the initial chaining variables */
+               bzero(ctx->X, sizeof (ctx->X));
+               (void) Skein_512_Update(ctx, key, keyBytes); /* hash the key */
+               /* put result into cfg.b[] */
+               (void) Skein_512_Final_Pad(ctx, cfg.b);
+               /* copy over into ctx->X[] */
+               bcopy(cfg.b, ctx->X, sizeof (cfg.b));
+#if    SKEIN_NEED_SWAP
+               {
+                       uint_t i;
+                       /* convert key bytes to context words */
+                       for (i = 0; i < SKEIN_512_STATE_WORDS; i++)
+                               ctx->X[i] = Skein_Swap64(ctx->X[i]);
+               }
+#endif
+       }
+       /*
+        * build/process the config block, type == CONFIG (could be
+        * precomputed for each key)
+        */
+       ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
+       Skein_Start_New_Type(ctx, CFG_FINAL);
+
+       bzero(&cfg.w, sizeof (cfg.w));  /* pre-pad cfg.w[] with zeroes */
+       cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+       cfg.w[1] = Skein_Swap64(hashBitLen);    /* hash result length in bits */
+       /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
+       cfg.w[2] = Skein_Swap64(treeInfo);
+
+       Skein_Show_Key(512, &ctx->h, key, keyBytes);
+
+       /* compute the initial chaining values from config block */
+       Skein_512_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
+
+       /* The chaining vars ctx->X are now initialized */
+       /* Set up to process the data message portion of the hash (default) */
+       ctx->h.bCnt = 0;        /* buffer b[] starts out empty */
+       Skein_Start_New_Type(ctx, MSG);
+
+       return (SKEIN_SUCCESS);
+}
+
+/* process the input bytes */
+int
+Skein_512_Update(Skein_512_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)
+{
+       size_t n;
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
+
+       /* process full blocks, if any */
+       if (msgByteCnt + ctx->h.bCnt > SKEIN_512_BLOCK_BYTES) {
+               /* finish up any buffered message data */
+               if (ctx->h.bCnt) {
+                       /* # bytes free in buffer b[] */
+                       n = SKEIN_512_BLOCK_BYTES - ctx->h.bCnt;
+                       if (n) {
+                               /* check on our logic here */
+                               Skein_assert(n < msgByteCnt);
+                               bcopy(msg, &ctx->b[ctx->h.bCnt], n);
+                               msgByteCnt -= n;
+                               msg += n;
+                               ctx->h.bCnt += n;
+                       }
+                       Skein_assert(ctx->h.bCnt == SKEIN_512_BLOCK_BYTES);
+                       Skein_512_Process_Block(ctx, ctx->b, 1,
+                           SKEIN_512_BLOCK_BYTES);
+                       ctx->h.bCnt = 0;
+               }
+               /*
+                * now process any remaining full blocks, directly from input
+                * message data
+                */
+               if (msgByteCnt > SKEIN_512_BLOCK_BYTES) {
+                       /* number of full blocks to process */
+                       n = (msgByteCnt - 1) / SKEIN_512_BLOCK_BYTES;
+                       Skein_512_Process_Block(ctx, msg, n,
+                           SKEIN_512_BLOCK_BYTES);
+                       msgByteCnt -= n * SKEIN_512_BLOCK_BYTES;
+                       msg += n * SKEIN_512_BLOCK_BYTES;
+               }
+               Skein_assert(ctx->h.bCnt == 0);
+       }
+
+       /* copy any remaining source message data bytes into b[] */
+       if (msgByteCnt) {
+               Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES);
+               bcopy(msg, &ctx->b[ctx->h.bCnt], msgByteCnt);
+               ctx->h.bCnt += msgByteCnt;
+       }
+
+       return (SKEIN_SUCCESS);
+}
+
+/* finalize the hash computation and output the result */
+int
+Skein_512_Final(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       size_t i, n, byteCnt;
+       uint64_t X[SKEIN_512_STATE_WORDS];
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
+
+       ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;     /* tag as the final block */
+       /* zero pad b[] if necessary */
+       if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)
+               bzero(&ctx->b[ctx->h.bCnt],
+                   SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
+
+       /* process the final block */
+       Skein_512_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
+
+       /* now output the result */
+       /* total number of output bytes */
+       byteCnt = (ctx->h.hashBitLen + 7) >> 3;
+
+       /* run Threefish in "counter mode" to generate output */
+       /* zero out b[], so it can hold the counter */
+       bzero(ctx->b, sizeof (ctx->b));
+       /* keep a local copy of counter mode "key" */
+       bcopy(ctx->X, X, sizeof (X));
+       for (i = 0; i * SKEIN_512_BLOCK_BYTES < byteCnt; i++) {
+               /* build the counter block */
+               uint64_t tmp = Skein_Swap64((uint64_t)i);
+               bcopy(&tmp, ctx->b, sizeof (tmp));
+               Skein_Start_New_Type(ctx, OUT_FINAL);
+               /* run "counter mode" */
+               Skein_512_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
+               /* number of output bytes left to go */
+               n = byteCnt - i * SKEIN_512_BLOCK_BYTES;
+               if (n >= SKEIN_512_BLOCK_BYTES)
+                       n = SKEIN_512_BLOCK_BYTES;
+               Skein_Put64_LSB_First(hashVal + i * SKEIN_512_BLOCK_BYTES,
+                   ctx->X, n); /* "output" the ctr mode bytes */
+               Skein_Show_Final(512, &ctx->h, n,
+                   hashVal + i * SKEIN_512_BLOCK_BYTES);
+               /* restore the counter mode key for next time */
+               bcopy(X, ctx->X, sizeof (X));
+       }
+       return (SKEIN_SUCCESS);
+}
+
+/* 1024-bit Skein */
+
+/* init the context for a straight hashing operation  */
+int
+Skein1024_Init(Skein1024_Ctxt_t *ctx, size_t hashBitLen)
+{
+       union {
+               uint8_t b[SKEIN1024_STATE_BYTES];
+               uint64_t w[SKEIN1024_STATE_WORDS];
+       } cfg;                  /* config block */
+
+       Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
+       ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
+
+       switch (hashBitLen) {   /* use pre-computed values, where available */
+#ifndef        SKEIN_NO_PRECOMP
+       case 512:
+               bcopy(SKEIN1024_IV_512, ctx->X, sizeof (ctx->X));
+               break;
+       case 384:
+               bcopy(SKEIN1024_IV_384, ctx->X, sizeof (ctx->X));
+               break;
+       case 1024:
+               bcopy(SKEIN1024_IV_1024, ctx->X, sizeof (ctx->X));
+               break;
+#endif
+       default:
+               /* here if there is no precomputed IV value available */
+               /*
+                * build/process the config block, type == CONFIG (could be
+                * precomputed)
+                */
+               /* set tweaks: T0=0; T1=CFG | FINAL */
+               Skein_Start_New_Type(ctx, CFG_FINAL);
+
+               /* set the schema, version */
+               cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+               /* hash result length in bits */
+               cfg.w[1] = Skein_Swap64(hashBitLen);
+               cfg.w[2] = Skein_Swap64(SKEIN_CFG_TREE_INFO_SEQUENTIAL);
+               /* zero pad config block */
+               bzero(&cfg.w[3], sizeof (cfg) - 3 * sizeof (cfg.w[0]));
+
+               /* compute the initial chaining values from config block */
+               /* zero the chaining variables */
+               bzero(ctx->X, sizeof (ctx->X));
+               Skein1024_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
+               break;
+       }
+
+       /*
+        * The chaining vars ctx->X are now initialized for the given
+        * hashBitLen. Set up to process the data message portion of the hash
+        * (default)
+        */
+       Skein_Start_New_Type(ctx, MSG); /* T0=0, T1= MSG type */
+
+       return (SKEIN_SUCCESS);
+}
+
+/* init the context for a MAC and/or tree hash operation */
+/*
+ * [identical to Skein1024_Init() when keyBytes == 0 &&
+ * treeInfo == SKEIN_CFG_TREE_INFO_SEQUENTIAL]
+ */
+int
+Skein1024_InitExt(Skein1024_Ctxt_t *ctx, size_t hashBitLen, uint64_t treeInfo,
+    const uint8_t *key, size_t keyBytes)
+{
+       union {
+               uint8_t b[SKEIN1024_STATE_BYTES];
+               uint64_t w[SKEIN1024_STATE_WORDS];
+       } cfg;                  /* config block */
+
+       Skein_Assert(hashBitLen > 0, SKEIN_BAD_HASHLEN);
+       Skein_Assert(keyBytes == 0 || key != NULL, SKEIN_FAIL);
+
+       /* compute the initial chaining values ctx->X[], based on key */
+       if (keyBytes == 0) {    /* is there a key? */
+               /* no key: use all zeroes as key for config block */
+               bzero(ctx->X, sizeof (ctx->X));
+       } else {                /* here to pre-process a key */
+               Skein_assert(sizeof (cfg.b) >= sizeof (ctx->X));
+               /* do a mini-Init right here */
+               /* set output hash bit count = state size */
+               ctx->h.hashBitLen = 8 * sizeof (ctx->X);
+               /* set tweaks: T0 = 0; T1 = KEY type */
+               Skein_Start_New_Type(ctx, KEY);
+               /* zero the initial chaining variables */
+               bzero(ctx->X, sizeof (ctx->X));
+               (void) Skein1024_Update(ctx, key, keyBytes); /* hash the key */
+               /* put result into cfg.b[] */
+               (void) Skein1024_Final_Pad(ctx, cfg.b);
+               /* copy over into ctx->X[] */
+               bcopy(cfg.b, ctx->X, sizeof (cfg.b));
+#if    SKEIN_NEED_SWAP
+               {
+                       uint_t i;
+                       /* convert key bytes to context words */
+                       for (i = 0; i < SKEIN1024_STATE_WORDS; i++)
+                               ctx->X[i] = Skein_Swap64(ctx->X[i]);
+               }
+#endif
+       }
+       /*
+        * build/process the config block, type == CONFIG (could be
+        * precomputed for each key)
+        */
+       ctx->h.hashBitLen = hashBitLen; /* output hash bit count */
+       Skein_Start_New_Type(ctx, CFG_FINAL);
+
+       bzero(&cfg.w, sizeof (cfg.w));  /* pre-pad cfg.w[] with zeroes */
+       cfg.w[0] = Skein_Swap64(SKEIN_SCHEMA_VER);
+       /* hash result length in bits */
+       cfg.w[1] = Skein_Swap64(hashBitLen);
+       /* tree hash config info (or SKEIN_CFG_TREE_INFO_SEQUENTIAL) */
+       cfg.w[2] = Skein_Swap64(treeInfo);
+
+       Skein_Show_Key(1024, &ctx->h, key, keyBytes);
+
+       /* compute the initial chaining values from config block */
+       Skein1024_Process_Block(ctx, cfg.b, 1, SKEIN_CFG_STR_LEN);
+
+       /* The chaining vars ctx->X are now initialized */
+       /* Set up to process the data message portion of the hash (default) */
+       ctx->h.bCnt = 0;        /* buffer b[] starts out empty */
+       Skein_Start_New_Type(ctx, MSG);
+
+       return (SKEIN_SUCCESS);
+}
+
+/* process the input bytes */
+int
+Skein1024_Update(Skein1024_Ctxt_t *ctx, const uint8_t *msg, size_t msgByteCnt)
+{
+       size_t n;
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);
+
+       /* process full blocks, if any */
+       if (msgByteCnt + ctx->h.bCnt > SKEIN1024_BLOCK_BYTES) {
+               /* finish up any buffered message data */
+               if (ctx->h.bCnt) {
+                       /* # bytes free in buffer b[] */
+                       n = SKEIN1024_BLOCK_BYTES - ctx->h.bCnt;
+                       if (n) {
+                               /* check on our logic here */
+                               Skein_assert(n < msgByteCnt);
+                               bcopy(msg, &ctx->b[ctx->h.bCnt], n);
+                               msgByteCnt -= n;
+                               msg += n;
+                               ctx->h.bCnt += n;
+                       }
+                       Skein_assert(ctx->h.bCnt == SKEIN1024_BLOCK_BYTES);
+                       Skein1024_Process_Block(ctx, ctx->b, 1,
+                           SKEIN1024_BLOCK_BYTES);
+                       ctx->h.bCnt = 0;
+               }
+               /*
+                * now process any remaining full blocks, directly from
+                * input message data
+                */
+               if (msgByteCnt > SKEIN1024_BLOCK_BYTES) {
+                       /* number of full blocks to process */
+                       n = (msgByteCnt - 1) / SKEIN1024_BLOCK_BYTES;
+                       Skein1024_Process_Block(ctx, msg, n,
+                           SKEIN1024_BLOCK_BYTES);
+                       msgByteCnt -= n * SKEIN1024_BLOCK_BYTES;
+                       msg += n * SKEIN1024_BLOCK_BYTES;
+               }
+               Skein_assert(ctx->h.bCnt == 0);
+       }
+
+       /* copy any remaining source message data bytes into b[] */
+       if (msgByteCnt) {
+               Skein_assert(msgByteCnt + ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES);
+               bcopy(msg, &ctx->b[ctx->h.bCnt], msgByteCnt);
+               ctx->h.bCnt += msgByteCnt;
+       }
+
+       return (SKEIN_SUCCESS);
+}
+
+/* finalize the hash computation and output the result */
+int
+Skein1024_Final(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       size_t i, n, byteCnt;
+       uint64_t X[SKEIN1024_STATE_WORDS];
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);
+
+       ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;     /* tag as the final block */
+       /* zero pad b[] if necessary */
+       if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)
+               bzero(&ctx->b[ctx->h.bCnt],
+                   SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
+
+       /* process the final block */
+       Skein1024_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
+
+       /* now output the result */
+       /* total number of output bytes */
+       byteCnt = (ctx->h.hashBitLen + 7) >> 3;
+
+       /* run Threefish in "counter mode" to generate output */
+       /* zero out b[], so it can hold the counter */
+       bzero(ctx->b, sizeof (ctx->b));
+       /* keep a local copy of counter mode "key" */
+       bcopy(ctx->X, X, sizeof (X));
+       for (i = 0; i * SKEIN1024_BLOCK_BYTES < byteCnt; i++) {
+               /* build the counter block */
+               uint64_t tmp = Skein_Swap64((uint64_t)i);
+               bcopy(&tmp, ctx->b, sizeof (tmp));
+               Skein_Start_New_Type(ctx, OUT_FINAL);
+               /* run "counter mode" */
+               Skein1024_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
+               /* number of output bytes left to go */
+               n = byteCnt - i * SKEIN1024_BLOCK_BYTES;
+               if (n >= SKEIN1024_BLOCK_BYTES)
+                       n = SKEIN1024_BLOCK_BYTES;
+               Skein_Put64_LSB_First(hashVal + i * SKEIN1024_BLOCK_BYTES,
+                   ctx->X, n); /* "output" the ctr mode bytes */
+               Skein_Show_Final(1024, &ctx->h, n,
+                   hashVal + i * SKEIN1024_BLOCK_BYTES);
+               /* restore the counter mode key for next time */
+               bcopy(X, ctx->X, sizeof (X));
+       }
+       return (SKEIN_SUCCESS);
+}
+
+/* Functions to support MAC/tree hashing */
+/* (this code is identical for Optimized and Reference versions) */
+
+/* finalize the hash computation and output the block, no OUTPUT stage */
+int
+Skein_256_Final_Pad(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
+
+       ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;     /* tag as the final block */
+       /* zero pad b[] if necessary */
+       if (ctx->h.bCnt < SKEIN_256_BLOCK_BYTES)
+               bzero(&ctx->b[ctx->h.bCnt],
+                   SKEIN_256_BLOCK_BYTES - ctx->h.bCnt);
+       /* process the final block */
+       Skein_256_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
+
+       /* "output" the state bytes */
+       Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_256_BLOCK_BYTES);
+
+       return (SKEIN_SUCCESS);
+}
+
+/* finalize the hash computation and output the block, no OUTPUT stage */
+int
+Skein_512_Final_Pad(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
+
+       ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;     /* tag as the final block */
+       /* zero pad b[] if necessary */
+       if (ctx->h.bCnt < SKEIN_512_BLOCK_BYTES)
+               bzero(&ctx->b[ctx->h.bCnt],
+                   SKEIN_512_BLOCK_BYTES - ctx->h.bCnt);
+       /* process the final block */
+       Skein_512_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
+
+       /* "output" the state bytes */
+       Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN_512_BLOCK_BYTES);
+
+       return (SKEIN_SUCCESS);
+}
+
+/* finalize the hash computation and output the block, no OUTPUT stage */
+int
+Skein1024_Final_Pad(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);
+
+       /* tag as the final block */
+       ctx->h.T[1] |= SKEIN_T1_FLAG_FINAL;
+       /* zero pad b[] if necessary */
+       if (ctx->h.bCnt < SKEIN1024_BLOCK_BYTES)
+               bzero(&ctx->b[ctx->h.bCnt],
+                   SKEIN1024_BLOCK_BYTES - ctx->h.bCnt);
+       /* process the final block */
+       Skein1024_Process_Block(ctx, ctx->b, 1, ctx->h.bCnt);
+
+       /* "output" the state bytes */
+       Skein_Put64_LSB_First(hashVal, ctx->X, SKEIN1024_BLOCK_BYTES);
+
+       return (SKEIN_SUCCESS);
+}
+
+#if    SKEIN_TREE_HASH
+/* just do the OUTPUT stage */
+int
+Skein_256_Output(Skein_256_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       size_t i, n, byteCnt;
+       uint64_t X[SKEIN_256_STATE_WORDS];
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN_256_BLOCK_BYTES, SKEIN_FAIL);
+
+       /* now output the result */
+       /* total number of output bytes */
+       byteCnt = (ctx->h.hashBitLen + 7) >> 3;
+
+       /* run Threefish in "counter mode" to generate output */
+       /* zero out b[], so it can hold the counter */
+       bzero(ctx->b, sizeof (ctx->b));
+       /* keep a local copy of counter mode "key" */
+       bcopy(ctx->X, X, sizeof (X));
+       for (i = 0; i * SKEIN_256_BLOCK_BYTES < byteCnt; i++) {
+               /* build the counter block */
+               uint64_t tmp = Skein_Swap64((uint64_t)i);
+               bcopy(&tmp, ctx->b, sizeof (tmp));
+               Skein_Start_New_Type(ctx, OUT_FINAL);
+               /* run "counter mode" */
+               Skein_256_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
+               /* number of output bytes left to go */
+               n = byteCnt - i * SKEIN_256_BLOCK_BYTES;
+               if (n >= SKEIN_256_BLOCK_BYTES)
+                       n = SKEIN_256_BLOCK_BYTES;
+               Skein_Put64_LSB_First(hashVal + i * SKEIN_256_BLOCK_BYTES,
+                   ctx->X, n); /* "output" the ctr mode bytes */
+               Skein_Show_Final(256, &ctx->h, n,
+                   hashVal + i * SKEIN_256_BLOCK_BYTES);
+               /* restore the counter mode key for next time */
+               bcopy(X, ctx->X, sizeof (X));
+       }
+       return (SKEIN_SUCCESS);
+}
+
+/* just do the OUTPUT stage */
+int
+Skein_512_Output(Skein_512_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       size_t i, n, byteCnt;
+       uint64_t X[SKEIN_512_STATE_WORDS];
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN_512_BLOCK_BYTES, SKEIN_FAIL);
+
+       /* now output the result */
+       /* total number of output bytes */
+       byteCnt = (ctx->h.hashBitLen + 7) >> 3;
+
+       /* run Threefish in "counter mode" to generate output */
+       /* zero out b[], so it can hold the counter */
+       bzero(ctx->b, sizeof (ctx->b));
+       /* keep a local copy of counter mode "key" */
+       bcopy(ctx->X, X, sizeof (X));
+       for (i = 0; i * SKEIN_512_BLOCK_BYTES < byteCnt; i++) {
+               /* build the counter block */
+               uint64_t tmp = Skein_Swap64((uint64_t)i);
+               bcopy(&tmp, ctx->b, sizeof (tmp));
+               Skein_Start_New_Type(ctx, OUT_FINAL);
+               /* run "counter mode" */
+               Skein_512_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
+               /* number of output bytes left to go */
+               n = byteCnt - i * SKEIN_512_BLOCK_BYTES;
+               if (n >= SKEIN_512_BLOCK_BYTES)
+                       n = SKEIN_512_BLOCK_BYTES;
+               Skein_Put64_LSB_First(hashVal + i * SKEIN_512_BLOCK_BYTES,
+                   ctx->X, n); /* "output" the ctr mode bytes */
+               Skein_Show_Final(256, &ctx->h, n,
+                   hashVal + i * SKEIN_512_BLOCK_BYTES);
+               /* restore the counter mode key for next time */
+               bcopy(X, ctx->X, sizeof (X));
+       }
+       return (SKEIN_SUCCESS);
+}
+
+/* just do the OUTPUT stage */
+int
+Skein1024_Output(Skein1024_Ctxt_t *ctx, uint8_t *hashVal)
+{
+       size_t i, n, byteCnt;
+       uint64_t X[SKEIN1024_STATE_WORDS];
+
+       /* catch uninitialized context */
+       Skein_Assert(ctx->h.bCnt <= SKEIN1024_BLOCK_BYTES, SKEIN_FAIL);
+
+       /* now output the result */
+       /* total number of output bytes */
+       byteCnt = (ctx->h.hashBitLen + 7) >> 3;
+
+       /* run Threefish in "counter mode" to generate output */
+       /* zero out b[], so it can hold the counter */
+       bzero(ctx->b, sizeof (ctx->b));
+       /* keep a local copy of counter mode "key" */
+       bcopy(ctx->X, X, sizeof (X));
+       for (i = 0; i * SKEIN1024_BLOCK_BYTES < byteCnt; i++) {
+               /* build the counter block */
+               uint64_t tmp = Skein_Swap64((uint64_t)i);
+               bcopy(&tmp, ctx->b, sizeof (tmp));
+               Skein_Start_New_Type(ctx, OUT_FINAL);
+               /* run "counter mode" */
+               Skein1024_Process_Block(ctx, ctx->b, 1, sizeof (uint64_t));
+               /* number of output bytes left to go */
+               n = byteCnt - i * SKEIN1024_BLOCK_BYTES;
+               if (n >= SKEIN1024_BLOCK_BYTES)
+                       n = SKEIN1024_BLOCK_BYTES;
+               Skein_Put64_LSB_First(hashVal + i * SKEIN1024_BLOCK_BYTES,
+                   ctx->X, n); /* "output" the ctr mode bytes */
+               Skein_Show_Final(256, &ctx->h, n,
+                   hashVal + i * SKEIN1024_BLOCK_BYTES);
+               /* restore the counter mode key for next time */
+               bcopy(X, ctx->X, sizeof (X));
+       }
+       return (SKEIN_SUCCESS);
+}
+#endif
+
+#ifdef _KERNEL
+EXPORT_SYMBOL(Skein_512_Init);
+EXPORT_SYMBOL(Skein_512_InitExt);
+EXPORT_SYMBOL(Skein_512_Update);
+EXPORT_SYMBOL(Skein_512_Final);
+#endif
diff --git a/zfs/module/icp/algs/skein/skein_block.c b/zfs/module/icp/algs/skein/skein_block.c
new file mode 100644 (file)
index 0000000..d2e8119
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * Implementation of the Skein block functions.
+ * Source code author: Doug Whiting, 2008.
+ * This algorithm and source code is released to the public domain.
+ * Compile-time switches:
+ *  SKEIN_USE_ASM  -- set bits (256/512/1024) to select which
+ *                    versions use ASM code for block processing
+ *                    [default: use C for all block sizes]
+ */
+/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
+
+#include <sys/skein.h>
+#include "skein_impl.h"
+#include <sys/isa_defs.h>      /* for _ILP32 */
+
+#ifndef        SKEIN_USE_ASM
+#define        SKEIN_USE_ASM   (0)     /* default is all C code (no ASM) */
+#endif
+
+#ifndef        SKEIN_LOOP
+/*
+ * The low-level checksum routines use a lot of stack space. On systems where
+ * small stacks frame are enforced (like 32-bit kernel builds), do not unroll
+ * checksum calculations to save stack space.
+ *
+ * Even with no loops unrolled, we still can exceed the 1k stack frame limit
+ * in Skein1024_Process_Block() (it hits 1272 bytes on ARM32).  We can
+ * safely ignore it though, since that the checksum functions will be called
+ * from a worker thread that won't be using much stack.  That's why we have
+ * the #pragma here to ignore the warning.
+ */
+#if defined(_ILP32) || defined(__powerpc)      /* Assume small stack */
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+/*
+ * We're running on 32-bit, don't unroll loops to save stack frame space
+ *
+ * Due to the ways the calculations on SKEIN_LOOP are done in
+ * Skein_*_Process_Block(), a value of 111 disables unrolling loops
+ * in any of those functions.
+ */
+#define        SKEIN_LOOP 111
+#else
+/* We're compiling with large stacks */
+#define        SKEIN_LOOP 001          /* default: unroll 256 and 512, but not 1024 */
+#endif
+#endif
+
+/* some useful definitions for code here */
+#define        BLK_BITS        (WCNT*64)
+#define        KW_TWK_BASE     (0)
+#define        KW_KEY_BASE     (3)
+#define        ks              (kw + KW_KEY_BASE)
+#define        ts              (kw + KW_TWK_BASE)
+
+/* no debugging in Illumos version */
+#define        DebugSaveTweak(ctx)
+
+/* Skein_256 */
+#if    !(SKEIN_USE_ASM & 256)
+
+void
+Skein_256_Process_Block(Skein_256_Ctxt_t *ctx, const uint8_t *blkPtr,
+    size_t blkCnt, size_t byteCntAdd)
+{                              /* do it in C */
+       enum {
+               WCNT = SKEIN_256_STATE_WORDS
+       };
+#undef  RCNT
+#define        RCNT  (SKEIN_256_ROUNDS_TOTAL / 8)
+
+#ifdef SKEIN_LOOP              /* configure how much to unroll the loop */
+#define        SKEIN_UNROLL_256 (((SKEIN_LOOP) / 100) % 10)
+#else
+#define        SKEIN_UNROLL_256 (0)
+#endif
+
+#if    SKEIN_UNROLL_256
+#if    (RCNT % SKEIN_UNROLL_256)
+#error "Invalid SKEIN_UNROLL_256"      /* sanity check on unroll count */
+#endif
+       size_t r;
+       /* key schedule words : chaining vars + tweak + "rotation" */
+       uint64_t kw[WCNT + 4 + RCNT * 2];
+#else
+       uint64_t kw[WCNT + 4];  /* key schedule words : chaining vars + tweak */
+#endif
+       /* local copy of context vars, for speed */
+       uint64_t X0, X1, X2, X3;
+       uint64_t w[WCNT];               /* local copy of input block */
+#ifdef SKEIN_DEBUG
+       /* use for debugging (help compiler put Xn in registers) */
+       const uint64_t *Xptr[4];
+       Xptr[0] = &X0;
+       Xptr[1] = &X1;
+       Xptr[2] = &X2;
+       Xptr[3] = &X3;
+#endif
+       Skein_assert(blkCnt != 0);      /* never call with blkCnt == 0! */
+       ts[0] = ctx->h.T[0];
+       ts[1] = ctx->h.T[1];
+       do {
+               /*
+                * this implementation only supports 2**64 input bytes
+                * (no carry out here)
+                */
+               ts[0] += byteCntAdd;    /* update processed length */
+
+               /* precompute the key schedule for this block */
+               ks[0] = ctx->X[0];
+               ks[1] = ctx->X[1];
+               ks[2] = ctx->X[2];
+               ks[3] = ctx->X[3];
+               ks[4] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^ SKEIN_KS_PARITY;
+
+               ts[2] = ts[0] ^ ts[1];
+
+               /* get input block in little-endian format */
+               Skein_Get64_LSB_First(w, blkPtr, WCNT);
+               DebugSaveTweak(ctx);
+               Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts);
+
+               X0 = w[0] + ks[0];      /* do the first full key injection */
+               X1 = w[1] + ks[1] + ts[0];
+               X2 = w[2] + ks[2] + ts[1];
+               X3 = w[3] + ks[3];
+
+               Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL,
+                   Xptr);      /* show starting state values */
+
+               blkPtr += SKEIN_256_BLOCK_BYTES;
+
+               /* run the rounds */
+
+#define        Round256(p0, p1, p2, p3, ROT, rNum)                          \
+    X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0; \
+    X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2; \
+
+#if    SKEIN_UNROLL_256 == 0
+#define        R256(p0, p1, p2, p3, ROT, rNum)         /* fully unrolled */    \
+    Round256(p0, p1, p2, p3, ROT, rNum)                                        \
+    Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rNum, Xptr);
+
+#define        I256(R)                                                         \
+    X0 += ks[((R) + 1) % 5];   /* inject the key schedule value */     \
+    X1 += ks[((R) + 2) % 5] + ts[((R) + 1) % 3];                       \
+    X2 += ks[((R) + 3) % 5] + ts[((R) + 2) % 3];                       \
+    X3 += ks[((R) + 4) % 5] + (R) + 1;                                 \
+    Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
+#else                          /* looping version */
+#define        R256(p0, p1, p2, p3, ROT, rNum)                             \
+    Round256(p0, p1, p2, p3, ROT, rNum)                             \
+    Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rNum, Xptr);
+
+#define        I256(R)                                                         \
+       X0 += ks[r + (R) + 0];  /* inject the key schedule value */     \
+       X1 += ks[r + (R) + 1] + ts[r + (R) + 0];                        \
+       X2 += ks[r + (R) + 2] + ts[r + (R) + 1];                        \
+       X3 += ks[r + (R) + 3] + r + (R);                                \
+       ks[r + (R) + 4] = ks[r + (R) - 1];   /* rotate key schedule */  \
+    ts[r + (R) + 2] = ts[r + (R) - 1];                                 \
+    Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
+
+               /* loop thru it */
+               for (r = 1; r < 2 * RCNT; r += 2 * SKEIN_UNROLL_256)
+#endif
+               {
+#define        R256_8_rounds(R)                         \
+       R256(0, 1, 2, 3, R_256_0, 8 * (R) + 1);  \
+       R256(0, 3, 2, 1, R_256_1, 8 * (R) + 2);  \
+       R256(0, 1, 2, 3, R_256_2, 8 * (R) + 3);  \
+       R256(0, 3, 2, 1, R_256_3, 8 * (R) + 4);  \
+       I256(2 * (R));                           \
+       R256(0, 1, 2, 3, R_256_4, 8 * (R) + 5);  \
+       R256(0, 3, 2, 1, R_256_5, 8 * (R) + 6);  \
+       R256(0, 1, 2, 3, R_256_6, 8 * (R) + 7);  \
+       R256(0, 3, 2, 1, R_256_7, 8 * (R) + 8);  \
+       I256(2 * (R) + 1);
+
+                       R256_8_rounds(0);
+
+#define        R256_Unroll_R(NN) \
+       ((SKEIN_UNROLL_256 == 0 && SKEIN_256_ROUNDS_TOTAL / 8 > (NN)) || \
+       (SKEIN_UNROLL_256 > (NN)))
+
+#if    R256_Unroll_R(1)
+                       R256_8_rounds(1);
+#endif
+#if    R256_Unroll_R(2)
+                       R256_8_rounds(2);
+#endif
+#if    R256_Unroll_R(3)
+                       R256_8_rounds(3);
+#endif
+#if    R256_Unroll_R(4)
+                       R256_8_rounds(4);
+#endif
+#if    R256_Unroll_R(5)
+                       R256_8_rounds(5);
+#endif
+#if    R256_Unroll_R(6)
+                       R256_8_rounds(6);
+#endif
+#if    R256_Unroll_R(7)
+                       R256_8_rounds(7);
+#endif
+#if    R256_Unroll_R(8)
+                       R256_8_rounds(8);
+#endif
+#if    R256_Unroll_R(9)
+                       R256_8_rounds(9);
+#endif
+#if    R256_Unroll_R(10)
+                       R256_8_rounds(10);
+#endif
+#if    R256_Unroll_R(11)
+                       R256_8_rounds(11);
+#endif
+#if    R256_Unroll_R(12)
+                       R256_8_rounds(12);
+#endif
+#if    R256_Unroll_R(13)
+                       R256_8_rounds(13);
+#endif
+#if    R256_Unroll_R(14)
+                       R256_8_rounds(14);
+#endif
+#if    (SKEIN_UNROLL_256 > 14)
+#error  "need more unrolling in Skein_256_Process_Block"
+#endif
+               }
+               /*
+                * do the final "feedforward" xor, update context chaining vars
+                */
+               ctx->X[0] = X0 ^ w[0];
+               ctx->X[1] = X1 ^ w[1];
+               ctx->X[2] = X2 ^ w[2];
+               ctx->X[3] = X3 ^ w[3];
+
+               Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X);
+
+               ts[1] &= ~SKEIN_T1_FLAG_FIRST;
+       }
+       while (--blkCnt);
+       ctx->h.T[0] = ts[0];
+       ctx->h.T[1] = ts[1];
+}
+
+#if    defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+size_t
+Skein_256_Process_Block_CodeSize(void)
+{
+       return ((uint8_t *)Skein_256_Process_Block_CodeSize) -
+           ((uint8_t *)Skein_256_Process_Block);
+}
+
+uint_t
+Skein_256_Unroll_Cnt(void)
+{
+       return (SKEIN_UNROLL_256);
+}
+#endif
+#endif
+
+/* Skein_512 */
+#if    !(SKEIN_USE_ASM & 512)
+void
+Skein_512_Process_Block(Skein_512_Ctxt_t *ctx, const uint8_t *blkPtr,
+    size_t blkCnt, size_t byteCntAdd)
+{                              /* do it in C */
+       enum {
+               WCNT = SKEIN_512_STATE_WORDS
+       };
+#undef  RCNT
+#define        RCNT  (SKEIN_512_ROUNDS_TOTAL / 8)
+
+#ifdef SKEIN_LOOP              /* configure how much to unroll the loop */
+#define        SKEIN_UNROLL_512 (((SKEIN_LOOP) / 10) % 10)
+#else
+#define        SKEIN_UNROLL_512 (0)
+#endif
+
+#if    SKEIN_UNROLL_512
+#if    (RCNT % SKEIN_UNROLL_512)
+#error "Invalid SKEIN_UNROLL_512"      /* sanity check on unroll count */
+#endif
+       size_t r;
+       /* key schedule words : chaining vars + tweak + "rotation" */
+       uint64_t kw[WCNT + 4 + RCNT * 2];
+#else
+       uint64_t kw[WCNT + 4];  /* key schedule words : chaining vars + tweak */
+#endif
+       /* local copy of vars, for speed */
+       uint64_t X0, X1, X2, X3, X4, X5, X6, X7;
+       uint64_t w[WCNT];               /* local copy of input block */
+#ifdef SKEIN_DEBUG
+       /* use for debugging (help compiler put Xn in registers) */
+       const uint64_t *Xptr[8];
+       Xptr[0] = &X0;
+       Xptr[1] = &X1;
+       Xptr[2] = &X2;
+       Xptr[3] = &X3;
+       Xptr[4] = &X4;
+       Xptr[5] = &X5;
+       Xptr[6] = &X6;
+       Xptr[7] = &X7;
+#endif
+
+       Skein_assert(blkCnt != 0);      /* never call with blkCnt == 0! */
+       ts[0] = ctx->h.T[0];
+       ts[1] = ctx->h.T[1];
+       do {
+               /*
+                * this implementation only supports 2**64 input bytes
+                * (no carry out here)
+                */
+               ts[0] += byteCntAdd;    /* update processed length */
+
+               /* precompute the key schedule for this block */
+               ks[0] = ctx->X[0];
+               ks[1] = ctx->X[1];
+               ks[2] = ctx->X[2];
+               ks[3] = ctx->X[3];
+               ks[4] = ctx->X[4];
+               ks[5] = ctx->X[5];
+               ks[6] = ctx->X[6];
+               ks[7] = ctx->X[7];
+               ks[8] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^
+                   ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^ SKEIN_KS_PARITY;
+
+               ts[2] = ts[0] ^ ts[1];
+
+               /* get input block in little-endian format */
+               Skein_Get64_LSB_First(w, blkPtr, WCNT);
+               DebugSaveTweak(ctx);
+               Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts);
+
+               X0 = w[0] + ks[0];      /* do the first full key injection */
+               X1 = w[1] + ks[1];
+               X2 = w[2] + ks[2];
+               X3 = w[3] + ks[3];
+               X4 = w[4] + ks[4];
+               X5 = w[5] + ks[5] + ts[0];
+               X6 = w[6] + ks[6] + ts[1];
+               X7 = w[7] + ks[7];
+
+               blkPtr += SKEIN_512_BLOCK_BYTES;
+
+               Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL,
+                   Xptr);
+               /* run the rounds */
+#define        Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum)             \
+       X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0;\
+       X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2;\
+       X##p4 += X##p5; X##p5 = RotL_64(X##p5, ROT##_2); X##p5 ^= X##p4;\
+       X##p6 += X##p7; X##p7 = RotL_64(X##p7, ROT##_3); X##p7 ^= X##p6;
+
+#if    SKEIN_UNROLL_512 == 0
+#define        R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum) /* unrolled */  \
+       Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum)             \
+       Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rNum, Xptr);
+
+#define        I512(R)                                                         \
+       X0 += ks[((R) + 1) % 9];        /* inject the key schedule value */\
+       X1 += ks[((R) + 2) % 9];                                        \
+       X2 += ks[((R) + 3) % 9];                                        \
+       X3 += ks[((R) + 4) % 9];                                        \
+       X4 += ks[((R) + 5) % 9];                                        \
+       X5 += ks[((R) + 6) % 9] + ts[((R) + 1) % 3];                    \
+       X6 += ks[((R) + 7) % 9] + ts[((R) + 2) % 3];                    \
+       X7 += ks[((R) + 8) % 9] + (R) + 1;                              \
+       Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
+#else                          /* looping version */
+#define        R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum)                 \
+       Round512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, rNum)             \
+       Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rNum, Xptr);
+
+#define        I512(R)                                                         \
+       X0 += ks[r + (R) + 0];  /* inject the key schedule value */     \
+       X1 += ks[r + (R) + 1];                                          \
+       X2 += ks[r + (R) + 2];                                          \
+       X3 += ks[r + (R) + 3];                                          \
+       X4 += ks[r + (R) + 4];                                          \
+       X5 += ks[r + (R) + 5] + ts[r + (R) + 0];                        \
+       X6 += ks[r + (R) + 6] + ts[r + (R) + 1];                        \
+       X7 += ks[r + (R) + 7] + r + (R);                                \
+       ks[r + (R)+8] = ks[r + (R) - 1];        /* rotate key schedule */\
+       ts[r + (R)+2] = ts[r + (R) - 1];                                \
+       Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
+
+               /* loop thru it */
+               for (r = 1; r < 2 * RCNT; r += 2 * SKEIN_UNROLL_512)
+#endif                         /* end of looped code definitions */
+               {
+#define        R512_8_rounds(R)        /* do 8 full rounds */                  \
+       R512(0, 1, 2, 3, 4, 5, 6, 7, R_512_0, 8 * (R) + 1);             \
+       R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_1, 8 * (R) + 2);             \
+       R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_2, 8 * (R) + 3);             \
+       R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_3, 8 * (R) + 4);             \
+       I512(2 * (R));                                                  \
+       R512(0, 1, 2, 3, 4, 5, 6, 7, R_512_4, 8 * (R) + 5);             \
+       R512(2, 1, 4, 7, 6, 5, 0, 3, R_512_5, 8 * (R) + 6);             \
+       R512(4, 1, 6, 3, 0, 5, 2, 7, R_512_6, 8 * (R) + 7);             \
+       R512(6, 1, 0, 7, 2, 5, 4, 3, R_512_7, 8 * (R) + 8);             \
+       I512(2*(R) + 1);                /* and key injection */
+
+                       R512_8_rounds(0);
+
+#define        R512_Unroll_R(NN) \
+       ((SKEIN_UNROLL_512 == 0 && SKEIN_512_ROUNDS_TOTAL / 8 > (NN)) || \
+       (SKEIN_UNROLL_512 > (NN)))
+
+#if    R512_Unroll_R(1)
+                       R512_8_rounds(1);
+#endif
+#if    R512_Unroll_R(2)
+                       R512_8_rounds(2);
+#endif
+#if    R512_Unroll_R(3)
+                       R512_8_rounds(3);
+#endif
+#if    R512_Unroll_R(4)
+                       R512_8_rounds(4);
+#endif
+#if    R512_Unroll_R(5)
+                       R512_8_rounds(5);
+#endif
+#if    R512_Unroll_R(6)
+                       R512_8_rounds(6);
+#endif
+#if    R512_Unroll_R(7)
+                       R512_8_rounds(7);
+#endif
+#if    R512_Unroll_R(8)
+                       R512_8_rounds(8);
+#endif
+#if    R512_Unroll_R(9)
+                       R512_8_rounds(9);
+#endif
+#if    R512_Unroll_R(10)
+                       R512_8_rounds(10);
+#endif
+#if    R512_Unroll_R(11)
+                       R512_8_rounds(11);
+#endif
+#if    R512_Unroll_R(12)
+                       R512_8_rounds(12);
+#endif
+#if    R512_Unroll_R(13)
+                       R512_8_rounds(13);
+#endif
+#if    R512_Unroll_R(14)
+                       R512_8_rounds(14);
+#endif
+#if    (SKEIN_UNROLL_512 > 14)
+#error "need more unrolling in Skein_512_Process_Block"
+#endif
+               }
+
+               /*
+                * do the final "feedforward" xor, update context chaining vars
+                */
+               ctx->X[0] = X0 ^ w[0];
+               ctx->X[1] = X1 ^ w[1];
+               ctx->X[2] = X2 ^ w[2];
+               ctx->X[3] = X3 ^ w[3];
+               ctx->X[4] = X4 ^ w[4];
+               ctx->X[5] = X5 ^ w[5];
+               ctx->X[6] = X6 ^ w[6];
+               ctx->X[7] = X7 ^ w[7];
+               Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X);
+
+               ts[1] &= ~SKEIN_T1_FLAG_FIRST;
+       }
+       while (--blkCnt);
+       ctx->h.T[0] = ts[0];
+       ctx->h.T[1] = ts[1];
+}
+
+#if    defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+size_t
+Skein_512_Process_Block_CodeSize(void)
+{
+       return ((uint8_t *)Skein_512_Process_Block_CodeSize) -
+           ((uint8_t *)Skein_512_Process_Block);
+}
+
+uint_t
+Skein_512_Unroll_Cnt(void)
+{
+       return (SKEIN_UNROLL_512);
+}
+#endif
+#endif
+
+/*  Skein1024 */
+#if    !(SKEIN_USE_ASM & 1024)
+void
+Skein1024_Process_Block(Skein1024_Ctxt_t *ctx, const uint8_t *blkPtr,
+    size_t blkCnt, size_t byteCntAdd)
+{
+       /* do it in C, always looping (unrolled is bigger AND slower!) */
+       enum {
+               WCNT = SKEIN1024_STATE_WORDS
+       };
+#undef  RCNT
+#define        RCNT  (SKEIN1024_ROUNDS_TOTAL/8)
+
+#ifdef SKEIN_LOOP              /* configure how much to unroll the loop */
+#define        SKEIN_UNROLL_1024 ((SKEIN_LOOP)%10)
+#else
+#define        SKEIN_UNROLL_1024 (0)
+#endif
+
+#if    (SKEIN_UNROLL_1024 != 0)
+#if    (RCNT % SKEIN_UNROLL_1024)
+#error "Invalid SKEIN_UNROLL_1024"     /* sanity check on unroll count */
+#endif
+       size_t r;
+       /* key schedule words : chaining vars + tweak + "rotation" */
+       uint64_t kw[WCNT + 4 + RCNT * 2];
+#else
+       uint64_t kw[WCNT + 4];  /* key schedule words : chaining vars + tweak */
+#endif
+
+       /* local copy of vars, for speed */
+       uint64_t X00, X01, X02, X03, X04, X05, X06, X07, X08, X09, X10, X11,
+           X12, X13, X14, X15;
+       uint64_t w[WCNT];               /* local copy of input block */
+#ifdef SKEIN_DEBUG
+       /* use for debugging (help compiler put Xn in registers) */
+       const uint64_t *Xptr[16];
+       Xptr[0] = &X00;
+       Xptr[1] = &X01;
+       Xptr[2] = &X02;
+       Xptr[3] = &X03;
+       Xptr[4] = &X04;
+       Xptr[5] = &X05;
+       Xptr[6] = &X06;
+       Xptr[7] = &X07;
+       Xptr[8] = &X08;
+       Xptr[9] = &X09;
+       Xptr[10] = &X10;
+       Xptr[11] = &X11;
+       Xptr[12] = &X12;
+       Xptr[13] = &X13;
+       Xptr[14] = &X14;
+       Xptr[15] = &X15;
+#endif
+
+       Skein_assert(blkCnt != 0);      /* never call with blkCnt == 0! */
+       ts[0] = ctx->h.T[0];
+       ts[1] = ctx->h.T[1];
+       do {
+               /*
+                * this implementation only supports 2**64 input bytes
+                * (no carry out here)
+                */
+               ts[0] += byteCntAdd;    /* update processed length */
+
+               /* precompute the key schedule for this block */
+               ks[0] = ctx->X[0];
+               ks[1] = ctx->X[1];
+               ks[2] = ctx->X[2];
+               ks[3] = ctx->X[3];
+               ks[4] = ctx->X[4];
+               ks[5] = ctx->X[5];
+               ks[6] = ctx->X[6];
+               ks[7] = ctx->X[7];
+               ks[8] = ctx->X[8];
+               ks[9] = ctx->X[9];
+               ks[10] = ctx->X[10];
+               ks[11] = ctx->X[11];
+               ks[12] = ctx->X[12];
+               ks[13] = ctx->X[13];
+               ks[14] = ctx->X[14];
+               ks[15] = ctx->X[15];
+               ks[16] = ks[0] ^ ks[1] ^ ks[2] ^ ks[3] ^
+                   ks[4] ^ ks[5] ^ ks[6] ^ ks[7] ^
+                   ks[8] ^ ks[9] ^ ks[10] ^ ks[11] ^
+                   ks[12] ^ ks[13] ^ ks[14] ^ ks[15] ^ SKEIN_KS_PARITY;
+
+               ts[2] = ts[0] ^ ts[1];
+
+               /* get input block in little-endian format */
+               Skein_Get64_LSB_First(w, blkPtr, WCNT);
+               DebugSaveTweak(ctx);
+               Skein_Show_Block(BLK_BITS, &ctx->h, ctx->X, blkPtr, w, ks, ts);
+
+               X00 = w[0] + ks[0];     /* do the first full key injection */
+               X01 = w[1] + ks[1];
+               X02 = w[2] + ks[2];
+               X03 = w[3] + ks[3];
+               X04 = w[4] + ks[4];
+               X05 = w[5] + ks[5];
+               X06 = w[6] + ks[6];
+               X07 = w[7] + ks[7];
+               X08 = w[8] + ks[8];
+               X09 = w[9] + ks[9];
+               X10 = w[10] + ks[10];
+               X11 = w[11] + ks[11];
+               X12 = w[12] + ks[12];
+               X13 = w[13] + ks[13] + ts[0];
+               X14 = w[14] + ks[14] + ts[1];
+               X15 = w[15] + ks[15];
+
+               Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INITIAL,
+                   Xptr);
+
+#define        Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC,   \
+       pD, pE, pF, ROT, rNum)                                          \
+       X##p0 += X##p1; X##p1 = RotL_64(X##p1, ROT##_0); X##p1 ^= X##p0;\
+       X##p2 += X##p3; X##p3 = RotL_64(X##p3, ROT##_1); X##p3 ^= X##p2;\
+       X##p4 += X##p5; X##p5 = RotL_64(X##p5, ROT##_2); X##p5 ^= X##p4;\
+       X##p6 += X##p7; X##p7 = RotL_64(X##p7, ROT##_3); X##p7 ^= X##p6;\
+       X##p8 += X##p9; X##p9 = RotL_64(X##p9, ROT##_4); X##p9 ^= X##p8;\
+       X##pA += X##pB; X##pB = RotL_64(X##pB, ROT##_5); X##pB ^= X##pA;\
+       X##pC += X##pD; X##pD = RotL_64(X##pD, ROT##_6); X##pD ^= X##pC;\
+       X##pE += X##pF; X##pF = RotL_64(X##pF, ROT##_7); X##pF ^= X##pE;
+
+#if    SKEIN_UNROLL_1024 == 0
+#define        R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD,   \
+       pE, pF, ROT, rn)                                                \
+       Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC,   \
+       pD, pE, pF, ROT, rn)                                            \
+       Skein_Show_R_Ptr(BLK_BITS, &ctx->h, rn, Xptr);
+
+#define        I1024(R)                                                        \
+       X00 += ks[((R) + 1) % 17];      /* inject the key schedule value */\
+       X01 += ks[((R) + 2) % 17];                                      \
+       X02 += ks[((R) + 3) % 17];                                      \
+       X03 += ks[((R) + 4) % 17];                                      \
+       X04 += ks[((R) + 5) % 17];                                      \
+       X05 += ks[((R) + 6) % 17];                                      \
+       X06 += ks[((R) + 7) % 17];                                      \
+       X07 += ks[((R) + 8) % 17];                                      \
+       X08 += ks[((R) + 9) % 17];                                      \
+       X09 += ks[((R) + 10) % 17];                                     \
+       X10 += ks[((R) + 11) % 17];                                     \
+       X11 += ks[((R) + 12) % 17];                                     \
+       X12 += ks[((R) + 13) % 17];                                     \
+       X13 += ks[((R) + 14) % 17] + ts[((R) + 1) % 3];                 \
+       X14 += ks[((R) + 15) % 17] + ts[((R) + 2) % 3];                 \
+       X15 += ks[((R) + 16) % 17] + (R) +1;                            \
+       Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
+#else                          /* looping version */
+#define        R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD,   \
+       pE, pF, ROT, rn)                                                \
+       Round1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC,   \
+       pD, pE, pF, ROT, rn)                                            \
+       Skein_Show_R_Ptr(BLK_BITS, &ctx->h, 4 * (r - 1) + rn, Xptr);
+
+#define        I1024(R)                                                        \
+       X00 += ks[r + (R) + 0]; /* inject the key schedule value */     \
+       X01 += ks[r + (R) + 1];                                         \
+       X02 += ks[r + (R) + 2];                                         \
+       X03 += ks[r + (R) + 3];                                         \
+       X04 += ks[r + (R) + 4];                                         \
+       X05 += ks[r + (R) + 5];                                         \
+       X06 += ks[r + (R) + 6];                                         \
+       X07 += ks[r + (R) + 7];                                         \
+       X08 += ks[r + (R) + 8];                                         \
+       X09 += ks[r + (R) + 9];                                         \
+       X10 += ks[r + (R) + 10];                                        \
+       X11 += ks[r + (R) + 11];                                        \
+       X12 += ks[r + (R) + 12];                                        \
+       X13 += ks[r + (R) + 13] + ts[r + (R) + 0];                      \
+       X14 += ks[r + (R) + 14] + ts[r + (R) + 1];                      \
+       X15 += ks[r + (R) + 15] +  r + (R);                             \
+       ks[r + (R) + 16] = ks[r + (R) - 1];     /* rotate key schedule */\
+       ts[r + (R) + 2] = ts[r + (R) - 1];                              \
+       Skein_Show_R_Ptr(BLK_BITS, &ctx->h, SKEIN_RND_KEY_INJECT, Xptr);
+
+               /* loop thru it */
+               for (r = 1; r <= 2 * RCNT; r += 2 * SKEIN_UNROLL_1024)
+#endif
+               {
+#define        R1024_8_rounds(R)       /* do 8 full rounds */                  \
+       R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13,   \
+           14, 15, R1024_0, 8 * (R) + 1);                              \
+       R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, 05,   \
+           08, 01, R1024_1, 8 * (R) + 2);                              \
+       R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, 11,   \
+           10, 09, R1024_2, 8 * (R) + 3);                              \
+       R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, 03,   \
+           12, 07, R1024_3, 8 * (R) + 4);                              \
+       I1024(2 * (R));                                                 \
+       R1024(00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13,   \
+           14, 15, R1024_4, 8 * (R) + 5);                              \
+       R1024(00, 09, 02, 13, 06, 11, 04, 15, 10, 07, 12, 03, 14, 05,   \
+           08, 01, R1024_5, 8 * (R) + 6);                              \
+       R1024(00, 07, 02, 05, 04, 03, 06, 01, 12, 15, 14, 13, 08, 11,   \
+           10, 09, R1024_6, 8 * (R) + 7);                              \
+       R1024(00, 15, 02, 11, 06, 13, 04, 09, 14, 01, 08, 05, 10, 03,   \
+           12, 07, R1024_7, 8 * (R) + 8);                              \
+       I1024(2 * (R) + 1);
+
+                       R1024_8_rounds(0);
+
+#define        R1024_Unroll_R(NN)                                              \
+       ((SKEIN_UNROLL_1024 == 0 && SKEIN1024_ROUNDS_TOTAL/8 > (NN)) || \
+       (SKEIN_UNROLL_1024 > (NN)))
+
+#if    R1024_Unroll_R(1)
+                       R1024_8_rounds(1);
+#endif
+#if    R1024_Unroll_R(2)
+                       R1024_8_rounds(2);
+#endif
+#if    R1024_Unroll_R(3)
+                       R1024_8_rounds(3);
+#endif
+#if    R1024_Unroll_R(4)
+                       R1024_8_rounds(4);
+#endif
+#if    R1024_Unroll_R(5)
+                       R1024_8_rounds(5);
+#endif
+#if    R1024_Unroll_R(6)
+                       R1024_8_rounds(6);
+#endif
+#if    R1024_Unroll_R(7)
+                       R1024_8_rounds(7);
+#endif
+#if    R1024_Unroll_R(8)
+                       R1024_8_rounds(8);
+#endif
+#if    R1024_Unroll_R(9)
+                       R1024_8_rounds(9);
+#endif
+#if    R1024_Unroll_R(10)
+                       R1024_8_rounds(10);
+#endif
+#if    R1024_Unroll_R(11)
+                       R1024_8_rounds(11);
+#endif
+#if    R1024_Unroll_R(12)
+                       R1024_8_rounds(12);
+#endif
+#if    R1024_Unroll_R(13)
+                       R1024_8_rounds(13);
+#endif
+#if    R1024_Unroll_R(14)
+                       R1024_8_rounds(14);
+#endif
+#if    (SKEIN_UNROLL_1024 > 14)
+#error  "need more unrolling in Skein_1024_Process_Block"
+#endif
+               }
+               /*
+                * do the final "feedforward" xor, update context chaining vars
+                */
+
+               ctx->X[0] = X00 ^ w[0];
+               ctx->X[1] = X01 ^ w[1];
+               ctx->X[2] = X02 ^ w[2];
+               ctx->X[3] = X03 ^ w[3];
+               ctx->X[4] = X04 ^ w[4];
+               ctx->X[5] = X05 ^ w[5];
+               ctx->X[6] = X06 ^ w[6];
+               ctx->X[7] = X07 ^ w[7];
+               ctx->X[8] = X08 ^ w[8];
+               ctx->X[9] = X09 ^ w[9];
+               ctx->X[10] = X10 ^ w[10];
+               ctx->X[11] = X11 ^ w[11];
+               ctx->X[12] = X12 ^ w[12];
+               ctx->X[13] = X13 ^ w[13];
+               ctx->X[14] = X14 ^ w[14];
+               ctx->X[15] = X15 ^ w[15];
+
+               Skein_Show_Round(BLK_BITS, &ctx->h, SKEIN_RND_FEED_FWD, ctx->X);
+
+               ts[1] &= ~SKEIN_T1_FLAG_FIRST;
+               blkPtr += SKEIN1024_BLOCK_BYTES;
+       } while (--blkCnt);
+       ctx->h.T[0] = ts[0];
+       ctx->h.T[1] = ts[1];
+}
+
+#if    defined(SKEIN_CODE_SIZE) || defined(SKEIN_PERF)
+size_t
+Skein1024_Process_Block_CodeSize(void)
+{
+       return ((uint8_t *)Skein1024_Process_Block_CodeSize) -
+           ((uint8_t *)Skein1024_Process_Block);
+}
+
+uint_t
+Skein1024_Unroll_Cnt(void)
+{
+       return (SKEIN_UNROLL_1024);
+}
+#endif
+#endif
diff --git a/zfs/module/icp/algs/skein/skein_impl.h b/zfs/module/icp/algs/skein/skein_impl.h
new file mode 100644 (file)
index 0000000..e83a069
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Internal definitions for Skein hashing.
+ * Source code author: Doug Whiting, 2008.
+ * This algorithm and source code is released to the public domain.
+ *
+ * The following compile-time switches may be defined to control some
+ * tradeoffs between speed, code size, error checking, and security.
+ *
+ * The "default" note explains what happens when the switch is not defined.
+ *
+ *  SKEIN_DEBUG            -- make callouts from inside Skein code
+ *                            to examine/display intermediate values.
+ *                            [default: no callouts (no overhead)]
+ *
+ *  SKEIN_ERR_CHECK        -- how error checking is handled inside Skein
+ *                            code. If not defined, most error checking
+ *                            is disabled (for performance). Otherwise,
+ *                            the switch value is interpreted as:
+ *                                0: use assert()      to flag errors
+ *                                1: return SKEIN_FAIL to flag errors
+ */
+/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
+
+#ifndef        _SKEIN_IMPL_H_
+#define        _SKEIN_IMPL_H_
+
+#include <sys/skein.h>
+#include "skein_impl.h"
+#include "skein_port.h"
+
+/* determine where we can get bcopy/bzero declarations */
+#ifdef _KERNEL
+#include <sys/systm.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * "Internal" Skein definitions
+ *    -- not needed for sequential hashing API, but will be
+ *           helpful for other uses of Skein (e.g., tree hash mode).
+ *    -- included here so that they can be shared between
+ *           reference and optimized code.
+ */
+
+/* tweak word T[1]: bit field starting positions */
+/* offset 64 because it's the second word  */
+#define        SKEIN_T1_BIT(BIT)       ((BIT) - 64)
+
+/* bits 112..118: level in hash tree */
+#define        SKEIN_T1_POS_TREE_LVL   SKEIN_T1_BIT(112)
+/* bit  119: partial final input byte */
+#define        SKEIN_T1_POS_BIT_PAD    SKEIN_T1_BIT(119)
+/* bits 120..125: type field */
+#define        SKEIN_T1_POS_BLK_TYPE   SKEIN_T1_BIT(120)
+/* bits 126: first block flag */
+#define        SKEIN_T1_POS_FIRST      SKEIN_T1_BIT(126)
+/* bit  127: final block flag */
+#define        SKEIN_T1_POS_FINAL      SKEIN_T1_BIT(127)
+
+/* tweak word T[1]: flag bit definition(s) */
+#define        SKEIN_T1_FLAG_FIRST     (((uint64_t)1) << SKEIN_T1_POS_FIRST)
+#define        SKEIN_T1_FLAG_FINAL     (((uint64_t)1) << SKEIN_T1_POS_FINAL)
+#define        SKEIN_T1_FLAG_BIT_PAD   (((uint64_t)1) << SKEIN_T1_POS_BIT_PAD)
+
+/* tweak word T[1]: tree level bit field mask */
+#define        SKEIN_T1_TREE_LVL_MASK  (((uint64_t)0x7F) << SKEIN_T1_POS_TREE_LVL)
+#define        SKEIN_T1_TREE_LEVEL(n)  (((uint64_t)(n)) << SKEIN_T1_POS_TREE_LVL)
+
+/* tweak word T[1]: block type field */
+#define        SKEIN_BLK_TYPE_KEY      (0)     /* key, for MAC and KDF */
+#define        SKEIN_BLK_TYPE_CFG      (4)     /* configuration block */
+#define        SKEIN_BLK_TYPE_PERS     (8)     /* personalization string */
+#define        SKEIN_BLK_TYPE_PK       (12)    /* public key (for signature hashing) */
+#define        SKEIN_BLK_TYPE_KDF      (16)    /* key identifier for KDF */
+#define        SKEIN_BLK_TYPE_NONCE    (20)    /* nonce for PRNG */
+#define        SKEIN_BLK_TYPE_MSG      (48)    /* message processing */
+#define        SKEIN_BLK_TYPE_OUT      (63)    /* output stage */
+#define        SKEIN_BLK_TYPE_MASK     (63)    /* bit field mask */
+
+#define        SKEIN_T1_BLK_TYPE(T)    \
+       (((uint64_t)(SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE)
+/* key, for MAC and KDF */
+#define        SKEIN_T1_BLK_TYPE_KEY   SKEIN_T1_BLK_TYPE(KEY)
+/* configuration block */
+#define        SKEIN_T1_BLK_TYPE_CFG   SKEIN_T1_BLK_TYPE(CFG)
+/* personalization string */
+#define        SKEIN_T1_BLK_TYPE_PERS  SKEIN_T1_BLK_TYPE(PERS)
+/* public key (for digital signature hashing) */
+#define        SKEIN_T1_BLK_TYPE_PK    SKEIN_T1_BLK_TYPE(PK)
+/* key identifier for KDF */
+#define        SKEIN_T1_BLK_TYPE_KDF   SKEIN_T1_BLK_TYPE(KDF)
+/* nonce for PRNG */
+#define        SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)
+/* message processing */
+#define        SKEIN_T1_BLK_TYPE_MSG   SKEIN_T1_BLK_TYPE(MSG)
+/* output stage */
+#define        SKEIN_T1_BLK_TYPE_OUT   SKEIN_T1_BLK_TYPE(OUT)
+/* field bit mask */
+#define        SKEIN_T1_BLK_TYPE_MASK  SKEIN_T1_BLK_TYPE(MASK)
+
+#define        SKEIN_T1_BLK_TYPE_CFG_FINAL     \
+       (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL)
+#define        SKEIN_T1_BLK_TYPE_OUT_FINAL     \
+       (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL)
+
+#define        SKEIN_VERSION           (1)
+
+#ifndef        SKEIN_ID_STRING_LE      /* allow compile-time personalization */
+#define        SKEIN_ID_STRING_LE      (0x33414853)    /* "SHA3" (little-endian) */
+#endif
+
+#define        SKEIN_MK_64(hi32, lo32) ((lo32) + (((uint64_t)(hi32)) << 32))
+#define        SKEIN_SCHEMA_VER        SKEIN_MK_64(SKEIN_VERSION, SKEIN_ID_STRING_LE)
+#define        SKEIN_KS_PARITY         SKEIN_MK_64(0x1BD11BDA, 0xA9FC1A22)
+
+#define        SKEIN_CFG_STR_LEN       (4*8)
+
+/* bit field definitions in config block treeInfo word */
+#define        SKEIN_CFG_TREE_LEAF_SIZE_POS    (0)
+#define        SKEIN_CFG_TREE_NODE_SIZE_POS    (8)
+#define        SKEIN_CFG_TREE_MAX_LEVEL_POS    (16)
+
+#define        SKEIN_CFG_TREE_LEAF_SIZE_MSK    \
+       (((uint64_t)0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS)
+#define        SKEIN_CFG_TREE_NODE_SIZE_MSK    \
+       (((uint64_t)0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS)
+#define        SKEIN_CFG_TREE_MAX_LEVEL_MSK    \
+       (((uint64_t)0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS)
+
+#define        SKEIN_CFG_TREE_INFO(leaf, node, maxLvl)                 \
+       ((((uint64_t)(leaf)) << SKEIN_CFG_TREE_LEAF_SIZE_POS) | \
+       (((uint64_t)(node)) << SKEIN_CFG_TREE_NODE_SIZE_POS) |  \
+       (((uint64_t)(maxLvl)) << SKEIN_CFG_TREE_MAX_LEVEL_POS))
+
+/* use as treeInfo in InitExt() call for sequential processing */
+#define        SKEIN_CFG_TREE_INFO_SEQUENTIAL  SKEIN_CFG_TREE_INFO(0, 0, 0)
+
+/*
+ * Skein macros for getting/setting tweak words, etc.
+ * These are useful for partial input bytes, hash tree init/update, etc.
+ */
+#define        Skein_Get_Tweak(ctxPtr, TWK_NUM)        ((ctxPtr)->h.T[TWK_NUM])
+#define        Skein_Set_Tweak(ctxPtr, TWK_NUM, tVal)          \
+       do {                                            \
+               (ctxPtr)->h.T[TWK_NUM] = (tVal);        \
+               _NOTE(CONSTCOND)                        \
+       } while (0)
+
+#define        Skein_Get_T0(ctxPtr)            Skein_Get_Tweak(ctxPtr, 0)
+#define        Skein_Get_T1(ctxPtr)            Skein_Get_Tweak(ctxPtr, 1)
+#define        Skein_Set_T0(ctxPtr, T0)        Skein_Set_Tweak(ctxPtr, 0, T0)
+#define        Skein_Set_T1(ctxPtr, T1)        Skein_Set_Tweak(ctxPtr, 1, T1)
+
+/* set both tweak words at once */
+#define        Skein_Set_T0_T1(ctxPtr, T0, T1)         \
+       do {                                    \
+               Skein_Set_T0(ctxPtr, (T0));     \
+               Skein_Set_T1(ctxPtr, (T1));     \
+               _NOTE(CONSTCOND)                \
+       } while (0)
+
+#define        Skein_Set_Type(ctxPtr, BLK_TYPE)        \
+       Skein_Set_T1(ctxPtr, SKEIN_T1_BLK_TYPE_##BLK_TYPE)
+
+/*
+ * set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0;
+ */
+#define        Skein_Start_New_Type(ctxPtr, BLK_TYPE)                          \
+       do {                                                            \
+               Skein_Set_T0_T1(ctxPtr, 0, SKEIN_T1_FLAG_FIRST |        \
+                   SKEIN_T1_BLK_TYPE_ ## BLK_TYPE);                    \
+               (ctxPtr)->h.bCnt = 0;   \
+               _NOTE(CONSTCOND)                                        \
+       } while (0)
+
+#define        Skein_Clear_First_Flag(hdr)                                     \
+       do {                                                            \
+               (hdr).T[1] &= ~SKEIN_T1_FLAG_FIRST;                     \
+               _NOTE(CONSTCOND)                                        \
+       } while (0)
+#define        Skein_Set_Bit_Pad_Flag(hdr)                                     \
+       do {                                                            \
+               (hdr).T[1] |=  SKEIN_T1_FLAG_BIT_PAD;                   \
+               _NOTE(CONSTCOND)                                        \
+       } while (0)
+
+#define        Skein_Set_Tree_Level(hdr, height)                               \
+       do {                                                            \
+               (hdr).T[1] |= SKEIN_T1_TREE_LEVEL(height);              \
+               _NOTE(CONSTCOND)                                        \
+       } while (0)
+
+/*
+ * "Internal" Skein definitions for debugging and error checking
+ * Note: in Illumos we always disable debugging features.
+ */
+#define        Skein_Show_Block(bits, ctx, X, blkPtr, wPtr, ksEvenPtr, ksOddPtr)
+#define        Skein_Show_Round(bits, ctx, r, X)
+#define        Skein_Show_R_Ptr(bits, ctx, r, X_ptr)
+#define        Skein_Show_Final(bits, ctx, cnt, outPtr)
+#define        Skein_Show_Key(bits, ctx, key, keyBytes)
+
+/* run-time checks (e.g., bad params, uninitialized context)? */
+#ifndef        SKEIN_ERR_CHECK
+/* default: ignore all Asserts, for performance */
+#define        Skein_Assert(x, retCode)
+#define        Skein_assert(x)
+#elif  defined(SKEIN_ASSERT)
+#include <sys/debug.h>
+#define        Skein_Assert(x, retCode)        ASSERT(x)
+#define        Skein_assert(x)                 ASSERT(x)
+#else
+#include <sys/debug.h>
+/*  caller error */
+#define        Skein_Assert(x, retCode)                \
+       do {                                    \
+               if (!(x))                       \
+                       return (retCode);       \
+               _NOTE(CONSTCOND)                \
+       } while (0)
+/* internal error */
+#define        Skein_assert(x) ASSERT(x)
+#endif
+
+/*
+ * Skein block function constants (shared across Ref and Opt code)
+ */
+enum {
+       /* Skein_256 round rotation constants */
+       R_256_0_0 = 14, R_256_0_1 = 16,
+       R_256_1_0 = 52, R_256_1_1 = 57,
+       R_256_2_0 = 23, R_256_2_1 = 40,
+       R_256_3_0 = 5, R_256_3_1 = 37,
+       R_256_4_0 = 25, R_256_4_1 = 33,
+       R_256_5_0 = 46, R_256_5_1 = 12,
+       R_256_6_0 = 58, R_256_6_1 = 22,
+       R_256_7_0 = 32, R_256_7_1 = 32,
+
+       /* Skein_512 round rotation constants */
+       R_512_0_0 = 46, R_512_0_1 = 36, R_512_0_2 = 19, R_512_0_3 = 37,
+       R_512_1_0 = 33, R_512_1_1 = 27, R_512_1_2 = 14, R_512_1_3 = 42,
+       R_512_2_0 = 17, R_512_2_1 = 49, R_512_2_2 = 36, R_512_2_3 = 39,
+       R_512_3_0 = 44, R_512_3_1 = 9, R_512_3_2 = 54, R_512_3_3 = 56,
+       R_512_4_0 = 39, R_512_4_1 = 30, R_512_4_2 = 34, R_512_4_3 = 24,
+       R_512_5_0 = 13, R_512_5_1 = 50, R_512_5_2 = 10, R_512_5_3 = 17,
+       R_512_6_0 = 25, R_512_6_1 = 29, R_512_6_2 = 39, R_512_6_3 = 43,
+       R_512_7_0 = 8, R_512_7_1 = 35, R_512_7_2 = 56, R_512_7_3 = 22,
+
+       /* Skein1024 round rotation constants */
+       R1024_0_0 = 24, R1024_0_1 = 13, R1024_0_2 = 8, R1024_0_3 =
+           47, R1024_0_4 = 8, R1024_0_5 = 17, R1024_0_6 = 22, R1024_0_7 = 37,
+       R1024_1_0 = 38, R1024_1_1 = 19, R1024_1_2 = 10, R1024_1_3 =
+           55, R1024_1_4 = 49, R1024_1_5 = 18, R1024_1_6 = 23, R1024_1_7 = 52,
+       R1024_2_0 = 33, R1024_2_1 = 4, R1024_2_2 = 51, R1024_2_3 =
+           13, R1024_2_4 = 34, R1024_2_5 = 41, R1024_2_6 = 59, R1024_2_7 = 17,
+       R1024_3_0 = 5, R1024_3_1 = 20, R1024_3_2 = 48, R1024_3_3 =
+           41, R1024_3_4 = 47, R1024_3_5 = 28, R1024_3_6 = 16, R1024_3_7 = 25,
+       R1024_4_0 = 41, R1024_4_1 = 9, R1024_4_2 = 37, R1024_4_3 =
+           31, R1024_4_4 = 12, R1024_4_5 = 47, R1024_4_6 = 44, R1024_4_7 = 30,
+       R1024_5_0 = 16, R1024_5_1 = 34, R1024_5_2 = 56, R1024_5_3 =
+           51, R1024_5_4 = 4, R1024_5_5 = 53, R1024_5_6 = 42, R1024_5_7 = 41,
+       R1024_6_0 = 31, R1024_6_1 = 44, R1024_6_2 = 47, R1024_6_3 =
+           46, R1024_6_4 = 19, R1024_6_5 = 42, R1024_6_6 = 44, R1024_6_7 = 25,
+       R1024_7_0 = 9, R1024_7_1 = 48, R1024_7_2 = 35, R1024_7_3 =
+           52, R1024_7_4 = 23, R1024_7_5 = 31, R1024_7_6 = 37, R1024_7_7 = 20
+};
+
+/* number of rounds for the different block sizes */
+#define        SKEIN_256_ROUNDS_TOTAL  (72)
+#define        SKEIN_512_ROUNDS_TOTAL  (72)
+#define        SKEIN1024_ROUNDS_TOTAL  (80)
+
+
+extern const uint64_t SKEIN_256_IV_128[];
+extern const uint64_t SKEIN_256_IV_160[];
+extern const uint64_t SKEIN_256_IV_224[];
+extern const uint64_t SKEIN_256_IV_256[];
+extern const uint64_t SKEIN_512_IV_128[];
+extern const uint64_t SKEIN_512_IV_160[];
+extern const uint64_t SKEIN_512_IV_224[];
+extern const uint64_t SKEIN_512_IV_256[];
+extern const uint64_t SKEIN_512_IV_384[];
+extern const uint64_t SKEIN_512_IV_512[];
+extern const uint64_t SKEIN1024_IV_384[];
+extern const uint64_t SKEIN1024_IV_512[];
+extern const uint64_t SKEIN1024_IV_1024[];
+
+#endif /* _SKEIN_IMPL_H_ */
diff --git a/zfs/module/icp/algs/skein/skein_iv.c b/zfs/module/icp/algs/skein/skein_iv.c
new file mode 100644 (file)
index 0000000..140d38f
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Pre-computed Skein IVs
+ *
+ * NOTE: these values are not "magic" constants, but
+ * are generated using the Threefish block function.
+ * They are pre-computed here only for speed; i.e., to
+ * avoid the need for a Threefish call during Init().
+ *
+ * The IV for any fixed hash length may be pre-computed.
+ * Only the most common values are included here.
+ */
+/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
+/*
+ * Illumos implementation note: these constants are for Skein v1.3 as per:
+ * http://www.skein-hash.info/sites/default/files/skein1.3.pdf
+ */
+
+#include <sys/skein.h>         /* get Skein macros and types */
+#include "skein_impl.h"                /* get internal definitions */
+
+#define        MK_64 SKEIN_MK_64
+
+/* blkSize =  256 bits. hashSize =  128 bits */
+const uint64_t SKEIN_256_IV_128[] = {
+       MK_64(0xE1111906, 0x964D7260),
+       MK_64(0x883DAAA7, 0x7C8D811C),
+       MK_64(0x10080DF4, 0x91960F7A),
+       MK_64(0xCCF7DDE5, 0xB45BC1C2)
+};
+
+/* blkSize =  256 bits. hashSize =  160 bits */
+const uint64_t SKEIN_256_IV_160[] = {
+       MK_64(0x14202314, 0x72825E98),
+       MK_64(0x2AC4E9A2, 0x5A77E590),
+       MK_64(0xD47A5856, 0x8838D63E),
+       MK_64(0x2DD2E496, 0x8586AB7D)
+};
+
+/* blkSize =  256 bits. hashSize =  224 bits */
+const uint64_t SKEIN_256_IV_224[] = {
+       MK_64(0xC6098A8C, 0x9AE5EA0B),
+       MK_64(0x876D5686, 0x08C5191C),
+       MK_64(0x99CB88D7, 0xD7F53884),
+       MK_64(0x384BDDB1, 0xAEDDB5DE)
+};
+
+/* blkSize =  256 bits. hashSize =  256 bits */
+const uint64_t SKEIN_256_IV_256[] = {
+       MK_64(0xFC9DA860, 0xD048B449),
+       MK_64(0x2FCA6647, 0x9FA7D833),
+       MK_64(0xB33BC389, 0x6656840F),
+       MK_64(0x6A54E920, 0xFDE8DA69)
+};
+
+/* blkSize =  512 bits. hashSize =  128 bits */
+const uint64_t SKEIN_512_IV_128[] = {
+       MK_64(0xA8BC7BF3, 0x6FBF9F52),
+       MK_64(0x1E9872CE, 0xBD1AF0AA),
+       MK_64(0x309B1790, 0xB32190D3),
+       MK_64(0xBCFBB854, 0x3F94805C),
+       MK_64(0x0DA61BCD, 0x6E31B11B),
+       MK_64(0x1A18EBEA, 0xD46A32E3),
+       MK_64(0xA2CC5B18, 0xCE84AA82),
+       MK_64(0x6982AB28, 0x9D46982D)
+};
+
+/* blkSize =  512 bits. hashSize =  160 bits */
+const uint64_t SKEIN_512_IV_160[] = {
+       MK_64(0x28B81A2A, 0xE013BD91),
+       MK_64(0xC2F11668, 0xB5BDF78F),
+       MK_64(0x1760D8F3, 0xF6A56F12),
+       MK_64(0x4FB74758, 0x8239904F),
+       MK_64(0x21EDE07F, 0x7EAF5056),
+       MK_64(0xD908922E, 0x63ED70B8),
+       MK_64(0xB8EC76FF, 0xECCB52FA),
+       MK_64(0x01A47BB8, 0xA3F27A6E)
+};
+
+/* blkSize =  512 bits. hashSize =  224 bits */
+const uint64_t SKEIN_512_IV_224[] = {
+       MK_64(0xCCD06162, 0x48677224),
+       MK_64(0xCBA65CF3, 0xA92339EF),
+       MK_64(0x8CCD69D6, 0x52FF4B64),
+       MK_64(0x398AED7B, 0x3AB890B4),
+       MK_64(0x0F59D1B1, 0x457D2BD0),
+       MK_64(0x6776FE65, 0x75D4EB3D),
+       MK_64(0x99FBC70E, 0x997413E9),
+       MK_64(0x9E2CFCCF, 0xE1C41EF7)
+};
+
+/* blkSize =  512 bits. hashSize =  256 bits */
+const uint64_t SKEIN_512_IV_256[] = {
+       MK_64(0xCCD044A1, 0x2FDB3E13),
+       MK_64(0xE8359030, 0x1A79A9EB),
+       MK_64(0x55AEA061, 0x4F816E6F),
+       MK_64(0x2A2767A4, 0xAE9B94DB),
+       MK_64(0xEC06025E, 0x74DD7683),
+       MK_64(0xE7A436CD, 0xC4746251),
+       MK_64(0xC36FBAF9, 0x393AD185),
+       MK_64(0x3EEDBA18, 0x33EDFC13)
+};
+
+/* blkSize =  512 bits. hashSize =  384 bits */
+const uint64_t SKEIN_512_IV_384[] = {
+       MK_64(0xA3F6C6BF, 0x3A75EF5F),
+       MK_64(0xB0FEF9CC, 0xFD84FAA4),
+       MK_64(0x9D77DD66, 0x3D770CFE),
+       MK_64(0xD798CBF3, 0xB468FDDA),
+       MK_64(0x1BC4A666, 0x8A0E4465),
+       MK_64(0x7ED7D434, 0xE5807407),
+       MK_64(0x548FC1AC, 0xD4EC44D6),
+       MK_64(0x266E1754, 0x6AA18FF8)
+};
+
+/* blkSize =  512 bits. hashSize =  512 bits */
+const uint64_t SKEIN_512_IV_512[] = {
+       MK_64(0x4903ADFF, 0x749C51CE),
+       MK_64(0x0D95DE39, 0x9746DF03),
+       MK_64(0x8FD19341, 0x27C79BCE),
+       MK_64(0x9A255629, 0xFF352CB1),
+       MK_64(0x5DB62599, 0xDF6CA7B0),
+       MK_64(0xEABE394C, 0xA9D5C3F4),
+       MK_64(0x991112C7, 0x1A75B523),
+       MK_64(0xAE18A40B, 0x660FCC33)
+};
+
+/* blkSize = 1024 bits. hashSize =  384 bits */
+const uint64_t SKEIN1024_IV_384[] = {
+       MK_64(0x5102B6B8, 0xC1894A35),
+       MK_64(0xFEEBC9E3, 0xFE8AF11A),
+       MK_64(0x0C807F06, 0xE32BED71),
+       MK_64(0x60C13A52, 0xB41A91F6),
+       MK_64(0x9716D35D, 0xD4917C38),
+       MK_64(0xE780DF12, 0x6FD31D3A),
+       MK_64(0x797846B6, 0xC898303A),
+       MK_64(0xB172C2A8, 0xB3572A3B),
+       MK_64(0xC9BC8203, 0xA6104A6C),
+       MK_64(0x65909338, 0xD75624F4),
+       MK_64(0x94BCC568, 0x4B3F81A0),
+       MK_64(0x3EBBF51E, 0x10ECFD46),
+       MK_64(0x2DF50F0B, 0xEEB08542),
+       MK_64(0x3B5A6530, 0x0DBC6516),
+       MK_64(0x484B9CD2, 0x167BBCE1),
+       MK_64(0x2D136947, 0xD4CBAFEA)
+};
+
+/* blkSize = 1024 bits. hashSize =  512 bits */
+const uint64_t SKEIN1024_IV_512[] = {
+       MK_64(0xCAEC0E5D, 0x7C1B1B18),
+       MK_64(0xA01B0E04, 0x5F03E802),
+       MK_64(0x33840451, 0xED912885),
+       MK_64(0x374AFB04, 0xEAEC2E1C),
+       MK_64(0xDF25A0E2, 0x813581F7),
+       MK_64(0xE4004093, 0x8B12F9D2),
+       MK_64(0xA662D539, 0xC2ED39B6),
+       MK_64(0xFA8B85CF, 0x45D8C75A),
+       MK_64(0x8316ED8E, 0x29EDE796),
+       MK_64(0x053289C0, 0x2E9F91B8),
+       MK_64(0xC3F8EF1D, 0x6D518B73),
+       MK_64(0xBDCEC3C4, 0xD5EF332E),
+       MK_64(0x549A7E52, 0x22974487),
+       MK_64(0x67070872, 0x5B749816),
+       MK_64(0xB9CD28FB, 0xF0581BD1),
+       MK_64(0x0E2940B8, 0x15804974)
+};
+
+/* blkSize = 1024 bits. hashSize = 1024 bits */
+const uint64_t SKEIN1024_IV_1024[] = {
+       MK_64(0xD593DA07, 0x41E72355),
+       MK_64(0x15B5E511, 0xAC73E00C),
+       MK_64(0x5180E5AE, 0xBAF2C4F0),
+       MK_64(0x03BD41D3, 0xFCBCAFAF),
+       MK_64(0x1CAEC6FD, 0x1983A898),
+       MK_64(0x6E510B8B, 0xCDD0589F),
+       MK_64(0x77E2BDFD, 0xC6394ADA),
+       MK_64(0xC11E1DB5, 0x24DCB0A3),
+       MK_64(0xD6D14AF9, 0xC6329AB5),
+       MK_64(0x6A9B0BFC, 0x6EB67E0D),
+       MK_64(0x9243C60D, 0xCCFF1332),
+       MK_64(0x1A1F1DDE, 0x743F02D4),
+       MK_64(0x0996753C, 0x10ED0BB8),
+       MK_64(0x6572DD22, 0xF2B4969A),
+       MK_64(0x61FD3062, 0xD00A579A),
+       MK_64(0x1DE0536E, 0x8682E539)
+};
diff --git a/zfs/module/icp/algs/skein/skein_port.h b/zfs/module/icp/algs/skein/skein_port.h
new file mode 100644 (file)
index 0000000..1b02252
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Platform-specific definitions for Skein hash function.
+ *
+ * Source code author: Doug Whiting, 2008.
+ *
+ * This algorithm and source code is released to the public domain.
+ *
+ * Many thanks to Brian Gladman for his portable header files.
+ *
+ * To port Skein to an "unsupported" platform, change the definitions
+ * in this file appropriately.
+ */
+/* Copyright 2013 Doug Whiting. This code is released to the public domain. */
+
+#ifndef        _SKEIN_PORT_H_
+#define        _SKEIN_PORT_H_
+
+#include <sys/types.h> /* get integer type definitions */
+#include <sys/systm.h> /* for bcopy() */
+
+#ifndef        RotL_64
+#define        RotL_64(x, N)   (((x) << (N)) | ((x) >> (64 - (N))))
+#endif
+
+/*
+ * Skein is "natively" little-endian (unlike SHA-xxx), for optimal
+ * performance on x86 CPUs. The Skein code requires the following
+ * definitions for dealing with endianness:
+ *
+ *    SKEIN_NEED_SWAP:  0 for little-endian, 1 for big-endian
+ *    Skein_Put64_LSB_First
+ *    Skein_Get64_LSB_First
+ *    Skein_Swap64
+ *
+ * If SKEIN_NEED_SWAP is defined at compile time, it is used here
+ * along with the portable versions of Put64/Get64/Swap64, which
+ * are slow in general.
+ *
+ * Otherwise, an "auto-detect" of endianness is attempted below.
+ * If the default handling doesn't work well, the user may insert
+ * platform-specific code instead (e.g., for big-endian CPUs).
+ *
+ */
+#ifndef        SKEIN_NEED_SWAP         /* compile-time "override" for endianness? */
+
+#include <sys/isa_defs.h>      /* get endianness selection */
+
+#define        PLATFORM_MUST_ALIGN     _ALIGNMENT_REQUIRED
+#if    defined(_BIG_ENDIAN)
+/* here for big-endian CPUs */
+#define        SKEIN_NEED_SWAP   (1)
+#else
+/* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */
+#define        SKEIN_NEED_SWAP   (0)
+#if    PLATFORM_MUST_ALIGN == 0        /* ok to use "fast" versions? */
+#define        Skein_Put64_LSB_First(dst08, src64, bCnt) bcopy(src64, dst08, bCnt)
+#define        Skein_Get64_LSB_First(dst64, src08, wCnt) \
+       bcopy(src08, dst64, 8 * (wCnt))
+#endif
+#endif
+
+#endif                         /* ifndef SKEIN_NEED_SWAP */
+
+/*
+ * Provide any definitions still needed.
+ */
+#ifndef        Skein_Swap64    /* swap for big-endian, nop for little-endian */
+#if    SKEIN_NEED_SWAP
+#define        Skein_Swap64(w64)                               \
+       (((((uint64_t)(w64)) & 0xFF) << 56) |           \
+       (((((uint64_t)(w64)) >> 8) & 0xFF) << 48) |     \
+       (((((uint64_t)(w64)) >> 16) & 0xFF) << 40) |    \
+       (((((uint64_t)(w64)) >> 24) & 0xFF) << 32) |    \
+       (((((uint64_t)(w64)) >> 32) & 0xFF) << 24) |    \
+       (((((uint64_t)(w64)) >> 40) & 0xFF) << 16) |    \
+       (((((uint64_t)(w64)) >> 48) & 0xFF) << 8) |     \
+       (((((uint64_t)(w64)) >> 56) & 0xFF)))
+#else
+#define        Skein_Swap64(w64)  (w64)
+#endif
+#endif                         /* ifndef Skein_Swap64 */
+
+#ifndef        Skein_Put64_LSB_First
+void
+Skein_Put64_LSB_First(uint8_t *dst, const uint64_t *src, size_t bCnt)
+#ifdef SKEIN_PORT_CODE         /* instantiate the function code here? */
+{
+       /*
+        * this version is fully portable (big-endian or little-endian),
+        * but slow
+        */
+       size_t n;
+
+       for (n = 0; n < bCnt; n++)
+               dst[n] = (uint8_t)(src[n >> 3] >> (8 * (n & 7)));
+}
+#else
+;                              /* output only the function prototype */
+#endif
+#endif                         /* ifndef Skein_Put64_LSB_First */
+
+#ifndef        Skein_Get64_LSB_First
+void
+Skein_Get64_LSB_First(uint64_t *dst, const uint8_t *src, size_t wCnt)
+#ifdef SKEIN_PORT_CODE         /* instantiate the function code here? */
+{
+       /*
+        * this version is fully portable (big-endian or little-endian),
+        * but slow
+        */
+       size_t n;
+
+       for (n = 0; n < 8 * wCnt; n += 8)
+               dst[n / 8] = (((uint64_t)src[n])) +
+                   (((uint64_t)src[n + 1]) << 8) +
+                   (((uint64_t)src[n + 2]) << 16) +
+                   (((uint64_t)src[n + 3]) << 24) +
+                   (((uint64_t)src[n + 4]) << 32) +
+                   (((uint64_t)src[n + 5]) << 40) +
+                   (((uint64_t)src[n + 6]) << 48) +
+                   (((uint64_t)src[n + 7]) << 56);
+}
+#else
+;                              /* output only the function prototype */
+#endif
+#endif                         /* ifndef Skein_Get64_LSB_First */
+
+#endif /* _SKEIN_PORT_H_ */
diff --git a/zfs/module/icp/api/kcf_cipher.c b/zfs/module/icp/api/kcf_cipher.c
new file mode 100644 (file)
index 0000000..2585b7f
--- /dev/null
@@ -0,0 +1,935 @@
+/*
+ * 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/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/sched_impl.h>
+
+#define        CRYPTO_OPS_OFFSET(f)            offsetof(crypto_ops_t, co_##f)
+#define        CRYPTO_CIPHER_OFFSET(f)         offsetof(crypto_cipher_ops_t, f)
+
+/*
+ * Encryption and decryption routines.
+ */
+
+/*
+ * The following are the possible returned values common to all the routines
+ * below. The applicability of some of these return values depends on the
+ * presence of the arguments.
+ *
+ *     CRYPTO_SUCCESS: The operation completed successfully.
+ *     CRYPTO_QUEUED:  A request was submitted successfully. The callback
+ *                     routine will be called when the operation is done.
+ *     CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
+ *     CRYPTO_INVALID_MECH for problems with the 'mech'.
+ *     CRYPTO_INVALID_DATA for bogus 'data'
+ *     CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
+ *     CRYPTO_INVALID_CONTEXT: Not a valid context.
+ *     CRYPTO_BUSY:    Cannot process the request now. Schedule a
+ *                     crypto_bufcall(), or try later.
+ *     CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is
+ *                     capable of a function or a mechanism.
+ *     CRYPTO_INVALID_KEY: bogus 'key' argument.
+ *     CRYPTO_INVALID_PLAINTEXT: bogus 'plaintext' argument.
+ *     CRYPTO_INVALID_CIPHERTEXT: bogus 'ciphertext' argument.
+ */
+
+/*
+ * crypto_cipher_init_prov()
+ *
+ * Arguments:
+ *
+ *     pd:     provider descriptor
+ *     sid:    session id
+ *     mech:   crypto_mechanism_t pointer.
+ *             mech_type is a valid value previously returned by
+ *             crypto_mech2id();
+ *             When the mech's parameter is not NULL, its definition depends
+ *             on the standard definition of the mechanism.
+ *     key:    pointer to a crypto_key_t structure.
+ *     tmpl:   a crypto_ctx_template_t, opaque template of a context of an
+ *             encryption  or decryption with the 'mech' using 'key'.
+ *             'tmpl' is created by a previous call to
+ *             crypto_create_ctx_template().
+ *     ctxp:   Pointer to a crypto_context_t.
+ *     func:   CRYPTO_FG_ENCRYPT or CRYPTO_FG_DECRYPT.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     This is a common function invoked internally by both
+ *     crypto_encrypt_init() and crypto_decrypt_init().
+ *     Asynchronously submits a request for, or synchronously performs the
+ *     initialization of an encryption or a decryption operation.
+ *     When possible and applicable, will internally use the pre-expanded key
+ *     schedule from the context template, tmpl.
+ *     When complete and successful, 'ctxp' will contain a crypto_context_t
+ *     valid for later calls to encrypt_update() and encrypt_final(), or
+ *     decrypt_update() and decrypt_final().
+ *     The caller should hold a reference on the specified provider
+ *     descriptor before calling this function.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+static int
+crypto_cipher_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_spi_ctx_template_t tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *crq, crypto_func_group_t func)
+{
+       int error;
+       crypto_ctx_t *ctx;
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd = provider;
+       kcf_provider_desc_t *real_provider = pd;
+
+       ASSERT(KCF_PROV_REFHELD(pd));
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               if (func == CRYPTO_FG_ENCRYPT) {
+                       error = kcf_get_hardware_provider(mech->cm_type,
+                           CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
+                           &real_provider, CRYPTO_FG_ENCRYPT);
+               } else {
+                       error = kcf_get_hardware_provider(mech->cm_type,
+                           CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
+                           &real_provider, CRYPTO_FG_DECRYPT);
+               }
+
+               if (error != CRYPTO_SUCCESS)
+                       return (error);
+       }
+
+       /* Allocate and initialize the canonical context */
+       if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
+               if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+                       KCF_PROV_REFRELE(real_provider);
+               return (CRYPTO_HOST_MEMORY);
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(crq, pd)) {
+               crypto_mechanism_t lmech;
+
+               lmech = *mech;
+               KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
+
+               if (func == CRYPTO_FG_ENCRYPT)
+                       error = KCF_PROV_ENCRYPT_INIT(real_provider, ctx,
+                           &lmech, key, tmpl, KCF_SWFP_RHNDL(crq));
+               else {
+                       ASSERT(func == CRYPTO_FG_DECRYPT);
+
+                       error = KCF_PROV_DECRYPT_INIT(real_provider, ctx,
+                           &lmech, key, tmpl, KCF_SWFP_RHNDL(crq));
+               }
+               KCF_PROV_INCRSTATS(pd, error);
+
+               goto done;
+       }
+
+       /* Check if context sharing is possible */
+       if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
+           key->ck_format == CRYPTO_KEY_RAW &&
+           KCF_CAN_SHARE_OPSTATE(pd, mech->cm_type)) {
+               kcf_context_t *tctxp = (kcf_context_t *)ctx;
+               kcf_provider_desc_t *tpd = NULL;
+               crypto_mech_info_t *sinfo;
+
+               if ((kcf_get_sw_prov(mech->cm_type, &tpd, &tctxp->kc_mech,
+                   B_FALSE) == CRYPTO_SUCCESS)) {
+                       int tlen;
+
+                       sinfo = &(KCF_TO_PROV_MECHINFO(tpd, mech->cm_type));
+                       /*
+                        * key->ck_length from the consumer is always in bits.
+                        * We convert it to be in the same unit registered by
+                        * the provider in order to do a comparison.
+                        */
+                       if (sinfo->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)
+                               tlen = key->ck_length >> 3;
+                       else
+                               tlen = key->ck_length;
+                       /*
+                        * Check if the software provider can support context
+                        * sharing and support this key length.
+                        */
+                       if ((sinfo->cm_mech_flags & CRYPTO_CAN_SHARE_OPSTATE) &&
+                           (tlen >= sinfo->cm_min_key_length) &&
+                           (tlen <= sinfo->cm_max_key_length)) {
+                               ctx->cc_flags = CRYPTO_INIT_OPSTATE;
+                               tctxp->kc_sw_prov_desc = tpd;
+                       } else
+                               KCF_PROV_REFRELE(tpd);
+               }
+       }
+
+       if (func == CRYPTO_FG_ENCRYPT) {
+               KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_INIT, sid,
+                   mech, key, NULL, NULL, tmpl);
+       } else {
+               ASSERT(func == CRYPTO_FG_DECRYPT);
+               KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_INIT, sid,
+                   mech, key, NULL, NULL, tmpl);
+       }
+
+       error = kcf_submit_request(real_provider, ctx, crq, &params,
+           B_FALSE);
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+               KCF_PROV_REFRELE(real_provider);
+
+done:
+       if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
+               *ctxp = (crypto_context_t)ctx;
+       else {
+               /* Release the hold done in kcf_new_ctx(). */
+               KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
+       }
+
+       return (error);
+}
+
+/*
+ * Same as crypto_cipher_init_prov(), but relies on the scheduler to pick
+ * an appropriate provider. See crypto_cipher_init_prov() comments for more
+ * details.
+ */
+static int
+crypto_cipher_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *crq, crypto_func_group_t func)
+{
+       int error;
+       kcf_mech_entry_t *me;
+       kcf_provider_desc_t *pd;
+       kcf_ctx_template_t *ctx_tmpl;
+       crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
+       kcf_prov_tried_t *list = NULL;
+
+retry:
+       /* pd is returned held */
+       if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
+           list, func, CHECK_RESTRICT(crq), 0)) == NULL) {
+               if (list != NULL)
+                       kcf_free_triedlist(list);
+               return (error);
+       }
+
+       /*
+        * For SW providers, check the validity of the context template
+        * It is very rare that the generation number mis-matches, so
+        * is acceptable to fail here, and let the consumer recover by
+        * freeing this tmpl and create a new one for the key and new SW
+        * provider
+        */
+       if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
+           ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
+               if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
+                       if (list != NULL)
+                               kcf_free_triedlist(list);
+                       KCF_PROV_REFRELE(pd);
+                       return (CRYPTO_OLD_CTX_TEMPLATE);
+               } else {
+                       spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
+               }
+       }
+
+       error = crypto_cipher_init_prov(pd, pd->pd_sid, mech, key,
+           spi_ctx_tmpl, ctxp, crq, func);
+       if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
+           IS_RECOVERABLE(error)) {
+               /* Add pd to the linked list of providers tried. */
+               if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+                       goto retry;
+       }
+
+       if (list != NULL)
+               kcf_free_triedlist(list);
+
+       KCF_PROV_REFRELE(pd);
+       return (error);
+}
+
+/*
+ * crypto_encrypt_prov()
+ *
+ * Arguments:
+ *     pd:     provider descriptor
+ *     sid:    session id
+ *     mech:   crypto_mechanism_t pointer.
+ *             mech_type is a valid value previously returned by
+ *             crypto_mech2id();
+ *             When the mech's parameter is not NULL, its definition depends
+ *             on the standard definition of the mechanism.
+ *     key:    pointer to a crypto_key_t structure.
+ *     plaintext: The message to be encrypted
+ *     ciphertext: Storage for the encrypted message. The length needed
+ *             depends on the mechanism, and the plaintext's size.
+ *     tmpl:   a crypto_ctx_template_t, opaque template of a context of an
+ *             encryption with the 'mech' using 'key'. 'tmpl' is created by
+ *             a previous call to crypto_create_ctx_template().
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs a
+ *     single-part encryption of 'plaintext' with the mechanism 'mech', using
+ *     the key 'key'.
+ *     When complete and successful, 'ciphertext' will contain the encrypted
+ *     message.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_encrypt_prov(crypto_provider_t provider, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_data_t *plaintext, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
+    crypto_call_req_t *crq)
+{
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd = provider;
+       kcf_provider_desc_t *real_provider = pd;
+       int error;
+
+       ASSERT(KCF_PROV_REFHELD(pd));
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               error = kcf_get_hardware_provider(mech->cm_type,
+                   CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
+                   &real_provider, CRYPTO_FG_ENCRYPT_ATOMIC);
+
+               if (error != CRYPTO_SUCCESS)
+                       return (error);
+       }
+
+       KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, key,
+           plaintext, ciphertext, tmpl);
+
+       error = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+               KCF_PROV_REFRELE(real_provider);
+
+       return (error);
+}
+
+/*
+ * Same as crypto_encrypt_prov(), but relies on the scheduler to pick
+ * a provider. See crypto_encrypt_prov() for more details.
+ */
+int
+crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
+    crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
+    crypto_call_req_t *crq)
+{
+       int error;
+       kcf_mech_entry_t *me;
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd;
+       kcf_ctx_template_t *ctx_tmpl;
+       crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
+       kcf_prov_tried_t *list = NULL;
+
+retry:
+       /* pd is returned held */
+       if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
+           list, CRYPTO_FG_ENCRYPT_ATOMIC, CHECK_RESTRICT(crq),
+           plaintext->cd_length)) == NULL) {
+               if (list != NULL)
+                       kcf_free_triedlist(list);
+               return (error);
+       }
+
+       /*
+        * For SW providers, check the validity of the context template
+        * It is very rare that the generation number mis-matches, so
+        * is acceptable to fail here, and let the consumer recover by
+        * freeing this tmpl and create a new one for the key and new SW
+        * provider
+        */
+       if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
+           ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
+               if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
+                       if (list != NULL)
+                               kcf_free_triedlist(list);
+                       KCF_PROV_REFRELE(pd);
+                       return (CRYPTO_OLD_CTX_TEMPLATE);
+               } else {
+                       spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
+               }
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(crq, pd)) {
+               crypto_mechanism_t lmech;
+
+               lmech = *mech;
+               KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+
+               error = KCF_PROV_ENCRYPT_ATOMIC(pd, pd->pd_sid, &lmech, key,
+                   plaintext, ciphertext, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_ATOMIC, pd->pd_sid,
+                   mech, key, plaintext, ciphertext, spi_ctx_tmpl);
+               error = kcf_submit_request(pd, NULL, crq, &params, B_FALSE);
+       }
+
+       if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
+           IS_RECOVERABLE(error)) {
+               /* Add pd to the linked list of providers tried. */
+               if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+                       goto retry;
+       }
+
+       if (list != NULL)
+               kcf_free_triedlist(list);
+
+       KCF_PROV_REFRELE(pd);
+       return (error);
+}
+
+/*
+ * crypto_encrypt_init_prov()
+ *
+ * Calls crypto_cipher_init_prov() to initialize an encryption operation.
+ */
+int
+crypto_encrypt_init_prov(crypto_provider_t pd, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *crq)
+{
+       return (crypto_cipher_init_prov(pd, sid, mech, key, tmpl, ctxp, crq,
+           CRYPTO_FG_ENCRYPT));
+}
+
+/*
+ * crypto_encrypt_init()
+ *
+ * Calls crypto_cipher_init() to initialize an encryption operation
+ */
+int
+crypto_encrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *crq)
+{
+       return (crypto_cipher_init(mech, key, tmpl, ctxp, crq,
+           CRYPTO_FG_ENCRYPT));
+}
+
+/*
+ * crypto_encrypt_update()
+ *
+ * Arguments:
+ *     context: A crypto_context_t initialized by encrypt_init().
+ *     plaintext: The message part to be encrypted
+ *     ciphertext: Storage for the encrypted message part.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs a
+ *     part of an encryption operation.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_encrypt_update(crypto_context_t context, crypto_data_t *plaintext,
+    crypto_data_t *ciphertext, crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_ENCRYPT_UPDATE(pd, ctx, plaintext,
+                   ciphertext, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+               return (error);
+       }
+
+       /* Check if we should use a software provider for small jobs */
+       if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && cr == NULL) {
+               if (plaintext->cd_length < kcf_ctx->kc_mech->me_threshold &&
+                   kcf_ctx->kc_sw_prov_desc != NULL &&
+                   KCF_IS_PROV_USABLE(kcf_ctx->kc_sw_prov_desc)) {
+                       pd = kcf_ctx->kc_sw_prov_desc;
+               }
+       }
+
+       KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_UPDATE,
+           ctx->cc_session, NULL, NULL, plaintext, ciphertext, NULL);
+       error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+
+       return (error);
+}
+
+/*
+ * crypto_encrypt_final()
+ *
+ * Arguments:
+ *     context: A crypto_context_t initialized by encrypt_init().
+ *     ciphertext: Storage for the last part of encrypted message
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs the
+ *     final part of an encryption operation.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_encrypt_final(crypto_context_t context, crypto_data_t *ciphertext,
+    crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_ENCRYPT_FINAL(pd, ctx, ciphertext, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_FINAL,
+                   ctx->cc_session, NULL, NULL, NULL, ciphertext, NULL);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       /* Release the hold done in kcf_new_ctx() during init step. */
+       KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
+       return (error);
+}
+
+/*
+ * crypto_decrypt_prov()
+ *
+ * Arguments:
+ *     pd:     provider descriptor
+ *     sid:    session id
+ *     mech:   crypto_mechanism_t pointer.
+ *             mech_type is a valid value previously returned by
+ *             crypto_mech2id();
+ *             When the mech's parameter is not NULL, its definition depends
+ *             on the standard definition of the mechanism.
+ *     key:    pointer to a crypto_key_t structure.
+ *     ciphertext: The message to be encrypted
+ *     plaintext: Storage for the encrypted message. The length needed
+ *             depends on the mechanism, and the plaintext's size.
+ *     tmpl:   a crypto_ctx_template_t, opaque template of a context of an
+ *             encryption with the 'mech' using 'key'. 'tmpl' is created by
+ *             a previous call to crypto_create_ctx_template().
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs a
+ *     single-part decryption of 'ciphertext' with the mechanism 'mech', using
+ *     the key 'key'.
+ *     When complete and successful, 'plaintext' will contain the decrypted
+ *     message.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_decrypt_prov(crypto_provider_t provider, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_data_t *ciphertext, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
+    crypto_call_req_t *crq)
+{
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd = provider;
+       kcf_provider_desc_t *real_provider = pd;
+       int rv;
+
+       ASSERT(KCF_PROV_REFHELD(pd));
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               rv = kcf_get_hardware_provider(mech->cm_type,
+                   CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
+                   &real_provider, CRYPTO_FG_DECRYPT_ATOMIC);
+
+               if (rv != CRYPTO_SUCCESS)
+                       return (rv);
+       }
+
+       KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, key,
+           ciphertext, plaintext, tmpl);
+
+       rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+               KCF_PROV_REFRELE(real_provider);
+
+       return (rv);
+}
+
+/*
+ * Same as crypto_decrypt_prov(), but relies on the KCF scheduler to
+ * choose a provider. See crypto_decrypt_prov() comments for more
+ * information.
+ */
+int
+crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *ciphertext,
+    crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
+    crypto_call_req_t *crq)
+{
+       int error;
+       kcf_mech_entry_t *me;
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd;
+       kcf_ctx_template_t *ctx_tmpl;
+       crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
+       kcf_prov_tried_t *list = NULL;
+
+retry:
+       /* pd is returned held */
+       if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
+           list, CRYPTO_FG_DECRYPT_ATOMIC, CHECK_RESTRICT(crq),
+           ciphertext->cd_length)) == NULL) {
+               if (list != NULL)
+                       kcf_free_triedlist(list);
+               return (error);
+       }
+
+       /*
+        * For SW providers, check the validity of the context template
+        * It is very rare that the generation number mis-matches, so
+        * is acceptable to fail here, and let the consumer recover by
+        * freeing this tmpl and create a new one for the key and new SW
+        * provider
+        */
+       if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
+           ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
+               if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
+                       if (list != NULL)
+                               kcf_free_triedlist(list);
+                       KCF_PROV_REFRELE(pd);
+                       return (CRYPTO_OLD_CTX_TEMPLATE);
+               } else {
+                       spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
+               }
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(crq, pd)) {
+               crypto_mechanism_t lmech;
+
+               lmech = *mech;
+               KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+
+               error = KCF_PROV_DECRYPT_ATOMIC(pd, pd->pd_sid, &lmech, key,
+                   ciphertext, plaintext, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_ATOMIC, pd->pd_sid,
+                   mech, key, ciphertext, plaintext, spi_ctx_tmpl);
+               error = kcf_submit_request(pd, NULL, crq, &params, B_FALSE);
+       }
+
+       if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
+           IS_RECOVERABLE(error)) {
+               /* Add pd to the linked list of providers tried. */
+               if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+                       goto retry;
+       }
+
+       if (list != NULL)
+               kcf_free_triedlist(list);
+
+       KCF_PROV_REFRELE(pd);
+       return (error);
+}
+
+/*
+ * crypto_decrypt_init_prov()
+ *
+ * Calls crypto_cipher_init_prov() to initialize a decryption operation
+ */
+int
+crypto_decrypt_init_prov(crypto_provider_t pd, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *crq)
+{
+       return (crypto_cipher_init_prov(pd, sid, mech, key, tmpl, ctxp, crq,
+           CRYPTO_FG_DECRYPT));
+}
+
+/*
+ * crypto_decrypt_init()
+ *
+ * Calls crypto_cipher_init() to initialize a decryption operation
+ */
+int
+crypto_decrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t *crq)
+{
+       return (crypto_cipher_init(mech, key, tmpl, ctxp, crq,
+           CRYPTO_FG_DECRYPT));
+}
+
+/*
+ * crypto_decrypt_update()
+ *
+ * Arguments:
+ *     context: A crypto_context_t initialized by decrypt_init().
+ *     ciphertext: The message part to be decrypted
+ *     plaintext: Storage for the decrypted message part.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs a
+ *     part of an decryption operation.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_decrypt_update(crypto_context_t context, crypto_data_t *ciphertext,
+    crypto_data_t *plaintext, crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_DECRYPT_UPDATE(pd, ctx, ciphertext,
+                   plaintext, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+               return (error);
+       }
+
+       /* Check if we should use a software provider for small jobs */
+       if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && cr == NULL) {
+               if (ciphertext->cd_length < kcf_ctx->kc_mech->me_threshold &&
+                   kcf_ctx->kc_sw_prov_desc != NULL &&
+                   KCF_IS_PROV_USABLE(kcf_ctx->kc_sw_prov_desc)) {
+                       pd = kcf_ctx->kc_sw_prov_desc;
+               }
+       }
+
+       KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_UPDATE,
+           ctx->cc_session, NULL, NULL, ciphertext, plaintext, NULL);
+       error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+
+       return (error);
+}
+
+/*
+ * crypto_decrypt_final()
+ *
+ * Arguments:
+ *     context: A crypto_context_t initialized by decrypt_init().
+ *     plaintext: Storage for the last part of the decrypted message
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs the
+ *     final part of a decryption operation.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_decrypt_final(crypto_context_t context, crypto_data_t *plaintext,
+    crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_DECRYPT_FINAL(pd, ctx, plaintext,
+                   NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_FINAL,
+                   ctx->cc_session, NULL, NULL, NULL, plaintext, NULL);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       /* Release the hold done in kcf_new_ctx() during init step. */
+       KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
+       return (error);
+}
+
+/*
+ * See comments for crypto_encrypt_update().
+ */
+int
+crypto_encrypt_single(crypto_context_t context, crypto_data_t *plaintext,
+    crypto_data_t *ciphertext, crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_ENCRYPT(pd, ctx, plaintext,
+                   ciphertext, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_ENCRYPT_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
+                   NULL, NULL, plaintext, ciphertext, NULL);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       /* Release the hold done in kcf_new_ctx() during init step. */
+       KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
+       return (error);
+}
+
+/*
+ * See comments for crypto_decrypt_update().
+ */
+int
+crypto_decrypt_single(crypto_context_t context, crypto_data_t *ciphertext,
+    crypto_data_t *plaintext, crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_DECRYPT(pd, ctx, ciphertext,
+                   plaintext, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_DECRYPT_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
+                   NULL, NULL, ciphertext, plaintext, NULL);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       /* Release the hold done in kcf_new_ctx() during init step. */
+       KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
+       return (error);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(crypto_cipher_init_prov);
+EXPORT_SYMBOL(crypto_cipher_init);
+EXPORT_SYMBOL(crypto_encrypt_prov);
+EXPORT_SYMBOL(crypto_encrypt);
+EXPORT_SYMBOL(crypto_encrypt_init_prov);
+EXPORT_SYMBOL(crypto_encrypt_init);
+EXPORT_SYMBOL(crypto_encrypt_update);
+EXPORT_SYMBOL(crypto_encrypt_final);
+EXPORT_SYMBOL(crypto_decrypt_prov);
+EXPORT_SYMBOL(crypto_decrypt);
+EXPORT_SYMBOL(crypto_decrypt_init_prov);
+EXPORT_SYMBOL(crypto_decrypt_init);
+EXPORT_SYMBOL(crypto_decrypt_update);
+EXPORT_SYMBOL(crypto_decrypt_final);
+EXPORT_SYMBOL(crypto_encrypt_single);
+EXPORT_SYMBOL(crypto_decrypt_single);
+#endif
diff --git a/zfs/module/icp/api/kcf_ctxops.c b/zfs/module/icp/api/kcf_ctxops.c
new file mode 100644 (file)
index 0000000..3f90674
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/sched_impl.h>
+
+/*
+ * Crypto contexts manipulation routines
+ */
+
+/*
+ * crypto_create_ctx_template()
+ *
+ * Arguments:
+ *
+ *     mech:   crypto_mechanism_t pointer.
+ *             mech_type is a valid value previously returned by
+ *             crypto_mech2id();
+ *             When the mech's parameter is not NULL, its definition depends
+ *             on the standard definition of the mechanism.
+ *     key:    pointer to a crypto_key_t structure.
+ *     ptmpl:  a storage for the opaque crypto_ctx_template_t, allocated and
+ *             initialized by the software provider this routine is
+ *             dispatched to.
+ *     kmflag: KM_SLEEP/KM_NOSLEEP mem. alloc. flag.
+ *
+ * Description:
+ *     Redirects the call to the software provider of the specified
+ *     mechanism. That provider will allocate and pre-compute/pre-expand
+ *     the context template, reusable by later calls to crypto_xxx_init().
+ *     The size and address of that provider context template are stored
+ *     in an internal structure, kcf_ctx_template_t. The address of that
+ *     structure is given back to the caller in *ptmpl.
+ *
+ * Context:
+ *     Process or interrupt.
+ *
+ * Returns:
+ *     CRYPTO_SUCCESS when the context template is successfully created.
+ *     CRYPTO_HOST_MEMEORY: mem alloc failure
+ *     CRYPTO_ARGUMENTS_BAD: NULL storage for the ctx template.
+ *     RYPTO_MECHANISM_INVALID: invalid mechanism 'mech'.
+ */
+int
+crypto_create_ctx_template(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t *ptmpl, int kmflag)
+{
+       int error;
+       kcf_mech_entry_t *me;
+       kcf_provider_desc_t *pd;
+       kcf_ctx_template_t *ctx_tmpl;
+       crypto_mechanism_t prov_mech;
+
+       /* A few args validation */
+
+       if (ptmpl == NULL)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       if (mech == NULL)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       error = kcf_get_sw_prov(mech->cm_type, &pd, &me, B_TRUE);
+       if (error != CRYPTO_SUCCESS)
+               return (error);
+
+       if ((ctx_tmpl = (kcf_ctx_template_t *)kmem_alloc(
+           sizeof (kcf_ctx_template_t), kmflag)) == NULL) {
+               KCF_PROV_REFRELE(pd);
+               return (CRYPTO_HOST_MEMORY);
+       }
+
+       /* Pass a mechtype that the provider understands */
+       prov_mech.cm_type = KCF_TO_PROV_MECHNUM(pd, mech->cm_type);
+       prov_mech.cm_param = mech->cm_param;
+       prov_mech.cm_param_len = mech->cm_param_len;
+
+       error = KCF_PROV_CREATE_CTX_TEMPLATE(pd, &prov_mech, key,
+           &(ctx_tmpl->ct_prov_tmpl), &(ctx_tmpl->ct_size), KCF_RHNDL(kmflag));
+
+       if (error == CRYPTO_SUCCESS) {
+               ctx_tmpl->ct_generation = me->me_gen_swprov;
+               *ptmpl = ctx_tmpl;
+       } else {
+               kmem_free(ctx_tmpl, sizeof (kcf_ctx_template_t));
+       }
+       KCF_PROV_REFRELE(pd);
+
+       return (error);
+}
+
+/*
+ * crypto_destroy_ctx_template()
+ *
+ * Arguments:
+ *
+ *     tmpl:   an opaque crypto_ctx_template_t previously created by
+ *             crypto_create_ctx_template()
+ *
+ * Description:
+ *     Frees the inbedded crypto_spi_ctx_template_t, then the
+ *     kcf_ctx_template_t.
+ *
+ * Context:
+ *     Process or interrupt.
+ *
+ */
+void
+crypto_destroy_ctx_template(crypto_ctx_template_t tmpl)
+{
+       kcf_ctx_template_t *ctx_tmpl = (kcf_ctx_template_t *)tmpl;
+
+       if (ctx_tmpl == NULL)
+               return;
+
+       ASSERT(ctx_tmpl->ct_prov_tmpl != NULL);
+
+       bzero(ctx_tmpl->ct_prov_tmpl, ctx_tmpl->ct_size);
+       kmem_free(ctx_tmpl->ct_prov_tmpl, ctx_tmpl->ct_size);
+       kmem_free(ctx_tmpl, sizeof (kcf_ctx_template_t));
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(crypto_create_ctx_template);
+EXPORT_SYMBOL(crypto_destroy_ctx_template);
+#endif
diff --git a/zfs/module/icp/api/kcf_digest.c b/zfs/module/icp/api/kcf_digest.c
new file mode 100644 (file)
index 0000000..b58d3b4
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * 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/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/sched_impl.h>
+
+#define        CRYPTO_OPS_OFFSET(f)            offsetof(crypto_ops_t, co_##f)
+#define        CRYPTO_DIGEST_OFFSET(f)         offsetof(crypto_digest_ops_t, f)
+
+/*
+ * Message digest routines
+ */
+
+/*
+ * The following are the possible returned values common to all the routines
+ * below. The applicability of some of these return values depends on the
+ * presence of the arguments.
+ *
+ *     CRYPTO_SUCCESS: The operation completed successfully.
+ *     CRYPTO_QUEUED:  A request was submitted successfully. The callback
+ *                     routine will be called when the operation is done.
+ *     CRYPTO_MECHANISM_INVALID or CRYPTO_INVALID_MECH_PARAM
+ *                     for problems with the 'mech'.
+ *     CRYPTO_INVALID_DATA for bogus 'data'
+ *     CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
+ *     CRYPTO_INVALID_CONTEXT: Not a valid context.
+ *     CRYPTO_BUSY:    Cannot process the request now. Schedule a
+ *                     crypto_bufcall(), or try later.
+ *     CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED:
+ *                     No provider is capable of a function or a mechanism.
+ */
+
+
+/*
+ * crypto_digest_prov()
+ *
+ * Arguments:
+ *     pd:     pointer to the descriptor of the provider to use for this
+ *             operation.
+ *     sid:    provider session id.
+ *     mech:   crypto_mechanism_t pointer.
+ *             mech_type is a valid value previously returned by
+ *             crypto_mech2id();
+ *             When the mech's parameter is not NULL, its definition depends
+ *             on the standard definition of the mechanism.
+ *     data:   The message to be digested.
+ *     digest: Storage for the digest. The length needed depends on the
+ *             mechanism.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs the
+ *     digesting operation of 'data' on the specified
+ *     provider with the specified session.
+ *     When complete and successful, 'digest' will contain the digest value.
+ *     The caller should hold a reference on the specified provider
+ *     descriptor before calling this function.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_digest_prov(crypto_provider_t provider, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest,
+    crypto_call_req_t *crq)
+{
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd = provider;
+       kcf_provider_desc_t *real_provider = pd;
+       int rv;
+
+       ASSERT(KCF_PROV_REFHELD(pd));
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               rv = kcf_get_hardware_provider(mech->cm_type,
+                   CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq),
+                   pd, &real_provider, CRYPTO_FG_DIGEST_ATOMIC);
+
+               if (rv != CRYPTO_SUCCESS)
+                       return (rv);
+       }
+       KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, NULL,
+           data, digest);
+
+       /* no crypto context to carry between multiple parts. */
+       rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+               KCF_PROV_REFRELE(real_provider);
+
+       return (rv);
+}
+
+
+/*
+ * Same as crypto_digest_prov(), but relies on the KCF scheduler to
+ * choose a provider. See crypto_digest_prov() comments for more information.
+ */
+int
+crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
+    crypto_data_t *digest, crypto_call_req_t *crq)
+{
+       int error;
+       kcf_provider_desc_t *pd;
+       kcf_req_params_t params;
+       kcf_prov_tried_t *list = NULL;
+
+retry:
+       /* The pd is returned held */
+       if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, list,
+           CRYPTO_FG_DIGEST_ATOMIC, CHECK_RESTRICT(crq),
+           data->cd_length)) == NULL) {
+               if (list != NULL)
+                       kcf_free_triedlist(list);
+               return (error);
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(crq, pd)) {
+               crypto_mechanism_t lmech;
+
+               lmech = *mech;
+               KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+               error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data,
+                   digest, KCF_SWFP_RHNDL(crq));
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
+                   (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
+                   (data->cd_length > pd->pd_hash_limit)) {
+                       error = CRYPTO_BUFFER_TOO_BIG;
+               } else {
+                       KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_ATOMIC,
+                           pd->pd_sid, mech, NULL, data, digest);
+
+                       /* no crypto context to carry between multiple parts. */
+                       error = kcf_submit_request(pd, NULL, crq, &params,
+                           B_FALSE);
+               }
+       }
+
+       if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
+           IS_RECOVERABLE(error)) {
+               /* Add pd to the linked list of providers tried. */
+               if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+                       goto retry;
+       }
+
+       if (list != NULL)
+               kcf_free_triedlist(list);
+
+       KCF_PROV_REFRELE(pd);
+       return (error);
+}
+
+/*
+ * crypto_digest_init_prov()
+ *
+ *     pd:     pointer to the descriptor of the provider to use for this
+ *             operation.
+ *     sid:    provider session id.
+ *     mech:   crypto_mechanism_t pointer.
+ *             mech_type is a valid value previously returned by
+ *             crypto_mech2id();
+ *             When the mech's parameter is not NULL, its definition depends
+ *             on the standard definition of the mechanism.
+ *     ctxp:   Pointer to a crypto_context_t.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs the
+ *     initialization of a message digest operation on the specified
+ *     provider with the specified session.
+ *     When complete and successful, 'ctxp' will contain a crypto_context_t
+ *     valid for later calls to digest_update() and digest_final().
+ *     The caller should hold a reference on the specified provider
+ *     descriptor before calling this function.
+ */
+int
+crypto_digest_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_context_t *ctxp, crypto_call_req_t  *crq)
+{
+       int error;
+       crypto_ctx_t *ctx;
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd = provider;
+       kcf_provider_desc_t *real_provider = pd;
+
+       ASSERT(KCF_PROV_REFHELD(pd));
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               error = kcf_get_hardware_provider(mech->cm_type,
+                   CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
+                   &real_provider, CRYPTO_FG_DIGEST);
+
+               if (error != CRYPTO_SUCCESS)
+                       return (error);
+       }
+
+       /* Allocate and initialize the canonical context */
+       if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
+               if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+                       KCF_PROV_REFRELE(real_provider);
+               return (CRYPTO_HOST_MEMORY);
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(crq, pd)) {
+               crypto_mechanism_t lmech;
+
+               lmech = *mech;
+               KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
+               error = KCF_PROV_DIGEST_INIT(real_provider, ctx, &lmech,
+                   KCF_SWFP_RHNDL(crq));
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_INIT, sid,
+                   mech, NULL, NULL, NULL);
+               error = kcf_submit_request(real_provider, ctx, crq, &params,
+                   B_FALSE);
+       }
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+               KCF_PROV_REFRELE(real_provider);
+
+       if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
+               *ctxp = (crypto_context_t)ctx;
+       else {
+               /* Release the hold done in kcf_new_ctx(). */
+               KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
+       }
+
+       return (error);
+}
+
+/*
+ * Same as crypto_digest_init_prov(), but relies on the KCF scheduler
+ * to choose a provider. See crypto_digest_init_prov() comments for
+ * more information.
+ */
+int
+crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
+    crypto_call_req_t  *crq)
+{
+       int error;
+       kcf_provider_desc_t *pd;
+       kcf_prov_tried_t *list = NULL;
+
+retry:
+       /* The pd is returned held */
+       if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error,
+           list, CRYPTO_FG_DIGEST, CHECK_RESTRICT(crq), 0)) == NULL) {
+               if (list != NULL)
+                       kcf_free_triedlist(list);
+               return (error);
+       }
+
+       if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
+           (pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
+               /*
+                * The hardware provider has limited digest support.
+                * So, we fallback early here to using a software provider.
+                *
+                * XXX - need to enhance to do the fallback later in
+                * crypto_digest_update() if the size of accumulated input data
+                * exceeds the maximum size digestable by hardware provider.
+                */
+               error = CRYPTO_BUFFER_TOO_BIG;
+       } else {
+               error = crypto_digest_init_prov(pd, pd->pd_sid,
+                   mech, ctxp, crq);
+       }
+
+       if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
+           IS_RECOVERABLE(error)) {
+               /* Add pd to the linked list of providers tried. */
+               if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+                       goto retry;
+       }
+
+       if (list != NULL)
+               kcf_free_triedlist(list);
+       KCF_PROV_REFRELE(pd);
+       return (error);
+}
+
+/*
+ * crypto_digest_update()
+ *
+ * Arguments:
+ *     context: A crypto_context_t initialized by digest_init().
+ *     data:   The part of message to be digested.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs a
+ *     part of a message digest operation.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_digest_update(crypto_context_t context, crypto_data_t *data,
+    crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_DIGEST_UPDATE(pd, ctx, data, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_UPDATE,
+                   ctx->cc_session, NULL, NULL, data, NULL);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       return (error);
+}
+
+/*
+ * crypto_digest_final()
+ *
+ * Arguments:
+ *     context: A crypto_context_t initialized by digest_init().
+ *     digest: The storage for the digest.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs the
+ *     final part of a message digest operation.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_digest_final(crypto_context_t context, crypto_data_t *digest,
+    crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_DIGEST_FINAL(pd, ctx, digest, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_FINAL,
+                   ctx->cc_session, NULL, NULL, NULL, digest);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       /* Release the hold done in kcf_new_ctx() during init step. */
+       KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
+       return (error);
+}
+
+/*
+ * Performs a digest update on the specified key. Note that there is
+ * no k-API crypto_digest_key() equivalent of this function.
+ */
+int
+crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key,
+    crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_DIGEST_KEY,
+                   ctx->cc_session, NULL, key, NULL, NULL);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       return (error);
+}
+
+/*
+ * See comments for crypto_digest_update() and crypto_digest_final().
+ */
+int
+crypto_digest_single(crypto_context_t context, crypto_data_t *data,
+    crypto_data_t *digest, crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_DIGEST(pd, ctx, data, digest, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_DIGEST_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
+                   NULL, NULL, data, digest);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       /* Release the hold done in kcf_new_ctx() during init step. */
+       KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
+       return (error);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(crypto_digest_prov);
+EXPORT_SYMBOL(crypto_digest);
+EXPORT_SYMBOL(crypto_digest_init_prov);
+EXPORT_SYMBOL(crypto_digest_init);
+EXPORT_SYMBOL(crypto_digest_update);
+EXPORT_SYMBOL(crypto_digest_final);
+EXPORT_SYMBOL(crypto_digest_key_prov);
+EXPORT_SYMBOL(crypto_digest_single);
+#endif
diff --git a/zfs/module/icp/api/kcf_mac.c b/zfs/module/icp/api/kcf_mac.c
new file mode 100644 (file)
index 0000000..2b4691c
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * 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/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/sched_impl.h>
+
+#define        CRYPTO_OPS_OFFSET(f)            offsetof(crypto_ops_t, co_##f)
+#define        CRYPTO_MAC_OFFSET(f)            offsetof(crypto_mac_ops_t, f)
+
+/*
+ * Message authentication codes routines.
+ */
+
+/*
+ * The following are the possible returned values common to all the routines
+ * below. The applicability of some of these return values depends on the
+ * presence of the arguments.
+ *
+ *     CRYPTO_SUCCESS: The operation completed successfully.
+ *     CRYPTO_QUEUED:  A request was submitted successfully. The callback
+ *                     routine will be called when the operation is done.
+ *     CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
+ *     CRYPTO_INVALID_MECH for problems with the 'mech'.
+ *     CRYPTO_INVALID_DATA for bogus 'data'
+ *     CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
+ *     CRYPTO_INVALID_CONTEXT: Not a valid context.
+ *     CRYPTO_BUSY:    Cannot process the request now. Schedule a
+ *                     crypto_bufcall(), or try later.
+ *     CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is
+ *                     capable of a function or a mechanism.
+ *     CRYPTO_INVALID_KEY: bogus 'key' argument.
+ *     CRYPTO_INVALID_MAC: bogus 'mac' argument.
+ */
+
+/*
+ * crypto_mac_prov()
+ *
+ * Arguments:
+ *     mech:   crypto_mechanism_t pointer.
+ *             mech_type is a valid value previously returned by
+ *             crypto_mech2id();
+ *             When the mech's parameter is not NULL, its definition depends
+ *             on the standard definition of the mechanism.
+ *     key:    pointer to a crypto_key_t structure.
+ *     data:   The message to compute the MAC for.
+ *     mac: Storage for the MAC. The length needed depends on the mechanism.
+ *     tmpl:   a crypto_ctx_template_t, opaque template of a context of a
+ *             MAC with the 'mech' using 'key'. 'tmpl' is created by
+ *             a previous call to crypto_create_ctx_template().
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs a
+ *     single-part message authentication of 'data' with the mechanism
+ *     'mech', using * the key 'key', on the specified provider with
+ *     the specified session id.
+ *     When complete and successful, 'mac' will contain the message
+ *     authentication code.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'crq'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_mac_prov(crypto_provider_t provider, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq)
+{
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd = provider;
+       kcf_provider_desc_t *real_provider = pd;
+       int rv;
+
+       ASSERT(KCF_PROV_REFHELD(pd));
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               rv = kcf_get_hardware_provider(mech->cm_type,
+                   CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
+                   &real_provider, CRYPTO_FG_MAC_ATOMIC);
+
+               if (rv != CRYPTO_SUCCESS)
+                       return (rv);
+       }
+
+       KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_ATOMIC, sid, mech, key,
+           data, mac, tmpl);
+       rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+               KCF_PROV_REFRELE(real_provider);
+
+       return (rv);
+}
+
+/*
+ * Same as crypto_mac_prov(), but relies on the KCF scheduler to choose
+ * a provider. See crypto_mac() comments for more information.
+ */
+int
+crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
+    crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
+    crypto_call_req_t *crq)
+{
+       int error;
+       kcf_mech_entry_t *me;
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd;
+       kcf_ctx_template_t *ctx_tmpl;
+       crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
+       kcf_prov_tried_t *list = NULL;
+
+retry:
+       /* The pd is returned held */
+       if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
+           list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq),
+           data->cd_length)) == NULL) {
+               if (list != NULL)
+                       kcf_free_triedlist(list);
+               return (error);
+       }
+
+       /*
+        * For SW providers, check the validity of the context template
+        * It is very rare that the generation number mis-matches, so
+        * is acceptable to fail here, and let the consumer recover by
+        * freeing this tmpl and create a new one for the key and new SW
+        * provider
+        */
+       if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
+           ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
+               if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
+                       if (list != NULL)
+                               kcf_free_triedlist(list);
+                       KCF_PROV_REFRELE(pd);
+                       return (CRYPTO_OLD_CTX_TEMPLATE);
+               } else {
+                       spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
+               }
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(crq, pd)) {
+               crypto_mechanism_t lmech;
+
+               lmech = *mech;
+               KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+
+               error = KCF_PROV_MAC_ATOMIC(pd, pd->pd_sid, &lmech, key, data,
+                   mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
+                   (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
+                   (data->cd_length > pd->pd_hash_limit)) {
+                       /*
+                        * XXX - We need a check to see if this is indeed
+                        * a HMAC. So far, all kernel clients use
+                        * this interface only for HMAC. So, this is fine
+                        * for now.
+                        */
+                       error = CRYPTO_BUFFER_TOO_BIG;
+               } else {
+                       KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_ATOMIC,
+                           pd->pd_sid, mech, key, data, mac, spi_ctx_tmpl);
+
+                       error = kcf_submit_request(pd, NULL, crq, &params,
+                           KCF_ISDUALREQ(crq));
+               }
+       }
+
+       if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
+           IS_RECOVERABLE(error)) {
+               /* Add pd to the linked list of providers tried. */
+               if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+                       goto retry;
+       }
+
+       if (list != NULL)
+               kcf_free_triedlist(list);
+
+       KCF_PROV_REFRELE(pd);
+       return (error);
+}
+
+/*
+ * Single part operation to compute the MAC corresponding to the specified
+ * 'data' and to verify that it matches the MAC specified by 'mac'.
+ * The other arguments are the same as the function crypto_mac_prov().
+ */
+int
+crypto_mac_verify_prov(crypto_provider_t provider, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq)
+{
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd = provider;
+       kcf_provider_desc_t *real_provider = pd;
+       int rv;
+
+       ASSERT(KCF_PROV_REFHELD(pd));
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               rv = kcf_get_hardware_provider(mech->cm_type,
+                   CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
+                   &real_provider, CRYPTO_FG_MAC_ATOMIC);
+
+               if (rv != CRYPTO_SUCCESS)
+                       return (rv);
+       }
+
+       KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_MAC_VERIFY_ATOMIC, sid, mech,
+           key, data, mac, tmpl);
+       rv = kcf_submit_request(real_provider, NULL, crq, &params, B_FALSE);
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+               KCF_PROV_REFRELE(real_provider);
+
+       return (rv);
+}
+
+/*
+ * Same as crypto_mac_verify_prov(), but relies on the KCF scheduler to choose
+ * a provider. See crypto_mac_verify_prov() comments for more information.
+ */
+int
+crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data,
+    crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
+    crypto_call_req_t *crq)
+{
+       int error;
+       kcf_mech_entry_t *me;
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd;
+       kcf_ctx_template_t *ctx_tmpl;
+       crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
+       kcf_prov_tried_t *list = NULL;
+
+retry:
+       /* The pd is returned held */
+       if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
+           list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq),
+           data->cd_length)) == NULL) {
+               if (list != NULL)
+                       kcf_free_triedlist(list);
+               return (error);
+       }
+
+       /*
+        * For SW providers, check the validity of the context template
+        * It is very rare that the generation number mis-matches, so
+        * is acceptable to fail here, and let the consumer recover by
+        * freeing this tmpl and create a new one for the key and new SW
+        * provider
+        */
+       if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
+           ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
+               if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
+                       if (list != NULL)
+                               kcf_free_triedlist(list);
+                       KCF_PROV_REFRELE(pd);
+                       return (CRYPTO_OLD_CTX_TEMPLATE);
+               } else {
+                       spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
+               }
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(crq, pd)) {
+               crypto_mechanism_t lmech;
+
+               lmech = *mech;
+               KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
+
+               error = KCF_PROV_MAC_VERIFY_ATOMIC(pd, pd->pd_sid, &lmech, key,
+                   data, mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
+                   (pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
+                   (data->cd_length > pd->pd_hash_limit)) {
+                       /* see comments in crypto_mac() */
+                       error = CRYPTO_BUFFER_TOO_BIG;
+               } else {
+                       KCF_WRAP_MAC_OPS_PARAMS(&params,
+                           KCF_OP_MAC_VERIFY_ATOMIC, pd->pd_sid, mech,
+                           key, data, mac, spi_ctx_tmpl);
+
+                       error = kcf_submit_request(pd, NULL, crq, &params,
+                           KCF_ISDUALREQ(crq));
+               }
+       }
+
+       if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
+           IS_RECOVERABLE(error)) {
+               /* Add pd to the linked list of providers tried. */
+               if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+                       goto retry;
+       }
+
+       if (list != NULL)
+               kcf_free_triedlist(list);
+
+       KCF_PROV_REFRELE(pd);
+       return (error);
+}
+
+/*
+ * crypto_mac_init_prov()
+ *
+ * Arguments:
+ *     pd:     pointer to the descriptor of the provider to use for this
+ *             operation.
+ *     sid:    provider session id.
+ *     mech:   crypto_mechanism_t pointer.
+ *             mech_type is a valid value previously returned by
+ *             crypto_mech2id();
+ *             When the mech's parameter is not NULL, its definition depends
+ *             on the standard definition of the mechanism.
+ *     key:    pointer to a crypto_key_t structure.
+ *     tmpl:   a crypto_ctx_template_t, opaque template of a context of a
+ *             MAC with the 'mech' using 'key'. 'tmpl' is created by
+ *             a previous call to crypto_create_ctx_template().
+ *     ctxp:   Pointer to a crypto_context_t.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs the
+ *     initialization of a MAC operation on the specified provider with
+ *     the specified session.
+ *     When possible and applicable, will internally use the pre-computed MAC
+ *     context from the context template, tmpl.
+ *     When complete and successful, 'ctxp' will contain a crypto_context_t
+ *     valid for later calls to mac_update() and mac_final().
+ *     The caller should hold a reference on the specified provider
+ *     descriptor before calling this function.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_mac_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
+    crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl,
+    crypto_context_t *ctxp, crypto_call_req_t *crq)
+{
+       int rv;
+       crypto_ctx_t *ctx;
+       kcf_req_params_t params;
+       kcf_provider_desc_t *pd = provider;
+       kcf_provider_desc_t *real_provider = pd;
+
+       ASSERT(KCF_PROV_REFHELD(pd));
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               rv = kcf_get_hardware_provider(mech->cm_type,
+                   CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
+                   &real_provider, CRYPTO_FG_MAC);
+
+               if (rv != CRYPTO_SUCCESS)
+                       return (rv);
+       }
+
+       /* Allocate and initialize the canonical context */
+       if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
+               if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+                       KCF_PROV_REFRELE(real_provider);
+               return (CRYPTO_HOST_MEMORY);
+       }
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(crq, pd)) {
+               crypto_mechanism_t lmech;
+
+               lmech = *mech;
+               KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
+               rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl,
+                   KCF_SWFP_RHNDL(crq));
+               KCF_PROV_INCRSTATS(pd, rv);
+       } else {
+               KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_INIT, sid, mech, key,
+                   NULL, NULL, tmpl);
+               rv = kcf_submit_request(real_provider, ctx, crq, &params,
+                   B_FALSE);
+       }
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
+               KCF_PROV_REFRELE(real_provider);
+
+       if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
+               *ctxp = (crypto_context_t)ctx;
+       else {
+               /* Release the hold done in kcf_new_ctx(). */
+               KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
+       }
+
+       return (rv);
+}
+
+/*
+ * Same as crypto_mac_init_prov(), but relies on the KCF scheduler to
+ * choose a provider. See crypto_mac_init_prov() comments for more
+ * information.
+ */
+int
+crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
+    crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
+    crypto_call_req_t  *crq)
+{
+       int error;
+       kcf_mech_entry_t *me;
+       kcf_provider_desc_t *pd;
+       kcf_ctx_template_t *ctx_tmpl;
+       crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
+       kcf_prov_tried_t *list = NULL;
+
+retry:
+       /* The pd is returned held */
+       if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
+           list, CRYPTO_FG_MAC, CHECK_RESTRICT(crq), 0)) == NULL) {
+               if (list != NULL)
+                       kcf_free_triedlist(list);
+               return (error);
+       }
+
+       /*
+        * For SW providers, check the validity of the context template
+        * It is very rare that the generation number mis-matches, so
+        * is acceptable to fail here, and let the consumer recover by
+        * freeing this tmpl and create a new one for the key and new SW
+        * provider
+        */
+
+       if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
+           ((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
+               if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
+                       if (list != NULL)
+                               kcf_free_triedlist(list);
+                       KCF_PROV_REFRELE(pd);
+                       return (CRYPTO_OLD_CTX_TEMPLATE);
+               } else {
+                       spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
+               }
+       }
+
+       if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
+           (pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
+               /*
+                * The hardware provider has limited HMAC support.
+                * So, we fallback early here to using a software provider.
+                *
+                * XXX - need to enhance to do the fallback later in
+                * crypto_mac_update() if the size of accumulated input data
+                * exceeds the maximum size digestable by hardware provider.
+                */
+               error = CRYPTO_BUFFER_TOO_BIG;
+       } else {
+               error = crypto_mac_init_prov(pd, pd->pd_sid, mech, key,
+                   spi_ctx_tmpl, ctxp, crq);
+       }
+       if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
+           IS_RECOVERABLE(error)) {
+               /* Add pd to the linked list of providers tried. */
+               if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
+                       goto retry;
+       }
+
+       if (list != NULL)
+               kcf_free_triedlist(list);
+
+       KCF_PROV_REFRELE(pd);
+       return (error);
+}
+
+/*
+ * crypto_mac_update()
+ *
+ * Arguments:
+ *     context: A crypto_context_t initialized by mac_init().
+ *     data: The message part to be MAC'ed
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs a
+ *     part of a MAC operation.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_mac_update(crypto_context_t context, crypto_data_t *data,
+    crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       kcf_req_params_t params;
+       int rv;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               rv = KCF_PROV_MAC_UPDATE(pd, ctx, data, NULL);
+               KCF_PROV_INCRSTATS(pd, rv);
+       } else {
+               KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_UPDATE,
+                   ctx->cc_session, NULL, NULL, data, NULL, NULL);
+               rv = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       return (rv);
+}
+
+/*
+ * crypto_mac_final()
+ *
+ * Arguments:
+ *     context: A crypto_context_t initialized by mac_init().
+ *     mac: Storage for the message authentication code.
+ *     cr:     crypto_call_req_t calling conditions and call back info.
+ *
+ * Description:
+ *     Asynchronously submits a request for, or synchronously performs a
+ *     part of a message authentication operation.
+ *
+ * Context:
+ *     Process or interrupt, according to the semantics dictated by the 'cr'.
+ *
+ * Returns:
+ *     See comment in the beginning of the file.
+ */
+int
+crypto_mac_final(crypto_context_t context, crypto_data_t *mac,
+    crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       kcf_req_params_t params;
+       int rv;
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+       ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               rv = KCF_PROV_MAC_FINAL(pd, ctx, mac, NULL);
+               KCF_PROV_INCRSTATS(pd, rv);
+       } else {
+               KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_FINAL,
+                   ctx->cc_session, NULL, NULL, NULL, mac, NULL);
+               rv = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       /* Release the hold done in kcf_new_ctx() during init step. */
+       KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx);
+       return (rv);
+}
+
+/*
+ * See comments for crypto_mac_update() and crypto_mac_final().
+ */
+int
+crypto_mac_single(crypto_context_t context, crypto_data_t *data,
+    crypto_data_t *mac, crypto_call_req_t *cr)
+{
+       crypto_ctx_t *ctx = (crypto_ctx_t *)context;
+       kcf_context_t *kcf_ctx;
+       kcf_provider_desc_t *pd;
+       int error;
+       kcf_req_params_t params;
+
+
+       if ((ctx == NULL) ||
+           ((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
+           ((pd = kcf_ctx->kc_prov_desc) == NULL)) {
+               return (CRYPTO_INVALID_CONTEXT);
+       }
+
+
+       /* The fast path for SW providers. */
+       if (CHECK_FASTPATH(cr, pd)) {
+               error = KCF_PROV_MAC(pd, ctx, data, mac, NULL);
+               KCF_PROV_INCRSTATS(pd, error);
+       } else {
+               KCF_WRAP_MAC_OPS_PARAMS(&params, KCF_OP_SINGLE, pd->pd_sid,
+                   NULL, NULL, data, mac, NULL);
+               error = kcf_submit_request(pd, ctx, cr, &params, B_FALSE);
+       }
+
+       /* Release the hold done in kcf_new_ctx() during init step. */
+       KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
+       return (error);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(crypto_mac_prov);
+EXPORT_SYMBOL(crypto_mac);
+EXPORT_SYMBOL(crypto_mac_verify_prov);
+EXPORT_SYMBOL(crypto_mac_verify);
+EXPORT_SYMBOL(crypto_mac_init_prov);
+EXPORT_SYMBOL(crypto_mac_init);
+EXPORT_SYMBOL(crypto_mac_update);
+EXPORT_SYMBOL(crypto_mac_final);
+EXPORT_SYMBOL(crypto_mac_single);
+#endif
diff --git a/zfs/module/icp/api/kcf_miscapi.c b/zfs/module/icp/api/kcf_miscapi.c
new file mode 100644 (file)
index 0000000..09d50f7
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/sched_impl.h>
+
+/*
+ * All event subscribers are put on a list. kcf_notify_list_lock
+ * protects changes to this list.
+ *
+ * The following locking order is maintained in the code - The
+ * global kcf_notify_list_lock followed by the individual lock
+ * in a kcf_ntfy_elem structure (kn_lock).
+ */
+kmutex_t               ntfy_list_lock;
+kcondvar_t             ntfy_list_cv;   /* cv the service thread waits on */
+static kcf_ntfy_elem_t *ntfy_list_head;
+
+/*
+ * crypto_mech2id()
+ *
+ * Arguments:
+ *     . mechname: A null-terminated string identifying the mechanism name.
+ *
+ * Description:
+ *     Walks the mechanisms tables, looking for an entry that matches the
+ *     mechname. Once it find it, it builds the 64-bit mech_type and returns
+ *     it.  If there are no hardware or software providers for the mechanism,
+ *     but there is an unloaded software provider, this routine will attempt
+ *     to load it.
+ *
+ * Context:
+ *     Process and interruption.
+ *
+ * Returns:
+ *     The unique mechanism identified by 'mechname', if found.
+ *     CRYPTO_MECH_INVALID otherwise.
+ */
+crypto_mech_type_t
+crypto_mech2id(char *mechname)
+{
+       return (crypto_mech2id_common(mechname, B_TRUE));
+}
+
+/*
+ * We walk the notification list and do the callbacks.
+ */
+void
+kcf_walk_ntfylist(uint32_t event, void *event_arg)
+{
+       kcf_ntfy_elem_t *nep;
+       int nelem = 0;
+
+       mutex_enter(&ntfy_list_lock);
+
+       /*
+        * Count how many clients are on the notification list. We need
+        * this count to ensure that clients which joined the list after we
+        * have started this walk, are not wrongly notified.
+        */
+       for (nep = ntfy_list_head; nep != NULL; nep = nep->kn_next)
+               nelem++;
+
+       for (nep = ntfy_list_head; (nep != NULL && nelem); nep = nep->kn_next) {
+               nelem--;
+
+               /*
+                * Check if this client is interested in the
+                * event.
+                */
+               if (!(nep->kn_event_mask & event))
+                       continue;
+
+               mutex_enter(&nep->kn_lock);
+               nep->kn_state = NTFY_RUNNING;
+               mutex_exit(&nep->kn_lock);
+               mutex_exit(&ntfy_list_lock);
+
+               /*
+                * We invoke the callback routine with no locks held. Another
+                * client could have joined the list meanwhile. This is fine
+                * as we maintain nelem as stated above. The NULL check in the
+                * for loop guards against shrinkage. Also, any callers of
+                * crypto_unnotify_events() at this point cv_wait till kn_state
+                * changes to NTFY_WAITING. Hence, nep is assured to be valid.
+                */
+               (*nep->kn_func)(event, event_arg);
+
+               mutex_enter(&nep->kn_lock);
+               nep->kn_state = NTFY_WAITING;
+               cv_broadcast(&nep->kn_cv);
+               mutex_exit(&nep->kn_lock);
+
+               mutex_enter(&ntfy_list_lock);
+       }
+
+       mutex_exit(&ntfy_list_lock);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+EXPORT_SYMBOL(crypto_mech2id);
+#endif
diff --git a/zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman b/zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman
new file mode 100644 (file)
index 0000000..48fea7b
--- /dev/null
@@ -0,0 +1,23 @@
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software is allowed (with or without
+ changes) provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
diff --git a/zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman.descrip b/zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman.descrip
new file mode 100644 (file)
index 0000000..5f822cf
--- /dev/null
@@ -0,0 +1 @@
+PORTIONS OF AES FUNCTIONALITY
diff --git a/zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl b/zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl
new file mode 100644 (file)
index 0000000..a2c4adc
--- /dev/null
@@ -0,0 +1,127 @@
+
+  LICENSE ISSUES
+  ==============
+
+  The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
+  the OpenSSL License and the original SSLeay license apply to the toolkit.
+  See below for the actual license texts. Actually both licenses are BSD-style
+  Open Source licenses. In case of any license issues related to OpenSSL
+  please contact openssl-core@openssl.org.
+
+  OpenSSL License
+  ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2008 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
diff --git a/zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl.descrip b/zfs/module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl.descrip
new file mode 100644 (file)
index 0000000..5f822cf
--- /dev/null
@@ -0,0 +1 @@
+PORTIONS OF AES FUNCTIONALITY
diff --git a/zfs/module/icp/asm-x86_64/aes/aes_amd64.S b/zfs/module/icp/asm-x86_64/aes/aes_amd64.S
new file mode 100644 (file)
index 0000000..fa66dc3
--- /dev/null
@@ -0,0 +1,904 @@
+/*
+ * ---------------------------------------------------------------------------
+ * Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software is allowed (with or without
+ * changes) provided that:
+ *
+ *  1. source code distributions include the above copyright notice, this
+ *     list of conditions and the following disclaimer;
+ *
+ *  2. binary distributions include the above copyright notice, this list
+ *     of conditions and the following disclaimer in their documentation;
+ *
+ *  3. the name of the copyright holder is not used to endorse products
+ *     built using this software without specific written permission.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ * Issue 20/12/2007
+ *
+ * I am grateful to Dag Arne Osvik for many discussions of the techniques that
+ * can be used to optimise AES assembler code on AMD64/EM64T architectures.
+ * Some of the techniques used in this implementation are the result of
+ * suggestions made by him for which I am most grateful.
+ *
+ * An AES implementation for AMD64 processors using the YASM assembler.  This
+ * implementation provides only encryption, decryption and hence requires key
+ * scheduling support in C. It uses 8k bytes of tables but its encryption and
+ * decryption performance is very close to that obtained using large tables.
+ * It can use either MS Windows or Gnu/Linux/OpenSolaris OS calling conventions,
+ * which are as follows:
+ *               ms windows  gnu/linux/opensolaris os
+ *
+ *   in_blk          rcx     rdi
+ *   out_blk         rdx     rsi
+ *   context (cx)     r8     rdx
+ *
+ *   preserved       rsi      -    + rbx, rbp, rsp, r12, r13, r14 & r15
+ *   registers       rdi      -      on both
+ *
+ *   destroyed        -      rsi   + rax, rcx, rdx, r8, r9, r10 & r11
+ *   registers        -      rdi     on both
+ *
+ * The convention used here is that for gnu/linux/opensolaris os.
+ *
+ * This code provides the standard AES block size (128 bits, 16 bytes) and the
+ * three standard AES key sizes (128, 192 and 256 bits). It has the same call
+ * interface as my C implementation.  It uses the Microsoft C AMD64 calling
+ * conventions in which the three parameters are placed in  rcx, rdx and r8
+ * respectively.  The rbx, rsi, rdi, rbp and r12..r15 registers are preserved.
+ *
+ * OpenSolaris Note:
+ * Modified to use GNU/Linux/Solaris calling conventions.
+ * That is parameters are placed in rdi, rsi, rdx, and rcx, respectively.
+ *
+ *     AES_RETURN aes_encrypt(const unsigned char in_blk[],
+ *                   unsigned char out_blk[], const aes_encrypt_ctx cx[1])/
+ *
+ *     AES_RETURN aes_decrypt(const unsigned char in_blk[],
+ *                   unsigned char out_blk[], const aes_decrypt_ctx cx[1])/
+ *
+ *     AES_RETURN aes_encrypt_key<NNN>(const unsigned char key[],
+ *                                            const aes_encrypt_ctx cx[1])/
+ *
+ *     AES_RETURN aes_decrypt_key<NNN>(const unsigned char key[],
+ *                                            const aes_decrypt_ctx cx[1])/
+ *
+ *     AES_RETURN aes_encrypt_key(const unsigned char key[],
+ *                           unsigned int len, const aes_decrypt_ctx cx[1])/
+ *
+ *     AES_RETURN aes_decrypt_key(const unsigned char key[],
+ *                           unsigned int len, const aes_decrypt_ctx cx[1])/
+ *
+ * where <NNN> is 128, 102 or 256.  In the last two calls the length can be in
+ * either bits or bytes.
+ *
+ * Comment in/out the following lines to obtain the desired subroutines. These
+ * selections MUST match those in the C header file aesopt.h
+ */
+#define        AES_REV_DKS       /* define if key decryption schedule is reversed */
+
+#define        LAST_ROUND_TABLES /* define for the faster version using extra tables */
+
+/*
+ * The encryption key schedule has the following in memory layout where N is the
+ * number of rounds (10, 12 or 14):
+ *
+ * lo: | input key (round 0)  |  / each round is four 32-bit words
+ *     | encryption round 1   |
+ *     | encryption round 2   |
+ *     ....
+ *     | encryption round N-1 |
+ * hi: | encryption round N   |
+ *
+ * The decryption key schedule is normally set up so that it has the same
+ * layout as above by actually reversing the order of the encryption key
+ * schedule in memory (this happens when AES_REV_DKS is set):
+ *
+ * lo: | decryption round 0   | =              | encryption round N   |
+ *     | decryption round 1   | = INV_MIX_COL[ | encryption round N-1 | ]
+ *     | decryption round 2   | = INV_MIX_COL[ | encryption round N-2 | ]
+ *     ....                       ....
+ *     | decryption round N-1 | = INV_MIX_COL[ | encryption round 1   | ]
+ * hi: | decryption round N   | =              | input key (round 0)  |
+ *
+ * with rounds except the first and last modified using inv_mix_column()
+ * But if AES_REV_DKS is NOT set the order of keys is left as it is for
+ * encryption so that it has to be accessed in reverse when used for
+ * decryption (although the inverse mix column modifications are done)
+ *
+ * lo: | decryption round 0   | =              | input key (round 0)  |
+ *     | decryption round 1   | = INV_MIX_COL[ | encryption round 1   | ]
+ *     | decryption round 2   | = INV_MIX_COL[ | encryption round 2   | ]
+ *     ....                       ....
+ *     | decryption round N-1 | = INV_MIX_COL[ | encryption round N-1 | ]
+ * hi: | decryption round N   | =              | encryption round N   |
+ *
+ * This layout is faster when the assembler key scheduling provided here
+ * is used.
+ *
+ * End of user defines
+ */
+
+/*
+ * ---------------------------------------------------------------------------
+ * OpenSolaris OS modifications
+ *
+ * This source originates from Brian Gladman file aes_amd64.asm
+ * in http://fp.gladman.plus.com/AES/aes-src-04-03-08.zip
+ * with these changes:
+ *
+ * 1. Removed MS Windows-specific code within DLL_EXPORT, _SEH_, and
+ * !__GNUC__ ifdefs.  Also removed ENCRYPTION, DECRYPTION,
+ * AES_128, AES_192, AES_256, AES_VAR ifdefs.
+ *
+ * 2. Translate yasm/nasm %define and .macro definitions to cpp(1) #define
+ *
+ * 3. Translate yasm/nasm %ifdef/%ifndef to cpp(1) #ifdef
+ *
+ * 4. Translate Intel/yasm/nasm syntax to ATT/OpenSolaris as(1) syntax
+ * (operands reversed, literals prefixed with "$", registers prefixed with "%",
+ * and "[register+offset]", addressing changed to "offset(register)",
+ * parenthesis in constant expressions "()" changed to square brackets "[]",
+ * "." removed from  local (numeric) labels, and other changes.
+ * Examples:
+ * Intel/yasm/nasm Syntax      ATT/OpenSolaris Syntax
+ * mov rax,(4*20h)             mov     $[4*0x20],%rax
+ * mov rax,[ebx+20h]           mov     0x20(%ebx),%rax
+ * lea rax,[ebx+ecx]           lea     (%ebx,%ecx),%rax
+ * sub rax,[ebx+ecx*4-20h]     sub     -0x20(%ebx,%ecx,4),%rax
+ *
+ * 5. Added OpenSolaris ENTRY_NP/SET_SIZE macros from
+ * /usr/include/sys/asm_linkage.h, lint(1B) guards, and dummy C function
+ * definitions for lint.
+ *
+ * 6. Renamed functions and reordered parameters to match OpenSolaris:
+ * Original Gladman interface:
+ *     int aes_encrypt(const unsigned char *in,
+ *             unsigned char *out, const aes_encrypt_ctx cx[1])/
+ *     int aes_decrypt(const unsigned char *in,
+ *             unsigned char *out, const aes_encrypt_ctx cx[1])/
+ * Note: aes_encrypt_ctx contains ks, a 60 element array of uint32_t,
+ * and a union type, inf., containing inf.l, a uint32_t and
+ * inf.b, a 4-element array of uint32_t.  Only b[0] in the array (aka "l") is
+ * used and contains the key schedule length * 16 where key schedule length is
+ * 10, 12, or 14 bytes.
+ *
+ * OpenSolaris OS interface:
+ *     void aes_encrypt_amd64(const aes_ks_t *ks, int Nr,
+ *             const uint32_t pt[4], uint32_t ct[4])/
+ *     void aes_decrypt_amd64(const aes_ks_t *ks, int Nr,
+ *             const uint32_t pt[4], uint32_t ct[4])/
+ *     typedef union {uint64_t ks64[(MAX_AES_NR + 1) * 4]/
+ *              uint32_t ks32[(MAX_AES_NR + 1) * 4]/ } aes_ks_t/
+ * Note: ks is the AES key schedule, Nr is number of rounds, pt is plain text,
+ * ct is crypto text, and MAX_AES_NR is 14.
+ * For the x86 64-bit architecture, OpenSolaris OS uses ks32 instead of ks64.
+ */
+
+#if defined(lint) || defined(__lint)
+
+#include <sys/types.h>
+/* ARGSUSED */
+void
+aes_encrypt_amd64(const uint32_t rk[], int Nr, const uint32_t pt[4],
+       uint32_t ct[4]) {
+}
+/* ARGSUSED */
+void
+aes_decrypt_amd64(const uint32_t rk[], int Nr, const uint32_t ct[4],
+       uint32_t pt[4]) {
+}
+
+
+#else
+
+#define _ASM
+#include <sys/asm_linkage.h>
+
+#define        KS_LENGTH       60
+
+#define        raxd            eax
+#define        rdxd            edx
+#define        rcxd            ecx
+#define        rbxd            ebx
+#define        rsid            esi
+#define        rdid            edi
+
+#define        raxb            al
+#define        rdxb            dl
+#define        rcxb            cl
+#define        rbxb            bl
+#define        rsib            sil
+#define        rdib            dil
+
+// finite field multiplies by {02}, {04} and {08}
+
+#define        f2(x) [[x<<1]^[[[x>>7]&1]*0x11b]]
+#define        f4(x) [[x<<2]^[[[x>>6]&1]*0x11b]^[[[x>>6]&2]*0x11b]]
+#define        f8(x) [[x<<3]^[[[x>>5]&1]*0x11b]^[[[x>>5]&2]*0x11b]^[[[x>>5]&4]*0x11b]]
+
+// finite field multiplies required in table generation
+
+#define        f3(x) [[f2(x)] ^ [x]]
+#define        f9(x) [[f8(x)] ^ [x]]
+#define        fb(x) [[f8(x)] ^ [f2(x)] ^ [x]]
+#define        fd(x) [[f8(x)] ^ [f4(x)] ^ [x]]
+#define        fe(x) [[f8(x)] ^ [f4(x)] ^ [f2(x)]]
+
+// macros for expanding S-box data
+
+#define        u8(x) [f2(x)], [x], [x], [f3(x)], [f2(x)], [x], [x], [f3(x)]
+#define        v8(x) [fe(x)], [f9(x)], [fd(x)], [fb(x)], [fe(x)], [f9(x)], [fd(x)], [x]
+#define        w8(x) [x], 0, 0, 0, [x], 0, 0, 0
+
+#define        enc_vals(x)     \
+   .byte x(0x63),x(0x7c),x(0x77),x(0x7b),x(0xf2),x(0x6b),x(0x6f),x(0xc5); \
+   .byte x(0x30),x(0x01),x(0x67),x(0x2b),x(0xfe),x(0xd7),x(0xab),x(0x76); \
+   .byte x(0xca),x(0x82),x(0xc9),x(0x7d),x(0xfa),x(0x59),x(0x47),x(0xf0); \
+   .byte x(0xad),x(0xd4),x(0xa2),x(0xaf),x(0x9c),x(0xa4),x(0x72),x(0xc0); \
+   .byte x(0xb7),x(0xfd),x(0x93),x(0x26),x(0x36),x(0x3f),x(0xf7),x(0xcc); \
+   .byte x(0x34),x(0xa5),x(0xe5),x(0xf1),x(0x71),x(0xd8),x(0x31),x(0x15); \
+   .byte x(0x04),x(0xc7),x(0x23),x(0xc3),x(0x18),x(0x96),x(0x05),x(0x9a); \
+   .byte x(0x07),x(0x12),x(0x80),x(0xe2),x(0xeb),x(0x27),x(0xb2),x(0x75); \
+   .byte x(0x09),x(0x83),x(0x2c),x(0x1a),x(0x1b),x(0x6e),x(0x5a),x(0xa0); \
+   .byte x(0x52),x(0x3b),x(0xd6),x(0xb3),x(0x29),x(0xe3),x(0x2f),x(0x84); \
+   .byte x(0x53),x(0xd1),x(0x00),x(0xed),x(0x20),x(0xfc),x(0xb1),x(0x5b); \
+   .byte x(0x6a),x(0xcb),x(0xbe),x(0x39),x(0x4a),x(0x4c),x(0x58),x(0xcf); \
+   .byte x(0xd0),x(0xef),x(0xaa),x(0xfb),x(0x43),x(0x4d),x(0x33),x(0x85); \
+   .byte x(0x45),x(0xf9),x(0x02),x(0x7f),x(0x50),x(0x3c),x(0x9f),x(0xa8); \
+   .byte x(0x51),x(0xa3),x(0x40),x(0x8f),x(0x92),x(0x9d),x(0x38),x(0xf5); \
+   .byte x(0xbc),x(0xb6),x(0xda),x(0x21),x(0x10),x(0xff),x(0xf3),x(0xd2); \
+   .byte x(0xcd),x(0x0c),x(0x13),x(0xec),x(0x5f),x(0x97),x(0x44),x(0x17); \
+   .byte x(0xc4),x(0xa7),x(0x7e),x(0x3d),x(0x64),x(0x5d),x(0x19),x(0x73); \
+   .byte x(0x60),x(0x81),x(0x4f),x(0xdc),x(0x22),x(0x2a),x(0x90),x(0x88); \
+   .byte x(0x46),x(0xee),x(0xb8),x(0x14),x(0xde),x(0x5e),x(0x0b),x(0xdb); \
+   .byte x(0xe0),x(0x32),x(0x3a),x(0x0a),x(0x49),x(0x06),x(0x24),x(0x5c); \
+   .byte x(0xc2),x(0xd3),x(0xac),x(0x62),x(0x91),x(0x95),x(0xe4),x(0x79); \
+   .byte x(0xe7),x(0xc8),x(0x37),x(0x6d),x(0x8d),x(0xd5),x(0x4e),x(0xa9); \
+   .byte x(0x6c),x(0x56),x(0xf4),x(0xea),x(0x65),x(0x7a),x(0xae),x(0x08); \
+   .byte x(0xba),x(0x78),x(0x25),x(0x2e),x(0x1c),x(0xa6),x(0xb4),x(0xc6); \
+   .byte x(0xe8),x(0xdd),x(0x74),x(0x1f),x(0x4b),x(0xbd),x(0x8b),x(0x8a); \
+   .byte x(0x70),x(0x3e),x(0xb5),x(0x66),x(0x48),x(0x03),x(0xf6),x(0x0e); \
+   .byte x(0x61),x(0x35),x(0x57),x(0xb9),x(0x86),x(0xc1),x(0x1d),x(0x9e); \
+   .byte x(0xe1),x(0xf8),x(0x98),x(0x11),x(0x69),x(0xd9),x(0x8e),x(0x94); \
+   .byte x(0x9b),x(0x1e),x(0x87),x(0xe9),x(0xce),x(0x55),x(0x28),x(0xdf); \
+   .byte x(0x8c),x(0xa1),x(0x89),x(0x0d),x(0xbf),x(0xe6),x(0x42),x(0x68); \
+   .byte x(0x41),x(0x99),x(0x2d),x(0x0f),x(0xb0),x(0x54),x(0xbb),x(0x16)
+
+#define        dec_vals(x) \
+   .byte x(0x52),x(0x09),x(0x6a),x(0xd5),x(0x30),x(0x36),x(0xa5),x(0x38); \
+   .byte x(0xbf),x(0x40),x(0xa3),x(0x9e),x(0x81),x(0xf3),x(0xd7),x(0xfb); \
+   .byte x(0x7c),x(0xe3),x(0x39),x(0x82),x(0x9b),x(0x2f),x(0xff),x(0x87); \
+   .byte x(0x34),x(0x8e),x(0x43),x(0x44),x(0xc4),x(0xde),x(0xe9),x(0xcb); \
+   .byte x(0x54),x(0x7b),x(0x94),x(0x32),x(0xa6),x(0xc2),x(0x23),x(0x3d); \
+   .byte x(0xee),x(0x4c),x(0x95),x(0x0b),x(0x42),x(0xfa),x(0xc3),x(0x4e); \
+   .byte x(0x08),x(0x2e),x(0xa1),x(0x66),x(0x28),x(0xd9),x(0x24),x(0xb2); \
+   .byte x(0x76),x(0x5b),x(0xa2),x(0x49),x(0x6d),x(0x8b),x(0xd1),x(0x25); \
+   .byte x(0x72),x(0xf8),x(0xf6),x(0x64),x(0x86),x(0x68),x(0x98),x(0x16); \
+   .byte x(0xd4),x(0xa4),x(0x5c),x(0xcc),x(0x5d),x(0x65),x(0xb6),x(0x92); \
+   .byte x(0x6c),x(0x70),x(0x48),x(0x50),x(0xfd),x(0xed),x(0xb9),x(0xda); \
+   .byte x(0x5e),x(0x15),x(0x46),x(0x57),x(0xa7),x(0x8d),x(0x9d),x(0x84); \
+   .byte x(0x90),x(0xd8),x(0xab),x(0x00),x(0x8c),x(0xbc),x(0xd3),x(0x0a); \
+   .byte x(0xf7),x(0xe4),x(0x58),x(0x05),x(0xb8),x(0xb3),x(0x45),x(0x06); \
+   .byte x(0xd0),x(0x2c),x(0x1e),x(0x8f),x(0xca),x(0x3f),x(0x0f),x(0x02); \
+   .byte x(0xc1),x(0xaf),x(0xbd),x(0x03),x(0x01),x(0x13),x(0x8a),x(0x6b); \
+   .byte x(0x3a),x(0x91),x(0x11),x(0x41),x(0x4f),x(0x67),x(0xdc),x(0xea); \
+   .byte x(0x97),x(0xf2),x(0xcf),x(0xce),x(0xf0),x(0xb4),x(0xe6),x(0x73); \
+   .byte x(0x96),x(0xac),x(0x74),x(0x22),x(0xe7),x(0xad),x(0x35),x(0x85); \
+   .byte x(0xe2),x(0xf9),x(0x37),x(0xe8),x(0x1c),x(0x75),x(0xdf),x(0x6e); \
+   .byte x(0x47),x(0xf1),x(0x1a),x(0x71),x(0x1d),x(0x29),x(0xc5),x(0x89); \
+   .byte x(0x6f),x(0xb7),x(0x62),x(0x0e),x(0xaa),x(0x18),x(0xbe),x(0x1b); \
+   .byte x(0xfc),x(0x56),x(0x3e),x(0x4b),x(0xc6),x(0xd2),x(0x79),x(0x20); \
+   .byte x(0x9a),x(0xdb),x(0xc0),x(0xfe),x(0x78),x(0xcd),x(0x5a),x(0xf4); \
+   .byte x(0x1f),x(0xdd),x(0xa8),x(0x33),x(0x88),x(0x07),x(0xc7),x(0x31); \
+   .byte x(0xb1),x(0x12),x(0x10),x(0x59),x(0x27),x(0x80),x(0xec),x(0x5f); \
+   .byte x(0x60),x(0x51),x(0x7f),x(0xa9),x(0x19),x(0xb5),x(0x4a),x(0x0d); \
+   .byte x(0x2d),x(0xe5),x(0x7a),x(0x9f),x(0x93),x(0xc9),x(0x9c),x(0xef); \
+   .byte x(0xa0),x(0xe0),x(0x3b),x(0x4d),x(0xae),x(0x2a),x(0xf5),x(0xb0); \
+   .byte x(0xc8),x(0xeb),x(0xbb),x(0x3c),x(0x83),x(0x53),x(0x99),x(0x61); \
+   .byte x(0x17),x(0x2b),x(0x04),x(0x7e),x(0xba),x(0x77),x(0xd6),x(0x26); \
+   .byte x(0xe1),x(0x69),x(0x14),x(0x63),x(0x55),x(0x21),x(0x0c),x(0x7d)
+
+#define        tptr    %rbp    /* table pointer */
+#define        kptr    %r8     /* key schedule pointer */
+#define        fofs    128     /* adjust offset in key schedule to keep |disp| < 128 */
+#define        fk_ref(x, y)    -16*x+fofs+4*y(kptr)
+
+#ifdef AES_REV_DKS
+#define        rofs            128
+#define        ik_ref(x, y)    -16*x+rofs+4*y(kptr)
+
+#else
+#define        rofs            -128
+#define        ik_ref(x, y)    16*x+rofs+4*y(kptr)
+#endif /* AES_REV_DKS */
+
+#define        tab_0(x)        (tptr,x,8)
+#define        tab_1(x)        3(tptr,x,8)
+#define        tab_2(x)        2(tptr,x,8)
+#define        tab_3(x)        1(tptr,x,8)
+#define        tab_f(x)        1(tptr,x,8)
+#define        tab_i(x)        7(tptr,x,8)
+
+#define        ff_rnd(p1, p2, p3, p4, round)   /* normal forward round */ \
+       mov     fk_ref(round,0), p1; \
+       mov     fk_ref(round,1), p2; \
+       mov     fk_ref(round,2), p3; \
+       mov     fk_ref(round,3), p4; \
+ \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       shr     $16, %eax; \
+       xor     tab_0(%rsi), p1; \
+       xor     tab_1(%rdi), p4; \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       xor     tab_2(%rsi), p3; \
+       xor     tab_3(%rdi), p2; \
+ \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       shr     $16, %ebx; \
+       xor     tab_0(%rsi), p2; \
+       xor     tab_1(%rdi), p1; \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       xor     tab_2(%rsi), p4; \
+       xor     tab_3(%rdi), p3; \
+ \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       shr     $16, %ecx; \
+       xor     tab_0(%rsi), p3; \
+       xor     tab_1(%rdi), p2; \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       xor     tab_2(%rsi), p1; \
+       xor     tab_3(%rdi), p4; \
+ \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       shr     $16, %edx; \
+       xor     tab_0(%rsi), p4; \
+       xor     tab_1(%rdi), p3; \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       xor     tab_2(%rsi), p2; \
+       xor     tab_3(%rdi), p1; \
+ \
+       mov     p1, %eax; \
+       mov     p2, %ebx; \
+       mov     p3, %ecx; \
+       mov     p4, %edx
+
+#ifdef LAST_ROUND_TABLES
+
+#define        fl_rnd(p1, p2, p3, p4, round)   /* last forward round */ \
+       add     $2048, tptr; \
+       mov     fk_ref(round,0), p1; \
+       mov     fk_ref(round,1), p2; \
+       mov     fk_ref(round,2), p3; \
+       mov     fk_ref(round,3), p4; \
+ \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       shr     $16, %eax; \
+       xor     tab_0(%rsi), p1; \
+       xor     tab_1(%rdi), p4; \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       xor     tab_2(%rsi), p3; \
+       xor     tab_3(%rdi), p2; \
+ \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       shr     $16, %ebx; \
+       xor     tab_0(%rsi), p2; \
+       xor     tab_1(%rdi), p1; \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       xor     tab_2(%rsi), p4; \
+       xor     tab_3(%rdi), p3; \
+ \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       shr     $16, %ecx; \
+       xor     tab_0(%rsi), p3; \
+       xor     tab_1(%rdi), p2; \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       xor     tab_2(%rsi), p1; \
+       xor     tab_3(%rdi), p4; \
+ \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       shr     $16, %edx; \
+       xor     tab_0(%rsi), p4; \
+       xor     tab_1(%rdi), p3; \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       xor     tab_2(%rsi), p2; \
+       xor     tab_3(%rdi), p1
+
+#else
+
+#define        fl_rnd(p1, p2, p3, p4, round)   /* last forward round */ \
+       mov     fk_ref(round,0), p1; \
+       mov     fk_ref(round,1), p2; \
+       mov     fk_ref(round,2), p3; \
+       mov     fk_ref(round,3), p4; \
+ \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       shr     $16, %eax; \
+       movzx   tab_f(%rsi), %esi; \
+       movzx   tab_f(%rdi), %edi; \
+       xor     %esi, p1; \
+       rol     $8, %edi; \
+       xor     %edi, p4; \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       movzx   tab_f(%rsi), %esi; \
+       movzx   tab_f(%rdi), %edi; \
+       rol     $16, %esi; \
+       rol     $24, %edi; \
+       xor     %esi, p3; \
+       xor     %edi, p2; \
+ \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       shr     $16, %ebx; \
+       movzx   tab_f(%rsi), %esi; \
+       movzx   tab_f(%rdi), %edi; \
+       xor     %esi, p2; \
+       rol     $8, %edi; \
+       xor     %edi, p1; \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       movzx   tab_f(%rsi), %esi; \
+       movzx   tab_f(%rdi), %edi; \
+       rol     $16, %esi; \
+       rol     $24, %edi; \
+       xor     %esi, p4; \
+       xor     %edi, p3; \
+ \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       movzx   tab_f(%rsi), %esi; \
+       movzx   tab_f(%rdi), %edi; \
+       shr     $16, %ecx; \
+       xor     %esi, p3; \
+       rol     $8, %edi; \
+       xor     %edi, p2; \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       movzx   tab_f(%rsi), %esi; \
+       movzx   tab_f(%rdi), %edi; \
+       rol     $16, %esi; \
+       rol     $24, %edi; \
+       xor     %esi, p1; \
+       xor     %edi, p4; \
+ \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       movzx   tab_f(%rsi), %esi; \
+       movzx   tab_f(%rdi), %edi; \
+       shr     $16, %edx; \
+       xor     %esi, p4; \
+       rol     $8, %edi; \
+       xor     %edi, p3; \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       movzx   tab_f(%rsi), %esi; \
+       movzx   tab_f(%rdi), %edi; \
+       rol     $16, %esi; \
+       rol     $24, %edi; \
+       xor     %esi, p2; \
+       xor     %edi, p1
+
+#endif /* LAST_ROUND_TABLES */
+
+#define        ii_rnd(p1, p2, p3, p4, round)   /* normal inverse round */ \
+       mov     ik_ref(round,0), p1; \
+       mov     ik_ref(round,1), p2; \
+       mov     ik_ref(round,2), p3; \
+       mov     ik_ref(round,3), p4; \
+ \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       shr     $16, %eax; \
+       xor     tab_0(%rsi), p1; \
+       xor     tab_1(%rdi), p2; \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       xor     tab_2(%rsi), p3; \
+       xor     tab_3(%rdi), p4; \
+ \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       shr     $16, %ebx; \
+       xor     tab_0(%rsi), p2; \
+       xor     tab_1(%rdi), p3; \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       xor     tab_2(%rsi), p4; \
+       xor     tab_3(%rdi), p1; \
+ \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       shr     $16, %ecx; \
+       xor     tab_0(%rsi), p3; \
+       xor     tab_1(%rdi), p4; \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       xor     tab_2(%rsi), p1; \
+       xor     tab_3(%rdi), p2; \
+ \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       shr     $16, %edx; \
+       xor     tab_0(%rsi), p4; \
+       xor     tab_1(%rdi), p1; \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       xor     tab_2(%rsi), p2; \
+       xor     tab_3(%rdi), p3; \
+ \
+       mov     p1, %eax; \
+       mov     p2, %ebx; \
+       mov     p3, %ecx; \
+       mov     p4, %edx
+
+#ifdef LAST_ROUND_TABLES
+
+#define        il_rnd(p1, p2, p3, p4, round)   /* last inverse round */ \
+       add     $2048, tptr; \
+       mov     ik_ref(round,0), p1; \
+       mov     ik_ref(round,1), p2; \
+       mov     ik_ref(round,2), p3; \
+       mov     ik_ref(round,3), p4; \
+ \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       shr     $16, %eax; \
+       xor     tab_0(%rsi), p1; \
+       xor     tab_1(%rdi), p2; \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       xor     tab_2(%rsi), p3; \
+       xor     tab_3(%rdi), p4; \
+ \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       shr     $16, %ebx; \
+       xor     tab_0(%rsi), p2; \
+       xor     tab_1(%rdi), p3; \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       xor     tab_2(%rsi), p4; \
+       xor     tab_3(%rdi), p1; \
+ \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       shr     $16, %ecx; \
+       xor     tab_0(%rsi), p3; \
+       xor     tab_1(%rdi), p4; \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       xor     tab_2(%rsi), p1; \
+       xor     tab_3(%rdi), p2; \
+ \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       shr     $16, %edx; \
+       xor     tab_0(%rsi), p4; \
+       xor     tab_1(%rdi), p1; \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       xor     tab_2(%rsi), p2; \
+       xor     tab_3(%rdi), p3
+
+#else
+
+#define        il_rnd(p1, p2, p3, p4, round)   /* last inverse round */ \
+       mov     ik_ref(round,0), p1; \
+       mov     ik_ref(round,1), p2; \
+       mov     ik_ref(round,2), p3; \
+       mov     ik_ref(round,3), p4; \
+ \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       movzx   tab_i(%rsi), %esi; \
+       movzx   tab_i(%rdi), %edi; \
+       shr     $16, %eax; \
+       xor     %esi, p1; \
+       rol     $8, %edi; \
+       xor     %edi, p2; \
+       movzx   %al, %esi; \
+       movzx   %ah, %edi; \
+       movzx   tab_i(%rsi), %esi; \
+       movzx   tab_i(%rdi), %edi; \
+       rol     $16, %esi; \
+       rol     $24, %edi; \
+       xor     %esi, p3; \
+       xor     %edi, p4; \
+ \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       movzx   tab_i(%rsi), %esi; \
+       movzx   tab_i(%rdi), %edi; \
+       shr     $16, %ebx; \
+       xor     %esi, p2; \
+       rol     $8, %edi; \
+       xor     %edi, p3; \
+       movzx   %bl, %esi; \
+       movzx   %bh, %edi; \
+       movzx   tab_i(%rsi), %esi; \
+       movzx   tab_i(%rdi), %edi; \
+       rol     $16, %esi; \
+       rol     $24, %edi; \
+       xor     %esi, p4; \
+       xor     %edi, p1; \
+ \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       movzx   tab_i(%rsi), %esi; \
+       movzx   tab_i(%rdi), %edi; \
+       shr     $16, %ecx; \
+       xor     %esi, p3; \
+       rol     $8, %edi; \
+       xor     %edi, p4; \
+       movzx   %cl, %esi; \
+       movzx   %ch, %edi; \
+       movzx   tab_i(%rsi), %esi; \
+       movzx   tab_i(%rdi), %edi; \
+       rol     $16, %esi; \
+       rol     $24, %edi; \
+       xor     %esi, p1; \
+       xor     %edi, p2; \
+ \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       movzx   tab_i(%rsi), %esi; \
+       movzx   tab_i(%rdi), %edi; \
+       shr     $16, %edx; \
+       xor     %esi, p4; \
+       rol     $8, %edi; \
+       xor     %edi, p1; \
+       movzx   %dl, %esi; \
+       movzx   %dh, %edi; \
+       movzx   tab_i(%rsi), %esi; \
+       movzx   tab_i(%rdi), %edi; \
+       rol     $16, %esi; \
+       rol     $24, %edi; \
+       xor     %esi, p2; \
+       xor     %edi, p3
+
+#endif /* LAST_ROUND_TABLES */
+
+/*
+ * OpenSolaris OS:
+ * void aes_encrypt_amd64(const aes_ks_t *ks, int Nr,
+ *     const uint32_t pt[4], uint32_t ct[4])/
+ *
+ * Original interface:
+ * int aes_encrypt(const unsigned char *in,
+ *     unsigned char *out, const aes_encrypt_ctx cx[1])/
+ */
+       .align  64
+enc_tab:
+       enc_vals(u8)
+#ifdef LAST_ROUND_TABLES
+       // Last Round Tables:
+       enc_vals(w8)
+#endif
+
+
+       ENTRY_NP(aes_encrypt_amd64)
+#ifdef GLADMAN_INTERFACE
+       // Original interface
+       sub     $[4*8], %rsp    // gnu/linux/opensolaris binary interface
+       mov     %rsi, (%rsp)    // output pointer (P2)
+       mov     %rdx, %r8       // context (P3)
+
+       mov     %rbx, 1*8(%rsp) // P1: input pointer in rdi
+       mov     %rbp, 2*8(%rsp) // P2: output pointer in (rsp)
+       mov     %r12, 3*8(%rsp) // P3: context in r8
+       movzx   4*KS_LENGTH(kptr), %esi // Get byte key length * 16
+
+#else
+       // OpenSolaris OS interface
+       sub     $[4*8], %rsp    // Make room on stack to save registers
+       mov     %rcx, (%rsp)    // Save output pointer (P4) on stack
+       mov     %rdi, %r8       // context (P1)
+       mov     %rdx, %rdi      // P3: save input pointer
+       shl     $4, %esi        // P2: esi byte key length * 16
+
+       mov     %rbx, 1*8(%rsp) // Save registers
+       mov     %rbp, 2*8(%rsp)
+       mov     %r12, 3*8(%rsp)
+       // P1: context in r8
+       // P2: byte key length * 16 in esi
+       // P3: input pointer in rdi
+       // P4: output pointer in (rsp)
+#endif /* GLADMAN_INTERFACE */
+
+       lea     enc_tab(%rip), tptr
+       sub     $fofs, kptr
+
+       // Load input block into registers
+       mov     (%rdi), %eax
+       mov     1*4(%rdi), %ebx
+       mov     2*4(%rdi), %ecx
+       mov     3*4(%rdi), %edx
+
+       xor     fofs(kptr), %eax
+       xor     fofs+4(kptr), %ebx
+       xor     fofs+8(kptr), %ecx
+       xor     fofs+12(kptr), %edx
+
+       lea     (kptr,%rsi), kptr
+       // Jump based on byte key length * 16:
+       cmp     $[10*16], %esi
+       je      3f
+       cmp     $[12*16], %esi
+       je      2f
+       cmp     $[14*16], %esi
+       je      1f
+       mov     $-1, %rax       // error
+       jmp     4f
+
+       // Perform normal forward rounds
+1:     ff_rnd(%r9d, %r10d, %r11d, %r12d, 13)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d, 12)
+2:     ff_rnd(%r9d, %r10d, %r11d, %r12d, 11)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d, 10)
+3:     ff_rnd(%r9d, %r10d, %r11d, %r12d,  9)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d,  8)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d,  7)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d,  6)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d,  5)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d,  4)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d,  3)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d,  2)
+       ff_rnd(%r9d, %r10d, %r11d, %r12d,  1)
+       fl_rnd(%r9d, %r10d, %r11d, %r12d,  0)
+
+       // Copy results
+       mov     (%rsp), %rbx
+       mov     %r9d, (%rbx)
+       mov     %r10d, 4(%rbx)
+       mov     %r11d, 8(%rbx)
+       mov     %r12d, 12(%rbx)
+       xor     %rax, %rax
+4:     // Restore registers
+       mov     1*8(%rsp), %rbx
+       mov     2*8(%rsp), %rbp
+       mov     3*8(%rsp), %r12
+       add     $[4*8], %rsp
+       ret
+
+       SET_SIZE(aes_encrypt_amd64)
+
+/*
+ * OpenSolaris OS:
+ * void aes_decrypt_amd64(const aes_ks_t *ks, int Nr,
+ *     const uint32_t pt[4], uint32_t ct[4])/
+ *
+ * Original interface:
+ * int aes_decrypt(const unsigned char *in,
+ *     unsigned char *out, const aes_encrypt_ctx cx[1])/
+ */
+       .align  64
+dec_tab:
+       dec_vals(v8)
+#ifdef LAST_ROUND_TABLES
+       // Last Round Tables:
+       dec_vals(w8)
+#endif
+
+
+       ENTRY_NP(aes_decrypt_amd64)
+#ifdef GLADMAN_INTERFACE
+       // Original interface
+       sub     $[4*8], %rsp    // gnu/linux/opensolaris binary interface
+       mov     %rsi, (%rsp)    // output pointer (P2)
+       mov     %rdx, %r8       // context (P3)
+
+       mov     %rbx, 1*8(%rsp) // P1: input pointer in rdi
+       mov     %rbp, 2*8(%rsp) // P2: output pointer in (rsp)
+       mov     %r12, 3*8(%rsp) // P3: context in r8
+       movzx   4*KS_LENGTH(kptr), %esi // Get byte key length * 16
+
+#else
+       // OpenSolaris OS interface
+       sub     $[4*8], %rsp    // Make room on stack to save registers
+       mov     %rcx, (%rsp)    // Save output pointer (P4) on stack
+       mov     %rdi, %r8       // context (P1)
+       mov     %rdx, %rdi      // P3: save input pointer
+       shl     $4, %esi        // P2: esi byte key length * 16
+
+       mov     %rbx, 1*8(%rsp) // Save registers
+       mov     %rbp, 2*8(%rsp)
+       mov     %r12, 3*8(%rsp)
+       // P1: context in r8
+       // P2: byte key length * 16 in esi
+       // P3: input pointer in rdi
+       // P4: output pointer in (rsp)
+#endif /* GLADMAN_INTERFACE */
+
+       lea     dec_tab(%rip), tptr
+       sub     $rofs, kptr
+
+       // Load input block into registers
+       mov     (%rdi), %eax
+       mov     1*4(%rdi), %ebx
+       mov     2*4(%rdi), %ecx
+       mov     3*4(%rdi), %edx
+
+#ifdef AES_REV_DKS
+       mov     kptr, %rdi
+       lea     (kptr,%rsi), kptr
+#else
+       lea     (kptr,%rsi), %rdi
+#endif
+
+       xor     rofs(%rdi), %eax
+       xor     rofs+4(%rdi), %ebx
+       xor     rofs+8(%rdi), %ecx
+       xor     rofs+12(%rdi), %edx
+
+       // Jump based on byte key length * 16:
+       cmp     $[10*16], %esi
+       je      3f
+       cmp     $[12*16], %esi
+       je      2f
+       cmp     $[14*16], %esi
+       je      1f
+       mov     $-1, %rax       // error
+       jmp     4f
+
+       // Perform normal inverse rounds
+1:     ii_rnd(%r9d, %r10d, %r11d, %r12d, 13)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d, 12)
+2:     ii_rnd(%r9d, %r10d, %r11d, %r12d, 11)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d, 10)
+3:     ii_rnd(%r9d, %r10d, %r11d, %r12d,  9)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d,  8)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d,  7)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d,  6)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d,  5)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d,  4)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d,  3)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d,  2)
+       ii_rnd(%r9d, %r10d, %r11d, %r12d,  1)
+       il_rnd(%r9d, %r10d, %r11d, %r12d,  0)
+
+       // Copy results
+       mov     (%rsp), %rbx
+       mov     %r9d, (%rbx)
+       mov     %r10d, 4(%rbx)
+       mov     %r11d, 8(%rbx)
+       mov     %r12d, 12(%rbx)
+       xor     %rax, %rax
+4:     // Restore registers
+       mov     1*8(%rsp), %rbx
+       mov     2*8(%rsp), %rbp
+       mov     3*8(%rsp), %r12
+       add     $[4*8], %rsp
+       ret
+
+       SET_SIZE(aes_decrypt_amd64)
+#endif /* lint || __lint */
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/zfs/module/icp/asm-x86_64/aes/aes_intel.S b/zfs/module/icp/asm-x86_64/aes/aes_intel.S
new file mode 100644 (file)
index 0000000..6c5c0f9
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ * ====================================================================
+ * Written by Intel Corporation for the OpenSSL project to add support
+ * for Intel AES-NI instructions. Rights for redistribution and usage
+ * in source and binary forms are granted according to the OpenSSL
+ * license.
+ *
+ *   Author: Huang Ying <ying.huang at intel dot com>
+ *           Vinodh Gopal <vinodh.gopal at intel dot com>
+ *           Kahraman Akdemir
+ *
+ * Intel AES-NI is a new set of Single Instruction Multiple Data (SIMD)
+ * instructions that are going to be introduced in the next generation
+ * of Intel processor, as of 2009. These instructions enable fast and
+ * secure data encryption and decryption, using the Advanced Encryption
+ * Standard (AES), defined by FIPS Publication number 197. The
+ * architecture introduces six instructions that offer full hardware
+ * support for AES. Four of them support high performance data
+ * encryption and decryption, and the other two instructions support
+ * the AES key expansion procedure.
+ * ====================================================================
+ */
+
+/*
+ * ====================================================================
+ * Copyright (c) 1998-2008 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/*
+ * ====================================================================
+ * OpenSolaris OS modifications
+ *
+ * This source originates as files aes-intel.S and eng_aesni_asm.pl, in
+ * patches sent sent Dec. 9, 2008 and Dec. 24, 2008, respectively, by
+ * Huang Ying of Intel to the openssl-dev mailing list under the subject
+ * of "Add support to Intel AES-NI instruction set for x86_64 platform".
+ *
+ * This OpenSolaris version has these major changes from the original source:
+ *
+ * 1. Added OpenSolaris ENTRY_NP/SET_SIZE macros from
+ * /usr/include/sys/asm_linkage.h, lint(1B) guards, and dummy C function
+ * definitions for lint.
+ *
+ * 2. Formatted code, added comments, and added #includes and #defines.
+ *
+ * 3. If bit CR0.TS is set, clear and set the TS bit, after and before
+ * calling kpreempt_disable() and kpreempt_enable().
+ * If the TS bit is not set, Save and restore %xmm registers at the beginning
+ * and end of function calls (%xmm* registers are not saved and restored by
+ * during kernel thread preemption).
+ *
+ * 4. Renamed functions, reordered parameters, and changed return value
+ * to match OpenSolaris:
+ *
+ * OpenSSL interface:
+ *     int intel_AES_set_encrypt_key(const unsigned char *userKey,
+ *             const int bits, AES_KEY *key);
+ *     int intel_AES_set_decrypt_key(const unsigned char *userKey,
+ *             const int bits, AES_KEY *key);
+ *     Return values for above are non-zero on error, 0 on success.
+ *
+ *     void intel_AES_encrypt(const unsigned char *in, unsigned char *out,
+ *             const AES_KEY *key);
+ *     void intel_AES_decrypt(const unsigned char *in, unsigned char *out,
+ *             const AES_KEY *key);
+ *     typedef struct aes_key_st {
+ *             unsigned int    rd_key[4 *(AES_MAXNR + 1)];
+ *             int             rounds;
+ *             unsigned int    pad[3];
+ *     } AES_KEY;
+ * Note: AES_LONG is undefined (that is, Intel uses 32-bit key schedules
+ * (ks32) instead of 64-bit (ks64).
+ * Number of rounds (aka round count) is at offset 240 of AES_KEY.
+ *
+ * OpenSolaris OS interface (#ifdefs removed for readability):
+ *     int rijndael_key_setup_dec_intel(uint32_t rk[],
+ *             const uint32_t cipherKey[], uint64_t keyBits);
+ *     int rijndael_key_setup_enc_intel(uint32_t rk[],
+ *             const uint32_t cipherKey[], uint64_t keyBits);
+ *     Return values for above are 0 on error, number of rounds on success.
+ *
+ *     void aes_encrypt_intel(const aes_ks_t *ks, int Nr,
+ *             const uint32_t pt[4], uint32_t ct[4]);
+ *     void aes_decrypt_intel(const aes_ks_t *ks, int Nr,
+ *             const uint32_t pt[4], uint32_t ct[4]);
+ *     typedef union {uint64_t ks64[(MAX_AES_NR + 1) * 4];
+ *              uint32_t ks32[(MAX_AES_NR + 1) * 4]; } aes_ks_t;
+ *
+ *     typedef union {
+ *             uint32_t        ks32[((MAX_AES_NR) + 1) * (MAX_AES_NB)];
+ *     } aes_ks_t;
+ *     typedef struct aes_key {
+ *             aes_ks_t        encr_ks, decr_ks;
+ *             long double     align128;
+ *             int             flags, nr, type;
+ *     } aes_key_t;
+ *
+ * Note: ks is the AES key schedule, Nr is number of rounds, pt is plain text,
+ * ct is crypto text, and MAX_AES_NR is 14.
+ * For the x86 64-bit architecture, OpenSolaris OS uses ks32 instead of ks64.
+ *
+ * Note2: aes_ks_t must be aligned on a 0 mod 128 byte boundary.
+ *
+ * ====================================================================
+ */
+
+#if defined(lint) || defined(__lint)
+
+#include <sys/types.h>
+
+/* ARGSUSED */
+void
+aes_encrypt_intel(const uint32_t rk[], int Nr, const uint32_t pt[4],
+    uint32_t ct[4]) {
+}
+/* ARGSUSED */
+void
+aes_decrypt_intel(const uint32_t rk[], int Nr, const uint32_t ct[4],
+    uint32_t pt[4]) {
+}
+/* ARGSUSED */
+int
+rijndael_key_setup_enc_intel(uint32_t rk[], const uint32_t cipherKey[],
+    uint64_t keyBits) {
+       return (0);
+}
+/* ARGSUSED */
+int
+rijndael_key_setup_dec_intel(uint32_t rk[], const uint32_t cipherKey[],
+   uint64_t keyBits) {
+       return (0);
+}
+
+
+#else  /* lint */
+
+#define _ASM
+#include <sys/asm_linkage.h>
+
+#ifdef _KERNEL
+       /*
+        * Note: the CLTS macro clobbers P2 (%rsi) under i86xpv.  That is,
+        * it calls HYPERVISOR_fpu_taskswitch() which modifies %rsi when it
+        * uses it to pass P2 to syscall.
+        * This also occurs with the STTS macro, but we dont care if
+        * P2 (%rsi) is modified just before function exit.
+        * The CLTS and STTS macros push and pop P1 (%rdi) already.
+        */
+#ifdef __xpv
+#define        PROTECTED_CLTS \
+       push    %rsi; \
+       CLTS; \
+       pop     %rsi
+#else
+#define        PROTECTED_CLTS \
+       CLTS
+#endif /* __xpv */
+
+#define        CLEAR_TS_OR_PUSH_XMM0_XMM1(tmpreg) \
+       push    %rbp; \
+       mov     %rsp, %rbp; \
+       movq    %cr0, tmpreg; \
+       testq   $CR0_TS, tmpreg; \
+       jnz     1f; \
+       and     $-XMM_ALIGN, %rsp; \
+       sub     $[XMM_SIZE * 2], %rsp; \
+       movaps  %xmm0, 16(%rsp); \
+       movaps  %xmm1, (%rsp); \
+       jmp     2f; \
+1: \
+       PROTECTED_CLTS; \
+2:
+
+       /*
+        * If CR0_TS was not set above, pop %xmm0 and %xmm1 off stack,
+        * otherwise set CR0_TS.
+        */
+#define        SET_TS_OR_POP_XMM0_XMM1(tmpreg) \
+       testq   $CR0_TS, tmpreg; \
+       jnz     1f; \
+       movaps  (%rsp), %xmm1; \
+       movaps  16(%rsp), %xmm0; \
+       jmp     2f; \
+1: \
+       STTS(tmpreg); \
+2: \
+       mov     %rbp, %rsp; \
+       pop     %rbp
+
+       /*
+        * If CR0_TS is not set, align stack (with push %rbp) and push
+        * %xmm0 - %xmm6 on stack, otherwise clear CR0_TS
+        */
+#define        CLEAR_TS_OR_PUSH_XMM0_TO_XMM6(tmpreg) \
+       push    %rbp; \
+       mov     %rsp, %rbp; \
+       movq    %cr0, tmpreg; \
+       testq   $CR0_TS, tmpreg; \
+       jnz     1f; \
+       and     $-XMM_ALIGN, %rsp; \
+       sub     $[XMM_SIZE * 7], %rsp; \
+       movaps  %xmm0, 96(%rsp); \
+       movaps  %xmm1, 80(%rsp); \
+       movaps  %xmm2, 64(%rsp); \
+       movaps  %xmm3, 48(%rsp); \
+       movaps  %xmm4, 32(%rsp); \
+       movaps  %xmm5, 16(%rsp); \
+       movaps  %xmm6, (%rsp); \
+       jmp     2f; \
+1: \
+       PROTECTED_CLTS; \
+2:
+
+
+       /*
+        * If CR0_TS was not set above, pop %xmm0 - %xmm6 off stack,
+        * otherwise set CR0_TS.
+        */
+#define        SET_TS_OR_POP_XMM0_TO_XMM6(tmpreg) \
+       testq   $CR0_TS, tmpreg; \
+       jnz     1f; \
+       movaps  (%rsp), %xmm6; \
+       movaps  16(%rsp), %xmm5; \
+       movaps  32(%rsp), %xmm4; \
+       movaps  48(%rsp), %xmm3; \
+       movaps  64(%rsp), %xmm2; \
+       movaps  80(%rsp), %xmm1; \
+       movaps  96(%rsp), %xmm0; \
+       jmp     2f; \
+1: \
+       STTS(tmpreg); \
+2: \
+       mov     %rbp, %rsp; \
+       pop     %rbp
+
+
+#else
+#define        PROTECTED_CLTS
+#define        CLEAR_TS_OR_PUSH_XMM0_XMM1(tmpreg)
+#define        SET_TS_OR_POP_XMM0_XMM1(tmpreg)
+#define        CLEAR_TS_OR_PUSH_XMM0_TO_XMM6(tmpreg)
+#define        SET_TS_OR_POP_XMM0_TO_XMM6(tmpreg)
+#endif /* _KERNEL */
+
+
+/*
+ * _key_expansion_128(), * _key_expansion_192a(), _key_expansion_192b(),
+ * _key_expansion_256a(), _key_expansion_256b()
+ *
+ * Helper functions called by rijndael_key_setup_inc_intel().
+ * Also used indirectly by rijndael_key_setup_dec_intel().
+ *
+ * Input:
+ * %xmm0       User-provided cipher key
+ * %xmm1       Round constant
+ * Output:
+ * (%rcx)      AES key
+ */
+
+.align 16
+_key_expansion_128:
+_key_expansion_256a:
+       pshufd  $0b11111111, %xmm1, %xmm1
+       shufps  $0b00010000, %xmm0, %xmm4
+       pxor    %xmm4, %xmm0
+       shufps  $0b10001100, %xmm0, %xmm4
+       pxor    %xmm4, %xmm0
+       pxor    %xmm1, %xmm0
+       movaps  %xmm0, (%rcx)
+       add     $0x10, %rcx
+       ret
+       SET_SIZE(_key_expansion_128)
+       SET_SIZE(_key_expansion_256a)
+
+.align 16
+_key_expansion_192a:
+       pshufd  $0b01010101, %xmm1, %xmm1
+       shufps  $0b00010000, %xmm0, %xmm4
+       pxor    %xmm4, %xmm0
+       shufps  $0b10001100, %xmm0, %xmm4
+       pxor    %xmm4, %xmm0
+       pxor    %xmm1, %xmm0
+
+       movaps  %xmm2, %xmm5
+       movaps  %xmm2, %xmm6
+       pslldq  $4, %xmm5
+       pshufd  $0b11111111, %xmm0, %xmm3
+       pxor    %xmm3, %xmm2
+       pxor    %xmm5, %xmm2
+
+       movaps  %xmm0, %xmm1
+       shufps  $0b01000100, %xmm0, %xmm6
+       movaps  %xmm6, (%rcx)
+       shufps  $0b01001110, %xmm2, %xmm1
+       movaps  %xmm1, 0x10(%rcx)
+       add     $0x20, %rcx
+       ret
+       SET_SIZE(_key_expansion_192a)
+
+.align 16
+_key_expansion_192b:
+       pshufd  $0b01010101, %xmm1, %xmm1
+       shufps  $0b00010000, %xmm0, %xmm4
+       pxor    %xmm4, %xmm0
+       shufps  $0b10001100, %xmm0, %xmm4
+       pxor    %xmm4, %xmm0
+       pxor    %xmm1, %xmm0
+
+       movaps  %xmm2, %xmm5
+       pslldq  $4, %xmm5
+       pshufd  $0b11111111, %xmm0, %xmm3
+       pxor    %xmm3, %xmm2
+       pxor    %xmm5, %xmm2
+
+       movaps  %xmm0, (%rcx)
+       add     $0x10, %rcx
+       ret
+       SET_SIZE(_key_expansion_192b)
+
+.align 16
+_key_expansion_256b:
+       pshufd  $0b10101010, %xmm1, %xmm1
+       shufps  $0b00010000, %xmm2, %xmm4
+       pxor    %xmm4, %xmm2
+       shufps  $0b10001100, %xmm2, %xmm4
+       pxor    %xmm4, %xmm2
+       pxor    %xmm1, %xmm2
+       movaps  %xmm2, (%rcx)
+       add     $0x10, %rcx
+       ret
+       SET_SIZE(_key_expansion_256b)
+
+
+/*
+ * rijndael_key_setup_enc_intel()
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * For kernel code, caller is responsible for ensuring kpreempt_disable()
+ * has been called.  This is because %xmm registers are not saved/restored.
+ * Clear and set the CR0.TS bit on entry and exit, respectively,  if TS is set
+ * on entry.  Otherwise, if TS is not set, save and restore %xmm registers
+ * on the stack.
+ *
+ * OpenSolaris interface:
+ * int rijndael_key_setup_enc_intel(uint32_t rk[], const uint32_t cipherKey[],
+ *     uint64_t keyBits);
+ * Return value is 0 on error, number of rounds on success.
+ *
+ * Original Intel OpenSSL interface:
+ * int intel_AES_set_encrypt_key(const unsigned char *userKey,
+ *     const int bits, AES_KEY *key);
+ * Return value is non-zero on error, 0 on success.
+ */
+
+#ifdef OPENSSL_INTERFACE
+#define        rijndael_key_setup_enc_intel    intel_AES_set_encrypt_key
+#define        rijndael_key_setup_dec_intel    intel_AES_set_decrypt_key
+
+#define        USERCIPHERKEY           rdi     /* P1, 64 bits */
+#define        KEYSIZE32               esi     /* P2, 32 bits */
+#define        KEYSIZE64               rsi     /* P2, 64 bits */
+#define        AESKEY                  rdx     /* P3, 64 bits */
+
+#else  /* OpenSolaris Interface */
+#define        AESKEY                  rdi     /* P1, 64 bits */
+#define        USERCIPHERKEY           rsi     /* P2, 64 bits */
+#define        KEYSIZE32               edx     /* P3, 32 bits */
+#define        KEYSIZE64               rdx     /* P3, 64 bits */
+#endif /* OPENSSL_INTERFACE */
+
+#define        ROUNDS32                KEYSIZE32       /* temp */
+#define        ROUNDS64                KEYSIZE64       /* temp */
+#define        ENDAESKEY               USERCIPHERKEY   /* temp */
+
+ENTRY_NP(rijndael_key_setup_enc_intel)
+rijndael_key_setup_enc_intel_local:
+       CLEAR_TS_OR_PUSH_XMM0_TO_XMM6(%r10)
+
+       // NULL pointer sanity check
+       test    %USERCIPHERKEY, %USERCIPHERKEY
+       jz      .Lenc_key_invalid_param
+       test    %AESKEY, %AESKEY
+       jz      .Lenc_key_invalid_param
+
+       movups  (%USERCIPHERKEY), %xmm0 // user key (first 16 bytes)
+       movaps  %xmm0, (%AESKEY)
+       lea     0x10(%AESKEY), %rcx     // key addr
+       pxor    %xmm4, %xmm4            // xmm4 is assumed 0 in _key_expansion_x
+
+       cmp     $256, %KEYSIZE32
+       jnz     .Lenc_key192
+
+       // AES 256: 14 rounds in encryption key schedule
+#ifdef OPENSSL_INTERFACE
+       mov     $14, %ROUNDS32
+       movl    %ROUNDS32, 240(%AESKEY)         // key.rounds = 14
+#endif /* OPENSSL_INTERFACE */
+
+       movups  0x10(%USERCIPHERKEY), %xmm2     // other user key (2nd 16 bytes)
+       movaps  %xmm2, (%rcx)
+       add     $0x10, %rcx
+
+       aeskeygenassist $0x1, %xmm2, %xmm1      // expand the key
+       call    _key_expansion_256a
+       aeskeygenassist $0x1, %xmm0, %xmm1
+       call    _key_expansion_256b
+       aeskeygenassist $0x2, %xmm2, %xmm1      // expand the key
+       call    _key_expansion_256a
+       aeskeygenassist $0x2, %xmm0, %xmm1
+       call    _key_expansion_256b
+       aeskeygenassist $0x4, %xmm2, %xmm1      // expand the key
+       call    _key_expansion_256a
+       aeskeygenassist $0x4, %xmm0, %xmm1
+       call    _key_expansion_256b
+       aeskeygenassist $0x8, %xmm2, %xmm1      // expand the key
+       call    _key_expansion_256a
+       aeskeygenassist $0x8, %xmm0, %xmm1
+       call    _key_expansion_256b
+       aeskeygenassist $0x10, %xmm2, %xmm1     // expand the key
+       call    _key_expansion_256a
+       aeskeygenassist $0x10, %xmm0, %xmm1
+       call    _key_expansion_256b
+       aeskeygenassist $0x20, %xmm2, %xmm1     // expand the key
+       call    _key_expansion_256a
+       aeskeygenassist $0x20, %xmm0, %xmm1
+       call    _key_expansion_256b
+       aeskeygenassist $0x40, %xmm2, %xmm1     // expand the key
+       call    _key_expansion_256a
+
+       SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
+#ifdef OPENSSL_INTERFACE
+       xor     %rax, %rax                      // return 0 (OK)
+#else  /* Open Solaris Interface */
+       mov     $14, %rax                       // return # rounds = 14
+#endif
+       ret
+
+.align 4
+.Lenc_key192:
+       cmp     $192, %KEYSIZE32
+       jnz     .Lenc_key128
+
+       // AES 192: 12 rounds in encryption key schedule
+#ifdef OPENSSL_INTERFACE
+       mov     $12, %ROUNDS32
+       movl    %ROUNDS32, 240(%AESKEY) // key.rounds = 12
+#endif /* OPENSSL_INTERFACE */
+
+       movq    0x10(%USERCIPHERKEY), %xmm2     // other user key
+       aeskeygenassist $0x1, %xmm2, %xmm1      // expand the key
+       call    _key_expansion_192a
+       aeskeygenassist $0x2, %xmm2, %xmm1      // expand the key
+       call    _key_expansion_192b
+       aeskeygenassist $0x4, %xmm2, %xmm1      // expand the key
+       call    _key_expansion_192a
+       aeskeygenassist $0x8, %xmm2, %xmm1      // expand the key
+       call    _key_expansion_192b
+       aeskeygenassist $0x10, %xmm2, %xmm1     // expand the key
+       call    _key_expansion_192a
+       aeskeygenassist $0x20, %xmm2, %xmm1     // expand the key
+       call    _key_expansion_192b
+       aeskeygenassist $0x40, %xmm2, %xmm1     // expand the key
+       call    _key_expansion_192a
+       aeskeygenassist $0x80, %xmm2, %xmm1     // expand the key
+       call    _key_expansion_192b
+
+       SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
+#ifdef OPENSSL_INTERFACE
+       xor     %rax, %rax                      // return 0 (OK)
+#else  /* OpenSolaris Interface */
+       mov     $12, %rax                       // return # rounds = 12
+#endif
+       ret
+
+.align 4
+.Lenc_key128:
+       cmp $128, %KEYSIZE32
+       jnz .Lenc_key_invalid_key_bits
+
+       // AES 128: 10 rounds in encryption key schedule
+#ifdef OPENSSL_INTERFACE
+       mov     $10, %ROUNDS32
+       movl    %ROUNDS32, 240(%AESKEY)         // key.rounds = 10
+#endif /* OPENSSL_INTERFACE */
+
+       aeskeygenassist $0x1, %xmm0, %xmm1      // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x2, %xmm0, %xmm1      // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x4, %xmm0, %xmm1      // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x8, %xmm0, %xmm1      // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x10, %xmm0, %xmm1     // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x20, %xmm0, %xmm1     // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x40, %xmm0, %xmm1     // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x80, %xmm0, %xmm1     // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x1b, %xmm0, %xmm1     // expand the key
+       call    _key_expansion_128
+       aeskeygenassist $0x36, %xmm0, %xmm1     // expand the key
+       call    _key_expansion_128
+
+       SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
+#ifdef OPENSSL_INTERFACE
+       xor     %rax, %rax                      // return 0 (OK)
+#else  /* OpenSolaris Interface */
+       mov     $10, %rax                       // return # rounds = 10
+#endif
+       ret
+
+.Lenc_key_invalid_param:
+#ifdef OPENSSL_INTERFACE
+       SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
+       mov     $-1, %rax       // user key or AES key pointer is NULL
+       ret
+#else
+       /* FALLTHROUGH */
+#endif /* OPENSSL_INTERFACE */
+
+.Lenc_key_invalid_key_bits:
+       SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
+#ifdef OPENSSL_INTERFACE
+       mov     $-2, %rax       // keysize is invalid
+#else  /* Open Solaris Interface */
+       xor     %rax, %rax      // a key pointer is NULL or invalid keysize
+#endif /* OPENSSL_INTERFACE */
+
+       ret
+       SET_SIZE(rijndael_key_setup_enc_intel)
+
+
+/*
+ * rijndael_key_setup_dec_intel()
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * For kernel code, caller is responsible for ensuring kpreempt_disable()
+ * has been called.  This is because %xmm registers are not saved/restored.
+ * Clear and set the CR0.TS bit on entry and exit, respectively,  if TS is set
+ * on entry.  Otherwise, if TS is not set, save and restore %xmm registers
+ * on the stack.
+ *
+ * OpenSolaris interface:
+ * int rijndael_key_setup_dec_intel(uint32_t rk[], const uint32_t cipherKey[],
+ *     uint64_t keyBits);
+ * Return value is 0 on error, number of rounds on success.
+ * P1->P2, P2->P3, P3->P1
+ *
+ * Original Intel OpenSSL interface:
+ * int intel_AES_set_decrypt_key(const unsigned char *userKey,
+ *     const int bits, AES_KEY *key);
+ * Return value is non-zero on error, 0 on success.
+ */
+ENTRY_NP(rijndael_key_setup_dec_intel)
+       // Generate round keys used for encryption
+       call    rijndael_key_setup_enc_intel_local
+       test    %rax, %rax
+#ifdef OPENSSL_INTERFACE
+       jnz     .Ldec_key_exit  // Failed if returned non-0
+#else  /* OpenSolaris Interface */
+       jz      .Ldec_key_exit  // Failed if returned 0
+#endif /* OPENSSL_INTERFACE */
+
+       CLEAR_TS_OR_PUSH_XMM0_XMM1(%r10)
+
+       /*
+        * Convert round keys used for encryption
+        * to a form usable for decryption
+        */
+#ifndef        OPENSSL_INTERFACE               /* OpenSolaris Interface */
+       mov     %rax, %ROUNDS64         // set # rounds (10, 12, or 14)
+                                       // (already set for OpenSSL)
+#endif
+
+       lea     0x10(%AESKEY), %rcx     // key addr
+       shl     $4, %ROUNDS32
+       add     %AESKEY, %ROUNDS64
+       mov     %ROUNDS64, %ENDAESKEY
+
+.align 4
+.Ldec_key_reorder_loop:
+       movaps  (%AESKEY), %xmm0
+       movaps  (%ROUNDS64), %xmm1
+       movaps  %xmm0, (%ROUNDS64)
+       movaps  %xmm1, (%AESKEY)
+       lea     0x10(%AESKEY), %AESKEY
+       lea     -0x10(%ROUNDS64), %ROUNDS64
+       cmp     %AESKEY, %ROUNDS64
+       ja      .Ldec_key_reorder_loop
+
+.align 4
+.Ldec_key_inv_loop:
+       movaps  (%rcx), %xmm0
+       // Convert an encryption round key to a form usable for decryption
+       // with the "AES Inverse Mix Columns" instruction
+       aesimc  %xmm0, %xmm1
+       movaps  %xmm1, (%rcx)
+       lea     0x10(%rcx), %rcx
+       cmp     %ENDAESKEY, %rcx
+       jnz     .Ldec_key_inv_loop
+
+       SET_TS_OR_POP_XMM0_XMM1(%r10)
+
+.Ldec_key_exit:
+       // OpenSolaris: rax = # rounds (10, 12, or 14) or 0 for error
+       // OpenSSL: rax = 0 for OK, or non-zero for error
+       ret
+       SET_SIZE(rijndael_key_setup_dec_intel)
+
+
+/*
+ * aes_encrypt_intel()
+ * Encrypt a single block (in and out can overlap).
+ *
+ * For kernel code, caller is responsible for ensuring kpreempt_disable()
+ * has been called.  This is because %xmm registers are not saved/restored.
+ * Clear and set the CR0.TS bit on entry and exit, respectively,  if TS is set
+ * on entry.  Otherwise, if TS is not set, save and restore %xmm registers
+ * on the stack.
+ *
+ * Temporary register usage:
+ * %xmm0       State
+ * %xmm1       Key
+ *
+ * Original OpenSolaris Interface:
+ * void aes_encrypt_intel(const aes_ks_t *ks, int Nr,
+ *     const uint32_t pt[4], uint32_t ct[4])
+ *
+ * Original Intel OpenSSL Interface:
+ * void intel_AES_encrypt(const unsigned char *in, unsigned char *out,
+ *     const AES_KEY *key)
+ */
+
+#ifdef OPENSSL_INTERFACE
+#define        aes_encrypt_intel       intel_AES_encrypt
+#define        aes_decrypt_intel       intel_AES_decrypt
+
+#define        INP             rdi     /* P1, 64 bits */
+#define        OUTP            rsi     /* P2, 64 bits */
+#define        KEYP            rdx     /* P3, 64 bits */
+
+/* No NROUNDS parameter--offset 240 from KEYP saved in %ecx:  */
+#define        NROUNDS32       ecx     /* temporary, 32 bits */
+#define        NROUNDS         cl      /* temporary,  8 bits */
+
+#else  /* OpenSolaris Interface */
+#define        KEYP            rdi     /* P1, 64 bits */
+#define        NROUNDS         esi     /* P2, 32 bits */
+#define        INP             rdx     /* P3, 64 bits */
+#define        OUTP            rcx     /* P4, 64 bits */
+#endif /* OPENSSL_INTERFACE */
+
+#define        STATE           xmm0    /* temporary, 128 bits */
+#define        KEY             xmm1    /* temporary, 128 bits */
+
+ENTRY_NP(aes_encrypt_intel)
+       CLEAR_TS_OR_PUSH_XMM0_XMM1(%r10)
+
+       movups  (%INP), %STATE                  // input
+       movaps  (%KEYP), %KEY                   // key
+#ifdef OPENSSL_INTERFACE
+       mov     240(%KEYP), %NROUNDS32          // round count
+#else  /* OpenSolaris Interface */
+       /* Round count is already present as P2 in %rsi/%esi */
+#endif /* OPENSSL_INTERFACE */
+
+       pxor    %KEY, %STATE                    // round 0
+       lea     0x30(%KEYP), %KEYP
+       cmp     $12, %NROUNDS
+       jb      .Lenc128
+       lea     0x20(%KEYP), %KEYP
+       je      .Lenc192
+
+       // AES 256
+       lea     0x20(%KEYP), %KEYP
+       movaps  -0x60(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  -0x50(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+
+.align 4
+.Lenc192:
+       // AES 192 and 256
+       movaps  -0x40(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  -0x30(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+
+.align 4
+.Lenc128:
+       // AES 128, 192, and 256
+       movaps  -0x20(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  -0x10(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  (%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  0x10(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  0x20(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  0x30(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  0x40(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  0x50(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  0x60(%KEYP), %KEY
+       aesenc  %KEY, %STATE
+       movaps  0x70(%KEYP), %KEY
+       aesenclast       %KEY, %STATE           // last round
+       movups  %STATE, (%OUTP)                 // output
+
+       SET_TS_OR_POP_XMM0_XMM1(%r10)
+       ret
+       SET_SIZE(aes_encrypt_intel)
+
+
+/*
+ * aes_decrypt_intel()
+ * Decrypt a single block (in and out can overlap).
+ *
+ * For kernel code, caller is responsible for ensuring kpreempt_disable()
+ * has been called.  This is because %xmm registers are not saved/restored.
+ * Clear and set the CR0.TS bit on entry and exit, respectively,  if TS is set
+ * on entry.  Otherwise, if TS is not set, save and restore %xmm registers
+ * on the stack.
+ *
+ * Temporary register usage:
+ * %xmm0       State
+ * %xmm1       Key
+ *
+ * Original OpenSolaris Interface:
+ * void aes_decrypt_intel(const aes_ks_t *ks, int Nr,
+ *     const uint32_t pt[4], uint32_t ct[4])/
+ *
+ * Original Intel OpenSSL Interface:
+ * void intel_AES_decrypt(const unsigned char *in, unsigned char *out,
+ *     const AES_KEY *key);
+ */
+ENTRY_NP(aes_decrypt_intel)
+       CLEAR_TS_OR_PUSH_XMM0_XMM1(%r10)
+
+       movups  (%INP), %STATE                  // input
+       movaps  (%KEYP), %KEY                   // key
+#ifdef OPENSSL_INTERFACE
+       mov     240(%KEYP), %NROUNDS32          // round count
+#else  /* OpenSolaris Interface */
+       /* Round count is already present as P2 in %rsi/%esi */
+#endif /* OPENSSL_INTERFACE */
+
+       pxor    %KEY, %STATE                    // round 0
+       lea     0x30(%KEYP), %KEYP
+       cmp     $12, %NROUNDS
+       jb      .Ldec128
+       lea     0x20(%KEYP), %KEYP
+       je      .Ldec192
+
+       // AES 256
+       lea     0x20(%KEYP), %KEYP
+       movaps  -0x60(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  -0x50(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+
+.align 4
+.Ldec192:
+       // AES 192 and 256
+       movaps  -0x40(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  -0x30(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+
+.align 4
+.Ldec128:
+       // AES 128, 192, and 256
+       movaps  -0x20(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  -0x10(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  (%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  0x10(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  0x20(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  0x30(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  0x40(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  0x50(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  0x60(%KEYP), %KEY
+       aesdec  %KEY, %STATE
+       movaps  0x70(%KEYP), %KEY
+       aesdeclast      %KEY, %STATE            // last round
+       movups  %STATE, (%OUTP)                 // output
+
+       SET_TS_OR_POP_XMM0_XMM1(%r10)
+       ret
+       SET_SIZE(aes_decrypt_intel)
+
+#endif /* lint || __lint */
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/zfs/module/icp/asm-x86_64/aes/aeskey.c b/zfs/module/icp/asm-x86_64/aes/aeskey.c
new file mode 100644 (file)
index 0000000..96767fb
--- /dev/null
@@ -0,0 +1,580 @@
+/*
+ * ---------------------------------------------------------------------------
+ * Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software is allowed (with or without
+ * changes) provided that:
+ *
+ *  1. source code distributions include the above copyright notice, this
+ *      list of conditions and the following disclaimer;
+ *
+ *  2. binary distributions include the above copyright notice, this list
+ *      of conditions and the following disclaimer in their documentation;
+ *
+ *  3. the name of the copyright holder is not used to endorse products
+ *      built using this software without specific written permission.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ * Issue Date: 20/12/2007
+ */
+
+#include <aes/aes_impl.h>
+#include "aesopt.h"
+#include "aestab.h"
+#include "aestab2.h"
+
+/*
+ *     Initialise the key schedule from the user supplied key. The key
+ *     length can be specified in bytes, with legal values of 16, 24
+ *     and 32, or in bits, with legal values of 128, 192 and 256. These
+ *     values correspond with Nk values of 4, 6 and 8 respectively.
+ *
+ *     The following macros implement a single cycle in the key
+ *     schedule generation process. The number of cycles needed
+ *     for each cx->n_col and nk value is:
+ *
+ *     nk =            4  5  6  7  8
+ *     ------------------------------
+ *     cx->n_col = 4   10  9  8  7  7
+ *     cx->n_col = 5   14 11 10  9  9
+ *     cx->n_col = 6   19 15 12 11 11
+ *     cx->n_col = 7   21 19 16 13 14
+ *     cx->n_col = 8   29 23 19 17 14
+ */
+
+/*
+ * OpenSolaris changes
+ * 1. Added header files aes_impl.h and aestab2.h
+ * 2. Changed uint_8t and uint_32t to uint8_t and uint32_t
+ * 3. Remove code under ifdef USE_VIA_ACE_IF_PRESENT (always undefined)
+ * 4. Removed always-defined ifdefs FUNCS_IN_C, ENC_KEYING_IN_C,
+ *     AES_128, AES_192, AES_256, AES_VAR defines
+ * 5. Changed aes_encrypt_key* aes_decrypt_key* functions to "static void"
+ * 6. Changed N_COLS to MAX_AES_NB
+ * 7. Replaced functions aes_encrypt_key and aes_decrypt_key with
+ *     OpenSolaris-compatible functions rijndael_key_setup_enc_amd64 and
+ *     rijndael_key_setup_dec_amd64
+ * 8. cstyled code and removed lint warnings
+ */
+
+#if defined(REDUCE_CODE_SIZE)
+#define        ls_box ls_sub
+       uint32_t        ls_sub(const uint32_t t, const uint32_t n);
+#define        inv_mcol im_sub
+       uint32_t        im_sub(const uint32_t x);
+#ifdef ENC_KS_UNROLL
+#undef ENC_KS_UNROLL
+#endif
+#ifdef DEC_KS_UNROLL
+#undef DEC_KS_UNROLL
+#endif
+#endif /* REDUCE_CODE_SIZE */
+
+
+#define        ke4(k, i) \
+{      k[4 * (i) + 4] = ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
+       k[4 * (i) + 5] = ss[1] ^= ss[0]; \
+       k[4 * (i) + 6] = ss[2] ^= ss[1]; \
+       k[4 * (i) + 7] = ss[3] ^= ss[2]; \
+}
+
+static void
+aes_encrypt_key128(const unsigned char *key, uint32_t rk[])
+{
+       uint32_t        ss[4];
+
+       rk[0] = ss[0] = word_in(key, 0);
+       rk[1] = ss[1] = word_in(key, 1);
+       rk[2] = ss[2] = word_in(key, 2);
+       rk[3] = ss[3] = word_in(key, 3);
+
+#ifdef ENC_KS_UNROLL
+       ke4(rk, 0);  ke4(rk, 1);
+       ke4(rk, 2);  ke4(rk, 3);
+       ke4(rk, 4);  ke4(rk, 5);
+       ke4(rk, 6);  ke4(rk, 7);
+       ke4(rk, 8);
+#else
+       {
+               uint32_t        i;
+               for (i = 0; i < 9; ++i)
+                       ke4(rk, i);
+       }
+#endif /* ENC_KS_UNROLL */
+       ke4(rk, 9);
+}
+
+
+#define        kef6(k, i) \
+{      k[6 * (i) + 6] = ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
+       k[6 * (i) + 7] = ss[1] ^= ss[0]; \
+       k[6 * (i) + 8] = ss[2] ^= ss[1]; \
+       k[6 * (i) + 9] = ss[3] ^= ss[2]; \
+}
+
+#define        ke6(k, i) \
+{      kef6(k, i); \
+       k[6 * (i) + 10] = ss[4] ^= ss[3]; \
+       k[6 * (i) + 11] = ss[5] ^= ss[4]; \
+}
+
+static void
+aes_encrypt_key192(const unsigned char *key, uint32_t rk[])
+{
+       uint32_t        ss[6];
+
+       rk[0] = ss[0] = word_in(key, 0);
+       rk[1] = ss[1] = word_in(key, 1);
+       rk[2] = ss[2] = word_in(key, 2);
+       rk[3] = ss[3] = word_in(key, 3);
+       rk[4] = ss[4] = word_in(key, 4);
+       rk[5] = ss[5] = word_in(key, 5);
+
+#ifdef ENC_KS_UNROLL
+       ke6(rk, 0);  ke6(rk, 1);
+       ke6(rk, 2);  ke6(rk, 3);
+       ke6(rk, 4);  ke6(rk, 5);
+       ke6(rk, 6);
+#else
+       {
+               uint32_t        i;
+               for (i = 0; i < 7; ++i)
+                       ke6(rk, i);
+       }
+#endif /* ENC_KS_UNROLL */
+       kef6(rk, 7);
+}
+
+
+
+#define        kef8(k, i) \
+{      k[8 * (i) + 8] = ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
+       k[8 * (i) + 9] = ss[1] ^= ss[0]; \
+       k[8 * (i) + 10] = ss[2] ^= ss[1]; \
+       k[8 * (i) + 11] = ss[3] ^= ss[2]; \
+}
+
+#define        ke8(k, i) \
+{   kef8(k, i); \
+       k[8 * (i) + 12] = ss[4] ^= ls_box(ss[3], 0); \
+       k[8 * (i) + 13] = ss[5] ^= ss[4]; \
+       k[8 * (i) + 14] = ss[6] ^= ss[5]; \
+       k[8 * (i) + 15] = ss[7] ^= ss[6]; \
+}
+
+static void
+aes_encrypt_key256(const unsigned char *key, uint32_t rk[])
+{
+       uint32_t        ss[8];
+
+       rk[0] = ss[0] = word_in(key, 0);
+       rk[1] = ss[1] = word_in(key, 1);
+       rk[2] = ss[2] = word_in(key, 2);
+       rk[3] = ss[3] = word_in(key, 3);
+       rk[4] = ss[4] = word_in(key, 4);
+       rk[5] = ss[5] = word_in(key, 5);
+       rk[6] = ss[6] = word_in(key, 6);
+       rk[7] = ss[7] = word_in(key, 7);
+
+#ifdef ENC_KS_UNROLL
+       ke8(rk, 0); ke8(rk, 1);
+       ke8(rk, 2); ke8(rk, 3);
+       ke8(rk, 4); ke8(rk, 5);
+#else
+       {
+               uint32_t        i;
+               for (i = 0; i < 6; ++i)
+                       ke8(rk,  i);
+       }
+#endif /* ENC_KS_UNROLL */
+       kef8(rk, 6);
+}
+
+
+/*
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * Return the number of rounds for the given cipher key size.
+ * The size of the key schedule depends on the number of rounds
+ * (which can be computed from the size of the key), i.e. 4 * (Nr + 1).
+ *
+ * Parameters:
+ * rk          AES key schedule 32-bit array to be initialized
+ * cipherKey   User key
+ * keyBits     AES key size (128, 192, or 256 bits)
+ */
+int
+rijndael_key_setup_enc_amd64(uint32_t rk[], const uint32_t cipherKey[],
+       int keyBits)
+{
+       switch (keyBits) {
+       case 128:
+               aes_encrypt_key128((unsigned char *)&cipherKey[0], rk);
+               return (10);
+       case 192:
+               aes_encrypt_key192((unsigned char *)&cipherKey[0], rk);
+               return (12);
+       case 256:
+               aes_encrypt_key256((unsigned char *)&cipherKey[0], rk);
+               return (14);
+       default: /* should never get here */
+               break;
+       }
+
+       return (0);
+}
+
+
+/* this is used to store the decryption round keys  */
+/* in forward or reverse order */
+
+#ifdef AES_REV_DKS
+#define        v(n, i)  ((n) - (i) + 2 * ((i) & 3))
+#else
+#define        v(n, i)  (i)
+#endif
+
+#if DEC_ROUND == NO_TABLES
+#define        ff(x)   (x)
+#else
+#define        ff(x)   inv_mcol(x)
+#if defined(dec_imvars)
+#define        d_vars  dec_imvars
+#endif
+#endif /* FUNCS_IN_C & DEC_KEYING_IN_C */
+
+
+#define        k4e(k, i) \
+{      k[v(40, (4 * (i)) + 4)] = ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
+       k[v(40, (4 * (i)) + 5)] = ss[1] ^= ss[0]; \
+       k[v(40, (4 * (i)) + 6)] = ss[2] ^= ss[1]; \
+       k[v(40, (4 * (i)) + 7)] = ss[3] ^= ss[2]; \
+}
+
+#if 1
+
+#define        kdf4(k, i) \
+{      ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
+       ss[1] = ss[1] ^ ss[3]; \
+       ss[2] = ss[2] ^ ss[3]; \
+       ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
+       ss[i % 4] ^= ss[4]; \
+       ss[4] ^= k[v(40, (4 * (i)))];   k[v(40, (4 * (i)) + 4)] = ff(ss[4]); \
+       ss[4] ^= k[v(40, (4 * (i)) + 1)]; k[v(40, (4 * (i)) + 5)] = ff(ss[4]); \
+       ss[4] ^= k[v(40, (4 * (i)) + 2)]; k[v(40, (4 * (i)) + 6)] = ff(ss[4]); \
+       ss[4] ^= k[v(40, (4 * (i)) + 3)]; k[v(40, (4 * (i)) + 7)] = ff(ss[4]); \
+}
+
+#define        kd4(k, i) \
+{      ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
+       ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
+       k[v(40, (4 * (i)) + 4)] = ss[4] ^= k[v(40, (4 * (i)))]; \
+       k[v(40, (4 * (i)) + 5)] = ss[4] ^= k[v(40, (4 * (i)) + 1)]; \
+       k[v(40, (4 * (i)) + 6)] = ss[4] ^= k[v(40, (4 * (i)) + 2)]; \
+       k[v(40, (4 * (i)) + 7)] = ss[4] ^= k[v(40, (4 * (i)) + 3)]; \
+}
+
+#define        kdl4(k, i) \
+{      ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
+       ss[i % 4] ^= ss[4]; \
+       k[v(40, (4 * (i)) + 4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
+       k[v(40, (4 * (i)) + 5)] = ss[1] ^ ss[3]; \
+       k[v(40, (4 * (i)) + 6)] = ss[0]; \
+       k[v(40, (4 * (i)) + 7)] = ss[1]; \
+}
+
+#else
+
+#define        kdf4(k, i) \
+{      ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
+       k[v(40, (4 * (i)) + 4)] = ff(ss[0]); \
+       ss[1] ^= ss[0]; k[v(40, (4 * (i)) + 5)] = ff(ss[1]); \
+       ss[2] ^= ss[1]; k[v(40, (4 * (i)) + 6)] = ff(ss[2]); \
+       ss[3] ^= ss[2]; k[v(40, (4 * (i)) + 7)] = ff(ss[3]); \
+}
+
+#define        kd4(k, i) \
+{      ss[4] = ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
+       ss[0] ^= ss[4]; \
+       ss[4] = ff(ss[4]); \
+       k[v(40, (4 * (i)) + 4)] = ss[4] ^= k[v(40, (4 * (i)))]; \
+       ss[1] ^= ss[0]; \
+       k[v(40, (4 * (i)) + 5)] = ss[4] ^= k[v(40, (4 * (i)) + 1)]; \
+       ss[2] ^= ss[1]; \
+       k[v(40, (4 * (i)) + 6)] = ss[4] ^= k[v(40, (4 * (i)) + 2)]; \
+       ss[3] ^= ss[2]; \
+       k[v(40, (4 * (i)) + 7)] = ss[4] ^= k[v(40, (4 * (i)) + 3)]; \
+}
+
+#define        kdl4(k, i) \
+{      ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
+       k[v(40, (4 * (i)) + 4)] = ss[0]; \
+       ss[1] ^= ss[0]; k[v(40, (4 * (i)) + 5)] = ss[1]; \
+       ss[2] ^= ss[1]; k[v(40, (4 * (i)) + 6)] = ss[2]; \
+       ss[3] ^= ss[2]; k[v(40, (4 * (i)) + 7)] = ss[3]; \
+}
+
+#endif
+
+static void
+aes_decrypt_key128(const unsigned char *key, uint32_t rk[])
+{
+       uint32_t        ss[5];
+#if defined(d_vars)
+       d_vars;
+#endif
+       rk[v(40, (0))] = ss[0] = word_in(key, 0);
+       rk[v(40, (1))] = ss[1] = word_in(key, 1);
+       rk[v(40, (2))] = ss[2] = word_in(key, 2);
+       rk[v(40, (3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+       kdf4(rk, 0); kd4(rk, 1);
+       kd4(rk, 2);  kd4(rk, 3);
+       kd4(rk, 4);  kd4(rk, 5);
+       kd4(rk, 6);  kd4(rk, 7);
+       kd4(rk, 8);  kdl4(rk, 9);
+#else
+       {
+               uint32_t        i;
+               for (i = 0; i < 10; ++i)
+                       k4e(rk, i);
+#if !(DEC_ROUND == NO_TABLES)
+               for (i = MAX_AES_NB; i < 10 * MAX_AES_NB; ++i)
+                       rk[i] = inv_mcol(rk[i]);
+#endif
+       }
+#endif /* DEC_KS_UNROLL */
+}
+
+
+
+#define        k6ef(k, i) \
+{      k[v(48, (6 * (i)) + 6)] = ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
+       k[v(48, (6 * (i)) + 7)] = ss[1] ^= ss[0]; \
+       k[v(48, (6 * (i)) + 8)] = ss[2] ^= ss[1]; \
+       k[v(48, (6 * (i)) + 9)] = ss[3] ^= ss[2]; \
+}
+
+#define        k6e(k, i) \
+{      k6ef(k, i); \
+       k[v(48, (6 * (i)) + 10)] = ss[4] ^= ss[3]; \
+       k[v(48, (6 * (i)) + 11)] = ss[5] ^= ss[4]; \
+}
+
+#define        kdf6(k, i) \
+{      ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
+       k[v(48, (6 * (i)) + 6)] = ff(ss[0]); \
+       ss[1] ^= ss[0]; k[v(48, (6 * (i)) + 7)] = ff(ss[1]); \
+       ss[2] ^= ss[1]; k[v(48, (6 * (i)) + 8)] = ff(ss[2]); \
+       ss[3] ^= ss[2]; k[v(48, (6 * (i)) + 9)] = ff(ss[3]); \
+       ss[4] ^= ss[3]; k[v(48, (6 * (i)) + 10)] = ff(ss[4]); \
+       ss[5] ^= ss[4]; k[v(48, (6 * (i)) + 11)] = ff(ss[5]); \
+}
+
+#define        kd6(k, i) \
+{      ss[6] = ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
+       ss[0] ^= ss[6]; ss[6] = ff(ss[6]); \
+       k[v(48, (6 * (i)) + 6)] = ss[6] ^= k[v(48, (6 * (i)))]; \
+       ss[1] ^= ss[0]; \
+       k[v(48, (6 * (i)) + 7)] = ss[6] ^= k[v(48, (6 * (i)) + 1)]; \
+       ss[2] ^= ss[1]; \
+       k[v(48, (6 * (i)) + 8)] = ss[6] ^= k[v(48, (6 * (i)) + 2)]; \
+       ss[3] ^= ss[2]; \
+       k[v(48, (6 * (i)) + 9)] = ss[6] ^= k[v(48, (6 * (i)) + 3)]; \
+       ss[4] ^= ss[3]; \
+       k[v(48, (6 * (i)) + 10)] = ss[6] ^= k[v(48, (6 * (i)) + 4)]; \
+       ss[5] ^= ss[4]; \
+       k[v(48, (6 * (i)) + 11)] = ss[6] ^= k[v(48, (6 * (i)) + 5)]; \
+}
+
+#define        kdl6(k, i) \
+{      ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
+       k[v(48, (6 * (i)) + 6)] = ss[0]; \
+       ss[1] ^= ss[0]; k[v(48, (6 * (i)) + 7)] = ss[1]; \
+       ss[2] ^= ss[1]; k[v(48, (6 * (i)) + 8)] = ss[2]; \
+       ss[3] ^= ss[2]; k[v(48, (6 * (i)) + 9)] = ss[3]; \
+}
+
+static void
+aes_decrypt_key192(const unsigned char *key, uint32_t rk[])
+{
+       uint32_t        ss[7];
+#if defined(d_vars)
+       d_vars;
+#endif
+       rk[v(48, (0))] = ss[0] = word_in(key, 0);
+       rk[v(48, (1))] = ss[1] = word_in(key, 1);
+       rk[v(48, (2))] = ss[2] = word_in(key, 2);
+       rk[v(48, (3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+       ss[4] = word_in(key, 4);
+       rk[v(48, (4))] = ff(ss[4]);
+       ss[5] = word_in(key, 5);
+       rk[v(48, (5))] = ff(ss[5]);
+       kdf6(rk, 0); kd6(rk, 1);
+       kd6(rk, 2);  kd6(rk, 3);
+       kd6(rk, 4);  kd6(rk, 5);
+       kd6(rk, 6);  kdl6(rk, 7);
+#else
+       rk[v(48, (4))] = ss[4] = word_in(key, 4);
+       rk[v(48, (5))] = ss[5] = word_in(key, 5);
+       {
+               uint32_t        i;
+
+               for (i = 0; i < 7; ++i)
+                       k6e(rk, i);
+               k6ef(rk, 7);
+#if !(DEC_ROUND == NO_TABLES)
+               for (i = MAX_AES_NB; i < 12 * MAX_AES_NB; ++i)
+                       rk[i] = inv_mcol(rk[i]);
+#endif
+       }
+#endif
+}
+
+
+
+#define        k8ef(k, i) \
+{      k[v(56, (8 * (i)) + 8)] = ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
+       k[v(56, (8 * (i)) + 9)] = ss[1] ^= ss[0]; \
+       k[v(56, (8 * (i)) + 10)] = ss[2] ^= ss[1]; \
+       k[v(56, (8 * (i)) + 11)] = ss[3] ^= ss[2]; \
+}
+
+#define        k8e(k, i) \
+{      k8ef(k, i); \
+       k[v(56, (8 * (i)) + 12)] = ss[4] ^= ls_box(ss[3], 0); \
+       k[v(56, (8 * (i)) + 13)] = ss[5] ^= ss[4]; \
+       k[v(56, (8 * (i)) + 14)] = ss[6] ^= ss[5]; \
+       k[v(56, (8 * (i)) + 15)] = ss[7] ^= ss[6]; \
+}
+
+#define        kdf8(k, i) \
+{      ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
+       k[v(56, (8 * (i)) + 8)] = ff(ss[0]); \
+       ss[1] ^= ss[0]; k[v(56, (8 * (i)) + 9)] = ff(ss[1]); \
+       ss[2] ^= ss[1]; k[v(56, (8 * (i)) + 10)] = ff(ss[2]); \
+       ss[3] ^= ss[2]; k[v(56, (8 * (i)) + 11)] = ff(ss[3]); \
+       ss[4] ^= ls_box(ss[3], 0); k[v(56, (8 * (i)) + 12)] = ff(ss[4]); \
+       ss[5] ^= ss[4]; k[v(56, (8 * (i)) + 13)] = ff(ss[5]); \
+       ss[6] ^= ss[5]; k[v(56, (8 * (i)) + 14)] = ff(ss[6]); \
+       ss[7] ^= ss[6]; k[v(56, (8 * (i)) + 15)] = ff(ss[7]); \
+}
+
+#define        kd8(k, i) \
+{      ss[8] = ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
+       ss[0] ^= ss[8]; \
+       ss[8] = ff(ss[8]); \
+       k[v(56, (8 * (i)) + 8)] = ss[8] ^= k[v(56, (8 * (i)))]; \
+       ss[1] ^= ss[0]; \
+       k[v(56, (8 * (i)) + 9)] = ss[8] ^= k[v(56, (8 * (i)) + 1)]; \
+       ss[2] ^= ss[1]; \
+       k[v(56, (8 * (i)) + 10)] = ss[8] ^= k[v(56, (8 * (i)) + 2)]; \
+       ss[3] ^= ss[2]; \
+       k[v(56, (8 * (i)) + 11)] = ss[8] ^= k[v(56, (8 * (i)) + 3)]; \
+       ss[8] = ls_box(ss[3], 0); \
+       ss[4] ^= ss[8]; \
+       ss[8] = ff(ss[8]); \
+       k[v(56, (8 * (i)) + 12)] = ss[8] ^= k[v(56, (8 * (i)) + 4)]; \
+       ss[5] ^= ss[4]; \
+       k[v(56, (8 * (i)) + 13)] = ss[8] ^= k[v(56, (8 * (i)) + 5)]; \
+       ss[6] ^= ss[5]; \
+       k[v(56, (8 * (i)) + 14)] = ss[8] ^= k[v(56, (8 * (i)) + 6)]; \
+       ss[7] ^= ss[6]; \
+       k[v(56, (8 * (i)) + 15)] = ss[8] ^= k[v(56, (8 * (i)) + 7)]; \
+}
+
+#define        kdl8(k, i) \
+{      ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
+       k[v(56, (8 * (i)) + 8)] = ss[0]; \
+       ss[1] ^= ss[0]; k[v(56, (8 * (i)) + 9)] = ss[1]; \
+       ss[2] ^= ss[1]; k[v(56, (8 * (i)) + 10)] = ss[2]; \
+       ss[3] ^= ss[2]; k[v(56, (8 * (i)) + 11)] = ss[3]; \
+}
+
+static void
+aes_decrypt_key256(const unsigned char *key, uint32_t rk[])
+{
+       uint32_t        ss[9];
+#if defined(d_vars)
+       d_vars;
+#endif
+       rk[v(56, (0))] = ss[0] = word_in(key, 0);
+       rk[v(56, (1))] = ss[1] = word_in(key, 1);
+       rk[v(56, (2))] = ss[2] = word_in(key, 2);
+       rk[v(56, (3))] = ss[3] = word_in(key, 3);
+
+#ifdef DEC_KS_UNROLL
+       ss[4] = word_in(key, 4);
+       rk[v(56, (4))] = ff(ss[4]);
+       ss[5] = word_in(key, 5);
+       rk[v(56, (5))] = ff(ss[5]);
+       ss[6] = word_in(key, 6);
+       rk[v(56, (6))] = ff(ss[6]);
+       ss[7] = word_in(key, 7);
+       rk[v(56, (7))] = ff(ss[7]);
+       kdf8(rk, 0); kd8(rk, 1);
+       kd8(rk, 2);  kd8(rk, 3);
+       kd8(rk, 4);  kd8(rk, 5);
+       kdl8(rk, 6);
+#else
+       rk[v(56, (4))] = ss[4] = word_in(key, 4);
+       rk[v(56, (5))] = ss[5] = word_in(key, 5);
+       rk[v(56, (6))] = ss[6] = word_in(key, 6);
+       rk[v(56, (7))] = ss[7] = word_in(key, 7);
+       {
+               uint32_t        i;
+
+               for (i = 0; i < 6; ++i)
+                       k8e(rk,  i);
+               k8ef(rk,  6);
+#if !(DEC_ROUND == NO_TABLES)
+               for (i = MAX_AES_NB; i < 14 * MAX_AES_NB; ++i)
+                       rk[i] = inv_mcol(rk[i]);
+#endif
+       }
+#endif /* DEC_KS_UNROLL */
+}
+
+
+/*
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * Return the number of rounds for the given cipher key size.
+ * The size of the key schedule depends on the number of rounds
+ * (which can be computed from the size of the key), i.e. 4 * (Nr + 1).
+ *
+ * Parameters:
+ * rk          AES key schedule 32-bit array to be initialized
+ * cipherKey   User key
+ * keyBits     AES key size (128, 192, or 256 bits)
+ */
+int
+rijndael_key_setup_dec_amd64(uint32_t rk[], const uint32_t cipherKey[],
+       int keyBits)
+{
+       switch (keyBits) {
+       case 128:
+               aes_decrypt_key128((unsigned char *)&cipherKey[0], rk);
+               return (10);
+       case 192:
+               aes_decrypt_key192((unsigned char *)&cipherKey[0], rk);
+               return (12);
+       case 256:
+               aes_decrypt_key256((unsigned char *)&cipherKey[0], rk);
+               return (14);
+       default: /* should never get here */
+               break;
+       }
+
+       return (0);
+}
diff --git a/zfs/module/icp/asm-x86_64/aes/aesopt.h b/zfs/module/icp/asm-x86_64/aes/aesopt.h
new file mode 100644 (file)
index 0000000..6aa61db
--- /dev/null
@@ -0,0 +1,770 @@
+/*
+ * ---------------------------------------------------------------------------
+ * Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software is allowed (with or without
+ * changes) provided that:
+ *
+ *  1. source code distributions include the above copyright notice, this
+ *     list of conditions and the following disclaimer;
+ *
+ *  2. binary distributions include the above copyright notice, this list
+ *     of conditions and the following disclaimer in their documentation;
+ *
+ *  3. the name of the copyright holder is not used to endorse products
+ *     built using this software without specific written permission.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ * Issue Date: 20/12/2007
+ *
+ * This file contains the compilation options for AES (Rijndael) and code
+ * that is common across encryption, key scheduling and table generation.
+ *
+ * OPERATION
+ *
+ * These source code files implement the AES algorithm Rijndael designed by
+ * Joan Daemen and Vincent Rijmen. This version is designed for the standard
+ * block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24
+ * and 32 bytes).
+ *
+ * This version is designed for flexibility and speed using operations on
+ * 32-bit words rather than operations on bytes.  It can be compiled with
+ * either big or little endian internal byte order but is faster when the
+ * native byte order for the processor is used.
+ *
+ * THE CIPHER INTERFACE
+ *
+ * The cipher interface is implemented as an array of bytes in which lower
+ * AES bit sequence indexes map to higher numeric significance within bytes.
+ */
+
+/*
+ * OpenSolaris changes
+ * 1. Added __cplusplus and _AESTAB_H header guards
+ * 2. Added header files sys/types.h and aes_impl.h
+ * 3. Added defines for AES_ENCRYPT, AES_DECRYPT, AES_REV_DKS, and ASM_AMD64_C
+ * 4. Moved defines for IS_BIG_ENDIAN, IS_LITTLE_ENDIAN, PLATFORM_BYTE_ORDER
+ *    from brg_endian.h
+ * 5. Undefined VIA_ACE_POSSIBLE and ASSUME_VIA_ACE_PRESENT
+ * 6. Changed uint_8t and uint_32t to uint8_t and uint32_t
+ * 7. Defined aes_sw32 as htonl() for byte swapping
+ * 8. Cstyled and hdrchk code
+ *
+ */
+
+#ifndef _AESOPT_H
+#define        _AESOPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <aes/aes_impl.h>
+
+/*  SUPPORT FEATURES */
+#define        AES_ENCRYPT /* if support for encryption is needed */
+#define        AES_DECRYPT /* if support for decryption is needed */
+
+/*  PLATFORM-SPECIFIC FEATURES */
+#define        IS_BIG_ENDIAN           4321 /* byte 0 is most significant (mc68k) */
+#define        IS_LITTLE_ENDIAN        1234 /* byte 0 is least significant (i386) */
+#define        PLATFORM_BYTE_ORDER     IS_LITTLE_ENDIAN
+#define        AES_REV_DKS /* define to reverse decryption key schedule */
+
+
+/*
+ *  CONFIGURATION - THE USE OF DEFINES
+ *     Later in this section there are a number of defines that control the
+ *     operation of the code.  In each section, the purpose of each define is
+ *     explained so that the relevant form can be included or excluded by
+ *     setting either 1's or 0's respectively on the branches of the related
+ *     #if clauses.  The following local defines should not be changed.
+ */
+
+#define        ENCRYPTION_IN_C 1
+#define        DECRYPTION_IN_C 2
+#define        ENC_KEYING_IN_C 4
+#define        DEC_KEYING_IN_C 8
+
+#define        NO_TABLES       0
+#define        ONE_TABLE       1
+#define        FOUR_TABLES     4
+#define        NONE            0
+#define        PARTIAL         1
+#define        FULL            2
+
+/*  --- START OF USER CONFIGURED OPTIONS --- */
+
+/*
+ *  1. BYTE ORDER WITHIN 32 BIT WORDS
+ *
+ *     The fundamental data processing units in Rijndael are 8-bit bytes. The
+ *     input, output and key input are all enumerated arrays of bytes in which
+ *     bytes are numbered starting at zero and increasing to one less than the
+ *     number of bytes in the array in question. This enumeration is only used
+ *     for naming bytes and does not imply any adjacency or order relationship
+ *     from one byte to another. When these inputs and outputs are considered
+ *     as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
+ *     byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
+ *     In this implementation bits are numbered from 0 to 7 starting at the
+ *     numerically least significant end of each byte.  Bit n represents 2^n.
+ *
+ *     However, Rijndael can be implemented more efficiently using 32-bit
+ *     words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
+ *     into word[n]. While in principle these bytes can be assembled into words
+ *     in any positions, this implementation only supports the two formats in
+ *     which bytes in adjacent positions within words also have adjacent byte
+ *     numbers. This order is called big-endian if the lowest numbered bytes
+ *     in words have the highest numeric significance and little-endian if the
+ *     opposite applies.
+ *
+ *     This code can work in either order irrespective of the order used by the
+ *     machine on which it runs. Normally the internal byte order will be set
+ *     to the order of the processor on which the code is to be run but this
+ *     define  can be used to reverse this in special situations
+ *
+ *     WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set.
+ *     This define will hence be redefined later (in section 4) if necessary
+ */
+
+#if 1
+#define        ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
+#elif 0
+#define        ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN
+#elif 0
+#define        ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN
+#else
+#error The algorithm byte order is not defined
+#endif
+
+/*  2. VIA ACE SUPPORT */
+
+#if defined(__GNUC__) && defined(__i386__) || \
+       defined(_WIN32) && defined(_M_IX86) && \
+       !(defined(_WIN64) || defined(_WIN32_WCE) || \
+       defined(_MSC_VER) && (_MSC_VER <= 800))
+#define        VIA_ACE_POSSIBLE
+#endif
+
+/*
+ *  Define this option if support for the VIA ACE is required. This uses
+ *  inline assembler instructions and is only implemented for the Microsoft,
+ *  Intel and GCC compilers.  If VIA ACE is known to be present, then defining
+ *  ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption
+ *  code.  If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if
+ *  it is detected (both present and enabled) but the normal AES code will
+ *  also be present.
+ *
+ *  When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte
+ *  aligned; other input/output buffers do not need to be 16 byte aligned
+ *  but there are very large performance gains if this can be arranged.
+ *  VIA ACE also requires the decryption key schedule to be in reverse
+ *  order (which later checks below ensure).
+ */
+
+/*  VIA ACE is not used here for OpenSolaris: */
+#undef VIA_ACE_POSSIBLE
+#undef ASSUME_VIA_ACE_PRESENT
+
+#if 0 && defined(VIA_ACE_POSSIBLE) && !defined(USE_VIA_ACE_IF_PRESENT)
+#define        USE_VIA_ACE_IF_PRESENT
+#endif
+
+#if 0 && defined(VIA_ACE_POSSIBLE) && !defined(ASSUME_VIA_ACE_PRESENT)
+#define        ASSUME_VIA_ACE_PRESENT
+#endif
+
+
+/*
+ *  3. ASSEMBLER SUPPORT
+ *
+ *     This define (which can be on the command line) enables the use of the
+ *     assembler code routines for encryption, decryption and key scheduling
+ *     as follows:
+ *
+ *     ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for
+ *             encryption and decryption and but with key scheduling in C
+ *     ASM_X86_V2  uses assembler (aes_x86_v2.asm) with compressed tables for
+ *             encryption, decryption and key scheduling
+ *     ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for
+ *             encryption and decryption and but with key scheduling in C
+ *     ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for
+ *             encryption and decryption and but with key scheduling in C
+ *
+ *     Change one 'if 0' below to 'if 1' to select the version or define
+ *     as a compilation option.
+ */
+
+#if 0 && !defined(ASM_X86_V1C)
+#define        ASM_X86_V1C
+#elif 0 && !defined(ASM_X86_V2)
+#define        ASM_X86_V2
+#elif 0 && !defined(ASM_X86_V2C)
+#define        ASM_X86_V2C
+#elif 1 && !defined(ASM_AMD64_C)
+#define        ASM_AMD64_C
+#endif
+
+#if (defined(ASM_X86_V1C) || defined(ASM_X86_V2) || defined(ASM_X86_V2C)) && \
+       !defined(_M_IX86) || defined(ASM_AMD64_C) && !defined(_M_X64) && \
+       !defined(__amd64)
+#error Assembler code is only available for x86 and AMD64 systems
+#endif
+
+/*
+ *  4. FAST INPUT/OUTPUT OPERATIONS.
+ *
+ *     On some machines it is possible to improve speed by transferring the
+ *     bytes in the input and output arrays to and from the internal 32-bit
+ *     variables by addressing these arrays as if they are arrays of 32-bit
+ *     words.  On some machines this will always be possible but there may
+ *     be a large performance penalty if the byte arrays are not aligned on
+ *     the normal word boundaries. On other machines this technique will
+ *     lead to memory access errors when such 32-bit word accesses are not
+ *     properly aligned. The option SAFE_IO avoids such problems but will
+ *     often be slower on those machines that support misaligned access
+ *     (especially so if care is taken to align the input  and output byte
+ *     arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
+ *     assumed that access to byte arrays as if they are arrays of 32-bit
+ *     words will not cause problems when such accesses are misaligned.
+ */
+#if 1 && !defined(_MSC_VER)
+#define        SAFE_IO
+#endif
+
+/*
+ *  5. LOOP UNROLLING
+ *
+ *     The code for encryption and decryption cycles through a number of rounds
+ *     that can be implemented either in a loop or by expanding the code into a
+ *     long sequence of instructions, the latter producing a larger program but
+ *     one that will often be much faster. The latter is called loop unrolling.
+ *     There are also potential speed advantages in expanding two iterations in
+ *     a loop with half the number of iterations, which is called partial loop
+ *     unrolling.  The following options allow partial or full loop unrolling
+ *     to be set independently for encryption and decryption
+ */
+#if 1
+#define        ENC_UNROLL  FULL
+#elif 0
+#define        ENC_UNROLL  PARTIAL
+#else
+#define        ENC_UNROLL  NONE
+#endif
+
+#if 1
+#define        DEC_UNROLL  FULL
+#elif 0
+#define        DEC_UNROLL  PARTIAL
+#else
+#define        DEC_UNROLL  NONE
+#endif
+
+#if 1
+#define        ENC_KS_UNROLL
+#endif
+
+#if 1
+#define        DEC_KS_UNROLL
+#endif
+
+/*
+ *  6. FAST FINITE FIELD OPERATIONS
+ *
+ *     If this section is included, tables are used to provide faster finite
+ *     field arithmetic.  This has no effect if FIXED_TABLES is defined.
+ */
+#if 1
+#define        FF_TABLES
+#endif
+
+/*
+ *  7. INTERNAL STATE VARIABLE FORMAT
+ *
+ *     The internal state of Rijndael is stored in a number of local 32-bit
+ *     word variables which can be defined either as an array or as individual
+ *     names variables. Include this section if you want to store these local
+ *     variables in arrays. Otherwise individual local variables will be used.
+ */
+#if 1
+#define        ARRAYS
+#endif
+
+/*
+ *  8. FIXED OR DYNAMIC TABLES
+ *
+ *     When this section is included the tables used by the code are compiled
+ *     statically into the binary file.  Otherwise the subroutine aes_init()
+ *     must be called to compute them before the code is first used.
+ */
+#if 1 && !(defined(_MSC_VER) && (_MSC_VER <= 800))
+#define        FIXED_TABLES
+#endif
+
+/*
+ *  9. MASKING OR CASTING FROM LONGER VALUES TO BYTES
+ *
+ *     In some systems it is better to mask longer values to extract bytes
+ *     rather than using a cast. This option allows this choice.
+ */
+#if 0
+#define        to_byte(x)  ((uint8_t)(x))
+#else
+#define        to_byte(x)  ((x) & 0xff)
+#endif
+
+/*
+ *  10. TABLE ALIGNMENT
+ *
+ *     On some systems speed will be improved by aligning the AES large lookup
+ *     tables on particular boundaries. This define should be set to a power of
+ *     two giving the desired alignment. It can be left undefined if alignment
+ *     is not needed.  This option is specific to the Micrsoft VC++ compiler -
+ *     it seems to sometimes cause trouble for the VC++ version 6 compiler.
+ */
+
+#if 1 && defined(_MSC_VER) && (_MSC_VER >= 1300)
+#define        TABLE_ALIGN 32
+#endif
+
+/*
+ *  11.  REDUCE CODE AND TABLE SIZE
+ *
+ *     This replaces some expanded macros with function calls if AES_ASM_V2 or
+ *     AES_ASM_V2C are defined
+ */
+
+#if 1 && (defined(ASM_X86_V2) || defined(ASM_X86_V2C))
+#define        REDUCE_CODE_SIZE
+#endif
+
+/*
+ *  12. TABLE OPTIONS
+ *
+ *     This cipher proceeds by repeating in a number of cycles known as rounds
+ *     which are implemented by a round function which is optionally be speeded
+ *     up using tables.  The basic tables are 256 32-bit words, with either
+ *     one or four tables being required for each round function depending on
+ *     how much speed is required. Encryption and decryption round functions
+ *     are different and the last encryption and decryption round functions are
+ *     different again making four different round functions in all.
+ *
+ *     This means that:
+ *     1. Normal encryption and decryption rounds can each use either 0, 1
+ *             or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
+ *     2. The last encryption and decryption rounds can also use either 0, 1
+ *             or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
+ *
+ *     Include or exclude the appropriate definitions below to set the number
+ *     of tables used by this implementation.
+ */
+
+#if 1   /* set tables for the normal encryption round */
+#define        ENC_ROUND   FOUR_TABLES
+#elif 0
+#define        ENC_ROUND   ONE_TABLE
+#else
+#define        ENC_ROUND   NO_TABLES
+#endif
+
+#if 1   /* set tables for the last encryption round */
+#define        LAST_ENC_ROUND  FOUR_TABLES
+#elif 0
+#define        LAST_ENC_ROUND  ONE_TABLE
+#else
+#define        LAST_ENC_ROUND  NO_TABLES
+#endif
+
+#if 1   /* set tables for the normal decryption round */
+#define        DEC_ROUND   FOUR_TABLES
+#elif 0
+#define        DEC_ROUND   ONE_TABLE
+#else
+#define        DEC_ROUND   NO_TABLES
+#endif
+
+#if 1   /* set tables for the last decryption round */
+#define        LAST_DEC_ROUND  FOUR_TABLES
+#elif 0
+#define        LAST_DEC_ROUND  ONE_TABLE
+#else
+#define        LAST_DEC_ROUND  NO_TABLES
+#endif
+
+/*
+ *  The decryption key schedule can be speeded up with tables in the same
+ *     way that the round functions can.  Include or exclude the following
+ *     defines to set this requirement.
+ */
+#if 1
+#define        KEY_SCHED   FOUR_TABLES
+#elif 0
+#define        KEY_SCHED   ONE_TABLE
+#else
+#define        KEY_SCHED   NO_TABLES
+#endif
+
+/*  ---- END OF USER CONFIGURED OPTIONS ---- */
+
+/* VIA ACE support is only available for VC++ and GCC */
+
+#if !defined(_MSC_VER) && !defined(__GNUC__)
+#if defined(ASSUME_VIA_ACE_PRESENT)
+#undef ASSUME_VIA_ACE_PRESENT
+#endif
+#if defined(USE_VIA_ACE_IF_PRESENT)
+#undef USE_VIA_ACE_IF_PRESENT
+#endif
+#endif
+
+#if defined(ASSUME_VIA_ACE_PRESENT) && !defined(USE_VIA_ACE_IF_PRESENT)
+#define        USE_VIA_ACE_IF_PRESENT
+#endif
+
+#if defined(USE_VIA_ACE_IF_PRESENT) && !defined(AES_REV_DKS)
+#define        AES_REV_DKS
+#endif
+
+/* Assembler support requires the use of platform byte order */
+
+#if (defined(ASM_X86_V1C) || defined(ASM_X86_V2C) || defined(ASM_AMD64_C)) && \
+       (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER)
+#undef  ALGORITHM_BYTE_ORDER
+#define        ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
+#endif
+
+/*
+ * In this implementation the columns of the state array are each held in
+ *     32-bit words. The state array can be held in various ways: in an array
+ *     of words, in a number of individual word variables or in a number of
+ *     processor registers. The following define maps a variable name x and
+ *     a column number c to the way the state array variable is to be held.
+ *     The first define below maps the state into an array x[c] whereas the
+ *     second form maps the state into a number of individual variables x0,
+ *     x1, etc.  Another form could map individual state columns to machine
+ *     register names.
+ */
+
+#if defined(ARRAYS)
+#define        s(x, c) x[c]
+#else
+#define        s(x, c) x##c
+#endif
+
+/*
+ *  This implementation provides subroutines for encryption, decryption
+ *     and for setting the three key lengths (separately) for encryption
+ *     and decryption. Since not all functions are needed, masks are set
+ *     up here to determine which will be implemented in C
+ */
+
+#if !defined(AES_ENCRYPT)
+#define        EFUNCS_IN_C   0
+#elif defined(ASSUME_VIA_ACE_PRESENT) || defined(ASM_X86_V1C) || \
+       defined(ASM_X86_V2C) || defined(ASM_AMD64_C)
+#define        EFUNCS_IN_C   ENC_KEYING_IN_C
+#elif !defined(ASM_X86_V2)
+#define        EFUNCS_IN_C   (ENCRYPTION_IN_C | ENC_KEYING_IN_C)
+#else
+#define        EFUNCS_IN_C   0
+#endif
+
+#if !defined(AES_DECRYPT)
+#define        DFUNCS_IN_C   0
+#elif defined(ASSUME_VIA_ACE_PRESENT) || defined(ASM_X86_V1C) || \
+       defined(ASM_X86_V2C) || defined(ASM_AMD64_C)
+#define        DFUNCS_IN_C   DEC_KEYING_IN_C
+#elif !defined(ASM_X86_V2)
+#define        DFUNCS_IN_C   (DECRYPTION_IN_C | DEC_KEYING_IN_C)
+#else
+#define        DFUNCS_IN_C   0
+#endif
+
+#define        FUNCS_IN_C  (EFUNCS_IN_C | DFUNCS_IN_C)
+
+/* END OF CONFIGURATION OPTIONS */
+
+/* Disable or report errors on some combinations of options */
+
+#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
+#undef  LAST_ENC_ROUND
+#define        LAST_ENC_ROUND  NO_TABLES
+#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
+#undef  LAST_ENC_ROUND
+#define        LAST_ENC_ROUND  ONE_TABLE
+#endif
+
+#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
+#undef  ENC_UNROLL
+#define        ENC_UNROLL  NONE
+#endif
+
+#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
+#undef  LAST_DEC_ROUND
+#define        LAST_DEC_ROUND  NO_TABLES
+#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
+#undef  LAST_DEC_ROUND
+#define        LAST_DEC_ROUND  ONE_TABLE
+#endif
+
+#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
+#undef  DEC_UNROLL
+#define        DEC_UNROLL  NONE
+#endif
+
+#if (ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN)
+#define        aes_sw32        htonl
+#elif defined(bswap32)
+#define        aes_sw32        bswap32
+#elif defined(bswap_32)
+#define        aes_sw32        bswap_32
+#else
+#define        brot(x, n)  (((uint32_t)(x) << (n)) | ((uint32_t)(x) >> (32 - (n))))
+#define        aes_sw32(x) ((brot((x), 8) & 0x00ff00ff) | (brot((x), 24) & 0xff00ff00))
+#endif
+
+
+/*
+ *     upr(x, n):  rotates bytes within words by n positions, moving bytes to
+ *             higher index positions with wrap around into low positions
+ *     ups(x, n):  moves bytes by n positions to higher index positions in
+ *             words but without wrap around
+ *     bval(x, n): extracts a byte from a word
+ *
+ *     WARNING:   The definitions given here are intended only for use with
+ *             unsigned variables and with shift counts that are compile
+ *             time constants
+ */
+
+#if (ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN)
+#define        upr(x, n)       (((uint32_t)(x) << (8 * (n))) | \
+                       ((uint32_t)(x) >> (32 - 8 * (n))))
+#define        ups(x, n)       ((uint32_t)(x) << (8 * (n)))
+#define        bval(x, n)      to_byte((x) >> (8 * (n)))
+#define        bytes2word(b0, b1, b2, b3)  \
+               (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | \
+               ((uint32_t)(b1) << 8) | (b0))
+#endif
+
+#if (ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN)
+#define        upr(x, n)       (((uint32_t)(x) >> (8 * (n))) | \
+                       ((uint32_t)(x) << (32 - 8 * (n))))
+#define        ups(x, n)       ((uint32_t)(x) >> (8 * (n)))
+#define        bval(x, n)      to_byte((x) >> (24 - 8 * (n)))
+#define        bytes2word(b0, b1, b2, b3)  \
+               (((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | \
+               ((uint32_t)(b2) << 8) | (b3))
+#endif
+
+#if defined(SAFE_IO)
+#define        word_in(x, c)   bytes2word(((const uint8_t *)(x) + 4 * c)[0], \
+                               ((const uint8_t *)(x) + 4 * c)[1], \
+                               ((const uint8_t *)(x) + 4 * c)[2], \
+                               ((const uint8_t *)(x) + 4 * c)[3])
+#define        word_out(x, c, v) { ((uint8_t *)(x) + 4 * c)[0] = bval(v, 0); \
+                       ((uint8_t *)(x) + 4 * c)[1] = bval(v, 1); \
+                       ((uint8_t *)(x) + 4 * c)[2] = bval(v, 2); \
+                       ((uint8_t *)(x) + 4 * c)[3] = bval(v, 3); }
+#elif (ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER)
+#define        word_in(x, c)   (*((uint32_t *)(x) + (c)))
+#define        word_out(x, c, v) (*((uint32_t *)(x) + (c)) = (v))
+#else
+#define        word_in(x, c)   aes_sw32(*((uint32_t *)(x) + (c)))
+#define        word_out(x, c, v) (*((uint32_t *)(x) + (c)) = aes_sw32(v))
+#endif
+
+/* the finite field modular polynomial and elements */
+
+#define        WPOLY   0x011b
+#define        BPOLY   0x1b
+
+/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+#define        m1  0x80808080
+#define        m2  0x7f7f7f7f
+#define        gf_mulx(x)  ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY))
+
+/*
+ * The following defines provide alternative definitions of gf_mulx that might
+ * give improved performance if a fast 32-bit multiply is not available. Note
+ * that a temporary variable u needs to be defined where gf_mulx is used.
+ *
+ * #define     gf_mulx(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ \
+ *                     ((u >> 3) | (u >> 6))
+ * #define     m4  (0x01010101 * BPOLY)
+ * #define     gf_mulx(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) \
+ *                     & m4)
+ */
+
+/* Work out which tables are needed for the different options   */
+
+#if defined(ASM_X86_V1C)
+#if defined(ENC_ROUND)
+#undef  ENC_ROUND
+#endif
+#define        ENC_ROUND   FOUR_TABLES
+#if defined(LAST_ENC_ROUND)
+#undef  LAST_ENC_ROUND
+#endif
+#define        LAST_ENC_ROUND  FOUR_TABLES
+#if defined(DEC_ROUND)
+#undef  DEC_ROUND
+#endif
+#define        DEC_ROUND   FOUR_TABLES
+#if defined(LAST_DEC_ROUND)
+#undef  LAST_DEC_ROUND
+#endif
+#define        LAST_DEC_ROUND  FOUR_TABLES
+#if defined(KEY_SCHED)
+#undef  KEY_SCHED
+#define        KEY_SCHED   FOUR_TABLES
+#endif
+#endif
+
+#if (FUNCS_IN_C & ENCRYPTION_IN_C) || defined(ASM_X86_V1C)
+#if ENC_ROUND == ONE_TABLE
+#define        FT1_SET
+#elif ENC_ROUND == FOUR_TABLES
+#define        FT4_SET
+#else
+#define        SBX_SET
+#endif
+#if LAST_ENC_ROUND == ONE_TABLE
+#define        FL1_SET
+#elif LAST_ENC_ROUND == FOUR_TABLES
+#define        FL4_SET
+#elif !defined(SBX_SET)
+#define        SBX_SET
+#endif
+#endif
+
+#if (FUNCS_IN_C & DECRYPTION_IN_C) || defined(ASM_X86_V1C)
+#if DEC_ROUND == ONE_TABLE
+#define        IT1_SET
+#elif DEC_ROUND == FOUR_TABLES
+#define        IT4_SET
+#else
+#define        ISB_SET
+#endif
+#if LAST_DEC_ROUND == ONE_TABLE
+#define        IL1_SET
+#elif LAST_DEC_ROUND == FOUR_TABLES
+#define        IL4_SET
+#elif !defined(ISB_SET)
+#define        ISB_SET
+#endif
+#endif
+
+
+#if !(defined(REDUCE_CODE_SIZE) && (defined(ASM_X86_V2) || \
+       defined(ASM_X86_V2C)))
+#if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C))
+#if KEY_SCHED == ONE_TABLE
+#if !defined(FL1_SET) && !defined(FL4_SET)
+#define        LS1_SET
+#endif
+#elif KEY_SCHED == FOUR_TABLES
+#if !defined(FL4_SET)
+#define        LS4_SET
+#endif
+#elif !defined(SBX_SET)
+#define        SBX_SET
+#endif
+#endif
+#if (FUNCS_IN_C & DEC_KEYING_IN_C)
+#if KEY_SCHED == ONE_TABLE
+#define        IM1_SET
+#elif KEY_SCHED == FOUR_TABLES
+#define        IM4_SET
+#elif !defined(SBX_SET)
+#define        SBX_SET
+#endif
+#endif
+#endif
+
+/* generic definitions of Rijndael macros that use tables */
+
+#define        no_table(x, box, vf, rf, c) bytes2word(\
+       box[bval(vf(x, 0, c), rf(0, c))], \
+       box[bval(vf(x, 1, c), rf(1, c))], \
+       box[bval(vf(x, 2, c), rf(2, c))], \
+       box[bval(vf(x, 3, c), rf(3, c))])
+
+#define        one_table(x, op, tab, vf, rf, c) \
+       (tab[bval(vf(x, 0, c), rf(0, c))] \
+       ^ op(tab[bval(vf(x, 1, c), rf(1, c))], 1) \
+       ^ op(tab[bval(vf(x, 2, c), rf(2, c))], 2) \
+       ^ op(tab[bval(vf(x, 3, c), rf(3, c))], 3))
+
+#define        four_tables(x, tab, vf, rf, c) \
+       (tab[0][bval(vf(x, 0, c), rf(0, c))] \
+       ^ tab[1][bval(vf(x, 1, c), rf(1, c))] \
+       ^ tab[2][bval(vf(x, 2, c), rf(2, c))] \
+       ^ tab[3][bval(vf(x, 3, c), rf(3, c))])
+
+#define        vf1(x, r, c)    (x)
+#define        rf1(r, c)       (r)
+#define        rf2(r, c)       ((8+r-c)&3)
+
+/*
+ * Perform forward and inverse column mix operation on four bytes in long word
+ * x in parallel. NOTE: x must be a simple variable, NOT an expression in
+ * these macros.
+ */
+
+#if !(defined(REDUCE_CODE_SIZE) && (defined(ASM_X86_V2) || \
+       defined(ASM_X86_V2C)))
+
+#if defined(FM4_SET)   /* not currently used */
+#define        fwd_mcol(x)     four_tables(x, t_use(f, m), vf1, rf1, 0)
+#elif defined(FM1_SET) /* not currently used */
+#define        fwd_mcol(x)     one_table(x, upr, t_use(f, m), vf1, rf1, 0)
+#else
+#define        dec_fmvars      uint32_t g2
+#define        fwd_mcol(x)     (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ \
+                               upr((x), 2) ^ upr((x), 1))
+#endif
+
+#if defined(IM4_SET)
+#define        inv_mcol(x)     four_tables(x, t_use(i, m), vf1, rf1, 0)
+#elif defined(IM1_SET)
+#define        inv_mcol(x)     one_table(x, upr, t_use(i, m), vf1, rf1, 0)
+#else
+#define        dec_imvars      uint32_t g2, g4, g9
+#define        inv_mcol(x)     (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = \
+                               (x) ^ gf_mulx(g4), g4 ^= g9, \
+                               (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ \
+                               upr(g4, 2) ^ upr(g9, 1))
+#endif
+
+#if defined(FL4_SET)
+#define        ls_box(x, c)    four_tables(x, t_use(f, l), vf1, rf2, c)
+#elif defined(LS4_SET)
+#define        ls_box(x, c)    four_tables(x, t_use(l, s), vf1, rf2, c)
+#elif defined(FL1_SET)
+#define        ls_box(x, c)    one_table(x, upr, t_use(f, l), vf1, rf2, c)
+#elif defined(LS1_SET)
+#define        ls_box(x, c)    one_table(x, upr, t_use(l, s), vf1, rf2, c)
+#else
+#define        ls_box(x, c)    no_table(x, t_use(s, box), vf1, rf2, c)
+#endif
+
+#endif
+
+#if defined(ASM_X86_V1C) && defined(AES_DECRYPT) && !defined(ISB_SET)
+#define        ISB_SET
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AESOPT_H */
diff --git a/zfs/module/icp/asm-x86_64/aes/aestab.h b/zfs/module/icp/asm-x86_64/aes/aestab.h
new file mode 100644 (file)
index 0000000..33cdb6c
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * ---------------------------------------------------------------------------
+ * Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software is allowed (with or without
+ * changes) provided that:
+ *
+ *  1. source code distributions include the above copyright notice, this
+ *     list of conditions and the following disclaimer;
+ *
+ *  2. binary distributions include the above copyright notice, this list
+ *     of conditions and the following disclaimer in their documentation;
+ *
+ *  3. the name of the copyright holder is not used to endorse products
+ *     built using this software without specific written permission.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ * Issue Date: 20/12/2007
+ *
+ * This file contains the code for declaring the tables needed to implement
+ * AES. The file aesopt.h is assumed to be included before this header file.
+ * If there are no global variables, the definitions here can be used to put
+ * the AES tables in a structure so that a pointer can then be added to the
+ * AES context to pass them to the AES routines that need them.   If this
+ * facility is used, the calling program has to ensure that this pointer is
+ * managed appropriately.  In particular, the value of the t_dec(in, it) item
+ * in the table structure must be set to zero in order to ensure that the
+ * tables are initialised. In practice the three code sequences in aeskey.c
+ * that control the calls to aes_init() and the aes_init() routine itself will
+ * have to be changed for a specific implementation. If global variables are
+ * available it will generally be preferable to use them with the precomputed
+ * FIXED_TABLES option that uses static global tables.
+ *
+ * The following defines can be used to control the way the tables
+ * are defined, initialised and used in embedded environments that
+ * require special features for these purposes
+ *
+ *    the 't_dec' construction is used to declare fixed table arrays
+ *    the 't_set' construction is used to set fixed table values
+ *    the 't_use' construction is used to access fixed table values
+ *
+ *    256 byte tables:
+ *
+ *        t_xxx(s, box)    => forward S box
+ *        t_xxx(i, box)    => inverse S box
+ *
+ *    256 32-bit word OR 4 x 256 32-bit word tables:
+ *
+ *        t_xxx(f, n)      => forward normal round
+ *        t_xxx(f, l)      => forward last round
+ *        t_xxx(i, n)      => inverse normal round
+ *        t_xxx(i, l)      => inverse last round
+ *        t_xxx(l, s)      => key schedule table
+ *        t_xxx(i, m)      => key schedule table
+ *
+ *    Other variables and tables:
+ *
+ *        t_xxx(r, c)      => the rcon table
+ */
+
+/*
+ * OpenSolaris OS modifications
+ *
+ * 1. Added __cplusplus and _AESTAB_H header guards
+ * 2. Added header file sys/types.h
+ * 3. Remove code defined for _MSC_VER
+ * 4. Changed all variables to "static const"
+ * 5. Changed uint_8t and uint_32t to uint8_t and uint32_t
+ * 6. Cstyled and hdrchk code
+ */
+
+#ifndef _AESTAB_H
+#define        _AESTAB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define        t_dec(m, n) t_##m##n
+#define        t_set(m, n) t_##m##n
+#define        t_use(m, n) t_##m##n
+
+#if defined(DO_TABLES) && defined(FIXED_TABLES)
+#define        d_1(t, n, b, e)          static const t n[256]    =   b(e)
+#define        d_4(t, n, b, e, f, g, h) static const t n[4][256] = \
+                                       {b(e), b(f), b(g), b(h)}
+static const uint32_t t_dec(r, c)[RC_LENGTH] = rc_data(w0);
+#else
+#define        d_1(t, n, b, e)                 static const t n[256]
+#define        d_4(t, n, b, e, f, g, h)        static const t n[4][256]
+static const uint32_t t_dec(r, c)[RC_LENGTH];
+#endif
+
+#if defined(SBX_SET)
+       d_1(uint8_t, t_dec(s, box), sb_data, h0);
+#endif
+#if defined(ISB_SET)
+       d_1(uint8_t, t_dec(i, box), isb_data, h0);
+#endif
+
+#if defined(FT1_SET)
+       d_1(uint32_t, t_dec(f, n), sb_data, u0);
+#endif
+#if defined(FT4_SET)
+       d_4(uint32_t, t_dec(f, n), sb_data, u0, u1, u2, u3);
+#endif
+
+#if defined(FL1_SET)
+       d_1(uint32_t, t_dec(f, l), sb_data, w0);
+#endif
+#if defined(FL4_SET)
+       d_4(uint32_t, t_dec(f, l), sb_data, w0, w1, w2, w3);
+#endif
+
+#if defined(IT1_SET)
+       d_1(uint32_t, t_dec(i, n), isb_data, v0);
+#endif
+#if defined(IT4_SET)
+       d_4(uint32_t, t_dec(i, n), isb_data, v0, v1, v2, v3);
+#endif
+
+#if defined(IL1_SET)
+       d_1(uint32_t, t_dec(i, l), isb_data, w0);
+#endif
+#if defined(IL4_SET)
+       d_4(uint32_t, t_dec(i, l), isb_data, w0, w1, w2, w3);
+#endif
+
+#if defined(LS1_SET)
+#if defined(FL1_SET)
+#undef  LS1_SET
+#else
+       d_1(uint32_t, t_dec(l, s), sb_data, w0);
+#endif
+#endif
+
+#if defined(LS4_SET)
+#if defined(FL4_SET)
+#undef  LS4_SET
+#else
+       d_4(uint32_t, t_dec(l, s), sb_data, w0, w1, w2, w3);
+#endif
+#endif
+
+#if defined(IM1_SET)
+       d_1(uint32_t, t_dec(i, m), mm_data, v0);
+#endif
+#if defined(IM4_SET)
+       d_4(uint32_t, t_dec(i, m), mm_data, v0, v1, v2, v3);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AESTAB_H */
diff --git a/zfs/module/icp/asm-x86_64/aes/aestab2.h b/zfs/module/icp/asm-x86_64/aes/aestab2.h
new file mode 100644 (file)
index 0000000..eb13f72
--- /dev/null
@@ -0,0 +1,594 @@
+/*
+ * 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.
+ */
+
+#ifndef _AESTAB2_H
+#define        _AESTAB2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * To create this file for OpenSolaris:
+ * 1. Compile and run tablegen.c, from aes-src-04-03-08.zip,
+ *     after defining ASM_AMD64_C
+ * 2. mv aestab2.c aestab2.h
+ * 3. Add __cplusplus and _AESTAB2_H header guards
+ * 3. Add #include <aes_impl.h>
+ * 4. Change "uint_32t" to "uint32_t"
+ * 5. Change all variables to "static const"
+ * 6. Cstyle and hdrchk this file
+ */
+
+#include <aes/aes_impl.h>
+
+static const uint32_t t_rc[RC_LENGTH] =
+{
+       0x00000001, 0x00000002, 0x00000004, 0x00000008,
+       0x00000010, 0x00000020, 0x00000040, 0x00000080,
+       0x0000001b, 0x00000036
+};
+
+static const uint32_t t_ls[4][256] =
+{
+       {
+       0x00000063, 0x0000007c, 0x00000077, 0x0000007b,
+       0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5,
+       0x00000030, 0x00000001, 0x00000067, 0x0000002b,
+       0x000000fe, 0x000000d7, 0x000000ab, 0x00000076,
+       0x000000ca, 0x00000082, 0x000000c9, 0x0000007d,
+       0x000000fa, 0x00000059, 0x00000047, 0x000000f0,
+       0x000000ad, 0x000000d4, 0x000000a2, 0x000000af,
+       0x0000009c, 0x000000a4, 0x00000072, 0x000000c0,
+       0x000000b7, 0x000000fd, 0x00000093, 0x00000026,
+       0x00000036, 0x0000003f, 0x000000f7, 0x000000cc,
+       0x00000034, 0x000000a5, 0x000000e5, 0x000000f1,
+       0x00000071, 0x000000d8, 0x00000031, 0x00000015,
+       0x00000004, 0x000000c7, 0x00000023, 0x000000c3,
+       0x00000018, 0x00000096, 0x00000005, 0x0000009a,
+       0x00000007, 0x00000012, 0x00000080, 0x000000e2,
+       0x000000eb, 0x00000027, 0x000000b2, 0x00000075,
+       0x00000009, 0x00000083, 0x0000002c, 0x0000001a,
+       0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0,
+       0x00000052, 0x0000003b, 0x000000d6, 0x000000b3,
+       0x00000029, 0x000000e3, 0x0000002f, 0x00000084,
+       0x00000053, 0x000000d1, 0x00000000, 0x000000ed,
+       0x00000020, 0x000000fc, 0x000000b1, 0x0000005b,
+       0x0000006a, 0x000000cb, 0x000000be, 0x00000039,
+       0x0000004a, 0x0000004c, 0x00000058, 0x000000cf,
+       0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb,
+       0x00000043, 0x0000004d, 0x00000033, 0x00000085,
+       0x00000045, 0x000000f9, 0x00000002, 0x0000007f,
+       0x00000050, 0x0000003c, 0x0000009f, 0x000000a8,
+       0x00000051, 0x000000a3, 0x00000040, 0x0000008f,
+       0x00000092, 0x0000009d, 0x00000038, 0x000000f5,
+       0x000000bc, 0x000000b6, 0x000000da, 0x00000021,
+       0x00000010, 0x000000ff, 0x000000f3, 0x000000d2,
+       0x000000cd, 0x0000000c, 0x00000013, 0x000000ec,
+       0x0000005f, 0x00000097, 0x00000044, 0x00000017,
+       0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d,
+       0x00000064, 0x0000005d, 0x00000019, 0x00000073,
+       0x00000060, 0x00000081, 0x0000004f, 0x000000dc,
+       0x00000022, 0x0000002a, 0x00000090, 0x00000088,
+       0x00000046, 0x000000ee, 0x000000b8, 0x00000014,
+       0x000000de, 0x0000005e, 0x0000000b, 0x000000db,
+       0x000000e0, 0x00000032, 0x0000003a, 0x0000000a,
+       0x00000049, 0x00000006, 0x00000024, 0x0000005c,
+       0x000000c2, 0x000000d3, 0x000000ac, 0x00000062,
+       0x00000091, 0x00000095, 0x000000e4, 0x00000079,
+       0x000000e7, 0x000000c8, 0x00000037, 0x0000006d,
+       0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9,
+       0x0000006c, 0x00000056, 0x000000f4, 0x000000ea,
+       0x00000065, 0x0000007a, 0x000000ae, 0x00000008,
+       0x000000ba, 0x00000078, 0x00000025, 0x0000002e,
+       0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6,
+       0x000000e8, 0x000000dd, 0x00000074, 0x0000001f,
+       0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a,
+       0x00000070, 0x0000003e, 0x000000b5, 0x00000066,
+       0x00000048, 0x00000003, 0x000000f6, 0x0000000e,
+       0x00000061, 0x00000035, 0x00000057, 0x000000b9,
+       0x00000086, 0x000000c1, 0x0000001d, 0x0000009e,
+       0x000000e1, 0x000000f8, 0x00000098, 0x00000011,
+       0x00000069, 0x000000d9, 0x0000008e, 0x00000094,
+       0x0000009b, 0x0000001e, 0x00000087, 0x000000e9,
+       0x000000ce, 0x00000055, 0x00000028, 0x000000df,
+       0x0000008c, 0x000000a1, 0x00000089, 0x0000000d,
+       0x000000bf, 0x000000e6, 0x00000042, 0x00000068,
+       0x00000041, 0x00000099, 0x0000002d, 0x0000000f,
+       0x000000b0, 0x00000054, 0x000000bb, 0x00000016
+       },
+       {
+       0x00006300, 0x00007c00, 0x00007700, 0x00007b00,
+       0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500,
+       0x00003000, 0x00000100, 0x00006700, 0x00002b00,
+       0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600,
+       0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00,
+       0x0000fa00, 0x00005900, 0x00004700, 0x0000f000,
+       0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00,
+       0x00009c00, 0x0000a400, 0x00007200, 0x0000c000,
+       0x0000b700, 0x0000fd00, 0x00009300, 0x00002600,
+       0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00,
+       0x00003400, 0x0000a500, 0x0000e500, 0x0000f100,
+       0x00007100, 0x0000d800, 0x00003100, 0x00001500,
+       0x00000400, 0x0000c700, 0x00002300, 0x0000c300,
+       0x00001800, 0x00009600, 0x00000500, 0x00009a00,
+       0x00000700, 0x00001200, 0x00008000, 0x0000e200,
+       0x0000eb00, 0x00002700, 0x0000b200, 0x00007500,
+       0x00000900, 0x00008300, 0x00002c00, 0x00001a00,
+       0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000,
+       0x00005200, 0x00003b00, 0x0000d600, 0x0000b300,
+       0x00002900, 0x0000e300, 0x00002f00, 0x00008400,
+       0x00005300, 0x0000d100, 0x00000000, 0x0000ed00,
+       0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00,
+       0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900,
+       0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00,
+       0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00,
+       0x00004300, 0x00004d00, 0x00003300, 0x00008500,
+       0x00004500, 0x0000f900, 0x00000200, 0x00007f00,
+       0x00005000, 0x00003c00, 0x00009f00, 0x0000a800,
+       0x00005100, 0x0000a300, 0x00004000, 0x00008f00,
+       0x00009200, 0x00009d00, 0x00003800, 0x0000f500,
+       0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100,
+       0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200,
+       0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00,
+       0x00005f00, 0x00009700, 0x00004400, 0x00001700,
+       0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00,
+       0x00006400, 0x00005d00, 0x00001900, 0x00007300,
+       0x00006000, 0x00008100, 0x00004f00, 0x0000dc00,
+       0x00002200, 0x00002a00, 0x00009000, 0x00008800,
+       0x00004600, 0x0000ee00, 0x0000b800, 0x00001400,
+       0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00,
+       0x0000e000, 0x00003200, 0x00003a00, 0x00000a00,
+       0x00004900, 0x00000600, 0x00002400, 0x00005c00,
+       0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200,
+       0x00009100, 0x00009500, 0x0000e400, 0x00007900,
+       0x0000e700, 0x0000c800, 0x00003700, 0x00006d00,
+       0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900,
+       0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00,
+       0x00006500, 0x00007a00, 0x0000ae00, 0x00000800,
+       0x0000ba00, 0x00007800, 0x00002500, 0x00002e00,
+       0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600,
+       0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00,
+       0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00,
+       0x00007000, 0x00003e00, 0x0000b500, 0x00006600,
+       0x00004800, 0x00000300, 0x0000f600, 0x00000e00,
+       0x00006100, 0x00003500, 0x00005700, 0x0000b900,
+       0x00008600, 0x0000c100, 0x00001d00, 0x00009e00,
+       0x0000e100, 0x0000f800, 0x00009800, 0x00001100,
+       0x00006900, 0x0000d900, 0x00008e00, 0x00009400,
+       0x00009b00, 0x00001e00, 0x00008700, 0x0000e900,
+       0x0000ce00, 0x00005500, 0x00002800, 0x0000df00,
+       0x00008c00, 0x0000a100, 0x00008900, 0x00000d00,
+       0x0000bf00, 0x0000e600, 0x00004200, 0x00006800,
+       0x00004100, 0x00009900, 0x00002d00, 0x00000f00,
+       0x0000b000, 0x00005400, 0x0000bb00, 0x00001600
+       },
+       {
+       0x00630000, 0x007c0000, 0x00770000, 0x007b0000,
+       0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000,
+       0x00300000, 0x00010000, 0x00670000, 0x002b0000,
+       0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000,
+       0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000,
+       0x00fa0000, 0x00590000, 0x00470000, 0x00f00000,
+       0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000,
+       0x009c0000, 0x00a40000, 0x00720000, 0x00c00000,
+       0x00b70000, 0x00fd0000, 0x00930000, 0x00260000,
+       0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000,
+       0x00340000, 0x00a50000, 0x00e50000, 0x00f10000,
+       0x00710000, 0x00d80000, 0x00310000, 0x00150000,
+       0x00040000, 0x00c70000, 0x00230000, 0x00c30000,
+       0x00180000, 0x00960000, 0x00050000, 0x009a0000,
+       0x00070000, 0x00120000, 0x00800000, 0x00e20000,
+       0x00eb0000, 0x00270000, 0x00b20000, 0x00750000,
+       0x00090000, 0x00830000, 0x002c0000, 0x001a0000,
+       0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000,
+       0x00520000, 0x003b0000, 0x00d60000, 0x00b30000,
+       0x00290000, 0x00e30000, 0x002f0000, 0x00840000,
+       0x00530000, 0x00d10000, 0x00000000, 0x00ed0000,
+       0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000,
+       0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000,
+       0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000,
+       0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000,
+       0x00430000, 0x004d0000, 0x00330000, 0x00850000,
+       0x00450000, 0x00f90000, 0x00020000, 0x007f0000,
+       0x00500000, 0x003c0000, 0x009f0000, 0x00a80000,
+       0x00510000, 0x00a30000, 0x00400000, 0x008f0000,
+       0x00920000, 0x009d0000, 0x00380000, 0x00f50000,
+       0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000,
+       0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000,
+       0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000,
+       0x005f0000, 0x00970000, 0x00440000, 0x00170000,
+       0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000,
+       0x00640000, 0x005d0000, 0x00190000, 0x00730000,
+       0x00600000, 0x00810000, 0x004f0000, 0x00dc0000,
+       0x00220000, 0x002a0000, 0x00900000, 0x00880000,
+       0x00460000, 0x00ee0000, 0x00b80000, 0x00140000,
+       0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000,
+       0x00e00000, 0x00320000, 0x003a0000, 0x000a0000,
+       0x00490000, 0x00060000, 0x00240000, 0x005c0000,
+       0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000,
+       0x00910000, 0x00950000, 0x00e40000, 0x00790000,
+       0x00e70000, 0x00c80000, 0x00370000, 0x006d0000,
+       0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000,
+       0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000,
+       0x00650000, 0x007a0000, 0x00ae0000, 0x00080000,
+       0x00ba0000, 0x00780000, 0x00250000, 0x002e0000,
+       0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000,
+       0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000,
+       0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000,
+       0x00700000, 0x003e0000, 0x00b50000, 0x00660000,
+       0x00480000, 0x00030000, 0x00f60000, 0x000e0000,
+       0x00610000, 0x00350000, 0x00570000, 0x00b90000,
+       0x00860000, 0x00c10000, 0x001d0000, 0x009e0000,
+       0x00e10000, 0x00f80000, 0x00980000, 0x00110000,
+       0x00690000, 0x00d90000, 0x008e0000, 0x00940000,
+       0x009b0000, 0x001e0000, 0x00870000, 0x00e90000,
+       0x00ce0000, 0x00550000, 0x00280000, 0x00df0000,
+       0x008c0000, 0x00a10000, 0x00890000, 0x000d0000,
+       0x00bf0000, 0x00e60000, 0x00420000, 0x00680000,
+       0x00410000, 0x00990000, 0x002d0000, 0x000f0000,
+       0x00b00000, 0x00540000, 0x00bb0000, 0x00160000
+       },
+       {
+       0x63000000, 0x7c000000, 0x77000000, 0x7b000000,
+       0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000,
+       0x30000000, 0x01000000, 0x67000000, 0x2b000000,
+       0xfe000000, 0xd7000000, 0xab000000, 0x76000000,
+       0xca000000, 0x82000000, 0xc9000000, 0x7d000000,
+       0xfa000000, 0x59000000, 0x47000000, 0xf0000000,
+       0xad000000, 0xd4000000, 0xa2000000, 0xaf000000,
+       0x9c000000, 0xa4000000, 0x72000000, 0xc0000000,
+       0xb7000000, 0xfd000000, 0x93000000, 0x26000000,
+       0x36000000, 0x3f000000, 0xf7000000, 0xcc000000,
+       0x34000000, 0xa5000000, 0xe5000000, 0xf1000000,
+       0x71000000, 0xd8000000, 0x31000000, 0x15000000,
+       0x04000000, 0xc7000000, 0x23000000, 0xc3000000,
+       0x18000000, 0x96000000, 0x05000000, 0x9a000000,
+       0x07000000, 0x12000000, 0x80000000, 0xe2000000,
+       0xeb000000, 0x27000000, 0xb2000000, 0x75000000,
+       0x09000000, 0x83000000, 0x2c000000, 0x1a000000,
+       0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000,
+       0x52000000, 0x3b000000, 0xd6000000, 0xb3000000,
+       0x29000000, 0xe3000000, 0x2f000000, 0x84000000,
+       0x53000000, 0xd1000000, 0x00000000, 0xed000000,
+       0x20000000, 0xfc000000, 0xb1000000, 0x5b000000,
+       0x6a000000, 0xcb000000, 0xbe000000, 0x39000000,
+       0x4a000000, 0x4c000000, 0x58000000, 0xcf000000,
+       0xd0000000, 0xef000000, 0xaa000000, 0xfb000000,
+       0x43000000, 0x4d000000, 0x33000000, 0x85000000,
+       0x45000000, 0xf9000000, 0x02000000, 0x7f000000,
+       0x50000000, 0x3c000000, 0x9f000000, 0xa8000000,
+       0x51000000, 0xa3000000, 0x40000000, 0x8f000000,
+       0x92000000, 0x9d000000, 0x38000000, 0xf5000000,
+       0xbc000000, 0xb6000000, 0xda000000, 0x21000000,
+       0x10000000, 0xff000000, 0xf3000000, 0xd2000000,
+       0xcd000000, 0x0c000000, 0x13000000, 0xec000000,
+       0x5f000000, 0x97000000, 0x44000000, 0x17000000,
+       0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000,
+       0x64000000, 0x5d000000, 0x19000000, 0x73000000,
+       0x60000000, 0x81000000, 0x4f000000, 0xdc000000,
+       0x22000000, 0x2a000000, 0x90000000, 0x88000000,
+       0x46000000, 0xee000000, 0xb8000000, 0x14000000,
+       0xde000000, 0x5e000000, 0x0b000000, 0xdb000000,
+       0xe0000000, 0x32000000, 0x3a000000, 0x0a000000,
+       0x49000000, 0x06000000, 0x24000000, 0x5c000000,
+       0xc2000000, 0xd3000000, 0xac000000, 0x62000000,
+       0x91000000, 0x95000000, 0xe4000000, 0x79000000,
+       0xe7000000, 0xc8000000, 0x37000000, 0x6d000000,
+       0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000,
+       0x6c000000, 0x56000000, 0xf4000000, 0xea000000,
+       0x65000000, 0x7a000000, 0xae000000, 0x08000000,
+       0xba000000, 0x78000000, 0x25000000, 0x2e000000,
+       0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000,
+       0xe8000000, 0xdd000000, 0x74000000, 0x1f000000,
+       0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000,
+       0x70000000, 0x3e000000, 0xb5000000, 0x66000000,
+       0x48000000, 0x03000000, 0xf6000000, 0x0e000000,
+       0x61000000, 0x35000000, 0x57000000, 0xb9000000,
+       0x86000000, 0xc1000000, 0x1d000000, 0x9e000000,
+       0xe1000000, 0xf8000000, 0x98000000, 0x11000000,
+       0x69000000, 0xd9000000, 0x8e000000, 0x94000000,
+       0x9b000000, 0x1e000000, 0x87000000, 0xe9000000,
+       0xce000000, 0x55000000, 0x28000000, 0xdf000000,
+       0x8c000000, 0xa1000000, 0x89000000, 0x0d000000,
+       0xbf000000, 0xe6000000, 0x42000000, 0x68000000,
+       0x41000000, 0x99000000, 0x2d000000, 0x0f000000,
+       0xb0000000, 0x54000000, 0xbb000000, 0x16000000
+       }
+};
+
+static const uint32_t t_im[4][256] =
+{
+       {
+       0x00000000, 0x0b0d090e, 0x161a121c, 0x1d171b12,
+       0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a,
+       0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362,
+       0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a,
+       0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2,
+       0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca,
+       0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382,
+       0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba,
+       0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9,
+       0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1,
+       0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9,
+       0x0fe75793, 0x04ea5e9d, 0x19fd458f, 0x12f04c81,
+       0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029,
+       0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411,
+       0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859,
+       0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61,
+       0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf,
+       0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987,
+       0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf,
+       0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7,
+       0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f,
+       0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967,
+       0x1ed5ae3d, 0x15d8a733, 0x08cfbc21, 0x03c2b52f,
+       0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117,
+       0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664,
+       0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c,
+       0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14,
+       0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c,
+       0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684,
+       0x1132f9ae, 0x1a3ff0a0, 0x0728ebb2, 0x0c25e2bc,
+       0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4,
+       0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc,
+       0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753,
+       0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b,
+       0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23,
+       0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b,
+       0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3,
+       0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b,
+       0x1f6234d1, 0x146f3ddf, 0x097826cd, 0x02752fc3,
+       0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb,
+       0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88,
+       0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0,
+       0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8,
+       0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0,
+       0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68,
+       0x10856342, 0x1b886a4c, 0x069f715e, 0x0d927850,
+       0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418,
+       0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020,
+       0x01b79aec, 0x0aba93e2, 0x17ad88f0, 0x1ca081fe,
+       0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6,
+       0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e,
+       0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6,
+       0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e,
+       0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526,
+       0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e,
+       0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56,
+       0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25,
+       0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d,
+       0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255,
+       0x0e50cd7f, 0x055dc471, 0x184adf63, 0x1347d66d,
+       0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5,
+       0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd,
+       0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5,
+       0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d
+       },
+       {
+       0x00000000, 0x0d090e0b, 0x1a121c16, 0x171b121d,
+       0x3424382c, 0x392d3627, 0x2e36243a, 0x233f2a31,
+       0x68487058, 0x65417e53, 0x725a6c4e, 0x7f536245,
+       0x5c6c4874, 0x5165467f, 0x467e5462, 0x4b775a69,
+       0xd090e0b0, 0xdd99eebb, 0xca82fca6, 0xc78bf2ad,
+       0xe4b4d89c, 0xe9bdd697, 0xfea6c48a, 0xf3afca81,
+       0xb8d890e8, 0xb5d19ee3, 0xa2ca8cfe, 0xafc382f5,
+       0x8cfca8c4, 0x81f5a6cf, 0x96eeb4d2, 0x9be7bad9,
+       0xbb3bdb7b, 0xb632d570, 0xa129c76d, 0xac20c966,
+       0x8f1fe357, 0x8216ed5c, 0x950dff41, 0x9804f14a,
+       0xd373ab23, 0xde7aa528, 0xc961b735, 0xc468b93e,
+       0xe757930f, 0xea5e9d04, 0xfd458f19, 0xf04c8112,
+       0x6bab3bcb, 0x66a235c0, 0x71b927dd, 0x7cb029d6,
+       0x5f8f03e7, 0x52860dec, 0x459d1ff1, 0x489411fa,
+       0x03e34b93, 0x0eea4598, 0x19f15785, 0x14f8598e,
+       0x37c773bf, 0x3ace7db4, 0x2dd56fa9, 0x20dc61a2,
+       0x6d76adf6, 0x607fa3fd, 0x7764b1e0, 0x7a6dbfeb,
+       0x595295da, 0x545b9bd1, 0x434089cc, 0x4e4987c7,
+       0x053eddae, 0x0837d3a5, 0x1f2cc1b8, 0x1225cfb3,
+       0x311ae582, 0x3c13eb89, 0x2b08f994, 0x2601f79f,
+       0xbde64d46, 0xb0ef434d, 0xa7f45150, 0xaafd5f5b,
+       0x89c2756a, 0x84cb7b61, 0x93d0697c, 0x9ed96777,
+       0xd5ae3d1e, 0xd8a73315, 0xcfbc2108, 0xc2b52f03,
+       0xe18a0532, 0xec830b39, 0xfb981924, 0xf691172f,
+       0xd64d768d, 0xdb447886, 0xcc5f6a9b, 0xc1566490,
+       0xe2694ea1, 0xef6040aa, 0xf87b52b7, 0xf5725cbc,
+       0xbe0506d5, 0xb30c08de, 0xa4171ac3, 0xa91e14c8,
+       0x8a213ef9, 0x872830f2, 0x903322ef, 0x9d3a2ce4,
+       0x06dd963d, 0x0bd49836, 0x1ccf8a2b, 0x11c68420,
+       0x32f9ae11, 0x3ff0a01a, 0x28ebb207, 0x25e2bc0c,
+       0x6e95e665, 0x639ce86e, 0x7487fa73, 0x798ef478,
+       0x5ab1de49, 0x57b8d042, 0x40a3c25f, 0x4daacc54,
+       0xdaec41f7, 0xd7e54ffc, 0xc0fe5de1, 0xcdf753ea,
+       0xeec879db, 0xe3c177d0, 0xf4da65cd, 0xf9d36bc6,
+       0xb2a431af, 0xbfad3fa4, 0xa8b62db9, 0xa5bf23b2,
+       0x86800983, 0x8b890788, 0x9c921595, 0x919b1b9e,
+       0x0a7ca147, 0x0775af4c, 0x106ebd51, 0x1d67b35a,
+       0x3e58996b, 0x33519760, 0x244a857d, 0x29438b76,
+       0x6234d11f, 0x6f3ddf14, 0x7826cd09, 0x752fc302,
+       0x5610e933, 0x5b19e738, 0x4c02f525, 0x410bfb2e,
+       0x61d79a8c, 0x6cde9487, 0x7bc5869a, 0x76cc8891,
+       0x55f3a2a0, 0x58faacab, 0x4fe1beb6, 0x42e8b0bd,
+       0x099fead4, 0x0496e4df, 0x138df6c2, 0x1e84f8c9,
+       0x3dbbd2f8, 0x30b2dcf3, 0x27a9ceee, 0x2aa0c0e5,
+       0xb1477a3c, 0xbc4e7437, 0xab55662a, 0xa65c6821,
+       0x85634210, 0x886a4c1b, 0x9f715e06, 0x9278500d,
+       0xd90f0a64, 0xd406046f, 0xc31d1672, 0xce141879,
+       0xed2b3248, 0xe0223c43, 0xf7392e5e, 0xfa302055,
+       0xb79aec01, 0xba93e20a, 0xad88f017, 0xa081fe1c,
+       0x83bed42d, 0x8eb7da26, 0x99acc83b, 0x94a5c630,
+       0xdfd29c59, 0xd2db9252, 0xc5c0804f, 0xc8c98e44,
+       0xebf6a475, 0xe6ffaa7e, 0xf1e4b863, 0xfcedb668,
+       0x670a0cb1, 0x6a0302ba, 0x7d1810a7, 0x70111eac,
+       0x532e349d, 0x5e273a96, 0x493c288b, 0x44352680,
+       0x0f427ce9, 0x024b72e2, 0x155060ff, 0x18596ef4,
+       0x3b6644c5, 0x366f4ace, 0x217458d3, 0x2c7d56d8,
+       0x0ca1377a, 0x01a83971, 0x16b32b6c, 0x1bba2567,
+       0x38850f56, 0x358c015d, 0x22971340, 0x2f9e1d4b,
+       0x64e94722, 0x69e04929, 0x7efb5b34, 0x73f2553f,
+       0x50cd7f0e, 0x5dc47105, 0x4adf6318, 0x47d66d13,
+       0xdc31d7ca, 0xd138d9c1, 0xc623cbdc, 0xcb2ac5d7,
+       0xe815efe6, 0xe51ce1ed, 0xf207f3f0, 0xff0efdfb,
+       0xb479a792, 0xb970a999, 0xae6bbb84, 0xa362b58f,
+       0x805d9fbe, 0x8d5491b5, 0x9a4f83a8, 0x97468da3
+       },
+       {
+       0x00000000, 0x090e0b0d, 0x121c161a, 0x1b121d17,
+       0x24382c34, 0x2d362739, 0x36243a2e, 0x3f2a3123,
+       0x48705868, 0x417e5365, 0x5a6c4e72, 0x5362457f,
+       0x6c48745c, 0x65467f51, 0x7e546246, 0x775a694b,
+       0x90e0b0d0, 0x99eebbdd, 0x82fca6ca, 0x8bf2adc7,
+       0xb4d89ce4, 0xbdd697e9, 0xa6c48afe, 0xafca81f3,
+       0xd890e8b8, 0xd19ee3b5, 0xca8cfea2, 0xc382f5af,
+       0xfca8c48c, 0xf5a6cf81, 0xeeb4d296, 0xe7bad99b,
+       0x3bdb7bbb, 0x32d570b6, 0x29c76da1, 0x20c966ac,
+       0x1fe3578f, 0x16ed5c82, 0x0dff4195, 0x04f14a98,
+       0x73ab23d3, 0x7aa528de, 0x61b735c9, 0x68b93ec4,
+       0x57930fe7, 0x5e9d04ea, 0x458f19fd, 0x4c8112f0,
+       0xab3bcb6b, 0xa235c066, 0xb927dd71, 0xb029d67c,
+       0x8f03e75f, 0x860dec52, 0x9d1ff145, 0x9411fa48,
+       0xe34b9303, 0xea45980e, 0xf1578519, 0xf8598e14,
+       0xc773bf37, 0xce7db43a, 0xd56fa92d, 0xdc61a220,
+       0x76adf66d, 0x7fa3fd60, 0x64b1e077, 0x6dbfeb7a,
+       0x5295da59, 0x5b9bd154, 0x4089cc43, 0x4987c74e,
+       0x3eddae05, 0x37d3a508, 0x2cc1b81f, 0x25cfb312,
+       0x1ae58231, 0x13eb893c, 0x08f9942b, 0x01f79f26,
+       0xe64d46bd, 0xef434db0, 0xf45150a7, 0xfd5f5baa,
+       0xc2756a89, 0xcb7b6184, 0xd0697c93, 0xd967779e,
+       0xae3d1ed5, 0xa73315d8, 0xbc2108cf, 0xb52f03c2,
+       0x8a0532e1, 0x830b39ec, 0x981924fb, 0x91172ff6,
+       0x4d768dd6, 0x447886db, 0x5f6a9bcc, 0x566490c1,
+       0x694ea1e2, 0x6040aaef, 0x7b52b7f8, 0x725cbcf5,
+       0x0506d5be, 0x0c08deb3, 0x171ac3a4, 0x1e14c8a9,
+       0x213ef98a, 0x2830f287, 0x3322ef90, 0x3a2ce49d,
+       0xdd963d06, 0xd498360b, 0xcf8a2b1c, 0xc6842011,
+       0xf9ae1132, 0xf0a01a3f, 0xebb20728, 0xe2bc0c25,
+       0x95e6656e, 0x9ce86e63, 0x87fa7374, 0x8ef47879,
+       0xb1de495a, 0xb8d04257, 0xa3c25f40, 0xaacc544d,
+       0xec41f7da, 0xe54ffcd7, 0xfe5de1c0, 0xf753eacd,
+       0xc879dbee, 0xc177d0e3, 0xda65cdf4, 0xd36bc6f9,
+       0xa431afb2, 0xad3fa4bf, 0xb62db9a8, 0xbf23b2a5,
+       0x80098386, 0x8907888b, 0x9215959c, 0x9b1b9e91,
+       0x7ca1470a, 0x75af4c07, 0x6ebd5110, 0x67b35a1d,
+       0x58996b3e, 0x51976033, 0x4a857d24, 0x438b7629,
+       0x34d11f62, 0x3ddf146f, 0x26cd0978, 0x2fc30275,
+       0x10e93356, 0x19e7385b, 0x02f5254c, 0x0bfb2e41,
+       0xd79a8c61, 0xde94876c, 0xc5869a7b, 0xcc889176,
+       0xf3a2a055, 0xfaacab58, 0xe1beb64f, 0xe8b0bd42,
+       0x9fead409, 0x96e4df04, 0x8df6c213, 0x84f8c91e,
+       0xbbd2f83d, 0xb2dcf330, 0xa9ceee27, 0xa0c0e52a,
+       0x477a3cb1, 0x4e7437bc, 0x55662aab, 0x5c6821a6,
+       0x63421085, 0x6a4c1b88, 0x715e069f, 0x78500d92,
+       0x0f0a64d9, 0x06046fd4, 0x1d1672c3, 0x141879ce,
+       0x2b3248ed, 0x223c43e0, 0x392e5ef7, 0x302055fa,
+       0x9aec01b7, 0x93e20aba, 0x88f017ad, 0x81fe1ca0,
+       0xbed42d83, 0xb7da268e, 0xacc83b99, 0xa5c63094,
+       0xd29c59df, 0xdb9252d2, 0xc0804fc5, 0xc98e44c8,
+       0xf6a475eb, 0xffaa7ee6, 0xe4b863f1, 0xedb668fc,
+       0x0a0cb167, 0x0302ba6a, 0x1810a77d, 0x111eac70,
+       0x2e349d53, 0x273a965e, 0x3c288b49, 0x35268044,
+       0x427ce90f, 0x4b72e202, 0x5060ff15, 0x596ef418,
+       0x6644c53b, 0x6f4ace36, 0x7458d321, 0x7d56d82c,
+       0xa1377a0c, 0xa8397101, 0xb32b6c16, 0xba25671b,
+       0x850f5638, 0x8c015d35, 0x97134022, 0x9e1d4b2f,
+       0xe9472264, 0xe0492969, 0xfb5b347e, 0xf2553f73,
+       0xcd7f0e50, 0xc471055d, 0xdf63184a, 0xd66d1347,
+       0x31d7cadc, 0x38d9c1d1, 0x23cbdcc6, 0x2ac5d7cb,
+       0x15efe6e8, 0x1ce1ede5, 0x07f3f0f2, 0x0efdfbff,
+       0x79a792b4, 0x70a999b9, 0x6bbb84ae, 0x62b58fa3,
+       0x5d9fbe80, 0x5491b58d, 0x4f83a89a, 0x468da397
+       },
+       {
+       0x00000000, 0x0e0b0d09, 0x1c161a12, 0x121d171b,
+       0x382c3424, 0x3627392d, 0x243a2e36, 0x2a31233f,
+       0x70586848, 0x7e536541, 0x6c4e725a, 0x62457f53,
+       0x48745c6c, 0x467f5165, 0x5462467e, 0x5a694b77,
+       0xe0b0d090, 0xeebbdd99, 0xfca6ca82, 0xf2adc78b,
+       0xd89ce4b4, 0xd697e9bd, 0xc48afea6, 0xca81f3af,
+       0x90e8b8d8, 0x9ee3b5d1, 0x8cfea2ca, 0x82f5afc3,
+       0xa8c48cfc, 0xa6cf81f5, 0xb4d296ee, 0xbad99be7,
+       0xdb7bbb3b, 0xd570b632, 0xc76da129, 0xc966ac20,
+       0xe3578f1f, 0xed5c8216, 0xff41950d, 0xf14a9804,
+       0xab23d373, 0xa528de7a, 0xb735c961, 0xb93ec468,
+       0x930fe757, 0x9d04ea5e, 0x8f19fd45, 0x8112f04c,
+       0x3bcb6bab, 0x35c066a2, 0x27dd71b9, 0x29d67cb0,
+       0x03e75f8f, 0x0dec5286, 0x1ff1459d, 0x11fa4894,
+       0x4b9303e3, 0x45980eea, 0x578519f1, 0x598e14f8,
+       0x73bf37c7, 0x7db43ace, 0x6fa92dd5, 0x61a220dc,
+       0xadf66d76, 0xa3fd607f, 0xb1e07764, 0xbfeb7a6d,
+       0x95da5952, 0x9bd1545b, 0x89cc4340, 0x87c74e49,
+       0xddae053e, 0xd3a50837, 0xc1b81f2c, 0xcfb31225,
+       0xe582311a, 0xeb893c13, 0xf9942b08, 0xf79f2601,
+       0x4d46bde6, 0x434db0ef, 0x5150a7f4, 0x5f5baafd,
+       0x756a89c2, 0x7b6184cb, 0x697c93d0, 0x67779ed9,
+       0x3d1ed5ae, 0x3315d8a7, 0x2108cfbc, 0x2f03c2b5,
+       0x0532e18a, 0x0b39ec83, 0x1924fb98, 0x172ff691,
+       0x768dd64d, 0x7886db44, 0x6a9bcc5f, 0x6490c156,
+       0x4ea1e269, 0x40aaef60, 0x52b7f87b, 0x5cbcf572,
+       0x06d5be05, 0x08deb30c, 0x1ac3a417, 0x14c8a91e,
+       0x3ef98a21, 0x30f28728, 0x22ef9033, 0x2ce49d3a,
+       0x963d06dd, 0x98360bd4, 0x8a2b1ccf, 0x842011c6,
+       0xae1132f9, 0xa01a3ff0, 0xb20728eb, 0xbc0c25e2,
+       0xe6656e95, 0xe86e639c, 0xfa737487, 0xf478798e,
+       0xde495ab1, 0xd04257b8, 0xc25f40a3, 0xcc544daa,
+       0x41f7daec, 0x4ffcd7e5, 0x5de1c0fe, 0x53eacdf7,
+       0x79dbeec8, 0x77d0e3c1, 0x65cdf4da, 0x6bc6f9d3,
+       0x31afb2a4, 0x3fa4bfad, 0x2db9a8b6, 0x23b2a5bf,
+       0x09838680, 0x07888b89, 0x15959c92, 0x1b9e919b,
+       0xa1470a7c, 0xaf4c0775, 0xbd51106e, 0xb35a1d67,
+       0x996b3e58, 0x97603351, 0x857d244a, 0x8b762943,
+       0xd11f6234, 0xdf146f3d, 0xcd097826, 0xc302752f,
+       0xe9335610, 0xe7385b19, 0xf5254c02, 0xfb2e410b,
+       0x9a8c61d7, 0x94876cde, 0x869a7bc5, 0x889176cc,
+       0xa2a055f3, 0xacab58fa, 0xbeb64fe1, 0xb0bd42e8,
+       0xead4099f, 0xe4df0496, 0xf6c2138d, 0xf8c91e84,
+       0xd2f83dbb, 0xdcf330b2, 0xceee27a9, 0xc0e52aa0,
+       0x7a3cb147, 0x7437bc4e, 0x662aab55, 0x6821a65c,
+       0x42108563, 0x4c1b886a, 0x5e069f71, 0x500d9278,
+       0x0a64d90f, 0x046fd406, 0x1672c31d, 0x1879ce14,
+       0x3248ed2b, 0x3c43e022, 0x2e5ef739, 0x2055fa30,
+       0xec01b79a, 0xe20aba93, 0xf017ad88, 0xfe1ca081,
+       0xd42d83be, 0xda268eb7, 0xc83b99ac, 0xc63094a5,
+       0x9c59dfd2, 0x9252d2db, 0x804fc5c0, 0x8e44c8c9,
+       0xa475ebf6, 0xaa7ee6ff, 0xb863f1e4, 0xb668fced,
+       0x0cb1670a, 0x02ba6a03, 0x10a77d18, 0x1eac7011,
+       0x349d532e, 0x3a965e27, 0x288b493c, 0x26804435,
+       0x7ce90f42, 0x72e2024b, 0x60ff1550, 0x6ef41859,
+       0x44c53b66, 0x4ace366f, 0x58d32174, 0x56d82c7d,
+       0x377a0ca1, 0x397101a8, 0x2b6c16b3, 0x25671bba,
+       0x0f563885, 0x015d358c, 0x13402297, 0x1d4b2f9e,
+       0x472264e9, 0x492969e0, 0x5b347efb, 0x553f73f2,
+       0x7f0e50cd, 0x71055dc4, 0x63184adf, 0x6d1347d6,
+       0xd7cadc31, 0xd9c1d138, 0xcbdcc623, 0xc5d7cb2a,
+       0xefe6e815, 0xe1ede51c, 0xf3f0f207, 0xfdfbff0e,
+       0xa792b479, 0xa999b970, 0xbb84ae6b, 0xb58fa362,
+       0x9fbe805d, 0x91b58d54, 0x83a89a4f, 0x8da39746
+       }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AESTAB2_H */
diff --git a/zfs/module/icp/asm-x86_64/modes/gcm_intel.S b/zfs/module/icp/asm-x86_64/modes/gcm_intel.S
new file mode 100644 (file)
index 0000000..109f9b4
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * 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 (c) 2009 Intel Corporation
+ * All Rights Reserved.
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
+ * instructions.  This file contains an accelerated
+ * Galois Field Multiplication implementation.
+ *
+ * PCLMULQDQ is used to accelerate the most time-consuming part of GHASH,
+ * carry-less multiplication. More information about PCLMULQDQ can be
+ * found at:
+ * http://software.intel.com/en-us/articles/
+ * carry-less-multiplication-and-its-usage-for-computing-the-gcm-mode/
+ *
+ */
+
+/*
+ * ====================================================================
+ * OpenSolaris OS modifications
+ *
+ * This source originates as file galois_hash_asm.c from
+ * Intel Corporation dated September 21, 2009.
+ *
+ * This OpenSolaris version has these major changes from the original source:
+ *
+ * 1. Added OpenSolaris ENTRY_NP/SET_SIZE macros from
+ * /usr/include/sys/asm_linkage.h, lint(1B) guards, and a dummy C function
+ * definition for lint.
+ *
+ * 2. Formatted code, added comments, and added #includes and #defines.
+ *
+ * 3. If bit CR0.TS is set, clear and set the TS bit, after and before
+ * calling kpreempt_disable() and kpreempt_enable().
+ * If the TS bit is not set, Save and restore %xmm registers at the beginning
+ * and end of function calls (%xmm* registers are not saved and restored by
+ * during kernel thread preemption).
+ *
+ * 4. Removed code to perform hashing.  This is already done with C macro
+ * GHASH in gcm.c.  For better performance, this removed code should be
+ * reintegrated in the future to replace the C GHASH macro.
+ *
+ * 5. Added code to byte swap 16-byte input and output.
+ *
+ * 6. Folded in comments from the original C source with embedded assembly
+ * (SB_w_shift_xor.c)
+ *
+ * 7. Renamed function and reordered parameters to match OpenSolaris:
+ * Intel interface:
+ *     void galois_hash_asm(unsigned char *hk, unsigned char *s,
+ *             unsigned char *d, int length)
+ * OpenSolaris OS interface:
+ *     void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res);
+ * ====================================================================
+ */
+
+
+#if defined(lint) || defined(__lint)
+
+#include <sys/types.h>
+
+/* ARGSUSED */
+void
+gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res) {
+}
+
+#else  /* lint */
+
+#define _ASM
+#include <sys/asm_linkage.h>
+
+#ifdef _KERNEL
+       /*
+        * Note: the CLTS macro clobbers P2 (%rsi) under i86xpv.  That is,
+        * it calls HYPERVISOR_fpu_taskswitch() which modifies %rsi when it
+        * uses it to pass P2 to syscall.
+        * This also occurs with the STTS macro, but we dont care if
+        * P2 (%rsi) is modified just before function exit.
+        * The CLTS and STTS macros push and pop P1 (%rdi) already.
+        */
+#ifdef __xpv
+#define        PROTECTED_CLTS \
+       push    %rsi; \
+       CLTS; \
+       pop     %rsi
+#else
+#define        PROTECTED_CLTS \
+       CLTS
+#endif /* __xpv */
+
+       /*
+        * If CR0_TS is not set, align stack (with push %rbp) and push
+        * %xmm0 - %xmm10 on stack, otherwise clear CR0_TS
+        */
+#define        CLEAR_TS_OR_PUSH_XMM_REGISTERS(tmpreg) \
+       push    %rbp; \
+       mov     %rsp, %rbp; \
+       movq    %cr0, tmpreg; \
+       testq   $CR0_TS, tmpreg; \
+       jnz     1f; \
+       and     $-XMM_ALIGN, %rsp; \
+       sub     $[XMM_SIZE * 11], %rsp; \
+       movaps  %xmm0, 160(%rsp); \
+       movaps  %xmm1, 144(%rsp); \
+       movaps  %xmm2, 128(%rsp); \
+       movaps  %xmm3, 112(%rsp); \
+       movaps  %xmm4, 96(%rsp); \
+       movaps  %xmm5, 80(%rsp); \
+       movaps  %xmm6, 64(%rsp); \
+       movaps  %xmm7, 48(%rsp); \
+       movaps  %xmm8, 32(%rsp); \
+       movaps  %xmm9, 16(%rsp); \
+       movaps  %xmm10, (%rsp); \
+       jmp     2f; \
+1: \
+       PROTECTED_CLTS; \
+2:
+
+
+       /*
+        * If CR0_TS was not set above, pop %xmm0 - %xmm10 off stack,
+        * otherwise set CR0_TS.
+        */
+#define        SET_TS_OR_POP_XMM_REGISTERS(tmpreg) \
+       testq   $CR0_TS, tmpreg; \
+       jnz     1f; \
+       movaps  (%rsp), %xmm10; \
+       movaps  16(%rsp), %xmm9; \
+       movaps  32(%rsp), %xmm8; \
+       movaps  48(%rsp), %xmm7; \
+       movaps  64(%rsp), %xmm6; \
+       movaps  80(%rsp), %xmm5; \
+       movaps  96(%rsp), %xmm4; \
+       movaps  112(%rsp), %xmm3; \
+       movaps  128(%rsp), %xmm2; \
+       movaps  144(%rsp), %xmm1; \
+       movaps  160(%rsp), %xmm0; \
+       jmp     2f; \
+1: \
+       STTS(tmpreg); \
+2: \
+       mov     %rbp, %rsp; \
+       pop     %rbp
+
+
+#else
+#define        PROTECTED_CLTS
+#define        CLEAR_TS_OR_PUSH_XMM_REGISTERS(tmpreg)
+#define        SET_TS_OR_POP_XMM_REGISTERS(tmpreg)
+#endif /* _KERNEL */
+
+/*
+ * Use this mask to byte-swap a 16-byte integer with the pshufb instruction
+ */
+
+// static uint8_t byte_swap16_mask[] = {
+//      15, 14, 13, 12, 11, 10, 9, 8, 7, 6 ,5, 4, 3, 2, 1, 0 };
+.text
+.align XMM_ALIGN
+.Lbyte_swap16_mask:
+       .byte   15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+
+
+/*
+ * void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res);
+ *
+ * Perform a carry-less multiplication (that is, use XOR instead of the
+ * multiply operator) on P1 and P2 and place the result in P3.
+ *
+ * Byte swap the input and the output.
+ *
+ * Note: x_in, y, and res all point to a block of 20-byte numbers
+ * (an array of two 64-bit integers).
+ *
+ * Note2: For kernel code, caller is responsible for ensuring
+ * kpreempt_disable() has been called.  This is because %xmm registers are
+ * not saved/restored.  Clear and set the CR0.TS bit on entry and exit,
+ * respectively, if TS is set on entry.  Otherwise, if TS is not set,
+ * save and restore %xmm registers on the stack.
+ *
+ * Note3: Original Intel definition:
+ * void galois_hash_asm(unsigned char *hk, unsigned char *s,
+ *     unsigned char *d, int length)
+ *
+ * Note4: Register/parameter mapping:
+ * Intel:
+ *     Parameter 1: %rcx (copied to %xmm0)     hk or x_in
+ *     Parameter 2: %rdx (copied to %xmm1)     s or y
+ *     Parameter 3: %rdi (result)              d or res
+ * OpenSolaris:
+ *     Parameter 1: %rdi (copied to %xmm0)     x_in
+ *     Parameter 2: %rsi (copied to %xmm1)     y
+ *     Parameter 3: %rdx (result)              res
+ */
+
+ENTRY_NP(gcm_mul_pclmulqdq)
+       CLEAR_TS_OR_PUSH_XMM_REGISTERS(%r10)
+
+       //
+       // Copy Parameters
+       //
+       movdqu  (%rdi), %xmm0   // P1
+       movdqu  (%rsi), %xmm1   // P2
+
+       //
+       // Byte swap 16-byte input
+       //
+       lea     .Lbyte_swap16_mask(%rip), %rax
+       movaps  (%rax), %xmm10
+       pshufb  %xmm10, %xmm0
+       pshufb  %xmm10, %xmm1
+
+
+       //
+       // Multiply with the hash key
+       //
+       movdqu  %xmm0, %xmm3
+       pclmulqdq $0, %xmm1, %xmm3      // xmm3 holds a0*b0
+
+       movdqu  %xmm0, %xmm4
+       pclmulqdq $16, %xmm1, %xmm4     // xmm4 holds a0*b1
+
+       movdqu  %xmm0, %xmm5
+       pclmulqdq $1, %xmm1, %xmm5      // xmm5 holds a1*b0
+       movdqu  %xmm0, %xmm6
+       pclmulqdq $17, %xmm1, %xmm6     // xmm6 holds a1*b1
+
+       pxor    %xmm5, %xmm4    // xmm4 holds a0*b1 + a1*b0
+
+       movdqu  %xmm4, %xmm5    // move the contents of xmm4 to xmm5
+       psrldq  $8, %xmm4       // shift by xmm4 64 bits to the right
+       pslldq  $8, %xmm5       // shift by xmm5 64 bits to the left
+       pxor    %xmm5, %xmm3
+       pxor    %xmm4, %xmm6    // Register pair <xmm6:xmm3> holds the result
+                               // of the carry-less multiplication of
+                               // xmm0 by xmm1.
+
+       // We shift the result of the multiplication by one bit position
+       // to the left to cope for the fact that the bits are reversed.
+       movdqu  %xmm3, %xmm7
+       movdqu  %xmm6, %xmm8
+       pslld   $1, %xmm3
+       pslld   $1, %xmm6
+       psrld   $31, %xmm7
+       psrld   $31, %xmm8
+       movdqu  %xmm7, %xmm9
+       pslldq  $4, %xmm8
+       pslldq  $4, %xmm7
+       psrldq  $12, %xmm9
+       por     %xmm7, %xmm3
+       por     %xmm8, %xmm6
+       por     %xmm9, %xmm6
+
+       //
+       // First phase of the reduction
+       //
+       // Move xmm3 into xmm7, xmm8, xmm9 in order to perform the shifts
+       // independently.
+       movdqu  %xmm3, %xmm7
+       movdqu  %xmm3, %xmm8
+       movdqu  %xmm3, %xmm9
+       pslld   $31, %xmm7      // packed right shift shifting << 31
+       pslld   $30, %xmm8      // packed right shift shifting << 30
+       pslld   $25, %xmm9      // packed right shift shifting << 25
+       pxor    %xmm8, %xmm7    // xor the shifted versions
+       pxor    %xmm9, %xmm7
+       movdqu  %xmm7, %xmm8
+       pslldq  $12, %xmm7
+       psrldq  $4, %xmm8
+       pxor    %xmm7, %xmm3    // first phase of the reduction complete
+
+       //
+       // Second phase of the reduction
+       //
+       // Make 3 copies of xmm3 in xmm2, xmm4, xmm5 for doing these
+       // shift operations.
+       movdqu  %xmm3, %xmm2
+       movdqu  %xmm3, %xmm4    // packed left shifting >> 1
+       movdqu  %xmm3, %xmm5
+       psrld   $1, %xmm2
+       psrld   $2, %xmm4       // packed left shifting >> 2
+       psrld   $7, %xmm5       // packed left shifting >> 7
+       pxor    %xmm4, %xmm2    // xor the shifted versions
+       pxor    %xmm5, %xmm2
+       pxor    %xmm8, %xmm2
+       pxor    %xmm2, %xmm3
+       pxor    %xmm3, %xmm6    // the result is in xmm6
+
+       //
+       // Byte swap 16-byte result
+       //
+       pshufb  %xmm10, %xmm6   // %xmm10 has the swap mask
+
+       //
+       // Store the result
+       //
+       movdqu  %xmm6, (%rdx)   // P3
+
+
+       //
+       // Cleanup and Return
+       //
+       SET_TS_OR_POP_XMM_REGISTERS(%r10)
+       ret
+       SET_SIZE(gcm_mul_pclmulqdq)
+
+#endif /* lint || __lint */
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/zfs/module/icp/asm-x86_64/sha1/sha1-x86_64.S b/zfs/module/icp/asm-x86_64/sha1/sha1-x86_64.S
new file mode 100644 (file)
index 0000000..6fb4ac5
--- /dev/null
@@ -0,0 +1,1350 @@
+/*
+ * !/usr/bin/env perl
+ * 
+ *  ====================================================================
+ *  Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+ *  project. The module is, however, dual licensed under OpenSSL and
+ *  CRYPTOGAMS licenses depending on where you obtain it. For further
+ *  details see http://www.openssl.org/~appro/cryptogams/.
+ *  ====================================================================
+ * 
+ *  sha1_block procedure for x86_64.
+ * 
+ *  It was brought to my attention that on EM64T compiler-generated code
+ *  was far behind 32-bit assembler implementation. This is unlike on
+ *  Opteron where compiler-generated code was only 15% behind 32-bit
+ *  assembler, which originally made it hard to motivate the effort.
+ *  There was suggestion to mechanically translate 32-bit code, but I
+ *  dismissed it, reasoning that x86_64 offers enough register bank
+ *  capacity to fully utilize SHA-1 parallelism. Therefore this fresh
+ *  implementation:-) However! While 64-bit code does performs better
+ *  on Opteron, I failed to beat 32-bit assembler on EM64T core. Well,
+ *  x86_64 does offer larger *addressable* bank, but out-of-order core
+ *  reaches for even more registers through dynamic aliasing, and EM64T
+ *  core must have managed to run-time optimize even 32-bit code just as
+ *  good as 64-bit one. Performance improvement is summarized in the
+ *  following table:
+ * 
+ *             gcc 3.4         32-bit asm      cycles/byte
+ *  Opteron    +45%            +20%            6.8
+ *  Xeon P4    +65%            +0%             9.9
+ *  Core2              +60%            +10%            7.0
+ * 
+ * 
+ *  OpenSolaris OS modifications
+ * 
+ *  Sun elects to use this software under the BSD license.
+ * 
+ *  This source originates from OpenSSL file sha1-x86_64.pl at
+ *  ftp://ftp.openssl.org/snapshot/openssl-0.9.8-stable-SNAP-20080131.tar.gz
+ *  (presumably for future OpenSSL release 0.9.8h), with these changes:
+ * 
+ *  1. Added perl "use strict" and declared variables.
+ * 
+ *  2. Added OpenSolaris ENTRY_NP/SET_SIZE macros from
+ *  /usr/include/sys/asm_linkage.h, .ident keywords, and lint(1B) guards.
+ * 
+ *  3. Removed x86_64-xlate.pl script (not needed for as(1) or gas(1)
+ *  assemblers).
+ * 
+ */
+
+/*
+ * This file was generated by a perl script (sha1-x86_64.pl). The comments from
+ * the original file have been pasted above.
+ */
+
+#if defined(lint) || defined(__lint)
+#include <sys/stdint.h>
+#include <sys/sha1.h>
+
+/* ARGSUSED */
+void
+sha1_block_data_order(SHA1_CTX *ctx, const void *inpp, size_t blocks)
+{
+}
+
+#else
+#define _ASM
+#include <sys/asm_linkage.h>
+ENTRY_NP(sha1_block_data_order)
+       push    %rbx
+       push    %rbp
+       push    %r12
+       mov     %rsp,%rax
+       mov     %rdi,%r8        # reassigned argument
+       sub     $72,%rsp
+       mov     %rsi,%r9        # reassigned argument
+       and     $-64,%rsp
+       mov     %rdx,%r10       # reassigned argument
+       mov     %rax,64(%rsp)
+
+       mov     0(%r8),%edx
+       mov     4(%r8),%esi
+       mov     8(%r8),%edi
+       mov     12(%r8),%ebp
+       mov     16(%r8),%r11d
+.align 4
+.Lloop:
+       mov     0(%r9),%eax     
+       bswap   %eax
+       mov     %eax,0(%rsp)
+       lea     0x5a827999(%eax,%r11d),%r12d
+       mov     %edi,%ebx
+       mov     4(%r9),%eax
+       mov     %edx,%r11d
+       xor     %ebp,%ebx
+       bswap   %eax    
+       rol     $5,%r11d
+       and     %esi,%ebx
+       mov     %eax,4(%rsp)
+       add     %r11d,%r12d
+       xor     %ebp,%ebx
+       rol     $30,%esi
+       add     %ebx,%r12d
+       lea     0x5a827999(%eax,%ebp),%r11d
+       mov     %esi,%ebx
+       mov     8(%r9),%eax
+       mov     %r12d,%ebp
+       xor     %edi,%ebx
+       bswap   %eax    
+       rol     $5,%ebp
+       and     %edx,%ebx
+       mov     %eax,8(%rsp)
+       add     %ebp,%r11d
+       xor     %edi,%ebx
+       rol     $30,%edx
+       add     %ebx,%r11d
+       lea     0x5a827999(%eax,%edi),%ebp
+       mov     %edx,%ebx
+       mov     12(%r9),%eax
+       mov     %r11d,%edi
+       xor     %esi,%ebx
+       bswap   %eax    
+       rol     $5,%edi
+       and     %r12d,%ebx
+       mov     %eax,12(%rsp)
+       add     %edi,%ebp
+       xor     %esi,%ebx
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       lea     0x5a827999(%eax,%esi),%edi
+       mov     %r12d,%ebx
+       mov     16(%r9),%eax
+       mov     %ebp,%esi
+       xor     %edx,%ebx
+       bswap   %eax    
+       rol     $5,%esi
+       and     %r11d,%ebx
+       mov     %eax,16(%rsp)
+       add     %esi,%edi
+       xor     %edx,%ebx
+       rol     $30,%r11d
+       add     %ebx,%edi
+       lea     0x5a827999(%eax,%edx),%esi
+       mov     %r11d,%ebx
+       mov     20(%r9),%eax
+       mov     %edi,%edx
+       xor     %r12d,%ebx
+       bswap   %eax    
+       rol     $5,%edx
+       and     %ebp,%ebx
+       mov     %eax,20(%rsp)
+       add     %edx,%esi
+       xor     %r12d,%ebx
+       rol     $30,%ebp
+       add     %ebx,%esi
+       lea     0x5a827999(%eax,%r12d),%edx
+       mov     %ebp,%ebx
+       mov     24(%r9),%eax
+       mov     %esi,%r12d
+       xor     %r11d,%ebx
+       bswap   %eax    
+       rol     $5,%r12d
+       and     %edi,%ebx
+       mov     %eax,24(%rsp)
+       add     %r12d,%edx
+       xor     %r11d,%ebx
+       rol     $30,%edi
+       add     %ebx,%edx
+       lea     0x5a827999(%eax,%r11d),%r12d
+       mov     %edi,%ebx
+       mov     28(%r9),%eax
+       mov     %edx,%r11d
+       xor     %ebp,%ebx
+       bswap   %eax    
+       rol     $5,%r11d
+       and     %esi,%ebx
+       mov     %eax,28(%rsp)
+       add     %r11d,%r12d
+       xor     %ebp,%ebx
+       rol     $30,%esi
+       add     %ebx,%r12d
+       lea     0x5a827999(%eax,%ebp),%r11d
+       mov     %esi,%ebx
+       mov     32(%r9),%eax
+       mov     %r12d,%ebp
+       xor     %edi,%ebx
+       bswap   %eax    
+       rol     $5,%ebp
+       and     %edx,%ebx
+       mov     %eax,32(%rsp)
+       add     %ebp,%r11d
+       xor     %edi,%ebx
+       rol     $30,%edx
+       add     %ebx,%r11d
+       lea     0x5a827999(%eax,%edi),%ebp
+       mov     %edx,%ebx
+       mov     36(%r9),%eax
+       mov     %r11d,%edi
+       xor     %esi,%ebx
+       bswap   %eax    
+       rol     $5,%edi
+       and     %r12d,%ebx
+       mov     %eax,36(%rsp)
+       add     %edi,%ebp
+       xor     %esi,%ebx
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       lea     0x5a827999(%eax,%esi),%edi
+       mov     %r12d,%ebx
+       mov     40(%r9),%eax
+       mov     %ebp,%esi
+       xor     %edx,%ebx
+       bswap   %eax    
+       rol     $5,%esi
+       and     %r11d,%ebx
+       mov     %eax,40(%rsp)
+       add     %esi,%edi
+       xor     %edx,%ebx
+       rol     $30,%r11d
+       add     %ebx,%edi
+       lea     0x5a827999(%eax,%edx),%esi
+       mov     %r11d,%ebx
+       mov     44(%r9),%eax
+       mov     %edi,%edx
+       xor     %r12d,%ebx
+       bswap   %eax    
+       rol     $5,%edx
+       and     %ebp,%ebx
+       mov     %eax,44(%rsp)
+       add     %edx,%esi
+       xor     %r12d,%ebx
+       rol     $30,%ebp
+       add     %ebx,%esi
+       lea     0x5a827999(%eax,%r12d),%edx
+       mov     %ebp,%ebx
+       mov     48(%r9),%eax
+       mov     %esi,%r12d
+       xor     %r11d,%ebx
+       bswap   %eax    
+       rol     $5,%r12d
+       and     %edi,%ebx
+       mov     %eax,48(%rsp)
+       add     %r12d,%edx
+       xor     %r11d,%ebx
+       rol     $30,%edi
+       add     %ebx,%edx
+       lea     0x5a827999(%eax,%r11d),%r12d
+       mov     %edi,%ebx
+       mov     52(%r9),%eax
+       mov     %edx,%r11d
+       xor     %ebp,%ebx
+       bswap   %eax    
+       rol     $5,%r11d
+       and     %esi,%ebx
+       mov     %eax,52(%rsp)
+       add     %r11d,%r12d
+       xor     %ebp,%ebx
+       rol     $30,%esi
+       add     %ebx,%r12d
+       lea     0x5a827999(%eax,%ebp),%r11d
+       mov     %esi,%ebx
+       mov     56(%r9),%eax
+       mov     %r12d,%ebp
+       xor     %edi,%ebx
+       bswap   %eax    
+       rol     $5,%ebp
+       and     %edx,%ebx
+       mov     %eax,56(%rsp)
+       add     %ebp,%r11d
+       xor     %edi,%ebx
+       rol     $30,%edx
+       add     %ebx,%r11d
+       lea     0x5a827999(%eax,%edi),%ebp
+       mov     %edx,%ebx
+       mov     60(%r9),%eax
+       mov     %r11d,%edi
+       xor     %esi,%ebx
+       bswap   %eax    
+       rol     $5,%edi
+       and     %r12d,%ebx
+       mov     %eax,60(%rsp)
+       add     %edi,%ebp
+       xor     %esi,%ebx
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       lea     0x5a827999(%eax,%esi),%edi
+       mov     0(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %ebp,%esi
+       xor     8(%rsp),%eax
+       xor     %edx,%ebx
+       rol     $5,%esi
+       xor     32(%rsp),%eax
+       and     %r11d,%ebx
+       add     %esi,%edi
+       xor     52(%rsp),%eax
+       xor     %edx,%ebx
+       rol     $30,%r11d
+       add     %ebx,%edi
+       rol     $1,%eax
+       mov     %eax,0(%rsp)
+       lea     0x5a827999(%eax,%edx),%esi
+       mov     4(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %edi,%edx
+       xor     12(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $5,%edx
+       xor     36(%rsp),%eax
+       and     %ebp,%ebx
+       add     %edx,%esi
+       xor     56(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $30,%ebp
+       add     %ebx,%esi
+       rol     $1,%eax
+       mov     %eax,4(%rsp)
+       lea     0x5a827999(%eax,%r12d),%edx
+       mov     8(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %esi,%r12d
+       xor     16(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $5,%r12d
+       xor     40(%rsp),%eax
+       and     %edi,%ebx
+       add     %r12d,%edx
+       xor     60(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $30,%edi
+       add     %ebx,%edx
+       rol     $1,%eax
+       mov     %eax,8(%rsp)
+       lea     0x5a827999(%eax,%r11d),%r12d
+       mov     12(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edx,%r11d
+       xor     20(%rsp),%eax
+       xor     %ebp,%ebx
+       rol     $5,%r11d
+       xor     44(%rsp),%eax
+       and     %esi,%ebx
+       add     %r11d,%r12d
+       xor     0(%rsp),%eax
+       xor     %ebp,%ebx
+       rol     $30,%esi
+       add     %ebx,%r12d
+       rol     $1,%eax
+       mov     %eax,12(%rsp)
+       lea     0x5a827999(%eax,%ebp),%r11d
+       mov     16(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %r12d,%ebp
+       xor     24(%rsp),%eax
+       xor     %edi,%ebx
+       rol     $5,%ebp
+       xor     48(%rsp),%eax
+       and     %edx,%ebx
+       add     %ebp,%r11d
+       xor     4(%rsp),%eax
+       xor     %edi,%ebx
+       rol     $30,%edx
+       add     %ebx,%r11d
+       rol     $1,%eax
+       mov     %eax,16(%rsp)
+       lea     0x6ed9eba1(%eax,%edi),%ebp
+       mov     20(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %r11d,%edi
+       xor     28(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $5,%edi
+       xor     52(%rsp),%eax
+       xor     %esi,%ebx
+       add     %edi,%ebp
+       xor     8(%rsp),%eax
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       rol     $1,%eax
+       mov     %eax,20(%rsp)
+       lea     0x6ed9eba1(%eax,%esi),%edi
+       mov     24(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %ebp,%esi
+       xor     32(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $5,%esi
+       xor     56(%rsp),%eax
+       xor     %edx,%ebx
+       add     %esi,%edi
+       xor     12(%rsp),%eax
+       rol     $30,%r11d
+       add     %ebx,%edi
+       rol     $1,%eax
+       mov     %eax,24(%rsp)
+       lea     0x6ed9eba1(%eax,%edx),%esi
+       mov     28(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %edi,%edx
+       xor     36(%rsp),%eax
+       xor     %ebp,%ebx
+       rol     $5,%edx
+       xor     60(%rsp),%eax
+       xor     %r12d,%ebx
+       add     %edx,%esi
+       xor     16(%rsp),%eax
+       rol     $30,%ebp
+       add     %ebx,%esi
+       rol     $1,%eax
+       mov     %eax,28(%rsp)
+       lea     0x6ed9eba1(%eax,%r12d),%edx
+       mov     32(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %esi,%r12d
+       xor     40(%rsp),%eax
+       xor     %edi,%ebx
+       rol     $5,%r12d
+       xor     0(%rsp),%eax
+       xor     %r11d,%ebx
+       add     %r12d,%edx
+       xor     20(%rsp),%eax
+       rol     $30,%edi
+       add     %ebx,%edx
+       rol     $1,%eax
+       mov     %eax,32(%rsp)
+       lea     0x6ed9eba1(%eax,%r11d),%r12d
+       mov     36(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edx,%r11d
+       xor     44(%rsp),%eax
+       xor     %esi,%ebx
+       rol     $5,%r11d
+       xor     4(%rsp),%eax
+       xor     %ebp,%ebx
+       add     %r11d,%r12d
+       xor     24(%rsp),%eax
+       rol     $30,%esi
+       add     %ebx,%r12d
+       rol     $1,%eax
+       mov     %eax,36(%rsp)
+       lea     0x6ed9eba1(%eax,%ebp),%r11d
+       mov     40(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %r12d,%ebp
+       xor     48(%rsp),%eax
+       xor     %edx,%ebx
+       rol     $5,%ebp
+       xor     8(%rsp),%eax
+       xor     %edi,%ebx
+       add     %ebp,%r11d
+       xor     28(%rsp),%eax
+       rol     $30,%edx
+       add     %ebx,%r11d
+       rol     $1,%eax
+       mov     %eax,40(%rsp)
+       lea     0x6ed9eba1(%eax,%edi),%ebp
+       mov     44(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %r11d,%edi
+       xor     52(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $5,%edi
+       xor     12(%rsp),%eax
+       xor     %esi,%ebx
+       add     %edi,%ebp
+       xor     32(%rsp),%eax
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       rol     $1,%eax
+       mov     %eax,44(%rsp)
+       lea     0x6ed9eba1(%eax,%esi),%edi
+       mov     48(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %ebp,%esi
+       xor     56(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $5,%esi
+       xor     16(%rsp),%eax
+       xor     %edx,%ebx
+       add     %esi,%edi
+       xor     36(%rsp),%eax
+       rol     $30,%r11d
+       add     %ebx,%edi
+       rol     $1,%eax
+       mov     %eax,48(%rsp)
+       lea     0x6ed9eba1(%eax,%edx),%esi
+       mov     52(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %edi,%edx
+       xor     60(%rsp),%eax
+       xor     %ebp,%ebx
+       rol     $5,%edx
+       xor     20(%rsp),%eax
+       xor     %r12d,%ebx
+       add     %edx,%esi
+       xor     40(%rsp),%eax
+       rol     $30,%ebp
+       add     %ebx,%esi
+       rol     $1,%eax
+       mov     %eax,52(%rsp)
+       lea     0x6ed9eba1(%eax,%r12d),%edx
+       mov     56(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %esi,%r12d
+       xor     0(%rsp),%eax
+       xor     %edi,%ebx
+       rol     $5,%r12d
+       xor     24(%rsp),%eax
+       xor     %r11d,%ebx
+       add     %r12d,%edx
+       xor     44(%rsp),%eax
+       rol     $30,%edi
+       add     %ebx,%edx
+       rol     $1,%eax
+       mov     %eax,56(%rsp)
+       lea     0x6ed9eba1(%eax,%r11d),%r12d
+       mov     60(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edx,%r11d
+       xor     4(%rsp),%eax
+       xor     %esi,%ebx
+       rol     $5,%r11d
+       xor     28(%rsp),%eax
+       xor     %ebp,%ebx
+       add     %r11d,%r12d
+       xor     48(%rsp),%eax
+       rol     $30,%esi
+       add     %ebx,%r12d
+       rol     $1,%eax
+       mov     %eax,60(%rsp)
+       lea     0x6ed9eba1(%eax,%ebp),%r11d
+       mov     0(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %r12d,%ebp
+       xor     8(%rsp),%eax
+       xor     %edx,%ebx
+       rol     $5,%ebp
+       xor     32(%rsp),%eax
+       xor     %edi,%ebx
+       add     %ebp,%r11d
+       xor     52(%rsp),%eax
+       rol     $30,%edx
+       add     %ebx,%r11d
+       rol     $1,%eax
+       mov     %eax,0(%rsp)
+       lea     0x6ed9eba1(%eax,%edi),%ebp
+       mov     4(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %r11d,%edi
+       xor     12(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $5,%edi
+       xor     36(%rsp),%eax
+       xor     %esi,%ebx
+       add     %edi,%ebp
+       xor     56(%rsp),%eax
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       rol     $1,%eax
+       mov     %eax,4(%rsp)
+       lea     0x6ed9eba1(%eax,%esi),%edi
+       mov     8(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %ebp,%esi
+       xor     16(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $5,%esi
+       xor     40(%rsp),%eax
+       xor     %edx,%ebx
+       add     %esi,%edi
+       xor     60(%rsp),%eax
+       rol     $30,%r11d
+       add     %ebx,%edi
+       rol     $1,%eax
+       mov     %eax,8(%rsp)
+       lea     0x6ed9eba1(%eax,%edx),%esi
+       mov     12(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %edi,%edx
+       xor     20(%rsp),%eax
+       xor     %ebp,%ebx
+       rol     $5,%edx
+       xor     44(%rsp),%eax
+       xor     %r12d,%ebx
+       add     %edx,%esi
+       xor     0(%rsp),%eax
+       rol     $30,%ebp
+       add     %ebx,%esi
+       rol     $1,%eax
+       mov     %eax,12(%rsp)
+       lea     0x6ed9eba1(%eax,%r12d),%edx
+       mov     16(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %esi,%r12d
+       xor     24(%rsp),%eax
+       xor     %edi,%ebx
+       rol     $5,%r12d
+       xor     48(%rsp),%eax
+       xor     %r11d,%ebx
+       add     %r12d,%edx
+       xor     4(%rsp),%eax
+       rol     $30,%edi
+       add     %ebx,%edx
+       rol     $1,%eax
+       mov     %eax,16(%rsp)
+       lea     0x6ed9eba1(%eax,%r11d),%r12d
+       mov     20(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edx,%r11d
+       xor     28(%rsp),%eax
+       xor     %esi,%ebx
+       rol     $5,%r11d
+       xor     52(%rsp),%eax
+       xor     %ebp,%ebx
+       add     %r11d,%r12d
+       xor     8(%rsp),%eax
+       rol     $30,%esi
+       add     %ebx,%r12d
+       rol     $1,%eax
+       mov     %eax,20(%rsp)
+       lea     0x6ed9eba1(%eax,%ebp),%r11d
+       mov     24(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %r12d,%ebp
+       xor     32(%rsp),%eax
+       xor     %edx,%ebx
+       rol     $5,%ebp
+       xor     56(%rsp),%eax
+       xor     %edi,%ebx
+       add     %ebp,%r11d
+       xor     12(%rsp),%eax
+       rol     $30,%edx
+       add     %ebx,%r11d
+       rol     $1,%eax
+       mov     %eax,24(%rsp)
+       lea     0x6ed9eba1(%eax,%edi),%ebp
+       mov     28(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %r11d,%edi
+       xor     36(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $5,%edi
+       xor     60(%rsp),%eax
+       xor     %esi,%ebx
+       add     %edi,%ebp
+       xor     16(%rsp),%eax
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       rol     $1,%eax
+       mov     %eax,28(%rsp)
+       lea     0x6ed9eba1(%eax,%esi),%edi
+       mov     32(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %ebp,%esi
+       xor     40(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $5,%esi
+       xor     0(%rsp),%eax
+       xor     %edx,%ebx
+       add     %esi,%edi
+       xor     20(%rsp),%eax
+       rol     $30,%r11d
+       add     %ebx,%edi
+       rol     $1,%eax
+       mov     %eax,32(%rsp)
+       lea     -0x70e44324(%eax,%edx),%esi
+       mov     36(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %ebp,%ecx
+       xor     44(%rsp),%eax
+       mov     %edi,%edx
+       and     %r11d,%ebx
+       xor     4(%rsp),%eax
+       or      %r11d,%ecx
+       rol     $5,%edx
+       xor     24(%rsp),%eax
+       and     %r12d,%ecx
+       add     %edx,%esi
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%ebp
+       mov     %eax,36(%rsp)
+       add     %ebx,%esi
+       lea     -0x70e44324(%eax,%r12d),%edx
+       mov     40(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edi,%ecx
+       xor     48(%rsp),%eax
+       mov     %esi,%r12d
+       and     %ebp,%ebx
+       xor     8(%rsp),%eax
+       or      %ebp,%ecx
+       rol     $5,%r12d
+       xor     28(%rsp),%eax
+       and     %r11d,%ecx
+       add     %r12d,%edx
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%edi
+       mov     %eax,40(%rsp)
+       add     %ebx,%edx
+       lea     -0x70e44324(%eax,%r11d),%r12d
+       mov     44(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %esi,%ecx
+       xor     52(%rsp),%eax
+       mov     %edx,%r11d
+       and     %edi,%ebx
+       xor     12(%rsp),%eax
+       or      %edi,%ecx
+       rol     $5,%r11d
+       xor     32(%rsp),%eax
+       and     %ebp,%ecx
+       add     %r11d,%r12d
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%esi
+       mov     %eax,44(%rsp)
+       add     %ebx,%r12d
+       lea     -0x70e44324(%eax,%ebp),%r11d
+       mov     48(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %edx,%ecx
+       xor     56(%rsp),%eax
+       mov     %r12d,%ebp
+       and     %esi,%ebx
+       xor     16(%rsp),%eax
+       or      %esi,%ecx
+       rol     $5,%ebp
+       xor     36(%rsp),%eax
+       and     %edi,%ecx
+       add     %ebp,%r11d
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%edx
+       mov     %eax,48(%rsp)
+       add     %ebx,%r11d
+       lea     -0x70e44324(%eax,%edi),%ebp
+       mov     52(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %r12d,%ecx
+       xor     60(%rsp),%eax
+       mov     %r11d,%edi
+       and     %edx,%ebx
+       xor     20(%rsp),%eax
+       or      %edx,%ecx
+       rol     $5,%edi
+       xor     40(%rsp),%eax
+       and     %esi,%ecx
+       add     %edi,%ebp
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%r12d
+       mov     %eax,52(%rsp)
+       add     %ebx,%ebp
+       lea     -0x70e44324(%eax,%esi),%edi
+       mov     56(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %r11d,%ecx
+       xor     0(%rsp),%eax
+       mov     %ebp,%esi
+       and     %r12d,%ebx
+       xor     24(%rsp),%eax
+       or      %r12d,%ecx
+       rol     $5,%esi
+       xor     44(%rsp),%eax
+       and     %edx,%ecx
+       add     %esi,%edi
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%r11d
+       mov     %eax,56(%rsp)
+       add     %ebx,%edi
+       lea     -0x70e44324(%eax,%edx),%esi
+       mov     60(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %ebp,%ecx
+       xor     4(%rsp),%eax
+       mov     %edi,%edx
+       and     %r11d,%ebx
+       xor     28(%rsp),%eax
+       or      %r11d,%ecx
+       rol     $5,%edx
+       xor     48(%rsp),%eax
+       and     %r12d,%ecx
+       add     %edx,%esi
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%ebp
+       mov     %eax,60(%rsp)
+       add     %ebx,%esi
+       lea     -0x70e44324(%eax,%r12d),%edx
+       mov     0(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edi,%ecx
+       xor     8(%rsp),%eax
+       mov     %esi,%r12d
+       and     %ebp,%ebx
+       xor     32(%rsp),%eax
+       or      %ebp,%ecx
+       rol     $5,%r12d
+       xor     52(%rsp),%eax
+       and     %r11d,%ecx
+       add     %r12d,%edx
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%edi
+       mov     %eax,0(%rsp)
+       add     %ebx,%edx
+       lea     -0x70e44324(%eax,%r11d),%r12d
+       mov     4(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %esi,%ecx
+       xor     12(%rsp),%eax
+       mov     %edx,%r11d
+       and     %edi,%ebx
+       xor     36(%rsp),%eax
+       or      %edi,%ecx
+       rol     $5,%r11d
+       xor     56(%rsp),%eax
+       and     %ebp,%ecx
+       add     %r11d,%r12d
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%esi
+       mov     %eax,4(%rsp)
+       add     %ebx,%r12d
+       lea     -0x70e44324(%eax,%ebp),%r11d
+       mov     8(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %edx,%ecx
+       xor     16(%rsp),%eax
+       mov     %r12d,%ebp
+       and     %esi,%ebx
+       xor     40(%rsp),%eax
+       or      %esi,%ecx
+       rol     $5,%ebp
+       xor     60(%rsp),%eax
+       and     %edi,%ecx
+       add     %ebp,%r11d
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%edx
+       mov     %eax,8(%rsp)
+       add     %ebx,%r11d
+       lea     -0x70e44324(%eax,%edi),%ebp
+       mov     12(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %r12d,%ecx
+       xor     20(%rsp),%eax
+       mov     %r11d,%edi
+       and     %edx,%ebx
+       xor     44(%rsp),%eax
+       or      %edx,%ecx
+       rol     $5,%edi
+       xor     0(%rsp),%eax
+       and     %esi,%ecx
+       add     %edi,%ebp
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%r12d
+       mov     %eax,12(%rsp)
+       add     %ebx,%ebp
+       lea     -0x70e44324(%eax,%esi),%edi
+       mov     16(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %r11d,%ecx
+       xor     24(%rsp),%eax
+       mov     %ebp,%esi
+       and     %r12d,%ebx
+       xor     48(%rsp),%eax
+       or      %r12d,%ecx
+       rol     $5,%esi
+       xor     4(%rsp),%eax
+       and     %edx,%ecx
+       add     %esi,%edi
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%r11d
+       mov     %eax,16(%rsp)
+       add     %ebx,%edi
+       lea     -0x70e44324(%eax,%edx),%esi
+       mov     20(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %ebp,%ecx
+       xor     28(%rsp),%eax
+       mov     %edi,%edx
+       and     %r11d,%ebx
+       xor     52(%rsp),%eax
+       or      %r11d,%ecx
+       rol     $5,%edx
+       xor     8(%rsp),%eax
+       and     %r12d,%ecx
+       add     %edx,%esi
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%ebp
+       mov     %eax,20(%rsp)
+       add     %ebx,%esi
+       lea     -0x70e44324(%eax,%r12d),%edx
+       mov     24(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edi,%ecx
+       xor     32(%rsp),%eax
+       mov     %esi,%r12d
+       and     %ebp,%ebx
+       xor     56(%rsp),%eax
+       or      %ebp,%ecx
+       rol     $5,%r12d
+       xor     12(%rsp),%eax
+       and     %r11d,%ecx
+       add     %r12d,%edx
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%edi
+       mov     %eax,24(%rsp)
+       add     %ebx,%edx
+       lea     -0x70e44324(%eax,%r11d),%r12d
+       mov     28(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %esi,%ecx
+       xor     36(%rsp),%eax
+       mov     %edx,%r11d
+       and     %edi,%ebx
+       xor     60(%rsp),%eax
+       or      %edi,%ecx
+       rol     $5,%r11d
+       xor     16(%rsp),%eax
+       and     %ebp,%ecx
+       add     %r11d,%r12d
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%esi
+       mov     %eax,28(%rsp)
+       add     %ebx,%r12d
+       lea     -0x70e44324(%eax,%ebp),%r11d
+       mov     32(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %edx,%ecx
+       xor     40(%rsp),%eax
+       mov     %r12d,%ebp
+       and     %esi,%ebx
+       xor     0(%rsp),%eax
+       or      %esi,%ecx
+       rol     $5,%ebp
+       xor     20(%rsp),%eax
+       and     %edi,%ecx
+       add     %ebp,%r11d
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%edx
+       mov     %eax,32(%rsp)
+       add     %ebx,%r11d
+       lea     -0x70e44324(%eax,%edi),%ebp
+       mov     36(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %r12d,%ecx
+       xor     44(%rsp),%eax
+       mov     %r11d,%edi
+       and     %edx,%ebx
+       xor     4(%rsp),%eax
+       or      %edx,%ecx
+       rol     $5,%edi
+       xor     24(%rsp),%eax
+       and     %esi,%ecx
+       add     %edi,%ebp
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%r12d
+       mov     %eax,36(%rsp)
+       add     %ebx,%ebp
+       lea     -0x70e44324(%eax,%esi),%edi
+       mov     40(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %r11d,%ecx
+       xor     48(%rsp),%eax
+       mov     %ebp,%esi
+       and     %r12d,%ebx
+       xor     8(%rsp),%eax
+       or      %r12d,%ecx
+       rol     $5,%esi
+       xor     28(%rsp),%eax
+       and     %edx,%ecx
+       add     %esi,%edi
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%r11d
+       mov     %eax,40(%rsp)
+       add     %ebx,%edi
+       lea     -0x70e44324(%eax,%edx),%esi
+       mov     44(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %ebp,%ecx
+       xor     52(%rsp),%eax
+       mov     %edi,%edx
+       and     %r11d,%ebx
+       xor     12(%rsp),%eax
+       or      %r11d,%ecx
+       rol     $5,%edx
+       xor     32(%rsp),%eax
+       and     %r12d,%ecx
+       add     %edx,%esi
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%ebp
+       mov     %eax,44(%rsp)
+       add     %ebx,%esi
+       lea     -0x70e44324(%eax,%r12d),%edx
+       mov     48(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edi,%ecx
+       xor     56(%rsp),%eax
+       mov     %esi,%r12d
+       and     %ebp,%ebx
+       xor     16(%rsp),%eax
+       or      %ebp,%ecx
+       rol     $5,%r12d
+       xor     36(%rsp),%eax
+       and     %r11d,%ecx
+       add     %r12d,%edx
+       rol     $1,%eax
+       or      %ecx,%ebx
+       rol     $30,%edi
+       mov     %eax,48(%rsp)
+       add     %ebx,%edx
+       lea     -0x359d3e2a(%eax,%r11d),%r12d
+       mov     52(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edx,%r11d
+       xor     60(%rsp),%eax
+       xor     %esi,%ebx
+       rol     $5,%r11d
+       xor     20(%rsp),%eax
+       xor     %ebp,%ebx
+       add     %r11d,%r12d
+       xor     40(%rsp),%eax
+       rol     $30,%esi
+       add     %ebx,%r12d
+       rol     $1,%eax
+       mov     %eax,52(%rsp)
+       lea     -0x359d3e2a(%eax,%ebp),%r11d
+       mov     56(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %r12d,%ebp
+       xor     0(%rsp),%eax
+       xor     %edx,%ebx
+       rol     $5,%ebp
+       xor     24(%rsp),%eax
+       xor     %edi,%ebx
+       add     %ebp,%r11d
+       xor     44(%rsp),%eax
+       rol     $30,%edx
+       add     %ebx,%r11d
+       rol     $1,%eax
+       mov     %eax,56(%rsp)
+       lea     -0x359d3e2a(%eax,%edi),%ebp
+       mov     60(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %r11d,%edi
+       xor     4(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $5,%edi
+       xor     28(%rsp),%eax
+       xor     %esi,%ebx
+       add     %edi,%ebp
+       xor     48(%rsp),%eax
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       rol     $1,%eax
+       mov     %eax,60(%rsp)
+       lea     -0x359d3e2a(%eax,%esi),%edi
+       mov     0(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %ebp,%esi
+       xor     8(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $5,%esi
+       xor     32(%rsp),%eax
+       xor     %edx,%ebx
+       add     %esi,%edi
+       xor     52(%rsp),%eax
+       rol     $30,%r11d
+       add     %ebx,%edi
+       rol     $1,%eax
+       mov     %eax,0(%rsp)
+       lea     -0x359d3e2a(%eax,%edx),%esi
+       mov     4(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %edi,%edx
+       xor     12(%rsp),%eax
+       xor     %ebp,%ebx
+       rol     $5,%edx
+       xor     36(%rsp),%eax
+       xor     %r12d,%ebx
+       add     %edx,%esi
+       xor     56(%rsp),%eax
+       rol     $30,%ebp
+       add     %ebx,%esi
+       rol     $1,%eax
+       mov     %eax,4(%rsp)
+       lea     -0x359d3e2a(%eax,%r12d),%edx
+       mov     8(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %esi,%r12d
+       xor     16(%rsp),%eax
+       xor     %edi,%ebx
+       rol     $5,%r12d
+       xor     40(%rsp),%eax
+       xor     %r11d,%ebx
+       add     %r12d,%edx
+       xor     60(%rsp),%eax
+       rol     $30,%edi
+       add     %ebx,%edx
+       rol     $1,%eax
+       mov     %eax,8(%rsp)
+       lea     -0x359d3e2a(%eax,%r11d),%r12d
+       mov     12(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edx,%r11d
+       xor     20(%rsp),%eax
+       xor     %esi,%ebx
+       rol     $5,%r11d
+       xor     44(%rsp),%eax
+       xor     %ebp,%ebx
+       add     %r11d,%r12d
+       xor     0(%rsp),%eax
+       rol     $30,%esi
+       add     %ebx,%r12d
+       rol     $1,%eax
+       mov     %eax,12(%rsp)
+       lea     -0x359d3e2a(%eax,%ebp),%r11d
+       mov     16(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %r12d,%ebp
+       xor     24(%rsp),%eax
+       xor     %edx,%ebx
+       rol     $5,%ebp
+       xor     48(%rsp),%eax
+       xor     %edi,%ebx
+       add     %ebp,%r11d
+       xor     4(%rsp),%eax
+       rol     $30,%edx
+       add     %ebx,%r11d
+       rol     $1,%eax
+       mov     %eax,16(%rsp)
+       lea     -0x359d3e2a(%eax,%edi),%ebp
+       mov     20(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %r11d,%edi
+       xor     28(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $5,%edi
+       xor     52(%rsp),%eax
+       xor     %esi,%ebx
+       add     %edi,%ebp
+       xor     8(%rsp),%eax
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       rol     $1,%eax
+       mov     %eax,20(%rsp)
+       lea     -0x359d3e2a(%eax,%esi),%edi
+       mov     24(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %ebp,%esi
+       xor     32(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $5,%esi
+       xor     56(%rsp),%eax
+       xor     %edx,%ebx
+       add     %esi,%edi
+       xor     12(%rsp),%eax
+       rol     $30,%r11d
+       add     %ebx,%edi
+       rol     $1,%eax
+       mov     %eax,24(%rsp)
+       lea     -0x359d3e2a(%eax,%edx),%esi
+       mov     28(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %edi,%edx
+       xor     36(%rsp),%eax
+       xor     %ebp,%ebx
+       rol     $5,%edx
+       xor     60(%rsp),%eax
+       xor     %r12d,%ebx
+       add     %edx,%esi
+       xor     16(%rsp),%eax
+       rol     $30,%ebp
+       add     %ebx,%esi
+       rol     $1,%eax
+       mov     %eax,28(%rsp)
+       lea     -0x359d3e2a(%eax,%r12d),%edx
+       mov     32(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %esi,%r12d
+       xor     40(%rsp),%eax
+       xor     %edi,%ebx
+       rol     $5,%r12d
+       xor     0(%rsp),%eax
+       xor     %r11d,%ebx
+       add     %r12d,%edx
+       xor     20(%rsp),%eax
+       rol     $30,%edi
+       add     %ebx,%edx
+       rol     $1,%eax
+       mov     %eax,32(%rsp)
+       lea     -0x359d3e2a(%eax,%r11d),%r12d
+       mov     36(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edx,%r11d
+       xor     44(%rsp),%eax
+       xor     %esi,%ebx
+       rol     $5,%r11d
+       xor     4(%rsp),%eax
+       xor     %ebp,%ebx
+       add     %r11d,%r12d
+       xor     24(%rsp),%eax
+       rol     $30,%esi
+       add     %ebx,%r12d
+       rol     $1,%eax
+       mov     %eax,36(%rsp)
+       lea     -0x359d3e2a(%eax,%ebp),%r11d
+       mov     40(%rsp),%eax
+       mov     %esi,%ebx
+       mov     %r12d,%ebp
+       xor     48(%rsp),%eax
+       xor     %edx,%ebx
+       rol     $5,%ebp
+       xor     8(%rsp),%eax
+       xor     %edi,%ebx
+       add     %ebp,%r11d
+       xor     28(%rsp),%eax
+       rol     $30,%edx
+       add     %ebx,%r11d
+       rol     $1,%eax
+       mov     %eax,40(%rsp)
+       lea     -0x359d3e2a(%eax,%edi),%ebp
+       mov     44(%rsp),%eax
+       mov     %edx,%ebx
+       mov     %r11d,%edi
+       xor     52(%rsp),%eax
+       xor     %r12d,%ebx
+       rol     $5,%edi
+       xor     12(%rsp),%eax
+       xor     %esi,%ebx
+       add     %edi,%ebp
+       xor     32(%rsp),%eax
+       rol     $30,%r12d
+       add     %ebx,%ebp
+       rol     $1,%eax
+       mov     %eax,44(%rsp)
+       lea     -0x359d3e2a(%eax,%esi),%edi
+       mov     48(%rsp),%eax
+       mov     %r12d,%ebx
+       mov     %ebp,%esi
+       xor     56(%rsp),%eax
+       xor     %r11d,%ebx
+       rol     $5,%esi
+       xor     16(%rsp),%eax
+       xor     %edx,%ebx
+       add     %esi,%edi
+       xor     36(%rsp),%eax
+       rol     $30,%r11d
+       add     %ebx,%edi
+       rol     $1,%eax
+       mov     %eax,48(%rsp)
+       lea     -0x359d3e2a(%eax,%edx),%esi
+       mov     52(%rsp),%eax
+       mov     %r11d,%ebx
+       mov     %edi,%edx
+       xor     60(%rsp),%eax
+       xor     %ebp,%ebx
+       rol     $5,%edx
+       xor     20(%rsp),%eax
+       xor     %r12d,%ebx
+       add     %edx,%esi
+       xor     40(%rsp),%eax
+       rol     $30,%ebp
+       add     %ebx,%esi
+       rol     $1,%eax
+       lea     -0x359d3e2a(%eax,%r12d),%edx
+       mov     56(%rsp),%eax
+       mov     %ebp,%ebx
+       mov     %esi,%r12d
+       xor     0(%rsp),%eax
+       xor     %edi,%ebx
+       rol     $5,%r12d
+       xor     24(%rsp),%eax
+       xor     %r11d,%ebx
+       add     %r12d,%edx
+       xor     44(%rsp),%eax
+       rol     $30,%edi
+       add     %ebx,%edx
+       rol     $1,%eax
+       lea     -0x359d3e2a(%eax,%r11d),%r12d
+       mov     60(%rsp),%eax
+       mov     %edi,%ebx
+       mov     %edx,%r11d
+       xor     4(%rsp),%eax
+       xor     %esi,%ebx
+       rol     $5,%r11d
+       xor     28(%rsp),%eax
+       xor     %ebp,%ebx
+       add     %r11d,%r12d
+       xor     48(%rsp),%eax
+       rol     $30,%esi
+       add     %ebx,%r12d
+       rol     $1,%eax
+       lea     -0x359d3e2a(%eax,%ebp),%r11d
+       mov     %esi,%ebx
+       mov     %r12d,%ebp
+       xor     %edx,%ebx
+       rol     $5,%ebp
+       xor     %edi,%ebx
+       add     %ebp,%r11d
+       rol     $30,%edx
+       add     %ebx,%r11d
+       // Update and save state information in SHA-1 context
+       add     0(%r8),%r11d
+       add     4(%r8),%r12d
+       add     8(%r8),%edx
+       add     12(%r8),%esi
+       add     16(%r8),%edi
+       mov     %r11d,0(%r8)
+       mov     %r12d,4(%r8)
+       mov     %edx,8(%r8)
+       mov     %esi,12(%r8)
+       mov     %edi,16(%r8)
+
+       xchg    %r11d,%edx      # mov   %r11d,%edx
+       xchg    %r12d,%esi      # mov   %r12d,%esi
+       xchg    %r11d,%edi      # mov   %edx,%edi
+       xchg    %r12d,%ebp      # mov   %esi,%ebp
+                       # mov   %edi,%r11d
+       lea     64(%r9),%r9
+       sub     $1,%r10
+       jnz     .Lloop
+       mov     64(%rsp),%rsp
+       pop     %r12
+       pop     %rbp
+       pop     %rbx
+       ret
+SET_SIZE(sha1_block_data_order)
+.asciz "SHA1 block transform for x86_64, CRYPTOGAMS by <appro@openssl.org>"
+
+#endif /* lint || __lint */
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/zfs/module/icp/asm-x86_64/sha2/sha256_impl.S b/zfs/module/icp/asm-x86_64/sha2/sha256_impl.S
new file mode 100644 (file)
index 0000000..d55c5eb
--- /dev/null
@@ -0,0 +1,2062 @@
+/*
+ * ====================================================================
+ * Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+ * project. Rights for redistribution and usage in source and binary
+ * forms are granted according to the OpenSSL license.
+ * ====================================================================
+ *
+ * sha256/512_block procedure for x86_64.
+ *
+ * 40% improvement over compiler-generated code on Opteron. On EM64T
+ * sha256 was observed to run >80% faster and sha512 - >40%. No magical
+ * tricks, just straight implementation... I really wonder why gcc
+ * [being armed with inline assembler] fails to generate as fast code.
+ * The only thing which is cool about this module is that it's very
+ * same instruction sequence used for both SHA-256 and SHA-512. In
+ * former case the instructions operate on 32-bit operands, while in
+ * latter - on 64-bit ones. All I had to do is to get one flavor right,
+ * the other one passed the test right away:-)
+ *
+ * sha256_block runs in ~1005 cycles on Opteron, which gives you
+ * asymptotic performance of 64*1000/1005=63.7MBps times CPU clock
+ * frequency in GHz. sha512_block runs in ~1275 cycles, which results
+ * in 128*1000/1275=100MBps per GHz. Is there room for improvement?
+ * Well, if you compare it to IA-64 implementation, which maintains
+ * X[16] in register bank[!], tends to 4 instructions per CPU clock
+ * cycle and runs in 1003 cycles, 1275 is very good result for 3-way
+ * issue Opteron pipeline and X[16] maintained in memory. So that *if*
+ * there is a way to improve it, *then* the only way would be to try to
+ * offload X[16] updates to SSE unit, but that would require "deeper"
+ * loop unroll, which in turn would naturally cause size blow-up, not
+ * to mention increased complexity! And once again, only *if* it's
+ * actually possible to noticeably improve overall ILP, instruction
+ * level parallelism, on a given CPU implementation in this case.
+ *
+ * Special note on Intel EM64T. While Opteron CPU exhibits perfect
+ * perfromance ratio of 1.5 between 64- and 32-bit flavors [see above],
+ * [currently available] EM64T CPUs apparently are far from it. On the
+ * contrary, 64-bit version, sha512_block, is ~30% *slower* than 32-bit
+ * sha256_block:-( This is presumably because 64-bit shifts/rotates
+ * apparently are not atomic instructions, but implemented in microcode.
+ */
+
+/*
+ * OpenSolaris OS modifications
+ *
+ * Sun elects to use this software under the BSD license.
+ *
+ * This source originates from OpenSSL file sha512-x86_64.pl at
+ * ftp://ftp.openssl.org/snapshot/openssl-0.9.8-stable-SNAP-20080131.tar.gz
+ * (presumably for future OpenSSL release 0.9.8h), with these changes:
+ *
+ * 1. Added perl "use strict" and declared variables.
+ *
+ * 2. Added OpenSolaris ENTRY_NP/SET_SIZE macros from
+ * /usr/include/sys/asm_linkage.h, .ident keywords, and lint(1B) guards.
+ *
+ * 3. Removed x86_64-xlate.pl script (not needed for as(1) or gas(1)
+ * assemblers).  Replaced the .picmeup macro with assembler code.
+ *
+ * 4. Added 8 to $ctx, as OpenSolaris OS has an extra 4-byte field, "algotype",
+ * at the beginning of SHA2_CTX (the next field is 8-byte aligned).
+ */
+
+/*
+ * This file was generated by a perl script (sha512-x86_64.pl) that were 
+ * used to generate sha256 and sha512 variants from the same code base.
+ * The comments from the original file have been pasted above.
+ */
+
+#if defined(lint) || defined(__lint)
+#include <sys/stdint.h>
+#include <sha2/sha2.h>
+
+/* ARGSUSED */
+void
+SHA256TransformBlocks(SHA2_CTX *ctx, const void *in, size_t num)
+{
+}
+
+
+#else
+#define _ASM
+#include <sys/asm_linkage.h>
+
+ENTRY_NP(SHA256TransformBlocks)
+       push    %rbx
+       push    %rbp
+       push    %r12
+       push    %r13
+       push    %r14
+       push    %r15
+       mov     %rsp,%rbp               # copy %rsp
+       shl     $4,%rdx         # num*16
+       sub     $16*4+4*8,%rsp
+       lea     (%rsi,%rdx,4),%rdx      # inp+num*16*4
+       and     $-64,%rsp               # align stack frame
+       add     $8,%rdi         # Skip OpenSolaris field, "algotype"
+       mov     %rdi,16*4+0*8(%rsp)             # save ctx, 1st arg
+       mov     %rsi,16*4+1*8(%rsp)             # save inp, 2nd arg
+       mov     %rdx,16*4+2*8(%rsp)             # save end pointer, "3rd" arg
+       mov     %rbp,16*4+3*8(%rsp)             # save copy of %rsp
+
+       /.picmeup %rbp
+       / The .picmeup pseudo-directive, from perlasm/x86_64_xlate.pl, puts
+       / the address of the "next" instruction into the target register
+       / (%rbp).  This generates these 2 instructions:
+       lea     .Llea(%rip),%rbp
+       /nop    / .picmeup generates a nop for mod 8 alignment--not needed here
+
+.Llea:
+       lea     K256-.(%rbp),%rbp
+
+       mov     4*0(%rdi),%eax
+       mov     4*1(%rdi),%ebx
+       mov     4*2(%rdi),%ecx
+       mov     4*3(%rdi),%edx
+       mov     4*4(%rdi),%r8d
+       mov     4*5(%rdi),%r9d
+       mov     4*6(%rdi),%r10d
+       mov     4*7(%rdi),%r11d
+       jmp     .Lloop
+
+.align 16
+.Lloop:
+       xor     %rdi,%rdi
+       mov     4*0(%rsi),%r12d
+       bswap   %r12d
+       mov     %r8d,%r13d
+       mov     %r8d,%r14d
+       mov     %r9d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r10d,%r15d                     # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r8d,%r15d                      # (f^g)&e
+       mov     %r12d,0(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r10d,%r15d                     # Ch(e,f,g)=((f^g)&e)^g
+       add     %r11d,%r12d                     # T1+=h
+
+       mov     %eax,%r11d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %eax,%r13d
+       mov     %eax,%r14d
+
+       ror     $2,%r11d
+       ror     $13,%r13d
+       mov     %eax,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r11d
+       ror     $9,%r13d
+       or      %ecx,%r14d                      # a|c
+
+       xor     %r13d,%r11d                     # h=Sigma0(a)
+       and     %ecx,%r15d                      # a&c
+       add     %r12d,%edx                      # d+=T1
+
+       and     %ebx,%r14d                      # (a|c)&b
+       add     %r12d,%r11d                     # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r11d                     # h+=Maj(a,b,c)
+       mov     4*1(%rsi),%r12d
+       bswap   %r12d
+       mov     %edx,%r13d
+       mov     %edx,%r14d
+       mov     %r8d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r9d,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %edx,%r15d                      # (f^g)&e
+       mov     %r12d,4(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r9d,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r10d,%r12d                     # T1+=h
+
+       mov     %r11d,%r10d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r11d,%r13d
+       mov     %r11d,%r14d
+
+       ror     $2,%r10d
+       ror     $13,%r13d
+       mov     %r11d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r10d
+       ror     $9,%r13d
+       or      %ebx,%r14d                      # a|c
+
+       xor     %r13d,%r10d                     # h=Sigma0(a)
+       and     %ebx,%r15d                      # a&c
+       add     %r12d,%ecx                      # d+=T1
+
+       and     %eax,%r14d                      # (a|c)&b
+       add     %r12d,%r10d                     # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r10d                     # h+=Maj(a,b,c)
+       mov     4*2(%rsi),%r12d
+       bswap   %r12d
+       mov     %ecx,%r13d
+       mov     %ecx,%r14d
+       mov     %edx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r8d,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %ecx,%r15d                      # (f^g)&e
+       mov     %r12d,8(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r8d,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r9d,%r12d                      # T1+=h
+
+       mov     %r10d,%r9d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r10d,%r13d
+       mov     %r10d,%r14d
+
+       ror     $2,%r9d
+       ror     $13,%r13d
+       mov     %r10d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r9d
+       ror     $9,%r13d
+       or      %eax,%r14d                      # a|c
+
+       xor     %r13d,%r9d                      # h=Sigma0(a)
+       and     %eax,%r15d                      # a&c
+       add     %r12d,%ebx                      # d+=T1
+
+       and     %r11d,%r14d                     # (a|c)&b
+       add     %r12d,%r9d                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r9d                      # h+=Maj(a,b,c)
+       mov     4*3(%rsi),%r12d
+       bswap   %r12d
+       mov     %ebx,%r13d
+       mov     %ebx,%r14d
+       mov     %ecx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %edx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %ebx,%r15d                      # (f^g)&e
+       mov     %r12d,12(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %edx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r8d,%r12d                      # T1+=h
+
+       mov     %r9d,%r8d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r9d,%r13d
+       mov     %r9d,%r14d
+
+       ror     $2,%r8d
+       ror     $13,%r13d
+       mov     %r9d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r8d
+       ror     $9,%r13d
+       or      %r11d,%r14d                     # a|c
+
+       xor     %r13d,%r8d                      # h=Sigma0(a)
+       and     %r11d,%r15d                     # a&c
+       add     %r12d,%eax                      # d+=T1
+
+       and     %r10d,%r14d                     # (a|c)&b
+       add     %r12d,%r8d                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r8d                      # h+=Maj(a,b,c)
+       mov     4*4(%rsi),%r12d
+       bswap   %r12d
+       mov     %eax,%r13d
+       mov     %eax,%r14d
+       mov     %ebx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %ecx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %eax,%r15d                      # (f^g)&e
+       mov     %r12d,16(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %ecx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %edx,%r12d                      # T1+=h
+
+       mov     %r8d,%edx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r8d,%r13d
+       mov     %r8d,%r14d
+
+       ror     $2,%edx
+       ror     $13,%r13d
+       mov     %r8d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%edx
+       ror     $9,%r13d
+       or      %r10d,%r14d                     # a|c
+
+       xor     %r13d,%edx                      # h=Sigma0(a)
+       and     %r10d,%r15d                     # a&c
+       add     %r12d,%r11d                     # d+=T1
+
+       and     %r9d,%r14d                      # (a|c)&b
+       add     %r12d,%edx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%edx                      # h+=Maj(a,b,c)
+       mov     4*5(%rsi),%r12d
+       bswap   %r12d
+       mov     %r11d,%r13d
+       mov     %r11d,%r14d
+       mov     %eax,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %ebx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r11d,%r15d                     # (f^g)&e
+       mov     %r12d,20(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %ebx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %ecx,%r12d                      # T1+=h
+
+       mov     %edx,%ecx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %edx,%r13d
+       mov     %edx,%r14d
+
+       ror     $2,%ecx
+       ror     $13,%r13d
+       mov     %edx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%ecx
+       ror     $9,%r13d
+       or      %r9d,%r14d                      # a|c
+
+       xor     %r13d,%ecx                      # h=Sigma0(a)
+       and     %r9d,%r15d                      # a&c
+       add     %r12d,%r10d                     # d+=T1
+
+       and     %r8d,%r14d                      # (a|c)&b
+       add     %r12d,%ecx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%ecx                      # h+=Maj(a,b,c)
+       mov     4*6(%rsi),%r12d
+       bswap   %r12d
+       mov     %r10d,%r13d
+       mov     %r10d,%r14d
+       mov     %r11d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %eax,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r10d,%r15d                     # (f^g)&e
+       mov     %r12d,24(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %eax,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %ebx,%r12d                      # T1+=h
+
+       mov     %ecx,%ebx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %ecx,%r13d
+       mov     %ecx,%r14d
+
+       ror     $2,%ebx
+       ror     $13,%r13d
+       mov     %ecx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%ebx
+       ror     $9,%r13d
+       or      %r8d,%r14d                      # a|c
+
+       xor     %r13d,%ebx                      # h=Sigma0(a)
+       and     %r8d,%r15d                      # a&c
+       add     %r12d,%r9d                      # d+=T1
+
+       and     %edx,%r14d                      # (a|c)&b
+       add     %r12d,%ebx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%ebx                      # h+=Maj(a,b,c)
+       mov     4*7(%rsi),%r12d
+       bswap   %r12d
+       mov     %r9d,%r13d
+       mov     %r9d,%r14d
+       mov     %r10d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r11d,%r15d                     # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r9d,%r15d                      # (f^g)&e
+       mov     %r12d,28(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r11d,%r15d                     # Ch(e,f,g)=((f^g)&e)^g
+       add     %eax,%r12d                      # T1+=h
+
+       mov     %ebx,%eax
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %ebx,%r13d
+       mov     %ebx,%r14d
+
+       ror     $2,%eax
+       ror     $13,%r13d
+       mov     %ebx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%eax
+       ror     $9,%r13d
+       or      %edx,%r14d                      # a|c
+
+       xor     %r13d,%eax                      # h=Sigma0(a)
+       and     %edx,%r15d                      # a&c
+       add     %r12d,%r8d                      # d+=T1
+
+       and     %ecx,%r14d                      # (a|c)&b
+       add     %r12d,%eax                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%eax                      # h+=Maj(a,b,c)
+       mov     4*8(%rsi),%r12d
+       bswap   %r12d
+       mov     %r8d,%r13d
+       mov     %r8d,%r14d
+       mov     %r9d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r10d,%r15d                     # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r8d,%r15d                      # (f^g)&e
+       mov     %r12d,32(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r10d,%r15d                     # Ch(e,f,g)=((f^g)&e)^g
+       add     %r11d,%r12d                     # T1+=h
+
+       mov     %eax,%r11d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %eax,%r13d
+       mov     %eax,%r14d
+
+       ror     $2,%r11d
+       ror     $13,%r13d
+       mov     %eax,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r11d
+       ror     $9,%r13d
+       or      %ecx,%r14d                      # a|c
+
+       xor     %r13d,%r11d                     # h=Sigma0(a)
+       and     %ecx,%r15d                      # a&c
+       add     %r12d,%edx                      # d+=T1
+
+       and     %ebx,%r14d                      # (a|c)&b
+       add     %r12d,%r11d                     # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r11d                     # h+=Maj(a,b,c)
+       mov     4*9(%rsi),%r12d
+       bswap   %r12d
+       mov     %edx,%r13d
+       mov     %edx,%r14d
+       mov     %r8d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r9d,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %edx,%r15d                      # (f^g)&e
+       mov     %r12d,36(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r9d,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r10d,%r12d                     # T1+=h
+
+       mov     %r11d,%r10d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r11d,%r13d
+       mov     %r11d,%r14d
+
+       ror     $2,%r10d
+       ror     $13,%r13d
+       mov     %r11d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r10d
+       ror     $9,%r13d
+       or      %ebx,%r14d                      # a|c
+
+       xor     %r13d,%r10d                     # h=Sigma0(a)
+       and     %ebx,%r15d                      # a&c
+       add     %r12d,%ecx                      # d+=T1
+
+       and     %eax,%r14d                      # (a|c)&b
+       add     %r12d,%r10d                     # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r10d                     # h+=Maj(a,b,c)
+       mov     4*10(%rsi),%r12d
+       bswap   %r12d
+       mov     %ecx,%r13d
+       mov     %ecx,%r14d
+       mov     %edx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r8d,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %ecx,%r15d                      # (f^g)&e
+       mov     %r12d,40(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r8d,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r9d,%r12d                      # T1+=h
+
+       mov     %r10d,%r9d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r10d,%r13d
+       mov     %r10d,%r14d
+
+       ror     $2,%r9d
+       ror     $13,%r13d
+       mov     %r10d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r9d
+       ror     $9,%r13d
+       or      %eax,%r14d                      # a|c
+
+       xor     %r13d,%r9d                      # h=Sigma0(a)
+       and     %eax,%r15d                      # a&c
+       add     %r12d,%ebx                      # d+=T1
+
+       and     %r11d,%r14d                     # (a|c)&b
+       add     %r12d,%r9d                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r9d                      # h+=Maj(a,b,c)
+       mov     4*11(%rsi),%r12d
+       bswap   %r12d
+       mov     %ebx,%r13d
+       mov     %ebx,%r14d
+       mov     %ecx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %edx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %ebx,%r15d                      # (f^g)&e
+       mov     %r12d,44(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %edx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r8d,%r12d                      # T1+=h
+
+       mov     %r9d,%r8d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r9d,%r13d
+       mov     %r9d,%r14d
+
+       ror     $2,%r8d
+       ror     $13,%r13d
+       mov     %r9d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r8d
+       ror     $9,%r13d
+       or      %r11d,%r14d                     # a|c
+
+       xor     %r13d,%r8d                      # h=Sigma0(a)
+       and     %r11d,%r15d                     # a&c
+       add     %r12d,%eax                      # d+=T1
+
+       and     %r10d,%r14d                     # (a|c)&b
+       add     %r12d,%r8d                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r8d                      # h+=Maj(a,b,c)
+       mov     4*12(%rsi),%r12d
+       bswap   %r12d
+       mov     %eax,%r13d
+       mov     %eax,%r14d
+       mov     %ebx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %ecx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %eax,%r15d                      # (f^g)&e
+       mov     %r12d,48(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %ecx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %edx,%r12d                      # T1+=h
+
+       mov     %r8d,%edx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r8d,%r13d
+       mov     %r8d,%r14d
+
+       ror     $2,%edx
+       ror     $13,%r13d
+       mov     %r8d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%edx
+       ror     $9,%r13d
+       or      %r10d,%r14d                     # a|c
+
+       xor     %r13d,%edx                      # h=Sigma0(a)
+       and     %r10d,%r15d                     # a&c
+       add     %r12d,%r11d                     # d+=T1
+
+       and     %r9d,%r14d                      # (a|c)&b
+       add     %r12d,%edx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%edx                      # h+=Maj(a,b,c)
+       mov     4*13(%rsi),%r12d
+       bswap   %r12d
+       mov     %r11d,%r13d
+       mov     %r11d,%r14d
+       mov     %eax,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %ebx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r11d,%r15d                     # (f^g)&e
+       mov     %r12d,52(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %ebx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %ecx,%r12d                      # T1+=h
+
+       mov     %edx,%ecx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %edx,%r13d
+       mov     %edx,%r14d
+
+       ror     $2,%ecx
+       ror     $13,%r13d
+       mov     %edx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%ecx
+       ror     $9,%r13d
+       or      %r9d,%r14d                      # a|c
+
+       xor     %r13d,%ecx                      # h=Sigma0(a)
+       and     %r9d,%r15d                      # a&c
+       add     %r12d,%r10d                     # d+=T1
+
+       and     %r8d,%r14d                      # (a|c)&b
+       add     %r12d,%ecx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%ecx                      # h+=Maj(a,b,c)
+       mov     4*14(%rsi),%r12d
+       bswap   %r12d
+       mov     %r10d,%r13d
+       mov     %r10d,%r14d
+       mov     %r11d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %eax,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r10d,%r15d                     # (f^g)&e
+       mov     %r12d,56(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %eax,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %ebx,%r12d                      # T1+=h
+
+       mov     %ecx,%ebx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %ecx,%r13d
+       mov     %ecx,%r14d
+
+       ror     $2,%ebx
+       ror     $13,%r13d
+       mov     %ecx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%ebx
+       ror     $9,%r13d
+       or      %r8d,%r14d                      # a|c
+
+       xor     %r13d,%ebx                      # h=Sigma0(a)
+       and     %r8d,%r15d                      # a&c
+       add     %r12d,%r9d                      # d+=T1
+
+       and     %edx,%r14d                      # (a|c)&b
+       add     %r12d,%ebx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%ebx                      # h+=Maj(a,b,c)
+       mov     4*15(%rsi),%r12d
+       bswap   %r12d
+       mov     %r9d,%r13d
+       mov     %r9d,%r14d
+       mov     %r10d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r11d,%r15d                     # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r9d,%r15d                      # (f^g)&e
+       mov     %r12d,60(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r11d,%r15d                     # Ch(e,f,g)=((f^g)&e)^g
+       add     %eax,%r12d                      # T1+=h
+
+       mov     %ebx,%eax
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %ebx,%r13d
+       mov     %ebx,%r14d
+
+       ror     $2,%eax
+       ror     $13,%r13d
+       mov     %ebx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%eax
+       ror     $9,%r13d
+       or      %edx,%r14d                      # a|c
+
+       xor     %r13d,%eax                      # h=Sigma0(a)
+       and     %edx,%r15d                      # a&c
+       add     %r12d,%r8d                      # d+=T1
+
+       and     %ecx,%r14d                      # (a|c)&b
+       add     %r12d,%eax                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%eax                      # h+=Maj(a,b,c)
+       jmp     .Lrounds_16_xx
+.align 16
+.Lrounds_16_xx:
+       mov     4(%rsp),%r13d
+       mov     56(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     36(%rsp),%r12d
+
+       add     0(%rsp),%r12d
+       mov     %r8d,%r13d
+       mov     %r8d,%r14d
+       mov     %r9d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r10d,%r15d                     # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r8d,%r15d                      # (f^g)&e
+       mov     %r12d,0(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r10d,%r15d                     # Ch(e,f,g)=((f^g)&e)^g
+       add     %r11d,%r12d                     # T1+=h
+
+       mov     %eax,%r11d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %eax,%r13d
+       mov     %eax,%r14d
+
+       ror     $2,%r11d
+       ror     $13,%r13d
+       mov     %eax,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r11d
+       ror     $9,%r13d
+       or      %ecx,%r14d                      # a|c
+
+       xor     %r13d,%r11d                     # h=Sigma0(a)
+       and     %ecx,%r15d                      # a&c
+       add     %r12d,%edx                      # d+=T1
+
+       and     %ebx,%r14d                      # (a|c)&b
+       add     %r12d,%r11d                     # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r11d                     # h+=Maj(a,b,c)
+       mov     8(%rsp),%r13d
+       mov     60(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     40(%rsp),%r12d
+
+       add     4(%rsp),%r12d
+       mov     %edx,%r13d
+       mov     %edx,%r14d
+       mov     %r8d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r9d,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %edx,%r15d                      # (f^g)&e
+       mov     %r12d,4(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r9d,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r10d,%r12d                     # T1+=h
+
+       mov     %r11d,%r10d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r11d,%r13d
+       mov     %r11d,%r14d
+
+       ror     $2,%r10d
+       ror     $13,%r13d
+       mov     %r11d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r10d
+       ror     $9,%r13d
+       or      %ebx,%r14d                      # a|c
+
+       xor     %r13d,%r10d                     # h=Sigma0(a)
+       and     %ebx,%r15d                      # a&c
+       add     %r12d,%ecx                      # d+=T1
+
+       and     %eax,%r14d                      # (a|c)&b
+       add     %r12d,%r10d                     # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r10d                     # h+=Maj(a,b,c)
+       mov     12(%rsp),%r13d
+       mov     0(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     44(%rsp),%r12d
+
+       add     8(%rsp),%r12d
+       mov     %ecx,%r13d
+       mov     %ecx,%r14d
+       mov     %edx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r8d,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %ecx,%r15d                      # (f^g)&e
+       mov     %r12d,8(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r8d,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r9d,%r12d                      # T1+=h
+
+       mov     %r10d,%r9d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r10d,%r13d
+       mov     %r10d,%r14d
+
+       ror     $2,%r9d
+       ror     $13,%r13d
+       mov     %r10d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r9d
+       ror     $9,%r13d
+       or      %eax,%r14d                      # a|c
+
+       xor     %r13d,%r9d                      # h=Sigma0(a)
+       and     %eax,%r15d                      # a&c
+       add     %r12d,%ebx                      # d+=T1
+
+       and     %r11d,%r14d                     # (a|c)&b
+       add     %r12d,%r9d                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r9d                      # h+=Maj(a,b,c)
+       mov     16(%rsp),%r13d
+       mov     4(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     48(%rsp),%r12d
+
+       add     12(%rsp),%r12d
+       mov     %ebx,%r13d
+       mov     %ebx,%r14d
+       mov     %ecx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %edx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %ebx,%r15d                      # (f^g)&e
+       mov     %r12d,12(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %edx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r8d,%r12d                      # T1+=h
+
+       mov     %r9d,%r8d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r9d,%r13d
+       mov     %r9d,%r14d
+
+       ror     $2,%r8d
+       ror     $13,%r13d
+       mov     %r9d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r8d
+       ror     $9,%r13d
+       or      %r11d,%r14d                     # a|c
+
+       xor     %r13d,%r8d                      # h=Sigma0(a)
+       and     %r11d,%r15d                     # a&c
+       add     %r12d,%eax                      # d+=T1
+
+       and     %r10d,%r14d                     # (a|c)&b
+       add     %r12d,%r8d                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r8d                      # h+=Maj(a,b,c)
+       mov     20(%rsp),%r13d
+       mov     8(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     52(%rsp),%r12d
+
+       add     16(%rsp),%r12d
+       mov     %eax,%r13d
+       mov     %eax,%r14d
+       mov     %ebx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %ecx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %eax,%r15d                      # (f^g)&e
+       mov     %r12d,16(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %ecx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %edx,%r12d                      # T1+=h
+
+       mov     %r8d,%edx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r8d,%r13d
+       mov     %r8d,%r14d
+
+       ror     $2,%edx
+       ror     $13,%r13d
+       mov     %r8d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%edx
+       ror     $9,%r13d
+       or      %r10d,%r14d                     # a|c
+
+       xor     %r13d,%edx                      # h=Sigma0(a)
+       and     %r10d,%r15d                     # a&c
+       add     %r12d,%r11d                     # d+=T1
+
+       and     %r9d,%r14d                      # (a|c)&b
+       add     %r12d,%edx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%edx                      # h+=Maj(a,b,c)
+       mov     24(%rsp),%r13d
+       mov     12(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     56(%rsp),%r12d
+
+       add     20(%rsp),%r12d
+       mov     %r11d,%r13d
+       mov     %r11d,%r14d
+       mov     %eax,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %ebx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r11d,%r15d                     # (f^g)&e
+       mov     %r12d,20(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %ebx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %ecx,%r12d                      # T1+=h
+
+       mov     %edx,%ecx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %edx,%r13d
+       mov     %edx,%r14d
+
+       ror     $2,%ecx
+       ror     $13,%r13d
+       mov     %edx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%ecx
+       ror     $9,%r13d
+       or      %r9d,%r14d                      # a|c
+
+       xor     %r13d,%ecx                      # h=Sigma0(a)
+       and     %r9d,%r15d                      # a&c
+       add     %r12d,%r10d                     # d+=T1
+
+       and     %r8d,%r14d                      # (a|c)&b
+       add     %r12d,%ecx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%ecx                      # h+=Maj(a,b,c)
+       mov     28(%rsp),%r13d
+       mov     16(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     60(%rsp),%r12d
+
+       add     24(%rsp),%r12d
+       mov     %r10d,%r13d
+       mov     %r10d,%r14d
+       mov     %r11d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %eax,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r10d,%r15d                     # (f^g)&e
+       mov     %r12d,24(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %eax,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %ebx,%r12d                      # T1+=h
+
+       mov     %ecx,%ebx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %ecx,%r13d
+       mov     %ecx,%r14d
+
+       ror     $2,%ebx
+       ror     $13,%r13d
+       mov     %ecx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%ebx
+       ror     $9,%r13d
+       or      %r8d,%r14d                      # a|c
+
+       xor     %r13d,%ebx                      # h=Sigma0(a)
+       and     %r8d,%r15d                      # a&c
+       add     %r12d,%r9d                      # d+=T1
+
+       and     %edx,%r14d                      # (a|c)&b
+       add     %r12d,%ebx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%ebx                      # h+=Maj(a,b,c)
+       mov     32(%rsp),%r13d
+       mov     20(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     0(%rsp),%r12d
+
+       add     28(%rsp),%r12d
+       mov     %r9d,%r13d
+       mov     %r9d,%r14d
+       mov     %r10d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r11d,%r15d                     # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r9d,%r15d                      # (f^g)&e
+       mov     %r12d,28(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r11d,%r15d                     # Ch(e,f,g)=((f^g)&e)^g
+       add     %eax,%r12d                      # T1+=h
+
+       mov     %ebx,%eax
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %ebx,%r13d
+       mov     %ebx,%r14d
+
+       ror     $2,%eax
+       ror     $13,%r13d
+       mov     %ebx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%eax
+       ror     $9,%r13d
+       or      %edx,%r14d                      # a|c
+
+       xor     %r13d,%eax                      # h=Sigma0(a)
+       and     %edx,%r15d                      # a&c
+       add     %r12d,%r8d                      # d+=T1
+
+       and     %ecx,%r14d                      # (a|c)&b
+       add     %r12d,%eax                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%eax                      # h+=Maj(a,b,c)
+       mov     36(%rsp),%r13d
+       mov     24(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     4(%rsp),%r12d
+
+       add     32(%rsp),%r12d
+       mov     %r8d,%r13d
+       mov     %r8d,%r14d
+       mov     %r9d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r10d,%r15d                     # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r8d,%r15d                      # (f^g)&e
+       mov     %r12d,32(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r10d,%r15d                     # Ch(e,f,g)=((f^g)&e)^g
+       add     %r11d,%r12d                     # T1+=h
+
+       mov     %eax,%r11d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %eax,%r13d
+       mov     %eax,%r14d
+
+       ror     $2,%r11d
+       ror     $13,%r13d
+       mov     %eax,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r11d
+       ror     $9,%r13d
+       or      %ecx,%r14d                      # a|c
+
+       xor     %r13d,%r11d                     # h=Sigma0(a)
+       and     %ecx,%r15d                      # a&c
+       add     %r12d,%edx                      # d+=T1
+
+       and     %ebx,%r14d                      # (a|c)&b
+       add     %r12d,%r11d                     # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r11d                     # h+=Maj(a,b,c)
+       mov     40(%rsp),%r13d
+       mov     28(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     8(%rsp),%r12d
+
+       add     36(%rsp),%r12d
+       mov     %edx,%r13d
+       mov     %edx,%r14d
+       mov     %r8d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r9d,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %edx,%r15d                      # (f^g)&e
+       mov     %r12d,36(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r9d,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r10d,%r12d                     # T1+=h
+
+       mov     %r11d,%r10d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r11d,%r13d
+       mov     %r11d,%r14d
+
+       ror     $2,%r10d
+       ror     $13,%r13d
+       mov     %r11d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r10d
+       ror     $9,%r13d
+       or      %ebx,%r14d                      # a|c
+
+       xor     %r13d,%r10d                     # h=Sigma0(a)
+       and     %ebx,%r15d                      # a&c
+       add     %r12d,%ecx                      # d+=T1
+
+       and     %eax,%r14d                      # (a|c)&b
+       add     %r12d,%r10d                     # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r10d                     # h+=Maj(a,b,c)
+       mov     44(%rsp),%r13d
+       mov     32(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     12(%rsp),%r12d
+
+       add     40(%rsp),%r12d
+       mov     %ecx,%r13d
+       mov     %ecx,%r14d
+       mov     %edx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r8d,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %ecx,%r15d                      # (f^g)&e
+       mov     %r12d,40(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r8d,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r9d,%r12d                      # T1+=h
+
+       mov     %r10d,%r9d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r10d,%r13d
+       mov     %r10d,%r14d
+
+       ror     $2,%r9d
+       ror     $13,%r13d
+       mov     %r10d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r9d
+       ror     $9,%r13d
+       or      %eax,%r14d                      # a|c
+
+       xor     %r13d,%r9d                      # h=Sigma0(a)
+       and     %eax,%r15d                      # a&c
+       add     %r12d,%ebx                      # d+=T1
+
+       and     %r11d,%r14d                     # (a|c)&b
+       add     %r12d,%r9d                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r9d                      # h+=Maj(a,b,c)
+       mov     48(%rsp),%r13d
+       mov     36(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     16(%rsp),%r12d
+
+       add     44(%rsp),%r12d
+       mov     %ebx,%r13d
+       mov     %ebx,%r14d
+       mov     %ecx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %edx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %ebx,%r15d                      # (f^g)&e
+       mov     %r12d,44(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %edx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %r8d,%r12d                      # T1+=h
+
+       mov     %r9d,%r8d
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r9d,%r13d
+       mov     %r9d,%r14d
+
+       ror     $2,%r8d
+       ror     $13,%r13d
+       mov     %r9d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%r8d
+       ror     $9,%r13d
+       or      %r11d,%r14d                     # a|c
+
+       xor     %r13d,%r8d                      # h=Sigma0(a)
+       and     %r11d,%r15d                     # a&c
+       add     %r12d,%eax                      # d+=T1
+
+       and     %r10d,%r14d                     # (a|c)&b
+       add     %r12d,%r8d                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%r8d                      # h+=Maj(a,b,c)
+       mov     52(%rsp),%r13d
+       mov     40(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     20(%rsp),%r12d
+
+       add     48(%rsp),%r12d
+       mov     %eax,%r13d
+       mov     %eax,%r14d
+       mov     %ebx,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %ecx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %eax,%r15d                      # (f^g)&e
+       mov     %r12d,48(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %ecx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %edx,%r12d                      # T1+=h
+
+       mov     %r8d,%edx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %r8d,%r13d
+       mov     %r8d,%r14d
+
+       ror     $2,%edx
+       ror     $13,%r13d
+       mov     %r8d,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%edx
+       ror     $9,%r13d
+       or      %r10d,%r14d                     # a|c
+
+       xor     %r13d,%edx                      # h=Sigma0(a)
+       and     %r10d,%r15d                     # a&c
+       add     %r12d,%r11d                     # d+=T1
+
+       and     %r9d,%r14d                      # (a|c)&b
+       add     %r12d,%edx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%edx                      # h+=Maj(a,b,c)
+       mov     56(%rsp),%r13d
+       mov     44(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     24(%rsp),%r12d
+
+       add     52(%rsp),%r12d
+       mov     %r11d,%r13d
+       mov     %r11d,%r14d
+       mov     %eax,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %ebx,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r11d,%r15d                     # (f^g)&e
+       mov     %r12d,52(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %ebx,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %ecx,%r12d                      # T1+=h
+
+       mov     %edx,%ecx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %edx,%r13d
+       mov     %edx,%r14d
+
+       ror     $2,%ecx
+       ror     $13,%r13d
+       mov     %edx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%ecx
+       ror     $9,%r13d
+       or      %r9d,%r14d                      # a|c
+
+       xor     %r13d,%ecx                      # h=Sigma0(a)
+       and     %r9d,%r15d                      # a&c
+       add     %r12d,%r10d                     # d+=T1
+
+       and     %r8d,%r14d                      # (a|c)&b
+       add     %r12d,%ecx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%ecx                      # h+=Maj(a,b,c)
+       mov     60(%rsp),%r13d
+       mov     48(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     28(%rsp),%r12d
+
+       add     56(%rsp),%r12d
+       mov     %r10d,%r13d
+       mov     %r10d,%r14d
+       mov     %r11d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %eax,%r15d                      # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r10d,%r15d                     # (f^g)&e
+       mov     %r12d,56(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %eax,%r15d                      # Ch(e,f,g)=((f^g)&e)^g
+       add     %ebx,%r12d                      # T1+=h
+
+       mov     %ecx,%ebx
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %ecx,%r13d
+       mov     %ecx,%r14d
+
+       ror     $2,%ebx
+       ror     $13,%r13d
+       mov     %ecx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%ebx
+       ror     $9,%r13d
+       or      %r8d,%r14d                      # a|c
+
+       xor     %r13d,%ebx                      # h=Sigma0(a)
+       and     %r8d,%r15d                      # a&c
+       add     %r12d,%r9d                      # d+=T1
+
+       and     %edx,%r14d                      # (a|c)&b
+       add     %r12d,%ebx                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%ebx                      # h+=Maj(a,b,c)
+       mov     0(%rsp),%r13d
+       mov     52(%rsp),%r12d
+
+       mov     %r13d,%r15d
+
+       shr     $3,%r13d
+       ror     $7,%r15d
+
+       xor     %r15d,%r13d
+       ror     $11,%r15d
+
+       xor     %r15d,%r13d                     # sigma0(X[(i+1)&0xf])
+       mov     %r12d,%r14d
+
+       shr     $10,%r12d
+       ror     $17,%r14d
+
+       xor     %r14d,%r12d
+       ror     $2,%r14d
+
+       xor     %r14d,%r12d                     # sigma1(X[(i+14)&0xf])
+
+       add     %r13d,%r12d
+
+       add     32(%rsp),%r12d
+
+       add     60(%rsp),%r12d
+       mov     %r9d,%r13d
+       mov     %r9d,%r14d
+       mov     %r10d,%r15d
+
+       ror     $6,%r13d
+       ror     $11,%r14d
+       xor     %r11d,%r15d                     # f^g
+
+       xor     %r14d,%r13d
+       ror     $14,%r14d
+       and     %r9d,%r15d                      # (f^g)&e
+       mov     %r12d,60(%rsp)
+
+       xor     %r14d,%r13d                     # Sigma1(e)
+       xor     %r11d,%r15d                     # Ch(e,f,g)=((f^g)&e)^g
+       add     %eax,%r12d                      # T1+=h
+
+       mov     %ebx,%eax
+       add     %r13d,%r12d                     # T1+=Sigma1(e)
+
+       add     %r15d,%r12d                     # T1+=Ch(e,f,g)
+       mov     %ebx,%r13d
+       mov     %ebx,%r14d
+
+       ror     $2,%eax
+       ror     $13,%r13d
+       mov     %ebx,%r15d
+       add     (%rbp,%rdi,4),%r12d     # T1+=K[round]
+
+       xor     %r13d,%eax
+       ror     $9,%r13d
+       or      %edx,%r14d                      # a|c
+
+       xor     %r13d,%eax                      # h=Sigma0(a)
+       and     %edx,%r15d                      # a&c
+       add     %r12d,%r8d                      # d+=T1
+
+       and     %ecx,%r14d                      # (a|c)&b
+       add     %r12d,%eax                      # h+=T1
+
+       or      %r15d,%r14d                     # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14d,%eax                      # h+=Maj(a,b,c)
+       cmp     $64,%rdi
+       jb      .Lrounds_16_xx
+
+       mov     16*4+0*8(%rsp),%rdi
+       lea     16*4(%rsi),%rsi
+
+       add     4*0(%rdi),%eax
+       add     4*1(%rdi),%ebx
+       add     4*2(%rdi),%ecx
+       add     4*3(%rdi),%edx
+       add     4*4(%rdi),%r8d
+       add     4*5(%rdi),%r9d
+       add     4*6(%rdi),%r10d
+       add     4*7(%rdi),%r11d
+
+       cmp     16*4+2*8(%rsp),%rsi
+
+       mov     %eax,4*0(%rdi)
+       mov     %ebx,4*1(%rdi)
+       mov     %ecx,4*2(%rdi)
+       mov     %edx,4*3(%rdi)
+       mov     %r8d,4*4(%rdi)
+       mov     %r9d,4*5(%rdi)
+       mov     %r10d,4*6(%rdi)
+       mov     %r11d,4*7(%rdi)
+       jb      .Lloop
+
+       mov     16*4+3*8(%rsp),%rsp
+       pop     %r15
+       pop     %r14
+       pop     %r13
+       pop     %r12
+       pop     %rbp
+       pop     %rbx
+
+       ret
+SET_SIZE(SHA256TransformBlocks)
+
+.align 64
+.type  K256,@object
+K256:
+       .long   0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
+       .long   0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
+       .long   0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
+       .long   0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
+       .long   0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
+       .long   0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
+       .long   0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
+       .long   0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
+       .long   0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
+       .long   0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
+       .long   0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
+       .long   0xd192e819,0xd6990624,0xf40e3585,0x106aa070
+       .long   0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
+       .long   0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
+       .long   0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
+       .long   0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+#endif /* !lint && !__lint */
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/zfs/module/icp/asm-x86_64/sha2/sha512_impl.S b/zfs/module/icp/asm-x86_64/sha2/sha512_impl.S
new file mode 100644 (file)
index 0000000..248d8b2
--- /dev/null
@@ -0,0 +1,2087 @@
+/*
+ * ====================================================================
+ * Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
+ * project. Rights for redistribution and usage in source and binary
+ * forms are granted according to the OpenSSL license.
+ * ====================================================================
+ *
+ * sha256/512_block procedure for x86_64.
+ *
+ * 40% improvement over compiler-generated code on Opteron. On EM64T
+ * sha256 was observed to run >80% faster and sha512 - >40%. No magical
+ * tricks, just straight implementation... I really wonder why gcc
+ * [being armed with inline assembler] fails to generate as fast code.
+ * The only thing which is cool about this module is that it's very
+ * same instruction sequence used for both SHA-256 and SHA-512. In
+ * former case the instructions operate on 32-bit operands, while in
+ * latter - on 64-bit ones. All I had to do is to get one flavor right,
+ * the other one passed the test right away:-)
+ *
+ * sha256_block runs in ~1005 cycles on Opteron, which gives you
+ * asymptotic performance of 64*1000/1005=63.7MBps times CPU clock
+ * frequency in GHz. sha512_block runs in ~1275 cycles, which results
+ * in 128*1000/1275=100MBps per GHz. Is there room for improvement?
+ * Well, if you compare it to IA-64 implementation, which maintains
+ * X[16] in register bank[!], tends to 4 instructions per CPU clock
+ * cycle and runs in 1003 cycles, 1275 is very good result for 3-way
+ * issue Opteron pipeline and X[16] maintained in memory. So that *if*
+ * there is a way to improve it, *then* the only way would be to try to
+ * offload X[16] updates to SSE unit, but that would require "deeper"
+ * loop unroll, which in turn would naturally cause size blow-up, not
+ * to mention increased complexity! And once again, only *if* it's
+ * actually possible to noticeably improve overall ILP, instruction
+ * level parallelism, on a given CPU implementation in this case.
+ *
+ * Special note on Intel EM64T. While Opteron CPU exhibits perfect
+ * perfromance ratio of 1.5 between 64- and 32-bit flavors [see above],
+ * [currently available] EM64T CPUs apparently are far from it. On the
+ * contrary, 64-bit version, sha512_block, is ~30% *slower* than 32-bit
+ * sha256_block:-( This is presumably because 64-bit shifts/rotates
+ * apparently are not atomic instructions, but implemented in microcode.
+ */
+
+/*
+ * OpenSolaris OS modifications
+ *
+ * Sun elects to use this software under the BSD license.
+ *
+ * This source originates from OpenSSL file sha512-x86_64.pl at
+ * ftp://ftp.openssl.org/snapshot/openssl-0.9.8-stable-SNAP-20080131.tar.gz
+ * (presumably for future OpenSSL release 0.9.8h), with these changes:
+ *
+ * 1. Added perl "use strict" and declared variables.
+ *
+ * 2. Added OpenSolaris ENTRY_NP/SET_SIZE macros from
+ * /usr/include/sys/asm_linkage.h, .ident keywords, and lint(1B) guards.
+ *
+ * 3. Removed x86_64-xlate.pl script (not needed for as(1) or gas(1)
+ * assemblers).  Replaced the .picmeup macro with assembler code.
+ *
+ * 4. Added 8 to $ctx, as OpenSolaris OS has an extra 4-byte field, "algotype",
+ * at the beginning of SHA2_CTX (the next field is 8-byte aligned).
+ */
+
+/*
+ * This file was generated by a perl script (sha512-x86_64.pl) that were
+ * used to generate sha256 and sha512 variants from the same code base.
+ * The comments from the original file have been pasted above.
+ */
+
+
+#if defined(lint) || defined(__lint)
+#include <sys/stdint.h>
+#include <sha2/sha2.h>
+
+/* ARGSUSED */
+void
+SHA512TransformBlocks(SHA2_CTX *ctx, const void *in, size_t num)
+{
+}
+
+
+#else
+#define _ASM
+#include <sys/asm_linkage.h>
+
+ENTRY_NP(SHA512TransformBlocks)
+       push    %rbx
+       push    %rbp
+       push    %r12
+       push    %r13
+       push    %r14
+       push    %r15
+       mov     %rsp,%rbp               # copy %rsp
+       shl     $4,%rdx         # num*16
+       sub     $16*8+4*8,%rsp
+       lea     (%rsi,%rdx,8),%rdx      # inp+num*16*8
+       and     $-64,%rsp               # align stack frame
+       add     $8,%rdi         # Skip OpenSolaris field, "algotype"
+       mov     %rdi,16*8+0*8(%rsp)             # save ctx, 1st arg
+       mov     %rsi,16*8+1*8(%rsp)             # save inp, 2nd arg
+       mov     %rdx,16*8+2*8(%rsp)             # save end pointer, "3rd" arg
+       mov     %rbp,16*8+3*8(%rsp)             # save copy of %rsp
+
+       /.picmeup %rbp
+       / The .picmeup pseudo-directive, from perlasm/x86_64_xlate.pl, puts
+       / the address of the "next" instruction into the target register
+       / (%rbp).  This generates these 2 instructions:
+       lea     .Llea(%rip),%rbp
+       /nop    / .picmeup generates a nop for mod 8 alignment--not needed here
+
+.Llea:
+       lea     K512-.(%rbp),%rbp
+
+       mov     8*0(%rdi),%rax
+       mov     8*1(%rdi),%rbx
+       mov     8*2(%rdi),%rcx
+       mov     8*3(%rdi),%rdx
+       mov     8*4(%rdi),%r8
+       mov     8*5(%rdi),%r9
+       mov     8*6(%rdi),%r10
+       mov     8*7(%rdi),%r11
+       jmp     .Lloop
+
+.align 16
+.Lloop:
+       xor     %rdi,%rdi
+       mov     8*0(%rsi),%r12
+       bswap   %r12
+       mov     %r8,%r13
+       mov     %r8,%r14
+       mov     %r9,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r10,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r8,%r15                        # (f^g)&e
+       mov     %r12,0(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r10,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %r11,%r12                       # T1+=h
+
+       mov     %rax,%r11
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rax,%r13
+       mov     %rax,%r14
+
+       ror     $28,%r11
+       ror     $34,%r13
+       mov     %rax,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r11
+       ror     $5,%r13
+       or      %rcx,%r14                       # a|c
+
+       xor     %r13,%r11                       # h=Sigma0(a)
+       and     %rcx,%r15                       # a&c
+       add     %r12,%rdx                       # d+=T1
+
+       and     %rbx,%r14                       # (a|c)&b
+       add     %r12,%r11                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r11                       # h+=Maj(a,b,c)
+       mov     8*1(%rsi),%r12
+       bswap   %r12
+       mov     %rdx,%r13
+       mov     %rdx,%r14
+       mov     %r8,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r9,%r15                        # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rdx,%r15                       # (f^g)&e
+       mov     %r12,8(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r9,%r15                        # Ch(e,f,g)=((f^g)&e)^g
+       add     %r10,%r12                       # T1+=h
+
+       mov     %r11,%r10
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r11,%r13
+       mov     %r11,%r14
+
+       ror     $28,%r10
+       ror     $34,%r13
+       mov     %r11,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r10
+       ror     $5,%r13
+       or      %rbx,%r14                       # a|c
+
+       xor     %r13,%r10                       # h=Sigma0(a)
+       and     %rbx,%r15                       # a&c
+       add     %r12,%rcx                       # d+=T1
+
+       and     %rax,%r14                       # (a|c)&b
+       add     %r12,%r10                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r10                       # h+=Maj(a,b,c)
+       mov     8*2(%rsi),%r12
+       bswap   %r12
+       mov     %rcx,%r13
+       mov     %rcx,%r14
+       mov     %rdx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r8,%r15                        # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rcx,%r15                       # (f^g)&e
+       mov     %r12,16(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r8,%r15                        # Ch(e,f,g)=((f^g)&e)^g
+       add     %r9,%r12                        # T1+=h
+
+       mov     %r10,%r9
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r10,%r13
+       mov     %r10,%r14
+
+       ror     $28,%r9
+       ror     $34,%r13
+       mov     %r10,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r9
+       ror     $5,%r13
+       or      %rax,%r14                       # a|c
+
+       xor     %r13,%r9                        # h=Sigma0(a)
+       and     %rax,%r15                       # a&c
+       add     %r12,%rbx                       # d+=T1
+
+       and     %r11,%r14                       # (a|c)&b
+       add     %r12,%r9                        # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r9                        # h+=Maj(a,b,c)
+       mov     8*3(%rsi),%r12
+       bswap   %r12
+       mov     %rbx,%r13
+       mov     %rbx,%r14
+       mov     %rcx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rdx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rbx,%r15                       # (f^g)&e
+       mov     %r12,24(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rdx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %r8,%r12                        # T1+=h
+
+       mov     %r9,%r8
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r9,%r13
+       mov     %r9,%r14
+
+       ror     $28,%r8
+       ror     $34,%r13
+       mov     %r9,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r8
+       ror     $5,%r13
+       or      %r11,%r14                       # a|c
+
+       xor     %r13,%r8                        # h=Sigma0(a)
+       and     %r11,%r15                       # a&c
+       add     %r12,%rax                       # d+=T1
+
+       and     %r10,%r14                       # (a|c)&b
+       add     %r12,%r8                        # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r8                        # h+=Maj(a,b,c)
+       mov     8*4(%rsi),%r12
+       bswap   %r12
+       mov     %rax,%r13
+       mov     %rax,%r14
+       mov     %rbx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rcx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rax,%r15                       # (f^g)&e
+       mov     %r12,32(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rcx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rdx,%r12                       # T1+=h
+
+       mov     %r8,%rdx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r8,%r13
+       mov     %r8,%r14
+
+       ror     $28,%rdx
+       ror     $34,%r13
+       mov     %r8,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rdx
+       ror     $5,%r13
+       or      %r10,%r14                       # a|c
+
+       xor     %r13,%rdx                       # h=Sigma0(a)
+       and     %r10,%r15                       # a&c
+       add     %r12,%r11                       # d+=T1
+
+       and     %r9,%r14                        # (a|c)&b
+       add     %r12,%rdx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rdx                       # h+=Maj(a,b,c)
+       mov     8*5(%rsi),%r12
+       bswap   %r12
+       mov     %r11,%r13
+       mov     %r11,%r14
+       mov     %rax,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rbx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r11,%r15                       # (f^g)&e
+       mov     %r12,40(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rbx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rcx,%r12                       # T1+=h
+
+       mov     %rdx,%rcx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rdx,%r13
+       mov     %rdx,%r14
+
+       ror     $28,%rcx
+       ror     $34,%r13
+       mov     %rdx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rcx
+       ror     $5,%r13
+       or      %r9,%r14                        # a|c
+
+       xor     %r13,%rcx                       # h=Sigma0(a)
+       and     %r9,%r15                        # a&c
+       add     %r12,%r10                       # d+=T1
+
+       and     %r8,%r14                        # (a|c)&b
+       add     %r12,%rcx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rcx                       # h+=Maj(a,b,c)
+       mov     8*6(%rsi),%r12
+       bswap   %r12
+       mov     %r10,%r13
+       mov     %r10,%r14
+       mov     %r11,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rax,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r10,%r15                       # (f^g)&e
+       mov     %r12,48(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rax,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rbx,%r12                       # T1+=h
+
+       mov     %rcx,%rbx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rcx,%r13
+       mov     %rcx,%r14
+
+       ror     $28,%rbx
+       ror     $34,%r13
+       mov     %rcx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rbx
+       ror     $5,%r13
+       or      %r8,%r14                        # a|c
+
+       xor     %r13,%rbx                       # h=Sigma0(a)
+       and     %r8,%r15                        # a&c
+       add     %r12,%r9                        # d+=T1
+
+       and     %rdx,%r14                       # (a|c)&b
+       add     %r12,%rbx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rbx                       # h+=Maj(a,b,c)
+       mov     8*7(%rsi),%r12
+       bswap   %r12
+       mov     %r9,%r13
+       mov     %r9,%r14
+       mov     %r10,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r11,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r9,%r15                        # (f^g)&e
+       mov     %r12,56(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r11,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rax,%r12                       # T1+=h
+
+       mov     %rbx,%rax
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rbx,%r13
+       mov     %rbx,%r14
+
+       ror     $28,%rax
+       ror     $34,%r13
+       mov     %rbx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rax
+       ror     $5,%r13
+       or      %rdx,%r14                       # a|c
+
+       xor     %r13,%rax                       # h=Sigma0(a)
+       and     %rdx,%r15                       # a&c
+       add     %r12,%r8                        # d+=T1
+
+       and     %rcx,%r14                       # (a|c)&b
+       add     %r12,%rax                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rax                       # h+=Maj(a,b,c)
+       mov     8*8(%rsi),%r12
+       bswap   %r12
+       mov     %r8,%r13
+       mov     %r8,%r14
+       mov     %r9,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r10,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r8,%r15                        # (f^g)&e
+       mov     %r12,64(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r10,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %r11,%r12                       # T1+=h
+
+       mov     %rax,%r11
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rax,%r13
+       mov     %rax,%r14
+
+       ror     $28,%r11
+       ror     $34,%r13
+       mov     %rax,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r11
+       ror     $5,%r13
+       or      %rcx,%r14                       # a|c
+
+       xor     %r13,%r11                       # h=Sigma0(a)
+       and     %rcx,%r15                       # a&c
+       add     %r12,%rdx                       # d+=T1
+
+       and     %rbx,%r14                       # (a|c)&b
+       add     %r12,%r11                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r11                       # h+=Maj(a,b,c)
+       mov     8*9(%rsi),%r12
+       bswap   %r12
+       mov     %rdx,%r13
+       mov     %rdx,%r14
+       mov     %r8,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r9,%r15                        # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rdx,%r15                       # (f^g)&e
+       mov     %r12,72(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r9,%r15                        # Ch(e,f,g)=((f^g)&e)^g
+       add     %r10,%r12                       # T1+=h
+
+       mov     %r11,%r10
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r11,%r13
+       mov     %r11,%r14
+
+       ror     $28,%r10
+       ror     $34,%r13
+       mov     %r11,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r10
+       ror     $5,%r13
+       or      %rbx,%r14                       # a|c
+
+       xor     %r13,%r10                       # h=Sigma0(a)
+       and     %rbx,%r15                       # a&c
+       add     %r12,%rcx                       # d+=T1
+
+       and     %rax,%r14                       # (a|c)&b
+       add     %r12,%r10                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r10                       # h+=Maj(a,b,c)
+       mov     8*10(%rsi),%r12
+       bswap   %r12
+       mov     %rcx,%r13
+       mov     %rcx,%r14
+       mov     %rdx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r8,%r15                        # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rcx,%r15                       # (f^g)&e
+       mov     %r12,80(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r8,%r15                        # Ch(e,f,g)=((f^g)&e)^g
+       add     %r9,%r12                        # T1+=h
+
+       mov     %r10,%r9
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r10,%r13
+       mov     %r10,%r14
+
+       ror     $28,%r9
+       ror     $34,%r13
+       mov     %r10,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r9
+       ror     $5,%r13
+       or      %rax,%r14                       # a|c
+
+       xor     %r13,%r9                        # h=Sigma0(a)
+       and     %rax,%r15                       # a&c
+       add     %r12,%rbx                       # d+=T1
+
+       and     %r11,%r14                       # (a|c)&b
+       add     %r12,%r9                        # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r9                        # h+=Maj(a,b,c)
+       mov     8*11(%rsi),%r12
+       bswap   %r12
+       mov     %rbx,%r13
+       mov     %rbx,%r14
+       mov     %rcx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rdx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rbx,%r15                       # (f^g)&e
+       mov     %r12,88(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rdx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %r8,%r12                        # T1+=h
+
+       mov     %r9,%r8
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r9,%r13
+       mov     %r9,%r14
+
+       ror     $28,%r8
+       ror     $34,%r13
+       mov     %r9,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r8
+       ror     $5,%r13
+       or      %r11,%r14                       # a|c
+
+       xor     %r13,%r8                        # h=Sigma0(a)
+       and     %r11,%r15                       # a&c
+       add     %r12,%rax                       # d+=T1
+
+       and     %r10,%r14                       # (a|c)&b
+       add     %r12,%r8                        # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r8                        # h+=Maj(a,b,c)
+       mov     8*12(%rsi),%r12
+       bswap   %r12
+       mov     %rax,%r13
+       mov     %rax,%r14
+       mov     %rbx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rcx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rax,%r15                       # (f^g)&e
+       mov     %r12,96(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rcx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rdx,%r12                       # T1+=h
+
+       mov     %r8,%rdx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r8,%r13
+       mov     %r8,%r14
+
+       ror     $28,%rdx
+       ror     $34,%r13
+       mov     %r8,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rdx
+       ror     $5,%r13
+       or      %r10,%r14                       # a|c
+
+       xor     %r13,%rdx                       # h=Sigma0(a)
+       and     %r10,%r15                       # a&c
+       add     %r12,%r11                       # d+=T1
+
+       and     %r9,%r14                        # (a|c)&b
+       add     %r12,%rdx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rdx                       # h+=Maj(a,b,c)
+       mov     8*13(%rsi),%r12
+       bswap   %r12
+       mov     %r11,%r13
+       mov     %r11,%r14
+       mov     %rax,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rbx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r11,%r15                       # (f^g)&e
+       mov     %r12,104(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rbx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rcx,%r12                       # T1+=h
+
+       mov     %rdx,%rcx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rdx,%r13
+       mov     %rdx,%r14
+
+       ror     $28,%rcx
+       ror     $34,%r13
+       mov     %rdx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rcx
+       ror     $5,%r13
+       or      %r9,%r14                        # a|c
+
+       xor     %r13,%rcx                       # h=Sigma0(a)
+       and     %r9,%r15                        # a&c
+       add     %r12,%r10                       # d+=T1
+
+       and     %r8,%r14                        # (a|c)&b
+       add     %r12,%rcx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rcx                       # h+=Maj(a,b,c)
+       mov     8*14(%rsi),%r12
+       bswap   %r12
+       mov     %r10,%r13
+       mov     %r10,%r14
+       mov     %r11,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rax,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r10,%r15                       # (f^g)&e
+       mov     %r12,112(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rax,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rbx,%r12                       # T1+=h
+
+       mov     %rcx,%rbx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rcx,%r13
+       mov     %rcx,%r14
+
+       ror     $28,%rbx
+       ror     $34,%r13
+       mov     %rcx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rbx
+       ror     $5,%r13
+       or      %r8,%r14                        # a|c
+
+       xor     %r13,%rbx                       # h=Sigma0(a)
+       and     %r8,%r15                        # a&c
+       add     %r12,%r9                        # d+=T1
+
+       and     %rdx,%r14                       # (a|c)&b
+       add     %r12,%rbx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rbx                       # h+=Maj(a,b,c)
+       mov     8*15(%rsi),%r12
+       bswap   %r12
+       mov     %r9,%r13
+       mov     %r9,%r14
+       mov     %r10,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r11,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r9,%r15                        # (f^g)&e
+       mov     %r12,120(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r11,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rax,%r12                       # T1+=h
+
+       mov     %rbx,%rax
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rbx,%r13
+       mov     %rbx,%r14
+
+       ror     $28,%rax
+       ror     $34,%r13
+       mov     %rbx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rax
+       ror     $5,%r13
+       or      %rdx,%r14                       # a|c
+
+       xor     %r13,%rax                       # h=Sigma0(a)
+       and     %rdx,%r15                       # a&c
+       add     %r12,%r8                        # d+=T1
+
+       and     %rcx,%r14                       # (a|c)&b
+       add     %r12,%rax                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rax                       # h+=Maj(a,b,c)
+       jmp     .Lrounds_16_xx
+.align 16
+.Lrounds_16_xx:
+       mov     8(%rsp),%r13
+       mov     112(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     72(%rsp),%r12
+
+       add     0(%rsp),%r12
+       mov     %r8,%r13
+       mov     %r8,%r14
+       mov     %r9,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r10,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r8,%r15                        # (f^g)&e
+       mov     %r12,0(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r10,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %r11,%r12                       # T1+=h
+
+       mov     %rax,%r11
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rax,%r13
+       mov     %rax,%r14
+
+       ror     $28,%r11
+       ror     $34,%r13
+       mov     %rax,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r11
+       ror     $5,%r13
+       or      %rcx,%r14                       # a|c
+
+       xor     %r13,%r11                       # h=Sigma0(a)
+       and     %rcx,%r15                       # a&c
+       add     %r12,%rdx                       # d+=T1
+
+       and     %rbx,%r14                       # (a|c)&b
+       add     %r12,%r11                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r11                       # h+=Maj(a,b,c)
+       mov     16(%rsp),%r13
+       mov     120(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     80(%rsp),%r12
+
+       add     8(%rsp),%r12
+       mov     %rdx,%r13
+       mov     %rdx,%r14
+       mov     %r8,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r9,%r15                        # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rdx,%r15                       # (f^g)&e
+       mov     %r12,8(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r9,%r15                        # Ch(e,f,g)=((f^g)&e)^g
+       add     %r10,%r12                       # T1+=h
+
+       mov     %r11,%r10
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r11,%r13
+       mov     %r11,%r14
+
+       ror     $28,%r10
+       ror     $34,%r13
+       mov     %r11,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r10
+       ror     $5,%r13
+       or      %rbx,%r14                       # a|c
+
+       xor     %r13,%r10                       # h=Sigma0(a)
+       and     %rbx,%r15                       # a&c
+       add     %r12,%rcx                       # d+=T1
+
+       and     %rax,%r14                       # (a|c)&b
+       add     %r12,%r10                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r10                       # h+=Maj(a,b,c)
+       mov     24(%rsp),%r13
+       mov     0(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     88(%rsp),%r12
+
+       add     16(%rsp),%r12
+       mov     %rcx,%r13
+       mov     %rcx,%r14
+       mov     %rdx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r8,%r15                        # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rcx,%r15                       # (f^g)&e
+       mov     %r12,16(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r8,%r15                        # Ch(e,f,g)=((f^g)&e)^g
+       add     %r9,%r12                        # T1+=h
+
+       mov     %r10,%r9
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r10,%r13
+       mov     %r10,%r14
+
+       ror     $28,%r9
+       ror     $34,%r13
+       mov     %r10,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r9
+       ror     $5,%r13
+       or      %rax,%r14                       # a|c
+
+       xor     %r13,%r9                        # h=Sigma0(a)
+       and     %rax,%r15                       # a&c
+       add     %r12,%rbx                       # d+=T1
+
+       and     %r11,%r14                       # (a|c)&b
+       add     %r12,%r9                        # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r9                        # h+=Maj(a,b,c)
+       mov     32(%rsp),%r13
+       mov     8(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     96(%rsp),%r12
+
+       add     24(%rsp),%r12
+       mov     %rbx,%r13
+       mov     %rbx,%r14
+       mov     %rcx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rdx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rbx,%r15                       # (f^g)&e
+       mov     %r12,24(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rdx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %r8,%r12                        # T1+=h
+
+       mov     %r9,%r8
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r9,%r13
+       mov     %r9,%r14
+
+       ror     $28,%r8
+       ror     $34,%r13
+       mov     %r9,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r8
+       ror     $5,%r13
+       or      %r11,%r14                       # a|c
+
+       xor     %r13,%r8                        # h=Sigma0(a)
+       and     %r11,%r15                       # a&c
+       add     %r12,%rax                       # d+=T1
+
+       and     %r10,%r14                       # (a|c)&b
+       add     %r12,%r8                        # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r8                        # h+=Maj(a,b,c)
+       mov     40(%rsp),%r13
+       mov     16(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     104(%rsp),%r12
+
+       add     32(%rsp),%r12
+       mov     %rax,%r13
+       mov     %rax,%r14
+       mov     %rbx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rcx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rax,%r15                       # (f^g)&e
+       mov     %r12,32(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rcx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rdx,%r12                       # T1+=h
+
+       mov     %r8,%rdx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r8,%r13
+       mov     %r8,%r14
+
+       ror     $28,%rdx
+       ror     $34,%r13
+       mov     %r8,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rdx
+       ror     $5,%r13
+       or      %r10,%r14                       # a|c
+
+       xor     %r13,%rdx                       # h=Sigma0(a)
+       and     %r10,%r15                       # a&c
+       add     %r12,%r11                       # d+=T1
+
+       and     %r9,%r14                        # (a|c)&b
+       add     %r12,%rdx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rdx                       # h+=Maj(a,b,c)
+       mov     48(%rsp),%r13
+       mov     24(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     112(%rsp),%r12
+
+       add     40(%rsp),%r12
+       mov     %r11,%r13
+       mov     %r11,%r14
+       mov     %rax,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rbx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r11,%r15                       # (f^g)&e
+       mov     %r12,40(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rbx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rcx,%r12                       # T1+=h
+
+       mov     %rdx,%rcx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rdx,%r13
+       mov     %rdx,%r14
+
+       ror     $28,%rcx
+       ror     $34,%r13
+       mov     %rdx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rcx
+       ror     $5,%r13
+       or      %r9,%r14                        # a|c
+
+       xor     %r13,%rcx                       # h=Sigma0(a)
+       and     %r9,%r15                        # a&c
+       add     %r12,%r10                       # d+=T1
+
+       and     %r8,%r14                        # (a|c)&b
+       add     %r12,%rcx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rcx                       # h+=Maj(a,b,c)
+       mov     56(%rsp),%r13
+       mov     32(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     120(%rsp),%r12
+
+       add     48(%rsp),%r12
+       mov     %r10,%r13
+       mov     %r10,%r14
+       mov     %r11,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rax,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r10,%r15                       # (f^g)&e
+       mov     %r12,48(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rax,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rbx,%r12                       # T1+=h
+
+       mov     %rcx,%rbx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rcx,%r13
+       mov     %rcx,%r14
+
+       ror     $28,%rbx
+       ror     $34,%r13
+       mov     %rcx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rbx
+       ror     $5,%r13
+       or      %r8,%r14                        # a|c
+
+       xor     %r13,%rbx                       # h=Sigma0(a)
+       and     %r8,%r15                        # a&c
+       add     %r12,%r9                        # d+=T1
+
+       and     %rdx,%r14                       # (a|c)&b
+       add     %r12,%rbx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rbx                       # h+=Maj(a,b,c)
+       mov     64(%rsp),%r13
+       mov     40(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     0(%rsp),%r12
+
+       add     56(%rsp),%r12
+       mov     %r9,%r13
+       mov     %r9,%r14
+       mov     %r10,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r11,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r9,%r15                        # (f^g)&e
+       mov     %r12,56(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r11,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rax,%r12                       # T1+=h
+
+       mov     %rbx,%rax
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rbx,%r13
+       mov     %rbx,%r14
+
+       ror     $28,%rax
+       ror     $34,%r13
+       mov     %rbx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rax
+       ror     $5,%r13
+       or      %rdx,%r14                       # a|c
+
+       xor     %r13,%rax                       # h=Sigma0(a)
+       and     %rdx,%r15                       # a&c
+       add     %r12,%r8                        # d+=T1
+
+       and     %rcx,%r14                       # (a|c)&b
+       add     %r12,%rax                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rax                       # h+=Maj(a,b,c)
+       mov     72(%rsp),%r13
+       mov     48(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     8(%rsp),%r12
+
+       add     64(%rsp),%r12
+       mov     %r8,%r13
+       mov     %r8,%r14
+       mov     %r9,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r10,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r8,%r15                        # (f^g)&e
+       mov     %r12,64(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r10,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %r11,%r12                       # T1+=h
+
+       mov     %rax,%r11
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rax,%r13
+       mov     %rax,%r14
+
+       ror     $28,%r11
+       ror     $34,%r13
+       mov     %rax,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r11
+       ror     $5,%r13
+       or      %rcx,%r14                       # a|c
+
+       xor     %r13,%r11                       # h=Sigma0(a)
+       and     %rcx,%r15                       # a&c
+       add     %r12,%rdx                       # d+=T1
+
+       and     %rbx,%r14                       # (a|c)&b
+       add     %r12,%r11                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r11                       # h+=Maj(a,b,c)
+       mov     80(%rsp),%r13
+       mov     56(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     16(%rsp),%r12
+
+       add     72(%rsp),%r12
+       mov     %rdx,%r13
+       mov     %rdx,%r14
+       mov     %r8,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r9,%r15                        # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rdx,%r15                       # (f^g)&e
+       mov     %r12,72(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r9,%r15                        # Ch(e,f,g)=((f^g)&e)^g
+       add     %r10,%r12                       # T1+=h
+
+       mov     %r11,%r10
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r11,%r13
+       mov     %r11,%r14
+
+       ror     $28,%r10
+       ror     $34,%r13
+       mov     %r11,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r10
+       ror     $5,%r13
+       or      %rbx,%r14                       # a|c
+
+       xor     %r13,%r10                       # h=Sigma0(a)
+       and     %rbx,%r15                       # a&c
+       add     %r12,%rcx                       # d+=T1
+
+       and     %rax,%r14                       # (a|c)&b
+       add     %r12,%r10                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r10                       # h+=Maj(a,b,c)
+       mov     88(%rsp),%r13
+       mov     64(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     24(%rsp),%r12
+
+       add     80(%rsp),%r12
+       mov     %rcx,%r13
+       mov     %rcx,%r14
+       mov     %rdx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r8,%r15                        # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rcx,%r15                       # (f^g)&e
+       mov     %r12,80(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r8,%r15                        # Ch(e,f,g)=((f^g)&e)^g
+       add     %r9,%r12                        # T1+=h
+
+       mov     %r10,%r9
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r10,%r13
+       mov     %r10,%r14
+
+       ror     $28,%r9
+       ror     $34,%r13
+       mov     %r10,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r9
+       ror     $5,%r13
+       or      %rax,%r14                       # a|c
+
+       xor     %r13,%r9                        # h=Sigma0(a)
+       and     %rax,%r15                       # a&c
+       add     %r12,%rbx                       # d+=T1
+
+       and     %r11,%r14                       # (a|c)&b
+       add     %r12,%r9                        # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r9                        # h+=Maj(a,b,c)
+       mov     96(%rsp),%r13
+       mov     72(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     32(%rsp),%r12
+
+       add     88(%rsp),%r12
+       mov     %rbx,%r13
+       mov     %rbx,%r14
+       mov     %rcx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rdx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rbx,%r15                       # (f^g)&e
+       mov     %r12,88(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rdx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %r8,%r12                        # T1+=h
+
+       mov     %r9,%r8
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r9,%r13
+       mov     %r9,%r14
+
+       ror     $28,%r8
+       ror     $34,%r13
+       mov     %r9,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%r8
+       ror     $5,%r13
+       or      %r11,%r14                       # a|c
+
+       xor     %r13,%r8                        # h=Sigma0(a)
+       and     %r11,%r15                       # a&c
+       add     %r12,%rax                       # d+=T1
+
+       and     %r10,%r14                       # (a|c)&b
+       add     %r12,%r8                        # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%r8                        # h+=Maj(a,b,c)
+       mov     104(%rsp),%r13
+       mov     80(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     40(%rsp),%r12
+
+       add     96(%rsp),%r12
+       mov     %rax,%r13
+       mov     %rax,%r14
+       mov     %rbx,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rcx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %rax,%r15                       # (f^g)&e
+       mov     %r12,96(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rcx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rdx,%r12                       # T1+=h
+
+       mov     %r8,%rdx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %r8,%r13
+       mov     %r8,%r14
+
+       ror     $28,%rdx
+       ror     $34,%r13
+       mov     %r8,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rdx
+       ror     $5,%r13
+       or      %r10,%r14                       # a|c
+
+       xor     %r13,%rdx                       # h=Sigma0(a)
+       and     %r10,%r15                       # a&c
+       add     %r12,%r11                       # d+=T1
+
+       and     %r9,%r14                        # (a|c)&b
+       add     %r12,%rdx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rdx                       # h+=Maj(a,b,c)
+       mov     112(%rsp),%r13
+       mov     88(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     48(%rsp),%r12
+
+       add     104(%rsp),%r12
+       mov     %r11,%r13
+       mov     %r11,%r14
+       mov     %rax,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rbx,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r11,%r15                       # (f^g)&e
+       mov     %r12,104(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rbx,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rcx,%r12                       # T1+=h
+
+       mov     %rdx,%rcx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rdx,%r13
+       mov     %rdx,%r14
+
+       ror     $28,%rcx
+       ror     $34,%r13
+       mov     %rdx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rcx
+       ror     $5,%r13
+       or      %r9,%r14                        # a|c
+
+       xor     %r13,%rcx                       # h=Sigma0(a)
+       and     %r9,%r15                        # a&c
+       add     %r12,%r10                       # d+=T1
+
+       and     %r8,%r14                        # (a|c)&b
+       add     %r12,%rcx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rcx                       # h+=Maj(a,b,c)
+       mov     120(%rsp),%r13
+       mov     96(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     56(%rsp),%r12
+
+       add     112(%rsp),%r12
+       mov     %r10,%r13
+       mov     %r10,%r14
+       mov     %r11,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %rax,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r10,%r15                       # (f^g)&e
+       mov     %r12,112(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %rax,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rbx,%r12                       # T1+=h
+
+       mov     %rcx,%rbx
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rcx,%r13
+       mov     %rcx,%r14
+
+       ror     $28,%rbx
+       ror     $34,%r13
+       mov     %rcx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rbx
+       ror     $5,%r13
+       or      %r8,%r14                        # a|c
+
+       xor     %r13,%rbx                       # h=Sigma0(a)
+       and     %r8,%r15                        # a&c
+       add     %r12,%r9                        # d+=T1
+
+       and     %rdx,%r14                       # (a|c)&b
+       add     %r12,%rbx                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rbx                       # h+=Maj(a,b,c)
+       mov     0(%rsp),%r13
+       mov     104(%rsp),%r12
+
+       mov     %r13,%r15
+
+       shr     $7,%r13
+       ror     $1,%r15
+
+       xor     %r15,%r13
+       ror     $7,%r15
+
+       xor     %r15,%r13                       # sigma0(X[(i+1)&0xf])
+       mov     %r12,%r14
+
+       shr     $6,%r12
+       ror     $19,%r14
+
+       xor     %r14,%r12
+       ror     $42,%r14
+
+       xor     %r14,%r12                       # sigma1(X[(i+14)&0xf])
+
+       add     %r13,%r12
+
+       add     64(%rsp),%r12
+
+       add     120(%rsp),%r12
+       mov     %r9,%r13
+       mov     %r9,%r14
+       mov     %r10,%r15
+
+       ror     $14,%r13
+       ror     $18,%r14
+       xor     %r11,%r15                       # f^g
+
+       xor     %r14,%r13
+       ror     $23,%r14
+       and     %r9,%r15                        # (f^g)&e
+       mov     %r12,120(%rsp)
+
+       xor     %r14,%r13                       # Sigma1(e)
+       xor     %r11,%r15                       # Ch(e,f,g)=((f^g)&e)^g
+       add     %rax,%r12                       # T1+=h
+
+       mov     %rbx,%rax
+       add     %r13,%r12                       # T1+=Sigma1(e)
+
+       add     %r15,%r12                       # T1+=Ch(e,f,g)
+       mov     %rbx,%r13
+       mov     %rbx,%r14
+
+       ror     $28,%rax
+       ror     $34,%r13
+       mov     %rbx,%r15
+       add     (%rbp,%rdi,8),%r12      # T1+=K[round]
+
+       xor     %r13,%rax
+       ror     $5,%r13
+       or      %rdx,%r14                       # a|c
+
+       xor     %r13,%rax                       # h=Sigma0(a)
+       and     %rdx,%r15                       # a&c
+       add     %r12,%r8                        # d+=T1
+
+       and     %rcx,%r14                       # (a|c)&b
+       add     %r12,%rax                       # h+=T1
+
+       or      %r15,%r14                       # Maj(a,b,c)=((a|c)&b)|(a&c)
+       lea     1(%rdi),%rdi    # round++
+
+       add     %r14,%rax                       # h+=Maj(a,b,c)
+       cmp     $80,%rdi
+       jb      .Lrounds_16_xx
+
+       mov     16*8+0*8(%rsp),%rdi
+       lea     16*8(%rsi),%rsi
+
+       add     8*0(%rdi),%rax
+       add     8*1(%rdi),%rbx
+       add     8*2(%rdi),%rcx
+       add     8*3(%rdi),%rdx
+       add     8*4(%rdi),%r8
+       add     8*5(%rdi),%r9
+       add     8*6(%rdi),%r10
+       add     8*7(%rdi),%r11
+
+       cmp     16*8+2*8(%rsp),%rsi
+
+       mov     %rax,8*0(%rdi)
+       mov     %rbx,8*1(%rdi)
+       mov     %rcx,8*2(%rdi)
+       mov     %rdx,8*3(%rdi)
+       mov     %r8,8*4(%rdi)
+       mov     %r9,8*5(%rdi)
+       mov     %r10,8*6(%rdi)
+       mov     %r11,8*7(%rdi)
+       jb      .Lloop
+
+       mov     16*8+3*8(%rsp),%rsp
+       pop     %r15
+       pop     %r14
+       pop     %r13
+       pop     %r12
+       pop     %rbp
+       pop     %rbx
+
+       ret
+SET_SIZE(SHA512TransformBlocks)
+
+.align 64
+.type  K512,@object
+K512:
+       .quad   0x428a2f98d728ae22,0x7137449123ef65cd
+       .quad   0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
+       .quad   0x3956c25bf348b538,0x59f111f1b605d019
+       .quad   0x923f82a4af194f9b,0xab1c5ed5da6d8118
+       .quad   0xd807aa98a3030242,0x12835b0145706fbe
+       .quad   0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
+       .quad   0x72be5d74f27b896f,0x80deb1fe3b1696b1
+       .quad   0x9bdc06a725c71235,0xc19bf174cf692694
+       .quad   0xe49b69c19ef14ad2,0xefbe4786384f25e3
+       .quad   0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
+       .quad   0x2de92c6f592b0275,0x4a7484aa6ea6e483
+       .quad   0x5cb0a9dcbd41fbd4,0x76f988da831153b5
+       .quad   0x983e5152ee66dfab,0xa831c66d2db43210
+       .quad   0xb00327c898fb213f,0xbf597fc7beef0ee4
+       .quad   0xc6e00bf33da88fc2,0xd5a79147930aa725
+       .quad   0x06ca6351e003826f,0x142929670a0e6e70
+       .quad   0x27b70a8546d22ffc,0x2e1b21385c26c926
+       .quad   0x4d2c6dfc5ac42aed,0x53380d139d95b3df
+       .quad   0x650a73548baf63de,0x766a0abb3c77b2a8
+       .quad   0x81c2c92e47edaee6,0x92722c851482353b
+       .quad   0xa2bfe8a14cf10364,0xa81a664bbc423001
+       .quad   0xc24b8b70d0f89791,0xc76c51a30654be30
+       .quad   0xd192e819d6ef5218,0xd69906245565a910
+       .quad   0xf40e35855771202a,0x106aa07032bbd1b8
+       .quad   0x19a4c116b8d2d0c8,0x1e376c085141ab53
+       .quad   0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
+       .quad   0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
+       .quad   0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
+       .quad   0x748f82ee5defb2fc,0x78a5636f43172f60
+       .quad   0x84c87814a1f0ab72,0x8cc702081a6439ec
+       .quad   0x90befffa23631e28,0xa4506cebde82bde9
+       .quad   0xbef9a3f7b2c67915,0xc67178f2e372532b
+       .quad   0xca273eceea26619c,0xd186b8c721c0c207
+       .quad   0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
+       .quad   0x06f067aa72176fba,0x0a637dc5a2c898a6
+       .quad   0x113f9804bef90dae,0x1b710b35131c471b
+       .quad   0x28db77f523047d84,0x32caab7b40c72493
+       .quad   0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
+       .quad   0x4cc5d4becb3e42b6,0x597f299cfc657e2a
+       .quad   0x5fcb6fab3ad6faec,0x6c44198c4a475817
+#endif /* !lint && !__lint */
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/zfs/module/icp/core/kcf_callprov.c b/zfs/module/icp/core/kcf_callprov.c
new file mode 100644 (file)
index 0000000..38927dc
--- /dev/null
@@ -0,0 +1,1567 @@
+/*
+ * 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/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/sched_impl.h>
+
+static int kcf_emulate_dual(kcf_provider_desc_t *, crypto_ctx_t *,
+    kcf_req_params_t *);
+
+void
+kcf_free_triedlist(kcf_prov_tried_t *list)
+{
+       kcf_prov_tried_t *l;
+
+       while ((l = list) != NULL) {
+               list = list->pt_next;
+               KCF_PROV_REFRELE(l->pt_pd);
+               kmem_free(l, sizeof (kcf_prov_tried_t));
+       }
+}
+
+kcf_prov_tried_t *
+kcf_insert_triedlist(kcf_prov_tried_t **list, kcf_provider_desc_t *pd,
+    int kmflag)
+{
+       kcf_prov_tried_t *l;
+
+       l = kmem_alloc(sizeof (kcf_prov_tried_t), kmflag);
+       if (l == NULL)
+               return (NULL);
+
+       l->pt_pd = pd;
+       l->pt_next = *list;
+       *list = l;
+
+       return (l);
+}
+
+static boolean_t
+is_in_triedlist(kcf_provider_desc_t *pd, kcf_prov_tried_t *triedl)
+{
+       while (triedl != NULL) {
+               if (triedl->pt_pd == pd)
+                       return (B_TRUE);
+               triedl = triedl->pt_next;
+       };
+
+       return (B_FALSE);
+}
+
+/*
+ * Search a mech entry's hardware provider list for the specified
+ * provider. Return true if found.
+ */
+static boolean_t
+is_valid_provider_for_mech(kcf_provider_desc_t *pd, kcf_mech_entry_t *me,
+    crypto_func_group_t fg)
+{
+       kcf_prov_mech_desc_t *prov_chain;
+
+       prov_chain = me->me_hw_prov_chain;
+       if (prov_chain != NULL) {
+               ASSERT(me->me_num_hwprov > 0);
+               for (; prov_chain != NULL; prov_chain = prov_chain->pm_next) {
+                       if (prov_chain->pm_prov_desc == pd &&
+                           IS_FG_SUPPORTED(prov_chain, fg)) {
+                               return (B_TRUE);
+                       }
+               }
+       }
+       return (B_FALSE);
+}
+
+/*
+ * This routine, given a logical provider, returns the least loaded
+ * provider belonging to the logical provider. The provider must be
+ * able to do the specified mechanism, i.e. check that the mechanism
+ * hasn't been disabled. In addition, just in case providers are not
+ * entirely equivalent, the provider's entry point is checked for
+ * non-nullness. This is accomplished by having the caller pass, as
+ * arguments, the offset of the function group (offset_1), and the
+ * offset of the function within the function group (offset_2).
+ * Returns NULL if no provider can be found.
+ */
+int
+kcf_get_hardware_provider(crypto_mech_type_t mech_type_1,
+    crypto_mech_type_t mech_type_2, boolean_t call_restrict,
+    kcf_provider_desc_t *old, kcf_provider_desc_t **new, crypto_func_group_t fg)
+{
+       kcf_provider_desc_t *provider, *real_pd = old;
+       kcf_provider_desc_t *gpd = NULL;        /* good provider */
+       kcf_provider_desc_t *bpd = NULL;        /* busy provider */
+       kcf_provider_list_t *p;
+       kcf_ops_class_t class;
+       kcf_mech_entry_t *me;
+       kcf_mech_entry_tab_t *me_tab;
+       int index, len, gqlen = INT_MAX, rv = CRYPTO_SUCCESS;
+
+       /* get the mech entry for the specified mechanism */
+       class = KCF_MECH2CLASS(mech_type_1);
+       if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       me_tab = &kcf_mech_tabs_tab[class];
+       index = KCF_MECH2INDEX(mech_type_1);
+       if ((index < 0) || (index >= me_tab->met_size)) {
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       me = &((me_tab->met_tab)[index]);
+       mutex_enter(&me->me_mutex);
+
+       /*
+        * We assume the provider descriptor will not go away because
+        * it is being held somewhere, i.e. its reference count has been
+        * incremented. In the case of the crypto module, the provider
+        * descriptor is held by the session structure.
+        */
+       if (old->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               if (old->pd_provider_list == NULL) {
+                       real_pd = NULL;
+                       rv = CRYPTO_DEVICE_ERROR;
+                       goto out;
+               }
+               /*
+                * Find the least loaded real provider. KCF_PROV_LOAD gives
+                * the load (number of pending requests) of the provider.
+                */
+               mutex_enter(&old->pd_lock);
+               p = old->pd_provider_list;
+               while (p != NULL) {
+                       provider = p->pl_provider;
+
+                       ASSERT(provider->pd_prov_type !=
+                           CRYPTO_LOGICAL_PROVIDER);
+
+                       if (call_restrict &&
+                           (provider->pd_flags & KCF_PROV_RESTRICTED)) {
+                               p = p->pl_next;
+                               continue;
+                       }
+
+                       if (!is_valid_provider_for_mech(provider, me, fg)) {
+                               p = p->pl_next;
+                               continue;
+                       }
+
+                       /* provider does second mech */
+                       if (mech_type_2 != CRYPTO_MECH_INVALID) {
+                               int i;
+
+                               i = KCF_TO_PROV_MECH_INDX(provider,
+                                   mech_type_2);
+                               if (i == KCF_INVALID_INDX) {
+                                       p = p->pl_next;
+                                       continue;
+                               }
+                       }
+
+                       if (provider->pd_state != KCF_PROV_READY) {
+                               /* choose BUSY if no READY providers */
+                               if (provider->pd_state == KCF_PROV_BUSY)
+                                       bpd = provider;
+                               p = p->pl_next;
+                               continue;
+                       }
+
+                       len = KCF_PROV_LOAD(provider);
+                       if (len < gqlen) {
+                               gqlen = len;
+                               gpd = provider;
+                       }
+
+                       p = p->pl_next;
+               }
+
+               if (gpd != NULL) {
+                       real_pd = gpd;
+                       KCF_PROV_REFHOLD(real_pd);
+               } else if (bpd != NULL) {
+                       real_pd = bpd;
+                       KCF_PROV_REFHOLD(real_pd);
+               } else {
+                       /* can't find provider */
+                       real_pd = NULL;
+                       rv = CRYPTO_MECHANISM_INVALID;
+               }
+               mutex_exit(&old->pd_lock);
+
+       } else {
+               if (!KCF_IS_PROV_USABLE(old) ||
+                   (call_restrict && (old->pd_flags & KCF_PROV_RESTRICTED))) {
+                       real_pd = NULL;
+                       rv = CRYPTO_DEVICE_ERROR;
+                       goto out;
+               }
+
+               if (!is_valid_provider_for_mech(old, me, fg)) {
+                       real_pd = NULL;
+                       rv = CRYPTO_MECHANISM_INVALID;
+                       goto out;
+               }
+
+               KCF_PROV_REFHOLD(real_pd);
+       }
+out:
+       mutex_exit(&me->me_mutex);
+       *new = real_pd;
+       return (rv);
+}
+
+/*
+ * Return the best provider for the specified mechanism. The provider
+ * is held and it is the caller's responsibility to release it when done.
+ * The fg input argument is used as a search criterion to pick a provider.
+ * A provider has to support this function group to be picked.
+ *
+ * Find the least loaded provider in the list of providers. We do a linear
+ * search to find one. This is fine as we assume there are only a few
+ * number of providers in this list. If this assumption ever changes,
+ * we should revisit this.
+ *
+ * call_restrict represents if the caller should not be allowed to
+ * use restricted providers.
+ */
+kcf_provider_desc_t *
+kcf_get_mech_provider(crypto_mech_type_t mech_type, kcf_mech_entry_t **mepp,
+    int *error, kcf_prov_tried_t *triedl, crypto_func_group_t fg,
+    boolean_t call_restrict, size_t data_size)
+{
+       kcf_provider_desc_t *pd = NULL, *gpd = NULL;
+       kcf_prov_mech_desc_t *prov_chain, *mdesc;
+       int len, gqlen = INT_MAX;
+       kcf_ops_class_t class;
+       int index;
+       kcf_mech_entry_t *me;
+       kcf_mech_entry_tab_t *me_tab;
+
+       class = KCF_MECH2CLASS(mech_type);
+       if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
+               *error = CRYPTO_MECHANISM_INVALID;
+               return (NULL);
+       }
+
+       me_tab = &kcf_mech_tabs_tab[class];
+       index = KCF_MECH2INDEX(mech_type);
+       if ((index < 0) || (index >= me_tab->met_size)) {
+               *error = CRYPTO_MECHANISM_INVALID;
+               return (NULL);
+       }
+
+       me = &((me_tab->met_tab)[index]);
+       if (mepp != NULL)
+               *mepp = me;
+
+       mutex_enter(&me->me_mutex);
+
+       prov_chain = me->me_hw_prov_chain;
+
+       /*
+        * We check for the threshhold for using a hardware provider for
+        * this amount of data. If there is no software provider available
+        * for the mechanism, then the threshold is ignored.
+        */
+       if ((prov_chain != NULL) &&
+           ((data_size == 0) || (me->me_threshold == 0) ||
+           (data_size >= me->me_threshold) ||
+           ((mdesc = me->me_sw_prov) == NULL) ||
+           (!IS_FG_SUPPORTED(mdesc, fg)) ||
+           (!KCF_IS_PROV_USABLE(mdesc->pm_prov_desc)))) {
+               ASSERT(me->me_num_hwprov > 0);
+               /* there is at least one provider */
+
+               /*
+                * Find the least loaded real provider. KCF_PROV_LOAD gives
+                * the load (number of pending requests) of the provider.
+                */
+               while (prov_chain != NULL) {
+                       pd = prov_chain->pm_prov_desc;
+
+                       if (!IS_FG_SUPPORTED(prov_chain, fg) ||
+                           !KCF_IS_PROV_USABLE(pd) ||
+                           IS_PROVIDER_TRIED(pd, triedl) ||
+                           (call_restrict &&
+                           (pd->pd_flags & KCF_PROV_RESTRICTED))) {
+                               prov_chain = prov_chain->pm_next;
+                               continue;
+                       }
+
+                       if ((len = KCF_PROV_LOAD(pd)) < gqlen) {
+                               gqlen = len;
+                               gpd = pd;
+                       }
+
+                       prov_chain = prov_chain->pm_next;
+               }
+
+               pd = gpd;
+       }
+
+       /* No HW provider for this mech, is there a SW provider? */
+       if (pd == NULL && (mdesc = me->me_sw_prov) != NULL) {
+               pd = mdesc->pm_prov_desc;
+               if (!IS_FG_SUPPORTED(mdesc, fg) ||
+                   !KCF_IS_PROV_USABLE(pd) ||
+                   IS_PROVIDER_TRIED(pd, triedl) ||
+                   (call_restrict && (pd->pd_flags & KCF_PROV_RESTRICTED)))
+                       pd = NULL;
+       }
+
+       if (pd == NULL) {
+               /*
+                * We do not want to report CRYPTO_MECH_NOT_SUPPORTED, when
+                * we are in the "fallback to the next provider" case. Rather
+                * we preserve the error, so that the client gets the right
+                * error code.
+                */
+               if (triedl == NULL)
+                       *error = CRYPTO_MECH_NOT_SUPPORTED;
+       } else
+               KCF_PROV_REFHOLD(pd);
+
+       mutex_exit(&me->me_mutex);
+       return (pd);
+}
+
+/*
+ * Very similar to kcf_get_mech_provider(). Finds the best provider capable of
+ * a dual operation with both me1 and me2.
+ * When no dual-ops capable providers are available, return the best provider
+ * for me1 only, and sets *prov_mt2 to CRYPTO_INVALID_MECHID;
+ * We assume/expect that a slower HW capable of the dual is still
+ * faster than the 2 fastest providers capable of the individual ops
+ * separately.
+ */
+kcf_provider_desc_t *
+kcf_get_dual_provider(crypto_mechanism_t *mech1, crypto_mechanism_t *mech2,
+    kcf_mech_entry_t **mepp, crypto_mech_type_t *prov_mt1,
+    crypto_mech_type_t *prov_mt2, int *error, kcf_prov_tried_t *triedl,
+    crypto_func_group_t fg1, crypto_func_group_t fg2, boolean_t call_restrict,
+    size_t data_size)
+{
+       kcf_provider_desc_t *pd = NULL, *pdm1 = NULL, *pdm1m2 = NULL;
+       kcf_prov_mech_desc_t *prov_chain, *mdesc;
+       int len, gqlen = INT_MAX, dgqlen = INT_MAX;
+       crypto_mech_info_list_t *mil;
+       crypto_mech_type_t m2id =  mech2->cm_type;
+       kcf_mech_entry_t *me;
+
+       /* when mech is a valid mechanism, me will be its mech_entry */
+       if (kcf_get_mech_entry(mech1->cm_type, &me) != KCF_SUCCESS) {
+               *error = CRYPTO_MECHANISM_INVALID;
+               return (NULL);
+       }
+
+       *prov_mt2 = CRYPTO_MECH_INVALID;
+
+       if (mepp != NULL)
+               *mepp = me;
+       mutex_enter(&me->me_mutex);
+
+       prov_chain = me->me_hw_prov_chain;
+       /*
+        * We check the threshold for using a hardware provider for
+        * this amount of data. If there is no software provider available
+        * for the first mechanism, then the threshold is ignored.
+        */
+       if ((prov_chain != NULL) &&
+           ((data_size == 0) || (me->me_threshold == 0) ||
+           (data_size >= me->me_threshold) ||
+           ((mdesc = me->me_sw_prov) == NULL) ||
+           (!IS_FG_SUPPORTED(mdesc, fg1)) ||
+           (!KCF_IS_PROV_USABLE(mdesc->pm_prov_desc)))) {
+               /* there is at least one provider */
+               ASSERT(me->me_num_hwprov > 0);
+
+               /*
+                * Find the least loaded provider capable of the combo
+                * me1 + me2, and save a pointer to the least loaded
+                * provider capable of me1 only.
+                */
+               while (prov_chain != NULL) {
+                       pd = prov_chain->pm_prov_desc;
+                       len = KCF_PROV_LOAD(pd);
+
+                       if (!IS_FG_SUPPORTED(prov_chain, fg1) ||
+                           !KCF_IS_PROV_USABLE(pd) ||
+                           IS_PROVIDER_TRIED(pd, triedl) ||
+                           (call_restrict &&
+                           (pd->pd_flags & KCF_PROV_RESTRICTED))) {
+                               prov_chain = prov_chain->pm_next;
+                               continue;
+                       }
+
+                       /* Save the best provider capable of m1 */
+                       if (len < gqlen) {
+                               *prov_mt1 =
+                                   prov_chain->pm_mech_info.cm_mech_number;
+                               gqlen = len;
+                               pdm1 = pd;
+                       }
+
+                       /* See if pd can do me2 too */
+                       for (mil = prov_chain->pm_mi_list;
+                           mil != NULL; mil = mil->ml_next) {
+                               if ((mil->ml_mech_info.cm_func_group_mask &
+                                   fg2) == 0)
+                                       continue;
+
+                               if ((mil->ml_kcf_mechid == m2id) &&
+                                   (len < dgqlen)) {
+                                       /* Bingo! */
+                                       dgqlen = len;
+                                       pdm1m2 = pd;
+                                       *prov_mt2 =
+                                           mil->ml_mech_info.cm_mech_number;
+                                       *prov_mt1 = prov_chain->
+                                           pm_mech_info.cm_mech_number;
+                                       break;
+                               }
+                       }
+
+                       prov_chain = prov_chain->pm_next;
+               }
+
+               pd =  (pdm1m2 != NULL) ? pdm1m2 : pdm1;
+       }
+
+       /* no HW provider for this mech, is there a SW provider? */
+       if (pd == NULL && (mdesc = me->me_sw_prov) != NULL) {
+               pd = mdesc->pm_prov_desc;
+               if (!IS_FG_SUPPORTED(mdesc, fg1) ||
+                   !KCF_IS_PROV_USABLE(pd) ||
+                   IS_PROVIDER_TRIED(pd, triedl) ||
+                   (call_restrict && (pd->pd_flags & KCF_PROV_RESTRICTED)))
+                       pd = NULL;
+               else {
+                       /* See if pd can do me2 too */
+                       for (mil = me->me_sw_prov->pm_mi_list;
+                           mil != NULL; mil = mil->ml_next) {
+                               if ((mil->ml_mech_info.cm_func_group_mask &
+                                   fg2) == 0)
+                                       continue;
+
+                               if (mil->ml_kcf_mechid == m2id) {
+                                       /* Bingo! */
+                                       *prov_mt2 =
+                                           mil->ml_mech_info.cm_mech_number;
+                                       break;
+                               }
+                       }
+                       *prov_mt1 = me->me_sw_prov->pm_mech_info.cm_mech_number;
+               }
+       }
+
+       if (pd == NULL)
+               *error = CRYPTO_MECH_NOT_SUPPORTED;
+       else
+               KCF_PROV_REFHOLD(pd);
+
+       mutex_exit(&me->me_mutex);
+       return (pd);
+}
+
+/*
+ * Do the actual work of calling the provider routines.
+ *
+ * pd - Provider structure
+ * ctx - Context for this operation
+ * params - Parameters for this operation
+ * rhndl - Request handle to use for notification
+ *
+ * The return values are the same as that of the respective SPI.
+ */
+int
+common_submit_request(kcf_provider_desc_t *pd, crypto_ctx_t *ctx,
+    kcf_req_params_t *params, crypto_req_handle_t rhndl)
+{
+       int err = CRYPTO_ARGUMENTS_BAD;
+       kcf_op_type_t optype;
+
+       optype = params->rp_optype;
+
+       switch (params->rp_opgrp) {
+       case KCF_OG_DIGEST: {
+               kcf_digest_ops_params_t *dops = &params->rp_u.digest_params;
+
+               switch (optype) {
+               case KCF_OP_INIT:
+                       /*
+                        * We should do this only here and not in KCF_WRAP_*
+                        * macros. This is because we may want to try other
+                        * providers, in case we recover from a failure.
+                        */
+                       KCF_SET_PROVIDER_MECHNUM(dops->do_framework_mechtype,
+                           pd, &dops->do_mech);
+
+                       err = KCF_PROV_DIGEST_INIT(pd, ctx, &dops->do_mech,
+                           rhndl);
+                       break;
+
+               case KCF_OP_SINGLE:
+                       err = KCF_PROV_DIGEST(pd, ctx, dops->do_data,
+                           dops->do_digest, rhndl);
+                       break;
+
+               case KCF_OP_UPDATE:
+                       err = KCF_PROV_DIGEST_UPDATE(pd, ctx,
+                           dops->do_data, rhndl);
+                       break;
+
+               case KCF_OP_FINAL:
+                       err = KCF_PROV_DIGEST_FINAL(pd, ctx,
+                           dops->do_digest, rhndl);
+                       break;
+
+               case KCF_OP_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(dops->do_framework_mechtype,
+                           pd, &dops->do_mech);
+                       err = KCF_PROV_DIGEST_ATOMIC(pd, dops->do_sid,
+                           &dops->do_mech, dops->do_data, dops->do_digest,
+                           rhndl);
+                       break;
+
+               case KCF_OP_DIGEST_KEY:
+                       err = KCF_PROV_DIGEST_KEY(pd, ctx, dops->do_digest_key,
+                           rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_MAC: {
+               kcf_mac_ops_params_t *mops = &params->rp_u.mac_params;
+
+               switch (optype) {
+               case KCF_OP_INIT:
+                       KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype,
+                           pd, &mops->mo_mech);
+
+                       err = KCF_PROV_MAC_INIT(pd, ctx, &mops->mo_mech,
+                           mops->mo_key, mops->mo_templ, rhndl);
+                       break;
+
+               case KCF_OP_SINGLE:
+                       err = KCF_PROV_MAC(pd, ctx, mops->mo_data,
+                           mops->mo_mac, rhndl);
+                       break;
+
+               case KCF_OP_UPDATE:
+                       err = KCF_PROV_MAC_UPDATE(pd, ctx, mops->mo_data,
+                           rhndl);
+                       break;
+
+               case KCF_OP_FINAL:
+                       err = KCF_PROV_MAC_FINAL(pd, ctx, mops->mo_mac, rhndl);
+                       break;
+
+               case KCF_OP_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype,
+                           pd, &mops->mo_mech);
+
+                       err = KCF_PROV_MAC_ATOMIC(pd, mops->mo_sid,
+                           &mops->mo_mech, mops->mo_key, mops->mo_data,
+                           mops->mo_mac, mops->mo_templ, rhndl);
+                       break;
+
+               case KCF_OP_MAC_VERIFY_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(mops->mo_framework_mechtype,
+                           pd, &mops->mo_mech);
+
+                       err = KCF_PROV_MAC_VERIFY_ATOMIC(pd, mops->mo_sid,
+                           &mops->mo_mech, mops->mo_key, mops->mo_data,
+                           mops->mo_mac, mops->mo_templ, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_ENCRYPT: {
+               kcf_encrypt_ops_params_t *eops = &params->rp_u.encrypt_params;
+
+               switch (optype) {
+               case KCF_OP_INIT:
+                       KCF_SET_PROVIDER_MECHNUM(eops->eo_framework_mechtype,
+                           pd, &eops->eo_mech);
+
+                       err = KCF_PROV_ENCRYPT_INIT(pd, ctx, &eops->eo_mech,
+                           eops->eo_key, eops->eo_templ, rhndl);
+                       break;
+
+               case KCF_OP_SINGLE:
+                       err = KCF_PROV_ENCRYPT(pd, ctx, eops->eo_plaintext,
+                           eops->eo_ciphertext, rhndl);
+                       break;
+
+               case KCF_OP_UPDATE:
+                       err = KCF_PROV_ENCRYPT_UPDATE(pd, ctx,
+                           eops->eo_plaintext, eops->eo_ciphertext, rhndl);
+                       break;
+
+               case KCF_OP_FINAL:
+                       err = KCF_PROV_ENCRYPT_FINAL(pd, ctx,
+                           eops->eo_ciphertext, rhndl);
+                       break;
+
+               case KCF_OP_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(eops->eo_framework_mechtype,
+                           pd, &eops->eo_mech);
+
+                       err = KCF_PROV_ENCRYPT_ATOMIC(pd, eops->eo_sid,
+                           &eops->eo_mech, eops->eo_key, eops->eo_plaintext,
+                           eops->eo_ciphertext, eops->eo_templ, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_DECRYPT: {
+               kcf_decrypt_ops_params_t *dcrops = &params->rp_u.decrypt_params;
+
+               switch (optype) {
+               case KCF_OP_INIT:
+                       KCF_SET_PROVIDER_MECHNUM(dcrops->dop_framework_mechtype,
+                           pd, &dcrops->dop_mech);
+
+                       err = KCF_PROV_DECRYPT_INIT(pd, ctx, &dcrops->dop_mech,
+                           dcrops->dop_key, dcrops->dop_templ, rhndl);
+                       break;
+
+               case KCF_OP_SINGLE:
+                       err = KCF_PROV_DECRYPT(pd, ctx, dcrops->dop_ciphertext,
+                           dcrops->dop_plaintext, rhndl);
+                       break;
+
+               case KCF_OP_UPDATE:
+                       err = KCF_PROV_DECRYPT_UPDATE(pd, ctx,
+                           dcrops->dop_ciphertext, dcrops->dop_plaintext,
+                           rhndl);
+                       break;
+
+               case KCF_OP_FINAL:
+                       err = KCF_PROV_DECRYPT_FINAL(pd, ctx,
+                           dcrops->dop_plaintext, rhndl);
+                       break;
+
+               case KCF_OP_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(dcrops->dop_framework_mechtype,
+                           pd, &dcrops->dop_mech);
+
+                       err = KCF_PROV_DECRYPT_ATOMIC(pd, dcrops->dop_sid,
+                           &dcrops->dop_mech, dcrops->dop_key,
+                           dcrops->dop_ciphertext, dcrops->dop_plaintext,
+                           dcrops->dop_templ, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_SIGN: {
+               kcf_sign_ops_params_t *sops = &params->rp_u.sign_params;
+
+               switch (optype) {
+               case KCF_OP_INIT:
+                       KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype,
+                           pd, &sops->so_mech);
+
+                       err = KCF_PROV_SIGN_INIT(pd, ctx, &sops->so_mech,
+                           sops->so_key, sops->so_templ, rhndl);
+                       break;
+
+               case KCF_OP_SIGN_RECOVER_INIT:
+                       KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype,
+                           pd, &sops->so_mech);
+
+                       err = KCF_PROV_SIGN_RECOVER_INIT(pd, ctx,
+                           &sops->so_mech, sops->so_key, sops->so_templ,
+                           rhndl);
+                       break;
+
+               case KCF_OP_SINGLE:
+                       err = KCF_PROV_SIGN(pd, ctx, sops->so_data,
+                           sops->so_signature, rhndl);
+                       break;
+
+               case KCF_OP_SIGN_RECOVER:
+                       err = KCF_PROV_SIGN_RECOVER(pd, ctx,
+                           sops->so_data, sops->so_signature, rhndl);
+                       break;
+
+               case KCF_OP_UPDATE:
+                       err = KCF_PROV_SIGN_UPDATE(pd, ctx, sops->so_data,
+                           rhndl);
+                       break;
+
+               case KCF_OP_FINAL:
+                       err = KCF_PROV_SIGN_FINAL(pd, ctx, sops->so_signature,
+                           rhndl);
+                       break;
+
+               case KCF_OP_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype,
+                           pd, &sops->so_mech);
+
+                       err = KCF_PROV_SIGN_ATOMIC(pd, sops->so_sid,
+                           &sops->so_mech, sops->so_key, sops->so_data,
+                           sops->so_templ, sops->so_signature, rhndl);
+                       break;
+
+               case KCF_OP_SIGN_RECOVER_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(sops->so_framework_mechtype,
+                           pd, &sops->so_mech);
+
+                       err = KCF_PROV_SIGN_RECOVER_ATOMIC(pd, sops->so_sid,
+                           &sops->so_mech, sops->so_key, sops->so_data,
+                           sops->so_templ, sops->so_signature, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_VERIFY: {
+               kcf_verify_ops_params_t *vops = &params->rp_u.verify_params;
+
+               switch (optype) {
+               case KCF_OP_INIT:
+                       KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype,
+                           pd, &vops->vo_mech);
+
+                       err = KCF_PROV_VERIFY_INIT(pd, ctx, &vops->vo_mech,
+                           vops->vo_key, vops->vo_templ, rhndl);
+                       break;
+
+               case KCF_OP_VERIFY_RECOVER_INIT:
+                       KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype,
+                           pd, &vops->vo_mech);
+
+                       err = KCF_PROV_VERIFY_RECOVER_INIT(pd, ctx,
+                           &vops->vo_mech, vops->vo_key, vops->vo_templ,
+                           rhndl);
+                       break;
+
+               case KCF_OP_SINGLE:
+                       err = KCF_PROV_VERIFY(pd, ctx, vops->vo_data,
+                           vops->vo_signature, rhndl);
+                       break;
+
+               case KCF_OP_VERIFY_RECOVER:
+                       err = KCF_PROV_VERIFY_RECOVER(pd, ctx,
+                           vops->vo_signature, vops->vo_data, rhndl);
+                       break;
+
+               case KCF_OP_UPDATE:
+                       err = KCF_PROV_VERIFY_UPDATE(pd, ctx, vops->vo_data,
+                           rhndl);
+                       break;
+
+               case KCF_OP_FINAL:
+                       err = KCF_PROV_VERIFY_FINAL(pd, ctx, vops->vo_signature,
+                           rhndl);
+                       break;
+
+               case KCF_OP_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype,
+                           pd, &vops->vo_mech);
+
+                       err = KCF_PROV_VERIFY_ATOMIC(pd, vops->vo_sid,
+                           &vops->vo_mech, vops->vo_key, vops->vo_data,
+                           vops->vo_templ, vops->vo_signature, rhndl);
+                       break;
+
+               case KCF_OP_VERIFY_RECOVER_ATOMIC:
+                       ASSERT(ctx == NULL);
+                       KCF_SET_PROVIDER_MECHNUM(vops->vo_framework_mechtype,
+                           pd, &vops->vo_mech);
+
+                       err = KCF_PROV_VERIFY_RECOVER_ATOMIC(pd, vops->vo_sid,
+                           &vops->vo_mech, vops->vo_key, vops->vo_signature,
+                           vops->vo_templ, vops->vo_data, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_ENCRYPT_MAC: {
+               kcf_encrypt_mac_ops_params_t *eops =
+                   &params->rp_u.encrypt_mac_params;
+               kcf_context_t *kcf_secondctx;
+
+               switch (optype) {
+               case KCF_OP_INIT:
+                       kcf_secondctx = ((kcf_context_t *)
+                           (ctx->cc_framework_private))->kc_secondctx;
+
+                       if (kcf_secondctx != NULL) {
+                               err = kcf_emulate_dual(pd, ctx, params);
+                               break;
+                       }
+                       KCF_SET_PROVIDER_MECHNUM(
+                           eops->em_framework_encr_mechtype,
+                           pd, &eops->em_encr_mech);
+
+                       KCF_SET_PROVIDER_MECHNUM(
+                           eops->em_framework_mac_mechtype,
+                           pd, &eops->em_mac_mech);
+
+                       err = KCF_PROV_ENCRYPT_MAC_INIT(pd, ctx,
+                           &eops->em_encr_mech, eops->em_encr_key,
+                           &eops->em_mac_mech, eops->em_mac_key,
+                           eops->em_encr_templ, eops->em_mac_templ,
+                           rhndl);
+
+                       break;
+
+               case KCF_OP_SINGLE:
+                       err = KCF_PROV_ENCRYPT_MAC(pd, ctx,
+                           eops->em_plaintext, eops->em_ciphertext,
+                           eops->em_mac, rhndl);
+                       break;
+
+               case KCF_OP_UPDATE:
+                       kcf_secondctx = ((kcf_context_t *)
+                           (ctx->cc_framework_private))->kc_secondctx;
+                       if (kcf_secondctx != NULL) {
+                               err = kcf_emulate_dual(pd, ctx, params);
+                               break;
+                       }
+                       err = KCF_PROV_ENCRYPT_MAC_UPDATE(pd, ctx,
+                           eops->em_plaintext, eops->em_ciphertext, rhndl);
+                       break;
+
+               case KCF_OP_FINAL:
+                       kcf_secondctx = ((kcf_context_t *)
+                           (ctx->cc_framework_private))->kc_secondctx;
+                       if (kcf_secondctx != NULL) {
+                               err = kcf_emulate_dual(pd, ctx, params);
+                               break;
+                       }
+                       err = KCF_PROV_ENCRYPT_MAC_FINAL(pd, ctx,
+                           eops->em_ciphertext, eops->em_mac, rhndl);
+                       break;
+
+               case KCF_OP_ATOMIC:
+                       ASSERT(ctx == NULL);
+
+                       KCF_SET_PROVIDER_MECHNUM(
+                           eops->em_framework_encr_mechtype,
+                           pd, &eops->em_encr_mech);
+
+                       KCF_SET_PROVIDER_MECHNUM(
+                           eops->em_framework_mac_mechtype,
+                           pd, &eops->em_mac_mech);
+
+                       err = KCF_PROV_ENCRYPT_MAC_ATOMIC(pd, eops->em_sid,
+                           &eops->em_encr_mech, eops->em_encr_key,
+                           &eops->em_mac_mech, eops->em_mac_key,
+                           eops->em_plaintext, eops->em_ciphertext,
+                           eops->em_mac,
+                           eops->em_encr_templ, eops->em_mac_templ,
+                           rhndl);
+
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_MAC_DECRYPT: {
+               kcf_mac_decrypt_ops_params_t *dops =
+                   &params->rp_u.mac_decrypt_params;
+               kcf_context_t *kcf_secondctx;
+
+               switch (optype) {
+               case KCF_OP_INIT:
+                       kcf_secondctx = ((kcf_context_t *)
+                           (ctx->cc_framework_private))->kc_secondctx;
+
+                       if (kcf_secondctx != NULL) {
+                               err = kcf_emulate_dual(pd, ctx, params);
+                               break;
+                       }
+                       KCF_SET_PROVIDER_MECHNUM(
+                           dops->md_framework_mac_mechtype,
+                           pd, &dops->md_mac_mech);
+
+                       KCF_SET_PROVIDER_MECHNUM(
+                           dops->md_framework_decr_mechtype,
+                           pd, &dops->md_decr_mech);
+
+                       err = KCF_PROV_MAC_DECRYPT_INIT(pd, ctx,
+                           &dops->md_mac_mech, dops->md_mac_key,
+                           &dops->md_decr_mech, dops->md_decr_key,
+                           dops->md_mac_templ, dops->md_decr_templ,
+                           rhndl);
+
+                       break;
+
+               case KCF_OP_SINGLE:
+                       err = KCF_PROV_MAC_DECRYPT(pd, ctx,
+                           dops->md_ciphertext, dops->md_mac,
+                           dops->md_plaintext, rhndl);
+                       break;
+
+               case KCF_OP_UPDATE:
+                       kcf_secondctx = ((kcf_context_t *)
+                           (ctx->cc_framework_private))->kc_secondctx;
+                       if (kcf_secondctx != NULL) {
+                               err = kcf_emulate_dual(pd, ctx, params);
+                               break;
+                       }
+                       err = KCF_PROV_MAC_DECRYPT_UPDATE(pd, ctx,
+                           dops->md_ciphertext, dops->md_plaintext, rhndl);
+                       break;
+
+               case KCF_OP_FINAL:
+                       kcf_secondctx = ((kcf_context_t *)
+                           (ctx->cc_framework_private))->kc_secondctx;
+                       if (kcf_secondctx != NULL) {
+                               err = kcf_emulate_dual(pd, ctx, params);
+                               break;
+                       }
+                       err = KCF_PROV_MAC_DECRYPT_FINAL(pd, ctx,
+                           dops->md_mac, dops->md_plaintext, rhndl);
+                       break;
+
+               case KCF_OP_ATOMIC:
+                       ASSERT(ctx == NULL);
+
+                       KCF_SET_PROVIDER_MECHNUM(
+                           dops->md_framework_mac_mechtype,
+                           pd, &dops->md_mac_mech);
+
+                       KCF_SET_PROVIDER_MECHNUM(
+                           dops->md_framework_decr_mechtype,
+                           pd, &dops->md_decr_mech);
+
+                       err = KCF_PROV_MAC_DECRYPT_ATOMIC(pd, dops->md_sid,
+                           &dops->md_mac_mech, dops->md_mac_key,
+                           &dops->md_decr_mech, dops->md_decr_key,
+                           dops->md_ciphertext, dops->md_mac,
+                           dops->md_plaintext,
+                           dops->md_mac_templ, dops->md_decr_templ,
+                           rhndl);
+
+                       break;
+
+               case KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC:
+                       ASSERT(ctx == NULL);
+
+                       KCF_SET_PROVIDER_MECHNUM(
+                           dops->md_framework_mac_mechtype,
+                           pd, &dops->md_mac_mech);
+
+                       KCF_SET_PROVIDER_MECHNUM(
+                           dops->md_framework_decr_mechtype,
+                           pd, &dops->md_decr_mech);
+
+                       err = KCF_PROV_MAC_VERIFY_DECRYPT_ATOMIC(pd,
+                           dops->md_sid, &dops->md_mac_mech, dops->md_mac_key,
+                           &dops->md_decr_mech, dops->md_decr_key,
+                           dops->md_ciphertext, dops->md_mac,
+                           dops->md_plaintext,
+                           dops->md_mac_templ, dops->md_decr_templ,
+                           rhndl);
+
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_KEY: {
+               kcf_key_ops_params_t *kops = &params->rp_u.key_params;
+
+               ASSERT(ctx == NULL);
+               KCF_SET_PROVIDER_MECHNUM(kops->ko_framework_mechtype, pd,
+                   &kops->ko_mech);
+
+               switch (optype) {
+               case KCF_OP_KEY_GENERATE:
+                       err = KCF_PROV_KEY_GENERATE(pd, kops->ko_sid,
+                           &kops->ko_mech,
+                           kops->ko_key_template, kops->ko_key_attribute_count,
+                           kops->ko_key_object_id_ptr, rhndl);
+                       break;
+
+               case KCF_OP_KEY_GENERATE_PAIR:
+                       err = KCF_PROV_KEY_GENERATE_PAIR(pd, kops->ko_sid,
+                           &kops->ko_mech,
+                           kops->ko_key_template, kops->ko_key_attribute_count,
+                           kops->ko_private_key_template,
+                           kops->ko_private_key_attribute_count,
+                           kops->ko_key_object_id_ptr,
+                           kops->ko_private_key_object_id_ptr, rhndl);
+                       break;
+
+               case KCF_OP_KEY_WRAP:
+                       err = KCF_PROV_KEY_WRAP(pd, kops->ko_sid,
+                           &kops->ko_mech,
+                           kops->ko_key, kops->ko_key_object_id_ptr,
+                           kops->ko_wrapped_key, kops->ko_wrapped_key_len_ptr,
+                           rhndl);
+                       break;
+
+               case KCF_OP_KEY_UNWRAP:
+                       err = KCF_PROV_KEY_UNWRAP(pd, kops->ko_sid,
+                           &kops->ko_mech,
+                           kops->ko_key, kops->ko_wrapped_key,
+                           kops->ko_wrapped_key_len_ptr,
+                           kops->ko_key_template, kops->ko_key_attribute_count,
+                           kops->ko_key_object_id_ptr, rhndl);
+                       break;
+
+               case KCF_OP_KEY_DERIVE:
+                       err = KCF_PROV_KEY_DERIVE(pd, kops->ko_sid,
+                           &kops->ko_mech,
+                           kops->ko_key, kops->ko_key_template,
+                           kops->ko_key_attribute_count,
+                           kops->ko_key_object_id_ptr, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_RANDOM: {
+               kcf_random_number_ops_params_t *rops =
+                   &params->rp_u.random_number_params;
+
+               ASSERT(ctx == NULL);
+
+               switch (optype) {
+               case KCF_OP_RANDOM_SEED:
+                       err = KCF_PROV_SEED_RANDOM(pd, rops->rn_sid,
+                           rops->rn_buf, rops->rn_buflen, rops->rn_entropy_est,
+                           rops->rn_flags, rhndl);
+                       break;
+
+               case KCF_OP_RANDOM_GENERATE:
+                       err = KCF_PROV_GENERATE_RANDOM(pd, rops->rn_sid,
+                           rops->rn_buf, rops->rn_buflen, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_SESSION: {
+               kcf_session_ops_params_t *sops = &params->rp_u.session_params;
+
+               ASSERT(ctx == NULL);
+               switch (optype) {
+               case KCF_OP_SESSION_OPEN:
+                       /*
+                        * so_pd may be a logical provider, in which case
+                        * we need to check whether it has been removed.
+                        */
+                       if (KCF_IS_PROV_REMOVED(sops->so_pd)) {
+                               err = CRYPTO_DEVICE_ERROR;
+                               break;
+                       }
+                       err = KCF_PROV_SESSION_OPEN(pd, sops->so_sid_ptr,
+                           rhndl, sops->so_pd);
+                       break;
+
+               case KCF_OP_SESSION_CLOSE:
+                       /*
+                        * so_pd may be a logical provider, in which case
+                        * we need to check whether it has been removed.
+                        */
+                       if (KCF_IS_PROV_REMOVED(sops->so_pd)) {
+                               err = CRYPTO_DEVICE_ERROR;
+                               break;
+                       }
+                       err = KCF_PROV_SESSION_CLOSE(pd, sops->so_sid,
+                           rhndl, sops->so_pd);
+                       break;
+
+               case KCF_OP_SESSION_LOGIN:
+                       err = KCF_PROV_SESSION_LOGIN(pd, sops->so_sid,
+                           sops->so_user_type, sops->so_pin,
+                           sops->so_pin_len, rhndl);
+                       break;
+
+               case KCF_OP_SESSION_LOGOUT:
+                       err = KCF_PROV_SESSION_LOGOUT(pd, sops->so_sid, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_OBJECT: {
+               kcf_object_ops_params_t *jops = &params->rp_u.object_params;
+
+               ASSERT(ctx == NULL);
+               switch (optype) {
+               case KCF_OP_OBJECT_CREATE:
+                       err = KCF_PROV_OBJECT_CREATE(pd, jops->oo_sid,
+                           jops->oo_template, jops->oo_attribute_count,
+                           jops->oo_object_id_ptr, rhndl);
+                       break;
+
+               case KCF_OP_OBJECT_COPY:
+                       err = KCF_PROV_OBJECT_COPY(pd, jops->oo_sid,
+                           jops->oo_object_id,
+                           jops->oo_template, jops->oo_attribute_count,
+                           jops->oo_object_id_ptr, rhndl);
+                       break;
+
+               case KCF_OP_OBJECT_DESTROY:
+                       err = KCF_PROV_OBJECT_DESTROY(pd, jops->oo_sid,
+                           jops->oo_object_id, rhndl);
+                       break;
+
+               case KCF_OP_OBJECT_GET_SIZE:
+                       err = KCF_PROV_OBJECT_GET_SIZE(pd, jops->oo_sid,
+                           jops->oo_object_id, jops->oo_object_size, rhndl);
+                       break;
+
+               case KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE:
+                       err = KCF_PROV_OBJECT_GET_ATTRIBUTE_VALUE(pd,
+                           jops->oo_sid, jops->oo_object_id,
+                           jops->oo_template, jops->oo_attribute_count, rhndl);
+                       break;
+
+               case KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE:
+                       err = KCF_PROV_OBJECT_SET_ATTRIBUTE_VALUE(pd,
+                           jops->oo_sid, jops->oo_object_id,
+                           jops->oo_template, jops->oo_attribute_count, rhndl);
+                       break;
+
+               case KCF_OP_OBJECT_FIND_INIT:
+                       err = KCF_PROV_OBJECT_FIND_INIT(pd, jops->oo_sid,
+                           jops->oo_template, jops->oo_attribute_count,
+                           jops->oo_find_init_pp_ptr, rhndl);
+                       break;
+
+               case KCF_OP_OBJECT_FIND:
+                       err = KCF_PROV_OBJECT_FIND(pd, jops->oo_find_pp,
+                           jops->oo_object_id_ptr, jops->oo_max_object_count,
+                           jops->oo_object_count_ptr, rhndl);
+                       break;
+
+               case KCF_OP_OBJECT_FIND_FINAL:
+                       err = KCF_PROV_OBJECT_FIND_FINAL(pd, jops->oo_find_pp,
+                           rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_PROVMGMT: {
+               kcf_provmgmt_ops_params_t *pops = &params->rp_u.provmgmt_params;
+
+               ASSERT(ctx == NULL);
+               switch (optype) {
+               case KCF_OP_MGMT_EXTINFO:
+                       /*
+                        * po_pd may be a logical provider, in which case
+                        * we need to check whether it has been removed.
+                        */
+                       if (KCF_IS_PROV_REMOVED(pops->po_pd)) {
+                               err = CRYPTO_DEVICE_ERROR;
+                               break;
+                       }
+                       err = KCF_PROV_EXT_INFO(pd, pops->po_ext_info, rhndl,
+                           pops->po_pd);
+                       break;
+
+               case KCF_OP_MGMT_INITTOKEN:
+                       err = KCF_PROV_INIT_TOKEN(pd, pops->po_pin,
+                           pops->po_pin_len, pops->po_label, rhndl);
+                       break;
+
+               case KCF_OP_MGMT_INITPIN:
+                       err = KCF_PROV_INIT_PIN(pd, pops->po_sid, pops->po_pin,
+                           pops->po_pin_len, rhndl);
+                       break;
+
+               case KCF_OP_MGMT_SETPIN:
+                       err = KCF_PROV_SET_PIN(pd, pops->po_sid,
+                           pops->po_old_pin, pops->po_old_pin_len,
+                           pops->po_pin, pops->po_pin_len, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
+       case KCF_OG_NOSTORE_KEY: {
+               kcf_key_ops_params_t *kops = &params->rp_u.key_params;
+
+               ASSERT(ctx == NULL);
+               KCF_SET_PROVIDER_MECHNUM(kops->ko_framework_mechtype, pd,
+                   &kops->ko_mech);
+
+               switch (optype) {
+               case KCF_OP_KEY_GENERATE:
+                       err = KCF_PROV_NOSTORE_KEY_GENERATE(pd, kops->ko_sid,
+                           &kops->ko_mech, kops->ko_key_template,
+                           kops->ko_key_attribute_count,
+                           kops->ko_out_template1,
+                           kops->ko_out_attribute_count1, rhndl);
+                       break;
+
+               case KCF_OP_KEY_GENERATE_PAIR:
+                       err = KCF_PROV_NOSTORE_KEY_GENERATE_PAIR(pd,
+                           kops->ko_sid, &kops->ko_mech,
+                           kops->ko_key_template, kops->ko_key_attribute_count,
+                           kops->ko_private_key_template,
+                           kops->ko_private_key_attribute_count,
+                           kops->ko_out_template1,
+                           kops->ko_out_attribute_count1,
+                           kops->ko_out_template2,
+                           kops->ko_out_attribute_count2,
+                           rhndl);
+                       break;
+
+               case KCF_OP_KEY_DERIVE:
+                       err = KCF_PROV_NOSTORE_KEY_DERIVE(pd, kops->ko_sid,
+                           &kops->ko_mech, kops->ko_key,
+                           kops->ko_key_template,
+                           kops->ko_key_attribute_count,
+                           kops->ko_out_template1,
+                           kops->ko_out_attribute_count1, rhndl);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+       default:
+               break;
+       }               /* end of switch(params->rp_opgrp) */
+
+       KCF_PROV_INCRSTATS(pd, err);
+       return (err);
+}
+
+
+/*
+ * Emulate the call for a multipart dual ops with 2 single steps.
+ * This routine is always called in the context of a working thread
+ * running kcf_svc_do_run().
+ * The single steps are submitted in a pure synchronous way (blocking).
+ * When this routine returns, kcf_svc_do_run() will call kcf_aop_done()
+ * so the originating consumer's callback gets invoked. kcf_aop_done()
+ * takes care of freeing the operation context. So, this routine does
+ * not free the operation context.
+ *
+ * The provider descriptor is assumed held by the callers.
+ */
+static int
+kcf_emulate_dual(kcf_provider_desc_t *pd, crypto_ctx_t *ctx,
+    kcf_req_params_t *params)
+{
+       int err = CRYPTO_ARGUMENTS_BAD;
+       kcf_op_type_t optype;
+       size_t save_len;
+       off_t save_offset;
+
+       optype = params->rp_optype;
+
+       switch (params->rp_opgrp) {
+       case KCF_OG_ENCRYPT_MAC: {
+               kcf_encrypt_mac_ops_params_t *cmops =
+                   &params->rp_u.encrypt_mac_params;
+               kcf_context_t *encr_kcf_ctx;
+               crypto_ctx_t *mac_ctx;
+               kcf_req_params_t encr_params;
+
+               encr_kcf_ctx = (kcf_context_t *)(ctx->cc_framework_private);
+
+               switch (optype) {
+               case KCF_OP_INIT: {
+                       encr_kcf_ctx->kc_secondctx = NULL;
+
+                       KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_INIT,
+                           pd->pd_sid, &cmops->em_encr_mech,
+                           cmops->em_encr_key, NULL, NULL,
+                           cmops->em_encr_templ);
+
+                       err = kcf_submit_request(pd, ctx, NULL, &encr_params,
+                           B_FALSE);
+
+                       /* It can't be CRYPTO_QUEUED */
+                       if (err != CRYPTO_SUCCESS) {
+                               break;
+                       }
+
+                       err = crypto_mac_init(&cmops->em_mac_mech,
+                           cmops->em_mac_key, cmops->em_mac_templ,
+                           (crypto_context_t *)&mac_ctx, NULL);
+
+                       if (err == CRYPTO_SUCCESS) {
+                               encr_kcf_ctx->kc_secondctx = (kcf_context_t *)
+                                   mac_ctx->cc_framework_private;
+                               KCF_CONTEXT_REFHOLD((kcf_context_t *)
+                                   mac_ctx->cc_framework_private);
+                       }
+
+                       break;
+
+               }
+               case KCF_OP_UPDATE: {
+                       crypto_dual_data_t *ct = cmops->em_ciphertext;
+                       crypto_data_t *pt = cmops->em_plaintext;
+                       kcf_context_t *mac_kcf_ctx = encr_kcf_ctx->kc_secondctx;
+                       crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx;
+
+                       KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_UPDATE,
+                           pd->pd_sid, NULL, NULL, pt, (crypto_data_t *)ct,
+                           NULL);
+
+                       err = kcf_submit_request(pd, ctx, NULL, &encr_params,
+                           B_FALSE);
+
+                       /* It can't be CRYPTO_QUEUED */
+                       if (err != CRYPTO_SUCCESS) {
+                               break;
+                       }
+
+                       save_offset = ct->dd_offset1;
+                       save_len = ct->dd_len1;
+                       if (ct->dd_len2 == 0) {
+                               /*
+                                * The previous encrypt step was an
+                                * accumulation only and didn't produce any
+                                * partial output
+                                */
+                               if (ct->dd_len1 == 0)
+                                       break;
+
+                       } else {
+                               ct->dd_offset1 = ct->dd_offset2;
+                               ct->dd_len1 = ct->dd_len2;
+                       }
+                       err = crypto_mac_update((crypto_context_t)mac_ctx,
+                           (crypto_data_t *)ct, NULL);
+
+                       ct->dd_offset1 = save_offset;
+                       ct->dd_len1 = save_len;
+
+                       break;
+               }
+               case KCF_OP_FINAL: {
+                       crypto_dual_data_t *ct = cmops->em_ciphertext;
+                       crypto_data_t *mac = cmops->em_mac;
+                       kcf_context_t *mac_kcf_ctx = encr_kcf_ctx->kc_secondctx;
+                       crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx;
+                       crypto_context_t mac_context = mac_ctx;
+
+                       KCF_WRAP_ENCRYPT_OPS_PARAMS(&encr_params, KCF_OP_FINAL,
+                           pd->pd_sid, NULL, NULL, NULL, (crypto_data_t *)ct,
+                           NULL);
+
+                       err = kcf_submit_request(pd, ctx, NULL, &encr_params,
+                           B_FALSE);
+
+                       /* It can't be CRYPTO_QUEUED */
+                       if (err != CRYPTO_SUCCESS) {
+                               crypto_cancel_ctx(mac_context);
+                               break;
+                       }
+
+                       if (ct->dd_len2 > 0) {
+                               save_offset = ct->dd_offset1;
+                               save_len = ct->dd_len1;
+                               ct->dd_offset1 = ct->dd_offset2;
+                               ct->dd_len1 = ct->dd_len2;
+
+                               err = crypto_mac_update(mac_context,
+                                   (crypto_data_t *)ct, NULL);
+
+                               ct->dd_offset1 = save_offset;
+                               ct->dd_len1 = save_len;
+
+                               if (err != CRYPTO_SUCCESS)  {
+                                       crypto_cancel_ctx(mac_context);
+                                       return (err);
+                               }
+                       }
+
+                       /* and finally, collect the MAC */
+                       err = crypto_mac_final(mac_context, mac, NULL);
+                       break;
+               }
+
+               default:
+                       break;
+               }
+               KCF_PROV_INCRSTATS(pd, err);
+               break;
+       }
+       case KCF_OG_MAC_DECRYPT: {
+               kcf_mac_decrypt_ops_params_t *mdops =
+                   &params->rp_u.mac_decrypt_params;
+               kcf_context_t *decr_kcf_ctx;
+               crypto_ctx_t *mac_ctx;
+               kcf_req_params_t decr_params;
+
+               decr_kcf_ctx = (kcf_context_t *)(ctx->cc_framework_private);
+
+               switch (optype) {
+               case KCF_OP_INIT: {
+                       decr_kcf_ctx->kc_secondctx = NULL;
+
+                       err = crypto_mac_init(&mdops->md_mac_mech,
+                           mdops->md_mac_key, mdops->md_mac_templ,
+                           (crypto_context_t *)&mac_ctx, NULL);
+
+                       /* It can't be CRYPTO_QUEUED */
+                       if (err != CRYPTO_SUCCESS) {
+                               break;
+                       }
+
+                       KCF_WRAP_DECRYPT_OPS_PARAMS(&decr_params, KCF_OP_INIT,
+                           pd->pd_sid, &mdops->md_decr_mech,
+                           mdops->md_decr_key, NULL, NULL,
+                           mdops->md_decr_templ);
+
+                       err = kcf_submit_request(pd, ctx, NULL, &decr_params,
+                           B_FALSE);
+
+                       /* It can't be CRYPTO_QUEUED */
+                       if (err != CRYPTO_SUCCESS) {
+                               crypto_cancel_ctx((crypto_context_t)mac_ctx);
+                               break;
+                       }
+
+                       decr_kcf_ctx->kc_secondctx = (kcf_context_t *)
+                           mac_ctx->cc_framework_private;
+                       KCF_CONTEXT_REFHOLD((kcf_context_t *)
+                           mac_ctx->cc_framework_private);
+
+                       break;
+               default:
+                       break;
+
+               }
+               case KCF_OP_UPDATE: {
+                       crypto_dual_data_t *ct = mdops->md_ciphertext;
+                       crypto_data_t *pt = mdops->md_plaintext;
+                       kcf_context_t *mac_kcf_ctx = decr_kcf_ctx->kc_secondctx;
+                       crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx;
+
+                       err = crypto_mac_update((crypto_context_t)mac_ctx,
+                           (crypto_data_t *)ct, NULL);
+
+                       if (err != CRYPTO_SUCCESS)
+                               break;
+
+                       save_offset = ct->dd_offset1;
+                       save_len = ct->dd_len1;
+
+                       /* zero ct->dd_len2 means decrypt everything */
+                       if (ct->dd_len2 > 0) {
+                               ct->dd_offset1 = ct->dd_offset2;
+                               ct->dd_len1 = ct->dd_len2;
+                       }
+
+                       err = crypto_decrypt_update((crypto_context_t)ctx,
+                           (crypto_data_t *)ct, pt, NULL);
+
+                       ct->dd_offset1 = save_offset;
+                       ct->dd_len1 = save_len;
+
+                       break;
+               }
+               case KCF_OP_FINAL: {
+                       crypto_data_t *pt = mdops->md_plaintext;
+                       crypto_data_t *mac = mdops->md_mac;
+                       kcf_context_t *mac_kcf_ctx = decr_kcf_ctx->kc_secondctx;
+                       crypto_ctx_t *mac_ctx = &mac_kcf_ctx->kc_glbl_ctx;
+
+                       err = crypto_mac_final((crypto_context_t)mac_ctx,
+                           mac, NULL);
+
+                       if (err != CRYPTO_SUCCESS) {
+                               crypto_cancel_ctx(ctx);
+                               break;
+                       }
+
+                       /* Get the last chunk of plaintext */
+                       KCF_CONTEXT_REFHOLD(decr_kcf_ctx);
+                       err = crypto_decrypt_final((crypto_context_t)ctx, pt,
+                           NULL);
+
+                       break;
+               }
+               }
+               break;
+       }
+       default:
+
+               break;
+       }               /* end of switch(params->rp_opgrp) */
+
+       return (err);
+}
diff --git a/zfs/module/icp/core/kcf_mech_tabs.c b/zfs/module/icp/core/kcf_mech_tabs.c
new file mode 100644 (file)
index 0000000..3ed1547
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/impl.h>
+#include <sys/modhash.h>
+
+/* Cryptographic mechanisms tables and their access functions */
+
+/*
+ * Internal numbers assigned to mechanisms are coded as follows:
+ *
+ * +----------------+----------------+
+ * | mech. class    | mech. index    |
+ * <--- 32-bits --->+<--- 32-bits --->
+ *
+ * the mech_class identifies the table the mechanism belongs to.
+ * mech_index  is the index for that mechanism in the table.
+ * A mechanism belongs to exactly 1 table.
+ * The tables are:
+ * . digest_mechs_tab[] for the msg digest mechs.
+ * . cipher_mechs_tab[] for encrypt/decrypt and wrap/unwrap mechs.
+ * . mac_mechs_tab[] for MAC mechs.
+ * . sign_mechs_tab[] for sign & verify mechs.
+ * . keyops_mechs_tab[] for key/key pair generation, and key derivation.
+ * . misc_mechs_tab[] for mechs that don't belong to any of the above.
+ *
+ * There are no holes in the tables.
+ */
+
+/*
+ * Locking conventions:
+ * --------------------
+ * A global mutex, kcf_mech_tabs_lock, serializes writes to the
+ * mechanism table via kcf_create_mech_entry().
+ *
+ * A mutex is associated with every entry of the tables.
+ * The mutex is acquired whenever the entry is accessed for
+ * 1) retrieving the mech_id (comparing the mech name)
+ * 2) finding a provider for an xxx_init() or atomic operation.
+ * 3) altering the mechs entry to add or remove a provider.
+ *
+ * In 2), after a provider is chosen, its prov_desc is held and the
+ * entry's mutex must be dropped. The provider's working function (SPI) is
+ * called outside the mech_entry's mutex.
+ *
+ * The number of providers for a particular mechanism is not expected to be
+ * long enough to justify the cost of using rwlocks, so the per-mechanism
+ * entry mutex won't be very *hot*.
+ *
+ * When both kcf_mech_tabs_lock and a mech_entry mutex need to be held,
+ * kcf_mech_tabs_lock must always be acquired first.
+ *
+ */
+
+               /* Mechanisms tables */
+
+
+/* RFE 4687834 Will deal with the extensibility of these tables later */
+
+kcf_mech_entry_t kcf_digest_mechs_tab[KCF_MAXDIGEST];
+kcf_mech_entry_t kcf_cipher_mechs_tab[KCF_MAXCIPHER];
+kcf_mech_entry_t kcf_mac_mechs_tab[KCF_MAXMAC];
+kcf_mech_entry_t kcf_sign_mechs_tab[KCF_MAXSIGN];
+kcf_mech_entry_t kcf_keyops_mechs_tab[KCF_MAXKEYOPS];
+kcf_mech_entry_t kcf_misc_mechs_tab[KCF_MAXMISC];
+
+kcf_mech_entry_tab_t kcf_mech_tabs_tab[KCF_LAST_OPSCLASS + 1] = {
+       {0, NULL},                              /* No class zero */
+       {KCF_MAXDIGEST, kcf_digest_mechs_tab},
+       {KCF_MAXCIPHER, kcf_cipher_mechs_tab},
+       {KCF_MAXMAC, kcf_mac_mechs_tab},
+       {KCF_MAXSIGN, kcf_sign_mechs_tab},
+       {KCF_MAXKEYOPS, kcf_keyops_mechs_tab},
+       {KCF_MAXMISC, kcf_misc_mechs_tab}
+};
+
+/*
+ * Per-algorithm internal threasholds for the minimum input size of before
+ * offloading to hardware provider.
+ * Dispatching a crypto operation  to a hardware provider entails paying the
+ * cost of an additional context switch.  Measurments with Sun Accelerator 4000
+ * shows that 512-byte jobs or smaller are better handled in software.
+ * There is room for refinement here.
+ *
+ */
+int kcf_md5_threshold = 512;
+int kcf_sha1_threshold = 512;
+int kcf_des_threshold = 512;
+int kcf_des3_threshold = 512;
+int kcf_aes_threshold = 512;
+int kcf_bf_threshold = 512;
+int kcf_rc4_threshold = 512;
+
+kmutex_t kcf_mech_tabs_lock;
+static uint32_t kcf_gen_swprov = 0;
+
+int kcf_mech_hash_size = 256;
+mod_hash_t *kcf_mech_hash;     /* mech name to id hash */
+
+static crypto_mech_type_t
+kcf_mech_hash_find(char *mechname)
+{
+       mod_hash_val_t hv;
+       crypto_mech_type_t mt;
+
+       mt = CRYPTO_MECH_INVALID;
+       if (mod_hash_find(kcf_mech_hash, (mod_hash_key_t)mechname, &hv) == 0) {
+               mt = *(crypto_mech_type_t *)hv;
+               ASSERT(mt != CRYPTO_MECH_INVALID);
+       }
+
+       return (mt);
+}
+
+void
+kcf_destroy_mech_tabs(void)
+{
+       if (kcf_mech_hash) mod_hash_destroy_hash(kcf_mech_hash);
+}
+
+/*
+ * kcf_init_mech_tabs()
+ *
+ * Called by the misc/kcf's _init() routine to initialize the tables
+ * of mech_entry's.
+ */
+void
+kcf_init_mech_tabs(void)
+{
+       int i, max;
+       kcf_ops_class_t class;
+       kcf_mech_entry_t *me_tab;
+
+       /* Initializes the mutex locks. */
+
+       mutex_init(&kcf_mech_tabs_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       /* Then the pre-defined mechanism entries */
+
+       /* Two digests */
+       (void) strncpy(kcf_digest_mechs_tab[0].me_name, SUN_CKM_MD5,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_digest_mechs_tab[0].me_threshold = kcf_md5_threshold;
+
+       (void) strncpy(kcf_digest_mechs_tab[1].me_name, SUN_CKM_SHA1,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_digest_mechs_tab[1].me_threshold = kcf_sha1_threshold;
+
+       /* The symmetric ciphers in various modes */
+       (void) strncpy(kcf_cipher_mechs_tab[0].me_name, SUN_CKM_DES_CBC,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[0].me_threshold = kcf_des_threshold;
+
+       (void) strncpy(kcf_cipher_mechs_tab[1].me_name, SUN_CKM_DES3_CBC,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[1].me_threshold = kcf_des3_threshold;
+
+       (void) strncpy(kcf_cipher_mechs_tab[2].me_name, SUN_CKM_DES_ECB,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[2].me_threshold = kcf_des_threshold;
+
+       (void) strncpy(kcf_cipher_mechs_tab[3].me_name, SUN_CKM_DES3_ECB,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[3].me_threshold = kcf_des3_threshold;
+
+       (void) strncpy(kcf_cipher_mechs_tab[4].me_name, SUN_CKM_BLOWFISH_CBC,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[4].me_threshold = kcf_bf_threshold;
+
+       (void) strncpy(kcf_cipher_mechs_tab[5].me_name, SUN_CKM_BLOWFISH_ECB,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[5].me_threshold = kcf_bf_threshold;
+
+       (void) strncpy(kcf_cipher_mechs_tab[6].me_name, SUN_CKM_AES_CBC,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[6].me_threshold = kcf_aes_threshold;
+
+       (void) strncpy(kcf_cipher_mechs_tab[7].me_name, SUN_CKM_AES_ECB,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[7].me_threshold = kcf_aes_threshold;
+
+       (void) strncpy(kcf_cipher_mechs_tab[8].me_name, SUN_CKM_RC4,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_cipher_mechs_tab[8].me_threshold = kcf_rc4_threshold;
+
+
+       /* 4 HMACs */
+       (void) strncpy(kcf_mac_mechs_tab[0].me_name, SUN_CKM_MD5_HMAC,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_mac_mechs_tab[0].me_threshold = kcf_md5_threshold;
+
+       (void) strncpy(kcf_mac_mechs_tab[1].me_name, SUN_CKM_MD5_HMAC_GENERAL,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_mac_mechs_tab[1].me_threshold = kcf_md5_threshold;
+
+       (void) strncpy(kcf_mac_mechs_tab[2].me_name, SUN_CKM_SHA1_HMAC,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_mac_mechs_tab[2].me_threshold = kcf_sha1_threshold;
+
+       (void) strncpy(kcf_mac_mechs_tab[3].me_name, SUN_CKM_SHA1_HMAC_GENERAL,
+           CRYPTO_MAX_MECH_NAME);
+       kcf_mac_mechs_tab[3].me_threshold = kcf_sha1_threshold;
+
+
+       /* 1 random number generation pseudo mechanism */
+       (void) strncpy(kcf_misc_mechs_tab[0].me_name, SUN_RANDOM,
+           CRYPTO_MAX_MECH_NAME);
+
+       kcf_mech_hash = mod_hash_create_strhash_nodtr("kcf mech2id hash",
+           kcf_mech_hash_size, mod_hash_null_valdtor);
+
+       for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
+               max = kcf_mech_tabs_tab[class].met_size;
+               me_tab = kcf_mech_tabs_tab[class].met_tab;
+               for (i = 0; i < max; i++) {
+                       mutex_init(&(me_tab[i].me_mutex), NULL,
+                           MUTEX_DEFAULT, NULL);
+                       if (me_tab[i].me_name[0] != 0) {
+                               me_tab[i].me_mechid = KCF_MECHID(class, i);
+                               (void) mod_hash_insert(kcf_mech_hash,
+                                   (mod_hash_key_t)me_tab[i].me_name,
+                                   (mod_hash_val_t)&(me_tab[i].me_mechid));
+                       }
+               }
+       }
+}
+
+/*
+ * kcf_create_mech_entry()
+ *
+ * Arguments:
+ *     . The class of mechanism.
+ *     . the name of the new mechanism.
+ *
+ * Description:
+ *     Creates a new mech_entry for a mechanism not yet known to the
+ *     framework.
+ *     This routine is called by kcf_add_mech_provider, which is
+ *     in turn invoked for each mechanism supported by a provider.
+ *     The'class' argument depends on the crypto_func_group_t bitmask
+ *     in the registering provider's mech_info struct for this mechanism.
+ *     When there is ambiguity in the mapping between the crypto_func_group_t
+ *     and a class (dual ops, ...) the KCF_MISC_CLASS should be used.
+ *
+ * Context:
+ *     User context only.
+ *
+ * Returns:
+ *     KCF_INVALID_MECH_CLASS or KCF_INVALID_MECH_NAME if the class or
+ *     the mechname is bogus.
+ *     KCF_MECH_TAB_FULL when there is no room left in the mech. tabs.
+ *     KCF_SUCCESS otherwise.
+ */
+static int
+kcf_create_mech_entry(kcf_ops_class_t class, char *mechname)
+{
+       crypto_mech_type_t mt;
+       kcf_mech_entry_t *me_tab;
+       int i = 0, size;
+
+       if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS))
+               return (KCF_INVALID_MECH_CLASS);
+
+       if ((mechname == NULL) || (mechname[0] == 0))
+               return (KCF_INVALID_MECH_NAME);
+       /*
+        * First check if the mechanism is already in one of the tables.
+        * The mech_entry could be in another class.
+        */
+       mutex_enter(&kcf_mech_tabs_lock);
+       mt = kcf_mech_hash_find(mechname);
+       if (mt != CRYPTO_MECH_INVALID) {
+               /* Nothing to do, regardless the suggested class. */
+               mutex_exit(&kcf_mech_tabs_lock);
+               return (KCF_SUCCESS);
+       }
+       /* Now take the next unused mech entry in the class's tab */
+       me_tab = kcf_mech_tabs_tab[class].met_tab;
+       size = kcf_mech_tabs_tab[class].met_size;
+
+       while (i < size) {
+               mutex_enter(&(me_tab[i].me_mutex));
+               if (me_tab[i].me_name[0] == 0) {
+                       /* Found an empty spot */
+                       (void) strncpy(me_tab[i].me_name, mechname,
+                           CRYPTO_MAX_MECH_NAME);
+                       me_tab[i].me_name[CRYPTO_MAX_MECH_NAME-1] = '\0';
+                       me_tab[i].me_mechid = KCF_MECHID(class, i);
+                       /*
+                        * No a-priori information about the new mechanism, so
+                        * the threshold is set to zero.
+                        */
+                       me_tab[i].me_threshold = 0;
+
+                       mutex_exit(&(me_tab[i].me_mutex));
+                       /* Add the new mechanism to the hash table */
+                       (void) mod_hash_insert(kcf_mech_hash,
+                           (mod_hash_key_t)me_tab[i].me_name,
+                           (mod_hash_val_t)&(me_tab[i].me_mechid));
+                       break;
+               }
+               mutex_exit(&(me_tab[i].me_mutex));
+               i++;
+       }
+
+       mutex_exit(&kcf_mech_tabs_lock);
+
+       if (i == size) {
+               return (KCF_MECH_TAB_FULL);
+       }
+
+       return (KCF_SUCCESS);
+}
+
+/*
+ * kcf_add_mech_provider()
+ *
+ * Arguments:
+ *     . An index in to  the provider mechanism array
+ *      . A pointer to the provider descriptor
+ *     . A storage for the kcf_prov_mech_desc_t the entry was added at.
+ *
+ * Description:
+ *      Adds  a new provider of a mechanism to the mechanism's mech_entry
+ *     chain.
+ *
+ * Context:
+ *      User context only.
+ *
+ * Returns
+ *      KCF_SUCCESS on success
+ *      KCF_MECH_TAB_FULL otherwise.
+ */
+int
+kcf_add_mech_provider(short mech_indx,
+    kcf_provider_desc_t *prov_desc, kcf_prov_mech_desc_t **pmdpp)
+{
+       int error;
+       kcf_mech_entry_t *mech_entry = NULL;
+       crypto_mech_info_t *mech_info;
+       crypto_mech_type_t kcf_mech_type, mt;
+       kcf_prov_mech_desc_t *prov_mech, *prov_mech2;
+       crypto_func_group_t simple_fg_mask, dual_fg_mask;
+       crypto_mech_info_t *dmi;
+       crypto_mech_info_list_t *mil, *mil2;
+       kcf_mech_entry_t *me;
+       int i;
+
+       ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       mech_info = &prov_desc->pd_mechanisms[mech_indx];
+
+       /*
+        * A mechanism belongs to exactly one mechanism table.
+        * Find the class corresponding to the function group flag of
+        * the mechanism.
+        */
+       kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
+       if (kcf_mech_type == CRYPTO_MECH_INVALID) {
+               crypto_func_group_t fg = mech_info->cm_func_group_mask;
+               kcf_ops_class_t class;
+
+               if (fg & CRYPTO_FG_DIGEST || fg & CRYPTO_FG_DIGEST_ATOMIC)
+                       class = KCF_DIGEST_CLASS;
+               else if (fg & CRYPTO_FG_ENCRYPT || fg & CRYPTO_FG_DECRYPT ||
+                   fg & CRYPTO_FG_ENCRYPT_ATOMIC ||
+                   fg & CRYPTO_FG_DECRYPT_ATOMIC)
+                       class = KCF_CIPHER_CLASS;
+               else if (fg & CRYPTO_FG_MAC || fg & CRYPTO_FG_MAC_ATOMIC)
+                       class = KCF_MAC_CLASS;
+               else if (fg & CRYPTO_FG_SIGN || fg & CRYPTO_FG_VERIFY ||
+                   fg & CRYPTO_FG_SIGN_ATOMIC ||
+                   fg & CRYPTO_FG_VERIFY_ATOMIC ||
+                   fg & CRYPTO_FG_SIGN_RECOVER ||
+                   fg & CRYPTO_FG_VERIFY_RECOVER)
+                       class = KCF_SIGN_CLASS;
+               else if (fg & CRYPTO_FG_GENERATE ||
+                   fg & CRYPTO_FG_GENERATE_KEY_PAIR ||
+                   fg & CRYPTO_FG_WRAP || fg & CRYPTO_FG_UNWRAP ||
+                   fg & CRYPTO_FG_DERIVE)
+                       class = KCF_KEYOPS_CLASS;
+               else
+                       class = KCF_MISC_CLASS;
+
+               /*
+                * Attempt to create a new mech_entry for the specified
+                * mechanism. kcf_create_mech_entry() can handle the case
+                * where such an entry already exists.
+                */
+               if ((error = kcf_create_mech_entry(class,
+                   mech_info->cm_mech_name)) != KCF_SUCCESS) {
+                       return (error);
+               }
+               /* get the KCF mech type that was assigned to the mechanism */
+               kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
+               ASSERT(kcf_mech_type != CRYPTO_MECH_INVALID);
+       }
+
+       error = kcf_get_mech_entry(kcf_mech_type, &mech_entry);
+       ASSERT(error == KCF_SUCCESS);
+
+       /* allocate and initialize new kcf_prov_mech_desc */
+       prov_mech = kmem_zalloc(sizeof (kcf_prov_mech_desc_t), KM_SLEEP);
+       bcopy(mech_info, &prov_mech->pm_mech_info, sizeof (crypto_mech_info_t));
+       prov_mech->pm_prov_desc = prov_desc;
+       prov_desc->pd_mech_indx[KCF_MECH2CLASS(kcf_mech_type)]
+           [KCF_MECH2INDEX(kcf_mech_type)] = mech_indx;
+
+       KCF_PROV_REFHOLD(prov_desc);
+       KCF_PROV_IREFHOLD(prov_desc);
+
+       dual_fg_mask = mech_info->cm_func_group_mask & CRYPTO_FG_DUAL_MASK;
+
+       if (dual_fg_mask == ((crypto_func_group_t)0))
+               goto add_entry;
+
+       simple_fg_mask = (mech_info->cm_func_group_mask &
+           CRYPTO_FG_SIMPLEOP_MASK) | CRYPTO_FG_RANDOM;
+
+       for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
+               dmi = &prov_desc->pd_mechanisms[i];
+
+               /* skip self */
+               if (dmi->cm_mech_number == mech_info->cm_mech_number)
+                       continue;
+
+               /* skip if not a dual operation mechanism */
+               if (!(dmi->cm_func_group_mask & dual_fg_mask) ||
+                   (dmi->cm_func_group_mask & simple_fg_mask))
+                       continue;
+
+               mt = kcf_mech_hash_find(dmi->cm_mech_name);
+               if (mt == CRYPTO_MECH_INVALID)
+                       continue;
+
+               if (kcf_get_mech_entry(mt, &me) != KCF_SUCCESS)
+                       continue;
+
+               mil = kmem_zalloc(sizeof (*mil), KM_SLEEP);
+               mil2 = kmem_zalloc(sizeof (*mil2), KM_SLEEP);
+
+               /*
+                * Ignore hard-coded entries in the mech table
+                * if the provider hasn't registered.
+                */
+               mutex_enter(&me->me_mutex);
+               if (me->me_hw_prov_chain == NULL && me->me_sw_prov == NULL) {
+                       mutex_exit(&me->me_mutex);
+                       kmem_free(mil, sizeof (*mil));
+                       kmem_free(mil2, sizeof (*mil2));
+                       continue;
+               }
+
+               /*
+                * Add other dual mechanisms that have registered
+                * with the framework to this mechanism's
+                * cross-reference list.
+                */
+               mil->ml_mech_info = *dmi; /* struct assignment */
+               mil->ml_kcf_mechid = mt;
+
+               /* add to head of list */
+               mil->ml_next = prov_mech->pm_mi_list;
+               prov_mech->pm_mi_list = mil;
+
+               if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
+                       prov_mech2 = me->me_hw_prov_chain;
+               else
+                       prov_mech2 = me->me_sw_prov;
+
+               if (prov_mech2 == NULL) {
+                       kmem_free(mil2, sizeof (*mil2));
+                       mutex_exit(&me->me_mutex);
+                       continue;
+               }
+
+               /*
+                * Update all other cross-reference lists by
+                * adding this new mechanism.
+                */
+               while (prov_mech2 != NULL) {
+                       if (prov_mech2->pm_prov_desc == prov_desc) {
+                               /* struct assignment */
+                               mil2->ml_mech_info = *mech_info;
+                               mil2->ml_kcf_mechid = kcf_mech_type;
+
+                               /* add to head of list */
+                               mil2->ml_next = prov_mech2->pm_mi_list;
+                               prov_mech2->pm_mi_list = mil2;
+                               break;
+                       }
+                       prov_mech2 = prov_mech2->pm_next;
+               }
+               if (prov_mech2 == NULL)
+                       kmem_free(mil2, sizeof (*mil2));
+
+               mutex_exit(&me->me_mutex);
+       }
+
+add_entry:
+       /*
+        * Add new kcf_prov_mech_desc at the front of HW providers
+        * chain.
+        */
+       switch (prov_desc->pd_prov_type) {
+
+       case CRYPTO_HW_PROVIDER:
+               mutex_enter(&mech_entry->me_mutex);
+               prov_mech->pm_me = mech_entry;
+               prov_mech->pm_next = mech_entry->me_hw_prov_chain;
+               mech_entry->me_hw_prov_chain = prov_mech;
+               mech_entry->me_num_hwprov++;
+               mutex_exit(&mech_entry->me_mutex);
+               break;
+
+       case CRYPTO_SW_PROVIDER:
+               mutex_enter(&mech_entry->me_mutex);
+               if (mech_entry->me_sw_prov != NULL) {
+                       /*
+                        * There is already a SW provider for this mechanism.
+                        * Since we allow only one SW provider per mechanism,
+                        * report this condition.
+                        */
+                       cmn_err(CE_WARN, "The cryptographic software provider "
+                           "\"%s\" will not be used for %s. The provider "
+                           "\"%s\" will be used for this mechanism "
+                           "instead.", prov_desc->pd_description,
+                           mech_info->cm_mech_name,
+                           mech_entry->me_sw_prov->pm_prov_desc->
+                           pd_description);
+                       KCF_PROV_REFRELE(prov_desc);
+                       kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
+                       prov_mech = NULL;
+               } else {
+                       /*
+                        * Set the provider as the software provider for
+                        * this mechanism.
+                        */
+                       mech_entry->me_sw_prov = prov_mech;
+
+                       /* We'll wrap around after 4 billion registrations! */
+                       mech_entry->me_gen_swprov = kcf_gen_swprov++;
+               }
+               mutex_exit(&mech_entry->me_mutex);
+               break;
+       default:
+               break;
+       }
+
+       *pmdpp = prov_mech;
+
+       return (KCF_SUCCESS);
+}
+
+/*
+ * kcf_remove_mech_provider()
+ *
+ * Arguments:
+ *      . mech_name: the name of the mechanism.
+ *      . prov_desc: The provider descriptor
+ *
+ * Description:
+ *      Removes a provider from chain of provider descriptors.
+ *     The provider is made unavailable to kernel consumers for the specified
+ *     mechanism.
+ *
+ * Context:
+ *      User context only.
+ */
+void
+kcf_remove_mech_provider(char *mech_name, kcf_provider_desc_t *prov_desc)
+{
+       crypto_mech_type_t mech_type;
+       kcf_prov_mech_desc_t *prov_mech = NULL, *prov_chain;
+       kcf_prov_mech_desc_t **prev_entry_next;
+       kcf_mech_entry_t *mech_entry;
+       crypto_mech_info_list_t *mil, *mil2, *next, **prev_next;
+
+       ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
+
+       /* get the KCF mech type that was assigned to the mechanism */
+       if ((mech_type = kcf_mech_hash_find(mech_name)) ==
+           CRYPTO_MECH_INVALID) {
+               /*
+                * Provider was not allowed for this mech due to policy or
+                * configuration.
+                */
+               return;
+       }
+
+       /* get a ptr to the mech_entry that was created */
+       if (kcf_get_mech_entry(mech_type, &mech_entry) != KCF_SUCCESS) {
+               /*
+                * Provider was not allowed for this mech due to policy or
+                * configuration.
+                */
+               return;
+       }
+
+       mutex_enter(&mech_entry->me_mutex);
+
+       switch (prov_desc->pd_prov_type) {
+
+       case CRYPTO_HW_PROVIDER:
+               /* find the provider in the mech_entry chain */
+               prev_entry_next = &mech_entry->me_hw_prov_chain;
+               prov_mech = mech_entry->me_hw_prov_chain;
+               while (prov_mech != NULL &&
+                   prov_mech->pm_prov_desc != prov_desc) {
+                       prev_entry_next = &prov_mech->pm_next;
+                       prov_mech = prov_mech->pm_next;
+               }
+
+               if (prov_mech == NULL) {
+                       /* entry not found, simply return */
+                       mutex_exit(&mech_entry->me_mutex);
+                       return;
+               }
+
+               /* remove provider entry from mech_entry chain */
+               *prev_entry_next = prov_mech->pm_next;
+               ASSERT(mech_entry->me_num_hwprov > 0);
+               mech_entry->me_num_hwprov--;
+               break;
+
+       case CRYPTO_SW_PROVIDER:
+               if (mech_entry->me_sw_prov == NULL ||
+                   mech_entry->me_sw_prov->pm_prov_desc != prov_desc) {
+                       /* not the software provider for this mechanism */
+                       mutex_exit(&mech_entry->me_mutex);
+                       return;
+               }
+               prov_mech = mech_entry->me_sw_prov;
+               mech_entry->me_sw_prov = NULL;
+               break;
+       default:
+               /* unexpected crypto_provider_type_t */
+               mutex_exit(&mech_entry->me_mutex);
+               return;
+       }
+
+       mutex_exit(&mech_entry->me_mutex);
+
+       /* Free the dual ops cross-reference lists  */
+       mil = prov_mech->pm_mi_list;
+       while (mil != NULL) {
+               next = mil->ml_next;
+               if (kcf_get_mech_entry(mil->ml_kcf_mechid,
+                   &mech_entry) != KCF_SUCCESS) {
+                       mil = next;
+                       continue;
+               }
+
+               mutex_enter(&mech_entry->me_mutex);
+               if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
+                       prov_chain = mech_entry->me_hw_prov_chain;
+               else
+                       prov_chain = mech_entry->me_sw_prov;
+
+               while (prov_chain != NULL) {
+                       if (prov_chain->pm_prov_desc == prov_desc) {
+                               prev_next = &prov_chain->pm_mi_list;
+                               mil2 = prov_chain->pm_mi_list;
+                               while (mil2 != NULL &&
+                                   mil2->ml_kcf_mechid != mech_type) {
+                                       prev_next = &mil2->ml_next;
+                                       mil2 = mil2->ml_next;
+                               }
+                               if (mil2 != NULL) {
+                                       *prev_next = mil2->ml_next;
+                                       kmem_free(mil2, sizeof (*mil2));
+                               }
+                               break;
+                       }
+                       prov_chain = prov_chain->pm_next;
+               }
+
+               mutex_exit(&mech_entry->me_mutex);
+               kmem_free(mil, sizeof (crypto_mech_info_list_t));
+               mil = next;
+       }
+
+       /* free entry  */
+       KCF_PROV_REFRELE(prov_mech->pm_prov_desc);
+       KCF_PROV_IREFRELE(prov_mech->pm_prov_desc);
+       kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
+}
+
+/*
+ * kcf_get_mech_entry()
+ *
+ * Arguments:
+ *      . The framework mechanism type
+ *      . Storage for the mechanism entry
+ *
+ * Description:
+ *      Retrieves the mechanism entry for the mech.
+ *
+ * Context:
+ *      User and interrupt contexts.
+ *
+ * Returns:
+ *      KCF_MECHANISM_XXX appropriate error code.
+ *      KCF_SUCCESS otherwise.
+ */
+int
+kcf_get_mech_entry(crypto_mech_type_t mech_type, kcf_mech_entry_t **mep)
+{
+       kcf_ops_class_t         class;
+       int                     index;
+       kcf_mech_entry_tab_t    *me_tab;
+
+       ASSERT(mep != NULL);
+
+       class = KCF_MECH2CLASS(mech_type);
+
+       if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
+               /* the caller won't need to know it's an invalid class */
+               return (KCF_INVALID_MECH_NUMBER);
+       }
+
+       me_tab = &kcf_mech_tabs_tab[class];
+       index = KCF_MECH2INDEX(mech_type);
+
+       if ((index < 0) || (index >= me_tab->met_size)) {
+               return (KCF_INVALID_MECH_NUMBER);
+       }
+
+       *mep = &((me_tab->met_tab)[index]);
+
+       return (KCF_SUCCESS);
+}
+
+/* CURRENTLY UNSUPPORTED: attempting to load the module if it isn't found */
+/*
+ * Lookup the hash table for an entry that matches the mechname.
+ * If there are no hardware or software providers for the mechanism,
+ * but there is an unloaded software provider, this routine will attempt
+ * to load it.
+ *
+ * If the MOD_NOAUTOUNLOAD flag is not set, a software provider is
+ * in constant danger of being unloaded.  For consumers that call
+ * crypto_mech2id() only once, the provider will not be reloaded
+ * if it becomes unloaded.  If a provider gets loaded elsewhere
+ * without the MOD_NOAUTOUNLOAD flag being set, we set it now.
+ */
+crypto_mech_type_t
+crypto_mech2id_common(char *mechname, boolean_t load_module)
+{
+       crypto_mech_type_t mt = kcf_mech_hash_find(mechname);
+       return (mt);
+}
diff --git a/zfs/module/icp/core/kcf_prov_lib.c b/zfs/module/icp/core/kcf_prov_lib.c
new file mode 100644 (file)
index 0000000..dd4cd08
--- /dev/null
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/zfs_context.h>
+#include <modes/modes.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+
+/*
+ * Utility routine to copy a buffer to a crypto_data structure.
+ */
+
+/*
+ * Utility routine to apply the command, 'cmd', to the
+ * data in the uio structure.
+ */
+int
+crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd,
+    void *digest_ctx, void (*update)(void))
+{
+       uio_t *uiop = data->cd_uio;
+       off_t offset = data->cd_offset;
+       size_t length = len;
+       uint_t vec_idx;
+       size_t cur_len;
+       uchar_t *datap;
+
+       ASSERT(data->cd_format == CRYPTO_DATA_UIO);
+       if (uiop->uio_segflg != UIO_SYSSPACE) {
+               return (CRYPTO_ARGUMENTS_BAD);
+       }
+
+       /*
+        * Jump to the first iovec containing data to be
+        * processed.
+        */
+       for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
+           offset >= uiop->uio_iov[vec_idx].iov_len;
+           offset -= uiop->uio_iov[vec_idx++].iov_len)
+               ;
+
+       if (vec_idx == uiop->uio_iovcnt) {
+               /*
+                * The caller specified an offset that is larger than
+                * the total size of the buffers it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       while (vec_idx < uiop->uio_iovcnt && length > 0) {
+               cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
+                   offset, length);
+
+               datap = (uchar_t *)(uiop->uio_iov[vec_idx].iov_base +
+                   offset);
+               switch (cmd) {
+               case COPY_FROM_DATA:
+                       bcopy(datap, buf, cur_len);
+                       buf += cur_len;
+                       break;
+               case COPY_TO_DATA:
+                       bcopy(buf, datap, cur_len);
+                       buf += cur_len;
+                       break;
+               case COMPARE_TO_DATA:
+                       if (bcmp(datap, buf, cur_len))
+                               return (CRYPTO_SIGNATURE_INVALID);
+                       buf += cur_len;
+                       break;
+               case MD5_DIGEST_DATA:
+               case SHA1_DIGEST_DATA:
+               case SHA2_DIGEST_DATA:
+               case GHASH_DATA:
+                       return (CRYPTO_ARGUMENTS_BAD);
+               }
+
+               length -= cur_len;
+               vec_idx++;
+               offset = 0;
+       }
+
+       if (vec_idx == uiop->uio_iovcnt && length > 0) {
+               /*
+                * The end of the specified iovec's was reached but
+                * the length requested could not be processed.
+                */
+               switch (cmd) {
+               case COPY_TO_DATA:
+                       data->cd_length = len;
+                       return (CRYPTO_BUFFER_TOO_SMALL);
+               default:
+                       return (CRYPTO_DATA_LEN_RANGE);
+               }
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+int
+crypto_put_output_data(uchar_t *buf, crypto_data_t *output, int len)
+{
+       switch (output->cd_format) {
+       case CRYPTO_DATA_RAW:
+               if (output->cd_raw.iov_len < len) {
+                       output->cd_length = len;
+                       return (CRYPTO_BUFFER_TOO_SMALL);
+               }
+               bcopy(buf, (uchar_t *)(output->cd_raw.iov_base +
+                   output->cd_offset), len);
+               break;
+
+       case CRYPTO_DATA_UIO:
+               return (crypto_uio_data(output, buf, len,
+                   COPY_TO_DATA, NULL, NULL));
+       default:
+               return (CRYPTO_ARGUMENTS_BAD);
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+int
+crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output,
+    int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
+    void (*copy_block)(uint8_t *, uint64_t *))
+{
+       common_ctx_t *common_ctx = ctx;
+       int rv;
+
+       if (input->cd_miscdata != NULL) {
+               copy_block((uint8_t *)input->cd_miscdata,
+                   &common_ctx->cc_iv[0]);
+       }
+
+       if (input->cd_raw.iov_len < input->cd_length)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset,
+           input->cd_length, (input == output) ? NULL : output);
+
+       return (rv);
+}
+
+int
+crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output,
+    int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
+    void (*copy_block)(uint8_t *, uint64_t *))
+{
+       common_ctx_t *common_ctx = ctx;
+       uio_t *uiop = input->cd_uio;
+       off_t offset = input->cd_offset;
+       size_t length = input->cd_length;
+       uint_t vec_idx;
+       size_t cur_len;
+
+       if (input->cd_miscdata != NULL) {
+               copy_block((uint8_t *)input->cd_miscdata,
+                   &common_ctx->cc_iv[0]);
+       }
+
+       if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
+               return (CRYPTO_ARGUMENTS_BAD);
+       }
+
+       /*
+        * Jump to the first iovec containing data to be
+        * processed.
+        */
+       for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
+           offset >= uiop->uio_iov[vec_idx].iov_len;
+           offset -= uiop->uio_iov[vec_idx++].iov_len)
+               ;
+       if (vec_idx == uiop->uio_iovcnt) {
+               /*
+                * The caller specified an offset that is larger than the
+                * total size of the buffers it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       /*
+        * Now process the iovecs.
+        */
+       while (vec_idx < uiop->uio_iovcnt && length > 0) {
+               cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
+                   offset, length);
+
+               (cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset,
+                   cur_len, (input == output) ? NULL : output);
+
+               length -= cur_len;
+               vec_idx++;
+               offset = 0;
+       }
+
+       if (vec_idx == uiop->uio_iovcnt && length > 0) {
+               /*
+                * The end of the specified iovec's was reached but
+                * the length requested could not be processed, i.e.
+                * The caller requested to digest more data than it provided.
+                */
+
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       return (CRYPTO_SUCCESS);
+}
diff --git a/zfs/module/icp/core/kcf_prov_tabs.c b/zfs/module/icp/core/kcf_prov_tabs.c
new file mode 100644 (file)
index 0000000..dca0fc1
--- /dev/null
@@ -0,0 +1,638 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is part of the core Kernel Cryptographic Framework.
+ * It implements the management of tables of Providers. Entries to
+ * added and removed when cryptographic providers register with
+ * and unregister from the framework, respectively. The KCF scheduler
+ * and ioctl pseudo driver call this function to obtain the list
+ * of available providers.
+ *
+ * The provider table is indexed by crypto_provider_id_t. Each
+ * element of the table contains a pointer to a provider descriptor,
+ * or NULL if the entry is free.
+ *
+ * This file also implements helper functions to allocate and free
+ * provider descriptors.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/sched_impl.h>
+#include <sys/crypto/spi.h>
+
+#define        KCF_MAX_PROVIDERS       512     /* max number of providers */
+
+/*
+ * Prov_tab is an array of providers which is updated when
+ * a crypto provider registers with kcf. The provider calls the
+ * SPI routine, crypto_register_provider(), which in turn calls
+ * kcf_prov_tab_add_provider().
+ *
+ * A provider unregisters by calling crypto_unregister_provider()
+ * which triggers the removal of the prov_tab entry.
+ * It also calls kcf_remove_mech_provider().
+ *
+ * prov_tab entries are not updated from kcf.conf or by cryptoadm(1M).
+ */
+static kcf_provider_desc_t **prov_tab = NULL;
+static kmutex_t prov_tab_mutex; /* ensure exclusive access to the table */
+static uint_t prov_tab_num = 0; /* number of providers in table */
+static uint_t prov_tab_max = KCF_MAX_PROVIDERS;
+
+void
+kcf_prov_tab_destroy(void)
+{
+       if (prov_tab) kmem_free(prov_tab, prov_tab_max *
+               sizeof (kcf_provider_desc_t *));
+}
+
+/*
+ * Initialize a mutex and the KCF providers table, prov_tab.
+ * The providers table is dynamically allocated with prov_tab_max entries.
+ * Called from kcf module _init().
+ */
+void
+kcf_prov_tab_init(void)
+{
+       mutex_init(&prov_tab_mutex, NULL, MUTEX_DEFAULT, NULL);
+
+       prov_tab = kmem_zalloc(prov_tab_max * sizeof (kcf_provider_desc_t *),
+           KM_SLEEP);
+}
+
+/*
+ * Add a provider to the provider table. If no free entry can be found
+ * for the new provider, returns CRYPTO_HOST_MEMORY. Otherwise, add
+ * the provider to the table, initialize the pd_prov_id field
+ * of the specified provider descriptor to the index in that table,
+ * and return CRYPTO_SUCCESS. Note that a REFHOLD is done on the
+ * provider when pointed to by a table entry.
+ */
+int
+kcf_prov_tab_add_provider(kcf_provider_desc_t *prov_desc)
+{
+       uint_t i;
+
+       ASSERT(prov_tab != NULL);
+
+       mutex_enter(&prov_tab_mutex);
+
+       /* find free slot in providers table */
+       for (i = 1; i < KCF_MAX_PROVIDERS && prov_tab[i] != NULL; i++)
+               ;
+       if (i == KCF_MAX_PROVIDERS) {
+               /* ran out of providers entries */
+               mutex_exit(&prov_tab_mutex);
+               cmn_err(CE_WARN, "out of providers entries");
+               return (CRYPTO_HOST_MEMORY);
+       }
+
+       /* initialize entry */
+       prov_tab[i] = prov_desc;
+       KCF_PROV_REFHOLD(prov_desc);
+       KCF_PROV_IREFHOLD(prov_desc);
+       prov_tab_num++;
+
+       mutex_exit(&prov_tab_mutex);
+
+       /* update provider descriptor */
+       prov_desc->pd_prov_id = i;
+
+       /*
+        * The KCF-private provider handle is defined as the internal
+        * provider id.
+        */
+       prov_desc->pd_kcf_prov_handle =
+           (crypto_kcf_provider_handle_t)prov_desc->pd_prov_id;
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Remove the provider specified by its id. A REFRELE is done on the
+ * corresponding provider descriptor before this function returns.
+ * Returns CRYPTO_UNKNOWN_PROVIDER if the provider id is not valid.
+ */
+int
+kcf_prov_tab_rem_provider(crypto_provider_id_t prov_id)
+{
+       kcf_provider_desc_t *prov_desc;
+
+       ASSERT(prov_tab != NULL);
+       ASSERT(prov_tab_num >= 0);
+
+       /*
+        * Validate provider id, since it can be specified by a 3rd-party
+        * provider.
+        */
+
+       mutex_enter(&prov_tab_mutex);
+       if (prov_id >= KCF_MAX_PROVIDERS ||
+           ((prov_desc = prov_tab[prov_id]) == NULL)) {
+               mutex_exit(&prov_tab_mutex);
+               return (CRYPTO_INVALID_PROVIDER_ID);
+       }
+       mutex_exit(&prov_tab_mutex);
+
+       /*
+        * The provider id must remain valid until the associated provider
+        * descriptor is freed. For this reason, we simply release our
+        * reference to the descriptor here. When the reference count
+        * reaches zero, kcf_free_provider_desc() will be invoked and
+        * the associated entry in the providers table will be released
+        * at that time.
+        */
+
+       KCF_PROV_REFRELE(prov_desc);
+       KCF_PROV_IREFRELE(prov_desc);
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Returns the provider descriptor corresponding to the specified
+ * provider id. A REFHOLD is done on the descriptor before it is
+ * returned to the caller. It is the responsibility of the caller
+ * to do a REFRELE once it is done with the provider descriptor.
+ */
+kcf_provider_desc_t *
+kcf_prov_tab_lookup(crypto_provider_id_t prov_id)
+{
+       kcf_provider_desc_t *prov_desc;
+
+       mutex_enter(&prov_tab_mutex);
+
+       prov_desc = prov_tab[prov_id];
+
+       if (prov_desc == NULL) {
+               mutex_exit(&prov_tab_mutex);
+               return (NULL);
+       }
+
+       KCF_PROV_REFHOLD(prov_desc);
+
+       mutex_exit(&prov_tab_mutex);
+
+       return (prov_desc);
+}
+
+static void
+allocate_ops_v1(crypto_ops_t *src, crypto_ops_t *dst, uint_t *mech_list_count)
+{
+       if (src->co_control_ops != NULL)
+               dst->co_control_ops = kmem_alloc(sizeof (crypto_control_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_digest_ops != NULL)
+               dst->co_digest_ops = kmem_alloc(sizeof (crypto_digest_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_cipher_ops != NULL)
+               dst->co_cipher_ops = kmem_alloc(sizeof (crypto_cipher_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_mac_ops != NULL)
+               dst->co_mac_ops = kmem_alloc(sizeof (crypto_mac_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_sign_ops != NULL)
+               dst->co_sign_ops = kmem_alloc(sizeof (crypto_sign_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_verify_ops != NULL)
+               dst->co_verify_ops = kmem_alloc(sizeof (crypto_verify_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_dual_ops != NULL)
+               dst->co_dual_ops = kmem_alloc(sizeof (crypto_dual_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_dual_cipher_mac_ops != NULL)
+               dst->co_dual_cipher_mac_ops = kmem_alloc(
+                   sizeof (crypto_dual_cipher_mac_ops_t), KM_SLEEP);
+
+       if (src->co_random_ops != NULL) {
+               dst->co_random_ops = kmem_alloc(
+                   sizeof (crypto_random_number_ops_t), KM_SLEEP);
+
+               /*
+                * Allocate storage to store the array of supported mechanisms
+                * specified by provider. We allocate extra mechanism storage
+                * if the provider has random_ops since we keep an internal
+                * mechanism, SUN_RANDOM, in this case.
+                */
+               (*mech_list_count)++;
+       }
+
+       if (src->co_session_ops != NULL)
+               dst->co_session_ops = kmem_alloc(sizeof (crypto_session_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_object_ops != NULL)
+               dst->co_object_ops = kmem_alloc(sizeof (crypto_object_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_key_ops != NULL)
+               dst->co_key_ops = kmem_alloc(sizeof (crypto_key_ops_t),
+                   KM_SLEEP);
+
+       if (src->co_provider_ops != NULL)
+               dst->co_provider_ops = kmem_alloc(
+                   sizeof (crypto_provider_management_ops_t), KM_SLEEP);
+
+       if (src->co_ctx_ops != NULL)
+               dst->co_ctx_ops = kmem_alloc(sizeof (crypto_ctx_ops_t),
+                   KM_SLEEP);
+}
+
+static void
+allocate_ops_v2(crypto_ops_t *src, crypto_ops_t *dst)
+{
+       if (src->co_mech_ops != NULL)
+               dst->co_mech_ops = kmem_alloc(sizeof (crypto_mech_ops_t),
+                   KM_SLEEP);
+}
+
+static void
+allocate_ops_v3(crypto_ops_t *src, crypto_ops_t *dst)
+{
+       if (src->co_nostore_key_ops != NULL)
+               dst->co_nostore_key_ops =
+                   kmem_alloc(sizeof (crypto_nostore_key_ops_t), KM_SLEEP);
+}
+
+/*
+ * Allocate a provider descriptor. mech_list_count specifies the
+ * number of mechanisms supported by the providers, and is used
+ * to allocate storage for the mechanism table.
+ * This function may sleep while allocating memory, which is OK
+ * since it is invoked from user context during provider registration.
+ */
+kcf_provider_desc_t *
+kcf_alloc_provider_desc(crypto_provider_info_t *info)
+{
+       int i, j;
+       kcf_provider_desc_t *desc;
+       uint_t mech_list_count = info->pi_mech_list_count;
+       crypto_ops_t *src_ops = info->pi_ops_vector;
+
+       desc = kmem_zalloc(sizeof (kcf_provider_desc_t), KM_SLEEP);
+
+       /*
+        * pd_description serves two purposes
+        * - Appears as a blank padded PKCS#11 style string, that will be
+        *   returned to applications in CK_SLOT_INFO.slotDescription.
+        *   This means that we should not have a null character in the
+        *   first CRYPTO_PROVIDER_DESCR_MAX_LEN bytes.
+        * - Appears as a null-terminated string that can be used by
+        *   other kcf routines.
+        *
+        * So, we allocate enough room for one extra null terminator
+        * which keeps every one happy.
+        */
+       desc->pd_description = kmem_alloc(CRYPTO_PROVIDER_DESCR_MAX_LEN + 1,
+           KM_SLEEP);
+       (void) memset(desc->pd_description, ' ',
+           CRYPTO_PROVIDER_DESCR_MAX_LEN);
+       desc->pd_description[CRYPTO_PROVIDER_DESCR_MAX_LEN] = '\0';
+
+       /*
+        * Since the framework does not require the ops vector specified
+        * by the providers during registration to be persistent,
+        * KCF needs to allocate storage where copies of the ops
+        * vectors are copied.
+        */
+       desc->pd_ops_vector = kmem_zalloc(sizeof (crypto_ops_t), KM_SLEEP);
+
+       if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
+               allocate_ops_v1(src_ops, desc->pd_ops_vector, &mech_list_count);
+               if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2)
+                       allocate_ops_v2(src_ops, desc->pd_ops_vector);
+               if (info->pi_interface_version == CRYPTO_SPI_VERSION_3)
+                       allocate_ops_v3(src_ops, desc->pd_ops_vector);
+       }
+
+       desc->pd_mech_list_count = mech_list_count;
+       desc->pd_mechanisms = kmem_zalloc(sizeof (crypto_mech_info_t) *
+           mech_list_count, KM_SLEEP);
+       for (i = 0; i < KCF_OPS_CLASSSIZE; i++)
+               for (j = 0; j < KCF_MAXMECHTAB; j++)
+                       desc->pd_mech_indx[i][j] = KCF_INVALID_INDX;
+
+       desc->pd_prov_id = KCF_PROVID_INVALID;
+       desc->pd_state = KCF_PROV_ALLOCATED;
+
+       mutex_init(&desc->pd_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&desc->pd_resume_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&desc->pd_remove_cv, NULL, CV_DEFAULT, NULL);
+
+       return (desc);
+}
+
+/*
+ * Called by KCF_PROV_REFRELE when a provider's reference count drops
+ * to zero. We free the descriptor when the last reference is released.
+ * However, for software providers, we do not free it when there is an
+ * unregister thread waiting. We signal that thread in this case and
+ * that thread is responsible for freeing the descriptor.
+ */
+void
+kcf_provider_zero_refcnt(kcf_provider_desc_t *desc)
+{
+       mutex_enter(&desc->pd_lock);
+       switch (desc->pd_prov_type) {
+       case CRYPTO_SW_PROVIDER:
+               if (desc->pd_state == KCF_PROV_REMOVED ||
+                   desc->pd_state == KCF_PROV_DISABLED) {
+                       desc->pd_state = KCF_PROV_FREED;
+                       cv_broadcast(&desc->pd_remove_cv);
+                       mutex_exit(&desc->pd_lock);
+                       break;
+               }
+               /* FALLTHRU */
+
+       case CRYPTO_HW_PROVIDER:
+       case CRYPTO_LOGICAL_PROVIDER:
+               mutex_exit(&desc->pd_lock);
+               kcf_free_provider_desc(desc);
+       }
+}
+
+/*
+ * Free a provider descriptor.
+ */
+void
+kcf_free_provider_desc(kcf_provider_desc_t *desc)
+{
+       if (desc == NULL)
+               return;
+
+       mutex_enter(&prov_tab_mutex);
+       if (desc->pd_prov_id != KCF_PROVID_INVALID) {
+               /* release the associated providers table entry */
+               ASSERT(prov_tab[desc->pd_prov_id] != NULL);
+               prov_tab[desc->pd_prov_id] = NULL;
+               prov_tab_num--;
+       }
+       mutex_exit(&prov_tab_mutex);
+
+       /* free the kernel memory associated with the provider descriptor */
+
+       if (desc->pd_description != NULL)
+               kmem_free(desc->pd_description,
+                   CRYPTO_PROVIDER_DESCR_MAX_LEN + 1);
+
+       if (desc->pd_ops_vector != NULL) {
+
+               if (desc->pd_ops_vector->co_control_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_control_ops,
+                           sizeof (crypto_control_ops_t));
+
+               if (desc->pd_ops_vector->co_digest_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_digest_ops,
+                           sizeof (crypto_digest_ops_t));
+
+               if (desc->pd_ops_vector->co_cipher_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_cipher_ops,
+                           sizeof (crypto_cipher_ops_t));
+
+               if (desc->pd_ops_vector->co_mac_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_mac_ops,
+                           sizeof (crypto_mac_ops_t));
+
+               if (desc->pd_ops_vector->co_sign_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_sign_ops,
+                           sizeof (crypto_sign_ops_t));
+
+               if (desc->pd_ops_vector->co_verify_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_verify_ops,
+                           sizeof (crypto_verify_ops_t));
+
+               if (desc->pd_ops_vector->co_dual_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_dual_ops,
+                           sizeof (crypto_dual_ops_t));
+
+               if (desc->pd_ops_vector->co_dual_cipher_mac_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_dual_cipher_mac_ops,
+                           sizeof (crypto_dual_cipher_mac_ops_t));
+
+               if (desc->pd_ops_vector->co_random_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_random_ops,
+                           sizeof (crypto_random_number_ops_t));
+
+               if (desc->pd_ops_vector->co_session_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_session_ops,
+                           sizeof (crypto_session_ops_t));
+
+               if (desc->pd_ops_vector->co_object_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_object_ops,
+                           sizeof (crypto_object_ops_t));
+
+               if (desc->pd_ops_vector->co_key_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_key_ops,
+                           sizeof (crypto_key_ops_t));
+
+               if (desc->pd_ops_vector->co_provider_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_provider_ops,
+                           sizeof (crypto_provider_management_ops_t));
+
+               if (desc->pd_ops_vector->co_ctx_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_ctx_ops,
+                           sizeof (crypto_ctx_ops_t));
+
+               if (desc->pd_ops_vector->co_mech_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_mech_ops,
+                           sizeof (crypto_mech_ops_t));
+
+               if (desc->pd_ops_vector->co_nostore_key_ops != NULL)
+                       kmem_free(desc->pd_ops_vector->co_nostore_key_ops,
+                           sizeof (crypto_nostore_key_ops_t));
+
+               kmem_free(desc->pd_ops_vector, sizeof (crypto_ops_t));
+       }
+
+       if (desc->pd_mechanisms != NULL)
+               /* free the memory associated with the mechanism info's */
+               kmem_free(desc->pd_mechanisms, sizeof (crypto_mech_info_t) *
+                   desc->pd_mech_list_count);
+
+       if (desc->pd_sched_info.ks_taskq != NULL)
+               taskq_destroy(desc->pd_sched_info.ks_taskq);
+
+       kmem_free(desc, sizeof (kcf_provider_desc_t));
+}
+
+/*
+ * Returns an array of hardware and logical provider descriptors,
+ * a.k.a the PKCS#11 slot list. A REFHOLD is done on each descriptor
+ * before the array is returned. The entire table can be freed by
+ * calling kcf_free_provider_tab().
+ */
+int
+kcf_get_slot_list(uint_t *count, kcf_provider_desc_t ***array,
+    boolean_t unverified)
+{
+       kcf_provider_desc_t *prov_desc;
+       kcf_provider_desc_t **p = NULL;
+       char *last;
+       uint_t cnt = 0;
+       uint_t i, j;
+       int rval = CRYPTO_SUCCESS;
+       size_t n, final_size;
+
+       /* count the providers */
+       mutex_enter(&prov_tab_mutex);
+       for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
+               if ((prov_desc = prov_tab[i]) != NULL &&
+                   ((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER &&
+                   (prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) ||
+                   prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) {
+                       if (KCF_IS_PROV_USABLE(prov_desc) ||
+                           (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
+                               cnt++;
+                       }
+               }
+       }
+       mutex_exit(&prov_tab_mutex);
+
+       if (cnt == 0)
+               goto out;
+
+       n = cnt * sizeof (kcf_provider_desc_t *);
+again:
+       p = kmem_zalloc(n, KM_SLEEP);
+
+       /* pointer to last entry in the array */
+       last = (char *)&p[cnt-1];
+
+       mutex_enter(&prov_tab_mutex);
+       /* fill the slot list */
+       for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) {
+               if ((prov_desc = prov_tab[i]) != NULL &&
+                   ((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER &&
+                   (prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) ||
+                   prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) {
+                       if (KCF_IS_PROV_USABLE(prov_desc) ||
+                           (unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
+                               if ((char *)&p[j] > last) {
+                                       mutex_exit(&prov_tab_mutex);
+                                       kcf_free_provider_tab(cnt, p);
+                                       n = n << 1;
+                                       cnt = cnt << 1;
+                                       goto again;
+                               }
+                               p[j++] = prov_desc;
+                               KCF_PROV_REFHOLD(prov_desc);
+                       }
+               }
+       }
+       mutex_exit(&prov_tab_mutex);
+
+       final_size = j * sizeof (kcf_provider_desc_t *);
+       cnt = j;
+       ASSERT(final_size <= n);
+
+       /* check if buffer we allocated is too large */
+       if (final_size < n) {
+               char *final_buffer = NULL;
+
+               if (final_size > 0) {
+                       final_buffer = kmem_alloc(final_size, KM_SLEEP);
+                       bcopy(p, final_buffer, final_size);
+               }
+               kmem_free(p, n);
+               p = (kcf_provider_desc_t **)final_buffer;
+       }
+out:
+       *count = cnt;
+       *array = p;
+       return (rval);
+}
+
+/*
+ * Free an array of hardware provider descriptors.  A REFRELE
+ * is done on each descriptor before the table is freed.
+ */
+void
+kcf_free_provider_tab(uint_t count, kcf_provider_desc_t **array)
+{
+       kcf_provider_desc_t *prov_desc;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               if ((prov_desc = array[i]) != NULL) {
+                       KCF_PROV_REFRELE(prov_desc);
+               }
+       }
+       kmem_free(array, count * sizeof (kcf_provider_desc_t *));
+}
+
+/*
+ * Returns in the location pointed to by pd a pointer to the descriptor
+ * for the software provider for the specified mechanism.
+ * The provider descriptor is returned held and it is the caller's
+ * responsibility to release it when done. The mechanism entry
+ * is returned if the optional argument mep is non NULL.
+ *
+ * Returns one of the CRYPTO_ * error codes on failure, and
+ * CRYPTO_SUCCESS on success.
+ */
+int
+kcf_get_sw_prov(crypto_mech_type_t mech_type, kcf_provider_desc_t **pd,
+    kcf_mech_entry_t **mep, boolean_t log_warn)
+{
+       kcf_mech_entry_t *me;
+
+       /* get the mechanism entry for this mechanism */
+       if (kcf_get_mech_entry(mech_type, &me) != KCF_SUCCESS)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       /*
+        * Get the software provider for this mechanism.
+        * Lock the mech_entry until we grab the 'pd'.
+        */
+       mutex_enter(&me->me_mutex);
+
+       if (me->me_sw_prov == NULL ||
+           (*pd = me->me_sw_prov->pm_prov_desc) == NULL) {
+               /* no SW provider for this mechanism */
+               if (log_warn)
+                       cmn_err(CE_WARN, "no SW provider for \"%s\"\n",
+                           me->me_name);
+               mutex_exit(&me->me_mutex);
+               return (CRYPTO_MECH_NOT_SUPPORTED);
+       }
+
+       KCF_PROV_REFHOLD(*pd);
+       mutex_exit(&me->me_mutex);
+
+       if (mep != NULL)
+               *mep = me;
+
+       return (CRYPTO_SUCCESS);
+}
diff --git a/zfs/module/icp/core/kcf_sched.c b/zfs/module/icp/core/kcf_sched.c
new file mode 100644 (file)
index 0000000..3b4cce4
--- /dev/null
@@ -0,0 +1,1765 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file contains the core framework routines for the
+ * kernel cryptographic framework. These routines are at the
+ * layer, between the kernel API/ioctls and the SPI.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/sched_impl.h>
+#include <sys/crypto/api.h>
+
+kcf_global_swq_t *gswq;        /* Global software queue */
+
+/* Thread pool related variables */
+static kcf_pool_t *kcfpool;    /* Thread pool of kcfd LWPs */
+int kcf_maxthreads = 2;
+int kcf_minthreads = 1;
+int kcf_thr_multiple = 2;      /* Boot-time tunable for experimentation */
+static ulong_t kcf_idlethr_timeout;
+#define        KCF_DEFAULT_THRTIMEOUT  60000000        /* 60 seconds */
+
+/* kmem caches used by the scheduler */
+static kmem_cache_t *kcf_sreq_cache;
+static kmem_cache_t *kcf_areq_cache;
+static kmem_cache_t *kcf_context_cache;
+
+/* Global request ID table */
+static kcf_reqid_table_t *kcf_reqid_table[REQID_TABLES];
+
+/* KCF stats. Not protected. */
+static kcf_stats_t kcf_ksdata = {
+       { "total threads in pool",      KSTAT_DATA_UINT32},
+       { "idle threads in pool",       KSTAT_DATA_UINT32},
+       { "min threads in pool",        KSTAT_DATA_UINT32},
+       { "max threads in pool",        KSTAT_DATA_UINT32},
+       { "requests in gswq",           KSTAT_DATA_UINT32},
+       { "max requests in gswq",       KSTAT_DATA_UINT32},
+       { "threads for HW taskq",       KSTAT_DATA_UINT32},
+       { "minalloc for HW taskq",      KSTAT_DATA_UINT32},
+       { "maxalloc for HW taskq",      KSTAT_DATA_UINT32}
+};
+
+static kstat_t *kcf_misc_kstat = NULL;
+ulong_t kcf_swprov_hndl = 0;
+
+static kcf_areq_node_t *kcf_areqnode_alloc(kcf_provider_desc_t *,
+    kcf_context_t *, crypto_call_req_t *, kcf_req_params_t *, boolean_t);
+static int kcf_disp_sw_request(kcf_areq_node_t *);
+static void process_req_hwp(void *);
+static int kcf_enqueue(kcf_areq_node_t *);
+static void kcfpool_alloc(void);
+static void kcf_reqid_delete(kcf_areq_node_t *areq);
+static crypto_req_id_t kcf_reqid_insert(kcf_areq_node_t *areq);
+static int kcf_misc_kstat_update(kstat_t *ksp, int rw);
+
+/*
+ * Create a new context.
+ */
+crypto_ctx_t *
+kcf_new_ctx(crypto_call_req_t *crq, kcf_provider_desc_t *pd,
+    crypto_session_id_t sid)
+{
+       crypto_ctx_t *ctx;
+       kcf_context_t *kcf_ctx;
+
+       kcf_ctx = kmem_cache_alloc(kcf_context_cache,
+           (crq == NULL) ? KM_SLEEP : KM_NOSLEEP);
+       if (kcf_ctx == NULL)
+               return (NULL);
+
+       /* initialize the context for the consumer */
+       kcf_ctx->kc_refcnt = 1;
+       kcf_ctx->kc_req_chain_first = NULL;
+       kcf_ctx->kc_req_chain_last = NULL;
+       kcf_ctx->kc_secondctx = NULL;
+       KCF_PROV_REFHOLD(pd);
+       kcf_ctx->kc_prov_desc = pd;
+       kcf_ctx->kc_sw_prov_desc = NULL;
+       kcf_ctx->kc_mech = NULL;
+
+       ctx = &kcf_ctx->kc_glbl_ctx;
+       ctx->cc_provider = pd->pd_prov_handle;
+       ctx->cc_session = sid;
+       ctx->cc_provider_private = NULL;
+       ctx->cc_framework_private = (void *)kcf_ctx;
+       ctx->cc_flags = 0;
+       ctx->cc_opstate = NULL;
+
+       return (ctx);
+}
+
+/*
+ * Allocate a new async request node.
+ *
+ * ictx - Framework private context pointer
+ * crq - Has callback function and argument. Should be non NULL.
+ * req - The parameters to pass to the SPI
+ */
+static kcf_areq_node_t *
+kcf_areqnode_alloc(kcf_provider_desc_t *pd, kcf_context_t *ictx,
+    crypto_call_req_t *crq, kcf_req_params_t *req, boolean_t isdual)
+{
+       kcf_areq_node_t *arptr, *areq;
+
+       ASSERT(crq != NULL);
+       arptr = kmem_cache_alloc(kcf_areq_cache, KM_NOSLEEP);
+       if (arptr == NULL)
+               return (NULL);
+
+       arptr->an_state = REQ_ALLOCATED;
+       arptr->an_reqarg = *crq;
+       arptr->an_params = *req;
+       arptr->an_context = ictx;
+       arptr->an_isdual = isdual;
+
+       arptr->an_next = arptr->an_prev = NULL;
+       KCF_PROV_REFHOLD(pd);
+       arptr->an_provider = pd;
+       arptr->an_tried_plist = NULL;
+       arptr->an_refcnt = 1;
+       arptr->an_idnext = arptr->an_idprev = NULL;
+
+       /*
+        * Requests for context-less operations do not use the
+        * fields - an_is_my_turn, and an_ctxchain_next.
+        */
+       if (ictx == NULL)
+               return (arptr);
+
+       KCF_CONTEXT_REFHOLD(ictx);
+       /*
+        * Chain this request to the context.
+        */
+       mutex_enter(&ictx->kc_in_use_lock);
+       arptr->an_ctxchain_next = NULL;
+       if ((areq = ictx->kc_req_chain_last) == NULL) {
+               arptr->an_is_my_turn = B_TRUE;
+               ictx->kc_req_chain_last =
+                   ictx->kc_req_chain_first = arptr;
+       } else {
+               ASSERT(ictx->kc_req_chain_first != NULL);
+               arptr->an_is_my_turn = B_FALSE;
+               /* Insert the new request to the end of the chain. */
+               areq->an_ctxchain_next = arptr;
+               ictx->kc_req_chain_last = arptr;
+       }
+       mutex_exit(&ictx->kc_in_use_lock);
+
+       return (arptr);
+}
+
+/*
+ * Queue the request node and do one of the following:
+ *     - If there is an idle thread signal it to run.
+ *     - If there is no idle thread and max running threads is not
+ *       reached, signal the creator thread for more threads.
+ *
+ * If the two conditions above are not met, we don't need to do
+ * any thing. The request will be picked up by one of the
+ * worker threads when it becomes available.
+ */
+static int
+kcf_disp_sw_request(kcf_areq_node_t *areq)
+{
+       int err;
+       int cnt = 0;
+
+       if ((err = kcf_enqueue(areq)) != 0)
+               return (err);
+
+       if (kcfpool->kp_idlethreads > 0) {
+               /* Signal an idle thread to run */
+               mutex_enter(&gswq->gs_lock);
+               cv_signal(&gswq->gs_cv);
+               mutex_exit(&gswq->gs_lock);
+
+               return (CRYPTO_QUEUED);
+       }
+
+       /*
+        * We keep the number of running threads to be at
+        * kcf_minthreads to reduce gs_lock contention.
+        */
+       cnt = kcf_minthreads -
+           (kcfpool->kp_threads - kcfpool->kp_blockedthreads);
+       if (cnt > 0) {
+               /*
+                * The following ensures the number of threads in pool
+                * does not exceed kcf_maxthreads.
+                */
+               cnt = MIN(cnt, kcf_maxthreads - (int)kcfpool->kp_threads);
+               if (cnt > 0) {
+                       /* Signal the creator thread for more threads */
+                       mutex_enter(&kcfpool->kp_user_lock);
+                       if (!kcfpool->kp_signal_create_thread) {
+                               kcfpool->kp_signal_create_thread = B_TRUE;
+                               kcfpool->kp_nthrs = cnt;
+                               cv_signal(&kcfpool->kp_user_cv);
+                       }
+                       mutex_exit(&kcfpool->kp_user_lock);
+               }
+       }
+
+       return (CRYPTO_QUEUED);
+}
+
+/*
+ * This routine is called by the taskq associated with
+ * each hardware provider. We notify the kernel consumer
+ * via the callback routine in case of CRYPTO_SUCCESS or
+ * a failure.
+ *
+ * A request can be of type kcf_areq_node_t or of type
+ * kcf_sreq_node_t.
+ */
+static void
+process_req_hwp(void *ireq)
+{
+       int error = 0;
+       crypto_ctx_t *ctx;
+       kcf_call_type_t ctype;
+       kcf_provider_desc_t *pd;
+       kcf_areq_node_t *areq = (kcf_areq_node_t *)ireq;
+       kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)ireq;
+
+       pd = ((ctype = GET_REQ_TYPE(ireq)) == CRYPTO_SYNCH) ?
+           sreq->sn_provider : areq->an_provider;
+
+       /*
+        * Wait if flow control is in effect for the provider. A
+        * CRYPTO_PROVIDER_READY or CRYPTO_PROVIDER_FAILED
+        * notification will signal us. We also get signaled if
+        * the provider is unregistering.
+        */
+       if (pd->pd_state == KCF_PROV_BUSY) {
+               mutex_enter(&pd->pd_lock);
+               while (pd->pd_state == KCF_PROV_BUSY)
+                       cv_wait(&pd->pd_resume_cv, &pd->pd_lock);
+               mutex_exit(&pd->pd_lock);
+       }
+
+       /*
+        * Bump the internal reference count while the request is being
+        * processed. This is how we know when it's safe to unregister
+        * a provider. This step must precede the pd_state check below.
+        */
+       KCF_PROV_IREFHOLD(pd);
+
+       /*
+        * Fail the request if the provider has failed. We return a
+        * recoverable error and the notified clients attempt any
+        * recovery. For async clients this is done in kcf_aop_done()
+        * and for sync clients it is done in the k-api routines.
+        */
+       if (pd->pd_state >= KCF_PROV_FAILED) {
+               error = CRYPTO_DEVICE_ERROR;
+               goto bail;
+       }
+
+       if (ctype == CRYPTO_SYNCH) {
+               mutex_enter(&sreq->sn_lock);
+               sreq->sn_state = REQ_INPROGRESS;
+               mutex_exit(&sreq->sn_lock);
+
+               ctx = sreq->sn_context ? &sreq->sn_context->kc_glbl_ctx : NULL;
+               error = common_submit_request(sreq->sn_provider, ctx,
+                   sreq->sn_params, sreq);
+       } else {
+               kcf_context_t *ictx;
+               ASSERT(ctype == CRYPTO_ASYNCH);
+
+               /*
+                * We are in the per-hardware provider thread context and
+                * hence can sleep. Note that the caller would have done
+                * a taskq_dispatch(..., TQ_NOSLEEP) and would have returned.
+                */
+               ctx = (ictx = areq->an_context) ? &ictx->kc_glbl_ctx : NULL;
+
+               mutex_enter(&areq->an_lock);
+               /*
+                * We need to maintain ordering for multi-part requests.
+                * an_is_my_turn is set to B_TRUE initially for a request
+                * when it is enqueued and there are no other requests
+                * for that context. It is set later from kcf_aop_done() when
+                * the request before us in the chain of requests for the
+                * context completes. We get signaled at that point.
+                */
+               if (ictx != NULL) {
+                       ASSERT(ictx->kc_prov_desc == areq->an_provider);
+
+                       while (areq->an_is_my_turn == B_FALSE) {
+                               cv_wait(&areq->an_turn_cv, &areq->an_lock);
+                       }
+               }
+               areq->an_state = REQ_INPROGRESS;
+               mutex_exit(&areq->an_lock);
+
+               error = common_submit_request(areq->an_provider, ctx,
+                   &areq->an_params, areq);
+       }
+
+bail:
+       if (error == CRYPTO_QUEUED) {
+               /*
+                * The request is queued by the provider and we should
+                * get a crypto_op_notification() from the provider later.
+                * We notify the consumer at that time.
+                */
+               return;
+       } else {                /* CRYPTO_SUCCESS or other failure */
+               KCF_PROV_IREFRELE(pd);
+               if (ctype == CRYPTO_SYNCH)
+                       kcf_sop_done(sreq, error);
+               else
+                       kcf_aop_done(areq, error);
+       }
+}
+
+/*
+ * This routine checks if a request can be retried on another
+ * provider. If true, mech1 is initialized to point to the mechanism
+ * structure. mech2 is also initialized in case of a dual operation. fg
+ * is initialized to the correct crypto_func_group_t bit flag. They are
+ * initialized by this routine, so that the caller can pass them to a
+ * kcf_get_mech_provider() or kcf_get_dual_provider() with no further change.
+ *
+ * We check that the request is for a init or atomic routine and that
+ * it is for one of the operation groups used from k-api .
+ */
+static boolean_t
+can_resubmit(kcf_areq_node_t *areq, crypto_mechanism_t **mech1,
+    crypto_mechanism_t **mech2, crypto_func_group_t *fg)
+{
+       kcf_req_params_t *params;
+       kcf_op_type_t optype;
+
+       params = &areq->an_params;
+       optype = params->rp_optype;
+
+       if (!(IS_INIT_OP(optype) || IS_ATOMIC_OP(optype)))
+               return (B_FALSE);
+
+       switch (params->rp_opgrp) {
+       case KCF_OG_DIGEST: {
+               kcf_digest_ops_params_t *dops = &params->rp_u.digest_params;
+
+               dops->do_mech.cm_type = dops->do_framework_mechtype;
+               *mech1 = &dops->do_mech;
+               *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_DIGEST :
+                   CRYPTO_FG_DIGEST_ATOMIC;
+               break;
+       }
+
+       case KCF_OG_MAC: {
+               kcf_mac_ops_params_t *mops = &params->rp_u.mac_params;
+
+               mops->mo_mech.cm_type = mops->mo_framework_mechtype;
+               *mech1 = &mops->mo_mech;
+               *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_MAC :
+                   CRYPTO_FG_MAC_ATOMIC;
+               break;
+       }
+
+       case KCF_OG_SIGN: {
+               kcf_sign_ops_params_t *sops = &params->rp_u.sign_params;
+
+               sops->so_mech.cm_type = sops->so_framework_mechtype;
+               *mech1 = &sops->so_mech;
+               switch (optype) {
+               case KCF_OP_INIT:
+                       *fg = CRYPTO_FG_SIGN;
+                       break;
+               case KCF_OP_ATOMIC:
+                       *fg = CRYPTO_FG_SIGN_ATOMIC;
+                       break;
+               default:
+                       ASSERT(optype == KCF_OP_SIGN_RECOVER_ATOMIC);
+                       *fg = CRYPTO_FG_SIGN_RECOVER_ATOMIC;
+               }
+               break;
+       }
+
+       case KCF_OG_VERIFY: {
+               kcf_verify_ops_params_t *vops = &params->rp_u.verify_params;
+
+               vops->vo_mech.cm_type = vops->vo_framework_mechtype;
+               *mech1 = &vops->vo_mech;
+               switch (optype) {
+               case KCF_OP_INIT:
+                       *fg = CRYPTO_FG_VERIFY;
+                       break;
+               case KCF_OP_ATOMIC:
+                       *fg = CRYPTO_FG_VERIFY_ATOMIC;
+                       break;
+               default:
+                       ASSERT(optype == KCF_OP_VERIFY_RECOVER_ATOMIC);
+                       *fg = CRYPTO_FG_VERIFY_RECOVER_ATOMIC;
+               }
+               break;
+       }
+
+       case KCF_OG_ENCRYPT: {
+               kcf_encrypt_ops_params_t *eops = &params->rp_u.encrypt_params;
+
+               eops->eo_mech.cm_type = eops->eo_framework_mechtype;
+               *mech1 = &eops->eo_mech;
+               *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_ENCRYPT :
+                   CRYPTO_FG_ENCRYPT_ATOMIC;
+               break;
+       }
+
+       case KCF_OG_DECRYPT: {
+               kcf_decrypt_ops_params_t *dcrops = &params->rp_u.decrypt_params;
+
+               dcrops->dop_mech.cm_type = dcrops->dop_framework_mechtype;
+               *mech1 = &dcrops->dop_mech;
+               *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_DECRYPT :
+                   CRYPTO_FG_DECRYPT_ATOMIC;
+               break;
+       }
+
+       case KCF_OG_ENCRYPT_MAC: {
+               kcf_encrypt_mac_ops_params_t *eops =
+                   &params->rp_u.encrypt_mac_params;
+
+               eops->em_encr_mech.cm_type = eops->em_framework_encr_mechtype;
+               *mech1 = &eops->em_encr_mech;
+               eops->em_mac_mech.cm_type = eops->em_framework_mac_mechtype;
+               *mech2 = &eops->em_mac_mech;
+               *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_ENCRYPT_MAC :
+                   CRYPTO_FG_ENCRYPT_MAC_ATOMIC;
+               break;
+       }
+
+       case KCF_OG_MAC_DECRYPT: {
+               kcf_mac_decrypt_ops_params_t *dops =
+                   &params->rp_u.mac_decrypt_params;
+
+               dops->md_mac_mech.cm_type = dops->md_framework_mac_mechtype;
+               *mech1 = &dops->md_mac_mech;
+               dops->md_decr_mech.cm_type = dops->md_framework_decr_mechtype;
+               *mech2 = &dops->md_decr_mech;
+               *fg = (optype == KCF_OP_INIT) ? CRYPTO_FG_MAC_DECRYPT :
+                   CRYPTO_FG_MAC_DECRYPT_ATOMIC;
+               break;
+       }
+
+       default:
+               return (B_FALSE);
+       }
+
+       return (B_TRUE);
+}
+
+/*
+ * This routine is called when a request to a provider has failed
+ * with a recoverable error. This routine tries to find another provider
+ * and dispatches the request to the new provider, if one is available.
+ * We reuse the request structure.
+ *
+ * A return value of NULL from kcf_get_mech_provider() indicates
+ * we have tried the last provider.
+ */
+static int
+kcf_resubmit_request(kcf_areq_node_t *areq)
+{
+       int error = CRYPTO_FAILED;
+       kcf_context_t *ictx;
+       kcf_provider_desc_t *old_pd;
+       kcf_provider_desc_t *new_pd;
+       crypto_mechanism_t *mech1 = NULL, *mech2 = NULL;
+       crypto_mech_type_t prov_mt1, prov_mt2;
+       crypto_func_group_t fg = 0;
+
+       if (!can_resubmit(areq, &mech1, &mech2, &fg))
+               return (error);
+
+       old_pd = areq->an_provider;
+       /*
+        * Add old_pd to the list of providers already tried. We release
+        * the hold on old_pd (from the earlier kcf_get_mech_provider()) in
+        * kcf_free_triedlist().
+        */
+       if (kcf_insert_triedlist(&areq->an_tried_plist, old_pd,
+           KM_NOSLEEP) == NULL)
+               return (error);
+
+       if (mech1 && !mech2) {
+               new_pd = kcf_get_mech_provider(mech1->cm_type, NULL, &error,
+                   areq->an_tried_plist, fg,
+                   (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED), 0);
+       } else {
+               ASSERT(mech1 != NULL && mech2 != NULL);
+
+               new_pd = kcf_get_dual_provider(mech1, mech2, NULL, &prov_mt1,
+                   &prov_mt2, &error, areq->an_tried_plist, fg, fg,
+                   (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED), 0);
+       }
+
+       if (new_pd == NULL)
+               return (error);
+
+       /*
+        * We reuse the old context by resetting provider specific
+        * fields in it.
+        */
+       if ((ictx = areq->an_context) != NULL) {
+               crypto_ctx_t *ctx;
+
+               ASSERT(old_pd == ictx->kc_prov_desc);
+               KCF_PROV_REFRELE(ictx->kc_prov_desc);
+               KCF_PROV_REFHOLD(new_pd);
+               ictx->kc_prov_desc = new_pd;
+
+               ctx = &ictx->kc_glbl_ctx;
+               ctx->cc_provider = new_pd->pd_prov_handle;
+               ctx->cc_session = new_pd->pd_sid;
+               ctx->cc_provider_private = NULL;
+       }
+
+       /* We reuse areq. by resetting the provider and context fields. */
+       KCF_PROV_REFRELE(old_pd);
+       KCF_PROV_REFHOLD(new_pd);
+       areq->an_provider = new_pd;
+       mutex_enter(&areq->an_lock);
+       areq->an_state = REQ_WAITING;
+       mutex_exit(&areq->an_lock);
+
+       switch (new_pd->pd_prov_type) {
+       case CRYPTO_SW_PROVIDER:
+               error = kcf_disp_sw_request(areq);
+               break;
+
+       case CRYPTO_HW_PROVIDER: {
+               taskq_t *taskq = new_pd->pd_sched_info.ks_taskq;
+
+               if (taskq_dispatch(taskq, process_req_hwp, areq, TQ_NOSLEEP) ==
+                   (taskqid_t)0) {
+                       error = CRYPTO_HOST_MEMORY;
+               } else {
+                       error = CRYPTO_QUEUED;
+               }
+
+               break;
+       default:
+               break;
+       }
+       }
+
+       return (error);
+}
+
+static inline int EMPTY_TASKQ(taskq_t *tq)
+{
+#ifdef _KERNEL
+       return (tq->tq_lowest_id == tq->tq_next_id);
+#else
+       return (tq->tq_task.tqent_next == &tq->tq_task || tq->tq_active == 0);
+#endif
+}
+
+/*
+ * Routine called by both ioctl and k-api. The consumer should
+ * bundle the parameters into a kcf_req_params_t structure. A bunch
+ * of macros are available in ops_impl.h for this bundling. They are:
+ *
+ *     KCF_WRAP_DIGEST_OPS_PARAMS()
+ *     KCF_WRAP_MAC_OPS_PARAMS()
+ *     KCF_WRAP_ENCRYPT_OPS_PARAMS()
+ *     KCF_WRAP_DECRYPT_OPS_PARAMS() ... etc.
+ *
+ * It is the caller's responsibility to free the ctx argument when
+ * appropriate. See the KCF_CONTEXT_COND_RELEASE macro for details.
+ */
+int
+kcf_submit_request(kcf_provider_desc_t *pd, crypto_ctx_t *ctx,
+    crypto_call_req_t *crq, kcf_req_params_t *params, boolean_t cont)
+{
+       int error = CRYPTO_SUCCESS;
+       kcf_areq_node_t *areq;
+       kcf_sreq_node_t *sreq;
+       kcf_context_t *kcf_ctx;
+       taskq_t *taskq = pd->pd_sched_info.ks_taskq;
+
+       kcf_ctx = ctx ? (kcf_context_t *)ctx->cc_framework_private : NULL;
+
+       /* Synchronous cases */
+       if (crq == NULL) {
+               switch (pd->pd_prov_type) {
+               case CRYPTO_SW_PROVIDER:
+                       error = common_submit_request(pd, ctx, params,
+                           KCF_RHNDL(KM_SLEEP));
+                       break;
+
+               case CRYPTO_HW_PROVIDER:
+                       /*
+                        * Special case for CRYPTO_SYNCHRONOUS providers that
+                        * never return a CRYPTO_QUEUED error. We skip any
+                        * request allocation and call the SPI directly.
+                        */
+                       if ((pd->pd_flags & CRYPTO_SYNCHRONOUS) &&
+                           EMPTY_TASKQ(taskq)) {
+                               KCF_PROV_IREFHOLD(pd);
+                               if (pd->pd_state == KCF_PROV_READY) {
+                                       error = common_submit_request(pd, ctx,
+                                           params, KCF_RHNDL(KM_SLEEP));
+                                       KCF_PROV_IREFRELE(pd);
+                                       ASSERT(error != CRYPTO_QUEUED);
+                                       break;
+                               }
+                               KCF_PROV_IREFRELE(pd);
+                       }
+
+                       sreq = kmem_cache_alloc(kcf_sreq_cache, KM_SLEEP);
+                       sreq->sn_state = REQ_ALLOCATED;
+                       sreq->sn_rv = CRYPTO_FAILED;
+                       sreq->sn_params = params;
+
+                       /*
+                        * Note that we do not need to hold the context
+                        * for synchronous case as the context will never
+                        * become invalid underneath us. We do not need to hold
+                        * the provider here either as the caller has a hold.
+                        */
+                       sreq->sn_context = kcf_ctx;
+                       ASSERT(KCF_PROV_REFHELD(pd));
+                       sreq->sn_provider = pd;
+
+                       ASSERT(taskq != NULL);
+                       /*
+                        * Call the SPI directly if the taskq is empty and the
+                        * provider is not busy, else dispatch to the taskq.
+                        * Calling directly is fine as this is the synchronous
+                        * case. This is unlike the asynchronous case where we
+                        * must always dispatch to the taskq.
+                        */
+                       if (EMPTY_TASKQ(taskq) &&
+                           pd->pd_state == KCF_PROV_READY) {
+                               process_req_hwp(sreq);
+                       } else {
+                               /*
+                                * We can not tell from taskq_dispatch() return
+                                * value if we exceeded maxalloc. Hence the
+                                * check here. Since we are allowed to wait in
+                                * the synchronous case, we wait for the taskq
+                                * to become empty.
+                                */
+                               if (taskq->tq_nalloc >= crypto_taskq_maxalloc) {
+                                       taskq_wait(taskq);
+                               }
+
+                               (void) taskq_dispatch(taskq, process_req_hwp,
+                                   sreq, TQ_SLEEP);
+                       }
+
+                       /*
+                        * Wait for the notification to arrive,
+                        * if the operation is not done yet.
+                        * Bug# 4722589 will make the wait a cv_wait_sig().
+                        */
+                       mutex_enter(&sreq->sn_lock);
+                       while (sreq->sn_state < REQ_DONE)
+                               cv_wait(&sreq->sn_cv, &sreq->sn_lock);
+                       mutex_exit(&sreq->sn_lock);
+
+                       error = sreq->sn_rv;
+                       kmem_cache_free(kcf_sreq_cache, sreq);
+
+                       break;
+
+               default:
+                       error = CRYPTO_FAILED;
+                       break;
+               }
+
+       } else {        /* Asynchronous cases */
+               switch (pd->pd_prov_type) {
+               case CRYPTO_SW_PROVIDER:
+                       if (!(crq->cr_flag & CRYPTO_ALWAYS_QUEUE)) {
+                               /*
+                                * This case has less overhead since there is
+                                * no switching of context.
+                                */
+                               error = common_submit_request(pd, ctx, params,
+                                   KCF_RHNDL(KM_NOSLEEP));
+                       } else {
+                               /*
+                                * CRYPTO_ALWAYS_QUEUE is set. We need to
+                                * queue the request and return.
+                                */
+                               areq = kcf_areqnode_alloc(pd, kcf_ctx, crq,
+                                   params, cont);
+                               if (areq == NULL)
+                                       error = CRYPTO_HOST_MEMORY;
+                               else {
+                                       if (!(crq->cr_flag
+                                           & CRYPTO_SKIP_REQID)) {
+                                       /*
+                                        * Set the request handle. This handle
+                                        * is used for any crypto_cancel_req(9f)
+                                        * calls from the consumer. We have to
+                                        * do this before dispatching the
+                                        * request.
+                                        */
+                                       crq->cr_reqid = kcf_reqid_insert(areq);
+                                       }
+
+                                       error = kcf_disp_sw_request(areq);
+                                       /*
+                                        * There is an error processing this
+                                        * request. Remove the handle and
+                                        * release the request structure.
+                                        */
+                                       if (error != CRYPTO_QUEUED) {
+                                               if (!(crq->cr_flag
+                                                   & CRYPTO_SKIP_REQID))
+                                                       kcf_reqid_delete(areq);
+                                               KCF_AREQ_REFRELE(areq);
+                                       }
+                               }
+                       }
+                       break;
+
+               case CRYPTO_HW_PROVIDER:
+                       /*
+                        * We need to queue the request and return.
+                        */
+                       areq = kcf_areqnode_alloc(pd, kcf_ctx, crq, params,
+                           cont);
+                       if (areq == NULL) {
+                               error = CRYPTO_HOST_MEMORY;
+                               goto done;
+                       }
+
+                       ASSERT(taskq != NULL);
+                       /*
+                        * We can not tell from taskq_dispatch() return
+                        * value if we exceeded maxalloc. Hence the check
+                        * here.
+                        */
+                       if (taskq->tq_nalloc >= crypto_taskq_maxalloc) {
+                               error = CRYPTO_BUSY;
+                               KCF_AREQ_REFRELE(areq);
+                               goto done;
+                       }
+
+                       if (!(crq->cr_flag & CRYPTO_SKIP_REQID)) {
+                       /*
+                        * Set the request handle. This handle is used
+                        * for any crypto_cancel_req(9f) calls from the
+                        * consumer. We have to do this before dispatching
+                        * the request.
+                        */
+                       crq->cr_reqid = kcf_reqid_insert(areq);
+                       }
+
+                       if (taskq_dispatch(taskq,
+                           process_req_hwp, areq, TQ_NOSLEEP) ==
+                           (taskqid_t)0) {
+                               error = CRYPTO_HOST_MEMORY;
+                               if (!(crq->cr_flag & CRYPTO_SKIP_REQID))
+                                       kcf_reqid_delete(areq);
+                               KCF_AREQ_REFRELE(areq);
+                       } else {
+                               error = CRYPTO_QUEUED;
+                       }
+                       break;
+
+               default:
+                       error = CRYPTO_FAILED;
+                       break;
+               }
+       }
+
+done:
+       return (error);
+}
+
+/*
+ * We're done with this framework context, so free it. Note that freeing
+ * framework context (kcf_context) frees the global context (crypto_ctx).
+ *
+ * The provider is responsible for freeing provider private context after a
+ * final or single operation and resetting the cc_provider_private field
+ * to NULL. It should do this before it notifies the framework of the
+ * completion. We still need to call KCF_PROV_FREE_CONTEXT to handle cases
+ * like crypto_cancel_ctx(9f).
+ */
+void
+kcf_free_context(kcf_context_t *kcf_ctx)
+{
+       kcf_provider_desc_t *pd = kcf_ctx->kc_prov_desc;
+       crypto_ctx_t *gctx = &kcf_ctx->kc_glbl_ctx;
+       kcf_context_t *kcf_secondctx = kcf_ctx->kc_secondctx;
+
+       /* Release the second context, if any */
+
+       if (kcf_secondctx != NULL)
+               KCF_CONTEXT_REFRELE(kcf_secondctx);
+
+       if (gctx->cc_provider_private != NULL) {
+               mutex_enter(&pd->pd_lock);
+               if (!KCF_IS_PROV_REMOVED(pd)) {
+                       /*
+                        * Increment the provider's internal refcnt so it
+                        * doesn't unregister from the framework while
+                        * we're calling the entry point.
+                        */
+                       KCF_PROV_IREFHOLD(pd);
+                       mutex_exit(&pd->pd_lock);
+                       (void) KCF_PROV_FREE_CONTEXT(pd, gctx);
+                       KCF_PROV_IREFRELE(pd);
+               } else {
+                       mutex_exit(&pd->pd_lock);
+               }
+       }
+
+       /* kcf_ctx->kc_prov_desc has a hold on pd */
+       KCF_PROV_REFRELE(kcf_ctx->kc_prov_desc);
+
+       /* check if this context is shared with a software provider */
+       if ((gctx->cc_flags & CRYPTO_INIT_OPSTATE) &&
+           kcf_ctx->kc_sw_prov_desc != NULL) {
+               KCF_PROV_REFRELE(kcf_ctx->kc_sw_prov_desc);
+       }
+
+       kmem_cache_free(kcf_context_cache, kcf_ctx);
+}
+
+/*
+ * Free the request after releasing all the holds.
+ */
+void
+kcf_free_req(kcf_areq_node_t *areq)
+{
+       KCF_PROV_REFRELE(areq->an_provider);
+       if (areq->an_context != NULL)
+               KCF_CONTEXT_REFRELE(areq->an_context);
+
+       if (areq->an_tried_plist != NULL)
+               kcf_free_triedlist(areq->an_tried_plist);
+       kmem_cache_free(kcf_areq_cache, areq);
+}
+
+/*
+ * Utility routine to remove a request from the chain of requests
+ * hanging off a context.
+ */
+void
+kcf_removereq_in_ctxchain(kcf_context_t *ictx, kcf_areq_node_t *areq)
+{
+       kcf_areq_node_t *cur, *prev;
+
+       /*
+        * Get context lock, search for areq in the chain and remove it.
+        */
+       ASSERT(ictx != NULL);
+       mutex_enter(&ictx->kc_in_use_lock);
+       prev = cur = ictx->kc_req_chain_first;
+
+       while (cur != NULL) {
+               if (cur == areq) {
+                       if (prev == cur) {
+                               if ((ictx->kc_req_chain_first =
+                                   cur->an_ctxchain_next) == NULL)
+                                       ictx->kc_req_chain_last = NULL;
+                       } else {
+                               if (cur == ictx->kc_req_chain_last)
+                                       ictx->kc_req_chain_last = prev;
+                               prev->an_ctxchain_next = cur->an_ctxchain_next;
+                       }
+
+                       break;
+               }
+               prev = cur;
+               cur = cur->an_ctxchain_next;
+       }
+       mutex_exit(&ictx->kc_in_use_lock);
+}
+
+/*
+ * Remove the specified node from the global software queue.
+ *
+ * The caller must hold the queue lock and request lock (an_lock).
+ */
+void
+kcf_remove_node(kcf_areq_node_t *node)
+{
+       kcf_areq_node_t *nextp = node->an_next;
+       kcf_areq_node_t *prevp = node->an_prev;
+
+       if (nextp != NULL)
+               nextp->an_prev = prevp;
+       else
+               gswq->gs_last = prevp;
+
+       if (prevp != NULL)
+               prevp->an_next = nextp;
+       else
+               gswq->gs_first = nextp;
+
+       node->an_state = REQ_CANCELED;
+}
+
+/*
+ * Add the request node to the end of the global software queue.
+ *
+ * The caller should not hold the queue lock. Returns 0 if the
+ * request is successfully queued. Returns CRYPTO_BUSY if the limit
+ * on the number of jobs is exceeded.
+ */
+static int
+kcf_enqueue(kcf_areq_node_t *node)
+{
+       kcf_areq_node_t *tnode;
+
+       mutex_enter(&gswq->gs_lock);
+
+       if (gswq->gs_njobs >= gswq->gs_maxjobs) {
+               mutex_exit(&gswq->gs_lock);
+               return (CRYPTO_BUSY);
+       }
+
+       if (gswq->gs_last == NULL) {
+               gswq->gs_first = gswq->gs_last = node;
+       } else {
+               ASSERT(gswq->gs_last->an_next == NULL);
+               tnode = gswq->gs_last;
+               tnode->an_next = node;
+               gswq->gs_last = node;
+               node->an_prev = tnode;
+       }
+
+       gswq->gs_njobs++;
+
+       /* an_lock not needed here as we hold gs_lock */
+       node->an_state = REQ_WAITING;
+
+       mutex_exit(&gswq->gs_lock);
+
+       return (0);
+}
+
+/*
+ * kmem_cache_alloc constructor for sync request structure.
+ */
+/* ARGSUSED */
+static int
+kcf_sreq_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+       kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)buf;
+
+       sreq->sn_type = CRYPTO_SYNCH;
+       cv_init(&sreq->sn_cv, NULL, CV_DEFAULT, NULL);
+       mutex_init(&sreq->sn_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       return (0);
+}
+
+/* ARGSUSED */
+static void
+kcf_sreq_cache_destructor(void *buf, void *cdrarg)
+{
+       kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)buf;
+
+       mutex_destroy(&sreq->sn_lock);
+       cv_destroy(&sreq->sn_cv);
+}
+
+/*
+ * kmem_cache_alloc constructor for async request structure.
+ */
+/* ARGSUSED */
+static int
+kcf_areq_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+       kcf_areq_node_t *areq = (kcf_areq_node_t *)buf;
+
+       areq->an_type = CRYPTO_ASYNCH;
+       areq->an_refcnt = 0;
+       mutex_init(&areq->an_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&areq->an_done, NULL, CV_DEFAULT, NULL);
+       cv_init(&areq->an_turn_cv, NULL, CV_DEFAULT, NULL);
+
+       return (0);
+}
+
+/* ARGSUSED */
+static void
+kcf_areq_cache_destructor(void *buf, void *cdrarg)
+{
+       kcf_areq_node_t *areq = (kcf_areq_node_t *)buf;
+
+       ASSERT(areq->an_refcnt == 0);
+       mutex_destroy(&areq->an_lock);
+       cv_destroy(&areq->an_done);
+       cv_destroy(&areq->an_turn_cv);
+}
+
+/*
+ * kmem_cache_alloc constructor for kcf_context structure.
+ */
+/* ARGSUSED */
+static int
+kcf_context_cache_constructor(void *buf, void *cdrarg, int kmflags)
+{
+       kcf_context_t *kctx = (kcf_context_t *)buf;
+
+       kctx->kc_refcnt = 0;
+       mutex_init(&kctx->kc_in_use_lock, NULL, MUTEX_DEFAULT, NULL);
+
+       return (0);
+}
+
+/* ARGSUSED */
+static void
+kcf_context_cache_destructor(void *buf, void *cdrarg)
+{
+       kcf_context_t *kctx = (kcf_context_t *)buf;
+
+       ASSERT(kctx->kc_refcnt == 0);
+       mutex_destroy(&kctx->kc_in_use_lock);
+}
+
+void
+kcf_sched_destroy(void)
+{
+       int i;
+
+       if (kcf_misc_kstat)
+               kstat_delete(kcf_misc_kstat);
+
+       if (kcfpool)
+               kmem_free(kcfpool, sizeof (kcf_pool_t));
+
+       for (i = 0; i < REQID_TABLES; i++) {
+               if (kcf_reqid_table[i])
+                       kmem_free(kcf_reqid_table[i],
+                               sizeof (kcf_reqid_table_t));
+       }
+
+       if (gswq)
+               kmem_free(gswq, sizeof (kcf_global_swq_t));
+
+       if (kcf_context_cache)
+               kmem_cache_destroy(kcf_context_cache);
+       if (kcf_areq_cache)
+               kmem_cache_destroy(kcf_areq_cache);
+       if (kcf_sreq_cache)
+               kmem_cache_destroy(kcf_sreq_cache);
+}
+
+/*
+ * Creates and initializes all the structures needed by the framework.
+ */
+void
+kcf_sched_init(void)
+{
+       int i;
+       kcf_reqid_table_t *rt;
+
+       /*
+        * Create all the kmem caches needed by the framework. We set the
+        * align argument to 64, to get a slab aligned to 64-byte as well as
+        * have the objects (cache_chunksize) to be a 64-byte multiple.
+        * This helps to avoid false sharing as this is the size of the
+        * CPU cache line.
+        */
+       kcf_sreq_cache = kmem_cache_create("kcf_sreq_cache",
+           sizeof (struct kcf_sreq_node), 64, kcf_sreq_cache_constructor,
+           kcf_sreq_cache_destructor, NULL, NULL, NULL, 0);
+
+       kcf_areq_cache = kmem_cache_create("kcf_areq_cache",
+           sizeof (struct kcf_areq_node), 64, kcf_areq_cache_constructor,
+           kcf_areq_cache_destructor, NULL, NULL, NULL, 0);
+
+       kcf_context_cache = kmem_cache_create("kcf_context_cache",
+           sizeof (struct kcf_context), 64, kcf_context_cache_constructor,
+           kcf_context_cache_destructor, NULL, NULL, NULL, 0);
+
+       gswq = kmem_alloc(sizeof (kcf_global_swq_t), KM_SLEEP);
+
+       mutex_init(&gswq->gs_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&gswq->gs_cv, NULL, CV_DEFAULT, NULL);
+       gswq->gs_njobs = 0;
+       gswq->gs_maxjobs = kcf_maxthreads * crypto_taskq_maxalloc;
+       gswq->gs_first = gswq->gs_last = NULL;
+
+       /* Initialize the global reqid table */
+       for (i = 0; i < REQID_TABLES; i++) {
+               rt = kmem_zalloc(sizeof (kcf_reqid_table_t), KM_SLEEP);
+               kcf_reqid_table[i] = rt;
+               mutex_init(&rt->rt_lock, NULL, MUTEX_DEFAULT, NULL);
+               rt->rt_curid = i;
+       }
+
+       /* Allocate and initialize the thread pool */
+       kcfpool_alloc();
+
+       /* Initialize the event notification list variables */
+       mutex_init(&ntfy_list_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&ntfy_list_cv, NULL, CV_DEFAULT, NULL);
+
+       /* Create the kcf kstat */
+       kcf_misc_kstat = kstat_create("kcf", 0, "framework_stats", "crypto",
+           KSTAT_TYPE_NAMED, sizeof (kcf_stats_t) / sizeof (kstat_named_t),
+           KSTAT_FLAG_VIRTUAL);
+
+       if (kcf_misc_kstat != NULL) {
+               kcf_misc_kstat->ks_data = &kcf_ksdata;
+               kcf_misc_kstat->ks_update = kcf_misc_kstat_update;
+               kstat_install(kcf_misc_kstat);
+       }
+}
+
+/*
+ * Signal the waiting sync client.
+ */
+void
+kcf_sop_done(kcf_sreq_node_t *sreq, int error)
+{
+       mutex_enter(&sreq->sn_lock);
+       sreq->sn_state = REQ_DONE;
+       sreq->sn_rv = error;
+       cv_signal(&sreq->sn_cv);
+       mutex_exit(&sreq->sn_lock);
+}
+
+/*
+ * Callback the async client with the operation status.
+ * We free the async request node and possibly the context.
+ * We also handle any chain of requests hanging off of
+ * the context.
+ */
+void
+kcf_aop_done(kcf_areq_node_t *areq, int error)
+{
+       kcf_op_type_t optype;
+       boolean_t skip_notify = B_FALSE;
+       kcf_context_t *ictx;
+       kcf_areq_node_t *nextreq;
+
+       /*
+        * Handle recoverable errors. This has to be done first
+        * before doing any thing else in this routine so that
+        * we do not change the state of the request.
+        */
+       if (error != CRYPTO_SUCCESS && IS_RECOVERABLE(error)) {
+               /*
+                * We try another provider, if one is available. Else
+                * we continue with the failure notification to the
+                * client.
+                */
+               if (kcf_resubmit_request(areq) == CRYPTO_QUEUED)
+                       return;
+       }
+
+       mutex_enter(&areq->an_lock);
+       areq->an_state = REQ_DONE;
+       mutex_exit(&areq->an_lock);
+
+       optype = (&areq->an_params)->rp_optype;
+       if ((ictx = areq->an_context) != NULL) {
+               /*
+                * A request after it is removed from the request
+                * queue, still stays on a chain of requests hanging
+                * of its context structure. It needs to be removed
+                * from this chain at this point.
+                */
+               mutex_enter(&ictx->kc_in_use_lock);
+               nextreq = areq->an_ctxchain_next;
+               if (nextreq != NULL) {
+                       mutex_enter(&nextreq->an_lock);
+                       nextreq->an_is_my_turn = B_TRUE;
+                       cv_signal(&nextreq->an_turn_cv);
+                       mutex_exit(&nextreq->an_lock);
+               }
+
+               ictx->kc_req_chain_first = nextreq;
+               if (nextreq == NULL)
+                       ictx->kc_req_chain_last = NULL;
+               mutex_exit(&ictx->kc_in_use_lock);
+
+               if (IS_SINGLE_OP(optype) || IS_FINAL_OP(optype)) {
+                       ASSERT(nextreq == NULL);
+                       KCF_CONTEXT_REFRELE(ictx);
+               } else if (error != CRYPTO_SUCCESS && IS_INIT_OP(optype)) {
+               /*
+                * NOTE - We do not release the context in case of update
+                * operations. We require the consumer to free it explicitly,
+                * in case it wants to abandon an update operation. This is done
+                * as there may be mechanisms in ECB mode that can continue
+                * even if an operation on a block fails.
+                */
+                       KCF_CONTEXT_REFRELE(ictx);
+               }
+       }
+
+       /* Deal with the internal continuation to this request first */
+
+       if (areq->an_isdual) {
+               kcf_dual_req_t *next_arg;
+               next_arg = (kcf_dual_req_t *)areq->an_reqarg.cr_callback_arg;
+               next_arg->kr_areq = areq;
+               KCF_AREQ_REFHOLD(areq);
+               areq->an_isdual = B_FALSE;
+
+               NOTIFY_CLIENT(areq, error);
+               return;
+       }
+
+       /*
+        * If CRYPTO_NOTIFY_OPDONE flag is set, we should notify
+        * always. If this flag is clear, we skip the notification
+        * provided there are no errors.  We check this flag for only
+        * init or update operations. It is ignored for single, final or
+        * atomic operations.
+        */
+       skip_notify = (IS_UPDATE_OP(optype) || IS_INIT_OP(optype)) &&
+           (!(areq->an_reqarg.cr_flag & CRYPTO_NOTIFY_OPDONE)) &&
+           (error == CRYPTO_SUCCESS);
+
+       if (!skip_notify) {
+               NOTIFY_CLIENT(areq, error);
+       }
+
+       if (!(areq->an_reqarg.cr_flag & CRYPTO_SKIP_REQID))
+               kcf_reqid_delete(areq);
+
+       KCF_AREQ_REFRELE(areq);
+}
+
+/*
+ * Allocate the thread pool and initialize all the fields.
+ */
+static void
+kcfpool_alloc()
+{
+       kcfpool = kmem_alloc(sizeof (kcf_pool_t), KM_SLEEP);
+
+       kcfpool->kp_threads = kcfpool->kp_idlethreads = 0;
+       kcfpool->kp_blockedthreads = 0;
+       kcfpool->kp_signal_create_thread = B_FALSE;
+       kcfpool->kp_nthrs = 0;
+       kcfpool->kp_user_waiting = B_FALSE;
+
+       mutex_init(&kcfpool->kp_thread_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&kcfpool->kp_nothr_cv, NULL, CV_DEFAULT, NULL);
+
+       mutex_init(&kcfpool->kp_user_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&kcfpool->kp_user_cv, NULL, CV_DEFAULT, NULL);
+
+       kcf_idlethr_timeout = KCF_DEFAULT_THRTIMEOUT;
+}
+
+/*
+ * Insert the async request in the hash table after assigning it
+ * an ID. Returns the ID.
+ *
+ * The ID is used by the caller to pass as an argument to a
+ * cancel_req() routine later.
+ */
+static crypto_req_id_t
+kcf_reqid_insert(kcf_areq_node_t *areq)
+{
+       int indx;
+       crypto_req_id_t id;
+       kcf_areq_node_t *headp;
+       kcf_reqid_table_t *rt =
+           kcf_reqid_table[CPU_SEQID & REQID_TABLE_MASK];
+
+       mutex_enter(&rt->rt_lock);
+
+       rt->rt_curid = id =
+           (rt->rt_curid - REQID_COUNTER_LOW) | REQID_COUNTER_HIGH;
+       SET_REQID(areq, id);
+       indx = REQID_HASH(id);
+       headp = areq->an_idnext = rt->rt_idhash[indx];
+       areq->an_idprev = NULL;
+       if (headp != NULL)
+               headp->an_idprev = areq;
+
+       rt->rt_idhash[indx] = areq;
+       mutex_exit(&rt->rt_lock);
+
+       return (id);
+}
+
+/*
+ * Delete the async request from the hash table.
+ */
+static void
+kcf_reqid_delete(kcf_areq_node_t *areq)
+{
+       int indx;
+       kcf_areq_node_t *nextp, *prevp;
+       crypto_req_id_t id = GET_REQID(areq);
+       kcf_reqid_table_t *rt;
+
+       rt = kcf_reqid_table[id & REQID_TABLE_MASK];
+       indx = REQID_HASH(id);
+
+       mutex_enter(&rt->rt_lock);
+
+       nextp = areq->an_idnext;
+       prevp = areq->an_idprev;
+       if (nextp != NULL)
+               nextp->an_idprev = prevp;
+       if (prevp != NULL)
+               prevp->an_idnext = nextp;
+       else
+               rt->rt_idhash[indx] = nextp;
+
+       SET_REQID(areq, 0);
+       cv_broadcast(&areq->an_done);
+
+       mutex_exit(&rt->rt_lock);
+}
+
+/*
+ * Cancel a single asynchronous request.
+ *
+ * We guarantee that no problems will result from calling
+ * crypto_cancel_req() for a request which is either running, or
+ * has already completed. We remove the request from any queues
+ * if it is possible. We wait for request completion if the
+ * request is dispatched to a provider.
+ *
+ * Calling context:
+ *     Can be called from user context only.
+ *
+ * NOTE: We acquire the following locks in this routine (in order):
+ *     - rt_lock (kcf_reqid_table_t)
+ *     - gswq->gs_lock
+ *     - areq->an_lock
+ *     - ictx->kc_in_use_lock (from kcf_removereq_in_ctxchain())
+ *
+ * This locking order MUST be maintained in code every where else.
+ */
+void
+crypto_cancel_req(crypto_req_id_t id)
+{
+       int indx;
+       kcf_areq_node_t *areq;
+       kcf_provider_desc_t *pd;
+       kcf_context_t *ictx;
+       kcf_reqid_table_t *rt;
+
+       rt = kcf_reqid_table[id & REQID_TABLE_MASK];
+       indx = REQID_HASH(id);
+
+       mutex_enter(&rt->rt_lock);
+       for (areq = rt->rt_idhash[indx]; areq; areq = areq->an_idnext) {
+       if (GET_REQID(areq) == id) {
+               /*
+                * We found the request. It is either still waiting
+                * in the framework queues or running at the provider.
+                */
+               pd = areq->an_provider;
+               ASSERT(pd != NULL);
+
+               switch (pd->pd_prov_type) {
+               case CRYPTO_SW_PROVIDER:
+                       mutex_enter(&gswq->gs_lock);
+                       mutex_enter(&areq->an_lock);
+
+                       /* This request can be safely canceled. */
+                       if (areq->an_state <= REQ_WAITING) {
+                               /* Remove from gswq, global software queue. */
+                               kcf_remove_node(areq);
+                               if ((ictx = areq->an_context) != NULL)
+                                       kcf_removereq_in_ctxchain(ictx, areq);
+
+                               mutex_exit(&areq->an_lock);
+                               mutex_exit(&gswq->gs_lock);
+                               mutex_exit(&rt->rt_lock);
+
+                               /* Remove areq from hash table and free it. */
+                               kcf_reqid_delete(areq);
+                               KCF_AREQ_REFRELE(areq);
+                               return;
+                       }
+
+                       mutex_exit(&areq->an_lock);
+                       mutex_exit(&gswq->gs_lock);
+                       break;
+
+               case CRYPTO_HW_PROVIDER:
+                       /*
+                        * There is no interface to remove an entry
+                        * once it is on the taskq. So, we do not do
+                        * any thing for a hardware provider.
+                        */
+                       break;
+               default:
+                       break;
+               }
+
+               /*
+                * The request is running. Wait for the request completion
+                * to notify us.
+                */
+               KCF_AREQ_REFHOLD(areq);
+               while (GET_REQID(areq) == id)
+                       cv_wait(&areq->an_done, &rt->rt_lock);
+               KCF_AREQ_REFRELE(areq);
+               break;
+       }
+       }
+
+       mutex_exit(&rt->rt_lock);
+}
+
+/*
+ * Cancel all asynchronous requests associated with the
+ * passed in crypto context and free it.
+ *
+ * A client SHOULD NOT call this routine after calling a crypto_*_final
+ * routine. This routine is called only during intermediate operations.
+ * The client should not use the crypto context after this function returns
+ * since we destroy it.
+ *
+ * Calling context:
+ *     Can be called from user context only.
+ */
+void
+crypto_cancel_ctx(crypto_context_t ctx)
+{
+       kcf_context_t *ictx;
+       kcf_areq_node_t *areq;
+
+       if (ctx == NULL)
+               return;
+
+       ictx = (kcf_context_t *)((crypto_ctx_t *)ctx)->cc_framework_private;
+
+       mutex_enter(&ictx->kc_in_use_lock);
+
+       /* Walk the chain and cancel each request */
+       while ((areq = ictx->kc_req_chain_first) != NULL) {
+               /*
+                * We have to drop the lock here as we may have
+                * to wait for request completion. We hold the
+                * request before dropping the lock though, so that it
+                * won't be freed underneath us.
+                */
+               KCF_AREQ_REFHOLD(areq);
+               mutex_exit(&ictx->kc_in_use_lock);
+
+               crypto_cancel_req(GET_REQID(areq));
+               KCF_AREQ_REFRELE(areq);
+
+               mutex_enter(&ictx->kc_in_use_lock);
+       }
+
+       mutex_exit(&ictx->kc_in_use_lock);
+       KCF_CONTEXT_REFRELE(ictx);
+}
+
+/*
+ * Update kstats.
+ */
+static int
+kcf_misc_kstat_update(kstat_t *ksp, int rw)
+{
+       uint_t tcnt;
+       kcf_stats_t *ks_data;
+
+       if (rw == KSTAT_WRITE)
+               return (EACCES);
+
+       ks_data = ksp->ks_data;
+
+       ks_data->ks_thrs_in_pool.value.ui32 = kcfpool->kp_threads;
+       /*
+        * The failover thread is counted in kp_idlethreads in
+        * some corner cases. This is done to avoid doing more checks
+        * when submitting a request. We account for those cases below.
+        */
+       if ((tcnt = kcfpool->kp_idlethreads) == (kcfpool->kp_threads + 1))
+               tcnt--;
+       ks_data->ks_idle_thrs.value.ui32 = tcnt;
+       ks_data->ks_minthrs.value.ui32 = kcf_minthreads;
+       ks_data->ks_maxthrs.value.ui32 = kcf_maxthreads;
+       ks_data->ks_swq_njobs.value.ui32 = gswq->gs_njobs;
+       ks_data->ks_swq_maxjobs.value.ui32 = gswq->gs_maxjobs;
+       ks_data->ks_taskq_threads.value.ui32 = crypto_taskq_threads;
+       ks_data->ks_taskq_minalloc.value.ui32 = crypto_taskq_minalloc;
+       ks_data->ks_taskq_maxalloc.value.ui32 = crypto_taskq_maxalloc;
+
+       return (0);
+}
+
+/*
+ * Allocate and initiatize a kcf_dual_req, used for saving the arguments of
+ * a dual operation or an atomic operation that has to be internally
+ * simulated with multiple single steps.
+ * crq determines the memory allocation flags.
+ */
+
+kcf_dual_req_t *
+kcf_alloc_req(crypto_call_req_t *crq)
+{
+       kcf_dual_req_t *kcr;
+
+       kcr = kmem_alloc(sizeof (kcf_dual_req_t), KCF_KMFLAG(crq));
+
+       if (kcr == NULL)
+               return (NULL);
+
+       /* Copy the whole crypto_call_req struct, as it isn't persistant */
+       if (crq != NULL)
+               kcr->kr_callreq = *crq;
+       else
+               bzero(&(kcr->kr_callreq), sizeof (crypto_call_req_t));
+       kcr->kr_areq = NULL;
+       kcr->kr_saveoffset = 0;
+       kcr->kr_savelen = 0;
+
+       return (kcr);
+}
+
+/*
+ * Callback routine for the next part of a simulated dual part.
+ * Schedules the next step.
+ *
+ * This routine can be called from interrupt context.
+ */
+void
+kcf_next_req(void *next_req_arg, int status)
+{
+       kcf_dual_req_t *next_req = (kcf_dual_req_t *)next_req_arg;
+       kcf_req_params_t *params = &(next_req->kr_params);
+       kcf_areq_node_t *areq = next_req->kr_areq;
+       int error = status;
+       kcf_provider_desc_t *pd = NULL;
+       crypto_dual_data_t *ct = NULL;
+
+       /* Stop the processing if an error occured at this step */
+       if (error != CRYPTO_SUCCESS) {
+out:
+               areq->an_reqarg = next_req->kr_callreq;
+               KCF_AREQ_REFRELE(areq);
+               kmem_free(next_req, sizeof (kcf_dual_req_t));
+               areq->an_isdual = B_FALSE;
+               kcf_aop_done(areq, error);
+               return;
+       }
+
+       switch (params->rp_opgrp) {
+       case KCF_OG_MAC: {
+
+               /*
+                * The next req is submitted with the same reqid as the
+                * first part. The consumer only got back that reqid, and
+                * should still be able to cancel the operation during its
+                * second step.
+                */
+               kcf_mac_ops_params_t *mops = &(params->rp_u.mac_params);
+               crypto_ctx_template_t mac_tmpl;
+               kcf_mech_entry_t *me;
+
+               ct = (crypto_dual_data_t *)mops->mo_data;
+               mac_tmpl = (crypto_ctx_template_t)mops->mo_templ;
+
+               /* No expected recoverable failures, so no retry list */
+               pd = kcf_get_mech_provider(mops->mo_framework_mechtype,
+                   &me, &error, NULL, CRYPTO_FG_MAC_ATOMIC,
+                   (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED), ct->dd_len2);
+
+               if (pd == NULL) {
+                       error = CRYPTO_MECH_NOT_SUPPORTED;
+                       goto out;
+               }
+               /* Validate the MAC context template here */
+               if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
+                   (mac_tmpl != NULL)) {
+                       kcf_ctx_template_t *ctx_mac_tmpl;
+
+                       ctx_mac_tmpl = (kcf_ctx_template_t *)mac_tmpl;
+
+                       if (ctx_mac_tmpl->ct_generation != me->me_gen_swprov) {
+                               KCF_PROV_REFRELE(pd);
+                               error = CRYPTO_OLD_CTX_TEMPLATE;
+                               goto out;
+                       }
+                       mops->mo_templ = ctx_mac_tmpl->ct_prov_tmpl;
+               }
+
+               break;
+       }
+       case KCF_OG_DECRYPT: {
+               kcf_decrypt_ops_params_t *dcrops =
+                   &(params->rp_u.decrypt_params);
+
+               ct = (crypto_dual_data_t *)dcrops->dop_ciphertext;
+               /* No expected recoverable failures, so no retry list */
+               pd = kcf_get_mech_provider(dcrops->dop_framework_mechtype,
+                   NULL, &error, NULL, CRYPTO_FG_DECRYPT_ATOMIC,
+                   (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED), ct->dd_len1);
+
+               if (pd == NULL) {
+                       error = CRYPTO_MECH_NOT_SUPPORTED;
+                       goto out;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+       /* The second step uses len2 and offset2 of the dual_data */
+       next_req->kr_saveoffset = ct->dd_offset1;
+       next_req->kr_savelen = ct->dd_len1;
+       ct->dd_offset1 = ct->dd_offset2;
+       ct->dd_len1 = ct->dd_len2;
+
+       /* preserve if the caller is restricted */
+       if (areq->an_reqarg.cr_flag & CRYPTO_RESTRICTED) {
+               areq->an_reqarg.cr_flag = CRYPTO_RESTRICTED;
+       } else {
+               areq->an_reqarg.cr_flag = 0;
+       }
+
+       areq->an_reqarg.cr_callback_func = kcf_last_req;
+       areq->an_reqarg.cr_callback_arg = next_req;
+       areq->an_isdual = B_TRUE;
+
+       /*
+        * We would like to call kcf_submit_request() here. But,
+        * that is not possible as that routine allocates a new
+        * kcf_areq_node_t request structure, while we need to
+        * reuse the existing request structure.
+        */
+       switch (pd->pd_prov_type) {
+       case CRYPTO_SW_PROVIDER:
+               error = common_submit_request(pd, NULL, params,
+                   KCF_RHNDL(KM_NOSLEEP));
+               break;
+
+       case CRYPTO_HW_PROVIDER: {
+               kcf_provider_desc_t *old_pd;
+               taskq_t *taskq = pd->pd_sched_info.ks_taskq;
+
+               /*
+                * Set the params for the second step in the
+                * dual-ops.
+                */
+               areq->an_params = *params;
+               old_pd = areq->an_provider;
+               KCF_PROV_REFRELE(old_pd);
+               KCF_PROV_REFHOLD(pd);
+               areq->an_provider = pd;
+
+               /*
+                * Note that we have to do a taskq_dispatch()
+                * here as we may be in interrupt context.
+                */
+               if (taskq_dispatch(taskq, process_req_hwp, areq,
+                   TQ_NOSLEEP) == (taskqid_t)0) {
+                       error = CRYPTO_HOST_MEMORY;
+               } else {
+                       error = CRYPTO_QUEUED;
+               }
+               break;
+       }
+       default:
+               break;
+       }
+
+       /*
+        * We have to release the holds on the request and the provider
+        * in all cases.
+        */
+       KCF_AREQ_REFRELE(areq);
+       KCF_PROV_REFRELE(pd);
+
+       if (error != CRYPTO_QUEUED) {
+               /* restore, clean up, and invoke the client's callback */
+
+               ct->dd_offset1 = next_req->kr_saveoffset;
+               ct->dd_len1 = next_req->kr_savelen;
+               areq->an_reqarg = next_req->kr_callreq;
+               kmem_free(next_req, sizeof (kcf_dual_req_t));
+               areq->an_isdual = B_FALSE;
+               kcf_aop_done(areq, error);
+       }
+}
+
+/*
+ * Last part of an emulated dual operation.
+ * Clean up and restore ...
+ */
+void
+kcf_last_req(void *last_req_arg, int status)
+{
+       kcf_dual_req_t *last_req = (kcf_dual_req_t *)last_req_arg;
+
+       kcf_req_params_t *params = &(last_req->kr_params);
+       kcf_areq_node_t *areq = last_req->kr_areq;
+       crypto_dual_data_t *ct = NULL;
+
+       switch (params->rp_opgrp) {
+       case KCF_OG_MAC: {
+               kcf_mac_ops_params_t *mops = &(params->rp_u.mac_params);
+
+               ct = (crypto_dual_data_t *)mops->mo_data;
+               break;
+       }
+       case KCF_OG_DECRYPT: {
+               kcf_decrypt_ops_params_t *dcrops =
+                   &(params->rp_u.decrypt_params);
+
+               ct = (crypto_dual_data_t *)dcrops->dop_ciphertext;
+               break;
+       }
+       default: {
+               panic("invalid kcf_op_group_t %d", (int)params->rp_opgrp);
+               return;
+       }
+       }
+       ct->dd_offset1 = last_req->kr_saveoffset;
+       ct->dd_len1 = last_req->kr_savelen;
+
+       /* The submitter used kcf_last_req as its callback */
+
+       if (areq == NULL) {
+               crypto_call_req_t *cr = &last_req->kr_callreq;
+
+               (*(cr->cr_callback_func))(cr->cr_callback_arg, status);
+               kmem_free(last_req, sizeof (kcf_dual_req_t));
+               return;
+       }
+       areq->an_reqarg = last_req->kr_callreq;
+       KCF_AREQ_REFRELE(areq);
+       kmem_free(last_req, sizeof (kcf_dual_req_t));
+       areq->an_isdual = B_FALSE;
+       kcf_aop_done(areq, status);
+}
diff --git a/zfs/module/icp/illumos-crypto.c b/zfs/module/icp/illumos-crypto.c
new file mode 100644 (file)
index 0000000..aa63e43
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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 (c) 2016, Datto, Inc. All rights reserved.
+ */
+
+#ifdef _KERNEL
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#else
+#define        __exit
+#define        __init
+#endif
+
+#include <sys/crypto/common.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/sched_impl.h>
+#include <sys/modhash_impl.h>
+#include <sys/crypto/icp.h>
+
+/*
+ * Changes made to the original Illumos Crypto Layer for the ICP:
+ *
+ * Several changes were needed to allow the Illumos Crypto Layer
+ * to work in the Linux kernel. Almost all of the changes fall into
+ * one of the following categories:
+ *
+ * 1) Moving the syntax to the C90: This was mostly a matter of
+ * changing func() definitions to func(void). In a few cases,
+ * initializations of structs with unions needed to have brackets
+ * added.
+ *
+ * 2) Changes to allow userspace compilation: The ICP is meant to be
+ * compiled and used in both userspace and kernel space (for ztest and
+ * libzfs), so the _KERNEL macros did not make sense anymore. For the
+ * same reason, many header includes were also changed to use
+ * sys/zfs_context.h
+ *
+ * 3) Moving to a statically compiled architecture: At some point in
+ * the future it may make sense to have encryption algorithms that are
+ * loadable into the ICP at runtime via separate kernel modules.
+ * However, considering that this code will probably not see much use
+ * outside of zfs and zfs encryption only requires aes and sha256
+ * algorithms it seemed like more trouble than it was worth to port over
+ * Illumos's kernel module structure to a Linux kernel module. In
+ * addition, The Illumos code related to keeping track of kernel modules
+ * is very much tied to the Illumos OS and proved difficult to port to
+ * Linux. Therefore, the structure of the ICP was simplified to work
+ * statically and several pieces of code responsible for keeping track
+ * of Illumos kernel modules were removed and simplified. All module
+ * initialization and destruction is now called in this file during
+ * Linux kernel module loading and unloading.
+ *
+ * 4) Adding destructors: The Illumos Crypto Layer is built into
+ * the Illumos kernel and is not meant to be unloaded. Some destructors
+ * were added to allow the ICP to be unloaded without leaking
+ * structures.
+ *
+ * 5) Removing CRYPTO_DATA_MBLK related structures and code:
+ * crypto_data_t can have 3 formats, CRYPTO_DATA_RAW, CRYPTO_DATA_UIO,
+ * and CRYPTO_DATA_MBLK. ZFS only requires the first 2 formats, as the
+ * last one is related to streamed data. To simplify the port, code
+ * related to this format was removed.
+ *
+ * 6) Changes for architecture specific code: Some changes were needed
+ * to make architecture specific assembly compile. The biggest change
+ * here was to functions related to detecting CPU capabilities for amd64.
+ * The Illumos Crypto Layer used called into the Illumos kernel's API
+ * to discover these. They have been converted to instead use the
+ * 'cpuid' instruction as per the Intel spec. In addition, references to
+ * the sun4u' and sparc architectures have been removed so that these
+ * will use the generic implementation.
+ *
+ * 7) Removing sha384 and sha512 code: The sha code was actually very
+ * wasy to port. However, the generic sha384 and sha512 code actually
+ * exceeds the stack size on arm and powerpc architectures. In an effort
+ * to remove warnings, this code was removed.
+ *
+ * 8) Change large allocations from kmem_alloc() to vmem_alloc(): In
+ * testing the ICP with the ZFS encryption code, a few allocations were
+ * found that could potentially be very large. These caused the SPL to
+ * throw warnings and so they were changed to use vmem_alloc().
+ *
+ * 9) Makefiles: Makefiles were added that would work with the existing
+ * ZFS Makefiles.
+ */
+
+void __exit
+icp_fini(void)
+{
+       skein_mod_fini();
+       sha2_mod_fini();
+       sha1_mod_fini();
+       edonr_mod_fini();
+       aes_mod_fini();
+       kcf_sched_destroy();
+       kcf_prov_tab_destroy();
+       kcf_destroy_mech_tabs();
+       mod_hash_fini();
+}
+
+/* roughly equivalent to kcf.c: _init() */
+int __init
+icp_init(void)
+{
+       /* initialize the mod hash module */
+       mod_hash_init();
+
+       /* initialize the mechanisms tables supported out-of-the-box */
+       kcf_init_mech_tabs();
+
+       /* initialize the providers tables */
+       kcf_prov_tab_init();
+
+       /*
+        * Initialize scheduling structures. Note that this does NOT
+        * start any threads since it might not be safe to do so.
+        */
+       kcf_sched_init();
+
+       /* initialize algorithms */
+       aes_mod_init();
+       edonr_mod_init();
+       sha1_mod_init();
+       sha2_mod_init();
+       skein_mod_init();
+
+       return (0);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+module_exit(icp_fini);
+module_init(icp_init);
+MODULE_LICENSE(ZFS_META_LICENSE);
+#endif
diff --git a/zfs/module/icp/include/aes/aes_impl.h b/zfs/module/icp/include/aes/aes_impl.h
new file mode 100644 (file)
index 0000000..ed15f74
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#ifndef        _AES_IMPL_H
+#define        _AES_IMPL_H
+
+/*
+ * Common definitions used by AES.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+
+/* Similar to sysmacros.h IS_P2ALIGNED, but checks two pointers: */
+#define        IS_P2ALIGNED2(v, w, a) \
+       ((((uintptr_t)(v) | (uintptr_t)(w)) & ((uintptr_t)(a) - 1)) == 0)
+
+#define        AES_BLOCK_LEN   16      /* bytes */
+/* Round constant length, in number of 32-bit elements: */
+#define        RC_LENGTH       (5 * ((AES_BLOCK_LEN) / 4 - 2))
+
+#define        AES_COPY_BLOCK(src, dst) \
+       (dst)[0] = (src)[0]; \
+       (dst)[1] = (src)[1]; \
+       (dst)[2] = (src)[2]; \
+       (dst)[3] = (src)[3]; \
+       (dst)[4] = (src)[4]; \
+       (dst)[5] = (src)[5]; \
+       (dst)[6] = (src)[6]; \
+       (dst)[7] = (src)[7]; \
+       (dst)[8] = (src)[8]; \
+       (dst)[9] = (src)[9]; \
+       (dst)[10] = (src)[10]; \
+       (dst)[11] = (src)[11]; \
+       (dst)[12] = (src)[12]; \
+       (dst)[13] = (src)[13]; \
+       (dst)[14] = (src)[14]; \
+       (dst)[15] = (src)[15]
+
+#define        AES_XOR_BLOCK(src, dst) \
+       (dst)[0] ^= (src)[0]; \
+       (dst)[1] ^= (src)[1]; \
+       (dst)[2] ^= (src)[2]; \
+       (dst)[3] ^= (src)[3]; \
+       (dst)[4] ^= (src)[4]; \
+       (dst)[5] ^= (src)[5]; \
+       (dst)[6] ^= (src)[6]; \
+       (dst)[7] ^= (src)[7]; \
+       (dst)[8] ^= (src)[8]; \
+       (dst)[9] ^= (src)[9]; \
+       (dst)[10] ^= (src)[10]; \
+       (dst)[11] ^= (src)[11]; \
+       (dst)[12] ^= (src)[12]; \
+       (dst)[13] ^= (src)[13]; \
+       (dst)[14] ^= (src)[14]; \
+       (dst)[15] ^= (src)[15]
+
+/* AES key size definitions */
+#define        AES_MINBITS             128
+#define        AES_MINBYTES            ((AES_MINBITS) >> 3)
+#define        AES_MAXBITS             256
+#define        AES_MAXBYTES            ((AES_MAXBITS) >> 3)
+
+#define        AES_MIN_KEY_BYTES       ((AES_MINBITS) >> 3)
+#define        AES_MAX_KEY_BYTES       ((AES_MAXBITS) >> 3)
+#define        AES_192_KEY_BYTES       24
+#define        AES_IV_LEN              16
+
+/* AES key schedule may be implemented with 32- or 64-bit elements: */
+#define        AES_32BIT_KS            32
+#define        AES_64BIT_KS            64
+
+#define        MAX_AES_NR              14 /* Maximum number of rounds */
+#define        MAX_AES_NB              4  /* Number of columns comprising a state */
+
+typedef union {
+#ifdef sun4u
+       uint64_t        ks64[((MAX_AES_NR) + 1) * (MAX_AES_NB)];
+#endif
+       uint32_t        ks32[((MAX_AES_NR) + 1) * (MAX_AES_NB)];
+} aes_ks_t;
+
+/* aes_key.flags value: */
+#define        INTEL_AES_NI_CAPABLE    0x1     /* AES-NI instructions present */
+
+typedef struct aes_key aes_key_t;
+struct aes_key {
+       aes_ks_t        encr_ks;  /* encryption key schedule */
+       aes_ks_t        decr_ks;  /* decryption key schedule */
+#ifdef __amd64
+       long double     align128; /* Align fields above for Intel AES-NI */
+       int             flags;    /* implementation-dependent flags */
+#endif /* __amd64 */
+       int             nr;       /* number of rounds (10, 12, or 14) */
+       int             type;     /* key schedule size (32 or 64 bits) */
+};
+
+/*
+ * Core AES functions.
+ * ks and keysched are pointers to aes_key_t.
+ * They are declared void* as they are intended to be opaque types.
+ * Use function aes_alloc_keysched() to allocate memory for ks and keysched.
+ */
+extern void *aes_alloc_keysched(size_t *size, int kmflag);
+extern void aes_init_keysched(const uint8_t *cipherKey, uint_t keyBits,
+       void *keysched);
+extern int aes_encrypt_block(const void *ks, const uint8_t *pt, uint8_t *ct);
+extern int aes_decrypt_block(const void *ks, const uint8_t *ct, uint8_t *pt);
+
+/*
+ * AES mode functions.
+ * The first 2 functions operate on 16-byte AES blocks.
+ */
+extern void aes_copy_block(uint8_t *in, uint8_t *out);
+extern void aes_xor_block(uint8_t *data, uint8_t *dst);
+
+/* Note: ctx is a pointer to aes_ctx_t defined in modes.h */
+extern int aes_encrypt_contiguous_blocks(void *ctx, char *data, size_t length,
+    crypto_data_t *out);
+extern int aes_decrypt_contiguous_blocks(void *ctx, char *data, size_t length,
+    crypto_data_t *out);
+
+/*
+ * The following definitions and declarations are only used by AES FIPS POST
+ */
+#ifdef _AES_IMPL
+
+typedef enum aes_mech_type {
+       AES_ECB_MECH_INFO_TYPE,         /* SUN_CKM_AES_ECB */
+       AES_CBC_MECH_INFO_TYPE,         /* SUN_CKM_AES_CBC */
+       AES_CBC_PAD_MECH_INFO_TYPE,     /* SUN_CKM_AES_CBC_PAD */
+       AES_CTR_MECH_INFO_TYPE,         /* SUN_CKM_AES_CTR */
+       AES_CCM_MECH_INFO_TYPE,         /* SUN_CKM_AES_CCM */
+       AES_GCM_MECH_INFO_TYPE,         /* SUN_CKM_AES_GCM */
+       AES_GMAC_MECH_INFO_TYPE         /* SUN_CKM_AES_GMAC */
+} aes_mech_type_t;
+
+#endif /* _AES_IMPL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AES_IMPL_H */
diff --git a/zfs/module/icp/include/modes/modes.h b/zfs/module/icp/include/modes/modes.h
new file mode 100644 (file)
index 0000000..7c1f10b
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * 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.
+ */
+
+#ifndef        _COMMON_CRYPTO_MODES_H
+#define        _COMMON_CRYPTO_MODES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+
+#define        ECB_MODE                        0x00000002
+#define        CBC_MODE                        0x00000004
+#define        CTR_MODE                        0x00000008
+#define        CCM_MODE                        0x00000010
+#define        GCM_MODE                        0x00000020
+#define        GMAC_MODE                       0x00000040
+
+/*
+ * cc_keysched:                Pointer to key schedule.
+ *
+ * cc_keysched_len:    Length of the key schedule.
+ *
+ * cc_remainder:       This is for residual data, i.e. data that can't
+ *                     be processed because there are too few bytes.
+ *                     Must wait until more data arrives.
+ *
+ * cc_remainder_len:   Number of bytes in cc_remainder.
+ *
+ * cc_iv:              Scratch buffer that sometimes contains the IV.
+ *
+ * cc_lastp:           Pointer to previous block of ciphertext.
+ *
+ * cc_copy_to:         Pointer to where encrypted residual data needs
+ *                     to be copied.
+ *
+ * cc_flags:           PROVIDER_OWNS_KEY_SCHEDULE
+ *                     When a context is freed, it is necessary
+ *                     to know whether the key schedule was allocated
+ *                     by the caller, or internally, e.g. an init routine.
+ *                     If allocated by the latter, then it needs to be freed.
+ *
+ *                     ECB_MODE, CBC_MODE, CTR_MODE, or CCM_MODE
+ */
+struct common_ctx {
+       void *cc_keysched;
+       size_t cc_keysched_len;
+       uint64_t cc_iv[2];
+       uint64_t cc_remainder[2];
+       size_t cc_remainder_len;
+       uint8_t *cc_lastp;
+       uint8_t *cc_copy_to;
+       uint32_t cc_flags;
+};
+
+typedef struct common_ctx common_ctx_t;
+
+typedef struct ecb_ctx {
+       struct common_ctx ecb_common;
+       uint64_t ecb_lastblock[2];
+} ecb_ctx_t;
+
+#define        ecb_keysched            ecb_common.cc_keysched
+#define        ecb_keysched_len        ecb_common.cc_keysched_len
+#define        ecb_iv                  ecb_common.cc_iv
+#define        ecb_remainder           ecb_common.cc_remainder
+#define        ecb_remainder_len       ecb_common.cc_remainder_len
+#define        ecb_lastp               ecb_common.cc_lastp
+#define        ecb_copy_to             ecb_common.cc_copy_to
+#define        ecb_flags               ecb_common.cc_flags
+
+typedef struct cbc_ctx {
+       struct common_ctx cbc_common;
+       uint64_t cbc_lastblock[2];
+} cbc_ctx_t;
+
+#define        cbc_keysched            cbc_common.cc_keysched
+#define        cbc_keysched_len        cbc_common.cc_keysched_len
+#define        cbc_iv                  cbc_common.cc_iv
+#define        cbc_remainder           cbc_common.cc_remainder
+#define        cbc_remainder_len       cbc_common.cc_remainder_len
+#define        cbc_lastp               cbc_common.cc_lastp
+#define        cbc_copy_to             cbc_common.cc_copy_to
+#define        cbc_flags               cbc_common.cc_flags
+
+/*
+ * ctr_lower_mask              Bit-mask for lower 8 bytes of counter block.
+ * ctr_upper_mask              Bit-mask for upper 8 bytes of counter block.
+ */
+typedef struct ctr_ctx {
+       struct common_ctx ctr_common;
+       uint64_t ctr_lower_mask;
+       uint64_t ctr_upper_mask;
+       uint32_t ctr_tmp[4];
+} ctr_ctx_t;
+
+/*
+ * ctr_cb                      Counter block.
+ */
+#define        ctr_keysched            ctr_common.cc_keysched
+#define        ctr_keysched_len        ctr_common.cc_keysched_len
+#define        ctr_cb                  ctr_common.cc_iv
+#define        ctr_remainder           ctr_common.cc_remainder
+#define        ctr_remainder_len       ctr_common.cc_remainder_len
+#define        ctr_lastp               ctr_common.cc_lastp
+#define        ctr_copy_to             ctr_common.cc_copy_to
+#define        ctr_flags               ctr_common.cc_flags
+
+/*
+ *
+ * ccm_mac_len:                Stores length of the MAC in CCM mode.
+ * ccm_mac_buf:                Stores the intermediate value for MAC in CCM encrypt.
+ *                     In CCM decrypt, stores the input MAC value.
+ * ccm_data_len:       Length of the plaintext for CCM mode encrypt, or
+ *                     length of the ciphertext for CCM mode decrypt.
+ * ccm_processed_data_len:
+ *                     Length of processed plaintext in CCM mode encrypt,
+ *                     or length of processed ciphertext for CCM mode decrypt.
+ * ccm_processed_mac_len:
+ *                     Length of MAC data accumulated in CCM mode decrypt.
+ *
+ * ccm_pt_buf:         Only used in CCM mode decrypt.  It stores the
+ *                     decrypted plaintext to be returned when
+ *                     MAC verification succeeds in decrypt_final.
+ *                     Memory for this should be allocated in the AES module.
+ *
+ */
+typedef struct ccm_ctx {
+       struct common_ctx ccm_common;
+       uint32_t ccm_tmp[4];
+       size_t ccm_mac_len;
+       uint64_t ccm_mac_buf[2];
+       size_t ccm_data_len;
+       size_t ccm_processed_data_len;
+       size_t ccm_processed_mac_len;
+       uint8_t *ccm_pt_buf;
+       uint64_t ccm_mac_input_buf[2];
+       uint64_t ccm_counter_mask;
+} ccm_ctx_t;
+
+#define        ccm_keysched            ccm_common.cc_keysched
+#define        ccm_keysched_len        ccm_common.cc_keysched_len
+#define        ccm_cb                  ccm_common.cc_iv
+#define        ccm_remainder           ccm_common.cc_remainder
+#define        ccm_remainder_len       ccm_common.cc_remainder_len
+#define        ccm_lastp               ccm_common.cc_lastp
+#define        ccm_copy_to             ccm_common.cc_copy_to
+#define        ccm_flags               ccm_common.cc_flags
+
+/*
+ * gcm_tag_len:                Length of authentication tag.
+ *
+ * gcm_ghash:          Stores output from the GHASH function.
+ *
+ * gcm_processed_data_len:
+ *                     Length of processed plaintext (encrypt) or
+ *                     length of processed ciphertext (decrypt).
+ *
+ * gcm_pt_buf:         Stores the decrypted plaintext returned by
+ *                     decrypt_final when the computed authentication
+ *                     tag matches the user supplied tag.
+ *
+ * gcm_pt_buf_len:     Length of the plaintext buffer.
+ *
+ * gcm_H:              Subkey.
+ *
+ * gcm_J0:             Pre-counter block generated from the IV.
+ *
+ * gcm_len_a_len_c:    64-bit representations of the bit lengths of
+ *                     AAD and ciphertext.
+ *
+ * gcm_kmflag:         Current value of kmflag. Used only for allocating
+ *                     the plaintext buffer during decryption.
+ */
+typedef struct gcm_ctx {
+       struct common_ctx gcm_common;
+       size_t gcm_tag_len;
+       size_t gcm_processed_data_len;
+       size_t gcm_pt_buf_len;
+       uint32_t gcm_tmp[4];
+       uint64_t gcm_ghash[2];
+       uint64_t gcm_H[2];
+       uint64_t gcm_J0[2];
+       uint64_t gcm_len_a_len_c[2];
+       uint8_t *gcm_pt_buf;
+       int gcm_kmflag;
+} gcm_ctx_t;
+
+#define        gcm_keysched            gcm_common.cc_keysched
+#define        gcm_keysched_len        gcm_common.cc_keysched_len
+#define        gcm_cb                  gcm_common.cc_iv
+#define        gcm_remainder           gcm_common.cc_remainder
+#define        gcm_remainder_len       gcm_common.cc_remainder_len
+#define        gcm_lastp               gcm_common.cc_lastp
+#define        gcm_copy_to             gcm_common.cc_copy_to
+#define        gcm_flags               gcm_common.cc_flags
+
+#define        AES_GMAC_IV_LEN         12
+#define        AES_GMAC_TAG_BITS       128
+
+typedef struct aes_ctx {
+       union {
+               ecb_ctx_t acu_ecb;
+               cbc_ctx_t acu_cbc;
+               ctr_ctx_t acu_ctr;
+               ccm_ctx_t acu_ccm;
+               gcm_ctx_t acu_gcm;
+       } acu;
+} aes_ctx_t;
+
+#define        ac_flags                acu.acu_ecb.ecb_common.cc_flags
+#define        ac_remainder_len        acu.acu_ecb.ecb_common.cc_remainder_len
+#define        ac_keysched             acu.acu_ecb.ecb_common.cc_keysched
+#define        ac_keysched_len         acu.acu_ecb.ecb_common.cc_keysched_len
+#define        ac_iv                   acu.acu_ecb.ecb_common.cc_iv
+#define        ac_lastp                acu.acu_ecb.ecb_common.cc_lastp
+#define        ac_pt_buf               acu.acu_ccm.ccm_pt_buf
+#define        ac_mac_len              acu.acu_ccm.ccm_mac_len
+#define        ac_data_len             acu.acu_ccm.ccm_data_len
+#define        ac_processed_mac_len    acu.acu_ccm.ccm_processed_mac_len
+#define        ac_processed_data_len   acu.acu_ccm.ccm_processed_data_len
+#define        ac_tag_len              acu.acu_gcm.gcm_tag_len
+
+typedef struct blowfish_ctx {
+       union {
+               ecb_ctx_t bcu_ecb;
+               cbc_ctx_t bcu_cbc;
+       } bcu;
+} blowfish_ctx_t;
+
+#define        bc_flags                bcu.bcu_ecb.ecb_common.cc_flags
+#define        bc_remainder_len        bcu.bcu_ecb.ecb_common.cc_remainder_len
+#define        bc_keysched             bcu.bcu_ecb.ecb_common.cc_keysched
+#define        bc_keysched_len         bcu.bcu_ecb.ecb_common.cc_keysched_len
+#define        bc_iv                   bcu.bcu_ecb.ecb_common.cc_iv
+#define        bc_lastp                bcu.bcu_ecb.ecb_common.cc_lastp
+
+typedef struct des_ctx {
+       union {
+               ecb_ctx_t dcu_ecb;
+               cbc_ctx_t dcu_cbc;
+       } dcu;
+} des_ctx_t;
+
+#define        dc_flags                dcu.dcu_ecb.ecb_common.cc_flags
+#define        dc_remainder_len        dcu.dcu_ecb.ecb_common.cc_remainder_len
+#define        dc_keysched             dcu.dcu_ecb.ecb_common.cc_keysched
+#define        dc_keysched_len         dcu.dcu_ecb.ecb_common.cc_keysched_len
+#define        dc_iv                   dcu.dcu_ecb.ecb_common.cc_iv
+#define        dc_lastp                dcu.dcu_ecb.ecb_common.cc_lastp
+
+extern int ecb_cipher_contiguous_blocks(ecb_ctx_t *, char *, size_t,
+    crypto_data_t *, size_t, int (*cipher)(const void *, const uint8_t *,
+    uint8_t *));
+
+extern int cbc_encrypt_contiguous_blocks(cbc_ctx_t *, char *, size_t,
+    crypto_data_t *, size_t,
+    int (*encrypt)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int cbc_decrypt_contiguous_blocks(cbc_ctx_t *, char *, size_t,
+    crypto_data_t *, size_t,
+    int (*decrypt)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int ctr_mode_contiguous_blocks(ctr_ctx_t *, char *, size_t,
+    crypto_data_t *, size_t,
+    int (*cipher)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *, char *, size_t,
+    crypto_data_t *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int ccm_mode_decrypt_contiguous_blocks(ccm_ctx_t *, char *, size_t,
+    crypto_data_t *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *, char *, size_t,
+    crypto_data_t *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *, char *, size_t,
+    crypto_data_t *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+int ccm_encrypt_final(ccm_ctx_t *, crypto_data_t *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+int gcm_encrypt_final(gcm_ctx_t *, crypto_data_t *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int ccm_decrypt_final(ccm_ctx_t *, crypto_data_t *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int gcm_decrypt_final(gcm_ctx_t *, crypto_data_t *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int ctr_mode_final(ctr_ctx_t *, crypto_data_t *,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *));
+
+extern int cbc_init_ctx(cbc_ctx_t *, char *, size_t, size_t,
+    void (*copy_block)(uint8_t *, uint64_t *));
+
+extern int ctr_init_ctx(ctr_ctx_t *, ulong_t, uint8_t *,
+    void (*copy_block)(uint8_t *, uint8_t *));
+
+extern int ccm_init_ctx(ccm_ctx_t *, char *, int, boolean_t, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int gcm_init_ctx(gcm_ctx_t *, char *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern int gmac_init_ctx(gcm_ctx_t *, char *, size_t,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
+    void (*copy_block)(uint8_t *, uint8_t *),
+    void (*xor_block)(uint8_t *, uint8_t *));
+
+extern void calculate_ccm_mac(ccm_ctx_t *, uint8_t *,
+    int (*encrypt_block)(const void *, const uint8_t *, uint8_t *));
+
+extern void gcm_mul(uint64_t *, uint64_t *, uint64_t *);
+
+extern void crypto_init_ptrs(crypto_data_t *, void **, offset_t *);
+extern void crypto_get_ptrs(crypto_data_t *, void **, offset_t *,
+    uint8_t **, size_t *, uint8_t **, size_t);
+
+extern void *ecb_alloc_ctx(int);
+extern void *cbc_alloc_ctx(int);
+extern void *ctr_alloc_ctx(int);
+extern void *ccm_alloc_ctx(int);
+extern void *gcm_alloc_ctx(int);
+extern void *gmac_alloc_ctx(int);
+extern void crypto_free_mode_ctx(void *);
+extern void gcm_set_kmflag(gcm_ctx_t *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COMMON_CRYPTO_MODES_H */
diff --git a/zfs/module/icp/include/sha1/sha1.h b/zfs/module/icp/include/sha1/sha1.h
new file mode 100644 (file)
index 0000000..b6ae6b8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 _SYS_SHA1_H
+#define        _SYS_SHA1_H
+
+#include <sys/types.h>         /* for uint_* */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * NOTE: n2rng (Niagara2 RNG driver) accesses the state field of
+ * SHA1_CTX directly.  NEVER change this structure without verifying
+ * compatiblity with n2rng.  The important thing is that the state
+ * must be in a field declared as uint32_t state[5].
+ */
+/* SHA-1 context. */
+typedef struct         {
+       uint32_t state[5];      /* state (ABCDE) */
+       uint32_t count[2];      /* number of bits, modulo 2^64 (msb first) */
+       union   {
+               uint8_t         buf8[64];       /* undigested input */
+               uint32_t        buf32[16];      /* realigned input */
+       } buf_un;
+} SHA1_CTX;
+
+#define        SHA1_DIGEST_LENGTH 20
+
+void SHA1Init(SHA1_CTX *);
+void SHA1Update(SHA1_CTX *, const void *, size_t);
+void SHA1Final(void *, SHA1_CTX *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SHA1_H */
diff --git a/zfs/module/icp/include/sha1/sha1_consts.h b/zfs/module/icp/include/sha1/sha1_consts.h
new file mode 100644 (file)
index 0000000..848d25e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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 (c) 1998, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef        _SYS_SHA1_CONSTS_H
+#define        _SYS_SHA1_CONSTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * as explained in sha1.c, loading 32-bit constants on a sparc is expensive
+ * since it involves both a `sethi' and an `or'.  thus, we instead use `ld'
+ * to load the constants from an array called `sha1_consts'.  however, on
+ * intel (and perhaps other processors), it is cheaper to load the constant
+ * directly.  thus, the c code in SHA1Transform() uses the macro SHA1_CONST()
+ * which either expands to a constant or an array reference, depending on
+ * the architecture the code is being compiled for.
+ */
+
+#include <sys/types.h>         /* uint32_t */
+
+extern const uint32_t  sha1_consts[];
+
+#if    defined(__sparc)
+#define        SHA1_CONST(x)           (sha1_consts[x])
+#else
+#define        SHA1_CONST(x)           (SHA1_CONST_ ## x)
+#endif
+
+/* constants, as provided in FIPS 180-1 */
+
+#define        SHA1_CONST_0            0x5a827999U
+#define        SHA1_CONST_1            0x6ed9eba1U
+#define        SHA1_CONST_2            0x8f1bbcdcU
+#define        SHA1_CONST_3            0xca62c1d6U
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SHA1_CONSTS_H */
diff --git a/zfs/module/icp/include/sha1/sha1_impl.h b/zfs/module/icp/include/sha1/sha1_impl.h
new file mode 100644 (file)
index 0000000..1c1f872
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SHA1_IMPL_H
+#define        _SHA1_IMPL_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        SHA1_HASH_SIZE          20      /* SHA_1 digest length in bytes */
+#define        SHA1_DIGEST_LENGTH      20      /* SHA1 digest length in bytes */
+#define        SHA1_HMAC_BLOCK_SIZE    64      /* SHA1-HMAC block size */
+#define        SHA1_HMAC_MIN_KEY_LEN   1       /* SHA1-HMAC min key length in bytes */
+#define        SHA1_HMAC_MAX_KEY_LEN   INT_MAX /* SHA1-HMAC max key length in bytes */
+#define        SHA1_HMAC_INTS_PER_BLOCK        (SHA1_HMAC_BLOCK_SIZE/sizeof (uint32_t))
+
+/*
+ * CSPI information (entry points, provider info, etc.)
+ */
+typedef enum sha1_mech_type {
+       SHA1_MECH_INFO_TYPE,            /* SUN_CKM_SHA1 */
+       SHA1_HMAC_MECH_INFO_TYPE,       /* SUN_CKM_SHA1_HMAC */
+       SHA1_HMAC_GEN_MECH_INFO_TYPE    /* SUN_CKM_SHA1_HMAC_GENERAL */
+} sha1_mech_type_t;
+
+/*
+ * Context for SHA1 mechanism.
+ */
+typedef struct sha1_ctx {
+       sha1_mech_type_t        sc_mech_type;   /* type of context */
+       SHA1_CTX                sc_sha1_ctx;    /* SHA1 context */
+} sha1_ctx_t;
+
+/*
+ * Context for SHA1-HMAC and SHA1-HMAC-GENERAL mechanisms.
+ */
+typedef struct sha1_hmac_ctx {
+       sha1_mech_type_t        hc_mech_type;   /* type of context */
+       uint32_t                hc_digest_len;  /* digest len in bytes */
+       SHA1_CTX                hc_icontext;    /* inner SHA1 context */
+       SHA1_CTX                hc_ocontext;    /* outer SHA1 context */
+} sha1_hmac_ctx_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SHA1_IMPL_H */
diff --git a/zfs/module/icp/include/sha2/sha2_consts.h b/zfs/module/icp/include/sha2/sha2_consts.h
new file mode 100644 (file)
index 0000000..3a66455
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SYS_SHA2_CONSTS_H
+#define        _SYS_SHA2_CONSTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Loading 32-bit constants on a sparc is expensive since it involves both
+ * a `sethi' and an `or'.  thus, we instead use `ld' to load the constants
+ * from an array called `sha2_consts'.  however, on intel (and perhaps other
+ * processors), it is cheaper to load the constant directly.  thus, the c
+ * code in SHA transform functions uses the macro SHA2_CONST() which either
+ * expands to a constant or an array reference, depending on
+ * the architecture the code is being compiled for.
+ *
+ * SHA512 constants are used for SHA384
+ */
+
+#include <sys/types.h>         /* uint32_t */
+
+extern const uint32_t  sha256_consts[];
+extern const uint64_t  sha512_consts[];
+
+#if    defined(__sparc)
+#define        SHA256_CONST(x)         (sha256_consts[x])
+#define        SHA512_CONST(x)         (sha512_consts[x])
+#else
+#define        SHA256_CONST(x)         (SHA256_CONST_ ## x)
+#define        SHA512_CONST(x)         (SHA512_CONST_ ## x)
+#endif
+
+/* constants, as provided in FIPS 180-2 */
+
+#define        SHA256_CONST_0          0x428a2f98U
+#define        SHA256_CONST_1          0x71374491U
+#define        SHA256_CONST_2          0xb5c0fbcfU
+#define        SHA256_CONST_3          0xe9b5dba5U
+#define        SHA256_CONST_4          0x3956c25bU
+#define        SHA256_CONST_5          0x59f111f1U
+#define        SHA256_CONST_6          0x923f82a4U
+#define        SHA256_CONST_7          0xab1c5ed5U
+
+#define        SHA256_CONST_8          0xd807aa98U
+#define        SHA256_CONST_9          0x12835b01U
+#define        SHA256_CONST_10         0x243185beU
+#define        SHA256_CONST_11         0x550c7dc3U
+#define        SHA256_CONST_12         0x72be5d74U
+#define        SHA256_CONST_13         0x80deb1feU
+#define        SHA256_CONST_14         0x9bdc06a7U
+#define        SHA256_CONST_15         0xc19bf174U
+
+#define        SHA256_CONST_16         0xe49b69c1U
+#define        SHA256_CONST_17         0xefbe4786U
+#define        SHA256_CONST_18         0x0fc19dc6U
+#define        SHA256_CONST_19         0x240ca1ccU
+#define        SHA256_CONST_20         0x2de92c6fU
+#define        SHA256_CONST_21         0x4a7484aaU
+#define        SHA256_CONST_22         0x5cb0a9dcU
+#define        SHA256_CONST_23         0x76f988daU
+
+#define        SHA256_CONST_24         0x983e5152U
+#define        SHA256_CONST_25         0xa831c66dU
+#define        SHA256_CONST_26         0xb00327c8U
+#define        SHA256_CONST_27         0xbf597fc7U
+#define        SHA256_CONST_28         0xc6e00bf3U
+#define        SHA256_CONST_29         0xd5a79147U
+#define        SHA256_CONST_30         0x06ca6351U
+#define        SHA256_CONST_31         0x14292967U
+
+#define        SHA256_CONST_32         0x27b70a85U
+#define        SHA256_CONST_33         0x2e1b2138U
+#define        SHA256_CONST_34         0x4d2c6dfcU
+#define        SHA256_CONST_35         0x53380d13U
+#define        SHA256_CONST_36         0x650a7354U
+#define        SHA256_CONST_37         0x766a0abbU
+#define        SHA256_CONST_38         0x81c2c92eU
+#define        SHA256_CONST_39         0x92722c85U
+
+#define        SHA256_CONST_40         0xa2bfe8a1U
+#define        SHA256_CONST_41         0xa81a664bU
+#define        SHA256_CONST_42         0xc24b8b70U
+#define        SHA256_CONST_43         0xc76c51a3U
+#define        SHA256_CONST_44         0xd192e819U
+#define        SHA256_CONST_45         0xd6990624U
+#define        SHA256_CONST_46         0xf40e3585U
+#define        SHA256_CONST_47         0x106aa070U
+
+#define        SHA256_CONST_48         0x19a4c116U
+#define        SHA256_CONST_49         0x1e376c08U
+#define        SHA256_CONST_50         0x2748774cU
+#define        SHA256_CONST_51         0x34b0bcb5U
+#define        SHA256_CONST_52         0x391c0cb3U
+#define        SHA256_CONST_53         0x4ed8aa4aU
+#define        SHA256_CONST_54         0x5b9cca4fU
+#define        SHA256_CONST_55         0x682e6ff3U
+
+#define        SHA256_CONST_56         0x748f82eeU
+#define        SHA256_CONST_57         0x78a5636fU
+#define        SHA256_CONST_58         0x84c87814U
+#define        SHA256_CONST_59         0x8cc70208U
+#define        SHA256_CONST_60         0x90befffaU
+#define        SHA256_CONST_61         0xa4506cebU
+#define        SHA256_CONST_62         0xbef9a3f7U
+#define        SHA256_CONST_63         0xc67178f2U
+
+#define        SHA512_CONST_0          0x428a2f98d728ae22ULL
+#define        SHA512_CONST_1          0x7137449123ef65cdULL
+#define        SHA512_CONST_2          0xb5c0fbcfec4d3b2fULL
+#define        SHA512_CONST_3          0xe9b5dba58189dbbcULL
+#define        SHA512_CONST_4          0x3956c25bf348b538ULL
+#define        SHA512_CONST_5          0x59f111f1b605d019ULL
+#define        SHA512_CONST_6          0x923f82a4af194f9bULL
+#define        SHA512_CONST_7          0xab1c5ed5da6d8118ULL
+#define        SHA512_CONST_8          0xd807aa98a3030242ULL
+#define        SHA512_CONST_9          0x12835b0145706fbeULL
+#define        SHA512_CONST_10         0x243185be4ee4b28cULL
+#define        SHA512_CONST_11         0x550c7dc3d5ffb4e2ULL
+#define        SHA512_CONST_12         0x72be5d74f27b896fULL
+#define        SHA512_CONST_13         0x80deb1fe3b1696b1ULL
+#define        SHA512_CONST_14         0x9bdc06a725c71235ULL
+#define        SHA512_CONST_15         0xc19bf174cf692694ULL
+#define        SHA512_CONST_16         0xe49b69c19ef14ad2ULL
+#define        SHA512_CONST_17         0xefbe4786384f25e3ULL
+#define        SHA512_CONST_18         0x0fc19dc68b8cd5b5ULL
+#define        SHA512_CONST_19         0x240ca1cc77ac9c65ULL
+#define        SHA512_CONST_20         0x2de92c6f592b0275ULL
+#define        SHA512_CONST_21         0x4a7484aa6ea6e483ULL
+#define        SHA512_CONST_22         0x5cb0a9dcbd41fbd4ULL
+#define        SHA512_CONST_23         0x76f988da831153b5ULL
+#define        SHA512_CONST_24         0x983e5152ee66dfabULL
+#define        SHA512_CONST_25         0xa831c66d2db43210ULL
+#define        SHA512_CONST_26         0xb00327c898fb213fULL
+#define        SHA512_CONST_27         0xbf597fc7beef0ee4ULL
+#define        SHA512_CONST_28         0xc6e00bf33da88fc2ULL
+#define        SHA512_CONST_29         0xd5a79147930aa725ULL
+#define        SHA512_CONST_30         0x06ca6351e003826fULL
+#define        SHA512_CONST_31         0x142929670a0e6e70ULL
+#define        SHA512_CONST_32         0x27b70a8546d22ffcULL
+#define        SHA512_CONST_33         0x2e1b21385c26c926ULL
+#define        SHA512_CONST_34         0x4d2c6dfc5ac42aedULL
+#define        SHA512_CONST_35         0x53380d139d95b3dfULL
+#define        SHA512_CONST_36         0x650a73548baf63deULL
+#define        SHA512_CONST_37         0x766a0abb3c77b2a8ULL
+#define        SHA512_CONST_38         0x81c2c92e47edaee6ULL
+#define        SHA512_CONST_39         0x92722c851482353bULL
+#define        SHA512_CONST_40         0xa2bfe8a14cf10364ULL
+#define        SHA512_CONST_41         0xa81a664bbc423001ULL
+#define        SHA512_CONST_42         0xc24b8b70d0f89791ULL
+#define        SHA512_CONST_43         0xc76c51a30654be30ULL
+#define        SHA512_CONST_44         0xd192e819d6ef5218ULL
+#define        SHA512_CONST_45         0xd69906245565a910ULL
+#define        SHA512_CONST_46         0xf40e35855771202aULL
+#define        SHA512_CONST_47         0x106aa07032bbd1b8ULL
+#define        SHA512_CONST_48         0x19a4c116b8d2d0c8ULL
+#define        SHA512_CONST_49         0x1e376c085141ab53ULL
+#define        SHA512_CONST_50         0x2748774cdf8eeb99ULL
+#define        SHA512_CONST_51         0x34b0bcb5e19b48a8ULL
+#define        SHA512_CONST_52         0x391c0cb3c5c95a63ULL
+#define        SHA512_CONST_53         0x4ed8aa4ae3418acbULL
+#define        SHA512_CONST_54         0x5b9cca4f7763e373ULL
+#define        SHA512_CONST_55         0x682e6ff3d6b2b8a3ULL
+#define        SHA512_CONST_56         0x748f82ee5defb2fcULL
+#define        SHA512_CONST_57         0x78a5636f43172f60ULL
+#define        SHA512_CONST_58         0x84c87814a1f0ab72ULL
+#define        SHA512_CONST_59         0x8cc702081a6439ecULL
+#define        SHA512_CONST_60         0x90befffa23631e28ULL
+#define        SHA512_CONST_61         0xa4506cebde82bde9ULL
+#define        SHA512_CONST_62         0xbef9a3f7b2c67915ULL
+#define        SHA512_CONST_63         0xc67178f2e372532bULL
+#define        SHA512_CONST_64         0xca273eceea26619cULL
+#define        SHA512_CONST_65         0xd186b8c721c0c207ULL
+#define        SHA512_CONST_66         0xeada7dd6cde0eb1eULL
+#define        SHA512_CONST_67         0xf57d4f7fee6ed178ULL
+#define        SHA512_CONST_68         0x06f067aa72176fbaULL
+#define        SHA512_CONST_69         0x0a637dc5a2c898a6ULL
+#define        SHA512_CONST_70         0x113f9804bef90daeULL
+#define        SHA512_CONST_71         0x1b710b35131c471bULL
+#define        SHA512_CONST_72         0x28db77f523047d84ULL
+#define        SHA512_CONST_73         0x32caab7b40c72493ULL
+#define        SHA512_CONST_74         0x3c9ebe0a15c9bebcULL
+#define        SHA512_CONST_75         0x431d67c49c100d4cULL
+#define        SHA512_CONST_76         0x4cc5d4becb3e42b6ULL
+#define        SHA512_CONST_77         0x597f299cfc657e2aULL
+#define        SHA512_CONST_78         0x5fcb6fab3ad6faecULL
+#define        SHA512_CONST_79         0x6c44198c4a475817ULL
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_SHA2_CONSTS_H */
diff --git a/zfs/module/icp/include/sha2/sha2_impl.h b/zfs/module/icp/include/sha2/sha2_impl.h
new file mode 100644 (file)
index 0000000..b9768d3
--- /dev/null
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef        _SHA2_IMPL_H
+#define        _SHA2_IMPL_H
+
+#include <sys/sha2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+       SHA1_TYPE,
+       SHA256_TYPE,
+       SHA384_TYPE,
+       SHA512_TYPE
+} sha2_mech_t;
+
+/*
+ * Context for SHA2 mechanism.
+ */
+typedef struct sha2_ctx {
+       sha2_mech_type_t        sc_mech_type;   /* type of context */
+       SHA2_CTX                sc_sha2_ctx;    /* SHA2 context */
+} sha2_ctx_t;
+
+/*
+ * Context for SHA2 HMAC and HMAC GENERAL mechanisms.
+ */
+typedef struct sha2_hmac_ctx {
+       sha2_mech_type_t        hc_mech_type;   /* type of context */
+       uint32_t                hc_digest_len;  /* digest len in bytes */
+       SHA2_CTX                hc_icontext;    /* inner SHA2 context */
+       SHA2_CTX                hc_ocontext;    /* outer SHA2 context */
+} sha2_hmac_ctx_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SHA2_IMPL_H */
diff --git a/zfs/module/icp/include/sys/asm_linkage.h b/zfs/module/icp/include/sys/asm_linkage.h
new file mode 100644 (file)
index 0000000..3805978
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_ASM_LINKAGE_H
+#define        _SYS_ASM_LINKAGE_H
+
+#if defined(__i386) || defined(__amd64)
+
+#include <sys/ia32/asm_linkage.h>      /* XX64 x86/sys/asm_linkage.h */
+
+#endif
+
+#endif /* _SYS_ASM_LINKAGE_H */
diff --git a/zfs/module/icp/include/sys/bitmap.h b/zfs/module/icp/include/sys/bitmap.h
new file mode 100644 (file)
index 0000000..b1f6823
--- /dev/null
@@ -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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*     Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/*       All Rights Reserved   */
+
+
+#ifndef _SYS_BITMAP_H
+#define        _SYS_BITMAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__GNUC__) && defined(_ASM_INLINES) && \
+       (defined(__i386) || defined(__amd64))
+#include <asm/bitmap.h>
+#endif
+
+/*
+ * Operations on bitmaps of arbitrary size
+ * A bitmap is a vector of 1 or more ulong_t's.
+ * The user of the package is responsible for range checks and keeping
+ * track of sizes.
+ */
+
+#ifdef _LP64
+#define        BT_ULSHIFT      6 /* log base 2 of BT_NBIPUL, to extract word index */
+#define        BT_ULSHIFT32    5 /* log base 2 of BT_NBIPUL, to extract word index */
+#else
+#define        BT_ULSHIFT      5 /* log base 2 of BT_NBIPUL, to extract word index */
+#endif
+
+#define        BT_NBIPUL       (1 << BT_ULSHIFT)       /* n bits per ulong_t */
+#define        BT_ULMASK       (BT_NBIPUL - 1)         /* to extract bit index */
+
+#ifdef _LP64
+#define        BT_NBIPUL32     (1 << BT_ULSHIFT32)     /* n bits per ulong_t */
+#define        BT_ULMASK32     (BT_NBIPUL32 - 1)       /* to extract bit index */
+#define        BT_ULMAXMASK    0xffffffffffffffff      /* used by bt_getlowbit */
+#else
+#define        BT_ULMAXMASK    0xffffffff
+#endif
+
+/*
+ * bitmap is a ulong_t *, bitindex an index_t
+ *
+ * The macros BT_WIM and BT_BIW internal; there is no need
+ * for users of this package to use them.
+ */
+
+/*
+ * word in map
+ */
+#define        BT_WIM(bitmap, bitindex) \
+       ((bitmap)[(bitindex) >> BT_ULSHIFT])
+/*
+ * bit in word
+ */
+#define        BT_BIW(bitindex) \
+       (1UL << ((bitindex) & BT_ULMASK))
+
+#ifdef _LP64
+#define        BT_WIM32(bitmap, bitindex) \
+       ((bitmap)[(bitindex) >> BT_ULSHIFT32])
+
+#define        BT_BIW32(bitindex) \
+       (1UL << ((bitindex) & BT_ULMASK32))
+#endif
+
+/*
+ * These are public macros
+ *
+ * BT_BITOUL == n bits to n ulong_t's
+ */
+#define        BT_BITOUL(nbits) \
+       (((nbits) + BT_NBIPUL - 1l) / BT_NBIPUL)
+#define        BT_SIZEOFMAP(nbits) \
+       (BT_BITOUL(nbits) * sizeof (ulong_t))
+#define        BT_TEST(bitmap, bitindex) \
+       ((BT_WIM((bitmap), (bitindex)) & BT_BIW(bitindex)) ? 1 : 0)
+#define        BT_SET(bitmap, bitindex) \
+       { BT_WIM((bitmap), (bitindex)) |= BT_BIW(bitindex); }
+#define        BT_CLEAR(bitmap, bitindex) \
+       { BT_WIM((bitmap), (bitindex)) &= ~BT_BIW(bitindex); }
+
+#ifdef _LP64
+#define        BT_BITOUL32(nbits) \
+       (((nbits) + BT_NBIPUL32 - 1l) / BT_NBIPUL32)
+#define        BT_SIZEOFMAP32(nbits) \
+       (BT_BITOUL32(nbits) * sizeof (uint_t))
+#define        BT_TEST32(bitmap, bitindex) \
+       ((BT_WIM32((bitmap), (bitindex)) & BT_BIW32(bitindex)) ? 1 : 0)
+#define        BT_SET32(bitmap, bitindex) \
+       { BT_WIM32((bitmap), (bitindex)) |= BT_BIW32(bitindex); }
+#define        BT_CLEAR32(bitmap, bitindex) \
+       { BT_WIM32((bitmap), (bitindex)) &= ~BT_BIW32(bitindex); }
+#endif /* _LP64 */
+
+
+/*
+ * BIT_ONLYONESET is a private macro not designed for bitmaps of
+ * arbitrary size.  u must be an unsigned integer/long.  It returns
+ * true if one and only one bit is set in u.
+ */
+#define        BIT_ONLYONESET(u) \
+       ((((u) == 0) ? 0 : ((u) & ((u) - 1)) == 0))
+
+#ifndef _ASM
+
+/*
+ * return next available bit index from map with specified number of bits
+ */
+extern index_t bt_availbit(ulong_t *bitmap, size_t nbits);
+/*
+ * find the highest order bit that is on, and is within or below
+ * the word specified by wx
+ */
+extern int     bt_gethighbit(ulong_t *mapp, int wx);
+extern int     bt_range(ulong_t *bitmap, size_t *pos1, size_t *pos2,
+                       size_t end_pos);
+extern int     bt_getlowbit(ulong_t *bitmap, size_t start, size_t stop);
+extern void    bt_copy(ulong_t *, ulong_t *, ulong_t);
+
+/*
+ * find the parity
+ */
+extern int     odd_parity(ulong_t);
+
+/*
+ * Atomically set/clear bits
+ * Atomic exclusive operations will set "result" to "-1"
+ * if the bit is already set/cleared. "result" will be set
+ * to 0 otherwise.
+ */
+#define        BT_ATOMIC_SET(bitmap, bitindex) \
+       { atomic_or_long(&(BT_WIM(bitmap, bitindex)), BT_BIW(bitindex)); }
+#define        BT_ATOMIC_CLEAR(bitmap, bitindex) \
+       { atomic_and_long(&(BT_WIM(bitmap, bitindex)), ~BT_BIW(bitindex)); }
+
+#define        BT_ATOMIC_SET_EXCL(bitmap, bitindex, result) \
+       { result = atomic_set_long_excl(&(BT_WIM(bitmap, bitindex)),    \
+           (bitindex) % BT_NBIPUL); }
+#define        BT_ATOMIC_CLEAR_EXCL(bitmap, bitindex, result) \
+       { result = atomic_clear_long_excl(&(BT_WIM(bitmap, bitindex)),  \
+           (bitindex) % BT_NBIPUL); }
+
+/*
+ * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
+ * u, which must be an unsigned integer.
+ */
+#define        BITX(u, h, l)   (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
+
+#endif /* _ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_BITMAP_H */
diff --git a/zfs/module/icp/include/sys/crypto/elfsign.h b/zfs/module/icp/include/sys/crypto/elfsign.h
new file mode 100644 (file)
index 0000000..5432f0c
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_CRYPTO_ELFSIGN_H
+#define        _SYS_CRYPTO_ELFSIGN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Consolidation Private Interface for elfsign/libpkcs11/kcfd
+ */
+
+#include <sys/zfs_context.h>
+
+/*
+ * Project Private structures and types used for communication between kcfd
+ * and KCF over the door.
+ */
+
+typedef enum ELFsign_status_e {
+       ELFSIGN_UNKNOWN,
+       ELFSIGN_SUCCESS,
+       ELFSIGN_FAILED,
+       ELFSIGN_NOTSIGNED,
+       ELFSIGN_INVALID_CERTPATH,
+       ELFSIGN_INVALID_ELFOBJ,
+       ELFSIGN_RESTRICTED
+} ELFsign_status_t;
+
+#define        KCF_KCFD_VERSION1       1
+#define        SIG_MAX_LENGTH          1024
+
+#define        ELF_SIGNATURE_SECTION   ".SUNW_signature"
+
+typedef struct kcf_door_arg_s {
+       short           da_version;
+       boolean_t       da_iskernel;
+
+       union {
+               char filename[MAXPATHLEN];      /* For request */
+
+               struct kcf_door_result_s {      /* For response */
+                       ELFsign_status_t        status;
+                       uint32_t                siglen;
+                       uchar_t                 signature[1];
+               } result;
+       } da_u;
+} kcf_door_arg_t;
+
+typedef uint32_t       filesig_vers_t;
+
+/*
+ * File Signature Structure
+ *     Applicable to ELF and other file formats
+ */
+struct filesignatures {
+       uint32_t        filesig_cnt;    /* count of signatures */
+       uint32_t        filesig_pad;    /* unused */
+       union {
+               char    filesig_data[1];
+               struct filesig {        /* one of these for each signature */
+                       uint32_t        filesig_size;
+                       filesig_vers_t  filesig_version;
+                       union {
+                               struct filesig_version1 {
+                                       uint32_t        filesig_v1_dnsize;
+                                       uint32_t        filesig_v1_sigsize;
+                                       uint32_t        filesig_v1_oidsize;
+                                       char    filesig_v1_data[1];
+                               } filesig_v1;
+                               struct filesig_version3 {
+                                       uint64_t        filesig_v3_time;
+                                       uint32_t        filesig_v3_dnsize;
+                                       uint32_t        filesig_v3_sigsize;
+                                       uint32_t        filesig_v3_oidsize;
+                                       char    filesig_v3_data[1];
+                               } filesig_v3;
+                       } _u2;
+               } filesig_sig;
+               uint64_t filesig_align;
+       } _u1;
+};
+#define        filesig_sig             _u1.filesig_sig
+
+#define        filesig_v1_dnsize       _u2.filesig_v1.filesig_v1_dnsize
+#define        filesig_v1_sigsize      _u2.filesig_v1.filesig_v1_sigsize
+#define        filesig_v1_oidsize      _u2.filesig_v1.filesig_v1_oidsize
+#define        filesig_v1_data         _u2.filesig_v1.filesig_v1_data
+
+#define        filesig_v3_time         _u2.filesig_v3.filesig_v3_time
+#define        filesig_v3_dnsize       _u2.filesig_v3.filesig_v3_dnsize
+#define        filesig_v3_sigsize      _u2.filesig_v3.filesig_v3_sigsize
+#define        filesig_v3_oidsize      _u2.filesig_v3.filesig_v3_oidsize
+#define        filesig_v3_data         _u2.filesig_v3.filesig_v3_data
+
+#define        filesig_ALIGN(s)        (((s) + sizeof (uint64_t) - 1) & \
+                                   (-sizeof (uint64_t)))
+#define        filesig_next(ptr)       (struct filesig *)((void *)((char *)(ptr) + \
+                                   filesig_ALIGN((ptr)->filesig_size)))
+
+#define        FILESIG_UNKNOWN         0       /* unrecognized version */
+#define        FILESIG_VERSION1        1       /* version1, all but sig section */
+#define        FILESIG_VERSION2        2       /* version1 format, SHF_ALLOC only */
+#define        FILESIG_VERSION3        3       /* version3, all but sig section */
+#define        FILESIG_VERSION4        4       /* version3 format, SHF_ALLOC only */
+
+#define        _PATH_KCFD_DOOR "/etc/svc/volatile/kcfd_door"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_ELFSIGN_H */
diff --git a/zfs/module/icp/include/sys/crypto/impl.h b/zfs/module/icp/include/sys/crypto/impl.h
new file mode 100644 (file)
index 0000000..258cb5f
--- /dev/null
@@ -0,0 +1,1363 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SYS_CRYPTO_IMPL_H
+#define        _SYS_CRYPTO_IMPL_H
+
+/*
+ * Kernel Cryptographic Framework private implementation definitions.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/ioctl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define        KCF_MODULE "kcf"
+
+/*
+ * Prefixes convention: structures internal to the kernel cryptographic
+ * framework start with 'kcf_'. Exposed structure start with 'crypto_'.
+ */
+
+/* Provider stats. Not protected. */
+typedef        struct kcf_prov_stats {
+       kstat_named_t   ps_ops_total;
+       kstat_named_t   ps_ops_passed;
+       kstat_named_t   ps_ops_failed;
+       kstat_named_t   ps_ops_busy_rval;
+} kcf_prov_stats_t;
+
+/* Various kcf stats. Not protected. */
+typedef        struct kcf_stats {
+       kstat_named_t   ks_thrs_in_pool;
+       kstat_named_t   ks_idle_thrs;
+       kstat_named_t   ks_minthrs;
+       kstat_named_t   ks_maxthrs;
+       kstat_named_t   ks_swq_njobs;
+       kstat_named_t   ks_swq_maxjobs;
+       kstat_named_t   ks_taskq_threads;
+       kstat_named_t   ks_taskq_minalloc;
+       kstat_named_t   ks_taskq_maxalloc;
+} kcf_stats_t;
+
+/*
+ * Keep all the information needed by the scheduler from
+ * this provider.
+ */
+typedef struct kcf_sched_info {
+       /* The number of operations dispatched. */
+       uint64_t        ks_ndispatches;
+
+       /* The number of operations that failed. */
+       uint64_t        ks_nfails;
+
+       /* The number of operations that returned CRYPTO_BUSY. */
+       uint64_t        ks_nbusy_rval;
+
+       /* taskq used to dispatch crypto requests */
+       taskq_t *ks_taskq;
+} kcf_sched_info_t;
+
+/*
+ * pd_irefcnt approximates the number of inflight requests to the
+ * provider. Though we increment this counter during registration for
+ * other purposes, that base value is mostly same across all providers.
+ * So, it is a good measure of the load on a provider when it is not
+ * in a busy state. Once a provider notifies it is busy, requests
+ * backup in the taskq. So, we use tq_nalloc in that case which gives
+ * the number of task entries in the task queue. Note that we do not
+ * acquire any locks here as it is not critical to get the exact number
+ * and the lock contention may be too costly for this code path.
+ */
+#define        KCF_PROV_LOAD(pd)       ((pd)->pd_state != KCF_PROV_BUSY ?      \
+       (pd)->pd_irefcnt : (pd)->pd_sched_info.ks_taskq->tq_nalloc)
+
+#define        KCF_PROV_INCRSTATS(pd, error)   {                               \
+       (pd)->pd_sched_info.ks_ndispatches++;                           \
+       if (error == CRYPTO_BUSY)                                       \
+               (pd)->pd_sched_info.ks_nbusy_rval++;                    \
+       else if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED)     \
+               (pd)->pd_sched_info.ks_nfails++;                        \
+}
+
+
+/*
+ * The following two macros should be
+ * #define     KCF_OPS_CLASSSIZE (KCF_LAST_OPSCLASS - KCF_FIRST_OPSCLASS + 2)
+ * #define     KCF_MAXMECHTAB KCF_MAXCIPHER
+ *
+ * However, doing that would involve reorganizing the header file a bit.
+ * When impl.h is broken up (bug# 4703218), this will be done. For now,
+ * we hardcode these values.
+ */
+#define        KCF_OPS_CLASSSIZE       8
+#define        KCF_MAXMECHTAB          32
+
+/*
+ * Valid values for the state of a provider. The order of
+ * the elements is important.
+ *
+ * Routines which get a provider or the list of providers
+ * should pick only those that are either in KCF_PROV_READY state
+ * or in KCF_PROV_BUSY state.
+ */
+typedef enum {
+       KCF_PROV_ALLOCATED = 1,
+       KCF_PROV_UNVERIFIED,
+       KCF_PROV_VERIFICATION_FAILED,
+       /*
+        * state < KCF_PROV_READY means the provider can not
+        * be used at all.
+        */
+       KCF_PROV_READY,
+       KCF_PROV_BUSY,
+       /*
+        * state > KCF_PROV_BUSY means the provider can not
+        * be used for new requests.
+        */
+       KCF_PROV_FAILED,
+       /*
+        * Threads setting the following two states should do so only
+        * if the current state < KCF_PROV_DISABLED.
+        */
+       KCF_PROV_DISABLED,
+       KCF_PROV_REMOVED,
+       KCF_PROV_FREED
+} kcf_prov_state_t;
+
+#define        KCF_IS_PROV_UNVERIFIED(pd) ((pd)->pd_state == KCF_PROV_UNVERIFIED)
+#define        KCF_IS_PROV_USABLE(pd) ((pd)->pd_state == KCF_PROV_READY || \
+       (pd)->pd_state == KCF_PROV_BUSY)
+#define        KCF_IS_PROV_REMOVED(pd) ((pd)->pd_state >= KCF_PROV_REMOVED)
+
+/* Internal flags valid for pd_flags field */
+#define        KCF_PROV_RESTRICTED     0x40000000
+#define        KCF_LPROV_MEMBER        0x80000000 /* is member of a logical provider */
+
+/*
+ * A provider descriptor structure. There is one such structure per
+ * provider. It is allocated and initialized at registration time and
+ * freed when the provider unregisters.
+ *
+ * pd_prov_type:       Provider type, hardware or software
+ * pd_sid:             Session ID of the provider used by kernel clients.
+ *                     This is valid only for session-oriented providers.
+ * pd_refcnt:          Reference counter to this provider descriptor
+ * pd_irefcnt:         References held by the framework internal structs
+ * pd_lock:            lock protects pd_state and pd_provider_list
+ * pd_state:           State value of the provider
+ * pd_provider_list:   Used to cross-reference logical providers and their
+ *                     members. Not used for software providers.
+ * pd_resume_cv:       cv to wait for state to change from KCF_PROV_BUSY
+ * pd_prov_handle:     Provider handle specified by provider
+ * pd_ops_vector:      The ops vector specified by Provider
+ * pd_mech_indx:       Lookup table which maps a core framework mechanism
+ *                     number to an index in pd_mechanisms array
+ * pd_mechanisms:      Array of mechanisms supported by the provider, specified
+ *                     by the provider during registration
+ * pd_sched_info:      Scheduling information associated with the provider
+ * pd_mech_list_count: The number of entries in pi_mechanisms, specified
+ *                     by the provider during registration
+ * pd_name:            Device name or module name
+ * pd_instance:                Device instance
+ * pd_module_id:       Module ID returned by modload
+ * pd_mctlp:           Pointer to modctl structure for this provider
+ * pd_remove_cv:       cv to wait on while the provider queue drains
+ * pd_description:     Provider description string
+ * pd_flags            bitwise OR of pi_flags from crypto_provider_info_t
+ *                     and other internal flags defined above.
+ * pd_hash_limit       Maximum data size that hash mechanisms of this provider
+ *                     can support.
+ * pd_kcf_prov_handle: KCF-private handle assigned by KCF
+ * pd_prov_id:         Identification # assigned by KCF to provider
+ * pd_kstat:           kstat associated with the provider
+ * pd_ks_data:         kstat data
+ */
+typedef struct kcf_provider_desc {
+       crypto_provider_type_t          pd_prov_type;
+       crypto_session_id_t             pd_sid;
+       uint_t                          pd_refcnt;
+       uint_t                          pd_irefcnt;
+       kmutex_t                        pd_lock;
+       kcf_prov_state_t                pd_state;
+       struct kcf_provider_list        *pd_provider_list;
+       kcondvar_t                      pd_resume_cv;
+       crypto_provider_handle_t        pd_prov_handle;
+       crypto_ops_t                    *pd_ops_vector;
+       ushort_t                        pd_mech_indx[KCF_OPS_CLASSSIZE]\
+                                           [KCF_MAXMECHTAB];
+       crypto_mech_info_t              *pd_mechanisms;
+       kcf_sched_info_t                pd_sched_info;
+       uint_t                          pd_mech_list_count;
+       // char                         *pd_name;
+       // uint_t                               pd_instance;
+       // int                          pd_module_id;
+       // struct modctl                        *pd_mctlp;
+       kcondvar_t                      pd_remove_cv;
+       char                            *pd_description;
+       uint_t                          pd_flags;
+       uint_t                          pd_hash_limit;
+       crypto_kcf_provider_handle_t    pd_kcf_prov_handle;
+       crypto_provider_id_t            pd_prov_id;
+       kstat_t                         *pd_kstat;
+       kcf_prov_stats_t                pd_ks_data;
+} kcf_provider_desc_t;
+
+/* useful for making a list of providers */
+typedef struct kcf_provider_list {
+       struct kcf_provider_list *pl_next;
+       struct kcf_provider_desc *pl_provider;
+} kcf_provider_list_t;
+
+/* atomic operations in linux implictly form a memory barrier */
+#define        membar_exit()
+
+/*
+ * If a component has a reference to a kcf_provider_desc_t,
+ * it REFHOLD()s. A new provider descriptor which is referenced only
+ * by the providers table has a reference counter of one.
+ */
+#define        KCF_PROV_REFHOLD(desc) {                \
+       atomic_add_32(&(desc)->pd_refcnt, 1);   \
+       ASSERT((desc)->pd_refcnt != 0);         \
+}
+
+#define        KCF_PROV_IREFHOLD(desc) {               \
+       atomic_add_32(&(desc)->pd_irefcnt, 1);  \
+       ASSERT((desc)->pd_irefcnt != 0);        \
+}
+
+#define        KCF_PROV_IREFRELE(desc) {                               \
+       ASSERT((desc)->pd_irefcnt != 0);                        \
+       membar_exit();                                          \
+       if (atomic_add_32_nv(&(desc)->pd_irefcnt, -1) == 0) {   \
+               cv_broadcast(&(desc)->pd_remove_cv);            \
+       }                                                       \
+}
+
+#define        KCF_PROV_REFHELD(desc)  ((desc)->pd_refcnt >= 1)
+
+#define        KCF_PROV_REFRELE(desc) {                                \
+       ASSERT((desc)->pd_refcnt != 0);                         \
+       membar_exit();                                          \
+       if (atomic_add_32_nv(&(desc)->pd_refcnt, -1) == 0) {    \
+               kcf_provider_zero_refcnt((desc));               \
+       }                                                       \
+}
+
+
+/* list of crypto_mech_info_t valid as the second mech in a dual operation */
+
+typedef        struct crypto_mech_info_list {
+       struct crypto_mech_info_list    *ml_next;
+       crypto_mech_type_t              ml_kcf_mechid;  /* KCF's id */
+       crypto_mech_info_t              ml_mech_info;
+} crypto_mech_info_list_t;
+
+/*
+ * An element in a mechanism provider descriptors chain.
+ * The kcf_prov_mech_desc_t is duplicated in every chain the provider belongs
+ * to. This is a small tradeoff memory vs mutex spinning time to access the
+ * common provider field.
+ */
+
+typedef struct kcf_prov_mech_desc {
+       struct kcf_mech_entry           *pm_me;         /* Back to the head */
+       struct kcf_prov_mech_desc       *pm_next;       /* Next in the chain */
+       crypto_mech_info_t              pm_mech_info;   /* Provider mech info */
+       crypto_mech_info_list_t         *pm_mi_list;    /* list for duals */
+       kcf_provider_desc_t             *pm_prov_desc;  /* Common desc. */
+} kcf_prov_mech_desc_t;
+
+/* and the notation shortcuts ... */
+#define        pm_provider_type        pm_prov_desc.pd_provider_type
+#define        pm_provider_handle      pm_prov_desc.pd_provider_handle
+#define        pm_ops_vector           pm_prov_desc.pd_ops_vector
+
+/*
+ * A mechanism entry in an xxx_mech_tab[]. me_pad was deemed
+ * to be unnecessary and removed.
+ */
+typedef        struct kcf_mech_entry {
+       crypto_mech_name_t      me_name;        /* mechanism name */
+       crypto_mech_type_t      me_mechid;      /* Internal id for mechanism */
+       kmutex_t                me_mutex;       /* access protection    */
+       kcf_prov_mech_desc_t    *me_hw_prov_chain;  /* list of HW providers */
+       kcf_prov_mech_desc_t    *me_sw_prov;    /* SW provider */
+       /*
+        * Number of HW providers in the chain. There is only one
+        * SW provider. So, we need only a count of HW providers.
+        */
+       int                     me_num_hwprov;
+       /*
+        * When a SW provider is present, this is the generation number that
+        * ensures no objects from old SW providers are used in the new one
+        */
+       uint32_t                me_gen_swprov;
+       /*
+        *  threshold for using hardware providers for this mech
+        */
+       size_t                  me_threshold;
+} kcf_mech_entry_t;
+
+/*
+ * A policy descriptor structure. It is allocated and initialized
+ * when administrative ioctls load disabled mechanisms.
+ *
+ * pd_prov_type:       Provider type, hardware or software
+ * pd_name:            Device name or module name.
+ * pd_instance:                Device instance.
+ * pd_refcnt:          Reference counter for this policy descriptor
+ * pd_mutex:           Protects array and count of disabled mechanisms.
+ * pd_disabled_count:  Count of disabled mechanisms.
+ * pd_disabled_mechs:  Array of disabled mechanisms.
+ */
+typedef struct kcf_policy_desc {
+       crypto_provider_type_t  pd_prov_type;
+       char                    *pd_name;
+       uint_t                  pd_instance;
+       uint_t                  pd_refcnt;
+       kmutex_t                pd_mutex;
+       uint_t                  pd_disabled_count;
+       crypto_mech_name_t      *pd_disabled_mechs;
+} kcf_policy_desc_t;
+
+/*
+ * If a component has a reference to a kcf_policy_desc_t,
+ * it REFHOLD()s. A new policy descriptor which is referenced only
+ * by the policy table has a reference count of one.
+ */
+#define        KCF_POLICY_REFHOLD(desc) {              \
+       atomic_add_32(&(desc)->pd_refcnt, 1);   \
+       ASSERT((desc)->pd_refcnt != 0);         \
+}
+
+/*
+ * Releases a reference to a policy descriptor. When the last
+ * reference is released, the descriptor is freed.
+ */
+#define        KCF_POLICY_REFRELE(desc) {                              \
+       ASSERT((desc)->pd_refcnt != 0);                         \
+       membar_exit();                                          \
+       if (atomic_add_32_nv(&(desc)->pd_refcnt, -1) == 0)      \
+               kcf_policy_free_desc(desc);                     \
+}
+
+/*
+ * This entry stores the name of a software module and its
+ * mechanisms.  The mechanisms are 'hints' that are used to
+ * trigger loading of the module.
+ */
+typedef struct kcf_soft_conf_entry {
+       struct kcf_soft_conf_entry      *ce_next;
+       char                            *ce_name;
+       crypto_mech_name_t              *ce_mechs;
+       uint_t                          ce_count;
+} kcf_soft_conf_entry_t;
+
+extern kmutex_t soft_config_mutex;
+extern kcf_soft_conf_entry_t *soft_config_list;
+
+/*
+ * Global tables. The sizes are from the predefined PKCS#11 v2.20 mechanisms,
+ * with a margin of few extra empty entry points
+ */
+
+#define        KCF_MAXDIGEST           16      /* Digests */
+#define        KCF_MAXCIPHER           64      /* Ciphers */
+#define        KCF_MAXMAC              40      /* Message authentication codes */
+#define        KCF_MAXSIGN             24      /* Sign/Verify */
+#define        KCF_MAXKEYOPS           116     /* Key generation and derivation */
+#define        KCF_MAXMISC             16      /* Others ... */
+
+#define        KCF_MAXMECHS            KCF_MAXDIGEST + KCF_MAXCIPHER + KCF_MAXMAC + \
+                               KCF_MAXSIGN + KCF_MAXKEYOPS + \
+                               KCF_MAXMISC
+
+extern kcf_mech_entry_t kcf_digest_mechs_tab[];
+extern kcf_mech_entry_t kcf_cipher_mechs_tab[];
+extern kcf_mech_entry_t kcf_mac_mechs_tab[];
+extern kcf_mech_entry_t kcf_sign_mechs_tab[];
+extern kcf_mech_entry_t kcf_keyops_mechs_tab[];
+extern kcf_mech_entry_t kcf_misc_mechs_tab[];
+
+extern kmutex_t kcf_mech_tabs_lock;
+
+typedef        enum {
+       KCF_DIGEST_CLASS = 1,
+       KCF_CIPHER_CLASS,
+       KCF_MAC_CLASS,
+       KCF_SIGN_CLASS,
+       KCF_KEYOPS_CLASS,
+       KCF_MISC_CLASS
+} kcf_ops_class_t;
+
+#define        KCF_FIRST_OPSCLASS      KCF_DIGEST_CLASS
+#define        KCF_LAST_OPSCLASS       KCF_MISC_CLASS
+
+/* The table of all the kcf_xxx_mech_tab[]s, indexed by kcf_ops_class */
+
+typedef        struct kcf_mech_entry_tab {
+       int                     met_size;       /* Size of the met_tab[] */
+       kcf_mech_entry_t        *met_tab;       /* the table             */
+} kcf_mech_entry_tab_t;
+
+extern kcf_mech_entry_tab_t kcf_mech_tabs_tab[];
+
+#define        KCF_MECHID(class, index)                                \
+       (((crypto_mech_type_t)(class) << 32) | (crypto_mech_type_t)(index))
+
+#define        KCF_MECH2CLASS(mech_type) ((kcf_ops_class_t)((mech_type) >> 32))
+
+#define        KCF_MECH2INDEX(mech_type) ((int)(mech_type))
+
+#define        KCF_TO_PROV_MECH_INDX(pd, mech_type)                    \
+       ((pd)->pd_mech_indx[KCF_MECH2CLASS(mech_type)]          \
+       [KCF_MECH2INDEX(mech_type)])
+
+#define        KCF_TO_PROV_MECHINFO(pd, mech_type)                     \
+       ((pd)->pd_mechanisms[KCF_TO_PROV_MECH_INDX(pd, mech_type)])
+
+#define        KCF_TO_PROV_MECHNUM(pd, mech_type)                      \
+       (KCF_TO_PROV_MECHINFO(pd, mech_type).cm_mech_number)
+
+#define        KCF_CAN_SHARE_OPSTATE(pd, mech_type)                    \
+       ((KCF_TO_PROV_MECHINFO(pd, mech_type).cm_mech_flags) &  \
+       CRYPTO_CAN_SHARE_OPSTATE)
+
+/* ps_refcnt is protected by cm_lock in the crypto_minor structure */
+typedef struct crypto_provider_session {
+       struct crypto_provider_session *ps_next;
+       crypto_session_id_t             ps_session;
+       kcf_provider_desc_t             *ps_provider;
+       kcf_provider_desc_t             *ps_real_provider;
+       uint_t                          ps_refcnt;
+} crypto_provider_session_t;
+
+typedef struct crypto_session_data {
+       kmutex_t                        sd_lock;
+       kcondvar_t                      sd_cv;
+       uint32_t                        sd_flags;
+       int                             sd_pre_approved_amount;
+       crypto_ctx_t                    *sd_digest_ctx;
+       crypto_ctx_t                    *sd_encr_ctx;
+       crypto_ctx_t                    *sd_decr_ctx;
+       crypto_ctx_t                    *sd_sign_ctx;
+       crypto_ctx_t                    *sd_verify_ctx;
+       crypto_ctx_t                    *sd_sign_recover_ctx;
+       crypto_ctx_t                    *sd_verify_recover_ctx;
+       kcf_provider_desc_t             *sd_provider;
+       void                            *sd_find_init_cookie;
+       crypto_provider_session_t       *sd_provider_session;
+} crypto_session_data_t;
+
+#define        CRYPTO_SESSION_IN_USE           0x00000001
+#define        CRYPTO_SESSION_IS_BUSY          0x00000002
+#define        CRYPTO_SESSION_IS_CLOSED        0x00000004
+
+#define        KCF_MAX_PIN_LEN                 1024
+
+/*
+ * Per-minor info.
+ *
+ * cm_lock protects everything in this structure except for cm_refcnt.
+ */
+typedef struct crypto_minor {
+       uint_t                          cm_refcnt;
+       kmutex_t                        cm_lock;
+       kcondvar_t                      cm_cv;
+       crypto_session_data_t           **cm_session_table;
+       uint_t                          cm_session_table_count;
+       kcf_provider_desc_t             **cm_provider_array;
+       uint_t                          cm_provider_count;
+       crypto_provider_session_t       *cm_provider_session;
+} crypto_minor_t;
+
+/*
+ * Return codes for internal functions
+ */
+#define        KCF_SUCCESS             0x0     /* Successful call */
+#define        KCF_INVALID_MECH_NUMBER 0x1     /* invalid mechanism number */
+#define        KCF_INVALID_MECH_NAME   0x2     /* invalid mechanism name */
+#define        KCF_INVALID_MECH_CLASS  0x3     /* invalid mechanism class */
+#define        KCF_MECH_TAB_FULL       0x4     /* Need more room in the mech tabs. */
+#define        KCF_INVALID_INDX        ((ushort_t)-1)
+
+/*
+ * kCF internal mechanism and function group for tracking RNG providers.
+ */
+#define        SUN_RANDOM              "random"
+#define        CRYPTO_FG_RANDOM        0x80000000      /* generate_random() */
+
+/*
+ * Wrappers for ops vectors. In the wrapper definitions below, the pd
+ * argument always corresponds to a pointer to a provider descriptor
+ * of type kcf_prov_desc_t.
+ */
+
+#define        KCF_PROV_CONTROL_OPS(pd)        ((pd)->pd_ops_vector->co_control_ops)
+#define        KCF_PROV_CTX_OPS(pd)            ((pd)->pd_ops_vector->co_ctx_ops)
+#define        KCF_PROV_DIGEST_OPS(pd)         ((pd)->pd_ops_vector->co_digest_ops)
+#define        KCF_PROV_CIPHER_OPS(pd)         ((pd)->pd_ops_vector->co_cipher_ops)
+#define        KCF_PROV_MAC_OPS(pd)            ((pd)->pd_ops_vector->co_mac_ops)
+#define        KCF_PROV_SIGN_OPS(pd)           ((pd)->pd_ops_vector->co_sign_ops)
+#define        KCF_PROV_VERIFY_OPS(pd)         ((pd)->pd_ops_vector->co_verify_ops)
+#define        KCF_PROV_DUAL_OPS(pd)           ((pd)->pd_ops_vector->co_dual_ops)
+#define        KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) \
+       ((pd)->pd_ops_vector->co_dual_cipher_mac_ops)
+#define        KCF_PROV_RANDOM_OPS(pd)         ((pd)->pd_ops_vector->co_random_ops)
+#define        KCF_PROV_SESSION_OPS(pd)        ((pd)->pd_ops_vector->co_session_ops)
+#define        KCF_PROV_OBJECT_OPS(pd)         ((pd)->pd_ops_vector->co_object_ops)
+#define        KCF_PROV_KEY_OPS(pd)            ((pd)->pd_ops_vector->co_key_ops)
+#define        KCF_PROV_PROVIDER_OPS(pd)       ((pd)->pd_ops_vector->co_provider_ops)
+#define        KCF_PROV_MECH_OPS(pd)           ((pd)->pd_ops_vector->co_mech_ops)
+#define        KCF_PROV_NOSTORE_KEY_OPS(pd)    \
+       ((pd)->pd_ops_vector->co_nostore_key_ops)
+
+/*
+ * Wrappers for crypto_control_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_STATUS(pd, status) ( \
+       (KCF_PROV_CONTROL_OPS(pd) && \
+       KCF_PROV_CONTROL_OPS(pd)->provider_status) ? \
+       KCF_PROV_CONTROL_OPS(pd)->provider_status( \
+           (pd)->pd_prov_handle, status) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_ctx_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_CREATE_CTX_TEMPLATE(pd, mech, key, template, size, req) ( \
+       (KCF_PROV_CTX_OPS(pd) && KCF_PROV_CTX_OPS(pd)->create_ctx_template) ? \
+       KCF_PROV_CTX_OPS(pd)->create_ctx_template( \
+           (pd)->pd_prov_handle, mech, key, template, size, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_FREE_CONTEXT(pd, ctx) ( \
+       (KCF_PROV_CTX_OPS(pd) && KCF_PROV_CTX_OPS(pd)->free_context) ? \
+       KCF_PROV_CTX_OPS(pd)->free_context(ctx) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_COPYIN_MECH(pd, umech, kmech, errorp, mode) ( \
+       (KCF_PROV_MECH_OPS(pd) && KCF_PROV_MECH_OPS(pd)->copyin_mechanism) ? \
+       KCF_PROV_MECH_OPS(pd)->copyin_mechanism( \
+           (pd)->pd_prov_handle, umech, kmech, errorp, mode) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_COPYOUT_MECH(pd, kmech, umech, errorp, mode) ( \
+       (KCF_PROV_MECH_OPS(pd) && KCF_PROV_MECH_OPS(pd)->copyout_mechanism) ? \
+       KCF_PROV_MECH_OPS(pd)->copyout_mechanism( \
+           (pd)->pd_prov_handle, kmech, umech, errorp, mode) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_FREE_MECH(pd, prov_mech) ( \
+       (KCF_PROV_MECH_OPS(pd) && KCF_PROV_MECH_OPS(pd)->free_mechanism) ? \
+       KCF_PROV_MECH_OPS(pd)->free_mechanism( \
+           (pd)->pd_prov_handle, prov_mech) : CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_digest_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_DIGEST_INIT(pd, ctx, mech, req) ( \
+       (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_init) ? \
+       KCF_PROV_DIGEST_OPS(pd)->digest_init(ctx, mech, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * The _ (underscore) in _digest is needed to avoid replacing the
+ * function digest().
+ */
+#define        KCF_PROV_DIGEST(pd, ctx, data, _digest, req) ( \
+       (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest) ? \
+       KCF_PROV_DIGEST_OPS(pd)->digest(ctx, data, _digest, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DIGEST_UPDATE(pd, ctx, data, req) ( \
+       (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_update) ? \
+       KCF_PROV_DIGEST_OPS(pd)->digest_update(ctx, data, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DIGEST_KEY(pd, ctx, key, req) ( \
+       (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_key) ? \
+       KCF_PROV_DIGEST_OPS(pd)->digest_key(ctx, key, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DIGEST_FINAL(pd, ctx, digest, req) ( \
+       (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_final) ? \
+       KCF_PROV_DIGEST_OPS(pd)->digest_final(ctx, digest, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DIGEST_ATOMIC(pd, session, mech, data, digest, req) ( \
+       (KCF_PROV_DIGEST_OPS(pd) && KCF_PROV_DIGEST_OPS(pd)->digest_atomic) ? \
+       KCF_PROV_DIGEST_OPS(pd)->digest_atomic( \
+           (pd)->pd_prov_handle, session, mech, data, digest, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_cipher_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_ENCRYPT_INIT(pd, ctx, mech, key, template, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt_init) ? \
+       KCF_PROV_CIPHER_OPS(pd)->encrypt_init(ctx, mech, key, template, \
+           req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_ENCRYPT(pd, ctx, plaintext, ciphertext, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt) ? \
+       KCF_PROV_CIPHER_OPS(pd)->encrypt(ctx, plaintext, ciphertext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_ENCRYPT_UPDATE(pd, ctx, plaintext, ciphertext, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt_update) ? \
+       KCF_PROV_CIPHER_OPS(pd)->encrypt_update(ctx, plaintext, \
+           ciphertext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_ENCRYPT_FINAL(pd, ctx, ciphertext, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt_final) ? \
+       KCF_PROV_CIPHER_OPS(pd)->encrypt_final(ctx, ciphertext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_ENCRYPT_ATOMIC(pd, session, mech, key, plaintext, ciphertext, \
+           template, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->encrypt_atomic) ? \
+       KCF_PROV_CIPHER_OPS(pd)->encrypt_atomic( \
+           (pd)->pd_prov_handle, session, mech, key, plaintext, ciphertext, \
+           template, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DECRYPT_INIT(pd, ctx, mech, key, template, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt_init) ? \
+       KCF_PROV_CIPHER_OPS(pd)->decrypt_init(ctx, mech, key, template, \
+           req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DECRYPT(pd, ctx, ciphertext, plaintext, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt) ? \
+       KCF_PROV_CIPHER_OPS(pd)->decrypt(ctx, ciphertext, plaintext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DECRYPT_UPDATE(pd, ctx, ciphertext, plaintext, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt_update) ? \
+       KCF_PROV_CIPHER_OPS(pd)->decrypt_update(ctx, ciphertext, \
+           plaintext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DECRYPT_FINAL(pd, ctx, plaintext, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt_final) ? \
+       KCF_PROV_CIPHER_OPS(pd)->decrypt_final(ctx, plaintext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DECRYPT_ATOMIC(pd, session, mech, key, ciphertext, plaintext, \
+           template, req) ( \
+       (KCF_PROV_CIPHER_OPS(pd) && KCF_PROV_CIPHER_OPS(pd)->decrypt_atomic) ? \
+       KCF_PROV_CIPHER_OPS(pd)->decrypt_atomic( \
+           (pd)->pd_prov_handle, session, mech, key, ciphertext, plaintext, \
+           template, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_mac_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_MAC_INIT(pd, ctx, mech, key, template, req) ( \
+       (KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_init) ? \
+       KCF_PROV_MAC_OPS(pd)->mac_init(ctx, mech, key, template, req) \
+       : CRYPTO_NOT_SUPPORTED)
+
+/*
+ * The _ (underscore) in _mac is needed to avoid replacing the
+ * function mac().
+ */
+#define        KCF_PROV_MAC(pd, ctx, data, _mac, req) ( \
+       (KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac) ? \
+       KCF_PROV_MAC_OPS(pd)->mac(ctx, data, _mac, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_UPDATE(pd, ctx, data, req) ( \
+       (KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_update) ? \
+       KCF_PROV_MAC_OPS(pd)->mac_update(ctx, data, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_FINAL(pd, ctx, mac, req) ( \
+       (KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_final) ? \
+       KCF_PROV_MAC_OPS(pd)->mac_final(ctx, mac, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_ATOMIC(pd, session, mech, key, data, mac, template, \
+           req) ( \
+       (KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_atomic) ? \
+       KCF_PROV_MAC_OPS(pd)->mac_atomic( \
+           (pd)->pd_prov_handle, session, mech, key, data, mac, template, \
+           req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_VERIFY_ATOMIC(pd, session, mech, key, data, mac, \
+           template, req) ( \
+       (KCF_PROV_MAC_OPS(pd) && KCF_PROV_MAC_OPS(pd)->mac_verify_atomic) ? \
+       KCF_PROV_MAC_OPS(pd)->mac_verify_atomic( \
+           (pd)->pd_prov_handle, session, mech, key, data, mac, template, \
+           req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_sign_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_SIGN_INIT(pd, ctx, mech, key, template, req) ( \
+       (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_init) ? \
+       KCF_PROV_SIGN_OPS(pd)->sign_init( \
+           ctx, mech, key, template, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SIGN(pd, ctx, data, sig, req) ( \
+       (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign) ? \
+       KCF_PROV_SIGN_OPS(pd)->sign(ctx, data, sig, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SIGN_UPDATE(pd, ctx, data, req) ( \
+       (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_update) ? \
+       KCF_PROV_SIGN_OPS(pd)->sign_update(ctx, data, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SIGN_FINAL(pd, ctx, sig, req) ( \
+       (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_final) ? \
+       KCF_PROV_SIGN_OPS(pd)->sign_final(ctx, sig, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SIGN_ATOMIC(pd, session, mech, key, data, template, \
+           sig, req) ( \
+       (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_atomic) ? \
+       KCF_PROV_SIGN_OPS(pd)->sign_atomic( \
+           (pd)->pd_prov_handle, session, mech, key, data, sig, template, \
+           req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SIGN_RECOVER_INIT(pd, ctx, mech, key, template, \
+           req) ( \
+       (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_recover_init) ? \
+       KCF_PROV_SIGN_OPS(pd)->sign_recover_init(ctx, mech, key, template, \
+           req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SIGN_RECOVER(pd, ctx, data, sig, req) ( \
+       (KCF_PROV_SIGN_OPS(pd) && KCF_PROV_SIGN_OPS(pd)->sign_recover) ? \
+       KCF_PROV_SIGN_OPS(pd)->sign_recover(ctx, data, sig, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SIGN_RECOVER_ATOMIC(pd, session, mech, key, data, template, \
+           sig, req) ( \
+       (KCF_PROV_SIGN_OPS(pd) && \
+       KCF_PROV_SIGN_OPS(pd)->sign_recover_atomic) ? \
+       KCF_PROV_SIGN_OPS(pd)->sign_recover_atomic( \
+           (pd)->pd_prov_handle, session, mech, key, data, sig, template, \
+           req) : CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_verify_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_VERIFY_INIT(pd, ctx, mech, key, template, req) ( \
+       (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_init) ? \
+       KCF_PROV_VERIFY_OPS(pd)->verify_init(ctx, mech, key, template, \
+           req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_VERIFY(pd, ctx, data, sig, req) ( \
+       (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->do_verify) ? \
+       KCF_PROV_VERIFY_OPS(pd)->do_verify(ctx, data, sig, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_VERIFY_UPDATE(pd, ctx, data, req) ( \
+       (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_update) ? \
+       KCF_PROV_VERIFY_OPS(pd)->verify_update(ctx, data, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_VERIFY_FINAL(pd, ctx, sig, req) ( \
+       (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_final) ? \
+       KCF_PROV_VERIFY_OPS(pd)->verify_final(ctx, sig, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_VERIFY_ATOMIC(pd, session, mech, key, data, template, sig, \
+           req) ( \
+       (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_atomic) ? \
+       KCF_PROV_VERIFY_OPS(pd)->verify_atomic( \
+           (pd)->pd_prov_handle, session, mech, key, data, sig, template, \
+           req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_VERIFY_RECOVER_INIT(pd, ctx, mech, key, template, \
+           req) ( \
+       (KCF_PROV_VERIFY_OPS(pd) && \
+       KCF_PROV_VERIFY_OPS(pd)->verify_recover_init) ? \
+       KCF_PROV_VERIFY_OPS(pd)->verify_recover_init(ctx, mech, key, \
+           template, req) : CRYPTO_NOT_SUPPORTED)
+
+/* verify_recover() CSPI routine has different argument order than verify() */
+#define        KCF_PROV_VERIFY_RECOVER(pd, ctx, sig, data, req) ( \
+       (KCF_PROV_VERIFY_OPS(pd) && KCF_PROV_VERIFY_OPS(pd)->verify_recover) ? \
+       KCF_PROV_VERIFY_OPS(pd)->verify_recover(ctx, sig, data, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * verify_recover_atomic() CSPI routine has different argument order
+ * than verify_atomic().
+ */
+#define        KCF_PROV_VERIFY_RECOVER_ATOMIC(pd, session, mech, key, sig, \
+           template, data,  req) ( \
+       (KCF_PROV_VERIFY_OPS(pd) && \
+       KCF_PROV_VERIFY_OPS(pd)->verify_recover_atomic) ? \
+       KCF_PROV_VERIFY_OPS(pd)->verify_recover_atomic( \
+           (pd)->pd_prov_handle, session, mech, key, sig, data, template, \
+           req) : CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_dual_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_DIGEST_ENCRYPT_UPDATE(digest_ctx, encrypt_ctx, plaintext, \
+           ciphertext, req) ( \
+       (KCF_PROV_DUAL_OPS(pd) && \
+       KCF_PROV_DUAL_OPS(pd)->digest_encrypt_update) ? \
+       KCF_PROV_DUAL_OPS(pd)->digest_encrypt_update( \
+           digest_ctx, encrypt_ctx, plaintext, ciphertext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DECRYPT_DIGEST_UPDATE(decrypt_ctx, digest_ctx, ciphertext, \
+           plaintext, req) ( \
+       (KCF_PROV_DUAL_OPS(pd) && \
+       KCF_PROV_DUAL_OPS(pd)->decrypt_digest_update) ? \
+       KCF_PROV_DUAL_OPS(pd)->decrypt_digest_update( \
+           decrypt_ctx, digest_ctx, ciphertext, plaintext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SIGN_ENCRYPT_UPDATE(sign_ctx, encrypt_ctx, plaintext, \
+           ciphertext, req) ( \
+       (KCF_PROV_DUAL_OPS(pd) && \
+       KCF_PROV_DUAL_OPS(pd)->sign_encrypt_update) ? \
+       KCF_PROV_DUAL_OPS(pd)->sign_encrypt_update( \
+           sign_ctx, encrypt_ctx, plaintext, ciphertext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_DECRYPT_VERIFY_UPDATE(decrypt_ctx, verify_ctx, ciphertext, \
+           plaintext, req) ( \
+       (KCF_PROV_DUAL_OPS(pd) && \
+       KCF_PROV_DUAL_OPS(pd)->decrypt_verify_update) ? \
+       KCF_PROV_DUAL_OPS(pd)->decrypt_verify_update( \
+           decrypt_ctx, verify_ctx, ciphertext, plaintext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_dual_cipher_mac_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_ENCRYPT_MAC_INIT(pd, ctx, encr_mech, encr_key, mac_mech, \
+           mac_key, encr_ctx_template, mac_ctx_template, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_init) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_init( \
+           ctx, encr_mech, encr_key, mac_mech, mac_key, encr_ctx_template, \
+           mac_ctx_template, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_ENCRYPT_MAC(pd, ctx, plaintext, ciphertext, mac, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac( \
+           ctx, plaintext, ciphertext, mac, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_ENCRYPT_MAC_UPDATE(pd, ctx, plaintext, ciphertext, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_update) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_update( \
+           ctx, plaintext, ciphertext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_ENCRYPT_MAC_FINAL(pd, ctx, ciphertext, mac, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_final) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_final( \
+           ctx, ciphertext, mac, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_ENCRYPT_MAC_ATOMIC(pd, session, encr_mech, encr_key, \
+           mac_mech, mac_key, plaintext, ciphertext, mac, \
+           encr_ctx_template, mac_ctx_template, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_atomic) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->encrypt_mac_atomic( \
+           (pd)->pd_prov_handle, session, encr_mech, encr_key, \
+           mac_mech, mac_key, plaintext, ciphertext, mac, \
+           encr_ctx_template, mac_ctx_template, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_DECRYPT_INIT(pd, ctx, mac_mech, mac_key, decr_mech, \
+           decr_key, mac_ctx_template, decr_ctx_template, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_init) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_init( \
+           ctx, mac_mech, mac_key, decr_mech, decr_key, mac_ctx_template, \
+           decr_ctx_template, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_DECRYPT(pd, ctx, ciphertext, mac, plaintext, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt( \
+           ctx, ciphertext, mac, plaintext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_DECRYPT_UPDATE(pd, ctx, ciphertext, plaintext, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_update) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_update( \
+           ctx, ciphertext, plaintext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_DECRYPT_FINAL(pd, ctx, mac, plaintext, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_final) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_final( \
+           ctx, mac, plaintext, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_DECRYPT_ATOMIC(pd, session, mac_mech, mac_key, \
+           decr_mech, decr_key, ciphertext, mac, plaintext, \
+           mac_ctx_template, decr_ctx_template, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_atomic) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_decrypt_atomic( \
+           (pd)->pd_prov_handle, session, mac_mech, mac_key, \
+           decr_mech, decr_key, ciphertext, mac, plaintext, \
+           mac_ctx_template, decr_ctx_template, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_MAC_VERIFY_DECRYPT_ATOMIC(pd, session, mac_mech, mac_key, \
+           decr_mech, decr_key, ciphertext, mac, plaintext, \
+           mac_ctx_template, decr_ctx_template, req) ( \
+       (KCF_PROV_DUAL_CIPHER_MAC_OPS(pd) && \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_verify_decrypt_atomic \
+           != NULL) ? \
+       KCF_PROV_DUAL_CIPHER_MAC_OPS(pd)->mac_verify_decrypt_atomic( \
+           (pd)->pd_prov_handle, session, mac_mech, mac_key, \
+           decr_mech, decr_key, ciphertext, mac, plaintext, \
+           mac_ctx_template, decr_ctx_template, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_random_number_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_SEED_RANDOM(pd, session, buf, len, est, flags, req) ( \
+       (KCF_PROV_RANDOM_OPS(pd) && KCF_PROV_RANDOM_OPS(pd)->seed_random) ? \
+       KCF_PROV_RANDOM_OPS(pd)->seed_random((pd)->pd_prov_handle, \
+           session, buf, len, est, flags, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_GENERATE_RANDOM(pd, session, buf, len, req) ( \
+       (KCF_PROV_RANDOM_OPS(pd) && \
+       KCF_PROV_RANDOM_OPS(pd)->generate_random) ? \
+       KCF_PROV_RANDOM_OPS(pd)->generate_random((pd)->pd_prov_handle, \
+           session, buf, len, req) : CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_session_ops(9S) entry points.
+ *
+ * ops_pd is the provider descriptor that supplies the ops_vector.
+ * pd is the descriptor that supplies the provider handle.
+ * Only session open/close needs two handles.
+ */
+
+#define        KCF_PROV_SESSION_OPEN(ops_pd, session, req, pd) ( \
+       (KCF_PROV_SESSION_OPS(ops_pd) && \
+       KCF_PROV_SESSION_OPS(ops_pd)->session_open) ? \
+       KCF_PROV_SESSION_OPS(ops_pd)->session_open((pd)->pd_prov_handle, \
+           session, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SESSION_CLOSE(ops_pd, session, req, pd) ( \
+       (KCF_PROV_SESSION_OPS(ops_pd) && \
+       KCF_PROV_SESSION_OPS(ops_pd)->session_close) ? \
+       KCF_PROV_SESSION_OPS(ops_pd)->session_close((pd)->pd_prov_handle, \
+           session, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SESSION_LOGIN(pd, session, user_type, pin, len, req) ( \
+       (KCF_PROV_SESSION_OPS(pd) && \
+       KCF_PROV_SESSION_OPS(pd)->session_login) ? \
+       KCF_PROV_SESSION_OPS(pd)->session_login((pd)->pd_prov_handle, \
+           session, user_type, pin, len, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SESSION_LOGOUT(pd, session, req) ( \
+       (KCF_PROV_SESSION_OPS(pd) && \
+       KCF_PROV_SESSION_OPS(pd)->session_logout) ? \
+       KCF_PROV_SESSION_OPS(pd)->session_logout((pd)->pd_prov_handle, \
+           session, req) : CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_object_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_OBJECT_CREATE(pd, session, template, count, object, req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && KCF_PROV_OBJECT_OPS(pd)->object_create) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_create((pd)->pd_prov_handle, \
+           session, template, count, object, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_OBJECT_COPY(pd, session, object, template, count, \
+           new_object, req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && KCF_PROV_OBJECT_OPS(pd)->object_copy) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_copy((pd)->pd_prov_handle, \
+       session, object, template, count, new_object, req) : \
+           CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_OBJECT_DESTROY(pd, session, object, req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && KCF_PROV_OBJECT_OPS(pd)->object_destroy) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_destroy((pd)->pd_prov_handle, \
+           session, object, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_OBJECT_GET_SIZE(pd, session, object, size, req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && \
+       KCF_PROV_OBJECT_OPS(pd)->object_get_size) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_get_size((pd)->pd_prov_handle, \
+           session, object, size, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_OBJECT_GET_ATTRIBUTE_VALUE(pd, session, object, template, \
+           count, req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && \
+       KCF_PROV_OBJECT_OPS(pd)->object_get_attribute_value) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_get_attribute_value( \
+       (pd)->pd_prov_handle, session, object, template, count, req) : \
+           CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_OBJECT_SET_ATTRIBUTE_VALUE(pd, session, object, template, \
+           count, req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && \
+       KCF_PROV_OBJECT_OPS(pd)->object_set_attribute_value) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_set_attribute_value( \
+       (pd)->pd_prov_handle, session, object, template, count, req) : \
+           CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_OBJECT_FIND_INIT(pd, session, template, count, ppriv, \
+           req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && \
+       KCF_PROV_OBJECT_OPS(pd)->object_find_init) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_find_init((pd)->pd_prov_handle, \
+       session, template, count, ppriv, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_OBJECT_FIND(pd, ppriv, objects, max_objects, object_count, \
+           req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && KCF_PROV_OBJECT_OPS(pd)->object_find) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_find( \
+       (pd)->pd_prov_handle, ppriv, objects, max_objects, object_count, \
+       req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_OBJECT_FIND_FINAL(pd, ppriv, req) ( \
+       (KCF_PROV_OBJECT_OPS(pd) && \
+       KCF_PROV_OBJECT_OPS(pd)->object_find_final) ? \
+       KCF_PROV_OBJECT_OPS(pd)->object_find_final( \
+           (pd)->pd_prov_handle, ppriv, req) : CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_key_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_KEY_GENERATE(pd, session, mech, template, count, object, \
+           req) ( \
+       (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_generate) ? \
+       KCF_PROV_KEY_OPS(pd)->key_generate((pd)->pd_prov_handle, \
+           session, mech, template, count, object, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_KEY_GENERATE_PAIR(pd, session, mech, pub_template, \
+           pub_count, priv_template, priv_count, pub_key, priv_key, req) ( \
+       (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_generate_pair) ? \
+       KCF_PROV_KEY_OPS(pd)->key_generate_pair((pd)->pd_prov_handle, \
+           session, mech, pub_template, pub_count, priv_template, \
+           priv_count, pub_key, priv_key, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_KEY_WRAP(pd, session, mech, wrapping_key, key, wrapped_key, \
+           wrapped_key_len, req) ( \
+       (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_wrap) ? \
+       KCF_PROV_KEY_OPS(pd)->key_wrap((pd)->pd_prov_handle, \
+           session, mech, wrapping_key, key, wrapped_key, wrapped_key_len, \
+           req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_KEY_UNWRAP(pd, session, mech, unwrapping_key, wrapped_key, \
+           wrapped_key_len, template, count, key, req) ( \
+       (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_unwrap) ? \
+       KCF_PROV_KEY_OPS(pd)->key_unwrap((pd)->pd_prov_handle, \
+           session, mech, unwrapping_key, wrapped_key, wrapped_key_len, \
+           template, count, key, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_KEY_DERIVE(pd, session, mech, base_key, template, count, \
+           key, req) ( \
+       (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_derive) ? \
+       KCF_PROV_KEY_OPS(pd)->key_derive((pd)->pd_prov_handle, \
+           session, mech, base_key, template, count, key, req) : \
+       CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_KEY_CHECK(pd, mech, key) ( \
+       (KCF_PROV_KEY_OPS(pd) && KCF_PROV_KEY_OPS(pd)->key_check) ? \
+       KCF_PROV_KEY_OPS(pd)->key_check((pd)->pd_prov_handle, mech, key) : \
+       CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_provider_management_ops(9S) entry points.
+ *
+ * ops_pd is the provider descriptor that supplies the ops_vector.
+ * pd is the descriptor that supplies the provider handle.
+ * Only ext_info needs two handles.
+ */
+
+#define        KCF_PROV_EXT_INFO(ops_pd, provext_info, req, pd) ( \
+       (KCF_PROV_PROVIDER_OPS(ops_pd) && \
+       KCF_PROV_PROVIDER_OPS(ops_pd)->ext_info) ? \
+       KCF_PROV_PROVIDER_OPS(ops_pd)->ext_info((pd)->pd_prov_handle, \
+           provext_info, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_INIT_TOKEN(pd, pin, pin_len, label, req) ( \
+       (KCF_PROV_PROVIDER_OPS(pd) && KCF_PROV_PROVIDER_OPS(pd)->init_token) ? \
+       KCF_PROV_PROVIDER_OPS(pd)->init_token((pd)->pd_prov_handle, \
+           pin, pin_len, label, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_INIT_PIN(pd, session, pin, pin_len, req) ( \
+       (KCF_PROV_PROVIDER_OPS(pd) && KCF_PROV_PROVIDER_OPS(pd)->init_pin) ? \
+       KCF_PROV_PROVIDER_OPS(pd)->init_pin((pd)->pd_prov_handle, \
+           session, pin, pin_len, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_SET_PIN(pd, session, old_pin, old_len, new_pin, new_len, \
+           req) ( \
+       (KCF_PROV_PROVIDER_OPS(pd) && KCF_PROV_PROVIDER_OPS(pd)->set_pin) ? \
+       KCF_PROV_PROVIDER_OPS(pd)->set_pin((pd)->pd_prov_handle, \
+       session, old_pin, old_len, new_pin, new_len, req) : \
+           CRYPTO_NOT_SUPPORTED)
+
+/*
+ * Wrappers for crypto_nostore_key_ops(9S) entry points.
+ */
+
+#define        KCF_PROV_NOSTORE_KEY_GENERATE(pd, session, mech, template, count, \
+           out_template, out_count, req) ( \
+       (KCF_PROV_NOSTORE_KEY_OPS(pd) && \
+           KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_generate) ? \
+       KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_generate( \
+           (pd)->pd_prov_handle, session, mech, template, count, \
+           out_template, out_count, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_NOSTORE_KEY_GENERATE_PAIR(pd, session, mech, pub_template, \
+           pub_count, priv_template, priv_count, out_pub_template, \
+           out_pub_count, out_priv_template, out_priv_count, req) ( \
+       (KCF_PROV_NOSTORE_KEY_OPS(pd) && \
+           KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_generate_pair) ? \
+       KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_generate_pair( \
+           (pd)->pd_prov_handle, session, mech, pub_template, pub_count, \
+           priv_template, priv_count, out_pub_template, out_pub_count, \
+           out_priv_template, out_priv_count, req) : CRYPTO_NOT_SUPPORTED)
+
+#define        KCF_PROV_NOSTORE_KEY_DERIVE(pd, session, mech, base_key, template, \
+           count, out_template, out_count, req) ( \
+       (KCF_PROV_NOSTORE_KEY_OPS(pd) && \
+           KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_derive) ? \
+       KCF_PROV_NOSTORE_KEY_OPS(pd)->nostore_key_derive( \
+           (pd)->pd_prov_handle, session, mech, base_key, template, count, \
+           out_template, out_count, req) : CRYPTO_NOT_SUPPORTED)
+
+/*
+ * The following routines are exported by the kcf module (/kernel/misc/kcf)
+ * to the crypto and cryptoadmin modules.
+ */
+
+/* Digest/mac/cipher entry points that take a provider descriptor and session */
+extern int crypto_digest_single(crypto_context_t, crypto_data_t *,
+    crypto_data_t *, crypto_call_req_t *);
+
+extern int crypto_mac_single(crypto_context_t, crypto_data_t *,
+    crypto_data_t *, crypto_call_req_t *);
+
+extern int crypto_encrypt_single(crypto_context_t, crypto_data_t *,
+    crypto_data_t *, crypto_call_req_t *);
+
+extern int crypto_decrypt_single(crypto_context_t, crypto_data_t *,
+    crypto_data_t *, crypto_call_req_t *);
+
+
+/* Other private digest/mac/cipher entry points not exported through k-API */
+extern int crypto_digest_key_prov(crypto_context_t, crypto_key_t *,
+    crypto_call_req_t *);
+
+/* Private sign entry points exported by KCF */
+extern int crypto_sign_single(crypto_context_t, crypto_data_t *,
+    crypto_data_t *, crypto_call_req_t *);
+
+extern int crypto_sign_recover_single(crypto_context_t, crypto_data_t *,
+    crypto_data_t *, crypto_call_req_t *);
+
+/* Private verify entry points exported by KCF */
+extern int crypto_verify_single(crypto_context_t, crypto_data_t *,
+    crypto_data_t *, crypto_call_req_t *);
+
+extern int crypto_verify_recover_single(crypto_context_t, crypto_data_t *,
+    crypto_data_t *, crypto_call_req_t *);
+
+/* Private dual operations entry points exported by KCF */
+extern int crypto_digest_encrypt_update(crypto_context_t, crypto_context_t,
+    crypto_data_t *, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_decrypt_digest_update(crypto_context_t, crypto_context_t,
+    crypto_data_t *, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_sign_encrypt_update(crypto_context_t, crypto_context_t,
+    crypto_data_t *, crypto_data_t *, crypto_call_req_t *);
+extern int crypto_decrypt_verify_update(crypto_context_t, crypto_context_t,
+    crypto_data_t *, crypto_data_t *, crypto_call_req_t *);
+
+/* Random Number Generation */
+int crypto_seed_random(crypto_provider_handle_t provider, uchar_t *buf,
+    size_t len, crypto_call_req_t *req);
+int crypto_generate_random(crypto_provider_handle_t provider, uchar_t *buf,
+    size_t len, crypto_call_req_t *req);
+
+/* Provider Management */
+int crypto_get_provider_info(crypto_provider_id_t id,
+    crypto_provider_info_t **info, crypto_call_req_t *req);
+int crypto_get_provider_mechanisms(crypto_minor_t *, crypto_provider_id_t id,
+    uint_t *count, crypto_mech_name_t **list);
+int crypto_init_token(crypto_provider_handle_t provider, char *pin,
+    size_t pin_len, char *label, crypto_call_req_t *);
+int crypto_init_pin(crypto_provider_handle_t provider, char *pin,
+    size_t pin_len, crypto_call_req_t *req);
+int crypto_set_pin(crypto_provider_handle_t provider, char *old_pin,
+    size_t old_len, char *new_pin, size_t new_len, crypto_call_req_t *req);
+void crypto_free_provider_list(crypto_provider_entry_t *list, uint_t count);
+void crypto_free_provider_info(crypto_provider_info_t *info);
+
+/* Administrative */
+int crypto_get_dev_list(uint_t *count, crypto_dev_list_entry_t **list);
+int crypto_get_soft_list(uint_t *count, char **list, size_t *len);
+int crypto_get_dev_info(char *name, uint_t instance, uint_t *count,
+    crypto_mech_name_t **list);
+int crypto_get_soft_info(caddr_t name, uint_t *count,
+    crypto_mech_name_t **list);
+int crypto_load_dev_disabled(char *name, uint_t instance, uint_t count,
+    crypto_mech_name_t *list);
+int crypto_load_soft_disabled(caddr_t name, uint_t count,
+    crypto_mech_name_t *list);
+int crypto_unload_soft_module(caddr_t path);
+int crypto_load_soft_config(caddr_t name, uint_t count,
+    crypto_mech_name_t *list);
+int crypto_load_door(uint_t did);
+void crypto_free_mech_list(crypto_mech_name_t *list, uint_t count);
+void crypto_free_dev_list(crypto_dev_list_entry_t *list, uint_t count);
+
+/* Miscellaneous */
+int crypto_get_mechanism_number(caddr_t name, crypto_mech_type_t *number);
+int crypto_get_function_list(crypto_provider_id_t id,
+    crypto_function_list_t **list, int kmflag);
+void crypto_free_function_list(crypto_function_list_t *list);
+int crypto_build_permitted_mech_names(kcf_provider_desc_t *,
+    crypto_mech_name_t **, uint_t *, int);
+extern void kcf_destroy_mech_tabs(void);
+extern void kcf_init_mech_tabs(void);
+extern int kcf_add_mech_provider(short, kcf_provider_desc_t *,
+    kcf_prov_mech_desc_t **);
+extern void kcf_remove_mech_provider(char *, kcf_provider_desc_t *);
+extern int kcf_get_mech_entry(crypto_mech_type_t, kcf_mech_entry_t **);
+extern kcf_provider_desc_t *kcf_alloc_provider_desc(crypto_provider_info_t *);
+extern void kcf_provider_zero_refcnt(kcf_provider_desc_t *);
+extern void kcf_free_provider_desc(kcf_provider_desc_t *);
+extern void kcf_soft_config_init(void);
+extern int get_sw_provider_for_mech(crypto_mech_name_t, char **);
+extern crypto_mech_type_t crypto_mech2id_common(char *, boolean_t);
+extern void undo_register_provider(kcf_provider_desc_t *, boolean_t);
+extern void redo_register_provider(kcf_provider_desc_t *);
+extern void kcf_rnd_init(void);
+extern boolean_t kcf_rngprov_check(void);
+extern int kcf_rnd_get_pseudo_bytes(uint8_t *, size_t);
+extern int kcf_rnd_get_bytes(uint8_t *, size_t, boolean_t, boolean_t);
+extern int random_add_pseudo_entropy(uint8_t *, size_t, uint_t);
+extern void kcf_rnd_schedule_timeout(boolean_t);
+extern int crypto_uio_data(crypto_data_t *, uchar_t *, int, cmd_type_t,
+    void *, void (*update)(void));
+extern int crypto_mblk_data(crypto_data_t *, uchar_t *, int, cmd_type_t,
+    void *, void (*update)(void));
+extern int crypto_put_output_data(uchar_t *, crypto_data_t *, int);
+extern int crypto_get_input_data(crypto_data_t *, uchar_t **, uchar_t *);
+extern int crypto_copy_key_to_ctx(crypto_key_t *, crypto_key_t **, size_t *,
+    int kmflag);
+extern int crypto_digest_data(crypto_data_t *, void *, uchar_t *,
+    void (*update)(void), void (*final)(void), uchar_t);
+extern int crypto_update_iov(void *, crypto_data_t *, crypto_data_t *,
+    int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
+    void (*copy_block)(uint8_t *, uint64_t *));
+extern int crypto_update_uio(void *, crypto_data_t *, crypto_data_t *,
+    int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
+    void (*copy_block)(uint8_t *, uint64_t *));
+extern int crypto_update_mp(void *, crypto_data_t *, crypto_data_t *,
+    int (*cipher)(void *, caddr_t, size_t, crypto_data_t *),
+    void (*copy_block)(uint8_t *, uint64_t *));
+extern int crypto_get_key_attr(crypto_key_t *, crypto_attr_type_t, uchar_t **,
+    ssize_t *);
+
+/* Access to the provider's table */
+extern void kcf_prov_tab_destroy(void);
+extern void kcf_prov_tab_init(void);
+extern int kcf_prov_tab_add_provider(kcf_provider_desc_t *);
+extern int kcf_prov_tab_rem_provider(crypto_provider_id_t);
+extern kcf_provider_desc_t *kcf_prov_tab_lookup_by_name(char *);
+extern kcf_provider_desc_t *kcf_prov_tab_lookup_by_dev(char *, uint_t);
+extern int kcf_get_hw_prov_tab(uint_t *, kcf_provider_desc_t ***, int,
+    char *, uint_t, boolean_t);
+extern int kcf_get_slot_list(uint_t *, kcf_provider_desc_t ***, boolean_t);
+extern void kcf_free_provider_tab(uint_t, kcf_provider_desc_t **);
+extern kcf_provider_desc_t *kcf_prov_tab_lookup(crypto_provider_id_t);
+extern int kcf_get_sw_prov(crypto_mech_type_t, kcf_provider_desc_t **,
+    kcf_mech_entry_t **, boolean_t);
+
+/* Access to the policy table */
+extern boolean_t is_mech_disabled(kcf_provider_desc_t *, crypto_mech_name_t);
+extern boolean_t is_mech_disabled_byname(crypto_provider_type_t, char *,
+    uint_t, crypto_mech_name_t);
+extern void kcf_policy_tab_init(void);
+extern void kcf_policy_free_desc(kcf_policy_desc_t *);
+extern void kcf_policy_remove_by_name(char *, uint_t *, crypto_mech_name_t **);
+extern void kcf_policy_remove_by_dev(char *, uint_t, uint_t *,
+    crypto_mech_name_t **);
+extern kcf_policy_desc_t *kcf_policy_lookup_by_name(char *);
+extern kcf_policy_desc_t *kcf_policy_lookup_by_dev(char *, uint_t);
+extern int kcf_policy_load_soft_disabled(char *, uint_t, crypto_mech_name_t *,
+    uint_t *, crypto_mech_name_t **);
+extern int kcf_policy_load_dev_disabled(char *, uint_t, uint_t,
+    crypto_mech_name_t *, uint_t *, crypto_mech_name_t **);
+extern boolean_t in_soft_config_list(char *);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_IMPL_H */
diff --git a/zfs/module/icp/include/sys/crypto/ioctl.h b/zfs/module/icp/include/sys/crypto/ioctl.h
new file mode 100644 (file)
index 0000000..dd59ca7
--- /dev/null
@@ -0,0 +1,1483 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SYS_CRYPTO_IOCTL_H
+#define        _SYS_CRYPTO_IOCTL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/common.h>
+
+#define        CRYPTO_MAX_ATTRIBUTE_COUNT      128
+
+#define        CRYPTO_IOFLAGS_RW_SESSION       0x00000001
+
+#define        CRYPTO(x)               (('y' << 8) | (x))
+
+#define        MAX_NUM_THRESHOLD       7
+
+/* the PKCS11 Mechanisms */
+#define        CKM_RC4                 0x00000111
+#define        CKM_DES3_ECB            0x00000132
+#define        CKM_DES3_CBC            0x00000133
+#define        CKM_MD5                 0x00000210
+#define        CKM_SHA_1               0x00000220
+#define        CKM_AES_ECB             0x00001081
+#define        CKM_AES_CBC             0x00001082
+
+/*
+ * General Purpose Ioctls
+ */
+
+typedef struct fl_mechs_threshold {
+       int             mech_type;
+       uint32_t        mech_threshold;
+} fl_mechs_threshold_t;
+
+typedef struct crypto_function_list {
+       boolean_t fl_digest_init;
+       boolean_t fl_digest;
+       boolean_t fl_digest_update;
+       boolean_t fl_digest_key;
+       boolean_t fl_digest_final;
+
+       boolean_t fl_encrypt_init;
+       boolean_t fl_encrypt;
+       boolean_t fl_encrypt_update;
+       boolean_t fl_encrypt_final;
+
+       boolean_t fl_decrypt_init;
+       boolean_t fl_decrypt;
+       boolean_t fl_decrypt_update;
+       boolean_t fl_decrypt_final;
+
+       boolean_t fl_mac_init;
+       boolean_t fl_mac;
+       boolean_t fl_mac_update;
+       boolean_t fl_mac_final;
+
+       boolean_t fl_sign_init;
+       boolean_t fl_sign;
+       boolean_t fl_sign_update;
+       boolean_t fl_sign_final;
+       boolean_t fl_sign_recover_init;
+       boolean_t fl_sign_recover;
+
+       boolean_t fl_verify_init;
+       boolean_t fl_verify;
+       boolean_t fl_verify_update;
+       boolean_t fl_verify_final;
+       boolean_t fl_verify_recover_init;
+       boolean_t fl_verify_recover;
+
+       boolean_t fl_digest_encrypt_update;
+       boolean_t fl_decrypt_digest_update;
+       boolean_t fl_sign_encrypt_update;
+       boolean_t fl_decrypt_verify_update;
+
+       boolean_t fl_seed_random;
+       boolean_t fl_generate_random;
+
+       boolean_t fl_session_open;
+       boolean_t fl_session_close;
+       boolean_t fl_session_login;
+       boolean_t fl_session_logout;
+
+       boolean_t fl_object_create;
+       boolean_t fl_object_copy;
+       boolean_t fl_object_destroy;
+       boolean_t fl_object_get_size;
+       boolean_t fl_object_get_attribute_value;
+       boolean_t fl_object_set_attribute_value;
+       boolean_t fl_object_find_init;
+       boolean_t fl_object_find;
+       boolean_t fl_object_find_final;
+
+       boolean_t fl_key_generate;
+       boolean_t fl_key_generate_pair;
+       boolean_t fl_key_wrap;
+       boolean_t fl_key_unwrap;
+       boolean_t fl_key_derive;
+
+       boolean_t fl_init_token;
+       boolean_t fl_init_pin;
+       boolean_t fl_set_pin;
+
+       boolean_t prov_is_limited;
+       uint32_t prov_hash_threshold;
+       uint32_t prov_hash_limit;
+
+       int total_threshold_count;
+       fl_mechs_threshold_t    fl_threshold[MAX_NUM_THRESHOLD];
+} crypto_function_list_t;
+
+typedef struct crypto_get_function_list {
+       uint_t                  fl_return_value;
+       crypto_provider_id_t    fl_provider_id;
+       crypto_function_list_t  fl_list;
+} crypto_get_function_list_t;
+
+typedef struct crypto_get_mechanism_number {
+       uint_t                  pn_return_value;
+       caddr_t                 pn_mechanism_string;
+       size_t                  pn_mechanism_len;
+       crypto_mech_type_t      pn_internal_number;
+} crypto_get_mechanism_number_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_get_mechanism_number32 {
+       uint32_t                pn_return_value;
+       caddr32_t               pn_mechanism_string;
+       size32_t                pn_mechanism_len;
+       crypto_mech_type_t      pn_internal_number;
+} crypto_get_mechanism_number32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_GET_FUNCTION_LIST        CRYPTO(20)
+#define        CRYPTO_GET_MECHANISM_NUMBER     CRYPTO(21)
+
+/*
+ * Session Ioctls
+ */
+
+typedef uint32_t       crypto_flags_t;
+
+typedef struct crypto_open_session {
+       uint_t                  os_return_value;
+       crypto_session_id_t     os_session;
+       crypto_flags_t          os_flags;
+       crypto_provider_id_t    os_provider_id;
+} crypto_open_session_t;
+
+typedef struct crypto_close_session {
+       uint_t                  cs_return_value;
+       crypto_session_id_t     cs_session;
+} crypto_close_session_t;
+
+typedef struct crypto_close_all_sessions {
+       uint_t                  as_return_value;
+       crypto_provider_id_t    as_provider_id;
+} crypto_close_all_sessions_t;
+
+#define        CRYPTO_OPEN_SESSION             CRYPTO(30)
+#define        CRYPTO_CLOSE_SESSION            CRYPTO(31)
+#define        CRYPTO_CLOSE_ALL_SESSIONS       CRYPTO(32)
+
+/*
+ * Login Ioctls
+ */
+typedef struct crypto_login {
+       uint_t                  co_return_value;
+       crypto_session_id_t     co_session;
+       uint_t                  co_user_type;
+       uint_t                  co_pin_len;
+       caddr_t                 co_pin;
+} crypto_login_t;
+
+typedef struct crypto_logout {
+       uint_t                  cl_return_value;
+       crypto_session_id_t     cl_session;
+} crypto_logout_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+typedef struct crypto_login32 {
+       uint32_t                co_return_value;
+       crypto_session_id_t     co_session;
+       uint32_t                co_user_type;
+       uint32_t                co_pin_len;
+       caddr32_t               co_pin;
+} crypto_login32_t;
+
+typedef struct crypto_logout32 {
+       uint32_t                cl_return_value;
+       crypto_session_id_t     cl_session;
+} crypto_logout32_t;
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_LOGIN                    CRYPTO(40)
+#define        CRYPTO_LOGOUT                   CRYPTO(41)
+
+/* flag for encrypt and decrypt operations */
+#define        CRYPTO_INPLACE_OPERATION        0x00000001
+
+/*
+ * Cryptographic Ioctls
+ */
+typedef struct crypto_encrypt {
+       uint_t                  ce_return_value;
+       crypto_session_id_t     ce_session;
+       size_t                  ce_datalen;
+       caddr_t                 ce_databuf;
+       size_t                  ce_encrlen;
+       caddr_t                 ce_encrbuf;
+       uint_t                  ce_flags;
+} crypto_encrypt_t;
+
+typedef struct crypto_encrypt_init {
+       uint_t                  ei_return_value;
+       crypto_session_id_t     ei_session;
+       crypto_mechanism_t      ei_mech;
+       crypto_key_t            ei_key;
+} crypto_encrypt_init_t;
+
+typedef struct crypto_encrypt_update {
+       uint_t                  eu_return_value;
+       crypto_session_id_t     eu_session;
+       size_t                  eu_datalen;
+       caddr_t                 eu_databuf;
+       size_t                  eu_encrlen;
+       caddr_t                 eu_encrbuf;
+} crypto_encrypt_update_t;
+
+typedef struct crypto_encrypt_final {
+       uint_t                  ef_return_value;
+       crypto_session_id_t     ef_session;
+       size_t                  ef_encrlen;
+       caddr_t                 ef_encrbuf;
+} crypto_encrypt_final_t;
+
+typedef struct crypto_decrypt {
+       uint_t                  cd_return_value;
+       crypto_session_id_t     cd_session;
+       size_t                  cd_encrlen;
+       caddr_t                 cd_encrbuf;
+       size_t                  cd_datalen;
+       caddr_t                 cd_databuf;
+       uint_t                  cd_flags;
+} crypto_decrypt_t;
+
+typedef struct crypto_decrypt_init {
+       uint_t                  di_return_value;
+       crypto_session_id_t     di_session;
+       crypto_mechanism_t      di_mech;
+       crypto_key_t            di_key;
+} crypto_decrypt_init_t;
+
+typedef struct crypto_decrypt_update {
+       uint_t                  du_return_value;
+       crypto_session_id_t     du_session;
+       size_t                  du_encrlen;
+       caddr_t                 du_encrbuf;
+       size_t                  du_datalen;
+       caddr_t                 du_databuf;
+} crypto_decrypt_update_t;
+
+typedef struct crypto_decrypt_final {
+       uint_t                  df_return_value;
+       crypto_session_id_t     df_session;
+       size_t                  df_datalen;
+       caddr_t                 df_databuf;
+} crypto_decrypt_final_t;
+
+typedef struct crypto_digest {
+       uint_t                  cd_return_value;
+       crypto_session_id_t     cd_session;
+       size_t                  cd_datalen;
+       caddr_t                 cd_databuf;
+       size_t                  cd_digestlen;
+       caddr_t                 cd_digestbuf;
+} crypto_digest_t;
+
+typedef struct crypto_digest_init {
+       uint_t                  di_return_value;
+       crypto_session_id_t     di_session;
+       crypto_mechanism_t      di_mech;
+} crypto_digest_init_t;
+
+typedef struct crypto_digest_update {
+       uint_t                  du_return_value;
+       crypto_session_id_t     du_session;
+       size_t                  du_datalen;
+       caddr_t                 du_databuf;
+} crypto_digest_update_t;
+
+typedef struct crypto_digest_key {
+       uint_t                  dk_return_value;
+       crypto_session_id_t     dk_session;
+       crypto_key_t            dk_key;
+} crypto_digest_key_t;
+
+typedef struct crypto_digest_final {
+       uint_t                  df_return_value;
+       crypto_session_id_t     df_session;
+       size_t                  df_digestlen;
+       caddr_t                 df_digestbuf;
+} crypto_digest_final_t;
+
+typedef struct crypto_mac {
+       uint_t                  cm_return_value;
+       crypto_session_id_t     cm_session;
+       size_t                  cm_datalen;
+       caddr_t                 cm_databuf;
+       size_t                  cm_maclen;
+       caddr_t                 cm_macbuf;
+} crypto_mac_t;
+
+typedef struct crypto_mac_init {
+       uint_t                  mi_return_value;
+       crypto_session_id_t     mi_session;
+       crypto_mechanism_t      mi_mech;
+       crypto_key_t            mi_key;
+} crypto_mac_init_t;
+
+typedef struct crypto_mac_update {
+       uint_t                  mu_return_value;
+       crypto_session_id_t     mu_session;
+       size_t                  mu_datalen;
+       caddr_t                 mu_databuf;
+} crypto_mac_update_t;
+
+typedef struct crypto_mac_final {
+       uint_t                  mf_return_value;
+       crypto_session_id_t     mf_session;
+       size_t                  mf_maclen;
+       caddr_t                 mf_macbuf;
+} crypto_mac_final_t;
+
+typedef struct crypto_sign {
+       uint_t                  cs_return_value;
+       crypto_session_id_t     cs_session;
+       size_t                  cs_datalen;
+       caddr_t                 cs_databuf;
+       size_t                  cs_signlen;
+       caddr_t                 cs_signbuf;
+} crypto_sign_t;
+
+typedef struct crypto_sign_init {
+       uint_t                  si_return_value;
+       crypto_session_id_t     si_session;
+       crypto_mechanism_t      si_mech;
+       crypto_key_t            si_key;
+} crypto_sign_init_t;
+
+typedef struct crypto_sign_update {
+       uint_t                  su_return_value;
+       crypto_session_id_t     su_session;
+       size_t                  su_datalen;
+       caddr_t                 su_databuf;
+} crypto_sign_update_t;
+
+typedef struct crypto_sign_final {
+       uint_t                  sf_return_value;
+       crypto_session_id_t     sf_session;
+       size_t                  sf_signlen;
+       caddr_t                 sf_signbuf;
+} crypto_sign_final_t;
+
+typedef struct crypto_sign_recover_init {
+       uint_t                  ri_return_value;
+       crypto_session_id_t     ri_session;
+       crypto_mechanism_t      ri_mech;
+       crypto_key_t            ri_key;
+} crypto_sign_recover_init_t;
+
+typedef struct crypto_sign_recover {
+       uint_t                  sr_return_value;
+       crypto_session_id_t     sr_session;
+       size_t                  sr_datalen;
+       caddr_t                 sr_databuf;
+       size_t                  sr_signlen;
+       caddr_t                 sr_signbuf;
+} crypto_sign_recover_t;
+
+typedef struct crypto_verify {
+       uint_t                  cv_return_value;
+       crypto_session_id_t     cv_session;
+       size_t                  cv_datalen;
+       caddr_t                 cv_databuf;
+       size_t                  cv_signlen;
+       caddr_t                 cv_signbuf;
+} crypto_verify_t;
+
+typedef struct crypto_verify_init {
+       uint_t                  vi_return_value;
+       crypto_session_id_t     vi_session;
+       crypto_mechanism_t      vi_mech;
+       crypto_key_t            vi_key;
+} crypto_verify_init_t;
+
+typedef struct crypto_verify_update {
+       uint_t                  vu_return_value;
+       crypto_session_id_t     vu_session;
+       size_t                  vu_datalen;
+       caddr_t                 vu_databuf;
+} crypto_verify_update_t;
+
+typedef struct crypto_verify_final {
+       uint_t                  vf_return_value;
+       crypto_session_id_t     vf_session;
+       size_t                  vf_signlen;
+       caddr_t                 vf_signbuf;
+} crypto_verify_final_t;
+
+typedef struct crypto_verify_recover_init {
+       uint_t                  ri_return_value;
+       crypto_session_id_t     ri_session;
+       crypto_mechanism_t      ri_mech;
+       crypto_key_t            ri_key;
+} crypto_verify_recover_init_t;
+
+typedef struct crypto_verify_recover {
+       uint_t                  vr_return_value;
+       crypto_session_id_t     vr_session;
+       size_t                  vr_signlen;
+       caddr_t                 vr_signbuf;
+       size_t                  vr_datalen;
+       caddr_t                 vr_databuf;
+} crypto_verify_recover_t;
+
+typedef struct crypto_digest_encrypt_update {
+       uint_t                  eu_return_value;
+       crypto_session_id_t     eu_session;
+       size_t                  eu_datalen;
+       caddr_t                 eu_databuf;
+       size_t                  eu_encrlen;
+       caddr_t                 eu_encrbuf;
+} crypto_digest_encrypt_update_t;
+
+typedef struct crypto_decrypt_digest_update {
+       uint_t                  du_return_value;
+       crypto_session_id_t     du_session;
+       size_t                  du_encrlen;
+       caddr_t                 du_encrbuf;
+       size_t                  du_datalen;
+       caddr_t                 du_databuf;
+} crypto_decrypt_digest_update_t;
+
+typedef struct crypto_sign_encrypt_update {
+       uint_t                  eu_return_value;
+       crypto_session_id_t     eu_session;
+       size_t                  eu_datalen;
+       caddr_t                 eu_databuf;
+       size_t                  eu_encrlen;
+       caddr_t                 eu_encrbuf;
+} crypto_sign_encrypt_update_t;
+
+typedef struct crypto_decrypt_verify_update {
+       uint_t                  vu_return_value;
+       crypto_session_id_t     vu_session;
+       size_t                  vu_encrlen;
+       caddr_t                 vu_encrbuf;
+       size_t                  vu_datalen;
+       caddr_t                 vu_databuf;
+} crypto_decrypt_verify_update_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+typedef struct crypto_encrypt32 {
+       uint32_t                ce_return_value;
+       crypto_session_id_t     ce_session;
+       size32_t                ce_datalen;
+       caddr32_t               ce_databuf;
+       size32_t                ce_encrlen;
+       caddr32_t               ce_encrbuf;
+       uint32_t                ce_flags;
+} crypto_encrypt32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_encrypt_init32 {
+       uint32_t                ei_return_value;
+       crypto_session_id_t     ei_session;
+       crypto_mechanism32_t    ei_mech;
+       crypto_key32_t          ei_key;
+} crypto_encrypt_init32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+typedef struct crypto_encrypt_update32 {
+       uint32_t                eu_return_value;
+       crypto_session_id_t     eu_session;
+       size32_t                eu_datalen;
+       caddr32_t               eu_databuf;
+       size32_t                eu_encrlen;
+       caddr32_t               eu_encrbuf;
+} crypto_encrypt_update32_t;
+
+typedef struct crypto_encrypt_final32 {
+       uint32_t                ef_return_value;
+       crypto_session_id_t     ef_session;
+       size32_t                ef_encrlen;
+       caddr32_t               ef_encrbuf;
+} crypto_encrypt_final32_t;
+
+typedef struct crypto_decrypt32 {
+       uint32_t                cd_return_value;
+       crypto_session_id_t     cd_session;
+       size32_t                cd_encrlen;
+       caddr32_t               cd_encrbuf;
+       size32_t                cd_datalen;
+       caddr32_t               cd_databuf;
+       uint32_t                cd_flags;
+} crypto_decrypt32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_decrypt_init32 {
+       uint32_t                di_return_value;
+       crypto_session_id_t     di_session;
+       crypto_mechanism32_t    di_mech;
+       crypto_key32_t          di_key;
+} crypto_decrypt_init32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+typedef struct crypto_decrypt_update32 {
+       uint32_t                du_return_value;
+       crypto_session_id_t     du_session;
+       size32_t                du_encrlen;
+       caddr32_t               du_encrbuf;
+       size32_t                du_datalen;
+       caddr32_t               du_databuf;
+} crypto_decrypt_update32_t;
+
+typedef struct crypto_decrypt_final32 {
+       uint32_t                df_return_value;
+       crypto_session_id_t     df_session;
+       size32_t                df_datalen;
+       caddr32_t               df_databuf;
+} crypto_decrypt_final32_t;
+
+typedef struct crypto_digest32 {
+       uint32_t                cd_return_value;
+       crypto_session_id_t     cd_session;
+       size32_t                cd_datalen;
+       caddr32_t               cd_databuf;
+       size32_t                cd_digestlen;
+       caddr32_t               cd_digestbuf;
+} crypto_digest32_t;
+
+typedef struct crypto_digest_init32 {
+       uint32_t                di_return_value;
+       crypto_session_id_t     di_session;
+       crypto_mechanism32_t    di_mech;
+} crypto_digest_init32_t;
+
+typedef struct crypto_digest_update32 {
+       uint32_t                du_return_value;
+       crypto_session_id_t     du_session;
+       size32_t                du_datalen;
+       caddr32_t               du_databuf;
+} crypto_digest_update32_t;
+
+typedef struct crypto_digest_key32 {
+       uint32_t                dk_return_value;
+       crypto_session_id_t     dk_session;
+       crypto_key32_t          dk_key;
+} crypto_digest_key32_t;
+
+typedef struct crypto_digest_final32 {
+       uint32_t                df_return_value;
+       crypto_session_id_t     df_session;
+       size32_t                df_digestlen;
+       caddr32_t               df_digestbuf;
+} crypto_digest_final32_t;
+
+typedef struct crypto_mac32 {
+       uint32_t                cm_return_value;
+       crypto_session_id_t     cm_session;
+       size32_t                cm_datalen;
+       caddr32_t               cm_databuf;
+       size32_t                cm_maclen;
+       caddr32_t               cm_macbuf;
+} crypto_mac32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_mac_init32 {
+       uint32_t                mi_return_value;
+       crypto_session_id_t     mi_session;
+       crypto_mechanism32_t    mi_mech;
+       crypto_key32_t          mi_key;
+} crypto_mac_init32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+typedef struct crypto_mac_update32 {
+       uint32_t                mu_return_value;
+       crypto_session_id_t     mu_session;
+       size32_t                mu_datalen;
+       caddr32_t               mu_databuf;
+} crypto_mac_update32_t;
+
+typedef struct crypto_mac_final32 {
+       uint32_t                mf_return_value;
+       crypto_session_id_t     mf_session;
+       size32_t                mf_maclen;
+       caddr32_t               mf_macbuf;
+} crypto_mac_final32_t;
+
+typedef struct crypto_sign32 {
+       uint32_t                cs_return_value;
+       crypto_session_id_t     cs_session;
+       size32_t                cs_datalen;
+       caddr32_t               cs_databuf;
+       size32_t                cs_signlen;
+       caddr32_t               cs_signbuf;
+} crypto_sign32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_sign_init32 {
+       uint32_t                si_return_value;
+       crypto_session_id_t     si_session;
+       crypto_mechanism32_t    si_mech;
+       crypto_key32_t          si_key;
+} crypto_sign_init32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+typedef struct crypto_sign_update32 {
+       uint32_t                su_return_value;
+       crypto_session_id_t     su_session;
+       size32_t                su_datalen;
+       caddr32_t               su_databuf;
+} crypto_sign_update32_t;
+
+typedef struct crypto_sign_final32 {
+       uint32_t                sf_return_value;
+       crypto_session_id_t     sf_session;
+       size32_t                sf_signlen;
+       caddr32_t               sf_signbuf;
+} crypto_sign_final32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_sign_recover_init32 {
+       uint32_t                ri_return_value;
+       crypto_session_id_t     ri_session;
+       crypto_mechanism32_t    ri_mech;
+       crypto_key32_t          ri_key;
+} crypto_sign_recover_init32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+typedef struct crypto_sign_recover32 {
+       uint32_t                sr_return_value;
+       crypto_session_id_t     sr_session;
+       size32_t                sr_datalen;
+       caddr32_t               sr_databuf;
+       size32_t                sr_signlen;
+       caddr32_t               sr_signbuf;
+} crypto_sign_recover32_t;
+
+typedef struct crypto_verify32 {
+       uint32_t                cv_return_value;
+       crypto_session_id_t     cv_session;
+       size32_t                cv_datalen;
+       caddr32_t               cv_databuf;
+       size32_t                cv_signlen;
+       caddr32_t               cv_signbuf;
+} crypto_verify32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_verify_init32 {
+       uint32_t                vi_return_value;
+       crypto_session_id_t     vi_session;
+       crypto_mechanism32_t    vi_mech;
+       crypto_key32_t          vi_key;
+} crypto_verify_init32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+typedef struct crypto_verify_update32 {
+       uint32_t                vu_return_value;
+       crypto_session_id_t     vu_session;
+       size32_t                vu_datalen;
+       caddr32_t               vu_databuf;
+} crypto_verify_update32_t;
+
+typedef struct crypto_verify_final32 {
+       uint32_t                vf_return_value;
+       crypto_session_id_t     vf_session;
+       size32_t                vf_signlen;
+       caddr32_t               vf_signbuf;
+} crypto_verify_final32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_verify_recover_init32 {
+       uint32_t                ri_return_value;
+       crypto_session_id_t     ri_session;
+       crypto_mechanism32_t    ri_mech;
+       crypto_key32_t          ri_key;
+} crypto_verify_recover_init32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+typedef struct crypto_verify_recover32 {
+       uint32_t                vr_return_value;
+       crypto_session_id_t     vr_session;
+       size32_t                vr_signlen;
+       caddr32_t               vr_signbuf;
+       size32_t                vr_datalen;
+       caddr32_t               vr_databuf;
+} crypto_verify_recover32_t;
+
+typedef struct crypto_digest_encrypt_update32 {
+       uint32_t                eu_return_value;
+       crypto_session_id_t     eu_session;
+       size32_t                eu_datalen;
+       caddr32_t               eu_databuf;
+       size32_t                eu_encrlen;
+       caddr32_t               eu_encrbuf;
+} crypto_digest_encrypt_update32_t;
+
+typedef struct crypto_decrypt_digest_update32 {
+       uint32_t                du_return_value;
+       crypto_session_id_t     du_session;
+       size32_t                du_encrlen;
+       caddr32_t               du_encrbuf;
+       size32_t                du_datalen;
+       caddr32_t               du_databuf;
+} crypto_decrypt_digest_update32_t;
+
+typedef struct crypto_sign_encrypt_update32 {
+       uint32_t                eu_return_value;
+       crypto_session_id_t     eu_session;
+       size32_t                eu_datalen;
+       caddr32_t               eu_databuf;
+       size32_t                eu_encrlen;
+       caddr32_t               eu_encrbuf;
+} crypto_sign_encrypt_update32_t;
+
+typedef struct crypto_decrypt_verify_update32 {
+       uint32_t                vu_return_value;
+       crypto_session_id_t     vu_session;
+       size32_t                vu_encrlen;
+       caddr32_t               vu_encrbuf;
+       size32_t                vu_datalen;
+       caddr32_t               vu_databuf;
+} crypto_decrypt_verify_update32_t;
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_ENCRYPT                  CRYPTO(50)
+#define        CRYPTO_ENCRYPT_INIT             CRYPTO(51)
+#define        CRYPTO_ENCRYPT_UPDATE           CRYPTO(52)
+#define        CRYPTO_ENCRYPT_FINAL            CRYPTO(53)
+#define        CRYPTO_DECRYPT                  CRYPTO(54)
+#define        CRYPTO_DECRYPT_INIT             CRYPTO(55)
+#define        CRYPTO_DECRYPT_UPDATE           CRYPTO(56)
+#define        CRYPTO_DECRYPT_FINAL            CRYPTO(57)
+
+#define        CRYPTO_DIGEST                   CRYPTO(58)
+#define        CRYPTO_DIGEST_INIT              CRYPTO(59)
+#define        CRYPTO_DIGEST_UPDATE            CRYPTO(60)
+#define        CRYPTO_DIGEST_KEY               CRYPTO(61)
+#define        CRYPTO_DIGEST_FINAL             CRYPTO(62)
+#define        CRYPTO_MAC                      CRYPTO(63)
+#define        CRYPTO_MAC_INIT                 CRYPTO(64)
+#define        CRYPTO_MAC_UPDATE               CRYPTO(65)
+#define        CRYPTO_MAC_FINAL                CRYPTO(66)
+
+#define        CRYPTO_SIGN                     CRYPTO(67)
+#define        CRYPTO_SIGN_INIT                CRYPTO(68)
+#define        CRYPTO_SIGN_UPDATE              CRYPTO(69)
+#define        CRYPTO_SIGN_FINAL               CRYPTO(70)
+#define        CRYPTO_SIGN_RECOVER_INIT        CRYPTO(71)
+#define        CRYPTO_SIGN_RECOVER             CRYPTO(72)
+#define        CRYPTO_VERIFY                   CRYPTO(73)
+#define        CRYPTO_VERIFY_INIT              CRYPTO(74)
+#define        CRYPTO_VERIFY_UPDATE            CRYPTO(75)
+#define        CRYPTO_VERIFY_FINAL             CRYPTO(76)
+#define        CRYPTO_VERIFY_RECOVER_INIT      CRYPTO(77)
+#define        CRYPTO_VERIFY_RECOVER           CRYPTO(78)
+
+#define        CRYPTO_DIGEST_ENCRYPT_UPDATE    CRYPTO(79)
+#define        CRYPTO_DECRYPT_DIGEST_UPDATE    CRYPTO(80)
+#define        CRYPTO_SIGN_ENCRYPT_UPDATE      CRYPTO(81)
+#define        CRYPTO_DECRYPT_VERIFY_UPDATE    CRYPTO(82)
+
+/*
+ * Random Number Ioctls
+ */
+typedef struct crypto_seed_random {
+       uint_t                  sr_return_value;
+       crypto_session_id_t     sr_session;
+       size_t                  sr_seedlen;
+       caddr_t                 sr_seedbuf;
+} crypto_seed_random_t;
+
+typedef struct crypto_generate_random {
+       uint_t                  gr_return_value;
+       crypto_session_id_t     gr_session;
+       caddr_t                 gr_buf;
+       size_t                  gr_buflen;
+} crypto_generate_random_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+typedef struct crypto_seed_random32 {
+       uint32_t                sr_return_value;
+       crypto_session_id_t     sr_session;
+       size32_t                sr_seedlen;
+       caddr32_t               sr_seedbuf;
+} crypto_seed_random32_t;
+
+typedef struct crypto_generate_random32 {
+       uint32_t                gr_return_value;
+       crypto_session_id_t     gr_session;
+       caddr32_t               gr_buf;
+       size32_t                gr_buflen;
+} crypto_generate_random32_t;
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_SEED_RANDOM              CRYPTO(90)
+#define        CRYPTO_GENERATE_RANDOM          CRYPTO(91)
+
+/*
+ * Object Management Ioctls
+ */
+typedef struct crypto_object_create {
+       uint_t                  oc_return_value;
+       crypto_session_id_t     oc_session;
+       crypto_object_id_t      oc_handle;
+       uint_t                  oc_count;
+       caddr_t                 oc_attributes;
+} crypto_object_create_t;
+
+typedef struct crypto_object_copy {
+       uint_t                  oc_return_value;
+       crypto_session_id_t     oc_session;
+       crypto_object_id_t      oc_handle;
+       crypto_object_id_t      oc_new_handle;
+       uint_t                  oc_count;
+       caddr_t                 oc_new_attributes;
+} crypto_object_copy_t;
+
+typedef struct crypto_object_destroy {
+       uint_t                  od_return_value;
+       crypto_session_id_t     od_session;
+       crypto_object_id_t      od_handle;
+} crypto_object_destroy_t;
+
+typedef struct crypto_object_get_attribute_value {
+       uint_t                  og_return_value;
+       crypto_session_id_t     og_session;
+       crypto_object_id_t      og_handle;
+       uint_t                  og_count;
+       caddr_t                 og_attributes;
+} crypto_object_get_attribute_value_t;
+
+typedef struct crypto_object_get_size {
+       uint_t                  gs_return_value;
+       crypto_session_id_t     gs_session;
+       crypto_object_id_t      gs_handle;
+       size_t                  gs_size;
+} crypto_object_get_size_t;
+
+typedef struct crypto_object_set_attribute_value {
+       uint_t                  sa_return_value;
+       crypto_session_id_t     sa_session;
+       crypto_object_id_t      sa_handle;
+       uint_t                  sa_count;
+       caddr_t                 sa_attributes;
+} crypto_object_set_attribute_value_t;
+
+typedef struct crypto_object_find_init {
+       uint_t                  fi_return_value;
+       crypto_session_id_t     fi_session;
+       uint_t                  fi_count;
+       caddr_t                 fi_attributes;
+} crypto_object_find_init_t;
+
+typedef struct crypto_object_find_update {
+       uint_t                  fu_return_value;
+       crypto_session_id_t     fu_session;
+       uint_t                  fu_max_count;
+       uint_t                  fu_count;
+       caddr_t                 fu_handles;
+} crypto_object_find_update_t;
+
+typedef struct crypto_object_find_final {
+       uint_t                  ff_return_value;
+       crypto_session_id_t     ff_session;
+} crypto_object_find_final_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+typedef struct crypto_object_create32 {
+       uint32_t                oc_return_value;
+       crypto_session_id_t     oc_session;
+       crypto_object_id_t      oc_handle;
+       uint32_t                oc_count;
+       caddr32_t               oc_attributes;
+} crypto_object_create32_t;
+
+typedef struct crypto_object_copy32 {
+       uint32_t                oc_return_value;
+       crypto_session_id_t     oc_session;
+       crypto_object_id_t      oc_handle;
+       crypto_object_id_t      oc_new_handle;
+       uint32_t                oc_count;
+       caddr32_t               oc_new_attributes;
+} crypto_object_copy32_t;
+
+typedef struct crypto_object_destroy32 {
+       uint32_t                od_return_value;
+       crypto_session_id_t     od_session;
+       crypto_object_id_t      od_handle;
+} crypto_object_destroy32_t;
+
+typedef struct crypto_object_get_attribute_value32 {
+       uint32_t                og_return_value;
+       crypto_session_id_t     og_session;
+       crypto_object_id_t      og_handle;
+       uint32_t                og_count;
+       caddr32_t               og_attributes;
+} crypto_object_get_attribute_value32_t;
+
+typedef struct crypto_object_get_size32 {
+       uint32_t                gs_return_value;
+       crypto_session_id_t     gs_session;
+       crypto_object_id_t      gs_handle;
+       size32_t                gs_size;
+} crypto_object_get_size32_t;
+
+typedef struct crypto_object_set_attribute_value32 {
+       uint32_t                sa_return_value;
+       crypto_session_id_t     sa_session;
+       crypto_object_id_t      sa_handle;
+       uint32_t                sa_count;
+       caddr32_t               sa_attributes;
+} crypto_object_set_attribute_value32_t;
+
+typedef struct crypto_object_find_init32 {
+       uint32_t                fi_return_value;
+       crypto_session_id_t     fi_session;
+       uint32_t                fi_count;
+       caddr32_t               fi_attributes;
+} crypto_object_find_init32_t;
+
+typedef struct crypto_object_find_update32 {
+       uint32_t                fu_return_value;
+       crypto_session_id_t     fu_session;
+       uint32_t                fu_max_count;
+       uint32_t                fu_count;
+       caddr32_t               fu_handles;
+} crypto_object_find_update32_t;
+
+typedef struct crypto_object_find_final32 {
+       uint32_t                ff_return_value;
+       crypto_session_id_t     ff_session;
+} crypto_object_find_final32_t;
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_OBJECT_CREATE                    CRYPTO(100)
+#define        CRYPTO_OBJECT_COPY                      CRYPTO(101)
+#define        CRYPTO_OBJECT_DESTROY                   CRYPTO(102)
+#define        CRYPTO_OBJECT_GET_ATTRIBUTE_VALUE       CRYPTO(103)
+#define        CRYPTO_OBJECT_GET_SIZE                  CRYPTO(104)
+#define        CRYPTO_OBJECT_SET_ATTRIBUTE_VALUE       CRYPTO(105)
+#define        CRYPTO_OBJECT_FIND_INIT                 CRYPTO(106)
+#define        CRYPTO_OBJECT_FIND_UPDATE               CRYPTO(107)
+#define        CRYPTO_OBJECT_FIND_FINAL                CRYPTO(108)
+
+/*
+ * Key Generation Ioctls
+ */
+typedef struct crypto_object_generate_key {
+       uint_t                  gk_return_value;
+       crypto_session_id_t     gk_session;
+       crypto_object_id_t      gk_handle;
+       crypto_mechanism_t      gk_mechanism;
+       uint_t                  gk_count;
+       caddr_t                 gk_attributes;
+} crypto_object_generate_key_t;
+
+typedef struct crypto_object_generate_key_pair {
+       uint_t                  kp_return_value;
+       crypto_session_id_t     kp_session;
+       crypto_object_id_t      kp_public_handle;
+       crypto_object_id_t      kp_private_handle;
+       uint_t                  kp_public_count;
+       uint_t                  kp_private_count;
+       caddr_t                 kp_public_attributes;
+       caddr_t                 kp_private_attributes;
+       crypto_mechanism_t      kp_mechanism;
+} crypto_object_generate_key_pair_t;
+
+typedef struct crypto_object_wrap_key {
+       uint_t                  wk_return_value;
+       crypto_session_id_t     wk_session;
+       crypto_mechanism_t      wk_mechanism;
+       crypto_key_t            wk_wrapping_key;
+       crypto_object_id_t      wk_object_handle;
+       size_t                  wk_wrapped_key_len;
+       caddr_t                 wk_wrapped_key;
+} crypto_object_wrap_key_t;
+
+typedef struct crypto_object_unwrap_key {
+       uint_t                  uk_return_value;
+       crypto_session_id_t     uk_session;
+       crypto_mechanism_t      uk_mechanism;
+       crypto_key_t            uk_unwrapping_key;
+       crypto_object_id_t      uk_object_handle;
+       size_t                  uk_wrapped_key_len;
+       caddr_t                 uk_wrapped_key;
+       uint_t                  uk_count;
+       caddr_t                 uk_attributes;
+} crypto_object_unwrap_key_t;
+
+typedef struct crypto_derive_key {
+       uint_t                  dk_return_value;
+       crypto_session_id_t     dk_session;
+       crypto_mechanism_t      dk_mechanism;
+       crypto_key_t            dk_base_key;
+       crypto_object_id_t      dk_object_handle;
+       uint_t                  dk_count;
+       caddr_t                 dk_attributes;
+} crypto_derive_key_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_object_generate_key32 {
+       uint32_t                gk_return_value;
+       crypto_session_id_t     gk_session;
+       crypto_object_id_t      gk_handle;
+       crypto_mechanism32_t    gk_mechanism;
+       uint32_t                gk_count;
+       caddr32_t               gk_attributes;
+} crypto_object_generate_key32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+typedef struct crypto_object_generate_key_pair32 {
+       uint32_t                kp_return_value;
+       crypto_session_id_t     kp_session;
+       crypto_object_id_t      kp_public_handle;
+       crypto_object_id_t      kp_private_handle;
+       uint32_t                kp_public_count;
+       uint32_t                kp_private_count;
+       caddr32_t               kp_public_attributes;
+       caddr32_t               kp_private_attributes;
+       crypto_mechanism32_t    kp_mechanism;
+} crypto_object_generate_key_pair32_t;
+
+typedef struct crypto_object_wrap_key32 {
+       uint32_t                wk_return_value;
+       crypto_session_id_t     wk_session;
+       crypto_mechanism32_t    wk_mechanism;
+       crypto_key32_t          wk_wrapping_key;
+       crypto_object_id_t      wk_object_handle;
+       size32_t                wk_wrapped_key_len;
+       caddr32_t               wk_wrapped_key;
+} crypto_object_wrap_key32_t;
+
+typedef struct crypto_object_unwrap_key32 {
+       uint32_t                uk_return_value;
+       crypto_session_id_t     uk_session;
+       crypto_mechanism32_t    uk_mechanism;
+       crypto_key32_t          uk_unwrapping_key;
+       crypto_object_id_t      uk_object_handle;
+       size32_t                uk_wrapped_key_len;
+       caddr32_t               uk_wrapped_key;
+       uint32_t                uk_count;
+       caddr32_t               uk_attributes;
+} crypto_object_unwrap_key32_t;
+
+typedef struct crypto_derive_key32 {
+       uint32_t                dk_return_value;
+       crypto_session_id_t     dk_session;
+       crypto_mechanism32_t    dk_mechanism;
+       crypto_key32_t          dk_base_key;
+       crypto_object_id_t      dk_object_handle;
+       uint32_t                dk_count;
+       caddr32_t               dk_attributes;
+} crypto_derive_key32_t;
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_GENERATE_KEY             CRYPTO(110)
+#define        CRYPTO_GENERATE_KEY_PAIR        CRYPTO(111)
+#define        CRYPTO_WRAP_KEY                 CRYPTO(112)
+#define        CRYPTO_UNWRAP_KEY               CRYPTO(113)
+#define        CRYPTO_DERIVE_KEY               CRYPTO(114)
+
+/*
+ * Provider Management Ioctls
+ */
+
+typedef struct crypto_get_provider_list {
+       uint_t                  pl_return_value;
+       uint_t                  pl_count;
+       crypto_provider_entry_t pl_list[1];
+} crypto_get_provider_list_t;
+
+typedef struct crypto_provider_data {
+       uchar_t                 pd_prov_desc[CRYPTO_PROVIDER_DESCR_MAX_LEN];
+       uchar_t                 pd_label[CRYPTO_EXT_SIZE_LABEL];
+       uchar_t                 pd_manufacturerID[CRYPTO_EXT_SIZE_MANUF];
+       uchar_t                 pd_model[CRYPTO_EXT_SIZE_MODEL];
+       uchar_t                 pd_serial_number[CRYPTO_EXT_SIZE_SERIAL];
+       ulong_t                 pd_flags;
+       ulong_t                 pd_max_session_count;
+       ulong_t                 pd_session_count;
+       ulong_t                 pd_max_rw_session_count;
+       ulong_t                 pd_rw_session_count;
+       ulong_t                 pd_max_pin_len;
+       ulong_t                 pd_min_pin_len;
+       ulong_t                 pd_total_public_memory;
+       ulong_t                 pd_free_public_memory;
+       ulong_t                 pd_total_private_memory;
+       ulong_t                 pd_free_private_memory;
+       crypto_version_t        pd_hardware_version;
+       crypto_version_t        pd_firmware_version;
+       uchar_t                 pd_time[CRYPTO_EXT_SIZE_TIME];
+} crypto_provider_data_t;
+
+typedef struct crypto_get_provider_info {
+       uint_t                  gi_return_value;
+       crypto_provider_id_t    gi_provider_id;
+       crypto_provider_data_t  gi_provider_data;
+} crypto_get_provider_info_t;
+
+typedef struct crypto_get_provider_mechanisms {
+       uint_t                  pm_return_value;
+       crypto_provider_id_t    pm_provider_id;
+       uint_t                  pm_count;
+       crypto_mech_name_t      pm_list[1];
+} crypto_get_provider_mechanisms_t;
+
+typedef struct crypto_get_provider_mechanism_info {
+       uint_t                  mi_return_value;
+       crypto_provider_id_t    mi_provider_id;
+       crypto_mech_name_t      mi_mechanism_name;
+       uint32_t                mi_min_key_size;
+       uint32_t                mi_max_key_size;
+       uint32_t                mi_flags;
+} crypto_get_provider_mechanism_info_t;
+
+typedef struct crypto_init_token {
+       uint_t                  it_return_value;
+       crypto_provider_id_t    it_provider_id;
+       caddr_t                 it_pin;
+       size_t                  it_pin_len;
+       caddr_t                 it_label;
+} crypto_init_token_t;
+
+typedef struct crypto_init_pin {
+       uint_t                  ip_return_value;
+       crypto_session_id_t     ip_session;
+       caddr_t                 ip_pin;
+       size_t                  ip_pin_len;
+} crypto_init_pin_t;
+
+typedef struct crypto_set_pin {
+       uint_t                  sp_return_value;
+       crypto_session_id_t     sp_session;
+       caddr_t                 sp_old_pin;
+       size_t                  sp_old_len;
+       caddr_t                 sp_new_pin;
+       size_t                  sp_new_len;
+} crypto_set_pin_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+typedef struct crypto_get_provider_list32 {
+       uint32_t                pl_return_value;
+       uint32_t                pl_count;
+       crypto_provider_entry_t pl_list[1];
+} crypto_get_provider_list32_t;
+
+typedef struct crypto_version32 {
+       uchar_t cv_major;
+       uchar_t cv_minor;
+} crypto_version32_t;
+
+typedef struct crypto_provider_data32 {
+       uchar_t                 pd_prov_desc[CRYPTO_PROVIDER_DESCR_MAX_LEN];
+       uchar_t                 pd_label[CRYPTO_EXT_SIZE_LABEL];
+       uchar_t                 pd_manufacturerID[CRYPTO_EXT_SIZE_MANUF];
+       uchar_t                 pd_model[CRYPTO_EXT_SIZE_MODEL];
+       uchar_t                 pd_serial_number[CRYPTO_EXT_SIZE_SERIAL];
+       uint32_t                pd_flags;
+       uint32_t                pd_max_session_count;
+       uint32_t                pd_session_count;
+       uint32_t                pd_max_rw_session_count;
+       uint32_t                pd_rw_session_count;
+       uint32_t                pd_max_pin_len;
+       uint32_t                pd_min_pin_len;
+       uint32_t                pd_total_public_memory;
+       uint32_t                pd_free_public_memory;
+       uint32_t                pd_total_private_memory;
+       uint32_t                pd_free_private_memory;
+       crypto_version32_t      pd_hardware_version;
+       crypto_version32_t      pd_firmware_version;
+       uchar_t                 pd_time[CRYPTO_EXT_SIZE_TIME];
+} crypto_provider_data32_t;
+
+typedef struct crypto_get_provider_info32 {
+       uint32_t                gi_return_value;
+       crypto_provider_id_t    gi_provider_id;
+       crypto_provider_data32_t gi_provider_data;
+} crypto_get_provider_info32_t;
+
+typedef struct crypto_get_provider_mechanisms32 {
+       uint32_t                pm_return_value;
+       crypto_provider_id_t    pm_provider_id;
+       uint32_t                pm_count;
+       crypto_mech_name_t      pm_list[1];
+} crypto_get_provider_mechanisms32_t;
+
+typedef struct crypto_init_token32 {
+       uint32_t                it_return_value;
+       crypto_provider_id_t    it_provider_id;
+       caddr32_t               it_pin;
+       size32_t                it_pin_len;
+       caddr32_t               it_label;
+} crypto_init_token32_t;
+
+typedef struct crypto_init_pin32 {
+       uint32_t                ip_return_value;
+       crypto_session_id_t     ip_session;
+       caddr32_t               ip_pin;
+       size32_t                ip_pin_len;
+} crypto_init_pin32_t;
+
+typedef struct crypto_set_pin32 {
+       uint32_t                sp_return_value;
+       crypto_session_id_t     sp_session;
+       caddr32_t               sp_old_pin;
+       size32_t                sp_old_len;
+       caddr32_t               sp_new_pin;
+       size32_t                sp_new_len;
+} crypto_set_pin32_t;
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_GET_PROVIDER_LIST                CRYPTO(120)
+#define        CRYPTO_GET_PROVIDER_INFO                CRYPTO(121)
+#define        CRYPTO_GET_PROVIDER_MECHANISMS          CRYPTO(122)
+#define        CRYPTO_GET_PROVIDER_MECHANISM_INFO      CRYPTO(123)
+#define        CRYPTO_INIT_TOKEN                       CRYPTO(124)
+#define        CRYPTO_INIT_PIN                         CRYPTO(125)
+#define        CRYPTO_SET_PIN                          CRYPTO(126)
+
+/*
+ * No (Key) Store Key Generation Ioctls
+ */
+typedef struct crypto_nostore_generate_key {
+       uint_t                  ngk_return_value;
+       crypto_session_id_t     ngk_session;
+       crypto_mechanism_t      ngk_mechanism;
+       uint_t                  ngk_in_count;
+       uint_t                  ngk_out_count;
+       caddr_t                 ngk_in_attributes;
+       caddr_t                 ngk_out_attributes;
+} crypto_nostore_generate_key_t;
+
+typedef struct crypto_nostore_generate_key_pair {
+       uint_t                  nkp_return_value;
+       crypto_session_id_t     nkp_session;
+       uint_t                  nkp_in_public_count;
+       uint_t                  nkp_in_private_count;
+       uint_t                  nkp_out_public_count;
+       uint_t                  nkp_out_private_count;
+       caddr_t                 nkp_in_public_attributes;
+       caddr_t                 nkp_in_private_attributes;
+       caddr_t                 nkp_out_public_attributes;
+       caddr_t                 nkp_out_private_attributes;
+       crypto_mechanism_t      nkp_mechanism;
+} crypto_nostore_generate_key_pair_t;
+
+typedef struct crypto_nostore_derive_key {
+       uint_t                  ndk_return_value;
+       crypto_session_id_t     ndk_session;
+       crypto_mechanism_t      ndk_mechanism;
+       crypto_key_t            ndk_base_key;
+       uint_t                  ndk_in_count;
+       uint_t                  ndk_out_count;
+       caddr_t                 ndk_in_attributes;
+       caddr_t                 ndk_out_attributes;
+} crypto_nostore_derive_key_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+typedef struct crypto_nostore_generate_key32 {
+       uint32_t                ngk_return_value;
+       crypto_session_id_t     ngk_session;
+       crypto_mechanism32_t    ngk_mechanism;
+       uint32_t                ngk_in_count;
+       uint32_t                ngk_out_count;
+       caddr32_t               ngk_in_attributes;
+       caddr32_t               ngk_out_attributes;
+} crypto_nostore_generate_key32_t;
+
+typedef struct crypto_nostore_generate_key_pair32 {
+       uint32_t                nkp_return_value;
+       crypto_session_id_t     nkp_session;
+       uint32_t                nkp_in_public_count;
+       uint32_t                nkp_in_private_count;
+       uint32_t                nkp_out_public_count;
+       uint32_t                nkp_out_private_count;
+       caddr32_t               nkp_in_public_attributes;
+       caddr32_t               nkp_in_private_attributes;
+       caddr32_t               nkp_out_public_attributes;
+       caddr32_t               nkp_out_private_attributes;
+       crypto_mechanism32_t    nkp_mechanism;
+} crypto_nostore_generate_key_pair32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack(4)
+#endif
+
+typedef struct crypto_nostore_derive_key32 {
+       uint32_t                ndk_return_value;
+       crypto_session_id_t     ndk_session;
+       crypto_mechanism32_t    ndk_mechanism;
+       crypto_key32_t          ndk_base_key;
+       uint32_t                ndk_in_count;
+       uint32_t                ndk_out_count;
+       caddr32_t               ndk_in_attributes;
+       caddr32_t               ndk_out_attributes;
+} crypto_nostore_derive_key32_t;
+
+#if _LONG_LONG_ALIGNMENT == 8 && _LONG_LONG_ALIGNMENT_32 == 4
+#pragma pack()
+#endif
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_NOSTORE_GENERATE_KEY             CRYPTO(127)
+#define        CRYPTO_NOSTORE_GENERATE_KEY_PAIR        CRYPTO(128)
+#define        CRYPTO_NOSTORE_DERIVE_KEY               CRYPTO(129)
+
+/*
+ * Mechanism Ioctls
+ */
+
+typedef struct crypto_get_mechanism_list {
+       uint_t                  ml_return_value;
+       uint_t                  ml_count;
+       crypto_mech_name_t      ml_list[1];
+} crypto_get_mechanism_list_t;
+
+typedef struct crypto_get_all_mechanism_info {
+       uint_t                  mi_return_value;
+       crypto_mech_name_t      mi_mechanism_name;
+       uint_t                  mi_count;
+       crypto_mechanism_info_t mi_list[1];
+} crypto_get_all_mechanism_info_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+typedef struct crypto_get_mechanism_list32 {
+       uint32_t                ml_return_value;
+       uint32_t                ml_count;
+       crypto_mech_name_t      ml_list[1];
+} crypto_get_mechanism_list32_t;
+
+typedef struct crypto_get_all_mechanism_info32 {
+       uint32_t                mi_return_value;
+       crypto_mech_name_t      mi_mechanism_name;
+       uint32_t                mi_count;
+       crypto_mechanism_info32_t mi_list[1];
+} crypto_get_all_mechanism_info32_t;
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_GET_MECHANISM_LIST               CRYPTO(140)
+#define        CRYPTO_GET_ALL_MECHANISM_INFO           CRYPTO(141)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_IOCTL_H */
diff --git a/zfs/module/icp/include/sys/crypto/ioctladmin.h b/zfs/module/icp/include/sys/crypto/ioctladmin.h
new file mode 100644 (file)
index 0000000..24babd7
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SYS_CRYPTO_IOCTLADMIN_H
+#define        _SYS_CRYPTO_IOCTLADMIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+
+#define        ADMIN_IOCTL_DEVICE      "/dev/cryptoadm"
+
+#define        CRYPTOADMIN(x)          (('y' << 8) | (x))
+
+/*
+ * Administrative IOCTLs
+ */
+
+typedef struct crypto_get_dev_list {
+       uint_t                  dl_return_value;
+       uint_t                  dl_dev_count;
+       crypto_dev_list_entry_t dl_devs[1];
+} crypto_get_dev_list_t;
+
+typedef struct crypto_get_soft_list {
+       uint_t                  sl_return_value;
+       uint_t                  sl_soft_count;
+       size_t                  sl_soft_len;
+       caddr_t                 sl_soft_names;
+} crypto_get_soft_list_t;
+
+typedef struct crypto_get_dev_info {
+       uint_t                  di_return_value;
+       char                    di_dev_name[MAXNAMELEN];
+       uint_t                  di_dev_instance;
+       uint_t                  di_count;
+       crypto_mech_name_t      di_list[1];
+} crypto_get_dev_info_t;
+
+typedef struct crypto_get_soft_info {
+       uint_t                  si_return_value;
+       char                    si_name[MAXNAMELEN];
+       uint_t                  si_count;
+       crypto_mech_name_t      si_list[1];
+} crypto_get_soft_info_t;
+
+typedef struct crypto_load_dev_disabled {
+       uint_t                  dd_return_value;
+       char                    dd_dev_name[MAXNAMELEN];
+       uint_t                  dd_dev_instance;
+       uint_t                  dd_count;
+       crypto_mech_name_t      dd_list[1];
+} crypto_load_dev_disabled_t;
+
+typedef struct crypto_load_soft_disabled {
+       uint_t                  sd_return_value;
+       char                    sd_name[MAXNAMELEN];
+       uint_t                  sd_count;
+       crypto_mech_name_t      sd_list[1];
+} crypto_load_soft_disabled_t;
+
+typedef struct crypto_unload_soft_module {
+       uint_t                  sm_return_value;
+       char                    sm_name[MAXNAMELEN];
+} crypto_unload_soft_module_t;
+
+typedef struct crypto_load_soft_config {
+       uint_t                  sc_return_value;
+       char                    sc_name[MAXNAMELEN];
+       uint_t                  sc_count;
+       crypto_mech_name_t      sc_list[1];
+} crypto_load_soft_config_t;
+
+typedef struct crypto_load_door {
+       uint_t                  ld_return_value;
+       uint_t                  ld_did;
+} crypto_load_door_t;
+
+#ifdef _KERNEL
+#ifdef _SYSCALL32
+
+typedef struct crypto_get_soft_list32 {
+       uint32_t                sl_return_value;
+       uint32_t                sl_soft_count;
+       size32_t                sl_soft_len;
+       caddr32_t               sl_soft_names;
+} crypto_get_soft_list32_t;
+
+#endif /* _SYSCALL32 */
+#endif /* _KERNEL */
+
+#define        CRYPTO_GET_VERSION              CRYPTOADMIN(1)
+#define        CRYPTO_GET_DEV_LIST             CRYPTOADMIN(2)
+#define        CRYPTO_GET_SOFT_LIST            CRYPTOADMIN(3)
+#define        CRYPTO_GET_DEV_INFO             CRYPTOADMIN(4)
+#define        CRYPTO_GET_SOFT_INFO            CRYPTOADMIN(5)
+#define        CRYPTO_LOAD_DEV_DISABLED        CRYPTOADMIN(8)
+#define        CRYPTO_LOAD_SOFT_DISABLED       CRYPTOADMIN(9)
+#define        CRYPTO_UNLOAD_SOFT_MODULE       CRYPTOADMIN(10)
+#define        CRYPTO_LOAD_SOFT_CONFIG         CRYPTOADMIN(11)
+#define        CRYPTO_POOL_CREATE              CRYPTOADMIN(12)
+#define        CRYPTO_POOL_WAIT                CRYPTOADMIN(13)
+#define        CRYPTO_POOL_RUN                 CRYPTOADMIN(14)
+#define        CRYPTO_LOAD_DOOR                CRYPTOADMIN(15)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_IOCTLADMIN_H */
diff --git a/zfs/module/icp/include/sys/crypto/ops_impl.h b/zfs/module/icp/include/sys/crypto/ops_impl.h
new file mode 100644 (file)
index 0000000..230d74b
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_CRYPTO_OPS_IMPL_H
+#define        _SYS_CRYPTO_OPS_IMPL_H
+
+/*
+ * Scheduler internal structures.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/common.h>
+
+/*
+ * The parameters needed for each function group are batched
+ * in one structure. This is much simpler than having a
+ * separate structure for each function.
+ *
+ * In some cases, a field is generically named to keep the
+ * structure small. The comments indicate these cases.
+ */
+typedef struct kcf_digest_ops_params {
+       crypto_session_id_t     do_sid;
+       crypto_mech_type_t      do_framework_mechtype;
+       crypto_mechanism_t      do_mech;
+       crypto_data_t           *do_data;
+       crypto_data_t           *do_digest;
+       crypto_key_t            *do_digest_key; /* Argument for digest_key() */
+} kcf_digest_ops_params_t;
+
+typedef struct kcf_mac_ops_params {
+       crypto_session_id_t             mo_sid;
+       crypto_mech_type_t              mo_framework_mechtype;
+       crypto_mechanism_t              mo_mech;
+       crypto_key_t                    *mo_key;
+       crypto_data_t                   *mo_data;
+       crypto_data_t                   *mo_mac;
+       crypto_spi_ctx_template_t       mo_templ;
+} kcf_mac_ops_params_t;
+
+typedef struct kcf_encrypt_ops_params {
+       crypto_session_id_t             eo_sid;
+       crypto_mech_type_t              eo_framework_mechtype;
+       crypto_mechanism_t              eo_mech;
+       crypto_key_t                    *eo_key;
+       crypto_data_t                   *eo_plaintext;
+       crypto_data_t                   *eo_ciphertext;
+       crypto_spi_ctx_template_t       eo_templ;
+} kcf_encrypt_ops_params_t;
+
+typedef struct kcf_decrypt_ops_params {
+       crypto_session_id_t             dop_sid;
+       crypto_mech_type_t              dop_framework_mechtype;
+       crypto_mechanism_t              dop_mech;
+       crypto_key_t                    *dop_key;
+       crypto_data_t                   *dop_ciphertext;
+       crypto_data_t                   *dop_plaintext;
+       crypto_spi_ctx_template_t       dop_templ;
+} kcf_decrypt_ops_params_t;
+
+typedef struct kcf_sign_ops_params {
+       crypto_session_id_t             so_sid;
+       crypto_mech_type_t              so_framework_mechtype;
+       crypto_mechanism_t              so_mech;
+       crypto_key_t                    *so_key;
+       crypto_data_t                   *so_data;
+       crypto_data_t                   *so_signature;
+       crypto_spi_ctx_template_t       so_templ;
+} kcf_sign_ops_params_t;
+
+typedef struct kcf_verify_ops_params {
+       crypto_session_id_t             vo_sid;
+       crypto_mech_type_t              vo_framework_mechtype;
+       crypto_mechanism_t              vo_mech;
+       crypto_key_t                    *vo_key;
+       crypto_data_t                   *vo_data;
+       crypto_data_t                   *vo_signature;
+       crypto_spi_ctx_template_t       vo_templ;
+} kcf_verify_ops_params_t;
+
+typedef struct kcf_encrypt_mac_ops_params {
+       crypto_session_id_t             em_sid;
+       crypto_mech_type_t              em_framework_encr_mechtype;
+       crypto_mechanism_t              em_encr_mech;
+       crypto_key_t                    *em_encr_key;
+       crypto_mech_type_t              em_framework_mac_mechtype;
+       crypto_mechanism_t              em_mac_mech;
+       crypto_key_t                    *em_mac_key;
+       crypto_data_t                   *em_plaintext;
+       crypto_dual_data_t              *em_ciphertext;
+       crypto_data_t                   *em_mac;
+       crypto_spi_ctx_template_t       em_encr_templ;
+       crypto_spi_ctx_template_t       em_mac_templ;
+} kcf_encrypt_mac_ops_params_t;
+
+typedef struct kcf_mac_decrypt_ops_params {
+       crypto_session_id_t             md_sid;
+       crypto_mech_type_t              md_framework_mac_mechtype;
+       crypto_mechanism_t              md_mac_mech;
+       crypto_key_t                    *md_mac_key;
+       crypto_mech_type_t              md_framework_decr_mechtype;
+       crypto_mechanism_t              md_decr_mech;
+       crypto_key_t                    *md_decr_key;
+       crypto_dual_data_t              *md_ciphertext;
+       crypto_data_t                   *md_mac;
+       crypto_data_t                   *md_plaintext;
+       crypto_spi_ctx_template_t       md_mac_templ;
+       crypto_spi_ctx_template_t       md_decr_templ;
+} kcf_mac_decrypt_ops_params_t;
+
+typedef struct kcf_random_number_ops_params {
+       crypto_session_id_t     rn_sid;
+       uchar_t                 *rn_buf;
+       size_t                  rn_buflen;
+       uint_t                  rn_entropy_est;
+       uint32_t                rn_flags;
+} kcf_random_number_ops_params_t;
+
+/*
+ * so_pd is useful when the provider descriptor (pd) supplying the
+ * provider handle is different from the pd supplying the ops vector.
+ * This is the case for session open/close where so_pd can be the pd
+ * of a logical provider. The pd supplying the ops vector is passed
+ * as an argument to kcf_submit_request().
+ */
+typedef struct kcf_session_ops_params {
+       crypto_session_id_t     *so_sid_ptr;
+       crypto_session_id_t     so_sid;
+       crypto_user_type_t      so_user_type;
+       char                    *so_pin;
+       size_t                  so_pin_len;
+       kcf_provider_desc_t     *so_pd;
+} kcf_session_ops_params_t;
+
+typedef struct kcf_object_ops_params {
+       crypto_session_id_t             oo_sid;
+       crypto_object_id_t              oo_object_id;
+       crypto_object_attribute_t       *oo_template;
+       uint_t                          oo_attribute_count;
+       crypto_object_id_t              *oo_object_id_ptr;
+       size_t                          *oo_object_size;
+       void                            **oo_find_init_pp_ptr;
+       void                            *oo_find_pp;
+       uint_t                          oo_max_object_count;
+       uint_t                          *oo_object_count_ptr;
+} kcf_object_ops_params_t;
+
+/*
+ * ko_key is used to encode wrapping key in key_wrap() and
+ * unwrapping key in key_unwrap(). ko_key_template and
+ * ko_key_attribute_count are used to encode public template
+ * and public template attr count in key_generate_pair().
+ * kops->ko_key_object_id_ptr is used to encode public key
+ * in key_generate_pair().
+ */
+typedef struct kcf_key_ops_params {
+       crypto_session_id_t             ko_sid;
+       crypto_mech_type_t              ko_framework_mechtype;
+       crypto_mechanism_t              ko_mech;
+       crypto_object_attribute_t       *ko_key_template;
+       uint_t                          ko_key_attribute_count;
+       crypto_object_id_t              *ko_key_object_id_ptr;
+       crypto_object_attribute_t       *ko_private_key_template;
+       uint_t                          ko_private_key_attribute_count;
+       crypto_object_id_t              *ko_private_key_object_id_ptr;
+       crypto_key_t                    *ko_key;
+       uchar_t                         *ko_wrapped_key;
+       size_t                          *ko_wrapped_key_len_ptr;
+       crypto_object_attribute_t       *ko_out_template1;
+       crypto_object_attribute_t       *ko_out_template2;
+       uint_t                          ko_out_attribute_count1;
+       uint_t                          ko_out_attribute_count2;
+} kcf_key_ops_params_t;
+
+/*
+ * po_pin and po_pin_len are used to encode new_pin and new_pin_len
+ * when wrapping set_pin() function parameters.
+ *
+ * po_pd is useful when the provider descriptor (pd) supplying the
+ * provider handle is different from the pd supplying the ops vector.
+ * This is true for the ext_info provider entry point where po_pd
+ * can be the pd of a logical provider. The pd supplying the ops vector
+ * is passed as an argument to kcf_submit_request().
+ */
+typedef struct kcf_provmgmt_ops_params {
+       crypto_session_id_t             po_sid;
+       char                            *po_pin;
+       size_t                          po_pin_len;
+       char                            *po_old_pin;
+       size_t                          po_old_pin_len;
+       char                            *po_label;
+       crypto_provider_ext_info_t      *po_ext_info;
+       kcf_provider_desc_t             *po_pd;
+} kcf_provmgmt_ops_params_t;
+
+/*
+ * The operation type within a function group.
+ */
+typedef enum kcf_op_type {
+       /* common ops for all mechanisms */
+       KCF_OP_INIT = 1,
+       KCF_OP_SINGLE,  /* pkcs11 sense. So, INIT is already done */
+       KCF_OP_UPDATE,
+       KCF_OP_FINAL,
+       KCF_OP_ATOMIC,
+
+       /* digest_key op */
+       KCF_OP_DIGEST_KEY,
+
+       /* mac specific op */
+       KCF_OP_MAC_VERIFY_ATOMIC,
+
+       /* mac/cipher specific op */
+       KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC,
+
+       /* sign_recover ops */
+       KCF_OP_SIGN_RECOVER_INIT,
+       KCF_OP_SIGN_RECOVER,
+       KCF_OP_SIGN_RECOVER_ATOMIC,
+
+       /* verify_recover ops */
+       KCF_OP_VERIFY_RECOVER_INIT,
+       KCF_OP_VERIFY_RECOVER,
+       KCF_OP_VERIFY_RECOVER_ATOMIC,
+
+       /* random number ops */
+       KCF_OP_RANDOM_SEED,
+       KCF_OP_RANDOM_GENERATE,
+
+       /* session management ops */
+       KCF_OP_SESSION_OPEN,
+       KCF_OP_SESSION_CLOSE,
+       KCF_OP_SESSION_LOGIN,
+       KCF_OP_SESSION_LOGOUT,
+
+       /* object management ops */
+       KCF_OP_OBJECT_CREATE,
+       KCF_OP_OBJECT_COPY,
+       KCF_OP_OBJECT_DESTROY,
+       KCF_OP_OBJECT_GET_SIZE,
+       KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE,
+       KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE,
+       KCF_OP_OBJECT_FIND_INIT,
+       KCF_OP_OBJECT_FIND,
+       KCF_OP_OBJECT_FIND_FINAL,
+
+       /* key management ops */
+       KCF_OP_KEY_GENERATE,
+       KCF_OP_KEY_GENERATE_PAIR,
+       KCF_OP_KEY_WRAP,
+       KCF_OP_KEY_UNWRAP,
+       KCF_OP_KEY_DERIVE,
+       KCF_OP_KEY_CHECK,
+
+       /* provider management ops */
+       KCF_OP_MGMT_EXTINFO,
+       KCF_OP_MGMT_INITTOKEN,
+       KCF_OP_MGMT_INITPIN,
+       KCF_OP_MGMT_SETPIN
+} kcf_op_type_t;
+
+/*
+ * The operation groups that need wrapping of parameters. This is somewhat
+ * similar to the function group type in spi.h except that this also includes
+ * all the functions that don't have a mechanism.
+ *
+ * The wrapper macros should never take these enum values as an argument.
+ * Rather, they are assigned in the macro itself since they are known
+ * from the macro name.
+ */
+typedef enum kcf_op_group {
+       KCF_OG_DIGEST = 1,
+       KCF_OG_MAC,
+       KCF_OG_ENCRYPT,
+       KCF_OG_DECRYPT,
+       KCF_OG_SIGN,
+       KCF_OG_VERIFY,
+       KCF_OG_ENCRYPT_MAC,
+       KCF_OG_MAC_DECRYPT,
+       KCF_OG_RANDOM,
+       KCF_OG_SESSION,
+       KCF_OG_OBJECT,
+       KCF_OG_KEY,
+       KCF_OG_PROVMGMT,
+       KCF_OG_NOSTORE_KEY
+} kcf_op_group_t;
+
+/*
+ * The kcf_op_type_t enum values used here should be only for those
+ * operations for which there is a k-api routine in sys/crypto/api.h.
+ */
+#define        IS_INIT_OP(ftype)       ((ftype) == KCF_OP_INIT)
+#define        IS_SINGLE_OP(ftype)     ((ftype) == KCF_OP_SINGLE)
+#define        IS_UPDATE_OP(ftype)     ((ftype) == KCF_OP_UPDATE)
+#define        IS_FINAL_OP(ftype)      ((ftype) == KCF_OP_FINAL)
+#define        IS_ATOMIC_OP(ftype)     ( \
+       (ftype) == KCF_OP_ATOMIC || (ftype) == KCF_OP_MAC_VERIFY_ATOMIC || \
+       (ftype) == KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC || \
+       (ftype) == KCF_OP_SIGN_RECOVER_ATOMIC || \
+       (ftype) == KCF_OP_VERIFY_RECOVER_ATOMIC)
+
+/*
+ * Keep the parameters associated with a request around.
+ * We need to pass them to the SPI.
+ */
+typedef struct kcf_req_params {
+       kcf_op_group_t          rp_opgrp;
+       kcf_op_type_t           rp_optype;
+
+       union {
+               kcf_digest_ops_params_t         digest_params;
+               kcf_mac_ops_params_t            mac_params;
+               kcf_encrypt_ops_params_t        encrypt_params;
+               kcf_decrypt_ops_params_t        decrypt_params;
+               kcf_sign_ops_params_t           sign_params;
+               kcf_verify_ops_params_t         verify_params;
+               kcf_encrypt_mac_ops_params_t    encrypt_mac_params;
+               kcf_mac_decrypt_ops_params_t    mac_decrypt_params;
+               kcf_random_number_ops_params_t  random_number_params;
+               kcf_session_ops_params_t        session_params;
+               kcf_object_ops_params_t         object_params;
+               kcf_key_ops_params_t            key_params;
+               kcf_provmgmt_ops_params_t       provmgmt_params;
+       } rp_u;
+} kcf_req_params_t;
+
+
+/*
+ * The ioctl/k-api code should bundle the parameters into a kcf_req_params_t
+ * structure before calling a scheduler routine. The following macros are
+ * available for that purpose.
+ *
+ * For the most part, the macro arguments closely correspond to the
+ * function parameters. In some cases, we use generic names. The comments
+ * for the structure should indicate these cases.
+ */
+#define        KCF_WRAP_DIGEST_OPS_PARAMS(req, ftype, _sid, _mech, _key,       \
+       _data, _digest) {                                               \
+       kcf_digest_ops_params_t *dops = &(req)->rp_u.digest_params;     \
+       crypto_mechanism_t *mechp = _mech;                              \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_DIGEST;                                \
+       (req)->rp_optype = ftype;                                       \
+       dops->do_sid = _sid;                                            \
+       if (mechp != NULL) {                                            \
+               dops->do_mech = *mechp;                                 \
+               dops->do_framework_mechtype = mechp->cm_type;           \
+       }                                                               \
+       dops->do_digest_key = _key;                                     \
+       dops->do_data = _data;                                          \
+       dops->do_digest = _digest;                                      \
+}
+
+#define        KCF_WRAP_MAC_OPS_PARAMS(req, ftype, _sid, _mech, _key,          \
+       _data, _mac, _templ) {                                          \
+       kcf_mac_ops_params_t *mops = &(req)->rp_u.mac_params;           \
+       crypto_mechanism_t *mechp = _mech;                              \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_MAC;                                   \
+       (req)->rp_optype = ftype;                                       \
+       mops->mo_sid = _sid;                                            \
+       if (mechp != NULL) {                                            \
+               mops->mo_mech = *mechp;                                 \
+               mops->mo_framework_mechtype = mechp->cm_type;           \
+       }                                                               \
+       mops->mo_key = _key;                                            \
+       mops->mo_data = _data;                                          \
+       mops->mo_mac = _mac;                                            \
+       mops->mo_templ = _templ;                                        \
+}
+
+#define        KCF_WRAP_ENCRYPT_OPS_PARAMS(req, ftype, _sid, _mech, _key,      \
+       _plaintext, _ciphertext, _templ) {                              \
+       kcf_encrypt_ops_params_t *cops = &(req)->rp_u.encrypt_params;   \
+       crypto_mechanism_t *mechp = _mech;                              \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_ENCRYPT;                               \
+       (req)->rp_optype = ftype;                                       \
+       cops->eo_sid = _sid;                                            \
+       if (mechp != NULL) {                                            \
+               cops->eo_mech = *mechp;                                 \
+               cops->eo_framework_mechtype = mechp->cm_type;           \
+       }                                                               \
+       cops->eo_key = _key;                                            \
+       cops->eo_plaintext = _plaintext;                                \
+       cops->eo_ciphertext = _ciphertext;                              \
+       cops->eo_templ = _templ;                                        \
+}
+
+#define        KCF_WRAP_DECRYPT_OPS_PARAMS(req, ftype, _sid, _mech, _key,      \
+       _ciphertext, _plaintext, _templ) {                              \
+       kcf_decrypt_ops_params_t *cops = &(req)->rp_u.decrypt_params;   \
+       crypto_mechanism_t *mechp = _mech;                              \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_DECRYPT;                               \
+       (req)->rp_optype = ftype;                                       \
+       cops->dop_sid = _sid;                                           \
+       if (mechp != NULL) {                                            \
+               cops->dop_mech = *mechp;                                \
+               cops->dop_framework_mechtype = mechp->cm_type;          \
+       }                                                               \
+       cops->dop_key = _key;                                           \
+       cops->dop_ciphertext = _ciphertext;                             \
+       cops->dop_plaintext = _plaintext;                               \
+       cops->dop_templ = _templ;                                       \
+}
+
+#define        KCF_WRAP_SIGN_OPS_PARAMS(req, ftype, _sid, _mech, _key,         \
+       _data, _signature, _templ) {                                    \
+       kcf_sign_ops_params_t *sops = &(req)->rp_u.sign_params;         \
+       crypto_mechanism_t *mechp = _mech;                              \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_SIGN;                                  \
+       (req)->rp_optype = ftype;                                       \
+       sops->so_sid = _sid;                                            \
+       if (mechp != NULL) {                                            \
+               sops->so_mech = *mechp;                                 \
+               sops->so_framework_mechtype = mechp->cm_type;           \
+       }                                                               \
+       sops->so_key = _key;                                            \
+       sops->so_data = _data;                                          \
+       sops->so_signature = _signature;                                \
+       sops->so_templ = _templ;                                        \
+}
+
+#define        KCF_WRAP_VERIFY_OPS_PARAMS(req, ftype, _sid, _mech, _key,       \
+       _data, _signature, _templ) {                                    \
+       kcf_verify_ops_params_t *vops = &(req)->rp_u.verify_params;     \
+       crypto_mechanism_t *mechp = _mech;                              \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_VERIFY;                                \
+       (req)->rp_optype = ftype;                                       \
+       vops->vo_sid = _sid;                                            \
+       if (mechp != NULL) {                                            \
+               vops->vo_mech = *mechp;                                 \
+               vops->vo_framework_mechtype = mechp->cm_type;           \
+       }                                                               \
+       vops->vo_key = _key;                                            \
+       vops->vo_data = _data;                                          \
+       vops->vo_signature = _signature;                                \
+       vops->vo_templ = _templ;                                        \
+}
+
+#define        KCF_WRAP_ENCRYPT_MAC_OPS_PARAMS(req, ftype, _sid, _encr_key,    \
+       _mac_key, _plaintext, _ciphertext, _mac, _encr_templ, _mac_templ) { \
+       kcf_encrypt_mac_ops_params_t *cmops = &(req)->rp_u.encrypt_mac_params; \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_ENCRYPT_MAC;                           \
+       (req)->rp_optype = ftype;                                       \
+       cmops->em_sid = _sid;                                           \
+       cmops->em_encr_key = _encr_key;                                 \
+       cmops->em_mac_key = _mac_key;                                   \
+       cmops->em_plaintext = _plaintext;                               \
+       cmops->em_ciphertext = _ciphertext;                             \
+       cmops->em_mac = _mac;                                           \
+       cmops->em_encr_templ = _encr_templ;                             \
+       cmops->em_mac_templ = _mac_templ;                               \
+}
+
+#define        KCF_WRAP_MAC_DECRYPT_OPS_PARAMS(req, ftype, _sid, _mac_key,     \
+       _decr_key, _ciphertext, _mac, _plaintext, _mac_templ, _decr_templ) { \
+       kcf_mac_decrypt_ops_params_t *cmops = &(req)->rp_u.mac_decrypt_params; \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_MAC_DECRYPT;                           \
+       (req)->rp_optype = ftype;                                       \
+       cmops->md_sid = _sid;                                           \
+       cmops->md_mac_key = _mac_key;                                   \
+       cmops->md_decr_key = _decr_key;                                 \
+       cmops->md_ciphertext = _ciphertext;                             \
+       cmops->md_mac = _mac;                                           \
+       cmops->md_plaintext = _plaintext;                               \
+       cmops->md_mac_templ = _mac_templ;                               \
+       cmops->md_decr_templ = _decr_templ;                             \
+}
+
+#define        KCF_WRAP_RANDOM_OPS_PARAMS(req, ftype, _sid, _buf, _buflen,     \
+       _est, _flags) {                                                 \
+       kcf_random_number_ops_params_t *rops =                          \
+               &(req)->rp_u.random_number_params;                      \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_RANDOM;                                \
+       (req)->rp_optype = ftype;                                       \
+       rops->rn_sid = _sid;                                            \
+       rops->rn_buf = _buf;                                            \
+       rops->rn_buflen = _buflen;                                      \
+       rops->rn_entropy_est = _est;                                    \
+       rops->rn_flags = _flags;                                        \
+}
+
+#define        KCF_WRAP_SESSION_OPS_PARAMS(req, ftype, _sid_ptr, _sid,         \
+       _user_type, _pin, _pin_len, _pd) {                              \
+       kcf_session_ops_params_t *sops = &(req)->rp_u.session_params;   \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_SESSION;                               \
+       (req)->rp_optype = ftype;                                       \
+       sops->so_sid_ptr = _sid_ptr;                                    \
+       sops->so_sid = _sid;                                            \
+       sops->so_user_type = _user_type;                                \
+       sops->so_pin = _pin;                                            \
+       sops->so_pin_len = _pin_len;                                    \
+       sops->so_pd = _pd;                                              \
+}
+
+#define        KCF_WRAP_OBJECT_OPS_PARAMS(req, ftype, _sid, _object_id,        \
+       _template, _attribute_count, _object_id_ptr, _object_size,      \
+       _find_init_pp_ptr, _find_pp, _max_object_count, _object_count_ptr) { \
+       kcf_object_ops_params_t *jops = &(req)->rp_u.object_params;     \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_OBJECT;                                \
+       (req)->rp_optype = ftype;                                       \
+       jops->oo_sid = _sid;                                            \
+       jops->oo_object_id = _object_id;                                \
+       jops->oo_template = _template;                                  \
+       jops->oo_attribute_count = _attribute_count;                    \
+       jops->oo_object_id_ptr = _object_id_ptr;                        \
+       jops->oo_object_size = _object_size;                            \
+       jops->oo_find_init_pp_ptr = _find_init_pp_ptr;                  \
+       jops->oo_find_pp = _find_pp;                                    \
+       jops->oo_max_object_count = _max_object_count;                  \
+       jops->oo_object_count_ptr = _object_count_ptr;                  \
+}
+
+#define        KCF_WRAP_KEY_OPS_PARAMS(req, ftype, _sid, _mech, _key_template, \
+       _key_attribute_count, _key_object_id_ptr, _private_key_template, \
+       _private_key_attribute_count, _private_key_object_id_ptr,       \
+       _key, _wrapped_key, _wrapped_key_len_ptr) {                     \
+       kcf_key_ops_params_t *kops = &(req)->rp_u.key_params;           \
+       crypto_mechanism_t *mechp = _mech;                              \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_KEY;                                   \
+       (req)->rp_optype = ftype;                                       \
+       kops->ko_sid = _sid;                                            \
+       if (mechp != NULL) {                                            \
+               kops->ko_mech = *mechp;                                 \
+               kops->ko_framework_mechtype = mechp->cm_type;           \
+       }                                                               \
+       kops->ko_key_template = _key_template;                          \
+       kops->ko_key_attribute_count = _key_attribute_count;            \
+       kops->ko_key_object_id_ptr = _key_object_id_ptr;                \
+       kops->ko_private_key_template = _private_key_template;          \
+       kops->ko_private_key_attribute_count = _private_key_attribute_count; \
+       kops->ko_private_key_object_id_ptr = _private_key_object_id_ptr; \
+       kops->ko_key = _key;                                            \
+       kops->ko_wrapped_key = _wrapped_key;                            \
+       kops->ko_wrapped_key_len_ptr = _wrapped_key_len_ptr;            \
+}
+
+#define        KCF_WRAP_PROVMGMT_OPS_PARAMS(req, ftype, _sid, _old_pin,        \
+       _old_pin_len, _pin, _pin_len, _label, _ext_info, _pd) {         \
+       kcf_provmgmt_ops_params_t *pops = &(req)->rp_u.provmgmt_params; \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_PROVMGMT;                              \
+       (req)->rp_optype = ftype;                                       \
+       pops->po_sid = _sid;                                            \
+       pops->po_pin = _pin;                                            \
+       pops->po_pin_len = _pin_len;                                    \
+       pops->po_old_pin = _old_pin;                                    \
+       pops->po_old_pin_len = _old_pin_len;                            \
+       pops->po_label = _label;                                        \
+       pops->po_ext_info = _ext_info;                                  \
+       pops->po_pd = _pd;                                              \
+}
+
+#define        KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(req, ftype, _sid, _mech,        \
+       _key_template, _key_attribute_count, _private_key_template,     \
+       _private_key_attribute_count, _key, _out_template1,             \
+       _out_attribute_count1, _out_template2, _out_attribute_count2) { \
+       kcf_key_ops_params_t *kops = &(req)->rp_u.key_params;           \
+       crypto_mechanism_t *mechp = _mech;                              \
+                                                                       \
+       (req)->rp_opgrp = KCF_OG_NOSTORE_KEY;                           \
+       (req)->rp_optype = ftype;                                       \
+       kops->ko_sid = _sid;                                            \
+       if (mechp != NULL) {                                            \
+               kops->ko_mech = *mechp;                                 \
+               kops->ko_framework_mechtype = mechp->cm_type;           \
+       }                                                               \
+       kops->ko_key_template = _key_template;                          \
+       kops->ko_key_attribute_count = _key_attribute_count;            \
+       kops->ko_key_object_id_ptr = NULL;                              \
+       kops->ko_private_key_template = _private_key_template;          \
+       kops->ko_private_key_attribute_count = _private_key_attribute_count; \
+       kops->ko_private_key_object_id_ptr = NULL;                      \
+       kops->ko_key = _key;                                            \
+       kops->ko_wrapped_key = NULL;                                    \
+       kops->ko_wrapped_key_len_ptr = 0;                               \
+       kops->ko_out_template1 = _out_template1;                        \
+       kops->ko_out_template2 = _out_template2;                        \
+       kops->ko_out_attribute_count1 = _out_attribute_count1;          \
+       kops->ko_out_attribute_count2 = _out_attribute_count2;          \
+}
+
+#define        KCF_SET_PROVIDER_MECHNUM(fmtype, pd, mechp)                     \
+       (mechp)->cm_type =                                              \
+           KCF_TO_PROV_MECHNUM(pd, fmtype);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_OPS_IMPL_H */
diff --git a/zfs/module/icp/include/sys/crypto/sched_impl.h b/zfs/module/icp/include/sys/crypto/sched_impl.h
new file mode 100644 (file)
index 0000000..32ffa77
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * 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 _SYS_CRYPTO_SCHED_IMPL_H
+#define        _SYS_CRYPTO_SCHED_IMPL_H
+
+/*
+ * Scheduler internal structures.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/ops_impl.h>
+
+typedef void (kcf_func_t)(void *, int);
+
+typedef enum kcf_req_status {
+       REQ_ALLOCATED = 1,
+       REQ_WAITING,            /* At the framework level */
+       REQ_INPROGRESS,         /* At the provider level */
+       REQ_DONE,
+       REQ_CANCELED
+} kcf_req_status_t;
+
+typedef enum kcf_call_type {
+       CRYPTO_SYNCH = 1,
+       CRYPTO_ASYNCH
+} kcf_call_type_t;
+
+#define        CHECK_RESTRICT(crq) (crq != NULL &&     \
+       ((crq)->cr_flag & CRYPTO_RESTRICTED))
+
+#define        CHECK_RESTRICT_FALSE    B_FALSE
+
+#define        CHECK_FASTPATH(crq, pd) ((crq) == NULL ||       \
+       !((crq)->cr_flag & CRYPTO_ALWAYS_QUEUE)) &&     \
+       (pd)->pd_prov_type == CRYPTO_SW_PROVIDER
+
+#define        KCF_KMFLAG(crq) (((crq) == NULL) ? KM_SLEEP : KM_NOSLEEP)
+
+/*
+ * The framework keeps an internal handle to use in the adaptive
+ * asynchronous case. This is the case when a client has the
+ * CRYPTO_ALWAYS_QUEUE bit clear and a software provider is used for
+ * the request. The request is completed in the context of the calling
+ * thread and kernel memory must be allocated with KM_NOSLEEP.
+ *
+ * The framework passes a pointer to the handle in crypto_req_handle_t
+ * argument when it calls the SPI of the software provider. The macros
+ * KCF_RHNDL() and KCF_SWFP_RHNDL() are used to do this.
+ *
+ * When a provider asks the framework for kmflag value via
+ * crypto_kmflag(9S) we use REQHNDL2_KMFLAG() macro.
+ */
+extern ulong_t kcf_swprov_hndl;
+#define        KCF_RHNDL(kmflag) (((kmflag) == KM_SLEEP) ? NULL : &kcf_swprov_hndl)
+#define        KCF_SWFP_RHNDL(crq) (((crq) == NULL) ? NULL : &kcf_swprov_hndl)
+#define        REQHNDL2_KMFLAG(rhndl) \
+       ((rhndl == &kcf_swprov_hndl) ? KM_NOSLEEP : KM_SLEEP)
+
+/* Internal call_req flags. They start after the public ones in api.h */
+
+#define        CRYPTO_SETDUAL  0x00001000      /* Set the 'cont' boolean before */
+                                       /* submitting the request */
+#define        KCF_ISDUALREQ(crq)      \
+       (((crq) == NULL) ? B_FALSE : (crq->cr_flag & CRYPTO_SETDUAL))
+
+typedef struct kcf_prov_tried {
+       kcf_provider_desc_t     *pt_pd;
+       struct kcf_prov_tried   *pt_next;
+} kcf_prov_tried_t;
+
+#define        IS_FG_SUPPORTED(mdesc, fg)              \
+       (((mdesc)->pm_mech_info.cm_func_group_mask & (fg)) != 0)
+
+#define        IS_PROVIDER_TRIED(pd, tlist)            \
+       (tlist != NULL && is_in_triedlist(pd, tlist))
+
+#define        IS_RECOVERABLE(error)                   \
+       (error == CRYPTO_BUFFER_TOO_BIG ||      \
+       error == CRYPTO_BUSY ||                 \
+       error == CRYPTO_DEVICE_ERROR ||         \
+       error == CRYPTO_DEVICE_MEMORY ||        \
+       error == CRYPTO_KEY_SIZE_RANGE ||       \
+       error == CRYPTO_NO_PERMISSION)
+
+#define        KCF_ATOMIC_INCR(x)      atomic_add_32(&(x), 1)
+#define        KCF_ATOMIC_DECR(x)      atomic_add_32(&(x), -1)
+
+/*
+ * Node structure for synchronous requests.
+ */
+typedef struct kcf_sreq_node {
+       /* Should always be the first field in this structure */
+       kcf_call_type_t         sn_type;
+       /*
+        * sn_cv and sr_lock are used to wait for the
+        * operation to complete. sn_lock also protects
+        * the sn_state field.
+        */
+       kcondvar_t              sn_cv;
+       kmutex_t                sn_lock;
+       kcf_req_status_t        sn_state;
+
+       /*
+        * Return value from the operation. This will be
+        * one of the CRYPTO_* errors defined in common.h.
+        */
+       int                     sn_rv;
+
+       /*
+        * parameters to call the SPI with. This can be
+        * a pointer as we know the caller context/stack stays.
+        */
+       struct kcf_req_params   *sn_params;
+
+       /* Internal context for this request */
+       struct kcf_context      *sn_context;
+
+       /* Provider handling this request */
+       kcf_provider_desc_t     *sn_provider;
+} kcf_sreq_node_t;
+
+/*
+ * Node structure for asynchronous requests. A node can be on
+ * on a chain of requests hanging of the internal context
+ * structure and can be in the global software provider queue.
+ */
+typedef struct kcf_areq_node {
+       /* Should always be the first field in this structure */
+       kcf_call_type_t         an_type;
+
+       /* an_lock protects the field an_state  */
+       kmutex_t                an_lock;
+       kcf_req_status_t        an_state;
+       crypto_call_req_t       an_reqarg;
+
+       /*
+        * parameters to call the SPI with. We need to
+        * save the params since the caller stack can go away.
+        */
+       struct kcf_req_params   an_params;
+
+       /*
+        * The next two fields should be NULL for operations that
+        * don't need a context.
+        */
+       /* Internal context for this request */
+       struct kcf_context      *an_context;
+
+       /* next in chain of requests for context */
+       struct kcf_areq_node    *an_ctxchain_next;
+
+       kcondvar_t              an_turn_cv;
+       boolean_t               an_is_my_turn;
+       boolean_t               an_isdual;      /* for internal reuse */
+
+       /*
+        * Next and previous nodes in the global software
+        * queue. These fields are NULL for a hardware
+        * provider since we use a taskq there.
+        */
+       struct kcf_areq_node    *an_next;
+       struct kcf_areq_node    *an_prev;
+
+       /* Provider handling this request */
+       kcf_provider_desc_t     *an_provider;
+       kcf_prov_tried_t        *an_tried_plist;
+
+       struct kcf_areq_node    *an_idnext;     /* Next in ID hash */
+       struct kcf_areq_node    *an_idprev;     /* Prev in ID hash */
+       kcondvar_t              an_done;        /* Signal request completion */
+       uint_t                  an_refcnt;
+} kcf_areq_node_t;
+
+#define        KCF_AREQ_REFHOLD(areq) {                \
+       atomic_add_32(&(areq)->an_refcnt, 1);   \
+       ASSERT((areq)->an_refcnt != 0);         \
+}
+
+#define        KCF_AREQ_REFRELE(areq) {                                \
+       ASSERT((areq)->an_refcnt != 0);                         \
+       membar_exit();                                          \
+       if (atomic_add_32_nv(&(areq)->an_refcnt, -1) == 0)      \
+               kcf_free_req(areq);                             \
+}
+
+#define        GET_REQ_TYPE(arg) *((kcf_call_type_t *)(arg))
+
+#define        NOTIFY_CLIENT(areq, err) (*(areq)->an_reqarg.cr_callback_func)(\
+       (areq)->an_reqarg.cr_callback_arg, err);
+
+/* For internally generated call requests for dual operations */
+typedef        struct kcf_call_req {
+       crypto_call_req_t       kr_callreq;     /* external client call req */
+       kcf_req_params_t        kr_params;      /* Params saved for next call */
+       kcf_areq_node_t         *kr_areq;       /* Use this areq */
+       off_t                   kr_saveoffset;
+       size_t                  kr_savelen;
+} kcf_dual_req_t;
+
+/*
+ * The following are some what similar to macros in callo.h, which implement
+ * callout tables.
+ *
+ * The lower four bits of the ID are used to encode the table ID to
+ * index in to. The REQID_COUNTER_HIGH bit is used to avoid any check for
+ * wrap around when generating ID. We assume that there won't be a request
+ * which takes more time than 2^^(sizeof (long) - 5) other requests submitted
+ * after it. This ensures there won't be any ID collision.
+ */
+#define        REQID_COUNTER_HIGH      (1UL << (8 * sizeof (long) - 1))
+#define        REQID_COUNTER_SHIFT     4
+#define        REQID_COUNTER_LOW       (1 << REQID_COUNTER_SHIFT)
+#define        REQID_TABLES            16
+#define        REQID_TABLE_MASK        (REQID_TABLES - 1)
+
+#define        REQID_BUCKETS           512
+#define        REQID_BUCKET_MASK       (REQID_BUCKETS - 1)
+#define        REQID_HASH(id)  (((id) >> REQID_COUNTER_SHIFT) & REQID_BUCKET_MASK)
+
+#define        GET_REQID(areq) (areq)->an_reqarg.cr_reqid
+#define        SET_REQID(areq, val)    GET_REQID(areq) = val
+
+/*
+ * Hash table for async requests.
+ */
+typedef struct kcf_reqid_table {
+       kmutex_t                rt_lock;
+       crypto_req_id_t         rt_curid;
+       kcf_areq_node_t         *rt_idhash[REQID_BUCKETS];
+} kcf_reqid_table_t;
+
+/*
+ * Global software provider queue structure. Requests to be
+ * handled by a SW provider and have the ALWAYS_QUEUE flag set
+ * get queued here.
+ */
+typedef struct kcf_global_swq {
+       /*
+        * gs_cv and gs_lock are used to wait for new requests.
+        * gs_lock protects the changes to the queue.
+        */
+       kcondvar_t              gs_cv;
+       kmutex_t                gs_lock;
+       uint_t                  gs_njobs;
+       uint_t                  gs_maxjobs;
+       kcf_areq_node_t         *gs_first;
+       kcf_areq_node_t         *gs_last;
+} kcf_global_swq_t;
+
+
+/*
+ * Internal representation of a canonical context. We contain crypto_ctx_t
+ * structure in order to have just one memory allocation. The SPI
+ * ((crypto_ctx_t *)ctx)->cc_framework_private maps to this structure.
+ */
+typedef struct kcf_context {
+       crypto_ctx_t            kc_glbl_ctx;
+       uint_t                  kc_refcnt;
+       kmutex_t                kc_in_use_lock;
+       /*
+        * kc_req_chain_first and kc_req_chain_last are used to chain
+        * multiple async requests using the same context. They should be
+        * NULL for sync requests.
+        */
+       kcf_areq_node_t         *kc_req_chain_first;
+       kcf_areq_node_t         *kc_req_chain_last;
+       kcf_provider_desc_t     *kc_prov_desc;  /* Prov. descriptor */
+       kcf_provider_desc_t     *kc_sw_prov_desc;       /* Prov. descriptor */
+       kcf_mech_entry_t        *kc_mech;
+       struct kcf_context      *kc_secondctx;  /* for dual contexts */
+} kcf_context_t;
+
+/*
+ * Bump up the reference count on the framework private context. A
+ * global context or a request that references this structure should
+ * do a hold.
+ */
+#define        KCF_CONTEXT_REFHOLD(ictx) {             \
+       atomic_add_32(&(ictx)->kc_refcnt, 1);   \
+       ASSERT((ictx)->kc_refcnt != 0);         \
+}
+
+/*
+ * Decrement the reference count on the framework private context.
+ * When the last reference is released, the framework private
+ * context structure is freed along with the global context.
+ */
+#define        KCF_CONTEXT_REFRELE(ictx) {                             \
+       ASSERT((ictx)->kc_refcnt != 0);                         \
+       membar_exit();                                          \
+       if (atomic_add_32_nv(&(ictx)->kc_refcnt, -1) == 0)      \
+               kcf_free_context(ictx);                         \
+}
+
+/*
+ * Check if we can release the context now. In case of CRYPTO_QUEUED
+ * we do not release it as we can do it only after the provider notified
+ * us. In case of CRYPTO_BUSY, the client can retry the request using
+ * the context, so we do not release the context.
+ *
+ * This macro should be called only from the final routine in
+ * an init/update/final sequence. We do not release the context in case
+ * of update operations. We require the consumer to free it
+ * explicitly, in case it wants to abandon the operation. This is done
+ * as there may be mechanisms in ECB mode that can continue even if
+ * an operation on a block fails.
+ */
+#define        KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx) {                 \
+       if (KCF_CONTEXT_DONE(rv))                               \
+               KCF_CONTEXT_REFRELE(kcf_ctx);                   \
+}
+
+/*
+ * This macro determines whether we're done with a context.
+ */
+#define        KCF_CONTEXT_DONE(rv)                                    \
+       ((rv) != CRYPTO_QUEUED && (rv) != CRYPTO_BUSY &&        \
+           (rv) != CRYPTO_BUFFER_TOO_SMALL)
+
+/*
+ * A crypto_ctx_template_t is internally a pointer to this struct
+ */
+typedef        struct kcf_ctx_template {
+       crypto_kcf_provider_handle_t    ct_prov_handle; /* provider handle */
+       uint_t                          ct_generation;  /* generation # */
+       size_t                          ct_size;        /* for freeing */
+       crypto_spi_ctx_template_t       ct_prov_tmpl;   /* context template */
+                                                       /* from the SW prov */
+} kcf_ctx_template_t;
+
+/*
+ * Structure for pool of threads working on global software queue.
+ */
+typedef struct kcf_pool {
+       uint32_t        kp_threads;             /* Number of threads in pool */
+       uint32_t        kp_idlethreads;         /* Idle threads in pool */
+       uint32_t        kp_blockedthreads;      /* Blocked threads in pool */
+
+       /*
+        * cv & lock to monitor the condition when no threads
+        * are around. In this case the failover thread kicks in.
+        */
+       kcondvar_t      kp_nothr_cv;
+       kmutex_t        kp_thread_lock;
+
+       /* Userspace thread creator variables. */
+       boolean_t       kp_signal_create_thread; /* Create requested flag  */
+       int             kp_nthrs;               /* # of threads to create */
+       boolean_t       kp_user_waiting;        /* Thread waiting for work */
+
+       /*
+        * cv & lock for the condition where more threads need to be
+        * created. kp_user_lock also protects the three fileds above.
+        */
+       kcondvar_t      kp_user_cv;             /* Creator cond. variable */
+       kmutex_t        kp_user_lock;           /* Creator lock */
+} kcf_pool_t;
+
+
+/*
+ * State of a crypto bufcall element.
+ */
+typedef enum cbuf_state {
+       CBUF_FREE = 1,
+       CBUF_WAITING,
+       CBUF_RUNNING
+} cbuf_state_t;
+
+/*
+ * Structure of a crypto bufcall element.
+ */
+typedef struct kcf_cbuf_elem {
+       /*
+        * lock and cv to wait for CBUF_RUNNING to be done
+        * kc_lock also protects kc_state.
+        */
+       kmutex_t                kc_lock;
+       kcondvar_t              kc_cv;
+       cbuf_state_t            kc_state;
+
+       struct kcf_cbuf_elem    *kc_next;
+       struct kcf_cbuf_elem    *kc_prev;
+
+       void                    (*kc_func)(void *arg);
+       void                    *kc_arg;
+} kcf_cbuf_elem_t;
+
+/*
+ * State of a notify element.
+ */
+typedef enum ntfy_elem_state {
+       NTFY_WAITING = 1,
+       NTFY_RUNNING
+} ntfy_elem_state_t;
+
+/*
+ * Structure of a notify list element.
+ */
+typedef struct kcf_ntfy_elem {
+       /*
+        * lock and cv to wait for NTFY_RUNNING to be done.
+        * kn_lock also protects kn_state.
+        */
+       kmutex_t                        kn_lock;
+       kcondvar_t                      kn_cv;
+       ntfy_elem_state_t               kn_state;
+
+       struct kcf_ntfy_elem            *kn_next;
+       struct kcf_ntfy_elem            *kn_prev;
+
+       crypto_notify_callback_t        kn_func;
+       uint32_t                        kn_event_mask;
+} kcf_ntfy_elem_t;
+
+
+/*
+ * The following values are based on the assumption that it would
+ * take around eight cpus to load a hardware provider (This is true for
+ * at least one product) and a kernel client may come from different
+ * low-priority interrupt levels. We will have CYRPTO_TASKQ_MIN number
+ * of cached taskq entries. The CRYPTO_TASKQ_MAX number is based on
+ * a throughput of 1GB/s using 512-byte buffers. These are just
+ * reasonable estimates and might need to change in future.
+ */
+#define        CRYPTO_TASKQ_THREADS    8
+#define        CYRPTO_TASKQ_MIN        64
+#define        CRYPTO_TASKQ_MAX        2 * 1024 * 1024
+
+extern int crypto_taskq_threads;
+extern int crypto_taskq_minalloc;
+extern int crypto_taskq_maxalloc;
+extern kcf_global_swq_t *gswq;
+extern int kcf_maxthreads;
+extern int kcf_minthreads;
+
+/*
+ * All pending crypto bufcalls are put on a list. cbuf_list_lock
+ * protects changes to this list.
+ */
+extern kmutex_t cbuf_list_lock;
+extern kcondvar_t cbuf_list_cv;
+
+/*
+ * All event subscribers are put on a list. kcf_notify_list_lock
+ * protects changes to this list.
+ */
+extern kmutex_t ntfy_list_lock;
+extern kcondvar_t ntfy_list_cv;
+
+boolean_t kcf_get_next_logical_provider_member(kcf_provider_desc_t *,
+    kcf_provider_desc_t *, kcf_provider_desc_t **);
+extern int kcf_get_hardware_provider(crypto_mech_type_t, crypto_mech_type_t,
+    boolean_t, kcf_provider_desc_t *, kcf_provider_desc_t **,
+    crypto_func_group_t);
+extern int kcf_get_hardware_provider_nomech(offset_t, offset_t,
+    boolean_t, kcf_provider_desc_t *, kcf_provider_desc_t **);
+extern void kcf_free_triedlist(kcf_prov_tried_t *);
+extern kcf_prov_tried_t *kcf_insert_triedlist(kcf_prov_tried_t **,
+    kcf_provider_desc_t *, int);
+extern kcf_provider_desc_t *kcf_get_mech_provider(crypto_mech_type_t,
+    kcf_mech_entry_t **, int *, kcf_prov_tried_t *, crypto_func_group_t,
+    boolean_t, size_t);
+extern kcf_provider_desc_t *kcf_get_dual_provider(crypto_mechanism_t *,
+    crypto_mechanism_t *, kcf_mech_entry_t **, crypto_mech_type_t *,
+    crypto_mech_type_t *, int *, kcf_prov_tried_t *,
+    crypto_func_group_t, crypto_func_group_t, boolean_t, size_t);
+extern crypto_ctx_t *kcf_new_ctx(crypto_call_req_t  *, kcf_provider_desc_t *,
+    crypto_session_id_t);
+extern int kcf_submit_request(kcf_provider_desc_t *, crypto_ctx_t *,
+    crypto_call_req_t *, kcf_req_params_t *, boolean_t);
+extern void kcf_sched_destroy(void);
+extern void kcf_sched_init(void);
+extern void kcf_sched_start(void);
+extern void kcf_sop_done(kcf_sreq_node_t *, int);
+extern void kcf_aop_done(kcf_areq_node_t *, int);
+extern int common_submit_request(kcf_provider_desc_t *,
+    crypto_ctx_t *, kcf_req_params_t *, crypto_req_handle_t);
+extern void kcf_free_context(kcf_context_t *);
+
+extern int kcf_svc_wait(int *);
+extern int kcf_svc_do_run(void);
+extern int kcf_need_signature_verification(kcf_provider_desc_t *);
+extern void kcf_verify_signature(void *);
+extern struct modctl *kcf_get_modctl(crypto_provider_info_t *);
+extern void verify_unverified_providers(void);
+extern void kcf_free_req(kcf_areq_node_t *areq);
+extern void crypto_bufcall_service(void);
+
+extern void kcf_walk_ntfylist(uint32_t, void *);
+extern void kcf_do_notify(kcf_provider_desc_t *, boolean_t);
+
+extern kcf_dual_req_t *kcf_alloc_req(crypto_call_req_t *);
+extern void kcf_next_req(void *, int);
+extern void kcf_last_req(void *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_SCHED_IMPL_H */
diff --git a/zfs/module/icp/include/sys/crypto/spi.h b/zfs/module/icp/include/sys/crypto/spi.h
new file mode 100644 (file)
index 0000000..0aae918
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SYS_CRYPTO_SPI_H
+#define        _SYS_CRYPTO_SPI_H
+
+/*
+ * CSPI: Cryptographic Service Provider Interface.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef CONSTIFY_PLUGIN
+#define        __no_const __attribute__((no_const))
+#else
+#define        __no_const
+#endif /* CONSTIFY_PLUGIN */
+
+#define        CRYPTO_SPI_VERSION_1    1
+#define        CRYPTO_SPI_VERSION_2    2
+#define        CRYPTO_SPI_VERSION_3    3
+
+/*
+ * Provider-private handle. This handle is specified by a provider
+ * when it registers by means of the pi_provider_handle field of
+ * the crypto_provider_info structure, and passed to the provider
+ * when its entry points are invoked.
+ */
+typedef void *crypto_provider_handle_t;
+
+/*
+ * Context templates can be used to by software providers to pre-process
+ * keying material, such as key schedules. They are allocated by
+ * a software provider create_ctx_template(9E) entry point, and passed
+ * as argument to initialization and atomic provider entry points.
+ */
+typedef void *crypto_spi_ctx_template_t;
+
+/*
+ * Request handles are used by the kernel to identify an asynchronous
+ * request being processed by a provider. It is passed by the kernel
+ * to a hardware provider when submitting a request, and must be
+ * specified by a provider when calling crypto_op_notification(9F)
+ */
+typedef void *crypto_req_handle_t;
+
+/* Values for cc_flags field */
+#define        CRYPTO_INIT_OPSTATE     0x00000001 /* allocate and init cc_opstate */
+#define        CRYPTO_USE_OPSTATE      0x00000002 /* .. start using it as context */
+
+/*
+ * The context structure is passed from the kernel to a provider.
+ * It contains the information needed to process a multi-part or
+ * single part operation. The context structure is not used
+ * by atomic operations.
+ *
+ * Parameters needed to perform a cryptographic operation, such
+ * as keys, mechanisms, input and output buffers, are passed
+ * as separate arguments to Provider routines.
+ */
+typedef struct crypto_ctx {
+       crypto_provider_handle_t cc_provider;
+       crypto_session_id_t     cc_session;
+       void                    *cc_provider_private;   /* owned by provider */
+       void                    *cc_framework_private;  /* owned by framework */
+       uint32_t                cc_flags;               /* flags */
+       void                    *cc_opstate;            /* state */
+} crypto_ctx_t;
+
+/*
+ * Extended provider information.
+ */
+
+/*
+ * valid values for ei_flags field of extended info structure
+ * They match the RSA Security, Inc PKCS#11 tokenInfo flags.
+ */
+#define        CRYPTO_EXTF_RNG                                 0x00000001
+#define        CRYPTO_EXTF_WRITE_PROTECTED                     0x00000002
+#define        CRYPTO_EXTF_LOGIN_REQUIRED                      0x00000004
+#define        CRYPTO_EXTF_USER_PIN_INITIALIZED                0x00000008
+#define        CRYPTO_EXTF_CLOCK_ON_TOKEN                      0x00000040
+#define        CRYPTO_EXTF_PROTECTED_AUTHENTICATION_PATH       0x00000100
+#define        CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS              0x00000200
+#define        CRYPTO_EXTF_TOKEN_INITIALIZED                   0x00000400
+#define        CRYPTO_EXTF_USER_PIN_COUNT_LOW                  0x00010000
+#define        CRYPTO_EXTF_USER_PIN_FINAL_TRY                  0x00020000
+#define        CRYPTO_EXTF_USER_PIN_LOCKED                     0x00040000
+#define        CRYPTO_EXTF_USER_PIN_TO_BE_CHANGED              0x00080000
+#define        CRYPTO_EXTF_SO_PIN_COUNT_LOW                    0x00100000
+#define        CRYPTO_EXTF_SO_PIN_FINAL_TRY                    0x00200000
+#define        CRYPTO_EXTF_SO_PIN_LOCKED                       0x00400000
+#define        CRYPTO_EXTF_SO_PIN_TO_BE_CHANGED                0x00800000
+
+/*
+ * The crypto_control_ops structure contains pointers to control
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_control_ops {
+       void (*provider_status)(crypto_provider_handle_t, uint_t *);
+} __no_const crypto_control_ops_t;
+
+/*
+ * The crypto_ctx_ops structure contains points to context and context
+ * templates management operations for cryptographic providers. It is
+ * passed through the crypto_ops(9S) structure when providers register
+ * with the kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_ctx_ops {
+       int (*create_ctx_template)(crypto_provider_handle_t,
+           crypto_mechanism_t *, crypto_key_t *,
+           crypto_spi_ctx_template_t *, size_t *, crypto_req_handle_t);
+       int (*free_context)(crypto_ctx_t *);
+} __no_const crypto_ctx_ops_t;
+
+/*
+ * The crypto_digest_ops structure contains pointers to digest
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_digest_ops {
+       int (*digest_init)(crypto_ctx_t *, crypto_mechanism_t *,
+           crypto_req_handle_t);
+       int (*digest)(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
+           crypto_req_handle_t);
+       int (*digest_update)(crypto_ctx_t *, crypto_data_t *,
+           crypto_req_handle_t);
+       int (*digest_key)(crypto_ctx_t *, crypto_key_t *, crypto_req_handle_t);
+       int (*digest_final)(crypto_ctx_t *, crypto_data_t *,
+           crypto_req_handle_t);
+       int (*digest_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_data_t *,
+           crypto_data_t *, crypto_req_handle_t);
+} __no_const crypto_digest_ops_t;
+
+/*
+ * The crypto_cipher_ops structure contains pointers to encryption
+ * and decryption operations for cryptographic providers.  It is
+ * passed through the crypto_ops(9S) structure when providers register
+ * with the kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_cipher_ops {
+       int (*encrypt_init)(crypto_ctx_t *,
+           crypto_mechanism_t *, crypto_key_t *,
+           crypto_spi_ctx_template_t, crypto_req_handle_t);
+       int (*encrypt)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*encrypt_update)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*encrypt_final)(crypto_ctx_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*encrypt_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+           crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+       int (*decrypt_init)(crypto_ctx_t *,
+           crypto_mechanism_t *, crypto_key_t *,
+           crypto_spi_ctx_template_t, crypto_req_handle_t);
+       int (*decrypt)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*decrypt_update)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*decrypt_final)(crypto_ctx_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*decrypt_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+           crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+} __no_const crypto_cipher_ops_t;
+
+/*
+ * The crypto_mac_ops structure contains pointers to MAC
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_mac_ops {
+       int (*mac_init)(crypto_ctx_t *,
+           crypto_mechanism_t *, crypto_key_t *,
+           crypto_spi_ctx_template_t, crypto_req_handle_t);
+       int (*mac)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*mac_update)(crypto_ctx_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*mac_final)(crypto_ctx_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*mac_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+           crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+       int (*mac_verify_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+           crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+} __no_const crypto_mac_ops_t;
+
+/*
+ * The crypto_sign_ops structure contains pointers to signing
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_sign_ops {
+       int (*sign_init)(crypto_ctx_t *,
+           crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+       int (*sign)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*sign_update)(crypto_ctx_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*sign_final)(crypto_ctx_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*sign_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+           crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+       int (*sign_recover_init)(crypto_ctx_t *, crypto_mechanism_t *,
+           crypto_key_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+       int (*sign_recover)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*sign_recover_atomic)(crypto_provider_handle_t,
+           crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+           crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+} __no_const crypto_sign_ops_t;
+
+/*
+ * The crypto_verify_ops structure contains pointers to verify
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_verify_ops {
+       int (*verify_init)(crypto_ctx_t *,
+           crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+       int (*do_verify)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*verify_update)(crypto_ctx_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*verify_final)(crypto_ctx_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*verify_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+           crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+       int (*verify_recover_init)(crypto_ctx_t *, crypto_mechanism_t *,
+           crypto_key_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+       int (*verify_recover)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*verify_recover_atomic)(crypto_provider_handle_t,
+           crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+           crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_req_handle_t);
+} __no_const crypto_verify_ops_t;
+
+/*
+ * The crypto_dual_ops structure contains pointers to dual
+ * cipher and sign/verify operations for cryptographic providers.
+ * It is passed through the crypto_ops(9S) structure when
+ * providers register with the kernel using
+ * crypto_register_provider(9F).
+ */
+typedef struct crypto_dual_ops {
+       int (*digest_encrypt_update)(
+           crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*decrypt_digest_update)(
+           crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*sign_encrypt_update)(
+           crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
+           crypto_data_t *, crypto_req_handle_t);
+       int (*decrypt_verify_update)(
+           crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
+           crypto_data_t *, crypto_req_handle_t);
+} __no_const crypto_dual_ops_t;
+
+/*
+ * The crypto_dual_cipher_mac_ops structure contains pointers to dual
+ * cipher and MAC operations for cryptographic providers.
+ * It is passed through the crypto_ops(9S) structure when
+ * providers register with the kernel using
+ * crypto_register_provider(9F).
+ */
+typedef struct crypto_dual_cipher_mac_ops {
+       int (*encrypt_mac_init)(crypto_ctx_t *,
+           crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
+           crypto_key_t *, crypto_spi_ctx_template_t,
+           crypto_spi_ctx_template_t, crypto_req_handle_t);
+       int (*encrypt_mac)(crypto_ctx_t *,
+           crypto_data_t *, crypto_dual_data_t *, crypto_data_t *,
+           crypto_req_handle_t);
+       int (*encrypt_mac_update)(crypto_ctx_t *,
+           crypto_data_t *, crypto_dual_data_t *, crypto_req_handle_t);
+       int (*encrypt_mac_final)(crypto_ctx_t *,
+           crypto_dual_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*encrypt_mac_atomic)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
+           crypto_key_t *, crypto_data_t *, crypto_dual_data_t *,
+           crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+       int (*mac_decrypt_init)(crypto_ctx_t *,
+           crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
+           crypto_key_t *, crypto_spi_ctx_template_t,
+           crypto_spi_ctx_template_t, crypto_req_handle_t);
+       int (*mac_decrypt)(crypto_ctx_t *,
+           crypto_dual_data_t *, crypto_data_t *, crypto_data_t *,
+           crypto_req_handle_t);
+       int (*mac_decrypt_update)(crypto_ctx_t *,
+           crypto_dual_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*mac_decrypt_final)(crypto_ctx_t *,
+           crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
+       int (*mac_decrypt_atomic)(crypto_provider_handle_t,
+           crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+           crypto_mechanism_t *, crypto_key_t *, crypto_dual_data_t *,
+           crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_spi_ctx_template_t, crypto_req_handle_t);
+       int (*mac_verify_decrypt_atomic)(crypto_provider_handle_t,
+           crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
+           crypto_mechanism_t *, crypto_key_t *, crypto_dual_data_t *,
+           crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
+           crypto_spi_ctx_template_t, crypto_req_handle_t);
+} __no_const crypto_dual_cipher_mac_ops_t;
+
+/*
+ * The crypto_random_number_ops structure contains pointers to random
+ * number operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_random_number_ops {
+       int (*seed_random)(crypto_provider_handle_t, crypto_session_id_t,
+           uchar_t *, size_t, uint_t, uint32_t, crypto_req_handle_t);
+       int (*generate_random)(crypto_provider_handle_t, crypto_session_id_t,
+           uchar_t *, size_t, crypto_req_handle_t);
+} __no_const crypto_random_number_ops_t;
+
+/*
+ * Flag values for seed_random.
+ */
+#define        CRYPTO_SEED_NOW         0x00000001
+
+/*
+ * The crypto_session_ops structure contains pointers to session
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_session_ops {
+       int (*session_open)(crypto_provider_handle_t, crypto_session_id_t *,
+           crypto_req_handle_t);
+       int (*session_close)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_req_handle_t);
+       int (*session_login)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_user_type_t, char *, size_t, crypto_req_handle_t);
+       int (*session_logout)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_req_handle_t);
+} __no_const crypto_session_ops_t;
+
+/*
+ * The crypto_object_ops structure contains pointers to object
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_object_ops {
+       int (*object_create)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
+           crypto_req_handle_t);
+       int (*object_copy)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_object_id_t, crypto_object_attribute_t *, uint_t,
+           crypto_object_id_t *, crypto_req_handle_t);
+       int (*object_destroy)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_object_id_t, crypto_req_handle_t);
+       int (*object_get_size)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_object_id_t, size_t *, crypto_req_handle_t);
+       int (*object_get_attribute_value)(crypto_provider_handle_t,
+           crypto_session_id_t, crypto_object_id_t,
+           crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
+       int (*object_set_attribute_value)(crypto_provider_handle_t,
+           crypto_session_id_t, crypto_object_id_t,
+           crypto_object_attribute_t *,  uint_t, crypto_req_handle_t);
+       int (*object_find_init)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_object_attribute_t *, uint_t, void **,
+           crypto_req_handle_t);
+       int (*object_find)(crypto_provider_handle_t, void *,
+           crypto_object_id_t *, uint_t, uint_t *, crypto_req_handle_t);
+       int (*object_find_final)(crypto_provider_handle_t, void *,
+           crypto_req_handle_t);
+} __no_const crypto_object_ops_t;
+
+/*
+ * The crypto_key_ops structure contains pointers to key
+ * operations for cryptographic providers.  It is passed through
+ * the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_key_ops {
+       int (*key_generate)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
+           crypto_object_id_t *, crypto_req_handle_t);
+       int (*key_generate_pair)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
+           crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
+           crypto_object_id_t *, crypto_req_handle_t);
+       int (*key_wrap)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_object_id_t *,
+           uchar_t *, size_t *, crypto_req_handle_t);
+       int (*key_unwrap)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, uchar_t *, size_t *,
+           crypto_object_attribute_t *, uint_t,
+           crypto_object_id_t *, crypto_req_handle_t);
+       int (*key_derive)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
+           uint_t, crypto_object_id_t *, crypto_req_handle_t);
+       int (*key_check)(crypto_provider_handle_t, crypto_mechanism_t *,
+           crypto_key_t *);
+} __no_const crypto_key_ops_t;
+
+/*
+ * The crypto_provider_management_ops structure contains pointers
+ * to management operations for cryptographic providers.  It is passed
+ * through the crypto_ops(9S) structure when providers register with the
+ * kernel using crypto_register_provider(9F).
+ */
+typedef struct crypto_provider_management_ops {
+       int (*ext_info)(crypto_provider_handle_t,
+           crypto_provider_ext_info_t *, crypto_req_handle_t);
+       int (*init_token)(crypto_provider_handle_t, char *, size_t,
+           char *, crypto_req_handle_t);
+       int (*init_pin)(crypto_provider_handle_t, crypto_session_id_t,
+           char *, size_t, crypto_req_handle_t);
+       int (*set_pin)(crypto_provider_handle_t, crypto_session_id_t,
+           char *, size_t, char *, size_t, crypto_req_handle_t);
+} __no_const crypto_provider_management_ops_t;
+
+typedef struct crypto_mech_ops {
+       int (*copyin_mechanism)(crypto_provider_handle_t,
+           crypto_mechanism_t *, crypto_mechanism_t *, int *, int);
+       int (*copyout_mechanism)(crypto_provider_handle_t,
+           crypto_mechanism_t *, crypto_mechanism_t *, int *, int);
+       int (*free_mechanism)(crypto_provider_handle_t, crypto_mechanism_t *);
+} __no_const crypto_mech_ops_t;
+
+typedef struct crypto_nostore_key_ops {
+       int (*nostore_key_generate)(crypto_provider_handle_t,
+           crypto_session_id_t, crypto_mechanism_t *,
+           crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
+           uint_t, crypto_req_handle_t);
+       int (*nostore_key_generate_pair)(crypto_provider_handle_t,
+           crypto_session_id_t, crypto_mechanism_t *,
+           crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
+           uint_t, crypto_object_attribute_t *, uint_t,
+           crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
+       int (*nostore_key_derive)(crypto_provider_handle_t, crypto_session_id_t,
+           crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
+           uint_t, crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
+} __no_const crypto_nostore_key_ops_t;
+
+/*
+ * The crypto_ops(9S) structure contains the structures containing
+ * the pointers to functions implemented by cryptographic providers.
+ * It is specified as part of the crypto_provider_info(9S)
+ * supplied by a provider when it registers with the kernel
+ * by calling crypto_register_provider(9F).
+ */
+typedef struct crypto_ops_v1 {
+       crypto_control_ops_t                    *co_control_ops;
+       crypto_digest_ops_t                     *co_digest_ops;
+       crypto_cipher_ops_t                     *co_cipher_ops;
+       crypto_mac_ops_t                        *co_mac_ops;
+       crypto_sign_ops_t                       *co_sign_ops;
+       crypto_verify_ops_t                     *co_verify_ops;
+       crypto_dual_ops_t                       *co_dual_ops;
+       crypto_dual_cipher_mac_ops_t            *co_dual_cipher_mac_ops;
+       crypto_random_number_ops_t              *co_random_ops;
+       crypto_session_ops_t                    *co_session_ops;
+       crypto_object_ops_t                     *co_object_ops;
+       crypto_key_ops_t                        *co_key_ops;
+       crypto_provider_management_ops_t        *co_provider_ops;
+       crypto_ctx_ops_t                        *co_ctx_ops;
+} crypto_ops_v1_t;
+
+typedef struct crypto_ops_v2 {
+       crypto_ops_v1_t                         v1_ops;
+       crypto_mech_ops_t                       *co_mech_ops;
+} crypto_ops_v2_t;
+
+typedef struct crypto_ops_v3 {
+       crypto_ops_v2_t                         v2_ops;
+       crypto_nostore_key_ops_t                *co_nostore_key_ops;
+} crypto_ops_v3_t;
+
+typedef struct crypto_ops {
+       union {
+               crypto_ops_v3_t cou_v3;
+               crypto_ops_v2_t cou_v2;
+               crypto_ops_v1_t cou_v1;
+       } cou;
+} crypto_ops_t;
+
+#define        co_control_ops                  cou.cou_v1.co_control_ops
+#define        co_digest_ops                   cou.cou_v1.co_digest_ops
+#define        co_cipher_ops                   cou.cou_v1.co_cipher_ops
+#define        co_mac_ops                      cou.cou_v1.co_mac_ops
+#define        co_sign_ops                     cou.cou_v1.co_sign_ops
+#define        co_verify_ops                   cou.cou_v1.co_verify_ops
+#define        co_dual_ops                     cou.cou_v1.co_dual_ops
+#define        co_dual_cipher_mac_ops          cou.cou_v1.co_dual_cipher_mac_ops
+#define        co_random_ops                   cou.cou_v1.co_random_ops
+#define        co_session_ops                  cou.cou_v1.co_session_ops
+#define        co_object_ops                   cou.cou_v1.co_object_ops
+#define        co_key_ops                      cou.cou_v1.co_key_ops
+#define        co_provider_ops                 cou.cou_v1.co_provider_ops
+#define        co_ctx_ops                      cou.cou_v1.co_ctx_ops
+#define        co_mech_ops                     cou.cou_v2.co_mech_ops
+#define        co_nostore_key_ops              cou.cou_v3.co_nostore_key_ops
+
+/*
+ * The mechanism info structure crypto_mech_info_t contains a function group
+ * bit mask cm_func_group_mask. This field, of type crypto_func_group_t,
+ * specifies the provider entry point that can be used a particular
+ * mechanism. The function group mask is a combination of the following values.
+ */
+
+typedef uint32_t crypto_func_group_t;
+
+
+#define        CRYPTO_FG_ENCRYPT               0x00000001 /* encrypt_init() */
+#define        CRYPTO_FG_DECRYPT               0x00000002 /* decrypt_init() */
+#define        CRYPTO_FG_DIGEST                0x00000004 /* digest_init() */
+#define        CRYPTO_FG_SIGN                  0x00000008 /* sign_init() */
+#define        CRYPTO_FG_SIGN_RECOVER          0x00000010 /* sign_recover_init() */
+#define        CRYPTO_FG_VERIFY                0x00000020 /* verify_init() */
+#define        CRYPTO_FG_VERIFY_RECOVER        0x00000040 /* verify_recover_init() */
+#define        CRYPTO_FG_GENERATE              0x00000080 /* key_generate() */
+#define        CRYPTO_FG_GENERATE_KEY_PAIR     0x00000100 /* key_generate_pair() */
+#define        CRYPTO_FG_WRAP                  0x00000200 /* key_wrap() */
+#define        CRYPTO_FG_UNWRAP                0x00000400 /* key_unwrap() */
+#define        CRYPTO_FG_DERIVE                0x00000800 /* key_derive() */
+#define        CRYPTO_FG_MAC                   0x00001000 /* mac_init() */
+#define        CRYPTO_FG_ENCRYPT_MAC           0x00002000 /* encrypt_mac_init() */
+#define        CRYPTO_FG_MAC_DECRYPT           0x00004000 /* decrypt_mac_init() */
+#define        CRYPTO_FG_ENCRYPT_ATOMIC        0x00008000 /* encrypt_atomic() */
+#define        CRYPTO_FG_DECRYPT_ATOMIC        0x00010000 /* decrypt_atomic() */
+#define        CRYPTO_FG_MAC_ATOMIC            0x00020000 /* mac_atomic() */
+#define        CRYPTO_FG_DIGEST_ATOMIC         0x00040000 /* digest_atomic() */
+#define        CRYPTO_FG_SIGN_ATOMIC           0x00080000 /* sign_atomic() */
+#define        CRYPTO_FG_SIGN_RECOVER_ATOMIC   0x00100000 /* sign_recover_atomic() */
+#define        CRYPTO_FG_VERIFY_ATOMIC         0x00200000 /* verify_atomic() */
+#define        CRYPTO_FG_VERIFY_RECOVER_ATOMIC 0x00400000 /* verify_recover_atomic() */
+#define        CRYPTO_FG_ENCRYPT_MAC_ATOMIC    0x00800000 /* encrypt_mac_atomic() */
+#define        CRYPTO_FG_MAC_DECRYPT_ATOMIC    0x01000000 /* mac_decrypt_atomic() */
+#define        CRYPTO_FG_RESERVED              0x80000000
+
+/*
+ * Maximum length of the pi_provider_description field of the
+ * crypto_provider_info structure.
+ */
+#define        CRYPTO_PROVIDER_DESCR_MAX_LEN   64
+
+
+/* Bit mask for all the simple operations */
+#define        CRYPTO_FG_SIMPLEOP_MASK (CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | \
+    CRYPTO_FG_DIGEST | CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY | CRYPTO_FG_MAC | \
+    CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC |              \
+    CRYPTO_FG_MAC_ATOMIC | CRYPTO_FG_DIGEST_ATOMIC | CRYPTO_FG_SIGN_ATOMIC | \
+    CRYPTO_FG_VERIFY_ATOMIC)
+
+/* Bit mask for all the dual operations */
+#define        CRYPTO_FG_MAC_CIPHER_MASK       (CRYPTO_FG_ENCRYPT_MAC |        \
+    CRYPTO_FG_MAC_DECRYPT | CRYPTO_FG_ENCRYPT_MAC_ATOMIC |             \
+    CRYPTO_FG_MAC_DECRYPT_ATOMIC)
+
+/* Add other combos to CRYPTO_FG_DUAL_MASK */
+#define        CRYPTO_FG_DUAL_MASK     CRYPTO_FG_MAC_CIPHER_MASK
+
+/*
+ * The crypto_mech_info structure specifies one of the mechanisms
+ * supported by a cryptographic provider. The pi_mechanisms field of
+ * the crypto_provider_info structure contains a pointer to an array
+ * of crypto_mech_info's.
+ */
+typedef struct crypto_mech_info {
+       crypto_mech_name_t      cm_mech_name;
+       crypto_mech_type_t      cm_mech_number;
+       crypto_func_group_t     cm_func_group_mask;
+       ssize_t                 cm_min_key_length;
+       ssize_t                 cm_max_key_length;
+       uint32_t                cm_mech_flags;
+} crypto_mech_info_t;
+
+/* Alias the old name to the new name for compatibility. */
+#define        cm_keysize_unit cm_mech_flags
+
+/*
+ * The following is used by a provider that sets
+ * CRYPTO_HASH_NO_UPDATE. It needs to specify the maximum
+ * input data size it can digest in this field.
+ */
+#define        cm_max_input_length     cm_max_key_length
+
+/*
+ * crypto_kcf_provider_handle_t is a handle allocated by the kernel.
+ * It is returned after the provider registers with
+ * crypto_register_provider(), and must be specified by the provider
+ * when calling crypto_unregister_provider(), and
+ * crypto_provider_notification().
+ */
+typedef uint_t crypto_kcf_provider_handle_t;
+
+/*
+ * Provider information. Passed as argument to crypto_register_provider(9F).
+ * Describes the provider and its capabilities. Multiple providers can
+ * register for the same device instance. In this case, the same
+ * pi_provider_dev must be specified with a different pi_provider_handle.
+ */
+typedef struct crypto_provider_info_v1 {
+       uint_t                          pi_interface_version;
+       char                            *pi_provider_description;
+       crypto_provider_type_t          pi_provider_type;
+       crypto_provider_handle_t        pi_provider_handle;
+       crypto_ops_t                    *pi_ops_vector;
+       uint_t                          pi_mech_list_count;
+       crypto_mech_info_t              *pi_mechanisms;
+       uint_t                          pi_logical_provider_count;
+       crypto_kcf_provider_handle_t    *pi_logical_providers;
+} crypto_provider_info_v1_t;
+
+typedef struct crypto_provider_info_v2 {
+       crypto_provider_info_v1_t       v1_info;
+       uint_t                          pi_flags;
+} crypto_provider_info_v2_t;
+
+typedef struct crypto_provider_info {
+       union {
+               crypto_provider_info_v2_t piu_v2;
+               crypto_provider_info_v1_t piu_v1;
+       } piu;
+} crypto_provider_info_t;
+
+#define        pi_interface_version            piu.piu_v1.pi_interface_version
+#define        pi_provider_description         piu.piu_v1.pi_provider_description
+#define        pi_provider_type                piu.piu_v1.pi_provider_type
+#define        pi_provider_handle              piu.piu_v1.pi_provider_handle
+#define        pi_ops_vector                   piu.piu_v1.pi_ops_vector
+#define        pi_mech_list_count              piu.piu_v1.pi_mech_list_count
+#define        pi_mechanisms                   piu.piu_v1.pi_mechanisms
+#define        pi_logical_provider_count       piu.piu_v1.pi_logical_provider_count
+#define        pi_logical_providers            piu.piu_v1.pi_logical_providers
+#define        pi_flags                        piu.piu_v2.pi_flags
+
+/* hidden providers can only be accessed via a logical provider */
+#define        CRYPTO_HIDE_PROVIDER            0x00000001
+/*
+ * provider can not do multi-part digest (updates) and has a limit
+ * on maximum input data that it can digest.
+ */
+#define        CRYPTO_HASH_NO_UPDATE           0x00000002
+
+/* provider can handle the request without returning a CRYPTO_QUEUED */
+#define        CRYPTO_SYNCHRONOUS              0x00000004
+
+#define        CRYPTO_PIFLAGS_RESERVED2        0x40000000
+#define        CRYPTO_PIFLAGS_RESERVED1        0x80000000
+
+/*
+ * Provider status passed by a provider to crypto_provider_notification(9F)
+ * and returned by the provider_stauts(9E) entry point.
+ */
+#define        CRYPTO_PROVIDER_READY           0
+#define        CRYPTO_PROVIDER_BUSY            1
+#define        CRYPTO_PROVIDER_FAILED          2
+
+/*
+ * Functions exported by Solaris to cryptographic providers. Providers
+ * call these functions to register and unregister, notify the kernel
+ * of state changes, and notify the kernel when a asynchronous request
+ * completed.
+ */
+extern int crypto_register_provider(crypto_provider_info_t *,
+               crypto_kcf_provider_handle_t *);
+extern int crypto_unregister_provider(crypto_kcf_provider_handle_t);
+extern void crypto_provider_notification(crypto_kcf_provider_handle_t, uint_t);
+extern void crypto_op_notification(crypto_req_handle_t, int);
+extern int crypto_kmflag(crypto_req_handle_t);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_CRYPTO_SPI_H */
diff --git a/zfs/module/icp/include/sys/ia32/asm_linkage.h b/zfs/module/icp/include/sys/ia32/asm_linkage.h
new file mode 100644 (file)
index 0000000..f2dae70
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * 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.
+ */
+
+#ifndef _IA32_SYS_ASM_LINKAGE_H
+#define        _IA32_SYS_ASM_LINKAGE_H
+
+#include <sys/stack.h>
+#include <sys/trap.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _ASM    /* The remainder of this file is only for assembly files */
+
+/*
+ * make annoying differences in assembler syntax go away
+ */
+
+/*
+ * D16 and A16 are used to insert instructions prefixes; the
+ * macros help the assembler code be slightly more portable.
+ */
+#if !defined(__GNUC_AS__)
+/*
+ * /usr/ccs/bin/as prefixes are parsed as separate instructions
+ */
+#define        D16     data16;
+#define        A16     addr16;
+
+/*
+ * (There are some weird constructs in constant expressions)
+ */
+#define        _CONST(const)           [const]
+#define        _BITNOT(const)          -1!_CONST(const)
+#define        _MUL(a, b)              _CONST(a \* b)
+
+#else
+/*
+ * Why not use the 'data16' and 'addr16' prefixes .. well, the
+ * assembler doesn't quite believe in real mode, and thus argues with
+ * us about what we're trying to do.
+ */
+#define        D16     .byte   0x66;
+#define        A16     .byte   0x67;
+
+#define        _CONST(const)           (const)
+#define        _BITNOT(const)          ~_CONST(const)
+#define        _MUL(a, b)              _CONST(a * b)
+
+#endif
+
+/*
+ * C pointers are different sizes between i386 and amd64.
+ * These constants can be used to compute offsets into pointer arrays.
+ */
+#if defined(__amd64)
+#define        CLONGSHIFT      3
+#define        CLONGSIZE       8
+#define        CLONGMASK       7
+#elif defined(__i386)
+#define        CLONGSHIFT      2
+#define        CLONGSIZE       4
+#define        CLONGMASK       3
+#endif
+
+/*
+ * Since we know we're either ILP32 or LP64 ..
+ */
+#define        CPTRSHIFT       CLONGSHIFT
+#define        CPTRSIZE        CLONGSIZE
+#define        CPTRMASK        CLONGMASK
+
+#if CPTRSIZE != (1 << CPTRSHIFT) || CLONGSIZE != (1 << CLONGSHIFT)
+#error "inconsistent shift constants"
+#endif
+
+#if CPTRMASK != (CPTRSIZE - 1) || CLONGMASK != (CLONGSIZE - 1)
+#error "inconsistent mask constants"
+#endif
+
+#define        ASM_ENTRY_ALIGN 16
+
+/*
+ * SSE register alignment and save areas
+ */
+
+#define        XMM_SIZE        16
+#define        XMM_ALIGN       16
+
+#if defined(__amd64)
+
+#define        SAVE_XMM_PROLOG(sreg, nreg)                             \
+       subq    $_CONST(_MUL(XMM_SIZE, nreg)), %rsp;            \
+       movq    %rsp, sreg
+
+#define        RSTOR_XMM_EPILOG(sreg, nreg)                            \
+       addq    $_CONST(_MUL(XMM_SIZE, nreg)), %rsp
+
+#elif defined(__i386)
+
+#define        SAVE_XMM_PROLOG(sreg, nreg)                             \
+       subl    $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp; \
+       movl    %esp, sreg;                                     \
+       addl    $XMM_ALIGN, sreg;                               \
+       andl    $_BITNOT(XMM_ALIGN-1), sreg
+
+#define        RSTOR_XMM_EPILOG(sreg, nreg)                            \
+       addl    $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp;
+
+#endif /* __i386 */
+
+/*
+ * profiling causes definitions of the MCOUNT and RTMCOUNT
+ * particular to the type
+ */
+#ifdef GPROF
+
+#define        MCOUNT(x) \
+       pushl   %ebp; \
+       movl    %esp, %ebp; \
+       call    _mcount; \
+       popl    %ebp
+
+#endif /* GPROF */
+
+#ifdef PROF
+
+#define        MCOUNT(x) \
+/* CSTYLED */ \
+       .lcomm .L_/**/x/**/1, 4, 4; \
+       pushl   %ebp; \
+       movl    %esp, %ebp; \
+/* CSTYLED */ \
+       movl    $.L_/**/x/**/1, %edx; \
+       call    _mcount; \
+       popl    %ebp
+
+#endif /* PROF */
+
+/*
+ * if we are not profiling, MCOUNT should be defined to nothing
+ */
+#if !defined(PROF) && !defined(GPROF)
+#define        MCOUNT(x)
+#endif /* !defined(PROF) && !defined(GPROF) */
+
+#define        RTMCOUNT(x)     MCOUNT(x)
+
+/*
+ * Macro to define weak symbol aliases. These are similar to the ANSI-C
+ *     #pragma weak _name = name
+ * except a compiler can determine type. The assembler must be told. Hence,
+ * the second parameter must be the type of the symbol (i.e.: function,...)
+ */
+#define        ANSI_PRAGMA_WEAK(sym, stype)    \
+/* CSTYLED */ \
+       .weak   _/**/sym; \
+/* CSTYLED */ \
+       .type   _/**/sym, @stype; \
+/* CSTYLED */ \
+_/**/sym = sym
+
+/*
+ * Like ANSI_PRAGMA_WEAK(), but for unrelated names, as in:
+ *     #pragma weak sym1 = sym2
+ */
+#define        ANSI_PRAGMA_WEAK2(sym1, sym2, stype)    \
+       .weak   sym1; \
+       .type sym1, @stype; \
+sym1   = sym2
+
+/*
+ * ENTRY provides the standard procedure entry code and an easy way to
+ * insert the calls to mcount for profiling. ENTRY_NP is identical, but
+ * never calls mcount.
+ */
+#define        ENTRY(x) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x; \
+       .type   x, @function; \
+x:     MCOUNT(x)
+
+#define        ENTRY_NP(x) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x; \
+       .type   x, @function; \
+x:
+
+#define        RTENTRY(x) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x; \
+       .type   x, @function; \
+x:     RTMCOUNT(x)
+
+/*
+ * ENTRY2 is identical to ENTRY but provides two labels for the entry point.
+ */
+#define        ENTRY2(x, y) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x, y; \
+       .type   x, @function; \
+       .type   y, @function; \
+/* CSTYLED */ \
+x:     ; \
+y:     MCOUNT(x)
+
+#define        ENTRY_NP2(x, y) \
+       .text; \
+       .align  ASM_ENTRY_ALIGN; \
+       .globl  x, y; \
+       .type   x, @function; \
+       .type   y, @function; \
+/* CSTYLED */ \
+x:     ; \
+y:
+
+
+/*
+ * ALTENTRY provides for additional entry points.
+ */
+#define        ALTENTRY(x) \
+       .globl x; \
+       .type   x, @function; \
+x:
+
+/*
+ * DGDEF and DGDEF2 provide global data declarations.
+ *
+ * DGDEF provides a word aligned word of storage.
+ *
+ * DGDEF2 allocates "sz" bytes of storage with **NO** alignment.  This
+ * implies this macro is best used for byte arrays.
+ *
+ * DGDEF3 allocates "sz" bytes of storage with "algn" alignment.
+ */
+#define        DGDEF2(name, sz) \
+       .data; \
+       .globl  name; \
+       .type   name, @object; \
+       .size   name, sz; \
+name:
+
+#define        DGDEF3(name, sz, algn) \
+       .data; \
+       .align  algn; \
+       .globl  name; \
+       .type   name, @object; \
+       .size   name, sz; \
+name:
+
+#define        DGDEF(name)     DGDEF3(name, 4, 4)
+
+/*
+ * SET_SIZE trails a function and set the size for the ELF symbol table.
+ */
+#define        SET_SIZE(x) \
+       .size   x, [.-x]
+
+/*
+ * NWORD provides native word value.
+ */
+#if defined(__amd64)
+
+/*CSTYLED*/
+#define        NWORD   quad
+
+#elif defined(__i386)
+
+#define        NWORD   long
+
+#endif  /* __i386 */
+
+#endif /* _ASM */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IA32_SYS_ASM_LINKAGE_H */
diff --git a/zfs/module/icp/include/sys/ia32/stack.h b/zfs/module/icp/include/sys/ia32/stack.h
new file mode 100644 (file)
index 0000000..c4deb7b
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IA32_SYS_STACK_H
+#define        _IA32_SYS_STACK_H
+
+#if !defined(_ASM)
+
+#include <sys/types.h>
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * In the x86 world, a stack frame looks like this:
+ *
+ *             |--------------------------|
+ * 4n+8(%ebp) ->| argument word n         |
+ *             | ...                      |    (Previous frame)
+ *    8(%ebp) ->| argument word 0         |
+ *             |--------------------------|--------------------
+ *    4(%ebp) ->| return address          |
+ *             |--------------------------|
+ *    0(%ebp) ->| previous %ebp (optional) |
+ *             |--------------------------|
+ *   -4(%ebp) ->| unspecified             |    (Current frame)
+ *             | ...                      |
+ *    0(%esp) ->| variable size                   |
+ *             |--------------------------|
+ */
+
+/*
+ * Stack alignment macros.
+ */
+
+#define        STACK_ALIGN32           4
+#define        STACK_ENTRY_ALIGN32     4
+#define        STACK_BIAS32            0
+#define        SA32(x)                 (((x)+(STACK_ALIGN32-1)) & ~(STACK_ALIGN32-1))
+#define        STACK_RESERVE32         0
+#define        MINFRAME32              0
+
+#if defined(__amd64)
+
+/*
+ * In the amd64 world, a stack frame looks like this:
+ *
+ *             |--------------------------|
+ * 8n+16(%rbp)->| argument word n         |
+ *             | ...                      |    (Previous frame)
+ *   16(%rbp) ->| argument word 0         |
+ *             |--------------------------|--------------------
+ *    8(%rbp) ->| return address          |
+ *             |--------------------------|
+ *    0(%rbp) ->| previous %rbp            |
+ *             |--------------------------|
+ *   -8(%rbp) ->| unspecified             |    (Current frame)
+ *             | ...                      |
+ *    0(%rsp) ->| variable size                   |
+ *             |--------------------------|
+ * -128(%rsp) ->| reserved for function           |
+ *             |--------------------------|
+ *
+ * The end of the input argument area must be aligned on a 16-byte
+ * boundary; i.e. (%rsp - 8) % 16 == 0 at function entry.
+ *
+ * The 128-byte location beyond %rsp is considered to be reserved for
+ * functions and is NOT modified by signal handlers.  It can be used
+ * to store temporary data that is not needed across function calls.
+ */
+
+/*
+ * Stack alignment macros.
+ */
+
+#define        STACK_ALIGN64           16
+#define        STACK_ENTRY_ALIGN64     8
+#define        STACK_BIAS64            0
+#define        SA64(x)                 (((x)+(STACK_ALIGN64-1)) & ~(STACK_ALIGN64-1))
+#define        STACK_RESERVE64         128
+#define        MINFRAME64              0
+
+#define        STACK_ALIGN             STACK_ALIGN64
+#define        STACK_ENTRY_ALIGN       STACK_ENTRY_ALIGN64
+#define        STACK_BIAS              STACK_BIAS64
+#define        SA(x)                   SA64(x)
+#define        STACK_RESERVE           STACK_RESERVE64
+#define        MINFRAME                MINFRAME64
+
+#elif defined(__i386)
+
+#define        STACK_ALIGN             STACK_ALIGN32
+#define        STACK_ENTRY_ALIGN       STACK_ENTRY_ALIGN32
+#define        STACK_BIAS              STACK_BIAS32
+#define        SA(x)                   SA32(x)
+#define        STACK_RESERVE           STACK_RESERVE32
+#define        MINFRAME                MINFRAME32
+
+#endif /* __i386 */
+
+#if defined(_KERNEL) && !defined(_ASM)
+
+#if defined(DEBUG)
+#if STACK_ALIGN == 4
+#define        ASSERT_STACK_ALIGNED()                                          \
+       {                                                               \
+               uint32_t __tmp;                                         \
+               ASSERT((((uintptr_t)&__tmp) & (STACK_ALIGN - 1)) == 0); \
+       }
+#elif (STACK_ALIGN == 16) && (_LONG_DOUBLE_ALIGNMENT == 16)
+#define        ASSERT_STACK_ALIGNED()                                          \
+       {                                                               \
+               long double __tmp;                                      \
+               ASSERT((((uintptr_t)&__tmp) & (STACK_ALIGN - 1)) == 0); \
+       }
+#endif
+#else  /* DEBUG */
+#define        ASSERT_STACK_ALIGNED()
+#endif /* DEBUG */
+
+struct regs;
+
+void traceregs(struct regs *);
+void traceback(caddr_t);
+
+#endif /* defined(_KERNEL) && !defined(_ASM) */
+
+#define        STACK_GROWTH_DOWN /* stacks grow from high to low addresses */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IA32_SYS_STACK_H */
diff --git a/zfs/module/icp/include/sys/ia32/trap.h b/zfs/module/icp/include/sys/ia32/trap.h
new file mode 100644 (file)
index 0000000..55b9496
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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 (c) 1990, 1991 UNIX System Laboratories, Inc. */
+/*     Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T   */
+/*       All Rights Reserved   */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IA32_SYS_TRAP_H
+#define        _IA32_SYS_TRAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Trap type values
+ */
+
+#define        T_ZERODIV       0x0     /* #de  divide by 0 error               */
+#define        T_SGLSTP        0x1     /* #db  single step                     */
+#define        T_NMIFLT        0x2     /*      NMI                             */
+#define        T_BPTFLT        0x3     /* #bp  breakpoint fault, INT3 insn     */
+#define        T_OVFLW         0x4     /* #of  INTO overflow fault             */
+#define        T_BOUNDFLT      0x5     /* #br  BOUND insn fault                */
+#define        T_ILLINST       0x6     /* #ud  invalid opcode fault            */
+#define        T_NOEXTFLT      0x7     /* #nm  device not available: x87       */
+#define        T_DBLFLT        0x8     /* #df  double fault                    */
+#define        T_EXTOVRFLT     0x9     /*      [not generated: 386 only]       */
+#define        T_TSSFLT        0xa     /* #ts  invalid TSS fault               */
+#define        T_SEGFLT        0xb     /* #np  segment not present fault       */
+#define        T_STKFLT        0xc     /* #ss  stack fault                     */
+#define        T_GPFLT         0xd     /* #gp  general protection fault        */
+#define        T_PGFLT         0xe     /* #pf  page fault                      */
+#define        T_EXTERRFLT     0x10    /* #mf  x87 FPU error fault             */
+#define        T_ALIGNMENT     0x11    /* #ac  alignment check error           */
+#define        T_MCE           0x12    /* #mc  machine check exception         */
+#define        T_SIMDFPE       0x13    /* #xm  SSE/SSE exception               */
+#define        T_DBGENTR       0x14    /*      debugger entry                  */
+#define        T_ENDPERR       0x21    /*      emulated extension error flt    */
+#define        T_ENOEXTFLT     0x20    /*      emulated ext not present        */
+#define        T_FASTTRAP      0xd2    /*      fast system call                */
+#define        T_SYSCALLINT    0x91    /*      general system call             */
+#define        T_DTRACE_RET    0x7f    /*      DTrace pid return               */
+#define        T_INT80         0x80    /*      int80 handler for linux emulation */
+#define        T_SOFTINT       0x50fd  /*      pseudo softint trap type        */
+
+/*
+ * Pseudo traps.
+ */
+#define        T_INTERRUPT             0x100
+#define        T_FAULT                 0x200
+#define        T_AST                   0x400
+#define        T_SYSCALL               0x180
+
+
+/*
+ *  Values of error code on stack in case of page fault
+ */
+
+#define        PF_ERR_MASK     0x01    /* Mask for error bit */
+#define        PF_ERR_PAGE     0x00    /* page not present */
+#define        PF_ERR_PROT     0x01    /* protection error */
+#define        PF_ERR_WRITE    0x02    /* fault caused by write (else read) */
+#define        PF_ERR_USER     0x04    /* processor was in user mode */
+                               /*      (else supervisor) */
+#define        PF_ERR_EXEC     0x10    /* attempt to execute a No eXec page (AMD) */
+
+/*
+ *  Definitions for fast system call subfunctions
+ */
+#define        T_FNULL         0       /* Null trap for testing                */
+#define        T_FGETFP        1       /* Get emulated FP context              */
+#define        T_FSETFP        2       /* Set emulated FP context              */
+#define        T_GETHRTIME     3       /* Get high resolution time             */
+#define        T_GETHRVTIME    4       /* Get high resolution virtual time     */
+#define        T_GETHRESTIME   5       /* Get high resolution time             */
+#define        T_GETLGRP       6       /* Get home lgrpid                      */
+
+#define        T_LASTFAST      6       /* Last valid subfunction               */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IA32_SYS_TRAP_H */
diff --git a/zfs/module/icp/include/sys/modctl.h b/zfs/module/icp/include/sys/modctl.h
new file mode 100644 (file)
index 0000000..a0b94ef
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * 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.
+ */
+
+#ifndef        _SYS_MODCTL_H
+#define        _SYS_MODCTL_H
+
+/*
+ * loadable module support.
+ */
+
+#include <sys/zfs_context.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct modlmisc;
+struct modlinkage;
+
+/*
+ * The following structure defines the operations used by modctl
+ * to load and unload modules.  Each supported loadable module type
+ * requires a set of mod_ops.
+ */
+struct mod_ops {
+       int     (*modm_install)(struct modlmisc *, struct modlinkage *);
+       int     (*modm_remove)(struct modlmisc *, struct modlinkage *);
+       int     (*modm_info)(void *, struct modlinkage *, int *);
+};
+
+/*
+ * The defined set of mod_ops structures for each loadable module type
+ * Defined in modctl.c
+ */
+extern struct mod_ops mod_brandops;
+#if defined(__i386) || defined(__amd64)
+extern struct mod_ops mod_cpuops;
+#endif
+extern struct mod_ops mod_cryptoops;
+extern struct mod_ops mod_driverops;
+extern struct mod_ops mod_execops;
+extern struct mod_ops mod_fsops;
+extern struct mod_ops mod_miscops;
+extern struct mod_ops mod_schedops;
+extern struct mod_ops mod_strmodops;
+extern struct mod_ops mod_syscallops;
+extern struct mod_ops mod_sockmodops;
+#ifdef _SYSCALL32_IMPL
+extern struct mod_ops mod_syscallops32;
+#endif
+extern struct mod_ops mod_dacfops;
+extern struct mod_ops mod_ippops;
+extern struct mod_ops mod_pcbeops;
+extern struct mod_ops mod_devfsops;
+extern struct mod_ops mod_kiconvops;
+
+/*
+ * Definitions for the module specific linkage structures.
+ * The first two fields are the same in all of the structures.
+ * The linkinfo is for informational purposes only and is returned by
+ * modctl with the MODINFO cmd.
+ */
+
+/* For cryptographic providers */
+struct modlcrypto {
+       struct mod_ops          *crypto_modops;
+       char                    *crypto_linkinfo;
+};
+
+/* For misc */
+struct modlmisc {
+       struct mod_ops          *misc_modops;
+       char                    *misc_linkinfo;
+};
+
+/*
+ * Revision number of loadable modules support.  This is the value
+ * that must be used in the modlinkage structure.
+ */
+#define        MODREV_1                1
+
+/*
+ * The modlinkage structure is the structure that the module writer
+ * provides to the routines to install, remove, and stat a module.
+ * The ml_linkage element is an array of pointers to linkage structures.
+ * For most modules there is only one linkage structure.  We allocate
+ * enough space for 3 linkage structures which happens to be the most
+ * we have in any sun supplied module.  For those modules with more
+ * than 3 linkage structures (which is very unlikely), a modlinkage
+ * structure must be kmem_alloc'd in the module wrapper to be big enough
+ * for all of the linkage structures.
+ */
+struct modlinkage {
+       int             ml_rev;         /* rev of loadable modules system */
+#ifdef _LP64
+       void            *ml_linkage[7]; /* more space in 64-bit OS */
+#else
+       void            *ml_linkage[4]; /* NULL terminated list of */
+                                       /* linkage structures */
+#endif
+};
+
+/*
+ * commands.  These are the commands supported by the modctl system call.
+ */
+#define        MODLOAD                 0
+#define        MODUNLOAD               1
+#define        MODINFO                 2
+#define        MODRESERVED             3
+#define        MODSETMINIROOT          4
+#define        MODADDMAJBIND           5
+#define        MODGETPATH              6
+#define        MODREADSYSBIND          7
+#define        MODGETMAJBIND           8
+#define        MODGETNAME              9
+#define        MODSIZEOF_DEVID         10
+#define        MODGETDEVID             11
+#define        MODSIZEOF_MINORNAME     12
+#define        MODGETMINORNAME         13
+#define        MODGETPATHLEN           14
+#define        MODEVENTS               15
+#define        MODGETFBNAME            16
+#define        MODREREADDACF           17
+#define        MODLOADDRVCONF          18
+#define        MODUNLOADDRVCONF        19
+#define        MODREMMAJBIND           20
+#define        MODDEVT2INSTANCE        21
+#define        MODGETDEVFSPATH_LEN     22
+#define        MODGETDEVFSPATH         23
+#define        MODDEVID2PATHS          24
+#define        MODSETDEVPOLICY         26
+#define        MODGETDEVPOLICY         27
+#define        MODALLOCPRIV            28
+#define        MODGETDEVPOLICYBYNAME   29
+#define        MODLOADMINORPERM        31
+#define        MODADDMINORPERM         32
+#define        MODREMMINORPERM         33
+#define        MODREMDRVCLEANUP        34
+#define        MODDEVEXISTS            35
+#define        MODDEVREADDIR           36
+#define        MODDEVNAME              37
+#define        MODGETDEVFSPATH_MI_LEN  38
+#define        MODGETDEVFSPATH_MI      39
+#define        MODRETIRE               40
+#define        MODUNRETIRE             41
+#define        MODISRETIRED            42
+#define        MODDEVEMPTYDIR          43
+#define        MODREMDRVALIAS          44
+
+/*
+ * sub cmds for MODEVENTS
+ */
+#define        MODEVENTS_FLUSH                         0
+#define        MODEVENTS_FLUSH_DUMP                    1
+#define        MODEVENTS_SET_DOOR_UPCALL_FILENAME      2
+#define        MODEVENTS_GETDATA                       3
+#define        MODEVENTS_FREEDATA                      4
+#define        MODEVENTS_POST_EVENT                    5
+#define        MODEVENTS_REGISTER_EVENT                6
+
+/*
+ * devname subcmds for MODDEVNAME
+ */
+#define        MODDEVNAME_LOOKUPDOOR   0
+#define        MODDEVNAME_DEVFSADMNODE 1
+#define        MODDEVNAME_NSMAPS       2
+#define        MODDEVNAME_PROFILE      3
+#define        MODDEVNAME_RECONFIG     4
+#define        MODDEVNAME_SYSAVAIL     5
+
+
+/*
+ * Data structure passed to modconfig command in kernel to build devfs tree
+ */
+
+struct aliases {
+       struct aliases *a_next;
+       char *a_name;
+       int a_len;
+};
+
+#define        MAXMODCONFNAME  256
+
+struct modconfig {
+       char drvname[MAXMODCONFNAME];
+       char drvclass[MAXMODCONFNAME];
+       int major;
+       int flags;
+       int num_aliases;
+       struct aliases *ap;
+};
+
+#if defined(_SYSCALL32)
+
+struct aliases32 {
+       caddr32_t a_next;
+       caddr32_t a_name;
+       int32_t a_len;
+};
+
+struct modconfig32 {
+       char drvname[MAXMODCONFNAME];
+       char drvclass[MAXMODCONFNAME];
+       int32_t major;
+       int32_t flags;
+       int32_t num_aliases;
+       caddr32_t ap;
+};
+
+#endif /* _SYSCALL32 */
+
+/* flags for modconfig */
+#define        MOD_UNBIND_OVERRIDE     0x01            /* fail unbind if in use */
+
+/*
+ * Max module path length
+ */
+#define        MOD_MAXPATH     256
+
+/*
+ * Default search path for modules ADDITIONAL to the directory
+ * where the kernel components we booted from are.
+ *
+ * Most often, this will be "/platform/{platform}/kernel /kernel /usr/kernel",
+ * but we don't wire it down here.
+ */
+#define        MOD_DEFPATH     "/kernel /usr/kernel"
+
+/*
+ * Default file name extension for autoloading modules.
+ */
+#define        MOD_DEFEXT      ""
+
+/*
+ * Parameters for modinfo
+ */
+#define        MODMAXNAMELEN 32                /* max module name length */
+#define        MODMAXLINKINFOLEN 32            /* max link info length */
+
+/*
+ * Module specific information.
+ */
+struct modspecific_info {
+       char    msi_linkinfo[MODMAXLINKINFOLEN]; /* name in linkage struct */
+       int     msi_p0;                 /* module specific information */
+};
+
+/*
+ * Structure returned by modctl with MODINFO command.
+ */
+#define        MODMAXLINK 10                   /* max linkages modinfo can handle */
+
+struct modinfo {
+       int                mi_info;             /* Flags for info wanted */
+       int                mi_state;            /* Flags for module state */
+       int                mi_id;               /* id of this loaded module */
+       int                mi_nextid;           /* id of next module or -1 */
+       caddr_t            mi_base;             /* virtual addr of text */
+       size_t             mi_size;             /* size of module in bytes */
+       int                mi_rev;              /* loadable modules rev */
+       int                mi_loadcnt;          /* # of times loaded */
+       char               mi_name[MODMAXNAMELEN]; /* name of module */
+       struct modspecific_info mi_msinfo[MODMAXLINK];
+                                               /* mod specific info */
+};
+
+
+#if defined(_SYSCALL32)
+
+#define        MODMAXNAMELEN32 32              /* max module name length */
+#define        MODMAXLINKINFOLEN32 32          /* max link info length */
+#define        MODMAXLINK32 10                 /* max linkages modinfo can handle */
+
+struct modspecific_info32 {
+       char    msi_linkinfo[MODMAXLINKINFOLEN32]; /* name in linkage struct */
+       int32_t msi_p0;                 /* module specific information */
+};
+
+struct modinfo32 {
+       int32_t            mi_info;             /* Flags for info wanted */
+       int32_t            mi_state;            /* Flags for module state */
+       int32_t            mi_id;               /* id of this loaded module */
+       int32_t            mi_nextid;           /* id of next module or -1 */
+       caddr32_t          mi_base;             /* virtual addr of text */
+       uint32_t           mi_size;             /* size of module in bytes */
+       int32_t            mi_rev;              /* loadable modules rev */
+       int32_t            mi_loadcnt;          /* # of times loaded */
+       char               mi_name[MODMAXNAMELEN32]; /* name of module */
+       struct modspecific_info32 mi_msinfo[MODMAXLINK32];
+                                               /* mod specific info */
+};
+
+#endif /* _SYSCALL32 */
+
+/* Values for mi_info flags */
+#define        MI_INFO_ONE     1
+#define        MI_INFO_ALL     2
+#define        MI_INFO_CNT     4
+#define        MI_INFO_LINKAGE 8       /* used internally to extract modlinkage */
+/*
+ * MI_INFO_NOBASE indicates caller does not need mi_base. Failure to use this
+ * flag may lead 32-bit apps to receive an EOVERFLOW error from modctl(MODINFO)
+ * when used with a 64-bit kernel.
+ */
+#define        MI_INFO_NOBASE  16
+
+/* Values for mi_state */
+#define        MI_LOADED       1
+#define        MI_INSTALLED    2
+
+/*
+ * Macros to vector to the appropriate module specific routine.
+ */
+#define        MODL_INSTALL(MODL, MODLP) \
+       (*(MODL)->misc_modops->modm_install)(MODL, MODLP)
+#define        MODL_REMOVE(MODL, MODLP) \
+       (*(MODL)->misc_modops->modm_remove)(MODL, MODLP)
+#define        MODL_INFO(MODL, MODLP, P0) \
+       (*(MODL)->misc_modops->modm_info)(MODL, MODLP, P0)
+
+/*
+ * Definitions for stubs
+ */
+struct mod_stub_info {
+       uintptr_t mods_func_adr;
+       struct mod_modinfo *mods_modinfo;
+       uintptr_t mods_stub_adr;
+       int (*mods_errfcn)(void);
+       int mods_flag;                  /* flags defined below */
+};
+
+/*
+ * Definitions for mods_flag.
+ */
+#define        MODS_WEAK       0x01            /* weak stub (not loaded if called) */
+#define        MODS_NOUNLOAD   0x02            /* module not unloadable (no _fini()) */
+#define        MODS_INSTALLED  0x10            /* module installed */
+
+struct mod_modinfo {
+       char *modm_module_name;
+       struct modctl *mp;
+       struct mod_stub_info modm_stubs[1];
+};
+
+struct modctl_list {
+       struct modctl_list *modl_next;
+       struct modctl *modl_modp;
+};
+
+/*
+ * Structure to manage a loadable module.
+ * Note: the module (mod_mp) structure's "text" and "text_size" information
+ * are replicated in the modctl structure so that mod_containing_pc()
+ * doesn't have to grab any locks (modctls are persistent; modules are not.)
+ */
+typedef struct modctl {
+       struct modctl   *mod_next;      /* &modules based list */
+       struct modctl   *mod_prev;
+       int             mod_id;
+       void            *mod_mp;
+       kthread_t       *mod_inprogress_thread;
+       struct mod_modinfo *mod_modinfo;
+       struct modlinkage *mod_linkage;
+       char            *mod_filename;
+       char            *mod_modname;
+
+       char            mod_busy;       /* inprogress_thread has locked */
+       char            mod_want;       /* someone waiting for unlock */
+       char            mod_prim;       /* primary module */
+
+       int             mod_ref;        /* ref count - from dependent or stub */
+
+       char            mod_loaded;     /* module in memory */
+       char            mod_installed;  /* post _init pre _fini */
+       char            mod_loadflags;
+       char            mod_delay_unload;       /* deferred unload */
+
+       struct modctl_list *mod_requisites;     /* mods this one depends on. */
+       void            *__unused;      /* NOTE: reuse (same size) is OK, */
+                                       /* deletion causes mdb.vs.core issues */
+       int             mod_loadcnt;    /* number of times mod was loaded */
+       int             mod_nenabled;   /* # of enabled DTrace probes in mod */
+       char            *mod_text;
+       size_t          mod_text_size;
+
+       int             mod_gencount;   /* # times loaded/unloaded */
+       struct modctl   *mod_requisite_loading; /* mod circular dependency */
+} modctl_t;
+
+/*
+ * mod_loadflags
+ */
+
+#define        MOD_NOAUTOUNLOAD        0x1     /* Auto mod-unloader skips this mod */
+#define        MOD_NONOTIFY            0x2     /* No krtld notifications on (un)load */
+#define        MOD_NOUNLOAD            0x4     /* Assume EBUSY for all _fini's */
+
+#define        MOD_BIND_HASHSIZE       64
+#define        MOD_BIND_HASHMASK       (MOD_BIND_HASHSIZE-1)
+
+typedef int modid_t;
+
+/*
+ * global function and data declarations
+ */
+extern kmutex_t mod_lock;
+
+extern char *systemfile;
+extern char **syscallnames;
+extern int moddebug;
+
+/*
+ * this is the head of a doubly linked list.  Only the next and prev
+ * pointers are used
+ */
+extern modctl_t modules;
+
+/*
+ * Only the following are part of the DDI/DKI
+ */
+extern int     mod_install(struct modlinkage *);
+extern int     mod_remove(struct modlinkage *);
+extern int     mod_info(struct modlinkage *, struct modinfo *);
+
+/*
+ * bit definitions for moddebug.
+ */
+#define        MODDEBUG_LOADMSG        0x80000000      /* print "[un]loading..." msg */
+#define        MODDEBUG_ERRMSG         0x40000000      /* print detailed error msgs */
+#define        MODDEBUG_LOADMSG2       0x20000000      /* print 2nd level msgs */
+#define        MODDEBUG_RETIRE         0x10000000      /* print retire msgs */
+#define        MODDEBUG_BINDING        0x00040000      /* driver/alias binding */
+#define        MODDEBUG_FINI_EBUSY     0x00020000      /* pretend fini returns EBUSY */
+#define        MODDEBUG_NOAUL_IPP      0x00010000      /* no Autounloading ipp mods */
+#define        MODDEBUG_NOAUL_DACF     0x00008000      /* no Autounloading dacf mods */
+#define        MODDEBUG_KEEPTEXT       0x00004000      /* keep text after unloading */
+#define        MODDEBUG_NOAUL_DRV      0x00001000      /* no Autounloading Drivers */
+#define        MODDEBUG_NOAUL_EXEC     0x00000800      /* no Autounloading Execs */
+#define        MODDEBUG_NOAUL_FS       0x00000400      /* no Autounloading File sys */
+#define        MODDEBUG_NOAUL_MISC     0x00000200      /* no Autounloading misc */
+#define        MODDEBUG_NOAUL_SCHED    0x00000100      /* no Autounloading scheds */
+#define        MODDEBUG_NOAUL_STR      0x00000080      /* no Autounloading streams */
+#define        MODDEBUG_NOAUL_SYS      0x00000040      /* no Autounloading syscalls */
+#define        MODDEBUG_NOCTF          0x00000020      /* do not load CTF debug data */
+#define        MODDEBUG_NOAUTOUNLOAD   0x00000010      /* no autounloading at all */
+#define        MODDEBUG_DDI_MOD        0x00000008      /* ddi_mod{open,sym,close} */
+#define        MODDEBUG_MP_MATCH       0x00000004      /* dev_minorperm */
+#define        MODDEBUG_MINORPERM      0x00000002      /* minor perm modctls */
+#define        MODDEBUG_USERDEBUG      0x00000001      /* bpt after init_module() */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MODCTL_H */
diff --git a/zfs/module/icp/include/sys/modhash.h b/zfs/module/icp/include/sys/modhash.h
new file mode 100644 (file)
index 0000000..06b52ff
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_MODHASH_H
+#define        _SYS_MODHASH_H
+
+/*
+ * Generic hash implementation for the kernel.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+
+/*
+ * Opaque data types for storing keys and values
+ */
+typedef void *mod_hash_val_t;
+typedef void *mod_hash_key_t;
+
+/*
+ * Opaque data type for reservation
+ */
+typedef void *mod_hash_hndl_t;
+
+/*
+ * Opaque type for hash itself.
+ */
+struct mod_hash;
+typedef struct mod_hash mod_hash_t;
+
+/*
+ * String hash table
+ */
+mod_hash_t *mod_hash_create_strhash_nodtr(char *, size_t,
+       void (*)(mod_hash_val_t));
+mod_hash_t *mod_hash_create_strhash(char *, size_t, void (*)(mod_hash_val_t));
+void mod_hash_destroy_strhash(mod_hash_t *);
+int mod_hash_strkey_cmp(mod_hash_key_t, mod_hash_key_t);
+void mod_hash_strkey_dtor(mod_hash_key_t);
+void mod_hash_strval_dtor(mod_hash_val_t);
+uint_t mod_hash_bystr(void *, mod_hash_key_t);
+
+/*
+ * Pointer hash table
+ */
+mod_hash_t *mod_hash_create_ptrhash(char *, size_t, void (*)(mod_hash_val_t),
+       size_t);
+void mod_hash_destroy_ptrhash(mod_hash_t *);
+int mod_hash_ptrkey_cmp(mod_hash_key_t, mod_hash_key_t);
+uint_t mod_hash_byptr(void *, mod_hash_key_t);
+
+/*
+ * ID hash table
+ */
+mod_hash_t *mod_hash_create_idhash(char *, size_t, void (*)(mod_hash_val_t));
+void mod_hash_destroy_idhash(mod_hash_t *);
+int mod_hash_idkey_cmp(mod_hash_key_t, mod_hash_key_t);
+uint_t mod_hash_byid(void *, mod_hash_key_t);
+uint_t mod_hash_iddata_gen(size_t);
+
+/*
+ * Hash management functions
+ */
+mod_hash_t *mod_hash_create_extended(char *, size_t, void (*)(mod_hash_key_t),
+       void (*)(mod_hash_val_t), uint_t (*)(void *, mod_hash_key_t), void *,
+       int (*)(mod_hash_key_t, mod_hash_key_t), int);
+
+void mod_hash_destroy_hash(mod_hash_t *);
+void mod_hash_clear(mod_hash_t *);
+
+/*
+ * Null key and value destructors
+ */
+void mod_hash_null_keydtor(mod_hash_key_t);
+void mod_hash_null_valdtor(mod_hash_val_t);
+
+/*
+ * Basic hash operations
+ */
+
+/*
+ * Error codes for insert, remove, find, destroy.
+ */
+#define        MH_ERR_NOMEM -1
+#define        MH_ERR_DUPLICATE -2
+#define        MH_ERR_NOTFOUND -3
+
+/*
+ * Return codes for hash walkers
+ */
+#define        MH_WALK_CONTINUE 0
+#define        MH_WALK_TERMINATE 1
+
+/*
+ * Basic hash operations
+ */
+int mod_hash_insert(mod_hash_t *, mod_hash_key_t, mod_hash_val_t);
+int mod_hash_replace(mod_hash_t *, mod_hash_key_t, mod_hash_val_t);
+int mod_hash_remove(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
+int mod_hash_destroy(mod_hash_t *, mod_hash_key_t);
+int mod_hash_find(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
+int mod_hash_find_cb(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *,
+       void (*)(mod_hash_key_t, mod_hash_val_t));
+int mod_hash_find_cb_rval(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *,
+       int (*)(mod_hash_key_t, mod_hash_val_t), int *);
+void mod_hash_walk(mod_hash_t *,
+       uint_t (*)(mod_hash_key_t, mod_hash_val_t *, void *), void *);
+
+/*
+ * Reserving hash operations
+ */
+int mod_hash_reserve(mod_hash_t *, mod_hash_hndl_t *);
+int mod_hash_reserve_nosleep(mod_hash_t *, mod_hash_hndl_t *);
+void mod_hash_cancel(mod_hash_t *, mod_hash_hndl_t *);
+int mod_hash_insert_reserve(mod_hash_t *, mod_hash_key_t, mod_hash_val_t,
+       mod_hash_hndl_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MODHASH_H */
diff --git a/zfs/module/icp/include/sys/modhash_impl.h b/zfs/module/icp/include/sys/modhash_impl.h
new file mode 100644 (file)
index 0000000..3130773
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_MODHASH_IMPL_H
+#define        _SYS_MODHASH_IMPL_H
+
+/*
+ * Internal details for the kernel's generic hash implementation.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/zfs_context.h>
+#include <sys/modhash.h>
+
+struct mod_hash_entry {
+       mod_hash_key_t mhe_key;                 /* stored hash key      */
+       mod_hash_val_t mhe_val;                 /* stored hash value    */
+       struct mod_hash_entry *mhe_next;        /* next item in chain   */
+};
+
+struct mod_hash_stat {
+       ulong_t mhs_hit;        /* tried a 'find' and it succeeded */
+       ulong_t mhs_miss;       /* tried a 'find' but it failed */
+       ulong_t mhs_coll;       /* occur when insert fails because of dup's */
+       ulong_t mhs_nelems;     /* total number of stored key/value pairs */
+       ulong_t mhs_nomem;      /* number of times kmem_alloc failed */
+};
+
+struct mod_hash {
+       krwlock_t       mh_contents;    /* lock protecting contents */
+       char            *mh_name;       /* hash name */
+       int             mh_sleep;       /* kmem_alloc flag */
+       size_t          mh_nchains;     /* # of elements in mh_entries */
+
+       /* key and val destructor */
+       void    (*mh_kdtor)(mod_hash_key_t);
+       void    (*mh_vdtor)(mod_hash_val_t);
+
+       /* key comparator */
+       int     (*mh_keycmp)(mod_hash_key_t, mod_hash_key_t);
+
+       /* hash algorithm, and algorithm-private data */
+       uint_t  (*mh_hashalg)(void *, mod_hash_key_t);
+       void    *mh_hashalg_data;
+
+       struct mod_hash *mh_next;       /* next hash in list */
+
+       struct mod_hash_stat mh_stat;
+
+       struct mod_hash_entry *mh_entries[1];
+};
+
+/*
+ * MH_SIZE()
+ *     Compute the size of a mod_hash_t, in bytes, given the number of
+ *     elements it contains.
+ */
+#define        MH_SIZE(n) \
+       (sizeof (mod_hash_t) + ((n) - 1) * (sizeof (struct mod_hash_entry *)))
+
+/*
+ * Module initialization; called once.
+ */
+void mod_hash_fini(void);
+void mod_hash_init(void);
+
+/*
+ * Internal routines.  Use directly with care.
+ */
+uint_t i_mod_hash(mod_hash_t *, mod_hash_key_t);
+int i_mod_hash_insert_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t,
+    mod_hash_hndl_t);
+int i_mod_hash_remove_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
+int i_mod_hash_find_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
+void i_mod_hash_walk_nosync(mod_hash_t *, uint_t (*)(mod_hash_key_t,
+    mod_hash_val_t *, void *), void *);
+void i_mod_hash_clear_nosync(mod_hash_t *hash);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_MODHASH_IMPL_H */
diff --git a/zfs/module/icp/include/sys/stack.h b/zfs/module/icp/include/sys/stack.h
new file mode 100644 (file)
index 0000000..64fecf4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_STACK_H
+#define        _SYS_STACK_H
+
+#if defined(__i386) || defined(__amd64)
+
+#include <sys/ia32/stack.h>    /* XX64 x86/sys/stack.h */
+
+#endif
+
+#endif /* _SYS_STACK_H */
diff --git a/zfs/module/icp/include/sys/trap.h b/zfs/module/icp/include/sys/trap.h
new file mode 100644 (file)
index 0000000..7f9fd37
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef _SYS_TRAP_H
+#define        _SYS_TRAP_H
+
+#if defined(__i386) || defined(__amd64)
+
+#include <sys/ia32/trap.h>     /* XX64 x86/sys/trap.h */
+
+#endif
+
+#endif /* _SYS_TRAP_H */
diff --git a/zfs/module/icp/io/aes.c b/zfs/module/icp/io/aes.c
new file mode 100644 (file)
index 0000000..7fd66be
--- /dev/null
@@ -0,0 +1,1437 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * AES provider for the Kernel Cryptographic Framework (KCF)
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/icp.h>
+#include <modes/modes.h>
+#include <sys/modctl.h>
+#define        _AES_IMPL
+#include <aes/aes_impl.h>
+
+#define        CRYPTO_PROVIDER_NAME "aes"
+
+extern struct mod_ops mod_cryptoops;
+
+/*
+ * Module linkage information for the kernel.
+ */
+static struct modlcrypto modlcrypto = {
+       &mod_cryptoops,
+       "AES Kernel SW Provider"
+};
+
+static struct modlinkage modlinkage = {
+       MODREV_1, { (void *)&modlcrypto, NULL }
+};
+
+/*
+ * Mechanism info structure passed to KCF during registration.
+ */
+static crypto_mech_info_t aes_mech_info_tab[] = {
+       /* AES_ECB */
+       {SUN_CKM_AES_ECB, AES_ECB_MECH_INFO_TYPE,
+           CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
+           CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
+           AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* AES_CBC */
+       {SUN_CKM_AES_CBC, AES_CBC_MECH_INFO_TYPE,
+           CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
+           CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
+           AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* AES_CTR */
+       {SUN_CKM_AES_CTR, AES_CTR_MECH_INFO_TYPE,
+           CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
+           CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
+           AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* AES_CCM */
+       {SUN_CKM_AES_CCM, AES_CCM_MECH_INFO_TYPE,
+           CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
+           CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
+           AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* AES_GCM */
+       {SUN_CKM_AES_GCM, AES_GCM_MECH_INFO_TYPE,
+           CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
+           CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
+           AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* AES_GMAC */
+       {SUN_CKM_AES_GMAC, AES_GMAC_MECH_INFO_TYPE,
+           CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
+           CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC |
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC |
+           CRYPTO_FG_SIGN | CRYPTO_FG_SIGN_ATOMIC |
+           CRYPTO_FG_VERIFY | CRYPTO_FG_VERIFY_ATOMIC,
+           AES_MIN_KEY_BYTES, AES_MAX_KEY_BYTES, CRYPTO_KEYSIZE_UNIT_IN_BYTES}
+};
+
+/* operations are in-place if the output buffer is NULL */
+#define        AES_ARG_INPLACE(input, output)                          \
+       if ((output) == NULL)                                   \
+               (output) = (input);
+
+static void aes_provider_status(crypto_provider_handle_t, uint_t *);
+
+static crypto_control_ops_t aes_control_ops = {
+       aes_provider_status
+};
+
+static int aes_encrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
+    crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int aes_decrypt_init(crypto_ctx_t *, crypto_mechanism_t *,
+    crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int aes_common_init(crypto_ctx_t *, crypto_mechanism_t *,
+    crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t, boolean_t);
+static int aes_common_init_ctx(aes_ctx_t *, crypto_spi_ctx_template_t *,
+    crypto_mechanism_t *, crypto_key_t *, int, boolean_t);
+static int aes_encrypt_final(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int aes_decrypt_final(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+
+static int aes_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int aes_encrypt_update(crypto_ctx_t *, crypto_data_t *,
+    crypto_data_t *, crypto_req_handle_t);
+static int aes_encrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+    crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+static int aes_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int aes_decrypt_update(crypto_ctx_t *, crypto_data_t *,
+    crypto_data_t *, crypto_req_handle_t);
+static int aes_decrypt_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
+    crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+static crypto_cipher_ops_t aes_cipher_ops = {
+       aes_encrypt_init,
+       aes_encrypt,
+       aes_encrypt_update,
+       aes_encrypt_final,
+       aes_encrypt_atomic,
+       aes_decrypt_init,
+       aes_decrypt,
+       aes_decrypt_update,
+       aes_decrypt_final,
+       aes_decrypt_atomic
+};
+
+static int aes_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int aes_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+static crypto_mac_ops_t aes_mac_ops = {
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       aes_mac_atomic,
+       aes_mac_verify_atomic
+};
+
+static int aes_create_ctx_template(crypto_provider_handle_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
+    size_t *, crypto_req_handle_t);
+static int aes_free_context(crypto_ctx_t *);
+
+static crypto_ctx_ops_t aes_ctx_ops = {
+       aes_create_ctx_template,
+       aes_free_context
+};
+
+static crypto_ops_t aes_crypto_ops = {{{{{
+       &aes_control_ops,
+       NULL,
+       &aes_cipher_ops,
+       &aes_mac_ops,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       &aes_ctx_ops
+}}}}};
+
+static crypto_provider_info_t aes_prov_info = {{{{
+       CRYPTO_SPI_VERSION_1,
+       "AES Software Provider",
+       CRYPTO_SW_PROVIDER,
+       NULL,
+       &aes_crypto_ops,
+       sizeof (aes_mech_info_tab)/sizeof (crypto_mech_info_t),
+       aes_mech_info_tab
+}}}};
+
+static crypto_kcf_provider_handle_t aes_prov_handle = 0;
+static crypto_data_t null_crypto_data = { CRYPTO_DATA_RAW };
+
+int
+aes_mod_init(void)
+{
+       int ret;
+
+       if ((ret = mod_install(&modlinkage)) != 0)
+               return (ret);
+
+       /* Register with KCF.  If the registration fails, remove the module. */
+       if (crypto_register_provider(&aes_prov_info, &aes_prov_handle)) {
+               (void) mod_remove(&modlinkage);
+               return (EACCES);
+       }
+
+       return (0);
+}
+
+int
+aes_mod_fini(void)
+{
+       /* Unregister from KCF if module is registered */
+       if (aes_prov_handle != 0) {
+               if (crypto_unregister_provider(aes_prov_handle))
+                       return (EBUSY);
+
+               aes_prov_handle = 0;
+       }
+
+       return (mod_remove(&modlinkage));
+}
+
+static int
+aes_check_mech_param(crypto_mechanism_t *mechanism, aes_ctx_t **ctx, int kmflag)
+{
+       void *p = NULL;
+       boolean_t param_required = B_TRUE;
+       size_t param_len;
+       void *(*alloc_fun)(int);
+       int rv = CRYPTO_SUCCESS;
+
+       switch (mechanism->cm_type) {
+       case AES_ECB_MECH_INFO_TYPE:
+               param_required = B_FALSE;
+               alloc_fun = ecb_alloc_ctx;
+               break;
+       case AES_CBC_MECH_INFO_TYPE:
+               param_len = AES_BLOCK_LEN;
+               alloc_fun = cbc_alloc_ctx;
+               break;
+       case AES_CTR_MECH_INFO_TYPE:
+               param_len = sizeof (CK_AES_CTR_PARAMS);
+               alloc_fun = ctr_alloc_ctx;
+               break;
+       case AES_CCM_MECH_INFO_TYPE:
+               param_len = sizeof (CK_AES_CCM_PARAMS);
+               alloc_fun = ccm_alloc_ctx;
+               break;
+       case AES_GCM_MECH_INFO_TYPE:
+               param_len = sizeof (CK_AES_GCM_PARAMS);
+               alloc_fun = gcm_alloc_ctx;
+               break;
+       case AES_GMAC_MECH_INFO_TYPE:
+               param_len = sizeof (CK_AES_GMAC_PARAMS);
+               alloc_fun = gmac_alloc_ctx;
+               break;
+       default:
+               rv = CRYPTO_MECHANISM_INVALID;
+               return (rv);
+       }
+       if (param_required && mechanism->cm_param != NULL &&
+           mechanism->cm_param_len != param_len) {
+               rv = CRYPTO_MECHANISM_PARAM_INVALID;
+       }
+       if (ctx != NULL) {
+               p = (alloc_fun)(kmflag);
+               *ctx = p;
+       }
+       return (rv);
+}
+
+/*
+ * Initialize key schedules for AES
+ */
+static int
+init_keysched(crypto_key_t *key, void *newbie)
+{
+       /*
+        * Only keys by value are supported by this module.
+        */
+       switch (key->ck_format) {
+       case CRYPTO_KEY_RAW:
+               if (key->ck_length < AES_MINBITS ||
+                   key->ck_length > AES_MAXBITS) {
+                       return (CRYPTO_KEY_SIZE_RANGE);
+               }
+
+               /* key length must be either 128, 192, or 256 */
+               if ((key->ck_length & 63) != 0)
+                       return (CRYPTO_KEY_SIZE_RANGE);
+               break;
+       default:
+               return (CRYPTO_KEY_TYPE_INCONSISTENT);
+       }
+
+       aes_init_keysched(key->ck_data, key->ck_length, newbie);
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * KCF software provider control entry points.
+ */
+/* ARGSUSED */
+static void
+aes_provider_status(crypto_provider_handle_t provider, uint_t *status)
+{
+       *status = CRYPTO_PROVIDER_READY;
+}
+
+static int
+aes_encrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_spi_ctx_template_t template,
+    crypto_req_handle_t req) {
+       return (aes_common_init(ctx, mechanism, key, template, req, B_TRUE));
+}
+
+static int
+aes_decrypt_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_spi_ctx_template_t template,
+    crypto_req_handle_t req) {
+       return (aes_common_init(ctx, mechanism, key, template, req, B_FALSE));
+}
+
+
+
+/*
+ * KCF software provider encrypt entry points.
+ */
+static int
+aes_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_spi_ctx_template_t template,
+    crypto_req_handle_t req, boolean_t is_encrypt_init)
+{
+       aes_ctx_t *aes_ctx;
+       int rv;
+       int kmflag;
+
+       /*
+        * Only keys by value are supported by this module.
+        */
+       if (key->ck_format != CRYPTO_KEY_RAW) {
+               return (CRYPTO_KEY_TYPE_INCONSISTENT);
+       }
+
+       kmflag = crypto_kmflag(req);
+       if ((rv = aes_check_mech_param(mechanism, &aes_ctx, kmflag))
+           != CRYPTO_SUCCESS)
+               return (rv);
+
+       rv = aes_common_init_ctx(aes_ctx, template, mechanism, key, kmflag,
+           is_encrypt_init);
+       if (rv != CRYPTO_SUCCESS) {
+               crypto_free_mode_ctx(aes_ctx);
+               return (rv);
+       }
+
+       ctx->cc_provider_private = aes_ctx;
+
+       return (CRYPTO_SUCCESS);
+}
+
+static void
+aes_copy_block64(uint8_t *in, uint64_t *out)
+{
+       if (IS_P2ALIGNED(in, sizeof (uint64_t))) {
+               /* LINTED: pointer alignment */
+               out[0] = *(uint64_t *)&in[0];
+               /* LINTED: pointer alignment */
+               out[1] = *(uint64_t *)&in[8];
+       } else {
+               uint8_t *iv8 = (uint8_t *)&out[0];
+
+               AES_COPY_BLOCK(in, iv8);
+       }
+}
+
+
+static int
+aes_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
+    crypto_data_t *ciphertext, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_FAILED;
+
+       aes_ctx_t *aes_ctx;
+       size_t saved_length, saved_offset, length_needed;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+       aes_ctx = ctx->cc_provider_private;
+
+       /*
+        * For block ciphers, plaintext must be a multiple of AES block size.
+        * This test is only valid for ciphers whose blocksize is a power of 2.
+        */
+       if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE))
+           == 0) && (plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
+               return (CRYPTO_DATA_LEN_RANGE);
+
+       AES_ARG_INPLACE(plaintext, ciphertext);
+
+       /*
+        * We need to just return the length needed to store the output.
+        * We should not destroy the context for the following case.
+        */
+       switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) {
+       case CCM_MODE:
+               length_needed = plaintext->cd_length + aes_ctx->ac_mac_len;
+               break;
+       case GCM_MODE:
+               length_needed = plaintext->cd_length + aes_ctx->ac_tag_len;
+               break;
+       case GMAC_MODE:
+               if (plaintext->cd_length != 0)
+                       return (CRYPTO_ARGUMENTS_BAD);
+
+               length_needed = aes_ctx->ac_tag_len;
+               break;
+       default:
+               length_needed = plaintext->cd_length;
+       }
+
+       if (ciphertext->cd_length < length_needed) {
+               ciphertext->cd_length = length_needed;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       saved_length = ciphertext->cd_length;
+       saved_offset = ciphertext->cd_offset;
+
+       /*
+        * Do an update on the specified input data.
+        */
+       ret = aes_encrypt_update(ctx, plaintext, ciphertext, req);
+       if (ret != CRYPTO_SUCCESS) {
+               return (ret);
+       }
+
+       /*
+        * For CCM mode, aes_ccm_encrypt_final() will take care of any
+        * left-over unprocessed data, and compute the MAC
+        */
+       if (aes_ctx->ac_flags & CCM_MODE) {
+               /*
+                * ccm_encrypt_final() will compute the MAC and append
+                * it to existing ciphertext. So, need to adjust the left over
+                * length value accordingly
+                */
+
+               /* order of following 2 lines MUST not be reversed */
+               ciphertext->cd_offset = ciphertext->cd_length;
+               ciphertext->cd_length = saved_length - ciphertext->cd_length;
+               ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, ciphertext,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+               if (ret != CRYPTO_SUCCESS) {
+                       return (ret);
+               }
+
+               if (plaintext != ciphertext) {
+                       ciphertext->cd_length =
+                           ciphertext->cd_offset - saved_offset;
+               }
+               ciphertext->cd_offset = saved_offset;
+       } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
+               /*
+                * gcm_encrypt_final() will compute the MAC and append
+                * it to existing ciphertext. So, need to adjust the left over
+                * length value accordingly
+                */
+
+               /* order of following 2 lines MUST not be reversed */
+               ciphertext->cd_offset = ciphertext->cd_length;
+               ciphertext->cd_length = saved_length - ciphertext->cd_length;
+               ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, ciphertext,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+               if (ret != CRYPTO_SUCCESS) {
+                       return (ret);
+               }
+
+               if (plaintext != ciphertext) {
+                       ciphertext->cd_length =
+                           ciphertext->cd_offset - saved_offset;
+               }
+               ciphertext->cd_offset = saved_offset;
+       }
+
+       ASSERT(aes_ctx->ac_remainder_len == 0);
+       (void) aes_free_context(ctx);
+
+       return (ret);
+}
+
+
+static int
+aes_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
+    crypto_data_t *plaintext, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_FAILED;
+
+       aes_ctx_t *aes_ctx;
+       off_t saved_offset;
+       size_t saved_length, length_needed;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+       aes_ctx = ctx->cc_provider_private;
+
+       /*
+        * For block ciphers, plaintext must be a multiple of AES block size.
+        * This test is only valid for ciphers whose blocksize is a power of 2.
+        */
+       if (((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE))
+           == 0) && (ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0) {
+               return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
+       }
+
+       AES_ARG_INPLACE(ciphertext, plaintext);
+
+       /*
+        * Return length needed to store the output.
+        * Do not destroy context when plaintext buffer is too small.
+        *
+        * CCM:  plaintext is MAC len smaller than cipher text
+        * GCM:  plaintext is TAG len smaller than cipher text
+        * GMAC: plaintext length must be zero
+        */
+       switch (aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) {
+       case CCM_MODE:
+               length_needed = aes_ctx->ac_processed_data_len;
+               break;
+       case GCM_MODE:
+               length_needed = ciphertext->cd_length - aes_ctx->ac_tag_len;
+               break;
+       case GMAC_MODE:
+               if (plaintext->cd_length != 0)
+                       return (CRYPTO_ARGUMENTS_BAD);
+
+               length_needed = 0;
+               break;
+       default:
+               length_needed = ciphertext->cd_length;
+       }
+
+       if (plaintext->cd_length < length_needed) {
+               plaintext->cd_length = length_needed;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       saved_offset = plaintext->cd_offset;
+       saved_length = plaintext->cd_length;
+
+       /*
+        * Do an update on the specified input data.
+        */
+       ret = aes_decrypt_update(ctx, ciphertext, plaintext, req);
+       if (ret != CRYPTO_SUCCESS) {
+               goto cleanup;
+       }
+
+       if (aes_ctx->ac_flags & CCM_MODE) {
+               ASSERT(aes_ctx->ac_processed_data_len == aes_ctx->ac_data_len);
+               ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len);
+
+               /* order of following 2 lines MUST not be reversed */
+               plaintext->cd_offset = plaintext->cd_length;
+               plaintext->cd_length = saved_length - plaintext->cd_length;
+
+               ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, plaintext,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+               if (ret == CRYPTO_SUCCESS) {
+                       if (plaintext != ciphertext) {
+                               plaintext->cd_length =
+                                   plaintext->cd_offset - saved_offset;
+                       }
+               } else {
+                       plaintext->cd_length = saved_length;
+               }
+
+               plaintext->cd_offset = saved_offset;
+       } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
+               /* order of following 2 lines MUST not be reversed */
+               plaintext->cd_offset = plaintext->cd_length;
+               plaintext->cd_length = saved_length - plaintext->cd_length;
+
+               ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, plaintext,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+               if (ret == CRYPTO_SUCCESS) {
+                       if (plaintext != ciphertext) {
+                               plaintext->cd_length =
+                                   plaintext->cd_offset - saved_offset;
+                       }
+               } else {
+                       plaintext->cd_length = saved_length;
+               }
+
+               plaintext->cd_offset = saved_offset;
+       }
+
+       ASSERT(aes_ctx->ac_remainder_len == 0);
+
+cleanup:
+       (void) aes_free_context(ctx);
+
+       return (ret);
+}
+
+
+/* ARGSUSED */
+static int
+aes_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
+    crypto_data_t *ciphertext, crypto_req_handle_t req)
+{
+       off_t saved_offset;
+       size_t saved_length, out_len;
+       int ret = CRYPTO_SUCCESS;
+       aes_ctx_t *aes_ctx;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+       aes_ctx = ctx->cc_provider_private;
+
+       AES_ARG_INPLACE(plaintext, ciphertext);
+
+       /* compute number of bytes that will hold the ciphertext */
+       out_len = aes_ctx->ac_remainder_len;
+       out_len += plaintext->cd_length;
+       out_len &= ~(AES_BLOCK_LEN - 1);
+
+       /* return length needed to store the output */
+       if (ciphertext->cd_length < out_len) {
+               ciphertext->cd_length = out_len;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       saved_offset = ciphertext->cd_offset;
+       saved_length = ciphertext->cd_length;
+
+       /*
+        * Do the AES update on the specified input data.
+        */
+       switch (plaintext->cd_format) {
+       case CRYPTO_DATA_RAW:
+               ret = crypto_update_iov(ctx->cc_provider_private,
+                   plaintext, ciphertext, aes_encrypt_contiguous_blocks,
+                   aes_copy_block64);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = crypto_update_uio(ctx->cc_provider_private,
+                   plaintext, ciphertext, aes_encrypt_contiguous_blocks,
+                   aes_copy_block64);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       /*
+        * Since AES counter mode is a stream cipher, we call
+        * ctr_mode_final() to pick up any remaining bytes.
+        * It is an internal function that does not destroy
+        * the context like *normal* final routines.
+        */
+       if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
+               ret = ctr_mode_final((ctr_ctx_t *)aes_ctx,
+                   ciphertext, aes_encrypt_block);
+       }
+
+       if (ret == CRYPTO_SUCCESS) {
+               if (plaintext != ciphertext)
+                       ciphertext->cd_length =
+                           ciphertext->cd_offset - saved_offset;
+       } else {
+               ciphertext->cd_length = saved_length;
+       }
+       ciphertext->cd_offset = saved_offset;
+
+       return (ret);
+}
+
+
+static int
+aes_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
+    crypto_data_t *plaintext, crypto_req_handle_t req)
+{
+       off_t saved_offset;
+       size_t saved_length, out_len;
+       int ret = CRYPTO_SUCCESS;
+       aes_ctx_t *aes_ctx;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+       aes_ctx = ctx->cc_provider_private;
+
+       AES_ARG_INPLACE(ciphertext, plaintext);
+
+       /*
+        * Compute number of bytes that will hold the plaintext.
+        * This is not necessary for CCM, GCM, and GMAC since these
+        * mechanisms never return plaintext for update operations.
+        */
+       if ((aes_ctx->ac_flags & (CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) {
+               out_len = aes_ctx->ac_remainder_len;
+               out_len += ciphertext->cd_length;
+               out_len &= ~(AES_BLOCK_LEN - 1);
+
+               /* return length needed to store the output */
+               if (plaintext->cd_length < out_len) {
+                       plaintext->cd_length = out_len;
+                       return (CRYPTO_BUFFER_TOO_SMALL);
+               }
+       }
+
+       saved_offset = plaintext->cd_offset;
+       saved_length = plaintext->cd_length;
+
+       if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE))
+               gcm_set_kmflag((gcm_ctx_t *)aes_ctx, crypto_kmflag(req));
+
+       /*
+        * Do the AES update on the specified input data.
+        */
+       switch (ciphertext->cd_format) {
+       case CRYPTO_DATA_RAW:
+               ret = crypto_update_iov(ctx->cc_provider_private,
+                   ciphertext, plaintext, aes_decrypt_contiguous_blocks,
+                   aes_copy_block64);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = crypto_update_uio(ctx->cc_provider_private,
+                   ciphertext, plaintext, aes_decrypt_contiguous_blocks,
+                   aes_copy_block64);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       /*
+        * Since AES counter mode is a stream cipher, we call
+        * ctr_mode_final() to pick up any remaining bytes.
+        * It is an internal function that does not destroy
+        * the context like *normal* final routines.
+        */
+       if ((aes_ctx->ac_flags & CTR_MODE) && (aes_ctx->ac_remainder_len > 0)) {
+               ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, plaintext,
+                   aes_encrypt_block);
+               if (ret == CRYPTO_DATA_LEN_RANGE)
+                       ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
+       }
+
+       if (ret == CRYPTO_SUCCESS) {
+               if (ciphertext != plaintext)
+                       plaintext->cd_length =
+                           plaintext->cd_offset - saved_offset;
+       } else {
+               plaintext->cd_length = saved_length;
+       }
+       plaintext->cd_offset = saved_offset;
+
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+aes_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
+    crypto_req_handle_t req)
+{
+       aes_ctx_t *aes_ctx;
+       int ret;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+       aes_ctx = ctx->cc_provider_private;
+
+       if (data->cd_format != CRYPTO_DATA_RAW &&
+           data->cd_format != CRYPTO_DATA_UIO) {
+               return (CRYPTO_ARGUMENTS_BAD);
+       }
+
+       if (aes_ctx->ac_flags & CTR_MODE) {
+               if (aes_ctx->ac_remainder_len > 0) {
+                       ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data,
+                           aes_encrypt_block);
+                       if (ret != CRYPTO_SUCCESS)
+                               return (ret);
+               }
+       } else if (aes_ctx->ac_flags & CCM_MODE) {
+               ret = ccm_encrypt_final((ccm_ctx_t *)aes_ctx, data,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+               if (ret != CRYPTO_SUCCESS) {
+                       return (ret);
+               }
+       } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
+               size_t saved_offset = data->cd_offset;
+
+               ret = gcm_encrypt_final((gcm_ctx_t *)aes_ctx, data,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+               if (ret != CRYPTO_SUCCESS) {
+                       return (ret);
+               }
+               data->cd_length = data->cd_offset - saved_offset;
+               data->cd_offset = saved_offset;
+       } else {
+               /*
+                * There must be no unprocessed plaintext.
+                * This happens if the length of the last data is
+                * not a multiple of the AES block length.
+                */
+               if (aes_ctx->ac_remainder_len > 0) {
+                       return (CRYPTO_DATA_LEN_RANGE);
+               }
+               data->cd_length = 0;
+       }
+
+       (void) aes_free_context(ctx);
+
+       return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+aes_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
+    crypto_req_handle_t req)
+{
+       aes_ctx_t *aes_ctx;
+       int ret;
+       off_t saved_offset;
+       size_t saved_length;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+       aes_ctx = ctx->cc_provider_private;
+
+       if (data->cd_format != CRYPTO_DATA_RAW &&
+           data->cd_format != CRYPTO_DATA_UIO) {
+               return (CRYPTO_ARGUMENTS_BAD);
+       }
+
+       /*
+        * There must be no unprocessed ciphertext.
+        * This happens if the length of the last ciphertext is
+        * not a multiple of the AES block length.
+        */
+       if (aes_ctx->ac_remainder_len > 0) {
+               if ((aes_ctx->ac_flags & CTR_MODE) == 0)
+                       return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
+               else {
+                       ret = ctr_mode_final((ctr_ctx_t *)aes_ctx, data,
+                           aes_encrypt_block);
+                       if (ret == CRYPTO_DATA_LEN_RANGE)
+                               ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
+                       if (ret != CRYPTO_SUCCESS)
+                               return (ret);
+               }
+       }
+
+       if (aes_ctx->ac_flags & CCM_MODE) {
+               /*
+                * This is where all the plaintext is returned, make sure
+                * the plaintext buffer is big enough
+                */
+               size_t pt_len = aes_ctx->ac_data_len;
+               if (data->cd_length < pt_len) {
+                       data->cd_length = pt_len;
+                       return (CRYPTO_BUFFER_TOO_SMALL);
+               }
+
+               ASSERT(aes_ctx->ac_processed_data_len == pt_len);
+               ASSERT(aes_ctx->ac_processed_mac_len == aes_ctx->ac_mac_len);
+               saved_offset = data->cd_offset;
+               saved_length = data->cd_length;
+               ret = ccm_decrypt_final((ccm_ctx_t *)aes_ctx, data,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+               if (ret == CRYPTO_SUCCESS) {
+                       data->cd_length = data->cd_offset - saved_offset;
+               } else {
+                       data->cd_length = saved_length;
+               }
+
+               data->cd_offset = saved_offset;
+               if (ret != CRYPTO_SUCCESS) {
+                       return (ret);
+               }
+       } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) {
+               /*
+                * This is where all the plaintext is returned, make sure
+                * the plaintext buffer is big enough
+                */
+               gcm_ctx_t *ctx = (gcm_ctx_t *)aes_ctx;
+               size_t pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
+
+               if (data->cd_length < pt_len) {
+                       data->cd_length = pt_len;
+                       return (CRYPTO_BUFFER_TOO_SMALL);
+               }
+
+               saved_offset = data->cd_offset;
+               saved_length = data->cd_length;
+               ret = gcm_decrypt_final((gcm_ctx_t *)aes_ctx, data,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block);
+               if (ret == CRYPTO_SUCCESS) {
+                       data->cd_length = data->cd_offset - saved_offset;
+               } else {
+                       data->cd_length = saved_length;
+               }
+
+               data->cd_offset = saved_offset;
+               if (ret != CRYPTO_SUCCESS) {
+                       return (ret);
+               }
+       }
+
+
+       if ((aes_ctx->ac_flags & (CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) == 0) {
+               data->cd_length = 0;
+       }
+
+       (void) aes_free_context(ctx);
+
+       return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+aes_encrypt_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
+    crypto_spi_ctx_template_t template, crypto_req_handle_t req)
+{
+       aes_ctx_t aes_ctx;      /* on the stack */
+       off_t saved_offset;
+       size_t saved_length;
+       size_t length_needed;
+       int ret;
+
+       AES_ARG_INPLACE(plaintext, ciphertext);
+
+       /*
+        * CTR, CCM, GCM, and GMAC modes do not require that plaintext
+        * be a multiple of AES block size.
+        */
+       switch (mechanism->cm_type) {
+       case AES_CTR_MECH_INFO_TYPE:
+       case AES_CCM_MECH_INFO_TYPE:
+       case AES_GCM_MECH_INFO_TYPE:
+       case AES_GMAC_MECH_INFO_TYPE:
+               break;
+       default:
+               if ((plaintext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
+                       return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
+               return (ret);
+
+       bzero(&aes_ctx, sizeof (aes_ctx_t));
+
+       ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
+           crypto_kmflag(req), B_TRUE);
+       if (ret != CRYPTO_SUCCESS)
+               return (ret);
+
+       switch (mechanism->cm_type) {
+       case AES_CCM_MECH_INFO_TYPE:
+               length_needed = plaintext->cd_length + aes_ctx.ac_mac_len;
+               break;
+       case AES_GMAC_MECH_INFO_TYPE:
+               if (plaintext->cd_length != 0)
+                       return (CRYPTO_ARGUMENTS_BAD);
+               /* FALLTHRU */
+       case AES_GCM_MECH_INFO_TYPE:
+               length_needed = plaintext->cd_length + aes_ctx.ac_tag_len;
+               break;
+       default:
+               length_needed = plaintext->cd_length;
+       }
+
+       /* return size of buffer needed to store output */
+       if (ciphertext->cd_length < length_needed) {
+               ciphertext->cd_length = length_needed;
+               ret = CRYPTO_BUFFER_TOO_SMALL;
+               goto out;
+       }
+
+       saved_offset = ciphertext->cd_offset;
+       saved_length = ciphertext->cd_length;
+
+       /*
+        * Do an update on the specified input data.
+        */
+       switch (plaintext->cd_format) {
+       case CRYPTO_DATA_RAW:
+               ret = crypto_update_iov(&aes_ctx, plaintext, ciphertext,
+                   aes_encrypt_contiguous_blocks, aes_copy_block64);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = crypto_update_uio(&aes_ctx, plaintext, ciphertext,
+                   aes_encrypt_contiguous_blocks, aes_copy_block64);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret == CRYPTO_SUCCESS) {
+               if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {
+                       ret = ccm_encrypt_final((ccm_ctx_t *)&aes_ctx,
+                           ciphertext, AES_BLOCK_LEN, aes_encrypt_block,
+                           aes_xor_block);
+                       if (ret != CRYPTO_SUCCESS)
+                               goto out;
+                       ASSERT(aes_ctx.ac_remainder_len == 0);
+               } else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
+                   mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) {
+                       ret = gcm_encrypt_final((gcm_ctx_t *)&aes_ctx,
+                           ciphertext, AES_BLOCK_LEN, aes_encrypt_block,
+                           aes_copy_block, aes_xor_block);
+                       if (ret != CRYPTO_SUCCESS)
+                               goto out;
+                       ASSERT(aes_ctx.ac_remainder_len == 0);
+               } else if (mechanism->cm_type == AES_CTR_MECH_INFO_TYPE) {
+                       if (aes_ctx.ac_remainder_len > 0) {
+                               ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx,
+                                   ciphertext, aes_encrypt_block);
+                               if (ret != CRYPTO_SUCCESS)
+                                       goto out;
+                       }
+               } else {
+                       ASSERT(aes_ctx.ac_remainder_len == 0);
+               }
+
+               if (plaintext != ciphertext) {
+                       ciphertext->cd_length =
+                           ciphertext->cd_offset - saved_offset;
+               }
+       } else {
+               ciphertext->cd_length = saved_length;
+       }
+       ciphertext->cd_offset = saved_offset;
+
+out:
+       if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
+               bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
+               kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
+       }
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+aes_decrypt_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
+    crypto_spi_ctx_template_t template, crypto_req_handle_t req)
+{
+       aes_ctx_t aes_ctx;      /* on the stack */
+       off_t saved_offset;
+       size_t saved_length;
+       size_t length_needed;
+       int ret;
+
+       AES_ARG_INPLACE(ciphertext, plaintext);
+
+       /*
+        * CCM, GCM, CTR, and GMAC modes do not require that ciphertext
+        * be a multiple of AES block size.
+        */
+       switch (mechanism->cm_type) {
+       case AES_CTR_MECH_INFO_TYPE:
+       case AES_CCM_MECH_INFO_TYPE:
+       case AES_GCM_MECH_INFO_TYPE:
+       case AES_GMAC_MECH_INFO_TYPE:
+               break;
+       default:
+               if ((ciphertext->cd_length & (AES_BLOCK_LEN - 1)) != 0)
+                       return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
+       }
+
+       if ((ret = aes_check_mech_param(mechanism, NULL, 0)) != CRYPTO_SUCCESS)
+               return (ret);
+
+       bzero(&aes_ctx, sizeof (aes_ctx_t));
+
+       ret = aes_common_init_ctx(&aes_ctx, template, mechanism, key,
+           crypto_kmflag(req), B_FALSE);
+       if (ret != CRYPTO_SUCCESS)
+               return (ret);
+
+       switch (mechanism->cm_type) {
+       case AES_CCM_MECH_INFO_TYPE:
+               length_needed = aes_ctx.ac_data_len;
+               break;
+       case AES_GCM_MECH_INFO_TYPE:
+               length_needed = ciphertext->cd_length - aes_ctx.ac_tag_len;
+               break;
+       case AES_GMAC_MECH_INFO_TYPE:
+               if (plaintext->cd_length != 0)
+                       return (CRYPTO_ARGUMENTS_BAD);
+               length_needed = 0;
+               break;
+       default:
+               length_needed = ciphertext->cd_length;
+       }
+
+       /* return size of buffer needed to store output */
+       if (plaintext->cd_length < length_needed) {
+               plaintext->cd_length = length_needed;
+               ret = CRYPTO_BUFFER_TOO_SMALL;
+               goto out;
+       }
+
+       saved_offset = plaintext->cd_offset;
+       saved_length = plaintext->cd_length;
+
+       if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
+           mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE)
+               gcm_set_kmflag((gcm_ctx_t *)&aes_ctx, crypto_kmflag(req));
+
+       /*
+        * Do an update on the specified input data.
+        */
+       switch (ciphertext->cd_format) {
+       case CRYPTO_DATA_RAW:
+               ret = crypto_update_iov(&aes_ctx, ciphertext, plaintext,
+                   aes_decrypt_contiguous_blocks, aes_copy_block64);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = crypto_update_uio(&aes_ctx, ciphertext, plaintext,
+                   aes_decrypt_contiguous_blocks, aes_copy_block64);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret == CRYPTO_SUCCESS) {
+               if (mechanism->cm_type == AES_CCM_MECH_INFO_TYPE) {
+                       ASSERT(aes_ctx.ac_processed_data_len
+                           == aes_ctx.ac_data_len);
+                       ASSERT(aes_ctx.ac_processed_mac_len
+                           == aes_ctx.ac_mac_len);
+                       ret = ccm_decrypt_final((ccm_ctx_t *)&aes_ctx,
+                           plaintext, AES_BLOCK_LEN, aes_encrypt_block,
+                           aes_copy_block, aes_xor_block);
+                       ASSERT(aes_ctx.ac_remainder_len == 0);
+                       if ((ret == CRYPTO_SUCCESS) &&
+                           (ciphertext != plaintext)) {
+                               plaintext->cd_length =
+                                   plaintext->cd_offset - saved_offset;
+                       } else {
+                               plaintext->cd_length = saved_length;
+                       }
+               } else if (mechanism->cm_type == AES_GCM_MECH_INFO_TYPE ||
+                   mechanism->cm_type == AES_GMAC_MECH_INFO_TYPE) {
+                       ret = gcm_decrypt_final((gcm_ctx_t *)&aes_ctx,
+                           plaintext, AES_BLOCK_LEN, aes_encrypt_block,
+                           aes_xor_block);
+                       ASSERT(aes_ctx.ac_remainder_len == 0);
+                       if ((ret == CRYPTO_SUCCESS) &&
+                           (ciphertext != plaintext)) {
+                               plaintext->cd_length =
+                                   plaintext->cd_offset - saved_offset;
+                       } else {
+                               plaintext->cd_length = saved_length;
+                       }
+               } else if (mechanism->cm_type != AES_CTR_MECH_INFO_TYPE) {
+                       ASSERT(aes_ctx.ac_remainder_len == 0);
+                       if (ciphertext != plaintext)
+                               plaintext->cd_length =
+                                   plaintext->cd_offset - saved_offset;
+               } else {
+                       if (aes_ctx.ac_remainder_len > 0) {
+                               ret = ctr_mode_final((ctr_ctx_t *)&aes_ctx,
+                                   plaintext, aes_encrypt_block);
+                               if (ret == CRYPTO_DATA_LEN_RANGE)
+                                       ret = CRYPTO_ENCRYPTED_DATA_LEN_RANGE;
+                               if (ret != CRYPTO_SUCCESS)
+                                       goto out;
+                       }
+                       if (ciphertext != plaintext)
+                               plaintext->cd_length =
+                                   plaintext->cd_offset - saved_offset;
+               }
+       } else {
+               plaintext->cd_length = saved_length;
+       }
+       plaintext->cd_offset = saved_offset;
+
+out:
+       if (aes_ctx.ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
+               bzero(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
+               kmem_free(aes_ctx.ac_keysched, aes_ctx.ac_keysched_len);
+       }
+
+       if (aes_ctx.ac_flags & CCM_MODE) {
+               if (aes_ctx.ac_pt_buf != NULL) {
+                       vmem_free(aes_ctx.ac_pt_buf, aes_ctx.ac_data_len);
+               }
+       } else if (aes_ctx.ac_flags & (GCM_MODE|GMAC_MODE)) {
+               if (((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf != NULL) {
+                       vmem_free(((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf,
+                           ((gcm_ctx_t *)&aes_ctx)->gcm_pt_buf_len);
+               }
+       }
+
+       return (ret);
+}
+
+/*
+ * KCF software provider context template entry points.
+ */
+/* ARGSUSED */
+static int
+aes_create_ctx_template(crypto_provider_handle_t provider,
+    crypto_mechanism_t *mechanism, crypto_key_t *key,
+    crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
+{
+       void *keysched;
+       size_t size;
+       int rv;
+
+       if (mechanism->cm_type != AES_ECB_MECH_INFO_TYPE &&
+           mechanism->cm_type != AES_CBC_MECH_INFO_TYPE &&
+           mechanism->cm_type != AES_CTR_MECH_INFO_TYPE &&
+           mechanism->cm_type != AES_CCM_MECH_INFO_TYPE &&
+           mechanism->cm_type != AES_GCM_MECH_INFO_TYPE &&
+           mechanism->cm_type != AES_GMAC_MECH_INFO_TYPE)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       if ((keysched = aes_alloc_keysched(&size,
+           crypto_kmflag(req))) == NULL) {
+               return (CRYPTO_HOST_MEMORY);
+       }
+
+       /*
+        * Initialize key schedule.  Key length information is stored
+        * in the key.
+        */
+       if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
+               bzero(keysched, size);
+               kmem_free(keysched, size);
+               return (rv);
+       }
+
+       *tmpl = keysched;
+       *tmpl_size = size;
+
+       return (CRYPTO_SUCCESS);
+}
+
+
+static int
+aes_free_context(crypto_ctx_t *ctx)
+{
+       aes_ctx_t *aes_ctx = ctx->cc_provider_private;
+
+       if (aes_ctx != NULL) {
+               if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
+                       ASSERT(aes_ctx->ac_keysched_len != 0);
+                       bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
+                       kmem_free(aes_ctx->ac_keysched,
+                           aes_ctx->ac_keysched_len);
+               }
+               crypto_free_mode_ctx(aes_ctx);
+               ctx->cc_provider_private = NULL;
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+
+static int
+aes_common_init_ctx(aes_ctx_t *aes_ctx, crypto_spi_ctx_template_t *template,
+    crypto_mechanism_t *mechanism, crypto_key_t *key, int kmflag,
+    boolean_t is_encrypt_init)
+{
+       int rv = CRYPTO_SUCCESS;
+       void *keysched;
+       size_t size = 0;
+
+       if (template == NULL) {
+               if ((keysched = aes_alloc_keysched(&size, kmflag)) == NULL)
+                       return (CRYPTO_HOST_MEMORY);
+               /*
+                * Initialize key schedule.
+                * Key length is stored in the key.
+                */
+               if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
+                       kmem_free(keysched, size);
+                       return (rv);
+               }
+
+               aes_ctx->ac_flags |= PROVIDER_OWNS_KEY_SCHEDULE;
+               aes_ctx->ac_keysched_len = size;
+       } else {
+               keysched = template;
+       }
+       aes_ctx->ac_keysched = keysched;
+
+       switch (mechanism->cm_type) {
+       case AES_CBC_MECH_INFO_TYPE:
+               rv = cbc_init_ctx((cbc_ctx_t *)aes_ctx, mechanism->cm_param,
+                   mechanism->cm_param_len, AES_BLOCK_LEN, aes_copy_block64);
+               break;
+       case AES_CTR_MECH_INFO_TYPE: {
+               CK_AES_CTR_PARAMS *pp;
+
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (CK_AES_CTR_PARAMS)) {
+                       return (CRYPTO_MECHANISM_PARAM_INVALID);
+               }
+               pp = (CK_AES_CTR_PARAMS *)(void *)mechanism->cm_param;
+               rv = ctr_init_ctx((ctr_ctx_t *)aes_ctx, pp->ulCounterBits,
+                   pp->cb, aes_copy_block);
+               break;
+       }
+       case AES_CCM_MECH_INFO_TYPE:
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (CK_AES_CCM_PARAMS)) {
+                       return (CRYPTO_MECHANISM_PARAM_INVALID);
+               }
+               rv = ccm_init_ctx((ccm_ctx_t *)aes_ctx, mechanism->cm_param,
+                   kmflag, is_encrypt_init, AES_BLOCK_LEN, aes_encrypt_block,
+                   aes_xor_block);
+               break;
+       case AES_GCM_MECH_INFO_TYPE:
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (CK_AES_GCM_PARAMS)) {
+                       return (CRYPTO_MECHANISM_PARAM_INVALID);
+               }
+               rv = gcm_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+               break;
+       case AES_GMAC_MECH_INFO_TYPE:
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (CK_AES_GMAC_PARAMS)) {
+                       return (CRYPTO_MECHANISM_PARAM_INVALID);
+               }
+               rv = gmac_init_ctx((gcm_ctx_t *)aes_ctx, mechanism->cm_param,
+                   AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block,
+                   aes_xor_block);
+               break;
+       case AES_ECB_MECH_INFO_TYPE:
+               aes_ctx->ac_flags |= ECB_MODE;
+       }
+
+       if (rv != CRYPTO_SUCCESS) {
+               if (aes_ctx->ac_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
+                       bzero(keysched, size);
+                       kmem_free(keysched, size);
+               }
+       }
+
+       return (rv);
+}
+
+static int
+process_gmac_mech(crypto_mechanism_t *mech, crypto_data_t *data,
+    CK_AES_GCM_PARAMS *gcm_params)
+{
+       /* LINTED: pointer alignment */
+       CK_AES_GMAC_PARAMS *params = (CK_AES_GMAC_PARAMS *)mech->cm_param;
+
+       if (mech->cm_type != AES_GMAC_MECH_INFO_TYPE)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       if (mech->cm_param_len != sizeof (CK_AES_GMAC_PARAMS))
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+
+       if (params->pIv == NULL)
+               return (CRYPTO_MECHANISM_PARAM_INVALID);
+
+       gcm_params->pIv = params->pIv;
+       gcm_params->ulIvLen = AES_GMAC_IV_LEN;
+       gcm_params->ulTagBits = AES_GMAC_TAG_BITS;
+
+       if (data == NULL)
+               return (CRYPTO_SUCCESS);
+
+       if (data->cd_format != CRYPTO_DATA_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       gcm_params->pAAD = (uchar_t *)data->cd_raw.iov_base;
+       gcm_params->ulAADLen = data->cd_length;
+       return (CRYPTO_SUCCESS);
+}
+
+static int
+aes_mac_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
+    crypto_spi_ctx_template_t template, crypto_req_handle_t req)
+{
+       CK_AES_GCM_PARAMS gcm_params;
+       crypto_mechanism_t gcm_mech;
+       int rv;
+
+       if ((rv = process_gmac_mech(mechanism, data, &gcm_params))
+           != CRYPTO_SUCCESS)
+               return (rv);
+
+       gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE;
+       gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
+       gcm_mech.cm_param = (char *)&gcm_params;
+
+       return (aes_encrypt_atomic(provider, session_id, &gcm_mech,
+           key, &null_crypto_data, mac, template, req));
+}
+
+static int
+aes_mac_verify_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
+    crypto_spi_ctx_template_t template, crypto_req_handle_t req)
+{
+       CK_AES_GCM_PARAMS gcm_params;
+       crypto_mechanism_t gcm_mech;
+       int rv;
+
+       if ((rv = process_gmac_mech(mechanism, data, &gcm_params))
+           != CRYPTO_SUCCESS)
+               return (rv);
+
+       gcm_mech.cm_type = AES_GCM_MECH_INFO_TYPE;
+       gcm_mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
+       gcm_mech.cm_param = (char *)&gcm_params;
+
+       return (aes_decrypt_atomic(provider, session_id, &gcm_mech,
+           key, mac, &null_crypto_data, template, req));
+}
diff --git a/zfs/module/icp/io/edonr_mod.c b/zfs/module/icp/io/edonr_mod.c
new file mode 100644 (file)
index 0000000..19b5c96
--- /dev/null
@@ -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://opensource.org/licenses/CDDL-1.0.
+ * 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 2013 Saso Kiselkov. All rights reserved.
+ */
+
+#include <sys/modctl.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/spi.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/edonr.h>
+
+/*
+ * Unlike sha2 or skein, we won't expose edonr via the Kernel Cryptographic
+ * Framework (KCF), because Edon-R is *NOT* suitable for general-purpose
+ * cryptographic use. Users of Edon-R must interface directly to this module.
+ */
+
+static struct modlmisc modlmisc = {
+       &mod_cryptoops,
+       "Edon-R Message-Digest Algorithm"
+};
+
+static struct modlinkage modlinkage = {
+       MODREV_1, {&modlmisc, NULL}
+};
+
+int
+edonr_mod_init(void)
+{
+       int error;
+
+       if ((error = mod_install(&modlinkage)) != 0)
+               return (error);
+
+       return (0);
+}
+
+int
+edonr_mod_fini(void) {
+       return (mod_remove(&modlinkage));
+}
diff --git a/zfs/module/icp/io/sha1_mod.c b/zfs/module/icp/io/sha1_mod.c
new file mode 100644 (file)
index 0000000..a278dac
--- /dev/null
@@ -0,0 +1,1239 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/modctl.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/spi.h>
+
+#include <sha1/sha1.h>
+#include <sha1/sha1_impl.h>
+
+/*
+ * The sha1 module is created with two modlinkages:
+ * - a modlmisc that allows consumers to directly call the entry points
+ *   SHA1Init, SHA1Update, and SHA1Final.
+ * - a modlcrypto that allows the module to register with the Kernel
+ *   Cryptographic Framework (KCF) as a software provider for the SHA1
+ *   mechanisms.
+ */
+
+static struct modlcrypto modlcrypto = {
+       &mod_cryptoops,
+       "SHA1 Kernel SW Provider 1.1"
+};
+
+static struct modlinkage modlinkage = {
+       MODREV_1, { &modlcrypto, NULL }
+};
+
+
+/*
+ * Macros to access the SHA1 or SHA1-HMAC contexts from a context passed
+ * by KCF to one of the entry points.
+ */
+
+#define        PROV_SHA1_CTX(ctx)      ((sha1_ctx_t *)(ctx)->cc_provider_private)
+#define        PROV_SHA1_HMAC_CTX(ctx) ((sha1_hmac_ctx_t *)(ctx)->cc_provider_private)
+
+/* to extract the digest length passed as mechanism parameter */
+#define        PROV_SHA1_GET_DIGEST_LEN(m, len) {                              \
+       if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t)))              \
+               (len) = (uint32_t)*((ulong_t *)(void *)mechanism->cm_param); \
+       else {                                                          \
+               ulong_t tmp_ulong;                                      \
+               bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t));     \
+               (len) = (uint32_t)tmp_ulong;                            \
+       }                                                               \
+}
+
+#define        PROV_SHA1_DIGEST_KEY(ctx, key, len, digest) {   \
+       SHA1Init(ctx);                                  \
+       SHA1Update(ctx, key, len);                      \
+       SHA1Final(digest, ctx);                         \
+}
+
+/*
+ * Mechanism info structure passed to KCF during registration.
+ */
+static crypto_mech_info_t sha1_mech_info_tab[] = {
+       /* SHA1 */
+       {SUN_CKM_SHA1, SHA1_MECH_INFO_TYPE,
+           CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
+           0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+       /* SHA1-HMAC */
+       {SUN_CKM_SHA1_HMAC, SHA1_HMAC_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
+           SHA1_HMAC_MIN_KEY_LEN, SHA1_HMAC_MAX_KEY_LEN,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* SHA1-HMAC GENERAL */
+       {SUN_CKM_SHA1_HMAC_GENERAL, SHA1_HMAC_GEN_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
+           SHA1_HMAC_MIN_KEY_LEN, SHA1_HMAC_MAX_KEY_LEN,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES}
+};
+
+static void sha1_provider_status(crypto_provider_handle_t, uint_t *);
+
+static crypto_control_ops_t sha1_control_ops = {
+       sha1_provider_status
+};
+
+static int sha1_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
+    crypto_req_handle_t);
+static int sha1_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int sha1_digest_update(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int sha1_digest_final(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int sha1_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+
+static crypto_digest_ops_t sha1_digest_ops = {
+       sha1_digest_init,
+       sha1_digest,
+       sha1_digest_update,
+       NULL,
+       sha1_digest_final,
+       sha1_digest_atomic
+};
+
+static int sha1_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int sha1_mac_update(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int sha1_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
+static int sha1_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int sha1_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+static crypto_mac_ops_t sha1_mac_ops = {
+       sha1_mac_init,
+       NULL,
+       sha1_mac_update,
+       sha1_mac_final,
+       sha1_mac_atomic,
+       sha1_mac_verify_atomic
+};
+
+static int sha1_create_ctx_template(crypto_provider_handle_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
+    size_t *, crypto_req_handle_t);
+static int sha1_free_context(crypto_ctx_t *);
+
+static crypto_ctx_ops_t sha1_ctx_ops = {
+       sha1_create_ctx_template,
+       sha1_free_context
+};
+
+static crypto_ops_t sha1_crypto_ops = {{{{{
+       &sha1_control_ops,
+       &sha1_digest_ops,
+       NULL,
+       &sha1_mac_ops,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       &sha1_ctx_ops,
+}}}}};
+
+static crypto_provider_info_t sha1_prov_info = {{{{
+       CRYPTO_SPI_VERSION_1,
+       "SHA1 Software Provider",
+       CRYPTO_SW_PROVIDER,
+       NULL,
+       &sha1_crypto_ops,
+       sizeof (sha1_mech_info_tab)/sizeof (crypto_mech_info_t),
+       sha1_mech_info_tab
+}}}};
+
+static crypto_kcf_provider_handle_t sha1_prov_handle = 0;
+
+int
+sha1_mod_init(void)
+{
+       int ret;
+
+       if ((ret = mod_install(&modlinkage)) != 0)
+               return (ret);
+
+       /*
+        * Register with KCF. If the registration fails, log an
+        * error but do not uninstall the module, since the functionality
+        * provided by misc/sha1 should still be available.
+        */
+       if ((ret = crypto_register_provider(&sha1_prov_info,
+           &sha1_prov_handle)) != CRYPTO_SUCCESS)
+               cmn_err(CE_WARN, "sha1 _init: "
+                   "crypto_register_provider() failed (0x%x)", ret);
+
+       return (0);
+}
+
+int
+sha1_mod_fini(void)
+{
+       int ret;
+
+       if (sha1_prov_handle != 0) {
+               if ((ret = crypto_unregister_provider(sha1_prov_handle)) !=
+                   CRYPTO_SUCCESS) {
+                       cmn_err(CE_WARN,
+                           "sha1 _fini: crypto_unregister_provider() "
+                           "failed (0x%x)", ret);
+                       return (EBUSY);
+               }
+               sha1_prov_handle = 0;
+       }
+
+       return (mod_remove(&modlinkage));
+}
+
+/*
+ * KCF software provider control entry points.
+ */
+/* ARGSUSED */
+static void
+sha1_provider_status(crypto_provider_handle_t provider, uint_t *status)
+{
+       *status = CRYPTO_PROVIDER_READY;
+}
+
+/*
+ * KCF software provider digest entry points.
+ */
+
+static int
+sha1_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_req_handle_t req)
+{
+       if (mechanism->cm_type != SHA1_MECH_INFO_TYPE)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       /*
+        * Allocate and initialize SHA1 context.
+        */
+       ctx->cc_provider_private = kmem_alloc(sizeof (sha1_ctx_t),
+           crypto_kmflag(req));
+       if (ctx->cc_provider_private == NULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       PROV_SHA1_CTX(ctx)->sc_mech_type = SHA1_MECH_INFO_TYPE;
+       SHA1Init(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Helper SHA1 digest update function for uio data.
+ */
+static int
+sha1_digest_update_uio(SHA1_CTX *sha1_ctx, crypto_data_t *data)
+{
+       off_t offset = data->cd_offset;
+       size_t length = data->cd_length;
+       uint_t vec_idx;
+       size_t cur_len;
+
+       /* we support only kernel buffer */
+       if (data->cd_uio->uio_segflg != UIO_SYSSPACE)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Jump to the first iovec containing data to be
+        * digested.
+        */
+       for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt &&
+           offset >= data->cd_uio->uio_iov[vec_idx].iov_len;
+           offset -= data->cd_uio->uio_iov[vec_idx++].iov_len)
+               ;
+       if (vec_idx == data->cd_uio->uio_iovcnt) {
+               /*
+                * The caller specified an offset that is larger than the
+                * total size of the buffers it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       /*
+        * Now do the digesting on the iovecs.
+        */
+       while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) {
+               cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len -
+                   offset, length);
+
+               SHA1Update(sha1_ctx,
+                   (uint8_t *)data->cd_uio->uio_iov[vec_idx].iov_base + offset,
+                   cur_len);
+
+               length -= cur_len;
+               vec_idx++;
+               offset = 0;
+       }
+
+       if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) {
+               /*
+                * The end of the specified iovec's was reached but
+                * the length requested could not be processed, i.e.
+                * The caller requested to digest more data than it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Helper SHA1 digest final function for uio data.
+ * digest_len is the length of the desired digest. If digest_len
+ * is smaller than the default SHA1 digest length, the caller
+ * must pass a scratch buffer, digest_scratch, which must
+ * be at least SHA1_DIGEST_LENGTH bytes.
+ */
+static int
+sha1_digest_final_uio(SHA1_CTX *sha1_ctx, crypto_data_t *digest,
+    ulong_t digest_len, uchar_t *digest_scratch)
+{
+       off_t offset = digest->cd_offset;
+       uint_t vec_idx;
+
+       /* we support only kernel buffer */
+       if (digest->cd_uio->uio_segflg != UIO_SYSSPACE)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Jump to the first iovec containing ptr to the digest to
+        * be returned.
+        */
+       for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len &&
+           vec_idx < digest->cd_uio->uio_iovcnt;
+           offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len)
+               ;
+       if (vec_idx == digest->cd_uio->uio_iovcnt) {
+               /*
+                * The caller specified an offset that is
+                * larger than the total size of the buffers
+                * it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       if (offset + digest_len <=
+           digest->cd_uio->uio_iov[vec_idx].iov_len) {
+               /*
+                * The computed SHA1 digest will fit in the current
+                * iovec.
+                */
+               if (digest_len != SHA1_DIGEST_LENGTH) {
+                       /*
+                        * The caller requested a short digest. Digest
+                        * into a scratch buffer and return to
+                        * the user only what was requested.
+                        */
+                       SHA1Final(digest_scratch, sha1_ctx);
+                       bcopy(digest_scratch, (uchar_t *)digest->
+                           cd_uio->uio_iov[vec_idx].iov_base + offset,
+                           digest_len);
+               } else {
+                       SHA1Final((uchar_t *)digest->
+                           cd_uio->uio_iov[vec_idx].iov_base + offset,
+                           sha1_ctx);
+               }
+       } else {
+               /*
+                * The computed digest will be crossing one or more iovec's.
+                * This is bad performance-wise but we need to support it.
+                * Allocate a small scratch buffer on the stack and
+                * copy it piece meal to the specified digest iovec's.
+                */
+               uchar_t digest_tmp[SHA1_DIGEST_LENGTH];
+               off_t scratch_offset = 0;
+               size_t length = digest_len;
+               size_t cur_len;
+
+               SHA1Final(digest_tmp, sha1_ctx);
+
+               while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
+                       cur_len = MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
+                           offset, length);
+                       bcopy(digest_tmp + scratch_offset,
+                           digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
+                           cur_len);
+
+                       length -= cur_len;
+                       vec_idx++;
+                       scratch_offset += cur_len;
+                       offset = 0;
+               }
+
+               if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
+                       /*
+                        * The end of the specified iovec's was reached but
+                        * the length requested could not be processed, i.e.
+                        * The caller requested to digest more data than it
+                        * provided.
+                        */
+                       return (CRYPTO_DATA_LEN_RANGE);
+               }
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+sha1_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       /*
+        * We need to just return the length needed to store the output.
+        * We should not destroy the context for the following cases.
+        */
+       if ((digest->cd_length == 0) ||
+           (digest->cd_length < SHA1_DIGEST_LENGTH)) {
+               digest->cd_length = SHA1_DIGEST_LENGTH;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       /*
+        * Do the SHA1 update on the specified input data.
+        */
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA1Update(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
+                   (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
+                   data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_update_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
+                   data);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret != CRYPTO_SUCCESS) {
+               /* the update failed, free context and bail */
+               kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
+               ctx->cc_provider_private = NULL;
+               digest->cd_length = 0;
+               return (ret);
+       }
+
+       /*
+        * Do a SHA1 final, must be done separately since the digest
+        * type can be different than the input data type.
+        */
+       switch (digest->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA1Final((unsigned char *)digest->cd_raw.iov_base +
+                   digest->cd_offset, &PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_final_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
+                   digest, SHA1_DIGEST_LENGTH, NULL);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       /* all done, free context and return */
+
+       if (ret == CRYPTO_SUCCESS) {
+               digest->cd_length = SHA1_DIGEST_LENGTH;
+       } else {
+               digest->cd_length = 0;
+       }
+
+       kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
+       ctx->cc_provider_private = NULL;
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha1_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       /*
+        * Do the SHA1 update on the specified input data.
+        */
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA1Update(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
+                   (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
+                   data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_update_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
+                   data);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha1_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       /*
+        * We need to just return the length needed to store the output.
+        * We should not destroy the context for the following cases.
+        */
+       if ((digest->cd_length == 0) ||
+           (digest->cd_length < SHA1_DIGEST_LENGTH)) {
+               digest->cd_length = SHA1_DIGEST_LENGTH;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       /*
+        * Do a SHA1 final.
+        */
+       switch (digest->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA1Final((unsigned char *)digest->cd_raw.iov_base +
+                   digest->cd_offset, &PROV_SHA1_CTX(ctx)->sc_sha1_ctx);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_final_uio(&PROV_SHA1_CTX(ctx)->sc_sha1_ctx,
+                   digest, SHA1_DIGEST_LENGTH, NULL);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       /* all done, free context and return */
+
+       if (ret == CRYPTO_SUCCESS) {
+               digest->cd_length = SHA1_DIGEST_LENGTH;
+       } else {
+               digest->cd_length = 0;
+       }
+
+       kmem_free(ctx->cc_provider_private, sizeof (sha1_ctx_t));
+       ctx->cc_provider_private = NULL;
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha1_digest_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_data_t *data, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       SHA1_CTX sha1_ctx;
+
+       if (mechanism->cm_type != SHA1_MECH_INFO_TYPE)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       /*
+        * Do the SHA1 init.
+        */
+       SHA1Init(&sha1_ctx);
+
+       /*
+        * Do the SHA1 update on the specified input data.
+        */
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA1Update(&sha1_ctx,
+                   (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
+                   data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_update_uio(&sha1_ctx, data);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret != CRYPTO_SUCCESS) {
+               /* the update failed, bail */
+               digest->cd_length = 0;
+               return (ret);
+       }
+
+       /*
+        * Do a SHA1 final, must be done separately since the digest
+        * type can be different than the input data type.
+        */
+       switch (digest->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA1Final((unsigned char *)digest->cd_raw.iov_base +
+                   digest->cd_offset, &sha1_ctx);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_final_uio(&sha1_ctx, digest,
+                   SHA1_DIGEST_LENGTH, NULL);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret == CRYPTO_SUCCESS) {
+               digest->cd_length = SHA1_DIGEST_LENGTH;
+       } else {
+               digest->cd_length = 0;
+       }
+
+       return (ret);
+}
+
+/*
+ * KCF software provider mac entry points.
+ *
+ * SHA1 HMAC is: SHA1(key XOR opad, SHA1(key XOR ipad, text))
+ *
+ * Init:
+ * The initialization routine initializes what we denote
+ * as the inner and outer contexts by doing
+ * - for inner context: SHA1(key XOR ipad)
+ * - for outer context: SHA1(key XOR opad)
+ *
+ * Update:
+ * Each subsequent SHA1 HMAC update will result in an
+ * update of the inner context with the specified data.
+ *
+ * Final:
+ * The SHA1 HMAC final will do a SHA1 final operation on the
+ * inner context, and the resulting digest will be used
+ * as the data for an update on the outer context. Last
+ * but not least, a SHA1 final on the outer context will
+ * be performed to obtain the SHA1 HMAC digest to return
+ * to the user.
+ */
+
+/*
+ * Initialize a SHA1-HMAC context.
+ */
+static void
+sha1_mac_init_ctx(sha1_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
+{
+       uint32_t ipad[SHA1_HMAC_INTS_PER_BLOCK];
+       uint32_t opad[SHA1_HMAC_INTS_PER_BLOCK];
+       uint_t i;
+
+       bzero(ipad, SHA1_HMAC_BLOCK_SIZE);
+       bzero(opad, SHA1_HMAC_BLOCK_SIZE);
+
+       bcopy(keyval, ipad, length_in_bytes);
+       bcopy(keyval, opad, length_in_bytes);
+
+       /* XOR key with ipad (0x36) and opad (0x5c) */
+       for (i = 0; i < SHA1_HMAC_INTS_PER_BLOCK; i++) {
+               ipad[i] ^= 0x36363636;
+               opad[i] ^= 0x5c5c5c5c;
+       }
+
+       /* perform SHA1 on ipad */
+       SHA1Init(&ctx->hc_icontext);
+       SHA1Update(&ctx->hc_icontext, (uint8_t *)ipad, SHA1_HMAC_BLOCK_SIZE);
+
+       /* perform SHA1 on opad */
+       SHA1Init(&ctx->hc_ocontext);
+       SHA1Update(&ctx->hc_ocontext, (uint8_t *)opad, SHA1_HMAC_BLOCK_SIZE);
+}
+
+/*
+ */
+static int
+sha1_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
+
+       if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
+           mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       /* Add support for key by attributes (RFE 4706552) */
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       ctx->cc_provider_private = kmem_alloc(sizeof (sha1_hmac_ctx_t),
+           crypto_kmflag(req));
+       if (ctx->cc_provider_private == NULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       if (ctx_template != NULL) {
+               /* reuse context template */
+               bcopy(ctx_template, PROV_SHA1_HMAC_CTX(ctx),
+                   sizeof (sha1_hmac_ctx_t));
+       } else {
+               /* no context template, compute context */
+               if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
+                       uchar_t digested_key[SHA1_DIGEST_LENGTH];
+                       sha1_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;
+
+                       /*
+                        * Hash the passed-in key to get a smaller key.
+                        * The inner context is used since it hasn't been
+                        * initialized yet.
+                        */
+                       PROV_SHA1_DIGEST_KEY(&hmac_ctx->hc_icontext,
+                           key->ck_data, keylen_in_bytes, digested_key);
+                       sha1_mac_init_ctx(PROV_SHA1_HMAC_CTX(ctx),
+                           digested_key, SHA1_DIGEST_LENGTH);
+               } else {
+                       sha1_mac_init_ctx(PROV_SHA1_HMAC_CTX(ctx),
+                           key->ck_data, keylen_in_bytes);
+               }
+       }
+
+       /*
+        * Get the mechanism parameters, if applicable.
+        */
+       PROV_SHA1_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;
+       if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (ulong_t))
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+               PROV_SHA1_GET_DIGEST_LEN(mechanism,
+                   PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len);
+               if (PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len >
+                   SHA1_DIGEST_LENGTH)
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+       }
+
+       if (ret != CRYPTO_SUCCESS) {
+               bzero(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
+               kmem_free(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
+               ctx->cc_provider_private = NULL;
+       }
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha1_mac_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       /*
+        * Do a SHA1 update of the inner context using the specified
+        * data.
+        */
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA1Update(&PROV_SHA1_HMAC_CTX(ctx)->hc_icontext,
+                   (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
+                   data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_update_uio(
+                   &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext, data);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha1_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uchar_t digest[SHA1_DIGEST_LENGTH];
+       uint32_t digest_len = SHA1_DIGEST_LENGTH;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       if (PROV_SHA1_HMAC_CTX(ctx)->hc_mech_type ==
+           SHA1_HMAC_GEN_MECH_INFO_TYPE)
+               digest_len = PROV_SHA1_HMAC_CTX(ctx)->hc_digest_len;
+
+       /*
+        * We need to just return the length needed to store the output.
+        * We should not destroy the context for the following cases.
+        */
+       if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {
+               mac->cd_length = digest_len;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       /*
+        * Do a SHA1 final on the inner context.
+        */
+       SHA1Final(digest, &PROV_SHA1_HMAC_CTX(ctx)->hc_icontext);
+
+       /*
+        * Do a SHA1 update on the outer context, feeding the inner
+        * digest as data.
+        */
+       SHA1Update(&PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, digest,
+           SHA1_DIGEST_LENGTH);
+
+       /*
+        * Do a SHA1 final on the outer context, storing the computing
+        * digest in the users buffer.
+        */
+       switch (mac->cd_format) {
+       case CRYPTO_DATA_RAW:
+               if (digest_len != SHA1_DIGEST_LENGTH) {
+                       /*
+                        * The caller requested a short digest. Digest
+                        * into a scratch buffer and return to
+                        * the user only what was requested.
+                        */
+                       SHA1Final(digest,
+                           &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext);
+                       bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
+                           mac->cd_offset, digest_len);
+               } else {
+                       SHA1Final((unsigned char *)mac->cd_raw.iov_base +
+                           mac->cd_offset,
+                           &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext);
+               }
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_final_uio(
+                   &PROV_SHA1_HMAC_CTX(ctx)->hc_ocontext, mac,
+                   digest_len, digest);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret == CRYPTO_SUCCESS) {
+               mac->cd_length = digest_len;
+       } else {
+               mac->cd_length = 0;
+       }
+
+       bzero(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
+       kmem_free(ctx->cc_provider_private, sizeof (sha1_hmac_ctx_t));
+       ctx->cc_provider_private = NULL;
+
+       return (ret);
+}
+
+#define        SHA1_MAC_UPDATE(data, ctx, ret) {                               \
+       switch (data->cd_format) {                                      \
+       case CRYPTO_DATA_RAW:                                           \
+               SHA1Update(&(ctx).hc_icontext,                          \
+                   (uint8_t *)data->cd_raw.iov_base +                  \
+                   data->cd_offset, data->cd_length);                  \
+               break;                                                  \
+       case CRYPTO_DATA_UIO:                                           \
+               ret = sha1_digest_update_uio(&(ctx).hc_icontext, data); \
+               break;                                                  \
+       default:                                                        \
+               ret = CRYPTO_ARGUMENTS_BAD;                             \
+       }                                                               \
+}
+
+/* ARGSUSED */
+static int
+sha1_mac_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
+    crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uchar_t digest[SHA1_DIGEST_LENGTH];
+       sha1_hmac_ctx_t sha1_hmac_ctx;
+       uint32_t digest_len = SHA1_DIGEST_LENGTH;
+       uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
+
+       if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
+           mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       /* Add support for key by attributes (RFE 4706552) */
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       if (ctx_template != NULL) {
+               /* reuse context template */
+               bcopy(ctx_template, &sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
+       } else {
+               /* no context template, initialize context */
+               if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
+                       /*
+                        * Hash the passed-in key to get a smaller key.
+                        * The inner context is used since it hasn't been
+                        * initialized yet.
+                        */
+                       PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx.hc_icontext,
+                           key->ck_data, keylen_in_bytes, digest);
+                       sha1_mac_init_ctx(&sha1_hmac_ctx, digest,
+                           SHA1_DIGEST_LENGTH);
+               } else {
+                       sha1_mac_init_ctx(&sha1_hmac_ctx, key->ck_data,
+                           keylen_in_bytes);
+               }
+       }
+
+       /* get the mechanism parameters, if applicable */
+       if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (ulong_t)) {
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+                       goto bail;
+               }
+               PROV_SHA1_GET_DIGEST_LEN(mechanism, digest_len);
+               if (digest_len > SHA1_DIGEST_LENGTH) {
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+                       goto bail;
+               }
+       }
+
+       /* do a SHA1 update of the inner context using the specified data */
+       SHA1_MAC_UPDATE(data, sha1_hmac_ctx, ret);
+       if (ret != CRYPTO_SUCCESS)
+               /* the update failed, free context and bail */
+               goto bail;
+
+       /*
+        * Do a SHA1 final on the inner context.
+        */
+       SHA1Final(digest, &sha1_hmac_ctx.hc_icontext);
+
+       /*
+        * Do an SHA1 update on the outer context, feeding the inner
+        * digest as data.
+        */
+       SHA1Update(&sha1_hmac_ctx.hc_ocontext, digest, SHA1_DIGEST_LENGTH);
+
+       /*
+        * Do a SHA1 final on the outer context, storing the computed
+        * digest in the users buffer.
+        */
+       switch (mac->cd_format) {
+       case CRYPTO_DATA_RAW:
+               if (digest_len != SHA1_DIGEST_LENGTH) {
+                       /*
+                        * The caller requested a short digest. Digest
+                        * into a scratch buffer and return to
+                        * the user only what was requested.
+                        */
+                       SHA1Final(digest, &sha1_hmac_ctx.hc_ocontext);
+                       bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
+                           mac->cd_offset, digest_len);
+               } else {
+                       SHA1Final((unsigned char *)mac->cd_raw.iov_base +
+                           mac->cd_offset, &sha1_hmac_ctx.hc_ocontext);
+               }
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha1_digest_final_uio(&sha1_hmac_ctx.hc_ocontext, mac,
+                   digest_len, digest);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret == CRYPTO_SUCCESS) {
+               mac->cd_length = digest_len;
+       } else {
+               mac->cd_length = 0;
+       }
+       /* Extra paranoia: zeroize the context on the stack */
+       bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
+
+       return (ret);
+bail:
+       bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
+       mac->cd_length = 0;
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha1_mac_verify_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
+    crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uchar_t digest[SHA1_DIGEST_LENGTH];
+       sha1_hmac_ctx_t sha1_hmac_ctx;
+       uint32_t digest_len = SHA1_DIGEST_LENGTH;
+       uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
+
+       if (mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE &&
+           mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)
+               return (CRYPTO_MECHANISM_INVALID);
+
+       /* Add support for key by attributes (RFE 4706552) */
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       if (ctx_template != NULL) {
+               /* reuse context template */
+               bcopy(ctx_template, &sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
+       } else {
+               /* no context template, initialize context */
+               if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
+                       /*
+                        * Hash the passed-in key to get a smaller key.
+                        * The inner context is used since it hasn't been
+                        * initialized yet.
+                        */
+                       PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx.hc_icontext,
+                           key->ck_data, keylen_in_bytes, digest);
+                       sha1_mac_init_ctx(&sha1_hmac_ctx, digest,
+                           SHA1_DIGEST_LENGTH);
+               } else {
+                       sha1_mac_init_ctx(&sha1_hmac_ctx, key->ck_data,
+                           keylen_in_bytes);
+               }
+       }
+
+       /* get the mechanism parameters, if applicable */
+       if (mechanism->cm_type == SHA1_HMAC_GEN_MECH_INFO_TYPE) {
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (ulong_t)) {
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+                       goto bail;
+               }
+               PROV_SHA1_GET_DIGEST_LEN(mechanism, digest_len);
+               if (digest_len > SHA1_DIGEST_LENGTH) {
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+                       goto bail;
+               }
+       }
+
+       if (mac->cd_length != digest_len) {
+               ret = CRYPTO_INVALID_MAC;
+               goto bail;
+       }
+
+       /* do a SHA1 update of the inner context using the specified data */
+       SHA1_MAC_UPDATE(data, sha1_hmac_ctx, ret);
+       if (ret != CRYPTO_SUCCESS)
+               /* the update failed, free context and bail */
+               goto bail;
+
+       /* do a SHA1 final on the inner context */
+       SHA1Final(digest, &sha1_hmac_ctx.hc_icontext);
+
+       /*
+        * Do an SHA1 update on the outer context, feeding the inner
+        * digest as data.
+        */
+       SHA1Update(&sha1_hmac_ctx.hc_ocontext, digest, SHA1_DIGEST_LENGTH);
+
+       /*
+        * Do a SHA1 final on the outer context, storing the computed
+        * digest in the users buffer.
+        */
+       SHA1Final(digest, &sha1_hmac_ctx.hc_ocontext);
+
+       /*
+        * Compare the computed digest against the expected digest passed
+        * as argument.
+        */
+
+       switch (mac->cd_format) {
+
+       case CRYPTO_DATA_RAW:
+               if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base +
+                   mac->cd_offset, digest_len) != 0)
+                       ret = CRYPTO_INVALID_MAC;
+               break;
+
+       case CRYPTO_DATA_UIO: {
+               off_t offset = mac->cd_offset;
+               uint_t vec_idx;
+               off_t scratch_offset = 0;
+               size_t length = digest_len;
+               size_t cur_len;
+
+               /* we support only kernel buffer */
+               if (mac->cd_uio->uio_segflg != UIO_SYSSPACE)
+                       return (CRYPTO_ARGUMENTS_BAD);
+
+               /* jump to the first iovec containing the expected digest */
+               for (vec_idx = 0;
+                   offset >= mac->cd_uio->uio_iov[vec_idx].iov_len &&
+                   vec_idx < mac->cd_uio->uio_iovcnt;
+                   offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len)
+                       ;
+               if (vec_idx == mac->cd_uio->uio_iovcnt) {
+                       /*
+                        * The caller specified an offset that is
+                        * larger than the total size of the buffers
+                        * it provided.
+                        */
+                       ret = CRYPTO_DATA_LEN_RANGE;
+                       break;
+               }
+
+               /* do the comparison of computed digest vs specified one */
+               while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) {
+                       cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len -
+                           offset, length);
+
+                       if (bcmp(digest + scratch_offset,
+                           mac->cd_uio->uio_iov[vec_idx].iov_base + offset,
+                           cur_len) != 0) {
+                               ret = CRYPTO_INVALID_MAC;
+                               break;
+                       }
+
+                       length -= cur_len;
+                       vec_idx++;
+                       scratch_offset += cur_len;
+                       offset = 0;
+               }
+               break;
+       }
+
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
+       return (ret);
+bail:
+       bzero(&sha1_hmac_ctx, sizeof (sha1_hmac_ctx_t));
+       mac->cd_length = 0;
+       return (ret);
+}
+
+/*
+ * KCF software provider context management entry points.
+ */
+
+/* ARGSUSED */
+static int
+sha1_create_ctx_template(crypto_provider_handle_t provider,
+    crypto_mechanism_t *mechanism, crypto_key_t *key,
+    crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
+    crypto_req_handle_t req)
+{
+       sha1_hmac_ctx_t *sha1_hmac_ctx_tmpl;
+       uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
+
+       if ((mechanism->cm_type != SHA1_HMAC_MECH_INFO_TYPE) &&
+           (mechanism->cm_type != SHA1_HMAC_GEN_MECH_INFO_TYPE)) {
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       /* Add support for key by attributes (RFE 4706552) */
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Allocate and initialize SHA1 context.
+        */
+       sha1_hmac_ctx_tmpl = kmem_alloc(sizeof (sha1_hmac_ctx_t),
+           crypto_kmflag(req));
+       if (sha1_hmac_ctx_tmpl == NULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       if (keylen_in_bytes > SHA1_HMAC_BLOCK_SIZE) {
+               uchar_t digested_key[SHA1_DIGEST_LENGTH];
+
+               /*
+                * Hash the passed-in key to get a smaller key.
+                * The inner context is used since it hasn't been
+                * initialized yet.
+                */
+               PROV_SHA1_DIGEST_KEY(&sha1_hmac_ctx_tmpl->hc_icontext,
+                   key->ck_data, keylen_in_bytes, digested_key);
+               sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, digested_key,
+                   SHA1_DIGEST_LENGTH);
+       } else {
+               sha1_mac_init_ctx(sha1_hmac_ctx_tmpl, key->ck_data,
+                   keylen_in_bytes);
+       }
+
+       sha1_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;
+       *ctx_template = (crypto_spi_ctx_template_t)sha1_hmac_ctx_tmpl;
+       *ctx_template_size = sizeof (sha1_hmac_ctx_t);
+
+
+       return (CRYPTO_SUCCESS);
+}
+
+static int
+sha1_free_context(crypto_ctx_t *ctx)
+{
+       uint_t ctx_len;
+       sha1_mech_type_t mech_type;
+
+       if (ctx->cc_provider_private == NULL)
+               return (CRYPTO_SUCCESS);
+
+       /*
+        * We have to free either SHA1 or SHA1-HMAC contexts, which
+        * have different lengths.
+        */
+
+       mech_type = PROV_SHA1_CTX(ctx)->sc_mech_type;
+       if (mech_type == SHA1_MECH_INFO_TYPE)
+               ctx_len = sizeof (sha1_ctx_t);
+       else {
+               ASSERT(mech_type == SHA1_HMAC_MECH_INFO_TYPE ||
+                   mech_type == SHA1_HMAC_GEN_MECH_INFO_TYPE);
+               ctx_len = sizeof (sha1_hmac_ctx_t);
+       }
+
+       bzero(ctx->cc_provider_private, ctx_len);
+       kmem_free(ctx->cc_provider_private, ctx_len);
+       ctx->cc_provider_private = NULL;
+
+       return (CRYPTO_SUCCESS);
+}
diff --git a/zfs/module/icp/io/sha2_mod.c b/zfs/module/icp/io/sha2_mod.c
new file mode 100644 (file)
index 0000000..8a3514c
--- /dev/null
@@ -0,0 +1,1409 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/modctl.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/spi.h>
+#include <sys/crypto/icp.h>
+#define        _SHA2_IMPL
+#include <sys/sha2.h>
+#include <sha2/sha2_impl.h>
+
+/*
+ * The sha2 module is created with two modlinkages:
+ * - a modlmisc that allows consumers to directly call the entry points
+ *   SHA2Init, SHA2Update, and SHA2Final.
+ * - a modlcrypto that allows the module to register with the Kernel
+ *   Cryptographic Framework (KCF) as a software provider for the SHA2
+ *   mechanisms.
+ */
+
+static struct modlcrypto modlcrypto = {
+       &mod_cryptoops,
+       "SHA2 Kernel SW Provider"
+};
+
+static struct modlinkage modlinkage = {
+       MODREV_1, {&modlcrypto, NULL}
+};
+
+/*
+ * Macros to access the SHA2 or SHA2-HMAC contexts from a context passed
+ * by KCF to one of the entry points.
+ */
+
+#define        PROV_SHA2_CTX(ctx)      ((sha2_ctx_t *)(ctx)->cc_provider_private)
+#define        PROV_SHA2_HMAC_CTX(ctx) ((sha2_hmac_ctx_t *)(ctx)->cc_provider_private)
+
+/* to extract the digest length passed as mechanism parameter */
+#define        PROV_SHA2_GET_DIGEST_LEN(m, len) {                              \
+       if (IS_P2ALIGNED((m)->cm_param, sizeof (ulong_t)))              \
+               (len) = (uint32_t)*((ulong_t *)(m)->cm_param);  \
+       else {                                                          \
+               ulong_t tmp_ulong;                                      \
+               bcopy((m)->cm_param, &tmp_ulong, sizeof (ulong_t));     \
+               (len) = (uint32_t)tmp_ulong;                            \
+       }                                                               \
+}
+
+#define        PROV_SHA2_DIGEST_KEY(mech, ctx, key, len, digest) {     \
+       SHA2Init(mech, ctx);                            \
+       SHA2Update(ctx, key, len);                      \
+       SHA2Final(digest, ctx);                         \
+}
+
+/*
+ * Mechanism info structure passed to KCF during registration.
+ */
+static crypto_mech_info_t sha2_mech_info_tab[] = {
+       /* SHA256 */
+       {SUN_CKM_SHA256, SHA256_MECH_INFO_TYPE,
+           CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
+           0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+       /* SHA256-HMAC */
+       {SUN_CKM_SHA256_HMAC, SHA256_HMAC_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
+           SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* SHA256-HMAC GENERAL */
+       {SUN_CKM_SHA256_HMAC_GENERAL, SHA256_HMAC_GEN_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
+           SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* SHA384 */
+       {SUN_CKM_SHA384, SHA384_MECH_INFO_TYPE,
+           CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
+           0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+       /* SHA384-HMAC */
+       {SUN_CKM_SHA384_HMAC, SHA384_HMAC_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
+           SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* SHA384-HMAC GENERAL */
+       {SUN_CKM_SHA384_HMAC_GENERAL, SHA384_HMAC_GEN_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
+           SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* SHA512 */
+       {SUN_CKM_SHA512, SHA512_MECH_INFO_TYPE,
+           CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
+           0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+       /* SHA512-HMAC */
+       {SUN_CKM_SHA512_HMAC, SHA512_HMAC_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
+           SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       /* SHA512-HMAC GENERAL */
+       {SUN_CKM_SHA512_HMAC_GENERAL, SHA512_HMAC_GEN_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC,
+           SHA2_HMAC_MIN_KEY_LEN, SHA2_HMAC_MAX_KEY_LEN,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES}
+};
+
+static void sha2_provider_status(crypto_provider_handle_t, uint_t *);
+
+static crypto_control_ops_t sha2_control_ops = {
+       sha2_provider_status
+};
+
+static int sha2_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
+    crypto_req_handle_t);
+static int sha2_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int sha2_digest_update(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int sha2_digest_final(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int sha2_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+
+static crypto_digest_ops_t sha2_digest_ops = {
+       sha2_digest_init,
+       sha2_digest,
+       sha2_digest_update,
+       NULL,
+       sha2_digest_final,
+       sha2_digest_atomic
+};
+
+static int sha2_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int sha2_mac_update(crypto_ctx_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int sha2_mac_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
+static int sha2_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int sha2_mac_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+static crypto_mac_ops_t sha2_mac_ops = {
+       sha2_mac_init,
+       NULL,
+       sha2_mac_update,
+       sha2_mac_final,
+       sha2_mac_atomic,
+       sha2_mac_verify_atomic
+};
+
+static int sha2_create_ctx_template(crypto_provider_handle_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
+    size_t *, crypto_req_handle_t);
+static int sha2_free_context(crypto_ctx_t *);
+
+static crypto_ctx_ops_t sha2_ctx_ops = {
+       sha2_create_ctx_template,
+       sha2_free_context
+};
+
+static crypto_ops_t sha2_crypto_ops = {{{{{
+       &sha2_control_ops,
+       &sha2_digest_ops,
+       NULL,
+       &sha2_mac_ops,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       &sha2_ctx_ops
+}}}}};
+
+static crypto_provider_info_t sha2_prov_info = {{{{
+       CRYPTO_SPI_VERSION_1,
+       "SHA2 Software Provider",
+       CRYPTO_SW_PROVIDER,
+       NULL,
+       &sha2_crypto_ops,
+       sizeof (sha2_mech_info_tab)/sizeof (crypto_mech_info_t),
+       sha2_mech_info_tab
+}}}};
+
+static crypto_kcf_provider_handle_t sha2_prov_handle = 0;
+
+int
+sha2_mod_init(void)
+{
+       int ret;
+
+       if ((ret = mod_install(&modlinkage)) != 0)
+               return (ret);
+
+       /*
+        * Register with KCF. If the registration fails, log an
+        * error but do not uninstall the module, since the functionality
+        * provided by misc/sha2 should still be available.
+        */
+       if ((ret = crypto_register_provider(&sha2_prov_info,
+           &sha2_prov_handle)) != CRYPTO_SUCCESS)
+               cmn_err(CE_WARN, "sha2 _init: "
+                   "crypto_register_provider() failed (0x%x)", ret);
+
+       return (0);
+}
+
+int
+sha2_mod_fini(void)
+{
+       int ret;
+
+       if (sha2_prov_handle != 0) {
+               if ((ret = crypto_unregister_provider(sha2_prov_handle)) !=
+                   CRYPTO_SUCCESS) {
+                       cmn_err(CE_WARN,
+                           "sha2 _fini: crypto_unregister_provider() "
+                           "failed (0x%x)", ret);
+                       return (EBUSY);
+               }
+               sha2_prov_handle = 0;
+       }
+
+       return (mod_remove(&modlinkage));
+}
+
+/*
+ * KCF software provider control entry points.
+ */
+/* ARGSUSED */
+static void
+sha2_provider_status(crypto_provider_handle_t provider, uint_t *status)
+{
+       *status = CRYPTO_PROVIDER_READY;
+}
+
+/*
+ * KCF software provider digest entry points.
+ */
+
+static int
+sha2_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_req_handle_t req)
+{
+
+       /*
+        * Allocate and initialize SHA2 context.
+        */
+       ctx->cc_provider_private = kmem_alloc(sizeof (sha2_ctx_t),
+           crypto_kmflag(req));
+       if (ctx->cc_provider_private == NULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       PROV_SHA2_CTX(ctx)->sc_mech_type = mechanism->cm_type;
+       SHA2Init(mechanism->cm_type, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx);
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Helper SHA2 digest update function for uio data.
+ */
+static int
+sha2_digest_update_uio(SHA2_CTX *sha2_ctx, crypto_data_t *data)
+{
+       off_t offset = data->cd_offset;
+       size_t length = data->cd_length;
+       uint_t vec_idx;
+       size_t cur_len;
+
+       /* we support only kernel buffer */
+       if (data->cd_uio->uio_segflg != UIO_SYSSPACE)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Jump to the first iovec containing data to be
+        * digested.
+        */
+       for (vec_idx = 0; vec_idx < data->cd_uio->uio_iovcnt &&
+           offset >= data->cd_uio->uio_iov[vec_idx].iov_len;
+           offset -= data->cd_uio->uio_iov[vec_idx++].iov_len)
+               ;
+       if (vec_idx == data->cd_uio->uio_iovcnt) {
+               /*
+                * The caller specified an offset that is larger than the
+                * total size of the buffers it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       /*
+        * Now do the digesting on the iovecs.
+        */
+       while (vec_idx < data->cd_uio->uio_iovcnt && length > 0) {
+               cur_len = MIN(data->cd_uio->uio_iov[vec_idx].iov_len -
+                   offset, length);
+
+               SHA2Update(sha2_ctx, (uint8_t *)data->cd_uio->
+                   uio_iov[vec_idx].iov_base + offset, cur_len);
+               length -= cur_len;
+               vec_idx++;
+               offset = 0;
+       }
+
+       if (vec_idx == data->cd_uio->uio_iovcnt && length > 0) {
+               /*
+                * The end of the specified iovec's was reached but
+                * the length requested could not be processed, i.e.
+                * The caller requested to digest more data than it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Helper SHA2 digest final function for uio data.
+ * digest_len is the length of the desired digest. If digest_len
+ * is smaller than the default SHA2 digest length, the caller
+ * must pass a scratch buffer, digest_scratch, which must
+ * be at least the algorithm's digest length bytes.
+ */
+static int
+sha2_digest_final_uio(SHA2_CTX *sha2_ctx, crypto_data_t *digest,
+    ulong_t digest_len, uchar_t *digest_scratch)
+{
+       off_t offset = digest->cd_offset;
+       uint_t vec_idx;
+
+       /* we support only kernel buffer */
+       if (digest->cd_uio->uio_segflg != UIO_SYSSPACE)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Jump to the first iovec containing ptr to the digest to
+        * be returned.
+        */
+       for (vec_idx = 0; offset >= digest->cd_uio->uio_iov[vec_idx].iov_len &&
+           vec_idx < digest->cd_uio->uio_iovcnt;
+           offset -= digest->cd_uio->uio_iov[vec_idx++].iov_len)
+               ;
+       if (vec_idx == digest->cd_uio->uio_iovcnt) {
+               /*
+                * The caller specified an offset that is
+                * larger than the total size of the buffers
+                * it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       if (offset + digest_len <=
+           digest->cd_uio->uio_iov[vec_idx].iov_len) {
+               /*
+                * The computed SHA2 digest will fit in the current
+                * iovec.
+                */
+               if (((sha2_ctx->algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) &&
+                   (digest_len != SHA256_DIGEST_LENGTH)) ||
+                   ((sha2_ctx->algotype > SHA256_HMAC_GEN_MECH_INFO_TYPE) &&
+                   (digest_len != SHA512_DIGEST_LENGTH))) {
+                       /*
+                        * The caller requested a short digest. Digest
+                        * into a scratch buffer and return to
+                        * the user only what was requested.
+                        */
+                       SHA2Final(digest_scratch, sha2_ctx);
+
+                       bcopy(digest_scratch, (uchar_t *)digest->
+                           cd_uio->uio_iov[vec_idx].iov_base + offset,
+                           digest_len);
+               } else {
+                       SHA2Final((uchar_t *)digest->
+                           cd_uio->uio_iov[vec_idx].iov_base + offset,
+                           sha2_ctx);
+
+               }
+       } else {
+               /*
+                * The computed digest will be crossing one or more iovec's.
+                * This is bad performance-wise but we need to support it.
+                * Allocate a small scratch buffer on the stack and
+                * copy it piece meal to the specified digest iovec's.
+                */
+               uchar_t digest_tmp[SHA512_DIGEST_LENGTH];
+               off_t scratch_offset = 0;
+               size_t length = digest_len;
+               size_t cur_len;
+
+               SHA2Final(digest_tmp, sha2_ctx);
+
+               while (vec_idx < digest->cd_uio->uio_iovcnt && length > 0) {
+                       cur_len =
+                           MIN(digest->cd_uio->uio_iov[vec_idx].iov_len -
+                           offset, length);
+                       bcopy(digest_tmp + scratch_offset,
+                           digest->cd_uio->uio_iov[vec_idx].iov_base + offset,
+                           cur_len);
+
+                       length -= cur_len;
+                       vec_idx++;
+                       scratch_offset += cur_len;
+                       offset = 0;
+               }
+
+               if (vec_idx == digest->cd_uio->uio_iovcnt && length > 0) {
+                       /*
+                        * The end of the specified iovec's was reached but
+                        * the length requested could not be processed, i.e.
+                        * The caller requested to digest more data than it
+                        * provided.
+                        */
+                       return (CRYPTO_DATA_LEN_RANGE);
+               }
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+/* ARGSUSED */
+static int
+sha2_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uint_t sha_digest_len;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       switch (PROV_SHA2_CTX(ctx)->sc_mech_type) {
+       case SHA256_MECH_INFO_TYPE:
+               sha_digest_len = SHA256_DIGEST_LENGTH;
+               break;
+       case SHA384_MECH_INFO_TYPE:
+               sha_digest_len = SHA384_DIGEST_LENGTH;
+               break;
+       case SHA512_MECH_INFO_TYPE:
+               sha_digest_len = SHA512_DIGEST_LENGTH;
+               break;
+       default:
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       /*
+        * We need to just return the length needed to store the output.
+        * We should not destroy the context for the following cases.
+        */
+       if ((digest->cd_length == 0) ||
+           (digest->cd_length < sha_digest_len)) {
+               digest->cd_length = sha_digest_len;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       /*
+        * Do the SHA2 update on the specified input data.
+        */
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA2Update(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
+                   (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
+                   data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_update_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
+                   data);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret != CRYPTO_SUCCESS) {
+               /* the update failed, free context and bail */
+               kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t));
+               ctx->cc_provider_private = NULL;
+               digest->cd_length = 0;
+               return (ret);
+       }
+
+       /*
+        * Do a SHA2 final, must be done separately since the digest
+        * type can be different than the input data type.
+        */
+       switch (digest->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA2Final((unsigned char *)digest->cd_raw.iov_base +
+                   digest->cd_offset, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_final_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
+                   digest, sha_digest_len, NULL);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       /* all done, free context and return */
+
+       if (ret == CRYPTO_SUCCESS)
+               digest->cd_length = sha_digest_len;
+       else
+               digest->cd_length = 0;
+
+       kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t));
+       ctx->cc_provider_private = NULL;
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha2_digest_update(crypto_ctx_t *ctx, crypto_data_t *data,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       /*
+        * Do the SHA2 update on the specified input data.
+        */
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA2Update(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
+                   (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
+                   data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_update_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
+                   data);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha2_digest_final(crypto_ctx_t *ctx, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uint_t sha_digest_len;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       switch (PROV_SHA2_CTX(ctx)->sc_mech_type) {
+       case SHA256_MECH_INFO_TYPE:
+               sha_digest_len = SHA256_DIGEST_LENGTH;
+               break;
+       case SHA384_MECH_INFO_TYPE:
+               sha_digest_len = SHA384_DIGEST_LENGTH;
+               break;
+       case SHA512_MECH_INFO_TYPE:
+               sha_digest_len = SHA512_DIGEST_LENGTH;
+               break;
+       default:
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       /*
+        * We need to just return the length needed to store the output.
+        * We should not destroy the context for the following cases.
+        */
+       if ((digest->cd_length == 0) ||
+           (digest->cd_length < sha_digest_len)) {
+               digest->cd_length = sha_digest_len;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       /*
+        * Do a SHA2 final.
+        */
+       switch (digest->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA2Final((unsigned char *)digest->cd_raw.iov_base +
+                   digest->cd_offset, &PROV_SHA2_CTX(ctx)->sc_sha2_ctx);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_final_uio(&PROV_SHA2_CTX(ctx)->sc_sha2_ctx,
+                   digest, sha_digest_len, NULL);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       /* all done, free context and return */
+
+       if (ret == CRYPTO_SUCCESS)
+               digest->cd_length = sha_digest_len;
+       else
+               digest->cd_length = 0;
+
+       kmem_free(ctx->cc_provider_private, sizeof (sha2_ctx_t));
+       ctx->cc_provider_private = NULL;
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha2_digest_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_data_t *data, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       SHA2_CTX sha2_ctx;
+       uint32_t sha_digest_len;
+
+       /*
+        * Do the SHA inits.
+        */
+
+       SHA2Init(mechanism->cm_type, &sha2_ctx);
+
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA2Update(&sha2_ctx, (uint8_t *)data->
+                   cd_raw.iov_base + data->cd_offset, data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_update_uio(&sha2_ctx, data);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       /*
+        * Do the SHA updates on the specified input data.
+        */
+
+       if (ret != CRYPTO_SUCCESS) {
+               /* the update failed, bail */
+               digest->cd_length = 0;
+               return (ret);
+       }
+
+       if (mechanism->cm_type <= SHA256_HMAC_GEN_MECH_INFO_TYPE)
+               sha_digest_len = SHA256_DIGEST_LENGTH;
+       else
+               sha_digest_len = SHA512_DIGEST_LENGTH;
+
+       /*
+        * Do a SHA2 final, must be done separately since the digest
+        * type can be different than the input data type.
+        */
+       switch (digest->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA2Final((unsigned char *)digest->cd_raw.iov_base +
+                   digest->cd_offset, &sha2_ctx);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_final_uio(&sha2_ctx, digest,
+                   sha_digest_len, NULL);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret == CRYPTO_SUCCESS)
+               digest->cd_length = sha_digest_len;
+       else
+               digest->cd_length = 0;
+
+       return (ret);
+}
+
+/*
+ * KCF software provider mac entry points.
+ *
+ * SHA2 HMAC is: SHA2(key XOR opad, SHA2(key XOR ipad, text))
+ *
+ * Init:
+ * The initialization routine initializes what we denote
+ * as the inner and outer contexts by doing
+ * - for inner context: SHA2(key XOR ipad)
+ * - for outer context: SHA2(key XOR opad)
+ *
+ * Update:
+ * Each subsequent SHA2 HMAC update will result in an
+ * update of the inner context with the specified data.
+ *
+ * Final:
+ * The SHA2 HMAC final will do a SHA2 final operation on the
+ * inner context, and the resulting digest will be used
+ * as the data for an update on the outer context. Last
+ * but not least, a SHA2 final on the outer context will
+ * be performed to obtain the SHA2 HMAC digest to return
+ * to the user.
+ */
+
+/*
+ * Initialize a SHA2-HMAC context.
+ */
+static void
+sha2_mac_init_ctx(sha2_hmac_ctx_t *ctx, void *keyval, uint_t length_in_bytes)
+{
+       uint64_t ipad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)];
+       uint64_t opad[SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t)];
+       int i, block_size, blocks_per_int64;
+
+       /* Determine the block size */
+       if (ctx->hc_mech_type <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
+               block_size = SHA256_HMAC_BLOCK_SIZE;
+               blocks_per_int64 = SHA256_HMAC_BLOCK_SIZE / sizeof (uint64_t);
+       } else {
+               block_size = SHA512_HMAC_BLOCK_SIZE;
+               blocks_per_int64 = SHA512_HMAC_BLOCK_SIZE / sizeof (uint64_t);
+       }
+
+       (void) bzero(ipad, block_size);
+       (void) bzero(opad, block_size);
+       (void) bcopy(keyval, ipad, length_in_bytes);
+       (void) bcopy(keyval, opad, length_in_bytes);
+
+       /* XOR key with ipad (0x36) and opad (0x5c) */
+       for (i = 0; i < blocks_per_int64; i ++) {
+               ipad[i] ^= 0x3636363636363636;
+               opad[i] ^= 0x5c5c5c5c5c5c5c5c;
+       }
+
+       /* perform SHA2 on ipad */
+       SHA2Init(ctx->hc_mech_type, &ctx->hc_icontext);
+       SHA2Update(&ctx->hc_icontext, (uint8_t *)ipad, block_size);
+
+       /* perform SHA2 on opad */
+       SHA2Init(ctx->hc_mech_type, &ctx->hc_ocontext);
+       SHA2Update(&ctx->hc_ocontext, (uint8_t *)opad, block_size);
+
+}
+
+/*
+ */
+static int
+sha2_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
+       uint_t sha_digest_len, sha_hmac_block_size;
+
+       /*
+        * Set the digest length and block size to values appropriate to the
+        * mechanism
+        */
+       switch (mechanism->cm_type) {
+       case SHA256_HMAC_MECH_INFO_TYPE:
+       case SHA256_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = SHA256_DIGEST_LENGTH;
+               sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE;
+               break;
+       case SHA384_HMAC_MECH_INFO_TYPE:
+       case SHA384_HMAC_GEN_MECH_INFO_TYPE:
+       case SHA512_HMAC_MECH_INFO_TYPE:
+       case SHA512_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = SHA512_DIGEST_LENGTH;
+               sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
+               break;
+       default:
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       ctx->cc_provider_private = kmem_alloc(sizeof (sha2_hmac_ctx_t),
+           crypto_kmflag(req));
+       if (ctx->cc_provider_private == NULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type = mechanism->cm_type;
+       if (ctx_template != NULL) {
+               /* reuse context template */
+               bcopy(ctx_template, PROV_SHA2_HMAC_CTX(ctx),
+                   sizeof (sha2_hmac_ctx_t));
+       } else {
+               /* no context template, compute context */
+               if (keylen_in_bytes > sha_hmac_block_size) {
+                       uchar_t digested_key[SHA512_DIGEST_LENGTH];
+                       sha2_hmac_ctx_t *hmac_ctx = ctx->cc_provider_private;
+
+                       /*
+                        * Hash the passed-in key to get a smaller key.
+                        * The inner context is used since it hasn't been
+                        * initialized yet.
+                        */
+                       PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
+                           &hmac_ctx->hc_icontext,
+                           key->ck_data, keylen_in_bytes, digested_key);
+                       sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx),
+                           digested_key, sha_digest_len);
+               } else {
+                       sha2_mac_init_ctx(PROV_SHA2_HMAC_CTX(ctx),
+                           key->ck_data, keylen_in_bytes);
+               }
+       }
+
+       /*
+        * Get the mechanism parameters, if applicable.
+        */
+       if (mechanism->cm_type % 3 == 2) {
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (ulong_t))
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+               PROV_SHA2_GET_DIGEST_LEN(mechanism,
+                   PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len);
+               if (PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len > sha_digest_len)
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+       }
+
+       if (ret != CRYPTO_SUCCESS) {
+               bzero(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
+               kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
+               ctx->cc_provider_private = NULL;
+       }
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha2_mac_update(crypto_ctx_t *ctx, crypto_data_t *data,
+    crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       /*
+        * Do a SHA2 update of the inner context using the specified
+        * data.
+        */
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_icontext,
+                   (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
+                   data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_update_uio(
+                   &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext, data);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha2_mac_final(crypto_ctx_t *ctx, crypto_data_t *mac, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uchar_t digest[SHA512_DIGEST_LENGTH];
+       uint32_t digest_len, sha_digest_len;
+
+       ASSERT(ctx->cc_provider_private != NULL);
+
+       /* Set the digest lengths to values appropriate to the mechanism */
+       switch (PROV_SHA2_HMAC_CTX(ctx)->hc_mech_type) {
+       case SHA256_HMAC_MECH_INFO_TYPE:
+               sha_digest_len = digest_len = SHA256_DIGEST_LENGTH;
+               break;
+       case SHA384_HMAC_MECH_INFO_TYPE:
+               sha_digest_len = digest_len = SHA384_DIGEST_LENGTH;
+               break;
+       case SHA512_HMAC_MECH_INFO_TYPE:
+               sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
+               break;
+       case SHA256_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = SHA256_DIGEST_LENGTH;
+               digest_len = PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len;
+               break;
+       case SHA384_HMAC_GEN_MECH_INFO_TYPE:
+       case SHA512_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = SHA512_DIGEST_LENGTH;
+               digest_len = PROV_SHA2_HMAC_CTX(ctx)->hc_digest_len;
+               break;
+       default:
+               return (CRYPTO_ARGUMENTS_BAD);
+       }
+
+       /*
+        * We need to just return the length needed to store the output.
+        * We should not destroy the context for the following cases.
+        */
+       if ((mac->cd_length == 0) || (mac->cd_length < digest_len)) {
+               mac->cd_length = digest_len;
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       /*
+        * Do a SHA2 final on the inner context.
+        */
+       SHA2Final(digest, &PROV_SHA2_HMAC_CTX(ctx)->hc_icontext);
+
+       /*
+        * Do a SHA2 update on the outer context, feeding the inner
+        * digest as data.
+        */
+       SHA2Update(&PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, digest,
+           sha_digest_len);
+
+       /*
+        * Do a SHA2 final on the outer context, storing the computing
+        * digest in the users buffer.
+        */
+       switch (mac->cd_format) {
+       case CRYPTO_DATA_RAW:
+               if (digest_len != sha_digest_len) {
+                       /*
+                        * The caller requested a short digest. Digest
+                        * into a scratch buffer and return to
+                        * the user only what was requested.
+                        */
+                       SHA2Final(digest,
+                           &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext);
+                       bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
+                           mac->cd_offset, digest_len);
+               } else {
+                       SHA2Final((unsigned char *)mac->cd_raw.iov_base +
+                           mac->cd_offset,
+                           &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext);
+               }
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_final_uio(
+                   &PROV_SHA2_HMAC_CTX(ctx)->hc_ocontext, mac,
+                   digest_len, digest);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret == CRYPTO_SUCCESS)
+               mac->cd_length = digest_len;
+       else
+               mac->cd_length = 0;
+
+       bzero(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
+       kmem_free(ctx->cc_provider_private, sizeof (sha2_hmac_ctx_t));
+       ctx->cc_provider_private = NULL;
+
+       return (ret);
+}
+
+#define        SHA2_MAC_UPDATE(data, ctx, ret) {                               \
+       switch (data->cd_format) {                                      \
+       case CRYPTO_DATA_RAW:                                           \
+               SHA2Update(&(ctx).hc_icontext,                          \
+                   (uint8_t *)data->cd_raw.iov_base +                  \
+                   data->cd_offset, data->cd_length);                  \
+               break;                                                  \
+       case CRYPTO_DATA_UIO:                                           \
+               ret = sha2_digest_update_uio(&(ctx).hc_icontext, data); \
+               break;                                                  \
+       default:                                                        \
+               ret = CRYPTO_ARGUMENTS_BAD;                             \
+       }                                                               \
+}
+
+/* ARGSUSED */
+static int
+sha2_mac_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
+    crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uchar_t digest[SHA512_DIGEST_LENGTH];
+       sha2_hmac_ctx_t sha2_hmac_ctx;
+       uint32_t sha_digest_len, digest_len, sha_hmac_block_size;
+       uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
+
+       /*
+        * Set the digest length and block size to values appropriate to the
+        * mechanism
+        */
+       switch (mechanism->cm_type) {
+       case SHA256_HMAC_MECH_INFO_TYPE:
+       case SHA256_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = digest_len = SHA256_DIGEST_LENGTH;
+               sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE;
+               break;
+       case SHA384_HMAC_MECH_INFO_TYPE:
+       case SHA384_HMAC_GEN_MECH_INFO_TYPE:
+       case SHA512_HMAC_MECH_INFO_TYPE:
+       case SHA512_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
+               sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
+               break;
+       default:
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       /* Add support for key by attributes (RFE 4706552) */
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       if (ctx_template != NULL) {
+               /* reuse context template */
+               bcopy(ctx_template, &sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
+       } else {
+               sha2_hmac_ctx.hc_mech_type = mechanism->cm_type;
+               /* no context template, initialize context */
+               if (keylen_in_bytes > sha_hmac_block_size) {
+                       /*
+                        * Hash the passed-in key to get a smaller key.
+                        * The inner context is used since it hasn't been
+                        * initialized yet.
+                        */
+                       PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
+                           &sha2_hmac_ctx.hc_icontext,
+                           key->ck_data, keylen_in_bytes, digest);
+                       sha2_mac_init_ctx(&sha2_hmac_ctx, digest,
+                           sha_digest_len);
+               } else {
+                       sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data,
+                           keylen_in_bytes);
+               }
+       }
+
+       /* get the mechanism parameters, if applicable */
+       if ((mechanism->cm_type % 3) == 2) {
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (ulong_t)) {
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+                       goto bail;
+               }
+               PROV_SHA2_GET_DIGEST_LEN(mechanism, digest_len);
+               if (digest_len > sha_digest_len) {
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+                       goto bail;
+               }
+       }
+
+       /* do a SHA2 update of the inner context using the specified data */
+       SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret);
+       if (ret != CRYPTO_SUCCESS)
+               /* the update failed, free context and bail */
+               goto bail;
+
+       /*
+        * Do a SHA2 final on the inner context.
+        */
+       SHA2Final(digest, &sha2_hmac_ctx.hc_icontext);
+
+       /*
+        * Do an SHA2 update on the outer context, feeding the inner
+        * digest as data.
+        *
+        * HMAC-SHA384 needs special handling as the outer hash needs only 48
+        * bytes of the inner hash value.
+        */
+       if (mechanism->cm_type == SHA384_HMAC_MECH_INFO_TYPE ||
+           mechanism->cm_type == SHA384_HMAC_GEN_MECH_INFO_TYPE)
+               SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest,
+                   SHA384_DIGEST_LENGTH);
+       else
+               SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len);
+
+       /*
+        * Do a SHA2 final on the outer context, storing the computed
+        * digest in the users buffer.
+        */
+       switch (mac->cd_format) {
+       case CRYPTO_DATA_RAW:
+               if (digest_len != sha_digest_len) {
+                       /*
+                        * The caller requested a short digest. Digest
+                        * into a scratch buffer and return to
+                        * the user only what was requested.
+                        */
+                       SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext);
+                       bcopy(digest, (unsigned char *)mac->cd_raw.iov_base +
+                           mac->cd_offset, digest_len);
+               } else {
+                       SHA2Final((unsigned char *)mac->cd_raw.iov_base +
+                           mac->cd_offset, &sha2_hmac_ctx.hc_ocontext);
+               }
+               break;
+       case CRYPTO_DATA_UIO:
+               ret = sha2_digest_final_uio(&sha2_hmac_ctx.hc_ocontext, mac,
+                   digest_len, digest);
+               break;
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (ret == CRYPTO_SUCCESS) {
+               mac->cd_length = digest_len;
+               return (CRYPTO_SUCCESS);
+       }
+bail:
+       bzero(&sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
+       mac->cd_length = 0;
+       return (ret);
+}
+
+/* ARGSUSED */
+static int
+sha2_mac_verify_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
+    crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
+{
+       int ret = CRYPTO_SUCCESS;
+       uchar_t digest[SHA512_DIGEST_LENGTH];
+       sha2_hmac_ctx_t sha2_hmac_ctx;
+       uint32_t sha_digest_len, digest_len, sha_hmac_block_size;
+       uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
+
+       /*
+        * Set the digest length and block size to values appropriate to the
+        * mechanism
+        */
+       switch (mechanism->cm_type) {
+       case SHA256_HMAC_MECH_INFO_TYPE:
+       case SHA256_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = digest_len = SHA256_DIGEST_LENGTH;
+               sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE;
+               break;
+       case SHA384_HMAC_MECH_INFO_TYPE:
+       case SHA384_HMAC_GEN_MECH_INFO_TYPE:
+       case SHA512_HMAC_MECH_INFO_TYPE:
+       case SHA512_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = digest_len = SHA512_DIGEST_LENGTH;
+               sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
+               break;
+       default:
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       /* Add support for key by attributes (RFE 4706552) */
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       if (ctx_template != NULL) {
+               /* reuse context template */
+               bcopy(ctx_template, &sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
+       } else {
+               sha2_hmac_ctx.hc_mech_type = mechanism->cm_type;
+               /* no context template, initialize context */
+               if (keylen_in_bytes > sha_hmac_block_size) {
+                       /*
+                        * Hash the passed-in key to get a smaller key.
+                        * The inner context is used since it hasn't been
+                        * initialized yet.
+                        */
+                       PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
+                           &sha2_hmac_ctx.hc_icontext,
+                           key->ck_data, keylen_in_bytes, digest);
+                       sha2_mac_init_ctx(&sha2_hmac_ctx, digest,
+                           sha_digest_len);
+               } else {
+                       sha2_mac_init_ctx(&sha2_hmac_ctx, key->ck_data,
+                           keylen_in_bytes);
+               }
+       }
+
+       /* get the mechanism parameters, if applicable */
+       if (mechanism->cm_type % 3 == 2) {
+               if (mechanism->cm_param == NULL ||
+                   mechanism->cm_param_len != sizeof (ulong_t)) {
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+                       goto bail;
+               }
+               PROV_SHA2_GET_DIGEST_LEN(mechanism, digest_len);
+               if (digest_len > sha_digest_len) {
+                       ret = CRYPTO_MECHANISM_PARAM_INVALID;
+                       goto bail;
+               }
+       }
+
+       if (mac->cd_length != digest_len) {
+               ret = CRYPTO_INVALID_MAC;
+               goto bail;
+       }
+
+       /* do a SHA2 update of the inner context using the specified data */
+       SHA2_MAC_UPDATE(data, sha2_hmac_ctx, ret);
+       if (ret != CRYPTO_SUCCESS)
+               /* the update failed, free context and bail */
+               goto bail;
+
+       /* do a SHA2 final on the inner context */
+       SHA2Final(digest, &sha2_hmac_ctx.hc_icontext);
+
+       /*
+        * Do an SHA2 update on the outer context, feeding the inner
+        * digest as data.
+        *
+        * HMAC-SHA384 needs special handling as the outer hash needs only 48
+        * bytes of the inner hash value.
+        */
+       if (mechanism->cm_type == SHA384_HMAC_MECH_INFO_TYPE ||
+           mechanism->cm_type == SHA384_HMAC_GEN_MECH_INFO_TYPE)
+               SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest,
+                   SHA384_DIGEST_LENGTH);
+       else
+               SHA2Update(&sha2_hmac_ctx.hc_ocontext, digest, sha_digest_len);
+
+       /*
+        * Do a SHA2 final on the outer context, storing the computed
+        * digest in the users buffer.
+        */
+       SHA2Final(digest, &sha2_hmac_ctx.hc_ocontext);
+
+       /*
+        * Compare the computed digest against the expected digest passed
+        * as argument.
+        */
+
+       switch (mac->cd_format) {
+
+       case CRYPTO_DATA_RAW:
+               if (bcmp(digest, (unsigned char *)mac->cd_raw.iov_base +
+                   mac->cd_offset, digest_len) != 0)
+                       ret = CRYPTO_INVALID_MAC;
+               break;
+
+       case CRYPTO_DATA_UIO: {
+               off_t offset = mac->cd_offset;
+               uint_t vec_idx;
+               off_t scratch_offset = 0;
+               size_t length = digest_len;
+               size_t cur_len;
+
+               /* we support only kernel buffer */
+               if (mac->cd_uio->uio_segflg != UIO_SYSSPACE)
+                       return (CRYPTO_ARGUMENTS_BAD);
+
+               /* jump to the first iovec containing the expected digest */
+               for (vec_idx = 0;
+                   offset >= mac->cd_uio->uio_iov[vec_idx].iov_len &&
+                   vec_idx < mac->cd_uio->uio_iovcnt;
+                   offset -= mac->cd_uio->uio_iov[vec_idx++].iov_len)
+                       ;
+               if (vec_idx == mac->cd_uio->uio_iovcnt) {
+                       /*
+                        * The caller specified an offset that is
+                        * larger than the total size of the buffers
+                        * it provided.
+                        */
+                       ret = CRYPTO_DATA_LEN_RANGE;
+                       break;
+               }
+
+               /* do the comparison of computed digest vs specified one */
+               while (vec_idx < mac->cd_uio->uio_iovcnt && length > 0) {
+                       cur_len = MIN(mac->cd_uio->uio_iov[vec_idx].iov_len -
+                           offset, length);
+
+                       if (bcmp(digest + scratch_offset,
+                           mac->cd_uio->uio_iov[vec_idx].iov_base + offset,
+                           cur_len) != 0) {
+                               ret = CRYPTO_INVALID_MAC;
+                               break;
+                       }
+
+                       length -= cur_len;
+                       vec_idx++;
+                       scratch_offset += cur_len;
+                       offset = 0;
+               }
+               break;
+       }
+
+       default:
+               ret = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       return (ret);
+bail:
+       bzero(&sha2_hmac_ctx, sizeof (sha2_hmac_ctx_t));
+       mac->cd_length = 0;
+       return (ret);
+}
+
+/*
+ * KCF software provider context management entry points.
+ */
+
+/* ARGSUSED */
+static int
+sha2_create_ctx_template(crypto_provider_handle_t provider,
+    crypto_mechanism_t *mechanism, crypto_key_t *key,
+    crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
+    crypto_req_handle_t req)
+{
+       sha2_hmac_ctx_t *sha2_hmac_ctx_tmpl;
+       uint_t keylen_in_bytes = CRYPTO_BITS2BYTES(key->ck_length);
+       uint32_t sha_digest_len, sha_hmac_block_size;
+
+       /*
+        * Set the digest length and block size to values appropriate to the
+        * mechanism
+        */
+       switch (mechanism->cm_type) {
+       case SHA256_HMAC_MECH_INFO_TYPE:
+       case SHA256_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = SHA256_DIGEST_LENGTH;
+               sha_hmac_block_size = SHA256_HMAC_BLOCK_SIZE;
+               break;
+       case SHA384_HMAC_MECH_INFO_TYPE:
+       case SHA384_HMAC_GEN_MECH_INFO_TYPE:
+       case SHA512_HMAC_MECH_INFO_TYPE:
+       case SHA512_HMAC_GEN_MECH_INFO_TYPE:
+               sha_digest_len = SHA512_DIGEST_LENGTH;
+               sha_hmac_block_size = SHA512_HMAC_BLOCK_SIZE;
+               break;
+       default:
+               return (CRYPTO_MECHANISM_INVALID);
+       }
+
+       /* Add support for key by attributes (RFE 4706552) */
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Allocate and initialize SHA2 context.
+        */
+       sha2_hmac_ctx_tmpl = kmem_alloc(sizeof (sha2_hmac_ctx_t),
+           crypto_kmflag(req));
+       if (sha2_hmac_ctx_tmpl == NULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       sha2_hmac_ctx_tmpl->hc_mech_type = mechanism->cm_type;
+
+       if (keylen_in_bytes > sha_hmac_block_size) {
+               uchar_t digested_key[SHA512_DIGEST_LENGTH];
+
+               /*
+                * Hash the passed-in key to get a smaller key.
+                * The inner context is used since it hasn't been
+                * initialized yet.
+                */
+               PROV_SHA2_DIGEST_KEY(mechanism->cm_type / 3,
+                   &sha2_hmac_ctx_tmpl->hc_icontext,
+                   key->ck_data, keylen_in_bytes, digested_key);
+               sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, digested_key,
+                   sha_digest_len);
+       } else {
+               sha2_mac_init_ctx(sha2_hmac_ctx_tmpl, key->ck_data,
+                   keylen_in_bytes);
+       }
+
+       *ctx_template = (crypto_spi_ctx_template_t)sha2_hmac_ctx_tmpl;
+       *ctx_template_size = sizeof (sha2_hmac_ctx_t);
+
+       return (CRYPTO_SUCCESS);
+}
+
+static int
+sha2_free_context(crypto_ctx_t *ctx)
+{
+       uint_t ctx_len;
+
+       if (ctx->cc_provider_private == NULL)
+               return (CRYPTO_SUCCESS);
+
+       /*
+        * We have to free either SHA2 or SHA2-HMAC contexts, which
+        * have different lengths.
+        *
+        * Note: Below is dependent on the mechanism ordering.
+        */
+
+       if (PROV_SHA2_CTX(ctx)->sc_mech_type % 3 == 0)
+               ctx_len = sizeof (sha2_ctx_t);
+       else
+               ctx_len = sizeof (sha2_hmac_ctx_t);
+
+       bzero(ctx->cc_provider_private, ctx_len);
+       kmem_free(ctx->cc_provider_private, ctx_len);
+       ctx->cc_provider_private = NULL;
+
+       return (CRYPTO_SUCCESS);
+}
diff --git a/zfs/module/icp/io/skein_mod.c b/zfs/module/icp/io/skein_mod.c
new file mode 100644 (file)
index 0000000..705b1e8
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 2013 Saso Kiselkov. All rights reserved.
+ */
+
+#include <sys/modctl.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/spi.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#define        SKEIN_MODULE_IMPL
+#include <sys/skein.h>
+
+/*
+ * Like the sha2 module, we create the skein module with two modlinkages:
+ * - modlmisc to allow direct calls to Skein_* API functions.
+ * - modlcrypto to integrate well into the Kernel Crypto Framework (KCF).
+ */
+static struct modlmisc modlmisc = {
+       &mod_cryptoops,
+       "Skein Message-Digest Algorithm"
+};
+
+static struct modlcrypto modlcrypto = {
+       &mod_cryptoops,
+       "Skein Kernel SW Provider"
+};
+
+static struct modlinkage modlinkage = {
+       MODREV_1, {&modlmisc, &modlcrypto, NULL}
+};
+
+static crypto_mech_info_t skein_mech_info_tab[] = {
+       {CKM_SKEIN_256, SKEIN_256_MECH_INFO_TYPE,
+           CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
+           0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+       {CKM_SKEIN_256_MAC, SKEIN_256_MAC_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       {CKM_SKEIN_512, SKEIN_512_MECH_INFO_TYPE,
+           CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
+           0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+       {CKM_SKEIN_512_MAC, SKEIN_512_MAC_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES},
+       {CKM_SKEIN1024, SKEIN1024_MECH_INFO_TYPE,
+           CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
+           0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
+       {CKM_SKEIN1024_MAC, SKEIN1024_MAC_MECH_INFO_TYPE,
+           CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
+           CRYPTO_KEYSIZE_UNIT_IN_BYTES}
+};
+
+static void skein_provider_status(crypto_provider_handle_t, uint_t *);
+
+static crypto_control_ops_t skein_control_ops = {
+       skein_provider_status
+};
+
+static int skein_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
+    crypto_req_handle_t);
+static int skein_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+static int skein_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
+static int skein_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
+static int skein_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
+    crypto_req_handle_t);
+
+static crypto_digest_ops_t skein_digest_ops = {
+       skein_digest_init,
+       skein_digest,
+       skein_update,
+       NULL,
+       skein_final,
+       skein_digest_atomic
+};
+
+static int skein_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+static int skein_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
+    crypto_spi_ctx_template_t, crypto_req_handle_t);
+
+static crypto_mac_ops_t skein_mac_ops = {
+       skein_mac_init,
+       NULL,
+       skein_update,   /* using regular digest update is OK here */
+       skein_final,    /* using regular digest final is OK here */
+       skein_mac_atomic,
+       NULL
+};
+
+static int skein_create_ctx_template(crypto_provider_handle_t,
+    crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
+    size_t *, crypto_req_handle_t);
+static int skein_free_context(crypto_ctx_t *);
+
+static crypto_ctx_ops_t skein_ctx_ops = {
+       skein_create_ctx_template,
+       skein_free_context
+};
+
+static crypto_ops_t skein_crypto_ops = {{{{{
+       &skein_control_ops,
+       &skein_digest_ops,
+       NULL,
+       &skein_mac_ops,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       &skein_ctx_ops,
+}}}}};
+
+static crypto_provider_info_t skein_prov_info = {{{{
+       CRYPTO_SPI_VERSION_1,
+       "Skein Software Provider",
+       CRYPTO_SW_PROVIDER,
+       NULL,
+       &skein_crypto_ops,
+       sizeof (skein_mech_info_tab) / sizeof (crypto_mech_info_t),
+       skein_mech_info_tab
+}}}};
+
+static crypto_kcf_provider_handle_t skein_prov_handle = 0;
+
+typedef struct skein_ctx {
+       skein_mech_type_t               sc_mech_type;
+       size_t                          sc_digest_bitlen;
+       /*LINTED(E_ANONYMOUS_UNION_DECL)*/
+       union {
+               Skein_256_Ctxt_t        sc_256;
+               Skein_512_Ctxt_t        sc_512;
+               Skein1024_Ctxt_t        sc_1024;
+       };
+} skein_ctx_t;
+#define        SKEIN_CTX(_ctx_)        ((skein_ctx_t *)((_ctx_)->cc_provider_private))
+#define        SKEIN_CTX_LVALUE(_ctx_) (_ctx_)->cc_provider_private
+#define        SKEIN_OP(_skein_ctx, _op, ...)                                  \
+       do {                                                            \
+               skein_ctx_t     *sc = (_skein_ctx);                     \
+               switch (sc->sc_mech_type) {                             \
+               case SKEIN_256_MECH_INFO_TYPE:                          \
+               case SKEIN_256_MAC_MECH_INFO_TYPE:                      \
+                       (void) Skein_256_ ## _op(&sc->sc_256, __VA_ARGS__);\
+                       break;                                          \
+               case SKEIN_512_MECH_INFO_TYPE:                          \
+               case SKEIN_512_MAC_MECH_INFO_TYPE:                      \
+                       (void) Skein_512_ ## _op(&sc->sc_512, __VA_ARGS__);\
+                       break;                                          \
+               case SKEIN1024_MECH_INFO_TYPE:                          \
+               case SKEIN1024_MAC_MECH_INFO_TYPE:                      \
+                       (void) Skein1024_ ## _op(&sc->sc_1024, __VA_ARGS__);\
+                       break;                                          \
+               }                                                       \
+               _NOTE(CONSTCOND)                                        \
+       } while (0)
+
+static int
+skein_get_digest_bitlen(const crypto_mechanism_t *mechanism, size_t *result)
+{
+       if (mechanism->cm_param != NULL) {
+               /*LINTED(E_BAD_PTR_CAST_ALIGN)*/
+               skein_param_t   *param = (skein_param_t *)mechanism->cm_param;
+
+               if (mechanism->cm_param_len != sizeof (*param) ||
+                   param->sp_digest_bitlen == 0) {
+                       return (CRYPTO_MECHANISM_PARAM_INVALID);
+               }
+               *result = param->sp_digest_bitlen;
+       } else {
+               switch (mechanism->cm_type) {
+               case SKEIN_256_MECH_INFO_TYPE:
+                       *result = 256;
+                       break;
+               case SKEIN_512_MECH_INFO_TYPE:
+                       *result = 512;
+                       break;
+               case SKEIN1024_MECH_INFO_TYPE:
+                       *result = 1024;
+                       break;
+               default:
+                       return (CRYPTO_MECHANISM_INVALID);
+               }
+       }
+       return (CRYPTO_SUCCESS);
+}
+
+int
+skein_mod_init(void)
+{
+       int error;
+
+       if ((error = mod_install(&modlinkage)) != 0)
+               return (error);
+
+       /*
+        * Try to register with KCF - failure shouldn't unload us, since we
+        * still may want to continue providing misc/skein functionality.
+        */
+       (void) crypto_register_provider(&skein_prov_info, &skein_prov_handle);
+
+       return (0);
+}
+
+int
+skein_mod_fini(void) {
+       int ret;
+
+       if (skein_prov_handle != 0) {
+               if ((ret = crypto_unregister_provider(skein_prov_handle)) !=
+                   CRYPTO_SUCCESS) {
+                       cmn_err(CE_WARN,
+                           "skein _fini: crypto_unregister_provider() "
+                           "failed (0x%x)", ret);
+                       return (EBUSY);
+               }
+               skein_prov_handle = 0;
+       }
+
+       return (mod_remove(&modlinkage));
+}
+
+/*
+ * KCF software provider control entry points.
+ */
+/* ARGSUSED */
+static void
+skein_provider_status(crypto_provider_handle_t provider, uint_t *status)
+{
+       *status = CRYPTO_PROVIDER_READY;
+}
+
+/*
+ * General Skein hashing helper functions.
+ */
+
+/*
+ * Performs an Update on a context with uio input data.
+ */
+static int
+skein_digest_update_uio(skein_ctx_t *ctx, const crypto_data_t *data)
+{
+       off_t           offset = data->cd_offset;
+       size_t          length = data->cd_length;
+       uint_t          vec_idx;
+       size_t          cur_len;
+       const uio_t     *uio = data->cd_uio;
+
+       /* we support only kernel buffer */
+       if (uio->uio_segflg != UIO_SYSSPACE)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Jump to the first iovec containing data to be
+        * digested.
+        */
+       for (vec_idx = 0; vec_idx < uio->uio_iovcnt &&
+           offset >= uio->uio_iov[vec_idx].iov_len;
+           offset -= uio->uio_iov[vec_idx++].iov_len)
+               ;
+       if (vec_idx == uio->uio_iovcnt) {
+               /*
+                * The caller specified an offset that is larger than the
+                * total size of the buffers it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       /*
+        * Now do the digesting on the iovecs.
+        */
+       while (vec_idx < uio->uio_iovcnt && length > 0) {
+               cur_len = MIN(uio->uio_iov[vec_idx].iov_len - offset, length);
+               SKEIN_OP(ctx, Update, (uint8_t *)uio->uio_iov[vec_idx].iov_base
+                   + offset, cur_len);
+               length -= cur_len;
+               vec_idx++;
+               offset = 0;
+       }
+
+       if (vec_idx == uio->uio_iovcnt && length > 0) {
+               /*
+                * The end of the specified iovec's was reached but
+                * the length requested could not be processed, i.e.
+                * The caller requested to digest more data than it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * Performs a Final on a context and writes to a uio digest output.
+ */
+static int
+skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+       off_t   offset = digest->cd_offset;
+       uint_t  vec_idx;
+       uio_t   *uio = digest->cd_uio;
+
+       /* we support only kernel buffer */
+       if (uio->uio_segflg != UIO_SYSSPACE)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Jump to the first iovec containing ptr to the digest to be returned.
+        */
+       for (vec_idx = 0; offset >= uio->uio_iov[vec_idx].iov_len &&
+           vec_idx < uio->uio_iovcnt;
+           offset -= uio->uio_iov[vec_idx++].iov_len)
+               ;
+       if (vec_idx == uio->uio_iovcnt) {
+               /*
+                * The caller specified an offset that is larger than the
+                * total size of the buffers it provided.
+                */
+               return (CRYPTO_DATA_LEN_RANGE);
+       }
+       if (offset + CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen) <=
+           uio->uio_iov[vec_idx].iov_len) {
+               /* The computed digest will fit in the current iovec. */
+               SKEIN_OP(ctx, Final,
+                   (uchar_t *)uio->uio_iov[vec_idx].iov_base + offset);
+       } else {
+               uint8_t *digest_tmp;
+               off_t scratch_offset = 0;
+               size_t length = CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen);
+               size_t cur_len;
+
+               digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES(
+                   ctx->sc_digest_bitlen), crypto_kmflag(req));
+               if (digest_tmp == NULL)
+                       return (CRYPTO_HOST_MEMORY);
+               SKEIN_OP(ctx, Final, digest_tmp);
+               while (vec_idx < uio->uio_iovcnt && length > 0) {
+                       cur_len = MIN(uio->uio_iov[vec_idx].iov_len - offset,
+                           length);
+                       bcopy(digest_tmp + scratch_offset,
+                           uio->uio_iov[vec_idx].iov_base + offset, cur_len);
+
+                       length -= cur_len;
+                       vec_idx++;
+                       scratch_offset += cur_len;
+                       offset = 0;
+               }
+               kmem_free(digest_tmp, CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen));
+
+               if (vec_idx == uio->uio_iovcnt && length > 0) {
+                       /*
+                        * The end of the specified iovec's was reached but
+                        * the length requested could not be processed, i.e.
+                        * The caller requested to digest more data than it
+                        * provided.
+                        */
+                       return (CRYPTO_DATA_LEN_RANGE);
+               }
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * KCF software provider digest entry points.
+ */
+
+/*
+ * Initializes a skein digest context to the configuration in `mechanism'.
+ * The mechanism cm_type must be one of SKEIN_*_MECH_INFO_TYPE. The cm_param
+ * field may contain a skein_param_t structure indicating the length of the
+ * digest the algorithm should produce. Otherwise the default output lengths
+ * are applied (32 bytes for Skein-256, 64 bytes for Skein-512 and 128 bytes
+ * for Skein-1024).
+ */
+static int
+skein_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_req_handle_t req)
+{
+       int     error = CRYPTO_SUCCESS;
+
+       if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
+               return (CRYPTO_MECHANISM_INVALID);
+
+       SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
+           crypto_kmflag(req));
+       if (SKEIN_CTX(ctx) == NULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       SKEIN_CTX(ctx)->sc_mech_type = mechanism->cm_type;
+       error = skein_get_digest_bitlen(mechanism,
+           &SKEIN_CTX(ctx)->sc_digest_bitlen);
+       if (error != CRYPTO_SUCCESS)
+               goto errout;
+       SKEIN_OP(SKEIN_CTX(ctx), Init, SKEIN_CTX(ctx)->sc_digest_bitlen);
+
+       return (CRYPTO_SUCCESS);
+errout:
+       bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+       kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+       SKEIN_CTX_LVALUE(ctx) = NULL;
+       return (error);
+}
+
+/*
+ * Executes a skein_update and skein_digest on a pre-initialized crypto
+ * context in a single step. See the documentation to these functions to
+ * see what to pass here.
+ */
+static int
+skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
+    crypto_req_handle_t req)
+{
+       int error = CRYPTO_SUCCESS;
+
+       ASSERT(SKEIN_CTX(ctx) != NULL);
+
+       if (digest->cd_length <
+           CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) {
+               digest->cd_length =
+                   CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       error = skein_update(ctx, data, req);
+       if (error != CRYPTO_SUCCESS) {
+               bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+               kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+               SKEIN_CTX_LVALUE(ctx) = NULL;
+               digest->cd_length = 0;
+               return (error);
+       }
+       error = skein_final(ctx, digest, req);
+
+       return (error);
+}
+
+/*
+ * Performs a skein Update with the input message in `data' (successive calls
+ * can push more data). This is used both for digest and MAC operation.
+ * Supported input data formats are raw, uio and mblk.
+ */
+/*ARGSUSED*/
+static int
+skein_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
+{
+       int error = CRYPTO_SUCCESS;
+
+       ASSERT(SKEIN_CTX(ctx) != NULL);
+
+       switch (data->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SKEIN_OP(SKEIN_CTX(ctx), Update,
+                   (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
+                   data->cd_length);
+               break;
+       case CRYPTO_DATA_UIO:
+               error = skein_digest_update_uio(SKEIN_CTX(ctx), data);
+               break;
+       default:
+               error = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       return (error);
+}
+
+/*
+ * Performs a skein Final, writing the output to `digest'. This is used both
+ * for digest and MAC operation.
+ * Supported output digest formats are raw, uio and mblk.
+ */
+/*ARGSUSED*/
+static int
+skein_final(crypto_ctx_t *ctx, crypto_data_t *digest, crypto_req_handle_t req)
+{
+       int error = CRYPTO_SUCCESS;
+
+       ASSERT(SKEIN_CTX(ctx) != NULL);
+
+       if (digest->cd_length <
+           CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) {
+               digest->cd_length =
+                   CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
+               return (CRYPTO_BUFFER_TOO_SMALL);
+       }
+
+       switch (digest->cd_format) {
+       case CRYPTO_DATA_RAW:
+               SKEIN_OP(SKEIN_CTX(ctx), Final,
+                   (uint8_t *)digest->cd_raw.iov_base + digest->cd_offset);
+               break;
+       case CRYPTO_DATA_UIO:
+               error = skein_digest_final_uio(SKEIN_CTX(ctx), digest, req);
+               break;
+       default:
+               error = CRYPTO_ARGUMENTS_BAD;
+       }
+
+       if (error == CRYPTO_SUCCESS)
+               digest->cd_length =
+                   CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
+       else
+               digest->cd_length = 0;
+
+       bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+       kmem_free(SKEIN_CTX(ctx), sizeof (*(SKEIN_CTX(ctx))));
+       SKEIN_CTX_LVALUE(ctx) = NULL;
+
+       return (error);
+}
+
+/*
+ * Performs a full skein digest computation in a single call, configuring the
+ * algorithm according to `mechanism', reading the input to be digested from
+ * `data' and writing the output to `digest'.
+ * Supported input/output formats are raw, uio and mblk.
+ */
+/*ARGSUSED*/
+static int
+skein_digest_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_data_t *data, crypto_data_t *digest, crypto_req_handle_t req)
+{
+       int             error;
+       skein_ctx_t     skein_ctx;
+       crypto_ctx_t    ctx;
+       SKEIN_CTX_LVALUE(&ctx) = &skein_ctx;
+
+       /* Init */
+       if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
+               return (CRYPTO_MECHANISM_INVALID);
+       skein_ctx.sc_mech_type = mechanism->cm_type;
+       error = skein_get_digest_bitlen(mechanism, &skein_ctx.sc_digest_bitlen);
+       if (error != CRYPTO_SUCCESS)
+               goto out;
+       SKEIN_OP(&skein_ctx, Init, skein_ctx.sc_digest_bitlen);
+
+       if ((error = skein_update(&ctx, data, digest)) != CRYPTO_SUCCESS)
+               goto out;
+       if ((error = skein_final(&ctx, data, digest)) != CRYPTO_SUCCESS)
+               goto out;
+
+out:
+       if (error == CRYPTO_SUCCESS)
+               digest->cd_length =
+                   CRYPTO_BITS2BYTES(skein_ctx.sc_digest_bitlen);
+       else
+               digest->cd_length = 0;
+       bzero(&skein_ctx, sizeof (skein_ctx));
+
+       return (error);
+}
+
+/*
+ * Helper function that builds a Skein MAC context from the provided
+ * mechanism and key.
+ */
+static int
+skein_mac_ctx_build(skein_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_key_t *key)
+{
+       int error;
+
+       if (!VALID_SKEIN_MAC_MECH(mechanism->cm_type))
+               return (CRYPTO_MECHANISM_INVALID);
+       if (key->ck_format != CRYPTO_KEY_RAW)
+               return (CRYPTO_ARGUMENTS_BAD);
+       ctx->sc_mech_type = mechanism->cm_type;
+       error = skein_get_digest_bitlen(mechanism, &ctx->sc_digest_bitlen);
+       if (error != CRYPTO_SUCCESS)
+               return (error);
+       SKEIN_OP(ctx, InitExt, ctx->sc_digest_bitlen, 0, key->ck_data,
+           CRYPTO_BITS2BYTES(key->ck_length));
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * KCF software provide mac entry points.
+ */
+/*
+ * Initializes a skein MAC context. You may pass a ctx_template, in which
+ * case the template will be reused to make initialization more efficient.
+ * Otherwise a new context will be constructed. The mechanism cm_type must
+ * be one of SKEIN_*_MAC_MECH_INFO_TYPE. Same as in skein_digest_init, you
+ * may pass a skein_param_t in cm_param to configure the length of the
+ * digest. The key must be in raw format.
+ */
+static int
+skein_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
+    crypto_req_handle_t req)
+{
+       int     error;
+
+       SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
+           crypto_kmflag(req));
+       if (SKEIN_CTX(ctx) == NULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       if (ctx_template != NULL) {
+               bcopy(ctx_template, SKEIN_CTX(ctx),
+                   sizeof (*SKEIN_CTX(ctx)));
+       } else {
+               error = skein_mac_ctx_build(SKEIN_CTX(ctx), mechanism, key);
+               if (error != CRYPTO_SUCCESS)
+                       goto errout;
+       }
+
+       return (CRYPTO_SUCCESS);
+errout:
+       bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+       kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+       return (error);
+}
+
+/*
+ * The MAC update and final calls are reused from the regular digest code.
+ */
+
+/*ARGSUSED*/
+/*
+ * Same as skein_digest_atomic, performs an atomic Skein MAC operation in
+ * one step. All the same properties apply to the arguments of this
+ * function as to those of the partial operations above.
+ */
+static int
+skein_mac_atomic(crypto_provider_handle_t provider,
+    crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
+    crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
+    crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
+{
+       /* faux crypto context just for skein_digest_{update,final} */
+       int             error;
+       crypto_ctx_t    ctx;
+       skein_ctx_t     skein_ctx;
+       SKEIN_CTX_LVALUE(&ctx) = &skein_ctx;
+
+       if (ctx_template != NULL) {
+               bcopy(ctx_template, &skein_ctx, sizeof (skein_ctx));
+       } else {
+               error = skein_mac_ctx_build(&skein_ctx, mechanism, key);
+               if (error != CRYPTO_SUCCESS)
+                       goto errout;
+       }
+
+       if ((error = skein_update(&ctx, data, req)) != CRYPTO_SUCCESS)
+               goto errout;
+       if ((error = skein_final(&ctx, mac, req)) != CRYPTO_SUCCESS)
+               goto errout;
+
+       return (CRYPTO_SUCCESS);
+errout:
+       bzero(&skein_ctx, sizeof (skein_ctx));
+       return (error);
+}
+
+/*
+ * KCF software provider context management entry points.
+ */
+
+/*
+ * Constructs a context template for the Skein MAC algorithm. The same
+ * properties apply to the arguments of this function as to those of
+ * skein_mac_init.
+ */
+/*ARGSUSED*/
+static int
+skein_create_ctx_template(crypto_provider_handle_t provider,
+    crypto_mechanism_t *mechanism, crypto_key_t *key,
+    crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
+    crypto_req_handle_t req)
+{
+       int             error;
+       skein_ctx_t     *ctx_tmpl;
+
+       ctx_tmpl = kmem_alloc(sizeof (*ctx_tmpl), crypto_kmflag(req));
+       if (ctx_tmpl == NULL)
+               return (CRYPTO_HOST_MEMORY);
+       error = skein_mac_ctx_build(ctx_tmpl, mechanism, key);
+       if (error != CRYPTO_SUCCESS)
+               goto errout;
+       *ctx_template = ctx_tmpl;
+       *ctx_template_size = sizeof (*ctx_tmpl);
+
+       return (CRYPTO_SUCCESS);
+errout:
+       bzero(ctx_tmpl, sizeof (*ctx_tmpl));
+       kmem_free(ctx_tmpl, sizeof (*ctx_tmpl));
+       return (error);
+}
+
+/*
+ * Frees a skein context in a parent crypto context.
+ */
+static int
+skein_free_context(crypto_ctx_t *ctx)
+{
+       if (SKEIN_CTX(ctx) != NULL) {
+               bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+               kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
+               SKEIN_CTX_LVALUE(ctx) = NULL;
+       }
+
+       return (CRYPTO_SUCCESS);
+}
diff --git a/zfs/module/icp/os/modconf.c b/zfs/module/icp/os/modconf.c
new file mode 100644 (file)
index 0000000..32b46b5
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/modctl.h>
+
+/*
+ * Null operations; used for uninitialized and "misc" modules.
+ */
+static int mod_null(struct modlmisc *, struct modlinkage *);
+static int mod_infonull(void *, struct modlinkage *, int *);
+
+/*
+ * Cryptographic Modules
+ */
+struct mod_ops mod_cryptoops = {
+       mod_null, mod_null, mod_infonull
+};
+
+/*
+ * Null operation; return 0.
+ */
+static int
+mod_null(struct modlmisc *modl, struct modlinkage *modlp)
+{
+       return (0);
+}
+
+/*
+ * Status for User modules.
+ */
+static int
+mod_infonull(void *modl, struct modlinkage *modlp, int *p0)
+{
+       *p0 = -1;               /* for modinfo display */
+       return (0);
+}
+
+/*
+ * Install a module.
+ * (This routine is in the Solaris SPARC DDI/DKI)
+ */
+int
+mod_install(struct modlinkage *modlp)
+{
+       int retval = -1;        /* No linkage structures */
+       struct modlmisc **linkpp;
+       struct modlmisc **linkpp1;
+
+       if (modlp->ml_rev != MODREV_1) {
+               cmn_err(CE_WARN, "mod_install: "
+                       "modlinkage structure is not MODREV_1\n");
+               return (EINVAL);
+       }
+       linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
+
+       while (*linkpp != NULL) {
+               if ((retval = MODL_INSTALL(*linkpp, modlp)) != 0) {
+                       linkpp1 = (struct modlmisc **)&modlp->ml_linkage[0];
+
+                       while (linkpp1 != linkpp) {
+                               MODL_REMOVE(*linkpp1, modlp); /* clean up */
+                               linkpp1++;
+                       }
+                       break;
+               }
+               linkpp++;
+       }
+       return (retval);
+}
+
+static char *reins_err =
+       "Could not reinstall %s\nReboot to correct the problem";
+
+/*
+ * Remove a module.  This is called by the module wrapper routine.
+ * (This routine is in the Solaris SPARC DDI/DKI)
+ */
+int
+mod_remove(struct modlinkage *modlp)
+{
+       int retval = 0;
+       struct modlmisc **linkpp, *last_linkp;
+
+       linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
+
+       while (*linkpp != NULL) {
+               if ((retval = MODL_REMOVE(*linkpp, modlp)) != 0) {
+                       last_linkp = *linkpp;
+                       linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
+                       while (*linkpp != last_linkp) {
+                               if (MODL_INSTALL(*linkpp, modlp) != 0) {
+                                       cmn_err(CE_WARN, reins_err,
+                                           (*linkpp)->misc_linkinfo);
+                                       break;
+                               }
+                               linkpp++;
+                       }
+                       break;
+               }
+               linkpp++;
+       }
+       return (retval);
+}
+
+/*
+ * Get module status.
+ * (This routine is in the Solaris SPARC DDI/DKI)
+ */
+int
+mod_info(struct modlinkage *modlp, struct modinfo *modinfop)
+{
+       int i;
+       int retval = 0;
+       struct modspecific_info *msip;
+       struct modlmisc **linkpp;
+
+       modinfop->mi_rev = modlp->ml_rev;
+
+       linkpp = (struct modlmisc **)modlp->ml_linkage;
+       msip = &modinfop->mi_msinfo[0];
+
+       for (i = 0; i < MODMAXLINK; i++) {
+               if (*linkpp == NULL) {
+                       msip->msi_linkinfo[0] = '\0';
+               } else {
+                       (void) strlcpy(msip->msi_linkinfo,
+                           (*linkpp)->misc_linkinfo, MODMAXLINKINFOLEN);
+                       retval = MODL_INFO(*linkpp, modlp, &msip->msi_p0);
+                       if (retval != 0)
+                               break;
+                       linkpp++;
+               }
+               msip++;
+       }
+
+       if (modinfop->mi_info == MI_INFO_LINKAGE) {
+               /*
+                * Slight kludge used to extract the address of the
+                * modlinkage structure from the module (just after
+                * loading a module for the very first time)
+                */
+               modinfop->mi_base = (void *)modlp;
+       }
+
+       if (retval == 0)
+               return (1);
+       return (0);
+}
\ No newline at end of file
diff --git a/zfs/module/icp/os/modhash.c b/zfs/module/icp/os/modhash.c
new file mode 100644 (file)
index 0000000..1ff782a
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ * 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.
+ */
+
+/*
+ * mod_hash: flexible hash table implementation.
+ *
+ * This is a reasonably fast, reasonably flexible hash table implementation
+ * which features pluggable hash algorithms to support storing arbitrary keys
+ * and values.  It is designed to handle small (< 100,000 items) amounts of
+ * data.  The hash uses chaining to resolve collisions, and does not feature a
+ * mechanism to grow the hash.  Care must be taken to pick nchains to be large
+ * enough for the application at hand, or lots of time will be wasted searching
+ * hash chains.
+ *
+ * The client of the hash is required to supply a number of items to support
+ * the various hash functions:
+ *
+ *     - Destructor functions for the key and value being hashed.
+ *       A destructor is responsible for freeing an object when the hash
+ *       table is no longer storing it.  Since keys and values can be of
+ *       arbitrary type, separate destructors for keys & values are used.
+ *       These may be mod_hash_null_keydtor and mod_hash_null_valdtor if no
+ *       destructor is needed for either a key or value.
+ *
+ *     - A hashing algorithm which returns a uint_t representing a hash index
+ *       The number returned need _not_ be between 0 and nchains.  The mod_hash
+ *       code will take care of doing that.  The second argument (after the
+ *       key) to the hashing function is a void * that represents
+ *       hash_alg_data-- this is provided so that the hashing algrorithm can
+ *       maintain some state across calls, or keep algorithm-specific
+ *       constants associated with the hash table.
+ *
+ *       A pointer-hashing and a string-hashing algorithm are supplied in
+ *       this file.
+ *
+ *     - A key comparator (a la qsort).
+ *       This is used when searching the hash chain.  The key comparator
+ *       determines if two keys match.  It should follow the return value
+ *       semantics of strcmp.
+ *
+ *       string and pointer comparators are supplied in this file.
+ *
+ * mod_hash_create_strhash() and mod_hash_create_ptrhash() provide good
+ * examples of how to create a customized hash table.
+ *
+ * Basic hash operations:
+ *
+ *   mod_hash_create_strhash(name, nchains, dtor),
+ *     create a hash using strings as keys.
+ *     NOTE: This create a hash which automatically cleans up the string
+ *           values it is given for keys.
+ *
+ *   mod_hash_create_ptrhash(name, nchains, dtor, key_elem_size):
+ *     create a hash using pointers as keys.
+ *
+ *   mod_hash_create_extended(name, nchains, kdtor, vdtor,
+ *                           hash_alg, hash_alg_data,
+ *                           keycmp, sleep)
+ *     create a customized hash table.
+ *
+ *   mod_hash_destroy_hash(hash):
+ *     destroy the given hash table, calling the key and value destructors
+ *     on each key-value pair stored in the hash.
+ *
+ *   mod_hash_insert(hash, key, val):
+ *     place a key, value pair into the given hash.
+ *     duplicate keys are rejected.
+ *
+ *   mod_hash_insert_reserve(hash, key, val, handle):
+ *     place a key, value pair into the given hash, using handle to indicate
+ *     the reserved storage for the pair.  (no memory allocation is needed
+ *     during a mod_hash_insert_reserve.)  duplicate keys are rejected.
+ *
+ *   mod_hash_reserve(hash, *handle):
+ *      reserve storage for a key-value pair using the memory allocation
+ *      policy of 'hash', returning the storage handle in 'handle'.
+ *
+ *   mod_hash_reserve_nosleep(hash, *handle): reserve storage for a key-value
+ *     pair ignoring the memory allocation policy of 'hash' and always without
+ *     sleep, returning the storage handle in 'handle'.
+ *
+ *   mod_hash_remove(hash, key, *val):
+ *     remove a key-value pair with key 'key' from 'hash', destroying the
+ *     stored key, and returning the value in val.
+ *
+ *   mod_hash_replace(hash, key, val)
+ *     atomically remove an existing key-value pair from a hash, and replace
+ *     the key and value with the ones supplied.  The removed key and value
+ *     (if any) are destroyed.
+ *
+ *   mod_hash_destroy(hash, key):
+ *     remove a key-value pair with key 'key' from 'hash', destroying both
+ *     stored key and stored value.
+ *
+ *   mod_hash_find(hash, key, val):
+ *     find a value in the hash table corresponding to the given key.
+ *
+ *   mod_hash_find_cb(hash, key, val, found_callback)
+ *     find a value in the hash table corresponding to the given key.
+ *     If a value is found, call specified callback passing key and val to it.
+ *      The callback is called with the hash lock held.
+ *     It is intended to be used in situations where the act of locating the
+ *     data must also modify it - such as in reference counting schemes.
+ *
+ *   mod_hash_walk(hash, callback(key, elem, arg), arg)
+ *     walks all the elements in the hashtable and invokes the callback
+ *     function with the key/value pair for each element.  the hashtable
+ *     is locked for readers so the callback function should not attempt
+ *     to do any updates to the hashable.  the callback function should
+ *     return MH_WALK_CONTINUE to continue walking the hashtable or
+ *     MH_WALK_TERMINATE to abort the walk of the hashtable.
+ *
+ *   mod_hash_clear(hash):
+ *     clears the given hash table of entries, calling the key and value
+ *     destructors for every element in the hash.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/bitmap.h>
+#include <sys/modhash_impl.h>
+#include <sys/sysmacros.h>
+
+/*
+ * MH_KEY_DESTROY()
+ *     Invoke the key destructor.
+ */
+#define        MH_KEY_DESTROY(hash, key) ((hash->mh_kdtor)(key))
+
+/*
+ * MH_VAL_DESTROY()
+ *     Invoke the value destructor.
+ */
+#define        MH_VAL_DESTROY(hash, val) ((hash->mh_vdtor)(val))
+
+/*
+ * MH_KEYCMP()
+ *     Call the key comparator for the given hash keys.
+ */
+#define        MH_KEYCMP(hash, key1, key2) ((hash->mh_keycmp)(key1, key2))
+
+/*
+ * Cache for struct mod_hash_entry
+ */
+kmem_cache_t *mh_e_cache = NULL;
+mod_hash_t *mh_head = NULL;
+kmutex_t mh_head_lock;
+
+/*
+ * mod_hash_null_keydtor()
+ * mod_hash_null_valdtor()
+ *     no-op key and value destructors.
+ */
+/*ARGSUSED*/
+void
+mod_hash_null_keydtor(mod_hash_key_t key)
+{
+}
+
+/*ARGSUSED*/
+void
+mod_hash_null_valdtor(mod_hash_val_t val)
+{
+}
+
+/*
+ * mod_hash_bystr()
+ * mod_hash_strkey_cmp()
+ * mod_hash_strkey_dtor()
+ * mod_hash_strval_dtor()
+ *     Hash and key comparison routines for hashes with string keys.
+ *
+ * mod_hash_create_strhash()
+ *     Create a hash using strings as keys
+ *
+ *     The string hashing algorithm is from the "Dragon Book" --
+ *     "Compilers: Principles, Tools & Techniques", by Aho, Sethi, Ullman
+ */
+
+/*ARGSUSED*/
+uint_t
+mod_hash_bystr(void *hash_data, mod_hash_key_t key)
+{
+       uint_t hash = 0;
+       uint_t g;
+       char *p, *k = (char *)key;
+
+       ASSERT(k);
+       for (p = k; *p != '\0'; p++) {
+               hash = (hash << 4) + *p;
+               if ((g = (hash & 0xf0000000)) != 0) {
+                       hash ^= (g >> 24);
+                       hash ^= g;
+               }
+       }
+       return (hash);
+}
+
+int
+mod_hash_strkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
+{
+       return (strcmp((char *)key1, (char *)key2));
+}
+
+void
+mod_hash_strkey_dtor(mod_hash_key_t key)
+{
+       char *c = (char *)key;
+       kmem_free(c, strlen(c) + 1);
+}
+
+void
+mod_hash_strval_dtor(mod_hash_val_t val)
+{
+       char *c = (char *)val;
+       kmem_free(c, strlen(c) + 1);
+}
+
+mod_hash_t *
+mod_hash_create_strhash_nodtr(char *name, size_t nchains,
+    void (*val_dtor)(mod_hash_val_t))
+{
+       return mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
+           val_dtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
+}
+
+mod_hash_t *
+mod_hash_create_strhash(char *name, size_t nchains,
+    void (*val_dtor)(mod_hash_val_t))
+{
+       return mod_hash_create_extended(name, nchains, mod_hash_strkey_dtor,
+           val_dtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
+}
+
+void
+mod_hash_destroy_strhash(mod_hash_t *strhash)
+{
+       ASSERT(strhash);
+       mod_hash_destroy_hash(strhash);
+}
+
+
+/*
+ * mod_hash_byptr()
+ * mod_hash_ptrkey_cmp()
+ *     Hash and key comparison routines for hashes with pointer keys.
+ *
+ * mod_hash_create_ptrhash()
+ * mod_hash_destroy_ptrhash()
+ *     Create a hash that uses pointers as keys.  This hash algorithm
+ *     picks an appropriate set of middle bits in the address to hash on
+ *     based on the size of the hash table and a hint about the size of
+ *     the items pointed at.
+ */
+uint_t
+mod_hash_byptr(void *hash_data, mod_hash_key_t key)
+{
+       uintptr_t k = (uintptr_t)key;
+       k >>= (int)(uintptr_t)hash_data;
+
+       return ((uint_t)k);
+}
+
+int
+mod_hash_ptrkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
+{
+       uintptr_t k1 = (uintptr_t)key1;
+       uintptr_t k2 = (uintptr_t)key2;
+       if (k1 > k2)
+               return (-1);
+       else if (k1 < k2)
+               return (1);
+       else
+               return (0);
+}
+
+mod_hash_t *
+mod_hash_create_ptrhash(char *name, size_t nchains,
+    void (*val_dtor)(mod_hash_val_t), size_t key_elem_size)
+{
+       size_t rshift;
+
+       /*
+        * We want to hash on the bits in the middle of the address word
+        * Bits far to the right in the word have little significance, and
+        * are likely to all look the same (for example, an array of
+        * 256-byte structures will have the bottom 8 bits of address
+        * words the same).  So we want to right-shift each address to
+        * ignore the bottom bits.
+        *
+        * The high bits, which are also unused, will get taken out when
+        * mod_hash takes hashkey % nchains.
+        */
+       rshift = highbit(key_elem_size);
+
+       return mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
+           val_dtor, mod_hash_byptr, (void *)rshift, mod_hash_ptrkey_cmp,
+           KM_SLEEP);
+}
+
+void
+mod_hash_destroy_ptrhash(mod_hash_t *hash)
+{
+       ASSERT(hash);
+       mod_hash_destroy_hash(hash);
+}
+
+/*
+ * mod_hash_byid()
+ * mod_hash_idkey_cmp()
+ *     Hash and key comparison routines for hashes with 32-bit unsigned keys.
+ *
+ * mod_hash_create_idhash()
+ * mod_hash_destroy_idhash()
+ * mod_hash_iddata_gen()
+ *     Create a hash that uses numeric keys.
+ *
+ *     The hash algorithm is documented in "Introduction to Algorithms"
+ *     (Cormen, Leiserson, Rivest);  when the hash table is created, it
+ *     attempts to find the next largest prime above the number of hash
+ *     slots.  The hash index is then this number times the key modulo
+ *     the hash size, or (key * prime) % nchains.
+ */
+uint_t
+mod_hash_byid(void *hash_data, mod_hash_key_t key)
+{
+       uint_t kval = (uint_t)(uintptr_t)hash_data;
+       return ((uint_t)(uintptr_t)key * (uint_t)kval);
+}
+
+int
+mod_hash_idkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
+{
+       return ((uint_t)(uintptr_t)key1 - (uint_t)(uintptr_t)key2);
+}
+
+/*
+ * Generate the next largest prime number greater than nchains; this value
+ * is intended to be later passed in to mod_hash_create_extended() as the
+ * hash_data.
+ */
+uint_t
+mod_hash_iddata_gen(size_t nchains)
+{
+       uint_t kval, i, prime;
+
+       /*
+        * Pick the first (odd) prime greater than nchains.  Make sure kval is
+        * odd (so start with nchains +1 or +2 as appropriate).
+        */
+       kval = (nchains % 2 == 0) ? nchains + 1 : nchains + 2;
+
+       for (;;) {
+               prime = 1;
+               for (i = 3; i * i <= kval; i += 2) {
+                       if (kval % i == 0)
+                               prime = 0;
+               }
+               if (prime == 1)
+                       break;
+               kval += 2;
+       }
+       return (kval);
+}
+
+mod_hash_t *
+mod_hash_create_idhash(char *name, size_t nchains,
+    void (*val_dtor)(mod_hash_val_t))
+{
+       uint_t kval = mod_hash_iddata_gen(nchains);
+
+       return (mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
+           val_dtor, mod_hash_byid, (void *)(uintptr_t)kval,
+           mod_hash_idkey_cmp, KM_SLEEP));
+}
+
+void
+mod_hash_destroy_idhash(mod_hash_t *hash)
+{
+       ASSERT(hash);
+       mod_hash_destroy_hash(hash);
+}
+
+void
+mod_hash_fini(void)
+{
+       mutex_destroy(&mh_head_lock);
+
+       if (mh_e_cache) {
+               kmem_cache_destroy(mh_e_cache);
+               mh_e_cache = NULL;
+       }
+}
+
+/*
+ * mod_hash_init()
+ *     sets up globals, etc for mod_hash_*
+ */
+void
+mod_hash_init(void)
+{
+       ASSERT(mh_e_cache == NULL);
+       mh_e_cache = kmem_cache_create("mod_hash_entries",
+           sizeof (struct mod_hash_entry), 0, NULL, NULL, NULL, NULL,
+           NULL, 0);
+
+       mutex_init(&mh_head_lock, NULL, MUTEX_DEFAULT, NULL);
+}
+
+/*
+ * mod_hash_create_extended()
+ *     The full-blown hash creation function.
+ *
+ * notes:
+ *     nchains         - how many hash slots to create.  More hash slots will
+ *                       result in shorter hash chains, but will consume
+ *                       slightly more memory up front.
+ *     sleep           - should be KM_SLEEP or KM_NOSLEEP, to indicate whether
+ *                       to sleep for memory, or fail in low-memory conditions.
+ *
+ *     Fails only if KM_NOSLEEP was specified, and no memory was available.
+ */
+mod_hash_t *
+mod_hash_create_extended(
+    char *hname,                       /* descriptive name for hash */
+    size_t nchains,                    /* number of hash slots */
+    void (*kdtor)(mod_hash_key_t),     /* key destructor */
+    void (*vdtor)(mod_hash_val_t),     /* value destructor */
+    uint_t (*hash_alg)(void *, mod_hash_key_t), /* hash algorithm */
+    void *hash_alg_data,               /* pass-thru arg for hash_alg */
+    int (*keycmp)(mod_hash_key_t, mod_hash_key_t), /* key comparator */
+    int sleep)                         /* whether to sleep for mem */
+{
+       mod_hash_t *mod_hash;
+       ASSERT(hname && keycmp && hash_alg && vdtor && kdtor);
+
+       if ((mod_hash = kmem_zalloc(MH_SIZE(nchains), sleep)) == NULL)
+               return (NULL);
+
+       mod_hash->mh_name = kmem_alloc(strlen(hname) + 1, sleep);
+       if (mod_hash->mh_name == NULL) {
+               kmem_free(mod_hash, MH_SIZE(nchains));
+               return (NULL);
+       }
+       (void) strcpy(mod_hash->mh_name, hname);
+
+       rw_init(&mod_hash->mh_contents, NULL, RW_DEFAULT, NULL);
+       mod_hash->mh_sleep = sleep;
+       mod_hash->mh_nchains = nchains;
+       mod_hash->mh_kdtor = kdtor;
+       mod_hash->mh_vdtor = vdtor;
+       mod_hash->mh_hashalg = hash_alg;
+       mod_hash->mh_hashalg_data = hash_alg_data;
+       mod_hash->mh_keycmp = keycmp;
+
+       /*
+        * Link the hash up on the list of hashes
+        */
+       mutex_enter(&mh_head_lock);
+       mod_hash->mh_next = mh_head;
+       mh_head = mod_hash;
+       mutex_exit(&mh_head_lock);
+
+       return (mod_hash);
+}
+
+/*
+ * mod_hash_destroy_hash()
+ *     destroy a hash table, destroying all of its stored keys and values
+ *     as well.
+ */
+void
+mod_hash_destroy_hash(mod_hash_t *hash)
+{
+       mod_hash_t *mhp, *mhpp;
+
+       mutex_enter(&mh_head_lock);
+       /*
+        * Remove the hash from the hash list
+        */
+       if (hash == mh_head) {          /* removing 1st list elem */
+               mh_head = mh_head->mh_next;
+       } else {
+               /*
+                * mhpp can start out NULL since we know the 1st elem isn't the
+                * droid we're looking for.
+                */
+               mhpp = NULL;
+               for (mhp = mh_head; mhp != NULL; mhp = mhp->mh_next) {
+                       if (mhp == hash) {
+                               mhpp->mh_next = mhp->mh_next;
+                               break;
+                       }
+                       mhpp = mhp;
+               }
+       }
+       mutex_exit(&mh_head_lock);
+
+       /*
+        * Clean out keys and values.
+        */
+       mod_hash_clear(hash);
+
+       rw_destroy(&hash->mh_contents);
+       kmem_free(hash->mh_name, strlen(hash->mh_name) + 1);
+       kmem_free(hash, MH_SIZE(hash->mh_nchains));
+}
+
+/*
+ * i_mod_hash()
+ *     Call the hashing algorithm for this hash table, with the given key.
+ */
+uint_t
+i_mod_hash(mod_hash_t *hash, mod_hash_key_t key)
+{
+       uint_t h;
+       /*
+        * Prevent div by 0 problems;
+        * Also a nice shortcut when using a hash as a list
+        */
+       if (hash->mh_nchains == 1)
+               return (0);
+
+       h = (hash->mh_hashalg)(hash->mh_hashalg_data, key);
+       return (h % (hash->mh_nchains - 1));
+}
+
+/*
+ * i_mod_hash_insert_nosync()
+ * mod_hash_insert()
+ * mod_hash_insert_reserve()
+ *     insert 'val' into the hash table, using 'key' as its key.  If 'key' is
+ *     already a key in the hash, an error will be returned, and the key-val
+ *     pair will not be inserted.  i_mod_hash_insert_nosync() supports a simple
+ *     handle abstraction, allowing hash entry allocation to be separated from
+ *     the hash insertion.  this abstraction allows simple use of the mod_hash
+ *     structure in situations where mod_hash_insert() with a KM_SLEEP
+ *     allocation policy would otherwise be unsafe.
+ */
+int
+i_mod_hash_insert_nosync(mod_hash_t *hash, mod_hash_key_t key,
+    mod_hash_val_t val, mod_hash_hndl_t handle)
+{
+       uint_t hashidx;
+       struct mod_hash_entry *entry;
+
+       ASSERT(hash);
+
+       /*
+        * If we've not been given reserved storage, allocate storage directly,
+        * using the hash's allocation policy.
+        */
+       if (handle == (mod_hash_hndl_t)0) {
+               entry = kmem_cache_alloc(mh_e_cache, hash->mh_sleep);
+               if (entry == NULL) {
+                       hash->mh_stat.mhs_nomem++;
+                       return (MH_ERR_NOMEM);
+               }
+       } else {
+               entry = (struct mod_hash_entry *)handle;
+       }
+
+       hashidx = i_mod_hash(hash, key);
+       entry->mhe_key = key;
+       entry->mhe_val = val;
+       entry->mhe_next = hash->mh_entries[hashidx];
+
+       hash->mh_entries[hashidx] = entry;
+       hash->mh_stat.mhs_nelems++;
+
+       return (0);
+}
+
+int
+mod_hash_insert(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t val)
+{
+       int res;
+       mod_hash_val_t v;
+
+       rw_enter(&hash->mh_contents, RW_WRITER);
+
+       /*
+        * Disallow duplicate keys in the hash
+        */
+       if (i_mod_hash_find_nosync(hash, key, &v) == 0) {
+               rw_exit(&hash->mh_contents);
+               hash->mh_stat.mhs_coll++;
+               return (MH_ERR_DUPLICATE);
+       }
+
+       res = i_mod_hash_insert_nosync(hash, key, val, (mod_hash_hndl_t)0);
+       rw_exit(&hash->mh_contents);
+
+       return (res);
+}
+
+int
+mod_hash_insert_reserve(mod_hash_t *hash, mod_hash_key_t key,
+    mod_hash_val_t val, mod_hash_hndl_t handle)
+{
+       int res;
+       mod_hash_val_t v;
+
+       rw_enter(&hash->mh_contents, RW_WRITER);
+
+       /*
+        * Disallow duplicate keys in the hash
+        */
+       if (i_mod_hash_find_nosync(hash, key, &v) == 0) {
+               rw_exit(&hash->mh_contents);
+               hash->mh_stat.mhs_coll++;
+               return (MH_ERR_DUPLICATE);
+       }
+       res = i_mod_hash_insert_nosync(hash, key, val, handle);
+       rw_exit(&hash->mh_contents);
+
+       return (res);
+}
+
+/*
+ * mod_hash_reserve()
+ * mod_hash_reserve_nosleep()
+ * mod_hash_cancel()
+ *   Make or cancel a mod_hash_entry_t reservation.  Reservations are used in
+ *   mod_hash_insert_reserve() above.
+ */
+int
+mod_hash_reserve(mod_hash_t *hash, mod_hash_hndl_t *handlep)
+{
+       *handlep = kmem_cache_alloc(mh_e_cache, hash->mh_sleep);
+       if (*handlep == NULL) {
+               hash->mh_stat.mhs_nomem++;
+               return (MH_ERR_NOMEM);
+       }
+
+       return (0);
+}
+
+int
+mod_hash_reserve_nosleep(mod_hash_t *hash, mod_hash_hndl_t *handlep)
+{
+       *handlep = kmem_cache_alloc(mh_e_cache, KM_NOSLEEP);
+       if (*handlep == NULL) {
+               hash->mh_stat.mhs_nomem++;
+               return (MH_ERR_NOMEM);
+       }
+
+       return (0);
+
+}
+
+/*ARGSUSED*/
+void
+mod_hash_cancel(mod_hash_t *hash, mod_hash_hndl_t *handlep)
+{
+       kmem_cache_free(mh_e_cache, *handlep);
+       *handlep = (mod_hash_hndl_t)0;
+}
+
+/*
+ * i_mod_hash_remove_nosync()
+ * mod_hash_remove()
+ *     Remove an element from the hash table.
+ */
+int
+i_mod_hash_remove_nosync(mod_hash_t *hash, mod_hash_key_t key,
+    mod_hash_val_t *val)
+{
+       int hashidx;
+       struct mod_hash_entry *e, *ep;
+
+       hashidx = i_mod_hash(hash, key);
+       ep = NULL; /* e's parent */
+
+       for (e = hash->mh_entries[hashidx]; e != NULL; e = e->mhe_next) {
+               if (MH_KEYCMP(hash, e->mhe_key, key) == 0)
+                       break;
+               ep = e;
+       }
+
+       if (e == NULL) {        /* not found */
+               return (MH_ERR_NOTFOUND);
+       }
+
+       if (ep == NULL)         /* special case 1st element in bucket */
+               hash->mh_entries[hashidx] = e->mhe_next;
+       else
+               ep->mhe_next = e->mhe_next;
+
+       /*
+        * Clean up resources used by the node's key.
+        */
+       MH_KEY_DESTROY(hash, e->mhe_key);
+
+       *val = e->mhe_val;
+       kmem_cache_free(mh_e_cache, e);
+       hash->mh_stat.mhs_nelems--;
+
+       return (0);
+}
+
+int
+mod_hash_remove(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val)
+{
+       int res;
+
+       rw_enter(&hash->mh_contents, RW_WRITER);
+       res = i_mod_hash_remove_nosync(hash, key, val);
+       rw_exit(&hash->mh_contents);
+
+       return (res);
+}
+
+/*
+ * mod_hash_replace()
+ *     atomically remove an existing key-value pair from a hash, and replace
+ *     the key and value with the ones supplied.  The removed key and value
+ *     (if any) are destroyed.
+ */
+int
+mod_hash_replace(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t val)
+{
+       int res;
+       mod_hash_val_t v;
+
+       rw_enter(&hash->mh_contents, RW_WRITER);
+
+       if (i_mod_hash_remove_nosync(hash, key, &v) == 0) {
+               /*
+                * mod_hash_remove() takes care of freeing up the key resources.
+                */
+               MH_VAL_DESTROY(hash, v);
+       }
+       res = i_mod_hash_insert_nosync(hash, key, val, (mod_hash_hndl_t)0);
+
+       rw_exit(&hash->mh_contents);
+
+       return (res);
+}
+
+/*
+ * mod_hash_destroy()
+ *     Remove an element from the hash table matching 'key', and destroy it.
+ */
+int
+mod_hash_destroy(mod_hash_t *hash, mod_hash_key_t key)
+{
+       mod_hash_val_t val;
+       int rv;
+
+       rw_enter(&hash->mh_contents, RW_WRITER);
+
+       if ((rv = i_mod_hash_remove_nosync(hash, key, &val)) == 0) {
+               /*
+                * mod_hash_remove() takes care of freeing up the key resources.
+                */
+               MH_VAL_DESTROY(hash, val);
+       }
+
+       rw_exit(&hash->mh_contents);
+       return (rv);
+}
+
+/*
+ * i_mod_hash_find_nosync()
+ * mod_hash_find()
+ *     Find a value in the hash table corresponding to the given key.
+ */
+int
+i_mod_hash_find_nosync(mod_hash_t *hash, mod_hash_key_t key,
+    mod_hash_val_t *val)
+{
+       uint_t hashidx;
+       struct mod_hash_entry *e;
+
+       hashidx = i_mod_hash(hash, key);
+
+       for (e = hash->mh_entries[hashidx]; e != NULL; e = e->mhe_next) {
+               if (MH_KEYCMP(hash, e->mhe_key, key) == 0) {
+                       *val = e->mhe_val;
+                       hash->mh_stat.mhs_hit++;
+                       return (0);
+               }
+       }
+       hash->mh_stat.mhs_miss++;
+       return (MH_ERR_NOTFOUND);
+}
+
+int
+mod_hash_find(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val)
+{
+       int res;
+
+       rw_enter(&hash->mh_contents, RW_READER);
+       res = i_mod_hash_find_nosync(hash, key, val);
+       rw_exit(&hash->mh_contents);
+
+       return (res);
+}
+
+int
+mod_hash_find_cb(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val,
+    void (*find_cb)(mod_hash_key_t, mod_hash_val_t))
+{
+       int res;
+
+       rw_enter(&hash->mh_contents, RW_READER);
+       res = i_mod_hash_find_nosync(hash, key, val);
+       if (res == 0) {
+               find_cb(key, *val);
+       }
+       rw_exit(&hash->mh_contents);
+
+       return (res);
+}
+
+int
+mod_hash_find_cb_rval(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val,
+    int (*find_cb)(mod_hash_key_t, mod_hash_val_t), int *cb_rval)
+{
+       int res;
+
+       rw_enter(&hash->mh_contents, RW_READER);
+       res = i_mod_hash_find_nosync(hash, key, val);
+       if (res == 0) {
+               *cb_rval = find_cb(key, *val);
+       }
+       rw_exit(&hash->mh_contents);
+
+       return (res);
+}
+
+void
+i_mod_hash_walk_nosync(mod_hash_t *hash,
+    uint_t (*callback)(mod_hash_key_t, mod_hash_val_t *, void *), void *arg)
+{
+       struct mod_hash_entry   *e;
+       uint_t                  hashidx;
+       int                     res = MH_WALK_CONTINUE;
+
+       for (hashidx = 0;
+           (hashidx < (hash->mh_nchains - 1)) && (res == MH_WALK_CONTINUE);
+           hashidx++) {
+               e = hash->mh_entries[hashidx];
+               while ((e != NULL) && (res == MH_WALK_CONTINUE)) {
+                       res = callback(e->mhe_key, e->mhe_val, arg);
+                       e = e->mhe_next;
+               }
+       }
+}
+
+/*
+ * mod_hash_walk()
+ *     Walks all the elements in the hashtable and invokes the callback
+ *     function with the key/value pair for each element.  The hashtable
+ *     is locked for readers so the callback function should not attempt
+ *     to do any updates to the hashable.  The callback function should
+ *     return MH_WALK_CONTINUE to continue walking the hashtable or
+ *     MH_WALK_TERMINATE to abort the walk of the hashtable.
+ */
+void
+mod_hash_walk(mod_hash_t *hash,
+    uint_t (*callback)(mod_hash_key_t, mod_hash_val_t *, void *), void *arg)
+{
+       rw_enter(&hash->mh_contents, RW_READER);
+       i_mod_hash_walk_nosync(hash, callback, arg);
+       rw_exit(&hash->mh_contents);
+}
+
+
+/*
+ * i_mod_hash_clear_nosync()
+ * mod_hash_clear()
+ *     Clears the given hash table by calling the destructor of every hash
+ *     element and freeing up all mod_hash_entry's.
+ */
+void
+i_mod_hash_clear_nosync(mod_hash_t *hash)
+{
+       int i;
+       struct mod_hash_entry *e, *old_e;
+
+       for (i = 0; i < hash->mh_nchains; i++) {
+               e = hash->mh_entries[i];
+               while (e != NULL) {
+                       MH_KEY_DESTROY(hash, e->mhe_key);
+                       MH_VAL_DESTROY(hash, e->mhe_val);
+                       old_e = e;
+                       e = e->mhe_next;
+                       kmem_cache_free(mh_e_cache, old_e);
+               }
+               hash->mh_entries[i] = NULL;
+       }
+       hash->mh_stat.mhs_nelems = 0;
+}
+
+void
+mod_hash_clear(mod_hash_t *hash)
+{
+       ASSERT(hash);
+       rw_enter(&hash->mh_contents, RW_WRITER);
+       i_mod_hash_clear_nosync(hash);
+       rw_exit(&hash->mh_contents);
+}
diff --git a/zfs/module/icp/spi/kcf_spi.c b/zfs/module/icp/spi/kcf_spi.c
new file mode 100644 (file)
index 0000000..8bd86b0
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file is part of the core Kernel Cryptographic Framework.
+ * It implements the SPI functions exported to cryptographic
+ * providers.
+ */
+
+
+#include <sys/zfs_context.h>
+#include <sys/crypto/common.h>
+#include <sys/crypto/impl.h>
+#include <sys/crypto/sched_impl.h>
+#include <sys/crypto/spi.h>
+
+/*
+ * minalloc and maxalloc values to be used for taskq_create().
+ */
+int crypto_taskq_threads = CRYPTO_TASKQ_THREADS;
+int crypto_taskq_minalloc = CYRPTO_TASKQ_MIN;
+int crypto_taskq_maxalloc = CRYPTO_TASKQ_MAX;
+
+static void remove_provider(kcf_provider_desc_t *);
+static void process_logical_providers(crypto_provider_info_t *,
+    kcf_provider_desc_t *);
+static int init_prov_mechs(crypto_provider_info_t *, kcf_provider_desc_t *);
+static int kcf_prov_kstat_update(kstat_t *, int);
+static void delete_kstat(kcf_provider_desc_t *);
+
+static kcf_prov_stats_t kcf_stats_ks_data_template = {
+       { "kcf_ops_total",              KSTAT_DATA_UINT64 },
+       { "kcf_ops_passed",             KSTAT_DATA_UINT64 },
+       { "kcf_ops_failed",             KSTAT_DATA_UINT64 },
+       { "kcf_ops_returned_busy",      KSTAT_DATA_UINT64 }
+};
+
+#define        KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
+       *((dst)->ops) = *((src)->ops);
+
+/*
+ * Copy an ops vector from src to dst. Used during provider registration
+ * to copy the ops vector from the provider info structure to the
+ * provider descriptor maintained by KCF.
+ * Copying the ops vector specified by the provider is needed since the
+ * framework does not require the provider info structure to be
+ * persistent.
+ */
+static void
+copy_ops_vector_v1(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
+{
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_control_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_digest_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_cipher_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mac_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_sign_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_verify_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_cipher_mac_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_random_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_session_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_object_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_key_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_provider_ops);
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_ctx_ops);
+}
+
+static void
+copy_ops_vector_v2(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
+{
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mech_ops);
+}
+
+static void
+copy_ops_vector_v3(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
+{
+       KCF_SPI_COPY_OPS(src_ops, dst_ops, co_nostore_key_ops);
+}
+
+/*
+ * This routine is used to add cryptographic providers to the KEF framework.
+ * Providers pass a crypto_provider_info structure to crypto_register_provider()
+ * and get back a handle.  The crypto_provider_info structure contains a
+ * list of mechanisms supported by the provider and an ops vector containing
+ * provider entry points.  Hardware providers call this routine in their attach
+ * routines.  Software providers call this routine in their _init() routine.
+ */
+int
+crypto_register_provider(crypto_provider_info_t *info,
+    crypto_kcf_provider_handle_t *handle)
+{
+       char ks_name[KSTAT_STRLEN];
+
+       kcf_provider_desc_t *prov_desc = NULL;
+       int ret = CRYPTO_ARGUMENTS_BAD;
+
+       if (info->pi_interface_version > CRYPTO_SPI_VERSION_3)
+               return (CRYPTO_VERSION_MISMATCH);
+
+       /*
+        * Check provider type, must be software, hardware, or logical.
+        */
+       if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
+           info->pi_provider_type != CRYPTO_SW_PROVIDER &&
+           info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       /*
+        * Allocate and initialize a new provider descriptor. We also
+        * hold it and release it when done.
+        */
+       prov_desc = kcf_alloc_provider_desc(info);
+       KCF_PROV_REFHOLD(prov_desc);
+
+       prov_desc->pd_prov_type = info->pi_provider_type;
+
+       /* provider-private handle, opaque to KCF */
+       prov_desc->pd_prov_handle = info->pi_provider_handle;
+
+       /* copy provider description string */
+       if (info->pi_provider_description != NULL) {
+               /*
+                * pi_provider_descriptor is a string that can contain
+                * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
+                * INCLUDING the terminating null character. A bcopy()
+                * is necessary here as pd_description should not have
+                * a null character. See comments in kcf_alloc_provider_desc()
+                * for details on pd_description field.
+                */
+               bcopy(info->pi_provider_description, prov_desc->pd_description,
+                   MIN(strlen(info->pi_provider_description),
+                   (size_t)CRYPTO_PROVIDER_DESCR_MAX_LEN));
+       }
+
+       if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
+               if (info->pi_ops_vector == NULL) {
+                       goto bail;
+               }
+               copy_ops_vector_v1(info->pi_ops_vector,
+                   prov_desc->pd_ops_vector);
+               if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2) {
+                       copy_ops_vector_v2(info->pi_ops_vector,
+                           prov_desc->pd_ops_vector);
+                       prov_desc->pd_flags = info->pi_flags;
+               }
+               if (info->pi_interface_version == CRYPTO_SPI_VERSION_3) {
+                       copy_ops_vector_v3(info->pi_ops_vector,
+                           prov_desc->pd_ops_vector);
+               }
+       }
+
+       /* object_ops and nostore_key_ops are mutually exclusive */
+       if (prov_desc->pd_ops_vector->co_object_ops &&
+           prov_desc->pd_ops_vector->co_nostore_key_ops) {
+               goto bail;
+       }
+
+       /* process the mechanisms supported by the provider */
+       if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
+               goto bail;
+
+       /*
+        * Add provider to providers tables, also sets the descriptor
+        * pd_prov_id field.
+        */
+       if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
+               undo_register_provider(prov_desc, B_FALSE);
+               goto bail;
+       }
+
+       /*
+        * We create a taskq only for a hardware provider. The global
+        * software queue is used for software providers. We handle ordering
+        * of multi-part requests in the taskq routine. So, it is safe to
+        * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
+        * to keep some entries cached to improve performance.
+        */
+       if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
+               prov_desc->pd_sched_info.ks_taskq = taskq_create("kcf_taskq",
+                   crypto_taskq_threads, minclsyspri,
+                   crypto_taskq_minalloc, crypto_taskq_maxalloc,
+                   TASKQ_PREPOPULATE);
+       else
+               prov_desc->pd_sched_info.ks_taskq = NULL;
+
+       /* no kernel session to logical providers */
+       if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
+               /*
+                * Open a session for session-oriented providers. This session
+                * is used for all kernel consumers. This is fine as a provider
+                * is required to support multiple thread access to a session.
+                * We can do this only after the taskq has been created as we
+                * do a kcf_submit_request() to open the session.
+                */
+               if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
+                       kcf_req_params_t params;
+
+                       KCF_WRAP_SESSION_OPS_PARAMS(&params,
+                           KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
+                           CRYPTO_USER, NULL, 0, prov_desc);
+                       ret = kcf_submit_request(prov_desc, NULL, NULL, &params,
+                           B_FALSE);
+
+                       if (ret != CRYPTO_SUCCESS) {
+                               undo_register_provider(prov_desc, B_TRUE);
+                               ret = CRYPTO_FAILED;
+                               goto bail;
+                       }
+               }
+       }
+
+       if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
+               /*
+                * Create the kstat for this provider. There is a kstat
+                * installed for each successfully registered provider.
+                * This kstat is deleted, when the provider unregisters.
+                */
+               if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
+                       (void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s",
+                           "NONAME", "provider_stats");
+               } else {
+                       (void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s",
+                           "NONAME", 0,
+                           prov_desc->pd_prov_id, "provider_stats");
+               }
+
+               prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
+                   KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
+                   sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
+
+               if (prov_desc->pd_kstat != NULL) {
+                       bcopy(&kcf_stats_ks_data_template,
+                           &prov_desc->pd_ks_data,
+                           sizeof (kcf_stats_ks_data_template));
+                       prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
+                       KCF_PROV_REFHOLD(prov_desc);
+                       KCF_PROV_IREFHOLD(prov_desc);
+                       prov_desc->pd_kstat->ks_private = prov_desc;
+                       prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
+                       kstat_install(prov_desc->pd_kstat);
+               }
+       }
+
+       if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
+               process_logical_providers(info, prov_desc);
+
+       mutex_enter(&prov_desc->pd_lock);
+       prov_desc->pd_state = KCF_PROV_READY;
+       mutex_exit(&prov_desc->pd_lock);
+       kcf_do_notify(prov_desc, B_TRUE);
+
+       *handle = prov_desc->pd_kcf_prov_handle;
+       ret = CRYPTO_SUCCESS;
+
+bail:
+       KCF_PROV_REFRELE(prov_desc);
+       return (ret);
+}
+
+/*
+ * This routine is used to notify the framework when a provider is being
+ * removed.  Hardware providers call this routine in their detach routines.
+ * Software providers call this routine in their _fini() routine.
+ */
+int
+crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
+{
+       uint_t mech_idx;
+       kcf_provider_desc_t *desc;
+       kcf_prov_state_t saved_state;
+
+       /* lookup provider descriptor */
+       if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
+               return (CRYPTO_UNKNOWN_PROVIDER);
+
+       mutex_enter(&desc->pd_lock);
+       /*
+        * Check if any other thread is disabling or removing
+        * this provider. We return if this is the case.
+        */
+       if (desc->pd_state >= KCF_PROV_DISABLED) {
+               mutex_exit(&desc->pd_lock);
+               /* Release reference held by kcf_prov_tab_lookup(). */
+               KCF_PROV_REFRELE(desc);
+               return (CRYPTO_BUSY);
+       }
+
+       saved_state = desc->pd_state;
+       desc->pd_state = KCF_PROV_REMOVED;
+
+       if (saved_state == KCF_PROV_BUSY) {
+               /*
+                * The per-provider taskq threads may be waiting. We
+                * signal them so that they can start failing requests.
+                */
+               cv_broadcast(&desc->pd_resume_cv);
+       }
+
+       if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
+               /*
+                * Check if this provider is currently being used.
+                * pd_irefcnt is the number of holds from the internal
+                * structures. We add one to account for the above lookup.
+                */
+               if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
+                       desc->pd_state = saved_state;
+                       mutex_exit(&desc->pd_lock);
+                       /* Release reference held by kcf_prov_tab_lookup(). */
+                       KCF_PROV_REFRELE(desc);
+                       /*
+                        * The administrator presumably will stop the clients
+                        * thus removing the holds, when they get the busy
+                        * return value.  Any retry will succeed then.
+                        */
+                       return (CRYPTO_BUSY);
+               }
+       }
+       mutex_exit(&desc->pd_lock);
+
+       if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
+               remove_provider(desc);
+       }
+
+       if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
+               /* remove the provider from the mechanisms tables */
+               for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
+                   mech_idx++) {
+                       kcf_remove_mech_provider(
+                           desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
+               }
+       }
+
+       /* remove provider from providers table */
+       if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
+           CRYPTO_SUCCESS) {
+               /* Release reference held by kcf_prov_tab_lookup(). */
+               KCF_PROV_REFRELE(desc);
+               return (CRYPTO_UNKNOWN_PROVIDER);
+       }
+
+       delete_kstat(desc);
+
+       if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
+               /* Release reference held by kcf_prov_tab_lookup(). */
+               KCF_PROV_REFRELE(desc);
+
+               /*
+                * Wait till the existing requests complete.
+                */
+               mutex_enter(&desc->pd_lock);
+               while (desc->pd_state != KCF_PROV_FREED)
+                       cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
+               mutex_exit(&desc->pd_lock);
+       } else {
+               /*
+                * Wait until requests that have been sent to the provider
+                * complete.
+                */
+               mutex_enter(&desc->pd_lock);
+               while (desc->pd_irefcnt > 0)
+                       cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
+               mutex_exit(&desc->pd_lock);
+       }
+
+       kcf_do_notify(desc, B_FALSE);
+
+       if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
+               /*
+                * This is the only place where kcf_free_provider_desc()
+                * is called directly. KCF_PROV_REFRELE() should free the
+                * structure in all other places.
+                */
+               ASSERT(desc->pd_state == KCF_PROV_FREED &&
+                   desc->pd_refcnt == 0);
+               kcf_free_provider_desc(desc);
+       } else {
+               KCF_PROV_REFRELE(desc);
+       }
+
+       return (CRYPTO_SUCCESS);
+}
+
+/*
+ * This routine is used to notify the framework that the state of
+ * a cryptographic provider has changed. Valid state codes are:
+ *
+ * CRYPTO_PROVIDER_READY
+ *     The provider indicates that it can process more requests. A provider
+ *     will notify with this event if it previously has notified us with a
+ *     CRYPTO_PROVIDER_BUSY.
+ *
+ * CRYPTO_PROVIDER_BUSY
+ *     The provider can not take more requests.
+ *
+ * CRYPTO_PROVIDER_FAILED
+ *     The provider encountered an internal error. The framework will not
+ *     be sending any more requests to the provider. The provider may notify
+ *     with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
+ *
+ * This routine can be called from user or interrupt context.
+ */
+void
+crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
+{
+       kcf_provider_desc_t *pd;
+
+       /* lookup the provider from the given handle */
+       if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
+               return;
+
+       mutex_enter(&pd->pd_lock);
+
+       if (pd->pd_state <= KCF_PROV_VERIFICATION_FAILED)
+               goto out;
+
+       if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               cmn_err(CE_WARN, "crypto_provider_notification: "
+                   "logical provider (%x) ignored\n", handle);
+               goto out;
+       }
+       switch (state) {
+       case CRYPTO_PROVIDER_READY:
+               switch (pd->pd_state) {
+               case KCF_PROV_BUSY:
+                       pd->pd_state = KCF_PROV_READY;
+                       /*
+                        * Signal the per-provider taskq threads that they
+                        * can start submitting requests.
+                        */
+                       cv_broadcast(&pd->pd_resume_cv);
+                       break;
+
+               case KCF_PROV_FAILED:
+                       /*
+                        * The provider recovered from the error. Let us
+                        * use it now.
+                        */
+                       pd->pd_state = KCF_PROV_READY;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case CRYPTO_PROVIDER_BUSY:
+               switch (pd->pd_state) {
+               case KCF_PROV_READY:
+                       pd->pd_state = KCF_PROV_BUSY;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case CRYPTO_PROVIDER_FAILED:
+               /*
+                * We note the failure and return. The per-provider taskq
+                * threads check this flag and start failing the
+                * requests, if it is set. See process_req_hwp() for details.
+                */
+               switch (pd->pd_state) {
+               case KCF_PROV_READY:
+                       pd->pd_state = KCF_PROV_FAILED;
+                       break;
+
+               case KCF_PROV_BUSY:
+                       pd->pd_state = KCF_PROV_FAILED;
+                       /*
+                        * The per-provider taskq threads may be waiting. We
+                        * signal them so that they can start failing requests.
+                        */
+                       cv_broadcast(&pd->pd_resume_cv);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+out:
+       mutex_exit(&pd->pd_lock);
+       KCF_PROV_REFRELE(pd);
+}
+
+/*
+ * This routine is used to notify the framework the result of
+ * an asynchronous request handled by a provider. Valid error
+ * codes are the same as the CRYPTO_* errors defined in common.h.
+ *
+ * This routine can be called from user or interrupt context.
+ */
+void
+crypto_op_notification(crypto_req_handle_t handle, int error)
+{
+       kcf_call_type_t ctype;
+
+       if (handle == NULL)
+               return;
+
+       if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
+               kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
+
+               if (error != CRYPTO_SUCCESS)
+                       sreq->sn_provider->pd_sched_info.ks_nfails++;
+               KCF_PROV_IREFRELE(sreq->sn_provider);
+               kcf_sop_done(sreq, error);
+       } else {
+               kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
+
+               ASSERT(ctype == CRYPTO_ASYNCH);
+               if (error != CRYPTO_SUCCESS)
+                       areq->an_provider->pd_sched_info.ks_nfails++;
+               KCF_PROV_IREFRELE(areq->an_provider);
+               kcf_aop_done(areq, error);
+       }
+}
+
+/*
+ * This routine is used by software providers to determine
+ * whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
+ * Note that hardware providers can always use KM_SLEEP. So,
+ * they do not need to call this routine.
+ *
+ * This routine can be called from user or interrupt context.
+ */
+int
+crypto_kmflag(crypto_req_handle_t handle)
+{
+       return (REQHNDL2_KMFLAG(handle));
+}
+
+/*
+ * Process the mechanism info structures specified by the provider
+ * during registration. A NULL crypto_provider_info_t indicates
+ * an already initialized provider descriptor.
+ *
+ * Mechanisms are not added to the kernel's mechanism table if the
+ * provider is a logical provider.
+ *
+ * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
+ * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
+ * if the table of mechanisms is full.
+ */
+static int
+init_prov_mechs(crypto_provider_info_t *info, kcf_provider_desc_t *desc)
+{
+       uint_t mech_idx;
+       uint_t cleanup_idx;
+       int err = CRYPTO_SUCCESS;
+       kcf_prov_mech_desc_t *pmd;
+       int desc_use_count = 0;
+       int mcount = desc->pd_mech_list_count;
+
+       if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
+               if (info != NULL) {
+                       ASSERT(info->pi_mechanisms != NULL);
+                       bcopy(info->pi_mechanisms, desc->pd_mechanisms,
+                           sizeof (crypto_mech_info_t) * mcount);
+               }
+               return (CRYPTO_SUCCESS);
+       }
+
+       /*
+        * Copy the mechanism list from the provider info to the provider
+        * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
+        * element if the provider has random_ops since we keep an internal
+        * mechanism, SUN_RANDOM, in this case.
+        */
+       if (info != NULL) {
+               if (info->pi_ops_vector->co_random_ops != NULL) {
+                       crypto_mech_info_t *rand_mi;
+
+                       /*
+                        * Need the following check as it is possible to have
+                        * a provider that implements just random_ops and has
+                        * pi_mechanisms == NULL.
+                        */
+                       if (info->pi_mechanisms != NULL) {
+                               bcopy(info->pi_mechanisms, desc->pd_mechanisms,
+                                   sizeof (crypto_mech_info_t) * (mcount - 1));
+                       }
+                       rand_mi = &desc->pd_mechanisms[mcount - 1];
+
+                       bzero(rand_mi, sizeof (crypto_mech_info_t));
+                       (void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
+                           CRYPTO_MAX_MECH_NAME);
+                       rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
+               } else {
+                       ASSERT(info->pi_mechanisms != NULL);
+                       bcopy(info->pi_mechanisms, desc->pd_mechanisms,
+                           sizeof (crypto_mech_info_t) * mcount);
+               }
+       }
+
+       /*
+        * For each mechanism support by the provider, add the provider
+        * to the corresponding KCF mechanism mech_entry chain.
+        */
+       for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
+               crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
+
+               if ((mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) &&
+                   (mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)) {
+                       err = CRYPTO_ARGUMENTS_BAD;
+                       break;
+               }
+
+               if (desc->pd_flags & CRYPTO_HASH_NO_UPDATE &&
+                   mi->cm_func_group_mask & CRYPTO_FG_DIGEST) {
+                       /*
+                        * We ask the provider to specify the limit
+                        * per hash mechanism. But, in practice, a
+                        * hardware limitation means all hash mechanisms
+                        * will have the same maximum size allowed for
+                        * input data. So, we make it a per provider
+                        * limit to keep it simple.
+                        */
+                       if (mi->cm_max_input_length == 0) {
+                               err = CRYPTO_ARGUMENTS_BAD;
+                               break;
+                       } else {
+                               desc->pd_hash_limit = mi->cm_max_input_length;
+                       }
+               }
+
+               if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
+                   KCF_SUCCESS)
+                       break;
+
+               if (pmd == NULL)
+                       continue;
+
+               /* The provider will be used for this mechanism */
+               desc_use_count++;
+       }
+
+       /*
+        * Don't allow multiple software providers with disabled mechanisms
+        * to register. Subsequent enabling of mechanisms will result in
+        * an unsupported configuration, i.e. multiple software providers
+        * per mechanism.
+        */
+       if (desc_use_count == 0 && desc->pd_prov_type == CRYPTO_SW_PROVIDER)
+               return (CRYPTO_ARGUMENTS_BAD);
+
+       if (err == KCF_SUCCESS)
+               return (CRYPTO_SUCCESS);
+
+       /*
+        * An error occurred while adding the mechanism, cleanup
+        * and bail.
+        */
+       for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
+               kcf_remove_mech_provider(
+                   desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
+       }
+
+       if (err == KCF_MECH_TAB_FULL)
+               return (CRYPTO_HOST_MEMORY);
+
+       return (CRYPTO_ARGUMENTS_BAD);
+}
+
+/*
+ * Update routine for kstat. Only privileged users are allowed to
+ * access this information, since this information is sensitive.
+ * There are some cryptographic attacks (e.g. traffic analysis)
+ * which can use this information.
+ */
+static int
+kcf_prov_kstat_update(kstat_t *ksp, int rw)
+{
+       kcf_prov_stats_t *ks_data;
+       kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
+
+       if (rw == KSTAT_WRITE)
+               return (EACCES);
+
+       ks_data = ksp->ks_data;
+
+       ks_data->ps_ops_total.value.ui64 =
+               pd->pd_sched_info.ks_ndispatches;
+       ks_data->ps_ops_failed.value.ui64 =
+               pd->pd_sched_info.ks_nfails;
+       ks_data->ps_ops_busy_rval.value.ui64 =
+               pd->pd_sched_info.ks_nbusy_rval;
+       ks_data->ps_ops_passed.value.ui64 =
+               pd->pd_sched_info.ks_ndispatches -
+               pd->pd_sched_info.ks_nfails -
+               pd->pd_sched_info.ks_nbusy_rval;
+
+       return (0);
+}
+
+
+/*
+ * Utility routine called from failure paths in crypto_register_provider()
+ * and from crypto_load_soft_disabled().
+ */
+void
+undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
+{
+       uint_t mech_idx;
+
+       /* remove the provider from the mechanisms tables */
+       for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
+           mech_idx++) {
+               kcf_remove_mech_provider(
+                   desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
+       }
+
+       /* remove provider from providers table */
+       if (remove_prov)
+               (void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
+}
+
+/*
+ * Utility routine called from crypto_load_soft_disabled(). Callers
+ * should have done a prior undo_register_provider().
+ */
+void
+redo_register_provider(kcf_provider_desc_t *pd)
+{
+       /* process the mechanisms supported by the provider */
+       (void) init_prov_mechs(NULL, pd);
+
+       /*
+        * Hold provider in providers table. We should not call
+        * kcf_prov_tab_add_provider() here as the provider descriptor
+        * is still valid which means it has an entry in the provider
+        * table.
+        */
+       KCF_PROV_REFHOLD(pd);
+       KCF_PROV_IREFHOLD(pd);
+}
+
+/*
+ * Add provider (p1) to another provider's array of providers (p2).
+ * Hardware and logical providers use this array to cross-reference
+ * each other.
+ */
+static void
+add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
+{
+       kcf_provider_list_t *new;
+
+       new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
+       mutex_enter(&p2->pd_lock);
+       new->pl_next = p2->pd_provider_list;
+       p2->pd_provider_list = new;
+       KCF_PROV_IREFHOLD(p1);
+       new->pl_provider = p1;
+       mutex_exit(&p2->pd_lock);
+}
+
+/*
+ * Remove provider (p1) from another provider's array of providers (p2).
+ * Hardware and logical providers use this array to cross-reference
+ * each other.
+ */
+static void
+remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
+{
+
+       kcf_provider_list_t *pl = NULL, **prev;
+
+       mutex_enter(&p2->pd_lock);
+       for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
+           pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
+               if (pl->pl_provider == p1) {
+                       break;
+               }
+       }
+
+       if (p1 == NULL) {
+               mutex_exit(&p2->pd_lock);
+               return;
+       }
+
+       /* detach and free kcf_provider_list structure */
+       KCF_PROV_IREFRELE(p1);
+       *prev = pl->pl_next;
+       kmem_free(pl, sizeof (*pl));
+       mutex_exit(&p2->pd_lock);
+}
+
+/*
+ * Convert an array of logical provider handles (crypto_provider_id)
+ * stored in a crypto_provider_info structure into an array of provider
+ * descriptors (kcf_provider_desc_t) attached to a logical provider.
+ */
+static void
+process_logical_providers(crypto_provider_info_t *info, kcf_provider_desc_t *hp)
+{
+       kcf_provider_desc_t *lp;
+       crypto_provider_id_t handle;
+       int count = info->pi_logical_provider_count;
+       int i;
+
+       /* add hardware provider to each logical provider */
+       for (i = 0; i < count; i++) {
+               handle = info->pi_logical_providers[i];
+               lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
+               if (lp == NULL) {
+                       continue;
+               }
+               add_provider_to_array(hp, lp);
+               hp->pd_flags |= KCF_LPROV_MEMBER;
+
+               /*
+                * A hardware provider has to have the provider descriptor of
+                * every logical provider it belongs to, so it can be removed
+                * from the logical provider if the hardware provider
+                * unregisters from the framework.
+                */
+               add_provider_to_array(lp, hp);
+               KCF_PROV_REFRELE(lp);
+       }
+}
+
+/*
+ * This routine removes a provider from all of the logical or
+ * hardware providers it belongs to, and frees the provider's
+ * array of pointers to providers.
+ */
+static void
+remove_provider(kcf_provider_desc_t *pp)
+{
+       kcf_provider_desc_t *p;
+       kcf_provider_list_t *e, *next;
+
+       mutex_enter(&pp->pd_lock);
+       for (e = pp->pd_provider_list; e != NULL; e = next) {
+               p = e->pl_provider;
+               remove_provider_from_array(pp, p);
+               if (p->pd_prov_type == CRYPTO_HW_PROVIDER &&
+                   p->pd_provider_list == NULL)
+                       p->pd_flags &= ~KCF_LPROV_MEMBER;
+               KCF_PROV_IREFRELE(p);
+               next = e->pl_next;
+               kmem_free(e, sizeof (*e));
+       }
+       pp->pd_provider_list = NULL;
+       mutex_exit(&pp->pd_lock);
+}
+
+/*
+ * Dispatch events as needed for a provider. is_added flag tells
+ * whether the provider is registering or unregistering.
+ */
+void
+kcf_do_notify(kcf_provider_desc_t *prov_desc, boolean_t is_added)
+{
+       int i;
+       crypto_notify_event_change_t ec;
+
+       ASSERT(prov_desc->pd_state > KCF_PROV_VERIFICATION_FAILED);
+
+       /*
+        * Inform interested clients of the mechanisms becoming
+        * available/unavailable. We skip this for logical providers
+        * as they do not affect mechanisms.
+        */
+       if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
+               ec.ec_provider_type = prov_desc->pd_prov_type;
+               ec.ec_change = is_added ? CRYPTO_MECH_ADDED :
+                   CRYPTO_MECH_REMOVED;
+               for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
+                       (void) strlcpy(ec.ec_mech_name,
+                           prov_desc->pd_mechanisms[i].cm_mech_name,
+                           CRYPTO_MAX_MECH_NAME);
+                       kcf_walk_ntfylist(CRYPTO_EVENT_MECHS_CHANGED, &ec);
+               }
+
+       }
+
+       /*
+        * Inform interested clients about the new or departing provider.
+        * In case of a logical provider, we need to notify the event only
+        * for the logical provider and not for the underlying
+        * providers which are known by the KCF_LPROV_MEMBER bit.
+        */
+       if (prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER ||
+           (prov_desc->pd_flags & KCF_LPROV_MEMBER) == 0) {
+               kcf_walk_ntfylist(is_added ? CRYPTO_EVENT_PROVIDER_REGISTERED :
+                   CRYPTO_EVENT_PROVIDER_UNREGISTERED, prov_desc);
+       }
+}
+
+static void
+delete_kstat(kcf_provider_desc_t *desc)
+{
+       /* destroy the kstat created for this provider */
+       if (desc->pd_kstat != NULL) {
+               kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
+
+               /* release reference held by desc->pd_kstat->ks_private */
+               ASSERT(desc == kspd);
+               kstat_delete(kspd->pd_kstat);
+               desc->pd_kstat = NULL;
+               KCF_PROV_REFRELE(kspd);
+               KCF_PROV_IREFRELE(kspd);
+       }
+}
index 16a0fc3eb571c68b51ddf98a7f474df0a1b9ff14..14b196d969fa592556344378c1975795575ba5a0 100644 (file)
@@ -1260,6 +1260,8 @@ nvpair_type_is_array(nvpair_t *nvp)
 static int
 nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
 {
+       int value_sz;
+
        if (nvp == NULL || nvpair_type(nvp) != type)
                return (EINVAL);
 
@@ -1289,8 +1291,9 @@ nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
 #endif
                if (data == NULL)
                        return (EINVAL);
-               bcopy(NVP_VALUE(nvp), data,
-                   (size_t)i_get_value_size(type, NULL, 1));
+               if ((value_sz = i_get_value_size(type, NULL, 1)) < 0)
+                       return (EINVAL);
+               bcopy(NVP_VALUE(nvp), data, (size_t)value_sz);
                if (nelem != NULL)
                        *nelem = 1;
                break;
@@ -2029,7 +2032,7 @@ typedef struct {
 /*
  * nvs operations are:
  *   - nvs_nvlist
- *     encoding / decoding of a nvlist header (nvlist_t)
+ *     encoding / decoding of an nvlist header (nvlist_t)
  *     calculates the size used for header and end detection
  *
  *   - nvs_nvpair
index 26cc39f3bcd225a000c5265b97b1ca7f5c92485f..992f6b6b72f538ddb9a80f41d99a18fb394f1c6e 100644 (file)
@@ -1060,7 +1060,7 @@ do_composition(size_t uv, uchar_t *s, uchar_t *comb_class, uchar_t *start,
        uchar_t *disp, size_t last, uchar_t **os, uchar_t *oslast)
 {
        uchar_t t[U8_STREAM_SAFE_TEXT_MAX + 1];
-       uchar_t tc[U8_MB_CUR_MAX];
+       uchar_t tc[U8_MB_CUR_MAX] = { '\0' };
        uint8_t saved_marks[U8_MAX_CHARS_A_SEQ];
        size_t saved_marks_count;
        uchar_t *p;
@@ -1396,7 +1396,7 @@ collect_a_seq(size_t uv, uchar_t *u8s, uchar_t **source, uchar_t *slast,
        uchar_t comb_class[U8_MAX_CHARS_A_SEQ];
        uchar_t disp[U8_MAX_CHARS_A_SEQ];
        uchar_t start[U8_MAX_CHARS_A_SEQ];
-       uchar_t u8t[U8_MB_CUR_MAX];
+       uchar_t u8t[U8_MB_CUR_MAX] = { '\0' };
        uchar_t uts[U8_STREAM_SAFE_TEXT_MAX + 1];
        uchar_t tc;
        size_t last;
index 67e474ee089d29320e7191304f3c5d11cfd80599..bcef477093be885184fb5e0ecc5b4dee8d056d7a 100644 (file)
@@ -15,3 +15,8 @@ $(MODULE)-objs += zfs_comutil.o
 $(MODULE)-objs += zfs_fletcher.o
 $(MODULE)-objs += zfs_uio.o
 $(MODULE)-objs += zpool_prop.o
+
+$(MODULE)-$(CONFIG_X86) += zfs_fletcher_intel.o
+$(MODULE)-$(CONFIG_X86) += zfs_fletcher_sse.o
+$(MODULE)-$(CONFIG_X86) += zfs_fletcher_avx512.o
+$(MODULE)-$(CONFIG_ARM64) += zfs_fletcher_aarch64_neon.o
index 6d0314fa78d08e14663c5e747a1075bcb9fdcd45..704ef84c77c8aa58e73e9acfde18ea7f5131fe4c 100644 (file)
@@ -40,6 +40,7 @@
 #include <sys/int_limits.h>
 #include <sys/nvpair.h>
 #include "zfs_comutil.h"
+#include <sys/zfs_ratelimit.h>
 
 /*
  * Are there allocatable vdevs?
@@ -206,10 +207,73 @@ const char *zfs_history_event_names[ZFS_NUM_LEGACY_HISTORY_EVENTS] = {
        "pool split",
 };
 
+/*
+ * Initialize rate limit struct
+ *
+ * rl:         zfs_ratelimit_t struct
+ * burst:      Number to allow in an interval before rate limiting
+ * interval:   Interval time in seconds
+ */
+void
+zfs_ratelimit_init(zfs_ratelimit_t *rl, unsigned int burst,
+    unsigned int interval)
+{
+       rl->count = 0;
+       rl->start = 0;
+       rl->interval = interval;
+       rl->burst = burst;
+       mutex_init(&rl->lock, NULL, MUTEX_DEFAULT, NULL);
+}
+
+/*
+ * Re-implementation of the kernel's __ratelimit() function
+ *
+ * We had to write our own rate limiter because the kernel's __ratelimit()
+ * function annoyingly prints out how many times it rate limited to the kernel
+ * logs (and there's no way to turn it off):
+ *
+ *     __ratelimit: 59 callbacks suppressed
+ *
+ * If the kernel ever allows us to disable these prints, we should go back to
+ * using __ratelimit() instead.
+ *
+ * Return values are the same as __ratelimit():
+ *
+ * 0: If we're rate limiting
+ * 1: If we're not rate limiting.
+ */
+int
+zfs_ratelimit(zfs_ratelimit_t *rl)
+{
+       hrtime_t now;
+       hrtime_t elapsed;
+       int rc = 1;
+
+       mutex_enter(&rl->lock);
+
+       now = gethrtime();
+       elapsed = now - rl->start;
+
+       rl->count++;
+       if (NSEC2SEC(elapsed) >= rl->interval) {
+               rl->start = now;
+               rl->count = 0;
+       } else {
+               if (rl->count >= rl->burst) {
+                       rc = 0; /* We're ratelimiting */
+               }
+       }
+       mutex_exit(&rl->lock);
+
+       return (rc);
+}
+
 #if defined(_KERNEL) && defined(HAVE_SPL)
 EXPORT_SYMBOL(zfs_allocatable_devs);
 EXPORT_SYMBOL(zpool_get_rewind_policy);
 EXPORT_SYMBOL(zfs_zpl_version_map);
 EXPORT_SYMBOL(zfs_spa_version_map);
 EXPORT_SYMBOL(zfs_history_event_names);
+EXPORT_SYMBOL(zfs_ratelimit_init);
+EXPORT_SYMBOL(zfs_ratelimit);
 #endif
index f6e41da9d7eac1e3cf100e059c1fbd25f6d9893c..647a24e5ff1f1c6070e5c1a96b2aad6bc0b90f87 100644 (file)
@@ -62,6 +62,10 @@ zfs_deleg_perm_tab_t zfs_deleg_perm_tab[] = {
        {ZFS_DELEG_PERM_GROUPQUOTA},
        {ZFS_DELEG_PERM_USERUSED},
        {ZFS_DELEG_PERM_GROUPUSED},
+       {ZFS_DELEG_PERM_USEROBJQUOTA},
+       {ZFS_DELEG_PERM_GROUPOBJQUOTA},
+       {ZFS_DELEG_PERM_USEROBJUSED},
+       {ZFS_DELEG_PERM_GROUPOBJUSED},
        {ZFS_DELEG_PERM_HOLD},
        {ZFS_DELEG_PERM_RELEASE},
        {NULL}
index edd0cbe6c6117c0e15e1ade541b8fccfafa9d10e..508ac4a1dca616b74b74d76a2445a95c348117f4 100644 (file)
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+/*
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
  */
 
 /*
 #include <sys/types.h>
 #include <sys/sysmacros.h>
 #include <sys/byteorder.h>
-#include <sys/zio.h>
 #include <sys/spa.h>
+#include <sys/zio_checksum.h>
+#include <sys/zfs_context.h>
+#include <zfs_fletcher.h>
+
+
+static void fletcher_4_scalar_init(fletcher_4_ctx_t *ctx);
+static void fletcher_4_scalar_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp);
+static void fletcher_4_scalar_native(fletcher_4_ctx_t *ctx,
+    const void *buf, uint64_t size);
+static void fletcher_4_scalar_byteswap(fletcher_4_ctx_t *ctx,
+    const void *buf, uint64_t size);
+static boolean_t fletcher_4_scalar_valid(void);
+
+static const fletcher_4_ops_t fletcher_4_scalar_ops = {
+       .init_native = fletcher_4_scalar_init,
+       .fini_native = fletcher_4_scalar_fini,
+       .compute_native = fletcher_4_scalar_native,
+       .init_byteswap = fletcher_4_scalar_init,
+       .fini_byteswap = fletcher_4_scalar_fini,
+       .compute_byteswap = fletcher_4_scalar_byteswap,
+       .valid = fletcher_4_scalar_valid,
+       .name = "scalar"
+};
+
+static fletcher_4_ops_t fletcher_4_fastest_impl = {
+       .name = "fastest",
+       .valid = fletcher_4_scalar_valid
+};
+
+static const fletcher_4_ops_t *fletcher_4_impls[] = {
+       &fletcher_4_scalar_ops,
+#if defined(HAVE_SSE2)
+       &fletcher_4_sse2_ops,
+#endif
+#if defined(HAVE_SSE2) && defined(HAVE_SSSE3)
+       &fletcher_4_ssse3_ops,
+#endif
+#if defined(HAVE_AVX) && defined(HAVE_AVX2)
+       &fletcher_4_avx2_ops,
+#endif
+#if defined(__x86_64) && defined(HAVE_AVX512F)
+       &fletcher_4_avx512f_ops,
+#endif
+#if defined(__aarch64__)
+       &fletcher_4_aarch64_neon_ops,
+#endif
+};
 
+/* Hold all supported implementations */
+static uint32_t fletcher_4_supp_impls_cnt = 0;
+static fletcher_4_ops_t *fletcher_4_supp_impls[ARRAY_SIZE(fletcher_4_impls)];
+
+/* Select fletcher4 implementation */
+#define        IMPL_FASTEST    (UINT32_MAX)
+#define        IMPL_CYCLE      (UINT32_MAX - 1)
+#define        IMPL_SCALAR     (0)
+
+static uint32_t fletcher_4_impl_chosen = IMPL_FASTEST;
+
+#define        IMPL_READ(i)    (*(volatile uint32_t *) &(i))
+
+static struct fletcher_4_impl_selector {
+       const char      *fis_name;
+       uint32_t        fis_sel;
+} fletcher_4_impl_selectors[] = {
+#if !defined(_KERNEL)
+       { "cycle",      IMPL_CYCLE },
+#endif
+       { "fastest",    IMPL_FASTEST },
+       { "scalar",     IMPL_SCALAR }
+};
+
+static kstat_t *fletcher_4_kstat;
+
+static struct fletcher_4_kstat {
+       uint64_t native;
+       uint64_t byteswap;
+} fletcher_4_stat_data[ARRAY_SIZE(fletcher_4_impls) + 1];
+
+/* Indicate that benchmark has been completed */
+static boolean_t fletcher_4_initialized = B_FALSE;
+
+/*ARGSUSED*/
 void
-fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
+fletcher_2_native(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
 {
        const uint64_t *ip = buf;
        const uint64_t *ipend = ip + (size / sizeof (uint64_t));
@@ -148,8 +234,10 @@ fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
        ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
 }
 
+/*ARGSUSED*/
 void
-fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
+fletcher_2_byteswap(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
 {
        const uint64_t *ip = buf;
        const uint64_t *ipend = ip + (size / sizeof (uint64_t));
@@ -165,90 +253,526 @@ fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
        ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
 }
 
-void
-fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
+static void
+fletcher_4_scalar_init(fletcher_4_ctx_t *ctx)
+{
+       ZIO_SET_CHECKSUM(&ctx->scalar, 0, 0, 0, 0);
+}
+
+static void
+fletcher_4_scalar_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
+{
+       memcpy(zcp, &ctx->scalar, sizeof (zio_cksum_t));
+}
+
+static void
+fletcher_4_scalar_native(fletcher_4_ctx_t *ctx, const void *buf,
+    uint64_t size)
 {
        const uint32_t *ip = buf;
        const uint32_t *ipend = ip + (size / sizeof (uint32_t));
        uint64_t a, b, c, d;
 
-       for (a = b = c = d = 0; ip < ipend; ip++) {
+       a = ctx->scalar.zc_word[0];
+       b = ctx->scalar.zc_word[1];
+       c = ctx->scalar.zc_word[2];
+       d = ctx->scalar.zc_word[3];
+
+       for (; ip < ipend; ip++) {
                a += ip[0];
                b += a;
                c += b;
                d += c;
        }
 
-       ZIO_SET_CHECKSUM(zcp, a, b, c, d);
+       ZIO_SET_CHECKSUM(&ctx->scalar, a, b, c, d);
 }
 
-void
-fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
+static void
+fletcher_4_scalar_byteswap(fletcher_4_ctx_t *ctx, const void *buf,
+    uint64_t size)
 {
        const uint32_t *ip = buf;
        const uint32_t *ipend = ip + (size / sizeof (uint32_t));
        uint64_t a, b, c, d;
 
-       for (a = b = c = d = 0; ip < ipend; ip++) {
+       a = ctx->scalar.zc_word[0];
+       b = ctx->scalar.zc_word[1];
+       c = ctx->scalar.zc_word[2];
+       d = ctx->scalar.zc_word[3];
+
+       for (; ip < ipend; ip++) {
                a += BSWAP_32(ip[0]);
                b += a;
                c += b;
                d += c;
        }
 
-       ZIO_SET_CHECKSUM(zcp, a, b, c, d);
+       ZIO_SET_CHECKSUM(&ctx->scalar, a, b, c, d);
 }
 
+static boolean_t
+fletcher_4_scalar_valid(void)
+{
+       return (B_TRUE);
+}
+
+int
+fletcher_4_impl_set(const char *val)
+{
+       int err = -EINVAL;
+       uint32_t impl = IMPL_READ(fletcher_4_impl_chosen);
+       size_t i, val_len;
+
+       val_len = strlen(val);
+       while ((val_len > 0) && !!isspace(val[val_len-1])) /* trim '\n' */
+               val_len--;
+
+       /* check mandatory implementations */
+       for (i = 0; i < ARRAY_SIZE(fletcher_4_impl_selectors); i++) {
+               const char *name = fletcher_4_impl_selectors[i].fis_name;
+
+               if (val_len == strlen(name) &&
+                   strncmp(val, name, val_len) == 0) {
+                       impl = fletcher_4_impl_selectors[i].fis_sel;
+                       err = 0;
+                       break;
+               }
+       }
+
+       if (err != 0 && fletcher_4_initialized) {
+               /* check all supported implementations */
+               for (i = 0; i < fletcher_4_supp_impls_cnt; i++) {
+                       const char *name = fletcher_4_supp_impls[i]->name;
+
+                       if (val_len == strlen(name) &&
+                           strncmp(val, name, val_len) == 0) {
+                               impl = i;
+                               err = 0;
+                               break;
+                       }
+               }
+       }
+
+       if (err == 0) {
+               atomic_swap_32(&fletcher_4_impl_chosen, impl);
+               membar_producer();
+       }
+
+       return (err);
+}
+
+static inline const fletcher_4_ops_t *
+fletcher_4_impl_get(void)
+{
+       fletcher_4_ops_t *ops = NULL;
+       const uint32_t impl = IMPL_READ(fletcher_4_impl_chosen);
+
+       switch (impl) {
+       case IMPL_FASTEST:
+               ASSERT(fletcher_4_initialized);
+               ops = &fletcher_4_fastest_impl;
+               break;
+#if !defined(_KERNEL)
+       case IMPL_CYCLE: {
+               ASSERT(fletcher_4_initialized);
+               ASSERT3U(fletcher_4_supp_impls_cnt, >, 0);
+
+               static uint32_t cycle_count = 0;
+               uint32_t idx = (++cycle_count) % fletcher_4_supp_impls_cnt;
+               ops = fletcher_4_supp_impls[idx];
+       }
+       break;
+#endif
+       default:
+               ASSERT3U(fletcher_4_supp_impls_cnt, >, 0);
+               ASSERT3U(impl, <, fletcher_4_supp_impls_cnt);
+
+               ops = fletcher_4_supp_impls[impl];
+               break;
+       }
+
+       ASSERT3P(ops, !=, NULL);
+
+       return (ops);
+}
+
+static inline void
+fletcher_4_native_impl(const void *buf, uint64_t size, zio_cksum_t *zcp)
+{
+       fletcher_4_ctx_t ctx;
+       const fletcher_4_ops_t *ops = fletcher_4_impl_get();
+
+       ops->init_native(&ctx);
+       ops->compute_native(&ctx, buf, size);
+       ops->fini_native(&ctx, zcp);
+}
+
+/*ARGSUSED*/
 void
-fletcher_4_incremental_native(const void *buf, uint64_t size,
+fletcher_4_native(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
+{
+       const uint64_t p2size = P2ALIGN(size, 64);
+
+       ASSERT(IS_P2ALIGNED(size, sizeof (uint32_t)));
+
+       if (size == 0 || p2size == 0) {
+               ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
+
+               if (size > 0)
+                       fletcher_4_scalar_native((fletcher_4_ctx_t *)zcp,
+                           buf, size);
+       } else {
+               fletcher_4_native_impl(buf, p2size, zcp);
+
+               if (p2size < size)
+                       fletcher_4_scalar_native((fletcher_4_ctx_t *)zcp,
+                           (char *)buf + p2size, size - p2size);
+       }
+}
+
+void
+fletcher_4_native_varsize(const void *buf, uint64_t size, zio_cksum_t *zcp)
+{
+       ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
+       fletcher_4_scalar_native((fletcher_4_ctx_t *)zcp, buf, size);
+}
+
+static inline void
+fletcher_4_byteswap_impl(const void *buf, uint64_t size, zio_cksum_t *zcp)
+{
+       fletcher_4_ctx_t ctx;
+       const fletcher_4_ops_t *ops = fletcher_4_impl_get();
+
+       ops->init_byteswap(&ctx);
+       ops->compute_byteswap(&ctx, buf, size);
+       ops->fini_byteswap(&ctx, zcp);
+}
+
+/*ARGSUSED*/
+void
+fletcher_4_byteswap(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
+{
+       const uint64_t p2size = P2ALIGN(size, 64);
+
+       ASSERT(IS_P2ALIGNED(size, sizeof (uint32_t)));
+
+       if (size == 0 || p2size == 0) {
+               ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
+
+               if (size > 0)
+                       fletcher_4_scalar_byteswap((fletcher_4_ctx_t *)zcp,
+                           buf, size);
+       } else {
+               fletcher_4_byteswap_impl(buf, p2size, zcp);
+
+               if (p2size < size)
+                       fletcher_4_scalar_byteswap((fletcher_4_ctx_t *)zcp,
+                           (char *)buf + p2size, size - p2size);
+       }
+}
+
+/* Incremental Fletcher 4 */
+
+#define        ZFS_FLETCHER_4_INC_MAX_SIZE     (8ULL << 20)
+
+static inline void
+fletcher_4_incremental_combine(zio_cksum_t *zcp, const uint64_t size,
+    const zio_cksum_t *nzcp)
+{
+       const uint64_t c1 = size / sizeof (uint32_t);
+       const uint64_t c2 = c1 * (c1 + 1) / 2;
+       const uint64_t c3 = c2 * (c1 + 2) / 3;
+
+       /*
+        * Value of 'c3' overflows on buffer sizes close to 16MiB. For that
+        * reason we split incremental fletcher4 computation of large buffers
+        * to steps of (ZFS_FLETCHER_4_INC_MAX_SIZE) size.
+        */
+       ASSERT3U(size, <=, ZFS_FLETCHER_4_INC_MAX_SIZE);
+
+       zcp->zc_word[3] += nzcp->zc_word[3] + c1 * zcp->zc_word[2] +
+           c2 * zcp->zc_word[1] + c3 * zcp->zc_word[0];
+       zcp->zc_word[2] += nzcp->zc_word[2] + c1 * zcp->zc_word[1] +
+           c2 * zcp->zc_word[0];
+       zcp->zc_word[1] += nzcp->zc_word[1] + c1 * zcp->zc_word[0];
+       zcp->zc_word[0] += nzcp->zc_word[0];
+}
+
+static inline void
+fletcher_4_incremental_impl(boolean_t native, const void *buf, uint64_t size,
     zio_cksum_t *zcp)
 {
-       const uint32_t *ip = buf;
-       const uint32_t *ipend = ip + (size / sizeof (uint32_t));
-       uint64_t a, b, c, d;
+       while (size > 0) {
+               zio_cksum_t nzc;
+               uint64_t len = MIN(size, ZFS_FLETCHER_4_INC_MAX_SIZE);
 
-       a = zcp->zc_word[0];
-       b = zcp->zc_word[1];
-       c = zcp->zc_word[2];
-       d = zcp->zc_word[3];
+               if (native)
+                       fletcher_4_native(buf, len, NULL, &nzc);
+               else
+                       fletcher_4_byteswap(buf, len, NULL, &nzc);
 
-       for (; ip < ipend; ip++) {
-               a += ip[0];
-               b += a;
-               c += b;
-               d += c;
+               fletcher_4_incremental_combine(zcp, len, &nzc);
+
+               size -= len;
+               buf += len;
        }
+}
 
-       ZIO_SET_CHECKSUM(zcp, a, b, c, d);
+void
+fletcher_4_incremental_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
+{
+       /* Use scalar impl to directly update cksum of small blocks */
+       if (size < SPA_MINBLOCKSIZE)
+               fletcher_4_scalar_native((fletcher_4_ctx_t *)zcp, buf, size);
+       else
+               fletcher_4_incremental_impl(B_TRUE, buf, size, zcp);
 }
 
 void
 fletcher_4_incremental_byteswap(const void *buf, uint64_t size,
     zio_cksum_t *zcp)
 {
-       const uint32_t *ip = buf;
-       const uint32_t *ipend = ip + (size / sizeof (uint32_t));
-       uint64_t a, b, c, d;
+       /* Use scalar impl to directly update cksum of small blocks */
+       if (size < SPA_MINBLOCKSIZE)
+               fletcher_4_scalar_byteswap((fletcher_4_ctx_t *)zcp, buf, size);
+       else
+               fletcher_4_incremental_impl(B_FALSE, buf, size, zcp);
+}
 
-       a = zcp->zc_word[0];
-       b = zcp->zc_word[1];
-       c = zcp->zc_word[2];
-       d = zcp->zc_word[3];
 
-       for (; ip < ipend; ip++) {
-               a += BSWAP_32(ip[0]);
-               b += a;
-               c += b;
-               d += c;
+/* Fletcher 4 kstats */
+
+static int
+fletcher_4_kstat_headers(char *buf, size_t size)
+{
+       ssize_t off = 0;
+
+       off += snprintf(buf + off, size, "%-17s", "implementation");
+       off += snprintf(buf + off, size - off, "%-15s", "native");
+       (void) snprintf(buf + off, size - off, "%-15s\n", "byteswap");
+
+       return (0);
+}
+
+static int
+fletcher_4_kstat_data(char *buf, size_t size, void *data)
+{
+       struct fletcher_4_kstat *fastest_stat =
+           &fletcher_4_stat_data[fletcher_4_supp_impls_cnt];
+       struct fletcher_4_kstat *curr_stat = (struct fletcher_4_kstat *) data;
+       ssize_t off = 0;
+
+       if (curr_stat == fastest_stat) {
+               off += snprintf(buf + off, size - off, "%-17s", "fastest");
+               off += snprintf(buf + off, size - off, "%-15s",
+                   fletcher_4_supp_impls[fastest_stat->native]->name);
+               off += snprintf(buf + off, size - off, "%-15s\n",
+                   fletcher_4_supp_impls[fastest_stat->byteswap]->name);
+       } else {
+               ptrdiff_t id = curr_stat - fletcher_4_stat_data;
+
+               off += snprintf(buf + off, size - off, "%-17s",
+                   fletcher_4_supp_impls[id]->name);
+               off += snprintf(buf + off, size - off, "%-15llu",
+                           (u_longlong_t) curr_stat->native);
+               off += snprintf(buf + off, size - off, "%-15llu\n",
+                           (u_longlong_t) curr_stat->byteswap);
        }
 
-       ZIO_SET_CHECKSUM(zcp, a, b, c, d);
+       return (0);
+}
+
+static void *
+fletcher_4_kstat_addr(kstat_t *ksp, loff_t n)
+{
+       if (n <= fletcher_4_supp_impls_cnt)
+               ksp->ks_private = (void *) (fletcher_4_stat_data + n);
+       else
+               ksp->ks_private = NULL;
+
+       return (ksp->ks_private);
+}
+
+#define        FLETCHER_4_FASTEST_FN_COPY(type, src)                             \
+{                                                                        \
+       fletcher_4_fastest_impl.init_ ## type = src->init_ ## type;       \
+       fletcher_4_fastest_impl.fini_ ## type = src->fini_ ## type;       \
+       fletcher_4_fastest_impl.compute_ ## type = src->compute_ ## type; \
+}
+
+#define        FLETCHER_4_BENCH_NS     (MSEC2NSEC(50))         /* 50ms */
+
+static void
+fletcher_4_benchmark_impl(boolean_t native, char *data, uint64_t data_size)
+{
+
+       struct fletcher_4_kstat *fastest_stat =
+           &fletcher_4_stat_data[fletcher_4_supp_impls_cnt];
+       hrtime_t start;
+       uint64_t run_bw, run_time_ns, best_run = 0;
+       zio_cksum_t zc;
+       uint32_t i, l, sel_save = IMPL_READ(fletcher_4_impl_chosen);
+
+       zio_checksum_func_t *fletcher_4_test = native ? fletcher_4_native :
+           fletcher_4_byteswap;
+
+       for (i = 0; i < fletcher_4_supp_impls_cnt; i++) {
+               struct fletcher_4_kstat *stat = &fletcher_4_stat_data[i];
+               uint64_t run_count = 0;
+
+               /* temporary set an implementation */
+               fletcher_4_impl_chosen = i;
+
+               kpreempt_disable();
+               start = gethrtime();
+               do {
+                       for (l = 0; l < 32; l++, run_count++)
+                               fletcher_4_test(data, data_size, NULL, &zc);
+
+                       run_time_ns = gethrtime() - start;
+               } while (run_time_ns < FLETCHER_4_BENCH_NS);
+               kpreempt_enable();
+
+               run_bw = data_size * run_count * NANOSEC;
+               run_bw /= run_time_ns;  /* B/s */
+
+               if (native)
+                       stat->native = run_bw;
+               else
+                       stat->byteswap = run_bw;
+
+               if (run_bw > best_run) {
+                       best_run = run_bw;
+
+                       if (native) {
+                               fastest_stat->native = i;
+                               FLETCHER_4_FASTEST_FN_COPY(native,
+                                   fletcher_4_supp_impls[i]);
+                       } else {
+                               fastest_stat->byteswap = i;
+                               FLETCHER_4_FASTEST_FN_COPY(byteswap,
+                                   fletcher_4_supp_impls[i]);
+                       }
+               }
+       }
+
+       /* restore original selection */
+       atomic_swap_32(&fletcher_4_impl_chosen, sel_save);
+}
+
+void
+fletcher_4_init(void)
+{
+       static const size_t data_size = 1 << SPA_OLD_MAXBLOCKSHIFT; /* 128kiB */
+       fletcher_4_ops_t *curr_impl;
+       char *databuf;
+       int i, c;
+
+       /* move supported impl into fletcher_4_supp_impls */
+       for (i = 0, c = 0; i < ARRAY_SIZE(fletcher_4_impls); i++) {
+               curr_impl = (fletcher_4_ops_t *) fletcher_4_impls[i];
+
+               if (curr_impl->valid && curr_impl->valid())
+                       fletcher_4_supp_impls[c++] = curr_impl;
+       }
+       membar_producer();      /* complete fletcher_4_supp_impls[] init */
+       fletcher_4_supp_impls_cnt = c;  /* number of supported impl */
+
+#if !defined(_KERNEL)
+       /* Skip benchmarking and use last implementation as fastest */
+       memcpy(&fletcher_4_fastest_impl,
+           fletcher_4_supp_impls[fletcher_4_supp_impls_cnt-1],
+           sizeof (fletcher_4_fastest_impl));
+       fletcher_4_fastest_impl.name = "fastest";
+       membar_producer();
+
+       fletcher_4_initialized = B_TRUE;
+       return;
+#endif
+       /* Benchmark all supported implementations */
+       databuf = vmem_alloc(data_size, KM_SLEEP);
+       for (i = 0; i < data_size / sizeof (uint64_t); i++)
+               ((uint64_t *)databuf)[i] = (uintptr_t)(databuf+i); /* warm-up */
+
+       fletcher_4_benchmark_impl(B_FALSE, databuf, data_size);
+       fletcher_4_benchmark_impl(B_TRUE, databuf, data_size);
+
+       vmem_free(databuf, data_size);
+
+       /* install kstats for all implementations */
+       fletcher_4_kstat = kstat_create("zfs", 0, "fletcher_4_bench", "misc",
+               KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
+       if (fletcher_4_kstat != NULL) {
+               fletcher_4_kstat->ks_data = NULL;
+               fletcher_4_kstat->ks_ndata = UINT32_MAX;
+               kstat_set_raw_ops(fletcher_4_kstat,
+                   fletcher_4_kstat_headers,
+                   fletcher_4_kstat_data,
+                   fletcher_4_kstat_addr);
+               kstat_install(fletcher_4_kstat);
+       }
+
+       /* Finish initialization */
+       fletcher_4_initialized = B_TRUE;
+}
+
+void
+fletcher_4_fini(void)
+{
+       if (fletcher_4_kstat != NULL) {
+               kstat_delete(fletcher_4_kstat);
+               fletcher_4_kstat = NULL;
+       }
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
+#include <linux/mod_compat.h>
+
+static int
+fletcher_4_param_get(char *buffer, zfs_kernel_param_t *unused)
+{
+       const uint32_t impl = IMPL_READ(fletcher_4_impl_chosen);
+       char *fmt;
+       int i, cnt = 0;
+
+       /* list fastest */
+       fmt = (impl == IMPL_FASTEST) ? "[%s] " : "%s ";
+       cnt += sprintf(buffer + cnt, fmt, "fastest");
+
+       /* list all supported implementations */
+       for (i = 0; i < fletcher_4_supp_impls_cnt; i++) {
+               fmt = (i == impl) ? "[%s] " : "%s ";
+               cnt += sprintf(buffer + cnt, fmt,
+                   fletcher_4_supp_impls[i]->name);
+       }
+
+       return (cnt);
+}
+
+static int
+fletcher_4_param_set(const char *val, zfs_kernel_param_t *unused)
+{
+       return (fletcher_4_impl_set(val));
+}
+
+/*
+ * Choose a fletcher 4 implementation in ZFS.
+ * Users can choose "cycle" to exercise all implementations, but this is
+ * for testing purpose therefore it can only be set in user space.
+ */
+module_param_call(zfs_fletcher_4_impl,
+    fletcher_4_param_set, fletcher_4_param_get, NULL, 0644);
+MODULE_PARM_DESC(zfs_fletcher_4_impl, "Select fletcher 4 implementation.");
+
+EXPORT_SYMBOL(fletcher_4_init);
+EXPORT_SYMBOL(fletcher_4_fini);
 EXPORT_SYMBOL(fletcher_2_native);
 EXPORT_SYMBOL(fletcher_2_byteswap);
 EXPORT_SYMBOL(fletcher_4_native);
+EXPORT_SYMBOL(fletcher_4_native_varsize);
 EXPORT_SYMBOL(fletcher_4_byteswap);
 EXPORT_SYMBOL(fletcher_4_incremental_native);
 EXPORT_SYMBOL(fletcher_4_incremental_byteswap);
diff --git a/zfs/module/zcommon/zfs_fletcher_aarch64_neon.c b/zfs/module/zcommon/zfs_fletcher_aarch64_neon.c
new file mode 100644 (file)
index 0000000..f8991b1
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Implement fast Fletcher4 with NEON instructions. (aarch64)
+ *
+ * Use the 128-bit NEON SIMD instructions and registers to compute
+ * Fletcher4 in four incremental 64-bit parallel accumulator streams,
+ * and then combine the streams to form the final four checksum words.
+ * This implementation is a derivative of the AVX SIMD implementation by
+ * James Guilford and Jinshan Xiong from Intel (see zfs_fletcher_intel.c).
+ *
+ * Copyright (C) 2016 Romain Dolbeau.
+ *
+ * Authors:
+ *     Romain Dolbeau <romain.dolbeau@atos.net>
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     - Redistributions of source code must retain the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer.
+ *
+ *     - Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if defined(__aarch64__)
+
+#include <linux/simd_aarch64.h>
+#include <sys/spa_checksum.h>
+#include <zfs_fletcher.h>
+#include <strings.h>
+
+static void
+fletcher_4_aarch64_neon_init(fletcher_4_ctx_t *ctx)
+{
+       bzero(ctx->aarch64_neon, 4 * sizeof (zfs_fletcher_aarch64_neon_t));
+}
+
+static void
+fletcher_4_aarch64_neon_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
+{
+       uint64_t A, B, C, D;
+       A = ctx->aarch64_neon[0].v[0] + ctx->aarch64_neon[0].v[1];
+       B = 2 * ctx->aarch64_neon[1].v[0] + 2 * ctx->aarch64_neon[1].v[1] -
+           ctx->aarch64_neon[0].v[1];
+       C = 4 * ctx->aarch64_neon[2].v[0] - ctx->aarch64_neon[1].v[0] +
+           4 * ctx->aarch64_neon[2].v[1] - 3 * ctx->aarch64_neon[1].v[1];
+       D = 8 * ctx->aarch64_neon[3].v[0] - 4 * ctx->aarch64_neon[2].v[0] +
+           8 * ctx->aarch64_neon[3].v[1] - 8 * ctx->aarch64_neon[2].v[1] +
+           ctx->aarch64_neon[1].v[1];
+       ZIO_SET_CHECKSUM(zcp, A, B, C, D);
+}
+
+#define        NEON_INIT_LOOP()                        \
+       asm("eor %[ZERO].16b,%[ZERO].16b,%[ZERO].16b\n" \
+       "ld1 { %[ACC0].4s }, %[CTX0]\n"         \
+       "ld1 { %[ACC1].4s }, %[CTX1]\n"         \
+       "ld1 { %[ACC2].4s }, %[CTX2]\n"         \
+       "ld1 { %[ACC3].4s }, %[CTX3]\n"         \
+       : [ZERO] "=w" (ZERO),                   \
+       [ACC0] "=w" (ACC0), [ACC1] "=w" (ACC1), \
+       [ACC2] "=w" (ACC2), [ACC3] "=w" (ACC3)  \
+       : [CTX0] "Q" (ctx->aarch64_neon[0]),    \
+       [CTX1] "Q" (ctx->aarch64_neon[1]),      \
+       [CTX2] "Q" (ctx->aarch64_neon[2]),      \
+       [CTX3] "Q" (ctx->aarch64_neon[3]))
+
+#define        NEON_DO_REVERSE "rev32 %[SRC].16b, %[SRC].16b\n"
+
+#define        NEON_DONT_REVERSE ""
+
+#define        NEON_MAIN_LOOP(REVERSE)                         \
+       asm("ld1 { %[SRC].4s }, %[IP]\n"                \
+       REVERSE                                         \
+       "zip1 %[TMP1].4s, %[SRC].4s, %[ZERO].4s\n"      \
+       "zip2 %[TMP2].4s, %[SRC].4s, %[ZERO].4s\n"      \
+       "add %[ACC0].2d, %[ACC0].2d, %[TMP1].2d\n"      \
+       "add %[ACC1].2d, %[ACC1].2d, %[ACC0].2d\n"      \
+       "add %[ACC2].2d, %[ACC2].2d, %[ACC1].2d\n"      \
+       "add %[ACC3].2d, %[ACC3].2d, %[ACC2].2d\n"      \
+       "add %[ACC0].2d, %[ACC0].2d, %[TMP2].2d\n"      \
+       "add %[ACC1].2d, %[ACC1].2d, %[ACC0].2d\n"      \
+       "add %[ACC2].2d, %[ACC2].2d, %[ACC1].2d\n"      \
+       "add %[ACC3].2d, %[ACC3].2d, %[ACC2].2d\n"      \
+       : [SRC] "=&w" (SRC),                            \
+       [TMP1] "=&w" (TMP1), [TMP2] "=&w" (TMP2),       \
+       [ACC0] "+w" (ACC0), [ACC1] "+w" (ACC1),         \
+       [ACC2] "+w" (ACC2), [ACC3] "+w" (ACC3)          \
+       : [ZERO] "w" (ZERO), [IP] "Q" (*ip))
+
+#define        NEON_FINI_LOOP()                        \
+       asm("st1 { %[ACC0].4s },%[DST0]\n"      \
+       "st1 { %[ACC1].4s },%[DST1]\n"          \
+       "st1 { %[ACC2].4s },%[DST2]\n"          \
+       "st1 { %[ACC3].4s },%[DST3]\n"          \
+       : [DST0] "=Q" (ctx->aarch64_neon[0]),   \
+       [DST1] "=Q" (ctx->aarch64_neon[1]),     \
+       [DST2] "=Q" (ctx->aarch64_neon[2]),     \
+       [DST3] "=Q" (ctx->aarch64_neon[3])      \
+       : [ACC0] "w" (ACC0), [ACC1] "w" (ACC1), \
+       [ACC2] "w" (ACC2), [ACC3] "w" (ACC3))
+
+static void
+fletcher_4_aarch64_neon_native(fletcher_4_ctx_t *ctx,
+    const void *buf, uint64_t size)
+{
+       const uint64_t *ip = buf;
+       const uint64_t *ipend = (uint64_t *)((uint8_t *)ip + size);
+#if defined(_KERNEL)
+register unsigned char ZERO asm("v0") __attribute__((vector_size(16)));
+register unsigned char ACC0 asm("v1") __attribute__((vector_size(16)));
+register unsigned char ACC1 asm("v2") __attribute__((vector_size(16)));
+register unsigned char ACC2 asm("v3") __attribute__((vector_size(16)));
+register unsigned char ACC3 asm("v4") __attribute__((vector_size(16)));
+register unsigned char TMP1 asm("v5") __attribute__((vector_size(16)));
+register unsigned char TMP2 asm("v6") __attribute__((vector_size(16)));
+register unsigned char SRC asm("v7") __attribute__((vector_size(16)));
+#else
+unsigned char ZERO __attribute__((vector_size(16)));
+unsigned char ACC0 __attribute__((vector_size(16)));
+unsigned char ACC1 __attribute__((vector_size(16)));
+unsigned char ACC2 __attribute__((vector_size(16)));
+unsigned char ACC3 __attribute__((vector_size(16)));
+unsigned char TMP1 __attribute__((vector_size(16)));
+unsigned char TMP2 __attribute__((vector_size(16)));
+unsigned char SRC __attribute__((vector_size(16)));
+#endif
+
+       kfpu_begin();
+
+       NEON_INIT_LOOP();
+
+       for (; ip < ipend; ip += 2) {
+               NEON_MAIN_LOOP(NEON_DONT_REVERSE);
+       }
+
+       NEON_FINI_LOOP();
+
+       kfpu_end();
+}
+
+static void
+fletcher_4_aarch64_neon_byteswap(fletcher_4_ctx_t *ctx,
+    const void *buf, uint64_t size)
+{
+       const uint64_t *ip = buf;
+       const uint64_t *ipend = (uint64_t *)((uint8_t *)ip + size);
+#if defined(_KERNEL)
+register unsigned char ZERO asm("v0") __attribute__((vector_size(16)));
+register unsigned char ACC0 asm("v1") __attribute__((vector_size(16)));
+register unsigned char ACC1 asm("v2") __attribute__((vector_size(16)));
+register unsigned char ACC2 asm("v3") __attribute__((vector_size(16)));
+register unsigned char ACC3 asm("v4") __attribute__((vector_size(16)));
+register unsigned char TMP1 asm("v5") __attribute__((vector_size(16)));
+register unsigned char TMP2 asm("v6") __attribute__((vector_size(16)));
+register unsigned char SRC asm("v7") __attribute__((vector_size(16)));
+#else
+unsigned char ZERO __attribute__((vector_size(16)));
+unsigned char ACC0 __attribute__((vector_size(16)));
+unsigned char ACC1 __attribute__((vector_size(16)));
+unsigned char ACC2 __attribute__((vector_size(16)));
+unsigned char ACC3 __attribute__((vector_size(16)));
+unsigned char TMP1 __attribute__((vector_size(16)));
+unsigned char TMP2 __attribute__((vector_size(16)));
+unsigned char SRC __attribute__((vector_size(16)));
+#endif
+
+       kfpu_begin();
+
+       NEON_INIT_LOOP();
+
+       for (; ip < ipend; ip += 2) {
+               NEON_MAIN_LOOP(NEON_DO_REVERSE);
+       }
+
+       NEON_FINI_LOOP();
+
+       kfpu_end();
+}
+
+static boolean_t fletcher_4_aarch64_neon_valid(void)
+{
+       return (B_TRUE);
+}
+
+const fletcher_4_ops_t fletcher_4_aarch64_neon_ops = {
+       .init_native = fletcher_4_aarch64_neon_init,
+       .compute_native = fletcher_4_aarch64_neon_native,
+       .fini_native = fletcher_4_aarch64_neon_fini,
+       .init_byteswap = fletcher_4_aarch64_neon_init,
+       .compute_byteswap = fletcher_4_aarch64_neon_byteswap,
+       .fini_byteswap = fletcher_4_aarch64_neon_fini,
+       .valid = fletcher_4_aarch64_neon_valid,
+       .name = "aarch64_neon"
+};
+
+#endif /* defined(__aarch64__) */
diff --git a/zfs/module/zcommon/zfs_fletcher_avx512.c b/zfs/module/zcommon/zfs_fletcher_avx512.c
new file mode 100644 (file)
index 0000000..2d28ffb
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#if defined(__x86_64) && defined(HAVE_AVX512F)
+
+#include <linux/simd_x86.h>
+#include <sys/byteorder.h>
+#include <sys/spa_checksum.h>
+#include <zfs_fletcher.h>
+#include <strings.h>
+
+#define        __asm __asm__ __volatile__
+
+static void
+fletcher_4_avx512f_init(fletcher_4_ctx_t *ctx)
+{
+       bzero(ctx->avx512, 4 * sizeof (zfs_fletcher_avx512_t));
+}
+
+static void
+fletcher_4_avx512f_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
+{
+       static const uint64_t
+       CcA[] = {   0,   0,   1,   3,   6,  10,  15,  21 },
+       CcB[] = {  28,  36,  44,  52,  60,  68,  76,  84 },
+       DcA[] = {   0,   0,   0,   1,   4,  10,  20,  35 },
+       DcB[] = {  56,  84, 120, 164, 216, 276, 344, 420 },
+       DcC[] = { 448, 512, 576, 640, 704, 768, 832, 896 };
+
+       uint64_t A, B, C, D;
+       uint64_t i;
+
+       A = ctx->avx512[0].v[0];
+       B = 8 * ctx->avx512[1].v[0];
+       C = 64 * ctx->avx512[2].v[0] - CcB[0] * ctx->avx512[1].v[0];
+       D = 512 * ctx->avx512[3].v[0] - DcC[0] * ctx->avx512[2].v[0] +
+           DcB[0] * ctx->avx512[1].v[0];
+
+       for (i = 1; i < 8; i++) {
+               A += ctx->avx512[0].v[i];
+               B += 8 * ctx->avx512[1].v[i] - i * ctx->avx512[0].v[i];
+               C += 64 * ctx->avx512[2].v[i] - CcB[i] * ctx->avx512[1].v[i] +
+                   CcA[i] * ctx->avx512[0].v[i];
+               D += 512 * ctx->avx512[3].v[i] - DcC[i] * ctx->avx512[2].v[i] +
+                   DcB[i] * ctx->avx512[1].v[i] - DcA[i] * ctx->avx512[0].v[i];
+       }
+
+       ZIO_SET_CHECKSUM(zcp, A, B, C, D);
+}
+
+#define        FLETCHER_4_AVX512_RESTORE_CTX(ctx)                              \
+{                                                                      \
+       __asm("vmovdqu64 %0, %%zmm0" :: "m" ((ctx)->avx512[0]));        \
+       __asm("vmovdqu64 %0, %%zmm1" :: "m" ((ctx)->avx512[1]));        \
+       __asm("vmovdqu64 %0, %%zmm2" :: "m" ((ctx)->avx512[2]));        \
+       __asm("vmovdqu64 %0, %%zmm3" :: "m" ((ctx)->avx512[3]));        \
+}
+
+#define        FLETCHER_4_AVX512_SAVE_CTX(ctx)                                 \
+{                                                                      \
+       __asm("vmovdqu64 %%zmm0, %0" : "=m" ((ctx)->avx512[0]));        \
+       __asm("vmovdqu64 %%zmm1, %0" : "=m" ((ctx)->avx512[1]));        \
+       __asm("vmovdqu64 %%zmm2, %0" : "=m" ((ctx)->avx512[2]));        \
+       __asm("vmovdqu64 %%zmm3, %0" : "=m" ((ctx)->avx512[3]));        \
+}
+
+static void
+fletcher_4_avx512f_native(fletcher_4_ctx_t *ctx, const void *buf, uint64_t size)
+{
+       const uint32_t *ip = buf;
+       const uint32_t *ipend = (uint32_t *)((uint8_t *)ip + size);
+
+       kfpu_begin();
+
+       FLETCHER_4_AVX512_RESTORE_CTX(ctx);
+
+       for (; ip < ipend; ip += 8) {
+               __asm("vpmovzxdq %0, %%zmm4"::"m" (*ip));
+               __asm("vpaddq %zmm4, %zmm0, %zmm0");
+               __asm("vpaddq %zmm0, %zmm1, %zmm1");
+               __asm("vpaddq %zmm1, %zmm2, %zmm2");
+               __asm("vpaddq %zmm2, %zmm3, %zmm3");
+       }
+
+       FLETCHER_4_AVX512_SAVE_CTX(ctx);
+
+       kfpu_end();
+}
+
+static void
+fletcher_4_avx512f_byteswap(fletcher_4_ctx_t *ctx, const void *buf,
+    uint64_t size)
+{
+       static const uint64_t byteswap_mask = 0xFFULL;
+       const uint32_t *ip = buf;
+       const uint32_t *ipend = (uint32_t *)((uint8_t *)ip + size);
+
+       kfpu_begin();
+
+       FLETCHER_4_AVX512_RESTORE_CTX(ctx);
+
+       __asm("vpbroadcastq %0, %%zmm8" :: "r" (byteswap_mask));
+       __asm("vpsllq $8, %zmm8, %zmm9");
+       __asm("vpsllq $16, %zmm8, %zmm10");
+       __asm("vpsllq $24, %zmm8, %zmm11");
+
+       for (; ip < ipend; ip += 8) {
+               __asm("vpmovzxdq %0, %%zmm5"::"m" (*ip));
+
+               __asm("vpsrlq $24, %zmm5, %zmm6");
+               __asm("vpandd %zmm8, %zmm6, %zmm6");
+               __asm("vpsrlq $8, %zmm5, %zmm7");
+               __asm("vpandd %zmm9, %zmm7, %zmm7");
+               __asm("vpord %zmm6, %zmm7, %zmm4");
+               __asm("vpsllq $8, %zmm5, %zmm6");
+               __asm("vpandd %zmm10, %zmm6, %zmm6");
+               __asm("vpord %zmm6, %zmm4, %zmm4");
+               __asm("vpsllq $24, %zmm5, %zmm5");
+               __asm("vpandd %zmm11, %zmm5, %zmm5");
+               __asm("vpord %zmm5, %zmm4, %zmm4");
+
+               __asm("vpaddq %zmm4, %zmm0, %zmm0");
+               __asm("vpaddq %zmm0, %zmm1, %zmm1");
+               __asm("vpaddq %zmm1, %zmm2, %zmm2");
+               __asm("vpaddq %zmm2, %zmm3, %zmm3");
+       }
+
+       FLETCHER_4_AVX512_SAVE_CTX(ctx)
+
+       kfpu_end();
+}
+
+static boolean_t
+fletcher_4_avx512f_valid(void)
+{
+       return (zfs_avx512f_available());
+}
+
+const fletcher_4_ops_t fletcher_4_avx512f_ops = {
+       .init_native = fletcher_4_avx512f_init,
+       .fini_native = fletcher_4_avx512f_fini,
+       .compute_native = fletcher_4_avx512f_native,
+       .init_byteswap = fletcher_4_avx512f_init,
+       .fini_byteswap = fletcher_4_avx512f_fini,
+       .compute_byteswap = fletcher_4_avx512f_byteswap,
+       .valid = fletcher_4_avx512f_valid,
+       .name = "avx512f"
+};
+
+#endif /* defined(__x86_64) && defined(HAVE_AVX512F) */
diff --git a/zfs/module/zcommon/zfs_fletcher_intel.c b/zfs/module/zcommon/zfs_fletcher_intel.c
new file mode 100644 (file)
index 0000000..a479b9d
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Implement fast Fletcher4 with AVX2 instructions. (x86_64)
+ *
+ * Use the 256-bit AVX2 SIMD instructions and registers to compute
+ * Fletcher4 in four incremental 64-bit parallel accumulator streams,
+ * and then combine the streams to form the final four checksum words.
+ *
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * Authors:
+ *      James Guilford <james.guilford@intel.com>
+ *      Jinshan Xiong <jinshan.xiong@intel.com>
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if defined(HAVE_AVX) && defined(HAVE_AVX2)
+
+#include <linux/simd_x86.h>
+#include <sys/spa_checksum.h>
+#include <zfs_fletcher.h>
+#include <strings.h>
+
+static void
+fletcher_4_avx2_init(fletcher_4_ctx_t *ctx)
+{
+       bzero(ctx->avx, 4 * sizeof (zfs_fletcher_avx_t));
+}
+
+static void
+fletcher_4_avx2_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp)
+{
+       uint64_t A, B, C, D;
+
+       A = ctx->avx[0].v[0] + ctx->avx[0].v[1] +
+           ctx->avx[0].v[2] + ctx->avx[0].v[3];
+       B = 0 - ctx->avx[0].v[1] - 2 * ctx->avx[0].v[2] - 3 * ctx->avx[0].v[3] +
+           4 * ctx->avx[1].v[0] + 4 * ctx->avx[1].v[1] + 4 * ctx->avx[1].v[2] +
+           4 * ctx->avx[1].v[3];
+
+       C = ctx->avx[0].v[2] + 3 * ctx->avx[0].v[3] - 6 * ctx->avx[1].v[0] -
+           10 * ctx->avx[1].v[1] - 14 * ctx->avx[1].v[2] -
+           18 * ctx->avx[1].v[3] + 16 * ctx->avx[2].v[0] +
+           16 * ctx->avx[2].v[1] + 16 * ctx->avx[2].v[2] +
+           16 * ctx->avx[2].v[3];
+
+       D = 0 - ctx->avx[0].v[3] + 4 * ctx->avx[1].v[0] +
+           10 * ctx->avx[1].v[1] + 20 * ctx->avx[1].v[2] +
+           34 * ctx->avx[1].v[3] - 48 * ctx->avx[2].v[0] -
+           64 * ctx->avx[2].v[1] - 80 * ctx->avx[2].v[2] -
+           96 * ctx->avx[2].v[3] + 64 * ctx->avx[3].v[0] +
+           64 * ctx->avx[3].v[1] + 64 * ctx->avx[3].v[2] +
+           64 * ctx->avx[3].v[3];
+
+       ZIO_SET_CHECKSUM(zcp, A, B, C, D);
+}
+
+#define        FLETCHER_4_AVX2_RESTORE_CTX(ctx)                                \
+{                                                                      \
+       asm volatile("vmovdqu %0, %%ymm0" :: "m" ((ctx)->avx[0]));      \
+       asm volatile("vmovdqu %0, %%ymm1" :: "m" ((ctx)->avx[1]));      \
+       asm volatile("vmovdqu %0, %%ymm2" :: "m" ((ctx)->avx[2]));      \
+       asm volatile("vmovdqu %0, %%ymm3" :: "m" ((ctx)->avx[3]));      \
+}
+
+#define        FLETCHER_4_AVX2_SAVE_CTX(ctx)                                   \
+{                                                                      \
+       asm volatile("vmovdqu %%ymm0, %0" : "=m" ((ctx)->avx[0]));      \
+       asm volatile("vmovdqu %%ymm1, %0" : "=m" ((ctx)->avx[1]));      \
+       asm volatile("vmovdqu %%ymm2, %0" : "=m" ((ctx)->avx[2]));      \
+       asm volatile("vmovdqu %%ymm3, %0" : "=m" ((ctx)->avx[3]));      \
+}
+
+
+static void
+fletcher_4_avx2_native(fletcher_4_ctx_t *ctx, const void *buf, uint64_t size)
+{
+       const uint64_t *ip = buf;
+       const uint64_t *ipend = (uint64_t *)((uint8_t *)ip + size);
+
+       kfpu_begin();
+
+       FLETCHER_4_AVX2_RESTORE_CTX(ctx);
+
+       for (; ip < ipend; ip += 2) {
+               asm volatile("vpmovzxdq %0, %%ymm4"::"m" (*ip));
+               asm volatile("vpaddq %ymm4, %ymm0, %ymm0");
+               asm volatile("vpaddq %ymm0, %ymm1, %ymm1");
+               asm volatile("vpaddq %ymm1, %ymm2, %ymm2");
+               asm volatile("vpaddq %ymm2, %ymm3, %ymm3");
+       }
+
+       FLETCHER_4_AVX2_SAVE_CTX(ctx);
+       asm volatile("vzeroupper");
+
+       kfpu_end();
+}
+
+static void
+fletcher_4_avx2_byteswap(fletcher_4_ctx_t *ctx, const void *buf, uint64_t size)
+{
+       static const zfs_fletcher_avx_t mask = {
+               .v = { 0xFFFFFFFF00010203, 0xFFFFFFFF08090A0B,
+                   0xFFFFFFFF00010203, 0xFFFFFFFF08090A0B }
+       };
+       const uint64_t *ip = buf;
+       const uint64_t *ipend = (uint64_t *)((uint8_t *)ip + size);
+
+       kfpu_begin();
+
+       FLETCHER_4_AVX2_RESTORE_CTX(ctx);
+
+       asm volatile("vmovdqu %0, %%ymm5" :: "m" (mask));
+
+       for (; ip < ipend; ip += 2) {
+               asm volatile("vpmovzxdq %0, %%ymm4"::"m" (*ip));
+               asm volatile("vpshufb %ymm5, %ymm4, %ymm4");
+
+               asm volatile("vpaddq %ymm4, %ymm0, %ymm0");
+               asm volatile("vpaddq %ymm0, %ymm1, %ymm1");
+               asm volatile("vpaddq %ymm1, %ymm2, %ymm2");
+               asm volatile("vpaddq %ymm2, %ymm3, %ymm3");
+       }
+
+       FLETCHER_4_AVX2_SAVE_CTX(ctx);
+       asm volatile("vzeroupper");
+
+       kfpu_end();
+}
+
+static boolean_t fletcher_4_avx2_valid(void)
+{
+       return (zfs_avx_available() && zfs_avx2_available());
+}
+
+const fletcher_4_ops_t fletcher_4_avx2_ops = {
+       .init_native = fletcher_4_avx2_init,
+       .fini_native = fletcher_4_avx2_fini,
+       .compute_native = fletcher_4_avx2_native,
+       .init_byteswap = fletcher_4_avx2_init,
+       .fini_byteswap = fletcher_4_avx2_fini,
+       .compute_byteswap = fletcher_4_avx2_byteswap,
+       .valid = fletcher_4_avx2_valid,
+       .name = "avx2"
+};
+
+#endif /* defined(HAVE_AVX) && defined(HAVE_AVX2) */
diff --git a/zfs/module/zcommon/zfs_fletcher_sse.c b/zfs/module/zcommon/zfs_fletcher_sse.c
new file mode 100644 (file)
index 0000000..ae03f42
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Implement fast Fletcher4 with SSE2,SSSE3 instructions. (x86)
+ *
+ * Use the 128-bit SSE2/SSSE3 SIMD instructions and registers to compute
+ * Fletcher4 in four incremental 64-bit parallel accumulator streams,
+ * and then combine the streams to form the final four checksum words.
+ * This implementation is a derivative of the AVX SIMD implementation by
+ * James Guilford and Jinshan Xiong from Intel (see zfs_fletcher_intel.c).
+ *
+ * Copyright (C) 2016 Tyler J. Stachecki.
+ *
+ * Authors:
+ *     Tyler J. Stachecki <stachecki.tyler@gmail.com>
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#if defined(HAVE_SSE2)
+
+#include <linux/simd_x86.h>
+#include <sys/spa_checksum.h>
+#include <sys/byteorder.h>
+#include <zfs_fletcher.h>
+#include <strings.h>
+
+static void
+fletcher_4_sse2_init(fletcher_4_ctx_t *ctx) {
+       bzero(ctx->sse, 4 * sizeof (zfs_fletcher_sse_t));
+}
+
+static void
+fletcher_4_sse2_fini(fletcher_4_ctx_t *ctx, zio_cksum_t *zcp) {
+       uint64_t A, B, C, D;
+
+       /*
+        * The mixing matrix for checksum calculation is:
+        * a = a0 + a1
+        * b = 2b0 + 2b1 - a1
+        * c = 4c0 - b0 + 4c1 -3b1
+        * d = 8d0 - 4c0 + 8d1 - 8c1 + b1;
+        *
+        * c and d are multiplied by 4 and 8, respectively,
+        * before spilling the vectors out to memory.
+        */
+       A = ctx->sse[0].v[0] + ctx->sse[0].v[1];
+       B = 2 * ctx->sse[1].v[0] + 2 * ctx->sse[1].v[1] - ctx->sse[0].v[1];
+       C = 4 * ctx->sse[2].v[0] - ctx->sse[1].v[0] + 4 * ctx->sse[2].v[1] -
+           3 * ctx->sse[1].v[1];
+       D = 8 * ctx->sse[3].v[0] - 4 * ctx->sse[2].v[0] + 8 * ctx->sse[3].v[1] -
+           8 * ctx->sse[2].v[1] + ctx->sse[1].v[1];
+
+       ZIO_SET_CHECKSUM(zcp, A, B, C, D);
+}
+
+#define        FLETCHER_4_SSE_RESTORE_CTX(ctx)                                 \
+{                                                                      \
+       asm volatile("movdqu %0, %%xmm0" :: "m" ((ctx)->sse[0]));       \
+       asm volatile("movdqu %0, %%xmm1" :: "m" ((ctx)->sse[1]));       \
+       asm volatile("movdqu %0, %%xmm2" :: "m" ((ctx)->sse[2]));       \
+       asm volatile("movdqu %0, %%xmm3" :: "m" ((ctx)->sse[3]));       \
+}
+
+#define        FLETCHER_4_SSE_SAVE_CTX(ctx)                                    \
+{                                                                      \
+       asm volatile("movdqu %%xmm0, %0" : "=m" ((ctx)->sse[0]));       \
+       asm volatile("movdqu %%xmm1, %0" : "=m" ((ctx)->sse[1]));       \
+       asm volatile("movdqu %%xmm2, %0" : "=m" ((ctx)->sse[2]));       \
+       asm volatile("movdqu %%xmm3, %0" : "=m" ((ctx)->sse[3]));       \
+}
+
+static void
+fletcher_4_sse2_native(fletcher_4_ctx_t *ctx, const void *buf, uint64_t size)
+{
+       const uint64_t *ip = buf;
+       const uint64_t *ipend = (uint64_t *)((uint8_t *)ip + size);
+
+       kfpu_begin();
+
+       FLETCHER_4_SSE_RESTORE_CTX(ctx);
+
+       asm volatile("pxor %xmm4, %xmm4");
+
+       for (; ip < ipend; ip += 2) {
+               asm volatile("movdqu %0, %%xmm5" :: "m"(*ip));
+               asm volatile("movdqa %xmm5, %xmm6");
+               asm volatile("punpckldq %xmm4, %xmm5");
+               asm volatile("punpckhdq %xmm4, %xmm6");
+               asm volatile("paddq %xmm5, %xmm0");
+               asm volatile("paddq %xmm0, %xmm1");
+               asm volatile("paddq %xmm1, %xmm2");
+               asm volatile("paddq %xmm2, %xmm3");
+               asm volatile("paddq %xmm6, %xmm0");
+               asm volatile("paddq %xmm0, %xmm1");
+               asm volatile("paddq %xmm1, %xmm2");
+               asm volatile("paddq %xmm2, %xmm3");
+       }
+
+       FLETCHER_4_SSE_SAVE_CTX(ctx);
+
+       kfpu_end();
+}
+
+static void
+fletcher_4_sse2_byteswap(fletcher_4_ctx_t *ctx, const void *buf, uint64_t size)
+{
+       const uint32_t *ip = buf;
+       const uint32_t *ipend = (uint32_t *)((uint8_t *)ip + size);
+
+       kfpu_begin();
+
+       FLETCHER_4_SSE_RESTORE_CTX(ctx);
+
+       for (; ip < ipend; ip += 2) {
+               uint32_t scratch1 = BSWAP_32(ip[0]);
+               uint32_t scratch2 = BSWAP_32(ip[1]);
+               asm volatile("movd %0, %%xmm5" :: "r"(scratch1));
+               asm volatile("movd %0, %%xmm6" :: "r"(scratch2));
+               asm volatile("punpcklqdq %xmm6, %xmm5");
+               asm volatile("paddq %xmm5, %xmm0");
+               asm volatile("paddq %xmm0, %xmm1");
+               asm volatile("paddq %xmm1, %xmm2");
+               asm volatile("paddq %xmm2, %xmm3");
+       }
+
+       FLETCHER_4_SSE_SAVE_CTX(ctx);
+
+       kfpu_end();
+}
+
+static boolean_t fletcher_4_sse2_valid(void)
+{
+       return (zfs_sse2_available());
+}
+
+const fletcher_4_ops_t fletcher_4_sse2_ops = {
+       .init_native = fletcher_4_sse2_init,
+       .fini_native = fletcher_4_sse2_fini,
+       .compute_native = fletcher_4_sse2_native,
+       .init_byteswap = fletcher_4_sse2_init,
+       .fini_byteswap = fletcher_4_sse2_fini,
+       .compute_byteswap = fletcher_4_sse2_byteswap,
+       .valid = fletcher_4_sse2_valid,
+       .name = "sse2"
+};
+
+#endif /* defined(HAVE_SSE2) */
+
+#if defined(HAVE_SSE2) && defined(HAVE_SSSE3)
+static void
+fletcher_4_ssse3_byteswap(fletcher_4_ctx_t *ctx, const void *buf, uint64_t size)
+{
+       static const zfs_fletcher_sse_t mask = {
+               .v = { 0x0405060700010203, 0x0C0D0E0F08090A0B }
+       };
+
+       const uint64_t *ip = buf;
+       const uint64_t *ipend = (uint64_t *)((uint8_t *)ip + size);
+
+       kfpu_begin();
+
+       FLETCHER_4_SSE_RESTORE_CTX(ctx);
+
+       asm volatile("movdqu %0, %%xmm7"::"m" (mask));
+       asm volatile("pxor %xmm4, %xmm4");
+
+       for (; ip < ipend; ip += 2) {
+               asm volatile("movdqu %0, %%xmm5"::"m" (*ip));
+               asm volatile("pshufb %xmm7, %xmm5");
+               asm volatile("movdqa %xmm5, %xmm6");
+               asm volatile("punpckldq %xmm4, %xmm5");
+               asm volatile("punpckhdq %xmm4, %xmm6");
+               asm volatile("paddq %xmm5, %xmm0");
+               asm volatile("paddq %xmm0, %xmm1");
+               asm volatile("paddq %xmm1, %xmm2");
+               asm volatile("paddq %xmm2, %xmm3");
+               asm volatile("paddq %xmm6, %xmm0");
+               asm volatile("paddq %xmm0, %xmm1");
+               asm volatile("paddq %xmm1, %xmm2");
+               asm volatile("paddq %xmm2, %xmm3");
+       }
+
+       FLETCHER_4_SSE_SAVE_CTX(ctx);
+
+       kfpu_end();
+}
+
+static boolean_t fletcher_4_ssse3_valid(void)
+{
+       return (zfs_sse2_available() && zfs_ssse3_available());
+}
+
+const fletcher_4_ops_t fletcher_4_ssse3_ops = {
+       .init_native = fletcher_4_sse2_init,
+       .fini_native = fletcher_4_sse2_fini,
+       .compute_native = fletcher_4_sse2_native,
+       .init_byteswap = fletcher_4_sse2_init,
+       .fini_byteswap = fletcher_4_sse2_fini,
+       .compute_byteswap = fletcher_4_ssse3_byteswap,
+       .valid = fletcher_4_ssse3_valid,
+       .name = "ssse3"
+};
+
+#endif /* defined(HAVE_SSE2) && defined(HAVE_SSSE3) */
index ff724be588ccd52c0bfcde73db47950e586a8b0c..b58071bed0557bdde450cf45f34cfa92c943e6a8 100644 (file)
@@ -69,7 +69,7 @@ zfs_component_namecheck(const char *path, namecheck_err_t *why, char *what)
 {
        const char *loc;
 
-       if (strlen(path) >= MAXNAMELEN) {
+       if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
                if (why)
                        *why = NAME_ERR_TOOLONG;
                return (-1);
@@ -140,27 +140,8 @@ dataset_namecheck(const char *path, namecheck_err_t *why, char *what)
 
        /*
         * Make sure the name is not too long.
-        *
-        * ZFS_MAXNAMELEN is the maximum dataset length used in the userland
-        * which is the same as MAXNAMELEN used in the kernel.
-        * If ZFS_MAXNAMELEN value is changed, make sure to cleanup all
-        * places using MAXNAMELEN.
-        *
-        * When HAVE_KOBJ_NAME_LEN is defined the maximum safe kobject name
-        * length is 20 bytes.  This 20 bytes is broken down as follows to
-        * provide a maximum safe <pool>/<dataset>[@snapshot] length of only
-        * 18 bytes.  To ensure bytes are left for <dataset>[@snapshot] the
-        * <pool> portition is futher limited to 9 bytes.  For 2.6.27 and
-        * newer kernels this limit is set to MAXNAMELEN.
-        *
-        *   <pool>/<dataset> + <partition> + <newline>
-        *   (18)             + (1)         + (1)
         */
-#ifdef HAVE_KOBJ_NAME_LEN
-       if (strlen(path) > 18) {
-#else
-       if (strlen(path) >= MAXNAMELEN) {
-#endif /* HAVE_KOBJ_NAME_LEN */
+       if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN) {
                if (why)
                        *why = NAME_ERR_TOOLONG;
                return (-1);
@@ -289,7 +270,7 @@ mountpoint_namecheck(const char *path, namecheck_err_t *why)
                while (*end != '/' && *end != '\0')
                        end++;
 
-               if (end - start >= MAXNAMELEN) {
+               if (end - start >= ZFS_MAX_DATASET_NAME_LEN) {
                        if (why)
                                *why = NAME_ERR_TOOLONG;
                        return (-1);
@@ -314,27 +295,8 @@ pool_namecheck(const char *pool, namecheck_err_t *why, char *what)
 
        /*
         * Make sure the name is not too long.
-        *
-        * ZPOOL_MAXNAMELEN is the maximum pool length used in the userland
-        * which is the same as MAXNAMELEN used in the kernel.
-        * If ZPOOL_MAXNAMELEN value is changed, make sure to cleanup all
-        * places using MAXNAMELEN.
-        *
-        * When HAVE_KOBJ_NAME_LEN is defined the maximum safe kobject name
-        * length is 20 bytes.  This 20 bytes is broken down as follows to
-        * provide a maximum safe <pool>/<dataset>[@snapshot] length of only
-        * 18 bytes.  To ensure bytes are left for <dataset>[@snapshot] the
-        * <pool> portition is futher limited to 8 bytes.  For 2.6.27 and
-        * newer kernels this limit is set to MAXNAMELEN.
-        *
-        *   <pool>/<dataset> + <partition> + <newline>
-        *   (18)             + (1)         + (1)
         */
-#ifdef HAVE_KOBJ_NAME_LEN
-       if (strlen(pool) > 8) {
-#else
-       if (strlen(pool) >= MAXNAMELEN) {
-#endif /* HAVE_KOBJ_NAME_LEN */
+       if (strlen(pool) >= ZFS_MAX_DATASET_NAME_LEN) {
                if (why)
                        *why = NAME_ERR_TOOLONG;
                return (-1);
index aaebab444cfa409432f41117643ddc962415af5e..1802750f946369b610359671d12b203acc19e67f 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "zfs_prop.h"
 #include "zfs_deleg.h"
+#include "zfs_fletcher.h"
 
 #if defined(_KERNEL)
 #include <sys/systm.h>
@@ -51,7 +52,11 @@ const char *zfs_userquota_prop_prefixes[] = {
        "userused@",
        "userquota@",
        "groupused@",
-       "groupquota@"
+       "groupquota@",
+       "userobjused@",
+       "userobjquota@",
+       "groupobjused@",
+       "groupobjquota@"
 };
 
 zprop_desc_t *
@@ -69,6 +74,10 @@ zfs_prop_init(void)
                { "fletcher2",  ZIO_CHECKSUM_FLETCHER_2 },
                { "fletcher4",  ZIO_CHECKSUM_FLETCHER_4 },
                { "sha256",     ZIO_CHECKSUM_SHA256 },
+               { "noparity",   ZIO_CHECKSUM_NOPARITY },
+               { "sha512",     ZIO_CHECKSUM_SHA512 },
+               { "skein",      ZIO_CHECKSUM_SKEIN },
+               { "edonr",      ZIO_CHECKSUM_EDONR },
                { NULL }
        };
 
@@ -79,6 +88,14 @@ zfs_prop_init(void)
                { "sha256",     ZIO_CHECKSUM_SHA256 },
                { "sha256,verify",
                                ZIO_CHECKSUM_SHA256 | ZIO_CHECKSUM_VERIFY },
+               { "sha512",     ZIO_CHECKSUM_SHA512 },
+               { "sha512,verify",
+                               ZIO_CHECKSUM_SHA512 | ZIO_CHECKSUM_VERIFY },
+               { "skein",      ZIO_CHECKSUM_SKEIN },
+               { "skein,verify",
+                               ZIO_CHECKSUM_SKEIN | ZIO_CHECKSUM_VERIFY },
+               { "edonr,verify",
+                               ZIO_CHECKSUM_EDONR | ZIO_CHECKSUM_VERIFY },
                { NULL }
        };
 
@@ -210,6 +227,17 @@ zfs_prop_init(void)
                { NULL }
        };
 
+       static zprop_index_t dnsize_table[] = {
+               { "legacy",     ZFS_DNSIZE_LEGACY },
+               { "auto",       ZFS_DNSIZE_AUTO },
+               { "1k",         ZFS_DNSIZE_1K },
+               { "2k",         ZFS_DNSIZE_2K },
+               { "4k",         ZFS_DNSIZE_4K },
+               { "8k",         ZFS_DNSIZE_8K },
+               { "16k",        ZFS_DNSIZE_16K },
+               { NULL }
+       };
+
        static zprop_index_t redundant_metadata_table[] = {
                { "all",        ZFS_REDUNDANT_METADATA_ALL },
                { "most",       ZFS_REDUNDANT_METADATA_MOST },
@@ -229,12 +257,12 @@ zfs_prop_init(void)
        zprop_register_index(ZFS_PROP_CHECKSUM, "checksum",
            ZIO_CHECKSUM_DEFAULT, PROP_INHERIT, ZFS_TYPE_FILESYSTEM |
            ZFS_TYPE_VOLUME,
-           "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM",
-           checksum_table);
+           "on | off | fletcher2 | fletcher4 | sha256 | sha512 | "
+           "skein | edonr", "CHECKSUM", checksum_table);
        zprop_register_index(ZFS_PROP_DEDUP, "dedup", ZIO_CHECKSUM_OFF,
            PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
-           "on | off | verify | sha256[,verify]", "DEDUP",
-           dedup_table);
+           "on | off | verify | sha256[,verify], sha512[,verify], "
+           "skein[,verify], edonr,verify", "DEDUP", dedup_table);
        zprop_register_index(ZFS_PROP_COMPRESSION, "compression",
            ZIO_COMPRESS_DEFAULT, PROP_INHERIT,
            ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
@@ -270,6 +298,9 @@ zfs_prop_init(void)
        zprop_register_index(ZFS_PROP_XATTR, "xattr", ZFS_XATTR_DIR,
            PROP_INHERIT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
            "on | off | dir | sa", "XATTR", xattr_table);
+       zprop_register_index(ZFS_PROP_DNODESIZE, "dnodesize",
+           ZFS_DNSIZE_LEGACY, PROP_INHERIT, ZFS_TYPE_FILESYSTEM,
+           "legacy | auto | 1k | 2k | 4k | 8k | 16k", "DNSIZE", dnsize_table);
 
        /* inherit index (boolean) properties */
        zprop_register_index(ZFS_PROP_ATIME, "atime", 1, PROP_INHERIT,
@@ -360,6 +391,10 @@ zfs_prop_init(void)
        zprop_register_string(ZFS_PROP_SELINUX_ROOTCONTEXT, "rootcontext",
            "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "<selinux rootcontext>",
            "ROOTCONTEXT");
+       zprop_register_string(ZFS_PROP_RECEIVE_RESUME_TOKEN,
+           "receive_resume_token",
+           NULL, PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+           "<string token>", "RESUMETOK");
 
        /* readonly number properties */
        zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,
@@ -452,6 +487,8 @@ zfs_prop_init(void)
            PROP_READONLY, ZFS_TYPE_DATASET, "OBJSETID");
        zprop_register_hidden(ZFS_PROP_INCONSISTENT, "inconsistent",
            PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET, "INCONSISTENT");
+       zprop_register_hidden(ZFS_PROP_PREV_SNAP, "prevsnap", PROP_TYPE_STRING,
+           PROP_READONLY, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "PREVSNAP");
 
        /*
         * Property to be removed once libbe is integrated
@@ -693,12 +730,14 @@ zfs_prop_align_right(zfs_prop_t prop)
 static int __init
 zcommon_init(void)
 {
+       fletcher_4_init();
        return (0);
 }
 
 static void __exit
 zcommon_fini(void)
 {
+       fletcher_4_fini();
 }
 
 module_init(zcommon_init);
index f78db68e4ea640eafce35504b783b62f622855b9..9ec3002a29e4128998cb825eb3680cef9dc484d6 100644 (file)
@@ -164,7 +164,7 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
        caddr_t p;
        uint8_t tmp;
        int iovcnt;
-       size_t skip = uio->uio_skip;
+       size_t skip;
 
        /* no need to fault in kernel pages */
        switch (uio->uio_segflg) {
@@ -180,9 +180,13 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
 
        iov = uio->uio_iov;
        iovcnt = uio->uio_iovcnt;
+       skip = uio->uio_skip;
 
-       while ((n > 0) && (iovcnt > 0)) {
+       for (; n > 0 && iovcnt > 0; iov++, iovcnt--, skip = 0) {
                cnt = MIN(iov->iov_len - skip, n);
+               /* empty iov */
+               if (cnt == 0)
+                       continue;
                n -= cnt;
                /*
                 * touch each page in this segment.
@@ -201,9 +205,6 @@ uio_prefaultpages(ssize_t n, struct uio *uio)
                p--;
                if (fuword8((uint8_t *) p, &tmp))
                        return;
-               iov++;
-               iovcnt--;
-               skip = 0;
        }
 }
 EXPORT_SYMBOL(uio_prefaultpages);
index 910c56dcc2a9226851e9f877e6aaba2a3d01a6b6..4a5836e5b73905d0544abe685e25f3f7e57ed4e5 100644 (file)
@@ -135,6 +135,8 @@ zpool_prop_init(void)
            PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_POOL, "MAXBLOCKSIZE");
        zprop_register_hidden(ZPOOL_PROP_TNAME, "tname", PROP_TYPE_STRING,
            PROP_ONETIME, ZFS_TYPE_POOL, "TNAME");
+       zprop_register_hidden(ZPOOL_PROP_MAXDNODESIZE, "maxdnodesize",
+           PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_POOL, "MAXDNODESIZE");
 }
 
 /*
index 55f8cef16b6d5cdbb2e15ebee53de263e8de4da3..ce368880cbd363f37be3f3921b97df7ac5acbbbe 100644 (file)
@@ -14,6 +14,7 @@ $(MODULE)-objs += bpobj.o
 $(MODULE)-objs += dbuf.o
 $(MODULE)-objs += dbuf_stats.o
 $(MODULE)-objs += bptree.o
+$(MODULE)-objs += bqueue.o
 $(MODULE)-objs += ddt.o
 $(MODULE)-objs += ddt_zap.o
 $(MODULE)-objs += dmu.o
@@ -35,17 +36,21 @@ $(MODULE)-objs += dsl_pool.o
 $(MODULE)-objs += dsl_prop.o
 $(MODULE)-objs += dsl_scan.o
 $(MODULE)-objs += dsl_synctask.o
+$(MODULE)-objs += edonr_zfs.o
 $(MODULE)-objs += fm.o
 $(MODULE)-objs += gzip.o
 $(MODULE)-objs += lzjb.o
 $(MODULE)-objs += lz4.o
 $(MODULE)-objs += metaslab.o
 $(MODULE)-objs += multilist.o
+$(MODULE)-objs += pathname.o
+$(MODULE)-objs += policy.o
 $(MODULE)-objs += range_tree.o
 $(MODULE)-objs += refcount.o
 $(MODULE)-objs += rrwlock.o
 $(MODULE)-objs += sa.o
 $(MODULE)-objs += sha256.o
+$(MODULE)-objs += skein_zfs.o
 $(MODULE)-objs += spa.o
 $(MODULE)-objs += spa_boot.o
 $(MODULE)-objs += spa_config.o
@@ -68,6 +73,8 @@ $(MODULE)-objs += vdev_mirror.o
 $(MODULE)-objs += vdev_missing.o
 $(MODULE)-objs += vdev_queue.o
 $(MODULE)-objs += vdev_raidz.o
+$(MODULE)-objs += vdev_raidz_math.o
+$(MODULE)-objs += vdev_raidz_math_scalar.o
 $(MODULE)-objs += vdev_root.o
 $(MODULE)-objs += zap.o
 $(MODULE)-objs += zap_leaf.o
@@ -106,3 +113,10 @@ $(MODULE)-objs += zrlock.o
 $(MODULE)-objs += zvol.o
 $(MODULE)-objs += dsl_destroy.o
 $(MODULE)-objs += dsl_userhold.o
+
+$(MODULE)-$(CONFIG_X86) += vdev_raidz_math_sse2.o
+$(MODULE)-$(CONFIG_X86) += vdev_raidz_math_ssse3.o
+$(MODULE)-$(CONFIG_X86) += vdev_raidz_math_avx2.o
+
+$(MODULE)-$(CONFIG_ARM64) += vdev_raidz_math_aarch64_neon.o
+$(MODULE)-$(CONFIG_ARM64) += vdev_raidz_math_aarch64_neonx2.o
index 04fde6c167893130ba737eb1aa7e2e8c66a0ae8d..0c5e66cbeb42c6de4a95c28c6b50c381044dd3aa 100644 (file)
@@ -21,9 +21,9 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2014 by Saso Kiselkov. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
  * A new reference to a cache buffer can be obtained in two
  * ways: 1) via a hash table lookup using the DVA as a key,
  * or 2) via one of the ARC lists.  The arc_read() interface
- * uses method 1, while the internal arc algorithms for
+ * uses method 1, while the internal ARC algorithms for
  * adjusting the cache use method 2.  We therefore provide two
  * types of locks: 1) the hash table lock array, and 2) the
- * arc list locks.
+ * ARC list locks.
  *
  * Buffers do not have their own mutexes, rather they rely on the
  * hash table mutexes for the bulk of their protection (i.e. most
  * buf_hash_remove() expects the appropriate hash mutex to be
  * already held before it is invoked.
  *
- * Each arc state also has a mutex which is used to protect the
+ * Each ARC state also has a mutex which is used to protect the
  * buffer list associated with the state.  When attempting to
- * obtain a hash table lock while holding an arc list lock you
+ * obtain a hash table lock while holding an ARC list lock you
  * must use: mutex_tryenter() to avoid deadlock.  Also note that
  * the active state mutex must be held before the ghost state mutex.
  *
- * Arc buffers may have an associated eviction callback function.
- * This function will be invoked prior to removing the buffer (e.g.
- * in arc_do_user_evicts()).  Note however that the data associated
- * with the buffer may be evicted prior to the callback.  The callback
- * must be made with *no locks held* (to prevent deadlock).  Additionally,
- * the users of callbacks must ensure that their private data is
- * protected from simultaneous callbacks from arc_clear_callback()
- * and arc_do_user_evicts().
- *
  * It as also possible to register a callback which is run when the
  * arc_meta_limit is reached and no buffers can be safely evicted.  In
  * this case the arc user should drop a reference on some arc buffers so
  *     - ARC header release, as it removes from L2ARC buflists
  */
 
+/*
+ * ARC operation:
+ *
+ * Every block that is in the ARC is tracked by an arc_buf_hdr_t structure.
+ * This structure can point either to a block that is still in the cache or to
+ * one that is only accessible in an L2 ARC device, or it can provide
+ * information about a block that was recently evicted. If a block is
+ * only accessible in the L2ARC, then the arc_buf_hdr_t only has enough
+ * information to retrieve it from the L2ARC device. This information is
+ * stored in the l2arc_buf_hdr_t sub-structure of the arc_buf_hdr_t. A block
+ * that is in this state cannot access the data directly.
+ *
+ * Blocks that are actively being referenced or have not been evicted
+ * are cached in the L1ARC. The L1ARC (l1arc_buf_hdr_t) is a structure within
+ * the arc_buf_hdr_t that will point to the data block in memory. A block can
+ * only be read by a consumer if it has an l1arc_buf_hdr_t. The L1ARC
+ * caches data in two ways -- in a list of ARC buffers (arc_buf_t) and
+ * also in the arc_buf_hdr_t's private physical data block pointer (b_pdata).
+ *
+ * The L1ARC's data pointer may or may not be uncompressed. The ARC has the
+ * ability to store the physical data (b_pdata) associated with the DVA of the
+ * arc_buf_hdr_t. Since the b_pdata is a copy of the on-disk physical block,
+ * it will match its on-disk compression characteristics. This behavior can be
+ * disabled by setting 'zfs_compressed_arc_enabled' to B_FALSE. When the
+ * compressed ARC functionality is disabled, the b_pdata will point to an
+ * uncompressed version of the on-disk data.
+ *
+ * Data in the L1ARC is not accessed by consumers of the ARC directly. Each
+ * arc_buf_hdr_t can have multiple ARC buffers (arc_buf_t) which reference it.
+ * Each ARC buffer (arc_buf_t) is being actively accessed by a specific ARC
+ * consumer. The ARC will provide references to this data and will keep it
+ * cached until it is no longer in use. The ARC caches only the L1ARC's physical
+ * data block and will evict any arc_buf_t that is no longer referenced. The
+ * amount of memory consumed by the arc_buf_ts' data buffers can be seen via the
+ * "overhead_size" kstat.
+ *
+ * Depending on the consumer, an arc_buf_t can be requested in uncompressed or
+ * compressed form. The typical case is that consumers will want uncompressed
+ * data, and when that happens a new data buffer is allocated where the data is
+ * decompressed for them to use. Currently the only consumer who wants
+ * compressed arc_buf_t's is "zfs send", when it streams data exactly as it
+ * exists on disk. When this happens, the arc_buf_t's data buffer is shared
+ * with the arc_buf_hdr_t.
+ *
+ * Here is a diagram showing an arc_buf_hdr_t referenced by two arc_buf_t's. The
+ * first one is owned by a compressed send consumer (and therefore references
+ * the same compressed data buffer as the arc_buf_hdr_t) and the second could be
+ * used by any other consumer (and has its own uncompressed copy of the data
+ * buffer).
+ *
+ *   arc_buf_hdr_t
+ *   +-----------+
+ *   | fields    |
+ *   | common to |
+ *   | L1- and   |
+ *   | L2ARC     |
+ *   +-----------+
+ *   | l2arc_buf_hdr_t
+ *   |           |
+ *   +-----------+
+ *   | l1arc_buf_hdr_t
+ *   |           |              arc_buf_t
+ *   | b_buf     +------------>+-----------+      arc_buf_t
+ *   | b_pdata   +-+           |b_next     +---->+-----------+
+ *   +-----------+ |           |-----------|     |b_next     +-->NULL
+ *                 |           |b_comp = T |     +-----------+
+ *                 |           |b_data     +-+   |b_comp = F |
+ *                 |           +-----------+ |   |b_data     +-+
+ *                 +->+------+               |   +-----------+ |
+ *        compressed  |      |               |                 |
+ *           data     |      |<--------------+                 | uncompressed
+ *                    +------+          compressed,            |     data
+ *                                        shared               +-->+------+
+ *                                         data                    |      |
+ *                                                                 |      |
+ *                                                                 +------+
+ *
+ * When a consumer reads a block, the ARC must first look to see if the
+ * arc_buf_hdr_t is cached. If the hdr is cached then the ARC allocates a new
+ * arc_buf_t and either copies uncompressed data into a new data buffer from an
+ * existing uncompressed arc_buf_t, decompresses the hdr's b_pdata buffer into a
+ * new data buffer, or shares the hdr's b_pdata buffer, depending on whether the
+ * hdr is compressed and the desired compression characteristics of the
+ * arc_buf_t consumer. If the arc_buf_t ends up sharing data with the
+ * arc_buf_hdr_t and both of them are uncompressed then the arc_buf_t must be
+ * the last buffer in the hdr's b_buf list, however a shared compressed buf can
+ * be anywhere in the hdr's list.
+ *
+ * The diagram below shows an example of an uncompressed ARC hdr that is
+ * sharing its data with an arc_buf_t (note that the shared uncompressed buf is
+ * the last element in the buf list):
+ *
+ *                arc_buf_hdr_t
+ *                +-----------+
+ *                |           |
+ *                |           |
+ *                |           |
+ *                +-----------+
+ * l2arc_buf_hdr_t|           |
+ *                |           |
+ *                +-----------+
+ * l1arc_buf_hdr_t|           |
+ *                |           |                 arc_buf_t    (shared)
+ *                |    b_buf  +------------>+---------+      arc_buf_t
+ *                |           |             |b_next   +---->+---------+
+ *                |  b_pdata  +-+           |---------|     |b_next   +-->NULL
+ *                +-----------+ |           |         |     +---------+
+ *                              |           |b_data   +-+   |         |
+ *                              |           +---------+ |   |b_data   +-+
+ *                              +->+------+             |   +---------+ |
+ *                                 |      |             |               |
+ *                   uncompressed  |      |             |               |
+ *                        data     +------+             |               |
+ *                                    ^                 +->+------+     |
+ *                                    |       uncompressed |      |     |
+ *                                    |           data     |      |     |
+ *                                    |                    +------+     |
+ *                                    +---------------------------------+
+ *
+ * Writing to the ARC requires that the ARC first discard the hdr's b_pdata
+ * since the physical block is about to be rewritten. The new data contents
+ * will be contained in the arc_buf_t. As the I/O pipeline performs the write,
+ * it may compress the data before writing it to disk. The ARC will be called
+ * with the transformed data and will bcopy the transformed on-disk block into
+ * a newly allocated b_pdata. Writes are always done into buffers which have
+ * either been loaned (and hence are new and don't have other readers) or
+ * buffers which have been released (and hence have their own hdr, if there
+ * were originally other readers of the buf's original hdr). This ensures that
+ * the ARC only needs to update a single buf and its hdr after a write occurs.
+ *
+ * When the L2ARC is in use, it will also take advantage of the b_pdata. The
+ * L2ARC will always write the contents of b_pdata to the L2ARC. This means
+ * that when compressed ARC is enabled that the L2ARC blocks are identical
+ * to the on-disk block in the main data pool. This provides a significant
+ * advantage since the ARC can leverage the bp's checksum when reading from the
+ * L2ARC to determine if the contents are valid. However, if the compressed
+ * ARC is disabled, then the L2ARC's block must be transformed to look
+ * like the physical block in the main data pool before comparing the
+ * checksum and determining its validity.
+ */
+
 #include <sys/spa.h>
 #include <sys/zio.h>
+#include <sys/spa_impl.h>
 #include <sys/zio_compress.h>
+#include <sys/zio_checksum.h>
 #include <sys/zfs_context.h>
 #include <sys/arc.h>
 #include <sys/refcount.h>
@@ -162,10 +296,6 @@ static kcondvar_t  arc_reclaim_thread_cv;
 static boolean_t       arc_reclaim_thread_exit;
 static kcondvar_t      arc_reclaim_waiters_cv;
 
-static kmutex_t                arc_user_evicts_lock;
-static kcondvar_t      arc_user_evicts_cv;
-static boolean_t       arc_user_evicts_thread_exit;
-
 /*
  * The number of headers to evict in arc_evict_state_impl() before
  * dropping the sublist lock and evicting from another sublist. A lower
@@ -224,6 +354,11 @@ static int arc_dead;
  */
 static boolean_t arc_warm;
 
+/*
+ * log2 fraction of the zio arena to keep free.
+ */
+int arc_zio_arena_free_shift = 2;
+
 /*
  * These tunables are for performance analysis.
  */
@@ -231,12 +366,26 @@ unsigned long zfs_arc_max = 0;
 unsigned long zfs_arc_min = 0;
 unsigned long zfs_arc_meta_limit = 0;
 unsigned long zfs_arc_meta_min = 0;
+unsigned long zfs_arc_dnode_limit = 0;
+unsigned long zfs_arc_dnode_reduce_percent = 10;
 int zfs_arc_grow_retry = 0;
 int zfs_arc_shrink_shift = 0;
 int zfs_arc_p_min_shift = 0;
-int zfs_disable_dup_eviction = 0;
 int zfs_arc_average_blocksize = 8 * 1024; /* 8KB */
 
+int zfs_compressed_arc_enabled = B_TRUE;
+
+/*
+ * ARC will evict meta buffers that exceed arc_meta_limit. This
+ * tunable make arc_meta_limit adjustable for different workloads.
+ */
+unsigned long zfs_arc_meta_limit_percent = 75;
+
+/*
+ * Percentage that can be consumed by dnodes of ARC meta buffers.
+ */
+unsigned long zfs_arc_dnode_limit_percent = 10;
+
 /*
  * These tunables are Linux specific
  */
@@ -305,6 +454,26 @@ typedef struct arc_stats {
        kstat_named_t arcstat_c_min;
        kstat_named_t arcstat_c_max;
        kstat_named_t arcstat_size;
+       /*
+        * Number of compressed bytes stored in the arc_buf_hdr_t's b_pdata.
+        * Note that the compressed bytes may match the uncompressed bytes
+        * if the block is either not compressed or compressed arc is disabled.
+        */
+       kstat_named_t arcstat_compressed_size;
+       /*
+        * Uncompressed size of the data stored in b_pdata. If compressed
+        * arc is disabled then this value will be identical to the stat
+        * above.
+        */
+       kstat_named_t arcstat_uncompressed_size;
+       /*
+        * Number of bytes stored in all the arc_buf_t's. This is classified
+        * as "overhead" since this data is typically short-lived and will
+        * be evicted from the arc when it becomes unreferenced unless the
+        * zfs_keep_uncompressed_metadata or zfs_keep_uncompressed_level
+        * values have been set (see comment in dbuf.c for more information).
+        */
+       kstat_named_t arcstat_overhead_size;
        /*
         * Number of bytes consumed by internal ARC structures necessary
         * for tracking purposes; these structures are not actually
@@ -328,13 +497,17 @@ typedef struct arc_stats {
         */
        kstat_named_t arcstat_metadata_size;
        /*
-        * Number of bytes consumed by various buffers and structures
-        * not actually backed with ARC buffers. This includes bonus
-        * buffers (allocated directly via zio_buf_* functions),
-        * dmu_buf_impl_t structures (allocated via dmu_buf_impl_t
-        * cache), and dnode_t structures (allocated via dnode_t cache).
+        * Number of bytes consumed by dmu_buf_impl_t objects.
+        */
+       kstat_named_t arcstat_dbuf_size;
+       /*
+        * Number of bytes consumed by dnode_t objects.
+        */
+       kstat_named_t arcstat_dnode_size;
+       /*
+        * Number of bytes consumed by bonus buffers.
         */
-       kstat_named_t arcstat_other_size;
+       kstat_named_t arcstat_bonus_size;
        /*
         * Total number of bytes consumed by ARC buffers residing in the
         * arc_anon state. This includes *all* buffers in the arc_anon
@@ -450,20 +623,13 @@ typedef struct arc_stats {
        kstat_named_t arcstat_l2_evict_reading;
        kstat_named_t arcstat_l2_evict_l1cached;
        kstat_named_t arcstat_l2_free_on_write;
-       kstat_named_t arcstat_l2_cdata_free_on_write;
        kstat_named_t arcstat_l2_abort_lowmem;
        kstat_named_t arcstat_l2_cksum_bad;
        kstat_named_t arcstat_l2_io_error;
        kstat_named_t arcstat_l2_size;
        kstat_named_t arcstat_l2_asize;
        kstat_named_t arcstat_l2_hdr_size;
-       kstat_named_t arcstat_l2_compress_successes;
-       kstat_named_t arcstat_l2_compress_zeros;
-       kstat_named_t arcstat_l2_compress_failures;
        kstat_named_t arcstat_memory_throttle_count;
-       kstat_named_t arcstat_duplicate_buffers;
-       kstat_named_t arcstat_duplicate_buffers_size;
-       kstat_named_t arcstat_duplicate_reads;
        kstat_named_t arcstat_memory_direct_count;
        kstat_named_t arcstat_memory_indirect_count;
        kstat_named_t arcstat_no_grow;
@@ -472,8 +638,11 @@ typedef struct arc_stats {
        kstat_named_t arcstat_prune;
        kstat_named_t arcstat_meta_used;
        kstat_named_t arcstat_meta_limit;
+       kstat_named_t arcstat_dnode_limit;
        kstat_named_t arcstat_meta_max;
        kstat_named_t arcstat_meta_min;
+       kstat_named_t arcstat_sync_wait_for_async;
+       kstat_named_t arcstat_demand_hit_predictive_prefetch;
        kstat_named_t arcstat_need_free;
        kstat_named_t arcstat_sys_free;
 } arc_stats_t;
@@ -511,10 +680,15 @@ static arc_stats_t arc_stats = {
        { "c_min",                      KSTAT_DATA_UINT64 },
        { "c_max",                      KSTAT_DATA_UINT64 },
        { "size",                       KSTAT_DATA_UINT64 },
+       { "compressed_size",            KSTAT_DATA_UINT64 },
+       { "uncompressed_size",          KSTAT_DATA_UINT64 },
+       { "overhead_size",              KSTAT_DATA_UINT64 },
        { "hdr_size",                   KSTAT_DATA_UINT64 },
        { "data_size",                  KSTAT_DATA_UINT64 },
        { "metadata_size",              KSTAT_DATA_UINT64 },
-       { "other_size",                 KSTAT_DATA_UINT64 },
+       { "dbuf_size",                  KSTAT_DATA_UINT64 },
+       { "dnode_size",                 KSTAT_DATA_UINT64 },
+       { "bonus_size",                 KSTAT_DATA_UINT64 },
        { "anon_size",                  KSTAT_DATA_UINT64 },
        { "anon_evictable_data",        KSTAT_DATA_UINT64 },
        { "anon_evictable_metadata",    KSTAT_DATA_UINT64 },
@@ -544,20 +718,13 @@ static arc_stats_t arc_stats = {
        { "l2_evict_reading",           KSTAT_DATA_UINT64 },
        { "l2_evict_l1cached",          KSTAT_DATA_UINT64 },
        { "l2_free_on_write",           KSTAT_DATA_UINT64 },
-       { "l2_cdata_free_on_write",     KSTAT_DATA_UINT64 },
        { "l2_abort_lowmem",            KSTAT_DATA_UINT64 },
        { "l2_cksum_bad",               KSTAT_DATA_UINT64 },
        { "l2_io_error",                KSTAT_DATA_UINT64 },
        { "l2_size",                    KSTAT_DATA_UINT64 },
        { "l2_asize",                   KSTAT_DATA_UINT64 },
        { "l2_hdr_size",                KSTAT_DATA_UINT64 },
-       { "l2_compress_successes",      KSTAT_DATA_UINT64 },
-       { "l2_compress_zeros",          KSTAT_DATA_UINT64 },
-       { "l2_compress_failures",       KSTAT_DATA_UINT64 },
        { "memory_throttle_count",      KSTAT_DATA_UINT64 },
-       { "duplicate_buffers",          KSTAT_DATA_UINT64 },
-       { "duplicate_buffers_size",     KSTAT_DATA_UINT64 },
-       { "duplicate_reads",            KSTAT_DATA_UINT64 },
        { "memory_direct_count",        KSTAT_DATA_UINT64 },
        { "memory_indirect_count",      KSTAT_DATA_UINT64 },
        { "arc_no_grow",                KSTAT_DATA_UINT64 },
@@ -566,8 +733,11 @@ static arc_stats_t arc_stats = {
        { "arc_prune",                  KSTAT_DATA_UINT64 },
        { "arc_meta_used",              KSTAT_DATA_UINT64 },
        { "arc_meta_limit",             KSTAT_DATA_UINT64 },
+       { "arc_dnode_limit",            KSTAT_DATA_UINT64 },
        { "arc_meta_max",               KSTAT_DATA_UINT64 },
        { "arc_meta_min",               KSTAT_DATA_UINT64 },
+       { "sync_wait_for_async",        KSTAT_DATA_UINT64 },
+       { "demand_hit_predictive_prefetch", KSTAT_DATA_UINT64 },
        { "arc_need_free",              KSTAT_DATA_UINT64 },
        { "arc_sys_free",               KSTAT_DATA_UINT64 }
 };
@@ -631,24 +801,30 @@ static arc_state_t        *arc_l2c_only;
 #define        arc_c           ARCSTAT(arcstat_c)      /* target size of cache */
 #define        arc_c_min       ARCSTAT(arcstat_c_min)  /* min target cache size */
 #define        arc_c_max       ARCSTAT(arcstat_c_max)  /* max target cache size */
-#define        arc_no_grow     ARCSTAT(arcstat_no_grow)
+#define        arc_no_grow     ARCSTAT(arcstat_no_grow) /* do not grow cache size */
 #define        arc_tempreserve ARCSTAT(arcstat_tempreserve)
 #define        arc_loaned_bytes        ARCSTAT(arcstat_loaned_bytes)
 #define        arc_meta_limit  ARCSTAT(arcstat_meta_limit) /* max size for metadata */
+#define        arc_dnode_limit ARCSTAT(arcstat_dnode_limit) /* max size for dnodes */
 #define        arc_meta_min    ARCSTAT(arcstat_meta_min) /* min size for metadata */
 #define        arc_meta_used   ARCSTAT(arcstat_meta_used) /* size of metadata */
 #define        arc_meta_max    ARCSTAT(arcstat_meta_max) /* max size of metadata */
+#define        arc_dbuf_size   ARCSTAT(arcstat_dbuf_size) /* dbuf metadata */
+#define        arc_dnode_size  ARCSTAT(arcstat_dnode_size) /* dnode metadata */
+#define        arc_bonus_size  ARCSTAT(arcstat_bonus_size) /* bonus buffer metadata */
 #define        arc_need_free   ARCSTAT(arcstat_need_free) /* bytes to be freed */
 #define        arc_sys_free    ARCSTAT(arcstat_sys_free) /* target system free bytes */
 
-#define        L2ARC_IS_VALID_COMPRESS(_c_) \
-       ((_c_) == ZIO_COMPRESS_LZ4 || (_c_) == ZIO_COMPRESS_EMPTY)
+/* compressed size of entire arc */
+#define        arc_compressed_size     ARCSTAT(arcstat_compressed_size)
+/* uncompressed size of entire arc */
+#define        arc_uncompressed_size   ARCSTAT(arcstat_uncompressed_size)
+/* number of bytes in the arc from arc_buf_t's */
+#define        arc_overhead_size       ARCSTAT(arcstat_overhead_size)
 
 static list_t arc_prune_list;
 static kmutex_t arc_prune_mtx;
 static taskq_t *arc_prune_taskq;
-static arc_buf_t *arc_eviction_list;
-static arc_buf_hdr_t arc_eviction_hdr;
 
 #define        GHOST_STATE(state)      \
        ((state) == arc_mru_ghost || (state) == arc_mfu_ghost ||        \
@@ -658,25 +834,37 @@ static arc_buf_hdr_t arc_eviction_hdr;
 #define        HDR_IO_IN_PROGRESS(hdr) ((hdr)->b_flags & ARC_FLAG_IO_IN_PROGRESS)
 #define        HDR_IO_ERROR(hdr)       ((hdr)->b_flags & ARC_FLAG_IO_ERROR)
 #define        HDR_PREFETCH(hdr)       ((hdr)->b_flags & ARC_FLAG_PREFETCH)
-#define        HDR_FREED_IN_READ(hdr)  ((hdr)->b_flags & ARC_FLAG_FREED_IN_READ)
-#define        HDR_BUF_AVAILABLE(hdr)  ((hdr)->b_flags & ARC_FLAG_BUF_AVAILABLE)
+#define        HDR_COMPRESSION_ENABLED(hdr)    \
+       ((hdr)->b_flags & ARC_FLAG_COMPRESSED_ARC)
 
 #define        HDR_L2CACHE(hdr)        ((hdr)->b_flags & ARC_FLAG_L2CACHE)
-#define        HDR_L2COMPRESS(hdr)     ((hdr)->b_flags & ARC_FLAG_L2COMPRESS)
 #define        HDR_L2_READING(hdr)     \
-           (((hdr)->b_flags & ARC_FLAG_IO_IN_PROGRESS) &&      \
-           ((hdr)->b_flags & ARC_FLAG_HAS_L2HDR))
+       (((hdr)->b_flags & ARC_FLAG_IO_IN_PROGRESS) &&  \
+       ((hdr)->b_flags & ARC_FLAG_HAS_L2HDR))
 #define        HDR_L2_WRITING(hdr)     ((hdr)->b_flags & ARC_FLAG_L2_WRITING)
 #define        HDR_L2_EVICTED(hdr)     ((hdr)->b_flags & ARC_FLAG_L2_EVICTED)
 #define        HDR_L2_WRITE_HEAD(hdr)  ((hdr)->b_flags & ARC_FLAG_L2_WRITE_HEAD)
+#define        HDR_SHARED_DATA(hdr)    ((hdr)->b_flags & ARC_FLAG_SHARED_DATA)
 
 #define        HDR_ISTYPE_METADATA(hdr)        \
-           ((hdr)->b_flags & ARC_FLAG_BUFC_METADATA)
+       ((hdr)->b_flags & ARC_FLAG_BUFC_METADATA)
 #define        HDR_ISTYPE_DATA(hdr)    (!HDR_ISTYPE_METADATA(hdr))
 
 #define        HDR_HAS_L1HDR(hdr)      ((hdr)->b_flags & ARC_FLAG_HAS_L1HDR)
 #define        HDR_HAS_L2HDR(hdr)      ((hdr)->b_flags & ARC_FLAG_HAS_L2HDR)
 
+/* For storing compression mode in b_flags */
+#define        HDR_COMPRESS_OFFSET     (highbit64(ARC_FLAG_COMPRESS_0) - 1)
+
+#define        HDR_GET_COMPRESS(hdr)   ((enum zio_compress)BF32_GET((hdr)->b_flags, \
+       HDR_COMPRESS_OFFSET, SPA_COMPRESSBITS))
+#define        HDR_SET_COMPRESS(hdr, cmp) BF32_SET((hdr)->b_flags, \
+       HDR_COMPRESS_OFFSET, SPA_COMPRESSBITS, (cmp));
+
+#define        ARC_BUF_LAST(buf)       ((buf)->b_next == NULL)
+#define        ARC_BUF_SHARED(buf)     ((buf)->b_flags & ARC_BUF_FLAG_SHARED)
+#define        ARC_BUF_COMPRESSED(buf) ((buf)->b_flags & ARC_BUF_FLAG_COMPRESSED)
+
 /*
  * Other sizes
  */
@@ -722,6 +910,7 @@ uint64_t zfs_crc64_table[256];
 
 #define        L2ARC_WRITE_SIZE        (8 * 1024 * 1024)       /* initial write max */
 #define        L2ARC_HEADROOM          2                       /* num of writes */
+
 /*
  * If we discover during ARC scan any buffers to be compressed, we boost
  * our headroom for the next scanning cycle by this percentage multiple.
@@ -730,16 +919,6 @@ uint64_t zfs_crc64_table[256];
 #define        L2ARC_FEED_SECS         1               /* caching interval secs */
 #define        L2ARC_FEED_MIN_MS       200             /* min caching interval ms */
 
-/*
- * Used to distinguish headers that are being process by
- * l2arc_write_buffers(), but have yet to be assigned to a l2arc disk
- * address. This can happen when the header is added to the l2arc's list
- * of buffers to write in the first stage of l2arc_write_buffers(), but
- * has not yet been written out which happens in the second stage of
- * l2arc_write_buffers().
- */
-#define        L2ARC_ADDR_UNSET        ((uint64_t)(-1))
-
 #define        l2arc_writes_sent       ARCSTAT(arcstat_l2_writes_sent)
 #define        l2arc_writes_done       ARCSTAT(arcstat_l2_writes_done)
 
@@ -751,7 +930,6 @@ unsigned long l2arc_headroom_boost = L2ARC_HEADROOM_BOOST;
 unsigned long l2arc_feed_secs = L2ARC_FEED_SECS;       /* interval seconds */
 unsigned long l2arc_feed_min_ms = L2ARC_FEED_MIN_MS;   /* min interval msecs */
 int l2arc_noprefetch = B_TRUE;                 /* don't cache prefetch bufs */
-int l2arc_nocompress = B_FALSE;                        /* don't compress bufs */
 int l2arc_feed_again = B_TRUE;                 /* turbo warmup */
 int l2arc_norw = B_FALSE;                      /* no reads during writes */
 
@@ -768,19 +946,17 @@ static kmutex_t l2arc_free_on_write_mtx;  /* mutex for list */
 static uint64_t l2arc_ndev;                    /* number of devices */
 
 typedef struct l2arc_read_callback {
-       arc_buf_t               *l2rcb_buf;             /* read buffer */
-       spa_t                   *l2rcb_spa;             /* spa */
+       arc_buf_hdr_t           *l2rcb_hdr;             /* read header */
        blkptr_t                l2rcb_bp;               /* original blkptr */
        zbookmark_phys_t        l2rcb_zb;               /* original bookmark */
        int                     l2rcb_flags;            /* original flags */
-       enum zio_compress       l2rcb_compress;         /* applied compress */
 } l2arc_read_callback_t;
 
 typedef struct l2arc_data_free {
        /* protected by l2arc_free_on_write_mtx */
        void            *l2df_data;
        size_t          l2df_size;
-       void            (*l2df_func)(void *, size_t);
+       arc_buf_contents_t l2df_type;
        list_node_t     l2df_list_node;
 } l2arc_data_free_t;
 
@@ -788,22 +964,24 @@ static kmutex_t l2arc_feed_thr_lock;
 static kcondvar_t l2arc_feed_thr_cv;
 static uint8_t l2arc_thread_exit;
 
-static void arc_get_data_buf(arc_buf_t *);
+static void *arc_get_data_buf(arc_buf_hdr_t *, uint64_t, void *);
+static void arc_free_data_buf(arc_buf_hdr_t *, void *, uint64_t, void *);
+static void arc_hdr_free_pdata(arc_buf_hdr_t *hdr);
+static void arc_hdr_alloc_pdata(arc_buf_hdr_t *);
 static void arc_access(arc_buf_hdr_t *, kmutex_t *);
 static boolean_t arc_is_overflowing(void);
 static void arc_buf_watch(arc_buf_t *);
 static void arc_tuning_update(void);
+static void arc_prune_async(int64_t);
 
 static arc_buf_contents_t arc_buf_type(arc_buf_hdr_t *);
 static uint32_t arc_bufc_to_flags(arc_buf_contents_t);
+static inline void arc_hdr_set_flags(arc_buf_hdr_t *hdr, arc_flags_t flags);
+static inline void arc_hdr_clear_flags(arc_buf_hdr_t *hdr, arc_flags_t flags);
 
 static boolean_t l2arc_write_eligible(uint64_t, arc_buf_hdr_t *);
 static void l2arc_read_done(zio_t *);
 
-static boolean_t l2arc_compress_buf(arc_buf_hdr_t *);
-static void l2arc_decompress_zio(zio_t *, arc_buf_hdr_t *, enum zio_compress);
-static void l2arc_release_cdata_buf(arc_buf_hdr_t *);
-
 static uint64_t
 buf_hash(uint64_t spa, const dva_t *dva, uint64_t birth)
 {
@@ -821,14 +999,14 @@ buf_hash(uint64_t spa, const dva_t *dva, uint64_t birth)
        return (crc);
 }
 
-#define        BUF_EMPTY(buf)                                          \
-       ((buf)->b_dva.dva_word[0] == 0 &&                       \
-       (buf)->b_dva.dva_word[1] == 0)
+#define        HDR_EMPTY(hdr)                                          \
+       ((hdr)->b_dva.dva_word[0] == 0 &&                       \
+       (hdr)->b_dva.dva_word[1] == 0)
 
-#define        BUF_EQUAL(spa, dva, birth, buf)                         \
-       ((buf)->b_dva.dva_word[0] == (dva)->dva_word[0]) &&     \
-       ((buf)->b_dva.dva_word[1] == (dva)->dva_word[1]) &&     \
-       ((buf)->b_birth == birth) && ((buf)->b_spa == spa)
+#define        HDR_EQUAL(spa, dva, birth, hdr)                         \
+       ((hdr)->b_dva.dva_word[0] == (dva)->dva_word[0]) &&     \
+       ((hdr)->b_dva.dva_word[1] == (dva)->dva_word[1]) &&     \
+       ((hdr)->b_birth == birth) && ((hdr)->b_spa == spa)
 
 static void
 buf_discard_identity(arc_buf_hdr_t *hdr)
@@ -850,7 +1028,7 @@ buf_hash_find(uint64_t spa, const blkptr_t *bp, kmutex_t **lockp)
        mutex_enter(hash_lock);
        for (hdr = buf_hash_table.ht_table[idx]; hdr != NULL;
            hdr = hdr->b_hash_next) {
-               if (BUF_EQUAL(spa, dva, birth, hdr)) {
+               if (HDR_EQUAL(spa, dva, birth, hdr)) {
                        *lockp = hash_lock;
                        return (hdr);
                }
@@ -888,13 +1066,13 @@ buf_hash_insert(arc_buf_hdr_t *hdr, kmutex_t **lockp)
 
        for (fhdr = buf_hash_table.ht_table[idx], i = 0; fhdr != NULL;
            fhdr = fhdr->b_hash_next, i++) {
-               if (BUF_EQUAL(hdr->b_spa, &hdr->b_dva, hdr->b_birth, fhdr))
+               if (HDR_EQUAL(hdr->b_spa, &hdr->b_dva, hdr->b_birth, fhdr))
                        return (fhdr);
        }
 
        hdr->b_hash_next = buf_hash_table.ht_table[idx];
        buf_hash_table.ht_table[idx] = hdr;
-       hdr->b_flags |= ARC_FLAG_IN_HASH_TABLE;
+       arc_hdr_set_flags(hdr, ARC_FLAG_IN_HASH_TABLE);
 
        /* collect some hash table performance data */
        if (i > 0) {
@@ -922,12 +1100,12 @@ buf_hash_remove(arc_buf_hdr_t *hdr)
 
        hdrp = &buf_hash_table.ht_table[idx];
        while ((fhdr = *hdrp) != hdr) {
-               ASSERT(fhdr != NULL);
+               ASSERT3P(fhdr, !=, NULL);
                hdrp = &fhdr->b_hash_next;
        }
        *hdrp = hdr->b_hash_next;
        hdr->b_hash_next = NULL;
-       hdr->b_flags &= ~ARC_FLAG_IN_HASH_TABLE;
+       arc_hdr_clear_flags(hdr, ARC_FLAG_IN_HASH_TABLE);
 
        /* collect some hash table performance data */
        ARCSTAT_BUMPDOWN(arcstat_hash_elements);
@@ -1024,7 +1202,7 @@ hdr_full_dest(void *vbuf, void *unused)
 {
        arc_buf_hdr_t *hdr = vbuf;
 
-       ASSERT(BUF_EMPTY(hdr));
+       ASSERT(HDR_EMPTY(hdr));
        cv_destroy(&hdr->b_l1hdr.b_cv);
        refcount_destroy(&hdr->b_l1hdr.b_refcnt);
        mutex_destroy(&hdr->b_l1hdr.b_freeze_lock);
@@ -1038,7 +1216,7 @@ hdr_l2only_dest(void *vbuf, void *unused)
 {
        ASSERTV(arc_buf_hdr_t *hdr = vbuf);
 
-       ASSERT(BUF_EMPTY(hdr));
+       ASSERT(HDR_EMPTY(hdr));
        arc_space_return(HDR_L2ONLY_SIZE, ARC_SPACE_L2HDRS);
 }
 
@@ -1071,7 +1249,7 @@ hdr_recl(void *unused)
 static void
 buf_init(void)
 {
-       uint64_t *ct;
+       uint64_t *ct = NULL;
        uint64_t hsize = 1ULL << 12;
        int i, j;
 
@@ -1120,159 +1298,206 @@ retry:
        }
 }
 
+#define        ARC_MINTIME     (hz>>4) /* 62 ms */
+
 /*
- * Transition between the two allocation states for the arc_buf_hdr struct.
- * The arc_buf_hdr struct can be allocated with (hdr_full_cache) or without
- * (hdr_l2only_cache) the fields necessary for the L1 cache - the smaller
- * version is used when a cache buffer is only in the L2ARC in order to reduce
- * memory usage.
+ * This is the size that the buf occupies in memory. If the buf is compressed,
+ * it will correspond to the compressed size. You should use this method of
+ * getting the buf size unless you explicitly need the logical size.
  */
-static arc_buf_hdr_t *
-arc_hdr_realloc(arc_buf_hdr_t *hdr, kmem_cache_t *old, kmem_cache_t *new)
+uint64_t
+arc_buf_size(arc_buf_t *buf)
 {
-       arc_buf_hdr_t *nhdr;
-       l2arc_dev_t *dev;
-
-       ASSERT(HDR_HAS_L2HDR(hdr));
-       ASSERT((old == hdr_full_cache && new == hdr_l2only_cache) ||
-           (old == hdr_l2only_cache && new == hdr_full_cache));
-
-       dev = hdr->b_l2hdr.b_dev;
-       nhdr = kmem_cache_alloc(new, KM_PUSHPAGE);
-
-       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)));
-       buf_hash_remove(hdr);
-
-       bcopy(hdr, nhdr, HDR_L2ONLY_SIZE);
-
-       if (new == hdr_full_cache) {
-               nhdr->b_flags |= ARC_FLAG_HAS_L1HDR;
-               /*
-                * arc_access and arc_change_state need to be aware that a
-                * header has just come out of L2ARC, so we set its state to
-                * l2c_only even though it's about to change.
-                */
-               nhdr->b_l1hdr.b_state = arc_l2c_only;
-
-               /* Verify previous threads set to NULL before freeing */
-               ASSERT3P(nhdr->b_l1hdr.b_tmp_cdata, ==, NULL);
-       } else {
-               ASSERT(hdr->b_l1hdr.b_buf == NULL);
-               ASSERT0(hdr->b_l1hdr.b_datacnt);
-
-               /*
-                * If we've reached here, We must have been called from
-                * arc_evict_hdr(), as such we should have already been
-                * removed from any ghost list we were previously on
-                * (which protects us from racing with arc_evict_state),
-                * thus no locking is needed during this check.
-                */
-               ASSERT(!multilist_link_active(&hdr->b_l1hdr.b_arc_node));
-
-               /*
-                * A buffer must not be moved into the arc_l2c_only
-                * state if it's not finished being written out to the
-                * l2arc device. Otherwise, the b_l1hdr.b_tmp_cdata field
-                * might try to be accessed, even though it was removed.
-                */
-               VERIFY(!HDR_L2_WRITING(hdr));
-               VERIFY3P(hdr->b_l1hdr.b_tmp_cdata, ==, NULL);
-
-               nhdr->b_flags &= ~ARC_FLAG_HAS_L1HDR;
-       }
-       /*
-        * The header has been reallocated so we need to re-insert it into any
-        * lists it was on.
-        */
-       (void) buf_hash_insert(nhdr, NULL);
-
-       ASSERT(list_link_active(&hdr->b_l2hdr.b_l2node));
+       return (ARC_BUF_COMPRESSED(buf) ?
+           HDR_GET_PSIZE(buf->b_hdr) : HDR_GET_LSIZE(buf->b_hdr));
+}
 
-       mutex_enter(&dev->l2ad_mtx);
+uint64_t
+arc_buf_lsize(arc_buf_t *buf)
+{
+       return (HDR_GET_LSIZE(buf->b_hdr));
+}
 
-       /*
-        * We must place the realloc'ed header back into the list at
-        * the same spot. Otherwise, if it's placed earlier in the list,
-        * l2arc_write_buffers() could find it during the function's
-        * write phase, and try to write it out to the l2arc.
-        */
-       list_insert_after(&dev->l2ad_buflist, hdr, nhdr);
-       list_remove(&dev->l2ad_buflist, hdr);
+enum zio_compress
+arc_get_compression(arc_buf_t *buf)
+{
+       return (ARC_BUF_COMPRESSED(buf) ?
+           HDR_GET_COMPRESS(buf->b_hdr) : ZIO_COMPRESS_OFF);
+}
 
-       mutex_exit(&dev->l2ad_mtx);
+static inline boolean_t
+arc_buf_is_shared(arc_buf_t *buf)
+{
+       boolean_t shared = (buf->b_data != NULL &&
+           buf->b_data == buf->b_hdr->b_l1hdr.b_pdata);
+       IMPLY(shared, HDR_SHARED_DATA(buf->b_hdr));
+       IMPLY(shared, ARC_BUF_SHARED(buf));
+       IMPLY(shared, ARC_BUF_COMPRESSED(buf) || ARC_BUF_LAST(buf));
 
        /*
-        * Since we're using the pointer address as the tag when
-        * incrementing and decrementing the l2ad_alloc refcount, we
-        * must remove the old pointer (that we're about to destroy) and
-        * add the new pointer to the refcount. Otherwise we'd remove
-        * the wrong pointer address when calling arc_hdr_destroy() later.
+        * It would be nice to assert arc_can_share() too, but the "hdr isn't
+        * already being shared" requirement prevents us from doing that.
         */
 
-       (void) refcount_remove_many(&dev->l2ad_alloc,
-           hdr->b_l2hdr.b_asize, hdr);
-
-       (void) refcount_add_many(&dev->l2ad_alloc,
-           nhdr->b_l2hdr.b_asize, nhdr);
-
-       buf_discard_identity(hdr);
-       hdr->b_freeze_cksum = NULL;
-       kmem_cache_free(old, hdr);
-
-       return (nhdr);
+       return (shared);
 }
 
+static inline void
+arc_cksum_free(arc_buf_hdr_t *hdr)
+{
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       mutex_enter(&hdr->b_l1hdr.b_freeze_lock);
+       if (hdr->b_l1hdr.b_freeze_cksum != NULL) {
+               kmem_free(hdr->b_l1hdr.b_freeze_cksum, sizeof (zio_cksum_t));
+               hdr->b_l1hdr.b_freeze_cksum = NULL;
+       }
+       mutex_exit(&hdr->b_l1hdr.b_freeze_lock);
+}
 
-#define        ARC_MINTIME     (hz>>4) /* 62 ms */
-
+/*
+ * If we've turned on the ZFS_DEBUG_MODIFY flag, verify that the buf's data
+ * matches the checksum that is stored in the hdr. If there is no checksum,
+ * or if the buf is compressed, this is a no-op.
+ */
 static void
 arc_cksum_verify(arc_buf_t *buf)
 {
+       arc_buf_hdr_t *hdr = buf->b_hdr;
        zio_cksum_t zc;
 
        if (!(zfs_flags & ZFS_DEBUG_MODIFY))
                return;
 
-       mutex_enter(&buf->b_hdr->b_l1hdr.b_freeze_lock);
-       if (buf->b_hdr->b_freeze_cksum == NULL || HDR_IO_ERROR(buf->b_hdr)) {
-               mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock);
+       if (ARC_BUF_COMPRESSED(buf)) {
+               ASSERT(hdr->b_l1hdr.b_freeze_cksum == NULL ||
+                   hdr->b_l1hdr.b_bufcnt > 1);
+               return;
+       }
+
+       ASSERT(HDR_HAS_L1HDR(hdr));
+
+       mutex_enter(&hdr->b_l1hdr.b_freeze_lock);
+       if (hdr->b_l1hdr.b_freeze_cksum == NULL || HDR_IO_ERROR(hdr)) {
+               mutex_exit(&hdr->b_l1hdr.b_freeze_lock);
                return;
        }
-       fletcher_2_native(buf->b_data, buf->b_hdr->b_size, &zc);
-       if (!ZIO_CHECKSUM_EQUAL(*buf->b_hdr->b_freeze_cksum, zc))
+
+       fletcher_2_native(buf->b_data, arc_buf_size(buf), NULL, &zc);
+       if (!ZIO_CHECKSUM_EQUAL(*hdr->b_l1hdr.b_freeze_cksum, zc))
                panic("buffer modified while frozen!");
-       mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock);
+       mutex_exit(&hdr->b_l1hdr.b_freeze_lock);
 }
 
-static int
-arc_cksum_equal(arc_buf_t *buf)
+static boolean_t
+arc_cksum_is_equal(arc_buf_hdr_t *hdr, zio_t *zio)
 {
-       zio_cksum_t zc;
-       int equal;
+       enum zio_compress compress = BP_GET_COMPRESS(zio->io_bp);
+       boolean_t valid_cksum;
 
-       mutex_enter(&buf->b_hdr->b_l1hdr.b_freeze_lock);
-       fletcher_2_native(buf->b_data, buf->b_hdr->b_size, &zc);
-       equal = ZIO_CHECKSUM_EQUAL(*buf->b_hdr->b_freeze_cksum, zc);
-       mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock);
+       ASSERT(!BP_IS_EMBEDDED(zio->io_bp));
+       VERIFY3U(BP_GET_PSIZE(zio->io_bp), ==, HDR_GET_PSIZE(hdr));
+
+       /*
+        * We rely on the blkptr's checksum to determine if the block
+        * is valid or not. When compressed arc is enabled, the l2arc
+        * writes the block to the l2arc just as it appears in the pool.
+        * This allows us to use the blkptr's checksum to validate the
+        * data that we just read off of the l2arc without having to store
+        * a separate checksum in the arc_buf_hdr_t. However, if compressed
+        * arc is disabled, then the data written to the l2arc is always
+        * uncompressed and won't match the block as it exists in the main
+        * pool. When this is the case, we must first compress it if it is
+        * compressed on the main pool before we can validate the checksum.
+        */
+       if (!HDR_COMPRESSION_ENABLED(hdr) && compress != ZIO_COMPRESS_OFF) {
+               uint64_t lsize;
+               uint64_t csize;
+               void *cbuf;
+               ASSERT3U(HDR_GET_COMPRESS(hdr), ==, ZIO_COMPRESS_OFF);
+
+               cbuf = zio_buf_alloc(HDR_GET_PSIZE(hdr));
+               lsize = HDR_GET_LSIZE(hdr);
+               csize = zio_compress_data(compress, zio->io_data, cbuf, lsize);
+               ASSERT3U(csize, <=, HDR_GET_PSIZE(hdr));
+               if (csize < HDR_GET_PSIZE(hdr)) {
+                       /*
+                        * Compressed blocks are always a multiple of the
+                        * smallest ashift in the pool. Ideally, we would
+                        * like to round up the csize to the next
+                        * spa_min_ashift but that value may have changed
+                        * since the block was last written. Instead,
+                        * we rely on the fact that the hdr's psize
+                        * was set to the psize of the block when it was
+                        * last written. We set the csize to that value
+                        * and zero out any part that should not contain
+                        * data.
+                        */
+                       bzero((char *)cbuf + csize, HDR_GET_PSIZE(hdr) - csize);
+                       csize = HDR_GET_PSIZE(hdr);
+               }
+               zio_push_transform(zio, cbuf, csize, HDR_GET_PSIZE(hdr), NULL);
+       }
 
-       return (equal);
+       /*
+        * Block pointers always store the checksum for the logical data.
+        * If the block pointer has the gang bit set, then the checksum
+        * it represents is for the reconstituted data and not for an
+        * individual gang member. The zio pipeline, however, must be able to
+        * determine the checksum of each of the gang constituents so it
+        * treats the checksum comparison differently than what we need
+        * for l2arc blocks. This prevents us from using the
+        * zio_checksum_error() interface directly. Instead we must call the
+        * zio_checksum_error_impl() so that we can ensure the checksum is
+        * generated using the correct checksum algorithm and accounts for the
+        * logical I/O size and not just a gang fragment.
+        */
+       valid_cksum = (zio_checksum_error_impl(zio->io_spa, zio->io_bp,
+           BP_GET_CHECKSUM(zio->io_bp), zio->io_data, zio->io_size,
+           zio->io_offset, NULL) == 0);
+       zio_pop_transforms(zio);
+       return (valid_cksum);
 }
 
+/*
+ * Given a buf full of data, if ZFS_DEBUG_MODIFY is enabled this computes a
+ * checksum and attaches it to the buf's hdr so that we can ensure that the buf
+ * isn't modified later on. If buf is compressed or there is already a checksum
+ * on the hdr, this is a no-op (we only checksum uncompressed bufs).
+ */
 static void
-arc_cksum_compute(arc_buf_t *buf, boolean_t force)
+arc_cksum_compute(arc_buf_t *buf)
 {
-       if (!force && !(zfs_flags & ZFS_DEBUG_MODIFY))
+       arc_buf_hdr_t *hdr = buf->b_hdr;
+
+       if (!(zfs_flags & ZFS_DEBUG_MODIFY))
                return;
 
+       ASSERT(HDR_HAS_L1HDR(hdr));
+
        mutex_enter(&buf->b_hdr->b_l1hdr.b_freeze_lock);
-       if (buf->b_hdr->b_freeze_cksum != NULL) {
-               mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock);
+       if (hdr->b_l1hdr.b_freeze_cksum != NULL) {
+               ASSERT(!ARC_BUF_COMPRESSED(buf) || hdr->b_l1hdr.b_bufcnt > 1);
+               mutex_exit(&hdr->b_l1hdr.b_freeze_lock);
+               return;
+       } else if (ARC_BUF_COMPRESSED(buf)) {
+               /*
+                * Since the checksum doesn't apply to compressed buffers, we
+                * only keep a checksum if there are uncompressed buffers.
+                * Therefore there must be another buffer, which is
+                * uncompressed.
+                */
+               IMPLY(hdr->b_l1hdr.b_freeze_cksum != NULL,
+                   hdr->b_l1hdr.b_bufcnt > 1);
+               mutex_exit(&hdr->b_l1hdr.b_freeze_lock);
                return;
        }
-       buf->b_hdr->b_freeze_cksum = kmem_alloc(sizeof (zio_cksum_t), KM_SLEEP);
-       fletcher_2_native(buf->b_data, buf->b_hdr->b_size,
-           buf->b_hdr->b_freeze_cksum);
-       mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock);
+
+       ASSERT(!ARC_BUF_COMPRESSED(buf));
+       hdr->b_l1hdr.b_freeze_cksum = kmem_alloc(sizeof (zio_cksum_t),
+           KM_SLEEP);
+       fletcher_2_native(buf->b_data, arc_buf_size(buf), NULL,
+           hdr->b_l1hdr.b_freeze_cksum);
+       mutex_exit(&hdr->b_l1hdr.b_freeze_lock);
        arc_buf_watch(buf);
 }
 
@@ -1290,7 +1515,7 @@ arc_buf_unwatch(arc_buf_t *buf)
 {
 #ifndef _KERNEL
        if (arc_watch) {
-               ASSERT0(mprotect(buf->b_data, buf->b_hdr->b_size,
+               ASSERT0(mprotect(buf->b_data, HDR_GET_LSIZE(buf->b_hdr),
                    PROT_READ | PROT_WRITE));
        }
 #endif
@@ -1302,18 +1527,28 @@ arc_buf_watch(arc_buf_t *buf)
 {
 #ifndef _KERNEL
        if (arc_watch)
-               ASSERT0(mprotect(buf->b_data, buf->b_hdr->b_size, PROT_READ));
+               ASSERT0(mprotect(buf->b_data, arc_buf_size(buf),
+                   PROT_READ));
 #endif
 }
 
 static arc_buf_contents_t
 arc_buf_type(arc_buf_hdr_t *hdr)
 {
+       arc_buf_contents_t type;
        if (HDR_ISTYPE_METADATA(hdr)) {
-               return (ARC_BUFC_METADATA);
+               type = ARC_BUFC_METADATA;
        } else {
-               return (ARC_BUFC_DATA);
+               type = ARC_BUFC_DATA;
        }
+       VERIFY3U(hdr->b_type, ==, type);
+       return (type);
+}
+
+boolean_t
+arc_is_metadata(arc_buf_t *buf)
+{
+       return (HDR_ISTYPE_METADATA(buf->b_hdr) != 0);
 }
 
 static uint32_t
@@ -1335,105 +1570,404 @@ arc_bufc_to_flags(arc_buf_contents_t type)
 void
 arc_buf_thaw(arc_buf_t *buf)
 {
-       if (zfs_flags & ZFS_DEBUG_MODIFY) {
-               if (buf->b_hdr->b_l1hdr.b_state != arc_anon)
-                       panic("modifying non-anon buffer!");
-               if (HDR_IO_IN_PROGRESS(buf->b_hdr))
-                       panic("modifying buffer while i/o in progress!");
-               arc_cksum_verify(buf);
-       }
+       arc_buf_hdr_t *hdr = buf->b_hdr;
 
-       mutex_enter(&buf->b_hdr->b_l1hdr.b_freeze_lock);
-       if (buf->b_hdr->b_freeze_cksum != NULL) {
-               kmem_free(buf->b_hdr->b_freeze_cksum, sizeof (zio_cksum_t));
-               buf->b_hdr->b_freeze_cksum = NULL;
-       }
+       ASSERT3P(hdr->b_l1hdr.b_state, ==, arc_anon);
+       ASSERT(!HDR_IO_IN_PROGRESS(hdr));
 
-       mutex_exit(&buf->b_hdr->b_l1hdr.b_freeze_lock);
+       arc_cksum_verify(buf);
+
+       /*
+        * Compressed buffers do not manipulate the b_freeze_cksum or
+        * allocate b_thawed.
+        */
+       if (ARC_BUF_COMPRESSED(buf)) {
+               ASSERT(hdr->b_l1hdr.b_freeze_cksum == NULL ||
+                   hdr->b_l1hdr.b_bufcnt > 1);
+               return;
+       }
 
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       arc_cksum_free(hdr);
        arc_buf_unwatch(buf);
 }
 
 void
 arc_buf_freeze(arc_buf_t *buf)
 {
+       arc_buf_hdr_t *hdr = buf->b_hdr;
        kmutex_t *hash_lock;
 
        if (!(zfs_flags & ZFS_DEBUG_MODIFY))
                return;
 
-       hash_lock = HDR_LOCK(buf->b_hdr);
+       if (ARC_BUF_COMPRESSED(buf)) {
+               ASSERT(hdr->b_l1hdr.b_freeze_cksum == NULL ||
+                   hdr->b_l1hdr.b_bufcnt > 1);
+               return;
+       }
+
+       hash_lock = HDR_LOCK(hdr);
        mutex_enter(hash_lock);
 
-       ASSERT(buf->b_hdr->b_freeze_cksum != NULL ||
-           buf->b_hdr->b_l1hdr.b_state == arc_anon);
-       arc_cksum_compute(buf, B_FALSE);
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       ASSERT(hdr->b_l1hdr.b_freeze_cksum != NULL ||
+           hdr->b_l1hdr.b_state == arc_anon);
+       arc_cksum_compute(buf);
        mutex_exit(hash_lock);
-
 }
 
-static void
-add_reference(arc_buf_hdr_t *hdr, kmutex_t *hash_lock, void *tag)
+/*
+ * The arc_buf_hdr_t's b_flags should never be modified directly. Instead,
+ * the following functions should be used to ensure that the flags are
+ * updated in a thread-safe way. When manipulating the flags either
+ * the hash_lock must be held or the hdr must be undiscoverable. This
+ * ensures that we're not racing with any other threads when updating
+ * the flags.
+ */
+static inline void
+arc_hdr_set_flags(arc_buf_hdr_t *hdr, arc_flags_t flags)
 {
-       arc_state_t *state;
-
-       ASSERT(HDR_HAS_L1HDR(hdr));
-       ASSERT(MUTEX_HELD(hash_lock));
-
-       state = hdr->b_l1hdr.b_state;
+       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)) || HDR_EMPTY(hdr));
+       hdr->b_flags |= flags;
+}
 
-       if ((refcount_add(&hdr->b_l1hdr.b_refcnt, tag) == 1) &&
-           (state != arc_anon)) {
-               /* We don't use the L2-only state list. */
-               if (state != arc_l2c_only) {
-                       arc_buf_contents_t type = arc_buf_type(hdr);
-                       uint64_t delta = hdr->b_size * hdr->b_l1hdr.b_datacnt;
-                       multilist_t *list = &state->arcs_list[type];
-                       uint64_t *size = &state->arcs_lsize[type];
+static inline void
+arc_hdr_clear_flags(arc_buf_hdr_t *hdr, arc_flags_t flags)
+{
+       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)) || HDR_EMPTY(hdr));
+       hdr->b_flags &= ~flags;
+}
 
-                       multilist_remove(list, hdr);
+/*
+ * Setting the compression bits in the arc_buf_hdr_t's b_flags is
+ * done in a special way since we have to clear and set bits
+ * at the same time. Consumers that wish to set the compression bits
+ * must use this function to ensure that the flags are updated in
+ * thread-safe manner.
+ */
+static void
+arc_hdr_set_compress(arc_buf_hdr_t *hdr, enum zio_compress cmp)
+{
+       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)) || HDR_EMPTY(hdr));
 
-                       if (GHOST_STATE(state)) {
-                               ASSERT0(hdr->b_l1hdr.b_datacnt);
-                               ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
-                               delta = hdr->b_size;
-                       }
-                       ASSERT(delta > 0);
-                       ASSERT3U(*size, >=, delta);
-                       atomic_add_64(size, -delta);
-               }
-               /* remove the prefetch flag if we get a reference */
-               hdr->b_flags &= ~ARC_FLAG_PREFETCH;
+       /*
+        * Holes and embedded blocks will always have a psize = 0 so
+        * we ignore the compression of the blkptr and set the
+        * want to uncompress them. Mark them as uncompressed.
+        */
+       if (!zfs_compressed_arc_enabled || HDR_GET_PSIZE(hdr) == 0) {
+               arc_hdr_clear_flags(hdr, ARC_FLAG_COMPRESSED_ARC);
+               HDR_SET_COMPRESS(hdr, ZIO_COMPRESS_OFF);
+               ASSERT(!HDR_COMPRESSION_ENABLED(hdr));
+               ASSERT3U(HDR_GET_COMPRESS(hdr), ==, ZIO_COMPRESS_OFF);
+       } else {
+               arc_hdr_set_flags(hdr, ARC_FLAG_COMPRESSED_ARC);
+               HDR_SET_COMPRESS(hdr, cmp);
+               ASSERT3U(HDR_GET_COMPRESS(hdr), ==, cmp);
+               ASSERT(HDR_COMPRESSION_ENABLED(hdr));
        }
 }
 
-static int
-remove_reference(arc_buf_hdr_t *hdr, kmutex_t *hash_lock, void *tag)
+/*
+ * Looks for another buf on the same hdr which has the data decompressed, copies
+ * from it, and returns true. If no such buf exists, returns false.
+ */
+static boolean_t
+arc_buf_try_copy_decompressed_data(arc_buf_t *buf)
 {
-       int cnt;
-       arc_state_t *state = hdr->b_l1hdr.b_state;
+       arc_buf_hdr_t *hdr = buf->b_hdr;
+       arc_buf_t *from;
+       boolean_t copied = B_FALSE;
 
        ASSERT(HDR_HAS_L1HDR(hdr));
-       ASSERT(state == arc_anon || MUTEX_HELD(hash_lock));
-       ASSERT(!GHOST_STATE(state));
+       ASSERT3P(buf->b_data, !=, NULL);
+       ASSERT(!ARC_BUF_COMPRESSED(buf));
+
+       for (from = hdr->b_l1hdr.b_buf; from != NULL;
+           from = from->b_next) {
+               /* can't use our own data buffer */
+               if (from == buf) {
+                       continue;
+               }
+
+               if (!ARC_BUF_COMPRESSED(from)) {
+                       bcopy(from->b_data, buf->b_data, arc_buf_size(buf));
+                       copied = B_TRUE;
+                       break;
+               }
+       }
 
        /*
-        * arc_l2c_only counts as a ghost state so we don't need to explicitly
-        * check to prevent usage of the arc_l2c_only list.
+        * There were no decompressed bufs, so there should not be a
+        * checksum on the hdr either.
         */
-       if (((cnt = refcount_remove(&hdr->b_l1hdr.b_refcnt, tag)) == 0) &&
-           (state != arc_anon)) {
-               arc_buf_contents_t type = arc_buf_type(hdr);
-               multilist_t *list = &state->arcs_list[type];
-               uint64_t *size = &state->arcs_lsize[type];
-
-               multilist_insert(list, hdr);
+       EQUIV(!copied, hdr->b_l1hdr.b_freeze_cksum == NULL);
 
-               ASSERT(hdr->b_l1hdr.b_datacnt > 0);
-               atomic_add_64(size, hdr->b_size *
-                   hdr->b_l1hdr.b_datacnt);
-       }
-       return (cnt);
+       return (copied);
+}
+
+/*
+ * Given a buf that has a data buffer attached to it, this function will
+ * efficiently fill the buf with data of the specified compression setting from
+ * the hdr and update the hdr's b_freeze_cksum if necessary. If the buf and hdr
+ * are already sharing a data buf, no copy is performed.
+ *
+ * If the buf is marked as compressed but uncompressed data was requested, this
+ * will allocate a new data buffer for the buf, remove that flag, and fill the
+ * buf with uncompressed data. You can't request a compressed buf on a hdr with
+ * uncompressed data, and (since we haven't added support for it yet) if you
+ * want compressed data your buf must already be marked as compressed and have
+ * the correct-sized data buffer.
+ */
+static int
+arc_buf_fill(arc_buf_t *buf, boolean_t compressed)
+{
+       arc_buf_hdr_t *hdr = buf->b_hdr;
+       boolean_t hdr_compressed = (HDR_GET_COMPRESS(hdr) != ZIO_COMPRESS_OFF);
+       dmu_object_byteswap_t bswap = hdr->b_l1hdr.b_byteswap;
+
+       ASSERT3P(buf->b_data, !=, NULL);
+       IMPLY(compressed, hdr_compressed);
+       IMPLY(compressed, ARC_BUF_COMPRESSED(buf));
+
+       if (hdr_compressed == compressed) {
+               if (!arc_buf_is_shared(buf)) {
+                       bcopy(hdr->b_l1hdr.b_pdata, buf->b_data,
+                           arc_buf_size(buf));
+               }
+       } else {
+               ASSERT(hdr_compressed);
+               ASSERT(!compressed);
+               ASSERT3U(HDR_GET_LSIZE(hdr), !=, HDR_GET_PSIZE(hdr));
+
+               /*
+                * If the buf is sharing its data with the hdr, unlink it and
+                * allocate a new data buffer for the buf.
+                */
+               if (arc_buf_is_shared(buf)) {
+                       ASSERT(ARC_BUF_COMPRESSED(buf));
+
+                       /* We need to give the buf it's own b_data */
+                       buf->b_flags &= ~ARC_BUF_FLAG_SHARED;
+                       buf->b_data =
+                           arc_get_data_buf(hdr, HDR_GET_LSIZE(hdr), buf);
+                       arc_hdr_clear_flags(hdr, ARC_FLAG_SHARED_DATA);
+
+                       /* Previously overhead was 0; just add new overhead */
+                       ARCSTAT_INCR(arcstat_overhead_size, HDR_GET_LSIZE(hdr));
+               } else if (ARC_BUF_COMPRESSED(buf)) {
+                       /* We need to reallocate the buf's b_data */
+                       arc_free_data_buf(hdr, buf->b_data, HDR_GET_PSIZE(hdr),
+                           buf);
+                       buf->b_data =
+                           arc_get_data_buf(hdr, HDR_GET_LSIZE(hdr), buf);
+
+                       /* We increased the size of b_data; update overhead */
+                       ARCSTAT_INCR(arcstat_overhead_size,
+                           HDR_GET_LSIZE(hdr) - HDR_GET_PSIZE(hdr));
+               }
+
+               /*
+                * Regardless of the buf's previous compression settings, it
+                * should not be compressed at the end of this function.
+                */
+               buf->b_flags &= ~ARC_BUF_FLAG_COMPRESSED;
+
+               /*
+                * Try copying the data from another buf which already has a
+                * decompressed version. If that's not possible, it's time to
+                * bite the bullet and decompress the data from the hdr.
+                */
+               if (arc_buf_try_copy_decompressed_data(buf)) {
+                       /* Skip byteswapping and checksumming (already done) */
+                       ASSERT3P(hdr->b_l1hdr.b_freeze_cksum, !=, NULL);
+                       return (0);
+               } else {
+                       int error = zio_decompress_data(HDR_GET_COMPRESS(hdr),
+                           hdr->b_l1hdr.b_pdata, buf->b_data,
+                           HDR_GET_PSIZE(hdr), HDR_GET_LSIZE(hdr));
+
+                       /*
+                        * Absent hardware errors or software bugs, this should
+                        * be impossible, but log it anyway so we can debug it.
+                        */
+                       if (error != 0) {
+                               zfs_dbgmsg(
+                                   "hdr %p, compress %d, psize %d, lsize %d",
+                                   hdr, HDR_GET_COMPRESS(hdr),
+                                   HDR_GET_PSIZE(hdr), HDR_GET_LSIZE(hdr));
+                               return (SET_ERROR(EIO));
+                       }
+               }
+       }
+
+       /* Byteswap the buf's data if necessary */
+       if (bswap != DMU_BSWAP_NUMFUNCS) {
+               ASSERT(!HDR_SHARED_DATA(hdr));
+               ASSERT3U(bswap, <, DMU_BSWAP_NUMFUNCS);
+               dmu_ot_byteswap[bswap].ob_func(buf->b_data, HDR_GET_LSIZE(hdr));
+       }
+
+       /* Compute the hdr's checksum if necessary */
+       arc_cksum_compute(buf);
+
+       return (0);
+}
+
+int
+arc_decompress(arc_buf_t *buf)
+{
+       return (arc_buf_fill(buf, B_FALSE));
+}
+
+/*
+ * Return the size of the block, b_pdata, that is stored in the arc_buf_hdr_t.
+ */
+static uint64_t
+arc_hdr_size(arc_buf_hdr_t *hdr)
+{
+       uint64_t size;
+
+       if (HDR_GET_COMPRESS(hdr) != ZIO_COMPRESS_OFF &&
+           HDR_GET_PSIZE(hdr) > 0) {
+               size = HDR_GET_PSIZE(hdr);
+       } else {
+               ASSERT3U(HDR_GET_LSIZE(hdr), !=, 0);
+               size = HDR_GET_LSIZE(hdr);
+       }
+       return (size);
+}
+
+/*
+ * Increment the amount of evictable space in the arc_state_t's refcount.
+ * We account for the space used by the hdr and the arc buf individually
+ * so that we can add and remove them from the refcount individually.
+ */
+static void
+arc_evictable_space_increment(arc_buf_hdr_t *hdr, arc_state_t *state)
+{
+       arc_buf_contents_t type = arc_buf_type(hdr);
+       arc_buf_t *buf;
+
+       ASSERT(HDR_HAS_L1HDR(hdr));
+
+       if (GHOST_STATE(state)) {
+               ASSERT0(hdr->b_l1hdr.b_bufcnt);
+               ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
+               ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
+               (void) refcount_add_many(&state->arcs_esize[type],
+                   HDR_GET_LSIZE(hdr), hdr);
+               return;
+       }
+
+       ASSERT(!GHOST_STATE(state));
+       if (hdr->b_l1hdr.b_pdata != NULL) {
+               (void) refcount_add_many(&state->arcs_esize[type],
+                   arc_hdr_size(hdr), hdr);
+       }
+       for (buf = hdr->b_l1hdr.b_buf; buf != NULL; buf = buf->b_next) {
+               if (arc_buf_is_shared(buf))
+                       continue;
+               (void) refcount_add_many(&state->arcs_esize[type],
+                   arc_buf_size(buf), buf);
+       }
+}
+
+/*
+ * Decrement the amount of evictable space in the arc_state_t's refcount.
+ * We account for the space used by the hdr and the arc buf individually
+ * so that we can add and remove them from the refcount individually.
+ */
+static void
+arc_evictable_space_decrement(arc_buf_hdr_t *hdr, arc_state_t *state)
+{
+       arc_buf_contents_t type = arc_buf_type(hdr);
+       arc_buf_t *buf;
+
+       ASSERT(HDR_HAS_L1HDR(hdr));
+
+       if (GHOST_STATE(state)) {
+               ASSERT0(hdr->b_l1hdr.b_bufcnt);
+               ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
+               ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
+               (void) refcount_remove_many(&state->arcs_esize[type],
+                   HDR_GET_LSIZE(hdr), hdr);
+               return;
+       }
+
+       ASSERT(!GHOST_STATE(state));
+       if (hdr->b_l1hdr.b_pdata != NULL) {
+               (void) refcount_remove_many(&state->arcs_esize[type],
+                   arc_hdr_size(hdr), hdr);
+       }
+       for (buf = hdr->b_l1hdr.b_buf; buf != NULL; buf = buf->b_next) {
+               if (arc_buf_is_shared(buf))
+                       continue;
+               (void) refcount_remove_many(&state->arcs_esize[type],
+                   arc_buf_size(buf), buf);
+       }
+}
+
+/*
+ * Add a reference to this hdr indicating that someone is actively
+ * referencing that memory. When the refcount transitions from 0 to 1,
+ * we remove it from the respective arc_state_t list to indicate that
+ * it is not evictable.
+ */
+static void
+add_reference(arc_buf_hdr_t *hdr, void *tag)
+{
+       arc_state_t *state;
+
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       if (!MUTEX_HELD(HDR_LOCK(hdr))) {
+               ASSERT(hdr->b_l1hdr.b_state == arc_anon);
+               ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
+               ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
+       }
+
+       state = hdr->b_l1hdr.b_state;
+
+       if ((refcount_add(&hdr->b_l1hdr.b_refcnt, tag) == 1) &&
+           (state != arc_anon)) {
+               /* We don't use the L2-only state list. */
+               if (state != arc_l2c_only) {
+                       multilist_remove(&state->arcs_list[arc_buf_type(hdr)],
+                           hdr);
+                       arc_evictable_space_decrement(hdr, state);
+               }
+               /* remove the prefetch flag if we get a reference */
+               arc_hdr_clear_flags(hdr, ARC_FLAG_PREFETCH);
+       }
+}
+
+/*
+ * Remove a reference from this hdr. When the reference transitions from
+ * 1 to 0 and we're not anonymous, then we add this hdr to the arc_state_t's
+ * list making it eligible for eviction.
+ */
+static int
+remove_reference(arc_buf_hdr_t *hdr, kmutex_t *hash_lock, void *tag)
+{
+       int cnt;
+       arc_state_t *state = hdr->b_l1hdr.b_state;
+
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       ASSERT(state == arc_anon || MUTEX_HELD(hash_lock));
+       ASSERT(!GHOST_STATE(state));
+
+       /*
+        * arc_l2c_only counts as a ghost state so we don't need to explicitly
+        * check to prevent usage of the arc_l2c_only list.
+        */
+       if (((cnt = refcount_remove(&hdr->b_l1hdr.b_refcnt, tag)) == 0) &&
+           (state != arc_anon)) {
+               multilist_insert(&state->arcs_list[arc_buf_type(hdr)], hdr);
+               ASSERT3U(hdr->b_l1hdr.b_bufcnt, >, 0);
+               arc_evictable_space_increment(hdr, state);
+       }
+       return (cnt);
 }
 
 /*
@@ -1466,7 +2000,7 @@ arc_buf_info(arc_buf_t *ab, arc_buf_info_t *abi, int state_index)
                l2hdr = &hdr->b_l2hdr;
 
        if (l1hdr) {
-               abi->abi_datacnt = l1hdr->b_datacnt;
+               abi->abi_bufcnt = l1hdr->b_bufcnt;
                abi->abi_access = l1hdr->b_arc_access;
                abi->abi_mru_hits = l1hdr->b_mru_hits;
                abi->abi_mru_ghost_hits = l1hdr->b_mru_ghost_hits;
@@ -1477,14 +2011,12 @@ arc_buf_info(arc_buf_t *ab, arc_buf_info_t *abi, int state_index)
 
        if (l2hdr) {
                abi->abi_l2arc_dattr = l2hdr->b_daddr;
-               abi->abi_l2arc_asize = l2hdr->b_asize;
-               abi->abi_l2arc_compress = l2hdr->b_compress;
                abi->abi_l2arc_hits = l2hdr->b_hits;
        }
 
        abi->abi_state_type = state ? state->arcs_state : ARC_STATE_ANON;
        abi->abi_state_contents = arc_buf_type(hdr);
-       abi->abi_size = hdr->b_size;
+       abi->abi_size = arc_hdr_size(hdr);
 }
 
 /*
@@ -1497,8 +2029,8 @@ arc_change_state(arc_state_t *new_state, arc_buf_hdr_t *hdr,
 {
        arc_state_t *old_state;
        int64_t refcnt;
-       uint32_t datacnt;
-       uint64_t from_delta, to_delta;
+       uint32_t bufcnt;
+       boolean_t update_old, update_new;
        arc_buf_contents_t buftype = arc_buf_type(hdr);
 
        /*
@@ -1511,20 +2043,20 @@ arc_change_state(arc_state_t *new_state, arc_buf_hdr_t *hdr,
        if (HDR_HAS_L1HDR(hdr)) {
                old_state = hdr->b_l1hdr.b_state;
                refcnt = refcount_count(&hdr->b_l1hdr.b_refcnt);
-               datacnt = hdr->b_l1hdr.b_datacnt;
+               bufcnt = hdr->b_l1hdr.b_bufcnt;
+               update_old = (bufcnt > 0 || hdr->b_l1hdr.b_pdata != NULL);
        } else {
                old_state = arc_l2c_only;
                refcnt = 0;
-               datacnt = 0;
+               bufcnt = 0;
+               update_old = B_FALSE;
        }
+       update_new = update_old;
 
        ASSERT(MUTEX_HELD(hash_lock));
        ASSERT3P(new_state, !=, old_state);
-       ASSERT(refcnt == 0 || datacnt > 0);
-       ASSERT(!GHOST_STATE(new_state) || datacnt == 0);
-       ASSERT(old_state != arc_anon || datacnt <= 1);
-
-       from_delta = to_delta = datacnt * hdr->b_size;
+       ASSERT(!GHOST_STATE(new_state) || bufcnt == 0);
+       ASSERT(old_state != arc_anon || bufcnt <= 1);
 
        /*
         * If this buffer is evictable, transfer it from the
@@ -1532,26 +2064,17 @@ arc_change_state(arc_state_t *new_state, arc_buf_hdr_t *hdr,
         */
        if (refcnt == 0) {
                if (old_state != arc_anon && old_state != arc_l2c_only) {
-                       uint64_t *size = &old_state->arcs_lsize[buftype];
-
                        ASSERT(HDR_HAS_L1HDR(hdr));
                        multilist_remove(&old_state->arcs_list[buftype], hdr);
 
-                       /*
-                        * If prefetching out of the ghost cache,
-                        * we will have a non-zero datacnt.
-                        */
-                       if (GHOST_STATE(old_state) && datacnt == 0) {
-                               /* ghost elements have a ghost size */
-                               ASSERT(hdr->b_l1hdr.b_buf == NULL);
-                               from_delta = hdr->b_size;
+                       if (GHOST_STATE(old_state)) {
+                               ASSERT0(bufcnt);
+                               ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
+                               update_old = B_TRUE;
                        }
-                       ASSERT3U(*size, >=, from_delta);
-                       atomic_add_64(size, -from_delta);
+                       arc_evictable_space_decrement(hdr, old_state);
                }
                if (new_state != arc_anon && new_state != arc_l2c_only) {
-                       uint64_t *size = &new_state->arcs_lsize[buftype];
-
                        /*
                         * An L1 header always exists here, since if we're
                         * moving to some L1-cached state (i.e. not l2c_only or
@@ -1561,39 +2084,39 @@ arc_change_state(arc_state_t *new_state, arc_buf_hdr_t *hdr,
                        ASSERT(HDR_HAS_L1HDR(hdr));
                        multilist_insert(&new_state->arcs_list[buftype], hdr);
 
-                       /* ghost elements have a ghost size */
                        if (GHOST_STATE(new_state)) {
-                               ASSERT0(datacnt);
-                               ASSERT(hdr->b_l1hdr.b_buf == NULL);
-                               to_delta = hdr->b_size;
+                               ASSERT0(bufcnt);
+                               ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
+                               update_new = B_TRUE;
                        }
-                       atomic_add_64(size, to_delta);
+                       arc_evictable_space_increment(hdr, new_state);
                }
        }
 
-       ASSERT(!BUF_EMPTY(hdr));
+       ASSERT(!HDR_EMPTY(hdr));
        if (new_state == arc_anon && HDR_IN_HASH_TABLE(hdr))
                buf_hash_remove(hdr);
 
        /* adjust state sizes (ignore arc_l2c_only) */
 
-       if (to_delta && new_state != arc_l2c_only) {
+       if (update_new && new_state != arc_l2c_only) {
                ASSERT(HDR_HAS_L1HDR(hdr));
                if (GHOST_STATE(new_state)) {
-                       ASSERT0(datacnt);
+                       ASSERT0(bufcnt);
 
                        /*
-                        * We moving a header to a ghost state, we first
+                        * When moving a header to a ghost state, we first
                         * remove all arc buffers. Thus, we'll have a
-                        * datacnt of zero, and no arc buffer to use for
+                        * bufcnt of zero, and no arc buffer to use for
                         * the reference. As a result, we use the arc
                         * header pointer for the reference.
                         */
                        (void) refcount_add_many(&new_state->arcs_size,
-                           hdr->b_size, hdr);
+                           HDR_GET_LSIZE(hdr), hdr);
+                       ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
                } else {
                        arc_buf_t *buf;
-                       ASSERT3U(datacnt, !=, 0);
+                       uint32_t buffers = 0;
 
                        /*
                         * Each individual buffer holds a unique reference,
@@ -1602,35 +2125,52 @@ arc_change_state(arc_state_t *new_state, arc_buf_hdr_t *hdr,
                         */
                        for (buf = hdr->b_l1hdr.b_buf; buf != NULL;
                            buf = buf->b_next) {
+                               ASSERT3U(bufcnt, !=, 0);
+                               buffers++;
+
+                               /*
+                                * When the arc_buf_t is sharing the data
+                                * block with the hdr, the owner of the
+                                * reference belongs to the hdr. Only
+                                * add to the refcount if the arc_buf_t is
+                                * not shared.
+                                */
+                               if (arc_buf_is_shared(buf))
+                                       continue;
+
+                               (void) refcount_add_many(&new_state->arcs_size,
+                                   arc_buf_size(buf), buf);
+                       }
+                       ASSERT3U(bufcnt, ==, buffers);
+
+                       if (hdr->b_l1hdr.b_pdata != NULL) {
                                (void) refcount_add_many(&new_state->arcs_size,
-                                   hdr->b_size, buf);
+                                   arc_hdr_size(hdr), hdr);
+                       } else {
+                               ASSERT(GHOST_STATE(old_state));
                        }
                }
        }
 
-       if (from_delta && old_state != arc_l2c_only) {
+       if (update_old && old_state != arc_l2c_only) {
                ASSERT(HDR_HAS_L1HDR(hdr));
                if (GHOST_STATE(old_state)) {
+                       ASSERT0(bufcnt);
+                       ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
+
                        /*
                         * When moving a header off of a ghost state,
-                        * there's the possibility for datacnt to be
-                        * non-zero. This is because we first add the
-                        * arc buffer to the header prior to changing
-                        * the header's state. Since we used the header
-                        * for the reference when putting the header on
-                        * the ghost state, we must balance that and use
-                        * the header when removing off the ghost state
-                        * (even though datacnt is non zero).
+                        * the header will not contain any arc buffers.
+                        * We use the arc header pointer for the reference
+                        * which is exactly what we did when we put the
+                        * header on the ghost state.
                         */
 
-                       IMPLY(datacnt == 0, new_state == arc_anon ||
-                           new_state == arc_l2c_only);
-
                        (void) refcount_remove_many(&old_state->arcs_size,
-                           hdr->b_size, hdr);
+                           HDR_GET_LSIZE(hdr), hdr);
                } else {
                        arc_buf_t *buf;
-                       ASSERT3U(datacnt, !=, 0);
+                       uint32_t buffers = 0;
 
                        /*
                         * Each individual buffer holds a unique reference,
@@ -1639,9 +2179,27 @@ arc_change_state(arc_state_t *new_state, arc_buf_hdr_t *hdr,
                         */
                        for (buf = hdr->b_l1hdr.b_buf; buf != NULL;
                            buf = buf->b_next) {
+                               ASSERT3U(bufcnt, !=, 0);
+                               buffers++;
+
+                               /*
+                                * When the arc_buf_t is sharing the data
+                                * block with the hdr, the owner of the
+                                * reference belongs to the hdr. Only
+                                * add to the refcount if the arc_buf_t is
+                                * not shared.
+                                */
+                               if (arc_buf_is_shared(buf))
+                                       continue;
+
                                (void) refcount_remove_many(
-                                   &old_state->arcs_size, hdr->b_size, buf);
+                                   &old_state->arcs_size, arc_buf_size(buf),
+                                   buf);
                        }
+                       ASSERT3U(bufcnt, ==, buffers);
+                       ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
+                       (void) refcount_remove_many(
+                           &old_state->arcs_size, arc_hdr_size(hdr), hdr);
                }
        }
 
@@ -1670,8 +2228,14 @@ arc_space_consume(uint64_t space, arc_space_type_t type)
        case ARC_SPACE_META:
                ARCSTAT_INCR(arcstat_metadata_size, space);
                break;
-       case ARC_SPACE_OTHER:
-               ARCSTAT_INCR(arcstat_other_size, space);
+       case ARC_SPACE_BONUS:
+               ARCSTAT_INCR(arcstat_bonus_size, space);
+               break;
+       case ARC_SPACE_DNODE:
+               ARCSTAT_INCR(arcstat_dnode_size, space);
+               break;
+       case ARC_SPACE_DBUF:
+               ARCSTAT_INCR(arcstat_dbuf_size, space);
                break;
        case ARC_SPACE_HDRS:
                ARCSTAT_INCR(arcstat_hdr_size, space);
@@ -1701,8 +2265,14 @@ arc_space_return(uint64_t space, arc_space_type_t type)
        case ARC_SPACE_META:
                ARCSTAT_INCR(arcstat_metadata_size, -space);
                break;
-       case ARC_SPACE_OTHER:
-               ARCSTAT_INCR(arcstat_other_size, -space);
+       case ARC_SPACE_BONUS:
+               ARCSTAT_INCR(arcstat_bonus_size, -space);
+               break;
+       case ARC_SPACE_DNODE:
+               ARCSTAT_INCR(arcstat_dnode_size, -space);
+               break;
+       case ARC_SPACE_DBUF:
+               ARCSTAT_INCR(arcstat_dbuf_size, -space);
                break;
        case ARC_SPACE_HDRS:
                ARCSTAT_INCR(arcstat_hdr_size, -space);
@@ -1723,45 +2293,135 @@ arc_space_return(uint64_t space, arc_space_type_t type)
        atomic_add_64(&arc_size, -space);
 }
 
-arc_buf_t *
-arc_buf_alloc(spa_t *spa, uint64_t size, void *tag, arc_buf_contents_t type)
+/*
+ * Given a hdr and a buf, returns whether that buf can share its b_data buffer
+ * with the hdr's b_pdata.
+ */
+static boolean_t
+arc_can_share(arc_buf_hdr_t *hdr, arc_buf_t *buf)
+{
+       boolean_t hdr_compressed, buf_compressed;
+       /*
+        * The criteria for sharing a hdr's data are:
+        * 1. the hdr's compression matches the buf's compression
+        * 2. the hdr doesn't need to be byteswapped
+        * 3. the hdr isn't already being shared
+        * 4. the buf is either compressed or it is the last buf in the hdr list
+        *
+        * Criterion #4 maintains the invariant that shared uncompressed
+        * bufs must be the final buf in the hdr's b_buf list. Reading this, you
+        * might ask, "if a compressed buf is allocated first, won't that be the
+        * last thing in the list?", but in that case it's impossible to create
+        * a shared uncompressed buf anyway (because the hdr must be compressed
+        * to have the compressed buf). You might also think that #3 is
+        * sufficient to make this guarantee, however it's possible
+        * (specifically in the rare L2ARC write race mentioned in
+        * arc_buf_alloc_impl()) there will be an existing uncompressed buf that
+        * is sharable, but wasn't at the time of its allocation. Rather than
+        * allow a new shared uncompressed buf to be created and then shuffle
+        * the list around to make it the last element, this simply disallows
+        * sharing if the new buf isn't the first to be added.
+        */
+       ASSERT3P(buf->b_hdr, ==, hdr);
+       hdr_compressed = HDR_GET_COMPRESS(hdr) != ZIO_COMPRESS_OFF;
+       buf_compressed = ARC_BUF_COMPRESSED(buf) != 0;
+       return (buf_compressed == hdr_compressed &&
+           hdr->b_l1hdr.b_byteswap == DMU_BSWAP_NUMFUNCS &&
+           !HDR_SHARED_DATA(hdr) &&
+           (ARC_BUF_LAST(buf) || ARC_BUF_COMPRESSED(buf)));
+}
+
+/*
+ * Allocate a buf for this hdr. If you care about the data that's in the hdr,
+ * or if you want a compressed buffer, pass those flags in. Returns 0 if the
+ * copy was made successfully, or an error code otherwise.
+ */
+static int
+arc_buf_alloc_impl(arc_buf_hdr_t *hdr, void *tag, boolean_t compressed,
+    boolean_t fill, arc_buf_t **ret)
 {
-       arc_buf_hdr_t *hdr;
        arc_buf_t *buf;
+       boolean_t can_share;
+
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       ASSERT3U(HDR_GET_LSIZE(hdr), >, 0);
+       VERIFY(hdr->b_type == ARC_BUFC_DATA ||
+           hdr->b_type == ARC_BUFC_METADATA);
+       ASSERT3P(ret, !=, NULL);
+       ASSERT3P(*ret, ==, NULL);
 
-       VERIFY3U(size, <=, spa_maxblocksize(spa));
-       hdr = kmem_cache_alloc(hdr_full_cache, KM_PUSHPAGE);
-       ASSERT(BUF_EMPTY(hdr));
-       ASSERT3P(hdr->b_freeze_cksum, ==, NULL);
-       hdr->b_size = size;
-       hdr->b_spa = spa_load_guid(spa);
        hdr->b_l1hdr.b_mru_hits = 0;
        hdr->b_l1hdr.b_mru_ghost_hits = 0;
        hdr->b_l1hdr.b_mfu_hits = 0;
        hdr->b_l1hdr.b_mfu_ghost_hits = 0;
        hdr->b_l1hdr.b_l2_hits = 0;
 
-       buf = kmem_cache_alloc(buf_cache, KM_PUSHPAGE);
+       buf = *ret = kmem_cache_alloc(buf_cache, KM_PUSHPAGE);
        buf->b_hdr = hdr;
        buf->b_data = NULL;
-       buf->b_efunc = NULL;
-       buf->b_private = NULL;
-       buf->b_next = NULL;
+       buf->b_next = hdr->b_l1hdr.b_buf;
+       buf->b_flags = 0;
 
-       hdr->b_flags = arc_bufc_to_flags(type);
-       hdr->b_flags |= ARC_FLAG_HAS_L1HDR;
+       add_reference(hdr, tag);
+
+       /*
+        * We're about to change the hdr's b_flags. We must either
+        * hold the hash_lock or be undiscoverable.
+        */
+       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)) || HDR_EMPTY(hdr));
+
+       /*
+        * Only honor requests for compressed bufs if the hdr is actually
+        * compressed.
+        */
+       if (compressed && HDR_GET_COMPRESS(hdr) != ZIO_COMPRESS_OFF)
+               buf->b_flags |= ARC_BUF_FLAG_COMPRESSED;
+
+       /*
+        * Although the ARC should handle it correctly, levels above the ARC
+        * should prevent us from having multiple compressed bufs off the same
+        * hdr. To ensure we notice it if this behavior changes, we assert this
+        * here the best we can.
+        */
+       IMPLY(ARC_BUF_COMPRESSED(buf), !HDR_SHARED_DATA(hdr));
+
+       /*
+        * If the hdr's data can be shared then we share the data buffer and
+        * set the appropriate bit in the hdr's b_flags to indicate the hdr is
+        * allocate a new buffer to store the buf's data.
+        *
+        * There is one additional restriction here because we're sharing
+        * hdr -> buf instead of the usual buf -> hdr: the hdr can't be actively
+        * involved in an L2ARC write, because if this buf is used by an
+        * arc_write() then the hdr's data buffer will be released when the
+        * write completes, even though the L2ARC write might still be using it.
+        */
+       can_share = arc_can_share(hdr, buf) && !HDR_L2_WRITING(hdr);
+
+       /* Set up b_data and sharing */
+       if (can_share) {
+               buf->b_data = hdr->b_l1hdr.b_pdata;
+               buf->b_flags |= ARC_BUF_FLAG_SHARED;
+               arc_hdr_set_flags(hdr, ARC_FLAG_SHARED_DATA);
+       } else {
+               buf->b_data =
+                   arc_get_data_buf(hdr, arc_buf_size(buf), buf);
+               ARCSTAT_INCR(arcstat_overhead_size, arc_buf_size(buf));
+       }
+       VERIFY3P(buf->b_data, !=, NULL);
 
        hdr->b_l1hdr.b_buf = buf;
-       hdr->b_l1hdr.b_state = arc_anon;
-       hdr->b_l1hdr.b_arc_access = 0;
-       hdr->b_l1hdr.b_datacnt = 1;
-       hdr->b_l1hdr.b_tmp_cdata = NULL;
+       hdr->b_l1hdr.b_bufcnt += 1;
 
-       arc_get_data_buf(buf);
-       ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
-       (void) refcount_add(&hdr->b_l1hdr.b_refcnt, tag);
+       /*
+        * If the user wants the data from the hdr, we need to either copy or
+        * decompress the data.
+        */
+       if (fill) {
+               return (arc_buf_fill(buf, ARC_BUF_COMPRESSED(buf) != 0));
+       }
 
-       return (buf);
+       return (0);
 }
 
 static char *arc_onloan_tag = "onloan";
@@ -1773,16 +2433,27 @@ static char *arc_onloan_tag = "onloan";
  * freed.
  */
 arc_buf_t *
-arc_loan_buf(spa_t *spa, uint64_t size)
+arc_loan_buf(spa_t *spa, boolean_t is_metadata, int size)
 {
-       arc_buf_t *buf;
-
-       buf = arc_buf_alloc(spa, size, arc_onloan_tag, ARC_BUFC_DATA);
+       arc_buf_t *buf = arc_alloc_buf(spa, arc_onloan_tag,
+           is_metadata ? ARC_BUFC_METADATA : ARC_BUFC_DATA, size);
 
        atomic_add_64(&arc_loaned_bytes, size);
        return (buf);
 }
 
+arc_buf_t *
+arc_loan_compressed_buf(spa_t *spa, uint64_t psize, uint64_t lsize,
+    enum zio_compress compression_type)
+{
+       arc_buf_t *buf = arc_alloc_compressed_buf(spa, arc_onloan_tag,
+           psize, lsize, compression_type);
+
+       atomic_add_64(&arc_loaned_bytes, psize);
+       return (buf);
+}
+
+
 /*
  * Return a loaned arc buffer to the arc.
  */
@@ -1791,12 +2462,12 @@ arc_return_buf(arc_buf_t *buf, void *tag)
 {
        arc_buf_hdr_t *hdr = buf->b_hdr;
 
-       ASSERT(buf->b_data != NULL);
+       ASSERT3P(buf->b_data, !=, NULL);
        ASSERT(HDR_HAS_L1HDR(hdr));
        (void) refcount_add(&hdr->b_l1hdr.b_refcnt, tag);
        (void) refcount_remove(&hdr->b_l1hdr.b_refcnt, arc_onloan_tag);
 
-       atomic_add_64(&arc_loaned_bytes, -hdr->b_size);
+       atomic_add_64(&arc_loaned_bytes, -arc_buf_size(buf));
 }
 
 /* Detach an arc_buf from a dbuf (tag) */
@@ -1805,244 +2476,455 @@ arc_loan_inuse_buf(arc_buf_t *buf, void *tag)
 {
        arc_buf_hdr_t *hdr = buf->b_hdr;
 
-       ASSERT(buf->b_data != NULL);
+       ASSERT3P(buf->b_data, !=, NULL);
        ASSERT(HDR_HAS_L1HDR(hdr));
        (void) refcount_add(&hdr->b_l1hdr.b_refcnt, arc_onloan_tag);
        (void) refcount_remove(&hdr->b_l1hdr.b_refcnt, tag);
-       buf->b_efunc = NULL;
-       buf->b_private = NULL;
 
-       atomic_add_64(&arc_loaned_bytes, hdr->b_size);
+       atomic_add_64(&arc_loaned_bytes, -arc_buf_size(buf));
+}
+
+static void
+l2arc_free_data_on_write(void *data, size_t size, arc_buf_contents_t type)
+{
+       l2arc_data_free_t *df = kmem_alloc(sizeof (*df), KM_SLEEP);
+
+       df->l2df_data = data;
+       df->l2df_size = size;
+       df->l2df_type = type;
+       mutex_enter(&l2arc_free_on_write_mtx);
+       list_insert_head(l2arc_free_on_write, df);
+       mutex_exit(&l2arc_free_on_write_mtx);
+}
+
+static void
+arc_hdr_free_on_write(arc_buf_hdr_t *hdr)
+{
+       arc_state_t *state = hdr->b_l1hdr.b_state;
+       arc_buf_contents_t type = arc_buf_type(hdr);
+       uint64_t size = arc_hdr_size(hdr);
+
+       /* protected by hash lock, if in the hash table */
+       if (multilist_link_active(&hdr->b_l1hdr.b_arc_node)) {
+               ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
+               ASSERT(state != arc_anon && state != arc_l2c_only);
+
+               (void) refcount_remove_many(&state->arcs_esize[type],
+                   size, hdr);
+       }
+       (void) refcount_remove_many(&state->arcs_size, size, hdr);
+
+       l2arc_free_data_on_write(hdr->b_l1hdr.b_pdata, size, type);
+}
+
+/*
+ * Share the arc_buf_t's data with the hdr. Whenever we are sharing the
+ * data buffer, we transfer the refcount ownership to the hdr and update
+ * the appropriate kstats.
+ */
+static void
+arc_share_buf(arc_buf_hdr_t *hdr, arc_buf_t *buf)
+{
+       ASSERT(arc_can_share(hdr, buf));
+       ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
+       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)) || HDR_EMPTY(hdr));
+
+       /*
+        * Start sharing the data buffer. We transfer the
+        * refcount ownership to the hdr since it always owns
+        * the refcount whenever an arc_buf_t is shared.
+        */
+       refcount_transfer_ownership(&hdr->b_l1hdr.b_state->arcs_size, buf, hdr);
+       hdr->b_l1hdr.b_pdata = buf->b_data;
+       arc_hdr_set_flags(hdr, ARC_FLAG_SHARED_DATA);
+       buf->b_flags |= ARC_BUF_FLAG_SHARED;
+
+       /*
+        * Since we've transferred ownership to the hdr we need
+        * to increment its compressed and uncompressed kstats and
+        * decrement the overhead size.
+        */
+       ARCSTAT_INCR(arcstat_compressed_size, arc_hdr_size(hdr));
+       ARCSTAT_INCR(arcstat_uncompressed_size, HDR_GET_LSIZE(hdr));
+       ARCSTAT_INCR(arcstat_overhead_size, -arc_buf_size(buf));
+}
+
+static void
+arc_unshare_buf(arc_buf_hdr_t *hdr, arc_buf_t *buf)
+{
+       ASSERT(arc_buf_is_shared(buf));
+       ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
+       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)) || HDR_EMPTY(hdr));
+
+       /*
+        * We are no longer sharing this buffer so we need
+        * to transfer its ownership to the rightful owner.
+        */
+       refcount_transfer_ownership(&hdr->b_l1hdr.b_state->arcs_size, hdr, buf);
+       arc_hdr_clear_flags(hdr, ARC_FLAG_SHARED_DATA);
+       hdr->b_l1hdr.b_pdata = NULL;
+       buf->b_flags &= ~ARC_BUF_FLAG_SHARED;
+
+       /*
+        * Since the buffer is no longer shared between
+        * the arc buf and the hdr, count it as overhead.
+        */
+       ARCSTAT_INCR(arcstat_compressed_size, -arc_hdr_size(hdr));
+       ARCSTAT_INCR(arcstat_uncompressed_size, -HDR_GET_LSIZE(hdr));
+       ARCSTAT_INCR(arcstat_overhead_size, arc_buf_size(buf));
 }
 
+/*
+ * Remove an arc_buf_t from the hdr's buf list and return the last
+ * arc_buf_t on the list. If no buffers remain on the list then return
+ * NULL.
+ */
 static arc_buf_t *
-arc_buf_clone(arc_buf_t *from)
+arc_buf_remove(arc_buf_hdr_t *hdr, arc_buf_t *buf)
 {
-       arc_buf_t *buf;
-       arc_buf_hdr_t *hdr = from->b_hdr;
-       uint64_t size = hdr->b_size;
+       arc_buf_t **bufp = &hdr->b_l1hdr.b_buf;
+       arc_buf_t *lastbuf = NULL;
 
        ASSERT(HDR_HAS_L1HDR(hdr));
-       ASSERT(hdr->b_l1hdr.b_state != arc_anon);
-
-       buf = kmem_cache_alloc(buf_cache, KM_PUSHPAGE);
-       buf->b_hdr = hdr;
-       buf->b_data = NULL;
-       buf->b_efunc = NULL;
-       buf->b_private = NULL;
-       buf->b_next = hdr->b_l1hdr.b_buf;
-       hdr->b_l1hdr.b_buf = buf;
-       arc_get_data_buf(buf);
-       bcopy(from->b_data, buf->b_data, size);
+       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)) || HDR_EMPTY(hdr));
 
        /*
-        * This buffer already exists in the arc so create a duplicate
-        * copy for the caller.  If the buffer is associated with user data
-        * then track the size and number of duplicates.  These stats will be
-        * updated as duplicate buffers are created and destroyed.
+        * Remove the buf from the hdr list and locate the last
+        * remaining buffer on the list.
         */
-       if (HDR_ISTYPE_DATA(hdr)) {
-               ARCSTAT_BUMP(arcstat_duplicate_buffers);
-               ARCSTAT_INCR(arcstat_duplicate_buffers_size, size);
+       while (*bufp != NULL) {
+               if (*bufp == buf)
+                       *bufp = buf->b_next;
+
+               /*
+                * If we've removed a buffer in the middle of
+                * the list then update the lastbuf and update
+                * bufp.
+                */
+               if (*bufp != NULL) {
+                       lastbuf = *bufp;
+                       bufp = &(*bufp)->b_next;
+               }
        }
-       hdr->b_l1hdr.b_datacnt += 1;
-       return (buf);
+       buf->b_next = NULL;
+       ASSERT3P(lastbuf, !=, buf);
+       IMPLY(hdr->b_l1hdr.b_bufcnt > 0, lastbuf != NULL);
+       IMPLY(hdr->b_l1hdr.b_bufcnt > 0, hdr->b_l1hdr.b_buf != NULL);
+       IMPLY(lastbuf != NULL, ARC_BUF_LAST(lastbuf));
+
+       return (lastbuf);
 }
 
-void
-arc_buf_add_ref(arc_buf_t *buf, void* tag)
+/*
+ * Free up buf->b_data and pull the arc_buf_t off of the the arc_buf_hdr_t's
+ * list and free it.
+ */
+static void
+arc_buf_destroy_impl(arc_buf_t *buf)
 {
-       arc_buf_hdr_t *hdr;
-       kmutex_t *hash_lock;
+       arc_buf_t *lastbuf;
+       arc_buf_hdr_t *hdr = buf->b_hdr;
 
        /*
-        * Check to see if this buffer is evicted.  Callers
-        * must verify b_data != NULL to know if the add_ref
-        * was successful.
+        * Free up the data associated with the buf but only if we're not
+        * sharing this with the hdr. If we are sharing it with the hdr, the
+        * hdr is responsible for doing the free.
         */
-       mutex_enter(&buf->b_evict_lock);
-       if (buf->b_data == NULL) {
-               mutex_exit(&buf->b_evict_lock);
-               return;
+       if (buf->b_data != NULL) {
+               /*
+                * We're about to change the hdr's b_flags. We must either
+                * hold the hash_lock or be undiscoverable.
+                */
+               ASSERT(MUTEX_HELD(HDR_LOCK(hdr)) || HDR_EMPTY(hdr));
+
+               arc_cksum_verify(buf);
+               arc_buf_unwatch(buf);
+
+               if (arc_buf_is_shared(buf)) {
+                       arc_hdr_clear_flags(hdr, ARC_FLAG_SHARED_DATA);
+               } else {
+                       uint64_t size = arc_buf_size(buf);
+                       arc_free_data_buf(hdr, buf->b_data, size, buf);
+                       ARCSTAT_INCR(arcstat_overhead_size, -size);
+               }
+               buf->b_data = NULL;
+
+               ASSERT(hdr->b_l1hdr.b_bufcnt > 0);
+               hdr->b_l1hdr.b_bufcnt -= 1;
        }
-       hash_lock = HDR_LOCK(buf->b_hdr);
-       mutex_enter(hash_lock);
-       hdr = buf->b_hdr;
-       ASSERT(HDR_HAS_L1HDR(hdr));
-       ASSERT3P(hash_lock, ==, HDR_LOCK(hdr));
-       mutex_exit(&buf->b_evict_lock);
 
-       ASSERT(hdr->b_l1hdr.b_state == arc_mru ||
-           hdr->b_l1hdr.b_state == arc_mfu);
+       lastbuf = arc_buf_remove(hdr, buf);
 
-       add_reference(hdr, hash_lock, tag);
-       DTRACE_PROBE1(arc__hit, arc_buf_hdr_t *, hdr);
-       arc_access(hdr, hash_lock);
-       mutex_exit(hash_lock);
-       ARCSTAT_BUMP(arcstat_hits);
-       ARCSTAT_CONDSTAT(!HDR_PREFETCH(hdr),
-           demand, prefetch, !HDR_ISTYPE_METADATA(hdr),
-           data, metadata, hits);
+       if (ARC_BUF_SHARED(buf) && !ARC_BUF_COMPRESSED(buf)) {
+               /*
+                * If the current arc_buf_t is sharing its data buffer with the
+                * hdr, then reassign the hdr's b_pdata to share it with the new
+                * buffer at the end of the list. The shared buffer is always
+                * the last one on the hdr's buffer list.
+                *
+                * There is an equivalent case for compressed bufs, but since
+                * they aren't guaranteed to be the last buf in the list and
+                * that is an exceedingly rare case, we just allow that space be
+                * wasted temporarily.
+                */
+               if (lastbuf != NULL) {
+                       /* Only one buf can be shared at once */
+                       VERIFY(!arc_buf_is_shared(lastbuf));
+                       /* hdr is uncompressed so can't have compressed buf */
+                       VERIFY(!ARC_BUF_COMPRESSED(lastbuf));
+
+                       ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
+                       arc_hdr_free_pdata(hdr);
+
+                       /*
+                        * We must setup a new shared block between the
+                        * last buffer and the hdr. The data would have
+                        * been allocated by the arc buf so we need to transfer
+                        * ownership to the hdr since it's now being shared.
+                        */
+                       arc_share_buf(hdr, lastbuf);
+               }
+       } else if (HDR_SHARED_DATA(hdr)) {
+               /*
+                * Uncompressed shared buffers are always at the end
+                * of the list. Compressed buffers don't have the
+                * same requirements. This makes it hard to
+                * simply assert that the lastbuf is shared so
+                * we rely on the hdr's compression flags to determine
+                * if we have a compressed, shared buffer.
+                */
+               ASSERT3P(lastbuf, !=, NULL);
+               ASSERT(arc_buf_is_shared(lastbuf) ||
+                   HDR_GET_COMPRESS(hdr) != ZIO_COMPRESS_OFF);
+       }
+
+       if (hdr->b_l1hdr.b_bufcnt == 0)
+               arc_cksum_free(hdr);
+
+       /* clean up the buf */
+       buf->b_hdr = NULL;
+       kmem_cache_free(buf_cache, buf);
 }
 
 static void
-arc_buf_free_on_write(void *data, size_t size,
-    void (*free_func)(void *, size_t))
+arc_hdr_alloc_pdata(arc_buf_hdr_t *hdr)
 {
-       l2arc_data_free_t *df;
+       ASSERT3U(HDR_GET_LSIZE(hdr), >, 0);
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       ASSERT(!HDR_SHARED_DATA(hdr));
 
-       df = kmem_alloc(sizeof (*df), KM_SLEEP);
-       df->l2df_data = data;
-       df->l2df_size = size;
-       df->l2df_func = free_func;
-       mutex_enter(&l2arc_free_on_write_mtx);
-       list_insert_head(l2arc_free_on_write, df);
-       mutex_exit(&l2arc_free_on_write_mtx);
+       ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
+       hdr->b_l1hdr.b_pdata = arc_get_data_buf(hdr, arc_hdr_size(hdr), hdr);
+       hdr->b_l1hdr.b_byteswap = DMU_BSWAP_NUMFUNCS;
+       ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
+
+       ARCSTAT_INCR(arcstat_compressed_size, arc_hdr_size(hdr));
+       ARCSTAT_INCR(arcstat_uncompressed_size, HDR_GET_LSIZE(hdr));
 }
 
-/*
- * Free the arc data buffer.  If it is an l2arc write in progress,
- * the buffer is placed on l2arc_free_on_write to be freed later.
- */
 static void
-arc_buf_data_free(arc_buf_t *buf, void (*free_func)(void *, size_t))
+arc_hdr_free_pdata(arc_buf_hdr_t *hdr)
 {
-       arc_buf_hdr_t *hdr = buf->b_hdr;
+       ASSERT(HDR_HAS_L1HDR(hdr));
+       ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
 
+       /*
+        * If the hdr is currently being written to the l2arc then
+        * we defer freeing the data by adding it to the l2arc_free_on_write
+        * list. The l2arc will free the data once it's finished
+        * writing it to the l2arc device.
+        */
        if (HDR_L2_WRITING(hdr)) {
-               arc_buf_free_on_write(buf->b_data, hdr->b_size, free_func);
+               arc_hdr_free_on_write(hdr);
                ARCSTAT_BUMP(arcstat_l2_free_on_write);
        } else {
-               free_func(buf->b_data, hdr->b_size);
+               arc_free_data_buf(hdr, hdr->b_l1hdr.b_pdata,
+                   arc_hdr_size(hdr), hdr);
        }
+       hdr->b_l1hdr.b_pdata = NULL;
+       hdr->b_l1hdr.b_byteswap = DMU_BSWAP_NUMFUNCS;
+
+       ARCSTAT_INCR(arcstat_compressed_size, -arc_hdr_size(hdr));
+       ARCSTAT_INCR(arcstat_uncompressed_size, -HDR_GET_LSIZE(hdr));
+}
+
+static arc_buf_hdr_t *
+arc_hdr_alloc(uint64_t spa, int32_t psize, int32_t lsize,
+    enum zio_compress compression_type, arc_buf_contents_t type)
+{
+       arc_buf_hdr_t *hdr;
+
+       VERIFY(type == ARC_BUFC_DATA || type == ARC_BUFC_METADATA);
+
+       hdr = kmem_cache_alloc(hdr_full_cache, KM_PUSHPAGE);
+       ASSERT(HDR_EMPTY(hdr));
+       ASSERT3P(hdr->b_l1hdr.b_freeze_cksum, ==, NULL);
+       HDR_SET_PSIZE(hdr, psize);
+       HDR_SET_LSIZE(hdr, lsize);
+       hdr->b_spa = spa;
+       hdr->b_type = type;
+       hdr->b_flags = 0;
+       arc_hdr_set_flags(hdr, arc_bufc_to_flags(type) | ARC_FLAG_HAS_L1HDR);
+       arc_hdr_set_compress(hdr, compression_type);
+
+       hdr->b_l1hdr.b_state = arc_anon;
+       hdr->b_l1hdr.b_arc_access = 0;
+       hdr->b_l1hdr.b_bufcnt = 0;
+       hdr->b_l1hdr.b_buf = NULL;
+
+       /*
+        * Allocate the hdr's buffer. This will contain either
+        * the compressed or uncompressed data depending on the block
+        * it references and compressed arc enablement.
+        */
+       arc_hdr_alloc_pdata(hdr);
+       ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
+
+       return (hdr);
 }
 
-static void
-arc_buf_l2_cdata_free(arc_buf_hdr_t *hdr)
-{
-       ASSERT(HDR_HAS_L2HDR(hdr));
-       ASSERT(MUTEX_HELD(&hdr->b_l2hdr.b_dev->l2ad_mtx));
+/*
+ * Transition between the two allocation states for the arc_buf_hdr struct.
+ * The arc_buf_hdr struct can be allocated with (hdr_full_cache) or without
+ * (hdr_l2only_cache) the fields necessary for the L1 cache - the smaller
+ * version is used when a cache buffer is only in the L2ARC in order to reduce
+ * memory usage.
+ */
+static arc_buf_hdr_t *
+arc_hdr_realloc(arc_buf_hdr_t *hdr, kmem_cache_t *old, kmem_cache_t *new)
+{
+       arc_buf_hdr_t *nhdr;
+       l2arc_dev_t *dev = hdr->b_l2hdr.b_dev;
+
+       ASSERT(HDR_HAS_L2HDR(hdr));
+       ASSERT((old == hdr_full_cache && new == hdr_l2only_cache) ||
+           (old == hdr_l2only_cache && new == hdr_full_cache));
+
+       nhdr = kmem_cache_alloc(new, KM_PUSHPAGE);
+
+       ASSERT(MUTEX_HELD(HDR_LOCK(hdr)));
+       buf_hash_remove(hdr);
+
+       bcopy(hdr, nhdr, HDR_L2ONLY_SIZE);
+
+       if (new == hdr_full_cache) {
+               arc_hdr_set_flags(nhdr, ARC_FLAG_HAS_L1HDR);
+               /*
+                * arc_access and arc_change_state need to be aware that a
+                * header has just come out of L2ARC, so we set its state to
+                * l2c_only even though it's about to change.
+                */
+               nhdr->b_l1hdr.b_state = arc_l2c_only;
+
+               /* Verify previous threads set to NULL before freeing */
+               ASSERT3P(nhdr->b_l1hdr.b_pdata, ==, NULL);
+       } else {
+               ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
+               ASSERT0(hdr->b_l1hdr.b_bufcnt);
+               ASSERT3P(hdr->b_l1hdr.b_freeze_cksum, ==, NULL);
+
+               /*
+                * If we've reached here, We must have been called from
+                * arc_evict_hdr(), as such we should have already been
+                * removed from any ghost list we were previously on
+                * (which protects us from racing with arc_evict_state),
+                * thus no locking is needed during this check.
+                */
+               ASSERT(!multilist_link_active(&hdr->b_l1hdr.b_arc_node));
+
+               /*
+                * A buffer must not be moved into the arc_l2c_only
+                * state if it's not finished being written out to the
+                * l2arc device. Otherwise, the b_l1hdr.b_pdata field
+                * might try to be accessed, even though it was removed.
+                */
+               VERIFY(!HDR_L2_WRITING(hdr));
+               VERIFY3P(hdr->b_l1hdr.b_pdata, ==, NULL);
 
+               arc_hdr_clear_flags(nhdr, ARC_FLAG_HAS_L1HDR);
+       }
        /*
-        * The b_tmp_cdata field is linked off of the b_l1hdr, so if
-        * that doesn't exist, the header is in the arc_l2c_only state,
-        * and there isn't anything to free (it's already been freed).
+        * The header has been reallocated so we need to re-insert it into any
+        * lists it was on.
         */
-       if (!HDR_HAS_L1HDR(hdr))
-               return;
+       (void) buf_hash_insert(nhdr, NULL);
 
-       /*
-        * The header isn't being written to the l2arc device, thus it
-        * shouldn't have a b_tmp_cdata to free.
-        */
-       if (!HDR_L2_WRITING(hdr)) {
-               ASSERT3P(hdr->b_l1hdr.b_tmp_cdata, ==, NULL);
-               return;
-       }
+       ASSERT(list_link_active(&hdr->b_l2hdr.b_l2node));
+
+       mutex_enter(&dev->l2ad_mtx);
 
        /*
-        * The header does not have compression enabled. This can be due
-        * to the buffer not being compressible, or because we're
-        * freeing the buffer before the second phase of
-        * l2arc_write_buffer() has started (which does the compression
-        * step). In either case, b_tmp_cdata does not point to a
-        * separately compressed buffer, so there's nothing to free (it
-        * points to the same buffer as the arc_buf_t's b_data field).
+        * We must place the realloc'ed header back into the list at
+        * the same spot. Otherwise, if it's placed earlier in the list,
+        * l2arc_write_buffers() could find it during the function's
+        * write phase, and try to write it out to the l2arc.
         */
-       if (hdr->b_l2hdr.b_compress == ZIO_COMPRESS_OFF) {
-               hdr->b_l1hdr.b_tmp_cdata = NULL;
-               return;
-       }
+       list_insert_after(&dev->l2ad_buflist, hdr, nhdr);
+       list_remove(&dev->l2ad_buflist, hdr);
+
+       mutex_exit(&dev->l2ad_mtx);
 
        /*
-        * There's nothing to free since the buffer was all zero's and
-        * compressed to a zero length buffer.
+        * Since we're using the pointer address as the tag when
+        * incrementing and decrementing the l2ad_alloc refcount, we
+        * must remove the old pointer (that we're about to destroy) and
+        * add the new pointer to the refcount. Otherwise we'd remove
+        * the wrong pointer address when calling arc_hdr_destroy() later.
         */
-       if (hdr->b_l2hdr.b_compress == ZIO_COMPRESS_EMPTY) {
-               ASSERT3P(hdr->b_l1hdr.b_tmp_cdata, ==, NULL);
-               return;
-       }
 
-       ASSERT(L2ARC_IS_VALID_COMPRESS(hdr->b_l2hdr.b_compress));
+       (void) refcount_remove_many(&dev->l2ad_alloc, arc_hdr_size(hdr), hdr);
+       (void) refcount_add_many(&dev->l2ad_alloc, arc_hdr_size(nhdr), nhdr);
 
-       arc_buf_free_on_write(hdr->b_l1hdr.b_tmp_cdata,
-           hdr->b_size, zio_data_buf_free);
+       buf_discard_identity(hdr);
+       kmem_cache_free(old, hdr);
 
-       ARCSTAT_BUMP(arcstat_l2_cdata_free_on_write);
-       hdr->b_l1hdr.b_tmp_cdata = NULL;
+       return (nhdr);
 }
 
 /*
- * Free up buf->b_data and if 'remove' is set, then pull the
- * arc_buf_t off of the the arc_buf_hdr_t's list and free it.
+ * Allocate a new arc_buf_hdr_t and arc_buf_t and return the buf to the caller.
+ * The buf is returned thawed since we expect the consumer to modify it.
  */
-static void
-arc_buf_destroy(arc_buf_t *buf, boolean_t remove)
+arc_buf_t *
+arc_alloc_buf(spa_t *spa, void *tag, arc_buf_contents_t type, int32_t size)
 {
-       arc_buf_t **bufp;
-
-       /* free up data associated with the buf */
-       if (buf->b_data != NULL) {
-               arc_state_t *state = buf->b_hdr->b_l1hdr.b_state;
-               uint64_t size = buf->b_hdr->b_size;
-               arc_buf_contents_t type = arc_buf_type(buf->b_hdr);
-
-               arc_cksum_verify(buf);
-               arc_buf_unwatch(buf);
-
-               if (type == ARC_BUFC_METADATA) {
-                       arc_buf_data_free(buf, zio_buf_free);
-                       arc_space_return(size, ARC_SPACE_META);
-               } else {
-                       ASSERT(type == ARC_BUFC_DATA);
-                       arc_buf_data_free(buf, zio_data_buf_free);
-                       arc_space_return(size, ARC_SPACE_DATA);
-               }
-
-               /* protected by hash lock, if in the hash table */
-               if (multilist_link_active(&buf->b_hdr->b_l1hdr.b_arc_node)) {
-                       uint64_t *cnt = &state->arcs_lsize[type];
-
-                       ASSERT(refcount_is_zero(
-                           &buf->b_hdr->b_l1hdr.b_refcnt));
-                       ASSERT(state != arc_anon && state != arc_l2c_only);
-
-                       ASSERT3U(*cnt, >=, size);
-                       atomic_add_64(cnt, -size);
-               }
+       arc_buf_t *buf;
+       arc_buf_hdr_t *hdr = arc_hdr_alloc(spa_load_guid(spa), size, size,
+           ZIO_COMPRESS_OFF, type);
+       ASSERT(!MUTEX_HELD(HDR_LOCK(hdr)));
 
-               (void) refcount_remove_many(&state->arcs_size, size, buf);
-               buf->b_data = NULL;
+       buf = NULL;
+       VERIFY0(arc_buf_alloc_impl(hdr, tag, B_FALSE, B_FALSE, &buf));
+       arc_buf_thaw(buf);
 
-               /*
-                * If we're destroying a duplicate buffer make sure
-                * that the appropriate statistics are updated.
-                */
-               if (buf->b_hdr->b_l1hdr.b_datacnt > 1 &&
-                   HDR_ISTYPE_DATA(buf->b_hdr)) {
-                       ARCSTAT_BUMPDOWN(arcstat_duplicate_buffers);
-                       ARCSTAT_INCR(arcstat_duplicate_buffers_size, -size);
-               }
-               ASSERT(buf->b_hdr->b_l1hdr.b_datacnt > 0);
-               buf->b_hdr->b_l1hdr.b_datacnt -= 1;
-       }
+       return (buf);
+}
 
-       /* only remove the buf if requested */
-       if (!remove)
-               return;
+/*
+ * Allocate a compressed buf in the same manner as arc_alloc_buf. Don't use this
+ * for bufs containing metadata.
+ */
+arc_buf_t *
+arc_alloc_compressed_buf(spa_t *spa, void *tag, uint64_t psize, uint64_t lsize,
+    enum zio_compress compression_type)
+{
+       arc_buf_hdr_t *hdr;
+       arc_buf_t *buf;
+       ASSERT3U(lsize, >, 0);
+       ASSERT3U(lsize, >=, psize);
+       ASSERT(compression_type > ZIO_COMPRESS_OFF);
+       ASSERT(compression_type < ZIO_COMPRESS_FUNCTIONS);
 
-       /* remove the buf from the hdr list */
-       for (bufp = &buf->b_hdr->b_l1hdr.b_buf; *bufp != buf;
-           bufp = &(*bufp)->b_next)
-               continue;
-       *bufp = buf->b_next;
-       buf->b_next = NULL;
+       hdr = arc_hdr_alloc(spa_load_guid(spa), psize, lsize,
+           compression_type, ARC_BUFC_DATA);
+       ASSERT(!MUTEX_HELD(HDR_LOCK(hdr)));
 
-       ASSERT(buf->b_efunc == NULL);
+       buf = NULL;
+       VERIFY0(arc_buf_alloc_impl(hdr, tag, B_TRUE, B_FALSE, &buf));
+       arc_buf_thaw(buf);
+       ASSERT3P(hdr->b_l1hdr.b_freeze_cksum, ==, NULL);
 
-       /* clean up the buf */
-       buf->b_hdr = NULL;
-       kmem_cache_free(buf_cache, buf);
+       return (buf);
 }
 
 static void
@@ -2050,50 +2932,20 @@ arc_hdr_l2hdr_destroy(arc_buf_hdr_t *hdr)
 {
        l2arc_buf_hdr_t *l2hdr = &hdr->b_l2hdr;
        l2arc_dev_t *dev = l2hdr->b_dev;
+       uint64_t asize = arc_hdr_size(hdr);
 
        ASSERT(MUTEX_HELD(&dev->l2ad_mtx));
        ASSERT(HDR_HAS_L2HDR(hdr));
 
        list_remove(&dev->l2ad_buflist, hdr);
 
-       /*
-        * We don't want to leak the b_tmp_cdata buffer that was
-        * allocated in l2arc_write_buffers()
-        */
-       arc_buf_l2_cdata_free(hdr);
-
-       /*
-        * If the l2hdr's b_daddr is equal to L2ARC_ADDR_UNSET, then
-        * this header is being processed by l2arc_write_buffers() (i.e.
-        * it's in the first stage of l2arc_write_buffers()).
-        * Re-affirming that truth here, just to serve as a reminder. If
-        * b_daddr does not equal L2ARC_ADDR_UNSET, then the header may or
-        * may not have its HDR_L2_WRITING flag set. (the write may have
-        * completed, in which case HDR_L2_WRITING will be false and the
-        * b_daddr field will point to the address of the buffer on disk).
-        */
-       IMPLY(l2hdr->b_daddr == L2ARC_ADDR_UNSET, HDR_L2_WRITING(hdr));
-
-       /*
-        * If b_daddr is equal to L2ARC_ADDR_UNSET, we're racing with
-        * l2arc_write_buffers(). Since we've just removed this header
-        * from the l2arc buffer list, this header will never reach the
-        * second stage of l2arc_write_buffers(), which increments the
-        * accounting stats for this header. Thus, we must be careful
-        * not to decrement them for this header either.
-        */
-       if (l2hdr->b_daddr != L2ARC_ADDR_UNSET) {
-               ARCSTAT_INCR(arcstat_l2_asize, -l2hdr->b_asize);
-               ARCSTAT_INCR(arcstat_l2_size, -hdr->b_size);
-
-               vdev_space_update(dev->l2ad_vdev,
-                   -l2hdr->b_asize, 0, 0);
+       ARCSTAT_INCR(arcstat_l2_asize, -asize);
+       ARCSTAT_INCR(arcstat_l2_size, -HDR_GET_LSIZE(hdr));
 
-               (void) refcount_remove_many(&dev->l2ad_alloc,
-                   l2hdr->b_asize, hdr);
-       }
+       vdev_space_update(dev->l2ad_vdev, -asize, 0, 0);
 
-       hdr->b_flags &= ~ARC_FLAG_HAS_L2HDR;
+       (void) refcount_remove_many(&dev->l2ad_alloc, asize, hdr);
+       arc_hdr_clear_flags(hdr, ARC_FLAG_HAS_L2HDR);
 }
 
 static void
@@ -2101,13 +2953,16 @@ arc_hdr_destroy(arc_buf_hdr_t *hdr)
 {
        if (HDR_HAS_L1HDR(hdr)) {
                ASSERT(hdr->b_l1hdr.b_buf == NULL ||
-                   hdr->b_l1hdr.b_datacnt > 0);
+                   hdr->b_l1hdr.b_bufcnt > 0);
                ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
                ASSERT3P(hdr->b_l1hdr.b_state, ==, arc_anon);
        }
        ASSERT(!HDR_IO_IN_PROGRESS(hdr));
        ASSERT(!HDR_IN_HASH_TABLE(hdr));
 
+       if (!HDR_EMPTY(hdr))
+               buf_discard_identity(hdr);
+
        if (HDR_HAS_L2HDR(hdr)) {
                l2arc_dev_t *dev = hdr->b_l2hdr.b_dev;
                boolean_t buflist_held = MUTEX_HELD(&dev->l2ad_mtx);
@@ -2131,33 +2986,14 @@ arc_hdr_destroy(arc_buf_hdr_t *hdr)
                        mutex_exit(&dev->l2ad_mtx);
        }
 
-       if (!BUF_EMPTY(hdr))
-               buf_discard_identity(hdr);
+       if (HDR_HAS_L1HDR(hdr)) {
+               arc_cksum_free(hdr);
 
-       if (hdr->b_freeze_cksum != NULL) {
-               kmem_free(hdr->b_freeze_cksum, sizeof (zio_cksum_t));
-               hdr->b_freeze_cksum = NULL;
-       }
+               while (hdr->b_l1hdr.b_buf != NULL)
+                       arc_buf_destroy_impl(hdr->b_l1hdr.b_buf);
 
-       if (HDR_HAS_L1HDR(hdr)) {
-               while (hdr->b_l1hdr.b_buf) {
-                       arc_buf_t *buf = hdr->b_l1hdr.b_buf;
-
-                       if (buf->b_efunc != NULL) {
-                               mutex_enter(&arc_user_evicts_lock);
-                               mutex_enter(&buf->b_evict_lock);
-                               ASSERT(buf->b_hdr != NULL);
-                               arc_buf_destroy(hdr->b_l1hdr.b_buf, FALSE);
-                               hdr->b_l1hdr.b_buf = buf->b_next;
-                               buf->b_hdr = &arc_eviction_hdr;
-                               buf->b_next = arc_eviction_list;
-                               arc_eviction_list = buf;
-                               mutex_exit(&buf->b_evict_lock);
-                               cv_signal(&arc_user_evicts_cv);
-                               mutex_exit(&arc_user_evicts_lock);
-                       } else {
-                               arc_buf_destroy(hdr->b_l1hdr.b_buf, TRUE);
-                       }
+               if (hdr->b_l1hdr.b_pdata != NULL) {
+                       arc_hdr_free_pdata(hdr);
                }
        }
 
@@ -2172,133 +3008,29 @@ arc_hdr_destroy(arc_buf_hdr_t *hdr)
 }
 
 void
-arc_buf_free(arc_buf_t *buf, void *tag)
-{
-       arc_buf_hdr_t *hdr = buf->b_hdr;
-       int hashed = hdr->b_l1hdr.b_state != arc_anon;
-
-       ASSERT(buf->b_efunc == NULL);
-       ASSERT(buf->b_data != NULL);
-
-       if (hashed) {
-               kmutex_t *hash_lock = HDR_LOCK(hdr);
-
-               mutex_enter(hash_lock);
-               hdr = buf->b_hdr;
-               ASSERT3P(hash_lock, ==, HDR_LOCK(hdr));
-
-               (void) remove_reference(hdr, hash_lock, tag);
-               if (hdr->b_l1hdr.b_datacnt > 1) {
-                       arc_buf_destroy(buf, TRUE);
-               } else {
-                       ASSERT(buf == hdr->b_l1hdr.b_buf);
-                       ASSERT(buf->b_efunc == NULL);
-                       hdr->b_flags |= ARC_FLAG_BUF_AVAILABLE;
-               }
-               mutex_exit(hash_lock);
-       } else if (HDR_IO_IN_PROGRESS(hdr)) {
-               int destroy_hdr;
-               /*
-                * We are in the middle of an async write.  Don't destroy
-                * this buffer unless the write completes before we finish
-                * decrementing the reference count.
-                */
-               mutex_enter(&arc_user_evicts_lock);
-               (void) remove_reference(hdr, NULL, tag);
-               ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
-               destroy_hdr = !HDR_IO_IN_PROGRESS(hdr);
-               mutex_exit(&arc_user_evicts_lock);
-               if (destroy_hdr)
-                       arc_hdr_destroy(hdr);
-       } else {
-               if (remove_reference(hdr, NULL, tag) > 0)
-                       arc_buf_destroy(buf, TRUE);
-               else
-                       arc_hdr_destroy(hdr);
-       }
-}
-
-boolean_t
-arc_buf_remove_ref(arc_buf_t *buf, void* tag)
+arc_buf_destroy(arc_buf_t *buf, void* tag)
 {
        arc_buf_hdr_t *hdr = buf->b_hdr;
        kmutex_t *hash_lock = HDR_LOCK(hdr);
-       boolean_t no_callback = (buf->b_efunc == NULL);
 
        if (hdr->b_l1hdr.b_state == arc_anon) {
-               ASSERT(hdr->b_l1hdr.b_datacnt == 1);
-               arc_buf_free(buf, tag);
-               return (no_callback);
+               ASSERT3U(hdr->b_l1hdr.b_bufcnt, ==, 1);
+               ASSERT(!HDR_IO_IN_PROGRESS(hdr));
+               VERIFY0(remove_reference(hdr, NULL, tag));
+               arc_hdr_destroy(hdr);
+               return;
        }
 
        mutex_enter(hash_lock);
-       hdr = buf->b_hdr;
-       ASSERT(hdr->b_l1hdr.b_datacnt > 0);
+       ASSERT3P(hdr, ==, buf->b_hdr);
+       ASSERT(hdr->b_l1hdr.b_bufcnt > 0);
        ASSERT3P(hash_lock, ==, HDR_LOCK(hdr));
-       ASSERT(hdr->b_l1hdr.b_state != arc_anon);
-       ASSERT(buf->b_data != NULL);
+       ASSERT3P(hdr->b_l1hdr.b_state, !=, arc_anon);
+       ASSERT3P(buf->b_data, !=, NULL);
 
        (void) remove_reference(hdr, hash_lock, tag);
-       if (hdr->b_l1hdr.b_datacnt > 1) {
-               if (no_callback)
-                       arc_buf_destroy(buf, TRUE);
-       } else if (no_callback) {
-               ASSERT(hdr->b_l1hdr.b_buf == buf && buf->b_next == NULL);
-               ASSERT(buf->b_efunc == NULL);
-               hdr->b_flags |= ARC_FLAG_BUF_AVAILABLE;
-       }
-       ASSERT(no_callback || hdr->b_l1hdr.b_datacnt > 1 ||
-           refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
+       arc_buf_destroy_impl(buf);
        mutex_exit(hash_lock);
-       return (no_callback);
-}
-
-uint64_t
-arc_buf_size(arc_buf_t *buf)
-{
-       return (buf->b_hdr->b_size);
-}
-
-/*
- * Called from the DMU to determine if the current buffer should be
- * evicted. In order to ensure proper locking, the eviction must be initiated
- * from the DMU. Return true if the buffer is associated with user data and
- * duplicate buffers still exist.
- */
-boolean_t
-arc_buf_eviction_needed(arc_buf_t *buf)
-{
-       arc_buf_hdr_t *hdr;
-       boolean_t evict_needed = B_FALSE;
-
-       if (zfs_disable_dup_eviction)
-               return (B_FALSE);
-
-       mutex_enter(&buf->b_evict_lock);
-       hdr = buf->b_hdr;
-       if (hdr == NULL) {
-               /*
-                * We are in arc_do_user_evicts(); let that function
-                * perform the eviction.
-                */
-               ASSERT(buf->b_data == NULL);
-               mutex_exit(&buf->b_evict_lock);
-               return (B_FALSE);
-       } else if (buf->b_data == NULL) {
-               /*
-                * We have already been added to the arc eviction list;
-                * recommend eviction.
-                */
-               ASSERT3P(hdr, ==, &arc_eviction_hdr);
-               mutex_exit(&buf->b_evict_lock);
-               return (B_TRUE);
-       }
-
-       if (hdr->b_l1hdr.b_datacnt > 1 && HDR_ISTYPE_DATA(hdr))
-               evict_needed = B_TRUE;
-
-       mutex_exit(&buf->b_evict_lock);
-       return (evict_needed);
 }
 
 /*
@@ -2325,11 +3057,11 @@ arc_evict_hdr(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
        state = hdr->b_l1hdr.b_state;
        if (GHOST_STATE(state)) {
                ASSERT(!HDR_IO_IN_PROGRESS(hdr));
-               ASSERT(hdr->b_l1hdr.b_buf == NULL);
+               ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
 
                /*
                 * l2arc_write_buffers() relies on a header's L1 portion
-                * (i.e. its b_tmp_cdata field) during its write phase.
+                * (i.e. its b_pdata field) during its write phase.
                 * Thus, we cannot push a header onto the arc_l2c_only
                 * state (removing its L1 piece) until the header is
                 * done being written to the l2arc.
@@ -2340,11 +3072,12 @@ arc_evict_hdr(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
                }
 
                ARCSTAT_BUMP(arcstat_deleted);
-               bytes_evicted += hdr->b_size;
+               bytes_evicted += HDR_GET_LSIZE(hdr);
 
                DTRACE_PROBE1(arc__delete, arc_buf_hdr_t *, hdr);
 
                if (HDR_HAS_L2HDR(hdr)) {
+                       ASSERT(hdr->b_l1hdr.b_pdata == NULL);
                        /*
                         * This buffer is cached on the 2nd Level ARC;
                         * don't destroy the header.
@@ -2376,7 +3109,6 @@ arc_evict_hdr(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
        }
 
        ASSERT0(refcount_count(&hdr->b_l1hdr.b_refcnt));
-       ASSERT3U(hdr->b_l1hdr.b_datacnt, >, 0);
        while (hdr->b_l1hdr.b_buf) {
                arc_buf_t *buf = hdr->b_l1hdr.b_buf;
                if (!mutex_tryenter(&buf->b_evict_lock)) {
@@ -2384,37 +3116,39 @@ arc_evict_hdr(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
                        break;
                }
                if (buf->b_data != NULL)
-                       bytes_evicted += hdr->b_size;
-               if (buf->b_efunc != NULL) {
-                       mutex_enter(&arc_user_evicts_lock);
-                       arc_buf_destroy(buf, FALSE);
-                       hdr->b_l1hdr.b_buf = buf->b_next;
-                       buf->b_hdr = &arc_eviction_hdr;
-                       buf->b_next = arc_eviction_list;
-                       arc_eviction_list = buf;
-                       cv_signal(&arc_user_evicts_cv);
-                       mutex_exit(&arc_user_evicts_lock);
-                       mutex_exit(&buf->b_evict_lock);
-               } else {
-                       mutex_exit(&buf->b_evict_lock);
-                       arc_buf_destroy(buf, TRUE);
-               }
+                       bytes_evicted += HDR_GET_LSIZE(hdr);
+               mutex_exit(&buf->b_evict_lock);
+               arc_buf_destroy_impl(buf);
        }
 
        if (HDR_HAS_L2HDR(hdr)) {
-               ARCSTAT_INCR(arcstat_evict_l2_cached, hdr->b_size);
+               ARCSTAT_INCR(arcstat_evict_l2_cached, HDR_GET_LSIZE(hdr));
        } else {
-               if (l2arc_write_eligible(hdr->b_spa, hdr))
-                       ARCSTAT_INCR(arcstat_evict_l2_eligible, hdr->b_size);
-               else
-                       ARCSTAT_INCR(arcstat_evict_l2_ineligible, hdr->b_size);
+               if (l2arc_write_eligible(hdr->b_spa, hdr)) {
+                       ARCSTAT_INCR(arcstat_evict_l2_eligible,
+                           HDR_GET_LSIZE(hdr));
+               } else {
+                       ARCSTAT_INCR(arcstat_evict_l2_ineligible,
+                           HDR_GET_LSIZE(hdr));
+               }
        }
 
-       if (hdr->b_l1hdr.b_datacnt == 0) {
+       if (hdr->b_l1hdr.b_bufcnt == 0) {
+               arc_cksum_free(hdr);
+
+               bytes_evicted += arc_hdr_size(hdr);
+
+               /*
+                * If this hdr is being evicted and has a compressed
+                * buffer then we discard it here before we change states.
+                * This ensures that the accounting is updated correctly
+                * in arc_free_data_buf().
+                */
+               arc_hdr_free_pdata(hdr);
+
                arc_change_state(evicted_state, hdr, hash_lock);
                ASSERT(HDR_IN_HASH_TABLE(hdr));
-               hdr->b_flags |= ARC_FLAG_IN_HASH_TABLE;
-               hdr->b_flags &= ~ARC_FLAG_BUF_AVAILABLE;
+               arc_hdr_set_flags(hdr, ARC_FLAG_IN_HASH_TABLE);
                DTRACE_PROBE1(arc__evict, arc_buf_hdr_t *, hdr);
        }
 
@@ -2589,6 +3323,18 @@ arc_evict_state(arc_state_t *state, uint64_t spa, int64_t bytes,
         * we're evicting all available buffers.
         */
        while (total_evicted < bytes || bytes == ARC_EVICT_ALL) {
+               int sublist_idx = multilist_get_random_index(ml);
+               uint64_t scan_evicted = 0;
+
+               /*
+                * Try to reduce pinned dnodes with a floor of arc_dnode_limit.
+                * Request that 10% of the LRUs be scanned by the superblock
+                * shrinker.
+                */
+               if (type == ARC_BUFC_DATA && arc_dnode_size > arc_dnode_limit)
+                       arc_prune_async((arc_dnode_size - arc_dnode_limit) /
+                           sizeof (dnode_t) / zfs_arc_dnode_reduce_percent);
+
                /*
                 * Start eviction using a randomly selected sublist,
                 * this is to try and evenly balance eviction across all
@@ -2596,9 +3342,6 @@ arc_evict_state(arc_state_t *state, uint64_t spa, int64_t bytes,
                 * (e.g. index 0) would cause evictions to favor certain
                 * sublists over others.
                 */
-               int sublist_idx = multilist_get_random_index(ml);
-               uint64_t scan_evicted = 0;
-
                for (i = 0; i < num_sublists; i++) {
                        uint64_t bytes_remaining;
                        uint64_t bytes_evicted;
@@ -2661,12 +3404,12 @@ arc_evict_state(arc_state_t *state, uint64_t spa, int64_t bytes,
  * Flush all "evictable" data of the given type from the arc state
  * specified. This will not evict any "active" buffers (i.e. referenced).
  *
- * When 'retry' is set to FALSE, the function will make a single pass
+ * When 'retry' is set to B_FALSE, the function will make a single pass
  * over the state and evict any buffers that it can. Since it doesn't
  * continually retry the eviction, it might end up leaving some buffers
  * in the ARC due to lock misses.
  *
- * When 'retry' is set to TRUE, the function will continually retry the
+ * When 'retry' is set to B_TRUE, the function will continually retry the
  * eviction until *all* evictable buffers have been removed from the
  * state. As a result, if concurrent insertions into the state are
  * allowed (e.g. if the ARC isn't shutting down), this function might
@@ -2678,7 +3421,7 @@ arc_flush_state(arc_state_t *state, uint64_t spa, arc_buf_contents_t type,
 {
        uint64_t evicted = 0;
 
-       while (state->arcs_lsize[type] != 0) {
+       while (refcount_count(&state->arcs_esize[type]) != 0) {
                evicted += arc_evict_state(state, spa, ARC_EVICT_ALL, type);
 
                if (!retry)
@@ -2729,7 +3472,11 @@ arc_prune_async(int64_t adjust)
 
                refcount_add(&ap->p_refcnt, ap->p_pfunc);
                ap->p_adjust = adjust;
-               taskq_dispatch(arc_prune_taskq, arc_prune_task, ap, TQ_SLEEP);
+               if (taskq_dispatch(arc_prune_taskq, arc_prune_task,
+                   ap, TQ_SLEEP) == 0) {
+                       refcount_remove(&ap->p_refcnt, ap->p_pfunc);
+                       continue;
+               }
                ARCSTAT_BUMP(arcstat_prune);
        }
        mutex_exit(&arc_prune_mtx);
@@ -2749,8 +3496,8 @@ arc_adjust_impl(arc_state_t *state, uint64_t spa, int64_t bytes,
 {
        int64_t delta;
 
-       if (bytes > 0 && state->arcs_lsize[type] > 0) {
-               delta = MIN(state->arcs_lsize[type], bytes);
+       if (bytes > 0 && refcount_count(&state->arcs_esize[type]) > 0) {
+               delta = MIN(refcount_count(&state->arcs_esize[type]), bytes);
                return (arc_evict_state(state, spa, delta, type));
        }
 
@@ -2777,7 +3524,7 @@ arc_adjust_impl(arc_state_t *state, uint64_t spa, int64_t bytes,
 static uint64_t
 arc_adjust_meta_balanced(void)
 {
-       int64_t adjustmnt, delta, prune = 0;
+       int64_t delta, prune = 0, adjustmnt;
        uint64_t total_evicted = 0;
        arc_buf_contents_t type = ARC_BUFC_DATA;
        int restarts = MAX(zfs_arc_meta_adjust_restarts, 0);
@@ -2793,8 +3540,9 @@ restart:
         */
        adjustmnt = arc_meta_used - arc_meta_limit;
 
-       if (adjustmnt > 0 && arc_mru->arcs_lsize[type] > 0) {
-               delta = MIN(arc_mru->arcs_lsize[type], adjustmnt);
+       if (adjustmnt > 0 && refcount_count(&arc_mru->arcs_esize[type]) > 0) {
+               delta = MIN(refcount_count(&arc_mru->arcs_esize[type]),
+                   adjustmnt);
                total_evicted += arc_adjust_impl(arc_mru, 0, delta, type);
                adjustmnt -= delta;
        }
@@ -2809,23 +3557,26 @@ restart:
         * simply decrement the amount of data evicted from the MRU.
         */
 
-       if (adjustmnt > 0 && arc_mfu->arcs_lsize[type] > 0) {
-               delta = MIN(arc_mfu->arcs_lsize[type], adjustmnt);
+       if (adjustmnt > 0 && refcount_count(&arc_mfu->arcs_esize[type]) > 0) {
+               delta = MIN(refcount_count(&arc_mfu->arcs_esize[type]),
+                   adjustmnt);
                total_evicted += arc_adjust_impl(arc_mfu, 0, delta, type);
        }
 
        adjustmnt = arc_meta_used - arc_meta_limit;
 
-       if (adjustmnt > 0 && arc_mru_ghost->arcs_lsize[type] > 0) {
+       if (adjustmnt > 0 &&
+           refcount_count(&arc_mru_ghost->arcs_esize[type]) > 0) {
                delta = MIN(adjustmnt,
-                   arc_mru_ghost->arcs_lsize[type]);
+                   refcount_count(&arc_mru_ghost->arcs_esize[type]));
                total_evicted += arc_adjust_impl(arc_mru_ghost, 0, delta, type);
                adjustmnt -= delta;
        }
 
-       if (adjustmnt > 0 && arc_mfu_ghost->arcs_lsize[type] > 0) {
+       if (adjustmnt > 0 &&
+           refcount_count(&arc_mfu_ghost->arcs_esize[type]) > 0) {
                delta = MIN(adjustmnt,
-                   arc_mfu_ghost->arcs_lsize[type]);
+                   refcount_count(&arc_mfu_ghost->arcs_esize[type]));
                total_evicted += arc_adjust_impl(arc_mfu_ghost, 0, delta, type);
        }
 
@@ -2882,7 +3633,7 @@ arc_adjust_meta_only(void)
        /*
         * Similar to the above, we want to evict enough bytes to get us
         * below the meta limit, but not so much as to drop us below the
-        * space alloted to the MFU (which is defined as arc_c - arc_p).
+        * space allotted to the MFU (which is defined as arc_c - arc_p).
         */
        target = MIN((int64_t)(arc_meta_used - arc_meta_limit),
            (int64_t)(refcount_count(&arc_mfu->arcs_size) - (arc_c - arc_p)));
@@ -3121,36 +3872,13 @@ arc_adjust(void)
        return (total_evicted);
 }
 
-static void
-arc_do_user_evicts(void)
-{
-       mutex_enter(&arc_user_evicts_lock);
-       while (arc_eviction_list != NULL) {
-               arc_buf_t *buf = arc_eviction_list;
-               arc_eviction_list = buf->b_next;
-               mutex_enter(&buf->b_evict_lock);
-               buf->b_hdr = NULL;
-               mutex_exit(&buf->b_evict_lock);
-               mutex_exit(&arc_user_evicts_lock);
-
-               if (buf->b_efunc != NULL)
-                       VERIFY0(buf->b_efunc(buf->b_private));
-
-               buf->b_efunc = NULL;
-               buf->b_private = NULL;
-               kmem_cache_free(buf_cache, buf);
-               mutex_enter(&arc_user_evicts_lock);
-       }
-       mutex_exit(&arc_user_evicts_lock);
-}
-
 void
 arc_flush(spa_t *spa, boolean_t retry)
 {
        uint64_t guid = 0;
 
        /*
-        * If retry is TRUE, a spa must not be specified since we have
+        * If retry is B_TRUE, a spa must not be specified since we have
         * no good way to determine if all of a spa's buffers have been
         * evicted from an arc state.
         */
@@ -3170,9 +3898,6 @@ arc_flush(spa_t *spa, boolean_t retry)
 
        (void) arc_flush_state(arc_mfu_ghost, guid, ARC_BUFC_DATA, retry);
        (void) arc_flush_state(arc_mfu_ghost, guid, ARC_BUFC_METADATA, retry);
-
-       arc_do_user_evicts();
-       ASSERT(spa || arc_eviction_list == NULL);
 }
 
 void
@@ -3315,15 +4040,15 @@ arc_available_memory(void)
        /*
         * If zio data pages are being allocated out of a separate heap segment,
         * then enforce that the size of available vmem for this arena remains
-        * above about 1/16th free.
+        * above about 1/4th (1/(2^arc_zio_arena_free_shift)) free.
         *
-        * Note: The 1/16th arena free requirement was put in place
-        * to aggressively evict memory from the arc in order to avoid
-        * memory fragmentation issues.
+        * Note that reducing the arc_zio_arena_free_shift keeps more virtual
+        * memory (in the zio_arena) free, which can avoid memory
+        * fragmentation issues.
         */
        if (zio_arena != NULL) {
-               n = vmem_size(zio_arena, VMEM_FREE) -
-                   (vmem_size(zio_arena, VMEM_ALLOC) >> 4);
+               n = vmem_size(zio_arena, VMEM_FREE) - (vmem_size(zio_arena,
+                   VMEM_ALLOC) >> arc_zio_arena_free_shift);
                if (n < lowest) {
                        lowest = n;
                        r = FMR_ZIO_ARENA;
@@ -3343,7 +4068,7 @@ arc_available_memory(void)
 
 /*
  * Determine if the system is under memory pressure and is asking
- * to reclaim memory. A return value of TRUE indicates that the system
+ * to reclaim memory. A return value of B_TRUE indicates that the system
  * is under memory pressure and that the arc should adjust accordingly.
  */
 static boolean_t
@@ -3419,7 +4144,7 @@ static void
 arc_reclaim_thread(void)
 {
        fstrans_cookie_t        cookie = spl_fstrans_mark();
-       clock_t                 growtime = 0;
+       hrtime_t                growtime = 0;
        callb_cpr_t             cpr;
 
        CALLB_CPR_INIT(&cpr, &arc_reclaim_lock, callb_generic_cpr, FTAG);
@@ -3432,6 +4157,21 @@ arc_reclaim_thread(void)
 
                arc_tuning_update();
 
+               /*
+                * This is necessary in order for the mdb ::arc dcmd to
+                * show up to date information. Since the ::arc command
+                * does not call the kstat's update function, without
+                * this call, the command may show stale stats for the
+                * anon, mru, mru_ghost, mfu, and mfu_ghost lists. Even
+                * with this change, the data might be up to 1 second
+                * out of date; but that should suffice. The arc_state_t
+                * structures can be queried directly if more accurate
+                * information is needed.
+                */
+#ifndef __linux__
+               if (arc_ksp != NULL)
+                       arc_ksp->ks_update(arc_ksp, KSTAT_READ);
+#endif
                mutex_exit(&arc_reclaim_lock);
 
                if (free_memory < 0) {
@@ -3443,7 +4183,7 @@ arc_reclaim_thread(void)
                         * Wait at least zfs_grow_retry (default 5) seconds
                         * before considering growing.
                         */
-                       growtime = ddi_get_lbolt() + (arc_grow_retry * hz);
+                       growtime = gethrtime() + SEC2NSEC(arc_grow_retry);
 
                        arc_kmem_reap_now();
 
@@ -3462,7 +4202,7 @@ arc_reclaim_thread(void)
                        }
                } else if (free_memory < arc_c >> arc_no_grow_shift) {
                        arc_no_grow = B_TRUE;
-               } else if (ddi_get_lbolt() >= growtime) {
+               } else if (gethrtime() >= growtime) {
                        arc_no_grow = B_FALSE;
                }
 
@@ -3495,66 +4235,19 @@ arc_reclaim_thread(void)
                         * even if we aren't being signalled)
                         */
                        CALLB_CPR_SAFE_BEGIN(&cpr);
-                       (void) cv_timedwait_sig(&arc_reclaim_thread_cv,
-                           &arc_reclaim_lock, ddi_get_lbolt() + hz);
+                       (void) cv_timedwait_sig_hires(&arc_reclaim_thread_cv,
+                           &arc_reclaim_lock, SEC2NSEC(1), MSEC2NSEC(1), 0);
                        CALLB_CPR_SAFE_END(&cpr, &arc_reclaim_lock);
                }
        }
 
-       arc_reclaim_thread_exit = FALSE;
+       arc_reclaim_thread_exit = B_FALSE;
        cv_broadcast(&arc_reclaim_thread_cv);
        CALLB_CPR_EXIT(&cpr);           /* drops arc_reclaim_lock */
        spl_fstrans_unmark(cookie);
        thread_exit();
 }
 
-static void
-arc_user_evicts_thread(void)
-{
-       fstrans_cookie_t        cookie = spl_fstrans_mark();
-       callb_cpr_t cpr;
-
-       CALLB_CPR_INIT(&cpr, &arc_user_evicts_lock, callb_generic_cpr, FTAG);
-
-       mutex_enter(&arc_user_evicts_lock);
-       while (!arc_user_evicts_thread_exit) {
-               mutex_exit(&arc_user_evicts_lock);
-
-               arc_do_user_evicts();
-
-               /*
-                * This is necessary in order for the mdb ::arc dcmd to
-                * show up to date information. Since the ::arc command
-                * does not call the kstat's update function, without
-                * this call, the command may show stale stats for the
-                * anon, mru, mru_ghost, mfu, and mfu_ghost lists. Even
-                * with this change, the data might be up to 1 second
-                * out of date; but that should suffice. The arc_state_t
-                * structures can be queried directly if more accurate
-                * information is needed.
-                */
-               if (arc_ksp != NULL)
-                       arc_ksp->ks_update(arc_ksp, KSTAT_READ);
-
-               mutex_enter(&arc_user_evicts_lock);
-
-               /*
-                * Block until signaled, or after one second (we need to
-                * call the arc's kstat update function regularly).
-                */
-               CALLB_CPR_SAFE_BEGIN(&cpr);
-               (void) cv_timedwait_sig(&arc_user_evicts_cv,
-                   &arc_user_evicts_lock, ddi_get_lbolt() + hz);
-               CALLB_CPR_SAFE_END(&cpr, &arc_user_evicts_lock);
-       }
-
-       arc_user_evicts_thread_exit = FALSE;
-       cv_broadcast(&arc_user_evicts_cv);
-       CALLB_CPR_EXIT(&cpr);           /* drops arc_user_evicts_lock */
-       spl_fstrans_unmark(cookie);
-       thread_exit();
-}
-
 #ifdef _KERNEL
 /*
  * Determine the amount of memory eligible for eviction contained in the
@@ -3604,15 +4297,15 @@ arc_user_evicts_thread(void)
 static uint64_t
 arc_evictable_memory(void) {
        uint64_t arc_clean =
-           arc_mru->arcs_lsize[ARC_BUFC_DATA] +
-           arc_mru->arcs_lsize[ARC_BUFC_METADATA] +
-           arc_mfu->arcs_lsize[ARC_BUFC_DATA] +
-           arc_mfu->arcs_lsize[ARC_BUFC_METADATA];
+           refcount_count(&arc_mru->arcs_esize[ARC_BUFC_DATA]) +
+           refcount_count(&arc_mru->arcs_esize[ARC_BUFC_METADATA]) +
+           refcount_count(&arc_mfu->arcs_esize[ARC_BUFC_DATA]) +
+           refcount_count(&arc_mfu->arcs_esize[ARC_BUFC_METADATA]);
        uint64_t ghost_clean =
-           arc_mru_ghost->arcs_lsize[ARC_BUFC_DATA] +
-           arc_mru_ghost->arcs_lsize[ARC_BUFC_METADATA] +
-           arc_mfu_ghost->arcs_lsize[ARC_BUFC_DATA] +
-           arc_mfu_ghost->arcs_lsize[ARC_BUFC_METADATA];
+           refcount_count(&arc_mru_ghost->arcs_esize[ARC_BUFC_DATA]) +
+           refcount_count(&arc_mru_ghost->arcs_esize[ARC_BUFC_METADATA]) +
+           refcount_count(&arc_mfu_ghost->arcs_esize[ARC_BUFC_DATA]) +
+           refcount_count(&arc_mfu_ghost->arcs_esize[ARC_BUFC_METADATA]);
        uint64_t arc_dirty = MAX((int64_t)arc_size - (int64_t)arc_clean, 0);
 
        if (arc_dirty >= arc_c_min)
@@ -3788,18 +4481,17 @@ arc_is_overflowing(void)
 }
 
 /*
- * The buffer, supplied as the first argument, needs a data block. If we
- * are hitting the hard limit for the cache size, we must sleep, waiting
- * for the eviction thread to catch up. If we're past the target size
- * but below the hard limit, we'll only signal the reclaim thread and
- * continue on.
+ * Allocate a block and return it to the caller. If we are hitting the
+ * hard limit for the cache size, we must sleep, waiting for the eviction
+ * thread to catch up. If we're past the target size but below the hard
+ * limit, we'll only signal the reclaim thread and continue on.
  */
-static void
-arc_get_data_buf(arc_buf_t *buf)
+static void *
+arc_get_data_buf(arc_buf_hdr_t *hdr, uint64_t size, void *tag)
 {
-       arc_state_t             *state = buf->b_hdr->b_l1hdr.b_state;
-       uint64_t                size = buf->b_hdr->b_size;
-       arc_buf_contents_t      type = arc_buf_type(buf->b_hdr);
+       void *datap = NULL;
+       arc_state_t             *state = hdr->b_l1hdr.b_state;
+       arc_buf_contents_t      type = arc_buf_type(hdr);
 
        arc_adapt(size, state);
 
@@ -3839,12 +4531,13 @@ arc_get_data_buf(arc_buf_t *buf)
                mutex_exit(&arc_reclaim_lock);
        }
 
+       VERIFY3U(hdr->b_type, ==, type);
        if (type == ARC_BUFC_METADATA) {
-               buf->b_data = zio_buf_alloc(size);
+               datap = zio_buf_alloc(size);
                arc_space_consume(size, ARC_SPACE_META);
        } else {
                ASSERT(type == ARC_BUFC_DATA);
-               buf->b_data = zio_data_buf_alloc(size);
+               datap = zio_data_buf_alloc(size);
                arc_space_consume(size, ARC_SPACE_DATA);
        }
 
@@ -3852,11 +4545,9 @@ arc_get_data_buf(arc_buf_t *buf)
         * Update the state size.  Note that ghost states have a
         * "ghost size" and so don't need to be updated.
         */
-       if (!GHOST_STATE(buf->b_hdr->b_l1hdr.b_state)) {
-               arc_buf_hdr_t *hdr = buf->b_hdr;
-               arc_state_t *state = hdr->b_l1hdr.b_state;
+       if (!GHOST_STATE(state)) {
 
-               (void) refcount_add_many(&state->arcs_size, size, buf);
+               (void) refcount_add_many(&state->arcs_size, size, tag);
 
                /*
                 * If this is reached via arc_read, the link is
@@ -3869,9 +4560,10 @@ arc_get_data_buf(arc_buf_t *buf)
                 */
                if (multilist_link_active(&hdr->b_l1hdr.b_arc_node)) {
                        ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
-                       atomic_add_64(&hdr->b_l1hdr.b_state->arcs_lsize[type],
-                           size);
+                       (void) refcount_add_many(&state->arcs_esize[type],
+                           size, tag);
                }
+
                /*
                 * If we are growing the cache, and we are adding anonymous
                 * data, and we have outgrown arc_p, update arc_p
@@ -3881,6 +4573,37 @@ arc_get_data_buf(arc_buf_t *buf)
                    refcount_count(&arc_mru->arcs_size) > arc_p))
                        arc_p = MIN(arc_c, arc_p + size);
        }
+       return (datap);
+}
+
+/*
+ * Free the arc data buffer.
+ */
+static void
+arc_free_data_buf(arc_buf_hdr_t *hdr, void *data, uint64_t size, void *tag)
+{
+       arc_state_t *state = hdr->b_l1hdr.b_state;
+       arc_buf_contents_t type = arc_buf_type(hdr);
+
+       /* protected by hash lock, if in the hash table */
+       if (multilist_link_active(&hdr->b_l1hdr.b_arc_node)) {
+               ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
+               ASSERT(state != arc_anon && state != arc_l2c_only);
+
+               (void) refcount_remove_many(&state->arcs_esize[type],
+                   size, tag);
+       }
+       (void) refcount_remove_many(&state->arcs_size, size, tag);
+
+       VERIFY3U(hdr->b_type, ==, type);
+       if (type == ARC_BUFC_METADATA) {
+               zio_buf_free(data, size);
+               arc_space_return(size, ARC_SPACE_META);
+       } else {
+               ASSERT(type == ARC_BUFC_DATA);
+               zio_data_buf_free(data, size);
+               arc_space_return(size, ARC_SPACE_DATA);
+       }
 }
 
 /*
@@ -3924,7 +4647,7 @@ arc_access(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
                                ASSERT(multilist_link_active(
                                    &hdr->b_l1hdr.b_arc_node));
                        } else {
-                               hdr->b_flags &= ~ARC_FLAG_PREFETCH;
+                               arc_hdr_clear_flags(hdr, ARC_FLAG_PREFETCH);
                                atomic_inc_32(&hdr->b_l1hdr.b_mru_hits);
                                ARCSTAT_BUMP(arcstat_mru_hits);
                        }
@@ -3961,7 +4684,7 @@ arc_access(arc_buf_hdr_t *hdr, kmutex_t *hash_lock)
                if (HDR_PREFETCH(hdr)) {
                        new_state = arc_mru;
                        if (refcount_count(&hdr->b_l1hdr.b_refcnt) > 0)
-                               hdr->b_flags &= ~ARC_FLAG_PREFETCH;
+                               arc_hdr_clear_flags(hdr, ARC_FLAG_PREFETCH);
                        DTRACE_PROBE1(new_state__mru, arc_buf_hdr_t *, hdr);
                } else {
                        new_state = arc_mfu;
@@ -4034,8 +4757,8 @@ void
 arc_bcopy_func(zio_t *zio, arc_buf_t *buf, void *arg)
 {
        if (zio == NULL || zio->io_error == 0)
-               bcopy(buf->b_data, arg, buf->b_hdr->b_size);
-       VERIFY(arc_buf_remove_ref(buf, arg));
+               bcopy(buf->b_data, arg, arc_buf_size(buf));
+       arc_buf_destroy(buf, arg);
 }
 
 /* a generic arc_done_func_t */
@@ -4044,7 +4767,7 @@ arc_getbuf_func(zio_t *zio, arc_buf_t *buf, void *arg)
 {
        arc_buf_t **bufp = arg;
        if (zio && zio->io_error) {
-               VERIFY(arc_buf_remove_ref(buf, arg));
+               arc_buf_destroy(buf, arg);
                *bufp = NULL;
        } else {
                *bufp = buf;
@@ -4052,19 +4775,32 @@ arc_getbuf_func(zio_t *zio, arc_buf_t *buf, void *arg)
        }
 }
 
+static void
+arc_hdr_verify(arc_buf_hdr_t *hdr, blkptr_t *bp)
+{
+       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp)) {
+               ASSERT3U(HDR_GET_PSIZE(hdr), ==, 0);
+               ASSERT3U(HDR_GET_COMPRESS(hdr), ==, ZIO_COMPRESS_OFF);
+       } else {
+               if (HDR_COMPRESSION_ENABLED(hdr)) {
+                       ASSERT3U(HDR_GET_COMPRESS(hdr), ==,
+                           BP_GET_COMPRESS(bp));
+               }
+               ASSERT3U(HDR_GET_LSIZE(hdr), ==, BP_GET_LSIZE(bp));
+               ASSERT3U(HDR_GET_PSIZE(hdr), ==, BP_GET_PSIZE(bp));
+       }
+}
+
 static void
 arc_read_done(zio_t *zio)
 {
-       arc_buf_hdr_t   *hdr;
-       arc_buf_t       *buf;
-       arc_buf_t       *abuf;  /* buffer we're assigning to callback */
+       arc_buf_hdr_t   *hdr = zio->io_private;
        kmutex_t        *hash_lock = NULL;
-       arc_callback_t  *callback_list, *acb;
-       int             freeable = FALSE;
-
-       buf = zio->io_private;
-       hdr = buf->b_hdr;
-
+       arc_callback_t  *callback_list;
+       arc_callback_t  *acb;
+       boolean_t       freeable = B_FALSE;
+       boolean_t       no_zio_error = (zio->io_error == 0);
+       int callback_cnt = 0;
        /*
         * The hdr was inserted into hash-table and removed from lists
         * prior to starting I/O.  We should find this header, since
@@ -4082,37 +4818,36 @@ arc_read_done(zio_t *zio)
                ASSERT3U(hdr->b_dva.dva_word[1], ==,
                    BP_IDENTITY(zio->io_bp)->dva_word[1]);
 
-               found = buf_hash_find(hdr->b_spa, zio->io_bp,
-                   &hash_lock);
+               found = buf_hash_find(hdr->b_spa, zio->io_bp, &hash_lock);
 
-               ASSERT((found == NULL && HDR_FREED_IN_READ(hdr) &&
-                   hash_lock == NULL) ||
-                   (found == hdr &&
+               ASSERT((found == hdr &&
                    DVA_EQUAL(&hdr->b_dva, BP_IDENTITY(zio->io_bp))) ||
                    (found == hdr && HDR_L2_READING(hdr)));
+               ASSERT3P(hash_lock, !=, NULL);
+       }
+
+       if (no_zio_error) {
+               /* byteswap if necessary */
+               if (BP_SHOULD_BYTESWAP(zio->io_bp)) {
+                       if (BP_GET_LEVEL(zio->io_bp) > 0) {
+                               hdr->b_l1hdr.b_byteswap = DMU_BSWAP_UINT64;
+                       } else {
+                               hdr->b_l1hdr.b_byteswap =
+                                   DMU_OT_BYTESWAP(BP_GET_TYPE(zio->io_bp));
+                       }
+               } else {
+                       hdr->b_l1hdr.b_byteswap = DMU_BSWAP_NUMFUNCS;
+               }
        }
 
-       hdr->b_flags &= ~ARC_FLAG_L2_EVICTED;
+       arc_hdr_clear_flags(hdr, ARC_FLAG_L2_EVICTED);
        if (l2arc_noprefetch && HDR_PREFETCH(hdr))
-               hdr->b_flags &= ~ARC_FLAG_L2CACHE;
+               arc_hdr_clear_flags(hdr, ARC_FLAG_L2CACHE);
 
-       /* byteswap if necessary */
        callback_list = hdr->b_l1hdr.b_acb;
-       ASSERT(callback_list != NULL);
-       if (BP_SHOULD_BYTESWAP(zio->io_bp) && zio->io_error == 0) {
-               dmu_object_byteswap_t bswap =
-                   DMU_OT_BYTESWAP(BP_GET_TYPE(zio->io_bp));
-               if (BP_GET_LEVEL(zio->io_bp) > 0)
-                   byteswap_uint64_array(buf->b_data, hdr->b_size);
-               else
-                   dmu_ot_byteswap[bswap].ob_func(buf->b_data, hdr->b_size);
-       }
-
-       arc_cksum_compute(buf, B_FALSE);
-       arc_buf_watch(buf);
+       ASSERT3P(callback_list, !=, NULL);
 
-       if (hash_lock && zio->io_error == 0 &&
-           hdr->b_l1hdr.b_state == arc_anon) {
+       if (hash_lock && no_zio_error && hdr->b_l1hdr.b_state == arc_anon) {
                /*
                 * Only call arc_access on anonymous buffers.  This is because
                 * if we've issued an I/O for an evicted buffer, we've already
@@ -4122,32 +4857,42 @@ arc_read_done(zio_t *zio)
                arc_access(hdr, hash_lock);
        }
 
-       /* create copies of the data buffer for the callers */
-       abuf = buf;
-       for (acb = callback_list; acb; acb = acb->acb_next) {
-               if (acb->acb_done) {
-                       if (abuf == NULL) {
-                               ARCSTAT_BUMP(arcstat_duplicate_reads);
-                               abuf = arc_buf_clone(buf);
-                       }
-                       acb->acb_buf = abuf;
-                       abuf = NULL;
+       /*
+        * If a read request has a callback (i.e. acb_done is not NULL), then we
+        * make a buf containing the data according to the parameters which were
+        * passed in. The implementation of arc_buf_alloc_impl() ensures that we
+        * aren't needlessly decompressing the data multiple times.
+        */
+       for (acb = callback_list; acb != NULL; acb = acb->acb_next) {
+               int error;
+               if (!acb->acb_done)
+                       continue;
+
+               /* This is a demand read since prefetches don't use callbacks */
+
+               callback_cnt++;
+
+               error = arc_buf_alloc_impl(hdr, acb->acb_private,
+                   acb->acb_compressed, no_zio_error, &acb->acb_buf);
+               if (no_zio_error) {
+                       zio->io_error = error;
                }
        }
        hdr->b_l1hdr.b_acb = NULL;
-       hdr->b_flags &= ~ARC_FLAG_IO_IN_PROGRESS;
-       ASSERT(!HDR_BUF_AVAILABLE(hdr));
-       if (abuf == buf) {
-               ASSERT(buf->b_efunc == NULL);
-               ASSERT(hdr->b_l1hdr.b_datacnt == 1);
-               hdr->b_flags |= ARC_FLAG_BUF_AVAILABLE;
+       arc_hdr_clear_flags(hdr, ARC_FLAG_IO_IN_PROGRESS);
+       if (callback_cnt == 0) {
+               ASSERT(HDR_PREFETCH(hdr));
+               ASSERT0(hdr->b_l1hdr.b_bufcnt);
+               ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
        }
 
        ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt) ||
            callback_list != NULL);
 
-       if (zio->io_error != 0) {
-               hdr->b_flags |= ARC_FLAG_IO_ERROR;
+       if (no_zio_error) {
+               arc_hdr_verify(hdr, zio->io_bp);
+       } else {
+               arc_hdr_set_flags(hdr, ARC_FLAG_IO_ERROR);
                if (hdr->b_l1hdr.b_state != arc_anon)
                        arc_change_state(arc_anon, hdr, hash_lock);
                if (HDR_IN_HASH_TABLE(hdr))
@@ -4217,10 +4962,10 @@ arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp, arc_done_func_t *done,
     arc_flags_t *arc_flags, const zbookmark_phys_t *zb)
 {
        arc_buf_hdr_t *hdr = NULL;
-       arc_buf_t *buf = NULL;
        kmutex_t *hash_lock = NULL;
        zio_t *rzio;
        uint64_t guid = spa_load_guid(spa);
+       boolean_t compressed_read = (zio_flags & ZIO_FLAG_RAW) != 0;
        int rc = 0;
 
        ASSERT(!BP_IS_EMBEDDED(bp) ||
@@ -4235,12 +4980,43 @@ top:
                hdr = buf_hash_find(guid, bp, &hash_lock);
        }
 
-       if (hdr != NULL && HDR_HAS_L1HDR(hdr) && hdr->b_l1hdr.b_datacnt > 0) {
-
+       if (hdr != NULL && HDR_HAS_L1HDR(hdr) && hdr->b_l1hdr.b_pdata != NULL) {
+               arc_buf_t *buf = NULL;
                *arc_flags |= ARC_FLAG_CACHED;
 
                if (HDR_IO_IN_PROGRESS(hdr)) {
 
+                       if ((hdr->b_flags & ARC_FLAG_PRIO_ASYNC_READ) &&
+                           priority == ZIO_PRIORITY_SYNC_READ) {
+                               /*
+                                * This sync read must wait for an
+                                * in-progress async read (e.g. a predictive
+                                * prefetch).  Async reads are queued
+                                * separately at the vdev_queue layer, so
+                                * this is a form of priority inversion.
+                                * Ideally, we would "inherit" the demand
+                                * i/o's priority by moving the i/o from
+                                * the async queue to the synchronous queue,
+                                * but there is currently no mechanism to do
+                                * so.  Track this so that we can evaluate
+                                * the magnitude of this potential performance
+                                * problem.
+                                *
+                                * Note that if the prefetch i/o is already
+                                * active (has been issued to the device),
+                                * the prefetch improved performance, because
+                                * we issued it sooner than we would have
+                                * without the prefetch.
+                                */
+                               DTRACE_PROBE1(arc__sync__wait__for__async,
+                                   arc_buf_hdr_t *, hdr);
+                               ARCSTAT_BUMP(arcstat_sync_wait_for_async);
+                       }
+                       if (hdr->b_flags & ARC_FLAG_PREDICTIVE_PREFETCH) {
+                               arc_hdr_clear_flags(hdr,
+                                   ARC_FLAG_PREDICTIVE_PREFETCH);
+                       }
+
                        if (*arc_flags & ARC_FLAG_WAIT) {
                                cv_wait(&hdr->b_l1hdr.b_cv, hash_lock);
                                mutex_exit(hash_lock);
@@ -4249,7 +5025,7 @@ top:
                        ASSERT(*arc_flags & ARC_FLAG_NOWAIT);
 
                        if (done) {
-                               arc_callback_t  *acb = NULL;
+                               arc_callback_t *acb = NULL;
 
                                acb = kmem_zalloc(sizeof (arc_callback_t),
                                    KM_SLEEP);
@@ -4259,10 +5035,9 @@ top:
                                        acb->acb_zio_dummy = zio_null(pio,
                                            spa, NULL, NULL, NULL, zio_flags);
 
-                               ASSERT(acb->acb_done != NULL);
+                               ASSERT3P(acb->acb_done, !=, NULL);
                                acb->acb_next = hdr->b_l1hdr.b_acb;
                                hdr->b_l1hdr.b_acb = acb;
-                               add_reference(hdr, hash_lock, private);
                                mutex_exit(hash_lock);
                                goto out;
                        }
@@ -4274,32 +5049,33 @@ top:
                    hdr->b_l1hdr.b_state == arc_mfu);
 
                if (done) {
-                       add_reference(hdr, hash_lock, private);
-                       /*
-                        * If this block is already in use, create a new
-                        * copy of the data so that we will be guaranteed
-                        * that arc_release() will always succeed.
-                        */
-                       buf = hdr->b_l1hdr.b_buf;
-                       ASSERT(buf);
-                       ASSERT(buf->b_data);
-                       if (HDR_BUF_AVAILABLE(hdr)) {
-                               ASSERT(buf->b_efunc == NULL);
-                               hdr->b_flags &= ~ARC_FLAG_BUF_AVAILABLE;
-                       } else {
-                               buf = arc_buf_clone(buf);
+                       if (hdr->b_flags & ARC_FLAG_PREDICTIVE_PREFETCH) {
+                               /*
+                                * This is a demand read which does not have to
+                                * wait for i/o because we did a predictive
+                                * prefetch i/o for it, which has completed.
+                                */
+                               DTRACE_PROBE1(
+                                   arc__demand__hit__predictive__prefetch,
+                                   arc_buf_hdr_t *, hdr);
+                               ARCSTAT_BUMP(
+                                   arcstat_demand_hit_predictive_prefetch);
+                               arc_hdr_clear_flags(hdr,
+                                   ARC_FLAG_PREDICTIVE_PREFETCH);
                        }
+                       ASSERT(!BP_IS_EMBEDDED(bp) || !BP_IS_HOLE(bp));
 
+                       /* Get a buf with the desired data in it. */
+                       VERIFY0(arc_buf_alloc_impl(hdr, private,
+                           compressed_read, B_TRUE, &buf));
                } else if (*arc_flags & ARC_FLAG_PREFETCH &&
                    refcount_count(&hdr->b_l1hdr.b_refcnt) == 0) {
-                       hdr->b_flags |= ARC_FLAG_PREFETCH;
+                       arc_hdr_set_flags(hdr, ARC_FLAG_PREFETCH);
                }
                DTRACE_PROBE1(arc__hit, arc_buf_hdr_t *, hdr);
                arc_access(hdr, hash_lock);
                if (*arc_flags & ARC_FLAG_L2CACHE)
-                       hdr->b_flags |= ARC_FLAG_L2CACHE;
-               if (*arc_flags & ARC_FLAG_L2COMPRESS)
-                       hdr->b_flags |= ARC_FLAG_L2COMPRESS;
+                       arc_hdr_set_flags(hdr, ARC_FLAG_L2CACHE);
                mutex_exit(hash_lock);
                ARCSTAT_BUMP(arcstat_hits);
                ARCSTAT_CONDSTAT(!HDR_PREFETCH(hdr),
@@ -4309,20 +5085,19 @@ top:
                if (done)
                        done(NULL, buf, private);
        } else {
-               uint64_t size = BP_GET_LSIZE(bp);
+               uint64_t lsize = BP_GET_LSIZE(bp);
+               uint64_t psize = BP_GET_PSIZE(bp);
                arc_callback_t *acb;
                vdev_t *vd = NULL;
                uint64_t addr = 0;
                boolean_t devw = B_FALSE;
-               enum zio_compress b_compress = ZIO_COMPRESS_OFF;
-               int32_t b_asize = 0;
+               uint64_t size;
 
                /*
                 * Gracefully handle a damaged logical block size as a
                 * checksum error.
                 */
-               if (size > spa_maxblocksize(spa)) {
-                       ASSERT3P(buf, ==, NULL);
+               if (lsize > spa_maxblocksize(spa)) {
                        rc = SET_ERROR(ECKSUM);
                        goto out;
                }
@@ -4331,8 +5106,9 @@ top:
                        /* this block is not in the cache */
                        arc_buf_hdr_t *exists = NULL;
                        arc_buf_contents_t type = BP_GET_BUFC_TYPE(bp);
-                       buf = arc_buf_alloc(spa, size, private, type);
-                       hdr = buf->b_hdr;
+                       hdr = arc_hdr_alloc(spa_load_guid(spa), psize, lsize,
+                           BP_GET_COMPRESS(bp), type);
+
                        if (!BP_IS_EMBEDDED(bp)) {
                                hdr->b_dva = *BP_IDENTITY(bp);
                                hdr->b_birth = BP_PHYSICAL_BIRTH(bp);
@@ -4342,22 +5118,9 @@ top:
                                /* somebody beat us to the hash insert */
                                mutex_exit(hash_lock);
                                buf_discard_identity(hdr);
-                               (void) arc_buf_remove_ref(buf, private);
+                               arc_hdr_destroy(hdr);
                                goto top; /* restart the IO request */
                        }
-
-                       /* if this is a prefetch, we don't have a reference */
-                       if (*arc_flags & ARC_FLAG_PREFETCH) {
-                               (void) remove_reference(hdr, hash_lock,
-                                   private);
-                               hdr->b_flags |= ARC_FLAG_PREFETCH;
-                       }
-                       if (*arc_flags & ARC_FLAG_L2CACHE)
-                               hdr->b_flags |= ARC_FLAG_L2CACHE;
-                       if (*arc_flags & ARC_FLAG_L2COMPRESS)
-                               hdr->b_flags |= ARC_FLAG_L2COMPRESS;
-                       if (BP_GET_LEVEL(bp) > 0)
-                               hdr->b_flags |= ARC_FLAG_INDIRECT;
                } else {
                        /*
                         * This block is in the ghost cache. If it was L2-only
@@ -4369,49 +5132,62 @@ top:
                                    hdr_full_cache);
                        }
 
+                       ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
                        ASSERT(GHOST_STATE(hdr->b_l1hdr.b_state));
                        ASSERT(!HDR_IO_IN_PROGRESS(hdr));
                        ASSERT(refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
                        ASSERT3P(hdr->b_l1hdr.b_buf, ==, NULL);
+                       ASSERT3P(hdr->b_l1hdr.b_freeze_cksum, ==, NULL);
 
-                       /* if this is a prefetch, we don't have a reference */
-                       if (*arc_flags & ARC_FLAG_PREFETCH)
-                               hdr->b_flags |= ARC_FLAG_PREFETCH;
-                       else
-                               add_reference(hdr, hash_lock, private);
-                       if (*arc_flags & ARC_FLAG_L2CACHE)
-                               hdr->b_flags |= ARC_FLAG_L2CACHE;
-                       if (*arc_flags & ARC_FLAG_L2COMPRESS)
-                               hdr->b_flags |= ARC_FLAG_L2COMPRESS;
-                       buf = kmem_cache_alloc(buf_cache, KM_PUSHPAGE);
-                       buf->b_hdr = hdr;
-                       buf->b_data = NULL;
-                       buf->b_efunc = NULL;
-                       buf->b_private = NULL;
-                       buf->b_next = NULL;
-                       hdr->b_l1hdr.b_buf = buf;
-                       ASSERT0(hdr->b_l1hdr.b_datacnt);
-                       hdr->b_l1hdr.b_datacnt = 1;
-                       arc_get_data_buf(buf);
+                       /*
+                        * This is a delicate dance that we play here.
+                        * This hdr is in the ghost list so we access it
+                        * to move it out of the ghost list before we
+                        * initiate the read. If it's a prefetch then
+                        * it won't have a callback so we'll remove the
+                        * reference that arc_buf_alloc_impl() created. We
+                        * do this after we've called arc_access() to
+                        * avoid hitting an assert in remove_reference().
+                        */
                        arc_access(hdr, hash_lock);
+                       arc_hdr_alloc_pdata(hdr);
                }
+               ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
+               size = arc_hdr_size(hdr);
 
+               /*
+                * If compression is enabled on the hdr, then will do
+                * RAW I/O and will store the compressed data in the hdr's
+                * data block. Otherwise, the hdr's data block will contain
+                * the uncompressed data.
+                */
+               if (HDR_GET_COMPRESS(hdr) != ZIO_COMPRESS_OFF) {
+                       zio_flags |= ZIO_FLAG_RAW;
+               }
+
+               if (*arc_flags & ARC_FLAG_PREFETCH)
+                       arc_hdr_set_flags(hdr, ARC_FLAG_PREFETCH);
+               if (*arc_flags & ARC_FLAG_L2CACHE)
+                       arc_hdr_set_flags(hdr, ARC_FLAG_L2CACHE);
+               if (BP_GET_LEVEL(bp) > 0)
+                       arc_hdr_set_flags(hdr, ARC_FLAG_INDIRECT);
+               if (*arc_flags & ARC_FLAG_PREDICTIVE_PREFETCH)
+                       arc_hdr_set_flags(hdr, ARC_FLAG_PREDICTIVE_PREFETCH);
                ASSERT(!GHOST_STATE(hdr->b_l1hdr.b_state));
 
                acb = kmem_zalloc(sizeof (arc_callback_t), KM_SLEEP);
                acb->acb_done = done;
                acb->acb_private = private;
+               acb->acb_compressed = compressed_read;
 
-               ASSERT(hdr->b_l1hdr.b_acb == NULL);
+               ASSERT3P(hdr->b_l1hdr.b_acb, ==, NULL);
                hdr->b_l1hdr.b_acb = acb;
-               hdr->b_flags |= ARC_FLAG_IO_IN_PROGRESS;
+               arc_hdr_set_flags(hdr, ARC_FLAG_IO_IN_PROGRESS);
 
                if (HDR_HAS_L2HDR(hdr) &&
                    (vd = hdr->b_l2hdr.b_dev->l2ad_vdev) != NULL) {
                        devw = hdr->b_l2hdr.b_dev->l2ad_writing;
                        addr = hdr->b_l2hdr.b_daddr;
-                       b_compress = hdr->b_l2hdr.b_compress;
-                       b_asize = hdr->b_l2hdr.b_asize;
                        /*
                         * Lock out device removal.
                         */
@@ -4420,6 +5196,11 @@ top:
                                vd = NULL;
                }
 
+               if (priority == ZIO_PRIORITY_ASYNC_READ)
+                       arc_hdr_set_flags(hdr, ARC_FLAG_PRIO_ASYNC_READ);
+               else
+                       arc_hdr_clear_flags(hdr, ARC_FLAG_PRIO_ASYNC_READ);
+
                if (hash_lock != NULL)
                        mutex_exit(hash_lock);
 
@@ -4427,9 +5208,10 @@ top:
                 * At this point, we have a level 1 cache miss.  Try again in
                 * L2ARC if possible.
                 */
-               ASSERT3U(hdr->b_size, ==, size);
+               ASSERT3U(HDR_GET_LSIZE(hdr), ==, lsize);
+
                DTRACE_PROBE4(arc__miss, arc_buf_hdr_t *, hdr, blkptr_t *, bp,
-                   uint64_t, size, zbookmark_phys_t *, zb);
+                   uint64_t, lsize, zbookmark_phys_t *, zb);
                ARCSTAT_BUMP(arcstat_misses);
                ARCSTAT_CONDSTAT(!HDR_PREFETCH(hdr),
                    demand, prefetch, !HDR_ISTYPE_METADATA(hdr),
@@ -4456,15 +5238,13 @@ top:
 
                                cb = kmem_zalloc(sizeof (l2arc_read_callback_t),
                                    KM_SLEEP);
-                               cb->l2rcb_buf = buf;
-                               cb->l2rcb_spa = spa;
+                               cb->l2rcb_hdr = hdr;
                                cb->l2rcb_bp = *bp;
                                cb->l2rcb_zb = *zb;
                                cb->l2rcb_flags = zio_flags;
-                               cb->l2rcb_compress = b_compress;
 
                                ASSERT(addr >= VDEV_LABEL_START_SIZE &&
-                                   addr + size < vd->vdev_psize -
+                                   addr + lsize < vd->vdev_psize -
                                    VDEV_LABEL_END_SIZE);
 
                                /*
@@ -4473,26 +5253,20 @@ top:
                                 * Issue a null zio if the underlying buffer
                                 * was squashed to zero size by compression.
                                 */
-                               if (b_compress == ZIO_COMPRESS_EMPTY) {
-                                       rzio = zio_null(pio, spa, vd,
-                                           l2arc_read_done, cb,
-                                           zio_flags | ZIO_FLAG_DONT_CACHE |
-                                           ZIO_FLAG_CANFAIL |
-                                           ZIO_FLAG_DONT_PROPAGATE |
-                                           ZIO_FLAG_DONT_RETRY);
-                               } else {
-                                       rzio = zio_read_phys(pio, vd, addr,
-                                           b_asize, buf->b_data,
-                                           ZIO_CHECKSUM_OFF,
-                                           l2arc_read_done, cb, priority,
-                                           zio_flags | ZIO_FLAG_DONT_CACHE |
-                                           ZIO_FLAG_CANFAIL |
-                                           ZIO_FLAG_DONT_PROPAGATE |
-                                           ZIO_FLAG_DONT_RETRY, B_FALSE);
-                               }
+                               ASSERT3U(HDR_GET_COMPRESS(hdr), !=,
+                                   ZIO_COMPRESS_EMPTY);
+                               rzio = zio_read_phys(pio, vd, addr,
+                                   size, hdr->b_l1hdr.b_pdata,
+                                   ZIO_CHECKSUM_OFF,
+                                   l2arc_read_done, cb, priority,
+                                   zio_flags | ZIO_FLAG_DONT_CACHE |
+                                   ZIO_FLAG_CANFAIL |
+                                   ZIO_FLAG_DONT_PROPAGATE |
+                                   ZIO_FLAG_DONT_RETRY, B_FALSE);
+
                                DTRACE_PROBE2(l2arc__read, vdev_t *, vd,
                                    zio_t *, rzio);
-                               ARCSTAT_INCR(arcstat_l2_read_bytes, b_asize);
+                               ARCSTAT_INCR(arcstat_l2_read_bytes, size);
 
                                if (*arc_flags & ARC_FLAG_NOWAIT) {
                                        zio_nowait(rzio);
@@ -4522,8 +5296,8 @@ top:
                        }
                }
 
-               rzio = zio_read(pio, spa, bp, buf->b_data, size,
-                   arc_read_done, buf, priority, zio_flags, zb);
+               rzio = zio_read(pio, spa, bp, hdr->b_l1hdr.b_pdata, size,
+                   arc_read_done, hdr, priority, zio_flags, zb);
 
                if (*arc_flags & ARC_FLAG_WAIT) {
                        rc = zio_wait(rzio);
@@ -4576,20 +5350,6 @@ arc_remove_prune_callback(arc_prune_t *p)
        kmem_free(p, sizeof (*p));
 }
 
-void
-arc_set_callback(arc_buf_t *buf, arc_evict_func_t *func, void *private)
-{
-       ASSERT(buf->b_hdr != NULL);
-       ASSERT(buf->b_hdr->b_l1hdr.b_state != arc_anon);
-       ASSERT(!refcount_is_zero(&buf->b_hdr->b_l1hdr.b_refcnt) ||
-           func == NULL);
-       ASSERT(buf->b_efunc == NULL);
-       ASSERT(!HDR_BUF_AVAILABLE(buf->b_hdr));
-
-       buf->b_efunc = func;
-       buf->b_private = private;
-}
-
 /*
  * Notify the arc that a block was freed, and thus will never be used again.
  */
@@ -4605,85 +5365,38 @@ arc_freed(spa_t *spa, const blkptr_t *bp)
        hdr = buf_hash_find(guid, bp, &hash_lock);
        if (hdr == NULL)
                return;
-       if (HDR_BUF_AVAILABLE(hdr)) {
-               arc_buf_t *buf = hdr->b_l1hdr.b_buf;
-               add_reference(hdr, hash_lock, FTAG);
-               hdr->b_flags &= ~ARC_FLAG_BUF_AVAILABLE;
-               mutex_exit(hash_lock);
 
-               arc_release(buf, FTAG);
-               (void) arc_buf_remove_ref(buf, FTAG);
-       } else {
+       /*
+        * We might be trying to free a block that is still doing I/O
+        * (i.e. prefetch) or has a reference (i.e. a dedup-ed,
+        * dmu_sync-ed block). If this block is being prefetched, then it
+        * would still have the ARC_FLAG_IO_IN_PROGRESS flag set on the hdr
+        * until the I/O completes. A block may also have a reference if it is
+        * part of a dedup-ed, dmu_synced write. The dmu_sync() function would
+        * have written the new block to its final resting place on disk but
+        * without the dedup flag set. This would have left the hdr in the MRU
+        * state and discoverable. When the txg finally syncs it detects that
+        * the block was overridden in open context and issues an override I/O.
+        * Since this is a dedup block, the override I/O will determine if the
+        * block is already in the DDT. If so, then it will replace the io_bp
+        * with the bp from the DDT and allow the I/O to finish. When the I/O
+        * reaches the done callback, dbuf_write_override_done, it will
+        * check to see if the io_bp and io_bp_override are identical.
+        * If they are not, then it indicates that the bp was replaced with
+        * the bp in the DDT and the override bp is freed. This allows
+        * us to arrive here with a reference on a block that is being
+        * freed. So if we have an I/O in progress, or a reference to
+        * this hdr, then we don't destroy the hdr.
+        */
+       if (!HDR_HAS_L1HDR(hdr) || (!HDR_IO_IN_PROGRESS(hdr) &&
+           refcount_is_zero(&hdr->b_l1hdr.b_refcnt))) {
+               arc_change_state(arc_anon, hdr, hash_lock);
+               arc_hdr_destroy(hdr);
                mutex_exit(hash_lock);
-       }
-
-}
-
-/*
- * Clear the user eviction callback set by arc_set_callback(), first calling
- * it if it exists.  Because the presence of a callback keeps an arc_buf cached
- * clearing the callback may result in the arc_buf being destroyed.  However,
- * it will not result in the *last* arc_buf being destroyed, hence the data
- * will remain cached in the ARC. We make a copy of the arc buffer here so
- * that we can process the callback without holding any locks.
- *
- * It's possible that the callback is already in the process of being cleared
- * by another thread.  In this case we can not clear the callback.
- *
- * Returns B_TRUE if the callback was successfully called and cleared.
- */
-boolean_t
-arc_clear_callback(arc_buf_t *buf)
-{
-       arc_buf_hdr_t *hdr;
-       kmutex_t *hash_lock;
-       arc_evict_func_t *efunc = buf->b_efunc;
-       void *private = buf->b_private;
-
-       mutex_enter(&buf->b_evict_lock);
-       hdr = buf->b_hdr;
-       if (hdr == NULL) {
-               /*
-                * We are in arc_do_user_evicts().
-                */
-               ASSERT(buf->b_data == NULL);
-               mutex_exit(&buf->b_evict_lock);
-               return (B_FALSE);
-       } else if (buf->b_data == NULL) {
-               /*
-                * We are on the eviction list; process this buffer now
-                * but let arc_do_user_evicts() do the reaping.
-                */
-               buf->b_efunc = NULL;
-               mutex_exit(&buf->b_evict_lock);
-               VERIFY0(efunc(private));
-               return (B_TRUE);
-       }
-       hash_lock = HDR_LOCK(hdr);
-       mutex_enter(hash_lock);
-       hdr = buf->b_hdr;
-       ASSERT3P(hash_lock, ==, HDR_LOCK(hdr));
-
-       ASSERT3U(refcount_count(&hdr->b_l1hdr.b_refcnt), <,
-           hdr->b_l1hdr.b_datacnt);
-       ASSERT(hdr->b_l1hdr.b_state == arc_mru ||
-           hdr->b_l1hdr.b_state == arc_mfu);
-
-       buf->b_efunc = NULL;
-       buf->b_private = NULL;
-
-       if (hdr->b_l1hdr.b_datacnt > 1) {
-               mutex_exit(&buf->b_evict_lock);
-               arc_buf_destroy(buf, TRUE);
        } else {
-               ASSERT(buf == hdr->b_l1hdr.b_buf);
-               hdr->b_flags |= ARC_FLAG_BUF_AVAILABLE;
-               mutex_exit(&buf->b_evict_lock);
+               mutex_exit(hash_lock);
        }
 
-       mutex_exit(hash_lock);
-       VERIFY0(efunc(private));
-       return (B_TRUE);
 }
 
 /*
@@ -4719,16 +5432,19 @@ arc_release(arc_buf_t *buf, void *tag)
                ASSERT(!HDR_IO_IN_PROGRESS(hdr));
                ASSERT(!HDR_IN_HASH_TABLE(hdr));
                ASSERT(!HDR_HAS_L2HDR(hdr));
-               ASSERT(BUF_EMPTY(hdr));
+               ASSERT(HDR_EMPTY(hdr));
 
-               ASSERT3U(hdr->b_l1hdr.b_datacnt, ==, 1);
+               ASSERT3U(hdr->b_l1hdr.b_bufcnt, ==, 1);
                ASSERT3S(refcount_count(&hdr->b_l1hdr.b_refcnt), ==, 1);
                ASSERT(!list_link_active(&hdr->b_l1hdr.b_arc_node));
 
-               ASSERT3P(buf->b_efunc, ==, NULL);
-               ASSERT3P(buf->b_private, ==, NULL);
-
                hdr->b_l1hdr.b_arc_access = 0;
+
+               /*
+                * If the buf is being overridden then it may already
+                * have a hdr that is not empty.
+                */
+               buf_discard_identity(hdr);
                arc_buf_thaw(buf);
 
                return;
@@ -4747,7 +5463,7 @@ arc_release(arc_buf_t *buf, void *tag)
        ASSERT3P(state, !=, arc_anon);
 
        /* this buffer is not on any list */
-       ASSERT(refcount_count(&hdr->b_l1hdr.b_refcnt) > 0);
+       ASSERT3S(refcount_count(&hdr->b_l1hdr.b_refcnt), >, 0);
 
        if (HDR_HAS_L2HDR(hdr)) {
                mutex_enter(&hdr->b_l2hdr.b_dev->l2ad_mtx);
@@ -4769,79 +5485,116 @@ arc_release(arc_buf_t *buf, void *tag)
        /*
         * Do we have more than one buf?
         */
-       if (hdr->b_l1hdr.b_datacnt > 1) {
+       if (hdr->b_l1hdr.b_bufcnt > 1) {
                arc_buf_hdr_t *nhdr;
-               arc_buf_t **bufp;
-               uint64_t blksz = hdr->b_size;
                uint64_t spa = hdr->b_spa;
+               uint64_t psize = HDR_GET_PSIZE(hdr);
+               uint64_t lsize = HDR_GET_LSIZE(hdr);
+               enum zio_compress compress = HDR_GET_COMPRESS(hdr);
                arc_buf_contents_t type = arc_buf_type(hdr);
-               uint32_t flags = hdr->b_flags;
+               arc_buf_t *lastbuf = NULL;
+               VERIFY3U(hdr->b_type, ==, type);
 
                ASSERT(hdr->b_l1hdr.b_buf != buf || buf->b_next != NULL);
+               (void) remove_reference(hdr, hash_lock, tag);
+
+               if (arc_buf_is_shared(buf) && !ARC_BUF_COMPRESSED(buf)) {
+                       ASSERT3P(hdr->b_l1hdr.b_buf, !=, buf);
+                       ASSERT(ARC_BUF_LAST(buf));
+               }
+
                /*
                 * Pull the data off of this hdr and attach it to
-                * a new anonymous hdr.
+                * a new anonymous hdr. Also find the last buffer
+                * in the hdr's buffer list.
                 */
-               (void) remove_reference(hdr, hash_lock, tag);
-               bufp = &hdr->b_l1hdr.b_buf;
-               while (*bufp != buf)
-                       bufp = &(*bufp)->b_next;
-               *bufp = buf->b_next;
-               buf->b_next = NULL;
+               lastbuf = arc_buf_remove(hdr, buf);
+               ASSERT3P(lastbuf, !=, NULL);
+
+               /*
+                * If the current arc_buf_t and the hdr are sharing their data
+                * buffer, then we must stop sharing that block.
+                */
+               if (arc_buf_is_shared(buf)) {
+                       ASSERT3P(hdr->b_l1hdr.b_buf, !=, buf);
+                       VERIFY(!arc_buf_is_shared(lastbuf));
+
+                       /*
+                        * First, sever the block sharing relationship between
+                        * buf and the arc_buf_hdr_t. Then, setup a new
+                        * block sharing relationship with the last buffer
+                        * on the arc_buf_t list.
+                        */
+                       arc_unshare_buf(hdr, buf);
 
+                       /*
+                        * Now we need to recreate the hdr's b_pdata. Since we
+                        * have lastbuf handy, we try to share with it, but if
+                        * we can't then we allocate a new b_pdata and copy the
+                        * data from buf into it.
+                        */
+                       if (arc_can_share(hdr, lastbuf)) {
+                               arc_share_buf(hdr, lastbuf);
+                       } else {
+                               arc_hdr_alloc_pdata(hdr);
+                               bcopy(buf->b_data, hdr->b_l1hdr.b_pdata, psize);
+                       }
+                       VERIFY3P(lastbuf->b_data, !=, NULL);
+               } else if (HDR_SHARED_DATA(hdr)) {
+                       /*
+                        * Uncompressed shared buffers are always at the end
+                        * of the list. Compressed buffers don't have the
+                        * same requirements. This makes it hard to
+                        * simply assert that the lastbuf is shared so
+                        * we rely on the hdr's compression flags to determine
+                        * if we have a compressed, shared buffer.
+                        */
+                       ASSERT(arc_buf_is_shared(lastbuf) ||
+                           HDR_GET_COMPRESS(hdr) != ZIO_COMPRESS_OFF);
+                       ASSERT(!ARC_BUF_SHARED(buf));
+               }
+               ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
                ASSERT3P(state, !=, arc_l2c_only);
 
-               (void) refcount_remove_many(
-                   &state->arcs_size, hdr->b_size, buf);
+               (void) refcount_remove_many(&state->arcs_size,
+                   arc_buf_size(buf), buf);
 
                if (refcount_is_zero(&hdr->b_l1hdr.b_refcnt)) {
-                       uint64_t *size;
-
                        ASSERT3P(state, !=, arc_l2c_only);
-                       size = &state->arcs_lsize[type];
-                       ASSERT3U(*size, >=, hdr->b_size);
-                       atomic_add_64(size, -hdr->b_size);
+                       (void) refcount_remove_many(&state->arcs_esize[type],
+                           arc_buf_size(buf), buf);
                }
 
-               /*
-                * We're releasing a duplicate user data buffer, update
-                * our statistics accordingly.
-                */
-               if (HDR_ISTYPE_DATA(hdr)) {
-                       ARCSTAT_BUMPDOWN(arcstat_duplicate_buffers);
-                       ARCSTAT_INCR(arcstat_duplicate_buffers_size,
-                           -hdr->b_size);
-               }
-               hdr->b_l1hdr.b_datacnt -= 1;
+               hdr->b_l1hdr.b_bufcnt -= 1;
                arc_cksum_verify(buf);
                arc_buf_unwatch(buf);
 
                mutex_exit(hash_lock);
 
-               nhdr = kmem_cache_alloc(hdr_full_cache, KM_PUSHPAGE);
-               nhdr->b_size = blksz;
-               nhdr->b_spa = spa;
+               /*
+                * Allocate a new hdr. The new hdr will contain a b_pdata
+                * buffer which will be freed in arc_write().
+                */
+               nhdr = arc_hdr_alloc(spa, psize, lsize, compress, type);
+               ASSERT3P(nhdr->b_l1hdr.b_buf, ==, NULL);
+               ASSERT0(nhdr->b_l1hdr.b_bufcnt);
+               ASSERT0(refcount_count(&nhdr->b_l1hdr.b_refcnt));
+               VERIFY3U(nhdr->b_type, ==, type);
+               ASSERT(!HDR_SHARED_DATA(nhdr));
 
+               nhdr->b_l1hdr.b_buf = buf;
+               nhdr->b_l1hdr.b_bufcnt = 1;
                nhdr->b_l1hdr.b_mru_hits = 0;
                nhdr->b_l1hdr.b_mru_ghost_hits = 0;
                nhdr->b_l1hdr.b_mfu_hits = 0;
                nhdr->b_l1hdr.b_mfu_ghost_hits = 0;
                nhdr->b_l1hdr.b_l2_hits = 0;
-               nhdr->b_flags = flags & ARC_FLAG_L2_WRITING;
-               nhdr->b_flags |= arc_bufc_to_flags(type);
-               nhdr->b_flags |= ARC_FLAG_HAS_L1HDR;
-
-               nhdr->b_l1hdr.b_buf = buf;
-               nhdr->b_l1hdr.b_datacnt = 1;
-               nhdr->b_l1hdr.b_state = arc_anon;
-               nhdr->b_l1hdr.b_arc_access = 0;
-               nhdr->b_l1hdr.b_tmp_cdata = NULL;
-               nhdr->b_freeze_cksum = NULL;
-
                (void) refcount_add(&nhdr->b_l1hdr.b_refcnt, tag);
                buf->b_hdr = nhdr;
+
                mutex_exit(&buf->b_evict_lock);
-               (void) refcount_add_many(&arc_anon->arcs_size, blksz, buf);
+               (void) refcount_add_many(&arc_anon->arcs_size,
+                   HDR_GET_LSIZE(nhdr), buf);
        } else {
                mutex_exit(&buf->b_evict_lock);
                ASSERT(refcount_count(&hdr->b_l1hdr.b_refcnt) == 1);
@@ -4860,8 +5613,6 @@ arc_release(arc_buf_t *buf, void *tag)
                buf_discard_identity(hdr);
                arc_buf_thaw(buf);
        }
-       buf->b_efunc = NULL;
-       buf->b_private = NULL;
 }
 
 int
@@ -4895,28 +5646,87 @@ arc_write_ready(zio_t *zio)
        arc_write_callback_t *callback = zio->io_private;
        arc_buf_t *buf = callback->awcb_buf;
        arc_buf_hdr_t *hdr = buf->b_hdr;
+       uint64_t psize = BP_IS_HOLE(zio->io_bp) ? 0 : BP_GET_PSIZE(zio->io_bp);
+       enum zio_compress compress;
 
        ASSERT(HDR_HAS_L1HDR(hdr));
        ASSERT(!refcount_is_zero(&buf->b_hdr->b_l1hdr.b_refcnt));
-       ASSERT(hdr->b_l1hdr.b_datacnt > 0);
-       callback->awcb_ready(zio, buf, callback->awcb_private);
+       ASSERT(hdr->b_l1hdr.b_bufcnt > 0);
 
        /*
-        * If the IO is already in progress, then this is a re-write
-        * attempt, so we need to thaw and re-compute the cksum.
-        * It is the responsibility of the callback to handle the
-        * accounting for any re-write attempt.
+        * If we're reexecuting this zio because the pool suspended, then
+        * cleanup any state that was previously set the first time the
+        * callback was invoked.
         */
-       if (HDR_IO_IN_PROGRESS(hdr)) {
-               mutex_enter(&hdr->b_l1hdr.b_freeze_lock);
-               if (hdr->b_freeze_cksum != NULL) {
-                       kmem_free(hdr->b_freeze_cksum, sizeof (zio_cksum_t));
-                       hdr->b_freeze_cksum = NULL;
+       if (zio->io_flags & ZIO_FLAG_REEXECUTED) {
+               arc_cksum_free(hdr);
+               arc_buf_unwatch(buf);
+               if (hdr->b_l1hdr.b_pdata != NULL) {
+                       if (arc_buf_is_shared(buf)) {
+                               arc_unshare_buf(hdr, buf);
+                       } else {
+                               arc_hdr_free_pdata(hdr);
+                       }
                }
-               mutex_exit(&hdr->b_l1hdr.b_freeze_lock);
        }
-       arc_cksum_compute(buf, B_FALSE);
-       hdr->b_flags |= ARC_FLAG_IO_IN_PROGRESS;
+       ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
+       ASSERT(!HDR_SHARED_DATA(hdr));
+       ASSERT(!arc_buf_is_shared(buf));
+
+       callback->awcb_ready(zio, buf, callback->awcb_private);
+
+       if (HDR_IO_IN_PROGRESS(hdr))
+               ASSERT(zio->io_flags & ZIO_FLAG_REEXECUTED);
+
+       arc_cksum_compute(buf);
+       arc_hdr_set_flags(hdr, ARC_FLAG_IO_IN_PROGRESS);
+
+       if (BP_IS_HOLE(zio->io_bp) || BP_IS_EMBEDDED(zio->io_bp)) {
+               compress = ZIO_COMPRESS_OFF;
+       } else {
+               ASSERT3U(HDR_GET_LSIZE(hdr), ==, BP_GET_LSIZE(zio->io_bp));
+               compress = BP_GET_COMPRESS(zio->io_bp);
+       }
+       HDR_SET_PSIZE(hdr, psize);
+       arc_hdr_set_compress(hdr, compress);
+
+       /*
+        * If the hdr is compressed, then copy the compressed
+        * zio contents into arc_buf_hdr_t. Otherwise, copy the original
+        * data buf into the hdr. Ideally, we would like to always copy the
+        * io_data into b_pdata but the user may have disabled compressed
+        * arc thus the on-disk block may or may not match what we maintain
+        * in the hdr's b_pdata field.
+        */
+       if (HDR_GET_COMPRESS(hdr) != ZIO_COMPRESS_OFF &&
+           !ARC_BUF_COMPRESSED(buf)) {
+               ASSERT3U(BP_GET_COMPRESS(zio->io_bp), !=, ZIO_COMPRESS_OFF);
+               ASSERT3U(psize, >, 0);
+               arc_hdr_alloc_pdata(hdr);
+               bcopy(zio->io_data, hdr->b_l1hdr.b_pdata, psize);
+       } else {
+               ASSERT3P(buf->b_data, ==, zio->io_orig_data);
+               ASSERT3U(zio->io_orig_size, ==, arc_buf_size(buf));
+               ASSERT3U(hdr->b_l1hdr.b_bufcnt, ==, 1);
+
+               /*
+                * This hdr is not compressed so we're able to share
+                * the arc_buf_t data buffer with the hdr.
+                */
+               arc_share_buf(hdr, buf);
+               ASSERT0(bcmp(zio->io_orig_data, hdr->b_l1hdr.b_pdata,
+                   HDR_GET_LSIZE(hdr)));
+       }
+       arc_hdr_verify(hdr, zio->io_bp);
+}
+
+static void
+arc_write_children_ready(zio_t *zio)
+{
+       arc_write_callback_t *callback = zio->io_private;
+       arc_buf_t *buf = callback->awcb_buf;
+
+       callback->awcb_children_ready(zio, buf, callback->awcb_private);
 }
 
 /*
@@ -4938,9 +5748,11 @@ arc_write_done(zio_t *zio)
        arc_buf_t *buf = callback->awcb_buf;
        arc_buf_hdr_t *hdr = buf->b_hdr;
 
-       ASSERT(hdr->b_l1hdr.b_acb == NULL);
+       ASSERT3P(hdr->b_l1hdr.b_acb, ==, NULL);
 
        if (zio->io_error == 0) {
+               arc_hdr_verify(hdr, zio->io_bp);
+
                if (BP_IS_HOLE(zio->io_bp) || BP_IS_EMBEDDED(zio->io_bp)) {
                        buf_discard_identity(hdr);
                } else {
@@ -4948,7 +5760,7 @@ arc_write_done(zio_t *zio)
                        hdr->b_birth = BP_PHYSICAL_BIRTH(zio->io_bp);
                }
        } else {
-               ASSERT(BUF_EMPTY(hdr));
+               ASSERT(HDR_EMPTY(hdr));
        }
 
        /*
@@ -4957,11 +5769,11 @@ arc_write_done(zio_t *zio)
         * dva/birth/checksum.  The buffer must therefore remain anonymous
         * (and uncached).
         */
-       if (!BUF_EMPTY(hdr)) {
+       if (!HDR_EMPTY(hdr)) {
                arc_buf_hdr_t *exists;
                kmutex_t *hash_lock;
 
-               ASSERT(zio->io_error == 0);
+               ASSERT3U(zio->io_error, ==, 0);
 
                arc_cksum_verify(buf);
 
@@ -4991,19 +5803,19 @@ arc_write_done(zio_t *zio)
                                            (void *)hdr, (void *)exists);
                        } else {
                                /* Dedup */
-                               ASSERT(hdr->b_l1hdr.b_datacnt == 1);
+                               ASSERT(hdr->b_l1hdr.b_bufcnt == 1);
                                ASSERT(hdr->b_l1hdr.b_state == arc_anon);
                                ASSERT(BP_GET_DEDUP(zio->io_bp));
                                ASSERT(BP_GET_LEVEL(zio->io_bp) == 0);
                        }
                }
-               hdr->b_flags &= ~ARC_FLAG_IO_IN_PROGRESS;
+               arc_hdr_clear_flags(hdr, ARC_FLAG_IO_IN_PROGRESS);
                /* if it's not anon, we are doing a scrub */
                if (exists == NULL && hdr->b_l1hdr.b_state == arc_anon)
                        arc_access(hdr, hash_lock);
                mutex_exit(hash_lock);
        } else {
-               hdr->b_flags &= ~ARC_FLAG_IO_IN_PROGRESS;
+               arc_hdr_clear_flags(hdr, ARC_FLAG_IO_IN_PROGRESS);
        }
 
        ASSERT(!refcount_is_zero(&hdr->b_l1hdr.b_refcnt));
@@ -5014,8 +5826,9 @@ arc_write_done(zio_t *zio)
 
 zio_t *
 arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
-    blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, boolean_t l2arc_compress,
-    const zio_prop_t *zp, arc_done_func_t *ready, arc_done_func_t *physdone,
+    blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc,
+    const zio_prop_t *zp, arc_done_func_t *ready,
+    arc_done_func_t *children_ready, arc_done_func_t *physdone,
     arc_done_func_t *done, void *private, zio_priority_t priority,
     int zio_flags, const zbookmark_phys_t *zb)
 {
@@ -5023,25 +5836,53 @@ arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
        arc_write_callback_t *callback;
        zio_t *zio;
 
-       ASSERT(ready != NULL);
-       ASSERT(done != NULL);
+       ASSERT3P(ready, !=, NULL);
+       ASSERT3P(done, !=, NULL);
        ASSERT(!HDR_IO_ERROR(hdr));
        ASSERT(!HDR_IO_IN_PROGRESS(hdr));
-       ASSERT(hdr->b_l1hdr.b_acb == NULL);
-       ASSERT(hdr->b_l1hdr.b_datacnt > 0);
+       ASSERT3P(hdr->b_l1hdr.b_acb, ==, NULL);
+       ASSERT3U(hdr->b_l1hdr.b_bufcnt, >, 0);
        if (l2arc)
-               hdr->b_flags |= ARC_FLAG_L2CACHE;
-       if (l2arc_compress)
-               hdr->b_flags |= ARC_FLAG_L2COMPRESS;
+               arc_hdr_set_flags(hdr, ARC_FLAG_L2CACHE);
+       if (ARC_BUF_COMPRESSED(buf)) {
+               ASSERT3U(zp->zp_compress, !=, ZIO_COMPRESS_OFF);
+               zio_flags |= ZIO_FLAG_RAW;
+       }
        callback = kmem_zalloc(sizeof (arc_write_callback_t), KM_SLEEP);
        callback->awcb_ready = ready;
+       callback->awcb_children_ready = children_ready;
        callback->awcb_physdone = physdone;
        callback->awcb_done = done;
        callback->awcb_private = private;
        callback->awcb_buf = buf;
 
-       zio = zio_write(pio, spa, txg, bp, buf->b_data, hdr->b_size, zp,
-           arc_write_ready, arc_write_physdone, arc_write_done, callback,
+       /*
+        * The hdr's b_pdata is now stale, free it now. A new data block
+        * will be allocated when the zio pipeline calls arc_write_ready().
+        */
+       if (hdr->b_l1hdr.b_pdata != NULL) {
+               /*
+                * If the buf is currently sharing the data block with
+                * the hdr then we need to break that relationship here.
+                * The hdr will remain with a NULL data pointer and the
+                * buf will take sole ownership of the block.
+                */
+               if (arc_buf_is_shared(buf)) {
+                       arc_unshare_buf(hdr, buf);
+               } else {
+                       arc_hdr_free_pdata(hdr);
+               }
+               VERIFY3P(buf->b_data, !=, NULL);
+               arc_hdr_set_compress(hdr, ZIO_COMPRESS_OFF);
+       }
+       ASSERT(!arc_buf_is_shared(buf));
+       ASSERT3P(hdr->b_l1hdr.b_pdata, ==, NULL);
+
+       zio = zio_write(pio, spa, txg, bp, buf->b_data,
+           HDR_GET_LSIZE(hdr), arc_buf_size(buf), zp,
+           arc_write_ready,
+           (children_ready != NULL) ? arc_write_children_ready : NULL,
+           arc_write_physdone, arc_write_done, callback,
            priority, zio_flags, zb);
 
        return (zio);
@@ -5065,7 +5906,6 @@ arc_memory_throttle(uint64_t reserve, uint64_t txg)
                last_txg = txg;
                page_load = 0;
        }
-
        /*
         * If we are in pageout, we know that memory is already tight,
         * the arc is already going to be evicting, so we just want to
@@ -5144,12 +5984,14 @@ arc_tempreserve_space(uint64_t reserve, uint64_t txg)
 
        if (reserve + arc_tempreserve + anon_size > arc_c / 2 &&
            anon_size > arc_c / 4) {
+               uint64_t meta_esize =
+                   refcount_count(&arc_anon->arcs_esize[ARC_BUFC_METADATA]);
+               uint64_t data_esize =
+                   refcount_count(&arc_anon->arcs_esize[ARC_BUFC_DATA]);
                dprintf("failing, arc_tempreserve=%lluK anon_meta=%lluK "
                    "anon_data=%lluK tempreserve=%lluK arc_c=%lluK\n",
-                   arc_tempreserve>>10,
-                   arc_anon->arcs_lsize[ARC_BUFC_METADATA]>>10,
-                   arc_anon->arcs_lsize[ARC_BUFC_DATA]>>10,
-                   reserve>>10, arc_c>>10);
+                   arc_tempreserve >> 10, meta_esize >> 10,
+                   data_esize >> 10, reserve >> 10, arc_c >> 10);
                DMU_TX_STAT_BUMP(dmu_tx_dirty_throttle);
                return (SET_ERROR(ERESTART));
        }
@@ -5162,8 +6004,10 @@ arc_kstat_update_state(arc_state_t *state, kstat_named_t *size,
     kstat_named_t *evict_data, kstat_named_t *evict_metadata)
 {
        size->value.ui64 = refcount_count(&state->arcs_size);
-       evict_data->value.ui64 = state->arcs_lsize[ARC_BUFC_DATA];
-       evict_metadata->value.ui64 = state->arcs_lsize[ARC_BUFC_METADATA];
+       evict_data->value.ui64 =
+           refcount_count(&state->arcs_esize[ARC_BUFC_DATA]);
+       evict_metadata->value.ui64 =
+           refcount_count(&state->arcs_esize[ARC_BUFC_METADATA]);
 }
 
 static int
@@ -5216,7 +6060,7 @@ arc_state_multilist_index_func(multilist_t *ml, void *obj)
         * numbers using buf_hash below. So, as an added precaution,
         * let's make sure we never add empty buffers to the arc lists.
         */
-       ASSERT(!BUF_EMPTY(hdr));
+       ASSERT(!HDR_EMPTY(hdr));
 
        /*
         * The assumption here, is the hash value for a given
@@ -5242,6 +6086,7 @@ arc_state_multilist_index_func(multilist_t *ml, void *obj)
 static void
 arc_tuning_update(void)
 {
+       uint64_t percent;
        /* Valid range: 64M - <all physical memory> */
        if ((zfs_arc_max) && (zfs_arc_max != arc_c_max) &&
            (zfs_arc_max > 64 << 20) && (zfs_arc_max < ptob(physmem)) &&
@@ -5249,7 +6094,11 @@ arc_tuning_update(void)
                arc_c_max = zfs_arc_max;
                arc_c = arc_c_max;
                arc_p = (arc_c >> 1);
-               arc_meta_limit = MIN(arc_meta_limit, (3 * arc_c_max) / 4);
+               /* Valid range of arc_meta_limit: arc_meta_min - arc_c_max */
+               percent = MIN(zfs_arc_meta_limit_percent, 100);
+               arc_meta_limit = MAX(arc_meta_min, (percent * arc_c_max) / 100);
+               percent = MIN(zfs_arc_dnode_limit_percent, 100);
+               arc_dnode_limit = (percent * arc_meta_limit) / 100;
        }
 
        /* Valid range: 32M - <arc_c_max> */
@@ -5266,6 +6115,7 @@ arc_tuning_update(void)
            (zfs_arc_meta_min <= arc_c_max)) {
                arc_meta_min = zfs_arc_meta_min;
                arc_meta_limit = MAX(arc_meta_limit, arc_meta_min);
+               arc_dnode_limit = arc_meta_limit / 10;
        }
 
        /* Valid range: <arc_meta_min> - <arc_c_max> */
@@ -5274,6 +6124,12 @@ arc_tuning_update(void)
            (zfs_arc_meta_limit <= arc_c_max))
                arc_meta_limit = zfs_arc_meta_limit;
 
+       /* Valid range: <arc_meta_min> - <arc_c_max> */
+       if ((zfs_arc_dnode_limit) && (zfs_arc_dnode_limit != arc_dnode_limit) &&
+           (zfs_arc_dnode_limit >= zfs_arc_meta_min) &&
+           (zfs_arc_dnode_limit <= arc_c_max))
+               arc_dnode_limit = zfs_arc_dnode_limit;
+
        /* Valid range: 1 - N */
        if (zfs_arc_grow_retry)
                arc_grow_retry = zfs_arc_grow_retry;
@@ -5303,6 +6159,126 @@ arc_tuning_update(void)
 
 }
 
+static void
+arc_state_init(void)
+{
+       arc_anon = &ARC_anon;
+       arc_mru = &ARC_mru;
+       arc_mru_ghost = &ARC_mru_ghost;
+       arc_mfu = &ARC_mfu;
+       arc_mfu_ghost = &ARC_mfu_ghost;
+       arc_l2c_only = &ARC_l2c_only;
+
+       multilist_create(&arc_mru->arcs_list[ARC_BUFC_METADATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_mru->arcs_list[ARC_BUFC_DATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_mru_ghost->arcs_list[ARC_BUFC_METADATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_mru_ghost->arcs_list[ARC_BUFC_DATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_mfu->arcs_list[ARC_BUFC_METADATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_mfu->arcs_list[ARC_BUFC_DATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_mfu_ghost->arcs_list[ARC_BUFC_METADATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_mfu_ghost->arcs_list[ARC_BUFC_DATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_l2c_only->arcs_list[ARC_BUFC_METADATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+       multilist_create(&arc_l2c_only->arcs_list[ARC_BUFC_DATA],
+           sizeof (arc_buf_hdr_t),
+           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
+           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
+
+       refcount_create(&arc_anon->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_create(&arc_anon->arcs_esize[ARC_BUFC_DATA]);
+       refcount_create(&arc_mru->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_create(&arc_mru->arcs_esize[ARC_BUFC_DATA]);
+       refcount_create(&arc_mru_ghost->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_create(&arc_mru_ghost->arcs_esize[ARC_BUFC_DATA]);
+       refcount_create(&arc_mfu->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_create(&arc_mfu->arcs_esize[ARC_BUFC_DATA]);
+       refcount_create(&arc_mfu_ghost->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_create(&arc_mfu_ghost->arcs_esize[ARC_BUFC_DATA]);
+       refcount_create(&arc_l2c_only->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_create(&arc_l2c_only->arcs_esize[ARC_BUFC_DATA]);
+
+       refcount_create(&arc_anon->arcs_size);
+       refcount_create(&arc_mru->arcs_size);
+       refcount_create(&arc_mru_ghost->arcs_size);
+       refcount_create(&arc_mfu->arcs_size);
+       refcount_create(&arc_mfu_ghost->arcs_size);
+       refcount_create(&arc_l2c_only->arcs_size);
+
+       arc_anon->arcs_state = ARC_STATE_ANON;
+       arc_mru->arcs_state = ARC_STATE_MRU;
+       arc_mru_ghost->arcs_state = ARC_STATE_MRU_GHOST;
+       arc_mfu->arcs_state = ARC_STATE_MFU;
+       arc_mfu_ghost->arcs_state = ARC_STATE_MFU_GHOST;
+       arc_l2c_only->arcs_state = ARC_STATE_L2C_ONLY;
+}
+
+static void
+arc_state_fini(void)
+{
+       refcount_destroy(&arc_anon->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_destroy(&arc_anon->arcs_esize[ARC_BUFC_DATA]);
+       refcount_destroy(&arc_mru->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_destroy(&arc_mru->arcs_esize[ARC_BUFC_DATA]);
+       refcount_destroy(&arc_mru_ghost->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_destroy(&arc_mru_ghost->arcs_esize[ARC_BUFC_DATA]);
+       refcount_destroy(&arc_mfu->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_destroy(&arc_mfu->arcs_esize[ARC_BUFC_DATA]);
+       refcount_destroy(&arc_mfu_ghost->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_destroy(&arc_mfu_ghost->arcs_esize[ARC_BUFC_DATA]);
+       refcount_destroy(&arc_l2c_only->arcs_esize[ARC_BUFC_METADATA]);
+       refcount_destroy(&arc_l2c_only->arcs_esize[ARC_BUFC_DATA]);
+
+       refcount_destroy(&arc_anon->arcs_size);
+       refcount_destroy(&arc_mru->arcs_size);
+       refcount_destroy(&arc_mru_ghost->arcs_size);
+       refcount_destroy(&arc_mfu->arcs_size);
+       refcount_destroy(&arc_mfu_ghost->arcs_size);
+       refcount_destroy(&arc_l2c_only->arcs_size);
+
+       multilist_destroy(&arc_mru->arcs_list[ARC_BUFC_METADATA]);
+       multilist_destroy(&arc_mru_ghost->arcs_list[ARC_BUFC_METADATA]);
+       multilist_destroy(&arc_mfu->arcs_list[ARC_BUFC_METADATA]);
+       multilist_destroy(&arc_mfu_ghost->arcs_list[ARC_BUFC_METADATA]);
+       multilist_destroy(&arc_mru->arcs_list[ARC_BUFC_DATA]);
+       multilist_destroy(&arc_mru_ghost->arcs_list[ARC_BUFC_DATA]);
+       multilist_destroy(&arc_mfu->arcs_list[ARC_BUFC_DATA]);
+       multilist_destroy(&arc_mfu_ghost->arcs_list[ARC_BUFC_DATA]);
+       multilist_destroy(&arc_l2c_only->arcs_list[ARC_BUFC_METADATA]);
+       multilist_destroy(&arc_l2c_only->arcs_list[ARC_BUFC_DATA]);
+}
+
+uint64_t
+arc_max_bytes(void)
+{
+       return (arc_c_max);
+}
+
 void
 arc_init(void)
 {
@@ -5314,28 +6290,16 @@ arc_init(void)
 #else
        uint64_t allmem = (physmem * PAGESIZE) / 2;
 #endif
+       uint64_t percent;
 
        mutex_init(&arc_reclaim_lock, NULL, MUTEX_DEFAULT, NULL);
        cv_init(&arc_reclaim_thread_cv, NULL, CV_DEFAULT, NULL);
        cv_init(&arc_reclaim_waiters_cv, NULL, CV_DEFAULT, NULL);
 
-       mutex_init(&arc_user_evicts_lock, NULL, MUTEX_DEFAULT, NULL);
-       cv_init(&arc_user_evicts_cv, NULL, CV_DEFAULT, NULL);
-
        /* Convert seconds to clock ticks */
        arc_min_prefetch_lifespan = 1 * hz;
 
-       /* Start out with 1/8 of all memory */
-       arc_c = allmem / 8;
-
 #ifdef _KERNEL
-       /*
-        * On architectures where the physical memory can be larger
-        * than the addressable space (intel in 32-bit mode), we may
-        * need to limit the cache to 1/8 of VM size.
-        */
-       arc_c = MIN(arc_c, vmem_size(heap_arena, VMEM_ALLOC | VMEM_FREE) / 8);
-
        /*
         * Register a shrinker to support synchronous (direct) memory
         * reclaim from the arc.  This is done to prevent kswapd from
@@ -5348,20 +6312,37 @@ arc_init(void)
        arc_need_free = 0;
 #endif
 
-       /* Set min cache to allow safe operation of arc_adapt() */
-       arc_c_min = 2ULL << SPA_MAXBLOCKSHIFT;
        /* Set max to 1/2 of all memory */
        arc_c_max = allmem / 2;
 
+       /*
+        * In userland, there's only the memory pressure that we artificially
+        * create (see arc_available_memory()).  Don't let arc_c get too
+        * small, because it can cause transactions to be larger than
+        * arc_c, causing arc_tempreserve_space() to fail.
+        */
+#ifndef        _KERNEL
+       arc_c_min = MAX(arc_c_max / 2, 2ULL << SPA_MAXBLOCKSHIFT);
+#else
+       arc_c_min = 2ULL << SPA_MAXBLOCKSHIFT;
+#endif
+
        arc_c = arc_c_max;
        arc_p = (arc_c >> 1);
+       arc_size = 0;
 
        /* Set min to 1/2 of arc_c_min */
        arc_meta_min = 1ULL << SPA_MAXBLOCKSHIFT;
        /* Initialize maximum observed usage to zero */
        arc_meta_max = 0;
-       /* Set limit to 3/4 of arc_c_max with a floor of arc_meta_min */
-       arc_meta_limit = MAX((3 * arc_c_max) / 4, arc_meta_min);
+       /*
+        * Set arc_meta_limit to a percent of arc_c_max with a floor of
+        * arc_meta_min, and a ceiling of arc_c_max.
+        */
+       percent = MIN(zfs_arc_meta_limit_percent, 100);
+       arc_meta_limit = MAX(arc_meta_min, (percent * arc_c_max) / 100);
+       percent = MIN(zfs_arc_dnode_limit_percent, 100);
+       arc_dnode_limit = (percent * arc_meta_limit) / 100;
 
        /* Apply user specified tunings */
        arc_tuning_update();
@@ -5375,82 +6356,18 @@ arc_init(void)
        if (arc_c < arc_c_min)
                arc_c = arc_c_min;
 
-       arc_anon = &ARC_anon;
-       arc_mru = &ARC_mru;
-       arc_mru_ghost = &ARC_mru_ghost;
-       arc_mfu = &ARC_mfu;
-       arc_mfu_ghost = &ARC_mfu_ghost;
-       arc_l2c_only = &ARC_l2c_only;
-       arc_size = 0;
-
-       multilist_create(&arc_mru->arcs_list[ARC_BUFC_METADATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_mru->arcs_list[ARC_BUFC_DATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_mru_ghost->arcs_list[ARC_BUFC_METADATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_mru_ghost->arcs_list[ARC_BUFC_DATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_mfu->arcs_list[ARC_BUFC_METADATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_mfu->arcs_list[ARC_BUFC_DATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_mfu_ghost->arcs_list[ARC_BUFC_METADATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_mfu_ghost->arcs_list[ARC_BUFC_DATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_l2c_only->arcs_list[ARC_BUFC_METADATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-       multilist_create(&arc_l2c_only->arcs_list[ARC_BUFC_DATA],
-           sizeof (arc_buf_hdr_t),
-           offsetof(arc_buf_hdr_t, b_l1hdr.b_arc_node),
-           zfs_arc_num_sublists_per_state, arc_state_multilist_index_func);
-
-       arc_anon->arcs_state = ARC_STATE_ANON;
-       arc_mru->arcs_state = ARC_STATE_MRU;
-       arc_mru_ghost->arcs_state = ARC_STATE_MRU_GHOST;
-       arc_mfu->arcs_state = ARC_STATE_MFU;
-       arc_mfu_ghost->arcs_state = ARC_STATE_MFU_GHOST;
-       arc_l2c_only->arcs_state = ARC_STATE_L2C_ONLY;
-
-       refcount_create(&arc_anon->arcs_size);
-       refcount_create(&arc_mru->arcs_size);
-       refcount_create(&arc_mru_ghost->arcs_size);
-       refcount_create(&arc_mfu->arcs_size);
-       refcount_create(&arc_mfu_ghost->arcs_size);
-       refcount_create(&arc_l2c_only->arcs_size);
-
+       arc_state_init();
        buf_init();
 
-       arc_reclaim_thread_exit = FALSE;
-       arc_user_evicts_thread_exit = FALSE;
        list_create(&arc_prune_list, sizeof (arc_prune_t),
            offsetof(arc_prune_t, p_node));
-       arc_eviction_list = NULL;
        mutex_init(&arc_prune_mtx, NULL, MUTEX_DEFAULT, NULL);
-       bzero(&arc_eviction_hdr, sizeof (arc_buf_hdr_t));
 
        arc_prune_taskq = taskq_create("arc_prune", max_ncpus, defclsyspri,
            max_ncpus, INT_MAX, TASKQ_PREPOPULATE | TASKQ_DYNAMIC);
 
+       arc_reclaim_thread_exit = B_FALSE;
+
        arc_ksp = kstat_create("zfs", 0, "arcstats", "misc", KSTAT_TYPE_NAMED,
            sizeof (arc_stats) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
 
@@ -5463,10 +6380,7 @@ arc_init(void)
        (void) thread_create(NULL, 0, arc_reclaim_thread, NULL, 0, &p0,
            TS_RUN, defclsyspri);
 
-       (void) thread_create(NULL, 0, arc_user_evicts_thread, NULL, 0, &p0,
-           TS_RUN, defclsyspri);
-
-       arc_dead = FALSE;
+       arc_dead = B_FALSE;
        arc_warm = B_FALSE;
 
        /*
@@ -5499,10 +6413,10 @@ arc_fini(void)
 #endif /* _KERNEL */
 
        mutex_enter(&arc_reclaim_lock);
-       arc_reclaim_thread_exit = TRUE;
+       arc_reclaim_thread_exit = B_TRUE;
        /*
         * The reclaim thread will set arc_reclaim_thread_exit back to
-        * FALSE when it is finished exiting; we're waiting for that.
+        * B_FALSE when it is finished exiting; we're waiting for that.
         */
        while (arc_reclaim_thread_exit) {
                cv_signal(&arc_reclaim_thread_cv);
@@ -5510,22 +6424,10 @@ arc_fini(void)
        }
        mutex_exit(&arc_reclaim_lock);
 
-       mutex_enter(&arc_user_evicts_lock);
-       arc_user_evicts_thread_exit = TRUE;
-       /*
-        * The user evicts thread will set arc_user_evicts_thread_exit
-        * to FALSE when it is finished exiting; we're waiting for that.
-        */
-       while (arc_user_evicts_thread_exit) {
-               cv_signal(&arc_user_evicts_cv);
-               cv_wait(&arc_user_evicts_cv, &arc_user_evicts_lock);
-       }
-       mutex_exit(&arc_user_evicts_lock);
-
-       /* Use TRUE to ensure *all* buffers are evicted */
-       arc_flush(NULL, TRUE);
+       /* Use B_TRUE to ensure *all* buffers are evicted */
+       arc_flush(NULL, B_TRUE);
 
-       arc_dead = TRUE;
+       arc_dead = B_TRUE;
 
        if (arc_ksp != NULL) {
                kstat_delete(arc_ksp);
@@ -5550,27 +6452,7 @@ arc_fini(void)
        cv_destroy(&arc_reclaim_thread_cv);
        cv_destroy(&arc_reclaim_waiters_cv);
 
-       mutex_destroy(&arc_user_evicts_lock);
-       cv_destroy(&arc_user_evicts_cv);
-
-       refcount_destroy(&arc_anon->arcs_size);
-       refcount_destroy(&arc_mru->arcs_size);
-       refcount_destroy(&arc_mru_ghost->arcs_size);
-       refcount_destroy(&arc_mfu->arcs_size);
-       refcount_destroy(&arc_mfu_ghost->arcs_size);
-       refcount_destroy(&arc_l2c_only->arcs_size);
-
-       multilist_destroy(&arc_mru->arcs_list[ARC_BUFC_METADATA]);
-       multilist_destroy(&arc_mru_ghost->arcs_list[ARC_BUFC_METADATA]);
-       multilist_destroy(&arc_mfu->arcs_list[ARC_BUFC_METADATA]);
-       multilist_destroy(&arc_mfu_ghost->arcs_list[ARC_BUFC_METADATA]);
-       multilist_destroy(&arc_mru->arcs_list[ARC_BUFC_DATA]);
-       multilist_destroy(&arc_mru_ghost->arcs_list[ARC_BUFC_DATA]);
-       multilist_destroy(&arc_mfu->arcs_list[ARC_BUFC_DATA]);
-       multilist_destroy(&arc_mfu_ghost->arcs_list[ARC_BUFC_DATA]);
-       multilist_destroy(&arc_l2c_only->arcs_list[ARC_BUFC_METADATA]);
-       multilist_destroy(&arc_l2c_only->arcs_list[ARC_BUFC_DATA]);
-
+       arc_state_fini();
        buf_fini();
 
        ASSERT0(arc_loaned_bytes);
@@ -5700,7 +6582,6 @@ arc_fini(void)
  *     l2arc_write_max         max write bytes per interval
  *     l2arc_write_boost       extra write bytes during device warmup
  *     l2arc_noprefetch        skip caching prefetched buffers
- *     l2arc_nocompress        skip compressing buffers
  *     l2arc_headroom          number of max device writes to precache
  *     l2arc_headroom_boost    when we find compressed buffers during ARC
  *                             scanning, we multiply headroom by this
@@ -5860,9 +6741,13 @@ l2arc_do_free_on_write(void)
 
        for (df = list_tail(buflist); df; df = df_prev) {
                df_prev = list_prev(buflist, df);
-               ASSERT(df->l2df_data != NULL);
-               ASSERT(df->l2df_func != NULL);
-               df->l2df_func(df->l2df_data, df->l2df_size);
+               ASSERT3P(df->l2df_data, !=, NULL);
+               if (df->l2df_type == ARC_BUFC_METADATA) {
+                       zio_buf_free(df->l2df_data, df->l2df_size);
+               } else {
+                       ASSERT(df->l2df_type == ARC_BUFC_DATA);
+                       zio_data_buf_free(df->l2df_data, df->l2df_size);
+               }
                list_remove(buflist, df);
                kmem_free(df, sizeof (l2arc_data_free_t));
        }
@@ -5885,13 +6770,13 @@ l2arc_write_done(zio_t *zio)
        int64_t bytes_dropped = 0;
 
        cb = zio->io_private;
-       ASSERT(cb != NULL);
+       ASSERT3P(cb, !=, NULL);
        dev = cb->l2wcb_dev;
-       ASSERT(dev != NULL);
+       ASSERT3P(dev, !=, NULL);
        head = cb->l2wcb_head;
-       ASSERT(head != NULL);
+       ASSERT3P(head, !=, NULL);
        buflist = &dev->l2ad_buflist;
-       ASSERT(buflist != NULL);
+       ASSERT3P(buflist, !=, NULL);
        DTRACE_PROBE2(l2arc__iodone, zio_t *, zio,
            l2arc_write_callback_t *, cb);
 
@@ -5950,31 +6835,29 @@ top:
                ASSERT(HDR_HAS_L1HDR(hdr));
 
                /*
-                * We may have allocated a buffer for L2ARC compression,
-                * we must release it to avoid leaking this data.
+                * Skipped - drop L2ARC entry and mark the header as no
+                * longer L2 eligibile.
                 */
-               l2arc_release_cdata_buf(hdr);
-
                if (zio->io_error != 0) {
                        /*
                         * Error - drop L2ARC entry.
                         */
                        list_remove(buflist, hdr);
-                       hdr->b_flags &= ~ARC_FLAG_HAS_L2HDR;
+                       arc_hdr_clear_flags(hdr, ARC_FLAG_HAS_L2HDR);
 
-                       ARCSTAT_INCR(arcstat_l2_asize, -hdr->b_l2hdr.b_asize);
-                       ARCSTAT_INCR(arcstat_l2_size, -hdr->b_size);
+                       ARCSTAT_INCR(arcstat_l2_asize, -arc_hdr_size(hdr));
+                       ARCSTAT_INCR(arcstat_l2_size, -HDR_GET_LSIZE(hdr));
 
-                       bytes_dropped += hdr->b_l2hdr.b_asize;
+                       bytes_dropped += arc_hdr_size(hdr);
                        (void) refcount_remove_many(&dev->l2ad_alloc,
-                           hdr->b_l2hdr.b_asize, hdr);
+                           arc_hdr_size(hdr), hdr);
                }
 
                /*
                 * Allow ARC to begin reads and ghost list evictions to
                 * this L2ARC entry.
                 */
-               hdr->b_flags &= ~ARC_FLAG_L2_WRITING;
+               arc_hdr_clear_flags(hdr, ARC_FLAG_L2_WRITING);
 
                mutex_exit(hash_lock);
        }
@@ -6001,43 +6884,36 @@ l2arc_read_done(zio_t *zio)
 {
        l2arc_read_callback_t *cb;
        arc_buf_hdr_t *hdr;
-       arc_buf_t *buf;
        kmutex_t *hash_lock;
-       int equal;
+       boolean_t valid_cksum;
 
-       ASSERT(zio->io_vd != NULL);
+       ASSERT3P(zio->io_vd, !=, NULL);
        ASSERT(zio->io_flags & ZIO_FLAG_DONT_PROPAGATE);
 
        spa_config_exit(zio->io_spa, SCL_L2ARC, zio->io_vd);
 
        cb = zio->io_private;
-       ASSERT(cb != NULL);
-       buf = cb->l2rcb_buf;
-       ASSERT(buf != NULL);
+       ASSERT3P(cb, !=, NULL);
+       hdr = cb->l2rcb_hdr;
+       ASSERT3P(hdr, !=, NULL);
 
-       hash_lock = HDR_LOCK(buf->b_hdr);
+       hash_lock = HDR_LOCK(hdr);
        mutex_enter(hash_lock);
-       hdr = buf->b_hdr;
        ASSERT3P(hash_lock, ==, HDR_LOCK(hdr));
 
-       /*
-        * If the buffer was compressed, decompress it first.
-        */
-       if (cb->l2rcb_compress != ZIO_COMPRESS_OFF)
-               l2arc_decompress_zio(zio, hdr, cb->l2rcb_compress);
-       ASSERT(zio->io_data != NULL);
-       ASSERT3U(zio->io_size, ==, hdr->b_size);
-       ASSERT3U(BP_GET_LSIZE(&cb->l2rcb_bp), ==, hdr->b_size);
+       ASSERT3P(zio->io_data, !=, NULL);
 
        /*
         * Check this survived the L2ARC journey.
         */
-       equal = arc_cksum_equal(buf);
-       if (equal && zio->io_error == 0 && !HDR_L2_EVICTED(hdr)) {
+       ASSERT3P(zio->io_data, ==, hdr->b_l1hdr.b_pdata);
+       zio->io_bp_copy = cb->l2rcb_bp; /* XXX fix in L2ARC 2.0 */
+       zio->io_bp = &zio->io_bp_copy;  /* XXX fix in L2ARC 2.0 */
+
+       valid_cksum = arc_cksum_is_equal(hdr, zio);
+       if (valid_cksum && zio->io_error == 0 && !HDR_L2_EVICTED(hdr)) {
                mutex_exit(hash_lock);
-               zio->io_private = buf;
-               zio->io_bp_copy = cb->l2rcb_bp; /* XXX fix in L2ARC 2.0 */
-               zio->io_bp = &zio->io_bp_copy;  /* XXX fix in L2ARC 2.0 */
+               zio->io_private = hdr;
                arc_read_done(zio);
        } else {
                mutex_exit(hash_lock);
@@ -6050,7 +6926,7 @@ l2arc_read_done(zio_t *zio)
                } else {
                        zio->io_error = SET_ERROR(EIO);
                }
-               if (!equal)
+               if (!valid_cksum)
                        ARCSTAT_BUMP(arcstat_l2_cksum_bad);
 
                /*
@@ -6063,9 +6939,10 @@ l2arc_read_done(zio_t *zio)
 
                        ASSERT(!pio || pio->io_child_type == ZIO_CHILD_LOGICAL);
 
-                       zio_nowait(zio_read(pio, cb->l2rcb_spa, &cb->l2rcb_bp,
-                           buf->b_data, hdr->b_size, arc_read_done, buf,
-                           zio->io_priority, cb->l2rcb_flags, &cb->l2rcb_zb));
+                       zio_nowait(zio_read(pio, zio->io_spa, zio->io_bp,
+                           hdr->b_l1hdr.b_pdata, zio->io_size, arc_read_done,
+                           hdr, zio->io_priority, cb->l2rcb_flags,
+                           &cb->l2rcb_zb));
                }
        }
 
@@ -6215,12 +7092,11 @@ top:
                         */
                        if (HDR_L2_READING(hdr)) {
                                ARCSTAT_BUMP(arcstat_l2_evict_reading);
-                               hdr->b_flags |= ARC_FLAG_L2_EVICTED;
+                               arc_hdr_set_flags(hdr, ARC_FLAG_L2_EVICTED);
                        }
 
                        /* Ensure this header has finished being written */
                        ASSERT(!HDR_L2_WRITING(hdr));
-                       ASSERT3P(hdr->b_l1hdr.b_tmp_cdata, ==, NULL);
 
                        arc_hdr_l2hdr_destroy(hdr);
                }
@@ -6241,37 +7117,23 @@ top:
  * the delta by which the device hand has changed due to alignment).
  */
 static uint64_t
-l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
-    boolean_t *headroom_boost)
+l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
 {
        arc_buf_hdr_t *hdr, *hdr_prev, *head;
-       uint64_t write_asize, write_sz, headroom, buf_compress_minsz,
-           stats_size;
-       void *buf_data;
+       uint64_t write_asize, write_psize, write_sz, headroom;
        boolean_t full;
        l2arc_write_callback_t *cb;
        zio_t *pio, *wzio;
        uint64_t guid = spa_load_guid(spa);
        int try;
-       const boolean_t do_headroom_boost = *headroom_boost;
 
-       ASSERT(dev->l2ad_vdev != NULL);
-
-       /* Lower the flag now, we might want to raise it again later. */
-       *headroom_boost = B_FALSE;
+       ASSERT3P(dev->l2ad_vdev, !=, NULL);
 
        pio = NULL;
-       write_sz = write_asize = 0;
+       write_sz = write_asize = write_psize = 0;
        full = B_FALSE;
        head = kmem_cache_alloc(hdr_l2only_cache, KM_PUSHPAGE);
-       head->b_flags |= ARC_FLAG_L2_WRITE_HEAD;
-       head->b_flags |= ARC_FLAG_HAS_L2HDR;
-
-       /*
-        * We will want to try to compress buffers that are at least 2x the
-        * device sector size.
-        */
-       buf_compress_minsz = 2 << dev->l2ad_vdev->vdev_ashift;
+       arc_hdr_set_flags(head, ARC_FLAG_L2_WRITE_HEAD | ARC_FLAG_HAS_L2HDR);
 
        /*
         * Copy buffers for L2ARC writing.
@@ -6292,13 +7154,13 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
                        hdr = multilist_sublist_tail(mls);
 
                headroom = target_sz * l2arc_headroom;
-               if (do_headroom_boost)
+               if (zfs_compressed_arc_enabled)
                        headroom = (headroom * l2arc_headroom_boost) / 100;
 
                for (; hdr; hdr = hdr_prev) {
                        kmutex_t *hash_lock;
-                       uint64_t buf_sz;
-                       uint64_t buf_a_sz;
+                       uint64_t asize, size;
+                       void *to_write;
 
                        if (arc_warm == B_FALSE)
                                hdr_prev = multilist_sublist_next(mls, hdr);
@@ -6313,7 +7175,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
                                continue;
                        }
 
-                       passed_sz += hdr->b_size;
+                       passed_sz += HDR_GET_LSIZE(hdr);
                        if (passed_sz > headroom) {
                                /*
                                 * Searched too far.
@@ -6327,15 +7189,7 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
                                continue;
                        }
 
-                       /*
-                        * Assume that the buffer is not going to be compressed
-                        * and could take more space on disk because of a larger
-                        * disk block size.
-                        */
-                       buf_sz = hdr->b_size;
-                       buf_a_sz = vdev_psize_to_asize(dev->l2ad_vdev, buf_sz);
-
-                       if ((write_asize + buf_a_sz) > target_sz) {
+                       if ((write_asize + HDR_GET_LSIZE(hdr)) > target_sz) {
                                full = B_TRUE;
                                mutex_exit(hash_lock);
                                break;
@@ -6359,63 +7213,76 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
                                    ZIO_FLAG_CANFAIL);
                        }
 
-                       /*
-                        * Create and add a new L2ARC header.
-                        */
                        hdr->b_l2hdr.b_dev = dev;
-                       hdr->b_flags |= ARC_FLAG_L2_WRITING;
-                       /*
-                        * Temporarily stash the data buffer in b_tmp_cdata.
-                        * The subsequent write step will pick it up from
-                        * there. This is because can't access b_l1hdr.b_buf
-                        * without holding the hash_lock, which we in turn
-                        * can't access without holding the ARC list locks
-                        * (which we want to avoid during compression/writing)
-                        */
-                       hdr->b_l2hdr.b_compress = ZIO_COMPRESS_OFF;
-                       hdr->b_l2hdr.b_asize = hdr->b_size;
                        hdr->b_l2hdr.b_hits = 0;
-                       hdr->b_l1hdr.b_tmp_cdata = hdr->b_l1hdr.b_buf->b_data;
 
-                       /*
-                        * Explicitly set the b_daddr field to a known
-                        * value which means "invalid address". This
-                        * enables us to differentiate which stage of
-                        * l2arc_write_buffers() the particular header
-                        * is in (e.g. this loop, or the one below).
-                        * ARC_FLAG_L2_WRITING is not enough to make
-                        * this distinction, and we need to know in
-                        * order to do proper l2arc vdev accounting in
-                        * arc_release() and arc_hdr_destroy().
-                        *
-                        * Note, we can't use a new flag to distinguish
-                        * the two stages because we don't hold the
-                        * header's hash_lock below, in the second stage
-                        * of this function. Thus, we can't simply
-                        * change the b_flags field to denote that the
-                        * IO has been sent. We can change the b_daddr
-                        * field of the L2 portion, though, since we'll
-                        * be holding the l2ad_mtx; which is why we're
-                        * using it to denote the header's state change.
-                        */
-                       hdr->b_l2hdr.b_daddr = L2ARC_ADDR_UNSET;
-                       hdr->b_flags |= ARC_FLAG_HAS_L2HDR;
+                       hdr->b_l2hdr.b_daddr = dev->l2ad_hand;
+                       arc_hdr_set_flags(hdr,
+                           ARC_FLAG_L2_WRITING | ARC_FLAG_HAS_L2HDR);
 
                        mutex_enter(&dev->l2ad_mtx);
                        list_insert_head(&dev->l2ad_buflist, hdr);
                        mutex_exit(&dev->l2ad_mtx);
 
                        /*
-                        * Compute and store the buffer cksum before
-                        * writing.  On debug the cksum is verified first.
+                        * We rely on the L1 portion of the header below, so
+                        * it's invalid for this header to have been evicted out
+                        * of the ghost cache, prior to being written out. The
+                        * ARC_FLAG_L2_WRITING bit ensures this won't happen.
+                        */
+                       ASSERT(HDR_HAS_L1HDR(hdr));
+
+                       ASSERT3U(HDR_GET_PSIZE(hdr), >, 0);
+                       ASSERT3P(hdr->b_l1hdr.b_pdata, !=, NULL);
+                       ASSERT3U(arc_hdr_size(hdr), >, 0);
+                       size = arc_hdr_size(hdr);
+
+                       (void) refcount_add_many(&dev->l2ad_alloc, size, hdr);
+
+                       /*
+                        * Normally the L2ARC can use the hdr's data, but if
+                        * we're sharing data between the hdr and one of its
+                        * bufs, L2ARC needs its own copy of the data so that
+                        * the ZIO below can't race with the buf consumer. To
+                        * ensure that this copy will be available for the
+                        * lifetime of the ZIO and be cleaned up afterwards, we
+                        * add it to the l2arc_free_on_write queue.
+                        */
+                       if (!HDR_SHARED_DATA(hdr)) {
+                               to_write = hdr->b_l1hdr.b_pdata;
+                       } else {
+                               arc_buf_contents_t type = arc_buf_type(hdr);
+                               if (type == ARC_BUFC_METADATA) {
+                                       to_write = zio_buf_alloc(size);
+                               } else {
+                                       ASSERT3U(type, ==, ARC_BUFC_DATA);
+                                       to_write = zio_data_buf_alloc(size);
+                               }
+
+                               bcopy(hdr->b_l1hdr.b_pdata, to_write, size);
+                               l2arc_free_data_on_write(to_write, size, type);
+                       }
+                       wzio = zio_write_phys(pio, dev->l2ad_vdev,
+                           hdr->b_l2hdr.b_daddr, size, to_write,
+                           ZIO_CHECKSUM_OFF, NULL, hdr,
+                           ZIO_PRIORITY_ASYNC_WRITE,
+                           ZIO_FLAG_CANFAIL, B_FALSE);
+
+                       write_sz += HDR_GET_LSIZE(hdr);
+                       DTRACE_PROBE2(l2arc__write, vdev_t *, dev->l2ad_vdev,
+                           zio_t *, wzio);
+
+                       write_asize += size;
+                       /*
+                        * Keep the clock hand suitably device-aligned.
                         */
-                       arc_cksum_verify(hdr->b_l1hdr.b_buf);
-                       arc_cksum_compute(hdr->b_l1hdr.b_buf, B_TRUE);
+                       asize = vdev_psize_to_asize(dev->l2ad_vdev, size);
+                       write_psize += asize;
+                       dev->l2ad_hand += asize;
 
                        mutex_exit(hash_lock);
 
-                       write_sz += buf_sz;
-                       write_asize += buf_a_sz;
+                       (void) zio_nowait(wzio);
                }
 
                multilist_sublist_unlock(mls);
@@ -6432,104 +7299,12 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
                return (0);
        }
 
-       mutex_enter(&dev->l2ad_mtx);
-
-       /*
-        * Note that elsewhere in this file arcstat_l2_asize
-        * and the used space on l2ad_vdev are updated using b_asize,
-        * which is not necessarily rounded up to the device block size.
-        * Too keep accounting consistent we do the same here as well:
-        * stats_size accumulates the sum of b_asize of the written buffers,
-        * while write_asize accumulates the sum of b_asize rounded up
-        * to the device block size.
-        * The latter sum is used only to validate the corectness of the code.
-        */
-       stats_size = 0;
-       write_asize = 0;
-
-       /*
-        * Now start writing the buffers. We're starting at the write head
-        * and work backwards, retracing the course of the buffer selector
-        * loop above.
-        */
-       for (hdr = list_prev(&dev->l2ad_buflist, head); hdr;
-           hdr = list_prev(&dev->l2ad_buflist, hdr)) {
-               uint64_t buf_sz;
-
-               /*
-                * We rely on the L1 portion of the header below, so
-                * it's invalid for this header to have been evicted out
-                * of the ghost cache, prior to being written out. The
-                * ARC_FLAG_L2_WRITING bit ensures this won't happen.
-                */
-               ASSERT(HDR_HAS_L1HDR(hdr));
-
-               /*
-                * We shouldn't need to lock the buffer here, since we flagged
-                * it as ARC_FLAG_L2_WRITING in the previous step, but we must
-                * take care to only access its L2 cache parameters. In
-                * particular, hdr->l1hdr.b_buf may be invalid by now due to
-                * ARC eviction.
-                */
-               hdr->b_l2hdr.b_daddr = dev->l2ad_hand;
-
-               if ((!l2arc_nocompress && HDR_L2COMPRESS(hdr)) &&
-                   hdr->b_l2hdr.b_asize >= buf_compress_minsz) {
-                       if (l2arc_compress_buf(hdr)) {
-                               /*
-                                * If compression succeeded, enable headroom
-                                * boost on the next scan cycle.
-                                */
-                               *headroom_boost = B_TRUE;
-                       }
-               }
-
-               /*
-                * Pick up the buffer data we had previously stashed away
-                * (and now potentially also compressed).
-                */
-               buf_data = hdr->b_l1hdr.b_tmp_cdata;
-               buf_sz = hdr->b_l2hdr.b_asize;
-
-               /*
-                * We need to do this regardless if buf_sz is zero or
-                * not, otherwise, when this l2hdr is evicted we'll
-                * remove a reference that was never added.
-                */
-               (void) refcount_add_many(&dev->l2ad_alloc, buf_sz, hdr);
-
-               /* Compression may have squashed the buffer to zero length. */
-               if (buf_sz != 0) {
-                       uint64_t buf_a_sz;
-
-                       wzio = zio_write_phys(pio, dev->l2ad_vdev,
-                           dev->l2ad_hand, buf_sz, buf_data, ZIO_CHECKSUM_OFF,
-                           NULL, NULL, ZIO_PRIORITY_ASYNC_WRITE,
-                           ZIO_FLAG_CANFAIL, B_FALSE);
-
-                       DTRACE_PROBE2(l2arc__write, vdev_t *, dev->l2ad_vdev,
-                           zio_t *, wzio);
-                       (void) zio_nowait(wzio);
-
-                       stats_size += buf_sz;
-
-                       /*
-                        * Keep the clock hand suitably device-aligned.
-                        */
-                       buf_a_sz = vdev_psize_to_asize(dev->l2ad_vdev, buf_sz);
-                       write_asize += buf_a_sz;
-                       dev->l2ad_hand += buf_a_sz;
-               }
-       }
-
-       mutex_exit(&dev->l2ad_mtx);
-
        ASSERT3U(write_asize, <=, target_sz);
        ARCSTAT_BUMP(arcstat_l2_writes_sent);
        ARCSTAT_INCR(arcstat_l2_write_bytes, write_asize);
        ARCSTAT_INCR(arcstat_l2_size, write_sz);
-       ARCSTAT_INCR(arcstat_l2_asize, stats_size);
-       vdev_space_update(dev->l2ad_vdev, stats_size, 0, 0);
+       ARCSTAT_INCR(arcstat_l2_asize, write_asize);
+       vdev_space_update(dev->l2ad_vdev, write_asize, 0, 0);
 
        /*
         * Bump device hand to the device start if it is approaching the end.
@@ -6547,186 +7322,6 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
        return (write_asize);
 }
 
-/*
- * Compresses an L2ARC buffer.
- * The data to be compressed must be prefilled in l1hdr.b_tmp_cdata and its
- * size in l2hdr->b_asize. This routine tries to compress the data and
- * depending on the compression result there are three possible outcomes:
- * *) The buffer was incompressible. The original l2hdr contents were left
- *    untouched and are ready for writing to an L2 device.
- * *) The buffer was all-zeros, so there is no need to write it to an L2
- *    device. To indicate this situation b_tmp_cdata is NULL'ed, b_asize is
- *    set to zero and b_compress is set to ZIO_COMPRESS_EMPTY.
- * *) Compression succeeded and b_tmp_cdata was replaced with a temporary
- *    data buffer which holds the compressed data to be written, and b_asize
- *    tells us how much data there is. b_compress is set to the appropriate
- *    compression algorithm. Once writing is done, invoke
- *    l2arc_release_cdata_buf on this l2hdr to free this temporary buffer.
- *
- * Returns B_TRUE if compression succeeded, or B_FALSE if it didn't (the
- * buffer was incompressible).
- */
-static boolean_t
-l2arc_compress_buf(arc_buf_hdr_t *hdr)
-{
-       void *cdata;
-       size_t csize, len, rounded;
-       l2arc_buf_hdr_t *l2hdr;
-
-       ASSERT(HDR_HAS_L2HDR(hdr));
-
-       l2hdr = &hdr->b_l2hdr;
-
-       ASSERT(HDR_HAS_L1HDR(hdr));
-       ASSERT3U(l2hdr->b_compress, ==, ZIO_COMPRESS_OFF);
-       ASSERT(hdr->b_l1hdr.b_tmp_cdata != NULL);
-
-       len = l2hdr->b_asize;
-       cdata = zio_data_buf_alloc(len);
-       ASSERT3P(cdata, !=, NULL);
-       csize = zio_compress_data(ZIO_COMPRESS_LZ4, hdr->b_l1hdr.b_tmp_cdata,
-           cdata, l2hdr->b_asize);
-
-       rounded = P2ROUNDUP(csize, (size_t)SPA_MINBLOCKSIZE);
-       if (rounded > csize) {
-               bzero((char *)cdata + csize, rounded - csize);
-               csize = rounded;
-       }
-
-       if (csize == 0) {
-               /* zero block, indicate that there's nothing to write */
-               zio_data_buf_free(cdata, len);
-               l2hdr->b_compress = ZIO_COMPRESS_EMPTY;
-               l2hdr->b_asize = 0;
-               hdr->b_l1hdr.b_tmp_cdata = NULL;
-               ARCSTAT_BUMP(arcstat_l2_compress_zeros);
-               return (B_TRUE);
-       } else if (csize > 0 && csize < len) {
-               /*
-                * Compression succeeded, we'll keep the cdata around for
-                * writing and release it afterwards.
-                */
-               l2hdr->b_compress = ZIO_COMPRESS_LZ4;
-               l2hdr->b_asize = csize;
-               hdr->b_l1hdr.b_tmp_cdata = cdata;
-               ARCSTAT_BUMP(arcstat_l2_compress_successes);
-               return (B_TRUE);
-       } else {
-               /*
-                * Compression failed, release the compressed buffer.
-                * l2hdr will be left unmodified.
-                */
-               zio_data_buf_free(cdata, len);
-               ARCSTAT_BUMP(arcstat_l2_compress_failures);
-               return (B_FALSE);
-       }
-}
-
-/*
- * Decompresses a zio read back from an l2arc device. On success, the
- * underlying zio's io_data buffer is overwritten by the uncompressed
- * version. On decompression error (corrupt compressed stream), the
- * zio->io_error value is set to signal an I/O error.
- *
- * Please note that the compressed data stream is not checksummed, so
- * if the underlying device is experiencing data corruption, we may feed
- * corrupt data to the decompressor, so the decompressor needs to be
- * able to handle this situation (LZ4 does).
- */
-static void
-l2arc_decompress_zio(zio_t *zio, arc_buf_hdr_t *hdr, enum zio_compress c)
-{
-       uint64_t csize;
-       void *cdata;
-
-       ASSERT(L2ARC_IS_VALID_COMPRESS(c));
-
-       if (zio->io_error != 0) {
-               /*
-                * An io error has occured, just restore the original io
-                * size in preparation for a main pool read.
-                */
-               zio->io_orig_size = zio->io_size = hdr->b_size;
-               return;
-       }
-
-       if (c == ZIO_COMPRESS_EMPTY) {
-               /*
-                * An empty buffer results in a null zio, which means we
-                * need to fill its io_data after we're done restoring the
-                * buffer's contents.
-                */
-               ASSERT(hdr->b_l1hdr.b_buf != NULL);
-               bzero(hdr->b_l1hdr.b_buf->b_data, hdr->b_size);
-               zio->io_data = zio->io_orig_data = hdr->b_l1hdr.b_buf->b_data;
-       } else {
-               ASSERT(zio->io_data != NULL);
-               /*
-                * We copy the compressed data from the start of the arc buffer
-                * (the zio_read will have pulled in only what we need, the
-                * rest is garbage which we will overwrite at decompression)
-                * and then decompress back to the ARC data buffer. This way we
-                * can minimize copying by simply decompressing back over the
-                * original compressed data (rather than decompressing to an
-                * aux buffer and then copying back the uncompressed buffer,
-                * which is likely to be much larger).
-                */
-               csize = zio->io_size;
-               cdata = zio_data_buf_alloc(csize);
-               bcopy(zio->io_data, cdata, csize);
-               if (zio_decompress_data(c, cdata, zio->io_data, csize,
-                   hdr->b_size) != 0)
-                       zio->io_error = EIO;
-               zio_data_buf_free(cdata, csize);
-       }
-
-       /* Restore the expected uncompressed IO size. */
-       zio->io_orig_size = zio->io_size = hdr->b_size;
-}
-
-/*
- * Releases the temporary b_tmp_cdata buffer in an l2arc header structure.
- * This buffer serves as a temporary holder of compressed data while
- * the buffer entry is being written to an l2arc device. Once that is
- * done, we can dispose of it.
- */
-static void
-l2arc_release_cdata_buf(arc_buf_hdr_t *hdr)
-{
-       enum zio_compress comp;
-
-       ASSERT(HDR_HAS_L1HDR(hdr));
-       ASSERT(HDR_HAS_L2HDR(hdr));
-       comp = hdr->b_l2hdr.b_compress;
-       ASSERT(comp == ZIO_COMPRESS_OFF || L2ARC_IS_VALID_COMPRESS(comp));
-
-       if (comp == ZIO_COMPRESS_OFF) {
-               /*
-                * In this case, b_tmp_cdata points to the same buffer
-                * as the arc_buf_t's b_data field. We don't want to
-                * free it, since the arc_buf_t will handle that.
-                */
-               hdr->b_l1hdr.b_tmp_cdata = NULL;
-       } else if (comp == ZIO_COMPRESS_EMPTY) {
-               /*
-                * In this case, b_tmp_cdata was compressed to an empty
-                * buffer, thus there's nothing to free and b_tmp_cdata
-                * should have been set to NULL in l2arc_write_buffers().
-                */
-               ASSERT3P(hdr->b_l1hdr.b_tmp_cdata, ==, NULL);
-       } else {
-               /*
-                * If the data was compressed, then we've allocated a
-                * temporary buffer for it, so now we need to release it.
-                */
-               ASSERT(hdr->b_l1hdr.b_tmp_cdata != NULL);
-               zio_data_buf_free(hdr->b_l1hdr.b_tmp_cdata,
-                   hdr->b_size);
-               hdr->b_l1hdr.b_tmp_cdata = NULL;
-       }
-
-}
-
 /*
  * This thread feeds the L2ARC at regular intervals.  This is the beating
  * heart of the L2ARC.
@@ -6739,7 +7334,6 @@ l2arc_feed_thread(void)
        spa_t *spa;
        uint64_t size, wrote;
        clock_t begin, next = ddi_get_lbolt();
-       boolean_t headroom_boost = B_FALSE;
        fstrans_cookie_t cookie;
 
        CALLB_CPR_INIT(&cpr, &l2arc_feed_thr_lock, callb_generic_cpr, FTAG);
@@ -6779,7 +7373,7 @@ l2arc_feed_thread(void)
                        continue;
 
                spa = dev->l2ad_spa;
-               ASSERT(spa != NULL);
+               ASSERT3P(spa, !=, NULL);
 
                /*
                 * If the pool is read-only then force the feed thread to
@@ -6812,7 +7406,7 @@ l2arc_feed_thread(void)
                /*
                 * Write ARC buffers.
                 */
-               wrote = l2arc_write_buffers(spa, dev, size, &headroom_boost);
+               wrote = l2arc_write_buffers(spa, dev, size);
 
                /*
                 * Calculate interval between writes.
@@ -6907,7 +7501,7 @@ l2arc_remove_vdev(vdev_t *vd)
                        break;
                }
        }
-       ASSERT(remdev != NULL);
+       ASSERT3P(remdev, !=, NULL);
 
        /*
         * Remove device from global list
@@ -6996,7 +7590,6 @@ l2arc_stop(void)
 EXPORT_SYMBOL(arc_buf_size);
 EXPORT_SYMBOL(arc_write);
 EXPORT_SYMBOL(arc_read);
-EXPORT_SYMBOL(arc_buf_remove_ref);
 EXPORT_SYMBOL(arc_buf_info);
 EXPORT_SYMBOL(arc_getbuf_func);
 EXPORT_SYMBOL(arc_add_prune_callback);
@@ -7011,6 +7604,10 @@ MODULE_PARM_DESC(zfs_arc_max, "Max arc size");
 module_param(zfs_arc_meta_limit, ulong, 0644);
 MODULE_PARM_DESC(zfs_arc_meta_limit, "Meta limit for arc size");
 
+module_param(zfs_arc_meta_limit_percent, ulong, 0644);
+MODULE_PARM_DESC(zfs_arc_meta_limit_percent,
+       "Percent of arc size for arc meta limit");
+
 module_param(zfs_arc_meta_min, ulong, 0644);
 MODULE_PARM_DESC(zfs_arc_meta_min, "Min arc metadata");
 
@@ -7039,12 +7636,12 @@ MODULE_PARM_DESC(zfs_arc_shrink_shift, "log2(fraction of arc to reclaim)");
 module_param(zfs_arc_p_min_shift, int, 0644);
 MODULE_PARM_DESC(zfs_arc_p_min_shift, "arc_c shift to calc min/max arc_p");
 
-module_param(zfs_disable_dup_eviction, int, 0644);
-MODULE_PARM_DESC(zfs_disable_dup_eviction, "disable duplicate buffer eviction");
-
 module_param(zfs_arc_average_blocksize, int, 0444);
 MODULE_PARM_DESC(zfs_arc_average_blocksize, "Target average block size");
 
+module_param(zfs_compressed_arc_enabled, int, 0644);
+MODULE_PARM_DESC(zfs_arc_average_blocksize, "Disable compressed arc buffers");
+
 module_param(zfs_arc_min_prefetch_lifespan, int, 0644);
 MODULE_PARM_DESC(zfs_arc_min_prefetch_lifespan, "Min life of prefetch block");
 
@@ -7073,9 +7670,6 @@ MODULE_PARM_DESC(l2arc_feed_min_ms, "Min feed interval in milliseconds");
 module_param(l2arc_noprefetch, int, 0644);
 MODULE_PARM_DESC(l2arc_noprefetch, "Skip caching prefetched buffers");
 
-module_param(l2arc_nocompress, int, 0644);
-MODULE_PARM_DESC(l2arc_nocompress, "Skip compressing L2ARC buffers");
-
 module_param(l2arc_feed_again, int, 0644);
 MODULE_PARM_DESC(l2arc_feed_again, "Turbo L2ARC warmup");
 
@@ -7089,4 +7683,15 @@ MODULE_PARM_DESC(zfs_arc_lotsfree_percent,
 module_param(zfs_arc_sys_free, ulong, 0644);
 MODULE_PARM_DESC(zfs_arc_sys_free, "System free memory target size in bytes");
 
+module_param(zfs_arc_dnode_limit, ulong, 0644);
+MODULE_PARM_DESC(zfs_arc_dnode_limit, "Minimum bytes of dnodes in arc");
+
+module_param(zfs_arc_dnode_limit_percent, ulong, 0644);
+MODULE_PARM_DESC(zfs_arc_dnode_limit_percent,
+       "Percent of ARC meta buffers for dnodes");
+
+module_param(zfs_arc_dnode_reduce_percent, ulong, 0644);
+MODULE_PARM_DESC(zfs_arc_dnode_reduce_percent,
+       "Percentage of excess dnodes to try to unpin");
+
 #endif
index 9f62d7b911f361ea2397bd9f96c4a756b883d6c5..c0edc9d768e860e562d77e0599572e8e9fcbc18f 100644 (file)
@@ -156,7 +156,7 @@ bptree_visit_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
        int err;
        struct bptree_args *ba = arg;
 
-       if (BP_IS_HOLE(bp))
+       if (bp == NULL || BP_IS_HOLE(bp))
                return (0);
 
        err = ba->ba_func(ba->ba_arg, bp, ba->ba_tx);
diff --git a/zfs/module/zfs/bqueue.c b/zfs/module/zfs/bqueue.c
new file mode 100644 (file)
index 0000000..0e49080
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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.
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2014 by Delphix. All rights reserved.
+ */
+
+#include       <sys/bqueue.h>
+#include       <sys/zfs_context.h>
+
+static inline bqueue_node_t *
+obj2node(bqueue_t *q, void *data)
+{
+       return ((bqueue_node_t *)((char *)data + q->bq_node_offset));
+}
+
+/*
+ * Initialize a blocking queue  The maximum capacity of the queue is set to
+ * size.  Types that want to be stored in a bqueue must contain a bqueue_node_t,
+ * and offset should give its offset from the start of the struct.  Return 0 on
+ * success, or -1 on failure.
+ */
+int
+bqueue_init(bqueue_t *q, uint64_t size, size_t node_offset)
+{
+       list_create(&q->bq_list, node_offset + sizeof (bqueue_node_t),
+           node_offset + offsetof(bqueue_node_t, bqn_node));
+       cv_init(&q->bq_add_cv, NULL, CV_DEFAULT, NULL);
+       cv_init(&q->bq_pop_cv, NULL, CV_DEFAULT, NULL);
+       mutex_init(&q->bq_lock, NULL, MUTEX_DEFAULT, NULL);
+       q->bq_node_offset = node_offset;
+       q->bq_size = 0;
+       q->bq_maxsize = size;
+       return (0);
+}
+
+/*
+ * Destroy a blocking queue.  This function asserts that there are no
+ * elements in the queue, and no one is blocked on the condition
+ * variables.
+ */
+void
+bqueue_destroy(bqueue_t *q)
+{
+       ASSERT0(q->bq_size);
+       cv_destroy(&q->bq_add_cv);
+       cv_destroy(&q->bq_pop_cv);
+       mutex_destroy(&q->bq_lock);
+       list_destroy(&q->bq_list);
+}
+
+/*
+ * Add data to q, consuming size units of capacity.  If there is insufficient
+ * capacity to consume size units, block until capacity exists.  Asserts size is
+ * > 0.
+ */
+void
+bqueue_enqueue(bqueue_t *q, void *data, uint64_t item_size)
+{
+       ASSERT3U(item_size, >, 0);
+       ASSERT3U(item_size, <=, q->bq_maxsize);
+       mutex_enter(&q->bq_lock);
+       obj2node(q, data)->bqn_size = item_size;
+       while (q->bq_size + item_size > q->bq_maxsize) {
+               cv_wait(&q->bq_add_cv, &q->bq_lock);
+       }
+       q->bq_size += item_size;
+       list_insert_tail(&q->bq_list, data);
+       cv_signal(&q->bq_pop_cv);
+       mutex_exit(&q->bq_lock);
+}
+/*
+ * Take the first element off of q.  If there are no elements on the queue, wait
+ * until one is put there.  Return the removed element.
+ */
+void *
+bqueue_dequeue(bqueue_t *q)
+{
+       void *ret = NULL;
+       uint64_t item_size;
+       mutex_enter(&q->bq_lock);
+       while (q->bq_size == 0) {
+               cv_wait(&q->bq_pop_cv, &q->bq_lock);
+       }
+       ret = list_remove_head(&q->bq_list);
+       ASSERT3P(ret, !=, NULL);
+       item_size = obj2node(q, ret)->bqn_size;
+       q->bq_size -= item_size;
+       mutex_exit(&q->bq_lock);
+       cv_signal(&q->bq_add_cv);
+       return (ret);
+}
+
+/*
+ * Returns true if the space used is 0.
+ */
+boolean_t
+bqueue_empty(bqueue_t *q)
+{
+       return (q->bq_size == 0);
+}
index 483067cc7ba45101c4b497d1bd131816c7270c4f..1d8c0518a2bcdb7fc9d37e5401d2781a80e41151 100644 (file)
@@ -21,7 +21,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
- * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
 #include <sys/blkptr.h>
 #include <sys/range_tree.h>
 #include <sys/trace_dbuf.h>
+#include <sys/callb.h>
 
 struct dbuf_hold_impl_data {
        /* Function arguments */
        dnode_t *dh_dn;
        uint8_t dh_level;
        uint64_t dh_blkid;
-       int dh_fail_sparse;
+       boolean_t dh_fail_sparse;
+       boolean_t dh_fail_uncached;
        void *dh_tag;
        dmu_buf_impl_t **dh_dbp;
        /* Local variables */
@@ -65,17 +67,18 @@ struct dbuf_hold_impl_data {
 };
 
 static void __dbuf_hold_impl_init(struct dbuf_hold_impl_data *dh,
-    dnode_t *dn, uint8_t level, uint64_t blkid, int fail_sparse,
-    void *tag, dmu_buf_impl_t **dbp, int depth);
+    dnode_t *dn, uint8_t level, uint64_t blkid, boolean_t fail_sparse,
+       boolean_t fail_uncached,
+       void *tag, dmu_buf_impl_t **dbp, int depth);
 static int __dbuf_hold_impl(struct dbuf_hold_impl_data *dh);
 
+uint_t zfs_dbuf_evict_key;
 /*
  * Number of times that zfs_free_range() took the slow path while doing
  * a zfs receive.  A nonzero value indicates a potential performance problem.
  */
 uint64_t zfs_free_range_recv_miss;
 
-static void dbuf_destroy(dmu_buf_impl_t *db);
 static boolean_t dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx);
 static void dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx);
 
@@ -87,9 +90,76 @@ extern inline void dmu_buf_init_user(dmu_buf_user_t *dbu,
 /*
  * Global data structures and functions for the dbuf cache.
  */
-static kmem_cache_t *dbuf_cache;
+static kmem_cache_t *dbuf_kmem_cache;
 static taskq_t *dbu_evict_taskq;
 
+static kthread_t *dbuf_cache_evict_thread;
+static kmutex_t dbuf_evict_lock;
+static kcondvar_t dbuf_evict_cv;
+static boolean_t dbuf_evict_thread_exit;
+
+/*
+ * LRU cache of dbufs. The dbuf cache maintains a list of dbufs that
+ * are not currently held but have been recently released. These dbufs
+ * are not eligible for arc eviction until they are aged out of the cache.
+ * Dbufs are added to the dbuf cache once the last hold is released. If a
+ * dbuf is later accessed and still exists in the dbuf cache, then it will
+ * be removed from the cache and later re-added to the head of the cache.
+ * Dbufs that are aged out of the cache will be immediately destroyed and
+ * become eligible for arc eviction.
+ */
+static multilist_t dbuf_cache;
+static refcount_t dbuf_cache_size;
+unsigned long  dbuf_cache_max_bytes = 100 * 1024 * 1024;
+
+/* Cap the size of the dbuf cache to log2 fraction of arc size. */
+int dbuf_cache_max_shift = 5;
+
+/*
+ * The dbuf cache uses a three-stage eviction policy:
+ *     - A low water marker designates when the dbuf eviction thread
+ *     should stop evicting from the dbuf cache.
+ *     - When we reach the maximum size (aka mid water mark), we
+ *     signal the eviction thread to run.
+ *     - The high water mark indicates when the eviction thread
+ *     is unable to keep up with the incoming load and eviction must
+ *     happen in the context of the calling thread.
+ *
+ * The dbuf cache:
+ *                                                 (max size)
+ *                                      low water   mid water   hi water
+ * +----------------------------------------+----------+----------+
+ * |                                        |          |          |
+ * |                                        |          |          |
+ * |                                        |          |          |
+ * |                                        |          |          |
+ * +----------------------------------------+----------+----------+
+ *                                        stop        signal     evict
+ *                                      evicting     eviction   directly
+ *                                                    thread
+ *
+ * The high and low water marks indicate the operating range for the eviction
+ * thread. The low water mark is, by default, 90% of the total size of the
+ * cache and the high water mark is at 110% (both of these percentages can be
+ * changed by setting dbuf_cache_lowater_pct and dbuf_cache_hiwater_pct,
+ * respectively). The eviction thread will try to ensure that the cache remains
+ * within this range by waking up every second and checking if the cache is
+ * above the low water mark. The thread can also be woken up by callers adding
+ * elements into the cache if the cache is larger than the mid water (i.e max
+ * cache size). Once the eviction thread is woken up and eviction is required,
+ * it will continue evicting buffers until it's able to reduce the cache size
+ * to the low water mark. If the cache size continues to grow and hits the high
+ * water mark, then callers adding elments to the cache will begin to evict
+ * directly from the cache until the cache is no longer above the high water
+ * mark.
+ */
+
+/*
+ * The percentage above and below the maximum cache size.
+ */
+uint_t dbuf_cache_hiwater_pct = 10;
+uint_t dbuf_cache_lowater_pct = 10;
+
 /* ARGSUSED */
 static int
 dbuf_cons(void *vdb, void *unused, int kmflag)
@@ -99,7 +169,9 @@ dbuf_cons(void *vdb, void *unused, int kmflag)
 
        mutex_init(&db->db_mtx, NULL, MUTEX_DEFAULT, NULL);
        cv_init(&db->db_changed, NULL, CV_DEFAULT, NULL);
+       multilist_link_init(&db->db_cache_link);
        refcount_create(&db->db_holds);
+       multilist_link_init(&db->db_cache_link);
 
        return (0);
 }
@@ -111,6 +183,7 @@ dbuf_dest(void *vdb, void *unused)
        dmu_buf_impl_t *db = vdb;
        mutex_destroy(&db->db_mtx);
        cv_destroy(&db->db_changed);
+       ASSERT(!multilist_link_active(&db->db_cache_link));
        refcount_destroy(&db->db_holds);
 }
 
@@ -140,8 +213,6 @@ dbuf_hash(void *os, uint64_t obj, uint8_t lvl, uint64_t blkid)
        return (crc);
 }
 
-#define        DBUF_HASH(os, obj, level, blkid) dbuf_hash(os, obj, level, blkid);
-
 #define        DBUF_EQUAL(dbuf, os, obj, level, blkid)         \
        ((dbuf)->db.db_object == (obj) &&               \
        (dbuf)->db_objset == (os) &&                    \
@@ -156,7 +227,7 @@ dbuf_find(objset_t *os, uint64_t obj, uint8_t level, uint64_t blkid)
        uint64_t idx;
        dmu_buf_impl_t *db;
 
-       hv = DBUF_HASH(os, obj, level, blkid);
+       hv = dbuf_hash(os, obj, level, blkid);
        idx = hv & h->hash_table_mask;
 
        mutex_enter(DBUF_HASH_MUTEX(h, idx));
@@ -209,7 +280,7 @@ dbuf_hash_insert(dmu_buf_impl_t *db)
        dmu_buf_impl_t *dbf;
 
        blkid = db->db_blkid;
-       hv = DBUF_HASH(os, obj, level, blkid);
+       hv = dbuf_hash(os, obj, level, blkid);
        idx = hv & h->hash_table_mask;
 
        mutex_enter(DBUF_HASH_MUTEX(h, idx));
@@ -228,7 +299,7 @@ dbuf_hash_insert(dmu_buf_impl_t *db)
        db->db_hash_next = h->hash_table[idx];
        h->hash_table[idx] = db;
        mutex_exit(DBUF_HASH_MUTEX(h, idx));
-       atomic_add_64(&dbuf_hash_count, 1);
+       atomic_inc_64(&dbuf_hash_count);
 
        return (NULL);
 }
@@ -243,7 +314,7 @@ dbuf_hash_remove(dmu_buf_impl_t *db)
        uint64_t hv, idx;
        dmu_buf_impl_t *dbf, **dbp;
 
-       hv = DBUF_HASH(db->db_objset, db->db.db_object,
+       hv = dbuf_hash(db->db_objset, db->db.db_object,
            db->db_level, db->db_blkid);
        idx = hv & h->hash_table_mask;
 
@@ -264,11 +335,9 @@ dbuf_hash_remove(dmu_buf_impl_t *db)
        *dbp = db->db_hash_next;
        db->db_hash_next = NULL;
        mutex_exit(DBUF_HASH_MUTEX(h, idx));
-       atomic_add_64(&dbuf_hash_count, -1);
+       atomic_dec_64(&dbuf_hash_count);
 }
 
-static arc_evict_func_t dbuf_do_evict;
-
 typedef enum {
        DBVU_EVICTING,
        DBVU_NOT_EVICTING
@@ -356,17 +425,186 @@ dbuf_is_metadata(dmu_buf_impl_t *db)
        }
 }
 
-void
-dbuf_evict(dmu_buf_impl_t *db)
+
+/*
+ * This function *must* return indices evenly distributed between all
+ * sublists of the multilist. This is needed due to how the dbuf eviction
+ * code is laid out; dbuf_evict_thread() assumes dbufs are evenly
+ * distributed between all sublists and uses this assumption when
+ * deciding which sublist to evict from and how much to evict from it.
+ */
+unsigned int
+dbuf_cache_multilist_index_func(multilist_t *ml, void *obj)
 {
-       ASSERT(MUTEX_HELD(&db->db_mtx));
-       ASSERT(db->db_buf == NULL);
-       ASSERT(db->db_data_pending == NULL);
+       dmu_buf_impl_t *db = obj;
+
+       /*
+        * The assumption here, is the hash value for a given
+        * dmu_buf_impl_t will remain constant throughout it's lifetime
+        * (i.e. it's objset, object, level and blkid fields don't change).
+        * Thus, we don't need to store the dbuf's sublist index
+        * on insertion, as this index can be recalculated on removal.
+        *
+        * Also, the low order bits of the hash value are thought to be
+        * distributed evenly. Otherwise, in the case that the multilist
+        * has a power of two number of sublists, each sublists' usage
+        * would not be evenly distributed.
+        */
+       return (dbuf_hash(db->db_objset, db->db.db_object,
+           db->db_level, db->db_blkid) %
+           multilist_get_num_sublists(ml));
+}
+
+static inline boolean_t
+dbuf_cache_above_hiwater(void)
+{
+       uint64_t dbuf_cache_hiwater_bytes =
+           (dbuf_cache_max_bytes * dbuf_cache_hiwater_pct) / 100;
+
+       return (refcount_count(&dbuf_cache_size) >
+           dbuf_cache_max_bytes + dbuf_cache_hiwater_bytes);
+}
+
+static inline boolean_t
+dbuf_cache_above_lowater(void)
+{
+       uint64_t dbuf_cache_lowater_bytes =
+           (dbuf_cache_max_bytes * dbuf_cache_lowater_pct) / 100;
+
+       return (refcount_count(&dbuf_cache_size) >
+           dbuf_cache_max_bytes - dbuf_cache_lowater_bytes);
+}
+
+/*
+ * Evict the oldest eligible dbuf from the dbuf cache.
+ */
+static void
+dbuf_evict_one(void)
+{
+       int idx = multilist_get_random_index(&dbuf_cache);
+       multilist_sublist_t *mls = multilist_sublist_lock(&dbuf_cache, idx);
+       dmu_buf_impl_t *db;
+       ASSERT(!MUTEX_HELD(&dbuf_evict_lock));
+
+       /*
+        * Set the thread's tsd to indicate that it's processing evictions.
+        * Once a thread stops evicting from the dbuf cache it will
+        * reset its tsd to NULL.
+        */
+       ASSERT3P(tsd_get(zfs_dbuf_evict_key), ==, NULL);
+       (void) tsd_set(zfs_dbuf_evict_key, (void *)B_TRUE);
+
+       db = multilist_sublist_tail(mls);
+       while (db != NULL && mutex_tryenter(&db->db_mtx) == 0) {
+               db = multilist_sublist_prev(mls, db);
+       }
+
+       DTRACE_PROBE2(dbuf__evict__one, dmu_buf_impl_t *, db,
+           multilist_sublist_t *, mls);
+
+       if (db != NULL) {
+               multilist_sublist_remove(mls, db);
+               multilist_sublist_unlock(mls);
+               (void) refcount_remove_many(&dbuf_cache_size,
+                   db->db.db_size, db);
+               dbuf_destroy(db);
+       } else {
+               multilist_sublist_unlock(mls);
+       }
+       (void) tsd_set(zfs_dbuf_evict_key, NULL);
+}
+
+/*
+ * The dbuf evict thread is responsible for aging out dbufs from the
+ * cache. Once the cache has reached it's maximum size, dbufs are removed
+ * and destroyed. The eviction thread will continue running until the size
+ * of the dbuf cache is at or below the maximum size. Once the dbuf is aged
+ * out of the cache it is destroyed and becomes eligible for arc eviction.
+ */
+static void
+dbuf_evict_thread(void)
+{
+       callb_cpr_t cpr;
+
+       CALLB_CPR_INIT(&cpr, &dbuf_evict_lock, callb_generic_cpr, FTAG);
 
-       dbuf_clear(db);
-       dbuf_destroy(db);
+       mutex_enter(&dbuf_evict_lock);
+       while (!dbuf_evict_thread_exit) {
+               while (!dbuf_cache_above_lowater() && !dbuf_evict_thread_exit) {
+                       CALLB_CPR_SAFE_BEGIN(&cpr);
+                       (void) cv_timedwait_sig_hires(&dbuf_evict_cv,
+                           &dbuf_evict_lock, SEC2NSEC(1), MSEC2NSEC(1), 0);
+                       CALLB_CPR_SAFE_END(&cpr, &dbuf_evict_lock);
+               }
+               mutex_exit(&dbuf_evict_lock);
+
+               /*
+                * Keep evicting as long as we're above the low water mark
+                * for the cache. We do this without holding the locks to
+                * minimize lock contention.
+                */
+               while (dbuf_cache_above_lowater() && !dbuf_evict_thread_exit) {
+                       dbuf_evict_one();
+               }
+
+               mutex_enter(&dbuf_evict_lock);
+       }
+
+       dbuf_evict_thread_exit = B_FALSE;
+       cv_broadcast(&dbuf_evict_cv);
+       CALLB_CPR_EXIT(&cpr);   /* drops dbuf_evict_lock */
+       thread_exit();
 }
 
+/*
+ * Wake up the dbuf eviction thread if the dbuf cache is at its max size.
+ * If the dbuf cache is at its high water mark, then evict a dbuf from the
+ * dbuf cache using the callers context.
+ */
+static void
+dbuf_evict_notify(void)
+{
+
+       /*
+        * We use thread specific data to track when a thread has
+        * started processing evictions. This allows us to avoid deeply
+        * nested stacks that would have a call flow similar to this:
+        *
+        * dbuf_rele()-->dbuf_rele_and_unlock()-->dbuf_evict_notify()
+        *      ^                                               |
+        *      |                                               |
+        *      +-----dbuf_destroy()<--dbuf_evict_one()<--------+
+        *
+        * The dbuf_eviction_thread will always have its tsd set until
+        * that thread exits. All other threads will only set their tsd
+        * if they are participating in the eviction process. This only
+        * happens if the eviction thread is unable to process evictions
+        * fast enough. To keep the dbuf cache size in check, other threads
+        * can evict from the dbuf cache directly. Those threads will set
+        * their tsd values so that we ensure that they only evict one dbuf
+        * from the dbuf cache.
+        */
+       if (tsd_get(zfs_dbuf_evict_key) != NULL)
+               return;
+
+       if (refcount_count(&dbuf_cache_size) > dbuf_cache_max_bytes) {
+               boolean_t evict_now = B_FALSE;
+
+               mutex_enter(&dbuf_evict_lock);
+               if (refcount_count(&dbuf_cache_size) > dbuf_cache_max_bytes) {
+                       evict_now = dbuf_cache_above_hiwater();
+                       cv_signal(&dbuf_evict_cv);
+               }
+               mutex_exit(&dbuf_evict_lock);
+
+               if (evict_now) {
+                       dbuf_evict_one();
+               }
+       }
+}
+
+
+
 void
 dbuf_init(void)
 {
@@ -401,7 +639,7 @@ retry:
                goto retry;
        }
 
-       dbuf_cache = kmem_cache_create("dmu_buf_impl_t",
+       dbuf_kmem_cache = kmem_cache_create("dmu_buf_impl_t",
            sizeof (dmu_buf_impl_t),
            0, dbuf_cons, dbuf_dest, NULL, NULL, NULL, 0);
 
@@ -410,11 +648,31 @@ retry:
 
        dbuf_stats_init(h);
 
+       /*
+        * Setup the parameters for the dbuf cache. We cap the size of the
+        * dbuf cache to 1/32nd (default) of the size of the ARC.
+        */
+       dbuf_cache_max_bytes = MIN(dbuf_cache_max_bytes,
+           arc_max_bytes() >> dbuf_cache_max_shift);
+
        /*
         * All entries are queued via taskq_dispatch_ent(), so min/maxalloc
         * configuration is not required.
         */
        dbu_evict_taskq = taskq_create("dbu_evict", 1, defclsyspri, 0, 0, 0);
+
+       multilist_create(&dbuf_cache, sizeof (dmu_buf_impl_t),
+           offsetof(dmu_buf_impl_t, db_cache_link),
+           zfs_arc_num_sublists_per_state,
+           dbuf_cache_multilist_index_func);
+       refcount_create(&dbuf_cache_size);
+
+       tsd_create(&zfs_dbuf_evict_key, NULL);
+       dbuf_evict_thread_exit = B_FALSE;
+       mutex_init(&dbuf_evict_lock, NULL, MUTEX_DEFAULT, NULL);
+       cv_init(&dbuf_evict_cv, NULL, CV_DEFAULT, NULL);
+       dbuf_cache_evict_thread = thread_create(NULL, 0, dbuf_evict_thread,
+           NULL, 0, &p0, TS_RUN, minclsyspri);
 }
 
 void
@@ -436,8 +694,23 @@ dbuf_fini(void)
 #else
        kmem_free(h->hash_table, (h->hash_table_mask + 1) * sizeof (void *));
 #endif
-       kmem_cache_destroy(dbuf_cache);
+       kmem_cache_destroy(dbuf_kmem_cache);
        taskq_destroy(dbu_evict_taskq);
+
+       mutex_enter(&dbuf_evict_lock);
+       dbuf_evict_thread_exit = B_TRUE;
+       while (dbuf_evict_thread_exit) {
+               cv_signal(&dbuf_evict_cv);
+               cv_wait(&dbuf_evict_cv, &dbuf_evict_lock);
+       }
+       mutex_exit(&dbuf_evict_lock);
+       tsd_destroy(&zfs_dbuf_evict_key);
+
+       mutex_destroy(&dbuf_evict_lock);
+       cv_destroy(&dbuf_evict_cv);
+
+       refcount_destroy(&dbuf_cache_size);
+       multilist_destroy(&dbuf_cache);
 }
 
 /*
@@ -476,7 +749,6 @@ dbuf_verify(dmu_buf_impl_t *db)
                ASSERT3U(db->db.db_offset, ==, DMU_BONUS_BLKID);
        } else if (db->db_blkid == DMU_SPILL_BLKID) {
                ASSERT(dn != NULL);
-               ASSERT3U(db->db.db_size, >=, dn->dn_bonuslen);
                ASSERT0(db->db.db_offset);
        } else {
                ASSERT3U(db->db.db_offset, ==, db->db_blkid * db->db.db_size);
@@ -541,13 +813,50 @@ dbuf_verify(dmu_buf_impl_t *db)
                 * If the blkptr isn't set but they have nonzero data,
                 * it had better be dirty, otherwise we'll lose that
                 * data when we evict this buffer.
+                *
+                * There is an exception to this rule for indirect blocks; in
+                * this case, if the indirect block is a hole, we fill in a few
+                * fields on each of the child blocks (importantly, birth time)
+                * to prevent hole birth times from being lost when you
+                * partially fill in a hole.
                 */
                if (db->db_dirtycnt == 0) {
-                       ASSERTV(uint64_t *buf = db->db.db_data);
-                       int i;
+                       if (db->db_level == 0) {
+                               uint64_t *buf = db->db.db_data;
+                               int i;
 
-                       for (i = 0; i < db->db.db_size >> 3; i++) {
-                               ASSERT(buf[i] == 0);
+                               for (i = 0; i < db->db.db_size >> 3; i++) {
+                                       ASSERT(buf[i] == 0);
+                               }
+                       } else {
+                               int i;
+                               blkptr_t *bps = db->db.db_data;
+                               ASSERT3U(1 << DB_DNODE(db)->dn_indblkshift, ==,
+                                   db->db.db_size);
+                               /*
+                                * We want to verify that all the blkptrs in the
+                                * indirect block are holes, but we may have
+                                * automatically set up a few fields for them.
+                                * We iterate through each blkptr and verify
+                                * they only have those fields set.
+                                */
+                               for (i = 0;
+                                   i < db->db.db_size / sizeof (blkptr_t);
+                                   i++) {
+                                       blkptr_t *bp = &bps[i];
+                                       ASSERT(ZIO_CHECKSUM_IS_ZERO(
+                                           &bp->blk_cksum));
+                                       ASSERT(
+                                           DVA_IS_EMPTY(&bp->blk_dva[0]) &&
+                                           DVA_IS_EMPTY(&bp->blk_dva[1]) &&
+                                           DVA_IS_EMPTY(&bp->blk_dva[2]));
+                                       ASSERT0(bp->blk_fill);
+                                       ASSERT0(bp->blk_pad[0]);
+                                       ASSERT0(bp->blk_pad[1]);
+                                       ASSERT(!BP_IS_EMBEDDED(bp));
+                                       ASSERT(BP_IS_HOLE(bp));
+                                       ASSERT0(bp->blk_phys_birth);
+                               }
                        }
                }
        }
@@ -560,7 +869,7 @@ dbuf_clear_data(dmu_buf_impl_t *db)
 {
        ASSERT(MUTEX_HELD(&db->db_mtx));
        dbuf_evict_user(db);
-       db->db_buf = NULL;
+       ASSERT3P(db->db_buf, ==, NULL);
        db->db.db_data = NULL;
        if (db->db_state != DB_NOFILL)
                db->db_state = DB_UNCACHED;
@@ -575,8 +884,6 @@ dbuf_set_data(dmu_buf_impl_t *db, arc_buf_t *buf)
        db->db_buf = buf;
        ASSERT(buf->b_data != NULL);
        db->db.db_data = buf->b_data;
-       if (!arc_released(buf))
-               arc_set_callback(buf, dbuf_do_evict, db);
 }
 
 /*
@@ -587,28 +894,65 @@ dbuf_loan_arcbuf(dmu_buf_impl_t *db)
 {
        arc_buf_t *abuf;
 
+       ASSERT(db->db_blkid != DMU_BONUS_BLKID);
        mutex_enter(&db->db_mtx);
        if (arc_released(db->db_buf) || refcount_count(&db->db_holds) > 1) {
                int blksz = db->db.db_size;
                spa_t *spa = db->db_objset->os_spa;
 
                mutex_exit(&db->db_mtx);
-               abuf = arc_loan_buf(spa, blksz);
+               abuf = arc_loan_buf(spa, B_FALSE, blksz);
                bcopy(db->db.db_data, abuf->b_data, blksz);
        } else {
                abuf = db->db_buf;
                arc_loan_inuse_buf(abuf, db);
+               db->db_buf = NULL;
                dbuf_clear_data(db);
                mutex_exit(&db->db_mtx);
        }
        return (abuf);
 }
 
+/*
+ * Calculate which level n block references the data at the level 0 offset
+ * provided.
+ */
 uint64_t
-dbuf_whichblock(dnode_t *dn, uint64_t offset)
+dbuf_whichblock(const dnode_t *dn, const int64_t level, const uint64_t offset)
 {
-       if (dn->dn_datablkshift) {
-               return (offset >> dn->dn_datablkshift);
+       if (dn->dn_datablkshift != 0 && dn->dn_indblkshift != 0) {
+               /*
+                * The level n blkid is equal to the level 0 blkid divided by
+                * the number of level 0s in a level n block.
+                *
+                * The level 0 blkid is offset >> datablkshift =
+                * offset / 2^datablkshift.
+                *
+                * The number of level 0s in a level n is the number of block
+                * pointers in an indirect block, raised to the power of level.
+                * This is 2^(indblkshift - SPA_BLKPTRSHIFT)^level =
+                * 2^(level*(indblkshift - SPA_BLKPTRSHIFT)).
+                *
+                * Thus, the level n blkid is: offset /
+                * ((2^datablkshift)*(2^(level*(indblkshift - SPA_BLKPTRSHIFT)))
+                * = offset / 2^(datablkshift + level *
+                *   (indblkshift - SPA_BLKPTRSHIFT))
+                * = offset >> (datablkshift + level *
+                *   (indblkshift - SPA_BLKPTRSHIFT))
+                */
+
+               const unsigned exp = dn->dn_datablkshift +
+                   level * (dn->dn_indblkshift - SPA_BLKPTRSHIFT);
+
+               if (exp >= 8 * sizeof (offset)) {
+                       /* This only happens on the highest indirection level */
+                       ASSERT3U(level, ==, dn->dn_nlevels - 1);
+                       return (0);
+               }
+
+               ASSERT3U(exp, <, 8 * sizeof (offset));
+
+               return (offset >> exp);
        } else {
                ASSERT3U(offset, <, dn->dn_datablksz);
                return (0);
@@ -642,7 +986,7 @@ dbuf_read_done(zio_t *zio, arc_buf_t *buf, void *vdb)
        } else {
                ASSERT(db->db_blkid != DMU_BONUS_BLKID);
                ASSERT3P(db->db_buf, ==, NULL);
-               VERIFY(arc_buf_remove_ref(buf, db));
+               arc_buf_destroy(buf, db);
                db->db_state = DB_UNCACHED;
        }
        cv_broadcast(&db->db_changed);
@@ -650,7 +994,7 @@ dbuf_read_done(zio_t *zio, arc_buf_t *buf, void *vdb)
 }
 
 static int
-dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
+dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
 {
        dnode_t *dn;
        zbookmark_phys_t zb;
@@ -667,13 +1011,18 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
        ASSERT(db->db_buf == NULL);
 
        if (db->db_blkid == DMU_BONUS_BLKID) {
+               /*
+                * The bonus length stored in the dnode may be less than
+                * the maximum available space in the bonus buffer.
+                */
                int bonuslen = MIN(dn->dn_bonuslen, dn->dn_phys->dn_bonuslen);
+               int max_bonuslen = DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots);
 
                ASSERT3U(bonuslen, <=, db->db.db_size);
-               db->db.db_data = zio_buf_alloc(DN_MAX_BONUSLEN);
-               arc_space_consume(DN_MAX_BONUSLEN, ARC_SPACE_OTHER);
-               if (bonuslen < DN_MAX_BONUSLEN)
-                       bzero(db->db.db_data, DN_MAX_BONUSLEN);
+               db->db.db_data = zio_buf_alloc(max_bonuslen);
+               arc_space_consume(max_bonuslen, ARC_SPACE_BONUS);
+               if (bonuslen < max_bonuslen)
+                       bzero(db->db.db_data, max_bonuslen);
                if (bonuslen)
                        bcopy(DN_BONUS(dn->dn_phys), db->db.db_data, bonuslen);
                DB_DNODE_EXIT(db);
@@ -692,12 +1041,33 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
            BP_IS_HOLE(db->db_blkptr)))) {
                arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
 
-               DB_DNODE_EXIT(db);
-               dbuf_set_data(db, arc_buf_alloc(db->db_objset->os_spa,
-                   db->db.db_size, db, type));
+               dbuf_set_data(db, arc_alloc_buf(db->db_objset->os_spa, db, type,
+                   db->db.db_size));
                bzero(db->db.db_data, db->db.db_size);
+
+               if (db->db_blkptr != NULL && db->db_level > 0 &&
+                   BP_IS_HOLE(db->db_blkptr) &&
+                   db->db_blkptr->blk_birth != 0) {
+                       blkptr_t *bps = db->db.db_data;
+                       int i;
+                       for (i = 0; i < ((1 <<
+                           DB_DNODE(db)->dn_indblkshift) / sizeof (blkptr_t));
+                           i++) {
+                               blkptr_t *bp = &bps[i];
+                               ASSERT3U(BP_GET_LSIZE(db->db_blkptr), ==,
+                                   1 << dn->dn_indblkshift);
+                               BP_SET_LSIZE(bp,
+                                   BP_GET_LEVEL(db->db_blkptr) == 1 ?
+                                   dn->dn_datablksz :
+                                   BP_GET_LSIZE(db->db_blkptr));
+                               BP_SET_TYPE(bp, BP_GET_TYPE(db->db_blkptr));
+                               BP_SET_LEVEL(bp,
+                                   BP_GET_LEVEL(db->db_blkptr) - 1);
+                               BP_SET_BIRTH(bp, db->db_blkptr->blk_birth, 0);
+                       }
+               }
+               DB_DNODE_EXIT(db);
                db->db_state = DB_CACHED;
-               *flags |= DB_RF_CACHED;
                mutex_exit(&db->db_mtx);
                return (0);
        }
@@ -709,8 +1079,6 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
 
        if (DBUF_IS_L2CACHEABLE(db))
                aflags |= ARC_FLAG_L2CACHE;
-       if (DBUF_IS_L2COMPRESSIBLE(db))
-               aflags |= ARC_FLAG_L2COMPRESS;
 
        SET_BOOKMARK(&zb, db->db_objset->os_dsl_dataset ?
            db->db_objset->os_dsl_dataset->ds_object : DMU_META_OBJSET,
@@ -720,12 +1088,74 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags)
 
        err = arc_read(zio, db->db_objset->os_spa, db->db_blkptr,
            dbuf_read_done, db, ZIO_PRIORITY_SYNC_READ,
-           (*flags & DB_RF_CANFAIL) ? ZIO_FLAG_CANFAIL : ZIO_FLAG_MUSTSUCCEED,
+           (flags & DB_RF_CANFAIL) ? ZIO_FLAG_CANFAIL : ZIO_FLAG_MUSTSUCCEED,
            &aflags, &zb);
-       if (aflags & ARC_FLAG_CACHED)
-               *flags |= DB_RF_CACHED;
 
-       return (SET_ERROR(err));
+       return (err);
+}
+
+/*
+ * This is our just-in-time copy function.  It makes a copy of buffers that
+ * have been modified in a previous transaction group before we access them in
+ * the current active group.
+ *
+ * This function is used in three places: when we are dirtying a buffer for the
+ * first time in a txg, when we are freeing a range in a dnode that includes
+ * this buffer, and when we are accessing a buffer which was received compressed
+ * and later referenced in a WRITE_BYREF record.
+ *
+ * Note that when we are called from dbuf_free_range() we do not put a hold on
+ * the buffer, we just traverse the active dbuf list for the dnode.
+ */
+static void
+dbuf_fix_old_data(dmu_buf_impl_t *db, uint64_t txg)
+{
+       dbuf_dirty_record_t *dr = db->db_last_dirty;
+
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+       ASSERT(db->db.db_data != NULL);
+       ASSERT(db->db_level == 0);
+       ASSERT(db->db.db_object != DMU_META_DNODE_OBJECT);
+
+       if (dr == NULL ||
+           (dr->dt.dl.dr_data !=
+           ((db->db_blkid  == DMU_BONUS_BLKID) ? db->db.db_data : db->db_buf)))
+               return;
+
+       /*
+        * If the last dirty record for this dbuf has not yet synced
+        * and its referencing the dbuf data, either:
+        *      reset the reference to point to a new copy,
+        * or (if there a no active holders)
+        *      just null out the current db_data pointer.
+        */
+       ASSERT(dr->dr_txg >= txg - 2);
+       if (db->db_blkid == DMU_BONUS_BLKID) {
+               /* Note that the data bufs here are zio_bufs */
+               dnode_t *dn = DB_DNODE(db);
+               int bonuslen = DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots);
+               dr->dt.dl.dr_data = zio_buf_alloc(bonuslen);
+               arc_space_consume(bonuslen, ARC_SPACE_BONUS);
+               bcopy(db->db.db_data, dr->dt.dl.dr_data, bonuslen);
+       } else if (refcount_count(&db->db_holds) > db->db_dirtycnt) {
+               int size = arc_buf_size(db->db_buf);
+               arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
+               spa_t *spa = db->db_objset->os_spa;
+               enum zio_compress compress_type =
+                   arc_get_compression(db->db_buf);
+
+               if (compress_type == ZIO_COMPRESS_OFF) {
+                       dr->dt.dl.dr_data = arc_alloc_buf(spa, db, type, size);
+               } else {
+                       ASSERT3U(type, ==, ARC_BUFC_DATA);
+                       dr->dt.dl.dr_data = arc_alloc_compressed_buf(spa, db,
+                           size, arc_buf_lsize(db->db_buf), compress_type);
+               }
+               bcopy(db->db.db_data, dr->dt.dl.dr_data->b_data, size);
+       } else {
+               db->db_buf = NULL;
+               dbuf_clear_data(db);
+       }
 }
 
 int
@@ -756,10 +1186,21 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
 
        mutex_enter(&db->db_mtx);
        if (db->db_state == DB_CACHED) {
+               /*
+                * If the arc buf is compressed, we need to decompress it to
+                * read the data. This could happen during the "zfs receive" of
+                * a stream which is compressed and deduplicated.
+                */
+               if (db->db_buf != NULL &&
+                   arc_get_compression(db->db_buf) != ZIO_COMPRESS_OFF) {
+                       dbuf_fix_old_data(db,
+                           spa_syncing_txg(dmu_objset_spa(db->db_objset)));
+                       err = arc_decompress(db->db_buf);
+                       dbuf_set_data(db, db->db_buf);
+               }
                mutex_exit(&db->db_mtx);
                if (prefetch)
-                       dmu_zfetch(&dn->dn_zfetch, db->db.db_offset,
-                           db->db.db_size, TRUE);
+                       dmu_zfetch(&dn->dn_zfetch, db->db_blkid, 1, B_TRUE);
                if ((flags & DB_RF_HAVESTRUCT) == 0)
                        rw_exit(&dn->dn_struct_rwlock);
                DB_DNODE_EXIT(db);
@@ -769,13 +1210,12 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
                if (zio == NULL)
                        zio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL);
 
-               err = dbuf_read_impl(db, zio, &flags);
+               err = dbuf_read_impl(db, zio, flags);
 
                /* dbuf_read_impl has dropped db_mtx for us */
 
                if (!err && prefetch)
-                       dmu_zfetch(&dn->dn_zfetch, db->db.db_offset,
-                           db->db.db_size, flags & DB_RF_CACHED);
+                       dmu_zfetch(&dn->dn_zfetch, db->db_blkid, 1, B_TRUE);
 
                if ((flags & DB_RF_HAVESTRUCT) == 0)
                        rw_exit(&dn->dn_struct_rwlock);
@@ -794,8 +1234,7 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
                 */
                mutex_exit(&db->db_mtx);
                if (prefetch)
-                       dmu_zfetch(&dn->dn_zfetch, db->db.db_offset,
-                           db->db.db_size, TRUE);
+                       dmu_zfetch(&dn->dn_zfetch, db->db_blkid, 1, B_TRUE);
                if ((flags & DB_RF_HAVESTRUCT) == 0)
                        rw_exit(&dn->dn_struct_rwlock);
                DB_DNODE_EXIT(db);
@@ -835,7 +1274,7 @@ dbuf_noread(dmu_buf_impl_t *db)
 
                ASSERT(db->db_buf == NULL);
                ASSERT(db->db.db_data == NULL);
-               dbuf_set_data(db, arc_buf_alloc(spa, db->db.db_size, db, type));
+               dbuf_set_data(db, arc_alloc_buf(spa, db, type, db->db.db_size));
                db->db_state = DB_FILL;
        } else if (db->db_state == DB_NOFILL) {
                dbuf_clear_data(db);
@@ -845,59 +1284,6 @@ dbuf_noread(dmu_buf_impl_t *db)
        mutex_exit(&db->db_mtx);
 }
 
-/*
- * This is our just-in-time copy function.  It makes a copy of
- * buffers, that have been modified in a previous transaction
- * group, before we modify them in the current active group.
- *
- * This function is used in two places: when we are dirtying a
- * buffer for the first time in a txg, and when we are freeing
- * a range in a dnode that includes this buffer.
- *
- * Note that when we are called from dbuf_free_range() we do
- * not put a hold on the buffer, we just traverse the active
- * dbuf list for the dnode.
- */
-static void
-dbuf_fix_old_data(dmu_buf_impl_t *db, uint64_t txg)
-{
-       dbuf_dirty_record_t *dr = db->db_last_dirty;
-
-       ASSERT(MUTEX_HELD(&db->db_mtx));
-       ASSERT(db->db.db_data != NULL);
-       ASSERT(db->db_level == 0);
-       ASSERT(db->db.db_object != DMU_META_DNODE_OBJECT);
-
-       if (dr == NULL ||
-           (dr->dt.dl.dr_data !=
-           ((db->db_blkid  == DMU_BONUS_BLKID) ? db->db.db_data : db->db_buf)))
-               return;
-
-       /*
-        * If the last dirty record for this dbuf has not yet synced
-        * and its referencing the dbuf data, either:
-        *      reset the reference to point to a new copy,
-        * or (if there a no active holders)
-        *      just null out the current db_data pointer.
-        */
-       ASSERT(dr->dr_txg >= txg - 2);
-       if (db->db_blkid == DMU_BONUS_BLKID) {
-               /* Note that the data bufs here are zio_bufs */
-               dr->dt.dl.dr_data = zio_buf_alloc(DN_MAX_BONUSLEN);
-               arc_space_consume(DN_MAX_BONUSLEN, ARC_SPACE_OTHER);
-               bcopy(db->db.db_data, dr->dt.dl.dr_data, DN_MAX_BONUSLEN);
-       } else if (refcount_count(&db->db_holds) > db->db_dirtycnt) {
-               int size = db->db.db_size;
-               arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
-               spa_t *spa = db->db_objset->os_spa;
-
-               dr->dt.dl.dr_data = arc_buf_alloc(spa, size, db, type);
-               bcopy(db->db.db_data, dr->dt.dl.dr_data->b_data, size);
-       } else {
-               dbuf_clear_data(db);
-       }
-}
-
 void
 dbuf_unoverride(dbuf_dirty_record_t *dr)
 {
@@ -1017,7 +1403,7 @@ dbuf_free_range(dnode_t *dn, uint64_t start_blkid, uint64_t end_blkid,
                }
                if (refcount_count(&db->db_holds) == 0) {
                        ASSERT(db->db_buf);
-                       dbuf_clear(db);
+                       dbuf_destroy(db);
                        continue;
                }
                /* The dbuf is referenced */
@@ -1125,7 +1511,7 @@ dbuf_new_size(dmu_buf_impl_t *db, int size, dmu_tx_t *tx)
        dmu_buf_will_dirty(&db->db, tx);
 
        /* create the data buffer for the new block */
-       buf = arc_buf_alloc(dn->dn_objset->os_spa, size, db, type);
+       buf = arc_alloc_buf(dn->dn_objset->os_spa, db, type, size);
 
        /* copy old block data to the new block */
        obuf = db->db_buf;
@@ -1136,7 +1522,7 @@ dbuf_new_size(dmu_buf_impl_t *db, int size, dmu_tx_t *tx)
 
        mutex_enter(&db->db_mtx);
        dbuf_set_data(db, buf);
-       VERIFY(arc_buf_remove_ref(obuf, db));
+       arc_buf_destroy(obuf, db);
        db->db.db_size = size;
 
        if (db->db_level == 0) {
@@ -1162,6 +1548,32 @@ dbuf_release_bp(dmu_buf_impl_t *db)
        (void) arc_release(db->db_buf, db);
 }
 
+/*
+ * We already have a dirty record for this TXG, and we are being
+ * dirtied again.
+ */
+static void
+dbuf_redirty(dbuf_dirty_record_t *dr)
+{
+       dmu_buf_impl_t *db = dr->dr_dbuf;
+
+       ASSERT(MUTEX_HELD(&db->db_mtx));
+
+       if (db->db_level == 0 && db->db_blkid != DMU_BONUS_BLKID) {
+               /*
+                * If this buffer has already been written out,
+                * we now need to reset its state.
+                */
+               dbuf_unoverride(dr);
+               if (db->db.db_object != DMU_META_DNODE_OBJECT &&
+                   db->db_state != DB_NOFILL) {
+                       /* Already released on initial dirty, so just thaw. */
+                       ASSERT(arc_released(db->db_buf));
+                       arc_buf_thaw(db->db_buf);
+               }
+       }
+}
+
 dbuf_dirty_record_t *
 dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
 {
@@ -1234,16 +1646,7 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
        if (dr && dr->dr_txg == tx->tx_txg) {
                DB_DNODE_EXIT(db);
 
-               if (db->db_level == 0 && db->db_blkid != DMU_BONUS_BLKID) {
-                       /*
-                        * If this buffer has already been written out,
-                        * we now need to reset its state.
-                        */
-                       dbuf_unoverride(dr);
-                       if (db->db.db_object != DMU_META_DNODE_OBJECT &&
-                           db->db_state != DB_NOFILL)
-                               arc_buf_thaw(db->db_buf);
-               }
+               dbuf_redirty(dr);
                mutex_exit(&db->db_mtx);
                return (dr);
        }
@@ -1320,7 +1723,7 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
                }
                dr->dt.dl.dr_data = data_old;
        } else {
-               mutex_init(&dr->dt.di.dr_mtx, NULL, MUTEX_DEFAULT, NULL);
+               mutex_init(&dr->dt.di.dr_mtx, NULL, MUTEX_NOLOCKDEP, NULL);
                list_create(&dr->dt.di.dr_children,
                    sizeof (dbuf_dirty_record_t),
                    offsetof(dbuf_dirty_record_t, dr_dirty_node));
@@ -1366,7 +1769,20 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
                dnode_setdirty(dn, tx);
                DB_DNODE_EXIT(db);
                return (dr);
-       } else if (do_free_accounting) {
+       }
+
+       /*
+        * The dn_struct_rwlock prevents db_blkptr from changing
+        * due to a write from syncing context completing
+        * while we are running, so we want to acquire it before
+        * looking at db_blkptr.
+        */
+       if (!RW_WRITE_HELD(&dn->dn_struct_rwlock)) {
+               rw_enter(&dn->dn_struct_rwlock, RW_READER);
+               drop_struct_lock = TRUE;
+       }
+
+       if (do_free_accounting) {
                blkptr_t *bp = db->db_blkptr;
                int64_t willfree = (bp && !BP_IS_HOLE(bp)) ?
                    bp_get_dsize(os->os_spa, bp) : db->db.db_size;
@@ -1382,11 +1798,6 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
                dnode_willuse_space(dn, -willfree, tx);
        }
 
-       if (!RW_WRITE_HELD(&dn->dn_struct_rwlock)) {
-               rw_enter(&dn->dn_struct_rwlock, RW_READER);
-               drop_struct_lock = TRUE;
-       }
-
        if (db->db_level == 0) {
                dnode_new_blkid(dn, db->db_blkid, tx, drop_struct_lock);
                ASSERT(dn->dn_maxblkid >= db->db_blkid);
@@ -1518,7 +1929,7 @@ dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
                ASSERT(db->db_buf != NULL);
                ASSERT(dr->dt.dl.dr_data != NULL);
                if (dr->dt.dl.dr_data != db->db_buf)
-                       VERIFY(arc_buf_remove_ref(dr->dt.dl.dr_data, db));
+                       arc_buf_destroy(dr->dt.dl.dr_data, db);
        }
 
        kmem_free(dr, sizeof (dbuf_dirty_record_t));
@@ -1527,12 +1938,8 @@ dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
        db->db_dirtycnt -= 1;
 
        if (refcount_remove(&db->db_holds, (void *)(uintptr_t)txg) == 0) {
-               arc_buf_t *buf = db->db_buf;
-
-               ASSERT(db->db_state == DB_NOFILL || arc_released(buf));
-               dbuf_clear_data(db);
-               VERIFY(arc_buf_remove_ref(buf, db));
-               dbuf_evict(db);
+               ASSERT(db->db_state == DB_NOFILL || arc_released(db->db_buf));
+               dbuf_destroy(db);
                return (B_TRUE);
        }
 
@@ -1544,10 +1951,35 @@ dmu_buf_will_dirty(dmu_buf_t *db_fake, dmu_tx_t *tx)
 {
        dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
        int rf = DB_RF_MUST_SUCCEED | DB_RF_NOPREFETCH;
+       dbuf_dirty_record_t *dr;
 
        ASSERT(tx->tx_txg != 0);
        ASSERT(!refcount_is_zero(&db->db_holds));
 
+       /*
+        * Quick check for dirtyness.  For already dirty blocks, this
+        * reduces runtime of this function by >90%, and overall performance
+        * by 50% for some workloads (e.g. file deletion with indirect blocks
+        * cached).
+        */
+       mutex_enter(&db->db_mtx);
+
+       for (dr = db->db_last_dirty;
+           dr != NULL && dr->dr_txg >= tx->tx_txg; dr = dr->dr_next) {
+               /*
+                * It's possible that it is already dirty but not cached,
+                * because there are some calls to dbuf_dirty() that don't
+                * go through dmu_buf_will_dirty().
+                */
+               if (dr->dr_txg == tx->tx_txg && db->db_state == DB_CACHED) {
+                       /* This dbuf is already dirty and cached. */
+                       dbuf_redirty(dr);
+                       mutex_exit(&db->db_mtx);
+                       return;
+               }
+       }
+       mutex_exit(&db->db_mtx);
+
        DB_DNODE_ENTER(db);
        if (RW_WRITE_HELD(&DB_DNODE(db)->dn_struct_rwlock))
                rf |= DB_RF_HAVESTRUCT;
@@ -1615,6 +2047,11 @@ dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data,
        struct dirty_leaf *dl;
        dmu_object_type_t type;
 
+       if (etype == BP_EMBEDDED_TYPE_DATA) {
+               ASSERT(spa_feature_is_active(dmu_objset_spa(db->db_objset),
+                   SPA_FEATURE_EMBEDDED_DATA));
+       }
+
        DB_DNODE_ENTER(db);
        type = DB_DNODE(db)->dn_type;
        DB_DNODE_EXIT(db);
@@ -1647,9 +2084,9 @@ dbuf_assign_arcbuf(dmu_buf_impl_t *db, arc_buf_t *buf, dmu_tx_t *tx)
        ASSERT(!refcount_is_zero(&db->db_holds));
        ASSERT(db->db_blkid != DMU_BONUS_BLKID);
        ASSERT(db->db_level == 0);
-       ASSERT(DBUF_GET_BUFC_TYPE(db) == ARC_BUFC_DATA);
+       ASSERT3U(dbuf_is_metadata(db), ==, arc_is_metadata(buf));
        ASSERT(buf != NULL);
-       ASSERT(arc_buf_size(buf) == db->db.db_size);
+       ASSERT(arc_buf_lsize(buf) == db->db.db_size);
        ASSERT(tx->tx_txg != 0);
 
        arc_return_buf(buf, db);
@@ -1667,7 +2104,7 @@ dbuf_assign_arcbuf(dmu_buf_impl_t *db, arc_buf_t *buf, dmu_tx_t *tx)
                mutex_exit(&db->db_mtx);
                (void) dbuf_dirty(db, tx);
                bcopy(buf->b_data, db->db.db_data, db->db.db_size);
-               VERIFY(arc_buf_remove_ref(buf, db));
+               arc_buf_destroy(buf, db);
                xuio_stat_wbuf_copied();
                return;
        }
@@ -1685,10 +2122,10 @@ dbuf_assign_arcbuf(dmu_buf_impl_t *db, arc_buf_t *buf, dmu_tx_t *tx)
                                arc_release(db->db_buf, db);
                        }
                        dr->dt.dl.dr_data = buf;
-                       VERIFY(arc_buf_remove_ref(db->db_buf, db));
+                       arc_buf_destroy(db->db_buf, db);
                } else if (dr == NULL || dr->dt.dl.dr_data != db->db_buf) {
                        arc_release(db->db_buf, db);
-                       VERIFY(arc_buf_remove_ref(db->db_buf, db));
+                       arc_buf_destroy(db->db_buf, db);
                }
                db->db_buf = NULL;
        }
@@ -1700,59 +2137,64 @@ dbuf_assign_arcbuf(dmu_buf_impl_t *db, arc_buf_t *buf, dmu_tx_t *tx)
        dmu_buf_fill_done(&db->db, tx);
 }
 
-/*
- * "Clear" the contents of this dbuf.  This will mark the dbuf
- * EVICTING and clear *most* of its references.  Unfortunately,
- * when we are not holding the dn_dbufs_mtx, we can't clear the
- * entry in the dn_dbufs list.  We have to wait until dbuf_destroy()
- * in this case.  For callers from the DMU we will usually see:
- *     dbuf_clear()->arc_clear_callback()->dbuf_do_evict()->dbuf_destroy()
- * For the arc callback, we will usually see:
- *     dbuf_do_evict()->dbuf_clear();dbuf_destroy()
- * Sometimes, though, we will get a mix of these two:
- *     DMU: dbuf_clear()->arc_clear_callback()
- *     ARC: dbuf_do_evict()->dbuf_destroy()
- *
- * This routine will dissociate the dbuf from the arc, by calling
- * arc_clear_callback(), but will not evict the data from the ARC.
- */
 void
-dbuf_clear(dmu_buf_impl_t *db)
+dbuf_destroy(dmu_buf_impl_t *db)
 {
        dnode_t *dn;
        dmu_buf_impl_t *parent = db->db_parent;
        dmu_buf_impl_t *dndb;
-       boolean_t dbuf_gone = B_FALSE;
 
        ASSERT(MUTEX_HELD(&db->db_mtx));
        ASSERT(refcount_is_zero(&db->db_holds));
 
-       dbuf_evict_user(db);
+       if (db->db_buf != NULL) {
+               arc_buf_destroy(db->db_buf, db);
+               db->db_buf = NULL;
+       }
 
-       if (db->db_state == DB_CACHED) {
+       if (db->db_blkid == DMU_BONUS_BLKID) {
+               int slots = DB_DNODE(db)->dn_num_slots;
+               int bonuslen = DN_SLOTS_TO_BONUSLEN(slots);
                ASSERT(db->db.db_data != NULL);
-               if (db->db_blkid == DMU_BONUS_BLKID) {
-                       zio_buf_free(db->db.db_data, DN_MAX_BONUSLEN);
-                       arc_space_return(DN_MAX_BONUSLEN, ARC_SPACE_OTHER);
-               }
-               db->db.db_data = NULL;
+               zio_buf_free(db->db.db_data, bonuslen);
+               arc_space_return(bonuslen, ARC_SPACE_BONUS);
                db->db_state = DB_UNCACHED;
        }
 
+       dbuf_clear_data(db);
+
+       if (multilist_link_active(&db->db_cache_link)) {
+               multilist_remove(&dbuf_cache, db);
+               (void) refcount_remove_many(&dbuf_cache_size,
+                   db->db.db_size, db);
+       }
+
        ASSERT(db->db_state == DB_UNCACHED || db->db_state == DB_NOFILL);
        ASSERT(db->db_data_pending == NULL);
 
        db->db_state = DB_EVICTING;
        db->db_blkptr = NULL;
 
+       /*
+        * Now that db_state is DB_EVICTING, nobody else can find this via
+        * the hash table.  We can now drop db_mtx, which allows us to
+        * acquire the dn_dbufs_mtx.
+        */
+       mutex_exit(&db->db_mtx);
+
        DB_DNODE_ENTER(db);
        dn = DB_DNODE(db);
        dndb = dn->dn_dbuf;
-       if (db->db_blkid != DMU_BONUS_BLKID && MUTEX_HELD(&dn->dn_dbufs_mtx)) {
+       if (db->db_blkid != DMU_BONUS_BLKID) {
+               boolean_t needlock = !MUTEX_HELD(&dn->dn_dbufs_mtx);
+               if (needlock)
+                       mutex_enter(&dn->dn_dbufs_mtx);
                avl_remove(&dn->dn_dbufs, db);
                atomic_dec_32(&dn->dn_dbufs_count);
                membar_producer();
                DB_DNODE_EXIT(db);
+               if (needlock)
+                       mutex_exit(&dn->dn_dbufs_mtx);
                /*
                 * Decrementing the dbuf count means that the hold corresponding
                 * to the removed dbuf is no longer discounted in dnode_move(),
@@ -1763,15 +2205,25 @@ dbuf_clear(dmu_buf_impl_t *db)
                 */
                dnode_rele(dn, db);
                db->db_dnode_handle = NULL;
+
+               dbuf_hash_remove(db);
        } else {
                DB_DNODE_EXIT(db);
        }
 
-       if (db->db_buf)
-               dbuf_gone = arc_clear_callback(db->db_buf);
+       ASSERT(refcount_is_zero(&db->db_holds));
+
+       db->db_parent = NULL;
 
-       if (!dbuf_gone)
-               mutex_exit(&db->db_mtx);
+       ASSERT(db->db_buf == NULL);
+       ASSERT(db->db.db_data == NULL);
+       ASSERT(db->db_hash_next == NULL);
+       ASSERT(db->db_blkptr == NULL);
+       ASSERT(db->db_data_pending == NULL);
+       ASSERT(!multilist_link_active(&db->db_cache_link));
+
+       kmem_cache_free(dbuf_kmem_cache, db);
+       arc_space_return(sizeof (dmu_buf_impl_t), ARC_SPACE_DBUF);
 
        /*
         * If this dbuf is referenced from an indirect dbuf,
@@ -1781,6 +2233,12 @@ dbuf_clear(dmu_buf_impl_t *db)
                dbuf_rele(parent, db);
 }
 
+/*
+ * Note: While bpp will always be updated if the function returns success,
+ * parentp will not be updated if the dnode does not have dn_dbuf filled in;
+ * this happens when the dnode is the meta-dnode, or a userused or groupused
+ * object.
+ */
 __attribute__((always_inline))
 static inline int
 dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse,
@@ -1797,7 +2255,7 @@ dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse,
                mutex_enter(&dn->dn_mtx);
                if (dn->dn_have_spill &&
                    (dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR))
-                       *bpp = &dn->dn_phys->dn_spill;
+                       *bpp = DN_SPILL_BLKPTR(dn->dn_phys);
                else
                        *bpp = NULL;
                dbuf_add_ref(dn->dn_dbuf, NULL);
@@ -1806,29 +2264,47 @@ dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse,
                return (0);
        }
 
-       if (dn->dn_phys->dn_nlevels == 0)
-               nlevels = 1;
-       else
-               nlevels = dn->dn_phys->dn_nlevels;
-
+       nlevels =
+           (dn->dn_phys->dn_nlevels == 0) ? 1 : dn->dn_phys->dn_nlevels;
        epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
 
        ASSERT3U(level * epbs, <, 64);
        ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
+       /*
+        * This assertion shouldn't trip as long as the max indirect block size
+        * is less than 1M.  The reason for this is that up to that point,
+        * the number of levels required to address an entire object with blocks
+        * of size SPA_MINBLOCKSIZE satisfies nlevels * epbs + 1 <= 64.  In
+        * other words, if N * epbs + 1 > 64, then if (N-1) * epbs + 1 > 55
+        * (i.e. we can address the entire object), objects will all use at most
+        * N-1 levels and the assertion won't overflow.  However, once epbs is
+        * 13, 4 * 13 + 1 = 53, but 5 * 13 + 1 = 66.  Then, 4 levels will not be
+        * enough to address an entire object, so objects will have 5 levels,
+        * but then this assertion will overflow.
+        *
+        * All this is to say that if we ever increase DN_MAX_INDBLKSHIFT, we
+        * need to redo this logic to handle overflows.
+        */
+       ASSERT(level >= nlevels ||
+           ((nlevels - level - 1) * epbs) +
+           highbit64(dn->dn_phys->dn_nblkptr) <= 64);
        if (level >= nlevels ||
-           (blkid > (dn->dn_phys->dn_maxblkid >> (level * epbs)))) {
+           blkid >= ((uint64_t)dn->dn_phys->dn_nblkptr <<
+           ((nlevels - level - 1) * epbs)) ||
+           (fail_sparse &&
+           blkid > (dn->dn_phys->dn_maxblkid >> (level * epbs)))) {
                /* the buffer has no parent yet */
                return (SET_ERROR(ENOENT));
        } else if (level < nlevels-1) {
                /* this block is referenced from an indirect block */
                int err;
                if (dh == NULL) {
-                       err = dbuf_hold_impl(dn, level+1, blkid >> epbs,
-                                       fail_sparse, NULL, parentp);
+                       err = dbuf_hold_impl(dn, level+1,
+                           blkid >> epbs, fail_sparse, FALSE, NULL, parentp);
                } else {
                        __dbuf_hold_impl_init(dh + 1, dn, dh->dh_level + 1,
-                                       blkid >> epbs, fail_sparse, NULL,
-                                       parentp, dh->dh_depth + 1);
+                           blkid >> epbs, fail_sparse, FALSE, NULL,
+                           parentp, dh->dh_depth + 1);
                        err = __dbuf_hold_impl(dh + 1);
                }
                if (err)
@@ -1842,6 +2318,8 @@ dbuf_findbp(dnode_t *dn, int level, uint64_t blkid, int fail_sparse,
                }
                *bpp = ((blkptr_t *)(*parentp)->db.db_data) +
                    (blkid & ((1ULL << epbs) - 1));
+               if (blkid > (dn->dn_phys->dn_maxblkid >> (level * epbs)))
+                       ASSERT(BP_IS_HOLE(*bpp));
                return (0);
        } else {
                /* the block is referenced from the dnode */
@@ -1867,7 +2345,7 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
        ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
        ASSERT(dn->dn_type != DMU_OT_NONE);
 
-       db = kmem_cache_alloc(dbuf_cache, KM_SLEEP);
+       db = kmem_cache_alloc(dbuf_kmem_cache, KM_SLEEP);
 
        db->db_objset = os;
        db->db.db_object = dn->dn_object;
@@ -1886,13 +2364,13 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
 
        if (blkid == DMU_BONUS_BLKID) {
                ASSERT3P(parent, ==, dn->dn_dbuf);
-               db->db.db_size = DN_MAX_BONUSLEN -
+               db->db.db_size = DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots) -
                    (dn->dn_nblkptr-1) * sizeof (blkptr_t);
                ASSERT3U(db->db.db_size, >=, dn->dn_bonuslen);
                db->db.db_offset = DMU_BONUS_BLKID;
                db->db_state = DB_UNCACHED;
                /* the bonus dbuf is not placed in the hash table */
-               arc_space_consume(sizeof (dmu_buf_impl_t), ARC_SPACE_OTHER);
+               arc_space_consume(sizeof (dmu_buf_impl_t), ARC_SPACE_DBUF);
                return (db);
        } else if (blkid == DMU_SPILL_BLKID) {
                db->db.db_size = (blkptr != NULL) ?
@@ -1916,7 +2394,7 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
        db->db_state = DB_EVICTING;
        if ((odb = dbuf_hash_insert(db)) != NULL) {
                /* someone else inserted it first */
-               kmem_cache_free(dbuf_cache, db);
+               kmem_cache_free(dbuf_kmem_cache, db);
                mutex_exit(&dn->dn_dbufs_mtx);
                return (odb);
        }
@@ -1926,7 +2404,7 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
                dn->dn_unlisted_l0_blkid = db->db_blkid + 1;
        db->db_state = DB_UNCACHED;
        mutex_exit(&dn->dn_dbufs_mtx);
-       arc_space_consume(sizeof (dmu_buf_impl_t), ARC_SPACE_OTHER);
+       arc_space_consume(sizeof (dmu_buf_impl_t), ARC_SPACE_DBUF);
 
        if (parent && parent != dn->dn_dbuf)
                dbuf_add_ref(parent, db);
@@ -1941,112 +2419,240 @@ dbuf_create(dnode_t *dn, uint8_t level, uint64_t blkid,
        return (db);
 }
 
-static int
-dbuf_do_evict(void *private)
-{
-       dmu_buf_impl_t *db = private;
+typedef struct dbuf_prefetch_arg {
+       spa_t *dpa_spa; /* The spa to issue the prefetch in. */
+       zbookmark_phys_t dpa_zb; /* The target block to prefetch. */
+       int dpa_epbs; /* Entries (blkptr_t's) Per Block Shift. */
+       int dpa_curlevel; /* The current level that we're reading */
+       dnode_t *dpa_dnode; /* The dnode associated with the prefetch */
+       zio_priority_t dpa_prio; /* The priority I/Os should be issued at. */
+       zio_t *dpa_zio; /* The parent zio_t for all prefetches. */
+       arc_flags_t dpa_aflags; /* Flags to pass to the final prefetch. */
+} dbuf_prefetch_arg_t;
 
-       if (!MUTEX_HELD(&db->db_mtx))
-               mutex_enter(&db->db_mtx);
+/*
+ * Actually issue the prefetch read for the block given.
+ */
+static void
+dbuf_issue_final_prefetch(dbuf_prefetch_arg_t *dpa, blkptr_t *bp)
+{
+       arc_flags_t aflags;
+       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
+               return;
 
-       ASSERT(refcount_is_zero(&db->db_holds));
+       aflags = dpa->dpa_aflags | ARC_FLAG_NOWAIT | ARC_FLAG_PREFETCH;
 
-       if (db->db_state != DB_EVICTING) {
-               ASSERT(db->db_state == DB_CACHED);
-               DBUF_VERIFY(db);
-               db->db_buf = NULL;
-               dbuf_evict(db);
-       } else {
-               mutex_exit(&db->db_mtx);
-               dbuf_destroy(db);
-       }
-       return (0);
+       ASSERT3U(dpa->dpa_curlevel, ==, BP_GET_LEVEL(bp));
+       ASSERT3U(dpa->dpa_curlevel, ==, dpa->dpa_zb.zb_level);
+       ASSERT(dpa->dpa_zio != NULL);
+       (void) arc_read(dpa->dpa_zio, dpa->dpa_spa, bp, NULL, NULL,
+           dpa->dpa_prio, ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE,
+           &aflags, &dpa->dpa_zb);
 }
 
+/*
+ * Called when an indirect block above our prefetch target is read in.  This
+ * will either read in the next indirect block down the tree or issue the actual
+ * prefetch if the next block down is our target.
+ */
 static void
-dbuf_destroy(dmu_buf_impl_t *db)
+dbuf_prefetch_indirect_done(zio_t *zio, arc_buf_t *abuf, void *private)
 {
-       ASSERT(refcount_is_zero(&db->db_holds));
+       dbuf_prefetch_arg_t *dpa = private;
+       uint64_t nextblkid;
+       blkptr_t *bp;
 
-       if (db->db_blkid != DMU_BONUS_BLKID) {
-               /*
-                * If this dbuf is still on the dn_dbufs list,
-                * remove it from that list.
-                */
-               if (db->db_dnode_handle != NULL) {
-                       dnode_t *dn;
+       ASSERT3S(dpa->dpa_zb.zb_level, <, dpa->dpa_curlevel);
+       ASSERT3S(dpa->dpa_curlevel, >, 0);
 
-                       DB_DNODE_ENTER(db);
-                       dn = DB_DNODE(db);
-                       mutex_enter(&dn->dn_dbufs_mtx);
-                       avl_remove(&dn->dn_dbufs, db);
-                       atomic_dec_32(&dn->dn_dbufs_count);
-                       mutex_exit(&dn->dn_dbufs_mtx);
-                       DB_DNODE_EXIT(db);
-                       /*
-                        * Decrementing the dbuf count means that the hold
-                        * corresponding to the removed dbuf is no longer
-                        * discounted in dnode_move(), so the dnode cannot be
-                        * moved until after we release the hold.
-                        */
-                       dnode_rele(dn, db);
-                       db->db_dnode_handle = NULL;
+       /*
+        * The dpa_dnode is only valid if we are called with a NULL
+        * zio. This indicates that the arc_read() returned without
+        * first calling zio_read() to issue a physical read. Once
+        * a physical read is made the dpa_dnode must be invalidated
+        * as the locks guarding it may have been dropped. If the
+        * dpa_dnode is still valid, then we want to add it to the dbuf
+        * cache. To do so, we must hold the dbuf associated with the block
+        * we just prefetched, read its contents so that we associate it
+        * with an arc_buf_t, and then release it.
+        */
+       if (zio != NULL) {
+               ASSERT3S(BP_GET_LEVEL(zio->io_bp), ==, dpa->dpa_curlevel);
+               if (zio->io_flags & ZIO_FLAG_RAW) {
+                       ASSERT3U(BP_GET_PSIZE(zio->io_bp), ==, zio->io_size);
+               } else {
+                       ASSERT3U(BP_GET_LSIZE(zio->io_bp), ==, zio->io_size);
                }
-               dbuf_hash_remove(db);
-       }
-       db->db_parent = NULL;
-       db->db_buf = NULL;
+               ASSERT3P(zio->io_spa, ==, dpa->dpa_spa);
+
+               dpa->dpa_dnode = NULL;
+       } else if (dpa->dpa_dnode != NULL) {
+               uint64_t curblkid = dpa->dpa_zb.zb_blkid >>
+                   (dpa->dpa_epbs * (dpa->dpa_curlevel -
+                   dpa->dpa_zb.zb_level));
+               dmu_buf_impl_t *db = dbuf_hold_level(dpa->dpa_dnode,
+                   dpa->dpa_curlevel, curblkid, FTAG);
+               (void) dbuf_read(db, NULL,
+                   DB_RF_MUST_SUCCEED | DB_RF_NOPREFETCH | DB_RF_HAVESTRUCT);
+               dbuf_rele(db, FTAG);
+       }
+
+       dpa->dpa_curlevel--;
+
+       nextblkid = dpa->dpa_zb.zb_blkid >>
+           (dpa->dpa_epbs * (dpa->dpa_curlevel - dpa->dpa_zb.zb_level));
+       bp = ((blkptr_t *)abuf->b_data) +
+           P2PHASE(nextblkid, 1ULL << dpa->dpa_epbs);
+       if (BP_IS_HOLE(bp) || (zio != NULL && zio->io_error != 0)) {
+               kmem_free(dpa, sizeof (*dpa));
+       } else if (dpa->dpa_curlevel == dpa->dpa_zb.zb_level) {
+               ASSERT3U(nextblkid, ==, dpa->dpa_zb.zb_blkid);
+               dbuf_issue_final_prefetch(dpa, bp);
+               kmem_free(dpa, sizeof (*dpa));
+       } else {
+               arc_flags_t iter_aflags = ARC_FLAG_NOWAIT;
+               zbookmark_phys_t zb;
 
-       ASSERT(db->db.db_data == NULL);
-       ASSERT(db->db_hash_next == NULL);
-       ASSERT(db->db_blkptr == NULL);
-       ASSERT(db->db_data_pending == NULL);
+               ASSERT3U(dpa->dpa_curlevel, ==, BP_GET_LEVEL(bp));
 
-       kmem_cache_free(dbuf_cache, db);
-       arc_space_return(sizeof (dmu_buf_impl_t), ARC_SPACE_OTHER);
+               SET_BOOKMARK(&zb, dpa->dpa_zb.zb_objset,
+                   dpa->dpa_zb.zb_object, dpa->dpa_curlevel, nextblkid);
+
+               (void) arc_read(dpa->dpa_zio, dpa->dpa_spa,
+                   bp, dbuf_prefetch_indirect_done, dpa, dpa->dpa_prio,
+                   ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE,
+                   &iter_aflags, &zb);
+       }
+
+       arc_buf_destroy(abuf, private);
 }
 
+/*
+ * Issue prefetch reads for the given block on the given level.  If the indirect
+ * blocks above that block are not in memory, we will read them in
+ * asynchronously.  As a result, this call never blocks waiting for a read to
+ * complete.
+ */
 void
-dbuf_prefetch(dnode_t *dn, uint64_t blkid, zio_priority_t prio)
+dbuf_prefetch(dnode_t *dn, int64_t level, uint64_t blkid, zio_priority_t prio,
+    arc_flags_t aflags)
 {
-       dmu_buf_impl_t *db = NULL;
-       blkptr_t *bp = NULL;
+       blkptr_t bp;
+       int epbs, nlevels, curlevel;
+       uint64_t curblkid;
+       dmu_buf_impl_t *db;
+       zio_t *pio;
+       dbuf_prefetch_arg_t *dpa;
+       dsl_dataset_t *ds;
 
        ASSERT(blkid != DMU_BONUS_BLKID);
        ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
 
+       if (blkid > dn->dn_maxblkid)
+               return;
+
        if (dnode_block_freed(dn, blkid))
                return;
 
-       /* dbuf_find() returns with db_mtx held */
-       if ((db = dbuf_find(dn->dn_objset, dn->dn_object, 0, blkid))) {
+       /*
+        * This dnode hasn't been written to disk yet, so there's nothing to
+        * prefetch.
+        */
+       nlevels = dn->dn_phys->dn_nlevels;
+       if (level >= nlevels || dn->dn_phys->dn_nblkptr == 0)
+               return;
+
+       epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
+       if (dn->dn_phys->dn_maxblkid < blkid << (epbs * level))
+               return;
+
+       db = dbuf_find(dn->dn_objset, dn->dn_object,
+           level, blkid);
+       if (db != NULL) {
+               mutex_exit(&db->db_mtx);
                /*
-                * This dbuf is already in the cache.  We assume that
-                * it is already CACHED, or else about to be either
-                * read or filled.
+                * This dbuf already exists.  It is either CACHED, or
+                * (we assume) about to be read or filled.
                 */
-               mutex_exit(&db->db_mtx);
                return;
        }
 
-       if (dbuf_findbp(dn, 0, blkid, TRUE, &db, &bp, NULL) == 0) {
-               if (bp && !BP_IS_HOLE(bp) && !BP_IS_EMBEDDED(bp)) {
-                       dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
-                       arc_flags_t aflags =
-                           ARC_FLAG_NOWAIT | ARC_FLAG_PREFETCH;
-                       zbookmark_phys_t zb;
+       /*
+        * Find the closest ancestor (indirect block) of the target block
+        * that is present in the cache.  In this indirect block, we will
+        * find the bp that is at curlevel, curblkid.
+        */
+       curlevel = level;
+       curblkid = blkid;
+       while (curlevel < nlevels - 1) {
+               int parent_level = curlevel + 1;
+               uint64_t parent_blkid = curblkid >> epbs;
+               dmu_buf_impl_t *db;
+
+               if (dbuf_hold_impl(dn, parent_level, parent_blkid,
+                   FALSE, TRUE, FTAG, &db) == 0) {
+                       blkptr_t *bpp = db->db_buf->b_data;
+                       bp = bpp[P2PHASE(curblkid, 1 << epbs)];
+                       dbuf_rele(db, FTAG);
+                       break;
+               }
 
-                       SET_BOOKMARK(&zb, ds ? ds->ds_object : DMU_META_OBJSET,
-                           dn->dn_object, 0, blkid);
+               curlevel = parent_level;
+               curblkid = parent_blkid;
+       }
 
-                       (void) arc_read(NULL, dn->dn_objset->os_spa,
-                           bp, NULL, NULL, prio,
-                           ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE,
-                           &aflags, &zb);
-               }
-               if (db)
-                       dbuf_rele(db, NULL);
+       if (curlevel == nlevels - 1) {
+               /* No cached indirect blocks found. */
+               ASSERT3U(curblkid, <, dn->dn_phys->dn_nblkptr);
+               bp = dn->dn_phys->dn_blkptr[curblkid];
+       }
+       if (BP_IS_HOLE(&bp))
+               return;
+
+       ASSERT3U(curlevel, ==, BP_GET_LEVEL(&bp));
+
+       pio = zio_root(dmu_objset_spa(dn->dn_objset), NULL, NULL,
+           ZIO_FLAG_CANFAIL);
+
+       dpa = kmem_zalloc(sizeof (*dpa), KM_SLEEP);
+       ds = dn->dn_objset->os_dsl_dataset;
+       SET_BOOKMARK(&dpa->dpa_zb, ds != NULL ? ds->ds_object : DMU_META_OBJSET,
+           dn->dn_object, level, blkid);
+       dpa->dpa_curlevel = curlevel;
+       dpa->dpa_prio = prio;
+       dpa->dpa_aflags = aflags;
+       dpa->dpa_spa = dn->dn_objset->os_spa;
+       dpa->dpa_dnode = dn;
+       dpa->dpa_epbs = epbs;
+       dpa->dpa_zio = pio;
+
+       /*
+        * If we have the indirect just above us, no need to do the asynchronous
+        * prefetch chain; we'll just run the last step ourselves.  If we're at
+        * a higher level, though, we want to issue the prefetches for all the
+        * indirect blocks asynchronously, so we can go on with whatever we were
+        * doing.
+        */
+       if (curlevel == level) {
+               ASSERT3U(curblkid, ==, blkid);
+               dbuf_issue_final_prefetch(dpa, &bp);
+               kmem_free(dpa, sizeof (*dpa));
+       } else {
+               arc_flags_t iter_aflags = ARC_FLAG_NOWAIT;
+               zbookmark_phys_t zb;
+
+               SET_BOOKMARK(&zb, ds != NULL ? ds->ds_object : DMU_META_OBJSET,
+                   dn->dn_object, curlevel, curblkid);
+               (void) arc_read(dpa->dpa_zio, dpa->dpa_spa,
+                   &bp, dbuf_prefetch_indirect_done, dpa, prio,
+                   ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE,
+                   &iter_aflags, &zb);
        }
+       /*
+        * We use pio here instead of dpa_zio since it's possible that
+        * dpa may have already been freed.
+        */
+       zio_nowait(pio);
 }
 
 #define        DBUF_HOLD_IMPL_MAX_DEPTH        20
@@ -2066,7 +2672,7 @@ __dbuf_hold_impl(struct dbuf_hold_impl_data *dh)
        ASSERT3U(dh->dh_dn->dn_nlevels, >, dh->dh_level);
 
        *(dh->dh_dbp) = NULL;
-top:
+
        /* dbuf_find() returns with db_mtx held */
        dh->dh_db = dbuf_find(dh->dh_dn->dn_objset, dh->dh_dn->dn_object,
            dh->dh_level, dh->dh_blkid);
@@ -2074,6 +2680,9 @@ top:
        if (dh->dh_db == NULL) {
                dh->dh_bp = NULL;
 
+               if (dh->dh_fail_uncached)
+                       return (SET_ERROR(ENOENT));
+
                ASSERT3P(dh->dh_parent, ==, NULL);
                dh->dh_err = dbuf_findbp(dh->dh_dn, dh->dh_level, dh->dh_blkid,
                                        dh->dh_fail_sparse, &dh->dh_parent,
@@ -2094,19 +2703,14 @@ top:
                                        dh->dh_parent, dh->dh_bp);
        }
 
-       if (dh->dh_db->db_buf && refcount_is_zero(&dh->dh_db->db_holds)) {
-               arc_buf_add_ref(dh->dh_db->db_buf, dh->dh_db);
-               if (dh->dh_db->db_buf->b_data == NULL) {
-                       dbuf_clear(dh->dh_db);
-                       if (dh->dh_parent) {
-                               dbuf_rele(dh->dh_parent, NULL);
-                               dh->dh_parent = NULL;
-                       }
-                       goto top;
-               }
-               ASSERT3P(dh->dh_db->db.db_data, ==, dh->dh_db->db_buf->b_data);
+       if (dh->dh_fail_uncached && dh->dh_db->db_state != DB_CACHED) {
+               mutex_exit(&dh->dh_db->db_mtx);
+               return (SET_ERROR(ENOENT));
        }
 
+       if (dh->dh_db->db_buf != NULL)
+               ASSERT3P(dh->dh_db->db.db_data, ==, dh->dh_db->db_buf->b_data);
+
        ASSERT(dh->dh_db->db_buf == NULL || arc_referenced(dh->dh_db->db_buf));
 
        /*
@@ -2124,13 +2728,19 @@ top:
                        dh->dh_type = DBUF_GET_BUFC_TYPE(dh->dh_db);
 
                        dbuf_set_data(dh->dh_db,
-                           arc_buf_alloc(dh->dh_dn->dn_objset->os_spa,
-                           dh->dh_db->db.db_size, dh->dh_db, dh->dh_type));
+                           arc_alloc_buf(dh->dh_dn->dn_objset->os_spa,
+                           dh->dh_db, dh->dh_type, dh->dh_db->db.db_size));
                        bcopy(dh->dh_dr->dt.dl.dr_data->b_data,
                            dh->dh_db->db.db_data, dh->dh_db->db.db_size);
                }
        }
 
+       if (multilist_link_active(&dh->dh_db->db_cache_link)) {
+               ASSERT(refcount_is_zero(&dh->dh_db->db_holds));
+               multilist_remove(&dbuf_cache, dh->dh_db);
+               (void) refcount_remove_many(&dbuf_cache_size,
+                   dh->dh_db->db.db_size, dh->dh_db);
+       }
        (void) refcount_add(&dh->dh_db->db_holds, dh->dh_tag);
        DBUF_VERIFY(dh->dh_db);
        mutex_exit(&dh->dh_db->db_mtx);
@@ -2154,15 +2764,17 @@ top:
  * on the stack for 20 levels of recursion.
  */
 int
-dbuf_hold_impl(dnode_t *dn, uint8_t level, uint64_t blkid, int fail_sparse,
+dbuf_hold_impl(dnode_t *dn, uint8_t level, uint64_t blkid,
+    boolean_t fail_sparse, boolean_t fail_uncached,
     void *tag, dmu_buf_impl_t **dbp)
 {
        struct dbuf_hold_impl_data *dh;
        int error;
 
-       dh = kmem_zalloc(sizeof (struct dbuf_hold_impl_data) *
+       dh = kmem_alloc(sizeof (struct dbuf_hold_impl_data) *
            DBUF_HOLD_IMPL_MAX_DEPTH, KM_SLEEP);
-       __dbuf_hold_impl_init(dh, dn, level, blkid, fail_sparse, tag, dbp, 0);
+       __dbuf_hold_impl_init(dh, dn, level, blkid, fail_sparse,
+               fail_uncached, tag, dbp, 0);
 
        error = __dbuf_hold_impl(dh);
 
@@ -2174,31 +2786,41 @@ dbuf_hold_impl(dnode_t *dn, uint8_t level, uint64_t blkid, int fail_sparse,
 
 static void
 __dbuf_hold_impl_init(struct dbuf_hold_impl_data *dh,
-    dnode_t *dn, uint8_t level, uint64_t blkid, int fail_sparse,
-    void *tag, dmu_buf_impl_t **dbp, int depth)
+    dnode_t *dn, uint8_t level, uint64_t blkid,
+       boolean_t fail_sparse, boolean_t fail_uncached,
+       void *tag, dmu_buf_impl_t **dbp, int depth)
 {
        dh->dh_dn = dn;
        dh->dh_level = level;
        dh->dh_blkid = blkid;
+
        dh->dh_fail_sparse = fail_sparse;
+       dh->dh_fail_uncached = fail_uncached;
+
        dh->dh_tag = tag;
        dh->dh_dbp = dbp;
+
+       dh->dh_db = NULL;
+       dh->dh_parent = NULL;
+       dh->dh_bp = NULL;
+       dh->dh_err = 0;
+       dh->dh_dr = NULL;
+       dh->dh_type = 0;
+
        dh->dh_depth = depth;
 }
 
 dmu_buf_impl_t *
 dbuf_hold(dnode_t *dn, uint64_t blkid, void *tag)
 {
-       dmu_buf_impl_t *db;
-       int err = dbuf_hold_impl(dn, 0, blkid, FALSE, tag, &db);
-       return (err ? NULL : db);
+       return (dbuf_hold_level(dn, 0, blkid, tag));
 }
 
 dmu_buf_impl_t *
 dbuf_hold_level(dnode_t *dn, int level, uint64_t blkid, void *tag)
 {
        dmu_buf_impl_t *db;
-       int err = dbuf_hold_impl(dn, level, blkid, FALSE, tag, &db);
+       int err = dbuf_hold_impl(dn, level, blkid, FALSE, FALSE, tag, &db);
        return (err ? NULL : db);
 }
 
@@ -2244,7 +2866,8 @@ dbuf_rm_spill(dnode_t *dn, dmu_tx_t *tx)
 void
 dbuf_add_ref(dmu_buf_impl_t *db, void *tag)
 {
-       VERIFY(refcount_add(&db->db_holds, tag) > 1);
+       int64_t holds = refcount_add(&db->db_holds, tag);
+       VERIFY3S(holds, >, 1);
 }
 
 #pragma weak dmu_buf_try_add_ref = dbuf_try_add_ref
@@ -2315,8 +2938,10 @@ dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag)
         * We can't freeze indirects if there is a possibility that they
         * may be modified in the current syncing context.
         */
-       if (db->db_buf && holds == (db->db_level == 0 ? db->db_dirtycnt : 0))
+       if (db->db_buf != NULL &&
+           holds == (db->db_level == 0 ? db->db_dirtycnt : 0)) {
                arc_buf_freeze(db->db_buf);
+       }
 
        if (holds == db->db_dirtycnt &&
            db->db_level == 0 && db->db_user_immediate_evict)
@@ -2361,55 +2986,44 @@ dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag)
                         */
                        ASSERT(db->db_state == DB_UNCACHED ||
                            db->db_state == DB_NOFILL);
-                       dbuf_evict(db);
+                       dbuf_destroy(db);
                } else if (arc_released(db->db_buf)) {
-                       arc_buf_t *buf = db->db_buf;
                        /*
                         * This dbuf has anonymous data associated with it.
                         */
-                       dbuf_clear_data(db);
-                       VERIFY(arc_buf_remove_ref(buf, db));
-                       dbuf_evict(db);
+                       dbuf_destroy(db);
                } else {
-                       VERIFY(!arc_buf_remove_ref(db->db_buf, db));
+                       boolean_t do_arc_evict = B_FALSE;
+                       blkptr_t bp;
+                       spa_t *spa = dmu_objset_spa(db->db_objset);
+
+                       if (!DBUF_IS_CACHEABLE(db) &&
+                           db->db_blkptr != NULL &&
+                           !BP_IS_HOLE(db->db_blkptr) &&
+                           !BP_IS_EMBEDDED(db->db_blkptr)) {
+                               do_arc_evict = B_TRUE;
+                               bp = *db->db_blkptr;
+                       }
 
-                       /*
-                        * A dbuf will be eligible for eviction if either the
-                        * 'primarycache' property is set or a duplicate
-                        * copy of this buffer is already cached in the arc.
-                        *
-                        * In the case of the 'primarycache' a buffer
-                        * is considered for eviction if it matches the
-                        * criteria set in the property.
-                        *
-                        * To decide if our buffer is considered a
-                        * duplicate, we must call into the arc to determine
-                        * if multiple buffers are referencing the same
-                        * block on-disk. If so, then we simply evict
-                        * ourselves.
-                        */
-                       if (!DBUF_IS_CACHEABLE(db)) {
-                               if (db->db_blkptr != NULL &&
-                                   !BP_IS_HOLE(db->db_blkptr) &&
-                                   !BP_IS_EMBEDDED(db->db_blkptr)) {
-                                       spa_t *spa =
-                                           dmu_objset_spa(db->db_objset);
-                                       blkptr_t bp = *db->db_blkptr;
-                                       dbuf_clear(db);
-                                       arc_freed(spa, &bp);
-                               } else {
-                                       dbuf_clear(db);
-                               }
-                       } else if (db->db_pending_evict ||
-                           arc_buf_eviction_needed(db->db_buf)) {
-                               dbuf_clear(db);
-                       } else {
+                       if (!DBUF_IS_CACHEABLE(db) ||
+                           db->db_pending_evict) {
+                               dbuf_destroy(db);
+                       } else if (!multilist_link_active(&db->db_cache_link)) {
+                               multilist_insert(&dbuf_cache, db);
+                               (void) refcount_add_many(&dbuf_cache_size,
+                                   db->db.db_size, db);
                                mutex_exit(&db->db_mtx);
+
+                               dbuf_evict_notify();
                        }
+
+                       if (do_arc_evict)
+                               arc_freed(spa, &bp);
                }
        } else {
                mutex_exit(&db->db_mtx);
        }
+
 }
 
 #pragma weak dmu_buf_refcount = dbuf_refcount
@@ -2493,6 +3107,28 @@ dmu_buf_get_blkptr(dmu_buf_t *db)
        return (dbi->db_blkptr);
 }
 
+objset_t *
+dmu_buf_get_objset(dmu_buf_t *db)
+{
+       dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db;
+       return (dbi->db_objset);
+}
+
+dnode_t *
+dmu_buf_dnode_enter(dmu_buf_t *db)
+{
+       dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db;
+       DB_DNODE_ENTER(dbi);
+       return (DB_DNODE(dbi));
+}
+
+void
+dmu_buf_dnode_exit(dmu_buf_t *db)
+{
+       dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db;
+       DB_DNODE_EXIT(dbi);
+}
+
 static void
 dbuf_check_blkptr(dnode_t *dn, dmu_buf_impl_t *db)
 {
@@ -2503,7 +3139,7 @@ dbuf_check_blkptr(dnode_t *dn, dmu_buf_impl_t *db)
                return;
 
        if (db->db_blkid == DMU_SPILL_BLKID) {
-               db->db_blkptr = &dn->dn_phys->dn_spill;
+               db->db_blkptr = DN_SPILL_BLKPTR(dn->dn_phys);
                BP_ZERO(db->db_blkptr);
                return;
        }
@@ -2526,8 +3162,8 @@ dbuf_check_blkptr(dnode_t *dn, dmu_buf_impl_t *db)
                if (parent == NULL) {
                        mutex_exit(&db->db_mtx);
                        rw_enter(&dn->dn_struct_rwlock, RW_READER);
-                       (void) dbuf_hold_impl(dn, db->db_level+1,
-                           db->db_blkid >> epbs, FALSE, db, &parent);
+                       parent = dbuf_hold_level(dn, db->db_level + 1,
+                           db->db_blkid >> epbs, db);
                        rw_exit(&dn->dn_struct_rwlock);
                        mutex_enter(&db->db_mtx);
                        db->db_parent = parent;
@@ -2659,13 +3295,16 @@ dbuf_sync_leaf(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
 
                ASSERT(*datap != NULL);
                ASSERT0(db->db_level);
-               ASSERT3U(dn->dn_phys->dn_bonuslen, <=, DN_MAX_BONUSLEN);
+               ASSERT3U(dn->dn_phys->dn_bonuslen, <=,
+                   DN_SLOTS_TO_BONUSLEN(dn->dn_phys->dn_extra_slots + 1));
                bcopy(*datap, DN_BONUS(dn->dn_phys), dn->dn_phys->dn_bonuslen);
                DB_DNODE_EXIT(db);
 
                if (*datap != db->db.db_data) {
-                       zio_buf_free(*datap, DN_MAX_BONUSLEN);
-                       arc_space_return(DN_MAX_BONUSLEN, ARC_SPACE_OTHER);
+                       int slots = DB_DNODE(db)->dn_num_slots;
+                       int bonuslen = DN_SLOTS_TO_BONUSLEN(slots);
+                       zio_buf_free(*datap, bonuslen);
+                       arc_space_return(bonuslen, ARC_SPACE_BONUS);
                }
                db->db_data_pending = NULL;
                drp = &db->db_last_dirty;
@@ -2721,10 +3360,19 @@ dbuf_sync_leaf(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
                 * objects only modified in the syncing context (e.g.
                 * DNONE_DNODE blocks).
                 */
-               int blksz = arc_buf_size(*datap);
+               int psize = arc_buf_size(*datap);
                arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
-               *datap = arc_buf_alloc(os->os_spa, blksz, db, type);
-               bcopy(db->db.db_data, (*datap)->b_data, blksz);
+               enum zio_compress compress_type = arc_get_compression(*datap);
+
+               if (compress_type == ZIO_COMPRESS_OFF) {
+                       *datap = arc_alloc_buf(os->os_spa, db, type, psize);
+               } else {
+                       int lsize = arc_buf_lsize(*datap);
+                       ASSERT3U(type, ==, ARC_BUFC_DATA);
+                       *datap = arc_alloc_compressed_buf(os->os_spa, db,
+                           psize, lsize, compress_type);
+               }
+               bcopy(db->db.db_data, (*datap)->b_data, psize);
        }
        db->db_data_pending = dr;
 
@@ -2792,7 +3440,8 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
        uint64_t fill = 0;
        int i;
 
-       ASSERT3P(db->db_blkptr, ==, bp);
+       ASSERT3P(db->db_blkptr, !=, NULL);
+       ASSERT3P(&db->db_data_pending->dr_bp_copy, ==, bp);
 
        DB_DNODE_ENTER(db);
        dn = DB_DNODE(db);
@@ -2814,8 +3463,8 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
 #ifdef ZFS_DEBUG
        if (db->db_blkid == DMU_SPILL_BLKID) {
                ASSERT(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR);
-               ASSERT(!(BP_IS_HOLE(db->db_blkptr)) &&
-                   db->db_blkptr == &dn->dn_phys->dn_spill);
+               ASSERT(!(BP_IS_HOLE(bp)) &&
+                   db->db_blkptr == DN_SPILL_BLKPTR(dn->dn_phys));
        }
 #endif
 
@@ -2827,11 +3476,16 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
                mutex_exit(&dn->dn_mtx);
 
                if (dn->dn_type == DMU_OT_DNODE) {
-                       dnode_phys_t *dnp = db->db.db_data;
-                       for (i = db->db.db_size >> DNODE_SHIFT; i > 0;
-                           i--, dnp++) {
-                               if (dnp->dn_type != DMU_OT_NONE)
+                       i = 0;
+                       while (i < db->db.db_size) {
+                               dnode_phys_t *dnp = db->db.db_data + i;
+
+                               i += DNODE_MIN_SIZE;
+                               if (dnp->dn_type != DMU_OT_NONE) {
                                        fill++;
+                                       i += dnp->dn_extra_slots *
+                                           DNODE_MIN_SIZE;
+                               }
                        }
                } else {
                        if (BP_IS_HOLE(bp)) {
@@ -2855,6 +3509,49 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
                bp->blk_fill = fill;
 
        mutex_exit(&db->db_mtx);
+
+       rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
+       *db->db_blkptr = *bp;
+       rw_exit(&dn->dn_struct_rwlock);
+}
+
+/* ARGSUSED */
+/*
+ * This function gets called just prior to running through the compression
+ * stage of the zio pipeline. If we're an indirect block comprised of only
+ * holes, then we want this indirect to be compressed away to a hole. In
+ * order to do that we must zero out any information about the holes that
+ * this indirect points to prior to before we try to compress it.
+ */
+static void
+dbuf_write_children_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
+{
+       dmu_buf_impl_t *db = vdb;
+       dnode_t *dn;
+       blkptr_t *bp;
+       uint64_t i;
+       int epbs;
+
+       ASSERT3U(db->db_level, >, 0);
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
+
+       /* Determine if all our children are holes */
+       for (i = 0, bp = db->db.db_data; i < 1ULL << epbs; i++, bp++) {
+               if (!BP_IS_HOLE(bp))
+                       break;
+       }
+
+       /*
+        * If all the children are holes, then zero them all out so that
+        * we may get compressed away.
+        */
+       if (i == 1ULL << epbs) {
+               /* didn't find any non-holes */
+               bzero(db->db.db_data, db->db.db_size);
+       }
+       DB_DNODE_EXIT(db);
 }
 
 /*
@@ -2935,7 +3632,7 @@ dbuf_write_done(zio_t *zio, arc_buf_t *buf, void *vdb)
                dn = DB_DNODE(db);
                ASSERT(dn->dn_phys->dn_flags & DNODE_FLAG_SPILL_BLKPTR);
                ASSERT(!(BP_IS_HOLE(db->db_blkptr)) &&
-                   db->db_blkptr == &dn->dn_phys->dn_spill);
+                   db->db_blkptr == DN_SPILL_BLKPTR(dn->dn_phys));
                DB_DNODE_EXIT(db);
        }
 #endif
@@ -2945,10 +3642,7 @@ dbuf_write_done(zio_t *zio, arc_buf_t *buf, void *vdb)
                ASSERT(dr->dt.dl.dr_override_state == DR_NOT_OVERRIDDEN);
                if (db->db_state != DB_NOFILL) {
                        if (dr->dt.dl.dr_data != db->db_buf)
-                               VERIFY(arc_buf_remove_ref(dr->dt.dl.dr_data,
-                                   db));
-                       else if (!arc_released(db->db_buf))
-                               arc_set_callback(db->db_buf, dbuf_do_evict, db);
+                               arc_buf_destroy(dr->dt.dl.dr_data, db);
                }
        } else {
                dnode_t *dn;
@@ -2964,8 +3658,6 @@ dbuf_write_done(zio_t *zio, arc_buf_t *buf, void *vdb)
                            dn->dn_phys->dn_maxblkid >> (db->db_level * epbs));
                        ASSERT3U(BP_GET_LSIZE(db->db_blkptr), ==,
                            db->db.db_size);
-                       if (!arc_released(db->db_buf))
-                               arc_set_callback(db->db_buf, dbuf_do_evict, db);
                }
                DB_DNODE_EXIT(db);
                mutex_destroy(&dr->dt.di.dr_mtx);
@@ -3033,6 +3725,8 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
        zio_t *zio;
        int wp_flag = 0;
 
+       ASSERT(dmu_tx_is_syncing(tx));
+
        DB_DNODE_ENTER(db);
        dn = DB_DNODE(db);
        os = dn->dn_objset;
@@ -3088,9 +3782,19 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
                wp_flag = WP_SPILL;
        wp_flag |= (db->db_state == DB_NOFILL) ? WP_NOFILL : 0;
 
-       dmu_write_policy(os, dn, db->db_level, wp_flag, &zp);
+       dmu_write_policy(os, dn, db->db_level, wp_flag,
+           (data != NULL && arc_get_compression(data) != ZIO_COMPRESS_OFF) ?
+           arc_get_compression(data) : ZIO_COMPRESS_INHERIT, &zp);
        DB_DNODE_EXIT(db);
 
+       /*
+        * We copy the blkptr now (rather than when we instantiate the dirty
+        * record), because its value can change between open context and
+        * syncing context. We do not need to hold dn_struct_rwlock to read
+        * db_blkptr because we are in syncing context.
+        */
+       dr->dr_bp_copy = *db->db_blkptr;
+
        if (db->db_level == 0 &&
            dr->dt.dl.dr_override_state == DR_OVERRIDDEN) {
                /*
@@ -3100,8 +3804,9 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
                void *contents = (data != NULL) ? data->b_data : NULL;
 
                dr->dr_zio = zio_write(zio, os->os_spa, txg,
-                   db->db_blkptr, contents, db->db.db_size, &zp,
-                   dbuf_write_override_ready, NULL, dbuf_write_override_done,
+                   &dr->dr_bp_copy, contents, db->db.db_size, db->db.db_size,
+                   &zp, dbuf_write_override_ready, NULL, NULL,
+                   dbuf_write_override_done,
                    dr, ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
                mutex_enter(&db->db_mtx);
                dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
@@ -3109,26 +3814,39 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
                    dr->dt.dl.dr_copies, dr->dt.dl.dr_nopwrite);
                mutex_exit(&db->db_mtx);
        } else if (db->db_state == DB_NOFILL) {
-               ASSERT(zp.zp_checksum == ZIO_CHECKSUM_OFF);
+               ASSERT(zp.zp_checksum == ZIO_CHECKSUM_OFF ||
+                   zp.zp_checksum == ZIO_CHECKSUM_NOPARITY);
                dr->dr_zio = zio_write(zio, os->os_spa, txg,
-                   db->db_blkptr, NULL, db->db.db_size, &zp,
-                   dbuf_write_nofill_ready, NULL, dbuf_write_nofill_done, db,
+                   &dr->dr_bp_copy, NULL, db->db.db_size, db->db.db_size, &zp,
+                   dbuf_write_nofill_ready, NULL, NULL,
+                   dbuf_write_nofill_done, db,
                    ZIO_PRIORITY_ASYNC_WRITE,
                    ZIO_FLAG_MUSTSUCCEED | ZIO_FLAG_NODATA, &zb);
        } else {
+               arc_done_func_t *children_ready_cb = NULL;
                ASSERT(arc_released(data));
+
+               /*
+                * For indirect blocks, we want to setup the children
+                * ready callback so that we can properly handle an indirect
+                * block that only contains holes.
+                */
+               if (db->db_level != 0)
+                       children_ready_cb = dbuf_write_children_ready;
+
                dr->dr_zio = arc_write(zio, os->os_spa, txg,
-                   db->db_blkptr, data, DBUF_IS_L2CACHEABLE(db),
-                   DBUF_IS_L2COMPRESSIBLE(db), &zp, dbuf_write_ready,
-                   dbuf_write_physdone, dbuf_write_done, db,
-                   ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
+                   &dr->dr_bp_copy, data, DBUF_IS_L2CACHEABLE(db),
+                   &zp, dbuf_write_ready,
+                   children_ready_cb, dbuf_write_physdone,
+                   dbuf_write_done, db, ZIO_PRIORITY_ASYNC_WRITE,
+                   ZIO_FLAG_MUSTSUCCEED, &zb);
        }
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
 EXPORT_SYMBOL(dbuf_find);
 EXPORT_SYMBOL(dbuf_is_metadata);
-EXPORT_SYMBOL(dbuf_evict);
+EXPORT_SYMBOL(dbuf_destroy);
 EXPORT_SYMBOL(dbuf_loan_arcbuf);
 EXPORT_SYMBOL(dbuf_whichblock);
 EXPORT_SYMBOL(dbuf_read);
@@ -3143,7 +3861,6 @@ EXPORT_SYMBOL(dmu_buf_will_fill);
 EXPORT_SYMBOL(dmu_buf_fill_done);
 EXPORT_SYMBOL(dmu_buf_rele);
 EXPORT_SYMBOL(dbuf_assign_arcbuf);
-EXPORT_SYMBOL(dbuf_clear);
 EXPORT_SYMBOL(dbuf_prefetch);
 EXPORT_SYMBOL(dbuf_hold_impl);
 EXPORT_SYMBOL(dbuf_hold);
@@ -3161,4 +3878,24 @@ EXPORT_SYMBOL(dmu_buf_set_user_ie);
 EXPORT_SYMBOL(dmu_buf_get_user);
 EXPORT_SYMBOL(dmu_buf_freeable);
 EXPORT_SYMBOL(dmu_buf_get_blkptr);
+
+
+module_param(dbuf_cache_max_bytes, ulong, 0644);
+MODULE_PARM_DESC(dbuf_cache_max_bytes,
+               "Maximum size in bytes of the dbuf cache.");
+
+module_param(dbuf_cache_hiwater_pct, uint, 0644);
+MODULE_PARM_DESC(dbuf_cache_hiwater_pct,
+               "Percentage over dbuf_cache_max_bytes when dbufs \
+                much be evicted directly.");
+
+module_param(dbuf_cache_lowater_pct, uint, 0644);
+MODULE_PARM_DESC(dbuf_cache_lowater_pct,
+               "Percentage below dbuf_cache_max_bytes \
+               when the evict thread stop evicting dbufs.");
+
+module_param(dbuf_cache_max_shift, int, 0644);
+MODULE_PARM_DESC(dbuf_cache_max_shift,
+               "Cap the size of the dbuf cache to log2 fraction of arc size.");
+
 #endif
index 6f39f80e563a52f5db627b299c5797b9ad98d6dd..ae8ba86825996d695bbfde2a3ffae1111caa708a 100644 (file)
@@ -95,7 +95,7 @@ __dbuf_stats_hash_table_data(char *buf, size_t size, dmu_buf_impl_t *db)
            abi.abi_state_type,
            abi.abi_state_contents,
            abi.abi_flags,
-           (ulong_t)abi.abi_datacnt,
+           (ulong_t)abi.abi_bufcnt,
            (u_longlong_t)abi.abi_size,
            (u_longlong_t)abi.abi_access,
            (ulong_t)abi.abi_mru_hits,
index 12c1b7300a2136e088806d8b83a25791578981cd..09a3536f58ee285539f1ef445ed5eb524bdd605c 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -62,7 +62,8 @@ ddt_object_create(ddt_t *ddt, enum ddt_type type, enum ddt_class class,
        spa_t *spa = ddt->ddt_spa;
        objset_t *os = ddt->ddt_os;
        uint64_t *objectp = &ddt->ddt_object[type][class];
-       boolean_t prehash = zio_checksum_table[ddt->ddt_checksum].ci_dedup;
+       boolean_t prehash = zio_checksum_table[ddt->ddt_checksum].ci_flags &
+           ZCHECKSUM_FLAG_DEDUP;
        char name[DDT_NAMELEN];
 
        ddt_object_name(ddt, type, class, name);
@@ -811,23 +812,32 @@ ddt_prefetch(spa_t *spa, const blkptr_t *bp)
        }
 }
 
+/*
+ * Opaque struct used for ddt_key comparison
+ */
+#define        DDT_KEY_CMP_LEN (sizeof (ddt_key_t) / sizeof (uint16_t))
+
+typedef struct ddt_key_cmp {
+       uint16_t        u16[DDT_KEY_CMP_LEN];
+} ddt_key_cmp_t;
+
 int
 ddt_entry_compare(const void *x1, const void *x2)
 {
        const ddt_entry_t *dde1 = x1;
        const ddt_entry_t *dde2 = x2;
-       const uint64_t *u1 = (const uint64_t *)&dde1->dde_key;
-       const uint64_t *u2 = (const uint64_t *)&dde2->dde_key;
+       const ddt_key_cmp_t *k1 = (const ddt_key_cmp_t *)&dde1->dde_key;
+       const ddt_key_cmp_t *k2 = (const ddt_key_cmp_t *)&dde2->dde_key;
+       int32_t cmp = 0;
        int i;
 
-       for (i = 0; i < DDT_KEY_WORDS; i++) {
-               if (u1[i] < u2[i])
-                       return (-1);
-               if (u1[i] > u2[i])
-                       return (1);
+       for (i = 0; i < DDT_KEY_CMP_LEN; i++) {
+               cmp = (int32_t)k1->u16[i] - (int32_t)k2->u16[i];
+               if (likely(cmp))
+                       break;
        }
 
-       return (0);
+       return (AVL_ISIGN(cmp));
 }
 
 static ddt_t *
index 5e2a1db601b49fc85d59bf064cfcfa8a150f814f..7da49af7b5f126f0ef0c116a57f7b547246d63ee 100644 (file)
@@ -20,8 +20,9 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
  */
@@ -126,6 +127,26 @@ const dmu_object_byteswap_info_t dmu_ot_byteswap[DMU_BSWAP_NUMFUNCS] = {
        {       zfs_acl_byteswap,       "acl"           }
 };
 
+int
+dmu_buf_hold_noread_by_dnode(dnode_t *dn, uint64_t offset,
+    void *tag, dmu_buf_t **dbp)
+{
+       uint64_t blkid;
+       dmu_buf_impl_t *db;
+
+       blkid = dbuf_whichblock(dn, 0, offset);
+       rw_enter(&dn->dn_struct_rwlock, RW_READER);
+       db = dbuf_hold(dn, blkid, tag);
+       rw_exit(&dn->dn_struct_rwlock);
+
+       if (db == NULL) {
+               *dbp = NULL;
+               return (SET_ERROR(EIO));
+       }
+
+       *dbp = &db->db;
+       return (0);
+}
 int
 dmu_buf_hold_noread(objset_t *os, uint64_t object, uint64_t offset,
     void *tag, dmu_buf_t **dbp)
@@ -138,7 +159,7 @@ dmu_buf_hold_noread(objset_t *os, uint64_t object, uint64_t offset,
        err = dnode_hold(os, object, FTAG, &dn);
        if (err)
                return (err);
-       blkid = dbuf_whichblock(dn, offset);
+       blkid = dbuf_whichblock(dn, 0, offset);
        rw_enter(&dn->dn_struct_rwlock, RW_READER);
        db = dbuf_hold(dn, blkid, tag);
        rw_exit(&dn->dn_struct_rwlock);
@@ -153,6 +174,29 @@ dmu_buf_hold_noread(objset_t *os, uint64_t object, uint64_t offset,
        return (err);
 }
 
+int
+dmu_buf_hold_by_dnode(dnode_t *dn, uint64_t offset,
+    void *tag, dmu_buf_t **dbp, int flags)
+{
+       int err;
+       int db_flags = DB_RF_CANFAIL;
+
+       if (flags & DMU_READ_NO_PREFETCH)
+               db_flags |= DB_RF_NOPREFETCH;
+
+       err = dmu_buf_hold_noread_by_dnode(dn, offset, tag, dbp);
+       if (err == 0) {
+               dmu_buf_impl_t *db = (dmu_buf_impl_t *)(*dbp);
+               err = dbuf_read(db, NULL, db_flags);
+               if (err != 0) {
+                       dbuf_rele(db, tag);
+                       *dbp = NULL;
+               }
+       }
+
+       return (err);
+}
+
 int
 dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset,
     void *tag, dmu_buf_t **dbp, int flags)
@@ -179,7 +223,7 @@ dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset,
 int
 dmu_bonus_max(void)
 {
-       return (DN_MAX_BONUSLEN);
+       return (DN_OLD_MAX_BONUSLEN);
 }
 
 int
@@ -386,7 +430,7 @@ dmu_spill_hold_by_bonus(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp)
  */
 static int
 dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
-    int read, void *tag, int *numbufsp, dmu_buf_t ***dbpp, uint32_t flags)
+    boolean_t read, void *tag, int *numbufsp, dmu_buf_t ***dbpp, uint32_t flags)
 {
        dmu_buf_t **dbp;
        uint64_t blkid, nblks, i;
@@ -396,15 +440,19 @@ dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
 
        ASSERT(length <= DMU_MAX_ACCESS);
 
-       dbuf_flags = DB_RF_CANFAIL | DB_RF_NEVERWAIT | DB_RF_HAVESTRUCT;
-       if (flags & DMU_READ_NO_PREFETCH || length > zfetch_array_rd_sz)
-               dbuf_flags |= DB_RF_NOPREFETCH;
+       /*
+        * Note: We directly notify the prefetch code of this read, so that
+        * we can tell it about the multi-block read.  dbuf_read() only knows
+        * about the one block it is accessing.
+        */
+       dbuf_flags = DB_RF_CANFAIL | DB_RF_NEVERWAIT | DB_RF_HAVESTRUCT |
+           DB_RF_NOPREFETCH;
 
        rw_enter(&dn->dn_struct_rwlock, RW_READER);
        if (dn->dn_datablkshift) {
                int blkshift = dn->dn_datablkshift;
-               nblks = (P2ROUNDUP(offset+length, 1ULL<<blkshift) -
-                   P2ALIGN(offset, 1ULL<<blkshift)) >> blkshift;
+               nblks = (P2ROUNDUP(offset + length, 1ULL << blkshift) -
+                   P2ALIGN(offset, 1ULL << blkshift)) >> blkshift;
        } else {
                if (offset + length > dn->dn_datablksz) {
                        zfs_panic_recover("zfs: accessing past end of object "
@@ -421,21 +469,27 @@ dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length,
        dbp = kmem_zalloc(sizeof (dmu_buf_t *) * nblks, KM_SLEEP);
 
        zio = zio_root(dn->dn_objset->os_spa, NULL, NULL, ZIO_FLAG_CANFAIL);
-       blkid = dbuf_whichblock(dn, offset);
+       blkid = dbuf_whichblock(dn, 0, offset);
        for (i = 0; i < nblks; i++) {
-               dmu_buf_impl_t *db = dbuf_hold(dn, blkid+i, tag);
+               dmu_buf_impl_t *db = dbuf_hold(dn, blkid + i, tag);
                if (db == NULL) {
                        rw_exit(&dn->dn_struct_rwlock);
                        dmu_buf_rele_array(dbp, nblks, tag);
                        zio_nowait(zio);
                        return (SET_ERROR(EIO));
                }
+
                /* initiate async i/o */
-               if (read) {
+               if (read)
                        (void) dbuf_read(db, zio, dbuf_flags);
-               }
                dbp[i] = &db->db;
        }
+
+       if ((flags & DMU_READ_NO_PREFETCH) == 0 &&
+           DNODE_META_IS_CACHEABLE(dn) && length <= zfetch_array_rd_sz) {
+               dmu_zfetch(&dn->dn_zfetch, blkid, nblks,
+                   read && DNODE_IS_CACHEABLE(dn));
+       }
        rw_exit(&dn->dn_struct_rwlock);
 
        /* wait for async i/o */
@@ -489,7 +543,8 @@ dmu_buf_hold_array(objset_t *os, uint64_t object, uint64_t offset,
 
 int
 dmu_buf_hold_array_by_bonus(dmu_buf_t *db_fake, uint64_t offset,
-    uint64_t length, int read, void *tag, int *numbufsp, dmu_buf_t ***dbpp)
+    uint64_t length, boolean_t read, void *tag, int *numbufsp,
+    dmu_buf_t ***dbpp)
 {
        dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
        dnode_t *dn;
@@ -522,25 +577,21 @@ dmu_buf_rele_array(dmu_buf_t **dbp_fake, int numbufs, void *tag)
 }
 
 /*
- * Issue prefetch i/os for the given blocks.
- *
- * Note: The assumption is that we *know* these blocks will be needed
- * almost immediately.  Therefore, the prefetch i/os will be issued at
- * ZIO_PRIORITY_SYNC_READ
+ * Issue prefetch i/os for the given blocks.  If level is greater than 0, the
+ * indirect blocks prefeteched will be those that point to the blocks containing
+ * the data starting at offset, and continuing to offset + len.
  *
- * Note: indirect blocks and other metadata will be read synchronously,
- * causing this function to block if they are not already cached.
+ * Note that if the indirect blocks above the blocks being prefetched are not in
+ * cache, they will be asychronously read in.
  */
 void
-dmu_prefetch(objset_t *os, uint64_t object, uint64_t offset, uint64_t len)
+dmu_prefetch(objset_t *os, uint64_t object, int64_t level, uint64_t offset,
+    uint64_t len, zio_priority_t pri)
 {
        dnode_t *dn;
        uint64_t blkid;
        int nblks, err;
 
-       if (zfs_prefetch_disable)
-               return;
-
        if (len == 0) {  /* they're interested in the bonus buffer */
                dn = DMU_META_DNODE(os);
 
@@ -548,8 +599,9 @@ dmu_prefetch(objset_t *os, uint64_t object, uint64_t offset, uint64_t len)
                        return;
 
                rw_enter(&dn->dn_struct_rwlock, RW_READER);
-               blkid = dbuf_whichblock(dn, object * sizeof (dnode_phys_t));
-               dbuf_prefetch(dn, blkid, ZIO_PRIORITY_SYNC_READ);
+               blkid = dbuf_whichblock(dn, level,
+                   object * sizeof (dnode_phys_t));
+               dbuf_prefetch(dn, level, blkid, pri, 0);
                rw_exit(&dn->dn_struct_rwlock);
                return;
        }
@@ -564,10 +616,16 @@ dmu_prefetch(objset_t *os, uint64_t object, uint64_t offset, uint64_t len)
                return;
 
        rw_enter(&dn->dn_struct_rwlock, RW_READER);
-       if (dn->dn_datablkshift) {
-               int blkshift = dn->dn_datablkshift;
-               nblks = (P2ROUNDUP(offset + len, 1 << blkshift) -
-                   P2ALIGN(offset, 1 << blkshift)) >> blkshift;
+       /*
+        * offset + len - 1 is the last byte we want to prefetch for, and offset
+        * is the first.  Then dbuf_whichblk(dn, level, off + len - 1) is the
+        * last block we want to prefetch, and dbuf_whichblock(dn, level,
+        * offset)  is the first.  Then the number we need to prefetch is the
+        * last - first + 1.
+        */
+       if (level > 0 || dn->dn_datablkshift != 0) {
+               nblks = dbuf_whichblock(dn, level, offset + len - 1) -
+                   dbuf_whichblock(dn, level, offset) + 1;
        } else {
                nblks = (offset < dn->dn_datablksz);
        }
@@ -575,9 +633,9 @@ dmu_prefetch(objset_t *os, uint64_t object, uint64_t offset, uint64_t len)
        if (nblks != 0) {
                int i;
 
-               blkid = dbuf_whichblock(dn, offset);
+               blkid = dbuf_whichblock(dn, level, offset);
                for (i = 0; i < nblks; i++)
-                       dbuf_prefetch(dn, blkid + i, ZIO_PRIORITY_SYNC_READ);
+                       dbuf_prefetch(dn, level, blkid + i, pri, 0);
        }
 
        rw_exit(&dn->dn_struct_rwlock);
@@ -674,6 +732,12 @@ dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
                tx = dmu_tx_create(os);
                dmu_tx_hold_free(tx, dn->dn_object,
                    chunk_begin, chunk_end - chunk_begin);
+
+               /*
+                * Mark this transaction as typically resulting in a net
+                * reduction in space used.
+                */
+               dmu_tx_mark_netfree(tx);
                err = dmu_tx_assign(tx, TXG_WAIT);
                if (err) {
                        dmu_tx_abort(tx);
@@ -725,6 +789,7 @@ dmu_free_long_object(objset_t *os, uint64_t object)
        tx = dmu_tx_create(os);
        dmu_tx_hold_bonus(tx, object);
        dmu_tx_hold_free(tx, object, 0, DMU_OBJECT_END);
+       dmu_tx_mark_netfree(tx);
        err = dmu_tx_assign(tx, TXG_WAIT);
        if (err == 0) {
                err = dmu_object_free(os, object, tx);
@@ -922,6 +987,7 @@ static xuio_stats_t xuio_stats = {
        atomic_add_64(&xuio_stats.stat.value.ui64, (val))
 #define        XUIOSTAT_BUMP(stat)     XUIOSTAT_INCR(stat, 1)
 
+#ifdef HAVE_UIO_ZEROCOPY
 int
 dmu_xuio_init(xuio_t *xuio, int nblk)
 {
@@ -974,7 +1040,7 @@ dmu_xuio_add(xuio_t *xuio, arc_buf_t *abuf, offset_t off, size_t n)
        int i = priv->next++;
 
        ASSERT(i < priv->cnt);
-       ASSERT(off + n <= arc_buf_size(abuf));
+       ASSERT(off + n <= arc_buf_lsize(abuf));
        iov = (iovec_t *)uio->uio_iov + i;
        iov->iov_base = (char *)abuf->b_data + off;
        iov->iov_len = n;
@@ -1006,6 +1072,7 @@ dmu_xuio_clear(xuio_t *xuio, int i)
        ASSERT(i < priv->cnt);
        priv->bufs[i] = NULL;
 }
+#endif /* HAVE_UIO_ZEROCOPY */
 
 static void
 xuio_stat_init(void)
@@ -1041,176 +1108,14 @@ xuio_stat_wbuf_nocopy()
 }
 
 #ifdef _KERNEL
-
-/*
- * Copy up to size bytes between arg_buf and req based on the data direction
- * described by the req.  If an entire req's data cannot be transfered in one
- * pass, you should pass in @req_offset to indicate where to continue. The
- * return value is the number of bytes successfully copied to arg_buf.
- */
-static int
-dmu_bio_copy(void *arg_buf, int size, struct bio *bio, size_t bio_offset)
-{
-       struct bio_vec bv, *bvp = &bv;
-       bvec_iterator_t iter;
-       char *bv_buf;
-       int tocpy, bv_len, bv_offset;
-       int offset = 0;
-
-       bio_for_each_segment4(bv, bvp, bio, iter) {
-
-               /*
-                * Fully consumed the passed arg_buf. We use goto here because
-                * rq_for_each_segment is a double loop
-                */
-               ASSERT3S(offset, <=, size);
-               if (size == offset)
-                       goto out;
-
-               /* Skip already copied bvp */
-               if (bio_offset >= bvp->bv_len) {
-                       bio_offset -= bvp->bv_len;
-                       continue;
-               }
-
-               bv_len = bvp->bv_len - bio_offset;
-               bv_offset = bvp->bv_offset + bio_offset;
-               bio_offset = 0;
-
-               tocpy = MIN(bv_len, size - offset);
-               ASSERT3S(tocpy, >=, 0);
-
-               bv_buf = page_address(bvp->bv_page) + bv_offset;
-               ASSERT3P(bv_buf, !=, NULL);
-
-               if (bio_data_dir(bio) == WRITE)
-                       memcpy(arg_buf + offset, bv_buf, tocpy);
-               else
-                       memcpy(bv_buf, arg_buf + offset, tocpy);
-
-               offset += tocpy;
-       }
-out:
-       return (offset);
-}
-
-int
-dmu_read_bio(objset_t *os, uint64_t object, struct bio *bio)
-{
-       uint64_t offset = BIO_BI_SECTOR(bio) << 9;
-       uint64_t size = BIO_BI_SIZE(bio);
-       dmu_buf_t **dbp;
-       int numbufs, i, err;
-       size_t bio_offset;
-
-       /*
-        * NB: we could do this block-at-a-time, but it's nice
-        * to be reading in parallel.
-        */
-       err = dmu_buf_hold_array(os, object, offset, size, TRUE, FTAG,
-           &numbufs, &dbp);
-       if (err)
-               return (err);
-
-       bio_offset = 0;
-       for (i = 0; i < numbufs; i++) {
-               uint64_t tocpy;
-               int64_t bufoff;
-               int didcpy;
-               dmu_buf_t *db = dbp[i];
-
-               bufoff = offset - db->db_offset;
-               ASSERT3S(bufoff, >=, 0);
-
-               tocpy = MIN(db->db_size - bufoff, size);
-               if (tocpy == 0)
-                       break;
-
-               didcpy = dmu_bio_copy(db->db_data + bufoff, tocpy, bio,
-                   bio_offset);
-
-               if (didcpy < tocpy)
-                       err = EIO;
-
-               if (err)
-                       break;
-
-               size -= tocpy;
-               offset += didcpy;
-               bio_offset += didcpy;
-               err = 0;
-       }
-       dmu_buf_rele_array(dbp, numbufs, FTAG);
-
-       return (err);
-}
-
-int
-dmu_write_bio(objset_t *os, uint64_t object, struct bio *bio, dmu_tx_t *tx)
-{
-       uint64_t offset = BIO_BI_SECTOR(bio) << 9;
-       uint64_t size = BIO_BI_SIZE(bio);
-       dmu_buf_t **dbp;
-       int numbufs, i, err;
-       size_t bio_offset;
-
-       if (size == 0)
-               return (0);
-
-       err = dmu_buf_hold_array(os, object, offset, size, FALSE, FTAG,
-           &numbufs, &dbp);
-       if (err)
-               return (err);
-
-       bio_offset = 0;
-       for (i = 0; i < numbufs; i++) {
-               uint64_t tocpy;
-               int64_t bufoff;
-               int didcpy;
-               dmu_buf_t *db = dbp[i];
-
-               bufoff = offset - db->db_offset;
-               ASSERT3S(bufoff, >=, 0);
-
-               tocpy = MIN(db->db_size - bufoff, size);
-               if (tocpy == 0)
-                       break;
-
-               ASSERT(i == 0 || i == numbufs-1 || tocpy == db->db_size);
-
-               if (tocpy == db->db_size)
-                       dmu_buf_will_fill(db, tx);
-               else
-                       dmu_buf_will_dirty(db, tx);
-
-               didcpy = dmu_bio_copy(db->db_data + bufoff, tocpy, bio,
-                   bio_offset);
-
-               if (tocpy == db->db_size)
-                       dmu_buf_fill_done(db, tx);
-
-               if (didcpy < tocpy)
-                       err = EIO;
-
-               if (err)
-                       break;
-
-               size -= tocpy;
-               offset += didcpy;
-               bio_offset += didcpy;
-               err = 0;
-       }
-
-       dmu_buf_rele_array(dbp, numbufs, FTAG);
-       return (err);
-}
-
 static int
 dmu_read_uio_dnode(dnode_t *dn, uio_t *uio, uint64_t size)
 {
        dmu_buf_t **dbp;
        int numbufs, i, err;
+#ifdef HAVE_UIO_ZEROCOPY
        xuio_t *xuio = NULL;
+#endif
 
        /*
         * NB: we could do this block-at-a-time, but it's nice
@@ -1231,6 +1136,7 @@ dmu_read_uio_dnode(dnode_t *dn, uio_t *uio, uint64_t size)
                bufoff = uio->uio_loffset - db->db_offset;
                tocpy = MIN(db->db_size - bufoff, size);
 
+#ifdef HAVE_UIO_ZEROCOPY
                if (xuio) {
                        dmu_buf_impl_t *dbi = (dmu_buf_impl_t *)db;
                        arc_buf_t *dbuf_abuf = dbi->db_buf;
@@ -1245,10 +1151,10 @@ dmu_read_uio_dnode(dnode_t *dn, uio_t *uio, uint64_t size)
                                XUIOSTAT_BUMP(xuiostat_rbuf_nocopy);
                        else
                                XUIOSTAT_BUMP(xuiostat_rbuf_copied);
-               } else {
+               } else
+#endif
                        err = uiomove((char *)db->db_data + bufoff, tocpy,
                            UIO_READ, uio);
-               }
                if (err)
                        break;
 
@@ -1426,7 +1332,7 @@ dmu_request_arcbuf(dmu_buf_t *handle, int size)
 {
        dmu_buf_impl_t *db = (dmu_buf_impl_t *)handle;
 
-       return (arc_loan_buf(db->db_objset->os_spa, size));
+       return (arc_loan_buf(db->db_objset->os_spa, B_FALSE, size));
 }
 
 /*
@@ -1436,7 +1342,7 @@ void
 dmu_return_arcbuf(arc_buf_t *buf)
 {
        arc_return_buf(buf, FTAG);
-       VERIFY(arc_buf_remove_ref(buf, FTAG));
+       arc_buf_destroy(buf, FTAG);
 }
 
 /*
@@ -1451,31 +1357,32 @@ dmu_assign_arcbuf(dmu_buf_t *handle, uint64_t offset, arc_buf_t *buf,
        dmu_buf_impl_t *dbuf = (dmu_buf_impl_t *)handle;
        dnode_t *dn;
        dmu_buf_impl_t *db;
-       uint32_t blksz = (uint32_t)arc_buf_size(buf);
+       uint32_t blksz = (uint32_t)arc_buf_lsize(buf);
        uint64_t blkid;
 
        DB_DNODE_ENTER(dbuf);
        dn = DB_DNODE(dbuf);
        rw_enter(&dn->dn_struct_rwlock, RW_READER);
-       blkid = dbuf_whichblock(dn, offset);
+       blkid = dbuf_whichblock(dn, 0, offset);
        VERIFY((db = dbuf_hold(dn, blkid, FTAG)) != NULL);
        rw_exit(&dn->dn_struct_rwlock);
        DB_DNODE_EXIT(dbuf);
 
        /*
         * We can only assign if the offset is aligned, the arc buf is the
-        * same size as the dbuf, and the dbuf is not metadata.  It
-        * can't be metadata because the loaned arc buf comes from the
-        * user-data kmem area.
+        * same size as the dbuf, and the dbuf is not metadata.
         */
-       if (offset == db->db.db_offset && blksz == db->db.db_size &&
-           DBUF_GET_BUFC_TYPE(db) == ARC_BUFC_DATA) {
+       if (offset == db->db.db_offset && blksz == db->db.db_size) {
                dbuf_assign_arcbuf(db, buf, tx);
                dbuf_rele(db, FTAG);
        } else {
                objset_t *os;
                uint64_t object;
 
+               /* compressed bufs must always be assignable to their dbuf */
+               ASSERT3U(arc_get_compression(buf), ==, ZIO_COMPRESS_OFF);
+               ASSERT(!(buf->b_flags & ARC_BUF_FLAG_COMPRESSED));
+
                DB_DNODE_ENTER(dbuf);
                dn = DB_DNODE(dbuf);
                os = dn->dn_objset;
@@ -1543,7 +1450,8 @@ dmu_sync_done(zio_t *zio, arc_buf_t *buf, void *varg)
 
                        ASSERT(BP_EQUAL(bp, bp_orig));
                        ASSERT(zio->io_prop.zp_compress != ZIO_COMPRESS_OFF);
-                       ASSERT(zio_checksum_table[chksum].ci_dedup);
+                       ASSERT(zio_checksum_table[chksum].ci_flags &
+                           ZCHECKSUM_FLAG_NOPWRITE);
                }
                dr->dt.dl.dr_overridden_by = *zio->io_bp;
                dr->dt.dl.dr_override_state = DR_OVERRIDDEN;
@@ -1624,10 +1532,11 @@ dmu_sync_late_arrival(zio_t *pio, objset_t *os, dmu_sync_cb_t *done, zgd_t *zgd,
        dsa->dsa_zgd = zgd;
        dsa->dsa_tx = tx;
 
-       zio_nowait(zio_write(pio, os->os_spa, dmu_tx_get_txg(tx), zgd->zgd_bp,
-           zgd->zgd_db->db_data, zgd->zgd_db->db_size, zp,
-           dmu_sync_late_arrival_ready, NULL, dmu_sync_late_arrival_done, dsa,
-           ZIO_PRIORITY_SYNC_WRITE, ZIO_FLAG_CANFAIL|ZIO_FLAG_FASTWRITE, zb));
+       zio_nowait(zio_write(pio, os->os_spa, dmu_tx_get_txg(tx),
+           zgd->zgd_bp, zgd->zgd_db->db_data, zgd->zgd_db->db_size,
+           zgd->zgd_db->db_size, zp, dmu_sync_late_arrival_ready, NULL,
+           NULL, dmu_sync_late_arrival_done, dsa, ZIO_PRIORITY_SYNC_WRITE,
+           ZIO_FLAG_CANFAIL, zb));
 
        return (0);
 }
@@ -1678,7 +1587,8 @@ dmu_sync(zio_t *pio, uint64_t txg, dmu_sync_cb_t *done, zgd_t *zgd)
 
        DB_DNODE_ENTER(db);
        dn = DB_DNODE(db);
-       dmu_write_policy(os, dn, db->db_level, WP_DMU_SYNC, &zp);
+       dmu_write_policy(os, dn, db->db_level, WP_DMU_SYNC,
+           ZIO_COMPRESS_INHERIT, &zp);
        DB_DNODE_EXIT(db);
 
        /*
@@ -1779,9 +1689,8 @@ dmu_sync(zio_t *pio, uint64_t txg, dmu_sync_cb_t *done, zgd_t *zgd)
 
        zio_nowait(arc_write(pio, os->os_spa, txg,
            bp, dr->dt.dl.dr_data, DBUF_IS_L2CACHEABLE(db),
-           DBUF_IS_L2COMPRESSIBLE(db), &zp, dmu_sync_ready,
-           NULL, dmu_sync_done, dsa, ZIO_PRIORITY_SYNC_WRITE,
-           ZIO_FLAG_CANFAIL, &zb));
+           &zp, dmu_sync_ready, NULL, NULL, dmu_sync_done, dsa,
+           ZIO_PRIORITY_SYNC_WRITE, ZIO_FLAG_CANFAIL, &zb));
 
        return (0);
 }
@@ -1849,7 +1758,8 @@ int zfs_mdcomp_disable = 0;
 int zfs_redundant_metadata_most_ditto_level = 2;
 
 void
-dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp)
+dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp,
+    enum zio_compress override_compress, zio_prop_t *zp)
 {
        dmu_object_type_t type = dn ? dn->dn_type : DMU_OT_OBJSET;
        boolean_t ismd = (level > 0 || DMU_OT_IS_METADATA(type) ||
@@ -1888,8 +1798,10 @@ dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp)
                 * as well.  Otherwise, the metadata checksum defaults
                 * to fletcher4.
                 */
-               if (zio_checksum_table[checksum].ci_correctable < 1 ||
-                   zio_checksum_table[checksum].ci_eck)
+               if (!(zio_checksum_table[checksum].ci_flags &
+                   ZCHECKSUM_FLAG_METADATA) ||
+                   (zio_checksum_table[checksum].ci_flags &
+                   ZCHECKSUM_FLAG_EMBEDDED))
                        checksum = ZIO_CHECKSUM_FLETCHER_4;
 
                if (os->os_redundant_metadata == ZFS_REDUNDANT_METADATA_ALL ||
@@ -1928,22 +1840,34 @@ dmu_write_policy(objset_t *os, dnode_t *dn, int level, int wp, zio_prop_t *zp)
                 */
                if (dedup_checksum != ZIO_CHECKSUM_OFF) {
                        dedup = (wp & WP_DMU_SYNC) ? B_FALSE : B_TRUE;
-                       if (!zio_checksum_table[checksum].ci_dedup)
+                       if (!(zio_checksum_table[checksum].ci_flags &
+                           ZCHECKSUM_FLAG_DEDUP))
                                dedup_verify = B_TRUE;
                }
 
                /*
-                * Enable nopwrite if we have a cryptographically secure
-                * checksum that has no known collisions (i.e. SHA-256)
-                * and compression is enabled.  We don't enable nopwrite if
-                * dedup is enabled as the two features are mutually exclusive.
+                * Enable nopwrite if we have secure enough checksum
+                * algorithm (see comment in zio_nop_write) and
+                * compression is enabled.  We don't enable nopwrite if
+                * dedup is enabled as the two features are mutually
+                * exclusive.
                 */
-               nopwrite = (!dedup && zio_checksum_table[checksum].ci_dedup &&
+               nopwrite = (!dedup && (zio_checksum_table[checksum].ci_flags &
+                   ZCHECKSUM_FLAG_NOPWRITE) &&
                    compress != ZIO_COMPRESS_OFF && zfs_nopwrite_enabled);
        }
 
        zp->zp_checksum = checksum;
-       zp->zp_compress = compress;
+
+       /*
+        * If we're writing a pre-compressed buffer, the compression type we use
+        * must match the data. If it hasn't been compressed yet, then we should
+        * use the value dictated by the policies above.
+        */
+       zp->zp_compress = override_compress != ZIO_COMPRESS_INHERIT
+           ? override_compress : compress;
+       ASSERT3U(zp->zp_compress, !=, ZIO_COMPRESS_INHERIT);
+
        zp->zp_type = (wp & WP_SPILL) ? dn->dn_bonustype : type;
        zp->zp_level = level;
        zp->zp_copies = MIN(copies, spa_max_replication(os->os_spa));
@@ -1995,6 +1919,7 @@ __dmu_object_info_from_dnode(dnode_t *dn, dmu_object_info_t *doi)
        doi->doi_type = dn->dn_type;
        doi->doi_bonus_type = dn->dn_bonustype;
        doi->doi_bonus_size = dn->dn_bonuslen;
+       doi->doi_dnodesize = dn->dn_num_slots << DNODE_SHIFT;
        doi->doi_indirection = dn->dn_nlevels;
        doi->doi_checksum = dn->dn_checksum;
        doi->doi_compress = dn->dn_compress;
@@ -2066,9 +1991,21 @@ dmu_object_size_from_db(dmu_buf_t *db_fake, uint32_t *blksize,
        dn = DB_DNODE(db);
 
        *blksize = dn->dn_datablksz;
-       /* add 1 for dnode space */
+       /* add in number of slots used for the dnode itself */
        *nblk512 = ((DN_USED_BYTES(dn->dn_phys) + SPA_MINBLOCKSIZE/2) >>
-           SPA_MINBLOCKSHIFT) + 1;
+           SPA_MINBLOCKSHIFT) + dn->dn_num_slots;
+       DB_DNODE_EXIT(db);
+}
+
+void
+dmu_object_dnsize_from_db(dmu_buf_t *db_fake, int *dnsize)
+{
+       dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+       dnode_t *dn;
+
+       DB_DNODE_ENTER(db);
+       dn = DB_DNODE(db);
+       *dnsize = dn->dn_num_slots << DNODE_SHIFT;
        DB_DNODE_EXIT(db);
 }
 
@@ -2125,11 +2062,11 @@ dmu_init(void)
        xuio_stat_init();
        dmu_objset_init();
        dnode_init();
-       dbuf_init();
        zfetch_init();
        dmu_tx_init();
        l2arc_init();
        arc_init();
+       dbuf_init();
 }
 
 void
@@ -2162,6 +2099,7 @@ EXPORT_SYMBOL(dmu_object_info);
 EXPORT_SYMBOL(dmu_object_info_from_dnode);
 EXPORT_SYMBOL(dmu_object_info_from_db);
 EXPORT_SYMBOL(dmu_object_size_from_db);
+EXPORT_SYMBOL(dmu_object_dnsize_from_db);
 EXPORT_SYMBOL(dmu_object_set_blocksize);
 EXPORT_SYMBOL(dmu_object_set_checksum);
 EXPORT_SYMBOL(dmu_object_set_compress);
index 91415d0d2dcb6aa8bc17f87aaf7e3b1e140016ac..982b96132cc8f497a73820a5798c95f1c8d665e5 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/dmu.h>
@@ -115,7 +115,7 @@ diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
        if (issig(JUSTLOOKING) && issig(FORREAL))
                return (SET_ERROR(EINTR));
 
-       if (zb->zb_object != DMU_META_DNODE_OBJECT)
+       if (bp == NULL || zb->zb_object != DMU_META_DNODE_OBJECT)
                return (0);
 
        if (BP_IS_HOLE(bp)) {
@@ -146,7 +146,7 @@ diff_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
                        if (err)
                                break;
                }
-               (void) arc_buf_remove_ref(abuf, &abuf);
+               arc_buf_destroy(abuf, &abuf);
                if (err)
                        return (err);
                /* Don't care about the data blocks */
index 177162f9365d5f60d33c4ac5a227eb0e825fdb66..e54043fc3e3a47a7ad78a2b65f8c5aeb3d64aa1a 100644 (file)
 #include <sys/dnode.h>
 #include <sys/zap.h>
 #include <sys/zfeature.h>
+#include <sys/dsl_dataset.h>
 
 uint64_t
 dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
+       return dmu_object_alloc_dnsize(os, ot, blocksize, bonustype, bonuslen,
+           0, tx);
+}
+
+uint64_t
+dmu_object_alloc_dnsize(objset_t *os, dmu_object_type_t ot, int blocksize,
+    dmu_object_type_t bonustype, int bonuslen, int dnodesize, dmu_tx_t *tx)
 {
        uint64_t object;
-       uint64_t L2_dnode_count = DNODES_PER_BLOCK <<
+       uint64_t L1_dnode_count = DNODES_PER_BLOCK <<
            (DMU_META_DNODE(os)->dn_indblkshift - SPA_BLKPTRSHIFT);
        dnode_t *dn = NULL;
-       int restarted = B_FALSE;
+       int dn_slots = dnodesize >> DNODE_SHIFT;
+       boolean_t restarted = B_FALSE;
+
+       if (dn_slots == 0) {
+               dn_slots = DNODE_MIN_SLOTS;
+       } else {
+               ASSERT3S(dn_slots, >=, DNODE_MIN_SLOTS);
+               ASSERT3S(dn_slots, <=, DNODE_MAX_SLOTS);
+       }
 
        mutex_enter(&os->os_obj_lock);
        for (;;) {
                object = os->os_obj_next;
                /*
-                * Each time we polish off an L2 bp worth of dnodes
-                * (2^13 objects), move to another L2 bp that's still
-                * reasonably sparse (at most 1/4 full).  Look from the
-                * beginning once, but after that keep looking from here.
-                * If we can't find one, just keep going from here.
+                * Each time we polish off a L1 bp worth of dnodes (2^12
+                * objects), move to another L1 bp that's still
+                * reasonably sparse (at most 1/4 full). Look from the
+                * beginning at most once per txg. If we still can't
+                * allocate from that L1 block, search for an empty L0
+                * block, which will quickly skip to the end of the
+                * metadnode if the no nearby L0 blocks are empty. This
+                * fallback avoids a pathology where full dnode blocks
+                * containing large dnodes appear sparse because they
+                * have a low blk_fill, leading to many failed
+                * allocation attempts. In the long term a better
+                * mechanism to search for sparse metadnode regions,
+                * such as spacemaps, could be implemented.
+                *
+                * os_scan_dnodes is set during txg sync if enough objects
+                * have been freed since the previous rescan to justify
+                * backfilling again.
                 *
                 * Note that dmu_traverse depends on the behavior that we use
                 * multiple blocks of the dnode object before going back to
@@ -57,16 +86,26 @@ dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
                 * that property or find another solution to the issues
                 * described in traverse_visitbp.
                 */
-               if (P2PHASE(object, L2_dnode_count) == 0) {
-                       uint64_t offset = restarted ? object << DNODE_SHIFT : 0;
-                       int error = dnode_next_offset(DMU_META_DNODE(os),
-                           DNODE_FIND_HOLE,
-                           &offset, 2, DNODES_PER_BLOCK >> 2, 0);
+               if (P2PHASE(object, L1_dnode_count) == 0) {
+                       uint64_t offset;
+                       uint64_t blkfill;
+                       int minlvl;
+                       int error;
+                       if (os->os_rescan_dnodes) {
+                               offset = 0;
+                               os->os_rescan_dnodes = B_FALSE;
+                       } else {
+                               offset = object << DNODE_SHIFT;
+                       }
+                       blkfill = restarted ? 1 : DNODES_PER_BLOCK >> 2;
+                       minlvl = restarted ? 1 : 2;
                        restarted = B_TRUE;
+                       error = dnode_next_offset(DMU_META_DNODE(os),
+                           DNODE_FIND_HOLE, &offset, minlvl, blkfill, 0);
                        if (error == 0)
                                object = offset >> DNODE_SHIFT;
                }
-               os->os_obj_next = ++object;
+               os->os_obj_next = object + dn_slots;
 
                /*
                 * XXX We should check for an i/o error here and return
@@ -74,16 +113,22 @@ dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
                 * dmu_tx_assign(), but there is currently no mechanism
                 * to do so.
                 */
-               (void) dnode_hold_impl(os, object, DNODE_MUST_BE_FREE,
+               (void) dnode_hold_impl(os, object, DNODE_MUST_BE_FREE, dn_slots,
                    FTAG, &dn);
                if (dn)
                        break;
 
                if (dmu_object_next(os, &object, B_TRUE, 0) == 0)
-                       os->os_obj_next = object - 1;
+                       os->os_obj_next = object;
+               else
+                       /*
+                        * Skip to next known valid starting point for a dnode.
+                        */
+                       os->os_obj_next = P2ROUNDUP(object + 1,
+                           DNODES_PER_BLOCK);
        }
 
-       dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
+       dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, dn_slots, tx);
        dnode_rele(dn, FTAG);
 
        mutex_exit(&os->os_obj_lock);
@@ -95,17 +140,34 @@ dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
 int
 dmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot,
     int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
+       return (dmu_object_claim_dnsize(os, object, ot, blocksize, bonustype,
+           bonuslen, 0, tx));
+}
+
+int
+dmu_object_claim_dnsize(objset_t *os, uint64_t object, dmu_object_type_t ot,
+    int blocksize, dmu_object_type_t bonustype, int bonuslen,
+    int dnodesize, dmu_tx_t *tx)
 {
        dnode_t *dn;
+       int dn_slots = dnodesize >> DNODE_SHIFT;
        int err;
 
+       if (dn_slots == 0)
+               dn_slots = DNODE_MIN_SLOTS;
+       ASSERT3S(dn_slots, >=, DNODE_MIN_SLOTS);
+       ASSERT3S(dn_slots, <=, DNODE_MAX_SLOTS);
+
        if (object == DMU_META_DNODE_OBJECT && !dmu_tx_private_ok(tx))
                return (SET_ERROR(EBADF));
 
-       err = dnode_hold_impl(os, object, DNODE_MUST_BE_FREE, FTAG, &dn);
+       err = dnode_hold_impl(os, object, DNODE_MUST_BE_FREE, dn_slots,
+           FTAG, &dn);
        if (err)
                return (err);
-       dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, tx);
+
+       dnode_allocate(dn, ot, blocksize, 0, bonustype, bonuslen, dn_slots, tx);
        dnode_rele(dn, FTAG);
 
        dmu_tx_add_new_object(tx, os, object);
@@ -115,24 +177,35 @@ dmu_object_claim(objset_t *os, uint64_t object, dmu_object_type_t ot,
 int
 dmu_object_reclaim(objset_t *os, uint64_t object, dmu_object_type_t ot,
     int blocksize, dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
+       return (dmu_object_reclaim_dnsize(os, object, ot, blocksize, bonustype,
+           bonuslen, 0, tx));
+}
+
+int
+dmu_object_reclaim_dnsize(objset_t *os, uint64_t object, dmu_object_type_t ot,
+    int blocksize, dmu_object_type_t bonustype, int bonuslen, int dnodesize,
+    dmu_tx_t *tx)
 {
        dnode_t *dn;
+       int dn_slots = dnodesize >> DNODE_SHIFT;
        int err;
 
        if (object == DMU_META_DNODE_OBJECT)
                return (SET_ERROR(EBADF));
 
-       err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
+       err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED, 0,
            FTAG, &dn);
        if (err)
                return (err);
 
-       dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, tx);
+       dnode_reallocate(dn, ot, blocksize, bonustype, bonuslen, dn_slots, tx);
 
        dnode_rele(dn, FTAG);
        return (err);
 }
 
+
 int
 dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
 {
@@ -141,7 +214,7 @@ dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
 
        ASSERT(object != DMU_META_DNODE_OBJECT || dmu_tx_private_ok(tx));
 
-       err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED,
+       err = dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED, 0,
            FTAG, &dn);
        if (err)
                return (err);
@@ -154,12 +227,38 @@ dmu_object_free(objset_t *os, uint64_t object, dmu_tx_t *tx)
        return (0);
 }
 
+/*
+ * Return (in *objectp) the next object which is allocated (or a hole)
+ * after *object, taking into account only objects that may have been modified
+ * after the specified txg.
+ */
 int
 dmu_object_next(objset_t *os, uint64_t *objectp, boolean_t hole, uint64_t txg)
 {
-       uint64_t offset = (*objectp + 1) << DNODE_SHIFT;
+       uint64_t offset;
+       dmu_object_info_t doi;
+       struct dsl_dataset *ds = os->os_dsl_dataset;
+       int dnodesize;
        int error;
 
+       /*
+        * Avoid expensive dnode hold if this dataset doesn't use large dnodes.
+        */
+       if (ds && ds->ds_feature_inuse[SPA_FEATURE_LARGE_DNODE]) {
+               error = dmu_object_info(os, *objectp, &doi);
+               if (error && !(error == EINVAL && *objectp == 0))
+                       return (SET_ERROR(error));
+               else
+                       dnodesize = doi.doi_dnodesize;
+       } else {
+               dnodesize = DNODE_MIN_SIZE;
+       }
+
+       if (*objectp == 0)
+               offset = 1 << DNODE_SHIFT;
+       else
+               offset = (*objectp << DNODE_SHIFT) + dnodesize;
+
        error = dnode_next_offset(DMU_META_DNODE(os),
            (hole ? DNODE_FIND_HOLE : 0), &offset, 0, DNODES_PER_BLOCK, txg);
 
@@ -221,8 +320,11 @@ dmu_object_free_zapified(objset_t *mos, uint64_t object, dmu_tx_t *tx)
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
 EXPORT_SYMBOL(dmu_object_alloc);
+EXPORT_SYMBOL(dmu_object_alloc_dnsize);
 EXPORT_SYMBOL(dmu_object_claim);
+EXPORT_SYMBOL(dmu_object_claim_dnsize);
 EXPORT_SYMBOL(dmu_object_reclaim);
+EXPORT_SYMBOL(dmu_object_reclaim_dnsize);
 EXPORT_SYMBOL(dmu_object_free);
 EXPORT_SYMBOL(dmu_object_next);
 EXPORT_SYMBOL(dmu_object_zapify);
index f2d492ebf0c3e702b9bf3bc6d7cd27d25d066d7e..ac60008a3a8029706763cbe7f7799e686a3a6dd0 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
@@ -31,6 +31,7 @@
 
 /* Portions Copyright 2010 Robert Milkowski */
 
+#include <sys/zfeature.h>
 #include <sys/cred.h>
 #include <sys/zfs_context.h>
 #include <sys/dmu_objset.h>
@@ -52,6 +53,8 @@
 #include <sys/zfs_onexit.h>
 #include <sys/dsl_destroy.h>
 #include <sys/vdev.h>
+#include <sys/policy.h>
+#include <sys/spa_impl.h>
 
 /*
  * Needed to close a window in dnode_move() that allows the objset to be freed
@@ -67,8 +70,18 @@ krwlock_t os_lock;
  */
 int dmu_find_threads = 0;
 
+/*
+ * Backfill lower metadnode objects after this many have been freed.
+ * Backfilling negatively impacts object creation rates, so only do it
+ * if there are enough holes to fill.
+ */
+int dmu_rescan_dnode_threshold = 1 << DN_MAX_INDBLKSHIFT;
+
 static void dmu_objset_find_dp_cb(void *arg);
 
+static void dmu_objset_upgrade(objset_t *os, dmu_objset_upgrade_cb_t cb);
+static void dmu_objset_upgrade_stop(objset_t *os);
+
 void
 dmu_objset_init(void)
 {
@@ -130,6 +143,12 @@ dmu_objset_id(objset_t *os)
        return (ds ? ds->ds_object : 0);
 }
 
+uint64_t
+dmu_objset_dnodesize(objset_t *os)
+{
+       return (os->os_dnodesize);
+}
+
 zfs_sync_type_t
 dmu_objset_syncprop(objset_t *os)
 {
@@ -259,6 +278,34 @@ redundant_metadata_changed_cb(void *arg, uint64_t newval)
        os->os_redundant_metadata = newval;
 }
 
+static void
+dnodesize_changed_cb(void *arg, uint64_t newval)
+{
+       objset_t *os = arg;
+
+       switch (newval) {
+       case ZFS_DNSIZE_LEGACY:
+               os->os_dnodesize = DNODE_MIN_SIZE;
+               break;
+       case ZFS_DNSIZE_AUTO:
+               /*
+                * Choose a dnode size that will work well for most
+                * workloads if the user specified "auto". Future code
+                * improvements could dynamically select a dnode size
+                * based on observed workload patterns.
+                */
+               os->os_dnodesize = DNODE_MIN_SIZE * 2;
+               break;
+       case ZFS_DNSIZE_1K:
+       case ZFS_DNSIZE_2K:
+       case ZFS_DNSIZE_4K:
+       case ZFS_DNSIZE_8K:
+       case ZFS_DNSIZE_16K:
+               os->os_dnodesize = newval;
+               break;
+       }
+}
+
 static void
 logbias_changed_cb(void *arg, uint64_t newval)
 {
@@ -316,8 +363,6 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
 
                if (DMU_OS_IS_L2CACHEABLE(os))
                        aflags |= ARC_FLAG_L2CACHE;
-               if (DMU_OS_IS_L2COMPRESSIBLE(os))
-                       aflags |= ARC_FLAG_L2COMPRESS;
 
                dprintf_bp(os->os_rootbp, "reading %s", "");
                err = arc_read(NULL, spa, os->os_rootbp,
@@ -334,14 +379,12 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
                /* Increase the blocksize if we are permitted. */
                if (spa_version(spa) >= SPA_VERSION_USERSPACE &&
                    arc_buf_size(os->os_phys_buf) < sizeof (objset_phys_t)) {
-                       arc_buf_t *buf = arc_buf_alloc(spa,
-                           sizeof (objset_phys_t), &os->os_phys_buf,
-                           ARC_BUFC_METADATA);
+                       arc_buf_t *buf = arc_alloc_buf(spa, &os->os_phys_buf,
+                           ARC_BUFC_METADATA, sizeof (objset_phys_t));
                        bzero(buf->b_data, sizeof (objset_phys_t));
                        bcopy(os->os_phys_buf->b_data, buf->b_data,
                            arc_buf_size(os->os_phys_buf));
-                       (void) arc_buf_remove_ref(os->os_phys_buf,
-                           &os->os_phys_buf);
+                       arc_buf_destroy(os->os_phys_buf, &os->os_phys_buf);
                        os->os_phys_buf = buf;
                }
 
@@ -350,8 +393,8 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
        } else {
                int size = spa_version(spa) >= SPA_VERSION_USERSPACE ?
                    sizeof (objset_phys_t) : OBJSET_OLD_PHYS_SIZE;
-               os->os_phys_buf = arc_buf_alloc(spa, size,
-                   &os->os_phys_buf, ARC_BUFC_METADATA);
+               os->os_phys_buf = arc_alloc_buf(spa, &os->os_phys_buf,
+                   ARC_BUFC_METADATA, size);
                os->os_phys = os->os_phys_buf->b_data;
                bzero(os->os_phys, size);
        }
@@ -363,6 +406,17 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
         * checksum/compression/copies.
         */
        if (ds != NULL) {
+               boolean_t needlock = B_FALSE;
+
+               /*
+                * Note: it's valid to open the objset if the dataset is
+                * long-held, in which case the pool_config lock will not
+                * be held.
+                */
+               if (!dsl_pool_config_held(dmu_objset_pool(os))) {
+                       needlock = B_TRUE;
+                       dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
+               }
                err = dsl_prop_register(ds,
                    zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE),
                    primary_cache_changed_cb, os);
@@ -413,10 +467,16 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
                                    zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
                                    recordsize_changed_cb, os);
                        }
+                       if (err == 0) {
+                               err = dsl_prop_register(ds,
+                                   zfs_prop_to_name(ZFS_PROP_DNODESIZE),
+                                   dnodesize_changed_cb, os);
+                       }
                }
+               if (needlock)
+                       dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
                if (err != 0) {
-                       VERIFY(arc_buf_remove_ref(os->os_phys_buf,
-                           &os->os_phys_buf));
+                       arc_buf_destroy(os->os_phys_buf, &os->os_phys_buf);
                        kmem_free(os, sizeof (objset_t));
                        return (err);
                }
@@ -431,6 +491,7 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
                os->os_sync = ZFS_SYNC_STANDARD;
                os->os_primary_cache = ZFS_CACHE_ALL;
                os->os_secondary_cache = ZFS_CACHE_ALL;
+               os->os_dnodesize = DNODE_MIN_SIZE;
        }
 
        if (ds == NULL || !ds->ds_is_snapshot)
@@ -463,6 +524,8 @@ dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
                    DMU_GROUPUSED_OBJECT, &os->os_groupused_dnode);
        }
 
+       mutex_init(&os->os_upgrade_lock, NULL, MUTEX_DEFAULT, NULL);
+
        *osp = os;
        return (0);
 }
@@ -472,6 +535,13 @@ dmu_objset_from_ds(dsl_dataset_t *ds, objset_t **osp)
 {
        int err = 0;
 
+       /*
+        * We shouldn't be doing anything with dsl_dataset_t's unless the
+        * pool_config lock is held, or the dataset is long-held.
+        */
+       ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool) ||
+           dsl_dataset_long_held(ds));
+
        mutex_enter(&ds->ds_opening_lock);
        if (ds->ds_objset == NULL) {
                objset_t *os;
@@ -562,6 +632,9 @@ dmu_objset_own(const char *name, dmu_objset_type_t type,
        err = dmu_objset_own_impl(ds, type, readonly, tag, osp);
        dsl_pool_rele(dp, FTAG);
 
+       if (err == 0 && dmu_objset_userobjspace_upgradable(*osp))
+               dmu_objset_userobjspace_upgrade(*osp);
+
        return (err);
 }
 
@@ -603,7 +676,7 @@ dmu_objset_refresh_ownership(objset_t *os, void *tag)
 {
        dsl_pool_t *dp;
        dsl_dataset_t *ds, *newds;
-       char name[MAXNAMELEN];
+       char name[ZFS_MAX_DATASET_NAME_LEN];
 
        ds = os->os_dsl_dataset;
        VERIFY3P(ds, !=, NULL);
@@ -622,6 +695,10 @@ dmu_objset_refresh_ownership(objset_t *os, void *tag)
 void
 dmu_objset_disown(objset_t *os, void *tag)
 {
+       /*
+        * Stop upgrading thread
+        */
+       dmu_objset_upgrade_stop(os);
        dsl_dataset_disown(os->os_dsl_dataset, tag);
 }
 
@@ -689,40 +766,8 @@ dmu_objset_evict(objset_t *os)
        for (t = 0; t < TXG_SIZE; t++)
                ASSERT(!dmu_objset_is_dirty(os, t));
 
-       if (ds) {
-               if (!ds->ds_is_snapshot) {
-                       VERIFY0(dsl_prop_unregister(ds,
-                           zfs_prop_to_name(ZFS_PROP_CHECKSUM),
-                           checksum_changed_cb, os));
-                       VERIFY0(dsl_prop_unregister(ds,
-                           zfs_prop_to_name(ZFS_PROP_COMPRESSION),
-                           compression_changed_cb, os));
-                       VERIFY0(dsl_prop_unregister(ds,
-                           zfs_prop_to_name(ZFS_PROP_COPIES),
-                           copies_changed_cb, os));
-                       VERIFY0(dsl_prop_unregister(ds,
-                           zfs_prop_to_name(ZFS_PROP_DEDUP),
-                           dedup_changed_cb, os));
-                       VERIFY0(dsl_prop_unregister(ds,
-                           zfs_prop_to_name(ZFS_PROP_LOGBIAS),
-                           logbias_changed_cb, os));
-                       VERIFY0(dsl_prop_unregister(ds,
-                           zfs_prop_to_name(ZFS_PROP_SYNC),
-                           sync_changed_cb, os));
-                       VERIFY0(dsl_prop_unregister(ds,
-                           zfs_prop_to_name(ZFS_PROP_REDUNDANT_METADATA),
-                           redundant_metadata_changed_cb, os));
-                       VERIFY0(dsl_prop_unregister(ds,
-                           zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
-                           recordsize_changed_cb, os));
-               }
-               VERIFY0(dsl_prop_unregister(ds,
-                   zfs_prop_to_name(ZFS_PROP_PRIMARYCACHE),
-                   primary_cache_changed_cb, os));
-               VERIFY0(dsl_prop_unregister(ds,
-                   zfs_prop_to_name(ZFS_PROP_SECONDARYCACHE),
-                   secondary_cache_changed_cb, os));
-       }
+       if (ds)
+               dsl_prop_unregister_all(ds, os);
 
        if (os->os_sa)
                sa_tear_down(os);
@@ -751,7 +796,7 @@ dmu_objset_evict_done(objset_t *os)
        }
        zil_free(os->os_zil);
 
-       VERIFY(arc_buf_remove_ref(os->os_phys_buf, &os->os_phys_buf));
+       arc_buf_destroy(os->os_phys_buf, &os->os_phys_buf);
 
        /*
         * This is a barrier to prevent the objset from going away in
@@ -792,8 +837,8 @@ dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
 
        mdn = DMU_META_DNODE(os);
 
-       dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT,
-           DN_MAX_INDBLKSHIFT, DMU_OT_NONE, 0, tx);
+       dnode_allocate(mdn, DMU_OT_DNODE, DNODE_BLOCK_SIZE, DN_MAX_INDBLKSHIFT,
+           DMU_OT_NONE, 0, DNODE_MIN_SLOTS, tx);
 
        /*
         * We don't want to have to increase the meta-dnode's nlevels
@@ -828,6 +873,12 @@ dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
        os->os_phys->os_type = type;
        if (dmu_objset_userused_enabled(os)) {
                os->os_phys->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
+               if (dmu_objset_userobjused_enabled(os)) {
+                       ds->ds_feature_activation_needed[
+                           SPA_FEATURE_USEROBJ_ACCOUNTING] = B_TRUE;
+                       os->os_phys->os_flags |=
+                           OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
+               }
                os->os_flags = os->os_phys->os_flags;
        }
 
@@ -859,6 +910,9 @@ dmu_objset_create_check(void *arg, dmu_tx_t *tx)
        if (strchr(doca->doca_name, '@') != NULL)
                return (SET_ERROR(EINVAL));
 
+       if (strlen(doca->doca_name) >= ZFS_MAX_DATASET_NAME_LEN)
+               return (SET_ERROR(ENAMETOOLONG));
+
        error = dsl_dir_hold(dp, doca->doca_name, FTAG, &pdd, &tail);
        if (error != 0)
                return (error);
@@ -945,6 +999,9 @@ dmu_objset_clone_check(void *arg, dmu_tx_t *tx)
        if (strchr(doca->doca_clone, '@') != NULL)
                return (SET_ERROR(EINVAL));
 
+       if (strlen(doca->doca_clone) >= ZFS_MAX_DATASET_NAME_LEN)
+               return (SET_ERROR(ENAMETOOLONG));
+
        error = dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail);
        if (error != 0)
                return (error);
@@ -984,7 +1041,7 @@ dmu_objset_clone_sync(void *arg, dmu_tx_t *tx)
        const char *tail;
        dsl_dataset_t *origin, *ds;
        uint64_t obj;
-       char namebuf[MAXNAMELEN];
+       char namebuf[ZFS_MAX_DATASET_NAME_LEN];
 
        VERIFY0(dsl_dir_hold(dp, doca->doca_clone, FTAG, &pdd, &tail));
        VERIFY0(dsl_dataset_hold(dp, doca->doca_origin, FTAG, &origin));
@@ -1030,6 +1087,60 @@ dmu_objset_snapshot_one(const char *fsname, const char *snapname)
        return (err);
 }
 
+static void
+dmu_objset_upgrade_task_cb(void *data)
+{
+       objset_t *os = data;
+
+       mutex_enter(&os->os_upgrade_lock);
+       os->os_upgrade_status = EINTR;
+       if (!os->os_upgrade_exit) {
+               mutex_exit(&os->os_upgrade_lock);
+
+               os->os_upgrade_status = os->os_upgrade_cb(os);
+               mutex_enter(&os->os_upgrade_lock);
+       }
+       os->os_upgrade_exit = B_TRUE;
+       os->os_upgrade_id = 0;
+       mutex_exit(&os->os_upgrade_lock);
+}
+
+static void
+dmu_objset_upgrade(objset_t *os, dmu_objset_upgrade_cb_t cb)
+{
+       if (os->os_upgrade_id != 0)
+               return;
+
+       mutex_enter(&os->os_upgrade_lock);
+       if (os->os_upgrade_id == 0 && os->os_upgrade_status == 0) {
+               os->os_upgrade_exit = B_FALSE;
+               os->os_upgrade_cb = cb;
+               os->os_upgrade_id = taskq_dispatch(
+                   os->os_spa->spa_upgrade_taskq,
+                   dmu_objset_upgrade_task_cb, os, TQ_SLEEP);
+               if (os->os_upgrade_id == 0)
+                       os->os_upgrade_status = ENOMEM;
+       }
+       mutex_exit(&os->os_upgrade_lock);
+}
+
+static void
+dmu_objset_upgrade_stop(objset_t *os)
+{
+       mutex_enter(&os->os_upgrade_lock);
+       os->os_upgrade_exit = B_TRUE;
+       if (os->os_upgrade_id != 0) {
+               taskqid_t id = os->os_upgrade_id;
+
+               os->os_upgrade_id = 0;
+               mutex_exit(&os->os_upgrade_lock);
+
+               taskq_cancel_id(os->os_spa->spa_upgrade_taskq, id);
+       } else {
+               mutex_exit(&os->os_upgrade_lock);
+       }
+}
+
 static void
 dmu_objset_sync_dnodes(list_t *list, list_t *newlist, dmu_tx_t *tx)
 {
@@ -1137,13 +1248,12 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
            ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
        arc_release(os->os_phys_buf, &os->os_phys_buf);
 
-       dmu_write_policy(os, NULL, 0, 0, &zp);
+       dmu_write_policy(os, NULL, 0, 0, ZIO_COMPRESS_INHERIT, &zp);
 
        zio = arc_write(pio, os->os_spa, tx->tx_txg,
            os->os_rootbp, os->os_phys_buf, DMU_OS_IS_L2CACHEABLE(os),
-           DMU_OS_IS_L2COMPRESSIBLE(os), &zp, dmu_objset_write_ready,
-           NULL, dmu_objset_write_done, os, ZIO_PRIORITY_ASYNC_WRITE,
-           ZIO_FLAG_MUSTSUCCEED, &zb);
+           &zp, dmu_objset_write_ready, NULL, NULL, dmu_objset_write_done,
+           os, ZIO_PRIORITY_ASYNC_WRITE, ZIO_FLAG_MUSTSUCCEED, &zb);
 
        /*
         * Sync special dnodes - the parent IO for the sync is the root block
@@ -1183,6 +1293,13 @@ dmu_objset_sync(objset_t *os, zio_t *pio, dmu_tx_t *tx)
                if (dr->dr_zio)
                        zio_nowait(dr->dr_zio);
        }
+
+       /* Enable dnode backfill if enough objects have been freed. */
+       if (os->os_freed_dnodes >= dmu_rescan_dnode_threshold) {
+               os->os_rescan_dnodes = B_TRUE;
+               os->os_freed_dnodes = 0;
+       }
+
        /*
         * Free intent log blocks up to this tx.
         */
@@ -1214,18 +1331,123 @@ dmu_objset_userused_enabled(objset_t *os)
            DMU_USERUSED_DNODE(os) != NULL);
 }
 
+boolean_t
+dmu_objset_userobjused_enabled(objset_t *os)
+{
+       return (dmu_objset_userused_enabled(os) &&
+           spa_feature_is_enabled(os->os_spa, SPA_FEATURE_USEROBJ_ACCOUNTING));
+}
+
+typedef struct userquota_node {
+       /* must be in the first filed, see userquota_update_cache() */
+       char            uqn_id[20 + DMU_OBJACCT_PREFIX_LEN];
+       int64_t         uqn_delta;
+       avl_node_t      uqn_node;
+} userquota_node_t;
+
+typedef struct userquota_cache {
+       avl_tree_t uqc_user_deltas;
+       avl_tree_t uqc_group_deltas;
+} userquota_cache_t;
+
+static int
+userquota_compare(const void *l, const void *r)
+{
+       const userquota_node_t *luqn = l;
+       const userquota_node_t *ruqn = r;
+       int rv;
+
+       /*
+        * NB: can only access uqn_id because userquota_update_cache() doesn't
+        * pass in an entire userquota_node_t.
+        */
+       rv = strcmp(luqn->uqn_id, ruqn->uqn_id);
+
+       return (AVL_ISIGN(rv));
+}
+
+static void
+do_userquota_cacheflush(objset_t *os, userquota_cache_t *cache, dmu_tx_t *tx)
+{
+       void *cookie;
+       userquota_node_t *uqn;
+
+       ASSERT(dmu_tx_is_syncing(tx));
+
+       cookie = NULL;
+       while ((uqn = avl_destroy_nodes(&cache->uqc_user_deltas,
+           &cookie)) != NULL) {
+               VERIFY0(zap_increment(os, DMU_USERUSED_OBJECT,
+                   uqn->uqn_id, uqn->uqn_delta, tx));
+               kmem_free(uqn, sizeof (*uqn));
+       }
+       avl_destroy(&cache->uqc_user_deltas);
+
+       cookie = NULL;
+       while ((uqn = avl_destroy_nodes(&cache->uqc_group_deltas,
+           &cookie)) != NULL) {
+               VERIFY0(zap_increment(os, DMU_GROUPUSED_OBJECT,
+                   uqn->uqn_id, uqn->uqn_delta, tx));
+               kmem_free(uqn, sizeof (*uqn));
+       }
+       avl_destroy(&cache->uqc_group_deltas);
+}
+
 static void
-do_userquota_update(objset_t *os, uint64_t used, uint64_t flags,
-    uint64_t user, uint64_t group, boolean_t subtract, dmu_tx_t *tx)
+userquota_update_cache(avl_tree_t *avl, const char *id, int64_t delta)
+{
+       userquota_node_t *uqn;
+       avl_index_t idx;
+
+       ASSERT(strlen(id) < sizeof (uqn->uqn_id));
+       /*
+        * Use id directly for searching because uqn_id is the first field of
+        * userquota_node_t and fields after uqn_id won't be accessed in
+        * avl_find().
+        */
+       uqn = avl_find(avl, (const void *)id, &idx);
+       if (uqn == NULL) {
+               uqn = kmem_zalloc(sizeof (*uqn), KM_SLEEP);
+               strlcpy(uqn->uqn_id, id, sizeof (uqn->uqn_id));
+               avl_insert(avl, uqn, idx);
+       }
+       uqn->uqn_delta += delta;
+}
+
+static void
+do_userquota_update(userquota_cache_t *cache, uint64_t used, uint64_t flags,
+    uint64_t user, uint64_t group, boolean_t subtract)
 {
        if ((flags & DNODE_FLAG_USERUSED_ACCOUNTED)) {
-               int64_t delta = DNODE_SIZE + used;
+               int64_t delta = DNODE_MIN_SIZE + used;
+               char name[20];
+
                if (subtract)
                        delta = -delta;
-               VERIFY3U(0, ==, zap_increment_int(os, DMU_USERUSED_OBJECT,
-                   user, delta, tx));
-               VERIFY3U(0, ==, zap_increment_int(os, DMU_GROUPUSED_OBJECT,
-                   group, delta, tx));
+
+               (void) sprintf(name, "%llx", (longlong_t)user);
+               userquota_update_cache(&cache->uqc_user_deltas, name, delta);
+
+               (void) sprintf(name, "%llx", (longlong_t)group);
+               userquota_update_cache(&cache->uqc_group_deltas, name, delta);
+       }
+}
+
+static void
+do_userobjquota_update(userquota_cache_t *cache, uint64_t flags,
+    uint64_t user, uint64_t group, boolean_t subtract)
+{
+       if (flags & DNODE_FLAG_USEROBJUSED_ACCOUNTED) {
+               char name[20 + DMU_OBJACCT_PREFIX_LEN];
+               int delta = subtract ? -1 : 1;
+
+               (void) snprintf(name, sizeof (name), DMU_OBJACCT_PREFIX "%llx",
+                   (longlong_t)user);
+               userquota_update_cache(&cache->uqc_user_deltas, name, delta);
+
+               (void) snprintf(name, sizeof (name), DMU_OBJACCT_PREFIX "%llx",
+                   (longlong_t)group);
+               userquota_update_cache(&cache->uqc_group_deltas, name, delta);
        }
 }
 
@@ -1234,9 +1456,15 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx)
 {
        dnode_t *dn;
        list_t *list = &os->os_synced_dnodes;
+       userquota_cache_t cache = { { 0 } };
 
        ASSERT(list_head(list) == NULL || dmu_objset_userused_enabled(os));
 
+       avl_create(&cache.uqc_user_deltas, userquota_compare,
+           sizeof (userquota_node_t), offsetof(userquota_node_t, uqn_node));
+       avl_create(&cache.uqc_group_deltas, userquota_compare,
+           sizeof (userquota_node_t), offsetof(userquota_node_t, uqn_node));
+
        while ((dn = list_head(list))) {
                int flags;
                ASSERT(!DMU_OBJECT_IS_SPECIAL(dn->dn_object));
@@ -1246,32 +1474,27 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx)
 
                /* Allocate the user/groupused objects if necessary. */
                if (DMU_USERUSED_DNODE(os)->dn_type == DMU_OT_NONE) {
-                       VERIFY(0 == zap_create_claim(os,
-                           DMU_USERUSED_OBJECT,
+                       VERIFY0(zap_create_claim(os, DMU_USERUSED_OBJECT,
                            DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx));
-                       VERIFY(0 == zap_create_claim(os,
-                           DMU_GROUPUSED_OBJECT,
+                       VERIFY0(zap_create_claim(os, DMU_GROUPUSED_OBJECT,
                            DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx));
                }
 
-               /*
-                * We intentionally modify the zap object even if the
-                * net delta is zero.  Otherwise
-                * the block of the zap obj could be shared between
-                * datasets but need to be different between them after
-                * a bprewrite.
-                */
-
                flags = dn->dn_id_flags;
                ASSERT(flags);
                if (flags & DN_ID_OLD_EXIST)  {
-                       do_userquota_update(os, dn->dn_oldused, dn->dn_oldflags,
-                           dn->dn_olduid, dn->dn_oldgid, B_TRUE, tx);
+                       do_userquota_update(&cache,
+                           dn->dn_oldused, dn->dn_oldflags,
+                           dn->dn_olduid, dn->dn_oldgid, B_TRUE);
+                       do_userobjquota_update(&cache, dn->dn_oldflags,
+                           dn->dn_olduid, dn->dn_oldgid, B_TRUE);
                }
                if (flags & DN_ID_NEW_EXIST) {
-                       do_userquota_update(os, DN_USED_BYTES(dn->dn_phys),
-                           dn->dn_phys->dn_flags,  dn->dn_newuid,
-                           dn->dn_newgid, B_FALSE, tx);
+                       do_userquota_update(&cache,
+                           DN_USED_BYTES(dn->dn_phys), dn->dn_phys->dn_flags,
+                           dn->dn_newuid, dn->dn_newgid, B_FALSE);
+                       do_userobjquota_update(&cache, dn->dn_phys->dn_flags,
+                           dn->dn_newuid, dn->dn_newgid, B_FALSE);
                }
 
                mutex_enter(&dn->dn_mtx);
@@ -1292,6 +1515,7 @@ dmu_objset_do_userquota_updates(objset_t *os, dmu_tx_t *tx)
                list_remove(list, dn);
                dnode_rele(dn, list);
        }
+       do_userquota_cacheflush(os, &cache, tx);
 }
 
 /*
@@ -1443,19 +1667,19 @@ dmu_objset_userspace_present(objset_t *os)
            OBJSET_FLAG_USERACCOUNTING_COMPLETE);
 }
 
-int
-dmu_objset_userspace_upgrade(objset_t *os)
+boolean_t
+dmu_objset_userobjspace_present(objset_t *os)
+{
+       return (os->os_phys->os_flags &
+           OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE);
+}
+
+static int
+dmu_objset_space_upgrade(objset_t *os)
 {
        uint64_t obj;
        int err = 0;
 
-       if (dmu_objset_userspace_present(os))
-               return (0);
-       if (!dmu_objset_userused_enabled(os))
-               return (SET_ERROR(ENOTSUP));
-       if (dmu_objset_is_snapshot(os))
-               return (SET_ERROR(EINVAL));
-
        /*
         * We simply need to mark every object dirty, so that it will be
         * synced out and now accounted.  If this is called
@@ -1469,6 +1693,13 @@ dmu_objset_userspace_upgrade(objset_t *os)
                dmu_buf_t *db;
                int objerr;
 
+               mutex_enter(&os->os_upgrade_lock);
+               if (os->os_upgrade_exit)
+                       err = SET_ERROR(EINTR);
+               mutex_exit(&os->os_upgrade_lock);
+               if (err != 0)
+                       return (err);
+
                if (issig(JUSTLOOKING) && issig(FORREAL))
                        return (SET_ERROR(EINTR));
 
@@ -1486,12 +1717,60 @@ dmu_objset_userspace_upgrade(objset_t *os)
                dmu_buf_rele(db, FTAG);
                dmu_tx_commit(tx);
        }
+       return (0);
+}
+
+int
+dmu_objset_userspace_upgrade(objset_t *os)
+{
+       int err = 0;
+
+       if (dmu_objset_userspace_present(os))
+               return (0);
+       if (dmu_objset_is_snapshot(os))
+               return (SET_ERROR(EINVAL));
+       if (!dmu_objset_userused_enabled(os))
+               return (SET_ERROR(ENOTSUP));
+
+       err = dmu_objset_space_upgrade(os);
+       if (err)
+               return (err);
 
        os->os_flags |= OBJSET_FLAG_USERACCOUNTING_COMPLETE;
        txg_wait_synced(dmu_objset_pool(os), 0);
        return (0);
 }
 
+static int
+dmu_objset_userobjspace_upgrade_cb(objset_t *os)
+{
+       int err = 0;
+
+       if (dmu_objset_userobjspace_present(os))
+               return (0);
+       if (dmu_objset_is_snapshot(os))
+               return (SET_ERROR(EINVAL));
+       if (!dmu_objset_userobjused_enabled(os))
+               return (SET_ERROR(ENOTSUP));
+
+       dmu_objset_ds(os)->ds_feature_activation_needed[
+           SPA_FEATURE_USEROBJ_ACCOUNTING] = B_TRUE;
+
+       err = dmu_objset_space_upgrade(os);
+       if (err)
+               return (err);
+
+       os->os_flags |= OBJSET_FLAG_USEROBJACCOUNTING_COMPLETE;
+       txg_wait_synced(dmu_objset_pool(os), 0);
+       return (0);
+}
+
+void
+dmu_objset_userobjspace_upgrade(objset_t *os)
+{
+       dmu_objset_upgrade(os, dmu_objset_userobjspace_upgrade_cb);
+}
+
 void
 dmu_objset_space(objset_t *os, uint64_t *refdbytesp, uint64_t *availbytesp,
     uint64_t *usedobjsp, uint64_t *availobjsp)
@@ -1821,6 +2100,7 @@ dmu_objset_find_dp(dsl_pool_t *dp, uint64_t ddobj,
                 * thread suffices. For now, stay single threaded.
                 */
                dmu_objset_find_dp_impl(dcp);
+               mutex_destroy(&err_lock);
 
                return (error);
        }
@@ -1832,6 +2112,8 @@ dmu_objset_find_dp(dsl_pool_t *dp, uint64_t ddobj,
            INT_MAX, 0);
        if (tq == NULL) {
                kmem_free(dcp, sizeof (*dcp));
+               mutex_destroy(&err_lock);
+
                return (SET_ERROR(ENOMEM));
        }
        dcp->dc_tq = tq;
@@ -2001,7 +2283,7 @@ dmu_objset_get_user(objset_t *os)
 
 /*
  * Determine name of filesystem, given name of snapshot.
- * buf must be at least MAXNAMELEN bytes
+ * buf must be at least ZFS_MAX_DATASET_NAME_LEN bytes
  */
 int
 dmu_fsname(const char *snapname, char *buf)
@@ -2009,7 +2291,7 @@ dmu_fsname(const char *snapname, char *buf)
        char *atp = strchr(snapname, '@');
        if (atp == NULL)
                return (SET_ERROR(EINVAL));
-       if (atp - snapname >= MAXNAMELEN)
+       if (atp - snapname >= ZFS_MAX_DATASET_NAME_LEN)
                return (SET_ERROR(ENAMETOOLONG));
        (void) strlcpy(buf, snapname, atp - snapname + 1);
        return (0);
@@ -2037,6 +2319,7 @@ EXPORT_SYMBOL(dmu_objset_find);
 EXPORT_SYMBOL(dmu_objset_byteswap);
 EXPORT_SYMBOL(dmu_objset_evict_dbufs);
 EXPORT_SYMBOL(dmu_objset_snap_cmtime);
+EXPORT_SYMBOL(dmu_objset_dnodesize);
 
 EXPORT_SYMBOL(dmu_objset_sync);
 EXPORT_SYMBOL(dmu_objset_is_dirty);
@@ -2049,4 +2332,7 @@ EXPORT_SYMBOL(dmu_objset_userquota_get_ids);
 EXPORT_SYMBOL(dmu_objset_userused_enabled);
 EXPORT_SYMBOL(dmu_objset_userspace_upgrade);
 EXPORT_SYMBOL(dmu_objset_userspace_present);
+EXPORT_SYMBOL(dmu_objset_userobjused_enabled);
+EXPORT_SYMBOL(dmu_objset_userobjspace_upgrade);
+EXPORT_SYMBOL(dmu_objset_userobjspace_present);
 #endif
index 6a349c6600d123c41f4b82b89abbc47b20978da4..f9414ea3ab2898e021edcbb5dfd95143df01c472 100644 (file)
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright 2014 HybridCluster. All rights reserved.
+ * Copyright 2016 RackTop Systems.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include <sys/blkptr.h>
 #include <sys/dsl_bookmark.h>
 #include <sys/zfeature.h>
+#include <sys/bqueue.h>
 #include <sys/zvol.h>
+#include <sys/policy.h>
 
 /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
 int zfs_send_corrupt_data = B_FALSE;
+int zfs_send_queue_length = 16 * 1024 * 1024;
+int zfs_recv_queue_length = 16 * 1024 * 1024;
+/* Set this tunable to FALSE to disable setting of DRR_FLAG_FREERECORDS */
+int zfs_send_set_freerecords_bit = B_TRUE;
 
 static char *dmu_recv_tag = "dmu_recv_tag";
-static const char *recv_clone_name = "%recv";
+const char *recv_clone_name = "%recv";
+
+#define        BP_SPAN(datablkszsec, indblkshift, level) \
+       (((uint64_t)datablkszsec) << (SPA_MINBLOCKSHIFT + \
+       (level) * (indblkshift - SPA_BLKPTRSHIFT)))
+
+static void byteswap_record(dmu_replay_record_t *drr);
+
+struct send_thread_arg {
+       bqueue_t        q;
+       dsl_dataset_t   *ds;            /* Dataset to traverse */
+       uint64_t        fromtxg;        /* Traverse from this txg */
+       int             flags;          /* flags to pass to traverse_dataset */
+       int             error_code;
+       boolean_t       cancel;
+       zbookmark_phys_t resume;
+};
+
+struct send_block_record {
+       boolean_t               eos_marker; /* Marks the end of the stream */
+       blkptr_t                bp;
+       zbookmark_phys_t        zb;
+       uint8_t                 indblkshift;
+       uint16_t                datablkszsec;
+       bqueue_node_t           ln;
+};
 
 typedef struct dump_bytes_io {
        dmu_sendarg_t   *dbi_dsp;
@@ -69,15 +101,27 @@ typedef struct dump_bytes_io {
 } dump_bytes_io_t;
 
 static void
-dump_bytes_strategy(void *arg)
+dump_bytes_cb(void *arg)
 {
        dump_bytes_io_t *dbi = (dump_bytes_io_t *)arg;
        dmu_sendarg_t *dsp = dbi->dbi_dsp;
-       dsl_dataset_t *ds = dsp->dsa_os->os_dsl_dataset;
+       dsl_dataset_t *ds = dmu_objset_ds(dsp->dsa_os);
        ssize_t resid; /* have to get resid to get detailed errno */
+
+       /*
+        * The code does not rely on this (len being a multiple of 8).  We keep
+        * this assertion because of the corresponding assertion in
+        * receive_read().  Keeping this assertion ensures that we do not
+        * inadvertently break backwards compatibility (causing the assertion
+        * in receive_read() to trigger on old software).
+        *
+        * Removing the assertions could be rolled into a new feature that uses
+        * data that isn't 8-byte aligned; if the assertions were removed, a
+        * feature flag would have to be added.
+        */
+
        ASSERT0(dbi->dbi_len % 8);
 
-       fletcher_4_incremental_native(dbi->dbi_buf, dbi->dbi_len, &dsp->dsa_zc);
        dsp->dsa_err = vn_rdwr(UIO_WRITE, dsp->dsa_vp,
            (caddr_t)dbi->dbi_buf, dbi->dbi_len,
            0, UIO_SYSSPACE, FAPPEND, RLIM64_INFINITY, CRED(), &resid);
@@ -96,6 +140,9 @@ dump_bytes(dmu_sendarg_t *dsp, void *buf, int len)
        dbi.dbi_buf = buf;
        dbi.dbi_len = len;
 
+#if defined(HAVE_LARGE_STACKS)
+       dump_bytes_cb(&dbi);
+#else
        /*
         * The vn_rdwr() call is performed in a taskq to ensure that there is
         * always enough stack space to write safely to the target filesystem.
@@ -103,11 +150,57 @@ dump_bytes(dmu_sendarg_t *dsp, void *buf, int len)
         * them and they are used in vdev_file.c for a similar purpose.
         */
        spa_taskq_dispatch_sync(dmu_objset_spa(dsp->dsa_os), ZIO_TYPE_FREE,
-           ZIO_TASKQ_ISSUE, dump_bytes_strategy, &dbi, TQ_SLEEP);
+           ZIO_TASKQ_ISSUE, dump_bytes_cb, &dbi, TQ_SLEEP);
+#endif /* HAVE_LARGE_STACKS */
 
        return (dsp->dsa_err);
 }
 
+/*
+ * For all record types except BEGIN, fill in the checksum (overlaid in
+ * drr_u.drr_checksum.drr_checksum).  The checksum verifies everything
+ * up to the start of the checksum itself.
+ */
+static int
+dump_record(dmu_sendarg_t *dsp, void *payload, int payload_len)
+{
+       ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+           ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
+       fletcher_4_incremental_native(dsp->dsa_drr,
+           offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+           &dsp->dsa_zc);
+       if (dsp->dsa_drr->drr_type == DRR_BEGIN) {
+               dsp->dsa_sent_begin = B_TRUE;
+       } else {
+               ASSERT(ZIO_CHECKSUM_IS_ZERO(&dsp->dsa_drr->drr_u.
+                   drr_checksum.drr_checksum));
+               dsp->dsa_drr->drr_u.drr_checksum.drr_checksum = dsp->dsa_zc;
+       }
+       if (dsp->dsa_drr->drr_type == DRR_END) {
+               dsp->dsa_sent_end = B_TRUE;
+       }
+       fletcher_4_incremental_native(&dsp->dsa_drr->
+           drr_u.drr_checksum.drr_checksum,
+           sizeof (zio_cksum_t), &dsp->dsa_zc);
+       if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0)
+               return (SET_ERROR(EINTR));
+       if (payload_len != 0) {
+               fletcher_4_incremental_native(payload, payload_len,
+                   &dsp->dsa_zc);
+               if (dump_bytes(dsp, payload, payload_len) != 0)
+                       return (SET_ERROR(EINTR));
+       }
+       return (0);
+}
+
+/*
+ * Fill in the drr_free struct, or perform aggregation if the previous record is
+ * also a free record, and the two are adjacent.
+ *
+ * Note that we send free records even for a full send, because we want to be
+ * able to receive a full send as a clone, which requires a list of all the free
+ * and freeobject records that were generated on the source.
+ */
 static int
 dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
     uint64_t length)
@@ -119,7 +212,7 @@ dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
         * that the receiving system doesn't have any dbufs in the range
         * being freed.  This is always true because there is a one-record
         * constraint: we only send one WRITE record for any given
-        * object+offset.  We know that the one-record constraint is
+        * object,offset.  We know that the one-record constraint is
         * true because we always send data in increasing order by
         * object,offset.
         *
@@ -131,15 +224,6 @@ dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
            (object == dsp->dsa_last_data_object &&
            offset > dsp->dsa_last_data_offset));
 
-       /*
-        * If we are doing a non-incremental send, then there can't
-        * be any data in the dataset we're receiving into.  Therefore
-        * a free record would simply be a no-op.  Save space by not
-        * sending it to begin with.
-        */
-       if (!dsp->dsa_incremental)
-               return (0);
-
        if (length != -1ULL && offset + length < offset)
                length = -1ULL;
 
@@ -152,8 +236,7 @@ dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
         */
        if (dsp->dsa_pending_op != PENDING_NONE &&
            dsp->dsa_pending_op != PENDING_FREE) {
-               if (dump_bytes(dsp, dsp->dsa_drr,
-                   sizeof (dmu_replay_record_t)) != 0)
+               if (dump_record(dsp, NULL, 0) != 0)
                        return (SET_ERROR(EINTR));
                dsp->dsa_pending_op = PENDING_NONE;
        }
@@ -176,8 +259,7 @@ dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
                        return (0);
                } else {
                        /* not a continuation.  Push out pending record */
-                       if (dump_bytes(dsp, dsp->dsa_drr,
-                           sizeof (dmu_replay_record_t)) != 0)
+                       if (dump_record(dsp, NULL, 0) != 0)
                                return (SET_ERROR(EINTR));
                        dsp->dsa_pending_op = PENDING_NONE;
                }
@@ -190,8 +272,7 @@ dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
        drrf->drr_length = length;
        drrf->drr_toguid = dsp->dsa_toguid;
        if (length == -1ULL) {
-               if (dump_bytes(dsp, dsp->dsa_drr,
-                   sizeof (dmu_replay_record_t)) != 0)
+               if (dump_record(dsp, NULL, 0) != 0)
                        return (SET_ERROR(EINTR));
        } else {
                dsp->dsa_pending_op = PENDING_FREE;
@@ -202,8 +283,10 @@ dump_free(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
 
 static int
 dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type,
-    uint64_t object, uint64_t offset, int blksz, const blkptr_t *bp, void *data)
+    uint64_t object, uint64_t offset, int lsize, int psize, const blkptr_t *bp,
+    void *data)
 {
+       uint64_t payload_size;
        struct drr_write *drrw = &(dsp->dsa_drr->drr_u.drr_write);
 
        /*
@@ -214,7 +297,7 @@ dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type,
            (object == dsp->dsa_last_data_object &&
            offset > dsp->dsa_last_data_offset));
        dsp->dsa_last_data_object = object;
-       dsp->dsa_last_data_offset = offset + blksz - 1;
+       dsp->dsa_last_data_offset = offset + lsize - 1;
 
        /*
         * If there is any kind of pending aggregation (currently either
@@ -223,19 +306,36 @@ dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type,
         * of different types.
         */
        if (dsp->dsa_pending_op != PENDING_NONE) {
-               if (dump_bytes(dsp, dsp->dsa_drr,
-                   sizeof (dmu_replay_record_t)) != 0)
+               if (dump_record(dsp, NULL, 0) != 0)
                        return (SET_ERROR(EINTR));
                dsp->dsa_pending_op = PENDING_NONE;
        }
-       /* write a DATA record */
+       /* write a WRITE record */
        bzero(dsp->dsa_drr, sizeof (dmu_replay_record_t));
        dsp->dsa_drr->drr_type = DRR_WRITE;
        drrw->drr_object = object;
        drrw->drr_type = type;
        drrw->drr_offset = offset;
-       drrw->drr_length = blksz;
        drrw->drr_toguid = dsp->dsa_toguid;
+       drrw->drr_logical_size = lsize;
+
+       /* only set the compression fields if the buf is compressed */
+       if (lsize != psize) {
+               ASSERT(dsp->dsa_featureflags & DMU_BACKUP_FEATURE_COMPRESSED);
+               ASSERT(!BP_IS_EMBEDDED(bp));
+               ASSERT(!BP_SHOULD_BYTESWAP(bp));
+               ASSERT(!DMU_OT_IS_METADATA(BP_GET_TYPE(bp)));
+               ASSERT3U(BP_GET_COMPRESS(bp), !=, ZIO_COMPRESS_OFF);
+               ASSERT3S(psize, >, 0);
+               ASSERT3S(lsize, >=, psize);
+
+               drrw->drr_compressiontype = BP_GET_COMPRESS(bp);
+               drrw->drr_compressed_size = psize;
+               payload_size = drrw->drr_compressed_size;
+       } else {
+               payload_size = drrw->drr_logical_size;
+       }
+
        if (bp == NULL || BP_IS_EMBEDDED(bp)) {
                /*
                 * There's no pre-computed checksum for partial-block
@@ -246,7 +346,8 @@ dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type,
                drrw->drr_checksumtype = ZIO_CHECKSUM_OFF;
        } else {
                drrw->drr_checksumtype = BP_GET_CHECKSUM(bp);
-               if (zio_checksum_table[drrw->drr_checksumtype].ci_dedup)
+               if (zio_checksum_table[drrw->drr_checksumtype].ci_flags &
+                   ZCHECKSUM_FLAG_DEDUP)
                        drrw->drr_checksumflags |= DRR_CHECKSUM_DEDUP;
                DDK_SET_LSIZE(&drrw->drr_key, BP_GET_LSIZE(bp));
                DDK_SET_PSIZE(&drrw->drr_key, BP_GET_PSIZE(bp));
@@ -254,9 +355,7 @@ dump_write(dmu_sendarg_t *dsp, dmu_object_type_t type,
                drrw->drr_key.ddk_cksum = bp->blk_cksum;
        }
 
-       if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0)
-               return (SET_ERROR(EINTR));
-       if (dump_bytes(dsp, data, blksz) != 0)
+       if (dump_record(dsp, data, payload_size) != 0)
                return (SET_ERROR(EINTR));
        return (0);
 }
@@ -270,8 +369,7 @@ dump_write_embedded(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
            &(dsp->dsa_drr->drr_u.drr_write_embedded);
 
        if (dsp->dsa_pending_op != PENDING_NONE) {
-               if (dump_bytes(dsp, dsp->dsa_drr,
-                   sizeof (dmu_replay_record_t)) != 0)
+               if (dump_record(dsp, NULL, 0) != 0)
                        return (EINTR);
                dsp->dsa_pending_op = PENDING_NONE;
        }
@@ -291,9 +389,7 @@ dump_write_embedded(dmu_sendarg_t *dsp, uint64_t object, uint64_t offset,
 
        decode_embedded_bp_compressed(bp, buf);
 
-       if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0)
-               return (EINTR);
-       if (dump_bytes(dsp, buf, P2ROUNDUP(drrw->drr_psize, 8)) != 0)
+       if (dump_record(dsp, buf, P2ROUNDUP(drrw->drr_psize, 8)) != 0)
                return (EINTR);
        return (0);
 }
@@ -304,8 +400,7 @@ dump_spill(dmu_sendarg_t *dsp, uint64_t object, int blksz, void *data)
        struct drr_spill *drrs = &(dsp->dsa_drr->drr_u.drr_spill);
 
        if (dsp->dsa_pending_op != PENDING_NONE) {
-               if (dump_bytes(dsp, dsp->dsa_drr,
-                   sizeof (dmu_replay_record_t)) != 0)
+               if (dump_record(dsp, NULL, 0) != 0)
                        return (SET_ERROR(EINTR));
                dsp->dsa_pending_op = PENDING_NONE;
        }
@@ -317,9 +412,7 @@ dump_spill(dmu_sendarg_t *dsp, uint64_t object, int blksz, void *data)
        drrs->drr_length = blksz;
        drrs->drr_toguid = dsp->dsa_toguid;
 
-       if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)))
-               return (SET_ERROR(EINTR));
-       if (dump_bytes(dsp, data, blksz))
+       if (dump_record(dsp, data, blksz) != 0)
                return (SET_ERROR(EINTR));
        return (0);
 }
@@ -329,10 +422,6 @@ dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs)
 {
        struct drr_freeobjects *drrfo = &(dsp->dsa_drr->drr_u.drr_freeobjects);
 
-       /* See comment in dump_free(). */
-       if (!dsp->dsa_incremental)
-               return (0);
-
        /*
         * If there is a pending op, but it's not PENDING_FREEOBJECTS,
         * push it out, since free block aggregation can only be done for
@@ -342,8 +431,7 @@ dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs)
         */
        if (dsp->dsa_pending_op != PENDING_NONE &&
            dsp->dsa_pending_op != PENDING_FREEOBJECTS) {
-               if (dump_bytes(dsp, dsp->dsa_drr,
-                   sizeof (dmu_replay_record_t)) != 0)
+               if (dump_record(dsp, NULL, 0) != 0)
                        return (SET_ERROR(EINTR));
                dsp->dsa_pending_op = PENDING_NONE;
        }
@@ -357,8 +445,7 @@ dump_freeobjects(dmu_sendarg_t *dsp, uint64_t firstobj, uint64_t numobjs)
                        return (0);
                } else {
                        /* can't be aggregated.  Push out pending record */
-                       if (dump_bytes(dsp, dsp->dsa_drr,
-                           sizeof (dmu_replay_record_t)) != 0)
+                       if (dump_record(dsp, NULL, 0) != 0)
                                return (SET_ERROR(EINTR));
                        dsp->dsa_pending_op = PENDING_NONE;
                }
@@ -381,12 +468,24 @@ dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp)
 {
        struct drr_object *drro = &(dsp->dsa_drr->drr_u.drr_object);
 
+       if (object < dsp->dsa_resume_object) {
+               /*
+                * Note: when resuming, we will visit all the dnodes in
+                * the block of dnodes that we are resuming from.  In
+                * this case it's unnecessary to send the dnodes prior to
+                * the one we are resuming from.  We should be at most one
+                * block's worth of dnodes behind the resume point.
+                */
+               ASSERT3U(dsp->dsa_resume_object - object, <,
+                   1 << (DNODE_BLOCK_SHIFT - DNODE_SHIFT));
+               return (0);
+       }
+
        if (dnp == NULL || dnp->dn_type == DMU_OT_NONE)
                return (dump_freeobjects(dsp, object, 1));
 
        if (dsp->dsa_pending_op != PENDING_NONE) {
-               if (dump_bytes(dsp, dsp->dsa_drr,
-                   sizeof (dmu_replay_record_t)) != 0)
+               if (dump_record(dsp, NULL, 0) != 0)
                        return (SET_ERROR(EINTR));
                dsp->dsa_pending_op = PENDING_NONE;
        }
@@ -399,6 +498,7 @@ dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp)
        drro->drr_bonustype = dnp->dn_bonustype;
        drro->drr_blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT;
        drro->drr_bonuslen = dnp->dn_bonuslen;
+       drro->drr_dn_slots = dnp->dn_extra_slots + 1;
        drro->drr_checksumtype = dnp->dn_checksum;
        drro->drr_compress = dnp->dn_compress;
        drro->drr_toguid = dsp->dsa_toguid;
@@ -407,11 +507,10 @@ dump_dnode(dmu_sendarg_t *dsp, uint64_t object, dnode_phys_t *dnp)
            drro->drr_blksz > SPA_OLD_MAXBLOCKSIZE)
                drro->drr_blksz = SPA_OLD_MAXBLOCKSIZE;
 
-       if (dump_bytes(dsp, dsp->dsa_drr, sizeof (dmu_replay_record_t)) != 0)
-               return (SET_ERROR(EINTR));
-
-       if (dump_bytes(dsp, DN_BONUS(dnp), P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0)
+       if (dump_record(dsp, DN_BONUS(dnp),
+           P2ROUNDUP(dnp->dn_bonuslen, 8)) != 0) {
                return (SET_ERROR(EINTR));
+       }
 
        /* Free anything past the end of the file. */
        if (dump_free(dsp, object, (dnp->dn_maxblkid + 1) *
@@ -432,7 +531,7 @@ backup_do_embed(dmu_sendarg_t *dsp, const blkptr_t *bp)
         * Compression function must be legacy, or explicitly enabled.
         */
        if ((BP_GET_COMPRESS(bp) >= ZIO_COMPRESS_LEGACY_FUNCTIONS &&
-           !(dsp->dsa_featureflags & DMU_BACKUP_FEATURE_EMBED_DATA_LZ4)))
+           !(dsp->dsa_featureflags & DMU_BACKUP_FEATURE_LZ4)))
                return (B_FALSE);
 
        /*
@@ -449,47 +548,118 @@ backup_do_embed(dmu_sendarg_t *dsp, const blkptr_t *bp)
        return (B_FALSE);
 }
 
-#define        BP_SPAN(dnp, level) \
-       (((uint64_t)dnp->dn_datablkszsec) << (SPA_MINBLOCKSHIFT + \
-       (level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT)))
+/*
+ * This is the callback function to traverse_dataset that acts as the worker
+ * thread for dmu_send_impl.
+ */
+/*ARGSUSED*/
+static int
+send_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
+    const zbookmark_phys_t *zb, const struct dnode_phys *dnp, void *arg)
+{
+       struct send_thread_arg *sta = arg;
+       struct send_block_record *record;
+       uint64_t record_size;
+       int err = 0;
+
+       ASSERT(zb->zb_object == DMU_META_DNODE_OBJECT ||
+           zb->zb_object >= sta->resume.zb_object);
 
-/* ARGSUSED */
+       if (sta->cancel)
+               return (SET_ERROR(EINTR));
+
+       if (bp == NULL) {
+               ASSERT3U(zb->zb_level, ==, ZB_DNODE_LEVEL);
+               return (0);
+       } else if (zb->zb_level < 0) {
+               return (0);
+       }
+
+       record = kmem_zalloc(sizeof (struct send_block_record), KM_SLEEP);
+       record->eos_marker = B_FALSE;
+       record->bp = *bp;
+       record->zb = *zb;
+       record->indblkshift = dnp->dn_indblkshift;
+       record->datablkszsec = dnp->dn_datablkszsec;
+       record_size = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT;
+       bqueue_enqueue(&sta->q, record, record_size);
+
+       return (err);
+}
+
+/*
+ * This function kicks off the traverse_dataset.  It also handles setting the
+ * error code of the thread in case something goes wrong, and pushes the End of
+ * Stream record when the traverse_dataset call has finished.  If there is no
+ * dataset to traverse, the thread immediately pushes End of Stream marker.
+ */
+static void
+send_traverse_thread(void *arg)
+{
+       struct send_thread_arg *st_arg = arg;
+       int err;
+       struct send_block_record *data;
+       fstrans_cookie_t cookie = spl_fstrans_mark();
+
+       if (st_arg->ds != NULL) {
+               err = traverse_dataset_resume(st_arg->ds,
+                   st_arg->fromtxg, &st_arg->resume,
+                   st_arg->flags, send_cb, st_arg);
+
+               if (err != EINTR)
+                       st_arg->error_code = err;
+       }
+       data = kmem_zalloc(sizeof (*data), KM_SLEEP);
+       data->eos_marker = B_TRUE;
+       bqueue_enqueue(&st_arg->q, data, 1);
+       spl_fstrans_unmark(cookie);
+}
+
+/*
+ * This function actually handles figuring out what kind of record needs to be
+ * dumped, reading the data (which has hopefully been prefetched), and calling
+ * the appropriate helper function.
+ */
 static int
-backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
-    const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
+do_dump(dmu_sendarg_t *dsa, struct send_block_record *data)
 {
-       dmu_sendarg_t *dsp = arg;
+       dsl_dataset_t *ds = dmu_objset_ds(dsa->dsa_os);
+       const blkptr_t *bp = &data->bp;
+       const zbookmark_phys_t *zb = &data->zb;
+       uint8_t indblkshift = data->indblkshift;
+       uint16_t dblkszsec = data->datablkszsec;
+       spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
        dmu_object_type_t type = bp ? BP_GET_TYPE(bp) : DMU_OT_NONE;
        int err = 0;
+       uint64_t dnobj;
 
-       if (issig(JUSTLOOKING) && issig(FORREAL))
-               return (SET_ERROR(EINTR));
+       ASSERT3U(zb->zb_level, >=, 0);
+
+       ASSERT(zb->zb_object == DMU_META_DNODE_OBJECT ||
+           zb->zb_object >= dsa->dsa_resume_object);
 
        if (zb->zb_object != DMU_META_DNODE_OBJECT &&
            DMU_OBJECT_IS_SPECIAL(zb->zb_object)) {
                return (0);
-       } else if (zb->zb_level == ZB_ZIL_LEVEL) {
-               /*
-                * If we are sending a non-snapshot (which is allowed on
-                * read-only pools), it may have a ZIL, which must be ignored.
-                */
-               return (0);
        } else if (BP_IS_HOLE(bp) &&
            zb->zb_object == DMU_META_DNODE_OBJECT) {
-               uint64_t span = BP_SPAN(dnp, zb->zb_level);
+               uint64_t span = BP_SPAN(dblkszsec, indblkshift, zb->zb_level);
                uint64_t dnobj = (zb->zb_blkid * span) >> DNODE_SHIFT;
-               err = dump_freeobjects(dsp, dnobj, span >> DNODE_SHIFT);
+               err = dump_freeobjects(dsa, dnobj, span >> DNODE_SHIFT);
        } else if (BP_IS_HOLE(bp)) {
-               uint64_t span = BP_SPAN(dnp, zb->zb_level);
-               err = dump_free(dsp, zb->zb_object, zb->zb_blkid * span, span);
+               uint64_t span = BP_SPAN(dblkszsec, indblkshift, zb->zb_level);
+               uint64_t offset = zb->zb_blkid * span;
+               err = dump_free(dsa, zb->zb_object, offset, span);
        } else if (zb->zb_level > 0 || type == DMU_OT_OBJSET) {
                return (0);
        } else if (type == DMU_OT_DNODE) {
                dnode_phys_t *blk;
-               int i;
-               int blksz = BP_GET_LSIZE(bp);
+               int epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT;
                arc_flags_t aflags = ARC_FLAG_WAIT;
                arc_buf_t *abuf;
+               int i;
+
+               ASSERT0(zb->zb_level);
 
                if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
                    ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
@@ -497,14 +667,13 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
                        return (SET_ERROR(EIO));
 
                blk = abuf->b_data;
-               for (i = 0; i < blksz >> DNODE_SHIFT; i++) {
-                       uint64_t dnobj = (zb->zb_blkid <<
-                           (DNODE_BLOCK_SHIFT - DNODE_SHIFT)) + i;
-                       err = dump_dnode(dsp, dnobj, blk+i);
+               dnobj = zb->zb_blkid * epb;
+               for (i = 0; i < epb; i += blk[i].dn_extra_slots + 1) {
+                       err = dump_dnode(dsa, dnobj + i, blk + i);
                        if (err != 0)
                                break;
                }
-               (void) arc_buf_remove_ref(abuf, &abuf);
+               arc_buf_destroy(abuf, &abuf);
        } else if (type == DMU_OT_SA) {
                arc_flags_t aflags = ARC_FLAG_WAIT;
                arc_buf_t *abuf;
@@ -515,29 +684,61 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
                    &aflags, zb) != 0)
                        return (SET_ERROR(EIO));
 
-               err = dump_spill(dsp, zb->zb_object, blksz, abuf->b_data);
-               (void) arc_buf_remove_ref(abuf, &abuf);
-       } else if (backup_do_embed(dsp, bp)) {
+               err = dump_spill(dsa, zb->zb_object, blksz, abuf->b_data);
+               arc_buf_destroy(abuf, &abuf);
+       } else if (backup_do_embed(dsa, bp)) {
                /* it's an embedded level-0 block of a regular object */
-               int blksz = dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT;
-               err = dump_write_embedded(dsp, zb->zb_object,
+               int blksz = dblkszsec << SPA_MINBLOCKSHIFT;
+               ASSERT0(zb->zb_level);
+               err = dump_write_embedded(dsa, zb->zb_object,
                    zb->zb_blkid * blksz, blksz, bp);
-       } else { /* it's a level-0 block of a regular object */
-               uint64_t offset;
+       } else {
+               /* it's a level-0 block of a regular object */
                arc_flags_t aflags = ARC_FLAG_WAIT;
                arc_buf_t *abuf;
-               int blksz = BP_GET_LSIZE(bp);
+               int blksz = dblkszsec << SPA_MINBLOCKSHIFT;
+               uint64_t offset;
+               enum zio_flag zioflags = ZIO_FLAG_CANFAIL;
+
+               /*
+                * If we have large blocks stored on disk but the send flags
+                * don't allow us to send large blocks, we split the data from
+                * the arc buf into chunks.
+                */
+               boolean_t split_large_blocks =
+                   data->datablkszsec > SPA_OLD_MAXBLOCKSIZE &&
+                   !(dsa->dsa_featureflags & DMU_BACKUP_FEATURE_LARGE_BLOCKS);
+               /*
+                * We should only request compressed data from the ARC if all
+                * the following are true:
+                *  - stream compression was requested
+                *  - we aren't splitting large blocks into smaller chunks
+                *  - the data won't need to be byteswapped before sending
+                *  - this isn't an embedded block
+                *  - this isn't metadata (if receiving on a different endian
+                *    system it can be byteswapped more easily)
+                */
+               boolean_t request_compressed =
+                   (dsa->dsa_featureflags & DMU_BACKUP_FEATURE_COMPRESSED) &&
+                   !split_large_blocks && !BP_SHOULD_BYTESWAP(bp) &&
+                   !BP_IS_EMBEDDED(bp) && !DMU_OT_IS_METADATA(BP_GET_TYPE(bp));
 
-               ASSERT3U(blksz, ==, dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT);
                ASSERT0(zb->zb_level);
+               ASSERT(zb->zb_object > dsa->dsa_resume_object ||
+                   (zb->zb_object == dsa->dsa_resume_object &&
+                   zb->zb_blkid * blksz >= dsa->dsa_resume_offset));
+
+               if (request_compressed)
+                       zioflags |= ZIO_FLAG_RAW;
+
                if (arc_read(NULL, spa, bp, arc_getbuf_func, &abuf,
-                   ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL,
+                   ZIO_PRIORITY_ASYNC_READ, zioflags,
                    &aflags, zb) != 0) {
                        if (zfs_send_corrupt_data) {
                                uint64_t *ptr;
                                /* Send a block filled with 0x"zfs badd bloc" */
-                               abuf = arc_buf_alloc(spa, blksz, &abuf,
-                                   ARC_BUFC_DATA);
+                               abuf = arc_alloc_buf(spa, &abuf, ARC_BUFC_DATA,
+                                   blksz);
                                for (ptr = abuf->b_data;
                                    (char *)ptr < (char *)abuf->b_data + blksz;
                                    ptr++)
@@ -549,23 +750,24 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
 
                offset = zb->zb_blkid * blksz;
 
-               if (!(dsp->dsa_featureflags &
-                   DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
-                   blksz > SPA_OLD_MAXBLOCKSIZE) {
+               if (split_large_blocks) {
                        char *buf = abuf->b_data;
+                       ASSERT3U(arc_get_compression(abuf), ==,
+                           ZIO_COMPRESS_OFF);
                        while (blksz > 0 && err == 0) {
                                int n = MIN(blksz, SPA_OLD_MAXBLOCKSIZE);
-                               err = dump_write(dsp, type, zb->zb_object,
-                                   offset, n, NULL, buf);
+                               err = dump_write(dsa, type, zb->zb_object,
+                                   offset, n, n, NULL, buf);
                                offset += n;
                                buf += n;
                                blksz -= n;
                        }
                } else {
-                       err = dump_write(dsp, type, zb->zb_object,
-                           offset, blksz, bp, abuf->b_data);
+                       err = dump_write(dsa, type, zb->zb_object, offset,
+                           blksz, arc_buf_size(abuf), bp,
+                           abuf->b_data);
                }
-               (void) arc_buf_remove_ref(abuf, &abuf);
+               arc_buf_destroy(abuf, &abuf);
        }
 
        ASSERT(err == 0 || err == EINTR);
@@ -573,12 +775,27 @@ backup_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
 }
 
 /*
- * Releases dp using the specified tag.
+ * Pop the new data off the queue, and free the old data.
+ */
+static struct send_block_record *
+get_next_record(bqueue_t *bq, struct send_block_record *data)
+{
+       struct send_block_record *tmp = bqueue_dequeue(bq);
+       kmem_free(data, sizeof (*data));
+       return (tmp);
+}
+
+/*
+ * Actually do the bulk of the work in a zfs send.
+ *
+ * Note: Releases dp using the specified tag.
  */
 static int
-dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
-    zfs_bookmark_phys_t *fromzb, boolean_t is_clone, boolean_t embedok,
-    boolean_t large_block_ok, int outfd, vnode_t *vp, offset_t *off)
+dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *to_ds,
+    zfs_bookmark_phys_t *ancestor_zb, boolean_t is_clone,
+    boolean_t embedok, boolean_t large_block_ok, boolean_t compressok,
+    int outfd, uint64_t resumeobj, uint64_t resumeoff,
+    vnode_t *vp, offset_t *off)
 {
        objset_t *os;
        dmu_replay_record_t *drr;
@@ -586,8 +803,12 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
        int err;
        uint64_t fromtxg = 0;
        uint64_t featureflags = 0;
+       struct send_thread_arg to_arg;
+       void *payload = NULL;
+       size_t payload_len = 0;
+       struct send_block_record *to_data;
 
-       err = dmu_objset_from_ds(ds, &os);
+       err = dmu_objset_from_ds(to_ds, &os);
        if (err != 0) {
                dsl_pool_rele(dp, tag);
                return (err);
@@ -599,6 +820,8 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
        DMU_SET_STREAM_HDRTYPE(drr->drr_u.drr_begin.drr_versioninfo,
            DMU_SUBSTREAM);
 
+       bzero(&to_arg, sizeof (to_arg));
+
 #ifdef _KERNEL
        if (dmu_objset_type(os) == DMU_OST_ZFS) {
                uint64_t version;
@@ -613,35 +836,48 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
        }
 #endif
 
-       if (large_block_ok && ds->ds_large_blocks)
+       if (large_block_ok && to_ds->ds_feature_inuse[SPA_FEATURE_LARGE_BLOCKS])
                featureflags |= DMU_BACKUP_FEATURE_LARGE_BLOCKS;
+       if (to_ds->ds_feature_inuse[SPA_FEATURE_LARGE_DNODE])
+               featureflags |= DMU_BACKUP_FEATURE_LARGE_DNODE;
        if (embedok &&
            spa_feature_is_active(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA)) {
                featureflags |= DMU_BACKUP_FEATURE_EMBED_DATA;
-               if (spa_feature_is_active(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
-                       featureflags |= DMU_BACKUP_FEATURE_EMBED_DATA_LZ4;
-       } else {
-               embedok = B_FALSE;
+       }
+       if (compressok) {
+               featureflags |= DMU_BACKUP_FEATURE_COMPRESSED;
+       }
+       if ((featureflags &
+           (DMU_BACKUP_FEATURE_EMBED_DATA | DMU_BACKUP_FEATURE_COMPRESSED)) !=
+           0 && spa_feature_is_active(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS)) {
+               featureflags |= DMU_BACKUP_FEATURE_LZ4;
+       }
+
+       if (resumeobj != 0 || resumeoff != 0) {
+               featureflags |= DMU_BACKUP_FEATURE_RESUMING;
        }
 
        DMU_SET_FEATUREFLAGS(drr->drr_u.drr_begin.drr_versioninfo,
            featureflags);
 
        drr->drr_u.drr_begin.drr_creation_time =
-           dsl_dataset_phys(ds)->ds_creation_time;
+           dsl_dataset_phys(to_ds)->ds_creation_time;
        drr->drr_u.drr_begin.drr_type = dmu_objset_type(os);
        if (is_clone)
                drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CLONE;
-       drr->drr_u.drr_begin.drr_toguid = dsl_dataset_phys(ds)->ds_guid;
-       if (dsl_dataset_phys(ds)->ds_flags & DS_FLAG_CI_DATASET)
+       drr->drr_u.drr_begin.drr_toguid = dsl_dataset_phys(to_ds)->ds_guid;
+       if (dsl_dataset_phys(to_ds)->ds_flags & DS_FLAG_CI_DATASET)
                drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_CI_DATA;
+       if (zfs_send_set_freerecords_bit)
+               drr->drr_u.drr_begin.drr_flags |= DRR_FLAG_FREERECORDS;
 
-       if (fromzb != NULL) {
-               drr->drr_u.drr_begin.drr_fromguid = fromzb->zbm_guid;
-               fromtxg = fromzb->zbm_creation_txg;
+       if (ancestor_zb != NULL) {
+               drr->drr_u.drr_begin.drr_fromguid =
+                   ancestor_zb->zbm_guid;
+               fromtxg = ancestor_zb->zbm_creation_txg;
        }
-       dsl_dataset_name(ds, drr->drr_u.drr_begin.drr_toname);
-       if (!ds->ds_is_snapshot) {
+       dsl_dataset_name(to_ds, drr->drr_u.drr_begin.drr_toname);
+       if (!to_ds->ds_is_snapshot) {
                (void) strlcat(drr->drr_u.drr_begin.drr_toname, "@--head--",
                    sizeof (drr->drr_u.drr_begin.drr_toname));
        }
@@ -654,29 +890,80 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
        dsp->dsa_proc = curproc;
        dsp->dsa_os = os;
        dsp->dsa_off = off;
-       dsp->dsa_toguid = dsl_dataset_phys(ds)->ds_guid;
-       ZIO_SET_CHECKSUM(&dsp->dsa_zc, 0, 0, 0, 0);
+       dsp->dsa_toguid = dsl_dataset_phys(to_ds)->ds_guid;
        dsp->dsa_pending_op = PENDING_NONE;
-       dsp->dsa_incremental = (fromzb != NULL);
        dsp->dsa_featureflags = featureflags;
+       dsp->dsa_resume_object = resumeobj;
+       dsp->dsa_resume_offset = resumeoff;
 
-       mutex_enter(&ds->ds_sendstream_lock);
-       list_insert_head(&ds->ds_sendstreams, dsp);
-       mutex_exit(&ds->ds_sendstream_lock);
+       mutex_enter(&to_ds->ds_sendstream_lock);
+       list_insert_head(&to_ds->ds_sendstreams, dsp);
+       mutex_exit(&to_ds->ds_sendstream_lock);
 
-       dsl_dataset_long_hold(ds, FTAG);
+       dsl_dataset_long_hold(to_ds, FTAG);
        dsl_pool_rele(dp, tag);
 
-       if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) {
+       if (resumeobj != 0 || resumeoff != 0) {
+               dmu_object_info_t to_doi;
+               nvlist_t *nvl;
+               err = dmu_object_info(os, resumeobj, &to_doi);
+               if (err != 0)
+                       goto out;
+               SET_BOOKMARK(&to_arg.resume, to_ds->ds_object, resumeobj, 0,
+                   resumeoff / to_doi.doi_data_block_size);
+
+               nvl = fnvlist_alloc();
+               fnvlist_add_uint64(nvl, "resume_object", resumeobj);
+               fnvlist_add_uint64(nvl, "resume_offset", resumeoff);
+               payload = fnvlist_pack(nvl, &payload_len);
+               drr->drr_payloadlen = payload_len;
+               fnvlist_free(nvl);
+       }
+
+       err = dump_record(dsp, payload, payload_len);
+       fnvlist_pack_free(payload, payload_len);
+       if (err != 0) {
                err = dsp->dsa_err;
                goto out;
        }
 
-       err = traverse_dataset(ds, fromtxg, TRAVERSE_PRE | TRAVERSE_PREFETCH,
-           backup_cb, dsp);
+       err = bqueue_init(&to_arg.q, zfs_send_queue_length,
+           offsetof(struct send_block_record, ln));
+       to_arg.error_code = 0;
+       to_arg.cancel = B_FALSE;
+       to_arg.ds = to_ds;
+       to_arg.fromtxg = fromtxg;
+       to_arg.flags = TRAVERSE_PRE | TRAVERSE_PREFETCH;
+       (void) thread_create(NULL, 0, send_traverse_thread, &to_arg, 0, curproc,
+           TS_RUN, minclsyspri);
+
+       to_data = bqueue_dequeue(&to_arg.q);
+
+       while (!to_data->eos_marker && err == 0) {
+               err = do_dump(dsp, to_data);
+               to_data = get_next_record(&to_arg.q, to_data);
+               if (issig(JUSTLOOKING) && issig(FORREAL))
+                       err = EINTR;
+       }
+
+       if (err != 0) {
+               to_arg.cancel = B_TRUE;
+               while (!to_data->eos_marker) {
+                       to_data = get_next_record(&to_arg.q, to_data);
+               }
+       }
+       kmem_free(to_data, sizeof (*to_data));
+
+       bqueue_destroy(&to_arg.q);
+
+       if (err == 0 && to_arg.error_code != 0)
+               err = to_arg.error_code;
+
+       if (err != 0)
+               goto out;
 
        if (dsp->dsa_pending_op != PENDING_NONE)
-               if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0)
+               if (dump_record(dsp, NULL, 0) != 0)
                        err = SET_ERROR(EINTR);
 
        if (err != 0) {
@@ -690,27 +977,27 @@ dmu_send_impl(void *tag, dsl_pool_t *dp, dsl_dataset_t *ds,
        drr->drr_u.drr_end.drr_checksum = dsp->dsa_zc;
        drr->drr_u.drr_end.drr_toguid = dsp->dsa_toguid;
 
-       if (dump_bytes(dsp, drr, sizeof (dmu_replay_record_t)) != 0) {
+       if (dump_record(dsp, NULL, 0) != 0)
                err = dsp->dsa_err;
-               goto out;
-       }
 
 out:
-       mutex_enter(&ds->ds_sendstream_lock);
-       list_remove(&ds->ds_sendstreams, dsp);
-       mutex_exit(&ds->ds_sendstream_lock);
+       mutex_enter(&to_ds->ds_sendstream_lock);
+       list_remove(&to_ds->ds_sendstreams, dsp);
+       mutex_exit(&to_ds->ds_sendstream_lock);
+
+       VERIFY(err != 0 || (dsp->dsa_sent_begin && dsp->dsa_sent_end));
 
        kmem_free(drr, sizeof (dmu_replay_record_t));
        kmem_free(dsp, sizeof (dmu_sendarg_t));
 
-       dsl_dataset_long_rele(ds, FTAG);
+       dsl_dataset_long_rele(to_ds, FTAG);
 
        return (err);
 }
 
 int
 dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
-    boolean_t embedok, boolean_t large_block_ok,
+    boolean_t embedok, boolean_t large_block_ok, boolean_t compressok,
     int outfd, vnode_t *vp, offset_t *off)
 {
        dsl_pool_t *dp;
@@ -747,19 +1034,20 @@ dmu_send_obj(const char *pool, uint64_t tosnap, uint64_t fromsnap,
                is_clone = (fromds->ds_dir != ds->ds_dir);
                dsl_dataset_rele(fromds, FTAG);
                err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
-                   embedok, large_block_ok, outfd, vp, off);
+                   embedok, large_block_ok, compressok, outfd, 0, 0, vp, off);
        } else {
                err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
-                   embedok, large_block_ok, outfd, vp, off);
+                   embedok, large_block_ok, compressok, outfd, 0, 0, vp, off);
        }
        dsl_dataset_rele(ds, FTAG);
        return (err);
 }
 
 int
-dmu_send(const char *tosnap, const char *fromsnap,
-    boolean_t embedok, boolean_t large_block_ok,
-    int outfd, vnode_t *vp, offset_t *off)
+dmu_send(const char *tosnap, const char *fromsnap, boolean_t embedok,
+    boolean_t large_block_ok, boolean_t compressok, int outfd,
+    uint64_t resumeobj, uint64_t resumeoff,
+    vnode_t *vp, offset_t *off)
 {
        dsl_pool_t *dp;
        dsl_dataset_t *ds;
@@ -826,10 +1114,12 @@ dmu_send(const char *tosnap, const char *fromsnap,
                        return (err);
                }
                err = dmu_send_impl(FTAG, dp, ds, &zb, is_clone,
-                   embedok, large_block_ok, outfd, vp, off);
+                   embedok, large_block_ok, compressok,
+                   outfd, resumeobj, resumeoff, vp, off);
        } else {
                err = dmu_send_impl(FTAG, dp, ds, NULL, B_FALSE,
-                   embedok, large_block_ok, outfd, vp, off);
+                   embedok, large_block_ok, compressok,
+                   outfd, resumeobj, resumeoff, vp, off);
        }
        if (owned)
                dsl_dataset_disown(ds, FTAG);
@@ -839,33 +1129,46 @@ dmu_send(const char *tosnap, const char *fromsnap,
 }
 
 static int
-dmu_adjust_send_estimate_for_indirects(dsl_dataset_t *ds, uint64_t size,
-    uint64_t *sizep)
+dmu_adjust_send_estimate_for_indirects(dsl_dataset_t *ds, uint64_t uncompressed,
+    uint64_t compressed, boolean_t stream_compressed, uint64_t *sizep)
 {
        int err;
+       uint64_t size;
        /*
         * Assume that space (both on-disk and in-stream) is dominated by
         * data.  We will adjust for indirect blocks and the copies property,
         * but ignore per-object space used (eg, dnodes and DRR_OBJECT records).
         */
 
+       uint64_t recordsize;
+       uint64_t record_count;
+
+       /* Assume all (uncompressed) blocks are recordsize. */
+       err = dsl_prop_get_int_ds(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
+           &recordsize);
+       if (err != 0)
+               return (err);
+       record_count = uncompressed / recordsize;
+
+       /*
+        * If we're estimating a send size for a compressed stream, use the
+        * compressed data size to estimate the stream size. Otherwise, use the
+        * uncompressed data size.
+        */
+       size = stream_compressed ? compressed : uncompressed;
+
        /*
         * Subtract out approximate space used by indirect blocks.
         * Assume most space is used by data blocks (non-indirect, non-dnode).
-        * Assume all blocks are recordsize.  Assume ditto blocks and
-        * internal fragmentation counter out compression.
+        * Assume no ditto blocks or internal fragmentation.
         *
         * Therefore, space used by indirect blocks is sizeof(blkptr_t) per
-        * block, which we observe in practice.
+        * block.
         */
-       uint64_t recordsize;
-       err = dsl_prop_get_int_ds(ds, "recordsize", &recordsize);
-       if (err != 0)
-               return (err);
-       size -= size / recordsize * sizeof (blkptr_t);
+       size -= record_count * sizeof (blkptr_t);
 
        /* Add in the space for the record associated with each block. */
-       size += size / recordsize * sizeof (dmu_replay_record_t);
+       size += record_count * sizeof (dmu_replay_record_t);
 
        *sizep = size;
 
@@ -873,10 +1176,11 @@ dmu_adjust_send_estimate_for_indirects(dsl_dataset_t *ds, uint64_t size,
 }
 
 int
-dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep)
+dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds,
+    boolean_t stream_compressed, uint64_t *sizep)
 {
        int err;
-       uint64_t size;
+       uint64_t uncomp, comp;
 
        ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
 
@@ -895,33 +1199,41 @@ dmu_send_estimate(dsl_dataset_t *ds, dsl_dataset_t *fromds, uint64_t *sizep)
        if (fromds != NULL && !dsl_dataset_is_before(ds, fromds, 0))
                return (SET_ERROR(EXDEV));
 
-       /* Get uncompressed size estimate of changed data. */
+       /* Get compressed and uncompressed size estimates of changed data. */
        if (fromds == NULL) {
-               size = dsl_dataset_phys(ds)->ds_uncompressed_bytes;
+               uncomp = dsl_dataset_phys(ds)->ds_uncompressed_bytes;
+               comp = dsl_dataset_phys(ds)->ds_compressed_bytes;
        } else {
-               uint64_t used, comp;
+               uint64_t used;
                err = dsl_dataset_space_written(fromds, ds,
-                   &used, &comp, &size);
+                   &used, &comp, &uncomp);
                if (err != 0)
                        return (err);
        }
 
-       err = dmu_adjust_send_estimate_for_indirects(ds, size, sizep);
+       err = dmu_adjust_send_estimate_for_indirects(ds, uncomp, comp,
+           stream_compressed, sizep);
        return (err);
 }
 
+struct calculate_send_arg {
+       uint64_t uncompressed;
+       uint64_t compressed;
+};
+
 /*
  * Simple callback used to traverse the blocks of a snapshot and sum their
- * uncompressed size
+ * uncompressed and compressed sizes.
  */
 /* ARGSUSED */
 static int
 dmu_calculate_send_traversal(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
     const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg)
 {
-       uint64_t *spaceptr = arg;
+       struct calculate_send_arg *space = arg;
        if (bp != NULL && !BP_IS_HOLE(bp)) {
-               *spaceptr += BP_GET_UCSIZE(bp);
+               space->uncompressed += BP_GET_UCSIZE(bp);
+               space->compressed += BP_GET_PSIZE(bp);
        }
        return (0);
 }
@@ -933,10 +1245,10 @@ dmu_calculate_send_traversal(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
  */
 int
 dmu_send_estimate_from_txg(dsl_dataset_t *ds, uint64_t from_txg,
-    uint64_t *sizep)
+    boolean_t stream_compressed, uint64_t *sizep)
 {
        int err;
-       uint64_t size = 0;
+       struct calculate_send_arg size = { 0 };
 
        ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
 
@@ -954,10 +1266,12 @@ dmu_send_estimate_from_txg(dsl_dataset_t *ds, uint64_t from_txg,
         */
        err = traverse_dataset(ds, from_txg, TRAVERSE_POST,
            dmu_calculate_send_traversal, &size);
+
        if (err)
                return (err);
 
-       err = dmu_adjust_send_estimate_for_indirects(ds, size, sizep);
+       err = dmu_adjust_send_estimate_for_indirects(ds, size.uncompressed,
+           size.compressed, stream_compressed, sizep);
        return (err);
 }
 
@@ -1069,6 +1383,7 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
 
        /* already checked */
        ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
+       ASSERT(!(featureflags & DMU_BACKUP_FEATURE_RESUMING));
 
        if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
            DMU_COMPOUNDSTREAM ||
@@ -1081,16 +1396,20 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
            spa_version(dp->dp_spa) < SPA_VERSION_SA)
                return (SET_ERROR(ENOTSUP));
 
+       if (drba->drba_cookie->drc_resumable &&
+           !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EXTENSIBLE_DATASET))
+               return (SET_ERROR(ENOTSUP));
+
        /*
         * The receiving code doesn't know how to translate a WRITE_EMBEDDED
-        * record to a plan WRITE record, so the pool must have the
+        * record to a plain WRITE record, so the pool must have the
         * EMBEDDED_DATA feature enabled if the stream has WRITE_EMBEDDED
         * records.  Same with WRITE_EMBEDDED records that use LZ4 compression.
         */
        if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) &&
            !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA))
                return (SET_ERROR(ENOTSUP));
-       if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA_LZ4) &&
+       if ((featureflags & DMU_BACKUP_FEATURE_LZ4) &&
            !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
                return (SET_ERROR(ENOTSUP));
 
@@ -1103,12 +1422,21 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
            !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
                return (SET_ERROR(ENOTSUP));
 
+       /*
+        * The receiving code doesn't know how to translate large dnodes
+        * to smaller ones, so the pool must have the LARGE_DNODE
+        * feature enabled if the stream has LARGE_DNODE.
+        */
+       if ((featureflags & DMU_BACKUP_FEATURE_LARGE_DNODE) &&
+           !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_DNODE))
+               return (SET_ERROR(ENOTSUP));
+
        error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
        if (error == 0) {
                /* target fs already exists; recv into temp clone */
 
                /* Can't recv a clone into an existing fs */
-               if (flags & DRR_FLAG_CLONE) {
+               if (flags & DRR_FLAG_CLONE || drba->drba_origin) {
                        dsl_dataset_rele(ds, FTAG);
                        return (SET_ERROR(EINVAL));
                }
@@ -1117,17 +1445,27 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
                dsl_dataset_rele(ds, FTAG);
        } else if (error == ENOENT) {
                /* target fs does not exist; must be a full backup or clone */
-               char buf[MAXNAMELEN];
+               char buf[ZFS_MAX_DATASET_NAME_LEN];
 
                /*
                 * If it's a non-clone incremental, we are missing the
                 * target fs, so fail the recv.
                 */
-               if (fromguid != 0 && !(flags & DRR_FLAG_CLONE))
+               if (fromguid != 0 && !(flags & DRR_FLAG_CLONE ||
+                   drba->drba_origin))
                        return (SET_ERROR(ENOENT));
 
+               /*
+                * If we're receiving a full send as a clone, and it doesn't
+                * contain all the necessary free records and freeobject
+                * records, reject it.
+                */
+               if (fromguid == 0 && drba->drba_origin &&
+                   !(flags & DRR_FLAG_FREERECORDS))
+                       return (SET_ERROR(EINVAL));
+
                /* Open the parent of tofs */
-               ASSERT3U(strlen(tofs), <, MAXNAMELEN);
+               ASSERT3U(strlen(tofs), <, sizeof (buf));
                (void) strlcpy(buf, tofs, strrchr(tofs, '/') - tofs + 1);
                error = dsl_dataset_hold(dp, buf, FTAG, &ds);
                if (error != 0)
@@ -1165,7 +1503,8 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
                                dsl_dataset_rele(ds, FTAG);
                                return (SET_ERROR(EINVAL));
                        }
-                       if (dsl_dataset_phys(origin)->ds_guid != fromguid) {
+                       if (dsl_dataset_phys(origin)->ds_guid != fromguid &&
+                           fromguid != 0) {
                                dsl_dataset_rele(origin, FTAG);
                                dsl_dataset_rele(ds, FTAG);
                                return (SET_ERROR(ENODEV));
@@ -1183,15 +1522,16 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
 {
        dmu_recv_begin_arg_t *drba = arg;
        dsl_pool_t *dp = dmu_tx_pool(tx);
+       objset_t *mos = dp->dp_meta_objset;
        struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
        const char *tofs = drba->drba_cookie->drc_tofs;
        dsl_dataset_t *ds, *newds;
        uint64_t dsobj;
        int error;
-       uint64_t crflags;
+       uint64_t crflags = 0;
 
-       crflags = (drrb->drr_flags & DRR_FLAG_CI_DATA) ?
-           DS_FLAG_CI_DATASET : 0;
+       if (drrb->drr_flags & DRR_FLAG_CI_DATA)
+               crflags |= DS_FLAG_CI_DATASET;
 
        error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
        if (error == 0) {
@@ -1203,7 +1543,8 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
                }
                dsobj = dsl_dataset_create_sync(ds->ds_dir, recv_clone_name,
                    snap, crflags, drba->drba_cred, tx);
-               dsl_dataset_rele(snap, FTAG);
+               if (drba->drba_snapobj != 0)
+                       dsl_dataset_rele(snap, FTAG);
                dsl_dataset_rele(ds, FTAG);
        } else {
                dsl_dir_t *dd;
@@ -1228,11 +1569,40 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
        }
        VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &newds));
 
-       if ((DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
-           DMU_BACKUP_FEATURE_LARGE_BLOCKS) &&
-           !newds->ds_large_blocks) {
-               dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
-               newds->ds_large_blocks = B_TRUE;
+       if (drba->drba_cookie->drc_resumable) {
+               uint64_t one = 1;
+               uint64_t zero = 0;
+
+               dsl_dataset_zapify(newds, tx);
+               if (drrb->drr_fromguid != 0) {
+                       VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_FROMGUID,
+                           8, 1, &drrb->drr_fromguid, tx));
+               }
+               VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_TOGUID,
+                   8, 1, &drrb->drr_toguid, tx));
+               VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_TONAME,
+                   1, strlen(drrb->drr_toname) + 1, drrb->drr_toname, tx));
+               VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_OBJECT,
+                   8, 1, &one, tx));
+               VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_OFFSET,
+                   8, 1, &zero, tx));
+               VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_BYTES,
+                   8, 1, &zero, tx));
+               if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+                   DMU_BACKUP_FEATURE_LARGE_BLOCKS) {
+                       VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_LARGEBLOCK,
+                                               8, 1, &one, tx));
+               }
+               if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+                   DMU_BACKUP_FEATURE_EMBED_DATA) {
+                       VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_EMBEDOK,
+                           8, 1, &one, tx));
+               }
+               if (DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo) &
+                   DMU_BACKUP_FEATURE_COMPRESSED) {
+                       VERIFY0(zap_add(mos, dsobj, DS_FIELD_RESUME_COMPRESSOK,
+                           8, 1, &one, tx));
+               }
        }
 
        dmu_buf_will_dirty(newds->ds_dbuf, tx);
@@ -1252,88 +1622,280 @@ dmu_recv_begin_sync(void *arg, dmu_tx_t *tx)
        spa_history_log_internal_ds(newds, "receive", tx, "");
 }
 
-/*
- * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
- * succeeds; otherwise we will leak the holds on the datasets.
- */
-int
-dmu_recv_begin(char *tofs, char *tosnap, struct drr_begin *drrb,
-    boolean_t force, char *origin, dmu_recv_cookie_t *drc)
+static int
+dmu_recv_resume_begin_check(void *arg, dmu_tx_t *tx)
 {
-       dmu_recv_begin_arg_t drba = { 0 };
-       dmu_replay_record_t *drr;
+       dmu_recv_begin_arg_t *drba = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       struct drr_begin *drrb = drba->drba_cookie->drc_drrb;
+       int error;
+       uint64_t featureflags = DMU_GET_FEATUREFLAGS(drrb->drr_versioninfo);
+       dsl_dataset_t *ds;
+       const char *tofs = drba->drba_cookie->drc_tofs;
+       uint64_t val;
 
-       bzero(drc, sizeof (dmu_recv_cookie_t));
-       drc->drc_drrb = drrb;
-       drc->drc_tosnap = tosnap;
-       drc->drc_tofs = tofs;
-       drc->drc_force = force;
-       drc->drc_cred = CRED();
+       /* 6 extra bytes for /%recv */
+       char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
 
-       if (drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC))
-               drc->drc_byteswap = B_TRUE;
-       else if (drrb->drr_magic != DMU_BACKUP_MAGIC)
+       /* already checked */
+       ASSERT3U(drrb->drr_magic, ==, DMU_BACKUP_MAGIC);
+       ASSERT(featureflags & DMU_BACKUP_FEATURE_RESUMING);
+
+       if (DMU_GET_STREAM_HDRTYPE(drrb->drr_versioninfo) ==
+           DMU_COMPOUNDSTREAM ||
+           drrb->drr_type >= DMU_OST_NUMTYPES)
                return (SET_ERROR(EINVAL));
 
-       drr = kmem_zalloc(sizeof (dmu_replay_record_t), KM_SLEEP);
-       drr->drr_type = DRR_BEGIN;
-       drr->drr_u.drr_begin = *drc->drc_drrb;
-       if (drc->drc_byteswap) {
-               fletcher_4_incremental_byteswap(drr,
-                   sizeof (dmu_replay_record_t), &drc->drc_cksum);
-       } else {
-               fletcher_4_incremental_native(drr,
-                   sizeof (dmu_replay_record_t), &drc->drc_cksum);
+       /* Verify pool version supports SA if SA_SPILL feature set */
+       if ((featureflags & DMU_BACKUP_FEATURE_SA_SPILL) &&
+           spa_version(dp->dp_spa) < SPA_VERSION_SA)
+               return (SET_ERROR(ENOTSUP));
+
+       /*
+        * The receiving code doesn't know how to translate a WRITE_EMBEDDED
+        * record to a plain WRITE record, so the pool must have the
+        * EMBEDDED_DATA feature enabled if the stream has WRITE_EMBEDDED
+        * records.  Same with WRITE_EMBEDDED records that use LZ4 compression.
+        */
+       if ((featureflags & DMU_BACKUP_FEATURE_EMBED_DATA) &&
+           !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_EMBEDDED_DATA))
+               return (SET_ERROR(ENOTSUP));
+       if ((featureflags & DMU_BACKUP_FEATURE_LZ4) &&
+           !spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LZ4_COMPRESS))
+               return (SET_ERROR(ENOTSUP));
+
+       (void) snprintf(recvname, sizeof (recvname), "%s/%s",
+           tofs, recv_clone_name);
+
+       if (dsl_dataset_hold(dp, recvname, FTAG, &ds) != 0) {
+               /* %recv does not exist; continue in tofs */
+               error = dsl_dataset_hold(dp, tofs, FTAG, &ds);
+               if (error != 0)
+                       return (error);
        }
-       kmem_free(drr, sizeof (dmu_replay_record_t));
 
-       if (drc->drc_byteswap) {
-               drrb->drr_magic = BSWAP_64(drrb->drr_magic);
-               drrb->drr_versioninfo = BSWAP_64(drrb->drr_versioninfo);
-               drrb->drr_creation_time = BSWAP_64(drrb->drr_creation_time);
-               drrb->drr_type = BSWAP_32(drrb->drr_type);
-               drrb->drr_toguid = BSWAP_64(drrb->drr_toguid);
-               drrb->drr_fromguid = BSWAP_64(drrb->drr_fromguid);
+       /* check that ds is marked inconsistent */
+       if (!DS_IS_INCONSISTENT(ds)) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
        }
 
-       drba.drba_origin = origin;
-       drba.drba_cookie = drc;
-       drba.drba_cred = CRED();
+       /* check that there is resuming data, and that the toguid matches */
+       if (!dsl_dataset_is_zapified(ds)) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
+       error = zap_lookup(dp->dp_meta_objset, ds->ds_object,
+           DS_FIELD_RESUME_TOGUID, sizeof (val), 1, &val);
+       if (error != 0 || drrb->drr_toguid != val) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
 
-       return (dsl_sync_task(tofs, dmu_recv_begin_check, dmu_recv_begin_sync,
-           &drba, 5, ZFS_SPACE_CHECK_NORMAL));
-}
+       /*
+        * Check if the receive is still running.  If so, it will be owned.
+        * Note that nothing else can own the dataset (e.g. after the receive
+        * fails) because it will be marked inconsistent.
+        */
+       if (dsl_dataset_has_owner(ds)) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EBUSY));
+       }
 
-struct restorearg {
-       int err;
-       boolean_t byteswap;
-       vnode_t *vp;
-       char *buf;
-       uint64_t voff;
-       int bufsize; /* amount of memory allocated for buf */
-       zio_cksum_t cksum;
-       avl_tree_t *guid_to_ds_map;
-};
+       /* There should not be any snapshots of this fs yet. */
+       if (ds->ds_prev != NULL && ds->ds_prev->ds_dir == ds->ds_dir) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
 
-typedef struct guid_map_entry {
-       uint64_t        guid;
-       dsl_dataset_t   *gme_ds;
-       avl_node_t      avlnode;
-} guid_map_entry_t;
+       /*
+        * Note: resume point will be checked when we process the first WRITE
+        * record.
+        */
 
-static int
-guid_compare(const void *arg1, const void *arg2)
-{
-       const guid_map_entry_t *gmep1 = arg1;
-       const guid_map_entry_t *gmep2 = arg2;
+       /* check that the origin matches */
+       val = 0;
+       (void) zap_lookup(dp->dp_meta_objset, ds->ds_object,
+           DS_FIELD_RESUME_FROMGUID, sizeof (val), 1, &val);
+       if (drrb->drr_fromguid != val) {
+               dsl_dataset_rele(ds, FTAG);
+               return (SET_ERROR(EINVAL));
+       }
 
-       if (gmep1->guid < gmep2->guid)
-               return (-1);
-       else if (gmep1->guid > gmep2->guid)
-               return (1);
+       dsl_dataset_rele(ds, FTAG);
        return (0);
 }
 
+static void
+dmu_recv_resume_begin_sync(void *arg, dmu_tx_t *tx)
+{
+       dmu_recv_begin_arg_t *drba = arg;
+       dsl_pool_t *dp = dmu_tx_pool(tx);
+       const char *tofs = drba->drba_cookie->drc_tofs;
+       dsl_dataset_t *ds;
+       uint64_t dsobj;
+       /* 6 extra bytes for /%recv */
+       char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
+
+       (void) snprintf(recvname, sizeof (recvname), "%s/%s",
+           tofs, recv_clone_name);
+
+       if (dsl_dataset_hold(dp, recvname, FTAG, &ds) != 0) {
+               /* %recv does not exist; continue in tofs */
+               VERIFY0(dsl_dataset_hold(dp, tofs, FTAG, &ds));
+               drba->drba_cookie->drc_newfs = B_TRUE;
+       }
+
+       /* clear the inconsistent flag so that we can own it */
+       ASSERT(DS_IS_INCONSISTENT(ds));
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
+       dsobj = ds->ds_object;
+       dsl_dataset_rele(ds, FTAG);
+
+       VERIFY0(dsl_dataset_own_obj(dp, dsobj, dmu_recv_tag, &ds));
+
+       dmu_buf_will_dirty(ds->ds_dbuf, tx);
+       dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT;
+
+       ASSERT(!BP_IS_HOLE(dsl_dataset_get_blkptr(ds)));
+
+       drba->drba_cookie->drc_ds = ds;
+
+       spa_history_log_internal_ds(ds, "resume receive", tx, "");
+}
+
+/*
+ * NB: callers *MUST* call dmu_recv_stream() if dmu_recv_begin()
+ * succeeds; otherwise we will leak the holds on the datasets.
+ */
+int
+dmu_recv_begin(char *tofs, char *tosnap, dmu_replay_record_t *drr_begin,
+    boolean_t force, boolean_t resumable, char *origin, dmu_recv_cookie_t *drc)
+{
+       dmu_recv_begin_arg_t drba = { 0 };
+
+       bzero(drc, sizeof (dmu_recv_cookie_t));
+       drc->drc_drr_begin = drr_begin;
+       drc->drc_drrb = &drr_begin->drr_u.drr_begin;
+       drc->drc_tosnap = tosnap;
+       drc->drc_tofs = tofs;
+       drc->drc_force = force;
+       drc->drc_resumable = resumable;
+       drc->drc_cred = CRED();
+
+       if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
+               drc->drc_byteswap = B_TRUE;
+               fletcher_4_incremental_byteswap(drr_begin,
+                   sizeof (dmu_replay_record_t), &drc->drc_cksum);
+               byteswap_record(drr_begin);
+       } else if (drc->drc_drrb->drr_magic == DMU_BACKUP_MAGIC) {
+               fletcher_4_incremental_native(drr_begin,
+                   sizeof (dmu_replay_record_t), &drc->drc_cksum);
+       } else {
+               return (SET_ERROR(EINVAL));
+       }
+
+       drba.drba_origin = origin;
+       drba.drba_cookie = drc;
+       drba.drba_cred = CRED();
+
+       if (DMU_GET_FEATUREFLAGS(drc->drc_drrb->drr_versioninfo) &
+           DMU_BACKUP_FEATURE_RESUMING) {
+               return (dsl_sync_task(tofs,
+                   dmu_recv_resume_begin_check, dmu_recv_resume_begin_sync,
+                   &drba, 5, ZFS_SPACE_CHECK_NORMAL));
+       } else  {
+               return (dsl_sync_task(tofs,
+                   dmu_recv_begin_check, dmu_recv_begin_sync,
+                   &drba, 5, ZFS_SPACE_CHECK_NORMAL));
+       }
+}
+
+struct receive_record_arg {
+       dmu_replay_record_t header;
+       void *payload; /* Pointer to a buffer containing the payload */
+       /*
+        * If the record is a write, pointer to the arc_buf_t containing the
+        * payload.
+        */
+       arc_buf_t *write_buf;
+       int payload_size;
+       uint64_t bytes_read; /* bytes read from stream when record created */
+       boolean_t eos_marker; /* Marks the end of the stream */
+       bqueue_node_t node;
+};
+
+struct receive_writer_arg {
+       objset_t *os;
+       boolean_t byteswap;
+       bqueue_t q;
+
+       /*
+        * These three args are used to signal to the main thread that we're
+        * done.
+        */
+       kmutex_t mutex;
+       kcondvar_t cv;
+       boolean_t done;
+
+       int err;
+       /* A map from guid to dataset to help handle dedup'd streams. */
+       avl_tree_t *guid_to_ds_map;
+       boolean_t resumable;
+       uint64_t last_object, last_offset;
+       uint64_t bytes_read; /* bytes read when current record created */
+};
+
+struct objlist {
+       list_t list; /* List of struct receive_objnode. */
+       /*
+        * Last object looked up. Used to assert that objects are being looked
+        * up in ascending order.
+        */
+       uint64_t last_lookup;
+};
+
+struct receive_objnode {
+       list_node_t node;
+       uint64_t object;
+};
+
+struct receive_arg  {
+       objset_t *os;
+       vnode_t *vp; /* The vnode to read the stream from */
+       uint64_t voff; /* The current offset in the stream */
+       uint64_t bytes_read;
+       /*
+        * A record that has had its payload read in, but hasn't yet been handed
+        * off to the worker thread.
+        */
+       struct receive_record_arg *rrd;
+       /* A record that has had its header read in, but not its payload. */
+       struct receive_record_arg *next_rrd;
+       zio_cksum_t cksum;
+       zio_cksum_t prev_cksum;
+       int err;
+       boolean_t byteswap;
+       /* Sorted list of objects not to issue prefetches for. */
+       struct objlist ignore_objlist;
+};
+
+typedef struct guid_map_entry {
+       uint64_t        guid;
+       dsl_dataset_t   *gme_ds;
+       avl_node_t      avlnode;
+} guid_map_entry_t;
+
+static int
+guid_compare(const void *arg1, const void *arg2)
+{
+       const guid_map_entry_t *gmep1 = (const guid_map_entry_t *)arg1;
+       const guid_map_entry_t *gmep2 = (const guid_map_entry_t *)arg2;
+
+       return (AVL_CMP(gmep1->guid, gmep2->guid));
+}
+
 static void
 free_guid_map_onexit(void *arg)
 {
@@ -1350,49 +1912,52 @@ free_guid_map_onexit(void *arg)
        kmem_free(ca, sizeof (avl_tree_t));
 }
 
-static void *
-restore_read(struct restorearg *ra, int len, char *buf)
+static int
+receive_read(struct receive_arg *ra, int len, void *buf)
 {
        int done = 0;
 
-       if (buf == NULL)
-               buf = ra->buf;
-
-       /* some things will require 8-byte alignment, so everything must */
+       /*
+        * The code doesn't rely on this (lengths being multiples of 8).  See
+        * comment in dump_bytes.
+        */
        ASSERT0(len % 8);
-       ASSERT3U(len, <=, ra->bufsize);
 
        while (done < len) {
                ssize_t resid;
 
                ra->err = vn_rdwr(UIO_READ, ra->vp,
-                   buf + done, len - done,
+                   (char *)buf + done, len - done,
                    ra->voff, UIO_SYSSPACE, FAPPEND,
                    RLIM64_INFINITY, CRED(), &resid);
 
-               if (resid == len - done)
-                       ra->err = SET_ERROR(EINVAL);
+               if (resid == len - done) {
+                       /*
+                        * Note: ECKSUM indicates that the receive
+                        * was interrupted and can potentially be resumed.
+                        */
+                       ra->err = SET_ERROR(ECKSUM);
+               }
                ra->voff += len - done - resid;
                done = len - resid;
                if (ra->err != 0)
-                       return (NULL);
+                       return (ra->err);
        }
 
+       ra->bytes_read += len;
+
        ASSERT3U(done, ==, len);
-       if (ra->byteswap)
-               fletcher_4_incremental_byteswap(buf, len, &ra->cksum);
-       else
-               fletcher_4_incremental_native(buf, len, &ra->cksum);
-       return (buf);
+       return (0);
 }
 
 noinline static void
-backup_byteswap(dmu_replay_record_t *drr)
+byteswap_record(dmu_replay_record_t *drr)
 {
 #define        DO64(X) (drr->drr_u.X = BSWAP_64(drr->drr_u.X))
 #define        DO32(X) (drr->drr_u.X = BSWAP_32(drr->drr_u.X))
        drr->drr_type = BSWAP_32(drr->drr_type);
        drr->drr_payloadlen = BSWAP_32(drr->drr_payloadlen);
+
        switch (drr->drr_type) {
        case DRR_BEGIN:
                DO64(drr_begin.drr_magic);
@@ -1420,13 +1985,11 @@ backup_byteswap(dmu_replay_record_t *drr)
                DO64(drr_write.drr_object);
                DO32(drr_write.drr_type);
                DO64(drr_write.drr_offset);
-               DO64(drr_write.drr_length);
+               DO64(drr_write.drr_logical_size);
                DO64(drr_write.drr_toguid);
-               DO64(drr_write.drr_key.ddk_cksum.zc_word[0]);
-               DO64(drr_write.drr_key.ddk_cksum.zc_word[1]);
-               DO64(drr_write.drr_key.ddk_cksum.zc_word[2]);
-               DO64(drr_write.drr_key.ddk_cksum.zc_word[3]);
+               ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_write.drr_key.ddk_cksum);
                DO64(drr_write.drr_key.ddk_prop);
+               DO64(drr_write.drr_compressed_size);
                break;
        case DRR_WRITE_BYREF:
                DO64(drr_write_byref.drr_object);
@@ -1436,10 +1999,8 @@ backup_byteswap(dmu_replay_record_t *drr)
                DO64(drr_write_byref.drr_refguid);
                DO64(drr_write_byref.drr_refobject);
                DO64(drr_write_byref.drr_refoffset);
-               DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[0]);
-               DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[1]);
-               DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[2]);
-               DO64(drr_write_byref.drr_key.ddk_cksum.zc_word[3]);
+               ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_write_byref.
+                   drr_key.ddk_cksum);
                DO64(drr_write_byref.drr_key.ddk_prop);
                break;
        case DRR_WRITE_EMBEDDED:
@@ -1462,15 +2023,17 @@ backup_byteswap(dmu_replay_record_t *drr)
                DO64(drr_spill.drr_toguid);
                break;
        case DRR_END:
-               DO64(drr_end.drr_checksum.zc_word[0]);
-               DO64(drr_end.drr_checksum.zc_word[1]);
-               DO64(drr_end.drr_checksum.zc_word[2]);
-               DO64(drr_end.drr_checksum.zc_word[3]);
                DO64(drr_end.drr_toguid);
+               ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_end.drr_checksum);
                break;
        default:
                break;
        }
+
+       if (drr->drr_type != DRR_BEGIN) {
+               ZIO_CHECKSUM_BSWAP(&drr->drr_u.drr_checksum.drr_checksum);
+       }
+
 #undef DO64
 #undef DO32
 }
@@ -1482,16 +2045,54 @@ deduce_nblkptr(dmu_object_type_t bonus_type, uint64_t bonus_size)
                return (1);
        } else {
                return (1 +
-                   ((DN_MAX_BONUSLEN - bonus_size) >> SPA_BLKPTRSHIFT));
+                   ((DN_OLD_MAX_BONUSLEN -
+                   MIN(DN_OLD_MAX_BONUSLEN, bonus_size)) >> SPA_BLKPTRSHIFT));
        }
 }
 
+static void
+save_resume_state(struct receive_writer_arg *rwa,
+    uint64_t object, uint64_t offset, dmu_tx_t *tx)
+{
+       int txgoff = dmu_tx_get_txg(tx) & TXG_MASK;
+
+       if (!rwa->resumable)
+               return;
+
+       /*
+        * We use ds_resume_bytes[] != 0 to indicate that we need to
+        * update this on disk, so it must not be 0.
+        */
+       ASSERT(rwa->bytes_read != 0);
+
+       /*
+        * We only resume from write records, which have a valid
+        * (non-meta-dnode) object number.
+        */
+       ASSERT(object != 0);
+
+       /*
+        * For resuming to work correctly, we must receive records in order,
+        * sorted by object,offset.  This is checked by the callers, but
+        * assert it here for good measure.
+        */
+       ASSERT3U(object, >=, rwa->os->os_dsl_dataset->ds_resume_object[txgoff]);
+       ASSERT(object != rwa->os->os_dsl_dataset->ds_resume_object[txgoff] ||
+           offset >= rwa->os->os_dsl_dataset->ds_resume_offset[txgoff]);
+       ASSERT3U(rwa->bytes_read, >=,
+           rwa->os->os_dsl_dataset->ds_resume_bytes[txgoff]);
+
+       rwa->os->os_dsl_dataset->ds_resume_object[txgoff] = object;
+       rwa->os->os_dsl_dataset->ds_resume_offset[txgoff] = offset;
+       rwa->os->os_dsl_dataset->ds_resume_bytes[txgoff] = rwa->bytes_read;
+}
+
 noinline static int
-restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro)
+receive_object(struct receive_writer_arg *rwa, struct drr_object *drro,
+       void *data)
 {
        dmu_object_info_t doi;
        dmu_tx_t *tx;
-       void *data = NULL;
        uint64_t object;
        int err;
 
@@ -1502,23 +2103,18 @@ restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro)
            drro->drr_compress >= ZIO_COMPRESS_FUNCTIONS ||
            P2PHASE(drro->drr_blksz, SPA_MINBLOCKSIZE) ||
            drro->drr_blksz < SPA_MINBLOCKSIZE ||
-           drro->drr_blksz > spa_maxblocksize(dmu_objset_spa(os)) ||
-           drro->drr_bonuslen > DN_MAX_BONUSLEN) {
+           drro->drr_blksz > spa_maxblocksize(dmu_objset_spa(rwa->os)) ||
+           drro->drr_bonuslen >
+           DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(rwa->os)))) {
                return (SET_ERROR(EINVAL));
        }
 
-       err = dmu_object_info(os, drro->drr_object, &doi);
+       err = dmu_object_info(rwa->os, drro->drr_object, &doi);
 
        if (err != 0 && err != ENOENT)
                return (SET_ERROR(EINVAL));
        object = err == 0 ? drro->drr_object : DMU_NEW_OBJECT;
 
-       if (drro->drr_bonuslen) {
-               data = restore_read(ra, P2ROUNDUP(drro->drr_bonuslen, 8), NULL);
-               if (ra->err != 0)
-                       return (ra->err);
-       }
-
        /*
         * If we are losing blkptrs or changing the block size this must
         * be a new file instance.  We must clear out the previous file
@@ -1532,14 +2128,14 @@ restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro)
 
                if (drro->drr_blksz != doi.doi_data_block_size ||
                    nblkptr < doi.doi_nblkptr) {
-                       err = dmu_free_long_range(os, drro->drr_object,
+                       err = dmu_free_long_range(rwa->os, drro->drr_object,
                            0, DMU_OBJECT_END);
                        if (err != 0)
                                return (SET_ERROR(EINVAL));
                }
        }
 
-       tx = dmu_tx_create(os);
+       tx = dmu_tx_create(rwa->os);
        dmu_tx_hold_bonus(tx, object);
        err = dmu_tx_assign(tx, TXG_WAIT);
        if (err != 0) {
@@ -1549,15 +2145,16 @@ restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro)
 
        if (object == DMU_NEW_OBJECT) {
                /* currently free, want to be allocated */
-               err = dmu_object_claim(os, drro->drr_object,
+               err = dmu_object_claim_dnsize(rwa->os, drro->drr_object,
                    drro->drr_type, drro->drr_blksz,
-                   drro->drr_bonustype, drro->drr_bonuslen, tx);
+                   drro->drr_bonustype, drro->drr_bonuslen,
+                   drro->drr_dn_slots << DNODE_SHIFT, tx);
        } else if (drro->drr_type != doi.doi_type ||
            drro->drr_blksz != doi.doi_data_block_size ||
            drro->drr_bonustype != doi.doi_bonus_type ||
            drro->drr_bonuslen != doi.doi_bonus_size) {
                /* currently allocated, but with different properties */
-               err = dmu_object_reclaim(os, drro->drr_object,
+               err = dmu_object_reclaim(rwa->os, drro->drr_object,
                    drro->drr_type, drro->drr_blksz,
                    drro->drr_bonustype, drro->drr_bonuslen, tx);
        }
@@ -1566,19 +2163,20 @@ restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro)
                return (SET_ERROR(EINVAL));
        }
 
-       dmu_object_set_checksum(os, drro->drr_object, drro->drr_checksumtype,
-           tx);
-       dmu_object_set_compress(os, drro->drr_object, drro->drr_compress, tx);
+       dmu_object_set_checksum(rwa->os, drro->drr_object,
+           drro->drr_checksumtype, tx);
+       dmu_object_set_compress(rwa->os, drro->drr_object,
+           drro->drr_compress, tx);
 
        if (data != NULL) {
                dmu_buf_t *db;
 
-               VERIFY(0 == dmu_bonus_hold(os, drro->drr_object, FTAG, &db));
+               VERIFY0(dmu_bonus_hold(rwa->os, drro->drr_object, FTAG, &db));
                dmu_buf_will_dirty(db, tx);
 
                ASSERT3U(db->db_size, >=, drro->drr_bonuslen);
                bcopy(data, db->db_data, drro->drr_bonuslen);
-               if (ra->byteswap) {
+               if (rwa->byteswap) {
                        dmu_object_byteswap_t byteswap =
                            DMU_OT_BYTESWAP(drro->drr_bonustype);
                        dmu_ot_byteswap[byteswap].ob_func(db->db_data,
@@ -1587,82 +2185,102 @@ restore_object(struct restorearg *ra, objset_t *os, struct drr_object *drro)
                dmu_buf_rele(db, FTAG);
        }
        dmu_tx_commit(tx);
+
        return (0);
 }
 
 /* ARGSUSED */
 noinline static int
-restore_freeobjects(struct restorearg *ra, objset_t *os,
+receive_freeobjects(struct receive_writer_arg *rwa,
     struct drr_freeobjects *drrfo)
 {
        uint64_t obj;
+       int next_err = 0;
 
        if (drrfo->drr_firstobj + drrfo->drr_numobjs < drrfo->drr_firstobj)
                return (SET_ERROR(EINVAL));
 
-       for (obj = drrfo->drr_firstobj;
-           obj < drrfo->drr_firstobj + drrfo->drr_numobjs;
-           (void) dmu_object_next(os, &obj, FALSE, 0)) {
+       for (obj = drrfo->drr_firstobj == 0 ? 1 : drrfo->drr_firstobj;
+           obj < drrfo->drr_firstobj + drrfo->drr_numobjs && next_err == 0;
+           next_err = dmu_object_next(rwa->os, &obj, FALSE, 0)) {
+               dmu_object_info_t doi;
                int err;
 
-               if (dmu_object_info(os, obj, NULL) != 0)
+               err = dmu_object_info(rwa->os, obj, &doi);
+               if (err == ENOENT) {
+                       obj++;
                        continue;
+               } else if (err != 0) {
+                       return (err);
+               }
 
-               err = dmu_free_long_object(os, obj);
+               err = dmu_free_long_object(rwa->os, obj);
                if (err != 0)
                        return (err);
        }
+       if (next_err != ESRCH)
+               return (next_err);
        return (0);
 }
 
 noinline static int
-restore_write(struct restorearg *ra, objset_t *os,
-    struct drr_write *drrw)
+receive_write(struct receive_writer_arg *rwa, struct drr_write *drrw,
+       arc_buf_t *abuf)
 {
        dmu_tx_t *tx;
        dmu_buf_t *bonus;
-       arc_buf_t *abuf;
-       void *data;
        int err;
 
-       if (drrw->drr_offset + drrw->drr_length < drrw->drr_offset ||
+       if (drrw->drr_offset + drrw->drr_logical_size < drrw->drr_offset ||
            !DMU_OT_IS_VALID(drrw->drr_type))
                return (SET_ERROR(EINVAL));
 
-       if (dmu_object_info(os, drrw->drr_object, NULL) != 0)
+       /*
+        * For resuming to work, records must be in increasing order
+        * by (object, offset).
+        */
+       if (drrw->drr_object < rwa->last_object ||
+           (drrw->drr_object == rwa->last_object &&
+           drrw->drr_offset < rwa->last_offset)) {
                return (SET_ERROR(EINVAL));
+       }
+       rwa->last_object = drrw->drr_object;
+       rwa->last_offset = drrw->drr_offset;
 
-       if (dmu_bonus_hold(os, drrw->drr_object, FTAG, &bonus) != 0)
+       if (dmu_object_info(rwa->os, drrw->drr_object, NULL) != 0)
                return (SET_ERROR(EINVAL));
 
-       abuf = dmu_request_arcbuf(bonus, drrw->drr_length);
-
-       data = restore_read(ra, drrw->drr_length, abuf->b_data);
-       if (data == NULL) {
-               dmu_return_arcbuf(abuf);
-               dmu_buf_rele(bonus, FTAG);
-               return (ra->err);
-       }
-
-       tx = dmu_tx_create(os);
+       tx = dmu_tx_create(rwa->os);
 
        dmu_tx_hold_write(tx, drrw->drr_object,
-           drrw->drr_offset, drrw->drr_length);
+           drrw->drr_offset, drrw->drr_logical_size);
        err = dmu_tx_assign(tx, TXG_WAIT);
        if (err != 0) {
-               dmu_return_arcbuf(abuf);
-               dmu_buf_rele(bonus, FTAG);
                dmu_tx_abort(tx);
                return (err);
        }
-       if (ra->byteswap) {
+       if (rwa->byteswap) {
                dmu_object_byteswap_t byteswap =
                    DMU_OT_BYTESWAP(drrw->drr_type);
-               dmu_ot_byteswap[byteswap].ob_func(data, drrw->drr_length);
+               dmu_ot_byteswap[byteswap].ob_func(abuf->b_data,
+                   DRR_WRITE_PAYLOAD_SIZE(drrw));
        }
+
+       /* use the bonus buf to look up the dnode in dmu_assign_arcbuf */
+       if (dmu_bonus_hold(rwa->os, drrw->drr_object, FTAG, &bonus) != 0)
+               return (SET_ERROR(EINVAL));
        dmu_assign_arcbuf(bonus, drrw->drr_offset, abuf, tx);
+
+       /*
+        * Note: If the receive fails, we want the resume stream to start
+        * with the same record that we last successfully received (as opposed
+        * to the next record), so that we can verify that we are
+        * resuming from the correct location.
+        */
+       save_resume_state(rwa, drrw->drr_object, drrw->drr_offset, tx);
        dmu_tx_commit(tx);
        dmu_buf_rele(bonus, FTAG);
+
        return (0);
 }
 
@@ -1674,7 +2292,7 @@ restore_write(struct restorearg *ra, objset_t *os,
  * data from the stream to fulfill this write.
  */
 static int
-restore_write_byref(struct restorearg *ra, objset_t *os,
+receive_write_byref(struct receive_writer_arg *rwa,
     struct drr_write_byref *drrwbr)
 {
        dmu_tx_t *tx;
@@ -1694,14 +2312,14 @@ restore_write_byref(struct restorearg *ra, objset_t *os,
         */
        if (drrwbr->drr_toguid != drrwbr->drr_refguid) {
                gmesrch.guid = drrwbr->drr_refguid;
-               if ((gmep = avl_find(ra->guid_to_ds_map, &gmesrch,
+               if ((gmep = avl_find(rwa->guid_to_ds_map, &gmesrch,
                    &where)) == NULL) {
                        return (SET_ERROR(EINVAL));
                }
                if (dmu_objset_from_ds(gmep->gme_ds, &ref_os))
                        return (SET_ERROR(EINVAL));
        } else {
-               ref_os = os;
+               ref_os = rwa->os;
        }
 
        err = dmu_buf_hold(ref_os, drrwbr->drr_refobject,
@@ -1709,7 +2327,7 @@ restore_write_byref(struct restorearg *ra, objset_t *os,
        if (err != 0)
                return (err);
 
-       tx = dmu_tx_create(os);
+       tx = dmu_tx_create(rwa->os);
 
        dmu_tx_hold_write(tx, drrwbr->drr_object,
            drrwbr->drr_offset, drrwbr->drr_length);
@@ -1718,81 +2336,77 @@ restore_write_byref(struct restorearg *ra, objset_t *os,
                dmu_tx_abort(tx);
                return (err);
        }
-       dmu_write(os, drrwbr->drr_object,
+       dmu_write(rwa->os, drrwbr->drr_object,
            drrwbr->drr_offset, drrwbr->drr_length, dbp->db_data, tx);
        dmu_buf_rele(dbp, FTAG);
+
+       /* See comment in restore_write. */
+       save_resume_state(rwa, drrwbr->drr_object, drrwbr->drr_offset, tx);
        dmu_tx_commit(tx);
        return (0);
 }
 
 static int
-restore_write_embedded(struct restorearg *ra, objset_t *os,
-    struct drr_write_embedded *drrwnp)
+receive_write_embedded(struct receive_writer_arg *rwa,
+    struct drr_write_embedded *drrwe, void *data)
 {
        dmu_tx_t *tx;
        int err;
-       void *data;
 
-       if (drrwnp->drr_offset + drrwnp->drr_length < drrwnp->drr_offset)
+       if (drrwe->drr_offset + drrwe->drr_length < drrwe->drr_offset)
                return (EINVAL);
 
-       if (drrwnp->drr_psize > BPE_PAYLOAD_SIZE)
+       if (drrwe->drr_psize > BPE_PAYLOAD_SIZE)
                return (EINVAL);
 
-       if (drrwnp->drr_etype >= NUM_BP_EMBEDDED_TYPES)
+       if (drrwe->drr_etype >= NUM_BP_EMBEDDED_TYPES)
                return (EINVAL);
-       if (drrwnp->drr_compression >= ZIO_COMPRESS_FUNCTIONS)
+       if (drrwe->drr_compression >= ZIO_COMPRESS_FUNCTIONS)
                return (EINVAL);
 
-       data = restore_read(ra, P2ROUNDUP(drrwnp->drr_psize, 8), NULL);
-       if (data == NULL)
-               return (ra->err);
-
-       tx = dmu_tx_create(os);
+       tx = dmu_tx_create(rwa->os);
 
-       dmu_tx_hold_write(tx, drrwnp->drr_object,
-           drrwnp->drr_offset, drrwnp->drr_length);
+       dmu_tx_hold_write(tx, drrwe->drr_object,
+           drrwe->drr_offset, drrwe->drr_length);
        err = dmu_tx_assign(tx, TXG_WAIT);
        if (err != 0) {
                dmu_tx_abort(tx);
                return (err);
        }
 
-       dmu_write_embedded(os, drrwnp->drr_object,
-           drrwnp->drr_offset, data, drrwnp->drr_etype,
-           drrwnp->drr_compression, drrwnp->drr_lsize, drrwnp->drr_psize,
-           ra->byteswap ^ ZFS_HOST_BYTEORDER, tx);
+       dmu_write_embedded(rwa->os, drrwe->drr_object,
+           drrwe->drr_offset, data, drrwe->drr_etype,
+           drrwe->drr_compression, drrwe->drr_lsize, drrwe->drr_psize,
+           rwa->byteswap ^ ZFS_HOST_BYTEORDER, tx);
 
+       /* See comment in restore_write. */
+       save_resume_state(rwa, drrwe->drr_object, drrwe->drr_offset, tx);
        dmu_tx_commit(tx);
        return (0);
 }
 
 static int
-restore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs)
+receive_spill(struct receive_writer_arg *rwa, struct drr_spill *drrs,
+    void *data)
 {
        dmu_tx_t *tx;
-       void *data;
        dmu_buf_t *db, *db_spill;
        int err;
 
        if (drrs->drr_length < SPA_MINBLOCKSIZE ||
-           drrs->drr_length > spa_maxblocksize(dmu_objset_spa(os)))
+           drrs->drr_length > spa_maxblocksize(dmu_objset_spa(rwa->os)))
                return (SET_ERROR(EINVAL));
 
-       data = restore_read(ra, drrs->drr_length, NULL);
-       if (data == NULL)
-               return (ra->err);
-
-       if (dmu_object_info(os, drrs->drr_object, NULL) != 0)
+       if (dmu_object_info(rwa->os, drrs->drr_object, NULL) != 0)
                return (SET_ERROR(EINVAL));
 
-       VERIFY(0 == dmu_bonus_hold(os, drrs->drr_object, FTAG, &db));
+       VERIFY0(dmu_bonus_hold(rwa->os, drrs->drr_object, FTAG, &db));
        if ((err = dmu_spill_hold_by_bonus(db, FTAG, &db_spill)) != 0) {
                dmu_buf_rele(db, FTAG);
                return (err);
        }
 
-       tx = dmu_tx_create(os);
+       tx = dmu_tx_create(rwa->os);
 
        dmu_tx_hold_spill(tx, db->db_object);
 
@@ -1819,8 +2433,7 @@ restore_spill(struct restorearg *ra, objset_t *os, struct drr_spill *drrs)
 
 /* ARGSUSED */
 noinline static int
-restore_free(struct restorearg *ra, objset_t *os,
-    struct drr_free *drrf)
+receive_free(struct receive_writer_arg *rwa, struct drr_free *drrf)
 {
        int err;
 
@@ -1828,11 +2441,12 @@ restore_free(struct restorearg *ra, objset_t *os,
            drrf->drr_offset + drrf->drr_length < drrf->drr_offset)
                return (SET_ERROR(EINVAL));
 
-       if (dmu_object_info(os, drrf->drr_object, NULL) != 0)
+       if (dmu_object_info(rwa->os, drrf->drr_object, NULL) != 0)
                return (SET_ERROR(EINVAL));
 
-       err = dmu_free_long_range(os, drrf->drr_object,
+       err = dmu_free_long_range(rwa->os, drrf->drr_object,
            drrf->drr_offset, drrf->drr_length);
+
        return (err);
 }
 
@@ -1840,31 +2454,493 @@ restore_free(struct restorearg *ra, objset_t *os,
 static void
 dmu_recv_cleanup_ds(dmu_recv_cookie_t *drc)
 {
-       char name[MAXNAMELEN];
-       dsl_dataset_name(drc->drc_ds, name);
-       dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
-       (void) dsl_destroy_head(name);
+       if (drc->drc_resumable) {
+               /* wait for our resume state to be written to disk */
+               txg_wait_synced(drc->drc_ds->ds_dir->dd_pool, 0);
+               dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
+       } else {
+               char name[ZFS_MAX_DATASET_NAME_LEN];
+               dsl_dataset_name(drc->drc_ds, name);
+               dsl_dataset_disown(drc->drc_ds, dmu_recv_tag);
+               (void) dsl_destroy_head(name);
+       }
+}
+
+static void
+receive_cksum(struct receive_arg *ra, int len, void *buf)
+{
+       if (ra->byteswap) {
+               fletcher_4_incremental_byteswap(buf, len, &ra->cksum);
+       } else {
+               fletcher_4_incremental_native(buf, len, &ra->cksum);
+       }
+}
+
+/*
+ * Read the payload into a buffer of size len, and update the current record's
+ * payload field.
+ * Allocate ra->next_rrd and read the next record's header into
+ * ra->next_rrd->header.
+ * Verify checksum of payload and next record.
+ */
+static int
+receive_read_payload_and_next_header(struct receive_arg *ra, int len, void *buf)
+{
+       int err;
+       zio_cksum_t cksum_orig;
+       zio_cksum_t *cksump;
+
+       if (len != 0) {
+               ASSERT3U(len, <=, SPA_MAXBLOCKSIZE);
+               err = receive_read(ra, len, buf);
+               if (err != 0)
+                       return (err);
+               receive_cksum(ra, len, buf);
+
+               /* note: rrd is NULL when reading the begin record's payload */
+               if (ra->rrd != NULL) {
+                       ra->rrd->payload = buf;
+                       ra->rrd->payload_size = len;
+                       ra->rrd->bytes_read = ra->bytes_read;
+               }
+       }
+
+       ra->prev_cksum = ra->cksum;
+
+       ra->next_rrd = kmem_zalloc(sizeof (*ra->next_rrd), KM_SLEEP);
+       err = receive_read(ra, sizeof (ra->next_rrd->header),
+           &ra->next_rrd->header);
+       ra->next_rrd->bytes_read = ra->bytes_read;
+       if (err != 0) {
+               kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
+               ra->next_rrd = NULL;
+               return (err);
+       }
+       if (ra->next_rrd->header.drr_type == DRR_BEGIN) {
+               kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
+               ra->next_rrd = NULL;
+               return (SET_ERROR(EINVAL));
+       }
+
+       /*
+        * Note: checksum is of everything up to but not including the
+        * checksum itself.
+        */
+       ASSERT3U(offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+           ==, sizeof (dmu_replay_record_t) - sizeof (zio_cksum_t));
+       receive_cksum(ra,
+           offsetof(dmu_replay_record_t, drr_u.drr_checksum.drr_checksum),
+           &ra->next_rrd->header);
+
+       cksum_orig = ra->next_rrd->header.drr_u.drr_checksum.drr_checksum;
+       cksump = &ra->next_rrd->header.drr_u.drr_checksum.drr_checksum;
+
+       if (ra->byteswap)
+               byteswap_record(&ra->next_rrd->header);
+
+       if ((!ZIO_CHECKSUM_IS_ZERO(cksump)) &&
+           !ZIO_CHECKSUM_EQUAL(ra->cksum, *cksump)) {
+               kmem_free(ra->next_rrd, sizeof (*ra->next_rrd));
+               ra->next_rrd = NULL;
+               return (SET_ERROR(ECKSUM));
+       }
+
+       receive_cksum(ra, sizeof (cksum_orig), &cksum_orig);
+
+       return (0);
+}
+
+static void
+objlist_create(struct objlist *list)
+{
+       list_create(&list->list, sizeof (struct receive_objnode),
+           offsetof(struct receive_objnode, node));
+       list->last_lookup = 0;
+}
+
+static void
+objlist_destroy(struct objlist *list)
+{
+       struct receive_objnode *n;
+
+       for (n = list_remove_head(&list->list);
+           n != NULL; n = list_remove_head(&list->list)) {
+               kmem_free(n, sizeof (*n));
+       }
+       list_destroy(&list->list);
+}
+
+/*
+ * This function looks through the objlist to see if the specified object number
+ * is contained in the objlist.  In the process, it will remove all object
+ * numbers in the list that are smaller than the specified object number.  Thus,
+ * any lookup of an object number smaller than a previously looked up object
+ * number will always return false; therefore, all lookups should be done in
+ * ascending order.
+ */
+static boolean_t
+objlist_exists(struct objlist *list, uint64_t object)
+{
+       struct receive_objnode *node = list_head(&list->list);
+       ASSERT3U(object, >=, list->last_lookup);
+       list->last_lookup = object;
+       while (node != NULL && node->object < object) {
+               VERIFY3P(node, ==, list_remove_head(&list->list));
+               kmem_free(node, sizeof (*node));
+               node = list_head(&list->list);
+       }
+       return (node != NULL && node->object == object);
+}
+
+/*
+ * The objlist is a list of object numbers stored in ascending order.  However,
+ * the insertion of new object numbers does not seek out the correct location to
+ * store a new object number; instead, it appends it to the list for simplicity.
+ * Thus, any users must take care to only insert new object numbers in ascending
+ * order.
+ */
+static void
+objlist_insert(struct objlist *list, uint64_t object)
+{
+       struct receive_objnode *node = kmem_zalloc(sizeof (*node), KM_SLEEP);
+       node->object = object;
+#ifdef ZFS_DEBUG
+       {
+       struct receive_objnode *last_object = list_tail(&list->list);
+       uint64_t last_objnum = (last_object != NULL ? last_object->object : 0);
+       ASSERT3U(node->object, >, last_objnum);
+       }
+#endif
+       list_insert_tail(&list->list, node);
+}
+
+/*
+ * Issue the prefetch reads for any necessary indirect blocks.
+ *
+ * We use the object ignore list to tell us whether or not to issue prefetches
+ * for a given object.  We do this for both correctness (in case the blocksize
+ * of an object has changed) and performance (if the object doesn't exist, don't
+ * needlessly try to issue prefetches).  We also trim the list as we go through
+ * the stream to prevent it from growing to an unbounded size.
+ *
+ * The object numbers within will always be in sorted order, and any write
+ * records we see will also be in sorted order, but they're not sorted with
+ * respect to each other (i.e. we can get several object records before
+ * receiving each object's write records).  As a result, once we've reached a
+ * given object number, we can safely remove any reference to lower object
+ * numbers in the ignore list. In practice, we receive up to 32 object records
+ * before receiving write records, so the list can have up to 32 nodes in it.
+ */
+/* ARGSUSED */
+static void
+receive_read_prefetch(struct receive_arg *ra,
+    uint64_t object, uint64_t offset, uint64_t length)
+{
+       if (!objlist_exists(&ra->ignore_objlist, object)) {
+               dmu_prefetch(ra->os, object, 1, offset, length,
+                   ZIO_PRIORITY_SYNC_READ);
+       }
+}
+
+/*
+ * Read records off the stream, issuing any necessary prefetches.
+ */
+static int
+receive_read_record(struct receive_arg *ra)
+{
+       int err;
+
+       switch (ra->rrd->header.drr_type) {
+       case DRR_OBJECT:
+       {
+               struct drr_object *drro = &ra->rrd->header.drr_u.drr_object;
+               uint32_t size = P2ROUNDUP(drro->drr_bonuslen, 8);
+               void *buf = kmem_zalloc(size, KM_SLEEP);
+               dmu_object_info_t doi;
+               err = receive_read_payload_and_next_header(ra, size, buf);
+               if (err != 0) {
+                       kmem_free(buf, size);
+                       return (err);
+               }
+               err = dmu_object_info(ra->os, drro->drr_object, &doi);
+               /*
+                * See receive_read_prefetch for an explanation why we're
+                * storing this object in the ignore_obj_list.
+                */
+               if (err == ENOENT ||
+                   (err == 0 && doi.doi_data_block_size != drro->drr_blksz)) {
+                       objlist_insert(&ra->ignore_objlist, drro->drr_object);
+                       err = 0;
+               }
+               return (err);
+       }
+       case DRR_FREEOBJECTS:
+       {
+               err = receive_read_payload_and_next_header(ra, 0, NULL);
+               return (err);
+       }
+       case DRR_WRITE:
+       {
+               struct drr_write *drrw = &ra->rrd->header.drr_u.drr_write;
+               arc_buf_t *abuf;
+               boolean_t is_meta = DMU_OT_IS_METADATA(drrw->drr_type);
+               if (DRR_WRITE_COMPRESSED(drrw)) {
+                       ASSERT3U(drrw->drr_compressed_size, >, 0);
+                       ASSERT3U(drrw->drr_logical_size, >=,
+                           drrw->drr_compressed_size);
+                       ASSERT(!is_meta);
+                       abuf = arc_loan_compressed_buf(
+                           dmu_objset_spa(ra->os),
+                           drrw->drr_compressed_size, drrw->drr_logical_size,
+                           drrw->drr_compressiontype);
+               } else {
+                       abuf = arc_loan_buf(dmu_objset_spa(ra->os),
+                           is_meta, drrw->drr_logical_size);
+               }
+
+               err = receive_read_payload_and_next_header(ra,
+                   DRR_WRITE_PAYLOAD_SIZE(drrw), abuf->b_data);
+               if (err != 0) {
+                       dmu_return_arcbuf(abuf);
+                       return (err);
+               }
+               ra->rrd->write_buf = abuf;
+               receive_read_prefetch(ra, drrw->drr_object, drrw->drr_offset,
+                   drrw->drr_logical_size);
+               return (err);
+       }
+       case DRR_WRITE_BYREF:
+       {
+               struct drr_write_byref *drrwb =
+                   &ra->rrd->header.drr_u.drr_write_byref;
+               err = receive_read_payload_and_next_header(ra, 0, NULL);
+               receive_read_prefetch(ra, drrwb->drr_object, drrwb->drr_offset,
+                   drrwb->drr_length);
+               return (err);
+       }
+       case DRR_WRITE_EMBEDDED:
+       {
+               struct drr_write_embedded *drrwe =
+                   &ra->rrd->header.drr_u.drr_write_embedded;
+               uint32_t size = P2ROUNDUP(drrwe->drr_psize, 8);
+               void *buf = kmem_zalloc(size, KM_SLEEP);
+
+               err = receive_read_payload_and_next_header(ra, size, buf);
+               if (err != 0) {
+                       kmem_free(buf, size);
+                       return (err);
+               }
+
+               receive_read_prefetch(ra, drrwe->drr_object, drrwe->drr_offset,
+                   drrwe->drr_length);
+               return (err);
+       }
+       case DRR_FREE:
+       {
+               /*
+                * It might be beneficial to prefetch indirect blocks here, but
+                * we don't really have the data to decide for sure.
+                */
+               err = receive_read_payload_and_next_header(ra, 0, NULL);
+               return (err);
+       }
+       case DRR_END:
+       {
+               struct drr_end *drre = &ra->rrd->header.drr_u.drr_end;
+               if (!ZIO_CHECKSUM_EQUAL(ra->prev_cksum, drre->drr_checksum))
+                       return (SET_ERROR(ECKSUM));
+               return (0);
+       }
+       case DRR_SPILL:
+       {
+               struct drr_spill *drrs = &ra->rrd->header.drr_u.drr_spill;
+               void *buf = kmem_zalloc(drrs->drr_length, KM_SLEEP);
+               err = receive_read_payload_and_next_header(ra, drrs->drr_length,
+                   buf);
+               if (err != 0)
+                       kmem_free(buf, drrs->drr_length);
+               return (err);
+       }
+       default:
+               return (SET_ERROR(EINVAL));
+       }
+}
+
+/*
+ * Commit the records to the pool.
+ */
+static int
+receive_process_record(struct receive_writer_arg *rwa,
+    struct receive_record_arg *rrd)
+{
+       int err;
+
+       /* Processing in order, therefore bytes_read should be increasing. */
+       ASSERT3U(rrd->bytes_read, >=, rwa->bytes_read);
+       rwa->bytes_read = rrd->bytes_read;
+
+       switch (rrd->header.drr_type) {
+       case DRR_OBJECT:
+       {
+               struct drr_object *drro = &rrd->header.drr_u.drr_object;
+               err = receive_object(rwa, drro, rrd->payload);
+               kmem_free(rrd->payload, rrd->payload_size);
+               rrd->payload = NULL;
+               return (err);
+       }
+       case DRR_FREEOBJECTS:
+       {
+               struct drr_freeobjects *drrfo =
+                   &rrd->header.drr_u.drr_freeobjects;
+               return (receive_freeobjects(rwa, drrfo));
+       }
+       case DRR_WRITE:
+       {
+               struct drr_write *drrw = &rrd->header.drr_u.drr_write;
+               err = receive_write(rwa, drrw, rrd->write_buf);
+               /* if receive_write() is successful, it consumes the arc_buf */
+               if (err != 0)
+                       dmu_return_arcbuf(rrd->write_buf);
+               rrd->write_buf = NULL;
+               rrd->payload = NULL;
+               return (err);
+       }
+       case DRR_WRITE_BYREF:
+       {
+               struct drr_write_byref *drrwbr =
+                   &rrd->header.drr_u.drr_write_byref;
+               return (receive_write_byref(rwa, drrwbr));
+       }
+       case DRR_WRITE_EMBEDDED:
+       {
+               struct drr_write_embedded *drrwe =
+                   &rrd->header.drr_u.drr_write_embedded;
+               err = receive_write_embedded(rwa, drrwe, rrd->payload);
+               kmem_free(rrd->payload, rrd->payload_size);
+               rrd->payload = NULL;
+               return (err);
+       }
+       case DRR_FREE:
+       {
+               struct drr_free *drrf = &rrd->header.drr_u.drr_free;
+               return (receive_free(rwa, drrf));
+       }
+       case DRR_SPILL:
+       {
+               struct drr_spill *drrs = &rrd->header.drr_u.drr_spill;
+               err = receive_spill(rwa, drrs, rrd->payload);
+               kmem_free(rrd->payload, rrd->payload_size);
+               rrd->payload = NULL;
+               return (err);
+       }
+       default:
+               return (SET_ERROR(EINVAL));
+       }
+}
+
+/*
+ * dmu_recv_stream's worker thread; pull records off the queue, and then call
+ * receive_process_record  When we're done, signal the main thread and exit.
+ */
+static void
+receive_writer_thread(void *arg)
+{
+       struct receive_writer_arg *rwa = arg;
+       struct receive_record_arg *rrd;
+       fstrans_cookie_t cookie = spl_fstrans_mark();
+
+       for (rrd = bqueue_dequeue(&rwa->q); !rrd->eos_marker;
+           rrd = bqueue_dequeue(&rwa->q)) {
+               /*
+                * If there's an error, the main thread will stop putting things
+                * on the queue, but we need to clear everything in it before we
+                * can exit.
+                */
+               if (rwa->err == 0) {
+                       rwa->err = receive_process_record(rwa, rrd);
+               } else if (rrd->write_buf != NULL) {
+                       dmu_return_arcbuf(rrd->write_buf);
+                       rrd->write_buf = NULL;
+                       rrd->payload = NULL;
+               } else if (rrd->payload != NULL) {
+                       kmem_free(rrd->payload, rrd->payload_size);
+                       rrd->payload = NULL;
+               }
+               kmem_free(rrd, sizeof (*rrd));
+       }
+       kmem_free(rrd, sizeof (*rrd));
+       mutex_enter(&rwa->mutex);
+       rwa->done = B_TRUE;
+       cv_signal(&rwa->cv);
+       mutex_exit(&rwa->mutex);
+       spl_fstrans_unmark(cookie);
+}
+
+static int
+resume_check(struct receive_arg *ra, nvlist_t *begin_nvl)
+{
+       uint64_t val;
+       objset_t *mos = dmu_objset_pool(ra->os)->dp_meta_objset;
+       uint64_t dsobj = dmu_objset_id(ra->os);
+       uint64_t resume_obj, resume_off;
+
+       if (nvlist_lookup_uint64(begin_nvl,
+           "resume_object", &resume_obj) != 0 ||
+           nvlist_lookup_uint64(begin_nvl,
+           "resume_offset", &resume_off) != 0) {
+               return (SET_ERROR(EINVAL));
+       }
+       VERIFY0(zap_lookup(mos, dsobj,
+           DS_FIELD_RESUME_OBJECT, sizeof (val), 1, &val));
+       if (resume_obj != val)
+               return (SET_ERROR(EINVAL));
+       VERIFY0(zap_lookup(mos, dsobj,
+           DS_FIELD_RESUME_OFFSET, sizeof (val), 1, &val));
+       if (resume_off != val)
+               return (SET_ERROR(EINVAL));
+
+       return (0);
 }
 
 /*
+ * Read in the stream's records, one by one, and apply them to the pool.  There
+ * are two threads involved; the thread that calls this function will spin up a
+ * worker thread, read the records off the stream one by one, and issue
+ * prefetches for any necessary indirect blocks.  It will then push the records
+ * onto an internal blocking queue.  The worker thread will pull the records off
+ * the queue, and actually write the data into the DMU.  This way, the worker
+ * thread doesn't have to wait for reads to complete, since everything it needs
+ * (the indirect blocks) will be prefetched.
+ *
  * NB: callers *must* call dmu_recv_end() if this succeeds.
  */
 int
 dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
     int cleanup_fd, uint64_t *action_handlep)
 {
-       struct restorearg ra = { 0 };
-       dmu_replay_record_t *drr;
-       objset_t *os;
-       zio_cksum_t pcksum;
+       int err = 0;
+       struct receive_arg *ra;
+       struct receive_writer_arg *rwa;
        int featureflags;
+       uint32_t payloadlen;
+       void *payload;
+       nvlist_t *begin_nvl = NULL;
+
+       ra = kmem_zalloc(sizeof (*ra), KM_SLEEP);
+       rwa = kmem_zalloc(sizeof (*rwa), KM_SLEEP);
+
+       ra->byteswap = drc->drc_byteswap;
+       ra->cksum = drc->drc_cksum;
+       ra->vp = vp;
+       ra->voff = *voffp;
+
+       if (dsl_dataset_is_zapified(drc->drc_ds)) {
+               (void) zap_lookup(drc->drc_ds->ds_dir->dd_pool->dp_meta_objset,
+                   drc->drc_ds->ds_object, DS_FIELD_RESUME_BYTES,
+                   sizeof (ra->bytes_read), 1, &ra->bytes_read);
+       }
 
-       ra.byteswap = drc->drc_byteswap;
-       ra.cksum = drc->drc_cksum;
-       ra.vp = vp;
-       ra.voff = *voffp;
-       ra.bufsize = SPA_MAXBLOCKSIZE;
-       ra.buf = vmem_alloc(ra.bufsize, KM_SLEEP);
+       objlist_create(&ra->ignore_objlist);
 
        /* these were verified in dmu_recv_begin */
        ASSERT3U(DMU_GET_STREAM_HDRTYPE(drc->drc_drrb->drr_versioninfo), ==,
@@ -1874,7 +2950,7 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
        /*
         * Open the objset we are modifying.
         */
-       VERIFY0(dmu_objset_from_ds(drc->drc_ds, &os));
+       VERIFY0(dmu_objset_from_ds(drc->drc_ds, &ra->os));
 
        ASSERT(dsl_dataset_phys(drc->drc_ds)->ds_flags & DS_FLAG_INCONSISTENT);
 
@@ -1885,136 +2961,143 @@ dmu_recv_stream(dmu_recv_cookie_t *drc, vnode_t *vp, offset_t *voffp,
                minor_t minor;
 
                if (cleanup_fd == -1) {
-                       ra.err = SET_ERROR(EBADF);
+                       ra->err = SET_ERROR(EBADF);
                        goto out;
                }
-               ra.err = zfs_onexit_fd_hold(cleanup_fd, &minor);
-               if (ra.err != 0) {
+               ra->err = zfs_onexit_fd_hold(cleanup_fd, &minor);
+               if (ra->err != 0) {
                        cleanup_fd = -1;
                        goto out;
                }
 
                if (*action_handlep == 0) {
-                       ra.guid_to_ds_map =
+                       rwa->guid_to_ds_map =
                            kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
-                       avl_create(ra.guid_to_ds_map, guid_compare,
+                       avl_create(rwa->guid_to_ds_map, guid_compare,
                            sizeof (guid_map_entry_t),
                            offsetof(guid_map_entry_t, avlnode));
-                       ra.err = zfs_onexit_add_cb(minor,
-                           free_guid_map_onexit, ra.guid_to_ds_map,
+                       err = zfs_onexit_add_cb(minor,
+                           free_guid_map_onexit, rwa->guid_to_ds_map,
                            action_handlep);
-                       if (ra.err != 0)
+                       if (ra->err != 0)
                                goto out;
                } else {
-                       ra.err = zfs_onexit_cb_data(minor, *action_handlep,
-                           (void **)&ra.guid_to_ds_map);
-                       if (ra.err != 0)
+                       err = zfs_onexit_cb_data(minor, *action_handlep,
+                           (void **)&rwa->guid_to_ds_map);
+                       if (ra->err != 0)
                                goto out;
                }
 
-               drc->drc_guid_to_ds_map = ra.guid_to_ds_map;
+               drc->drc_guid_to_ds_map = rwa->guid_to_ds_map;
+       }
+
+       payloadlen = drc->drc_drr_begin->drr_payloadlen;
+       payload = NULL;
+       if (payloadlen != 0)
+               payload = kmem_alloc(payloadlen, KM_SLEEP);
+
+       err = receive_read_payload_and_next_header(ra, payloadlen, payload);
+       if (err != 0) {
+               if (payloadlen != 0)
+                       kmem_free(payload, payloadlen);
+               goto out;
+       }
+       if (payloadlen != 0) {
+               err = nvlist_unpack(payload, payloadlen, &begin_nvl, KM_SLEEP);
+               kmem_free(payload, payloadlen);
+               if (err != 0)
+                       goto out;
+       }
+
+       if (featureflags & DMU_BACKUP_FEATURE_RESUMING) {
+               err = resume_check(ra, begin_nvl);
+               if (err != 0)
+                       goto out;
        }
 
+       (void) bqueue_init(&rwa->q, zfs_recv_queue_length,
+           offsetof(struct receive_record_arg, node));
+       cv_init(&rwa->cv, NULL, CV_DEFAULT, NULL);
+       mutex_init(&rwa->mutex, NULL, MUTEX_DEFAULT, NULL);
+       rwa->os = ra->os;
+       rwa->byteswap = drc->drc_byteswap;
+       rwa->resumable = drc->drc_resumable;
+
+       (void) thread_create(NULL, 0, receive_writer_thread, rwa, 0, curproc,
+           TS_RUN, minclsyspri);
        /*
-        * Read records and process them.
+        * We're reading rwa->err without locks, which is safe since we are the
+        * only reader, and the worker thread is the only writer.  It's ok if we
+        * miss a write for an iteration or two of the loop, since the writer
+        * thread will keep freeing records we send it until we send it an eos
+        * marker.
+        *
+        * We can leave this loop in 3 ways:  First, if rwa->err is
+        * non-zero.  In that case, the writer thread will free the rrd we just
+        * pushed.  Second, if  we're interrupted; in that case, either it's the
+        * first loop and ra->rrd was never allocated, or it's later and ra->rrd
+        * has been handed off to the writer thread who will free it.  Finally,
+        * if receive_read_record fails or we're at the end of the stream, then
+        * we free ra->rrd and exit.
         */
-       pcksum = ra.cksum;
-       while (ra.err == 0 &&
-           NULL != (drr = restore_read(&ra, sizeof (*drr), NULL))) {
+       while (rwa->err == 0) {
                if (issig(JUSTLOOKING) && issig(FORREAL)) {
-                       ra.err = SET_ERROR(EINTR);
-                       goto out;
+                       err = SET_ERROR(EINTR);
+                       break;
                }
 
-               if (ra.byteswap)
-                       backup_byteswap(drr);
+               ASSERT3P(ra->rrd, ==, NULL);
+               ra->rrd = ra->next_rrd;
+               ra->next_rrd = NULL;
+               /* Allocates and loads header into ra->next_rrd */
+               err = receive_read_record(ra);
 
-               switch (drr->drr_type) {
-               case DRR_OBJECT:
-               {
-                       /*
-                        * We need to make a copy of the record header,
-                        * because restore_{object,write} may need to
-                        * restore_read(), which will invalidate drr.
-                        */
-                       struct drr_object drro = drr->drr_u.drr_object;
-                       ra.err = restore_object(&ra, os, &drro);
-                       break;
-               }
-               case DRR_FREEOBJECTS:
-               {
-                       struct drr_freeobjects drrfo =
-                           drr->drr_u.drr_freeobjects;
-                       ra.err = restore_freeobjects(&ra, os, &drrfo);
-                       break;
-               }
-               case DRR_WRITE:
-               {
-                       struct drr_write drrw = drr->drr_u.drr_write;
-                       ra.err = restore_write(&ra, os, &drrw);
-                       break;
-               }
-               case DRR_WRITE_BYREF:
-               {
-                       struct drr_write_byref drrwbr =
-                           drr->drr_u.drr_write_byref;
-                       ra.err = restore_write_byref(&ra, os, &drrwbr);
-                       break;
-               }
-               case DRR_WRITE_EMBEDDED:
-               {
-                       struct drr_write_embedded drrwe =
-                           drr->drr_u.drr_write_embedded;
-                       ra.err = restore_write_embedded(&ra, os, &drrwe);
-                       break;
-               }
-               case DRR_FREE:
-               {
-                       struct drr_free drrf = drr->drr_u.drr_free;
-                       ra.err = restore_free(&ra, os, &drrf);
-                       break;
-               }
-               case DRR_END:
-               {
-                       struct drr_end drre = drr->drr_u.drr_end;
-                       /*
-                        * We compare against the *previous* checksum
-                        * value, because the stored checksum is of
-                        * everything before the DRR_END record.
-                        */
-                       if (!ZIO_CHECKSUM_EQUAL(drre.drr_checksum, pcksum))
-                               ra.err = SET_ERROR(ECKSUM);
-                       goto out;
-               }
-               case DRR_SPILL:
-               {
-                       struct drr_spill drrs = drr->drr_u.drr_spill;
-                       ra.err = restore_spill(&ra, os, &drrs);
+               if (ra->rrd->header.drr_type == DRR_END || err != 0) {
+                       kmem_free(ra->rrd, sizeof (*ra->rrd));
+                       ra->rrd = NULL;
                        break;
                }
-               default:
-                       ra.err = SET_ERROR(EINVAL);
-                       goto out;
-               }
-               pcksum = ra.cksum;
+
+               bqueue_enqueue(&rwa->q, ra->rrd,
+                   sizeof (struct receive_record_arg) + ra->rrd->payload_size);
+               ra->rrd = NULL;
        }
-       ASSERT(ra.err != 0);
+       if (ra->next_rrd == NULL)
+               ra->next_rrd = kmem_zalloc(sizeof (*ra->next_rrd), KM_SLEEP);
+       ra->next_rrd->eos_marker = B_TRUE;
+       bqueue_enqueue(&rwa->q, ra->next_rrd, 1);
+
+       mutex_enter(&rwa->mutex);
+       while (!rwa->done) {
+               cv_wait(&rwa->cv, &rwa->mutex);
+       }
+       mutex_exit(&rwa->mutex);
+
+       cv_destroy(&rwa->cv);
+       mutex_destroy(&rwa->mutex);
+       bqueue_destroy(&rwa->q);
+       if (err == 0)
+               err = rwa->err;
 
 out:
+       nvlist_free(begin_nvl);
        if ((featureflags & DMU_BACKUP_FEATURE_DEDUP) && (cleanup_fd != -1))
                zfs_onexit_fd_rele(cleanup_fd);
 
-       if (ra.err != 0) {
+       if (err != 0) {
                /*
-                * destroy what we created, so we don't leave it in the
-                * inconsistent restoring state.
+                * Clean up references. If receive is not resumable,
+                * destroy what we created, so we don't leave it in
+                * the inconsistent state.
                 */
                dmu_recv_cleanup_ds(drc);
        }
 
-       vmem_free(ra.buf, ra.bufsize);
-       *voffp = ra.voff;
-       return (ra.err);
+       *voffp = ra->voff;
+       objlist_destroy(&ra->ignore_objlist);
+       kmem_free(ra, sizeof (*ra));
+       kmem_free(rwa, sizeof (*rwa));
+       return (err);
 }
 
 static int
@@ -2162,6 +3245,20 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
 
                dmu_buf_will_dirty(ds->ds_dbuf, tx);
                dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
+               if (dsl_dataset_has_resume_receive_state(ds)) {
+                       (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+                           DS_FIELD_RESUME_FROMGUID, tx);
+                       (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+                           DS_FIELD_RESUME_OBJECT, tx);
+                       (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+                           DS_FIELD_RESUME_OFFSET, tx);
+                       (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+                           DS_FIELD_RESUME_BYTES, tx);
+                       (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+                           DS_FIELD_RESUME_TOGUID, tx);
+                       (void) zap_remove(dp->dp_meta_objset, ds->ds_object,
+                           DS_FIELD_RESUME_TONAME, tx);
+               }
        }
        drc->drc_newsnapobj = dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
        zvol_create_minors(dp->dp_spa, drc->drc_tofs, B_TRUE);
@@ -2210,16 +3307,13 @@ dmu_recv_existing_end(dmu_recv_cookie_t *drc)
        int error;
 
 #ifdef _KERNEL
-       char *name;
-
        /*
         * We will be destroying the ds; make sure its origin is unmounted if
         * necessary.
         */
-       name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+       char name[ZFS_MAX_DATASET_NAME_LEN];
        dsl_dataset_name(drc->drc_ds, name);
        zfs_destroy_unmount_origin(name);
-       kmem_free(name, MAXNAMELEN);
 #endif
 
        error = dsl_sync_task(drc->drc_tofs,
index a58f77f082f3dc491d8727701745ac69510c6fe5..a2566ced3211eac30eafa7ae5a3743b4a3950a20 100644 (file)
@@ -39,7 +39,7 @@
 #include <sys/zfeature.h>
 
 int32_t zfs_pd_bytes_max = 50 * 1024 * 1024;   /* 50MB */
-int32_t ignore_hole_birth = 1;
+int32_t send_holes_without_birth_time = 1;
 
 typedef struct prefetch_data {
        kmutex_t pd_mtx;
@@ -48,6 +48,7 @@ typedef struct prefetch_data {
        int pd_flags;
        boolean_t pd_cancel;
        boolean_t pd_exited;
+       zbookmark_phys_t pd_resume;
 } prefetch_data_t;
 
 typedef struct traverse_data {
@@ -159,7 +160,7 @@ resume_skip_check(traverse_data_t *td, const dnode_phys_t *dnp,
                 * If we already visited this bp & everything below,
                 * don't bother doing it again.
                 */
-               if (zbookmark_is_before(dnp, zb, td->td_resume))
+               if (zbookmark_subtree_completed(dnp, zb, td->td_resume))
                        return (RESUME_SKIP_ALL);
 
                /*
@@ -251,9 +252,10 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
                 *
                 * Note that the meta-dnode cannot be reallocated.
                 */
-               if (!ignore_hole_birth && (!td->td_realloc_possible ||
-                       zb->zb_object == DMU_META_DNODE_OBJECT) &&
-                       td->td_hole_birth_enabled_txg <= td->td_min_txg)
+               if (!send_holes_without_birth_time &&
+                   (!td->td_realloc_possible ||
+                   zb->zb_object == DMU_META_DNODE_OBJECT) &&
+                   td->td_hole_birth_enabled_txg <= td->td_min_txg)
                        return (0);
        } else if (bp->blk_birth <= td->td_min_txg) {
                return (0);
@@ -324,30 +326,29 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
                uint32_t flags = ARC_FLAG_WAIT;
                int32_t i;
                int32_t epb = BP_GET_LSIZE(bp) >> DNODE_SHIFT;
-               dnode_phys_t *cdnp;
+               dnode_phys_t *child_dnp;
 
                err = arc_read(NULL, td->td_spa, bp, arc_getbuf_func, &buf,
                    ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
                if (err != 0)
                        goto post;
-               cdnp = buf->b_data;
+               child_dnp = buf->b_data;
 
-               for (i = 0; i < epb; i++) {
-                       prefetch_dnode_metadata(td, &cdnp[i], zb->zb_objset,
-                           zb->zb_blkid * epb + i);
+               for (i = 0; i < epb; i += child_dnp[i].dn_extra_slots + 1) {
+                       prefetch_dnode_metadata(td, &child_dnp[i],
+                           zb->zb_objset, zb->zb_blkid * epb + i);
                }
 
                /* recursively visitbp() blocks below this */
-               for (i = 0; i < epb; i++) {
-                       err = traverse_dnode(td, &cdnp[i], zb->zb_objset,
-                           zb->zb_blkid * epb + i);
+               for (i = 0; i < epb; i += child_dnp[i].dn_extra_slots + 1) {
+                       err = traverse_dnode(td, &child_dnp[i],
+                           zb->zb_objset, zb->zb_blkid * epb + i);
                        if (err != 0)
                                break;
                }
        } else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) {
                arc_flags_t flags = ARC_FLAG_WAIT;
                objset_phys_t *osp;
-               dnode_phys_t *mdnp, *gdnp, *udnp;
 
                err = arc_read(NULL, td->td_spa, bp, arc_getbuf_func, &buf,
                    ZIO_PRIORITY_ASYNC_READ, ZIO_FLAG_CANFAIL, &flags, zb);
@@ -355,11 +356,7 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
                        goto post;
 
                osp = buf->b_data;
-               mdnp = &osp->os_meta_dnode;
-               gdnp = &osp->os_groupused_dnode;
-               udnp = &osp->os_userused_dnode;
-
-               prefetch_dnode_metadata(td, mdnp, zb->zb_objset,
+               prefetch_dnode_metadata(td, &osp->os_meta_dnode, zb->zb_objset,
                    DMU_META_DNODE_OBJECT);
                /*
                 * See the block comment above for the goal of this variable.
@@ -371,26 +368,26 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
                        td->td_realloc_possible = B_FALSE;
 
                if (arc_buf_size(buf) >= sizeof (objset_phys_t)) {
-                       prefetch_dnode_metadata(td, gdnp, zb->zb_objset,
-                           DMU_GROUPUSED_OBJECT);
-                       prefetch_dnode_metadata(td, udnp, zb->zb_objset,
-                           DMU_USERUSED_OBJECT);
+                       prefetch_dnode_metadata(td, &osp->os_groupused_dnode,
+                           zb->zb_objset, DMU_GROUPUSED_OBJECT);
+                       prefetch_dnode_metadata(td, &osp->os_userused_dnode,
+                           zb->zb_objset, DMU_USERUSED_OBJECT);
                }
 
-               err = traverse_dnode(td, mdnp, zb->zb_objset,
+               err = traverse_dnode(td, &osp->os_meta_dnode, zb->zb_objset,
                    DMU_META_DNODE_OBJECT);
                if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
-                       err = traverse_dnode(td, gdnp, zb->zb_objset,
-                           DMU_GROUPUSED_OBJECT);
+                       err = traverse_dnode(td, &osp->os_groupused_dnode,
+                           zb->zb_objset, DMU_GROUPUSED_OBJECT);
                }
                if (err == 0 && arc_buf_size(buf) >= sizeof (objset_phys_t)) {
-                       err = traverse_dnode(td, udnp, zb->zb_objset,
-                           DMU_USERUSED_OBJECT);
+                       err = traverse_dnode(td, &osp->os_userused_dnode,
+                           zb->zb_objset, DMU_USERUSED_OBJECT);
                }
        }
 
        if (buf)
-               (void) arc_buf_remove_ref(buf, &buf);
+               arc_buf_destroy(buf, &buf);
 
 post:
        if (err == 0 && (td->td_flags & TRAVERSE_POST))
@@ -417,9 +414,15 @@ post:
                 * Set the bookmark to the first level-0 block that we need
                 * to visit.  This way, the resuming code does not need to
                 * deal with resuming from indirect blocks.
+                *
+                * Note, if zb_level <= 0, dnp may be NULL, so we don't want
+                * to dereference it.
                 */
-               td->td_resume->zb_blkid = zb->zb_blkid <<
-                   (zb->zb_level * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT));
+               td->td_resume->zb_blkid = zb->zb_blkid;
+               if (zb->zb_level > 0) {
+                       td->td_resume->zb_blkid <<= zb->zb_level *
+                           (dnp->dn_indblkshift - SPA_BLKPTRSHIFT);
+               }
                td->td_paused = B_TRUE;
        }
 
@@ -440,7 +443,7 @@ prefetch_dnode_metadata(traverse_data_t *td, const dnode_phys_t *dnp,
 
        if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) {
                SET_BOOKMARK(&czb, objset, object, 0, DMU_SPILL_BLKID);
-               traverse_prefetch_metadata(td, &dnp->dn_spill, &czb);
+               traverse_prefetch_metadata(td, DN_SPILL_BLKPTR(dnp), &czb);
        }
 }
 
@@ -451,6 +454,21 @@ traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
        int j, err = 0;
        zbookmark_phys_t czb;
 
+       if (object != DMU_META_DNODE_OBJECT && td->td_resume != NULL &&
+           object < td->td_resume->zb_object)
+               return (0);
+
+       if (td->td_flags & TRAVERSE_PRE) {
+               SET_BOOKMARK(&czb, objset, object, ZB_DNODE_LEVEL,
+                   ZB_DNODE_BLKID);
+               err = td->td_func(td->td_spa, NULL, NULL, &czb, dnp,
+                   td->td_arg);
+               if (err == TRAVERSE_VISIT_NO_CHILDREN)
+                       return (0);
+               if (err != 0)
+                       return (err);
+       }
+
        for (j = 0; j < dnp->dn_nblkptr; j++) {
                SET_BOOKMARK(&czb, objset, object, dnp->dn_nlevels - 1, j);
                err = traverse_visitbp(td, dnp, &dnp->dn_blkptr[j], &czb);
@@ -458,9 +476,20 @@ traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
                        break;
        }
 
-       if (err == 0 && dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) {
+       if (err == 0 && (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR)) {
                SET_BOOKMARK(&czb, objset, object, 0, DMU_SPILL_BLKID);
-               err = traverse_visitbp(td, dnp, &dnp->dn_spill, &czb);
+               err = traverse_visitbp(td, dnp, DN_SPILL_BLKPTR(dnp), &czb);
+       }
+
+       if (err == 0 && (td->td_flags & TRAVERSE_POST)) {
+               SET_BOOKMARK(&czb, objset, object, ZB_DNODE_LEVEL,
+                   ZB_DNODE_BLKID);
+               err = td->td_func(td->td_spa, NULL, NULL, &czb, dnp,
+                   td->td_arg);
+               if (err == TRAVERSE_VISIT_NO_CHILDREN)
+                       return (0);
+               if (err != 0)
+                       return (err);
        }
        return (err);
 }
@@ -474,6 +503,8 @@ traverse_prefetcher(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
        arc_flags_t aflags = ARC_FLAG_NOWAIT | ARC_FLAG_PREFETCH;
 
        ASSERT(pfd->pd_bytes_fetched >= 0);
+       if (bp == NULL)
+               return (0);
        if (pfd->pd_cancel)
                return (SET_ERROR(EINTR));
 
@@ -504,6 +535,7 @@ traverse_prefetch_thread(void *arg)
        td.td_func = traverse_prefetcher;
        td.td_arg = td_main->td_pfd;
        td.td_pfd = NULL;
+       td.td_resume = &td_main->td_pfd->pd_resume;
 
        SET_BOOKMARK(&czb, td.td_objset,
            ZB_ROOT_OBJECT, ZB_ROOT_LEVEL, ZB_ROOT_BLKID);
@@ -533,12 +565,6 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
        ASSERT(ds == NULL || objset == ds->ds_object);
        ASSERT(!(flags & TRAVERSE_PRE) || !(flags & TRAVERSE_POST));
 
-       /*
-        * The data prefetching mechanism (the prefetch thread) is incompatible
-        * with resuming from a bookmark.
-        */
-       ASSERT(resume == NULL || !(flags & TRAVERSE_PREFETCH_DATA));
-
        td = kmem_alloc(sizeof (traverse_data_t), KM_SLEEP);
        pd = kmem_zalloc(sizeof (prefetch_data_t), KM_SLEEP);
        czb = kmem_alloc(sizeof (zbookmark_phys_t), KM_SLEEP);
@@ -563,6 +589,8 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
        }
 
        pd->pd_flags = flags;
+       if (resume != NULL)
+               pd->pd_resume = *resume;
        mutex_init(&pd->pd_mtx, NULL, MUTEX_DEFAULT, NULL);
        cv_init(&pd->pd_cv, NULL, CV_DEFAULT, NULL);
 
@@ -583,7 +611,7 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
 
                osp = buf->b_data;
                traverse_zil(td, &osp->os_zil_header);
-               (void) arc_buf_remove_ref(buf, &buf);
+               arc_buf_destroy(buf, &buf);
        }
 
        if (!(flags & TRAVERSE_PREFETCH_DATA) ||
@@ -615,11 +643,19 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
  * in syncing context).
  */
 int
-traverse_dataset(dsl_dataset_t *ds, uint64_t txg_start, int flags,
-    blkptr_cb_t func, void *arg)
+traverse_dataset_resume(dsl_dataset_t *ds, uint64_t txg_start,
+    zbookmark_phys_t *resume,
+    int flags, blkptr_cb_t func, void *arg)
 {
        return (traverse_impl(ds->ds_dir->dd_pool->dp_spa, ds, ds->ds_object,
-           &dsl_dataset_phys(ds)->ds_bp, txg_start, NULL, flags, func, arg));
+           &dsl_dataset_phys(ds)->ds_bp, txg_start, resume, flags, func, arg));
+}
+
+int
+traverse_dataset(dsl_dataset_t *ds, uint64_t txg_start,
+    int flags, blkptr_cb_t func, void *arg)
+{
+       return (traverse_dataset_resume(ds, txg_start, NULL, flags, func, arg));
 }
 
 int
@@ -652,7 +688,7 @@ traverse_pool(spa_t *spa, uint64_t txg_start, int flags,
 
        /* visit each dataset */
        for (obj = 1; err == 0;
-           err = dmu_object_next(mos, &obj, FALSE, txg_start)) {
+           err = dmu_object_next(mos, &obj, B_FALSE, txg_start)) {
                dmu_object_info_t doi;
 
                err = dmu_object_info(mos, obj, &doi);
@@ -694,6 +730,11 @@ EXPORT_SYMBOL(traverse_pool);
 module_param(zfs_pd_bytes_max, int, 0644);
 MODULE_PARM_DESC(zfs_pd_bytes_max, "Max number of bytes to prefetch");
 
-module_param(ignore_hole_birth, int, 0644);
-MODULE_PARM_DESC(ignore_hole_birth, "Ignore hole_birth txg for send");
+module_param_named(ignore_hole_birth, send_holes_without_birth_time, int, 0644);
+MODULE_PARM_DESC(ignore_hole_birth, "Alias for send_holes_without_birth_time");
+
+module_param_named(send_holes_without_birth_time,
+       send_holes_without_birth_time, int, 0644);
+MODULE_PARM_DESC(send_holes_without_birth_time,
+       "Ignore hole_birth txg for zfs send");
 #endif
index 5ae429f70866264ce059c715d5d83ae2c3ece80b..d8bd7cb787ba15d8309673e407c6d6c6bfbc5929 100644 (file)
@@ -21,7 +21,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
- * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  */
 
 #include <sys/dmu.h>
@@ -332,7 +332,8 @@ dmu_tx_count_write(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
                        dmu_buf_impl_t *db;
 
                        rw_enter(&dn->dn_struct_rwlock, RW_READER);
-                       err = dbuf_hold_impl(dn, 0, start, FALSE, FTAG, &db);
+                       err = dbuf_hold_impl(dn, 0, start,
+                           FALSE, FALSE, FTAG, &db);
                        rw_exit(&dn->dn_struct_rwlock);
 
                        if (err) {
@@ -408,7 +409,7 @@ dmu_tx_count_dnode(dmu_tx_hold_t *txh)
        dnode_t *dn = txh->txh_dnode;
        dnode_t *mdn = DMU_META_DNODE(txh->txh_tx->tx_objset);
        uint64_t space = mdn->dn_datablksz +
-           ((mdn->dn_nlevels-1) << mdn->dn_indblkshift);
+           ((uint64_t)(mdn->dn_nlevels-1) << mdn->dn_indblkshift);
 
        if (dn && dn->dn_dbuf->db_blkptr &&
            dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
@@ -533,7 +534,8 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
                blkoff = P2PHASE(blkid, epb);
                tochk = MIN(epb - blkoff, nblks);
 
-               err = dbuf_hold_impl(dn, 1, blkid >> epbs, FALSE, FTAG, &dbuf);
+               err = dbuf_hold_impl(dn, 1, blkid >> epbs,
+                   FALSE, FALSE, FTAG, &dbuf);
                if (err) {
                        txh->txh_tx->tx_err = err;
                        break;
@@ -608,6 +610,32 @@ dmu_tx_count_free(dmu_tx_hold_t *txh, uint64_t off, uint64_t len)
        txh->txh_space_tounref += unref;
 }
 
+/*
+ * This function marks the transaction as being a "net free".  The end
+ * result is that refquotas will be disabled for this transaction, and
+ * this transaction will be able to use half of the pool space overhead
+ * (see dsl_pool_adjustedsize()).  Therefore this function should only
+ * be called for transactions that we expect will not cause a net increase
+ * in the amount of space used (but it's OK if that is occasionally not true).
+ */
+void
+dmu_tx_mark_netfree(dmu_tx_t *tx)
+{
+       dmu_tx_hold_t *txh;
+
+       txh = dmu_tx_hold_object_impl(tx, tx->tx_objset,
+           DMU_NEW_OBJECT, THT_FREE, 0, 0);
+
+       /*
+        * Pretend that this operation will free 1GB of space.  This
+        * should be large enough to cancel out the largest write.
+        * We don't want to use something like UINT64_MAX, because that would
+        * cause overflows when doing math with these values (e.g. in
+        * dmu_tx_try_assign()).
+        */
+       txh->txh_space_tofree = txh->txh_space_tounref = 1024 * 1024 * 1024;
+}
+
 void
 dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off, uint64_t len)
 {
@@ -766,15 +794,14 @@ dmu_tx_hold_zap(dmu_tx_t *tx, uint64_t object, int add, const char *name)
                 * access the name in this fat-zap so that we'll check
                 * for i/o errors to the leaf blocks, etc.
                 */
-               err = zap_lookup(dn->dn_objset, dn->dn_object, name,
-                   8, 0, NULL);
+               err = zap_lookup_by_dnode(dn, name, 8, 0, NULL);
                if (err == EIO) {
                        tx->tx_err = err;
                        return;
                }
        }
 
-       err = zap_count_write(dn->dn_objset, dn->dn_object, name, add,
+       err = zap_count_write_by_dnode(dn, name, add,
            &txh->txh_space_towrite, &txh->txh_space_tooverwrite);
 
        /*
@@ -1558,7 +1585,7 @@ dmu_tx_hold_spill(dmu_tx_t *tx, uint64_t object)
        } else {
                blkptr_t *bp;
 
-               bp = &dn->dn_phys->dn_spill;
+               bp = DN_SPILL_BLKPTR(dn->dn_phys);
                if (dsl_dataset_block_freeable(dn->dn_objset->os_dsl_dataset,
                    bp, bp->blk_birth))
                        txh->txh_space_tooverwrite += SPA_OLD_MAXBLOCKSIZE;
@@ -1590,7 +1617,7 @@ dmu_tx_hold_sa_create(dmu_tx_t *tx, int attrsize)
 
        dmu_tx_sa_registration_hold(sa, tx);
 
-       if (attrsize <= DN_MAX_BONUSLEN && !sa->sa_force_spill)
+       if (attrsize <= DN_OLD_MAX_BONUSLEN && !sa->sa_force_spill)
                return;
 
        (void) dmu_tx_hold_object_impl(tx, tx->tx_objset, DMU_NEW_OBJECT,
index 8ff2f0509787cf8061960cf77eef166f57145b07..baed0492f9066df062f0f810ea48751e9cb9f7c4 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
 #include <sys/kstat.h>
 
 /*
- * I'm against tune-ables, but these should probably exist as tweakable globals
- * until we can get this working the way we want it to.
+ * This tunable disables predictive prefetch.  Note that it leaves "prescient"
+ * prefetch (e.g. prefetch for zfs send) intact.  Unlike predictive prefetch,
+ * prescient prefetch never issues i/os that end up not being needed,
+ * so it can't hurt performance.
  */
 
-int zfs_prefetch_disable = 0;
+int zfs_prefetch_disable = B_FALSE;
 
 /* max # of streams per zfetch */
 unsigned int   zfetch_max_streams = 8;
 /* min time before stream reclaim */
 unsigned int   zfetch_min_sec_reap = 2;
-/* max number of blocks to fetch at a time */
-unsigned int   zfetch_block_cap = 256;
-/* number of bytes in a array_read at which we stop prefetching (1Mb) */
+/* max bytes to prefetch per stream (default 8MB) */
+unsigned int   zfetch_max_distance = 8 * 1024 * 1024;
+/* max bytes to prefetch indirects for per stream (default 64MB) */
+unsigned int   zfetch_max_idistance = 64 * 1024 * 1024;
+/* max number of bytes in an array_read in which we allow prefetching (1MB) */
 unsigned long  zfetch_array_rd_sz = 1024 * 1024;
 
-/* forward decls for static routines */
-static boolean_t       dmu_zfetch_colinear(zfetch_t *, zstream_t *);
-static void            dmu_zfetch_dofetch(zfetch_t *, zstream_t *);
-static uint64_t                dmu_zfetch_fetch(dnode_t *, uint64_t, uint64_t);
-static uint64_t                dmu_zfetch_fetchsz(dnode_t *, uint64_t, uint64_t);
-static boolean_t       dmu_zfetch_find(zfetch_t *, zstream_t *, int);
-static int             dmu_zfetch_stream_insert(zfetch_t *, zstream_t *);
-static zstream_t       *dmu_zfetch_stream_reclaim(zfetch_t *);
-static void            dmu_zfetch_stream_remove(zfetch_t *, zstream_t *);
-static int             dmu_zfetch_streams_equal(zstream_t *, zstream_t *);
-
 typedef struct zfetch_stats {
        kstat_named_t zfetchstat_hits;
        kstat_named_t zfetchstat_misses;
-       kstat_named_t zfetchstat_colinear_hits;
-       kstat_named_t zfetchstat_colinear_misses;
-       kstat_named_t zfetchstat_stride_hits;
-       kstat_named_t zfetchstat_stride_misses;
-       kstat_named_t zfetchstat_reclaim_successes;
-       kstat_named_t zfetchstat_reclaim_failures;
-       kstat_named_t zfetchstat_stream_resets;
-       kstat_named_t zfetchstat_stream_noresets;
-       kstat_named_t zfetchstat_bogus_streams;
+       kstat_named_t zfetchstat_max_streams;
 } zfetch_stats_t;
 
 static zfetch_stats_t zfetch_stats = {
        { "hits",                       KSTAT_DATA_UINT64 },
        { "misses",                     KSTAT_DATA_UINT64 },
-       { "colinear_hits",              KSTAT_DATA_UINT64 },
-       { "colinear_misses",            KSTAT_DATA_UINT64 },
-       { "stride_hits",                KSTAT_DATA_UINT64 },
-       { "stride_misses",              KSTAT_DATA_UINT64 },
-       { "reclaim_successes",          KSTAT_DATA_UINT64 },
-       { "reclaim_failures",           KSTAT_DATA_UINT64 },
-       { "streams_resets",             KSTAT_DATA_UINT64 },
-       { "streams_noresets",           KSTAT_DATA_UINT64 },
-       { "bogus_streams",              KSTAT_DATA_UINT64 },
+       { "max_streams",                KSTAT_DATA_UINT64 },
 };
 
-#define        ZFETCHSTAT_INCR(stat, val) \
-       atomic_add_64(&zfetch_stats.stat.value.ui64, (val));
-
-#define        ZFETCHSTAT_BUMP(stat)           ZFETCHSTAT_INCR(stat, 1);
+#define        ZFETCHSTAT_BUMP(stat) \
+       atomic_inc_64(&zfetch_stats.stat.value.ui64);
 
 kstat_t                *zfetch_ksp;
 
-/*
- * Given a zfetch structure and a zstream structure, determine whether the
- * blocks to be read are part of a co-linear pair of existing prefetch
- * streams.  If a set is found, coalesce the streams, removing one, and
- * configure the prefetch so it looks for a strided access pattern.
- *
- * In other words: if we find two sequential access streams that are
- * the same length and distance N appart, and this read is N from the
- * last stream, then we are probably in a strided access pattern.  So
- * combine the two sequential streams into a single strided stream.
- *
- * Returns whether co-linear streams were found.
- */
-static boolean_t
-dmu_zfetch_colinear(zfetch_t *zf, zstream_t *zh)
-{
-       zstream_t       *z_walk;
-       zstream_t       *z_comp;
-
-       if (! rw_tryenter(&zf->zf_rwlock, RW_WRITER))
-               return (0);
-
-       if (zh == NULL) {
-               rw_exit(&zf->zf_rwlock);
-               return (0);
-       }
-
-       for (z_walk = list_head(&zf->zf_stream); z_walk;
-           z_walk = list_next(&zf->zf_stream, z_walk)) {
-               for (z_comp = list_next(&zf->zf_stream, z_walk); z_comp;
-                   z_comp = list_next(&zf->zf_stream, z_comp)) {
-                       int64_t         diff;
-
-                       if (z_walk->zst_len != z_walk->zst_stride ||
-                           z_comp->zst_len != z_comp->zst_stride) {
-                               continue;
-                       }
-
-                       diff = z_comp->zst_offset - z_walk->zst_offset;
-                       if (z_comp->zst_offset + diff == zh->zst_offset) {
-                               z_walk->zst_offset = zh->zst_offset;
-                               z_walk->zst_direction = diff < 0 ?
-                                   ZFETCH_BACKWARD : ZFETCH_FORWARD;
-                               z_walk->zst_stride =
-                                   diff * z_walk->zst_direction;
-                               z_walk->zst_ph_offset =
-                                   zh->zst_offset + z_walk->zst_stride;
-                               dmu_zfetch_stream_remove(zf, z_comp);
-                               mutex_destroy(&z_comp->zst_lock);
-                               kmem_free(z_comp, sizeof (zstream_t));
-
-                               dmu_zfetch_dofetch(zf, z_walk);
-
-                               rw_exit(&zf->zf_rwlock);
-                               return (1);
-                       }
-
-                       diff = z_walk->zst_offset - z_comp->zst_offset;
-                       if (z_walk->zst_offset + diff == zh->zst_offset) {
-                               z_walk->zst_offset = zh->zst_offset;
-                               z_walk->zst_direction = diff < 0 ?
-                                   ZFETCH_BACKWARD : ZFETCH_FORWARD;
-                               z_walk->zst_stride =
-                                   diff * z_walk->zst_direction;
-                               z_walk->zst_ph_offset =
-                                   zh->zst_offset + z_walk->zst_stride;
-                               dmu_zfetch_stream_remove(zf, z_comp);
-                               mutex_destroy(&z_comp->zst_lock);
-                               kmem_free(z_comp, sizeof (zstream_t));
-
-                               dmu_zfetch_dofetch(zf, z_walk);
-
-                               rw_exit(&zf->zf_rwlock);
-                               return (1);
-                       }
-               }
-       }
-
-       rw_exit(&zf->zf_rwlock);
-       return (0);
-}
-
-/*
- * Given a zstream_t, determine the bounds of the prefetch.  Then call the
- * routine that actually prefetches the individual blocks.
- */
-static void
-dmu_zfetch_dofetch(zfetch_t *zf, zstream_t *zs)
-{
-       uint64_t        prefetch_tail;
-       uint64_t        prefetch_limit;
-       uint64_t        prefetch_ofst;
-       uint64_t        prefetch_len;
-       uint64_t        blocks_fetched;
-
-       zs->zst_stride = MAX((int64_t)zs->zst_stride, zs->zst_len);
-       zs->zst_cap = MIN(zfetch_block_cap, 2 * zs->zst_cap);
-
-       prefetch_tail = MAX((int64_t)zs->zst_ph_offset,
-           (int64_t)(zs->zst_offset + zs->zst_stride));
-       /*
-        * XXX: use a faster division method?
-        */
-       prefetch_limit = zs->zst_offset + zs->zst_len +
-           (zs->zst_cap * zs->zst_stride) / zs->zst_len;
-
-       while (prefetch_tail < prefetch_limit) {
-               prefetch_ofst = zs->zst_offset + zs->zst_direction *
-                   (prefetch_tail - zs->zst_offset);
-
-               prefetch_len = zs->zst_len;
-
-               /*
-                * Don't prefetch beyond the end of the file, if working
-                * backwards.
-                */
-               if ((zs->zst_direction == ZFETCH_BACKWARD) &&
-                   (prefetch_ofst > prefetch_tail)) {
-                       prefetch_len += prefetch_ofst;
-                       prefetch_ofst = 0;
-               }
-
-               /* don't prefetch more than we're supposed to */
-               if (prefetch_len > zs->zst_len)
-                       break;
-
-               blocks_fetched = dmu_zfetch_fetch(zf->zf_dnode,
-                   prefetch_ofst, zs->zst_len);
-
-               prefetch_tail += zs->zst_stride;
-               /* stop if we've run out of stuff to prefetch */
-               if (blocks_fetched < zs->zst_len)
-                       break;
-       }
-       zs->zst_ph_offset = prefetch_tail;
-       zs->zst_last = ddi_get_lbolt();
-}
-
 void
 zfetch_init(void)
 {
-
        zfetch_ksp = kstat_create("zfs", 0, "zfetchstats", "misc",
            KSTAT_TYPE_NAMED, sizeof (zfetch_stats) / sizeof (kstat_named_t),
            KSTAT_FLAG_VIRTUAL);
@@ -266,272 +102,41 @@ zfetch_fini(void)
 void
 dmu_zfetch_init(zfetch_t *zf, dnode_t *dno)
 {
-       if (zf == NULL) {
+       if (zf == NULL)
                return;
-       }
 
        zf->zf_dnode = dno;
-       zf->zf_stream_cnt = 0;
-       zf->zf_alloc_fail = 0;
 
        list_create(&zf->zf_stream, sizeof (zstream_t),
-           offsetof(zstream_t, zst_node));
+           offsetof(zstream_t, zs_node));
 
        rw_init(&zf->zf_rwlock, NULL, RW_DEFAULT, NULL);
 }
 
-/*
- * This function computes the actual size, in blocks, that can be prefetched,
- * and fetches it.
- */
-static uint64_t
-dmu_zfetch_fetch(dnode_t *dn, uint64_t blkid, uint64_t nblks)
-{
-       uint64_t        fetchsz;
-       uint64_t        i;
-
-       fetchsz = dmu_zfetch_fetchsz(dn, blkid, nblks);
-
-       for (i = 0; i < fetchsz; i++) {
-               dbuf_prefetch(dn, blkid + i, ZIO_PRIORITY_ASYNC_READ);
-       }
-
-       return (fetchsz);
-}
-
-/*
- * this function returns the number of blocks that would be prefetched, based
- * upon the supplied dnode, blockid, and nblks.  This is used so that we can
- * update streams in place, and then prefetch with their old value after the
- * fact.  This way, we can delay the prefetch, but subsequent accesses to the
- * stream won't result in the same data being prefetched multiple times.
- */
-static uint64_t
-dmu_zfetch_fetchsz(dnode_t *dn, uint64_t blkid, uint64_t nblks)
-{
-       uint64_t        fetchsz;
-
-       if (blkid > dn->dn_maxblkid) {
-               return (0);
-       }
-
-       /* compute fetch size */
-       if (blkid + nblks + 1 > dn->dn_maxblkid) {
-               fetchsz = (dn->dn_maxblkid - blkid) + 1;
-               ASSERT(blkid + fetchsz - 1 <= dn->dn_maxblkid);
-       } else {
-               fetchsz = nblks;
-       }
-
-
-       return (fetchsz);
-}
-
-/*
- * given a zfetch and a zstream structure, see if there is an associated zstream
- * for this block read.  If so, it starts a prefetch for the stream it
- * located and returns true, otherwise it returns false
- */
-static boolean_t
-dmu_zfetch_find(zfetch_t *zf, zstream_t *zh, int prefetched)
+static void
+dmu_zfetch_stream_remove(zfetch_t *zf, zstream_t *zs)
 {
-       zstream_t       *zs;
-       int64_t         diff;
-       int             reset = !prefetched;
-       int             rc = 0;
-
-       if (zh == NULL)
-               return (0);
-
-       /*
-        * XXX: This locking strategy is a bit coarse; however, it's impact has
-        * yet to be tested.  If this turns out to be an issue, it can be
-        * modified in a number of different ways.
-        */
-
-       rw_enter(&zf->zf_rwlock, RW_READER);
-top:
-
-       for (zs = list_head(&zf->zf_stream); zs;
-           zs = list_next(&zf->zf_stream, zs)) {
-
-               /*
-                * XXX - should this be an assert?
-                */
-               if (zs->zst_len == 0) {
-                       /* bogus stream */
-                       ZFETCHSTAT_BUMP(zfetchstat_bogus_streams);
-                       continue;
-               }
-
-               /*
-                * We hit this case when we are in a strided prefetch stream:
-                * we will read "len" blocks before "striding".
-                */
-               if (zh->zst_offset >= zs->zst_offset &&
-                   zh->zst_offset < zs->zst_offset + zs->zst_len) {
-                       if (prefetched) {
-                               /* already fetched */
-                               ZFETCHSTAT_BUMP(zfetchstat_stride_hits);
-                               rc = 1;
-                               goto out;
-                       } else {
-                               ZFETCHSTAT_BUMP(zfetchstat_stride_misses);
-                       }
-               }
-
-               /*
-                * This is the forward sequential read case: we increment
-                * len by one each time we hit here, so we will enter this
-                * case on every read.
-                */
-               if (zh->zst_offset == zs->zst_offset + zs->zst_len) {
-
-                       reset = !prefetched && zs->zst_len > 1;
-
-                       mutex_enter(&zs->zst_lock);
-
-                       if (zh->zst_offset != zs->zst_offset + zs->zst_len) {
-                               mutex_exit(&zs->zst_lock);
-                               goto top;
-                       }
-                       zs->zst_len += zh->zst_len;
-                       diff = zs->zst_len - zfetch_block_cap;
-                       if (diff > 0) {
-                               zs->zst_offset += diff;
-                               zs->zst_len = zs->zst_len > diff ?
-                                   zs->zst_len - diff : 0;
-                       }
-                       zs->zst_direction = ZFETCH_FORWARD;
-
-                       break;
-
-               /*
-                * Same as above, but reading backwards through the file.
-                */
-               } else if (zh->zst_offset == zs->zst_offset - zh->zst_len) {
-                       /* backwards sequential access */
-
-                       reset = !prefetched && zs->zst_len > 1;
-
-                       mutex_enter(&zs->zst_lock);
-
-                       if (zh->zst_offset != zs->zst_offset - zh->zst_len) {
-                               mutex_exit(&zs->zst_lock);
-                               goto top;
-                       }
-
-                       zs->zst_offset = zs->zst_offset > zh->zst_len ?
-                           zs->zst_offset - zh->zst_len : 0;
-                       zs->zst_ph_offset = zs->zst_ph_offset > zh->zst_len ?
-                           zs->zst_ph_offset - zh->zst_len : 0;
-                       zs->zst_len += zh->zst_len;
-
-                       diff = zs->zst_len - zfetch_block_cap;
-                       if (diff > 0) {
-                               zs->zst_ph_offset = zs->zst_ph_offset > diff ?
-                                   zs->zst_ph_offset - diff : 0;
-                               zs->zst_len = zs->zst_len > diff ?
-                                   zs->zst_len - diff : zs->zst_len;
-                       }
-                       zs->zst_direction = ZFETCH_BACKWARD;
-
-                       break;
-
-               } else if ((zh->zst_offset - zs->zst_offset - zs->zst_stride <
-                   zs->zst_len) && (zs->zst_len != zs->zst_stride)) {
-                       /* strided forward access */
-
-                       mutex_enter(&zs->zst_lock);
-
-                       if ((zh->zst_offset - zs->zst_offset - zs->zst_stride >=
-                           zs->zst_len) || (zs->zst_len == zs->zst_stride)) {
-                               mutex_exit(&zs->zst_lock);
-                               goto top;
-                       }
-
-                       zs->zst_offset += zs->zst_stride;
-                       zs->zst_direction = ZFETCH_FORWARD;
-
-                       break;
-
-               } else if ((zh->zst_offset - zs->zst_offset + zs->zst_stride <
-                   zs->zst_len) && (zs->zst_len != zs->zst_stride)) {
-                       /* strided reverse access */
-
-                       mutex_enter(&zs->zst_lock);
-
-                       if ((zh->zst_offset - zs->zst_offset + zs->zst_stride >=
-                           zs->zst_len) || (zs->zst_len == zs->zst_stride)) {
-                               mutex_exit(&zs->zst_lock);
-                               goto top;
-                       }
-
-                       zs->zst_offset = zs->zst_offset > zs->zst_stride ?
-                           zs->zst_offset - zs->zst_stride : 0;
-                       zs->zst_ph_offset = (zs->zst_ph_offset >
-                           (2 * zs->zst_stride)) ?
-                           (zs->zst_ph_offset - (2 * zs->zst_stride)) : 0;
-                       zs->zst_direction = ZFETCH_BACKWARD;
-
-                       break;
-               }
-       }
-
-       if (zs) {
-               if (reset) {
-                       zstream_t *remove = zs;
-
-                       ZFETCHSTAT_BUMP(zfetchstat_stream_resets);
-                       rc = 0;
-                       mutex_exit(&zs->zst_lock);
-                       rw_exit(&zf->zf_rwlock);
-                       rw_enter(&zf->zf_rwlock, RW_WRITER);
-                       /*
-                        * Relocate the stream, in case someone removes
-                        * it while we were acquiring the WRITER lock.
-                        */
-                       for (zs = list_head(&zf->zf_stream); zs;
-                           zs = list_next(&zf->zf_stream, zs)) {
-                               if (zs == remove) {
-                                       dmu_zfetch_stream_remove(zf, zs);
-                                       mutex_destroy(&zs->zst_lock);
-                                       kmem_free(zs, sizeof (zstream_t));
-                                       break;
-                               }
-                       }
-               } else {
-                       ZFETCHSTAT_BUMP(zfetchstat_stream_noresets);
-                       rc = 1;
-                       dmu_zfetch_dofetch(zf, zs);
-                       mutex_exit(&zs->zst_lock);
-               }
-       }
-out:
-       rw_exit(&zf->zf_rwlock);
-       return (rc);
+       ASSERT(RW_WRITE_HELD(&zf->zf_rwlock));
+       list_remove(&zf->zf_stream, zs);
+       mutex_destroy(&zs->zs_lock);
+       kmem_free(zs, sizeof (*zs));
 }
 
 /*
- * Clean-up state associated with a zfetch structure.  This frees allocated
- * structure members, empties the zf_stream tree, and generally makes things
- * nice.  This doesn't free the zfetch_t itself, that's left to the caller.
+ * Clean-up state associated with a zfetch structure (e.g. destroy the
+ * streams).  This doesn't free the zfetch_t itself, that's left to the caller.
  */
 void
-dmu_zfetch_rele(zfetch_t *zf)
+dmu_zfetch_fini(zfetch_t *zf)
 {
-       zstream_t       *zs;
-       zstream_t       *zs_next;
+       zstream_t *zs;
 
        ASSERT(!RW_LOCK_HELD(&zf->zf_rwlock));
 
-       for (zs = list_head(&zf->zf_stream); zs; zs = zs_next) {
-               zs_next = list_next(&zf->zf_stream, zs);
-
-               list_remove(&zf->zf_stream, zs);
-               mutex_destroy(&zs->zst_lock);
-               kmem_free(zs, sizeof (zstream_t));
-       }
+       rw_enter(&zf->zf_rwlock, RW_WRITER);
+       while ((zs = list_head(&zf->zf_stream)) != NULL)
+               dmu_zfetch_stream_remove(zf, zs);
+       rw_exit(&zf->zf_rwlock);
        list_destroy(&zf->zf_stream);
        rw_destroy(&zf->zf_rwlock);
 
@@ -539,195 +144,195 @@ dmu_zfetch_rele(zfetch_t *zf)
 }
 
 /*
- * Given a zfetch and zstream structure, insert the zstream structure into the
- * AVL tree contained within the zfetch structure.  Peform the appropriate
- * book-keeping.  It is possible that another thread has inserted a stream which
- * matches one that we are about to insert, so we must be sure to check for this
- * case.  If one is found, return failure, and let the caller cleanup the
- * duplicates.
+ * If there aren't too many streams already, create a new stream.
+ * The "blkid" argument is the next block that we expect this stream to access.
+ * While we're here, clean up old streams (which haven't been
+ * accessed for at least zfetch_min_sec_reap seconds).
  */
-static int
-dmu_zfetch_stream_insert(zfetch_t *zf, zstream_t *zs)
+static void
+dmu_zfetch_stream_create(zfetch_t *zf, uint64_t blkid)
 {
-       zstream_t       *zs_walk;
-       zstream_t       *zs_next;
+       zstream_t *zs;
+       zstream_t *zs_next;
+       int numstreams = 0;
+       uint32_t max_streams;
 
        ASSERT(RW_WRITE_HELD(&zf->zf_rwlock));
 
-       for (zs_walk = list_head(&zf->zf_stream); zs_walk; zs_walk = zs_next) {
-               zs_next = list_next(&zf->zf_stream, zs_walk);
-
-               if (dmu_zfetch_streams_equal(zs_walk, zs)) {
-                       return (0);
-               }
-       }
-
-       list_insert_head(&zf->zf_stream, zs);
-       zf->zf_stream_cnt++;
-       return (1);
-}
-
-
-/*
- * Walk the list of zstreams in the given zfetch, find an old one (by time), and
- * reclaim it for use by the caller.
- */
-static zstream_t *
-dmu_zfetch_stream_reclaim(zfetch_t *zf)
-{
-       zstream_t       *zs;
-
-       if (! rw_tryenter(&zf->zf_rwlock, RW_WRITER))
-               return (0);
-
-       for (zs = list_head(&zf->zf_stream); zs;
-           zs = list_next(&zf->zf_stream, zs)) {
-
-               if (((ddi_get_lbolt() - zs->zst_last)/hz) > zfetch_min_sec_reap)
-                       break;
+       /*
+        * Clean up old streams.
+        */
+       for (zs = list_head(&zf->zf_stream);
+           zs != NULL; zs = zs_next) {
+               zs_next = list_next(&zf->zf_stream, zs);
+               if (((gethrtime() - zs->zs_atime) / NANOSEC) >
+                   zfetch_min_sec_reap)
+                       dmu_zfetch_stream_remove(zf, zs);
+               else
+                       numstreams++;
        }
 
-       if (zs) {
-               dmu_zfetch_stream_remove(zf, zs);
-               mutex_destroy(&zs->zst_lock);
-               bzero(zs, sizeof (zstream_t));
-       } else {
-               zf->zf_alloc_fail++;
+       /*
+        * The maximum number of streams is normally zfetch_max_streams,
+        * but for small files we lower it such that it's at least possible
+        * for all the streams to be non-overlapping.
+        *
+        * If we are already at the maximum number of streams for this file,
+        * even after removing old streams, then don't create this stream.
+        */
+       max_streams = MAX(1, MIN(zfetch_max_streams,
+           zf->zf_dnode->dn_maxblkid * zf->zf_dnode->dn_datablksz /
+           zfetch_max_distance));
+       if (numstreams >= max_streams) {
+               ZFETCHSTAT_BUMP(zfetchstat_max_streams);
+               return;
        }
-       rw_exit(&zf->zf_rwlock);
 
-       return (zs);
-}
-
-/*
- * Given a zfetch and zstream structure, remove the zstream structure from its
- * container in the zfetch structure.  Perform the appropriate book-keeping.
- */
-static void
-dmu_zfetch_stream_remove(zfetch_t *zf, zstream_t *zs)
-{
-       ASSERT(RW_WRITE_HELD(&zf->zf_rwlock));
-
-       list_remove(&zf->zf_stream, zs);
-       zf->zf_stream_cnt--;
-}
-
-static int
-dmu_zfetch_streams_equal(zstream_t *zs1, zstream_t *zs2)
-{
-       if (zs1->zst_offset != zs2->zst_offset)
-               return (0);
-
-       if (zs1->zst_len != zs2->zst_len)
-               return (0);
+       zs = kmem_zalloc(sizeof (*zs), KM_SLEEP);
+       zs->zs_blkid = blkid;
+       zs->zs_pf_blkid = blkid;
+       zs->zs_ipf_blkid = blkid;
+       zs->zs_atime = gethrtime();
+       mutex_init(&zs->zs_lock, NULL, MUTEX_DEFAULT, NULL);
 
-       if (zs1->zst_stride != zs2->zst_stride)
-               return (0);
-
-       if (zs1->zst_ph_offset != zs2->zst_ph_offset)
-               return (0);
-
-       if (zs1->zst_cap != zs2->zst_cap)
-               return (0);
-
-       if (zs1->zst_direction != zs2->zst_direction)
-               return (0);
-
-       return (1);
+       list_insert_head(&zf->zf_stream, zs);
 }
 
 /*
- * This is the prefetch entry point.  It calls all of the other dmu_zfetch
- * routines to create, delete, find, or operate upon prefetch streams.
+ * This is the predictive prefetch entry point.  It associates dnode access
+ * specified with blkid and nblks arguments with prefetch stream, predicts
+ * further accesses based on that stats and initiates speculative prefetch.
+ * fetch_data argument specifies whether actual data blocks should be fetched:
+ *   FALSE -- prefetch only indirect blocks for predicted data blocks;
+ *   TRUE -- prefetch predicted data blocks plus following indirect blocks.
  */
 void
-dmu_zfetch(zfetch_t *zf, uint64_t offset, uint64_t size, int prefetched)
+dmu_zfetch(zfetch_t *zf, uint64_t blkid, uint64_t nblks, boolean_t fetch_data)
 {
-       zstream_t       zst;
-       zstream_t       *newstream;
-       boolean_t       fetched;
-       int             inserted;
-       unsigned int    blkshft;
-       uint64_t        blksz;
+       zstream_t *zs;
+       int64_t pf_start, ipf_start, ipf_istart, ipf_iend;
+       int64_t pf_ahead_blks, max_blks, iblk;
+       int epbs, max_dist_blks, pf_nblks, ipf_nblks, i;
+       uint64_t end_of_access_blkid;
+       end_of_access_blkid = blkid + nblks;
 
        if (zfs_prefetch_disable)
                return;
 
-       /* files that aren't ln2 blocksz are only one block -- nothing to do */
-       if (!zf->zf_dnode->dn_datablkshift)
+       /*
+        * As a fast path for small (single-block) files, ignore access
+        * to the first block.
+        */
+       if (blkid == 0)
                return;
 
-       /* convert offset and size, into blockid and nblocks */
-       blkshft = zf->zf_dnode->dn_datablkshift;
-       blksz = (1 << blkshft);
+       rw_enter(&zf->zf_rwlock, RW_READER);
 
-       bzero(&zst, sizeof (zstream_t));
-       zst.zst_offset = offset >> blkshft;
-       zst.zst_len = (P2ROUNDUP(offset + size, blksz) -
-           P2ALIGN(offset, blksz)) >> blkshft;
+       for (zs = list_head(&zf->zf_stream); zs != NULL;
+           zs = list_next(&zf->zf_stream, zs)) {
+               if (blkid == zs->zs_blkid) {
+                       mutex_enter(&zs->zs_lock);
+                       /*
+                        * zs_blkid could have changed before we
+                        * acquired zs_lock; re-check them here.
+                        */
+                       if (blkid != zs->zs_blkid) {
+                               mutex_exit(&zs->zs_lock);
+                               continue;
+                       }
+                       break;
+               }
+       }
 
-       fetched = dmu_zfetch_find(zf, &zst, prefetched);
-       if (fetched) {
-               ZFETCHSTAT_BUMP(zfetchstat_hits);
-       } else {
+       if (zs == NULL) {
+               /*
+                * This access is not part of any existing stream.  Create
+                * a new stream for it.
+                */
                ZFETCHSTAT_BUMP(zfetchstat_misses);
-               if ((fetched = dmu_zfetch_colinear(zf, &zst))) {
-                       ZFETCHSTAT_BUMP(zfetchstat_colinear_hits);
-               } else {
-                       ZFETCHSTAT_BUMP(zfetchstat_colinear_misses);
-               }
+               if (rw_tryupgrade(&zf->zf_rwlock))
+                       dmu_zfetch_stream_create(zf, end_of_access_blkid);
+               rw_exit(&zf->zf_rwlock);
+               return;
        }
 
-       if (!fetched) {
-               newstream = dmu_zfetch_stream_reclaim(zf);
+       /*
+        * This access was to a block that we issued a prefetch for on
+        * behalf of this stream. Issue further prefetches for this stream.
+        *
+        * Normally, we start prefetching where we stopped
+        * prefetching last (zs_pf_blkid).  But when we get our first
+        * hit on this stream, zs_pf_blkid == zs_blkid, we don't
+        * want to prefetch the block we just accessed.  In this case,
+        * start just after the block we just accessed.
+        */
+       pf_start = MAX(zs->zs_pf_blkid, end_of_access_blkid);
 
+       /*
+        * Double our amount of prefetched data, but don't let the
+        * prefetch get further ahead than zfetch_max_distance.
+        */
+       if (fetch_data) {
+               max_dist_blks =
+                   zfetch_max_distance >> zf->zf_dnode->dn_datablkshift;
                /*
-                * we still couldn't find a stream, drop the lock, and allocate
-                * one if possible.  Otherwise, give up and go home.
+                * Previously, we were (zs_pf_blkid - blkid) ahead.  We
+                * want to now be double that, so read that amount again,
+                * plus the amount we are catching up by (i.e. the amount
+                * read just now).
                 */
-               if (newstream) {
-                       ZFETCHSTAT_BUMP(zfetchstat_reclaim_successes);
-               } else {
-                       uint64_t        maxblocks;
-                       uint32_t        max_streams;
-                       uint32_t        cur_streams;
-
-                       ZFETCHSTAT_BUMP(zfetchstat_reclaim_failures);
-                       cur_streams = zf->zf_stream_cnt;
-                       maxblocks = zf->zf_dnode->dn_maxblkid;
-
-                       max_streams = MIN(zfetch_max_streams,
-                           (maxblocks / zfetch_block_cap));
-                       if (max_streams == 0) {
-                               max_streams++;
-                       }
-
-                       if (cur_streams >= max_streams) {
-                               return;
-                       }
-                       newstream =
-                           kmem_zalloc(sizeof (zstream_t), KM_SLEEP);
-               }
+               pf_ahead_blks = zs->zs_pf_blkid - blkid + nblks;
+               max_blks = max_dist_blks - (pf_start - end_of_access_blkid);
+               pf_nblks = MIN(pf_ahead_blks, max_blks);
+       } else {
+               pf_nblks = 0;
+       }
 
-               newstream->zst_offset = zst.zst_offset;
-               newstream->zst_len = zst.zst_len;
-               newstream->zst_stride = zst.zst_len;
-               newstream->zst_ph_offset = zst.zst_len + zst.zst_offset;
-               newstream->zst_cap = zst.zst_len;
-               newstream->zst_direction = ZFETCH_FORWARD;
-               newstream->zst_last = ddi_get_lbolt();
+       zs->zs_pf_blkid = pf_start + pf_nblks;
 
-               mutex_init(&newstream->zst_lock, NULL, MUTEX_DEFAULT, NULL);
+       /*
+        * Do the same for indirects, starting from where we stopped last,
+        * or where we will stop reading data blocks (and the indirects
+        * that point to them).
+        */
+       ipf_start = MAX(zs->zs_ipf_blkid, zs->zs_pf_blkid);
+       max_dist_blks = zfetch_max_idistance >> zf->zf_dnode->dn_datablkshift;
+       /*
+        * We want to double our distance ahead of the data prefetch
+        * (or reader, if we are not prefetching data).  Previously, we
+        * were (zs_ipf_blkid - blkid) ahead.  To double that, we read
+        * that amount again, plus the amount we are catching up by
+        * (i.e. the amount read now + the amount of data prefetched now).
+        */
+       pf_ahead_blks = zs->zs_ipf_blkid - blkid + nblks + pf_nblks;
+       max_blks = max_dist_blks - (ipf_start - end_of_access_blkid);
+       ipf_nblks = MIN(pf_ahead_blks, max_blks);
+       zs->zs_ipf_blkid = ipf_start + ipf_nblks;
+
+       epbs = zf->zf_dnode->dn_indblkshift - SPA_BLKPTRSHIFT;
+       ipf_istart = P2ROUNDUP(ipf_start, 1 << epbs) >> epbs;
+       ipf_iend = P2ROUNDUP(zs->zs_ipf_blkid, 1 << epbs) >> epbs;
+
+       zs->zs_atime = gethrtime();
+       zs->zs_blkid = end_of_access_blkid;
+       mutex_exit(&zs->zs_lock);
+       rw_exit(&zf->zf_rwlock);
 
-               rw_enter(&zf->zf_rwlock, RW_WRITER);
-               inserted = dmu_zfetch_stream_insert(zf, newstream);
-               rw_exit(&zf->zf_rwlock);
+       /*
+        * dbuf_prefetch() is asynchronous (even when it needs to read
+        * indirect blocks), but we still prefer to drop our locks before
+        * calling it to reduce the time we hold them.
+        */
 
-               if (!inserted) {
-                       mutex_destroy(&newstream->zst_lock);
-                       kmem_free(newstream, sizeof (zstream_t));
-               }
+       for (i = 0; i < pf_nblks; i++) {
+               dbuf_prefetch(zf->zf_dnode, 0, pf_start + i,
+                   ZIO_PRIORITY_ASYNC_READ, ARC_FLAG_PREDICTIVE_PREFETCH);
+       }
+       for (iblk = ipf_istart; iblk < ipf_iend; iblk++) {
+               dbuf_prefetch(zf->zf_dnode, 1, iblk,
+                   ZIO_PRIORITY_ASYNC_READ, ARC_FLAG_PREDICTIVE_PREFETCH);
        }
+       ZFETCHSTAT_BUMP(zfetchstat_hits);
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
@@ -740,8 +345,9 @@ MODULE_PARM_DESC(zfetch_max_streams, "Max number of streams per zfetch");
 module_param(zfetch_min_sec_reap, uint, 0644);
 MODULE_PARM_DESC(zfetch_min_sec_reap, "Min time before stream reclaim");
 
-module_param(zfetch_block_cap, uint, 0644);
-MODULE_PARM_DESC(zfetch_block_cap, "Max number of blocks to fetch at a time");
+module_param(zfetch_max_distance, uint, 0644);
+MODULE_PARM_DESC(zfetch_max_distance,
+       "Max bytes to prefetch per stream (default 8MB)");
 
 module_param(zfetch_array_rd_sz, ulong, 0644);
 MODULE_PARM_DESC(zfetch_array_rd_sz, "Number of bytes in a array_read");
index 2858bbfb492ea74f81e241cab6fb84f9f94f931e..6ba8207e2bcf8be5f7bcbb6741d25026d93946c5 100644 (file)
@@ -69,19 +69,13 @@ dbuf_compare(const void *x1, const void *x2)
        const dmu_buf_impl_t *d1 = x1;
        const dmu_buf_impl_t *d2 = x2;
 
-       if (d1->db_level < d2->db_level) {
-               return (-1);
-       }
-       if (d1->db_level > d2->db_level) {
-               return (1);
-       }
+       int cmp = AVL_CMP(d1->db_level, d2->db_level);
+       if (likely(cmp))
+               return (cmp);
 
-       if (d1->db_blkid < d2->db_blkid) {
-               return (-1);
-       }
-       if (d1->db_blkid > d2->db_blkid) {
-               return (1);
-       }
+       cmp = AVL_CMP(d1->db_blkid, d2->db_blkid);
+       if (likely(cmp))
+               return (cmp);
 
        if (d1->db_state == DB_SEARCH) {
                ASSERT3S(d2->db_state, !=, DB_SEARCH);
@@ -91,13 +85,7 @@ dbuf_compare(const void *x1, const void *x2)
                return (1);
        }
 
-       if ((uintptr_t)d1 < (uintptr_t)d2) {
-               return (-1);
-       }
-       if ((uintptr_t)d1 > (uintptr_t)d2) {
-               return (1);
-       }
-       return (0);
+       return (AVL_PCMP(d1, d2));
 }
 
 /* ARGSUSED */
@@ -107,7 +95,7 @@ dnode_cons(void *arg, void *unused, int kmflag)
        dnode_t *dn = arg;
        int i;
 
-       rw_init(&dn->dn_struct_rwlock, NULL, RW_DEFAULT, NULL);
+       rw_init(&dn->dn_struct_rwlock, NULL, RW_NOLOCKDEP, NULL);
        mutex_init(&dn->dn_mtx, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&dn->dn_dbufs_mtx, NULL, MUTEX_DEFAULT, NULL);
        cv_init(&dn->dn_notxholds, NULL, CV_DEFAULT, NULL);
@@ -248,6 +236,7 @@ dnode_verify(dnode_t *dn)
        }
        if (dn->dn_phys->dn_type != DMU_OT_NONE || dn->dn_allocated_txg != 0) {
                int i;
+               int max_bonuslen = DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots);
                ASSERT3U(dn->dn_indblkshift, <=, SPA_MAXBLOCKSHIFT);
                if (dn->dn_datablkshift) {
                        ASSERT3U(dn->dn_datablkshift, >=, SPA_MINBLOCKSHIFT);
@@ -258,12 +247,12 @@ dnode_verify(dnode_t *dn)
                ASSERT(DMU_OT_IS_VALID(dn->dn_type));
                ASSERT3U(dn->dn_nblkptr, >=, 1);
                ASSERT3U(dn->dn_nblkptr, <=, DN_MAX_NBLKPTR);
-               ASSERT3U(dn->dn_bonuslen, <=, DN_MAX_BONUSLEN);
+               ASSERT3U(dn->dn_bonuslen, <=, max_bonuslen);
                ASSERT3U(dn->dn_datablksz, ==,
                    dn->dn_datablkszsec << SPA_MINBLOCKSHIFT);
                ASSERT3U(ISP2(dn->dn_datablksz), ==, dn->dn_datablkshift != 0);
                ASSERT3U((dn->dn_nblkptr - 1) * sizeof (blkptr_t) +
-                   dn->dn_bonuslen, <=, DN_MAX_BONUSLEN);
+                   dn->dn_bonuslen, <=, max_bonuslen);
                for (i = 0; i < TXG_SIZE; i++) {
                        ASSERT3U(dn->dn_next_nlevels[i], <=, dn->dn_nlevels);
                }
@@ -294,6 +283,7 @@ dnode_byteswap(dnode_phys_t *dnp)
 
        dnp->dn_datablkszsec = BSWAP_16(dnp->dn_datablkszsec);
        dnp->dn_bonuslen = BSWAP_16(dnp->dn_bonuslen);
+       dnp->dn_extra_slots = BSWAP_8(dnp->dn_extra_slots);
        dnp->dn_maxblkid = BSWAP_64(dnp->dn_maxblkid);
        dnp->dn_used = BSWAP_64(dnp->dn_used);
 
@@ -320,7 +310,8 @@ dnode_byteswap(dnode_phys_t *dnp)
                 * dnode buffer).
                 */
                int off = (dnp->dn_nblkptr-1) * sizeof (blkptr_t);
-               size_t len = DN_MAX_BONUSLEN - off;
+               int slots = dnp->dn_extra_slots + 1;
+               size_t len = DN_SLOTS_TO_BONUSLEN(slots) - off;
                dmu_object_byteswap_t byteswap;
                ASSERT(DMU_OT_IS_VALID(dnp->dn_bonustype));
                byteswap = DMU_OT_BYTESWAP(dnp->dn_bonustype);
@@ -329,23 +320,24 @@ dnode_byteswap(dnode_phys_t *dnp)
 
        /* Swap SPILL block if we have one */
        if (dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR)
-               byteswap_uint64_array(&dnp->dn_spill, sizeof (blkptr_t));
-
+               byteswap_uint64_array(DN_SPILL_BLKPTR(dnp), sizeof (blkptr_t));
 }
 
 void
 dnode_buf_byteswap(void *vbuf, size_t size)
 {
-       dnode_phys_t *buf = vbuf;
-       int i;
+       int i = 0;
 
        ASSERT3U(sizeof (dnode_phys_t), ==, (1<<DNODE_SHIFT));
        ASSERT((size & (sizeof (dnode_phys_t)-1)) == 0);
 
-       size >>= DNODE_SHIFT;
-       for (i = 0; i < size; i++) {
-               dnode_byteswap(buf);
-               buf++;
+       while (i < size) {
+               dnode_phys_t *dnp = vbuf + i;
+               dnode_byteswap(dnp);
+
+               i += DNODE_MIN_SIZE;
+               if (dnp->dn_type != DMU_OT_NONE)
+                       i += dnp->dn_extra_slots * DNODE_MIN_SIZE;
        }
 }
 
@@ -356,7 +348,7 @@ dnode_setbonuslen(dnode_t *dn, int newsize, dmu_tx_t *tx)
 
        dnode_setdirty(dn, tx);
        rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
-       ASSERT3U(newsize, <=, DN_MAX_BONUSLEN -
+       ASSERT3U(newsize, <=, DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots) -
            (dn->dn_nblkptr-1) * sizeof (blkptr_t));
        dn->dn_bonuslen = newsize;
        if (newsize == 0)
@@ -434,6 +426,7 @@ dnode_create(objset_t *os, dnode_phys_t *dnp, dmu_buf_impl_t *db,
        dn->dn_compress = dnp->dn_compress;
        dn->dn_bonustype = dnp->dn_bonustype;
        dn->dn_bonuslen = dnp->dn_bonuslen;
+       dn->dn_num_slots = dnp->dn_extra_slots + 1;
        dn->dn_maxblkid = dnp->dn_maxblkid;
        dn->dn_have_spill = ((dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) != 0);
        dn->dn_id_flags = 0;
@@ -470,7 +463,7 @@ dnode_create(objset_t *os, dnode_phys_t *dnp, dmu_buf_impl_t *db,
        dnh->dnh_dnode = dn;
        mutex_exit(&os->os_lock);
 
-       arc_space_consume(sizeof (dnode_t), ARC_SPACE_OTHER);
+       arc_space_consume(sizeof (dnode_t), ARC_SPACE_DNODE);
        return (dn);
 }
 
@@ -509,7 +502,7 @@ dnode_destroy(dnode_t *dn)
        }
        if (dn->dn_bonus != NULL) {
                mutex_enter(&dn->dn_bonus->db_mtx);
-               dbuf_evict(dn->dn_bonus);
+               dbuf_destroy(dn->dn_bonus);
                dn->dn_bonus = NULL;
        }
        dn->dn_zio = NULL;
@@ -524,9 +517,9 @@ dnode_destroy(dnode_t *dn)
        dn->dn_id_flags = 0;
        dn->dn_unlisted_l0_blkid = 0;
 
-       dmu_zfetch_rele(&dn->dn_zfetch);
+       dmu_zfetch_fini(&dn->dn_zfetch);
        kmem_cache_free(dnode_cache, dn);
-       arc_space_return(sizeof (dnode_t), ARC_SPACE_OTHER);
+       arc_space_return(sizeof (dnode_t), ARC_SPACE_DNODE);
 
        if (complete_os_eviction)
                dmu_objset_evict_done(os);
@@ -534,10 +527,13 @@ dnode_destroy(dnode_t *dn)
 
 void
 dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
-    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+    dmu_object_type_t bonustype, int bonuslen, int dn_slots, dmu_tx_t *tx)
 {
        int i;
 
+       ASSERT3U(dn_slots, >, 0);
+       ASSERT3U(dn_slots << DNODE_SHIFT, <=,
+           spa_maxdnodesize(dmu_objset_spa(dn->dn_objset)));
        ASSERT3U(blocksize, <=,
            spa_maxblocksize(dmu_objset_spa(dn->dn_objset)));
        if (blocksize == 0)
@@ -550,8 +546,8 @@ dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
 
        ibs = MIN(MAX(ibs, DN_MIN_INDBLKSHIFT), DN_MAX_INDBLKSHIFT);
 
-       dprintf("os=%p obj=%llu txg=%llu blocksize=%d ibs=%d\n", dn->dn_objset,
-           dn->dn_object, tx->tx_txg, blocksize, ibs);
+       dprintf("os=%p obj=%llu txg=%llu blocksize=%d ibs=%d dn_slots=%d\n",
+           dn->dn_objset, dn->dn_object, tx->tx_txg, blocksize, ibs, dn_slots);
 
        ASSERT(dn->dn_type == DMU_OT_NONE);
        ASSERT(bcmp(dn->dn_phys, &dnode_phys_zero, sizeof (dnode_phys_t)) == 0);
@@ -562,7 +558,7 @@ dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
            (bonustype == DMU_OT_SA && bonuslen == 0) ||
            (bonustype != DMU_OT_NONE && bonuslen != 0));
        ASSERT(DMU_OT_IS_VALID(bonustype));
-       ASSERT3U(bonuslen, <=, DN_MAX_BONUSLEN);
+       ASSERT3U(bonuslen, <=, DN_SLOTS_TO_BONUSLEN(dn_slots));
        ASSERT(dn->dn_type == DMU_OT_NONE);
        ASSERT0(dn->dn_maxblkid);
        ASSERT0(dn->dn_allocated_txg);
@@ -588,11 +584,15 @@ dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
        dnode_setdblksz(dn, blocksize);
        dn->dn_indblkshift = ibs;
        dn->dn_nlevels = 1;
+       dn->dn_num_slots = dn_slots;
        if (bonustype == DMU_OT_SA) /* Maximize bonus space for SA */
                dn->dn_nblkptr = 1;
-       else
-               dn->dn_nblkptr = 1 +
-                   ((DN_MAX_BONUSLEN - bonuslen) >> SPA_BLKPTRSHIFT);
+       else {
+               dn->dn_nblkptr = MIN(DN_MAX_NBLKPTR,
+                   1 + ((DN_SLOTS_TO_BONUSLEN(dn_slots) - bonuslen) >>
+                   SPA_BLKPTRSHIFT));
+       }
+
        dn->dn_bonustype = bonustype;
        dn->dn_bonuslen = bonuslen;
        dn->dn_checksum = ZIO_CHECKSUM_INHERIT;
@@ -617,7 +617,7 @@ dnode_allocate(dnode_t *dn, dmu_object_type_t ot, int blocksize, int ibs,
 
 void
 dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
-    dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+    dmu_object_type_t bonustype, int bonuslen, int dn_slots, dmu_tx_t *tx)
 {
        int nblkptr;
 
@@ -631,7 +631,10 @@ dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
            (bonustype != DMU_OT_NONE && bonuslen != 0) ||
            (bonustype == DMU_OT_SA && bonuslen == 0));
        ASSERT(DMU_OT_IS_VALID(bonustype));
-       ASSERT3U(bonuslen, <=, DN_MAX_BONUSLEN);
+       ASSERT3U(bonuslen, <=,
+               DN_BONUS_SIZE(spa_maxdnodesize(dmu_objset_spa(dn->dn_objset))));
+
+       dn_slots = dn_slots > 0 ? dn_slots : DNODE_MIN_SLOTS;
 
        /* clean up any unreferenced dbufs */
        dnode_evict_dbufs(dn);
@@ -654,7 +657,9 @@ dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
        if (bonustype == DMU_OT_SA) /* Maximize bonus space for SA */
                nblkptr = 1;
        else
-               nblkptr = 1 + ((DN_MAX_BONUSLEN - bonuslen) >> SPA_BLKPTRSHIFT);
+               nblkptr = MIN(DN_MAX_NBLKPTR,
+                   1 + ((DN_SLOTS_TO_BONUSLEN(dn_slots) - bonuslen) >>
+                   SPA_BLKPTRSHIFT));
        if (dn->dn_bonustype != bonustype)
                dn->dn_next_bonustype[tx->tx_txg&TXG_MASK] = bonustype;
        if (dn->dn_nblkptr != nblkptr)
@@ -672,6 +677,7 @@ dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
        mutex_enter(&dn->dn_mtx);
        dn->dn_bonustype = bonustype;
        dn->dn_bonuslen = bonuslen;
+       dn->dn_num_slots = dn_slots;
        dn->dn_nblkptr = nblkptr;
        dn->dn_checksum = ZIO_CHECKSUM_INHERIT;
        dn->dn_compress = ZIO_COMPRESS_INHERIT;
@@ -680,7 +686,8 @@ dnode_reallocate(dnode_t *dn, dmu_object_type_t ot, int blocksize,
        /* fix up the bonus db_size */
        if (dn->dn_bonus) {
                dn->dn_bonus->db.db_size =
-                   DN_MAX_BONUSLEN - (dn->dn_nblkptr-1) * sizeof (blkptr_t);
+                   DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots) -
+                   (dn->dn_nblkptr-1) * sizeof (blkptr_t);
                ASSERT(dn->dn_bonuslen <= dn->dn_bonus->db.db_size);
        }
 
@@ -773,8 +780,6 @@ dnode_move_impl(dnode_t *odn, dnode_t *ndn)
        dmu_zfetch_init(&ndn->dn_zfetch, NULL);
        list_move_tail(&ndn->dn_zfetch.zf_stream, &odn->dn_zfetch.zf_stream);
        ndn->dn_zfetch.zf_dnode = odn->dn_zfetch.zf_dnode;
-       ndn->dn_zfetch.zf_stream_cnt = odn->dn_zfetch.zf_stream_cnt;
-       ndn->dn_zfetch.zf_alloc_fail = odn->dn_zfetch.zf_alloc_fail;
 
        /*
         * Update back pointers. Updating the handle fixes the back pointer of
@@ -1054,25 +1059,151 @@ dnode_buf_pageout(void *dbu)
            children_dnodes->dnc_count * sizeof (dnode_handle_t));
 }
 
+/*
+ * Return true if the given index is interior to a dnode already
+ * allocated in the block. That is, the index is neither free nor
+ * allocated, but is consumed by a large dnode.
+ *
+ * The dnode_phys_t buffer may not be in sync with the in-core dnode
+ * structure, so we try to check the dnode structure first and fall back
+ * to the dnode_phys_t buffer it doesn't exist.
+ */
+static boolean_t
+dnode_is_consumed(dmu_buf_impl_t *db, int idx)
+{
+       dnode_handle_t *dnh;
+       dmu_object_type_t ot;
+       dnode_children_t *children_dnodes;
+       dnode_phys_t *dn_block;
+       int skip;
+       int i;
+
+       children_dnodes = dmu_buf_get_user(&db->db);
+       dn_block = (dnode_phys_t *)db->db.db_data;
+
+       for (i = 0; i < idx; i += skip) {
+               dnh = &children_dnodes->dnc_children[i];
+
+               zrl_add(&dnh->dnh_zrlock);
+               if (dnh->dnh_dnode != NULL) {
+                       ot = dnh->dnh_dnode->dn_type;
+                       skip = dnh->dnh_dnode->dn_num_slots;
+               } else {
+                       ot = dn_block[i].dn_type;
+                       skip = dn_block[i].dn_extra_slots + 1;
+               }
+               zrl_remove(&dnh->dnh_zrlock);
+
+               if (ot == DMU_OT_NONE)
+                       skip = 1;
+       }
+
+       return (i > idx);
+}
+
+/*
+ * Return true if the given index in the dnode block is a valid
+ * allocated dnode. That is, the index is not consumed by a large
+ * dnode and is not free.
+ *
+ * The dnode_phys_t buffer may not be in sync with the in-core dnode
+ * structure, so we try to check the dnode structure first and fall back
+ * to the dnode_phys_t buffer it doesn't exist.
+ */
+static boolean_t
+dnode_is_allocated(dmu_buf_impl_t *db, int idx)
+{
+       dnode_handle_t *dnh;
+       dmu_object_type_t ot;
+       dnode_children_t *children_dnodes;
+       dnode_phys_t *dn_block;
+
+       if (dnode_is_consumed(db, idx))
+               return (B_FALSE);
+
+       children_dnodes = dmu_buf_get_user(&db->db);
+       dn_block = (dnode_phys_t *)db->db.db_data;
+
+       dnh = &children_dnodes->dnc_children[idx];
+
+       zrl_add(&dnh->dnh_zrlock);
+       if (dnh->dnh_dnode != NULL)
+               ot = dnh->dnh_dnode->dn_type;
+       else
+               ot = dn_block[idx].dn_type;
+       zrl_remove(&dnh->dnh_zrlock);
+
+       return (ot != DMU_OT_NONE);
+}
+
+/*
+ * Return true if the given range of indices in the dnode block are
+ * free. That is, the starting index is not consumed by a large dnode
+ * and none of the indices are allocated.
+ *
+ * The dnode_phys_t buffer may not be in sync with the in-core dnode
+ * structure, so we try to check the dnode structure first and fall back
+ * to the dnode_phys_t buffer it doesn't exist.
+ */
+static boolean_t
+dnode_is_free(dmu_buf_impl_t *db, int idx, int slots)
+{
+       dnode_handle_t *dnh;
+       dmu_object_type_t ot;
+       dnode_children_t *children_dnodes;
+       dnode_phys_t *dn_block;
+       int i;
+
+       if (idx + slots > DNODES_PER_BLOCK)
+               return (B_FALSE);
+
+       children_dnodes = dmu_buf_get_user(&db->db);
+       dn_block = (dnode_phys_t *)db->db.db_data;
+
+       if (dnode_is_consumed(db, idx))
+               return (B_FALSE);
+
+       for (i = idx; i < idx + slots; i++) {
+               dnh = &children_dnodes->dnc_children[i];
+
+               zrl_add(&dnh->dnh_zrlock);
+               if (dnh->dnh_dnode != NULL)
+                       ot = dnh->dnh_dnode->dn_type;
+               else
+                       ot = dn_block[i].dn_type;
+               zrl_remove(&dnh->dnh_zrlock);
+
+               if (ot != DMU_OT_NONE)
+                       return (B_FALSE);
+       }
+
+       return (B_TRUE);
+}
+
 /*
  * errors:
  * EINVAL - invalid object number.
+ * ENOSPC - hole too small to fulfill "slots" request
  * EIO - i/o error.
  * succeeds even for free dnodes.
  */
 int
-dnode_hold_impl(objset_t *os, uint64_t object, int flag,
+dnode_hold_impl(objset_t *os, uint64_t object, int flag, int slots,
     void *tag, dnode_t **dnp)
 {
-       int epb, idx, err;
+       int epb, idx, err, i;
        int drop_struct_lock = FALSE;
        int type;
        uint64_t blk;
        dnode_t *mdn, *dn;
        dmu_buf_impl_t *db;
        dnode_children_t *children_dnodes;
+       dnode_phys_t *dn_block_begin;
        dnode_handle_t *dnh;
 
+       ASSERT(!(flag & DNODE_MUST_BE_ALLOCATED) || (slots == 0));
+       ASSERT(!(flag & DNODE_MUST_BE_FREE) || (slots > 0));
+
        /*
         * If you are holding the spa config lock as writer, you shouldn't
         * be asking the DMU to do *anything* unless it's the root pool
@@ -1112,7 +1243,7 @@ dnode_hold_impl(objset_t *os, uint64_t object, int flag,
                drop_struct_lock = TRUE;
        }
 
-       blk = dbuf_whichblock(mdn, object * sizeof (dnode_phys_t));
+       blk = dbuf_whichblock(mdn, 0, object * sizeof (dnode_phys_t));
 
        db = dbuf_hold(mdn, blk, FTAG);
        if (drop_struct_lock)
@@ -1128,12 +1259,9 @@ dnode_hold_impl(objset_t *os, uint64_t object, int flag,
        ASSERT3U(db->db.db_size, >=, 1<<DNODE_SHIFT);
        epb = db->db.db_size >> DNODE_SHIFT;
 
-       idx = object & (epb-1);
-
        ASSERT(DB_DNODE(db)->dn_type == DMU_OT_DNODE);
        children_dnodes = dmu_buf_get_user(&db->db);
        if (children_dnodes == NULL) {
-               int i;
                dnode_children_t *winner;
                children_dnodes = kmem_zalloc(sizeof (dnode_children_t) +
                    epb * sizeof (dnode_handle_t), KM_SLEEP);
@@ -1158,21 +1286,28 @@ dnode_hold_impl(objset_t *os, uint64_t object, int flag,
        }
        ASSERT(children_dnodes->dnc_count == epb);
 
+       idx = object & (epb - 1);
+       dn_block_begin = (dnode_phys_t *)db->db.db_data;
+
+       if ((flag & DNODE_MUST_BE_FREE) && !dnode_is_free(db, idx, slots)) {
+               dbuf_rele(db, FTAG);
+               return (ENOSPC);
+       } else if ((flag & DNODE_MUST_BE_ALLOCATED) &&
+           !dnode_is_allocated(db, idx)) {
+               dbuf_rele(db, FTAG);
+               return (ENOENT);
+       }
+
        dnh = &children_dnodes->dnc_children[idx];
        zrl_add(&dnh->dnh_zrlock);
        dn = dnh->dnh_dnode;
-       if (dn == NULL) {
-               dnode_phys_t *phys = (dnode_phys_t *)db->db.db_data+idx;
-
-               dn = dnode_create(os, phys, db, object, dnh);
-       }
+       if (dn == NULL)
+               dn = dnode_create(os, dn_block_begin + idx, db, object, dnh);
 
        mutex_enter(&dn->dn_mtx);
        type = dn->dn_type;
        if (dn->dn_free_txg ||
-           ((flag & DNODE_MUST_BE_ALLOCATED) && type == DMU_OT_NONE) ||
-           ((flag & DNODE_MUST_BE_FREE) &&
-           (type != DMU_OT_NONE || !refcount_is_zero(&dn->dn_holds)))) {
+           ((flag & DNODE_MUST_BE_FREE) && !refcount_is_zero(&dn->dn_holds))) {
                mutex_exit(&dn->dn_mtx);
                zrl_remove(&dnh->dnh_zrlock);
                dbuf_rele(db, FTAG);
@@ -1200,7 +1335,8 @@ dnode_hold_impl(objset_t *os, uint64_t object, int flag,
 int
 dnode_hold(objset_t *os, uint64_t object, void *tag, dnode_t **dnp)
 {
-       return (dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED, tag, dnp));
+       return (dnode_hold_impl(os, object, DNODE_MUST_BE_ALLOCATED, 0, tag,
+           dnp));
 }
 
 /*
@@ -1409,7 +1545,7 @@ dnode_set_blksz(dnode_t *dn, uint64_t size, int ibs, dmu_tx_t *tx)
                goto fail;
 
        /* resize the old block */
-       err = dbuf_hold_impl(dn, 0, 0, TRUE, FTAG, &db);
+       err = dbuf_hold_impl(dn, 0, 0, TRUE, FALSE, FTAG, &db);
        if (err == 0)
                dbuf_new_size(db, size, tx);
        else if (err != ENOENT)
@@ -1476,6 +1612,8 @@ dnode_new_blkid(dnode_t *dn, uint64_t blkid, dmu_tx_t *tx, boolean_t have_read)
            sz <= blkid && sz >= dn->dn_nblkptr; sz <<= epbs)
                new_nlevels++;
 
+       ASSERT3U(new_nlevels, <=, DN_MAX_LEVELS);
+
        if (new_nlevels > dn->dn_nlevels) {
                int old_nlevels = dn->dn_nlevels;
                dmu_buf_impl_t *db;
@@ -1582,8 +1720,8 @@ dnode_free_range(dnode_t *dn, uint64_t off, uint64_t len, dmu_tx_t *tx)
                ASSERT3U(blkoff + head, ==, blksz);
                if (len < head)
                        head = len;
-               if (dbuf_hold_impl(dn, 0, dbuf_whichblock(dn, off), TRUE,
-                   FTAG, &db) == 0) {
+               if (dbuf_hold_impl(dn, 0, dbuf_whichblock(dn, 0, off),
+                   TRUE, FALSE, FTAG, &db) == 0) {
                        caddr_t data;
 
                        /* don't dirty if it isn't on disk and isn't dirty */
@@ -1620,8 +1758,8 @@ dnode_free_range(dnode_t *dn, uint64_t off, uint64_t len, dmu_tx_t *tx)
        if (tail) {
                if (len < tail)
                        tail = len;
-               if (dbuf_hold_impl(dn, 0, dbuf_whichblock(dn, off+len),
-                   TRUE, FTAG, &db) == 0) {
+               if (dbuf_hold_impl(dn, 0, dbuf_whichblock(dn, 0, off+len),
+                   TRUE, FALSE, FTAG, &db) == 0) {
                        /* don't dirty if not on disk and not dirty */
                        if (db->db_last_dirty ||
                            (db->db_blkptr && !BP_IS_HOLE(db->db_blkptr))) {
@@ -1853,7 +1991,7 @@ dnode_willuse_space(dnode_t *dn, int64_t space, dmu_tx_t *tx)
  */
 static int
 dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
-       int lvl, uint64_t blkfill, uint64_t txg)
+    int lvl, uint64_t blkfill, uint64_t txg)
 {
        dmu_buf_impl_t *db = NULL;
        void *data = NULL;
@@ -1863,9 +2001,6 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
        boolean_t hole;
        int i, inc, error, span;
 
-       dprintf("probing object %llu offset %llx level %d of %u\n",
-           dn->dn_object, *offset, lvl, dn->dn_phys->dn_nlevels);
-
        hole = ((flags & DNODE_FIND_HOLE) != 0);
        inc = (flags & DNODE_FIND_BACKWARDS) ? -1 : 1;
        ASSERT(txg == 0 || !hole);
@@ -1875,8 +2010,8 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
                epb = dn->dn_phys->dn_nblkptr;
                data = dn->dn_phys->dn_blkptr;
        } else {
-               uint64_t blkid = dbuf_whichblock(dn, *offset) >> (epbs * lvl);
-               error = dbuf_hold_impl(dn, lvl, blkid, TRUE, FTAG, &db);
+               uint64_t blkid = dbuf_whichblock(dn, lvl, *offset);
+               error = dbuf_hold_impl(dn, lvl, blkid, TRUE, FALSE, FTAG, &db);
                if (error) {
                        if (error != ENOENT)
                                return (error);
@@ -1910,17 +2045,21 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
                error = SET_ERROR(ESRCH);
        } else if (lvl == 0) {
                dnode_phys_t *dnp = data;
-               span = DNODE_SHIFT;
+
                ASSERT(dn->dn_type == DMU_OT_DNODE);
+               ASSERT(!(flags & DNODE_FIND_BACKWARDS));
 
-               for (i = (*offset >> span) & (blkfill - 1);
-                   i >= 0 && i < blkfill; i += inc) {
+               for (i = (*offset >> DNODE_SHIFT) & (blkfill - 1);
+                   i < blkfill; i += dnp[i].dn_extra_slots + 1) {
                        if ((dnp[i].dn_type == DMU_OT_NONE) == hole)
                                break;
-                       *offset += (1ULL << span) * inc;
                }
-               if (i < 0 || i == blkfill)
+
+               if (i == blkfill)
                        error = SET_ERROR(ESRCH);
+
+               *offset = (*offset & ~(DNODE_BLOCK_SIZE - 1)) +
+                   (i << DNODE_SHIFT);
        } else {
                blkptr_t *bp = data;
                uint64_t start = *offset;
@@ -1933,7 +2072,14 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
                else
                        minfill++;
 
-               *offset = *offset >> span;
+               if (span >= 8 * sizeof (*offset)) {
+                       /* This only happens on the highest indirection level */
+                       ASSERT3U((lvl - 1), ==, dn->dn_phys->dn_nlevels - 1);
+                       *offset = 0;
+               } else {
+                       *offset = *offset >> span;
+               }
+
                for (i = BF64_GET(*offset, 0, epbs);
                    i >= 0 && i < epb; i += inc) {
                        if (BP_GET_FILL(&bp[i]) >= minfill &&
@@ -1943,7 +2089,13 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset,
                        if (inc > 0 || *offset > 0)
                                *offset += inc;
                }
-               *offset = *offset << span;
+
+               if (span >= 8 * sizeof (*offset)) {
+                       *offset = start;
+               } else {
+                       *offset = *offset << span;
+               }
+
                if (inc < 0) {
                        /* traversing backwards; position offset at the end */
                        ASSERT3U(*offset, <=, start);
index df5c8e4ee6c43421ce04d4f2ec83d75059a4fda1..6d1fa3339ae6646e5858cecccab2f186f4faf710 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
 
@@ -60,20 +60,14 @@ dnode_increase_indirection(dnode_t *dn, dmu_tx_t *tx)
        dprintf("os=%p obj=%llu, increase to %d\n", dn->dn_objset,
            dn->dn_object, dn->dn_phys->dn_nlevels);
 
-       /* check for existing blkptrs in the dnode */
-       for (i = 0; i < nblkptr; i++)
-               if (!BP_IS_HOLE(&dn->dn_phys->dn_blkptr[i]))
-                       break;
-       if (i != nblkptr) {
-               /* transfer dnode's block pointers to new indirect block */
-               (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED|DB_RF_HAVESTRUCT);
-               ASSERT(db->db.db_data);
-               ASSERT(arc_released(db->db_buf));
-               ASSERT3U(sizeof (blkptr_t) * nblkptr, <=, db->db.db_size);
-               bcopy(dn->dn_phys->dn_blkptr, db->db.db_data,
-                   sizeof (blkptr_t) * nblkptr);
-               arc_buf_freeze(db->db_buf);
-       }
+       /* transfer dnode's block pointers to new indirect block */
+       (void) dbuf_read(db, NULL, DB_RF_MUST_SUCCEED|DB_RF_HAVESTRUCT);
+       ASSERT(db->db.db_data);
+       ASSERT(arc_released(db->db_buf));
+       ASSERT3U(sizeof (blkptr_t) * nblkptr, <=, db->db.db_size);
+       bcopy(dn->dn_phys->dn_blkptr, db->db.db_data,
+           sizeof (blkptr_t) * nblkptr);
+       arc_buf_freeze(db->db_buf);
 
        /* set dbuf's parent pointers to new indirect buf */
        for (i = 0; i < nblkptr; i++) {
@@ -192,7 +186,7 @@ free_verify(dmu_buf_impl_t *db, uint64_t start, uint64_t end, dmu_tx_t *tx)
 
                rw_enter(&dn->dn_struct_rwlock, RW_READER);
                err = dbuf_hold_impl(dn, db->db_level-1,
-                   (db->db_blkid << epbs) + i, TRUE, FTAG, &child);
+                   (db->db_blkid << epbs) + i, TRUE, FALSE, FTAG, &child);
                rw_exit(&dn->dn_struct_rwlock);
                if (err == ENOENT)
                        continue;
@@ -288,7 +282,7 @@ free_children(dmu_buf_impl_t *db, uint64_t blkid, uint64_t nblks,
                                continue;
                        rw_enter(&dn->dn_struct_rwlock, RW_READER);
                        VERIFY0(dbuf_hold_impl(dn, db->db_level - 1,
-                           i, B_TRUE, FTAG, &subdb));
+                           i, TRUE, FALSE, FTAG, &subdb));
                        rw_exit(&dn->dn_struct_rwlock);
                        ASSERT3P(bp, ==, subdb->db_blkptr);
 
@@ -362,7 +356,7 @@ dnode_sync_free_range_impl(dnode_t *dn, uint64_t blkid, uint64_t nblks,
                                continue;
                        rw_enter(&dn->dn_struct_rwlock, RW_READER);
                        VERIFY0(dbuf_hold_impl(dn, dnlevel - 1, i,
-                           TRUE, FTAG, &db));
+                           TRUE, FALSE, FTAG, &db));
                        rw_exit(&dn->dn_struct_rwlock);
 
                        free_children(db, blkid, nblks, tx);
@@ -427,7 +421,7 @@ dnode_evict_dbufs(dnode_t *dn)
                        avl_insert_here(&dn->dn_dbufs, db_marker, db,
                            AVL_BEFORE);
 
-                       dbuf_clear(db);
+                       dbuf_destroy(db);
 
                        db_next = AVL_NEXT(&dn->dn_dbufs, db_marker);
                        avl_remove(&dn->dn_dbufs, db_marker);
@@ -451,7 +445,7 @@ dnode_evict_bonus(dnode_t *dn)
        if (dn->dn_bonus != NULL) {
                if (refcount_is_zero(&dn->dn_bonus->db_holds)) {
                        mutex_enter(&dn->dn_bonus->db_mtx);
-                       dbuf_evict(dn->dn_bonus);
+                       dbuf_destroy(dn->dn_bonus);
                        dn->dn_bonus = NULL;
                } else {
                        dn->dn_bonus->db_pending_evict = TRUE;
@@ -530,7 +524,7 @@ dnode_sync_free(dnode_t *dn, dmu_tx_t *tx)
        ASSERT(dn->dn_free_txg > 0);
        if (dn->dn_allocated_txg != dn->dn_free_txg)
                dmu_buf_will_dirty(&dn->dn_dbuf->db, tx);
-       bzero(dn->dn_phys, sizeof (dnode_phys_t));
+       bzero(dn->dn_phys, sizeof (dnode_phys_t) * dn->dn_num_slots);
 
        mutex_enter(&dn->dn_mtx);
        dn->dn_type = DMU_OT_NONE;
@@ -565,7 +559,7 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
        ASSERT(dmu_tx_is_syncing(tx));
        ASSERT(dnp->dn_type != DMU_OT_NONE || dn->dn_allocated_txg);
        ASSERT(dnp->dn_type != DMU_OT_NONE ||
-           bcmp(dnp, &zerodn, DNODE_SIZE) == 0);
+           bcmp(dnp, &zerodn, DNODE_MIN_SIZE) == 0);
        DNODE_VERIFY(dn);
 
        ASSERT(dn->dn_dbuf == NULL || arc_released(dn->dn_dbuf->db_buf));
@@ -576,12 +570,17 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
                dn->dn_oldused = DN_USED_BYTES(dn->dn_phys);
                dn->dn_oldflags = dn->dn_phys->dn_flags;
                dn->dn_phys->dn_flags |= DNODE_FLAG_USERUSED_ACCOUNTED;
+               if (dmu_objset_userobjused_enabled(dn->dn_objset))
+                       dn->dn_phys->dn_flags |=
+                           DNODE_FLAG_USEROBJUSED_ACCOUNTED;
                mutex_exit(&dn->dn_mtx);
                dmu_objset_userquota_get_ids(dn, B_FALSE, tx);
        } else {
                /* Once we account for it, we should always account for it. */
                ASSERT(!(dn->dn_phys->dn_flags &
                    DNODE_FLAG_USERUSED_ACCOUNTED));
+               ASSERT(!(dn->dn_phys->dn_flags &
+                   DNODE_FLAG_USEROBJUSED_ACCOUNTED));
        }
 
        mutex_enter(&dn->dn_mtx);
@@ -597,6 +596,9 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
                dnp->dn_bonustype = dn->dn_bonustype;
                dnp->dn_bonuslen = dn->dn_bonuslen;
        }
+
+       dnp->dn_extra_slots = dn->dn_num_slots - 1;
+
        ASSERT(dnp->dn_nlevels > 1 ||
            BP_IS_HOLE(&dnp->dn_blkptr[0]) ||
            BP_IS_EMBEDDED(&dnp->dn_blkptr[0]) ||
@@ -629,7 +631,8 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
                        dnp->dn_bonuslen = 0;
                else
                        dnp->dn_bonuslen = dn->dn_next_bonuslen[txgoff];
-               ASSERT(dnp->dn_bonuslen <= DN_MAX_BONUSLEN);
+               ASSERT(dnp->dn_bonuslen <=
+                   DN_SLOTS_TO_BONUSLEN(dnp->dn_extra_slots + 1));
                dn->dn_next_bonuslen[txgoff] = 0;
        }
 
@@ -668,7 +671,7 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
        mutex_exit(&dn->dn_mtx);
 
        if (kill_spill) {
-               free_blocks(dn, &dn->dn_phys->dn_spill, 1, tx);
+               free_blocks(dn, DN_SPILL_BLKPTR(dn->dn_phys), 1, tx);
                mutex_enter(&dn->dn_mtx);
                dnp->dn_flags &= ~DNODE_FLAG_SPILL_BLKPTR;
                mutex_exit(&dn->dn_mtx);
@@ -688,10 +691,19 @@ dnode_sync(dnode_t *dn, dmu_tx_t *tx)
        }
 
        if (freeing_dnode) {
+               dn->dn_objset->os_freed_dnodes++;
                dnode_sync_free(dn, tx);
                return;
        }
 
+       if (dn->dn_num_slots > DNODE_MIN_SLOTS) {
+               dsl_dataset_t *ds = dn->dn_objset->os_dsl_dataset;
+               mutex_enter(&ds->ds_lock);
+               ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_DNODE] =
+                   B_TRUE;
+               mutex_exit(&ds->ds_lock);
+       }
+
        if (dn->dn_next_nlevels[txgoff]) {
                dnode_increase_indirection(dn, tx);
                dn->dn_next_nlevels[txgoff] = 0;
index 447a3a2dc3a2de6df39c4061b78772cf11ab0b4a..5a7f034ce6498e40a34b0bcc73d1498ae9851318 100644 (file)
@@ -34,10 +34,10 @@ static int
 dsl_bookmark_hold_ds(dsl_pool_t *dp, const char *fullname,
     dsl_dataset_t **dsp, void *tag, char **shortnamep)
 {
-       char buf[MAXNAMELEN];
+       char buf[ZFS_MAX_DATASET_NAME_LEN];
        char *hashp;
 
-       if (strlen(fullname) >= MAXNAMELEN)
+       if (strlen(fullname) >= ZFS_MAX_DATASET_NAME_LEN)
                return (SET_ERROR(ENAMETOOLONG));
        hashp = strchr(fullname, '#');
        if (hashp == NULL)
index 7124f3d6a83c23e9aacf5864b418028c2629fae6..9362d49bd26e78085568bf1c79206a8a11babf7f 100644 (file)
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 RackTop Systems.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+ * Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 #include <sys/dmu_objset.h>
 #include <sys/dsl_destroy.h>
 #include <sys/dsl_userhold.h>
 #include <sys/dsl_bookmark.h>
+#include <sys/policy.h>
+#include <sys/dmu_send.h>
+#include <sys/zio_compress.h>
+#include <zfs_fletcher.h>
+#include <sys/zio_checksum.h>
 
 /*
  * The SPA supports block sizes up to 16MB.  However, very large blocks
@@ -74,6 +80,8 @@ int zfs_max_recordsize = 1 * 1024 * 1024;
 
 extern inline dsl_dataset_phys_t *dsl_dataset_phys(dsl_dataset_t *ds);
 
+extern int spa_asize_inflation;
+
 /*
  * Figure out how much of this delta should be propogated to the dsl_dir
  * layer.  If there's a refreservation, that space has already been
@@ -101,6 +109,7 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
 {
        int used, compressed, uncompressed;
        int64_t delta;
+       spa_feature_t f;
 
        used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
        compressed = BP_GET_PSIZE(bp);
@@ -127,8 +136,16 @@ dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx)
        dsl_dataset_phys(ds)->ds_compressed_bytes += compressed;
        dsl_dataset_phys(ds)->ds_uncompressed_bytes += uncompressed;
        dsl_dataset_phys(ds)->ds_unique_bytes += used;
-       if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE)
-               ds->ds_need_large_blocks = B_TRUE;
+
+       if (BP_GET_LSIZE(bp) > SPA_OLD_MAXBLOCKSIZE) {
+               ds->ds_feature_activation_needed[SPA_FEATURE_LARGE_BLOCKS] =
+                   B_TRUE;
+       }
+
+       f = zio_checksum_to_feature(BP_GET_CHECKSUM(bp));
+       if (f != SPA_FEATURE_NONE)
+               ds->ds_feature_activation_needed[f] = B_TRUE;
+
        mutex_exit(&ds->ds_lock);
        dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta,
            compressed, uncompressed, tx);
@@ -283,6 +300,7 @@ dsl_dataset_evict(void *dbu)
 
        ASSERT(!list_link_active(&ds->ds_synced_link));
 
+       list_destroy(&ds->ds_prop_cbs);
        mutex_destroy(&ds->ds_lock);
        mutex_destroy(&ds->ds_opening_lock);
        mutex_destroy(&ds->ds_sendstream_lock);
@@ -432,20 +450,29 @@ dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag,
                list_create(&ds->ds_sendstreams, sizeof (dmu_sendarg_t),
                    offsetof(dmu_sendarg_t, dsa_link));
 
+               list_create(&ds->ds_prop_cbs, sizeof (dsl_prop_cb_record_t),
+                   offsetof(dsl_prop_cb_record_t, cbr_ds_node));
+
                if (doi.doi_type == DMU_OTN_ZAP_METADATA) {
-                       int zaperr = zap_contains(mos, dsobj,
-                           DS_FIELD_LARGE_BLOCKS);
-                       if (zaperr != ENOENT) {
-                               VERIFY0(zaperr);
-                               ds->ds_large_blocks = B_TRUE;
+                       spa_feature_t f;
+
+                       for (f = 0; f < SPA_FEATURES; f++) {
+                               if (!(spa_feature_table[f].fi_flags &
+                                   ZFEATURE_FLAG_PER_DATASET))
+                                       continue;
+                               err = zap_contains(mos, dsobj,
+                                   spa_feature_table[f].fi_guid);
+                               if (err == 0) {
+                                       ds->ds_feature_inuse[f] = B_TRUE;
+                               } else {
+                                       ASSERT3U(err, ==, ENOENT);
+                                       err = 0;
+                               }
                        }
                }
 
-               if (err == 0) {
-                       err = dsl_dir_hold_obj(dp,
-                           dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds,
-                           &ds->ds_dir);
-               }
+               err = dsl_dir_hold_obj(dp,
+                   dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds, &ds->ds_dir);
                if (err != 0) {
                        mutex_destroy(&ds->ds_lock);
                        mutex_destroy(&ds->ds_opening_lock);
@@ -540,6 +567,7 @@ dsl_dataset_hold(dsl_pool_t *dp, const char *name,
        const char *snapname;
        uint64_t obj;
        int err = 0;
+       dsl_dataset_t *ds;
 
        err = dsl_dir_hold(dp, name, FTAG, &dd, &snapname);
        if (err != 0)
@@ -548,36 +576,37 @@ dsl_dataset_hold(dsl_pool_t *dp, const char *name,
        ASSERT(dsl_pool_config_held(dp));
        obj = dsl_dir_phys(dd)->dd_head_dataset_obj;
        if (obj != 0)
-               err = dsl_dataset_hold_obj(dp, obj, tag, dsp);
+               err = dsl_dataset_hold_obj(dp, obj, tag, &ds);
        else
                err = SET_ERROR(ENOENT);
 
        /* we may be looking for a snapshot */
        if (err == 0 && snapname != NULL) {
-               dsl_dataset_t *ds;
+               dsl_dataset_t *snap_ds;
 
                if (*snapname++ != '@') {
-                       dsl_dataset_rele(*dsp, tag);
+                       dsl_dataset_rele(ds, tag);
                        dsl_dir_rele(dd, FTAG);
                        return (SET_ERROR(ENOENT));
                }
 
                dprintf("looking for snapshot '%s'\n", snapname);
-               err = dsl_dataset_snap_lookup(*dsp, snapname, &obj);
+               err = dsl_dataset_snap_lookup(ds, snapname, &obj);
                if (err == 0)
-                       err = dsl_dataset_hold_obj(dp, obj, tag, &ds);
-               dsl_dataset_rele(*dsp, tag);
+                       err = dsl_dataset_hold_obj(dp, obj, tag, &snap_ds);
+               dsl_dataset_rele(ds, tag);
 
                if (err == 0) {
-                       mutex_enter(&ds->ds_lock);
-                       if (ds->ds_snapname[0] == 0)
-                               (void) strlcpy(ds->ds_snapname, snapname,
-                                   sizeof (ds->ds_snapname));
-                       mutex_exit(&ds->ds_lock);
-                       *dsp = ds;
+                       mutex_enter(&snap_ds->ds_lock);
+                       if (snap_ds->ds_snapname[0] == 0)
+                               (void) strlcpy(snap_ds->ds_snapname, snapname,
+                                   sizeof (snap_ds->ds_snapname));
+                       mutex_exit(&snap_ds->ds_lock);
+                       ds = snap_ds;
                }
        }
-
+       if (err == 0)
+               *dsp = ds;
        dsl_dir_rele(dd, FTAG);
        return (err);
 }
@@ -649,17 +678,22 @@ dsl_dataset_name(dsl_dataset_t *ds, char *name)
                dsl_dir_name(ds->ds_dir, name);
                VERIFY0(dsl_dataset_get_snapname(ds));
                if (ds->ds_snapname[0]) {
-                       (void) strcat(name, "@");
+                       VERIFY3U(strlcat(name, "@", ZFS_MAX_DATASET_NAME_LEN),
+                           <, ZFS_MAX_DATASET_NAME_LEN);
                        /*
                         * We use a "recursive" mutex so that we
                         * can call dprintf_ds() with ds_lock held.
                         */
                        if (!MUTEX_HELD(&ds->ds_lock)) {
                                mutex_enter(&ds->ds_lock);
-                               (void) strcat(name, ds->ds_snapname);
+                               VERIFY3U(strlcat(name, ds->ds_snapname,
+                                   ZFS_MAX_DATASET_NAME_LEN), <,
+                                   ZFS_MAX_DATASET_NAME_LEN);
                                mutex_exit(&ds->ds_lock);
                        } else {
-                               (void) strcat(name, ds->ds_snapname);
+                               VERIFY3U(strlcat(name, ds->ds_snapname,
+                                   ZFS_MAX_DATASET_NAME_LEN), <,
+                                   ZFS_MAX_DATASET_NAME_LEN);
                        }
                }
        }
@@ -700,6 +734,7 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
 {
        boolean_t gotit = FALSE;
 
+       ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
        mutex_enter(&ds->ds_lock);
        if (ds->ds_owner == NULL && !DS_IS_INCONSISTENT(ds)) {
                ds->ds_owner = tag;
@@ -710,6 +745,44 @@ dsl_dataset_tryown(dsl_dataset_t *ds, void *tag)
        return (gotit);
 }
 
+boolean_t
+dsl_dataset_has_owner(dsl_dataset_t *ds)
+{
+       boolean_t rv;
+       mutex_enter(&ds->ds_lock);
+       rv = (ds->ds_owner != NULL);
+       mutex_exit(&ds->ds_lock);
+       return (rv);
+}
+
+static void
+dsl_dataset_activate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       objset_t *mos = dmu_tx_pool(tx)->dp_meta_objset;
+       uint64_t zero = 0;
+
+       VERIFY(spa_feature_table[f].fi_flags & ZFEATURE_FLAG_PER_DATASET);
+
+       spa_feature_incr(spa, f, tx);
+       dmu_object_zapify(mos, dsobj, DMU_OT_DSL_DATASET, tx);
+
+       VERIFY0(zap_add(mos, dsobj, spa_feature_table[f].fi_guid,
+           sizeof (zero), 1, &zero, tx));
+}
+
+void
+dsl_dataset_deactivate_feature(uint64_t dsobj, spa_feature_t f, dmu_tx_t *tx)
+{
+       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
+       objset_t *mos = dmu_tx_pool(tx)->dp_meta_objset;
+
+       VERIFY(spa_feature_table[f].fi_flags & ZFEATURE_FLAG_PER_DATASET);
+
+       VERIFY0(zap_remove(mos, dsobj, spa_feature_table[f].fi_guid, tx));
+       spa_feature_decr(spa, f, tx);
+}
+
 uint64_t
 dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
     uint64_t flags, dmu_tx_t *tx)
@@ -748,6 +821,7 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
        if (origin == NULL) {
                dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx);
        } else {
+               spa_feature_t f;
                dsl_dataset_t *ohds; /* head of the origin snapshot */
 
                dsphys->ds_prev_snap_obj = origin->ds_object;
@@ -768,8 +842,10 @@ dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin,
                dsphys->ds_flags |= dsl_dataset_phys(origin)->ds_flags &
                    (DS_FLAG_INCONSISTENT | DS_FLAG_CI_DATASET);
 
-               if (origin->ds_large_blocks)
-                       dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
+               for (f = 0; f < SPA_FEATURES; f++) {
+                       if (origin->ds_feature_inuse[f])
+                               dsl_dataset_activate_feature(dsobj, f, tx);
+               }
 
                dmu_buf_will_dirty(origin->ds_dbuf, tx);
                dsl_dataset_phys(origin)->ds_num_children++;
@@ -1202,11 +1278,11 @@ dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
            pair != NULL; pair = nvlist_next_nvpair(ddsa->ddsa_snaps, pair)) {
                int error = 0;
                dsl_dataset_t *ds;
-               char *name, *atp;
-               char dsname[MAXNAMELEN];
+               char *name, *atp = NULL;
+               char dsname[ZFS_MAX_DATASET_NAME_LEN];
 
                name = nvpair_name(pair);
-               if (strlen(name) >= MAXNAMELEN)
+               if (strlen(name) >= ZFS_MAX_DATASET_NAME_LEN)
                        error = SET_ERROR(ENAMETOOLONG);
                if (error == 0) {
                        atp = strchr(name, '@');
@@ -1245,6 +1321,7 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
        dsl_dataset_phys_t *dsphys;
        uint64_t dsobj, crtxg;
        objset_t *mos = dp->dp_meta_objset;
+       spa_feature_t f;
        ASSERTV(static zil_header_t zero_zil);
        ASSERTV(objset_t *os);
 
@@ -1294,8 +1371,10 @@ dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
        dsphys->ds_bp = dsl_dataset_phys(ds)->ds_bp;
        dmu_buf_rele(dbuf, FTAG);
 
-       if (ds->ds_large_blocks)
-               dsl_dataset_activate_large_blocks_sync_impl(dsobj, tx);
+       for (f = 0; f < SPA_FEATURES; f++) {
+               if (ds->ds_feature_inuse[f])
+                       dsl_dataset_activate_feature(dsobj, f, tx);
+       }
 
        ASSERT3U(ds->ds_prev != 0, ==,
            dsl_dataset_phys(ds)->ds_prev_snap_obj != 0);
@@ -1376,7 +1455,7 @@ dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx)
            pair != NULL; pair = nvlist_next_nvpair(ddsa->ddsa_snaps, pair)) {
                dsl_dataset_t *ds;
                char *name, *atp;
-               char dsname[MAXNAMELEN];
+               char dsname[ZFS_MAX_DATASET_NAME_LEN];
 
                name = nvpair_name(pair);
                atp = strchr(name, '@');
@@ -1423,7 +1502,7 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
                suspended = fnvlist_alloc();
                for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
                    pair = nvlist_next_nvpair(snaps, pair)) {
-                       char fsname[MAXNAMELEN];
+                       char fsname[ZFS_MAX_DATASET_NAME_LEN];
                        char *snapname = nvpair_name(pair);
                        char *atp;
                        void *cookie;
@@ -1513,7 +1592,7 @@ dsl_dataset_snapshot_tmp_sync(void *arg, dmu_tx_t *tx)
 {
        dsl_dataset_snapshot_tmp_arg_t *ddsta = arg;
        dsl_pool_t *dp = dmu_tx_pool(tx);
-       dsl_dataset_t *ds;
+       dsl_dataset_t *ds = NULL;
 
        VERIFY0(dsl_dataset_hold(dp, ddsta->ddsta_fsname, FTAG, &ds));
 
@@ -1564,6 +1643,8 @@ dsl_dataset_snapshot_tmp(const char *fsname, const char *snapname,
 void
 dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
 {
+       spa_feature_t f;
+
        ASSERT(dmu_tx_is_syncing(tx));
        ASSERT(ds->ds_objset != NULL);
        ASSERT(dsl_dataset_phys(ds)->ds_next_snap_obj == 0);
@@ -1575,11 +1656,30 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
        dmu_buf_will_dirty(ds->ds_dbuf, tx);
        dsl_dataset_phys(ds)->ds_fsid_guid = ds->ds_fsid_guid;
 
+       if (ds->ds_resume_bytes[tx->tx_txg & TXG_MASK] != 0) {
+               VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
+                   ds->ds_object, DS_FIELD_RESUME_OBJECT, 8, 1,
+                   &ds->ds_resume_object[tx->tx_txg & TXG_MASK], tx));
+               VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
+                   ds->ds_object, DS_FIELD_RESUME_OFFSET, 8, 1,
+                   &ds->ds_resume_offset[tx->tx_txg & TXG_MASK], tx));
+               VERIFY0(zap_update(tx->tx_pool->dp_meta_objset,
+                   ds->ds_object, DS_FIELD_RESUME_BYTES, 8, 1,
+                   &ds->ds_resume_bytes[tx->tx_txg & TXG_MASK], tx));
+               ds->ds_resume_object[tx->tx_txg & TXG_MASK] = 0;
+               ds->ds_resume_offset[tx->tx_txg & TXG_MASK] = 0;
+               ds->ds_resume_bytes[tx->tx_txg & TXG_MASK] = 0;
+       }
+
        dmu_objset_sync(ds->ds_objset, zio, tx);
 
-       if (ds->ds_need_large_blocks && !ds->ds_large_blocks) {
-               dsl_dataset_activate_large_blocks_sync_impl(ds->ds_object, tx);
-               ds->ds_large_blocks = B_TRUE;
+       for (f = 0; f < SPA_FEATURES; f++) {
+               if (ds->ds_feature_activation_needed[f]) {
+                       if (ds->ds_feature_inuse[f])
+                               continue;
+                       dsl_dataset_activate_feature(ds->ds_object, f, tx);
+                       ds->ds_feature_inuse[f] = B_TRUE;
+               }
        }
 }
 
@@ -1611,7 +1711,7 @@ get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
            zap_cursor_retrieve(&zc, &za) == 0;
            zap_cursor_advance(&zc)) {
                dsl_dataset_t *clone;
-               char buf[ZFS_MAXNAMELEN];
+               char buf[ZFS_MAX_DATASET_NAME_LEN];
                VERIFY0(dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
                    za.za_first_integer, FTAG, &clone));
                dsl_dir_name(clone->ds_dir, buf);
@@ -1626,11 +1726,91 @@ fail:
        nvlist_free(propval);
 }
 
+static void
+get_receive_resume_stats(dsl_dataset_t *ds, nvlist_t *nv)
+{
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
+
+       if (dsl_dataset_has_resume_receive_state(ds)) {
+               char *str;
+               void *packed;
+               uint8_t *compressed;
+               uint64_t val;
+               nvlist_t *token_nv = fnvlist_alloc();
+               size_t packed_size, compressed_size;
+               zio_cksum_t cksum;
+               char *propval;
+               char buf[MAXNAMELEN];
+               int i;
+
+               if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_FROMGUID, sizeof (val), 1, &val) == 0) {
+                       fnvlist_add_uint64(token_nv, "fromguid", val);
+               }
+               if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_OBJECT, sizeof (val), 1, &val) == 0) {
+                       fnvlist_add_uint64(token_nv, "object", val);
+               }
+               if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_OFFSET, sizeof (val), 1, &val) == 0) {
+                       fnvlist_add_uint64(token_nv, "offset", val);
+               }
+               if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_BYTES, sizeof (val), 1, &val) == 0) {
+                       fnvlist_add_uint64(token_nv, "bytes", val);
+               }
+               if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_TOGUID, sizeof (val), 1, &val) == 0) {
+                       fnvlist_add_uint64(token_nv, "toguid", val);
+               }
+               if (zap_lookup(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_TONAME, 1, sizeof (buf), buf) == 0) {
+                       fnvlist_add_string(token_nv, "toname", buf);
+               }
+               if (zap_contains(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_LARGEBLOCK) == 0) {
+                       fnvlist_add_boolean(token_nv, "largeblockok");
+               }
+               if (zap_contains(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_EMBEDOK) == 0) {
+                       fnvlist_add_boolean(token_nv, "embedok");
+               }
+               if (zap_contains(dp->dp_meta_objset, ds->ds_object,
+                   DS_FIELD_RESUME_COMPRESSOK) == 0) {
+                       fnvlist_add_boolean(token_nv, "compressok");
+               }
+               packed = fnvlist_pack(token_nv, &packed_size);
+               fnvlist_free(token_nv);
+               compressed = kmem_alloc(packed_size, KM_SLEEP);
+
+               compressed_size = gzip_compress(packed, compressed,
+                   packed_size, packed_size, 6);
+
+               fletcher_4_native_varsize(compressed, compressed_size, &cksum);
+
+               str = kmem_alloc(compressed_size * 2 + 1, KM_SLEEP);
+               for (i = 0; i < compressed_size; i++) {
+                       (void) sprintf(str + i * 2, "%02x", compressed[i]);
+               }
+               str[compressed_size * 2] = '\0';
+               propval = kmem_asprintf("%u-%llx-%llx-%s",
+                   ZFS_SEND_RESUME_TOKEN_VERSION,
+                   (longlong_t)cksum.zc_word[0],
+                   (longlong_t)packed_size, str);
+               dsl_prop_nvlist_add_string(nv,
+                   ZFS_PROP_RECEIVE_RESUME_TOKEN, propval);
+               kmem_free(packed, packed_size);
+               kmem_free(str, compressed_size * 2 + 1);
+               kmem_free(compressed, packed_size);
+               strfree(propval);
+       }
+}
+
 void
 dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
 {
+       dsl_pool_t *dp = ds->ds_dir->dd_pool;
        uint64_t refd, avail, uobjs, aobjs, ratio;
-       ASSERTV(dsl_pool_t *dp = ds->ds_dir->dd_pool);
 
        ASSERT(dsl_pool_config_held(dp));
 
@@ -1648,6 +1828,12 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
                    dsl_dataset_phys(ds)->ds_unique_bytes);
                get_clones_stat(ds, nv);
        } else {
+               if (ds->ds_prev != NULL && ds->ds_prev != dp->dp_origin_snap) {
+                       char buf[ZFS_MAX_DATASET_NAME_LEN];
+                       dsl_dataset_name(ds->ds_prev, buf);
+                       dsl_prop_nvlist_add_string(nv, ZFS_PROP_PREV_SNAP, buf);
+               }
+
                dsl_dir_stats(ds->ds_dir, nv);
        }
 
@@ -1693,6 +1879,32 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
                }
        }
 
+       if (!dsl_dataset_is_snapshot(ds)) {
+               /* 6 extra bytes for /%recv */
+               char recvname[ZFS_MAX_DATASET_NAME_LEN + 6];
+               dsl_dataset_t *recv_ds;
+
+               /*
+                * A failed "newfs" (e.g. full) resumable receive leaves
+                * the stats set on this dataset.  Check here for the prop.
+                */
+               get_receive_resume_stats(ds, nv);
+
+               /*
+                * A failed incremental resumable receive leaves the
+                * stats set on our child named "%recv".  Check the child
+                * for the prop.
+                */
+               dsl_dataset_name(ds, recvname);
+               if (strlcat(recvname, "/", sizeof (recvname)) <
+                   sizeof (recvname) &&
+                   strlcat(recvname, recv_clone_name, sizeof (recvname)) <
+                   sizeof (recvname) &&
+                   dsl_dataset_hold(dp, recvname, FTAG, &recv_ds) == 0) {
+                       get_receive_resume_stats(recv_ds, nv);
+                       dsl_dataset_rele(recv_ds, FTAG);
+               }
+       }
 }
 
 void
@@ -1813,7 +2025,7 @@ dsl_dataset_rename_snapshot_check_impl(dsl_pool_t *dp,
 
        /* dataset name + 1 for the "@" + the new snapshot name must fit */
        if (dsl_dir_namelen(hds->ds_dir) + 1 +
-           strlen(ddrsa->ddrsa_newsnapname) >= MAXNAMELEN)
+           strlen(ddrsa->ddrsa_newsnapname) >= ZFS_MAX_DATASET_NAME_LEN)
                error = SET_ERROR(ENAMETOOLONG);
 
        return (error);
@@ -1868,7 +2080,8 @@ dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
        VERIFY0(dsl_dataset_snap_remove(hds, ddrsa->ddrsa_oldsnapname, tx,
            B_FALSE));
        mutex_enter(&ds->ds_lock);
-       (void) strcpy(ds->ds_snapname, ddrsa->ddrsa_newsnapname);
+       (void) strlcpy(ds->ds_snapname, ddrsa->ddrsa_newsnapname,
+           sizeof (ds->ds_snapname));
        mutex_exit(&ds->ds_lock);
        VERIFY0(zap_add(dp->dp_meta_objset,
            dsl_dataset_phys(hds)->ds_snapnames_zapobj,
@@ -1885,7 +2098,7 @@ dsl_dataset_rename_snapshot_sync(void *arg, dmu_tx_t *tx)
 {
        dsl_dataset_rename_snapshot_arg_t *ddrsa = arg;
        dsl_pool_t *dp = dmu_tx_pool(tx);
-       dsl_dataset_t *hds;
+       dsl_dataset_t *hds = NULL;
 
        VERIFY0(dsl_dataset_hold(dp, ddrsa->ddrsa_fsname, FTAG, &hds));
        ddrsa->ddrsa_tx = tx;
@@ -1920,7 +2133,8 @@ dsl_dataset_rename_snapshot(const char *fsname,
  * only one long hold on the dataset.  We're not allowed to change anything here
  * so we don't permanently release the long hold or regular hold here.  We want
  * to do this only when syncing to avoid the dataset unexpectedly going away
- * when we release the long hold.
+ * when we release the long hold.  Allow a long hold to exist for volumes, this
+ * may occur when asynchronously registering the minor with the kernel.
  */
 static int
 dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx)
@@ -1935,7 +2149,7 @@ dsl_dataset_handoff_check(dsl_dataset_t *ds, void *owner, dmu_tx_t *tx)
                dsl_dataset_long_rele(ds, owner);
        }
 
-       held = dsl_dataset_long_held(ds);
+       held = (dsl_dataset_long_held(ds) && (ds->ds_owner != zvol_tag));
 
        if (owner != NULL)
                dsl_dataset_long_hold(ds, owner);
@@ -2045,7 +2259,7 @@ dsl_dataset_rollback_sync(void *arg, dmu_tx_t *tx)
        dsl_pool_t *dp = dmu_tx_pool(tx);
        dsl_dataset_t *ds, *clone;
        uint64_t cloneobj;
-       char namebuf[ZFS_MAXNAMELEN];
+       char namebuf[ZFS_MAX_DATASET_NAME_LEN];
 
        VERIFY0(dsl_dataset_hold(dp, ddra->ddra_fsname, FTAG, &ds));
 
@@ -2148,6 +2362,10 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
        }
 
        snap = list_head(&ddpa->shared_snaps);
+       if (snap == NULL) {
+               err = SET_ERROR(ENOENT);
+               goto out;
+       }
        origin_ds = snap->ds;
 
        /* compute origin's new unique space */
@@ -2256,6 +2474,10 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
                 * iterate over all bps.
                 */
                snap = list_head(&ddpa->origin_snaps);
+               if (snap == NULL) {
+                       err = SET_ERROR(ENOENT);
+                       goto out;
+               }
                err = snaplist_space(&ddpa->shared_snaps,
                    snap->ds->ds_dir->dd_origin_txg, &ddpa->cloneusedsnap);
                if (err != 0)
@@ -2598,7 +2820,7 @@ promote_rele(dsl_dataset_promote_arg_t *ddpa, void *tag)
  * Promote a clone.
  *
  * If it fails due to a conflicting snapshot name, "conflsnap" will be filled
- * in with the name.  (It must be at least MAXNAMELEN bytes long.)
+ * in with the name.  (It must be at least ZFS_MAX_DATASET_NAME_LEN bytes long.)
  */
 int
 dsl_dataset_promote(const char *name, char *conflsnap)
@@ -2635,6 +2857,12 @@ int
 dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
     dsl_dataset_t *origin_head, boolean_t force, void *owner, dmu_tx_t *tx)
 {
+       /*
+        * "slack" factor for received datasets with refquota set on them.
+        * See the bottom of this function for details on its use.
+        */
+       uint64_t refquota_slack = (uint64_t)DMU_MAX_ACCESS *
+           spa_asize_inflation;
        int64_t unused_refres_delta;
 
        /* they should both be heads */
@@ -2677,10 +2905,22 @@ dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
            dsl_dir_space_available(origin_head->ds_dir, NULL, 0, TRUE))
                return (SET_ERROR(ENOSPC));
 
-       /* clone can't be over the head's refquota */
+       /*
+        * The clone can't be too much over the head's refquota.
+        *
+        * To ensure that the entire refquota can be used, we allow one
+        * transaction to exceed the the refquota.  Therefore, this check
+        * needs to also allow for the space referenced to be more than the
+        * refquota.  The maximum amount of space that one transaction can use
+        * on disk is DMU_MAX_ACCESS * spa_asize_inflation.  Allowing this
+        * overage ensures that we are able to receive a filesystem that
+        * exceeds the refquota on the source system.
+        *
+        * So that overage is the refquota_slack we use below.
+        */
        if (origin_head->ds_quota != 0 &&
            dsl_dataset_phys(clone)->ds_referenced_bytes >
-           origin_head->ds_quota)
+           origin_head->ds_quota + refquota_slack)
                return (SET_ERROR(EDQUOT));
 
        return (0);
@@ -2690,14 +2930,57 @@ void
 dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
     dsl_dataset_t *origin_head, dmu_tx_t *tx)
 {
+       spa_feature_t f;
        dsl_pool_t *dp = dmu_tx_pool(tx);
        int64_t unused_refres_delta;
 
        ASSERT(clone->ds_reserved == 0);
+       /*
+        * NOTE: On DEBUG kernels there could be a race between this and
+        * the check function if spa_asize_inflation is adjusted...
+        */
        ASSERT(origin_head->ds_quota == 0 ||
-           dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota);
+           dsl_dataset_phys(clone)->ds_unique_bytes <= origin_head->ds_quota +
+           DMU_MAX_ACCESS * spa_asize_inflation);
        ASSERT3P(clone->ds_prev, ==, origin_head->ds_prev);
 
+       /*
+        * Swap per-dataset feature flags.
+        */
+       for (f = 0; f < SPA_FEATURES; f++) {
+               boolean_t clone_inuse;
+               boolean_t origin_head_inuse;
+
+               if (!(spa_feature_table[f].fi_flags &
+                   ZFEATURE_FLAG_PER_DATASET)) {
+                       ASSERT(!clone->ds_feature_inuse[f]);
+                       ASSERT(!origin_head->ds_feature_inuse[f]);
+                       continue;
+               }
+
+               clone_inuse = clone->ds_feature_inuse[f];
+               origin_head_inuse = origin_head->ds_feature_inuse[f];
+
+               if (clone_inuse) {
+                       dsl_dataset_deactivate_feature(clone->ds_object, f, tx);
+                       clone->ds_feature_inuse[f] = B_FALSE;
+               }
+               if (origin_head_inuse) {
+                       dsl_dataset_deactivate_feature(origin_head->ds_object,
+                           f, tx);
+                       origin_head->ds_feature_inuse[f] = B_FALSE;
+               }
+               if (clone_inuse) {
+                       dsl_dataset_activate_feature(origin_head->ds_object,
+                           f, tx);
+                       origin_head->ds_feature_inuse[f] = B_TRUE;
+               }
+               if (origin_head_inuse) {
+                       dsl_dataset_activate_feature(clone->ds_object, f, tx);
+                       clone->ds_feature_inuse[f] = B_TRUE;
+               }
+       }
+
        dmu_buf_will_dirty(clone->ds_dbuf, tx);
        dmu_buf_will_dirty(origin_head->ds_dbuf, tx);
 
@@ -2951,7 +3234,7 @@ dsl_dataset_set_refquota_sync(void *arg, dmu_tx_t *tx)
 {
        dsl_dataset_set_qr_arg_t *ddsqra = arg;
        dsl_pool_t *dp = dmu_tx_pool(tx);
-       dsl_dataset_t *ds;
+       dsl_dataset_t *ds = NULL;
        uint64_t newval;
 
        VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds));
@@ -3078,7 +3361,7 @@ dsl_dataset_set_refreservation_sync(void *arg, dmu_tx_t *tx)
 {
        dsl_dataset_set_qr_arg_t *ddsqra = arg;
        dsl_pool_t *dp = dmu_tx_pool(tx);
-       dsl_dataset_t *ds;
+       dsl_dataset_t *ds = NULL;
 
        VERIFY0(dsl_dataset_hold(dp, ddsqra->ddsqra_name, FTAG, &ds));
        dsl_dataset_set_refreservation_sync_impl(ds,
@@ -3252,77 +3535,6 @@ dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
        return (err);
 }
 
-static int
-dsl_dataset_activate_large_blocks_check(void *arg, dmu_tx_t *tx)
-{
-       const char *dsname = arg;
-       dsl_dataset_t *ds;
-       dsl_pool_t *dp = dmu_tx_pool(tx);
-       int error = 0;
-
-       if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS))
-               return (SET_ERROR(ENOTSUP));
-
-       ASSERT(spa_feature_is_enabled(dp->dp_spa,
-           SPA_FEATURE_EXTENSIBLE_DATASET));
-
-       error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
-       if (error != 0)
-               return (error);
-
-       if (ds->ds_large_blocks)
-               error = EALREADY;
-       dsl_dataset_rele(ds, FTAG);
-
-       return (error);
-}
-
-void
-dsl_dataset_activate_large_blocks_sync_impl(uint64_t dsobj, dmu_tx_t *tx)
-{
-       spa_t *spa = dmu_tx_pool(tx)->dp_spa;
-       objset_t *mos = dmu_tx_pool(tx)->dp_meta_objset;
-       uint64_t zero = 0;
-
-       spa_feature_incr(spa, SPA_FEATURE_LARGE_BLOCKS, tx);
-       dmu_object_zapify(mos, dsobj, DMU_OT_DSL_DATASET, tx);
-
-       VERIFY0(zap_add(mos, dsobj, DS_FIELD_LARGE_BLOCKS,
-           sizeof (zero), 1, &zero, tx));
-}
-
-static void
-dsl_dataset_activate_large_blocks_sync(void *arg, dmu_tx_t *tx)
-{
-       const char *dsname = arg;
-       dsl_dataset_t *ds;
-
-       VERIFY0(dsl_dataset_hold(dmu_tx_pool(tx), dsname, FTAG, &ds));
-
-       dsl_dataset_activate_large_blocks_sync_impl(ds->ds_object, tx);
-       ASSERT(!ds->ds_large_blocks);
-       ds->ds_large_blocks = B_TRUE;
-       dsl_dataset_rele(ds, FTAG);
-}
-
-int
-dsl_dataset_activate_large_blocks(const char *dsname)
-{
-       int error;
-
-       error = dsl_sync_task(dsname,
-           dsl_dataset_activate_large_blocks_check,
-           dsl_dataset_activate_large_blocks_sync, (void *)dsname,
-           1, ZFS_SPACE_CHECK_RESERVED);
-
-       /*
-        * EALREADY indicates that this dataset already supports large blocks.
-        */
-       if (error == EALREADY)
-               error = 0;
-       return (error);
-}
-
 /*
  * Return TRUE if 'earlier' is an earlier snapshot in 'later's timeline.
  * For example, they could both be snapshots of the same filesystem, and
@@ -3367,7 +3579,6 @@ dsl_dataset_is_before(dsl_dataset_t *later, dsl_dataset_t *earlier,
        return (ret);
 }
 
-
 void
 dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
 {
@@ -3375,6 +3586,23 @@ dsl_dataset_zapify(dsl_dataset_t *ds, dmu_tx_t *tx)
        dmu_object_zapify(mos, ds->ds_object, DMU_OT_DSL_DATASET, tx);
 }
 
+boolean_t
+dsl_dataset_is_zapified(dsl_dataset_t *ds)
+{
+       dmu_object_info_t doi;
+
+       dmu_object_info_from_db(ds->ds_dbuf, &doi);
+       return (doi.doi_type == DMU_OTN_ZAP_METADATA);
+}
+
+boolean_t
+dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds)
+{
+       return (dsl_dataset_is_zapified(ds) &&
+           zap_contains(ds->ds_dir->dd_pool->dp_meta_objset,
+           ds->ds_object, DS_FIELD_RESUME_TOGUID) == 0);
+}
+
 #if defined(_KERNEL) && defined(HAVE_SPL)
 #if defined(_LP64)
 module_param(zfs_max_recordsize, int, 0644);
index 8da77ebd7b6e12208e1db7a3ecbf378315efc298..0b99e9713a7c5d133855602502560d9df396f4b0 100644 (file)
 static int
 dsl_deadlist_compare(const void *arg1, const void *arg2)
 {
-       const dsl_deadlist_entry_t *dle1 = arg1;
-       const dsl_deadlist_entry_t *dle2 = arg2;
+       const dsl_deadlist_entry_t *dle1 = (const dsl_deadlist_entry_t *)arg1;
+       const dsl_deadlist_entry_t *dle2 = (const dsl_deadlist_entry_t *)arg2;
 
-       if (dle1->dle_mintxg < dle2->dle_mintxg)
-               return (-1);
-       else if (dle1->dle_mintxg > dle2->dle_mintxg)
-               return (+1);
-       else
-               return (0);
+       return (AVL_CMP(dle1->dle_mintxg, dle2->dle_mintxg));
 }
 
 static void
@@ -239,6 +234,14 @@ dsl_deadlist_insert(dsl_deadlist_t *dl, const blkptr_t *bp, dmu_tx_t *tx)
                dle = avl_nearest(&dl->dl_tree, where, AVL_BEFORE);
        else
                dle = AVL_PREV(&dl->dl_tree, dle);
+
+       if (dle == NULL) {
+               zfs_panic_recover("blkptr at %p has invalid BLK_BIRTH %llu",
+                   bp, (longlong_t)bp->blk_birth);
+               dle = avl_first(&dl->dl_tree);
+       }
+
+       ASSERT3P(dle, !=, NULL);
        dle_enqueue(dl, dle, bp, tx);
 }
 
index 952422be23813914dbb8efcf654d54c71e997aad..f17cedb082137db51a4e169c3fa89e05e15de950 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 /*
@@ -330,7 +330,7 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
        za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
        basezc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
        baseza = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
-       source = kmem_alloc(MAXNAMELEN + strlen(MOS_DIR_NAME) + 1, KM_SLEEP);
+       source = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
        VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 
        for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
@@ -370,7 +370,7 @@ dsl_deleg_get(const char *ddname, nvlist_t **nvp)
                nvlist_free(sp_nvp);
        }
 
-       kmem_free(source, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1);
+       kmem_free(source, ZFS_MAX_DATASET_NAME_LEN);
        kmem_free(baseza, sizeof (zap_attribute_t));
        kmem_free(basezc, sizeof (zap_cursor_t));
        kmem_free(za, sizeof (zap_attribute_t));
@@ -393,14 +393,13 @@ typedef struct perm_set {
 static int
 perm_set_compare(const void *arg1, const void *arg2)
 {
-       const perm_set_t *node1 = arg1;
-       const perm_set_t *node2 = arg2;
+       const perm_set_t *node1 = (const perm_set_t *)arg1;
+       const perm_set_t *node2 = (const perm_set_t *)arg2;
        int val;
 
        val = strcmp(node1->p_setname, node2->p_setname);
-       if (val == 0)
-               return (0);
-       return (val > 0 ? 1 : -1);
+
+       return (AVL_ISIGN(val));
 }
 
 /*
index 34d076e9f2ae2859493a062f444119eb677f22d9..716081ba3ac333febbcc897cca7c34603cd059b5 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2013 by Joyent, Inc. All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
@@ -245,6 +245,7 @@ dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx)
 void
 dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
 {
+       spa_feature_t f;
        int after_branch_point = FALSE;
        dsl_pool_t *dp = ds->ds_dir->dd_pool;
        objset_t *mos = dp->dp_meta_objset;
@@ -276,9 +277,11 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
 
        obj = ds->ds_object;
 
-       if (ds->ds_large_blocks) {
-               ASSERT0(zap_contains(mos, obj, DS_FIELD_LARGE_BLOCKS));
-               spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
+       for (f = 0; f < SPA_FEATURES; f++) {
+               if (ds->ds_feature_inuse[f]) {
+                       dsl_dataset_deactivate_feature(obj, f, tx);
+                       ds->ds_feature_inuse[f] = B_FALSE;
+               }
        }
        if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
                ASSERT3P(ds->ds_prev, ==, NULL);
@@ -558,7 +561,7 @@ kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
        struct killarg *ka = arg;
        dmu_tx_t *tx = ka->tx;
 
-       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
+       if (bp == NULL || BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
                return (0);
 
        if (zb->zb_level == ZB_ZIL_LEVEL) {
@@ -716,6 +719,7 @@ void
 dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
 {
        dsl_pool_t *dp = dmu_tx_pool(tx);
+       spa_feature_t f;
        objset_t *mos = dp->dp_meta_objset;
        uint64_t obj, ddobj, prevobj = 0;
        boolean_t rmorigin;
@@ -743,12 +747,16 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
                ASSERT0(ds->ds_reserved);
        }
 
-       if (ds->ds_large_blocks)
-               spa_feature_decr(dp->dp_spa, SPA_FEATURE_LARGE_BLOCKS, tx);
+       obj = ds->ds_object;
 
-       dsl_scan_ds_destroyed(ds, tx);
+       for (f = 0; f < SPA_FEATURES; f++) {
+               if (ds->ds_feature_inuse[f]) {
+                       dsl_dataset_deactivate_feature(obj, f, tx);
+                       ds->ds_feature_inuse[f] = B_FALSE;
+               }
+       }
 
-       obj = ds->ds_object;
+       dsl_scan_ds_destroyed(ds, tx);
 
        if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
                /* This is a clone */
@@ -970,9 +978,17 @@ dsl_destroy_inconsistent(const char *dsname, void *arg)
        objset_t *os;
 
        if (dmu_objset_hold(dsname, FTAG, &os) == 0) {
-               boolean_t inconsistent = DS_IS_INCONSISTENT(dmu_objset_ds(os));
+               boolean_t need_destroy = DS_IS_INCONSISTENT(dmu_objset_ds(os));
+
+               /*
+                * If the dataset is inconsistent because a resumable receive
+                * has failed, then do not destroy it.
+                */
+               if (dsl_dataset_has_resume_receive_state(dmu_objset_ds(os)))
+                       need_destroy = B_FALSE;
+
                dmu_objset_rele(os, FTAG);
-               if (inconsistent)
+               if (need_destroy)
                        (void) dsl_destroy_head(dsname);
        }
        return (0);
index 762e2e5ff23043c48dbc244b6f8421a3a89e55d5..b2173523590831e18debb99250ce746b7959eba9 100644 (file)
@@ -148,11 +148,7 @@ dsl_dir_evict(void *dbu)
 
        spa_async_close(dd->dd_pool->dp_spa, dd);
 
-       /*
-        * The props callback list should have been cleaned up by
-        * objset_evict().
-        */
-       list_destroy(&dd->dd_prop_cbs);
+       dsl_prop_fini(dd);
        mutex_destroy(&dd->dd_lock);
        kmem_free(dd, sizeof (dsl_dir_t));
 }
@@ -187,9 +183,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
                dd->dd_dbuf = dbuf;
                dd->dd_pool = dp;
                mutex_init(&dd->dd_lock, NULL, MUTEX_DEFAULT, NULL);
-
-               list_create(&dd->dd_prop_cbs, sizeof (dsl_prop_cb_record_t),
-                   offsetof(dsl_prop_cb_record_t, cbr_node));
+               dsl_prop_init(dd);
 
                dsl_dir_snap_cmtime_update(dd);
 
@@ -209,7 +203,8 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
                                    sizeof (foundobj), 1, &foundobj);
                                ASSERT(err || foundobj == ddobj);
 #endif
-                               (void) strcpy(dd->dd_myname, tail);
+                               (void) strlcpy(dd->dd_myname, tail,
+                                   sizeof (dd->dd_myname));
                        } else {
                                err = zap_value_search(dp->dp_meta_objset,
                                    dsl_dir_phys(dd->dd_parent)->
@@ -247,6 +242,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
                if (winner != NULL) {
                        if (dd->dd_parent)
                                dsl_dir_rele(dd->dd_parent, dd);
+                       dsl_prop_fini(dd);
                        mutex_destroy(&dd->dd_lock);
                        kmem_free(dd, sizeof (dsl_dir_t));
                        dd = winner;
@@ -274,6 +270,7 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
 errout:
        if (dd->dd_parent)
                dsl_dir_rele(dd->dd_parent, dd);
+       dsl_prop_fini(dd);
        mutex_destroy(&dd->dd_lock);
        kmem_free(dd, sizeof (dsl_dir_t));
        dmu_buf_rele(dbuf, tag);
@@ -303,13 +300,14 @@ dsl_dir_async_rele(dsl_dir_t *dd, void *tag)
        dmu_buf_rele(dd->dd_dbuf, tag);
 }
 
-/* buf must be long enough (MAXNAMELEN + strlen(MOS_DIR_NAME) + 1 should do) */
+/* buf must be at least ZFS_MAX_DATASET_NAME_LEN bytes */
 void
 dsl_dir_name(dsl_dir_t *dd, char *buf)
 {
        if (dd->dd_parent) {
                dsl_dir_name(dd->dd_parent, buf);
-               (void) strcat(buf, "/");
+               VERIFY3U(strlcat(buf, "/", ZFS_MAX_DATASET_NAME_LEN), <,
+                   ZFS_MAX_DATASET_NAME_LEN);
        } else {
                buf[0] = '\0';
        }
@@ -319,10 +317,12 @@ dsl_dir_name(dsl_dir_t *dd, char *buf)
                 * dprintf_dd() with dd_lock held
                 */
                mutex_enter(&dd->dd_lock);
-               (void) strcat(buf, dd->dd_myname);
+               VERIFY3U(strlcat(buf, dd->dd_myname, ZFS_MAX_DATASET_NAME_LEN),
+                   <, ZFS_MAX_DATASET_NAME_LEN);
                mutex_exit(&dd->dd_lock);
        } else {
-               (void) strcat(buf, dd->dd_myname);
+               VERIFY3U(strlcat(buf, dd->dd_myname, ZFS_MAX_DATASET_NAME_LEN),
+                   <, ZFS_MAX_DATASET_NAME_LEN);
        }
 }
 
@@ -371,12 +371,12 @@ getcomponent(const char *path, char *component, const char **nextp)
                if (p != NULL &&
                    (p[0] != '@' || strpbrk(path+1, "/@") || p[1] == '\0'))
                        return (SET_ERROR(EINVAL));
-               if (strlen(path) >= MAXNAMELEN)
+               if (strlen(path) >= ZFS_MAX_DATASET_NAME_LEN)
                        return (SET_ERROR(ENAMETOOLONG));
                (void) strcpy(component, path);
                p = NULL;
        } else if (p[0] == '/') {
-               if (p - path >= MAXNAMELEN)
+               if (p - path >= ZFS_MAX_DATASET_NAME_LEN)
                        return (SET_ERROR(ENAMETOOLONG));
                (void) strncpy(component, path, p - path);
                component[p - path] = '\0';
@@ -388,7 +388,7 @@ getcomponent(const char *path, char *component, const char **nextp)
                 */
                if (strchr(path, '/'))
                        return (SET_ERROR(EINVAL));
-               if (p - path >= MAXNAMELEN)
+               if (p - path >= ZFS_MAX_DATASET_NAME_LEN)
                        return (SET_ERROR(ENAMETOOLONG));
                (void) strncpy(component, path, p - path);
                component[p - path] = '\0';
@@ -416,7 +416,7 @@ dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag,
        dsl_dir_t *dd;
        uint64_t ddobj;
 
-       buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+       buf = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
        err = getcomponent(name, buf, &next);
        if (err != 0)
                goto error;
@@ -483,7 +483,7 @@ dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag,
                *tailp = next;
        *ddp = dd;
 error:
-       kmem_free(buf, MAXNAMELEN);
+       kmem_free(buf, ZFS_MAX_DATASET_NAME_LEN);
        return (err);
 }
 
@@ -978,7 +978,7 @@ dsl_dir_stats(dsl_dir_t *dd, nvlist_t *nv)
 
        if (dsl_dir_is_clone(dd)) {
                dsl_dataset_t *ds;
-               char buf[MAXNAMELEN];
+               char buf[ZFS_MAX_DATASET_NAME_LEN];
 
                VERIFY0(dsl_dataset_hold_obj(dd->dd_pool,
                    dsl_dir_phys(dd)->dd_origin_obj, FTAG, &ds));
@@ -1695,11 +1695,11 @@ static int
 dsl_valid_rename(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
 {
        int *deltap = arg;
-       char namebuf[MAXNAMELEN];
+       char namebuf[ZFS_MAX_DATASET_NAME_LEN];
 
        dsl_dataset_name(ds, namebuf);
 
-       if (strlen(namebuf) + *deltap >= MAXNAMELEN)
+       if (strlen(namebuf) + *deltap >= ZFS_MAX_DATASET_NAME_LEN)
                return (SET_ERROR(ENAMETOOLONG));
        return (0);
 }
@@ -1904,7 +1904,8 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
            dd->dd_myname, tx);
        ASSERT0(error);
 
-       (void) strcpy(dd->dd_myname, mynewname);
+       (void) strlcpy(dd->dd_myname, mynewname,
+           sizeof (dd->dd_myname));
        dsl_dir_rele(dd->dd_parent, dd);
        dsl_dir_phys(dd)->dd_parent_obj = newparent->dd_object;
        VERIFY0(dsl_dir_hold_obj(dp,
old mode 100755 (executable)
new mode 100644 (file)
index 28b101eee5475b11563266f3d6342cacda82023a..24836000f3b0fd61bea6996d5237e3c3cd964b22 100644 (file)
@@ -20,8 +20,9 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 Martin Matuska. All rights reserved.
+ * Copyright 2015, Joyent, Inc.
  */
 
 #include <sys/zfs_context.h>
 #define        ZPROP_RECVD_SUFFIX "$recvd"
 
 static int
-dodefault(const char *propname, int intsz, int numints, void *buf)
+dodefault(zfs_prop_t prop, int intsz, int numints, void *buf)
 {
-       zfs_prop_t prop;
-
        /*
         * The setonce properties are read-only, BUT they still
         * have a default value that can be used as the initial
         * value.
         */
-       if ((prop = zfs_name_to_prop(propname)) == ZPROP_INVAL ||
+       if (prop == ZPROP_INVAL ||
            (zfs_prop_readonly(prop) && !zfs_prop_setonce(prop)))
                return (SET_ERROR(ENOENT));
 
@@ -149,7 +148,7 @@ dsl_prop_get_dd(dsl_dir_t *dd, const char *propname,
        }
 
        if (err == ENOENT)
-               err = dodefault(propname, intsz, numints, buf);
+               err = dodefault(prop, intsz, numints, buf);
 
        strfree(inheritstr);
        strfree(recvdstr);
@@ -216,6 +215,58 @@ dsl_prop_get_ds(dsl_dataset_t *ds, const char *propname,
            intsz, numints, buf, setpoint, ds->ds_is_snapshot));
 }
 
+static dsl_prop_record_t *
+dsl_prop_record_find(dsl_dir_t *dd, const char *propname)
+{
+       dsl_prop_record_t *pr = NULL;
+
+       ASSERT(MUTEX_HELD(&dd->dd_lock));
+
+       for (pr = list_head(&dd->dd_props);
+           pr != NULL; pr = list_next(&dd->dd_props, pr)) {
+               if (strcmp(pr->pr_propname, propname) == 0)
+                       break;
+       }
+
+       return (pr);
+}
+
+static dsl_prop_record_t *
+dsl_prop_record_create(dsl_dir_t *dd, const char *propname)
+{
+       dsl_prop_record_t *pr;
+
+       ASSERT(MUTEX_HELD(&dd->dd_lock));
+
+       pr = kmem_alloc(sizeof (dsl_prop_record_t), KM_SLEEP);
+       pr->pr_propname = spa_strdup(propname);
+       list_create(&pr->pr_cbs, sizeof (dsl_prop_cb_record_t),
+           offsetof(dsl_prop_cb_record_t, cbr_pr_node));
+       list_insert_head(&dd->dd_props, pr);
+
+       return (pr);
+}
+
+void
+dsl_prop_init(dsl_dir_t *dd)
+{
+       list_create(&dd->dd_props, sizeof (dsl_prop_record_t),
+           offsetof(dsl_prop_record_t, pr_node));
+}
+
+void
+dsl_prop_fini(dsl_dir_t *dd)
+{
+       dsl_prop_record_t *pr;
+
+       while ((pr = list_remove_head(&dd->dd_props)) != NULL) {
+               list_destroy(&pr->pr_cbs);
+               spa_strfree((char *)pr->pr_propname);
+               kmem_free(pr, sizeof (dsl_prop_record_t));
+       }
+       list_destroy(&dd->dd_props);
+}
+
 /*
  * Register interest in the named property.  We'll call the callback
  * once to notify it of the current property value, and again each time
@@ -229,6 +280,7 @@ dsl_prop_register(dsl_dataset_t *ds, const char *propname,
 {
        dsl_dir_t *dd = ds->ds_dir;
        uint64_t value;
+       dsl_prop_record_t *pr;
        dsl_prop_cb_record_t *cbr;
        int err;
        ASSERTV(dsl_pool_t *dp = dd->dd_pool);
@@ -241,12 +293,16 @@ dsl_prop_register(dsl_dataset_t *ds, const char *propname,
 
        cbr = kmem_alloc(sizeof (dsl_prop_cb_record_t), KM_SLEEP);
        cbr->cbr_ds = ds;
-       cbr->cbr_propname = kmem_alloc(strlen(propname)+1, KM_SLEEP);
-       (void) strcpy((char *)cbr->cbr_propname, propname);
        cbr->cbr_func = callback;
        cbr->cbr_arg = cbarg;
+
        mutex_enter(&dd->dd_lock);
-       list_insert_head(&dd->dd_prop_cbs, cbr);
+       pr = dsl_prop_record_find(dd, propname);
+       if (pr == NULL)
+               pr = dsl_prop_record_create(dd, propname);
+       cbr->cbr_pr = pr;
+       list_insert_head(&pr->pr_cbs, cbr);
+       list_insert_head(&ds->ds_prop_cbs, cbr);
        mutex_exit(&dd->dd_lock);
 
        cbr->cbr_func(cbr->cbr_arg, value);
@@ -379,6 +435,9 @@ dsl_prop_predict(dsl_dir_t *dd, const char *propname,
 /*
  * Unregister this callback.  Return 0 on success, ENOENT if ddname is
  * invalid, or ENOMSG if no matching callback registered.
+ *
+ * NOTE: This function is no longer used internally but has been preserved
+ * to prevent breaking external consumers (Lustre, etc).
  */
 int
 dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
@@ -388,12 +447,12 @@ dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
        dsl_prop_cb_record_t *cbr;
 
        mutex_enter(&dd->dd_lock);
-       for (cbr = list_head(&dd->dd_prop_cbs);
-           cbr; cbr = list_next(&dd->dd_prop_cbs, cbr)) {
+       for (cbr = list_head(&ds->ds_prop_cbs);
+           cbr; cbr = list_next(&ds->ds_prop_cbs, cbr)) {
                if (cbr->cbr_ds == ds &&
                    cbr->cbr_func == callback &&
                    cbr->cbr_arg == cbarg &&
-                   strcmp(cbr->cbr_propname, propname) == 0)
+                   strcmp(cbr->cbr_pr->pr_propname, propname) == 0)
                        break;
        }
 
@@ -402,31 +461,43 @@ dsl_prop_unregister(dsl_dataset_t *ds, const char *propname,
                return (SET_ERROR(ENOMSG));
        }
 
-       list_remove(&dd->dd_prop_cbs, cbr);
+       list_remove(&ds->ds_prop_cbs, cbr);
+       list_remove(&cbr->cbr_pr->pr_cbs, cbr);
        mutex_exit(&dd->dd_lock);
-       kmem_free((void*)cbr->cbr_propname, strlen(cbr->cbr_propname)+1);
        kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
 
        return (0);
 }
 
-boolean_t
-dsl_prop_hascb(dsl_dataset_t *ds)
+/*
+ * Unregister all callbacks that are registered with the
+ * given callback argument.
+ */
+void
+dsl_prop_unregister_all(dsl_dataset_t *ds, void *cbarg)
 {
+       dsl_prop_cb_record_t *cbr, *next_cbr;
+
        dsl_dir_t *dd = ds->ds_dir;
-       boolean_t rv = B_FALSE;
-       dsl_prop_cb_record_t *cbr;
 
        mutex_enter(&dd->dd_lock);
-       for (cbr = list_head(&dd->dd_prop_cbs); cbr;
-           cbr = list_next(&dd->dd_prop_cbs, cbr)) {
-               if (cbr->cbr_ds == ds) {
-                       rv = B_TRUE;
-                       break;
+       next_cbr = list_head(&ds->ds_prop_cbs);
+       while (next_cbr != NULL) {
+               cbr = next_cbr;
+               next_cbr = list_next(&ds->ds_prop_cbs, cbr);
+               if (cbr->cbr_arg == cbarg) {
+                       list_remove(&ds->ds_prop_cbs, cbr);
+                       list_remove(&cbr->cbr_pr->pr_cbs, cbr);
+                       kmem_free(cbr, sizeof (dsl_prop_cb_record_t));
                }
        }
        mutex_exit(&dd->dd_lock);
-       return (rv);
+}
+
+boolean_t
+dsl_prop_hascb(dsl_dataset_t *ds)
+{
+       return (!list_is_empty(&ds->ds_prop_cbs));
 }
 
 /* ARGSUSED */
@@ -434,38 +505,50 @@ static int
 dsl_prop_notify_all_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
 {
        dsl_dir_t *dd = ds->ds_dir;
+       dsl_prop_record_t *pr;
        dsl_prop_cb_record_t *cbr;
 
        mutex_enter(&dd->dd_lock);
-       for (cbr = list_head(&dd->dd_prop_cbs); cbr;
-           cbr = list_next(&dd->dd_prop_cbs, cbr)) {
-               uint64_t value;
+       for (pr = list_head(&dd->dd_props);
+           pr; pr = list_next(&dd->dd_props, pr)) {
+               for (cbr = list_head(&pr->pr_cbs); cbr;
+                   cbr = list_next(&pr->pr_cbs, cbr)) {
+                       uint64_t value;
 
-               /*
-                * Callback entries do not have holds on their datasets
-                * so that datasets with registered callbacks are still
-                * eligible for eviction.  Unlike operations on callbacks
-                * for a single dataset, we are performing a recursive
-                * descent of related datasets and the calling context
-                * for this iteration only has a dataset hold on the root.
-                * Without a hold, the callback's pointer to the dataset
-                * could be invalidated by eviction at any time.
-                *
-                * Use dsl_dataset_try_add_ref() to verify that the
-                * dataset has not begun eviction processing and to
-                * prevent eviction from occurring for the duration
-                * of the callback.  If the hold attempt fails, this
-                * object is already being evicted and the callback can
-                * be safely ignored.
-                */
-               if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
-                       continue;
+                       /*
+                        * Callback entries do not have holds on their
+                        * datasets so that datasets with registered
+                        * callbacks are still eligible for eviction.
+                        * Unlike operations to update properties on a
+                        * single dataset, we are performing a recursive
+                        * descent of related head datasets.  The caller
+                        * of this function only has a dataset hold on
+                        * the passed in head dataset, not the snapshots
+                        * associated with this dataset.  Without a hold,
+                        * the dataset pointer within callback records
+                        * for snapshots can be invalidated by eviction
+                        * at any time.
+                        *
+                        * Use dsl_dataset_try_add_ref() to verify
+                        * that the dataset for a snapshot has not
+                        * begun eviction processing and to prevent
+                        * eviction from occurring for the duration of
+                        * the callback.  If the hold attempt fails,
+                        * this object is already being evicted and the
+                        * callback can be safely ignored.
+                        */
+                       if (ds != cbr->cbr_ds &&
+                           !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
+                               continue;
 
-               if (dsl_prop_get_ds(cbr->cbr_ds, cbr->cbr_propname,
-                   sizeof (value), 1, &value, NULL) == 0)
-                       cbr->cbr_func(cbr->cbr_arg, value);
+                       if (dsl_prop_get_ds(cbr->cbr_ds,
+                           cbr->cbr_pr->pr_propname, sizeof (value), 1,
+                           &value, NULL) == 0)
+                               cbr->cbr_func(cbr->cbr_arg, value);
 
-               dsl_dataset_rele(cbr->cbr_ds, FTAG);
+                       if (ds != cbr->cbr_ds)
+                               dsl_dataset_rele(cbr->cbr_ds, FTAG);
+               }
        }
        mutex_exit(&dd->dd_lock);
 
@@ -490,6 +573,7 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
     const char *propname, uint64_t value, int first)
 {
        dsl_dir_t *dd;
+       dsl_prop_record_t *pr;
        dsl_prop_cb_record_t *cbr;
        objset_t *mos = dp->dp_meta_objset;
        zap_cursor_t zc;
@@ -516,30 +600,33 @@ dsl_prop_changed_notify(dsl_pool_t *dp, uint64_t ddobj,
        }
 
        mutex_enter(&dd->dd_lock);
-       for (cbr = list_head(&dd->dd_prop_cbs); cbr;
-           cbr = list_next(&dd->dd_prop_cbs, cbr)) {
-               uint64_t propobj;
+       pr = dsl_prop_record_find(dd, propname);
+       if (pr != NULL) {
+               for (cbr = list_head(&pr->pr_cbs); cbr;
+                   cbr = list_next(&pr->pr_cbs, cbr)) {
+                       uint64_t propobj;
 
-               /*
-                * cbr->cbf_ds may be invalidated due to eviction,
-                * requiring the use of dsl_dataset_try_add_ref().
-                * See comment block in dsl_prop_notify_all_cb()
-                * for details.
-                */
-               if (strcmp(cbr->cbr_propname, propname) != 0 ||
-                   !dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
-                       continue;
+                       /*
+                        * cbr->cbr_ds may be invalidated due to eviction,
+                        * requiring the use of dsl_dataset_try_add_ref().
+                        * See comment block in dsl_prop_notify_all_cb()
+                        * for details.
+                        */
+                       if (!dsl_dataset_try_add_ref(dp, cbr->cbr_ds, FTAG))
+                               continue;
 
-               propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
+                       propobj = dsl_dataset_phys(cbr->cbr_ds)->ds_props_obj;
 
-               /*
-                * If the property is not set on this ds, then it is
-                * inherited here; call the callback.
-                */
-               if (propobj == 0 || zap_contains(mos, propobj, propname) != 0)
-                       cbr->cbr_func(cbr->cbr_arg, value);
+                       /*
+                        * If the property is not set on this ds, then it is
+                        * inherited here; call the callback.
+                        */
+                       if (propobj == 0 ||
+                           zap_contains(mos, propobj, propname) != 0)
+                               cbr->cbr_func(cbr->cbr_arg, value);
 
-               dsl_dataset_rele(cbr->cbr_ds, FTAG);
+                       dsl_dataset_rele(cbr->cbr_ds, FTAG);
+               }
        }
        mutex_exit(&dd->dd_lock);
 
@@ -572,7 +659,7 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
        int err;
        uint64_t version = spa_version(ds->ds_dir->dd_pool->dp_spa);
 
-       isint = (dodefault(propname, 8, 1, &intval) == 0);
+       isint = (dodefault(zfs_name_to_prop(propname), 8, 1, &intval) == 0);
 
        if (ds->ds_is_snapshot) {
                ASSERT(version >= SPA_VERSION_SNAP_PROPS);
@@ -679,10 +766,10 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname,
                         * ds here.
                         */
                        mutex_enter(&ds->ds_dir->dd_lock);
-                       for (cbr = list_head(&ds->ds_dir->dd_prop_cbs); cbr;
-                           cbr = list_next(&ds->ds_dir->dd_prop_cbs, cbr)) {
-                               if (cbr->cbr_ds == ds &&
-                                   strcmp(cbr->cbr_propname, propname) == 0)
+                       for (cbr = list_head(&ds->ds_prop_cbs); cbr;
+                           cbr = list_next(&ds->ds_prop_cbs, cbr)) {
+                               if (strcmp(cbr->cbr_pr->pr_propname,
+                                   propname) == 0)
                                        cbr->cbr_func(cbr->cbr_arg, intval);
                        }
                        mutex_exit(&ds->ds_dir->dd_lock);
@@ -1008,7 +1095,7 @@ dsl_prop_get_all_ds(dsl_dataset_t *ds, nvlist_t **nvp,
        dsl_pool_t *dp = dd->dd_pool;
        objset_t *mos = dp->dp_meta_objset;
        int err = 0;
-       char setpoint[MAXNAMELEN];
+       char setpoint[ZFS_MAX_DATASET_NAME_LEN];
 
        VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 
@@ -1130,7 +1217,7 @@ dsl_prop_nvlist_add_uint64(nvlist_t *nv, zfs_prop_t prop, uint64_t value)
        VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
        VERIFY(nvlist_add_uint64(propval, ZPROP_VALUE, value) == 0);
        /* Indicate the default source if we can. */
-       if (dodefault(propname, 8, 1, &default_value) == 0 &&
+       if (dodefault(prop, 8, 1, &default_value) == 0 &&
            value == default_value) {
                VERIFY(nvlist_add_string(propval, ZPROP_SOURCE, "") == 0);
        }
@@ -1158,6 +1245,7 @@ dsl_prop_nvlist_add_string(nvlist_t *nv, zfs_prop_t prop, const char *value)
 #if defined(_KERNEL) && defined(HAVE_SPL)
 EXPORT_SYMBOL(dsl_prop_register);
 EXPORT_SYMBOL(dsl_prop_unregister);
+EXPORT_SYMBOL(dsl_prop_unregister_all);
 EXPORT_SYMBOL(dsl_prop_get);
 EXPORT_SYMBOL(dsl_prop_get_integer);
 EXPORT_SYMBOL(dsl_prop_get_all);
index b989e763386b2759420841a4eb637340307e812e..41b3ce79b04def118f7ab933883eecbecba4ade6 100644 (file)
@@ -20,7 +20,8 @@
  */
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright 2016 Gary Mills
  */
 
 #include <sys/dsl_scan.h>
@@ -55,7 +56,8 @@ typedef int (scan_cb_t)(dsl_pool_t *, const blkptr_t *,
 
 static scan_cb_t dsl_scan_scrub_cb;
 static void dsl_scan_cancel_sync(void *, dmu_tx_t *);
-static void dsl_scan_sync_state(dsl_scan_t *, dmu_tx_t *tx);
+static void dsl_scan_sync_state(dsl_scan_t *, dmu_tx_t *);
+static boolean_t dsl_scan_restarting(dsl_scan_t *, dmu_tx_t *);
 
 int zfs_top_maxinflight = 32;          /* maximum I/Os per top-level */
 int zfs_resilver_delay = 2;            /* number of ticks to delay resilver */
@@ -76,6 +78,11 @@ ulong zfs_free_max_blocks = 100000;
        ((scn)->scn_phys.scn_func == POOL_SCAN_SCRUB || \
        (scn)->scn_phys.scn_func == POOL_SCAN_RESILVER)
 
+/*
+ * Enable/disable the processing of the free_bpobj object.
+ */
+int zfs_free_bpobj_enabled = 1;
+
 /* the order has to match pool_scan_type */
 static scan_cb_t *scan_funcs[POOL_SCAN_FUNCS] = {
        NULL,
@@ -240,11 +247,9 @@ dsl_scan_setup_sync(void *arg, dmu_tx_t *tx)
 
                if (vdev_resilver_needed(spa->spa_root_vdev,
                    &scn->scn_phys.scn_min_txg, &scn->scn_phys.scn_max_txg)) {
-                       spa_event_notify(spa, NULL,
-                           FM_EREPORT_ZFS_RESILVER_START);
+                       spa_event_notify(spa, NULL, ESC_ZFS_RESILVER_START);
                } else {
-                       spa_event_notify(spa, NULL,
-                           FM_EREPORT_ZFS_SCRUB_START);
+                       spa_event_notify(spa, NULL, ESC_ZFS_SCRUB_START);
                }
 
                spa->spa_scrub_started = B_TRUE;
@@ -323,8 +328,15 @@ dsl_scan_done(dsl_scan_t *scn, boolean_t complete, dmu_tx_t *tx)
        else
                scn->scn_phys.scn_state = DSS_CANCELED;
 
-       spa_history_log_internal(spa, "scan done", tx,
-           "complete=%u", complete);
+       if (dsl_scan_restarting(scn, tx))
+               spa_history_log_internal(spa, "scan aborted, restarting", tx,
+                   "errors=%llu", spa_get_errlog_size(spa));
+       else if (!complete)
+               spa_history_log_internal(spa, "scan cancelled", tx,
+                   "errors=%llu", spa_get_errlog_size(spa));
+       else
+               spa_history_log_internal(spa, "scan done", tx,
+                   "errors=%llu", spa_get_errlog_size(spa));
 
        if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) {
                mutex_enter(&spa->spa_scrub_lock);
@@ -345,8 +357,7 @@ dsl_scan_done(dsl_scan_t *scn, boolean_t complete, dmu_tx_t *tx)
                    complete ? scn->scn_phys.scn_max_txg : 0, B_TRUE);
                if (complete) {
                        spa_event_notify(spa, NULL, scn->scn_phys.scn_min_txg ?
-                           FM_EREPORT_ZFS_RESILVER_FINISH :
-                           FM_EREPORT_ZFS_SCRUB_FINISH);
+                           ESC_ZFS_RESILVER_FINISH : ESC_ZFS_SCRUB_FINISH);
                }
                spa_errlog_rotate(spa);
 
@@ -619,7 +630,8 @@ dsl_scan_check_resume(dsl_scan_t *scn, const dnode_phys_t *dnp,
                 * If we already visited this bp & everything below (in
                 * a prior txg sync), don't bother doing it again.
                 */
-               if (zbookmark_is_before(dnp, zb, &scn->scn_phys.scn_bookmark))
+               if (zbookmark_subtree_completed(dnp, zb,
+                   &scn->scn_phys.scn_bookmark))
                        return (B_TRUE);
 
                /*
@@ -680,7 +692,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
                        dsl_scan_visitbp(cbp, &czb, dnp,
                            ds, scn, ostype, tx);
                }
-               (void) arc_buf_remove_ref(buf, &buf);
+               arc_buf_destroy(buf, &buf);
        } else if (BP_GET_TYPE(bp) == DMU_OT_DNODE) {
                arc_flags_t flags = ARC_FLAG_WAIT;
                dnode_phys_t *cdnp;
@@ -694,19 +706,23 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
                        scn->scn_phys.scn_errors++;
                        return (err);
                }
-               for (i = 0, cdnp = buf->b_data; i < epb; i++, cdnp++) {
+               for (i = 0, cdnp = buf->b_data; i < epb;
+                   i += cdnp->dn_extra_slots + 1,
+                   cdnp += cdnp->dn_extra_slots + 1) {
                        for (j = 0; j < cdnp->dn_nblkptr; j++) {
                                blkptr_t *cbp = &cdnp->dn_blkptr[j];
                                dsl_scan_prefetch(scn, buf, cbp,
                                    zb->zb_objset, zb->zb_blkid * epb + i, j);
                        }
                }
-               for (i = 0, cdnp = buf->b_data; i < epb; i++, cdnp++) {
+               for (i = 0, cdnp = buf->b_data; i < epb;
+                   i += cdnp->dn_extra_slots + 1,
+                   cdnp += cdnp->dn_extra_slots + 1) {
                        dsl_scan_visitdnode(scn, ds, ostype,
                            cdnp, zb->zb_blkid * epb + i, tx);
                }
 
-               (void) arc_buf_remove_ref(buf, &buf);
+               arc_buf_destroy(buf, &buf);
        } else if (BP_GET_TYPE(bp) == DMU_OT_OBJSET) {
                arc_flags_t flags = ARC_FLAG_WAIT;
                objset_phys_t *osp;
@@ -738,7 +754,7 @@ dsl_scan_recurse(dsl_scan_t *scn, dsl_dataset_t *ds, dmu_objset_type_t ostype,
                            &osp->os_userused_dnode,
                            DMU_USERUSED_OBJECT, tx);
                }
-               (void) arc_buf_remove_ref(buf, &buf);
+               arc_buf_destroy(buf, &buf);
        }
 
        return (0);
@@ -764,7 +780,7 @@ dsl_scan_visitdnode(dsl_scan_t *scn, dsl_dataset_t *ds,
                zbookmark_phys_t czb;
                SET_BOOKMARK(&czb, ds ? ds->ds_object : 0, object,
                    0, DMU_SPILL_BLKID);
-               dsl_scan_visitbp(&dnp->dn_spill,
+               dsl_scan_visitbp(DN_SPILL_BLKPTR(dnp),
                    &czb, dnp, ds, scn, ostype, tx);
        }
 }
@@ -866,7 +882,16 @@ dsl_scan_ds_destroyed(dsl_dataset_t *ds, dmu_tx_t *tx)
 
        if (scn->scn_phys.scn_bookmark.zb_objset == ds->ds_object) {
                if (ds->ds_is_snapshot) {
-                       /* Note, scn_cur_{min,max}_txg stays the same. */
+                       /*
+                        * Note:
+                        *  - scn_cur_{min,max}_txg stays the same.
+                        *  - Setting the flag is not really necessary if
+                        *    scn_cur_max_txg == scn_max_txg, because there
+                        *    is nothing after this snapshot that we care
+                        *    about.  However, we set it anyway and then
+                        *    ignore it when we retraverse it in
+                        *    dsl_scan_visitds().
+                        */
                        scn->scn_phys.scn_bookmark.zb_objset =
                            dsl_dataset_phys(ds)->ds_next_snap_obj;
                        zfs_dbgmsg("destroying ds %llu; currently traversing; "
@@ -906,9 +931,6 @@ dsl_scan_ds_destroyed(dsl_dataset_t *ds, dmu_tx_t *tx)
                        zfs_dbgmsg("destroying ds %llu; in queue; removing",
                            (u_longlong_t)ds->ds_object);
                }
-       } else {
-               zfs_dbgmsg("destroying ds %llu; ignoring",
-                   (u_longlong_t)ds->ds_object);
        }
 
        /*
@@ -1062,6 +1084,46 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx)
 
        VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds));
 
+       if (scn->scn_phys.scn_cur_min_txg >=
+           scn->scn_phys.scn_max_txg) {
+               /*
+                * This can happen if this snapshot was created after the
+                * scan started, and we already completed a previous snapshot
+                * that was created after the scan started.  This snapshot
+                * only references blocks with:
+                *
+                *      birth < our ds_creation_txg
+                *      cur_min_txg is no less than ds_creation_txg.
+                *      We have already visited these blocks.
+                * or
+                *      birth > scn_max_txg
+                *      The scan requested not to visit these blocks.
+                *
+                * Subsequent snapshots (and clones) can reference our
+                * blocks, or blocks with even higher birth times.
+                * Therefore we do not need to visit them either,
+                * so we do not add them to the work queue.
+                *
+                * Note that checking for cur_min_txg >= cur_max_txg
+                * is not sufficient, because in that case we may need to
+                * visit subsequent snapshots.  This happens when min_txg > 0,
+                * which raises cur_min_txg.  In this case we will visit
+                * this dataset but skip all of its blocks, because the
+                * rootbp's birth time is < cur_min_txg.  Then we will
+                * add the next snapshots/clones to the work queue.
+                */
+               char *dsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
+               dsl_dataset_name(ds, dsname);
+               zfs_dbgmsg("scanning dataset %llu (%s) is unnecessary because "
+                   "cur_min_txg (%llu) >= max_txg (%llu)",
+                   dsobj, dsname,
+                   scn->scn_phys.scn_cur_min_txg,
+                   scn->scn_phys.scn_max_txg);
+               kmem_free(dsname, MAXNAMELEN);
+
+               goto out;
+       }
+
        if (dmu_objset_from_ds(ds, &os))
                goto out;
 
@@ -1081,7 +1143,7 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx)
        dmu_buf_will_dirty(ds->ds_dbuf, tx);
        dsl_scan_visit_rootbp(scn, ds, &dsl_dataset_phys(ds)->ds_bp, tx);
 
-       dsname = kmem_alloc(ZFS_MAXNAMELEN, KM_SLEEP);
+       dsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
        dsl_dataset_name(ds, dsname);
        zfs_dbgmsg("scanned dataset %llu (%s) with min=%llu max=%llu; "
            "pausing=%u",
@@ -1089,7 +1151,7 @@ dsl_scan_visitds(dsl_scan_t *scn, uint64_t dsobj, dmu_tx_t *tx)
            (longlong_t)scn->scn_phys.scn_cur_min_txg,
            (longlong_t)scn->scn_phys.scn_cur_max_txg,
            (int)scn->scn_pausing);
-       kmem_free(dsname, ZFS_MAXNAMELEN);
+       kmem_free(dsname, ZFS_MAX_DATASET_NAME_LEN);
 
        if (scn->scn_pausing)
                goto out;
@@ -1458,8 +1520,7 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
         * that we can restart an old-style scan while the pool is being
         * imported (see dsl_scan_init).
         */
-       if (scn->scn_restart_txg != 0 &&
-           scn->scn_restart_txg <= tx->tx_txg) {
+       if (dsl_scan_restarting(scn, tx)) {
                pool_scan_func_t func = POOL_SCAN_SCRUB;
                dsl_scan_done(scn, B_FALSE, tx);
                if (vdev_resilver_needed(spa->spa_root_vdev, NULL, NULL))
@@ -1469,11 +1530,24 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
                dsl_scan_setup_sync(&func, tx);
        }
 
+       /*
+        * Only process scans in sync pass 1.
+        */
+       if (spa_sync_pass(dp->dp_spa) > 1)
+               return;
+
+       /*
+        * If the spa is shutting down, then stop scanning. This will
+        * ensure that the scan does not dirty any new data during the
+        * shutdown phase.
+        */
+       if (spa_shutting_down(spa))
+               return;
+
        /*
         * If the scan is inactive due to a stalled async destroy, try again.
         */
-       if ((!scn->scn_async_stalled && !dsl_scan_active(scn)) ||
-           spa_sync_pass(dp->dp_spa) > 1)
+       if (!scn->scn_async_stalled && !dsl_scan_active(scn))
                return;
 
        scn->scn_visited_this_txg = 0;
@@ -1488,7 +1562,8 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
         * have to worry about traversing it.  It is also faster to free the
         * blocks than to scrub them.
         */
-       if (spa_version(dp->dp_spa) >= SPA_VERSION_DEADLISTS) {
+       if (zfs_free_bpobj_enabled &&
+           spa_version(dp->dp_spa) >= SPA_VERSION_DEADLISTS) {
                scn->scn_is_bptree = B_FALSE;
                scn->scn_zio_root = zio_root(dp->dp_spa, NULL,
                    NULL, ZIO_FLAG_MUSTSUCCEED);
@@ -1560,7 +1635,8 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
        }
        if (err != 0)
                return;
-       if (!scn->scn_async_destroying && zfs_free_leak_on_eio &&
+       if (dp->dp_free_dir != NULL && !scn->scn_async_destroying &&
+           zfs_free_leak_on_eio &&
            (dsl_dir_phys(dp->dp_free_dir)->dd_used_bytes != 0 ||
            dsl_dir_phys(dp->dp_free_dir)->dd_compressed_bytes != 0 ||
            dsl_dir_phys(dp->dp_free_dir)->dd_uncompressed_bytes != 0)) {
@@ -1586,7 +1662,7 @@ dsl_scan_sync(dsl_pool_t *dp, dmu_tx_t *tx)
                    -dsl_dir_phys(dp->dp_free_dir)->dd_compressed_bytes,
                    -dsl_dir_phys(dp->dp_free_dir)->dd_uncompressed_bytes, tx);
        }
-       if (!scn->scn_async_destroying) {
+       if (dp->dp_free_dir != NULL && !scn->scn_async_destroying) {
                /* finished; verify that space accounting went to zero */
                ASSERT0(dsl_dir_phys(dp->dp_free_dir)->dd_used_bytes);
                ASSERT0(dsl_dir_phys(dp->dp_free_dir)->dd_compressed_bytes);
@@ -1874,6 +1950,13 @@ dsl_scan(dsl_pool_t *dp, pool_scan_func_t func)
            dsl_scan_setup_sync, &func, 0, ZFS_SPACE_CHECK_NONE));
 }
 
+static boolean_t
+dsl_scan_restarting(dsl_scan_t *scn, dmu_tx_t *tx)
+{
+       return (scn->scn_restart_txg != 0 &&
+           scn->scn_restart_txg <= tx->tx_txg);
+}
+
 #if defined(_KERNEL) && defined(HAVE_SPL)
 module_param(zfs_top_maxinflight, int, 0644);
 MODULE_PARM_DESC(zfs_top_maxinflight, "Max I/Os per top-level");
@@ -1904,4 +1987,7 @@ MODULE_PARM_DESC(zfs_no_scrub_prefetch, "Set to disable scrub prefetching");
 
 module_param(zfs_free_max_blocks, ulong, 0644);
 MODULE_PARM_DESC(zfs_free_max_blocks, "Max number of blocks freed in one txg");
+
+module_param(zfs_free_bpobj_enabled, int, 0644);
+MODULE_PARM_DESC(zfs_free_bpobj_enabled, "Enable processing of the free_bpobj");
 #endif
index 1b234ed480f92bd4f2bf765acb6e06444a833cd8..a6d1aa937ef126932a8061d6b161ed53d3e1762f 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  */
 
@@ -181,7 +181,7 @@ dsl_dataset_user_hold_sync_one_impl(nvlist_t *tmpholds, dsl_dataset_t *ds,
 }
 
 typedef struct zfs_hold_cleanup_arg {
-       char zhca_spaname[MAXNAMELEN];
+       char zhca_spaname[ZFS_MAX_DATASET_NAME_LEN];
        uint64_t zhca_spa_load_guid;
        nvlist_t *zhca_holds;
 } zfs_hold_cleanup_arg_t;
@@ -580,7 +580,7 @@ dsl_dataset_user_release_impl(nvlist_t *holds, nvlist_t *errlist,
                        error = dsl_dataset_hold_obj_string(tmpdp,
                            nvpair_name(pair), FTAG, &ds);
                        if (error == 0) {
-                               char name[MAXNAMELEN];
+                               char name[ZFS_MAX_DATASET_NAME_LEN];
                                dsl_dataset_name(ds, name);
                                dsl_pool_config_exit(tmpdp, FTAG);
                                dsl_dataset_rele(ds, FTAG);
diff --git a/zfs/module/zfs/edonr_zfs.c b/zfs/module/zfs/edonr_zfs.c
new file mode 100644 (file)
index 0000000..3c7d986
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 2013 Saso Kiselkov.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#include <sys/zfs_context.h>
+#include <sys/zio.h>
+#include <sys/edonr.h>
+#include <sys/zfs_context.h>   /* For CTASSERT() */
+
+#define        EDONR_MODE              512
+#define        EDONR_BLOCK_SIZE        EdonR512_BLOCK_SIZE
+
+/*
+ * Native zio_checksum interface for the Edon-R hash function.
+ */
+/*ARGSUSED*/
+void
+zio_checksum_edonr_native(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
+{
+       uint8_t         digest[EDONR_MODE / 8];
+       EdonRState      ctx;
+
+       ASSERT(ctx_template != NULL);
+       bcopy(ctx_template, &ctx, sizeof (ctx));
+       EdonRUpdate(&ctx, buf, size * 8);
+       EdonRFinal(&ctx, digest);
+       bcopy(digest, zcp->zc_word, sizeof (zcp->zc_word));
+}
+
+/*
+ * Byteswapped zio_checksum interface for the Edon-R hash function.
+ */
+void
+zio_checksum_edonr_byteswap(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
+{
+       zio_cksum_t     tmp;
+
+       zio_checksum_edonr_native(buf, size, ctx_template, &tmp);
+       zcp->zc_word[0] = BSWAP_64(zcp->zc_word[0]);
+       zcp->zc_word[1] = BSWAP_64(zcp->zc_word[1]);
+       zcp->zc_word[2] = BSWAP_64(zcp->zc_word[2]);
+       zcp->zc_word[3] = BSWAP_64(zcp->zc_word[3]);
+}
+
+void *
+zio_checksum_edonr_tmpl_init(const zio_cksum_salt_t *salt)
+{
+       EdonRState      *ctx;
+       uint8_t         salt_block[EDONR_BLOCK_SIZE];
+
+       /*
+        * Edon-R needs all but the last hash invocation to be on full-size
+        * blocks, but the salt is too small. Rather than simply padding it
+        * with zeros, we expand the salt into a new salt block of proper
+        * size by double-hashing it (the new salt block will be composed of
+        * H(salt) || H(H(salt))).
+        */
+       CTASSERT(EDONR_BLOCK_SIZE == 2 * (EDONR_MODE / 8));
+       EdonRHash(EDONR_MODE, salt->zcs_bytes, sizeof (salt->zcs_bytes) * 8,
+           salt_block);
+       EdonRHash(EDONR_MODE, salt_block, EDONR_MODE, salt_block +
+           EDONR_MODE / 8);
+
+       /*
+        * Feed the new salt block into the hash function - this will serve
+        * as our MAC key.
+        */
+       ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
+       EdonRInit(ctx, EDONR_MODE);
+       EdonRUpdate(ctx, salt_block, sizeof (salt_block) * 8);
+       return (ctx);
+}
+
+void
+zio_checksum_edonr_tmpl_free(void *ctx_template)
+{
+       EdonRState      *ctx = ctx_template;
+
+       bzero(ctx, sizeof (*ctx));
+       kmem_free(ctx, sizeof (*ctx));
+}
index 999bd8adc5187efff9a2747129296dffe3e2aaf6..6c569ffc444aa1a3a8e54dd85713bbe9dec0eb2f 100644 (file)
@@ -84,6 +84,9 @@ static int zevent_len_cur = 0;
 static int zevent_waiters = 0;
 static int zevent_flags = 0;
 
+/* Num events rate limited since the last time zfs_zevent_next() was called */
+static uint64_t ratelimit_dropped = 0;
+
 /*
  * The EID (Event IDentifier) is used to uniquely tag a zevent when it is
  * posted.  The posted EIDs are monotonically increasing but not persistent.
@@ -97,7 +100,6 @@ static list_t zevent_list;
 static kcondvar_t zevent_cv;
 #endif /* _KERNEL */
 
-extern void fastreboot_disable_highpil(void);
 
 /*
  * Common fault management kstats to record event generation failures
@@ -154,7 +156,7 @@ fm_printf(int depth, int c, int cols, const char *format, ...)
 }
 
 /*
- * Recursively print a nvlist in the specified column width and return the
+ * Recursively print an nvlist in the specified column width and return the
  * column we end up in.  This function is called recursively by fm_nvprint(),
  * below.  We generically format the entire nvpair using hexadecimal
  * integers and strings, and elide any integer arrays.  Arrays are basically
@@ -427,8 +429,6 @@ zfs_zevent_alloc(void)
        zevent_t *ev;
 
        ev = kmem_zalloc(sizeof (zevent_t), KM_SLEEP);
-       if (ev == NULL)
-               return (NULL);
 
        list_create(&ev->ev_ze_list, sizeof (zfs_zevent_t),
                    offsetof(zfs_zevent_t, ze_node));
@@ -523,25 +523,25 @@ zfs_zevent_post(nvlist_t *nvl, nvlist_t *detector, zevent_cb_t *cb)
 
        error = nvlist_add_int64_array(nvl, FM_EREPORT_TIME, tv_array, 2);
        if (error) {
-               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
                goto out;
        }
 
        eid = atomic_inc_64_nv(&zevent_eid);
        error = nvlist_add_uint64(nvl, FM_EREPORT_EID, eid);
        if (error) {
-               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
                goto out;
        }
 
        error = nvlist_size(nvl, &nvl_size, NV_ENCODE_NATIVE);
        if (error) {
-               atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
                goto out;
        }
 
        if (nvl_size > ERPT_DATA_SZ || nvl_size == 0) {
-               atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
                error = EOVERFLOW;
                goto out;
        }
@@ -551,7 +551,7 @@ zfs_zevent_post(nvlist_t *nvl, nvlist_t *detector, zevent_cb_t *cb)
 
        ev = zfs_zevent_alloc();
        if (ev == NULL) {
-               atomic_add_64(&erpt_kstat_data.erpt_dropped.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_dropped.value.ui64);
                error = ENOMEM;
                goto out;
        }
@@ -655,8 +655,14 @@ zfs_zevent_next(zfs_zevent_t *ze, nvlist_t **event, uint64_t *event_size,
 
        ze->ze_zevent = ev;
        list_insert_head(&ev->ev_ze_list, ze);
-       nvlist_dup(ev->ev_nvl, event, KM_SLEEP);
+       (void) nvlist_dup(ev->ev_nvl, event, KM_SLEEP);
        *dropped = ze->ze_dropped;
+
+#ifdef _KERNEL
+       /* Include events dropped due to rate limiting */
+       *dropped += ratelimit_dropped;
+       ratelimit_dropped = 0;
+#endif
        ze->ze_dropped = 0;
 out:
        mutex_exit(&zevent_lock);
@@ -1025,8 +1031,7 @@ fm_payload_set(nvlist_t *payload, ...)
        va_end(ap);
 
        if (ret)
-               atomic_add_64(
-                   &erpt_kstat_data.payload_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.payload_set_failed.value.ui64);
 }
 
 /*
@@ -1059,24 +1064,24 @@ fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class,
        int ret;
 
        if (version != FM_EREPORT_VERS0) {
-               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
                return;
        }
 
        (void) snprintf(ereport_class, FM_MAX_CLASS, "%s.%s",
            FM_EREPORT_CLASS, erpt_class);
        if (nvlist_add_string(ereport, FM_CLASS, ereport_class) != 0) {
-               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
                return;
        }
 
        if (nvlist_add_uint64(ereport, FM_EREPORT_ENA, ena)) {
-               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
        }
 
        if (nvlist_add_nvlist(ereport, FM_EREPORT_DETECTOR,
            (nvlist_t *)detector) != 0) {
-               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
        }
 
        va_start(ap, detector);
@@ -1085,7 +1090,7 @@ fm_ereport_set(nvlist_t *ereport, int version, const char *erpt_class,
        va_end(ap);
 
        if (ret)
-               atomic_add_64(&erpt_kstat_data.erpt_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.erpt_set_failed.value.ui64);
 }
 
 /*
@@ -1108,19 +1113,19 @@ static int
 fm_fmri_hc_set_common(nvlist_t *fmri, int version, const nvlist_t *auth)
 {
        if (version != FM_HC_SCHEME_VERSION) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return (0);
        }
 
        if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0 ||
            nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return (0);
        }
 
        if (auth != NULL && nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
            (nvlist_t *)auth) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return (0);
        }
 
@@ -1152,22 +1157,22 @@ fm_fmri_hc_set(nvlist_t *fmri, int version, const nvlist_t *auth,
                pairs[i] = fm_nvlist_create(nva);
                if (nvlist_add_string(pairs[i], FM_FMRI_HC_NAME, name) != 0 ||
                    nvlist_add_string(pairs[i], FM_FMRI_HC_ID, idstr) != 0) {
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                }
        }
        va_end(ap);
 
        if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs, npairs) != 0)
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
 
        for (i = 0; i < npairs; i++)
                fm_nvlist_destroy(pairs[i], FM_NVA_RETAIN);
 
        if (snvl != NULL) {
                if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                }
        }
 }
@@ -1192,20 +1197,20 @@ fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
         */
        if (nvlist_lookup_nvlist_array(bboard, FM_FMRI_HC_LIST, &hcl, &n)
            != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
        for (i = 0; i < n; i++) {
                if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME,
                    &hcname) != 0) {
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                        return;
                }
                if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &hcid) != 0) {
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                        return;
                }
 
@@ -1217,8 +1222,8 @@ fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
                                        fm_nvlist_destroy(pairs[j],
                                            FM_NVA_RETAIN);
                        }
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                        return;
                }
        }
@@ -1242,8 +1247,8 @@ fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
                                        fm_nvlist_destroy(pairs[j],
                                            FM_NVA_RETAIN);
                        }
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                        return;
                }
        }
@@ -1254,7 +1259,7 @@ fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
         */
        if (nvlist_add_nvlist_array(fmri, FM_FMRI_HC_LIST, pairs,
            npairs + n) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
@@ -1264,8 +1269,8 @@ fm_fmri_hc_create(nvlist_t *fmri, int version, const nvlist_t *auth,
 
        if (snvl != NULL) {
                if (nvlist_add_nvlist(fmri, FM_FMRI_HC_SPECIFIC, snvl) != 0) {
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                        return;
                }
        }
@@ -1291,7 +1296,7 @@ fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth,
        int err = 0;
 
        if (version != DEV_SCHEME_VERSION0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
@@ -1312,7 +1317,7 @@ fm_fmri_dev_set(nvlist_t *fmri_dev, int version, const nvlist_t *auth,
                err |= nvlist_add_string(fmri_dev, FM_FMRI_DEV_TGTPTLUN0, tpl0);
 
        if (err)
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
 
 }
 
@@ -1337,35 +1342,35 @@ fm_fmri_cpu_set(nvlist_t *fmri_cpu, int version, const nvlist_t *auth,
        uint64_t *failedp = &erpt_kstat_data.fmri_set_failed.value.ui64;
 
        if (version < CPU_SCHEME_VERSION1) {
-               atomic_add_64(failedp, 1);
+               atomic_inc_64(failedp);
                return;
        }
 
        if (nvlist_add_uint8(fmri_cpu, FM_VERSION, version) != 0) {
-               atomic_add_64(failedp, 1);
+               atomic_inc_64(failedp);
                return;
        }
 
        if (nvlist_add_string(fmri_cpu, FM_FMRI_SCHEME,
            FM_FMRI_SCHEME_CPU) != 0) {
-               atomic_add_64(failedp, 1);
+               atomic_inc_64(failedp);
                return;
        }
 
        if (auth != NULL && nvlist_add_nvlist(fmri_cpu, FM_FMRI_AUTHORITY,
            (nvlist_t *)auth) != 0)
-               atomic_add_64(failedp, 1);
+               atomic_inc_64(failedp);
 
        if (nvlist_add_uint32(fmri_cpu, FM_FMRI_CPU_ID, cpu_id) != 0)
-               atomic_add_64(failedp, 1);
+               atomic_inc_64(failedp);
 
        if (cpu_maskp != NULL && nvlist_add_uint8(fmri_cpu, FM_FMRI_CPU_MASK,
            *cpu_maskp) != 0)
-               atomic_add_64(failedp, 1);
+               atomic_inc_64(failedp);
 
        if (serial_idp == NULL || nvlist_add_string(fmri_cpu,
            FM_FMRI_CPU_SERIAL_ID, (char *)serial_idp) != 0)
-                       atomic_add_64(failedp, 1);
+                       atomic_inc_64(failedp);
 }
 
 /*
@@ -1386,49 +1391,47 @@ fm_fmri_mem_set(nvlist_t *fmri, int version, const nvlist_t *auth,
     const char *unum, const char *serial, uint64_t offset)
 {
        if (version != MEM_SCHEME_VERSION0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
        if (!serial && (offset != (uint64_t)-1)) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
        if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
        if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_MEM) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
        if (auth != NULL) {
                if (nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY,
                    (nvlist_t *)auth) != 0) {
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                }
        }
 
        if (nvlist_add_string(fmri, FM_FMRI_MEM_UNUM, unum) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
        }
 
        if (serial != NULL) {
                if (nvlist_add_string_array(fmri, FM_FMRI_MEM_SERIAL_ID,
                    (char **)&serial, 1) != 0) {
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                }
-               if (offset != (uint64_t)-1) {
-                       if (nvlist_add_uint64(fmri, FM_FMRI_MEM_OFFSET,
-                           offset) != 0) {
-                               atomic_add_64(&erpt_kstat_data.
-                                   fmri_set_failed.value.ui64, 1);
-                       }
+               if (offset != (uint64_t)-1 && nvlist_add_uint64(fmri,
+                   FM_FMRI_MEM_OFFSET, offset) != 0) {
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                }
        }
 }
@@ -1438,28 +1441,28 @@ fm_fmri_zfs_set(nvlist_t *fmri, int version, uint64_t pool_guid,
     uint64_t vdev_guid)
 {
        if (version != ZFS_SCHEME_VERSION0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
        if (nvlist_add_uint8(fmri, FM_VERSION, version) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
        if (nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_ZFS) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
                return;
        }
 
        if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_POOL, pool_guid) != 0) {
-               atomic_add_64(&erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+               atomic_inc_64(&erpt_kstat_data.fmri_set_failed.value.ui64);
        }
 
        if (vdev_guid != 0) {
                if (nvlist_add_uint64(fmri, FM_FMRI_ZFS_VDEV, vdev_guid) != 0) {
-                       atomic_add_64(
-                           &erpt_kstat_data.fmri_set_failed.value.ui64, 1);
+                       atomic_inc_64(
+                           &erpt_kstat_data.fmri_set_failed.value.ui64);
                }
        }
 }
@@ -1592,6 +1595,19 @@ fm_ena_time_get(uint64_t ena)
        return (time);
 }
 
+#ifdef _KERNEL
+/*
+ * Helper function to increment ereport dropped count.  Used by the event
+ * rate limiting code to give feedback to the user about how many events were
+ * rate limited by including them in the 'dropped' count.
+ */
+void
+fm_erpt_dropped_increment(void)
+{
+       atomic_inc_64(&ratelimit_dropped);
+}
+#endif
+
 #ifdef _KERNEL
 void
 fm_init(void)
index 59bcefd346c0e41a0cb68cfad9f8879416fa7dae..e54eeeae266c2d7912d14f7660e50405c8e52edc 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
 
 #define        WITH_DF_BLOCK_ALLOCATOR
 
-/*
- * Allow allocations to switch to gang blocks quickly. We do this to
- * avoid having to load lots of space_maps in a given txg. There are,
- * however, some cases where we want to avoid "fast" ganging and instead
- * we want to do an exhaustive search of all metaslabs on this device.
- * Currently we don't allow any gang, slog, or dump device related allocations
- * to "fast" gang.
- */
-#define        CAN_FASTGANG(flags) \
-       (!((flags) & (METASLAB_GANG_CHILD | METASLAB_GANG_HEADER | \
-       METASLAB_GANG_AVOID)))
+#define        GANG_ALLOCATION(flags) \
+       ((flags) & (METASLAB_GANG_CHILD | METASLAB_GANG_HEADER))
 
 #define        METASLAB_WEIGHT_PRIMARY         (1ULL << 63)
 #define        METASLAB_WEIGHT_SECONDARY       (1ULL << 62)
@@ -198,7 +189,8 @@ metaslab_class_create(spa_t *spa, metaslab_ops_t *ops)
        mc->mc_spa = spa;
        mc->mc_rotor = NULL;
        mc->mc_ops = ops;
-       mutex_init(&mc->mc_fastwrite_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&mc->mc_lock, NULL, MUTEX_DEFAULT, NULL);
+       refcount_create_tracked(&mc->mc_alloc_slots);
 
        return (mc);
 }
@@ -212,7 +204,8 @@ metaslab_class_destroy(metaslab_class_t *mc)
        ASSERT(mc->mc_space == 0);
        ASSERT(mc->mc_dspace == 0);
 
-       mutex_destroy(&mc->mc_fastwrite_lock);
+       refcount_destroy(&mc->mc_alloc_slots);
+       mutex_destroy(&mc->mc_lock);
        kmem_free(mc, sizeof (metaslab_class_t));
 }
 
@@ -401,33 +394,25 @@ metaslab_class_expandable_space(metaslab_class_t *mc)
 static int
 metaslab_compare(const void *x1, const void *x2)
 {
-       const metaslab_t *m1 = x1;
-       const metaslab_t *m2 = x2;
-
-       if (m1->ms_weight < m2->ms_weight)
-               return (1);
-       if (m1->ms_weight > m2->ms_weight)
-               return (-1);
+       const metaslab_t *m1 = (const metaslab_t *)x1;
+       const metaslab_t *m2 = (const metaslab_t *)x2;
 
-       /*
-        * If the weights are identical, use the offset to force uniqueness.
-        */
-       if (m1->ms_start < m2->ms_start)
-               return (-1);
-       if (m1->ms_start > m2->ms_start)
-               return (1);
+       int cmp = AVL_CMP(m2->ms_weight, m1->ms_weight);
+       if (likely(cmp))
+               return (cmp);
 
-       ASSERT3P(m1, ==, m2);
+       IMPLY(AVL_CMP(m1->ms_start, m2->ms_start) == 0, m1 == m2);
 
-       return (0);
+       return (AVL_CMP(m1->ms_start, m2->ms_start));
 }
 
 /*
  * Update the allocatable flag and the metaslab group's capacity.
  * The allocatable flag is set to true if the capacity is below
- * the zfs_mg_noalloc_threshold. If a metaslab group transitions
- * from allocatable to non-allocatable or vice versa then the metaslab
- * group's class is updated to reflect the transition.
+ * the zfs_mg_noalloc_threshold or has a fragmentation value that is
+ * greater than zfs_mg_fragmentation_threshold. If a metaslab group
+ * transitions from allocatable to non-allocatable or vice versa then the
+ * metaslab group's class is updated to reflect the transition.
  */
 static void
 metaslab_group_alloc_update(metaslab_group_t *mg)
@@ -436,22 +421,45 @@ metaslab_group_alloc_update(metaslab_group_t *mg)
        metaslab_class_t *mc = mg->mg_class;
        vdev_stat_t *vs = &vd->vdev_stat;
        boolean_t was_allocatable;
+       boolean_t was_initialized;
 
        ASSERT(vd == vd->vdev_top);
 
        mutex_enter(&mg->mg_lock);
        was_allocatable = mg->mg_allocatable;
+       was_initialized = mg->mg_initialized;
 
        mg->mg_free_capacity = ((vs->vs_space - vs->vs_alloc) * 100) /
            (vs->vs_space + 1);
 
+       mutex_enter(&mc->mc_lock);
+
+       /*
+        * If the metaslab group was just added then it won't
+        * have any space until we finish syncing out this txg.
+        * At that point we will consider it initialized and available
+        * for allocations.  We also don't consider non-activated
+        * metaslab groups (e.g. vdevs that are in the middle of being removed)
+        * to be initialized, because they can't be used for allocation.
+        */
+       mg->mg_initialized = metaslab_group_initialized(mg);
+       if (!was_initialized && mg->mg_initialized) {
+               mc->mc_groups++;
+       } else if (was_initialized && !mg->mg_initialized) {
+               ASSERT3U(mc->mc_groups, >, 0);
+               mc->mc_groups--;
+       }
+       if (mg->mg_initialized)
+               mg->mg_no_free_space = B_FALSE;
+
        /*
         * A metaslab group is considered allocatable if it has plenty
         * of free space or is not heavily fragmented. We only take
         * fragmentation into account if the metaslab group has a valid
         * fragmentation metric (i.e. a value between 0 and 100).
         */
-       mg->mg_allocatable = (mg->mg_free_capacity > zfs_mg_noalloc_threshold &&
+       mg->mg_allocatable = (mg->mg_activation_count > 0 &&
+           mg->mg_free_capacity > zfs_mg_noalloc_threshold &&
            (mg->mg_fragmentation == ZFS_FRAG_INVALID ||
            mg->mg_fragmentation <= zfs_mg_fragmentation_threshold));
 
@@ -474,6 +482,7 @@ metaslab_group_alloc_update(metaslab_group_t *mg)
                mc->mc_alloc_groups--;
        else if (!was_allocatable && mg->mg_allocatable)
                mc->mc_alloc_groups++;
+       mutex_exit(&mc->mc_lock);
 
        mutex_exit(&mg->mg_lock);
 }
@@ -490,6 +499,9 @@ metaslab_group_create(metaslab_class_t *mc, vdev_t *vd)
        mg->mg_vd = vd;
        mg->mg_class = mc;
        mg->mg_activation_count = 0;
+       mg->mg_initialized = B_FALSE;
+       mg->mg_no_free_space = B_TRUE;
+       refcount_create_tracked(&mg->mg_alloc_queue_depth);
 
        mg->mg_taskq = taskq_create("metaslab_group_taskq", metaslab_load_pct,
            maxclsyspri, 10, INT_MAX, TASKQ_THREADS_CPU_PCT | TASKQ_DYNAMIC);
@@ -512,6 +524,7 @@ metaslab_group_destroy(metaslab_group_t *mg)
        taskq_destroy(mg->mg_taskq);
        avl_destroy(&mg->mg_metaslab_tree);
        mutex_destroy(&mg->mg_lock);
+       refcount_destroy(&mg->mg_alloc_queue_depth);
        kmem_free(mg, sizeof (metaslab_group_t));
 }
 
@@ -581,6 +594,15 @@ metaslab_group_passivate(metaslab_group_t *mg)
        mg->mg_next = NULL;
 }
 
+boolean_t
+metaslab_group_initialized(metaslab_group_t *mg)
+{
+       vdev_t *vd = mg->mg_vd;
+       vdev_stat_t *vs = &vd->vdev_stat;
+
+       return (vs->vs_space != 0 && mg->mg_activation_count > 0);
+}
+
 uint64_t
 metaslab_group_get_space(metaslab_group_t *mg)
 {
@@ -753,30 +775,97 @@ metaslab_group_fragmentation(metaslab_group_t *mg)
  * group should avoid allocations if its free capacity is less than the
  * zfs_mg_noalloc_threshold or its fragmentation metric is greater than
  * zfs_mg_fragmentation_threshold and there is at least one metaslab group
- * that can still handle allocations.
+ * that can still handle allocations. If the allocation throttle is enabled
+ * then we skip allocations to devices that have reached their maximum
+ * allocation queue depth unless the selected metaslab group is the only
+ * eligible group remaining.
  */
 static boolean_t
-metaslab_group_allocatable(metaslab_group_t *mg)
+metaslab_group_allocatable(metaslab_group_t *mg, metaslab_group_t *rotor,
+    uint64_t psize)
 {
-       vdev_t *vd = mg->mg_vd;
-       spa_t *spa = vd->vdev_spa;
+       spa_t *spa = mg->mg_vd->vdev_spa;
        metaslab_class_t *mc = mg->mg_class;
 
        /*
-        * We use two key metrics to determine if a metaslab group is
-        * considered allocatable -- free space and fragmentation. If
-        * the free space is greater than the free space threshold and
-        * the fragmentation is less than the fragmentation threshold then
-        * consider the group allocatable. There are two case when we will
-        * not consider these key metrics. The first is if the group is
-        * associated with a slog device and the second is if all groups
-        * in this metaslab class have already been consider ineligible
+        * We can only consider skipping this metaslab group if it's
+        * in the normal metaslab class and there are other metaslab
+        * groups to select from. Otherwise, we always consider it eligible
         * for allocations.
         */
-       return ((mg->mg_free_capacity > zfs_mg_noalloc_threshold &&
-           (mg->mg_fragmentation == ZFS_FRAG_INVALID ||
-           mg->mg_fragmentation <= zfs_mg_fragmentation_threshold)) ||
-           mc != spa_normal_class(spa) || mc->mc_alloc_groups == 0);
+       if (mc != spa_normal_class(spa) || mc->mc_groups <= 1)
+               return (B_TRUE);
+
+       /*
+        * If the metaslab group's mg_allocatable flag is set (see comments
+        * in metaslab_group_alloc_update() for more information) and
+        * the allocation throttle is disabled then allow allocations to this
+        * device. However, if the allocation throttle is enabled then
+        * check if we have reached our allocation limit (mg_alloc_queue_depth)
+        * to determine if we should allow allocations to this metaslab group.
+        * If all metaslab groups are no longer considered allocatable
+        * (mc_alloc_groups == 0) or we're trying to allocate the smallest
+        * gang block size then we allow allocations on this metaslab group
+        * regardless of the mg_allocatable or throttle settings.
+        */
+       if (mg->mg_allocatable) {
+               metaslab_group_t *mgp;
+               int64_t qdepth;
+               uint64_t qmax = mg->mg_max_alloc_queue_depth;
+
+               if (!mc->mc_alloc_throttle_enabled)
+                       return (B_TRUE);
+
+               /*
+                * If this metaslab group does not have any free space, then
+                * there is no point in looking further.
+                */
+               if (mg->mg_no_free_space)
+                       return (B_FALSE);
+
+               qdepth = refcount_count(&mg->mg_alloc_queue_depth);
+
+               /*
+                * If this metaslab group is below its qmax or it's
+                * the only allocatable metasable group, then attempt
+                * to allocate from it.
+                */
+               if (qdepth < qmax || mc->mc_alloc_groups == 1)
+                       return (B_TRUE);
+               ASSERT3U(mc->mc_alloc_groups, >, 1);
+
+               /*
+                * Since this metaslab group is at or over its qmax, we
+                * need to determine if there are metaslab groups after this
+                * one that might be able to handle this allocation. This is
+                * racy since we can't hold the locks for all metaslab
+                * groups at the same time when we make this check.
+                */
+               for (mgp = mg->mg_next; mgp != rotor; mgp = mgp->mg_next) {
+                       qmax = mgp->mg_max_alloc_queue_depth;
+
+                       qdepth = refcount_count(&mgp->mg_alloc_queue_depth);
+
+                       /*
+                        * If there is another metaslab group that
+                        * might be able to handle the allocation, then
+                        * we return false so that we skip this group.
+                        */
+                       if (qdepth < qmax && !mgp->mg_no_free_space)
+                               return (B_FALSE);
+               }
+
+               /*
+                * We didn't find another group to handle the allocation
+                * so we can't skip this metaslab group even though
+                * we are at or over our qmax.
+                */
+               return (B_TRUE);
+
+       } else if (mc->mc_alloc_groups == 0 || psize == SPA_MINBLOCKSIZE) {
+               return (B_TRUE);
+       }
+       return (B_FALSE);
 }
 
 /*
@@ -797,18 +886,11 @@ metaslab_rangesize_compare(const void *x1, const void *x2)
        uint64_t rs_size1 = r1->rs_end - r1->rs_start;
        uint64_t rs_size2 = r2->rs_end - r2->rs_start;
 
-       if (rs_size1 < rs_size2)
-               return (-1);
-       if (rs_size1 > rs_size2)
-               return (1);
-
-       if (r1->rs_start < r2->rs_start)
-               return (-1);
+       int cmp = AVL_CMP(rs_size1, rs_size2);
+       if (likely(cmp))
+               return (cmp);
 
-       if (r1->rs_start > r2->rs_start)
-               return (1);
-
-       return (0);
+       return (AVL_CMP(r1->rs_start, r2->rs_start));
 }
 
 /*
@@ -1742,10 +1824,11 @@ metaslab_condense(metaslab_t *msp, uint64_t txg, dmu_tx_t *tx)
        ASSERT(msp->ms_loaded);
 
 
-       spa_dbgmsg(spa, "condensing: txg %llu, msp[%llu] %p, "
-           "smp size %llu, segments %lu, forcing condense=%s", txg,
-           msp->ms_id, msp, space_map_length(msp->ms_sm),
-           avl_numnodes(&msp->ms_tree->rt_root),
+       spa_dbgmsg(spa, "condensing: txg %llu, msp[%llu] %p, vdev id %llu, "
+           "spa %s, smp size %llu, segments %lu, forcing condense=%s", txg,
+           msp->ms_id, msp, msp->ms_group->mg_vd->vdev_id,
+           msp->ms_group->mg_vd->vdev_spa->spa_name,
+           space_map_length(msp->ms_sm), avl_numnodes(&msp->ms_tree->rt_root),
            msp->ms_condense_wanted ? "TRUE" : "FALSE");
 
        msp->ms_condense_wanted = B_FALSE;
@@ -2071,8 +2154,62 @@ metaslab_distance(metaslab_t *msp, dva_t *dva)
        return (0);
 }
 
+/*
+ * ==========================================================================
+ * Metaslab block operations
+ * ==========================================================================
+ */
+
+static void
+metaslab_group_alloc_increment(spa_t *spa, uint64_t vdev, void *tag, int flags)
+{
+       metaslab_group_t *mg;
+
+       if (!(flags & METASLAB_ASYNC_ALLOC) ||
+           flags & METASLAB_DONT_THROTTLE)
+               return;
+
+       mg = vdev_lookup_top(spa, vdev)->vdev_mg;
+       if (!mg->mg_class->mc_alloc_throttle_enabled)
+               return;
+
+       (void) refcount_add(&mg->mg_alloc_queue_depth, tag);
+}
+
+void
+metaslab_group_alloc_decrement(spa_t *spa, uint64_t vdev, void *tag, int flags)
+{
+       metaslab_group_t *mg;
+
+       if (!(flags & METASLAB_ASYNC_ALLOC) ||
+           flags & METASLAB_DONT_THROTTLE)
+               return;
+
+       mg = vdev_lookup_top(spa, vdev)->vdev_mg;
+       if (!mg->mg_class->mc_alloc_throttle_enabled)
+               return;
+
+       (void) refcount_remove(&mg->mg_alloc_queue_depth, tag);
+}
+
+void
+metaslab_group_alloc_verify(spa_t *spa, const blkptr_t *bp, void *tag)
+{
+#ifdef ZFS_DEBUG
+       const dva_t *dva = bp->blk_dva;
+       int ndvas = BP_GET_NDVAS(bp);
+       int d;
+
+       for (d = 0; d < ndvas; d++) {
+               uint64_t vdev = DVA_GET_VDEV(&dva[d]);
+               metaslab_group_t *mg = vdev_lookup_top(spa, vdev)->vdev_mg;
+               VERIFY(refcount_not_held(&mg->mg_alloc_queue_depth, tag));
+       }
+#endif
+}
+
 static uint64_t
-metaslab_group_alloc(metaslab_group_t *mg, uint64_t psize, uint64_t asize,
+metaslab_group_alloc(metaslab_group_t *mg, uint64_t asize,
     uint64_t txg, uint64_t min_distance, dva_t *dva, int d)
 {
        spa_t *spa = mg->mg_vd->vdev_spa;
@@ -2099,10 +2236,10 @@ metaslab_group_alloc(metaslab_group_t *mg, uint64_t psize, uint64_t asize,
                        if (msp->ms_weight < asize) {
                                spa_dbgmsg(spa, "%s: failed to meet weight "
                                    "requirement: vdev %llu, txg %llu, mg %p, "
-                                   "msp %p, psize %llu, asize %llu, "
+                                   "msp %p, asize %llu, "
                                    "weight %llu", spa_name(spa),
                                    mg->mg_vd->vdev_id, txg,
-                                   mg, msp, psize, asize, msp->ms_weight);
+                                   mg, msp, asize, msp->ms_weight);
                                mutex_exit(&mg->mg_lock);
                                return (-1ULL);
                        }
@@ -2184,7 +2321,6 @@ metaslab_group_alloc(metaslab_group_t *mg, uint64_t psize, uint64_t asize,
        msp->ms_access_txg = txg + metaslab_unload_delay;
 
        mutex_exit(&msp->ms_lock);
-
        return (offset);
 }
 
@@ -2201,7 +2337,6 @@ metaslab_alloc_dva(spa_t *spa, metaslab_class_t *mc, uint64_t psize,
        int all_zero;
        int zio_lock = B_FALSE;
        boolean_t allocatable;
-       uint64_t offset = -1ULL;
        uint64_t asize;
        uint64_t distance;
 
@@ -2213,9 +2348,6 @@ metaslab_alloc_dva(spa_t *spa, metaslab_class_t *mc, uint64_t psize,
        if (psize >= metaslab_gang_bang && (ddi_get_lbolt() & 3) == 0)
                return (SET_ERROR(ENOSPC));
 
-       if (flags & METASLAB_FASTWRITE)
-               mutex_enter(&mc->mc_fastwrite_lock);
-
        /*
         * Start at the rotor and loop through all mgs until we find something.
         * Note that there's no locking on mc_rotor or mc_aliquot because
@@ -2282,8 +2414,9 @@ metaslab_alloc_dva(spa_t *spa, metaslab_class_t *mc, uint64_t psize,
 top:
        all_zero = B_TRUE;
        do {
-               ASSERT(mg->mg_activation_count == 1);
+               uint64_t offset;
 
+               ASSERT(mg->mg_activation_count == 1);
                vd = mg->mg_vd;
 
                /*
@@ -2299,24 +2432,23 @@ top:
 
                /*
                 * Determine if the selected metaslab group is eligible
-                * for allocations. If we're ganging or have requested
-                * an allocation for the smallest gang block size
-                * then we don't want to avoid allocating to the this
-                * metaslab group. If we're in this condition we should
-                * try to allocate from any device possible so that we
-                * don't inadvertently return ENOSPC and suspend the pool
+                * for allocations. If we're ganging then don't allow
+                * this metaslab group to skip allocations since that would
+                * inadvertently return ENOSPC and suspend the pool
                 * even though space is still available.
                 */
-               if (allocatable && CAN_FASTGANG(flags) &&
-                   psize > SPA_GANGBLOCKSIZE)
-                       allocatable = metaslab_group_allocatable(mg);
+               if (allocatable && !GANG_ALLOCATION(flags) && !zio_lock) {
+                       allocatable = metaslab_group_allocatable(mg, rotor,
+                           psize);
+               }
 
                if (!allocatable)
                        goto next;
 
+               ASSERT(mg->mg_initialized);
+
                /*
-                * Avoid writing single-copy data to a failing vdev
-                * unless the user instructs us that it is okay.
+                * Avoid writing single-copy data to a failing vdev.
                 */
                if ((vd->vdev_stat.vs_write_errors > 0 ||
                    vd->vdev_state < VDEV_STATE_HEALTHY) &&
@@ -2336,8 +2468,31 @@ top:
                asize = vdev_psize_to_asize(vd, psize);
                ASSERT(P2PHASE(asize, 1ULL << vd->vdev_ashift) == 0);
 
-               offset = metaslab_group_alloc(mg, psize, asize, txg, distance,
-                   dva, d);
+               offset = metaslab_group_alloc(mg, asize, txg, distance, dva, d);
+
+               mutex_enter(&mg->mg_lock);
+               if (offset == -1ULL) {
+                       mg->mg_failed_allocations++;
+                       if (asize == SPA_GANGBLOCKSIZE) {
+                               /*
+                                * This metaslab group was unable to allocate
+                                * the minimum gang block size so it must be
+                                * out of space. We must notify the allocation
+                                * throttle to start skipping allocation
+                                * attempts to this metaslab group until more
+                                * space becomes available.
+                                *
+                                * Note: this failure cannot be caused by the
+                                * allocation throttle since the allocation
+                                * throttle is only responsible for skipping
+                                * devices and not failing block allocations.
+                                */
+                               mg->mg_no_free_space = B_TRUE;
+                       }
+               }
+               mg->mg_allocations++;
+               mutex_exit(&mg->mg_lock);
+
                if (offset != -1ULL) {
                        /*
                         * If we've just selected this metaslab group,
@@ -2394,13 +2549,13 @@ top:
 
                        DVA_SET_VDEV(&dva[d], vd->vdev_id);
                        DVA_SET_OFFSET(&dva[d], offset);
-                       DVA_SET_GANG(&dva[d], !!(flags & METASLAB_GANG_HEADER));
+                       DVA_SET_GANG(&dva[d],
+                           ((flags & METASLAB_GANG_HEADER) ? 1 : 0));
                        DVA_SET_ASIZE(&dva[d], asize);
 
                        if (flags & METASLAB_FASTWRITE) {
                                atomic_add_64(&vd->vdev_pending_fastwrite,
                                    psize);
-                               mutex_exit(&mc->mc_fastwrite_lock);
                        }
 
                        return (0);
@@ -2424,9 +2579,6 @@ next:
 
        bzero(&dva[d], sizeof (dva_t));
 
-       if (flags & METASLAB_FASTWRITE)
-               mutex_exit(&mc->mc_fastwrite_lock);
-
        return (SET_ERROR(ENOSPC));
 }
 
@@ -2540,9 +2692,62 @@ metaslab_claim_dva(spa_t *spa, const dva_t *dva, uint64_t txg)
        return (0);
 }
 
+/*
+ * Reserve some allocation slots. The reservation system must be called
+ * before we call into the allocator. If there aren't any available slots
+ * then the I/O will be throttled until an I/O completes and its slots are
+ * freed up. The function returns true if it was successful in placing
+ * the reservation.
+ */
+boolean_t
+metaslab_class_throttle_reserve(metaslab_class_t *mc, int slots, zio_t *zio,
+    int flags)
+{
+       uint64_t available_slots = 0;
+       uint64_t reserved_slots;
+       boolean_t slot_reserved = B_FALSE;
+
+       ASSERT(mc->mc_alloc_throttle_enabled);
+       mutex_enter(&mc->mc_lock);
+
+       reserved_slots = refcount_count(&mc->mc_alloc_slots);
+       if (reserved_slots < mc->mc_alloc_max_slots)
+               available_slots = mc->mc_alloc_max_slots - reserved_slots;
+
+       if (slots <= available_slots || GANG_ALLOCATION(flags)) {
+               int d;
+
+               /*
+                * We reserve the slots individually so that we can unreserve
+                * them individually when an I/O completes.
+                */
+               for (d = 0; d < slots; d++) {
+                       reserved_slots = refcount_add(&mc->mc_alloc_slots, zio);
+               }
+               zio->io_flags |= ZIO_FLAG_IO_ALLOCATING;
+               slot_reserved = B_TRUE;
+       }
+
+       mutex_exit(&mc->mc_lock);
+       return (slot_reserved);
+}
+
+void
+metaslab_class_throttle_unreserve(metaslab_class_t *mc, int slots, zio_t *zio)
+{
+       int d;
+
+       ASSERT(mc->mc_alloc_throttle_enabled);
+       mutex_enter(&mc->mc_lock);
+       for (d = 0; d < slots; d++) {
+               (void) refcount_remove(&mc->mc_alloc_slots, zio);
+       }
+       mutex_exit(&mc->mc_lock);
+}
+
 int
 metaslab_alloc(spa_t *spa, metaslab_class_t *mc, uint64_t psize, blkptr_t *bp,
-    int ndvas, uint64_t txg, blkptr_t *hintbp, int flags)
+    int ndvas, uint64_t txg, blkptr_t *hintbp, int flags, zio_t *zio)
 {
        dva_t *dva = bp->blk_dva;
        dva_t *hintdva = hintbp->blk_dva;
@@ -2568,18 +2773,28 @@ metaslab_alloc(spa_t *spa, metaslab_class_t *mc, uint64_t psize, blkptr_t *bp,
                if (error != 0) {
                        for (d--; d >= 0; d--) {
                                metaslab_free_dva(spa, &dva[d], txg, B_TRUE);
+                               metaslab_group_alloc_decrement(spa,
+                                   DVA_GET_VDEV(&dva[d]), zio, flags);
                                bzero(&dva[d], sizeof (dva_t));
                        }
                        spa_config_exit(spa, SCL_ALLOC, FTAG);
                        return (error);
+               } else {
+                       /*
+                        * Update the metaslab group's queue depth
+                        * based on the newly allocated dva.
+                        */
+                       metaslab_group_alloc_increment(spa,
+                           DVA_GET_VDEV(&dva[d]), zio, flags);
                }
+
        }
        ASSERT(error == 0);
        ASSERT(BP_GET_NDVAS(bp) == ndvas);
 
        spa_config_exit(spa, SCL_ALLOC, FTAG);
 
-       BP_SET_BIRTH(bp, txg, txg);
+       BP_SET_BIRTH(bp, txg, 0);
 
        return (0);
 }
index e4446ded22089bf743dab72770d0db292f378e10..e02a4bae33830cb591632df7dbf4c652ce2c9475 100644 (file)
@@ -85,7 +85,7 @@ multilist_create(multilist_t *ml, size_t size, size_t offset, unsigned int num,
 
        for (i = 0; i < ml->ml_num_sublists; i++) {
                multilist_sublist_t *mls = &ml->ml_sublists[i];
-               mutex_init(&mls->mls_lock, NULL, MUTEX_DEFAULT, NULL);
+               mutex_init(&mls->mls_lock, NULL, MUTEX_NOLOCKDEP, NULL);
                list_create(&mls->mls_list, size, offset);
        }
 }
diff --git a/zfs/module/zfs/pathname.c b/zfs/module/zfs/pathname.c
new file mode 100644 (file)
index 0000000..4ec1320
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
+/*       All Rights Reserved   */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/pathname.h>
+#include <sys/kmem.h>
+
+/*
+ * Pathname utilities.
+ *
+ * In translating file names we copy each argument file
+ * name into a pathname structure where we operate on it.
+ * Each pathname structure can hold "pn_bufsize" characters
+ * including a terminating null, and operations here support
+ * allocating and freeing pathname structures, fetching
+ * strings from user space, getting the next character from
+ * a pathname, combining two pathnames (used in symbolic
+ * link processing), and peeling off the first component
+ * of a pathname.
+ */
+
+/*
+ * Allocate contents of pathname structure.  Structure is typically
+ * an automatic variable in calling routine for convenience.
+ *
+ * May sleep in the call to kmem_alloc() and so must not be called
+ * from interrupt level.
+ */
+void
+pn_alloc(struct pathname *pnp)
+{
+       pn_alloc_sz(pnp, MAXPATHLEN);
+}
+void
+pn_alloc_sz(struct pathname *pnp, size_t sz)
+{
+       pnp->pn_path = pnp->pn_buf = kmem_alloc(sz, KM_SLEEP);
+       pnp->pn_pathlen = 0;
+       pnp->pn_bufsize = sz;
+}
+
+/*
+ * Free pathname resources.
+ */
+void
+pn_free(struct pathname *pnp)
+{
+       /* pn_bufsize is usually MAXPATHLEN, but may not be */
+       kmem_free(pnp->pn_buf, pnp->pn_bufsize);
+       pnp->pn_path = pnp->pn_buf = NULL;
+       pnp->pn_pathlen = pnp->pn_bufsize = 0;
+}
diff --git a/zfs/module/zfs/policy.c b/zfs/module/zfs/policy.c
new file mode 100644 (file)
index 0000000..fda13a9
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * 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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Joyent, Inc. All rights reserved.
+ * Copyright (C) 2016 Lawrence Livermore National Security, LLC.
+ *
+ * For Linux the vast majority of this enforcement is already handled via
+ * the standard Linux VFS permission checks.  However certain administrative
+ * commands which bypass the standard mechanisms may need to make use of
+ * this functionality.
+ */
+
+#include <sys/policy.h>
+#include <linux/security.h>
+#include <linux/vfs_compat.h>
+
+/*
+ * The passed credentials cannot be directly verified because Linux only
+ * provides and interface to check the *current* proces credentials.  In
+ * order to handle this the capable() test is only run when the passed
+ * credentials match the current process credentials or the kcred.  In
+ * all other cases this function must fail and return the passed err.
+ */
+static int
+priv_policy(const cred_t *cr, int capability, boolean_t all, int err)
+{
+       ASSERT3S(all, ==, B_FALSE);
+
+       if (cr != CRED() && (cr != kcred))
+               return (err);
+
+       if (!capable(capability))
+               return (err);
+
+       return (0);
+}
+
+/*
+ * Checks for operations that are either client-only or are used by
+ * both clients and servers.
+ */
+int
+secpolicy_nfs(const cred_t *cr)
+{
+       return (priv_policy(cr, CAP_SYS_ADMIN, B_FALSE, EPERM));
+}
+
+/*
+ * Catch all system configuration.
+ */
+int
+secpolicy_sys_config(const cred_t *cr, boolean_t checkonly)
+{
+       return (priv_policy(cr, CAP_SYS_ADMIN, B_FALSE, EPERM));
+}
+
+/*
+ * Like secpolicy_vnode_access() but we get the actual wanted mode and the
+ * current mode of the file, not the missing bits.
+ *
+ * Enforced in the Linux VFS.
+ */
+int
+secpolicy_vnode_access2(const cred_t *cr, struct inode *ip, uid_t owner,
+       mode_t curmode, mode_t wantmode)
+{
+       return (0);
+}
+
+/*
+ * This is a special routine for ZFS; it is used to determine whether
+ * any of the privileges in effect allow any form of access to the
+ * file.  There's no reason to audit this or any reason to record
+ * this.  More work is needed to do the "KPLD" stuff.
+ */
+int
+secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner)
+{
+       if (crgetfsuid(cr) == owner)
+               return (0);
+
+       if (zpl_inode_owner_or_capable(ip))
+               return (0);
+
+       if (priv_policy(cr, CAP_DAC_OVERRIDE, B_FALSE, EPERM) == 0)
+               return (0);
+
+       if (priv_policy(cr, CAP_DAC_READ_SEARCH, B_FALSE, EPERM) == 0)
+               return (0);
+
+       return (EPERM);
+}
+
+/*
+ * Determine if subject can chown owner of a file.
+ */
+int
+secpolicy_vnode_chown(const cred_t *cr, uid_t owner)
+{
+       if (crgetfsuid(cr) == owner)
+               return (0);
+
+       return (priv_policy(cr, CAP_FOWNER, B_FALSE, EPERM));
+}
+
+/*
+ * Determine if subject can change group ownership of a file.
+ */
+int
+secpolicy_vnode_create_gid(const cred_t *cr)
+{
+       return (priv_policy(cr, CAP_SETGID, B_FALSE, EPERM));
+}
+
+/*
+ * Policy determines whether we can remove an entry from a directory,
+ * regardless of permission bits.
+ */
+int
+secpolicy_vnode_remove(const cred_t *cr)
+{
+       return (priv_policy(cr, CAP_FOWNER, B_FALSE, EPERM));
+}
+
+/*
+ * Determine that subject can modify the mode of a file.  allzone privilege
+ * needed when modifying root owned object.
+ */
+int
+secpolicy_vnode_setdac(const cred_t *cr, uid_t owner)
+{
+       if (crgetfsuid(cr) == owner)
+               return (0);
+
+       return (priv_policy(cr, CAP_FOWNER, B_FALSE, EPERM));
+}
+
+/*
+ * Are we allowed to retain the set-uid/set-gid bits when
+ * changing ownership or when writing to a file?
+ * "issuid" should be true when set-uid; only in that case
+ * root ownership is checked (setgid is assumed).
+ *
+ * Enforced in the Linux VFS.
+ */
+int
+secpolicy_vnode_setid_retain(const cred_t *cr, boolean_t issuidroot)
+{
+       return (0);
+}
+
+/*
+ * Determine that subject can set the file setgid flag.
+ */
+int
+secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid)
+{
+       if (crgetfsgid(cr) != gid && !groupmember(gid, cr))
+               return (priv_policy(cr, CAP_FSETID, B_FALSE, EPERM));
+
+       return (0);
+}
+
+/*
+ * Determine if the subject can inject faults in the ZFS fault injection
+ * framework.  Requires all privileges.
+ */
+int
+secpolicy_zinject(const cred_t *cr)
+{
+       return (priv_policy(cr, CAP_SYS_ADMIN, B_FALSE, EACCES));
+}
+
+/*
+ * Determine if the subject has permission to manipulate ZFS datasets
+ * (not pools).  Equivalent to the SYS_MOUNT privilege.
+ */
+int
+secpolicy_zfs(const cred_t *cr)
+{
+       return (priv_policy(cr, CAP_SYS_ADMIN, B_FALSE, EACCES));
+}
+
+void
+secpolicy_setid_clear(vattr_t *vap, cred_t *cr)
+{
+       if ((vap->va_mode & (S_ISUID | S_ISGID)) != 0 &&
+           secpolicy_vnode_setid_retain(cr,
+           (vap->va_mode & S_ISUID) != 0 &&
+           (vap->va_mask & AT_UID) != 0 && vap->va_uid == 0) != 0) {
+               vap->va_mask |= AT_MODE;
+               vap->va_mode &= ~(S_ISUID|S_ISGID);
+       }
+}
+
+/*
+ * Determine that subject can set the file setid flags.
+ */
+static int
+secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner)
+{
+       if (crgetfsuid(cr) == owner)
+               return (0);
+
+       return (priv_policy(cr, CAP_FSETID, B_FALSE, EPERM));
+}
+
+/*
+ * Determine that subject can make a file a "sticky".
+ *
+ * Enforced in the Linux VFS.
+ */
+static int
+secpolicy_vnode_stky_modify(const cred_t *cr)
+{
+       return (0);
+}
+
+int
+secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap,
+    const vattr_t *ovap, cred_t *cr)
+{
+       int error;
+
+       if ((vap->va_mode & S_ISUID) != 0 &&
+           (error = secpolicy_vnode_setid_modify(cr,
+           ovap->va_uid)) != 0) {
+               return (error);
+       }
+
+       /*
+        * Check privilege if attempting to set the
+        * sticky bit on a non-directory.
+        */
+       if (!S_ISDIR(ip->i_mode) && (vap->va_mode & S_ISVTX) != 0 &&
+           secpolicy_vnode_stky_modify(cr) != 0) {
+               vap->va_mode &= ~S_ISVTX;
+       }
+
+       /*
+        * Check for privilege if attempting to set the
+        * group-id bit.
+        */
+       if ((vap->va_mode & S_ISGID) != 0 &&
+           secpolicy_vnode_setids_setgids(cr, ovap->va_gid) != 0) {
+               vap->va_mode &= ~S_ISGID;
+       }
+
+       return (0);
+}
+
+/*
+ * Check privileges for setting xvattr attributes
+ */
+int
+secpolicy_xvattr(xvattr_t *xvap, uid_t owner, cred_t *cr, vtype_t vtype)
+{
+       return (secpolicy_vnode_chown(cr, owner));
+}
+
+/*
+ * Check privileges for setattr attributes.
+ *
+ * Enforced in the Linux VFS.
+ */
+int
+secpolicy_vnode_setattr(cred_t *cr, struct inode *ip, struct vattr *vap,
+    const struct vattr *ovap, int flags,
+    int unlocked_access(void *, int, cred_t *), void *node)
+{
+       return (0);
+}
+
+/*
+ * Check privileges for links.
+ *
+ * Enforced in the Linux VFS.
+ */
+int
+secpolicy_basic_link(const cred_t *cr)
+{
+       return (0);
+}
index 6422fd1c1fa6ecf2a9283fefeabca772f6b0a76a..ebef7f447862d9f966c49d752f3ff923548887fc 100644 (file)
@@ -111,20 +111,13 @@ range_tree_stat_decr(range_tree_t *rt, range_seg_t *rs)
 static int
 range_tree_seg_compare(const void *x1, const void *x2)
 {
-       const range_seg_t *r1 = x1;
-       const range_seg_t *r2 = x2;
+       const range_seg_t *r1 = (const range_seg_t *)x1;
+       const range_seg_t *r2 = (const range_seg_t *)x2;
 
-       if (r1->rs_start < r2->rs_start) {
-               if (r1->rs_end > r2->rs_start)
-                       return (0);
-               return (-1);
-       }
-       if (r1->rs_start > r2->rs_start) {
-               if (r1->rs_start < r2->rs_end)
-                       return (0);
-               return (1);
-       }
-       return (0);
+       ASSERT3U(r1->rs_start, <=, r1->rs_end);
+       ASSERT3U(r2->rs_start, <=, r2->rs_end);
+
+       return ((r1->rs_start >= r2->rs_end) - (r1->rs_end <= r2->rs_start));
 }
 
 range_tree_t *
index 4c460a2009673bfc24794d2fe908f75775c7dac7..6f8f4db0891f06bad9c2703a19cf32629b52f01d 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -68,6 +68,13 @@ refcount_create(refcount_t *rc)
        rc->rc_tracked = reference_tracking_enable;
 }
 
+void
+refcount_create_tracked(refcount_t *rc)
+{
+       refcount_create(rc);
+       rc->rc_tracked = B_TRUE;
+}
+
 void
 refcount_create_untracked(refcount_t *rc)
 {
@@ -227,4 +234,84 @@ refcount_transfer(refcount_t *dst, refcount_t *src)
        list_destroy(&removed);
 }
 
+void
+refcount_transfer_ownership(refcount_t *rc, void *current_holder,
+    void *new_holder)
+{
+       reference_t *ref;
+       boolean_t found = B_FALSE;
+
+       mutex_enter(&rc->rc_mtx);
+       if (!rc->rc_tracked) {
+               mutex_exit(&rc->rc_mtx);
+               return;
+       }
+
+       for (ref = list_head(&rc->rc_list); ref;
+           ref = list_next(&rc->rc_list, ref)) {
+               if (ref->ref_holder == current_holder) {
+                       ref->ref_holder = new_holder;
+                       found = B_TRUE;
+                       break;
+               }
+       }
+       ASSERT(found);
+       mutex_exit(&rc->rc_mtx);
+}
+
+/*
+ * If tracking is enabled, return true if a reference exists that matches
+ * the "holder" tag. If tracking is disabled, then return true if a reference
+ * might be held.
+ */
+boolean_t
+refcount_held(refcount_t *rc, void *holder)
+{
+       reference_t *ref;
+
+       mutex_enter(&rc->rc_mtx);
+
+       if (!rc->rc_tracked) {
+               mutex_exit(&rc->rc_mtx);
+               return (rc->rc_count > 0);
+       }
+
+       for (ref = list_head(&rc->rc_list); ref;
+           ref = list_next(&rc->rc_list, ref)) {
+               if (ref->ref_holder == holder) {
+                       mutex_exit(&rc->rc_mtx);
+                       return (B_TRUE);
+               }
+       }
+       mutex_exit(&rc->rc_mtx);
+       return (B_FALSE);
+}
+
+/*
+ * If tracking is enabled, return true if a reference does not exist that
+ * matches the "holder" tag. If tracking is disabled, always return true
+ * since the reference might not be held.
+ */
+boolean_t
+refcount_not_held(refcount_t *rc, void *holder)
+{
+       reference_t *ref;
+
+       mutex_enter(&rc->rc_mtx);
+
+       if (!rc->rc_tracked) {
+               mutex_exit(&rc->rc_mtx);
+               return (B_TRUE);
+       }
+
+       for (ref = list_head(&rc->rc_list); ref;
+           ref = list_next(&rc->rc_list, ref)) {
+               if (ref->ref_holder == holder) {
+                       mutex_exit(&rc->rc_mtx);
+                       return (B_FALSE);
+               }
+       }
+       mutex_exit(&rc->rc_mtx);
+       return (B_TRUE);
+}
 #endif /* ZFS_DEBUG */
index d6ac5fcc709a05a676cf8227e8a8f35bdd3470d6..1548c56346f7959dcc0021381c77db4b0c6e44cc 100644 (file)
@@ -33,6 +33,7 @@
 #include <sys/dmu.h>
 #include <sys/dmu_impl.h>
 #include <sys/dmu_objset.h>
+#include <sys/dmu_tx.h>
 #include <sys/dbuf.h>
 #include <sys/dnode.h>
 #include <sys/zap.h>
@@ -240,31 +241,23 @@ sa_cache_fini(void)
 static int
 layout_num_compare(const void *arg1, const void *arg2)
 {
-       const sa_lot_t *node1 = arg1;
-       const sa_lot_t *node2 = arg2;
+       const sa_lot_t *node1 = (const sa_lot_t *)arg1;
+       const sa_lot_t *node2 = (const sa_lot_t *)arg2;
 
-       if (node1->lot_num > node2->lot_num)
-               return (1);
-       else if (node1->lot_num < node2->lot_num)
-               return (-1);
-       return (0);
+       return (AVL_CMP(node1->lot_num, node2->lot_num));
 }
 
 static int
 layout_hash_compare(const void *arg1, const void *arg2)
 {
-       const sa_lot_t *node1 = arg1;
-       const sa_lot_t *node2 = arg2;
+       const sa_lot_t *node1 = (const sa_lot_t *)arg1;
+       const sa_lot_t *node2 = (const sa_lot_t *)arg2;
 
-       if (node1->lot_hash > node2->lot_hash)
-               return (1);
-       if (node1->lot_hash < node2->lot_hash)
-               return (-1);
-       if (node1->lot_instance > node2->lot_instance)
-               return (1);
-       if (node1->lot_instance < node2->lot_instance)
-               return (-1);
-       return (0);
+       int cmp = AVL_CMP(node1->lot_hash, node2->lot_hash);
+       if (likely(cmp))
+               return (cmp);
+
+       return (AVL_CMP(node1->lot_instance, node2->lot_instance));
 }
 
 boolean_t
@@ -553,12 +546,11 @@ sa_copy_data(sa_data_locator_t *func, void *datastart, void *target, int buflen)
  */
 static int
 sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
-    dmu_buf_t *db, sa_buf_type_t buftype, int *index, int *total,
-    boolean_t *will_spill)
+    dmu_buf_t *db, sa_buf_type_t buftype, int full_space, int *index,
+    int *total, boolean_t *will_spill)
 {
        int var_size_count = 0;
        int i;
-       int full_space;
        int hdrsize;
        int extra_hdrsize;
 
@@ -577,7 +569,6 @@ sa_find_sizes(sa_os_t *sa, sa_bulk_attr_t *attr_desc, int attr_count,
        hdrsize = (SA_BONUSTYPE_FROM_DB(db) == DMU_OT_ZNODE) ? 0 :
            sizeof (sa_hdr_phys_t);
 
-       full_space = (buftype == SA_BONUS) ? DN_MAX_BONUSLEN : db->db_size;
        ASSERT(IS_P2ALIGNED(full_space, 8));
 
        for (i = 0; i != attr_count; i++) {
@@ -668,6 +659,7 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
        void *data_start;
        sa_attr_type_t *attrs, *attrs_start;
        int i, lot_count;
+       int dnodesize;
        int spill_idx;
        int hdrsize;
        int spillhdrsize = 0;
@@ -676,20 +668,23 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
        sa_lot_t *lot;
        int len_idx;
        int spill_used;
+       int bonuslen;
        boolean_t spilling;
 
        dmu_buf_will_dirty(hdl->sa_bonus, tx);
        bonustype = SA_BONUSTYPE_FROM_DB(hdl->sa_bonus);
+       dmu_object_dnsize_from_db(hdl->sa_bonus, &dnodesize);
+       bonuslen = DN_BONUS_SIZE(dnodesize);
 
        /* first determine bonus header size and sum of all attributes */
        hdrsize = sa_find_sizes(sa, attr_desc, attr_count, hdl->sa_bonus,
-           SA_BONUS, &spill_idx, &used, &spilling);
+           SA_BONUS, bonuslen, &spill_idx, &used, &spilling);
 
        if (used > SPA_OLD_MAXBLOCKSIZE)
                return (SET_ERROR(EFBIG));
 
-       VERIFY(0 == dmu_set_bonus(hdl->sa_bonus, spilling ?
-           MIN(DN_MAX_BONUSLEN - sizeof (blkptr_t), used + hdrsize) :
+       VERIFY0(dmu_set_bonus(hdl->sa_bonus, spilling ?
+           MIN(bonuslen - sizeof (blkptr_t), used + hdrsize) :
            used + hdrsize, tx));
 
        ASSERT((bonustype == DMU_OT_ZNODE && spilling == 0) ||
@@ -706,8 +701,8 @@ sa_build_layouts(sa_handle_t *hdl, sa_bulk_attr_t *attr_desc, int attr_count,
                dmu_buf_will_dirty(hdl->sa_spill, tx);
 
                spillhdrsize = sa_find_sizes(sa, &attr_desc[spill_idx],
-                   attr_count - spill_idx, hdl->sa_spill, SA_SPILL, &i,
-                   &spill_used, &dummy);
+                   attr_count - spill_idx, hdl->sa_spill, SA_SPILL,
+                   hdl->sa_spill->db_size, &i, &spill_used, &dummy);
 
                if (spill_used > SPA_OLD_MAXBLOCKSIZE)
                        return (SET_ERROR(EFBIG));
index cf9dd8fcba1a8eea342823345f78807a6862ad5f..c8a4882f84b201d9f7fe52e6c8720fdfd3af3280 100644 (file)
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
+/*
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
+ */
 #include <sys/zfs_context.h>
 #include <sys/zio.h>
 #include <sys/zio_checksum.h>
+#include <sys/sha2.h>
 
-/*
- * SHA-256 checksum, as specified in FIPS 180-3, available at:
- * http://csrc.nist.gov/publications/PubsFIPS.html
- *
- * This is a very compact implementation of SHA-256.
- * It is designed to be simple and portable, not to be fast.
- */
-
-/*
- * The literal definitions of Ch() and Maj() according to FIPS 180-3 are:
- *
- *     Ch(x, y, z)     (x & y) ^ (~x & z)
- *     Maj(x, y, z)    (x & y) ^ (x & z) ^ (y & z)
- *
- * We use equivalent logical reductions here that require one less op.
- */
-#define        Ch(x, y, z)     ((z) ^ ((x) & ((y) ^ (z))))
-#define        Maj(x, y, z)    (((x) & (y)) ^ ((z) & ((x) ^ (y))))
-#define        Rot32(x, s)     (((x) >> s) | ((x) << (32 - s)))
-#define        SIGMA0(x)       (Rot32(x, 2) ^ Rot32(x, 13) ^ Rot32(x, 22))
-#define        SIGMA1(x)       (Rot32(x, 6) ^ Rot32(x, 11) ^ Rot32(x, 25))
-#define        sigma0(x)       (Rot32(x, 7) ^ Rot32(x, 18) ^ ((x) >> 3))
-#define        sigma1(x)       (Rot32(x, 17) ^ Rot32(x, 19) ^ ((x) >> 10))
-
-static const uint32_t SHA256_K[64] = {
-       0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
-       0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
-       0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
-       0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
-       0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
-       0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
-       0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
-       0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
-       0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
-       0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
-       0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
-       0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
-       0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
-       0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
-       0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
-       0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
-};
-
-static void
-SHA256Transform(uint32_t *H, const uint8_t *cp)
+/*ARGSUSED*/
+void
+zio_checksum_SHA256(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
 {
-       uint32_t a, b, c, d, e, f, g, h, t, T1, T2, W[64];
-
-       for (t = 0; t < 16; t++, cp += 4)
-               W[t] = (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | cp[3];
-
-       for (t = 16; t < 64; t++)
-               W[t] = sigma1(W[t - 2]) + W[t - 7] +
-                   sigma0(W[t - 15]) + W[t - 16];
-
-       a = H[0]; b = H[1]; c = H[2]; d = H[3];
-       e = H[4]; f = H[5]; g = H[6]; h = H[7];
-
-       for (t = 0; t < 64; t++) {
-               T1 = h + SIGMA1(e) + Ch(e, f, g) + SHA256_K[t] + W[t];
-               T2 = SIGMA0(a) + Maj(a, b, c);
-               h = g; g = f; f = e; e = d + T1;
-               d = c; c = b; b = a; a = T1 + T2;
-       }
-
-       H[0] += a; H[1] += b; H[2] += c; H[3] += d;
-       H[4] += e; H[5] += f; H[6] += g; H[7] += h;
+       SHA2_CTX ctx;
+       zio_cksum_t tmp;
+
+       SHA2Init(SHA256, &ctx);
+       SHA2Update(&ctx, buf, size);
+       SHA2Final(&tmp, &ctx);
+
+       /*
+        * A prior implementation of this function had a
+        * private SHA256 implementation always wrote things out in
+        * Big Endian and there wasn't a byteswap variant of it.
+        * To preseve on disk compatibility we need to force that
+        * behaviour.
+        */
+       zcp->zc_word[0] = BE_64(tmp.zc_word[0]);
+       zcp->zc_word[1] = BE_64(tmp.zc_word[1]);
+       zcp->zc_word[2] = BE_64(tmp.zc_word[2]);
+       zcp->zc_word[3] = BE_64(tmp.zc_word[3]);
 }
 
+/*ARGSUSED*/
 void
-zio_checksum_SHA256(const void *buf, uint64_t size, zio_cksum_t *zcp)
+zio_checksum_SHA512_native(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
 {
-       uint32_t H[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
-           0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 };
-       uint8_t pad[128];
-       int i, padsize;
+       SHA2_CTX        ctx;
 
-       for (i = 0; i < (size & ~63ULL); i += 64)
-               SHA256Transform(H, (uint8_t *)buf + i);
-
-       for (padsize = 0; i < size; i++)
-               pad[padsize++] = *((uint8_t *)buf + i);
-
-       for (pad[padsize++] = 0x80; (padsize & 63) != 56; padsize++)
-               pad[padsize] = 0;
-
-       for (i = 56; i >= 0; i -= 8)
-               pad[padsize++] = (size << 3) >> i;
+       SHA2Init(SHA512_256, &ctx);
+       SHA2Update(&ctx, buf, size);
+       SHA2Final(zcp, &ctx);
+}
 
-       for (i = 0; i < padsize; i += 64)
-               SHA256Transform(H, pad + i);
+/*ARGSUSED*/
+void
+zio_checksum_SHA512_byteswap(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
+{
+       zio_cksum_t     tmp;
 
-       ZIO_SET_CHECKSUM(zcp,
-           (uint64_t)H[0] << 32 | H[1],
-           (uint64_t)H[2] << 32 | H[3],
-           (uint64_t)H[4] << 32 | H[5],
-           (uint64_t)H[6] << 32 | H[7]);
+       zio_checksum_SHA512_native(buf, size, ctx_template, &tmp);
+       zcp->zc_word[0] = BSWAP_64(tmp.zc_word[0]);
+       zcp->zc_word[1] = BSWAP_64(tmp.zc_word[1]);
+       zcp->zc_word[2] = BSWAP_64(tmp.zc_word[2]);
+       zcp->zc_word[3] = BSWAP_64(tmp.zc_word[3]);
 }
diff --git a/zfs/module/zfs/skein_zfs.c b/zfs/module/zfs/skein_zfs.c
new file mode 100644 (file)
index 0000000..6592340
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 2013 Saso Kiselkov.  All rights reserved.
+ */
+#include <sys/zfs_context.h>
+#include <sys/zio.h>
+#include <sys/skein.h>
+
+/*
+ * Computes a native 256-bit skein MAC checksum. Please note that this
+ * function requires the presence of a ctx_template that should be allocated
+ * using zio_checksum_skein_tmpl_init.
+ */
+/*ARGSUSED*/
+void
+zio_checksum_skein_native(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
+{
+       Skein_512_Ctxt_t        ctx;
+
+       ASSERT(ctx_template != NULL);
+       bcopy(ctx_template, &ctx, sizeof (ctx));
+       (void) Skein_512_Update(&ctx, buf, size);
+       (void) Skein_512_Final(&ctx, (uint8_t *)zcp);
+       bzero(&ctx, sizeof (ctx));
+}
+
+/*
+ * Byteswapped version of zio_checksum_skein_native. This just invokes
+ * the native checksum function and byteswaps the resulting checksum (since
+ * skein is internally endian-insensitive).
+ */
+void
+zio_checksum_skein_byteswap(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
+{
+       zio_cksum_t     tmp;
+
+       zio_checksum_skein_native(buf, size, ctx_template, &tmp);
+       zcp->zc_word[0] = BSWAP_64(tmp.zc_word[0]);
+       zcp->zc_word[1] = BSWAP_64(tmp.zc_word[1]);
+       zcp->zc_word[2] = BSWAP_64(tmp.zc_word[2]);
+       zcp->zc_word[3] = BSWAP_64(tmp.zc_word[3]);
+}
+
+/*
+ * Allocates a skein MAC template suitable for using in skein MAC checksum
+ * computations and returns a pointer to it.
+ */
+void *
+zio_checksum_skein_tmpl_init(const zio_cksum_salt_t *salt)
+{
+       Skein_512_Ctxt_t        *ctx;
+
+       ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
+       (void) Skein_512_InitExt(ctx, sizeof (zio_cksum_t) * 8, 0,
+           salt->zcs_bytes, sizeof (salt->zcs_bytes));
+       return (ctx);
+}
+
+/*
+ * Frees a skein context template previously allocated using
+ * zio_checksum_skein_tmpl_init.
+ */
+void
+zio_checksum_skein_tmpl_free(void *ctx_template)
+{
+       Skein_512_Ctxt_t        *ctx = ctx_template;
+
+       bzero(ctx, sizeof (*ctx));
+       kmem_free(ctx, sizeof (*ctx));
+}
index a220ae393ea84ba3bff63a56639ffa116bae6fda..ec6924a020b46e74c68abc730bc6f3f46f2771d4 100644 (file)
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2015, Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2013, 2014, Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include "zfs_prop.h"
 #include "zfs_comutil.h"
 
+/*
+ * The interval, in seconds, at which failed configuration cache file writes
+ * should be retried.
+ */
+static int zfs_ccw_retry_interval = 300;
+
 typedef enum zti_modes {
        ZTI_MODE_FIXED,                 /* value is # of threads (min 1) */
        ZTI_MODE_BATCH,                 /* cpu-intensive; value is ignored */
@@ -193,7 +201,7 @@ spa_prop_get_config(spa_t *spa, nvlist_t **nvp)
        vdev_t *rvd = spa->spa_root_vdev;
        dsl_pool_t *pool = spa->spa_dsl_pool;
        uint64_t size, alloc, cap, version;
-       zprop_source_t src = ZPROP_SRC_NONE;
+       const zprop_source_t src = ZPROP_SRC_NONE;
        spa_config_dirent_t *dp;
        metaslab_class_t *mc = spa_normal_class(spa);
 
@@ -225,11 +233,13 @@ spa_prop_get_config(spa_t *spa, nvlist_t **nvp)
                    rvd->vdev_state, src);
 
                version = spa_version(spa);
-               if (version == zpool_prop_default_numeric(ZPOOL_PROP_VERSION))
-                       src = ZPROP_SRC_DEFAULT;
-               else
-                       src = ZPROP_SRC_LOCAL;
-               spa_prop_add_list(*nvp, ZPOOL_PROP_VERSION, NULL, version, src);
+               if (version == zpool_prop_default_numeric(ZPOOL_PROP_VERSION)) {
+                       spa_prop_add_list(*nvp, ZPOOL_PROP_VERSION, NULL,
+                           version, ZPROP_SRC_DEFAULT);
+               } else {
+                       spa_prop_add_list(*nvp, ZPOOL_PROP_VERSION, NULL,
+                           version, ZPROP_SRC_LOCAL);
+               }
        }
 
        if (pool != NULL) {
@@ -275,6 +285,14 @@ spa_prop_get_config(spa_t *spa, nvlist_t **nvp)
                    SPA_OLD_MAXBLOCKSIZE, ZPROP_SRC_NONE);
        }
 
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_DNODE)) {
+               spa_prop_add_list(*nvp, ZPOOL_PROP_MAXDNODESIZE, NULL,
+                   DNODE_MAX_SIZE, ZPROP_SRC_NONE);
+       } else {
+               spa_prop_add_list(*nvp, ZPOOL_PROP_MAXDNODESIZE, NULL,
+                   DNODE_MIN_SIZE, ZPROP_SRC_NONE);
+       }
+
        if ((dp = list_head(&spa->spa_config_list)) != NULL) {
                if (dp->scd_path == NULL) {
                        spa_prop_add_list(*nvp, ZPOOL_PROP_CACHEFILE,
@@ -347,8 +365,7 @@ spa_prop_get(spa_t *spa, nvlist_t **nvp)
                                        break;
                                }
 
-                               strval = kmem_alloc(
-                                   MAXNAMELEN + strlen(MOS_DIR_NAME) + 1,
+                               strval = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN,
                                    KM_SLEEP);
                                dsl_dataset_name(ds, strval);
                                dsl_dataset_rele(ds, FTAG);
@@ -361,8 +378,7 @@ spa_prop_get(spa_t *spa, nvlist_t **nvp)
                        spa_prop_add_list(*nvp, prop, strval, intval, src);
 
                        if (strval != NULL)
-                               kmem_free(strval,
-                                   MAXNAMELEN + strlen(MOS_DIR_NAME) + 1);
+                               kmem_free(strval, ZFS_MAX_DATASET_NAME_LEN);
 
                        break;
 
@@ -506,7 +522,8 @@ spa_prop_validate(spa_t *spa, nvlist_t *props)
                                /*
                                 * Must be ZPL, and its property settings
                                 * must be supported by GRUB (compression
-                                * is not gzip, and large blocks are not used).
+                                * is not gzip, and large blocks or large
+                                * dnodes are not used).
                                 */
 
                                if (dmu_objset_type(os) != DMU_OST_ZFS) {
@@ -523,6 +540,12 @@ spa_prop_validate(spa_t *spa, nvlist_t *props)
                                    &propval)) == 0 &&
                                    propval > SPA_OLD_MAXBLOCKSIZE) {
                                        error = SET_ERROR(ENOTSUP);
+                               } else if ((error =
+                                   dsl_prop_get_int_ds(dmu_objset_ds(os),
+                                   zfs_prop_to_name(ZFS_PROP_DNODESIZE),
+                                   &propval)) == 0 &&
+                                   propval != ZFS_DNSIZE_LEGACY) {
+                                       error = SET_ERROR(ENOTSUP);
                                } else {
                                        objnum = dmu_objset_id(os);
                                }
@@ -583,7 +606,6 @@ spa_prop_validate(spa_t *spa, nvlist_t *props)
                                        error = SET_ERROR(EINVAL);
                                        break;
                                }
-                               check++;
                        }
                        if (strlen(strval) > ZPROP_MAX_COMMENT)
                                error = SET_ERROR(E2BIG);
@@ -783,7 +805,7 @@ spa_change_guid(spa_t *spa)
 
        if (error == 0) {
                spa_config_sync(spa, B_FALSE, B_TRUE);
-               spa_event_notify(spa, NULL, FM_EREPORT_ZFS_POOL_REGUID);
+               spa_event_notify(spa, NULL, ESC_ZFS_POOL_REGUID);
        }
 
        mutex_exit(&spa_namespace_lock);
@@ -801,19 +823,14 @@ spa_change_guid(spa_t *spa)
 static int
 spa_error_entry_compare(const void *a, const void *b)
 {
-       spa_error_entry_t *sa = (spa_error_entry_t *)a;
-       spa_error_entry_t *sb = (spa_error_entry_t *)b;
+       const spa_error_entry_t *sa = (const spa_error_entry_t *)a;
+       const spa_error_entry_t *sb = (const spa_error_entry_t *)b;
        int ret;
 
-       ret = bcmp(&sa->se_bookmark, &sb->se_bookmark,
+       ret = memcmp(&sa->se_bookmark, &sb->se_bookmark,
            sizeof (zbookmark_phys_t));
 
-       if (ret < 0)
-               return (-1);
-       else if (ret > 0)
-               return (1);
-       else
-               return (0);
+       return (AVL_ISIGN(ret));
 }
 
 /*
@@ -845,7 +862,7 @@ spa_taskqs_init(spa_t *spa, zio_type_t t, zio_taskq_type_t q)
        uint_t count = ztip->zti_count;
        spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q];
        char name[32];
-       uint_t i, flags = TASKQ_DYNAMIC;
+       uint_t i, flags = 0;
        boolean_t batch = B_FALSE;
 
        if (mode == ZTI_MODE_NULL) {
@@ -863,6 +880,7 @@ spa_taskqs_init(spa_t *spa, zio_type_t t, zio_taskq_type_t q)
        case ZTI_MODE_FIXED:
                ASSERT3U(value, >=, 1);
                value = MAX(value, 1);
+               flags |= TASKQ_DYNAMIC;
                break;
 
        case ZTI_MODE_BATCH:
@@ -1150,6 +1168,13 @@ spa_activate(spa_t *spa, int mode)
         */
        spa->spa_zvol_taskq = taskq_create("z_zvol", 1, defclsyspri,
            1, INT_MAX, 0);
+
+       /*
+        * The taskq to upgrade datasets in this pool. Currently used by
+        * feature SPA_FEATURE_USEROBJ_ACCOUNTING.
+        */
+       spa->spa_upgrade_taskq = taskq_create("z_upgrade", boot_ncpus,
+           defclsyspri, 1, INT_MAX, TASKQ_DYNAMIC);
 }
 
 /*
@@ -1173,6 +1198,11 @@ spa_deactivate(spa_t *spa)
                spa->spa_zvol_taskq = NULL;
        }
 
+       if (spa->spa_upgrade_taskq) {
+               taskq_destroy(spa->spa_upgrade_taskq);
+               spa->spa_upgrade_taskq = NULL;
+       }
+
        txg_list_destroy(&spa->spa_vdev_txg_list);
 
        list_destroy(&spa->spa_config_dirty_list);
@@ -1333,7 +1363,6 @@ spa_unload(spa_t *spa)
 
        ddt_unload(spa);
 
-
        /*
         * Drop and purge level 2 cache
         */
@@ -1512,20 +1541,21 @@ spa_load_l2cache(spa_t *spa)
 
        ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
 
-       if (sav->sav_config != NULL) {
-               VERIFY(nvlist_lookup_nvlist_array(sav->sav_config,
-                   ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0);
-               newvdevs = kmem_alloc(nl2cache * sizeof (void *), KM_SLEEP);
-       } else {
-               nl2cache = 0;
-               newvdevs = NULL;
-       }
-
        oldvdevs = sav->sav_vdevs;
        oldnvdevs = sav->sav_count;
        sav->sav_vdevs = NULL;
        sav->sav_count = 0;
 
+       if (sav->sav_config == NULL) {
+               nl2cache = 0;
+               newvdevs = NULL;
+               goto out;
+       }
+
+       VERIFY(nvlist_lookup_nvlist_array(sav->sav_config,
+           ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0);
+       newvdevs = kmem_alloc(nl2cache * sizeof (void *), KM_SLEEP);
+
        /*
         * Process new nvlist of vdevs.
         */
@@ -1576,6 +1606,24 @@ spa_load_l2cache(spa_t *spa)
                }
        }
 
+       sav->sav_vdevs = newvdevs;
+       sav->sav_count = (int)nl2cache;
+
+       /*
+        * Recompute the stashed list of l2cache devices, with status
+        * information this time.
+        */
+       VERIFY(nvlist_remove(sav->sav_config, ZPOOL_CONFIG_L2CACHE,
+           DATA_TYPE_NVLIST_ARRAY) == 0);
+
+       l2cache = kmem_alloc(sav->sav_count * sizeof (void *), KM_SLEEP);
+       for (i = 0; i < sav->sav_count; i++)
+               l2cache[i] = vdev_config_generate(spa,
+                   sav->sav_vdevs[i], B_TRUE, VDEV_CONFIG_L2CACHE);
+       VERIFY(nvlist_add_nvlist_array(sav->sav_config,
+           ZPOOL_CONFIG_L2CACHE, l2cache, sav->sav_count) == 0);
+
+out:
        /*
         * Purge vdevs that were dropped
         */
@@ -1597,26 +1645,6 @@ spa_load_l2cache(spa_t *spa)
        if (oldvdevs)
                kmem_free(oldvdevs, oldnvdevs * sizeof (void *));
 
-       if (sav->sav_config == NULL)
-               goto out;
-
-       sav->sav_vdevs = newvdevs;
-       sav->sav_count = (int)nl2cache;
-
-       /*
-        * Recompute the stashed list of l2cache devices, with status
-        * information this time.
-        */
-       VERIFY(nvlist_remove(sav->sav_config, ZPOOL_CONFIG_L2CACHE,
-           DATA_TYPE_NVLIST_ARRAY) == 0);
-
-       l2cache = kmem_alloc(sav->sav_count * sizeof (void *), KM_SLEEP);
-       for (i = 0; i < sav->sav_count; i++)
-               l2cache[i] = vdev_config_generate(spa,
-                   sav->sav_vdevs[i], B_TRUE, VDEV_CONFIG_L2CACHE);
-       VERIFY(nvlist_add_nvlist_array(sav->sav_config,
-           ZPOOL_CONFIG_L2CACHE, l2cache, sav->sav_count) == 0);
-out:
        for (i = 0; i < sav->sav_count; i++)
                nvlist_free(l2cache[i]);
        if (sav->sav_count)
@@ -1663,9 +1691,23 @@ spa_check_removed(vdev_t *vd)
 
        if (vd->vdev_ops->vdev_op_leaf && vdev_is_dead(vd) &&
            !vd->vdev_ishole) {
-               zfs_ereport_post(FM_EREPORT_RESOURCE_AUTOREPLACE,
-                   vd->vdev_spa, vd, NULL, 0, 0);
-               spa_event_notify(vd->vdev_spa, vd, FM_EREPORT_ZFS_DEVICE_CHECK);
+               zfs_post_autoreplace(vd->vdev_spa, vd);
+               spa_event_notify(vd->vdev_spa, vd, ESC_ZFS_VDEV_CHECK);
+       }
+}
+
+static void
+spa_config_valid_zaps(vdev_t *vd, vdev_t *mvd)
+{
+       uint64_t i;
+
+       ASSERT3U(vd->vdev_children, ==, mvd->vdev_children);
+
+       vd->vdev_top_zap = mvd->vdev_top_zap;
+       vd->vdev_leaf_zap = mvd->vdev_leaf_zap;
+
+       for (i = 0; i < vd->vdev_children; i++) {
+               spa_config_valid_zaps(vd->vdev_child[i], mvd->vdev_child[i]);
        }
 }
 
@@ -1695,7 +1737,7 @@ spa_config_valid(spa_t *spa, nvlist_t *config)
                nvlist_t **child, *nv;
                uint64_t idx = 0;
 
-               child = kmem_alloc(rvd->vdev_children * sizeof (nvlist_t **),
+               child = kmem_alloc(rvd->vdev_children * sizeof (nvlist_t *),
                    KM_SLEEP);
                VERIFY(nvlist_alloc(&nv, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 
@@ -1773,16 +1815,25 @@ spa_config_valid(spa_t *spa, nvlist_t *config)
                        spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
 
                        vdev_reopen(rvd);
-               } else if (mtvd->vdev_islog) {
+               } else {
+                       if (mtvd->vdev_islog) {
+                               /*
+                                * Load the slog device's state from the MOS
+                                * config since it's possible that the label
+                                * does not contain the most up-to-date
+                                * information.
+                                */
+                               vdev_load_log_state(tvd, mtvd);
+                               vdev_reopen(tvd);
+                       }
+
                        /*
-                        * Load the slog device's state from the MOS config
-                        * since it's possible that the label does not
-                        * contain the most up-to-date information.
+                        * Per-vdev ZAP info is stored exclusively in the MOS.
                         */
-                       vdev_load_log_state(tvd, mtvd);
-                       vdev_reopen(tvd);
+                       spa_config_valid_zaps(tvd, mtvd);
                }
        }
+
        vdev_free(mrvd);
        spa_config_exit(spa, SCL_ALL, FTAG);
 
@@ -1916,9 +1967,9 @@ spa_load_verify_done(zio_t *zio)
        if (error) {
                if ((BP_GET_LEVEL(bp) != 0 || DMU_OT_IS_METADATA(type)) &&
                    type != DMU_OT_INTENT_LOG)
-                       atomic_add_64(&sle->sle_meta_count, 1);
+                       atomic_inc_64(&sle->sle_meta_count);
                else
-                       atomic_add_64(&sle->sle_data_count, 1);
+                       atomic_inc_64(&sle->sle_data_count);
        }
        zio_data_buf_free(zio->io_data, zio->io_size);
 
@@ -1945,7 +1996,7 @@ spa_load_verify_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
        size_t size;
        void *data;
 
-       if (BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
+       if (bp == NULL || BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp))
                return (0);
        /*
         * Note: normally this routine will not be called if
@@ -2227,6 +2278,38 @@ spa_load(spa_t *spa, spa_load_state_t state, spa_import_type_t type,
        return (error);
 }
 
+#ifdef ZFS_DEBUG
+/*
+ * Count the number of per-vdev ZAPs associated with all of the vdevs in the
+ * vdev tree rooted in the given vd, and ensure that each ZAP is present in the
+ * spa's per-vdev ZAP list.
+ */
+static uint64_t
+vdev_count_verify_zaps(vdev_t *vd)
+{
+       spa_t *spa = vd->vdev_spa;
+       uint64_t total = 0;
+       uint64_t i;
+
+       if (vd->vdev_top_zap != 0) {
+               total++;
+               ASSERT0(zap_lookup_int(spa->spa_meta_objset,
+                   spa->spa_all_vdev_zaps, vd->vdev_top_zap));
+       }
+       if (vd->vdev_leaf_zap != 0) {
+               total++;
+               ASSERT0(zap_lookup_int(spa->spa_meta_objset,
+                   spa->spa_all_vdev_zaps, vd->vdev_leaf_zap));
+       }
+
+       for (i = 0; i < vd->vdev_children; i++) {
+               total += vdev_count_verify_zaps(vd->vdev_child[i]);
+       }
+
+       return (total);
+}
+#endif
+
 /*
  * Load an existing storage pool, using the pool's builtin spa_config as a
  * source of configuration information.
@@ -2247,6 +2330,7 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
        int parse, i;
        uint64_t obj;
        boolean_t missing_feat_write = B_FALSE;
+       nvlist_t *mos_config;
 
        /*
         * If this is an untrusted config, access the pool in read-only mode.
@@ -2604,6 +2688,19 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
                return (spa_load(spa, state, SPA_IMPORT_EXISTING, B_TRUE));
        }
 
+       /* Grab the checksum salt from the MOS. */
+       error = zap_lookup(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_CHECKSUM_SALT, 1,
+           sizeof (spa->spa_cksum_salt.zcs_bytes),
+           spa->spa_cksum_salt.zcs_bytes);
+       if (error == ENOENT) {
+               /* Generate a new salt for subsequent use */
+               (void) random_get_pseudo_bytes(spa->spa_cksum_salt.zcs_bytes,
+                   sizeof (spa->spa_cksum_salt.zcs_bytes));
+       } else if (error != 0) {
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+       }
+
        if (spa_dir_prop(spa, DMU_POOL_SYNC_BPOBJ, &obj) != 0)
                return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
        error = bpobj_open(&spa->spa_deferred_bpobj, spa->spa_meta_objset, obj);
@@ -2645,6 +2742,38 @@ spa_load_impl(spa_t *spa, uint64_t pool_guid, nvlist_t *config,
        if (error != 0 && error != ENOENT)
                return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
 
+       /*
+        * Load the per-vdev ZAP map. If we have an older pool, this will not
+        * be present; in this case, defer its creation to a later time to
+        * avoid dirtying the MOS this early / out of sync context. See
+        * spa_sync_config_object.
+        */
+
+       /* The sentinel is only available in the MOS config. */
+       if (load_nvlist(spa, spa->spa_config_object, &mos_config) != 0)
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+
+       error = spa_dir_prop(spa, DMU_POOL_VDEV_ZAP_MAP,
+           &spa->spa_all_vdev_zaps);
+
+       if (error != ENOENT && error != 0) {
+               return (spa_vdev_err(rvd, VDEV_AUX_CORRUPT_DATA, EIO));
+       } else if (error == 0 && !nvlist_exists(mos_config,
+           ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS)) {
+               /*
+                * An older version of ZFS overwrote the sentinel value, so
+                * we have orphaned per-vdev ZAPs in the MOS. Defer their
+                * destruction to later; see spa_sync_config_object.
+                */
+               spa->spa_avz_action = AVZ_ACTION_DESTROY;
+               /*
+                * We're assuming that no vdevs have had their ZAPs created
+                * before this. Better be sure of it.
+                */
+               ASSERT0(vdev_count_verify_zaps(spa->spa_root_vdev));
+       }
+       nvlist_free(mos_config);
+
        /*
         * If we're assembling the pool from the split-off vdevs of
         * an existing pool, we don't want to attach the spares & cache
@@ -2988,6 +3117,8 @@ spa_load_best(spa_t *spa, spa_load_state_t state, int mosconfig,
 
        if (config && (rewind_error || state != SPA_LOAD_RECOVER))
                spa_config_set(spa, config);
+       else
+               nvlist_free(config);
 
        if (state == SPA_LOAD_RECOVER) {
                ASSERT3P(loadinfo, ==, NULL);
@@ -3274,6 +3405,8 @@ spa_add_l2cache(spa_t *spa, nvlist_t *config)
                            ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc)
                            == 0);
                        vdev_get_stats(vd, vs);
+                       vdev_config_generate_stats(vd, l2cache[i]);
+
                }
        }
 }
@@ -3679,6 +3812,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
        spa->spa_uberblock.ub_txg = txg - 1;
        spa->spa_uberblock.ub_version = version;
        spa->spa_ubsync = spa->spa_uberblock;
+       spa->spa_load_state = SPA_LOAD_CREATE;
 
        /*
         * Create "The Godfather" zio to hold all async IOs
@@ -3822,6 +3956,12 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
        if (version >= SPA_VERSION_ZPOOL_HISTORY)
                spa_history_create_obj(spa, tx);
 
+       /*
+        * Generate some random noise for salted checksums to operate on.
+        */
+       (void) random_get_pseudo_bytes(spa->spa_cksum_salt.zcs_bytes,
+           sizeof (spa->spa_cksum_salt.zcs_bytes));
+
        /*
         * Set pool properties.
         */
@@ -3847,6 +3987,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
        txg_wait_synced(spa->spa_dsl_pool, txg);
 
        spa_config_sync(spa, B_FALSE, B_TRUE);
+       spa_event_notify(spa, NULL, ESC_ZFS_POOL_CREATE);
 
        spa_history_log_version(spa, "create");
 
@@ -3856,217 +3997,13 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props,
         */
        spa_evicting_os_wait(spa);
        spa->spa_minref = refcount_count(&spa->spa_refcount);
+       spa->spa_load_state = SPA_LOAD_NONE;
 
        mutex_exit(&spa_namespace_lock);
 
        return (0);
 }
 
-#ifdef _KERNEL
-/*
- * Get the root pool information from the root disk, then import the root pool
- * during the system boot up time.
- */
-extern int vdev_disk_read_rootlabel(char *, char *, nvlist_t **);
-
-static nvlist_t *
-spa_generate_rootconf(char *devpath, char *devid, uint64_t *guid)
-{
-       nvlist_t *config;
-       nvlist_t *nvtop, *nvroot;
-       uint64_t pgid;
-
-       if (vdev_disk_read_rootlabel(devpath, devid, &config) != 0)
-               return (NULL);
-
-       /*
-        * Add this top-level vdev to the child array.
-        */
-       VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
-           &nvtop) == 0);
-       VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID,
-           &pgid) == 0);
-       VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, guid) == 0);
-
-       /*
-        * Put this pool's top-level vdevs into a root vdev.
-        */
-       VERIFY(nvlist_alloc(&nvroot, NV_UNIQUE_NAME, KM_SLEEP) == 0);
-       VERIFY(nvlist_add_string(nvroot, ZPOOL_CONFIG_TYPE,
-           VDEV_TYPE_ROOT) == 0);
-       VERIFY(nvlist_add_uint64(nvroot, ZPOOL_CONFIG_ID, 0ULL) == 0);
-       VERIFY(nvlist_add_uint64(nvroot, ZPOOL_CONFIG_GUID, pgid) == 0);
-       VERIFY(nvlist_add_nvlist_array(nvroot, ZPOOL_CONFIG_CHILDREN,
-           &nvtop, 1) == 0);
-
-       /*
-        * Replace the existing vdev_tree with the new root vdev in
-        * this pool's configuration (remove the old, add the new).
-        */
-       VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot) == 0);
-       nvlist_free(nvroot);
-       return (config);
-}
-
-/*
- * Walk the vdev tree and see if we can find a device with "better"
- * configuration. A configuration is "better" if the label on that
- * device has a more recent txg.
- */
-static void
-spa_alt_rootvdev(vdev_t *vd, vdev_t **avd, uint64_t *txg)
-{
-       int c;
-
-       for (c = 0; c < vd->vdev_children; c++)
-               spa_alt_rootvdev(vd->vdev_child[c], avd, txg);
-
-       if (vd->vdev_ops->vdev_op_leaf) {
-               nvlist_t *label;
-               uint64_t label_txg;
-
-               if (vdev_disk_read_rootlabel(vd->vdev_physpath, vd->vdev_devid,
-                   &label) != 0)
-                       return;
-
-               VERIFY(nvlist_lookup_uint64(label, ZPOOL_CONFIG_POOL_TXG,
-                   &label_txg) == 0);
-
-               /*
-                * Do we have a better boot device?
-                */
-               if (label_txg > *txg) {
-                       *txg = label_txg;
-                       *avd = vd;
-               }
-               nvlist_free(label);
-       }
-}
-
-/*
- * Import a root pool.
- *
- * For x86. devpath_list will consist of devid and/or physpath name of
- * the vdev (e.g. "id1,sd@SSEAGATE..." or "/pci@1f,0/ide@d/disk@0,0:a").
- * The GRUB "findroot" command will return the vdev we should boot.
- *
- * For Sparc, devpath_list consists the physpath name of the booting device
- * no matter the rootpool is a single device pool or a mirrored pool.
- * e.g.
- *     "/pci@1f,0/ide@d/disk@0,0:a"
- */
-int
-spa_import_rootpool(char *devpath, char *devid)
-{
-       spa_t *spa;
-       vdev_t *rvd, *bvd, *avd = NULL;
-       nvlist_t *config, *nvtop;
-       uint64_t guid, txg;
-       char *pname;
-       int error;
-
-       /*
-        * Read the label from the boot device and generate a configuration.
-        */
-       config = spa_generate_rootconf(devpath, devid, &guid);
-#if defined(_OBP) && defined(_KERNEL)
-       if (config == NULL) {
-               if (strstr(devpath, "/iscsi/ssd") != NULL) {
-                       /* iscsi boot */
-                       get_iscsi_bootpath_phy(devpath);
-                       config = spa_generate_rootconf(devpath, devid, &guid);
-               }
-       }
-#endif
-       if (config == NULL) {
-               cmn_err(CE_NOTE, "Cannot read the pool label from '%s'",
-                   devpath);
-               return (SET_ERROR(EIO));
-       }
-
-       VERIFY(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME,
-           &pname) == 0);
-       VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, &txg) == 0);
-
-       mutex_enter(&spa_namespace_lock);
-       if ((spa = spa_lookup(pname)) != NULL) {
-               /*
-                * Remove the existing root pool from the namespace so that we
-                * can replace it with the correct config we just read in.
-                */
-               spa_remove(spa);
-       }
-
-       spa = spa_add(pname, config, NULL);
-       spa->spa_is_root = B_TRUE;
-       spa->spa_import_flags = ZFS_IMPORT_VERBATIM;
-
-       /*
-        * Build up a vdev tree based on the boot device's label config.
-        */
-       VERIFY(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE,
-           &nvtop) == 0);
-       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
-       error = spa_config_parse(spa, &rvd, nvtop, NULL, 0,
-           VDEV_ALLOC_ROOTPOOL);
-       spa_config_exit(spa, SCL_ALL, FTAG);
-       if (error) {
-               mutex_exit(&spa_namespace_lock);
-               nvlist_free(config);
-               cmn_err(CE_NOTE, "Can not parse the config for pool '%s'",
-                   pname);
-               return (error);
-       }
-
-       /*
-        * Get the boot vdev.
-        */
-       if ((bvd = vdev_lookup_by_guid(rvd, guid)) == NULL) {
-               cmn_err(CE_NOTE, "Can not find the boot vdev for guid %llu",
-                   (u_longlong_t)guid);
-               error = SET_ERROR(ENOENT);
-               goto out;
-       }
-
-       /*
-        * Determine if there is a better boot device.
-        */
-       avd = bvd;
-       spa_alt_rootvdev(rvd, &avd, &txg);
-       if (avd != bvd) {
-               cmn_err(CE_NOTE, "The boot device is 'degraded'. Please "
-                   "try booting from '%s'", avd->vdev_path);
-               error = SET_ERROR(EINVAL);
-               goto out;
-       }
-
-       /*
-        * If the boot device is part of a spare vdev then ensure that
-        * we're booting off the active spare.
-        */
-       if (bvd->vdev_parent->vdev_ops == &vdev_spare_ops &&
-           !bvd->vdev_isspare) {
-               cmn_err(CE_NOTE, "The boot device is currently spared. Please "
-                   "try booting from '%s'",
-                   bvd->vdev_parent->
-                   vdev_child[bvd->vdev_parent->vdev_children - 1]->vdev_path);
-               error = SET_ERROR(EINVAL);
-               goto out;
-       }
-
-       error = 0;
-out:
-       spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
-       vdev_free(rvd);
-       spa_config_exit(spa, SCL_ALL, FTAG);
-       mutex_exit(&spa_namespace_lock);
-
-       nvlist_free(config);
-       return (error);
-}
-
-#endif
-
 /*
  * Import a non-root pool into the system.
  */
@@ -4114,6 +4051,7 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
                        spa_configfile_set(spa, props, B_FALSE);
 
                spa_config_sync(spa, B_FALSE, B_TRUE);
+               spa_event_notify(spa, NULL, ESC_ZFS_POOL_IMPORT);
 
                mutex_exit(&spa_namespace_lock);
                return (0);
@@ -4244,10 +4182,14 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
         */
        spa_async_request(spa, SPA_ASYNC_AUTOEXPAND);
 
-       mutex_exit(&spa_namespace_lock);
        spa_history_log_version(spa, "import");
+
+       spa_event_notify(spa, NULL, ESC_ZFS_POOL_IMPORT);
+
        zvol_create_minors(spa, pool, B_TRUE);
 
+       mutex_exit(&spa_namespace_lock);
+
        return (0);
 }
 
@@ -4443,7 +4385,7 @@ spa_export_common(char *pool, int new_state, nvlist_t **oldconfig,
        }
 
 export_spa:
-       spa_event_notify(spa, NULL, FM_EREPORT_ZFS_POOL_DESTROY);
+       spa_event_notify(spa, NULL, ESC_ZFS_POOL_DESTROY);
 
        if (spa->spa_state != POOL_STATE_UNINITIALIZED) {
                spa_unload(spa);
@@ -4599,6 +4541,7 @@ spa_vdev_add(spa_t *spa, nvlist_t *nvroot)
 
        mutex_enter(&spa_namespace_lock);
        spa_config_update(spa, SPA_CONFIG_UPDATE_POOL);
+       spa_event_notify(spa, NULL, ESC_ZFS_VDEV_ADD);
        mutex_exit(&spa_namespace_lock);
 
        return (0);
@@ -4774,7 +4717,7 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing)
 
        if (newvd->vdev_isspare) {
                spa_spare_activate(newvd);
-               spa_event_notify(spa, newvd, FM_EREPORT_ZFS_DEVICE_SPARE);
+               spa_event_notify(spa, newvd, ESC_ZFS_VDEV_SPARE);
        }
 
        oldvdpath = spa_strdup(oldvd->vdev_path);
@@ -4793,6 +4736,11 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing)
         */
        dsl_resilver_restart(spa->spa_dsl_pool, dtl_max_txg);
 
+       if (spa->spa_bootfs)
+               spa_event_notify(spa, newvd, ESC_ZFS_BOOTFS_VDEV_ATTACH);
+
+       spa_event_notify(spa, newvd, ESC_ZFS_VDEV_ATTACH);
+
        /*
         * Commit the config
         */
@@ -4807,9 +4755,6 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing)
        spa_strfree(oldvdpath);
        spa_strfree(newvdpath);
 
-       if (spa->spa_bootfs)
-               spa_event_notify(spa, newvd, FM_EREPORT_ZFS_BOOTFS_VDEV_ATTACH);
-
        return (0);
 }
 
@@ -5002,13 +4947,13 @@ spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid, int replace_done)
         * But first make sure we're not on any *other* txg's DTL list, to
         * prevent vd from being accessed after it's freed.
         */
-       vdpath = spa_strdup(vd->vdev_path);
+       vdpath = spa_strdup(vd->vdev_path ? vd->vdev_path : "none");
        for (t = 0; t < TXG_SIZE; t++)
                (void) txg_list_remove_this(&tvd->vdev_dtl_list, vd, t);
        vd->vdev_detached = B_TRUE;
        vdev_dirty(tvd, VDD_DTL, vd, txg);
 
-       spa_event_notify(spa, vd, FM_EREPORT_ZFS_DEVICE_REMOVE);
+       spa_event_notify(spa, vd, ESC_ZFS_VDEV_REMOVE);
 
        /* hang on to the spa before we release the lock */
        spa_open_ref(spa, FTAG);
@@ -5183,6 +5128,16 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
                    vml[c]->vdev_top->vdev_asize) == 0);
                VERIFY(nvlist_add_uint64(child[c], ZPOOL_CONFIG_ASHIFT,
                    vml[c]->vdev_top->vdev_ashift) == 0);
+
+               /* transfer per-vdev ZAPs */
+               ASSERT3U(vml[c]->vdev_leaf_zap, !=, 0);
+               VERIFY0(nvlist_add_uint64(child[c],
+                   ZPOOL_CONFIG_VDEV_LEAF_ZAP, vml[c]->vdev_leaf_zap));
+
+               ASSERT3U(vml[c]->vdev_top->vdev_top_zap, !=, 0);
+               VERIFY0(nvlist_add_uint64(child[c],
+                   ZPOOL_CONFIG_VDEV_TOP_ZAP,
+                   vml[c]->vdev_parent->vdev_top_zap));
        }
 
        if (error != 0) {
@@ -5224,11 +5179,13 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
            spa->spa_config_txg) == 0);
        VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
            spa_generate_guid(NULL)) == 0);
+       VERIFY0(nvlist_add_boolean(config, ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS));
        (void) nvlist_lookup_string(props,
            zpool_prop_to_name(ZPOOL_PROP_ALTROOT), &altroot);
 
        /* add the new pool to the namespace */
        newspa = spa_add(newname, config, altroot);
+       newspa->spa_avz_action = AVZ_ACTION_REBUILD;
        newspa->spa_config_txg = spa->spa_config_txg;
        spa_set_log_state(newspa, SPA_LOG_CLEAR);
 
@@ -5286,9 +5243,11 @@ spa_vdev_split_mirror(spa_t *spa, char *newname, nvlist_t *config,
                        if (error == 0)
                                spa_history_log_internal(spa, "detach", tx,
                                    "vdev=%s", vml[c]->vdev_path);
+
                        vdev_free(vml[c]);
                }
        }
+       spa->spa_avz_action = AVZ_ACTION_REBUILD;
        vdev_config_dirty(spa->spa_root_vdev);
        spa->spa_config_splitting = NULL;
        nvlist_free(nvl);
@@ -5354,7 +5313,7 @@ spa_nvlist_lookup_by_guid(nvlist_t **nvpp, int count, uint64_t target_guid)
 
 static void
 spa_vdev_remove_aux(nvlist_t *config, char *name, nvlist_t **dev, int count,
-       nvlist_t *dev_to_remove)
+    nvlist_t *dev_to_remove)
 {
        nvlist_t **newdev = NULL;
        int i, j;
@@ -5510,6 +5469,7 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
                } else {
                        error = SET_ERROR(EBUSY);
                }
+               spa_event_notify(spa, vd, ESC_ZFS_VDEV_REMOVE_AUX);
        } else if (spa->spa_l2cache.sav_vdevs != NULL &&
            nvlist_lookup_nvlist_array(spa->spa_l2cache.sav_config,
            ZPOOL_CONFIG_L2CACHE, &l2cache, &nl2cache) == 0 &&
@@ -5521,6 +5481,7 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
                    ZPOOL_CONFIG_L2CACHE, l2cache, nl2cache, nv);
                spa_load_l2cache(spa);
                spa->spa_l2cache.sav_sync = B_TRUE;
+               spa_event_notify(spa, vd, ESC_ZFS_VDEV_REMOVE_AUX);
        } else if (vd != NULL && vd->vdev_islog) {
                ASSERT(!locked);
                ASSERT(vd == vd->vdev_top);
@@ -5559,6 +5520,7 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare)
                 */
                spa_vdev_remove_from_namespace(spa, vd);
 
+               spa_event_notify(spa, vd, ESC_ZFS_VDEV_REMOVE_DEV);
        } else if (vd != NULL) {
                /*
                 * Normal vdevs cannot be removed (yet).
@@ -5846,7 +5808,7 @@ spa_async_autoexpand(spa_t *spa, vdev_t *vd)
        if (!vd->vdev_ops->vdev_op_leaf || vd->vdev_physpath == NULL)
                return;
 
-       spa_event_notify(vd->vdev_spa, vd, FM_EREPORT_ZFS_DEVICE_AUTOEXPAND);
+       spa_event_notify(vd->vdev_spa, vd, ESC_ZFS_VDEV_AUTOEXPAND);
 }
 
 static void
@@ -5953,13 +5915,34 @@ spa_async_resume(spa_t *spa)
        mutex_exit(&spa->spa_async_lock);
 }
 
+static boolean_t
+spa_async_tasks_pending(spa_t *spa)
+{
+       uint_t non_config_tasks;
+       uint_t config_task;
+       boolean_t config_task_suspended;
+
+       non_config_tasks = spa->spa_async_tasks & ~SPA_ASYNC_CONFIG_UPDATE;
+       config_task = spa->spa_async_tasks & SPA_ASYNC_CONFIG_UPDATE;
+       if (spa->spa_ccw_fail_time == 0) {
+               config_task_suspended = B_FALSE;
+       } else {
+               config_task_suspended =
+                   (gethrtime() - spa->spa_ccw_fail_time) <
+                   ((hrtime_t)zfs_ccw_retry_interval * NANOSEC);
+       }
+
+       return (non_config_tasks || (config_task && !config_task_suspended));
+}
+
 static void
 spa_async_dispatch(spa_t *spa)
 {
        mutex_enter(&spa->spa_async_lock);
-       if (spa->spa_async_tasks && !spa->spa_async_suspended &&
+       if (spa_async_tasks_pending(spa) &&
+           !spa->spa_async_suspended &&
            spa->spa_async_thread == NULL &&
-           rootdir != NULL && !vn_is_readonly(rootdir))
+           rootdir != NULL)
                spa->spa_async_thread = thread_create(NULL, 0,
                    spa_async_thread, spa, 0, &p0, TS_RUN, maxclsyspri);
        mutex_exit(&spa->spa_async_lock);
@@ -6101,16 +6084,120 @@ spa_sync_aux_dev(spa_t *spa, spa_aux_vdev_t *sav, dmu_tx_t *tx,
        sav->sav_sync = B_FALSE;
 }
 
+/*
+ * Rebuild spa's all-vdev ZAP from the vdev ZAPs indicated in each vdev_t.
+ * The all-vdev ZAP must be empty.
+ */
+static void
+spa_avz_build(vdev_t *vd, uint64_t avz, dmu_tx_t *tx)
+{
+       spa_t *spa = vd->vdev_spa;
+       uint64_t i;
+
+       if (vd->vdev_top_zap != 0) {
+               VERIFY0(zap_add_int(spa->spa_meta_objset, avz,
+                   vd->vdev_top_zap, tx));
+       }
+       if (vd->vdev_leaf_zap != 0) {
+               VERIFY0(zap_add_int(spa->spa_meta_objset, avz,
+                   vd->vdev_leaf_zap, tx));
+       }
+       for (i = 0; i < vd->vdev_children; i++) {
+               spa_avz_build(vd->vdev_child[i], avz, tx);
+       }
+}
+
 static void
 spa_sync_config_object(spa_t *spa, dmu_tx_t *tx)
 {
        nvlist_t *config;
 
-       if (list_is_empty(&spa->spa_config_dirty_list))
+       /*
+        * If the pool is being imported from a pre-per-vdev-ZAP version of ZFS,
+        * its config may not be dirty but we still need to build per-vdev ZAPs.
+        * Similarly, if the pool is being assembled (e.g. after a split), we
+        * need to rebuild the AVZ although the config may not be dirty.
+        */
+       if (list_is_empty(&spa->spa_config_dirty_list) &&
+           spa->spa_avz_action == AVZ_ACTION_NONE)
                return;
 
        spa_config_enter(spa, SCL_STATE, FTAG, RW_READER);
 
+       ASSERT(spa->spa_avz_action == AVZ_ACTION_NONE ||
+           spa->spa_all_vdev_zaps != 0);
+
+       if (spa->spa_avz_action == AVZ_ACTION_REBUILD) {
+               zap_cursor_t zc;
+               zap_attribute_t za;
+
+               /* Make and build the new AVZ */
+               uint64_t new_avz = zap_create(spa->spa_meta_objset,
+                   DMU_OTN_ZAP_METADATA, DMU_OT_NONE, 0, tx);
+               spa_avz_build(spa->spa_root_vdev, new_avz, tx);
+
+               /* Diff old AVZ with new one */
+               for (zap_cursor_init(&zc, spa->spa_meta_objset,
+                   spa->spa_all_vdev_zaps);
+                   zap_cursor_retrieve(&zc, &za) == 0;
+                   zap_cursor_advance(&zc)) {
+                       uint64_t vdzap = za.za_first_integer;
+                       if (zap_lookup_int(spa->spa_meta_objset, new_avz,
+                           vdzap) == ENOENT) {
+                               /*
+                                * ZAP is listed in old AVZ but not in new one;
+                                * destroy it
+                                */
+                               VERIFY0(zap_destroy(spa->spa_meta_objset, vdzap,
+                                   tx));
+                       }
+               }
+
+               zap_cursor_fini(&zc);
+
+               /* Destroy the old AVZ */
+               VERIFY0(zap_destroy(spa->spa_meta_objset,
+                   spa->spa_all_vdev_zaps, tx));
+
+               /* Replace the old AVZ in the dir obj with the new one */
+               VERIFY0(zap_update(spa->spa_meta_objset,
+                   DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_VDEV_ZAP_MAP,
+                   sizeof (new_avz), 1, &new_avz, tx));
+
+               spa->spa_all_vdev_zaps = new_avz;
+       } else if (spa->spa_avz_action == AVZ_ACTION_DESTROY) {
+               zap_cursor_t zc;
+               zap_attribute_t za;
+
+               /* Walk through the AVZ and destroy all listed ZAPs */
+               for (zap_cursor_init(&zc, spa->spa_meta_objset,
+                   spa->spa_all_vdev_zaps);
+                   zap_cursor_retrieve(&zc, &za) == 0;
+                   zap_cursor_advance(&zc)) {
+                       uint64_t zap = za.za_first_integer;
+                       VERIFY0(zap_destroy(spa->spa_meta_objset, zap, tx));
+               }
+
+               zap_cursor_fini(&zc);
+
+               /* Destroy and unlink the AVZ itself */
+               VERIFY0(zap_destroy(spa->spa_meta_objset,
+                   spa->spa_all_vdev_zaps, tx));
+               VERIFY0(zap_remove(spa->spa_meta_objset,
+                   DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_VDEV_ZAP_MAP, tx));
+               spa->spa_all_vdev_zaps = 0;
+       }
+
+       if (spa->spa_all_vdev_zaps == 0) {
+               spa->spa_all_vdev_zaps = zap_create_link(spa->spa_meta_objset,
+                   DMU_OTN_ZAP_METADATA, DMU_POOL_DIRECTORY_OBJECT,
+                   DMU_POOL_VDEV_ZAP_MAP, tx);
+       }
+       spa->spa_avz_action = AVZ_ACTION_NONE;
+
+       /* Create ZAPs for vdevs that don't have them. */
+       vdev_construct_zaps(spa->spa_root_vdev, tx);
+
        config = spa_config_generate(spa, spa->spa_root_vdev,
            dmu_tx_get_txg(tx), B_FALSE);
 
@@ -6124,8 +6211,7 @@ spa_sync_config_object(spa_t *spa, dmu_tx_t *tx)
 
        spa_config_exit(spa, SCL_STATE, FTAG);
 
-       if (spa->spa_config_syncing)
-               nvlist_free(spa->spa_config_syncing);
+       nvlist_free(spa->spa_config_syncing);
        spa->spa_config_syncing = config;
 
        spa_sync_nvlist(spa, spa->spa_config_object, config, tx);
@@ -6354,6 +6440,20 @@ spa_sync_upgrades(spa_t *spa, dmu_tx_t *tx)
                if (lz4_en && !lz4_ac)
                        spa_feature_incr(spa, SPA_FEATURE_LZ4_COMPRESS, tx);
        }
+
+       /*
+        * If we haven't written the salt, do so now.  Note that the
+        * feature may not be activated yet, but that's fine since
+        * the presence of this ZAP entry is backwards compatible.
+        */
+       if (zap_contains(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT,
+           DMU_POOL_CHECKSUM_SALT) == ENOENT) {
+               VERIFY0(zap_add(spa->spa_meta_objset,
+                   DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_CHECKSUM_SALT, 1,
+                   sizeof (spa->spa_cksum_salt.zcs_bytes),
+                   spa->spa_cksum_salt.zcs_bytes, tx));
+       }
+
        rrw_exit(&dp->dp_config_rwlock, FTAG);
 }
 
@@ -6367,10 +6467,14 @@ spa_sync(spa_t *spa, uint64_t txg)
        dsl_pool_t *dp = spa->spa_dsl_pool;
        objset_t *mos = spa->spa_meta_objset;
        bplist_t *free_bpl = &spa->spa_free_bplist[txg & TXG_MASK];
+       metaslab_class_t *mc;
        vdev_t *rvd = spa->spa_root_vdev;
        vdev_t *vd;
        dmu_tx_t *tx;
        int error;
+       uint32_t max_queue_depth = zfs_vdev_async_write_max_active *
+           zfs_vdev_queue_depth_pct / 100;
+       uint64_t queue_depth_total;
        int c;
 
        VERIFY(spa_writeable(spa));
@@ -6383,6 +6487,10 @@ spa_sync(spa_t *spa, uint64_t txg)
        spa->spa_syncing_txg = txg;
        spa->spa_sync_pass = 0;
 
+       mutex_enter(&spa->spa_alloc_lock);
+       VERIFY0(avl_numnodes(&spa->spa_alloc_tree));
+       mutex_exit(&spa->spa_alloc_lock);
+
        /*
         * If there are any pending vdev state changes, convert them
         * into config changes that go out with this transaction group.
@@ -6436,6 +6544,38 @@ spa_sync(spa_t *spa, uint64_t txg)
                }
        }
 
+       /*
+        * Set the top-level vdev's max queue depth. Evaluate each
+        * top-level's async write queue depth in case it changed.
+        * The max queue depth will not change in the middle of syncing
+        * out this txg.
+        */
+       queue_depth_total = 0;
+       for (c = 0; c < rvd->vdev_children; c++) {
+               vdev_t *tvd = rvd->vdev_child[c];
+               metaslab_group_t *mg = tvd->vdev_mg;
+
+               if (mg == NULL || mg->mg_class != spa_normal_class(spa) ||
+                   !metaslab_group_initialized(mg))
+                       continue;
+
+               /*
+                * It is safe to do a lock-free check here because only async
+                * allocations look at mg_max_alloc_queue_depth, and async
+                * allocations all happen from spa_sync().
+                */
+               ASSERT0(refcount_count(&mg->mg_alloc_queue_depth));
+               mg->mg_max_alloc_queue_depth = max_queue_depth;
+               queue_depth_total += mg->mg_max_alloc_queue_depth;
+       }
+       mc = spa_normal_class(spa);
+       ASSERT0(refcount_count(&mc->mc_alloc_slots));
+       mc->mc_alloc_max_slots = queue_depth_total;
+       mc->mc_alloc_throttle_enabled = zio_dva_throttle_enabled;
+
+       ASSERT3U(mc->mc_alloc_max_slots, <=,
+           max_queue_depth * rvd->vdev_children);
+
        /*
         * Iterate to convergence.
         */
@@ -6502,6 +6642,23 @@ spa_sync(spa_t *spa, uint64_t txg)
 
        } while (dmu_objset_is_dirty(mos, txg));
 
+#ifdef ZFS_DEBUG
+       if (!list_is_empty(&spa->spa_config_dirty_list)) {
+               /*
+                * Make sure that the number of ZAPs for all the vdevs matches
+                * the number of ZAPs in the per-vdev ZAP list. This only gets
+                * called if the config is dirty; otherwise there may be
+                * outstanding AVZ operations that weren't completed in
+                * spa_sync_config_object.
+                */
+               uint64_t all_vdev_zap_entry_count;
+               ASSERT0(zap_count(spa->spa_meta_objset,
+                   spa->spa_all_vdev_zaps, &all_vdev_zap_entry_count));
+               ASSERT3U(vdev_count_verify_zaps(spa->spa_root_vdev), ==,
+                   all_vdev_zap_entry_count);
+       }
+#endif
+
        /*
         * Rewrite the vdev configuration (which includes the uberblock)
         * to commit the transaction group.
@@ -6532,16 +6689,10 @@ spa_sync(spa_t *spa, uint64_t txg)
                                if (svdcount == SPA_DVAS_PER_BP)
                                        break;
                        }
-                       error = vdev_config_sync(svd, svdcount, txg, B_FALSE);
-                       if (error != 0)
-                               error = vdev_config_sync(svd, svdcount, txg,
-                                   B_TRUE);
+                       error = vdev_config_sync(svd, svdcount, txg);
                } else {
                        error = vdev_config_sync(rvd->vdev_child,
-                           rvd->vdev_children, txg, B_FALSE);
-                       if (error != 0)
-                               error = vdev_config_sync(rvd->vdev_child,
-                                   rvd->vdev_children, txg, B_TRUE);
+                           rvd->vdev_children, txg);
                }
 
                if (error == 0)
@@ -6579,6 +6730,10 @@ spa_sync(spa_t *spa, uint64_t txg)
 
        dsl_pool_sync_done(dp, txg);
 
+       mutex_enter(&spa->spa_alloc_lock);
+       VERIFY0(avl_numnodes(&spa->spa_alloc_tree));
+       mutex_exit(&spa->spa_alloc_lock);
+
        /*
         * Update usable space statistics.
         */
@@ -6761,7 +6916,8 @@ spa_has_active_shared_spare(spa_t *spa)
 }
 
 /*
- * Post a FM_EREPORT_ZFS_* event from sys/fm/fs/zfs.h.  The payload will be
+ * Post a zevent corresponding to the given sysevent.   The 'name' must be one
+ * of the event definitions in sys/sysevent/eventdefs.h.  The payload will be
  * filled in from the spa and (optionally) the vdev.  This doesn't do anything
  * in the userland libzpool, as we don't want consumers to misinterpret ztest
  * or zdb as real changes.
@@ -6769,9 +6925,7 @@ spa_has_active_shared_spare(spa_t *spa)
 void
 spa_event_notify(spa_t *spa, vdev_t *vd, const char *name)
 {
-#ifdef _KERNEL
-       zfs_ereport_post(name, spa, vd, NULL, 0, 0);
-#endif
+       zfs_post_sysevent(spa, vd, name);
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
@@ -6780,7 +6934,6 @@ EXPORT_SYMBOL(spa_open);
 EXPORT_SYMBOL(spa_open_rewind);
 EXPORT_SYMBOL(spa_get_stats);
 EXPORT_SYMBOL(spa_create);
-EXPORT_SYMBOL(spa_import_rootpool);
 EXPORT_SYMBOL(spa_import);
 EXPORT_SYMBOL(spa_tryimport);
 EXPORT_SYMBOL(spa_destroy);
index 19432e0a024ea46788564dd6cbc4f33e6d682174..a3ff24bd5fdcafc4221c84e28bc9f852f334ec5b 100644 (file)
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/spa.h>
+#include <sys/fm/fs/zfs.h>
 #include <sys/spa_impl.h>
 #include <sys/nvpair.h>
 #include <sys/uio.h>
@@ -128,7 +129,7 @@ spa_config_load(void)
                if (nvpair_type(nvpair) != DATA_TYPE_NVLIST)
                        continue;
 
-               VERIFY(nvpair_value_nvlist(nvpair, &child) == 0);
+               child = fnvpair_value_nvlist(nvpair);
 
                if (spa_lookup(nvpair_name(nvpair)) != NULL)
                        continue;
@@ -145,35 +146,30 @@ out:
        kobj_close_file(file);
 }
 
-static void
+static int
 spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
 {
        size_t buflen;
        char *buf;
        vnode_t *vp;
        int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
-       int error;
        char *temp;
+       int err;
 
        /*
         * If the nvlist is empty (NULL), then remove the old cachefile.
         */
        if (nvl == NULL) {
-               (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
-               return;
+               err = vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
+               return (err);
        }
 
        /*
         * Pack the configuration into a buffer.
         */
-       VERIFY(nvlist_size(nvl, &buflen, NV_ENCODE_XDR) == 0);
-
-       buf = vmem_alloc(buflen, KM_SLEEP);
+       buf = fnvlist_pack(nvl, &buflen);
        temp = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 
-       VERIFY(nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_XDR,
-           KM_SLEEP) == 0);
-
 #if defined(__linux__) && defined(_KERNEL)
        /*
         * Write the configuration to disk.  Due to the complexity involved
@@ -181,16 +177,16 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
         * and overwritten in place.  In the event of an error the file is
         * unlinked to make sure we always have a consistent view of the data.
         */
-       error = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0);
-       if (error == 0) {
-               error = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0,
+       err = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0);
+       if (err == 0) {
+               err = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0,
                    UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL);
-               if (error == 0)
-                       error = VOP_FSYNC(vp, FSYNC, kcred, NULL);
+               if (err == 0)
+                       err = VOP_FSYNC(vp, FSYNC, kcred, NULL);
 
                (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
 
-               if (error)
+               if (err)
                        (void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
        }
 #else
@@ -201,21 +197,23 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
         */
        (void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path);
 
-       error = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0);
-       if (error == 0) {
-               if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
-                   0, RLIM64_INFINITY, kcred, NULL) == 0 &&
-                   VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
-                       (void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
-               }
+       err = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0);
+       if (err == 0) {
+               err = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
+                   0, RLIM64_INFINITY, kcred, NULL);
+               if (err == 0)
+                       err = VOP_FSYNC(vp, FSYNC, kcred, NULL);
+               if (err == 0)
+                       err = vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
                (void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
        }
 
        (void) vn_remove(temp, UIO_SYSSPACE, RMFILE);
 #endif
 
-       vmem_free(buf, buflen);
+       fnvlist_pack_free(buf, buflen);
        kmem_free(temp, MAXPATHLEN);
+       return (err);
 }
 
 /*
@@ -233,6 +231,8 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
        spa_config_dirent_t *dp, *tdp;
        nvlist_t *nvl;
        char *pool_name;
+       boolean_t ccw_failure;
+       int error = 0;
 
        ASSERT(MUTEX_HELD(&spa_namespace_lock));
 
@@ -244,6 +244,7 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
         * cachefile is changed, the new one is pushed onto this list, allowing
         * us to update previous cachefiles that no longer contain this pool.
         */
+       ccw_failure = B_FALSE;
        for (dp = list_head(&target->spa_config_list); dp != NULL;
            dp = list_next(&target->spa_config_list, dp)) {
                spa_t *spa = NULL;
@@ -269,6 +270,7 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
                        mutex_enter(&spa->spa_props_lock);
                        tdp = list_head(&spa->spa_config_list);
                        if (spa->spa_config == NULL ||
+                           tdp == NULL ||
                            tdp->scd_path == NULL ||
                            strcmp(tdp->scd_path, dp->scd_path) != 0) {
                                mutex_exit(&spa->spa_props_lock);
@@ -276,24 +278,44 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
                        }
 
                        if (nvl == NULL)
-                               VERIFY(nvlist_alloc(&nvl, NV_UNIQUE_NAME,
-                                   KM_SLEEP) == 0);
+                               nvl = fnvlist_alloc();
 
-                       if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME) {
-                               VERIFY0(nvlist_lookup_string(spa->spa_config,
-                                       ZPOOL_CONFIG_POOL_NAME, &pool_name));
-                       else
+                       if (spa->spa_import_flags & ZFS_IMPORT_TEMP_NAME)
+                               pool_name = fnvlist_lookup_string(
+                                   spa->spa_config, ZPOOL_CONFIG_POOL_NAME);
+                       else
                                pool_name = spa_name(spa);
 
-                       VERIFY(nvlist_add_nvlist(nvl, pool_name,
-                           spa->spa_config) == 0);
+                       fnvlist_add_nvlist(nvl, pool_name, spa->spa_config);
                        mutex_exit(&spa->spa_props_lock);
                }
 
-               spa_config_write(dp, nvl);
+               error = spa_config_write(dp, nvl);
+               if (error != 0)
+                       ccw_failure = B_TRUE;
                nvlist_free(nvl);
        }
 
+       if (ccw_failure) {
+               /*
+                * Keep trying so that configuration data is
+                * written if/when any temporary filesystem
+                * resource issues are resolved.
+                */
+               if (target->spa_ccw_fail_time == 0) {
+                       zfs_ereport_post(FM_EREPORT_ZFS_CONFIG_CACHE_WRITE,
+                           target, NULL, NULL, 0, 0);
+               }
+               target->spa_ccw_fail_time = gethrtime();
+               spa_async_request(target, SPA_ASYNC_CONFIG_UPDATE);
+       } else {
+               /*
+                * Do not rate limit future attempts to update
+                * the config cache.
+                */
+               target->spa_ccw_fail_time = 0;
+       }
+
        /*
         * Remove any config entries older than the current one.
         */
@@ -308,7 +330,7 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
        spa_config_generation++;
 
        if (postsysevent)
-               spa_event_notify(target, NULL, FM_EREPORT_ZFS_CONFIG_SYNC);
+               spa_event_notify(target, NULL, ESC_ZFS_CONFIG_SYNC);
 }
 
 /*
@@ -326,15 +348,15 @@ spa_all_configs(uint64_t *generation)
        if (*generation == spa_config_generation)
                return (NULL);
 
-       VERIFY(nvlist_alloc(&pools, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+       pools = fnvlist_alloc();
 
        mutex_enter(&spa_namespace_lock);
        while ((spa = spa_next(spa)) != NULL) {
                if (INGLOBALZONE(curproc) ||
                    zone_dataset_visible(spa_name(spa), NULL)) {
                        mutex_enter(&spa->spa_props_lock);
-                       VERIFY(nvlist_add_nvlist(pools, spa_name(spa),
-                           spa->spa_config) == 0);
+                       fnvlist_add_nvlist(pools, spa_name(spa),
+                           spa->spa_config);
                        mutex_exit(&spa->spa_props_lock);
                }
        }
@@ -348,8 +370,7 @@ void
 spa_config_set(spa_t *spa, nvlist_t *config)
 {
        mutex_enter(&spa->spa_props_lock);
-       if (spa->spa_config != NULL)
-               nvlist_free(spa->spa_config);
+       nvlist_free(spa->spa_config);
        spa->spa_config = config;
        mutex_exit(&spa->spa_props_lock);
 }
@@ -369,6 +390,7 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
        boolean_t locked = B_FALSE;
        uint64_t split_guid;
        char *pool_name;
+       int config_gen_flags = 0;
 
        if (vd == NULL) {
                vd = rvd;
@@ -401,23 +423,17 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
        } else
                pool_name = spa_name(spa);
 
-       VERIFY(nvlist_alloc(&config, NV_UNIQUE_NAME, KM_SLEEP) == 0);
-
-       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_VERSION,
-           spa_version(spa)) == 0);
-       VERIFY(nvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME,
-           pool_name) == 0);
-       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE,
-           spa_state(spa)) == 0);
-       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG,
-           txg) == 0);
-       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID,
-           spa_guid(spa)) == 0);
-       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_ERRATA,
-           spa->spa_errata) == 0);
-       VERIFY(spa->spa_comment == NULL || nvlist_add_string(config,
-           ZPOOL_CONFIG_COMMENT, spa->spa_comment) == 0);
+       config = fnvlist_alloc();
 
+       fnvlist_add_uint64(config, ZPOOL_CONFIG_VERSION, spa_version(spa));
+       fnvlist_add_string(config, ZPOOL_CONFIG_POOL_NAME, spa_name(spa));
+       fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_STATE, spa_state(spa));
+       fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_TXG, txg);
+       fnvlist_add_uint64(config, ZPOOL_CONFIG_POOL_GUID, spa_guid(spa));
+       fnvlist_add_uint64(config, ZPOOL_CONFIG_ERRATA, spa->spa_errata);
+       if (spa->spa_comment != NULL)
+               fnvlist_add_string(config, ZPOOL_CONFIG_COMMENT,
+                   spa->spa_comment);
 
 #ifdef _KERNEL
        hostid = zone_get_hostid(NULL);
@@ -428,24 +444,21 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
         */
        (void) ddi_strtoul(hw_serial, NULL, 10, &hostid);
 #endif /* _KERNEL */
-       if (hostid != 0) {
-               VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID,
-                   hostid) == 0);
-       }
-       VERIFY0(nvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME,
-           utsname()->nodename));
+       if (hostid != 0)
+               fnvlist_add_uint64(config, ZPOOL_CONFIG_HOSTID, hostid);
+       fnvlist_add_string(config, ZPOOL_CONFIG_HOSTNAME, utsname()->nodename);
 
        if (vd != rvd) {
-               VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_TOP_GUID,
-                   vd->vdev_top->vdev_guid) == 0);
-               VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_GUID,
-                   vd->vdev_guid) == 0);
+               fnvlist_add_uint64(config, ZPOOL_CONFIG_TOP_GUID,
+                   vd->vdev_top->vdev_guid);
+               fnvlist_add_uint64(config, ZPOOL_CONFIG_GUID,
+                   vd->vdev_guid);
                if (vd->vdev_isspare)
-                       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_SPARE,
-                           1ULL) == 0);
+                       fnvlist_add_uint64(config,
+                           ZPOOL_CONFIG_IS_SPARE, 1ULL);
                if (vd->vdev_islog)
-                       VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_IS_LOG,
-                           1ULL) == 0);
+                       fnvlist_add_uint64(config,
+                           ZPOOL_CONFIG_IS_LOG, 1ULL);
                vd = vd->vdev_top;              /* label contains top config */
        } else {
                /*
@@ -453,8 +466,12 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
                 * in the mos config, and not in the vdev labels
                 */
                if (spa->spa_config_splitting != NULL)
-                       VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_SPLIT,
-                           spa->spa_config_splitting) == 0);
+                       fnvlist_add_nvlist(config, ZPOOL_CONFIG_SPLIT,
+                           spa->spa_config_splitting);
+
+               fnvlist_add_boolean(config, ZPOOL_CONFIG_HAS_PER_VDEV_ZAPS);
+
+               config_gen_flags |= VDEV_CONFIG_MOS;
        }
 
        /*
@@ -469,19 +486,18 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
        if (spa->spa_config_splitting != NULL &&
            nvlist_lookup_uint64(spa->spa_config_splitting,
            ZPOOL_CONFIG_SPLIT_GUID, &split_guid) == 0) {
-               VERIFY(nvlist_add_uint64(config, ZPOOL_CONFIG_SPLIT_GUID,
-                   split_guid) == 0);
+               fnvlist_add_uint64(config, ZPOOL_CONFIG_SPLIT_GUID, split_guid);
        }
 
-       nvroot = vdev_config_generate(spa, vd, getstats, 0);
-       VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot) == 0);
+       nvroot = vdev_config_generate(spa, vd, getstats, config_gen_flags);
+       fnvlist_add_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, nvroot);
        nvlist_free(nvroot);
 
        /*
         * Store what's necessary for reading the MOS in the label.
         */
-       VERIFY(nvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURES_FOR_READ,
-           spa->spa_label_features) == 0);
+       fnvlist_add_nvlist(config, ZPOOL_CONFIG_FEATURES_FOR_READ,
+           spa->spa_label_features);
 
        if (getstats && spa_load_state(spa) == SPA_LOAD_NONE) {
                ddt_histogram_t *ddh;
@@ -490,23 +506,23 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats)
 
                ddh = kmem_zalloc(sizeof (ddt_histogram_t), KM_SLEEP);
                ddt_get_dedup_histogram(spa, ddh);
-               VERIFY(nvlist_add_uint64_array(config,
+               fnvlist_add_uint64_array(config,
                    ZPOOL_CONFIG_DDT_HISTOGRAM,
-                   (uint64_t *)ddh, sizeof (*ddh) / sizeof (uint64_t)) == 0);
+                   (uint64_t *)ddh, sizeof (*ddh) / sizeof (uint64_t));
                kmem_free(ddh, sizeof (ddt_histogram_t));
 
                ddo = kmem_zalloc(sizeof (ddt_object_t), KM_SLEEP);
                ddt_get_dedup_object_stats(spa, ddo);
-               VERIFY(nvlist_add_uint64_array(config,
+               fnvlist_add_uint64_array(config,
                    ZPOOL_CONFIG_DDT_OBJ_STATS,
-                   (uint64_t *)ddo, sizeof (*ddo) / sizeof (uint64_t)) == 0);
+                   (uint64_t *)ddo, sizeof (*ddo) / sizeof (uint64_t));
                kmem_free(ddo, sizeof (ddt_object_t));
 
                dds = kmem_zalloc(sizeof (ddt_stat_t), KM_SLEEP);
                ddt_get_dedup_stats(spa, dds);
-               VERIFY(nvlist_add_uint64_array(config,
+               fnvlist_add_uint64_array(config,
                    ZPOOL_CONFIG_DDT_STATS,
-                   (uint64_t *)dds, sizeof (*dds) / sizeof (uint64_t)) == 0);
+                   (uint64_t *)dds, sizeof (*dds) / sizeof (uint64_t));
                kmem_free(dds, sizeof (ddt_stat_t));
        }
 
index 01aa4641e63fe50483fc949973e5ccbf3d2d785f..4ae74c28401a7453fcb8209d8b16eaee5aff4ffe 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/spa.h>
@@ -46,7 +46,7 @@
  * The history log is stored as a dmu object containing
  * <packed record length, record nvlist> tuples.
  *
- * Where "record nvlist" is a nvlist containing uint64_ts and strings, and
+ * Where "record nvlist" is an nvlist containing uint64_ts and strings, and
  * "packed record length" is the packed length of the "record nvlist" stored
  * as a little endian uint64_t.
  *
@@ -493,7 +493,7 @@ spa_history_log_internal_ds(dsl_dataset_t *ds, const char *operation,
     dmu_tx_t *tx, const char *fmt, ...)
 {
        va_list adx;
-       char namebuf[MAXNAMELEN];
+       char namebuf[ZFS_MAX_DATASET_NAME_LEN];
        nvlist_t *nvl = fnvlist_alloc();
 
        ASSERT(tx != NULL);
@@ -512,7 +512,7 @@ spa_history_log_internal_dd(dsl_dir_t *dd, const char *operation,
     dmu_tx_t *tx, const char *fmt, ...)
 {
        va_list adx;
-       char namebuf[MAXNAMELEN];
+       char namebuf[ZFS_MAX_DATASET_NAME_LEN];
        nvlist_t *nvl = fnvlist_alloc();
 
        ASSERT(tx != NULL);
index 409dce12121276ce97e08d0a3477112e4957c1a5..6ec05214ef134efa1cb9c03799f85c21af7caf9d 100644 (file)
@@ -21,8 +21,9 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -36,6 +37,7 @@
 #include <sys/zil.h>
 #include <sys/vdev_impl.h>
 #include <sys/vdev_file.h>
+#include <sys/vdev_raidz.h>
 #include <sys/metaslab.h>
 #include <sys/uberblock_impl.h>
 #include <sys/txg.h>
@@ -52,7 +54,7 @@
 #include <sys/ddt.h>
 #include <sys/kstat.h>
 #include "zfs_prop.h"
-#include "zfeature_common.h"
+#include <sys/zfeature.h>
 
 /*
  * SPA locking
@@ -385,14 +387,16 @@ spa_config_tryenter(spa_t *spa, int locks, void *tag, krw_t rw)
                if (rw == RW_READER) {
                        if (scl->scl_writer || scl->scl_write_wanted) {
                                mutex_exit(&scl->scl_lock);
-                               spa_config_exit(spa, locks ^ (1 << i), tag);
+                               spa_config_exit(spa, locks & ((1 << i) - 1),
+                                   tag);
                                return (0);
                        }
                } else {
                        ASSERT(scl->scl_writer != curthread);
                        if (!refcount_is_zero(&scl->scl_count)) {
                                mutex_exit(&scl->scl_lock);
-                               spa_config_exit(spa, locks ^ (1 << i), tag);
+                               spa_config_exit(spa, locks & ((1 << i) - 1),
+                                   tag);
                                return (0);
                        }
                        scl->scl_writer = curthread;
@@ -527,7 +531,7 @@ spa_deadman(void *arg)
                vdev_deadman(spa->spa_root_vdev);
 
        spa->spa_deadman_tqid = taskq_dispatch_delay(system_taskq,
-           spa_deadman, spa, KM_SLEEP, ddi_get_lbolt() +
+           spa_deadman, spa, TQ_SLEEP, ddi_get_lbolt() +
            NSEC_TO_TICK(spa->spa_deadman_synctime));
 }
 
@@ -555,10 +559,12 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
        mutex_init(&spa->spa_history_lock, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&spa->spa_proc_lock, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&spa->spa_props_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&spa->spa_cksum_tmpls_lock, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&spa->spa_scrub_lock, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&spa->spa_suspend_lock, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&spa->spa_vdev_top_lock, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&spa->spa_feat_stats_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&spa->spa_alloc_lock, NULL, MUTEX_DEFAULT, NULL);
 
        cv_init(&spa->spa_async_cv, NULL, CV_DEFAULT, NULL);
        cv_init(&spa->spa_evicting_os_cv, NULL, CV_DEFAULT, NULL);
@@ -591,6 +597,9 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
        if (altroot)
                spa->spa_root = spa_strdup(altroot);
 
+       avl_create(&spa->spa_alloc_tree, zio_timestamp_compare,
+           sizeof (zio_t), offsetof(zio_t, io_alloc_node));
+
        /*
         * Every pool starts with the default cachefile
         */
@@ -668,6 +677,7 @@ spa_remove(spa_t *spa)
                kmem_free(dp, sizeof (spa_config_dirent_t));
        }
 
+       avl_destroy(&spa->spa_alloc_tree);
        list_destroy(&spa->spa_config_list);
 
        nvlist_free(spa->spa_label_features);
@@ -683,12 +693,15 @@ spa_remove(spa_t *spa)
        for (t = 0; t < TXG_SIZE; t++)
                bplist_destroy(&spa->spa_free_bplist[t]);
 
+       zio_checksum_templates_free(spa);
+
        cv_destroy(&spa->spa_async_cv);
        cv_destroy(&spa->spa_evicting_os_cv);
        cv_destroy(&spa->spa_proc_cv);
        cv_destroy(&spa->spa_scrub_io_cv);
        cv_destroy(&spa->spa_suspend_cv);
 
+       mutex_destroy(&spa->spa_alloc_lock);
        mutex_destroy(&spa->spa_async_lock);
        mutex_destroy(&spa->spa_errlist_lock);
        mutex_destroy(&spa->spa_errlog_lock);
@@ -696,6 +709,7 @@ spa_remove(spa_t *spa)
        mutex_destroy(&spa->spa_history_lock);
        mutex_destroy(&spa->spa_proc_lock);
        mutex_destroy(&spa->spa_props_lock);
+       mutex_destroy(&spa->spa_cksum_tmpls_lock);
        mutex_destroy(&spa->spa_scrub_lock);
        mutex_destroy(&spa->spa_suspend_lock);
        mutex_destroy(&spa->spa_vdev_top_lock);
@@ -794,18 +808,13 @@ typedef struct spa_aux {
        int             aux_count;
 } spa_aux_t;
 
-static int
+static inline int
 spa_aux_compare(const void *a, const void *b)
 {
-       const spa_aux_t *sa = a;
-       const spa_aux_t *sb = b;
+       const spa_aux_t *sa = (const spa_aux_t *)a;
+       const spa_aux_t *sb = (const spa_aux_t *)b;
 
-       if (sa->aux_guid < sb->aux_guid)
-               return (-1);
-       else if (sa->aux_guid > sb->aux_guid)
-               return (1);
-       else
-               return (0);
+       return (AVL_CMP(sa->aux_guid, sb->aux_guid));
 }
 
 void
@@ -1771,11 +1780,8 @@ spa_name_compare(const void *a1, const void *a2)
        int s;
 
        s = strcmp(s1->spa_name, s2->spa_name);
-       if (s > 0)
-               return (1);
-       if (s < 0)
-               return (-1);
-       return (0);
+
+       return (AVL_ISIGN(s));
 }
 
 void
@@ -1829,6 +1835,7 @@ spa_init(int mode)
        dmu_init();
        zil_init();
        vdev_cache_stat_init();
+       vdev_raidz_math_init();
        zfs_prop_init();
        zpool_prop_init();
        zpool_feature_init();
@@ -1844,6 +1851,7 @@ spa_fini(void)
        spa_evict_all();
 
        vdev_cache_stat_fini();
+       vdev_raidz_math_fini();
        zil_fini();
        dmu_fini();
        zio_fini();
@@ -1995,6 +2003,15 @@ spa_maxblocksize(spa_t *spa)
                return (SPA_OLD_MAXBLOCKSIZE);
 }
 
+int
+spa_maxdnodesize(spa_t *spa)
+{
+       if (spa_feature_is_enabled(spa, SPA_FEATURE_LARGE_DNODE))
+               return (DNODE_MAX_SIZE);
+       else
+               return (DNODE_MIN_SIZE);
+}
+
 #if defined(_KERNEL) && defined(HAVE_SPL)
 /* Namespace manipulation */
 EXPORT_SYMBOL(spa_lookup);
@@ -2051,6 +2068,7 @@ EXPORT_SYMBOL(spa_bootfs);
 EXPORT_SYMBOL(spa_delegation);
 EXPORT_SYMBOL(spa_meta_objset);
 EXPORT_SYMBOL(spa_maxblocksize);
+EXPORT_SYMBOL(spa_maxdnodesize);
 
 /* Miscellaneous support routines */
 EXPORT_SYMBOL(spa_rename);
index 2b8559b5d276b0c53f1ef61271bfceb66afeb8d2..c3d1c3b958dc96f2c83974fe77983c7a4936d73f 100644 (file)
@@ -600,7 +600,7 @@ spa_tx_assign_add_nsecs(spa_t *spa, uint64_t nsecs)
        spa_stats_history_t *ssh = &spa->spa_stats.tx_assign_histogram;
        uint64_t idx = 0;
 
-       while (((1 << idx) < nsecs) && (idx < ssh->size - 1))
+       while (((1ULL << idx) < nsecs) && (idx < ssh->size - 1))
                idx++;
 
        atomic_inc_64(&((kstat_named_t *)ssh->private)[idx].value.ui64);
index b3aa469bf45b665fec84c06db899a4784082c705..126fd6bee0b9459e82385d94c4eebe97eb4750d1 100644 (file)
@@ -76,8 +76,8 @@ space_map_load(space_map_t *sm, range_tree_t *rt, maptype_t maptype)
 
        mutex_exit(sm->sm_lock);
        if (end > bufsize) {
-               dmu_prefetch(sm->sm_os, space_map_object(sm), bufsize,
-                   end - bufsize);
+               dmu_prefetch(sm->sm_os, space_map_object(sm), 0, bufsize,
+                   end - bufsize, ZIO_PRIORITY_SYNC_READ);
        }
        mutex_enter(sm->sm_lock);
 
index a508092c530e0055023bf9ede71453e46e661bd6..efbf95099eab22d38c4a5707e99dba37dc1ba5b1 100644 (file)
 static int
 space_reftree_compare(const void *x1, const void *x2)
 {
-       const space_ref_t *sr1 = x1;
-       const space_ref_t *sr2 = x2;
+       const space_ref_t *sr1 = (const space_ref_t *)x1;
+       const space_ref_t *sr2 = (const space_ref_t *)x2;
 
-       if (sr1->sr_offset < sr2->sr_offset)
-               return (-1);
-       if (sr1->sr_offset > sr2->sr_offset)
-               return (1);
+       int cmp = AVL_CMP(sr1->sr_offset, sr2->sr_offset);
+       if (likely(cmp))
+               return (cmp);
 
-       if (sr1 < sr2)
-               return (-1);
-       if (sr1 > sr2)
-               return (1);
-
-       return (0);
+       return (AVL_PCMP(sr1, sr2));
 }
 
 void
index 0c9990e8547bd39de16304eb19d4bf101efef0ad..e4ebf31b3fbefdae7a385e491c26e258b7ff4368 100644 (file)
@@ -47,4 +47,5 @@
 #include <sys/trace_multilist.h>
 #include <sys/trace_txg.h>
 #include <sys/trace_zil.h>
+#include <sys/trace_zio.h>
 #include <sys/trace_zrlock.h>
index 1d5ee97b1368d9c5fe56274abed4cae4b2c74002..9dda58c283df40b7d35df97777ad9e17f51f5430 100644 (file)
@@ -128,7 +128,7 @@ txg_init(dsl_pool_t *dp, uint64_t txg)
                int i;
 
                mutex_init(&tx->tx_cpu[c].tc_lock, NULL, MUTEX_DEFAULT, NULL);
-               mutex_init(&tx->tx_cpu[c].tc_open_lock, NULL, MUTEX_DEFAULT,
+               mutex_init(&tx->tx_cpu[c].tc_open_lock, NULL, MUTEX_NOLOCKDEP,
                    NULL);
                for (i = 0; i < TXG_SIZE; i++) {
                        cv_init(&tx->tx_cpu[c].tc_cv[i], NULL, CV_DEFAULT,
@@ -212,7 +212,7 @@ txg_sync_start(dsl_pool_t *dp)
         * 32-bit x86.  This is due in part to nested pools and
         * scrub_visitbp() recursion.
         */
-       tx->tx_sync_thread = thread_create(NULL, 32<<10, txg_sync_thread,
+       tx->tx_sync_thread = thread_create(NULL, 0, txg_sync_thread,
            dp, 0, &p0, TS_RUN, defclsyspri);
 
        mutex_exit(&tx->tx_sync_lock);
@@ -365,6 +365,7 @@ static void
 txg_quiesce(dsl_pool_t *dp, uint64_t txg)
 {
        tx_state_t *tx = &dp->dp_tx;
+       uint64_t tx_open_time;
        int g = txg & TXG_MASK;
        int c;
 
@@ -376,10 +377,7 @@ txg_quiesce(dsl_pool_t *dp, uint64_t txg)
 
        ASSERT(txg == tx->tx_open_txg);
        tx->tx_open_txg++;
-       tx->tx_open_time = gethrtime();
-
-       spa_txg_history_set(dp->dp_spa, txg, TXG_STATE_OPEN, tx->tx_open_time);
-       spa_txg_history_add(dp->dp_spa, tx->tx_open_txg, tx->tx_open_time);
+       tx->tx_open_time = tx_open_time = gethrtime();
 
        DTRACE_PROBE2(txg__quiescing, dsl_pool_t *, dp, uint64_t, txg);
        DTRACE_PROBE2(txg__opened, dsl_pool_t *, dp, uint64_t, tx->tx_open_txg);
@@ -391,6 +389,9 @@ txg_quiesce(dsl_pool_t *dp, uint64_t txg)
        for (c = 0; c < max_ncpus; c++)
                mutex_exit(&tx->tx_cpu[c].tc_open_lock);
 
+       spa_txg_history_set(dp->dp_spa, txg, TXG_STATE_OPEN, tx_open_time);
+       spa_txg_history_add(dp->dp_spa, txg + 1, tx_open_time);
+
        /*
         * Quiesce the transaction group by waiting for everyone to txg_exit().
         */
index 8c1d2e2f985643c2f8fcfe76dd9f8592c90e6e2a..5cdd025f49bc621e7c0b9645f74e93b9334ef1cf 100644 (file)
@@ -42,14 +42,10 @@ typedef struct unique {
 static int
 unique_compare(const void *a, const void *b)
 {
-       const unique_t *una = a;
-       const unique_t *unb = b;
-
-       if (una->un_value < unb->un_value)
-               return (-1);
-       if (una->un_value > unb->un_value)
-               return (+1);
-       return (0);
+       const unique_t *una = (const unique_t *)a;
+       const unique_t *unb = (const unique_t *)b;
+
+       return (AVL_CMP(una->un_value, unb->un_value));
 }
 
 void
index 7d814a63b41f684863992e75bdbc63707380caf1..e3a9da2d5d7b8a585dcd9f5babc3cd801dea6dbc 100644 (file)
@@ -44,6 +44,7 @@
 #include <sys/zil.h>
 #include <sys/dsl_scan.h>
 #include <sys/zvol.h>
+#include <sys/zfs_ratelimit.h>
 
 /*
  * When a vdev is added, it will be divided into approximately (but no
@@ -346,11 +347,21 @@ vdev_alloc_common(spa_t *spa, uint_t id, uint64_t guid, vdev_ops_t *ops)
        vd->vdev_state = VDEV_STATE_CLOSED;
        vd->vdev_ishole = (ops == &vdev_hole_ops);
 
+       /*
+        * Initialize rate limit structs for events.  We rate limit ZIO delay
+        * and checksum events so that we don't overwhelm ZED with thousands
+        * of events when a disk is acting up.
+        */
+       zfs_ratelimit_init(&vd->vdev_delay_rl, DELAYS_PER_SECOND, 1);
+       zfs_ratelimit_init(&vd->vdev_checksum_rl, CHECKSUMS_PER_SECOND, 1);
+
        list_link_init(&vd->vdev_config_dirty_node);
        list_link_init(&vd->vdev_state_dirty_node);
-       mutex_init(&vd->vdev_dtl_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&vd->vdev_dtl_lock, NULL, MUTEX_NOLOCKDEP, NULL);
        mutex_init(&vd->vdev_stat_lock, NULL, MUTEX_DEFAULT, NULL);
        mutex_init(&vd->vdev_probe_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&vd->vdev_queue_lock, NULL, MUTEX_DEFAULT, NULL);
+
        for (t = 0; t < DTL_TYPES; t++) {
                vd->vdev_dtl[t] = range_tree_create(NULL, NULL,
                    &vd->vdev_dtl_lock);
@@ -477,6 +488,11 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
        if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PHYS_PATH,
            &vd->vdev_physpath) == 0)
                vd->vdev_physpath = spa_strdup(vd->vdev_physpath);
+
+       if (nvlist_lookup_string(nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
+           &vd->vdev_enc_sysfs_path) == 0)
+               vd->vdev_enc_sysfs_path = spa_strdup(vd->vdev_enc_sysfs_path);
+
        if (nvlist_lookup_string(nv, ZPOOL_CONFIG_FRU, &vd->vdev_fru) == 0)
                vd->vdev_fru = spa_strdup(vd->vdev_fru);
 
@@ -519,6 +535,10 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
                    &vd->vdev_asize);
                (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_REMOVING,
                    &vd->vdev_removing);
+               (void) nvlist_lookup_uint64(nv, ZPOOL_CONFIG_VDEV_TOP_ZAP,
+                   &vd->vdev_top_zap);
+       } else {
+               ASSERT0(vd->vdev_top_zap);
        }
 
        if (parent && !parent->vdev_parent && alloctype != VDEV_ALLOC_ATTACH) {
@@ -530,9 +550,18 @@ vdev_alloc(spa_t *spa, vdev_t **vdp, nvlist_t *nv, vdev_t *parent, uint_t id,
                    spa_log_class(spa) : spa_normal_class(spa), vd);
        }
 
+       if (vd->vdev_ops->vdev_op_leaf &&
+           (alloctype == VDEV_ALLOC_LOAD || alloctype == VDEV_ALLOC_SPLIT)) {
+               (void) nvlist_lookup_uint64(nv,
+                   ZPOOL_CONFIG_VDEV_LEAF_ZAP, &vd->vdev_leaf_zap);
+       } else {
+               ASSERT0(vd->vdev_leaf_zap);
+       }
+
        /*
         * If we're a leaf vdev, try to load the DTL object and other state.
         */
+
        if (vd->vdev_ops->vdev_op_leaf &&
            (alloctype == VDEV_ALLOC_LOAD || alloctype == VDEV_ALLOC_L2CACHE ||
            alloctype == VDEV_ALLOC_ROOTPOOL)) {
@@ -649,6 +678,10 @@ vdev_free(vdev_t *vd)
                spa_strfree(vd->vdev_devid);
        if (vd->vdev_physpath)
                spa_strfree(vd->vdev_physpath);
+
+       if (vd->vdev_enc_sysfs_path)
+               spa_strfree(vd->vdev_enc_sysfs_path);
+
        if (vd->vdev_fru)
                spa_strfree(vd->vdev_fru);
 
@@ -668,6 +701,7 @@ vdev_free(vdev_t *vd)
        }
        mutex_exit(&vd->vdev_dtl_lock);
 
+       mutex_destroy(&vd->vdev_queue_lock);
        mutex_destroy(&vd->vdev_dtl_lock);
        mutex_destroy(&vd->vdev_stat_lock);
        mutex_destroy(&vd->vdev_probe_lock);
@@ -691,13 +725,16 @@ vdev_top_transfer(vdev_t *svd, vdev_t *tvd)
 
        ASSERT(tvd == tvd->vdev_top);
 
+       tvd->vdev_pending_fastwrite = svd->vdev_pending_fastwrite;
        tvd->vdev_ms_array = svd->vdev_ms_array;
        tvd->vdev_ms_shift = svd->vdev_ms_shift;
        tvd->vdev_ms_count = svd->vdev_ms_count;
+       tvd->vdev_top_zap = svd->vdev_top_zap;
 
        svd->vdev_ms_array = 0;
        svd->vdev_ms_shift = 0;
        svd->vdev_ms_count = 0;
+       svd->vdev_top_zap = 0;
 
        if (tvd->vdev_mg)
                ASSERT3P(tvd->vdev_mg, ==, svd->vdev_mg);
@@ -974,6 +1011,7 @@ vdev_probe_done(zio_t *zio)
                zio_buf_free(zio->io_data, zio->io_size);
        } else if (zio->io_type == ZIO_TYPE_NULL) {
                zio_t *pio;
+               zio_link_t *zl;
 
                vd->vdev_cant_read |= !vps->vps_readable;
                vd->vdev_cant_write |= !vps->vps_writeable;
@@ -993,7 +1031,8 @@ vdev_probe_done(zio_t *zio)
                vd->vdev_probe_zio = NULL;
                mutex_exit(&vd->vdev_probe_lock);
 
-               while ((pio = zio_walk_parents(zio)) != NULL)
+               zl = NULL;
+               while ((pio = zio_walk_parents(zio, &zl)) != NULL)
                        if (!vdev_accessible(vd, pio))
                                pio->io_error = SET_ERROR(ENXIO);
 
@@ -1108,7 +1147,6 @@ vdev_open_child(void *arg)
        vd->vdev_open_thread = curthread;
        vd->vdev_open_error = vdev_open(vd);
        vd->vdev_open_thread = NULL;
-       vd->vdev_parent->vdev_nonrot &= vd->vdev_nonrot;
 }
 
 static boolean_t
@@ -1135,29 +1173,30 @@ vdev_open_children(vdev_t *vd)
        int children = vd->vdev_children;
        int c;
 
-       vd->vdev_nonrot = B_TRUE;
-
        /*
         * in order to handle pools on top of zvols, do the opens
         * in a single thread so that the same thread holds the
         * spa_namespace_lock
         */
        if (vdev_uses_zvols(vd)) {
-               for (c = 0; c < children; c++) {
+retry_sync:
+               for (c = 0; c < children; c++)
                        vd->vdev_child[c]->vdev_open_error =
                            vdev_open(vd->vdev_child[c]);
-                       vd->vdev_nonrot &= vd->vdev_child[c]->vdev_nonrot;
-               }
-               return;
-       }
-       tq = taskq_create("vdev_open", children, minclsyspri,
-           children, children, TASKQ_PREPOPULATE);
+       } else {
+               tq = taskq_create("vdev_open", children, minclsyspri,
+                   children, children, TASKQ_PREPOPULATE);
+               if (tq == NULL)
+                       goto retry_sync;
 
-       for (c = 0; c < children; c++)
-               VERIFY(taskq_dispatch(tq, vdev_open_child, vd->vdev_child[c],
-                   TQ_SLEEP) != 0);
+               for (c = 0; c < children; c++)
+                       VERIFY(taskq_dispatch(tq, vdev_open_child,
+                           vd->vdev_child[c], TQ_SLEEP) != 0);
+
+               taskq_destroy(tq);
+       }
 
-       taskq_destroy(tq);
+       vd->vdev_nonrot = B_TRUE;
 
        for (c = 0; c < children; c++)
                vd->vdev_nonrot &= vd->vdev_child[c]->vdev_nonrot;
@@ -1979,6 +2018,51 @@ vdev_dtl_load(vdev_t *vd)
        return (error);
 }
 
+void
+vdev_destroy_unlink_zap(vdev_t *vd, uint64_t zapobj, dmu_tx_t *tx)
+{
+       spa_t *spa = vd->vdev_spa;
+
+       VERIFY0(zap_destroy(spa->spa_meta_objset, zapobj, tx));
+       VERIFY0(zap_remove_int(spa->spa_meta_objset, spa->spa_all_vdev_zaps,
+           zapobj, tx));
+}
+
+uint64_t
+vdev_create_link_zap(vdev_t *vd, dmu_tx_t *tx)
+{
+       spa_t *spa = vd->vdev_spa;
+       uint64_t zap = zap_create(spa->spa_meta_objset, DMU_OTN_ZAP_METADATA,
+           DMU_OT_NONE, 0, tx);
+
+       ASSERT(zap != 0);
+       VERIFY0(zap_add_int(spa->spa_meta_objset, spa->spa_all_vdev_zaps,
+           zap, tx));
+
+       return (zap);
+}
+
+void
+vdev_construct_zaps(vdev_t *vd, dmu_tx_t *tx)
+{
+       uint64_t i;
+
+       if (vd->vdev_ops != &vdev_hole_ops &&
+           vd->vdev_ops != &vdev_missing_ops &&
+           vd->vdev_ops != &vdev_root_ops &&
+           !vd->vdev_top->vdev_removing) {
+               if (vd->vdev_ops->vdev_op_leaf && vd->vdev_leaf_zap == 0) {
+                       vd->vdev_leaf_zap = vdev_create_link_zap(vd, tx);
+               }
+               if (vd == vd->vdev_top && vd->vdev_top_zap == 0) {
+                       vd->vdev_top_zap = vdev_create_link_zap(vd, tx);
+               }
+       }
+       for (i = 0; i < vd->vdev_children; i++) {
+               vdev_construct_zaps(vd->vdev_child[i], tx);
+       }
+}
+
 void
 vdev_dtl_sync(vdev_t *vd, uint64_t txg)
 {
@@ -2001,6 +2085,18 @@ vdev_dtl_sync(vdev_t *vd, uint64_t txg)
                space_map_close(vd->vdev_dtl_sm);
                vd->vdev_dtl_sm = NULL;
                mutex_exit(&vd->vdev_dtl_lock);
+
+               /*
+                * We only destroy the leaf ZAP for detached leaves or for
+                * removed log devices. Removed data devices handle leaf ZAP
+                * cleanup later, once cancellation is no longer possible.
+                */
+               if (vd->vdev_leaf_zap != 0 && (vd->vdev_detached ||
+                   vd->vdev_top->vdev_islog)) {
+                       vdev_destroy_unlink_zap(vd, vd->vdev_leaf_zap, tx);
+                       vd->vdev_leaf_zap = 0;
+               }
+
                dmu_tx_commit(tx);
                return;
        }
@@ -2147,7 +2243,6 @@ vdev_load(vdev_t *vd)
            vdev_metaslab_init(vd, 0) != 0))
                vdev_set_state(vd, B_FALSE, VDEV_STATE_CANT_OPEN,
                    VDEV_AUX_CORRUPT_DATA);
-
        /*
         * If this is a leaf vdev, load its DTL.
         */
@@ -2207,6 +2302,8 @@ vdev_remove(vdev_t *vd, uint64_t txg)
        int m, i;
 
        tx = dmu_tx_create_assigned(spa_get_dsl(spa), txg);
+       ASSERT(vd == vd->vdev_top);
+       ASSERT3U(txg, ==, spa_syncing_txg(spa));
 
        if (vd->vdev_ms != NULL) {
                metaslab_group_t *mg = vd->vdev_mg;
@@ -2248,6 +2345,11 @@ vdev_remove(vdev_t *vd, uint64_t txg)
                (void) dmu_object_free(mos, vd->vdev_ms_array, tx);
                vd->vdev_ms_array = 0;
        }
+
+       if (vd->vdev_islog && vd->vdev_top_zap != 0) {
+               vdev_destroy_unlink_zap(vd, vd->vdev_top_zap, tx);
+               vd->vdev_top_zap = 0;
+       }
        dmu_tx_commit(tx);
 }
 
@@ -2408,6 +2510,7 @@ int
 vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate)
 {
        vdev_t *vd, *tvd, *pvd, *rvd = spa->spa_root_vdev;
+       boolean_t postevent = B_FALSE;
 
        spa_vdev_state_enter(spa, SCL_NONE);
 
@@ -2417,6 +2520,10 @@ vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate)
        if (!vd->vdev_ops->vdev_op_leaf)
                return (spa_vdev_state_exit(spa, NULL, ENOTSUP));
 
+       postevent =
+           (vd->vdev_offline == B_TRUE || vd->vdev_tmpoffline == B_TRUE) ?
+           B_TRUE : B_FALSE;
+
        tvd = vd->vdev_top;
        vd->vdev_offline = B_FALSE;
        vd->vdev_tmpoffline = B_FALSE;
@@ -2452,6 +2559,10 @@ vdev_online(spa_t *spa, uint64_t guid, uint64_t flags, vdev_state_t *newstate)
                        return (spa_vdev_state_exit(spa, vd, ENOTSUP));
                spa_async_request(spa, SPA_ASYNC_CONFIG_UPDATE);
        }
+
+       if (postevent)
+               spa_event_notify(spa, vd, ESC_ZFS_VDEV_ONLINE);
+
        return (spa_vdev_state_exit(spa, vd, 0));
 }
 
@@ -2614,7 +2725,7 @@ vdev_clear(spa_t *spa, vdev_t *vd)
                if (vd->vdev_aux == NULL && !vdev_is_dead(vd))
                        spa_async_request(spa, SPA_ASYNC_RESILVER);
 
-               spa_event_notify(spa, vd, FM_EREPORT_ZFS_DEVICE_CLEAR);
+               spa_event_notify(spa, vd, ESC_ZFS_VDEV_CLEAR);
        }
 
        /*
@@ -2668,7 +2779,8 @@ vdev_allocatable(vdev_t *vd)
         * we're asking two separate questions about it.
         */
        return (!(state < VDEV_STATE_DEGRADED && state != VDEV_STATE_CLOSED) &&
-           !vd->vdev_cant_write && !vd->vdev_ishole);
+           !vd->vdev_cant_write && !vd->vdev_ishole &&
+           vd->vdev_mg->mg_initialized);
 }
 
 boolean_t
@@ -2688,49 +2800,132 @@ vdev_accessible(vdev_t *vd, zio_t *zio)
        return (B_TRUE);
 }
 
+static void
+vdev_get_child_stat(vdev_t *cvd, vdev_stat_t *vs, vdev_stat_t *cvs)
+{
+       int t;
+       for (t = 0; t < ZIO_TYPES; t++) {
+               vs->vs_ops[t] += cvs->vs_ops[t];
+               vs->vs_bytes[t] += cvs->vs_bytes[t];
+       }
+
+       cvs->vs_scan_removing = cvd->vdev_removing;
+}
+
 /*
- * Get statistics for the given vdev.
+ * Get extended stats
  */
-void
-vdev_get_stats(vdev_t *vd, vdev_stat_t *vs)
+static void
+vdev_get_child_stat_ex(vdev_t *cvd, vdev_stat_ex_t *vsx, vdev_stat_ex_t *cvsx)
 {
-       spa_t *spa = vd->vdev_spa;
-       vdev_t *rvd = spa->spa_root_vdev;
-       int c, t;
+       int t, b;
+       for (t = 0; t < ZIO_TYPES; t++) {
+               for (b = 0; b < ARRAY_SIZE(vsx->vsx_disk_histo[0]); b++)
+                       vsx->vsx_disk_histo[t][b] += cvsx->vsx_disk_histo[t][b];
 
-       ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0);
+               for (b = 0; b < ARRAY_SIZE(vsx->vsx_total_histo[0]); b++) {
+                       vsx->vsx_total_histo[t][b] +=
+                           cvsx->vsx_total_histo[t][b];
+               }
+       }
 
-       mutex_enter(&vd->vdev_stat_lock);
-       bcopy(&vd->vdev_stat, vs, sizeof (*vs));
-       vs->vs_timestamp = gethrtime() - vs->vs_timestamp;
-       vs->vs_state = vd->vdev_state;
-       vs->vs_rsize = vdev_get_min_asize(vd);
-       if (vd->vdev_ops->vdev_op_leaf)
-               vs->vs_rsize += VDEV_LABEL_START_SIZE + VDEV_LABEL_END_SIZE;
-       vs->vs_esize = vd->vdev_max_asize - vd->vdev_asize;
-       if (vd->vdev_aux == NULL && vd == vd->vdev_top && !vd->vdev_ishole) {
-               vs->vs_fragmentation = vd->vdev_mg->mg_fragmentation;
+       for (t = 0; t < ZIO_PRIORITY_NUM_QUEUEABLE; t++) {
+               for (b = 0; b < ARRAY_SIZE(vsx->vsx_queue_histo[0]); b++) {
+                       vsx->vsx_queue_histo[t][b] +=
+                           cvsx->vsx_queue_histo[t][b];
+               }
+               vsx->vsx_active_queue[t] += cvsx->vsx_active_queue[t];
+               vsx->vsx_pend_queue[t] += cvsx->vsx_pend_queue[t];
+
+               for (b = 0; b < ARRAY_SIZE(vsx->vsx_ind_histo[0]); b++)
+                       vsx->vsx_ind_histo[t][b] += cvsx->vsx_ind_histo[t][b];
+
+               for (b = 0; b < ARRAY_SIZE(vsx->vsx_agg_histo[0]); b++)
+                       vsx->vsx_agg_histo[t][b] += cvsx->vsx_agg_histo[t][b];
        }
 
+}
+
+/*
+ * Get statistics for the given vdev.
+ */
+static void
+vdev_get_stats_ex_impl(vdev_t *vd, vdev_stat_t *vs, vdev_stat_ex_t *vsx)
+{
+       int c, t;
        /*
         * If we're getting stats on the root vdev, aggregate the I/O counts
         * over all top-level vdevs (i.e. the direct children of the root).
         */
-       if (vd == rvd) {
-               for (c = 0; c < rvd->vdev_children; c++) {
-                       vdev_t *cvd = rvd->vdev_child[c];
+       if (!vd->vdev_ops->vdev_op_leaf) {
+               if (vs) {
+                       memset(vs->vs_ops, 0, sizeof (vs->vs_ops));
+                       memset(vs->vs_bytes, 0, sizeof (vs->vs_bytes));
+               }
+               if (vsx)
+                       memset(vsx, 0, sizeof (*vsx));
+
+               for (c = 0; c < vd->vdev_children; c++) {
+                       vdev_t *cvd = vd->vdev_child[c];
                        vdev_stat_t *cvs = &cvd->vdev_stat;
+                       vdev_stat_ex_t *cvsx = &cvd->vdev_stat_ex;
+
+                       vdev_get_stats_ex_impl(cvd, cvs, cvsx);
+                       if (vs)
+                               vdev_get_child_stat(cvd, vs, cvs);
+                       if (vsx)
+                               vdev_get_child_stat_ex(cvd, vsx, cvsx);
 
-                       for (t = 0; t < ZIO_TYPES; t++) {
-                               vs->vs_ops[t] += cvs->vs_ops[t];
-                               vs->vs_bytes[t] += cvs->vs_bytes[t];
-                       }
-                       cvs->vs_scan_removing = cvd->vdev_removing;
+               }
+       } else {
+               /*
+                * We're a leaf.  Just copy our ZIO active queue stats in.  The
+                * other leaf stats are updated in vdev_stat_update().
+                */
+               if (!vsx)
+                       return;
+
+               memcpy(vsx, &vd->vdev_stat_ex, sizeof (vd->vdev_stat_ex));
+
+               for (t = 0; t < ARRAY_SIZE(vd->vdev_queue.vq_class); t++) {
+                       vsx->vsx_active_queue[t] =
+                           vd->vdev_queue.vq_class[t].vqc_active;
+                       vsx->vsx_pend_queue[t] = avl_numnodes(
+                           &vd->vdev_queue.vq_class[t].vqc_queued_tree);
+               }
+       }
+}
+
+void
+vdev_get_stats_ex(vdev_t *vd, vdev_stat_t *vs, vdev_stat_ex_t *vsx)
+{
+       mutex_enter(&vd->vdev_stat_lock);
+       if (vs) {
+               bcopy(&vd->vdev_stat, vs, sizeof (*vs));
+               vs->vs_timestamp = gethrtime() - vs->vs_timestamp;
+               vs->vs_state = vd->vdev_state;
+               vs->vs_rsize = vdev_get_min_asize(vd);
+               if (vd->vdev_ops->vdev_op_leaf)
+                       vs->vs_rsize += VDEV_LABEL_START_SIZE +
+                           VDEV_LABEL_END_SIZE;
+               vs->vs_esize = vd->vdev_max_asize - vd->vdev_asize;
+               if (vd->vdev_aux == NULL && vd == vd->vdev_top &&
+                   !vd->vdev_ishole) {
+                       vs->vs_fragmentation = vd->vdev_mg->mg_fragmentation;
                }
        }
+
+       ASSERT(spa_config_held(vd->vdev_spa, SCL_ALL, RW_READER) != 0);
+       vdev_get_stats_ex_impl(vd, vs, vsx);
        mutex_exit(&vd->vdev_stat_lock);
 }
 
+void
+vdev_get_stats(vdev_t *vd, vdev_stat_t *vs)
+{
+       return (vdev_get_stats_ex(vd, vs, NULL));
+}
+
 void
 vdev_clear_stats(vdev_t *vd)
 {
@@ -2764,6 +2959,7 @@ vdev_stat_update(zio_t *zio, uint64_t psize)
        vdev_t *pvd;
        uint64_t txg = zio->io_txg;
        vdev_stat_t *vs = &vd->vdev_stat;
+       vdev_stat_ex_t *vsx = &vd->vdev_stat_ex;
        zio_type_t type = zio->io_type;
        int flags = zio->io_flags;
 
@@ -2814,8 +3010,33 @@ vdev_stat_update(zio_t *zio, uint64_t psize)
                                vs->vs_self_healed += psize;
                }
 
-               vs->vs_ops[type]++;
-               vs->vs_bytes[type] += psize;
+               /*
+                * The bytes/ops/histograms are recorded at the leaf level and
+                * aggregated into the higher level vdevs in vdev_get_stats().
+                */
+               if (vd->vdev_ops->vdev_op_leaf &&
+                   (zio->io_priority < ZIO_PRIORITY_NUM_QUEUEABLE)) {
+
+                       vs->vs_ops[type]++;
+                       vs->vs_bytes[type] += psize;
+
+                       if (flags & ZIO_FLAG_DELEGATED) {
+                               vsx->vsx_agg_histo[zio->io_priority]
+                                   [RQ_HISTO(zio->io_size)]++;
+                       } else {
+                               vsx->vsx_ind_histo[zio->io_priority]
+                                   [RQ_HISTO(zio->io_size)]++;
+                       }
+
+                       if (zio->io_delta && zio->io_delay) {
+                               vsx->vsx_queue_histo[zio->io_priority]
+                                   [L_HISTO(zio->io_delta - zio->io_delay)]++;
+                               vsx->vsx_disk_histo[type]
+                                   [L_HISTO(zio->io_delay)]++;
+                               vsx->vsx_total_histo[type]
+                                   [L_HISTO(zio->io_delta)]++;
+                       }
+               }
 
                mutex_exit(&vd->vdev_stat_lock);
                return;
@@ -3175,19 +3396,6 @@ vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state, vdev_aux_t aux)
            vd->vdev_ops->vdev_op_leaf)
                vd->vdev_ops->vdev_op_close(vd);
 
-       /*
-        * If we have brought this vdev back into service, we need
-        * to notify fmd so that it can gracefully repair any outstanding
-        * cases due to a missing device.  We do this in all cases, even those
-        * that probably don't correlate to a repaired fault.  This is sure to
-        * catch all cases, and we let the zfs-retire agent sort it out.  If
-        * this is a transient state it's OK, as the retire agent will
-        * double-check the state of the vdev before repairing it.
-        */
-       if (state == VDEV_STATE_HEALTHY && vd->vdev_ops->vdev_op_leaf &&
-           vd->vdev_prevstate != state)
-               zfs_post_state_change(spa, vd);
-
        if (vd->vdev_removed &&
            state == VDEV_STATE_CANT_OPEN &&
            (aux == VDEV_AUX_OPEN_FAILED || vd->vdev_checkremove)) {
@@ -3268,6 +3476,22 @@ vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state, vdev_aux_t aux)
                vd->vdev_removed = B_FALSE;
        }
 
+       /*
+        * Notify ZED of any significant state-change on a leaf vdev.
+        *
+        */
+       if (vd->vdev_ops->vdev_op_leaf) {
+               /* preserve original state from a vdev_reopen() */
+               if ((vd->vdev_prevstate != VDEV_STATE_UNKNOWN) &&
+                   (vd->vdev_prevstate != vd->vdev_state) &&
+                   (save_state <= VDEV_STATE_CLOSED))
+                       save_state = vd->vdev_prevstate;
+
+               /* filter out state change due to initial vdev_open */
+               if (save_state > VDEV_STATE_CLOSED)
+                       zfs_post_state_change(spa, vd, save_state);
+       }
+
        if (!isopen && vd->vdev_parent)
                vdev_propagate_state(vd->vdev_parent);
 }
index 389fa6fd9d0706e7e33a24cce9468b26ea76b901..321ea4a2f38c32419c36acf0aa6dfda1886cd52b 100644 (file)
@@ -23,7 +23,7 @@
  * Use is subject to license terms.
  */
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -102,31 +102,26 @@ static vdc_stats_t vdc_stats = {
        { "misses",             KSTAT_DATA_UINT64 }
 };
 
-#define        VDCSTAT_BUMP(stat)      atomic_add_64(&vdc_stats.stat.value.ui64, 1);
+#define        VDCSTAT_BUMP(stat)      atomic_inc_64(&vdc_stats.stat.value.ui64);
 
-static int
+static inline int
 vdev_cache_offset_compare(const void *a1, const void *a2)
 {
-       const vdev_cache_entry_t *ve1 = a1;
-       const vdev_cache_entry_t *ve2 = a2;
-
-       if (ve1->ve_offset < ve2->ve_offset)
-               return (-1);
-       if (ve1->ve_offset > ve2->ve_offset)
-               return (1);
-       return (0);
+       const vdev_cache_entry_t *ve1 = (const vdev_cache_entry_t *)a1;
+       const vdev_cache_entry_t *ve2 = (const vdev_cache_entry_t *)a2;
+
+       return (AVL_CMP(ve1->ve_offset, ve2->ve_offset));
 }
 
 static int
 vdev_cache_lastused_compare(const void *a1, const void *a2)
 {
-       const vdev_cache_entry_t *ve1 = a1;
-       const vdev_cache_entry_t *ve2 = a2;
+       const vdev_cache_entry_t *ve1 = (const vdev_cache_entry_t *)a1;
+       const vdev_cache_entry_t *ve2 = (const vdev_cache_entry_t *)a2;
 
-       if (ddi_time_before(ve1->ve_lastused, ve2->ve_lastused))
-               return (-1);
-       if (ddi_time_after(ve1->ve_lastused, ve2->ve_lastused))
-               return (1);
+       int cmp = AVL_CMP(ve1->ve_lastused, ve2->ve_lastused);
+       if (likely(cmp))
+               return (cmp);
 
        /*
         * Among equally old entries, sort by offset to ensure uniqueness.
@@ -219,6 +214,7 @@ vdev_cache_fill(zio_t *fio)
        vdev_cache_t *vc = &vd->vdev_cache;
        vdev_cache_entry_t *ve = fio->io_private;
        zio_t *pio;
+       zio_link_t *zl;
 
        ASSERT(fio->io_size == VCBS);
 
@@ -238,7 +234,8 @@ vdev_cache_fill(zio_t *fio)
         * any reads that were queued up before the missed update are still
         * valid, so we can satisfy them from this line before we evict it.
         */
-       while ((pio = zio_walk_parents(fio)) != NULL)
+       zl = NULL;
+       while ((pio = zio_walk_parents(fio, &zl)) != NULL)
                vdev_cache_hit(vc, ve, pio);
 
        if (fio->io_error || ve->ve_missed_update)
index 2f06e721bed961c7e9cf029d1dda42abf5fd4b75..ce65760ee817d10a5b5ae79cfaeff9bbf9364996 100644 (file)
@@ -23,7 +23,7 @@
  * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
  * Rewritten for Linux by Brian Behlendorf <behlendorf1@llnl.gov>.
  * LLNL-CODE-403049.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -41,10 +41,8 @@ static void *zfs_vdev_holder = VDEV_HOLDER;
  * Virtual device vector for disks.
  */
 typedef struct dio_request {
-       struct completion       dr_comp;        /* Completion for sync IO */
        zio_t                   *dr_zio;        /* Parent ZIO */
        atomic_t                dr_ref;         /* References */
-       int                     dr_wait;        /* Wait for IO */
        int                     dr_error;       /* Bio error */
        int                     dr_bio_count;   /* Count of bio's */
        struct bio              *dr_bio[0];     /* Attached bio's */
@@ -100,9 +98,9 @@ vdev_disk_error(zio_t *zio)
 {
 #ifdef ZFS_DEBUG
        printk("ZFS: zio error=%d type=%d offset=%llu size=%llu "
-           "flags=%x delay=%llu\n", zio->io_error, zio->io_type,
+           "flags=%x\n", zio->io_error, zio->io_type,
            (u_longlong_t)zio->io_offset, (u_longlong_t)zio->io_size,
-           zio->io_flags, (u_longlong_t)zio->io_delay);
+           zio->io_flags);
 #endif
 }
 
@@ -363,7 +361,6 @@ vdev_disk_dio_alloc(int bio_count)
        dr = kmem_zalloc(sizeof (dio_request_t) +
            sizeof (struct bio *) * bio_count, KM_SLEEP);
        if (dr) {
-               init_completion(&dr->dr_comp);
                atomic_set(&dr->dr_ref, 0);
                dr->dr_bio_count = bio_count;
                dr->dr_error = 0;
@@ -410,12 +407,11 @@ vdev_disk_dio_put(dio_request_t *dr)
                vdev_disk_dio_free(dr);
 
                if (zio) {
-                       zio->io_delay = jiffies_64 - zio->io_delay;
                        zio->io_error = error;
                        ASSERT3S(zio->io_error, >=, 0);
                        if (zio->io_error)
                                vdev_disk_error(zio);
-                       zio_interrupt(zio);
+                       zio_delay_interrupt(zio);
                }
        }
 
@@ -426,7 +422,6 @@ BIO_END_IO_PROTO(vdev_disk_physio_completion, bio, error)
 {
        dio_request_t *dr = bio->bi_private;
        int rc;
-       int wait;
 
        if (dr->dr_error == 0) {
 #ifdef HAVE_1ARG_BIO_END_IO_T
@@ -439,13 +434,8 @@ BIO_END_IO_PROTO(vdev_disk_physio_completion, bio, error)
 #endif
        }
 
-       wait = dr->dr_wait;
        /* Drop reference aquired by __vdev_disk_physio */
        rc = vdev_disk_dio_put(dr);
-
-       /* Wake up synchronous waiter this is the last outstanding bio */
-       if (wait && rc == 1)
-               complete(&dr->dr_comp);
 }
 
 static inline unsigned long
@@ -527,13 +517,16 @@ vdev_submit_bio(struct bio *bio)
 
 static int
 __vdev_disk_physio(struct block_device *bdev, zio_t *zio, caddr_t kbuf_ptr,
-    size_t kbuf_size, uint64_t kbuf_offset, int rw, int flags, int wait)
+    size_t kbuf_size, uint64_t kbuf_offset, int rw, int flags)
 {
        dio_request_t *dr;
        caddr_t bio_ptr;
        uint64_t bio_offset;
        int bio_size, bio_count = 16;
        int i = 0, error = 0;
+#if defined(HAVE_BLK_QUEUE_HAVE_BLK_PLUG)
+       struct blk_plug plug;
+#endif
 
        ASSERT3U(kbuf_offset + kbuf_size, <=, bdev->bd_inode->i_size);
 
@@ -546,7 +539,6 @@ retry:
                bio_set_flags_failfast(bdev, &flags);
 
        dr->dr_zio = zio;
-       dr->dr_wait = wait;
 
        /*
         * When the IO size exceeds the maximum bio size for the request
@@ -602,42 +594,27 @@ retry:
 
        /* Extra reference to protect dio_request during vdev_submit_bio */
        vdev_disk_dio_get(dr);
-       if (zio)
-               zio->io_delay = jiffies_64;
+
+#if defined(HAVE_BLK_QUEUE_HAVE_BLK_PLUG)
+       if (dr->dr_bio_count > 1)
+               blk_start_plug(&plug);
+#endif
 
        /* Submit all bio's associated with this dio */
        for (i = 0; i < dr->dr_bio_count; i++)
                if (dr->dr_bio[i])
                        vdev_submit_bio(dr->dr_bio[i]);
 
-       /*
-        * On synchronous blocking requests we wait for all bio the completion
-        * callbacks to run.  We will be woken when the last callback runs
-        * for this dio.  We are responsible for putting the last dio_request
-        * reference will in turn put back the last bio references.  The
-        * only synchronous consumer is vdev_disk_read_rootlabel() all other
-        * IO originating from vdev_disk_io_start() is asynchronous.
-        */
-       if (wait) {
-               wait_for_completion(&dr->dr_comp);
-               error = dr->dr_error;
-               ASSERT3S(atomic_read(&dr->dr_ref), ==, 1);
-       }
+#if defined(HAVE_BLK_QUEUE_HAVE_BLK_PLUG)
+       if (dr->dr_bio_count > 1)
+               blk_finish_plug(&plug);
+#endif
 
        (void) vdev_disk_dio_put(dr);
 
        return (error);
 }
 
-int
-vdev_disk_physio(struct block_device *bdev, caddr_t kbuf,
-    size_t size, uint64_t offset, int rw, int flags)
-{
-       bio_set_flags_failfast(bdev, &flags);
-       return (__vdev_disk_physio(bdev, NULL, kbuf, size, offset, rw, flags,
-           1));
-}
-
 BIO_END_IO_PROTO(vdev_disk_io_flush_completion, bio, rc)
 {
        zio_t *zio = bio->bi_private;
@@ -645,7 +622,6 @@ BIO_END_IO_PROTO(vdev_disk_io_flush_completion, bio, rc)
        int rc = bio->bi_error;
 #endif
 
-       zio->io_delay = jiffies_64 - zio->io_delay;
        zio->io_error = -rc;
        if (rc && (rc == -EOPNOTSUPP))
                zio->io_vd->vdev_nowritecache = B_TRUE;
@@ -675,7 +651,6 @@ vdev_disk_io_flush(struct block_device *bdev, zio_t *zio)
        bio->bi_end_io = vdev_disk_io_flush_completion;
        bio->bi_private = zio;
        bio->bi_bdev = bdev;
-       zio->io_delay = jiffies_64;
        bio_set_op_attrs(bio, 0, VDEV_WRITE_FLUSH_FUA);
        vdev_submit_bio(bio);
        invalidate_bdev(bdev);
@@ -688,7 +663,6 @@ vdev_disk_io_start(zio_t *zio)
 {
        vdev_t *v = zio->io_vd;
        vdev_disk_t *vd = v->vdev_tsd;
-       zio_priority_t pri = zio->io_priority;
        int rw, flags, error;
 
        switch (zio->io_type) {
@@ -729,18 +703,24 @@ vdev_disk_io_start(zio_t *zio)
                return;
        case ZIO_TYPE_WRITE:
                rw = WRITE;
-               if ((pri == ZIO_PRIORITY_SYNC_WRITE) && (v->vdev_nonrot))
-                       flags = WRITE_SYNC;
-               else
-                       flags = 0;
+#if defined(HAVE_BLK_QUEUE_HAVE_BIO_RW_UNPLUG)
+               flags = (1 << BIO_RW_UNPLUG);
+#elif defined(REQ_UNPLUG)
+               flags = REQ_UNPLUG;
+#else
+               flags = 0;
+#endif
                break;
 
        case ZIO_TYPE_READ:
                rw = READ;
-               if ((pri == ZIO_PRIORITY_SYNC_READ) && (v->vdev_nonrot))
-                       flags = READ_SYNC;
-               else
-                       flags = 0;
+#if defined(HAVE_BLK_QUEUE_HAVE_BIO_RW_UNPLUG)
+               flags = (1 << BIO_RW_UNPLUG);
+#elif defined(REQ_UNPLUG)
+               flags = REQ_UNPLUG;
+#else
+               flags = 0;
+#endif
                break;
 
        default:
@@ -749,8 +729,9 @@ vdev_disk_io_start(zio_t *zio)
                return;
        }
 
+       zio->io_target_timestamp = zio_handle_io_delay(zio);
        error = __vdev_disk_physio(vd->vd_bdev, zio, zio->io_data,
-           zio->io_size, zio->io_offset, rw, flags, 0);
+           zio->io_size, zio->io_offset, rw, flags);
        if (error) {
                zio->io_error = error;
                zio_interrupt(zio);
@@ -820,69 +801,5 @@ vdev_ops_t vdev_disk_ops = {
        B_TRUE                  /* leaf vdev */
 };
 
-/*
- * Given the root disk device devid or pathname, read the label from
- * the device, and construct a configuration nvlist.
- */
-int
-vdev_disk_read_rootlabel(char *devpath, char *devid, nvlist_t **config)
-{
-       struct block_device *bdev;
-       vdev_label_t *label;
-       uint64_t s, size;
-       int i;
-
-       bdev = vdev_bdev_open(devpath, vdev_bdev_mode(FREAD), zfs_vdev_holder);
-       if (IS_ERR(bdev))
-               return (-PTR_ERR(bdev));
-
-       s = bdev_capacity(bdev);
-       if (s == 0) {
-               vdev_bdev_close(bdev, vdev_bdev_mode(FREAD));
-               return (EIO);
-       }
-
-       size = P2ALIGN_TYPED(s, sizeof (vdev_label_t), uint64_t);
-       label = vmem_alloc(sizeof (vdev_label_t), KM_SLEEP);
-
-       for (i = 0; i < VDEV_LABELS; i++) {
-               uint64_t offset, state, txg = 0;
-
-               /* read vdev label */
-               offset = vdev_label_offset(size, i, 0);
-               if (vdev_disk_physio(bdev, (caddr_t)label,
-                   VDEV_SKIP_SIZE + VDEV_PHYS_SIZE, offset, READ,
-                   REQ_SYNC) != 0)
-                       continue;
-
-               if (nvlist_unpack(label->vl_vdev_phys.vp_nvlist,
-                   sizeof (label->vl_vdev_phys.vp_nvlist), config, 0) != 0) {
-                       *config = NULL;
-                       continue;
-               }
-
-               if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_STATE,
-                   &state) != 0 || state >= POOL_STATE_DESTROYED) {
-                       nvlist_free(*config);
-                       *config = NULL;
-                       continue;
-               }
-
-               if (nvlist_lookup_uint64(*config, ZPOOL_CONFIG_POOL_TXG,
-                   &txg) != 0 || txg == 0) {
-                       nvlist_free(*config);
-                       *config = NULL;
-                       continue;
-               }
-
-               break;
-       }
-
-       vmem_free(label, sizeof (vdev_label_t));
-       vdev_bdev_close(bdev, vdev_bdev_mode(FREAD));
-
-       return (0);
-}
-
 module_param(zfs_vdev_scheduler, charp, 0644);
 MODULE_PARM_DESC(zfs_vdev_scheduler, "I/O scheduler");
index a29ea7bf9515a2b5106417b4fd036e0cfc3fe616..bca4175a6ff414f7332e23b9433187a2e6584d76 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -159,7 +159,7 @@ vdev_file_io_strategy(void *arg)
        if (resid != 0 && zio->io_error == 0)
                zio->io_error = SET_ERROR(ENOSPC);
 
-       zio_interrupt(zio);
+       zio_delay_interrupt(zio);
 }
 
 static void
@@ -217,6 +217,8 @@ vdev_file_io_start(zio_t *zio)
                return;
        }
 
+       zio->io_target_timestamp = zio_handle_io_delay(zio);
+
        VERIFY3U(taskq_dispatch(system_taskq, vdev_file_io_strategy, zio,
            TQ_SLEEP), !=, 0);
 }
index 7f588ed6b0b5611905cea0ce53d8ccfca64204b7..4edbfa41e6677a54fbc72e5f62330ee98536bede 100644 (file)
@@ -207,6 +207,149 @@ vdev_label_write(zio_t *zio, vdev_t *vd, int l, void *buf, uint64_t offset,
            ZIO_PRIORITY_SYNC_WRITE, flags, B_TRUE));
 }
 
+/*
+ * Generate the nvlist representing this vdev's stats
+ */
+void
+vdev_config_generate_stats(vdev_t *vd, nvlist_t *nv)
+{
+       nvlist_t *nvx;
+       vdev_stat_t *vs;
+       vdev_stat_ex_t *vsx;
+
+       vs = kmem_alloc(sizeof (*vs), KM_SLEEP);
+       vsx = kmem_alloc(sizeof (*vsx), KM_SLEEP);
+
+       vdev_get_stats_ex(vd, vs, vsx);
+       fnvlist_add_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
+           (uint64_t *)vs, sizeof (*vs) / sizeof (uint64_t));
+
+       kmem_free(vs, sizeof (*vs));
+
+       /*
+        * Add extended stats into a special extended stats nvlist.  This keeps
+        * all the extended stats nicely grouped together.  The extended stats
+        * nvlist is then added to the main nvlist.
+        */
+       nvx = fnvlist_alloc();
+
+       /* ZIOs in flight to disk */
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE,
+           vsx->vsx_active_queue[ZIO_PRIORITY_SYNC_READ]);
+
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE,
+           vsx->vsx_active_queue[ZIO_PRIORITY_SYNC_WRITE]);
+
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE,
+           vsx->vsx_active_queue[ZIO_PRIORITY_ASYNC_READ]);
+
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE,
+           vsx->vsx_active_queue[ZIO_PRIORITY_ASYNC_WRITE]);
+
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE,
+           vsx->vsx_active_queue[ZIO_PRIORITY_SCRUB]);
+
+       /* ZIOs pending */
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SYNC_R_PEND_QUEUE,
+           vsx->vsx_pend_queue[ZIO_PRIORITY_SYNC_READ]);
+
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SYNC_W_PEND_QUEUE,
+           vsx->vsx_pend_queue[ZIO_PRIORITY_SYNC_WRITE]);
+
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ASYNC_R_PEND_QUEUE,
+           vsx->vsx_pend_queue[ZIO_PRIORITY_ASYNC_READ]);
+
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_ASYNC_W_PEND_QUEUE,
+           vsx->vsx_pend_queue[ZIO_PRIORITY_ASYNC_WRITE]);
+
+       fnvlist_add_uint64(nvx, ZPOOL_CONFIG_VDEV_SCRUB_PEND_QUEUE,
+           vsx->vsx_pend_queue[ZIO_PRIORITY_SCRUB]);
+
+       /* Histograms */
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO,
+           vsx->vsx_total_histo[ZIO_TYPE_READ],
+           ARRAY_SIZE(vsx->vsx_total_histo[ZIO_TYPE_READ]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO,
+           vsx->vsx_total_histo[ZIO_TYPE_WRITE],
+           ARRAY_SIZE(vsx->vsx_total_histo[ZIO_TYPE_WRITE]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO,
+           vsx->vsx_disk_histo[ZIO_TYPE_READ],
+           ARRAY_SIZE(vsx->vsx_disk_histo[ZIO_TYPE_READ]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO,
+           vsx->vsx_disk_histo[ZIO_TYPE_WRITE],
+           ARRAY_SIZE(vsx->vsx_disk_histo[ZIO_TYPE_WRITE]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO,
+           vsx->vsx_queue_histo[ZIO_PRIORITY_SYNC_READ],
+           ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_SYNC_READ]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO,
+           vsx->vsx_queue_histo[ZIO_PRIORITY_SYNC_WRITE],
+           ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_SYNC_WRITE]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO,
+           vsx->vsx_queue_histo[ZIO_PRIORITY_ASYNC_READ],
+           ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_ASYNC_READ]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO,
+           vsx->vsx_queue_histo[ZIO_PRIORITY_ASYNC_WRITE],
+           ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_ASYNC_WRITE]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO,
+           vsx->vsx_queue_histo[ZIO_PRIORITY_SCRUB],
+           ARRAY_SIZE(vsx->vsx_queue_histo[ZIO_PRIORITY_SCRUB]));
+
+       /* Request sizes */
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO,
+           vsx->vsx_ind_histo[ZIO_PRIORITY_SYNC_READ],
+           ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_SYNC_READ]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO,
+           vsx->vsx_ind_histo[ZIO_PRIORITY_SYNC_WRITE],
+           ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_SYNC_WRITE]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO,
+           vsx->vsx_ind_histo[ZIO_PRIORITY_ASYNC_READ],
+           ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_ASYNC_READ]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO,
+           vsx->vsx_ind_histo[ZIO_PRIORITY_ASYNC_WRITE],
+           ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_ASYNC_WRITE]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO,
+           vsx->vsx_ind_histo[ZIO_PRIORITY_SCRUB],
+           ARRAY_SIZE(vsx->vsx_ind_histo[ZIO_PRIORITY_SCRUB]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO,
+           vsx->vsx_agg_histo[ZIO_PRIORITY_SYNC_READ],
+           ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_SYNC_READ]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO,
+           vsx->vsx_agg_histo[ZIO_PRIORITY_SYNC_WRITE],
+           ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_SYNC_WRITE]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO,
+           vsx->vsx_agg_histo[ZIO_PRIORITY_ASYNC_READ],
+           ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_ASYNC_READ]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO,
+           vsx->vsx_agg_histo[ZIO_PRIORITY_ASYNC_WRITE],
+           ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_ASYNC_WRITE]));
+
+       fnvlist_add_uint64_array(nvx, ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO,
+           vsx->vsx_agg_histo[ZIO_PRIORITY_SCRUB],
+           ARRAY_SIZE(vsx->vsx_agg_histo[ZIO_PRIORITY_SCRUB]));
+
+       /* Add extended stats nvlist to main nvlist */
+       fnvlist_add_nvlist(nv, ZPOOL_CONFIG_VDEV_STATS_EX, nvx);
+
+       fnvlist_free(nvx);
+       kmem_free(vsx, sizeof (*vsx));
+}
+
 /*
  * Generate the nvlist representing this vdev's config.
  */
@@ -215,7 +358,6 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats,
     vdev_config_flag_t flags)
 {
        nvlist_t *nv = NULL;
-
        nv = fnvlist_alloc();
 
        fnvlist_add_string(nv, ZPOOL_CONFIG_TYPE, vd->vdev_ops->vdev_op_type);
@@ -233,6 +375,10 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats,
                fnvlist_add_string(nv, ZPOOL_CONFIG_PHYS_PATH,
                    vd->vdev_physpath);
 
+       if (vd->vdev_enc_sysfs_path != NULL)
+               fnvlist_add_string(nv, ZPOOL_CONFIG_VDEV_ENC_SYSFS_PATH,
+                   vd->vdev_enc_sysfs_path);
+
        if (vd->vdev_fru != NULL)
                fnvlist_add_string(nv, ZPOOL_CONFIG_FRU, vd->vdev_fru);
 
@@ -291,13 +437,24 @@ vdev_config_generate(spa_t *spa, vdev_t *vd, boolean_t getstats,
        if (vd->vdev_crtxg)
                fnvlist_add_uint64(nv, ZPOOL_CONFIG_CREATE_TXG, vd->vdev_crtxg);
 
+       if (flags & VDEV_CONFIG_MOS) {
+               if (vd->vdev_leaf_zap != 0) {
+                       ASSERT(vd->vdev_ops->vdev_op_leaf);
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_VDEV_LEAF_ZAP,
+                           vd->vdev_leaf_zap);
+               }
+
+               if (vd->vdev_top_zap != 0) {
+                       ASSERT(vd == vd->vdev_top);
+                       fnvlist_add_uint64(nv, ZPOOL_CONFIG_VDEV_TOP_ZAP,
+                           vd->vdev_top_zap);
+               }
+       }
+
        if (getstats) {
-               vdev_stat_t vs;
                pool_scan_stat_t ps;
 
-               vdev_get_stats(vd, &vs);
-               fnvlist_add_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
-                   (uint64_t *)&vs, sizeof (vs) / sizeof (uint64_t));
+               vdev_config_generate_stats(vd, nv);
 
                /* provide either current or previous scan information */
                if (spa_scan_get_stats(spa, &ps) == 0) {
@@ -862,19 +1019,13 @@ retry:
  * among uberblocks with equal txg, choose the one with the latest timestamp.
  */
 static int
-vdev_uberblock_compare(uberblock_t *ub1, uberblock_t *ub2)
+vdev_uberblock_compare(const uberblock_t *ub1, const uberblock_t *ub2)
 {
-       if (ub1->ub_txg < ub2->ub_txg)
-               return (-1);
-       if (ub1->ub_txg > ub2->ub_txg)
-               return (1);
+       int cmp = AVL_CMP(ub1->ub_txg, ub2->ub_txg);
+       if (likely(cmp))
+               return (cmp);
 
-       if (ub1->ub_timestamp < ub2->ub_timestamp)
-               return (-1);
-       if (ub1->ub_timestamp > ub2->ub_timestamp)
-               return (1);
-
-       return (0);
+       return (AVL_CMP(ub1->ub_timestamp, ub2->ub_timestamp));
 }
 
 struct ubl_cbdata {
@@ -984,7 +1135,7 @@ vdev_uberblock_sync_done(zio_t *zio)
        uint64_t *good_writes = zio->io_private;
 
        if (zio->io_error == 0 && zio->io_vd->vdev_top->vdev_ms_array != 0)
-               atomic_add_64(good_writes, 1);
+               atomic_inc_64(good_writes);
 }
 
 /*
@@ -1060,7 +1211,7 @@ vdev_label_sync_done(zio_t *zio)
        uint64_t *good_writes = zio->io_private;
 
        if (zio->io_error == 0)
-               atomic_add_64(good_writes, 1);
+               atomic_inc_64(good_writes);
 }
 
 /*
@@ -1187,15 +1338,16 @@ vdev_label_sync_list(spa_t *spa, int l, uint64_t txg, int flags)
  * at any time, you can just call it again, and it will resume its work.
  */
 int
-vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg, boolean_t tryhard)
+vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg)
 {
        spa_t *spa = svd[0]->vdev_spa;
        uberblock_t *ub = &spa->spa_uberblock;
        vdev_t *vd;
        zio_t *zio;
-       int error;
+       int error = 0;
        int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL;
 
+retry:
        /*
         * Normally, we don't want to try too hard to write every label and
         * uberblock.  If there is a flaky disk, we don't want the rest of the
@@ -1203,8 +1355,11 @@ vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg, boolean_t tryhard)
         * single label out, we should retry with ZIO_FLAG_TRYHARD before
         * bailing out and declaring the pool faulted.
         */
-       if (tryhard)
+       if (error != 0) {
+               if ((flags & ZIO_FLAG_TRYHARD) != 0)
+                       return (error);
                flags |= ZIO_FLAG_TRYHARD;
+       }
 
        ASSERT(ub->ub_txg <= txg);
 
@@ -1248,7 +1403,7 @@ vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg, boolean_t tryhard)
         * are committed to stable storage before the uberblock update.
         */
        if ((error = vdev_label_sync_list(spa, 0, txg, flags)) != 0)
-               return (error);
+               goto retry;
 
        /*
         * Sync the uberblocks to all vdevs in svd[].
@@ -1266,7 +1421,7 @@ vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg, boolean_t tryhard)
         *      to the new uberblocks.
         */
        if ((error = vdev_uberblock_sync_list(svd, svdcount, ub, flags)) != 0)
-               return (error);
+               goto retry;
 
        /*
         * Sync out odd labels for every dirty vdev.  If the system dies
@@ -1278,5 +1433,8 @@ vdev_config_sync(vdev_t **svd, int svdcount, uint64_t txg, boolean_t tryhard)
         * to disk to ensure that all odd-label updates are committed to
         * stable storage before the next transaction group begins.
         */
-       return (vdev_label_sync_list(spa, 1, txg, flags));
+       if ((error = vdev_label_sync_list(spa, 1, txg, flags)) != 0)
+               goto retry;
+
+       return (0);
 }
index 6b699e883e37a8c90e1e3ee95a34db8b741cc45d..7803111954041f1a0850c2c6ba1e538623b3390d 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -41,44 +41,70 @@ typedef struct mirror_child {
        vdev_t          *mc_vd;
        uint64_t        mc_offset;
        int             mc_error;
-       int             mc_pending;
+       int             mc_load;
        uint8_t         mc_tried;
        uint8_t         mc_skipped;
        uint8_t         mc_speculative;
 } mirror_child_t;
 
 typedef struct mirror_map {
+       int             *mm_preferred;
+       int             mm_preferred_cnt;
        int             mm_children;
-       int             mm_replacing;
-       int             mm_preferred;
-       int             mm_root;
-       mirror_child_t  mm_child[1];
+       boolean_t       mm_replacing;
+       boolean_t       mm_root;
+       mirror_child_t  mm_child[];
 } mirror_map_t;
 
+static int vdev_mirror_shift = 21;
+
 /*
- * When the children are equally busy queue incoming requests to a single
- * child for N microseconds.  This is done to maximize the likelihood that
- * the Linux elevator will be able to merge requests while it is plugged.
- * Otherwise, requests are queued to the least busy device.
- *
- * For rotational disks the Linux elevator will plug for 10ms which is
- * why zfs_vdev_mirror_switch_us is set to 10ms by default.  For non-
- * rotational disks the elevator will not plug, but 10ms is still a small
- * enough value that the requests will get spread over all the children.
+ * The load configuration settings below are tuned by default for
+ * the case where all devices are of the same rotational type.
  *
- * For fast SSDs it may make sense to decrease zfs_vdev_mirror_switch_us
- * significantly to bound the worst case latencies.  It would probably be
- * ideal to calculate a decaying average of the last observed latencies and
- * use that to dynamically adjust the zfs_vdev_mirror_switch_us time.
+ * If there is a mixture of rotating and non-rotating media, setting
+ * zfs_vdev_mirror_non_rotating_seek_inc to 0 may well provide better results
+ * as it will direct more reads to the non-rotating vdevs which are more likely
+ * to have a higher performance.
  */
-int zfs_vdev_mirror_switch_us = 10000;
+
+/* Rotating media load calculation configuration. */
+static int zfs_vdev_mirror_rotating_inc = 0;
+static int zfs_vdev_mirror_rotating_seek_inc = 5;
+static int zfs_vdev_mirror_rotating_seek_offset = 1 * 1024 * 1024;
+
+/* Non-rotating media load calculation configuration. */
+static int zfs_vdev_mirror_non_rotating_inc = 0;
+static int zfs_vdev_mirror_non_rotating_seek_inc = 1;
+
+static inline size_t
+vdev_mirror_map_size(int children)
+{
+       return (offsetof(mirror_map_t, mm_child[children]) +
+           sizeof (int) * children);
+}
+
+static inline mirror_map_t *
+vdev_mirror_map_alloc(int children, boolean_t replacing, boolean_t root)
+{
+       mirror_map_t *mm;
+
+       mm = kmem_zalloc(vdev_mirror_map_size(children), KM_SLEEP);
+       mm->mm_children = children;
+       mm->mm_replacing = replacing;
+       mm->mm_root = root;
+       mm->mm_preferred = (int *)((uintptr_t)mm +
+           offsetof(mirror_map_t, mm_child[children]));
+
+       return (mm);
+}
 
 static void
 vdev_mirror_map_free(zio_t *zio)
 {
        mirror_map_t *mm = zio->io_vsd;
 
-       kmem_free(mm, offsetof(mirror_map_t, mm_child[mm->mm_children]));
+       kmem_free(mm, vdev_mirror_map_size(mm->mm_children));
 }
 
 static const zio_vsd_ops_t vdev_mirror_vsd_ops = {
@@ -87,9 +113,54 @@ static const zio_vsd_ops_t vdev_mirror_vsd_ops = {
 };
 
 static int
-vdev_mirror_pending(vdev_t *vd)
+vdev_mirror_load(mirror_map_t *mm, vdev_t *vd, uint64_t zio_offset)
 {
-       return (avl_numnodes(&vd->vdev_queue.vq_active_tree));
+       uint64_t lastoffset;
+       int load;
+
+       /* All DVAs have equal weight at the root. */
+       if (mm->mm_root)
+               return (INT_MAX);
+
+       /*
+        * We don't return INT_MAX if the device is resilvering i.e.
+        * vdev_resilver_txg != 0 as when tested performance was slightly
+        * worse overall when resilvering with compared to without.
+        */
+
+       /* Standard load based on pending queue length. */
+       load = vdev_queue_length(vd);
+       lastoffset = vdev_queue_lastoffset(vd);
+
+       if (vd->vdev_nonrot) {
+               /* Non-rotating media. */
+               if (lastoffset == zio_offset)
+                       return (load + zfs_vdev_mirror_non_rotating_inc);
+
+               /*
+                * Apply a seek penalty even for non-rotating devices as
+                * sequential I/O's can be aggregated into fewer operations on
+                * the device, thus avoiding unnecessary per-command overhead
+                * and boosting performance.
+                */
+               return (load + zfs_vdev_mirror_non_rotating_seek_inc);
+       }
+
+       /* Rotating media I/O's which directly follow the last I/O. */
+       if (lastoffset == zio_offset)
+               return (load + zfs_vdev_mirror_rotating_inc);
+
+       /*
+        * Apply half the seek increment to I/O's within seek offset
+        * of the last I/O queued to this vdev as they should incure less
+        * of a seek increment.
+        */
+       if (ABS(lastoffset - zio_offset) <
+           zfs_vdev_mirror_rotating_seek_offset)
+               return (load + (zfs_vdev_mirror_rotating_seek_inc / 2));
+
+       /* Apply the full seek increment to all other I/O's. */
+       return (load + zfs_vdev_mirror_rotating_seek_inc);
 }
 
 /*
@@ -97,38 +168,19 @@ vdev_mirror_pending(vdev_t *vd)
  * is this functions only caller, as small as possible on the stack.
  */
 noinline static mirror_map_t *
-vdev_mirror_map_alloc(zio_t *zio)
+vdev_mirror_map_init(zio_t *zio)
 {
        mirror_map_t *mm = NULL;
        mirror_child_t *mc;
        vdev_t *vd = zio->io_vd;
-       int c, d;
+       int c;
 
        if (vd == NULL) {
                dva_t *dva = zio->io_bp->blk_dva;
                spa_t *spa = zio->io_spa;
 
-               c = BP_GET_NDVAS(zio->io_bp);
-
-               mm = kmem_zalloc(offsetof(mirror_map_t, mm_child[c]),
-                   KM_SLEEP);
-               mm->mm_children = c;
-               mm->mm_replacing = B_FALSE;
-               mm->mm_preferred = spa_get_random(c);
-               mm->mm_root = B_TRUE;
-
-               /*
-                * Check the other, lower-index DVAs to see if they're on
-                * the same vdev as the child we picked.  If they are, use
-                * them since they are likely to have been allocated from
-                * the primary metaslab in use at the time, and hence are
-                * more likely to have locality with single-copy data.
-                */
-               for (c = mm->mm_preferred, d = c - 1; d >= 0; d--) {
-                       if (DVA_GET_VDEV(&dva[d]) == DVA_GET_VDEV(&dva[c]))
-                               mm->mm_preferred = d;
-               }
-
+               mm = vdev_mirror_map_alloc(BP_GET_NDVAS(zio->io_bp), B_FALSE,
+                   B_TRUE);
                for (c = 0; c < mm->mm_children; c++) {
                        mc = &mm->mm_child[c];
 
@@ -136,56 +188,13 @@ vdev_mirror_map_alloc(zio_t *zio)
                        mc->mc_offset = DVA_GET_OFFSET(&dva[c]);
                }
        } else {
-               int lowest_pending = INT_MAX;
-               int lowest_nr = 1;
-
-               c = vd->vdev_children;
-
-               mm = kmem_zalloc(offsetof(mirror_map_t, mm_child[c]),
-                   KM_SLEEP);
-               mm->mm_children = c;
-               mm->mm_replacing = (vd->vdev_ops == &vdev_replacing_ops ||
-                   vd->vdev_ops == &vdev_spare_ops);
-               mm->mm_preferred = 0;
-               mm->mm_root = B_FALSE;
-
+               mm = vdev_mirror_map_alloc(vd->vdev_children,
+                   (vd->vdev_ops == &vdev_replacing_ops ||
+                   vd->vdev_ops == &vdev_spare_ops), B_FALSE);
                for (c = 0; c < mm->mm_children; c++) {
                        mc = &mm->mm_child[c];
                        mc->mc_vd = vd->vdev_child[c];
                        mc->mc_offset = zio->io_offset;
-
-                       if (mm->mm_replacing)
-                               continue;
-
-                       if (!vdev_readable(mc->mc_vd)) {
-                               mc->mc_error = SET_ERROR(ENXIO);
-                               mc->mc_tried = 1;
-                               mc->mc_skipped = 1;
-                               mc->mc_pending = INT_MAX;
-                               continue;
-                       }
-
-                       mc->mc_pending = vdev_mirror_pending(mc->mc_vd);
-                       if (mc->mc_pending < lowest_pending) {
-                               lowest_pending = mc->mc_pending;
-                               lowest_nr = 1;
-                       } else if (mc->mc_pending == lowest_pending) {
-                               lowest_nr++;
-                       }
-               }
-
-               d = gethrtime() / (NSEC_PER_USEC * zfs_vdev_mirror_switch_us);
-               d = (d % lowest_nr) + 1;
-
-               for (c = 0; c < mm->mm_children; c++) {
-                       mc = &mm->mm_child[c];
-
-                       if (mm->mm_child[c].mc_pending == lowest_pending) {
-                               if (--d == 0) {
-                                       mm->mm_preferred = c;
-                                       break;
-                               }
-                       }
                }
        }
 
@@ -257,9 +266,10 @@ vdev_mirror_scrub_done(zio_t *zio)
 
        if (zio->io_error == 0) {
                zio_t *pio;
+               zio_link_t *zl = NULL;
 
                mutex_enter(&zio->io_lock);
-               while ((pio = zio_walk_parents(zio)) != NULL) {
+               while ((pio = zio_walk_parents(zio, &zl)) != NULL) {
                        mutex_enter(&pio->io_lock);
                        ASSERT3U(zio->io_size, >=, pio->io_size);
                        bcopy(zio->io_data, pio->io_data, pio->io_size);
@@ -276,6 +286,54 @@ vdev_mirror_scrub_done(zio_t *zio)
 }
 
 /*
+ * Check the other, lower-index DVAs to see if they're on the same
+ * vdev as the child we picked.  If they are, use them since they
+ * are likely to have been allocated from the primary metaslab in
+ * use at the time, and hence are more likely to have locality with
+ * single-copy data.
+ */
+static int
+vdev_mirror_dva_select(zio_t *zio, int p)
+{
+       dva_t *dva = zio->io_bp->blk_dva;
+       mirror_map_t *mm = zio->io_vsd;
+       int preferred;
+       int c;
+
+       preferred = mm->mm_preferred[p];
+       for (p--; p >= 0; p--) {
+               c = mm->mm_preferred[p];
+               if (DVA_GET_VDEV(&dva[c]) == DVA_GET_VDEV(&dva[preferred]))
+                       preferred = c;
+       }
+       return (preferred);
+}
+
+static int
+vdev_mirror_preferred_child_randomize(zio_t *zio)
+{
+       mirror_map_t *mm = zio->io_vsd;
+       int p;
+
+       if (mm->mm_root) {
+               p = spa_get_random(mm->mm_preferred_cnt);
+               return (vdev_mirror_dva_select(zio, p));
+       }
+
+       /*
+        * To ensure we don't always favour the first matching vdev,
+        * which could lead to wear leveling issues on SSD's, we
+        * use the I/O offset as a pseudo random seed into the vdevs
+        * which have the lowest load.
+        */
+       p = (zio->io_offset >> vdev_mirror_shift) % mm->mm_preferred_cnt;
+       return (mm->mm_preferred[p]);
+}
+
+/*
+ * Try to find a vdev whose DTL doesn't contain the block we want to read
+ * prefering vdevs based on determined load.
+ *
  * Try to find a child whose DTL doesn't contain the block we want to read.
  * If we can't, try the read on any vdev we haven't already tried.
  */
@@ -283,43 +341,70 @@ static int
 vdev_mirror_child_select(zio_t *zio)
 {
        mirror_map_t *mm = zio->io_vsd;
-       mirror_child_t *mc;
        uint64_t txg = zio->io_txg;
-       int i, c;
+       int c, lowest_load;
 
        ASSERT(zio->io_bp == NULL || BP_PHYSICAL_BIRTH(zio->io_bp) == txg);
 
-       /*
-        * Try to find a child whose DTL doesn't contain the block to read.
-        * If a child is known to be completely inaccessible (indicated by
-        * vdev_readable() returning B_FALSE), don't even try.
-        */
-       for (i = 0, c = mm->mm_preferred; i < mm->mm_children; i++, c++) {
-               if (c >= mm->mm_children)
-                       c = 0;
+       lowest_load = INT_MAX;
+       mm->mm_preferred_cnt = 0;
+       for (c = 0; c < mm->mm_children; c++) {
+               mirror_child_t *mc;
+
                mc = &mm->mm_child[c];
                if (mc->mc_tried || mc->mc_skipped)
                        continue;
+
                if (mc->mc_vd == NULL || !vdev_readable(mc->mc_vd)) {
                        mc->mc_error = SET_ERROR(ENXIO);
                        mc->mc_tried = 1;       /* don't even try */
                        mc->mc_skipped = 1;
                        continue;
                }
-               if (!vdev_dtl_contains(mc->mc_vd, DTL_MISSING, txg, 1))
-                       return (c);
-               mc->mc_error = SET_ERROR(ESTALE);
-               mc->mc_skipped = 1;
-               mc->mc_speculative = 1;
+
+               if (vdev_dtl_contains(mc->mc_vd, DTL_MISSING, txg, 1)) {
+                       mc->mc_error = SET_ERROR(ESTALE);
+                       mc->mc_skipped = 1;
+                       mc->mc_speculative = 1;
+                       continue;
+               }
+
+               mc->mc_load = vdev_mirror_load(mm, mc->mc_vd, mc->mc_offset);
+               if (mc->mc_load > lowest_load)
+                       continue;
+
+               if (mc->mc_load < lowest_load) {
+                       lowest_load = mc->mc_load;
+                       mm->mm_preferred_cnt = 0;
+               }
+               mm->mm_preferred[mm->mm_preferred_cnt] = c;
+               mm->mm_preferred_cnt++;
+       }
+
+       if (mm->mm_preferred_cnt == 1) {
+               vdev_queue_register_lastoffset(
+                   mm->mm_child[mm->mm_preferred[0]].mc_vd, zio);
+               return (mm->mm_preferred[0]);
+       }
+
+       if (mm->mm_preferred_cnt > 1) {
+               int c = vdev_mirror_preferred_child_randomize(zio);
+
+               vdev_queue_register_lastoffset(mm->mm_child[c].mc_vd, zio);
+               return (c);
        }
 
        /*
         * Every device is either missing or has this txg in its DTL.
         * Look for any child we haven't already tried before giving up.
         */
-       for (c = 0; c < mm->mm_children; c++)
-               if (!mm->mm_child[c].mc_tried)
+       for (c = 0; c < mm->mm_children; c++) {
+               if (!mm->mm_child[c].mc_tried) {
+                       vdev_queue_register_lastoffset(mm->mm_child[c].mc_vd,
+                           zio);
                        return (c);
+               }
+       }
 
        /*
         * Every child failed.  There's no place left to look.
@@ -334,7 +419,7 @@ vdev_mirror_io_start(zio_t *zio)
        mirror_child_t *mc;
        int c, children;
 
-       mm = vdev_mirror_map_alloc(zio);
+       mm = vdev_mirror_map_init(zio);
 
        if (zio->io_type == ZIO_TYPE_READ) {
                if ((zio->io_flags & ZIO_FLAG_SCRUB) && !mm->mm_replacing) {
@@ -559,6 +644,25 @@ vdev_ops_t vdev_spare_ops = {
 };
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
-module_param(zfs_vdev_mirror_switch_us, int, 0644);
-MODULE_PARM_DESC(zfs_vdev_mirror_switch_us, "Switch mirrors every N usecs");
+module_param(zfs_vdev_mirror_rotating_inc, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_mirror_rotating_inc,
+       "Rotating media load increment for non-seeking I/O's");
+
+module_param(zfs_vdev_mirror_rotating_seek_inc, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_mirror_rotating_seek_inc,
+       "Rotating media load increment for seeking I/O's");
+
+module_param(zfs_vdev_mirror_rotating_seek_offset, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_mirror_rotating_seek_offset,
+       "Offset in bytes from the last I/O which "
+       "triggers a reduced rotating media seek increment");
+
+module_param(zfs_vdev_mirror_non_rotating_inc, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_mirror_non_rotating_inc,
+       "Non-rotating media load increment for non-seeking I/O's");
+
+module_param(zfs_vdev_mirror_non_rotating_seek_inc, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_mirror_non_rotating_seek_inc,
+       "Non-rotating media load increment for seeking I/O's");
+
 #endif
index 4ed62f96328c8da8aee7a083afe2c9b3a07c1093..8f394eef5b6589e430972472365c8fc8829619e8 100644 (file)
@@ -33,6 +33,7 @@
 #include <sys/zio.h>
 #include <sys/avl.h>
 #include <sys/dsl_pool.h>
+#include <sys/metaslab_impl.h>
 #include <sys/spa.h>
 #include <sys/spa_impl.h>
 #include <sys/kstat.h>
@@ -171,23 +172,35 @@ int zfs_vdev_aggregation_limit = SPA_OLD_MAXBLOCKSIZE;
 int zfs_vdev_read_gap_limit = 32 << 10;
 int zfs_vdev_write_gap_limit = 4 << 10;
 
+/*
+ * Define the queue depth percentage for each top-level. This percentage is
+ * used in conjunction with zfs_vdev_async_max_active to determine how many
+ * allocations a specific top-level vdev should handle. Once the queue depth
+ * reaches zfs_vdev_queue_depth_pct * zfs_vdev_async_write_max_active / 100
+ * then allocator will stop allocating blocks on that top-level device.
+ * The default kernel setting is 1000% which will yield 100 allocations per
+ * device. For userland testing, the default setting is 300% which equates
+ * to 30 allocations per device.
+ */
+#ifdef _KERNEL
+int zfs_vdev_queue_depth_pct = 1000;
+#else
+int zfs_vdev_queue_depth_pct = 300;
+#endif
+
+
 int
 vdev_queue_offset_compare(const void *x1, const void *x2)
 {
-       const zio_t *z1 = x1;
-       const zio_t *z2 = x2;
+       const zio_t *z1 = (const zio_t *)x1;
+       const zio_t *z2 = (const zio_t *)x2;
 
-       if (z1->io_offset < z2->io_offset)
-               return (-1);
-       if (z1->io_offset > z2->io_offset)
-               return (1);
+       int cmp = AVL_CMP(z1->io_offset, z2->io_offset);
 
-       if (z1 < z2)
-               return (-1);
-       if (z1 > z2)
-               return (1);
+       if (likely(cmp))
+               return (cmp);
 
-       return (0);
+       return (AVL_PCMP(z1, z2));
 }
 
 static inline avl_tree_t *
@@ -209,20 +222,15 @@ vdev_queue_type_tree(vdev_queue_t *vq, zio_type_t t)
 int
 vdev_queue_timestamp_compare(const void *x1, const void *x2)
 {
-       const zio_t *z1 = x1;
-       const zio_t *z2 = x2;
+       const zio_t *z1 = (const zio_t *)x1;
+       const zio_t *z2 = (const zio_t *)x2;
 
-       if (z1->io_timestamp < z2->io_timestamp)
-               return (-1);
-       if (z1->io_timestamp > z2->io_timestamp)
-               return (1);
+       int cmp = AVL_CMP(z1->io_timestamp, z2->io_timestamp);
 
-       if (z1 < z2)
-               return (-1);
-       if (z1 > z2)
-               return (1);
+       if (likely(cmp))
+               return (cmp);
 
-       return (0);
+       return (AVL_PCMP(z1, z2));
 }
 
 static int
@@ -383,6 +391,8 @@ vdev_queue_init(vdev_t *vd)
                avl_create(vdev_queue_class_tree(vq, p), compfn,
                        sizeof (zio_t), offsetof(struct zio, io_queue_node));
        }
+
+       vq->vq_lastoffset = 0;
 }
 
 void
@@ -484,7 +494,8 @@ vdev_queue_agg_io_done(zio_t *aio)
 {
        if (aio->io_type == ZIO_TYPE_READ) {
                zio_t *pio;
-               while ((pio = zio_walk_parents(aio)) != NULL) {
+               zio_link_t *zl = NULL;
+               while ((pio = zio_walk_parents(aio, &zl)) != NULL) {
                        bcopy((char *)aio->io_data + (pio->io_offset -
                            aio->io_offset), pio->io_data, pio->io_size);
                }
@@ -508,20 +519,17 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
        zio_t *first, *last, *aio, *dio, *mandatory, *nio;
        uint64_t maxgap = 0;
        uint64_t size;
+       uint64_t limit;
        boolean_t stretch = B_FALSE;
        avl_tree_t *t = vdev_queue_type_tree(vq, zio->io_type);
        enum zio_flag flags = zio->io_flags & ZIO_FLAG_AGG_INHERIT;
        void *buf;
 
-       if (zio->io_flags & ZIO_FLAG_DONT_AGGREGATE)
-               return (NULL);
+       limit = MAX(MIN(zfs_vdev_aggregation_limit,
+           spa_maxblocksize(vq->vq_vdev->vdev_spa)), 0);
 
-       /*
-        * Prevent users from setting the zfs_vdev_aggregation_limit
-        * tuning larger than SPA_MAXBLOCKSIZE.
-        */
-       zfs_vdev_aggregation_limit =
-           MIN(zfs_vdev_aggregation_limit, SPA_MAXBLOCKSIZE);
+       if (zio->io_flags & ZIO_FLAG_DONT_AGGREGATE || limit == 0)
+               return (NULL);
 
        first = last = zio;
 
@@ -549,7 +557,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
         */
        while ((dio = AVL_PREV(t, first)) != NULL &&
            (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags &&
-           IO_SPAN(dio, last) <= zfs_vdev_aggregation_limit &&
+           IO_SPAN(dio, last) <= limit &&
            IO_GAP(dio, first) <= maxgap) {
                first = dio;
                if (mandatory == NULL && !(first->io_flags & ZIO_FLAG_OPTIONAL))
@@ -570,7 +578,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
         */
        while ((dio = AVL_NEXT(t, last)) != NULL &&
            (dio->io_flags & ZIO_FLAG_AGG_INHERIT) == flags &&
-           IO_SPAN(first, dio) <= zfs_vdev_aggregation_limit &&
+           IO_SPAN(first, dio) <= limit &&
            IO_GAP(last, dio) <= maxgap) {
                last = dio;
                if (!(last->io_flags & ZIO_FLAG_OPTIONAL))
@@ -616,7 +624,7 @@ vdev_queue_aggregate(vdev_queue_t *vq, zio_t *zio)
                return (NULL);
 
        size = IO_SPAN(first, last);
-       ASSERT3U(size, <=, zfs_vdev_aggregation_limit);
+       ASSERT3U(size, <=, limit);
 
        buf = zio_buf_alloc_flags(size, KM_NOSLEEP);
        if (buf == NULL)
@@ -763,9 +771,6 @@ vdev_queue_io_done(zio_t *zio)
        vdev_queue_t *vq = &zio->io_vd->vdev_queue;
        zio_t *nio;
 
-       if (zio_injection_enabled)
-               delay(SEC_TO_TICK(zio_handle_io_delay(zio)));
-
        mutex_enter(&vq->vq_lock);
 
        vdev_queue_pending_remove(vq, zio);
@@ -788,6 +793,30 @@ vdev_queue_io_done(zio_t *zio)
        mutex_exit(&vq->vq_lock);
 }
 
+/*
+ * As these three methods are only used for load calculations we're not
+ * concerned if we get an incorrect value on 32bit platforms due to lack of
+ * vq_lock mutex use here, instead we prefer to keep it lock free for
+ * performance.
+ */
+int
+vdev_queue_length(vdev_t *vd)
+{
+       return (avl_numnodes(&vd->vdev_queue.vq_active_tree));
+}
+
+uint64_t
+vdev_queue_lastoffset(vdev_t *vd)
+{
+       return (vd->vdev_queue.vq_lastoffset);
+}
+
+void
+vdev_queue_register_lastoffset(vdev_t *vd, zio_t *zio)
+{
+       vd->vdev_queue.vq_lastoffset = zio->io_offset + zio->io_size;
+}
+
 #if defined(_KERNEL) && defined(HAVE_SPL)
 module_param(zfs_vdev_aggregation_limit, int, 0644);
 MODULE_PARM_DESC(zfs_vdev_aggregation_limit, "Max vdev I/O aggregation size");
@@ -846,4 +875,8 @@ MODULE_PARM_DESC(zfs_vdev_sync_write_max_active,
 module_param(zfs_vdev_sync_write_min_active, int, 0644);
 MODULE_PARM_DESC(zfs_vdev_sync_write_min_active,
        "Min active sync write I/Os per vdev");
+
+module_param(zfs_vdev_queue_depth_pct, int, 0644);
+MODULE_PARM_DESC(zfs_vdev_queue_depth_pct,
+       "Queue depth percentage for each top-level vdev");
 #endif
index b9479092c8429d7d688ac22f67a01aa88d58148e..d1b41536780530a639cf32e8f5247e5a79fc913d 100644 (file)
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2016 Gvozden Nešković. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -31,6 +32,8 @@
 #include <sys/zio_checksum.h>
 #include <sys/fs/zfs.h>
 #include <sys/fm/fs/zfs.h>
+#include <sys/vdev_raidz.h>
+#include <sys/vdev_raidz_impl.h>
 
 /*
  * Virtual device vector for RAID-Z.
  * or in concert to recover missing data columns.
  */
 
-typedef struct raidz_col {
-       uint64_t rc_devidx;             /* child device index for I/O */
-       uint64_t rc_offset;             /* device offset */
-       uint64_t rc_size;               /* I/O size */
-       void *rc_data;                  /* I/O data */
-       void *rc_gdata;                 /* used to store the "good" version */
-       int rc_error;                   /* I/O error for this device */
-       uint8_t rc_tried;               /* Did we attempt this I/O column? */
-       uint8_t rc_skipped;             /* Did we skip this I/O column? */
-} raidz_col_t;
-
-typedef struct raidz_map {
-       uint64_t rm_cols;               /* Regular column count */
-       uint64_t rm_scols;              /* Count including skipped columns */
-       uint64_t rm_bigcols;            /* Number of oversized columns */
-       uint64_t rm_asize;              /* Actual total I/O size */
-       uint64_t rm_missingdata;        /* Count of missing data devices */
-       uint64_t rm_missingparity;      /* Count of missing parity devices */
-       uint64_t rm_firstdatacol;       /* First data column/parity count */
-       uint64_t rm_nskip;              /* Skipped sectors for padding */
-       uint64_t rm_skipstart;          /* Column index of padding start */
-       void *rm_datacopy;              /* rm_asize-buffer of copied data */
-       uintptr_t rm_reports;           /* # of referencing checksum reports */
-       uint8_t rm_freed;               /* map no longer has referencing ZIO */
-       uint8_t rm_ecksuminjected;      /* checksum error was injected */
-       raidz_col_t rm_col[1];          /* Flexible array of I/O columns */
-} raidz_map_t;
-
 #define        VDEV_RAIDZ_P            0
 #define        VDEV_RAIDZ_Q            1
 #define        VDEV_RAIDZ_R            2
@@ -154,104 +129,7 @@ typedef struct raidz_map {
        VDEV_RAIDZ_64MUL_2((x), mask); \
 }
 
-/*
- * Force reconstruction to use the general purpose method.
- */
-int vdev_raidz_default_to_general;
-
-/* Powers of 2 in the Galois field defined above. */
-static const uint8_t vdev_raidz_pow2[256] = {
-       0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
-       0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
-       0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9,
-       0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
-       0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35,
-       0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
-       0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0,
-       0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
-       0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc,
-       0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
-       0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f,
-       0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
-       0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88,
-       0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
-       0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93,
-       0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
-       0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9,
-       0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
-       0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa,
-       0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
-       0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e,
-       0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
-       0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4,
-       0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
-       0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e,
-       0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
-       0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef,
-       0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
-       0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5,
-       0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
-       0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83,
-       0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01
-};
-/* Logs of 2 in the Galois field defined above. */
-static const uint8_t vdev_raidz_log2[256] = {
-       0x00, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6,
-       0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
-       0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81,
-       0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
-       0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21,
-       0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
-       0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9,
-       0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
-       0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd,
-       0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
-       0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd,
-       0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
-       0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e,
-       0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
-       0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b,
-       0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
-       0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d,
-       0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
-       0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c,
-       0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
-       0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd,
-       0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
-       0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e,
-       0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
-       0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76,
-       0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
-       0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa,
-       0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
-       0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51,
-       0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
-       0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8,
-       0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf,
-};
-
-static void vdev_raidz_generate_parity(raidz_map_t *rm);
-
-/*
- * Multiply a given number by 2 raised to the given power.
- */
-static uint8_t
-vdev_raidz_exp2(uint_t a, int exp)
-{
-       if (a == 0)
-               return (0);
-
-       ASSERT(exp >= 0);
-       ASSERT(vdev_raidz_log2[a] > 0 || a == 1);
-
-       exp += vdev_raidz_log2[a];
-       if (exp > 255)
-               exp -= 255;
-
-       return (vdev_raidz_pow2[exp]);
-}
-
-static void
+void
 vdev_raidz_map_free(raidz_map_t *rm)
 {
        int c;
@@ -437,7 +315,7 @@ static const zio_vsd_ops_t vdev_raidz_vsd_ops = {
  * Avoid inlining the function to keep vdev_raidz_io_start(), which
  * is this functions only caller, as small as possible on the stack.
  */
-noinline static raidz_map_t *
+noinline raidz_map_t *
 vdev_raidz_map_alloc(zio_t *zio, uint64_t unit_shift, uint64_t dcols,
     uint64_t nparity)
 {
@@ -579,6 +457,10 @@ vdev_raidz_map_alloc(zio_t *zio, uint64_t unit_shift, uint64_t dcols,
 
        zio->io_vsd = rm;
        zio->io_vsd_ops = &vdev_raidz_vsd_ops;
+
+       /* init RAIDZ parity ops */
+       rm->rm_ops = vdev_raidz_math_get_ops();
+
        return (rm);
 }
 
@@ -726,9 +608,13 @@ vdev_raidz_generate_parity_pqr(raidz_map_t *rm)
  * Generate RAID parity in the first virtual columns according to the number of
  * parity columns available.
  */
-static void
+void
 vdev_raidz_generate_parity(raidz_map_t *rm)
 {
+       /* Generate using the new math implementation */
+       if (vdev_raidz_math_generate(rm) != RAIDZ_ORIGINAL_IMPL)
+               return;
+
        switch (rm->rm_firstdatacol) {
        case 1:
                vdev_raidz_generate_parity_p(rm);
@@ -1217,8 +1103,8 @@ vdev_raidz_matrix_reconstruct(raidz_map_t *rm, int n, int nmissing,
        int i, j, x, cc, c;
        uint8_t *src;
        uint64_t ccount;
-       uint8_t *dst[VDEV_RAIDZ_MAXPARITY];
-       uint64_t dcount[VDEV_RAIDZ_MAXPARITY];
+       uint8_t *dst[VDEV_RAIDZ_MAXPARITY] = { NULL };
+       uint64_t dcount[VDEV_RAIDZ_MAXPARITY] = { 0 };
        uint8_t log = 0;
        uint8_t val;
        int ll;
@@ -1392,12 +1278,12 @@ vdev_raidz_reconstruct_general(raidz_map_t *rm, int *tgts, int ntgts)
        return (code);
 }
 
-static int
-vdev_raidz_reconstruct(raidz_map_t *rm, int *t, int nt)
+int
+vdev_raidz_reconstruct(raidz_map_t *rm, const int *t, int nt)
 {
        int tgts[VDEV_RAIDZ_MAXPARITY], *dt;
        int ntgts;
-       int i, c;
+       int i, c, ret;
        int code;
        int nbadparity, nbaddata;
        int parity_valid[VDEV_RAIDZ_MAXPARITY];
@@ -1435,34 +1321,38 @@ vdev_raidz_reconstruct(raidz_map_t *rm, int *t, int nt)
 
        dt = &tgts[nbadparity];
 
+
+       /* Reconstruct using the new math implementation */
+       ret = vdev_raidz_math_reconstruct(rm, parity_valid, dt, nbaddata);
+       if (ret != RAIDZ_ORIGINAL_IMPL)
+               return (ret);
+
        /*
         * See if we can use any of our optimized reconstruction routines.
         */
-       if (!vdev_raidz_default_to_general) {
-               switch (nbaddata) {
-               case 1:
-                       if (parity_valid[VDEV_RAIDZ_P])
-                               return (vdev_raidz_reconstruct_p(rm, dt, 1));
+       switch (nbaddata) {
+       case 1:
+               if (parity_valid[VDEV_RAIDZ_P])
+                       return (vdev_raidz_reconstruct_p(rm, dt, 1));
 
-                       ASSERT(rm->rm_firstdatacol > 1);
+               ASSERT(rm->rm_firstdatacol > 1);
 
-                       if (parity_valid[VDEV_RAIDZ_Q])
-                               return (vdev_raidz_reconstruct_q(rm, dt, 1));
+               if (parity_valid[VDEV_RAIDZ_Q])
+                       return (vdev_raidz_reconstruct_q(rm, dt, 1));
 
-                       ASSERT(rm->rm_firstdatacol > 2);
-                       break;
+               ASSERT(rm->rm_firstdatacol > 2);
+               break;
 
-               case 2:
-                       ASSERT(rm->rm_firstdatacol > 1);
+       case 2:
+               ASSERT(rm->rm_firstdatacol > 1);
 
-                       if (parity_valid[VDEV_RAIDZ_P] &&
-                           parity_valid[VDEV_RAIDZ_Q])
-                               return (vdev_raidz_reconstruct_pq(rm, dt, 2));
+               if (parity_valid[VDEV_RAIDZ_P] &&
+                   parity_valid[VDEV_RAIDZ_Q])
+                       return (vdev_raidz_reconstruct_pq(rm, dt, 2));
 
-                       ASSERT(rm->rm_firstdatacol > 2);
+               ASSERT(rm->rm_firstdatacol > 2);
 
-                       break;
-               }
+               break;
        }
 
        code = vdev_raidz_reconstruct_general(rm, tgts, ntgts);
@@ -1714,6 +1604,13 @@ raidz_parity_verify(zio_t *zio, raidz_map_t *rm)
        int c, ret = 0;
        raidz_col_t *rc;
 
+       blkptr_t *bp = zio->io_bp;
+       enum zio_checksum checksum = (bp == NULL ? zio->io_prop.zp_checksum :
+           (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
+
+       if (checksum == ZIO_CHECKSUM_NOPARITY)
+               return (ret);
+
        for (c = 0; c < rm->rm_firstdatacol; c++) {
                rc = &rm->rm_col[c];
                if (!rc->rc_tried || rc->rc_error != 0)
@@ -1739,11 +1636,6 @@ raidz_parity_verify(zio_t *zio, raidz_map_t *rm)
        return (ret);
 }
 
-/*
- * Keep statistics on all the ways that we used parity to correct data.
- */
-static uint64_t raidz_corrected[1 << VDEV_RAIDZ_MAXPARITY];
-
 static int
 vdev_raidz_worst_error(raidz_map_t *rm)
 {
@@ -1845,7 +1737,6 @@ vdev_raidz_combrec(zio_t *zio, int total_errors, int data_errors)
                         */
                        code = vdev_raidz_reconstruct(rm, tgts, n);
                        if (raidz_checksum_verify(zio) == 0) {
-                               atomic_inc_64(&raidz_corrected[code]);
 
                                for (i = 0; i < n; i++) {
                                        c = tgts[i];
@@ -2058,8 +1949,6 @@ vdev_raidz_io_done(zio_t *zio)
                        code = vdev_raidz_reconstruct(rm, tgts, n);
 
                        if (raidz_checksum_verify(zio) == 0) {
-                               atomic_inc_64(&raidz_corrected[code]);
-
                                /*
                                 * If we read more parity disks than were used
                                 * for reconstruction, confirm that the other
diff --git a/zfs/module/zfs/vdev_raidz_math.c b/zfs/module/zfs/vdev_raidz_math.c
new file mode 100644 (file)
index 0000000..c22d544
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#include <sys/zfs_context.h>
+#include <sys/types.h>
+#include <sys/zio.h>
+#include <sys/debug.h>
+#include <sys/zfs_debug.h>
+
+#include <sys/vdev_raidz.h>
+#include <sys/vdev_raidz_impl.h>
+
+extern boolean_t raidz_will_scalar_work(void);
+
+/* Opaque implementation with NULL methods to represent original methods */
+static const raidz_impl_ops_t vdev_raidz_original_impl = {
+       .name = "original",
+       .is_supported = raidz_will_scalar_work,
+};
+
+/* RAIDZ parity op that contain the fastest methods */
+static raidz_impl_ops_t vdev_raidz_fastest_impl = {
+       .name = "fastest"
+};
+
+/* All compiled in implementations */
+const raidz_impl_ops_t *raidz_all_maths[] = {
+       &vdev_raidz_original_impl,
+       &vdev_raidz_scalar_impl,
+#if defined(__x86_64) && defined(HAVE_SSE2)    /* only x86_64 for now */
+       &vdev_raidz_sse2_impl,
+#endif
+#if defined(__x86_64) && defined(HAVE_SSSE3)   /* only x86_64 for now */
+       &vdev_raidz_ssse3_impl,
+#endif
+#if defined(__x86_64) && defined(HAVE_AVX2)    /* only x86_64 for now */
+       &vdev_raidz_avx2_impl,
+#endif
+#if defined(__aarch64__)
+       &vdev_raidz_aarch64_neon_impl,
+       &vdev_raidz_aarch64_neonx2_impl,
+#endif
+};
+
+/* Indicate that benchmark has been completed */
+static boolean_t raidz_math_initialized = B_FALSE;
+
+/* Select raidz implementation */
+#define        IMPL_FASTEST    (UINT32_MAX)
+#define        IMPL_CYCLE      (UINT32_MAX - 1)
+#define        IMPL_ORIGINAL   (0)
+#define        IMPL_SCALAR     (1)
+
+#define        RAIDZ_IMPL_READ(i)      (*(volatile uint32_t *) &(i))
+
+static uint32_t zfs_vdev_raidz_impl = IMPL_SCALAR;
+static uint32_t user_sel_impl = IMPL_FASTEST;
+
+/* Hold all supported implementations */
+static size_t raidz_supp_impl_cnt = 0;
+static raidz_impl_ops_t *raidz_supp_impl[ARRAY_SIZE(raidz_all_maths)];
+
+/*
+ * kstats values for supported implementations
+ * Values represent per disk throughput of 8 disk+parity raidz vdev [B/s]
+ */
+static raidz_impl_kstat_t raidz_impl_kstats[ARRAY_SIZE(raidz_all_maths) + 1];
+
+/* kstat for benchmarked implementations */
+static kstat_t *raidz_math_kstat = NULL;
+
+/*
+ * Selects the raidz operation for raidz_map
+ * If rm_ops is set to NULL original raidz implementation will be used
+ */
+raidz_impl_ops_t *
+vdev_raidz_math_get_ops()
+{
+       raidz_impl_ops_t *ops = NULL;
+       const uint32_t impl = RAIDZ_IMPL_READ(zfs_vdev_raidz_impl);
+
+       switch (impl) {
+       case IMPL_FASTEST:
+               ASSERT(raidz_math_initialized);
+               ops = &vdev_raidz_fastest_impl;
+               break;
+#if !defined(_KERNEL)
+       case IMPL_CYCLE:
+       {
+               ASSERT(raidz_math_initialized);
+               ASSERT3U(raidz_supp_impl_cnt, >, 0);
+               /* Cycle through all supported implementations */
+               static size_t cycle_impl_idx = 0;
+               size_t idx = (++cycle_impl_idx) % raidz_supp_impl_cnt;
+               ops = raidz_supp_impl[idx];
+       }
+       break;
+#endif
+       case IMPL_ORIGINAL:
+               ops = (raidz_impl_ops_t *) &vdev_raidz_original_impl;
+               break;
+       case IMPL_SCALAR:
+               ops = (raidz_impl_ops_t *) &vdev_raidz_scalar_impl;
+               break;
+       default:
+               ASSERT3U(impl, <, raidz_supp_impl_cnt);
+               ASSERT3U(raidz_supp_impl_cnt, >, 0);
+               ops = raidz_supp_impl[impl];
+               break;
+       }
+
+       ASSERT3P(ops, !=, NULL);
+
+       return (ops);
+}
+
+/*
+ * Select parity generation method for raidz_map
+ */
+int
+vdev_raidz_math_generate(raidz_map_t *rm)
+{
+       raidz_gen_f gen_parity = NULL;
+
+       switch (raidz_parity(rm)) {
+               case 1:
+                       gen_parity = rm->rm_ops->gen[RAIDZ_GEN_P];
+                       break;
+               case 2:
+                       gen_parity = rm->rm_ops->gen[RAIDZ_GEN_PQ];
+                       break;
+               case 3:
+                       gen_parity = rm->rm_ops->gen[RAIDZ_GEN_PQR];
+                       break;
+               default:
+                       gen_parity = NULL;
+                       cmn_err(CE_PANIC, "invalid RAID-Z configuration %d",
+                               raidz_parity(rm));
+                       break;
+       }
+
+       /* if method is NULL execute the original implementation */
+       if (gen_parity == NULL)
+               return (RAIDZ_ORIGINAL_IMPL);
+
+       gen_parity(rm);
+
+       return (0);
+}
+
+static raidz_rec_f
+reconstruct_fun_p_sel(raidz_map_t *rm, const int *parity_valid,
+       const int nbaddata)
+{
+       if (nbaddata == 1 && parity_valid[CODE_P]) {
+               return (rm->rm_ops->rec[RAIDZ_REC_P]);
+       }
+       return ((raidz_rec_f) NULL);
+}
+
+static raidz_rec_f
+reconstruct_fun_pq_sel(raidz_map_t *rm, const int *parity_valid,
+       const int nbaddata)
+{
+       if (nbaddata == 1) {
+               if (parity_valid[CODE_P]) {
+                       return (rm->rm_ops->rec[RAIDZ_REC_P]);
+               } else if (parity_valid[CODE_Q]) {
+                       return (rm->rm_ops->rec[RAIDZ_REC_Q]);
+               }
+       } else if (nbaddata == 2 &&
+               parity_valid[CODE_P] && parity_valid[CODE_Q]) {
+               return (rm->rm_ops->rec[RAIDZ_REC_PQ]);
+       }
+       return ((raidz_rec_f) NULL);
+}
+
+static raidz_rec_f
+reconstruct_fun_pqr_sel(raidz_map_t *rm, const int *parity_valid,
+       const int nbaddata)
+{
+       if (nbaddata == 1) {
+               if (parity_valid[CODE_P]) {
+                       return (rm->rm_ops->rec[RAIDZ_REC_P]);
+               } else if (parity_valid[CODE_Q]) {
+                       return (rm->rm_ops->rec[RAIDZ_REC_Q]);
+               } else if (parity_valid[CODE_R]) {
+                       return (rm->rm_ops->rec[RAIDZ_REC_R]);
+               }
+       } else if (nbaddata == 2) {
+               if (parity_valid[CODE_P] && parity_valid[CODE_Q]) {
+                       return (rm->rm_ops->rec[RAIDZ_REC_PQ]);
+               } else if (parity_valid[CODE_P] && parity_valid[CODE_R]) {
+                       return (rm->rm_ops->rec[RAIDZ_REC_PR]);
+               } else if (parity_valid[CODE_Q] && parity_valid[CODE_R]) {
+                       return (rm->rm_ops->rec[RAIDZ_REC_QR]);
+               }
+       } else if (nbaddata == 3 &&
+               parity_valid[CODE_P] && parity_valid[CODE_Q] &&
+               parity_valid[CODE_R]) {
+               return (rm->rm_ops->rec[RAIDZ_REC_PQR]);
+       }
+       return ((raidz_rec_f) NULL);
+}
+
+/*
+ * Select data reconstruction method for raidz_map
+ * @parity_valid - Parity validity flag
+ * @dt           - Failed data index array
+ * @nbaddata     - Number of failed data columns
+ */
+int
+vdev_raidz_math_reconstruct(raidz_map_t *rm, const int *parity_valid,
+       const int *dt, const int nbaddata)
+{
+       raidz_rec_f rec_data = NULL;
+
+       switch (raidz_parity(rm)) {
+       case PARITY_P:
+               rec_data = reconstruct_fun_p_sel(rm, parity_valid, nbaddata);
+               break;
+       case PARITY_PQ:
+               rec_data = reconstruct_fun_pq_sel(rm, parity_valid, nbaddata);
+               break;
+       case PARITY_PQR:
+               rec_data = reconstruct_fun_pqr_sel(rm, parity_valid, nbaddata);
+               break;
+       default:
+               cmn_err(CE_PANIC, "invalid RAID-Z configuration %d",
+                   raidz_parity(rm));
+               break;
+       }
+
+       if (rec_data == NULL)
+               return (RAIDZ_ORIGINAL_IMPL);
+       else
+               return (rec_data(rm, dt));
+}
+
+const char *raidz_gen_name[] = {
+       "gen_p", "gen_pq", "gen_pqr"
+};
+const char *raidz_rec_name[] = {
+       "rec_p", "rec_q", "rec_r",
+       "rec_pq", "rec_pr", "rec_qr", "rec_pqr"
+};
+
+#define        RAIDZ_KSTAT_LINE_LEN    (17 + 10*12 + 1)
+
+static int
+raidz_math_kstat_headers(char *buf, size_t size)
+{
+       int i;
+       ssize_t off;
+
+       ASSERT3U(size, >=, RAIDZ_KSTAT_LINE_LEN);
+
+       off = snprintf(buf, size, "%-17s", "implementation");
+
+       for (i = 0; i < ARRAY_SIZE(raidz_gen_name); i++)
+               off += snprintf(buf + off, size - off, "%-16s",
+                   raidz_gen_name[i]);
+
+       for (i = 0; i < ARRAY_SIZE(raidz_rec_name); i++)
+               off += snprintf(buf + off, size - off, "%-16s",
+                   raidz_rec_name[i]);
+
+       (void) snprintf(buf + off, size - off, "\n");
+
+       return (0);
+}
+
+static int
+raidz_math_kstat_data(char *buf, size_t size, void *data)
+{
+       raidz_impl_kstat_t * fstat = &raidz_impl_kstats[raidz_supp_impl_cnt];
+       raidz_impl_kstat_t * cstat = (raidz_impl_kstat_t *) data;
+       ssize_t off = 0;
+       int i;
+
+       ASSERT3U(size, >=, RAIDZ_KSTAT_LINE_LEN);
+
+       if (cstat == fstat) {
+               off += snprintf(buf + off, size - off, "%-17s", "fastest");
+
+               for (i = 0; i < ARRAY_SIZE(raidz_gen_name); i++) {
+                       int id = fstat->gen[i];
+                       off += snprintf(buf + off, size - off, "%-16s",
+                           raidz_supp_impl[id]->name);
+               }
+               for (i = 0; i < ARRAY_SIZE(raidz_rec_name); i++) {
+                       int id = fstat->rec[i];
+                       off += snprintf(buf + off, size - off, "%-16s",
+                           raidz_supp_impl[id]->name);
+               }
+       } else {
+               ptrdiff_t id = cstat - raidz_impl_kstats;
+
+               off += snprintf(buf + off, size - off, "%-17s",
+                   raidz_supp_impl[id]->name);
+
+               for (i = 0; i < ARRAY_SIZE(raidz_gen_name); i++)
+                       off += snprintf(buf + off, size - off, "%-16llu",
+                           (u_longlong_t) cstat->gen[i]);
+
+               for (i = 0; i < ARRAY_SIZE(raidz_rec_name); i++)
+                       off += snprintf(buf + off, size - off, "%-16llu",
+                           (u_longlong_t) cstat->rec[i]);
+       }
+
+       (void) snprintf(buf + off, size - off, "\n");
+
+       return (0);
+}
+
+static void *
+raidz_math_kstat_addr(kstat_t *ksp, loff_t n)
+{
+       if (n <= raidz_supp_impl_cnt)
+               ksp->ks_private = (void *) (raidz_impl_kstats + n);
+       else
+               ksp->ks_private = NULL;
+
+       return (ksp->ks_private);
+}
+
+#define        BENCH_D_COLS    (8ULL)
+#define        BENCH_COLS      (BENCH_D_COLS + PARITY_PQR)
+#define        BENCH_ZIO_SIZE  (1ULL << SPA_OLD_MAXBLOCKSHIFT) /* 128 kiB */
+#define        BENCH_NS        MSEC2NSEC(25)                   /* 25ms */
+
+typedef void (*benchmark_fn)(raidz_map_t *rm, const int fn);
+
+static void
+benchmark_gen_impl(raidz_map_t *rm, const int fn)
+{
+       (void) fn;
+       vdev_raidz_generate_parity(rm);
+}
+
+static void
+benchmark_rec_impl(raidz_map_t *rm, const int fn)
+{
+       static const int rec_tgt[7][3] = {
+               {1, 2, 3},      /* rec_p:   bad QR & D[0]       */
+               {0, 2, 3},      /* rec_q:   bad PR & D[0]       */
+               {0, 1, 3},      /* rec_r:   bad PQ & D[0]       */
+               {2, 3, 4},      /* rec_pq:  bad R  & D[0][1]    */
+               {1, 3, 4},      /* rec_pr:  bad Q  & D[0][1]    */
+               {0, 3, 4},      /* rec_qr:  bad P  & D[0][1]    */
+               {3, 4, 5}       /* rec_pqr: bad    & D[0][1][2] */
+       };
+
+       vdev_raidz_reconstruct(rm, rec_tgt[fn], 3);
+}
+
+/*
+ * Benchmarking of all supported implementations (raidz_supp_impl_cnt)
+ * is performed by setting the rm_ops pointer and calling the top level
+ * generate/reconstruct methods of bench_rm.
+ */
+static void
+benchmark_raidz_impl(raidz_map_t *bench_rm, const int fn, benchmark_fn bench_fn)
+{
+       uint64_t run_cnt, speed, best_speed = 0;
+       hrtime_t t_start, t_diff;
+       raidz_impl_ops_t *curr_impl;
+       raidz_impl_kstat_t * fstat = &raidz_impl_kstats[raidz_supp_impl_cnt];
+       int impl, i;
+
+       for (impl = 0; impl < raidz_supp_impl_cnt; impl++) {
+               /* set an implementation to benchmark */
+               curr_impl = raidz_supp_impl[impl];
+               bench_rm->rm_ops = curr_impl;
+
+               run_cnt = 0;
+               t_start = gethrtime();
+
+               do {
+                       for (i = 0; i < 25; i++, run_cnt++)
+                               bench_fn(bench_rm, fn);
+
+                       t_diff = gethrtime() - t_start;
+               } while (t_diff < BENCH_NS);
+
+               speed = run_cnt * BENCH_ZIO_SIZE * NANOSEC;
+               speed /= (t_diff * BENCH_COLS);
+
+               if (bench_fn == benchmark_gen_impl)
+                       raidz_impl_kstats[impl].gen[fn] = speed;
+               else
+                       raidz_impl_kstats[impl].rec[fn] = speed;
+
+               /* Update fastest implementation method */
+               if (speed > best_speed) {
+                       best_speed = speed;
+
+                       if (bench_fn == benchmark_gen_impl) {
+                               fstat->gen[fn] = impl;
+                               vdev_raidz_fastest_impl.gen[fn] =
+                                   curr_impl->gen[fn];
+                       } else {
+                               fstat->rec[fn] = impl;
+                               vdev_raidz_fastest_impl.rec[fn] =
+                                   curr_impl->rec[fn];
+                       }
+               }
+       }
+}
+
+void
+vdev_raidz_math_init(void)
+{
+       raidz_impl_ops_t *curr_impl;
+       zio_t *bench_zio = NULL;
+       raidz_map_t *bench_rm = NULL;
+       uint64_t bench_parity;
+       int i, c, fn;
+
+       /* move supported impl into raidz_supp_impl */
+       for (i = 0, c = 0; i < ARRAY_SIZE(raidz_all_maths); i++) {
+               curr_impl = (raidz_impl_ops_t *) raidz_all_maths[i];
+
+               /* initialize impl */
+               if (curr_impl->init)
+                       curr_impl->init();
+
+               if (curr_impl->is_supported())
+                       raidz_supp_impl[c++] = (raidz_impl_ops_t *) curr_impl;
+       }
+       membar_producer();              /* complete raidz_supp_impl[] init */
+       raidz_supp_impl_cnt = c;        /* number of supported impl */
+
+#if !defined(_KERNEL)
+       /* Skip benchmarking and use last implementation as fastest */
+       memcpy(&vdev_raidz_fastest_impl, raidz_supp_impl[raidz_supp_impl_cnt-1],
+           sizeof (vdev_raidz_fastest_impl));
+       strcpy(vdev_raidz_fastest_impl.name, "fastest");
+
+       raidz_math_initialized = B_TRUE;
+
+       /* Use 'cycle' math selection method for userspace */
+       VERIFY0(vdev_raidz_impl_set("cycle"));
+       return;
+#endif
+
+       /* Fake an zio and run the benchmark on it */
+       bench_zio = kmem_zalloc(sizeof (zio_t), KM_SLEEP);
+       bench_zio->io_offset = 0;
+       bench_zio->io_size = BENCH_ZIO_SIZE; /* only data columns */
+       bench_zio->io_data = zio_data_buf_alloc(BENCH_ZIO_SIZE);
+       VERIFY(bench_zio->io_data);
+       memset(bench_zio->io_data, 0xAA, BENCH_ZIO_SIZE); /* warm up */
+
+       /* Benchmark parity generation methods */
+       for (fn = 0; fn < RAIDZ_GEN_NUM; fn++) {
+               bench_parity = fn + 1;
+               /* New raidz_map is needed for each generate_p/q/r */
+               bench_rm = vdev_raidz_map_alloc(bench_zio, SPA_MINBLOCKSHIFT,
+                   BENCH_D_COLS + bench_parity, bench_parity);
+
+               benchmark_raidz_impl(bench_rm, fn, benchmark_gen_impl);
+
+               vdev_raidz_map_free(bench_rm);
+       }
+
+       /* Benchmark data reconstruction methods */
+       bench_rm = vdev_raidz_map_alloc(bench_zio, SPA_MINBLOCKSHIFT,
+           BENCH_COLS, PARITY_PQR);
+
+       for (fn = 0; fn < RAIDZ_REC_NUM; fn++)
+               benchmark_raidz_impl(bench_rm, fn, benchmark_rec_impl);
+
+       vdev_raidz_map_free(bench_rm);
+
+       /* cleanup the bench zio */
+       zio_data_buf_free(bench_zio->io_data, BENCH_ZIO_SIZE);
+       kmem_free(bench_zio, sizeof (zio_t));
+
+       /* install kstats for all impl */
+       raidz_math_kstat = kstat_create("zfs", 0, "vdev_raidz_bench", "misc",
+               KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);
+
+       if (raidz_math_kstat != NULL) {
+               raidz_math_kstat->ks_data = NULL;
+               raidz_math_kstat->ks_ndata = UINT32_MAX;
+               kstat_set_raw_ops(raidz_math_kstat,
+                   raidz_math_kstat_headers,
+                   raidz_math_kstat_data,
+                   raidz_math_kstat_addr);
+               kstat_install(raidz_math_kstat);
+       }
+
+       /* Finish initialization */
+       atomic_swap_32(&zfs_vdev_raidz_impl, user_sel_impl);
+       raidz_math_initialized = B_TRUE;
+}
+
+void
+vdev_raidz_math_fini(void)
+{
+       raidz_impl_ops_t const *curr_impl;
+       int i;
+
+       if (raidz_math_kstat != NULL) {
+               kstat_delete(raidz_math_kstat);
+               raidz_math_kstat = NULL;
+       }
+
+       /* fini impl */
+       for (i = 0; i < ARRAY_SIZE(raidz_all_maths); i++) {
+               curr_impl = raidz_all_maths[i];
+               if (curr_impl->fini)
+                       curr_impl->fini();
+       }
+}
+
+static const struct {
+       char    *name;
+       uint32_t sel;
+} math_impl_opts[] = {
+#if !defined(_KERNEL)
+               { "cycle",      IMPL_CYCLE },
+#endif
+               { "fastest",    IMPL_FASTEST },
+               { "original",   IMPL_ORIGINAL },
+               { "scalar",     IMPL_SCALAR }
+};
+
+/*
+ * Function sets desired raidz implementation.
+ *
+ * If we are called before init(), user preference will be saved in
+ * user_sel_impl, and applied in later init() call. This occurs when module
+ * parameter is specified on module load. Otherwise, directly update
+ * zfs_vdev_raidz_impl.
+ *
+ * @val                Name of raidz implementation to use
+ * @param      Unused.
+ */
+int
+vdev_raidz_impl_set(const char *val)
+{
+       int err = -EINVAL;
+       char req_name[RAIDZ_IMPL_NAME_MAX];
+       uint32_t impl = RAIDZ_IMPL_READ(user_sel_impl);
+       size_t i;
+
+       /* sanitize input */
+       i = strnlen(val, RAIDZ_IMPL_NAME_MAX);
+       if (i == 0 || i == RAIDZ_IMPL_NAME_MAX)
+               return (err);
+
+       strlcpy(req_name, val, RAIDZ_IMPL_NAME_MAX);
+       while (i > 0 && !!isspace(req_name[i-1]))
+               i--;
+       req_name[i] = '\0';
+
+       /* Check mandatory options */
+       for (i = 0; i < ARRAY_SIZE(math_impl_opts); i++) {
+               if (strcmp(req_name, math_impl_opts[i].name) == 0) {
+                       impl = math_impl_opts[i].sel;
+                       err = 0;
+                       break;
+               }
+       }
+
+       /* check all supported impl if init() was already called */
+       if (err != 0 && raidz_math_initialized) {
+               /* check all supported implementations */
+               for (i = 0; i < raidz_supp_impl_cnt; i++) {
+                       if (strcmp(req_name, raidz_supp_impl[i]->name) == 0) {
+                               impl = i;
+                               err = 0;
+                               break;
+                       }
+               }
+       }
+
+       if (err == 0) {
+               if (raidz_math_initialized)
+                       atomic_swap_32(&zfs_vdev_raidz_impl, impl);
+               else
+                       atomic_swap_32(&user_sel_impl, impl);
+       }
+
+       return (err);
+}
+
+#if defined(_KERNEL) && defined(HAVE_SPL)
+#include <linux/mod_compat.h>
+
+static int
+zfs_vdev_raidz_impl_set(const char *val, zfs_kernel_param_t *kp)
+{
+       return (vdev_raidz_impl_set(val));
+}
+
+static int
+zfs_vdev_raidz_impl_get(char *buffer, zfs_kernel_param_t *kp)
+{
+       int i, cnt = 0;
+       char *fmt;
+       const uint32_t impl = RAIDZ_IMPL_READ(zfs_vdev_raidz_impl);
+
+       ASSERT(raidz_math_initialized);
+
+       /* list mandatory options */
+       for (i = 0; i < ARRAY_SIZE(math_impl_opts) - 2; i++) {
+               fmt = (impl == math_impl_opts[i].sel) ? "[%s] " : "%s ";
+               cnt += sprintf(buffer + cnt, fmt, math_impl_opts[i].name);
+       }
+
+       /* list all supported implementations */
+       for (i = 0; i < raidz_supp_impl_cnt; i++) {
+               fmt = (i == impl) ? "[%s] " : "%s ";
+               cnt += sprintf(buffer + cnt, fmt, raidz_supp_impl[i]->name);
+       }
+
+       return (cnt);
+}
+
+module_param_call(zfs_vdev_raidz_impl, zfs_vdev_raidz_impl_set,
+       zfs_vdev_raidz_impl_get, NULL, 0644);
+MODULE_PARM_DESC(zfs_vdev_raidz_impl, "Select raidz implementation.");
+#endif
diff --git a/zfs/module/zfs/vdev_raidz_math_aarch64_neon.c b/zfs/module/zfs/vdev_raidz_math_aarch64_neon.c
new file mode 100644 (file)
index 0000000..f6a433f
--- /dev/null
@@ -0,0 +1,2210 @@
+/*
+ * 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 (C) 2016 Romain Dolbeau. All rights reserved.
+ */
+
+#include <sys/isa_defs.h>
+
+#if defined(__aarch64__)
+
+#include "vdev_raidz_math_aarch64_neon_common.h"
+
+#define        GEN_P_DEFINE() \
+       GEN_X_DEFINE_0_3() \
+       GEN_X_DEFINE_33_36()
+#define        GEN_P_STRIDE            4
+#define        GEN_P_P                 0, 1, 2, 3
+
+#define        GEN_PQ_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_8_9()      \
+       GEN_X_DEFINE_10_11()    \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_33_36()
+#define        GEN_PQ_STRIDE           4
+#define        GEN_PQ_D                0, 1, 2, 3
+#define        GEN_PQ_P                4, 5, 6, 7
+#define        GEN_PQ_Q                8, 9, 10, 11
+
+#define        GEN_PQR_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_31()       \
+       GEN_X_DEFINE_32()       \
+       GEN_X_DEFINE_33_36()
+#define        GEN_PQR_STRIDE          2
+#define        GEN_PQR_D               0, 1
+#define        GEN_PQR_P               2, 3
+#define        GEN_PQR_Q               4, 5
+#define        GEN_PQR_R               6, 7
+
+#define        REC_P_DEFINE() \
+       GEN_X_DEFINE_0_3() \
+       GEN_X_DEFINE_33_36()
+#define        REC_P_STRIDE            4
+#define        REC_P_X                 0, 1, 2, 3
+
+#define        REC_Q_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_33_36()
+#define        REC_Q_STRIDE            4
+#define        REC_Q_X                 0, 1, 2, 3
+
+#define        REC_R_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_33_36()
+#define        REC_R_STRIDE            4
+#define        REC_R_X                 0, 1, 2, 3
+
+#define        REC_PQ_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_31()       \
+       GEN_X_DEFINE_32()       \
+       GEN_X_DEFINE_33_36()
+#define        REC_PQ_STRIDE           2
+#define        REC_PQ_X                0, 1
+#define        REC_PQ_Y                2, 3
+#define        REC_PQ_D                4, 5
+
+#define        REC_PR_DEFINE() REC_PQ_DEFINE()
+#define        REC_PR_STRIDE           2
+#define        REC_PR_X                0, 1
+#define        REC_PR_Y                2, 3
+#define        REC_PR_D                4, 5
+
+#define        REC_QR_DEFINE() REC_PQ_DEFINE()
+#define        REC_QR_STRIDE           2
+#define        REC_QR_X                0, 1
+#define        REC_QR_Y                2, 3
+#define        REC_QR_D                4, 5
+
+#define        REC_PQR_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_8_9()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_31()       \
+       GEN_X_DEFINE_32()       \
+       GEN_X_DEFINE_33_36()
+#define        REC_PQR_STRIDE          2
+#define        REC_PQR_X               0, 1
+#define        REC_PQR_Y               2, 3
+#define        REC_PQR_Z               4, 5
+#define        REC_PQR_D               6, 7
+#define        REC_PQR_XS              6, 7
+#define        REC_PQR_YS              8, 9
+
+
+#include <sys/vdev_raidz_impl.h>
+#include "vdev_raidz_math_impl.h"
+
+DEFINE_GEN_METHODS(aarch64_neon);
+DEFINE_REC_METHODS(aarch64_neon);
+
+static boolean_t
+raidz_will_aarch64_neon_work(void)
+{
+       return (B_TRUE); // __arch64__ requires NEON
+}
+
+const raidz_impl_ops_t vdev_raidz_aarch64_neon_impl = {
+       .init = NULL,
+       .fini = NULL,
+       .gen = RAIDZ_GEN_METHODS(aarch64_neon),
+       .rec = RAIDZ_REC_METHODS(aarch64_neon),
+       .is_supported = &raidz_will_aarch64_neon_work,
+       .name = "aarch64_neon"
+};
+
+#endif /* defined(__aarch64__) */
+
+
+#if defined(__aarch64__)
+
+const uint8_t
+__attribute__((aligned(256))) gf_clmul_mod_lt[4*256][16] = {
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+           0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09,
+           0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
+           0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x11, 0x1e, 0x1b,
+           0x28, 0x2d, 0x22, 0x27, 0x3c, 0x39, 0x36, 0x33  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x06, 0x0c, 0x0a, 0x18, 0x1e, 0x14, 0x12,
+           0x30, 0x36, 0x3c, 0x3a, 0x28, 0x2e, 0x24, 0x22  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
+           0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38,
+           0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+           0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0a, 0x14, 0x1e, 0x28, 0x22, 0x3c, 0x36,
+           0x50, 0x5a, 0x44, 0x4e, 0x78, 0x72, 0x6c, 0x66  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31,
+           0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0c, 0x18, 0x14, 0x30, 0x3c, 0x28, 0x24,
+           0x60, 0x6c, 0x78, 0x74, 0x50, 0x5c, 0x48, 0x44  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23,
+           0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a,
+           0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0f, 0x1e, 0x11, 0x3c, 0x33, 0x22, 0x2d,
+           0x78, 0x77, 0x66, 0x69, 0x44, 0x4b, 0x5a, 0x55  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+           0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xf5, 0xe8, 0xcf, 0xd2, 0x81, 0x9c, 0xbb, 0xa6  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e,
+           0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xf5, 0xe8, 0xcf, 0xd2, 0x81, 0x9c, 0xbb, 0xa6  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x13, 0x26, 0x35, 0x4c, 0x5f, 0x6a, 0x79,
+           0x98, 0x8b, 0xbe, 0xad, 0xd4, 0xc7, 0xf2, 0xe1  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x69, 0x74, 0x53, 0x4e,
+           0xd2, 0xcf, 0xe8, 0xf5, 0xbb, 0xa6, 0x81, 0x9c  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x14, 0x28, 0x3c, 0x50, 0x44, 0x78, 0x6c,
+           0xa0, 0xb4, 0x88, 0x9c, 0xf0, 0xe4, 0xd8, 0xcc  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x69, 0x74, 0x53, 0x4e,
+           0xd2, 0xcf, 0xe8, 0xf5, 0xbb, 0xa6, 0x81, 0x9c  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x15, 0x2a, 0x3f, 0x54, 0x41, 0x7e, 0x6b,
+           0xa8, 0xbd, 0x82, 0x97, 0xfc, 0xe9, 0xd6, 0xc3  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x69, 0x74, 0x53, 0x4e,
+           0xcf, 0xd2, 0xf5, 0xe8, 0xa6, 0xbb, 0x9c, 0x81  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x16, 0x2c, 0x3a, 0x58, 0x4e, 0x74, 0x62,
+           0xb0, 0xa6, 0x9c, 0x8a, 0xe8, 0xfe, 0xc4, 0xd2  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x69, 0x74, 0x53, 0x4e,
+           0xcf, 0xd2, 0xf5, 0xe8, 0xa6, 0xbb, 0x9c, 0x81  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x17, 0x2e, 0x39, 0x5c, 0x4b, 0x72, 0x65,
+           0xb8, 0xaf, 0x96, 0x81, 0xe4, 0xf3, 0xca, 0xdd  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x4e, 0x53, 0x69, 0x74,
+           0x9c, 0x81, 0xbb, 0xa6, 0xd2, 0xcf, 0xf5, 0xe8  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x18, 0x30, 0x28, 0x60, 0x78, 0x50, 0x48,
+           0xc0, 0xd8, 0xf0, 0xe8, 0xa0, 0xb8, 0x90, 0x88  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x4e, 0x53, 0x69, 0x74,
+           0x9c, 0x81, 0xbb, 0xa6, 0xd2, 0xcf, 0xf5, 0xe8  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x19, 0x32, 0x2b, 0x64, 0x7d, 0x56, 0x4f,
+           0xc8, 0xd1, 0xfa, 0xe3, 0xac, 0xb5, 0x9e, 0x87  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x4e, 0x53, 0x69, 0x74,
+           0x81, 0x9c, 0xa6, 0xbb, 0xcf, 0xd2, 0xe8, 0xf5  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1a, 0x34, 0x2e, 0x68, 0x72, 0x5c, 0x46,
+           0xd0, 0xca, 0xe4, 0xfe, 0xb8, 0xa2, 0x8c, 0x96  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x4e, 0x53, 0x69, 0x74,
+           0x81, 0x9c, 0xa6, 0xbb, 0xcf, 0xd2, 0xe8, 0xf5  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1b, 0x36, 0x2d, 0x6c, 0x77, 0x5a, 0x41,
+           0xd8, 0xc3, 0xee, 0xf5, 0xb4, 0xaf, 0x82, 0x99  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x53, 0x4e, 0x74, 0x69,
+           0xa6, 0xbb, 0x81, 0x9c, 0xf5, 0xe8, 0xd2, 0xcf  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1c, 0x38, 0x24, 0x70, 0x6c, 0x48, 0x54,
+           0xe0, 0xfc, 0xd8, 0xc4, 0x90, 0x8c, 0xa8, 0xb4  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x53, 0x4e, 0x74, 0x69,
+           0xa6, 0xbb, 0x81, 0x9c, 0xf5, 0xe8, 0xd2, 0xcf  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x53, 0x4e, 0x74, 0x69,
+           0xbb, 0xa6, 0x9c, 0x81, 0xe8, 0xf5, 0xcf, 0xd2  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1e, 0x3c, 0x22, 0x78, 0x66, 0x44, 0x5a,
+           0xf0, 0xee, 0xcc, 0xd2, 0x88, 0x96, 0xb4, 0xaa  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x53, 0x4e, 0x74, 0x69,
+           0xbb, 0xa6, 0x9c, 0x81, 0xe8, 0xf5, 0xcf, 0xd2  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1f, 0x3e, 0x21, 0x7c, 0x63, 0x42, 0x5d,
+           0xf8, 0xe7, 0xc6, 0xd9, 0x84, 0x9b, 0xba, 0xa5  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xcd, 0xf7, 0xb9, 0x83, 0x25, 0x1f, 0x51, 0x6b  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xcd, 0xf7, 0xb9, 0x83, 0x25, 0x1f, 0x51, 0x6b  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x21, 0x42, 0x63, 0x84, 0xa5, 0xc6, 0xe7,
+           0x08, 0x29, 0x4a, 0x6b, 0x8c, 0xad, 0xce, 0xef  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xd0, 0xea, 0xa4, 0x9e, 0x38, 0x02, 0x4c, 0x76  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee,
+           0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xd0, 0xea, 0xa4, 0x9e, 0x38, 0x02, 0x4c, 0x76  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x23, 0x46, 0x65, 0x8c, 0xaf, 0xca, 0xe9,
+           0x18, 0x3b, 0x5e, 0x7d, 0x94, 0xb7, 0xd2, 0xf1  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xf5, 0xcf, 0x81, 0xbb,
+           0xf7, 0xcd, 0x83, 0xb9, 0x02, 0x38, 0x76, 0x4c  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x24, 0x48, 0x6c, 0x90, 0xb4, 0xd8, 0xfc,
+           0x20, 0x04, 0x68, 0x4c, 0xb0, 0x94, 0xf8, 0xdc  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xf5, 0xcf, 0x81, 0xbb,
+           0xf7, 0xcd, 0x83, 0xb9, 0x02, 0x38, 0x76, 0x4c  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x25, 0x4a, 0x6f, 0x94, 0xb1, 0xde, 0xfb,
+           0x28, 0x0d, 0x62, 0x47, 0xbc, 0x99, 0xf6, 0xd3  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xf5, 0xcf, 0x81, 0xbb,
+           0xea, 0xd0, 0x9e, 0xa4, 0x1f, 0x25, 0x6b, 0x51  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x26, 0x4c, 0x6a, 0x98, 0xbe, 0xd4, 0xf2,
+           0x30, 0x16, 0x7c, 0x5a, 0xa8, 0x8e, 0xe4, 0xc2  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xf5, 0xcf, 0x81, 0xbb,
+           0xea, 0xd0, 0x9e, 0xa4, 0x1f, 0x25, 0x6b, 0x51  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x38, 0x1f, 0x76, 0x51, 0xa4, 0x83, 0xea, 0xcd  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xd2, 0xe8, 0xbb, 0x81,
+           0xb9, 0x83, 0xd0, 0xea, 0x6b, 0x51, 0x02, 0x38  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x28, 0x50, 0x78, 0xa0, 0x88, 0xf0, 0xd8,
+           0x40, 0x68, 0x10, 0x38, 0xe0, 0xc8, 0xb0, 0x98  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xd2, 0xe8, 0xbb, 0x81,
+           0xb9, 0x83, 0xd0, 0xea, 0x6b, 0x51, 0x02, 0x38  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x29, 0x52, 0x7b, 0xa4, 0x8d, 0xf6, 0xdf,
+           0x48, 0x61, 0x1a, 0x33, 0xec, 0xc5, 0xbe, 0x97  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xd2, 0xe8, 0xbb, 0x81,
+           0xa4, 0x9e, 0xcd, 0xf7, 0x76, 0x4c, 0x1f, 0x25  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2a, 0x54, 0x7e, 0xa8, 0x82, 0xfc, 0xd6,
+           0x50, 0x7a, 0x04, 0x2e, 0xf8, 0xd2, 0xac, 0x86  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xd2, 0xe8, 0xbb, 0x81,
+           0xa4, 0x9e, 0xcd, 0xf7, 0x76, 0x4c, 0x1f, 0x25  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2b, 0x56, 0x7d, 0xac, 0x87, 0xfa, 0xd1,
+           0x58, 0x73, 0x0e, 0x25, 0xf4, 0xdf, 0xa2, 0x89  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xcf, 0xf5, 0xa6, 0x9c,
+           0x83, 0xb9, 0xea, 0xd0, 0x4c, 0x76, 0x25, 0x1f  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2c, 0x58, 0x74, 0xb0, 0x9c, 0xe8, 0xc4,
+           0x60, 0x4c, 0x38, 0x14, 0xd0, 0xfc, 0x88, 0xa4  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xcf, 0xf5, 0xa6, 0x9c,
+           0x83, 0xb9, 0xea, 0xd0, 0x4c, 0x76, 0x25, 0x1f  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2d, 0x5a, 0x77, 0xb4, 0x99, 0xee, 0xc3,
+           0x68, 0x45, 0x32, 0x1f, 0xdc, 0xf1, 0x86, 0xab  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xcf, 0xf5, 0xa6, 0x9c,
+           0x9e, 0xa4, 0xf7, 0xcd, 0x51, 0x6b, 0x38, 0x02  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2e, 0x5c, 0x72, 0xb8, 0x96, 0xe4, 0xca,
+           0x70, 0x5e, 0x2c, 0x02, 0xc8, 0xe6, 0x94, 0xba  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xcf, 0xf5, 0xa6, 0x9c,
+           0x9e, 0xa4, 0xf7, 0xcd, 0x51, 0x6b, 0x38, 0x02  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2f, 0x5e, 0x71, 0xbc, 0x93, 0xe2, 0xcd,
+           0x78, 0x57, 0x26, 0x09, 0xc4, 0xeb, 0x9a, 0xb5  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x25, 0x02, 0x6b, 0x4c, 0xb9, 0x9e, 0xf7, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x25, 0x02, 0x6b, 0x4c, 0xb9, 0x9e, 0xf7, 0xd0  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97,
+           0x88, 0xb9, 0xea, 0xdb, 0x4c, 0x7d, 0x2e, 0x1f  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x38, 0x1f, 0x76, 0x51, 0xa4, 0x83, 0xea, 0xcd  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x32, 0x64, 0x56, 0xc8, 0xfa, 0xac, 0x9e,
+           0x90, 0xa2, 0xf4, 0xc6, 0x58, 0x6a, 0x3c, 0x0e  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x38, 0x1f, 0x76, 0x51, 0xa4, 0x83, 0xea, 0xcd  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x33, 0x66, 0x55, 0xcc, 0xff, 0xaa, 0x99,
+           0x98, 0xab, 0xfe, 0xcd, 0x54, 0x67, 0x32, 0x01  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x81, 0xa6, 0xcf, 0xe8,
+           0x1f, 0x38, 0x51, 0x76, 0x9e, 0xb9, 0xd0, 0xf7  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x34, 0x68, 0x5c, 0xd0, 0xe4, 0xb8, 0x8c,
+           0xa0, 0x94, 0xc8, 0xfc, 0x70, 0x44, 0x18, 0x2c  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x81, 0xa6, 0xcf, 0xe8,
+           0x1f, 0x38, 0x51, 0x76, 0x9e, 0xb9, 0xd0, 0xf7  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x35, 0x6a, 0x5f, 0xd4, 0xe1, 0xbe, 0x8b,
+           0xa8, 0x9d, 0xc2, 0xf7, 0x7c, 0x49, 0x16, 0x23  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x81, 0xa6, 0xcf, 0xe8,
+           0x02, 0x25, 0x4c, 0x6b, 0x83, 0xa4, 0xcd, 0xea  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x36, 0x6c, 0x5a, 0xd8, 0xee, 0xb4, 0x82,
+           0xb0, 0x86, 0xdc, 0xea, 0x68, 0x5e, 0x04, 0x32  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x81, 0xa6, 0xcf, 0xe8,
+           0x02, 0x25, 0x4c, 0x6b, 0x83, 0xa4, 0xcd, 0xea  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x37, 0x6e, 0x59, 0xdc, 0xeb, 0xb2, 0x85,
+           0xb8, 0x8f, 0xd6, 0xe1, 0x64, 0x53, 0x0a, 0x3d  },
+       { 0x00, 0x27, 0x53, 0x74, 0xa6, 0x81, 0xf5, 0xd2,
+           0x51, 0x76, 0x02, 0x25, 0xf7, 0xd0, 0xa4, 0x83  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x38, 0x70, 0x48, 0xe0, 0xd8, 0x90, 0xa8,
+           0xc0, 0xf8, 0xb0, 0x88, 0x20, 0x18, 0x50, 0x68  },
+       { 0x00, 0x27, 0x53, 0x74, 0xa6, 0x81, 0xf5, 0xd2,
+           0x51, 0x76, 0x02, 0x25, 0xf7, 0xd0, 0xa4, 0x83  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x39, 0x72, 0x4b, 0xe4, 0xdd, 0x96, 0xaf,
+           0xc8, 0xf1, 0xba, 0x83, 0x2c, 0x15, 0x5e, 0x67  },
+       { 0x00, 0x27, 0x53, 0x74, 0xa6, 0x81, 0xf5, 0xd2,
+           0x4c, 0x6b, 0x1f, 0x38, 0xea, 0xcd, 0xb9, 0x9e  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xd0, 0xea, 0xa4, 0x9e, 0x38, 0x02, 0x4c, 0x76  },
+       { 0x00, 0x27, 0x53, 0x74, 0xa6, 0x81, 0xf5, 0xd2,
+           0x4c, 0x6b, 0x1f, 0x38, 0xea, 0xcd, 0xb9, 0x9e  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3b, 0x76, 0x4d, 0xec, 0xd7, 0x9a, 0xa1,
+           0xd8, 0xe3, 0xae, 0x95, 0x34, 0x0f, 0x42, 0x79  },
+       { 0x00, 0x27, 0x53, 0x74, 0xbb, 0x9c, 0xe8, 0xcf,
+           0x6b, 0x4c, 0x38, 0x1f, 0xd0, 0xf7, 0x83, 0xa4  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3c, 0x78, 0x44, 0xf0, 0xcc, 0x88, 0xb4,
+           0xe0, 0xdc, 0x98, 0xa4, 0x10, 0x2c, 0x68, 0x54  },
+       { 0x00, 0x27, 0x53, 0x74, 0xbb, 0x9c, 0xe8, 0xcf,
+           0x6b, 0x4c, 0x38, 0x1f, 0xd0, 0xf7, 0x83, 0xa4  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3d, 0x7a, 0x47, 0xf4, 0xc9, 0x8e, 0xb3,
+           0xe8, 0xd5, 0x92, 0xaf, 0x1c, 0x21, 0x66, 0x5b  },
+       { 0x00, 0x27, 0x53, 0x74, 0xbb, 0x9c, 0xe8, 0xcf,
+           0x76, 0x51, 0x25, 0x02, 0xcd, 0xea, 0x9e, 0xb9  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3e, 0x7c, 0x42, 0xf8, 0xc6, 0x84, 0xba,
+           0xf0, 0xce, 0x8c, 0xb2, 0x08, 0x36, 0x74, 0x4a  },
+       { 0x00, 0x27, 0x53, 0x74, 0xbb, 0x9c, 0xe8, 0xcf,
+           0x76, 0x51, 0x25, 0x02, 0xcd, 0xea, 0x9e, 0xb9  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3f, 0x7e, 0x41, 0xfc, 0xc3, 0x82, 0xbd,
+           0xf8, 0xc7, 0x86, 0xb9, 0x04, 0x3b, 0x7a, 0x45  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51,
+           0x87, 0xf3, 0x6f, 0x1b, 0x4a, 0x3e, 0xa2, 0xd6  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51,
+           0x87, 0xf3, 0x6f, 0x1b, 0x4a, 0x3e, 0xa2, 0xd6  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x41, 0x82, 0xc3, 0x04, 0x45, 0x86, 0xc7,
+           0x08, 0x49, 0x8a, 0xcb, 0x0c, 0x4d, 0x8e, 0xcf  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51,
+           0x9a, 0xee, 0x72, 0x06, 0x57, 0x23, 0xbf, 0xcb  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x42, 0x84, 0xc6, 0x08, 0x4a, 0x8c, 0xce,
+           0x10, 0x52, 0x94, 0xd6, 0x18, 0x5a, 0x9c, 0xde  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51,
+           0x9a, 0xee, 0x72, 0x06, 0x57, 0x23, 0xbf, 0xcb  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x43, 0x86, 0xc5, 0x0c, 0x4f, 0x8a, 0xc9,
+           0x18, 0x5b, 0x9e, 0xdd, 0x14, 0x57, 0x92, 0xd1  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xbd, 0xc9, 0x55, 0x21, 0x6d, 0x19, 0x85, 0xf1  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x44, 0x88, 0xcc, 0x10, 0x54, 0x98, 0xdc,
+           0x20, 0x64, 0xa8, 0xec, 0x30, 0x74, 0xb8, 0xfc  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xbd, 0xc9, 0x55, 0x21, 0x6d, 0x19, 0x85, 0xf1  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x45, 0x8a, 0xcf, 0x14, 0x51, 0x9e, 0xdb,
+           0x28, 0x6d, 0xa2, 0xe7, 0x3c, 0x79, 0xb6, 0xf3  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xa0, 0xd4, 0x48, 0x3c, 0x70, 0x04, 0x98, 0xec  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x46, 0x8c, 0xca, 0x18, 0x5e, 0x94, 0xd2,
+           0x30, 0x76, 0xbc, 0xfa, 0x28, 0x6e, 0xa4, 0xe2  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xa0, 0xd4, 0x48, 0x3c, 0x70, 0x04, 0x98, 0xec  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x47, 0x8e, 0xc9, 0x1c, 0x5b, 0x92, 0xd5,
+           0x38, 0x7f, 0xb6, 0xf1, 0x24, 0x63, 0xaa, 0xed  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xf7, 0x83, 0x02, 0x76,
+           0xf3, 0x87, 0x06, 0x72, 0x04, 0x70, 0xf1, 0x85  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x48, 0x90, 0xd8, 0x20, 0x68, 0xb0, 0xf8,
+           0x40, 0x08, 0xd0, 0x98, 0x60, 0x28, 0xf0, 0xb8  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xf7, 0x83, 0x02, 0x76,
+           0xf3, 0x87, 0x06, 0x72, 0x04, 0x70, 0xf1, 0x85  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x49, 0x92, 0xdb, 0x24, 0x6d, 0xb6, 0xff,
+           0x48, 0x01, 0xda, 0x93, 0x6c, 0x25, 0xfe, 0xb7  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xf7, 0x83, 0x02, 0x76,
+           0xee, 0x9a, 0x1b, 0x6f, 0x19, 0x6d, 0xec, 0x98  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4a, 0x94, 0xde, 0x28, 0x62, 0xbc, 0xf6,
+           0x50, 0x1a, 0xc4, 0x8e, 0x78, 0x32, 0xec, 0xa6  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xf7, 0x83, 0x02, 0x76,
+           0xee, 0x9a, 0x1b, 0x6f, 0x19, 0x6d, 0xec, 0x98  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4b, 0x96, 0xdd, 0x2c, 0x67, 0xba, 0xf1,
+           0x58, 0x13, 0xce, 0x85, 0x74, 0x3f, 0xe2, 0xa9  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xea, 0x9e, 0x1f, 0x6b,
+           0xc9, 0xbd, 0x3c, 0x48, 0x23, 0x57, 0xd6, 0xa2  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4c, 0x98, 0xd4, 0x30, 0x7c, 0xa8, 0xe4,
+           0x60, 0x2c, 0xf8, 0xb4, 0x50, 0x1c, 0xc8, 0x84  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xea, 0x9e, 0x1f, 0x6b,
+           0xc9, 0xbd, 0x3c, 0x48, 0x23, 0x57, 0xd6, 0xa2  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4d, 0x9a, 0xd7, 0x34, 0x79, 0xae, 0xe3,
+           0x68, 0x25, 0xf2, 0xbf, 0x5c, 0x11, 0xc6, 0x8b  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xea, 0x9e, 0x1f, 0x6b,
+           0xd4, 0xa0, 0x21, 0x55, 0x3e, 0x4a, 0xcb, 0xbf  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x70, 0x3e, 0xec, 0xa2, 0x48, 0x06, 0xd4, 0x9a  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xea, 0x9e, 0x1f, 0x6b,
+           0xd4, 0xa0, 0x21, 0x55, 0x3e, 0x4a, 0xcb, 0xbf  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4f, 0x9e, 0xd1, 0x3c, 0x73, 0xa2, 0xed,
+           0x78, 0x37, 0xe6, 0xa9, 0x44, 0x0b, 0xda, 0x95  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02,
+           0x6f, 0x06, 0xbd, 0xd4, 0xd6, 0xbf, 0x04, 0x6d  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02,
+           0x6f, 0x06, 0xbd, 0xd4, 0xd6, 0xbf, 0x04, 0x6d  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x51, 0xa2, 0xf3, 0x44, 0x15, 0xe6, 0xb7,
+           0x88, 0xd9, 0x2a, 0x7b, 0xcc, 0x9d, 0x6e, 0x3f  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02,
+           0x72, 0x1b, 0xa0, 0xc9, 0xcb, 0xa2, 0x19, 0x70  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x52, 0xa4, 0xf6, 0x48, 0x1a, 0xec, 0xbe,
+           0x90, 0xc2, 0x34, 0x66, 0xd8, 0x8a, 0x7c, 0x2e  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02,
+           0x72, 0x1b, 0xa0, 0xc9, 0xcb, 0xa2, 0x19, 0x70  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x98, 0xcb, 0x3e, 0x6d, 0xd4, 0x87, 0x72, 0x21  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x55, 0x3c, 0x87, 0xee, 0xf1, 0x98, 0x23, 0x4a  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x54, 0xa8, 0xfc, 0x50, 0x04, 0xf8, 0xac,
+           0xa0, 0xf4, 0x08, 0x5c, 0xf0, 0xa4, 0x58, 0x0c  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x55, 0x3c, 0x87, 0xee, 0xf1, 0x98, 0x23, 0x4a  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x55, 0xaa, 0xff, 0x54, 0x01, 0xfe, 0xab,
+           0xa8, 0xfd, 0x02, 0x57, 0xfc, 0xa9, 0x56, 0x03  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x48, 0x21, 0x9a, 0xf3, 0xec, 0x85, 0x3e, 0x57  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x56, 0xac, 0xfa, 0x58, 0x0e, 0xf4, 0xa2,
+           0xb0, 0xe6, 0x1c, 0x4a, 0xe8, 0xbe, 0x44, 0x12  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x48, 0x21, 0x9a, 0xf3, 0xec, 0x85, 0x3e, 0x57  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x57, 0xae, 0xf9, 0x5c, 0x0b, 0xf2, 0xa5,
+           0xb8, 0xef, 0x16, 0x41, 0xe4, 0xb3, 0x4a, 0x1d  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x83, 0xea, 0x4c, 0x25,
+           0x1b, 0x72, 0xd4, 0xbd, 0x98, 0xf1, 0x57, 0x3e  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x58, 0xb0, 0xe8, 0x60, 0x38, 0xd0, 0x88,
+           0xc0, 0x98, 0x70, 0x28, 0xa0, 0xf8, 0x10, 0x48  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x83, 0xea, 0x4c, 0x25,
+           0x1b, 0x72, 0xd4, 0xbd, 0x98, 0xf1, 0x57, 0x3e  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x59, 0xb2, 0xeb, 0x64, 0x3d, 0xd6, 0x8f,
+           0xc8, 0x91, 0x7a, 0x23, 0xac, 0xf5, 0x1e, 0x47  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x83, 0xea, 0x4c, 0x25,
+           0x06, 0x6f, 0xc9, 0xa0, 0x85, 0xec, 0x4a, 0x23  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5a, 0xb4, 0xee, 0x68, 0x32, 0xdc, 0x86,
+           0xd0, 0x8a, 0x64, 0x3e, 0xb8, 0xe2, 0x0c, 0x56  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x83, 0xea, 0x4c, 0x25,
+           0x06, 0x6f, 0xc9, 0xa0, 0x85, 0xec, 0x4a, 0x23  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5b, 0xb6, 0xed, 0x6c, 0x37, 0xda, 0x81,
+           0xd8, 0x83, 0x6e, 0x35, 0xb4, 0xef, 0x02, 0x59  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x9e, 0xf7, 0x51, 0x38,
+           0x21, 0x48, 0xee, 0x87, 0xbf, 0xd6, 0x70, 0x19  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5c, 0xb8, 0xe4, 0x70, 0x2c, 0xc8, 0x94,
+           0xe0, 0xbc, 0x58, 0x04, 0x90, 0xcc, 0x28, 0x74  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x9e, 0xf7, 0x51, 0x38,
+           0x21, 0x48, 0xee, 0x87, 0xbf, 0xd6, 0x70, 0x19  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5d, 0xba, 0xe7, 0x74, 0x29, 0xce, 0x93,
+           0xe8, 0xb5, 0x52, 0x0f, 0x9c, 0xc1, 0x26, 0x7b  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x9e, 0xf7, 0x51, 0x38,
+           0x3c, 0x55, 0xf3, 0x9a, 0xa2, 0xcb, 0x6d, 0x04  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5e, 0xbc, 0xe2, 0x78, 0x26, 0xc4, 0x9a,
+           0xf0, 0xae, 0x4c, 0x12, 0x88, 0xd6, 0x34, 0x6a  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x9e, 0xf7, 0x51, 0x38,
+           0x3c, 0x55, 0xf3, 0x9a, 0xa2, 0xcb, 0x6d, 0x04  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5f, 0xbe, 0xe1, 0x7c, 0x23, 0xc2, 0x9d,
+           0xf8, 0xa7, 0x46, 0x19, 0x84, 0xdb, 0x3a, 0x65  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7,
+           0x4a, 0x04, 0xd6, 0x98, 0x6f, 0x21, 0xf3, 0xbd  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7,
+           0x4a, 0x04, 0xd6, 0x98, 0x6f, 0x21, 0xf3, 0xbd  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x61, 0xc2, 0xa3, 0x84, 0xe5, 0x46, 0x27,
+           0x08, 0x69, 0xca, 0xab, 0x8c, 0xed, 0x4e, 0x2f  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7,
+           0x57, 0x19, 0xcb, 0x85, 0x72, 0x3c, 0xee, 0xa0  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x62, 0xc4, 0xa6, 0x88, 0xea, 0x4c, 0x2e,
+           0x10, 0x72, 0xd4, 0xb6, 0x98, 0xfa, 0x5c, 0x3e  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7,
+           0x57, 0x19, 0xcb, 0x85, 0x72, 0x3c, 0xee, 0xa0  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x63, 0xc6, 0xa5, 0x8c, 0xef, 0x4a, 0x29,
+           0x18, 0x7b, 0xde, 0xbd, 0x94, 0xf7, 0x52, 0x31  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x70, 0x3e, 0xec, 0xa2, 0x48, 0x06, 0xd4, 0x9a  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x64, 0xc8, 0xac, 0x90, 0xf4, 0x58, 0x3c,
+           0x20, 0x44, 0xe8, 0x8c, 0xb0, 0xd4, 0x78, 0x1c  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x70, 0x3e, 0xec, 0xa2, 0x48, 0x06, 0xd4, 0x9a  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x65, 0xca, 0xaf, 0x94, 0xf1, 0x5e, 0x3b,
+           0x28, 0x4d, 0xe2, 0x87, 0xbc, 0xd9, 0x76, 0x13  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x6d, 0x23, 0xf1, 0xbf, 0x55, 0x1b, 0xc9, 0x87  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x66, 0xcc, 0xaa, 0x98, 0xfe, 0x54, 0x32,
+           0x30, 0x56, 0xfc, 0x9a, 0xa8, 0xce, 0x64, 0x02  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x6d, 0x23, 0xf1, 0xbf, 0x55, 0x1b, 0xc9, 0x87  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x67, 0xce, 0xa9, 0x9c, 0xfb, 0x52, 0x35,
+           0x38, 0x5f, 0xf6, 0x91, 0xa4, 0xc3, 0x6a, 0x0d  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x1f, 0x51, 0x9e, 0xd0,
+           0x3e, 0x70, 0xbf, 0xf1, 0x21, 0x6f, 0xa0, 0xee  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x68, 0xd0, 0xb8, 0xa0, 0xc8, 0x70, 0x18,
+           0x40, 0x28, 0x90, 0xf8, 0xe0, 0x88, 0x30, 0x58  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x1f, 0x51, 0x9e, 0xd0,
+           0x3e, 0x70, 0xbf, 0xf1, 0x21, 0x6f, 0xa0, 0xee  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x48, 0x21, 0x9a, 0xf3, 0xec, 0x85, 0x3e, 0x57  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x1f, 0x51, 0x9e, 0xd0,
+           0x23, 0x6d, 0xa2, 0xec, 0x3c, 0x72, 0xbd, 0xf3  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6a, 0xd4, 0xbe, 0xa8, 0xc2, 0x7c, 0x16,
+           0x50, 0x3a, 0x84, 0xee, 0xf8, 0x92, 0x2c, 0x46  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x1f, 0x51, 0x9e, 0xd0,
+           0x23, 0x6d, 0xa2, 0xec, 0x3c, 0x72, 0xbd, 0xf3  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6b, 0xd6, 0xbd, 0xac, 0xc7, 0x7a, 0x11,
+           0x58, 0x33, 0x8e, 0xe5, 0xf4, 0x9f, 0x22, 0x49  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x02, 0x4c, 0x83, 0xcd,
+           0x04, 0x4a, 0x85, 0xcb, 0x06, 0x48, 0x87, 0xc9  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6c, 0xd8, 0xb4, 0xb0, 0xdc, 0x68, 0x04,
+           0x60, 0x0c, 0xb8, 0xd4, 0xd0, 0xbc, 0x08, 0x64  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x02, 0x4c, 0x83, 0xcd,
+           0x04, 0x4a, 0x85, 0xcb, 0x06, 0x48, 0x87, 0xc9  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6d, 0xda, 0xb7, 0xb4, 0xd9, 0x6e, 0x03,
+           0x68, 0x05, 0xb2, 0xdf, 0xdc, 0xb1, 0x06, 0x6b  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x02, 0x4c, 0x83, 0xcd,
+           0x19, 0x57, 0x98, 0xd6, 0x1b, 0x55, 0x9a, 0xd4  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6e, 0xdc, 0xb2, 0xb8, 0xd6, 0x64, 0x0a,
+           0x70, 0x1e, 0xac, 0xc2, 0xc8, 0xa6, 0x14, 0x7a  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x02, 0x4c, 0x83, 0xcd,
+           0x19, 0x57, 0x98, 0xd6, 0x1b, 0x55, 0x9a, 0xd4  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6f, 0xde, 0xb1, 0xbc, 0xd3, 0x62, 0x0d,
+           0x78, 0x17, 0xa6, 0xc9, 0xc4, 0xab, 0x1a, 0x75  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4,
+           0xa2, 0xf1, 0x04, 0x57, 0xf3, 0xa0, 0x55, 0x06  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4,
+           0xa2, 0xf1, 0x04, 0x57, 0xf3, 0xa0, 0x55, 0x06  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x71, 0xe2, 0x93, 0xc4, 0xb5, 0x26, 0x57,
+           0x88, 0xf9, 0x6a, 0x1b, 0x4c, 0x3d, 0xae, 0xdf  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4,
+           0xbf, 0xec, 0x19, 0x4a, 0xee, 0xbd, 0x48, 0x1b  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x72, 0xe4, 0x96, 0xc8, 0xba, 0x2c, 0x5e,
+           0x90, 0xe2, 0x74, 0x06, 0x58, 0x2a, 0xbc, 0xce  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4,
+           0xbf, 0xec, 0x19, 0x4a, 0xee, 0xbd, 0x48, 0x1b  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x73, 0xe6, 0x95, 0xcc, 0xbf, 0x2a, 0x59,
+           0x98, 0xeb, 0x7e, 0x0d, 0x54, 0x27, 0xb2, 0xc1  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x98, 0xcb, 0x3e, 0x6d, 0xd4, 0x87, 0x72, 0x21  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xa0, 0xd4, 0x48, 0x3c, 0x70, 0x04, 0x98, 0xec  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x98, 0xcb, 0x3e, 0x6d, 0xd4, 0x87, 0x72, 0x21  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x75, 0xea, 0x9f, 0xd4, 0xa1, 0x3e, 0x4b,
+           0xa8, 0xdd, 0x42, 0x37, 0x7c, 0x09, 0x96, 0xe3  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x85, 0xd6, 0x23, 0x70, 0xc9, 0x9a, 0x6f, 0x3c  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x76, 0xec, 0x9a, 0xd8, 0xae, 0x34, 0x42,
+           0xb0, 0xc6, 0x5c, 0x2a, 0x68, 0x1e, 0x84, 0xf2  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x85, 0xd6, 0x23, 0x70, 0xc9, 0x9a, 0x6f, 0x3c  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x77, 0xee, 0x99, 0xdc, 0xab, 0x32, 0x45,
+           0xb8, 0xcf, 0x56, 0x21, 0x64, 0x13, 0x8a, 0xfd  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x6b, 0x38, 0xd0, 0x83,
+           0xd6, 0x85, 0x6d, 0x3e, 0xbd, 0xee, 0x06, 0x55  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x78, 0xf0, 0x88, 0xe0, 0x98, 0x10, 0x68,
+           0xc0, 0xb8, 0x30, 0x48, 0x20, 0x58, 0xd0, 0xa8  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x6b, 0x38, 0xd0, 0x83,
+           0xd6, 0x85, 0x6d, 0x3e, 0xbd, 0xee, 0x06, 0x55  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x79, 0xf2, 0x8b, 0xe4, 0x9d, 0x16, 0x6f,
+           0xc8, 0xb1, 0x3a, 0x43, 0x2c, 0x55, 0xde, 0xa7  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x6b, 0x38, 0xd0, 0x83,
+           0xcb, 0x98, 0x70, 0x23, 0xa0, 0xf3, 0x1b, 0x48  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7a, 0xf4, 0x8e, 0xe8, 0x92, 0x1c, 0x66,
+           0xd0, 0xaa, 0x24, 0x5e, 0x38, 0x42, 0xcc, 0xb6  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x6b, 0x38, 0xd0, 0x83,
+           0xcb, 0x98, 0x70, 0x23, 0xa0, 0xf3, 0x1b, 0x48  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7b, 0xf6, 0x8d, 0xec, 0x97, 0x1a, 0x61,
+           0xd8, 0xa3, 0x2e, 0x55, 0x34, 0x4f, 0xc2, 0xb9  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x76, 0x25, 0xcd, 0x9e,
+           0xec, 0xbf, 0x57, 0x04, 0x9a, 0xc9, 0x21, 0x72  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7c, 0xf8, 0x84, 0xf0, 0x8c, 0x08, 0x74,
+           0xe0, 0x9c, 0x18, 0x64, 0x10, 0x6c, 0xe8, 0x94  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x76, 0x25, 0xcd, 0x9e,
+           0xec, 0xbf, 0x57, 0x04, 0x9a, 0xc9, 0x21, 0x72  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7d, 0xfa, 0x87, 0xf4, 0x89, 0x0e, 0x73,
+           0xe8, 0x95, 0x12, 0x6f, 0x1c, 0x61, 0xe6, 0x9b  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x76, 0x25, 0xcd, 0x9e,
+           0xf1, 0xa2, 0x4a, 0x19, 0x87, 0xd4, 0x3c, 0x6f  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7e, 0xfc, 0x82, 0xf8, 0x86, 0x04, 0x7a,
+           0xf0, 0x8e, 0x0c, 0x72, 0x08, 0x76, 0xf4, 0x8a  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x76, 0x25, 0xcd, 0x9e,
+           0xf1, 0xa2, 0x4a, 0x19, 0x87, 0xd4, 0x3c, 0x6f  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7f, 0xfe, 0x81, 0xfc, 0x83, 0x02, 0x7d,
+           0xf8, 0x87, 0x06, 0x79, 0x04, 0x7b, 0xfa, 0x85  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2,
+           0x13, 0xfb, 0xde, 0x36, 0x94, 0x7c, 0x59, 0xb1  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2,
+           0x13, 0xfb, 0xde, 0x36, 0x94, 0x7c, 0x59, 0xb1  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x08, 0x89, 0x0a, 0x8b, 0x0c, 0x8d, 0x0e, 0x8f  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2,
+           0x0e, 0xe6, 0xc3, 0x2b, 0x89, 0x61, 0x44, 0xac  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x82, 0x04, 0x86, 0x08, 0x8a, 0x0c, 0x8e,
+           0x10, 0x92, 0x14, 0x96, 0x18, 0x9a, 0x1c, 0x9e  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2,
+           0x0e, 0xe6, 0xc3, 0x2b, 0x89, 0x61, 0x44, 0xac  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x83, 0x06, 0x85, 0x0c, 0x8f, 0x0a, 0x89,
+           0x18, 0x9b, 0x1e, 0x9d, 0x14, 0x97, 0x12, 0x91  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x9a, 0x72, 0x57, 0xbf,
+           0x29, 0xc1, 0xe4, 0x0c, 0xb3, 0x5b, 0x7e, 0x96  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x84, 0x08, 0x8c, 0x10, 0x94, 0x18, 0x9c,
+           0x20, 0xa4, 0x28, 0xac, 0x30, 0xb4, 0x38, 0xbc  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x9a, 0x72, 0x57, 0xbf,
+           0x29, 0xc1, 0xe4, 0x0c, 0xb3, 0x5b, 0x7e, 0x96  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x85, 0x0a, 0x8f, 0x14, 0x91, 0x1e, 0x9b,
+           0x28, 0xad, 0x22, 0xa7, 0x3c, 0xb9, 0x36, 0xb3  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x9a, 0x72, 0x57, 0xbf,
+           0x34, 0xdc, 0xf9, 0x11, 0xae, 0x46, 0x63, 0x8b  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x86, 0x0c, 0x8a, 0x18, 0x9e, 0x14, 0x92,
+           0x30, 0xb6, 0x3c, 0xba, 0x28, 0xae, 0x24, 0xa2  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x9a, 0x72, 0x57, 0xbf,
+           0x34, 0xdc, 0xf9, 0x11, 0xae, 0x46, 0x63, 0x8b  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x87, 0x0e, 0x89, 0x1c, 0x9b, 0x12, 0x95,
+           0x38, 0xbf, 0x36, 0xb1, 0x24, 0xa3, 0x2a, 0xad  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xbd, 0x55, 0x6d, 0x85,
+           0x67, 0x8f, 0xb7, 0x5f, 0xda, 0x32, 0x0a, 0xe2  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x88, 0x10, 0x98, 0x20, 0xa8, 0x30, 0xb8,
+           0x40, 0xc8, 0x50, 0xd8, 0x60, 0xe8, 0x70, 0xf8  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xbd, 0x55, 0x6d, 0x85,
+           0x67, 0x8f, 0xb7, 0x5f, 0xda, 0x32, 0x0a, 0xe2  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf,
+           0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e, 0xf7  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xbd, 0x55, 0x6d, 0x85,
+           0x7a, 0x92, 0xaa, 0x42, 0xc7, 0x2f, 0x17, 0xff  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8a, 0x14, 0x9e, 0x28, 0xa2, 0x3c, 0xb6,
+           0x50, 0xda, 0x44, 0xce, 0x78, 0xf2, 0x6c, 0xe6  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xbd, 0x55, 0x6d, 0x85,
+           0x7a, 0x92, 0xaa, 0x42, 0xc7, 0x2f, 0x17, 0xff  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8b, 0x16, 0x9d, 0x2c, 0xa7, 0x3a, 0xb1,
+           0x58, 0xd3, 0x4e, 0xc5, 0x74, 0xff, 0x62, 0xe9  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x5d, 0xb5, 0x8d, 0x65, 0xfd, 0x15, 0x2d, 0xc5  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8c, 0x18, 0x94, 0x30, 0xbc, 0x28, 0xa4,
+           0x60, 0xec, 0x78, 0xf4, 0x50, 0xdc, 0x48, 0xc4  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x5d, 0xb5, 0x8d, 0x65, 0xfd, 0x15, 0x2d, 0xc5  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8d, 0x1a, 0x97, 0x34, 0xb9, 0x2e, 0xa3,
+           0x68, 0xe5, 0x72, 0xff, 0x5c, 0xd1, 0x46, 0xcb  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x40, 0xa8, 0x90, 0x78, 0xe0, 0x08, 0x30, 0xd8  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8e, 0x1c, 0x92, 0x38, 0xb6, 0x24, 0xaa,
+           0x70, 0xfe, 0x6c, 0xe2, 0x48, 0xc6, 0x54, 0xda  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x40, 0xa8, 0x90, 0x78, 0xe0, 0x08, 0x30, 0xd8  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8f, 0x1e, 0x91, 0x3c, 0xb3, 0x22, 0xad,
+           0x78, 0xf7, 0x66, 0xe9, 0x44, 0xcb, 0x5a, 0xd5  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1,
+           0xfb, 0x0e, 0x0c, 0xf9, 0x08, 0xfd, 0xff, 0x0a  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1,
+           0xfb, 0x0e, 0x0c, 0xf9, 0x08, 0xfd, 0xff, 0x0a  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x91, 0x22, 0xb3, 0x44, 0xd5, 0x66, 0xf7,
+           0x88, 0x19, 0xaa, 0x3b, 0xcc, 0x5d, 0xee, 0x7f  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1,
+           0xe6, 0x13, 0x11, 0xe4, 0x15, 0xe0, 0xe2, 0x17  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x92, 0x24, 0xb6, 0x48, 0xda, 0x6c, 0xfe,
+           0x90, 0x02, 0xb4, 0x26, 0xd8, 0x4a, 0xfc, 0x6e  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1,
+           0xe6, 0x13, 0x11, 0xe4, 0x15, 0xe0, 0xe2, 0x17  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x93, 0x26, 0xb5, 0x4c, 0xdf, 0x6a, 0xf9,
+           0x98, 0x0b, 0xbe, 0x2d, 0xd4, 0x47, 0xf2, 0x61  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xee, 0x1b, 0x19, 0xec,
+           0xc1, 0x34, 0x36, 0xc3, 0x2f, 0xda, 0xd8, 0x2d  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x94, 0x28, 0xbc, 0x50, 0xc4, 0x78, 0xec,
+           0xa0, 0x34, 0x88, 0x1c, 0xf0, 0x64, 0xd8, 0x4c  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xee, 0x1b, 0x19, 0xec,
+           0xc1, 0x34, 0x36, 0xc3, 0x2f, 0xda, 0xd8, 0x2d  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x95, 0x2a, 0xbf, 0x54, 0xc1, 0x7e, 0xeb,
+           0xa8, 0x3d, 0x82, 0x17, 0xfc, 0x69, 0xd6, 0x43  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xee, 0x1b, 0x19, 0xec,
+           0xdc, 0x29, 0x2b, 0xde, 0x32, 0xc7, 0xc5, 0x30  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x96, 0x2c, 0xba, 0x58, 0xce, 0x74, 0xe2,
+           0xb0, 0x26, 0x9c, 0x0a, 0xe8, 0x7e, 0xc4, 0x52  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xee, 0x1b, 0x19, 0xec,
+           0xdc, 0x29, 0x2b, 0xde, 0x32, 0xc7, 0xc5, 0x30  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x97, 0x2e, 0xb9, 0x5c, 0xcb, 0x72, 0xe5,
+           0xb8, 0x2f, 0x96, 0x01, 0xe4, 0x73, 0xca, 0x5d  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xc9, 0x3c, 0x23, 0xd6,
+           0x8f, 0x7a, 0x65, 0x90, 0x46, 0xb3, 0xac, 0x59  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x98, 0x30, 0xa8, 0x60, 0xf8, 0x50, 0xc8,
+           0xc0, 0x58, 0xf0, 0x68, 0xa0, 0x38, 0x90, 0x08  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xc9, 0x3c, 0x23, 0xd6,
+           0x8f, 0x7a, 0x65, 0x90, 0x46, 0xb3, 0xac, 0x59  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x99, 0x32, 0xab, 0x64, 0xfd, 0x56, 0xcf,
+           0xc8, 0x51, 0xfa, 0x63, 0xac, 0x35, 0x9e, 0x07  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xc9, 0x3c, 0x23, 0xd6,
+           0x92, 0x67, 0x78, 0x8d, 0x5b, 0xae, 0xb1, 0x44  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9a, 0x34, 0xae, 0x68, 0xf2, 0x5c, 0xc6,
+           0xd0, 0x4a, 0xe4, 0x7e, 0xb8, 0x22, 0x8c, 0x16  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xc9, 0x3c, 0x23, 0xd6,
+           0x92, 0x67, 0x78, 0x8d, 0x5b, 0xae, 0xb1, 0x44  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9b, 0x36, 0xad, 0x6c, 0xf7, 0x5a, 0xc1,
+           0xd8, 0x43, 0xee, 0x75, 0xb4, 0x2f, 0x82, 0x19  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xb5, 0x40, 0x5f, 0xaa, 0x61, 0x94, 0x8b, 0x7e  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xe0, 0x7c, 0xd8, 0x44, 0x90, 0x0c, 0xa8, 0x34  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xb5, 0x40, 0x5f, 0xaa, 0x61, 0x94, 0x8b, 0x7e  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9d, 0x3a, 0xa7, 0x74, 0xe9, 0x4e, 0xd3,
+           0xe8, 0x75, 0xd2, 0x4f, 0x9c, 0x01, 0xa6, 0x3b  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xa8, 0x5d, 0x42, 0xb7, 0x7c, 0x89, 0x96, 0x63  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9e, 0x3c, 0xa2, 0x78, 0xe6, 0x44, 0xda,
+           0xf0, 0x6e, 0xcc, 0x52, 0x88, 0x16, 0xb4, 0x2a  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xa8, 0x5d, 0x42, 0xb7, 0x7c, 0x89, 0x96, 0x63  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9f, 0x3e, 0xa1, 0x7c, 0xe3, 0x42, 0xdd,
+           0xf8, 0x67, 0xc6, 0x59, 0x84, 0x1b, 0xba, 0x25  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04,
+           0xde, 0x0c, 0x67, 0xb5, 0xb1, 0x63, 0x08, 0xda  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04,
+           0xde, 0x0c, 0x67, 0xb5, 0xb1, 0x63, 0x08, 0xda  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa1, 0x42, 0xe3, 0x84, 0x25, 0xc6, 0x67,
+           0x08, 0xa9, 0x4a, 0xeb, 0x8c, 0x2d, 0xce, 0x6f  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04,
+           0xc3, 0x11, 0x7a, 0xa8, 0xac, 0x7e, 0x15, 0xc7  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa2, 0x44, 0xe6, 0x88, 0x2a, 0xcc, 0x6e,
+           0x10, 0xb2, 0x54, 0xf6, 0x98, 0x3a, 0xdc, 0x7e  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04,
+           0xc3, 0x11, 0x7a, 0xa8, 0xac, 0x7e, 0x15, 0xc7  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa3, 0x46, 0xe5, 0x8c, 0x2f, 0xca, 0x69,
+           0x18, 0xbb, 0x5e, 0xfd, 0x94, 0x37, 0xd2, 0x71  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x72, 0xa0, 0xcb, 0x19,
+           0xe4, 0x36, 0x5d, 0x8f, 0x96, 0x44, 0x2f, 0xfd  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa4, 0x48, 0xec, 0x90, 0x34, 0xd8, 0x7c,
+           0x20, 0x84, 0x68, 0xcc, 0xb0, 0x14, 0xf8, 0x5c  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x72, 0xa0, 0xcb, 0x19,
+           0xe4, 0x36, 0x5d, 0x8f, 0x96, 0x44, 0x2f, 0xfd  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa5, 0x4a, 0xef, 0x94, 0x31, 0xde, 0x7b,
+           0x28, 0x8d, 0x62, 0xc7, 0xbc, 0x19, 0xf6, 0x53  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x72, 0xa0, 0xcb, 0x19,
+           0xf9, 0x2b, 0x40, 0x92, 0x8b, 0x59, 0x32, 0xe0  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x30, 0x96, 0x7c, 0xda, 0xa8, 0x0e, 0xe4, 0x42  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x72, 0xa0, 0xcb, 0x19,
+           0xf9, 0x2b, 0x40, 0x92, 0x8b, 0x59, 0x32, 0xe0  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa7, 0x4e, 0xe9, 0x9c, 0x3b, 0xd2, 0x75,
+           0x38, 0x9f, 0x76, 0xd1, 0xa4, 0x03, 0xea, 0x4d  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x55, 0x87, 0xf1, 0x23,
+           0xaa, 0x78, 0x0e, 0xdc, 0xff, 0x2d, 0x5b, 0x89  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa8, 0x50, 0xf8, 0xa0, 0x08, 0xf0, 0x58,
+           0x40, 0xe8, 0x10, 0xb8, 0xe0, 0x48, 0xb0, 0x18  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x55, 0x87, 0xf1, 0x23,
+           0xaa, 0x78, 0x0e, 0xdc, 0xff, 0x2d, 0x5b, 0x89  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa9, 0x52, 0xfb, 0xa4, 0x0d, 0xf6, 0x5f,
+           0x48, 0xe1, 0x1a, 0xb3, 0xec, 0x45, 0xbe, 0x17  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x55, 0x87, 0xf1, 0x23,
+           0xb7, 0x65, 0x13, 0xc1, 0xe2, 0x30, 0x46, 0x94  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xaa, 0x54, 0xfe, 0xa8, 0x02, 0xfc, 0x56,
+           0x50, 0xfa, 0x04, 0xae, 0xf8, 0x52, 0xac, 0x06  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x55, 0x87, 0xf1, 0x23,
+           0xb7, 0x65, 0x13, 0xc1, 0xe2, 0x30, 0x46, 0x94  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xab, 0x56, 0xfd, 0xac, 0x07, 0xfa, 0x51,
+           0x58, 0xf3, 0x0e, 0xa5, 0xf4, 0x5f, 0xa2, 0x09  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x90, 0x42, 0x34, 0xe6, 0xd8, 0x0a, 0x7c, 0xae  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xac, 0x58, 0xf4, 0xb0, 0x1c, 0xe8, 0x44,
+           0x60, 0xcc, 0x38, 0x94, 0xd0, 0x7c, 0x88, 0x24  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x90, 0x42, 0x34, 0xe6, 0xd8, 0x0a, 0x7c, 0xae  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xad, 0x5a, 0xf7, 0xb4, 0x19, 0xee, 0x43,
+           0x68, 0xc5, 0x32, 0x9f, 0xdc, 0x71, 0x86, 0x2b  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x8d, 0x5f, 0x29, 0xfb, 0xc5, 0x17, 0x61, 0xb3  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xae, 0x5c, 0xf2, 0xb8, 0x16, 0xe4, 0x4a,
+           0x70, 0xde, 0x2c, 0x82, 0xc8, 0x66, 0x94, 0x3a  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x8d, 0x5f, 0x29, 0xfb, 0xc5, 0x17, 0x61, 0xb3  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xaf, 0x5e, 0xf1, 0xbc, 0x13, 0xe2, 0x4d,
+           0x78, 0xd7, 0x26, 0x89, 0xc4, 0x6b, 0x9a, 0x35  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57,
+           0x36, 0xf9, 0xb5, 0x7a, 0x2d, 0xe2, 0xae, 0x61  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57,
+           0x36, 0xf9, 0xb5, 0x7a, 0x2d, 0xe2, 0xae, 0x61  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb1, 0x62, 0xd3, 0xc4, 0x75, 0xa6, 0x17,
+           0x88, 0x39, 0xea, 0x5b, 0x4c, 0xfd, 0x2e, 0x9f  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57,
+           0x2b, 0xe4, 0xa8, 0x67, 0x30, 0xff, 0xb3, 0x7c  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb2, 0x64, 0xd6, 0xc8, 0x7a, 0xac, 0x1e,
+           0x90, 0x22, 0xf4, 0x46, 0x58, 0xea, 0x3c, 0x8e  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57,
+           0x2b, 0xe4, 0xa8, 0x67, 0x30, 0xff, 0xb3, 0x7c  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb3, 0x66, 0xd5, 0xcc, 0x7f, 0xaa, 0x19,
+           0x98, 0x2b, 0xfe, 0x4d, 0x54, 0xe7, 0x32, 0x81  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x06, 0xc9, 0x85, 0x4a,
+           0x0c, 0xc3, 0x8f, 0x40, 0x0a, 0xc5, 0x89, 0x46  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb4, 0x68, 0xdc, 0xd0, 0x64, 0xb8, 0x0c,
+           0xa0, 0x14, 0xc8, 0x7c, 0x70, 0xc4, 0x18, 0xac  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x06, 0xc9, 0x85, 0x4a,
+           0x0c, 0xc3, 0x8f, 0x40, 0x0a, 0xc5, 0x89, 0x46  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb5, 0x6a, 0xdf, 0xd4, 0x61, 0xbe, 0x0b,
+           0xa8, 0x1d, 0xc2, 0x77, 0x7c, 0xc9, 0x16, 0xa3  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x06, 0xc9, 0x85, 0x4a,
+           0x11, 0xde, 0x92, 0x5d, 0x17, 0xd8, 0x94, 0x5b  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb6, 0x6c, 0xda, 0xd8, 0x6e, 0xb4, 0x02,
+           0xb0, 0x06, 0xdc, 0x6a, 0x68, 0xde, 0x04, 0xb2  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x06, 0xc9, 0x85, 0x4a,
+           0x11, 0xde, 0x92, 0x5d, 0x17, 0xd8, 0x94, 0x5b  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb7, 0x6e, 0xd9, 0xdc, 0x6b, 0xb2, 0x05,
+           0xb8, 0x0f, 0xd6, 0x61, 0x64, 0xd3, 0x0a, 0xbd  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x21, 0xee, 0xbf, 0x70,
+           0x42, 0x8d, 0xdc, 0x13, 0x63, 0xac, 0xfd, 0x32  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb8, 0x70, 0xc8, 0xe0, 0x58, 0x90, 0x28,
+           0xc0, 0x78, 0xb0, 0x08, 0x20, 0x98, 0x50, 0xe8  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x21, 0xee, 0xbf, 0x70,
+           0x42, 0x8d, 0xdc, 0x13, 0x63, 0xac, 0xfd, 0x32  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb9, 0x72, 0xcb, 0xe4, 0x5d, 0x96, 0x2f,
+           0xc8, 0x71, 0xba, 0x03, 0x2c, 0x95, 0x5e, 0xe7  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x21, 0xee, 0xbf, 0x70,
+           0x5f, 0x90, 0xc1, 0x0e, 0x7e, 0xb1, 0xe0, 0x2f  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xba, 0x74, 0xce, 0xe8, 0x52, 0x9c, 0x26,
+           0xd0, 0x6a, 0xa4, 0x1e, 0x38, 0x82, 0x4c, 0xf6  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x21, 0xee, 0xbf, 0x70,
+           0x5f, 0x90, 0xc1, 0x0e, 0x7e, 0xb1, 0xe0, 0x2f  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xd8, 0x63, 0xae, 0x15, 0x34, 0x8f, 0x42, 0xf9  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x78, 0xb7, 0xe6, 0x29, 0x44, 0x8b, 0xda, 0x15  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbc, 0x78, 0xc4, 0xf0, 0x4c, 0x88, 0x34,
+           0xe0, 0x5c, 0x98, 0x24, 0x10, 0xac, 0x68, 0xd4  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x78, 0xb7, 0xe6, 0x29, 0x44, 0x8b, 0xda, 0x15  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbd, 0x7a, 0xc7, 0xf4, 0x49, 0x8e, 0x33,
+           0xe8, 0x55, 0x92, 0x2f, 0x1c, 0xa1, 0x66, 0xdb  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x65, 0xaa, 0xfb, 0x34, 0x59, 0x96, 0xc7, 0x08  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbe, 0x7c, 0xc2, 0xf8, 0x46, 0x84, 0x3a,
+           0xf0, 0x4e, 0x8c, 0x32, 0x08, 0xb6, 0x74, 0xca  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x65, 0xaa, 0xfb, 0x34, 0x59, 0x96, 0xc7, 0x08  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbf, 0x7e, 0xc1, 0xfc, 0x43, 0x82, 0x3d,
+           0xf8, 0x47, 0x86, 0x39, 0x04, 0xbb, 0x7a, 0xc5  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3,
+           0x94, 0x08, 0xb1, 0x2d, 0xde, 0x42, 0xfb, 0x67  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3,
+           0x94, 0x08, 0xb1, 0x2d, 0xde, 0x42, 0xfb, 0x67  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc1, 0x82, 0x43, 0x04, 0xc5, 0x86, 0x47,
+           0x08, 0xc9, 0x8a, 0x4b, 0x0c, 0xcd, 0x8e, 0x4f  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3,
+           0x89, 0x15, 0xac, 0x30, 0xc3, 0x5f, 0xe6, 0x7a  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc2, 0x84, 0x46, 0x08, 0xca, 0x8c, 0x4e,
+           0x10, 0xd2, 0x94, 0x56, 0x18, 0xda, 0x9c, 0x5e  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3,
+           0x89, 0x15, 0xac, 0x30, 0xc3, 0x5f, 0xe6, 0x7a  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc3, 0x86, 0x45, 0x0c, 0xcf, 0x8a, 0x49,
+           0x18, 0xdb, 0x9e, 0x5d, 0x14, 0xd7, 0x92, 0x51  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x57, 0xcb, 0x72, 0xee,
+           0xae, 0x32, 0x8b, 0x17, 0xf9, 0x65, 0xdc, 0x40  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc4, 0x88, 0x4c, 0x10, 0xd4, 0x98, 0x5c,
+           0x20, 0xe4, 0xa8, 0x6c, 0x30, 0xf4, 0xb8, 0x7c  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x57, 0xcb, 0x72, 0xee,
+           0xae, 0x32, 0x8b, 0x17, 0xf9, 0x65, 0xdc, 0x40  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc5, 0x8a, 0x4f, 0x14, 0xd1, 0x9e, 0x5b,
+           0x28, 0xed, 0xa2, 0x67, 0x3c, 0xf9, 0xb6, 0x73  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x57, 0xcb, 0x72, 0xee,
+           0xb3, 0x2f, 0x96, 0x0a, 0xe4, 0x78, 0xc1, 0x5d  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc6, 0x8c, 0x4a, 0x18, 0xde, 0x94, 0x52,
+           0x30, 0xf6, 0xbc, 0x7a, 0x28, 0xee, 0xa4, 0x62  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x57, 0xcb, 0x72, 0xee,
+           0xb3, 0x2f, 0x96, 0x0a, 0xe4, 0x78, 0xc1, 0x5d  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc7, 0x8e, 0x49, 0x1c, 0xdb, 0x92, 0x55,
+           0x38, 0xff, 0xb6, 0x71, 0x24, 0xe3, 0xaa, 0x6d  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xe0, 0x7c, 0xd8, 0x44, 0x90, 0x0c, 0xa8, 0x34  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc8, 0x90, 0x58, 0x20, 0xe8, 0xb0, 0x78,
+           0x40, 0x88, 0xd0, 0x18, 0x60, 0xa8, 0xf0, 0x38  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xe0, 0x7c, 0xd8, 0x44, 0x90, 0x0c, 0xa8, 0x34  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc9, 0x92, 0x5b, 0x24, 0xed, 0xb6, 0x7f,
+           0x48, 0x81, 0xda, 0x13, 0x6c, 0xa5, 0xfe, 0x37  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xfd, 0x61, 0xc5, 0x59, 0x8d, 0x11, 0xb5, 0x29  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xca, 0x94, 0x5e, 0x28, 0xe2, 0xbc, 0x76,
+           0x50, 0x9a, 0xc4, 0x0e, 0x78, 0xb2, 0xec, 0x26  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xfd, 0x61, 0xc5, 0x59, 0x8d, 0x11, 0xb5, 0x29  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xcb, 0x96, 0x5d, 0x2c, 0xe7, 0xba, 0x71,
+           0x58, 0x93, 0xce, 0x05, 0x74, 0xbf, 0xe2, 0x29  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x6d, 0xf1, 0x55, 0xc9,
+           0xda, 0x46, 0xe2, 0x7e, 0xb7, 0x2b, 0x8f, 0x13  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xcc, 0x98, 0x54, 0x30, 0xfc, 0xa8, 0x64,
+           0x60, 0xac, 0xf8, 0x34, 0x50, 0x9c, 0xc8, 0x04  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x6d, 0xf1, 0x55, 0xc9,
+           0xda, 0x46, 0xe2, 0x7e, 0xb7, 0x2b, 0x8f, 0x13  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xcd, 0x9a, 0x57, 0x34, 0xf9, 0xae, 0x63,
+           0x68, 0xa5, 0xf2, 0x3f, 0x5c, 0x91, 0xc6, 0x0b  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x6d, 0xf1, 0x55, 0xc9,
+           0xc7, 0x5b, 0xff, 0x63, 0xaa, 0x36, 0x92, 0x0e  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xce, 0x9c, 0x52, 0x38, 0xf6, 0xa4, 0x6a,
+           0x70, 0xbe, 0xec, 0x22, 0x48, 0x86, 0xd4, 0x1a  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x6d, 0xf1, 0x55, 0xc9,
+           0xc7, 0x5b, 0xff, 0x63, 0xaa, 0x36, 0x92, 0x0e  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x78, 0xb7, 0xe6, 0x29, 0x44, 0x8b, 0xda, 0x15  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0,
+           0x7c, 0xfd, 0x63, 0xe2, 0x42, 0xc3, 0x5d, 0xdc  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0,
+           0x7c, 0xfd, 0x63, 0xe2, 0x42, 0xc3, 0x5d, 0xdc  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd1, 0xa2, 0x73, 0x44, 0x95, 0xe6, 0x37,
+           0x88, 0x59, 0x2a, 0xfb, 0xcc, 0x1d, 0x6e, 0xbf  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0,
+           0x61, 0xe0, 0x7e, 0xff, 0x5f, 0xde, 0x40, 0xc1  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x90, 0x42, 0x34, 0xe6, 0xd8, 0x0a, 0x7c, 0xae  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0,
+           0x61, 0xe0, 0x7e, 0xff, 0x5f, 0xde, 0x40, 0xc1  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd3, 0xa6, 0x75, 0x4c, 0x9f, 0xea, 0x39,
+           0x98, 0x4b, 0x3e, 0xed, 0xd4, 0x07, 0x72, 0xa1  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x23, 0xa2, 0x3c, 0xbd,
+           0x46, 0xc7, 0x59, 0xd8, 0x65, 0xe4, 0x7a, 0xfb  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd4, 0xa8, 0x7c, 0x50, 0x84, 0xf8, 0x2c,
+           0xa0, 0x74, 0x08, 0xdc, 0xf0, 0x24, 0x58, 0x8c  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x23, 0xa2, 0x3c, 0xbd,
+           0x46, 0xc7, 0x59, 0xd8, 0x65, 0xe4, 0x7a, 0xfb  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd5, 0xaa, 0x7f, 0x54, 0x81, 0xfe, 0x2b,
+           0xa8, 0x7d, 0x02, 0xd7, 0xfc, 0x29, 0x56, 0x83  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x23, 0xa2, 0x3c, 0xbd,
+           0x5b, 0xda, 0x44, 0xc5, 0x78, 0xf9, 0x67, 0xe6  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd6, 0xac, 0x7a, 0x58, 0x8e, 0xf4, 0x22,
+           0xb0, 0x66, 0x1c, 0xca, 0xe8, 0x3e, 0x44, 0x92  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x23, 0xa2, 0x3c, 0xbd,
+           0x5b, 0xda, 0x44, 0xc5, 0x78, 0xf9, 0x67, 0xe6  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd7, 0xae, 0x79, 0x5c, 0x8b, 0xf2, 0x25,
+           0xb8, 0x6f, 0x16, 0xc1, 0xe4, 0x33, 0x4a, 0x9d  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x08, 0x89, 0x0a, 0x8b, 0x0c, 0x8d, 0x0e, 0x8f  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd8, 0xb0, 0x68, 0x60, 0xb8, 0xd0, 0x08,
+           0xc0, 0x18, 0x70, 0xa8, 0xa0, 0x78, 0x10, 0xc8  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x08, 0x89, 0x0a, 0x8b, 0x0c, 0x8d, 0x0e, 0x8f  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd9, 0xb2, 0x6b, 0x64, 0xbd, 0xd6, 0x0f,
+           0xc8, 0x11, 0x7a, 0xa3, 0xac, 0x75, 0x1e, 0xc7  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x15, 0x94, 0x17, 0x96, 0x11, 0x90, 0x13, 0x92  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xda, 0xb4, 0x6e, 0x68, 0xb2, 0xdc, 0x06,
+           0xd0, 0x0a, 0x64, 0xbe, 0xb8, 0x62, 0x0c, 0xd6  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x15, 0x94, 0x17, 0x96, 0x11, 0x90, 0x13, 0x92  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xdb, 0xb6, 0x6d, 0x6c, 0xb7, 0xda, 0x01,
+           0xd8, 0x03, 0x6e, 0xb5, 0xb4, 0x6f, 0x02, 0xd9  },
+       { 0x00, 0x81, 0x02, 0x83, 0x19, 0x98, 0x1b, 0x9a,
+           0x32, 0xb3, 0x30, 0xb1, 0x2b, 0xaa, 0x29, 0xa8  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xdc, 0xb8, 0x64, 0x70, 0xac, 0xc8, 0x14,
+           0xe0, 0x3c, 0x58, 0x84, 0x90, 0x4c, 0x28, 0xf4  },
+       { 0x00, 0x81, 0x02, 0x83, 0x19, 0x98, 0x1b, 0x9a,
+           0x32, 0xb3, 0x30, 0xb1, 0x2b, 0xaa, 0x29, 0xa8  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xdd, 0xba, 0x67, 0x74, 0xa9, 0xce, 0x13,
+           0xe8, 0x35, 0x52, 0x8f, 0x9c, 0x41, 0x26, 0xfb  },
+       { 0x00, 0x81, 0x02, 0x83, 0x19, 0x98, 0x1b, 0x9a,
+           0x2f, 0xae, 0x2d, 0xac, 0x36, 0xb7, 0x34, 0xb5  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xde, 0xbc, 0x62, 0x78, 0xa6, 0xc4, 0x1a,
+           0xf0, 0x2e, 0x4c, 0x92, 0x88, 0x56, 0x34, 0xea  },
+       { 0x00, 0x81, 0x02, 0x83, 0x19, 0x98, 0x1b, 0x9a,
+           0x2f, 0xae, 0x2d, 0xac, 0x36, 0xb7, 0x34, 0xb5  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xdf, 0xbe, 0x61, 0x7c, 0xa3, 0xc2, 0x1d,
+           0xf8, 0x27, 0x46, 0x99, 0x84, 0x5b, 0x3a, 0xe5  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55,
+           0x59, 0xff, 0x08, 0xae, 0xfb, 0x5d, 0xaa, 0x0c  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55,
+           0x59, 0xff, 0x08, 0xae, 0xfb, 0x5d, 0xaa, 0x0c  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe1, 0xc2, 0x23, 0x84, 0x65, 0x46, 0xa7,
+           0x08, 0xe9, 0xca, 0x2b, 0x8c, 0x6d, 0x4e, 0xaf  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55,
+           0x44, 0xe2, 0x15, 0xb3, 0xe6, 0x40, 0xb7, 0x11  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe2, 0xc4, 0x26, 0x88, 0x6a, 0x4c, 0xae,
+           0x10, 0xf2, 0xd4, 0x36, 0x98, 0x7a, 0x5c, 0xbe  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55,
+           0x44, 0xe2, 0x15, 0xb3, 0xe6, 0x40, 0xb7, 0x11  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe3, 0xc6, 0x25, 0x8c, 0x6f, 0x4a, 0xa9,
+           0x18, 0xfb, 0xde, 0x3d, 0x94, 0x77, 0x52, 0xb1  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xbf, 0x19, 0xee, 0x48,
+           0x63, 0xc5, 0x32, 0x94, 0xdc, 0x7a, 0x8d, 0x2b  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe4, 0xc8, 0x2c, 0x90, 0x74, 0x58, 0xbc,
+           0x20, 0xc4, 0xe8, 0x0c, 0xb0, 0x54, 0x78, 0x9c  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xbf, 0x19, 0xee, 0x48,
+           0x63, 0xc5, 0x32, 0x94, 0xdc, 0x7a, 0x8d, 0x2b  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe5, 0xca, 0x2f, 0x94, 0x71, 0x5e, 0xbb,
+           0x28, 0xcd, 0xe2, 0x07, 0xbc, 0x59, 0x76, 0x93  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xbf, 0x19, 0xee, 0x48,
+           0x7e, 0xd8, 0x2f, 0x89, 0xc1, 0x67, 0x90, 0x36  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe6, 0xcc, 0x2a, 0x98, 0x7e, 0x54, 0xb2,
+           0x30, 0xd6, 0xfc, 0x1a, 0xa8, 0x4e, 0x64, 0x82  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xbf, 0x19, 0xee, 0x48,
+           0x7e, 0xd8, 0x2f, 0x89, 0xc1, 0x67, 0x90, 0x36  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe7, 0xce, 0x29, 0x9c, 0x7b, 0x52, 0xb5,
+           0x38, 0xdf, 0xf6, 0x11, 0xa4, 0x43, 0x6a, 0x8d  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x2d, 0x8b, 0x61, 0xc7, 0xb5, 0x13, 0xf9, 0x5f  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x40, 0xa8, 0x90, 0x78, 0xe0, 0x08, 0x30, 0xd8  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x2d, 0x8b, 0x61, 0xc7, 0xb5, 0x13, 0xf9, 0x5f  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe9, 0xd2, 0x3b, 0xa4, 0x4d, 0x76, 0x9f,
+           0x48, 0xa1, 0x9a, 0x73, 0xec, 0x05, 0x3e, 0xd7  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x30, 0x96, 0x7c, 0xda, 0xa8, 0x0e, 0xe4, 0x42  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xea, 0xd4, 0x3e, 0xa8, 0x42, 0x7c, 0x96,
+           0x50, 0xba, 0x84, 0x6e, 0xf8, 0x12, 0x2c, 0xc6  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x30, 0x96, 0x7c, 0xda, 0xa8, 0x0e, 0xe4, 0x42  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xeb, 0xd6, 0x3d, 0xac, 0x47, 0x7a, 0x91,
+           0x58, 0xb3, 0x8e, 0x65, 0xf4, 0x1f, 0x22, 0xc9  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x85, 0x23, 0xc9, 0x6f,
+           0x17, 0xb1, 0x5b, 0xfd, 0x92, 0x34, 0xde, 0x78  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xec, 0xd8, 0x34, 0xb0, 0x5c, 0x68, 0x84,
+           0x60, 0x8c, 0xb8, 0x54, 0xd0, 0x3c, 0x08, 0xe4  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x85, 0x23, 0xc9, 0x6f,
+           0x17, 0xb1, 0x5b, 0xfd, 0x92, 0x34, 0xde, 0x78  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xed, 0xda, 0x37, 0xb4, 0x59, 0x6e, 0x83,
+           0x68, 0x85, 0xb2, 0x5f, 0xdc, 0x31, 0x06, 0xeb  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x85, 0x23, 0xc9, 0x6f,
+           0x0a, 0xac, 0x46, 0xe0, 0x8f, 0x29, 0xc3, 0x65  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xee, 0xdc, 0x32, 0xb8, 0x56, 0x64, 0x8a,
+           0x70, 0x9e, 0xac, 0x42, 0xc8, 0x26, 0x14, 0xfa  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x85, 0x23, 0xc9, 0x6f,
+           0x0a, 0xac, 0x46, 0xe0, 0x8f, 0x29, 0xc3, 0x65  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xef, 0xde, 0x31, 0xbc, 0x53, 0x62, 0x8d,
+           0x78, 0x97, 0xa6, 0x49, 0xc4, 0x2b, 0x1a, 0xf5  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06,
+           0xb1, 0x0a, 0xda, 0x61, 0x67, 0xdc, 0x0c, 0xb7  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06,
+           0xb1, 0x0a, 0xda, 0x61, 0x67, 0xdc, 0x0c, 0xb7  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf1, 0xe2, 0x13, 0xc4, 0x35, 0x26, 0xd7,
+           0x88, 0x79, 0x6a, 0x9b, 0x4c, 0xbd, 0xae, 0x5f  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06,
+           0xac, 0x17, 0xc7, 0x7c, 0x7a, 0xc1, 0x11, 0xaa  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf2, 0xe4, 0x16, 0xc8, 0x3a, 0x2c, 0xde,
+           0x90, 0x62, 0x74, 0x86, 0x58, 0xaa, 0xbc, 0x4e  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06,
+           0xac, 0x17, 0xc7, 0x7c, 0x7a, 0xc1, 0x11, 0xaa  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf3, 0xe6, 0x15, 0xcc, 0x3f, 0x2a, 0xd9,
+           0x98, 0x6b, 0x7e, 0x8d, 0x54, 0xa7, 0xb2, 0x41  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xcb, 0x70, 0xa0, 0x1b,
+           0x8b, 0x30, 0xe0, 0x5b, 0x40, 0xfb, 0x2b, 0x90  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf4, 0xe8, 0x1c, 0xd0, 0x24, 0x38, 0xcc,
+           0xa0, 0x54, 0x48, 0xbc, 0x70, 0x84, 0x98, 0x6c  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xcb, 0x70, 0xa0, 0x1b,
+           0x8b, 0x30, 0xe0, 0x5b, 0x40, 0xfb, 0x2b, 0x90  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xa8, 0x5d, 0x42, 0xb7, 0x7c, 0x89, 0x96, 0x63  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xcb, 0x70, 0xa0, 0x1b,
+           0x96, 0x2d, 0xfd, 0x46, 0x5d, 0xe6, 0x36, 0x8d  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf6, 0xec, 0x1a, 0xd8, 0x2e, 0x34, 0xc2,
+           0xb0, 0x46, 0x5c, 0xaa, 0x68, 0x9e, 0x84, 0x72  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xcb, 0x70, 0xa0, 0x1b,
+           0x96, 0x2d, 0xfd, 0x46, 0x5d, 0xe6, 0x36, 0x8d  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf7, 0xee, 0x19, 0xdc, 0x2b, 0x32, 0xc5,
+           0xb8, 0x4f, 0x56, 0xa1, 0x64, 0x93, 0x8a, 0x7d  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xc5, 0x7e, 0xb3, 0x08, 0x29, 0x92, 0x5f, 0xe4  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf8, 0xf0, 0x08, 0xe0, 0x18, 0x10, 0xe8,
+           0xc0, 0x38, 0x30, 0xc8, 0x20, 0xd8, 0xd0, 0x28  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xc5, 0x7e, 0xb3, 0x08, 0x29, 0x92, 0x5f, 0xe4  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf9, 0xf2, 0x0b, 0xe4, 0x1d, 0x16, 0xef,
+           0xc8, 0x31, 0x3a, 0xc3, 0x2c, 0xd5, 0xde, 0x27  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xd8, 0x63, 0xae, 0x15, 0x34, 0x8f, 0x42, 0xf9  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfa, 0xf4, 0x0e, 0xe8, 0x12, 0x1c, 0xe6,
+           0xd0, 0x2a, 0x24, 0xde, 0x38, 0xc2, 0xcc, 0x36  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xd8, 0x63, 0xae, 0x15, 0x34, 0x8f, 0x42, 0xf9  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfb, 0xf6, 0x0d, 0xec, 0x17, 0x1a, 0xe1,
+           0xd8, 0x23, 0x2e, 0xd5, 0x34, 0xcf, 0xc2, 0x39  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xf1, 0x4a, 0x87, 0x3c,
+           0xff, 0x44, 0x89, 0x32, 0x0e, 0xb5, 0x78, 0xc3  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfc, 0xf8, 0x04, 0xf0, 0x0c, 0x08, 0xf4,
+           0xe0, 0x1c, 0x18, 0xe4, 0x10, 0xec, 0xe8, 0x14  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xf1, 0x4a, 0x87, 0x3c,
+           0xff, 0x44, 0x89, 0x32, 0x0e, 0xb5, 0x78, 0xc3  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfd, 0xfa, 0x07, 0xf4, 0x09, 0x0e, 0xf3,
+           0xe8, 0x15, 0x12, 0xef, 0x1c, 0xe1, 0xe6, 0x1b  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xf1, 0x4a, 0x87, 0x3c,
+           0xe2, 0x59, 0x94, 0x2f, 0x13, 0xa8, 0x65, 0xde  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfe, 0xfc, 0x02, 0xf8, 0x06, 0x04, 0xfa,
+           0xf0, 0x0e, 0x0c, 0xf2, 0x08, 0xf6, 0xf4, 0x0a  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xf1, 0x4a, 0x87, 0x3c,
+           0xe2, 0x59, 0x94, 0x2f, 0x13, 0xa8, 0x65, 0xde  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xff, 0xfe, 0x01, 0xfc, 0x03, 0x02, 0xfd,
+           0xf8, 0x07, 0x06, 0xf9, 0x04, 0xfb, 0xfa, 0x05  }
+};
+
+#endif /* defined(__aarch64__) */
diff --git a/zfs/module/zfs/vdev_raidz_math_aarch64_neon_common.h b/zfs/module/zfs/vdev_raidz_math_aarch64_neon_common.h
new file mode 100644 (file)
index 0000000..08dbdda
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * 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 (C) 2016 Romain Dolbeau. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <linux/simd_aarch64.h>
+
+#define        __asm __asm__ __volatile__
+
+#define        _REG_CNT(_0, _1, _2, _3, _4, _5, _6, _7, N, ...) N
+#define        REG_CNT(r...) _REG_CNT(r, 8, 7, 6, 5, 4, 3, 2, 1)
+
+#define        VR0_(REG, ...) "%[w"#REG"]"
+#define        VR1_(_1, REG, ...) "%[w"#REG"]"
+#define        VR2_(_1, _2, REG, ...) "%[w"#REG"]"
+#define        VR3_(_1, _2, _3, REG, ...) "%[w"#REG"]"
+#define        VR4_(_1, _2, _3, _4, REG, ...) "%[w"#REG"]"
+#define        VR5_(_1, _2, _3, _4, _5, REG, ...) "%[w"#REG"]"
+#define        VR6_(_1, _2, _3, _4, _5, _6, REG, ...) "%[w"#REG"]"
+#define        VR7_(_1, _2, _3, _4, _5, _6, _7, REG, ...) "%[w"#REG"]"
+
+/*
+ * Here we need registers not used otherwise.
+ * They will be used in unused ASM for the case
+ * with more registers than required... but GGC
+ * will still need to make sure the constraints
+ * are correct, and duplicate constraints are illegal
+ * ... and we use the "register" number as a name
+ */
+
+#define        VR0(r...) VR0_(r)
+#define        VR1(r...) VR1_(r)
+#define        VR2(r...) VR2_(r, 36)
+#define        VR3(r...) VR3_(r, 36, 35)
+#define        VR4(r...) VR4_(r, 36, 35, 34, 33)
+#define        VR5(r...) VR5_(r, 36, 35, 34, 33, 32)
+#define        VR6(r...) VR6_(r, 36, 35, 34, 33, 32, 31)
+#define        VR7(r...) VR7_(r, 36, 35, 34, 33, 32, 31, 30)
+
+#define        VR(X) "%[w"#X"]"
+
+#define        RVR0_(REG, ...) [w##REG] "w" (w##REG)
+#define        RVR1_(_1, REG, ...) [w##REG] "w" (w##REG)
+#define        RVR2_(_1, _2, REG, ...) [w##REG] "w" (w##REG)
+#define        RVR3_(_1, _2, _3, REG, ...) [w##REG] "w" (w##REG)
+#define        RVR4_(_1, _2, _3, _4, REG, ...) [w##REG] "w" (w##REG)
+#define        RVR5_(_1, _2, _3, _4, _5, REG, ...) [w##REG] "w" (w##REG)
+#define        RVR6_(_1, _2, _3, _4, _5, _6, REG, ...) [w##REG] "w" (w##REG)
+#define        RVR7_(_1, _2, _3, _4, _5, _6, _7, REG, ...) [w##REG] "w" (w##REG)
+
+#define        RVR0(r...) RVR0_(r)
+#define        RVR1(r...) RVR1_(r)
+#define        RVR2(r...) RVR2_(r, 36)
+#define        RVR3(r...) RVR3_(r, 36, 35)
+#define        RVR4(r...) RVR4_(r, 36, 35, 34, 33)
+#define        RVR5(r...) RVR5_(r, 36, 35, 34, 33, 32)
+#define        RVR6(r...) RVR6_(r, 36, 35, 34, 33, 32, 31)
+#define        RVR7(r...) RVR7_(r, 36, 35, 34, 33, 32, 31, 30)
+
+#define        RVR(X) [w##X] "w" (w##X)
+
+#define        WVR0_(REG, ...) [w##REG] "=w" (w##REG)
+#define        WVR1_(_1, REG, ...) [w##REG] "=w" (w##REG)
+#define        WVR2_(_1, _2, REG, ...) [w##REG] "=w" (w##REG)
+#define        WVR3_(_1, _2, _3, REG, ...) [w##REG] "=w" (w##REG)
+#define        WVR4_(_1, _2, _3, _4, REG, ...) [w##REG] "=w" (w##REG)
+#define        WVR5_(_1, _2, _3, _4, _5, REG, ...) [w##REG] "=w" (w##REG)
+#define        WVR6_(_1, _2, _3, _4, _5, _6, REG, ...) [w##REG] "=w" (w##REG)
+#define        WVR7_(_1, _2, _3, _4, _5, _6, _7, REG, ...) [w##REG] "=w" (w##REG)
+
+#define        WVR0(r...) WVR0_(r)
+#define        WVR1(r...) WVR1_(r)
+#define        WVR2(r...) WVR2_(r, 36)
+#define        WVR3(r...) WVR3_(r, 36, 35)
+#define        WVR4(r...) WVR4_(r, 36, 35, 34, 33)
+#define        WVR5(r...) WVR5_(r, 36, 35, 34, 33, 32)
+#define        WVR6(r...) WVR6_(r, 36, 35, 34, 33, 32, 31)
+#define        WVR7(r...) WVR7_(r, 36, 35, 34, 33, 32, 31, 30)
+
+#define        WVR(X) [w##X] "=w" (w##X)
+
+#define        UVR0_(REG, ...) [w##REG] "+&w" (w##REG)
+#define        UVR1_(_1, REG, ...) [w##REG] "+&w" (w##REG)
+#define        UVR2_(_1, _2, REG, ...) [w##REG] "+&w" (w##REG)
+#define        UVR3_(_1, _2, _3, REG, ...) [w##REG] "+&w" (w##REG)
+#define        UVR4_(_1, _2, _3, _4, REG, ...) [w##REG] "+&w" (w##REG)
+#define        UVR5_(_1, _2, _3, _4, _5, REG, ...) [w##REG] "+&w" (w##REG)
+#define        UVR6_(_1, _2, _3, _4, _5, _6, REG, ...) [w##REG] "+&w" (w##REG)
+#define        UVR7_(_1, _2, _3, _4, _5, _6, _7, REG, ...) [w##REG] "+&w" (w##REG)
+
+#define        UVR0(r...) UVR0_(r)
+#define        UVR1(r...) UVR1_(r)
+#define        UVR2(r...) UVR2_(r, 36)
+#define        UVR3(r...) UVR3_(r, 36, 35)
+#define        UVR4(r...) UVR4_(r, 36, 35, 34, 33)
+#define        UVR5(r...) UVR5_(r, 36, 35, 34, 33, 32)
+#define        UVR6(r...) UVR6_(r, 36, 35, 34, 33, 32, 31)
+#define        UVR7(r...) UVR7_(r, 36, 35, 34, 33, 32, 31, 30)
+
+#define        UVR(X) [w##X] "+&w" (w##X)
+
+#define        R_01(REG1, REG2, ...) REG1, REG2
+#define        _R_23(_0, _1, REG2, REG3, ...) REG2, REG3
+#define        R_23(REG...) _R_23(REG, 1, 2, 3)
+
+#define        ASM_BUG()       ASSERT(0)
+
+#define        OFFSET(ptr, val)        (((unsigned char *)ptr)+val)
+
+extern const uint8_t gf_clmul_mod_lt[4*256][16];
+
+#define        ELEM_SIZE 16
+
+typedef struct v {
+       uint8_t b[ELEM_SIZE] __attribute__((aligned(ELEM_SIZE)));
+} v_t;
+
+#define        PREFETCHNTA(ptr, offset)                                        \
+{                                                                      \
+       __asm(                                                          \
+           "prfm pstl1strm, %[MEM]\n"                                  \
+           :   :       [MEM] "Q" (*(ptr + offset)));                   \
+}
+
+#define        PREFETCH(ptr, offset)                                           \
+{                                                                      \
+       __asm(                                                          \
+           "prfm pldl1keep, %[MEM]\n"                                  \
+           :   :       [MEM] "Q" (*(ptr + offset)));                   \
+}
+
+#define        XOR_ACC(src, r...)                                              \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+               "ld1 { v21.4s },%[SRC0]\n"                              \
+               "ld1 { v20.4s },%[SRC1]\n"                              \
+               "ld1 { v19.4s },%[SRC2]\n"                              \
+               "ld1 { v18.4s },%[SRC3]\n"                              \
+               "eor " VR0(r) ".16b," VR0(r) ".16b,v21.16b\n"           \
+               "eor " VR1(r) ".16b," VR1(r) ".16b,v20.16b\n"           \
+               "eor " VR2(r) ".16b," VR2(r) ".16b,v19.16b\n"           \
+               "eor " VR3(r) ".16b," VR3(r) ".16b,v18.16b\n"           \
+               "ld1 { v21.4s },%[SRC4]\n"                              \
+               "ld1 { v20.4s },%[SRC5]\n"                              \
+               "ld1 { v19.4s },%[SRC6]\n"                              \
+               "ld1 { v18.4s },%[SRC7]\n"                              \
+               "eor " VR4(r) ".16b," VR4(r) ".16b,v21.16b\n"           \
+               "eor " VR5(r) ".16b," VR5(r) ".16b,v20.16b\n"           \
+               "eor " VR6(r) ".16b," VR6(r) ".16b,v19.16b\n"           \
+               "eor " VR7(r) ".16b," VR7(r) ".16b,v18.16b\n"           \
+               :       UVR0(r), UVR1(r), UVR2(r), UVR3(r),             \
+                       UVR4(r), UVR5(r), UVR6(r), UVR7(r)              \
+               :       [SRC0] "Q" (*(OFFSET(src, 0))),                 \
+               [SRC1] "Q" (*(OFFSET(src, 16))),                        \
+               [SRC2] "Q" (*(OFFSET(src, 32))),                        \
+               [SRC3] "Q" (*(OFFSET(src, 48))),                        \
+               [SRC4] "Q" (*(OFFSET(src, 64))),                        \
+               [SRC5] "Q" (*(OFFSET(src, 80))),                        \
+               [SRC6] "Q" (*(OFFSET(src, 96))),                        \
+               [SRC7] "Q" (*(OFFSET(src, 112)))                        \
+               :       "v18", "v19", "v20", "v21");                    \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+               "ld1 { v21.4s },%[SRC0]\n"                              \
+               "ld1 { v20.4s },%[SRC1]\n"                              \
+               "ld1 { v19.4s },%[SRC2]\n"                              \
+               "ld1 { v18.4s },%[SRC3]\n"                              \
+               "eor " VR0(r) ".16b," VR0(r) ".16b,v21.16b\n"           \
+               "eor " VR1(r) ".16b," VR1(r) ".16b,v20.16b\n"           \
+               "eor " VR2(r) ".16b," VR2(r) ".16b,v19.16b\n"           \
+               "eor " VR3(r) ".16b," VR3(r) ".16b,v18.16b\n"           \
+               :       UVR0(r), UVR1(r), UVR2(r), UVR3(r)              \
+               :       [SRC0] "Q" (*(OFFSET(src, 0))),                 \
+               [SRC1] "Q" (*(OFFSET(src, 16))),                        \
+               [SRC2] "Q" (*(OFFSET(src, 32))),                        \
+               [SRC3] "Q" (*(OFFSET(src, 48)))                         \
+               :       "v18", "v19", "v20", "v21");                    \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+               "ld1 { v21.4s },%[SRC0]\n"                              \
+               "ld1 { v20.4s },%[SRC1]\n"                              \
+               "eor " VR0(r) ".16b," VR0(r) ".16b,v21.16b\n"           \
+               "eor " VR1(r) ".16b," VR1(r) ".16b,v20.16b\n"           \
+               :       UVR0(r), UVR1(r)                                \
+               :       [SRC0] "Q" (*(OFFSET(src, 0))),                 \
+               [SRC1] "Q" (*(OFFSET(src, 16)))                         \
+               :       "v20", "v21");                                  \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        XOR(r...)                                                       \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+               "eor " VR4(r) ".16b," VR4(r) ".16b," VR0(r) ".16b\n"    \
+               "eor " VR5(r) ".16b," VR5(r) ".16b," VR1(r) ".16b\n"    \
+               "eor " VR6(r) ".16b," VR6(r) ".16b," VR2(r) ".16b\n"    \
+               "eor " VR7(r) ".16b," VR7(r) ".16b," VR3(r) ".16b\n"    \
+               :       UVR4(r), UVR5(r), UVR6(r), UVR7(r)              \
+               :       RVR0(r), RVR1(r), RVR2(r), RVR3(r));            \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+               "eor " VR2(r) ".16b," VR2(r) ".16b," VR0(r) ".16b\n"    \
+               "eor " VR3(r) ".16b," VR3(r) ".16b," VR1(r) ".16b\n"    \
+               :       UVR2(r), UVR3(r)                                \
+               :       RVR0(r), RVR1(r));                              \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        ZERO(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+               "eor " VR0(r) ".16b," VR0(r) ".16b," VR0(r) ".16b\n"    \
+               "eor " VR1(r) ".16b," VR1(r) ".16b," VR1(r) ".16b\n"    \
+               "eor " VR2(r) ".16b," VR2(r) ".16b," VR2(r) ".16b\n"    \
+               "eor " VR3(r) ".16b," VR3(r) ".16b," VR3(r) ".16b\n"    \
+               :       WVR0(r), WVR1(r), WVR2(r), WVR3(r));            \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+               "eor " VR0(r) ".16b," VR0(r) ".16b," VR0(r) ".16b\n"    \
+               "eor " VR1(r) ".16b," VR1(r) ".16b," VR1(r) ".16b\n"    \
+               :       WVR0(r), WVR1(r));                              \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        COPY(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+               "mov " VR4(r) ".16b," VR0(r) ".16b\n"                   \
+               "mov " VR5(r) ".16b," VR1(r) ".16b\n"                   \
+               "mov " VR6(r) ".16b," VR2(r) ".16b\n"                   \
+               "mov " VR7(r) ".16b," VR3(r) ".16b\n"                   \
+               :       WVR4(r), WVR5(r), WVR6(r), WVR7(r)              \
+               :       RVR0(r), RVR1(r), RVR2(r), RVR3(r));            \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+               "mov " VR2(r) ".16b," VR0(r) ".16b\n"                   \
+               "mov " VR3(r) ".16b," VR1(r) ".16b\n"                   \
+               :       WVR2(r), WVR3(r)                                \
+               :       RVR0(r), RVR1(r));                              \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        LOAD(src, r...)                                                 \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+               "ld1 { " VR0(r) ".4s },%[SRC0]\n"                       \
+               "ld1 { " VR1(r) ".4s },%[SRC1]\n"                       \
+               "ld1 { " VR2(r) ".4s },%[SRC2]\n"                       \
+               "ld1 { " VR3(r) ".4s },%[SRC3]\n"                       \
+               "ld1 { " VR4(r) ".4s },%[SRC4]\n"                       \
+               "ld1 { " VR5(r) ".4s },%[SRC5]\n"                       \
+               "ld1 { " VR6(r) ".4s },%[SRC6]\n"                       \
+               "ld1 { " VR7(r) ".4s },%[SRC7]\n"                       \
+               :       WVR0(r), WVR1(r), WVR2(r), WVR3(r),             \
+                       WVR4(r), WVR5(r), WVR6(r), WVR7(r)              \
+               :       [SRC0] "Q" (*(OFFSET(src, 0))),                 \
+               [SRC1] "Q" (*(OFFSET(src, 16))),                        \
+               [SRC2] "Q" (*(OFFSET(src, 32))),                        \
+               [SRC3] "Q" (*(OFFSET(src, 48))),                        \
+               [SRC4] "Q" (*(OFFSET(src, 64))),                        \
+               [SRC5] "Q" (*(OFFSET(src, 80))),                        \
+               [SRC6] "Q" (*(OFFSET(src, 96))),                        \
+               [SRC7] "Q" (*(OFFSET(src, 112))));                      \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+               "ld1 { " VR0(r) ".4s },%[SRC0]\n"                       \
+               "ld1 { " VR1(r) ".4s },%[SRC1]\n"                       \
+               "ld1 { " VR2(r) ".4s },%[SRC2]\n"                       \
+               "ld1 { " VR3(r) ".4s },%[SRC3]\n"                       \
+               :       WVR0(r), WVR1(r), WVR2(r), WVR3(r)              \
+               :       [SRC0] "Q" (*(OFFSET(src, 0))),                 \
+               [SRC1] "Q" (*(OFFSET(src, 16))),                        \
+               [SRC2] "Q" (*(OFFSET(src, 32))),                        \
+               [SRC3] "Q" (*(OFFSET(src, 48))));                       \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+               "ld1 { " VR0(r) ".4s },%[SRC0]\n"                       \
+               "ld1 { " VR1(r) ".4s },%[SRC1]\n"                       \
+               :       WVR0(r), WVR1(r)                                \
+               :       [SRC0] "Q" (*(OFFSET(src, 0))),                 \
+               [SRC1] "Q" (*(OFFSET(src, 16))));                       \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        STORE(dst, r...)                                                \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+               "st1 { " VR0(r) ".4s },%[DST0]\n"                       \
+               "st1 { " VR1(r) ".4s },%[DST1]\n"                       \
+               "st1 { " VR2(r) ".4s },%[DST2]\n"                       \
+               "st1 { " VR3(r) ".4s },%[DST3]\n"                       \
+               "st1 { " VR4(r) ".4s },%[DST4]\n"                       \
+               "st1 { " VR5(r) ".4s },%[DST5]\n"                       \
+               "st1 { " VR6(r) ".4s },%[DST6]\n"                       \
+               "st1 { " VR7(r) ".4s },%[DST7]\n"                       \
+               :       [DST0] "=Q" (*(OFFSET(dst, 0))),                \
+               [DST1] "=Q" (*(OFFSET(dst, 16))),                       \
+               [DST2] "=Q" (*(OFFSET(dst, 32))),                       \
+               [DST3] "=Q" (*(OFFSET(dst, 48))),                       \
+               [DST4] "=Q" (*(OFFSET(dst, 64))),                       \
+               [DST5] "=Q" (*(OFFSET(dst, 80))),                       \
+               [DST6] "=Q" (*(OFFSET(dst, 96))),                       \
+               [DST7] "=Q" (*(OFFSET(dst, 112)))                       \
+               :       RVR0(r), RVR1(r), RVR2(r), RVR3(r),             \
+                       RVR4(r), RVR5(r), RVR6(r), RVR7(r));            \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+               "st1 { " VR0(r) ".4s },%[DST0]\n"                       \
+               "st1 { " VR1(r) ".4s },%[DST1]\n"                       \
+               "st1 { " VR2(r) ".4s },%[DST2]\n"                       \
+               "st1 { " VR3(r) ".4s },%[DST3]\n"                       \
+               :       [DST0] "=Q" (*(OFFSET(dst, 0))),                \
+               [DST1] "=Q" (*(OFFSET(dst, 16))),                       \
+               [DST2] "=Q" (*(OFFSET(dst, 32))),                       \
+               [DST3] "=Q" (*(OFFSET(dst, 48)))                        \
+               :       RVR0(r), RVR1(r), RVR2(r), RVR3(r));            \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+               "st1 { " VR0(r) ".4s },%[DST0]\n"                       \
+               "st1 { " VR1(r) ".4s },%[DST1]\n"                       \
+               :       [DST0] "=Q" (*(OFFSET(dst, 0))),                \
+               [DST1] "=Q" (*(OFFSET(dst, 16)))                        \
+               :       RVR0(r), RVR1(r));                              \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+/*
+ * Unfortunately cannot use the macro, because GCC
+ * will try to use the macro name and not value
+ * later on...
+ * Kept as a reference to what a numbered variable is
+ */
+#define        _00     "v17"
+#define        _1d     "v16"
+#define        _temp0  "v19"
+#define        _temp1  "v18"
+
+#define        MUL2_SETUP()                                                    \
+{                                                                      \
+       __asm(                                                          \
+       "eor " VR(17) ".16b," VR(17) ".16b," VR(17) ".16b\n"            \
+       "movi " VR(16) ".16b,#0x1d\n"                                   \
+       :       WVR(16), WVR(17));                                      \
+}
+
+#define        MUL2(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+               "cmgt v19.16b," VR(17) ".16b," VR0(r) ".16b\n"          \
+               "cmgt v18.16b," VR(17) ".16b," VR1(r) ".16b\n"          \
+               "cmgt v21.16b," VR(17) ".16b," VR2(r) ".16b\n"          \
+               "cmgt v20.16b," VR(17) ".16b," VR3(r) ".16b\n"          \
+               "and v19.16b,v19.16b," VR(16) ".16b\n"                  \
+               "and v18.16b,v18.16b," VR(16) ".16b\n"                  \
+               "and v21.16b,v21.16b," VR(16) ".16b\n"                  \
+               "and v20.16b,v20.16b," VR(16) ".16b\n"                  \
+               "shl " VR0(r) ".16b," VR0(r) ".16b,#1\n"                \
+               "shl " VR1(r) ".16b," VR1(r) ".16b,#1\n"                \
+               "shl " VR2(r) ".16b," VR2(r) ".16b,#1\n"                \
+               "shl " VR3(r) ".16b," VR3(r) ".16b,#1\n"                \
+               "eor " VR0(r) ".16b,v19.16b," VR0(r) ".16b\n"           \
+               "eor " VR1(r) ".16b,v18.16b," VR1(r) ".16b\n"           \
+               "eor " VR2(r) ".16b,v21.16b," VR2(r) ".16b\n"           \
+               "eor " VR3(r) ".16b,v20.16b," VR3(r) ".16b\n"           \
+               :       UVR0(r), UVR1(r), UVR2(r), UVR3(r)              \
+               :       RVR(17), RVR(16)                                \
+               :       "v18", "v19", "v20", "v21");                    \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+               "cmgt v19.16b," VR(17) ".16b," VR0(r) ".16b\n"          \
+               "cmgt v18.16b," VR(17) ".16b," VR1(r) ".16b\n"          \
+               "and v19.16b,v19.16b," VR(16) ".16b\n"                  \
+               "and v18.16b,v18.16b," VR(16) ".16b\n"                  \
+               "shl " VR0(r) ".16b," VR0(r) ".16b,#1\n"                \
+               "shl " VR1(r) ".16b," VR1(r) ".16b,#1\n"                \
+               "eor " VR0(r) ".16b,v19.16b," VR0(r) ".16b\n"           \
+               "eor " VR1(r) ".16b,v18.16b," VR1(r) ".16b\n"           \
+               :       UVR0(r), UVR1(r)                                \
+               :       RVR(17), RVR(16)                                \
+               :       "v18", "v19");                                  \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL4(r...)                                                      \
+{                                                                      \
+       MUL2(r);                                                        \
+       MUL2(r);                                                        \
+}
+
+/*
+ * Unfortunately cannot use the macro, because GCC
+ * will try to use the macro name and not value
+ * later on...
+ * Kept as a reference to what a register is
+ * (here we're using actual registers for the
+ * clobbered ones)
+ */
+#define        _0f             "v15"
+#define        _a_save         "v14"
+#define        _b_save         "v13"
+#define        _lt_mod_a       "v12"
+#define        _lt_clmul_a     "v11"
+#define        _lt_mod_b       "v10"
+#define        _lt_clmul_b     "v15"
+
+#define        _MULx2(c, r...)                                                 \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 2:                                                         \
+               __asm(                                                  \
+               /* lts for upper part */                                \
+               "movi v15.16b,#0x0f\n"                                  \
+               "ld1 { v10.4s },%[lt0]\n"                               \
+               "ld1 { v11.4s },%[lt1]\n"                               \
+               /* upper part */                                        \
+               "and v14.16b," VR0(r) ".16b,v15.16b\n"                  \
+               "and v13.16b," VR1(r) ".16b,v15.16b\n"                  \
+               "sshr " VR0(r) ".8h," VR0(r) ".8h,#4\n"                 \
+               "sshr " VR1(r) ".8h," VR1(r) ".8h,#4\n"                 \
+               "and " VR0(r) ".16b," VR0(r) ".16b,v15.16b\n"           \
+               "and " VR1(r) ".16b," VR1(r) ".16b,v15.16b\n"           \
+                                                                       \
+               "tbl v12.16b,{v10.16b}," VR0(r) ".16b\n"                \
+               "tbl v10.16b,{v10.16b}," VR1(r) ".16b\n"                \
+               "tbl v15.16b,{v11.16b}," VR0(r) ".16b\n"                \
+               "tbl v11.16b,{v11.16b}," VR1(r) ".16b\n"                \
+                                                                       \
+               "eor " VR0(r) ".16b,v15.16b,v12.16b\n"                  \
+               "eor " VR1(r) ".16b,v11.16b,v10.16b\n"                  \
+               /* lts for lower part */                                \
+               "ld1 { v10.4s },%[lt2]\n"                               \
+               "ld1 { v15.4s },%[lt3]\n"                               \
+               /* lower part */                                        \
+               "tbl v12.16b,{v10.16b},v14.16b\n"                       \
+               "tbl v10.16b,{v10.16b},v13.16b\n"                       \
+               "tbl v11.16b,{v15.16b},v14.16b\n"                       \
+               "tbl v15.16b,{v15.16b},v13.16b\n"                       \
+                                                                       \
+               "eor " VR0(r) ".16b," VR0(r) ".16b,v12.16b\n"           \
+               "eor " VR1(r) ".16b," VR1(r) ".16b,v10.16b\n"           \
+               "eor " VR0(r) ".16b," VR0(r) ".16b,v11.16b\n"           \
+               "eor " VR1(r) ".16b," VR1(r) ".16b,v15.16b\n"           \
+               :       UVR0(r), UVR1(r)                                \
+               :       [lt0] "Q" ((gf_clmul_mod_lt[4*(c)+0][0])),      \
+               [lt1] "Q" ((gf_clmul_mod_lt[4*(c)+1][0])),              \
+               [lt2] "Q" ((gf_clmul_mod_lt[4*(c)+2][0])),              \
+               [lt3] "Q" ((gf_clmul_mod_lt[4*(c)+3][0]))               \
+               :       "v10", "v11", "v12", "v13", "v14", "v15");      \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL(c, r...)                                                    \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               _MULx2(c, R_23(r));                                     \
+               _MULx2(c, R_01(r));                                     \
+               break;                                                  \
+       case 2:                                                         \
+               _MULx2(c, R_01(r));                                     \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        raidz_math_begin()      kfpu_begin()
+#define        raidz_math_end()        kfpu_end()
+
+/* Overkill... */
+#if defined(_KERNEL)
+#define        GEN_X_DEFINE_0_3()      \
+register unsigned char w0 asm("v0") __attribute__((vector_size(16)));  \
+register unsigned char w1 asm("v1") __attribute__((vector_size(16)));  \
+register unsigned char w2 asm("v2") __attribute__((vector_size(16)));  \
+register unsigned char w3 asm("v3") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_4_5()      \
+register unsigned char w4 asm("v4") __attribute__((vector_size(16)));  \
+register unsigned char w5 asm("v5") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_6_7()      \
+register unsigned char w6 asm("v6") __attribute__((vector_size(16)));  \
+register unsigned char w7 asm("v7") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_8_9()      \
+register unsigned char w8 asm("v8") __attribute__((vector_size(16)));  \
+register unsigned char w9 asm("v9") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_10_11()    \
+register unsigned char w10 asm("v10") __attribute__((vector_size(16)));        \
+register unsigned char w11 asm("v11") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_12_15()    \
+register unsigned char w12 asm("v12") __attribute__((vector_size(16)));        \
+register unsigned char w13 asm("v13") __attribute__((vector_size(16)));        \
+register unsigned char w14 asm("v14") __attribute__((vector_size(16)));        \
+register unsigned char w15 asm("v15") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_16()       \
+register unsigned char w16 asm("v16") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_17()       \
+register unsigned char w17 asm("v17") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_18_21()    \
+register unsigned char w18 asm("v18") __attribute__((vector_size(16)));        \
+register unsigned char w19 asm("v19") __attribute__((vector_size(16)));        \
+register unsigned char w20 asm("v20") __attribute__((vector_size(16)));        \
+register unsigned char w21 asm("v21") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_22_23()    \
+register unsigned char w22 asm("v22") __attribute__((vector_size(16)));        \
+register unsigned char w23 asm("v23") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_24_27()    \
+register unsigned char w24 asm("v24") __attribute__((vector_size(16)));        \
+register unsigned char w25 asm("v25") __attribute__((vector_size(16)));        \
+register unsigned char w26 asm("v26") __attribute__((vector_size(16)));        \
+register unsigned char w27 asm("v27") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_28_30()    \
+register unsigned char w28 asm("v28") __attribute__((vector_size(16)));        \
+register unsigned char w29 asm("v29") __attribute__((vector_size(16)));        \
+register unsigned char w30 asm("v30") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_31()       \
+register unsigned char w31 asm("v31") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_32()       \
+register unsigned char w32 asm("v31") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_33_36()    \
+register unsigned char w33 asm("v31") __attribute__((vector_size(16)));        \
+register unsigned char w34 asm("v31") __attribute__((vector_size(16)));        \
+register unsigned char w35 asm("v31") __attribute__((vector_size(16)));        \
+register unsigned char w36 asm("v31") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_37_38()    \
+register unsigned char w37 asm("v31") __attribute__((vector_size(16)));        \
+register unsigned char w38 asm("v31") __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_ALL()      \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_8_9()      \
+       GEN_X_DEFINE_10_11()    \
+       GEN_X_DEFINE_12_15()    \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_18_21()    \
+       GEN_X_DEFINE_22_23()    \
+       GEN_X_DEFINE_24_27()    \
+       GEN_X_DEFINE_28_30()    \
+       GEN_X_DEFINE_31()       \
+       GEN_X_DEFINE_32()       \
+       GEN_X_DEFINE_33_36()    \
+       GEN_X_DEFINE_37_38()
+#else
+#define        GEN_X_DEFINE_0_3()      \
+       unsigned char w0 __attribute__((vector_size(16)));      \
+       unsigned char w1 __attribute__((vector_size(16)));      \
+       unsigned char w2 __attribute__((vector_size(16)));      \
+       unsigned char w3 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_4_5()      \
+       unsigned char w4 __attribute__((vector_size(16)));      \
+       unsigned char w5 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_6_7()      \
+       unsigned char w6 __attribute__((vector_size(16)));      \
+       unsigned char w7 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_8_9()      \
+       unsigned char w8 __attribute__((vector_size(16)));      \
+       unsigned char w9 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_10_11()    \
+       unsigned char w10 __attribute__((vector_size(16)));     \
+       unsigned char w11 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_12_15()    \
+       unsigned char w12 __attribute__((vector_size(16)));     \
+       unsigned char w13 __attribute__((vector_size(16)));     \
+       unsigned char w14 __attribute__((vector_size(16)));     \
+       unsigned char w15 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_16()       \
+       unsigned char w16 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_17()       \
+       unsigned char w17 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_18_21()    \
+       unsigned char w18 __attribute__((vector_size(16)));     \
+       unsigned char w19 __attribute__((vector_size(16)));     \
+       unsigned char w20 __attribute__((vector_size(16)));     \
+       unsigned char w21 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_22_23()    \
+       unsigned char w22 __attribute__((vector_size(16)));     \
+       unsigned char w23 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_24_27()    \
+       unsigned char w24 __attribute__((vector_size(16)));     \
+       unsigned char w25 __attribute__((vector_size(16)));     \
+       unsigned char w26 __attribute__((vector_size(16)));     \
+       unsigned char w27 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_28_30()    \
+       unsigned char w28 __attribute__((vector_size(16)));     \
+       unsigned char w29 __attribute__((vector_size(16)));     \
+       unsigned char w30 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_31()       \
+       unsigned char w31 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_32()       \
+       unsigned char w32 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_33_36()    \
+       unsigned char w33 __attribute__((vector_size(16)));     \
+       unsigned char w34 __attribute__((vector_size(16)));     \
+       unsigned char w35 __attribute__((vector_size(16)));     \
+       unsigned char w36 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_37_38()    \
+       unsigned char w37 __attribute__((vector_size(16)));     \
+       unsigned char w38 __attribute__((vector_size(16)));
+#define        GEN_X_DEFINE_ALL()      \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_8_9()      \
+       GEN_X_DEFINE_10_11()    \
+       GEN_X_DEFINE_12_15()    \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_18_21()    \
+       GEN_X_DEFINE_22_23()    \
+       GEN_X_DEFINE_24_27()    \
+       GEN_X_DEFINE_28_30()    \
+       GEN_X_DEFINE_31()       \
+       GEN_X_DEFINE_32()       \
+       GEN_X_DEFINE_33_36()    \
+       GEN_X_DEFINE_37_38()
+#endif
diff --git a/zfs/module/zfs/vdev_raidz_math_aarch64_neonx2.c b/zfs/module/zfs/vdev_raidz_math_aarch64_neonx2.c
new file mode 100644 (file)
index 0000000..d8d1f1b
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * 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 (C) 2016 Romain Dolbeau. All rights reserved.
+ */
+
+#include <sys/isa_defs.h>
+
+#if defined(__aarch64__)
+
+#include "vdev_raidz_math_aarch64_neon_common.h"
+
+#define        GEN_P_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()
+#define        GEN_P_STRIDE            8
+#define        GEN_P_P                 0, 1, 2, 3, 4, 5, 6, 7
+
+#define        GEN_PQ_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_8_9()      \
+       GEN_X_DEFINE_10_11()    \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_33_36()
+#define        GEN_PQ_STRIDE           4
+#define        GEN_PQ_D                0, 1, 2, 3
+#define        GEN_PQ_P                4, 5, 6, 7
+#define        GEN_PQ_Q                8, 9, 10, 11
+
+#define        GEN_PQR_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_8_9()      \
+       GEN_X_DEFINE_22_23()    \
+       GEN_X_DEFINE_24_27()    \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_33_36()
+#define        GEN_PQR_STRIDE          4
+#define        GEN_PQR_D               0, 1, 2, 3
+#define        GEN_PQR_P               4, 5, 6, 7
+#define        GEN_PQR_Q               8, 9, 22, 23
+#define        GEN_PQR_R               24, 25, 26, 27
+
+#define        REC_P_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_33_36()
+#define        REC_P_STRIDE            4
+#define        REC_P_X                 0, 1, 2, 3
+
+#define        REC_Q_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_33_36()
+#define        REC_Q_STRIDE            4
+#define        REC_Q_X                 0, 1, 2, 3
+
+#define        REC_R_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_33_36()
+#define        REC_R_STRIDE            4
+#define        REC_R_X                 0, 1, 2, 3
+
+#define        REC_PQ_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_8_9()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_22_23()    \
+       GEN_X_DEFINE_33_36()
+#define        REC_PQ_STRIDE           4
+#define        REC_PQ_X                0, 1, 2, 3
+#define        REC_PQ_Y                4, 5, 6, 7
+#define        REC_PQ_D                8, 9, 22, 23
+
+#define        REC_PR_DEFINE() REC_PQ_DEFINE()
+#define        REC_PR_STRIDE           4
+#define        REC_PR_X                0, 1, 2, 3
+#define        REC_PR_Y                4, 5, 6, 7
+#define        REC_PR_D                8, 9, 22, 23
+
+#define        REC_QR_DEFINE() REC_PQ_DEFINE()
+#define        REC_QR_STRIDE           4
+#define        REC_QR_X                0, 1, 2, 3
+#define        REC_QR_Y                4, 5, 6, 7
+#define        REC_QR_D                8, 9, 22, 23
+
+#define        REC_PQR_DEFINE() \
+       GEN_X_DEFINE_0_3()      \
+       GEN_X_DEFINE_4_5()      \
+       GEN_X_DEFINE_6_7()      \
+       GEN_X_DEFINE_8_9()      \
+       GEN_X_DEFINE_16()       \
+       GEN_X_DEFINE_17()       \
+       GEN_X_DEFINE_22_23()    \
+       GEN_X_DEFINE_24_27()    \
+       GEN_X_DEFINE_28_30()    \
+       GEN_X_DEFINE_31()       \
+       GEN_X_DEFINE_33_36()
+#define        REC_PQR_STRIDE          4
+#define        REC_PQR_X               0, 1, 2, 3
+#define        REC_PQR_Y               4, 5, 6, 7
+#define        REC_PQR_Z               8, 9, 22, 23
+#define        REC_PQR_D               24, 25, 26, 27
+#define        REC_PQR_XS              24, 25, 26, 27
+#define        REC_PQR_YS              28, 29, 30, 31
+
+
+#include <sys/vdev_raidz_impl.h>
+#include "vdev_raidz_math_impl.h"
+
+DEFINE_GEN_METHODS(aarch64_neonx2);
+/*
+ * If compiled with -O0, gcc doesn't do any stack frame coalescing
+ * and -Wframe-larger-than=1024 is triggered in debug mode.
+ */
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+DEFINE_REC_METHODS(aarch64_neonx2);
+#pragma GCC diagnostic pop
+
+static boolean_t
+raidz_will_aarch64_neonx2_work(void)
+{
+       return (B_TRUE); // __arch64__ requires NEON
+}
+
+const raidz_impl_ops_t vdev_raidz_aarch64_neonx2_impl = {
+       .init = NULL,
+       .fini = NULL,
+       .gen = RAIDZ_GEN_METHODS(aarch64_neonx2),
+       .rec = RAIDZ_REC_METHODS(aarch64_neonx2),
+       .is_supported = &raidz_will_aarch64_neonx2_work,
+       .name = "aarch64_neonx2"
+};
+
+#endif /* defined(__aarch64__) */
diff --git a/zfs/module/zfs/vdev_raidz_math_avx2.c b/zfs/module/zfs/vdev_raidz_math_avx2.c
new file mode 100644 (file)
index 0000000..90c94c7
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#include <sys/isa_defs.h>
+
+#if defined(__x86_64) && defined(HAVE_AVX2)
+
+#include <sys/types.h>
+#include <linux/simd_x86.h>
+
+#define        __asm __asm__ __volatile__
+
+#define        _REG_CNT(_0, _1, _2, _3, _4, _5, _6, _7, N, ...) N
+#define        REG_CNT(r...) _REG_CNT(r, 8, 7, 6, 5, 4, 3, 2, 1)
+
+#define        VR0_(REG, ...) "ymm"#REG
+#define        VR1_(_1, REG, ...) "ymm"#REG
+#define        VR2_(_1, _2, REG, ...) "ymm"#REG
+#define        VR3_(_1, _2, _3, REG, ...) "ymm"#REG
+#define        VR4_(_1, _2, _3, _4, REG, ...) "ymm"#REG
+#define        VR5_(_1, _2, _3, _4, _5, REG, ...) "ymm"#REG
+#define        VR6_(_1, _2, _3, _4, _5, _6, REG, ...) "ymm"#REG
+#define        VR7_(_1, _2, _3, _4, _5, _6, _7, REG, ...) "ymm"#REG
+
+#define        VR0(r...) VR0_(r)
+#define        VR1(r...) VR1_(r)
+#define        VR2(r...) VR2_(r, 1)
+#define        VR3(r...) VR3_(r, 1, 2)
+#define        VR4(r...) VR4_(r, 1, 2)
+#define        VR5(r...) VR5_(r, 1, 2, 3)
+#define        VR6(r...) VR6_(r, 1, 2, 3, 4)
+#define        VR7(r...) VR7_(r, 1, 2, 3, 4, 5)
+
+#define        R_01(REG1, REG2, ...) REG1, REG2
+#define        _R_23(_0, _1, REG2, REG3, ...) REG2, REG3
+#define        R_23(REG...) _R_23(REG, 1, 2, 3)
+
+#define        ASM_BUG()       ASSERT(0)
+
+extern const uint8_t gf_clmul_mod_lt[4*256][16];
+
+#define        ELEM_SIZE 32
+
+typedef struct v {
+       uint8_t b[ELEM_SIZE] __attribute__((aligned(ELEM_SIZE)));
+} v_t;
+
+#define        PREFETCHNTA(ptr, offset)                                        \
+{                                                                      \
+       __asm(                                                          \
+           "prefetchnta " #offset "(%[MEM])\n"                         \
+           : : [MEM] "r" (ptr));                                       \
+}
+
+#define        PREFETCH(ptr, offset)                                           \
+{                                                                      \
+       __asm(                                                          \
+           "prefetcht0 " #offset "(%[MEM])\n"                          \
+           : : [MEM] "r" (ptr));                                       \
+}
+
+#define        XOR_ACC(src, r...)                                              \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "vpxor 0x00(%[SRC]), %%" VR0(r)", %%" VR0(r) "\n"   \
+                   "vpxor 0x20(%[SRC]), %%" VR1(r)", %%" VR1(r) "\n"   \
+                   "vpxor 0x40(%[SRC]), %%" VR2(r)", %%" VR2(r) "\n"   \
+                   "vpxor 0x60(%[SRC]), %%" VR3(r)", %%" VR3(r) "\n"   \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "vpxor 0x00(%[SRC]), %%" VR0(r)", %%" VR0(r) "\n"   \
+                   "vpxor 0x20(%[SRC]), %%" VR1(r)", %%" VR1(r) "\n"   \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        XOR(r...)                                                       \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+                   "vpxor %" VR0(r) ", %" VR4(r)", %" VR4(r) "\n"      \
+                   "vpxor %" VR1(r) ", %" VR5(r)", %" VR5(r) "\n"      \
+                   "vpxor %" VR2(r) ", %" VR6(r)", %" VR6(r) "\n"      \
+                   "vpxor %" VR3(r) ", %" VR7(r)", %" VR7(r));         \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "vpxor %" VR0(r) ", %" VR2(r)", %" VR2(r) "\n"      \
+                   "vpxor %" VR1(r) ", %" VR3(r)", %" VR3(r));         \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        ZERO(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "vpxor %" VR0(r) ", %" VR0(r)", %" VR0(r) "\n"      \
+                   "vpxor %" VR1(r) ", %" VR1(r)", %" VR1(r) "\n"      \
+                   "vpxor %" VR2(r) ", %" VR2(r)", %" VR2(r) "\n"      \
+                   "vpxor %" VR3(r) ", %" VR3(r)", %" VR3(r));         \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "vpxor %" VR0(r) ", %" VR0(r)", %" VR0(r) "\n"      \
+                   "vpxor %" VR1(r) ", %" VR1(r)", %" VR1(r));         \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        COPY(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+                   "vmovdqa %" VR0(r) ", %" VR4(r) "\n"                \
+                   "vmovdqa %" VR1(r) ", %" VR5(r) "\n"                \
+                   "vmovdqa %" VR2(r) ", %" VR6(r) "\n"                \
+                   "vmovdqa %" VR3(r) ", %" VR7(r));                   \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "vmovdqa %" VR0(r) ", %" VR2(r) "\n"                \
+                   "vmovdqa %" VR1(r) ", %" VR3(r));                   \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        LOAD(src, r...)                                                 \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "vmovdqa 0x00(%[SRC]), %%" VR0(r) "\n"              \
+                   "vmovdqa 0x20(%[SRC]), %%" VR1(r) "\n"              \
+                   "vmovdqa 0x40(%[SRC]), %%" VR2(r) "\n"              \
+                   "vmovdqa 0x60(%[SRC]), %%" VR3(r) "\n"              \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "vmovdqa 0x00(%[SRC]), %%" VR0(r) "\n"              \
+                   "vmovdqa 0x20(%[SRC]), %%" VR1(r) "\n"              \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        STORE(dst, r...)                                                \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "vmovdqa %%" VR0(r) ", 0x00(%[DST])\n"              \
+                   "vmovdqa %%" VR1(r) ", 0x20(%[DST])\n"              \
+                   "vmovdqa %%" VR2(r) ", 0x40(%[DST])\n"              \
+                   "vmovdqa %%" VR3(r) ", 0x60(%[DST])\n"              \
+                   : : [DST] "r" (dst));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "vmovdqa %%" VR0(r) ", 0x00(%[DST])\n"              \
+                   "vmovdqa %%" VR1(r) ", 0x20(%[DST])\n"              \
+                   : : [DST] "r" (dst));                               \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        FLUSH()                                                         \
+{                                                                      \
+       __asm("vzeroupper");                                            \
+}
+
+#define        MUL2_SETUP()                                                    \
+{                                                                      \
+       __asm("vmovq %0,   %%xmm14" :: "r"(0x1d1d1d1d1d1d1d1d));        \
+       __asm("vpbroadcastq %xmm14, %ymm14");                           \
+       __asm("vpxor        %ymm15, %ymm15 ,%ymm15");                   \
+}
+
+#define        _MUL2(r...)                                                     \
+{                                                                      \
+       switch  (REG_CNT(r)) {                                          \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "vpcmpgtb %" VR0(r)", %ymm15,     %ymm12\n"         \
+                   "vpcmpgtb %" VR1(r)", %ymm15,     %ymm13\n"         \
+                   "vpaddb   %" VR0(r)", %" VR0(r)", %" VR0(r) "\n"    \
+                   "vpaddb   %" VR1(r)", %" VR1(r)", %" VR1(r) "\n"    \
+                   "vpand    %ymm14,     %ymm12,     %ymm12\n"         \
+                   "vpand    %ymm14,     %ymm13,     %ymm13\n"         \
+                   "vpxor    %ymm12,     %" VR0(r)", %" VR0(r) "\n"    \
+                   "vpxor    %ymm13,     %" VR1(r)", %" VR1(r));       \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL2(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+           _MUL2(R_01(r));                                             \
+           _MUL2(R_23(r));                                             \
+           break;                                                      \
+       case 2:                                                         \
+           _MUL2(r);                                                   \
+           break;                                                      \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL4(r...)                                                      \
+{                                                                      \
+       MUL2(r);                                                        \
+       MUL2(r);                                                        \
+}
+
+#define        _0f             "ymm15"
+#define        _as             "ymm14"
+#define        _bs             "ymm13"
+#define        _ltmod          "ymm12"
+#define        _ltmul          "ymm11"
+#define        _ta             "ymm10"
+#define        _tb             "ymm15"
+
+static const uint8_t __attribute__((aligned(32))) _mul_mask = 0x0F;
+
+#define        _MULx2(c, r...)                                                 \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "vpbroadcastb (%[mask]), %%" _0f "\n"               \
+                   /* upper bits */                                    \
+                   "vbroadcasti128 0x00(%[lt]), %%" _ltmod "\n"        \
+                   "vbroadcasti128 0x10(%[lt]), %%" _ltmul "\n"        \
+                                                                       \
+                   "vpsraw $0x4, %%" VR0(r) ", %%"_as "\n"             \
+                   "vpsraw $0x4, %%" VR1(r) ", %%"_bs "\n"             \
+                   "vpand %%" _0f ", %%" VR0(r) ", %%" VR0(r) "\n"     \
+                   "vpand %%" _0f ", %%" VR1(r) ", %%" VR1(r) "\n"     \
+                   "vpand %%" _0f ", %%" _as ", %%" _as "\n"           \
+                   "vpand %%" _0f ", %%" _bs ", %%" _bs "\n"           \
+                                                                       \
+                   "vpshufb %%" _as ", %%" _ltmod ", %%" _ta "\n"      \
+                   "vpshufb %%" _bs ", %%" _ltmod ", %%" _tb "\n"      \
+                   "vpshufb %%" _as ", %%" _ltmul ", %%" _as "\n"      \
+                   "vpshufb %%" _bs ", %%" _ltmul ", %%" _bs "\n"      \
+                   /* lower bits */                                    \
+                   "vbroadcasti128 0x20(%[lt]), %%" _ltmod "\n"        \
+                   "vbroadcasti128 0x30(%[lt]), %%" _ltmul "\n"        \
+                                                                       \
+                   "vpxor %%" _ta ", %%" _as ", %%" _as "\n"           \
+                   "vpxor %%" _tb ", %%" _bs ", %%" _bs "\n"           \
+                                                                       \
+                   "vpshufb %%" VR0(r) ", %%" _ltmod ", %%" _ta "\n"   \
+                   "vpshufb %%" VR1(r) ", %%" _ltmod ", %%" _tb "\n"   \
+                   "vpshufb %%" VR0(r) ", %%" _ltmul ", %%" VR0(r) "\n"\
+                   "vpshufb %%" VR1(r) ", %%" _ltmul ", %%" VR1(r) "\n"\
+                                                                       \
+                   "vpxor %%" _ta ", %%" VR0(r) ", %%" VR0(r) "\n"     \
+                   "vpxor %%" _as ", %%" VR0(r) ", %%" VR0(r) "\n"     \
+                   "vpxor %%" _tb ", %%" VR1(r) ", %%" VR1(r) "\n"     \
+                   "vpxor %%" _bs ", %%" VR1(r) ", %%" VR1(r) "\n"     \
+                   : : [mask] "r" (&_mul_mask),                        \
+                   [lt] "r" (gf_clmul_mod_lt[4*(c)]));                 \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL(c, r...)                                                    \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               _MULx2(c, R_01(r));                                     \
+               _MULx2(c, R_23(r));                                     \
+               break;                                                  \
+       case 2:                                                         \
+               _MULx2(c, R_01(r));                                     \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        raidz_math_begin()      kfpu_begin()
+#define        raidz_math_end()                                                \
+{                                                                      \
+       FLUSH();                                                        \
+       kfpu_end();                                                     \
+}
+
+#define        GEN_P_DEFINE()          {}
+#define        GEN_P_STRIDE            4
+#define        GEN_P_P                 0, 1, 2, 3
+
+#define        GEN_PQ_DEFINE()         {}
+#define        GEN_PQ_STRIDE           4
+#define        GEN_PQ_D                0, 1, 2, 3
+#define        GEN_PQ_P                4, 5, 6, 7
+#define        GEN_PQ_Q                8, 9, 10, 11
+
+#define        GEN_PQR_DEFINE()        {}
+#define        GEN_PQR_STRIDE          2
+#define        GEN_PQR_D               0, 1
+#define        GEN_PQR_P               2, 3
+#define        GEN_PQR_Q               4, 5
+#define        GEN_PQR_R               6, 7
+
+#define        REC_P_DEFINE()          {}
+#define        REC_P_STRIDE            4
+#define        REC_P_X                 0, 1, 2, 3
+
+#define        REC_Q_DEFINE()          {}
+#define        REC_Q_STRIDE            4
+#define        REC_Q_X                 0, 1, 2, 3
+
+#define        REC_R_DEFINE()          {}
+#define        REC_R_STRIDE            4
+#define        REC_R_X                 0, 1, 2, 3
+
+#define        REC_PQ_DEFINE()         {}
+#define        REC_PQ_STRIDE           2
+#define        REC_PQ_X                0, 1
+#define        REC_PQ_Y                2, 3
+#define        REC_PQ_D                4, 5
+
+#define        REC_PR_DEFINE()         {}
+#define        REC_PR_STRIDE           2
+#define        REC_PR_X                0, 1
+#define        REC_PR_Y                2, 3
+#define        REC_PR_D                4, 5
+
+#define        REC_QR_DEFINE()         {}
+#define        REC_QR_STRIDE           2
+#define        REC_QR_X                0, 1
+#define        REC_QR_Y                2, 3
+#define        REC_QR_D                4, 5
+
+#define        REC_PQR_DEFINE()        {}
+#define        REC_PQR_STRIDE          2
+#define        REC_PQR_X               0, 1
+#define        REC_PQR_Y               2, 3
+#define        REC_PQR_Z               4, 5
+#define        REC_PQR_D               6, 7
+#define        REC_PQR_XS              6, 7
+#define        REC_PQR_YS              8, 9
+
+
+#include <sys/vdev_raidz_impl.h>
+#include "vdev_raidz_math_impl.h"
+
+DEFINE_GEN_METHODS(avx2);
+DEFINE_REC_METHODS(avx2);
+
+static boolean_t
+raidz_will_avx2_work(void)
+{
+       return (zfs_avx_available() && zfs_avx2_available());
+}
+
+const raidz_impl_ops_t vdev_raidz_avx2_impl = {
+       .init = NULL,
+       .fini = NULL,
+       .gen = RAIDZ_GEN_METHODS(avx2),
+       .rec = RAIDZ_REC_METHODS(avx2),
+       .is_supported = &raidz_will_avx2_work,
+       .name = "avx2"
+};
+
+#endif /* defined(__x86_64) && defined(HAVE_AVX2) */
diff --git a/zfs/module/zfs/vdev_raidz_math_impl.h b/zfs/module/zfs/vdev_raidz_math_impl.h
new file mode 100644 (file)
index 0000000..70257ee
--- /dev/null
@@ -0,0 +1,1199 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#ifndef _VDEV_RAIDZ_MATH_IMPL_H
+#define        _VDEV_RAIDZ_MATH_IMPL_H
+
+#include <sys/types.h>
+
+#define        raidz_inline inline __attribute__((always_inline))
+#ifndef noinline
+#define        noinline __attribute__((noinline))
+#endif
+
+/* Calculate data offset in raidz column, offset is in bytes */
+#define        COL_OFF(col, off)       ((v_t *)(((char *)(col)->rc_data) + (off)))
+
+/*
+ * PARITY CALCULATION
+ * An optimized function is called for a full length of data columns
+ * If RAIDZ map contains remainder columns (shorter columns) the same function
+ * is called for reminder of full columns.
+ *
+ * GEN_[P|PQ|PQR]_BLOCK() functions are designed to be efficiently in-lined by
+ * the compiler. This removes a lot of conditionals from the inside loop which
+ * makes the code faster, especially for vectorized code.
+ * They are also highly parametrized, allowing for each implementation to define
+ * most optimal stride, and register allocation.
+ */
+
+static raidz_inline void
+GEN_P_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int ncols)
+{
+       int c;
+       size_t ioff;
+       raidz_col_t * const pcol = raidz_col_p(rm, CODE_P);
+       raidz_col_t *col;
+
+       GEN_P_DEFINE();
+
+       for (ioff = off; ioff < end; ioff += (GEN_P_STRIDE * sizeof (v_t))) {
+               LOAD(COL_OFF(&(rm->rm_col[1]), ioff), GEN_P_P);
+
+               for (c = 2; c < ncols; c++) {
+                       col = &rm->rm_col[c];
+                       XOR_ACC(COL_OFF(col, ioff), GEN_P_P);
+               }
+
+               STORE(COL_OFF(pcol, ioff), GEN_P_P);
+       }
+}
+
+/*
+ * Generate P parity (RAIDZ1)
+ *
+ * @rm RAIDZ map
+ */
+static raidz_inline void
+raidz_generate_p_impl(raidz_map_t * const rm)
+{
+       const int ncols = raidz_ncols(rm);
+       const size_t psize = raidz_big_size(rm);
+       const size_t short_size = raidz_short_size(rm);
+
+       raidz_math_begin();
+
+       /* short_size */
+       GEN_P_BLOCK(rm, 0, short_size, ncols);
+
+       /* fullcols */
+       GEN_P_BLOCK(rm, short_size, psize, raidz_nbigcols(rm));
+
+       raidz_math_end();
+}
+
+static raidz_inline void
+GEN_PQ_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int ncols, const int nbigcols)
+{
+       int c;
+       size_t ioff;
+       raidz_col_t * const pcol = raidz_col_p(rm, CODE_P);
+       raidz_col_t * const qcol = raidz_col_p(rm, CODE_Q);
+       raidz_col_t *col;
+
+       GEN_PQ_DEFINE();
+
+       MUL2_SETUP();
+
+       for (ioff = off; ioff < end; ioff += (GEN_PQ_STRIDE * sizeof (v_t))) {
+               LOAD(COL_OFF(&rm->rm_col[2], ioff), GEN_PQ_P);
+               COPY(GEN_PQ_P, GEN_PQ_Q);
+
+               for (c = 3; c < nbigcols; c++) {
+                       col = &rm->rm_col[c];
+                       LOAD(COL_OFF(col, ioff), GEN_PQ_D);
+                       MUL2(GEN_PQ_Q);
+                       XOR(GEN_PQ_D, GEN_PQ_P);
+                       XOR(GEN_PQ_D, GEN_PQ_Q);
+               }
+
+               STORE(COL_OFF(pcol, ioff), GEN_PQ_P);
+
+               for (; c < ncols; c++)
+                       MUL2(GEN_PQ_Q);
+
+               STORE(COL_OFF(qcol, ioff), GEN_PQ_Q);
+       }
+}
+
+/*
+ * Generate PQ parity (RAIDZ2)
+ *
+ * @rm RAIDZ map
+ */
+static raidz_inline void
+raidz_generate_pq_impl(raidz_map_t * const rm)
+{
+       const int ncols = raidz_ncols(rm);
+       const size_t psize = raidz_big_size(rm);
+       const size_t short_size = raidz_short_size(rm);
+
+       raidz_math_begin();
+
+       /* short_size */
+       GEN_PQ_BLOCK(rm, 0, short_size, ncols, ncols);
+
+       /* fullcols */
+       GEN_PQ_BLOCK(rm, short_size, psize, ncols, raidz_nbigcols(rm));
+
+       raidz_math_end();
+}
+
+
+static raidz_inline void
+GEN_PQR_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int ncols, const int nbigcols)
+{
+       int c;
+       size_t ioff;
+       raidz_col_t *col;
+       raidz_col_t * const pcol = raidz_col_p(rm, CODE_P);
+       raidz_col_t * const qcol = raidz_col_p(rm, CODE_Q);
+       raidz_col_t * const rcol = raidz_col_p(rm, CODE_R);
+
+       GEN_PQR_DEFINE();
+
+       MUL2_SETUP();
+
+       for (ioff = off; ioff < end; ioff += (GEN_PQR_STRIDE * sizeof (v_t))) {
+               LOAD(COL_OFF(&rm->rm_col[3], ioff), GEN_PQR_P);
+               COPY(GEN_PQR_P, GEN_PQR_Q);
+               COPY(GEN_PQR_P, GEN_PQR_R);
+
+               for (c = 4; c < nbigcols; c++) {
+                       col = &rm->rm_col[c];
+                       LOAD(COL_OFF(col, ioff), GEN_PQR_D);
+                       MUL2(GEN_PQR_Q);
+                       MUL4(GEN_PQR_R);
+                       XOR(GEN_PQR_D, GEN_PQR_P);
+                       XOR(GEN_PQR_D, GEN_PQR_Q);
+                       XOR(GEN_PQR_D, GEN_PQR_R);
+               }
+
+               STORE(COL_OFF(pcol, ioff), GEN_PQR_P);
+
+               for (; c < ncols; c++) {
+                       MUL2(GEN_PQR_Q);
+                       MUL4(GEN_PQR_R);
+               }
+
+               STORE(COL_OFF(qcol, ioff), GEN_PQR_Q);
+               STORE(COL_OFF(rcol, ioff), GEN_PQR_R);
+       }
+}
+
+
+/*
+ * Generate PQR parity (RAIDZ3)
+ *
+ * @rm RAIDZ map
+ */
+static raidz_inline void
+raidz_generate_pqr_impl(raidz_map_t * const rm)
+{
+       const int ncols = raidz_ncols(rm);
+       const size_t psize = raidz_big_size(rm);
+       const size_t short_size = raidz_short_size(rm);
+
+       raidz_math_begin();
+
+       /* short_size */
+       GEN_PQR_BLOCK(rm, 0, short_size, ncols, ncols);
+
+       /* fullcols */
+       GEN_PQR_BLOCK(rm, short_size, psize, ncols, raidz_nbigcols(rm));
+
+       raidz_math_end();
+}
+
+/*
+ * DATA RECONSTRUCTION
+ *
+ * Data reconstruction process consists of two phases:
+ *     - Syndrome calculation
+ *     - Data reconstruction
+ *
+ * Syndrome is calculated by generating parity using available data columns
+ * and zeros in places of erasure. Existing parity is added to corresponding
+ * syndrome value to obtain the [P|Q|R]syn values from equation:
+ *     P = Psyn + Dx + Dy + Dz
+ *     Q = Qsyn + 2^x * Dx + 2^y * Dy + 2^z * Dz
+ *     R = Rsyn + 4^x * Dx + 4^y * Dy + 4^z * Dz
+ *
+ * For data reconstruction phase, the corresponding equations are solved
+ * for missing data (Dx, Dy, Dz). This generally involves multiplying known
+ * symbols by an coefficient and adding them together. The multiplication
+ * constant coefficients are calculated ahead of the operation in
+ * raidz_rec_[q|r|pq|pq|qr|pqr]_coeff() functions.
+ *
+ * IMPLEMENTATION NOTE: RAID-Z block can have complex geometry, with "big"
+ * and "short" columns.
+ * For this reason, reconstruction is performed in minimum of
+ * two steps. First, from offset 0 to short_size, then from short_size to
+ * short_size. Calculation functions REC_[*]_BLOCK() are implemented to work
+ * over both ranges. The split also enables removal of conditional expressions
+ * from loop bodies, improving throughput of SIMD implementations.
+ * For the best performance, all functions marked with raidz_inline attribute
+ * must be inlined by compiler.
+ *
+ *    parity          data
+ *    columns         columns
+ * <----------> <------------------>
+ *                   x       y  <----+ missing columns (x, y)
+ *                   |       |
+ * +---+---+---+---+-v-+---+-v-+---+   ^ 0
+ * |   |   |   |   |   |   |   |   |   |
+ * |   |   |   |   |   |   |   |   |   |
+ * | P | Q | R | D | D | D | D | D |   |
+ * |   |   |   | 0 | 1 | 2 | 3 | 4 |   |
+ * |   |   |   |   |   |   |   |   |   v
+ * |   |   |   |   |   +---+---+---+   ^ short_size
+ * |   |   |   |   |   |               |
+ * +---+---+---+---+---+               v big_size
+ * <------------------> <---------->
+ *      big columns     short columns
+ *
+ */
+
+/*
+ * Functions calculate multiplication constants for data reconstruction.
+ * Coefficients depend on RAIDZ geometry, indexes of failed child vdevs, and
+ * used parity columns for reconstruction.
+ * @rm                 RAIDZ map
+ * @tgtidx             array of missing data indexes
+ * @coeff              output array of coefficients. Array must be user
+ *                     provided and must hold minimum MUL_CNT values
+ */
+static noinline void
+raidz_rec_q_coeff(const raidz_map_t *rm, const int *tgtidx, unsigned *coeff)
+{
+       const unsigned ncols = raidz_ncols(rm);
+       const unsigned x = tgtidx[TARGET_X];
+
+       coeff[MUL_Q_X] = gf_exp2(255 - (ncols - x - 1));
+}
+
+static noinline void
+raidz_rec_r_coeff(const raidz_map_t *rm, const int *tgtidx, unsigned *coeff)
+{
+       const unsigned ncols = raidz_ncols(rm);
+       const unsigned x = tgtidx[TARGET_X];
+
+       coeff[MUL_R_X] = gf_exp4(255 - (ncols - x - 1));
+}
+
+static noinline void
+raidz_rec_pq_coeff(const raidz_map_t *rm, const int *tgtidx, unsigned *coeff)
+{
+       const unsigned ncols = raidz_ncols(rm);
+       const unsigned x = tgtidx[TARGET_X];
+       const unsigned y = tgtidx[TARGET_Y];
+       gf_t a, b, e;
+
+       a = gf_exp2(x + 255 - y);
+       b = gf_exp2(255 - (ncols - x - 1));
+       e = a ^ 0x01;
+
+       coeff[MUL_PQ_X] = gf_div(a, e);
+       coeff[MUL_PQ_Y] = gf_div(b, e);
+}
+
+static noinline void
+raidz_rec_pr_coeff(const raidz_map_t *rm, const int *tgtidx, unsigned *coeff)
+{
+       const unsigned ncols = raidz_ncols(rm);
+       const unsigned x = tgtidx[TARGET_X];
+       const unsigned y = tgtidx[TARGET_Y];
+
+       gf_t a, b, e;
+
+       a = gf_exp4(x + 255 - y);
+       b = gf_exp4(255 - (ncols - x - 1));
+       e = a ^ 0x01;
+
+       coeff[MUL_PR_X] = gf_div(a, e);
+       coeff[MUL_PR_Y] = gf_div(b, e);
+}
+
+static noinline void
+raidz_rec_qr_coeff(const raidz_map_t *rm, const int *tgtidx, unsigned *coeff)
+{
+       const unsigned ncols = raidz_ncols(rm);
+       const unsigned x = tgtidx[TARGET_X];
+       const unsigned y = tgtidx[TARGET_Y];
+
+       gf_t nx, ny, nxxy, nxyy, d;
+
+       nx = gf_exp2(ncols - x - 1);
+       ny = gf_exp2(ncols - y - 1);
+       nxxy = gf_mul(gf_mul(nx, nx), ny);
+       nxyy = gf_mul(gf_mul(nx, ny), ny);
+       d = nxxy ^ nxyy;
+
+       coeff[MUL_QR_XQ] = ny;
+       coeff[MUL_QR_X] = gf_div(ny, d);
+       coeff[MUL_QR_YQ] = nx;
+       coeff[MUL_QR_Y] = gf_div(nx, d);
+}
+
+static noinline void
+raidz_rec_pqr_coeff(const raidz_map_t *rm, const int *tgtidx, unsigned *coeff)
+{
+       const unsigned ncols = raidz_ncols(rm);
+       const unsigned x = tgtidx[TARGET_X];
+       const unsigned y = tgtidx[TARGET_Y];
+       const unsigned z = tgtidx[TARGET_Z];
+
+       gf_t nx, ny, nz, nxx, nyy, nzz, nyyz, nyzz, xd, yd;
+
+       nx = gf_exp2(ncols - x - 1);
+       ny = gf_exp2(ncols - y - 1);
+       nz = gf_exp2(ncols - z - 1);
+
+       nxx = gf_exp4(ncols - x - 1);
+       nyy = gf_exp4(ncols - y - 1);
+       nzz = gf_exp4(ncols - z - 1);
+
+       nyyz = gf_mul(gf_mul(ny, nz), ny);
+       nyzz = gf_mul(nzz, ny);
+
+       xd = gf_mul(nxx, ny) ^ gf_mul(nx, nyy) ^ nyyz ^
+           gf_mul(nxx, nz) ^ gf_mul(nzz, nx) ^  nyzz;
+
+       yd = gf_inv(ny ^ nz);
+
+       coeff[MUL_PQR_XP] = gf_div(nyyz ^ nyzz, xd);
+       coeff[MUL_PQR_XQ] = gf_div(nyy ^ nzz, xd);
+       coeff[MUL_PQR_XR] = gf_div(ny ^ nz, xd);
+       coeff[MUL_PQR_YU] = nx;
+       coeff[MUL_PQR_YP] = gf_mul(nz, yd);
+       coeff[MUL_PQR_YQ] = yd;
+}
+
+
+/*
+ * Reconstruction using P parity
+ * @rm         RAIDZ map
+ * @off                starting offset
+ * @end                ending offset
+ * @x          missing data column
+ * @ncols      number of column
+ */
+static raidz_inline void
+REC_P_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int x, const int ncols)
+{
+       int c;
+       size_t ioff;
+       const size_t firstdc = raidz_parity(rm);
+       raidz_col_t * const pcol = raidz_col_p(rm, CODE_P);
+       raidz_col_t * const xcol = raidz_col_p(rm, x);
+       raidz_col_t *col;
+
+       REC_P_DEFINE();
+
+       for (ioff = off; ioff < end; ioff += (REC_P_STRIDE * sizeof (v_t))) {
+               LOAD(COL_OFF(pcol, ioff), REC_P_X);
+
+               for (c = firstdc; c < x; c++) {
+                       col = &rm->rm_col[c];
+                       XOR_ACC(COL_OFF(col, ioff), REC_P_X);
+               }
+
+               for (c++; c < ncols; c++) {
+                       col = &rm->rm_col[c];
+                       XOR_ACC(COL_OFF(col, ioff), REC_P_X);
+               }
+
+               STORE(COL_OFF(xcol, ioff), REC_P_X);
+       }
+}
+
+/*
+ * Reconstruct single data column using P parity
+ * @rec_method REC_P_BLOCK()
+ *
+ * @rm         RAIDZ map
+ * @tgtidx     array of missing data indexes
+ */
+static raidz_inline int
+raidz_reconstruct_p_impl(raidz_map_t *rm, const int *tgtidx)
+{
+       const int x = tgtidx[TARGET_X];
+       const int ncols = raidz_ncols(rm);
+       const int nbigcols = raidz_nbigcols(rm);
+       const size_t xsize = raidz_col_size(rm, x);
+       const size_t short_size = raidz_short_size(rm);
+
+       raidz_math_begin();
+
+       /* 0 - short_size */
+       REC_P_BLOCK(rm, 0, short_size, x, ncols);
+
+       /* short_size - xsize */
+       REC_P_BLOCK(rm, short_size, xsize, x, nbigcols);
+
+       raidz_math_end();
+
+       return (1 << CODE_P);
+}
+
+/*
+ * Reconstruct using Q parity
+ */
+
+#define        REC_Q_SYN_UPDATE()      MUL2(REC_Q_X)
+
+#define        REC_Q_INNER_LOOP(c)                     \
+{                                              \
+       col = &rm->rm_col[c];                   \
+       REC_Q_SYN_UPDATE();                     \
+       XOR_ACC(COL_OFF(col, ioff), REC_Q_X);   \
+}
+
+/*
+ * Reconstruction using Q parity
+ * @rm         RAIDZ map
+ * @off                starting offset
+ * @end                ending offset
+ * @x          missing data column
+ * @coeff      multiplication coefficients
+ * @ncols      number of column
+ * @nbigcols   number of big columns
+ */
+static raidz_inline void
+REC_Q_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int x, const unsigned *coeff, const int ncols, const int nbigcols)
+{
+       int c;
+       size_t ioff = 0;
+       const size_t firstdc = raidz_parity(rm);
+       raidz_col_t * const qcol = raidz_col_p(rm, CODE_Q);
+       raidz_col_t * const xcol = raidz_col_p(rm, x);
+       raidz_col_t *col;
+
+       REC_Q_DEFINE();
+
+       for (ioff = off; ioff < end; ioff += (REC_Q_STRIDE * sizeof (v_t))) {
+               MUL2_SETUP();
+
+               ZERO(REC_Q_X);
+
+               if (ncols == nbigcols) {
+                       for (c = firstdc; c < x; c++)
+                               REC_Q_INNER_LOOP(c);
+
+                       REC_Q_SYN_UPDATE();
+                       for (c++; c < nbigcols; c++)
+                               REC_Q_INNER_LOOP(c);
+               } else {
+                       for (c = firstdc; c < nbigcols; c++) {
+                               REC_Q_SYN_UPDATE();
+                               if (x != c) {
+                                       col = &rm->rm_col[c];
+                                       XOR_ACC(COL_OFF(col, ioff), REC_Q_X);
+                               }
+                       }
+                       for (; c < ncols; c++)
+                               REC_Q_SYN_UPDATE();
+               }
+
+               XOR_ACC(COL_OFF(qcol, ioff), REC_Q_X);
+               MUL(coeff[MUL_Q_X], REC_Q_X);
+               STORE(COL_OFF(xcol, ioff), REC_Q_X);
+       }
+}
+
+/*
+ * Reconstruct single data column using Q parity
+ * @rec_method REC_Q_BLOCK()
+ *
+ * @rm         RAIDZ map
+ * @tgtidx     array of missing data indexes
+ */
+static raidz_inline int
+raidz_reconstruct_q_impl(raidz_map_t *rm, const int *tgtidx)
+{
+       const int x = tgtidx[TARGET_X];
+       const int ncols = raidz_ncols(rm);
+       const int nbigcols = raidz_nbigcols(rm);
+       const size_t xsize = raidz_col_size(rm, x);
+       const size_t short_size = raidz_short_size(rm);
+       unsigned coeff[MUL_CNT];
+
+       raidz_rec_q_coeff(rm, tgtidx, coeff);
+
+       raidz_math_begin();
+
+       /* 0 - short_size */
+       REC_Q_BLOCK(rm, 0, short_size, x, coeff, ncols, ncols);
+
+       /* short_size - xsize */
+       REC_Q_BLOCK(rm, short_size, xsize, x, coeff, ncols, nbigcols);
+
+       raidz_math_end();
+
+       return (1 << CODE_Q);
+}
+
+/*
+ * Reconstruct using R parity
+ */
+
+#define        REC_R_SYN_UPDATE()      MUL4(REC_R_X)
+#define        REC_R_INNER_LOOP(c)                     \
+{                                              \
+       col = &rm->rm_col[c];                   \
+       REC_R_SYN_UPDATE();                     \
+       XOR_ACC(COL_OFF(col, ioff), REC_R_X);   \
+}
+
+/*
+ * Reconstruction using R parity
+ * @rm         RAIDZ map
+ * @off                starting offset
+ * @end                ending offset
+ * @x          missing data column
+ * @coeff      multiplication coefficients
+ * @ncols      number of column
+ * @nbigcols   number of big columns
+ */
+static raidz_inline void
+REC_R_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int x, const unsigned *coeff, const int ncols, const int nbigcols)
+{
+       int c;
+       size_t ioff = 0;
+       const size_t firstdc = raidz_parity(rm);
+       raidz_col_t * const rcol = raidz_col_p(rm, CODE_R);
+       raidz_col_t * const xcol = raidz_col_p(rm, x);
+       raidz_col_t *col;
+
+       REC_R_DEFINE();
+
+       for (ioff = off; ioff < end; ioff += (REC_R_STRIDE * sizeof (v_t))) {
+               MUL2_SETUP();
+
+               ZERO(REC_R_X);
+
+               if (ncols == nbigcols) {
+                       for (c = firstdc; c < x; c++)
+                               REC_R_INNER_LOOP(c);
+
+                       REC_R_SYN_UPDATE();
+                       for (c++; c < nbigcols; c++)
+                               REC_R_INNER_LOOP(c);
+               } else {
+                       for (c = firstdc; c < nbigcols; c++) {
+                               REC_R_SYN_UPDATE();
+                               if (c != x) {
+                                       col = &rm->rm_col[c];
+                                       XOR_ACC(COL_OFF(col, ioff), REC_R_X);
+                               }
+                       }
+                       for (; c < ncols; c++)
+                               REC_R_SYN_UPDATE();
+               }
+
+               XOR_ACC(COL_OFF(rcol, ioff), REC_R_X);
+               MUL(coeff[MUL_R_X], REC_R_X);
+               STORE(COL_OFF(xcol, ioff), REC_R_X);
+       }
+}
+
+/*
+ * Reconstruct single data column using R parity
+ * @rec_method REC_R_BLOCK()
+ *
+ * @rm         RAIDZ map
+ * @tgtidx     array of missing data indexes
+ */
+static raidz_inline int
+raidz_reconstruct_r_impl(raidz_map_t *rm, const int *tgtidx)
+{
+       const int x = tgtidx[TARGET_X];
+       const int ncols = raidz_ncols(rm);
+       const int nbigcols = raidz_nbigcols(rm);
+       const size_t xsize = raidz_col_size(rm, x);
+       const size_t short_size = raidz_short_size(rm);
+       unsigned coeff[MUL_CNT];
+
+       raidz_rec_r_coeff(rm, tgtidx, coeff);
+
+       raidz_math_begin();
+
+       /* 0 - short_size */
+       REC_R_BLOCK(rm, 0, short_size, x, coeff, ncols, ncols);
+
+       /* short_size - xsize */
+       REC_R_BLOCK(rm, short_size, xsize, x, coeff, ncols, nbigcols);
+
+       raidz_math_end();
+
+       return (1 << CODE_R);
+}
+
+/*
+ * Reconstruct using PQ parity
+ */
+
+#define        REC_PQ_SYN_UPDATE()     MUL2(REC_PQ_Y)
+#define        REC_PQ_INNER_LOOP(c)                    \
+{                                              \
+       col = &rm->rm_col[c];                   \
+       LOAD(COL_OFF(col, ioff), REC_PQ_D);     \
+       REC_PQ_SYN_UPDATE();                    \
+       XOR(REC_PQ_D, REC_PQ_X);                \
+       XOR(REC_PQ_D, REC_PQ_Y);                \
+}
+
+/*
+ * Reconstruction using PQ parity
+ * @rm         RAIDZ map
+ * @off                starting offset
+ * @end                ending offset
+ * @x          missing data column
+ * @y          missing data column
+ * @coeff      multiplication coefficients
+ * @ncols      number of column
+ * @nbigcols   number of big columns
+ * @calcy      calculate second data column
+ */
+static raidz_inline void
+REC_PQ_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int x, const int y, const unsigned *coeff, const int ncols,
+    const int nbigcols, const boolean_t calcy)
+{
+       int c;
+       size_t ioff = 0;
+       const size_t firstdc = raidz_parity(rm);
+       raidz_col_t * const pcol = raidz_col_p(rm, CODE_P);
+       raidz_col_t * const qcol = raidz_col_p(rm, CODE_Q);
+       raidz_col_t * const xcol = raidz_col_p(rm, x);
+       raidz_col_t * const ycol = raidz_col_p(rm, y);
+       raidz_col_t *col;
+
+       REC_PQ_DEFINE();
+
+       for (ioff = off; ioff < end; ioff += (REC_PQ_STRIDE * sizeof (v_t))) {
+               LOAD(COL_OFF(pcol, ioff), REC_PQ_X);
+               ZERO(REC_PQ_Y);
+               MUL2_SETUP();
+
+               if (ncols == nbigcols) {
+                       for (c = firstdc; c < x; c++)
+                               REC_PQ_INNER_LOOP(c);
+
+                       REC_PQ_SYN_UPDATE();
+                       for (c++; c < y; c++)
+                               REC_PQ_INNER_LOOP(c);
+
+                       REC_PQ_SYN_UPDATE();
+                       for (c++; c < nbigcols; c++)
+                               REC_PQ_INNER_LOOP(c);
+               } else {
+                       for (c = firstdc; c < nbigcols; c++) {
+                               REC_PQ_SYN_UPDATE();
+                               if (c != x && c != y) {
+                                       col = &rm->rm_col[c];
+                                       LOAD(COL_OFF(col, ioff), REC_PQ_D);
+                                       XOR(REC_PQ_D, REC_PQ_X);
+                                       XOR(REC_PQ_D, REC_PQ_Y);
+                               }
+                       }
+                       for (; c < ncols; c++)
+                               REC_PQ_SYN_UPDATE();
+               }
+
+               XOR_ACC(COL_OFF(qcol, ioff), REC_PQ_Y);
+
+               /* Save Pxy */
+               COPY(REC_PQ_X, REC_PQ_D);
+
+               /* Calc X */
+               MUL(coeff[MUL_PQ_X], REC_PQ_X);
+               MUL(coeff[MUL_PQ_Y], REC_PQ_Y);
+               XOR(REC_PQ_Y,  REC_PQ_X);
+               STORE(COL_OFF(xcol, ioff), REC_PQ_X);
+
+               if (calcy) {
+                       /* Calc Y */
+                       XOR(REC_PQ_D,  REC_PQ_X);
+                       STORE(COL_OFF(ycol, ioff), REC_PQ_X);
+               }
+       }
+}
+
+/*
+ * Reconstruct two data columns using PQ parity
+ * @rec_method REC_PQ_BLOCK()
+ *
+ * @rm         RAIDZ map
+ * @tgtidx     array of missing data indexes
+ */
+static raidz_inline int
+raidz_reconstruct_pq_impl(raidz_map_t *rm, const int *tgtidx)
+{
+       const int x = tgtidx[TARGET_X];
+       const int y = tgtidx[TARGET_Y];
+       const int ncols = raidz_ncols(rm);
+       const int nbigcols = raidz_nbigcols(rm);
+       const size_t xsize = raidz_col_size(rm, x);
+       const size_t ysize = raidz_col_size(rm, y);
+       const size_t short_size = raidz_short_size(rm);
+       unsigned coeff[MUL_CNT];
+
+       raidz_rec_pq_coeff(rm, tgtidx, coeff);
+
+       raidz_math_begin();
+
+       /* 0 - short_size */
+       REC_PQ_BLOCK(rm, 0, short_size, x, y, coeff, ncols, ncols, B_TRUE);
+
+       /* short_size - xsize */
+       REC_PQ_BLOCK(rm, short_size, xsize, x, y, coeff, ncols, nbigcols,
+           xsize == ysize);
+
+       raidz_math_end();
+
+       return ((1 << CODE_P) | (1 << CODE_Q));
+}
+
+/*
+ * Reconstruct using PR parity
+ */
+
+#define        REC_PR_SYN_UPDATE()     MUL4(REC_PR_Y)
+#define        REC_PR_INNER_LOOP(c)                    \
+{                                              \
+       col = &rm->rm_col[c];                   \
+       LOAD(COL_OFF(col, ioff), REC_PR_D);     \
+       REC_PR_SYN_UPDATE();                    \
+       XOR(REC_PR_D, REC_PR_X);                \
+       XOR(REC_PR_D, REC_PR_Y);                \
+}
+
+/*
+ * Reconstruction using PR parity
+ * @rm         RAIDZ map
+ * @off                starting offset
+ * @end                ending offset
+ * @x          missing data column
+ * @y          missing data column
+ * @coeff      multiplication coefficients
+ * @ncols      number of column
+ * @nbigcols   number of big columns
+ * @calcy      calculate second data column
+ */
+static raidz_inline void
+REC_PR_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int x, const int y, const unsigned *coeff, const int ncols,
+    const int nbigcols, const boolean_t calcy)
+{
+       int c;
+       size_t ioff;
+       const size_t firstdc = raidz_parity(rm);
+       raidz_col_t * const pcol = raidz_col_p(rm, CODE_P);
+       raidz_col_t * const rcol = raidz_col_p(rm, CODE_R);
+       raidz_col_t * const xcol = raidz_col_p(rm, x);
+       raidz_col_t * const ycol = raidz_col_p(rm, y);
+       raidz_col_t *col;
+
+       REC_PR_DEFINE();
+
+       for (ioff = off; ioff < end; ioff += (REC_PR_STRIDE * sizeof (v_t))) {
+               LOAD(COL_OFF(pcol, ioff), REC_PR_X);
+               ZERO(REC_PR_Y);
+               MUL2_SETUP();
+
+               if (ncols == nbigcols) {
+                       for (c = firstdc; c < x; c++)
+                               REC_PR_INNER_LOOP(c);
+
+                       REC_PR_SYN_UPDATE();
+                       for (c++; c < y; c++)
+                               REC_PR_INNER_LOOP(c);
+
+                       REC_PR_SYN_UPDATE();
+                       for (c++; c < nbigcols; c++)
+                               REC_PR_INNER_LOOP(c);
+               } else {
+                       for (c = firstdc; c < nbigcols; c++) {
+                               REC_PR_SYN_UPDATE();
+                               if (c != x && c != y) {
+                                       col = &rm->rm_col[c];
+                                       LOAD(COL_OFF(col, ioff), REC_PR_D);
+                                       XOR(REC_PR_D, REC_PR_X);
+                                       XOR(REC_PR_D, REC_PR_Y);
+                               }
+                       }
+                       for (; c < ncols; c++)
+                               REC_PR_SYN_UPDATE();
+               }
+
+               XOR_ACC(COL_OFF(rcol, ioff), REC_PR_Y);
+
+               /* Save Pxy */
+               COPY(REC_PR_X,  REC_PR_D);
+
+               /* Calc X */
+               MUL(coeff[MUL_PR_X], REC_PR_X);
+               MUL(coeff[MUL_PR_Y], REC_PR_Y);
+               XOR(REC_PR_Y,  REC_PR_X);
+               STORE(COL_OFF(xcol, ioff), REC_PR_X);
+
+               if (calcy) {
+                       /* Calc Y */
+                       XOR(REC_PR_D,  REC_PR_X);
+                       STORE(COL_OFF(ycol, ioff), REC_PR_X);
+               }
+       }
+}
+
+
+/*
+ * Reconstruct two data columns using PR parity
+ * @rec_method REC_PR_BLOCK()
+ *
+ * @rm         RAIDZ map
+ * @tgtidx     array of missing data indexes
+ */
+static raidz_inline int
+raidz_reconstruct_pr_impl(raidz_map_t *rm, const int *tgtidx)
+{
+       const int x = tgtidx[TARGET_X];
+       const int y = tgtidx[TARGET_Y];
+       const int ncols = raidz_ncols(rm);
+       const int nbigcols = raidz_nbigcols(rm);
+       const size_t xsize = raidz_col_size(rm, x);
+       const size_t ysize = raidz_col_size(rm, y);
+       const size_t short_size = raidz_short_size(rm);
+       unsigned coeff[MUL_CNT];
+
+       raidz_rec_pr_coeff(rm, tgtidx, coeff);
+
+       raidz_math_begin();
+
+       /* 0 - short_size */
+       REC_PR_BLOCK(rm, 0, short_size, x, y, coeff, ncols, ncols, B_TRUE);
+
+       /* short_size - xsize */
+       REC_PR_BLOCK(rm, short_size, xsize, x, y, coeff, ncols, nbigcols,
+           xsize == ysize);
+
+       raidz_math_end();
+
+       return ((1 << CODE_P) | (1 << CODE_R));
+}
+
+
+/*
+ * Reconstruct using QR parity
+ */
+
+#define        REC_QR_SYN_UPDATE()                     \
+{                                              \
+       MUL2(REC_QR_X);                         \
+       MUL4(REC_QR_Y);                         \
+}
+
+#define        REC_QR_INNER_LOOP(c)                    \
+{                                              \
+       col = &rm->rm_col[c];                   \
+       LOAD(COL_OFF(col, ioff), REC_QR_D);     \
+       REC_QR_SYN_UPDATE();                    \
+       XOR(REC_QR_D, REC_QR_X);                \
+       XOR(REC_QR_D, REC_QR_Y);                \
+}
+
+/*
+ * Reconstruction using QR parity
+ * @rm         RAIDZ map
+ * @off                starting offset
+ * @end                ending offset
+ * @x          missing data column
+ * @y          missing data column
+ * @coeff      multiplication coefficients
+ * @ncols      number of column
+ * @nbigcols   number of big columns
+ * @calcy      calculate second data column
+ */
+static raidz_inline void
+REC_QR_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int x, const int y, const unsigned *coeff, const int ncols,
+    const int nbigcols, const boolean_t calcy)
+{
+       int c;
+       size_t ioff;
+       const size_t firstdc = raidz_parity(rm);
+       raidz_col_t * const qcol = raidz_col_p(rm, CODE_Q);
+       raidz_col_t * const rcol = raidz_col_p(rm, CODE_R);
+       raidz_col_t * const xcol = raidz_col_p(rm, x);
+       raidz_col_t * const ycol = raidz_col_p(rm, y);
+       raidz_col_t *col;
+
+       REC_QR_DEFINE();
+
+       for (ioff = off; ioff < end; ioff += (REC_QR_STRIDE * sizeof (v_t))) {
+               MUL2_SETUP();
+               ZERO(REC_QR_X);
+               ZERO(REC_QR_Y);
+
+               if (ncols == nbigcols) {
+                       for (c = firstdc; c < x; c++)
+                               REC_QR_INNER_LOOP(c);
+
+                       REC_QR_SYN_UPDATE();
+                       for (c++; c < y; c++)
+                               REC_QR_INNER_LOOP(c);
+
+                       REC_QR_SYN_UPDATE();
+                       for (c++; c < nbigcols; c++)
+                               REC_QR_INNER_LOOP(c);
+               } else {
+                       for (c = firstdc; c < nbigcols; c++) {
+                               REC_QR_SYN_UPDATE();
+                               if (c != x && c != y) {
+                                       col = &rm->rm_col[c];
+                                       LOAD(COL_OFF(col, ioff), REC_QR_D);
+                                       XOR(REC_QR_D, REC_QR_X);
+                                       XOR(REC_QR_D, REC_QR_Y);
+                               }
+                       }
+                       for (; c < ncols; c++)
+                               REC_QR_SYN_UPDATE();
+               }
+
+               XOR_ACC(COL_OFF(qcol, ioff), REC_QR_X);
+               XOR_ACC(COL_OFF(rcol, ioff), REC_QR_Y);
+
+               /* Save Qxy */
+               COPY(REC_QR_X,  REC_QR_D);
+
+               /* Calc X */
+               MUL(coeff[MUL_QR_XQ], REC_QR_X);        /* X = Q * xqm */
+               XOR(REC_QR_Y, REC_QR_X);                /* X = R ^ X   */
+               MUL(coeff[MUL_QR_X], REC_QR_X);         /* X = X * xm  */
+               STORE(COL_OFF(xcol, ioff), REC_QR_X);
+
+               if (calcy) {
+                       /* Calc Y */
+                       MUL(coeff[MUL_QR_YQ], REC_QR_D); /* X = Q * xqm */
+                       XOR(REC_QR_Y, REC_QR_D);         /* X = R ^ X   */
+                       MUL(coeff[MUL_QR_Y], REC_QR_D);  /* X = X * xm  */
+                       STORE(COL_OFF(ycol, ioff), REC_QR_D);
+               }
+       }
+}
+
+/*
+ * Reconstruct two data columns using QR parity
+ * @rec_method REC_QR_BLOCK()
+ *
+ * @rm         RAIDZ map
+ * @tgtidx     array of missing data indexes
+ */
+static raidz_inline int
+raidz_reconstruct_qr_impl(raidz_map_t *rm, const int *tgtidx)
+{
+       const int x = tgtidx[TARGET_X];
+       const int y = tgtidx[TARGET_Y];
+       const int ncols = raidz_ncols(rm);
+       const int nbigcols = raidz_nbigcols(rm);
+       const size_t xsize = raidz_col_size(rm, x);
+       const size_t ysize = raidz_col_size(rm, y);
+       const size_t short_size = raidz_short_size(rm);
+       unsigned coeff[MUL_CNT];
+
+       raidz_rec_qr_coeff(rm, tgtidx, coeff);
+
+       raidz_math_begin();
+
+       /* 0 - short_size */
+       REC_QR_BLOCK(rm, 0, short_size, x, y, coeff, ncols, ncols, B_TRUE);
+
+       /* short_size - xsize */
+       REC_QR_BLOCK(rm, short_size, xsize, x, y, coeff, ncols, nbigcols,
+           xsize == ysize);
+
+       raidz_math_end();
+
+       return ((1 << CODE_Q) | (1 << CODE_R));
+}
+
+/*
+ * Reconstruct using PQR parity
+ */
+
+#define        REC_PQR_SYN_UPDATE()                    \
+{                                              \
+       MUL2(REC_PQR_Y);                        \
+       MUL4(REC_PQR_Z);                        \
+}
+
+#define        REC_PQR_INNER_LOOP(c)                   \
+{                                              \
+       col = &rm->rm_col[(c)];                 \
+       LOAD(COL_OFF(col, ioff), REC_PQR_D);    \
+       REC_PQR_SYN_UPDATE();                   \
+       XOR(REC_PQR_D, REC_PQR_X);              \
+       XOR(REC_PQR_D, REC_PQR_Y);              \
+       XOR(REC_PQR_D, REC_PQR_Z);              \
+}
+
+/*
+ * Reconstruction using PQR parity
+ * @rm         RAIDZ map
+ * @off                starting offset
+ * @end                ending offset
+ * @x          missing data column
+ * @y          missing data column
+ * @z          missing data column
+ * @coeff      multiplication coefficients
+ * @ncols      number of column
+ * @nbigcols   number of big columns
+ * @calcy      calculate second data column
+ * @calcz      calculate third data column
+ */
+static raidz_inline void
+REC_PQR_BLOCK(raidz_map_t * const rm, const size_t off, const size_t end,
+    const int x, const int y, const int z, const unsigned *coeff,
+    const int ncols, const int nbigcols, const boolean_t calcy,
+    const boolean_t calcz)
+{
+       int c;
+       size_t ioff;
+       const size_t firstdc = raidz_parity(rm);
+       raidz_col_t * const pcol = raidz_col_p(rm, CODE_P);
+       raidz_col_t * const qcol = raidz_col_p(rm, CODE_Q);
+       raidz_col_t * const rcol = raidz_col_p(rm, CODE_R);
+       raidz_col_t * const xcol = raidz_col_p(rm, x);
+       raidz_col_t * const ycol = raidz_col_p(rm, y);
+       raidz_col_t * const zcol = raidz_col_p(rm, z);
+       raidz_col_t *col;
+
+       REC_PQR_DEFINE();
+
+       for (ioff = off; ioff < end; ioff += (REC_PQR_STRIDE * sizeof (v_t))) {
+               MUL2_SETUP();
+               LOAD(COL_OFF(pcol, ioff), REC_PQR_X);
+               ZERO(REC_PQR_Y);
+               ZERO(REC_PQR_Z);
+
+               if (ncols == nbigcols) {
+                       for (c = firstdc; c < x; c++)
+                               REC_PQR_INNER_LOOP(c);
+
+                       REC_PQR_SYN_UPDATE();
+                       for (c++; c < y; c++)
+                               REC_PQR_INNER_LOOP(c);
+
+                       REC_PQR_SYN_UPDATE();
+                       for (c++; c < z; c++)
+                               REC_PQR_INNER_LOOP(c);
+
+                       REC_PQR_SYN_UPDATE();
+                       for (c++; c < nbigcols; c++)
+                               REC_PQR_INNER_LOOP(c);
+               } else {
+                       for (c = firstdc; c < nbigcols; c++) {
+                               REC_PQR_SYN_UPDATE();
+                               if (c != x && c != y && c != z) {
+                                       col = &rm->rm_col[c];
+                                       LOAD(COL_OFF(col, ioff), REC_PQR_D);
+                                       XOR(REC_PQR_D, REC_PQR_X);
+                                       XOR(REC_PQR_D, REC_PQR_Y);
+                                       XOR(REC_PQR_D, REC_PQR_Z);
+                               }
+                       }
+                       for (; c < ncols; c++)
+                               REC_PQR_SYN_UPDATE();
+               }
+
+               XOR_ACC(COL_OFF(qcol, ioff), REC_PQR_Y);
+               XOR_ACC(COL_OFF(rcol, ioff), REC_PQR_Z);
+
+               /* Save Pxyz and Qxyz */
+               COPY(REC_PQR_X, REC_PQR_XS);
+               COPY(REC_PQR_Y, REC_PQR_YS);
+
+               /* Calc X */
+               MUL(coeff[MUL_PQR_XP], REC_PQR_X);      /* Xp = Pxyz * xp   */
+               MUL(coeff[MUL_PQR_XQ], REC_PQR_Y);      /* Xq = Qxyz * xq   */
+               XOR(REC_PQR_Y, REC_PQR_X);
+               MUL(coeff[MUL_PQR_XR], REC_PQR_Z);      /* Xr = Rxyz * xr   */
+               XOR(REC_PQR_Z, REC_PQR_X);              /* X = Xp + Xq + Xr */
+               STORE(COL_OFF(xcol, ioff), REC_PQR_X);
+
+               if (calcy) {
+                       /* Calc Y */
+                       XOR(REC_PQR_X, REC_PQR_XS);        /* Pyz = Pxyz + X */
+                       MUL(coeff[MUL_PQR_YU], REC_PQR_X); /* Xq = X * upd_q */
+                       XOR(REC_PQR_X, REC_PQR_YS);        /* Qyz = Qxyz + Xq */
+                       COPY(REC_PQR_XS, REC_PQR_X);       /* restore Pyz */
+                       MUL(coeff[MUL_PQR_YP], REC_PQR_X); /* Yp = Pyz * yp */
+                       MUL(coeff[MUL_PQR_YQ], REC_PQR_YS); /* Yq = Qyz * yq */
+                       XOR(REC_PQR_X, REC_PQR_YS);         /* Y = Yp + Yq */
+                       STORE(COL_OFF(ycol, ioff), REC_PQR_YS);
+               }
+
+               if (calcz) {
+                       /* Calc Z */
+                       XOR(REC_PQR_XS, REC_PQR_YS);    /* Z = Pz = Pyz + Y */
+                       STORE(COL_OFF(zcol, ioff), REC_PQR_YS);
+               }
+       }
+}
+
+/*
+ * Reconstruct three data columns using PQR parity
+ * @rec_method REC_PQR_BLOCK()
+ *
+ * @rm         RAIDZ map
+ * @tgtidx     array of missing data indexes
+ */
+static raidz_inline int
+raidz_reconstruct_pqr_impl(raidz_map_t *rm, const int *tgtidx)
+{
+       const int x = tgtidx[TARGET_X];
+       const int y = tgtidx[TARGET_Y];
+       const int z = tgtidx[TARGET_Z];
+       const int ncols = raidz_ncols(rm);
+       const int nbigcols = raidz_nbigcols(rm);
+       const size_t xsize = raidz_col_size(rm, x);
+       const size_t ysize = raidz_col_size(rm, y);
+       const size_t zsize = raidz_col_size(rm, z);
+       const size_t short_size = raidz_short_size(rm);
+       unsigned coeff[MUL_CNT];
+
+       raidz_rec_pqr_coeff(rm, tgtidx, coeff);
+
+       raidz_math_begin();
+
+       /* 0 - short_size */
+       REC_PQR_BLOCK(rm, 0, short_size, x, y, z, coeff, ncols, ncols,
+           B_TRUE, B_TRUE);
+
+       /* short_size - xsize */
+       REC_PQR_BLOCK(rm, short_size, xsize, x, y, z, coeff, ncols, nbigcols,
+           xsize == ysize, xsize == zsize);
+
+       raidz_math_end();
+
+       return ((1 << CODE_P) | (1 << CODE_Q) | (1 << CODE_R));
+}
+
+#endif /* _VDEV_RAIDZ_MATH_IMPL_H */
diff --git a/zfs/module/zfs/vdev_raidz_math_scalar.c b/zfs/module/zfs/vdev_raidz_math_scalar.c
new file mode 100644 (file)
index 0000000..993d406
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#include <sys/vdev_raidz_impl.h>
+
+/*
+ * Provide native CPU scalar routines.
+ * Support 32bit and 64bit CPUs.
+ */
+#if ((~(0x0ULL)) >> 24) == 0xffULL
+#define        ELEM_SIZE       4
+typedef uint32_t iv_t;
+#elif ((~(0x0ULL)) >> 56) == 0xffULL
+#define        ELEM_SIZE       8
+typedef uint64_t iv_t;
+#endif
+
+/*
+ * Vector type used in scalar implementation
+ *
+ * The union is expected to be of native CPU register size. Since addition
+ * uses XOR operation, it can be performed an all byte elements at once.
+ * Multiplication requires per byte access.
+ */
+typedef union {
+       iv_t e;
+       uint8_t b[ELEM_SIZE];
+} v_t;
+
+/*
+ * Precomputed lookup tables for multiplication by a constant
+ *
+ * Reconstruction path requires multiplication by a constant factors. Instead of
+ * performing two step lookup (log & exp tables), a direct lookup can be used
+ * instead. Multiplication of element 'a' by a constant 'c' is obtained as:
+ *
+ *     r = vdev_raidz_mul_lt[c_log][a];
+ *
+ * where c_log = vdev_raidz_log2[c]. Log of coefficient factors is used because
+ * they are faster to obtain while solving the syndrome equations.
+ *
+ * PERFORMANCE NOTE:
+ * Even though the complete lookup table uses 64kiB, only relatively small
+ * portion of it is used at the same time. Following shows number of accessed
+ * bytes for different cases:
+ *     - 1 failed disk: 256B (1 mul. coefficient)
+ *     - 2 failed disks: 512B (2 mul. coefficients)
+ *     - 3 failed disks: 1536B (6 mul. coefficients)
+ *
+ * Size of actually accessed lookup table regions is only larger for
+ * reconstruction of 3 failed disks, when compared to traditional log/exp
+ * method. But since the result is obtained in one lookup step performance is
+ * doubled.
+ */
+static uint8_t vdev_raidz_mul_lt[256][256] __attribute__((aligned(256)));
+
+static void
+raidz_init_scalar(void)
+{
+       int c, i;
+       for (c = 0; c < 256; c++)
+               for (i = 0; i < 256; i++)
+                       vdev_raidz_mul_lt[c][i] = gf_mul(c, i);
+
+}
+
+#define        PREFETCHNTA(ptr, offset)        {}
+#define        PREFETCH(ptr, offset)           {}
+
+#define        XOR_ACC(src, acc)       acc.e ^= ((v_t *)src)[0].e
+#define        XOR(src, acc)           acc.e ^= src.e
+#define        ZERO(acc)               acc.e = 0
+#define        COPY(src, dst)          dst = src
+#define        LOAD(src, val)          val = ((v_t *)src)[0]
+#define        STORE(dst, val)         ((v_t *)dst)[0] = val
+
+/*
+ * Constants used for optimized multiplication by 2.
+ */
+static const struct {
+       iv_t mod;
+       iv_t mask;
+       iv_t msb;
+} scalar_mul2_consts = {
+#if ELEM_SIZE == 8
+       .mod    = 0x1d1d1d1d1d1d1d1dULL,
+       .mask   = 0xfefefefefefefefeULL,
+       .msb    = 0x8080808080808080ULL,
+#else
+       .mod    = 0x1d1d1d1dULL,
+       .mask   = 0xfefefefeULL,
+       .msb    = 0x80808080ULL,
+#endif
+};
+
+#define        MUL2_SETUP() {}
+
+#define        MUL2(a)                                                         \
+{                                                                      \
+       iv_t _mask;                                                     \
+                                                                       \
+       _mask = (a).e & scalar_mul2_consts.msb;                         \
+       _mask = (_mask << 1) - (_mask >> 7);                            \
+       (a).e = ((a).e << 1) & scalar_mul2_consts.mask;                 \
+       (a).e = (a).e ^ (_mask & scalar_mul2_consts.mod);               \
+}
+
+#define        MUL4(a)                                                         \
+{                                                                      \
+       MUL2(a);                                                        \
+       MUL2(a);                                                        \
+}
+
+#define        MUL(c, a)                                                       \
+{                                                                      \
+       const uint8_t *mul_lt = vdev_raidz_mul_lt[c];                   \
+       switch (ELEM_SIZE) {                                            \
+       case 8:                                                         \
+               a.b[7] = mul_lt[a.b[7]];                                \
+               a.b[6] = mul_lt[a.b[6]];                                \
+               a.b[5] = mul_lt[a.b[5]];                                \
+               a.b[4] = mul_lt[a.b[4]];                                \
+       case 4:                                                         \
+               a.b[3] = mul_lt[a.b[3]];                                \
+               a.b[2] = mul_lt[a.b[2]];                                \
+               a.b[1] = mul_lt[a.b[1]];                                \
+               a.b[0] = mul_lt[a.b[0]];                                \
+               break;                                                  \
+       }                                                               \
+}
+
+#define        raidz_math_begin()      {}
+#define        raidz_math_end()        {}
+
+#define        GEN_P_DEFINE() v_t p0
+#define        GEN_P_STRIDE    1
+#define        GEN_P_P         p0
+
+#define        GEN_PQ_DEFINE() v_t d0, p0, q0
+#define        GEN_PQ_STRIDE   1
+#define        GEN_PQ_D        d0
+#define        GEN_PQ_P        p0
+#define        GEN_PQ_Q        q0
+
+#define        GEN_PQR_DEFINE() v_t d0, p0, q0, r0
+#define        GEN_PQR_STRIDE  1
+#define        GEN_PQR_D       d0
+#define        GEN_PQR_P       p0
+#define        GEN_PQR_Q       q0
+#define        GEN_PQR_R       r0
+
+#define        REC_P_DEFINE()  v_t x0
+#define        REC_P_STRIDE    1
+#define        REC_P_X         x0
+
+#define        REC_Q_DEFINE()  v_t x0
+#define        REC_Q_STRIDE    1
+#define        REC_Q_X         x0
+
+#define        REC_R_DEFINE()  v_t x0
+#define        REC_R_STRIDE    1
+#define        REC_R_X         x0
+
+#define        REC_PQ_DEFINE() v_t x0, y0, d0
+#define        REC_PQ_STRIDE   1
+#define        REC_PQ_X        x0
+#define        REC_PQ_Y        y0
+#define        REC_PQ_D        d0
+
+#define        REC_PR_DEFINE() v_t x0, y0, d0
+#define        REC_PR_STRIDE   1
+#define        REC_PR_X        x0
+#define        REC_PR_Y        y0
+#define        REC_PR_D        d0
+
+#define        REC_QR_DEFINE() v_t x0, y0, d0
+#define        REC_QR_STRIDE   1
+#define        REC_QR_X        x0
+#define        REC_QR_Y        y0
+#define        REC_QR_D        d0
+
+#define        REC_PQR_DEFINE() v_t x0, y0, z0, d0, t0
+#define        REC_PQR_STRIDE  1
+#define        REC_PQR_X       x0
+#define        REC_PQR_Y       y0
+#define        REC_PQR_Z       z0
+#define        REC_PQR_D       d0
+#define        REC_PQR_XS      d0
+#define        REC_PQR_YS      t0
+
+#include "vdev_raidz_math_impl.h"
+
+/*
+ * If compiled with -O0, gcc doesn't do any stack frame coalescing
+ * and -Wframe-larger-than=1024 is triggered in debug mode.
+ * Starting with gcc 4.8, new opt level -Og is introduced for debugging, which
+ * does not trigger this warning.
+ */
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+
+DEFINE_GEN_METHODS(scalar);
+DEFINE_REC_METHODS(scalar);
+
+boolean_t
+raidz_will_scalar_work(void)
+{
+       return (B_TRUE); /* always */
+}
+
+const raidz_impl_ops_t vdev_raidz_scalar_impl = {
+       .init = raidz_init_scalar,
+       .fini = NULL,
+       .gen = RAIDZ_GEN_METHODS(scalar),
+       .rec = RAIDZ_REC_METHODS(scalar),
+       .is_supported = &raidz_will_scalar_work,
+       .name = "scalar"
+};
+
+/* Powers of 2 in the RAID-Z Galois field. */
+const uint8_t vdev_raidz_pow2[256] __attribute__((aligned(256))) = {
+       0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+       0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
+       0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9,
+       0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
+       0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35,
+       0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
+       0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0,
+       0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
+       0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc,
+       0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
+       0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f,
+       0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
+       0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88,
+       0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
+       0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93,
+       0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
+       0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9,
+       0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
+       0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa,
+       0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
+       0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e,
+       0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
+       0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4,
+       0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
+       0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e,
+       0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
+       0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef,
+       0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
+       0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5,
+       0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
+       0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83,
+       0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01
+};
+
+/* Logs of 2 in the RAID-Z Galois field. */
+const uint8_t vdev_raidz_log2[256] __attribute__((aligned(256))) = {
+       0x00, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6,
+       0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b,
+       0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81,
+       0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71,
+       0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21,
+       0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45,
+       0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9,
+       0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6,
+       0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd,
+       0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88,
+       0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd,
+       0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40,
+       0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e,
+       0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d,
+       0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b,
+       0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57,
+       0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d,
+       0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18,
+       0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c,
+       0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e,
+       0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd,
+       0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61,
+       0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e,
+       0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2,
+       0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76,
+       0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6,
+       0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa,
+       0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a,
+       0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51,
+       0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7,
+       0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8,
+       0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf,
+};
diff --git a/zfs/module/zfs/vdev_raidz_math_sse2.c b/zfs/module/zfs/vdev_raidz_math_sse2.c
new file mode 100644 (file)
index 0000000..6fc8121
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#include <sys/isa_defs.h>
+
+#if defined(__x86_64) && defined(HAVE_SSE2)
+
+#include <sys/types.h>
+#include <linux/simd_x86.h>
+
+#define        __asm __asm__ __volatile__
+
+#define        _REG_CNT(_0, _1, _2, _3, _4, _5, _6, _7, N, ...) N
+#define        REG_CNT(r...) _REG_CNT(r, 8, 7, 6, 5, 4, 3, 2, 1)
+
+#define        VR0_(REG, ...) "xmm"#REG
+#define        VR1_(_1, REG, ...) "xmm"#REG
+#define        VR2_(_1, _2, REG, ...) "xmm"#REG
+#define        VR3_(_1, _2, _3, REG, ...) "xmm"#REG
+#define        VR4_(_1, _2, _3, _4, REG, ...) "xmm"#REG
+#define        VR5_(_1, _2, _3, _4, _5, REG, ...) "xmm"#REG
+#define        VR6_(_1, _2, _3, _4, _5, _6, REG, ...) "xmm"#REG
+#define        VR7_(_1, _2, _3, _4, _5, _6, _7, REG, ...) "xmm"#REG
+
+#define        VR0(r...) VR0_(r, 1, 2, 3, 4, 5, 6)
+#define        VR1(r...) VR1_(r, 1, 2, 3, 4, 5, 6)
+#define        VR2(r...) VR2_(r, 1, 2, 3, 4, 5, 6)
+#define        VR3(r...) VR3_(r, 1, 2, 3, 4, 5, 6)
+#define        VR4(r...) VR4_(r, 1, 2, 3, 4, 5, 6)
+#define        VR5(r...) VR5_(r, 1, 2, 3, 4, 5, 6)
+#define        VR6(r...) VR6_(r, 1, 2, 3, 4, 5, 6)
+#define        VR7(r...) VR7_(r, 1, 2, 3, 4, 5, 6)
+
+#define        ELEM_SIZE 16
+
+typedef struct v {
+       uint8_t b[ELEM_SIZE] __attribute__((aligned(ELEM_SIZE)));
+} v_t;
+
+#define        PREFETCHNTA(ptr, offset)        {}
+#define        PREFETCH(ptr, offset)           {}
+
+#define        XOR_ACC(src, r...)                                              \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "pxor 0x00(%[SRC]), %%" VR0(r) "\n"                 \
+                   "pxor 0x10(%[SRC]), %%" VR1(r) "\n"                 \
+                   "pxor 0x20(%[SRC]), %%" VR2(r) "\n"                 \
+                   "pxor 0x30(%[SRC]), %%" VR3(r) "\n"                 \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "pxor 0x00(%[SRC]), %%" VR0(r) "\n"                 \
+                   "pxor 0x10(%[SRC]), %%" VR1(r) "\n"                 \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       case 1:                                                         \
+               __asm("pxor 0x00(%[SRC]), %%" VR0(r) "\n"               \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       }                                                               \
+}
+
+#define        XOR(r...)                                                       \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR4(r) "\n"                   \
+                   "pxor %" VR1(r) ", %" VR5(r) "\n"                   \
+                   "pxor %" VR2(r) ", %" VR6(r) "\n"                   \
+                   "pxor %" VR3(r) ", %" VR7(r));                      \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR2(r) "\n"                   \
+                   "pxor %" VR1(r) ", %" VR3(r));                      \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR1(r));                      \
+               break;                                                  \
+       }                                                               \
+}
+#define        ZERO(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR0(r) "\n"                   \
+                   "pxor %" VR1(r) ", %" VR1(r) "\n"                   \
+                   "pxor %" VR2(r) ", %" VR2(r) "\n"                   \
+                   "pxor %" VR3(r) ", %" VR3(r));                      \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR0(r) "\n"                   \
+                   "pxor %" VR1(r) ", %" VR1(r));                      \
+               break;                                                  \
+       case 1:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR0(r));                      \
+               break;                                                  \
+       }                                                               \
+}
+
+#define        COPY(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+                   "movdqa %" VR0(r) ", %" VR4(r) "\n"                 \
+                   "movdqa %" VR1(r) ", %" VR5(r) "\n"                 \
+                   "movdqa %" VR2(r) ", %" VR6(r) "\n"                 \
+                   "movdqa %" VR3(r) ", %" VR7(r));                    \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "movdqa %" VR0(r) ", %" VR2(r) "\n"                 \
+                   "movdqa %" VR1(r) ", %" VR3(r));                    \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "movdqa %" VR0(r) ", %" VR1(r));                    \
+               break;                                                  \
+       }                                                               \
+}
+
+#define        LOAD(src, r...)                                                 \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "movdqa 0x00(%[SRC]), %%" VR0(r) "\n"               \
+                   "movdqa 0x10(%[SRC]), %%" VR1(r) "\n"               \
+                   "movdqa 0x20(%[SRC]), %%" VR2(r) "\n"               \
+                   "movdqa 0x30(%[SRC]), %%" VR3(r) "\n"               \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "movdqa 0x00(%[SRC]), %%" VR0(r) "\n"               \
+                   "movdqa 0x10(%[SRC]), %%" VR1(r) "\n"               \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       case 1:                                                         \
+               __asm(                                                  \
+                   "movdqa 0x00(%[SRC]), %%" VR0(r) "\n"               \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       }                                                               \
+}
+
+#define        STORE(dst, r...)                                                \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "movdqa %%" VR0(r)", 0x00(%[DST])\n"                \
+                   "movdqa %%" VR1(r)", 0x10(%[DST])\n"                \
+                   "movdqa %%" VR2(r)", 0x20(%[DST])\n"                \
+                   "movdqa %%" VR3(r)", 0x30(%[DST])\n"                \
+                   : : [DST] "r" (dst));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "movdqa %%" VR0(r)", 0x00(%[DST])\n"                \
+                   "movdqa %%" VR1(r)", 0x10(%[DST])\n"                \
+                   : : [DST] "r" (dst));                               \
+               break;                                                  \
+       case 1:                                                         \
+               __asm(                                                  \
+                   "movdqa %%" VR0(r)", 0x00(%[DST])\n"                \
+                   : : [DST] "r" (dst));                               \
+               break;                                                  \
+       }                                                               \
+}
+
+#define        MUL2_SETUP()                                                    \
+{                                                                      \
+       __asm(                                                          \
+           "movd %[mask], %%xmm15\n"                                   \
+           "pshufd $0x0, %%xmm15, %%xmm15\n"                           \
+           : : [mask] "r" (0x1d1d1d1d));                               \
+}
+
+#define        _MUL2_x1(a0)                                                    \
+{                                                                      \
+       __asm(                                                          \
+           "pxor    %xmm14,      %xmm14\n"                             \
+           "pcmpgtb %" a0",  %xmm14\n"                                 \
+           "pand    %xmm15,      %xmm14\n"                             \
+           "paddb   %" a0",  %" a0 "\n"                                \
+           "pxor    %xmm14,      %" a0);                               \
+}
+
+#define        _MUL2_x2(a0, a1)                                                \
+{                                                                      \
+       __asm(                                                          \
+           "pxor    %xmm14,      %xmm14\n"                             \
+           "pxor    %xmm13,      %xmm13\n"                             \
+           "pcmpgtb %" a0",  %xmm14\n"                                 \
+           "pcmpgtb %" a1",  %xmm13\n"                                 \
+           "pand    %xmm15,      %xmm14\n"                             \
+           "pand    %xmm15,      %xmm13\n"                             \
+           "paddb   %" a0",  %" a0 "\n"                                \
+           "paddb   %" a1",  %" a1 "\n"                                \
+           "pxor    %xmm14,      %" a0 "\n"                            \
+           "pxor    %xmm13,      %" a1);                               \
+}
+
+#define        MUL2(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 2:                                                         \
+               _MUL2_x2(VR0(r), VR1(r));                               \
+               break;                                                  \
+       case 1:                                                         \
+               _MUL2_x1(VR0(r));                                       \
+               break;                                                  \
+       }                                                               \
+}
+
+#define        MUL4(r...)                                                      \
+{                                                                      \
+       MUL2(r);                                                        \
+       MUL2(r);                                                        \
+}
+
+/* General multiplication by adding powers of two */
+
+#define        _MUL_PARAM(x, in, acc)                                          \
+{                                                                      \
+       if (x & 0x01) { COPY(in, acc); } else { XOR(acc, acc); }        \
+       if (x & 0xfe) { MUL2(in); }                                     \
+       if (x & 0x02) { XOR(in, acc); }                                 \
+       if (x & 0xfc) { MUL2(in); }                                     \
+       if (x & 0x04) { XOR(in, acc); }                                 \
+       if (x & 0xf8) { MUL2(in); }                                     \
+       if (x & 0x08) { XOR(in, acc); }                                 \
+       if (x & 0xf0) { MUL2(in); }                                     \
+       if (x & 0x10) { XOR(in, acc); }                                 \
+       if (x & 0xe0) { MUL2(in); }                                     \
+       if (x & 0x20) { XOR(in, acc); }                                 \
+       if (x & 0xc0) { MUL2(in); }                                     \
+       if (x & 0x40) { XOR(in, acc); }                                 \
+       if (x & 0x80) { MUL2(in); XOR(in, acc); }                       \
+}
+
+#define        _mul_x1_in      9
+#define        _mul_x1_acc     11
+
+#define        MUL_x1_DEFINE(x)                                                \
+static void                                                            \
+mul_x1_ ## x(void) { _MUL_PARAM(x, _mul_x1_in, _mul_x1_acc); }
+
+#define        _mul_x2_in      9, 10
+#define        _mul_x2_acc     11, 12
+
+#define        MUL_x2_DEFINE(x)                                                \
+static void                                                            \
+mul_x2_ ## x(void) { _MUL_PARAM(x, _mul_x2_in, _mul_x2_acc); }
+
+MUL_x1_DEFINE(0); MUL_x1_DEFINE(1); MUL_x1_DEFINE(2); MUL_x1_DEFINE(3);
+MUL_x1_DEFINE(4); MUL_x1_DEFINE(5); MUL_x1_DEFINE(6); MUL_x1_DEFINE(7);
+MUL_x1_DEFINE(8); MUL_x1_DEFINE(9); MUL_x1_DEFINE(10); MUL_x1_DEFINE(11);
+MUL_x1_DEFINE(12); MUL_x1_DEFINE(13); MUL_x1_DEFINE(14); MUL_x1_DEFINE(15);
+MUL_x1_DEFINE(16); MUL_x1_DEFINE(17); MUL_x1_DEFINE(18); MUL_x1_DEFINE(19);
+MUL_x1_DEFINE(20); MUL_x1_DEFINE(21); MUL_x1_DEFINE(22); MUL_x1_DEFINE(23);
+MUL_x1_DEFINE(24); MUL_x1_DEFINE(25); MUL_x1_DEFINE(26); MUL_x1_DEFINE(27);
+MUL_x1_DEFINE(28); MUL_x1_DEFINE(29); MUL_x1_DEFINE(30); MUL_x1_DEFINE(31);
+MUL_x1_DEFINE(32); MUL_x1_DEFINE(33); MUL_x1_DEFINE(34); MUL_x1_DEFINE(35);
+MUL_x1_DEFINE(36); MUL_x1_DEFINE(37); MUL_x1_DEFINE(38); MUL_x1_DEFINE(39);
+MUL_x1_DEFINE(40); MUL_x1_DEFINE(41); MUL_x1_DEFINE(42); MUL_x1_DEFINE(43);
+MUL_x1_DEFINE(44); MUL_x1_DEFINE(45); MUL_x1_DEFINE(46); MUL_x1_DEFINE(47);
+MUL_x1_DEFINE(48); MUL_x1_DEFINE(49); MUL_x1_DEFINE(50); MUL_x1_DEFINE(51);
+MUL_x1_DEFINE(52); MUL_x1_DEFINE(53); MUL_x1_DEFINE(54); MUL_x1_DEFINE(55);
+MUL_x1_DEFINE(56); MUL_x1_DEFINE(57); MUL_x1_DEFINE(58); MUL_x1_DEFINE(59);
+MUL_x1_DEFINE(60); MUL_x1_DEFINE(61); MUL_x1_DEFINE(62); MUL_x1_DEFINE(63);
+MUL_x1_DEFINE(64); MUL_x1_DEFINE(65); MUL_x1_DEFINE(66); MUL_x1_DEFINE(67);
+MUL_x1_DEFINE(68); MUL_x1_DEFINE(69); MUL_x1_DEFINE(70); MUL_x1_DEFINE(71);
+MUL_x1_DEFINE(72); MUL_x1_DEFINE(73); MUL_x1_DEFINE(74); MUL_x1_DEFINE(75);
+MUL_x1_DEFINE(76); MUL_x1_DEFINE(77); MUL_x1_DEFINE(78); MUL_x1_DEFINE(79);
+MUL_x1_DEFINE(80); MUL_x1_DEFINE(81); MUL_x1_DEFINE(82); MUL_x1_DEFINE(83);
+MUL_x1_DEFINE(84); MUL_x1_DEFINE(85); MUL_x1_DEFINE(86); MUL_x1_DEFINE(87);
+MUL_x1_DEFINE(88); MUL_x1_DEFINE(89); MUL_x1_DEFINE(90); MUL_x1_DEFINE(91);
+MUL_x1_DEFINE(92); MUL_x1_DEFINE(93); MUL_x1_DEFINE(94); MUL_x1_DEFINE(95);
+MUL_x1_DEFINE(96); MUL_x1_DEFINE(97); MUL_x1_DEFINE(98); MUL_x1_DEFINE(99);
+MUL_x1_DEFINE(100); MUL_x1_DEFINE(101); MUL_x1_DEFINE(102); MUL_x1_DEFINE(103);
+MUL_x1_DEFINE(104); MUL_x1_DEFINE(105); MUL_x1_DEFINE(106); MUL_x1_DEFINE(107);
+MUL_x1_DEFINE(108); MUL_x1_DEFINE(109); MUL_x1_DEFINE(110); MUL_x1_DEFINE(111);
+MUL_x1_DEFINE(112); MUL_x1_DEFINE(113); MUL_x1_DEFINE(114); MUL_x1_DEFINE(115);
+MUL_x1_DEFINE(116); MUL_x1_DEFINE(117); MUL_x1_DEFINE(118); MUL_x1_DEFINE(119);
+MUL_x1_DEFINE(120); MUL_x1_DEFINE(121); MUL_x1_DEFINE(122); MUL_x1_DEFINE(123);
+MUL_x1_DEFINE(124); MUL_x1_DEFINE(125); MUL_x1_DEFINE(126); MUL_x1_DEFINE(127);
+MUL_x1_DEFINE(128); MUL_x1_DEFINE(129); MUL_x1_DEFINE(130); MUL_x1_DEFINE(131);
+MUL_x1_DEFINE(132); MUL_x1_DEFINE(133); MUL_x1_DEFINE(134); MUL_x1_DEFINE(135);
+MUL_x1_DEFINE(136); MUL_x1_DEFINE(137); MUL_x1_DEFINE(138); MUL_x1_DEFINE(139);
+MUL_x1_DEFINE(140); MUL_x1_DEFINE(141); MUL_x1_DEFINE(142); MUL_x1_DEFINE(143);
+MUL_x1_DEFINE(144); MUL_x1_DEFINE(145); MUL_x1_DEFINE(146); MUL_x1_DEFINE(147);
+MUL_x1_DEFINE(148); MUL_x1_DEFINE(149); MUL_x1_DEFINE(150); MUL_x1_DEFINE(151);
+MUL_x1_DEFINE(152); MUL_x1_DEFINE(153); MUL_x1_DEFINE(154); MUL_x1_DEFINE(155);
+MUL_x1_DEFINE(156); MUL_x1_DEFINE(157); MUL_x1_DEFINE(158); MUL_x1_DEFINE(159);
+MUL_x1_DEFINE(160); MUL_x1_DEFINE(161); MUL_x1_DEFINE(162); MUL_x1_DEFINE(163);
+MUL_x1_DEFINE(164); MUL_x1_DEFINE(165); MUL_x1_DEFINE(166); MUL_x1_DEFINE(167);
+MUL_x1_DEFINE(168); MUL_x1_DEFINE(169); MUL_x1_DEFINE(170); MUL_x1_DEFINE(171);
+MUL_x1_DEFINE(172); MUL_x1_DEFINE(173); MUL_x1_DEFINE(174); MUL_x1_DEFINE(175);
+MUL_x1_DEFINE(176); MUL_x1_DEFINE(177); MUL_x1_DEFINE(178); MUL_x1_DEFINE(179);
+MUL_x1_DEFINE(180); MUL_x1_DEFINE(181); MUL_x1_DEFINE(182); MUL_x1_DEFINE(183);
+MUL_x1_DEFINE(184); MUL_x1_DEFINE(185); MUL_x1_DEFINE(186); MUL_x1_DEFINE(187);
+MUL_x1_DEFINE(188); MUL_x1_DEFINE(189); MUL_x1_DEFINE(190); MUL_x1_DEFINE(191);
+MUL_x1_DEFINE(192); MUL_x1_DEFINE(193); MUL_x1_DEFINE(194); MUL_x1_DEFINE(195);
+MUL_x1_DEFINE(196); MUL_x1_DEFINE(197); MUL_x1_DEFINE(198); MUL_x1_DEFINE(199);
+MUL_x1_DEFINE(200); MUL_x1_DEFINE(201); MUL_x1_DEFINE(202); MUL_x1_DEFINE(203);
+MUL_x1_DEFINE(204); MUL_x1_DEFINE(205); MUL_x1_DEFINE(206); MUL_x1_DEFINE(207);
+MUL_x1_DEFINE(208); MUL_x1_DEFINE(209); MUL_x1_DEFINE(210); MUL_x1_DEFINE(211);
+MUL_x1_DEFINE(212); MUL_x1_DEFINE(213); MUL_x1_DEFINE(214); MUL_x1_DEFINE(215);
+MUL_x1_DEFINE(216); MUL_x1_DEFINE(217); MUL_x1_DEFINE(218); MUL_x1_DEFINE(219);
+MUL_x1_DEFINE(220); MUL_x1_DEFINE(221); MUL_x1_DEFINE(222); MUL_x1_DEFINE(223);
+MUL_x1_DEFINE(224); MUL_x1_DEFINE(225); MUL_x1_DEFINE(226); MUL_x1_DEFINE(227);
+MUL_x1_DEFINE(228); MUL_x1_DEFINE(229); MUL_x1_DEFINE(230); MUL_x1_DEFINE(231);
+MUL_x1_DEFINE(232); MUL_x1_DEFINE(233); MUL_x1_DEFINE(234); MUL_x1_DEFINE(235);
+MUL_x1_DEFINE(236); MUL_x1_DEFINE(237); MUL_x1_DEFINE(238); MUL_x1_DEFINE(239);
+MUL_x1_DEFINE(240); MUL_x1_DEFINE(241); MUL_x1_DEFINE(242); MUL_x1_DEFINE(243);
+MUL_x1_DEFINE(244); MUL_x1_DEFINE(245); MUL_x1_DEFINE(246); MUL_x1_DEFINE(247);
+MUL_x1_DEFINE(248); MUL_x1_DEFINE(249); MUL_x1_DEFINE(250); MUL_x1_DEFINE(251);
+MUL_x1_DEFINE(252); MUL_x1_DEFINE(253); MUL_x1_DEFINE(254); MUL_x1_DEFINE(255);
+
+MUL_x2_DEFINE(0); MUL_x2_DEFINE(1); MUL_x2_DEFINE(2); MUL_x2_DEFINE(3);
+MUL_x2_DEFINE(4); MUL_x2_DEFINE(5); MUL_x2_DEFINE(6); MUL_x2_DEFINE(7);
+MUL_x2_DEFINE(8); MUL_x2_DEFINE(9); MUL_x2_DEFINE(10); MUL_x2_DEFINE(11);
+MUL_x2_DEFINE(12); MUL_x2_DEFINE(13); MUL_x2_DEFINE(14); MUL_x2_DEFINE(15);
+MUL_x2_DEFINE(16); MUL_x2_DEFINE(17); MUL_x2_DEFINE(18); MUL_x2_DEFINE(19);
+MUL_x2_DEFINE(20); MUL_x2_DEFINE(21); MUL_x2_DEFINE(22); MUL_x2_DEFINE(23);
+MUL_x2_DEFINE(24); MUL_x2_DEFINE(25); MUL_x2_DEFINE(26); MUL_x2_DEFINE(27);
+MUL_x2_DEFINE(28); MUL_x2_DEFINE(29); MUL_x2_DEFINE(30); MUL_x2_DEFINE(31);
+MUL_x2_DEFINE(32); MUL_x2_DEFINE(33); MUL_x2_DEFINE(34); MUL_x2_DEFINE(35);
+MUL_x2_DEFINE(36); MUL_x2_DEFINE(37); MUL_x2_DEFINE(38); MUL_x2_DEFINE(39);
+MUL_x2_DEFINE(40); MUL_x2_DEFINE(41); MUL_x2_DEFINE(42); MUL_x2_DEFINE(43);
+MUL_x2_DEFINE(44); MUL_x2_DEFINE(45); MUL_x2_DEFINE(46); MUL_x2_DEFINE(47);
+MUL_x2_DEFINE(48); MUL_x2_DEFINE(49); MUL_x2_DEFINE(50); MUL_x2_DEFINE(51);
+MUL_x2_DEFINE(52); MUL_x2_DEFINE(53); MUL_x2_DEFINE(54); MUL_x2_DEFINE(55);
+MUL_x2_DEFINE(56); MUL_x2_DEFINE(57); MUL_x2_DEFINE(58); MUL_x2_DEFINE(59);
+MUL_x2_DEFINE(60); MUL_x2_DEFINE(61); MUL_x2_DEFINE(62); MUL_x2_DEFINE(63);
+MUL_x2_DEFINE(64); MUL_x2_DEFINE(65); MUL_x2_DEFINE(66); MUL_x2_DEFINE(67);
+MUL_x2_DEFINE(68); MUL_x2_DEFINE(69); MUL_x2_DEFINE(70); MUL_x2_DEFINE(71);
+MUL_x2_DEFINE(72); MUL_x2_DEFINE(73); MUL_x2_DEFINE(74); MUL_x2_DEFINE(75);
+MUL_x2_DEFINE(76); MUL_x2_DEFINE(77); MUL_x2_DEFINE(78); MUL_x2_DEFINE(79);
+MUL_x2_DEFINE(80); MUL_x2_DEFINE(81); MUL_x2_DEFINE(82); MUL_x2_DEFINE(83);
+MUL_x2_DEFINE(84); MUL_x2_DEFINE(85); MUL_x2_DEFINE(86); MUL_x2_DEFINE(87);
+MUL_x2_DEFINE(88); MUL_x2_DEFINE(89); MUL_x2_DEFINE(90); MUL_x2_DEFINE(91);
+MUL_x2_DEFINE(92); MUL_x2_DEFINE(93); MUL_x2_DEFINE(94); MUL_x2_DEFINE(95);
+MUL_x2_DEFINE(96); MUL_x2_DEFINE(97); MUL_x2_DEFINE(98); MUL_x2_DEFINE(99);
+MUL_x2_DEFINE(100); MUL_x2_DEFINE(101); MUL_x2_DEFINE(102); MUL_x2_DEFINE(103);
+MUL_x2_DEFINE(104); MUL_x2_DEFINE(105); MUL_x2_DEFINE(106); MUL_x2_DEFINE(107);
+MUL_x2_DEFINE(108); MUL_x2_DEFINE(109); MUL_x2_DEFINE(110); MUL_x2_DEFINE(111);
+MUL_x2_DEFINE(112); MUL_x2_DEFINE(113); MUL_x2_DEFINE(114); MUL_x2_DEFINE(115);
+MUL_x2_DEFINE(116); MUL_x2_DEFINE(117); MUL_x2_DEFINE(118); MUL_x2_DEFINE(119);
+MUL_x2_DEFINE(120); MUL_x2_DEFINE(121); MUL_x2_DEFINE(122); MUL_x2_DEFINE(123);
+MUL_x2_DEFINE(124); MUL_x2_DEFINE(125); MUL_x2_DEFINE(126); MUL_x2_DEFINE(127);
+MUL_x2_DEFINE(128); MUL_x2_DEFINE(129); MUL_x2_DEFINE(130); MUL_x2_DEFINE(131);
+MUL_x2_DEFINE(132); MUL_x2_DEFINE(133); MUL_x2_DEFINE(134); MUL_x2_DEFINE(135);
+MUL_x2_DEFINE(136); MUL_x2_DEFINE(137); MUL_x2_DEFINE(138); MUL_x2_DEFINE(139);
+MUL_x2_DEFINE(140); MUL_x2_DEFINE(141); MUL_x2_DEFINE(142); MUL_x2_DEFINE(143);
+MUL_x2_DEFINE(144); MUL_x2_DEFINE(145); MUL_x2_DEFINE(146); MUL_x2_DEFINE(147);
+MUL_x2_DEFINE(148); MUL_x2_DEFINE(149); MUL_x2_DEFINE(150); MUL_x2_DEFINE(151);
+MUL_x2_DEFINE(152); MUL_x2_DEFINE(153); MUL_x2_DEFINE(154); MUL_x2_DEFINE(155);
+MUL_x2_DEFINE(156); MUL_x2_DEFINE(157); MUL_x2_DEFINE(158); MUL_x2_DEFINE(159);
+MUL_x2_DEFINE(160); MUL_x2_DEFINE(161); MUL_x2_DEFINE(162); MUL_x2_DEFINE(163);
+MUL_x2_DEFINE(164); MUL_x2_DEFINE(165); MUL_x2_DEFINE(166); MUL_x2_DEFINE(167);
+MUL_x2_DEFINE(168); MUL_x2_DEFINE(169); MUL_x2_DEFINE(170); MUL_x2_DEFINE(171);
+MUL_x2_DEFINE(172); MUL_x2_DEFINE(173); MUL_x2_DEFINE(174); MUL_x2_DEFINE(175);
+MUL_x2_DEFINE(176); MUL_x2_DEFINE(177); MUL_x2_DEFINE(178); MUL_x2_DEFINE(179);
+MUL_x2_DEFINE(180); MUL_x2_DEFINE(181); MUL_x2_DEFINE(182); MUL_x2_DEFINE(183);
+MUL_x2_DEFINE(184); MUL_x2_DEFINE(185); MUL_x2_DEFINE(186); MUL_x2_DEFINE(187);
+MUL_x2_DEFINE(188); MUL_x2_DEFINE(189); MUL_x2_DEFINE(190); MUL_x2_DEFINE(191);
+MUL_x2_DEFINE(192); MUL_x2_DEFINE(193); MUL_x2_DEFINE(194); MUL_x2_DEFINE(195);
+MUL_x2_DEFINE(196); MUL_x2_DEFINE(197); MUL_x2_DEFINE(198); MUL_x2_DEFINE(199);
+MUL_x2_DEFINE(200); MUL_x2_DEFINE(201); MUL_x2_DEFINE(202); MUL_x2_DEFINE(203);
+MUL_x2_DEFINE(204); MUL_x2_DEFINE(205); MUL_x2_DEFINE(206); MUL_x2_DEFINE(207);
+MUL_x2_DEFINE(208); MUL_x2_DEFINE(209); MUL_x2_DEFINE(210); MUL_x2_DEFINE(211);
+MUL_x2_DEFINE(212); MUL_x2_DEFINE(213); MUL_x2_DEFINE(214); MUL_x2_DEFINE(215);
+MUL_x2_DEFINE(216); MUL_x2_DEFINE(217); MUL_x2_DEFINE(218); MUL_x2_DEFINE(219);
+MUL_x2_DEFINE(220); MUL_x2_DEFINE(221); MUL_x2_DEFINE(222); MUL_x2_DEFINE(223);
+MUL_x2_DEFINE(224); MUL_x2_DEFINE(225); MUL_x2_DEFINE(226); MUL_x2_DEFINE(227);
+MUL_x2_DEFINE(228); MUL_x2_DEFINE(229); MUL_x2_DEFINE(230); MUL_x2_DEFINE(231);
+MUL_x2_DEFINE(232); MUL_x2_DEFINE(233); MUL_x2_DEFINE(234); MUL_x2_DEFINE(235);
+MUL_x2_DEFINE(236); MUL_x2_DEFINE(237); MUL_x2_DEFINE(238); MUL_x2_DEFINE(239);
+MUL_x2_DEFINE(240); MUL_x2_DEFINE(241); MUL_x2_DEFINE(242); MUL_x2_DEFINE(243);
+MUL_x2_DEFINE(244); MUL_x2_DEFINE(245); MUL_x2_DEFINE(246); MUL_x2_DEFINE(247);
+MUL_x2_DEFINE(248); MUL_x2_DEFINE(249); MUL_x2_DEFINE(250); MUL_x2_DEFINE(251);
+MUL_x2_DEFINE(252); MUL_x2_DEFINE(253); MUL_x2_DEFINE(254); MUL_x2_DEFINE(255);
+
+
+
+typedef void (*mul_fn_ptr_t)(void);
+
+static const mul_fn_ptr_t __attribute__((aligned(256)))
+gf_x1_mul_fns[256] = {
+       mul_x1_0, mul_x1_1, mul_x1_2, mul_x1_3, mul_x1_4, mul_x1_5,
+       mul_x1_6, mul_x1_7, mul_x1_8, mul_x1_9, mul_x1_10, mul_x1_11,
+       mul_x1_12, mul_x1_13, mul_x1_14, mul_x1_15, mul_x1_16, mul_x1_17,
+       mul_x1_18, mul_x1_19, mul_x1_20, mul_x1_21, mul_x1_22, mul_x1_23,
+       mul_x1_24, mul_x1_25, mul_x1_26, mul_x1_27, mul_x1_28, mul_x1_29,
+       mul_x1_30, mul_x1_31, mul_x1_32, mul_x1_33, mul_x1_34, mul_x1_35,
+       mul_x1_36, mul_x1_37, mul_x1_38, mul_x1_39, mul_x1_40, mul_x1_41,
+       mul_x1_42, mul_x1_43, mul_x1_44, mul_x1_45, mul_x1_46, mul_x1_47,
+       mul_x1_48, mul_x1_49, mul_x1_50, mul_x1_51, mul_x1_52, mul_x1_53,
+       mul_x1_54, mul_x1_55, mul_x1_56, mul_x1_57, mul_x1_58, mul_x1_59,
+       mul_x1_60, mul_x1_61, mul_x1_62, mul_x1_63, mul_x1_64, mul_x1_65,
+       mul_x1_66, mul_x1_67, mul_x1_68, mul_x1_69, mul_x1_70, mul_x1_71,
+       mul_x1_72, mul_x1_73, mul_x1_74, mul_x1_75, mul_x1_76, mul_x1_77,
+       mul_x1_78, mul_x1_79, mul_x1_80, mul_x1_81, mul_x1_82, mul_x1_83,
+       mul_x1_84, mul_x1_85, mul_x1_86, mul_x1_87, mul_x1_88, mul_x1_89,
+       mul_x1_90, mul_x1_91, mul_x1_92, mul_x1_93, mul_x1_94, mul_x1_95,
+       mul_x1_96, mul_x1_97, mul_x1_98, mul_x1_99, mul_x1_100, mul_x1_101,
+       mul_x1_102, mul_x1_103, mul_x1_104, mul_x1_105, mul_x1_106, mul_x1_107,
+       mul_x1_108, mul_x1_109, mul_x1_110, mul_x1_111, mul_x1_112, mul_x1_113,
+       mul_x1_114, mul_x1_115, mul_x1_116, mul_x1_117, mul_x1_118, mul_x1_119,
+       mul_x1_120, mul_x1_121, mul_x1_122, mul_x1_123, mul_x1_124, mul_x1_125,
+       mul_x1_126, mul_x1_127, mul_x1_128, mul_x1_129, mul_x1_130, mul_x1_131,
+       mul_x1_132, mul_x1_133, mul_x1_134, mul_x1_135, mul_x1_136, mul_x1_137,
+       mul_x1_138, mul_x1_139, mul_x1_140, mul_x1_141, mul_x1_142, mul_x1_143,
+       mul_x1_144, mul_x1_145, mul_x1_146, mul_x1_147, mul_x1_148, mul_x1_149,
+       mul_x1_150, mul_x1_151, mul_x1_152, mul_x1_153, mul_x1_154, mul_x1_155,
+       mul_x1_156, mul_x1_157, mul_x1_158, mul_x1_159, mul_x1_160, mul_x1_161,
+       mul_x1_162, mul_x1_163, mul_x1_164, mul_x1_165, mul_x1_166, mul_x1_167,
+       mul_x1_168, mul_x1_169, mul_x1_170, mul_x1_171, mul_x1_172, mul_x1_173,
+       mul_x1_174, mul_x1_175, mul_x1_176, mul_x1_177, mul_x1_178, mul_x1_179,
+       mul_x1_180, mul_x1_181, mul_x1_182, mul_x1_183, mul_x1_184, mul_x1_185,
+       mul_x1_186, mul_x1_187, mul_x1_188, mul_x1_189, mul_x1_190, mul_x1_191,
+       mul_x1_192, mul_x1_193, mul_x1_194, mul_x1_195, mul_x1_196, mul_x1_197,
+       mul_x1_198, mul_x1_199, mul_x1_200, mul_x1_201, mul_x1_202, mul_x1_203,
+       mul_x1_204, mul_x1_205, mul_x1_206, mul_x1_207, mul_x1_208, mul_x1_209,
+       mul_x1_210, mul_x1_211, mul_x1_212, mul_x1_213, mul_x1_214, mul_x1_215,
+       mul_x1_216, mul_x1_217, mul_x1_218, mul_x1_219, mul_x1_220, mul_x1_221,
+       mul_x1_222, mul_x1_223, mul_x1_224, mul_x1_225, mul_x1_226, mul_x1_227,
+       mul_x1_228, mul_x1_229, mul_x1_230, mul_x1_231, mul_x1_232, mul_x1_233,
+       mul_x1_234, mul_x1_235, mul_x1_236, mul_x1_237, mul_x1_238, mul_x1_239,
+       mul_x1_240, mul_x1_241, mul_x1_242, mul_x1_243, mul_x1_244, mul_x1_245,
+       mul_x1_246, mul_x1_247, mul_x1_248, mul_x1_249, mul_x1_250, mul_x1_251,
+       mul_x1_252, mul_x1_253, mul_x1_254, mul_x1_255
+};
+
+static const mul_fn_ptr_t __attribute__((aligned(256)))
+gf_x2_mul_fns[256] = {
+       mul_x2_0, mul_x2_1, mul_x2_2, mul_x2_3, mul_x2_4, mul_x2_5,
+       mul_x2_6, mul_x2_7, mul_x2_8, mul_x2_9, mul_x2_10, mul_x2_11,
+       mul_x2_12, mul_x2_13, mul_x2_14, mul_x2_15, mul_x2_16, mul_x2_17,
+       mul_x2_18, mul_x2_19, mul_x2_20, mul_x2_21, mul_x2_22, mul_x2_23,
+       mul_x2_24, mul_x2_25, mul_x2_26, mul_x2_27, mul_x2_28, mul_x2_29,
+       mul_x2_30, mul_x2_31, mul_x2_32, mul_x2_33, mul_x2_34, mul_x2_35,
+       mul_x2_36, mul_x2_37, mul_x2_38, mul_x2_39, mul_x2_40, mul_x2_41,
+       mul_x2_42, mul_x2_43, mul_x2_44, mul_x2_45, mul_x2_46, mul_x2_47,
+       mul_x2_48, mul_x2_49, mul_x2_50, mul_x2_51, mul_x2_52, mul_x2_53,
+       mul_x2_54, mul_x2_55, mul_x2_56, mul_x2_57, mul_x2_58, mul_x2_59,
+       mul_x2_60, mul_x2_61, mul_x2_62, mul_x2_63, mul_x2_64, mul_x2_65,
+       mul_x2_66, mul_x2_67, mul_x2_68, mul_x2_69, mul_x2_70, mul_x2_71,
+       mul_x2_72, mul_x2_73, mul_x2_74, mul_x2_75, mul_x2_76, mul_x2_77,
+       mul_x2_78, mul_x2_79, mul_x2_80, mul_x2_81, mul_x2_82, mul_x2_83,
+       mul_x2_84, mul_x2_85, mul_x2_86, mul_x2_87, mul_x2_88, mul_x2_89,
+       mul_x2_90, mul_x2_91, mul_x2_92, mul_x2_93, mul_x2_94, mul_x2_95,
+       mul_x2_96, mul_x2_97, mul_x2_98, mul_x2_99, mul_x2_100, mul_x2_101,
+       mul_x2_102, mul_x2_103, mul_x2_104, mul_x2_105, mul_x2_106, mul_x2_107,
+       mul_x2_108, mul_x2_109, mul_x2_110, mul_x2_111, mul_x2_112, mul_x2_113,
+       mul_x2_114, mul_x2_115, mul_x2_116, mul_x2_117, mul_x2_118, mul_x2_119,
+       mul_x2_120, mul_x2_121, mul_x2_122, mul_x2_123, mul_x2_124, mul_x2_125,
+       mul_x2_126, mul_x2_127, mul_x2_128, mul_x2_129, mul_x2_130, mul_x2_131,
+       mul_x2_132, mul_x2_133, mul_x2_134, mul_x2_135, mul_x2_136, mul_x2_137,
+       mul_x2_138, mul_x2_139, mul_x2_140, mul_x2_141, mul_x2_142, mul_x2_143,
+       mul_x2_144, mul_x2_145, mul_x2_146, mul_x2_147, mul_x2_148, mul_x2_149,
+       mul_x2_150, mul_x2_151, mul_x2_152, mul_x2_153, mul_x2_154, mul_x2_155,
+       mul_x2_156, mul_x2_157, mul_x2_158, mul_x2_159, mul_x2_160, mul_x2_161,
+       mul_x2_162, mul_x2_163, mul_x2_164, mul_x2_165, mul_x2_166, mul_x2_167,
+       mul_x2_168, mul_x2_169, mul_x2_170, mul_x2_171, mul_x2_172, mul_x2_173,
+       mul_x2_174, mul_x2_175, mul_x2_176, mul_x2_177, mul_x2_178, mul_x2_179,
+       mul_x2_180, mul_x2_181, mul_x2_182, mul_x2_183, mul_x2_184, mul_x2_185,
+       mul_x2_186, mul_x2_187, mul_x2_188, mul_x2_189, mul_x2_190, mul_x2_191,
+       mul_x2_192, mul_x2_193, mul_x2_194, mul_x2_195, mul_x2_196, mul_x2_197,
+       mul_x2_198, mul_x2_199, mul_x2_200, mul_x2_201, mul_x2_202, mul_x2_203,
+       mul_x2_204, mul_x2_205, mul_x2_206, mul_x2_207, mul_x2_208, mul_x2_209,
+       mul_x2_210, mul_x2_211, mul_x2_212, mul_x2_213, mul_x2_214, mul_x2_215,
+       mul_x2_216, mul_x2_217, mul_x2_218, mul_x2_219, mul_x2_220, mul_x2_221,
+       mul_x2_222, mul_x2_223, mul_x2_224, mul_x2_225, mul_x2_226, mul_x2_227,
+       mul_x2_228, mul_x2_229, mul_x2_230, mul_x2_231, mul_x2_232, mul_x2_233,
+       mul_x2_234, mul_x2_235, mul_x2_236, mul_x2_237, mul_x2_238, mul_x2_239,
+       mul_x2_240, mul_x2_241, mul_x2_242, mul_x2_243, mul_x2_244, mul_x2_245,
+       mul_x2_246, mul_x2_247, mul_x2_248, mul_x2_249, mul_x2_250, mul_x2_251,
+       mul_x2_252, mul_x2_253, mul_x2_254, mul_x2_255
+};
+
+#define        MUL(c, r...)                                                    \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 2:                                                         \
+               COPY(r, _mul_x2_in);                                    \
+               gf_x2_mul_fns[c]();                                     \
+               COPY(_mul_x2_acc, r);                                   \
+               break;                                                  \
+       case 1:                                                         \
+               COPY(r, _mul_x1_in);                                    \
+               gf_x1_mul_fns[c]();                                     \
+               COPY(_mul_x1_acc, r);                                   \
+               break;                                                  \
+       }                                                               \
+}
+
+
+#define        raidz_math_begin()      kfpu_begin()
+#define        raidz_math_end()        kfpu_end()
+
+#define        GEN_P_DEFINE()          {}
+#define        GEN_P_STRIDE            4
+#define        GEN_P_P                 0, 1, 2, 3
+
+#define        GEN_PQ_DEFINE()         {}
+#define        GEN_PQ_STRIDE           2
+#define        GEN_PQ_D                0, 1
+#define        GEN_PQ_P                2, 3
+#define        GEN_PQ_Q                4, 5
+
+#define        GEN_PQR_DEFINE()        {}
+#define        GEN_PQR_STRIDE          2
+#define        GEN_PQR_D               0, 1
+#define        GEN_PQR_P               2, 3
+#define        GEN_PQR_Q               4, 5
+#define        GEN_PQR_R               6, 7
+
+#define        REC_P_DEFINE()          {}
+#define        REC_P_STRIDE            4
+#define        REC_P_X                 0, 1, 2, 3
+
+#define        REC_Q_DEFINE()          {}
+#define        REC_Q_STRIDE            2
+#define        REC_Q_X                 0, 1
+
+#define        REC_R_DEFINE()          {}
+#define        REC_R_STRIDE            2
+#define        REC_R_X                 0, 1
+
+#define        REC_PQ_DEFINE()         {}
+#define        REC_PQ_STRIDE           2
+#define        REC_PQ_X                0, 1
+#define        REC_PQ_Y                2, 3
+#define        REC_PQ_D                4, 5
+
+#define        REC_PR_DEFINE()         {}
+#define        REC_PR_STRIDE           2
+#define        REC_PR_X                0, 1
+#define        REC_PR_Y                2, 3
+#define        REC_PR_D                4, 5
+
+#define        REC_QR_DEFINE()         {}
+#define        REC_QR_STRIDE           2
+#define        REC_QR_X                0, 1
+#define        REC_QR_Y                2, 3
+#define        REC_QR_D                4, 5
+
+#define        REC_PQR_DEFINE()        {}
+#define        REC_PQR_STRIDE          1
+#define        REC_PQR_X               0
+#define        REC_PQR_Y               1
+#define        REC_PQR_Z               2
+#define        REC_PQR_D               3
+#define        REC_PQR_XS              4
+#define        REC_PQR_YS              5
+
+
+#include <sys/vdev_raidz_impl.h>
+#include "vdev_raidz_math_impl.h"
+
+DEFINE_GEN_METHODS(sse2);
+DEFINE_REC_METHODS(sse2);
+
+static boolean_t
+raidz_will_sse2_work(void)
+{
+       return (zfs_sse_available() && zfs_sse2_available());
+}
+
+const raidz_impl_ops_t vdev_raidz_sse2_impl = {
+       .init = NULL,
+       .fini = NULL,
+       .gen = RAIDZ_GEN_METHODS(sse2),
+       .rec = RAIDZ_REC_METHODS(sse2),
+       .is_supported = &raidz_will_sse2_work,
+       .name = "sse2"
+};
+
+#endif /* defined(__x86_64) && defined(HAVE_SSE2) */
diff --git a/zfs/module/zfs/vdev_raidz_math_ssse3.c b/zfs/module/zfs/vdev_raidz_math_ssse3.c
new file mode 100644 (file)
index 0000000..d934413
--- /dev/null
@@ -0,0 +1,2476 @@
+/*
+ * 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 (C) 2016 Gvozden Nešković. All rights reserved.
+ */
+
+#include <sys/isa_defs.h>
+
+#if defined(__x86_64) && defined(HAVE_SSSE3)
+
+#include <sys/types.h>
+#include <linux/simd_x86.h>
+
+#define        __asm __asm__ __volatile__
+
+#define        _REG_CNT(_0, _1, _2, _3, _4, _5, _6, _7, N, ...) N
+#define        REG_CNT(r...) _REG_CNT(r, 8, 7, 6, 5, 4, 3, 2, 1)
+
+#define        VR0_(REG, ...) "xmm"#REG
+#define        VR1_(_1, REG, ...) "xmm"#REG
+#define        VR2_(_1, _2, REG, ...) "xmm"#REG
+#define        VR3_(_1, _2, _3, REG, ...) "xmm"#REG
+#define        VR4_(_1, _2, _3, _4, REG, ...) "xmm"#REG
+#define        VR5_(_1, _2, _3, _4, _5, REG, ...) "xmm"#REG
+#define        VR6_(_1, _2, _3, _4, _5, _6, REG, ...) "xmm"#REG
+#define        VR7_(_1, _2, _3, _4, _5, _6, _7, REG, ...) "xmm"#REG
+
+#define        VR0(r...) VR0_(r)
+#define        VR1(r...) VR1_(r)
+#define        VR2(r...) VR2_(r, 1)
+#define        VR3(r...) VR3_(r, 1, 2)
+#define        VR4(r...) VR4_(r, 1, 2)
+#define        VR5(r...) VR5_(r, 1, 2, 3)
+#define        VR6(r...) VR6_(r, 1, 2, 3, 4)
+#define        VR7(r...) VR7_(r, 1, 2, 3, 4, 5)
+
+#define        R_01(REG1, REG2, ...) REG1, REG2
+#define        _R_23(_0, _1, REG2, REG3, ...) REG2, REG3
+#define        R_23(REG...) _R_23(REG, 1, 2, 3)
+
+#define        ASM_BUG()       ASSERT(0)
+
+const uint8_t gf_clmul_mod_lt[4*256][16];
+
+#define        ELEM_SIZE 16
+
+typedef struct v {
+       uint8_t b[ELEM_SIZE] __attribute__((aligned(ELEM_SIZE)));
+} v_t;
+
+#define        PREFETCHNTA(ptr, offset)                                        \
+{                                                                      \
+       __asm(                                                          \
+           "prefetchnta " #offset "(%[MEM])\n"                         \
+           : : [MEM] "r" (ptr));                                       \
+}
+
+#define        PREFETCH(ptr, offset)                                           \
+{                                                                      \
+       __asm(                                                          \
+           "prefetcht0 " #offset "(%[MEM])\n"                          \
+           : : [MEM] "r" (ptr));                                       \
+}
+
+#define        XOR_ACC(src, r...)                                              \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "pxor 0x00(%[SRC]), %%" VR0(r) "\n"                 \
+                   "pxor 0x10(%[SRC]), %%" VR1(r) "\n"                 \
+                   "pxor 0x20(%[SRC]), %%" VR2(r) "\n"                 \
+                   "pxor 0x30(%[SRC]), %%" VR3(r) "\n"                 \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "pxor 0x00(%[SRC]), %%" VR0(r) "\n"                 \
+                   "pxor 0x10(%[SRC]), %%" VR1(r) "\n"                 \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        XOR(r...)                                                       \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR4(r) "\n"                   \
+                   "pxor %" VR1(r) ", %" VR5(r) "\n"                   \
+                   "pxor %" VR2(r) ", %" VR6(r) "\n"                   \
+                   "pxor %" VR3(r) ", %" VR7(r));                      \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR2(r) "\n"                   \
+                   "pxor %" VR1(r) ", %" VR3(r));                      \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        ZERO(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR0(r) "\n"                   \
+                   "pxor %" VR1(r) ", %" VR1(r) "\n"                   \
+                   "pxor %" VR2(r) ", %" VR2(r) "\n"                   \
+                   "pxor %" VR3(r) ", %" VR3(r));                      \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "pxor %" VR0(r) ", %" VR0(r) "\n"                   \
+                   "pxor %" VR1(r) ", %" VR1(r));                      \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        COPY(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 8:                                                         \
+               __asm(                                                  \
+                   "movdqa %" VR0(r) ", %" VR4(r) "\n"                 \
+                   "movdqa %" VR1(r) ", %" VR5(r) "\n"                 \
+                   "movdqa %" VR2(r) ", %" VR6(r) "\n"                 \
+                   "movdqa %" VR3(r) ", %" VR7(r));                    \
+               break;                                                  \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "movdqa %" VR0(r) ", %" VR2(r) "\n"                 \
+                   "movdqa %" VR1(r) ", %" VR3(r));                    \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        LOAD(src, r...)                                                 \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "movdqa 0x00(%[SRC]), %%" VR0(r) "\n"               \
+                   "movdqa 0x10(%[SRC]), %%" VR1(r) "\n"               \
+                   "movdqa 0x20(%[SRC]), %%" VR2(r) "\n"               \
+                   "movdqa 0x30(%[SRC]), %%" VR3(r) "\n"               \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "movdqa 0x00(%[SRC]), %%" VR0(r) "\n"               \
+                   "movdqa 0x10(%[SRC]), %%" VR1(r) "\n"               \
+                   : : [SRC] "r" (src));                               \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        STORE(dst, r...)                                                \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               __asm(                                                  \
+                   "movdqa %%" VR0(r)", 0x00(%[DST])\n"                \
+                   "movdqa %%" VR1(r)", 0x10(%[DST])\n"                \
+                   "movdqa %%" VR2(r)", 0x20(%[DST])\n"                \
+                   "movdqa %%" VR3(r)", 0x30(%[DST])\n"                \
+                   : : [DST] "r" (dst));                               \
+               break;                                                  \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "movdqa %%" VR0(r)", 0x00(%[DST])\n"                \
+                   "movdqa %%" VR1(r)", 0x10(%[DST])\n"                \
+                   : : [DST] "r" (dst));                               \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL2_SETUP()                                                    \
+{                                                                      \
+       __asm(                                                          \
+           "movd %[mask], %%xmm15\n"                                   \
+           "pshufd $0x0, %%xmm15, %%xmm15\n"                           \
+           : : [mask] "r" (0x1d1d1d1d));                               \
+}
+
+#define        _MUL2_x2(r...)                                                  \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 2:                                                         \
+               __asm(                                                  \
+                   "pxor    %xmm14,      %xmm14\n"                     \
+                   "pxor    %xmm13,      %xmm13\n"                     \
+                   "pcmpgtb %" VR0(r)",  %xmm14\n"                     \
+                   "pcmpgtb %" VR1(r)",  %xmm13\n"                     \
+                   "pand    %xmm15,      %xmm14\n"                     \
+                   "pand    %xmm15,      %xmm13\n"                     \
+                   "paddb   %" VR0(r)",  %" VR0(r) "\n"                \
+                   "paddb   %" VR1(r)",  %" VR1(r) "\n"                \
+                   "pxor    %xmm14,      %" VR0(r) "\n"                \
+                   "pxor    %xmm13,      %" VR1(r));                   \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL2(r...)                                                      \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               _MUL2_x2(R_01(r));                                      \
+               _MUL2_x2(R_23(r));                                      \
+               break;                                                  \
+       case 2:                                                         \
+               _MUL2_x2(r);                                            \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL4(r...)                                                      \
+{                                                                      \
+       MUL2(r);                                                        \
+       MUL2(r);                                                        \
+}
+
+#define        _0f             "xmm15"
+#define        _a_save         "xmm14"
+#define        _b_save         "xmm13"
+#define        _lt_mod_a       "xmm12"
+#define        _lt_clmul_a     "xmm11"
+#define        _lt_mod_b       "xmm10"
+#define        _lt_clmul_b     "xmm15"
+
+#define        _MULx2(c, r...)                                                 \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 2:                                                         \
+               __asm(                                                  \
+                   /* lts for upper part */                            \
+                   "movd %[mask], %%" _0f "\n"                         \
+                   "pshufd $0x0, %%" _0f ", %%" _0f "\n"               \
+                   "movdqa 0x00(%[lt]), %%" _lt_mod_a "\n"             \
+                   "movdqa 0x10(%[lt]), %%" _lt_clmul_a "\n"           \
+                   /* upper part */                                    \
+                   "movdqa %%" VR0(r) ", %%" _a_save "\n"              \
+                   "movdqa %%" VR1(r) ", %%" _b_save "\n"              \
+                   "psraw $0x4, %%" VR0(r) "\n"                        \
+                   "psraw $0x4, %%" VR1(r) "\n"                        \
+                   "pand %%" _0f ", %%" _a_save "\n"                   \
+                   "pand %%" _0f ", %%" _b_save "\n"                   \
+                   "pand %%" _0f ", %%" VR0(r) "\n"                    \
+                   "pand %%" _0f ", %%" VR1(r) "\n"                    \
+                                                                       \
+                   "movdqa %%" _lt_mod_a ", %%" _lt_mod_b "\n"         \
+                   "movdqa %%" _lt_clmul_a ", %%" _lt_clmul_b "\n"     \
+                                                                       \
+                   "pshufb %%" VR0(r) ",%%" _lt_mod_a "\n"             \
+                   "pshufb %%" VR1(r) ",%%" _lt_mod_b "\n"             \
+                   "pshufb %%" VR0(r) ",%%" _lt_clmul_a "\n"           \
+                   "pshufb %%" VR1(r) ",%%" _lt_clmul_b "\n"           \
+                                                                       \
+                   "pxor %%" _lt_mod_a ",%%" _lt_clmul_a "\n"          \
+                   "pxor %%" _lt_mod_b ",%%" _lt_clmul_b "\n"          \
+                   "movdqa %%" _lt_clmul_a ",%%" VR0(r) "\n"           \
+                   "movdqa %%" _lt_clmul_b ",%%" VR1(r) "\n"           \
+                   /* lts for lower part */                            \
+                   "movdqa 0x20(%[lt]), %%" _lt_mod_a "\n"             \
+                   "movdqa 0x30(%[lt]), %%" _lt_clmul_a "\n"           \
+                   "movdqa %%" _lt_mod_a ", %%" _lt_mod_b "\n"         \
+                   "movdqa %%" _lt_clmul_a ", %%" _lt_clmul_b "\n"     \
+                   /* lower part */                                    \
+                   "pshufb %%" _a_save ",%%" _lt_mod_a "\n"            \
+                   "pshufb %%" _b_save ",%%" _lt_mod_b "\n"            \
+                   "pshufb %%" _a_save ",%%" _lt_clmul_a "\n"          \
+                   "pshufb %%" _b_save ",%%" _lt_clmul_b "\n"          \
+                                                                       \
+                   "pxor %%" _lt_mod_a ",%%" VR0(r) "\n"               \
+                   "pxor %%" _lt_mod_b ",%%" VR1(r) "\n"               \
+                   "pxor %%" _lt_clmul_a ",%%" VR0(r) "\n"             \
+                   "pxor %%" _lt_clmul_b ",%%" VR1(r) "\n"             \
+                   : : [mask] "r" (0x0f0f0f0f),                        \
+                   [lt] "r" (gf_clmul_mod_lt[4*(c)]));                 \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        MUL(c, r...)                                                    \
+{                                                                      \
+       switch (REG_CNT(r)) {                                           \
+       case 4:                                                         \
+               _MULx2(c, R_23(r));                                     \
+               _MULx2(c, R_01(r));                                     \
+               break;                                                  \
+       case 2:                                                         \
+               _MULx2(c, R_01(r));                                     \
+               break;                                                  \
+       default:                                                        \
+               ASM_BUG();                                              \
+       }                                                               \
+}
+
+#define        raidz_math_begin()      kfpu_begin()
+#define        raidz_math_end()        kfpu_end()
+
+#define        GEN_P_DEFINE()          {}
+#define        GEN_P_STRIDE            4
+#define        GEN_P_P                 0, 1, 2, 3
+
+#define        GEN_PQ_DEFINE()         {}
+#define        GEN_PQ_STRIDE           4
+#define        GEN_PQ_D                0, 1, 2, 3
+#define        GEN_PQ_P                4, 5, 6, 7
+#define        GEN_PQ_Q                8, 9, 10, 11
+
+#define        GEN_PQR_DEFINE()        {}
+#define        GEN_PQR_STRIDE          2
+#define        GEN_PQR_D               0, 1
+#define        GEN_PQR_P               2, 3
+#define        GEN_PQR_Q               4, 5
+#define        GEN_PQR_R               6, 7
+
+#define        REC_P_DEFINE()          {}
+#define        REC_P_STRIDE            4
+#define        REC_P_X                 0, 1, 2, 3
+
+#define        REC_Q_DEFINE()          {}
+#define        REC_Q_STRIDE            4
+#define        REC_Q_X                 0, 1, 2, 3
+
+#define        REC_R_DEFINE()          {}
+#define        REC_R_STRIDE            4
+#define        REC_R_X                 0, 1, 2, 3
+
+#define        REC_PQ_DEFINE()         {}
+#define        REC_PQ_STRIDE           2
+#define        REC_PQ_X                0, 1
+#define        REC_PQ_Y                2, 3
+#define        REC_PQ_D                4, 5
+
+#define        REC_PR_DEFINE()         {}
+#define        REC_PR_STRIDE           2
+#define        REC_PR_X                0, 1
+#define        REC_PR_Y                2, 3
+#define        REC_PR_D                4, 5
+
+#define        REC_QR_DEFINE()         {}
+#define        REC_QR_STRIDE           2
+#define        REC_QR_X                0, 1
+#define        REC_QR_Y                2, 3
+#define        REC_QR_D                4, 5
+
+#define        REC_PQR_DEFINE()        {}
+#define        REC_PQR_STRIDE          2
+#define        REC_PQR_X               0, 1
+#define        REC_PQR_Y               2, 3
+#define        REC_PQR_Z               4, 5
+#define        REC_PQR_D               6, 7
+#define        REC_PQR_XS              6, 7
+#define        REC_PQR_YS              8, 9
+
+
+#include <sys/vdev_raidz_impl.h>
+#include "vdev_raidz_math_impl.h"
+
+DEFINE_GEN_METHODS(ssse3);
+DEFINE_REC_METHODS(ssse3);
+
+static boolean_t
+raidz_will_ssse3_work(void)
+{
+       return (zfs_sse_available() && zfs_sse2_available() &&
+           zfs_ssse3_available());
+}
+
+const raidz_impl_ops_t vdev_raidz_ssse3_impl = {
+       .init = NULL,
+       .fini = NULL,
+       .gen = RAIDZ_GEN_METHODS(ssse3),
+       .rec = RAIDZ_REC_METHODS(ssse3),
+       .is_supported = &raidz_will_ssse3_work,
+       .name = "ssse3"
+};
+
+#endif /* defined(__x86_64) && defined(HAVE_SSSE3) */
+
+
+#if defined(__x86_64) && (defined(HAVE_SSSE3) || defined(HAVE_AVX2))
+
+const uint8_t
+__attribute__((aligned(256))) gf_clmul_mod_lt[4*256][16] = {
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+           0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09,
+           0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
+           0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x11, 0x1e, 0x1b,
+           0x28, 0x2d, 0x22, 0x27, 0x3c, 0x39, 0x36, 0x33  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x06, 0x0c, 0x0a, 0x18, 0x1e, 0x14, 0x12,
+           0x30, 0x36, 0x3c, 0x3a, 0x28, 0x2e, 0x24, 0x22  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
+           0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38,
+           0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+           0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0a, 0x14, 0x1e, 0x28, 0x22, 0x3c, 0x36,
+           0x50, 0x5a, 0x44, 0x4e, 0x78, 0x72, 0x6c, 0x66  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31,
+           0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0c, 0x18, 0x14, 0x30, 0x3c, 0x28, 0x24,
+           0x60, 0x6c, 0x78, 0x74, 0x50, 0x5c, 0x48, 0x44  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23,
+           0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a,
+           0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x0f, 0x1e, 0x11, 0x3c, 0x33, 0x22, 0x2d,
+           0x78, 0x77, 0x66, 0x69, 0x44, 0x4b, 0x5a, 0x55  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+           0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xf5, 0xe8, 0xcf, 0xd2, 0x81, 0x9c, 0xbb, 0xa6  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e,
+           0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xf5, 0xe8, 0xcf, 0xd2, 0x81, 0x9c, 0xbb, 0xa6  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x13, 0x26, 0x35, 0x4c, 0x5f, 0x6a, 0x79,
+           0x98, 0x8b, 0xbe, 0xad, 0xd4, 0xc7, 0xf2, 0xe1  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x69, 0x74, 0x53, 0x4e,
+           0xd2, 0xcf, 0xe8, 0xf5, 0xbb, 0xa6, 0x81, 0x9c  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x14, 0x28, 0x3c, 0x50, 0x44, 0x78, 0x6c,
+           0xa0, 0xb4, 0x88, 0x9c, 0xf0, 0xe4, 0xd8, 0xcc  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x69, 0x74, 0x53, 0x4e,
+           0xd2, 0xcf, 0xe8, 0xf5, 0xbb, 0xa6, 0x81, 0x9c  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x15, 0x2a, 0x3f, 0x54, 0x41, 0x7e, 0x6b,
+           0xa8, 0xbd, 0x82, 0x97, 0xfc, 0xe9, 0xd6, 0xc3  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x69, 0x74, 0x53, 0x4e,
+           0xcf, 0xd2, 0xf5, 0xe8, 0xa6, 0xbb, 0x9c, 0x81  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x16, 0x2c, 0x3a, 0x58, 0x4e, 0x74, 0x62,
+           0xb0, 0xa6, 0x9c, 0x8a, 0xe8, 0xfe, 0xc4, 0xd2  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x69, 0x74, 0x53, 0x4e,
+           0xcf, 0xd2, 0xf5, 0xe8, 0xa6, 0xbb, 0x9c, 0x81  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x17, 0x2e, 0x39, 0x5c, 0x4b, 0x72, 0x65,
+           0xb8, 0xaf, 0x96, 0x81, 0xe4, 0xf3, 0xca, 0xdd  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x4e, 0x53, 0x69, 0x74,
+           0x9c, 0x81, 0xbb, 0xa6, 0xd2, 0xcf, 0xf5, 0xe8  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x18, 0x30, 0x28, 0x60, 0x78, 0x50, 0x48,
+           0xc0, 0xd8, 0xf0, 0xe8, 0xa0, 0xb8, 0x90, 0x88  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x4e, 0x53, 0x69, 0x74,
+           0x9c, 0x81, 0xbb, 0xa6, 0xd2, 0xcf, 0xf5, 0xe8  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x19, 0x32, 0x2b, 0x64, 0x7d, 0x56, 0x4f,
+           0xc8, 0xd1, 0xfa, 0xe3, 0xac, 0xb5, 0x9e, 0x87  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x4e, 0x53, 0x69, 0x74,
+           0x81, 0x9c, 0xa6, 0xbb, 0xcf, 0xd2, 0xe8, 0xf5  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1a, 0x34, 0x2e, 0x68, 0x72, 0x5c, 0x46,
+           0xd0, 0xca, 0xe4, 0xfe, 0xb8, 0xa2, 0x8c, 0x96  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x4e, 0x53, 0x69, 0x74,
+           0x81, 0x9c, 0xa6, 0xbb, 0xcf, 0xd2, 0xe8, 0xf5  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1b, 0x36, 0x2d, 0x6c, 0x77, 0x5a, 0x41,
+           0xd8, 0xc3, 0xee, 0xf5, 0xb4, 0xaf, 0x82, 0x99  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x53, 0x4e, 0x74, 0x69,
+           0xa6, 0xbb, 0x81, 0x9c, 0xf5, 0xe8, 0xd2, 0xcf  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1c, 0x38, 0x24, 0x70, 0x6c, 0x48, 0x54,
+           0xe0, 0xfc, 0xd8, 0xc4, 0x90, 0x8c, 0xa8, 0xb4  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x53, 0x4e, 0x74, 0x69,
+           0xa6, 0xbb, 0x81, 0x9c, 0xf5, 0xe8, 0xd2, 0xcf  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1d, 0x3a, 0x27, 0x74, 0x69, 0x4e, 0x53,
+           0xe8, 0xf5, 0xd2, 0xcf, 0x9c, 0x81, 0xa6, 0xbb  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x53, 0x4e, 0x74, 0x69,
+           0xbb, 0xa6, 0x9c, 0x81, 0xe8, 0xf5, 0xcf, 0xd2  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1e, 0x3c, 0x22, 0x78, 0x66, 0x44, 0x5a,
+           0xf0, 0xee, 0xcc, 0xd2, 0x88, 0x96, 0xb4, 0xaa  },
+       { 0x00, 0x1d, 0x27, 0x3a, 0x53, 0x4e, 0x74, 0x69,
+           0xbb, 0xa6, 0x9c, 0x81, 0xe8, 0xf5, 0xcf, 0xd2  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x1f, 0x3e, 0x21, 0x7c, 0x63, 0x42, 0x5d,
+           0xf8, 0xe7, 0xc6, 0xd9, 0x84, 0x9b, 0xba, 0xa5  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xcd, 0xf7, 0xb9, 0x83, 0x25, 0x1f, 0x51, 0x6b  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xcd, 0xf7, 0xb9, 0x83, 0x25, 0x1f, 0x51, 0x6b  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x21, 0x42, 0x63, 0x84, 0xa5, 0xc6, 0xe7,
+           0x08, 0x29, 0x4a, 0x6b, 0x8c, 0xad, 0xce, 0xef  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xd0, 0xea, 0xa4, 0x9e, 0x38, 0x02, 0x4c, 0x76  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x22, 0x44, 0x66, 0x88, 0xaa, 0xcc, 0xee,
+           0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xd0, 0xea, 0xa4, 0x9e, 0x38, 0x02, 0x4c, 0x76  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x23, 0x46, 0x65, 0x8c, 0xaf, 0xca, 0xe9,
+           0x18, 0x3b, 0x5e, 0x7d, 0x94, 0xb7, 0xd2, 0xf1  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xf5, 0xcf, 0x81, 0xbb,
+           0xf7, 0xcd, 0x83, 0xb9, 0x02, 0x38, 0x76, 0x4c  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x24, 0x48, 0x6c, 0x90, 0xb4, 0xd8, 0xfc,
+           0x20, 0x04, 0x68, 0x4c, 0xb0, 0x94, 0xf8, 0xdc  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xf5, 0xcf, 0x81, 0xbb,
+           0xf7, 0xcd, 0x83, 0xb9, 0x02, 0x38, 0x76, 0x4c  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x25, 0x4a, 0x6f, 0x94, 0xb1, 0xde, 0xfb,
+           0x28, 0x0d, 0x62, 0x47, 0xbc, 0x99, 0xf6, 0xd3  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xf5, 0xcf, 0x81, 0xbb,
+           0xea, 0xd0, 0x9e, 0xa4, 0x1f, 0x25, 0x6b, 0x51  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x26, 0x4c, 0x6a, 0x98, 0xbe, 0xd4, 0xf2,
+           0x30, 0x16, 0x7c, 0x5a, 0xa8, 0x8e, 0xe4, 0xc2  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xf5, 0xcf, 0x81, 0xbb,
+           0xea, 0xd0, 0x9e, 0xa4, 0x1f, 0x25, 0x6b, 0x51  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x38, 0x1f, 0x76, 0x51, 0xa4, 0x83, 0xea, 0xcd  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xd2, 0xe8, 0xbb, 0x81,
+           0xb9, 0x83, 0xd0, 0xea, 0x6b, 0x51, 0x02, 0x38  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x28, 0x50, 0x78, 0xa0, 0x88, 0xf0, 0xd8,
+           0x40, 0x68, 0x10, 0x38, 0xe0, 0xc8, 0xb0, 0x98  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xd2, 0xe8, 0xbb, 0x81,
+           0xb9, 0x83, 0xd0, 0xea, 0x6b, 0x51, 0x02, 0x38  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x29, 0x52, 0x7b, 0xa4, 0x8d, 0xf6, 0xdf,
+           0x48, 0x61, 0x1a, 0x33, 0xec, 0xc5, 0xbe, 0x97  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xd2, 0xe8, 0xbb, 0x81,
+           0xa4, 0x9e, 0xcd, 0xf7, 0x76, 0x4c, 0x1f, 0x25  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2a, 0x54, 0x7e, 0xa8, 0x82, 0xfc, 0xd6,
+           0x50, 0x7a, 0x04, 0x2e, 0xf8, 0xd2, 0xac, 0x86  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xd2, 0xe8, 0xbb, 0x81,
+           0xa4, 0x9e, 0xcd, 0xf7, 0x76, 0x4c, 0x1f, 0x25  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2b, 0x56, 0x7d, 0xac, 0x87, 0xfa, 0xd1,
+           0x58, 0x73, 0x0e, 0x25, 0xf4, 0xdf, 0xa2, 0x89  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xcf, 0xf5, 0xa6, 0x9c,
+           0x83, 0xb9, 0xea, 0xd0, 0x4c, 0x76, 0x25, 0x1f  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2c, 0x58, 0x74, 0xb0, 0x9c, 0xe8, 0xc4,
+           0x60, 0x4c, 0x38, 0x14, 0xd0, 0xfc, 0x88, 0xa4  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xcf, 0xf5, 0xa6, 0x9c,
+           0x83, 0xb9, 0xea, 0xd0, 0x4c, 0x76, 0x25, 0x1f  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2d, 0x5a, 0x77, 0xb4, 0x99, 0xee, 0xc3,
+           0x68, 0x45, 0x32, 0x1f, 0xdc, 0xf1, 0x86, 0xab  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xcf, 0xf5, 0xa6, 0x9c,
+           0x9e, 0xa4, 0xf7, 0xcd, 0x51, 0x6b, 0x38, 0x02  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2e, 0x5c, 0x72, 0xb8, 0x96, 0xe4, 0xca,
+           0x70, 0x5e, 0x2c, 0x02, 0xc8, 0xe6, 0x94, 0xba  },
+       { 0x00, 0x3a, 0x69, 0x53, 0xcf, 0xf5, 0xa6, 0x9c,
+           0x9e, 0xa4, 0xf7, 0xcd, 0x51, 0x6b, 0x38, 0x02  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x2f, 0x5e, 0x71, 0xbc, 0x93, 0xe2, 0xcd,
+           0x78, 0x57, 0x26, 0x09, 0xc4, 0xeb, 0x9a, 0xb5  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x25, 0x02, 0x6b, 0x4c, 0xb9, 0x9e, 0xf7, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x25, 0x02, 0x6b, 0x4c, 0xb9, 0x9e, 0xf7, 0xd0  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97,
+           0x88, 0xb9, 0xea, 0xdb, 0x4c, 0x7d, 0x2e, 0x1f  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x38, 0x1f, 0x76, 0x51, 0xa4, 0x83, 0xea, 0xcd  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x32, 0x64, 0x56, 0xc8, 0xfa, 0xac, 0x9e,
+           0x90, 0xa2, 0xf4, 0xc6, 0x58, 0x6a, 0x3c, 0x0e  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x9c, 0xbb, 0xd2, 0xf5,
+           0x38, 0x1f, 0x76, 0x51, 0xa4, 0x83, 0xea, 0xcd  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x33, 0x66, 0x55, 0xcc, 0xff, 0xaa, 0x99,
+           0x98, 0xab, 0xfe, 0xcd, 0x54, 0x67, 0x32, 0x01  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x81, 0xa6, 0xcf, 0xe8,
+           0x1f, 0x38, 0x51, 0x76, 0x9e, 0xb9, 0xd0, 0xf7  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x34, 0x68, 0x5c, 0xd0, 0xe4, 0xb8, 0x8c,
+           0xa0, 0x94, 0xc8, 0xfc, 0x70, 0x44, 0x18, 0x2c  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x81, 0xa6, 0xcf, 0xe8,
+           0x1f, 0x38, 0x51, 0x76, 0x9e, 0xb9, 0xd0, 0xf7  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x35, 0x6a, 0x5f, 0xd4, 0xe1, 0xbe, 0x8b,
+           0xa8, 0x9d, 0xc2, 0xf7, 0x7c, 0x49, 0x16, 0x23  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x81, 0xa6, 0xcf, 0xe8,
+           0x02, 0x25, 0x4c, 0x6b, 0x83, 0xa4, 0xcd, 0xea  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x36, 0x6c, 0x5a, 0xd8, 0xee, 0xb4, 0x82,
+           0xb0, 0x86, 0xdc, 0xea, 0x68, 0x5e, 0x04, 0x32  },
+       { 0x00, 0x27, 0x4e, 0x69, 0x81, 0xa6, 0xcf, 0xe8,
+           0x02, 0x25, 0x4c, 0x6b, 0x83, 0xa4, 0xcd, 0xea  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x37, 0x6e, 0x59, 0xdc, 0xeb, 0xb2, 0x85,
+           0xb8, 0x8f, 0xd6, 0xe1, 0x64, 0x53, 0x0a, 0x3d  },
+       { 0x00, 0x27, 0x53, 0x74, 0xa6, 0x81, 0xf5, 0xd2,
+           0x51, 0x76, 0x02, 0x25, 0xf7, 0xd0, 0xa4, 0x83  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x38, 0x70, 0x48, 0xe0, 0xd8, 0x90, 0xa8,
+           0xc0, 0xf8, 0xb0, 0x88, 0x20, 0x18, 0x50, 0x68  },
+       { 0x00, 0x27, 0x53, 0x74, 0xa6, 0x81, 0xf5, 0xd2,
+           0x51, 0x76, 0x02, 0x25, 0xf7, 0xd0, 0xa4, 0x83  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x39, 0x72, 0x4b, 0xe4, 0xdd, 0x96, 0xaf,
+           0xc8, 0xf1, 0xba, 0x83, 0x2c, 0x15, 0x5e, 0x67  },
+       { 0x00, 0x27, 0x53, 0x74, 0xa6, 0x81, 0xf5, 0xd2,
+           0x4c, 0x6b, 0x1f, 0x38, 0xea, 0xcd, 0xb9, 0x9e  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3a, 0x74, 0x4e, 0xe8, 0xd2, 0x9c, 0xa6,
+           0xd0, 0xea, 0xa4, 0x9e, 0x38, 0x02, 0x4c, 0x76  },
+       { 0x00, 0x27, 0x53, 0x74, 0xa6, 0x81, 0xf5, 0xd2,
+           0x4c, 0x6b, 0x1f, 0x38, 0xea, 0xcd, 0xb9, 0x9e  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3b, 0x76, 0x4d, 0xec, 0xd7, 0x9a, 0xa1,
+           0xd8, 0xe3, 0xae, 0x95, 0x34, 0x0f, 0x42, 0x79  },
+       { 0x00, 0x27, 0x53, 0x74, 0xbb, 0x9c, 0xe8, 0xcf,
+           0x6b, 0x4c, 0x38, 0x1f, 0xd0, 0xf7, 0x83, 0xa4  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3c, 0x78, 0x44, 0xf0, 0xcc, 0x88, 0xb4,
+           0xe0, 0xdc, 0x98, 0xa4, 0x10, 0x2c, 0x68, 0x54  },
+       { 0x00, 0x27, 0x53, 0x74, 0xbb, 0x9c, 0xe8, 0xcf,
+           0x6b, 0x4c, 0x38, 0x1f, 0xd0, 0xf7, 0x83, 0xa4  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3d, 0x7a, 0x47, 0xf4, 0xc9, 0x8e, 0xb3,
+           0xe8, 0xd5, 0x92, 0xaf, 0x1c, 0x21, 0x66, 0x5b  },
+       { 0x00, 0x27, 0x53, 0x74, 0xbb, 0x9c, 0xe8, 0xcf,
+           0x76, 0x51, 0x25, 0x02, 0xcd, 0xea, 0x9e, 0xb9  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3e, 0x7c, 0x42, 0xf8, 0xc6, 0x84, 0xba,
+           0xf0, 0xce, 0x8c, 0xb2, 0x08, 0x36, 0x74, 0x4a  },
+       { 0x00, 0x27, 0x53, 0x74, 0xbb, 0x9c, 0xe8, 0xcf,
+           0x76, 0x51, 0x25, 0x02, 0xcd, 0xea, 0x9e, 0xb9  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d  },
+       { 0x00, 0x3f, 0x7e, 0x41, 0xfc, 0xc3, 0x82, 0xbd,
+           0xf8, 0xc7, 0x86, 0xb9, 0x04, 0x3b, 0x7a, 0x45  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51,
+           0x87, 0xf3, 0x6f, 0x1b, 0x4a, 0x3e, 0xa2, 0xd6  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51,
+           0x87, 0xf3, 0x6f, 0x1b, 0x4a, 0x3e, 0xa2, 0xd6  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x41, 0x82, 0xc3, 0x04, 0x45, 0x86, 0xc7,
+           0x08, 0x49, 0x8a, 0xcb, 0x0c, 0x4d, 0x8e, 0xcf  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51,
+           0x9a, 0xee, 0x72, 0x06, 0x57, 0x23, 0xbf, 0xcb  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x42, 0x84, 0xc6, 0x08, 0x4a, 0x8c, 0xce,
+           0x10, 0x52, 0x94, 0xd6, 0x18, 0x5a, 0x9c, 0xde  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xcd, 0xb9, 0x25, 0x51,
+           0x9a, 0xee, 0x72, 0x06, 0x57, 0x23, 0xbf, 0xcb  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x43, 0x86, 0xc5, 0x0c, 0x4f, 0x8a, 0xc9,
+           0x18, 0x5b, 0x9e, 0xdd, 0x14, 0x57, 0x92, 0xd1  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xbd, 0xc9, 0x55, 0x21, 0x6d, 0x19, 0x85, 0xf1  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x44, 0x88, 0xcc, 0x10, 0x54, 0x98, 0xdc,
+           0x20, 0x64, 0xa8, 0xec, 0x30, 0x74, 0xb8, 0xfc  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xbd, 0xc9, 0x55, 0x21, 0x6d, 0x19, 0x85, 0xf1  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x45, 0x8a, 0xcf, 0x14, 0x51, 0x9e, 0xdb,
+           0x28, 0x6d, 0xa2, 0xe7, 0x3c, 0x79, 0xb6, 0xf3  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xa0, 0xd4, 0x48, 0x3c, 0x70, 0x04, 0x98, 0xec  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x46, 0x8c, 0xca, 0x18, 0x5e, 0x94, 0xd2,
+           0x30, 0x76, 0xbc, 0xfa, 0x28, 0x6e, 0xa4, 0xe2  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xa0, 0xd4, 0x48, 0x3c, 0x70, 0x04, 0x98, 0xec  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x47, 0x8e, 0xc9, 0x1c, 0x5b, 0x92, 0xd5,
+           0x38, 0x7f, 0xb6, 0xf1, 0x24, 0x63, 0xaa, 0xed  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xf7, 0x83, 0x02, 0x76,
+           0xf3, 0x87, 0x06, 0x72, 0x04, 0x70, 0xf1, 0x85  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x48, 0x90, 0xd8, 0x20, 0x68, 0xb0, 0xf8,
+           0x40, 0x08, 0xd0, 0x98, 0x60, 0x28, 0xf0, 0xb8  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xf7, 0x83, 0x02, 0x76,
+           0xf3, 0x87, 0x06, 0x72, 0x04, 0x70, 0xf1, 0x85  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x49, 0x92, 0xdb, 0x24, 0x6d, 0xb6, 0xff,
+           0x48, 0x01, 0xda, 0x93, 0x6c, 0x25, 0xfe, 0xb7  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xf7, 0x83, 0x02, 0x76,
+           0xee, 0x9a, 0x1b, 0x6f, 0x19, 0x6d, 0xec, 0x98  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4a, 0x94, 0xde, 0x28, 0x62, 0xbc, 0xf6,
+           0x50, 0x1a, 0xc4, 0x8e, 0x78, 0x32, 0xec, 0xa6  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xf7, 0x83, 0x02, 0x76,
+           0xee, 0x9a, 0x1b, 0x6f, 0x19, 0x6d, 0xec, 0x98  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4b, 0x96, 0xdd, 0x2c, 0x67, 0xba, 0xf1,
+           0x58, 0x13, 0xce, 0x85, 0x74, 0x3f, 0xe2, 0xa9  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xea, 0x9e, 0x1f, 0x6b,
+           0xc9, 0xbd, 0x3c, 0x48, 0x23, 0x57, 0xd6, 0xa2  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4c, 0x98, 0xd4, 0x30, 0x7c, 0xa8, 0xe4,
+           0x60, 0x2c, 0xf8, 0xb4, 0x50, 0x1c, 0xc8, 0x84  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xea, 0x9e, 0x1f, 0x6b,
+           0xc9, 0xbd, 0x3c, 0x48, 0x23, 0x57, 0xd6, 0xa2  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4d, 0x9a, 0xd7, 0x34, 0x79, 0xae, 0xe3,
+           0x68, 0x25, 0xf2, 0xbf, 0x5c, 0x11, 0xc6, 0x8b  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xea, 0x9e, 0x1f, 0x6b,
+           0xd4, 0xa0, 0x21, 0x55, 0x3e, 0x4a, 0xcb, 0xbf  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x70, 0x3e, 0xec, 0xa2, 0x48, 0x06, 0xd4, 0x9a  },
+       { 0x00, 0x74, 0xf5, 0x81, 0xea, 0x9e, 0x1f, 0x6b,
+           0xd4, 0xa0, 0x21, 0x55, 0x3e, 0x4a, 0xcb, 0xbf  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x4f, 0x9e, 0xd1, 0x3c, 0x73, 0xa2, 0xed,
+           0x78, 0x37, 0xe6, 0xa9, 0x44, 0x0b, 0xda, 0x95  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02,
+           0x6f, 0x06, 0xbd, 0xd4, 0xd6, 0xbf, 0x04, 0x6d  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02,
+           0x6f, 0x06, 0xbd, 0xd4, 0xd6, 0xbf, 0x04, 0x6d  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x51, 0xa2, 0xf3, 0x44, 0x15, 0xe6, 0xb7,
+           0x88, 0xd9, 0x2a, 0x7b, 0xcc, 0x9d, 0x6e, 0x3f  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02,
+           0x72, 0x1b, 0xa0, 0xc9, 0xcb, 0xa2, 0x19, 0x70  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x52, 0xa4, 0xf6, 0x48, 0x1a, 0xec, 0xbe,
+           0x90, 0xc2, 0x34, 0x66, 0xd8, 0x8a, 0x7c, 0x2e  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xb9, 0xd0, 0x6b, 0x02,
+           0x72, 0x1b, 0xa0, 0xc9, 0xcb, 0xa2, 0x19, 0x70  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x98, 0xcb, 0x3e, 0x6d, 0xd4, 0x87, 0x72, 0x21  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x55, 0x3c, 0x87, 0xee, 0xf1, 0x98, 0x23, 0x4a  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x54, 0xa8, 0xfc, 0x50, 0x04, 0xf8, 0xac,
+           0xa0, 0xf4, 0x08, 0x5c, 0xf0, 0xa4, 0x58, 0x0c  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x55, 0x3c, 0x87, 0xee, 0xf1, 0x98, 0x23, 0x4a  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x55, 0xaa, 0xff, 0x54, 0x01, 0xfe, 0xab,
+           0xa8, 0xfd, 0x02, 0x57, 0xfc, 0xa9, 0x56, 0x03  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x48, 0x21, 0x9a, 0xf3, 0xec, 0x85, 0x3e, 0x57  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x56, 0xac, 0xfa, 0x58, 0x0e, 0xf4, 0xa2,
+           0xb0, 0xe6, 0x1c, 0x4a, 0xe8, 0xbe, 0x44, 0x12  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x48, 0x21, 0x9a, 0xf3, 0xec, 0x85, 0x3e, 0x57  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x57, 0xae, 0xf9, 0x5c, 0x0b, 0xf2, 0xa5,
+           0xb8, 0xef, 0x16, 0x41, 0xe4, 0xb3, 0x4a, 0x1d  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x83, 0xea, 0x4c, 0x25,
+           0x1b, 0x72, 0xd4, 0xbd, 0x98, 0xf1, 0x57, 0x3e  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x58, 0xb0, 0xe8, 0x60, 0x38, 0xd0, 0x88,
+           0xc0, 0x98, 0x70, 0x28, 0xa0, 0xf8, 0x10, 0x48  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x83, 0xea, 0x4c, 0x25,
+           0x1b, 0x72, 0xd4, 0xbd, 0x98, 0xf1, 0x57, 0x3e  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x59, 0xb2, 0xeb, 0x64, 0x3d, 0xd6, 0x8f,
+           0xc8, 0x91, 0x7a, 0x23, 0xac, 0xf5, 0x1e, 0x47  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x83, 0xea, 0x4c, 0x25,
+           0x06, 0x6f, 0xc9, 0xa0, 0x85, 0xec, 0x4a, 0x23  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5a, 0xb4, 0xee, 0x68, 0x32, 0xdc, 0x86,
+           0xd0, 0x8a, 0x64, 0x3e, 0xb8, 0xe2, 0x0c, 0x56  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x83, 0xea, 0x4c, 0x25,
+           0x06, 0x6f, 0xc9, 0xa0, 0x85, 0xec, 0x4a, 0x23  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5b, 0xb6, 0xed, 0x6c, 0x37, 0xda, 0x81,
+           0xd8, 0x83, 0x6e, 0x35, 0xb4, 0xef, 0x02, 0x59  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x9e, 0xf7, 0x51, 0x38,
+           0x21, 0x48, 0xee, 0x87, 0xbf, 0xd6, 0x70, 0x19  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5c, 0xb8, 0xe4, 0x70, 0x2c, 0xc8, 0x94,
+           0xe0, 0xbc, 0x58, 0x04, 0x90, 0xcc, 0x28, 0x74  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x9e, 0xf7, 0x51, 0x38,
+           0x21, 0x48, 0xee, 0x87, 0xbf, 0xd6, 0x70, 0x19  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5d, 0xba, 0xe7, 0x74, 0x29, 0xce, 0x93,
+           0xe8, 0xb5, 0x52, 0x0f, 0x9c, 0xc1, 0x26, 0x7b  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x9e, 0xf7, 0x51, 0x38,
+           0x3c, 0x55, 0xf3, 0x9a, 0xa2, 0xcb, 0x6d, 0x04  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5e, 0xbc, 0xe2, 0x78, 0x26, 0xc4, 0x9a,
+           0xf0, 0xae, 0x4c, 0x12, 0x88, 0xd6, 0x34, 0x6a  },
+       { 0x00, 0x69, 0xcf, 0xa6, 0x9e, 0xf7, 0x51, 0x38,
+           0x3c, 0x55, 0xf3, 0x9a, 0xa2, 0xcb, 0x6d, 0x04  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x3a, 0x3a, 0x3a, 0x3a, 0x27, 0x27, 0x27, 0x27  },
+       { 0x00, 0x5f, 0xbe, 0xe1, 0x7c, 0x23, 0xc2, 0x9d,
+           0xf8, 0xa7, 0x46, 0x19, 0x84, 0xdb, 0x3a, 0x65  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7,
+           0x4a, 0x04, 0xd6, 0x98, 0x6f, 0x21, 0xf3, 0xbd  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7,
+           0x4a, 0x04, 0xd6, 0x98, 0x6f, 0x21, 0xf3, 0xbd  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x61, 0xc2, 0xa3, 0x84, 0xe5, 0x46, 0x27,
+           0x08, 0x69, 0xca, 0xab, 0x8c, 0xed, 0x4e, 0x2f  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7,
+           0x57, 0x19, 0xcb, 0x85, 0x72, 0x3c, 0xee, 0xa0  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x62, 0xc4, 0xa6, 0x88, 0xea, 0x4c, 0x2e,
+           0x10, 0x72, 0xd4, 0xb6, 0x98, 0xfa, 0x5c, 0x3e  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x25, 0x6b, 0xb9, 0xf7,
+           0x57, 0x19, 0xcb, 0x85, 0x72, 0x3c, 0xee, 0xa0  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x63, 0xc6, 0xa5, 0x8c, 0xef, 0x4a, 0x29,
+           0x18, 0x7b, 0xde, 0xbd, 0x94, 0xf7, 0x52, 0x31  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x70, 0x3e, 0xec, 0xa2, 0x48, 0x06, 0xd4, 0x9a  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x64, 0xc8, 0xac, 0x90, 0xf4, 0x58, 0x3c,
+           0x20, 0x44, 0xe8, 0x8c, 0xb0, 0xd4, 0x78, 0x1c  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x70, 0x3e, 0xec, 0xa2, 0x48, 0x06, 0xd4, 0x9a  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x65, 0xca, 0xaf, 0x94, 0xf1, 0x5e, 0x3b,
+           0x28, 0x4d, 0xe2, 0x87, 0xbc, 0xd9, 0x76, 0x13  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x6d, 0x23, 0xf1, 0xbf, 0x55, 0x1b, 0xc9, 0x87  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x66, 0xcc, 0xaa, 0x98, 0xfe, 0x54, 0x32,
+           0x30, 0x56, 0xfc, 0x9a, 0xa8, 0xce, 0x64, 0x02  },
+       { 0x00, 0x4e, 0x9c, 0xd2, 0x38, 0x76, 0xa4, 0xea,
+           0x6d, 0x23, 0xf1, 0xbf, 0x55, 0x1b, 0xc9, 0x87  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x67, 0xce, 0xa9, 0x9c, 0xfb, 0x52, 0x35,
+           0x38, 0x5f, 0xf6, 0x91, 0xa4, 0xc3, 0x6a, 0x0d  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x1f, 0x51, 0x9e, 0xd0,
+           0x3e, 0x70, 0xbf, 0xf1, 0x21, 0x6f, 0xa0, 0xee  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x68, 0xd0, 0xb8, 0xa0, 0xc8, 0x70, 0x18,
+           0x40, 0x28, 0x90, 0xf8, 0xe0, 0x88, 0x30, 0x58  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x1f, 0x51, 0x9e, 0xd0,
+           0x3e, 0x70, 0xbf, 0xf1, 0x21, 0x6f, 0xa0, 0xee  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x69, 0xd2, 0xbb, 0xa4, 0xcd, 0x76, 0x1f,
+           0x48, 0x21, 0x9a, 0xf3, 0xec, 0x85, 0x3e, 0x57  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x1f, 0x51, 0x9e, 0xd0,
+           0x23, 0x6d, 0xa2, 0xec, 0x3c, 0x72, 0xbd, 0xf3  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6a, 0xd4, 0xbe, 0xa8, 0xc2, 0x7c, 0x16,
+           0x50, 0x3a, 0x84, 0xee, 0xf8, 0x92, 0x2c, 0x46  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x1f, 0x51, 0x9e, 0xd0,
+           0x23, 0x6d, 0xa2, 0xec, 0x3c, 0x72, 0xbd, 0xf3  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6b, 0xd6, 0xbd, 0xac, 0xc7, 0x7a, 0x11,
+           0x58, 0x33, 0x8e, 0xe5, 0xf4, 0x9f, 0x22, 0x49  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x02, 0x4c, 0x83, 0xcd,
+           0x04, 0x4a, 0x85, 0xcb, 0x06, 0x48, 0x87, 0xc9  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6c, 0xd8, 0xb4, 0xb0, 0xdc, 0x68, 0x04,
+           0x60, 0x0c, 0xb8, 0xd4, 0xd0, 0xbc, 0x08, 0x64  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x02, 0x4c, 0x83, 0xcd,
+           0x04, 0x4a, 0x85, 0xcb, 0x06, 0x48, 0x87, 0xc9  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6d, 0xda, 0xb7, 0xb4, 0xd9, 0x6e, 0x03,
+           0x68, 0x05, 0xb2, 0xdf, 0xdc, 0xb1, 0x06, 0x6b  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x02, 0x4c, 0x83, 0xcd,
+           0x19, 0x57, 0x98, 0xd6, 0x1b, 0x55, 0x9a, 0xd4  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6e, 0xdc, 0xb2, 0xb8, 0xd6, 0x64, 0x0a,
+           0x70, 0x1e, 0xac, 0xc2, 0xc8, 0xa6, 0x14, 0x7a  },
+       { 0x00, 0x4e, 0x81, 0xcf, 0x02, 0x4c, 0x83, 0xcd,
+           0x19, 0x57, 0x98, 0xd6, 0x1b, 0x55, 0x9a, 0xd4  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x6f, 0xde, 0xb1, 0xbc, 0xd3, 0x62, 0x0d,
+           0x78, 0x17, 0xa6, 0xc9, 0xc4, 0xab, 0x1a, 0x75  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4,
+           0xa2, 0xf1, 0x04, 0x57, 0xf3, 0xa0, 0x55, 0x06  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4,
+           0xa2, 0xf1, 0x04, 0x57, 0xf3, 0xa0, 0x55, 0x06  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x71, 0xe2, 0x93, 0xc4, 0xb5, 0x26, 0x57,
+           0x88, 0xf9, 0x6a, 0x1b, 0x4c, 0x3d, 0xae, 0xdf  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4,
+           0xbf, 0xec, 0x19, 0x4a, 0xee, 0xbd, 0x48, 0x1b  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x72, 0xe4, 0x96, 0xc8, 0xba, 0x2c, 0x5e,
+           0x90, 0xe2, 0x74, 0x06, 0x58, 0x2a, 0xbc, 0xce  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x51, 0x02, 0xf7, 0xa4,
+           0xbf, 0xec, 0x19, 0x4a, 0xee, 0xbd, 0x48, 0x1b  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x73, 0xe6, 0x95, 0xcc, 0xbf, 0x2a, 0x59,
+           0x98, 0xeb, 0x7e, 0x0d, 0x54, 0x27, 0xb2, 0xc1  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x98, 0xcb, 0x3e, 0x6d, 0xd4, 0x87, 0x72, 0x21  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x74, 0xe8, 0x9c, 0xd0, 0xa4, 0x38, 0x4c,
+           0xa0, 0xd4, 0x48, 0x3c, 0x70, 0x04, 0x98, 0xec  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x98, 0xcb, 0x3e, 0x6d, 0xd4, 0x87, 0x72, 0x21  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x75, 0xea, 0x9f, 0xd4, 0xa1, 0x3e, 0x4b,
+           0xa8, 0xdd, 0x42, 0x37, 0x7c, 0x09, 0x96, 0xe3  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x85, 0xd6, 0x23, 0x70, 0xc9, 0x9a, 0x6f, 0x3c  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x76, 0xec, 0x9a, 0xd8, 0xae, 0x34, 0x42,
+           0xb0, 0xc6, 0x5c, 0x2a, 0x68, 0x1e, 0x84, 0xf2  },
+       { 0x00, 0x53, 0xa6, 0xf5, 0x4c, 0x1f, 0xea, 0xb9,
+           0x85, 0xd6, 0x23, 0x70, 0xc9, 0x9a, 0x6f, 0x3c  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x77, 0xee, 0x99, 0xdc, 0xab, 0x32, 0x45,
+           0xb8, 0xcf, 0x56, 0x21, 0x64, 0x13, 0x8a, 0xfd  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x6b, 0x38, 0xd0, 0x83,
+           0xd6, 0x85, 0x6d, 0x3e, 0xbd, 0xee, 0x06, 0x55  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x78, 0xf0, 0x88, 0xe0, 0x98, 0x10, 0x68,
+           0xc0, 0xb8, 0x30, 0x48, 0x20, 0x58, 0xd0, 0xa8  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x6b, 0x38, 0xd0, 0x83,
+           0xd6, 0x85, 0x6d, 0x3e, 0xbd, 0xee, 0x06, 0x55  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x79, 0xf2, 0x8b, 0xe4, 0x9d, 0x16, 0x6f,
+           0xc8, 0xb1, 0x3a, 0x43, 0x2c, 0x55, 0xde, 0xa7  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x6b, 0x38, 0xd0, 0x83,
+           0xcb, 0x98, 0x70, 0x23, 0xa0, 0xf3, 0x1b, 0x48  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7a, 0xf4, 0x8e, 0xe8, 0x92, 0x1c, 0x66,
+           0xd0, 0xaa, 0x24, 0x5e, 0x38, 0x42, 0xcc, 0xb6  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x6b, 0x38, 0xd0, 0x83,
+           0xcb, 0x98, 0x70, 0x23, 0xa0, 0xf3, 0x1b, 0x48  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7b, 0xf6, 0x8d, 0xec, 0x97, 0x1a, 0x61,
+           0xd8, 0xa3, 0x2e, 0x55, 0x34, 0x4f, 0xc2, 0xb9  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x76, 0x25, 0xcd, 0x9e,
+           0xec, 0xbf, 0x57, 0x04, 0x9a, 0xc9, 0x21, 0x72  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7c, 0xf8, 0x84, 0xf0, 0x8c, 0x08, 0x74,
+           0xe0, 0x9c, 0x18, 0x64, 0x10, 0x6c, 0xe8, 0x94  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x76, 0x25, 0xcd, 0x9e,
+           0xec, 0xbf, 0x57, 0x04, 0x9a, 0xc9, 0x21, 0x72  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7d, 0xfa, 0x87, 0xf4, 0x89, 0x0e, 0x73,
+           0xe8, 0x95, 0x12, 0x6f, 0x1c, 0x61, 0xe6, 0x9b  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x76, 0x25, 0xcd, 0x9e,
+           0xf1, 0xa2, 0x4a, 0x19, 0x87, 0xd4, 0x3c, 0x6f  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7e, 0xfc, 0x82, 0xf8, 0x86, 0x04, 0x7a,
+           0xf0, 0x8e, 0x0c, 0x72, 0x08, 0x76, 0xf4, 0x8a  },
+       { 0x00, 0x53, 0xbb, 0xe8, 0x76, 0x25, 0xcd, 0x9e,
+           0xf1, 0xa2, 0x4a, 0x19, 0x87, 0xd4, 0x3c, 0x6f  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0x1d,
+           0x27, 0x27, 0x27, 0x27, 0x3a, 0x3a, 0x3a, 0x3a  },
+       { 0x00, 0x7f, 0xfe, 0x81, 0xfc, 0x83, 0x02, 0x7d,
+           0xf8, 0x87, 0x06, 0x79, 0x04, 0x7b, 0xfa, 0x85  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2,
+           0x13, 0xfb, 0xde, 0x36, 0x94, 0x7c, 0x59, 0xb1  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2,
+           0x13, 0xfb, 0xde, 0x36, 0x94, 0x7c, 0x59, 0xb1  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x08, 0x89, 0x0a, 0x8b, 0x0c, 0x8d, 0x0e, 0x8f  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2,
+           0x0e, 0xe6, 0xc3, 0x2b, 0x89, 0x61, 0x44, 0xac  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x82, 0x04, 0x86, 0x08, 0x8a, 0x0c, 0x8e,
+           0x10, 0x92, 0x14, 0x96, 0x18, 0x9a, 0x1c, 0x9e  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x87, 0x6f, 0x4a, 0xa2,
+           0x0e, 0xe6, 0xc3, 0x2b, 0x89, 0x61, 0x44, 0xac  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x83, 0x06, 0x85, 0x0c, 0x8f, 0x0a, 0x89,
+           0x18, 0x9b, 0x1e, 0x9d, 0x14, 0x97, 0x12, 0x91  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x9a, 0x72, 0x57, 0xbf,
+           0x29, 0xc1, 0xe4, 0x0c, 0xb3, 0x5b, 0x7e, 0x96  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x84, 0x08, 0x8c, 0x10, 0x94, 0x18, 0x9c,
+           0x20, 0xa4, 0x28, 0xac, 0x30, 0xb4, 0x38, 0xbc  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x9a, 0x72, 0x57, 0xbf,
+           0x29, 0xc1, 0xe4, 0x0c, 0xb3, 0x5b, 0x7e, 0x96  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x85, 0x0a, 0x8f, 0x14, 0x91, 0x1e, 0x9b,
+           0x28, 0xad, 0x22, 0xa7, 0x3c, 0xb9, 0x36, 0xb3  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x9a, 0x72, 0x57, 0xbf,
+           0x34, 0xdc, 0xf9, 0x11, 0xae, 0x46, 0x63, 0x8b  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x86, 0x0c, 0x8a, 0x18, 0x9e, 0x14, 0x92,
+           0x30, 0xb6, 0x3c, 0xba, 0x28, 0xae, 0x24, 0xa2  },
+       { 0x00, 0xe8, 0xcd, 0x25, 0x9a, 0x72, 0x57, 0xbf,
+           0x34, 0xdc, 0xf9, 0x11, 0xae, 0x46, 0x63, 0x8b  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x87, 0x0e, 0x89, 0x1c, 0x9b, 0x12, 0x95,
+           0x38, 0xbf, 0x36, 0xb1, 0x24, 0xa3, 0x2a, 0xad  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xbd, 0x55, 0x6d, 0x85,
+           0x67, 0x8f, 0xb7, 0x5f, 0xda, 0x32, 0x0a, 0xe2  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x88, 0x10, 0x98, 0x20, 0xa8, 0x30, 0xb8,
+           0x40, 0xc8, 0x50, 0xd8, 0x60, 0xe8, 0x70, 0xf8  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xbd, 0x55, 0x6d, 0x85,
+           0x67, 0x8f, 0xb7, 0x5f, 0xda, 0x32, 0x0a, 0xe2  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x89, 0x12, 0x9b, 0x24, 0xad, 0x36, 0xbf,
+           0x48, 0xc1, 0x5a, 0xd3, 0x6c, 0xe5, 0x7e, 0xf7  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xbd, 0x55, 0x6d, 0x85,
+           0x7a, 0x92, 0xaa, 0x42, 0xc7, 0x2f, 0x17, 0xff  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8a, 0x14, 0x9e, 0x28, 0xa2, 0x3c, 0xb6,
+           0x50, 0xda, 0x44, 0xce, 0x78, 0xf2, 0x6c, 0xe6  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xbd, 0x55, 0x6d, 0x85,
+           0x7a, 0x92, 0xaa, 0x42, 0xc7, 0x2f, 0x17, 0xff  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8b, 0x16, 0x9d, 0x2c, 0xa7, 0x3a, 0xb1,
+           0x58, 0xd3, 0x4e, 0xc5, 0x74, 0xff, 0x62, 0xe9  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x5d, 0xb5, 0x8d, 0x65, 0xfd, 0x15, 0x2d, 0xc5  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8c, 0x18, 0x94, 0x30, 0xbc, 0x28, 0xa4,
+           0x60, 0xec, 0x78, 0xf4, 0x50, 0xdc, 0x48, 0xc4  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x5d, 0xb5, 0x8d, 0x65, 0xfd, 0x15, 0x2d, 0xc5  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8d, 0x1a, 0x97, 0x34, 0xb9, 0x2e, 0xa3,
+           0x68, 0xe5, 0x72, 0xff, 0x5c, 0xd1, 0x46, 0xcb  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x40, 0xa8, 0x90, 0x78, 0xe0, 0x08, 0x30, 0xd8  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8e, 0x1c, 0x92, 0x38, 0xb6, 0x24, 0xaa,
+           0x70, 0xfe, 0x6c, 0xe2, 0x48, 0xc6, 0x54, 0xda  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x40, 0xa8, 0x90, 0x78, 0xe0, 0x08, 0x30, 0xd8  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x8f, 0x1e, 0x91, 0x3c, 0xb3, 0x22, 0xad,
+           0x78, 0xf7, 0x66, 0xe9, 0x44, 0xcb, 0x5a, 0xd5  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1,
+           0xfb, 0x0e, 0x0c, 0xf9, 0x08, 0xfd, 0xff, 0x0a  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1,
+           0xfb, 0x0e, 0x0c, 0xf9, 0x08, 0xfd, 0xff, 0x0a  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x91, 0x22, 0xb3, 0x44, 0xd5, 0x66, 0xf7,
+           0x88, 0x19, 0xaa, 0x3b, 0xcc, 0x5d, 0xee, 0x7f  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1,
+           0xe6, 0x13, 0x11, 0xe4, 0x15, 0xe0, 0xe2, 0x17  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x92, 0x24, 0xb6, 0x48, 0xda, 0x6c, 0xfe,
+           0x90, 0x02, 0xb4, 0x26, 0xd8, 0x4a, 0xfc, 0x6e  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xf3, 0x06, 0x04, 0xf1,
+           0xe6, 0x13, 0x11, 0xe4, 0x15, 0xe0, 0xe2, 0x17  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x93, 0x26, 0xb5, 0x4c, 0xdf, 0x6a, 0xf9,
+           0x98, 0x0b, 0xbe, 0x2d, 0xd4, 0x47, 0xf2, 0x61  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xee, 0x1b, 0x19, 0xec,
+           0xc1, 0x34, 0x36, 0xc3, 0x2f, 0xda, 0xd8, 0x2d  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x94, 0x28, 0xbc, 0x50, 0xc4, 0x78, 0xec,
+           0xa0, 0x34, 0x88, 0x1c, 0xf0, 0x64, 0xd8, 0x4c  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xee, 0x1b, 0x19, 0xec,
+           0xc1, 0x34, 0x36, 0xc3, 0x2f, 0xda, 0xd8, 0x2d  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x95, 0x2a, 0xbf, 0x54, 0xc1, 0x7e, 0xeb,
+           0xa8, 0x3d, 0x82, 0x17, 0xfc, 0x69, 0xd6, 0x43  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xee, 0x1b, 0x19, 0xec,
+           0xdc, 0x29, 0x2b, 0xde, 0x32, 0xc7, 0xc5, 0x30  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x96, 0x2c, 0xba, 0x58, 0xce, 0x74, 0xe2,
+           0xb0, 0x26, 0x9c, 0x0a, 0xe8, 0x7e, 0xc4, 0x52  },
+       { 0x00, 0xf5, 0xf7, 0x02, 0xee, 0x1b, 0x19, 0xec,
+           0xdc, 0x29, 0x2b, 0xde, 0x32, 0xc7, 0xc5, 0x30  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x97, 0x2e, 0xb9, 0x5c, 0xcb, 0x72, 0xe5,
+           0xb8, 0x2f, 0x96, 0x01, 0xe4, 0x73, 0xca, 0x5d  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xc9, 0x3c, 0x23, 0xd6,
+           0x8f, 0x7a, 0x65, 0x90, 0x46, 0xb3, 0xac, 0x59  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x98, 0x30, 0xa8, 0x60, 0xf8, 0x50, 0xc8,
+           0xc0, 0x58, 0xf0, 0x68, 0xa0, 0x38, 0x90, 0x08  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xc9, 0x3c, 0x23, 0xd6,
+           0x8f, 0x7a, 0x65, 0x90, 0x46, 0xb3, 0xac, 0x59  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x99, 0x32, 0xab, 0x64, 0xfd, 0x56, 0xcf,
+           0xc8, 0x51, 0xfa, 0x63, 0xac, 0x35, 0x9e, 0x07  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xc9, 0x3c, 0x23, 0xd6,
+           0x92, 0x67, 0x78, 0x8d, 0x5b, 0xae, 0xb1, 0x44  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9a, 0x34, 0xae, 0x68, 0xf2, 0x5c, 0xc6,
+           0xd0, 0x4a, 0xe4, 0x7e, 0xb8, 0x22, 0x8c, 0x16  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xc9, 0x3c, 0x23, 0xd6,
+           0x92, 0x67, 0x78, 0x8d, 0x5b, 0xae, 0xb1, 0x44  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9b, 0x36, 0xad, 0x6c, 0xf7, 0x5a, 0xc1,
+           0xd8, 0x43, 0xee, 0x75, 0xb4, 0x2f, 0x82, 0x19  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xb5, 0x40, 0x5f, 0xaa, 0x61, 0x94, 0x8b, 0x7e  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xe0, 0x7c, 0xd8, 0x44, 0x90, 0x0c, 0xa8, 0x34  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xb5, 0x40, 0x5f, 0xaa, 0x61, 0x94, 0x8b, 0x7e  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9d, 0x3a, 0xa7, 0x74, 0xe9, 0x4e, 0xd3,
+           0xe8, 0x75, 0xd2, 0x4f, 0x9c, 0x01, 0xa6, 0x3b  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xa8, 0x5d, 0x42, 0xb7, 0x7c, 0x89, 0x96, 0x63  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9e, 0x3c, 0xa2, 0x78, 0xe6, 0x44, 0xda,
+           0xf0, 0x6e, 0xcc, 0x52, 0x88, 0x16, 0xb4, 0x2a  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xa8, 0x5d, 0x42, 0xb7, 0x7c, 0x89, 0x96, 0x63  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x74, 0x74, 0x69, 0x69, 0x4e, 0x4e, 0x53, 0x53  },
+       { 0x00, 0x9f, 0x3e, 0xa1, 0x7c, 0xe3, 0x42, 0xdd,
+           0xf8, 0x67, 0xc6, 0x59, 0x84, 0x1b, 0xba, 0x25  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04,
+           0xde, 0x0c, 0x67, 0xb5, 0xb1, 0x63, 0x08, 0xda  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04,
+           0xde, 0x0c, 0x67, 0xb5, 0xb1, 0x63, 0x08, 0xda  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa1, 0x42, 0xe3, 0x84, 0x25, 0xc6, 0x67,
+           0x08, 0xa9, 0x4a, 0xeb, 0x8c, 0x2d, 0xce, 0x6f  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04,
+           0xc3, 0x11, 0x7a, 0xa8, 0xac, 0x7e, 0x15, 0xc7  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa2, 0x44, 0xe6, 0x88, 0x2a, 0xcc, 0x6e,
+           0x10, 0xb2, 0x54, 0xf6, 0x98, 0x3a, 0xdc, 0x7e  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x6f, 0xbd, 0xd6, 0x04,
+           0xc3, 0x11, 0x7a, 0xa8, 0xac, 0x7e, 0x15, 0xc7  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa3, 0x46, 0xe5, 0x8c, 0x2f, 0xca, 0x69,
+           0x18, 0xbb, 0x5e, 0xfd, 0x94, 0x37, 0xd2, 0x71  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x72, 0xa0, 0xcb, 0x19,
+           0xe4, 0x36, 0x5d, 0x8f, 0x96, 0x44, 0x2f, 0xfd  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa4, 0x48, 0xec, 0x90, 0x34, 0xd8, 0x7c,
+           0x20, 0x84, 0x68, 0xcc, 0xb0, 0x14, 0xf8, 0x5c  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x72, 0xa0, 0xcb, 0x19,
+           0xe4, 0x36, 0x5d, 0x8f, 0x96, 0x44, 0x2f, 0xfd  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa5, 0x4a, 0xef, 0x94, 0x31, 0xde, 0x7b,
+           0x28, 0x8d, 0x62, 0xc7, 0xbc, 0x19, 0xf6, 0x53  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x72, 0xa0, 0xcb, 0x19,
+           0xf9, 0x2b, 0x40, 0x92, 0x8b, 0x59, 0x32, 0xe0  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x30, 0x96, 0x7c, 0xda, 0xa8, 0x0e, 0xe4, 0x42  },
+       { 0x00, 0xd2, 0xb9, 0x6b, 0x72, 0xa0, 0xcb, 0x19,
+           0xf9, 0x2b, 0x40, 0x92, 0x8b, 0x59, 0x32, 0xe0  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa7, 0x4e, 0xe9, 0x9c, 0x3b, 0xd2, 0x75,
+           0x38, 0x9f, 0x76, 0xd1, 0xa4, 0x03, 0xea, 0x4d  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x55, 0x87, 0xf1, 0x23,
+           0xaa, 0x78, 0x0e, 0xdc, 0xff, 0x2d, 0x5b, 0x89  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa8, 0x50, 0xf8, 0xa0, 0x08, 0xf0, 0x58,
+           0x40, 0xe8, 0x10, 0xb8, 0xe0, 0x48, 0xb0, 0x18  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x55, 0x87, 0xf1, 0x23,
+           0xaa, 0x78, 0x0e, 0xdc, 0xff, 0x2d, 0x5b, 0x89  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xa9, 0x52, 0xfb, 0xa4, 0x0d, 0xf6, 0x5f,
+           0x48, 0xe1, 0x1a, 0xb3, 0xec, 0x45, 0xbe, 0x17  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x55, 0x87, 0xf1, 0x23,
+           0xb7, 0x65, 0x13, 0xc1, 0xe2, 0x30, 0x46, 0x94  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xaa, 0x54, 0xfe, 0xa8, 0x02, 0xfc, 0x56,
+           0x50, 0xfa, 0x04, 0xae, 0xf8, 0x52, 0xac, 0x06  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x55, 0x87, 0xf1, 0x23,
+           0xb7, 0x65, 0x13, 0xc1, 0xe2, 0x30, 0x46, 0x94  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xab, 0x56, 0xfd, 0xac, 0x07, 0xfa, 0x51,
+           0x58, 0xf3, 0x0e, 0xa5, 0xf4, 0x5f, 0xa2, 0x09  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x90, 0x42, 0x34, 0xe6, 0xd8, 0x0a, 0x7c, 0xae  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xac, 0x58, 0xf4, 0xb0, 0x1c, 0xe8, 0x44,
+           0x60, 0xcc, 0x38, 0x94, 0xd0, 0x7c, 0x88, 0x24  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x90, 0x42, 0x34, 0xe6, 0xd8, 0x0a, 0x7c, 0xae  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xad, 0x5a, 0xf7, 0xb4, 0x19, 0xee, 0x43,
+           0x68, 0xc5, 0x32, 0x9f, 0xdc, 0x71, 0x86, 0x2b  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x8d, 0x5f, 0x29, 0xfb, 0xc5, 0x17, 0x61, 0xb3  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xae, 0x5c, 0xf2, 0xb8, 0x16, 0xe4, 0x4a,
+           0x70, 0xde, 0x2c, 0x82, 0xc8, 0x66, 0x94, 0x3a  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x8d, 0x5f, 0x29, 0xfb, 0xc5, 0x17, 0x61, 0xb3  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xaf, 0x5e, 0xf1, 0xbc, 0x13, 0xe2, 0x4d,
+           0x78, 0xd7, 0x26, 0x89, 0xc4, 0x6b, 0x9a, 0x35  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57,
+           0x36, 0xf9, 0xb5, 0x7a, 0x2d, 0xe2, 0xae, 0x61  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57,
+           0x36, 0xf9, 0xb5, 0x7a, 0x2d, 0xe2, 0xae, 0x61  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb1, 0x62, 0xd3, 0xc4, 0x75, 0xa6, 0x17,
+           0x88, 0x39, 0xea, 0x5b, 0x4c, 0xfd, 0x2e, 0x9f  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57,
+           0x2b, 0xe4, 0xa8, 0x67, 0x30, 0xff, 0xb3, 0x7c  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb2, 0x64, 0xd6, 0xc8, 0x7a, 0xac, 0x1e,
+           0x90, 0x22, 0xf4, 0x46, 0x58, 0xea, 0x3c, 0x8e  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x1b, 0xd4, 0x98, 0x57,
+           0x2b, 0xe4, 0xa8, 0x67, 0x30, 0xff, 0xb3, 0x7c  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb3, 0x66, 0xd5, 0xcc, 0x7f, 0xaa, 0x19,
+           0x98, 0x2b, 0xfe, 0x4d, 0x54, 0xe7, 0x32, 0x81  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x06, 0xc9, 0x85, 0x4a,
+           0x0c, 0xc3, 0x8f, 0x40, 0x0a, 0xc5, 0x89, 0x46  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb4, 0x68, 0xdc, 0xd0, 0x64, 0xb8, 0x0c,
+           0xa0, 0x14, 0xc8, 0x7c, 0x70, 0xc4, 0x18, 0xac  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x06, 0xc9, 0x85, 0x4a,
+           0x0c, 0xc3, 0x8f, 0x40, 0x0a, 0xc5, 0x89, 0x46  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb5, 0x6a, 0xdf, 0xd4, 0x61, 0xbe, 0x0b,
+           0xa8, 0x1d, 0xc2, 0x77, 0x7c, 0xc9, 0x16, 0xa3  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x06, 0xc9, 0x85, 0x4a,
+           0x11, 0xde, 0x92, 0x5d, 0x17, 0xd8, 0x94, 0x5b  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb6, 0x6c, 0xda, 0xd8, 0x6e, 0xb4, 0x02,
+           0xb0, 0x06, 0xdc, 0x6a, 0x68, 0xde, 0x04, 0xb2  },
+       { 0x00, 0xcf, 0x83, 0x4c, 0x06, 0xc9, 0x85, 0x4a,
+           0x11, 0xde, 0x92, 0x5d, 0x17, 0xd8, 0x94, 0x5b  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb7, 0x6e, 0xd9, 0xdc, 0x6b, 0xb2, 0x05,
+           0xb8, 0x0f, 0xd6, 0x61, 0x64, 0xd3, 0x0a, 0xbd  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x21, 0xee, 0xbf, 0x70,
+           0x42, 0x8d, 0xdc, 0x13, 0x63, 0xac, 0xfd, 0x32  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb8, 0x70, 0xc8, 0xe0, 0x58, 0x90, 0x28,
+           0xc0, 0x78, 0xb0, 0x08, 0x20, 0x98, 0x50, 0xe8  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x21, 0xee, 0xbf, 0x70,
+           0x42, 0x8d, 0xdc, 0x13, 0x63, 0xac, 0xfd, 0x32  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xb9, 0x72, 0xcb, 0xe4, 0x5d, 0x96, 0x2f,
+           0xc8, 0x71, 0xba, 0x03, 0x2c, 0x95, 0x5e, 0xe7  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x21, 0xee, 0xbf, 0x70,
+           0x5f, 0x90, 0xc1, 0x0e, 0x7e, 0xb1, 0xe0, 0x2f  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xba, 0x74, 0xce, 0xe8, 0x52, 0x9c, 0x26,
+           0xd0, 0x6a, 0xa4, 0x1e, 0x38, 0x82, 0x4c, 0xf6  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x21, 0xee, 0xbf, 0x70,
+           0x5f, 0x90, 0xc1, 0x0e, 0x7e, 0xb1, 0xe0, 0x2f  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xd8, 0x63, 0xae, 0x15, 0x34, 0x8f, 0x42, 0xf9  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x78, 0xb7, 0xe6, 0x29, 0x44, 0x8b, 0xda, 0x15  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbc, 0x78, 0xc4, 0xf0, 0x4c, 0x88, 0x34,
+           0xe0, 0x5c, 0x98, 0x24, 0x10, 0xac, 0x68, 0xd4  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x78, 0xb7, 0xe6, 0x29, 0x44, 0x8b, 0xda, 0x15  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbd, 0x7a, 0xc7, 0xf4, 0x49, 0x8e, 0x33,
+           0xe8, 0x55, 0x92, 0x2f, 0x1c, 0xa1, 0x66, 0xdb  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x65, 0xaa, 0xfb, 0x34, 0x59, 0x96, 0xc7, 0x08  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbe, 0x7c, 0xc2, 0xf8, 0x46, 0x84, 0x3a,
+           0xf0, 0x4e, 0x8c, 0x32, 0x08, 0xb6, 0x74, 0xca  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x65, 0xaa, 0xfb, 0x34, 0x59, 0x96, 0xc7, 0x08  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x3a, 0x3a, 0x27, 0x27,
+           0x69, 0x69, 0x74, 0x74, 0x53, 0x53, 0x4e, 0x4e  },
+       { 0x00, 0xbf, 0x7e, 0xc1, 0xfc, 0x43, 0x82, 0x3d,
+           0xf8, 0x47, 0x86, 0x39, 0x04, 0xbb, 0x7a, 0xc5  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3,
+           0x94, 0x08, 0xb1, 0x2d, 0xde, 0x42, 0xfb, 0x67  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3,
+           0x94, 0x08, 0xb1, 0x2d, 0xde, 0x42, 0xfb, 0x67  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc1, 0x82, 0x43, 0x04, 0xc5, 0x86, 0x47,
+           0x08, 0xc9, 0x8a, 0x4b, 0x0c, 0xcd, 0x8e, 0x4f  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3,
+           0x89, 0x15, 0xac, 0x30, 0xc3, 0x5f, 0xe6, 0x7a  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc2, 0x84, 0x46, 0x08, 0xca, 0x8c, 0x4e,
+           0x10, 0xd2, 0x94, 0x56, 0x18, 0xda, 0x9c, 0x5e  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x4a, 0xd6, 0x6f, 0xf3,
+           0x89, 0x15, 0xac, 0x30, 0xc3, 0x5f, 0xe6, 0x7a  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc3, 0x86, 0x45, 0x0c, 0xcf, 0x8a, 0x49,
+           0x18, 0xdb, 0x9e, 0x5d, 0x14, 0xd7, 0x92, 0x51  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x57, 0xcb, 0x72, 0xee,
+           0xae, 0x32, 0x8b, 0x17, 0xf9, 0x65, 0xdc, 0x40  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc4, 0x88, 0x4c, 0x10, 0xd4, 0x98, 0x5c,
+           0x20, 0xe4, 0xa8, 0x6c, 0x30, 0xf4, 0xb8, 0x7c  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x57, 0xcb, 0x72, 0xee,
+           0xae, 0x32, 0x8b, 0x17, 0xf9, 0x65, 0xdc, 0x40  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc5, 0x8a, 0x4f, 0x14, 0xd1, 0x9e, 0x5b,
+           0x28, 0xed, 0xa2, 0x67, 0x3c, 0xf9, 0xb6, 0x73  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x57, 0xcb, 0x72, 0xee,
+           0xb3, 0x2f, 0x96, 0x0a, 0xe4, 0x78, 0xc1, 0x5d  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc6, 0x8c, 0x4a, 0x18, 0xde, 0x94, 0x52,
+           0x30, 0xf6, 0xbc, 0x7a, 0x28, 0xee, 0xa4, 0x62  },
+       { 0x00, 0x9c, 0x25, 0xb9, 0x57, 0xcb, 0x72, 0xee,
+           0xb3, 0x2f, 0x96, 0x0a, 0xe4, 0x78, 0xc1, 0x5d  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc7, 0x8e, 0x49, 0x1c, 0xdb, 0x92, 0x55,
+           0x38, 0xff, 0xb6, 0x71, 0x24, 0xe3, 0xaa, 0x6d  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xe0, 0x7c, 0xd8, 0x44, 0x90, 0x0c, 0xa8, 0x34  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc8, 0x90, 0x58, 0x20, 0xe8, 0xb0, 0x78,
+           0x40, 0x88, 0xd0, 0x18, 0x60, 0xa8, 0xf0, 0x38  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xe0, 0x7c, 0xd8, 0x44, 0x90, 0x0c, 0xa8, 0x34  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xc9, 0x92, 0x5b, 0x24, 0xed, 0xb6, 0x7f,
+           0x48, 0x81, 0xda, 0x13, 0x6c, 0xa5, 0xfe, 0x37  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xfd, 0x61, 0xc5, 0x59, 0x8d, 0x11, 0xb5, 0x29  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xca, 0x94, 0x5e, 0x28, 0xe2, 0xbc, 0x76,
+           0x50, 0x9a, 0xc4, 0x0e, 0x78, 0xb2, 0xec, 0x26  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x70, 0xec, 0x48, 0xd4,
+           0xfd, 0x61, 0xc5, 0x59, 0x8d, 0x11, 0xb5, 0x29  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xcb, 0x96, 0x5d, 0x2c, 0xe7, 0xba, 0x71,
+           0x58, 0x93, 0xce, 0x05, 0x74, 0xbf, 0xe2, 0x29  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x6d, 0xf1, 0x55, 0xc9,
+           0xda, 0x46, 0xe2, 0x7e, 0xb7, 0x2b, 0x8f, 0x13  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xcc, 0x98, 0x54, 0x30, 0xfc, 0xa8, 0x64,
+           0x60, 0xac, 0xf8, 0x34, 0x50, 0x9c, 0xc8, 0x04  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x6d, 0xf1, 0x55, 0xc9,
+           0xda, 0x46, 0xe2, 0x7e, 0xb7, 0x2b, 0x8f, 0x13  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xcd, 0x9a, 0x57, 0x34, 0xf9, 0xae, 0x63,
+           0x68, 0xa5, 0xf2, 0x3f, 0x5c, 0x91, 0xc6, 0x0b  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x6d, 0xf1, 0x55, 0xc9,
+           0xc7, 0x5b, 0xff, 0x63, 0xaa, 0x36, 0x92, 0x0e  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xce, 0x9c, 0x52, 0x38, 0xf6, 0xa4, 0x6a,
+           0x70, 0xbe, 0xec, 0x22, 0x48, 0x86, 0xd4, 0x1a  },
+       { 0x00, 0x9c, 0x38, 0xa4, 0x6d, 0xf1, 0x55, 0xc9,
+           0xc7, 0x5b, 0xff, 0x63, 0xaa, 0x36, 0x92, 0x0e  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xcf, 0x9e, 0x51, 0x3c, 0xf3, 0xa2, 0x6d,
+           0x78, 0xb7, 0xe6, 0x29, 0x44, 0x8b, 0xda, 0x15  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0,
+           0x7c, 0xfd, 0x63, 0xe2, 0x42, 0xc3, 0x5d, 0xdc  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0,
+           0x7c, 0xfd, 0x63, 0xe2, 0x42, 0xc3, 0x5d, 0xdc  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd1, 0xa2, 0x73, 0x44, 0x95, 0xe6, 0x37,
+           0x88, 0x59, 0x2a, 0xfb, 0xcc, 0x1d, 0x6e, 0xbf  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0,
+           0x61, 0xe0, 0x7e, 0xff, 0x5f, 0xde, 0x40, 0xc1  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd2, 0xa4, 0x76, 0x48, 0x9a, 0xec, 0x3e,
+           0x90, 0x42, 0x34, 0xe6, 0xd8, 0x0a, 0x7c, 0xae  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x3e, 0xbf, 0x21, 0xa0,
+           0x61, 0xe0, 0x7e, 0xff, 0x5f, 0xde, 0x40, 0xc1  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd3, 0xa6, 0x75, 0x4c, 0x9f, 0xea, 0x39,
+           0x98, 0x4b, 0x3e, 0xed, 0xd4, 0x07, 0x72, 0xa1  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x23, 0xa2, 0x3c, 0xbd,
+           0x46, 0xc7, 0x59, 0xd8, 0x65, 0xe4, 0x7a, 0xfb  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd4, 0xa8, 0x7c, 0x50, 0x84, 0xf8, 0x2c,
+           0xa0, 0x74, 0x08, 0xdc, 0xf0, 0x24, 0x58, 0x8c  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x23, 0xa2, 0x3c, 0xbd,
+           0x46, 0xc7, 0x59, 0xd8, 0x65, 0xe4, 0x7a, 0xfb  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd5, 0xaa, 0x7f, 0x54, 0x81, 0xfe, 0x2b,
+           0xa8, 0x7d, 0x02, 0xd7, 0xfc, 0x29, 0x56, 0x83  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x23, 0xa2, 0x3c, 0xbd,
+           0x5b, 0xda, 0x44, 0xc5, 0x78, 0xf9, 0x67, 0xe6  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd6, 0xac, 0x7a, 0x58, 0x8e, 0xf4, 0x22,
+           0xb0, 0x66, 0x1c, 0xca, 0xe8, 0x3e, 0x44, 0x92  },
+       { 0x00, 0x81, 0x1f, 0x9e, 0x23, 0xa2, 0x3c, 0xbd,
+           0x5b, 0xda, 0x44, 0xc5, 0x78, 0xf9, 0x67, 0xe6  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd7, 0xae, 0x79, 0x5c, 0x8b, 0xf2, 0x25,
+           0xb8, 0x6f, 0x16, 0xc1, 0xe4, 0x33, 0x4a, 0x9d  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x08, 0x89, 0x0a, 0x8b, 0x0c, 0x8d, 0x0e, 0x8f  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd8, 0xb0, 0x68, 0x60, 0xb8, 0xd0, 0x08,
+           0xc0, 0x18, 0x70, 0xa8, 0xa0, 0x78, 0x10, 0xc8  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x08, 0x89, 0x0a, 0x8b, 0x0c, 0x8d, 0x0e, 0x8f  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xd9, 0xb2, 0x6b, 0x64, 0xbd, 0xd6, 0x0f,
+           0xc8, 0x11, 0x7a, 0xa3, 0xac, 0x75, 0x1e, 0xc7  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x15, 0x94, 0x17, 0x96, 0x11, 0x90, 0x13, 0x92  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xda, 0xb4, 0x6e, 0x68, 0xb2, 0xdc, 0x06,
+           0xd0, 0x0a, 0x64, 0xbe, 0xb8, 0x62, 0x0c, 0xd6  },
+       { 0x00, 0x81, 0x02, 0x83, 0x04, 0x85, 0x06, 0x87,
+           0x15, 0x94, 0x17, 0x96, 0x11, 0x90, 0x13, 0x92  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xdb, 0xb6, 0x6d, 0x6c, 0xb7, 0xda, 0x01,
+           0xd8, 0x03, 0x6e, 0xb5, 0xb4, 0x6f, 0x02, 0xd9  },
+       { 0x00, 0x81, 0x02, 0x83, 0x19, 0x98, 0x1b, 0x9a,
+           0x32, 0xb3, 0x30, 0xb1, 0x2b, 0xaa, 0x29, 0xa8  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xdc, 0xb8, 0x64, 0x70, 0xac, 0xc8, 0x14,
+           0xe0, 0x3c, 0x58, 0x84, 0x90, 0x4c, 0x28, 0xf4  },
+       { 0x00, 0x81, 0x02, 0x83, 0x19, 0x98, 0x1b, 0x9a,
+           0x32, 0xb3, 0x30, 0xb1, 0x2b, 0xaa, 0x29, 0xa8  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xdd, 0xba, 0x67, 0x74, 0xa9, 0xce, 0x13,
+           0xe8, 0x35, 0x52, 0x8f, 0x9c, 0x41, 0x26, 0xfb  },
+       { 0x00, 0x81, 0x02, 0x83, 0x19, 0x98, 0x1b, 0x9a,
+           0x2f, 0xae, 0x2d, 0xac, 0x36, 0xb7, 0x34, 0xb5  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xde, 0xbc, 0x62, 0x78, 0xa6, 0xc4, 0x1a,
+           0xf0, 0x2e, 0x4c, 0x92, 0x88, 0x56, 0x34, 0xea  },
+       { 0x00, 0x81, 0x02, 0x83, 0x19, 0x98, 0x1b, 0x9a,
+           0x2f, 0xae, 0x2d, 0xac, 0x36, 0xb7, 0x34, 0xb5  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x4e, 0x4e, 0x53, 0x53, 0x69, 0x69, 0x74, 0x74  },
+       { 0x00, 0xdf, 0xbe, 0x61, 0x7c, 0xa3, 0xc2, 0x1d,
+           0xf8, 0x27, 0x46, 0x99, 0x84, 0x5b, 0x3a, 0xe5  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55,
+           0x59, 0xff, 0x08, 0xae, 0xfb, 0x5d, 0xaa, 0x0c  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55,
+           0x59, 0xff, 0x08, 0xae, 0xfb, 0x5d, 0xaa, 0x0c  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe1, 0xc2, 0x23, 0x84, 0x65, 0x46, 0xa7,
+           0x08, 0xe9, 0xca, 0x2b, 0x8c, 0x6d, 0x4e, 0xaf  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55,
+           0x44, 0xe2, 0x15, 0xb3, 0xe6, 0x40, 0xb7, 0x11  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe2, 0xc4, 0x26, 0x88, 0x6a, 0x4c, 0xae,
+           0x10, 0xf2, 0xd4, 0x36, 0x98, 0x7a, 0x5c, 0xbe  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xa2, 0x04, 0xf3, 0x55,
+           0x44, 0xe2, 0x15, 0xb3, 0xe6, 0x40, 0xb7, 0x11  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe3, 0xc6, 0x25, 0x8c, 0x6f, 0x4a, 0xa9,
+           0x18, 0xfb, 0xde, 0x3d, 0x94, 0x77, 0x52, 0xb1  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xbf, 0x19, 0xee, 0x48,
+           0x63, 0xc5, 0x32, 0x94, 0xdc, 0x7a, 0x8d, 0x2b  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe4, 0xc8, 0x2c, 0x90, 0x74, 0x58, 0xbc,
+           0x20, 0xc4, 0xe8, 0x0c, 0xb0, 0x54, 0x78, 0x9c  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xbf, 0x19, 0xee, 0x48,
+           0x63, 0xc5, 0x32, 0x94, 0xdc, 0x7a, 0x8d, 0x2b  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe5, 0xca, 0x2f, 0x94, 0x71, 0x5e, 0xbb,
+           0x28, 0xcd, 0xe2, 0x07, 0xbc, 0x59, 0x76, 0x93  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xbf, 0x19, 0xee, 0x48,
+           0x7e, 0xd8, 0x2f, 0x89, 0xc1, 0x67, 0x90, 0x36  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe6, 0xcc, 0x2a, 0x98, 0x7e, 0x54, 0xb2,
+           0x30, 0xd6, 0xfc, 0x1a, 0xa8, 0x4e, 0x64, 0x82  },
+       { 0x00, 0xa6, 0x51, 0xf7, 0xbf, 0x19, 0xee, 0x48,
+           0x7e, 0xd8, 0x2f, 0x89, 0xc1, 0x67, 0x90, 0x36  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe7, 0xce, 0x29, 0x9c, 0x7b, 0x52, 0xb5,
+           0x38, 0xdf, 0xf6, 0x11, 0xa4, 0x43, 0x6a, 0x8d  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x2d, 0x8b, 0x61, 0xc7, 0xb5, 0x13, 0xf9, 0x5f  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe8, 0xd0, 0x38, 0xa0, 0x48, 0x70, 0x98,
+           0x40, 0xa8, 0x90, 0x78, 0xe0, 0x08, 0x30, 0xd8  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x2d, 0x8b, 0x61, 0xc7, 0xb5, 0x13, 0xf9, 0x5f  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xe9, 0xd2, 0x3b, 0xa4, 0x4d, 0x76, 0x9f,
+           0x48, 0xa1, 0x9a, 0x73, 0xec, 0x05, 0x3e, 0xd7  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x30, 0x96, 0x7c, 0xda, 0xa8, 0x0e, 0xe4, 0x42  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xea, 0xd4, 0x3e, 0xa8, 0x42, 0x7c, 0x96,
+           0x50, 0xba, 0x84, 0x6e, 0xf8, 0x12, 0x2c, 0xc6  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x98, 0x3e, 0xd4, 0x72,
+           0x30, 0x96, 0x7c, 0xda, 0xa8, 0x0e, 0xe4, 0x42  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xeb, 0xd6, 0x3d, 0xac, 0x47, 0x7a, 0x91,
+           0x58, 0xb3, 0x8e, 0x65, 0xf4, 0x1f, 0x22, 0xc9  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x85, 0x23, 0xc9, 0x6f,
+           0x17, 0xb1, 0x5b, 0xfd, 0x92, 0x34, 0xde, 0x78  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xec, 0xd8, 0x34, 0xb0, 0x5c, 0x68, 0x84,
+           0x60, 0x8c, 0xb8, 0x54, 0xd0, 0x3c, 0x08, 0xe4  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x85, 0x23, 0xc9, 0x6f,
+           0x17, 0xb1, 0x5b, 0xfd, 0x92, 0x34, 0xde, 0x78  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xed, 0xda, 0x37, 0xb4, 0x59, 0x6e, 0x83,
+           0x68, 0x85, 0xb2, 0x5f, 0xdc, 0x31, 0x06, 0xeb  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x85, 0x23, 0xc9, 0x6f,
+           0x0a, 0xac, 0x46, 0xe0, 0x8f, 0x29, 0xc3, 0x65  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xee, 0xdc, 0x32, 0xb8, 0x56, 0x64, 0x8a,
+           0x70, 0x9e, 0xac, 0x42, 0xc8, 0x26, 0x14, 0xfa  },
+       { 0x00, 0xa6, 0x4c, 0xea, 0x85, 0x23, 0xc9, 0x6f,
+           0x0a, 0xac, 0x46, 0xe0, 0x8f, 0x29, 0xc3, 0x65  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xef, 0xde, 0x31, 0xbc, 0x53, 0x62, 0x8d,
+           0x78, 0x97, 0xa6, 0x49, 0xc4, 0x2b, 0x1a, 0xf5  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06,
+           0xb1, 0x0a, 0xda, 0x61, 0x67, 0xdc, 0x0c, 0xb7  },
+       { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06,
+           0xb1, 0x0a, 0xda, 0x61, 0x67, 0xdc, 0x0c, 0xb7  },
+       { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+           0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf1, 0xe2, 0x13, 0xc4, 0x35, 0x26, 0xd7,
+           0x88, 0x79, 0x6a, 0x9b, 0x4c, 0xbd, 0xae, 0x5f  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06,
+           0xac, 0x17, 0xc7, 0x7c, 0x7a, 0xc1, 0x11, 0xaa  },
+       { 0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0,
+           0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf2, 0xe4, 0x16, 0xc8, 0x3a, 0x2c, 0xde,
+           0x90, 0x62, 0x74, 0x86, 0x58, 0xaa, 0xbc, 0x4e  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xd6, 0x6d, 0xbd, 0x06,
+           0xac, 0x17, 0xc7, 0x7c, 0x7a, 0xc1, 0x11, 0xaa  },
+       { 0x00, 0x30, 0x60, 0x50, 0xc0, 0xf0, 0xa0, 0x90,
+           0x80, 0xb0, 0xe0, 0xd0, 0x40, 0x70, 0x20, 0x10  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf3, 0xe6, 0x15, 0xcc, 0x3f, 0x2a, 0xd9,
+           0x98, 0x6b, 0x7e, 0x8d, 0x54, 0xa7, 0xb2, 0x41  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xcb, 0x70, 0xa0, 0x1b,
+           0x8b, 0x30, 0xe0, 0x5b, 0x40, 0xfb, 0x2b, 0x90  },
+       { 0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0,
+           0x00, 0x40, 0x80, 0xc0, 0x00, 0x40, 0x80, 0xc0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf4, 0xe8, 0x1c, 0xd0, 0x24, 0x38, 0xcc,
+           0xa0, 0x54, 0x48, 0xbc, 0x70, 0x84, 0x98, 0x6c  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xcb, 0x70, 0xa0, 0x1b,
+           0x8b, 0x30, 0xe0, 0x5b, 0x40, 0xfb, 0x2b, 0x90  },
+       { 0x00, 0x50, 0xa0, 0xf0, 0x40, 0x10, 0xe0, 0xb0,
+           0x80, 0xd0, 0x20, 0x70, 0xc0, 0x90, 0x60, 0x30  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf5, 0xea, 0x1f, 0xd4, 0x21, 0x3e, 0xcb,
+           0xa8, 0x5d, 0x42, 0xb7, 0x7c, 0x89, 0x96, 0x63  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xcb, 0x70, 0xa0, 0x1b,
+           0x96, 0x2d, 0xfd, 0x46, 0x5d, 0xe6, 0x36, 0x8d  },
+       { 0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20,
+           0x00, 0x60, 0xc0, 0xa0, 0x80, 0xe0, 0x40, 0x20  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf6, 0xec, 0x1a, 0xd8, 0x2e, 0x34, 0xc2,
+           0xb0, 0x46, 0x5c, 0xaa, 0x68, 0x9e, 0x84, 0x72  },
+       { 0x00, 0xbb, 0x6b, 0xd0, 0xcb, 0x70, 0xa0, 0x1b,
+           0x96, 0x2d, 0xfd, 0x46, 0x5d, 0xe6, 0x36, 0x8d  },
+       { 0x00, 0x70, 0xe0, 0x90, 0xc0, 0xb0, 0x20, 0x50,
+           0x80, 0xf0, 0x60, 0x10, 0x40, 0x30, 0xa0, 0xd0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf7, 0xee, 0x19, 0xdc, 0x2b, 0x32, 0xc5,
+           0xb8, 0x4f, 0x56, 0xa1, 0x64, 0x93, 0x8a, 0x7d  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xc5, 0x7e, 0xb3, 0x08, 0x29, 0x92, 0x5f, 0xe4  },
+       { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
+           0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf8, 0xf0, 0x08, 0xe0, 0x18, 0x10, 0xe8,
+           0xc0, 0x38, 0x30, 0xc8, 0x20, 0xd8, 0xd0, 0x28  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xc5, 0x7e, 0xb3, 0x08, 0x29, 0x92, 0x5f, 0xe4  },
+       { 0x00, 0x90, 0x20, 0xb0, 0x40, 0xd0, 0x60, 0xf0,
+           0x80, 0x10, 0xa0, 0x30, 0xc0, 0x50, 0xe0, 0x70  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xf9, 0xf2, 0x0b, 0xe4, 0x1d, 0x16, 0xef,
+           0xc8, 0x31, 0x3a, 0xc3, 0x2c, 0xd5, 0xde, 0x27  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xd8, 0x63, 0xae, 0x15, 0x34, 0x8f, 0x42, 0xf9  },
+       { 0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60,
+           0x00, 0xa0, 0x40, 0xe0, 0x80, 0x20, 0xc0, 0x60  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfa, 0xf4, 0x0e, 0xe8, 0x12, 0x1c, 0xe6,
+           0xd0, 0x2a, 0x24, 0xde, 0x38, 0xc2, 0xcc, 0x36  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xec, 0x57, 0x9a, 0x21,
+           0xd8, 0x63, 0xae, 0x15, 0x34, 0x8f, 0x42, 0xf9  },
+       { 0x00, 0xb0, 0x60, 0xd0, 0xc0, 0x70, 0xa0, 0x10,
+           0x80, 0x30, 0xe0, 0x50, 0x40, 0xf0, 0x20, 0x90  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfb, 0xf6, 0x0d, 0xec, 0x17, 0x1a, 0xe1,
+           0xd8, 0x23, 0x2e, 0xd5, 0x34, 0xcf, 0xc2, 0x39  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xf1, 0x4a, 0x87, 0x3c,
+           0xff, 0x44, 0x89, 0x32, 0x0e, 0xb5, 0x78, 0xc3  },
+       { 0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40,
+           0x00, 0xc0, 0x80, 0x40, 0x00, 0xc0, 0x80, 0x40  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfc, 0xf8, 0x04, 0xf0, 0x0c, 0x08, 0xf4,
+           0xe0, 0x1c, 0x18, 0xe4, 0x10, 0xec, 0xe8, 0x14  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xf1, 0x4a, 0x87, 0x3c,
+           0xff, 0x44, 0x89, 0x32, 0x0e, 0xb5, 0x78, 0xc3  },
+       { 0x00, 0xd0, 0xa0, 0x70, 0x40, 0x90, 0xe0, 0x30,
+           0x80, 0x50, 0x20, 0xf0, 0xc0, 0x10, 0x60, 0xb0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfd, 0xfa, 0x07, 0xf4, 0x09, 0x0e, 0xf3,
+           0xe8, 0x15, 0x12, 0xef, 0x1c, 0xe1, 0xe6, 0x1b  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xf1, 0x4a, 0x87, 0x3c,
+           0xe2, 0x59, 0x94, 0x2f, 0x13, 0xa8, 0x65, 0xde  },
+       { 0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0,
+           0x00, 0xe0, 0xc0, 0x20, 0x80, 0x60, 0x40, 0xa0  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xfe, 0xfc, 0x02, 0xf8, 0x06, 0x04, 0xfa,
+           0xf0, 0x0e, 0x0c, 0xf2, 0x08, 0xf6, 0xf4, 0x0a  },
+       { 0x00, 0xbb, 0x76, 0xcd, 0xf1, 0x4a, 0x87, 0x3c,
+           0xe2, 0x59, 0x94, 0x2f, 0x13, 0xa8, 0x65, 0xde  },
+       { 0x00, 0xf0, 0xe0, 0x10, 0xc0, 0x30, 0x20, 0xd0,
+           0x80, 0x70, 0x60, 0x90, 0x40, 0xb0, 0xa0, 0x50  },
+       { 0x00, 0x00, 0x1d, 0x1d, 0x27, 0x27, 0x3a, 0x3a,
+           0x53, 0x53, 0x4e, 0x4e, 0x74, 0x74, 0x69, 0x69  },
+       { 0x00, 0xff, 0xfe, 0x01, 0xfc, 0x03, 0x02, 0xfd,
+           0xf8, 0x07, 0x06, 0xf9, 0x04, 0xfb, 0xfa, 0x05  }
+};
+
+#endif /* defined(__x86_64) && (defined(HAVE_SSSE3) || defined(HAVE_AVX2)) */
index c9398e885fdafc40c955516ae432b3faf26ff58c..a8ccd2895501128c9caf368daa70fef1ac6bb626 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
 
@@ -162,8 +162,9 @@ zap_table_grow(zap_t *zap, zap_table_phys_t *tbl,
                newblk = zap_allocate_blocks(zap, tbl->zt_numblks * 2);
                tbl->zt_nextblk = newblk;
                ASSERT0(tbl->zt_blks_copied);
-               dmu_prefetch(zap->zap_objset, zap->zap_object,
-                   tbl->zt_blk << bs, tbl->zt_numblks << bs);
+               dmu_prefetch(zap->zap_objset, zap->zap_object, 0,
+                   tbl->zt_blk << bs, tbl->zt_numblks << bs,
+                   ZIO_PRIORITY_SYNC_READ);
        }
 
        /*
@@ -269,6 +270,7 @@ zap_table_load(zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, uint64_t *valp)
        uint64_t blk, off;
        int err;
        dmu_buf_t *db;
+       dnode_t *dn;
        int bs = FZAP_BLOCK_SHIFT(zap);
 
        ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
@@ -276,8 +278,15 @@ zap_table_load(zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, uint64_t *valp)
        blk = idx >> (bs-3);
        off = idx & ((1<<(bs-3))-1);
 
-       err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+       /*
+        * Note: this is equivalent to dmu_buf_hold(), but we use
+        * _dnode_enter / _by_dnode because it's faster because we don't
+        * have to hold the dnode.
+        */
+       dn = dmu_buf_dnode_enter(zap->zap_dbuf);
+       err = dmu_buf_hold_by_dnode(dn,
            (tbl->zt_blk + blk) << bs, FTAG, &db, DMU_READ_NO_PREFETCH);
+       dmu_buf_dnode_exit(zap->zap_dbuf);
        if (err)
                return (err);
        *valp = ((uint64_t *)db->db_data)[off];
@@ -291,9 +300,11 @@ zap_table_load(zap_t *zap, zap_table_phys_t *tbl, uint64_t idx, uint64_t *valp)
                 */
                blk = (idx*2) >> (bs-3);
 
-               err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+               dn = dmu_buf_dnode_enter(zap->zap_dbuf);
+               err = dmu_buf_hold_by_dnode(dn,
                    (tbl->zt_nextblk + blk) << bs, FTAG, &db,
                    DMU_READ_NO_PREFETCH);
+               dmu_buf_dnode_exit(zap->zap_dbuf);
                if (err == 0)
                        dmu_buf_rele(db, FTAG);
        }
@@ -404,7 +415,7 @@ zap_create_leaf(zap_t *zap, dmu_tx_t *tx)
 
        ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
 
-       rw_init(&l->l_rwlock, NULL, RW_DEFAULT, NULL);
+       rw_init(&l->l_rwlock, NULL, RW_NOLOCKDEP, NULL);
        rw_enter(&l->l_rwlock, RW_WRITER);
        l->l_blkid = zap_allocate_blocks(zap, 1);
        l->l_dbuf = NULL;
@@ -501,6 +512,7 @@ zap_get_leaf_byblk(zap_t *zap, uint64_t blkid, dmu_tx_t *tx, krw_t lt,
        zap_leaf_t *l;
        int bs = FZAP_BLOCK_SHIFT(zap);
        int err;
+       dnode_t *dn;
 
        ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
 
@@ -514,8 +526,10 @@ zap_get_leaf_byblk(zap_t *zap, uint64_t blkid, dmu_tx_t *tx, krw_t lt,
        if (blkid == 0)
                return (ENOENT);
 
-       err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
+       dn = dmu_buf_dnode_enter(zap->zap_dbuf);
+       err = dmu_buf_hold_by_dnode(dn,
            blkid << bs, NULL, &db, DMU_READ_NO_PREFETCH);
+       dmu_buf_dnode_exit(zap->zap_dbuf);
        if (err)
                return (err);
 
@@ -584,7 +598,13 @@ zap_deref_leaf(zap_t *zap, uint64_t h, dmu_tx_t *tx, krw_t lt, zap_leaf_t **lp)
 
        ASSERT(zap->zap_dbuf == NULL ||
            zap_f_phys(zap) == zap->zap_dbuf->db_data);
-       ASSERT3U(zap_f_phys(zap)->zap_magic, ==, ZAP_MAGIC);
+
+       /* Reality check for corrupt zap objects (leaf or header). */
+       if ((zap_f_phys(zap)->zap_block_type != ZBT_LEAF &&
+           zap_f_phys(zap)->zap_block_type != ZBT_HEADER) ||
+           zap_f_phys(zap)->zap_magic != ZAP_MAGIC) {
+               return (SET_ERROR(EIO));
+       }
        idx = ZAP_HASH_IDX(h, zap_f_phys(zap)->zap_ptrtbl.zt_shift);
        err = zap_idx_to_blk(zap, idx, &blk);
        if (err != 0)
@@ -598,7 +618,8 @@ zap_deref_leaf(zap_t *zap, uint64_t h, dmu_tx_t *tx, krw_t lt, zap_leaf_t **lp)
 }
 
 static int
-zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx, zap_leaf_t **lp)
+zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l,
+    void *tag, dmu_tx_t *tx, zap_leaf_t **lp)
 {
        zap_t *zap = zn->zn_zap;
        uint64_t hash = zn->zn_hash;
@@ -620,9 +641,9 @@ zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx, zap_leaf_t **lp)
                uint64_t object = zap->zap_object;
 
                zap_put_leaf(l);
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, tag);
                err = zap_lockdir(os, object, tx, RW_WRITER,
-                   FALSE, FALSE, &zn->zn_zap);
+                   FALSE, FALSE, tag, &zn->zn_zap);
                zap = zn->zn_zap;
                if (err)
                        return (err);
@@ -672,6 +693,8 @@ zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx, zap_leaf_t **lp)
                ASSERT0(err); /* we checked for i/o errors above */
        }
 
+       ASSERT3U(zap_leaf_phys(l)->l_hdr.lh_prefix_len, >, 0);
+
        if (hash & (1ULL << (64 - zap_leaf_phys(l)->l_hdr.lh_prefix_len))) {
                /* we want the sibling */
                zap_put_leaf(l);
@@ -685,7 +708,8 @@ zap_expand_leaf(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx, zap_leaf_t **lp)
 }
 
 static void
-zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx)
+zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l,
+    void *tag, dmu_tx_t *tx)
 {
        zap_t *zap = zn->zn_zap;
        int shift = zap_f_phys(zap)->zap_ptrtbl.zt_shift;
@@ -705,9 +729,9 @@ zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx)
                        objset_t *os = zap->zap_objset;
                        uint64_t zapobj = zap->zap_object;
 
-                       zap_unlockdir(zap);
+                       zap_unlockdir(zap, tag);
                        err = zap_lockdir(os, zapobj, tx,
-                           RW_WRITER, FALSE, FALSE, &zn->zn_zap);
+                           RW_WRITER, FALSE, FALSE, tag, &zn->zn_zap);
                        zap = zn->zn_zap;
                        if (err)
                                return;
@@ -797,7 +821,7 @@ fzap_lookup(zap_name_t *zn,
 int
 fzap_add_cd(zap_name_t *zn,
     uint64_t integer_size, uint64_t num_integers,
-    const void *val, uint32_t cd, dmu_tx_t *tx)
+    const void *val, uint32_t cd, void *tag, dmu_tx_t *tx)
 {
        zap_leaf_t *l;
        int err;
@@ -826,7 +850,7 @@ retry:
        if (err == 0) {
                zap_increment_num_entries(zap, 1, tx);
        } else if (err == EAGAIN) {
-               err = zap_expand_leaf(zn, l, tx, &l);
+               err = zap_expand_leaf(zn, l, tag, tx, &l);
                zap = zn->zn_zap;       /* zap_expand_leaf() may change zap */
                if (err == 0)
                        goto retry;
@@ -834,26 +858,27 @@ retry:
 
 out:
        if (zap != NULL)
-               zap_put_leaf_maybe_grow_ptrtbl(zn, l, tx);
+               zap_put_leaf_maybe_grow_ptrtbl(zn, l, tag, tx);
        return (err);
 }
 
 int
 fzap_add(zap_name_t *zn,
     uint64_t integer_size, uint64_t num_integers,
-    const void *val, dmu_tx_t *tx)
+    const void *val, void *tag, dmu_tx_t *tx)
 {
        int err = fzap_check(zn, integer_size, num_integers);
        if (err != 0)
                return (err);
 
        return (fzap_add_cd(zn, integer_size, num_integers,
-           val, ZAP_NEED_CD, tx));
+           val, ZAP_NEED_CD, tag, tx));
 }
 
 int
 fzap_update(zap_name_t *zn,
-    int integer_size, uint64_t num_integers, const void *val, dmu_tx_t *tx)
+    int integer_size, uint64_t num_integers, const void *val,
+    void *tag, dmu_tx_t *tx)
 {
        zap_leaf_t *l;
        int err, create;
@@ -883,14 +908,14 @@ retry:
        }
 
        if (err == EAGAIN) {
-               err = zap_expand_leaf(zn, l, tx, &l);
+               err = zap_expand_leaf(zn, l, tag, tx, &l);
                zap = zn->zn_zap;       /* zap_expand_leaf() may change zap */
                if (err == 0)
                        goto retry;
        }
 
        if (zap != NULL)
-               zap_put_leaf_maybe_grow_ptrtbl(zn, l, tx);
+               zap_put_leaf_maybe_grow_ptrtbl(zn, l, tag, tx);
        return (err);
 }
 
@@ -949,7 +974,8 @@ fzap_prefetch(zap_name_t *zn)
        if (zap_idx_to_blk(zap, idx, &blk) != 0)
                return;
        bs = FZAP_BLOCK_SHIFT(zap);
-       dmu_prefetch(zap->zap_objset, zap->zap_object, blk << bs, 1 << bs);
+       dmu_prefetch(zap->zap_objset, zap->zap_object, 0, blk << bs, 1 << bs,
+           ZIO_PRIORITY_SYNC_READ);
 }
 
 /*
@@ -959,12 +985,20 @@ fzap_prefetch(zap_name_t *zn)
 uint64_t
 zap_create_link(objset_t *os, dmu_object_type_t ot, uint64_t parent_obj,
     const char *name, dmu_tx_t *tx)
+{
+       return (zap_create_link_dnsize(os, ot, parent_obj, name, 0, tx));
+}
+
+uint64_t
+zap_create_link_dnsize(objset_t *os, dmu_object_type_t ot, uint64_t parent_obj,
+    const char *name, int dnodesize, dmu_tx_t *tx)
 {
        uint64_t new_obj;
 
-       VERIFY((new_obj = zap_create(os, ot, DMU_OT_NONE, 0, tx)) > 0);
-       VERIFY(zap_add(os, parent_obj, name, sizeof (uint64_t), 1, &new_obj,
-           tx) == 0);
+       VERIFY((new_obj = zap_create_dnsize(os, ot, DMU_OT_NONE, 0,
+           dnodesize, tx)) > 0);
+       VERIFY0(zap_add(os, parent_obj, name, sizeof (uint64_t), 1, &new_obj,
+           tx));
 
        return (new_obj);
 }
@@ -1198,17 +1232,23 @@ again:
        err = zap_leaf_lookup_closest(l, zc->zc_hash, zc->zc_cd, &zeh);
 
        if (err == ENOENT) {
-               uint64_t nocare =
-                   (1ULL << (64 - zap_leaf_phys(l)->l_hdr.lh_prefix_len)) - 1;
-               zc->zc_hash = (zc->zc_hash & ~nocare) + nocare + 1;
-               zc->zc_cd = 0;
-               if (zap_leaf_phys(l)->l_hdr.lh_prefix_len == 0 ||
-                   zc->zc_hash == 0) {
+               if (zap_leaf_phys(l)->l_hdr.lh_prefix_len == 0) {
                        zc->zc_hash = -1ULL;
+                       zc->zc_cd = 0;
                } else {
-                       zap_put_leaf(zc->zc_leaf);
-                       zc->zc_leaf = NULL;
-                       goto again;
+                       uint64_t nocare = (1ULL <<
+                           (64 - zap_leaf_phys(l)->l_hdr.lh_prefix_len)) - 1;
+
+                       zc->zc_hash = (zc->zc_hash & ~nocare) + nocare + 1;
+                       zc->zc_cd = 0;
+
+                       if (zc->zc_hash == 0) {
+                               zc->zc_hash = -1ULL;
+                       } else {
+                               zap_put_leaf(zc->zc_leaf);
+                               zc->zc_leaf = NULL;
+                               goto again;
+                       }
                }
        }
 
@@ -1295,9 +1335,10 @@ fzap_get_stats(zap_t *zap, zap_stats_t *zs)
        } else {
                int b;
 
-               dmu_prefetch(zap->zap_objset, zap->zap_object,
+               dmu_prefetch(zap->zap_objset, zap->zap_object, 0,
                    zap_f_phys(zap)->zap_ptrtbl.zt_blk << bs,
-                   zap_f_phys(zap)->zap_ptrtbl.zt_numblks << bs);
+                   zap_f_phys(zap)->zap_ptrtbl.zt_numblks << bs,
+                   ZIO_PRIORITY_SYNC_READ);
 
                for (b = 0; b < zap_f_phys(zap)->zap_ptrtbl.zt_numblks;
                    b++) {
index 85b465b0528465fd8673fecebafe5367526c55c5..a15e22c5bec5f38514e9158dcd663bd2eeff955c 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  */
 
@@ -42,7 +42,8 @@
 
 extern inline mzap_phys_t *zap_m_phys(zap_t *zap);
 
-static int mzap_upgrade(zap_t **zapp, dmu_tx_t *tx, zap_flags_t flags);
+static int mzap_upgrade(zap_t **zapp,
+    void *tag, dmu_tx_t *tx, zap_flags_t flags);
 
 uint64_t
 zap_getflags(zap_t *zap)
@@ -256,15 +257,11 @@ mze_compare(const void *arg1, const void *arg2)
        const mzap_ent_t *mze1 = arg1;
        const mzap_ent_t *mze2 = arg2;
 
-       if (mze1->mze_hash > mze2->mze_hash)
-               return (+1);
-       if (mze1->mze_hash < mze2->mze_hash)
-               return (-1);
-       if (mze1->mze_cd > mze2->mze_cd)
-               return (+1);
-       if (mze1->mze_cd < mze2->mze_cd)
-               return (-1);
-       return (0);
+       int cmp = AVL_CMP(mze1->mze_hash, mze2->mze_hash);
+       if (likely(cmp))
+               return (cmp);
+
+       return (AVL_CMP(mze1->mze_cd, mze2->mze_cd));
 }
 
 static void
@@ -366,6 +363,9 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
        zap_t *winner;
        zap_t *zap;
        int i;
+       uint64_t *zap_hdr = (uint64_t *)db->db_data;
+       uint64_t zap_block_type = zap_hdr[0];
+       uint64_t zap_magic = zap_hdr[1];
 
        ASSERT3U(MZAP_ENT_LEN, ==, sizeof (mzap_ent_phys_t));
 
@@ -376,9 +376,13 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
        zap->zap_object = obj;
        zap->zap_dbuf = db;
 
-       if (*(uint64_t *)db->db_data != ZBT_MICRO) {
+       if (zap_block_type != ZBT_MICRO) {
                mutex_init(&zap->zap_f.zap_num_entries_mtx, 0, 0, 0);
                zap->zap_f.zap_block_shift = highbit64(db->db_size) - 1;
+               if (zap_block_type != ZBT_HEADER || zap_magic != ZAP_MAGIC) {
+                       winner = NULL;  /* No actual winner here... */
+                       goto handle_winner;
+               }
        } else {
                zap->zap_ismicro = TRUE;
        }
@@ -391,14 +395,8 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
        dmu_buf_init_user(&zap->zap_dbu, zap_evict, &zap->zap_dbuf);
        winner = dmu_buf_set_user(db, &zap->zap_dbu);
 
-       if (winner != NULL) {
-               rw_exit(&zap->zap_rwlock);
-               rw_destroy(&zap->zap_rwlock);
-               if (!zap->zap_ismicro)
-                       mutex_destroy(&zap->zap_f.zap_num_entries_mtx);
-               kmem_free(zap, sizeof (zap_t));
-               return (winner);
-       }
+       if (winner != NULL)
+               goto handle_winner;
 
        if (zap->zap_ismicro) {
                zap->zap_salt = zap_m_phys(zap)->mz_salt;
@@ -445,31 +443,45 @@ mzap_open(objset_t *os, uint64_t obj, dmu_buf_t *db)
        }
        rw_exit(&zap->zap_rwlock);
        return (zap);
+
+handle_winner:
+       rw_exit(&zap->zap_rwlock);
+       rw_destroy(&zap->zap_rwlock);
+       if (!zap->zap_ismicro)
+               mutex_destroy(&zap->zap_f.zap_num_entries_mtx);
+       kmem_free(zap, sizeof (zap_t));
+       return (winner);
 }
 
-int
-zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
+static int
+zap_lockdir_impl(dmu_buf_t *db, void *tag, dmu_tx_t *tx,
     krw_t lti, boolean_t fatreader, boolean_t adding, zap_t **zapp)
 {
        dmu_object_info_t doi;
        zap_t *zap;
-       dmu_buf_t *db;
        krw_t lt;
-       int err;
 
-       *zapp = NULL;
+       objset_t *os = dmu_buf_get_objset(db);
+       uint64_t obj = db->db_object;
 
-       err = dmu_buf_hold(os, obj, 0, NULL, &db, DMU_READ_NO_PREFETCH);
-       if (err)
-               return (err);
+       ASSERT0(db->db_offset);
+       *zapp = NULL;
 
        dmu_object_info_from_db(db, &doi);
        if (DMU_OT_BYTESWAP(doi.doi_type) != DMU_BSWAP_ZAP)
                return (SET_ERROR(EINVAL));
 
        zap = dmu_buf_get_user(db);
-       if (zap == NULL)
+       if (zap == NULL) {
                zap = mzap_open(os, obj, db);
+               if (zap == NULL) {
+                       /*
+                        * mzap_open() didn't like what it saw on-disk.
+                        * Check for corruption!
+                        */
+                       return (SET_ERROR(EIO));
+               }
+       }
 
        /*
         * We're checking zap_ismicro without the lock held, in order to
@@ -502,13 +514,16 @@ zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
            zap->zap_m.zap_num_entries == zap->zap_m.zap_num_chunks) {
                uint64_t newsz = db->db_size + SPA_MINBLOCKSIZE;
                if (newsz > MZAP_MAX_BLKSZ) {
+                       int err;
                        dprintf("upgrading obj %llu: num_entries=%u\n",
                            obj, zap->zap_m.zap_num_entries);
                        *zapp = zap;
-                       return (mzap_upgrade(zapp, tx, 0));
+                       err = mzap_upgrade(zapp, tag, tx, 0);
+                       if (err != 0)
+                               rw_exit(&zap->zap_rwlock);
+                       return (err);
                }
-               err = dmu_object_set_blocksize(os, obj, newsz, 0, tx);
-               ASSERT0(err);
+               VERIFY0(dmu_object_set_blocksize(os, obj, newsz, 0, tx));
                zap->zap_m.zap_num_chunks =
                    db->db_size / MZAP_ENT_LEN - 1;
        }
@@ -517,15 +532,49 @@ zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
        return (0);
 }
 
+static int
+zap_lockdir_by_dnode(dnode_t *dn, dmu_tx_t *tx,
+    krw_t lti, boolean_t fatreader, boolean_t adding, void *tag, zap_t **zapp)
+{
+       dmu_buf_t *db;
+       int err;
+
+       err = dmu_buf_hold_by_dnode(dn, 0, tag, &db, DMU_READ_NO_PREFETCH);
+       if (err != 0) {
+               return (err);
+       }
+       err = zap_lockdir_impl(db, tag, tx, lti, fatreader, adding, zapp);
+       if (err != 0) {
+               dmu_buf_rele(db, tag);
+       }
+       return (err);
+}
+
+int
+zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
+    krw_t lti, boolean_t fatreader, boolean_t adding, void *tag, zap_t **zapp)
+{
+       dmu_buf_t *db;
+       int err;
+
+       err = dmu_buf_hold(os, obj, 0, tag, &db, DMU_READ_NO_PREFETCH);
+       if (err != 0)
+               return (err);
+       err = zap_lockdir_impl(db, tag, tx, lti, fatreader, adding, zapp);
+       if (err != 0)
+               dmu_buf_rele(db, tag);
+       return (err);
+}
+
 void
-zap_unlockdir(zap_t *zap)
+zap_unlockdir(zap_t *zap, void *tag)
 {
        rw_exit(&zap->zap_rwlock);
-       dmu_buf_rele(zap->zap_dbuf, NULL);
+       dmu_buf_rele(zap->zap_dbuf, tag);
 }
 
 static int
-mzap_upgrade(zap_t **zapp, dmu_tx_t *tx, zap_flags_t flags)
+mzap_upgrade(zap_t **zapp, void *tag, dmu_tx_t *tx, zap_flags_t flags)
 {
        mzap_phys_t *mzp;
        int i, sz, nchunks;
@@ -563,7 +612,8 @@ mzap_upgrade(zap_t **zapp, dmu_tx_t *tx, zap_flags_t flags)
                dprintf("adding %s=%llu\n",
                    mze->mze_name, mze->mze_value);
                zn = zap_name_alloc(zap, mze->mze_name, MT_EXACT);
-               err = fzap_add_cd(zn, 8, 1, &mze->mze_value, mze->mze_cd, tx);
+               err = fzap_add_cd(zn, 8, 1, &mze->mze_value, mze->mze_cd,
+                   tag, tx);
                zap = zn->zn_zap;       /* fzap_add_cd() may change zap */
                zap_name_free(zn);
                if (err)
@@ -602,9 +652,9 @@ mzap_create_impl(objset_t *os, uint64_t obj, int normflags, zap_flags_t flags,
                zap_t *zap;
                /* Only fat zap supports flags; upgrade immediately. */
                VERIFY(0 == zap_lockdir(os, obj, tx, RW_WRITER,
-                   B_FALSE, B_FALSE, &zap));
-               VERIFY3U(0, ==, mzap_upgrade(&zap, tx, flags));
-               zap_unlockdir(zap);
+                   B_FALSE, B_FALSE, FTAG, &zap));
+               VERIFY3U(0, ==, mzap_upgrade(&zap, FTAG, tx, flags));
+               zap_unlockdir(zap, FTAG);
        }
 }
 
@@ -612,18 +662,36 @@ int
 zap_create_claim(objset_t *os, uint64_t obj, dmu_object_type_t ot,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
 {
-       return (zap_create_claim_norm(os, obj,
-           0, ot, bonustype, bonuslen, tx));
+       return (zap_create_claim_dnsize(os, obj, ot, bonustype, bonuslen,
+           0, tx));
+}
+
+int
+zap_create_claim_dnsize(objset_t *os, uint64_t obj, dmu_object_type_t ot,
+    dmu_object_type_t bonustype, int bonuslen, int dnodesize, dmu_tx_t *tx)
+{
+       return (zap_create_claim_norm_dnsize(os, obj,
+           0, ot, bonustype, bonuslen, dnodesize, tx));
 }
 
 int
 zap_create_claim_norm(objset_t *os, uint64_t obj, int normflags,
     dmu_object_type_t ot,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
+{
+       return (zap_create_claim_norm_dnsize(os, obj, normflags, ot, bonustype,
+           bonuslen, 0, tx));
+}
+
+int
+zap_create_claim_norm_dnsize(objset_t *os, uint64_t obj, int normflags,
+    dmu_object_type_t ot, dmu_object_type_t bonustype, int bonuslen,
+    int dnodesize, dmu_tx_t *tx)
 {
        int err;
 
-       err = dmu_object_claim(os, obj, ot, 0, bonustype, bonuslen, tx);
+       err = dmu_object_claim_dnsize(os, obj, ot, 0, bonustype, bonuslen,
+           dnodesize, tx);
        if (err != 0)
                return (err);
        mzap_create_impl(os, obj, normflags, 0, tx);
@@ -637,11 +705,28 @@ zap_create(objset_t *os, dmu_object_type_t ot,
        return (zap_create_norm(os, 0, ot, bonustype, bonuslen, tx));
 }
 
+uint64_t
+zap_create_dnsize(objset_t *os, dmu_object_type_t ot,
+    dmu_object_type_t bonustype, int bonuslen, int dnodesize, dmu_tx_t *tx)
+{
+       return (zap_create_norm_dnsize(os, 0, ot, bonustype, bonuslen,
+           dnodesize, tx));
+}
+
 uint64_t
 zap_create_norm(objset_t *os, int normflags, dmu_object_type_t ot,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
 {
-       uint64_t obj = dmu_object_alloc(os, ot, 0, bonustype, bonuslen, tx);
+       return (zap_create_norm_dnsize(os, normflags, ot, bonustype, bonuslen,
+           0, tx));
+}
+
+uint64_t
+zap_create_norm_dnsize(objset_t *os, int normflags, dmu_object_type_t ot,
+    dmu_object_type_t bonustype, int bonuslen, int dnodesize, dmu_tx_t *tx)
+{
+       uint64_t obj = dmu_object_alloc_dnsize(os, ot, 0, bonustype, bonuslen,
+           dnodesize, tx);
 
        mzap_create_impl(os, obj, normflags, 0, tx);
        return (obj);
@@ -652,7 +737,17 @@ zap_create_flags(objset_t *os, int normflags, zap_flags_t flags,
     dmu_object_type_t ot, int leaf_blockshift, int indirect_blockshift,
     dmu_object_type_t bonustype, int bonuslen, dmu_tx_t *tx)
 {
-       uint64_t obj = dmu_object_alloc(os, ot, 0, bonustype, bonuslen, tx);
+       return (zap_create_flags_dnsize(os, normflags, flags, ot,
+           leaf_blockshift, indirect_blockshift, bonustype, bonuslen, 0, tx));
+}
+
+uint64_t
+zap_create_flags_dnsize(objset_t *os, int normflags, zap_flags_t flags,
+    dmu_object_type_t ot, int leaf_blockshift, int indirect_blockshift,
+    dmu_object_type_t bonustype, int bonuslen, int dnodesize, dmu_tx_t *tx)
+{
+       uint64_t obj = dmu_object_alloc_dnsize(os, ot, 0, bonustype, bonuslen,
+           dnodesize, tx);
 
        ASSERT(leaf_blockshift >= SPA_MINBLOCKSHIFT &&
            leaf_blockshift <= SPA_OLD_MAXBLOCKSHIFT &&
@@ -699,7 +794,7 @@ zap_count(objset_t *os, uint64_t zapobj, uint64_t *count)
        zap_t *zap;
        int err;
 
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
        if (!zap->zap_ismicro) {
@@ -707,7 +802,7 @@ zap_count(objset_t *os, uint64_t zapobj, uint64_t *count)
        } else {
                *count = zap->zap_m.zap_num_entries;
        }
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -764,25 +859,19 @@ zap_lookup(objset_t *os, uint64_t zapobj, const char *name,
            num_integers, buf, MT_EXACT, NULL, 0, NULL));
 }
 
-int
-zap_lookup_norm(objset_t *os, uint64_t zapobj, const char *name,
+static int
+zap_lookup_impl(zap_t *zap, const char *name,
     uint64_t integer_size, uint64_t num_integers, void *buf,
     matchtype_t mt, char *realname, int rn_len,
     boolean_t *ncp)
 {
-       zap_t *zap;
-       int err;
+       int err = 0;
        mzap_ent_t *mze;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
-       if (err)
-               return (err);
        zn = zap_name_alloc(zap, name, mt);
-       if (zn == NULL) {
-               zap_unlockdir(zap);
+       if (zn == NULL)
                return (SET_ERROR(ENOTSUP));
-       }
 
        if (!zap->zap_ismicro) {
                err = fzap_lookup(zn, integer_size, num_integers, buf,
@@ -809,7 +898,24 @@ zap_lookup_norm(objset_t *os, uint64_t zapobj, const char *name,
                }
        }
        zap_name_free(zn);
-       zap_unlockdir(zap);
+       return (err);
+}
+
+int
+zap_lookup_norm(objset_t *os, uint64_t zapobj, const char *name,
+    uint64_t integer_size, uint64_t num_integers, void *buf,
+    matchtype_t mt, char *realname, int rn_len,
+    boolean_t *ncp)
+{
+       zap_t *zap;
+       int err;
+
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
+       if (err != 0)
+               return (err);
+       err = zap_lookup_impl(zap, name, integer_size,
+           num_integers, buf, mt, realname, rn_len, ncp);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -820,18 +926,45 @@ zap_prefetch(objset_t *os, uint64_t zapobj, const char *name)
        int err;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc(zap, name, MT_EXACT);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
 
        fzap_prefetch(zn);
        zap_name_free(zn);
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
+       return (err);
+}
+
+int
+zap_lookup_by_dnode(dnode_t *dn, const char *name,
+    uint64_t integer_size, uint64_t num_integers, void *buf)
+{
+       return (zap_lookup_norm_by_dnode(dn, name, integer_size,
+           num_integers, buf, MT_EXACT, NULL, 0, NULL));
+}
+
+int
+zap_lookup_norm_by_dnode(dnode_t *dn, const char *name,
+    uint64_t integer_size, uint64_t num_integers, void *buf,
+    matchtype_t mt, char *realname, int rn_len,
+    boolean_t *ncp)
+{
+       zap_t *zap;
+       int err;
+
+       err = zap_lockdir_by_dnode(dn, NULL, RW_READER, TRUE, FALSE,
+           FTAG, &zap);
+       if (err != 0)
+               return (err);
+       err = zap_lookup_impl(zap, name, integer_size,
+           num_integers, buf, mt, realname, rn_len, ncp);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -843,18 +976,18 @@ zap_prefetch_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
        int err;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc_uint64(zap, key, key_numints);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
 
        fzap_prefetch(zn);
        zap_name_free(zn);
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -866,19 +999,19 @@ zap_lookup_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
        int err;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc_uint64(zap, key, key_numints);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
 
        err = fzap_lookup(zn, integer_size, num_integers, buf,
            NULL, 0, NULL);
        zap_name_free(zn);
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -901,12 +1034,12 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name,
        mzap_ent_t *mze;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc(zap, name, MT_EXACT);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
        if (!zap->zap_ismicro) {
@@ -923,7 +1056,7 @@ zap_length(objset_t *os, uint64_t zapobj, const char *name,
                }
        }
        zap_name_free(zn);
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -935,17 +1068,17 @@ zap_length_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
        int err;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc_uint64(zap, key, key_numints);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
        err = fzap_length(zn, integer_size, num_integers);
        zap_name_free(zn);
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -977,7 +1110,8 @@ again:
                if (mze->mze_name[0] == 0) {
                        mze->mze_value = value;
                        mze->mze_cd = cd;
-                       (void) strcpy(mze->mze_name, zn->zn_key_orig);
+                       (void) strlcpy(mze->mze_name, zn->zn_key_orig,
+                           sizeof (mze->mze_name));
                        zap->zap_m.zap_num_entries++;
                        zap->zap_m.zap_alloc_next = i+1;
                        if (zap->zap_m.zap_alloc_next ==
@@ -1005,22 +1139,24 @@ zap_add(objset_t *os, uint64_t zapobj, const char *key,
        const uint64_t *intval = val;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap);
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc(zap, key, MT_EXACT);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
        if (!zap->zap_ismicro) {
-               err = fzap_add(zn, integer_size, num_integers, val, tx);
+               err = fzap_add(zn, integer_size, num_integers, val, FTAG, tx);
                zap = zn->zn_zap;       /* fzap_add() may change zap */
        } else if (integer_size != 8 || num_integers != 1 ||
            strlen(key) >= MZAP_NAME_LEN) {
-               err = mzap_upgrade(&zn->zn_zap, tx, 0);
-               if (err == 0)
-                       err = fzap_add(zn, integer_size, num_integers, val, tx);
+               err = mzap_upgrade(&zn->zn_zap, FTAG, tx, 0);
+               if (err == 0) {
+                       err = fzap_add(zn, integer_size, num_integers, val,
+                           FTAG, tx);
+               }
                zap = zn->zn_zap;       /* fzap_add() may change zap */
        } else {
                mze = mze_find(zn);
@@ -1033,7 +1169,7 @@ zap_add(objset_t *os, uint64_t zapobj, const char *key,
        ASSERT(zap == zn->zn_zap);
        zap_name_free(zn);
        if (zap != NULL)        /* may be NULL if fzap_add() failed */
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -1046,19 +1182,19 @@ zap_add_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
        int err;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap);
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc_uint64(zap, key, key_numints);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
-       err = fzap_add(zn, integer_size, num_integers, val, tx);
+       err = fzap_add(zn, integer_size, num_integers, val, FTAG, tx);
        zap = zn->zn_zap;       /* fzap_add() may change zap */
        zap_name_free(zn);
        if (zap != NULL)        /* may be NULL if fzap_add() failed */
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -1083,25 +1219,27 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name,
                (void) zap_lookup(os, zapobj, name, 8, 1, &oldval);
 #endif
 
-       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap);
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc(zap, name, MT_EXACT);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
        if (!zap->zap_ismicro) {
-               err = fzap_update(zn, integer_size, num_integers, val, tx);
+               err = fzap_update(zn, integer_size, num_integers, val,
+                   FTAG, tx);
                zap = zn->zn_zap;       /* fzap_update() may change zap */
        } else if (integer_size != 8 || num_integers != 1 ||
            strlen(name) >= MZAP_NAME_LEN) {
                dprintf("upgrading obj %llu: intsz=%u numint=%llu name=%s\n",
                    zapobj, integer_size, num_integers, name);
-               err = mzap_upgrade(&zn->zn_zap, tx, 0);
-               if (err == 0)
+               err = mzap_upgrade(&zn->zn_zap, FTAG, tx, 0);
+               if (err == 0) {
                        err = fzap_update(zn, integer_size, num_integers,
-                           val, tx);
+                           val, FTAG, tx);
+               }
                zap = zn->zn_zap;       /* fzap_update() may change zap */
        } else {
                mze = mze_find(zn);
@@ -1115,7 +1253,7 @@ zap_update(objset_t *os, uint64_t zapobj, const char *name,
        ASSERT(zap == zn->zn_zap);
        zap_name_free(zn);
        if (zap != NULL)        /* may be NULL if fzap_upgrade() failed */
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -1128,19 +1266,19 @@ zap_update_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
        zap_name_t *zn;
        int err;
 
-       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, &zap);
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, TRUE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc_uint64(zap, key, key_numints);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
-       err = fzap_update(zn, integer_size, num_integers, val, tx);
+       err = fzap_update(zn, integer_size, num_integers, val, FTAG, tx);
        zap = zn->zn_zap;       /* fzap_update() may change zap */
        zap_name_free(zn);
        if (zap != NULL)        /* may be NULL if fzap_upgrade() failed */
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -1159,12 +1297,12 @@ zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name,
        mzap_ent_t *mze;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc(zap, name, mt);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
        if (!zap->zap_ismicro) {
@@ -1181,7 +1319,7 @@ zap_remove_norm(objset_t *os, uint64_t zapobj, const char *name,
                }
        }
        zap_name_free(zn);
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -1193,17 +1331,17 @@ zap_remove_uint64(objset_t *os, uint64_t zapobj, const uint64_t *key,
        int err;
        zap_name_t *zn;
 
-       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, tx, RW_WRITER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
        zn = zap_name_alloc_uint64(zap, key, key_numints);
        if (zn == NULL) {
-               zap_unlockdir(zap);
+               zap_unlockdir(zap, FTAG);
                return (SET_ERROR(ENOTSUP));
        }
        err = fzap_remove(zn, tx);
        zap_name_free(zn);
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
@@ -1235,7 +1373,7 @@ zap_cursor_fini(zap_cursor_t *zc)
 {
        if (zc->zc_zap) {
                rw_enter(&zc->zc_zap->zap_rwlock, RW_READER);
-               zap_unlockdir(zc->zc_zap);
+               zap_unlockdir(zc->zc_zap, NULL);
                zc->zc_zap = NULL;
        }
        if (zc->zc_leaf) {
@@ -1282,7 +1420,7 @@ zap_cursor_retrieve(zap_cursor_t *zc, zap_attribute_t *za)
        if (zc->zc_zap == NULL) {
                int hb;
                err = zap_lockdir(zc->zc_objset, zc->zc_zapobj, NULL,
-                   RW_READER, TRUE, FALSE, &zc->zc_zap);
+                   RW_READER, TRUE, FALSE, NULL, &zc->zc_zap);
                if (err)
                        return (err);
 
@@ -1346,7 +1484,7 @@ zap_get_stats(objset_t *os, uint64_t zapobj, zap_stats_t *zs)
        int err;
        zap_t *zap;
 
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
+       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, FTAG, &zap);
        if (err)
                return (err);
 
@@ -1359,12 +1497,12 @@ zap_get_stats(objset_t *os, uint64_t zapobj, zap_stats_t *zs)
        } else {
                fzap_get_stats(zap, zs);
        }
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (0);
 }
 
 int
-zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
+zap_count_write_by_dnode(dnode_t *dn, const char *name, int add,
     uint64_t *towrite, uint64_t *tooverwrite)
 {
        zap_t *zap;
@@ -1378,7 +1516,7 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
         *      - 2 blocks for possibly split leaves,
         *      - 2 grown ptrtbl blocks
         *
-        * This also accomodates the case where an add operation to a fairly
+        * This also accommodates the case where an add operation to a fairly
         * large microzap results in a promotion to fatzap.
         */
        if (name == NULL) {
@@ -1390,10 +1528,11 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
         * We lock the zap with adding == FALSE. Because, if we pass
         * the actual value of add, it could trigger a mzap_upgrade().
         * At present we are just evaluating the possibility of this operation
-        * and hence we donot want to trigger an upgrade.
+        * and hence we do not want to trigger an upgrade.
         */
-       err = zap_lockdir(os, zapobj, NULL, RW_READER, TRUE, FALSE, &zap);
-       if (err)
+       err = zap_lockdir_by_dnode(dn, NULL, RW_READER, TRUE, FALSE,
+           FTAG, &zap);
+       if (err != 0)
                return (err);
 
        if (!zap->zap_ismicro) {
@@ -1434,16 +1573,20 @@ zap_count_write(objset_t *os, uint64_t zapobj, const char *name, int add,
                }
        }
 
-       zap_unlockdir(zap);
+       zap_unlockdir(zap, FTAG);
        return (err);
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
 EXPORT_SYMBOL(zap_create);
+EXPORT_SYMBOL(zap_create_dnsize);
 EXPORT_SYMBOL(zap_create_norm);
+EXPORT_SYMBOL(zap_create_norm_dnsize);
 EXPORT_SYMBOL(zap_create_flags);
+EXPORT_SYMBOL(zap_create_flags_dnsize);
 EXPORT_SYMBOL(zap_create_claim);
 EXPORT_SYMBOL(zap_create_claim_norm);
+EXPORT_SYMBOL(zap_create_claim_norm_dnsize);
 EXPORT_SYMBOL(zap_destroy);
 EXPORT_SYMBOL(zap_lookup);
 EXPORT_SYMBOL(zap_lookup_norm);
@@ -1451,7 +1594,7 @@ EXPORT_SYMBOL(zap_lookup_uint64);
 EXPORT_SYMBOL(zap_contains);
 EXPORT_SYMBOL(zap_prefetch);
 EXPORT_SYMBOL(zap_prefetch_uint64);
-EXPORT_SYMBOL(zap_count_write);
+EXPORT_SYMBOL(zap_count_write_by_dnode);
 EXPORT_SYMBOL(zap_add);
 EXPORT_SYMBOL(zap_add_uint64);
 EXPORT_SYMBOL(zap_update);
index 352376f22b9ed8a097efd37bb52d67a86ddb9b0c..bda9548293d0184bce777749a1ab30a06471dff6 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -253,7 +253,7 @@ feature_get_refcount_from_disk(spa_t *spa, zfeature_info_t *feature,
 {
        int err;
        uint64_t refcount;
-       uint64_t zapobj = feature->fi_can_readonly ?
+       uint64_t zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
 
        /*
@@ -306,7 +306,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
        uint64_t zapobj;
 
        ASSERT(VALID_FEATURE_OR_NONE(feature->fi_feature));
-       zapobj = feature->fi_can_readonly ?
+       zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
        VERIFY0(zap_update(spa->spa_meta_objset, zapobj, feature->fi_guid,
            sizeof (uint64_t), 1, &refcount, tx));
@@ -327,7 +327,7 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
 
        if (refcount == 0)
                spa_deactivate_mos_feature(spa, feature->fi_guid);
-       else if (feature->fi_mos)
+       else if (feature->fi_flags & ZFEATURE_FLAG_MOS)
                spa_activate_mos_feature(spa, feature->fi_guid, tx);
 }
 
@@ -338,8 +338,9 @@ feature_sync(spa_t *spa, zfeature_info_t *feature, uint64_t refcount,
 void
 feature_enable_sync(spa_t *spa, zfeature_info_t *feature, dmu_tx_t *tx)
 {
-       uint64_t initial_refcount = feature->fi_activate_on_enable ? 1 : 0;
-       uint64_t zapobj = feature->fi_can_readonly ?
+       uint64_t initial_refcount =
+           (feature->fi_flags & ZFEATURE_FLAG_ACTIVATE_ON_ENABLE) ? 1 : 0;
+       uint64_t zapobj = (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj;
        int i;
 
@@ -385,7 +386,8 @@ feature_do_action(spa_t *spa, spa_feature_t fid, feature_action_t action,
 {
        uint64_t refcount = 0;
        zfeature_info_t *feature = &spa_feature_table[fid];
-       ASSERTV(uint64_t zapobj = feature->fi_can_readonly ?
+       ASSERTV(uint64_t zapobj =
+           (feature->fi_flags & ZFEATURE_FLAG_READONLY_COMPAT) ?
            spa->spa_feat_for_write_obj : spa->spa_feat_for_read_obj);
 
        ASSERT(VALID_FEATURE_FID(fid));
index 609a72ab301a220e55aef68f53285b1dde433e0e..ccd65a7b74d9eeacaea22849041f9166d6c93cec 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
  */
@@ -135,15 +135,15 @@ zfeature_depends_on(spa_feature_t fid, spa_feature_t check) {
 
 static void
 zfeature_register(spa_feature_t fid, const char *guid, const char *name,
-    const char *desc, boolean_t readonly, boolean_t mos,
-    boolean_t activate_on_enable, const spa_feature_t *deps)
+    const char *desc, zfeature_flags_t flags, const spa_feature_t *deps)
 {
        zfeature_info_t *feature = &spa_feature_table[fid];
        static spa_feature_t nodeps[] = { SPA_FEATURE_NONE };
 
        ASSERT(name != NULL);
        ASSERT(desc != NULL);
-       ASSERT(!readonly || !mos);
+       ASSERT((flags & ZFEATURE_FLAG_READONLY_COMPAT) == 0 ||
+           (flags & ZFEATURE_FLAG_MOS) == 0);
        ASSERT3U(fid, <, SPA_FEATURES);
        ASSERT(zfeature_is_valid_guid(guid));
 
@@ -154,9 +154,7 @@ zfeature_register(spa_feature_t fid, const char *guid, const char *name,
        feature->fi_guid = guid;
        feature->fi_uname = name;
        feature->fi_desc = desc;
-       feature->fi_can_readonly = readonly;
-       feature->fi_mos = mos;
-       feature->fi_activate_on_enable = activate_on_enable;
+       feature->fi_flags = flags;
        feature->fi_depends = deps;
 }
 
@@ -165,28 +163,28 @@ zpool_feature_init(void)
 {
        zfeature_register(SPA_FEATURE_ASYNC_DESTROY,
            "com.delphix:async_destroy", "async_destroy",
-           "Destroy filesystems asynchronously.", B_TRUE, B_FALSE,
-           B_FALSE, NULL);
+           "Destroy filesystems asynchronously.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 
        zfeature_register(SPA_FEATURE_EMPTY_BPOBJ,
            "com.delphix:empty_bpobj", "empty_bpobj",
-           "Snapshots use less space.", B_TRUE, B_FALSE,
-           B_FALSE, NULL);
+           "Snapshots use less space.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 
        zfeature_register(SPA_FEATURE_LZ4_COMPRESS,
            "org.illumos:lz4_compress", "lz4_compress",
-           "LZ4 compression algorithm support.", B_FALSE, B_FALSE,
-           B_TRUE, NULL);
+           "LZ4 compression algorithm support.",
+           ZFEATURE_FLAG_ACTIVATE_ON_ENABLE, NULL);
 
        zfeature_register(SPA_FEATURE_SPACEMAP_HISTOGRAM,
            "com.delphix:spacemap_histogram", "spacemap_histogram",
-           "Spacemaps maintain space histograms.", B_TRUE, B_FALSE,
-           B_FALSE, NULL);
+           "Spacemaps maintain space histograms.",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 
        zfeature_register(SPA_FEATURE_ENABLED_TXG,
            "com.delphix:enabled_txg", "enabled_txg",
-           "Record txg at which a feature is enabled", B_TRUE, B_FALSE,
-           B_FALSE, NULL);
+           "Record txg at which a feature is enabled",
+           ZFEATURE_FLAG_READONLY_COMPAT, NULL);
 
        {
        static const spa_feature_t hole_birth_deps[] = {
@@ -196,13 +194,14 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_HOLE_BIRTH,
            "com.delphix:hole_birth", "hole_birth",
            "Retain hole birth txg for more precise zfs send",
-           B_FALSE, B_TRUE, B_TRUE, hole_birth_deps);
+           ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
+           hole_birth_deps);
        }
 
        zfeature_register(SPA_FEATURE_EXTENSIBLE_DATASET,
            "com.delphix:extensible_dataset", "extensible_dataset",
            "Enhanced dataset functionality, used by other features.",
-           B_FALSE, B_FALSE, B_FALSE, NULL);
+           0, NULL);
 
        {
        static const spa_feature_t bookmarks_deps[] = {
@@ -213,7 +212,7 @@ zpool_feature_init(void)
        zfeature_register(SPA_FEATURE_BOOKMARKS,
            "com.delphix:bookmarks", "bookmarks",
            "\"zfs bookmark\" command",
-           B_TRUE, B_FALSE, B_FALSE, bookmarks_deps);
+           ZFEATURE_FLAG_READONLY_COMPAT, bookmarks_deps);
        }
 
        {
@@ -223,14 +222,15 @@ zpool_feature_init(void)
        };
        zfeature_register(SPA_FEATURE_FS_SS_LIMIT,
            "com.joyent:filesystem_limits", "filesystem_limits",
-           "Filesystem and snapshot limits.", B_TRUE, B_FALSE, B_FALSE,
-           filesystem_limits_deps);
+           "Filesystem and snapshot limits.",
+           ZFEATURE_FLAG_READONLY_COMPAT, filesystem_limits_deps);
        }
 
        zfeature_register(SPA_FEATURE_EMBEDDED_DATA,
            "com.delphix:embedded_data", "embedded_data",
            "Blocks which compress very well use even less space.",
-           B_FALSE, B_TRUE, B_TRUE, NULL);
+           ZFEATURE_FLAG_MOS | ZFEATURE_FLAG_ACTIVATE_ON_ENABLE,
+           NULL);
 
        {
        static const spa_feature_t large_blocks_deps[] = {
@@ -239,7 +239,61 @@ zpool_feature_init(void)
        };
        zfeature_register(SPA_FEATURE_LARGE_BLOCKS,
            "org.open-zfs:large_blocks", "large_blocks",
-           "Support for blocks larger than 128KB.", B_FALSE, B_FALSE, B_FALSE,
-           large_blocks_deps);
+           "Support for blocks larger than 128KB.",
+           ZFEATURE_FLAG_PER_DATASET, large_blocks_deps);
+       }
+
+       {
+       static const spa_feature_t large_dnode_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_LARGE_DNODE,
+           "org.zfsonlinux:large_dnode", "large_dnode",
+           "Variable on-disk size of dnodes.",
+           ZFEATURE_FLAG_PER_DATASET, large_dnode_deps);
+       }
+
+       {
+       static const spa_feature_t sha512_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_SHA512,
+           "org.illumos:sha512", "sha512",
+           "SHA-512/256 hash algorithm.",
+           ZFEATURE_FLAG_PER_DATASET, sha512_deps);
+       }
+       {
+       static const spa_feature_t skein_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_SKEIN,
+           "org.illumos:skein", "skein",
+           "Skein hash algorithm.",
+           ZFEATURE_FLAG_PER_DATASET, skein_deps);
+       }
+
+       {
+       static const spa_feature_t edonr_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_EDONR,
+           "org.illumos:edonr", "edonr",
+           "Edon-R hash algorithm.",
+           ZFEATURE_FLAG_PER_DATASET, edonr_deps);
+       }
+       {
+       static const spa_feature_t userobj_accounting_deps[] = {
+               SPA_FEATURE_EXTENSIBLE_DATASET,
+               SPA_FEATURE_NONE
+       };
+       zfeature_register(SPA_FEATURE_USEROBJ_ACCOUNTING,
+           "org.zfsonlinux:userobj_accounting", "userobj_accounting",
+           "User/Group object accounting.",
+           ZFEATURE_FLAG_READONLY_COMPAT | ZFEATURE_FLAG_PER_DATASET,
+           userobj_accounting_deps);
        }
 }
index bbb01930fa79e4a55f496c4e1ca52384c5aaa052..7198c7ebff16f002f05407c9da73bcbc1fb6d16f 100644 (file)
@@ -53,6 +53,7 @@
 #include <sys/zap.h>
 #include <sys/sa.h>
 #include <sys/trace_acl.h>
+#include <sys/zpl.h>
 #include "fs/fs_subr.h"
 
 #define        ALLOW   ACE_ACCESS_ALLOWED_ACE_TYPE
@@ -1165,8 +1166,10 @@ zfs_acl_chown_setattr(znode_t *zp)
 
        error = zfs_acl_node_read(zp, B_TRUE, &aclp, B_FALSE);
        if (error == 0 && aclp->z_acl_count > 0)
-               zp->z_mode = zfs_mode_compute(zp->z_mode, aclp,
-                   &zp->z_pflags, zp->z_uid, zp->z_gid);
+               zp->z_mode = ZTOI(zp)->i_mode =
+                   zfs_mode_compute(zp->z_mode, aclp,
+                   &zp->z_pflags, KUID_TO_SUID(ZTOI(zp)->i_uid),
+                   KGID_TO_SGID(ZTOI(zp)->i_gid));
 
        /*
         * Some ZFS implementations (ZEVO) create neither a ZNODE_ACL
@@ -1324,9 +1327,9 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
        mode = zp->z_mode;
 
        mode = zfs_mode_compute(mode, aclp, &zp->z_pflags,
-           zp->z_uid, zp->z_gid);
+           KUID_TO_SUID(ZTOI(zp)->i_uid), KGID_TO_SGID(ZTOI(zp)->i_gid));
 
-       zp->z_mode = mode;
+       zp->z_mode = ZTOI(zp)->i_mode = mode;
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zsb), NULL,
            &mode, sizeof (mode));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb), NULL,
@@ -1394,7 +1397,7 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
                                    otype == DMU_OT_ACL ?
                                    DMU_OT_SYSACL : DMU_OT_NONE,
                                    otype == DMU_OT_ACL ?
-                                   DN_MAX_BONUSLEN : 0, tx);
+                                   DN_OLD_MAX_BONUSLEN : 0, tx);
                        } else {
                                (void) dmu_object_set_blocksize(zsb->z_os,
                                    aoid, aclp->z_acl_bytes, 0, tx);
@@ -1457,7 +1460,7 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx)
        if (ace_trivial_common(aclp, 0, zfs_ace_walk) == 0)
                zp->z_pflags |= ZFS_ACL_TRIVIAL;
 
-       zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime, B_TRUE);
+       zfs_tstamp_update_setup(zp, STATE_CHANGED, NULL, ctime);
        return (sa_bulk_update(zp->z_sa_hdl, bulk, count, tx));
 }
 
@@ -1744,9 +1747,7 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
        int             error;
        zfs_sb_t        *zsb = ZTOZSB(dzp);
        zfs_acl_t       *paclp;
-#ifdef HAVE_KSID
-       gid_t           gid;
-#endif /* HAVE_KSID */
+       gid_t           gid = vap->va_gid;
        boolean_t       need_chmod = B_TRUE;
        boolean_t       inherited = B_FALSE;
 
@@ -1780,7 +1781,7 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
                            (uint64_t)vap->va_gid,
                            cr, ZFS_GROUP, &acl_ids->z_fuidp);
                        gid = vap->va_gid;
-                       if (acl_ids->z_fgid != dzp->z_gid &&
+                       if (acl_ids->z_fgid != KGID_TO_SGID(ZTOI(dzp)->i_gid) &&
                            !groupmember(vap->va_gid, cr) &&
                            secpolicy_vnode_create_gid(cr) != 0)
                                acl_ids->z_fgid = 0;
@@ -1790,7 +1791,8 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
                                char            *domain;
                                uint32_t        rid;
 
-                               acl_ids->z_fgid = dzp->z_gid;
+                               acl_ids->z_fgid = KGID_TO_SGID(
+                                   ZTOI(dzp)->i_gid);
                                gid = zfs_fuid_map_id(zsb, acl_ids->z_fgid,
                                    cr, ZFS_GROUP);
 
@@ -1884,7 +1886,9 @@ boolean_t
 zfs_acl_ids_overquota(zfs_sb_t *zsb, zfs_acl_ids_t *acl_ids)
 {
        return (zfs_fuid_overquota(zsb, B_FALSE, acl_ids->z_fuid) ||
-           zfs_fuid_overquota(zsb, B_TRUE, acl_ids->z_fgid));
+           zfs_fuid_overquota(zsb, B_TRUE, acl_ids->z_fgid) ||
+           zfs_fuid_overobjquota(zsb, B_FALSE, acl_ids->z_fuid) ||
+           zfs_fuid_overobjquota(zsb, B_TRUE, acl_ids->z_fgid));
 }
 
 /*
@@ -2342,7 +2346,8 @@ zfs_has_access(znode_t *zp, cred_t *cr)
        if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) {
                uid_t owner;
 
-               owner = zfs_fuid_map_id(ZTOZSB(zp), zp->z_uid, cr, ZFS_OWNER);
+               owner = zfs_fuid_map_id(ZTOZSB(zp),
+                   KUID_TO_SUID(ZTOI(zp)->i_uid), cr, ZFS_OWNER);
                return (secpolicy_vnode_any_access(cr, ZTOI(zp), owner) == 0);
        }
        return (B_TRUE);
@@ -2420,12 +2425,13 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
                return (0);
        }
 
-       if (FUID_INDEX(zdp->z_uid) != 0 || FUID_INDEX(zdp->z_gid) != 0) {
+       if (KUID_TO_SUID(ZTOI(zdp)->i_uid) != 0 ||
+           KGID_TO_SGID(ZTOI(zdp)->i_gid) != 0) {
                mutex_exit(&zdp->z_acl_lock);
                goto slow;
        }
 
-       if (uid == zdp->z_uid) {
+       if (uid == KUID_TO_SUID(ZTOI(zdp)->i_uid)) {
                owner = B_TRUE;
                if (zdp->z_mode & S_IXUSR) {
                        mutex_exit(&zdp->z_acl_lock);
@@ -2435,7 +2441,7 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
                        goto slow;
                }
        }
-       if (groupmember(zdp->z_gid, cr)) {
+       if (groupmember(KGID_TO_SGID(ZTOI(zdp)->i_gid), cr)) {
                groupmbr = B_TRUE;
                if (zdp->z_mode & S_IXGRP) {
                        mutex_exit(&zdp->z_acl_lock);
@@ -2515,7 +2521,8 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
                }
        }
 
-       owner = zfs_fuid_map_id(ZTOZSB(zp), zp->z_uid, cr, ZFS_OWNER);
+       owner = zfs_fuid_map_id(ZTOZSB(zp), KUID_TO_SUID(ZTOI(zp)->i_uid),
+           cr, ZFS_OWNER);
        /*
         * Map the bits required to the standard inode flags
         * S_IRUSR|S_IWUSR|S_IXUSR in the needed_bits.  Map the bits
@@ -2644,7 +2651,8 @@ zfs_delete_final_check(znode_t *zp, znode_t *dzp,
        int error;
        uid_t downer;
 
-       downer = zfs_fuid_map_id(ZTOZSB(dzp), dzp->z_uid, cr, ZFS_OWNER);
+       downer = zfs_fuid_map_id(ZTOZSB(dzp), KUID_TO_SUID(ZTOI(dzp)->i_uid),
+           cr, ZFS_OWNER);
 
        error = secpolicy_vnode_access2(cr, ZTOI(dzp),
            downer, available_perms, S_IWUSR|S_IXUSR);
index 05d841d4bb17b963fc485e44c6fe121c36e7246a..44003a5a625706ef6b7e7a2edc3cd6ec2c72d612 100644 (file)
@@ -28,6 +28,7 @@
  *   Rohan Puri <rohan.puri15@gmail.com>
  *   Brian Behlendorf <behlendorf1@llnl.gov>
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
  */
 
 /*
@@ -108,7 +109,7 @@ static krwlock_t zfs_snapshot_lock;
  * Control Directory Tunables (.zfs)
  */
 int zfs_expire_snapshot = ZFSCTL_EXPIRE_SNAPSHOT;
-int zfs_admin_snapshot = 0;
+int zfs_admin_snapshot = 1;
 
 /*
  * Dedicated task queue for unmounting snapshots.
@@ -476,22 +477,17 @@ zfsctl_inode_alloc(zfs_sb_t *zsb, uint64_t id,
        zp->z_blksz = 0;
        zp->z_seq = 0;
        zp->z_mapcnt = 0;
-       zp->z_gen = 0;
        zp->z_size = 0;
-       zp->z_atime[0] = 0;
-       zp->z_atime[1] = 0;
-       zp->z_links = 0;
        zp->z_pflags = 0;
-       zp->z_uid = 0;
-       zp->z_gid = 0;
        zp->z_mode = 0;
        zp->z_sync_cnt = 0;
        zp->z_is_mapped = B_FALSE;
        zp->z_is_ctldir = B_TRUE;
        zp->z_is_sa = B_FALSE;
        zp->z_is_stale = B_FALSE;
+       ip->i_generation = 0;
        ip->i_ino = id;
-       ip->i_mode = (S_IFDIR | S_IRUGO | S_IXUGO);
+       ip->i_mode = (S_IFDIR | S_IRWXUGO);
        ip->i_uid = SUID_TO_KUID(0);
        ip->i_gid = SGID_TO_KGID(0);
        ip->i_blkbits = SPA_MINBLOCKSHIFT;
@@ -750,12 +746,13 @@ zfsctl_snapshot_path_objset(zfs_sb_t *zsb, uint64_t objsetid,
                return (ENOENT);
 
        cookie = spl_fstrans_mark();
-       snapname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+       snapname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
 
        while (error == 0) {
                dsl_pool_config_enter(dmu_objset_pool(os), FTAG);
-               error = dmu_snapshot_list_next(zsb->z_os, MAXNAMELEN,
-                   snapname, &id, &pos, &case_conflict);
+               error = dmu_snapshot_list_next(zsb->z_os,
+                   ZFS_MAX_DATASET_NAME_LEN, snapname, &id, &pos,
+                   &case_conflict);
                dsl_pool_config_exit(dmu_objset_pool(os), FTAG);
                if (error)
                        goto out;
@@ -768,7 +765,7 @@ zfsctl_snapshot_path_objset(zfs_sb_t *zsb, uint64_t objsetid,
        snprintf(full_path, path_len - 1, "%s/.zfs/snapshot/%s",
            zsb->z_mntopts->z_mntpoint, snapname);
 out:
-       kmem_free(snapname, MAXNAMELEN);
+       kmem_free(snapname, ZFS_MAX_DATASET_NAME_LEN);
        spl_fstrans_unmark(cookie);
 
        return (error);
@@ -855,14 +852,14 @@ zfsctl_snapdir_rename(struct inode *sdip, char *snm,
 
        ZFS_ENTER(zsb);
 
-       to = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-       from = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-       real = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-       fsname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+       to = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
+       from = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
+       real = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
+       fsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
 
        if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
                error = dmu_snapshot_realname(zsb->z_os, snm, real,
-                   MAXNAMELEN, NULL);
+                   ZFS_MAX_DATASET_NAME_LEN, NULL);
                if (error == 0) {
                        snm = real;
                } else if (error != ENOTSUP) {
@@ -872,9 +869,11 @@ zfsctl_snapdir_rename(struct inode *sdip, char *snm,
 
        dmu_objset_name(zsb->z_os, fsname);
 
-       error = zfsctl_snapshot_name(ITOZSB(sdip), snm, MAXNAMELEN, from);
+       error = zfsctl_snapshot_name(ITOZSB(sdip), snm,
+           ZFS_MAX_DATASET_NAME_LEN, from);
        if (error == 0)
-               error = zfsctl_snapshot_name(ITOZSB(tdip), tnm, MAXNAMELEN, to);
+               error = zfsctl_snapshot_name(ITOZSB(tdip), tnm,
+           ZFS_MAX_DATASET_NAME_LEN, to);
        if (error == 0)
                error = zfs_secpolicy_rename_perms(from, to, cr);
        if (error != 0)
@@ -904,10 +903,10 @@ zfsctl_snapdir_rename(struct inode *sdip, char *snm,
 
        rw_exit(&zfs_snapshot_lock);
 out:
-       kmem_free(from, MAXNAMELEN);
-       kmem_free(to, MAXNAMELEN);
-       kmem_free(real, MAXNAMELEN);
-       kmem_free(fsname, MAXNAMELEN);
+       kmem_free(from, ZFS_MAX_DATASET_NAME_LEN);
+       kmem_free(to, ZFS_MAX_DATASET_NAME_LEN);
+       kmem_free(real, ZFS_MAX_DATASET_NAME_LEN);
+       kmem_free(fsname, ZFS_MAX_DATASET_NAME_LEN);
 
        ZFS_EXIT(zsb);
 
@@ -930,12 +929,12 @@ zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags)
 
        ZFS_ENTER(zsb);
 
-       snapname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-       real = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+       snapname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
+       real = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
 
        if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
                error = dmu_snapshot_realname(zsb->z_os, name, real,
-                   MAXNAMELEN, NULL);
+                   ZFS_MAX_DATASET_NAME_LEN, NULL);
                if (error == 0) {
                        name = real;
                } else if (error != ENOTSUP) {
@@ -943,7 +942,8 @@ zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags)
                }
        }
 
-       error = zfsctl_snapshot_name(ITOZSB(dip), name, MAXNAMELEN, snapname);
+       error = zfsctl_snapshot_name(ITOZSB(dip), name,
+           ZFS_MAX_DATASET_NAME_LEN, snapname);
        if (error == 0)
                error = zfs_secpolicy_destroy_perms(snapname, cr);
        if (error != 0)
@@ -953,8 +953,8 @@ zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags)
        if ((error == 0) || (error == ENOENT))
                error = dsl_destroy_snapshot(snapname, B_FALSE);
 out:
-       kmem_free(snapname, MAXNAMELEN);
-       kmem_free(real, MAXNAMELEN);
+       kmem_free(snapname, ZFS_MAX_DATASET_NAME_LEN);
+       kmem_free(real, ZFS_MAX_DATASET_NAME_LEN);
 
        ZFS_EXIT(zsb);
 
@@ -976,7 +976,7 @@ zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
        if (!zfs_admin_snapshot)
                return (EACCES);
 
-       dsname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+       dsname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
 
        if (zfs_component_namecheck(dirname, NULL, NULL) != 0) {
                error = SET_ERROR(EILSEQ);
@@ -998,7 +998,7 @@ zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
                    0, cr, NULL, NULL);
        }
 out:
-       kmem_free(dsname, MAXNAMELEN);
+       kmem_free(dsname, ZFS_MAX_DATASET_NAME_LEN);
 
        return (error);
 }
@@ -1009,16 +1009,11 @@ out:
  * best effort.  In the case where it does fail, perhaps because
  * it's in use, the unmount will fail harmlessly.
  */
-#define        SET_UNMOUNT_CMD \
-       "exec 0</dev/null " \
-       "     1>/dev/null " \
-       "     2>/dev/null; " \
-       "umount -t zfs -n %s'%s'"
-
 int
 zfsctl_snapshot_unmount(char *snapname, int flags)
 {
-       char *argv[] = { "/bin/sh", "-c", NULL, NULL };
+       char *argv[] = { "/usr/bin/env", "umount", "-t", "zfs", "-n", NULL,
+           NULL };
        char *envp[] = { NULL };
        zfs_snapentry_t *se;
        int error;
@@ -1030,12 +1025,12 @@ zfsctl_snapshot_unmount(char *snapname, int flags)
        }
        rw_exit(&zfs_snapshot_lock);
 
-       argv[2] = kmem_asprintf(SET_UNMOUNT_CMD,
-           flags & MNT_FORCE ? "-f " : "", se->se_path);
-       zfsctl_snapshot_rele(se);
+       if (flags & MNT_FORCE)
+               argv[4] = "-fn";
+       argv[5] = se->se_path;
        dprintf("unmount; path=%s\n", se->se_path);
        error = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
-       strfree(argv[2]);
+       zfsctl_snapshot_rele(se);
 
 
        /*
@@ -1050,11 +1045,6 @@ zfsctl_snapshot_unmount(char *snapname, int flags)
 }
 
 #define        MOUNT_BUSY 0x80         /* Mount failed due to EBUSY (from mntent.h) */
-#define        SET_MOUNT_CMD \
-       "exec 0</dev/null " \
-       "     1>/dev/null " \
-       "     2>/dev/null; " \
-       "mount -t zfs -n '%s' '%s'"
 
 int
 zfsctl_snapshot_mount(struct path *path, int flags)
@@ -1065,7 +1055,8 @@ zfsctl_snapshot_mount(struct path *path, int flags)
        zfs_sb_t *snap_zsb;
        zfs_snapentry_t *se;
        char *full_name, *full_path;
-       char *argv[] = { "/bin/sh", "-c", NULL, NULL };
+       char *argv[] = { "/usr/bin/env", "mount", "-t", "zfs", "-n", NULL, NULL,
+           NULL };
        char *envp[] = { NULL };
        int error;
        struct path spath;
@@ -1076,11 +1067,11 @@ zfsctl_snapshot_mount(struct path *path, int flags)
        zsb = ITOZSB(ip);
        ZFS_ENTER(zsb);
 
-       full_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+       full_name = kmem_zalloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
        full_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 
        error = zfsctl_snapshot_name(zsb, dname(dentry),
-           MAXNAMELEN, full_name);
+           ZFS_MAX_DATASET_NAME_LEN, full_name);
        if (error)
                goto error;
 
@@ -1110,9 +1101,9 @@ zfsctl_snapshot_mount(struct path *path, int flags)
         * value from call_usermodehelper() will be (exitcode << 8 + signal).
         */
        dprintf("mount; name=%s path=%s\n", full_name, full_path);
-       argv[2] = kmem_asprintf(SET_MOUNT_CMD, full_name, full_path);
+       argv[5] = full_name;
+       argv[6] = full_path;
        error = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
-       strfree(argv[2]);
        if (error) {
                if (!(error & MOUNT_BUSY << 8)) {
                        cmn_err(CE_WARN, "Unable to automount %s/%s: %d",
@@ -1154,7 +1145,7 @@ zfsctl_snapshot_mount(struct path *path, int flags)
        }
        path_put(&spath);
 error:
-       kmem_free(full_name, MAXNAMELEN);
+       kmem_free(full_name, ZFS_MAX_DATASET_NAME_LEN);
        kmem_free(full_path, MAXPATHLEN);
 
        ZFS_EXIT(zsb);
@@ -1246,21 +1237,16 @@ zfsctl_shares_lookup(struct inode *dip, char *name, struct inode **ipp,
                return (SET_ERROR(ENOTSUP));
        }
 
-       error = zfs_zget(zsb, zsb->z_shares_dir, &dzp);
-       if (error) {
-               ZFS_EXIT(zsb);
-               return (error);
+       if ((error = zfs_zget(zsb, zsb->z_shares_dir, &dzp)) == 0) {
+               error = zfs_lookup(ZTOI(dzp), name, &ip, 0, cr, NULL, NULL);
+               iput(ZTOI(dzp));
        }
 
-       error = zfs_lookup(ZTOI(dzp), name, &ip, 0, cr, NULL, NULL);
-
-       iput(ZTOI(dzp));
        ZFS_EXIT(zsb);
 
        return (error);
 }
 
-
 /*
  * Initialize the various pieces we'll need to create and manipulate .zfs
  * directories.  Currently this is unused but available.
index b0c8e3658211d35f5e28ce37d44c2f51aed9c2f5..8eee626d9814ceea911e443a712f623ed7b7dde1 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2014 by Delphix. All rights reserved.
  */
 
 
@@ -478,7 +478,7 @@ zfs_unlinked_add(znode_t *zp, dmu_tx_t *tx)
        zfs_sb_t *zsb = ZTOZSB(zp);
 
        ASSERT(zp->z_unlinked);
-       ASSERT(zp->z_links == 0);
+       ASSERT(ZTOI(zp)->i_nlink == 0);
 
        VERIFY3U(0, ==,
            zap_add_int(zsb->z_os, zsb->z_unlinkedobj, zp->z_id, tx));
@@ -578,6 +578,7 @@ zfs_purgedir(znode_t *dzp)
                dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
                /* Is this really needed ? */
                zfs_sa_upgrade_txholds(tx, xzp);
+               dmu_tx_mark_netfree(tx);
                error = dmu_tx_assign(tx, TXG_WAIT);
                if (error) {
                        dmu_tx_abort(tx);
@@ -593,7 +594,7 @@ zfs_purgedir(znode_t *dzp)
                if (error)
                        skipped += 1;
                dmu_tx_commit(tx);
-               set_nlink(ZTOI(xzp), xzp->z_links);
+
                zfs_iput_async(ZTOI(xzp));
        }
        zap_cursor_fini(&zc);
@@ -611,9 +612,10 @@ zfs_rmnode(znode_t *zp)
        dmu_tx_t        *tx;
        uint64_t        acl_obj;
        uint64_t        xattr_obj;
+       uint64_t        links;
        int             error;
 
-       ASSERT(zp->z_links == 0);
+       ASSERT(ZTOI(zp)->i_nlink == 0);
        ASSERT(atomic_read(&ZTOI(zp)->i_count) == 0);
 
        /*
@@ -693,10 +695,10 @@ zfs_rmnode(znode_t *zp)
                ASSERT(error == 0);
                mutex_enter(&xzp->z_lock);
                xzp->z_unlinked = B_TRUE;       /* mark xzp for deletion */
-               xzp->z_links = 0;       /* no more links to it */
-               set_nlink(ZTOI(xzp), 0); /* this will let iput purge us */
+               clear_nlink(ZTOI(xzp));         /* no more links to it */
+               links = 0;
                VERIFY(0 == sa_update(xzp->z_sa_hdl, SA_ZPL_LINKS(zsb),
-                   &xzp->z_links, sizeof (xzp->z_links), tx));
+                   &links, sizeof (links), tx));
                mutex_exit(&xzp->z_lock);
                zfs_unlinked_add(xzp, tx);
        }
@@ -735,6 +737,7 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
        int zp_is_dir = S_ISDIR(ZTOI(zp)->i_mode);
        sa_bulk_attr_t bulk[5];
        uint64_t mtime[2], ctime[2];
+       uint64_t links;
        int count = 0;
        int error;
 
@@ -746,10 +749,16 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
                        mutex_exit(&zp->z_lock);
                        return (SET_ERROR(ENOENT));
                }
-               zp->z_links++;
-               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb), NULL,
-                   &zp->z_links, sizeof (zp->z_links));
-
+               if (!(flag & ZNEW)) {
+                       /*
+                        * ZNEW nodes come from zfs_mknode() where the link
+                        * count has already been initialised
+                        */
+                       inc_nlink(ZTOI(zp));
+                       links = ZTOI(zp)->i_nlink;
+                       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb), NULL,
+                           &links, sizeof (links));
+               }
        }
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zsb), NULL,
            &dzp->z_id, sizeof (dzp->z_id));
@@ -760,7 +769,7 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
                SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL,
                    ctime, sizeof (ctime));
                zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime,
-                   ctime, B_TRUE);
+                   ctime);
        }
        error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
        ASSERT(error == 0);
@@ -769,19 +778,21 @@ zfs_link_create(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag)
 
        mutex_enter(&dzp->z_lock);
        dzp->z_size++;
-       dzp->z_links += zp_is_dir;
+       if (zp_is_dir)
+               inc_nlink(ZTOI(dzp));
+       links = ZTOI(dzp)->i_nlink;
        count = 0;
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zsb), NULL,
            &dzp->z_size, sizeof (dzp->z_size));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb), NULL,
-           &dzp->z_links, sizeof (dzp->z_links));
+           &links, sizeof (links));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb), NULL,
            mtime, sizeof (mtime));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL,
            ctime, sizeof (ctime));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb), NULL,
            &dzp->z_pflags, sizeof (dzp->z_pflags));
-       zfs_tstamp_update_setup(dzp, CONTENT_MODIFIED, mtime, ctime, B_TRUE);
+       zfs_tstamp_update_setup(dzp, CONTENT_MODIFIED, mtime, ctime);
        error = sa_bulk_update(dzp->z_sa_hdl, bulk, count, tx);
        ASSERT(error == 0);
        mutex_exit(&dzp->z_lock);
@@ -835,6 +846,7 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
        boolean_t unlinked = B_FALSE;
        sa_bulk_attr_t bulk[5];
        uint64_t mtime[2], ctime[2];
+       uint64_t links;
        int count = 0;
        int error;
 
@@ -861,26 +873,28 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
                        return (error);
                }
 
-               if (zp->z_links <= zp_is_dir) {
+               if (ZTOI(zp)->i_nlink <= zp_is_dir) {
                        zfs_panic_recover("zfs: link count on %lu is %u, "
                            "should be at least %u", zp->z_id,
-                           (int)zp->z_links, zp_is_dir + 1);
-                       zp->z_links = zp_is_dir + 1;
+                           (int)ZTOI(zp)->i_nlink, zp_is_dir + 1);
+                       set_nlink(ZTOI(zp), zp_is_dir + 1);
                }
-               if (--zp->z_links == zp_is_dir) {
+               drop_nlink(ZTOI(zp));
+               if (ZTOI(zp)->i_nlink == zp_is_dir) {
                        zp->z_unlinked = B_TRUE;
-                       zp->z_links = 0;
+                       clear_nlink(ZTOI(zp));
                        unlinked = B_TRUE;
                } else {
                        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb),
                            NULL, &ctime, sizeof (ctime));
                        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb),
                            NULL, &zp->z_pflags, sizeof (zp->z_pflags));
-                       zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime, ctime,
-                           B_TRUE);
+                       zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime,
+                           ctime);
                }
+               links = ZTOI(zp)->i_nlink;
                SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb),
-                   NULL, &zp->z_links, sizeof (zp->z_links));
+                   NULL, &links, sizeof (links));
                error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
                count = 0;
                ASSERT(error == 0);
@@ -893,9 +907,11 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
 
        mutex_enter(&dzp->z_lock);
        dzp->z_size--;          /* one dirent removed */
-       dzp->z_links -= zp_is_dir;      /* ".." link from zp */
+       if (zp_is_dir)
+               drop_nlink(ZTOI(dzp));  /* ".." link from zp */
+       links = ZTOI(dzp)->i_nlink;
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb),
-           NULL, &dzp->z_links, sizeof (dzp->z_links));
+           NULL, &links, sizeof (links));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zsb),
            NULL, &dzp->z_size, sizeof (dzp->z_size));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb),
@@ -904,7 +920,7 @@ zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag,
            NULL, mtime, sizeof (mtime));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb),
            NULL, &dzp->z_pflags, sizeof (dzp->z_pflags));
-       zfs_tstamp_update_setup(dzp, CONTENT_MODIFIED, mtime, ctime, B_TRUE);
+       zfs_tstamp_update_setup(dzp, CONTENT_MODIFIED, mtime, ctime);
        error = sa_bulk_update(dzp->z_sa_hdl, bulk, count, tx);
        ASSERT(error == 0);
        mutex_exit(&dzp->z_lock);
@@ -1088,8 +1104,10 @@ zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr)
        if ((zdp->z_mode & S_ISVTX) == 0)
                return (0);
 
-       downer = zfs_fuid_map_id(zsb, zdp->z_uid, cr, ZFS_OWNER);
-       fowner = zfs_fuid_map_id(zsb, zp->z_uid, cr, ZFS_OWNER);
+       downer = zfs_fuid_map_id(zsb, KUID_TO_SUID(ZTOI(zdp)->i_uid),
+           cr, ZFS_OWNER);
+       fowner = zfs_fuid_map_id(zsb, KUID_TO_SUID(ZTOI(zp)->i_uid),
+           cr, ZFS_OWNER);
 
        if ((uid = crgetuid(cr)) == downer || uid == fowner ||
            (S_ISDIR(ZTOI(zp)->i_mode) &&
index c7b7180009c83b990a9dcbb09290bddd8a0c2e46..df37fed2b9729742eb4f83bf76f84e472a40e39f 100644 (file)
@@ -112,9 +112,32 @@ zfs_zevent_post_cb(nvlist_t *nvl, nvlist_t *detector)
                fm_nvlist_destroy(detector, FM_NVA_FREE);
 }
 
-static void
-zfs_zevent_post_cb_noop(nvlist_t *nvl, nvlist_t *detector)
+/*
+ * We want to rate limit ZIO delay and checksum events so as to not
+ * flood ZED when a disk is acting up.
+ *
+ * Returns 1 if we're ratelimiting, 0 if not.
+ */
+static int
+zfs_is_ratelimiting_event(const char *subclass, vdev_t *vd)
 {
+       int rc = 0;
+       /*
+        * __ratelimit() returns 1 if we're *not* ratelimiting and 0 if we
+        * are.  Invert it to get our return value.
+        */
+       if (strcmp(subclass, FM_EREPORT_ZFS_DELAY) == 0) {
+               rc = !zfs_ratelimit(&vd->vdev_delay_rl);
+       } else if (strcmp(subclass, FM_EREPORT_ZFS_CHECKSUM) == 0) {
+               rc = !zfs_ratelimit(&vd->vdev_checksum_rl);
+       }
+
+       if (rc) {
+               /* We're rate limiting */
+               fm_erpt_dropped_increment();
+       }
+
+       return (rc);
 }
 
 static void
@@ -195,6 +218,12 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
                return;
        }
 
+       if ((strcmp(subclass, FM_EREPORT_ZFS_DELAY) == 0) &&
+           (zio != NULL) && (!zio->io_timestamp)) {
+               /* Ignore bogus delay events */
+               return;
+       }
+
        /*
         * Serialize ereport generation
         */
@@ -278,6 +307,10 @@ zfs_ereport_start(nvlist_t **ereport_out, nvlist_t **detector_out,
                        fm_payload_set(ereport,
                            FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU,
                            DATA_TYPE_STRING, vd->vdev_fru, NULL);
+               if (vd->vdev_enc_sysfs_path != NULL)
+                       fm_payload_set(ereport,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_ENC_SYSFS_PATH,
+                           DATA_TYPE_STRING, vd->vdev_enc_sysfs_path, NULL);
                if (vd->vdev_ashift)
                        fm_payload_set(ereport,
                            FM_EREPORT_PAYLOAD_ZFS_VDEV_ASHIFT,
@@ -742,6 +775,9 @@ zfs_ereport_post(const char *subclass, spa_t *spa, vdev_t *vd, zio_t *zio,
        if (ereport == NULL)
                return;
 
+       if (zfs_is_ratelimiting_event(subclass, vd))
+               return;
+
        /* Cleanup is handled by the callback function */
        zfs_zevent_post(ereport, detector, zfs_zevent_post_cb);
 #endif
@@ -752,7 +788,15 @@ zfs_ereport_start_checksum(spa_t *spa, vdev_t *vd,
     struct zio *zio, uint64_t offset, uint64_t length, void *arg,
     zio_bad_cksum_t *info)
 {
-       zio_cksum_report_t *report = kmem_zalloc(sizeof (*report), KM_SLEEP);
+       zio_cksum_report_t *report;
+
+
+#ifdef _KERNEL
+       if (zfs_is_ratelimiting_event(FM_EREPORT_ZFS_CHECKSUM, vd))
+               return;
+#endif
+
+       report = kmem_zalloc(sizeof (*report), KM_SLEEP);
 
        if (zio->io_vsd != NULL)
                zio->io_vsd_ops->vsd_cksum_report(zio, report, arg);
@@ -824,14 +868,6 @@ zfs_ereport_free_checksum(zio_cksum_report_t *rpt)
        kmem_free(rpt, sizeof (*rpt));
 }
 
-void
-zfs_ereport_send_interim_checksum(zio_cksum_report_t *report)
-{
-#ifdef _KERNEL
-       zfs_zevent_post(report->zcr_ereport, report->zcr_detector,
-           zfs_zevent_post_cb_noop);
-#endif
-}
 
 void
 zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd,
@@ -860,7 +896,8 @@ zfs_ereport_post_checksum(spa_t *spa, vdev_t *vd,
 }
 
 static void
-zfs_post_common(spa_t *spa, vdev_t *vd, const char *name)
+zfs_post_common(spa_t *spa, vdev_t *vd, const char *type, const char *name,
+    nvlist_t *aux)
 {
 #ifdef _KERNEL
        nvlist_t *resource;
@@ -872,7 +909,7 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *name)
        if ((resource = fm_nvlist_create(NULL)) == NULL)
                return;
 
-       (void) snprintf(class, sizeof (class), "%s.%s.%s", FM_RSRC_RESOURCE,
+       (void) snprintf(class, sizeof (class), "%s.%s.%s", type,
            ZFS_ERROR_CLASS, name);
        VERIFY0(nvlist_add_uint8(resource, FM_VERSION, FM_RSRC_VERSION));
        VERIFY0(nvlist_add_string(resource, FM_CLASS, class));
@@ -886,6 +923,26 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *name)
                    FM_EREPORT_PAYLOAD_ZFS_VDEV_GUID, vd->vdev_guid));
                VERIFY0(nvlist_add_uint64(resource,
                    FM_EREPORT_PAYLOAD_ZFS_VDEV_STATE, vd->vdev_state));
+               if (vd->vdev_path != NULL)
+                       VERIFY0(nvlist_add_string(resource,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_PATH, vd->vdev_path));
+               if (vd->vdev_devid != NULL)
+                       VERIFY0(nvlist_add_string(resource,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_DEVID, vd->vdev_devid));
+               if (vd->vdev_fru != NULL)
+                       VERIFY0(nvlist_add_string(resource,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_FRU, vd->vdev_fru));
+               if (vd->vdev_enc_sysfs_path != NULL)
+                       VERIFY0(nvlist_add_string(resource,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_ENC_SYSFS_PATH,
+                           vd->vdev_enc_sysfs_path));
+               /* also copy any optional payload data */
+               if (aux) {
+                       nvpair_t *elem = NULL;
+
+                       while ((elem = nvlist_next_nvpair(aux, elem)) != NULL)
+                               (void) nvlist_add_nvpair(resource, elem);
+               }
        }
 
        zfs_zevent_post(resource, NULL, zfs_zevent_post_cb);
@@ -901,7 +958,7 @@ zfs_post_common(spa_t *spa, vdev_t *vd, const char *name)
 void
 zfs_post_remove(spa_t *spa, vdev_t *vd)
 {
-       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_REMOVED);
+       zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_REMOVED, NULL);
 }
 
 /*
@@ -912,7 +969,7 @@ zfs_post_remove(spa_t *spa, vdev_t *vd)
 void
 zfs_post_autoreplace(spa_t *spa, vdev_t *vd)
 {
-       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_AUTOREPLACE);
+       zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_AUTOREPLACE, NULL);
 }
 
 /*
@@ -922,9 +979,49 @@ zfs_post_autoreplace(spa_t *spa, vdev_t *vd)
  * open because the device was not found (fault.fs.zfs.device).
  */
 void
-zfs_post_state_change(spa_t *spa, vdev_t *vd)
+zfs_post_state_change(spa_t *spa, vdev_t *vd, uint64_t laststate)
+{
+#ifdef _KERNEL
+       nvlist_t *aux;
+
+       /*
+        * Add optional supplemental keys to payload
+        */
+       aux = fm_nvlist_create(NULL);
+       if (vd && aux) {
+               if (vd->vdev_physpath) {
+                       (void) nvlist_add_string(aux,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_PHYSPATH,
+                           vd->vdev_physpath);
+               }
+               if (vd->vdev_enc_sysfs_path) {
+                       (void) nvlist_add_string(aux,
+                           FM_EREPORT_PAYLOAD_ZFS_VDEV_ENC_SYSFS_PATH,
+                           vd->vdev_enc_sysfs_path);
+               }
+
+               (void) nvlist_add_uint64(aux,
+                   FM_EREPORT_PAYLOAD_ZFS_VDEV_LASTSTATE, laststate);
+       }
+
+       zfs_post_common(spa, vd, FM_RSRC_CLASS, FM_RESOURCE_STATECHANGE,
+           aux);
+
+       if (aux)
+               fm_nvlist_destroy(aux, FM_NVA_FREE);
+#endif
+}
+
+/*
+ * The 'sysevent.fs.zfs.*' events are signals posted to notify user space of
+ * change in the pool.  All sysevents are listed in sys/sysevent/eventdefs.h
+ * and are designed to be consumed by the ZFS Event Daemon (ZED).  For
+ * additional details refer to the zed(8) man page.
+ */
+void
+zfs_post_sysevent(spa_t *spa, vdev_t *vd, const char *name)
 {
-       zfs_post_common(spa, vd, FM_EREPORT_RESOURCE_STATECHANGE);
+       zfs_post_common(spa, vd, FM_SYSEVENT_CLASS, name, NULL);
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
@@ -933,4 +1030,5 @@ EXPORT_SYMBOL(zfs_ereport_post_checksum);
 EXPORT_SYMBOL(zfs_post_remove);
 EXPORT_SYMBOL(zfs_post_autoreplace);
 EXPORT_SYMBOL(zfs_post_state_change);
+EXPORT_SYMBOL(zfs_post_sysevent);
 #endif /* _KERNEL */
index 6ca61b87242f02d5524f95d80793886969408f22..3ab1c7ba03f5652601ec2204b9b0d68384a88112 100644 (file)
@@ -71,14 +71,10 @@ static char *nulldomain = "";
 static int
 idx_compare(const void *arg1, const void *arg2)
 {
-       const fuid_domain_t *node1 = arg1;
-       const fuid_domain_t *node2 = arg2;
+       const fuid_domain_t *node1 = (const fuid_domain_t *)arg1;
+       const fuid_domain_t *node2 = (const fuid_domain_t *)arg2;
 
-       if (node1->f_idx < node2->f_idx)
-               return (-1);
-       else if (node1->f_idx > node2->f_idx)
-               return (1);
-       return (0);
+       return (AVL_CMP(node1->f_idx, node2->f_idx));
 }
 
 /*
@@ -87,14 +83,13 @@ idx_compare(const void *arg1, const void *arg2)
 static int
 domain_compare(const void *arg1, const void *arg2)
 {
-       const fuid_domain_t *node1 = arg1;
-       const fuid_domain_t *node2 = arg2;
+       const fuid_domain_t *node1 = (const fuid_domain_t *)arg1;
+       const fuid_domain_t *node2 = (const fuid_domain_t *)arg2;
        int val;
 
        val = strcmp(node1->f_ksid->kd_name, node2->f_ksid->kd_name);
-       if (val == 0)
-               return (0);
-       return (val > 0 ? 1 : -1);
+
+       return (AVL_ISIGN(val));
 }
 
 void
@@ -387,8 +382,10 @@ zfs_fuid_find_by_idx(zfs_sb_t *zsb, uint32_t idx)
 void
 zfs_fuid_map_ids(znode_t *zp, cred_t *cr, uid_t *uidp, uid_t *gidp)
 {
-       *uidp = zfs_fuid_map_id(ZTOZSB(zp), zp->z_uid, cr, ZFS_OWNER);
-       *gidp = zfs_fuid_map_id(ZTOZSB(zp), zp->z_gid, cr, ZFS_GROUP);
+       *uidp = zfs_fuid_map_id(ZTOZSB(zp), KUID_TO_SUID(ZTOI(zp)->i_uid),
+           cr, ZFS_OWNER);
+       *gidp = zfs_fuid_map_id(ZTOZSB(zp), KGID_TO_SGID(ZTOI(zp)->i_gid),
+           cr, ZFS_GROUP);
 }
 
 uid_t
@@ -694,7 +691,7 @@ zfs_fuid_info_free(zfs_fuid_info_t *fuidp)
 
        if (fuidp->z_domain_table != NULL)
                kmem_free(fuidp->z_domain_table,
-                   (sizeof (char **)) * fuidp->z_domain_cnt);
+                   (sizeof (char *)) * fuidp->z_domain_cnt);
 
        while ((zdomain = list_head(&fuidp->z_domains)) != NULL) {
                list_remove(&fuidp->z_domains, zdomain);
index 3ebe28d7fcfc413c809a2ccfe6c5cda47ba3fb67..e3166a40e979ac40c759262fd0ba352d796bd519 100644 (file)
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Portions Copyright 2011 Martin Matuska
+ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
  * Portions Copyright 2012 Pawel Jakub Dawidek <pawel@dawidek.net>
  * Copyright (c) 2012, Joyent, Inc. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
- * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include <sys/dsl_bookmark.h>
 #include <sys/dsl_userhold.h>
 #include <sys/zfeature.h>
+#include <sys/zio_checksum.h>
 
 #include <linux/miscdevice.h>
+#include <linux/slab.h>
 
 #include "zfs_namecheck.h"
 #include "zfs_prop.h"
 #include "zfs_deleg.h"
 #include "zfs_comutil.h"
 
+/*
+ * Limit maximum nvlist size.  We don't want users passing in insane values
+ * for zc->zc_nvlist_src_size, since we will need to allocate that much memory.
+ */
+#define        MAX_NVLIST_SRC_SIZE     KMALLOC_MAX_SIZE
+
 kmutex_t zfsdev_state_lock;
 zfsdev_state_t *zfsdev_state_list;
 
@@ -236,9 +244,14 @@ static const char *userquota_perms[] = {
        ZFS_DELEG_PERM_USERQUOTA,
        ZFS_DELEG_PERM_GROUPUSED,
        ZFS_DELEG_PERM_GROUPQUOTA,
+       ZFS_DELEG_PERM_USEROBJUSED,
+       ZFS_DELEG_PERM_USEROBJQUOTA,
+       ZFS_DELEG_PERM_GROUPOBJUSED,
+       ZFS_DELEG_PERM_GROUPOBJQUOTA,
 };
 
 static int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc);
+static int zfs_ioc_userobjspace_upgrade(zfs_cmd_t *zc);
 static int zfs_check_settable(const char *name, nvpair_t *property,
     cred_t *cr);
 static int zfs_check_clearable(char *dataset, nvlist_t *props,
@@ -597,7 +610,7 @@ zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval,
        case ZFS_PROP_SNAPSHOT_LIMIT:
                if (!INGLOBALZONE(curproc)) {
                        uint64_t zoned;
-                       char setpoint[MAXNAMELEN];
+                       char setpoint[ZFS_MAX_DATASET_NAME_LEN];
                        /*
                         * Unprivileged users are allowed to modify the
                         * limit on things *under* (ie. contained by)
@@ -839,7 +852,7 @@ zfs_secpolicy_destroy_snaps(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
 int
 zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr)
 {
-       char    parentname[MAXNAMELEN];
+       char    parentname[ZFS_MAX_DATASET_NAME_LEN];
        int     error;
 
        if ((error = zfs_secpolicy_write_perms(from,
@@ -892,7 +905,7 @@ zfs_secpolicy_promote(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
        error = dsl_dataset_hold(dp, zc->zc_name, FTAG, &clone);
 
        if (error == 0) {
-               char parentname[MAXNAMELEN];
+               char parentname[ZFS_MAX_DATASET_NAME_LEN];
                dsl_dataset_t *origin = NULL;
                dsl_dir_t *dd;
                dd = clone->ds_dir;
@@ -938,6 +951,13 @@ zfs_secpolicy_recv(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
            ZFS_DELEG_PERM_CREATE, cr));
 }
 
+/* ARGSUSED */
+static int
+zfs_secpolicy_recv_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
+{
+       return (zfs_secpolicy_recv(zc, innvl, cr));
+}
+
 int
 zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr)
 {
@@ -1062,7 +1082,7 @@ zfs_secpolicy_log_history(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
 static int
 zfs_secpolicy_create_clone(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
 {
-       char    parentname[MAXNAMELEN];
+       char    parentname[ZFS_MAX_DATASET_NAME_LEN];
        int     error;
        char    *origin;
 
@@ -1156,7 +1176,9 @@ zfs_secpolicy_userspace_one(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
                 * themself, allow it.
                 */
                if (zc->zc_objset_type == ZFS_PROP_USERUSED ||
-                   zc->zc_objset_type == ZFS_PROP_USERQUOTA) {
+                   zc->zc_objset_type == ZFS_PROP_USERQUOTA ||
+                   zc->zc_objset_type == ZFS_PROP_USEROBJUSED ||
+                   zc->zc_objset_type == ZFS_PROP_USEROBJQUOTA) {
                        if (zc->zc_guid == crgetuid(cr))
                                return (0);
                } else {
@@ -1205,7 +1227,7 @@ zfs_secpolicy_hold(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
 
        for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
            pair = nvlist_next_nvpair(holds, pair)) {
-               char fsname[MAXNAMELEN];
+               char fsname[ZFS_MAX_DATASET_NAME_LEN];
                error = dmu_fsname(nvpair_name(pair), fsname);
                if (error != 0)
                        return (error);
@@ -1226,7 +1248,7 @@ zfs_secpolicy_release(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
 
        for (pair = nvlist_next_nvpair(innvl, NULL); pair != NULL;
            pair = nvlist_next_nvpair(innvl, pair)) {
-               char fsname[MAXNAMELEN];
+               char fsname[ZFS_MAX_DATASET_NAME_LEN];
                error = dmu_fsname(nvpair_name(pair), fsname);
                if (error != 0)
                        return (error);
@@ -1537,9 +1559,7 @@ zfs_ioc_pool_import(zfs_cmd_t *zc)
        }
 
        nvlist_free(config);
-
-       if (props)
-               nvlist_free(props);
+       nvlist_free(props);
 
        return (error);
 }
@@ -2248,7 +2268,8 @@ zfs_ioc_snapshot_list_next(zfs_cmd_t *zc)
         * A dataset name of maximum length cannot have any snapshots,
         * so exit immediately.
         */
-       if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >= MAXNAMELEN) {
+       if (strlcat(zc->zc_name, "@", sizeof (zc->zc_name)) >=
+           ZFS_MAX_DATASET_NAME_LEN) {
                dmu_objset_rele(os, FTAG);
                return (SET_ERROR(ESRCH));
        }
@@ -2412,6 +2433,7 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
                        zc = kmem_zalloc(sizeof (zfs_cmd_t), KM_SLEEP);
                        (void) strcpy(zc->zc_name, dsname);
                        (void) zfs_ioc_userspace_upgrade(zc);
+                       (void) zfs_ioc_userobjspace_upgrade(zc);
                        kmem_free(zc, sizeof (zfs_cmd_t));
                }
                break;
@@ -2751,6 +2773,10 @@ zfs_ioc_inherit_prop(zfs_cmd_t *zc)
                }
 
                pair = nvlist_next_nvpair(dummy, NULL);
+               if (pair == NULL) {
+                       nvlist_free(dummy);
+                       return (SET_ERROR(EINVAL));
+               }
                err = zfs_prop_set_special(zc->zc_name, source, pair);
                nvlist_free(dummy);
                if (err != -1)
@@ -3036,7 +3062,7 @@ zfs_fill_zplprops(const char *dataset, nvlist_t *createprops,
        boolean_t fuids_ok, sa_ok;
        uint64_t zplver = ZPL_VERSION;
        objset_t *os = NULL;
-       char parentname[MAXNAMELEN];
+       char parentname[ZFS_MAX_DATASET_NAME_LEN];
        char *cp;
        spa_t *spa;
        uint64_t spa_vers;
@@ -3185,8 +3211,25 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
        if (error == 0) {
                error = zfs_set_prop_nvlist(fsname, ZPROP_SRC_LOCAL,
                    nvprops, outnvl);
-               if (error != 0)
-                       (void) dsl_destroy_head(fsname);
+               if (error != 0) {
+                       spa_t *spa;
+                       int error2;
+
+                       /*
+                        * Volumes will return EBUSY and cannot be destroyed
+                        * until all asynchronous minor handling has completed.
+                        * Wait for the spa_zvol_taskq to drain then retry.
+                        */
+                       error2 = dsl_destroy_head(fsname);
+                       while ((error2 == EBUSY) && (type == DMU_OST_ZVOL)) {
+                               error2 = spa_open(fsname, &spa, FTAG);
+                               if (error2 == 0) {
+                                       taskq_wait(spa->spa_zvol_taskq);
+                                       spa_close(spa, FTAG);
+                               }
+                               error2 = dsl_destroy_head(fsname);
+                       }
+               }
        }
        return (error);
 }
@@ -3315,6 +3358,8 @@ zfs_ioc_log_history(const char *unused, nvlist_t *innvl, nvlist_t *outnvl)
         * we clear the TSD here.
         */
        poolname = tsd_get(zfs_allow_log_key);
+       if (poolname == NULL)
+               return (SET_ERROR(EINVAL));
        (void) tsd_set(zfs_allow_log_key, NULL);
        error = spa_open(poolname, &spa, FTAG);
        strfree(poolname);
@@ -3385,7 +3430,7 @@ zfs_destroy_unmount_origin(const char *fsname)
                return;
        ds = dmu_objset_ds(os);
        if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev)) {
-               char originname[MAXNAMELEN];
+               char originname[ZFS_MAX_DATASET_NAME_LEN];
                dsl_dataset_name(ds->ds_prev, originname);
                dmu_objset_rele(os, FTAG);
                (void) zfs_unmount_snap(originname);
@@ -3538,10 +3583,37 @@ zfs_ioc_destroy(zfs_cmd_t *zc)
                        return (err);
        }
 
-       if (strchr(zc->zc_name, '@'))
+       if (strchr(zc->zc_name, '@')) {
                err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy);
-       else
+       } else {
                err = dsl_destroy_head(zc->zc_name);
+               if (err == EEXIST) {
+                       /*
+                        * It is possible that the given DS may have
+                        * hidden child (%recv) datasets - "leftovers"
+                        * resulting from the previously interrupted
+                        * 'zfs receive'.
+                        *
+                        * 6 extra bytes for /%recv
+                        */
+                       char namebuf[ZFS_MAX_DATASET_NAME_LEN + 6];
+
+                       (void) snprintf(namebuf, sizeof (namebuf),
+                           "%s/%s", zc->zc_name, recv_clone_name);
+
+                       /*
+                        * Try to remove the hidden child (%recv) and after
+                        * that try to remove the target dataset.
+                        * If the hidden child (%recv) does not exist
+                        * the original error (EEXIST) will be returned
+                        */
+                       err = dsl_destroy_head(namebuf);
+                       if (err == 0)
+                               err = dsl_destroy_head(zc->zc_name);
+                       else if (err == ENOENT)
+                               err = EEXIST;
+               }
+       }
 
        return (err);
 }
@@ -3660,13 +3732,23 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
                            zfs_userquota_prop_prefixes[ZFS_PROP_USERQUOTA];
                        const char *gq_prefix =
                            zfs_userquota_prop_prefixes[ZFS_PROP_GROUPQUOTA];
+                       const char *uiq_prefix =
+                           zfs_userquota_prop_prefixes[ZFS_PROP_USEROBJQUOTA];
+                       const char *giq_prefix =
+                           zfs_userquota_prop_prefixes[ZFS_PROP_GROUPOBJQUOTA];
 
                        if (strncmp(propname, uq_prefix,
                            strlen(uq_prefix)) == 0) {
                                perm = ZFS_DELEG_PERM_USERQUOTA;
+                       } else if (strncmp(propname, uiq_prefix,
+                           strlen(uiq_prefix)) == 0) {
+                               perm = ZFS_DELEG_PERM_USEROBJQUOTA;
                        } else if (strncmp(propname, gq_prefix,
                            strlen(gq_prefix)) == 0) {
                                perm = ZFS_DELEG_PERM_GROUPQUOTA;
+                       } else if (strncmp(propname, giq_prefix,
+                           strlen(giq_prefix)) == 0) {
+                               perm = ZFS_DELEG_PERM_GROUPOBJQUOTA;
                        } else {
                                /* USERUSED and GROUPUSED are read-only */
                                return (SET_ERROR(EINVAL));
@@ -3750,11 +3832,6 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
                        return (SET_ERROR(ENOTSUP));
                break;
 
-       case ZFS_PROP_DEDUP:
-               if (zfs_earlier_version(dsname, SPA_VERSION_DEDUP))
-                       return (SET_ERROR(ENOTSUP));
-               break;
-
        case ZFS_PROP_VOLBLOCKSIZE:
        case ZFS_PROP_RECORDSIZE:
                /* Record sizes above 128k need the feature to be enabled */
@@ -3764,12 +3841,12 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
 
                        /*
                         * If this is a bootable dataset then
-                        * the we don't allow large (>128K) blocks,
+                        * we don't allow large (>128K) blocks,
                         * because GRUB doesn't support them.
                         */
                        if (zfs_is_bootfs(dsname) &&
                            intval > SPA_OLD_MAXBLOCKSIZE) {
-                               return (SET_ERROR(EDOM));
+                               return (SET_ERROR(ERANGE));
                        }
 
                        /*
@@ -3778,7 +3855,7 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
                         */
                        if (intval > zfs_max_recordsize ||
                            intval > SPA_MAXBLOCKSIZE)
-                               return (SET_ERROR(EDOM));
+                               return (SET_ERROR(ERANGE));
 
                        if ((err = spa_open(dsname, &spa, FTAG)) != 0)
                                return (err);
@@ -3792,6 +3869,34 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
                }
                break;
 
+       case ZFS_PROP_DNODESIZE:
+               /* Dnode sizes above 512 need the feature to be enabled */
+               if (nvpair_value_uint64(pair, &intval) == 0 &&
+                   intval != ZFS_DNSIZE_LEGACY) {
+                       spa_t *spa;
+
+                       /*
+                        * If this is a bootable dataset then
+                        * we don't allow large (>512B) dnodes,
+                        * because GRUB doesn't support them.
+                        */
+                       if (zfs_is_bootfs(dsname) &&
+                               intval != ZFS_DNSIZE_LEGACY) {
+                               return (SET_ERROR(EDOM));
+                       }
+
+                       if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+                               return (err);
+
+                       if (!spa_feature_is_enabled(spa,
+                           SPA_FEATURE_LARGE_DNODE)) {
+                               spa_close(spa, FTAG);
+                               return (SET_ERROR(ENOTSUP));
+                       }
+                       spa_close(spa, FTAG);
+               }
+               break;
+
        case ZFS_PROP_SHARESMB:
                if (zpl_earlier_version(dsname, ZPL_VERSION_FUID))
                        return (SET_ERROR(ENOTSUP));
@@ -3806,6 +3911,47 @@ zfs_check_settable(const char *dsname, nvpair_t *pair, cred_t *cr)
                                return (SET_ERROR(ENOTSUP));
                }
                break;
+       case ZFS_PROP_CHECKSUM:
+       case ZFS_PROP_DEDUP:
+       {
+               spa_feature_t feature;
+               spa_t *spa;
+               uint64_t intval;
+               int err;
+
+               /* dedup feature version checks */
+               if (prop == ZFS_PROP_DEDUP &&
+                   zfs_earlier_version(dsname, SPA_VERSION_DEDUP))
+                       return (SET_ERROR(ENOTSUP));
+
+               if (nvpair_value_uint64(pair, &intval) != 0)
+                       return (SET_ERROR(EINVAL));
+
+               /* check prop value is enabled in features */
+               feature = zio_checksum_to_feature(intval & ZIO_CHECKSUM_MASK);
+               if (feature == SPA_FEATURE_NONE)
+                       break;
+
+               if ((err = spa_open(dsname, &spa, FTAG)) != 0)
+                       return (err);
+               /*
+                * Salted checksums are not supported on root pools.
+                */
+               if (spa_bootfs(spa) != 0 &&
+                   intval < ZIO_CHECKSUM_FUNCTIONS &&
+                   (zio_checksum_table[intval].ci_flags &
+                   ZCHECKSUM_FLAG_SALTED)) {
+                       spa_close(spa, FTAG);
+                       return (SET_ERROR(ERANGE));
+               }
+               if (!spa_feature_is_enabled(spa, feature)) {
+                       spa_close(spa, FTAG);
+                       return (SET_ERROR(ENOTSUP));
+               }
+               spa_close(spa, FTAG);
+               break;
+       }
+
        default:
                break;
        }
@@ -3841,12 +3987,13 @@ zfs_check_clearable(char *dataset, nvlist_t *props, nvlist_t **errlist)
        VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 
        zc = kmem_alloc(sizeof (zfs_cmd_t), KM_SLEEP);
-       (void) strcpy(zc->zc_name, dataset);
+       (void) strlcpy(zc->zc_name, dataset, sizeof (zc->zc_name));
        pair = nvlist_next_nvpair(props, NULL);
        while (pair != NULL) {
                next_pair = nvlist_next_nvpair(props, pair);
 
-               (void) strcpy(zc->zc_value, nvpair_name(pair));
+               (void) strlcpy(zc->zc_value, nvpair_name(pair),
+                   sizeof (zc->zc_value));
                if ((err = zfs_check_settable(dataset, pair, CRED())) != 0 ||
                    (err = zfs_secpolicy_inherit_prop(zc, NULL, CRED())) != 0) {
                        VERIFY(nvlist_remove_nvpair(props, pair) == 0);
@@ -3941,74 +4088,89 @@ next:
        }
 }
 
+/*
+ * Extract properties that cannot be set PRIOR to the receipt of a dataset.
+ * For example, refquota cannot be set until after the receipt of a dataset,
+ * because in replication streams, an older/earlier snapshot may exceed the
+ * refquota.  We want to receive the older/earlier snapshot, but setting
+ * refquota pre-receipt will set the dsl's ACTUAL quota, which will prevent
+ * the older/earlier snapshot from being received (with EDQUOT).
+ *
+ * The ZFS test "zfs_receive_011_pos" demonstrates such a scenario.
+ *
+ * libzfs will need to be judicious handling errors encountered by props
+ * extracted by this function.
+ */
+static nvlist_t *
+extract_delay_props(nvlist_t *props)
+{
+       nvlist_t *delayprops;
+       nvpair_t *nvp, *tmp;
+       static const zfs_prop_t delayable[] = { ZFS_PROP_REFQUOTA, 0 };
+       int i;
+
+       VERIFY(nvlist_alloc(&delayprops, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+       for (nvp = nvlist_next_nvpair(props, NULL); nvp != NULL;
+           nvp = nvlist_next_nvpair(props, nvp)) {
+               /*
+                * strcmp() is safe because zfs_prop_to_name() always returns
+                * a bounded string.
+                */
+               for (i = 0; delayable[i] != 0; i++) {
+                       if (strcmp(zfs_prop_to_name(delayable[i]),
+                           nvpair_name(nvp)) == 0) {
+                               break;
+                       }
+               }
+               if (delayable[i] != 0) {
+                       tmp = nvlist_prev_nvpair(props, nvp);
+                       VERIFY(nvlist_add_nvpair(delayprops, nvp) == 0);
+                       VERIFY(nvlist_remove_nvpair(props, nvp) == 0);
+                       nvp = tmp;
+               }
+       }
+
+       if (nvlist_empty(delayprops)) {
+               nvlist_free(delayprops);
+               delayprops = NULL;
+       }
+       return (delayprops);
+}
+
 #ifdef DEBUG
 static boolean_t zfs_ioc_recv_inject_err;
 #endif
 
 /*
- * inputs:
- * zc_name             name of containing filesystem
- * zc_nvlist_src{_size}        nvlist of properties to apply
- * zc_value            name of snapshot to create
- * zc_string           name of clone origin (if DRR_FLAG_CLONE)
- * zc_cookie           file descriptor to recv from
- * zc_begin_record     the BEGIN record of the stream (not byteswapped)
- * zc_guid             force flag
- * zc_cleanup_fd       cleanup-on-exit file descriptor
- * zc_action_handle    handle for this guid/ds mapping (or zero on first call)
- *
- * outputs:
- * zc_cookie           number of bytes read
- * zc_nvlist_dst{_size} error for each unapplied received property
- * zc_obj              zprop_errflags_t
- * zc_action_handle    handle for this guid/ds mapping
+ * nvlist 'errors' is always allocated. It will contain descriptions of
+ * encountered errors, if any. It's the callers responsibility to free.
  */
 static int
-zfs_ioc_recv(zfs_cmd_t *zc)
+zfs_ioc_recv_impl(char *tofs, char *tosnap, char *origin,
+    nvlist_t *props, boolean_t force, boolean_t resumable, int input_fd,
+    dmu_replay_record_t *begin_record, int cleanup_fd, uint64_t *read_bytes,
+    uint64_t *errflags, uint64_t *action_handle, nvlist_t **errors)
 {
-       file_t *fp;
        dmu_recv_cookie_t drc;
-       boolean_t force = (boolean_t)zc->zc_guid;
-       int fd;
        int error = 0;
        int props_error = 0;
-       nvlist_t *errors;
        offset_t off;
-       nvlist_t *props = NULL; /* sent properties */
+       nvlist_t *delayprops = NULL; /* sent properties applied post-receive */
        nvlist_t *origprops = NULL; /* existing properties */
-       char *origin = NULL;
-       char *tosnap;
-       char tofs[ZFS_MAXNAMELEN];
        boolean_t first_recvd_props = B_FALSE;
+       file_t *input_fp;
 
-       if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
-           strchr(zc->zc_value, '@') == NULL ||
-           strchr(zc->zc_value, '%'))
-               return (SET_ERROR(EINVAL));
+       *read_bytes = 0;
+       *errflags = 0;
+       *errors = fnvlist_alloc();
 
-       (void) strcpy(tofs, zc->zc_value);
-       tosnap = strchr(tofs, '@');
-       *tosnap++ = '\0';
-
-       if (zc->zc_nvlist_src != 0 &&
-           (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
-           zc->zc_iflags, &props)) != 0)
-               return (error);
-
-       fd = zc->zc_cookie;
-       fp = getf(fd);
-       if (fp == NULL) {
-               nvlist_free(props);
+       input_fp = getf(input_fd);
+       if (input_fp == NULL)
                return (SET_ERROR(EBADF));
-       }
-
-       VERIFY(nvlist_alloc(&errors, NV_UNIQUE_NAME, KM_SLEEP) == 0);
-
-       if (zc->zc_string[0])
-               origin = zc->zc_string;
 
        error = dmu_recv_begin(tofs, tosnap,
-           &zc->zc_begin_record, force, origin, &drc);
+           begin_record, force, resumable, origin, &drc);
        if (error != 0)
                goto out;
 
@@ -4041,14 +4203,14 @@ zfs_ioc_recv(zfs_cmd_t *zc)
                        if (!first_recvd_props)
                                props_reduce(props, origprops);
                        if (zfs_check_clearable(tofs, origprops, &errlist) != 0)
-                               (void) nvlist_merge(errors, errlist, 0);
+                               (void) nvlist_merge(*errors, errlist, 0);
                        nvlist_free(errlist);
 
                        if (clear_received_props(tofs, origprops,
                            first_recvd_props ? NULL : props) != 0)
-                               zc->zc_obj |= ZPROP_ERR_NOCLEAR;
+                               *errflags |= ZPROP_ERR_NOCLEAR;
                } else {
-                       zc->zc_obj |= ZPROP_ERR_NOCLEAR;
+                       *errflags |= ZPROP_ERR_NOCLEAR;
                }
        }
 
@@ -4056,24 +4218,15 @@ zfs_ioc_recv(zfs_cmd_t *zc)
                props_error = dsl_prop_set_hasrecvd(tofs);
 
                if (props_error == 0) {
+                       delayprops = extract_delay_props(props);
                        (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
-                           props, errors);
+                           props, *errors);
                }
        }
 
-       if (zc->zc_nvlist_dst_size != 0 &&
-           (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
-           put_nvlist(zc, errors) != 0)) {
-               /*
-                * Caller made zc->zc_nvlist_dst less than the minimum expected
-                * size or supplied an invalid address.
-                */
-               props_error = SET_ERROR(EINVAL);
-       }
-
-       off = fp->f_offset;
-       error = dmu_recv_stream(&drc, fp->f_vnode, &off, zc->zc_cleanup_fd,
-           &zc->zc_action_handle);
+       off = input_fp->f_offset;
+       error = dmu_recv_stream(&drc, input_fp->f_vnode, &off, cleanup_fd,
+           action_handle);
 
        if (error == 0) {
                zfs_sb_t *zsb = NULL;
@@ -4095,11 +4248,32 @@ zfs_ioc_recv(zfs_cmd_t *zc)
                } else {
                        error = dmu_recv_end(&drc, NULL);
                }
+
+               /* Set delayed properties now, after we're done receiving. */
+               if (delayprops != NULL && error == 0) {
+                       (void) zfs_set_prop_nvlist(tofs, ZPROP_SRC_RECEIVED,
+                           delayprops, *errors);
+               }
        }
 
-       zc->zc_cookie = off - fp->f_offset;
-       if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
-               fp->f_offset = off;
+       if (delayprops != NULL) {
+               /*
+                * Merge delayed props back in with initial props, in case
+                * we're DEBUG and zfs_ioc_recv_inject_err is set (which means
+                * we have to make sure clear_received_props() includes
+                * the delayed properties).
+                *
+                * Since zfs_ioc_recv_inject_err is only in DEBUG kernels,
+                * using ASSERT() will be just like a VERIFY.
+                */
+               ASSERT(nvlist_merge(props, delayprops, 0) == 0);
+               nvlist_free(delayprops);
+       }
+
+
+       *read_bytes = off - input_fp->f_offset;
+       if (VOP_SEEK(input_fp->f_vnode, input_fp->f_offset, &off, NULL) == 0)
+           input_fp->f_offset = off;
 
 #ifdef DEBUG
        if (zfs_ioc_recv_inject_err) {
@@ -4118,14 +4292,14 @@ zfs_ioc_recv(zfs_cmd_t *zc)
                         * Since we may have left a $recvd value on the
                         * system, we can't clear the $hasrecvd flag.
                         */
-                       zc->zc_obj |= ZPROP_ERR_NORESTORE;
+                       *errflags |= ZPROP_ERR_NORESTORE;
                } else if (first_recvd_props) {
                        dsl_prop_unset_hasrecvd(tofs);
                }
 
                if (origprops == NULL && !drc.drc_newfs) {
                        /* We failed to stash the original properties. */
-                       zc->zc_obj |= ZPROP_ERR_NORESTORE;
+                       *errflags |= ZPROP_ERR_NORESTORE;
                }
 
                /*
@@ -4142,14 +4316,12 @@ zfs_ioc_recv(zfs_cmd_t *zc)
                         * We stashed the original properties but failed to
                         * restore them.
                         */
-                       zc->zc_obj |= ZPROP_ERR_NORESTORE;
+                       *errflags |= ZPROP_ERR_NORESTORE;
                }
        }
 out:
-       nvlist_free(props);
+       releasef(input_fd);
        nvlist_free(origprops);
-       nvlist_free(errors);
-       releasef(fd);
 
        if (error == 0)
                error = props_error;
@@ -4157,6 +4329,176 @@ out:
        return (error);
 }
 
+/*
+ * inputs:
+ * zc_name             name of containing filesystem (unused)
+ * zc_nvlist_src{_size}        nvlist of properties to apply
+ * zc_value            name of snapshot to create
+ * zc_string           name of clone origin (if DRR_FLAG_CLONE)
+ * zc_cookie           file descriptor to recv from
+ * zc_begin_record     the BEGIN record of the stream (not byteswapped)
+ * zc_guid             force flag
+ * zc_cleanup_fd       cleanup-on-exit file descriptor
+ * zc_action_handle    handle for this guid/ds mapping (or zero on first call)
+ *
+ * outputs:
+ * zc_cookie           number of bytes read
+ * zc_obj              zprop_errflags_t
+ * zc_action_handle    handle for this guid/ds mapping
+ * zc_nvlist_dst{_size} error for each unapplied received property
+ */
+static int
+zfs_ioc_recv(zfs_cmd_t *zc)
+{
+       dmu_replay_record_t begin_record;
+       nvlist_t *errors = NULL;
+       nvlist_t *props = NULL;
+       char *origin = NULL;
+       char *tosnap;
+       char tofs[ZFS_MAX_DATASET_NAME_LEN];
+       int error = 0;
+
+       if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
+           strchr(zc->zc_value, '@') == NULL ||
+           strchr(zc->zc_value, '%'))
+               return (SET_ERROR(EINVAL));
+
+       (void) strlcpy(tofs, zc->zc_value, sizeof (tofs));
+       tosnap = strchr(tofs, '@');
+       *tosnap++ = '\0';
+
+       if (zc->zc_nvlist_src != 0 &&
+           (error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
+           zc->zc_iflags, &props)) != 0)
+               return (error);
+
+       if (zc->zc_string[0])
+               origin = zc->zc_string;
+
+       begin_record.drr_type = DRR_BEGIN;
+       begin_record.drr_payloadlen = 0;
+       begin_record.drr_u.drr_begin = zc->zc_begin_record;
+
+       error = zfs_ioc_recv_impl(tofs, tosnap, origin, props, zc->zc_guid,
+           B_FALSE, zc->zc_cookie, &begin_record, zc->zc_cleanup_fd,
+           &zc->zc_cookie, &zc->zc_obj, &zc->zc_action_handle, &errors);
+       nvlist_free(props);
+
+       /*
+        * Now that all props, initial and delayed, are set, report the prop
+        * errors to the caller.
+        */
+       if (zc->zc_nvlist_dst_size != 0 && errors != NULL &&
+           (nvlist_smush(errors, zc->zc_nvlist_dst_size) != 0 ||
+           put_nvlist(zc, errors) != 0)) {
+               /*
+                * Caller made zc->zc_nvlist_dst less than the minimum expected
+                * size or supplied an invalid address.
+                */
+               error = SET_ERROR(EINVAL);
+       }
+
+       nvlist_free(errors);
+
+       return (error);
+}
+
+/*
+ * innvl: {
+ *     "snapname" -> full name of the snapshot to create
+ *     (optional) "props" -> properties to set (nvlist)
+ *     (optional) "origin" -> name of clone origin (DRR_FLAG_CLONE)
+ *     "begin_record" -> non-byteswapped dmu_replay_record_t
+ *     "input_fd" -> file descriptor to read stream from (int32)
+ *     (optional) "force" -> force flag (value ignored)
+ *     (optional) "resumable" -> resumable flag (value ignored)
+ *     (optional) "cleanup_fd" -> cleanup-on-exit file descriptor
+ *     (optional) "action_handle" -> handle for this guid/ds mapping
+ * }
+ *
+ * outnvl: {
+ *     "read_bytes" -> number of bytes read
+ *     "error_flags" -> zprop_errflags_t
+ *     "action_handle" -> handle for this guid/ds mapping
+ *     "errors" -> error for each unapplied received property (nvlist)
+ * }
+ */
+static int
+zfs_ioc_recv_new(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
+{
+       dmu_replay_record_t *begin_record;
+       uint_t begin_record_size;
+       nvlist_t *errors = NULL;
+       nvlist_t *props = NULL;
+       char *snapname = NULL;
+       char *origin = NULL;
+       char *tosnap;
+       char tofs[ZFS_MAX_DATASET_NAME_LEN];
+       boolean_t force;
+       boolean_t resumable;
+       uint64_t action_handle = 0;
+       uint64_t read_bytes = 0;
+       uint64_t errflags = 0;
+       int input_fd = -1;
+       int cleanup_fd = -1;
+       int error;
+
+       error = nvlist_lookup_string(innvl, "snapname", &snapname);
+       if (error != 0)
+               return (SET_ERROR(EINVAL));
+
+       if (dataset_namecheck(snapname, NULL, NULL) != 0 ||
+           strchr(snapname, '@') == NULL ||
+           strchr(snapname, '%'))
+               return (SET_ERROR(EINVAL));
+
+       (void) strcpy(tofs, snapname);
+       tosnap = strchr(tofs, '@');
+       *tosnap++ = '\0';
+
+       error = nvlist_lookup_string(innvl, "origin", &origin);
+       if (error && error != ENOENT)
+               return (error);
+
+       error = nvlist_lookup_byte_array(innvl, "begin_record",
+           (uchar_t **) &begin_record, &begin_record_size);
+       if (error != 0 || begin_record_size != sizeof (*begin_record))
+               return (SET_ERROR(EINVAL));
+
+       error = nvlist_lookup_int32(innvl, "input_fd", &input_fd);
+       if (error != 0)
+               return (SET_ERROR(EINVAL));
+
+       force = nvlist_exists(innvl, "force");
+       resumable = nvlist_exists(innvl, "resumable");
+
+       error = nvlist_lookup_int32(innvl, "cleanup_fd", &cleanup_fd);
+       if (error && error != ENOENT)
+               return (error);
+
+       error = nvlist_lookup_uint64(innvl, "action_handle", &action_handle);
+       if (error && error != ENOENT)
+               return (error);
+
+       error = nvlist_lookup_nvlist(innvl, "props", &props);
+       if (error && error != ENOENT)
+               return (error);
+
+       error = zfs_ioc_recv_impl(tofs, tosnap, origin, props, force,
+           resumable, input_fd, begin_record, cleanup_fd, &read_bytes,
+           &errflags, &action_handle, &errors);
+
+       fnvlist_add_uint64(outnvl, "read_bytes", read_bytes);
+       fnvlist_add_uint64(outnvl, "error_flags", errflags);
+       fnvlist_add_uint64(outnvl, "action_handle", action_handle);
+       fnvlist_add_nvlist(outnvl, "errors", errors);
+
+       nvlist_free(errors);
+       nvlist_free(props);
+
+       return (error);
+}
+
 /*
  * inputs:
  * zc_name     name of snapshot to send
@@ -4179,6 +4521,7 @@ zfs_ioc_send(zfs_cmd_t *zc)
        boolean_t estimate = (zc->zc_guid != 0);
        boolean_t embedok = (zc->zc_flags & 0x1);
        boolean_t large_block_ok = (zc->zc_flags & 0x2);
+       boolean_t compressok = (zc->zc_flags & 0x4);
 
        if (zc->zc_obj != 0) {
                dsl_pool_t *dp;
@@ -4226,7 +4569,7 @@ zfs_ioc_send(zfs_cmd_t *zc)
                        }
                }
 
-               error = dmu_send_estimate(tosnap, fromsnap,
+               error = dmu_send_estimate(tosnap, fromsnap, compressok,
                    &zc->zc_objset_type);
 
                if (fromsnap != NULL)
@@ -4240,7 +4583,7 @@ zfs_ioc_send(zfs_cmd_t *zc)
 
                off = fp->f_offset;
                error = dmu_send_obj(zc->zc_name, zc->zc_sendobj,
-                   zc->zc_fromobj, embedok, large_block_ok,
+                   zc->zc_fromobj, embedok, large_block_ok, compressok,
                    zc->zc_cookie, fp->f_vnode, &off);
 
                if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
@@ -4606,6 +4949,48 @@ zfs_ioc_userspace_upgrade(zfs_cmd_t *zc)
        return (error);
 }
 
+/*
+ * inputs:
+ * zc_name             name of filesystem
+ *
+ * outputs:
+ * none
+ */
+static int
+zfs_ioc_userobjspace_upgrade(zfs_cmd_t *zc)
+{
+       objset_t *os;
+       int error;
+
+       error = dmu_objset_hold(zc->zc_name, FTAG, &os);
+       if (error != 0)
+               return (error);
+
+       dsl_dataset_long_hold(dmu_objset_ds(os), FTAG);
+       dsl_pool_rele(dmu_objset_pool(os), FTAG);
+
+       if (dmu_objset_userobjspace_upgradable(os)) {
+               mutex_enter(&os->os_upgrade_lock);
+               if (os->os_upgrade_id == 0) {
+                       /* clear potential error code and retry */
+                       os->os_upgrade_status = 0;
+                       mutex_exit(&os->os_upgrade_lock);
+
+                       dmu_objset_userobjspace_upgrade(os);
+               } else {
+                       mutex_exit(&os->os_upgrade_lock);
+               }
+
+               taskq_wait_id(os->os_spa->spa_upgrade_taskq, os->os_upgrade_id);
+               error = os->os_upgrade_status;
+       }
+
+       dsl_dataset_long_rele(dmu_objset_ds(os), FTAG);
+       dsl_dataset_rele(dmu_objset_ds(os), FTAG);
+
+       return (error);
+}
+
 static int
 zfs_ioc_share(zfs_cmd_t *zc)
 {
@@ -4668,7 +5053,8 @@ zfs_ioc_tmp_snapshot(zfs_cmd_t *zc)
        error = dsl_dataset_snapshot_tmp(zc->zc_name, snap_name, minor,
            hold_name);
        if (error == 0)
-               (void) strcpy(zc->zc_value, snap_name);
+               (void) strlcpy(zc->zc_value, snap_name,
+                   sizeof (zc->zc_value));
        strfree(snap_name);
        strfree(hold_name);
        zfs_onexit_fd_rele(zc->zc_cleanup_fd);
@@ -4823,6 +5209,7 @@ zfs_ioc_smb_acl(zfs_cmd_t *zc)
                if ((error = get_nvlist(zc->zc_nvlist_src,
                    zc->zc_nvlist_src_size, zc->zc_iflags, &nvlist)) != 0) {
                        VN_RELE(vp);
+                       VN_RELE(ZTOV(sharedir));
                        ZFS_EXIT(zsb);
                        return (error);
                }
@@ -4875,6 +5262,7 @@ zfs_ioc_smb_acl(zfs_cmd_t *zc)
 static int
 zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
 {
+       nvpair_t *pair;
        nvlist_t *holds;
        int cleanup_fd = -1;
        int error;
@@ -4884,6 +5272,19 @@ zfs_ioc_hold(const char *pool, nvlist_t *args, nvlist_t *errlist)
        if (error != 0)
                return (SET_ERROR(EINVAL));
 
+       /* make sure the user didn't pass us any invalid (empty) tags */
+       for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL;
+           pair = nvlist_next_nvpair(holds, pair)) {
+               char *htag;
+
+               error = nvpair_value_string(pair, &htag);
+               if (error != 0)
+                       return (SET_ERROR(error));
+
+               if (strlen(htag) == 0)
+                       return (SET_ERROR(EINVAL));
+       }
+
        if (nvlist_lookup_int32(args, "cleanup_fd", &cleanup_fd) == 0) {
                error = zfs_onexit_fd_hold(cleanup_fd, &minor);
                if (error != 0)
@@ -5118,6 +5519,10 @@ zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl)
  *         indicates that blocks > 128KB are permitted
  *     (optional) "embedok" -> (value ignored)
  *         presence indicates DRR_WRITE_EMBEDDED records are permitted
+ *     (optional) "compressok" -> (value ignored)
+ *         presence indicates compressed DRR_WRITE records are permitted
+ *     (optional) "resume_object" and "resume_offset" -> (uint64)
+ *         if present, resume send stream from specified object and offset.
  * }
  *
  * outnvl is unused
@@ -5133,6 +5538,9 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
        file_t *fp;
        boolean_t largeblockok;
        boolean_t embedok;
+       boolean_t compressok;
+       uint64_t resumeobj = 0;
+       uint64_t resumeoff = 0;
 
        error = nvlist_lookup_int32(innvl, "fd", &fd);
        if (error != 0)
@@ -5142,13 +5550,17 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
 
        largeblockok = nvlist_exists(innvl, "largeblockok");
        embedok = nvlist_exists(innvl, "embedok");
+       compressok = nvlist_exists(innvl, "compressok");
+
+       (void) nvlist_lookup_uint64(innvl, "resume_object", &resumeobj);
+       (void) nvlist_lookup_uint64(innvl, "resume_offset", &resumeoff);
 
        if ((fp = getf(fd)) == NULL)
                return (SET_ERROR(EBADF));
 
        off = fp->f_offset;
-       error = dmu_send(snapname, fromname, embedok, largeblockok,
-           fd, fp->f_vnode, &off);
+       error = dmu_send(snapname, fromname, embedok, largeblockok, compressok,
+               fd, resumeobj, resumeoff, fp->f_vnode, &off);
 
        if (VOP_SEEK(fp->f_vnode, fp->f_offset, &off, NULL) == 0)
                fp->f_offset = off;
@@ -5164,6 +5576,12 @@ zfs_ioc_send_new(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
  * innvl: {
  *     (optional) "from" -> full snap or bookmark name to send an incremental
  *                          from
+ *     (optional) "largeblockok" -> (value ignored)
+ *         indicates that blocks > 128KB are permitted
+ *     (optional) "embedok" -> (value ignored)
+ *         presence indicates DRR_WRITE_EMBEDDED records are permitted
+ *     (optional) "compressok" -> (value ignored)
+ *         presence indicates compressed DRR_WRITE records are permitted
  * }
  *
  * outnvl: {
@@ -5177,6 +5595,11 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
        dsl_dataset_t *tosnap;
        int error;
        char *fromname;
+       /* LINTED E_FUNC_SET_NOT_USED */
+       boolean_t largeblockok;
+       /* LINTED E_FUNC_SET_NOT_USED */
+       boolean_t embedok;
+       boolean_t compressok;
        uint64_t space;
 
        error = dsl_pool_hold(snapname, FTAG, &dp);
@@ -5189,6 +5612,10 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
                return (error);
        }
 
+       largeblockok = nvlist_exists(innvl, "largeblockok");
+       embedok = nvlist_exists(innvl, "embedok");
+       compressok = nvlist_exists(innvl, "compressok");
+
        error = nvlist_lookup_string(innvl, "from", &fromname);
        if (error == 0) {
                if (strchr(fromname, '@') != NULL) {
@@ -5201,7 +5628,8 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
                        error = dsl_dataset_hold(dp, fromname, FTAG, &fromsnap);
                        if (error != 0)
                                goto out;
-                       error = dmu_send_estimate(tosnap, fromsnap, &space);
+                       error = dmu_send_estimate(tosnap, fromsnap, compressok,
+                               &space);
                        dsl_dataset_rele(fromsnap, FTAG);
                } else if (strchr(fromname, '#') != NULL) {
                        /*
@@ -5216,7 +5644,7 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
                        if (error != 0)
                                goto out;
                        error = dmu_send_estimate_from_txg(tosnap,
-                           frombm.zbm_creation_txg, &space);
+                           frombm.zbm_creation_txg, compressok, &space);
                } else {
                        /*
                         * from is not properly formatted as a snapshot or
@@ -5227,7 +5655,7 @@ zfs_ioc_send_space(const char *snapname, nvlist_t *innvl, nvlist_t *outnvl)
                }
        } else {
                // If estimating the size of a full send, use dmu_send_estimate
-               error = dmu_send_estimate(tosnap, NULL, &space);
+               error = dmu_send_estimate(tosnap, NULL, compressok, &space);
        }
 
        fnvlist_add_uint64(outnvl, "space", space);
@@ -5406,6 +5834,10 @@ zfs_ioctl_init(void)
            POOL_NAME,
            POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
 
+       zfs_ioctl_register("receive", ZFS_IOC_RECV_NEW,
+           zfs_ioc_recv_new, zfs_secpolicy_recv_new, DATASET_NAME,
+           POOL_CHECK_SUSPENDED | POOL_CHECK_READONLY, B_TRUE, B_TRUE);
+
        /* IOCTLS that use the legacy function signature */
 
        zfs_ioctl_register_legacy(ZFS_IOC_POOL_FREEZE, zfs_ioc_pool_freeze,
@@ -5783,7 +6215,23 @@ zfsdev_ioctl(struct file *filp, unsigned cmd, unsigned long arg)
        }
 
        zc->zc_iflags = flag & FKIOCTL;
-       if (zc->zc_nvlist_src_size != 0) {
+       if (zc->zc_nvlist_src_size > MAX_NVLIST_SRC_SIZE) {
+               /*
+                * Make sure the user doesn't pass in an insane value for
+                * zc_nvlist_src_size.  We have to check, since we will end
+                * up allocating that much memory inside of get_nvlist().  This
+                * prevents a nefarious user from allocating tons of kernel
+                * memory.
+                *
+                * Also, we return EINVAL instead of ENOMEM here.  The reason
+                * being that returning ENOMEM from an ioctl() has a special
+                * connotation; that the user's size value is too small and
+                * needs to be expanded to hold the nvlist.  See
+                * zcmd_expand_dst_nvlist() for details.
+                */
+               error = SET_ERROR(EINVAL);      /* User's size too big */
+
+       } else if (zc->zc_nvlist_src_size != 0) {
                error = get_nvlist(zc->zc_nvlist_src, zc->zc_nvlist_src_size,
                    zc->zc_iflags, &innvl);
                if (error != 0)
@@ -5975,7 +6423,9 @@ static void
 zfs_allow_log_destroy(void *arg)
 {
        char *poolname = arg;
-       strfree(poolname);
+
+       if (poolname != NULL)
+               strfree(poolname);
 }
 
 #ifdef DEBUG
index 38d8de0ebf9764b1381e73882f17039d9aa7c725..69efb3c161323bbd33b72aecc28bf856554d0c48 100644 (file)
@@ -279,14 +279,16 @@ zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
        lr = (lr_create_t *)&itx->itx_lr;
        lr->lr_doid = dzp->z_id;
        lr->lr_foid = zp->z_id;
+       /* Store dnode slot count in 8 bits above object id. */
+       LR_FOID_SET_SLOTS(lr->lr_foid, zp->z_dnodesize >> DNODE_SHIFT);
        lr->lr_mode = zp->z_mode;
-       if (!IS_EPHEMERAL(zp->z_uid)) {
-               lr->lr_uid = (uint64_t)zp->z_uid;
+       if (!IS_EPHEMERAL(KUID_TO_SUID(ZTOI(zp)->i_uid))) {
+               lr->lr_uid = (uint64_t)KUID_TO_SUID(ZTOI(zp)->i_uid);
        } else {
                lr->lr_uid = fuidp->z_fuid_owner;
        }
-       if (!IS_EPHEMERAL(zp->z_gid)) {
-               lr->lr_gid = (uint64_t)zp->z_gid;
+       if (!IS_EPHEMERAL(KGID_TO_SGID(ZTOI(zp)->i_gid))) {
+               lr->lr_gid = (uint64_t)KGID_TO_SGID(ZTOI(zp)->i_gid);
        } else {
                lr->lr_gid = fuidp->z_fuid_group;
        }
@@ -405,8 +407,8 @@ zfs_log_symlink(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype,
        lr = (lr_create_t *)&itx->itx_lr;
        lr->lr_doid = dzp->z_id;
        lr->lr_foid = zp->z_id;
-       lr->lr_uid = zp->z_uid;
-       lr->lr_gid = zp->z_gid;
+       lr->lr_uid = KUID_TO_SUID(ZTOI(zp)->i_uid);
+       lr->lr_gid = KGID_TO_SGID(ZTOI(zp)->i_gid);
        lr->lr_mode = zp->z_mode;
        (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_GEN(ZTOZSB(zp)), &lr->lr_gen,
            sizeof (uint64_t));
index 0ca1e03b595bc4dac27494d2ca8d764b798ad598..eee13c0651a296918b474d58a6560c8598862766 100644 (file)
@@ -204,7 +204,7 @@ zfs_replay_fuid_domain(void *buf, void **end, uint64_t uid, uint64_t gid)
                return (fuid_infop);
 
        fuid_infop->z_domain_table =
-           kmem_zalloc(domcnt * sizeof (char **), KM_SLEEP);
+           kmem_zalloc(domcnt * sizeof (char *), KM_SLEEP);
 
        zfs_replay_fuid_ugid(fuid_infop, uid, gid);
 
@@ -228,7 +228,7 @@ zfs_replay_fuids(void *start, void **end, int idcnt, int domcnt, uint64_t uid,
        fuid_infop->z_domain_cnt = domcnt;
 
        fuid_infop->z_domain_table =
-           kmem_zalloc(domcnt * sizeof (char **), KM_SLEEP);
+           kmem_zalloc(domcnt * sizeof (char *), KM_SLEEP);
 
        for (i = 0; i != idcnt; i++) {
                zfs_fuid_t *zfuid;
@@ -279,6 +279,8 @@ zfs_replay_create_acl(zfs_sb_t *zsb, lr_acl_create_t *lracl, boolean_t byteswap)
        void *fuidstart;
        size_t xvatlen = 0;
        uint64_t txtype;
+       uint64_t objid;
+       uint64_t dnodesize;
        int error;
 
        txtype = (lr->lr_common.lrc_txtype & ~TX_CI);
@@ -304,19 +306,24 @@ zfs_replay_create_acl(zfs_sb_t *zsb, lr_acl_create_t *lracl, boolean_t byteswap)
        if ((error = zfs_zget(zsb, lr->lr_doid, &dzp)) != 0)
                return (error);
 
+       objid = LR_FOID_GET_OBJ(lr->lr_foid);
+       dnodesize = LR_FOID_GET_SLOTS(lr->lr_foid) << DNODE_SHIFT;
+
        xva_init(&xva);
        zfs_init_vattr(&xva.xva_vattr, ATTR_MODE | ATTR_UID | ATTR_GID,
-           lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);
+           lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, objid);
 
        /*
         * All forms of zfs create (create, mkdir, mkxattrdir, symlink)
         * eventually end up in zfs_mknode(), which assigns the object's
-        * creation time and generation number.  The generic zfs_create()
-        * doesn't have either concept, so we smuggle the values inside
-        * the vattr's otherwise unused va_ctime and va_nblocks fields.
+        * creation time, generation number, and dnode size. The generic
+        * zfs_create() has no concept of these attributes, so we smuggle
+        * the values inside the vattr's otherwise unused va_ctime,
+        * va_nblocks, and va_fsid fields.
         */
        ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
        xva.xva_vattr.va_nblocks = lr->lr_gen;
+       xva.xva_vattr.va_fsid = dnodesize;
 
        error = dmu_object_info(zsb->z_os, lr->lr_foid, NULL);
        if (error != ENOENT)
@@ -418,6 +425,8 @@ zfs_replay_create(zfs_sb_t *zsb, lr_create_t *lr, boolean_t byteswap)
        void *start;
        size_t xvatlen;
        uint64_t txtype;
+       uint64_t objid;
+       uint64_t dnodesize;
        int error;
 
        txtype = (lr->lr_common.lrc_txtype & ~TX_CI);
@@ -431,21 +440,26 @@ zfs_replay_create(zfs_sb_t *zsb, lr_create_t *lr, boolean_t byteswap)
        if ((error = zfs_zget(zsb, lr->lr_doid, &dzp)) != 0)
                return (error);
 
+       objid = LR_FOID_GET_OBJ(lr->lr_foid);
+       dnodesize = LR_FOID_GET_SLOTS(lr->lr_foid) << DNODE_SHIFT;
+
        xva_init(&xva);
        zfs_init_vattr(&xva.xva_vattr, ATTR_MODE | ATTR_UID | ATTR_GID,
-           lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, lr->lr_foid);
+           lr->lr_mode, lr->lr_uid, lr->lr_gid, lr->lr_rdev, objid);
 
        /*
         * All forms of zfs create (create, mkdir, mkxattrdir, symlink)
         * eventually end up in zfs_mknode(), which assigns the object's
-        * creation time and generation number.  The generic zfs_create()
-        * doesn't have either concept, so we smuggle the values inside
-        * the vattr's otherwise unused va_ctime and va_nblocks fields.
+        * creation time, generation number, and dnode slot count. The
+        * generic zfs_create() has no concept of these attributes, so
+        * we smuggle the values inside * the vattr's otherwise unused
+        * va_ctime, va_nblocks, and va_nlink fields.
         */
        ZFS_TIME_DECODE(&xva.xva_vattr.va_ctime, lr->lr_crtime);
        xva.xva_vattr.va_nblocks = lr->lr_gen;
+       xva.xva_vattr.va_fsid = dnodesize;
 
-       error = dmu_object_info(zsb->z_os, lr->lr_foid, NULL);
+       error = dmu_object_info(zsb->z_os, objid, NULL);
        if (error != ENOENT)
                goto out;
 
@@ -548,7 +562,7 @@ zfs_replay_remove(zfs_sb_t *zsb, lr_remove_t *lr, boolean_t byteswap)
 
        switch ((int)lr->lr_common.lrc_txtype) {
        case TX_REMOVE:
-               error = zfs_remove(ZTOI(dzp), name, kcred);
+               error = zfs_remove(ZTOI(dzp), name, kcred, vflg);
                break;
        case TX_RMDIR:
                error = zfs_rmdir(ZTOI(dzp), name, NULL, kcred, vflg);
@@ -584,7 +598,7 @@ zfs_replay_link(zfs_sb_t *zsb, lr_link_t *lr, boolean_t byteswap)
        if (lr->lr_common.lrc_txtype & TX_CI)
                vflg |= FIGNORECASE;
 
-       error = zfs_link(ZTOI(dzp), ZTOI(zp), name, kcred);
+       error = zfs_link(ZTOI(dzp), ZTOI(zp), name, kcred, vflg);
 
        iput(ZTOI(zp));
        iput(ZTOI(dzp));
@@ -791,6 +805,8 @@ zfs_replay_setattr(zfs_sb_t *zsb, lr_setattr_t *lr, boolean_t byteswap)
        vap->va_size = lr->lr_size;
        ZFS_TIME_DECODE(&vap->va_atime, lr->lr_atime);
        ZFS_TIME_DECODE(&vap->va_mtime, lr->lr_mtime);
+       gethrestime(&vap->va_ctime);
+       vap->va_mask |= ATTR_CTIME;
 
        /*
         * Fill in xvattr_t portions if necessary.
index fd3e8a68d2a71db93249655676aab8ad10edaf32..d3f68537f97efd50a0dca28fe827a162318407ad 100644 (file)
@@ -617,14 +617,10 @@ zfs_range_reduce(rl_t *rl, uint64_t off, uint64_t len)
 int
 zfs_range_compare(const void *arg1, const void *arg2)
 {
-       const rl_t *rl1 = arg1;
-       const rl_t *rl2 = arg2;
-
-       if (rl1->r_off > rl2->r_off)
-               return (1);
-       if (rl1->r_off < rl2->r_off)
-               return (-1);
-       return (0);
+       const rl_t *rl1 = (const rl_t *)arg1;
+       const rl_t *rl2 = (const rl_t *)arg2;
+
+       return (AVL_CMP(rl1->r_off, rl2->r_off));
 }
 
 #ifdef _KERNEL
index fa1a679e177a9031b55057d968383a6466af5f14..33b767808cde51656ea03e0c70d0bb60a8dfa8c1 100644 (file)
@@ -97,8 +97,7 @@ zfs_sa_symlink(znode_t *zp, char *link, int len, dmu_tx_t *tx)
        dmu_buf_t *db = sa_get_db(zp->z_sa_hdl);
 
        if (ZFS_OLD_ZNODE_PHYS_SIZE + len <= dmu_bonus_max()) {
-               VERIFY(dmu_set_bonus(db,
-                   len + ZFS_OLD_ZNODE_PHYS_SIZE, tx) == 0);
+               VERIFY0(dmu_set_bonus(db, len + ZFS_OLD_ZNODE_PHYS_SIZE, tx));
                if (len) {
                        bcopy(link, (caddr_t)db->db_data +
                            ZFS_OLD_ZNODE_PHYS_SIZE, len);
@@ -107,8 +106,8 @@ zfs_sa_symlink(znode_t *zp, char *link, int len, dmu_tx_t *tx)
                dmu_buf_t *dbp;
 
                zfs_grow_blocksize(zp, len, tx);
-               VERIFY(0 == dmu_buf_hold(ZTOZSB(zp)->z_os,
-                   zp->z_id, 0, FTAG, &dbp, DMU_READ_NO_PREFETCH));
+               VERIFY0(dmu_buf_hold(ZTOZSB(zp)->z_os, zp->z_id, 0, FTAG, &dbp,
+                   DMU_READ_NO_PREFETCH));
 
                dmu_buf_will_dirty(dbp, tx);
 
@@ -276,8 +275,9 @@ zfs_sa_upgrade(sa_handle_t *hdl, dmu_tx_t *tx)
        int count = 0;
        sa_bulk_attr_t *bulk, *sa_attrs;
        zfs_acl_locator_cb_t locate = { 0 };
-       uint64_t uid, gid, mode, rdev, xattr, parent;
-       uint64_t crtime[2], mtime[2], ctime[2];
+       uint64_t uid, gid, mode, rdev, xattr, parent, tmp_gen;
+       uint64_t crtime[2], mtime[2], ctime[2], atime[2];
+       uint64_t links;
        zfs_acl_phys_t znode_acl;
        char scanstamp[AV_SCANSTAMP_SZ];
        boolean_t drop_lock = B_FALSE;
@@ -309,6 +309,7 @@ zfs_sa_upgrade(sa_handle_t *hdl, dmu_tx_t *tx)
 
        /* First do a bulk query of the attributes that aren't cached */
        bulk = kmem_alloc(sizeof (sa_bulk_attr_t) * 20, KM_SLEEP);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL, &atime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL, &ctime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CRTIME(zsb), NULL, &crtime, 16);
@@ -318,6 +319,7 @@ zfs_sa_upgrade(sa_handle_t *hdl, dmu_tx_t *tx)
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_RDEV(zsb), NULL, &rdev, 8);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zsb), NULL, &uid, 8);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zsb), NULL, &gid, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GEN(zsb), NULL, &tmp_gen, 8);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ZNODE_ACL(zsb), NULL,
            &znode_acl, 88);
 
@@ -335,8 +337,7 @@ zfs_sa_upgrade(sa_handle_t *hdl, dmu_tx_t *tx)
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_MODE(zsb), NULL, &mode, 8);
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_SIZE(zsb), NULL,
            &zp->z_size, 8);
-       SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_GEN(zsb),
-           NULL, &zp->z_gen, 8);
+       SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_GEN(zsb), NULL, &tmp_gen, 8);
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_UID(zsb), NULL, &uid, 8);
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_GID(zsb), NULL, &gid, 8);
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_PARENT(zsb),
@@ -344,15 +345,16 @@ zfs_sa_upgrade(sa_handle_t *hdl, dmu_tx_t *tx)
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_FLAGS(zsb), NULL,
            &zp->z_pflags, 8);
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_ATIME(zsb), NULL,
-           zp->z_atime, 16);
+           &atime, 16);
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_MTIME(zsb), NULL,
            &mtime, 16);
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_CTIME(zsb), NULL,
            &ctime, 16);
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_CRTIME(zsb), NULL,
            &crtime, 16);
+       links = ZTOI(zp)->i_nlink;
        SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_LINKS(zsb), NULL,
-           &zp->z_links, 8);
+           &links, 8);
        if (S_ISBLK(ZTOI(zp)->i_mode) || S_ISCHR(ZTOI(zp)->i_mode))
                SA_ADD_BULK_ATTR(sa_attrs, count, SA_ZPL_RDEV(zsb), NULL,
                    &rdev, 8);
index b9f1715b538ed9e0061f23ab517a97b1fd93e30b..eb73f3b600c7b729397ba90b9a130d1556756f90 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -341,38 +341,7 @@ zfs_register_callbacks(zfs_sb_t *zsb)
        return (0);
 
 unregister:
-       /*
-        * We may attempt to unregister some callbacks that are not
-        * registered, but this is OK; it will simply return ENOMSG,
-        * which we will ignore.
-        */
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ATIME),
-           atime_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RELATIME),
-           relatime_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_XATTR),
-           xattr_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_RECORDSIZE),
-           blksz_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_READONLY),
-           readonly_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_DEVICES),
-           devices_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SETUID),
-           setuid_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_EXEC),
-           exec_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_SNAPDIR),
-           snapdir_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLTYPE),
-           acltype_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_ACLINHERIT),
-           acl_inherit_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_VSCAN),
-           vscan_changed_cb, zsb);
-       (void) dsl_prop_unregister(ds, zfs_prop_to_name(ZFS_PROP_NBMAND),
-           nbmand_changed_cb, zsb);
-
+       dsl_prop_unregister_all(ds, zsb);
        return (error);
 }
 EXPORT_SYMBOL(zfs_register_callbacks);
@@ -462,17 +431,22 @@ zfs_userquota_prop_to_obj(zfs_sb_t *zsb, zfs_userquota_prop_t type)
 {
        switch (type) {
        case ZFS_PROP_USERUSED:
+       case ZFS_PROP_USEROBJUSED:
                return (DMU_USERUSED_OBJECT);
        case ZFS_PROP_GROUPUSED:
+       case ZFS_PROP_GROUPOBJUSED:
                return (DMU_GROUPUSED_OBJECT);
        case ZFS_PROP_USERQUOTA:
                return (zsb->z_userquota_obj);
        case ZFS_PROP_GROUPQUOTA:
                return (zsb->z_groupquota_obj);
+       case ZFS_PROP_USEROBJQUOTA:
+               return (zsb->z_userobjquota_obj);
+       case ZFS_PROP_GROUPOBJQUOTA:
+               return (zsb->z_groupobjquota_obj);
        default:
-               return (SET_ERROR(ENOTSUP));
+               return (ZFS_NO_OBJECT);
        }
-       return (0);
 }
 
 int
@@ -484,16 +458,25 @@ zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
        zap_attribute_t za;
        zfs_useracct_t *buf = vbuf;
        uint64_t obj;
+       int offset = 0;
 
        if (!dmu_objset_userspace_present(zsb->z_os))
                return (SET_ERROR(ENOTSUP));
 
+       if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
+           type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA) &&
+           !dmu_objset_userobjspace_present(zsb->z_os))
+               return (SET_ERROR(ENOTSUP));
+
        obj = zfs_userquota_prop_to_obj(zsb, type);
-       if (obj == 0) {
+       if (obj == ZFS_NO_OBJECT) {
                *bufsizep = 0;
                return (0);
        }
 
+       if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED)
+               offset = DMU_OBJACCT_PREFIX_LEN;
+
        for (zap_cursor_init_serialized(&zc, zsb->z_os, obj, *cookiep);
            (error = zap_cursor_retrieve(&zc, &za)) == 0;
            zap_cursor_advance(&zc)) {
@@ -501,7 +484,15 @@ zfs_userspace_many(zfs_sb_t *zsb, zfs_userquota_prop_t type,
                    *bufsizep)
                        break;
 
-               fuidstr_to_sid(zsb, za.za_name,
+               /*
+                * skip object quota (with zap name prefix DMU_OBJACCT_PREFIX)
+                * when dealing with block quota and vice versa.
+                */
+               if ((offset > 0) != (strncmp(za.za_name, DMU_OBJACCT_PREFIX,
+                   DMU_OBJACCT_PREFIX_LEN) == 0))
+                       continue;
+
+               fuidstr_to_sid(zsb, za.za_name + offset,
                    buf->zu_domain, sizeof (buf->zu_domain), &buf->zu_rid);
 
                buf->zu_space = za.za_first_integer;
@@ -542,7 +533,8 @@ int
 zfs_userspace_one(zfs_sb_t *zsb, zfs_userquota_prop_t type,
     const char *domain, uint64_t rid, uint64_t *valp)
 {
-       char buf[32];
+       char buf[20 + DMU_OBJACCT_PREFIX_LEN];
+       int offset = 0;
        int err;
        uint64_t obj;
 
@@ -551,11 +543,21 @@ zfs_userspace_one(zfs_sb_t *zsb, zfs_userquota_prop_t type,
        if (!dmu_objset_userspace_present(zsb->z_os))
                return (SET_ERROR(ENOTSUP));
 
+       if ((type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED ||
+           type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA) &&
+           !dmu_objset_userobjspace_present(zsb->z_os))
+               return (SET_ERROR(ENOTSUP));
+
        obj = zfs_userquota_prop_to_obj(zsb, type);
-       if (obj == 0)
+       if (obj == ZFS_NO_OBJECT)
                return (0);
 
-       err = id_to_fuidstr(zsb, domain, rid, buf, B_FALSE);
+       if (type == ZFS_PROP_USEROBJUSED || type == ZFS_PROP_GROUPOBJUSED) {
+               strlcpy(buf, DMU_OBJACCT_PREFIX, DMU_OBJACCT_PREFIX_LEN);
+               offset = DMU_OBJACCT_PREFIX_LEN;
+       }
+
+       err = id_to_fuidstr(zsb, domain, rid, buf + offset, B_FALSE);
        if (err)
                return (err);
 
@@ -576,14 +578,25 @@ zfs_set_userquota(zfs_sb_t *zsb, zfs_userquota_prop_t type,
        uint64_t *objp;
        boolean_t fuid_dirtied;
 
-       if (type != ZFS_PROP_USERQUOTA && type != ZFS_PROP_GROUPQUOTA)
-               return (SET_ERROR(EINVAL));
-
        if (zsb->z_version < ZPL_VERSION_USERSPACE)
                return (SET_ERROR(ENOTSUP));
 
-       objp = (type == ZFS_PROP_USERQUOTA) ? &zsb->z_userquota_obj :
-           &zsb->z_groupquota_obj;
+       switch (type) {
+       case ZFS_PROP_USERQUOTA:
+               objp = &zsb->z_userquota_obj;
+               break;
+       case ZFS_PROP_GROUPQUOTA:
+               objp = &zsb->z_groupquota_obj;
+               break;
+       case ZFS_PROP_USEROBJQUOTA:
+               objp = &zsb->z_userobjquota_obj;
+               break;
+       case ZFS_PROP_GROUPOBJQUOTA:
+               objp = &zsb->z_groupobjquota_obj;
+               break;
+       default:
+               return (SET_ERROR(EINVAL));
+       }
 
        err = id_to_fuidstr(zsb, domain, rid, buf, B_TRUE);
        if (err)
@@ -628,10 +641,40 @@ zfs_set_userquota(zfs_sb_t *zsb, zfs_userquota_prop_t type,
 }
 EXPORT_SYMBOL(zfs_set_userquota);
 
+boolean_t
+zfs_fuid_overobjquota(zfs_sb_t *zsb, boolean_t isgroup, uint64_t fuid)
+{
+       char buf[20 + DMU_OBJACCT_PREFIX_LEN];
+       uint64_t used, quota, usedobj, quotaobj;
+       int err;
+
+       if (!dmu_objset_userobjspace_present(zsb->z_os)) {
+               if (dmu_objset_userobjspace_upgradable(zsb->z_os))
+                       dmu_objset_userobjspace_upgrade(zsb->z_os);
+               return (B_FALSE);
+       }
+
+       usedobj = isgroup ? DMU_GROUPUSED_OBJECT : DMU_USERUSED_OBJECT;
+       quotaobj = isgroup ? zsb->z_groupobjquota_obj : zsb->z_userobjquota_obj;
+       if (quotaobj == 0 || zsb->z_replay)
+               return (B_FALSE);
+
+       (void) sprintf(buf, "%llx", (longlong_t)fuid);
+       err = zap_lookup(zsb->z_os, quotaobj, buf, 8, 1, &quota);
+       if (err != 0)
+               return (B_FALSE);
+
+       (void) sprintf(buf, DMU_OBJACCT_PREFIX "%llx", (longlong_t)fuid);
+       err = zap_lookup(zsb->z_os, usedobj, buf, 8, 1, &used);
+       if (err != 0)
+               return (B_FALSE);
+       return (used >= quota);
+}
+
 boolean_t
 zfs_fuid_overquota(zfs_sb_t *zsb, boolean_t isgroup, uint64_t fuid)
 {
-       char buf[32];
+       char buf[20];
        uint64_t used, quota, usedobj, quotaobj;
        int err;
 
@@ -658,10 +701,11 @@ zfs_owner_overquota(zfs_sb_t *zsb, znode_t *zp, boolean_t isgroup)
 {
        uint64_t fuid;
        uint64_t quotaobj;
+       struct inode *ip = ZTOI(zp);
 
        quotaobj = isgroup ? zsb->z_groupquota_obj : zsb->z_userquota_obj;
 
-       fuid = isgroup ? zp->z_gid : zp->z_uid;
+       fuid = isgroup ? KGID_TO_SGID(ip->i_gid) : KUID_TO_SUID(ip->i_uid);
 
        if (quotaobj == 0 || zsb->z_replay)
                return (B_FALSE);
@@ -807,6 +851,18 @@ zfs_sb_create(const char *osname, zfs_mntopts_t *zmo, zfs_sb_t **zsbp)
        if (error && error != ENOENT)
                goto out;
 
+       error = zap_lookup(os, MASTER_NODE_OBJ,
+           zfs_userquota_prop_prefixes[ZFS_PROP_USEROBJQUOTA],
+           8, 1, &zsb->z_userobjquota_obj);
+       if (error && error != ENOENT)
+               goto out;
+
+       error = zap_lookup(os, MASTER_NODE_OBJ,
+           zfs_userquota_prop_prefixes[ZFS_PROP_GROUPOBJQUOTA],
+           8, 1, &zsb->z_groupobjquota_obj);
+       if (error && error != ENOENT)
+               goto out;
+
        error = zap_lookup(os, MASTER_NODE_OBJ, ZFS_FUID_TABLES, 8, 1,
            &zsb->z_fuid_obj);
        if (error && error != ENOENT)
@@ -965,52 +1021,9 @@ void
 zfs_unregister_callbacks(zfs_sb_t *zsb)
 {
        objset_t *os = zsb->z_os;
-       struct dsl_dataset *ds;
-
-       /*
-        * Unregister properties.
-        */
-       if (!dmu_objset_is_snapshot(os)) {
-               ds = dmu_objset_ds(os);
-               VERIFY(dsl_prop_unregister(ds, "atime", atime_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "relatime", relatime_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "xattr", xattr_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "recordsize", blksz_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "readonly", readonly_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "devices", devices_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "setuid", setuid_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "exec", exec_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "snapdir", snapdir_changed_cb,
-                   zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "acltype", acltype_changed_cb,
-                   zsb) == 0);
 
-               VERIFY(dsl_prop_unregister(ds, "aclinherit",
-                   acl_inherit_changed_cb, zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "vscan",
-                   vscan_changed_cb, zsb) == 0);
-
-               VERIFY(dsl_prop_unregister(ds, "nbmand",
-                   nbmand_changed_cb, zsb) == 0);
-       }
+       if (!dmu_objset_is_snapshot(os))
+               dsl_prop_unregister_all(dmu_objset_ds(os), zsb);
 }
 EXPORT_SYMBOL(zfs_unregister_callbacks);
 
@@ -1094,7 +1107,7 @@ zfs_statvfs(struct dentry *dentry, struct kstatfs *statp)
        statp->f_fsid.val[0] = (uint32_t)fsid;
        statp->f_fsid.val[1] = (uint32_t)(fsid >> 32);
        statp->f_type = ZFS_SUPER_MAGIC;
-       statp->f_namelen = ZFS_MAXNAMELEN;
+       statp->f_namelen = MAXNAMELEN - 1;
 
        /*
         * We have all of 40 characters to stuff a string here.
@@ -1443,7 +1456,8 @@ zfs_domount(struct super_block *sb, zfs_mntopts_t *zmo, int silent)
                dmu_objset_set_user(zsb->z_os, zsb);
                mutex_exit(&zsb->z_os->os_user_ptr_lock);
        } else {
-               error = zfs_sb_setup(zsb, B_TRUE);
+               if ((error = zfs_sb_setup(zsb, B_TRUE)))
+                       goto out;
        }
 
        /* Allocate a root inode for the filesystem. */
@@ -1469,6 +1483,11 @@ out:
        if (error) {
                dmu_objset_disown(zsb->z_os, zsb);
                zfs_sb_free(zsb);
+               /*
+                * make sure we don't have dangling sb->s_fs_info which
+                * zfs_preumount will use.
+                */
+               sb->s_fs_info = NULL;
        }
 
        return (error);
@@ -1487,8 +1506,29 @@ zfs_preumount(struct super_block *sb)
 {
        zfs_sb_t *zsb = sb->s_fs_info;
 
-       if (zsb)
+       /* zsb is NULL when zfs_domount fails during mount */
+       if (zsb) {
                zfsctl_destroy(sb->s_fs_info);
+               /*
+                * Wait for iput_async before entering evict_inodes in
+                * generic_shutdown_super. The reason we must finish before
+                * evict_inodes is when lazytime is on, or when zfs_purgedir
+                * calls zfs_zget, iput would bump i_count from 0 to 1. This
+                * would race with the i_count check in evict_inodes. This means
+                * it could destroy the inode while we are still using it.
+                *
+                * We wait for two passes. xattr directories in the first pass
+                * may add xattr entries in zfs_purgedir, so in the second pass
+                * we wait for them. We don't use taskq_wait here because it is
+                * a pool wide taskq. Other mounted filesystems can constantly
+                * do iput_async and there's no guarantee when taskq will be
+                * empty.
+                */
+               taskq_wait_outstanding(dsl_pool_iput_taskq(
+                   dmu_objset_pool(zsb->z_os)), 0);
+               taskq_wait_outstanding(dsl_pool_iput_taskq(
+                   dmu_objset_pool(zsb->z_os)), 0);
+       }
 }
 EXPORT_SYMBOL(zfs_preumount);
 
index 960df25bcc810c9eda1cbe019a685e23a70a213a..8ac14df0039f0916fff1b505b3bcb61bc7b0f3ba 100644 (file)
@@ -20,7 +20,8 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
  */
 
@@ -417,6 +418,7 @@ mappedread(struct inode *ip, int nbytes, uio_t *uio)
 #endif /* _KERNEL */
 
 unsigned long zfs_read_chunk_size = 1024 * 1024; /* Tunable */
+unsigned long zfs_delete_blocks = DMU_MAX_DELETEBLKCNT;
 
 /*
  * Read bytes from specified file into supplied buffer.
@@ -550,7 +552,6 @@ zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 out:
        zfs_range_unlock(rl);
 
-       ZFS_ACCESSTIME_STAMP(zsb, zp);
        ZFS_EXIT(zsb);
        return (error);
 }
@@ -595,13 +596,16 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
        arc_buf_t       *abuf;
        const iovec_t   *aiov = NULL;
        xuio_t          *xuio = NULL;
-       int             i_iov = 0;
-       const iovec_t   *iovp = uio->uio_iov;
        int             write_eof;
        int             count = 0;
        sa_bulk_attr_t  bulk[4];
        uint64_t        mtime[2], ctime[2];
+       uint32_t        uid;
+#ifdef HAVE_UIO_ZEROCOPY
+       int             i_iov = 0;
+       const iovec_t   *iovp = uio->uio_iov;
        ASSERTV(int     iovcnt = uio->uio_iovcnt);
+#endif
 
        /*
         * Fasttrack empty write
@@ -622,6 +626,15 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb), NULL,
            &zp->z_pflags, 8);
 
+       /*
+        * Callers might not be able to detect properly that we are read-only,
+        * so check it explicitly here.
+        */
+       if (zfs_is_readonly(zsb)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EROFS));
+       }
+
        /*
         * If immutable or not appending then return EPERM
         */
@@ -715,6 +728,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                }
 
                if (xuio && abuf == NULL) {
+#ifdef HAVE_UIO_ZEROCOPY
                        ASSERT(i_iov < iovcnt);
                        ASSERT3U(uio->uio_segflg, !=, UIO_BVEC);
                        aiov = &iovp[i_iov];
@@ -724,6 +738,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                            ((char *)aiov->iov_base - (char *)abuf->b_data +
                            aiov->iov_len == arc_buf_size(abuf)));
                        i_iov++;
+#endif
                } else if (abuf == NULL && n >= max_blksz &&
                    woff >= zp->z_size &&
                    P2PHASE(woff, max_blksz) == 0 &&
@@ -852,21 +867,21 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                 * user 0 is not an ephemeral uid.
                 */
                mutex_enter(&zp->z_acl_lock);
+               uid = KUID_TO_SUID(ip->i_uid);
                if ((zp->z_mode & (S_IXUSR | (S_IXUSR >> 3) |
                    (S_IXUSR >> 6))) != 0 &&
                    (zp->z_mode & (S_ISUID | S_ISGID)) != 0 &&
                    secpolicy_vnode_setid_retain(cr,
-                   (zp->z_mode & S_ISUID) != 0 && zp->z_uid == 0) != 0) {
+                   ((zp->z_mode & S_ISUID) != 0 && uid == 0)) != 0) {
                        uint64_t newmode;
                        zp->z_mode &= ~(S_ISUID | S_ISGID);
-                       newmode = zp->z_mode;
+                       ip->i_mode = newmode = zp->z_mode;
                        (void) sa_update(zp->z_sa_hdl, SA_ZPL_MODE(zsb),
                            (void *)&newmode, sizeof (uint64_t), tx);
                }
                mutex_exit(&zp->z_acl_lock);
 
-               zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime,
-                   B_TRUE);
+               zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime);
 
                /*
                 * Update the file size (zp_size) if it has changed;
@@ -921,6 +936,12 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 }
 EXPORT_SYMBOL(zfs_write);
 
+/*
+ * Drop a reference on the passed inode asynchronously. This ensures
+ * that the caller will never drop the last reference on an inode in
+ * the current context. Doing so while holding open a tx could result
+ * in a deadlock if iput_final() re-enters the filesystem code.
+ */
 void
 zfs_iput_async(struct inode *ip)
 {
@@ -930,8 +951,8 @@ zfs_iput_async(struct inode *ip)
        ASSERT(os != NULL);
 
        if (atomic_read(&ip->i_count) == 1)
-               taskq_dispatch(dsl_pool_iput_taskq(dmu_objset_pool(os)),
-                   (task_func_t *)iput, ip, TQ_SLEEP);
+               VERIFY(taskq_dispatch(dsl_pool_iput_taskq(dmu_objset_pool(os)),
+                   (task_func_t *)iput, ip, TQ_SLEEP) != 0);
        else
                iput(ip);
 }
@@ -1459,8 +1480,10 @@ top:
                if (S_ISREG(ZTOI(zp)->i_mode) &&
                    (vap->va_mask & ATTR_SIZE) && (vap->va_size == 0)) {
                        /* we can't hold any locks when calling zfs_freesp() */
-                       zfs_dirent_unlock(dl);
-                       dl = NULL;
+                       if (dl) {
+                               zfs_dirent_unlock(dl);
+                               dl = NULL;
+                       }
                        error = zfs_freesp(zp, 0, 0, mode, TRUE);
                }
        }
@@ -1505,24 +1528,24 @@ uint64_t null_xattr = 0;
 
 /*ARGSUSED*/
 int
-zfs_remove(struct inode *dip, char *name, cred_t *cr)
+zfs_remove(struct inode *dip, char *name, cred_t *cr, int flags)
 {
        znode_t         *zp, *dzp = ITOZ(dip);
        znode_t         *xzp;
        struct inode    *ip;
        zfs_sb_t        *zsb = ITOZSB(dip);
        zilog_t         *zilog;
-       uint64_t        xattr_obj;
+       uint64_t        acl_obj, xattr_obj;
        uint64_t        xattr_obj_unlinked = 0;
        uint64_t        obj = 0;
+       uint64_t        links;
        zfs_dirlock_t   *dl;
        dmu_tx_t        *tx;
-       boolean_t       unlinked;
+       boolean_t       may_delete_now, delete_now = FALSE;
+       boolean_t       unlinked, toobig = FALSE;
        uint64_t        txtype;
        pathname_t      *realnmp = NULL;
-#ifdef HAVE_PN_UTILS
        pathname_t      realnm;
-#endif /* HAVE_PN_UTILS */
        int             error;
        int             zflg = ZEXISTS;
        boolean_t       waited = B_FALSE;
@@ -1531,13 +1554,11 @@ zfs_remove(struct inode *dip, char *name, cred_t *cr)
        ZFS_VERIFY_ZP(dzp);
        zilog = zsb->z_log;
 
-#ifdef HAVE_PN_UTILS
        if (flags & FIGNORECASE) {
                zflg |= ZCILOOK;
                pn_alloc(&realnm);
                realnmp = &realnm;
        }
-#endif /* HAVE_PN_UTILS */
 
 top:
        xattr_obj = 0;
@@ -1547,10 +1568,8 @@ top:
         */
        if ((error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg,
            NULL, realnmp))) {
-#ifdef HAVE_PN_UTILS
                if (realnmp)
                        pn_free(realnmp);
-#endif /* HAVE_PN_UTILS */
                ZFS_EXIT(zsb);
                return (error);
        }
@@ -1576,10 +1595,15 @@ top:
                dnlc_remove(dvp, name);
 #endif /* HAVE_DNLC */
 
+       mutex_enter(&zp->z_lock);
+       may_delete_now = atomic_read(&ip->i_count) == 1 && !(zp->z_is_mapped);
+       mutex_exit(&zp->z_lock);
+
        /*
-        * We never delete the znode and always place it in the unlinked
-        * set.  The dentry cache will always hold the last reference and
-        * is responsible for safely freeing the znode.
+        * We may delete the znode now, or we may put it in the unlinked set;
+        * it depends on whether we're the last link, and on whether there are
+        * other holds on the inode.  So we dmu_tx_hold() the right things to
+        * allow for either case.
         */
        obj = zp->z_id;
        tx = dmu_tx_create(zsb->z_os);
@@ -1587,6 +1611,12 @@ top:
        dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
        zfs_sa_upgrade_txholds(tx, zp);
        zfs_sa_upgrade_txholds(tx, dzp);
+       if (may_delete_now) {
+               toobig = zp->z_size > zp->z_blksz * zfs_delete_blocks;
+               /* if the file is too big, only hold_free a token amount */
+               dmu_tx_hold_free(tx, zp->z_id, 0,
+                   (toobig ? DMU_MAX_ACCESS : DMU_OBJECT_END));
+       }
 
        /* are there any extended attributes? */
        error = sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zsb),
@@ -1598,9 +1628,19 @@ top:
                dmu_tx_hold_sa(tx, xzp->z_sa_hdl, B_FALSE);
        }
 
+       mutex_enter(&zp->z_lock);
+       if ((acl_obj = zfs_external_acl(zp)) != 0 && may_delete_now)
+               dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END);
+       mutex_exit(&zp->z_lock);
+
        /* charge as an update -- would be nice not to charge at all */
        dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
 
+       /*
+        * Mark this transaction as typically resulting in a net free of space
+        */
+       dmu_tx_mark_netfree(tx);
+
        error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
        if (error) {
                zfs_dirent_unlock(dl);
@@ -1613,10 +1653,8 @@ top:
                        dmu_tx_abort(tx);
                        goto top;
                }
-#ifdef HAVE_PN_UTILS
                if (realnmp)
                        pn_free(realnmp);
-#endif /* HAVE_PN_UTILS */
                dmu_tx_abort(tx);
                ZFS_EXIT(zsb);
                return (error);
@@ -1641,33 +1679,69 @@ top:
                mutex_enter(&zp->z_lock);
                (void) sa_lookup(zp->z_sa_hdl, SA_ZPL_XATTR(zsb),
                    &xattr_obj_unlinked, sizeof (xattr_obj_unlinked));
+               delete_now = may_delete_now && !toobig &&
+                   atomic_read(&ip->i_count) == 1 && !(zp->z_is_mapped) &&
+                   xattr_obj == xattr_obj_unlinked && zfs_external_acl(zp) ==
+                   acl_obj;
+       }
+
+       if (delete_now) {
+               if (xattr_obj_unlinked) {
+                       ASSERT3U(ZTOI(xzp)->i_nlink, ==, 2);
+                       mutex_enter(&xzp->z_lock);
+                       xzp->z_unlinked = 1;
+                       clear_nlink(ZTOI(xzp));
+                       links = 0;
+                       error = sa_update(xzp->z_sa_hdl, SA_ZPL_LINKS(zsb),
+                           &links, sizeof (links), tx);
+                       ASSERT3U(error,  ==,  0);
+                       mutex_exit(&xzp->z_lock);
+                       zfs_unlinked_add(xzp, tx);
+
+                       if (zp->z_is_sa)
+                               error = sa_remove(zp->z_sa_hdl,
+                                   SA_ZPL_XATTR(zsb), tx);
+                       else
+                               error = sa_update(zp->z_sa_hdl,
+                                   SA_ZPL_XATTR(zsb), &null_xattr,
+                                   sizeof (uint64_t), tx);
+                       ASSERT0(error);
+               }
+               /*
+                * Add to the unlinked set because a new reference could be
+                * taken concurrently resulting in a deferred destruction.
+                */
+               zfs_unlinked_add(zp, tx);
+               mutex_exit(&zp->z_lock);
+               zfs_inode_update(zp);
+               iput(ip);
+       } else if (unlinked) {
                mutex_exit(&zp->z_lock);
                zfs_unlinked_add(zp, tx);
        }
 
        txtype = TX_REMOVE;
-#ifdef HAVE_PN_UTILS
        if (flags & FIGNORECASE)
                txtype |= TX_CI;
-#endif /* HAVE_PN_UTILS */
        zfs_log_remove(zilog, tx, txtype, dzp, name, obj);
 
        dmu_tx_commit(tx);
 out:
-#ifdef HAVE_PN_UTILS
        if (realnmp)
                pn_free(realnmp);
-#endif /* HAVE_PN_UTILS */
 
        zfs_dirent_unlock(dl);
        zfs_inode_update(dzp);
-       zfs_inode_update(zp);
-       if (xzp)
-               zfs_inode_update(xzp);
 
-       iput(ip);
-       if (xzp)
-               iput(ZTOI(xzp));
+       if (!delete_now) {
+               zfs_inode_update(zp);
+               zfs_iput_async(ip);
+       }
+
+       if (xzp) {
+               zfs_inode_update(xzp);
+               zfs_iput_async(ZTOI(xzp));
+       }
 
        if (zsb->z_os->os_sync == ZFS_SYNC_ALWAYS)
                zil_commit(zilog, 0);
@@ -1941,6 +2015,7 @@ top:
        dmu_tx_hold_zap(tx, zsb->z_unlinkedobj, FALSE, NULL);
        zfs_sa_upgrade_txholds(tx, zp);
        zfs_sa_upgrade_txholds(tx, dzp);
+       dmu_tx_mark_netfree(tx);
        error = dmu_tx_assign(tx, waited ? TXG_WAITED : TXG_NOWAIT);
        if (error) {
                rw_exit(&zp->z_parent_lock);
@@ -2120,7 +2195,8 @@ zfs_readdir(struct inode *ip, struct dir_context *ctx, cred_t *cr)
 
                /* Prefetch znode */
                if (prefetch) {
-                       dmu_prefetch(os, objnum, 0, 0);
+                       dmu_prefetch(os, objnum, 0, 0, 0,
+                           ZIO_PRIORITY_SYNC_READ);
                }
 
                /*
@@ -2140,9 +2216,6 @@ update:
        zap_cursor_fini(&zc);
        if (error == ENOENT)
                error = 0;
-
-       ZFS_ACCESSTIME_STAMP(zsb, zp);
-
 out:
        ZFS_EXIT(zsb);
 
@@ -2195,11 +2268,11 @@ zfs_getattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
        zfs_sb_t *zsb = ITOZSB(ip);
        int     error = 0;
        uint64_t links;
-       uint64_t mtime[2], ctime[2];
+       uint64_t atime[2], mtime[2], ctime[2];
        xvattr_t *xvap = (xvattr_t *)vap;       /* vap may be an xvattr_t * */
        xoptattr_t *xoap = NULL;
        boolean_t skipaclchk = (flags & ATTR_NOACLCHECK) ? B_TRUE : B_FALSE;
-       sa_bulk_attr_t bulk[2];
+       sa_bulk_attr_t bulk[3];
        int count = 0;
 
        ZFS_ENTER(zsb);
@@ -2207,6 +2280,7 @@ zfs_getattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
 
        zfs_fuid_map_ids(zp, cr, &vap->va_uid, &vap->va_gid);
 
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL, &atime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL, &ctime, 16);
 
@@ -2240,9 +2314,9 @@ zfs_getattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
        vap->va_fsid = ZTOI(zp)->i_sb->s_dev;
        vap->va_nodeid = zp->z_id;
        if ((zp->z_id == zsb->z_root) && zfs_show_ctldir(zp))
-               links = zp->z_links + 1;
+               links = ZTOI(zp)->i_nlink + 1;
        else
-               links = zp->z_links;
+               links = ZTOI(zp)->i_nlink;
        vap->va_nlink = MIN(links, ZFS_LINK_MAX);
        vap->va_size = i_size_read(ip);
        vap->va_rdev = ip->i_rdev;
@@ -2338,7 +2412,7 @@ zfs_getattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
                        XVA_SET_RTN(xvap, XAT_REPARSE);
                }
                if (XVA_ISSET_REQ(xvap, XAT_GEN)) {
-                       xoap->xoa_generation = zp->z_gen;
+                       xoap->xoa_generation = ip->i_generation;
                        XVA_SET_RTN(xvap, XAT_GEN);
                }
 
@@ -2355,7 +2429,7 @@ zfs_getattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
                }
        }
 
-       ZFS_TIME_DECODE(&vap->va_atime, zp->z_atime);
+       ZFS_TIME_DECODE(&vap->va_atime, atime);
        ZFS_TIME_DECODE(&vap->va_mtime, mtime);
        ZFS_TIME_DECODE(&vap->va_ctime, ctime);
 
@@ -2402,7 +2476,6 @@ zfs_getattr_fast(struct inode *ip, struct kstat *sp)
        mutex_enter(&zp->z_lock);
 
        generic_fillattr(ip, sp);
-       ZFS_TIME_DECODE(&sp->atime, zp->z_atime);
 
        sa_object_size(zp->z_sa_hdl, &blksize, &nblocks);
        sp->blksize = blksize;
@@ -2464,9 +2537,9 @@ zfs_setattr(struct inode *ip, vattr_t *vap, int flags, cred_t *cr)
        uint_t          saved_mask = 0;
        int             trim_mask = 0;
        uint64_t        new_mode;
-       uint64_t        new_uid, new_gid;
+       uint64_t        new_kuid = 0, new_kgid = 0, new_uid, new_gid;
        uint64_t        xattr_obj;
-       uint64_t        mtime[2], ctime[2];
+       uint64_t        mtime[2], ctime[2], atime[2];
        znode_t         *attrzp;
        int             need_policy = FALSE;
        int             err, err2;
@@ -2784,10 +2857,10 @@ top:
                                goto out2;
                }
                if (mask & ATTR_UID) {
-                       new_uid = zfs_fuid_create(zsb,
+                       new_kuid = zfs_fuid_create(zsb,
                            (uint64_t)vap->va_uid, cr, ZFS_OWNER, &fuidp);
-                       if (new_uid != zp->z_uid &&
-                           zfs_fuid_overquota(zsb, B_FALSE, new_uid)) {
+                       if (new_kuid != KUID_TO_SUID(ZTOI(zp)->i_uid) &&
+                           zfs_fuid_overquota(zsb, B_FALSE, new_kuid)) {
                                if (attrzp)
                                        iput(ZTOI(attrzp));
                                err = EDQUOT;
@@ -2796,10 +2869,10 @@ top:
                }
 
                if (mask & ATTR_GID) {
-                       new_gid = zfs_fuid_create(zsb, (uint64_t)vap->va_gid,
+                       new_kgid = zfs_fuid_create(zsb, (uint64_t)vap->va_gid,
                            cr, ZFS_GROUP, &fuidp);
-                       if (new_gid != zp->z_gid &&
-                           zfs_fuid_overquota(zsb, B_TRUE, new_gid)) {
+                       if (new_kgid != KGID_TO_SGID(ZTOI(zp)->i_gid) &&
+                           zfs_fuid_overquota(zsb, B_TRUE, new_kgid)) {
                                if (attrzp)
                                        iput(ZTOI(attrzp));
                                err = EDQUOT;
@@ -2890,26 +2963,28 @@ top:
        if (mask & (ATTR_UID|ATTR_GID)) {
 
                if (mask & ATTR_UID) {
+                       ZTOI(zp)->i_uid = SUID_TO_KUID(new_kuid);
+                       new_uid = zfs_uid_read(ZTOI(zp));
                        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zsb), NULL,
                            &new_uid, sizeof (new_uid));
-                       zp->z_uid = new_uid;
                        if (attrzp) {
                                SA_ADD_BULK_ATTR(xattr_bulk, xattr_count,
                                    SA_ZPL_UID(zsb), NULL, &new_uid,
                                    sizeof (new_uid));
-                               attrzp->z_uid = new_uid;
+                               ZTOI(attrzp)->i_uid = SUID_TO_KUID(new_uid);
                        }
                }
 
                if (mask & ATTR_GID) {
+                       ZTOI(zp)->i_gid = SGID_TO_KGID(new_kgid);
+                       new_gid = zfs_gid_read(ZTOI(zp));
                        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zsb),
                            NULL, &new_gid, sizeof (new_gid));
-                       zp->z_gid = new_gid;
                        if (attrzp) {
                                SA_ADD_BULK_ATTR(xattr_bulk, xattr_count,
                                    SA_ZPL_GID(zsb), NULL, &new_gid,
                                    sizeof (new_gid));
-                               attrzp->z_gid = new_gid;
+                               ZTOI(attrzp)->i_gid = SGID_TO_KGID(new_kgid);
                        }
                }
                if (!(mask & ATTR_MODE)) {
@@ -2928,7 +3003,7 @@ top:
        if (mask & ATTR_MODE) {
                SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zsb), NULL,
                    &new_mode, sizeof (new_mode));
-               zp->z_mode = new_mode;
+               zp->z_mode = ZTOI(zp)->i_mode = new_mode;
                ASSERT3P(aclp, !=, NULL);
                err = zfs_aclset_common(zp, aclp, cr, tx);
                ASSERT0(err);
@@ -2938,40 +3013,36 @@ top:
                aclp = NULL;
        }
 
-
-       if (mask & ATTR_ATIME) {
-               ZFS_TIME_ENCODE(&vap->va_atime, zp->z_atime);
+       if ((mask & ATTR_ATIME) || zp->z_atime_dirty) {
+               zp->z_atime_dirty = 0;
+               ZFS_TIME_ENCODE(&ip->i_atime, atime);
                SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL,
-                   &zp->z_atime, sizeof (zp->z_atime));
+                   &atime, sizeof (atime));
        }
 
        if (mask & ATTR_MTIME) {
                ZFS_TIME_ENCODE(&vap->va_mtime, mtime);
+               ZTOI(zp)->i_mtime = timespec_trunc(vap->va_mtime,
+                   ZTOI(zp)->i_sb->s_time_gran);
+
                SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb), NULL,
                    mtime, sizeof (mtime));
        }
 
-       /* XXX - shouldn't this be done *before* the ATIME/MTIME checks? */
-       if (mask & ATTR_SIZE && !(mask & ATTR_MTIME)) {
-               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb),
-                   NULL, mtime, sizeof (mtime));
-               SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL,
-                   &ctime, sizeof (ctime));
-               zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime,
-                   B_TRUE);
-       } else if (mask != 0) {
+       if (mask & ATTR_CTIME) {
+               ZFS_TIME_ENCODE(&vap->va_ctime, ctime);
+               ZTOI(zp)->i_ctime = timespec_trunc(vap->va_ctime,
+                   ZTOI(zp)->i_sb->s_time_gran);
                SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL,
-                   &ctime, sizeof (ctime));
-               zfs_tstamp_update_setup(zp, STATE_CHANGED, mtime, ctime,
-                   B_TRUE);
-               if (attrzp) {
-                       SA_ADD_BULK_ATTR(xattr_bulk, xattr_count,
-                           SA_ZPL_CTIME(zsb), NULL,
-                           &ctime, sizeof (ctime));
-                       zfs_tstamp_update_setup(attrzp, STATE_CHANGED,
-                           mtime, ctime, B_TRUE);
-               }
+                   ctime, sizeof (ctime));
+       }
+
+       if (attrzp && mask) {
+               SA_ADD_BULK_ATTR(xattr_bulk, xattr_count,
+                   SA_ZPL_CTIME(zsb), NULL, &ctime,
+                   sizeof (ctime));
        }
+
        /*
         * Do this after setting timestamps to prevent timestamp
         * update from toggling bit
@@ -3198,13 +3269,18 @@ zfs_rename(struct inode *sdip, char *snm, struct inode *tdip, char *tnm,
        ZFS_VERIFY_ZP(sdzp);
        zilog = zsb->z_log;
 
+       tdzp = ITOZ(tdip);
+       ZFS_VERIFY_ZP(tdzp);
+
+       /*
+        * We check i_sb because snapshots and the ctldir must have different
+        * super blocks.
+        */
        if (tdip->i_sb != sdip->i_sb || zfsctl_is_node(tdip)) {
                ZFS_EXIT(zsb);
                return (SET_ERROR(EXDEV));
        }
 
-       tdzp = ITOZ(tdip);
-       ZFS_VERIFY_ZP(tdzp);
        if (zsb->z_utf8 && u8_validate(tnm,
            strlen(tnm), NULL, U8_VALIDATE_ENTIRE, &error) < 0) {
                ZFS_EXIT(zsb);
@@ -3690,7 +3766,6 @@ zfs_readlink(struct inode *ip, uio_t *uio, cred_t *cr)
                error = zfs_sa_readlink(zp, uio);
        mutex_exit(&zp->z_lock);
 
-       ZFS_ACCESSTIME_STAMP(zsb, zp);
        ZFS_EXIT(zsb);
        return (error);
 }
@@ -3713,7 +3788,8 @@ EXPORT_SYMBOL(zfs_readlink);
  */
 /* ARGSUSED */
 int
-zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr)
+zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr,
+    int flags)
 {
        znode_t         *dzp = ITOZ(tdip);
        znode_t         *tzp, *szp;
@@ -3742,14 +3818,18 @@ zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr)
                return (SET_ERROR(EPERM));
        }
 
+       szp = ITOZ(sip);
+       ZFS_VERIFY_ZP(szp);
+
+       /*
+        * We check i_sb because snapshots and the ctldir must have different
+        * super blocks.
+        */
        if (sip->i_sb != tdip->i_sb || zfsctl_is_node(sip)) {
                ZFS_EXIT(zsb);
                return (SET_ERROR(EXDEV));
        }
 
-       szp = ITOZ(sip);
-       ZFS_VERIFY_ZP(szp);
-
        /* Prevent links to .zfs/shares files */
 
        if ((error = sa_lookup(szp->z_sa_hdl, SA_ZPL_PARENT(zsb),
@@ -3767,10 +3847,8 @@ zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr)
                ZFS_EXIT(zsb);
                return (SET_ERROR(EILSEQ));
        }
-#ifdef HAVE_PN_UTILS
        if (flags & FIGNORECASE)
                zf |= ZCILOOK;
-#endif /* HAVE_PN_UTILS */
 
        /*
         * We do not support links between attributes and non-attributes
@@ -3783,7 +3861,7 @@ zfs_link(struct inode *tdip, struct inode *sip, char *name, cred_t *cr)
                return (SET_ERROR(EINVAL));
        }
 
-       owner = zfs_fuid_map_id(zsb, szp->z_uid, cr, ZFS_OWNER);
+       owner = zfs_fuid_map_id(zsb, KUID_TO_SUID(sip->i_uid), cr, ZFS_OWNER);
        if (owner != crgetuid(cr) && secpolicy_basic_link(cr) != 0) {
                ZFS_EXIT(zsb);
                return (SET_ERROR(EPERM));
@@ -3827,10 +3905,8 @@ top:
 
        if (error == 0) {
                uint64_t txtype = TX_LINK;
-#ifdef HAVE_PN_UTILS
                if (flags & FIGNORECASE)
                        txtype |= TX_CI;
-#endif /* HAVE_PN_UTILS */
                zfs_log_link(zilog, tx, txtype, dzp, szp, name);
        }
 
@@ -4056,7 +4132,7 @@ zfs_dirty_inode(struct inode *ip, int flags)
        dmu_tx_t        *tx;
        uint64_t        mode, atime[2], mtime[2], ctime[2];
        sa_bulk_attr_t  bulk[4];
-       int             error;
+       int             error = 0;
        int             cnt = 0;
 
        if (zfs_is_readonly(zsb) || dmu_objset_is_snapshot(zsb->z_os))
@@ -4065,6 +4141,20 @@ zfs_dirty_inode(struct inode *ip, int flags)
        ZFS_ENTER(zsb);
        ZFS_VERIFY_ZP(zp);
 
+#ifdef I_DIRTY_TIME
+       /*
+        * This is the lazytime semantic indroduced in Linux 4.0
+        * This flag will only be called from update_time when lazytime is set.
+        * (Note, I_DIRTY_SYNC will also set if not lazytime)
+        * Fortunately mtime and ctime are managed within ZFS itself, so we
+        * only need to dirty atime.
+        */
+       if (flags == I_DIRTY_TIME) {
+               zp->z_atime_dirty = 1;
+               goto out;
+       }
+#endif
+
        tx = dmu_tx_create(zsb->z_os);
 
        dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
@@ -4077,6 +4167,8 @@ zfs_dirty_inode(struct inode *ip, int flags)
        }
 
        mutex_enter(&zp->z_lock);
+       zp->z_atime_dirty = 0;
+
        SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MODE(zsb), NULL, &mode, 8);
        SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_ATIME(zsb), NULL, &atime, 16);
        SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
@@ -4089,7 +4181,6 @@ zfs_dirty_inode(struct inode *ip, int flags)
        mode = ip->i_mode;
 
        zp->z_mode = mode;
-       zp->z_atime_dirty = 0;
 
        error = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx);
        mutex_exit(&zp->z_lock);
@@ -4107,6 +4198,7 @@ zfs_inactive(struct inode *ip)
 {
        znode_t *zp = ITOZ(ip);
        zfs_sb_t *zsb = ITOZSB(ip);
+       uint64_t atime[2];
        int error;
        int need_unlock = 0;
 
@@ -4130,9 +4222,10 @@ zfs_inactive(struct inode *ip)
                if (error) {
                        dmu_tx_abort(tx);
                } else {
+                       ZFS_TIME_ENCODE(&ip->i_atime, atime);
                        mutex_enter(&zp->z_lock);
                        (void) sa_update(zp->z_sa_hdl, SA_ZPL_ATIME(zsb),
-                           (void *)&zp->z_atime, sizeof (zp->z_atime), tx);
+                           (void *)&atime, sizeof (atime), tx);
                        zp->z_atime_dirty = 0;
                        mutex_exit(&zp->z_lock);
                        dmu_tx_commit(tx);
@@ -4241,9 +4334,6 @@ zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages)
 
        err = zfs_fillpage(ip, pl, nr_pages);
 
-       if (!err)
-               ZFS_ACCESSTIME_STAMP(zsb, zp);
-
        ZFS_EXIT(zsb);
        return (err);
 }
@@ -4378,6 +4468,15 @@ zfs_space(struct inode *ip, int cmd, flock64_t *bfp, int flag,
                return (SET_ERROR(EINVAL));
        }
 
+       /*
+        * Callers might not be able to detect properly that we are read-only,
+        * so check it explicitly here.
+        */
+       if (zfs_is_readonly(zsb)) {
+               ZFS_EXIT(zsb);
+               return (SET_ERROR(EROFS));
+       }
+
        if ((error = convoff(ip, bfp, 0, offset))) {
                ZFS_EXIT(zsb);
                return (error);
@@ -4669,6 +4768,8 @@ zfs_retzcbuf(struct inode *ip, xuio_t *xuio, cred_t *cr)
 #endif /* HAVE_UIO_ZEROCOPY */
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
+module_param(zfs_delete_blocks, ulong, 0644);
+MODULE_PARM_DESC(zfs_delete_blocks, "Delete files larger than N blocks async");
 module_param(zfs_read_chunk_size, long, 0644);
 MODULE_PARM_DESC(zfs_read_chunk_size, "Bytes to read per chunk");
 #endif
index eac9ce486d9be51e62f2087305aad71a0f0c87fb..11bb8675be66357420fd9095fe7e05c33bda148d 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  */
 
 /* Portions Copyright 2007 Jeremy Teo */
@@ -62,6 +62,7 @@
 
 #include <sys/dmu.h>
 #include <sys/dmu_objset.h>
+#include <sys/dmu_tx.h>
 #include <sys/refcount.h>
 #include <sys/stat.h>
 #include <sys/zap.h>
@@ -109,7 +110,7 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
 
        mutex_init(&zp->z_lock, NULL, MUTEX_DEFAULT, NULL);
        rw_init(&zp->z_parent_lock, NULL, RW_DEFAULT, NULL);
-       rw_init(&zp->z_name_lock, NULL, RW_DEFAULT, NULL);
+       rw_init(&zp->z_name_lock, NULL, RW_NOLOCKDEP, NULL);
        mutex_init(&zp->z_acl_lock, NULL, MUTEX_DEFAULT, NULL);
        rw_init(&zp->z_xattr_lock, NULL, RW_DEFAULT, NULL);
 
@@ -227,15 +228,10 @@ zfs_znode_fini(void)
 int
 zfs_znode_hold_compare(const void *a, const void *b)
 {
-       const znode_hold_t *zh_a = a;
-       const znode_hold_t *zh_b = b;
+       const znode_hold_t *zh_a = (const znode_hold_t *)a;
+       const znode_hold_t *zh_b = (const znode_hold_t *)b;
 
-       if (zh_a->zh_obj < zh_b->zh_obj)
-               return (-1);
-       else if (zh_a->zh_obj > zh_b->zh_obj)
-               return (1);
-       else
-               return (0);
+       return (AVL_CMP(zh_a->zh_obj, zh_b->zh_obj));
 }
 
 boolean_t
@@ -460,7 +456,7 @@ zfs_inode_set_ops(zfs_sb_t *zsb, struct inode *ip)
         */
        case S_IFCHR:
        case S_IFBLK:
-               sa_lookup(ITOZ(ip)->z_sa_hdl, SA_ZPL_RDEV(zsb), &rdev,
+               (void) sa_lookup(ITOZ(ip)->z_sa_hdl, SA_ZPL_RDEV(zsb), &rdev,
                    sizeof (rdev));
                /*FALLTHROUGH*/
        case S_IFIFO:
@@ -482,6 +478,38 @@ zfs_inode_set_ops(zfs_sb_t *zsb, struct inode *ip)
        }
 }
 
+/*
+ * Update the embedded inode given the znode.  We should work toward
+ * eliminating this function as soon as possible by removing values
+ * which are duplicated between the znode and inode.  If the generic
+ * inode has the correct field it should be used, and the ZFS code
+ * updated to access the inode.  This can be done incrementally.
+ */
+void
+zfs_inode_update(znode_t *zp)
+{
+       zfs_sb_t        *zsb;
+       struct inode    *ip;
+       uint32_t        blksize;
+       u_longlong_t    i_blocks;
+
+       ASSERT(zp != NULL);
+       zsb = ZTOZSB(zp);
+       ip = ZTOI(zp);
+
+       /* Skip .zfs control nodes which do not exist on disk. */
+       if (zfsctl_is_node(ip))
+               return;
+
+       dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize, &i_blocks);
+
+       spin_lock(&ip->i_lock);
+       ip->i_blocks = i_blocks;
+       i_size_write(ip, zp->z_size);
+       spin_unlock(&ip->i_lock);
+}
+
+
 /*
  * Construct a znode+inode and initialize.
  *
@@ -497,7 +525,11 @@ zfs_znode_alloc(zfs_sb_t *zsb, dmu_buf_t *db, int blksz,
        struct inode *ip;
        uint64_t mode;
        uint64_t parent;
-       sa_bulk_attr_t bulk[9];
+       uint64_t tmp_gen;
+       uint64_t links;
+       uint64_t z_uid, z_gid;
+       uint64_t atime[2], mtime[2], ctime[2];
+       sa_bulk_attr_t bulk[11];
        int count = 0;
 
        ASSERT(zsb != NULL);
@@ -529,26 +561,38 @@ zfs_znode_alloc(zfs_sb_t *zsb, dmu_buf_t *db, int blksz,
        zfs_znode_sa_init(zsb, zp, db, obj_type, hdl);
 
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zsb), NULL, &mode, 8);
-       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GEN(zsb), NULL, &zp->z_gen, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GEN(zsb), NULL, &tmp_gen, 8);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zsb), NULL, &zp->z_size, 8);
-       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb), NULL, &zp->z_links, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb), NULL, &links, 8);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb), NULL,
            &zp->z_pflags, 8);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_PARENT(zsb), NULL,
            &parent, 8);
-       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL,
-           &zp->z_atime, 16);
-       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zsb), NULL, &zp->z_uid, 8);
-       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zsb), NULL, &zp->z_gid, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zsb), NULL, &z_uid, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zsb), NULL, &z_gid, 8);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL, &atime, 16);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb), NULL, &mtime, 16);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL, &ctime, 16);
+
+       if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0 ||
+               tmp_gen == 0) {
 
-       if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count) != 0 || zp->z_gen == 0) {
                if (hdl == NULL)
                        sa_handle_destroy(zp->z_sa_hdl);
                zp->z_sa_hdl = NULL;
                goto error;
        }
 
-       zp->z_mode = mode;
+       zp->z_mode = ip->i_mode = mode;
+       ip->i_generation = (uint32_t)tmp_gen;
+       ip->i_blkbits = SPA_MINBLOCKSHIFT;
+       set_nlink(ip, (uint32_t)links);
+       zfs_uid_write(ip, z_uid);
+       zfs_gid_write(ip, z_gid);
+
+       ZFS_TIME_DECODE(&ip->i_atime, atime);
+       ZFS_TIME_DECODE(&ip->i_mtime, mtime);
+       ZFS_TIME_DECODE(&ip->i_ctime, ctime);
 
        ip->i_ino = obj;
        zfs_inode_update(zp);
@@ -578,71 +622,6 @@ error:
        return (NULL);
 }
 
-void
-zfs_set_inode_flags(znode_t *zp, struct inode *ip)
-{
-       /*
-        * Linux and Solaris have different sets of file attributes, so we
-        * restrict this conversion to the intersection of the two.
-        */
-
-       if (zp->z_pflags & ZFS_IMMUTABLE)
-               ip->i_flags |= S_IMMUTABLE;
-       else
-               ip->i_flags &= ~S_IMMUTABLE;
-
-       if (zp->z_pflags & ZFS_APPENDONLY)
-               ip->i_flags |= S_APPEND;
-       else
-               ip->i_flags &= ~S_APPEND;
-}
-
-/*
- * Update the embedded inode given the znode.  We should work toward
- * eliminating this function as soon as possible by removing values
- * which are duplicated between the znode and inode.  If the generic
- * inode has the correct field it should be used, and the ZFS code
- * updated to access the inode.  This can be done incrementally.
- */
-void
-zfs_inode_update(znode_t *zp)
-{
-       zfs_sb_t        *zsb;
-       struct inode    *ip;
-       uint32_t        blksize;
-       uint64_t        atime[2], mtime[2], ctime[2];
-
-       ASSERT(zp != NULL);
-       zsb = ZTOZSB(zp);
-       ip = ZTOI(zp);
-
-       /* Skip .zfs control nodes which do not exist on disk. */
-       if (zfsctl_is_node(ip))
-               return;
-
-       sa_lookup(zp->z_sa_hdl, SA_ZPL_ATIME(zsb), &atime, 16);
-       sa_lookup(zp->z_sa_hdl, SA_ZPL_MTIME(zsb), &mtime, 16);
-       sa_lookup(zp->z_sa_hdl, SA_ZPL_CTIME(zsb), &ctime, 16);
-
-       spin_lock(&ip->i_lock);
-       ip->i_generation = zp->z_gen;
-       ip->i_uid = SUID_TO_KUID(zp->z_uid);
-       ip->i_gid = SGID_TO_KGID(zp->z_gid);
-       set_nlink(ip, zp->z_links);
-       ip->i_mode = zp->z_mode;
-       zfs_set_inode_flags(zp, ip);
-       ip->i_blkbits = SPA_MINBLOCKSHIFT;
-       dmu_object_size_from_db(sa_get_db(zp->z_sa_hdl), &blksize,
-           (u_longlong_t *)&ip->i_blocks);
-
-       ZFS_TIME_DECODE(&ip->i_atime, atime);
-       ZFS_TIME_DECODE(&ip->i_mtime, mtime);
-       ZFS_TIME_DECODE(&ip->i_ctime, ctime);
-
-       i_size_write(ip, zp->z_size);
-       spin_unlock(&ip->i_lock);
-}
-
 /*
  * Safely mark an inode dirty.  Inodes which are part of a read-only
  * file system or snapshot may not be dirtied.
@@ -691,6 +670,7 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
        timestruc_t     now;
        uint64_t        gen, obj;
        int             bonuslen;
+       int             dnodesize;
        sa_handle_t     *sa_hdl;
        dmu_object_type_t obj_type;
        sa_bulk_attr_t  *sa_attrs;
@@ -702,15 +682,21 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
                obj = vap->va_nodeid;
                now = vap->va_ctime;            /* see zfs_replay_create() */
                gen = vap->va_nblocks;          /* ditto */
+               dnodesize = vap->va_fsid;       /* ditto */
        } else {
                obj = 0;
                gethrestime(&now);
                gen = dmu_tx_get_txg(tx);
+               dnodesize = dmu_objset_dnodesize(zsb->z_os);
        }
 
+       if (dnodesize == 0)
+               dnodesize = DNODE_MIN_SIZE;
+
        obj_type = zsb->z_use_sa ? DMU_OT_SA : DMU_OT_ZNODE;
+
        bonuslen = (obj_type == DMU_OT_SA) ?
-           DN_MAX_BONUSLEN : ZFS_OLD_ZNODE_PHYS_SIZE;
+           DN_BONUS_SIZE(dnodesize) : ZFS_OLD_ZNODE_PHYS_SIZE;
 
        /*
         * Create a new DMU object.
@@ -723,23 +709,23 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
         */
        if (S_ISDIR(vap->va_mode)) {
                if (zsb->z_replay) {
-                       VERIFY0(zap_create_claim_norm(zsb->z_os, obj,
+                       VERIFY0(zap_create_claim_norm_dnsize(zsb->z_os, obj,
                            zsb->z_norm, DMU_OT_DIRECTORY_CONTENTS,
-                           obj_type, bonuslen, tx));
+                           obj_type, bonuslen, dnodesize, tx));
                } else {
-                       obj = zap_create_norm(zsb->z_os,
+                       obj = zap_create_norm_dnsize(zsb->z_os,
                            zsb->z_norm, DMU_OT_DIRECTORY_CONTENTS,
-                           obj_type, bonuslen, tx);
+                           obj_type, bonuslen, dnodesize, tx);
                }
        } else {
                if (zsb->z_replay) {
-                       VERIFY0(dmu_object_claim(zsb->z_os, obj,
+                       VERIFY0(dmu_object_claim_dnsize(zsb->z_os, obj,
                            DMU_OT_PLAIN_FILE_CONTENTS, 0,
-                           obj_type, bonuslen, tx));
+                           obj_type, bonuslen, dnodesize, tx));
                } else {
-                       obj = dmu_object_alloc(zsb->z_os,
+                       obj = dmu_object_alloc_dnsize(zsb->z_os,
                            DMU_OT_PLAIN_FILE_CONTENTS, 0,
-                           obj_type, bonuslen, tx);
+                           obj_type, bonuslen, dnodesize, tx);
                }
        }
 
@@ -770,9 +756,10 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
 
        if (S_ISDIR(vap->va_mode)) {
                size = 2;               /* contents ("." and "..") */
-               links = (flag & (IS_ROOT_NODE | IS_XATTR)) ? 2 : 1;
+               links = 2;
        } else {
-               size = links = 0;
+               size = 0;
+               links = 1;
        }
 
        if (S_ISBLK(vap->va_mode) || S_ISCHR(vap->va_mode))
@@ -909,7 +896,8 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
        }
 
        (*zpp)->z_pflags = pflags;
-       (*zpp)->z_mode = mode;
+       (*zpp)->z_mode = ZTOI(*zpp)->i_mode = mode;
+       (*zpp)->z_dnodesize = dnodesize;
 
        if (obj_type == DMU_OT_ZNODE ||
            acl_ids->z_aclp->z_version < ZFS_ACL_VERSION_FUID) {
@@ -938,6 +926,7 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)
                    &times, sizeof (times), tx);
                XVA_SET_RTN(xvap, XAT_CREATETIME);
        }
+
        if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
                ZFS_ATTR_SET(zp, ZFS_READONLY, xoap->xoa_readonly,
                    zp->z_pflags, tx);
@@ -962,7 +951,12 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)
                ZFS_ATTR_SET(zp, ZFS_IMMUTABLE, xoap->xoa_immutable,
                    zp->z_pflags, tx);
                XVA_SET_RTN(xvap, XAT_IMMUTABLE);
+
+               ZTOI(zp)->i_flags |= S_IMMUTABLE;
+       } else {
+               ZTOI(zp)->i_flags &= ~S_IMMUTABLE;
        }
+
        if (XVA_ISSET_REQ(xvap, XAT_NOUNLINK)) {
                ZFS_ATTR_SET(zp, ZFS_NOUNLINK, xoap->xoa_nounlink,
                    zp->z_pflags, tx);
@@ -972,7 +966,13 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx)
                ZFS_ATTR_SET(zp, ZFS_APPENDONLY, xoap->xoa_appendonly,
                    zp->z_pflags, tx);
                XVA_SET_RTN(xvap, XAT_APPENDONLY);
+
+               ZTOI(zp)->i_flags |= S_APPEND;
+       } else {
+
+               ZTOI(zp)->i_flags &= ~S_APPEND;
        }
+
        if (XVA_ISSET_REQ(xvap, XAT_NODUMP)) {
                ZFS_ATTR_SET(zp, ZFS_NODUMP, xoap->xoa_nodump,
                    zp->z_pflags, tx);
@@ -1123,10 +1123,13 @@ zfs_rezget(znode_t *zp)
        dmu_buf_t *db;
        uint64_t obj_num = zp->z_id;
        uint64_t mode;
-       sa_bulk_attr_t bulk[8];
+       uint64_t links;
+       sa_bulk_attr_t bulk[10];
        int err;
        int count = 0;
        uint64_t gen;
+       uint64_t z_uid, z_gid;
+       uint64_t atime[2], mtime[2], ctime[2];
        znode_hold_t *zh;
 
        /*
@@ -1180,17 +1183,21 @@ zfs_rezget(znode_t *zp)
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zsb), NULL,
            &zp->z_size, sizeof (zp->z_size));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_LINKS(zsb), NULL,
-           &zp->z_links, sizeof (zp->z_links));
+           &links, sizeof (links));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb), NULL,
            &zp->z_pflags, sizeof (zp->z_pflags));
-       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL,
-           &zp->z_atime, sizeof (zp->z_atime));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_UID(zsb), NULL,
-           &zp->z_uid, sizeof (zp->z_uid));
+           &z_uid, sizeof (z_uid));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_GID(zsb), NULL,
-           &zp->z_gid, sizeof (zp->z_gid));
+           &z_gid, sizeof (z_gid));
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MODE(zsb), NULL,
            &mode, sizeof (mode));
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_ATIME(zsb), NULL,
+           &atime, 16);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zsb), NULL,
+           &mtime, 16);
+       SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL,
+           &ctime, 16);
 
        if (sa_bulk_lookup(zp->z_sa_hdl, bulk, count)) {
                zfs_znode_dmu_fini(zp);
@@ -1198,18 +1205,28 @@ zfs_rezget(znode_t *zp)
                return (SET_ERROR(EIO));
        }
 
-       zp->z_mode = mode;
+       zp->z_mode = ZTOI(zp)->i_mode = mode;
+       zfs_uid_write(ZTOI(zp), z_uid);
+       zfs_gid_write(ZTOI(zp), z_gid);
 
-       if (gen != zp->z_gen) {
+       ZFS_TIME_DECODE(&ZTOI(zp)->i_atime, atime);
+       ZFS_TIME_DECODE(&ZTOI(zp)->i_mtime, mtime);
+       ZFS_TIME_DECODE(&ZTOI(zp)->i_ctime, ctime);
+
+       if (gen != ZTOI(zp)->i_generation) {
                zfs_znode_dmu_fini(zp);
                zfs_znode_hold_exit(zsb, zh);
                return (SET_ERROR(EIO));
        }
 
-       zp->z_unlinked = (zp->z_links == 0);
+       zp->z_unlinked = (ZTOI(zp)->i_nlink == 0);
+       set_nlink(ZTOI(zp), (uint32_t)links);
+
        zp->z_blksz = doi.doi_data_block_size;
+       zp->z_atime_dirty = 0;
        zfs_inode_update(zp);
 
+
        zfs_znode_hold_exit(zsb, zh);
 
        return (0);
@@ -1279,81 +1296,32 @@ zfs_compare_timespec(struct timespec *t1, struct timespec *t2)
        return (t1->tv_nsec - t2->tv_nsec);
 }
 
-/*
- *  Determine whether the znode's atime must be updated.  The logic mostly
- *  duplicates the Linux kernel's relatime_need_update() functionality.
- *  This function is only called if the underlying filesystem actually has
- *  atime updates enabled.
- */
-static inline boolean_t
-zfs_atime_need_update(znode_t *zp, timestruc_t *now)
-{
-       if (!ZTOZSB(zp)->z_relatime)
-               return (B_TRUE);
-
-       /*
-        * In relatime mode, only update the atime if the previous atime
-        * is earlier than either the ctime or mtime or if at least a day
-        * has passed since the last update of atime.
-        */
-       if (zfs_compare_timespec(&ZTOI(zp)->i_mtime, &ZTOI(zp)->i_atime) >= 0)
-               return (B_TRUE);
-
-       if (zfs_compare_timespec(&ZTOI(zp)->i_ctime, &ZTOI(zp)->i_atime) >= 0)
-               return (B_TRUE);
-
-       if ((long)now->tv_sec - ZTOI(zp)->i_atime.tv_sec >= 24*60*60)
-               return (B_TRUE);
-
-       return (B_FALSE);
-}
-
 /*
  * Prepare to update znode time stamps.
  *
  *     IN:     zp      - znode requiring timestamp update
- *             flag    - ATTR_MTIME, ATTR_CTIME, ATTR_ATIME flags
- *             have_tx - true of caller is creating a new txg
+ *             flag    - ATTR_MTIME, ATTR_CTIME flags
  *
- *     OUT:    zp      - new atime (via underlying inode's i_atime)
+ *     OUT:    zp      - z_seq
  *             mtime   - new mtime
  *             ctime   - new ctime
  *
- * NOTE: The arguments are somewhat redundant.  The following condition
- * is always true:
- *
- *             have_tx == !(flag & ATTR_ATIME)
+ *     Note: We don't update atime here, because we rely on Linux VFS to do
+ *     atime updating.
  */
 void
 zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2],
-    uint64_t ctime[2], boolean_t have_tx)
+    uint64_t ctime[2])
 {
        timestruc_t     now;
 
-       ASSERT(have_tx == !(flag & ATTR_ATIME));
        gethrestime(&now);
 
-       /*
-        * NOTE: The following test intentionally does not update z_atime_dirty
-        * in the case where an ATIME update has been requested but for which
-        * the update is omitted due to relatime logic.  The rationale being
-        * that if the flag was set somewhere else, we should leave it alone
-        * here.
-        */
-       if (flag & ATTR_ATIME) {
-               if (zfs_atime_need_update(zp, &now)) {
-                       ZFS_TIME_ENCODE(&now, zp->z_atime);
-                       ZTOI(zp)->i_atime.tv_sec = zp->z_atime[0];
-                       ZTOI(zp)->i_atime.tv_nsec = zp->z_atime[1];
-                       zp->z_atime_dirty = 1;
-               }
-       } else {
-               zp->z_atime_dirty = 0;
-               zp->z_seq++;
-       }
+       zp->z_seq++;
 
        if (flag & ATTR_MTIME) {
                ZFS_TIME_ENCODE(&now, mtime);
+               ZFS_TIME_DECODE(&(ZTOI(zp)->i_mtime), mtime);
                if (ZTOZSB(zp)->z_use_fuids) {
                        zp->z_pflags |= (ZFS_ARCHIVE |
                            ZFS_AV_MODIFIED);
@@ -1362,6 +1330,7 @@ zfs_tstamp_update_setup(znode_t *zp, uint_t flag, uint64_t mtime[2],
 
        if (flag & ATTR_CTIME) {
                ZFS_TIME_ENCODE(&now, ctime);
+               ZFS_TIME_DECODE(&(ZTOI(zp)->i_ctime), ctime);
                if (ZTOZSB(zp)->z_use_fuids)
                        zp->z_pflags |= ZFS_ARCHIVE;
        }
@@ -1409,7 +1378,7 @@ zfs_grow_blocksize(znode_t *zp, uint64_t size, dmu_tx_t *tx)
  *     IN:     zp      - znode of file to free data in.
  *             end     - new end-of-file
  *
- *     RETURN: 0 on success, error code on failure
+ *     RETURN: 0 on success, error code on failure
  */
 static int
 zfs_extend(znode_t *zp, uint64_t end)
@@ -1528,7 +1497,7 @@ zfs_zero_partial_page(znode_t *zp, uint64_t start, uint64_t len)
  *             off     - start of section to free.
  *             len     - length of section to free.
  *
- *     RETURN: 0 on success, error code on failure
+ *     RETURN: 0 on success, error code on failure
  */
 static int
 zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
@@ -1607,7 +1576,7 @@ zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
  *     IN:     zp      - znode of file to free data in.
  *             end     - new end-of-file.
  *
- *     RETURN: 0 on success, error code on failure
+ *     RETURN: 0 on success, error code on failure
  */
 static int
 zfs_trunc(znode_t *zp, uint64_t end)
@@ -1640,6 +1609,7 @@ zfs_trunc(znode_t *zp, uint64_t end)
        tx = dmu_tx_create(zsb->z_os);
        dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
        zfs_sa_upgrade_txholds(tx, zp);
+       dmu_tx_mark_netfree(tx);
        error = dmu_tx_assign(tx, TXG_WAIT);
        if (error) {
                dmu_tx_abort(tx);
@@ -1674,7 +1644,7 @@ zfs_trunc(znode_t *zp, uint64_t end)
  *             flag    - current file open mode flags.
  *             log     - TRUE if this action should be logged
  *
- *     RETURN: 0 on success, error code on failure
+ *     RETURN: 0 on success, error code on failure
  */
 int
 zfs_freesp(znode_t *zp, uint64_t off, uint64_t len, int flag, boolean_t log)
@@ -1722,7 +1692,7 @@ log:
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zsb), NULL, ctime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zsb),
            NULL, &zp->z_pflags, 8);
-       zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime, B_TRUE);
+       zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime);
        error = sa_bulk_update(zp->z_sa_hdl, bulk, count, tx);
        ASSERT(error == 0);
 
@@ -1773,6 +1743,14 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
            DMU_OT_NONE, 0, tx);
        ASSERT(error == 0);
 
+       /*
+        * Give dmu_object_alloc() a hint about where to start
+        * allocating new objects. Otherwise, since the metadnode's
+        * dnode_phys_t structure isn't initialized yet, dmu_object_next()
+        * would fail and we'd have to skip to the next dnode block.
+        */
+       os->os_obj_next = moid + 1;
+
        /*
         * Set starting attributes.
         */
@@ -1959,13 +1937,16 @@ zfs_release_sa_handle(sa_handle_t *hdl, dmu_buf_t *db, void *tag)
  * or not the object is an extended attribute directory.
  */
 static int
-zfs_obj_to_pobj(sa_handle_t *hdl, sa_attr_type_t *sa_table, uint64_t *pobjp,
-    int *is_xattrdir)
+zfs_obj_to_pobj(objset_t *osp, sa_handle_t *hdl, sa_attr_type_t *sa_table,
+    uint64_t *pobjp, int *is_xattrdir)
 {
        uint64_t parent;
        uint64_t pflags;
        uint64_t mode;
+       uint64_t parent_mode;
        sa_bulk_attr_t bulk[3];
+       sa_handle_t *sa_hdl;
+       dmu_buf_t *sa_db;
        int count = 0;
        int error;
 
@@ -1979,9 +1960,32 @@ zfs_obj_to_pobj(sa_handle_t *hdl, sa_attr_type_t *sa_table, uint64_t *pobjp,
        if ((error = sa_bulk_lookup(hdl, bulk, count)) != 0)
                return (error);
 
-       *pobjp = parent;
+       /*
+        * When a link is removed its parent pointer is not changed and will
+        * be invalid.  There are two cases where a link is removed but the
+        * file stays around, when it goes to the delete queue and when there
+        * are additional links.
+        */
+       error = zfs_grab_sa_handle(osp, parent, &sa_hdl, &sa_db, FTAG);
+       if (error != 0)
+               return (error);
+
+       error = sa_lookup(sa_hdl, ZPL_MODE, &parent_mode, sizeof (parent_mode));
+       zfs_release_sa_handle(sa_hdl, sa_db, FTAG);
+       if (error != 0)
+               return (error);
+
        *is_xattrdir = ((pflags & ZFS_XATTR) != 0) && S_ISDIR(mode);
 
+       /*
+        * Extended attributes can be applied to files, directories, etc.
+        * Otherwise the parent must be a directory.
+        */
+       if (!*is_xattrdir && !S_ISDIR(parent_mode))
+               return (EINVAL);
+
+       *pobjp = parent;
+
        return (0);
 }
 
@@ -2030,7 +2034,7 @@ zfs_obj_to_path_impl(objset_t *osp, uint64_t obj, sa_handle_t *hdl,
                if (prevdb)
                        zfs_release_sa_handle(prevhdl, prevdb, FTAG);
 
-               if ((error = zfs_obj_to_pobj(sa_hdl, sa_table, &pobj,
+               if ((error = zfs_obj_to_pobj(osp, sa_hdl, sa_table, &pobj,
                    &is_xattrdir)) != 0)
                        break;
 
index 289b23c7f488a44755be6c59f4929ac0b618ff36..760f0a891beb35f9cb931e462aa791da0317ecad 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -123,17 +123,11 @@ zil_bp_compare(const void *x1, const void *x2)
        const dva_t *dva1 = &((zil_bp_node_t *)x1)->zn_dva;
        const dva_t *dva2 = &((zil_bp_node_t *)x2)->zn_dva;
 
-       if (DVA_GET_VDEV(dva1) < DVA_GET_VDEV(dva2))
-               return (-1);
-       if (DVA_GET_VDEV(dva1) > DVA_GET_VDEV(dva2))
-               return (1);
+       int cmp = AVL_CMP(DVA_GET_VDEV(dva1), DVA_GET_VDEV(dva2));
+       if (likely(cmp))
+               return (cmp);
 
-       if (DVA_GET_OFFSET(dva1) < DVA_GET_OFFSET(dva2))
-               return (-1);
-       if (DVA_GET_OFFSET(dva1) > DVA_GET_OFFSET(dva2))
-               return (1);
-
-       return (0);
+       return (AVL_CMP(DVA_GET_OFFSET(dva1), DVA_GET_OFFSET(dva2)));
 }
 
 static void
@@ -266,7 +260,7 @@ zil_read_log_block(zilog_t *zilog, const blkptr_t *bp, blkptr_t *nbp, void *dst,
                        }
                }
 
-               VERIFY(arc_buf_remove_ref(abuf, &abuf));
+               arc_buf_destroy(abuf, &abuf);
        }
 
        return (error);
@@ -303,7 +297,7 @@ zil_read_log_data(zilog_t *zilog, const lr_write_t *lr, void *wbuf)
        if (error == 0) {
                if (wbuf != NULL)
                        bcopy(abuf->b_data, wbuf, arc_buf_size(abuf));
-               (void) arc_buf_remove_ref(abuf, &abuf);
+               arc_buf_destroy(abuf, &abuf);
        }
 
        return (error);
@@ -786,12 +780,7 @@ zil_vdev_compare(const void *x1, const void *x2)
        const uint64_t v1 = ((zil_vdev_node_t *)x1)->zv_vdev;
        const uint64_t v2 = ((zil_vdev_node_t *)x2)->zv_vdev;
 
-       if (v1 < v2)
-               return (-1);
-       if (v1 > v2)
-               return (1);
-
-       return (0);
+       return (AVL_CMP(v1, v2));
 }
 
 void
@@ -1257,12 +1246,7 @@ zil_aitx_compare(const void *x1, const void *x2)
        const uint64_t o1 = ((itx_async_node_t *)x1)->ia_foid;
        const uint64_t o2 = ((itx_async_node_t *)x2)->ia_foid;
 
-       if (o1 < o2)
-               return (-1);
-       if (o1 > o2)
-               return (1);
-
-       return (0);
+       return (AVL_CMP(o1, o2));
 }
 
 /*
@@ -1372,7 +1356,8 @@ zil_itx_assign(zilog_t *zilog, itx_t *itx, dmu_tx_t *tx)
                itxg->itxg_sod += itx->itx_sod;
        } else {
                avl_tree_t *t = &itxs->i_async_tree;
-               uint64_t foid = ((lr_ooo_t *)&itx->itx_lr)->lr_foid;
+               uint64_t foid =
+                   LR_FOID_GET_OBJ(((lr_ooo_t *)&itx->itx_lr)->lr_foid);
                itx_async_node_t *ian;
                avl_index_t where;
 
@@ -1918,7 +1903,8 @@ zil_close(zilog_t *zilog)
        mutex_exit(&zilog->zl_lock);
        if (txg)
                txg_wait_synced(zilog->zl_dmu_pool, txg);
-       ASSERT(!zilog_is_dirty(zilog));
+       if (txg < spa_freeze_txg(zilog->zl_spa))
+               ASSERT(!zilog_is_dirty(zilog));
 
        taskq_destroy(zilog->zl_clean_taskq);
        zilog->zl_clean_taskq = NULL;
@@ -2078,7 +2064,7 @@ typedef struct zil_replay_arg {
 static int
 zil_replay_error(zilog_t *zilog, lr_t *lr, int error)
 {
-       char name[MAXNAMELEN];
+       char name[ZFS_MAX_DATASET_NAME_LEN];
 
        zilog->zl_replaying_seq--;      /* didn't actually replay this one */
 
@@ -2122,7 +2108,7 @@ zil_replay_log_record(zilog_t *zilog, lr_t *lr, void *zra, uint64_t claim_txg)
         */
        if (TX_OOO(txtype)) {
                error = dmu_object_info(zilog->zl_os,
-                   ((lr_ooo_t *)lr)->lr_foid, NULL);
+                   LR_FOID_GET_OBJ(((lr_ooo_t *)lr)->lr_foid), NULL);
                if (error == ENOENT || error == EEXIST)
                        return (0);
        }
index 794439bbe7db2f4af9b859c590a2b372accb8a28..c149b4ff234970938aaaf5eb8ea575021adb6470 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
  */
 
@@ -39,6 +39,9 @@
 #include <sys/ddt.h>
 #include <sys/blkptr.h>
 #include <sys/zfeature.h>
+#include <sys/metaslab_impl.h>
+#include <sys/time.h>
+#include <sys/trace_zio.h>
 
 /*
  * ==========================================================================
  * ==========================================================================
  */
 const char *zio_type_name[ZIO_TYPES] = {
+       /*
+        * Note: Linux kernel thread name length is limited
+        * so these names will differ from upstream open zfs.
+        */
        "z_null", "z_rd", "z_wr", "z_fr", "z_cl", "z_ioctl"
 };
 
+int zio_dva_throttle_enabled = B_FALSE;
+
 /*
  * ==========================================================================
  * I/O kmem caches
@@ -63,6 +72,9 @@ int zio_delay_max = ZIO_DELAY_MAX;
 #define        ZIO_PIPELINE_CONTINUE           0x100
 #define        ZIO_PIPELINE_STOP               0x101
 
+#define        BP_SPANB(indblkshift, level) \
+       (((uint64_t)1) << ((level) * ((indblkshift) - SPA_BLKPTRSHIFT)))
+#define        COMPARE_META_LEVEL      0x80000000ul
 /*
  * The following actions directly effect the spa's sync-to-convergence logic.
  * The values below define the sync pass when we start performing the action.
@@ -95,6 +107,8 @@ int zio_buf_debug_limit = 0;
 
 static inline void __zio_execute(zio_t *zio);
 
+static void zio_taskq_dispatch(zio_t *, zio_taskq_type_t, boolean_t);
+
 void
 zio_init(void)
 {
@@ -138,12 +152,21 @@ zio_init(void)
                 */
                if (arc_watch && !IS_P2ALIGNED(size, PAGESIZE))
                        continue;
-#endif
+               /*
+                * Here's the problem - on 4K native devices in userland on
+                * Linux using O_DIRECT, buffers must be 4K aligned or I/O
+                * will fail with EINVAL, causing zdb (and others) to coredump.
+                * Since userland probably doesn't need optimized buffer caches,
+                * we just force 4K alignment on everything.
+                */
+               align = 8 * SPA_MINBLOCKSIZE;
+#else
                if (size <= 4 * SPA_MINBLOCKSIZE) {
                        align = SPA_MINBLOCKSIZE;
                } else if (IS_P2ALIGNED(size, p2 >> 2)) {
                        align = MIN(p2 >> 2, PAGESIZE);
                }
+#endif
 
                if (align != 0) {
                        char name[36];
@@ -287,7 +310,7 @@ zio_data_buf_free(void *buf, size_t size)
  * Push and pop I/O transform buffers
  * ==========================================================================
  */
-static void
+void
 zio_push_transform(zio_t *zio, void *data, uint64_t size, uint64_t bufsize,
        zio_transform_func_t *transform)
 {
@@ -305,7 +328,7 @@ zio_push_transform(zio_t *zio, void *data, uint64_t size, uint64_t bufsize,
        zio->io_size = size;
 }
 
-static void
+void
 zio_pop_transforms(zio_t *zio)
 {
        zio_transform_t *zt;
@@ -354,52 +377,39 @@ zio_decompress(zio_t *zio, void *data, uint64_t size)
  * I/O parent/child relationships and pipeline interlocks
  * ==========================================================================
  */
-/*
- * NOTE - Callers to zio_walk_parents() and zio_walk_children must
- *        continue calling these functions until they return NULL.
- *        Otherwise, the next caller will pick up the list walk in
- *        some indeterminate state.  (Otherwise every caller would
- *        have to pass in a cookie to keep the state represented by
- *        io_walk_link, which gets annoying.)
- */
 zio_t *
-zio_walk_parents(zio_t *cio)
+zio_walk_parents(zio_t *cio, zio_link_t **zl)
 {
-       zio_link_t *zl = cio->io_walk_link;
        list_t *pl = &cio->io_parent_list;
 
-       zl = (zl == NULL) ? list_head(pl) : list_next(pl, zl);
-       cio->io_walk_link = zl;
-
-       if (zl == NULL)
+       *zl = (*zl == NULL) ? list_head(pl) : list_next(pl, *zl);
+       if (*zl == NULL)
                return (NULL);
 
-       ASSERT(zl->zl_child == cio);
-       return (zl->zl_parent);
+       ASSERT((*zl)->zl_child == cio);
+       return ((*zl)->zl_parent);
 }
 
 zio_t *
-zio_walk_children(zio_t *pio)
+zio_walk_children(zio_t *pio, zio_link_t **zl)
 {
-       zio_link_t *zl = pio->io_walk_link;
        list_t *cl = &pio->io_child_list;
 
-       zl = (zl == NULL) ? list_head(cl) : list_next(cl, zl);
-       pio->io_walk_link = zl;
-
-       if (zl == NULL)
+       *zl = (*zl == NULL) ? list_head(cl) : list_next(cl, *zl);
+       if (*zl == NULL)
                return (NULL);
 
-       ASSERT(zl->zl_parent == pio);
-       return (zl->zl_child);
+       ASSERT((*zl)->zl_parent == pio);
+       return ((*zl)->zl_child);
 }
 
 zio_t *
 zio_unique_parent(zio_t *cio)
 {
-       zio_t *pio = zio_walk_parents(cio);
+       zio_link_t *zl = NULL;
+       zio_t *pio = zio_walk_parents(cio, &zl);
 
-       VERIFY(zio_walk_parents(cio) == NULL);
+       VERIFY3P(zio_walk_parents(cio, &zl), ==, NULL);
        return (pio);
 }
 
@@ -455,7 +465,6 @@ zio_remove_child(zio_t *pio, zio_t *cio, zio_link_t *zl)
 
        mutex_exit(&pio->io_lock);
        mutex_exit(&cio->io_lock);
-
        kmem_cache_free(zio_link_cache, zl);
 }
 
@@ -469,6 +478,7 @@ zio_wait_for_children(zio_t *zio, enum zio_child child, enum zio_wait_type wait)
        ASSERT(zio->io_stall == NULL);
        if (*countp != 0) {
                zio->io_stage >>= 1;
+               ASSERT3U(zio->io_stage, !=, ZIO_STAGE_OPEN);
                zio->io_stall = countp;
                waiting = B_TRUE;
        }
@@ -493,9 +503,18 @@ zio_notify_parent(zio_t *pio, zio_t *zio, enum zio_wait_type wait)
        (*countp)--;
 
        if (*countp == 0 && pio->io_stall == countp) {
+               zio_taskq_type_t type =
+                   pio->io_stage < ZIO_STAGE_VDEV_IO_START ? ZIO_TASKQ_ISSUE :
+                   ZIO_TASKQ_INTERRUPT;
                pio->io_stall = NULL;
                mutex_exit(&pio->io_lock);
-               __zio_execute(pio);
+               /*
+                * Dispatch the parent zio in its own taskq so that
+                * the child can continue to make progress. This also
+                * prevents overflowing the stack when we have deeply nested
+                * parent-child relationships.
+                */
+               zio_taskq_dispatch(pio, type, B_FALSE);
        } else {
                mutex_exit(&pio->io_lock);
        }
@@ -508,6 +527,24 @@ zio_inherit_child_errors(zio_t *zio, enum zio_child c)
                zio->io_error = zio->io_child_error[c];
 }
 
+int
+zio_timestamp_compare(const void *x1, const void *x2)
+{
+       const zio_t *z1 = x1;
+       const zio_t *z2 = x2;
+       int cmp;
+
+       cmp = AVL_CMP(z1->io_queued_timestamp, z2->io_queued_timestamp);
+       if (likely(cmp))
+               return (cmp);
+
+       cmp = AVL_CMP(z1->io_offset, z2->io_offset);
+       if (likely(cmp))
+               return (cmp);
+
+       return (AVL_PCMP(z1, z2));
+}
+
 /*
  * ==========================================================================
  * Create the various types of I/O (read, write, free, etc)
@@ -515,25 +552,28 @@ zio_inherit_child_errors(zio_t *zio, enum zio_child c)
  */
 static zio_t *
 zio_create(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp,
-    void *data, uint64_t size, zio_done_func_t *done, void *private,
-    zio_type_t type, zio_priority_t priority, enum zio_flag flags,
-    vdev_t *vd, uint64_t offset, const zbookmark_phys_t *zb,
-    enum zio_stage stage, enum zio_stage pipeline)
+    void *data, uint64_t lsize, uint64_t psize, zio_done_func_t *done,
+    void *private, zio_type_t type, zio_priority_t priority,
+    enum zio_flag flags, vdev_t *vd, uint64_t offset,
+    const zbookmark_phys_t *zb, enum zio_stage stage,
+    enum zio_stage pipeline)
 {
        zio_t *zio;
 
-       ASSERT3U(size, <=, SPA_MAXBLOCKSIZE);
-       ASSERT(P2PHASE(size, SPA_MINBLOCKSIZE) == 0);
+       ASSERT3U(psize, <=, SPA_MAXBLOCKSIZE);
+       ASSERT(P2PHASE(psize, SPA_MINBLOCKSIZE) == 0);
        ASSERT(P2PHASE(offset, SPA_MINBLOCKSIZE) == 0);
 
        ASSERT(!vd || spa_config_held(spa, SCL_STATE_ALL, RW_READER));
        ASSERT(!bp || !(flags & ZIO_FLAG_CONFIG_WRITER));
        ASSERT(vd || stage == ZIO_STAGE_OPEN);
 
+       IMPLY(lsize != psize, (flags & ZIO_FLAG_RAW) != 0);
+
        zio = kmem_cache_alloc(zio_cache, KM_SLEEP);
        bzero(zio, sizeof (zio_t));
 
-       mutex_init(&zio->io_lock, NULL, MUTEX_DEFAULT, NULL);
+       mutex_init(&zio->io_lock, NULL, MUTEX_NOLOCKDEP, NULL);
        cv_init(&zio->io_cv, NULL, CV_DEFAULT, NULL);
 
        list_create(&zio->io_parent_list, sizeof (zio_link_t),
@@ -572,10 +612,12 @@ zio_create(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp,
        zio->io_vd = vd;
        zio->io_offset = offset;
        zio->io_orig_data = zio->io_data = data;
-       zio->io_orig_size = zio->io_size = size;
+       zio->io_orig_size = zio->io_size = psize;
+       zio->io_lsize = lsize;
        zio->io_orig_flags = zio->io_flags = flags;
        zio->io_orig_stage = zio->io_stage = stage;
        zio->io_orig_pipeline = zio->io_pipeline = pipeline;
+       zio->io_pipeline_trace = ZIO_STAGE_OPEN;
 
        zio->io_state[ZIO_WAIT_READY] = (stage >= ZIO_STAGE_READY);
        zio->io_state[ZIO_WAIT_DONE] = (stage >= ZIO_STAGE_DONE);
@@ -612,7 +654,7 @@ zio_null(zio_t *pio, spa_t *spa, vdev_t *vd, zio_done_func_t *done,
 {
        zio_t *zio;
 
-       zio = zio_create(pio, spa, 0, NULL, NULL, 0, done, private,
+       zio = zio_create(pio, spa, 0, NULL, NULL, 0, 0, done, private,
            ZIO_TYPE_NULL, ZIO_PRIORITY_NOW, flags, vd, 0, NULL,
            ZIO_STAGE_OPEN, ZIO_INTERLOCK_PIPELINE);
 
@@ -676,18 +718,20 @@ zfs_blkptr_verify(spa_t *spa, const blkptr_t *bp)
                        zfs_panic_recover("blkptr at %p DVA %u has invalid "
                            "VDEV %llu",
                            bp, i, (longlong_t)vdevid);
+                       continue;
                }
                vd = spa->spa_root_vdev->vdev_child[vdevid];
                if (vd == NULL) {
                        zfs_panic_recover("blkptr at %p DVA %u has invalid "
                            "VDEV %llu",
                            bp, i, (longlong_t)vdevid);
+                       continue;
                }
                if (vd->vdev_ops == &vdev_hole_ops) {
                        zfs_panic_recover("blkptr at %p DVA %u has hole "
                            "VDEV %llu",
                            bp, i, (longlong_t)vdevid);
-
+                       continue;
                }
                if (vd->vdev_ops == &vdev_missing_ops) {
                        /*
@@ -719,7 +763,7 @@ zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
        zfs_blkptr_verify(spa, bp);
 
        zio = zio_create(pio, spa, BP_PHYSICAL_BIRTH(bp), bp,
-           data, size, done, private,
+           data, size, size, done, private,
            ZIO_TYPE_READ, priority, flags, NULL, 0, zb,
            ZIO_STAGE_OPEN, (flags & ZIO_FLAG_DDT_CHILD) ?
            ZIO_DDT_CHILD_READ_PIPELINE : ZIO_READ_PIPELINE);
@@ -729,10 +773,11 @@ zio_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
 
 zio_t *
 zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
-    void *data, uint64_t size, const zio_prop_t *zp,
-    zio_done_func_t *ready, zio_done_func_t *physdone, zio_done_func_t *done,
-    void *private,
-    zio_priority_t priority, enum zio_flag flags, const zbookmark_phys_t *zb)
+    void *data, uint64_t lsize, uint64_t psize, const zio_prop_t *zp,
+    zio_done_func_t *ready, zio_done_func_t *children_ready,
+    zio_done_func_t *physdone, zio_done_func_t *done,
+    void *private, zio_priority_t priority, enum zio_flag flags,
+    const zbookmark_phys_t *zb)
 {
        zio_t *zio;
 
@@ -745,12 +790,13 @@ zio_write(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp,
            zp->zp_copies > 0 &&
            zp->zp_copies <= spa_max_replication(spa));
 
-       zio = zio_create(pio, spa, txg, bp, data, size, done, private,
+       zio = zio_create(pio, spa, txg, bp, data, lsize, psize, done, private,
            ZIO_TYPE_WRITE, priority, flags, NULL, 0, zb,
            ZIO_STAGE_OPEN, (flags & ZIO_FLAG_DDT_CHILD) ?
            ZIO_DDT_CHILD_WRITE_PIPELINE : ZIO_WRITE_PIPELINE);
 
        zio->io_ready = ready;
+       zio->io_children_ready = children_ready;
        zio->io_physdone = physdone;
        zio->io_prop = *zp;
 
@@ -774,8 +820,8 @@ zio_rewrite(zio_t *pio, spa_t *spa, uint64_t txg, blkptr_t *bp, void *data,
 {
        zio_t *zio;
 
-       zio = zio_create(pio, spa, txg, bp, data, size, done, private,
-           ZIO_TYPE_WRITE, priority, flags, NULL, 0, zb,
+       zio = zio_create(pio, spa, txg, bp, data, size, size, done, private,
+           ZIO_TYPE_WRITE, priority, flags | ZIO_FLAG_IO_REWRITE, NULL, 0, zb,
            ZIO_STAGE_OPEN, ZIO_REWRITE_PIPELINE);
 
        return (zio);
@@ -854,8 +900,8 @@ zio_free_sync(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp,
                stage |= ZIO_STAGE_ISSUE_ASYNC;
 
        zio = zio_create(pio, spa, txg, bp, NULL, BP_GET_PSIZE(bp),
-           NULL, NULL, ZIO_TYPE_FREE, ZIO_PRIORITY_NOW, flags,
-           NULL, 0, NULL, ZIO_STAGE_OPEN, stage);
+           BP_GET_PSIZE(bp), NULL, NULL, ZIO_TYPE_FREE, ZIO_PRIORITY_NOW,
+           flags, NULL, 0, NULL, ZIO_STAGE_OPEN, stage);
 
        return (zio);
 }
@@ -888,8 +934,9 @@ zio_claim(zio_t *pio, spa_t *spa, uint64_t txg, const blkptr_t *bp,
        ASSERT(!BP_GET_DEDUP(bp) || !spa_writeable(spa));       /* zdb(1M) */
 
        zio = zio_create(pio, spa, txg, bp, NULL, BP_GET_PSIZE(bp),
-           done, private, ZIO_TYPE_CLAIM, ZIO_PRIORITY_NOW, flags,
-           NULL, 0, NULL, ZIO_STAGE_OPEN, ZIO_CLAIM_PIPELINE);
+           BP_GET_PSIZE(bp), done, private, ZIO_TYPE_CLAIM, ZIO_PRIORITY_NOW,
+           flags, NULL, 0, NULL, ZIO_STAGE_OPEN, ZIO_CLAIM_PIPELINE);
+       ASSERT0(zio->io_queued_timestamp);
 
        return (zio);
 }
@@ -902,7 +949,7 @@ zio_ioctl(zio_t *pio, spa_t *spa, vdev_t *vd, int cmd,
        int c;
 
        if (vd->vdev_children == 0) {
-               zio = zio_create(pio, spa, 0, NULL, NULL, 0, done, private,
+               zio = zio_create(pio, spa, 0, NULL, NULL, 0, 0, done, private,
                    ZIO_TYPE_IOCTL, ZIO_PRIORITY_NOW, flags, vd, 0, NULL,
                    ZIO_STAGE_OPEN, ZIO_IOCTL_PIPELINE);
 
@@ -930,9 +977,9 @@ zio_read_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size,
            offset >= vd->vdev_psize - VDEV_LABEL_END_SIZE);
        ASSERT3U(offset + size, <=, vd->vdev_psize);
 
-       zio = zio_create(pio, vd->vdev_spa, 0, NULL, data, size, done, private,
-           ZIO_TYPE_READ, priority, flags | ZIO_FLAG_PHYSICAL, vd, offset,
-           NULL, ZIO_STAGE_OPEN, ZIO_READ_PHYS_PIPELINE);
+       zio = zio_create(pio, vd->vdev_spa, 0, NULL, data, size, size, done,
+           private, ZIO_TYPE_READ, priority, flags | ZIO_FLAG_PHYSICAL, vd,
+           offset, NULL, ZIO_STAGE_OPEN, ZIO_READ_PHYS_PIPELINE);
 
        zio->io_prop.zp_checksum = checksum;
 
@@ -951,13 +998,13 @@ zio_write_phys(zio_t *pio, vdev_t *vd, uint64_t offset, uint64_t size,
            offset >= vd->vdev_psize - VDEV_LABEL_END_SIZE);
        ASSERT3U(offset + size, <=, vd->vdev_psize);
 
-       zio = zio_create(pio, vd->vdev_spa, 0, NULL, data, size, done, private,
-           ZIO_TYPE_WRITE, priority, flags | ZIO_FLAG_PHYSICAL, vd, offset,
-           NULL, ZIO_STAGE_OPEN, ZIO_WRITE_PHYS_PIPELINE);
+       zio = zio_create(pio, vd->vdev_spa, 0, NULL, data, size, size, done,
+           private, ZIO_TYPE_WRITE, priority, flags | ZIO_FLAG_PHYSICAL, vd,
+           offset, NULL, ZIO_STAGE_OPEN, ZIO_WRITE_PHYS_PIPELINE);
 
        zio->io_prop.zp_checksum = checksum;
 
-       if (zio_checksum_table[checksum].ci_eck) {
+       if (zio_checksum_table[checksum].ci_flags & ZCHECKSUM_FLAG_EMBEDDED) {
                /*
                 * zec checksums are necessarily destructive -- they modify
                 * the end of the write buffer to hold the verifier/checksum.
@@ -1009,9 +1056,31 @@ zio_vdev_child_io(zio_t *pio, blkptr_t *bp, vdev_t *vd, uint64_t offset,
        if (flags & ZIO_FLAG_IO_REPAIR)
                flags &= ~ZIO_FLAG_SPECULATIVE;
 
-       zio = zio_create(pio, pio->io_spa, pio->io_txg, bp, data, size,
+       /*
+        * If we're creating a child I/O that is not associated with a
+        * top-level vdev, then the child zio is not an allocating I/O.
+        * If this is a retried I/O then we ignore it since we will
+        * have already processed the original allocating I/O.
+        */
+       if (flags & ZIO_FLAG_IO_ALLOCATING &&
+           (vd != vd->vdev_top || (flags & ZIO_FLAG_IO_RETRY))) {
+               ASSERTV(metaslab_class_t *mc = spa_normal_class(pio->io_spa));
+
+               ASSERT(mc->mc_alloc_throttle_enabled);
+               ASSERT(type == ZIO_TYPE_WRITE);
+               ASSERT(priority == ZIO_PRIORITY_ASYNC_WRITE);
+               ASSERT(!(flags & ZIO_FLAG_IO_REPAIR));
+               ASSERT(!(pio->io_flags & ZIO_FLAG_IO_REWRITE) ||
+                   pio->io_child_type == ZIO_CHILD_GANG);
+
+               flags &= ~ZIO_FLAG_IO_ALLOCATING;
+       }
+
+
+       zio = zio_create(pio, pio->io_spa, pio->io_txg, bp, data, size, size,
            done, private, type, priority, flags, vd, offset, &pio->io_bookmark,
            ZIO_STAGE_VDEV_IO_START >> 1, pipeline);
+       ASSERT3U(zio->io_child_type, ==, ZIO_CHILD_VDEV);
 
        zio->io_physdone = pio->io_physdone;
        if (vd->vdev_ops->vdev_op_leaf && zio->io_logical != NULL)
@@ -1030,7 +1099,7 @@ zio_vdev_delegated_io(vdev_t *vd, uint64_t offset, void *data, uint64_t size,
        ASSERT(vd->vdev_ops->vdev_op_leaf);
 
        zio = zio_create(NULL, vd->vdev_spa, 0, NULL,
-           data, size, done, private, type, priority,
+           data, size, size, done, private, type, priority,
            flags | ZIO_FLAG_CANFAIL | ZIO_FLAG_DONT_RETRY | ZIO_FLAG_DELEGATED,
            vd, offset, NULL,
            ZIO_STAGE_VDEV_IO_START >> 1, ZIO_VDEV_CHILD_PIPELINE);
@@ -1059,8 +1128,11 @@ zio_shrink(zio_t *zio, uint64_t size)
         * Note, BP_IS_RAIDZ() assumes no compression.
         */
        ASSERT(BP_GET_COMPRESS(zio->io_bp) == ZIO_COMPRESS_OFF);
-       if (!BP_IS_RAIDZ(zio->io_bp))
-               zio->io_orig_size = zio->io_size = size;
+       if (!BP_IS_RAIDZ(zio->io_bp)) {
+               /* we are not doing a raw write */
+               ASSERT3U(zio->io_size, ==, zio->io_lsize);
+               zio->io_orig_size = zio->io_size = zio->io_lsize = size;
+       }
 }
 
 /*
@@ -1106,21 +1178,6 @@ zio_read_bp_init(zio_t *zio)
 static int
 zio_write_bp_init(zio_t *zio)
 {
-       spa_t *spa = zio->io_spa;
-       zio_prop_t *zp = &zio->io_prop;
-       enum zio_compress compress = zp->zp_compress;
-       blkptr_t *bp = zio->io_bp;
-       uint64_t lsize = zio->io_size;
-       uint64_t psize = lsize;
-       int pass = 1;
-
-       /*
-        * If our children haven't all reached the ready stage,
-        * wait for them and then repeat this pipeline stage.
-        */
-       if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_READY) ||
-           zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_READY))
-               return (ZIO_PIPELINE_STOP);
 
        if (!IO_IS_ALLOCATING(zio))
                return (ZIO_PIPELINE_CONTINUE);
@@ -1128,6 +1185,9 @@ zio_write_bp_init(zio_t *zio)
        ASSERT(zio->io_child_type != ZIO_CHILD_DDT);
 
        if (zio->io_bp_override) {
+               blkptr_t *bp = zio->io_bp;
+               zio_prop_t *zp = &zio->io_prop;
+
                ASSERT(bp->blk_birth != zio->io_txg);
                ASSERT(BP_GET_DEDUP(zio->io_bp_override) == 0);
 
@@ -1144,6 +1204,7 @@ zio_write_bp_init(zio_t *zio)
                 */
                if (!BP_IS_HOLE(bp) && zp->zp_nopwrite) {
                        ASSERT(!zp->zp_dedup);
+                       ASSERT3U(BP_GET_CHECKSUM(bp), ==, zp->zp_checksum);
                        zio->io_flags |= ZIO_FLAG_NOPWRITE;
                        return (ZIO_PIPELINE_CONTINUE);
                }
@@ -1153,16 +1214,64 @@ zio_write_bp_init(zio_t *zio)
                if (BP_IS_HOLE(bp) || !zp->zp_dedup)
                        return (ZIO_PIPELINE_CONTINUE);
 
-               ASSERT(zio_checksum_table[zp->zp_checksum].ci_dedup ||
-                   zp->zp_dedup_verify);
+               ASSERT((zio_checksum_table[zp->zp_checksum].ci_flags &
+                   ZCHECKSUM_FLAG_DEDUP) || zp->zp_dedup_verify);
 
                if (BP_GET_CHECKSUM(bp) == zp->zp_checksum) {
                        BP_SET_DEDUP(bp, 1);
                        zio->io_pipeline |= ZIO_STAGE_DDT_WRITE;
                        return (ZIO_PIPELINE_CONTINUE);
                }
+
+               /*
+                * We were unable to handle this as an override bp, treat
+                * it as a regular write I/O.
+                */
+               zio->io_bp_override = NULL;
+               *bp = zio->io_bp_orig;
+               zio->io_pipeline = zio->io_orig_pipeline;
+       }
+
+       return (ZIO_PIPELINE_CONTINUE);
+}
+
+static int
+zio_write_compress(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       zio_prop_t *zp = &zio->io_prop;
+       enum zio_compress compress = zp->zp_compress;
+       blkptr_t *bp = zio->io_bp;
+       uint64_t lsize = zio->io_lsize;
+       uint64_t psize = zio->io_size;
+       int pass = 1;
+
+       EQUIV(lsize != psize, (zio->io_flags & ZIO_FLAG_RAW) != 0);
+
+       /*
+        * If our children haven't all reached the ready stage,
+        * wait for them and then repeat this pipeline stage.
+        */
+       if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_READY) ||
+           zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_READY))
+               return (ZIO_PIPELINE_STOP);
+
+       if (!IO_IS_ALLOCATING(zio))
+               return (ZIO_PIPELINE_CONTINUE);
+
+       if (zio->io_children_ready != NULL) {
+               /*
+                * Now that all our children are ready, run the callback
+                * associated with this zio in case it wants to modify the
+                * data to be written.
+                */
+               ASSERT3U(zp->zp_level, >, 0);
+               zio->io_children_ready(zio);
        }
 
+       ASSERT(zio->io_child_type != ZIO_CHILD_DDT);
+       ASSERT(zio->io_bp_override == NULL);
+
        if (!BP_IS_HOLE(bp) && bp->blk_birth == zio->io_txg) {
                /*
                 * We're rewriting an existing block, which means we're
@@ -1187,7 +1296,8 @@ zio_write_bp_init(zio_t *zio)
                    spa_max_replication(spa)) == BP_GET_NDVAS(bp));
        }
 
-       if (compress != ZIO_COMPRESS_OFF) {
+       /* If it's a compressed write that is not raw, compress the buffer. */
+       if (compress != ZIO_COMPRESS_OFF && psize == lsize) {
                void *cbuf = zio_buf_alloc(lsize);
                psize = zio_compress_data(compress, zio->io_data, cbuf, lsize);
                if (psize == 0 || psize == lsize) {
@@ -1233,6 +1343,18 @@ zio_write_bp_init(zio_t *zio)
                                    psize, lsize, NULL);
                        }
                }
+
+               /*
+                * We were unable to handle this as an override bp, treat
+                * it as a regular write I/O.
+                */
+               zio->io_bp_override = NULL;
+               *bp = zio->io_bp_orig;
+               zio->io_pipeline = zio->io_orig_pipeline;
+
+       } else {
+               ASSERT3U(psize, !=, 0);
+
        }
 
        /*
@@ -1285,7 +1407,6 @@ zio_write_bp_init(zio_t *zio)
                        zio->io_pipeline |= ZIO_STAGE_NOP_WRITE;
                }
        }
-
        return (ZIO_PIPELINE_CONTINUE);
 }
 
@@ -1382,6 +1503,76 @@ zio_interrupt(zio_t *zio)
        zio_taskq_dispatch(zio, ZIO_TASKQ_INTERRUPT, B_FALSE);
 }
 
+void
+zio_delay_interrupt(zio_t *zio)
+{
+       /*
+        * The timeout_generic() function isn't defined in userspace, so
+        * rather than trying to implement the function, the zio delay
+        * functionality has been disabled for userspace builds.
+        */
+
+#ifdef _KERNEL
+       /*
+        * If io_target_timestamp is zero, then no delay has been registered
+        * for this IO, thus jump to the end of this function and "skip" the
+        * delay; issuing it directly to the zio layer.
+        */
+       if (zio->io_target_timestamp != 0) {
+               hrtime_t now = gethrtime();
+
+               if (now >= zio->io_target_timestamp) {
+                       /*
+                        * This IO has already taken longer than the target
+                        * delay to complete, so we don't want to delay it
+                        * any longer; we "miss" the delay and issue it
+                        * directly to the zio layer. This is likely due to
+                        * the target latency being set to a value less than
+                        * the underlying hardware can satisfy (e.g. delay
+                        * set to 1ms, but the disks take 10ms to complete an
+                        * IO request).
+                        */
+
+                       DTRACE_PROBE2(zio__delay__miss, zio_t *, zio,
+                           hrtime_t, now);
+
+                       zio_interrupt(zio);
+               } else {
+                       taskqid_t tid;
+                       hrtime_t diff = zio->io_target_timestamp - now;
+                       clock_t expire_at_tick = ddi_get_lbolt() +
+                           NSEC_TO_TICK(diff);
+
+                       DTRACE_PROBE3(zio__delay__hit, zio_t *, zio,
+                           hrtime_t, now, hrtime_t, diff);
+
+                       if (NSEC_TO_TICK(diff) == 0) {
+                               /* Our delay is less than a jiffy - just spin */
+                               zfs_sleep_until(zio->io_target_timestamp);
+                       } else {
+                               /*
+                                * Use taskq_dispatch_delay() in the place of
+                                * OpenZFS's timeout_generic().
+                                */
+                               tid = taskq_dispatch_delay(system_taskq,
+                                   (task_func_t *) zio_interrupt,
+                                   zio, TQ_NOSLEEP, expire_at_tick);
+                               if (!tid) {
+                                       /*
+                                        * Couldn't allocate a task.  Just
+                                        * finish the zio without a delay.
+                                        */
+                                       zio_interrupt(zio);
+                               }
+                       }
+               }
+               return;
+       }
+#endif
+       DTRACE_PROBE1(zio__delay__skip, zio_t *, zio);
+       zio_interrupt(zio);
+}
+
 /*
  * Execute the I/O pipeline until one of the following occurs:
  * (1) the I/O completes; (2) the pipeline stalls waiting for
@@ -1415,17 +1606,42 @@ zio_execute(zio_t *zio)
        spl_fstrans_unmark(cookie);
 }
 
+/*
+ * Used to determine if in the current context the stack is sized large
+ * enough to allow zio_execute() to be called recursively.  A minimum
+ * stack size of 16K is required to avoid needing to re-dispatch the zio.
+ */
+boolean_t
+zio_execute_stack_check(zio_t *zio)
+{
+#if !defined(HAVE_LARGE_STACKS)
+       dsl_pool_t *dp = spa_get_dsl(zio->io_spa);
+
+       /* Executing in txg_sync_thread() context. */
+       if (dp && curthread == dp->dp_tx.tx_sync_thread)
+               return (B_TRUE);
+
+       /* Pool initialization outside of zio_taskq context. */
+       if (dp && spa_is_initializing(dp->dp_spa) &&
+           !zio_taskq_member(zio, ZIO_TASKQ_ISSUE) &&
+           !zio_taskq_member(zio, ZIO_TASKQ_ISSUE_HIGH))
+               return (B_TRUE);
+#endif /* HAVE_LARGE_STACKS */
+
+       return (B_FALSE);
+}
+
 __attribute__((always_inline))
 static inline void
 __zio_execute(zio_t *zio)
 {
        zio->io_executor = curthread;
 
+       ASSERT3U(zio->io_queued_timestamp, >, 0);
+
        while (zio->io_stage < ZIO_STAGE_DONE) {
                enum zio_stage pipeline = zio->io_pipeline;
                enum zio_stage stage = zio->io_stage;
-               dsl_pool_t *dp;
-               boolean_t cut;
                int rv;
 
                ASSERT(!MUTEX_HELD(&zio->io_lock));
@@ -1438,10 +1654,6 @@ __zio_execute(zio_t *zio)
 
                ASSERT(stage <= ZIO_STAGE_DONE);
 
-               dp = spa_get_dsl(zio->io_spa);
-               cut = (stage == ZIO_STAGE_VDEV_IO_START) ?
-                   zio_requeue_io_start_cut_in_line : B_FALSE;
-
                /*
                 * If we are in interrupt context and this pipeline stage
                 * will grab a config lock that is held across I/O,
@@ -1453,26 +1665,25 @@ __zio_execute(zio_t *zio)
                 */
                if ((stage & ZIO_BLOCKING_STAGES) && zio->io_vd == NULL &&
                    zio_taskq_member(zio, ZIO_TASKQ_INTERRUPT)) {
+                       boolean_t cut = (stage == ZIO_STAGE_VDEV_IO_START) ?
+                           zio_requeue_io_start_cut_in_line : B_FALSE;
                        zio_taskq_dispatch(zio, ZIO_TASKQ_ISSUE, cut);
                        return;
                }
 
                /*
-                * If we executing in the context of the tx_sync_thread,
-                * or we are performing pool initialization outside of a
-                * zio_taskq[ZIO_TASKQ_ISSUE|ZIO_TASKQ_ISSUE_HIGH] context.
-                * Then issue the zio asynchronously to minimize stack usage
-                * for these deep call paths.
+                * If the current context doesn't have large enough stacks
+                * the zio must be issued asynchronously to prevent overflow.
                 */
-               if ((dp && curthread == dp->dp_tx.tx_sync_thread) ||
-                   (dp && spa_is_initializing(dp->dp_spa) &&
-                   !zio_taskq_member(zio, ZIO_TASKQ_ISSUE) &&
-                   !zio_taskq_member(zio, ZIO_TASKQ_ISSUE_HIGH))) {
+               if (zio_execute_stack_check(zio)) {
+                       boolean_t cut = (stage == ZIO_STAGE_VDEV_IO_START) ?
+                           zio_requeue_io_start_cut_in_line : B_FALSE;
                        zio_taskq_dispatch(zio, ZIO_TASKQ_ISSUE, cut);
                        return;
                }
 
                zio->io_stage = stage;
+               zio->io_pipeline_trace |= zio->io_stage;
                rv = zio_pipeline[highbit64(stage) - 1](zio);
 
                if (rv == ZIO_PIPELINE_STOP)
@@ -1497,6 +1708,8 @@ zio_wait(zio_t *zio)
        ASSERT(zio->io_executor == NULL);
 
        zio->io_waiter = curthread;
+       ASSERT0(zio->io_queued_timestamp);
+       zio->io_queued_timestamp = gethrtime();
 
        __zio_execute(zio);
 
@@ -1533,6 +1746,8 @@ zio_nowait(zio_t *zio)
                zio_add_child(pio, zio);
        }
 
+       ASSERT0(zio->io_queued_timestamp);
+       zio->io_queued_timestamp = gethrtime();
        __zio_execute(zio);
 }
 
@@ -1547,6 +1762,7 @@ zio_reexecute(zio_t *pio)
 {
        zio_t *cio, *cio_next;
        int c, w;
+       zio_link_t *zl = NULL;
 
        ASSERT(pio->io_child_type == ZIO_CHILD_LOGICAL);
        ASSERT(pio->io_orig_stage == ZIO_STAGE_OPEN);
@@ -1558,6 +1774,7 @@ zio_reexecute(zio_t *pio)
        pio->io_pipeline = pio->io_orig_pipeline;
        pio->io_reexecute = 0;
        pio->io_flags |= ZIO_FLAG_REEXECUTED;
+       pio->io_pipeline_trace = 0;
        pio->io_error = 0;
        for (w = 0; w < ZIO_WAIT_TYPES; w++)
                pio->io_state[w] = 0;
@@ -1574,8 +1791,8 @@ zio_reexecute(zio_t *pio)
         * the remainder of pio's io_child_list, from 'cio_next' onward,
         * cannot be affected by any side effects of reexecuting 'cio'.
         */
-       for (cio = zio_walk_children(pio); cio != NULL; cio = cio_next) {
-               cio_next = zio_walk_children(pio);
+       for (cio = zio_walk_children(pio, &zl); cio != NULL; cio = cio_next) {
+               cio_next = zio_walk_children(pio, &zl);
                mutex_enter(&pio->io_lock);
                for (w = 0; w < ZIO_WAIT_TYPES; w++)
                        pio->io_children[cio->io_child_type][w]++;
@@ -1588,8 +1805,10 @@ zio_reexecute(zio_t *pio)
         * We don't reexecute "The Godfather" I/O here as it's the
         * responsibility of the caller to wait on him.
         */
-       if (!(pio->io_flags & ZIO_FLAG_GODFATHER))
+       if (!(pio->io_flags & ZIO_FLAG_GODFATHER)) {
+               pio->io_queued_timestamp = gethrtime();
                __zio_execute(pio);
+       }
 }
 
 void
@@ -1990,6 +2209,7 @@ static int
 zio_write_gang_block(zio_t *pio)
 {
        spa_t *spa = pio->io_spa;
+       metaslab_class_t *mc = spa_normal_class(spa);
        blkptr_t *bp = pio->io_bp;
        zio_t *gio = pio->io_gang_leader;
        zio_t *zio;
@@ -2003,10 +2223,44 @@ zio_write_gang_block(zio_t *pio)
        zio_prop_t zp;
        int g, error;
 
-       error = metaslab_alloc(spa, spa_normal_class(spa), SPA_GANGBLOCKSIZE,
-           bp, gbh_copies, txg, pio == gio ? NULL : gio->io_bp,
-           METASLAB_HINTBP_FAVOR | METASLAB_GANG_HEADER);
+       int flags = METASLAB_HINTBP_FAVOR | METASLAB_GANG_HEADER;
+       if (pio->io_flags & ZIO_FLAG_IO_ALLOCATING) {
+               ASSERT(pio->io_priority == ZIO_PRIORITY_ASYNC_WRITE);
+               ASSERT(!(pio->io_flags & ZIO_FLAG_NODATA));
+
+               flags |= METASLAB_ASYNC_ALLOC;
+               VERIFY(refcount_held(&mc->mc_alloc_slots, pio));
+
+               /*
+                * The logical zio has already placed a reservation for
+                * 'copies' allocation slots but gang blocks may require
+                * additional copies. These additional copies
+                * (i.e. gbh_copies - copies) are guaranteed to succeed
+                * since metaslab_class_throttle_reserve() always allows
+                * additional reservations for gang blocks.
+                */
+               VERIFY(metaslab_class_throttle_reserve(mc, gbh_copies - copies,
+                   pio, flags));
+       }
+
+       error = metaslab_alloc(spa, mc, SPA_GANGBLOCKSIZE,
+           bp, gbh_copies, txg, pio == gio ? NULL : gio->io_bp, flags, pio);
        if (error) {
+               if (pio->io_flags & ZIO_FLAG_IO_ALLOCATING) {
+                       ASSERT(pio->io_priority == ZIO_PRIORITY_ASYNC_WRITE);
+                       ASSERT(!(pio->io_flags & ZIO_FLAG_NODATA));
+
+                       /*
+                        * If we failed to allocate the gang block header then
+                        * we remove any additional allocation reservations that
+                        * we placed here. The original reservation will
+                        * be removed when the logical I/O goes to the ready
+                        * stage.
+                        */
+                       metaslab_class_throttle_unreserve(mc,
+                           gbh_copies - copies, pio);
+               }
+
                pio->io_error = error;
                return (ZIO_PIPELINE_CONTINUE);
        }
@@ -2032,6 +2286,8 @@ zio_write_gang_block(zio_t *pio)
         * Create and nowait the gang children.
         */
        for (g = 0; resid != 0; resid -= lsize, g++) {
+               zio_t *cio;
+
                lsize = P2ROUNDUP(resid / (SPA_GBH_NBLKPTRS - g),
                    SPA_MINBLOCKSIZE);
                ASSERT(lsize >= SPA_MINBLOCKSIZE && lsize <= resid);
@@ -2045,11 +2301,26 @@ zio_write_gang_block(zio_t *pio)
                zp.zp_dedup_verify = B_FALSE;
                zp.zp_nopwrite = B_FALSE;
 
-               zio_nowait(zio_write(zio, spa, txg, &gbh->zg_blkptr[g],
-                   (char *)pio->io_data + (pio->io_size - resid), lsize, &zp,
-                   zio_write_gang_member_ready, NULL, NULL, &gn->gn_child[g],
-                   pio->io_priority, ZIO_GANG_CHILD_FLAGS(pio),
-                   &pio->io_bookmark));
+               cio = zio_write(zio, spa, txg, &gbh->zg_blkptr[g],
+                   (char *)pio->io_data + (pio->io_size - resid), lsize,
+                   lsize, &zp, zio_write_gang_member_ready, NULL, NULL, NULL,
+                   &gn->gn_child[g], pio->io_priority,
+                   ZIO_GANG_CHILD_FLAGS(pio), &pio->io_bookmark);
+
+               if (pio->io_flags & ZIO_FLAG_IO_ALLOCATING) {
+                       ASSERT(pio->io_priority == ZIO_PRIORITY_ASYNC_WRITE);
+                       ASSERT(!(pio->io_flags & ZIO_FLAG_NODATA));
+
+                       /*
+                        * Gang children won't throttle but we should
+                        * account for their work, so reserve an allocation
+                        * slot for them here.
+                        */
+                       VERIFY(metaslab_class_throttle_reserve(mc,
+                           zp.zp_copies, cio, flags));
+               }
+               zio_nowait(cio);
+
        }
 
        /*
@@ -2068,12 +2339,22 @@ zio_write_gang_block(zio_t *pio)
 }
 
 /*
- * The zio_nop_write stage in the pipeline determines if allocating
- * a new bp is necessary.  By leveraging a cryptographically secure checksum,
- * such as SHA256, we can compare the checksums of the new data and the old
- * to determine if allocating a new block is required.  The nopwrite
- * feature can handle writes in either syncing or open context (i.e. zil
- * writes) and as a result is mutually exclusive with dedup.
+ * The zio_nop_write stage in the pipeline determines if allocating a
+ * new bp is necessary.  The nopwrite feature can handle writes in
+ * either syncing or open context (i.e. zil writes) and as a result is
+ * mutually exclusive with dedup.
+ *
+ * By leveraging a cryptographically secure checksum, such as SHA256, we
+ * can compare the checksums of the new data and the old to determine if
+ * allocating a new block is required.  Note that our requirements for
+ * cryptographic strength are fairly weak: there can't be any accidental
+ * hash collisions, but we don't need to be secure against intentional
+ * (malicious) collisions.  To trigger a nopwrite, you have to be able
+ * to write the file to begin with, and triggering an incorrect (hash
+ * collision) nopwrite is no worse than simply writing to the file.
+ * That said, there are no known attacks against the checksum algorithms
+ * used for nopwrite, assuming that the salt and the checksums
+ * themselves remain secret.
  */
 static int
 zio_nop_write(zio_t *zio)
@@ -2096,7 +2377,8 @@ zio_nop_write(zio_t *zio)
         * allocate a new bp.
         */
        if (BP_IS_HOLE(bp_orig) ||
-           !zio_checksum_table[BP_GET_CHECKSUM(bp)].ci_dedup ||
+           !(zio_checksum_table[BP_GET_CHECKSUM(bp)].ci_flags &
+           ZCHECKSUM_FLAG_NOPWRITE) ||
            BP_GET_CHECKSUM(bp) != BP_GET_CHECKSUM(bp_orig) ||
            BP_GET_COMPRESS(bp) != BP_GET_COMPRESS(bp_orig) ||
            BP_GET_DEDUP(bp) != BP_GET_DEDUP(bp_orig) ||
@@ -2108,7 +2390,8 @@ zio_nop_write(zio_t *zio)
         * avoid allocating a new bp and issuing any I/O.
         */
        if (ZIO_CHECKSUM_EQUAL(bp->blk_cksum, bp_orig->blk_cksum)) {
-               ASSERT(zio_checksum_table[zp->zp_checksum].ci_dedup);
+               ASSERT(zio_checksum_table[zp->zp_checksum].ci_flags &
+                   ZCHECKSUM_FLAG_NOPWRITE);
                ASSERT3U(BP_GET_PSIZE(bp), ==, BP_GET_PSIZE(bp_orig));
                ASSERT3U(BP_GET_LSIZE(bp), ==, BP_GET_LSIZE(bp_orig));
                ASSERT(zp->zp_compress != ZIO_COMPRESS_OFF);
@@ -2233,17 +2516,30 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
 {
        spa_t *spa = zio->io_spa;
        int p;
+       boolean_t do_raw = !!(zio->io_flags & ZIO_FLAG_RAW);
+
+       ASSERT(!(zio->io_bp_override && do_raw));
 
        /*
         * Note: we compare the original data, not the transformed data,
         * because when zio->io_bp is an override bp, we will not have
         * pushed the I/O transforms.  That's an important optimization
         * because otherwise we'd compress/encrypt all dmu_sync() data twice.
+        * However, we should never get a raw, override zio so in these
+        * cases we can compare the io_data directly. This is useful because
+        * it allows us to do dedup verification even if we don't have access
+        * to the original data (for instance, if the encryption keys aren't
+        * loaded).
         */
+
        for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
                zio_t *lio = dde->dde_lead_zio[p];
 
-               if (lio != NULL) {
+               if (lio != NULL && do_raw) {
+                       return (lio->io_size != zio->io_size ||
+                           bcmp(zio->io_data, lio->io_data,
+                           zio->io_size) != 0);
+               } else if (lio != NULL) {
                        return (lio->io_orig_size != zio->io_orig_size ||
                            bcmp(zio->io_orig_data, lio->io_orig_data,
                            zio->io_orig_size) != 0);
@@ -2253,7 +2549,36 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
        for (p = DDT_PHYS_SINGLE; p <= DDT_PHYS_TRIPLE; p++) {
                ddt_phys_t *ddp = &dde->dde_phys[p];
 
-               if (ddp->ddp_phys_birth != 0) {
+               if (ddp->ddp_phys_birth != 0 && do_raw) {
+                       blkptr_t blk = *zio->io_bp;
+                       uint64_t psize;
+                       void *tmpbuf;
+                       int error;
+
+                       ddt_bp_fill(ddp, &blk, ddp->ddp_phys_birth);
+                       psize = BP_GET_PSIZE(&blk);
+
+                       if (psize != zio->io_size)
+                               return (B_TRUE);
+
+                       ddt_exit(ddt);
+
+                       tmpbuf = zio_buf_alloc(psize);
+
+                       error = zio_wait(zio_read(NULL, spa, &blk, tmpbuf,
+                           psize, NULL, NULL, ZIO_PRIORITY_SYNC_READ,
+                           ZIO_FLAG_CANFAIL | ZIO_FLAG_SPECULATIVE |
+                           ZIO_FLAG_RAW, &zio->io_bookmark));
+
+                       if (error == 0) {
+                               if (bcmp(tmpbuf, zio->io_data, psize) != 0)
+                                       error = SET_ERROR(ENOENT);
+                       }
+
+                       zio_buf_free(tmpbuf, psize);
+                       ddt_enter(ddt);
+                       return (error != 0);
+               } else if (ddp->ddp_phys_birth != 0) {
                        arc_buf_t *abuf = NULL;
                        arc_flags_t aflags = ARC_FLAG_WAIT;
                        blkptr_t blk = *zio->io_bp;
@@ -2261,6 +2586,9 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
 
                        ddt_bp_fill(ddp, &blk, ddp->ddp_phys_birth);
 
+                       if (BP_GET_LSIZE(&blk) != zio->io_orig_size)
+                               return (B_TRUE);
+
                        ddt_exit(ddt);
 
                        error = arc_read(NULL, spa, &blk,
@@ -2269,11 +2597,10 @@ zio_ddt_collision(zio_t *zio, ddt_t *ddt, ddt_entry_t *dde)
                            &aflags, &zio->io_bookmark);
 
                        if (error == 0) {
-                               if (arc_buf_size(abuf) != zio->io_orig_size ||
-                                   bcmp(abuf->b_data, zio->io_orig_data,
+                               if (bcmp(abuf->b_data, zio->io_orig_data,
                                    zio->io_orig_size) != 0)
-                                       error = SET_ERROR(EEXIST);
-                               VERIFY(arc_buf_remove_ref(abuf, &abuf));
+                                       error = SET_ERROR(ENOENT);
+                               arc_buf_destroy(abuf, &abuf);
                        }
 
                        ddt_enter(ddt);
@@ -2292,6 +2619,7 @@ zio_ddt_child_write_ready(zio_t *zio)
        ddt_entry_t *dde = zio->io_private;
        ddt_phys_t *ddp = &dde->dde_phys[p];
        zio_t *pio;
+       zio_link_t *zl;
 
        if (zio->io_error)
                return;
@@ -2302,7 +2630,8 @@ zio_ddt_child_write_ready(zio_t *zio)
 
        ddt_phys_fill(ddp, zio->io_bp);
 
-       while ((pio = zio_walk_parents(zio)) != NULL)
+       zl = NULL;
+       while ((pio = zio_walk_parents(zio, &zl)) != NULL)
                ddt_bp_fill(ddp, pio->io_bp, zio->io_txg);
 
        ddt_exit(ddt);
@@ -2323,7 +2652,8 @@ zio_ddt_child_write_done(zio_t *zio)
        dde->dde_lead_zio[p] = NULL;
 
        if (zio->io_error == 0) {
-               while (zio_walk_parents(zio) != NULL)
+               zio_link_t *zl = NULL;
+               while (zio_walk_parents(zio, &zl) != NULL)
                        ddt_phys_addref(ddp);
        } else {
                ddt_phys_clear(ddp);
@@ -2379,6 +2709,7 @@ zio_ddt_write(zio_t *zio)
        ASSERT(BP_GET_DEDUP(bp));
        ASSERT(BP_GET_CHECKSUM(bp) == zp->zp_checksum);
        ASSERT(BP_IS_HOLE(bp) || zio->io_bp_override);
+       ASSERT(!(zio->io_bp_override && (zio->io_flags & ZIO_FLAG_RAW)));
 
        ddt_enter(ddt);
        dde = ddt_lookup(ddt, bp, B_TRUE);
@@ -2391,7 +2722,8 @@ zio_ddt_write(zio_t *zio)
                 * we can't resolve it, so just convert to an ordinary write.
                 * (And automatically e-mail a paper to Nature?)
                 */
-               if (!zio_checksum_table[zp->zp_checksum].ci_dedup) {
+               if (!(zio_checksum_table[zp->zp_checksum].ci_flags &
+                   ZCHECKSUM_FLAG_DEDUP)) {
                        zp->zp_checksum = spa_dedup_checksum(spa);
                        zio_pop_transforms(zio);
                        zio->io_stage = ZIO_STAGE_OPEN;
@@ -2431,8 +2763,8 @@ zio_ddt_write(zio_t *zio)
                }
 
                dio = zio_write(zio, spa, txg, bp, zio->io_orig_data,
-                   zio->io_orig_size, &czp, NULL, NULL,
-                   zio_ddt_ditto_write_done, dde, zio->io_priority,
+                   zio->io_orig_size, zio->io_orig_size, &czp, NULL, NULL,
+                   NULL, zio_ddt_ditto_write_done, dde, zio->io_priority,
                    ZIO_DDT_CHILD_FLAGS(zio), &zio->io_bookmark);
 
                zio_push_transform(dio, zio->io_data, zio->io_size, 0, NULL);
@@ -2453,7 +2785,8 @@ zio_ddt_write(zio_t *zio)
                ddt_phys_addref(ddp);
        } else {
                cio = zio_write(zio, spa, txg, bp, zio->io_orig_data,
-                   zio->io_orig_size, zp, zio_ddt_child_write_ready, NULL,
+                   zio->io_orig_size, zio->io_orig_size, zp,
+                   zio_ddt_child_write_ready, NULL, NULL,
                    zio_ddt_child_write_done, dde, zio->io_priority,
                    ZIO_DDT_CHILD_FLAGS(zio), &zio->io_bookmark);
 
@@ -2502,6 +2835,97 @@ zio_ddt_free(zio_t *zio)
  * Allocate and free blocks
  * ==========================================================================
  */
+
+static zio_t *
+zio_io_to_allocate(spa_t *spa)
+{
+       zio_t *zio;
+
+       ASSERT(MUTEX_HELD(&spa->spa_alloc_lock));
+
+       zio = avl_first(&spa->spa_alloc_tree);
+       if (zio == NULL)
+               return (NULL);
+
+       ASSERT(IO_IS_ALLOCATING(zio));
+
+       /*
+        * Try to place a reservation for this zio. If we're unable to
+        * reserve then we throttle.
+        */
+       if (!metaslab_class_throttle_reserve(spa_normal_class(spa),
+           zio->io_prop.zp_copies, zio, 0)) {
+               return (NULL);
+       }
+
+       avl_remove(&spa->spa_alloc_tree, zio);
+       ASSERT3U(zio->io_stage, <, ZIO_STAGE_DVA_ALLOCATE);
+
+       return (zio);
+}
+
+static int
+zio_dva_throttle(zio_t *zio)
+{
+       spa_t *spa = zio->io_spa;
+       zio_t *nio;
+
+       if (zio->io_priority == ZIO_PRIORITY_SYNC_WRITE ||
+           !spa_normal_class(zio->io_spa)->mc_alloc_throttle_enabled ||
+           zio->io_child_type == ZIO_CHILD_GANG ||
+           zio->io_flags & ZIO_FLAG_NODATA) {
+               return (ZIO_PIPELINE_CONTINUE);
+       }
+
+       ASSERT(zio->io_child_type > ZIO_CHILD_GANG);
+
+       ASSERT3U(zio->io_queued_timestamp, >, 0);
+       ASSERT(zio->io_stage == ZIO_STAGE_DVA_THROTTLE);
+
+       mutex_enter(&spa->spa_alloc_lock);
+
+       ASSERT(zio->io_type == ZIO_TYPE_WRITE);
+       avl_add(&spa->spa_alloc_tree, zio);
+
+       nio = zio_io_to_allocate(zio->io_spa);
+       mutex_exit(&spa->spa_alloc_lock);
+
+       if (nio == zio)
+               return (ZIO_PIPELINE_CONTINUE);
+
+       if (nio != NULL) {
+               ASSERT3U(nio->io_queued_timestamp, <=,
+                   zio->io_queued_timestamp);
+               ASSERT(nio->io_stage == ZIO_STAGE_DVA_THROTTLE);
+               /*
+                * We are passing control to a new zio so make sure that
+                * it is processed by a different thread. We do this to
+                * avoid stack overflows that can occur when parents are
+                * throttled and children are making progress. We allow
+                * it to go to the head of the taskq since it's already
+                * been waiting.
+                */
+               zio_taskq_dispatch(nio, ZIO_TASKQ_ISSUE, B_TRUE);
+       }
+       return (ZIO_PIPELINE_STOP);
+}
+
+void
+zio_allocate_dispatch(spa_t *spa)
+{
+       zio_t *zio;
+
+       mutex_enter(&spa->spa_alloc_lock);
+       zio = zio_io_to_allocate(spa);
+       mutex_exit(&spa->spa_alloc_lock);
+       if (zio == NULL)
+               return;
+
+       ASSERT3U(zio->io_stage, ==, ZIO_STAGE_DVA_THROTTLE);
+       ASSERT0(zio->io_error);
+       zio_taskq_dispatch(zio, ZIO_TASKQ_ISSUE, B_TRUE);
+}
+
 static int
 zio_dva_allocate(zio_t *zio)
 {
@@ -2522,19 +2946,18 @@ zio_dva_allocate(zio_t *zio)
        ASSERT3U(zio->io_prop.zp_copies, <=, spa_max_replication(spa));
        ASSERT3U(zio->io_size, ==, BP_GET_PSIZE(bp));
 
-       /*
-        * The dump device does not support gang blocks so allocation on
-        * behalf of the dump device (i.e. ZIO_FLAG_NODATA) must avoid
-        * the "fast" gang feature.
-        */
-       flags |= (zio->io_flags & ZIO_FLAG_NODATA) ? METASLAB_GANG_AVOID : 0;
-       flags |= (zio->io_flags & ZIO_FLAG_GANG_CHILD) ?
-           METASLAB_GANG_CHILD : 0;
        flags |= (zio->io_flags & ZIO_FLAG_FASTWRITE) ? METASLAB_FASTWRITE : 0;
+       if (zio->io_flags & ZIO_FLAG_NODATA)
+               flags |= METASLAB_DONT_THROTTLE;
+       if (zio->io_flags & ZIO_FLAG_GANG_CHILD)
+               flags |= METASLAB_GANG_CHILD;
+       if (zio->io_priority == ZIO_PRIORITY_ASYNC_WRITE)
+               flags |= METASLAB_ASYNC_ALLOC;
+
        error = metaslab_alloc(spa, mc, zio->io_size, bp,
-           zio->io_prop.zp_copies, zio->io_txg, NULL, flags);
+           zio->io_prop.zp_copies, zio->io_txg, NULL, flags, zio);
 
-       if (error) {
+       if (error != 0) {
                spa_dbgmsg(spa, "%s: metaslab allocation failure: zio %p, "
                    "size %llu, error %d", spa_name(spa), zio, zio->io_size,
                    error);
@@ -2601,21 +3024,14 @@ zio_alloc_zil(spa_t *spa, uint64_t txg, blkptr_t *new_bp, uint64_t size,
 
        ASSERT(txg > spa_syncing_txg(spa));
 
-       /*
-        * ZIL blocks are always contiguous (i.e. not gang blocks) so we
-        * set the METASLAB_GANG_AVOID flag so that they don't "fast gang"
-        * when allocating them.
-        */
        if (use_slog) {
                error = metaslab_alloc(spa, spa_log_class(spa), size,
-                   new_bp, 1, txg, NULL,
-                   METASLAB_FASTWRITE | METASLAB_GANG_AVOID);
+                   new_bp, 1, txg, NULL, METASLAB_FASTWRITE, NULL);
        }
 
        if (error) {
                error = metaslab_alloc(spa, spa_normal_class(spa), size,
-                   new_bp, 1, txg, NULL,
-                   METASLAB_FASTWRITE);
+                   new_bp, 1, txg, NULL, METASLAB_FASTWRITE, NULL);
        }
 
        if (error == 0) {
@@ -2670,6 +3086,8 @@ zio_vdev_io_start(zio_t *zio)
        uint64_t align;
        spa_t *spa = zio->io_spa;
 
+       zio->io_delay = 0;
+
        ASSERT(zio->io_error == 0);
        ASSERT(zio->io_child_error[ZIO_CHILD_VDEV] == 0);
 
@@ -2684,6 +3102,8 @@ zio_vdev_io_start(zio_t *zio)
                return (ZIO_PIPELINE_STOP);
        }
 
+       ASSERT3P(zio->io_logical, !=, zio);
+
        /*
         * We keep track of time-sensitive I/Os so that the scan thread
         * can quickly react to certain workloads.  In particular, we care
@@ -2775,6 +3195,7 @@ zio_vdev_io_start(zio_t *zio)
                }
        }
 
+       zio->io_delay = gethrtime();
        vd->vdev_ops->vdev_op_io_start(zio);
        return (ZIO_PIPELINE_STOP);
 }
@@ -2791,6 +3212,9 @@ zio_vdev_io_done(zio_t *zio)
 
        ASSERT(zio->io_type == ZIO_TYPE_READ || zio->io_type == ZIO_TYPE_WRITE);
 
+       if (zio->io_delay)
+               zio->io_delay = gethrtime() - zio->io_delay;
+
        if (vd != NULL && vd->vdev_ops->vdev_op_leaf) {
 
                vdev_queue_io_done(zio);
@@ -3057,6 +3481,7 @@ zio_ready(zio_t *zio)
 {
        blkptr_t *bp = zio->io_bp;
        zio_t *pio, *pio_next;
+       zio_link_t *zl = NULL;
 
        if (zio_wait_for_children(zio, ZIO_CHILD_GANG, ZIO_WAIT_READY) ||
            zio_wait_for_children(zio, ZIO_CHILD_DDT, ZIO_WAIT_READY))
@@ -3074,12 +3499,26 @@ zio_ready(zio_t *zio)
        if (bp != NULL && bp != &zio->io_bp_copy)
                zio->io_bp_copy = *bp;
 
-       if (zio->io_error)
+       if (zio->io_error != 0) {
                zio->io_pipeline = ZIO_INTERLOCK_PIPELINE;
 
+               if (zio->io_flags & ZIO_FLAG_IO_ALLOCATING) {
+                       ASSERT(IO_IS_ALLOCATING(zio));
+                       ASSERT(zio->io_priority == ZIO_PRIORITY_ASYNC_WRITE);
+                       /*
+                        * We were unable to allocate anything, unreserve and
+                        * issue the next I/O to allocate.
+                        */
+                       metaslab_class_throttle_unreserve(
+                           spa_normal_class(zio->io_spa),
+                           zio->io_prop.zp_copies, zio);
+                       zio_allocate_dispatch(zio->io_spa);
+               }
+       }
+
        mutex_enter(&zio->io_lock);
        zio->io_state[ZIO_WAIT_READY] = 1;
-       pio = zio_walk_parents(zio);
+       pio = zio_walk_parents(zio, &zl);
        mutex_exit(&zio->io_lock);
 
        /*
@@ -3090,7 +3529,7 @@ zio_ready(zio_t *zio)
         * all parents must wait for us to be done before they can be done.
         */
        for (; pio != NULL; pio = pio_next) {
-               pio_next = zio_walk_parents(zio);
+               pio_next = zio_walk_parents(zio, &zl);
                zio_notify_parent(pio, zio, ZIO_WAIT_READY);
        }
 
@@ -3110,11 +3549,76 @@ zio_ready(zio_t *zio)
        return (ZIO_PIPELINE_CONTINUE);
 }
 
+/*
+ * Update the allocation throttle accounting.
+ */
+static void
+zio_dva_throttle_done(zio_t *zio)
+{
+       zio_t *pio = zio_unique_parent(zio);
+       vdev_t *vd = zio->io_vd;
+       int flags = METASLAB_ASYNC_ALLOC;
+       ASSERTV(zio_t *lio = zio->io_logical);
+
+       ASSERT3P(zio->io_bp, !=, NULL);
+       ASSERT3U(zio->io_type, ==, ZIO_TYPE_WRITE);
+       ASSERT3U(zio->io_priority, ==, ZIO_PRIORITY_ASYNC_WRITE);
+       ASSERT3U(zio->io_child_type, ==, ZIO_CHILD_VDEV);
+       ASSERT(vd != NULL);
+       ASSERT3P(vd, ==, vd->vdev_top);
+       ASSERT(!(zio->io_flags & (ZIO_FLAG_IO_REPAIR | ZIO_FLAG_IO_RETRY)));
+       ASSERT(zio->io_flags & ZIO_FLAG_IO_ALLOCATING);
+       ASSERT(!(lio->io_flags & ZIO_FLAG_IO_REWRITE));
+       ASSERT(!(lio->io_orig_flags & ZIO_FLAG_NODATA));
+
+       /*
+        * Parents of gang children can have two flavors -- ones that
+        * allocated the gang header (will have ZIO_FLAG_IO_REWRITE set)
+        * and ones that allocated the constituent blocks. The allocation
+        * throttle needs to know the allocating parent zio so we must find
+        * it here.
+        */
+       if (pio->io_child_type == ZIO_CHILD_GANG) {
+               /*
+                * If our parent is a rewrite gang child then our grandparent
+                * would have been the one that performed the allocation.
+                */
+               if (pio->io_flags & ZIO_FLAG_IO_REWRITE)
+                       pio = zio_unique_parent(pio);
+               flags |= METASLAB_GANG_CHILD;
+       }
+
+       ASSERT(IO_IS_ALLOCATING(pio));
+       ASSERT3P(zio, !=, zio->io_logical);
+       ASSERT(zio->io_logical != NULL);
+       ASSERT(!(zio->io_flags & ZIO_FLAG_IO_REPAIR));
+       ASSERT0(zio->io_flags & ZIO_FLAG_NOPWRITE);
+
+       mutex_enter(&pio->io_lock);
+       metaslab_group_alloc_decrement(zio->io_spa, vd->vdev_id, pio, flags);
+       mutex_exit(&pio->io_lock);
+
+       metaslab_class_throttle_unreserve(spa_normal_class(zio->io_spa),
+           1, pio);
+
+       /*
+        * Call into the pipeline to see if there is more work that
+        * needs to be done. If there is work to be done it will be
+        * dispatched to another taskq thread.
+        */
+       zio_allocate_dispatch(zio->io_spa);
+}
+
 static int
 zio_done(zio_t *zio)
 {
+       /*
+        * Always attempt to keep stack usage minimal here since
+        * we can be called recurisvely up to 19 levels deep.
+        */
        zio_t *pio, *pio_next;
        int c, w;
+       zio_link_t *zl = NULL;
 
        /*
         * If our children haven't all completed,
@@ -3126,6 +3630,33 @@ zio_done(zio_t *zio)
            zio_wait_for_children(zio, ZIO_CHILD_LOGICAL, ZIO_WAIT_DONE))
                return (ZIO_PIPELINE_STOP);
 
+       /*
+        * If the allocation throttle is enabled, then update the accounting.
+        * We only track child I/Os that are part of an allocating async
+        * write. We must do this since the allocation is performed
+        * by the logical I/O but the actual write is done by child I/Os.
+        */
+       if (zio->io_flags & ZIO_FLAG_IO_ALLOCATING &&
+           zio->io_child_type == ZIO_CHILD_VDEV) {
+               ASSERT(spa_normal_class(
+                   zio->io_spa)->mc_alloc_throttle_enabled);
+               zio_dva_throttle_done(zio);
+       }
+
+       /*
+        * If the allocation throttle is enabled, verify that
+        * we have decremented the refcounts for every I/O that was throttled.
+        */
+       if (zio->io_flags & ZIO_FLAG_IO_ALLOCATING) {
+               ASSERT(zio->io_type == ZIO_TYPE_WRITE);
+               ASSERT(zio->io_priority == ZIO_PRIORITY_ASYNC_WRITE);
+               ASSERT(zio->io_bp != NULL);
+               metaslab_group_alloc_verify(zio->io_spa, zio->io_bp, zio);
+               VERIFY(refcount_not_held(
+                   &(spa_normal_class(zio->io_spa)->mc_alloc_slots), zio));
+       }
+
+
        for (c = 0; c < ZIO_CHILD_TYPES; c++)
                for (w = 0; w < ZIO_WAIT_TYPES; w++)
                        ASSERT(zio->io_children[c][w] == 0);
@@ -3193,7 +3724,7 @@ zio_done(zio_t *zio)
         * 30 seconds to complete, post an error described the I/O delay.
         * We ignore these errors if the device is currently unavailable.
         */
-       if (zio->io_delay >= MSEC_TO_TICK(zio_delay_max)) {
+       if (zio->io_delay >= MSEC2NSEC(zio_delay_max)) {
                if (zio->io_vd != NULL && !vdev_is_dead(zio->io_vd))
                        zfs_ereport_post(FM_EREPORT_ZFS_DELAY, zio->io_spa,
                            zio->io_vd, zio, 0, 0);
@@ -3311,13 +3842,15 @@ zio_done(zio_t *zio)
                 * trouble (e.g. suspended). This allows "The Godfather"
                 * I/O to return status without blocking.
                 */
-               for (pio = zio_walk_parents(zio); pio != NULL; pio = pio_next) {
-                       zio_link_t *zl = zio->io_walk_link;
-                       pio_next = zio_walk_parents(zio);
+               zl = NULL;
+               for (pio = zio_walk_parents(zio, &zl); pio != NULL;
+                   pio = pio_next) {
+                       zio_link_t *remove_zl = zl;
+                       pio_next = zio_walk_parents(zio, &zl);
 
                        if ((pio->io_flags & ZIO_FLAG_GODFATHER) &&
                            (zio->io_reexecute & ZIO_REEXECUTE_SUSPEND)) {
-                               zio_remove_child(pio, zio, zl);
+                               zio_remove_child(pio, zio, remove_zl);
                                zio_notify_parent(pio, zio, ZIO_WAIT_DONE);
                        }
                }
@@ -3384,10 +3917,11 @@ zio_done(zio_t *zio)
        zio->io_state[ZIO_WAIT_DONE] = 1;
        mutex_exit(&zio->io_lock);
 
-       for (pio = zio_walk_parents(zio); pio != NULL; pio = pio_next) {
-               zio_link_t *zl = zio->io_walk_link;
-               pio_next = zio_walk_parents(zio);
-               zio_remove_child(pio, zio, zl);
+       zl = NULL;
+       for (pio = zio_walk_parents(zio, &zl); pio != NULL; pio = pio_next) {
+               zio_link_t *remove_zl = zl;
+               pio_next = zio_walk_parents(zio, &zl);
+               zio_remove_child(pio, zio, remove_zl);
                zio_notify_parent(pio, zio, ZIO_WAIT_DONE);
        }
 
@@ -3411,9 +3945,10 @@ zio_done(zio_t *zio)
 static zio_pipe_stage_t *zio_pipeline[] = {
        NULL,
        zio_read_bp_init,
+       zio_write_bp_init,
        zio_free_bp_init,
        zio_issue_async,
-       zio_write_bp_init,
+       zio_write_compress,
        zio_checksum_generate,
        zio_nop_write,
        zio_ddt_read_start,
@@ -3422,6 +3957,7 @@ static zio_pipe_stage_t *zio_pipeline[] = {
        zio_ddt_free,
        zio_gang_assemble,
        zio_gang_issue,
+       zio_dva_throttle,
        zio_dva_allocate,
        zio_dva_free,
        zio_dva_claim,
@@ -3433,39 +3969,129 @@ static zio_pipe_stage_t *zio_pipeline[] = {
        zio_done
 };
 
-/* dnp is the dnode for zb1->zb_object */
-boolean_t
-zbookmark_is_before(const dnode_phys_t *dnp, const zbookmark_phys_t *zb1,
-    const zbookmark_phys_t *zb2)
-{
-       uint64_t zb1nextL0, zb2thisobj;
 
-       ASSERT(zb1->zb_objset == zb2->zb_objset);
-       ASSERT(zb2->zb_level == 0);
 
-       /* The objset_phys_t isn't before anything. */
-       if (dnp == NULL)
-               return (B_FALSE);
 
-       zb1nextL0 = (zb1->zb_blkid + 1) <<
-           ((zb1->zb_level) * (dnp->dn_indblkshift - SPA_BLKPTRSHIFT));
+/*
+ * Compare two zbookmark_phys_t's to see which we would reach first in a
+ * pre-order traversal of the object tree.
+ *
+ * This is simple in every case aside from the meta-dnode object. For all other
+ * objects, we traverse them in order (object 1 before object 2, and so on).
+ * However, all of these objects are traversed while traversing object 0, since
+ * the data it points to is the list of objects.  Thus, we need to convert to a
+ * canonical representation so we can compare meta-dnode bookmarks to
+ * non-meta-dnode bookmarks.
+ *
+ * We do this by calculating "equivalents" for each field of the zbookmark.
+ * zbookmarks outside of the meta-dnode use their own object and level, and
+ * calculate the level 0 equivalent (the first L0 blkid that is contained in the
+ * blocks this bookmark refers to) by multiplying their blkid by their span
+ * (the number of L0 blocks contained within one block at their level).
+ * zbookmarks inside the meta-dnode calculate their object equivalent
+ * (which is L0equiv * dnodes per data block), use 0 for their L0equiv, and use
+ * level + 1<<31 (any value larger than a level could ever be) for their level.
+ * This causes them to always compare before a bookmark in their object
+ * equivalent, compare appropriately to bookmarks in other objects, and to
+ * compare appropriately to other bookmarks in the meta-dnode.
+ */
+int
+zbookmark_compare(uint16_t dbss1, uint8_t ibs1, uint16_t dbss2, uint8_t ibs2,
+    const zbookmark_phys_t *zb1, const zbookmark_phys_t *zb2)
+{
+       /*
+        * These variables represent the "equivalent" values for the zbookmark,
+        * after converting zbookmarks inside the meta dnode to their
+        * normal-object equivalents.
+        */
+       uint64_t zb1obj, zb2obj;
+       uint64_t zb1L0, zb2L0;
+       uint64_t zb1level, zb2level;
+
+       if (zb1->zb_object == zb2->zb_object &&
+           zb1->zb_level == zb2->zb_level &&
+           zb1->zb_blkid == zb2->zb_blkid)
+               return (0);
 
-       zb2thisobj = zb2->zb_object ? zb2->zb_object :
-           zb2->zb_blkid << (DNODE_BLOCK_SHIFT - DNODE_SHIFT);
+       /*
+        * BP_SPANB calculates the span in blocks.
+        */
+       zb1L0 = (zb1->zb_blkid) * BP_SPANB(ibs1, zb1->zb_level);
+       zb2L0 = (zb2->zb_blkid) * BP_SPANB(ibs2, zb2->zb_level);
 
        if (zb1->zb_object == DMU_META_DNODE_OBJECT) {
-               uint64_t nextobj = zb1nextL0 *
-                   (dnp->dn_datablkszsec << SPA_MINBLOCKSHIFT) >> DNODE_SHIFT;
-               return (nextobj <= zb2thisobj);
+               zb1obj = zb1L0 * (dbss1 << (SPA_MINBLOCKSHIFT - DNODE_SHIFT));
+               zb1L0 = 0;
+               zb1level = zb1->zb_level + COMPARE_META_LEVEL;
+       } else {
+               zb1obj = zb1->zb_object;
+               zb1level = zb1->zb_level;
        }
 
-       if (zb1->zb_object < zb2thisobj)
-               return (B_TRUE);
-       if (zb1->zb_object > zb2thisobj)
-               return (B_FALSE);
-       if (zb2->zb_object == DMU_META_DNODE_OBJECT)
+       if (zb2->zb_object == DMU_META_DNODE_OBJECT) {
+               zb2obj = zb2L0 * (dbss2 << (SPA_MINBLOCKSHIFT - DNODE_SHIFT));
+               zb2L0 = 0;
+               zb2level = zb2->zb_level + COMPARE_META_LEVEL;
+       } else {
+               zb2obj = zb2->zb_object;
+               zb2level = zb2->zb_level;
+       }
+
+       /* Now that we have a canonical representation, do the comparison. */
+       if (zb1obj != zb2obj)
+               return (zb1obj < zb2obj ? -1 : 1);
+       else if (zb1L0 != zb2L0)
+               return (zb1L0 < zb2L0 ? -1 : 1);
+       else if (zb1level != zb2level)
+               return (zb1level > zb2level ? -1 : 1);
+       /*
+        * This can (theoretically) happen if the bookmarks have the same object
+        * and level, but different blkids, if the block sizes are not the same.
+        * There is presently no way to change the indirect block sizes
+        */
+       return (0);
+}
+
+/*
+ *  This function checks the following: given that last_block is the place that
+ *  our traversal stopped last time, does that guarantee that we've visited
+ *  every node under subtree_root?  Therefore, we can't just use the raw output
+ *  of zbookmark_compare.  We have to pass in a modified version of
+ *  subtree_root; by incrementing the block id, and then checking whether
+ *  last_block is before or equal to that, we can tell whether or not having
+ *  visited last_block implies that all of subtree_root's children have been
+ *  visited.
+ */
+boolean_t
+zbookmark_subtree_completed(const dnode_phys_t *dnp,
+    const zbookmark_phys_t *subtree_root, const zbookmark_phys_t *last_block)
+{
+       zbookmark_phys_t mod_zb = *subtree_root;
+       mod_zb.zb_blkid++;
+       ASSERT(last_block->zb_level == 0);
+
+       /* The objset_phys_t isn't before anything. */
+       if (dnp == NULL)
                return (B_FALSE);
-       return (zb1nextL0 <= zb2->zb_blkid);
+
+       /*
+        * We pass in 1ULL << (DNODE_BLOCK_SHIFT - SPA_MINBLOCKSHIFT) for the
+        * data block size in sectors, because that variable is only used if
+        * the bookmark refers to a block in the meta-dnode.  Since we don't
+        * know without examining it what object it refers to, and there's no
+        * harm in passing in this value in other cases, we always pass it in.
+        *
+        * We pass in 0 for the indirect block size shift because zb2 must be
+        * level 0.  The indirect block size is only used to calculate the span
+        * of the bookmark, but since the bookmark must be level 0, the span is
+        * always 1, so the math works out.
+        *
+        * If you make changes to how the zbookmark_compare code works, be sure
+        * to make sure that this code still works afterwards.
+        */
+       return (zbookmark_compare(dnp->dn_datablkszsec, dnp->dn_indblkshift,
+           1ULL << (DNODE_BLOCK_SHIFT - SPA_MINBLOCKSHIFT), 0, &mod_zb,
+           last_block) <= 0);
 }
 
 #if defined(_KERNEL) && defined(HAVE_SPL)
@@ -3493,4 +4119,8 @@ MODULE_PARM_DESC(zfs_sync_pass_dont_compress,
 module_param(zfs_sync_pass_rewrite, int, 0644);
 MODULE_PARM_DESC(zfs_sync_pass_rewrite,
        "Rewrite new bps starting in this pass");
+
+module_param(zio_dva_throttle_enabled, int, 0644);
+MODULE_PARM_DESC(zio_dva_throttle_enabled,
+       "Throttle block allocations in the ZIO pipeline");
 #endif
index 3a5c73a6a1e94cd7c9cb22ea95b703a44c3bf262..d3d2f05a803b4dd24c89c8dfe763fb36694e4604 100644 (file)
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2013 Saso Kiselkov. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
 #include <sys/spa.h>
+#include <sys/spa_impl.h>
 #include <sys/zio.h>
 #include <sys/zio_checksum.h>
 #include <sys/zil.h>
  * checksum function of the appropriate strength.  When reading a block,
  * we compare the expected checksum against the actual checksum, which we
  * compute via the checksum function specified by BP_GET_CHECKSUM(bp).
+ *
+ * SALTED CHECKSUMS
+ *
+ * To enable the use of less secure hash algorithms with dedup, we
+ * introduce the notion of salted checksums (MACs, really).  A salted
+ * checksum is fed both a random 256-bit value (the salt) and the data
+ * to be checksummed.  This salt is kept secret (stored on the pool, but
+ * never shown to the user).  Thus even if an attacker knew of collision
+ * weaknesses in the hash algorithm, they won't be able to mount a known
+ * plaintext attack on the DDT, since the actual hash value cannot be
+ * known ahead of time.  How the salt is used is algorithm-specific
+ * (some might simply prefix it to the data block, others might need to
+ * utilize a full-blown HMAC).  On disk the salt is stored in a ZAP
+ * object in the MOS (DMU_POOL_CHECKSUM_SALT).
+ *
+ * CONTEXT TEMPLATES
+ *
+ * Some hashing algorithms need to perform a substantial amount of
+ * initialization work (e.g. salted checksums above may need to pre-hash
+ * the salt) before being able to process data.  Performing this
+ * redundant work for each block would be wasteful, so we instead allow
+ * a checksum algorithm to do the work once (the first time it's used)
+ * and then keep this pre-initialized context as a template inside the
+ * spa_t (spa_cksum_tmpls).  If the zio_checksum_info_t contains
+ * non-NULL ci_tmpl_init and ci_tmpl_free callbacks, they are used to
+ * construct and destruct the pre-initialized checksum context.  The
+ * pre-initialized context is then reused during each checksum
+ * invocation and passed to the checksum function.
  */
 
 /*ARGSUSED*/
 static void
-zio_checksum_off(const void *buf, uint64_t size, zio_cksum_t *zcp)
+zio_checksum_off(const void *buf, uint64_t size,
+    const void *ctx_template, zio_cksum_t *zcp)
 {
        ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
 }
 
 zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = {
-       {{NULL,                 NULL},                  0, 0, 0, "inherit"},
-       {{NULL,                 NULL},                  0, 0, 0, "on"},
-       {{zio_checksum_off,     zio_checksum_off},      0, 0, 0, "off"},
-       {{zio_checksum_SHA256,  zio_checksum_SHA256},   1, 1, 0, "label"},
-       {{zio_checksum_SHA256,  zio_checksum_SHA256},   1, 1, 0, "gang_header"},
-       {{fletcher_2_native,    fletcher_2_byteswap},   0, 1, 0, "zilog"},
-       {{fletcher_2_native,    fletcher_2_byteswap},   0, 0, 0, "fletcher2"},
-       {{fletcher_4_native,    fletcher_4_byteswap},   1, 0, 0, "fletcher4"},
-       {{zio_checksum_SHA256,  zio_checksum_SHA256},   1, 0, 1, "sha256"},
-       {{fletcher_4_native,    fletcher_4_byteswap},   0, 1, 0, "zilog2"},
+       {{NULL, NULL}, NULL, NULL, 0, "inherit"},
+       {{NULL, NULL}, NULL, NULL, 0, "on"},
+       {{zio_checksum_off,             zio_checksum_off},
+           NULL, NULL, 0, "off"},
+       {{zio_checksum_SHA256,          zio_checksum_SHA256},
+           NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_EMBEDDED,
+           "label"},
+       {{zio_checksum_SHA256,          zio_checksum_SHA256},
+           NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_EMBEDDED,
+           "gang_header"},
+       {{fletcher_2_native,            fletcher_2_byteswap},
+           NULL, NULL, ZCHECKSUM_FLAG_EMBEDDED, "zilog"},
+       {{fletcher_2_native,            fletcher_2_byteswap},
+           NULL, NULL, 0, "fletcher2"},
+       {{fletcher_4_native,            fletcher_4_byteswap},
+           NULL, NULL, ZCHECKSUM_FLAG_METADATA, "fletcher4"},
+       {{zio_checksum_SHA256,          zio_checksum_SHA256},
+           NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
+           ZCHECKSUM_FLAG_NOPWRITE, "sha256"},
+       {{fletcher_4_native,            fletcher_4_byteswap},
+           NULL, NULL, ZCHECKSUM_FLAG_EMBEDDED, "zilog2"},
+       {{zio_checksum_off,             zio_checksum_off},
+           NULL, NULL, 0, "noparity"},
+       {{zio_checksum_SHA512_native,   zio_checksum_SHA512_byteswap},
+           NULL, NULL, ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
+           ZCHECKSUM_FLAG_NOPWRITE, "sha512"},
+       {{zio_checksum_skein_native,    zio_checksum_skein_byteswap},
+           zio_checksum_skein_tmpl_init, zio_checksum_skein_tmpl_free,
+           ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_DEDUP |
+           ZCHECKSUM_FLAG_SALTED | ZCHECKSUM_FLAG_NOPWRITE, "skein"},
+       {{zio_checksum_edonr_native,    zio_checksum_edonr_byteswap},
+           zio_checksum_edonr_tmpl_init, zio_checksum_edonr_tmpl_free,
+           ZCHECKSUM_FLAG_METADATA | ZCHECKSUM_FLAG_SALTED |
+           ZCHECKSUM_FLAG_NOPWRITE, "edonr"},
 };
 
+/*
+ * The flag corresponding to the "verify" in dedup=[checksum,]verify
+ * must be cleared first, so callers should use ZIO_CHECKSUM_MASK.
+ */
+spa_feature_t
+zio_checksum_to_feature(enum zio_checksum cksum)
+{
+       VERIFY((cksum & ~ZIO_CHECKSUM_MASK) == 0);
+
+       switch (cksum) {
+       case ZIO_CHECKSUM_SHA512:
+               return (SPA_FEATURE_SHA512);
+       case ZIO_CHECKSUM_SKEIN:
+               return (SPA_FEATURE_SKEIN);
+       case ZIO_CHECKSUM_EDONR:
+               return (SPA_FEATURE_EDONR);
+       default:
+               return (SPA_FEATURE_NONE);
+       }
+}
+
 enum zio_checksum
 zio_checksum_select(enum zio_checksum child, enum zio_checksum parent)
 {
@@ -113,7 +189,8 @@ zio_checksum_dedup_select(spa_t *spa, enum zio_checksum child,
        if (child == (ZIO_CHECKSUM_ON | ZIO_CHECKSUM_VERIFY))
                return (spa_dedup_checksum(spa) | ZIO_CHECKSUM_VERIFY);
 
-       ASSERT(zio_checksum_table[child & ZIO_CHECKSUM_MASK].ci_dedup ||
+       ASSERT((zio_checksum_table[child & ZIO_CHECKSUM_MASK].ci_flags &
+           ZCHECKSUM_FLAG_DEDUP) ||
            (child & ZIO_CHECKSUM_VERIFY) || child == ZIO_CHECKSUM_OFF);
 
        return (child);
@@ -145,6 +222,30 @@ zio_checksum_label_verifier(zio_cksum_t *zcp, uint64_t offset)
        ZIO_SET_CHECKSUM(zcp, offset, 0, 0, 0);
 }
 
+/*
+ * Calls the template init function of a checksum which supports context
+ * templates and installs the template into the spa_t.
+ */
+static void
+zio_checksum_template_init(enum zio_checksum checksum, spa_t *spa)
+{
+       zio_checksum_info_t *ci = &zio_checksum_table[checksum];
+
+       if (ci->ci_tmpl_init == NULL)
+               return;
+       if (spa->spa_cksum_tmpls[checksum] != NULL)
+               return;
+
+       VERIFY(ci->ci_tmpl_free != NULL);
+       mutex_enter(&spa->spa_cksum_tmpls_lock);
+       if (spa->spa_cksum_tmpls[checksum] == NULL) {
+               spa->spa_cksum_tmpls[checksum] =
+                   ci->ci_tmpl_init(&spa->spa_cksum_salt);
+               VERIFY(spa->spa_cksum_tmpls[checksum] != NULL);
+       }
+       mutex_exit(&spa->spa_cksum_tmpls_lock);
+}
+
 /*
  * Generate the checksum.
  */
@@ -156,11 +257,14 @@ zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
        uint64_t offset = zio->io_offset;
        zio_checksum_info_t *ci = &zio_checksum_table[checksum];
        zio_cksum_t cksum;
+       spa_t *spa = zio->io_spa;
 
        ASSERT((uint_t)checksum < ZIO_CHECKSUM_FUNCTIONS);
        ASSERT(ci->ci_func[0] != NULL);
 
-       if (ci->ci_eck) {
+       zio_checksum_template_init(checksum, spa);
+
+       if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) {
                zio_eck_t *eck;
 
                if (checksum == ZIO_CHECKSUM_ZILOG2) {
@@ -179,33 +283,31 @@ zio_checksum_compute(zio_t *zio, enum zio_checksum checksum,
                else
                        bp->blk_cksum = eck->zec_cksum;
                eck->zec_magic = ZEC_MAGIC;
-               ci->ci_func[0](data, size, &cksum);
+               ci->ci_func[0](data, size, spa->spa_cksum_tmpls[checksum],
+                   &cksum);
                eck->zec_cksum = cksum;
        } else {
-               ci->ci_func[0](data, size, &bp->blk_cksum);
+               ci->ci_func[0](data, size, spa->spa_cksum_tmpls[checksum],
+                   &bp->blk_cksum);
        }
 }
 
 int
-zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
+zio_checksum_error_impl(spa_t *spa, blkptr_t *bp, enum zio_checksum checksum,
+    void *data, uint64_t size, uint64_t offset, zio_bad_cksum_t *info)
 {
-       blkptr_t *bp = zio->io_bp;
-       uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
-           (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
-       int byteswap;
-       int error;
-       uint64_t size = (bp == NULL ? zio->io_size :
-           (BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp)));
-       uint64_t offset = zio->io_offset;
-       void *data = zio->io_data;
        zio_checksum_info_t *ci = &zio_checksum_table[checksum];
-       zio_cksum_t actual_cksum, expected_cksum, verifier;
+       int byteswap;
+       zio_cksum_t actual_cksum, expected_cksum;
 
        if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func[0] == NULL)
                return (SET_ERROR(EINVAL));
 
-       if (ci->ci_eck) {
+       zio_checksum_template_init(checksum, spa);
+
+       if (ci->ci_flags & ZCHECKSUM_FLAG_EMBEDDED) {
                zio_eck_t *eck;
+               zio_cksum_t verifier;
 
                if (checksum == ZIO_CHECKSUM_ZILOG2) {
                        zil_chain_t *zilc = data;
@@ -241,35 +343,77 @@ zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
 
                expected_cksum = eck->zec_cksum;
                eck->zec_cksum = verifier;
-               ci->ci_func[byteswap](data, size, &actual_cksum);
+               ci->ci_func[byteswap](data, size,
+                   spa->spa_cksum_tmpls[checksum], &actual_cksum);
                eck->zec_cksum = expected_cksum;
 
-               if (byteswap)
+               if (byteswap) {
                        byteswap_uint64_array(&expected_cksum,
                            sizeof (zio_cksum_t));
+               }
        } else {
-               ASSERT(!BP_IS_GANG(bp));
                byteswap = BP_SHOULD_BYTESWAP(bp);
                expected_cksum = bp->blk_cksum;
-               ci->ci_func[byteswap](data, size, &actual_cksum);
+               ci->ci_func[byteswap](data, size,
+                   spa->spa_cksum_tmpls[checksum], &actual_cksum);
        }
 
-       info->zbc_expected = expected_cksum;
-       info->zbc_actual = actual_cksum;
-       info->zbc_checksum_name = ci->ci_name;
-       info->zbc_byteswapped = byteswap;
-       info->zbc_injected = 0;
-       info->zbc_has_cksum = 1;
+       if (info != NULL) {
+               info->zbc_expected = expected_cksum;
+               info->zbc_actual = actual_cksum;
+               info->zbc_checksum_name = ci->ci_name;
+               info->zbc_byteswapped = byteswap;
+               info->zbc_injected = 0;
+               info->zbc_has_cksum = 1;
+       }
 
        if (!ZIO_CHECKSUM_EQUAL(actual_cksum, expected_cksum))
                return (SET_ERROR(ECKSUM));
 
-       if (zio_injection_enabled && !zio->io_error &&
+       return (0);
+}
+
+int
+zio_checksum_error(zio_t *zio, zio_bad_cksum_t *info)
+{
+       blkptr_t *bp = zio->io_bp;
+       uint_t checksum = (bp == NULL ? zio->io_prop.zp_checksum :
+           (BP_IS_GANG(bp) ? ZIO_CHECKSUM_GANG_HEADER : BP_GET_CHECKSUM(bp)));
+       int error;
+       uint64_t size = (bp == NULL ? zio->io_size :
+           (BP_IS_GANG(bp) ? SPA_GANGBLOCKSIZE : BP_GET_PSIZE(bp)));
+       uint64_t offset = zio->io_offset;
+       void *data = zio->io_data;
+       spa_t *spa = zio->io_spa;
+
+       error = zio_checksum_error_impl(spa, bp, checksum, data, size,
+           offset, info);
+       if (error != 0 && zio_injection_enabled && !zio->io_error &&
            (error = zio_handle_fault_injection(zio, ECKSUM)) != 0) {
 
                info->zbc_injected = 1;
                return (error);
        }
+       return (error);
+}
 
-       return (0);
+/*
+ * Called by a spa_t that's about to be deallocated. This steps through
+ * all of the checksum context templates and deallocates any that were
+ * initialized using the algorithm-specific template init function.
+ */
+void
+zio_checksum_templates_free(spa_t *spa)
+{
+       enum zio_checksum checksum;
+       for (checksum = 0; checksum < ZIO_CHECKSUM_FUNCTIONS;
+           checksum++) {
+               if (spa->spa_cksum_tmpls[checksum] != NULL) {
+                       zio_checksum_info_t *ci = &zio_checksum_table[checksum];
+
+                       VERIFY(ci->ci_tmpl_free != NULL);
+                       ci->ci_tmpl_free(spa->spa_cksum_tmpls[checksum]);
+                       spa->spa_cksum_tmpls[checksum] = NULL;
+               }
+       }
 }
index 40b507a0b6d83f3803c2cc07dfafd943312ad1e5..61b7d25e6536c230868742e7724b5f9e5d096353 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
  */
 
 /*
 
 uint32_t zio_injection_enabled = 0;
 
+/*
+ * Data describing each zinject handler registered on the system, and
+ * contains the list node linking the handler in the global zinject
+ * handler list.
+ */
 typedef struct inject_handler {
        int                     zi_id;
        spa_t                   *zi_spa;
        zinject_record_t        zi_record;
+       uint64_t                *zi_lanes;
+       int                     zi_next_lane;
        list_node_t             zi_link;
 } inject_handler_t;
 
+/*
+ * List of all zinject handlers registered on the system, protected by
+ * the inject_lock defined below.
+ */
 static list_t inject_handlers;
+
+/*
+ * This protects insertion into, and traversal of, the inject handler
+ * list defined above; as well as the inject_delay_count. Any time a
+ * handler is inserted or removed from the list, this lock should be
+ * taken as a RW_WRITER; and any time traversal is done over the list
+ * (without modification to it) this lock should be taken as a RW_READER.
+ */
 static krwlock_t inject_lock;
+
+/*
+ * This holds the number of zinject delay handlers that have been
+ * registered on the system. It is protected by the inject_lock defined
+ * above. Thus modifications to this count must be a RW_WRITER of the
+ * inject_lock, and reads of this count must be (at least) a RW_READER
+ * of the lock.
+ */
+static int inject_delay_count = 0;
+
+/*
+ * This lock is used only in zio_handle_io_delay(), refer to the comment
+ * in that function for more details.
+ */
+static kmutex_t inject_delay_mtx;
+
+/*
+ * Used to assign unique identifying numbers to each new zinject handler.
+ */
 static int inject_next_id = 1;
 
 /*
@@ -361,32 +399,173 @@ spa_handle_ignored_writes(spa_t *spa)
        rw_exit(&inject_lock);
 }
 
-uint64_t
+hrtime_t
 zio_handle_io_delay(zio_t *zio)
 {
        vdev_t *vd = zio->io_vd;
+       inject_handler_t *min_handler = NULL;
+       hrtime_t min_target = 0;
        inject_handler_t *handler;
-       uint64_t seconds = 0;
-
-       if (zio_injection_enabled == 0)
-               return (0);
+       hrtime_t idle;
+       hrtime_t busy;
+       hrtime_t target;
 
        rw_enter(&inject_lock, RW_READER);
 
-       for (handler = list_head(&inject_handlers); handler != NULL;
-           handler = list_next(&inject_handlers, handler)) {
+       /*
+        * inject_delay_count is a subset of zio_injection_enabled that
+        * is only incremented for delay handlers. These checks are
+        * mainly added to remind the reader why we're not explicitly
+        * checking zio_injection_enabled like the other functions.
+        */
+       IMPLY(inject_delay_count > 0, zio_injection_enabled > 0);
+       IMPLY(zio_injection_enabled == 0, inject_delay_count == 0);
 
+       /*
+        * If there aren't any inject delay handlers registered, then we
+        * can short circuit and simply return 0 here. A value of zero
+        * informs zio_delay_interrupt() that this request should not be
+        * delayed. This short circuit keeps us from acquiring the
+        * inject_delay_mutex unnecessarily.
+        */
+       if (inject_delay_count == 0) {
+               rw_exit(&inject_lock);
+               return (0);
+       }
+
+       /*
+        * Each inject handler has a number of "lanes" associated with
+        * it. Each lane is able to handle requests independently of one
+        * another, and at a latency defined by the inject handler
+        * record's zi_timer field. Thus if a handler in configured with
+        * a single lane with a 10ms latency, it will delay requests
+        * such that only a single request is completed every 10ms. So,
+        * if more than one request is attempted per each 10ms interval,
+        * the average latency of the requests will be greater than
+        * 10ms; but if only a single request is submitted each 10ms
+        * interval the average latency will be 10ms.
+        *
+        * We need to acquire this mutex to prevent multiple concurrent
+        * threads being assigned to the same lane of a given inject
+        * handler. The mutex allows us to perform the following two
+        * operations atomically:
+        *
+        *      1. determine the minimum handler and minimum target
+        *         value of all the possible handlers
+        *      2. update that minimum handler's lane array
+        *
+        * Without atomicity, two (or more) threads could pick the same
+        * lane in step (1), and then conflict with each other in step
+        * (2). This could allow a single lane handler to process
+        * multiple requests simultaneously, which shouldn't be possible.
+        */
+       mutex_enter(&inject_delay_mtx);
+
+       for (handler = list_head(&inject_handlers);
+           handler != NULL; handler = list_next(&inject_handlers, handler)) {
                if (handler->zi_record.zi_cmd != ZINJECT_DELAY_IO)
                        continue;
 
-               if (vd->vdev_guid == handler->zi_record.zi_guid) {
-                       seconds = handler->zi_record.zi_timer;
-                       break;
+               if (handler->zi_record.zi_freq != 0 &&
+                   spa_get_random(100) >= handler->zi_record.zi_freq) {
+                       continue;
                }
 
+               if (vd->vdev_guid != handler->zi_record.zi_guid)
+                       continue;
+
+               /*
+                * Defensive; should never happen as the array allocation
+                * occurs prior to inserting this handler on the list.
+                */
+               ASSERT3P(handler->zi_lanes, !=, NULL);
+
+               /*
+                * This should never happen, the zinject command should
+                * prevent a user from setting an IO delay with zero lanes.
+                */
+               ASSERT3U(handler->zi_record.zi_nlanes, !=, 0);
+
+               ASSERT3U(handler->zi_record.zi_nlanes, >,
+                   handler->zi_next_lane);
+
+               /*
+                * We want to issue this IO to the lane that will become
+                * idle the soonest, so we compare the soonest this
+                * specific handler can complete the IO with all other
+                * handlers, to find the lowest value of all possible
+                * lanes. We then use this lane to submit the request.
+                *
+                * Since each handler has a constant value for its
+                * delay, we can just use the "next" lane for that
+                * handler; as it will always be the lane with the
+                * lowest value for that particular handler (i.e. the
+                * lane that will become idle the soonest). This saves a
+                * scan of each handler's lanes array.
+                *
+                * There's two cases to consider when determining when
+                * this specific IO request should complete. If this
+                * lane is idle, we want to "submit" the request now so
+                * it will complete after zi_timer milliseconds. Thus,
+                * we set the target to now + zi_timer.
+                *
+                * If the lane is busy, we want this request to complete
+                * zi_timer milliseconds after the lane becomes idle.
+                * Since the 'zi_lanes' array holds the time at which
+                * each lane will become idle, we use that value to
+                * determine when this request should complete.
+                */
+               idle = handler->zi_record.zi_timer + gethrtime();
+               busy = handler->zi_record.zi_timer +
+                   handler->zi_lanes[handler->zi_next_lane];
+               target = MAX(idle, busy);
+
+               if (min_handler == NULL) {
+                       min_handler = handler;
+                       min_target = target;
+                       continue;
+               }
+
+               ASSERT3P(min_handler, !=, NULL);
+               ASSERT3U(min_target, !=, 0);
+
+               /*
+                * We don't yet increment the "next lane" variable since
+                * we still might find a lower value lane in another
+                * handler during any remaining iterations. Once we're
+                * sure we've selected the absolute minimum, we'll claim
+                * the lane and increment the handler's "next lane"
+                * field below.
+                */
+
+               if (target < min_target) {
+                       min_handler = handler;
+                       min_target = target;
+               }
+       }
+
+       /*
+        * 'min_handler' will be NULL if no IO delays are registered for
+        * this vdev, otherwise it will point to the handler containing
+        * the lane that will become idle the soonest.
+        */
+       if (min_handler != NULL) {
+               ASSERT3U(min_target, !=, 0);
+               min_handler->zi_lanes[min_handler->zi_next_lane] = min_target;
+
+               /*
+                * If we've used all possible lanes for this handler,
+                * loop back and start using the first lane again;
+                * otherwise, just increment the lane index.
+                */
+               min_handler->zi_next_lane = (min_handler->zi_next_lane + 1) %
+                   min_handler->zi_record.zi_nlanes;
        }
+
+       mutex_exit(&inject_delay_mtx);
        rw_exit(&inject_lock);
-       return (seconds);
+
+       return (min_target);
 }
 
 /*
@@ -410,6 +589,24 @@ zio_inject_fault(char *name, int flags, int *id, zinject_record_t *record)
                if ((error = spa_reset(name)) != 0)
                        return (error);
 
+       if (record->zi_cmd == ZINJECT_DELAY_IO) {
+               /*
+                * A value of zero for the number of lanes or for the
+                * delay time doesn't make sense.
+                */
+               if (record->zi_timer == 0 || record->zi_nlanes == 0)
+                       return (SET_ERROR(EINVAL));
+
+               /*
+                * The number of lanes is directly mapped to the size of
+                * an array used by the handler. Thus, to ensure the
+                * user doesn't trigger an allocation that's "too large"
+                * we cap the number of lanes here.
+                */
+               if (record->zi_nlanes >= UINT16_MAX)
+                       return (SET_ERROR(EINVAL));
+       }
+
        if (!(flags & ZINJECT_NULL)) {
                /*
                 * spa_inject_ref() will add an injection reference, which will
@@ -421,13 +618,36 @@ zio_inject_fault(char *name, int flags, int *id, zinject_record_t *record)
 
                handler = kmem_alloc(sizeof (inject_handler_t), KM_SLEEP);
 
+               handler->zi_spa = spa;
+               handler->zi_record = *record;
+
+               if (handler->zi_record.zi_cmd == ZINJECT_DELAY_IO) {
+                       handler->zi_lanes = kmem_zalloc(
+                           sizeof (*handler->zi_lanes) *
+                           handler->zi_record.zi_nlanes, KM_SLEEP);
+                       handler->zi_next_lane = 0;
+               } else {
+                       handler->zi_lanes = NULL;
+                       handler->zi_next_lane = 0;
+               }
+
                rw_enter(&inject_lock, RW_WRITER);
 
+               /*
+                * We can't move this increment into the conditional
+                * above because we need to hold the RW_WRITER lock of
+                * inject_lock, and we don't want to hold that while
+                * allocating the handler's zi_lanes array.
+                */
+               if (handler->zi_record.zi_cmd == ZINJECT_DELAY_IO) {
+                       ASSERT3S(inject_delay_count, >=, 0);
+                       inject_delay_count++;
+                       ASSERT3S(inject_delay_count, >, 0);
+               }
+
                *id = handler->zi_id = inject_next_id++;
-               handler->zi_spa = spa;
-               handler->zi_record = *record;
                list_insert_tail(&inject_handlers, handler);
-               atomic_add_32(&zio_injection_enabled, 1);
+               atomic_inc_32(&zio_injection_enabled);
 
                rw_exit(&inject_lock);
        }
@@ -503,12 +723,26 @@ zio_clear_fault(int id)
                return (SET_ERROR(ENOENT));
        }
 
+       if (handler->zi_record.zi_cmd == ZINJECT_DELAY_IO) {
+               ASSERT3S(inject_delay_count, >, 0);
+               inject_delay_count--;
+               ASSERT3S(inject_delay_count, >=, 0);
+       }
+
        list_remove(&inject_handlers, handler);
        rw_exit(&inject_lock);
 
+       if (handler->zi_record.zi_cmd == ZINJECT_DELAY_IO) {
+               ASSERT3P(handler->zi_lanes, !=, NULL);
+               kmem_free(handler->zi_lanes, sizeof (*handler->zi_lanes) *
+                   handler->zi_record.zi_nlanes);
+       } else {
+               ASSERT3P(handler->zi_lanes, ==, NULL);
+       }
+
        spa_inject_delref(handler->zi_spa);
        kmem_free(handler, sizeof (inject_handler_t));
-       atomic_add_32(&zio_injection_enabled, -1);
+       atomic_dec_32(&zio_injection_enabled);
 
        return (0);
 }
@@ -517,6 +751,7 @@ void
 zio_inject_init(void)
 {
        rw_init(&inject_lock, NULL, RW_DEFAULT, NULL);
+       mutex_init(&inject_delay_mtx, NULL, MUTEX_DEFAULT, NULL);
        list_create(&inject_handlers, sizeof (inject_handler_t),
            offsetof(inject_handler_t, zi_link));
 }
@@ -525,6 +760,7 @@ void
 zio_inject_fini(void)
 {
        list_destroy(&inject_handlers);
+       mutex_destroy(&inject_delay_mtx);
        rw_destroy(&inject_lock);
 }
 
index 069834eae662eca2e3976ea961f75b82ebe2ceee..cdd6668b1dc008a0be1e67fd1a6245448acf7947 100644 (file)
@@ -52,7 +52,7 @@ zpl_common_open(struct inode *ip, struct file *filp)
 static int
 zpl_root_iterate(struct file *filp, struct dir_context *ctx)
 {
-       zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
+       zfs_sb_t *zsb = ITOZSB(file_inode(filp));
        int error = 0;
 
        ZFS_ENTER(zsb);
@@ -249,7 +249,7 @@ zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
 static int
 zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx)
 {
-       zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
+       zfs_sb_t *zsb = ITOZSB(file_inode(filp));
        fstrans_cookie_t cookie;
        char snapname[MAXNAMELEN];
        boolean_t case_conflict;
@@ -301,13 +301,17 @@ zpl_snapdir_readdir(struct file *filp, void *dirent, filldir_t filldir)
 }
 #endif /* HAVE_VFS_ITERATE */
 
-int
-zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry,
-    struct inode *tdip, struct dentry *tdentry)
+static int
+zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry,
+    struct inode *tdip, struct dentry *tdentry, unsigned int flags)
 {
        cred_t *cr = CRED();
        int error;
 
+       /* We probably don't want to support renameat2(2) in ctldir */
+       if (flags)
+               return (-EINVAL);
+
        crhold(cr);
        error = -zfsctl_snapdir_rename(sdip, dname(sdentry),
            tdip, dname(tdentry), cr, 0);
@@ -317,6 +321,15 @@ zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry,
        return (error);
 }
 
+#ifndef HAVE_RENAME_WANTS_FLAGS
+static int
+zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry,
+    struct inode *tdip, struct dentry *tdentry)
+{
+       return (zpl_snapdir_rename2(sdip, sdentry, tdip, tdentry, 0));
+}
+#endif
+
 static int
 zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry)
 {
@@ -405,7 +418,11 @@ const struct file_operations zpl_fops_snapdir = {
 const struct inode_operations zpl_ops_snapdir = {
        .lookup         = zpl_snapdir_lookup,
        .getattr        = zpl_snapdir_getattr,
+#ifdef HAVE_RENAME_WANTS_FLAGS
+       .rename         = zpl_snapdir_rename2,
+#else
        .rename         = zpl_snapdir_rename,
+#endif
        .rmdir          = zpl_snapdir_rmdir,
        .mkdir          = zpl_snapdir_mkdir,
 };
@@ -447,7 +464,7 @@ zpl_shares_iterate(struct file *filp, struct dir_context *ctx)
 {
        fstrans_cookie_t cookie;
        cred_t *cr = CRED();
-       zfs_sb_t *zsb = ITOZSB(filp->f_path.dentry->d_inode);
+       zfs_sb_t *zsb = ITOZSB(file_inode(filp));
        znode_t *dzp;
        int error = 0;
 
index a629b59dc996adf212e333a7e130bddbced01a89..2c84d700d6d1e636a633dcaf094dfe20906af92e 100644 (file)
@@ -78,14 +78,13 @@ zpl_release(struct inode *ip, struct file *filp)
 static int
 zpl_iterate(struct file *filp, struct dir_context *ctx)
 {
-       struct dentry *dentry = filp->f_path.dentry;
        cred_t *cr = CRED();
        int error;
        fstrans_cookie_t cookie;
 
        crhold(cr);
        cookie = spl_fstrans_mark();
-       error = -zfs_readdir(dentry->d_inode, ctx, cr);
+       error = -zfs_readdir(file_inode(filp), ctx, cr);
        spl_fstrans_unmark(cookie);
        crfree(cr);
        ASSERT3S(error, <=, 0);
@@ -135,7 +134,7 @@ static int
 zpl_aio_fsync(struct kiocb *kiocb, int datasync)
 {
        struct file *filp = kiocb->ki_filp;
-       return (zpl_fsync(filp, filp->f_path.dentry, datasync));
+       return (zpl_fsync(filp, file_dentry(filp), datasync));
 }
 #elif defined(HAVE_FSYNC_WITHOUT_DENTRY)
 /*
@@ -261,6 +260,7 @@ zpl_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
            UIO_USERSPACE, filp->f_flags, cr);
        crfree(cr);
 
+       file_accessed(filp);
        return (read);
 }
 
@@ -277,6 +277,7 @@ zpl_iter_read_common(struct kiocb *kiocb, const struct iovec *iovp,
            nr_segs, &kiocb->ki_pos, seg, filp->f_flags, cr, skip);
        crfree(cr);
 
+       file_accessed(filp);
        return (read);
 }
 
@@ -649,8 +650,6 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
        if (mode != (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
                return (error);
 
-       crhold(cr);
-
        if (offset < 0 || len <= 0)
                return (-EINVAL);
 
@@ -669,6 +668,7 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
        bf.l_len = len;
        bf.l_pid = 0;
 
+       crhold(cr);
        cookie = spl_fstrans_mark();
        error = -zfs_space(ip, F_FREESP, &bf, FWRITE, offset, cr);
        spl_fstrans_unmark(cookie);
@@ -686,7 +686,7 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
 static long
 zpl_fallocate(struct file *filp, int mode, loff_t offset, loff_t len)
 {
-       return zpl_fallocate_common(filp->f_path.dentry->d_inode,
+       return zpl_fallocate_common(file_inode(filp),
            mode, offset, len);
 }
 #endif /* HAVE_FILE_FALLOCATE */
index cbdab7d3003b9ad93c9bbfe0b384b74b1a9717a0..b8adda7a1b1b8cf7fa21f395fa1d605b78860911 100644 (file)
@@ -50,7 +50,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
        int zfs_flags = 0;
        zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
 
-       if (dlen(dentry) > ZFS_MAXNAMELEN)
+       if (dlen(dentry) > ZFS_MAX_DATASET_NAME_LEN)
                return (ERR_PTR(-ENAMETOOLONG));
 
        crhold(cr);
@@ -59,8 +59,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
        /* If we are a case insensitive fs, we need the real name */
        if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
                zfs_flags = FIGNORECASE;
-               pn.pn_bufsize = ZFS_MAXNAMELEN;
-               pn.pn_buf = kmem_zalloc(ZFS_MAXNAMELEN, KM_SLEEP);
+               pn_alloc(&pn);
                ppn = &pn;
        }
 
@@ -83,7 +82,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
                 * Fall through if the error is not ENOENT. Also free memory.
                 */
                if (ppn) {
-                       kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
+                       pn_free(ppn);
                        if (error == -ENOENT)
                                return (NULL);
                }
@@ -102,10 +101,14 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
                struct dentry *new_dentry;
                struct qstr ci_name;
 
-               ci_name.name = pn.pn_buf;
-               ci_name.len = strlen(pn.pn_buf);
-               new_dentry = d_add_ci(dentry, ip, &ci_name);
-               kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
+               if (strcmp(dname(dentry), pn.pn_buf) == 0) {
+                       new_dentry = d_splice_alias(ip,  dentry);
+               } else {
+                       ci_name.name = pn.pn_buf;
+                       ci_name.len = strlen(pn.pn_buf);
+                       new_dentry = d_add_ci(dentry, ip, &ci_name);
+               }
+               pn_free(ppn);
                return (new_dentry);
        } else {
                return (d_splice_alias(ip, dentry));
@@ -157,7 +160,7 @@ zpl_create(struct inode *dir, struct dentry *dentry, zpl_umode_t mode,
                        error = zpl_init_acl(ip, dir);
 
                if (error)
-                       (void) zfs_remove(dir, dname(dentry), cr);
+                       (void) zfs_remove(dir, dname(dentry), cr, 0);
        }
 
        spl_fstrans_unmark(cookie);
@@ -200,7 +203,7 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, zpl_umode_t mode,
                        error = zpl_init_acl(ip, dir);
 
                if (error)
-                       (void) zfs_remove(dir, dname(dentry), cr);
+                       (void) zfs_remove(dir, dname(dentry), cr, 0);
        }
 
        spl_fstrans_unmark(cookie);
@@ -221,7 +224,7 @@ zpl_unlink(struct inode *dir, struct dentry *dentry)
 
        crhold(cr);
        cookie = spl_fstrans_mark();
-       error = -zfs_remove(dir, dname(dentry), cr);
+       error = -zfs_remove(dir, dname(dentry), cr, 0);
 
        /*
         * For a CI FS we must invalidate the dentry to prevent the
@@ -320,7 +323,7 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia)
        int error;
        fstrans_cookie_t cookie;
 
-       error = inode_change_ok(ip, ia);
+       error = setattr_prepare(dentry, ia);
        if (error)
                return (error);
 
@@ -335,6 +338,10 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia)
        vap->va_mtime = ia->ia_mtime;
        vap->va_ctime = ia->ia_ctime;
 
+       if (vap->va_mask & ATTR_ATIME)
+               ip->i_atime = timespec_trunc(ia->ia_atime,
+                               ip->i_sb->s_time_gran);
+
        cookie = spl_fstrans_mark();
        error = -zfs_setattr(ip, vap, 0, cr);
        if (!error && (ia->ia_valid & ATTR_MODE))
@@ -349,13 +356,17 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia)
 }
 
 static int
-zpl_rename(struct inode *sdip, struct dentry *sdentry,
-    struct inode *tdip, struct dentry *tdentry)
+zpl_rename2(struct inode *sdip, struct dentry *sdentry,
+    struct inode *tdip, struct dentry *tdentry, unsigned int flags)
 {
        cred_t *cr = CRED();
        int error;
        fstrans_cookie_t cookie;
 
+       /* We don't have renameat2(2) support */
+       if (flags)
+               return (-EINVAL);
+
        crhold(cr);
        cookie = spl_fstrans_mark();
        error = -zfs_rename(sdip, dname(sdentry), tdip, dname(tdentry), cr, 0);
@@ -366,6 +377,15 @@ zpl_rename(struct inode *sdip, struct dentry *sdentry,
        return (error);
 }
 
+#ifndef HAVE_RENAME_WANTS_FLAGS
+static int
+zpl_rename(struct inode *sdip, struct dentry *sdentry,
+    struct inode *tdip, struct dentry *tdentry)
+{
+       return (zpl_rename2(sdip, sdentry, tdip, tdentry, 0));
+}
+#endif
+
 static int
 zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name)
 {
@@ -386,7 +406,7 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name)
 
                error = zpl_xattr_security_init(ip, dir, &dentry->d_name);
                if (error)
-                       (void) zfs_remove(dir, dname(dentry), cr);
+                       (void) zfs_remove(dir, dname(dentry), cr, 0);
        }
 
        spl_fstrans_unmark(cookie);
@@ -534,7 +554,7 @@ zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
        igrab(ip); /* Use ihold() if available */
 
        cookie = spl_fstrans_mark();
-       error = -zfs_link(dir, ip, dname(dentry), cr);
+       error = -zfs_link(dir, ip, dname(dentry), cr, 0);
        if (error) {
                iput(ip);
                goto out;
@@ -642,19 +662,13 @@ zpl_revalidate(struct dentry *dentry, unsigned int flags)
 }
 
 const struct inode_operations zpl_inode_operations = {
-       .create         = zpl_create,
-       .link           = zpl_link,
-       .unlink         = zpl_unlink,
-       .symlink        = zpl_symlink,
-       .mkdir          = zpl_mkdir,
-       .rmdir          = zpl_rmdir,
-       .mknod          = zpl_mknod,
-       .rename         = zpl_rename,
        .setattr        = zpl_setattr,
        .getattr        = zpl_getattr,
+#ifdef HAVE_GENERIC_SETXATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .removexattr    = generic_removexattr,
+#endif
        .listxattr      = zpl_xattr_list,
 #ifdef HAVE_INODE_TRUNCATE_RANGE
        .truncate_range = zpl_truncate_range,
@@ -682,12 +696,18 @@ const struct inode_operations zpl_dir_inode_operations = {
        .mkdir          = zpl_mkdir,
        .rmdir          = zpl_rmdir,
        .mknod          = zpl_mknod,
+#ifdef HAVE_RENAME_WANTS_FLAGS
+       .rename         = zpl_rename2,
+#else
        .rename         = zpl_rename,
+#endif
        .setattr        = zpl_setattr,
        .getattr        = zpl_getattr,
+#ifdef HAVE_GENERIC_SETXATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .removexattr    = generic_removexattr,
+#endif
        .listxattr      = zpl_xattr_list,
 #if defined(CONFIG_FS_POSIX_ACL)
 #if defined(HAVE_GET_ACL)
@@ -712,18 +732,22 @@ const struct inode_operations zpl_symlink_inode_operations = {
 #endif
        .setattr        = zpl_setattr,
        .getattr        = zpl_getattr,
+#ifdef HAVE_GENERIC_SETXATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .removexattr    = generic_removexattr,
+#endif
        .listxattr      = zpl_xattr_list,
 };
 
 const struct inode_operations zpl_special_inode_operations = {
        .setattr        = zpl_setattr,
        .getattr        = zpl_getattr,
+#ifdef HAVE_GENERIC_SETXATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
        .removexattr    = generic_removexattr,
+#endif
        .listxattr      = zpl_xattr_list,
 #if defined(CONFIG_FS_POSIX_ACL)
 #if defined(HAVE_GET_ACL)
index f14dd1a5251d067ec3cfadefb114c8a7ce72f2e0..471cb16c67ef8af06cac20c15ac0642d05566a66 100644 (file)
@@ -465,7 +465,7 @@ zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value,
        /* Remove a specific name xattr when value is set to NULL. */
        if (value == NULL) {
                if (xip)
-                       error = -zfs_remove(dxip, (char *)name, cr);
+                       error = -zfs_remove(dxip, (char *)name, cr, 0);
 
                goto out;
        }
index 04f68b5f8b70d571f458f7c6ecfb322fc29b7f02..72a6bc5e24bb64ede1cfc1d2e2b471628d7c4d83 100644 (file)
@@ -34,6 +34,7 @@
  * Volumes are persistent through reboot and module load.  No user command
  * needs to be run before opening and using a device.
  *
+ * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
@@ -60,7 +61,7 @@ unsigned long zvol_max_discard_blocks = 16384;
 
 static kmutex_t zvol_state_lock;
 static list_t zvol_state_list;
-static char *zvol_tag = "zvol_tag";
+void *zvol_tag = "zvol_tag";
 
 /*
  * The in-core state of each volume.
@@ -79,7 +80,6 @@ typedef struct zvol_state {
        dev_t                   zv_dev;         /* device id */
        struct gendisk          *zv_disk;       /* generic disk */
        struct request_queue    *zv_queue;      /* request queue */
-       spinlock_t              zv_lock;        /* request queue lock */
        list_node_t             zv_next;        /* next zvol_state_t linkage */
 } zvol_state_t;
 
@@ -174,7 +174,7 @@ zvol_is_zvol(const char *device)
        struct block_device *bdev;
        unsigned int major;
 
-       bdev = lookup_bdev(device);
+       bdev = vdev_lookup_bdev(device);
        if (IS_ERR(bdev))
                return (B_FALSE);
 
@@ -261,19 +261,9 @@ zvol_size_changed(zvol_state_t *zv, uint64_t volsize)
        bdev = bdget_disk(zv->zv_disk, 0);
        if (bdev == NULL)
                return;
-/*
- * 2.6.28 API change
- * Added check_disk_size_change() helper function.
- */
-#ifdef HAVE_CHECK_DISK_SIZE_CHANGE
        set_capacity(zv->zv_disk, volsize >> 9);
        zv->zv_volsize = volsize;
        check_disk_size_change(zv->zv_disk, bdev);
-#else
-       zv->zv_volsize = volsize;
-       zv->zv_changed = 1;
-       (void) check_disk_change(bdev);
-#endif /* HAVE_CHECK_DISK_SIZE_CHANGE */
 
        bdput(bdev);
 }
@@ -305,21 +295,26 @@ zvol_update_volsize(uint64_t volsize, objset_t *os)
 {
        dmu_tx_t *tx;
        int error;
+       uint64_t txg;
 
        ASSERT(MUTEX_HELD(&zvol_state_lock));
 
        tx = dmu_tx_create(os);
        dmu_tx_hold_zap(tx, ZVOL_ZAP_OBJ, TRUE, NULL);
+       dmu_tx_mark_netfree(tx);
        error = dmu_tx_assign(tx, TXG_WAIT);
        if (error) {
                dmu_tx_abort(tx);
                return (SET_ERROR(error));
        }
+       txg = dmu_tx_get_txg(tx);
 
        error = zap_update(os, ZVOL_ZAP_OBJ, "size", 8, 1,
            &volsize, tx);
        dmu_tx_commit(tx);
 
+       txg_wait_synced(dmu_objset_pool(os), txg);
+
        if (error == 0)
                error = dmu_free_long_range(os,
                    ZVOL_OBJ, volsize, DMU_OBJECT_END);
@@ -478,6 +473,24 @@ out:
        return (SET_ERROR(error));
 }
 
+/*
+ * Replay a TX_TRUNCATE ZIL transaction if asked.  TX_TRUNCATE is how we
+ * implement DKIOCFREE/free-long-range.
+ */
+static int
+zvol_replay_truncate(zvol_state_t *zv, lr_truncate_t *lr, boolean_t byteswap)
+{
+       uint64_t offset, length;
+
+       if (byteswap)
+               byteswap_uint64_array(lr, sizeof (*lr));
+
+       offset = lr->lr_offset;
+       length = lr->lr_length;
+
+       return (dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, offset, length));
+}
+
 /*
  * Replay a TX_WRITE ZIL transaction that didn't get committed
  * after a system failure
@@ -516,7 +529,7 @@ zvol_replay_err(zvol_state_t *zv, lr_t *lr, boolean_t byteswap)
 
 /*
  * Callback vectors for replaying records.
- * Only TX_WRITE is needed for zvol.
+ * Only TX_WRITE and TX_TRUNCATE are needed for zvol.
  */
 zil_replay_func_t zvol_replay_vector[TX_MAX_TYPE] = {
        (zil_replay_func_t)zvol_replay_err,     /* no such transaction type */
@@ -529,7 +542,7 @@ zil_replay_func_t zvol_replay_vector[TX_MAX_TYPE] = {
        (zil_replay_func_t)zvol_replay_err,     /* TX_LINK */
        (zil_replay_func_t)zvol_replay_err,     /* TX_RENAME */
        (zil_replay_func_t)zvol_replay_write,   /* TX_WRITE */
-       (zil_replay_func_t)zvol_replay_err,     /* TX_TRUNCATE */
+       (zil_replay_func_t)zvol_replay_truncate, /* TX_TRUNCATE */
        (zil_replay_func_t)zvol_replay_err,     /* TX_SETATTR */
        (zil_replay_func_t)zvol_replay_err,     /* TX_ACL */
 };
@@ -612,53 +625,69 @@ zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, uint64_t offset,
 }
 
 static int
-zvol_write(struct bio *bio)
+zvol_write(zvol_state_t *zv, uio_t *uio, boolean_t sync)
 {
-       zvol_state_t *zv = bio->bi_bdev->bd_disk->private_data;
-       uint64_t offset = BIO_BI_SECTOR(bio) << 9;
-       uint64_t size = BIO_BI_SIZE(bio);
-       int error = 0;
-       dmu_tx_t *tx;
+       uint64_t volsize = zv->zv_volsize;
        rl_t *rl;
+       int error = 0;
 
        ASSERT(zv && zv->zv_open_count > 0);
 
-       if (bio_is_flush(bio))
-               zil_commit(zv->zv_zilog, ZVOL_OBJ);
+       rl = zfs_range_lock(&zv->zv_range_lock, uio->uio_loffset,
+           uio->uio_resid, RL_WRITER);
 
-       /*
-        * Some requests are just for flush and nothing else.
-        */
-       if (size == 0)
-               goto out;
+       while (uio->uio_resid > 0 && uio->uio_loffset < volsize) {
+               uint64_t bytes = MIN(uio->uio_resid, DMU_MAX_ACCESS >> 1);
+               uint64_t off = uio->uio_loffset;
+               dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
 
-       rl = zfs_range_lock(&zv->zv_range_lock, offset, size, RL_WRITER);
+               if (bytes > volsize - off)      /* don't write past the end */
+                       bytes = volsize - off;
 
-       tx = dmu_tx_create(zv->zv_objset);
-       dmu_tx_hold_write(tx, ZVOL_OBJ, offset, size);
+               dmu_tx_hold_write(tx, ZVOL_OBJ, off, bytes);
 
-       /* This will only fail for ENOSPC */
-       error = dmu_tx_assign(tx, TXG_WAIT);
-       if (error) {
-               dmu_tx_abort(tx);
-               zfs_range_unlock(rl);
-               goto out;
+               /* This will only fail for ENOSPC */
+               error = dmu_tx_assign(tx, TXG_WAIT);
+               if (error) {
+                       dmu_tx_abort(tx);
+                       break;
+               }
+               error = dmu_write_uio_dbuf(zv->zv_dbuf, uio, bytes, tx);
+               if (error == 0)
+                       zvol_log_write(zv, tx, off, bytes, sync);
+               dmu_tx_commit(tx);
+
+               if (error)
+                       break;
        }
+       zfs_range_unlock(rl);
+       if (sync)
+               zil_commit(zv->zv_zilog, ZVOL_OBJ);
+       return (error);
+}
 
-       error = dmu_write_bio(zv->zv_objset, ZVOL_OBJ, bio, tx);
-       if (error == 0)
-               zvol_log_write(zv, tx, offset, size,
-                   !!(bio_is_fua(bio)));
+/*
+ * Log a DKIOCFREE/free-long-range to the ZIL with TX_TRUNCATE.
+ */
+static void
+zvol_log_truncate(zvol_state_t *zv, dmu_tx_t *tx, uint64_t off, uint64_t len,
+    boolean_t sync)
+{
+       itx_t *itx;
+       lr_truncate_t *lr;
+       zilog_t *zilog = zv->zv_zilog;
 
-       dmu_tx_commit(tx);
-       zfs_range_unlock(rl);
+       if (zil_replaying(zilog, tx))
+               return;
 
-       if ((bio_is_fua(bio)) ||
-           zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS)
-               zil_commit(zv->zv_zilog, ZVOL_OBJ);
+       itx = zil_itx_create(TX_TRUNCATE, sizeof (*lr));
+       lr = (lr_truncate_t *)&itx->itx_lr;
+       lr->lr_foid = ZVOL_OBJ;
+       lr->lr_offset = off;
+       lr->lr_length = len;
 
-out:
-       return (error);
+       itx->itx_sync = sync;
+       zil_itx_assign(zilog, itx, tx);
 }
 
 static int
@@ -670,6 +699,7 @@ zvol_discard(struct bio *bio)
        uint64_t end = start + size;
        int error;
        rl_t *rl;
+       dmu_tx_t *tx;
 
        ASSERT(zv && zv->zv_open_count > 0);
 
@@ -692,69 +722,85 @@ zvol_discard(struct bio *bio)
                return (0);
 
        rl = zfs_range_lock(&zv->zv_range_lock, start, size, RL_WRITER);
+       tx = dmu_tx_create(zv->zv_objset);
+       dmu_tx_mark_netfree(tx);
+       error = dmu_tx_assign(tx, TXG_WAIT);
+       if (error != 0) {
+               dmu_tx_abort(tx);
+       } else {
+               zvol_log_truncate(zv, tx, start, size, B_TRUE);
+               dmu_tx_commit(tx);
+               error = dmu_free_long_range(zv->zv_objset,
+                   ZVOL_OBJ, start, size);
+       }
 
-       error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, start, size);
-
-       /*
-        * TODO: maybe we should add the operation to the log.
-        */
        zfs_range_unlock(rl);
 
        return (error);
 }
 
 static int
-zvol_read(struct bio *bio)
+zvol_read(zvol_state_t *zv, uio_t *uio)
 {
-       zvol_state_t *zv = bio->bi_bdev->bd_disk->private_data;
-       uint64_t offset = BIO_BI_SECTOR(bio) << 9;
-       uint64_t len = BIO_BI_SIZE(bio);
-       int error;
+       uint64_t volsize = zv->zv_volsize;
        rl_t *rl;
+       int error = 0;
 
        ASSERT(zv && zv->zv_open_count > 0);
 
-       if (len == 0)
-               return (0);
-
-       rl = zfs_range_lock(&zv->zv_range_lock, offset, len, RL_READER);
+       rl = zfs_range_lock(&zv->zv_range_lock, uio->uio_loffset,
+           uio->uio_resid, RL_READER);
+       while (uio->uio_resid > 0 && uio->uio_loffset < volsize) {
+               uint64_t bytes = MIN(uio->uio_resid, DMU_MAX_ACCESS >> 1);
 
-       error = dmu_read_bio(zv->zv_objset, ZVOL_OBJ, bio);
+               /* don't read past the end */
+               if (bytes > volsize - uio->uio_loffset)
+                       bytes = volsize - uio->uio_loffset;
 
+               error = dmu_read_uio_dbuf(zv->zv_dbuf, uio, bytes);
+               if (error) {
+                       /* convert checksum errors into IO errors */
+                       if (error == ECKSUM)
+                               error = SET_ERROR(EIO);
+                       break;
+               }
+       }
        zfs_range_unlock(rl);
-
-       /* convert checksum errors into IO errors */
-       if (error == ECKSUM)
-               error = SET_ERROR(EIO);
-
        return (error);
 }
 
 static MAKE_REQUEST_FN_RET
 zvol_request(struct request_queue *q, struct bio *bio)
 {
+       uio_t uio;
        zvol_state_t *zv = q->queuedata;
        fstrans_cookie_t cookie = spl_fstrans_mark();
-       uint64_t offset = BIO_BI_SECTOR(bio);
-       unsigned int sectors = bio_sectors(bio);
        int rw = bio_data_dir(bio);
 #ifdef HAVE_GENERIC_IO_ACCT
        unsigned long start = jiffies;
 #endif
        int error = 0;
 
-       if (bio_has_data(bio) && offset + sectors >
-           get_capacity(zv->zv_disk)) {
+       uio.uio_bvec = &bio->bi_io_vec[BIO_BI_IDX(bio)];
+       uio.uio_skip = BIO_BI_SKIP(bio);
+       uio.uio_resid = BIO_BI_SIZE(bio);
+       uio.uio_iovcnt = bio->bi_vcnt - BIO_BI_IDX(bio);
+       uio.uio_loffset = BIO_BI_SECTOR(bio) << 9;
+       uio.uio_limit = MAXOFFSET_T;
+       uio.uio_segflg = UIO_BVEC;
+
+       if (bio_has_data(bio) && uio.uio_loffset + uio.uio_resid >
+           zv->zv_volsize) {
                printk(KERN_INFO
-                   "%s: bad access: block=%llu, count=%lu\n",
+                   "%s: bad access: offset=%llu, size=%lu\n",
                    zv->zv_disk->disk_name,
-                   (long long unsigned)offset,
-                   (long unsigned)sectors);
+                   (long long unsigned)uio.uio_loffset,
+                   (long unsigned)uio.uio_resid);
                error = SET_ERROR(EIO);
                goto out1;
        }
 
-       generic_start_io_acct(rw, sectors, &zv->zv_disk->part0);
+       generic_start_io_acct(rw, bio_sectors(bio), &zv->zv_disk->part0);
 
        if (rw == WRITE) {
                if (unlikely(zv->zv_flags & ZVOL_RDONLY)) {
@@ -767,9 +813,20 @@ zvol_request(struct request_queue *q, struct bio *bio)
                        goto out2;
                }
 
-               error = zvol_write(bio);
+               /*
+                * Some requests are just for flush and nothing else.
+                */
+               if (uio.uio_resid == 0) {
+                       if (bio_is_flush(bio))
+                               zil_commit(zv->zv_zilog, ZVOL_OBJ);
+                       goto out2;
+               }
+
+               error = zvol_write(zv, &uio,
+                   bio_is_flush(bio) || bio_is_fua(bio) ||
+                   zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS);
        } else
-               error = zvol_read(bio);
+               error = zvol_read(zv, &uio);
 
 out2:
        generic_end_io_acct(rw, &zv->zv_disk->part0, start);
@@ -1222,7 +1279,6 @@ zvol_alloc(dev_t dev, const char *name)
 
        zv = kmem_zalloc(sizeof (zvol_state_t), KM_SLEEP);
 
-       spin_lock_init(&zv->zv_lock);
        list_link_init(&zv->zv_next);
 
        zv->zv_queue = blk_alloc_queue(GFP_ATOMIC);
@@ -1369,8 +1425,9 @@ zvol_create_minor_impl(const char *name)
         */
        len = MIN(MAX(zvol_prefetch_bytes, 0), SPA_MAXBLOCKSIZE);
        if (len > 0) {
-               dmu_prefetch(os, ZVOL_OBJ, 0, len);
-               dmu_prefetch(os, ZVOL_OBJ, volsize - len, len);
+               dmu_prefetch(os, ZVOL_OBJ, 0, 0, len, ZIO_PRIORITY_SYNC_READ);
+               dmu_prefetch(os, ZVOL_OBJ, 0, volsize - len, len,
+                       ZIO_PRIORITY_SYNC_READ);
        }
 
        zv->zv_objset = NULL;
index e3a85c1686e61894f6faedb43889fed3d9917e33..43af6bff0cecd44f16d8eaa27da201e678e2403d 100644 (file)
  *
  *  You should have received a copy of the GNU General Public License along
  *  with ZPIOS.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *  Copyright (c) 2015, Intel Corporation.
  */
 
 #include <sys/zfs_context.h>
 #include <sys/dmu.h>
+#include <sys/spa.h>
 #include <sys/txg.h>
 #include <sys/dsl_destroy.h>
 #include <linux/miscdevice.h>
@@ -129,8 +132,17 @@ zpios_dmu_object_create(run_args_t *run_args, objset_t *os)
 {
        struct dmu_tx *tx;
        uint64_t obj = 0ULL;
+       uint64_t blksize = run_args->block_size;
        int rc;
 
+       if (blksize < SPA_MINBLOCKSIZE ||
+           blksize > spa_maxblocksize(dmu_objset_spa(os)) ||
+           !ISP2(blksize)) {
+               zpios_print(run_args->file,
+                   "invalid block size for pool: %d\n", (int)blksize);
+               return (obj);
+       }
+
        tx = dmu_tx_create(os);
        dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, OBJ_SIZE);
        rc = dmu_tx_assign(tx, TXG_WAIT);
@@ -142,10 +154,11 @@ zpios_dmu_object_create(run_args_t *run_args, objset_t *os)
        }
 
        obj = dmu_object_alloc(os, DMU_OT_UINT64_OTHER, 0, DMU_OT_NONE, 0, tx);
-       rc = dmu_object_set_blocksize(os, obj, 128ULL << 10, 0, tx);
+       rc = dmu_object_set_blocksize(os, obj, blksize, 0, tx);
        if (rc) {
                zpios_print(run_args->file,
-                           "dmu_object_set_blocksize() failed: %d\n", rc);
+                   "dmu_object_set_blocksize to %d failed: %d\n",
+                   (int)blksize, rc);
                dmu_tx_abort(tx);
                return (obj);
        }
@@ -274,11 +287,6 @@ zpios_setup_run(run_args_t **run_args, zpios_cmd_t *kcmd, struct file *file)
        size = sizeof (*ra) + kcmd->cmd_region_count * sizeof (zpios_region_t);
 
        ra = vmem_zalloc(size, KM_SLEEP);
-       if (ra == NULL) {
-               zpios_print(file, "Unable to vmem_zalloc() %d bytes "
-                           "for regions\n", size);
-               return (-ENOMEM);
-       }
 
        *run_args = ra;
        strncpy(ra->pool, kcmd->cmd_pool, ZPIOS_NAME_SIZE - 1);
@@ -295,6 +303,7 @@ zpios_setup_run(run_args_t **run_args, zpios_cmd_t *kcmd, struct file *file)
        ra->chunk_noise         = kcmd->cmd_chunk_noise;
        ra->thread_delay        = kcmd->cmd_thread_delay;
        ra->flags               = kcmd->cmd_flags;
+       ra->block_size          = kcmd->cmd_block_size;
        ra->stats.wr_data       = 0;
        ra->stats.wr_chunks     = 0;
        ra->stats.rd_data       = 0;
@@ -720,16 +729,8 @@ zpios_threads_run(run_args_t *run_args)
        int i, rc = 0, tc = run_args->thread_count;
 
        tsks = kmem_zalloc(sizeof (struct task_struct *) * tc, KM_SLEEP);
-       if (tsks == NULL) {
-               rc = -ENOMEM;
-               goto cleanup2;
-       }
 
        run_args->threads = kmem_zalloc(sizeof (thread_data_t *)*tc, KM_SLEEP);
-       if (run_args->threads == NULL) {
-               rc = -ENOMEM;
-               goto cleanup;
-       }
 
        init_waitqueue_head(&run_args->waitq);
        run_args->threads_done = 0;
@@ -737,10 +738,6 @@ zpios_threads_run(run_args_t *run_args)
        /* Create all the needed threads which will sleep until awoken */
        for (i = 0; i < tc; i++) {
                thr = kmem_zalloc(sizeof (thread_data_t), KM_SLEEP);
-               if (thr == NULL) {
-                       rc = -ENOMEM;
-                       goto taskerr;
-               }
 
                thr->thread_no = i;
                thr->run_args = run_args;
@@ -832,8 +829,6 @@ out:
 
 cleanup:
        kmem_free(tsks, sizeof (struct task_struct *) * tc);
-cleanup2:
-       /* Returns first encountered thread error (if any) */
        return (rc);
 
 taskerr:
@@ -929,17 +924,11 @@ zpios_open(struct inode *inode, struct file *file)
        zpios_info_t *info;
 
        info = (zpios_info_t *)kmem_alloc(sizeof (*info), KM_SLEEP);
-       if (info == NULL)
-               return (-ENOMEM);
 
        spin_lock_init(&info->info_lock);
        info->info_size = ZPIOS_INFO_BUFFER_SIZE;
        info->info_buffer =
            (char *) vmem_alloc(ZPIOS_INFO_BUFFER_SIZE, KM_SLEEP);
-       if (info->info_buffer == NULL) {
-               kmem_free(info, sizeof (*info));
-               return (-ENOMEM);
-       }
 
        info->info_head = info->info_buffer;
        file->private_data = (void *)info;
@@ -992,10 +981,6 @@ zpios_buffer_size(struct file *file, zpios_cfg_t *kcfg, unsigned long arg)
 
                size = kcfg->cfg_arg1;
                buf = (char *)vmem_alloc(size, KM_SLEEP);
-               if (buf == NULL) {
-                       rc = -ENOMEM;
-                       goto out;
-               }
 
                /* Zero fill and truncate contents when coping buffer */
                min = ((size < info->info_size) ? size : info->info_size);
@@ -1012,7 +997,7 @@ zpios_buffer_size(struct file *file, zpios_cfg_t *kcfg, unsigned long arg)
        if (copy_to_user((struct zpios_cfg_t __user *)arg,
            kcfg, sizeof (*kcfg)))
                rc = -EFAULT;
-out:
+
        spin_unlock(&info->info_lock);
 
        return (rc);
@@ -1066,11 +1051,6 @@ zpios_ioctl_cmd(struct file *file, unsigned long arg)
        int rc = -EINVAL;
 
        kcmd = kmem_alloc(sizeof (zpios_cmd_t), KM_SLEEP);
-       if (kcmd == NULL) {
-               zpios_print(file, "Unable to kmem_alloc() %ld byte for "
-                           "zpios_cmd_t\n", (long int)sizeof (zpios_cmd_t));
-               return (-ENOMEM);
-       }
 
        rc = copy_from_user(kcmd, (zpios_cfg_t *)arg, sizeof (zpios_cmd_t));
        if (rc) {
@@ -1089,13 +1069,6 @@ zpios_ioctl_cmd(struct file *file, unsigned long arg)
        /* Allocate memory for any opaque data the caller needed to pass on */
        if (kcmd->cmd_data_size > 0) {
                data = (void *)vmem_alloc(kcmd->cmd_data_size, KM_SLEEP);
-               if (data == NULL) {
-                       zpios_print(file, "Unable to vmem_alloc() %ld "
-                                   "bytes for data buffer\n",
-                                   (long)kcmd->cmd_data_size);
-                       rc = -ENOMEM;
-                       goto out_cmd;
-               }
 
                rc = copy_from_user(data, (void *)(arg + offsetof(zpios_cmd_t,
                    cmd_data_str)), kcmd->cmd_data_size);
diff --git a/zfs/rpm/Makefile.am b/zfs/rpm/Makefile.am
new file mode 100644 (file)
index 0000000..f2cf72c
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = generic redhat
diff --git a/zfs/rpm/Makefile.in b/zfs/rpm/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/rpm/generic/Makefile.am b/zfs/rpm/generic/Makefile.am
new file mode 100644 (file)
index 0000000..89b1364
--- /dev/null
@@ -0,0 +1 @@
+EXTRA_DIST = zfs.spec.in zfs-kmod.spec.in zfs-dkms.spec.in
diff --git a/zfs/rpm/generic/Makefile.in b/zfs/rpm/generic/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
index b3e8c1303bda612cfbec58359220e20cc62e48d7..e432bc4142dba5719a161c7e0b4465542fc2d5d8 100644 (file)
@@ -1,2 +1,78 @@
-%:
-       #
+%{?!packager: %define packager Brian Behlendorf <behlendorf1@llnl.gov>}
+
+%define module  @PACKAGE@
+%define mkconf  scripts/dkms.mkconf
+
+Name:           %{module}-dkms
+
+Version:        @VERSION@
+Release:        @RELEASE@%{?dist}
+Summary:        Kernel module(s) (dkms)
+
+Group:          System Environment/Kernel
+License:        @ZFS_META_LICENSE@
+URL:            http://zfsonlinux.org/
+Source0:        %{module}-%{version}.tar.gz
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildArch:      noarch
+
+Requires:       dkms >= 2.2.0.3-20
+Requires:       spl-dkms = %{version}
+Requires:       gcc, make, perl
+Requires:       kernel-devel
+Provides:       %{module}-kmod = %{version}
+
+%description
+This package contains the dkms ZFS kernel modules.
+
+%prep
+%setup -q -n %{module}-%{version}
+
+%build
+%{mkconf} -n %{module} -v %{version} -f dkms.conf
+
+%install
+if [ "$RPM_BUILD_ROOT" != "/" ]; then
+    rm -rf $RPM_BUILD_ROOT
+fi
+mkdir -p $RPM_BUILD_ROOT/usr/src/
+cp -rf ${RPM_BUILD_DIR}/%{module}-%{version} $RPM_BUILD_ROOT/usr/src/
+
+%clean
+if [ "$RPM_BUILD_ROOT" != "/" ]; then
+    rm -rf $RPM_BUILD_ROOT
+fi
+
+%files
+%defattr(-,root,root)
+/usr/src/%{module}-%{version}
+
+%post
+for POSTINST in /usr/lib/dkms/common.postinst; do
+    if [ -f $POSTINST ]; then
+        $POSTINST %{module} %{version}
+        exit $?
+    fi
+    echo "WARNING: $POSTINST does not exist."
+done
+echo -e "ERROR: DKMS version is too old and %{module} was not"
+echo -e "built with legacy DKMS support."
+echo -e "You must either rebuild %{module} with legacy postinst"
+echo -e "support or upgrade DKMS to a more current version."
+exit 1
+
+%preun
+CONFIG_H="/var/lib/dkms/%{module}/%{version}/*/*/%{module}_config.h"
+SPEC_META_ALIAS="@PACKAGE@-@VERSION@-@RELEASE@"
+DKMS_META_ALIAS=`cat $CONFIG_H 2>/dev/null |
+    awk -F'"' '/META_ALIAS/ { print $2; exit 0 }'`
+if [ "$SPEC_META_ALIAS" = "$DKMS_META_ALIAS" ]; then
+    echo -e
+    echo -e "Uninstall of %{module} module ($SPEC_META_ALIAS) beginning:"
+    dkms remove -m %{module} -v %{version} --all --rpm_safe_upgrade
+fi
+exit 0
+
+%changelog
+* %(date "+%a %b %d %Y") %packager %{version}-%{release}
+- Automatic build by DKMS
index b3e8c1303bda612cfbec58359220e20cc62e48d7..9d10e6075801e736fbf013ef65d140616922d34a 100644 (file)
@@ -1,2 +1,199 @@
-%:
-       #
+%define module  @PACKAGE@
+
+%if !%{defined ksrc}
+%if 0%{?rhel}%{?fedora}
+%define ksrc    ${kernel_version##*___}
+%else
+%define ksrc    "$( \
+        if [ -e "/usr/src/linux-${kernel_version%%___*}" ]; then \
+            echo "/usr/src/linux-${kernel_version%%___*}"; \
+        elif [ -e "/lib/modules/${kernel_version%%___*}/source" ]; then \
+            echo "/lib/modules/${kernel_version%%___*}/source"; \
+        else \
+            echo "/lib/modules/${kernel_version%%___*}/build"; \
+        fi)"
+%endif
+%endif
+
+%if !%{defined kobj}
+%if 0%{?rhel}%{?fedora}
+%define kobj    ${kernel_version##*___}
+%else
+%define kobj    "$( \
+        if [ -e "/usr/src/linux-${kernel_version%%___*}" ]; then \
+            echo "/usr/src/linux-${kernel_version%%___*}"; \
+        else \
+            echo "/lib/modules/${kernel_version%%___*}/build"; \
+        fi)"
+%endif
+%endif
+
+#define repo    rpmfusion
+#define repo    chaos
+
+# (un)define the next line to either build for the newest or all current kernels
+%define buildforkernels newest
+#define buildforkernels current
+#define buildforkernels akmod
+
+%bcond_with     debug
+%bcond_with     debug_dmu_tx
+
+
+Name:           %{module}-kmod
+
+Version:        @VERSION@
+Release:        @RELEASE@%{?dist}
+Summary:        Kernel module(s)
+
+Group:          System Environment/Kernel
+License:        @ZFS_META_LICENSE@
+URL:            http://zfsonlinux.org/
+Source0:        %{module}-%{version}.tar.gz
+Source10:       kmodtool
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id} -u -n)
+
+# The developments headers will conflict with the dkms packages.
+Conflicts:      %{module}-dkms
+
+%if %{defined repo}
+
+# Building for a repository use the proper build-sysbuild package
+# to determine which kernel-devel packages should be installed.
+BuildRequires:  %{_bindir}/kmodtool
+%{!?kernels:BuildRequires: buildsys-build-%{repo}-kerneldevpkgs-%{?buildforkernels:%{buildforkernels}}%{!?buildforkernels:current}-%{_target_cpu}}
+
+%else
+
+# Building local packages attempt to to use the installed kernel.
+%{?rhel:BuildRequires: kernel-devel}
+%{?fedora:BuildRequires: kernel-devel}
+%{?suse_version:BuildRequires: kernel-source}
+
+%if !%{defined kernels} && !%{defined build_src_rpm}
+    %if 0%{?rhel}%{?fedora}%{?suse_version}
+        %define kernels %(ls -1 /usr/src/kernels)
+    %else
+        %define kernels %(ls -1 /lib/modules)
+    %endif
+%endif
+%endif
+
+%if 0%{?rhel}%{?fedora}%{?suse_version}
+BuildRequires:             kmod-spl-devel = %{version}
+%global KmodsRequires      kmod-spl
+%global KmodsDevelRequires kmod-spl-devel
+%global KmodsMetaRequires  spl-kmod
+%endif
+
+%if 0%{?fedora} >= 17
+%define prefix  /usr
+%endif
+
+# Kmodtool does its magic here.  A patched version of kmodtool is shipped
+# with the source rpm until kmod development packages are supported upstream.
+# https://bugzilla.rpmfusion.org/show_bug.cgi?id=2714
+%{expand:%(bash %{SOURCE10} --target %{_target_cpu} %{?repo:--repo %{?repo}} --kmodname %{name} %{?buildforkernels:--%{buildforkernels}} --devel %{?prefix:--prefix "%{?prefix}"} %{?kernels:--for-kernels "%{?kernels}"} %{?kernelbuildroot:--buildroot "%{?kernelbuildroot}"} 2>/dev/null) }
+
+
+%description
+This package contains the ZFS kernel modules.
+
+%prep
+# Error out if there was something wrong with kmodtool.
+%{?kmodtool_check}
+
+# Print kmodtool output for debugging purposes:
+bash %{SOURCE10}  --target %{_target_cpu} %{?repo:--repo %{?repo}} --kmodname %{name} %{?buildforkernels:--%{buildforkernels}} --devel %{?prefix:--prefix "%{?prefix}"} %{?kernels:--for-kernels "%{?kernels}"} %{?kernelbuildroot:--buildroot "%{?kernelbuildroot}"} 2>/dev/null
+
+%if %{with debug}
+    %define debug --enable-debug
+%else
+    %define debug --disable-debug
+%endif
+
+%if %{with debug_dmu_tx}
+    %define debug_dmu_tx --enable-debug-dmu-tx
+%else
+    %define debug_dmu_tx --disable-debug-dmu-tx
+%endif
+
+#
+# Allow the overriding of spl locations
+#
+%if %{defined require_splver}
+%define splver %{require_splver}
+%else
+%define splver %{version}
+%endif
+
+%if %{defined require_spldir}
+%define spldir %{require_spldir}
+%else
+%define spldir %{_usrsrc}/spl-%{splver}
+%endif
+
+%if %{defined require_splobj}
+%define splobj %{require_splobj}
+%else
+%define splobj %{spldir}/${kernel_version%%___*}
+%endif
+
+
+# Leverage VPATH from configure to avoid making multiple copies.
+%define _configure ../%{module}-%{version}/configure
+
+%setup -q -c -T -a 0
+
+for kernel_version in %{?kernel_versions}; do
+    %{__mkdir} _kmod_build_${kernel_version%%___*}
+done
+
+%build
+for kernel_version in %{?kernel_versions}; do
+    cd _kmod_build_${kernel_version%%___*}
+    %configure \
+        --with-config=kernel \
+        --with-linux=%{ksrc} \
+        --with-linux-obj=%{kobj} \
+        --with-spl="%{spldir}" \
+        --with-spl-obj="%{splobj}" \
+        %{debug} \
+        %{debug_dmu_tx}
+    make %{?_smp_mflags}
+    cd ..
+done
+
+
+%install
+rm -rf ${RPM_BUILD_ROOT}
+
+# Relies on the kernel 'modules_install' make target.
+for kernel_version in %{?kernel_versions}; do
+    cd _kmod_build_${kernel_version%%___*}
+    make install \
+        DESTDIR=${RPM_BUILD_ROOT} \
+        %{?prefix:INSTALL_MOD_PATH=%{?prefix}} \
+        INSTALL_MOD_DIR=%{kmodinstdir_postfix}
+    cd ..
+done
+# find-debuginfo.sh only considers executables
+chmod u+x ${RPM_BUILD_ROOT}%{kmodinstdir_prefix}/*/extra/*/*/*
+%{?akmod_install}
+
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%changelog
+* Fri Sep 11 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.5-1
+- Released 0.6.5-1, detailed release notes are available at:
+- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.6.5
+* Wed Apr  8 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.4-1
+- Released 0.6.4-1
+* Thu Jun 12 2014 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.3-1
+- Released 0.6.3-1
+* Wed Aug 21 2013 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.2-1
+- Released 0.6.2-1
+* Fri Mar 22 2013 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.1-1
+- First official stable release.
index b3e8c1303bda612cfbec58359220e20cc62e48d7..e80f51e312b334edb29d20ede65247494c712c99 100644 (file)
@@ -1,2 +1,339 @@
-%:
-       #
+%global _sbindir    /sbin
+%global _libdir     /%{_lib}
+
+# Set the default udev directory based on distribution.
+%if %{undefined _udevdir}
+%if 0%{?fedora} >= 17 || 0%{?rhel} >= 7 || 0%{?centos} >= 7
+%global _udevdir    %{_prefix}/lib/udev
+%else
+%global _udevdir    /lib/udev
+%endif
+%endif
+
+# Set the default udevrule directory based on distribution.
+%if %{undefined _udevruledir}
+%if 0%{?fedora} >= 17 || 0%{?rhel} >= 7 || 0%{?centos} >= 7
+%global _udevruledir    %{_prefix}/lib/udev/rules.d
+%else
+%global _udevruledir    /lib/udev/rules.d
+%endif
+%endif
+
+# Set the default dracut directory based on distribution.
+%if %{undefined _dracutdir}
+%if 0%{?fedora} >= 17 || 0%{?rhel} >= 7 || 0%{?centos} >= 7
+%global _dracutdir  %{_prefix}/lib/dracut
+%else
+%global _dracutdir  %{_prefix}/share/dracut
+%endif
+%endif
+
+# Set the default _initconfdir when undefined.
+%if %{undefined _initconfdir}
+%global _initconfdir /etc/sysconfig
+%endif
+
+%bcond_with    debug
+%bcond_with    systemd
+
+# Generic enable switch for systemd
+%if %{with systemd}
+%define _systemd 1
+%endif
+
+# RHEL >= 7 comes with systemd
+%if 0%{?rhel} >= 7
+%define _systemd 1
+%endif
+
+# Fedora >= 15 comes with systemd, but only >= 18 has
+# the proper macros
+%if 0%{?fedora} >= 18
+%define _systemd 1
+%endif
+
+# opensuse >= 12.1 comes with systemd, but only >= 13.1
+# has the proper macros
+%if 0%{?suse_version} >= 1310
+%define _systemd 1
+%endif
+
+Name:           @PACKAGE@
+Version:        @VERSION@
+Release:        @RELEASE@%{?dist}
+Summary:        Commands to control the kernel modules and libraries
+
+Group:          System Environment/Kernel
+License:        @ZFS_META_LICENSE@
+URL:            http://zfsonlinux.org/
+Source0:        %{name}-%{version}.tar.gz
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+Requires:       spl = %{version}
+Requires:       libzpool2 = %{version}
+Requires:       libnvpair1 = %{version}
+Requires:       libuutil1 = %{version}
+Requires:       libzfs2 = %{version}
+Requires:       device-mapper
+Requires:       %{name}-kmod = %{version}
+Provides:       %{name}-kmod-common = %{version}
+
+# zfs-fuse provides the same commands and man pages that ZoL does. Renaming
+# those on either side would conflict with all available documentation.
+Conflicts:      zfs-fuse
+
+%if 0%{?rhel}%{?fedora}%{?suse_version}
+BuildRequires:  zlib-devel
+BuildRequires:  libuuid-devel
+BuildRequires:  libblkid-devel
+BuildRequires:  device-mapper-devel
+BuildRequires:  libudev-devel
+BuildRequires:  libattr-devel
+%endif
+%if 0%{?_systemd}
+Requires(post): systemd
+Requires(preun): systemd
+Requires(postun): systemd
+BuildRequires: systemd
+%endif
+
+%description
+This package contains the ZFS command line utilities.
+
+%package -n libzpool2
+Summary:        Native ZFS pool library for Linux
+Group:          System Environment/Kernel
+
+%description -n libzpool2
+This package contains the zpool library, which provides support
+for managing zpools
+
+%post -n libzpool2 -p /sbin/ldconfig
+%postun -n libzpool2 -p /sbin/ldconfig
+
+%package -n libnvpair1
+Summary:        Solaris name-value library for Linux
+Group:          System Environment/Kernel
+
+%description -n libnvpair1
+This package contains routines for packing and unpacking name-value
+pairs.  This functionality is used to portably transport data across
+process boundaries, between kernel and user space, and can be used
+to write self describing data structures on disk.
+
+%post -n libnvpair1 -p /sbin/ldconfig
+%postun -n libnvpair1 -p /sbin/ldconfig
+
+%package -n libuutil1
+Summary:        Solaris userland utility library for Linux
+Group:          System Environment/Kernel
+
+%description -n libuutil1
+This library provides a variety of compatibility functions for ZFS on Linux:
+ * libspl: The Solaris Porting Layer userland library, which provides APIs
+   that make it possible to run Solaris user code in a Linux environment
+   with relatively minimal modification.
+ * libavl: The Adelson-Velskii Landis balanced binary tree manipulation
+   library.
+ * libefi: The Extensible Firmware Interface library for GUID disk
+   partitioning.
+ * libshare: NFS, SMB, and iSCSI service integration for ZFS.
+
+%post -n libuutil1 -p /sbin/ldconfig
+%postun -n libuutil1 -p /sbin/ldconfig
+
+%package -n libzfs2
+Summary:        Native ZFS filesystem library for Linux
+Group:          System Environment/Kernel
+
+%description -n libzfs2
+This package provides support for managing ZFS filesystems
+
+%post -n libzfs2 -p /sbin/ldconfig
+%postun -n libzfs2 -p /sbin/ldconfig
+
+%package -n libzfs2-devel
+Summary:        Development headers
+Group:          System Environment/Kernel
+Requires:       libzfs2 = %{version}
+Requires:       libzpool2 = %{version}
+Requires:       libnvpair1 = %{version}
+Requires:       libuutil1 = %{version}
+Provides:       libzpool2-devel
+Provides:       libnvpair1-devel
+Provides:       libuutil1-devel
+Obsoletes:      zfs-devel
+
+%description -n libzfs2-devel
+This package contains the header files needed for building additional
+applications against the ZFS libraries.
+
+%package test
+Summary:        Test infrastructure
+Group:          System Environment/Kernel
+Requires:       %{name}%{?_isa} = %{version}-%{release}
+Requires:       parted
+Requires:       lsscsi
+Requires:       mdadm
+Requires:       bc
+Requires:       ksh
+Requires:      fio
+Requires:      acl
+Requires:      sysstat
+
+%description test
+This package contains test infrastructure and support scripts for
+validating the file system.
+
+%package dracut
+Summary:        Dracut module
+Group:          System Environment/Kernel
+Requires:       %{name}%{?_isa} = %{version}-%{release}
+Requires:       dracut
+
+%description dracut
+This package contains a dracut module used to construct an initramfs
+image which is ZFS aware.
+
+%if 0%{?_initramfs}
+%package initramfs
+Summary:        Initramfs module
+Group:          System Environment/Kernel
+Requires:       %{name}%{?_isa} = %{version}-%{release}
+Requires:       %{name} = %{version}-%{release}
+Requires:       initramfs-tools
+
+%description initramfs
+This package contains a initramfs module used to construct an initramfs
+image which is ZFS aware.
+%endif
+
+%prep
+%if %{with debug}
+    %define debug --enable-debug
+%else
+    %define debug --disable-debug
+%endif
+%if 0%{?_systemd}
+    %define systemd --enable-systemd --with-systemdunitdir=%{_unitdir} --with-systemdpresetdir=%{_presetdir} --disable-sysvinit
+%else
+    %define systemd --enable-sysvinit --disable-systemd
+%endif
+
+%setup -q
+
+%build
+%configure \
+    --with-config=user \
+    --with-udevdir=%{_udevdir} \
+    --with-udevruledir=%{_udevruledir} \
+    --with-dracutdir=%{_dracutdir} \
+    --disable-static \
+    %{debug} \
+    %{systemd}
+make %{?_smp_mflags}
+
+%install
+%{__rm} -rf $RPM_BUILD_ROOT
+make install DESTDIR=%{?buildroot}
+find %{?buildroot}%{_libdir} -name '*.la' -exec rm -f {} \;
+
+%post
+%if 0%{?_systemd}
+%systemd_post zfs.target
+%else
+if [ -x /sbin/chkconfig ]; then
+    /sbin/chkconfig --add zfs-import
+    /sbin/chkconfig --add zfs-mount
+    /sbin/chkconfig --add zfs-share
+    /sbin/chkconfig --add zfs-zed
+fi
+%endif
+exit 0
+
+%preun
+%if 0%{?_systemd}
+%systemd_preun zfs.target
+%else
+if [ $1 -eq 0 ] && [ -x /sbin/chkconfig ]; then
+    /sbin/chkconfig --del zfs-import
+    /sbin/chkconfig --del zfs-mount
+    /sbin/chkconfig --del zfs-share
+    /sbin/chkconfig --del zfs-zed
+fi
+%endif
+exit 0
+
+%postun
+%if 0%{?_systemd}
+%systemd_postun zfs.target
+%endif
+
+%files
+%{_sbindir}/*
+%{_bindir}/*
+%{_libexecdir}/%{name}
+%{_mandir}/man1/*
+%{_mandir}/man5/*
+%{_mandir}/man8/*
+%{_udevdir}/vdev_id
+%{_udevdir}/zvol_id
+%{_udevdir}/rules.d/*
+%if 0%{?_systemd}
+/usr/lib/modules-load.d/*
+%{_unitdir}/*
+%{_presetdir}/*
+%else
+%config(noreplace) %{_sysconfdir}/init.d/*
+%config(noreplace) %{_initconfdir}/zfs
+%endif
+%config(noreplace) %{_sysconfdir}/%{name}
+
+%files -n libzpool2
+%{_libdir}/libzpool.so.*
+
+%files -n libnvpair1
+%{_libdir}/libnvpair.so.*
+
+%files -n libuutil1
+%{_libdir}/libuutil.so.*
+
+%files -n libzfs2
+%{_libdir}/libzfs*.so.*
+
+%files -n libzfs2-devel
+%{_datadir}/pkgconfig/libzfs.pc
+%{_datadir}/pkgconfig/libzfs_core.pc
+%{_libdir}/*.so
+%{_includedir}/*
+%doc AUTHORS COPYRIGHT DISCLAIMER
+%doc OPENSOLARIS.LICENSE README.markdown
+
+%files test
+%{_datadir}/%{name}
+
+%files dracut
+%doc contrib/dracut/README.dracut.markdown
+%{_dracutdir}/modules.d/*
+
+%if 0%{?_initramfs}
+%files initramfs
+%doc contrib/initramfs/README.initramfs.markdown
+/usr/share/initramfs-tools/*
+%else
+# Since we're not building the initramfs package,
+# ignore those files.
+%exclude /usr/share/initramfs-tools
+%endif
+
+%changelog
+* Fri Sep 11 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.5-1
+- Released 0.6.5-1, detailed release notes are available at:
+- https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.6.5
+* Wed Apr  8 2015 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.4-1
+- Released 0.6.4-1
+* Thu Jun 12 2014 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.3-1
+- Released 0.6.3-1
+* Wed Aug 21 2013 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.2-1
+- Released 0.6.2-1
+* Fri Mar 22 2013 Brian Behlendorf <behlendorf1@llnl.gov> - 0.6.1-1
+- First official stable release.
diff --git a/zfs/rpm/redhat/Makefile.am b/zfs/rpm/redhat/Makefile.am
new file mode 100644 (file)
index 0000000..89b1364
--- /dev/null
@@ -0,0 +1 @@
+EXTRA_DIST = zfs.spec.in zfs-kmod.spec.in zfs-dkms.spec.in
diff --git a/zfs/rpm/redhat/Makefile.in b/zfs/rpm/redhat/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
deleted file mode 100644 (file)
index b3e8c1303bda612cfbec58359220e20cc62e48d7..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..ffa051baaf0388804eaa38953b0a1b765a0a6241
--- /dev/null
@@ -0,0 +1 @@
+../generic/zfs-dkms.spec.in
\ No newline at end of file
index b3e8c1303bda612cfbec58359220e20cc62e48d7..fa0c1108e08977f6460574a352d676b62266c9e0 100644 (file)
@@ -1,2 +1,88 @@
-%:
-       #
+%bcond_with     debug
+%bcond_with     debug_dmu_tx
+
+Name:           @PACKAGE@-kmod
+Version:        @VERSION@
+Release:        @RELEASE@%{?dist}
+
+Summary:        Kernel module(s)
+Group:          System Environment/Kernel
+License:        @ZFS_META_LICENSE@
+URL:            http://zfsonlinux.org/
+BuildRequires:  %kernel_module_package_buildreqs
+BuildRequires:  kmod-spl-devel = %{version}
+Source0:        @PACKAGE@-%{version}.tar.gz
+BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+# Additional dependency information for the kmod sub-package must be specified
+# by generating a preamble text file which kmodtool can append to the spec file.
+%(/bin/echo -e "\
+Requires:       spl-kmod\n\
+Requires:       @PACKAGE@ = %{version}\n\
+Conflicts:      @PACKAGE@-dkms\n\n" > %{_sourcedir}/kmod-preamble)
+
+%description
+This package contains the ZFS kernel modules.
+
+%define kmod_name @PACKAGE@
+
+%kernel_module_package -n %{kmod_name} -p %{_sourcedir}/kmod-preamble
+
+%define ksrc %{_usrsrc}/kernels/%{kverrel}
+%define kobj %{ksrc}
+%define splsrc %{_usrsrc}/spl-%{version}
+%define splobj %{splsrc}/%{kverrel}
+
+%package -n kmod-%{kmod_name}-devel
+Summary:        ZFS kernel module(s) devel common
+Group:          System Environment/Kernel
+Requires:       kmod-spl-devel = %{version}
+
+%description -n  kmod-%{kmod_name}-devel
+This package provides the header files and objects to build kernel modules
+which depend on the spl kernel module.
+
+%prep
+if ! [ -d "%{ksrc}"  ]; then
+        echo "Kernel build directory isn't set properly, cannot continue"
+        exit 1
+fi
+
+%if %{with debug}
+%define debug --enable-debug
+%else
+%define debug --disable-debug
+%endif
+
+%if %{with debug_dmu_tx}
+%define debug_dmu_tx --enable-debug-dmu-tx
+%else
+%define debug_dmu_tx --disable-debug-dmu-tx
+%endif
+
+%setup -n %{kmod_name}-%{version}
+%build
+%configure \
+        --with-config=kernel \
+        --with-linux=%{ksrc} \
+        --with-linux-obj=%{kobj} \
+        --with-spl="%{splsrc}" \
+        --with-spl-obj="%{splobj}" \
+        %{debug} \
+        %{debug_dmu_tx}
+make %{?_smp_mflags}
+
+%install
+make install \
+        DESTDIR=${RPM_BUILD_ROOT} \
+        INSTALL_MOD_DIR=extra/%{kmod_name}
+%{__rm} -f %{buildroot}/lib/modules/%{kverrel}/modules.*
+
+# find-debuginfo.sh only considers executables
+%{__chmod} u+x  %{buildroot}/lib/modules/%{kverrel}/extra/*/*/*
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files -n kmod-%{kmod_name}-devel
+%{_usrsrc}/%{kmod_name}-%{version}
deleted file mode 100644 (file)
index b3e8c1303bda612cfbec58359220e20cc62e48d7..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..4c8079166ff8f82a557fa008b51d90edde7597b3
--- /dev/null
@@ -0,0 +1 @@
+../generic/zfs.spec.in
\ No newline at end of file
diff --git a/zfs/scripts/.gitignore b/zfs/scripts/.gitignore
new file mode 100644 (file)
index 0000000..5621a6e
--- /dev/null
@@ -0,0 +1 @@
+common.sh
diff --git a/zfs/scripts/Makefile.am b/zfs/scripts/Makefile.am
new file mode 100644 (file)
index 0000000..b556009
--- /dev/null
@@ -0,0 +1,19 @@
+SUBDIRS = zpool-config zpios-test zpios-profile
+
+EXTRA_DIST = dkms.mkconf dkms.postbuild kmodtool zfs2zol-patch.sed cstyle.pl
+
+pkgdatadir = $(datadir)/@PACKAGE@
+dist_pkgdata_SCRIPTS = \
+       $(top_builddir)/scripts/common.sh \
+       $(top_srcdir)/scripts/zconfig.sh \
+       $(top_srcdir)/scripts/ziltest.sh \
+       $(top_srcdir)/scripts/zimport.sh \
+       $(top_srcdir)/scripts/zfs.sh \
+       $(top_srcdir)/scripts/zfs-tests.sh \
+       $(top_srcdir)/scripts/zloop.sh \
+       $(top_srcdir)/scripts/zpool-create.sh \
+       $(top_srcdir)/scripts/zpios.sh \
+       $(top_srcdir)/scripts/zpios-sanity.sh \
+       $(top_srcdir)/scripts/zpios-survey.sh \
+       $(top_srcdir)/scripts/smb.sh \
+       $(top_srcdir)/scripts/zfs-helpers.sh
diff --git a/zfs/scripts/Makefile.in b/zfs/scripts/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
index b3e8c1303bda612cfbec58359220e20cc62e48d7..010b534be668a426b08fa00308c8b8db21f866ed 100644 (file)
@@ -1,2 +1,785 @@
-%:
-       #
+#!/bin/bash
+#
+# Common support functions for testing scripts.  If a script-config
+# files is available it will be sourced so in-tree kernel modules and
+# utilities will be used.  If no script-config can be found then the
+# installed kernel modules and utilities will be used.
+
+basedir="$(dirname $0)"
+
+SCRIPT_CONFIG=zfs-script-config.sh
+if [ -f "${basedir}/../${SCRIPT_CONFIG}" ]; then
+. "${basedir}/../${SCRIPT_CONFIG}"
+else
+KERNEL_MODULES=(zlib_deflate zlib_inflate)
+MODULES=(spl splat zavl znvpair zunicode zcommon icp zfs)
+fi
+
+PROG="<define PROG>"
+CLEANUP=
+VERBOSE=
+VERBOSE_FLAG=
+FORCE=
+FORCE_FLAG=
+DUMP_LOG=
+ERROR=
+RAID0S=()
+RAID10S=()
+RAIDZS=()
+RAIDZ2S=()
+TESTS_RUN=${TESTS_RUN:-'*'}
+TESTS_SKIP=${TESTS_SKIP:-}
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+pkgdatadir=@datarootdir@/@PACKAGE@
+bindir=@bindir@
+sbindir=@sbindir@
+udevdir=@udevdir@
+udevruledir=@udevruledir@
+mounthelperdir=@mounthelperdir@
+sysconfdir=@sysconfdir@
+localstatedir=@localstatedir@
+
+ETCDIR=${ETCDIR:-/etc}
+DEVDIR=${DEVDIR:-/dev/disk/by-vdev}
+ZPOOLDIR=${ZPOOLDIR:-${pkgdatadir}/zpool-config}
+ZPIOSDIR=${ZPIOSDIR:-${pkgdatadir}/zpios-test}
+ZPIOSPROFILEDIR=${ZPIOSPROFILEDIR:-${pkgdatadir}/zpios-profile}
+TESTSDIR=${TESTSDIR:-${pkgdatadir}/zfs-tests}
+RUNFILEDIR=${RUNFILEDIR:-${pkgdatadir}/runfiles}
+
+ZDB=${ZDB:-${sbindir}/zdb}
+ZFS=${ZFS:-${sbindir}/zfs}
+ZINJECT=${ZINJECT:-${sbindir}/zinject}
+ZHACK=${ZHACK:-${sbindir}/zhack}
+ZPOOL=${ZPOOL:-${sbindir}/zpool}
+ZTEST=${ZTEST:-${sbindir}/ztest}
+ZPIOS=${ZPIOS:-${sbindir}/zpios}
+
+COMMON_SH=${COMMON_SH:-${pkgdatadir}/common.sh}
+ZFS_SH=${ZFS_SH:-${pkgdatadir}/zfs.sh}
+ZPOOL_CREATE_SH=${ZPOOL_CREATE_SH:-${pkgdatadir}/zpool-create.sh}
+ZPIOS_SH=${ZPIOS_SH:-${pkgdatadir}/zpios.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}
+LSMOD=${LSMOD:-/sbin/lsmod}
+RMMOD=${RMMOD:-/sbin/rmmod}
+INFOMOD=${INFOMOD:-/sbin/modinfo}
+LOSETUP=${LOSETUP:-/sbin/losetup}
+MDADM=${MDADM:-/sbin/mdadm}
+DMSETUP=${DMSETUP:-/sbin/dmsetup}
+PARTED=${PARTED:-/sbin/parted}
+BLOCKDEV=${BLOCKDEV:-/sbin/blockdev}
+LSSCSI=${LSSCSI:-/usr/bin/lsscsi}
+SCSIRESCAN=${SCSIRESCAN:-/usr/bin/scsi-rescan}
+SYSCTL=${SYSCTL:-/sbin/sysctl}
+UDEVADM=${UDEVADM:-/sbin/udevadm}
+AWK=${AWK:-/usr/bin/awk}
+GDB=${GDB:-/usr/bin/gdb}
+
+ZED_PIDFILE=${ZED_PIDFILE:-${localstatedir}/run/zed.pid}
+
+COLOR_BLACK="\033[0;30m"
+COLOR_DK_GRAY="\033[1;30m"
+COLOR_BLUE="\033[0;34m"
+COLOR_LT_BLUE="\033[1;34m" 
+COLOR_GREEN="\033[0;32m"
+COLOR_LT_GREEN="\033[1;32m"
+COLOR_CYAN="\033[0;36m"
+COLOR_LT_CYAN="\033[1;36m"
+COLOR_RED="\033[0;31m"
+COLOR_LT_RED="\033[1;31m"
+COLOR_PURPLE="\033[0;35m"
+COLOR_LT_PURPLE="\033[1;35m"
+COLOR_BROWN="\033[0;33m"
+COLOR_YELLOW="\033[1;33m"
+COLOR_LT_GRAY="\033[0;37m"
+COLOR_WHITE="\033[1;37m"
+COLOR_RESET="\033[0m"
+
+die() {
+       echo -e "${PROG}: $1" >&2
+       exit 1
+}
+
+msg() {
+       if [ ${VERBOSE} ]; then
+               echo "$@"
+       fi
+}
+
+pass() {
+       echo -e "${COLOR_GREEN}Pass${COLOR_RESET}"
+}
+
+fail() {
+       echo -e "${COLOR_RED}Fail${COLOR_RESET} ($1)"
+       exit $1
+}
+
+skip() {
+       echo -e "${COLOR_BROWN}Skip${COLOR_RESET}"
+}
+
+populate() {
+       local ROOT=$1
+       local MAX_DIR_SIZE=$2
+       local MAX_FILE_SIZE=$3
+
+       mkdir -p $ROOT/{a,b,c,d,e,f,g}/{h,i}
+       DIRS=`find $ROOT`
+
+       for DIR in $DIRS; do
+               COUNT=$(($RANDOM % $MAX_DIR_SIZE))
+
+               for i in `seq $COUNT`; do
+                       FILE=`mktemp -p ${DIR}`
+                       SIZE=$(($RANDOM % $MAX_FILE_SIZE))
+                       dd if=/dev/urandom of=$FILE bs=1k count=$SIZE &>/dev/null
+               done
+       done
+
+       return 0
+}
+
+init() {
+       # Create a random directory tree of files and sub-directories to
+       # to act as a copy source for the various regression tests.
+       SRC_DIR=`mktemp -d -p /var/tmp/ zfs.src.XXXXXXXX`
+       trap "rm -Rf $SRC_DIR" INT TERM EXIT
+       populate $SRC_DIR 10 100
+}
+
+spl_dump_log() {
+       ${SYSCTL} -w kernel.spl.debug.dump=1 &>/dev/null
+       local NAME=`dmesg | tail -n 1 | cut -f5 -d' '`
+       ${SPLBUILD}/cmd/spl ${NAME} >${NAME}.log
+       echo
+       echo "Dumped debug log: ${NAME}.log"
+       tail -n1 ${NAME}.log
+       echo
+       return 0
+}
+
+check_modules() {
+       local LOADED_MODULES=()
+       local MISSING_MODULES=()
+
+       for MOD in ${MODULES[*]}; do
+               local NAME=`basename $MOD .ko`
+
+               if ${LSMOD} | egrep -q "^${NAME}"; then
+                       LOADED_MODULES=(${NAME} ${LOADED_MODULES[*]})
+               fi
+
+               if [ ${INFOMOD} ${MOD} 2>/dev/null ]; then
+                       MISSING_MODULES=("\t${MOD}\n" ${MISSING_MODULES[*]})
+               fi
+       done
+
+       if [ ${#LOADED_MODULES[*]} -gt 0 ]; then
+               ERROR="Unload these modules with '${PROG} -u':\n"
+               ERROR="${ERROR}${LOADED_MODULES[*]}"
+               return 1
+       fi
+
+       if [ ${#MISSING_MODULES[*]} -gt 0 ]; then
+               ERROR="The following modules can not be found,"
+               ERROR="${ERROR} ensure your source trees are built:\n"
+               ERROR="${ERROR}${MISSING_MODULES[*]}"
+               return 1
+       fi
+
+       return 0
+}
+
+load_module() {
+       local NAME=`basename $1 .ko`
+
+       if [ ${VERBOSE} ]; then
+               echo "Loading ${NAME} ($@)"
+       fi
+
+       ${LDMOD} $* &>/dev/null
+       if [ $? -ne 0 ]; then
+               echo "Failed to load ${NAME} ($@)"
+               return 1
+       fi
+
+       return 0
+}
+
+load_modules() {
+       mkdir -p /etc/zfs
+
+       for MOD in ${KERNEL_MODULES[*]}; do
+               load_module ${MOD} >/dev/null
+       done
+
+       for MOD in ${MODULES[*]}; do
+               local NAME=`basename ${MOD} .ko`
+               local VALUE=
+
+               for OPT in "$@"; do
+                       OPT_NAME=`echo ${OPT} | cut -f1 -d'='`
+
+                       if [ ${NAME} = "${OPT_NAME}" ]; then
+                               VALUE=`echo ${OPT} | cut -f2- -d'='`
+                       fi
+               done
+
+               load_module ${MOD} ${VALUE} || return 1
+       done
+
+       if [ ${VERBOSE} ]; then
+               echo "Successfully loaded ZFS module stack"
+       fi
+
+       return 0
+}
+
+unload_module() {
+       local NAME=`basename $1 .ko`
+
+       if [ ${VERBOSE} ]; then
+               echo "Unloading ${NAME} ($@)"
+       fi
+
+       ${RMMOD} ${NAME} || ERROR="Failed to unload ${NAME}" return 1
+
+       return 0
+}
+
+unload_modules() {
+       local MODULES_REVERSE=( $(echo ${MODULES[@]} |
+               ${AWK} '{for (i=NF;i>=1;i--) printf $i" "} END{print ""}') )
+
+       for MOD in ${MODULES_REVERSE[*]}; do
+               local NAME=`basename ${MOD} .ko`
+               local USE_COUNT=`${LSMOD} |
+                               egrep "^${NAME} "| ${AWK} '{print $3}'`
+
+               if [ "${USE_COUNT}" = 0 ] ; then
+
+                       if [ "${DUMP_LOG}" -a ${NAME} = "spl" ]; then
+                               spl_dump_log
+                       fi
+
+                       unload_module ${MOD} || return 1
+               fi
+       done
+
+       if [ ${VERBOSE} ]; then
+               echo "Successfully unloaded ZFS module stack"
+       fi
+
+       return 0
+}
+
+#
+# Check that the mdadm utilities are installed.
+#
+check_loop_utils() {
+        test -f ${LOSETUP} || die "${LOSETUP} utility must be installed"
+}
+
+
+#
+# Find and return an unused loop device.  A new /dev/loopN node will be
+# created if required.  The kernel loop driver will automatically register
+# the minor as long as it's less than /sys/module/loop/parameters/max_loop.
+#
+unused_loop_device() {
+       local DEVICE=$(${LOSETUP} -f)
+       local MAX_LOOP_PATH="/sys/module/loop/parameters/max_loop"
+       local MAX_LOOP;
+
+       # An existing /dev/loopN device was available.
+       if [ -n "${DEVICE}" ]; then
+               echo "${DEVICE}"
+               return 0
+       fi
+
+       # Create a new /dev/loopN provided we are not at MAX_LOOP.
+       if [ -f "${MAX_LOOP_PATH}" ]; then
+               MAX_LOOP=`cat /sys/module/loop/parameters/max_loop`
+               if [ ${MAX_LOOP} -eq 0 ]; then
+                       MAX_LOOP=255
+               fi
+
+               for (( i=0; i<=${MAX_LOOP}; i++ )); do
+                       DEVICE="/dev/loop$i"
+
+                       if [ -b "${DEVICE}" ]; then
+                               continue
+                       else
+                               mknod -m660 "${DEVICE}" b 7 $i
+                               chown root.disk "${DEVICE}"
+                               chmod 666 "${DEVICE}"
+
+                               echo "${DEVICE}"
+                               return 0
+                       fi
+               done
+       fi
+
+       die "Error: Unable to create new loopback device"
+}
+
+#
+# This can be slightly dangerous because the loop devices we are
+# cleaning up may not be ours.  However, if the devices are currently
+# in use we will not be able to remove them, and we only remove
+# devices which include 'zpool' or 'deleted' in the name.  So any
+# damage we might do should be limited to other zfs related testing.
+#
+cleanup_loop_devices() {
+       local TMP_FILE=`mktemp`
+
+       ${LOSETUP} -a | tr -d '()' >${TMP_FILE}
+       ${AWK} -F":" -v losetup="$LOSETUP" \
+           '/zpool/ || /deleted/ { system("losetup -d "$1) }' ${TMP_FILE}
+       ${AWK} -F" " '/zpool/ || /deleted/ { system("rm -f "$3) }' ${TMP_FILE}
+
+       rm -f ${TMP_FILE}
+}
+
+#
+# Destroy the passed loopback devices, this is used when you know
+# the names of the loopback devices.
+#
+destroy_loop_devices() {
+       local LODEVICES="$1"
+
+       msg "Destroying ${LODEVICES}"
+       ${LOSETUP} -d ${LODEVICES} || \
+               die "Error $? destroying ${FILE} -> ${DEVICE} loopback"
+
+       rm -f ${FILES}
+       return 0
+}
+
+#
+# Create a device label taking care to briefly wait if udev needs to settle.
+#
+label() {
+       local DEVICE=$1
+       local LABEL=$2
+
+       wait_udev ${DEVICE} 30 || return 1
+       ${PARTED} ${DEVICE} --script -- mklabel ${LABEL} || return 2
+
+       return 0
+}
+
+#
+# Create a primary partition on a block device.
+#
+partition() {
+       local DEVICE=$1
+       local TYPE=$2
+       local START=$3
+       local END=$4
+
+       ${PARTED} --align optimal ${DEVICE} --script -- \
+           mkpart ${TYPE} ${START} ${END} || return 1
+       udev_trigger
+
+       return 0
+}
+
+#
+# Create a filesystem on the block device
+#
+format() {
+       local DEVICE=$1
+       local FSTYPE=$2
+
+       # Force 4K blocksize, else mkfs.ext2 tries to use 8K, which
+       # won't mount
+       /sbin/mkfs.${FSTYPE} -b 4096 -F -q ${DEVICE} >/dev/null || return 1
+
+       return 0
+}
+
+#
+# Check that the mdadm utilities are installed.
+#
+check_md_utils() {
+        test -f ${MDADM} || die "${MDADM} utility must be installed"
+       test -f ${PARTED} || die "${PARTED} utility must be installed"
+}
+
+check_md_partitionable() {
+       local LOFILE=`mktemp -p /tmp zpool-lo.XXXXXXXX`
+       local LODEVICE=`unused_loop_device`
+       local MDDEVICE=`unused_md_device`
+       local RESULT=1
+
+       check_md_utils
+
+       rm -f ${LOFILE}
+       dd if=/dev/zero of=${LOFILE} bs=1M count=0 seek=16 \
+               &>/dev/null || return ${RESULT}
+
+       msg "Creating ${LODEVICE} using ${LOFILE}"
+       ${LOSETUP} ${LODEVICE} ${LOFILE}
+       if [ $? -ne 0 ]; then
+               rm -f ${LOFILE}
+               return ${RESULT}
+       fi
+
+       msg "Creating ${MDDEVICE} using ${LODEVICE}"
+       ${MDADM} --build ${MDDEVICE} --level=faulty \
+               --raid-devices=1 ${LODEVICE} &>/dev/null
+       if [ $? -ne 0 ]; then
+               destroy_loop_devices ${LODEVICE}
+               rm -f ${LOFILE}
+               return ${RESULT}
+       fi
+       wait_udev ${MDDEVICE} 30
+
+       ${BLOCKDEV} --rereadpt ${MDDEVICE} 2>/dev/null
+       RESULT=$?
+
+       destroy_md_devices ${MDDEVICE}
+       destroy_loop_devices ${LODEVICE}
+       rm -f ${LOFILE}
+
+       return ${RESULT}
+}
+
+#
+# Find and return an unused md device.
+#
+unused_md_device() {
+       for (( i=0; i<32; i++ )); do
+               MDDEVICE=md${i}
+
+               # Skip active devicesudo in /proc/mdstat.
+               grep -q "${MDDEVICE} " /proc/mdstat && continue
+
+               # Device doesn't exist, use it.
+               if [ ! -e $/dev/{MDDEVICE} ]; then
+                       echo /dev/${MDDEVICE}
+                       return
+               fi
+
+               # Device exists but may not be in use.
+               if [ -b /dev/${MDDEVICE} ]; then
+                       ${MDADM} --detail /dev/${MDDEVICE} &>/dev/null
+                       if [ $? -eq 1 ]; then
+                               echo /dev/${MDDEVICE}
+                               return
+                       fi
+               fi
+        done
+
+        die "Error: Unable to find unused md device"
+}
+
+#
+# This can be slightly dangerous because it is possible the md devices
+# we are cleaning up may not be ours.  However, if the devices are
+# currently in use we will not be able to remove them, and even if
+# we remove devices which were not out we do not zero the super block
+# so you should be able to reconstruct them.
+#
+cleanup_md_devices() {
+       destroy_md_devices "`ls /dev/md* 2>/dev/null | grep -v p`"
+       udev_trigger
+}
+
+#
+# Destroy the passed md devices, this is used when you know
+# the names of the md devices.
+#
+destroy_md_devices() {
+       local MDDEVICES="$1"
+
+       msg "Destroying ${MDDEVICES}"
+       for MDDEVICE in ${MDDEVICES}; do
+               ${MDADM} --stop ${MDDEVICE} &>/dev/null
+               ${MDADM} --remove ${MDDEVICE} &>/dev/null
+               ${MDADM} --detail ${MDDEVICE} &>/dev/null
+       done
+
+       return 0
+}
+
+#
+# Check that the scsi utilities are installed.
+#
+check_sd_utils() {
+       ${INFOMOD} scsi_debug &>/dev/null || die "scsi_debug module required"
+       test -f ${LSSCSI} || die "${LSSCSI} utility must be installed"
+}
+
+#
+# Rescan the scsi bus for scsi_debug devices.  It is preferable to use the
+# scsi-rescan tool if it is installed, but if it's not we can fall back to
+# removing and readding the device manually.  This rescan will only effect
+# the first scsi_debug device if scsi-rescan is missing.
+#
+scsi_rescan() {
+       local AWK_SCRIPT="/scsi_debug/ { print \$1; exit }"
+
+       if [ -f ${SCSIRESCAN} ]; then
+               ${SCSIRESCAN} --forcerescan --remove &>/dev/null
+       else
+               local SCSIID=`${LSSCSI} | ${AWK} "${AWK_SCRIPT}" | tr -d '[]'`
+               local SCSIHOST=`echo ${SCSIID} | cut -f1 -d':'`
+               echo 1 >"/sys/class/scsi_device/${SCSIID}/device/delete"
+               udev_trigger
+               echo "- - -" >/sys/class/scsi_host/host${SCSIHOST}/scan
+               udev_trigger
+       fi
+}
+
+#
+# Trigger udev and wait for it to settle.
+#
+udev_trigger() {
+       if [ -f ${UDEVADM} ]; then
+               ${UDEVADM} trigger --action=change --subsystem-match=block
+               ${UDEVADM} settle
+       else
+               /sbin/udevtrigger
+               /sbin/udevsettle
+       fi
+}
+
+#
+# The following udev helper functions assume that the provided
+# udev rules file will create a /dev/disk/by-vdev/<CHANNEL><RANK>
+# disk mapping.  In this mapping each CHANNEL is represented by
+# the letters a-z, and the RANK is represented by the numbers
+# 1-n.  A CHANNEL should identify a group of RANKS which are all
+# attached to a single controller, each RANK represents a disk.
+# This provides a simply mechanism to locate a specific drive
+# given a known hardware configuration.
+#
+udev_setup() {
+       local SRC_PATH=$1
+
+       # When running in tree manually contruct symlinks in tree to
+       # the proper devices.  Symlinks are installed for all entires
+       # in the config file regardless of if that device actually
+       # exists.  When installed as a package udev can be relied on for
+       # this and it will only create links for devices which exist.
+       if [ ${INTREE} ]; then
+               PWD=`pwd`
+               mkdir -p ${DEVDIR}/
+               cd ${DEVDIR}/
+               ${AWK} '!/^#/ && /./ { system( \
+                       "ln -f -s /dev/disk/by-path/"$2" "$1";" \
+                       "ln -f -s /dev/disk/by-path/"$2"-part1 "$1"p1;" \
+                       "ln -f -s /dev/disk/by-path/"$2"-part9 "$1"p9;" \
+                       ) }' $SRC_PATH
+               cd ${PWD}
+       else
+               DST_FILE=`basename ${SRC_PATH} | cut -f1-2 -d'.'`
+               DST_PATH=/etc/zfs/${DST_FILE}
+
+               if [ -e ${DST_PATH} ]; then
+                       die "Error: Config ${DST_PATH} already exists"
+               fi
+
+               cp ${SRC_PATH} ${DST_PATH}
+               udev_trigger
+       fi
+
+       return 0
+}
+
+udev_cleanup() {
+       local SRC_PATH=$1
+
+       if [ ${INTREE} ]; then
+               PWD=`pwd`
+               cd ${DEVDIR}/
+               ${AWK} '!/^#/ && /./ { system( \
+                       "rm -f "$1" "$1"p1 "$1"p9") }' $SRC_PATH
+               cd ${PWD}
+       fi
+
+       return 0
+}
+
+udev_cr2d() {
+       local CHANNEL=`echo "obase=16; $1+96" | bc`
+       local RANK=$2
+
+       printf "\x${CHANNEL}${RANK}"
+}
+
+udev_raid0_setup() {
+       local RANKS=$1
+       local CHANNELS=$2
+       local IDX=0
+
+       RAID0S=()
+       for RANK in `seq 1 ${RANKS}`; do
+               for CHANNEL in `seq 1 ${CHANNELS}`; do
+                       DISK=`udev_cr2d ${CHANNEL} ${RANK}`
+                       RAID0S[${IDX}]="${DEVDIR}/${DISK}"
+                       let IDX=IDX+1
+               done
+       done
+
+       return 0
+}
+
+udev_raid10_setup() {
+       local RANKS=$1
+       local CHANNELS=$2
+       local IDX=0
+
+       RAID10S=()
+       for RANK in `seq 1 ${RANKS}`; do
+               for CHANNEL1 in `seq 1 2 ${CHANNELS}`; do
+                       let CHANNEL2=CHANNEL1+1
+                       DISK1=`udev_cr2d ${CHANNEL1} ${RANK}`
+                       DISK2=`udev_cr2d ${CHANNEL2} ${RANK}`
+                       GROUP="${DEVDIR}/${DISK1} ${DEVDIR}/${DISK2}"
+                       RAID10S[${IDX}]="mirror ${GROUP}"
+                       let IDX=IDX+1
+               done
+       done
+
+       return 0
+}
+
+udev_raidz_setup() {
+       local RANKS=$1
+       local CHANNELS=$2
+
+       RAIDZS=()
+       for RANK in `seq 1 ${RANKS}`; do
+               RAIDZ=("raidz")
+
+               for CHANNEL in `seq 1 ${CHANNELS}`; do
+                       DISK=`udev_cr2d ${CHANNEL} ${RANK}`
+                       RAIDZ[${CHANNEL}]="${DEVDIR}/${DISK}"
+               done
+
+               RAIDZS[${RANK}]="${RAIDZ[*]}"
+       done
+
+       return 0
+}
+
+udev_raidz2_setup() {
+       local RANKS=$1
+       local CHANNELS=$2
+
+       RAIDZ2S=()
+       for RANK in `seq 1 ${RANKS}`; do
+               RAIDZ2=("raidz2")
+
+               for CHANNEL in `seq 1 ${CHANNELS}`; do
+                       DISK=`udev_cr2d ${CHANNEL} ${RANK}`
+                       RAIDZ2[${CHANNEL}]="${DEVDIR}/${DISK}"
+               done
+
+               RAIDZ2S[${RANK}]="${RAIDZ2[*]}"
+       done
+
+       return 0
+}
+
+run_one_test() {
+       local TEST_NUM=$1
+       local TEST_NAME=$2
+
+       printf "%-4d %-34s " ${TEST_NUM} "${TEST_NAME}"
+       test_${TEST_NUM}
+}
+
+skip_one_test() {
+       local TEST_NUM=$1
+       local TEST_NAME=$2
+
+       printf "%-4d %-34s " ${TEST_NUM} "${TEST_NAME}"
+       skip
+}
+
+run_test() {
+       local TEST_NUM=$1
+       local TEST_NAME=$2
+
+       for i in ${TESTS_SKIP[@]}; do
+               if [[ $i == ${TEST_NUM} ]] ; then
+                       skip_one_test ${TEST_NUM} "${TEST_NAME}"
+                       return 0
+               fi
+       done
+
+       if [ "${TESTS_RUN[0]}" = "*" ]; then
+               run_one_test ${TEST_NUM} "${TEST_NAME}"
+       else
+               for i in ${TESTS_RUN[@]}; do
+                       if [[ $i == ${TEST_NUM} ]] ; then
+                               run_one_test ${TEST_NUM} "${TEST_NAME}"
+                               return 0
+                       fi
+               done
+
+               skip_one_test ${TEST_NUM} "${TEST_NAME}"
+       fi
+}
+
+wait_udev() {
+       local DEVICE=$1
+       local DELAY=$2
+       local COUNT=0
+
+       udev_trigger
+       while [ ! -e ${DEVICE} ]; do
+               if [ ${COUNT} -gt ${DELAY} ]; then
+                       return 1
+               fi
+
+               let COUNT=${COUNT}+1
+               sleep 1
+       done
+
+       return 0
+}
+
+stack_clear() {
+       local STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size
+       local STACK_TRACER_ENABLED=/proc/sys/kernel/stack_tracer_enabled
+
+       if [ -e $STACK_MAX_SIZE ]; then
+               echo 1 >$STACK_TRACER_ENABLED
+               echo 0 >$STACK_MAX_SIZE
+       fi
+}
+
+stack_check() {
+       local STACK_MAX_SIZE=/sys/kernel/debug/tracing/stack_max_size
+       local STACK_TRACE=/sys/kernel/debug/tracing/stack_trace
+       local STACK_LIMIT=7000
+
+       if [ -e $STACK_MAX_SIZE ]; then
+               STACK_SIZE=`cat $STACK_MAX_SIZE`
+
+               if [ $STACK_SIZE -ge $STACK_LIMIT ]; then
+                       echo
+                       echo "Warning: max stack size $STACK_SIZE bytes"
+                       cat $STACK_TRACE
+               fi
+       fi
+}
+
+kill_zed() {
+        if [ -f $ZED_PIDFILE ]; then
+               kill $(cat $ZED_PIDFILE)
+        fi
+}
diff --git a/zfs/scripts/cstyle.pl b/zfs/scripts/cstyle.pl
new file mode 100755 (executable)
index 0000000..7baf255
--- /dev/null
@@ -0,0 +1,963 @@
+#!/usr/bin/perl -w
+#
+# 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.
+#
+# @(#)cstyle 1.58 98/09/09 (from shannon)
+#ident "%Z%%M% %I%     %E% SMI"
+#
+# cstyle - check for some common stylistic errors.
+#
+#      cstyle is a sort of "lint" for C coding style.
+#      It attempts to check for the style used in the
+#      kernel, sometimes known as "Bill Joy Normal Form".
+#
+#      There's a lot this can't check for, like proper indentation
+#      of code blocks.  There's also a lot more this could check for.
+#
+#      A note to the non perl literate:
+#
+#              perl regular expressions are pretty much like egrep
+#              regular expressions, with the following special symbols
+#
+#              \s      any space character
+#              \S      any non-space character
+#              \w      any "word" character [a-zA-Z0-9_]
+#              \W      any non-word character
+#              \d      a digit [0-9]
+#              \D      a non-digit
+#              \b      word boundary (between \w and \W)
+#              \B      non-word boundary
+#
+
+require 5.0;
+use IO::File;
+use Getopt::Std;
+use strict;
+
+my $usage =
+"usage: cstyle [-chpvCP] [-o constructs] file ...
+       -c      check continuation indentation inside functions
+       -h      perform heuristic checks that are sometimes wrong
+       -p      perform some of the more picky checks
+       -v      verbose
+       -C      don't check anything in header block comments
+       -P      check for use of non-POSIX types
+       -o constructs
+               allow a comma-seperated list of optional constructs:
+                   doxygen     allow doxygen-style block comments (/** /*!)
+                   splint      allow splint-style lint comments (/*@ ... @*/)
+";
+
+my %opts;
+
+if (!getopts("cho:pvCP", \%opts)) {
+       print $usage;
+       exit 2;
+}
+
+my $check_continuation = $opts{'c'};
+my $heuristic = $opts{'h'};
+my $picky = $opts{'p'};
+my $verbose = $opts{'v'};
+my $ignore_hdr_comment = $opts{'C'};
+my $check_posix_types = $opts{'P'};
+
+my $doxygen_comments = 0;
+my $splint_comments = 0;
+
+if (defined($opts{'o'})) {
+       for my $x (split /,/, $opts{'o'}) {
+               if ($x eq "doxygen") {
+                       $doxygen_comments = 1;
+               } elsif ($x eq "splint") {
+                       $splint_comments = 1;
+               } else {
+                       print "cstyle: unrecognized construct \"$x\"\n";
+                       print $usage;
+                       exit 2;
+               }
+       }
+}
+
+my ($filename, $line, $prev);          # shared globals
+
+my $fmt;
+my $hdr_comment_start;
+
+if ($verbose) {
+       $fmt = "%s: %d: %s\n%s\n";
+} else {
+       $fmt = "%s: %d: %s\n";
+}
+
+if ($doxygen_comments) {
+       # doxygen comments look like "/*!" or "/**"; allow them.
+       $hdr_comment_start = qr/^\s*\/\*[\!\*]?$/;
+} else {
+       $hdr_comment_start = qr/^\s*\/\*$/;
+}
+
+# Note, following must be in single quotes so that \s and \w work right.
+my $typename = '(int|char|short|long|unsigned|float|double' .
+    '|\w+_t|struct\s+\w+|union\s+\w+|FILE)';
+
+# mapping of old types to POSIX compatible types
+my %old2posix = (
+       'unchar' => 'uchar_t',
+       'ushort' => 'ushort_t',
+       'uint' => 'uint_t',
+       'ulong' => 'ulong_t',
+       'u_int' => 'uint_t',
+       'u_short' => 'ushort_t',
+       'u_long' => 'ulong_t',
+       'u_char' => 'uchar_t',
+       'quad' => 'quad_t'
+);
+
+my $lint_re = qr/\/\*(?:
+       ARGSUSED[0-9]*|NOTREACHED|LINTLIBRARY|VARARGS[0-9]*|
+       CONSTCOND|CONSTANTCOND|CONSTANTCONDITION|EMPTY|
+       FALLTHRU|FALLTHROUGH|LINTED.*?|PRINTFLIKE[0-9]*|
+       PROTOLIB[0-9]*|SCANFLIKE[0-9]*|CSTYLED.*?
+    )\*\//x;
+
+my $splint_re = qr/\/\*@.*?@\*\//x;
+
+my $warlock_re = qr/\/\*\s*(?:
+       VARIABLES\ PROTECTED\ BY|
+       MEMBERS\ PROTECTED\ BY|
+       ALL\ MEMBERS\ PROTECTED\ BY|
+       READ-ONLY\ VARIABLES:|
+       READ-ONLY\ MEMBERS:|
+       VARIABLES\ READABLE\ WITHOUT\ LOCK:|
+       MEMBERS\ READABLE\ WITHOUT\ LOCK:|
+       LOCKS\ COVERED\ BY|
+       LOCK\ UNNEEDED\ BECAUSE|
+       LOCK\ NEEDED:|
+       LOCK\ HELD\ ON\ ENTRY:|
+       READ\ LOCK\ HELD\ ON\ ENTRY:|
+       WRITE\ LOCK\ HELD\ ON\ ENTRY:|
+       LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
+       READ\ LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
+       WRITE\ LOCK\ ACQUIRED\ AS\ SIDE\ EFFECT:|
+       LOCK\ RELEASED\ AS\ SIDE\ EFFECT:|
+       LOCK\ UPGRADED\ AS\ SIDE\ EFFECT:|
+       LOCK\ DOWNGRADED\ AS\ SIDE\ EFFECT:|
+       FUNCTIONS\ CALLED\ THROUGH\ POINTER|
+       FUNCTIONS\ CALLED\ THROUGH\ MEMBER|
+       LOCK\ ORDER:
+    )/x;
+
+my $err_stat = 0;              # exit status
+
+if ($#ARGV >= 0) {
+       foreach my $arg (@ARGV) {
+               my $fh = new IO::File $arg, "r";
+               if (!defined($fh)) {
+                       printf "%s: can not open\n", $arg;
+               } else {
+                       &cstyle($arg, $fh);
+                       close $fh;
+               }
+       }
+} else {
+       &cstyle("<stdin>", *STDIN);
+}
+exit $err_stat;
+
+my $no_errs = 0;               # set for CSTYLED-protected lines
+
+sub err($) {
+       my ($error) = @_;
+       unless ($no_errs) {
+               if ($verbose) {
+                       printf $fmt, $filename, $., $error, $line;
+               } else {
+                       printf $fmt, $filename, $., $error;
+               }       
+               $err_stat = 1;
+       }
+}
+
+sub err_prefix($$) {
+       my ($prevline, $error) = @_;
+       my $out = $prevline."\n".$line;
+       unless ($no_errs) {
+               if ($verbose) {
+                       printf $fmt, $filename, $., $error, $out;
+               } else {
+                       printf $fmt, $filename, $., $error;
+               }
+               $err_stat = 1;
+       }
+}
+
+sub err_prev($) {
+       my ($error) = @_;
+       unless ($no_errs) {
+               if ($verbose) {
+                       printf $fmt, $filename, $. - 1, $error, $prev;
+               } else {
+                       printf $fmt, $filename, $. - 1, $error;
+               }
+               $err_stat = 1;
+       }
+}
+
+sub cstyle($$) {
+
+my ($fn, $filehandle) = @_;
+$filename = $fn;                       # share it globally
+
+my $in_cpp = 0;
+my $next_in_cpp = 0;
+
+my $in_comment = 0;
+my $in_header_comment = 0;
+my $comment_done = 0;
+my $in_warlock_comment = 0;
+my $in_function = 0;
+my $in_function_header = 0;
+my $in_declaration = 0;
+my $note_level = 0;
+my $nextok = 0;
+my $nocheck = 0;
+
+my $in_string = 0;
+
+my ($okmsg, $comment_prefix);
+
+$line = '';
+$prev = '';
+reset_indent();
+
+line: while (<$filehandle>) {
+       s/\r?\n$//;     # strip return and newline
+
+       # save the original line, then remove all text from within
+       # double or single quotes, we do not want to check such text.
+
+       $line = $_;
+
+       #
+       # C allows strings to be continued with a backslash at the end of
+       # the line.  We translate that into a quoted string on the previous
+       # line followed by an initial quote on the next line.
+       #
+       # (we assume that no-one will use backslash-continuation with character
+       # constants)
+       #
+       $_ = '"' . $_           if ($in_string && !$nocheck && !$in_comment);
+
+       #
+       # normal strings and characters
+       #
+       s/'([^\\']|\\[^xX0]|\\0[0-9]*|\\[xX][0-9a-fA-F]*)'/''/g;
+       s/"([^\\"]|\\.)*"/\"\"/g;
+
+       #
+       # detect string continuation
+       #
+       if ($nocheck || $in_comment) {
+               $in_string = 0;
+       } else {
+               #
+               # Now that all full strings are replaced with "", we check
+               # for unfinished strings continuing onto the next line.
+               #
+               $in_string =
+                   (s/([^"](?:"")*)"([^\\"]|\\.)*\\$/$1""/ ||
+                   s/^("")*"([^\\"]|\\.)*\\$/""/);
+       }
+
+       #
+       # figure out if we are in a cpp directive
+       #
+       $in_cpp = $next_in_cpp || /^\s*#/;      # continued or started
+       $next_in_cpp = $in_cpp && /\\$/;        # only if continued
+
+       # strip off trailing backslashes, which appear in long macros
+       s/\s*\\$//;
+
+       # an /* END CSTYLED */ comment ends a no-check block.
+       if ($nocheck) {
+               if (/\/\* *END *CSTYLED *\*\//) {
+                       $nocheck = 0;
+               } else {
+                       reset_indent();
+                       next line;
+               }
+       }
+
+       # a /*CSTYLED*/ comment indicates that the next line is ok.
+       if ($nextok) {
+               if ($okmsg) {
+                       err($okmsg);
+               }
+               $nextok = 0;
+               $okmsg = 0;
+               if (/\/\* *CSTYLED.*\*\//) {
+                       /^.*\/\* *CSTYLED *(.*) *\*\/.*$/;
+                       $okmsg = $1;
+                       $nextok = 1;
+               }
+               $no_errs = 1;
+       } elsif ($no_errs) {
+               $no_errs = 0;
+       }
+
+       # check length of line.
+       # first, a quick check to see if there is any chance of being too long.
+       if (($line =~ tr/\t/\t/) * 7 + length($line) > 80) {
+               # yes, there is a chance.
+               # replace tabs with spaces and check again.
+               my $eline = $line;
+               1 while $eline =~
+                   s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
+               if (length($eline) > 80) {
+                       err("line > 80 characters");
+               }
+       }
+
+       # ignore NOTE(...) annotations (assumes NOTE is on lines by itself).
+       if ($note_level || /\b_?NOTE\s*\(/) { # if in NOTE or this is NOTE
+               s/[^()]//g;                       # eliminate all non-parens
+               $note_level += s/\(//g - length;  # update paren nest level
+               next;
+       }
+
+       # a /* BEGIN CSTYLED */ comment starts a no-check block.
+       if (/\/\* *BEGIN *CSTYLED *\*\//) {
+               $nocheck = 1;
+       }
+
+       # a /*CSTYLED*/ comment indicates that the next line is ok.
+       if (/\/\* *CSTYLED.*\*\//) {
+               /^.*\/\* *CSTYLED *(.*) *\*\/.*$/;
+               $okmsg = $1;
+               $nextok = 1;
+       }
+       if (/\/\/ *CSTYLED/) {
+               /^.*\/\/ *CSTYLED *(.*)$/;
+               $okmsg = $1;
+               $nextok = 1;
+       }
+
+       # universal checks; apply to everything
+       if (/\t +\t/) {
+               err("spaces between tabs");
+       }
+       if (/ \t+ /) {
+               err("tabs between spaces");
+       }
+       if (/\s$/) {
+               err("space or tab at end of line");
+       }
+       if (/[^ \t(]\/\*/ && !/\w\(\/\*.*\*\/\);/) {
+               err("comment preceded by non-blank");
+       }
+
+       # is this the beginning or ending of a function?
+       # (not if "struct foo\n{\n")
+       if (/^{$/ && $prev =~ /\)\s*(const\s*)?(\/\*.*\*\/\s*)?\\?$/) {
+               $in_function = 1;
+               $in_declaration = 1;
+               $in_function_header = 0;
+               $prev = $line;
+               next line;
+       }
+       if (/^}\s*(\/\*.*\*\/\s*)*$/) {
+               if ($prev =~ /^\s*return\s*;/) {
+                       err_prev("unneeded return at end of function");
+               }
+               $in_function = 0;
+               reset_indent();         # we don't check between functions
+               $prev = $line;
+               next line;
+       }
+       if (/^\w*\($/) {
+               $in_function_header = 1;
+       }
+
+       if ($in_warlock_comment && /\*\//) {
+               $in_warlock_comment = 0;
+               $prev = $line;
+               next line;
+       }
+
+       # a blank line terminates the declarations within a function.
+       # XXX - but still a problem in sub-blocks.
+       if ($in_declaration && /^$/) {
+               $in_declaration = 0;
+       }
+
+       if ($comment_done) {
+               $in_comment = 0;
+               $in_header_comment = 0;
+               $comment_done = 0;
+       }
+       # does this looks like the start of a block comment?
+       if (/$hdr_comment_start/) {
+               if (!/^\t*\/\*/) {
+                       err("block comment not indented by tabs");
+               }
+               $in_comment = 1;
+               /^(\s*)\//;
+               $comment_prefix = $1;
+               if ($comment_prefix eq "") {
+                       $in_header_comment = 1;
+               }
+               $prev = $line;
+               next line;
+       }
+       # are we still in the block comment?
+       if ($in_comment) {
+               if (/^$comment_prefix \*\/$/) {
+                       $comment_done = 1;
+               } elsif (/\*\//) {
+                       $comment_done = 1;
+                       err("improper block comment close")
+                           unless ($ignore_hdr_comment && $in_header_comment);
+               } elsif (!/^$comment_prefix \*[ \t]/ &&
+                   !/^$comment_prefix \*$/) {
+                       err("improper block comment")
+                           unless ($ignore_hdr_comment && $in_header_comment);
+               }
+       }
+
+       if ($in_header_comment && $ignore_hdr_comment) {
+               $prev = $line;
+               next line;
+       }
+
+       # check for errors that might occur in comments and in code.
+
+       # allow spaces to be used to draw pictures in all comments.
+       if (/[^ ]     / && !/".*     .*"/ && !$in_comment) {
+               err("spaces instead of tabs");
+       }
+       if (/^ / && !/^ \*[ \t\/]/ && !/^ \*$/ &&
+           (!/^    \w/ || $in_function != 0)) {
+               err("indent by spaces instead of tabs");
+       }
+       if (/^\t+ [^ \t\*]/ || /^\t+  \S/ || /^\t+   \S/) {
+               err("continuation line not indented by 4 spaces");
+       }
+       if (/$warlock_re/ && !/\*\//) {
+               $in_warlock_comment = 1;
+               $prev = $line;
+               next line;
+       }
+       if (/^\s*\/\*./ && !/^\s*\/\*.*\*\// && !/$hdr_comment_start/) {
+               err("improper first line of block comment");
+       }
+
+       if ($in_comment) {      # still in comment, don't do further checks
+               $prev = $line;
+               next line;
+       }
+
+       if ((/[^(]\/\*\S/ || /^\/\*\S/) &&
+           !(/$lint_re/ || ($splint_comments && /$splint_re/))) {
+               err("missing blank after open comment");
+       }
+       if (/\S\*\/[^)]|\S\*\/$/ &&
+           !(/$lint_re/ || ($splint_comments && /$splint_re/))) {
+               err("missing blank before close comment");
+       }
+       if (/\/\/\S/) {         # C++ comments
+               err("missing blank after start comment");
+       }
+       # check for unterminated single line comments, but allow them when
+       # they are used to comment out the argument list of a function
+       # declaration.
+       if (/\S.*\/\*/ && !/\S.*\/\*.*\*\// && !/\(\/\*/) {
+               err("unterminated single line comment");
+       }
+
+       if (/^(#else|#endif|#include)(.*)$/) {
+               $prev = $line;
+               if ($picky) {
+                       my $directive = $1;
+                       my $clause = $2;
+                       # Enforce ANSI rules for #else and #endif: no noncomment
+                       # identifiers are allowed after #endif or #else.  Allow
+                       # C++ comments since they seem to be a fact of life.
+                       if ((($1 eq "#endif") || ($1 eq "#else")) &&
+                           ($clause ne "") &&
+                           (!($clause =~ /^\s+\/\*.*\*\/$/)) &&
+                           (!($clause =~ /^\s+\/\/.*$/))) {
+                               err("non-comment text following " .
+                                   "$directive (or malformed $directive " .
+                                   "directive)");
+                       }
+               }
+               next line;
+       }
+
+       #
+       # delete any comments and check everything else.  Note that
+       # ".*?" is a non-greedy match, so that we don't get confused by
+       # multiple comments on the same line.
+       #
+       s/\/\*.*?\*\//\ 1/g;
+       s/\/\/.*$/\ 1/;           # C++ comments
+
+       # delete any trailing whitespace; we have already checked for that.
+       s/\s*$//;
+
+       # following checks do not apply to text in comments.
+
+       if (/[^<>\s][!<>=]=/ || /[^<>][!<>=]=[^\s,]/ ||
+           (/[^->]>[^,=>\s]/ && !/[^->]>$/) ||
+           (/[^<]<[^,=<\s]/ && !/[^<]<$/) ||
+           /[^<\s]<[^<]/ || /[^->\s]>[^>]/) {
+               err("missing space around relational operator");
+       }
+       if (/\S>>=/ || /\S<<=/ || />>=\S/ || /<<=\S/ || /\S[-+*\/&|^%]=/ ||
+           (/[^-+*\/&|^%!<>=\s]=[^=]/ && !/[^-+*\/&|^%!<>=\s]=$/) ||
+           (/[^!<>=]=[^=\s]/ && !/[^!<>=]=$/)) {
+               # XXX - should only check this for C++ code
+               # XXX - there are probably other forms that should be allowed
+               if (!/\soperator=/) {
+                       err("missing space around assignment operator");
+               }
+       }
+       if (/[,;]\S/ && !/\bfor \(;;\)/) {
+               err("comma or semicolon followed by non-blank");
+       }
+       # allow "for" statements to have empty "while" clauses
+       if (/\s[,;]/ && !/^[\t]+;$/ && !/^\s*for \([^;]*; ;[^;]*\)/) {
+               err("comma or semicolon preceded by blank");
+       }
+       if (/^\s*(&&|\|\|)/) {
+               err("improper boolean continuation");
+       }
+       if (/\S   *(&&|\|\|)/ || /(&&|\|\|)   *\S/) {
+               err("more than one space around boolean operator");
+       }
+       if (/\b(for|if|while|switch|sizeof|return|case)\(/) {
+               err("missing space between keyword and paren");
+       }
+       if (/(\b(for|if|while|switch|return)\b.*){2,}/ && !/^#define/) {
+               # multiple "case" and "sizeof" allowed
+               err("more than one keyword on line");
+       }
+       if (/\b(for|if|while|switch|sizeof|return|case)\s\s+\(/ &&
+           !/^#if\s+\(/) {
+               err("extra space between keyword and paren");
+       }
+       # try to detect "func (x)" but not "if (x)" or
+       # "#define foo (x)" or "int (*func)();"
+       if (/\w\s\(/) {
+               my $s = $_;
+               # strip off all keywords on the line
+               s/\b(for|if|while|switch|return|case|sizeof)\s\(/XXX(/g;
+               s/#elif\s\(/XXX(/g;
+               s/^#define\s+\w+\s+\(/XXX(/;
+               # do not match things like "void (*f)();"
+               # or "typedef void (func_t)();"
+               s/\w\s\(+\*/XXX(*/g;
+               s/\b($typename|void)\s+\(+/XXX(/og;
+               if (/\w\s\(/) {
+                       err("extra space between function name and left paren");
+               }
+               $_ = $s;
+       }
+       # try to detect "int foo(x)", but not "extern int foo(x);"
+       # XXX - this still trips over too many legitimate things,
+       # like "int foo(x,\n\ty);"
+#              if (/^(\w+(\s|\*)+)+\w+\(/ && !/\)[;,](\s|\ 1)*$/ &&
+#                  !/^(extern|static)\b/) {
+#                      err("return type of function not on separate line");
+#              }
+       # this is a close approximation
+       if (/^(\w+(\s|\*)+)+\w+\(.*\)(\s|\ 1)*$/ &&
+           !/^(extern|static)\b/) {
+               err("return type of function not on separate line");
+       }
+       if (/^#define /) {
+               err("#define followed by space instead of tab");
+       }
+       if (/^\s*return\W[^;]*;/ && !/^\s*return\s*\(.*\);/) {
+               err("unparenthesized return expression");
+       }
+       if (/\bsizeof\b/ && !/\bsizeof\s*\(.*\)/) {
+               err("unparenthesized sizeof expression");
+       }
+       if (/\(\s/) {
+               err("whitespace after left paren");
+       }
+       # Allow "for" statements to have empty "continue" clauses.
+       # Allow right paren on its own line unless we're being picky (-p).
+       if (/\s\)/ && !/^\s*for \([^;]*;[^;]*; \)/ && ($picky || !/^\s*\)/)) {
+               err("whitespace before right paren");
+       }
+       if (/^\s*\(void\)[^ ]/) {
+               err("missing space after (void) cast");
+       }
+       if (/\S\{/ && !/\{\{/) {
+               err("missing space before left brace");
+       }
+       if ($in_function && /^\s+{/ &&
+           ($prev =~ /\)\s*$/ || $prev =~ /\bstruct\s+\w+$/)) {
+               err("left brace starting a line");
+       }
+       if (/}(else|while)/) {
+               err("missing space after right brace");
+       }
+       if (/}\s\s+(else|while)/) {
+               err("extra space after right brace");
+       }
+       if (/\b_VOID\b|\bVOID\b|\bSTATIC\b/) {
+               err("obsolete use of VOID or STATIC");
+       }
+       if (/\b$typename\*/o) {
+               err("missing space between type name and *");
+       }
+       if (/^\s+#/) {
+               err("preprocessor statement not in column 1");
+       }
+       if (/^#\s/) {
+               err("blank after preprocessor #");
+       }
+       if (/!\s*(strcmp|strncmp|bcmp)\s*\(/) {
+               err("don't use boolean ! with comparison functions");
+       }
+
+       #
+       # We completely ignore, for purposes of indentation:
+       #  * lines outside of functions
+       #  * preprocessor lines
+       #
+       if ($check_continuation && $in_function && !$in_cpp) {
+               process_indent($_);
+       }
+       if ($picky) {
+               # try to detect spaces after casts, but allow (e.g.)
+               # "sizeof (int) + 1", "void (*funcptr)(int) = foo;", and
+               # "int foo(int) __NORETURN;"
+               if ((/^\($typename( \*+)?\)\s/o ||
+                   /\W\($typename( \*+)?\)\s/o) &&
+                   !/sizeof\s*\($typename( \*)?\)\s/o &&
+                   !/\($typename( \*+)?\)\s+=[^=]/o) {
+                       err("space after cast");
+               }
+               if (/\b$typename\s*\*\s/o &&
+                   !/\b$typename\s*\*\s+const\b/o) {
+                       err("unary * followed by space");
+               }
+       }
+       if ($check_posix_types) {
+               # try to detect old non-POSIX types.
+               # POSIX requires all non-standard typedefs to end in _t,
+               # but historically these have been used.
+               if (/\b(unchar|ushort|uint|ulong|u_int|u_short|u_long|u_char|quad)\b/) {
+                       err("non-POSIX typedef $1 used: use $old2posix{$1} instead");
+               }
+       }
+       if ($heuristic) {
+               # cannot check this everywhere due to "struct {\n...\n} foo;"
+               if ($in_function && !$in_declaration &&
+                   /}./ && !/}\s+=/ && !/{.*}[;,]$/ && !/}(\s|\ 1)*$/ &&
+                   !/} (else|while)/ && !/}}/) {
+                       err("possible bad text following right brace");
+               }
+               # cannot check this because sub-blocks in
+               # the middle of code are ok
+               if ($in_function && /^\s+{/) {
+                       err("possible left brace starting a line");
+               }
+       }
+       if (/^\s*else\W/) {
+               if ($prev =~ /^\s*}$/) {
+                       err_prefix($prev,
+                           "else and right brace should be on same line");
+               }
+       }
+       $prev = $line;
+}
+
+if ($prev eq "") {
+       err("last line in file is blank");
+}
+
+}
+
+#
+# Continuation-line checking
+#
+# The rest of this file contains the code for the continuation checking
+# engine.  It's a pretty simple state machine which tracks the expression
+# depth (unmatched '('s and '['s).
+#
+# Keep in mind that the argument to process_indent() has already been heavily
+# processed; all comments have been replaced by control-A, and the contents of
+# strings and character constants have been elided.
+#
+
+my $cont_in;           # currently inside of a continuation
+my $cont_off;          # skipping an initializer or definition
+my $cont_noerr;                # suppress cascading errors
+my $cont_start;                # the line being continued
+my $cont_base;         # the base indentation
+my $cont_first;                # this is the first line of a statement
+my $cont_multiseg;     # this continuation has multiple segments
+
+my $cont_special;      # this is a C statement (if, for, etc.)
+my $cont_macro;                # this is a macro
+my $cont_case;         # this is a multi-line case
+
+my @cont_paren;                # the stack of unmatched ( and [s we've seen
+
+sub
+reset_indent()
+{
+       $cont_in = 0;
+       $cont_off = 0;
+}
+
+sub
+delabel($)
+{
+       #
+       # replace labels with tabs.  Note that there may be multiple
+       # labels on a line.
+       #
+       local $_ = $_[0];
+
+       while (/^(\t*)( *(?:(?:\w+\s*)|(?:case\b[^:]*)): *)(.*)$/) {
+               my ($pre_tabs, $label, $rest) = ($1, $2, $3);
+               $_ = $pre_tabs;
+               while ($label =~ s/^([^\t]*)(\t+)//) {
+                       $_ .= "\t" x (length($2) + length($1) / 8);
+               }
+               $_ .= ("\t" x (length($label) / 8)).$rest;
+       }
+
+       return ($_);
+}
+
+sub
+process_indent($)
+{
+       require strict;
+       local $_ = $_[0];                       # preserve the global $_
+
+       s/\ 1//g; # No comments
+       s/\s+$//;       # Strip trailing whitespace
+
+       return                  if (/^$/);      # skip empty lines
+
+       # regexps used below; keywords taking (), macros, and continued cases
+       my $special = '(?:(?:\}\s*)?else\s+)?(?:if|for|while|switch)\b';
+       my $macro = '[A-Z_][A-Z_0-9]*\(';
+       my $case = 'case\b[^:]*$';
+
+       # skip over enumerations, array definitions, initializers, etc.
+       if ($cont_off <= 0 && !/^\s*$special/ &&
+           (/(?:(?:\b(?:enum|struct|union)\s*[^\{]*)|(?:\s+=\s*)){/ ||
+           (/^\s*{/ && $prev =~ /=\s*(?:\/\*.*\*\/\s*)*$/))) {
+               $cont_in = 0;
+               $cont_off = tr/{/{/ - tr/}/}/;
+               return;
+       }
+       if ($cont_off) {
+               $cont_off += tr/{/{/ - tr/}/}/;
+               return;
+       }
+
+       if (!$cont_in) {
+               $cont_start = $line;
+
+               if (/^\t* /) {
+                       err("non-continuation indented 4 spaces");
+                       $cont_noerr = 1;                # stop reporting
+               }
+               $_ = delabel($_);       # replace labels with tabs
+
+               # check if the statement is complete
+               return          if (/^\s*\}?$/);
+               return          if (/^\s*\}?\s*else\s*\{?$/);
+               return          if (/^\s*do\s*\{?$/);
+               return          if (/{$/);
+               return          if (/}[,;]?$/);
+
+               # Allow macros on their own lines
+               return          if (/^\s*[A-Z_][A-Z_0-9]*$/);
+
+               # cases we don't deal with, generally non-kosher
+               if (/{/) {
+                       err("stuff after {");
+                       return;
+               }
+
+               # Get the base line, and set up the state machine
+               /^(\t*)/;
+               $cont_base = $1;
+               $cont_in = 1;
+               @cont_paren = ();
+               $cont_first = 1;
+               $cont_multiseg = 0;
+
+               # certain things need special processing
+               $cont_special = /^\s*$special/? 1 : 0;
+               $cont_macro = /^\s*$macro/? 1 : 0;
+               $cont_case = /^\s*$case/? 1 : 0;
+       } else {
+               $cont_first = 0;
+
+               # Strings may be pulled back to an earlier (half-)tabstop
+               unless ($cont_noerr || /^$cont_base    / ||
+                   (/^\t*(?:    )?(?:gettext\()?\"/ && !/^$cont_base\t/)) {
+                       err_prefix($cont_start,
+                           "continuation should be indented 4 spaces");
+               }
+       }
+
+       my $rest = $_;                  # keeps the remainder of the line
+
+       #
+       # The split matches 0 characters, so that each 'special' character
+       # is processed separately.  Parens and brackets are pushed and
+       # popped off the @cont_paren stack.  For normal processing, we wait
+       # until a ; or { terminates the statement.  "special" processing
+       # (if/for/while/switch) is allowed to stop when the stack empties,
+       # as is macro processing.  Case statements are terminated with a :
+       # and an empty paren stack.
+       #
+       foreach $_ (split /[^\(\)\[\]\{\}\;\:]*/) {
+               next            if (length($_) == 0);
+
+               # rest contains the remainder of the line
+               my $rxp = "[^\Q$_\E]*\Q$_\E";
+               $rest =~ s/^$rxp//;
+
+               if (/\(/ || /\[/) {
+                       push @cont_paren, $_;
+               } elsif (/\)/ || /\]/) {
+                       my $cur = $_;
+                       tr/\)\]/\(\[/;
+
+                       my $old = (pop @cont_paren);
+                       if (!defined($old)) {
+                               err("unexpected '$cur'");
+                               $cont_in = 0;
+                               last;
+                       } elsif ($old ne $_) {
+                               err("'$cur' mismatched with '$old'");
+                               $cont_in = 0;
+                               last;
+                       }
+
+                       #
+                       # If the stack is now empty, do special processing
+                       # for if/for/while/switch and macro statements.
+                       #
+                       next            if (@cont_paren != 0);
+                       if ($cont_special) {
+                               if ($rest =~ /^\s*{?$/) {
+                                       $cont_in = 0;
+                                       last;
+                               }
+                               if ($rest =~ /^\s*;$/) {
+                                       err("empty if/for/while body ".
+                                           "not on its own line");
+                                       $cont_in = 0;
+                                       last;
+                               }
+                               if (!$cont_first && $cont_multiseg == 1) {
+                                       err_prefix($cont_start,
+                                           "multiple statements continued ".
+                                           "over multiple lines");
+                                       $cont_multiseg = 2;
+                               } elsif ($cont_multiseg == 0) {
+                                       $cont_multiseg = 1;
+                               }
+                               # We've finished this section, start
+                               # processing the next.
+                               goto section_ended;
+                       }
+                       if ($cont_macro) {
+                               if ($rest =~ /^$/) {
+                                       $cont_in = 0;
+                                       last;
+                               }
+                       }
+               } elsif (/\;/) {
+                       if ($cont_case) {
+                               err("unexpected ;");
+                       } elsif (!$cont_special) {
+                               err("unexpected ;")     if (@cont_paren != 0);
+                               if (!$cont_first && $cont_multiseg == 1) {
+                                       err_prefix($cont_start,
+                                           "multiple statements continued ".
+                                           "over multiple lines");
+                                       $cont_multiseg = 2;
+                               } elsif ($cont_multiseg == 0) {
+                                       $cont_multiseg = 1;
+                               }
+                               if ($rest =~ /^$/) {
+                                       $cont_in = 0;
+                                       last;
+                               }
+                               if ($rest =~ /^\s*special/) {
+                                       err("if/for/while/switch not started ".
+                                           "on its own line");
+                               }
+                               goto section_ended;
+                       }
+               } elsif (/\{/) {
+                       err("{ while in parens/brackets") if (@cont_paren != 0);
+                       err("stuff after {")            if ($rest =~ /[^\s}]/);
+                       $cont_in = 0;
+                       last;
+               } elsif (/\}/) {
+                       err("} while in parens/brackets") if (@cont_paren != 0);
+                       if (!$cont_special && $rest !~ /^\s*(while|else)\b/) {
+                               if ($rest =~ /^$/) {
+                                       err("unexpected }");
+                               } else {
+                                       err("stuff after }");
+                               }
+                               $cont_in = 0;
+                               last;
+                       }
+               } elsif (/\:/ && $cont_case && @cont_paren == 0) {
+                       err("stuff after multi-line case") if ($rest !~ /$^/);
+                       $cont_in = 0;
+                       last;
+               }
+               next;
+section_ended:
+               # End of a statement or if/while/for loop.  Reset
+               # cont_special and cont_macro based on the rest of the
+               # line.
+               $cont_special = ($rest =~ /^\s*$special/)? 1 : 0;
+               $cont_macro = ($rest =~ /^\s*$macro/)? 1 : 0;
+               $cont_case = 0;
+               next;
+       }
+       $cont_noerr = 0                 if (!$cont_in);
+}
diff --git a/zfs/scripts/dkms.mkconf b/zfs/scripts/dkms.mkconf
new file mode 100755 (executable)
index 0000000..ad97f9b
--- /dev/null
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+PROG=$0
+
+pkgcfg=/etc/sysconfig/zfs
+
+while getopts "n:v:c:f:" opt; do
+       case $opt in
+               n) pkgname=$OPTARG ;;
+               v) pkgver=$OPTARG  ;;
+               c) pkgcfg=$OPTARG ;;
+               f) filename=$OPTARG ;;
+       esac
+done
+
+if [ -z "${pkgname}" -o -z "${pkgver}" -o -z "${filename}" ]; then
+       echo "Usage: $PROG -n <pkgname> -v <pkgver> -c <pkgcfg> -f <filename>"
+       exit 1
+fi
+
+cat >${filename} <<EOF
+PACKAGE_NAME="${pkgname}"
+PACKAGE_VERSION="${pkgver}"
+PACKAGE_CONFIG="${pkgcfg}"
+PRE_BUILD="configure
+  --prefix=/usr
+  --with-config=kernel
+  --with-linux=\${kernel_source_dir}
+  --with-linux-obj=\${kernel_source_dir}
+  --with-spl=\${source_tree}/spl-\${PACKAGE_VERSION}
+  --with-spl-obj=\${dkms_tree}/spl/\${PACKAGE_VERSION}/\${kernelver}/\${arch}
+  --with-spl-timeout=300
+  \$(
+    [[ -r \${PACKAGE_CONFIG} ]] \\
+    && source \${PACKAGE_CONFIG} \\
+    && shopt -q -s extglob \\
+    && \\
+    {
+      if [[ \${ZFS_DKMS_ENABLE_DEBUG,,} == @(y|yes) ]]
+      then
+        echo --enable-debug
+      fi
+      if [[ \${ZFS_DKMS_ENABLE_DMU_TX,,} == @(y|yes) ]]
+      then
+        echo --enable-debug-dmu-tx
+      fi
+    }
+  )
+"
+POST_BUILD="scripts/dkms.postbuild
+  -n \${PACKAGE_NAME}
+  -v \${PACKAGE_VERSION}
+  -a \${arch}
+  -k \${kernelver}
+  -t \${dkms_tree}
+"
+BUILD_DEPENDS[0]="spl"
+AUTOINSTALL="yes"
+REMAKE_INITRD="no"
+MAKE[0]="make"
+STRIP[0]="\$(
+  [[ -r \${PACKAGE_CONFIG} ]] \\
+  && source \${PACKAGE_CONFIG} \\
+  && shopt -q -s extglob \\
+  && [[ \${ZFS_DKMS_DISABLE_STRIP,,} == @(y|yes) ]] \\
+  && echo -n no
+)"
+STRIP[1]="\${STRIP[0]}"
+STRIP[2]="\${STRIP[0]}"
+STRIP[3]="\${STRIP[0]}"
+STRIP[4]="\${STRIP[0]}"
+STRIP[5]="\${STRIP[0]}"
+STRIP[6]="\${STRIP[0]}"
+BUILT_MODULE_NAME[0]="zavl"
+BUILT_MODULE_LOCATION[0]="module/avl/"
+DEST_MODULE_LOCATION[0]="/extra/avl/avl"
+BUILT_MODULE_NAME[1]="znvpair"
+BUILT_MODULE_LOCATION[1]="module/nvpair/"
+DEST_MODULE_LOCATION[1]="/extra/nvpair/znvpair"
+BUILT_MODULE_NAME[2]="zunicode"
+BUILT_MODULE_LOCATION[2]="module/unicode/"
+DEST_MODULE_LOCATION[2]="/extra/unicode/zunicode"
+BUILT_MODULE_NAME[3]="zcommon"
+BUILT_MODULE_LOCATION[3]="module/zcommon/"
+DEST_MODULE_LOCATION[3]="/extra/zcommon/zcommon"
+BUILT_MODULE_NAME[4]="zfs"
+BUILT_MODULE_LOCATION[4]="module/zfs/"
+DEST_MODULE_LOCATION[4]="/extra/zfs/zfs"
+BUILT_MODULE_NAME[5]="zpios"
+BUILT_MODULE_LOCATION[5]="module/zpios/"
+DEST_MODULE_LOCATION[5]="/extra/zpios/zpios"
+BUILT_MODULE_NAME[6]="icp"
+BUILT_MODULE_LOCATION[6]="module/icp/"
+DEST_MODULE_LOCATION[6]="/extra/icp/icp"
+EOF
diff --git a/zfs/scripts/dkms.postbuild b/zfs/scripts/dkms.postbuild
new file mode 100755 (executable)
index 0000000..3cbc7c7
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+PROG=$0
+
+while getopts "a:k:n:t:v:" opt; do
+       case $opt in
+               a) arch=$OPTARG    ;;
+               k) kver=$OPTARG    ;;
+               n) pkgname=$OPTARG ;;
+               t) tree=$OPTARG    ;;
+               v) pkgver=$OPTARG  ;;
+       esac
+done
+
+if [ -z "${arch}" -o -z "${kver}" -o -z "${pkgname}" -o \
+     -z "${tree}" -o -z "${pkgver}" ]; then
+       echo "Usage: $PROG -a <arch> -k <kver> -n <pkgname>" \
+            "-t <tree> -v <pkgver>"
+       exit 1
+fi
+
+cp ${tree}/${pkgname}/${pkgver}/build/zfs_config.h          \
+   ${tree}/${pkgname}/${pkgver}/build/module/Module.symvers \
+   ${tree}/${pkgname}/${pkgver}/${kver}/${arch}/
diff --git a/zfs/scripts/kmodtool b/zfs/scripts/kmodtool
new file mode 100755 (executable)
index 0000000..ce3f042
--- /dev/null
@@ -0,0 +1,592 @@
+#!/bin/bash
+
+# kmodtool - Helper script for building kernel module RPMs
+# Copyright (c) 2003-2012 Ville Skyttä <ville.skytta@iki.fi>,
+#                         Thorsten Leemhuis <fedora@leemhuis.info>
+#                         Nicolas Chauvet <kwizart@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+shopt -s extglob
+
+myprog="kmodtool-${repo}"
+myver="0.12.1"
+
+kmodname=
+build_kernels="current"
+kernels_known_variants=
+kernel_versions=
+kernel_versions_to_build_for=
+prefix=
+filterfile=
+target=
+buildroot=
+
+error_out()
+{
+       local errorlevel=${1}
+       shift
+       echo "Error: $@" >&2
+       # the next line is not multi-line safe -- not needed *yet*
+       echo "%global kmodtool_check echo \"kmodtool error: $@\"; exit ${errorlevel};"
+       exit ${errorlevel}
+}
+
+print_rpmtemplate_header()
+{
+       echo
+       echo '%global kmodinstdir_prefix  '${prefix}/lib/modules/
+       echo '%global kmodinstdir_postfix '/extra/${kmodname}/
+       echo '%global kernel_versions     '${kernel_versions}
+       echo
+}
+
+print_akmodtemplate ()
+{
+       echo
+       cat <<EOF
+
+%global akmod_install mkdir -p \$RPM_BUILD_ROOT/%{_usrsrc}/akmods/; \\\
+LANG=C rpmbuild --define "_sourcedir %{_sourcedir}" \\\
+--define "_srcrpmdir \$RPM_BUILD_ROOT/%{_usrsrc}/akmods/" \\\
+-bs --nodeps %{_specdir}/%{name}.spec ; \\\
+ln -s \$(ls \$RPM_BUILD_ROOT/%{_usrsrc}/akmods/) \$RPM_BUILD_ROOT/%{_usrsrc}/akmods/${kmodname}-kmod.latest
+
+%package -n akmod-${kmodname}
+Summary:       Akmod package for ${kmodname} kernel module(s) 
+Group:                 System Environment/Kernel
+Requires:   kmodtool
+Requires:      akmods
+%{?AkmodsBuildRequires:Requires: %{AkmodsBuildRequires}}
+# same requires and provides as a kmods package would have
+Requires:      ${kmodname}-kmod-common >= %{?epoch:%{epoch}:}%{version}
+Provides:      ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
+EOF
+
+       if [[ ${obsolete_name} ]]; then
+               echo "Provides:   akmod-${obsolete_name} = ${obsolete_version}"
+               echo "Obsoletes:  akmod-${obsolete_name} < ${obsolete_version}"
+       fi
+
+       cat <<EOF
+
+%description -n akmod-${kmodname}
+This package provides the akmod package for the ${kmodname} kernel modules.
+
+%posttrans -n akmod-${kmodname}
+nohup ${prefix}/sbin/akmods --from-akmod-posttrans --akmod ${kmodname} &> /dev/null &
+
+%files -n akmod-${kmodname}
+%defattr(-,root,root,-)
+%{_usrsrc}/akmods/*
+
+EOF
+}
+
+print_akmodmeta ()
+{
+               cat <<EOF
+%package      -n kmod-${kmodname}
+Summary:         Metapackage which tracks in ${kmodname} kernel module for newest kernel${dashvariant}
+Group:           System Environment/Kernel
+
+Provides:        ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
+Provides:        kmod-${kmodname}-xen = %{?epoch:%{epoch}:}%{version}-%{release}
+Provides:        kmod-${kmodname}-smp = %{?epoch:%{epoch}:}%{version}-%{release}
+Provides:        kmod-${kmodname}-PAE = %{?epoch:%{epoch}:}%{version}-%{release}
+Requires:        akmod-${kmodname} = %{?epoch:%{epoch}:}%{version}-%{release}
+EOF
+
+       if [[ ${obsolete_name} ]]; then
+               echo "Provides:        kmod-${obsolete_name} = ${obsolete_version}"
+               echo "Obsoletes:       kmod-${obsolete_name} < ${obsolete_version}"
+       fi
+cat <<EOF
+
+%description  -n kmod-${kmodname}${dashvariant}
+This is a meta-package without payload which sole purpose is to require the
+${kmodname} kernel module(s) for the newest kernel${dashvariant},
+to make sure you get it together with a new kernel.
+
+%files        -n kmod-${kmodname}${dashvariant}
+%defattr(644,root,root,755)
+EOF
+}
+
+print_rpmtemplate_per_kmodpkg ()
+{
+       if [[ "${1}" == "--custom" ]]; then
+               shift
+               local customkernel=true
+       elif [[ "${1}" == "--redhat" ]]; then
+               # this is needed for akmods
+               shift
+               local redhatkernel=true
+       fi
+
+       local kernel_uname_r=${1}
+       local kernel_variant="${2:+-${2}}"
+
+    # first part
+       cat <<EOF
+%package       -n kmod-${kmodname}-${kernel_uname_r}
+Summary:          ${kmodname} kernel module(s) for ${kernel_uname_r}
+Group:            System Environment/Kernel
+Provides:         kernel-modules-for-kernel = ${kernel_uname_r}
+Provides:         kmod-${kmodname}-uname-r = ${kernel_uname_r}
+Provides:         ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
+Requires:         ${kmodname}-kmod-common >= %{?epoch:%{epoch}:}%{version}
+Requires(post):   ${prefix}/sbin/depmod
+Requires(postun): ${prefix}/sbin/depmod
+EOF
+
+       if [[ ${obsolete_name} ]]; then
+               echo "Provides:        kmod-${obsolete_name}-${kernel_uname_r} = ${obsolete_version}"
+               echo "Obsoletes:       kmod-${obsolete_name}-${kernel_uname_r} < ${obsolete_version}"
+       fi
+
+       # second part
+       if [[ ! "${customkernel}" ]]; then
+            cat <<EOF
+Requires:         kernel-uname-r = ${kernel_uname_r}
+BuildRequires:   kernel-devel-uname-r = ${kernel_uname_r}
+%{?KmodsRequires:Requires: %{KmodsRequires}-uname-r = ${kernel_uname_r}}
+%{?KmodsRequires:BuildRequires: %{KmodsRequires}-uname-r = ${kernel_uname_r}}
+%post          -n kmod-${kmodname}-${kernel_uname_r}
+${prefix}/sbin/depmod -aeF /boot/System.map-${kernel_uname_r} ${kernel_uname_r} > /dev/null || :
+%postun        -n kmod-${kmodname}-${kernel_uname_r}
+${prefix}/sbin/depmod  -aF /boot/System.map-${kernel_uname_r} ${kernel_uname_r} &> /dev/null || :
+
+EOF
+       else
+         cat <<EOF
+%post          -n kmod-${kmodname}-${kernel_uname_r}
+[[ "$(uname -r)" == "${kernel_uname_r}"  ]] && ${prefix}/sbin/depmod -a > /dev/null || :
+%postun        -n kmod-${kmodname}-${kernel_uname_r}
+[[ "$(uname -r)" == "${kernel_uname_r}"  ]] && ${prefix}/sbin/depmod -a > /dev/null || :
+
+EOF
+       fi
+
+  # third part
+       cat <<EOF
+%description  -n kmod-${kmodname}-${kernel_uname_r}
+This package provides the ${kmodname} kernel modules built for the Linux
+kernel ${kernel_uname_r} for the %{_target_cpu} family of processors.
+%files        -n kmod-${kmodname}-${kernel_uname_r}
+%defattr(644,root,root,755)
+%dir $prefix/lib/modules/${kernel_uname_r}/extra
+${prefix}/lib/modules/${kernel_uname_r}/extra/${kmodname}/
+
+
+EOF
+}
+
+print_rpmtemplate_kmoddevelpkg ()
+{
+       if [[ "${1}" == "--custom" ]]; then
+               shift
+               local customkernel=true
+       elif [[ "${1}" == "--redhat" ]]; then
+               shift
+               local redhatkernel=true
+       fi
+
+       local kernel_uname_r=${1}
+
+       cat <<EOF
+%package       -n kmod-${kmodname}-devel
+Summary:          ${kmodname} kernel module(s) devel common
+Group:            System Environment/Kernel
+Provides:         ${kmodname}-devel-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
+EOF
+
+       if [[ ! ${customkernel} ]] && [[ ! ${redhatkernel} ]]; then
+               echo "Requires:        kmod-${kmodname}-devel-${kernel_uname_r} >= %{?epoch:%{epoch}:}%{version}-%{release}"
+       fi
+
+       if [[ ${obsolete_name} ]]; then
+               echo "Provides:        kmod-${obsolete_name}-devel = ${obsolete_version}"
+               echo "Obsoletes:       kmod-${obsolete_name}-devel < ${obsolete_version}"
+       fi
+
+       cat <<EOF
+%description  -n kmod-${kmodname}-devel
+This package provides the common header files to build kernel modules
+which depend on the ${kmodname} kernel module.  It may optionally require
+the ${kmodname}-devel-<kernel> objects for the newest kernel.
+
+%files        -n kmod-${kmodname}-devel
+%defattr(644,root,root,755)
+%{_usrsrc}/${kmodname}-%{version}
+EOF
+
+       for kernel in ${1}; do
+               local kernel_uname_r=${kernel}
+               echo "%exclude %{_usrsrc}/${kmodname}-%{version}/${kernel_uname_r}"
+       done
+
+       echo
+       echo
+}
+
+print_rpmtemplate_per_kmoddevelpkg ()
+{
+       if [[ "${1}" == "--custom" ]]; then
+               shift
+               local customkernel=true
+       elif [[ "${1}" == "--redhat" ]]; then
+               # this is needed for akmods
+               shift
+               local redhatkernel=true
+       fi
+
+       local kernel_uname_r=${1}
+       local kernel_variant="${2:+-${2}}"
+
+       # first part
+       cat <<EOF
+%package       -n kmod-${kmodname}-devel-${kernel_uname_r}
+Summary:          ${kmodname} kernel module(s) devel for ${kernel_uname_r}
+Group:            System Environment/Kernel
+Provides:         kernel-objects-for-kernel = ${kernel_uname_r}
+Provides:         ${kmodname}-devel-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
+Provides:         kmod-${kmodname}-devel-uname-r = ${kernel_uname_r}
+EOF
+
+       if [[ ${obsolete_name} ]]; then
+               echo "Provides:        kmod-${obsolete_name}-devel-${kernel_uname_r} = ${obsolete_version}"
+               echo "Obsoletes:       kmod-${obsolete_name}-devel-${kernel_uname_r} < ${obsolete_version}"
+       fi
+
+       # second part
+       if [[ ! "${customkernel}" ]]; then
+               cat <<EOF
+Requires:         kernel-devel-uname-r = ${kernel_uname_r}
+BuildRequires:    kernel-devel-uname-r = ${kernel_uname_r}
+%{?KmodsDevelRequires:Requires: %{KmodsDevelRequires}-uname-r = ${kernel_uname_r}}
+%{?KmodsDevelRequires:BuildRequires: %{KmodsDevelRequires}-uname-r = ${kernel_uname_r}}
+EOF
+       fi
+
+       # third part
+       cat <<EOF
+%description  -n kmod-${kmodname}-devel-${kernel_uname_r}
+This package provides objects and symbols required to build kernel modules
+which depend on the ${kmodname} kernel modules built for the Linux
+kernel ${kernel_uname_r} for the %{_target_cpu} family of processors.
+%files        -n kmod-${kmodname}-devel-${kernel_uname_r}
+%defattr(644,root,root,755)
+%{_usrsrc}/${kmodname}-%{version}/${kernel_uname_r}
+
+
+EOF
+}
+
+print_rpmtemplate_kmodmetapkg ()
+{
+               local kernel_uname_r=${1}
+               local kernel_variant="${2:+-${2}}"
+
+               cat <<EOF
+%package      -n kmod-${kmodname}${kernel_variant}
+Summary:         Metapackage which tracks in ${kmodname} kernel module for newest kernel${kernel_variant}
+Group:           System Environment/Kernel
+
+Provides:        ${kmodname}-kmod = %{?epoch:%{epoch}:}%{version}-%{release}
+Requires:        kmod-${kmodname}-${kernel_uname_r} >= %{?epoch:%{epoch}:}%{version}-%{release}
+%{?KmodsMetaRequires:Requires: %{?KmodsMetaRequires}}
+EOF
+
+               if [[ ${obsolete_name} ]]; then
+                       echo "Provides:        kmod-${obsolete_name}${kernel_variant} = ${obsolete_version}"
+                       echo "Obsoletes:       kmod-${obsolete_name}${kernel_variant} < ${obsolete_version}"
+               fi
+
+               cat <<EOF
+
+%description  -n kmod-${kmodname}${kernel_variant}
+This is a meta-package without payload which sole purpose is to require the
+${kmodname} kernel module(s) for the newest kernel${kernel_variant}.
+to make sure you get it together with a new kernel.
+
+%files        -n kmod-${kmodname}${kernel_variant}
+%defattr(644,root,root,755)
+
+
+EOF
+}
+
+print_customrpmtemplate ()
+{
+       for kernel in ${1}
+       do
+               if [[ -e "${buildroot}/usr/src/kernels/${kernel}" ]] ; then
+                       # this looks like a Fedora/RH kernel -- print a normal template (which includes the proper BR) and be happy :)
+                       kernel_versions="${kernel_versions}${kernel}___${buildroot}%{_usrsrc}/kernels/${kernel} "
+
+                       # parse kernel versions string and print template
+                       local kernel_verrelarch=${kernel%%${kernels_known_variants}}
+                       print_rpmtemplate_per_kmodpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}}
+
+                       # create development package
+                       if [[ "${devel}" ]]; then
+                               # create devel package including common headers
+                               print_rpmtemplate_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}}
+
+                               # create devel package
+                               print_rpmtemplate_per_kmoddevelpkg --redhat ${kernel} ${kernel##${kernel_verrelarch}}
+                       fi
+               elif [[ -e ${prefix}/lib/modules/"${kernel}"/build/Makefile ]] ; then 
+                       # likely a user-build-kernel with available buildfiles
+                       # fixme: we should check if uname from Makefile is the same as ${kernel}
+
+                       kernel_versions="${kernel_versions}${kernel}___${prefix}/lib/modules/${kernel}/build/ "
+                       print_rpmtemplate_per_kmodpkg --custom "${kernel}"
+
+                       # create development package
+                       if [[ "${devel}" ]]; then
+                               # create devel package including common headers
+                               print_rpmtemplate_kmoddevelpkg --custom "${kernel}"
+
+                               # create devel package
+                               print_rpmtemplate_per_kmoddevelpkg --custom "${kernel}"
+                       fi
+               else
+                       error_out 2 "Don't know how to handle ${kernel} -- ${prefix}/lib/modules/${kernel}/build/Makefile not found"
+               fi
+       done
+
+       # well, it's no header anymore, but who cares ;-)
+       print_rpmtemplate_header
+}
+
+
+print_rpmtemplate ()
+{
+       # create kernel_versions var
+       for kernel_version in ${kernel_versions_to_build_for}
+       do
+               kernel_versions="${kernel_versions}${kernel_version}___%{_usrsrc}/kernels/${kernel_version} "
+       done
+
+       # and print it and some other required stuff as macro
+       print_rpmtemplate_header
+
+       # now print the packages itselfs
+       for kernel in ${kernel_versions_to_build_for} ; do
+
+               local kernel_verrelarch=${kernel%%${kernels_known_variants}}
+
+               # create metapackage 
+               print_rpmtemplate_kmodmetapkg ${kernel} ${kernel##${kernel_verrelarch}}
+
+               # create package
+               print_rpmtemplate_per_kmodpkg ${kernel} ${kernel##${kernel_verrelarch}}
+
+               if [[ "${devel}" ]]; then
+                       # create devel package including common headers
+                       print_rpmtemplate_kmoddevelpkg ${kernel} ${kernel##${kernel_verrelarch}}
+
+                       # create devel package
+                       print_rpmtemplate_per_kmoddevelpkg ${kernel} ${kernel##${kernel_verrelarch}}
+               fi
+       done
+}
+
+myprog_help ()
+{
+       echo "Usage: $(basename ${0}) [OPTIONS]"
+       echo $'\n'"Creates a template to be used during kmod building"
+       echo $'\n'"Available options:"
+       echo " --filterfile <file>  -- filter the results with grep --file <file>"
+       echo " --for-kernels <list> -- created templates only for these kernels"
+       echo " --kmodname <file>    -- name of the kmod (required)"
+       echo " --devel              -- make kmod-devel package"
+       echo " --noakmod            -- no akmod package"
+       echo " --repo <name>        -- use buildsys-build-<name>-kerneldevpkgs"
+       echo " --target <arch>      -- target-arch (required)"
+       echo " --buildroot <dir>    -- Build root (place to look for build files)"
+}
+
+while [ "${1}" ] ; do
+       case "${1}" in
+               --filterfile)
+                       shift
+                       if [[ ! "${1}" ]] ; then
+                               error_out 2 "Please provide path to a filter-file together with --filterfile" >&2
+                       elif [[ ! -e "${1}" ]]; then    
+                               error_out 2 "Filterfile ${1} not found" >&2
+                       fi
+                       filterfile="${1}"
+                       shift
+                       ;;
+               --kmodname)
+                       shift
+                       if [[ ! "${1}" ]] ; then
+                               error_out 2 "Please provide the name of the kmod together with --kmodname" >&2
+                   fi
+                       # strip pending -kmod
+                       kmodname="${1%%-kmod}"
+                       shift
+                       ;;
+               --devel)
+                       shift
+                       devel="true"
+                       ;;
+               --prefix)
+                       shift
+                       if [[ ! "${1}" ]] ; then
+                               error_out 2 "Please provide a prefix with --prefix" >&2
+                   fi
+                       prefix="${1}"
+                       shift
+                       ;;
+               --repo)
+                       shift
+                       if [[ ! "${1}" ]] ; then
+                               error_out 2 "Please provide the name of the repo together with --repo" >&2
+                   fi
+                       repo=${1}
+                       shift
+                       ;;
+               --for-kernels)
+                       shift
+                       if [[ ! "${1}" ]] ; then
+                               error_out 2 "Please provide the name of the kmod together with --kmodname" >&2
+                       fi
+                       for_kernels="${1}"
+                       shift
+                       ;;
+               --noakmod)
+                       shift
+                       noakmod="true"
+                       ;;
+               --obsolete-name)
+                       shift
+                       if [[ ! "${1}" ]] ; then
+                               error_out 2 "Please provide the name of the kmod to obsolte together with --obsolete-name" >&2
+                       fi
+                       obsolete_name="${1}"
+                       shift
+                       ;;
+               --obsolete-version)
+                       shift
+                       if [[ ! "${1}" ]] ; then
+                               error_out 2 "Please provide the version of the kmod to obsolte together with --obsolete-version" >&2
+                       fi
+                       obsolete_version="${1}"
+                       shift
+                       ;;
+               --target)
+                       shift
+                       target="${1}"
+                       shift
+                       ;;
+               --akmod)
+                       shift
+                       build_kernels="akmod"
+                       ;;
+               --newest)
+                       shift
+                       build_kernels="newest"
+                       ;;
+               --current)
+                       shift
+                       build_kernels="current"
+                       ;;
+               --buildroot)
+                       shift
+                       buildroot="${1}"
+                       shift
+                       ;;
+               --help)
+                       myprog_help
+                       exit 0
+                       ;;
+               --version)
+                       echo "${myprog} ${myver}"
+                       exit 0
+                       ;;
+               *)
+                       echo "Error: Unknown option '${1}'." >&2
+                       usage >&2
+                       exit 2
+                       ;;
+       esac
+done
+
+if [[ -e ./kmodtool-kernel-variants ]]; then
+       kernels_known_variants="$(cat ./kmodtool-kernel-variants)"
+elif [[ -e /usr/share/kmodtool/kernel-variants ]] ; then
+       kernels_known_variants="$(cat /usr/share/kmodtool/kernel-variants)"
+else
+       kernels_known_variants="@(smp?(-debug)|PAE?(-debug)|debug|kdump|xen|kirkwood|highbank|imx|omap|tegra)"
+fi
+
+# general sanity checks
+if [[ ! "${target}" ]]; then
+               error_out 2 "please pass target arch with --target"
+elif [[ ! "${kmodname}" ]]; then
+               error_out 2 "please pass kmodname with --kmodname"
+elif [[ ! "${kernels_known_variants}" ]] ; then
+               error_out 2 "could not determine known variants"
+elif ( [[ "${obsolete_name}" ]] && [[ ! "${obsolete_version}" ]] ) ||  ( [[ ! "${obsolete_name}" ]] && [[ "${obsolete_version}" ]] ) ; then
+               error_out 2 "you need to provide both --obsolete-name and --obsolete-version"
+fi
+
+# go
+if [[ "${for_kernels}" ]]; then
+       # this is easy:
+       print_customrpmtemplate "${for_kernels}"
+elif [[ "${build_kernels}" == "akmod" ]]; then
+       # do only a akmod package
+       print_akmodtemplate
+       print_akmodmeta
+else
+       # seems we are on out own to decide for which kernels to build
+
+       # we need more sanity checks in this case
+       if [[ ! "${repo}" ]]; then
+               error_out 2 "please provide repo name with --repo"
+       elif ! $(which buildsys-build-${repo}-kerneldevpkgs &> /dev/null) ; then
+               error_out 2 "buildsys-build-${repo}-kerneldevpkgs not found"
+       fi
+
+       # call buildsys-build-${repo}-kerneldevpkgs to get the list of kernels
+       cmdoptions="--target ${target}"
+
+       # filterfile to filter list of kernels? 
+       if [[ "${filterfile}" ]] ; then
+                cmdoptions="${cmdoptions} --filterfile ${filterfile}"
+       fi
+
+       kernel_versions_to_build_for="$(buildsys-build-${repo}-kerneldevpkgs --${build_kernels} ${cmdoptions})"
+       returncode=$?
+       if (( ${returncode} != 0 )); then
+               error_out 2 "buildsys-build-${repo}-kerneldevpkgs failed: $(buildsys-build-${repo}-kerneldevpkgs --${build_kernels} ${cmdoptions})"
+       fi
+
+       if [[ "${build_kernels}" == "current" ]] && [[ ! "${noakmod}" ]]; then
+               print_akmodtemplate
+       fi
+
+       print_rpmtemplate 
+fi
diff --git a/zfs/scripts/smb.sh b/zfs/scripts/smb.sh
new file mode 100755 (executable)
index 0000000..7cf6c4b
--- /dev/null
@@ -0,0 +1,214 @@
+#!/bin/bash
+
+BASETANK="share"
+DATE=`date "+%Y%m%d"`
+
+TEST_SMBFS=0
+TEST_DESTROY=0
+
+if [ -z "$1" ]; then
+       echo "Usage: `basename $0` [unpack]<[smbfs][snapshot][all]>"
+       exit 1
+fi
+
+set_onoff() {
+       type="$1"
+       dataset="$2"
+       toggle="$3"
+
+       current=`zfs get -H $type -o value $dataset`
+       if [ "$current" != "$toggle" ]; then
+               run "zfs set $type=$toggle $dataset"
+       fi
+}
+
+check_exists() {
+       dataset="$1"
+
+       extra=""
+       [ -n "$2" ] && extra="$2"
+
+       zfs get all "$dataset" > /dev/null 2>&1
+       if [ $? != 0 ]; then
+               run "zfs create $extra $dataset"
+       fi
+}
+
+check_shares() {
+       if [ "$TEST_SMBFS" == "1" ]; then
+               echo "Shares:"
+               echo "=> usershare list:"
+               net usershare list
+               echo
+               echo "=> /etc/dfs/sharetab:"
+               cat /etc/dfs/sharetab
+               echo
+       fi
+
+       sleep 2
+}
+
+test_header() {
+       echo "TEST: $*"
+       echo "======================================"
+}
+
+run() {
+       cmd="$*"
+
+       echo "CMD: $cmd"
+       $cmd
+}
+
+# ---------
+# Needs more work...
+if echo "$*" | grep -qi "unpack"; then
+       zfs unmount -a
+       zfs unshare -a
+       run "zfs destroy -r $BASETANK/tests"
+
+       sh /etc/init.d/zfs stop
+
+#      for tid in `grep ^tid /proc/net/iet/volume | sed "s@.*:\([0-9].*\) name.*@\1@"`
+#      do
+#              ietadm --op delete --tid $tid
+#      done
+
+       set -e
+       rmmod `lsmod | grep ^z | grep -v zlib_deflate | sed 's@ .*@@'` spl zlib_deflate
+
+       pushd / > /dev/null
+       [ -f "tmp/zfs.tgz" ] && tar xzf tmp/zfs.tgz && rm tmp/zfs.tgz
+       [ -f "tmp/spl.tgz" ] && tar xzf tmp/spl.tgz && rm tmp/spl.tgz
+       popd > /dev/null
+
+       depmod -a
+
+       sh /etc/init.d/zfs start
+       set +e
+fi
+
+# ---------
+if echo "$*" | egrep -qi "smbfs|all"; then
+       check_exists $BASETANK/tests
+
+       TEST_SMBFS=1
+
+       test_header "Exists || Create"
+       str=
+       for volnr in 1 2 3; do
+               check_exists $BASETANK/tests/smbfs$volnr
+
+               str="$str $BASETANK/tests/smbfs$volnr"
+       done
+       run "zfs get sharesmb $str"
+
+       # Set sharesmb=on
+       test_header "Enable SMB share"
+       for volnr in 1 2 3; do
+           set_onoff sharesmb "$BASETANK/tests/smbfs$volnr" on
+           check_shares
+       done
+
+       # Share all
+       test_header "Share all (individually)"
+       for volnr in 1 2 3; do
+           run "zfs share $BASETANK/tests/smbfs$volnr"
+           check_shares
+       done
+
+       # Unshare all
+       test_header "Unshare all (individually)"
+       for volnr in 1 2 3; do
+           run "zfs unshare $BASETANK/tests/smbfs$volnr"
+           check_shares
+       done
+
+       # Change mountpoint - first unshare and then share individual
+       test_header "Change mount point (unshare ; share)"
+       mkdir -p /tests
+       set_onoff sharesmb "$str" off
+       for volnr in 3 1 2; do
+               run "zfs set mountpoint=/tests/smbfs$volnr $BASETANK/tests/smbfs$volnr"
+               echo "CMD: mount | grep ^$BASETANK/tests/smbfs$volnr"
+               mount | grep ^$BASETANK/tests/smbfs$volnr
+               echo
+
+               run "zfs mount $BASETANK/tests/smbfs$volnr"
+               echo "CMD: mount | grep ^$BASETANK/tests/smbfs$volnr"
+               mount | grep ^$BASETANK/tests/smbfs$volnr
+               echo
+
+               set_onoff sharesmb "$BASETANK/tests/smbfs$volnr" on
+               check_shares
+
+               run "zfs share $BASETANK/tests/smbfs$volnr"
+               check_shares
+
+               echo "-------------------"
+       done
+
+       # Change mountpoint - remounting
+       test_header "Change mount point (remounting)"
+       for volnr in 3 1 2; do
+               run "zfs set mountpoint=/$BASETANK/tests/smbfs$volnr $BASETANK/tests/smbfs$volnr"
+               echo "CMD: mount | grep ^$BASETANK/tests/smbfs$volnr"
+               mount | grep ^$BASETANK/tests/smbfs$volnr
+               echo
+               # => Doesn't seem to remount (!?)
+
+               run "zfs mount $BASETANK/tests/smbfs$volnr"
+               echo "CMD: mount | grep ^$BASETANK/tests/smbfs$volnr"
+               mount | grep ^$BASETANK/tests/smbfs$volnr
+               echo
+               # => Doesn't seem to reshare (!?)
+
+               check_shares
+
+               run "zfs share $BASETANK/tests/smbfs$volnr"
+               check_shares
+
+               echo "-------------------"
+       done
+fi
+
+# ---------
+if echo "$*" | egrep -qi "smbfs|all"; then
+       test_header "Unshare + Share all"
+
+       run "zfs share -a" ; check_shares
+       run "zfs unshare -a" ; check_shares
+fi
+
+# ---------
+if echo "$*" | grep -qi "snapshot|all"; then
+       test_header "Snapshots"
+
+       echo ; echo "-------------------"
+       check_exists $BASETANK/tests/destroy
+       check_exists $BASETANK/tests/destroy/destroy1
+       run "zfs destroy -r $BASETANK/tests/destroy"
+
+       echo ; echo "-------------------"
+       check_exists $BASETANK/tests/destroy
+       run "zfs snapshot $BASETANK/tests/destroy@$DATE"
+       run "zfs destroy -r $BASETANK/tests/destroy"
+
+       echo ; echo "-------------------"
+       check_exists $BASETANK/tests/destroy
+       run "zfs snapshot $BASETANK/tests/destroy@$DATE"
+       run "zfs destroy -r $BASETANK/tests/destroy@$DATE"
+       run "zfs destroy -r $BASETANK/tests/destroy"
+fi
+
+if echo "$*" | egrep -qi "smbfs|snapshot|all"; then
+       test_header "Cleanup (Share all + Destroy all)"
+
+       run "zfs share -a"
+       check_shares
+
+       run "zfs destroy -r $BASETANK/tests"
+       check_shares
+
+       run "zfs list"
+fi
diff --git a/zfs/scripts/zconfig.sh b/zfs/scripts/zconfig.sh
new file mode 100755 (executable)
index 0000000..45b6644
--- /dev/null
@@ -0,0 +1,696 @@
+#!/bin/bash
+#
+# ZFS/ZPOOL configuration test script.
+
+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=zconfig.sh
+
+usage() {
+cat << EOF
+USAGE:
+$0 [hvcts]
+
+DESCRIPTION:
+       ZFS/ZPOOL configuration tests
+
+OPTIONS:
+       -h      Show this message
+       -v      Verbose
+       -c      Cleanup 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
+
+# Disable the udev rule 90-zfs.rules to prevent the zfs module
+# stack from being loaded due to the detection of a zfs device.
+# This is important because this test scripts require full control
+# over when and how the modules are loaded/unloaded.  A trap is
+# set to ensure the udev rule is correctly replaced on exit.
+RULE=${udevruledir}/90-zfs.rules
+if test -e  ${RULE}; then
+       trap "mv ${RULE}.disabled ${RULE}" INT TERM EXIT
+       mv ${RULE} ${RULE}.disabled
+fi
+
+# 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 the tests that require scsi_debug and lsscsi.
+SCSI_DEBUG=0
+${INFOMOD} scsi_debug &>/dev/null && SCSI_DEBUG=1
+HAVE_LSSCSI=0
+test -f ${LSSCSI} && HAVE_LSSCSI=1
+if [ ${SCSI_DEBUG} -eq 0 ] || [ ${HAVE_LSSCSI} -eq 0 ]; then
+       echo "Skipping test 10 which requires the scsi_debug " \
+               "module and the ${LSSCSI} utility"
+fi
+
+# Validate persistent zpool.cache configuration.
+test_1() {
+       local POOL_NAME=test1
+       local TMP_FILE1=`mktemp`
+       local TMP_FILE2=`mktemp`
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+
+       # Create a pool save its status for comparison.
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 || fail 2
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE1} || fail 3
+
+       # Unload/load the module stack and verify the pool persists.
+       ${ZFS_SH} -u || fail 4
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 5
+       ${ZPOOL} import -c ${TMP_CACHE} ${POOL_NAME} || fail 5
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE2} || fail 6
+       cmp ${TMP_FILE1} ${TMP_FILE2} || fail 7
+
+       # Cleanup the test pool and temporary files
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 8
+       rm -f ${TMP_FILE1} ${TMP_FILE2} ${TMP_CACHE} || fail 9
+       ${ZFS_SH} -u || fail 10
+
+       pass
+}
+run_test 1 "persistent zpool.cache"
+
+# Validate ZFS disk scanning and import w/out zpool.cache configuration.
+test_2() {
+       local POOL_NAME=test2
+       local TMP_FILE1=`mktemp`
+       local TMP_FILE2=`mktemp`
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+
+       # Create a pool save its status for comparison.
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 || fail 2
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE1} || fail 3
+
+       # Unload the module stack, remove the cache file, load the module
+       # stack and attempt to probe the disks to import the pool.  As
+       # a cross check verify the old pool state against the imported.
+       ${ZFS_SH} -u || fail 4
+       rm -f ${TMP_CACHE} || fail 5
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 6
+       ${ZPOOL} import -d /dev ${POOL_NAME} || fail 8
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE2} || fail 9
+       cmp ${TMP_FILE1} ${TMP_FILE2} || fail 10
+
+       # Cleanup the test pool and temporary files
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 11
+       rm -f ${TMP_FILE1} ${TMP_FILE2} || fail 12
+       ${ZFS_SH} -u || fail 13
+
+       pass
+}
+run_test 2 "scan disks for pools to import"
+
+zconfig_zvol_device_stat() {
+       local EXPECT=$1
+       local POOL_NAME=/dev/zvol/$2
+       local ZVOL_NAME=/dev/zvol/$3
+       local SNAP_NAME=/dev/zvol/$4
+       local CLONE_NAME=/dev/zvol/$5
+       local COUNT=0
+
+       # Briefly delay for udev
+       udev_trigger
+
+       # Pool exists
+       stat ${POOL_NAME} &>/dev/null   && let COUNT=$COUNT+1
+
+       # Volume and partitions
+       stat ${ZVOL_NAME}  &>/dev/null  && let COUNT=$COUNT+1
+       stat ${ZVOL_NAME}-part1 &>/dev/null  && let COUNT=$COUNT+1
+       stat ${ZVOL_NAME}-part2 &>/dev/null  && let COUNT=$COUNT+1
+
+       # Snapshot with partitions
+       stat ${SNAP_NAME}  &>/dev/null  && let COUNT=$COUNT+1
+       stat ${SNAP_NAME}-part1 &>/dev/null  && let COUNT=$COUNT+1
+       stat ${SNAP_NAME}-part2 &>/dev/null  && let COUNT=$COUNT+1
+
+       # Clone with partitions
+       stat ${CLONE_NAME}  &>/dev/null && let COUNT=$COUNT+1
+       stat ${CLONE_NAME}-part1 &>/dev/null && let COUNT=$COUNT+1
+       stat ${CLONE_NAME}-part2 &>/dev/null && let COUNT=$COUNT+1
+
+       if [ $EXPECT -ne $COUNT ]; then
+               return 1
+       fi
+
+       return 0
+}
+
+# zpool import/export device check
+# (1 volume, 2 partitions, 1 snapshot, 1 clone)
+test_3() {
+       local POOL_NAME=tank
+       local ZVOL_NAME=volume
+       local SNAP_NAME=snap
+       local CLONE_NAME=clone
+       local FULL_ZVOL_NAME=${POOL_NAME}/${ZVOL_NAME}
+       local FULL_SNAP_NAME=${POOL_NAME}/${ZVOL_NAME}@${SNAP_NAME}
+       local FULL_CLONE_NAME=${POOL_NAME}/${CLONE_NAME}
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+
+       # Create a pool, volume, partition, snapshot, and clone.
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 || fail 2
+       ${ZFS} create -V 100M ${FULL_ZVOL_NAME} || fail 3
+       ${ZFS} set snapdev=visible ${FULL_ZVOL_NAME} || fail 3
+       label /dev/zvol/${FULL_ZVOL_NAME} msdos || fail 4
+       partition /dev/zvol/${FULL_ZVOL_NAME} primary 1% 50% || fail 4
+       partition /dev/zvol/${FULL_ZVOL_NAME} primary 51% -1 || fail 4
+       ${ZFS} snapshot ${FULL_SNAP_NAME} || fail 5
+       ${ZFS} clone ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 6
+
+       # Verify the devices were created
+       zconfig_zvol_device_stat 10 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 7
+
+       # Export the pool
+       ${ZPOOL} export ${POOL_NAME} || fail 8
+
+       # verify the devices were removed
+       zconfig_zvol_device_stat 0 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 9
+
+       # Import the pool, wait 1 second for udev
+       ${ZPOOL} import ${POOL_NAME} || fail 10
+
+       # Verify the devices were created
+       zconfig_zvol_device_stat 10 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 11
+
+       # Toggle the snapdev and observe snapshot device links toggled
+       ${ZFS} set snapdev=hidden ${FULL_ZVOL_NAME} || fail 12
+       
+       zconfig_zvol_device_stat 7 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           "invalid" ${FULL_CLONE_NAME} || fail 13
+
+       ${ZFS} set snapdev=visible ${FULL_ZVOL_NAME} || fail 14
+
+       zconfig_zvol_device_stat 10 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 15
+
+       # Destroy the pool and consequently the devices
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 16
+
+       # verify the devices were removed
+       zconfig_zvol_device_stat 0 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 17
+
+       ${ZFS_SH} -u || fail 18
+       rm -f ${TMP_CACHE} || fail 19
+
+       pass
+}
+run_test 3 "zpool import/export device"
+
+# zpool insmod/rmmod device check (1 volume, 1 snapshot, 1 clone)
+test_4() {
+       POOL_NAME=tank
+       ZVOL_NAME=volume
+       SNAP_NAME=snap
+       CLONE_NAME=clone
+       FULL_ZVOL_NAME=${POOL_NAME}/${ZVOL_NAME}
+       FULL_SNAP_NAME=${POOL_NAME}/${ZVOL_NAME}@${SNAP_NAME}
+       FULL_CLONE_NAME=${POOL_NAME}/${CLONE_NAME}
+       TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+
+       # Create a pool, volume, snapshot, and clone
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 || fail 2
+       ${ZFS} create -V 100M ${FULL_ZVOL_NAME} || fail 3
+       ${ZFS} set snapdev=visible ${FULL_ZVOL_NAME} || fail 3
+       label /dev/zvol/${FULL_ZVOL_NAME} msdos || fail 4
+       partition /dev/zvol/${FULL_ZVOL_NAME} primary 1% 50% || fail 4
+       partition /dev/zvol/${FULL_ZVOL_NAME} primary 51% -1 || fail 4
+       ${ZFS} snapshot ${FULL_SNAP_NAME} || fail 5
+       ${ZFS} clone ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 6
+
+       # Verify the devices were created
+       zconfig_zvol_device_stat 10 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 7
+
+       # Unload the modules
+       ${ZFS_SH} -u || fail 8
+
+       # Verify the devices were removed
+       zconfig_zvol_device_stat 0 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 9
+
+       # Load the modules, list the pools to ensure they are opened
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 10
+       ${ZPOOL} import -c ${TMP_CACHE} ${POOL_NAME} || fail 10
+       ${ZPOOL} list &>/dev/null
+
+       # Verify the devices were created
+       zconfig_zvol_device_stat 10 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 11
+
+       # Destroy the pool and consequently the devices
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 12
+
+       # Verify the devices were removed
+       zconfig_zvol_device_stat 0 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+           ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 13
+
+       ${ZFS_SH} -u || fail 14
+       rm -f ${TMP_CACHE} || fail 15
+
+       pass
+}
+run_test 4 "zpool insmod/rmmod device"
+
+# ZVOL volume sanity check
+test_5() {
+       local POOL_NAME=tank
+       local ZVOL_NAME=fish
+       local FULL_NAME=${POOL_NAME}/${ZVOL_NAME}
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+
+       # Create a pool and volume.
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raid0 || fail 2
+       ${ZFS} create -V 800M ${FULL_NAME} || fail 3
+       label /dev/zvol/${FULL_NAME} msdos || fail 4
+       partition /dev/zvol/${FULL_NAME} primary 1 -1 || fail 4
+       format /dev/zvol/${FULL_NAME}-part1 ext2 || fail 5
+
+       # Mount the ext2 filesystem and copy some data to it.
+       mkdir -p /tmp/${ZVOL_NAME}-part1 || fail 6
+       mount /dev/zvol/${FULL_NAME}-part1 /tmp/${ZVOL_NAME}-part1 || fail 7
+       cp -RL ${SRC_DIR} /tmp/${ZVOL_NAME}-part1 || fail 8
+       sync
+
+       # Verify the copied files match the original files.
+       diff -ur ${SRC_DIR} /tmp/${ZVOL_NAME}-part1/${SRC_DIR##*/} \
+               &>/dev/null || fail 9
+
+       # Remove the files, umount, destroy the volume and pool.
+       rm -Rf /tmp/${ZVOL_NAME}-part1/${SRC_DIR##*/} || fail 10
+       umount /tmp/${ZVOL_NAME}-part1 || fail 11
+       rmdir /tmp/${ZVOL_NAME}-part1 || fail 12
+
+       ${ZFS} destroy ${FULL_NAME} || fail 13
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 14
+       ${ZFS_SH} -u || fail 15
+       rm -f ${TMP_CACHE} || fail 16
+
+       pass
+}
+run_test 5 "zvol+ext2 volume"
+
+# ZVOL snapshot sanity check
+test_6() {
+       local POOL_NAME=tank
+       local ZVOL_NAME=fish
+       local SNAP_NAME=pristine
+       local FULL_ZVOL_NAME=${POOL_NAME}/${ZVOL_NAME}
+       local FULL_SNAP_NAME=${POOL_NAME}/${ZVOL_NAME}@${SNAP_NAME}
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+
+       # Create a pool and volume.
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raid0 || fail 2
+       ${ZFS} create -V 800M ${FULL_ZVOL_NAME} || fail 3
+       ${ZFS} set snapdev=visible ${FULL_ZVOL_NAME} || fail 3
+       label /dev/zvol/${FULL_ZVOL_NAME} msdos || fail 4
+       partition /dev/zvol/${FULL_ZVOL_NAME} primary 1 -1 || fail 4
+       format /dev/zvol/${FULL_ZVOL_NAME}-part1 ext2 || fail 5
+
+       # Mount the ext2 filesystem and copy some data to it.
+       mkdir -p /tmp/${ZVOL_NAME}-part1 || fail 6
+       mount /dev/zvol/${FULL_ZVOL_NAME}-part1 /tmp/${ZVOL_NAME}-part1 \
+               || fail 7
+
+       # Snapshot the pristine ext2 filesystem and mount it read-only.
+       ${ZFS} snapshot ${FULL_SNAP_NAME} || fail 8
+       wait_udev /dev/zvol/${FULL_SNAP_NAME}-part1 30 || fail 8
+       mkdir -p /tmp/${SNAP_NAME}-part1 || fail 9
+       mount /dev/zvol/${FULL_SNAP_NAME}-part1 /tmp/${SNAP_NAME}-part1 \
+               &>/dev/null || fail 10
+
+       # Copy to original volume
+       cp -RL ${SRC_DIR} /tmp/${ZVOL_NAME}-part1 || fail 11
+       sync
+
+       # Verify the copied files match the original files,
+       # and the copied files do NOT appear in the snapshot.
+       diff -ur ${SRC_DIR} /tmp/${ZVOL_NAME}-part1/${SRC_DIR##*/} \
+               &>/dev/null || fail 12
+       diff -ur ${SRC_DIR} /tmp/${SNAP_NAME}-part1/${SRC_DIR##*/} \
+               &>/dev/null && fail 13
+
+       # umount, destroy the snapshot, volume, and pool.
+       umount /tmp/${SNAP_NAME}-part1 || fail 14
+       rmdir /tmp/${SNAP_NAME}-part1 || fail 15
+       ${ZFS} destroy ${FULL_SNAP_NAME} || fail 16
+
+       umount /tmp/${ZVOL_NAME}-part1 || fail 17
+       rmdir /tmp/${ZVOL_NAME}-part1 || fail 18
+       ${ZFS} destroy ${FULL_ZVOL_NAME} || fail 19
+
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 20
+       ${ZFS_SH} -u || fail 21
+       rm -f ${TMP_CACHE} || fail 22
+
+       pass
+}
+run_test 6 "zvol+ext2 snapshot"
+
+# ZVOL clone sanity check
+test_7() {
+       local POOL_NAME=tank
+       local ZVOL_NAME=fish
+       local SNAP_NAME=pristine
+       local CLONE_NAME=clone
+       local FULL_ZVOL_NAME=${POOL_NAME}/${ZVOL_NAME}
+       local FULL_SNAP_NAME=${POOL_NAME}/${ZVOL_NAME}@${SNAP_NAME}
+       local FULL_CLONE_NAME=${POOL_NAME}/${CLONE_NAME}
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+
+       # Create a pool and volume.
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 || fail 2
+       ${ZFS} create -V 300M ${FULL_ZVOL_NAME} || fail 3
+       ${ZFS} set snapdev=visible ${FULL_ZVOL_NAME} || fail 3
+       label /dev/zvol/${FULL_ZVOL_NAME} msdos || fail 4
+       partition /dev/zvol/${FULL_ZVOL_NAME} primary 1 -1 || fail 4
+       format /dev/zvol/${FULL_ZVOL_NAME}-part1 ext2 || fail 5
+
+       # Snapshot the pristine ext2 filesystem.
+       ${ZFS} snapshot ${FULL_SNAP_NAME} || fail 6
+       wait_udev /dev/zvol/${FULL_SNAP_NAME}-part1 30 || fail 7
+
+       # Mount the ext2 filesystem so some data can be copied to it.
+       mkdir -p /tmp/${ZVOL_NAME}-part1 || fail 7
+       mount /dev/zvol/${FULL_ZVOL_NAME}-part1 \
+               /tmp/${ZVOL_NAME}-part1 || fail 8
+
+       # Mount the pristine ext2 snapshot.
+       mkdir -p /tmp/${SNAP_NAME}-part1 || fail 9
+       mount /dev/zvol/${FULL_SNAP_NAME}-part1 \
+               /tmp/${SNAP_NAME}-part1 &>/dev/null || fail 10
+
+       # Copy to original volume.
+       cp -RL ${SRC_DIR} /tmp/${ZVOL_NAME}-part1 || fail 11
+       sync
+
+       # Verify the copied files match the original files,
+       # and the copied files do NOT appear in the snapshot.
+       diff -ur ${SRC_DIR} /tmp/${ZVOL_NAME}-part1/${SRC_DIR##*/} \
+               &>/dev/null || fail 12
+       diff -ur ${SRC_DIR} /tmp/${SNAP_NAME}-part1/${SRC_DIR##*/} \
+               &>/dev/null && fail 13
+
+       # Clone from the original pristine snapshot
+       ${ZFS} clone ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 14
+       wait_udev /dev/zvol/${FULL_CLONE_NAME}-part1 30 || fail 14
+       mkdir -p /tmp/${CLONE_NAME}-part1 || fail 15
+       mount /dev/zvol/${FULL_CLONE_NAME}-part1 \
+               /tmp/${CLONE_NAME}-part1 || fail 16
+
+       # Verify the clone matches the pristine snapshot,
+       # and the files copied to the original volume are NOT there.
+       diff -ur /tmp/${SNAP_NAME}-part1 /tmp/${CLONE_NAME}-part1 \
+               &>/dev/null || fail 17
+       diff -ur /tmp/${ZVOL_NAME}-part1 /tmp/${CLONE_NAME}-part1 \
+               &>/dev/null && fail 18
+
+       # Copy to cloned volume.
+       cp -RL ${SRC_DIR} /tmp/${CLONE_NAME}-part1 || fail 19
+       sync
+
+       # Verify the clone matches the modified original volume.
+       diff -ur /tmp/${ZVOL_NAME}-part1 /tmp/${CLONE_NAME}-part1 \
+               &>/dev/null || fail 20
+
+       # umount, destroy the snapshot, volume, and pool.
+       umount /tmp/${CLONE_NAME}-part1 || fail 21
+       rmdir /tmp/${CLONE_NAME}-part1 || fail 22
+       ${ZFS} destroy ${FULL_CLONE_NAME} || fail 23
+
+       umount /tmp/${SNAP_NAME}-part1 || fail 24
+       rmdir /tmp/${SNAP_NAME}-part1 || fail 25
+       ${ZFS} destroy ${FULL_SNAP_NAME} || fail 26
+
+       umount /tmp/${ZVOL_NAME}-part1 || fail 27
+       rmdir /tmp/${ZVOL_NAME}-part1 || fail 28
+       ${ZFS} destroy ${FULL_ZVOL_NAME} || fail 29
+
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 30
+       ${ZFS_SH} -u || fail 31
+       rm -f ${TMP_CACHE} || fail 32
+
+       pass
+}
+run_test 7 "zvol+ext2 clone"
+
+# Send/Receive sanity check
+test_8() {
+       local POOL_NAME1=tank1
+       local POOL_NAME2=tank2
+       local ZVOL_NAME=fish
+       local SNAP_NAME=snap
+       local FULL_ZVOL_NAME1=${POOL_NAME1}/${ZVOL_NAME}
+       local FULL_ZVOL_NAME2=${POOL_NAME2}/${ZVOL_NAME}
+       local FULL_SNAP_NAME1=${POOL_NAME1}/${ZVOL_NAME}@${SNAP_NAME}
+       local FULL_SNAP_NAME2=${POOL_NAME2}/${ZVOL_NAME}@${SNAP_NAME}
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+
+       # Create two pools and a volume
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME1} -c lo-raidz2 || fail 2
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME2} -c lo-raidz2 || fail 2
+       ${ZFS} create -V 300M ${FULL_ZVOL_NAME1} || fail 3
+       ${ZFS} set snapdev=visible ${FULL_ZVOL_NAME1} || fail 3
+       label /dev/zvol/${FULL_ZVOL_NAME1} msdos || fail 4
+       partition /dev/zvol/${FULL_ZVOL_NAME1} primary 1 -1 || fail 4
+       format /dev/zvol/${FULL_ZVOL_NAME1}-part1 ext2 || fail 5
+
+       # Mount the ext2 filesystem and copy some data to it.
+       mkdir -p /tmp/${FULL_ZVOL_NAME1}-part1 || fail 6
+       mount /dev/zvol/${FULL_ZVOL_NAME1}-part1 \
+               /tmp/${FULL_ZVOL_NAME1}-part1 || fail 7
+       cp -RL ${SRC_DIR} /tmp/${FULL_ZVOL_NAME1}-part1 || fail 8
+
+       # Unmount, snapshot, mount the ext2 filesystem so it may be sent.
+       # We only unmount to ensure the ext2 filesystem is clean.
+       umount /tmp/${FULL_ZVOL_NAME1}-part1 || fail 9
+       ${ZFS} snapshot ${FULL_SNAP_NAME1} || fail 10
+       wait_udev /dev/zvol/${FULL_SNAP_NAME1} 30 || fail 10
+       mount /dev/zvol/${FULL_ZVOL_NAME1}-part1 \
+               /tmp/${FULL_ZVOL_NAME1}-part1 || 11
+
+       # Send/receive the snapshot from POOL_NAME1 to POOL_NAME2
+       (${ZFS} send ${FULL_SNAP_NAME1} | \
+       ${ZFS} receive ${FULL_ZVOL_NAME2}) || fail 12
+       wait_udev /dev/zvol/${FULL_ZVOL_NAME2}-part1 30 || fail 12
+
+       # Mount the sent ext2 filesystem.
+       mkdir -p /tmp/${FULL_ZVOL_NAME2}-part1 || fail 13
+       mount /dev/zvol/${FULL_ZVOL_NAME2}-part1 \
+               /tmp/${FULL_ZVOL_NAME2}-part1 || fail 14
+
+       # Verify the contents of the volumes match
+       diff -ur /tmp/${FULL_ZVOL_NAME1}-part1 /tmp/${FULL_ZVOL_NAME2}-part1 \
+           &>/dev/null || fail 15
+
+       # Umount, destroy the volume and pool.
+       umount /tmp/${FULL_ZVOL_NAME1}-part1 || fail 16
+       umount /tmp/${FULL_ZVOL_NAME2}-part1 || fail 17
+       rmdir /tmp/${FULL_ZVOL_NAME1}-part1 || fail 18
+       rmdir /tmp/${FULL_ZVOL_NAME2}-part1 || fail 19
+       rmdir /tmp/${POOL_NAME1} || fail 20
+       rmdir /tmp/${POOL_NAME2} || fail 21
+
+       ${ZFS} destroy ${FULL_SNAP_NAME1} || fail 22
+       ${ZFS} destroy ${FULL_SNAP_NAME2} || fail 23
+       ${ZFS} destroy ${FULL_ZVOL_NAME1} || fail 24
+       ${ZFS} destroy ${FULL_ZVOL_NAME2} || fail 25
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME1} -c lo-raidz2 -d || fail 26
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME2} -c lo-raidz2 -d || fail 27
+       ${ZFS_SH} -u || fail 28
+       rm -f ${TMP_CACHE} || fail 29
+
+       pass
+}
+run_test 8 "zfs send/receive"
+
+# zpool event sanity check
+test_9() {
+       local POOL_NAME=tank
+       local ZVOL_NAME=fish
+       local FULL_NAME=${POOL_NAME}/${ZVOL_NAME}
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+       local TMP_EVENTS=`mktemp -p /tmp zpool.events.XXXXXXXX`
+
+       # Create a pool and volume.
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 || fail 2
+       ${ZFS} create -V 300M ${FULL_NAME} || fail 3
+       udev_trigger
+
+       # Dump the events, there should be a pool create event
+       ${ZPOOL} events >${TMP_EVENTS} || fail 4
+       MATCHES=`grep -c sysevent\.fs\.zfs\.pool_create ${TMP_EVENTS}`
+       [ $MATCHES -eq 1 ] || fail 5
+
+       # Clear the events and ensure there are none.
+       ${ZPOOL} events -c >/dev/null || fail 6
+       ${ZPOOL} events >${TMP_EVENTS} || fail 7
+       EVENTS=`wc -l ${TMP_EVENTS} | cut -f1 -d' '`
+       [ $EVENTS -gt 1 ] && fail 8
+
+       ${ZFS} destroy ${FULL_NAME} || fail 9
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 10
+       ${ZFS_SH} -u || fail 11
+       rm -f ${TMP_CACHE} || fail 12
+       rm -f ${TMP_EVENTS} || fail 13
+
+       pass
+}
+run_test 9 "zpool events"
+
+zconfig_add_vdev() {
+       local POOL_NAME=$1
+       local TYPE=$2
+       local DEVICE=$3
+       local TMP_FILE1=`mktemp`
+       local TMP_FILE2=`mktemp`
+       local TMP_FILE3=`mktemp`
+
+       BASE_DEVICE=`basename ${DEVICE}`
+
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE1}
+       ${ZPOOL} add -f ${POOL_NAME} ${TYPE} ${DEVICE} 2>/dev/null || return 1
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE2}
+       diff ${TMP_FILE1} ${TMP_FILE2} > ${TMP_FILE3}
+
+       [ `wc -l ${TMP_FILE3}|${AWK} '{print $1}'` -eq 3 ] || return 1
+
+       PARENT_VDEV=`tail -2 ${TMP_FILE3} | head -1 | ${AWK} '{print $NF}'`
+       case $TYPE in
+       cache)
+               [ "${PARENT_VDEV}" = "${TYPE}" ] || return 1
+               ;;
+       log)
+               [ "${PARENT_VDEV}" = "logs" ] || return 1
+               ;;
+       esac
+
+       if ! tail -1 ${TMP_FILE3} |
+           egrep -q "^>[[:space:]]+${BASE_DEVICE}[[:space:]]+ONLINE" ; then
+               return 1
+       fi
+       rm -f ${TMP_FILE1} ${TMP_FILE2} ${TMP_FILE3}
+
+       return 0
+}
+
+# zpool add and remove sanity check
+test_10() {
+       local POOL_NAME=tank
+       local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+       local TMP_FILE1=`mktemp`
+       local TMP_FILE2=`mktemp`
+
+       if [ ${SCSI_DEBUG} -eq 0 ] || [ ${HAVE_LSSCSI} -eq 0 ] ; then
+               skip
+               return
+       fi
+
+       test `${LSMOD} | grep -c scsi_debug` -gt 0 && \
+               (${RMMOD} scsi_debug || exit 1)
+
+       /sbin/modprobe scsi_debug dev_size_mb=128 ||
+               die "Error $? creating scsi_debug device"
+       udev_trigger
+
+       SDDEVICE=`${LSSCSI}|${AWK} '/scsi_debug/ { print $6; exit }'`
+       BASE_SDDEVICE=`basename $SDDEVICE`
+
+       # Create a pool
+       ${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 || fail 2
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE1} || fail 3
+
+       # Add and remove a cache vdev by full path
+       zconfig_add_vdev ${POOL_NAME} cache ${SDDEVICE} || fail 4
+       ${ZPOOL} remove ${POOL_NAME} ${SDDEVICE} || fail 5
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE2} || fail 6
+       cmp ${TMP_FILE1} ${TMP_FILE2} || fail 7
+       sleep 1
+
+       # Add and remove a cache vdev by shorthand path
+       zconfig_add_vdev ${POOL_NAME} cache ${BASE_SDDEVICE} || fail 8
+       ${ZPOOL} remove ${POOL_NAME} ${BASE_SDDEVICE} || fail 9
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE2} || fail 10
+       cmp ${TMP_FILE1} ${TMP_FILE2} || fail 11
+       sleep 1
+
+       # Add and remove a log vdev
+       zconfig_add_vdev ${POOL_NAME} log ${BASE_SDDEVICE} || fail 12
+       ${ZPOOL} remove ${POOL_NAME} ${BASE_SDDEVICE} || fail 13
+       ${ZPOOL} status ${POOL_NAME} >${TMP_FILE2} || fail 14
+       cmp ${TMP_FILE1} ${TMP_FILE2} || fail 15
+
+       ${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 16
+       ${ZFS_SH} -u || fail 17
+       ${RMMOD} scsi_debug || fail 18
+
+       rm -f ${TMP_FILE1} ${TMP_FILE2} ${TMP_CACHE} || fail 19
+
+       pass
+}
+run_test 10 "zpool add/remove vdev"
+
+exit 0
diff --git a/zfs/scripts/zfs-helpers.sh b/zfs/scripts/zfs-helpers.sh
new file mode 100755 (executable)
index 0000000..6e97ce1
--- /dev/null
@@ -0,0 +1,149 @@
+#!/bin/bash
+#
+# This script is designed to facilitate in-tree development and testing
+# by installing symlinks on your system which refer to in-tree helper
+# utilities.  These helper utilities must be installed to in order to
+# exercise all ZFS functionality.  By using symbolic links and keeping
+# the scripts in-tree during development they can be easily modified
+# and those changes tracked.
+#
+# Use the following configuration option to override the installation
+# paths for these scripts.  The correct path is automatically set for
+# most distributions but you can optionally set it for your environment.
+#
+#   --with-mounthelperdir=DIR  install mount.zfs in dir [/sbin]
+#   --with-udevdir=DIR         install udev helpers [default=check]
+#   --with-udevruledir=DIR     install udev rules [default=UDEVDIR/rules.d]
+#
+
+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=zfs-helpers.sh
+DRYRUN=
+INSTALL=
+REMOVE=
+VERBOSE=
+
+usage() {
+cat << EOF
+USAGE:
+$0 [dhirv]
+
+DESCRIPTION:
+       Install/remove the ZFS helper utilities.
+
+OPTIONS:
+       -d      Dry run
+       -h      Show this message
+       -i      Install the helper utilties
+       -r      Remove the helper utilities
+       -v      Verbose
+
+$0 -iv
+$0 -r
+
+EOF
+}
+
+while getopts 'hdirv' OPTION; do
+       case $OPTION in
+       h)
+               usage
+               exit 1
+               ;;
+       d)
+               DRYRUN=1
+               ;;
+       i)
+               INSTALL=1
+               ;;
+       r)
+               REMOVE=1
+               ;;
+       v)
+               VERBOSE=1
+               ;;
+       ?)
+               usage
+               exit
+               ;;
+       esac
+done
+
+if [ "${INSTALL}" -a "${REMOVE}" ]; then
+       usage
+       die "Specify -i or -r but not both"
+fi
+
+if [ ! "${INSTALL}" -a ! "${REMOVE}" ]; then
+       usage
+       die "Either -i or -r must be specified"
+fi
+
+if [ $(id -u) != 0 ]; then
+       die "Must run as root"
+fi
+
+if [ "$VERBOSE" ]; then
+       echo "--- Configuration ---"
+       echo "udevdir:          $udevdir"
+       echo "udevruledir:      $udevruledir"
+       echo "mounthelperdir:   $mounthelperdir"
+       echo "DRYRUN:           $DRYRUN"
+       echo
+fi
+
+install() {
+       local src=$1
+       local dst=$2
+
+       if [ -h $dst ]; then
+               echo "Symlink exists: $dst"
+       elif [ -e $dst ]; then
+               echo "File exists: $dst"
+       elif [ ! -e $src ]; then
+               echo "Source missing: $src"
+       else
+               msg "ln -s $src $dst"
+
+               if [ ! "$DRYRUN" ]; then
+                       ln -s $src $dst
+               fi
+       fi
+}
+
+remove() {
+       local dst=$1
+
+       if [ -h $dst ]; then
+               msg "rm $dst"
+               rm $dst
+       fi
+}
+
+if [ ${INSTALL} ]; then
+       install $CMDDIR/mount_zfs/mount.zfs $mounthelperdir/mount.zfs
+       install $CMDDIR/fsck_zfs/fsck.zfs $mounthelperdir/fsck.zfs
+       install $CMDDIR/zvol_id/zvol_id $udevdir/zvol_id
+       install $CMDDIR/vdev_id/vdev_id $udevdir/vdev_id
+       install $UDEVRULEDIR/60-zvol.rules $udevruledir/60-zvol.rules
+       install $UDEVRULEDIR/69-vdev.rules $udevruledir/69-vdev.rules
+       install $UDEVRULEDIR/90-zfs.rules $udevruledir/90-zfs.rules
+else
+       remove $mounthelperdir/mount.zfs
+       remove $mounthelperdir/fsck.zfs
+       remove $udevdir/zvol_id
+       remove $udevdir/vdev_id
+       remove $udevruledir/60-zvol.rules
+       remove $udevruledir/69-vdev.rules
+       remove $udevruledir/90-zfs.rules
+fi
+
+exit 0
diff --git a/zfs/scripts/zfs-tests.sh b/zfs/scripts/zfs-tests.sh
new file mode 100755 (executable)
index 0000000..01fb2b2
--- /dev/null
@@ -0,0 +1,350 @@
+#!/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: 2G)
+       -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 -x
+
+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
+
+#
+# Check if ksh exists
+#
+if [ -z "$(which ksh 2>/dev/null)" ]; then
+       fail "This test suite requires ksh."
+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}
diff --git a/zfs/scripts/zfs.sh b/zfs/scripts/zfs.sh
new file mode 100755 (executable)
index 0000000..55584dd
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/bash
+#
+# A simple script to simply the loading/unloading the ZFS module stack.
+
+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=zfs.sh
+UNLOAD=
+
+usage() {
+cat << EOF
+USAGE:
+$0 [hvud] [module-options]
+
+DESCRIPTION:
+       Load/unload the ZFS module stack.
+
+OPTIONS:
+       -h      Show this message
+       -v      Verbose
+       -u      Unload modules
+       -d      Save debug log on unload
+
+MODULE-OPTIONS:
+       Must be of the from module="options", for example:
+
+$0 zfs="zfs_prefetch_disable=1"
+$0 zfs="zfs_prefetch_disable=1 zfs_mdcomp_disable=1"
+
+EOF
+}
+
+while getopts 'hvud' OPTION; do
+       case $OPTION in
+       h)
+               usage
+               exit 1
+               ;;
+       v)
+               VERBOSE=1
+               ;;
+       u)
+               UNLOAD=1
+               ;;
+       d)
+               DUMP_LOG=1
+               ;;
+       ?)
+               usage
+               exit
+               ;;
+       esac
+done
+
+if [ $(id -u) != 0 ]; then
+       die "Must run as root"
+fi
+
+if [ ${UNLOAD} ]; then
+       kill_zed
+       umount -t zfs -a
+       stack_check
+       unload_modules
+else
+       stack_clear
+       check_modules || die "${ERROR}"
+       load_modules "$@" || die "Failed to load modules"
+       wait_udev /dev/zfs 30 || die "'/dev/zfs' was not created"
+fi
+
+exit 0
diff --git a/zfs/scripts/zfs2zol-patch.sed b/zfs/scripts/zfs2zol-patch.sed
new file mode 100755 (executable)
index 0000000..d4def44
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sed -f
+
+s:usr/src/uts/common/fs/zfs/sys:include/sys:g
+s:usr/src/uts/common/fs/zfs:module/zfs:g
+s:usr/src/lib/libzpool:lib/libzpool:g
+s:usr/src/cmd:cmd:g
+s:usr/src/common/nvpair:module/nvpair:g
+s:usr/src/lib/libzfs/common/libzfs.h:include/libzfs.h:g
+s:usr/src/man/man1m/zfs.1m:man/man8/zfs.8:g
+s:usr/src/uts/common/sys:include/sys:g
+s:usr/src/lib/libzfs_core/common/libzfs_core.h:include/libzfs_core.h:g
+s:usr/src/lib/libzfs/common:lib/libzfs:g
+s:usr/src/lib/libzfs_core/common:lib/libzfs_core:g
+s:lib/libzpool/common/sys:include/sys:g
+s:lib/libzpool/common:lib/libzpool:g
+
+s:usr/src/test/zfs-tests/include:tests/zfs-tests/include:g
+s:usr/src/test/zfs-tests/runfiles:tests/runfiles:g
+s:usr/src/test/zfs-tests/tests/functional:tests/zfs-tests/tests/functional:g
+s:usr/src/test/zfs-tests/tests/perf:tests/zfs-tests/tests/perf:g
+s:usr/src/test/test-runner/cmd/run.py:tests/test-runner/cmd/test-runner.py:g
+
+#
+# The usr/src/common/zfs/ files go in a couple different dirs.
+# usr/src/common/zfs/zfeature_common.c goes in module/zfs
+#
+s:usr/src/common/zfs/zfeature_common.c:module/zfs/zfeature_common.c:g
+
+# ...but most of the rest of the C files go in module/zcommon
+s/usr\/src\/common\/zfs\/\(.*\)\.c/module\/zcommon\/\1.c/g
+
+# crypto framework
+s:usr/src/common/crypto:module/icp/algs:g
+s:usr/src/uts/common/crypto/io:module/icp/io:g
+
+# Headers
+s:usr/src/common/zfs/\(.*\)\.h:include/\1.h:g
+
+# Man pages
+s:usr/src/man:man:g
diff --git a/zfs/scripts/ziltest.sh b/zfs/scripts/ziltest.sh
new file mode 100755 (executable)
index 0000000..bb81629
--- /dev/null
@@ -0,0 +1,305 @@
+#!/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
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# Linux version
+#
+# To run just type ziltest.sh
+#
+# - creates a 200MB pool in /var/tmp/
+# - prints information on:
+#      working set files
+#      ZIL records written
+#      ZIL block usage
+#      verification results
+# - returns status of 0 on success
+#
+##########################################################################
+#
+# Here's how it all works:
+#
+# The general idea is to build up
+# an intent log from a bunch of diverse user commands
+# without actually committing them to the file system.
+# Then copy the file system, replay the intent
+# log and compare the file system and the copy.
+#
+# To enable this automated testing of the intent log
+# requires some but minimal support from the file system.
+# In particular, a "freeze" command is required to flush
+# the in-flight transactions; to stop the actual
+# committing of transactions; and to ensure no deltas are
+# discarded. All deltas past a freeze point are kept for
+# replay and comparison later. Here is the flow:
+#
+#      create an empty file system (FS)
+#      freeze FS
+#      run various user commands that create files, directories and ACLs
+#      copy FS to temporary location (COPY)
+#      unmount filesystem
+#      <at this stage FS is empty again and unfrozen, and the
+#       intent log contains a complete set of deltas to replay it>
+#      remount FS <which replays the intent log>
+#      compare FS against the COPY
+#
+
+PATH=/usr/bin
+PATH=$PATH:/usr/sbin
+PATH=$PATH:/bin
+PATH=$PATH:/sbin
+export PATH
+
+# ====================================================================
+# SETUP
+# ====================================================================
+CMD=$(basename "$0")
+POOL=ziltestpool.$$
+DEVSIZE=${DEVSIZE-200m}
+POOLDIR=/var/tmp
+POOLFILE=$POOLDIR/ziltest_poolfile.$$
+SLOGFILE=$POOLDIR/ziltest_slog.$$
+FS=$POOL/fs
+ROOT=/$FS
+COPY=/var/tmp/${POOL}
+KEEP=no
+
+cleanup()
+{
+       zfs destroy -rf $FS
+       echo "$CMD: pool I/O summary & status:"
+       echo "----------------------------------------------------"
+       zpool iostat $POOL
+       echo
+       zpool status $POOL
+       echo "----------------------------------------------------"
+       echo
+       zpool destroy -f $POOL
+       rm -rf $COPY
+       rm $POOLFILE $SLOGFILE
+}
+
+bail()
+{
+       test $KEEP = no && cleanup
+       echo "$1"
+       exit 1
+}
+
+test $# -eq 0 || bail "usage: $CMD"
+
+# ====================================================================
+# PREP
+#
+# Create a pool using a file based vdev
+# Create a destination for runtime copy of FS
+# Freeze transaction syncing in the pool
+# ====================================================================
+truncate -s "$DEVSIZE" $POOLFILE || bail "can't make $POOLFILE"
+truncate -s "$DEVSIZE" $SLOGFILE || bail "can't make $SLOGFILE"
+zpool create $POOL $POOLFILE log $SLOGFILE || bail "can't create pool
+$POOL"
+zpool list $POOL
+
+zfs set compression=on $POOL || bail "can't enable compression on $POOL"
+zfs create $FS || bail "can't create $FS"
+mkdir -p $COPY || bail "can't create $COPY"
+
+#
+# This dd command works around an issue where ZIL records aren't created
+# after freezing the pool unless a ZIL header already exists. Create a file
+# synchronously to force ZFS to write one out.
+#
+dd if=/dev/zero of=$ROOT/sync conv=fdatasync,fsync bs=1 count=1 2> /dev/null
+
+zpool freeze $POOL || bail "can't freeze $POOL"
+
+# ====================================================================
+# TESTS
+#
+# Add operations here that will add commit records to the ZIL
+#
+# Use $ROOT for all file name prefixes
+# ====================================================================
+
+#
+# TX_CREATE
+#
+touch $ROOT/a
+
+#
+# TX_RENAME
+#
+mv $ROOT/a $ROOT/b
+
+#
+# TX_SYMLINK
+#
+touch $ROOT/c
+ln -s $ROOT/c $ROOT/d
+
+#
+# TX_LINK
+#
+touch $ROOT/e
+ln $ROOT/e $ROOT/f
+
+#
+# TX_MKDIR
+#
+mkdir $ROOT/dir_to_delete
+
+#
+# TX_RMDIR
+#
+rmdir $ROOT/dir_to_delete
+
+#
+# Create a simple validation payload
+#
+PAYLOAD=$(modinfo -F filename zfs)
+cp "$PAYLOAD" "$ROOT/payload"
+CHECKSUM_BEFORE=$(sha256sum -b "$PAYLOAD")
+
+#
+# TX_WRITE (small file with ordering)
+#
+if is_linux; then
+       cp /proc/self/mounts $ROOT/small_file
+else
+       cp /etc/mtab $ROOT/small_file
+fi
+cp /etc/profile $ROOT/small_file
+
+#
+# TX_CREATE, TX_MKDIR, TX_REMOVE, TX_RMDIR
+#
+cp -R /usr/share/dict $ROOT
+rm -rf $ROOT/dict
+
+#
+# TX_SETATTR
+#
+touch $ROOT/setattr
+chmod 567 $ROOT/setattr
+chgrp root $ROOT/setattr
+touch -cm -t 201311271200 $ROOT/setattr
+
+#
+# TX_TRUNCATE (to zero)
+#
+cp /etc/services $ROOT/truncated_file
+> $ROOT/truncated_file
+
+#
+# Write to an open but removed file
+#
+(sleep 2; date) > $ROOT/date & sleep 1; rm $ROOT/date; wait
+
+#
+# TX_WRITE (large file)
+#
+dd if=/usr/share/lib/termcap of=$ROOT/large bs=128k oflag=sync 2> /dev/null
+
+#
+# Write zeroes, which compresss to holes, in the middle of a file
+#
+dd if=$POOLFILE of=$ROOT/holes.1 bs=128k count=8 2> /dev/null
+dd if=/dev/zero of=$ROOT/holes.1 bs=128k count=2 2> /dev/null
+
+dd if=$POOLFILE of=$ROOT/holes.2 bs=128k count=8 2> /dev/null
+dd if=/dev/zero of=$ROOT/holes.2 bs=128k count=2 oseek=2 2> /dev/null
+
+dd if=$POOLFILE of=$ROOT/holes.3 bs=128k count=8 2> /dev/null
+dd if=/dev/zero of=$ROOT/holes.3 bs=128k count=2 oseek=2 conv=notrunc 2> /dev/null
+
+#
+# TX_MKXATTR
+#
+mkdir $ROOT/xattr.dir
+attr -qs fileattr -V HelloWorld $ROOT/xattr.dir
+attr -qs tmpattr -V HelloWorld $ROOT/xattr.dir
+attr -qr tmpattr $ROOT/xattr.dir
+
+touch $ROOT/xattr.file
+attr -qs fileattr -V HelloWorld $ROOT/xattr.file
+attr -qs tmpattr -V HelloWorld $ROOT/xattr.file
+attr -qr tmpattr $ROOT/xattr.file
+rm $ROOT/xattr.file
+
+
+# ====================================================================
+# REPLAY
+# ====================================================================
+
+KEEP=yes       # keep stuff around if we fail, so we can look at it
+
+cd $ROOT
+find . | cpio -pdmu --quiet $COPY
+echo
+cd /
+
+zfs unmount $FS || bail "can't unmount $FS"
+
+echo "$CMD: transactions to replay:"
+echo "----------------------------------------------------"
+zdb -ivv $FS || bail "can't run zdb on $POOL"
+echo "----------------------------------------------------"
+echo
+
+#
+# Export and reimport the pool to unfreeze it and claim log blocks.
+# It has to be import -f because we can't write a frozen pool's labels!
+#
+zpool export $POOL || bail "can't export $POOL"
+zpool import -f -d $POOLDIR $POOL || bail "can't import $POOL"
+
+# ====================================================================
+# VERIFY
+# ====================================================================
+
+echo "$CMD: current block usage:"
+echo "----------------------------------------------------"
+zdb -bcv $POOL || bail "blocks were leaked!"
+echo "----------------------------------------------------"
+echo
+
+echo "$CMD: Copy of xattrs:"
+echo "----------------------------------------------------"
+attr -l $ROOT/xattr.dir || bail "can't list xattrs"
+echo "----------------------------------------------------"
+echo
+
+echo "$CMD: Results of workingset diff:"
+echo "----------------------------------------------------"
+diff -r $ROOT $COPY > /dev/null || diff -r $ROOT $COPY || bail "replay diffs!"
+
+echo "$CHECKSUM_BEFORE" | sha256sum -c || bail "payload checksums don't match"
+echo "payload checksum matched"
+echo "----------------------------------------------------"
+echo
+
+cleanup
+
+exit 0
diff --git a/zfs/scripts/zimport.sh b/zfs/scripts/zimport.sh
new file mode 100755 (executable)
index 0000000..3488460
--- /dev/null
@@ -0,0 +1,505 @@
+#!/bin/bash
+#
+# Verify that an assortment of known good reference pools can be imported
+# using different versions of the ZoL code.
+#
+# By default references pools for the major ZFS implementation will be
+# checked against the most recent ZoL tags and the master development branch.
+# Alternate tags or branches may be verified with the '-s <src-tag> option.
+# Passing the keyword "installed" will instruct the script to test whatever
+# version is installed.
+#
+# Preferentially a reference pool is used for all tests.  However, if one
+# does not exist and the pool-tag matches one of the src-tags then a new
+# reference pool will be created using binaries from that source build.
+# This is particularly useful when you need to test your changes before
+# opening a pull request.  The keyword 'all' can be used as short hand
+# refer to all available reference pools.
+#
+# New reference pools may be added by placing a bzip2 compressed tarball
+# of the pool in the scripts/zfs-images directory and then passing
+# the -p <pool-tag> option.  To increase the test coverage reference pools
+# should be collected for all the major ZFS implementations.  Having these
+# pools easily available is also helpful to the developers.
+#
+# Care should be taken to run these tests with a kernel supported by all
+# the listed tags.  Otherwise build failure will cause false positives.
+#
+#
+# EXAMPLES:
+#
+# The following example will verify the zfs-0.6.2 tag, the master branch,
+# and the installed zfs version can correctly import the listed pools.
+# Note there is no reference pool available for master and installed but
+# because binaries are available one is automatically constructed.  The
+# working directory is also preserved between runs (-k) preventing the
+# need to rebuild from source for multiple runs.
+#
+#  zimport.sh -k -f /var/tmp/zimport \
+#      -s "zfs-0.6.2 master installed" \
+#      -p "zevo-1.1.1 zol-0.6.2 zol-0.6.2-173 master installed"
+#
+# --------------------- ZFS on Linux Source Versions --------------
+#                 zfs-0.6.2       master          0.6.2-175_g36eb554
+# -----------------------------------------------------------------
+# Clone SPL       Local                Local           Skip
+# Clone ZFS       Local                Local           Skip
+# Build SPL       Pass         Pass            Skip
+# Build ZFS       Pass         Pass            Skip
+# -----------------------------------------------------------------
+# zevo-1.1.1      Pass         Pass            Pass
+# zol-0.6.2       Pass         Pass            Pass
+# zol-0.6.2-173   Fail         Pass            Pass
+# master          Pass         Pass            Pass
+# installed       Pass         Pass            Pass
+#
+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=zimport.sh
+
+SRC_TAGS="zfs-0.6.1 zfs-0.6.2 master"
+POOL_TAGS="all master"
+TEST_DIR=`mktemp -u -d -p /var/tmp zimport.XXXXXXXX`
+KEEP=0
+VERBOSE=0
+COLOR=1
+REPO="https://github.com/zfsonlinux"
+IMAGES_DIR="$SCRIPTDIR/zfs-images/"
+IMAGES_TAR="https://github.com/zfsonlinux/zfs-images/tarball/master"
+ERROR=0
+
+CONFIG_LOG="configure.log"
+CONFIG_OPTIONS=${CONFIG_OPTIONS:-""}
+MAKE_LOG="make.log"
+MAKE_OPTIONS=${MAKE_OPTIONS:-"-s -j$(nproc)"}
+
+usage() {
+cat << EOF
+USAGE:
+zimport.sh [hvl] [-r repo] [-s src-tag] [-i pool-dir] [-p pool-tag] [-f path]
+
+DESCRIPTION:
+       ZPOOL import verification tests
+
+OPTIONS:
+       -h                Show this message
+       -v                Verbose
+       -c                No color
+       -k                Keep temporary directory
+       -r <repo>         Source repository ($REPO)
+       -s <src-tag>...   Verify ZoL versions with the listed tags
+       -i <pool-dir>     Pool image directory
+       -p <pool-tag>...  Verify pools created with the listed tags
+       -f <path>         Temporary directory to use
+
+EOF
+}
+
+while getopts 'hvckr:s:i:p:f:?' OPTION; do
+       case $OPTION in
+       h)
+               usage
+               exit 1
+               ;;
+       v)
+               VERBOSE=1
+               ;;
+       c)
+               COLOR=0
+               ;;
+       k)
+               KEEP=1
+               ;;
+       r)
+               REPO="$OPTARG"
+               ;;
+       s)
+               SRC_TAGS="$OPTARG"
+               ;;
+       i)
+               IMAGES_DIR="$OPTARG"
+               ;;
+       p)
+               POOL_TAGS="$OPTARG"
+               ;;
+       f)
+               TEST_DIR="$OPTARG"
+               ;;
+       ?)
+               usage
+               exit
+               ;;
+       esac
+done
+
+# Initialize the test suite
+init
+check_modules || die "ZFS modules must be unloaded"
+
+SRC_DIR="$TEST_DIR/src"
+SRC_DIR_SPL="$SRC_DIR/spl"
+SRC_DIR_ZFS="$SRC_DIR/zfs"
+
+if [ $COLOR -eq 0 ]; then
+       COLOR_GREEN=""
+       COLOR_BROWN=""
+       COLOR_RED=""
+       COLOR_RESET=""
+fi
+
+pass_nonewline() {
+       echo -n -e "${COLOR_GREEN}Pass${COLOR_RESET}\t\t"
+}
+
+skip_nonewline() {
+       echo -n -e "${COLOR_BROWN}Skip${COLOR_RESET}\t\t"
+}
+
+fail_nonewline() {
+       echo -n -e "${COLOR_RED}Fail${COLOR_RESET}\t\t"
+}
+
+#
+# Set several helper variables which are derived from a source tag.
+#
+# SPL_TAG - The tag zfs-x.y.z is translated to spl-x.y.z.
+# SPL_DIR - The spl directory name.
+# SPL_URL - The spl github URL to fetch the tarball.
+# ZFS_TAG - The passed zfs-x.y.z tag
+# ZFS_DIR - The zfs directory name
+# ZFS_URL - The zfs github URL to fetch the tarball
+#
+src_set_vars() {
+       local TAG=$1
+
+       SPL_TAG=`echo $TAG | sed -e 's/zfs/spl/'`
+       SPL_DIR=$SRC_DIR_SPL/$SPL_TAG
+       SPL_URL=$REPO/spl/tarball/$SPL_TAG
+
+       ZFS_TAG=$TAG
+       ZFS_DIR=$SRC_DIR_ZFS/$ZFS_TAG
+       ZFS_URL=$REPO/zfs/tarball/$ZFS_TAG
+
+       if [ "$TAG" = "installed" ]; then
+               ZPOOL_CMD=`which zpool`
+               ZFS_CMD=`which zfs`
+               ZFS_SH="/usr/share/zfs/zfs.sh"
+               ZPOOL_CREATE="/usr/share/zfs/zpool-create.sh"
+       else
+               ZPOOL_CMD="./cmd/zpool/zpool"
+               ZFS_CMD="./cmd/zfs/zfs"
+               ZFS_SH="./scripts/zfs.sh"
+               ZPOOL_CREATE="./scripts/zpool-create.sh"
+       fi
+}
+
+#
+# Set several helper variables which are derived from a pool name such
+# as zol-0.6.x, zevo-1.1.1, etc.  These refer to example pools from various
+# ZFS implementations which are used to verify compatibility.
+#
+# POOL_TAG          - The example pools name in scripts/zfs-images/.
+# POOL_BZIP         - The full path to the example bzip2 compressed pool.
+# POOL_DIR          - The top level test path for this pool.
+# POOL_DIR_PRISTINE - The directory containing a pristine version of the pool.
+# POOL_DIR_COPY     - The directory containing a working copy of the pool.
+# POOL_DIR_SRC      - Location of a source build if it exists for this pool.
+#
+pool_set_vars() {
+       local TAG=$1
+
+       POOL_TAG=$TAG
+       POOL_BZIP=$IMAGES_DIR/$POOL_TAG.tar.bz2
+       POOL_DIR=$TEST_DIR/pools/$POOL_TAG
+       POOL_DIR_PRISTINE=$POOL_DIR/pristine
+       POOL_DIR_COPY=$POOL_DIR/copy
+       POOL_DIR_SRC=`echo -n "$SRC_DIR_ZFS/"; \
+           echo "$POOL_TAG" | sed -e 's/zol/zfs/'`
+}
+
+#
+# Construct a non-trivial pool given a specific version of the source.  More
+# interesting pools provide better test coverage so this function should
+# extended as needed to create more realistic pools.
+#
+pool_create() {
+       pool_set_vars $1
+       src_set_vars $1
+
+       if [ "$POOL_TAG" != "installed" ]; then
+               cd $POOL_DIR_SRC
+       fi
+
+       $ZFS_SH zfs="spa_config_path=$POOL_DIR_PRISTINE" || fail 1
+
+       # Create a file vdev RAIDZ pool.
+       FILEDIR="$POOL_DIR_PRISTINE" $ZPOOL_CREATE \
+           -c file-raidz -p $POOL_TAG -v -x >/dev/null || fail 2
+
+       # Create a pool/fs filesystem with some random contents.
+       $ZFS_CMD create $POOL_TAG/fs || fail 3
+       populate /$POOL_TAG/fs/ 10 100
+
+       # Snapshot that filesystem, clone it, remove the files/dirs,
+       # replace them with new files/dirs.
+       $ZFS_CMD snap $POOL_TAG/fs@snap || fail 4
+       $ZFS_CMD clone $POOL_TAG/fs@snap $POOL_TAG/clone || fail 5
+       rm -Rf /$POOL_TAG/clone/* || fail 6
+       populate /$POOL_TAG/clone/ 10 100
+
+       # Scrub the pool, delay slightly, then export it.  It is now
+       # somewhat interesting for testing purposes.
+       $ZPOOL_CMD scrub $POOL_TAG || fail 7
+       sleep 10
+       $ZPOOL_CMD export $POOL_TAG || fail 8
+
+       $ZFS_SH -u || fail 9
+}
+
+# If the zfs-images directory doesn't exist fetch a copy from Github then
+# cache it in the $TEST_DIR and update $IMAGES_DIR.
+if [ ! -d $IMAGES_DIR ]; then
+       IMAGES_DIR="$TEST_DIR/zfs-images"
+       mkdir -p $IMAGES_DIR
+       curl -sL $IMAGES_TAR | \
+           tar -xz -C $IMAGES_DIR --strip-components=1 || fail 10
+fi
+
+# Given the available images in the zfs-images directory substitute the
+# list of available images for the reserved keywork 'all'.
+for TAG in $POOL_TAGS; do
+
+       if  [ "$TAG" = "all" ]; then
+               ALL_TAGS=`ls $IMAGES_DIR | grep "tar.bz2" | \
+                   sed 's/.tar.bz2//' | tr '\n' ' '`
+               NEW_TAGS="$NEW_TAGS $ALL_TAGS"
+       else
+               NEW_TAGS="$NEW_TAGS $TAG"
+       fi
+done
+POOL_TAGS="$NEW_TAGS"
+
+if [ $VERBOSE -ne 0 ]; then
+       echo "---------------------------- Options ----------------------------"
+       echo "VERBOSE=$VERBOSE"
+       echo "KEEP=$KEEP"
+       echo "REPO=$REPO"
+       echo "SRC_TAGS="$SRC_TAGS""
+       echo "POOL_TAGS="$POOL_TAGS""
+       echo "PATH=$TEST_DIR"
+       echo
+fi
+
+if [ ! -d $TEST_DIR ]; then
+       mkdir -p $TEST_DIR
+fi
+
+if [ ! -d $SRC_DIR ]; then
+       mkdir -p $SRC_DIR
+fi
+
+# Print a header for all tags which are being tested.
+echo "--------------------- ZFS on Linux Source Versions --------------"
+printf "%-16s" " "
+for TAG in $SRC_TAGS; do
+       src_set_vars $TAG
+
+       if [ "$TAG" = "installed" ]; then
+               ZFS_VERSION=`modinfo zfs | awk '/version:/ { print $2; exit }'`
+               if [ -n "$ZFS_VERSION" ]; then
+                       printf "%-16s" $ZFS_VERSION
+               else
+                       echo "ZFS is not installed\n"
+                       fail
+               fi
+       else
+               printf "%-16s" $TAG
+       fi
+done
+echo -e "\n-----------------------------------------------------------------"
+
+#
+# Attempt to generate the tarball from your local git repository, if that
+# fails then attempt to download the tarball from Github.
+#
+printf "%-16s" "Clone SPL"
+for TAG in $SRC_TAGS; do
+       src_set_vars $TAG
+
+       if [ -d $SPL_DIR ]; then
+               skip_nonewline
+       elif  [ "$SPL_TAG" = "installed" ]; then
+               skip_nonewline
+       else
+               cd $SRC_DIR
+
+               if [ ! -d $SRC_DIR_SPL ]; then
+                       mkdir -p $SRC_DIR_SPL
+               fi
+
+               git archive --format=tar --prefix=$SPL_TAG/ $SPL_TAG \
+                   -o $SRC_DIR_SPL/$SPL_TAG.tar &>/dev/nul || \
+                   rm $SRC_DIR_SPL/$SPL_TAG.tar
+               if [ -s $SRC_DIR_SPL/$SPL_TAG.tar ]; then
+                       tar -xf $SRC_DIR_SPL/$SPL_TAG.tar -C $SRC_DIR_SPL
+                       rm $SRC_DIR_SPL/$SPL_TAG.tar
+                       echo -n -e "${COLOR_GREEN}Local${COLOR_RESET}\t\t"
+               else
+                       mkdir -p $SPL_DIR || fail 1
+                       curl -sL $SPL_URL | tar -xz -C $SPL_DIR \
+                           --strip-components=1 || fail 2
+                       echo -n -e "${COLOR_GREEN}Remote${COLOR_RESET}\t\t"
+               fi
+       fi
+done
+printf "\n"
+
+#
+# Attempt to generate the tarball from your local git repository, if that
+# fails then attempt to download the tarball from Github.
+#
+printf "%-16s" "Clone ZFS"
+for TAG in $SRC_TAGS; do
+       src_set_vars $TAG
+
+       if [ -d $ZFS_DIR ]; then
+               skip_nonewline
+       elif  [ "$ZFS_TAG" = "installed" ]; then
+               skip_nonewline
+       else
+               cd $SRC_DIR
+
+               if [ ! -d $SRC_DIR_ZFS ]; then
+                       mkdir -p $SRC_DIR_ZFS
+               fi
+
+               git archive --format=tar --prefix=$ZFS_TAG/ $ZFS_TAG \
+                   -o $SRC_DIR_ZFS/$ZFS_TAG.tar &>/dev/nul || \
+                   rm $SRC_DIR_ZFS/$ZFS_TAG.tar
+               if [ -s $SRC_DIR_ZFS/$ZFS_TAG.tar ]; then
+                       tar -xf $SRC_DIR_ZFS/$ZFS_TAG.tar -C $SRC_DIR_ZFS
+                       rm $SRC_DIR_ZFS/$ZFS_TAG.tar
+                       echo -n -e "${COLOR_GREEN}Local${COLOR_RESET}\t\t"
+               else
+                       mkdir -p $ZFS_DIR || fail 1
+                       curl -sL $ZFS_URL | tar -xz -C $ZFS_DIR \
+                           --strip-components=1 || fail 2
+                       echo -n -e "${COLOR_GREEN}Remote${COLOR_RESET}\t\t"
+               fi
+       fi
+done
+printf "\n"
+
+# Build the listed tags
+printf "%-16s" "Build SPL"
+for TAG in $SRC_TAGS; do
+       src_set_vars $TAG
+
+       if [ -f $SPL_DIR/module/spl/spl.ko ]; then
+               skip_nonewline
+       elif  [ "$SPL_TAG" = "installed" ]; then
+               skip_nonewline
+       else
+               cd $SPL_DIR
+               make distclean &>/dev/null
+               ./autogen.sh >>$CONFIG_LOG 2>&1 || fail 1
+               ./configure $CONFIG_OPTIONS >>$CONFIG_LOG 2>&1 || fail 2
+               make ${MAKE_OPTIONS} >>$MAKE_LOG 2>&1 || fail 3
+               pass_nonewline
+       fi
+done
+printf "\n"
+
+# Build the listed tags
+printf "%-16s" "Build ZFS"
+for TAG in $SRC_TAGS; do
+       src_set_vars $TAG
+
+       if [ -f $ZFS_DIR/module/zfs/zfs.ko ]; then
+               skip_nonewline
+       elif  [ "$ZFS_TAG" = "installed" ]; then
+               skip_nonewline
+       else
+               cd $ZFS_DIR
+               make distclean &>/dev/null
+               ./autogen.sh >>$CONFIG_LOG 2>&1 || fail 1
+               ./configure --with-spl=$SPL_DIR $CONFIG_OPTIONS \
+                    >>$CONFIG_LOG 2>&1 || fail 2
+               make ${MAKE_OPTIONS} >>$MAKE_LOG 2>&1 || fail 3
+               pass_nonewline
+       fi
+done
+printf "\n"
+echo "-----------------------------------------------------------------"
+
+# Either create a new pool using 'zpool create', or alternately restore an
+# existing pool from another ZFS implementation for compatibility testing.
+for TAG in $POOL_TAGS; do
+       pool_set_vars $TAG
+       SKIP=0
+
+       printf "%-16s" $POOL_TAG
+       rm -Rf $POOL_DIR
+       mkdir -p $POOL_DIR_PRISTINE
+
+       # Use the existing compressed image if available.
+       if [ -f $POOL_BZIP ]; then
+               tar -xjf $POOL_BZIP -C $POOL_DIR_PRISTINE \
+                   --strip-components=1 || fail 1
+       # Use the installed version to create the pool.
+       elif  [ "$TAG" = "installed" ]; then
+               pool_create $TAG
+       # A source build is available to create the pool.
+       elif [ -d $POOL_DIR_SRC ]; then
+               pool_create $TAG
+       else
+               SKIP=1
+       fi
+
+       # Verify 'zpool import' works for all listed source versions.
+       for TAG in $SRC_TAGS; do
+
+               if [ $SKIP -eq 1 ]; then
+                       skip_nonewline
+                       continue
+               fi
+
+               src_set_vars $TAG
+               if [ "$TAG" != "installed" ]; then
+                       cd $ZFS_DIR
+               fi
+               $ZFS_SH zfs="spa_config_path=$POOL_DIR_COPY"
+
+               cp -a --sparse=always $POOL_DIR_PRISTINE \
+                   $POOL_DIR_COPY || fail 2
+               POOL_NAME=`$ZPOOL_CMD import -d $POOL_DIR_COPY | \
+                   awk '/pool:/ { print $2; exit 0 }'`
+
+               $ZPOOL_CMD import -N -d $POOL_DIR_COPY $POOL_NAME &>/dev/null
+               if [ $? -ne 0 ]; then
+                       fail_nonewline
+                       ERROR=1
+               else
+                       $ZPOOL_CMD export $POOL_NAME || fail 3
+                       pass_nonewline
+               fi
+
+               rm -Rf $POOL_DIR_COPY
+
+               $ZFS_SH -u || fail 4
+       done
+       printf "\n"
+done
+
+if [ ! $KEEP ]; then
+       rm -Rf $TEST_DIR
+fi
+
+exit $ERROR
diff --git a/zfs/scripts/zloop.sh b/zfs/scripts/zloop.sh
new file mode 100755 (executable)
index 0000000..580fcfe
--- /dev/null
@@ -0,0 +1,246 @@
+#!/bin/bash
+
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2015 by Delphix. All rights reserved.
+# Copyright (C) 2016 Lawrence Livermore National Security, LLC.
+#
+
+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=zloop.sh
+
+DEFAULTWORKDIR=/var/tmp
+DEFAULTCOREDIR=/var/tmp/zloop
+
+function usage
+{
+       echo -e "\n$0 [-t <timeout>] [-c <dump directory>]" \
+           "[ -- [extra ztest parameters]]\n" \
+           "\n" \
+           "  This script runs ztest repeatedly with randomized arguments.\n" \
+           "  If a crash is encountered, the ztest logs, any associated\n" \
+           "  vdev files, and core file (if one exists) are moved to the\n" \
+           "  output directory ($DEFAULTCOREDIR by default). Any options\n" \
+           "  after the -- end-of-options marker will be passed to ztest.\n" \
+           "\n" \
+           "  Options:\n" \
+           "    -t  Total time to loop for, in seconds. If not provided,\n" \
+           "        zloop runs forever.\n" \
+           "    -f  Specify working directory for ztest vdev files.\n" \
+           "    -c  Specify a core dump directory to use.\n" \
+           "    -h  Print this help message.\n" \
+           "" >&2
+}
+
+function or_die
+{
+       $@
+       if [[ $? -ne 0 ]]; then
+               echo "Command failed: $@"
+               exit 1
+       fi
+}
+
+# core file helpers
+origcorepattern="$(cat /proc/sys/kernel/core_pattern)"
+coreglob="$(egrep -o '^([^|%[:space:]]*)' /proc/sys/kernel/core_pattern)*"
+
+if [[ $coreglob = "*" ]]; then
+        echo "Setting core file pattern..."
+        echo "core" > /proc/sys/kernel/core_pattern
+        coreglob="$(egrep -o '^([^|%[:space:]]*)' \
+            /proc/sys/kernel/core_pattern)*"
+fi
+
+function core_file
+{
+        printf "%s" "$(ls -tr1 $coreglob 2> /dev/null | head -1)"
+}
+
+function core_prog
+{
+       prog=$ZTEST
+       core_id=$($GDB --batch -c $1 | grep "Core was generated by" | \
+           tr  \' ' ')
+       if [[ "$core_id" =~ "zdb "  ]]; then
+               prog=$ZDB
+       fi
+       printf "%s" "$prog"
+}
+
+function store_core
+{
+       core="$(core_file)"
+       if [[ $ztrc -ne 0 ]] || [[ -f "$core" ]]; then
+               coreid=$(date "+zloop-%y%m%d-%H%M%S")
+               foundcrashes=$(($foundcrashes + 1))
+
+               dest=$coredir/$coreid
+               or_die mkdir -p $dest
+               or_die mkdir -p $dest/vdev
+
+               echo "*** ztest crash found - moving logs to $dest"
+
+               or_die mv ztest.history $dest/
+               or_die mv ztest.ddt $dest/
+               or_die mv ztest.out $dest/
+               or_die mv $workdir/ztest* $dest/vdev/
+               or_die mv $workdir/zpool.cache $dest/vdev/
+
+               # check for core
+               if [[ -f "$core" ]]; then
+                       coreprog=$(core_prog $core)
+                       corestatus=$($GDB --batch --quiet \
+                           -ex "set print thread-events off" \
+                           -ex "printf \"*\n* Backtrace \n*\n\"" \
+                           -ex "bt" \
+                           -ex "printf \"*\n* Libraries \n*\n\"" \
+                           -ex "info sharedlib" \
+                           -ex "printf \"*\n* Threads (full) \n*\n\"" \
+                           -ex "info threads" \
+                           -ex "printf \"*\n* Backtraces \n*\n\"" \
+                           -ex "thread apply all bt" \
+                           -ex "printf \"*\n* Backtraces (full) \n*\n\"" \
+                           -ex "thread apply all bt full" \
+                           -ex "quit" $coreprog "$core" | grep -v "New LWP")
+
+                       # Dump core + logs to stored directory
+                       echo "$corestatus" >>$dest/status
+                       or_die mv "$core" $dest/
+
+                       # Record info in cores logfile
+                       echo "*** core @ $coredir/$coreid/$core:" | \
+                           tee -a ztest.cores
+                       echo "$corestatus" | tee -a ztest.cores
+                       echo "" | tee -a ztest.cores
+               fi
+               echo "continuing..."
+       fi
+}
+
+# parse arguments
+# expected format: zloop [-t timeout] [-c coredir] [-- extra ztest args]
+coredir=$DEFAULTCOREDIR
+workdir=$DEFAULTWORKDIR
+timeout=0
+while getopts ":ht:c:f:" opt; do
+       case $opt in
+               t ) [[ $OPTARG -gt 0 ]] && timeout=$OPTARG ;;
+               c ) [[ $OPTARG ]] && coredir=$OPTARG ;;
+               f ) [[ $OPTARG ]] && workdir=$(readlink -f $OPTARG) ;;
+               h ) usage
+                   exit 2
+                   ;;
+               * ) echo "Invalid argument: -$OPTARG";
+                   usage
+                   exit 1
+       esac
+done
+# pass remaining arguments on to ztest
+shift $((OPTIND - 1))
+
+# enable core dumps
+ulimit -c unlimited
+
+if [[ -f "$(core_file)" ]]; then
+       echo -n "There's a core dump here you might want to look at first... "
+       echo "$(core_file)"
+       exit 1
+fi
+
+if [[ ! -d $coredir ]]; then
+       echo "core dump directory ($coredir) does not exist, creating it."
+       or_die mkdir -p $coredir
+fi
+
+if [[ ! -w $coredir ]]; then
+       echo "core dump directory ($coredir) is not writable."
+       exit 1
+fi
+
+or_die rm -f ztest.history
+or_die rm -f ztest.ddt
+or_die rm -f ztest.cores
+
+ztrc=0         # ztest return value
+foundcrashes=0 # number of crashes found so far
+starttime=$(date +%s)
+curtime=$starttime
+
+# if no timeout was specified, loop forever.
+while [[ $timeout -eq 0 ]] || [[ $curtime -le $(($starttime + $timeout)) ]]; do
+       zopt="-VVVVV"
+
+       # switch between common arrangements & fully randomized
+       if [[ $((RANDOM % 2)) -eq 0 ]]; then
+               mirrors=2
+               raidz=0
+               parity=1
+               vdevs=2
+       else
+               mirrors=$(((RANDOM % 3) * 1))
+               parity=$(((RANDOM % 3) + 1))
+               raidz=$((((RANDOM % 9) + parity + 1) * (RANDOM % 2)))
+               vdevs=$(((RANDOM % 3) + 3))
+       fi
+       align=$(((RANDOM % 2) * 3 + 9))
+       runtime=$((RANDOM % 100))
+       passtime=$((RANDOM % (runtime / 3 + 1) + 10))
+       size=128m
+
+       zopt="$zopt -m $mirrors"
+       zopt="$zopt -r $raidz"
+       zopt="$zopt -R $parity"
+       zopt="$zopt -v $vdevs"
+       zopt="$zopt -a $align"
+       zopt="$zopt -T $runtime"
+       zopt="$zopt -P $passtime"
+       zopt="$zopt -s $size"
+       zopt="$zopt -f $workdir"
+
+       cmd="$ZTEST $zopt $@"
+       desc="$(date '+%m/%d %T') $cmd"
+       echo "$desc" | tee -a ztest.history
+       echo "$desc" >>ztest.out
+       $cmd >>ztest.out 2>&1
+       ztrc=$?
+       egrep '===|WARNING' ztest.out >>ztest.history
+       $ZDB -U $workdir/zpool.cache -DD ztest >>ztest.ddt
+
+       store_core
+
+       curtime=$(date +%s)
+done
+
+echo "zloop finished, $foundcrashes crashes found"
+
+#restore core pattern
+echo "$origcorepattern" > /proc/sys/kernel/core_pattern
+
+uptime >>ztest.out
+
+if [[ $foundcrashes -gt 0 ]]; then
+       exit 1
+fi
diff --git a/zfs/scripts/zol2zfs-patch.sed b/zfs/scripts/zol2zfs-patch.sed
new file mode 100755 (executable)
index 0000000..bb6d9fa
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sed -f
+
+s:cmd:usr/src/cmd:g
+s:include/libzfs.h:usr/src/lib/libzfs/common/libzfs.h:g
+s:include/libzfs_core.h:usr/src/lib/libzfs_core/common/libzfs_core.h:g
+s:include/sys:lib/libzpool/common/sys:g
+s:include/sys:usr/src/uts/common/fs/zfs/sys:g
+s:include/sys:usr/src/uts/common/sys:g
+s:include/zfs_fletcher.h:usr/src/common/zfs/zfs_fletcher.h:g
+s:include:usr/src/common/zfs:g
+s:lib/libzfs:usr/src/lib/libzfs/common:g
+s:lib/libzfs_core:usr/src/lib/libzfs_core/common:g
+s:lib/libzpool:lib/libzpool/common:g
+s:lib/libzpool:usr/src/lib/libzpool:g
+s:man/man5/zpool-features.5:usr/src/man/man5/zpool-features.5:g
+s:man/man8/zfs.8:usr/src/man/man1m/zfs.1m:g
+s:module/nvpair:usr/src/common/nvpair:g
+s:module/zcommon:usr/src/common/zfs/:g
+s:module/zfs:usr/src/uts/common/fs/zfs:g
+s:tests/zfs-tests:test/zfs-tests:g
diff --git a/zfs/scripts/zpios-profile/Makefile.am b/zfs/scripts/zpios-profile/Makefile.am
new file mode 100644 (file)
index 0000000..c87f169
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdataprofiledir = $(pkgdatadir)/zpios-profile
+dist_pkgdataprofile_SCRIPTS = \
+       $(top_srcdir)/scripts/zpios-profile/zpios-profile-disk.sh \
+       $(top_srcdir)/scripts/zpios-profile/zpios-profile-pids.sh \
+       $(top_srcdir)/scripts/zpios-profile/zpios-profile-post.sh \
+       $(top_srcdir)/scripts/zpios-profile/zpios-profile-pre.sh \
+       $(top_srcdir)/scripts/zpios-profile/zpios-profile.sh
diff --git a/zfs/scripts/zpios-profile/Makefile.in b/zfs/scripts/zpios-profile/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/scripts/zpios-profile/zpios-profile-disk.sh b/zfs/scripts/zpios-profile/zpios-profile-disk.sh
new file mode 100755 (executable)
index 0000000..b56ee1e
--- /dev/null
@@ -0,0 +1,129 @@
+#!/bin/bash
+#
+# /proc/diskinfo <after skipping major/minor>
+# Field 1 -- device name
+# Field 2 -- # of reads issued
+# Field 3 -- # of reads merged
+# Field 4 -- # of sectors read
+# Field 5 -- # of milliseconds spent reading
+# Field 6 -- # of writes completed
+# Field 7 -- # of writes merged
+# Field 8 -- # of sectors written
+# Field 9 -- # of milliseconds spent writing
+# Field 10 -- # of I/Os currently in progress
+# Field 11 -- # of milliseconds spent doing I/Os
+# Field 12 -- weighted # of milliseconds spent doing I/Os
+
+PROG=zpios-profile-disk.sh
+
+RUN_PIDS=${0}
+RUN_LOG_DIR=${1}
+RUN_ID=${2}
+
+create_table() {
+       local FIELD=$1
+       local ROW_M=()
+       local ROW_N=()
+       local HEADER=1
+       local STEP=1
+
+       for DISK_FILE in `ls -r --sort=time --time=ctime ${RUN_LOG_DIR}/${RUN_ID}/disk-[0-9]*`; do
+               ROW_M=( ${ROW_N[@]} )
+               ROW_N=( `cat ${DISK_FILE} | grep sd | cut -c11- | cut -f${FIELD} -d' ' | tr "\n" "\t"` )
+
+               if [ $HEADER -eq 1 ]; then
+                       echo -n "step, "
+                       cat ${DISK_FILE} | grep sd | cut -c11- | cut -f1 -d' ' | tr "\n" ", "
+                       echo "total"
+                       HEADER=0
+               fi
+
+               if [ ${#ROW_M[@]} -eq 0 ]; then
+                       continue
+               fi
+
+               if [ ${#ROW_M[@]} -ne ${#ROW_N[@]} ]; then
+                       echo "Badly formatted profile data in ${DISK_FILE}"
+                       break
+               fi
+
+               TOTAL=0
+               echo -n "${STEP}, "
+               for (( i=0; i<${#ROW_N[@]}; i++ )); do
+                       DELTA=`echo "${ROW_N[${i}]}-${ROW_M[${i}]}" | bc`
+                       let TOTAL=${TOTAL}+${DELTA}
+                       echo -n "${DELTA}, "
+               done
+               echo "${TOTAL}, "
+
+               let STEP=${STEP}+1
+       done
+}
+
+create_table_mbs() {
+       local FIELD=$1
+       local TIME=$2
+       local ROW_M=()
+       local ROW_N=()
+       local HEADER=1
+       local STEP=1
+
+       for DISK_FILE in `ls -r --sort=time --time=ctime ${RUN_LOG_DIR}/${RUN_ID}/disk-[0-9]*`; do
+               ROW_M=( ${ROW_N[@]} )
+               ROW_N=( `cat ${DISK_FILE} | grep sd | cut -c11- | cut -f${FIELD} -d' ' | tr "\n" "\t"` )
+
+               if [ $HEADER -eq 1 ]; then
+                       echo -n "step, "
+                       cat ${DISK_FILE} | grep sd | cut -c11- | cut -f1 -d' ' | tr "\n" ", "
+                       echo "total"
+                       HEADER=0
+               fi
+
+               if [ ${#ROW_M[@]} -eq 0 ]; then
+                       continue
+               fi
+
+               if [ ${#ROW_M[@]} -ne ${#ROW_N[@]} ]; then
+                       echo "Badly formatted profile data in ${DISK_FILE}"
+                       break
+               fi
+
+               TOTAL=0
+               echo -n "${STEP}, "
+               for (( i=0; i<${#ROW_N[@]}; i++ )); do
+                       DELTA=`echo "${ROW_N[${i}]}-${ROW_M[${i}]}" | bc`
+                       MBS=`echo "scale=2; ((${DELTA}*512)/${TIME})/(1024*1024)" | bc`
+                       TOTAL=`echo "scale=2; ${TOTAL}+${MBS}" | bc`
+                       echo -n "${MBS}, "
+               done
+               echo "${TOTAL}, "
+
+               let STEP=${STEP}+1
+       done
+}
+
+echo
+echo "Reads issued per device"
+create_table 2
+echo
+echo "Reads merged per device"
+create_table 3
+echo
+echo "Sectors read per device"
+create_table 4
+echo "MB/s per device"
+create_table_mbs 4 3
+
+echo
+echo "Writes issued per device"
+create_table 6
+echo
+echo "Writes merged per device"
+create_table 7
+echo
+echo "Sectors written per device"
+create_table 8
+echo "MB/s per device"
+create_table_mbs 8 3
+
+exit 0
diff --git a/zfs/scripts/zpios-profile/zpios-profile-pids.sh b/zfs/scripts/zpios-profile/zpios-profile-pids.sh
new file mode 100755 (executable)
index 0000000..3514b38
--- /dev/null
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+PROG=zpios-profile-pids.sh
+
+RUN_PIDS=${0}
+RUN_LOG_DIR=${1}
+RUN_ID=${2}
+
+ROW_M=()
+ROW_N=()
+ROW_N_SCHED=()
+ROW_N_WAIT=()
+
+HEADER=1
+STEP=1
+
+for PID_FILE in `ls -r --sort=time --time=ctime ${RUN_LOG_DIR}/${RUN_ID}/pids-[0-9]*`; do
+       ROW_M=( ${ROW_N[@]} )
+       ROW_N=( 0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 0  0 0 0 )
+       ROW_N_SCHED=( `cat ${PID_FILE} | cut -f15 -d' ' | tr "\n" "\t"` )
+       ROW_N_WAIT=(  `cat ${PID_FILE} | cut -f17 -d' ' | tr "\n" "\t"` )
+       ROW_N_NAMES=( `cat ${PID_FILE} | cut -f2  -d' ' | cut -f2 -d'(' | 
+                       cut -f1 -d')'   | cut -f1  -d'/' | tr "\n" "\t"` )
+
+       for (( i=0; i<${#ROW_N_SCHED[@]}; i++ )); do
+               SUM=`echo "${ROW_N_WAIT[${i}]}+${ROW_N_SCHED[${i}]}" | bc`
+
+               case ${ROW_N_NAMES[${i}]} in
+                       zio_taskq)      IDX=0;;
+                       zio_req_nul)    IDX=1;;
+                       zio_irq_nul)    IDX=2;;
+                       zio_req_rd)     IDX=3;;
+                       zio_irq_rd)     IDX=4;;
+                       zio_req_wr)     IDX=5;;
+                       zio_irq_wr)     IDX=6;;
+                       zio_req_fr)     IDX=7;;
+                       zio_irq_fr)     IDX=8;;
+                       zio_req_cm)     IDX=9;;
+                       zio_irq_cm)     IDX=10;;
+                       zio_req_ctl)    IDX=11;;
+                       zio_irq_ctl)    IDX=12;;
+                       txg_quiesce)    IDX=13;;
+                       txg_sync)       IDX=14;;
+                       txg_timelimit)  IDX=15;;
+                       arc_reclaim)    IDX=16;;
+                       l2arc_feed)     IDX=17;;
+                       zpios_io)       IDX=18;;
+                       *)              continue;;
+               esac
+
+               let ROW_N[${IDX}]=${ROW_N[${IDX}]}+${SUM}
+       done
+
+       if [ $HEADER -eq 1 ]; then
+               echo "step, zio_taskq, zio_req_nul, zio_irq_nul, "        \
+                     "zio_req_rd, zio_irq_rd, zio_req_wr, zio_irq_wr, "   \
+                     "zio_req_fr, zio_irq_fr, zio_req_cm, zio_irq_cm, "   \
+                     "zio_req_ctl, zio_irq_ctl, txg_quiesce, txg_sync, "  \
+                     "txg_timelimit, arc_reclaim, l2arc_feed, zpios_io, " \
+                    "idle"
+               HEADER=0
+       fi
+
+       if [ ${#ROW_M[@]} -eq 0 ]; then
+               continue
+       fi
+
+       if [ ${#ROW_M[@]} -ne ${#ROW_N[@]} ]; then
+               echo "Badly formatted profile data in ${PID_FILE}"
+               break
+       fi
+
+       # Original values are in jiffies and we expect HZ to be 1000
+       # on most 2.6 systems thus we divide by 10 to get a percentage.
+       IDLE=1000
+        echo -n "${STEP}, "
+       for (( i=0; i<${#ROW_N[@]}; i++ )); do
+               DELTA=`echo "${ROW_N[${i}]}-${ROW_M[${i}]}" | bc`
+               DELTA_PERCENT=`echo "scale=1; ${DELTA}/10" | bc`
+               let IDLE=${IDLE}-${DELTA}
+               echo -n "${DELTA_PERCENT}, "
+       done
+       ILDE_PERCENT=`echo "scale=1; ${IDLE}/10" | bc`
+       echo "${ILDE_PERCENT}"
+
+       let STEP=${STEP}+1
+done
+
+exit
+
+echo
+echo "Percent of total system time per pid"
+for PID_FILE in `ls -r --sort=time --time=ctime ${RUN_LOG_DIR}/${RUN_ID}/pids-[0-9]*`; do
+       ROW_M=( ${ROW_N[@]} )
+       ROW_N_SCHED=( `cat ${PID_FILE} | cut -f15 -d' ' | tr "\n" "\t"` )
+       ROW_N_WAIT=( `cat ${PID_FILE} | cut -f17 -d' ' | tr "\n" "\t"` )
+
+       for (( i=0; i<${#ROW_N_SCHED[@]}; i++ )); do
+               ROW_N[${i}]=`echo "${ROW_N_WAIT[${i}]}+${ROW_N_SCHED[${i}]}" | bc`
+       done
+
+       if [ $HEADER -eq 1 ]; then
+               echo -n "step, "
+               cat ${PID_FILE} | cut -f2 -d' ' | tr "\n" ", "
+               echo
+               HEADER=0
+       fi
+
+       if [ ${#ROW_M[@]} -eq 0 ]; then
+               continue
+       fi
+
+       if [ ${#ROW_M[@]} -ne ${#ROW_N[@]} ]; then
+               echo "Badly formatted profile data in ${PID_FILE}"
+               break
+       fi
+
+       # Original values are in jiffies and we expect HZ to be 1000
+       # on most 2.6 systems thus we divide by 10 to get a percentage.
+        echo -n "${STEP}, "
+       for (( i=0; i<${#ROW_N[@]}; i++ )); do
+               DELTA=`echo "scale=1; (${ROW_N[${i}]}-${ROW_M[${i}]})/10" | bc`
+               echo -n "${DELTA}, "
+       done
+
+       echo
+       let STEP=${STEP}+1
+done
+
+
+exit 0
diff --git a/zfs/scripts/zpios-profile/zpios-profile-post.sh b/zfs/scripts/zpios-profile/zpios-profile-post.sh
new file mode 100755 (executable)
index 0000000..3a454ba
--- /dev/null
@@ -0,0 +1,129 @@
+#!/bin/bash
+
+PROG=zpios-profile-post.sh
+
+RUN_POST=${0}
+RUN_PHASE=${1}
+RUN_DIR=${2}
+RUN_ID=${3}
+RUN_POOL=${4}
+RUN_CHUNK_SIZE=${5}
+RUN_REGION_SIZE=${6}
+RUN_THRD_COUNT=${7}
+RUN_REGION_COUNT=${8}
+RUN_OFFSET=${9}
+RUN_REGION_NOISE=${10}
+RUN_CHUNK_NOISE=${11}
+RUN_THRD_DELAY=${12}
+RUN_FLAGS=${13}
+RUN_RESULT=${14}
+
+# Summarize system time per process
+zpios_profile_post_pids() {
+       ${PROFILE_PIDS} ${PROFILE_RUN_CR_PIDS_LOG} >${PROFILE_RUN_CR_PIDS_CSV}
+       ${PROFILE_PIDS} ${PROFILE_RUN_WR_PIDS_LOG} >${PROFILE_RUN_WR_PIDS_CSV}
+       ${PROFILE_PIDS} ${PROFILE_RUN_RD_PIDS_LOG} >${PROFILE_RUN_RD_PIDS_CSV}
+       ${PROFILE_PIDS} ${PROFILE_RUN_RM_PIDS_LOG} >${PROFILE_RUN_RM_PIDS_CSV}
+}
+
+zpios_profile_post_disk() {
+       ${PROFILE_DISK} ${PROFILE_RUN_CR_DISK_LOG} >${PROFILE_RUN_CR_DISK_CSV}
+       ${PROFILE_DISK} ${PROFILE_RUN_WR_DISK_LOG} >${PROFILE_RUN_WR_DISK_CSV}
+       ${PROFILE_DISK} ${PROFILE_RUN_RD_DISK_LOG} >${PROFILE_RUN_RD_DISK_CSV}
+       ${PROFILE_DISK} ${PROFILE_RUN_RM_DISK_LOG} >${PROFILE_RUN_RM_DISK_CSV}
+}
+
+# Summarize per device performance
+
+# Stop a user defined profiling script which is gathering additional data
+zpios_profile_post_stop() {
+       local PROFILE_PID=$1
+
+       kill -s SIGHUP `cat ${PROFILE_PID}`
+
+
+       # Sleep waiting for profile script to exit
+       while [ -f ${PROFILE_PID} ]; do
+               sleep 0.01
+       done
+}
+
+zpios_profile_post_proc_stop() {
+       local PROC_DIR=$1
+
+       if [ -f ${PROFILE_ARC_PROC} ]; then
+               cat ${PROFILE_ARC_PROC} >${PROC_DIR}/arcstats.txt
+       fi
+
+       if [ -f ${PROFILE_VDEV_CACHE_PROC} ]; then
+               cat ${PROFILE_VDEV_CACHE_PROC} >${PROC_DIR}/vdev_cache_stats.txt
+       fi
+}
+
+zpios_profile_post_oprofile_stop() {
+       local OPROFILE_LOG=$1
+       local OPROFILE_ARGS="-a -g -l -p ${OPROFILE_KERNEL_DIR},${OPROFILE_SPL_DIR},${OPROFILE_ZFS_DIR}"
+
+       /usr/bin/opcontrol --stop >>${OPROFILE_LOG} 2>&1
+       /usr/bin/opcontrol --dump >>${OPROFILE_LOG} 2>&1
+       /usr/bin/opreport ${OPROFILE_ARGS} >${OPROFILE_LOG} 2>&1
+       /usr/bin/oparchive
+}
+
+zpios_profile_post_create() {
+       zpios_profile_post_oprofile_stop ${PROFILE_RUN_CR_OPROFILE_LOG}
+       zpios_profile_post_proc_stop ${PROFILE_RUN_CR_DIR}
+       zpios_profile_post_stop ${PROFILE_RUN_CR_PID}
+}
+
+zpios_profile_post_write() {
+       zpios_profile_post_oprofile_stop ${PROFILE_RUN_WR_OPROFILE_LOG}
+       zpios_profile_post_proc_stop ${PROFILE_RUN_WR_DIR}
+       zpios_profile_post_stop ${PROFILE_RUN_WR_PID}
+}
+
+zpios_profile_post_read() {
+       zpios_profile_post_oprofile_stop ${PROFILE_RUN_CR_RD_LOG}
+       zpios_profile_post_proc_stop ${PROFILE_RUN_RD_DIR}
+       zpios_profile_post_stop ${PROFILE_RUN_RD_PID}
+}
+
+zpios_profile_post_remove() {
+       zpios_profile_post_oprofile_stop ${PROFILE_RUN_RM_OPROFILE_LOG}
+       zpios_profile_post_proc_stop ${PROFILE_RUN_RM_DIR}
+       zpios_profile_post_stop ${PROFILE_RUN_RM_PID}
+}
+
+# Source global zpios test configuration
+if [ -f ${RUN_DIR}/zpios-config.sh ]; then
+       . ${RUN_DIR}/zpios-config.sh
+fi
+
+# Source global per-run test configuration
+if [ -f ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh ]; then
+       . ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh
+fi
+
+case "${RUN_PHASE}" in
+       post-run)
+               zpios_profile_post_pids
+               zpios_profile_post_disk
+               ;;
+       post-create)
+               zpios_profile_post_create
+               ;;
+       post-write)
+               zpios_profile_post_write
+               ;;
+       post-read)
+               zpios_profile_post_read
+               ;;
+       post-remove)
+               zpios_profile_post_remove
+               ;;
+       *)
+               echo "Usage: ${PROG} {post-run|post-create|post-write|post-read|post-remove}"
+               exit 1
+esac
+
+exit 0
diff --git a/zfs/scripts/zpios-profile/zpios-profile-pre.sh b/zfs/scripts/zpios-profile/zpios-profile-pre.sh
new file mode 100755 (executable)
index 0000000..a2a8857
--- /dev/null
@@ -0,0 +1,184 @@
+#!/bin/bash
+
+PROG=zpios-profile-pre.sh
+
+PROFILE_RDY=0
+trap "PROFILE_RDY=1" SIGHUP
+
+RUN_PRE=${0}
+RUN_PHASE=${1}
+RUN_DIR=${2}
+RUN_ID=${3}
+RUN_POOL=${4}
+RUN_CHUNK_SIZE=${5}
+RUN_REGION_SIZE=${6}
+RUN_THRD_COUNT=${7}
+RUN_REGION_COUNT=${8}
+RUN_OFFSET=${9}
+RUN_REGION_NOISE=${10}
+RUN_CHUNK_NOISE=${11}
+RUN_THRD_DELAY=${12}
+RUN_FLAGS=${13}
+RUN_RESULT=${14}
+
+zpios_profile_pre_run_cfg() {
+cat > ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh << EOF
+#
+# Zpios Profiling Configuration for Run ${RUN_ID}
+#
+
+PROFILE_RUN_DIR=${RUN_DIR}/${RUN_ID}
+
+PROFILE_RUN_CR_DIR=${RUN_DIR}/${RUN_ID}/create
+PROFILE_RUN_CR_PID=${RUN_DIR}/${RUN_ID}/create/profile.pid
+PROFILE_RUN_CR_OPROFILE_LOG=${RUN_DIR}/${RUN_ID}/create/oprofile.txt
+PROFILE_RUN_CR_PIDS_LOG=${RUN_DIR}/${RUN_ID}/create/pids.txt
+PROFILE_RUN_CR_PIDS_CSV=${RUN_DIR}/${RUN_ID}/create/pids.csv
+PROFILE_RUN_CR_DISK_LOG=${RUN_DIR}/${RUN_ID}/create/disk.txt
+PROFILE_RUN_CR_DISK_CSV=${RUN_DIR}/${RUN_ID}/create/disk.csv
+
+PROFILE_RUN_WR_DIR=${RUN_DIR}/${RUN_ID}/write
+PROFILE_RUN_WR_PID=${RUN_DIR}/${RUN_ID}/write/profile.pid
+PROFILE_RUN_WR_OPROFILE_LOG=${RUN_DIR}/${RUN_ID}/write/oprofile.txt
+PROFILE_RUN_WR_PIDS_LOG=${RUN_DIR}/${RUN_ID}/write/pids.txt
+PROFILE_RUN_WR_PIDS_CSV=${RUN_DIR}/${RUN_ID}/write/pids.csv
+PROFILE_RUN_WR_DISK_LOG=${RUN_DIR}/${RUN_ID}/write/disk.txt
+PROFILE_RUN_WR_DISK_CSV=${RUN_DIR}/${RUN_ID}/write/disk.csv
+
+PROFILE_RUN_RD_DIR=${RUN_DIR}/${RUN_ID}/read
+PROFILE_RUN_RD_PID=${RUN_DIR}/${RUN_ID}/read/profile.pid
+PROFILE_RUN_RD_OPROFILE_LOG=${RUN_DIR}/${RUN_ID}/read/oprofile.txt
+PROFILE_RUN_RD_PIDS_LOG=${RUN_DIR}/${RUN_ID}/read/pids.txt
+PROFILE_RUN_RD_PIDS_CSV=${RUN_DIR}/${RUN_ID}/read/pids.csv
+PROFILE_RUN_RD_DISK_LOG=${RUN_DIR}/${RUN_ID}/read/disk.txt
+PROFILE_RUN_RD_DISK_CSV=${RUN_DIR}/${RUN_ID}/read/disk.csv
+
+PROFILE_RUN_RM_DIR=${RUN_DIR}/${RUN_ID}/remove
+PROFILE_RUN_RM_PID=${RUN_DIR}/${RUN_ID}/remove/profile.pid
+PROFILE_RUN_RM_OPROFILE_LOG=${RUN_DIR}/${RUN_ID}/remove/oprofile.txt
+PROFILE_RUN_RM_PIDS_LOG=${RUN_DIR}/${RUN_ID}/remove/pids.txt
+PROFILE_RUN_RM_PIDS_CSV=${RUN_DIR}/${RUN_ID}/remove/pids.csv
+PROFILE_RUN_RM_DISK_LOG=${RUN_DIR}/${RUN_ID}/remove/disk.txt
+PROFILE_RUN_RM_DISK_CSV=${RUN_DIR}/${RUN_ID}/remove/disk.csv
+
+# PROFILE_PIDS_LOG=${RUN_DIR}/${RUN_ID}/pids-summary.csv
+# PROFILE_DISK_LOG=${RUN_DIR}/${RUN_ID}/disk-summary.csv
+EOF
+}
+
+zpios_profile_pre_run_args() {
+cat > ${RUN_DIR}/${RUN_ID}/zpios-args.txt << EOF
+#
+# Zpios Arguments for Run ${RUN_ID}
+#
+
+DIR=${RUN_DIR}
+ID=${RUN_ID}
+POOL=${RUN_POOL}
+CHUNK_SIZE=${RUN_CHUNK_SIZE}
+REGION_SIZE=${RUN_REGION_SIZE}
+THRD_COUNT=${RUN_THRD_COUNT}
+REGION_COUNT=${RUN_REGION_COUNT}
+OFFSET=${RUN_OFFSET}
+REGION_NOISE=${RUN_REGION_NOISE}
+CHUNK_NOISE=${RUN_CHUNK_NOISE}
+THRD_DELAY=${RUN_THRD_DELAY}
+FLAGS=${RUN_FLAGS}
+RESULT=${RUN_RESULT}
+EOF
+}
+
+# Spawn a user defined profiling script to gather additional data
+zpios_profile_pre_start() {
+       local PROFILE_PID=$1
+
+       ${PROFILE_USER} ${RUN_PHASE} ${RUN_DIR} ${RUN_ID} &
+       echo "$!" >${PROFILE_PID}
+
+       # Sleep waiting for profile script to be ready, it will
+       # signal us via SIGHUP when it is ready to start profiling.
+       while [ ${PROFILE_RDY} -eq 0 ]; do
+               sleep 0.01
+       done
+}
+
+zpios_profile_post_proc_start() { 
+
+        if [ -f ${PROFILE_ARC_PROC} ]; then
+                echo 0 >${PROFILE_ARC_PROC}
+        fi
+
+        if [ -f ${PROFILE_VDEV_CACHE_PROC} ]; then
+                echo 0 >${PROFILE_VDEV_CACHE_PROC}
+        fi
+}
+
+zpios_profile_pre_oprofile_start() {
+       local OPROFILE_LOG=$1
+
+       /usr/bin/opcontrol --reset >>${OPROFILE_LOG} 2>&1
+       /usr/bin/opcontrol --start >>${OPROFILE_LOG} 2>&1
+}
+
+zpios_profile_pre_create() {
+       mkdir ${PROFILE_RUN_CR_DIR}
+       zpios_profile_pre_start ${PROFILE_RUN_CR_PID}
+       zpios_profile_post_proc_start
+       zpios_profile_pre_oprofile_start ${PROFILE_RUN_CR_OPROFILE_LOG}
+}
+
+zpios_profile_pre_write() {
+       mkdir ${PROFILE_RUN_WR_DIR}
+       zpios_profile_pre_start ${PROFILE_RUN_WR_PID}
+       zpios_profile_post_proc_start
+       zpios_profile_pre_oprofile_start ${PROFILE_RUN_WR_OPROFILE_LOG}
+}
+
+zpios_profile_pre_read() {
+       mkdir ${PROFILE_RUN_RD_DIR}
+       zpios_profile_pre_start ${PROFILE_RUN_RD_PID}
+       zpios_profile_post_proc_start
+       zpios_profile_pre_oprofile_start ${PROFILE_RUN_CR_RD_LOG}
+}
+
+zpios_profile_pre_remove() {
+       mkdir ${PROFILE_RUN_RM_DIR}
+       zpios_profile_pre_start ${PROFILE_RUN_RM_PID}
+       zpios_profile_post_proc_start
+       zpios_profile_pre_oprofile_start ${PROFILE_RUN_RM_OPROFILE_LOG}
+}
+
+# Source global zpios test configuration
+if [ -f ${RUN_DIR}/zpios-config.sh ]; then
+       . ${RUN_DIR}/zpios-config.sh
+fi
+
+# Source global per-run test configuration
+if [ -f ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh ]; then
+       . ${RUN_DIR}/${RUN_ID}/zpios-config-run.sh
+fi
+
+case "${RUN_PHASE}" in
+       pre-run)
+               mkdir -p ${RUN_DIR}/${RUN_ID}/
+               zpios_profile_pre_run_cfg
+               zpios_profile_pre_run_args
+               ;;
+       pre-create)
+               zpios_profile_pre_create
+               ;;
+       pre-write)
+               zpios_profile_pre_write
+               ;;
+       pre-read)
+               zpios_profile_pre_read
+               ;;
+       pre-remove)
+               zpios_profile_pre_remove
+               ;;
+       *)
+               echo "Usage: ${PROG} {pre-run|pre-create|pre-write|pre-read|pre-remove}"
+               exit 1
+esac
+
+exit 0
diff --git a/zfs/scripts/zpios-profile/zpios-profile.sh b/zfs/scripts/zpios-profile/zpios-profile.sh
new file mode 100755 (executable)
index 0000000..f4f0ee9
--- /dev/null
@@ -0,0 +1,226 @@
+#!/bin/bash
+
+
+PROG=zpios-profile.sh
+
+trap "RUN_DONE=1" SIGHUP
+
+RUN_PHASE=${1}
+RUN_LOG_DIR=${2}
+RUN_ID=${3}
+RUN_DONE=0
+
+POLL_INTERVAL=2.99
+
+# Log these pids, the exact pid numbers will vary from system to system
+# so I harvest pid for all the following type of processes from /proc/<pid>/
+#
+# zio_taskq/#
+# spa_zio_issue/#
+# spa_zio_intr/#
+# txg_quiesce_thr
+# txg_sync_thread
+# txg_timelimit_t
+# arc_reclaim_thr
+# l2arc_feed_thre
+# zpios_io/#
+
+ZIO_TASKQ_PIDS=()
+ZIO_REQ_NUL_PIDS=() 
+ZIO_IRQ_NUL_PIDS=() 
+ZIO_REQ_RD_PIDS=() 
+ZIO_IRQ_RD_PIDS=() 
+ZIO_REQ_WR_PIDS=() 
+ZIO_IRQ_WR_PIDS=()
+ZIO_REQ_FR_PIDS=() 
+ZIO_IRQ_FR_PIDS=()
+ZIO_REQ_CM_PIDS=() 
+ZIO_IRQ_CM_PIDS=()
+ZIO_REQ_CTL_PIDS=() 
+ZIO_IRQ_CTL_PIDS=()
+
+TXG_QUIESCE_PIDS=()
+TXG_SYNC_PIDS=() 
+TXG_TIMELIMIT_PIDS=()
+
+ARC_RECLAIM_PIDS=()
+L2ARC_FEED_PIDS=()
+
+ZPIOS_IO_PIDS=()
+
+show_pids() {
+       echo "* zio_taskq:     { ${ZIO_TASKQ_PIDS[@]} } = ${#ZIO_TASKQ_PIDS[@]}"
+       echo "* zio_req_nul:   { ${ZIO_REQ_NUL_PIDS[@]} } = ${#ZIO_REQ_NUL_PIDS[@]}"
+       echo "* zio_irq_nul:   { ${ZIO_IRQ_NUL_PIDS[@]} } = ${#ZIO_IRQ_NUL_PIDS[@]}"
+       echo "* zio_req_rd:    { ${ZIO_REQ_RD_PIDS[@]} } = ${#ZIO_REQ_RD_PIDS[@]}"
+       echo "* zio_irq_rd:    { ${ZIO_IRQ_RD_PIDS[@]} } = ${#ZIO_IRQ_RD_PIDS[@]}"
+       echo "* zio_req_wr:    { ${ZIO_REQ_WR_PIDS[@]} } = ${#ZIO_REQ_WR_PIDS[@]}"
+       echo "* zio_irq_wr:    { ${ZIO_IRQ_WR_PIDS[@]} } = ${#ZIO_IRQ_WR_PIDS[@]}"
+       echo "* zio_req_fr:    { ${ZIO_REQ_FR_PIDS[@]} } = ${#ZIO_REQ_FR_PIDS[@]}"
+       echo "* zio_irq_fr:    { ${ZIO_IRQ_FR_PIDS[@]} } = ${#ZIO_IRQ_FR_PIDS[@]}"
+       echo "* zio_req_cm:    { ${ZIO_REQ_CM_PIDS[@]} } = ${#ZIO_REQ_CM_PIDS[@]}"
+       echo "* zio_irq_cm:    { ${ZIO_IRQ_CM_PIDS[@]} } = ${#ZIO_IRQ_CM_PIDS[@]}"
+       echo "* zio_req_ctl:   { ${ZIO_REQ_CTL_PIDS[@]} } = ${#ZIO_REQ_CTL_PIDS[@]}"
+       echo "* zio_irq_ctl:   { ${ZIO_IRQ_CTL_PIDS[@]} } = ${#ZIO_IRQ_CTL_PIDS[@]}"
+       echo "* txg_quiesce:   { ${TXG_QUIESCE_PIDS[@]} } = ${#TXG_QUIESCE_PIDS[@]}"
+       echo "* txg_sync:      { ${TXG_SYNC_PIDS[@]} } = ${#TXG_SYNC_PIDS[@]}"
+       echo "* txg_timelimit: { ${TXG_TIMELIMIT_PIDS[@]} } = ${#TXG_TIMELIMIT_PIDS[@]}"
+       echo "* arc_reclaim:   { ${ARC_RECLAIM_PIDS[@]} } = ${#ARC_RECLAIM_PIDS[@]}"
+       echo "* l2arc_feed:    { ${L2ARC_FEED_PIDS[@]} } = ${#L2ARC_FEED_PIDS[@]}"
+       echo "* zpios_io:      { ${ZPIOS_IO_PIDS[@]} } = ${#ZPIOS_IO_PIDS[@]}"
+}
+
+check_pid() {
+       local PID=$1
+       local NAME=$2
+       local TYPE=$3
+       local PIDS=( "$4" )
+        local NAME_STRING=`echo ${NAME} | cut -f1 -d'/'`
+        local NAME_NUMBER=`echo ${NAME} | cut -f2 -d'/'`
+
+       if [ "${NAME_STRING}" == "${TYPE}" ]; then
+               if [ -n "${NAME_NUMBER}" ]; then
+                       PIDS[${NAME_NUMBER}]=${PID}
+               else
+                       PIDS[${#PIDS[@]}]=${PID}
+
+               fi
+       fi
+
+       echo "${PIDS[@]}"
+}
+
+# NOTE: This whole process is crazy slow but it will do for now
+aquire_pids() {
+       echo "--- Aquiring ZFS pids ---"
+
+       for PID in `ls /proc/ | grep [0-9] | sort -n -u`; do
+               if [ ! -e /proc/${PID}/status ]; then
+                       continue
+               fi
+
+               NAME=`cat /proc/${PID}/status  | head -n1 | cut -f2`
+
+               ZIO_TASKQ_PIDS=( `check_pid ${PID} ${NAME} "zio_taskq" \
+                                "$(echo "${ZIO_TASKQ_PIDS[@]}")"` )
+
+               ZIO_REQ_NUL_PIDS=( `check_pid ${PID} ${NAME} "zio_req_nul" \
+                                  "$(echo "${ZIO_REQ_NUL_PIDS[@]}")"` )
+
+               ZIO_IRQ_NUL_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_nul" \
+                                  "$(echo "${ZIO_IRQ_NUL_PIDS[@]}")"` )
+
+               ZIO_REQ_RD_PIDS=( `check_pid ${PID} ${NAME} "zio_req_rd" \
+                                  "$(echo "${ZIO_REQ_RD_PIDS[@]}")"` )
+
+               ZIO_IRQ_RD_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_rd" \
+                                  "$(echo "${ZIO_IRQ_RD_PIDS[@]}")"` )
+
+               ZIO_REQ_WR_PIDS=( `check_pid ${PID} ${NAME} "zio_req_wr" \
+                                  "$(echo "${ZIO_REQ_WR_PIDS[@]}")"` )
+
+               ZIO_IRQ_WR_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_wr" \
+                                  "$(echo "${ZIO_IRQ_WR_PIDS[@]}")"` )
+
+               ZIO_REQ_FR_PIDS=( `check_pid ${PID} ${NAME} "zio_req_fr" \
+                                  "$(echo "${ZIO_REQ_FR_PIDS[@]}")"` )
+
+               ZIO_IRQ_FR_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_fr" \
+                                  "$(echo "${ZIO_IRQ_FR_PIDS[@]}")"` )
+
+               ZIO_REQ_CM_PIDS=( `check_pid ${PID} ${NAME} "zio_req_cm" \
+                                  "$(echo "${ZIO_REQ_CM_PIDS[@]}")"` )
+
+               ZIO_IRQ_CM_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_cm" \
+                                  "$(echo "${ZIO_IRQ_CM_PIDS[@]}")"` )
+
+               ZIO_REQ_CTL_PIDS=( `check_pid ${PID} ${NAME} "zio_req_ctl" \
+                                  "$(echo "${ZIO_REQ_CTL_PIDS[@]}")"` )
+
+               ZIO_IRQ_CTL_PIDS=( `check_pid ${PID} ${NAME} "zio_irq_ctl" \
+                                  "$(echo "${ZIO_IRQ_CTL_PIDS[@]}")"` )
+
+               TXG_QUIESCE_PIDS=( `check_pid ${PID} ${NAME} "txg_quiesce" \
+                                  "$(echo "${TXG_QUIESCE_PIDS[@]}")"` )
+
+               TXG_SYNC_PIDS=( `check_pid ${PID} ${NAME} "txg_sync" \
+                               "$(echo "${TXG_SYNC_PIDS[@]}")"` )
+
+               TXG_TIMELIMIT_PIDS=( `check_pid ${PID} ${NAME} "txg_timelimit" \
+                                    "$(echo "${TXG_TIMELIMIT_PIDS[@]}")"` )
+
+               ARC_RECLAIM_PIDS=( `check_pid ${PID} ${NAME} "arc_reclaim" \
+                                     "$(echo "${ARC_RECLAIM_PIDS[@]}")"` )
+
+               L2ARC_FEED_PIDS=( `check_pid ${PID} ${NAME} "l2arc_feed" \
+                                  "$(echo "${L2ARC_FEED_PIDS[@]}")"` )
+       done
+
+       # Wait for zpios_io threads to start
+       kill -s SIGHUP ${PPID}
+       echo "* Waiting for zpios_io threads to start"
+       while [ ${RUN_DONE} -eq 0 ]; do
+               ZPIOS_IO_PIDS=( `ps ax | grep zpios_io | grep -v grep | \
+                                 sed 's/^ *//g' | cut -f1 -d' '` )
+               if [ ${#ZPIOS_IO_PIDS[@]} -gt 0 ]; then
+                       break;
+               fi
+               sleep 0.1
+       done
+
+       echo "`show_pids`" >${RUN_LOG_DIR}/${RUN_ID}/pids.txt
+}
+
+log_pids() {
+       echo "--- Logging ZFS profile to ${RUN_LOG_DIR}/${RUN_ID}/ ---"
+       ALL_PIDS=( ${ZIO_TASKQ_PIDS[@]}     \
+                   ${ZIO_REQ_NUL_PIDS[@]}   \
+                   ${ZIO_IRQ_NUL_PIDS[@]}   \
+                   ${ZIO_REQ_RD_PID[@]}     \
+                   ${ZIO_IRQ_RD_PIDS[@]}    \
+                   ${ZIO_REQ_WR_PIDS[@]}    \
+                   ${ZIO_IRQ_WR_PIDS[@]}    \
+                   ${ZIO_REQ_FR_PIDS[@]}    \ 
+                   ${ZIO_IRQ_FR_PIDS[@]}    \
+                   ${ZIO_REQ_CM_PIDS[@]}    \ 
+                   ${ZIO_IRQ_CM_PIDS[@]}    \
+                   ${ZIO_REQ_CTL_PIDS[@]}   \
+                   ${ZIO_IRQ_CTL_PIDS[@]}   \
+                   ${TXG_QUIESCE_PIDS[@]}   \
+                   ${TXG_SYNC_PIDS[@]}      \
+                   ${TXG_TIMELIMIT_PIDS[@]} \
+                   ${ARC_RECLAIM_PIDS[@]}   \
+                   ${L2ARC_FEED_PIDS[@]}    \
+                   ${ZPIOS_IO_PIDS[@]} )
+
+       while [ ${RUN_DONE} -eq 0 ]; do
+               NOW=`date +%s.%N`
+               LOG_PIDS="${RUN_LOG_DIR}/${RUN_ID}/pids-${NOW}"
+               LOG_DISK="${RUN_LOG_DIR}/${RUN_ID}/disk-${NOW}"
+
+               for PID in "${ALL_PIDS[@]}"; do
+                       if [ -z ${PID} ]; then
+                               continue;
+                       fi
+
+                       if [ -e /proc/${PID}/stat ]; then
+                               cat /proc/${PID}/stat | head -n1 >>${LOG_PIDS}
+                       else
+                               echo "<${PID} exited>" >>${LOG_PIDS}
+                       fi
+               done
+
+               cat /proc/diskstats >${LOG_DISK}
+
+               NOW2=`date +%s.%N`
+               DELTA=`echo "${POLL_INTERVAL}-(${NOW2}-${NOW})" | bc`
+               sleep ${DELTA}
+       done
+}
+
+aquire_pids
+log_pids
+
+# rm ${PROFILE_PID}
+
+exit 0
diff --git a/zfs/scripts/zpios-sanity.sh b/zfs/scripts/zpios-sanity.sh
new file mode 100755 (executable)
index 0000000..0f44115
--- /dev/null
@@ -0,0 +1,171 @@
+#!/bin/bash
+#
+# ZFS/ZPOOL configuration test script.
+
+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=zpios-sanity.sh
+HEADER=
+FAILS=0
+
+usage() {
+cat << EOF
+USAGE:
+$0 [hvxfc]
+
+DESCRIPTION:
+        ZPIOS sanity tests
+
+OPTIONS:
+        -h      Show this message
+        -v      Verbose
+        -x      Destructive hd/sd/md/dm/ram tests
+       -f      Don't prompt due to -x
+       -c      Cleanup lo+file devices at start
+
+EOF
+}
+
+while getopts 'hvxfc?' OPTION; do
+       case $OPTION in
+       h)
+               usage
+               exit 1
+               ;;
+       v)
+               VERBOSE=1
+               ;;
+       x)
+               DANGEROUS=1
+               ;;
+       f)
+               FORCE=1
+               ;;
+       c)
+               CLEANUP=1
+               ;;
+       ?)
+               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
+
+zpios_test() {
+       CONFIG=$1
+       TEST=$2
+       LOG=`mktemp`
+
+       ${ZPIOS_SH} -f -c ${CONFIG} -t ${TEST} &>${LOG}
+       if [ $? -ne 0 ]; then
+               FAILS=1
+
+               if [ ${VERBOSE} ]; then
+                       printf "FAIL:     %-13s\n" ${CONFIG}
+                       cat ${LOG}
+               else
+                       if [ ! ${HEADER} ]; then
+                               head -2 ${LOG}
+                               HEADER=1
+                       fi
+
+                       printf "FAIL:     %-13s" ${CONFIG}
+                       tail -1 ${LOG}
+               fi
+       else
+               if [ ${VERBOSE} ]; then
+                       cat ${LOG}
+               else
+                       if [ ! ${HEADER} ]; then
+                               head -2 ${LOG}
+                               HEADER=1
+                       fi
+
+                       tail -1 ${LOG}
+               fi
+       fi
+
+       rm -f ${LOG}
+}
+
+if [ ${DANGEROUS} ] && [ ! ${FORCE} ]; then
+       cat << EOF
+The -x option was passed which will result in UNRECOVERABLE DATA LOSS
+on on the following block devices:
+
+  /dev/sd[abcd]
+  /dev/hda
+  /dev/ram0
+  /dev/md0
+  /dev/dm-0
+
+To continue please confirm by entering YES:
+EOF
+       read CONFIRM
+       if [ ${CONFIRM} != "YES" ] && [ ${CONFIRM} != "yes" ]; then
+               exit 0;
+       fi
+fi
+
+#
+# These configurations are all safe and pose no risk to any data on
+# the system which runs them.  They will confine all their IO to a
+# file in /tmp or a loopback device configured to use a file in /tmp.
+#
+SAFE_CONFIGS=(                                         \
+       file-raid0 file-raid10 file-raidz file-raidz2   \
+       lo-raid0 lo-raid10 lo-raidz lo-raidz2           \
+)
+
+#
+# These configurations are down right dangerous.  They will attempt
+# to use various real block devices on your system which may contain
+# data you car about.  You are STRONGLY advised not to run this unless
+# you are certain there is no data on the system you care about.
+#
+DANGEROUS_CONFIGS=(                                    \
+       hda-raid0                                       \
+       sda-raid0                                       \
+       ram0-raid0                                      \
+       md0-raid10 md0-raid5                            \
+       dm0-raid0                                       \
+)
+
+TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
+${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || die "Unable to load modules"
+
+for CONFIG in ${SAFE_CONFIGS[*]}; do
+       zpios_test $CONFIG tiny
+done
+
+if [ ${DANGEROUS} ]; then
+       for CONFIG in ${DANGEROUS_CONFIGS[*]}; do
+               zpios_test $CONFIG tiny
+       done
+fi
+
+${ZFS_SH} -u
+
+exit $FAILS
diff --git a/zfs/scripts/zpios-survey.sh b/zfs/scripts/zpios-survey.sh
new file mode 100755 (executable)
index 0000000..7860169
--- /dev/null
@@ -0,0 +1,187 @@
+#!/bin/bash
+#
+# Wrapper script for easily running a survey of zpios based tests
+#
+
+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=zpios-survey.sh
+
+usage() {
+cat << EOF
+USAGE:
+$0 [hvp] <-c config> <-t test>
+
+DESCRIPTION:
+        Helper script for easy zpios survey benchmarking.
+
+OPTIONS:
+        -h      Show this message
+        -v      Verbose
+        -p      Enable profiling
+        -c      Zpool configuration
+        -t      Zpios test
+        -l      Zpios survey log
+
+EOF
+}
+
+print_header() {
+tee -a ${ZPIOS_SURVEY_LOG} << EOF
+
+================================================================
+Test: $1
+EOF
+}
+
+# Baseline performance for an out of the box config with no manual tuning.
+# Ideally, we want everything to be automatically tuned for your system and
+# for this to perform reasonably well.
+zpios_survey_base() {
+       TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+baseline"
+       print_header ${TEST_NAME}
+
+       ${ZFS_SH} ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZFS_SH} -u ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+}
+
+# Disable ZFS's prefetching.  For some reason still not clear to me
+# current prefetching policy is quite bad for a random workload.
+# Allowing the algorithm to detect a random workload and not do 
+# anything may be the way to address this issue.
+zpios_survey_prefetch() {
+       TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+prefetch"
+       print_header ${TEST_NAME}
+
+       ${ZFS_SH} ${VERBOSE_FLAG}               \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \
+               -o "--noprefetch" |                                    \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZFS_SH} -u ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+}
+
+# Simulating a zerocopy IO path should improve performance by freeing up
+# lots of CPU which is wasted move data between buffers.
+zpios_survey_zerocopy() {
+       TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+zerocopy"
+       print_header ${TEST_NAME}
+
+       ${ZFS_SH} ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \
+               -o "--zerocopy" |                                      \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZFS_SH} -u ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+}
+
+# Disabling checksumming should show some (if small) improvement
+# simply due to freeing up a modest amount of CPU.
+zpios_survey_checksum() {
+       TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+checksum"
+       print_header ${TEST_NAME}
+
+       ${ZFS_SH} ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \
+               -s "set checksum=off" |                                \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZFS_SH} -u ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+}
+
+# Increasing the pending IO depth also seems to improve things likely
+# at the expense of latency.  This should be explored more because I'm
+# seeing a much bigger impact there that I would have expected.  There
+# may be some low hanging fruit to be found here.
+zpios_survey_pending() {
+       TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+pending"
+       print_header ${TEST_NAME}
+
+       ${ZFS_SH} ${VERBOSE_FLAG}                  \
+               zfs="zfs_vdev_max_pending=1024" | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZFS_SH} -u ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+}
+
+# Apply all possible turning concurrently to get a best case number
+zpios_survey_all() {
+       TEST_NAME="${ZPOOL_CONFIG}+${ZPIOS_TEST}+all"
+       print_header ${TEST_NAME}
+
+       ${ZFS_SH} ${VERBOSE_FLAG}                \  
+               zfs="zfs_vdev_max_pending=1024" | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZPIOS_SH} ${VERBOSE_FLAG} -c ${ZPOOL_CONFIG} -t ${ZPIOS_TEST} \
+               -o "--noprefetch --zerocopy"                           \
+               -s "set checksum=off" |                                \
+               tee -a ${ZPIOS_SURVEY_LOG}
+       ${ZFS_SH} -u ${VERBOSE_FLAG} | \
+               tee -a ${ZPIOS_SURVEY_LOG}
+}
+
+
+PROFILE=
+ZPOOL_NAME=zpios-survey
+ZPOOL_CONFIG=zpool-config.sh
+ZPIOS_TEST=zpios-test.sh
+ZPIOS_SURVEY_LOG=/dev/null
+
+while getopts 'hvpc:t:l:' OPTION; do
+       case $OPTION in
+       h)
+               usage
+               exit 1
+               ;;
+       v)
+               VERBOSE=1
+               VERBOSE_FLAG="-v"
+               ;;
+       p)
+               PROFILE=1
+               PROFILE_FLAG="-p"
+               ;;
+       c)
+               ZPOOL_CONFIG=${OPTARG}
+               ;;
+       t)
+               ZPIOS_TEST=${OPTARG}
+               ;;
+       l)
+               ZPIOS_SURVEY_LOG=${OPTARG}
+               ;;
+       ?)
+               usage
+               exit
+               ;;
+       esac
+done
+
+if [ $(id -u) != 0 ]; then
+       die "Must run as root"
+fi
+
+zpios_survey_base
+zpios_survey_prefetch
+zpios_survey_zerocopy
+zpios_survey_checksum
+zpios_survey_pending
+zpios_survey_all
+
+exit 0
diff --git a/zfs/scripts/zpios-test/16th-8192rc-4rs-1cs-4off.sh b/zfs/scripts/zpios-test/16th-8192rc-4rs-1cs-4off.sh
new file mode 100755 (executable)
index 0000000..cbd9c69
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Usage: zpios
+#        --threadcount       -t    =values
+#        --threadcount_low   -l    =value
+#        --threadcount_high  -h    =value
+#        --threadcount_incr  -e    =value
+#        --regioncount       -n    =values
+#        --regioncount_low   -i    =value
+#        --regioncount_high  -j    =value
+#        --regioncount_incr  -k    =value
+#        --offset            -o    =values
+#        --offset_low        -m    =value
+#        --offset_high       -q    =value
+#        --offset_incr       -r    =value
+#        --chunksize         -c    =values
+#        --chunksize_low     -a    =value
+#        --chunksize_high    -b    =value
+#        --chunksize_incr    -g    =value
+#        --regionsize        -s    =values
+#        --regionsize_low    -A    =value
+#        --regionsize_high   -B    =value
+#        --regionsize_incr   -C    =value
+#        --load              -L    =dmuio|ssf|fpp
+#        --pool              -p    =pool name
+#        --name              -M    =test name
+#        --cleanup           -x
+#        --prerun            -P    =pre-command
+#        --postrun           -R    =post-command
+#        --log               -G    =log directory
+#        --regionnoise       -I    =shift
+#        --chunknoise        -N    =bytes
+#        --threaddelay       -T    =jiffies
+#        --verify            -V
+#        --zerocopy          -z
+#        --nowait            -O
+#        --human-readable    -H
+#        --verbose           -v    =increase verbosity
+#        --help              -?    =this help
+
+ZPIOS_CMD="${ZPIOS}                                              \
+       --load=dmuio                                             \
+       --pool=${ZPOOL_NAME}                                     \
+       --name=${ZPOOL_CONFIG}                                   \
+       --threadcount=16                                         \
+       --regioncount=8192                                       \
+       --regionsize=4M                                          \
+       --chunksize=1M                                           \
+       --offset=4M                                              \
+       --cleanup                                                \
+       --human-readable                                         \
+       ${ZPIOS_OPTIONS}"
+
+zpios_start() {
+       if [ ${VERBOSE} ]; then
+               ZPIOS_CMD="${ZPIOS_CMD} --verbose"
+               echo ${ZPIOS_CMD}
+       fi
+
+       ${ZPIOS_CMD} || exit 1
+}
+
+zpios_stop() {
+       [ ${VERBOSE} ] && echo
+}
diff --git a/zfs/scripts/zpios-test/1th-16rc-4rs-1cs-4off.sh b/zfs/scripts/zpios-test/1th-16rc-4rs-1cs-4off.sh
new file mode 100755 (executable)
index 0000000..cd3c50b
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+#
+# Usage: zpios
+#        --threadcount       -t    =values
+#        --threadcount_low   -l    =value
+#        --threadcount_high  -h    =value
+#        --threadcount_incr  -e    =value
+#        --regioncount       -n    =values
+#        --regioncount_low   -i    =value
+#        --regioncount_high  -j    =value
+#        --regioncount_incr  -k    =value
+#        --offset            -o    =values
+#        --offset_low        -m    =value
+#        --offset_high       -q    =value
+#        --offset_incr       -r    =value
+#        --chunksize         -c    =values
+#        --chunksize_low     -a    =value
+#        --chunksize_high    -b    =value
+#        --chunksize_incr    -g    =value
+#        --regionsize        -s    =values
+#        --regionsize_low    -A    =value
+#        --regionsize_high   -B    =value
+#        --regionsize_incr   -C    =value
+#        --load              -L    =dmuio|ssf|fpp
+#        --pool              -p    =pool name
+#        --name              -M    =test name
+#        --cleanup           -x
+#        --prerun            -P    =pre-command
+#        --postrun           -R    =post-command
+#        --log               -G    =log directory
+#        --regionnoise       -I    =shift
+#        --chunknoise        -N    =bytes
+#        --threaddelay       -T    =jiffies
+#        --verify            -V
+#        --zerocopy          -z
+#        --nowait            -O
+#        --human-readable    -H
+#        --verbose           -v    =increase verbosity
+#        --help              -?    =this help
+
+
+ZPIOS_CMD="${ZPIOS}                                              \
+       --load=dmuio                                             \
+       --pool=${ZPOOL_NAME}                                     \
+       --name=${ZPOOL_CONFIG}                                   \
+       --threadcount=1                                          \
+       --regioncount=16                                         \
+       --regionsize=4M                                          \
+       --chunksize=1M                                           \
+       --offset=4M                                              \
+       --cleanup                                                \
+       --human-readable                                         \
+       ${ZPIOS_OPTIONS}"
+
+zpios_start() {
+       if [ ${VERBOSE} ]; then
+               ZPIOS_CMD="${ZPIOS_CMD} --verbose"
+               echo ${ZPIOS_CMD}
+       fi
+
+       ${ZPIOS_CMD} || exit 1
+}
+
+zpios_stop() {
+       [ ${VERBOSE} ] && echo
+}
diff --git a/zfs/scripts/zpios-test/1x256th-65536rc-4rs-1cs-4off.sh b/zfs/scripts/zpios-test/1x256th-65536rc-4rs-1cs-4off.sh
new file mode 100755 (executable)
index 0000000..743e97b
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Usage: zpios
+#        --threadcount       -t    =values
+#        --threadcount_low   -l    =value
+#        --threadcount_high  -h    =value
+#        --threadcount_incr  -e    =value
+#        --regioncount       -n    =values
+#        --regioncount_low   -i    =value
+#        --regioncount_high  -j    =value
+#        --regioncount_incr  -k    =value
+#        --offset            -o    =values
+#        --offset_low        -m    =value
+#        --offset_high       -q    =value
+#        --offset_incr       -r    =value
+#        --chunksize         -c    =values
+#        --chunksize_low     -a    =value
+#        --chunksize_high    -b    =value
+#        --chunksize_incr    -g    =value
+#        --regionsize        -s    =values
+#        --regionsize_low    -A    =value
+#        --regionsize_high   -B    =value
+#        --regionsize_incr   -C    =value
+#        --load              -L    =dmuio|ssf|fpp
+#        --pool              -p    =pool name
+#        --name              -M    =test name
+#        --cleanup           -x
+#        --prerun            -P    =pre-command
+#        --postrun           -R    =post-command
+#        --log               -G    =log directory
+#        --regionnoise       -I    =shift
+#        --chunknoise        -N    =bytes
+#        --threaddelay       -T    =jiffies
+#        --verify            -V
+#        --zerocopy          -z
+#        --nowait            -O
+#        --human-readable    -H
+#        --verbose           -v    =increase verbosity
+#        --help              -?    =this help
+
+ZPIOS_CMD="${ZPIOS}                                              \
+       --load=dmuio                                             \
+       --pool=${ZPOOL_NAME}                                     \
+       --name=${ZPOOL_CONFIG}                                   \
+       --threadcount=1,2,4,8,16,32,64,128,256                   \
+       --regioncount=65536                                      \
+       --regionsize=4M                                          \
+       --chunksize=1M                                           \
+       --offset=4M                                              \
+        --cleanup                                                \
+       --human-readable                                         \
+       ${ZPIOS_OPTIONS}"
+
+zpios_start() {
+       if [ ${VERBOSE} ]; then
+               ZPIOS_CMD="${ZPIOS_CMD} --verbose"
+               echo ${ZPIOS_CMD}
+       fi
+
+       ${ZPIOS_CMD} || exit 1
+}
+
+zpios_stop() {
+       [ ${VERBOSE} ] && echo
+}
diff --git a/zfs/scripts/zpios-test/256th-65536rc-4rs-1cs-4off.sh b/zfs/scripts/zpios-test/256th-65536rc-4rs-1cs-4off.sh
new file mode 100755 (executable)
index 0000000..92a3b77
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Usage: zpios
+#        --threadcount       -t    =values
+#        --threadcount_low   -l    =value
+#        --threadcount_high  -h    =value
+#        --threadcount_incr  -e    =value
+#        --regioncount       -n    =values
+#        --regioncount_low   -i    =value
+#        --regioncount_high  -j    =value
+#        --regioncount_incr  -k    =value
+#        --offset            -o    =values
+#        --offset_low        -m    =value
+#        --offset_high       -q    =value
+#        --offset_incr       -r    =value
+#        --chunksize         -c    =values
+#        --chunksize_low     -a    =value
+#        --chunksize_high    -b    =value
+#        --chunksize_incr    -g    =value
+#        --regionsize        -s    =values
+#        --regionsize_low    -A    =value
+#        --regionsize_high   -B    =value
+#        --regionsize_incr   -C    =value
+#        --load              -L    =dmuio|ssf|fpp
+#        --pool              -p    =pool name
+#        --name              -M    =test name
+#        --cleanup           -x
+#        --prerun            -P    =pre-command
+#        --postrun           -R    =post-command
+#        --log               -G    =log directory
+#        --regionnoise       -I    =shift
+#        --chunknoise        -N    =bytes
+#        --threaddelay       -T    =jiffies
+#        --verify            -V
+#        --zerocopy          -z
+#        --nowait            -O
+#        --human-readable    -H
+#        --verbose           -v    =increase verbosity
+#        --help              -?    =this help
+
+ZPIOS_CMD="${ZPIOS}                                              \
+       --load=dmuio                                             \
+       --pool=${ZPOOL_NAME}                                     \
+       --name=${ZPOOL_CONFIG}                                   \
+       --threadcount=256                                        \
+       --regioncount=65536                                      \
+       --regionsize=4M                                          \
+       --chunksize=1M                                           \
+       --offset=4M                                              \
+        --cleanup                                                \
+       --human-readable                                         \
+       ${ZPIOS_OPTIONS}"
+
+zpios_start() {
+       if [ ${VERBOSE} ]; then
+               ZPIOS_CMD="${ZPIOS_CMD} --verbose"
+               echo ${ZPIOS_CMD}
+       fi
+
+       ${ZPIOS_CMD} || exit 1
+}
+
+zpios_stop() {
+       [ ${VERBOSE} ] && echo
+}
diff --git a/zfs/scripts/zpios-test/4th-1024rc-4rs-1cs-4off.sh b/zfs/scripts/zpios-test/4th-1024rc-4rs-1cs-4off.sh
new file mode 100755 (executable)
index 0000000..0db952c
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Usage: zpios
+#        --threadcount       -t    =values
+#        --threadcount_low   -l    =value
+#        --threadcount_high  -h    =value
+#        --threadcount_incr  -e    =value
+#        --regioncount       -n    =values
+#        --regioncount_low   -i    =value
+#        --regioncount_high  -j    =value
+#        --regioncount_incr  -k    =value
+#        --offset            -o    =values
+#        --offset_low        -m    =value
+#        --offset_high       -q    =value
+#        --offset_incr       -r    =value
+#        --chunksize         -c    =values
+#        --chunksize_low     -a    =value
+#        --chunksize_high    -b    =value
+#        --chunksize_incr    -g    =value
+#        --regionsize        -s    =values
+#        --regionsize_low    -A    =value
+#        --regionsize_high   -B    =value
+#        --regionsize_incr   -C    =value
+#        --load              -L    =dmuio|ssf|fpp
+#        --pool              -p    =pool name
+#        --name              -M    =test name
+#        --cleanup           -x
+#        --prerun            -P    =pre-command
+#        --postrun           -R    =post-command
+#        --log               -G    =log directory
+#        --regionnoise       -I    =shift
+#        --chunknoise        -N    =bytes
+#        --threaddelay       -T    =jiffies
+#        --verify            -V
+#        --zerocopy          -z
+#        --nowait            -O
+#        --human-readable    -H
+#        --verbose           -v    =increase verbosity
+#        --help              -?    =this help
+
+ZPIOS_CMD="${ZPIOS}                                              \
+       --load=dmuio                                             \
+       --pool=${ZPOOL_NAME}                                     \
+       --name=${ZPOOL_CONFIG}                                   \
+       --threadcount=4                                          \
+       --regioncount=1024                                       \
+       --regionsize=4M                                          \
+       --chunksize=1M                                           \
+       --offset=4M                                              \
+       --cleanup                                                \
+       --human-readable                                         \
+       ${ZPIOS_OPTIONS}"
+
+zpios_start() {
+       if [ ${VERBOSE} ]; then
+               ZPIOS_CMD="${ZPIOS_CMD} --verbose"
+               echo ${ZPIOS_CMD}
+       fi
+
+       ${ZPIOS_CMD} || exit 1
+}
+
+zpios_stop() {
+       [ ${VERBOSE} ] && echo
+}
diff --git a/zfs/scripts/zpios-test/Makefile.am b/zfs/scripts/zpios-test/Makefile.am
new file mode 100644 (file)
index 0000000..c74e24f
--- /dev/null
@@ -0,0 +1,13 @@
+pkgdatatestdir = $(pkgdatadir)/zpios-test
+dist_pkgdatatest_SCRIPTS = \
+       $(top_srcdir)/scripts/zpios-test/16th-8192rc-4rs-1cs-4off.sh \
+       $(top_srcdir)/scripts/zpios-test/1th-16rc-4rs-1cs-4off.sh \
+       $(top_srcdir)/scripts/zpios-test/1x256th-65536rc-4rs-1cs-4off.sh \
+       $(top_srcdir)/scripts/zpios-test/256th-65536rc-4rs-1cs-4off.sh \
+       $(top_srcdir)/scripts/zpios-test/4th-1024rc-4rs-1cs-4off.sh \
+       $(top_srcdir)/scripts/zpios-test/large.sh \
+       $(top_srcdir)/scripts/zpios-test/large-thread-survey.sh \
+       $(top_srcdir)/scripts/zpios-test/medium.sh \
+       $(top_srcdir)/scripts/zpios-test/small.sh \
+       $(top_srcdir)/scripts/zpios-test/tiny.sh \
+       $(top_srcdir)/scripts/zpios-test/lustre.sh
diff --git a/zfs/scripts/zpios-test/Makefile.in b/zfs/scripts/zpios-test/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/scripts/zpios-test/large-thread-survey.sh b/zfs/scripts/zpios-test/large-thread-survey.sh
new file mode 120000 (symlink)
index 0000000..90b6e3c
--- /dev/null
@@ -0,0 +1 @@
+1x256th-65536rc-4rs-1cs-4off.sh
\ No newline at end of file
diff --git a/zfs/scripts/zpios-test/large.sh b/zfs/scripts/zpios-test/large.sh
new file mode 120000 (symlink)
index 0000000..b8e22bf
--- /dev/null
@@ -0,0 +1 @@
+256th-65536rc-4rs-1cs-4off.sh
\ No newline at end of file
diff --git a/zfs/scripts/zpios-test/lustre.sh b/zfs/scripts/zpios-test/lustre.sh
new file mode 100644 (file)
index 0000000..e02df22
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+#
+# Usage: zpios
+#        --threadcount       -t    =values
+#        --threadcount_low   -l    =value
+#        --threadcount_high  -h    =value
+#        --threadcount_incr  -e    =value
+#        --regioncount       -n    =values
+#        --regioncount_low   -i    =value
+#        --regioncount_high  -j    =value
+#        --regioncount_incr  -k    =value
+#        --offset            -o    =values
+#        --offset_low        -m    =value
+#        --offset_high       -q    =value
+#        --offset_incr       -r    =value
+#        --chunksize         -c    =values
+#        --chunksize_low     -a    =value
+#        --chunksize_high    -b    =value
+#        --chunksize_incr    -g    =value
+#        --regionsize        -s    =values
+#        --regionsize_low    -A    =value
+#        --regionsize_high   -B    =value
+#        --regionsize_incr   -C    =value
+#        --load              -L    =dmuio|ssf|fpp
+#        --pool              -p    =pool name
+#        --name              -M    =test name
+#        --cleanup           -x
+#        --prerun            -P    =pre-command
+#        --postrun           -R    =post-command
+#        --log               -G    =log directory
+#        --regionnoise       -I    =shift
+#        --chunknoise        -N    =bytes
+#        --threaddelay       -T    =jiffies
+#        --verify            -V
+#        --zerocopy          -z
+#        --nowait            -O
+#        --human-readable    -H
+#        --verbose           -v    =increase verbosity
+#        --help              -?    =this help
+
+ZPIOS_CMD="${ZPIOS}                                              \
+       --load=dmuio,fpp                                         \
+       --pool=${ZPOOL_NAME}                                     \
+       --name=${ZPOOL_DESC}                                     \
+       --threadcount=128                                        \
+       --regioncount=4096                                       \
+       --regionsize=16M                                         \
+       --chunksize=1M                                           \
+       --offset=0M                                              \
+       --threaddelay=0                                          \
+       --cleanup                                                \
+       --human-readable                                         \
+       ${ZPIOS_OPTIONS}"
+
+zpios_start() {
+       if [ ${VERBOSE} ]; then
+               ZPIOS_CMD="${ZPIOS_CMD} --verbose"
+               echo ${ZPIOS_CMD}
+       fi
+
+       ${ZPIOS_CMD} || exit 1
+}
+
+zpios_stop() {
+       [ ${VERBOSE} ] && echo
+}
diff --git a/zfs/scripts/zpios-test/medium.sh b/zfs/scripts/zpios-test/medium.sh
new file mode 120000 (symlink)
index 0000000..d81027b
--- /dev/null
@@ -0,0 +1 @@
+16th-8192rc-4rs-1cs-4off.sh
\ No newline at end of file
diff --git a/zfs/scripts/zpios-test/small.sh b/zfs/scripts/zpios-test/small.sh
new file mode 120000 (symlink)
index 0000000..cbf03b5
--- /dev/null
@@ -0,0 +1 @@
+4th-1024rc-4rs-1cs-4off.sh
\ No newline at end of file
diff --git a/zfs/scripts/zpios-test/tiny.sh b/zfs/scripts/zpios-test/tiny.sh
new file mode 120000 (symlink)
index 0000000..ba8b7cd
--- /dev/null
@@ -0,0 +1 @@
+1th-16rc-4rs-1cs-4off.sh
\ No newline at end of file
diff --git a/zfs/scripts/zpios.sh b/zfs/scripts/zpios.sh
new file mode 100755 (executable)
index 0000000..0fcb88d
--- /dev/null
@@ -0,0 +1,281 @@
+#!/bin/bash
+#
+# Wrapper script for easily running zpios based tests
+#
+
+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=zpios.sh
+DATE=`date +%Y%m%d-%H%M%S`
+if [ "${ZPIOS_MODULES}" ]; then
+       MODULES=(${ZPIOS_MODULES[*]})
+else
+       MODULES=(zpios)
+fi
+
+usage() {
+cat << EOF
+USAGE:
+$0 [hvp] <-c config> <-t test>
+
+DESCRIPTION:
+        Helper script for easy zpios benchmarking.
+
+OPTIONS:
+        -h      Show this message
+        -v      Verbose
+        -f      Force everything
+        -p      Enable profiling
+        -c      Zpool configuration
+        -t      Zpios test
+        -o      Additional zpios options
+        -l      Additional zpool options
+        -s      Additional zfs options
+
+EOF
+}
+
+unload_die() {
+       unload_modules
+       while [ -c /dev/zpios ]; do
+               sleep 1
+       done
+
+       exit 1
+}
+
+print_header() {
+       echo --------------------- ZPIOS RESULTS ----------------------------
+       echo -n "Date: "; date
+       echo -n "Kernel: "; uname -r
+       dmesg | grep "Loaded Solaris Porting Layer" | tail -n1
+       dmesg | grep "Loaded ZFS Filesystem" | tail -n1
+       echo
+}
+
+print_spl_info() {
+       echo --------------------- SPL Tunings ------------------------------
+       ${SYSCTL} -A | grep spl
+
+       if [ -d /sys/module/spl/parameters ]; then
+               grep [0-9] /sys/module/spl/parameters/*
+       else
+               grep [0-9] /sys/module/spl/*
+       fi
+
+       echo
+}
+
+print_zfs_info() {
+       echo --------------------- ZFS Tunings ------------------------------
+       ${SYSCTL} -A | grep zfs
+
+       if [ -d /sys/module/zfs/parameters ]; then
+               grep [0-9] /sys/module/zfs/parameters/*
+       else
+               grep [0-9] /sys/module/zfs/*
+       fi
+
+       echo
+}
+
+print_stats() {
+       echo ---------------------- Statistics -------------------------------
+       ${SYSCTL} -A | grep spl | grep stack_max
+
+       if [ -d /proc/spl/kstat/ ]; then
+               if [ -f /proc/spl/kstat/zfs/arcstats ]; then
+                       echo "* ARC"
+                       cat /proc/spl/kstat/zfs/arcstats
+                       echo
+               fi
+
+               if [ -f /proc/spl/kstat/zfs/vdev_cache_stats ]; then
+                       echo "* VDEV Cache"
+                       cat /proc/spl/kstat/zfs/vdev_cache_stats
+                       echo
+               fi
+       fi
+
+       if [ -f /proc/spl/kmem/slab ]; then
+               echo "* SPL SLAB"
+               cat /proc/spl/kmem/slab
+               echo
+       fi
+
+       echo
+}
+
+check_test() {
+
+       if [ ! -f ${ZPIOS_TEST} ]; then
+               local NAME=`basename ${ZPIOS_TEST} .sh`
+               ERROR="Unknown test '${NAME}', available tests are:\n"
+
+               for TST in `ls ${ZPIOSDIR}/ | grep ".sh"`; do
+                       local NAME=`basename ${TST} .sh`
+                       ERROR="${ERROR}${NAME}\n"
+               done
+
+               return 1
+       fi
+
+       return 0
+}
+
+zpios_profile_config() {
+cat > ${PROFILE_DIR}/zpios-config.sh << EOF
+#
+# Zpios Profiling Configuration
+#
+
+PROFILE_DIR=/tmp/zpios/${ZPOOL_CONFIG}+${ZPIOS_TEST_ARG}+${DATE}
+PROFILE_PRE=${ZPIOSPROFILEDIR}/zpios-profile-pre.sh
+PROFILE_POST=${ZPIOSPROFILEDIR}/zpios-profile-post.sh
+PROFILE_USER=${ZPIOSPROFILEDIR}/zpios-profile.sh
+PROFILE_PIDS=${ZPIOSPROFILEDIR}/zpios-profile-pids.sh
+PROFILE_DISK=${ZPIOSPROFILEDIR}/zpios-profile-disk.sh
+PROFILE_ARC_PROC=/proc/spl/kstat/zfs/arcstats
+PROFILE_VDEV_CACHE_PROC=/proc/spl/kstat/zfs/vdev_cache_stats
+
+OPROFILE_KERNEL="/boot/vmlinux-`uname -r`"
+OPROFILE_KERNEL_DIR="/lib/modules/`uname -r`/kernel/"
+OPROFILE_SPL_DIR=${SPLBUILD}/module/
+OPROFILE_ZFS_DIR=${MODDIR}
+
+EOF
+}
+
+zpios_profile_start() {
+       PROFILE_DIR=/tmp/zpios/${ZPOOL_CONFIG}+${ZPIOS_TEST_ARG}+${DATE}
+
+       mkdir -p ${PROFILE_DIR}
+       zpios_profile_config
+       . ${PROFILE_DIR}/zpios-config.sh
+
+       ZPIOS_OPTIONS="${ZPIOS_OPTIONS} --log=${PROFILE_DIR}"
+       ZPIOS_OPTIONS="${ZPIOS_OPTIONS} --prerun=${PROFILE_PRE}"
+       ZPIOS_OPTIONS="${ZPIOS_OPTIONS} --postrun=${PROFILE_POST}"
+
+       /usr/bin/opcontrol --init
+       /usr/bin/opcontrol --setup --vmlinux=${OPROFILE_KERNEL}
+}
+
+zpios_profile_stop() {
+       /usr/bin/opcontrol --shutdown
+       /usr/bin/opcontrol --deinit
+}
+
+PROFILE=
+ZPOOL_CONFIG=zpool-config.sh
+ZPIOS_TEST=zpios-test.sh
+ZPOOL_NAME=zpios
+ZPIOS_OPTIONS=
+ZPOOL_OPTIONS=""
+ZFS_OPTIONS=""
+
+while getopts 'hvfpc:t:o:l:s:' OPTION; do
+       case $OPTION in
+       h)
+               usage
+               exit 1
+               ;;
+       v)
+               VERBOSE=1
+               VERBOSE_FLAG="-v"
+               ;;
+       f)
+               FORCE=1
+               FORCE_FLAG="-f"
+               ;;
+       p)
+               PROFILE=1
+               ;;
+       c)
+               ZPOOL_CONFIG=${OPTARG}
+               ;;
+       t)
+               ZPIOS_TEST_ARG=${OPTARG}
+               ZPIOS_TEST=${ZPIOSDIR}/${OPTARG}.sh
+               ;;
+       o)
+               ZPIOS_OPTIONS=${OPTARG}
+               ;;
+       l)      # Passed through to zpool-create.sh 
+               ZPOOL_OPTIONS=${OPTARG}
+               ;;
+       s)      # Passed through to zpool-create.sh
+               ZFS_OPTIONS=${OPTARG}
+               ;;
+       ?)
+               usage
+               exit
+               ;;
+       esac
+done
+
+if [ $(id -u) != 0 ]; then
+        die "Must run as root"
+fi
+
+# Validate and source your test config
+check_test || die "${ERROR}"
+. ${ZPIOS_TEST}
+
+# Pull in the zpios test module if not loaded.  If this fails, it is
+# likely because the full module stack was not yet loaded with zfs.sh
+if check_modules; then
+       if ! load_modules; then
+               die "Run 'zfs.sh' to ensure the full module stack is loaded"
+       fi
+fi
+
+# Wait for device creation
+while [ ! -c /dev/zpios ]; do
+       sleep 1
+done
+
+if [ ${VERBOSE} ]; then
+       print_header
+       print_spl_info
+       print_zfs_info
+fi
+
+# Create the zpool configuration
+${ZPOOL_CREATE_SH} ${VERBOSE_FLAG} ${FORCE_FLAG} \
+       -p ${ZPOOL_NAME} -c ${ZPOOL_CONFIG} \
+       -l "${ZPOOL_OPTIONS}" -s "${ZFS_OPTIONS}" || unload_die
+
+if [ ${PROFILE} ]; then
+       zpios_profile_start
+fi
+
+zpios_start
+zpios_stop
+
+if [ ${PROFILE} ]; then
+       zpios_profile_stop
+fi
+
+if [ ${VERBOSE} ]; then
+       print_stats
+fi
+
+# Destroy the zpool configuration
+${ZPOOL_CREATE_SH} ${VERBOSE_FLAG} ${FORCE_FLAG} \
+       -p ${ZPOOL_NAME} -c ${ZPOOL_CONFIG} -d || unload_die
+
+# Unload the test module stack and wait for device removal
+unload_modules
+while [ -c /dev/zpios ]; do
+       sleep 1
+done
+
+exit 0
diff --git a/zfs/scripts/zpool-config/Makefile.am b/zfs/scripts/zpool-config/Makefile.am
new file mode 100644 (file)
index 0000000..2d77994
--- /dev/null
@@ -0,0 +1,30 @@
+pkgdataconfigdir = $(pkgdatadir)/zpool-config
+dist_pkgdataconfig_SCRIPTS = \
+       $(top_srcdir)/scripts/zpool-config/dm0-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/file-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/file-raid10.sh \
+       $(top_srcdir)/scripts/zpool-config/file-raidz2.sh \
+       $(top_srcdir)/scripts/zpool-config/file-raidz.sh \
+       $(top_srcdir)/scripts/zpool-config/hda-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-raid10.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-raidz2.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-raidz.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-faulty-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-faulty-raid10.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-faulty-raidz.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-faulty-raidz2.sh \
+       $(top_srcdir)/scripts/zpool-config/lo-faulty-raidz3.sh \
+       $(top_srcdir)/scripts/zpool-config/md0-raid10.sh \
+       $(top_srcdir)/scripts/zpool-config/md0-raid5.sh \
+       $(top_srcdir)/scripts/zpool-config/ram0-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/scsi_debug-noraid.sh \
+       $(top_srcdir)/scripts/zpool-config/scsi_debug-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/scsi_debug-raid10.sh \
+       $(top_srcdir)/scripts/zpool-config/scsi_debug-raidz.sh \
+       $(top_srcdir)/scripts/zpool-config/scsi_debug-raidz2.sh \
+       $(top_srcdir)/scripts/zpool-config/scsi_debug-raidz3.sh \
+       $(top_srcdir)/scripts/zpool-config/sda-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/zpool-raid0.sh \
+       $(top_srcdir)/scripts/zpool-config/zpool-raid10.sh \
+       $(top_srcdir)/scripts/zpool-config/zpool-raidz.sh
diff --git a/zfs/scripts/zpool-config/Makefile.in b/zfs/scripts/zpool-config/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
diff --git a/zfs/scripts/zpool-config/dm0-raid0.sh b/zfs/scripts/zpool-config/dm0-raid0.sh
new file mode 100644 (file)
index 0000000..f7fa8f6
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/bash
+#
+# Four disk Raid-0 DM in a single Raid-0 Configuration
+#
+
+PVCREATE=${PVCREATE:-/sbin/pvcreate}
+PVREMOVE=${PVREMOVE:-/sbin/pvremove}
+PVDEVICES=${PVDEVICES:-"/dev/sd[abcd]"}
+
+VGCREATE=${VGCREATE:-/sbin/vgcreate}
+VGREMOVE=${VGREMOVE:-/sbin/vgremove}
+VGNAME=${VGNAME:-"vg_tank"}
+
+LVCREATE=${LVCREATE:-/sbin/lvcreate}
+LVREMOVE=${LVREMOVE:-/sbin/lvremove}
+LVNAME=${LVNAME:-"lv_tank"}
+LVSTRIPES=${LVSTRIPES:-4}
+LVSIZE=${LVSIZE:-32G}
+
+DEVICES="/dev/${VGNAME}/${LVNAME}"
+
+zpool_dm_destroy() {
+       msg ${LVREMOVE} -f ${VGNAME}/${LVNAME}
+       ${LVREMOVE} -f ${VGNAME}/${LVNAME} >/dev/null
+
+       msg ${VGREMOVE} -f ${VGNAME}
+       ${VGREMOVE} -f ${VGNAME} >/dev/null
+
+       msg ${PVREMOVE} ${PVDEVICES}
+       ${PVREMOVE} ${PVDEVICES} >/dev/null
+}
+
+zpool_create() {
+       # Remove EFI labels which cause pvcreate failure
+       for DEVICE in ${PVDEVICES}; do
+               dd if=/dev/urandom of=${DEVICE} bs=1k count=32 &>/dev/null
+       done
+
+       msg ${PVCREATE} -f ${PVDEVICES}
+       ${PVCREATE} -f ${PVDEVICES} >/dev/null || exit 1
+
+       msg ${VGCREATE} ${VGNAME} ${PVDEVICES}
+       ${VGCREATE} ${VGNAME} ${PVDEVICES} >/dev/null || exit 2
+
+       msg ${LVCREATE} --size=${LVSIZE} --stripes=${LVSTRIPES} \
+               --name=${LVNAME} ${VGNAME}
+       ${LVCREATE} --size=${LVSIZE} --stripes=${LVSTRIPES} \
+               --name=${LVNAME} ${VGNAME} >/dev/null || exit 3
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} \
+               ${DEVICES} || (zpool_dm_destroy && exit 4)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       zpool_dm_destroy
+}
diff --git a/zfs/scripts/zpool-config/file-raid0.sh b/zfs/scripts/zpool-config/file-raid0.sh
new file mode 100644 (file)
index 0000000..24b6aec
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# 4 File Raid-0 Configuration
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+
+zpool_create() {
+       for FILE in ${FILES}; do
+               msg "Creating ${FILE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${FILES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${FILES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               msg "Removing ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+}
diff --git a/zfs/scripts/zpool-config/file-raid10.sh b/zfs/scripts/zpool-config/file-raid10.sh
new file mode 100644 (file)
index 0000000..92b22c2
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# 4 File Raid-10 Configuration
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES_M1=${FILES_M1:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1"}
+FILES_M2=${FILES_M2:-"$FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+FILES="${FILES_M1} ${FILES_M2}"
+
+zpool_create() {
+       for FILE in ${FILES}; do
+               msg "Creating ${FILE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} \
+               mirror ${FILES_M1} mirror ${FILES_M2}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} \
+               mirror ${FILES_M1} mirror ${FILES_M2} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               msg "Removing ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+}
diff --git a/zfs/scripts/zpool-config/file-raidz.sh b/zfs/scripts/zpool-config/file-raidz.sh
new file mode 100644 (file)
index 0000000..4112deb
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# 4 File Raid-Z Configuration
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+
+zpool_create() {
+       for FILE in ${FILES}; do
+               msg "Creating ${FILE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz ${FILES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz ${FILES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               msg "Removing ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+}
diff --git a/zfs/scripts/zpool-config/file-raidz2.sh b/zfs/scripts/zpool-config/file-raidz2.sh
new file mode 100644 (file)
index 0000000..6e03da8
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# 4 File Raid-Z2 Configuration
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+
+zpool_create() {
+       for FILE in ${FILES}; do
+               msg "Creating ${FILE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz2 ${FILES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz2 ${FILES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               msg "Removing ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+}
diff --git a/zfs/scripts/zpool-config/hda-raid0.sh b/zfs/scripts/zpool-config/hda-raid0.sh
new file mode 100644 (file)
index 0000000..0623963
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Single disk /dev/hda Raid-0 Configuration
+#
+
+DEVICES="/dev/hda"
+
+zpool_create() {
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME} || exit 1
+}
diff --git a/zfs/scripts/zpool-config/lo-faulty-raid0.sh b/zfs/scripts/zpool-config/lo-faulty-raid0.sh
new file mode 100644 (file)
index 0000000..72894ee
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/bash
+#
+# 4 loopback devices using the md faulty level for easy
+# fault injection on top of which is layered raid0 (striped).
+#
+#     zpool-vdev0    zpool-vdev1    zpool-vdev2    zpool-vdev3
+#     loop0          loop1          loop2          loop3
+#     md0 (faulty)   md1 (faulty)   md2 (faulty)   md3 (faulty)
+#     <--------------------- raid0 zpool --------------------->
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+LODEVICES=""
+MDDEVICES=""
+
+zpool_create() {
+       check_loop_utils
+       check_md_utils
+       check_md_partitionable || die "Error non-partitionable md devices"
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+               MDDEVICE=`unused_md_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1M count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || \
+                       die "Error $? creating ${LODEVICE} using ${FILE}"
+
+               LODEVICES="${LODEVICES} ${LODEVICE}"
+
+               # Setup the md device on the loopback device.
+               msg "Creating ${MDDEVICE} using ${LODEVICE}"
+               ${MDADM} --build ${MDDEVICE} --level=faulty                  \
+                       --raid-devices=1 ${LODEVICE} &>/dev/null ||          \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error $? creating ${MDDEVICE} using ${LODEVICE}")
+               wait_udev ${MDDEVICE} 30 ||                                  \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error udev never created ${MDDEVICE}")
+
+               # Check if the md device support partitions
+               ${BLOCKDEV} --rereadpt ${MDDEVICE} 2>/dev/null ||            \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error ${MDDEVICE} does not support partitions")
+
+               # Create a GPT/EFI partition table for ZFS to use.
+               ${PARTED} --script ${MDDEVICE} mklabel gpt
+               MDDEVICES="${MDDEVICES} ${MDDEVICE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${MDDEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${MDDEVICES} ||          \
+               (destroy_md_devices "${MDDEVICES}" &&                        \
+               destroy_loop_devices "${LODEVICES}" && exit 1)
+
+       echo "$LODEVICES" >/tmp/zpool-lo.txt
+       echo "$MDDEVICES" >/tmp/zpool-md.txt
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+       destroy_md_devices "`cat /tmp/zpool-md.txt`"
+       destroy_loop_devices "`cat /tmp/zpool-lo.txt`"
+
+       rm -f /tmp/zpool-md.txt /tmp/zpool-lo.txt
+}
diff --git a/zfs/scripts/zpool-config/lo-faulty-raid10.sh b/zfs/scripts/zpool-config/lo-faulty-raid10.sh
new file mode 100644 (file)
index 0000000..1a523ec
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/bash
+#
+# 4 loopback devices using the md faulty level for easy
+# fault injection on top of which is layered raid10 (mirrored).
+#
+#     zpool-vdev0    zpool-vdev1    zpool-vdev2    zpool-vdev3
+#     loop0          loop1          loop2          loop3
+#     md0 (faulty)   md1 (faulty)   md2 (faulty)   md3 (faulty)
+#     <--------------------- raid10 zpool --------------------->
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES_M1=${FILES_M1:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1"}
+FILES_M2=${FILES_M2:-"$FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+FILES="${FILES_M1} ${FILES_M2}"
+LODEVICES=""
+MDDEVICES=""
+MDDEVICES_M1=""
+MDDEVICES_M2=""
+
+zpool_create() {
+       local COUNT=0
+
+       check_loop_utils
+       check_md_utils
+       check_md_partitionable || die "Error non-partitionable md devices"
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+               MDDEVICE=`unused_md_device`
+               let COUNT=${COUNT}+1
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1M count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || \
+                       die "Error $? creating ${LODEVICE} using ${FILE}"
+
+               LODEVICES="${LODEVICES} ${LODEVICE}"
+
+               # Setup the md device on the loopback device.
+               msg "Creating ${MDDEVICE} using ${LODEVICE}"
+               ${MDADM} --build ${MDDEVICE} --level=faulty                  \
+                       --raid-devices=1 ${LODEVICE} &>/dev/null ||          \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error $? creating ${MDDEVICE} using ${LODEVICE}")
+               wait_udev ${MDDEVICE} 30 ||                                  \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error udev never created ${MDDEVICE}")
+
+               # Create empty GPT/EFI partition table.
+               ${PARTED} --script ${MDDEVICE} mklabel gpt
+               MDDEVICES="${MDDEVICES} ${MDDEVICE}"
+               if [ $((COUNT % 2)) -eq 0 ]; then
+                       MDDEVICES_M2="${MDDEVICES_M2} ${MDDEVICE}"
+               else
+                       MDDEVICES_M1="${MDDEVICES_M1} ${MDDEVICE}"
+               fi 
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME}                      \
+               mirror ${MDDEVICES_M1} mirror ${MDDEVICES_M2}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME}                          \
+               mirror ${MDDEVICES_M1} mirror ${MDDEVICES_M2} ||             \
+               (destroy_md_devices "${MDDEVICES}" &&                        \
+               destroy_loop_devices "${LODEVICES}" && exit 1)
+
+       echo "$LODEVICES" >/tmp/zpool-lo.txt
+       echo "$MDDEVICES" >/tmp/zpool-md.txt
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+       destroy_md_devices "`cat /tmp/zpool-md.txt`"
+       destroy_loop_devices "`cat /tmp/zpool-lo.txt`"
+
+       rm -f /tmp/zpool-md.txt /tmp/zpool-lo.txt
+}
diff --git a/zfs/scripts/zpool-config/lo-faulty-raidz.sh b/zfs/scripts/zpool-config/lo-faulty-raidz.sh
new file mode 100644 (file)
index 0000000..c8f88b3
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/bash
+#
+# 4 loopback devices using the md faulty level for easy
+# fault injection on top of which is layered raidz.
+#
+#     zpool-vdev0    zpool-vdev1    zpool-vdev2    zpool-vdev3
+#     loop0          loop1          loop2          loop3
+#     md0 (faulty)   md1 (faulty)   md2 (faulty)   md3 (faulty)
+#     <--------------------- raidz zpool --------------------->
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+LODEVICES=""
+MDDEVICES=""
+
+zpool_create() {
+       check_loop_utils
+       check_md_utils
+       check_md_partitionable || die "Error non-partitionable md devices"
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+               MDDEVICE=`unused_md_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1M count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || \
+                       die "Error $? creating ${LODEVICE} using ${FILE}"
+
+               LODEVICES="${LODEVICES} ${LODEVICE}"
+
+               # Setup the md device on the loopback device.
+               msg "Creating ${MDDEVICE} using ${LODEVICE}"
+               ${MDADM} --build ${MDDEVICE} --level=faulty                  \
+                       --raid-devices=1 ${LODEVICE} &>/dev/null ||          \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error $? creating ${MDDEVICE} using ${LODEVICE}")
+               wait_udev ${MDDEVICE} 30 ||                                  \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error udev never created ${MDDEVICE}")
+
+               # Create empty GPT/EFI partition table.
+               ${PARTED} --script ${MDDEVICE} mklabel gpt
+               MDDEVICES="${MDDEVICES} ${MDDEVICE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz ${MDDEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz ${MDDEVICES} ||    \
+               (destroy_md_devices "${MDDEVICES}" &&                        \
+               destroy_loop_devices "${LODEVICES}" && exit 1)
+
+       echo "$LODEVICES" >/tmp/zpool-lo.txt
+       echo "$MDDEVICES" >/tmp/zpool-md.txt
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+       destroy_md_devices "`cat /tmp/zpool-md.txt`"
+       destroy_loop_devices "`cat /tmp/zpool-lo.txt`"
+
+       rm -f /tmp/zpool-md.txt /tmp/zpool-lo.txt
+}
diff --git a/zfs/scripts/zpool-config/lo-faulty-raidz2.sh b/zfs/scripts/zpool-config/lo-faulty-raidz2.sh
new file mode 100644 (file)
index 0000000..85b7d46
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/bash
+#
+# 4 loopback devices using the md faulty level for easy
+# fault injection on top of which is layered raidz2.
+#
+#     zpool-vdev0    zpool-vdev1    zpool-vdev2    zpool-vdev3
+#     loop0          loop1          loop2          loop3
+#     md0 (faulty)   md1 (faulty)   md2 (faulty)   md3 (faulty)
+#     <--------------------- raidz2 zpool -------------------->
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+LODEVICES=""
+MDDEVICES=""
+
+zpool_create() {
+       check_loop_utils
+       check_md_utils
+       check_md_partitionable || die "Error non-partitionable md devices"
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+               MDDEVICE=`unused_md_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1M count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || \
+                       die "Error $? creating ${LODEVICE} using ${FILE}"
+
+               LODEVICES="${LODEVICES} ${LODEVICE}"
+
+               # Setup the md device on the loopback device.
+               msg "Creating ${MDDEVICE} using ${LODEVICE}"
+               ${MDADM} --build ${MDDEVICE} --level=faulty                  \
+                       --raid-devices=1 ${LODEVICE} &>/dev/null ||          \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error $? creating ${MDDEVICE} using ${LODEVICE}")
+               wait_udev ${MDDEVICE} 30 ||                                  \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error udev never created ${MDDEVICE}")
+
+               # Create empty GPT/EFI partition table.
+               ${PARTED} --script ${MDDEVICE} mklabel gpt
+               MDDEVICES="${MDDEVICES} ${MDDEVICE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz2 ${MDDEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz2 ${MDDEVICES} ||   \
+               (destroy_md_devices "${MDDEVICES}" &&                        \
+               destroy_loop_devices "${LODEVICES}" && exit 1)
+
+       echo "$LODEVICES" >/tmp/zpool-lo.txt
+       echo "$MDDEVICES" >/tmp/zpool-md.txt
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+       destroy_md_devices "`cat /tmp/zpool-md.txt`"
+       destroy_loop_devices "`cat /tmp/zpool-lo.txt`"
+
+       rm -f /tmp/zpool-md.txt /tmp/zpool-lo.txt
+}
diff --git a/zfs/scripts/zpool-config/lo-faulty-raidz3.sh b/zfs/scripts/zpool-config/lo-faulty-raidz3.sh
new file mode 100644 (file)
index 0000000..7836b5f
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# 4 loopback devices using the md faulty level for easy
+# fault injection on top of which is layered raidz3.
+#
+#     zpool-vdev0    zpool-vdev1    zpool-vdev2    zpool-vdev3
+#     loop0          loop1          loop2          loop3
+#     md0 (faulty)   md1 (faulty)   md2 (faulty)   md3 (faulty)
+#     <--------------------- raidz3 zpool -------------------->
+#
+
+FILES="/tmp/zpool-vdev0  \
+       /tmp/zpool-vdev1  \
+       /tmp/zpool-vdev2  \
+       /tmp/zpool-vdev3"
+LODEVICES=""
+MDDEVICES=""
+
+zpool_create() {
+       check_loop_utils
+       check_md_utils
+       check_md_partitionable || die "Error non-partitionable md devices"
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+               MDDEVICE=`unused_md_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1M count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || \
+                       die "Error $? creating ${LODEVICE} using ${FILE}"
+
+               LODEVICES="${LODEVICES} ${LODEVICE}"
+
+               # Setup the md device on the loopback device.
+               msg "Creating ${MDDEVICE} using ${LODEVICE}"
+               ${MDADM} --build ${MDDEVICE} --level=faulty                  \
+                       --raid-devices=1 ${LODEVICE} &>/dev/null ||          \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error $? creating ${MDDEVICE} using ${LODEVICE}")
+               wait_udev ${MDDEVICE} 30 ||                                  \
+                       (destroy_md_devices "${MDDEVICES}" &&                \
+                       destroy_loop_devices "${LODEVICES}" &&               \
+                       die "Error udev never created ${MDDEVICE}")
+
+               # Create empty GPT/EFI partition table.
+               ${PARTED} --script ${MDDEVICE} mklabel gpt
+               MDDEVICES="${MDDEVICES} ${MDDEVICE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz3 ${MDDEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz3 ${MDDEVICES} ||   \
+               (destroy_md_devices "${MDDEVICES}" &&                        \
+               destroy_loop_devices "${LODEVICES}" && exit 1)
+
+       echo "$LODEVICES" >/tmp/zpool-lo.txt
+       echo "$MDDEVICES" >/tmp/zpool-md.txt
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+       destroy_md_devices "`cat /tmp/zpool-md.txt`"
+       destroy_loop_devices "`cat /tmp/zpool-lo.txt`"
+
+       rm -f /tmp/zpool-md.txt /tmp/zpool-lo.txt
+}
diff --git a/zfs/scripts/zpool-config/lo-raid0.sh b/zfs/scripts/zpool-config/lo-raid0.sh
new file mode 100644 (file)
index 0000000..3f2cfe5
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# 4 Device Loopback Raid-0 Configuration
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+DEVICES=""
+
+zpool_create() {
+       check_loop_utils
+
+       for FILE in ${FILES}; do
+               DEVICE=`unused_loop_device`
+               msg "Creating ${FILE} using loopback device ${DEVICE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+               ${LOSETUP} ${DEVICE} ${FILE} ||
+                       die "Error $? creating ${FILE} -> ${DEVICE} loopback"
+               DEVICES="${DEVICES} ${DEVICE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       # Delay to ensure device is closed before removing loop device
+       sleep 1
+
+       for FILE in ${FILES}; do
+               DEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${FILE} using loopback device ${DEVICE}"
+               ${LOSETUP} -d ${DEVICE} ||
+                       die "Error $? destroying ${FILE} -> ${DEVICE} loopback"
+               rm -f ${FILE} || exit 1
+       done
+}
diff --git a/zfs/scripts/zpool-config/lo-raid10.sh b/zfs/scripts/zpool-config/lo-raid10.sh
new file mode 100644 (file)
index 0000000..580ed1f
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# 4 Device Loopback Raid-0 Configuration
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES_M1=${FILES_M1:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1"}
+FILES_M2=${FILES_M2:-"$FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+FILES="${FILES_M1} ${FILES_M2}"
+DEVICES_M1=""
+DEVICES_M2=""
+
+zpool_create() {
+       check_loop_utils
+
+       for FILE in ${FILES_M1}; do
+               DEVICE=`unused_loop_device`
+               msg "Creating ${FILE} using loopback device ${DEVICE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+               ${LOSETUP} ${DEVICE} ${FILE} ||
+                       die "Error $? creating ${FILE} -> ${DEVICE} loopback"
+               DEVICES_M1="${DEVICES_M1} ${DEVICE}"
+       done
+
+       for FILE in ${FILES_M2}; do
+               DEVICE=`unused_loop_device`
+               msg "Creating ${FILE} using loopback device ${DEVICE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+               ${LOSETUP} ${DEVICE} ${FILE} ||
+                       die "Error $? creating ${FILE} -> ${DEVICE} loopback"
+               DEVICES_M2="${DEVICES_M2} ${DEVICE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} \
+               mirror ${DEVICES_M1} mirror ${DEVICES_M2}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} \
+               mirror ${DEVICES_M1} mirror ${DEVICES_M2}
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       # Delay to ensure device is closed before removing loop device
+       sleep 1
+
+       for FILE in ${FILES}; do
+               DEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${FILE} using loopback device ${DEVICE}"
+               ${LOSETUP} -d ${DEVICE} ||
+                       die "Error $? destroying ${FILE} -> ${DEVICE} loopback"
+               rm -f ${FILE} || exit 1
+       done
+}
diff --git a/zfs/scripts/zpool-config/lo-raidz.sh b/zfs/scripts/zpool-config/lo-raidz.sh
new file mode 100644 (file)
index 0000000..90b26c5
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/bash
+#
+# 4 Device Loopback Raid-0 Configuration
+#
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+DEVICES=""
+
+zpool_create() {
+       check_loop_utils
+
+       for FILE in ${FILES}; do
+               DEVICE=`unused_loop_device`
+               msg "Creating ${FILE} using loopback device ${DEVICE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+               ${LOSETUP} ${DEVICE} ${FILE} ||
+                       die "Error $? creating ${FILE} -> ${DEVICE} loopback"
+               DEVICES="${DEVICES} ${DEVICE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz ${DEVICES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       # Delay to ensure device is closed before removing loop device
+       sleep 1
+
+       for FILE in ${FILES}; do
+               DEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${FILE} using loopback device ${DEVICE}"
+               ${LOSETUP} -d ${DEVICE} ||
+                       die "Error $? destroying ${FILE} -> ${DEVICE} loopback"
+               rm -f ${FILE} || exit 1
+       done
+}
diff --git a/zfs/scripts/zpool-config/lo-raidz2.sh b/zfs/scripts/zpool-config/lo-raidz2.sh
new file mode 100644 (file)
index 0000000..9e58b2a
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# 4 Device Loopback Raid-0 Configuration
+#
+
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 \
+    $FILEDIR/file-vdev2 $FILEDIR/file-vdev3"}
+DEVICES=""
+
+zpool_create() {
+       check_loop_utils
+
+       for FILE in ${FILES}; do
+               DEVICE=`unused_loop_device`
+               msg "Creating ${FILE} using loopback device ${DEVICE}"
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256 \
+                       &>/dev/null || die "Error $? creating ${FILE}"
+               ${LOSETUP} ${DEVICE} ${FILE} ||
+                       die "Error $? creating ${FILE} -> ${DEVICE} loopback"
+               DEVICES="${DEVICES} ${DEVICE}"
+       done
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz2 ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz2 ${DEVICES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       # Delay to ensure device is closed before removing loop device
+       sleep 1
+
+       for FILE in ${FILES}; do
+               DEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${FILE} using loopback device ${DEVICE}"
+               ${LOSETUP} -d ${DEVICE} ||
+                       die "Error $? destroying ${FILE} -> ${DEVICE} loopback"
+               rm -f ${FILE} || exit 1
+       done
+}
diff --git a/zfs/scripts/zpool-config/md0-raid10.sh b/zfs/scripts/zpool-config/md0-raid10.sh
new file mode 100644 (file)
index 0000000..65cae6a
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# Four disk Raid-10 in a single Raid-0 Configuration
+#
+
+MDADM=${MDADM:-/sbin/mdadm}
+MDDEVICES=${MDDEVICES:-"/dev/sd[abcd]"}
+MDCOUNT=${MDCOUNT:-4}
+MDRAID=${MDRAID:-10}
+
+DEVICES="/dev/md0"
+
+zpool_md_destroy() {
+       msg ${MDADM} --manage --stop ${DEVICES}
+       ${MDADM} --manage --stop ${DEVICES} &>/dev/null
+
+       msg ${MDADM} --zero-superblock ${MDDEVICES}
+       ${MDADM} --zero-superblock ${MDDEVICES} >/dev/null
+}
+
+zpool_create() {
+       msg ${MDADM} --create ${DEVICES} --level=${MDRAID} \
+               --raid-devices=${MDCOUNT} ${MDDEVICES}
+       ${MDADM} --create ${DEVICES} --level=${MDRAID} \
+               --raid-devices=${MDCOUNT} ${MDDEVICES} \
+               &>/dev/null || (zpool_md_destroy && exit 1)
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} \
+               ${DEVICES} || (zpool_md_destroy && exit 2)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       zpool_md_destroy
+}
diff --git a/zfs/scripts/zpool-config/md0-raid5.sh b/zfs/scripts/zpool-config/md0-raid5.sh
new file mode 100644 (file)
index 0000000..373034b
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/bash
+#
+# Four disk Raid-5 in a single Raid-0 Configuration
+#
+
+MDADM=${MDADM:-/sbin/mdadm}
+MDDEVICES=${MDDEVICES:-"/dev/sd[abcd]"}
+MDCOUNT=${MDCOUNT:-4}
+MDRAID=${MDRAID:-5}
+
+DEVICES="/dev/md0"
+
+zpool_md_destroy() {
+       msg ${MDADM} --manage --stop ${DEVICES}
+       ${MDADM} --manage --stop ${DEVICES} &>/dev/null
+
+       msg ${MDADM} --zero-superblock ${MDDEVICES}
+       ${MDADM} --zero-superblock ${MDDEVICES} >/dev/null
+}
+
+zpool_create() {
+       msg ${MDADM} --create ${DEVICES} --level=${MDRAID} \
+               --raid-devices=${MDCOUNT} ${MDDEVICES}
+       ${MDADM} --create ${DEVICES} --level=${MDRAID} \
+               --raid-devices=${MDCOUNT} ${MDDEVICES} \
+               &>/dev/null || (zpool_md_destroy && exit 1)
+
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} \
+               ${DEVICES} || (zpool_md_destroy && exit 2)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       zpool_md_destroy
+}
diff --git a/zfs/scripts/zpool-config/ram0-raid0.sh b/zfs/scripts/zpool-config/ram0-raid0.sh
new file mode 100644 (file)
index 0000000..801c912
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Single ram disk /dev/ram0 Raid-0 Configuration
+#
+
+DEVICES="/dev/ram0"
+
+zpool_create() {
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME} || exit 1
+}
diff --git a/zfs/scripts/zpool-config/scsi_debug-noraid.sh b/zfs/scripts/zpool-config/scsi_debug-noraid.sh
new file mode 100644 (file)
index 0000000..c508ffb
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# 1 scsi_debug devices on top of which is layered no raid.
+#
+
+SDSIZE=${SDSIZE:-128}
+SDHOSTS=${SDHOSTS:-1}
+SDTGTS=${SDTGTS:-1}
+SDLUNS=${SDLUNS:-1}
+LDMOD=/sbin/modprobe
+
+zpool_create() {
+       check_sd_utils
+
+       test `${LSMOD} | grep -c scsi_debug` -gt 0 && \
+               (echo 0 >/sys/module/scsi_debug/parameters/every_nth &&      \
+               ${RMMOD} scsi_debug || exit 1)
+       udev_trigger
+
+       msg "${LDMOD} scsi_debug dev_size_mb=${SDSIZE} "                     \
+               "add_host=${SDHOSTS} num_tgts=${SDTGTS} "                    \
+               "max_luns=${SDLUNS}"
+       ${LDMOD} scsi_debug                                                  \
+               dev_size_mb=${SDSIZE}                                        \
+               add_host=${SDHOSTS}                                          \
+               num_tgts=${SDTGTS}                                           \
+               max_luns=${SDLUNS} ||                                        \
+               die "Error $? creating scsi_debug devices"
+       udev_trigger
+       SDDEVICE=`${LSSCSI}|${AWK} '/scsi_debug/ { print $6; exit }'`
+
+       msg "${PARTED} -s ${SDDEVICE} mklabel gpt"
+       ${PARTED} -s ${SDDEVICE} mklabel gpt ||                              \
+               (${RMMOD} scsi_debug && die "Error $? creating gpt label")
+
+       msg "${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${SDDEVICE}"
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${SDDEVICE} ||           \
+               (${RMMOD} scsi_debug && exit 1)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+       msg "${RMMOD} scsi_debug"
+       ${RMMOD} scsi_debug || die "Error $? removing scsi_debug devices"
+}
diff --git a/zfs/scripts/zpool-config/scsi_debug-raid0.sh b/zfs/scripts/zpool-config/scsi_debug-raid0.sh
new file mode 100644 (file)
index 0000000..6672085
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/bash
+#
+# 1 scsi_debug device for fault injection and 3 loopback devices
+# on top of which is layered raid0 (striped).
+#
+
+SDSIZE=${SDSIZE:-256}
+SDHOSTS=${SDHOSTS:-1}
+SDTGTS=${SDTGTS:-1}
+SDLUNS=${SDLUNS:-1}
+LDMOD=/sbin/modprobe
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 $FILEDIR/file-vdev2"}
+DEVICES=""
+
+zpool_create() {
+       check_loop_utils
+       check_sd_utils
+
+       test `${LSMOD} | grep -c scsi_debug` -gt 0 &&                        \
+               (echo 0 >/sys/module/scsi_debug/parameters/every_nth &&      \
+               ${RMMOD} scsi_debug || exit 1)
+       udev_trigger
+
+       msg "${LDMOD} scsi_debug dev_size_mb=${SDSIZE} "                     \
+               "add_host=${SDHOSTS} num_tgts=${SDTGTS} "                    \
+               "max_luns=${SDLUNS}"
+       ${LDMOD} scsi_debug                                                  \
+               dev_size_mb=${SDSIZE}                                        \
+               add_host=${SDHOSTS}                                          \
+               num_tgts=${SDTGTS}                                           \
+               max_luns=${SDLUNS} ||                                        \
+               die "Error $? creating scsi_debug devices"
+       udev_trigger
+
+       SDDEVICE=`${LSSCSI} | ${AWK} '/scsi_debug/ { print $6; exit }'`
+       msg "${PARTED} -s ${SDDEVICE} mklabel gpt"
+       ${PARTED} -s ${SDDEVICE} mklabel gpt ||                              \
+               (${RMMOD} scsi_debug && die "Error $? creating gpt label")
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256         \
+                       &>/dev/null || (${RMMOD} scsi_debug &&               \
+                       die "Error $? creating ${FILE}")
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || (${RMMOD} scsi_debug       \
+                       die "Error $? creating ${LODEVICE} using ${FILE}")
+
+               DEVICES="${DEVICES} ${LODEVICE}"
+       done
+
+       DEVICES="${DEVICES} ${SDDEVICE}"
+
+       msg "${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES}"
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES} ||            \
+               (${RMMOD} scsi_debug && exit 1)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               LODEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${LODEVICE} using ${FILE}"
+               ${LOSETUP} -d ${LODEVICE} ||
+                       die "Error $? destroying ${LODEVICE} using ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+
+       msg "${RMMOD} scsi_debug"
+       ${RMMOD} scsi_debug || die "Error $? removing scsi_debug devices"
+}
diff --git a/zfs/scripts/zpool-config/scsi_debug-raid10.sh b/zfs/scripts/zpool-config/scsi_debug-raid10.sh
new file mode 100644 (file)
index 0000000..caff1a0
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/bash
+#
+# 1 scsi_debug device for fault injection and 3 loopback devices
+# on top of which is layered raid10 (mirrored).
+#
+
+SDSIZE=${SDSIZE:-256}
+SDHOSTS=${SDHOSTS:-1}
+SDTGTS=${SDTGTS:-1}
+SDLUNS=${SDLUNS:-1}
+LDMOD=/sbin/modprobe
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 $FILEDIR/file-vdev2"}
+DEVICES_M1=""
+DEVICES_M2=""
+
+zpool_create() {
+       local COUNT=0
+
+       check_loop_utils
+       check_sd_utils
+
+       test `${LSMOD} | grep -c scsi_debug` -gt 0 &&                        \
+               (echo 0 >/sys/module/scsi_debug/parameters/every_nth &&      \
+               ${RMMOD} scsi_debug || exit 1)
+       udev_trigger
+
+       msg "${LDMOD} scsi_debug dev_size_mb=${SDSIZE} "                     \
+               "add_host=${SDHOSTS} num_tgts=${SDTGTS} "                    \
+               "max_luns=${SDLUNS}"
+       ${LDMOD} scsi_debug                                                  \
+               dev_size_mb=${SDSIZE}                                        \
+               add_host=${SDHOSTS}                                          \
+               num_tgts=${SDTGTS}                                           \
+               max_luns=${SDLUNS} ||                                        \
+               die "Error $? creating scsi_debug devices"
+       udev_trigger
+       SDDEVICE=`${LSSCSI}|${AWK} '/scsi_debug/ { print $6; exit }'`
+       msg "${PARTED} -s ${SDDEVICE} mklabel gpt"
+       ${PARTED} -s ${SDDEVICE} mklabel gpt ||                              \
+               (${RMMOD} scsi_debug && die "Error $? creating gpt label")
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256         \
+                       &>/dev/null || (${RMMOD} scsi_debug &&               \
+                       die "Error $? creating ${FILE}")
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || (${RMMOD} scsi_debug       \
+                       die "Error $? creating ${LODEVICE} using ${FILE}")
+
+               DEVICES="${DEVICES} ${LODEVICE}"
+       done
+
+        DEVICES="${DEVICES} ${SDDEVICE}"
+
+        for DEVICE in ${DEVICES}; do
+               let COUNT=${COUNT}+1
+
+               if [ $((COUNT % 2)) -eq 0 ]; then
+                       DEVICES_M2="${DEVICES_M2} ${DEVICE}"
+               else
+                       DEVICES_M1="${DEVICES_M1} ${DEVICE}"
+               fi
+       done
+
+       msg "${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} "                   \
+               "mirror ${DEVICES_M1} mirror ${DEVICES_M2}"
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME}                          \
+               mirror ${DEVICES_M1} mirror ${DEVICES_M2} ||                 \
+               (${RMMOD} scsi_debug && exit 1)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               LODEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${LODEVICE} using ${FILE}"
+               ${LOSETUP} -d ${LODEVICE} ||
+                       die "Error $? destroying ${LODEVICE} using ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+
+       msg "${RMMOD} scsi_debug"
+       ${RMMOD} scsi_debug || die "Error $? removing scsi_debug devices"
+}
diff --git a/zfs/scripts/zpool-config/scsi_debug-raidz.sh b/zfs/scripts/zpool-config/scsi_debug-raidz.sh
new file mode 100644 (file)
index 0000000..bc22d10
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/bash
+#
+# 1 scsi_debug device for fault injection and 3 loopback devices
+# on top of which is layered raidz.
+#
+
+SDSIZE=${SDSIZE:-256}
+SDHOSTS=${SDHOSTS:-1}
+SDTGTS=${SDTGTS:-1}
+SDLUNS=${SDLUNS:-1}
+LDMOD=/sbin/modprobe
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 $FILEDIR/file-vdev2"}
+DEVICES=""
+
+zpool_create() {
+       check_loop_utils
+       check_sd_utils
+
+       test `${LSMOD} | grep -c scsi_debug` -gt 0 &&                        \
+               (echo 0 >/sys/module/scsi_debug/parameters/every_nth &&      \
+               ${RMMOD} scsi_debug || exit 1)
+       udev_trigger
+
+       msg "${LDMOD} scsi_debug dev_size_mb=${SDSIZE} "                     \
+               "add_host=${SDHOSTS} num_tgts=${SDTGTS} "                    \
+               "max_luns=${SDLUNS}"
+       ${LDMOD} scsi_debug                                                  \
+               dev_size_mb=${SDSIZE}                                        \
+               add_host=${SDHOSTS}                                          \
+               num_tgts=${SDTGTS}                                           \
+               max_luns=${SDLUNS} ||                                        \
+               die "Error $? creating scsi_debug devices"
+       udev_trigger
+
+       SDDEVICE=`${LSSCSI} | ${AWK} '/scsi_debug/ { print $6; exit }'`
+       msg "${PARTED} -s ${SDDEVICE} mklabel gpt"
+       ${PARTED} -s ${SDDEVICE} mklabel gpt ||                              \
+               (${RMMOD} scsi_debug && die "Error $? creating gpt label")
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256         \
+                       &>/dev/null || (${RMMOD} scsi_debug &&               \
+                       die "Error $? creating ${FILE}")
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || (${RMMOD} scsi_debug       \
+                       die "Error $? creating ${LODEVICE} using ${FILE}")
+
+               DEVICES="${DEVICES} ${LODEVICE}"
+       done
+
+       DEVICES="${DEVICES} ${SDDEVICE}"
+
+       msg "${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz ${DEVICES}"
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz ${DEVICES} ||      \
+               (${RMMOD} scsi_debug && exit 1)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               LODEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${LODEVICE} using ${FILE}"
+               ${LOSETUP} -d ${LODEVICE} ||
+                       die "Error $? destroying ${LODEVICE} using ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+
+       msg "${RMMOD} scsi_debug"
+       ${RMMOD} scsi_debug || die "Error $? removing scsi_debug devices"
+}
diff --git a/zfs/scripts/zpool-config/scsi_debug-raidz2.sh b/zfs/scripts/zpool-config/scsi_debug-raidz2.sh
new file mode 100644 (file)
index 0000000..67a6f24
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/bash
+#
+# 1 scsi_debug device for fault injection and 3 loopback devices
+# on top of which is layered raidz2.
+#
+
+SDSIZE=${SDSIZE:-256}
+SDHOSTS=${SDHOSTS:-1}
+SDTGTS=${SDTGTS:-1}
+SDLUNS=${SDLUNS:-1}
+LDMOD=/sbin/modprobe
+FILEDIR=${FILEDIR:-/var/tmp}
+FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 $FILEDIR/file-vdev2"}
+DEVICES=""
+
+zpool_create() {
+       check_loop_utils
+       check_sd_utils
+
+       test `${LSMOD} | grep -c scsi_debug` -gt 0 &&                        \
+               (echo 0 >/sys/module/scsi_debug/parameters/every_nth &&      \
+               ${RMMOD} scsi_debug || exit 1)
+       udev_trigger
+
+       msg "${LDMOD} scsi_debug dev_size_mb=${SDSIZE} "                     \
+               "add_host=${SDHOSTS} num_tgts=${SDTGTS} "                    \
+               "max_luns=${SDLUNS}"
+       ${LDMOD} scsi_debug                                                  \
+               dev_size_mb=${SDSIZE}                                        \
+               add_host=${SDHOSTS}                                          \
+               num_tgts=${SDTGTS}                                           \
+               max_luns=${SDLUNS} ||                                        \
+               die "Error $? creating scsi_debug devices"
+       udev_trigger
+
+       SDDEVICE=`${LSSCSI} | ${AWK} '/scsi_debug/ { print $6; exit }'`
+       msg "${PARTED} -s ${SDDEVICE} mklabel gpt"
+       ${PARTED} -s ${SDDEVICE} mklabel gpt ||                              \
+               (${RMMOD} scsi_debug && die "Error $? creating gpt label")
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256         \
+                       &>/dev/null || (${RMMOD} scsi_debug &&               \
+                       die "Error $? creating ${FILE}")
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || (${RMMOD} scsi_debug       \
+                       die "Error $? creating ${LODEVICE} using ${FILE}")
+
+               DEVICES="${DEVICES} ${LODEVICE}"
+       done
+
+       DEVICES="${DEVICES} ${SDDEVICE}"
+
+       msg "${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz2 ${DEVICES}"
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz2 ${DEVICES} ||     \
+               (${RMMOD} scsi_debug && exit 1)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               LODEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${LODEVICE} using ${FILE}"
+               ${LOSETUP} -d ${LODEVICE} ||
+                       die "Error $? destroying ${LODEVICE} using ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+
+       msg "${RMMOD} scsi_debug"
+       ${RMMOD} scsi_debug || die "Error $? removing scsi_debug devices"
+}
diff --git a/zfs/scripts/zpool-config/scsi_debug-raidz3.sh b/zfs/scripts/zpool-config/scsi_debug-raidz3.sh
new file mode 100644 (file)
index 0000000..d7ef209
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/bash
+#
+# 1 scsi_debug device for fault injection and 3 loopback devices
+# on top of which is layered raidz3.
+#
+
+SDSIZE=${SDSIZE:-256}
+SDHOSTS=${SDHOSTS:-1}
+SDTGTS=${SDTGTS:-1}
+SDLUNS=${SDLUNS:-1}
+LDMOD=/sbin/modprobe
+FILES="/tmp/zpool-vdev0  \
+       /tmp/zpool-vdev1  \
+       /tmp/zpool-vdev2"
+DEVICES=""
+
+zpool_create() {
+       check_loop_utils
+       check_sd_utils
+
+       test `${LSMOD} | grep -c scsi_debug` -gt 0 &&                        \
+               (echo 0 >/sys/module/scsi_debug/parameters/every_nth &&      \
+               ${RMMOD} scsi_debug || exit 1)
+       udev_trigger
+
+       msg "${LDMOD} scsi_debug dev_size_mb=${SDSIZE} "                     \
+               "add_host=${SDHOSTS} num_tgts=${SDTGTS} "                    \
+               "max_luns=${SDLUNS}"
+       ${LDMOD} scsi_debug                                                  \
+               dev_size_mb=${SDSIZE}                                        \
+               add_host=${SDHOSTS}                                          \
+               num_tgts=${SDTGTS}                                           \
+               max_luns=${SDLUNS} ||                                        \
+               die "Error $? creating scsi_debug devices"
+       udev_trigger
+
+       SDDEVICE=`${LSSCSI} | ${AWK} '/scsi_debug/ { print $6; exit }'`
+       msg "${PARTED} -s ${SDDEVICE} mklabel gpt"
+       ${PARTED} -s ${SDDEVICE} mklabel gpt ||                              \
+               (${RMMOD} scsi_debug && die "Error $? creating gpt label")
+
+       for FILE in ${FILES}; do
+               LODEVICE=`unused_loop_device`
+
+               rm -f ${FILE} || exit 1
+               dd if=/dev/zero of=${FILE} bs=1024k count=0 seek=256         \
+                       &>/dev/null || (${RMMOD} scsi_debug &&               \
+                       die "Error $? creating ${FILE}")
+
+               # Setup the loopback device on the file.
+               msg "Creating ${LODEVICE} using ${FILE}"
+               ${LOSETUP} ${LODEVICE} ${FILE} || (${RMMOD} scsi_debug       \
+                       die "Error $? creating ${LODEVICE} using ${FILE}")
+
+               DEVICES="${DEVICES} ${LODEVICE}"
+       done
+
+       DEVICES="${DEVICES} ${SDDEVICE}"
+
+       msg "${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz3 ${DEVICES}"
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} raidz3 ${DEVICES} ||     \
+               (${RMMOD} scsi_debug && exit 1)
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+
+       for FILE in ${FILES}; do
+               LODEVICE=`${LOSETUP} -a | grep ${FILE} | head -n1|cut -f1 -d:`
+               msg "Removing ${LODEVICE} using ${FILE}"
+               ${LOSETUP} -d ${LODEVICE} ||
+                       die "Error $? destroying ${LODEVICE} using ${FILE}"
+               rm -f ${FILE} || exit 1
+       done
+
+       msg "${RMMOD} scsi_debug"
+       ${RMMOD} scsi_debug || die "Error $? removing scsi_debug devices"
+}
diff --git a/zfs/scripts/zpool-config/sda-raid0.sh b/zfs/scripts/zpool-config/sda-raid0.sh
new file mode 100644 (file)
index 0000000..48dc96d
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Single disk /dev/sda Raid-0 Configuration
+#
+
+DEVICES="/dev/sda"
+
+zpool_create() {
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${DEVICES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME} || exit 1
+}
diff --git a/zfs/scripts/zpool-config/zpool-raid0.sh b/zfs/scripts/zpool-config/zpool-raid0.sh
new file mode 100644 (file)
index 0000000..c757755
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/bash
+#
+# Zpool Raid-0 Configuration
+#
+# This script is used to test with the /dev/disk/by-vdev/[A-Z][1-n] devices.
+# It assumes that you have already populated /dev/disk/by-vdev/ by creating
+# an /etc/zfs/vdev_id.conf file based on your system design.
+#
+# You can then use either the zpool-create.sh or the zpios.sh test script to
+# test various Raid-0 configurations by adjusting the following tunables.
+# For example if you wanted to create and test a single 4-disk Raid-0
+# configuration using disks [A-D]1 with dedicated ZIL and L2ARC devices
+# you could run the following.
+#
+# ZIL="log A2" L2ARC="cache B2" RANKS=1 CHANNELS=4 \
+# zpool-create.sh -c zpool-raid0
+#
+# zpool status tank
+#   pool: tank
+#  state: ONLINE
+#  scan: none requested
+# config:
+# 
+#      NAME        STATE     READ WRITE CKSUM
+#      tank        ONLINE       0     0     0
+#        A1        ONLINE       0     0     0
+#        B1        ONLINE       0     0     0
+#        C1        ONLINE       0     0     0
+#        D1        ONLINE       0     0     0
+#      logs
+#        A2        ONLINE       0     0     0
+#      cache
+#        B2        ONLINE       0     0     0
+#
+# errors: No known data errors
+# 
+
+# Number of interior vdevs to create using the following rank ids.
+RANKS=${RANKS:-1}
+RANK_LIST=( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 )
+
+# Number of devices per vdev using the following channel ids.
+CHANNELS=${CHANNELS:-8}
+CHANNEL_LIST=( A B C D E F G H I J K L M N O P Q R S T U V W X Y Z )
+
+# Create a ZIL vdev as follows.
+ZIL=${ZIL:-}
+
+# Create an L2ARC vdev as follows.
+L2ARC=${L2ARC:-}
+
+
+raid0_setup() {
+        local RANKS=$1
+        local CHANNELS=$2
+
+        RAID0S=()
+       for (( i=0, k=0; i<${RANKS}; i++ )); do
+               RANK=${RANK_LIST[$i]}
+
+               for (( j=0; j<${CHANNELS}; j++, k++ )); do
+                        RAID0S[${k}]="${CHANNEL_LIST[$j]}${RANK}"
+                done
+        done
+
+        return 0
+}
+
+zpool_create() {
+        raid0_setup ${RANKS} ${CHANNELS}
+
+       ZPOOL_DEVICES="${RAID0S[*]} ${ZIL} ${L2ARC}"
+        msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${ZPOOL_DEVICES}
+        ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${ZPOOL_DEVICES} || exit 1
+}
+
+zpool_destroy() {
+        msg ${ZPOOL} destroy ${ZPOOL_NAME}
+        ${ZPOOL} destroy ${ZPOOL_NAME}
+}
diff --git a/zfs/scripts/zpool-config/zpool-raid10.sh b/zfs/scripts/zpool-config/zpool-raid10.sh
new file mode 100644 (file)
index 0000000..d71c4d3
--- /dev/null
@@ -0,0 +1,85 @@
+#!/bin/bash
+#
+# Zpool Raid-10 Configuration
+#
+# This script is used to test with the /dev/disk/by-vdev/[A-Z][1-n] devices.
+# It assumes that you have already populated /dev/disk/by-vdev/ by creating
+# an /etc/zfs/vdev_id.conf file based on your system design.
+#
+# You can then use either the zpool-create.sh or the zpios.sh test script to
+# test various Raid-10 configurations by adjusting the following tunables.
+# For example if you wanted to create and test a single 4-disk Raid-10
+# configuration using disks [A-D]1 with dedicated ZIL and L2ARC devices
+# you could run the following.
+#
+# ZIL="log A2" L2ARC="cache B2" RANKS=1 CHANNELS=4 \
+# zpool-create.sh -c zpool-raid10
+#
+# zpool status tank
+#   pool: tank
+#  state: ONLINE
+#  scan: none requested
+# config:
+# 
+#      NAME        STATE     READ WRITE CKSUM
+#      tank        ONLINE       0     0     0
+#        mirror-0  ONLINE       0     0     0
+#          A1      ONLINE       0     0     0
+#          B1      ONLINE       0     0     0
+#        mirror-1  ONLINE       0     0     0
+#          C1      ONLINE       0     0     0
+#          D1      ONLINE       0     0     0
+#      logs
+#        A2        ONLINE       0     0     0
+#      cache
+#        B2        ONLINE       0     0     0
+#
+# errors: No known data errors
+#
+
+# Number of interior vdevs to create using the following rank ids.
+RANKS=${RANKS:-1}
+RANK_LIST=( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 )
+
+# Number of devices per vdev using the following channel ids.
+CHANNELS=${CHANNELS:-8}
+CHANNEL_LIST=( A B C D E F G H I J K L M N O P Q R S T U V W X Y Z )
+
+# Create a ZIL vdev as follows.
+ZIL=${ZIL:-}
+
+# Create an L2ARC vdev as follows.
+L2ARC=${L2ARC:-}
+
+
+raid10_setup() {
+       local RANKS=$1
+       local CHANNELS=$2
+       local IDX=0
+
+       RAID10S=()
+       for (( i=0, l=0 ; i<${RANKS}; i++ )); do
+               RANK=${RANK_LIST[$i]}
+
+               for (( j=0, k=1; j<${CHANNELS}; j+=2,k+=2,l++ )); do
+                       DISK1="${CHANNEL_LIST[$j]}${RANK}"
+                       DISK2="${CHANNEL_LIST[$k]}${RANK}"
+                       RAID10S[$l]="mirror ${DISK1} ${DISK2}"
+               done
+       done
+
+       return 0
+}
+
+zpool_create() {
+       raid10_setup ${RANKS} ${CHANNELS}
+
+       ZPOOL_DEVICES="${RAID10S[*]} ${ZIL} ${L2ARC}"
+       msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${ZPOOL_DEVICES}
+       ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${ZPOOL_DEVICES} || exit 1
+}
+
+zpool_destroy() {
+       msg ${ZPOOL} destroy ${ZPOOL_NAME}
+       ${ZPOOL} destroy ${ZPOOL_NAME}
+}
diff --git a/zfs/scripts/zpool-config/zpool-raidz.sh b/zfs/scripts/zpool-config/zpool-raidz.sh
new file mode 100644 (file)
index 0000000..b3f21a0
--- /dev/null
@@ -0,0 +1,87 @@
+#!/bin/bash
+#
+# Zpool Raid-Z Configuration
+#
+# This script is used to test with the /dev/disk/by-vdev/[A-Z][1-n] devices.
+# It assumes that you have already populated /dev/disk/by-vdev/ by creating
+# an /etc/zfs/vdev_id.conf file based on your system design.
+#
+# You can then use either the zpool-create.sh or the zpios.sh test script to
+# test various Raid-Z configurations by adjusting the following tunables.
+# For example if you wanted to create and test a single 4-disk Raid-Z2
+# configuration using disks [A-D]1 with dedicated ZIL and L2ARC devices
+# you could run the following.
+#
+# ZIL="log A2" L2ARC="cache B2" RANKS=1 CHANNELS=4 LEVEL=2 \
+# zpool-create.sh -c zpool-raidz
+#
+# zpool status tank
+#   pool: tank
+#  state: ONLINE
+#  scan: none requested
+# config:
+# 
+#      NAME        STATE     READ WRITE CKSUM
+#      tank        ONLINE       0     0     0
+#        raidz2-0  ONLINE       0     0     0
+#          A1      ONLINE       0     0     0
+#          B1      ONLINE       0     0     0
+#          C1      ONLINE       0     0     0
+#          D1      ONLINE       0     0     0
+#      logs
+#        A2        ONLINE       0     0     0
+#      cache
+#        B2        ONLINE       0     0     0
+#  
+# errors: No known data errors
+# 
+
+# Number of interior vdevs to create using the following rank ids.
+RANKS=${RANKS:-1}
+RANK_LIST=( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 )
+
+# Number of devices per vdev using the following channel ids.
+CHANNELS=${CHANNELS:-8}
+CHANNEL_LIST=( A B C D E F G H I J K L M N O P Q R S T U V W X Y Z )
+
+# Raid-Z Level: 1, 2, or 3.
+LEVEL=${LEVEL:-2}
+
+# Create a ZIL vdev as follows.
+ZIL=${ZIL:-}
+
+# Create an L2ARC vdev as follows.
+L2ARC=${L2ARC:-}
+
+
+raidz_setup() {
+        local RANKS=$1
+        local CHANNELS=$2
+
+        RAIDZS=()
+        for (( i=0; i<${RANKS}; i++ )); do
+                RANK=${RANK_LIST[$i]}
+                RAIDZ=("raidz${LEVEL}")
+
+                for (( j=0, k=1; j<${CHANNELS}; j++, k++ )); do
+                        RAIDZ[$k]="${CHANNEL_LIST[$j]}${RANK}"
+                done
+
+                RAIDZS[$i]="${RAIDZ[*]}"
+        done
+
+        return 0
+}
+
+zpool_create() {
+        raidz_setup ${RANKS} ${CHANNELS}
+
+       ZPOOL_DEVICES="${RAIDZS[*]} ${ZIL} ${L2ARC}"
+        msg ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${ZPOOL_DEVICES}
+        ${ZPOOL} create ${ZPOOL_FLAGS} ${ZPOOL_NAME} ${ZPOOL_DEVICES} || exit 1
+}
+
+zpool_destroy() {
+        msg ${ZPOOL} destroy ${ZPOOL_NAME}
+        ${ZPOOL} destroy ${ZPOOL_NAME}
+}
diff --git a/zfs/scripts/zpool-create.sh b/zfs/scripts/zpool-create.sh
new file mode 100755 (executable)
index 0000000..16ee671
--- /dev/null
@@ -0,0 +1,139 @@
+#!/bin/bash
+
+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=zpool-create.sh
+
+usage() {
+cat << EOF
+USAGE:
+$0 [hvfxcp]
+
+DESCRIPTION:
+        Create one of several predefined zpool configurations.
+
+OPTIONS:
+        -h      Show this message
+        -v      Verbose
+        -f      Force everything
+        -x      Disable all zpool features
+        -c      Configuration for zpool
+        -p      Name for zpool
+        -d      Destroy zpool (default create)
+        -l      Additional zpool options
+        -s      Additional zfs options
+
+EOF
+}
+
+check_config() {
+
+       if [ ! -f ${ZPOOL_CONFIG} ]; then
+               local NAME=`basename ${ZPOOL_CONFIG} .sh`
+               ERROR="Unknown config '${NAME}', available configs are:\n"
+
+               for CFG in `ls ${ZPOOLDIR}/ | grep ".sh"`; do
+                       local NAME=`basename ${CFG} .sh`
+                       ERROR="${ERROR}${NAME}\n"
+               done
+
+               return 1
+       fi
+
+       return 0
+}
+
+ZPOOL_CONFIG=unknown
+ZPOOL_NAME=tank
+ZPOOL_DESTROY=
+ZPOOL_FLAGS=${ZPOOL_FLAGS:-""}
+ZPOOL_OPTIONS=""
+ZFS_OPTIONS=""
+
+while getopts 'hvfxc:p:dl:s:' OPTION; do
+       case $OPTION in
+       h)
+               usage
+               exit 1
+               ;;
+       v)
+               VERBOSE=1
+               VERBOSE_FLAG="-v"
+               ;;
+       f)
+               FORCE=1
+               ZPOOL_FLAGS="$ZPOOL_FLAGS -f"
+               ;;
+       x)
+               NO_FEATURES=1
+               ZPOOL_FLAGS="$ZPOOL_FLAGS -d"
+               ;;
+       c)
+               ZPOOL_CONFIG=${ZPOOLDIR}/${OPTARG}.sh
+               ;;
+       p)
+               ZPOOL_NAME=${OPTARG}
+               ;;
+       d)
+               ZPOOL_DESTROY=1
+               ;;
+       l)
+               ZPOOL_OPTIONS=${OPTARG}
+               ;;
+       s)
+               ZFS_OPTIONS=${OPTARG}
+               ;;
+       ?)
+               usage
+               exit 1
+               ;;
+       esac
+done
+
+if [ $(id -u) != 0 ]; then
+        die "Must run as root"
+fi
+
+check_config || die "${ERROR}"
+. ${ZPOOL_CONFIG}
+
+if [ ${ZPOOL_DESTROY} ]; then
+       zpool_destroy
+else
+       zpool_create
+
+       if [ "${ZPOOL_OPTIONS}" ]; then
+               if [ ${VERBOSE} ]; then
+                       echo
+                       echo "${ZPOOL} ${ZPOOL_OPTIONS} ${ZPOOL_NAME}"
+               fi
+               ${ZPOOL} ${ZPOOL_OPTIONS} ${ZPOOL_NAME} || exit 1
+       fi
+
+       if [ "${ZFS_OPTIONS}" ]; then
+               if [ ${VERBOSE} ]; then
+                       echo
+                       echo "${ZFS} ${ZFS_OPTIONS} ${ZPOOL_NAME}"
+               fi
+               ${ZFS} ${ZFS_OPTIONS} ${ZPOOL_NAME} || exit 1
+       fi
+
+       if [ ${VERBOSE} ]; then
+               echo
+               echo "zpool list"
+               ${ZPOOL} list || exit 1
+
+               echo
+               echo "zpool status ${ZPOOL_NAME}"
+               ${ZPOOL} status ${ZPOOL_NAME} || exit 1
+       fi
+fi
+
+exit 0
diff --git a/zfs/tests/Makefile.am b/zfs/tests/Makefile.am
new file mode 100644 (file)
index 0000000..28d6e95
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = runfiles test-runner zfs-tests
diff --git a/zfs/tests/README.md b/zfs/tests/README.md
new file mode 100644 (file)
index 0000000..18bdd05
--- /dev/null
@@ -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
diff --git a/zfs/tests/runfiles/Makefile.am b/zfs/tests/runfiles/Makefile.am
new file mode 100644 (file)
index 0000000..cddfb2e
--- /dev/null
@@ -0,0 +1,2 @@
+pkgdatadir = $(datadir)/@PACKAGE@/runfiles
+dist_pkgdata_SCRIPTS = *.run
diff --git a/zfs/tests/runfiles/linux.run b/zfs/tests/runfiles/linux.run
new file mode 100644 (file)
index 0000000..9d63d68
--- /dev/null
@@ -0,0 +1,638 @@
+#
+# 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: update to use ZFS_ACL_* variables and user_run helper.
+# posix_001_pos
+# posix_002_pos
+[tests/functional/acl/posix]
+tests = ['posix_003_pos']
+
+[tests/functional/atime]
+tests = ['atime_001_pos', 'atime_002_neg', 'atime_003_pos']
+
+# 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/checksum]
+tests = ['run_edonr_test', 'run_sha2_test', 'run_skein_test', 'filetest_001_pos']
+
+[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
+[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',
+    'zfs_clone_010_pos']
+
+# DISABLED:
+# 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_002_pos', 'zfs_copies_004_neg',
+    'zfs_copies_006_pos']
+
+[tests/functional/cli_root/zfs_create]
+tests = ['zfs_create_001_pos', 'zfs_create_002_pos', 'zfs_create_003_pos',
+    'zfs_create_004_pos', 'zfs_create_005_pos', 'zfs_create_006_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_005_neg - busy mountpoint behavior
+[tests/functional/cli_root/zfs_destroy]
+tests = ['zfs_destroy_001_pos', 'zfs_destroy_002_pos', 'zfs_destroy_003_pos',
+    'zfs_destroy_004_pos','zfs_destroy_006_neg', 'zfs_destroy_007_neg',
+    'zfs_destroy_008_pos','zfs_destroy_009_pos', 'zfs_destroy_010_pos',
+    'zfs_destroy_011_pos','zfs_destroy_012_pos', 'zfs_destroy_013_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_006_pos - needs investigation
+# zfs_mount_007_pos - needs investigation
+# zfs_mount_009_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_005_pos', 'zfs_mount_008_pos',
+    'zfs_mount_010_neg', '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_004_neg - Fails for OpenZFS on illumos
+[tests/functional/cli_root/zfs_receive]
+tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
+    'zfs_receive_005_neg', 'zfs_receive_006_pos',
+    'zfs_receive_007_neg', 'zfs_receive_008_pos', 'zfs_receive_009_neg',
+    'zfs_receive_010_pos', 'zfs_receive_011_pos', 'zfs_receive_012_pos',
+    'zfs_receive_013_pos']
+
+[tests/functional/cli_root/zfs_rename]
+tests = ['zfs_rename_001_pos', 'zfs_rename_002_pos', 'zfs_rename_003_pos',
+    'zfs_rename_004_neg', 'zfs_rename_005_neg', 'zfs_rename_006_pos',
+    'zfs_rename_007_pos', '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']
+
+[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',
+    'zfs_send_007_pos']
+
+# DISABLED:
+# mountpoint_003_pos - needs investigation
+# ro_props_001_pos - https://github.com/zfsonlinux/zfs/issues/5201
+# 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', 'onoffs_001_pos',
+    'user_property_001_pos', 'user_property_003_neg', 'readonly_001_pos',
+    'user_property_004_pos', 'version_001_neg', 'zfs_set_001_neg',
+    'zfs_set_002_neg', 'zfs_set_003_neg', 'property_alias_001_pos']
+
+# 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']
+
+[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_008_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_004_pos - nested pools
+# 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_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_024_pos',
+    'zpool_create_features_001_pos', 'zpool_create_features_002_pos',
+    'zpool_create_features_003_pos', 'zpool_create_features_004_neg',
+    'zpool_create_features_005_pos']
+
+# 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_002_pos - https://github.com/zfsonlinux/zfs/issues/5202
+# zpool_import_012_pos - sharenfs issue
+# zpool_import_all_001_pos - partition issue
+[tests/functional/cli_root/zpool_import]
+tests = ['zpool_import_001_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',
+    'zpool_import_features_001_pos', 'zpool_import_features_002_neg',
+    'zpool_import_features_003_pos','zpool_import_missing_001_pos',
+    'zpool_import_missing_002_pos', 'zpool_import_missing_003_pos',
+    'zpool_import_rename_001_pos']
+
+[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']
+
+[tests/functional/cli_root/zpool_scrub]
+tests = ['zpool_scrub_001_neg', 'zpool_scrub_002_pos', 'zpool_scrub_003_pos',
+    'zpool_scrub_004_pos', 'zpool_scrub_005_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:
+# zpool_upgrade_002_pos - Issue zfsonlinux/zfs#4034
+# zpool_upgrade_004_pos - Issue zfsonlinux/zfs#4034
+# zpool_upgrade_007_pos - needs investigation
+[tests/functional/cli_root/zpool_upgrade]
+tests = ['zpool_upgrade_001_pos',
+    'zpool_upgrade_003_pos', 'zpool_upgrade_005_neg',
+    'zpool_upgrade_006_neg', 'zpool_upgrade_008_pos',
+    'zpool_upgrade_009_neg']
+
+# DISABLED:
+# zfs_share_001_neg - requires additional dependencies
+# zfs_unshare_001_neg - requires additional dependencies
+[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_snapshot_001_neg', 'zfs_unallow_001_neg',
+    'zfs_unmount_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', 'arcstat_001_pos',
+    'arc_summary_001_pos', 'dbufstat_001_pos']
+user =
+
+[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']
+user =
+
+[tests/functional/cli_user/zpool_iostat]
+tests = ['zpool_iostat_001_neg', 'zpool_iostat_002_pos',
+    'zpool_iostat_003_neg', 'zpool_iostat_004_pos']
+user =
+
+[tests/functional/cli_user/zpool_list]
+tests = ['zpool_list_001_pos', 'zpool_list_002_neg']
+user =
+
+[tests/functional/compression]
+tests = ['compress_001_pos', 'compress_002_pos', 'compress_003_pos',
+    'compress_004_pos']
+
+[tests/functional/ctime]
+tests = ['ctime_001_pos' ]
+
+[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']
+
+[tests/functional/features/large_dnode]
+tests = ['large_dnode_001_pos', 'large_dnode_002_pos', 'large_dnode_003_pos',
+         'large_dnode_004_neg', 'large_dnode_005_pos', 'large_dnode_006_pos',
+         'large_dnode_007_neg']
+
+# 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 =
+
+[tests/functional/history]
+tests = ['history_001_pos', 'history_002_pos', 'history_003_pos',
+    'history_004_pos', 'history_005_neg', 'history_006_neg',
+    'history_007_pos', 'history_008_pos', 'history_009_pos',
+    'history_010_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:
+# nopwrite_varying_compression - needs investigation
+[tests/functional/nopwrite]
+tests = ['nopwrite_copies', 'nopwrite_mtime', 'nopwrite_negative',
+    'nopwrite_promoted_clone', 'nopwrite_recsize', 'nopwrite_sync',
+    'nopwrite_volume']
+
+# 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']
+
+[tests/functional/quota]
+tests = ['quota_001_pos', 'quota_002_pos', 'quota_003_pos',
+         'quota_004_pos', 'quota_005_pos', 'quota_006_neg']
+
+[tests/functional/raidz]
+tests = ['raidz_001_neg', 'raidz_002_pos']
+
+[tests/functional/redundancy]
+tests = ['redundancy_001_pos', 'redundancy_002_pos', 'redundancy_003_pos']
+
+[tests/functional/refquota]
+tests = ['refquota_001_pos', 'refquota_002_pos', 'refquota_003_pos',
+    'refquota_004_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']
+
+[tests/functional/replacement]
+tests = ['replacement_001_pos', 'replacement_002_pos', 'replacement_003_pos']
+
+[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_012_pos',
+    'reservation_013_pos', 'reservation_014_pos', 'reservation_015_pos',
+    'reservation_016_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:
+# rsend_008_pos - Fails for OpenZFS on illumos
+# rsend_009_pos - Fails for OpenZFS on illumos
+# rsend_020_pos - ASSERTs in dump_record()
+[tests/functional/rsend]
+tests = ['rsend_001_pos', 'rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos',
+    'rsend_005_pos', 'rsend_006_pos', 'rsend_007_pos',
+    'rsend_010_pos', 'rsend_011_pos', 'rsend_012_pos',
+    'rsend_013_pos', 'rsend_014_pos',
+    'rsend_019_pos',
+    'rsend_021_pos', 'rsend_022_pos', 'rsend_024_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:
+# clone_001_pos - nested pools
+# rollback_003_pos - Hangs in unmount and spins.
+# snapshot_016_pos - Problem with automount
+[tests/functional/snapshot]
+tests = ['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_013_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']
+
+[tests/functional/upgrade]
+tests = [ 'upgrade_userobj_001_pos' ]
+
+[tests/functional/userquota]
+tests = [
+    'userquota_001_pos', 'userquota_002_pos', 'userquota_003_pos',
+    'userquota_004_pos', 'userquota_005_neg', 'userquota_006_pos',
+    'userquota_007_pos', 'userquota_008_pos', 'userquota_009_pos',
+    'userquota_010_pos', 'userquota_011_pos', 'userquota_012_neg',
+    'userquota_013_pos',
+    'userspace_001_pos', 'userspace_002_pos', 'userspace_003_pos',
+    'groupspace_001_pos', 'groupspace_002_pos', 'groupspace_003_pos' ]
+
+# DISABLED:
+# vdev_zaps_007_pos -- fails due to a pre-existing issue with zpool split
+#
+[tests/functional/vdev_zaps]
+tests = ['vdev_zaps_001_pos', 'vdev_zaps_002_pos', 'vdev_zaps_003_pos',
+    'vdev_zaps_004_pos', 'vdev_zaps_005_pos', 'vdev_zaps_006_pos']
+
+# 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']
diff --git a/zfs/tests/runfiles/perf-regression.run b/zfs/tests/runfiles/perf-regression.run
new file mode 100644 (file)
index 0000000..95df3f2
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+[DEFAULT]
+pre = setup
+quiet = False
+pre_user = root
+user = root
+timeout = 0
+post_user = root
+post = cleanup
+outputdir = /var/tmp/test_results
+
+[tests/perf/regression]
+tests = ['sequential_writes', 'sequential_reads', 'sequential_reads_cached',
+    'sequential_reads_cached_clone', 'random_reads', 'random_writes',
+    'random_readwrite']
+post =
diff --git a/zfs/tests/test-runner/Makefile.am b/zfs/tests/test-runner/Makefile.am
new file mode 100644 (file)
index 0000000..6a0d9ec
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = cmd include man
diff --git a/zfs/tests/test-runner/cmd/Makefile.am b/zfs/tests/test-runner/cmd/Makefile.am
new file mode 100644 (file)
index 0000000..223622d
--- /dev/null
@@ -0,0 +1,3 @@
+pkgdatadir = $(datadir)/@PACKAGE@/test-runner/bin
+dist_pkgdata_SCRIPTS = \
+       test-runner.py
diff --git a/zfs/tests/test-runner/cmd/test-runner.py b/zfs/tests/test-runner/cmd/test-runner.py
new file mode 100755 (executable)
index 0000000..d7727e8
--- /dev/null
@@ -0,0 +1,882 @@
+#!/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 maxint
+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
+        self.user = user or ''
+        self.killed = False
+        self.result = Result()
+
+        if self.timeout is None:
+            self.timeout = 60
+
+    def __str__(self):
+        return "Pathname: %s\nOutputdir: %s\nTimeout: %d\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:
+            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'
+            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)
+
+        self.result.starttime = time()
+        proc = Popen(privcmd, stdout=PIPE, stderr=PIPE)
+        # Allow a special timeout value of 0 to mean infinity
+        if int(self.timeout) == 0:
+            self.timeout = maxint
+        t = Timer(int(self.timeout), self.kill_cmd, [proc])
+
+        try:
+            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: %d\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: %d\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 uniq not 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)
+        # make a symlink to the output for the currently running test
+        logsymlink = os.path.join(self.outputdir, '../current')
+        if os.path.islink(logsymlink):
+            os.unlink(logsymlink)
+        if not os.path.exists(logsymlink):
+            os.symlink(self.outputdir, logsymlink)
+        else:
+            print 'Could not make a symlink 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
+
+    for ext in '', '.ksh', '.sh':
+        script_path = pathname + ext
+        if os.path.isfile(script_path) and os.access(script_path, 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]
+
+    if user in Cmd.verified_users:
+        return True
+
+    try:
+        getpwnam(user)
+    except KeyError:
+        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:])
diff --git a/zfs/tests/test-runner/include/Makefile.am b/zfs/tests/test-runner/include/Makefile.am
new file mode 100644 (file)
index 0000000..d071dd4
--- /dev/null
@@ -0,0 +1,4 @@
+pkgdatadir = $(datadir)/@PACKAGE@/test-runner/include
+dist_pkgdata_SCRIPTS = \
+       logapi.shlib \
+       stf.shlib
diff --git a/zfs/tests/test-runner/include/logapi.shlib b/zfs/tests/test-runner/include/logapi.shlib
new file mode 100644 (file)
index 0000000..b970e4e
--- /dev/null
@@ -0,0 +1,460 @@
+#!/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 positive test but retry the command on failure if the output
+# matches an expected pattern.  Otherwise behave like log_must and exit
+# $STF_FAIL is test fails.
+#
+# $1 - retry keyword
+# $2 - retry attempts
+# $3-$@ - command to execute
+#
+function log_must_retry
+{
+       typeset out=""
+       typeset logfile="/tmp/log.$$"
+       typeset status=1
+       typeset expect=$1
+       typeset retry=$2
+       typeset delay=1
+       shift 2
+
+       while [[ -e $logfile ]]; do
+               logfile="$logfile.$$"
+       done
+
+       while (( $retry > 0 )); do
+               "$@" 2>$logfile
+               status=$?
+               out="$CAT $logfile"
+
+               if (( $status == 0 )); then
+                       $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
+                       break
+               else
+                       $out | $GREP -i "$expect" > /dev/null 2>&1
+                       if (( $? == 0 )); then
+                               print -u2 $($out)
+                               _printerror "$@" "Retry in $delay seconds"
+                               $SLEEP $delay
+
+                               (( retry=retry - 1 ))
+                               (( delay=delay * 2 ))
+                       else
+                               break;
+                       fi
+               fi
+       done
+
+       if (( $status != 0 )) ; then
+               print -u2 $($out)
+               _printerror "$@" "exited $status"
+       fi
+
+       _recursive_output $logfile "false"
+       return $status
+}
+
+# Execute a positive test and exit $STF_FAIL is test fails after being
+# retried up to 5 times when the command returns the keyword "busy".
+#
+# $@ - command to execute
+function log_must_busy
+{
+       log_must_retry "busy" 5 "$@"
+       (( $? != 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
+}
diff --git a/zfs/tests/test-runner/include/stf.shlib b/zfs/tests/test-runner/include/stf.shlib
new file mode 100644 (file)
index 0000000..ea879a8
--- /dev/null
@@ -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" )
diff --git a/zfs/tests/test-runner/man/Makefile.am b/zfs/tests/test-runner/man/Makefile.am
new file mode 100644 (file)
index 0000000..a7017f5
--- /dev/null
@@ -0,0 +1,4 @@
+dist_man_MANS = test-runner.1
+
+install-data-local:
+       $(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man1"
diff --git a/zfs/tests/test-runner/man/test-runner.1 b/zfs/tests/test-runner/man/test-runner.1
new file mode 100644 (file)
index 0000000..31cd412
--- /dev/null
@@ -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)
diff --git a/zfs/tests/zfs-tests/Makefile.am b/zfs/tests/zfs-tests/Makefile.am
new file mode 100644 (file)
index 0000000..8617034
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = cmd include tests
diff --git a/zfs/tests/zfs-tests/cmd/Makefile.am b/zfs/tests/zfs-tests/cmd/Makefile.am
new file mode 100644 (file)
index 0000000..f55ff8c
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/chg_usr_exec/Makefile.am b/zfs/tests/zfs-tests/cmd/chg_usr_exec/Makefile.am
new file mode 100644 (file)
index 0000000..6f2968f
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/chg_usr_exec/chg_usr_exec.c b/zfs/tests/zfs-tests/cmd/chg_usr_exec/chg_usr_exec.c
new file mode 100644 (file)
index 0000000..1fa9e88
--- /dev/null
@@ -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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/devname2devid/Makefile.am b/zfs/tests/zfs-tests/cmd/devname2devid/Makefile.am
new file mode 100644 (file)
index 0000000..a8991bb
--- /dev/null
@@ -0,0 +1,9 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+if WANT_DEVNAME2DEVID
+pkgexec_PROGRAMS = devname2devid
+devname2devid_SOURCES = devname2devid.c
+devname2devid_LDADD = -ludev
+endif
diff --git a/zfs/tests/zfs-tests/cmd/devname2devid/devname2devid.c b/zfs/tests/zfs-tests/cmd/devname2devid/devname2devid.c
new file mode 100644 (file)
index 0000000..59fbcdd
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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) 2016, Intel Corporation.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <libudev.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+/*
+ * Linux persistent device strings for vdev labels
+ *
+ * based on udev_device_get_devid() at zfs/lib/libzfs/libzfs_import.c
+ */
+
+#define        DEV_BYID_PATH   "/dev/disk/by-id/"
+
+static int
+udev_device_get_devid(struct udev_device *dev, char *bufptr, size_t buflen)
+{
+       struct udev_list_entry *entry;
+       const char *bus;
+       char devbyid[MAXPATHLEN];
+
+       /* The bus based by-id path is preferred */
+       bus = udev_device_get_property_value(dev, "ID_BUS");
+
+       if (bus == NULL) {
+               const char *dm_uuid;
+
+               /*
+                * For multipath nodes use the persistent uuid based identifier
+                *
+                * Example: 'dm-uuid-mpath-35000c5006304de3f'
+                */
+               dm_uuid = udev_device_get_property_value(dev, "DM_UUID");
+               if (dm_uuid != NULL) {
+                       (void) snprintf(bufptr, buflen, "dm-uuid-%s", dm_uuid);
+                       return (0);
+               }
+               return (ENODATA);
+       }
+
+       /*
+        * locate the bus specific by-id link
+        *
+        * Example: 'scsi-MG03SCA300_350000494a8cb3d67-part1'
+        */
+       (void) snprintf(devbyid, sizeof (devbyid), "%s%s-", DEV_BYID_PATH, bus);
+       entry = udev_device_get_devlinks_list_entry(dev);
+       while (entry != NULL) {
+               const char *name;
+
+               name = udev_list_entry_get_name(entry);
+               if (strncmp(name, devbyid, strlen(devbyid)) == 0) {
+                       name += strlen(DEV_BYID_PATH);
+                       (void) stpncpy(bufptr, name, buflen);
+                       return (0);
+               }
+               entry = udev_list_entry_get_next(entry);
+       }
+
+       return (ENODATA);
+}
+
+/*
+ * Usage: devname2devid <devicepath>
+ *
+ * Examples:
+ * # ./devname2devid /dev/sda1
+ * devid scsi-350000394a8caede4-part1
+ *
+ * # ./devname2devid /dev/dm-1
+ * devid: 'dm-uuid-mpath-35000c5006304de3f'
+ *
+ * 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[])
+{
+       struct udev *udev;
+       struct udev_device *dev = NULL;
+       char devid[128], nodepath[MAXPATHLEN];
+       char *device, *sysname;
+       int ret;
+
+       if (argc == 1) {
+               (void) printf("%s <devicepath> [search path]\n", argv[0]);
+               exit(1);
+       }
+       device = argv[1];
+
+       if ((udev = udev_new()) == NULL) {
+               perror("udev_new");
+               exit(1);
+       }
+
+       /* resolve path to a runtime device node instance */
+       if (realpath(device, nodepath) == NULL) {
+               perror("realpath");
+               exit(1);
+       }
+       sysname = strrchr(nodepath, '/') + 1;
+
+       if ((dev = udev_device_new_from_subsystem_sysname(udev, "block",
+           sysname)) == NULL) {
+               perror(sysname);
+               exit(1);
+       }
+
+       if ((ret = udev_device_get_devid(dev, devid, sizeof (devid))) != 0) {
+               udev_device_unref(dev);
+               errno = ret;
+               perror(sysname);
+               exit(1);
+       }
+
+       (void) printf("devid %s\n", devid);
+
+       udev_device_unref(dev);
+       udev_unref(udev);
+
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/cmd/dir_rd_update/Makefile.am b/zfs/tests/zfs-tests/cmd/dir_rd_update/Makefile.am
new file mode 100644 (file)
index 0000000..27cc9e9
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/dir_rd_update/dir_rd_update.c b/zfs/tests/zfs-tests/cmd/dir_rd_update/dir_rd_update.c
new file mode 100644 (file)
index 0000000..6434854
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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];
+       if (strlen(cp1) >= (sizeof (dirpath) - strlen("TMP_DIR"))) {
+               (void) printf("The string length of mount point is "
+                       "too large\n");
+               exit(-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;
+
+               if (fd < 0) {
+                       (void) printf("%s: open <%s> again failed:"
+                           " errno = %d\n", argv[0], dirpath, errno);
+                       exit(-1);
+               }
+
+               while (j < op_num) {
+                       (void) sleep(1);
+                       rdret = read(fd, buf, 16);
+                       if (rdret == -1) {
+                               (void) printf("readdir failed");
+                       }
+                       j++;
+               }
+               (void) close(fd);
+       } else if (pid == 0) {
+               int fd = open(dirpath, O_RDONLY);
+               int chownret;
+               int k = 0;
+
+               if (fd < 0) {
+                       (void) printf("%s: open(<%s>, O_RDONLY) again failed:"
+                           " errno (decimal)=%d\n", argv[0], dirpath, errno);
+                       exit(-1);
+               }
+
+               while (k < op_num) {
+                       (void) sleep(1);
+                       chownret = fchown(fd, 0, 0);
+                       if (chownret == -1) {
+                               (void) printf("chown failed");
+                       }
+
+                       k++;
+               }
+               (void) close(fd);
+       }
+
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/cmd/file_check/Makefile.am b/zfs/tests/zfs-tests/cmd/file_check/Makefile.am
new file mode 100644 (file)
index 0000000..13027ef
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/file_check/file_check.c b/zfs/tests/zfs-tests/cmd/file_check/file_check.c
new file mode 100644 (file)
index 0000000..5df0ea7
--- /dev/null
@@ -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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/file_common.h b/zfs/tests/zfs-tests/cmd/file_common.h
new file mode 100644 (file)
index 0000000..759889e
--- /dev/null
@@ -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 */
diff --git a/zfs/tests/zfs-tests/cmd/file_trunc/Makefile.am b/zfs/tests/zfs-tests/cmd/file_trunc/Makefile.am
new file mode 100644 (file)
index 0000000..0455eb4
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/file_trunc/file_trunc.c b/zfs/tests/zfs-tests/cmd/file_trunc/file_trunc.c
new file mode 100644 (file)
index 0000000..38e36c9
--- /dev/null
@@ -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));
+       }
+}
diff --git a/zfs/tests/zfs-tests/cmd/file_write/Makefile.am b/zfs/tests/zfs-tests/cmd/file_write/Makefile.am
new file mode 100644 (file)
index 0000000..6089571
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/file_write/file_write.c b/zfs/tests/zfs-tests/cmd/file_write/file_write.c
new file mode 100644 (file)
index 0000000..81fc5de
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * 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>
+#include <stdlib.h>
+#include <time.h>
+#include <stdint.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 *);
+
+/*
+ * psudo-randomize the buffer
+ */
+void randomize_buffer(int block_size) {
+       int i;
+       char rnd = rand() & 0xff;
+       for (i = 0; i < block_size; i++)
+               bigbuffer[i] ^= rnd;
+}
+
+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':
+                               if (optarg[0] == 'R')
+                                       fillchar = 'R'; /* R = random data */
+                               else
+                                       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); /* no return */
+               return (1);
+       }
+
+       /*
+        * Prepare the buffer and determine the requested operation
+        */
+       nxtfillchar = fillchar;
+       k = 0;
+
+       if (fillchar == 'R')
+               srand(time(NULL));
+
+       for (i = 0; i < block_size; i++) {
+               bigbuffer[i] = nxtfillchar;
+
+               if (fillchar == 0) {
+                       if ((k % DATA_RANGE) == 0) {
+                               k = 0;
+                       }
+                       nxtfillchar = k++;
+               } else if (fillchar == 'R') {
+                       nxtfillchar = rand() & 0xff;
+               }
+       }
+
+       /*
+        * 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, ", filename, block_size,
+                   write_count, offset);
+               if (fillchar == 'R') {
+                       (void) printf("data = [random]\n");
+               } else {
+                       (void) printf("data = %s%d\n",
+                           (fillchar == 0) ? "0->" : "",
+                           (fillchar == 0) ? DATA_RANGE : fillchar);
+               }
+       }
+
+       for (i = 0; i < write_count; i++) {
+               ssize_t n;
+               if (fillchar == 'R')
+                       randomize_buffer(block_size);
+
+               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\n"
+           "Where [data] equal to zero causes chars "
+           "0->%d to be repeated throughout, or [data]\n"
+           "equal to 'R' for psudorandom data.\n",
+           prog, DATA_RANGE);
+
+       exit(1);
+}
diff --git a/zfs/tests/zfs-tests/cmd/largest_file/Makefile.am b/zfs/tests/zfs-tests/cmd/largest_file/Makefile.am
new file mode 100644 (file)
index 0000000..a3e4e93
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/largest_file/largest_file.c b/zfs/tests/zfs-tests/cmd/largest_file/largest_file.c
new file mode 100644 (file)
index 0000000..286232d
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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] = "aaaa\0";
+       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) {
+               err = errno;
+               perror("Failed to create testfile");
+               free(testfile);
+               return (err);
+       }
+
+       llseek_ret = lseek64(fd, offset, SEEK_SET);
+       if (llseek_ret < 0) {
+               err = errno;
+               perror("Failed to seek to end of testfile");
+               goto out;
+       }
+
+       write_ret = write(fd, mybuf, 1);
+       if (write_ret < 0) {
+               err = errno;
+               perror("Failed to write to end of file");
+               goto out;
+       }
+
+       offset = 0;
+       llseek_ret = lseek64(fd, offset, SEEK_CUR);
+       if (llseek_ret < 0) {
+               err = errno;
+               perror("Failed to seek to end of file");
+               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 {
+                       err = errno;
+                       perror("Did not receive EFBIG");
+               }
+       } else {
+               (void) printf("write completed successfully, test failed\n");
+               err = 1;
+       }
+
+out:
+       (void) unlink(testfile);
+       free(testfile);
+       close(fd);
+       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");
+}
diff --git a/zfs/tests/zfs-tests/cmd/mkbusy/Makefile.am b/zfs/tests/zfs-tests/cmd/mkbusy/Makefile.am
new file mode 100644 (file)
index 0000000..abae69d
--- /dev/null
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+pkgexec_PROGRAMS = mkbusy
+mkbusy_SOURCES = mkbusy.c
diff --git a/zfs/tests/zfs-tests/cmd/mkbusy/mkbusy.c b/zfs/tests/zfs-tests/cmd/mkbusy/mkbusy.c
new file mode 100644 (file)
index 0000000..1e45674
--- /dev/null
@@ -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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/mkfile/Makefile.am b/zfs/tests/zfs-tests/cmd/mkfile/Makefile.am
new file mode 100644 (file)
index 0000000..016c671
--- /dev/null
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+pkgexec_PROGRAMS = mkfile
+mkfile_SOURCES = mkfile.c
diff --git a/zfs/tests/zfs-tests/cmd/mkfile/mkfile.c b/zfs/tests/zfs-tests/cmd/mkfile/mkfile.c
new file mode 100644 (file)
index 0000000..4e0be93
--- /dev/null
@@ -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 */
+}
diff --git a/zfs/tests/zfs-tests/cmd/mkfiles/Makefile.am b/zfs/tests/zfs-tests/cmd/mkfiles/Makefile.am
new file mode 100644 (file)
index 0000000..54c2159
--- /dev/null
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+pkgexec_PROGRAMS = mkfiles
+mkfiles_SOURCES = mkfiles.c
diff --git a/zfs/tests/zfs-tests/cmd/mkfiles/mkfiles.c b/zfs/tests/zfs-tests/cmd/mkfiles/mkfiles.c
new file mode 100644 (file)
index 0000000..62dee16
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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);
+
+       for (i = first_file; i < first_file + 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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/mktree/Makefile.am b/zfs/tests/zfs-tests/cmd/mktree/Makefile.am
new file mode 100644 (file)
index 0000000..88c74ae
--- /dev/null
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+pkgexec_PROGRAMS = mktree
+mktree_SOURCES = mktree.c
diff --git a/zfs/tests/zfs-tests/cmd/mktree/mktree.c b/zfs/tests/zfs-tests/cmd/mktree/mktree.c
new file mode 100644 (file)
index 0000000..95d31a6
--- /dev/null
@@ -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, "user.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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/mmap_exec/Makefile.am b/zfs/tests/zfs-tests/cmd/mmap_exec/Makefile.am
new file mode 100644 (file)
index 0000000..ab9f81b
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/mmap_exec/mmap_exec.c b/zfs/tests/zfs-tests/cmd/mmap_exec/mmap_exec.c
new file mode 100644 (file)
index 0000000..6a48a9c
--- /dev/null
@@ -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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/mmapwrite/Makefile.am b/zfs/tests/zfs-tests/cmd/mmapwrite/Makefile.am
new file mode 100644 (file)
index 0000000..b21b9e7
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/mmapwrite/mmapwrite.c b/zfs/tests/zfs-tests/cmd/mmapwrite/mmapwrite.c
new file mode 100644 (file)
index 0000000..190d31a
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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 <string.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[1024];
+       pthread_t tid;
+
+       memset(buf, 'a', sizeof (buf));
+
+       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");
+               close(fd);
+               exit(1);
+       }
+       for (;;) {
+               if (write(fd, buf, sizeof (buf)) == -1) {
+                       perror("write");
+                       close(fd);
+                       exit(1);
+               }
+       }
+
+       close(fd);
+
+       /* NOTREACHED */
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/cmd/randfree_file/Makefile.am b/zfs/tests/zfs-tests/cmd/randfree_file/Makefile.am
new file mode 100644 (file)
index 0000000..6306e0e
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/randfree_file/randfree_file.c b/zfs/tests/zfs-tests/cmd/randfree_file/randfree_file.c
new file mode 100644 (file)
index 0000000..c708d64
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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 <string.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 = NULL;
+       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]);
+
+       if ((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, mode)) < 0) {
+               perror("open");
+               return (1);
+       }
+
+       buf = (char *)calloc(1, filesize);
+       if (buf == NULL) {
+               perror("write");
+               close(fd);
+               return (1);
+       }
+       memset(buf, 'c', filesize);
+
+       if (write(fd, buf, filesize) < filesize) {
+               free(buf);
+               perror("write");
+               close(fd);
+               return (1);
+       }
+
+       free(buf);
+
+#if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
+       if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+           start_off, off_len) < 0) {
+               perror("fallocate");
+               close(fd);
+               return (1);
+       }
+#else /* !(defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)) */
+       {
+               perror("FALLOC_FL_PUNCH_HOLE unsupported");
+               close(fd);
+               return (1);
+       }
+#endif /* defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE) */
+       close(fd);
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/cmd/readmmap/Makefile.am b/zfs/tests/zfs-tests/cmd/readmmap/Makefile.am
new file mode 100644 (file)
index 0000000..9b735c2
--- /dev/null
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+pkgexec_PROGRAMS = readmmap
+readmmap_SOURCES = readmmap.c
diff --git a/zfs/tests/zfs-tests/cmd/readmmap/readmmap.c b/zfs/tests/zfs-tests/cmd/readmmap/readmmap.c
new file mode 100644 (file)
index 0000000..e21c2c8
--- /dev/null
@@ -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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/rename_dir/Makefile.am b/zfs/tests/zfs-tests/cmd/rename_dir/Makefile.am
new file mode 100644 (file)
index 0000000..21971cd
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/rename_dir/rename_dir.c b/zfs/tests/zfs-tests/cmd/rename_dir/rename_dir.c
new file mode 100644 (file)
index 0000000..5f80f72
--- /dev/null
@@ -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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile.am b/zfs/tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile.am
new file mode 100644 (file)
index 0000000..90fc8d0
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/rm_lnkcnt_zero_file/rm_lnkcnt_zero_file.c b/zfs/tests/zfs-tests/cmd/rm_lnkcnt_zero_file/rm_lnkcnt_zero_file.c
new file mode 100644 (file)
index 0000000..7986851
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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) {
+               if (*fd != -1)
+                       (void) close (*fd);
+
+               *fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644);
+               if (*fd == -1) {
+                       perror("fail to open test file, refreshing it");
+                       continue;
+               }
+
+               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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/threadsappend/Makefile.am b/zfs/tests/zfs-tests/cmd/threadsappend/Makefile.am
new file mode 100644 (file)
index 0000000..f030b42
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/cmd/threadsappend/threadsappend.c b/zfs/tests/zfs-tests/cmd/threadsappend/threadsappend.c
new file mode 100644 (file)
index 0000000..25710a3
--- /dev/null
@@ -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);
+}
diff --git a/zfs/tests/zfs-tests/cmd/xattrtest/Makefile.am b/zfs/tests/zfs-tests/cmd/xattrtest/Makefile.am
new file mode 100644 (file)
index 0000000..7398ae6
--- /dev/null
@@ -0,0 +1,6 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
+
+pkgexec_PROGRAMS = xattrtest
+xattrtest_SOURCES = xattrtest.c
diff --git a/zfs/tests/zfs-tests/cmd/xattrtest/xattrtest.c b/zfs/tests/zfs-tests/cmd/xattrtest/xattrtest.c
new file mode 100644 (file)
index 0000000..991dd06
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ * 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:rRko:";
+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' },
+       { "only",               required_argument,      0,      'o' },
+       { 0,                    0,                      0,      0   }
+};
+
+enum phases {
+       PHASE_ALL = 0,
+       PHASE_CREATE,
+       PHASE_SETXATTR,
+       PHASE_GETXATTR,
+       PHASE_UNLINK,
+       PHASE_INVAL
+};
+
+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 = 6;
+static int size_is_random = 0;
+static int value_is_random = 0;
+static int keep_files = 0;
+static int phase = PHASE_ALL;
+static char path[PATH_MAX] = "/tmp/xattrtest";
+static char script[PATH_MAX] = "/bin/true";
+static char xattrbytes[XATTR_SIZE_MAX];
+
+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> ] [-o <phase>]\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"
+       "  --only        -o <num>     Only run phase N\n"
+       "                             0=all, 1=create, 2=setxattr,\n"
+       "                             3=getxattr, 4=unlink\n\n");
+
+       return (1);
+}
+
+static int
+parse_args(int argc, char **argv)
+{
+       long seed = time(NULL);
+       int c;
+       int rc = 0;
+
+       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 (phase != PHASE_ALL) {
+                               fprintf(stderr,
+                                   "Error: -y and -o 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 -s value may not "
+                                   "be greater than %d\n", XATTR_SIZE_MAX);
+                               rc = 1;
+                       }
+                       break;
+               case 'p':
+                       strncpy(path, optarg, PATH_MAX);
+                       path[PATH_MAX - 1] = '\0';
+                       break;
+               case 'c':
+                       synccaches = 1;
+                       break;
+               case 'd':
+                       dropcaches = 1;
+                       break;
+               case 't':
+                       strncpy(script, optarg, PATH_MAX);
+                       script[PATH_MAX - 1] = '\0';
+                       break;
+               case 'e':
+                       seed = strtol(optarg, NULL, 0);
+                       break;
+               case 'r':
+                       size_is_random = 1;
+                       break;
+               case 'R':
+                       value_is_random = 1;
+                       break;
+               case 'k':
+                       keep_files = 1;
+                       break;
+               case 'o':
+                       phase = strtol(optarg, NULL, 0);
+                       if (phase <= PHASE_ALL || phase >= PHASE_INVAL) {
+                               fprintf(stderr, "Error: the -o value must be "
+                                   "greater than %d and less than %d\n",
+                                   PHASE_ALL, PHASE_INVAL);
+                               rc = 1;
+                       }
+                       if (verify == 1) {
+                               fprintf(stderr,
+                                   "Error: -y and -o are incompatible.\n");
+                               rc = 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, "only:             %d\n", phase);
+               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);
+               (void) close(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 double
+timeval_sub_seconds(struct timeval *tv1, struct timeval *tv2)
+{
+       struct timeval delta;
+
+       timeval_sub(&delta, tv1, tv2);
+       return ((double)delta.tv_usec / USEC_PER_SEC + delta.tv_sec);
+}
+
+static int
+create_files(void)
+{
+       int i, rc;
+       char *file = NULL;
+       struct timeval start, stop;
+       double seconds;
+
+       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);
+       seconds = timeval_sub_seconds(&stop, &start);
+       fprintf(stdout, "create:   %f seconds %f creates/second\n",
+           seconds, files / seconds);
+
+       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;
+       double seconds;
+
+       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);
+                       shift = sprintf(value, "size=%d ", rnd_size);
+                       memcpy(value + shift, xattrbytes,
+                           sizeof (xattrbytes) - 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);
+       seconds = timeval_sub_seconds(&stop, &start);
+       fprintf(stdout, "setxattr: %f seconds %f setxattrs/second\n",
+           seconds, (files * xattrs) / seconds);
+
+       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 *verify_string;
+       char *value = NULL;
+       char *value_string;
+       char *file = NULL;
+       struct timeval start, stop;
+       double seconds;
+
+       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;
+       }
+
+       verify_string = value_is_random ? "<random>" : verify_value;
+       value_string = value_is_random ? "<random>" : value;
+
+       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)
+                               continue;
+
+                       sscanf(value, "size=%d [a-z]", &rnd_size);
+                       shift = sprintf(verify_value, "size=%d ",
+                           rnd_size);
+                       memcpy(verify_value + shift, xattrbytes,
+                           sizeof (xattrbytes) - shift);
+
+                       if (rnd_size != rc ||
+                           memcmp(verify_value, value, rnd_size)) {
+                               ERROR("Error %d: verify failed\n "
+                                   "verify: %s\n value:  %s\n", EINVAL,
+                                   verify_string, value_string);
+                               rc = 1;
+                               goto out;
+                       }
+               }
+       }
+
+       (void) gettimeofday(&stop, NULL);
+       seconds = timeval_sub_seconds(&stop, &start);
+       fprintf(stdout, "getxattr: %f seconds %f getxattrs/second\n",
+           seconds, (files * xattrs) / seconds);
+
+       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;
+       double seconds;
+
+       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);
+                       free(file);
+                       return (errno);
+               }
+       }
+
+       (void) gettimeofday(&stop, NULL);
+       seconds = timeval_sub_seconds(&stop, &start);
+       fprintf(stdout, "unlink:   %f seconds %f unlinks/second\n",
+           seconds, files / seconds);
+
+       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);
+
+       if (value_is_random) {
+               size_t rndsz = sizeof (xattrbytes);
+
+               rc = get_random_bytes(xattrbytes, rndsz);
+               if (rc < rndsz) {
+                       ERROR("Error %d: get_random_bytes() wanted %zd "
+                           "got %d\n", errno, rndsz, rc);
+                       return (rc);
+               }
+       } else {
+               memset(xattrbytes, 'x', sizeof (xattrbytes));
+       }
+
+       if (phase == PHASE_ALL || phase == PHASE_CREATE) {
+               rc = create_files();
+               if (rc)
+                       return (rc);
+       }
+
+       if (phase == PHASE_ALL || phase == PHASE_SETXATTR) {
+               rc = setxattrs();
+               if (rc)
+                       return (rc);
+       }
+
+       if (phase == PHASE_ALL || phase == PHASE_GETXATTR) {
+               rc = getxattrs();
+               if (rc)
+                       return (rc);
+       }
+
+       if (!keep_files && (phase == PHASE_ALL || phase == PHASE_UNLINK)) {
+               rc = unlink_files();
+               if (rc)
+                       return (rc);
+       }
+
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/include/Makefile.am b/zfs/tests/zfs-tests/include/Makefile.am
new file mode 100644 (file)
index 0000000..a10d6a3
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/include
+dist_pkgdata_SCRIPTS = \
+       commands.cfg \
+       default.cfg \
+       libtest.shlib \
+       math.shlib \
+       properties.shlib
diff --git a/zfs/tests/zfs-tests/include/commands.cfg.in b/zfs/tests/zfs-tests/include/commands.cfg.in
new file mode 100644 (file)
index 0000000..e7fb5ff
--- /dev/null
@@ -0,0 +1,130 @@
+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 FALSE="@FALSE@"
+export FDISK="@FDISK@"
+export FGREP="@FGREP@"
+export FILE="@FILE@"
+export FIND="@FIND@"
+export FIO="@FIO@"
+export FORMAT="@FORMAT@"
+export FREE="@FREE@"
+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 IOSTAT="@IOSTAT@"
+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 LSBLK="@LSBLK@"
+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 MPSTAT="@MPSTAT@"
+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 READLINK="@READLINK@"
+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 STAT="@STAT@"
+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 TIMEOUT="@TIMEOUT@"
+export TOUCH="@TOUCH@"
+export TR="@TR@"
+export TRUNCATE="@TRUNCATE@"
+export TRUE="@TRUE@"
+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 UUIDGEN="@UUIDGEN@"
+export VMSTAT="@VMSTAT@"
+export WAIT="@WAIT@"
+export WC="@WC@"
+export ZONEADM="@ZONEADM@"
+export ZONECFG="@ZONECFG@"
+export ZONENAME="@ZONENAME@"
diff --git a/zfs/tests/zfs-tests/include/default.cfg.in b/zfs/tests/zfs-tests/include/default.cfg.in
new file mode 100644 (file)
index 0000000..f93bfa9
--- /dev/null
@@ -0,0 +1,210 @@
+#
+# 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
+
+# Common paths
+bindir=@bindir@
+sbindir=@sbindir@
+
+# ZFS Commands
+export ZDB=${ZDB:-${sbindir}/zdb}
+export ZFS=${ZFS:-${sbindir}/zfs}
+export ZHACK=${ZHACK:-${sbindir}/zhack}
+export ZINJECT=${ZINJECT:-${sbindir}/zinject}
+export ZPOOL=${ZPOOL:-${sbindir}/zpool}
+export ZTEST=${ZTEST:-${sbindir}/ztest}
+export ZPIOS=${ZPIOS:-${sbindir}/zpios}
+export RAIDZ_TEST=${RAIDZ_TEST:-${bindir}/raidz_test}
+export ARC_SUMMARY=${ARC_SUMMARY:-${bindir}/arc_summary.py}
+export ARCSTAT=${ARCSTAT:-${bindir}/arcstat.py}
+export DBUFSTAT=${DBUFSTAT:-${bindir}/dbufstat.py}
+
+. $STF_SUITE/include/libtest.shlib
+
+# Optionally override the installed ZFS commands to run in-tree
+if [[ -f "$SRCDIR/zfs-script-config.sh" ]]; then
+       . $SRCDIR/zfs-script-config.sh
+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"
+
+# Test Suite Specific Commands
+helperdir=@datarootdir@/@PACKAGE@/zfs-tests/bin
+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:-${helperdir}/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 :
+export FIO_SCRIPTS=$STF_SUITE/tests/perf/fio
+export PERF_SCRIPTS=$STF_SUITE/tests/perf/scripts
+
+# some test pool names
+export TESTPOOL=testpool.$$
+export TESTPOOL1=testpool1.$$
+export TESTPOOL2=testpool2.$$
+export TESTPOOL3=testpool3.$$
+export PERFPOOL=perfpool
+
+# 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
+
+export MAX_PARTITIONS=8
+
+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_RDSKDIR="/dev"
+       DEV_MPATHDIR="/dev/mapper"
+
+       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_RDSKDIR DEV_MPATHDIR
diff --git a/zfs/tests/zfs-tests/include/libtest.shlib b/zfs/tests/zfs-tests/include/libtest.shlib
new file mode 100644 (file)
index 0000000..1857cf9
--- /dev/null
@@ -0,0 +1,2885 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+#
+
+. ${STF_TOOLS}/include/logapi.shlib
+
+# Determine if this is a Linux test system
+#
+# Return 0 if platform Linux, 1 if otherwise
+
+function is_linux
+{
+       if [[ $($UNAME -o) == "GNU/Linux" ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
+
+# Determine whether a dataset is mounted
+#
+# $1 dataset name
+# $2 filesystem type; optional - defaulted to zfs
+#
+# Return 0 if dataset is mounted; 1 if unmounted; 2 on error
+
+function ismounted
+{
+       typeset fstype=$2
+       [[ -z $fstype ]] && fstype=zfs
+       typeset out dir name ret
+
+       case $fstype in
+               zfs)
+                       if [[ "$1" == "/"* ]] ; then
+                               for out in $($ZFS mount | $AWK '{print $2}'); do
+                                       [[ $1 == $out ]] && return 0
+                               done
+                       else
+                               for out in $($ZFS mount | $AWK '{print $1}'); do
+                                       [[ $1 == $out ]] && return 0
+                               done
+                       fi
+               ;;
+               ufs|nfs)
+                       out=$($DF -F $fstype $1 2>/dev/null)
+                       ret=$?
+                       (($ret != 0)) && return $ret
+
+                       dir=${out%%\(*}
+                       dir=${dir%% *}
+                       name=${out##*\(}
+                       name=${name%%\)*}
+                       name=${name%% *}
+
+                       [[ "$1" == "$dir" || "$1" == "$name" ]] && return 0
+               ;;
+               ext2)
+                       out=$($DF -t $fstype $1 2>/dev/null)
+                       return $?
+               ;;
+               zvol)
+                       if [[ -L "$ZVOL_DEVDIR/$1" ]]; then
+                               link=$(readlink -f $ZVOL_DEVDIR/$1)
+                               [[ -n "$link" ]] && \
+                                       $MOUNT | $GREP -q "^$link" && \
+                                               return 0
+                       fi
+               ;;
+       esac
+
+       return 1
+}
+
+# Return 0 if a dataset is mounted; 1 otherwise
+#
+# $1 dataset name
+# $2 filesystem type; optional - defaulted to zfs
+
+function mounted
+{
+       ismounted $1 $2
+       (($? == 0)) && return 0
+       return 1
+}
+
+# Return 0 if a dataset is unmounted; 1 otherwise
+#
+# $1 dataset name
+# $2 filesystem type; optional - defaulted to zfs
+
+function unmounted
+{
+       ismounted $1 $2
+       (($? == 1)) && return 0
+       return 1
+}
+
+# split line on ","
+#
+# $1 - line to split
+
+function splitline
+{
+       $ECHO $1 | $SED "s/,/ /g"
+}
+
+function default_setup
+{
+       default_setup_noexit "$@"
+
+       log_pass
+}
+
+#
+# Given a list of disks, setup storage pools and datasets.
+#
+function default_setup_noexit
+{
+       typeset disklist=$1
+       typeset container=$2
+       typeset volume=$3
+       log_note begin default_setup_noexit
+
+       if is_global_zone; then
+               if poolexists $TESTPOOL ; then
+                       destroy_pool $TESTPOOL
+               fi
+               [[ -d /$TESTPOOL ]] && $RM -rf /$TESTPOOL
+               log_note creating pool $TESTPOOL $disklist
+               log_must $ZPOOL create -f $TESTPOOL $disklist
+       else
+               reexport_pool
+       fi
+
+       $RM -rf $TESTDIR  || log_unresolved Could not remove $TESTDIR
+       $MKDIR -p $TESTDIR || log_unresolved Could not create $TESTDIR
+
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+       if [[ -n $container ]]; then
+               $RM -rf $TESTDIR1  || \
+                       log_unresolved Could not remove $TESTDIR1
+               $MKDIR -p $TESTDIR1 || \
+                       log_unresolved Could not create $TESTDIR1
+
+               log_must $ZFS create $TESTPOOL/$TESTCTR
+               log_must $ZFS set canmount=off $TESTPOOL/$TESTCTR
+               log_must $ZFS create $TESTPOOL/$TESTCTR/$TESTFS1
+               log_must $ZFS set mountpoint=$TESTDIR1 \
+                   $TESTPOOL/$TESTCTR/$TESTFS1
+       fi
+
+       if [[ -n $volume ]]; then
+               if is_global_zone ; then
+                       log_must $ZFS create -V $VOLSIZE $TESTPOOL/$TESTVOL
+                       block_device_wait
+               else
+                       log_must $ZFS create $TESTPOOL/$TESTVOL
+               fi
+       fi
+}
+
+#
+# Given a list of disks, setup a storage pool, file system and
+# a container.
+#
+function default_container_setup
+{
+       typeset disklist=$1
+
+       default_setup "$disklist" "true"
+}
+
+#
+# Given a list of disks, setup a storage pool,file system
+# and a volume.
+#
+function default_volume_setup
+{
+       typeset disklist=$1
+
+       default_setup "$disklist" "" "true"
+}
+
+#
+# Given a list of disks, setup a storage pool,file system,
+# a container and a volume.
+#
+function default_container_volume_setup
+{
+       typeset disklist=$1
+
+       default_setup "$disklist" "true" "true"
+}
+
+#
+# Create a snapshot on a filesystem or volume. Defaultly create a snapshot on
+# filesystem
+#
+# $1 Existing filesystem or volume name. Default, $TESTFS
+# $2 snapshot name. Default, $TESTSNAP
+#
+function create_snapshot
+{
+       typeset fs_vol=${1:-$TESTFS}
+       typeset snap=${2:-$TESTSNAP}
+
+       [[ -z $fs_vol ]] && log_fail "Filesystem or volume's name is undefined."
+       [[ -z $snap ]] && log_fail "Snapshot's name is undefined."
+
+       if snapexists $fs_vol@$snap; then
+               log_fail "$fs_vol@$snap already exists."
+       fi
+       datasetexists $fs_vol || \
+               log_fail "$fs_vol must exist."
+
+       log_must $ZFS snapshot $fs_vol@$snap
+}
+
+#
+# Create a clone from a snapshot, default clone name is $TESTCLONE.
+#
+# $1 Existing snapshot, $TESTPOOL/$TESTFS@$TESTSNAP is default.
+# $2 Clone name, $TESTPOOL/$TESTCLONE is default.
+#
+function create_clone   # snapshot clone
+{
+       typeset snap=${1:-$TESTPOOL/$TESTFS@$TESTSNAP}
+       typeset clone=${2:-$TESTPOOL/$TESTCLONE}
+
+       [[ -z $snap ]] && \
+               log_fail "Snapshot name is undefined."
+       [[ -z $clone ]] && \
+               log_fail "Clone name is undefined."
+
+       log_must $ZFS clone $snap $clone
+}
+
+function default_mirror_setup
+{
+       default_mirror_setup_noexit $1 $2 $3
+
+       log_pass
+}
+
+#
+# Given a pair of disks, set up a storage pool and dataset for the mirror
+# @parameters: $1 the primary side of the mirror
+#   $2 the secondary side of the mirror
+# @uses: ZPOOL ZFS TESTPOOL TESTFS
+function default_mirror_setup_noexit
+{
+       readonly func="default_mirror_setup_noexit"
+       typeset primary=$1
+       typeset secondary=$2
+
+       [[ -z $primary ]] && \
+               log_fail "$func: No parameters passed"
+       [[ -z $secondary ]] && \
+               log_fail "$func: No secondary partition passed"
+       [[ -d /$TESTPOOL ]] && $RM -rf /$TESTPOOL
+       log_must $ZPOOL create -f $TESTPOOL mirror $@
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+#
+# create a number of mirrors.
+# We create a number($1) of 2 way mirrors using the pairs of disks named
+# on the command line. These mirrors are *not* mounted
+# @parameters: $1 the number of mirrors to create
+#  $... the devices to use to create the mirrors on
+# @uses: ZPOOL ZFS TESTPOOL
+function setup_mirrors
+{
+       typeset -i nmirrors=$1
+
+       shift
+       while ((nmirrors > 0)); do
+               log_must test -n "$1" -a -n "$2"
+               [[ -d /$TESTPOOL$nmirrors ]] && $RM -rf /$TESTPOOL$nmirrors
+               log_must $ZPOOL create -f $TESTPOOL$nmirrors mirror $1 $2
+               shift 2
+               ((nmirrors = nmirrors - 1))
+       done
+}
+
+#
+# create a number of raidz pools.
+# We create a number($1) of 2 raidz pools  using the pairs of disks named
+# on the command line. These pools are *not* mounted
+# @parameters: $1 the number of pools to create
+#  $... the devices to use to create the pools on
+# @uses: ZPOOL ZFS TESTPOOL
+function setup_raidzs
+{
+       typeset -i nraidzs=$1
+
+       shift
+       while ((nraidzs > 0)); do
+               log_must test -n "$1" -a -n "$2"
+               [[ -d /$TESTPOOL$nraidzs ]] && $RM -rf /$TESTPOOL$nraidzs
+               log_must $ZPOOL create -f $TESTPOOL$nraidzs raidz $1 $2
+               shift 2
+               ((nraidzs = nraidzs - 1))
+       done
+}
+
+#
+# Destroy the configured testpool mirrors.
+# the mirrors are of the form ${TESTPOOL}{number}
+# @uses: ZPOOL ZFS TESTPOOL
+function destroy_mirrors
+{
+       default_cleanup_noexit
+
+       log_pass
+}
+
+#
+# Given a minimum of two disks, set up a storage pool and dataset for the raid-z
+# $1 the list of disks
+#
+function default_raidz_setup
+{
+       typeset disklist="$*"
+       disks=(${disklist[*]})
+
+       if [[ ${#disks[*]} -lt 2 ]]; then
+               log_fail "A raid-z requires a minimum of two disks."
+       fi
+
+       [[ -d /$TESTPOOL ]] && $RM -rf /$TESTPOOL
+       log_must $ZPOOL create -f $TESTPOOL raidz $1 $2 $3
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+       log_pass
+}
+
+#
+# Common function used to cleanup storage pools and datasets.
+#
+# Invoked at the start of the test suite to ensure the system
+# is in a known state, and also at the end of each set of
+# sub-tests to ensure errors from one set of tests doesn't
+# impact the execution of the next set.
+
+function default_cleanup
+{
+       default_cleanup_noexit
+
+       log_pass
+}
+
+function default_cleanup_noexit
+{
+       typeset exclude=""
+       typeset pool=""
+       #
+       # Destroying the pool will also destroy any
+       # filesystems it contains.
+       #
+       if is_global_zone; then
+               $ZFS unmount -a > /dev/null 2>&1
+               [[ -z "$KEEP" ]] && KEEP="rpool"
+               exclude=`eval $ECHO \"'(${KEEP})'\"`
+               ALL_POOLS=$($ZPOOL list -H -o name \
+                   | $GREP -v "$NO_POOLS" | $EGREP -v "$exclude")
+               # Here, we loop through the pools we're allowed to
+               # destroy, only destroying them if it's safe to do
+               # so.
+               while [ ! -z ${ALL_POOLS} ]
+               do
+                       for pool in ${ALL_POOLS}
+                       do
+                               if safe_to_destroy_pool $pool ;
+                               then
+                                       destroy_pool $pool
+                               fi
+                               ALL_POOLS=$($ZPOOL list -H -o name \
+                                   | $GREP -v "$NO_POOLS" \
+                                   | $EGREP -v "$exclude")
+                       done
+               done
+
+               $ZFS mount -a
+       else
+               typeset fs=""
+               for fs in $($ZFS list -H -o name \
+                   | $GREP "^$ZONE_POOL/$ZONE_CTR[01234]/"); do
+                       datasetexists $fs && \
+                               log_must $ZFS destroy -Rf $fs
+               done
+
+               # Need cleanup here to avoid garbage dir left.
+               for fs in $($ZFS list -H -o name); do
+                       [[ $fs == /$ZONE_POOL ]] && continue
+                       [[ -d $fs ]] && log_must $RM -rf $fs/*
+               done
+
+               #
+               # Reset the $ZONE_POOL/$ZONE_CTR[01234] file systems property to
+               # the default value
+               #
+               for fs in $($ZFS list -H -o name); do
+                       if [[ $fs == $ZONE_POOL/$ZONE_CTR[01234] ]]; then
+                               log_must $ZFS set reservation=none $fs
+                               log_must $ZFS set recordsize=128K $fs
+                               log_must $ZFS set mountpoint=/$fs $fs
+                               typeset enc=""
+                               enc=$(get_prop encryption $fs)
+                               if [[ $? -ne 0 ]] || [[ -z "$enc" ]] || \
+                                       [[ "$enc" == "off" ]]; then
+                                       log_must $ZFS set checksum=on $fs
+                               fi
+                               log_must $ZFS set compression=off $fs
+                               log_must $ZFS set atime=on $fs
+                               log_must $ZFS set devices=off $fs
+                               log_must $ZFS set exec=on $fs
+                               log_must $ZFS set setuid=on $fs
+                               log_must $ZFS set readonly=off $fs
+                               log_must $ZFS set snapdir=hidden $fs
+                               log_must $ZFS set aclmode=groupmask $fs
+                               log_must $ZFS set aclinherit=secure $fs
+                       fi
+               done
+       fi
+
+       [[ -d $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR
+
+       disk1=${DISKS%% *}
+       if is_mpath_device $disk1; then
+               delete_partitions
+       fi
+}
+
+
+#
+# Common function used to cleanup storage pools, file systems
+# and containers.
+#
+function default_container_cleanup
+{
+       if ! is_global_zone; then
+               reexport_pool
+       fi
+
+       ismounted $TESTPOOL/$TESTCTR/$TESTFS1
+       [[ $? -eq 0 ]] && \
+           log_must $ZFS unmount $TESTPOOL/$TESTCTR/$TESTFS1
+
+       datasetexists $TESTPOOL/$TESTCTR/$TESTFS1 && \
+           log_must $ZFS destroy -R $TESTPOOL/$TESTCTR/$TESTFS1
+
+       datasetexists $TESTPOOL/$TESTCTR && \
+           log_must $ZFS destroy -Rf $TESTPOOL/$TESTCTR
+
+       [[ -e $TESTDIR1 ]] && \
+           log_must $RM -rf $TESTDIR1 > /dev/null 2>&1
+
+       default_cleanup
+}
+
+#
+# Common function used to cleanup snapshot of file system or volume. Default to
+# delete the file system's snapshot
+#
+# $1 snapshot name
+#
+function destroy_snapshot
+{
+       typeset snap=${1:-$TESTPOOL/$TESTFS@$TESTSNAP}
+
+       if ! snapexists $snap; then
+               log_fail "'$snap' does not existed."
+       fi
+
+       #
+       # For the sake of the value which come from 'get_prop' is not equal
+       # to the really mountpoint when the snapshot is unmounted. So, firstly
+       # check and make sure this snapshot's been mounted in current system.
+       #
+       typeset mtpt=""
+       if ismounted $snap; then
+               mtpt=$(get_prop mountpoint $snap)
+               (($? != 0)) && \
+                       log_fail "get_prop mountpoint $snap failed."
+       fi
+
+       log_must $ZFS destroy $snap
+       [[ $mtpt != "" && -d $mtpt ]] && \
+               log_must $RM -rf $mtpt
+}
+
+#
+# Common function used to cleanup clone.
+#
+# $1 clone name
+#
+function destroy_clone
+{
+       typeset clone=${1:-$TESTPOOL/$TESTCLONE}
+
+       if ! datasetexists $clone; then
+               log_fail "'$clone' does not existed."
+       fi
+
+       # With the same reason in destroy_snapshot
+       typeset mtpt=""
+       if ismounted $clone; then
+               mtpt=$(get_prop mountpoint $clone)
+               (($? != 0)) && \
+                       log_fail "get_prop mountpoint $clone failed."
+       fi
+
+       log_must $ZFS destroy $clone
+       [[ $mtpt != "" && -d $mtpt ]] && \
+               log_must $RM -rf $mtpt
+}
+
+# Return 0 if a snapshot exists; $? otherwise
+#
+# $1 - snapshot name
+
+function snapexists
+{
+       $ZFS list -H -t snapshot "$1" > /dev/null 2>&1
+       return $?
+}
+
+#
+# Set a property to a certain value on a dataset.
+# Sets a property of the dataset to the value as passed in.
+# @param:
+#      $1 dataset who's property is being set
+#      $2 property to set
+#      $3 value to set property to
+# @return:
+#      0 if the property could be set.
+#      non-zero otherwise.
+# @use: ZFS
+#
+function dataset_setprop
+{
+       typeset fn=dataset_setprop
+
+       if (($# < 3)); then
+               log_note "$fn: Insufficient parameters (need 3, had $#)"
+               return 1
+       fi
+       typeset output=
+       output=$($ZFS set $2=$3 $1 2>&1)
+       typeset rv=$?
+       if ((rv != 0)); then
+               log_note "Setting property on $1 failed."
+               log_note "property $2=$3"
+               log_note "Return Code: $rv"
+               log_note "Output: $output"
+               return $rv
+       fi
+       return 0
+}
+
+#
+# Assign suite defined dataset properties.
+# This function is used to apply the suite's defined default set of
+# properties to a dataset.
+# @parameters: $1 dataset to use
+# @uses: ZFS COMPRESSION_PROP CHECKSUM_PROP
+# @returns:
+#   0 if the dataset has been altered.
+#   1 if no pool name was passed in.
+#   2 if the dataset could not be found.
+#   3 if the dataset could not have it's properties set.
+#
+function dataset_set_defaultproperties
+{
+       typeset dataset="$1"
+
+       [[ -z $dataset ]] && return 1
+
+       typeset confset=
+       typeset -i found=0
+       for confset in $($ZFS list); do
+               if [[ $dataset = $confset ]]; then
+                       found=1
+                       break
+               fi
+       done
+       [[ $found -eq 0 ]] && return 2
+       if [[ -n $COMPRESSION_PROP ]]; then
+               dataset_setprop $dataset compression $COMPRESSION_PROP || \
+                       return 3
+               log_note "Compression set to '$COMPRESSION_PROP' on $dataset"
+       fi
+       if [[ -n $CHECKSUM_PROP ]]; then
+               dataset_setprop $dataset checksum $CHECKSUM_PROP || \
+                       return 3
+               log_note "Checksum set to '$CHECKSUM_PROP' on $dataset"
+       fi
+       return 0
+}
+
+#
+# Check a numeric assertion
+# @parameter: $@ the assertion to check
+# @output: big loud notice if assertion failed
+# @use: log_fail
+#
+function assert
+{
+       (($@)) || log_fail "$@"
+}
+
+#
+# Function to format partition size of a disk
+# Given a disk cxtxdx reduces all partitions
+# to 0 size
+#
+function zero_partitions #<whole_disk_name>
+{
+       typeset diskname=$1
+       typeset i
+
+       if is_linux; then
+               log_must $FORMAT $DEV_DSKDIR/$diskname -s -- mklabel gpt
+       else
+               for i in 0 1 3 4 5 6 7
+               do
+                       set_partition $i "" 0mb $diskname
+               done
+       fi
+}
+
+#
+# Given a slice, size and disk, this function
+# formats the slice to the specified size.
+# Size should be specified with units as per
+# the `format` command requirements eg. 100mb 3gb
+#
+# NOTE: This entire interface is problematic for the Linux parted utilty
+# which requires the end of the partition to be specified.  It would be
+# best to retire this interface and replace it with something more flexible.
+# At the moment a best effort is made.
+#
+function set_partition #<slice_num> <slice_start> <size_plus_units>  <whole_disk_name>
+{
+       typeset -i slicenum=$1
+       typeset start=$2
+       typeset size=$3
+       typeset disk=$4
+       [[ -z $slicenum || -z $size || -z $disk ]] && \
+           log_fail "The slice, size or disk name is unspecified."
+
+       if is_linux; then
+               typeset size_mb=${size%%[mMgG]}
+
+               size_mb=${size_mb%%[mMgG][bB]}
+               if [[ ${size:1:1} == 'g' ]]; then
+                       ((size_mb = size_mb * 1024))
+               fi
+
+               # Create GPT partition table when setting slice 0 or
+               # when the device doesn't already contain a GPT label.
+               $FORMAT $DEV_DSKDIR/$disk -s -- print 1 >/dev/null
+               typeset ret_val=$?
+               if [[ $slicenum -eq 0 || $ret_val -ne 0 ]]; then
+                       log_must $FORMAT $DEV_DSKDIR/$disk -s -- mklabel gpt
+               fi
+
+               # When no start is given align on the first cylinder.
+               if [[ -z "$start" ]]; then
+                       start=1
+               fi
+
+               # Determine the cylinder size for the device and using
+               # that calculate the end offset in cylinders.
+               typeset -i cly_size_kb=0
+               cly_size_kb=$($FORMAT -m $DEV_DSKDIR/$disk -s -- \
+                       unit cyl print | $HEAD -3 | $TAIL -1 | \
+                       $AWK -F '[:k.]' '{print $4}')
+               ((end = (size_mb * 1024 / cly_size_kb) + start))
+
+               log_must $FORMAT $DEV_DSKDIR/$disk -s -- \
+                   mkpart part$slicenum ${start}cyl ${end}cyl
+
+               $BLOCKDEV --rereadpt $DEV_DSKDIR/$disk 2>/dev/null
+               block_device_wait
+       else
+               typeset format_file=/var/tmp/format_in.$$
+
+               $ECHO "partition" >$format_file
+               $ECHO "$slicenum" >> $format_file
+               $ECHO "" >> $format_file
+               $ECHO "" >> $format_file
+               $ECHO "$start" >> $format_file
+               $ECHO "$size" >> $format_file
+               $ECHO "label" >> $format_file
+               $ECHO "" >> $format_file
+               $ECHO "q" >> $format_file
+               $ECHO "q" >> $format_file
+
+               $FORMAT -e -s -d $disk -f $format_file
+       fi
+       typeset ret_val=$?
+       $RM -f $format_file
+       [[ $ret_val -ne 0 ]] && \
+           log_fail "Unable to format $disk slice $slicenum to $size"
+       return 0
+}
+
+#
+# Delete all partitions on all disks - this is specifically for the use of multipath
+# devices which currently can only be used in the test suite as raw/un-partitioned
+# devices (ie a zpool cannot be created on a whole mpath device that has partitions)
+#
+function delete_partitions
+{
+       typeset -i j=1
+
+       if [[ -z $DISK_ARRAY_NUM ]]; then
+               DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+       fi
+       if [[ -z $DISKSARRAY ]]; then
+               DISKSARRAY=$DISKS
+       fi
+
+       if is_linux; then
+               if (( $DISK_ARRAY_NUM == 1 )); then
+                       while ((j < MAX_PARTITIONS)); do
+                               $FORMAT $DEV_DSKDIR/$DISK -s rm $j > /dev/null 2>&1
+                               if (( $? == 1 )); then
+                                       $LSBLK | $EGREP ${DISK}${SLICE_PREFIX}${j} > /dev/null
+                                               if (( $? == 1 )); then
+                                                       log_note "Partitions for $DISK should be deleted"
+                                               else
+                                                       log_fail "Partition for ${DISK}${SLICE_PREFIX}${j} not deleted"
+                                               fi
+                                               return 0
+                               else
+                                       $LSBLK | $EGREP ${DISK}${SLICE_PREFIX}${j} > /dev/null
+                                               if (( $? == 0 )); then
+                                                       log_fail "Partition for ${DISK}${SLICE_PREFIX}${j} not deleted"
+                                               fi
+                               fi
+                               ((j = j+1))
+                       done
+               else
+                       for disk in `$ECHO $DISKSARRAY`; do
+                               while ((j < MAX_PARTITIONS)); do
+                                       $FORMAT $DEV_DSKDIR/$disk -s rm $j > /dev/null 2>&1
+                                       if (( $? == 1 )); then
+                                               $LSBLK | $EGREP ${disk}${SLICE_PREFIX}${j} > /dev/null
+                                               if (( $? == 1 )); then
+                                                       log_note "Partitions for $disk should be deleted"
+                                               else
+                                                       log_fail "Partition for ${disk}${SLICE_PREFIX}${j} not deleted"
+                                               fi
+                                               j=7
+                                       else
+                                               $LSBLK | $EGREP ${disk}${SLICE_PREFIX}${j} > /dev/null
+                                               if (( $? == 0 )); then
+                                                       log_fail "Partition for ${disk}${SLICE_PREFIX}${j} not deleted"
+                                               fi
+                                       fi
+                                       ((j = j+1))
+                               done
+                               j=1
+                       done
+               fi
+       fi
+       return 0
+}
+
+#
+# Get the end cyl of the given slice
+#
+function get_endslice #<disk> <slice>
+{
+       typeset disk=$1
+       typeset slice=$2
+       if [[ -z $disk || -z $slice ]] ; then
+               log_fail "The disk name or slice number is unspecified."
+       fi
+
+       if is_linux; then
+               endcyl=$($FORMAT -s $DEV_DSKDIR/$disk -- unit cyl print | \
+                       $GREP "part${slice}" | \
+                       $AWK '{print $3}' | \
+                       $SED 's,cyl,,')
+               ((endcyl = (endcyl + 1)))
+       else
+               disk=${disk#/dev/dsk/}
+               disk=${disk#/dev/rdsk/}
+               disk=${disk%s*}
+
+               typeset -i ratio=0
+               ratio=$($PRTVTOC /dev/rdsk/${disk}s2 | \
+                       $GREP "sectors\/cylinder" | \
+                       $AWK '{print $2}')
+
+               if ((ratio == 0)); then
+                       return
+               fi
+
+               typeset -i endcyl=$($PRTVTOC -h /dev/rdsk/${disk}s2 |
+                       $NAWK -v token="$slice" '{if ($1==token) print $6}')
+
+               ((endcyl = (endcyl + 1) / ratio))
+       fi
+
+       echo $endcyl
+}
+
+
+#
+# Given a size,disk and total slice number,  this function formats the
+# disk slices from 0 to the total slice number with the same specified
+# size.
+#
+function partition_disk        #<slice_size> <whole_disk_name> <total_slices>
+{
+       typeset -i i=0
+       typeset slice_size=$1
+       typeset disk_name=$2
+       typeset total_slices=$3
+       typeset cyl
+
+       zero_partitions $disk_name
+       while ((i < $total_slices)); do
+               if ! is_linux; then
+                       if ((i == 2)); then
+                               ((i = i + 1))
+                               continue
+                       fi
+               fi
+               set_partition $i "$cyl" $slice_size $disk_name
+               cyl=$(get_endslice $disk_name $i)
+               ((i = i+1))
+       done
+}
+
+#
+# This function continues to write to a filenum number of files into dirnum
+# number of directories until either $FILE_WRITE returns an error or the
+# maximum number of files per directory have been written.
+#
+# Usage:
+# fill_fs [destdir] [dirnum] [filenum] [bytes] [num_writes] [data]
+#
+# Return value: 0 on success
+#              non 0 on error
+#
+# Where :
+#      destdir:    is the directory where everything is to be created under
+#      dirnum:     the maximum number of subdirectories to use, -1 no limit
+#      filenum:    the maximum number of files per subdirectory
+#      bytes:      number of bytes to write
+#      num_writes: numer of types to write out bytes
+#      data:       the data that will be writen
+#
+#      E.g.
+#      file_fs /testdir 20 25 1024 256 0
+#
+# Note: bytes * num_writes equals the size of the testfile
+#
+function fill_fs # destdir dirnum filenum bytes num_writes data
+{
+       typeset destdir=${1:-$TESTDIR}
+       typeset -i dirnum=${2:-50}
+       typeset -i filenum=${3:-50}
+       typeset -i bytes=${4:-8192}
+       typeset -i num_writes=${5:-10240}
+       typeset -i data=${6:-0}
+
+       typeset -i odirnum=1
+       typeset -i idirnum=0
+       typeset -i fn=0
+       typeset -i retval=0
+
+       log_must $MKDIR -p $destdir/$idirnum
+       while (($odirnum > 0)); do
+               if ((dirnum >= 0 && idirnum >= dirnum)); then
+                       odirnum=0
+                       break
+               fi
+               $FILE_WRITE -o create -f $destdir/$idirnum/$TESTFILE.$fn \
+                   -b $bytes -c $num_writes -d $data
+               retval=$?
+               if (($retval != 0)); then
+                       odirnum=0
+                       break
+               fi
+               if (($fn >= $filenum)); then
+                       fn=0
+                       ((idirnum = idirnum + 1))
+                       log_must $MKDIR -p $destdir/$idirnum
+               else
+                       ((fn = fn + 1))
+               fi
+       done
+       return $retval
+}
+
+#
+# Simple function to get the specified property. If unable to
+# get the property then exits.
+#
+# Note property is in 'parsable' format (-p)
+#
+function get_prop # property dataset
+{
+       typeset prop_val
+       typeset prop=$1
+       typeset dataset=$2
+
+       prop_val=$($ZFS get -pH -o value $prop $dataset 2>/dev/null)
+       if [[ $? -ne 0 ]]; then
+               log_note "Unable to get $prop property for dataset " \
+               "$dataset"
+               return 1
+       fi
+
+       $ECHO $prop_val
+       return 0
+}
+
+#
+# Simple function to get the specified property of pool. If unable to
+# get the property then exits.
+#
+function get_pool_prop # property pool
+{
+       typeset prop_val
+       typeset prop=$1
+       typeset pool=$2
+
+       if poolexists $pool ; then
+               prop_val=$($ZPOOL get $prop $pool 2>/dev/null | $TAIL -1 | \
+                       $AWK '{print $3}')
+               if [[ $? -ne 0 ]]; then
+                       log_note "Unable to get $prop property for pool " \
+                       "$pool"
+                       return 1
+               fi
+       else
+               log_note "Pool $pool not exists."
+               return 1
+       fi
+
+       $ECHO $prop_val
+       return 0
+}
+
+# Return 0 if a pool exists; $? otherwise
+#
+# $1 - pool name
+
+function poolexists
+{
+       typeset pool=$1
+
+       if [[ -z $pool ]]; then
+               log_note "No pool name given."
+               return 1
+       fi
+
+       $ZPOOL get name "$pool" > /dev/null 2>&1
+       return $?
+}
+
+# Return 0 if all the specified datasets exist; $? otherwise
+#
+# $1-n  dataset name
+function datasetexists
+{
+       if (($# == 0)); then
+               log_note "No dataset name given."
+               return 1
+       fi
+
+       while (($# > 0)); do
+               $ZFS get name $1 > /dev/null 2>&1 || \
+                       return $?
+               shift
+       done
+
+       return 0
+}
+
+# return 0 if none of the specified datasets exists, otherwise return 1.
+#
+# $1-n  dataset name
+function datasetnonexists
+{
+       if (($# == 0)); then
+               log_note "No dataset name given."
+               return 1
+       fi
+
+       while (($# > 0)); do
+               $ZFS list -H -t filesystem,snapshot,volume $1 > /dev/null 2>&1 \
+                   && return 1
+               shift
+       done
+
+       return 0
+}
+
+#
+# Given a mountpoint, or a dataset name, determine if it is shared.
+#
+# Returns 0 if shared, 1 otherwise.
+#
+function is_shared
+{
+       typeset fs=$1
+       typeset mtpt
+
+       if is_linux; then
+               log_unsupported "Currently unsupported by the test framework"
+               return 1
+       fi
+
+       if [[ $fs != "/"* ]] ; then
+               if datasetnonexists "$fs" ; then
+                       return 1
+               else
+                       mtpt=$(get_prop mountpoint "$fs")
+                       case $mtpt in
+                               none|legacy|-) return 1
+                                       ;;
+                               *)      fs=$mtpt
+                                       ;;
+                       esac
+               fi
+       fi
+
+       for mtpt in `$SHARE | $AWK '{print $2}'` ; do
+               if [[ $mtpt == $fs ]] ; then
+                       return 0
+               fi
+       done
+
+       typeset stat=$($SVCS -H -o STA nfs/server:default)
+       if [[ $stat != "ON" ]]; then
+               log_note "Current nfs/server status: $stat"
+       fi
+
+       return 1
+}
+
+#
+# Given a mountpoint, determine if it is not shared.
+#
+# Returns 0 if not shared, 1 otherwise.
+#
+function not_shared
+{
+       typeset fs=$1
+
+       if is_linux; then
+               log_unsupported "Currently unsupported by the test framework"
+               return 1
+       fi
+
+       is_shared $fs
+       if (($? == 0)); then
+               return 1
+       fi
+
+       return 0
+}
+
+#
+# Helper function to unshare a mountpoint.
+#
+function unshare_fs #fs
+{
+       typeset fs=$1
+
+       if is_linux; then
+               log_unsupported "Currently unsupported by the test framework"
+               return 1
+       fi
+
+       is_shared $fs
+       if (($? == 0)); then
+               log_must $ZFS unshare $fs
+       fi
+
+       return 0
+}
+
+#
+# Check NFS server status and trigger it online.
+#
+function setup_nfs_server
+{
+       # Cannot share directory in non-global zone.
+       #
+       if ! is_global_zone; then
+               log_note "Cannot trigger NFS server by sharing in LZ."
+               return
+       fi
+
+       if is_linux; then
+               log_unsupported "Currently unsupported by the test framework"
+               return
+       fi
+
+       typeset nfs_fmri="svc:/network/nfs/server:default"
+       if [[ $($SVCS -Ho STA $nfs_fmri) != "ON" ]]; then
+               #
+               # Only really sharing operation can enable NFS server
+               # to online permanently.
+               #
+               typeset dummy=/tmp/dummy
+
+               if [[ -d $dummy ]]; then
+                       log_must $RM -rf $dummy
+               fi
+
+               log_must $MKDIR $dummy
+               log_must $SHARE $dummy
+
+               #
+               # Waiting for fmri's status to be the final status.
+               # Otherwise, in transition, an asterisk (*) is appended for
+               # instances, unshare will reverse status to 'DIS' again.
+               #
+               # Waiting for 1's at least.
+               #
+               log_must $SLEEP 1
+               timeout=10
+               while [[ timeout -ne 0 && $($SVCS -Ho STA $nfs_fmri) == *'*' ]]
+               do
+                       log_must $SLEEP 1
+
+                       ((timeout -= 1))
+               done
+
+               log_must $UNSHARE $dummy
+               log_must $RM -rf $dummy
+       fi
+
+       log_note "Current NFS status: '$($SVCS -Ho STA,FMRI $nfs_fmri)'"
+}
+
+#
+# To verify whether calling process is in global zone
+#
+# Return 0 if in global zone, 1 in non-global zone
+#
+function is_global_zone
+{
+       typeset cur_zone=$($ZONENAME 2>/dev/null)
+       if [[ $cur_zone != "global" ]]; then
+               return 1
+       fi
+       return 0
+}
+
+#
+# Verify whether test is permitted to run from
+# global zone, local zone, or both
+#
+# $1 zone limit, could be "global", "local", or "both"(no limit)
+#
+# Return 0 if permitted, otherwise exit with log_unsupported
+#
+function verify_runnable # zone limit
+{
+       typeset limit=$1
+
+       [[ -z $limit ]] && return 0
+
+       if is_global_zone ; then
+               case $limit in
+                       global|both)
+                               ;;
+                       local)  log_unsupported "Test is unable to run from "\
+                                       "global zone."
+                               ;;
+                       *)      log_note "Warning: unknown limit $limit - " \
+                                       "use both."
+                               ;;
+               esac
+       else
+               case $limit in
+                       local|both)
+                               ;;
+                       global) log_unsupported "Test is unable to run from "\
+                                       "local zone."
+                               ;;
+                       *)      log_note "Warning: unknown limit $limit - " \
+                                       "use both."
+                               ;;
+               esac
+
+               reexport_pool
+       fi
+
+       return 0
+}
+
+# Return 0 if create successfully or the pool exists; $? otherwise
+# Note: In local zones, this function should return 0 silently.
+#
+# $1 - pool name
+# $2-n - [keyword] devs_list
+
+function create_pool #pool devs_list
+{
+       typeset pool=${1%%/*}
+
+       shift
+
+       if [[ -z $pool ]]; then
+               log_note "Missing pool name."
+               return 1
+       fi
+
+       if poolexists $pool ; then
+               destroy_pool $pool
+       fi
+
+       if is_global_zone ; then
+               [[ -d /$pool ]] && $RM -rf /$pool
+               log_must $ZPOOL create -f $pool $@
+       fi
+
+       return 0
+}
+
+# Return 0 if destroy successfully or the pool exists; $? otherwise
+# Note: In local zones, this function should return 0 silently.
+#
+# $1 - pool name
+# Destroy pool with the given parameters.
+
+function destroy_pool #pool
+{
+       typeset pool=${1%%/*}
+       typeset mtpt
+
+       if [[ -z $pool ]]; then
+               log_note "No pool name given."
+               return 1
+       fi
+
+       if is_global_zone ; then
+               if poolexists "$pool" ; then
+                       mtpt=$(get_prop mountpoint "$pool")
+
+                       # At times, syseventd activity can cause attempts to
+                       # destroy a pool to fail with EBUSY. We retry a few
+                       # times allowing failures before requiring the destroy
+                       # to succeed.
+                       typeset -i wait_time=10 ret=1 count=0
+                       must=""
+                       while [[ $ret -ne 0 ]]; do
+                               $must $ZPOOL destroy -f $pool
+                               ret=$?
+                               [[ $ret -eq 0 ]] && break
+                               log_note "zpool destroy failed with $ret"
+                               [[ count++ -ge 7 ]] && must=log_must
+                               $SLEEP $wait_time
+                       done
+
+                       [[ -d $mtpt ]] && \
+                               log_must $RM -rf $mtpt
+               else
+                       log_note "Pool does not exist. ($pool)"
+                       return 1
+               fi
+       fi
+
+       return 0
+}
+
+#
+# Firstly, create a pool with 5 datasets. Then, create a single zone and
+# export the 5 datasets to it. In addition, we also add a ZFS filesystem
+# and a zvol device to the zone.
+#
+# $1 zone name
+# $2 zone root directory prefix
+# $3 zone ip
+#
+function zfs_zones_setup #zone_name zone_root zone_ip
+{
+       typeset zone_name=${1:-$(hostname)-z}
+       typeset zone_root=${2:-"/zone_root"}
+       typeset zone_ip=${3:-"10.1.1.10"}
+       typeset prefix_ctr=$ZONE_CTR
+       typeset pool_name=$ZONE_POOL
+       typeset -i cntctr=5
+       typeset -i i=0
+
+       # Create pool and 5 container within it
+       #
+       [[ -d /$pool_name ]] && $RM -rf /$pool_name
+       log_must $ZPOOL create -f $pool_name $DISKS
+       while ((i < cntctr)); do
+               log_must $ZFS create $pool_name/$prefix_ctr$i
+               ((i += 1))
+       done
+
+       # create a zvol
+       log_must $ZFS create -V 1g $pool_name/zone_zvol
+       block_device_wait
+
+       #
+       # If current system support slog, add slog device for pool
+       #
+       if verify_slog_support ; then
+               typeset sdevs="/var/tmp/sdev1 /var/tmp/sdev2"
+               log_must $MKFILE 100M $sdevs
+               log_must $ZPOOL add $pool_name log mirror $sdevs
+       fi
+
+       # this isn't supported just yet.
+       # Create a filesystem. In order to add this to
+       # the zone, it must have it's mountpoint set to 'legacy'
+       # log_must $ZFS create $pool_name/zfs_filesystem
+       # log_must $ZFS set mountpoint=legacy $pool_name/zfs_filesystem
+
+       [[ -d $zone_root ]] && \
+               log_must $RM -rf $zone_root/$zone_name
+       [[ ! -d $zone_root ]] && \
+               log_must $MKDIR -p -m 0700 $zone_root/$zone_name
+
+       # Create zone configure file and configure the zone
+       #
+       typeset zone_conf=/tmp/zone_conf.$$
+       $ECHO "create" > $zone_conf
+       $ECHO "set zonepath=$zone_root/$zone_name" >> $zone_conf
+       $ECHO "set autoboot=true" >> $zone_conf
+       i=0
+       while ((i < cntctr)); do
+               $ECHO "add dataset" >> $zone_conf
+               $ECHO "set name=$pool_name/$prefix_ctr$i" >> \
+                       $zone_conf
+               $ECHO "end" >> $zone_conf
+               ((i += 1))
+       done
+
+       # add our zvol to the zone
+       $ECHO "add device" >> $zone_conf
+       $ECHO "set match=$ZVOL_DEVDIR/$pool_name/zone_zvol" >> $zone_conf
+       $ECHO "end" >> $zone_conf
+
+       # add a corresponding zvol rdsk to the zone
+       $ECHO "add device" >> $zone_conf
+       $ECHO "set match=$ZVOL_RDEVDIR/$pool_name/zone_zvol" >> $zone_conf
+       $ECHO "end" >> $zone_conf
+
+       # once it's supported, we'll add our filesystem to the zone
+       # $ECHO "add fs" >> $zone_conf
+       # $ECHO "set type=zfs" >> $zone_conf
+       # $ECHO "set special=$pool_name/zfs_filesystem" >> $zone_conf
+       # $ECHO "set dir=/export/zfs_filesystem" >> $zone_conf
+       # $ECHO "end" >> $zone_conf
+
+       $ECHO "verify" >> $zone_conf
+       $ECHO "commit" >> $zone_conf
+       log_must $ZONECFG -z $zone_name -f $zone_conf
+       log_must $RM -f $zone_conf
+
+       # Install the zone
+       $ZONEADM -z $zone_name install
+       if (($? == 0)); then
+               log_note "SUCCESS: $ZONEADM -z $zone_name install"
+       else
+               log_fail "FAIL: $ZONEADM -z $zone_name install"
+       fi
+
+       # Install sysidcfg file
+       #
+       typeset sysidcfg=$zone_root/$zone_name/root/etc/sysidcfg
+       $ECHO "system_locale=C" > $sysidcfg
+       $ECHO  "terminal=dtterm" >> $sysidcfg
+       $ECHO  "network_interface=primary {" >> $sysidcfg
+       $ECHO  "hostname=$zone_name" >> $sysidcfg
+       $ECHO  "}" >> $sysidcfg
+       $ECHO  "name_service=NONE" >> $sysidcfg
+       $ECHO  "root_password=mo791xfZ/SFiw" >> $sysidcfg
+       $ECHO  "security_policy=NONE" >> $sysidcfg
+       $ECHO  "timezone=US/Eastern" >> $sysidcfg
+
+       # Boot this zone
+       log_must $ZONEADM -z $zone_name boot
+}
+
+#
+# Reexport TESTPOOL & TESTPOOL(1-4)
+#
+function reexport_pool
+{
+       typeset -i cntctr=5
+       typeset -i i=0
+
+       while ((i < cntctr)); do
+               if ((i == 0)); then
+                       TESTPOOL=$ZONE_POOL/$ZONE_CTR$i
+                       if ! ismounted $TESTPOOL; then
+                               log_must $ZFS mount $TESTPOOL
+                       fi
+               else
+                       eval TESTPOOL$i=$ZONE_POOL/$ZONE_CTR$i
+                       if eval ! ismounted \$TESTPOOL$i; then
+                               log_must eval $ZFS mount \$TESTPOOL$i
+                       fi
+               fi
+               ((i += 1))
+       done
+}
+
+#
+# Verify a given disk is online or offline
+#
+# Return 0 is pool/disk matches expected state, 1 otherwise
+#
+function check_state # pool disk state{online,offline}
+{
+       typeset pool=$1
+       typeset disk=${2#$DEV_DSKDIR/}
+       typeset state=$3
+
+       $ZPOOL status -v $pool | grep "$disk"  \
+           | grep -i "$state" > /dev/null 2>&1
+
+       return $?
+}
+
+#
+# Get the mountpoint of snapshot
+# For the snapshot use <mp_filesystem>/.zfs/snapshot/<snap>
+# as its mountpoint
+#
+function snapshot_mountpoint
+{
+       typeset dataset=${1:-$TESTPOOL/$TESTFS@$TESTSNAP}
+
+       if [[ $dataset != *@* ]]; then
+               log_fail "Error name of snapshot '$dataset'."
+       fi
+
+       typeset fs=${dataset%@*}
+       typeset snap=${dataset#*@}
+
+       if [[ -z $fs || -z $snap ]]; then
+               log_fail "Error name of snapshot '$dataset'."
+       fi
+
+       $ECHO $(get_prop mountpoint $fs)/.zfs/snapshot/$snap
+}
+
+#
+# Given a pool and file system, this function will verify the file system
+# using the zdb internal tool. Note that the pool is exported and imported
+# to ensure it has consistent state.
+#
+function verify_filesys # pool filesystem dir
+{
+       typeset pool="$1"
+       typeset filesys="$2"
+       typeset zdbout="/tmp/zdbout.$$"
+
+       shift
+       shift
+       typeset dirs=$@
+       typeset search_path=""
+
+       log_note "Calling $ZDB to verify filesystem '$filesys'"
+       $ZFS unmount -a > /dev/null 2>&1
+       log_must $ZPOOL export $pool
+
+       if [[ -n $dirs ]] ; then
+               for dir in $dirs ; do
+                       search_path="$search_path -d $dir"
+               done
+       fi
+
+       log_must $ZPOOL import $search_path $pool
+
+       $ZDB -cudi $filesys > $zdbout 2>&1
+       if [[ $? != 0 ]]; then
+               log_note "Output: $ZDB -cudi $filesys"
+               $CAT $zdbout
+               log_fail "$ZDB detected errors with: '$filesys'"
+       fi
+
+       log_must $ZFS mount -a
+       log_must $RM -rf $zdbout
+}
+
+#
+# Given a pool, and this function list all disks in the pool
+#
+function get_disklist # pool
+{
+       typeset disklist=""
+
+       disklist=$($ZPOOL iostat -v $1 | $NAWK '(NR >4) {print $1}' | \
+           $GREP -v "\-\-\-\-\-" | \
+           $EGREP -v -e "^(mirror|raidz1|raidz2|spare|log|cache)$")
+
+       $ECHO $disklist
+}
+
+#
+# Given a pool, and this function list all disks in the pool with their full
+# path (like "/dev/sda" instead of "sda").
+#
+function get_disklist_fullpath # pool
+{
+       args="-P $1"
+       get_disklist $args
+}
+
+
+
+# /**
+#  This function kills a given list of processes after a time period. We use
+#  this in the stress tests instead of STF_TIMEOUT so that we can have processes
+#  run for a fixed amount of time, yet still pass. Tests that hit STF_TIMEOUT
+#  would be listed as FAIL, which we don't want : we're happy with stress tests
+#  running for a certain amount of time, then finishing.
+#
+# @param $1 the time in seconds after which we should terminate these processes
+# @param $2..$n the processes we wish to terminate.
+# */
+function stress_timeout
+{
+       typeset -i TIMEOUT=$1
+       shift
+       typeset cpids="$@"
+
+       log_note "Waiting for child processes($cpids). " \
+               "It could last dozens of minutes, please be patient ..."
+       log_must $SLEEP $TIMEOUT
+
+       log_note "Killing child processes after ${TIMEOUT} stress timeout."
+       typeset pid
+       for pid in $cpids; do
+               $PS -p $pid > /dev/null 2>&1
+               if (($? == 0)); then
+                       log_must $KILL -USR1 $pid
+               fi
+       done
+}
+
+#
+# Verify a given hotspare disk is inuse or avail
+#
+# Return 0 is pool/disk matches expected state, 1 otherwise
+#
+function check_hotspare_state # pool disk state{inuse,avail}
+{
+       typeset pool=$1
+       typeset disk=${2#$DEV_DSKDIR/}
+       typeset state=$3
+
+       cur_state=$(get_device_state $pool $disk "spares")
+
+       if [[ $state != ${cur_state} ]]; then
+               return 1
+       fi
+       return 0
+}
+
+#
+# Verify a given slog disk is inuse or avail
+#
+# Return 0 is pool/disk matches expected state, 1 otherwise
+#
+function check_slog_state # pool disk state{online,offline,unavail}
+{
+       typeset pool=$1
+       typeset disk=${2#$DEV_DSKDIR/}
+       typeset state=$3
+
+       cur_state=$(get_device_state $pool $disk "logs")
+
+       if [[ $state != ${cur_state} ]]; then
+               return 1
+       fi
+       return 0
+}
+
+#
+# Verify a given vdev disk is inuse or avail
+#
+# Return 0 is pool/disk matches expected state, 1 otherwise
+#
+function check_vdev_state # pool disk state{online,offline,unavail}
+{
+       typeset pool=$1
+       typeset disk=${2#$/DEV_DSKDIR/}
+       typeset state=$3
+
+       cur_state=$(get_device_state $pool $disk)
+
+       if [[ $state != ${cur_state} ]]; then
+               return 1
+       fi
+       return 0
+}
+
+#
+# Check the output of 'zpool status -v <pool>',
+# and to see if the content of <token> contain the <keyword> specified.
+#
+# Return 0 is contain, 1 otherwise
+#
+function check_pool_status # pool token keyword
+{
+       typeset pool=$1
+       typeset token=$2
+       typeset keyword=$3
+
+       $ZPOOL status -v "$pool" 2>/dev/null | $NAWK -v token="$token:" '
+               ($1==token) {print $0}' \
+       | $GREP -i "$keyword" > /dev/null 2>&1
+
+       return $?
+}
+
+#
+# These 5 following functions are instance of check_pool_status()
+#      is_pool_resilvering - to check if the pool is resilver in progress
+#      is_pool_resilvered - to check if the pool is resilver completed
+#      is_pool_scrubbing - to check if the pool is scrub in progress
+#      is_pool_scrubbed - to check if the pool is scrub completed
+#      is_pool_scrub_stopped - to check if the pool is scrub stopped
+#
+function is_pool_resilvering #pool
+{
+       check_pool_status "$1" "scan" "resilver in progress since "
+       return $?
+}
+
+function is_pool_resilvered #pool
+{
+       check_pool_status "$1" "scan" "resilvered "
+       return $?
+}
+
+function is_pool_scrubbing #pool
+{
+       check_pool_status "$1" "scan" "scrub in progress since "
+       return $?
+}
+
+function is_pool_scrubbed #pool
+{
+       check_pool_status "$1" "scan" "scrub repaired"
+       return $?
+}
+
+function is_pool_scrub_stopped #pool
+{
+       check_pool_status "$1" "scan" "scrub canceled"
+       return $?
+}
+
+#
+# Use create_pool()/destroy_pool() to clean up the infomation in
+# in the given disk to avoid slice overlapping.
+#
+function cleanup_devices #vdevs
+{
+       typeset pool="foopool$$"
+
+       if poolexists $pool ; then
+               destroy_pool $pool
+       fi
+
+       create_pool $pool $@
+       destroy_pool $pool
+
+       return 0
+}
+
+#
+# Verify the rsh connectivity to each remote host in RHOSTS.
+#
+# Return 0 if remote host is accessible; otherwise 1.
+# $1 remote host name
+# $2 username
+#
+function verify_rsh_connect #rhost, username
+{
+       typeset rhost=$1
+       typeset username=$2
+       typeset rsh_cmd="$RSH -n"
+       typeset cur_user=
+
+       $GETENT hosts $rhost >/dev/null 2>&1
+       if (($? != 0)); then
+               log_note "$rhost cannot be found from" \
+                       "administrative database."
+               return 1
+       fi
+
+       $PING $rhost 3 >/dev/null 2>&1
+       if (($? != 0)); then
+               log_note "$rhost is not reachable."
+               return 1
+       fi
+
+       if ((${#username} != 0)); then
+               rsh_cmd="$rsh_cmd -l $username"
+               cur_user="given user \"$username\""
+       else
+               cur_user="current user \"`$LOGNAME`\""
+       fi
+
+        if ! $rsh_cmd $rhost $TRUE; then
+               log_note "$RSH to $rhost is not accessible" \
+                       "with $cur_user."
+               return 1
+       fi
+
+       return 0
+}
+
+#
+# Verify the remote host connection via rsh after rebooting
+# $1 remote host
+#
+function verify_remote
+{
+       rhost=$1
+
+       #
+       # The following loop waits for the remote system rebooting.
+       # Each iteration will wait for 150 seconds. there are
+       # total 5 iterations, so the total timeout value will
+       # be 12.5  minutes for the system rebooting. This number
+       # is an approxiate number.
+       #
+       typeset -i count=0
+       while ! verify_rsh_connect $rhost; do
+               sleep 150
+               ((count = count + 1))
+               if ((count > 5)); then
+                       return 1
+               fi
+       done
+       return 0
+}
+
+#
+# Replacement function for /usr/bin/rsh. This function will include
+# the /usr/bin/rsh and meanwhile return the execution status of the
+# last command.
+#
+# $1 usrname passing down to -l option of /usr/bin/rsh
+# $2 remote machine hostname
+# $3... command string
+#
+
+function rsh_status
+{
+       typeset ruser=$1
+       typeset rhost=$2
+       typeset -i ret=0
+       typeset cmd_str=""
+       typeset rsh_str=""
+
+       shift; shift
+       cmd_str="$@"
+
+       err_file=/tmp/${rhost}.$$.err
+       if ((${#ruser} == 0)); then
+               rsh_str="$RSH -n"
+       else
+               rsh_str="$RSH -n -l $ruser"
+       fi
+
+       $rsh_str $rhost /bin/ksh -c "'$cmd_str; \
+               print -u 2 \"status=\$?\"'" \
+               >/dev/null 2>$err_file
+       ret=$?
+       if (($ret != 0)); then
+               $CAT $err_file
+               $RM -f $std_file $err_file
+               log_fail  "$RSH itself failed with exit code $ret..."
+       fi
+
+        ret=$($GREP -v 'print -u 2' $err_file | $GREP 'status=' | \
+               $CUT -d= -f2)
+       (($ret != 0)) && $CAT $err_file >&2
+
+       $RM -f $err_file >/dev/null 2>&1
+       return $ret
+}
+
+#
+# Get the SUNWstc-fs-zfs package installation path in a remote host
+# $1 remote host name
+#
+function get_remote_pkgpath
+{
+       typeset rhost=$1
+       typeset pkgpath=""
+
+       pkgpath=$($RSH -n $rhost "$PKGINFO -l SUNWstc-fs-zfs | $GREP BASEDIR: |\
+                       $CUT -d: -f2")
+
+       $ECHO $pkgpath
+}
+
+#/**
+# A function to find and locate free disks on a system or from given
+# disks as the parameter. It works by locating disks that are in use
+# as swap devices and dump devices, and also disks listed in /etc/vfstab
+#
+# $@ given disks to find which are free, default is all disks in
+# the test system
+#
+# @return a string containing the list of available disks
+#*/
+function find_disks
+{
+       # Trust provided list, no attempt is made to locate unused devices.
+       if is_linux; then
+               $ECHO "$@"
+               return
+       fi
+
+
+       sfi=/tmp/swaplist.$$
+       dmpi=/tmp/dumpdev.$$
+       max_finddisksnum=${MAX_FINDDISKSNUM:-6}
+
+       $SWAP -l > $sfi
+       $DUMPADM > $dmpi 2>/dev/null
+
+# write an awk script that can process the output of format
+# to produce a list of disks we know about. Note that we have
+# to escape "$2" so that the shell doesn't interpret it while
+# we're creating the awk script.
+# -------------------
+       $CAT > /tmp/find_disks.awk <<EOF
+#!/bin/nawk -f
+       BEGIN { FS="."; }
+
+       /^Specify disk/{
+               searchdisks=0;
+       }
+
+       {
+               if (searchdisks && \$2 !~ "^$"){
+                       split(\$2,arr," ");
+                       print arr[1];
+               }
+       }
+
+       /^AVAILABLE DISK SELECTIONS:/{
+               searchdisks=1;
+       }
+EOF
+#---------------------
+
+       $CHMOD 755 /tmp/find_disks.awk
+       disks=${@:-$($ECHO "" | $FORMAT -e 2>/dev/null | /tmp/find_disks.awk)}
+       $RM /tmp/find_disks.awk
+
+       unused=""
+       for disk in $disks; do
+       # Check for mounted
+               $GREP "${disk}[sp]" /etc/mnttab >/dev/null
+               (($? == 0)) && continue
+       # Check for swap
+               $GREP "${disk}[sp]" $sfi >/dev/null
+               (($? == 0)) && continue
+       # check for dump device
+               $GREP "${disk}[sp]" $dmpi >/dev/null
+               (($? == 0)) && continue
+       # check to see if this disk hasn't been explicitly excluded
+       # by a user-set environment variable
+               $ECHO "${ZFS_HOST_DEVICES_IGNORE}" | $GREP "${disk}" > /dev/null
+               (($? == 0)) && continue
+               unused_candidates="$unused_candidates $disk"
+       done
+       $RM $sfi
+       $RM $dmpi
+
+# now just check to see if those disks do actually exist
+# by looking for a device pointing to the first slice in
+# each case. limit the number to max_finddisksnum
+       count=0
+       for disk in $unused_candidates; do
+               if [ -b $DEV_DSKDIR/${disk}s0 ]; then
+               if [ $count -lt $max_finddisksnum ]; then
+                       unused="$unused $disk"
+                       # do not impose limit if $@ is provided
+                       [[ -z $@ ]] && ((count = count + 1))
+               fi
+               fi
+       done
+
+# finally, return our disk list
+       $ECHO $unused
+}
+
+#
+# Add specified user to specified group
+#
+# $1 group name
+# $2 user name
+# $3 base of the homedir (optional)
+#
+function add_user #<group_name> <user_name> <basedir>
+{
+       typeset gname=$1
+       typeset uname=$2
+       typeset basedir=${3:-"/var/tmp"}
+
+       if ((${#gname} == 0 || ${#uname} == 0)); then
+               log_fail "group name or user name are not defined."
+       fi
+
+       log_must $USERADD -g $gname -d $basedir/$uname -m $uname
+
+       # Add new users to the same group and the command line utils.
+       # This allows them to be run out of the original users home
+       # directory as long as it permissioned to be group readable.
+       if is_linux; then
+               cmd_group=$(stat --format="%G" $ZFS)
+               log_must $USERMOD -a -G $cmd_group $uname
+       fi
+
+       return 0
+}
+
+#
+# Delete the specified user.
+#
+# $1 login name
+# $2 base of the homedir (optional)
+#
+function del_user #<logname> <basedir>
+{
+       typeset user=$1
+       typeset basedir=${2:-"/var/tmp"}
+
+       if ((${#user} == 0)); then
+               log_fail "login name is necessary."
+       fi
+
+       if $ID $user > /dev/null 2>&1; then
+               log_must $USERDEL $user
+       fi
+
+       [[ -d $basedir/$user ]] && $RM -fr $basedir/$user
+
+       return 0
+}
+
+#
+# Select valid gid and create specified group.
+#
+# $1 group name
+#
+function add_group #<group_name>
+{
+       typeset group=$1
+
+       if ((${#group} == 0)); then
+               log_fail "group name is necessary."
+       fi
+
+       # Assign 100 as the base gid, a larger value is selected for
+       # Linux because for many distributions 1000 and under are reserved.
+       if is_linux; then
+               while true; do
+                       $GROUPADD $group > /dev/null 2>&1
+                       typeset -i ret=$?
+                       case $ret in
+                               0) return 0 ;;
+                               *) return 1 ;;
+                       esac
+               done
+       else
+               typeset -i gid=100
+
+               while true; do
+                       $GROUPADD -g $gid $group > /dev/null 2>&1
+                       typeset -i ret=$?
+                       case $ret in
+                               0) return 0 ;;
+                               # The gid is not  unique
+                               4) ((gid += 1)) ;;
+                               *) return 1 ;;
+                       esac
+               done
+       fi
+}
+
+#
+# Delete the specified group.
+#
+# $1 group name
+#
+function del_group #<group_name>
+{
+       typeset grp=$1
+       if ((${#grp} == 0)); then
+               log_fail "group name is necessary."
+       fi
+
+       if is_linux; then
+               $GETENT group $grp > /dev/null 2>&1
+               typeset -i ret=$?
+               case $ret in
+                       # Group does not exist.
+                       2) return 0 ;;
+                       # Name already exists as a group name
+                       0) log_must $GROUPDEL $grp ;;
+                       *) return 1 ;;
+               esac
+       else
+               $GROUPMOD -n $grp $grp > /dev/null 2>&1
+               typeset -i ret=$?
+               case $ret in
+                       # Group does not exist.
+                       6) return 0 ;;
+                       # Name already exists as a group name
+                       9) log_must $GROUPDEL $grp ;;
+                       *) return 1 ;;
+               esac
+       fi
+
+       return 0
+}
+
+#
+# This function will return true if it's safe to destroy the pool passed
+# as argument 1. It checks for pools based on zvols and files, and also
+# files contained in a pool that may have a different mountpoint.
+#
+function safe_to_destroy_pool { # $1 the pool name
+
+       typeset pool=""
+       typeset DONT_DESTROY=""
+
+       # We check that by deleting the $1 pool, we're not
+       # going to pull the rug out from other pools. Do this
+       # by looking at all other pools, ensuring that they
+       # aren't built from files or zvols contained in this pool.
+
+       for pool in $($ZPOOL list -H -o name)
+       do
+               ALTMOUNTPOOL=""
+
+               # this is a list of the top-level directories in each of the
+               # files that make up the path to the files the pool is based on
+               FILEPOOL=$($ZPOOL status -v $pool | $GREP /$1/ | \
+                       $AWK '{print $1}')
+
+               # this is a list of the zvols that make up the pool
+               ZVOLPOOL=$($ZPOOL status -v $pool | $GREP "$ZVOL_DEVDIR/$1$" \
+                   | $AWK '{print $1}')
+
+               # also want to determine if it's a file-based pool using an
+               # alternate mountpoint...
+               POOL_FILE_DIRS=$($ZPOOL status -v $pool | \
+                                       $GREP / | $AWK '{print $1}' | \
+                                       $AWK -F/ '{print $2}' | $GREP -v "dev")
+
+               for pooldir in $POOL_FILE_DIRS
+               do
+                       OUTPUT=$($ZFS list -H -r -o mountpoint $1 | \
+                                       $GREP "${pooldir}$" | $AWK '{print $1}')
+
+                       ALTMOUNTPOOL="${ALTMOUNTPOOL}${OUTPUT}"
+               done
+
+
+               if [ ! -z "$ZVOLPOOL" ]
+               then
+                       DONT_DESTROY="true"
+                       log_note "Pool $pool is built from $ZVOLPOOL on $1"
+               fi
+
+               if [ ! -z "$FILEPOOL" ]
+               then
+                       DONT_DESTROY="true"
+                       log_note "Pool $pool is built from $FILEPOOL on $1"
+               fi
+
+               if [ ! -z "$ALTMOUNTPOOL" ]
+               then
+                       DONT_DESTROY="true"
+                       log_note "Pool $pool is built from $ALTMOUNTPOOL on $1"
+               fi
+       done
+
+       if [ -z "${DONT_DESTROY}" ]
+       then
+               return 0
+       else
+               log_note "Warning: it is not safe to destroy $1!"
+               return 1
+       fi
+}
+
+#
+# Get the available ZFS compression options
+# $1 option type zfs_set|zfs_compress
+#
+function get_compress_opts
+{
+       typeset COMPRESS_OPTS
+       typeset GZIP_OPTS="gzip gzip-1 gzip-2 gzip-3 gzip-4 gzip-5 \
+                       gzip-6 gzip-7 gzip-8 gzip-9"
+
+       if [[ $1 == "zfs_compress" ]] ; then
+               COMPRESS_OPTS="on lzjb"
+       elif [[ $1 == "zfs_set" ]] ; then
+               COMPRESS_OPTS="on off lzjb"
+       fi
+       typeset valid_opts="$COMPRESS_OPTS"
+       $ZFS get 2>&1 | $GREP gzip >/dev/null 2>&1
+       if [[ $? -eq 0 ]]; then
+               valid_opts="$valid_opts $GZIP_OPTS"
+       fi
+       $ECHO "$valid_opts"
+}
+
+#
+# Verify zfs operation with -p option work as expected
+# $1 operation, value could be create, clone or rename
+# $2 dataset type, value could be fs or vol
+# $3 dataset name
+# $4 new dataset name
+#
+function verify_opt_p_ops
+{
+       typeset ops=$1
+       typeset datatype=$2
+       typeset dataset=$3
+       typeset newdataset=$4
+
+       if [[ $datatype != "fs" && $datatype != "vol" ]]; then
+               log_fail "$datatype is not supported."
+       fi
+
+       # check parameters accordingly
+       case $ops in
+               create)
+                       newdataset=$dataset
+                       dataset=""
+                       if [[ $datatype == "vol" ]]; then
+                               ops="create -V $VOLSIZE"
+                       fi
+                       ;;
+               clone)
+                       if [[ -z $newdataset ]]; then
+                               log_fail "newdataset should not be empty" \
+                                       "when ops is $ops."
+                       fi
+                       log_must datasetexists $dataset
+                       log_must snapexists $dataset
+                       ;;
+               rename)
+                       if [[ -z $newdataset ]]; then
+                               log_fail "newdataset should not be empty" \
+                                       "when ops is $ops."
+                       fi
+                       log_must datasetexists $dataset
+                       log_mustnot snapexists $dataset
+                       ;;
+               *)
+                       log_fail "$ops is not supported."
+                       ;;
+       esac
+
+       # make sure the upper level filesystem does not exist
+       if datasetexists ${newdataset%/*} ; then
+               log_must $ZFS destroy -rRf ${newdataset%/*}
+       fi
+
+       # without -p option, operation will fail
+       log_mustnot $ZFS $ops $dataset $newdataset
+       log_mustnot datasetexists $newdataset ${newdataset%/*}
+
+       # with -p option, operation should succeed
+       log_must $ZFS $ops -p $dataset $newdataset
+       block_device_wait
+
+       if ! datasetexists $newdataset ; then
+               log_fail "-p option does not work for $ops"
+       fi
+
+       # when $ops is create or clone, redo the operation still return zero
+       if [[ $ops != "rename" ]]; then
+               log_must $ZFS $ops -p $dataset $newdataset
+       fi
+
+       return 0
+}
+
+#
+# Get configuration of pool
+# $1 pool name
+# $2 config name
+#
+function get_config
+{
+       typeset pool=$1
+       typeset config=$2
+       typeset alt_root
+
+       if ! poolexists "$pool" ; then
+               return 1
+       fi
+       alt_root=$($ZPOOL list -H $pool | $AWK '{print $NF}')
+       if [[ $alt_root == "-" ]]; then
+               value=$($ZDB -C $pool | $GREP "$config:" | $AWK -F: \
+                   '{print $2}')
+       else
+               value=$($ZDB -e $pool | $GREP "$config:" | $AWK -F: \
+                   '{print $2}')
+       fi
+       if [[ -n $value ]] ; then
+               value=${value#'}
+               value=${value%'}
+       fi
+       echo $value
+
+       return 0
+}
+
+#
+# Privated function. Random select one of items from arguments.
+#
+# $1 count
+# $2-n string
+#
+function _random_get
+{
+       typeset cnt=$1
+       shift
+
+       typeset str="$@"
+       typeset -i ind
+       ((ind = RANDOM % cnt + 1))
+
+       typeset ret=$($ECHO "$str" | $CUT -f $ind -d ' ')
+       $ECHO $ret
+}
+
+#
+# Random select one of item from arguments which include NONE string
+#
+function random_get_with_non
+{
+       typeset -i cnt=$#
+       ((cnt =+ 1))
+
+       _random_get "$cnt" "$@"
+}
+
+#
+# Random select one of item from arguments which doesn't include NONE string
+#
+function random_get
+{
+       _random_get "$#" "$@"
+}
+
+#
+# Detect if the current system support slog
+#
+function verify_slog_support
+{
+       typeset dir=/tmp/disk.$$
+       typeset pool=foo.$$
+       typeset vdev=$dir/a
+       typeset sdev=$dir/b
+
+       $MKDIR -p $dir
+       $MKFILE 64M $vdev $sdev
+
+       typeset -i ret=0
+       if ! $ZPOOL create -n $pool $vdev log $sdev > /dev/null 2>&1; then
+               ret=1
+       fi
+       $RM -r $dir
+
+       return $ret
+}
+
+#
+# The function will generate a dataset name with specific length
+# $1, the length of the name
+# $2, the base string to construct the name
+#
+function gen_dataset_name
+{
+       typeset -i len=$1
+       typeset basestr="$2"
+       typeset -i baselen=${#basestr}
+       typeset -i iter=0
+       typeset l_name=""
+
+       if ((len % baselen == 0)); then
+               ((iter = len / baselen))
+       else
+               ((iter = len / baselen + 1))
+       fi
+       while ((iter > 0)); do
+               l_name="${l_name}$basestr"
+
+               ((iter -= 1))
+       done
+
+       $ECHO $l_name
+}
+
+#
+# Get cksum tuple of dataset
+# $1 dataset name
+#
+# sample zdb output:
+# Dataset data/test [ZPL], ID 355, cr_txg 2413856, 31.0K, 7 objects, rootbp
+# DVA[0]=<0:803046400:200> DVA[1]=<0:81199000:200> [L0 DMU objset] fletcher4
+# lzjb LE contiguous unique double size=800L/200P birth=2413856L/2413856P
+# fill=7 cksum=11ce125712:643a9c18ee2:125e25238fca0:254a3f74b59744
+function datasetcksum
+{
+       typeset cksum
+       $SYNC
+       cksum=$($ZDB -vvv $1 | $GREP "^Dataset $1 \[" | $GREP "cksum" \
+               | $AWK -F= '{print $7}')
+       $ECHO $cksum
+}
+
+#
+# Get cksum of file
+# #1 file path
+#
+function checksum
+{
+       typeset cksum
+       cksum=$($CKSUM $1 | $AWK '{print $1}')
+       $ECHO $cksum
+}
+
+#
+# Get the given disk/slice state from the specific field of the pool
+#
+function get_device_state #pool disk field("", "spares","logs")
+{
+       typeset pool=$1
+       typeset disk=${2#$DEV_DSKDIR/}
+       typeset field=${3:-$pool}
+
+       state=$($ZPOOL status -v "$pool" 2>/dev/null | \
+               $NAWK -v device=$disk -v pool=$pool -v field=$field \
+               'BEGIN {startconfig=0; startfield=0; }
+               /config:/ {startconfig=1}
+               (startconfig==1) && ($1==field) {startfield=1; next;}
+               (startfield==1) && ($1==device) {print $2; exit;}
+               (startfield==1) &&
+               ($1==field || $1 ~ "^spares$" || $1 ~ "^logs$") {startfield=0}')
+       echo $state
+}
+
+
+#
+# print the given directory filesystem type
+#
+# $1 directory name
+#
+function get_fstype
+{
+       typeset dir=$1
+
+       if [[ -z $dir ]]; then
+               log_fail "Usage: get_fstype <directory>"
+       fi
+
+       #
+       #  $ df -n /
+       #  /              : ufs
+       #
+       $DF -n $dir | $AWK '{print $3}'
+}
+
+#
+# Given a disk, label it to VTOC regardless what label was on the disk
+# $1 disk
+#
+function labelvtoc
+{
+       typeset disk=$1
+       if [[ -z $disk ]]; then
+               log_fail "The disk name is unspecified."
+       fi
+       typeset label_file=/var/tmp/labelvtoc.$$
+       typeset arch=$($UNAME -p)
+
+       if is_linux; then
+               log_note "Currently unsupported by the test framework"
+               return 1
+       fi
+
+       if [[ $arch == "i386" ]]; then
+               $ECHO "label" > $label_file
+               $ECHO "0" >> $label_file
+               $ECHO "" >> $label_file
+               $ECHO "q" >> $label_file
+               $ECHO "q" >> $label_file
+
+               $FDISK -B $disk >/dev/null 2>&1
+               # wait a while for fdisk finishes
+               $SLEEP 60
+       elif [[ $arch == "sparc" ]]; then
+               $ECHO "label" > $label_file
+               $ECHO "0" >> $label_file
+               $ECHO "" >> $label_file
+               $ECHO "" >> $label_file
+               $ECHO "" >> $label_file
+               $ECHO "q" >> $label_file
+       else
+               log_fail "unknown arch type"
+       fi
+
+       $FORMAT -e -s -d $disk -f $label_file
+       typeset -i ret_val=$?
+       $RM -f $label_file
+       #
+       # wait the format to finish
+       #
+       $SLEEP 60
+       if ((ret_val != 0)); then
+               log_fail "unable to label $disk as VTOC."
+       fi
+
+       return 0
+}
+
+#
+# check if the system was installed as zfsroot or not
+# return: 0 ture, otherwise false
+#
+function is_zfsroot
+{
+       $DF -n / | $GREP zfs > /dev/null 2>&1
+       return $?
+}
+
+#
+# get the root filesystem name if it's zfsroot system.
+#
+# return: root filesystem name
+function get_rootfs
+{
+       typeset rootfs=""
+       rootfs=$($AWK '{if ($2 == "/" && $3 == "zfs") print $1}' \
+               /etc/mnttab)
+       if [[ -z "$rootfs" ]]; then
+               log_fail "Can not get rootfs"
+       fi
+       $ZFS list $rootfs > /dev/null 2>&1
+       if (($? == 0)); then
+               $ECHO $rootfs
+       else
+               log_fail "This is not a zfsroot system."
+       fi
+}
+
+#
+# get the rootfs's pool name
+# return:
+#       rootpool name
+#
+function get_rootpool
+{
+       typeset rootfs=""
+       typeset rootpool=""
+       rootfs=$($AWK '{if ($2 == "/" && $3 =="zfs") print $1}' \
+                /etc/mnttab)
+       if [[ -z "$rootfs" ]]; then
+               log_fail "Can not get rootpool"
+       fi
+       $ZFS list $rootfs > /dev/null 2>&1
+       if (($? == 0)); then
+               rootpool=`$ECHO $rootfs | awk -F\/ '{print $1}'`
+               $ECHO $rootpool
+       else
+               log_fail "This is not a zfsroot system."
+       fi
+}
+
+#
+# Get the sub string from specified source string
+#
+# $1 source string
+# $2 start position. Count from 1
+# $3 offset
+#
+function get_substr #src_str pos offset
+{
+       typeset pos offset
+
+       $ECHO $1 | \
+               $NAWK -v pos=$2 -v offset=$3 '{print substr($0, pos, offset)}'
+}
+
+#
+# Check if the given device is physical device
+#
+function is_physical_device #device
+{
+       typeset device=${1#$DEV_DSKDIR}
+       device=${device#$DEV_RDSKDIR}
+
+       if is_linux; then
+               [[ -b "$DEV_DSKDIR/$device" ]] && \
+               [[ -f /sys/module/loop/parameters/max_part ]]
+               return $?
+       else
+               $ECHO $device | $EGREP "^c[0-F]+([td][0-F]+)+$" > /dev/null 2>&1
+               return $?
+       fi
+}
+
+#
+# Check if the given device is a real device (ie SCSI device)
+#
+function is_real_device #disk
+{
+       typeset disk=$1
+       [[ -z $disk ]] && log_fail "No argument for disk given."
+
+       if is_linux; then
+               $LSBLK $DEV_RDSKDIR/$disk -o TYPE | $EGREP disk > /dev/null 2>&1
+               return $?
+       fi
+}
+
+#
+# Check if the given device is a loop device
+#
+function is_loop_device #disk
+{
+       typeset disk=$1
+       [[ -z $disk ]] && log_fail "No argument for disk given."
+
+       if is_linux; then
+               $LSBLK $DEV_RDSKDIR/$disk -o TYPE | $EGREP loop > /dev/null 2>&1
+               return $?
+       fi
+}
+
+#
+# Check if the given device is a multipath device and if there is a sybolic
+# link to a device mapper and to a disk
+# Currently no support for dm devices alone without multipath
+#
+function is_mpath_device #disk
+{
+       typeset disk=$1
+       [[ -z $disk ]] && log_fail "No argument for disk given."
+
+       if is_linux; then
+               $LSBLK $DEV_MPATHDIR/$disk -o TYPE | $EGREP mpath > /dev/null 2>&1
+               if (($? == 0)); then
+                       $READLINK $DEV_MPATHDIR/$disk > /dev/null 2>&1
+                       return $?
+               else
+                       return $?
+               fi
+       fi
+}
+
+# Set the slice prefix for disk partitioning depending
+# on whether the device is a real, multipath, or loop device.
+# Currently all disks have to be of the same type, so only
+# checks first disk to determine slice prefix.
+#
+function set_slice_prefix
+{
+       typeset disk
+       typeset -i i=0
+
+       if is_linux; then
+               while (( i < $DISK_ARRAY_NUM )); do
+                       disk="$($ECHO $DISKS | $NAWK '{print $(i + 1)}')"
+                       if ( is_mpath_device $disk ) && [[ -z $($ECHO $disk | awk 'substr($1,18,1)\
+                            ~ /^[[:digit:]]+$/') ]] || ( is_real_device $disk ); then
+                               export SLICE_PREFIX=""
+                               return 0
+                       elif ( is_mpath_device $disk || is_loop_device $disk ); then
+                               export SLICE_PREFIX="p"
+                               return 0
+                       else
+                               log_fail "$disk not supported for partitioning."
+                       fi
+                       (( i = i + 1))
+               done
+       fi
+}
+
+#
+# Set the directory path of the listed devices in $DISK_ARRAY_NUM
+# Currently all disks have to be of the same type, so only
+# checks first disk to determine device directory
+# default = /dev (linux)
+# real disk = /dev (linux)
+# multipath device = /dev/mapper (linux)
+#
+function set_device_dir
+{
+       typeset disk
+       typeset -i i=0
+
+       if is_linux; then
+               while (( i < $DISK_ARRAY_NUM )); do
+                       disk="$($ECHO $DISKS | $NAWK '{print $(i + 1)}')"
+                       if is_mpath_device $disk; then
+                               export DEV_DSKDIR=$DEV_MPATHDIR
+                               return 0
+                       else
+                               export DEV_DSKDIR=$DEV_RDSKDIR
+                               return 0
+                       fi
+                       (( i = i + 1))
+               done
+       else
+               export DEV_DSKDIR=$DEV_RDSKDIR
+       fi
+}
+
+#
+# Get the directory path of given device
+#
+function get_device_dir #device
+{
+       typeset device=$1
+
+       if ! $(is_physical_device $device) ; then
+               if [[ $device != "/" ]]; then
+                       device=${device%/*}
+               fi
+               if [[ -b "$DEV_DSKDIR/$device" ]]; then
+                       device="$DEV_DSKDIR"
+               fi
+               $ECHO $device
+       else
+               $ECHO "$DEV_DSKDIR"
+       fi
+}
+
+#
+# Get the package name
+#
+function get_package_name
+{
+       typeset dirpath=${1:-$STC_NAME}
+
+       echo "SUNWstc-${dirpath}" | /usr/bin/sed -e "s/\//-/g"
+}
+
+#
+# Get the word numbers from a string separated by white space
+#
+function get_word_count
+{
+       $ECHO $1 | $WC -w
+}
+
+#
+# To verify if the require numbers of disks is given
+#
+function verify_disk_count
+{
+       typeset -i min=${2:-1}
+
+       typeset -i count=$(get_word_count "$1")
+
+       if ((count < min)); then
+               log_untested "A minimum of $min disks is required to run." \
+                       " You specified $count disk(s)"
+       fi
+}
+
+function ds_is_volume
+{
+       typeset type=$(get_prop type $1)
+       [[ $type = "volume" ]] && return 0
+       return 1
+}
+
+function ds_is_filesystem
+{
+       typeset type=$(get_prop type $1)
+       [[ $type = "filesystem" ]] && return 0
+       return 1
+}
+
+function ds_is_snapshot
+{
+       typeset type=$(get_prop type $1)
+       [[ $type = "snapshot" ]] && return 0
+       return 1
+}
+
+#
+# Check if Trusted Extensions are installed and enabled
+#
+function is_te_enabled
+{
+       $SVCS -H -o state labeld 2>/dev/null | $GREP "enabled"
+       if (($? != 0)); then
+               return 1
+       else
+               return 0
+       fi
+}
+
+# Utility function to determine if a system has multiple cpus.
+function is_mp
+{
+       if is_linux; then
+               (($($NPROC) > 1))
+       else
+               (($($PSRINFO | $WC -l) > 1))
+       fi
+
+       return $?
+}
+
+function get_cpu_freq
+{
+       if is_linux; then
+               lscpu | $AWK '/CPU MHz/ { print $3 }'
+       else
+               $PSRINFO -v 0 | $AWK '/processor operates at/ {print $6}'
+       fi
+}
+
+# Run the given command as the user provided.
+function user_run
+{
+       typeset user=$1
+       shift
+
+       log_note "user:$user $@"
+       eval \$SU \$user -c \"$@\" > /tmp/out 2>/tmp/err
+       return $?
+}
+
+#
+# Check if the pool contains the specified vdevs
+#
+# $1 pool
+# $2..n <vdev> ...
+#
+# Return 0 if the vdevs are contained in the pool, 1 if any of the specified
+# vdevs is not in the pool, and 2 if pool name is missing.
+#
+function vdevs_in_pool
+{
+       typeset pool=$1
+       typeset vdev
+
+       if [[ -z $pool ]]; then
+               log_note "Missing pool name."
+               return 2
+       fi
+
+       shift
+
+       typeset tmpfile=$($MKTEMP)
+       $ZPOOL list -Hv "$pool" >$tmpfile
+       for vdev in $@; do
+               $GREP -w ${vdev##*/} $tmpfile >/dev/null 2>&1
+               [[ $? -ne 0 ]] && return 1
+       done
+
+       $RM -f $tmpfile
+
+       return 0;
+}
+
+function get_max
+{
+       typeset -l i max=$1
+       shift
+
+       for i in "$@"; do
+               max=$(echo $((max > i ? max : i)))
+       done
+
+       echo $max
+}
+
+function get_min
+{
+       typeset -l i min=$1
+       shift
+
+       for i in "$@"; do
+               min=$(echo $((min < i ? min : i)))
+       done
+
+       echo $min
+}
+
+#
+# Wait for newly created block devices to have their minors created.
+#
+function block_device_wait
+{
+       if is_linux; then
+               $UDEVADM trigger
+               $UDEVADM settle
+       fi
+}
+
+#
+# Synchronize all the data in pool
+#
+# $1 pool name
+#
+function sync_pool #pool
+{
+       typeset pool=${1:-$TESTPOOL}
+
+       log_must $SYNC
+       log_must $SLEEP 2
+       # Flush all the pool data.
+       typeset -i ret
+       $ZPOOL scrub $pool >/dev/null 2>&1
+       ret=$?
+       (( $ret != 0 )) && \
+       log_fail "$ZPOOL scrub $pool failed."
+
+       while ! is_pool_scrubbed $pool; do
+               if is_pool_resilvered $pool ; then
+                       log_fail "$pool should not be resilver completed."
+               fi
+               log_must $SLEEP 2
+       done
+}
diff --git a/zfs/tests/zfs-tests/include/math.shlib b/zfs/tests/zfs-tests/include/math.shlib
new file mode 100644 (file)
index 0000000..38479d3
--- /dev/null
@@ -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
+}
diff --git a/zfs/tests/zfs-tests/include/properties.shlib b/zfs/tests/zfs-tests/include/properties.shlib
new file mode 100644 (file)
index 0000000..c495eec
--- /dev/null
@@ -0,0 +1,64 @@
+#
+# 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' 'sha512'
+    'edonr' 'skein' 'noparity')
+
+#
+# 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
+}
diff --git a/zfs/tests/zfs-tests/tests/Makefile.am b/zfs/tests/zfs-tests/tests/Makefile.am
new file mode 100644 (file)
index 0000000..f749479
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = functional perf stress
diff --git a/zfs/tests/zfs-tests/tests/functional/Makefile.am b/zfs/tests/zfs-tests/tests/functional/Makefile.am
new file mode 100644 (file)
index 0000000..ffba71b
--- /dev/null
@@ -0,0 +1,59 @@
+SUBDIRS = \
+       acl \
+       atime \
+       bootfs \
+       cache \
+       cachefile \
+       casenorm \
+       checksum \
+       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 \
+       raidz \
+       redundancy \
+       refquota \
+       refreserv \
+       rename_dirs \
+       replacement \
+       reservation \
+       rootpool \
+       rsend \
+       scrub_mirror \
+       slog \
+       snapshot \
+       snapused \
+       sparse \
+       threadsappend \
+       truncate \
+       upgrade \
+       userquota \
+       vdev_zaps \
+       write_dirs \
+       xattr \
+       zvol
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/Makefile.am b/zfs/tests/zfs-tests/tests/functional/acl/Makefile.am
new file mode 100644 (file)
index 0000000..6a02583
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/acl
+dist_pkgdata_SCRIPTS = \
+       acl.cfg \
+       acl_common.kshlib
+
+SUBDIRS = posix
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/acl.cfg b/zfs/tests/zfs-tests/tests/functional/acl/acl.cfg
new file mode 100644 (file)
index 0000000..fbebe38
--- /dev/null
@@ -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
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/acl_common.kshlib b/zfs/tests/zfs-tests/tests/functional/acl/acl_common.kshlib
new file mode 100644 (file)
index 0000000..1ebc1cd
--- /dev/null
@@ -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
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/posix/Makefile.am b/zfs/tests/zfs-tests/tests/functional/acl/posix/Makefile.am
new file mode 100644 (file)
index 0000000..dcf2788
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/acl/posix
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       posix_001_pos.ksh \
+       posix_002_pos.ksh \
+       posix_003_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/posix/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/acl/posix/cleanup.ksh
new file mode 100755 (executable)
index 0000000..bb58a8c
--- /dev/null
@@ -0,0 +1,33 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/acl/acl_common.kshlib
+
+cleanup_user_group
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/posix/posix_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/acl/posix/posix_001_pos.ksh
new file mode 100755 (executable)
index 0000000..25c250f
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# DESCRIPTION:
+#      Verify that user can access file/directory if acltype=posixacl.
+#
+# STRATEGY:
+#      1. Test access to file (mode=rw-)
+#         a. Can modify file
+#         b. Can't create new file
+#         b. Can't execute file
+#
+
+verify_runnable "both"
+log_assert "Verify acltype=posixacl works on file"
+
+# Test access to FILE
+log_note "Testing access to FILE"
+log_must $TOUCH $TESTDIR/file.0
+log_must $SETFACL -m g:zfsgrp:rw $TESTDIR/file.0
+$GETFACL $TESTDIR/file.0 2> /dev/null | $EGREP -q "^group:zfsgrp:rw-$"
+if [ "$?" -eq "0" ]; then
+       # Should be able to write to file
+       log_must $SU staff1 -c "$ECHO \"$ECHO test > /dev/null\" > $TESTDIR/file.0"
+
+       # Should NOT be able to create new file
+       log_mustnot $SU staff1 -c "$TOUCH $TESTDIR/file.1"
+
+       # Root should be able to run file, but not user
+       chmod +x $TESTDIR/file.0
+       log_must $TESTDIR/file.0
+       log_mustnot $SU staff1 -c $TESTDIR/file.0
+
+       log_pass "POSIX ACL mode works on files"
+else
+       log_fail "Group 'zfsgrp' does not have 'rw' as specified"
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/posix/posix_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/acl/posix/posix_002_pos.ksh
new file mode 100755 (executable)
index 0000000..fcd0114
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# DESCRIPTION:
+#      Verify that user can access file/directory if acltype=posixacl.
+#
+# STRATEGY:
+#      1. Test access to directory (mode=-wx)
+#         a. Can create file in dir
+#         b. Can't list directory
+#
+
+verify_runnable "both"
+log_assert "Verify acltype=posixacl works on directory"
+
+# Test access to DIRECTORY
+log_note "Testing access to DIRECTORY"
+log_must $MKDIR $TESTDIR/dir.0
+log_must $SETFACL -m g:zfsgrp:wx $TESTDIR/dir.0
+$GETFACL $TESTDIR/dir.0 2> /dev/null | $EGREP -q "^group:zfsgrp:-wx$"
+if [ "$?" -eq "0" ]; then
+       # Should be able to create file in directory
+       log_must $SU staff1 -c "$TOUCH $TESTDIR/dir.0/file.0"
+
+       # Should NOT be able to list files in directory
+       log_mustnot $SU staff1 -c "$LS -l $TESTDIR/dir.0"
+
+       log_pass "POSIX ACL mode works on directories"
+else
+       log_fail "Group 'zfsgrp' does not have 'rwx' as specified"
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/posix/posix_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/acl/posix/posix_003_pos.ksh
new file mode 100755 (executable)
index 0000000..535214f
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify that ACLs survive remount.
+#      Regression test for https://github.com/zfsonlinux/zfs/issues/4520
+#
+# STRATEGY:
+#      1. Test presence of default and regular ACLs after remount
+#         a. Can set and list ACL before remount
+#         b. Can list ACL after remount
+#
+
+verify_runnable "both"
+log_assert "Verify regular and default POSIX ACLs survive  remount"
+
+typeset output=/tmp/zfs-posixacl.$$
+typeset acl_str1="^group:${ZFS_ACL_STAFF_GROUP}:-wx$"
+typeset acl_str2="^default:group:${ZFS_ACL_STAFF_GROUP}:-wx$"
+typeset ACLDIR="${TESTDIR}/dir.1"
+
+log_note "Testing access to DIRECTORY"
+log_must $MKDIR $ACLDIR
+log_must $SETFACL -m g:${ZFS_ACL_STAFF_GROUP}:wx $ACLDIR
+log_must $SETFACL -d -m g:${ZFS_ACL_STAFF_GROUP}:wx $ACLDIR
+$GETFACL $ACLDIR 2> /dev/null | $EGREP -q "${acl_str1}"
+if [ "$?" -eq "0" ]; then
+       $GETFACL $ACLDIR 2> /dev/null | $EGREP -q "${acl_str2}"
+fi
+
+if [ "$?" -eq "0" ]; then
+       log_must $ZFS unmount $TESTPOOL/$TESTFS
+       log_must $ZFS mount $TESTPOOL/$TESTFS
+       log_must eval '$GETFACL $ACLDIR 2> /dev/null | $EGREP -q "${acl_str1}"'
+       log_must eval '$GETFACL $ACLDIR 2> /dev/null | $EGREP -q "${acl_str2}"'
+       log_pass "POSIX ACLs survive remount"
+else
+       log_fail "Group '${ZFS_ACL_STAFF_GROUP}' does not have 'rwx'"
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/acl/posix/setup.ksh b/zfs/tests/zfs-tests/tests/functional/acl/posix/setup.ksh
new file mode 100755 (executable)
index 0000000..dc17f7c
--- /dev/null
@@ -0,0 +1,48 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/acl/acl_common.kshlib
+
+log_must $GETFACL --version
+log_must $SETFACL --version
+
+cleanup_user_group
+
+# Create staff group and add user to it
+log_must add_group $ZFS_ACL_STAFF_GROUP
+log_must add_user $ZFS_ACL_STAFF_GROUP $ZFS_ACL_STAFF1
+
+DISK=${DISKS%% *}
+default_setup_noexit $DISK
+log_must $CHMOD 777 $TESTDIR
+
+# Use POSIX ACLs on filesystem
+log_must $ZFS set acltype=posixacl $TESTPOOL/$TESTFS
+log_must $ZFS set xattr=sa $TESTPOOL/$TESTFS
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/atime/Makefile.am b/zfs/tests/zfs-tests/tests/functional/atime/Makefile.am
new file mode 100644 (file)
index 0000000..e072925
--- /dev/null
@@ -0,0 +1,9 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/atime
+dist_pkgdata_SCRIPTS = \
+       atime.cfg \
+       atime_common.kshlib \
+       cleanup.ksh \
+       setup.ksh \
+       atime_001_pos.ksh \
+       atime_002_neg.ksh \
+       atime_003_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/atime/atime.cfg b/zfs/tests/zfs-tests/tests/functional/atime/atime.cfg
new file mode 100644 (file)
index 0000000..c1532eb
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+export TESTCLONE=testclone$$
+export TESTSNAP=testsnap$$
+
+export TESTFILE=testfile
diff --git a/zfs/tests/zfs-tests/tests/functional/atime/atime_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/atime/atime_001_pos.ksh
new file mode 100755 (executable)
index 0000000..5db0eaf
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/atime/atime_common.kshlib
+
+#
+# DESCRIPTION:
+# When atime=on, verify the access time for files is updated when read. It
+# is available to fs and clone. To snapshot, it is unavailable.
+#
+# STRATEGY:
+# 1. Create pool and fs.
+# 2. Create '$TESTFILE' for fs.
+# 3. Create snapshot and clone.
+# 4. Setting atime=on on datasets except snapshot, and read '$TESTFILE'.
+# 5. Expect the access time is updated on datasets except snapshot.
+#
+
+verify_runnable "both"
+
+log_assert "Setting atime=on, the access time for files is updated when read."
+log_onexit cleanup
+
+#
+# Create $TESTFILE, snapshot and clone.
+#
+setup_snap_clone
+
+for dst in $TESTPOOL/$TESTFS $TESTPOOL/$TESTCLONE $TESTPOOL/$TESTFS@$TESTSNAP
+do
+       typeset mtpt=$(get_prop mountpoint $dst)
+
+       if [[ $dst == $TESTPOOL/$TESTFS@$TESTSNAP ]]; then
+               mtpt=$(snapshot_mountpoint $dst)
+               log_mustnot check_atime_updated $mtpt/$TESTFILE
+       else
+               log_must $ZFS set atime=on $dst
+               log_must $ZFS set relatime=off $dst
+               log_must check_atime_updated $mtpt/$TESTFILE
+               log_must check_atime_updated $mtpt/$TESTFILE
+       fi
+done
+
+log_pass "Verify the property atime=on passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/atime/atime_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/atime/atime_002_neg.ksh
new file mode 100755 (executable)
index 0000000..06a35cc
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/atime/atime_common.kshlib
+
+#
+# DESCRIPTION:
+# When atime=off, verify the access time for files is not updated when read.
+# It is available to pool, fs snapshot and clone.
+#
+# STRATEGY:
+# 1. Create pool, fs.
+# 2. Create '$TESTFILE' for fs.
+# 3. Create snapshot and clone.
+# 4. Setting atime=off on dataset and read '$TESTFILE'.
+# 5. Verify the access time is not updated.
+#
+
+verify_runnable "both"
+
+log_assert "Setting atime=off, the access time for files will not be updated \
+       when read."
+log_onexit cleanup
+
+#
+# Create $TESTFILE, snapshot and clone.
+#
+setup_snap_clone
+
+for dst in $TESTPOOL/$TESTFS $TESTPOOL/$TESTCLONE $TESTPOOL/$TESTFS@$TESTSNAP
+do
+       typeset mtpt=$(get_prop mountpoint $dst)
+
+       if [[ $dst == $TESTPOOL/$TESTFS@$TESTSNAP ]]; then
+               mtpt=$(snapshot_mountpoint $dst)
+       else
+               log_must $ZFS set atime=off $dst
+       fi
+
+       log_mustnot check_atime_updated $mtpt/$TESTFILE
+done
+
+log_pass "Verify the property atime=off passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/atime/atime_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/atime/atime_003_pos.ksh
new file mode 100755 (executable)
index 0000000..359f4a0
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/atime/atime_common.kshlib
+
+#
+# DESCRIPTION:
+# When relatime=on, verify the access time for files is updated when first
+# read but not on second.
+# It is available to fs and clone. To snapshot, it is unavailable.
+#
+# STRATEGY:
+# 1. Create pool and fs.
+# 2. Create '$TESTFILE' for fs.
+# 3. Create snapshot and clone.
+# 4. Setting atime=on and relatime=on on datasets.
+# 5. Expect the access time is updated for first read but not on second.
+#
+
+verify_runnable "both"
+
+log_assert "Setting relatime=on, the access time for files is updated when \
+       when read the first time, but not second time."
+log_onexit cleanup
+
+#
+# Create $TESTFILE, snapshot and clone.
+#
+setup_snap_clone
+
+for dst in $TESTPOOL/$TESTFS $TESTPOOL/$TESTCLONE $TESTPOOL/$TESTFS@$TESTSNAP
+do
+       typeset mtpt=$(get_prop mountpoint $dst)
+
+       if [[ $dst == $TESTPOOL/$TESTFS@$TESTSNAP ]]; then
+               mtpt=$(snapshot_mountpoint $dst)
+               log_mustnot check_atime_updated $mtpt/$TESTFILE
+       else
+               log_must $ZFS set atime=on $dst
+               log_must $ZFS set relatime=on $dst
+               log_must check_atime_updated $mtpt/$TESTFILE
+               log_mustnot check_atime_updated $mtpt/$TESTFILE
+       fi
+done
+
+log_pass "Verify the property relatime=on passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/atime/atime_common.kshlib b/zfs/tests/zfs-tests/tests/functional/atime/atime_common.kshlib
new file mode 100644 (file)
index 0000000..c2f90eb
--- /dev/null
@@ -0,0 +1,78 @@
+#
+# 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.
+#
+
+. $STF_SUITE/tests/functional/atime/atime.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Check if the access time for specified file is updated.
+#
+# $1 Given an absolute path to a file name
+#
+# Return value:
+#      0 -> The access time is updated.
+#      1 -> The access time is not updated.
+#
+function check_atime_updated
+{
+       typeset filename=$1
+
+       if is_linux; then
+               typeset before=$(stat -c %X $filename)
+               sleep 2
+       else
+               typeset before=$($LS -Eu $filename | $AWK '{print $7}')
+       fi
+
+       log_must $CAT $filename
+
+       if is_linux; then
+               typeset after=$(stat -c %X $filename)
+       else
+               typeset after=$($LS -Eu $filename | $AWK '{print $7}')
+       fi
+
+       if [[ $before != $after ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
+
+function setup_snap_clone
+{
+       # Create two file to verify snapshot.
+       log_must $TOUCH $TESTDIR/$TESTFILE
+
+       create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
+       create_clone $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTCLONE
+}
+
+function cleanup
+{
+       destroy_clone $TESTPOOL/$TESTCLONE
+       destroy_snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/atime/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/atime/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/atime/setup.ksh b/zfs/tests/zfs-tests/tests/functional/atime/setup.ksh
new file mode 100755 (executable)
index 0000000..0c5d38f
--- /dev/null
@@ -0,0 +1,31 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/Makefile.am b/zfs/tests/zfs-tests/tests/functional/bootfs/Makefile.am
new file mode 100644 (file)
index 0000000..901c039
--- /dev/null
@@ -0,0 +1,12 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/bootfs
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       bootfs_001_pos.ksh \
+       bootfs_002_neg.ksh \
+       bootfs_003_pos.ksh \
+       bootfs_004_neg.ksh \
+       bootfs_005_neg.ksh \
+       bootfs_006_pos.ksh \
+       bootfs_007_neg.ksh \
+       bootfs_008_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_001_pos.ksh
new file mode 100755 (executable)
index 0000000..ad416a5
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2015 Nexenta Systems, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Valid datasets and snapshots are accepted as bootfs property values
+#
+# STRATEGY:
+# 1. Create a set of datasets and snapshots in a test pool
+# 2. Try setting them as boot filesystems
+#
+
+verify_runnable "global"
+
+function cleanup {
+       if poolexists $TESTPOOL ; then
+               log_must $ZPOOL destroy $TESTPOOL
+       fi
+
+       if [[ -f $VDEV ]]; then
+               log_must $RM -f $VDEV
+       fi
+}
+
+$ZPOOL set 2>&1 | $GREP bootfs > /dev/null
+if [ $? -ne 0 ]
+then
+        log_unsupported "bootfs pool property not supported on this release."
+fi
+
+log_assert "Valid datasets are accepted as bootfs property values"
+log_onexit cleanup
+
+typeset VDEV=$TESTDIR/bootfs_001_pos_a.$$.dat
+
+log_must $MKFILE 400m $VDEV
+create_pool "$TESTPOOL" "$VDEV"
+log_must $ZFS create $TESTPOOL/$TESTFS
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snap
+log_must $ZFS clone $TESTPOOL/$TESTFS@snap $TESTPOOL/clone
+
+log_must $ZPOOL set bootfs=$TESTPOOL/$TESTFS $TESTPOOL
+log_must $ZPOOL set bootfs=$TESTPOOL/$TESTFS@snap $TESTPOOL
+log_must $ZPOOL set bootfs=$TESTPOOL/clone $TESTPOOL
+
+log_must $ZFS promote $TESTPOOL/clone
+log_must $ZPOOL set bootfs=$TESTPOOL/clone $TESTPOOL
+log_pass "Valid datasets are accepted as bootfs property values"
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_002_neg.ksh
new file mode 100755 (executable)
index 0000000..cd61b92
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2015 Nexenta Systems, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Invalid datasets are rejected as boot property values
+#
+# STRATEGY:
+#
+# 1. Create a zvol 
+# 2. Verify that we can't set the bootfs to that dataset
+#
+
+verify_runnable "global"
+
+function cleanup {
+       if datasetexists $TESTPOOL/vol
+       then
+               log_must $ZFS destroy $TESTPOOL/vol
+       fi
+       if poolexists $TESTPOOL
+       then
+               log_must $ZPOOL destroy $TESTPOOL
+       fi
+       if [[ -f $VDEV ]]; then
+               log_must $RM -f $VDEV
+       fi
+}
+
+
+$ZPOOL set 2>&1 | $GREP bootfs > /dev/null
+if [ $? -ne 0 ]
+then
+       log_unsupported "bootfs pool property not supported on this release."
+fi
+
+log_assert "Invalid datasets are rejected as boot property values"
+log_onexit cleanup
+
+typeset VDEV=$TESTDIR/bootfs_002_neg_a.$$.dat
+
+log_must $MKFILE 400m $VDEV
+create_pool "$TESTPOOL" "$VDEV"
+log_must $ZFS create -V 10m $TESTPOOL/vol
+block_device_wait
+
+log_mustnot $ZPOOL set bootfs=$TESTPOOL/vol $TESTPOOL
+
+log_pass "Invalid datasets are rejected as boot property values"
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_003_pos.ksh
new file mode 100755 (executable)
index 0000000..f3cf1c9
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Valid pool names are accepted
+#
+# STRATEGY:
+# 1. Using a list of valid pool names
+# 2. Create a filesystem in that pool
+# 2. Verify we can set the bootfs to that filesystem
+#
+
+verify_runnable "global"
+
+set -A pools "pool.$$" "pool123" "mypool"
+
+function cleanup {
+       if poolexists $POOL ; then
+               log_must $ZPOOL destroy $POOL
+       fi
+       $RM /bootfs_003.$$.dat
+}
+
+
+$ZPOOL set 2>&1 | $GREP bootfs > /dev/null
+if [ $? -ne 0 ]
+then
+        log_unsupported "bootfs pool property not supported on this release."
+fi
+
+log_onexit cleanup
+
+log_assert "Valid pool names are accepted by zpool set bootfs"
+$MKFILE 64m $TESTDIR/bootfs_003.$$.dat
+
+typeset -i i=0;
+
+while [ $i -lt "${#pools[@]}" ]
+do
+       POOL=${pools[$i]}
+       log_must $ZPOOL create $POOL $TESTDIR/bootfs_003.$$.dat
+       log_must $ZFS create $POOL/$TESTFS
+
+       log_must $ZPOOL set bootfs=$POOL/$TESTFS $POOL
+       RES=$($ZPOOL get bootfs $POOL | $TAIL -1 | $AWK '{print $3}' )
+       if [ $RES != "$POOL/$TESTFS" ]
+       then
+               log_fail "Expected $RES == $POOL/$TESTFS"
+       fi
+       log_must $ZPOOL destroy $POOL
+       i=$(( $i + 1 ))
+done
+
+log_pass "Valid pool names are accepted by zpool set bootfs"
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_004_neg.ksh
new file mode 100755 (executable)
index 0000000..62bbb3d
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Invalid pool names are rejected by zpool set bootfs
+#
+# STRATEGY:
+#      1. Try to set bootfs on some non-existent pools
+#
+#
+#
+
+verify_runnable "global"
+
+set -A pools "pool//$$" "pool%d123" "mirror" "c0t0d0s0" "pool*23*" "*po!l" \
+       "%s££%^"
+
+function cleanup {
+       if poolexists $POOL; then
+               log_must $ZPOOL destroy $POOL
+       fi
+       $RM /bootfs_004.$$.dat
+}
+
+
+$ZPOOL set 2>&1 | $GREP bootfs > /dev/null
+if [ $? -ne 0 ]
+then
+        log_unsupported "bootfs pool property not supported on this release."
+fi
+
+log_assert "Invalid pool names are rejected by zpool set bootfs"
+log_onexit cleanup
+
+# here, we build up a large string and add it to the list of pool names
+# a word to the ksh-wary, ${#array[@]} gives you the
+# total number of entries in an array, so array[${#array[@]}]
+# will index the last entry+1, ksh arrays start at index 0.
+COUNT=0
+while [ $COUNT -le 1025 ]
+do
+        bigname="${bigname}o"
+        COUNT=$(( $COUNT + 1 ))
+done
+pools[${#pools[@]}]="$bigname"
+
+
+
+$MKFILE 64m $TESTDIR/bootfs_004.$$.dat
+
+typeset -i i=0;
+
+while [ $i -lt "${#pools[@]}" ]
+do
+       POOL=${pools[$i]}/$TESTFS
+       log_mustnot $ZPOOL create $POOL $TESTDIR/bootfs_004.$$.dat
+       log_mustnot $ZFS create $POOL/$TESTFS
+       log_mustnot $ZPOOL set bootfs=$POOL/$TESTFS $POOL
+
+       i=$(( $i + 1 ))
+done
+
+log_pass "Invalid pool names are rejected by zpool set bootfs"
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_005_neg.ksh
new file mode 100755 (executable)
index 0000000..3928cdd
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+#
+# Boot properties cannot be set on pools with older versions
+#
+# STRATEGY:
+# 1. Copy and import some pools of older versions
+# 2. Create a filesystem on each
+# 3. Verify that zpool set bootfs fails on each
+#
+
+verify_runnable "global"
+
+function cleanup {
+
+       #
+       # we need destroy pools that created on top of $TESTPOOL first
+       #
+       typeset pool_name
+       for config in $CONFIGS; do
+               pool_name=$(eval $ECHO \$ZPOOL_VERSION_${config}_NAME)
+               if poolexists $pool_name; then
+                       log_must $ZPOOL destroy $pool_name
+               fi
+       done
+
+       if poolexists $TESTPOOL ; then
+               log_must $ZPOOL destroy $TESTPOOL
+       fi
+}
+
+log_assert "Boot properties cannot be set on pools with older versions"
+
+# These are configs from zpool_upgrade.cfg - see that file for more info.
+CONFIGS="1 2 3"
+
+log_onexit cleanup
+log_must $ZPOOL create -f $TESTPOOL $DISKS
+
+for config in $CONFIGS
+do
+       create_old_pool $config
+       POOL_NAME=$(eval $ECHO \$ZPOOL_VERSION_${config}_NAME)
+       log_must $ZFS create $POOL_NAME/$TESTFS
+       log_mustnot $ZPOOL set bootfs=$POOL_NAME/$TESTFS $POOL_NAME
+       log_must destroy_upgraded_pool $config
+done
+
+log_pass "Boot properties cannot be set on pools with older versions"
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_006_pos.ksh
new file mode 100755 (executable)
index 0000000..fc3ca14
--- /dev/null
@@ -0,0 +1,142 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Pools of correct vdev types accept boot property
+#
+# STRATEGY:
+# 1. create pools of each vdev type (raid, raidz, raidz2, mirror + hotspares)
+# 2. verify we can set bootfs on each pool type according to design
+#
+
+verify_runnable "global"
+
+
+$ZPOOL set 2>&1 | $GREP bootfs > /dev/null
+if [ $? -ne 0 ]
+then
+       log_unsupported "bootfs pool property not supported on this release."
+fi
+
+VDEV1=$TESTDIR/bootfs_006_pos_a.$$.dat
+VDEV2=$TESTDIR/bootfs_006_pos_b.$$.dat
+VDEV3=$TESTDIR/bootfs_006_pos_c.$$.dat
+VDEV4=$TESTDIR/bootfs_006_pos_d.$$.dat
+
+function verify_bootfs { # $POOL
+       POOL=$1
+       log_must $ZFS create $POOL/$TESTFS
+
+       log_must $ZPOOL set bootfs=$POOL/$TESTFS $POOL
+       VAL=$($ZPOOL get bootfs $POOL | $TAIL -1 | $AWK '{print $3}' )
+       if [ $VAL != "$POOL/$TESTFS" ]
+       then
+               log_must $ZPOOL status -v $POOL
+               log_fail \
+                   "set/get failed on $POOL - expected $VAL == $POOL/$TESTFS"
+       fi
+       log_must $ZPOOL destroy $POOL
+}
+
+function verify_no_bootfs { # $POOL
+       POOL=$1
+       log_must $ZFS create $POOL/$TESTFS
+       log_mustnot $ZPOOL set bootfs=$POOL/$TESTFS $POOL
+       VAL=$($ZPOOL get bootfs $POOL | $TAIL -1 | $AWK '{print $3}' )
+       if [ $VAL == "$POOL/$TESTFS" ]
+       then
+               log_must $ZPOOL status -v $POOL
+               log_fail "set/get unexpectedly failed $VAL != $POOL/$TESTFS"
+       fi
+       log_must $ZPOOL destroy $POOL
+}
+
+function cleanup {
+       if poolexists $TESTPOOL
+       then
+               log_must $ZPOOL destroy $TESTPOOL
+       fi
+       log_must $RM $VDEV1 $VDEV2 $VDEV3 $VDEV4
+}
+
+log_assert "Pools of correct vdev types accept boot property"
+
+
+
+log_onexit cleanup
+log_must $MKFILE 64m $VDEV1 $VDEV2 $VDEV3 $VDEV4
+
+
+## the following configurations are supported bootable pools
+
+# normal
+log_must $ZPOOL create $TESTPOOL $VDEV1
+verify_bootfs $TESTPOOL
+
+# normal + hotspare
+log_must $ZPOOL create $TESTPOOL $VDEV1 spare $VDEV2
+verify_bootfs $TESTPOOL
+
+# mirror
+log_must $ZPOOL create $TESTPOOL mirror $VDEV1 $VDEV2
+verify_bootfs $TESTPOOL
+
+# mirror + hotspare
+log_must $ZPOOL create $TESTPOOL mirror $VDEV1 $VDEV2 spare $VDEV3
+verify_bootfs $TESTPOOL
+
+## the following configurations are not supported as bootable pools
+
+# stripe
+log_must $ZPOOL create $TESTPOOL $VDEV1 $VDEV2
+verify_no_bootfs $TESTPOOL
+
+# stripe + hotspare
+log_must $ZPOOL create $TESTPOOL $VDEV1 $VDEV2 spare $VDEV3
+verify_no_bootfs $TESTPOOL
+
+# raidz
+log_must $ZPOOL create $TESTPOOL raidz $VDEV1 $VDEV2
+verify_no_bootfs $TESTPOOL
+
+# raidz + hotspare
+log_must $ZPOOL create $TESTPOOL raidz $VDEV1 $VDEV2 spare $VDEV3
+verify_no_bootfs $TESTPOOL
+
+# raidz2
+log_must $ZPOOL create $TESTPOOL raidz2 $VDEV1 $VDEV2 $VDEV3
+verify_no_bootfs $TESTPOOL
+
+# raidz2 + hotspare
+log_must $ZPOOL create $TESTPOOL raidz2 $VDEV1 $VDEV2 $VDEV3 spare $VDEV4
+verify_no_bootfs $TESTPOOL
+
+log_pass "Pools of correct vdev types accept boot property"
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_007_neg.ksh
new file mode 100755 (executable)
index 0000000..6f6bb40
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Setting bootfs on a pool which was configured with the whole disk
+# (i.e. EFI) will fail
+#
+# STRATEGY:
+# 1. create a pool with a whole disk
+# 2. create a filesystem on this pool
+# 3. verify we can not set bootfs on the filesystem we just created.
+#
+
+verify_runnable "global"
+
+function cleanup {
+       if poolexists $TESTPOOL ; then
+               destroy_pool "$TESTPOOL"
+       fi
+}
+
+log_onexit cleanup
+
+DISK=${DISKS%% *}
+typeset EFI_BOOTFS=$TESTPOOL/efs
+typeset assert_mesg="setting bootfs on a pool which was configured with the \
+    whole disk will fail"
+
+log_assert $assert_mesg
+create_pool "$TESTPOOL" "$DISK"
+log_must $ZFS create $EFI_BOOTFS
+
+if is_linux; then
+       log_must $ZPOOL set bootfs=$EFI_BOOTFS $TESTPOOL
+else
+       log_mustnot $ZPOOL set bootfs=$EFI_BOOTFS $TESTPOOL
+fi
+
+log_pass $assert_mesg
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_007_pos.ksh
new file mode 100644 (file)
index 0000000..56235f3
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2015 Nexenta Systems, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Setting bootfs on a pool which was configured with the whole disk
+# (i.e. EFI) works.
+#
+# STRATEGY:
+# 1. create a pool with a whole disk
+# 2. create a filesystem on this pool
+# 3. verify we can set bootfs on the filesystem we just created.
+#
+
+verify_runnable "global"
+
+function cleanup {
+       if poolexists $TESTPOOL ; then
+               destroy_pool "$TESTPOOL"
+       fi
+}
+
+log_onexit cleanup
+
+DISK=${DISKS%% *}
+typeset EFI_BOOTFS=$TESTPOOL/efs
+typeset assert_mesg="setting bootfs on a pool which was configured with the \
+    whole disk works"
+
+log_assert $assert_mesg
+create_pool "$TESTPOOL" "$DISK"
+log_must $ZFS create $EFI_BOOTFS
+
+log_must $ZPOOL set bootfs=$EFI_BOOTFS $TESTPOOL
+
+log_pass $assert_mesg
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/bootfs_008_neg.ksh
new file mode 100755 (executable)
index 0000000..1bf9bda
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# setting bootfs on a dataset which has gzip compression enabled will fail
+#
+# STRATEGY:
+# 1. create pools based on a valid vdev
+# 2. create a filesytem on this pool and set the compression property to gzip1-9
+# 3. set the pool's bootfs property to filesystem we just configured which
+#    should fail
+#
+
+verify_runnable "global"
+
+function cleanup {
+       if poolexists $TESTPOOL ; then
+               destroy_pool "$TESTPOOL"
+       fi
+
+       if [[ -f $VDEV ]]; then
+               log_must $RM -f $VDEV
+       fi
+}
+
+typeset assert_msg="setting bootfs on a dataset which has gzip \
+    compression enabled will fail"
+
+typeset VDEV=$TESTDIR/bootfs_008_neg_a.$$.dat
+typeset COMP_FS=$TESTPOOL/COMP_FS
+
+log_onexit cleanup
+log_assert $assert_msg
+
+log_must $MKFILE 300m $VDEV
+log_must $ZPOOL create $TESTPOOL $VDEV
+log_must $ZFS create $COMP_FS
+
+typeset -i i=0
+set -A gtype "gzip" "gzip-1" "gzip-2" "gzip-3" "gzip-4" "gzip-5" \
+            "gzip-6" "gzip-7" "gzip-8" "gzip-9"
+
+while (( i < ${#gtype[@]} )); do
+       log_must $ZFS set compression=${gtype[i]} $COMP_FS
+       log_mustnot $ZPOOL set bootfs=$COMP_FS $TESTPOOL
+       log_must $ZFS set compression=off $COMP_FS
+       (( i += 1 ))
+done
+
+log_pass $assert_msg
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/cleanup.ksh
new file mode 100755 (executable)
index 0000000..f481a70
--- /dev/null
@@ -0,0 +1,34 @@
+#! /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 (c) 2015 by Lawrence Livermore National Security, LLC
+# All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+[[ -e $TESTDIR ]] && $RM -rf $TESTDIR
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/bootfs/setup.ksh b/zfs/tests/zfs-tests/tests/functional/bootfs/setup.ksh
new file mode 100755 (executable)
index 0000000..694a805
--- /dev/null
@@ -0,0 +1,34 @@
+#! /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 (c) 2015 by Lawrence Livermore National Security, LLC.
+# All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+log_must $MKDIR $TESTDIR
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cache/Makefile.am
new file mode 100644 (file)
index 0000000..f1aaf72
--- /dev/null
@@ -0,0 +1,17 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cache
+dist_pkgdata_SCRIPTS = \
+       cache.cfg \
+       cache.kshlib \
+       cleanup.ksh \
+       setup.ksh \
+       cache_001_pos.ksh \
+       cache_002_pos.ksh \
+       cache_003_pos.ksh \
+       cache_004_neg.ksh \
+       cache_005_neg.ksh \
+       cache_006_pos.ksh \
+       cache_007_neg.ksh \
+       cache_008_neg.ksh \
+       cache_009_pos.ksh \
+       cache_010_neg.ksh \
+       cache_011_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache.cfg b/zfs/tests/zfs-tests/tests/functional/cache/cache.cfg
new file mode 100644 (file)
index 0000000..f315532
--- /dev/null
@@ -0,0 +1,71 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export DISK_ARRAY_NUM=0
+
+function set_disks
+{
+       set -A disk_array $(find_disks $DISKS)
+
+       if (( ${#disk_array[*]} <= 1 )); then
+               export DISK=${DISKS%% *}
+       else
+               export DISK=""
+               typeset -i i=0
+               while (( i < ${#disk_array[*]} )); do
+                       export DISK${i}="${disk_array[$i]}"
+                       DISKSARRAY="$DISKSARRAY ${disk_array[$i]}"
+                       (( i = i + 1 ))
+               done
+               export DISK_ARRAY_NUM=$i
+               export DISKSARRAY
+       fi
+
+       if (( $DISK_ARRAY_NUM == 0 )); then
+               export disk=$DISK
+       else
+               export disk=$DISK0
+       fi
+}
+
+set_disks
+set_device_dir
+
+export SIZE=64M
+
+export VDIR=$TESTDIR/disk.cache
+export VDIR2=$TESTDIR/disk2.cache
+
+export VDEV="$VDIR/a $VDIR/b $VDIR/c"
+export LDEV="$DISK0"
+export VDEV2="$VDIR2/a $VDIR2/b $VDIR2/c"
+export LDEV2="$DISK1"
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache.kshlib b/zfs/tests/zfs-tests/tests/functional/cache/cache.kshlib
new file mode 100644 (file)
index 0000000..6cdeef7
--- /dev/null
@@ -0,0 +1,160 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+function cleanup
+{
+       if datasetexists $TESTPOOL ; then
+               log_must $ZPOOL destroy -f $TESTPOOL
+       fi
+       if datasetexists $TESTPOOL2 ; then
+               log_must $ZPOOL destroy -f $TESTPOOL2
+       fi
+}
+
+#
+# Try zpool status/iostat for given pool
+#
+# $1 pool
+#
+function display_status
+{
+       typeset pool=$1
+
+       typeset -i ret=0
+       $ZPOOL status -xv $pool > /dev/null 2>&1
+       ret=$?
+
+       $ZPOOL iostat > /dev/null 2>&1
+       ((ret |= $?))
+
+       typeset mntpnt=$(get_prop mountpoint $pool)
+       $DD if=/dev/random of=$mntpnt/testfile.$$ &
+       typeset pid=$!
+
+       $ZPOOL iostat -v 1 3 > /dev/null
+       ((ret |= $?))
+
+       kill -9 $pid
+
+       return $ret
+}
+
+#
+# Verify the given cache device have correct type and status
+#
+# $1 pool name
+# $2 device name
+# $3 device status
+# $4 device type
+#
+function verify_cache_device
+{
+       typeset pool=$1
+       typeset device=$2
+       typeset status=$3
+       typeset type=$4
+
+       if [[ -z $pool || -z $device || -z $status ]]; then
+               log_fail "Usage: verify_cache_device <pool> <device> " \
+                       "<status> [type]"
+       fi
+
+       if [[ $WRAPPER == *"smi"* ]]; then
+               $ECHO $device | $EGREP "^c[0-F]+([td][0-F]+)+$" > /dev/null 2>&1
+               if (( $? == 0 )); then
+                       device=${device}s2
+               fi
+       fi
+
+       #
+       # Get all the cache devices and status table like below
+       #
+       # mirror:/disks/d ONLINE mirror:/disks/e ONLINE stripe:/disks/f ONLINE
+       #
+       set -A dev_stat_tab $($ZPOOL status -v $pool | $NAWK 'BEGIN {start=0} \
+                               /\tcache/ {start=1}
+                               /\tmirror/ || /\tspares/ || /^$/ {start=0}
+                               (start==1) && /\t  (\/|[a-zA-Z])/ \
+                                       {print "stripe:" $1 " " $2}
+                               (start==1) && /\t    (\/|[a-zA-Z])/ \
+                                       {print "mirror:" $1 " " $2}
+                               # When hotspare is replacing
+                               (start==1) && /\t      (\/|[a-zA-Z])/ \
+                                       {print "mirror:" $1 " " $2}'
+                            )
+
+       typeset -i i=0
+       typeset find=0
+       while (( i < ${#dev_stat_tab[@]} )); do
+               typeset dev=${dev_stat_tab[$i]}
+               typeset stat=${dev_stat_tab[((i+1))]}
+
+               case $dev in
+                       stripe:$device)
+                               if [[ "$type" == 'mirror' ]]; then
+                                       log_note "Unexpected type: mirror"
+                                       return 1
+                               else
+                                       if [[ $stat != $status ]]; then
+                                               log_note "Status($stat) " \
+                                                       "!= Expected stat($status)"
+                                               return 1
+                                       fi
+                                       return 0
+                               fi
+                               ;;
+                       mirror:$device)
+                               if [[ -z "$type" || $type == 'stripe' ]]; then
+                                       log_note "Unexpected type: stripe"
+                                       return 1
+                               else
+                                       if [[ $stat != $status ]]; then
+                                               log_note "Status($stat) " \
+                                                       "!= Expected stat($status)"
+                                               return 1
+                                       fi
+                                       return 0
+                               fi
+                               ;;
+               esac
+               ((i += 2))
+       done
+
+       log_note "Can not find device: $device"
+       return 1
+}
+
+function verify_cache_support
+{
+       $ZPOOL upgrade -v | $GREP "Cache devices" > /dev/null 2>&1
+       return $?
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_001_pos.ksh
new file mode 100755 (executable)
index 0000000..7b4f560
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Creating a pool with a cache device succeeds.
+#
+# STRATEGY:
+#      1. Create pool with separated cache devices.
+#      2. Display pool status
+#      3. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Creating a pool with a cache device succeeds."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+               cache $LDEV
+       log_must display_status $TESTPOOL
+
+       ldev=$(random_get $LDEV)
+       log_must verify_cache_device $TESTPOOL $ldev 'ONLINE'
+
+       log_must $ZPOOL remove $TESTPOOL $ldev
+       log_must check_vdev_state $TESTPOOL $ldev ""
+
+       log_must $ZPOOL destroy -f $TESTPOOL
+done
+
+log_pass "Creating a pool with a cache device succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_002_pos.ksh
new file mode 100755 (executable)
index 0000000..5c2c34e
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Adding a cache device to normal pool works.
+#
+# STRATEGY:
+#      1. Create pool
+#      2. Add cache devices with different configuration
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Adding a cache device to normal pool works."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       log_must $ZPOOL create $TESTPOOL $type $VDEV
+       log_must $ZPOOL add $TESTPOOL cache $LDEV
+       log_must display_status $TESTPOOL
+       typeset ldev=$(random_get $LDEV)
+       log_must verify_cache_device $TESTPOOL $ldev 'ONLINE'
+
+       log_must $ZPOOL remove $TESTPOOL $ldev
+       log_must check_vdev_state $TESTPOOL $ldev ""
+
+       log_must $ZPOOL destroy -f $TESTPOOL
+done
+
+log_pass "Adding a cache device to normal pool works."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_003_pos.ksh
new file mode 100755 (executable)
index 0000000..73b5d34
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Adding an extra cache device works
+#
+# STRATEGY:
+#      1. Create pool with separated cache devices.
+#      2. Add an extra cache devices
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+verify_disk_count "$LDEV2"
+
+log_assert "Adding an extra cache device works."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+               cache $LDEV
+       log_must $ZPOOL add $TESTPOOL \
+               cache $LDEV2
+
+       log_must display_status $TESTPOOL
+       ldev=$(random_get $LDEV2)
+       log_must verify_cache_device $TESTPOOL $ldev 'ONLINE'
+
+       log_must $ZPOOL remove $TESTPOOL $ldev
+       log_must check_vdev_state $TESTPOOL $ldev ""
+
+       log_must $ZPOOL destroy -f $TESTPOOL
+done
+
+log_pass "Adding an extra cache device works."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_004_neg.ksh
new file mode 100755 (executable)
index 0000000..e71d4d0
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Attaching a cache device fails.
+#
+# STRATEGY:
+#      1. Create pool with separated cache devices.
+#      2. Attaching a cache device for existing cache device
+#      3. Verify the operation fails
+#
+
+verify_runnable "global"
+verify_disk_count "$LDEV2"
+
+log_assert "Attaching a cache device fails for an existing cache device."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+               cache $LDEV
+
+       ldev=$(random_get $LDEV)
+       typeset ldev2=$(random_get $LDEV2)
+       log_mustnot $ZPOOL attach $TESTPOOL $ldev $ldev2
+       log_must check_vdev_state $TESTPOOL $ldev2 ""
+
+       log_must $ZPOOL destroy -f $TESTPOOL
+done
+
+log_pass "Attaching a cache device fails for an existing cache device."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_005_neg.ksh
new file mode 100755 (executable)
index 0000000..6f61326
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Replacing a cache device fails.
+#
+# STRATEGY:
+#      1. Create pool with cache devices.
+#      2. Replacing one cache device
+#      3. Verify replace fails
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+verify_disk_count "$LDEV2"
+
+log_assert "Replacing a cache device fails."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+               cache $LDEV
+       sdev=$(random_get $LDEV)
+       tdev=$(random_get $LDEV2)
+       log_mustnot $ZPOOL replace $TESTPOOL $sdev $tdev
+       log_must verify_cache_device $TESTPOOL $sdev 'ONLINE'
+       log_must check_vdev_state $TESTPOOL $tdev ""
+
+       log_must $ZPOOL destroy -f $TESTPOOL
+done
+
+log_pass "Replacing a cache device fails."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_006_pos.ksh
new file mode 100755 (executable)
index 0000000..1ced5ab
--- /dev/null
@@ -0,0 +1,85 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Exporting and importing pool with cache devices passes.
+#
+# STRATEGY:
+#      1. Create pool with cache devices.
+#      2. Export and import the pool
+#      3. Display pool status
+#      4. Destroy and import the pool again
+#      5. Display pool status
+#      6. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+verify_disk_count "$LDEV2"
+
+log_assert "Exporting and importing pool with cache devices passes."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+               cache $LDEV $LDEV2
+       ldev=$(random_get $LDEV $LDEV2)
+       log_must verify_cache_device \
+               $TESTPOOL $ldev 'ONLINE'
+
+       #
+       # Nomal export/import operating
+       #
+       log_must $ZPOOL export $TESTPOOL
+       log_must $ZPOOL import -d $VDIR $TESTPOOL
+       log_must display_status $TESTPOOL
+       ldev=$(random_get $LDEV $LDEV2)
+       log_must verify_cache_device \
+               $TESTPOOL $ldev 'ONLINE'
+
+       #
+       # Destroy the pool and import again
+       #
+       log_must $ZPOOL destroy $TESTPOOL
+       log_must $ZPOOL import -Df -d $VDIR $TESTPOOL
+       log_must display_status $TESTPOOL
+       ldev=$(random_get $LDEV $LDEV2)
+       log_must verify_cache_device \
+               $TESTPOOL $ldev 'ONLINE'
+
+       log_must $ZPOOL destroy -f $TESTPOOL
+done
+
+log_pass "Exporting and importing pool with cache devices passes."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_007_neg.ksh
new file mode 100755 (executable)
index 0000000..3f204ef
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      A mirror/raidz/raidz2 cache is not supported.
+#
+# STRATEGY:
+#      1. Try to create pool with unsupported type
+#      2. Verify failed to create pool.
+#
+
+verify_runnable "global"
+verify_disk_count "$LDEV2"
+
+log_assert "A mirror/raidz/raidz2 cache is not supported."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for cachetype in "mirror" "raidz" "raidz1" "raidz2"
+       do
+               log_mustnot $ZPOOL create $TESTPOOL $type $VDEV \
+                       cache $cachetype $LDEV $LDEV2
+               ldev=$(random_get $LDEV $LDEV2)
+               log_mustnot verify_cache_device \
+                       $TESTPOOL $ldev 'ONLINE' $cachetype
+               log_must datasetnonexists $TESTPOOL
+       done
+done
+
+log_pass "A mirror/raidz/raidz2 cache is not supported."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_008_neg.ksh
new file mode 100755 (executable)
index 0000000..c251c5a
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      A mirror/raidz/raidz2 cache can not be added to existed pool.
+#
+# STRATEGY:
+#      1. Create pool with or without cache.
+#      2. Add a mirror/raidz/raidz2 cache to this pool.
+#      3. Verify failed to add.
+#
+
+verify_runnable "global"
+verify_disk_count "$LDEV2"
+
+log_assert "A raidz/raidz2 cache can not be added to existed pool."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for cachetype in "mirror" "raidz" "raidz1" "raidz2"
+       do
+               log_must $ZPOOL create $TESTPOOL $type $VDEV \
+                       cache $LDEV
+
+               log_mustnot $ZPOOL add $TESTPOOL cache $cachetype $LDEV2
+               ldev=$(random_get $LDEV2)
+               log_mustnot verify_cache_device \
+                       $TESTPOOL $ldev 'ONLINE' $cachetype
+
+               log_must $ZPOOL destroy $TESTPOOL
+       done
+done
+
+log_pass "A mirror/raidz/raidz2 cache can not be added to existed pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_009_pos.ksh
new file mode 100755 (executable)
index 0000000..f4c5f50
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Offline and online a cache device succeed.
+#
+# STRATEGY:
+#      1. Create pool with mirror cache devices.
+#      2. Offine and online a cache device
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+verify_disk_count "$LDEV2"
+
+log_assert "Offline and online a cache device succeed."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+               cache $LDEV $LDEV2
+
+       ldev=$(random_get $LDEV $LDEV2)
+       log_must $ZPOOL offline $TESTPOOL $ldev
+       log_must display_status $TESTPOOL
+       log_must verify_cache_device $TESTPOOL $ldev 'OFFLINE' ''
+
+       log_must $ZPOOL online $TESTPOOL $ldev
+       log_must display_status $TESTPOOL
+       log_must verify_cache_device $TESTPOOL $ldev 'ONLINE' ''
+
+       log_must $ZPOOL destroy -f $TESTPOOL
+done
+
+log_pass "Offline and online a cache device succeed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_010_neg.ksh
new file mode 100755 (executable)
index 0000000..7aca708
--- /dev/null
@@ -0,0 +1,90 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Verify cache device must be a block device.
+#
+# STRATEGY:
+#      1. Create a pool
+#      2. Add different object as cache
+#      3. Verify character devices and files fail
+#
+
+verify_runnable "global"
+
+function cleanup_testenv
+{
+       cleanup
+       if [[ -n $lofidev ]]; then
+               log_must $LOFIADM -d $lofidev
+       fi
+}
+
+log_assert "Cache device can only be block devices."
+log_onexit cleanup_testenv
+
+TESTVOL=testvol1$$
+dsk1=${DISKS%% *}
+log_must $ZPOOL create $TESTPOOL ${DISKS#$dsk1}
+
+if is_linux; then
+       SLICE="p1"
+else
+       SLICE="s0"
+fi
+
+# Add nomal ${DEV_RDSKDIR} device
+log_mustnot $ZPOOL add $TESTPOOL cache ${DEV_RDSKDIR}/${dsk1}${SLICE}
+#log_must verify_cache_device $TESTPOOL $dsk1 'ONLINE'
+
+# Add nomal file
+log_mustnot $ZPOOL add $TESTPOOL cache $VDEV2
+
+# Add /dev/rlofi device
+lofidev=${VDEV2%% *}
+log_must $LOFIADM -a $lofidev
+lofidev=$($LOFIADM $lofidev)
+log_mustnot $ZPOOL add $TESTPOOL cache "/dev/rlofi/${lofidev#/dev/lofi/}"
+if [[ -n $lofidev ]]; then
+       log_must $LOFIADM -d $lofidev
+       lofidev=""
+fi
+
+# Add ${ZVOL_RDEVDIR} device
+log_must $ZPOOL create $TESTPOOL2 $VDEV2
+log_must $ZFS create -V $SIZE $TESTPOOL2/$TESTVOL
+log_mustnot $ZPOOL add $TESTPOOL cache ${ZVOL_RDEVDIR}/$TESTPOOL2/$TESTVOL
+
+log_pass "Cache device can only be block devices."
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cache_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cache_011_pos.ksh
new file mode 100755 (executable)
index 0000000..5f9e6db
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+#
+# DESCRIPTION:
+#      Remove cache device from pool with spare device should succeed.
+#
+# STRATEGY:
+#      1. Create pool with cache devices and spare devices
+#      2. Remove cache device from the pool
+#      3. The upper action should succeed
+#
+
+verify_runnable "global"
+verify_disk_count "$LDEV2"
+
+function cleanup {
+       if datasetexists $TESTPOOL ; then
+               log_must $ZPOOL destroy -f $TESTPOOL
+       fi
+}
+
+log_assert "Remove cache device from pool with spare device should succeed"
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+               cache $LDEV spare $LDEV2
+
+       log_must $ZPOOL remove $TESTPOOL $LDEV
+       log_must display_status $TESTPOOL
+
+       log_must $ZPOOL destroy -f $TESTPOOL
+done
+
+log_pass "Remove cache device from pool with spare device should succeed"
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cache/cleanup.ksh
new file mode 100755 (executable)
index 0000000..ea57d0d
--- /dev/null
@@ -0,0 +1,46 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+verify_runnable "global"
+
+if datasetexists $TESTPOOL ; then
+       log_must $ZPOOL destroy -f $TESTPOOL
+fi
+if datasetexists $TESTPOOL2 ; then
+       log_must $ZPOOL destroy -f $TESTPOOL2
+fi
+
+log_must $RM -rf $VDIR $VDIR2
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cache/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cache/setup.ksh
new file mode 100755 (executable)
index 0000000..713eca9
--- /dev/null
@@ -0,0 +1,45 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cache/cache.cfg
+. $STF_SUITE/tests/functional/cache/cache.kshlib
+
+verify_runnable "global"
+
+if ! is_physical_device $LDEV; then
+       log_unsupported "Only physical disk could be cache device"
+fi
+
+log_must $RM -rf $VDIR $VDIR2
+log_must $MKDIR -p $VDIR $VDIR2
+log_must $MKFILE $SIZE $VDEV $VDEV2
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cachefile/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cachefile/Makefile.am
new file mode 100644 (file)
index 0000000..4252c70
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cachefile
+dist_pkgdata_SCRIPTS = \
+       cachefile.cfg \
+       cachefile.kshlib \
+       cachefile_001_pos.ksh \
+       cachefile_002_pos.ksh \
+       cachefile_003_pos.ksh \
+       cachefile_004_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile.cfg b/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile.cfg
new file mode 100644 (file)
index 0000000..1379198
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export CPATH="/etc/zfs/zpool.cache"
+export CPATH1=/var/tmp/cachefile.$$
+export CPATH2=$TEST_BASE_DIR/cachefile.$$
diff --git a/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile.kshlib b/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile.kshlib
new file mode 100644 (file)
index 0000000..27a36af
--- /dev/null
@@ -0,0 +1,47 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+#
+# A function to determine if a given pool name has an entry in cachefile
+# returns 1 if the pool is not in the cache, 0 otherwise.
+function pool_in_cache {
+
+       # checking for the pool name in the strings output of
+       # the given cachefile, default is /etc/zfs/zpool.cache
+       typeset cachefile=${2:-$CPATH}
+
+       RESULT=$($STRINGS $cachefile | $GREP -w $1)
+       if [ -z "$RESULT" ]
+       then
+               return 1
+       fi
+       return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_001_pos.ksh
new file mode 100755 (executable)
index 0000000..0023807
--- /dev/null
@@ -0,0 +1,94 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cachefile/cachefile.cfg
+. $STF_SUITE/tests/functional/cachefile/cachefile.kshlib
+
+#
+# DESCRIPTION:
+#
+# Creating a pool with "cachefile" set doesn't update zpool.cache
+#
+# STRATEGY:
+# 1. Create a pool with the cachefile property set
+# 2. Verify that the pool doesn't have an entry in zpool.cache
+# 3. Verify the cachefile property is set
+# 4. Create a pool without the cachefile property
+# 5. Verify the cachefile property isn't set
+# 6. Verify that zpool.cache contains an entry for the pool
+#
+
+function cleanup
+{
+       typeset file
+
+       if poolexists $TESTPOOL ; then
+                destroy_pool $TESTPOOL
+        fi
+       for file in $CPATH1 $CPATH2 ; do
+               if [[ -f $file ]] ; then
+                       log_must $RM $file
+               fi
+       done
+}
+
+verify_runnable "global"
+
+log_assert "Creating a pool with \"cachefile\" set doesn't update zpool.cache"
+log_onexit cleanup
+
+set -A opts "none" "false" "none" \
+       "$CPATH" "true" "-" \
+       "$CPATH1" "true" "$CPATH1" \
+       "$CPATH2" "true" "$CPATH2"
+
+typeset -i i=0
+
+while (( i < ${#opts[*]} )); do
+       log_must $ZPOOL create -o cachefile=${opts[i]} $TESTPOOL $DISKS
+       case ${opts[((i+1))]} in
+               false) log_mustnot pool_in_cache $TESTPOOL
+                       ;;
+               true) log_must pool_in_cache $TESTPOOL ${opts[i]}
+                       ;;
+       esac
+
+       PROP=$(get_pool_prop cachefile $TESTPOOL)
+       if [[ $PROP != ${opts[((i+2))]} ]]; then
+               log_fail "cachefile property not set as expected. " \
+                       "Expect: ${opts[((i+2))]}, Current: $PROP"
+       fi
+       log_must $ZPOOL destroy $TESTPOOL
+       (( i = i + 3 ))
+done
+
+log_pass "Creating a pool with \"cachefile\" set doesn't update zpool.cache"
diff --git a/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_002_pos.ksh
new file mode 100755 (executable)
index 0000000..1680e66
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cachefile/cachefile.cfg
+. $STF_SUITE/tests/functional/cachefile/cachefile.kshlib
+
+#
+# DESCRIPTION:
+#
+# Importing a pool with "cachefile" set doesn't update zpool.cache
+#
+# STRATEGY:
+# 1. Create a pool with the cachefile property set
+# 2. Verify the pool doesn't have an entry in zpool.cache
+# 3. Export the pool
+# 4. Import the pool
+# 5. Verify the pool does have an entry in zpool.cache
+# 6. Export the pool
+# 7. Import the pool -o cachefile=<cachefile>
+# 8. Verify the pool doesn't have an entry in zpool.cache
+#
+
+function cleanup
+{
+       if poolexists $TESTPOOL ; then
+                destroy_pool $TESTPOOL
+        fi
+}
+
+verify_runnable "global"
+
+log_assert "Importing a pool with \"cachefile\" set doesn't update zpool.cache"
+log_onexit cleanup
+
+log_must $ZPOOL create -o cachefile=none $TESTPOOL $DISKS
+typeset DEVICEDIR=$(get_device_dir $DISKS)
+log_mustnot pool_in_cache $TESTPOOL
+
+log_must $ZPOOL export $TESTPOOL
+log_must $ZPOOL import -d $DEVICEDIR $TESTPOOL
+log_must pool_in_cache $TESTPOOL
+
+log_must $ZPOOL export $TESTPOOL
+log_must $ZPOOL import -o cachefile=none -d $DEVICEDIR $TESTPOOL
+log_mustnot pool_in_cache $TESTPOOL
+
+log_must $ZPOOL export $TESTPOOL
+log_must $ZPOOL import -o cachefile=$CPATH -d $DEVICEDIR $TESTPOOL
+log_must pool_in_cache $TESTPOOL
+
+log_must $ZPOOL destroy $TESTPOOL
+
+log_pass "Importing a pool with \"cachefile\" set doesn't update zpool.cache"
diff --git a/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_003_pos.ksh
new file mode 100755 (executable)
index 0000000..d79a1a7
--- /dev/null
@@ -0,0 +1,100 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cachefile/cachefile.cfg
+. $STF_SUITE/tests/functional/cachefile/cachefile.kshlib
+
+#
+# DESCRIPTION:
+#
+# Setting altroot=<path> and cachefile=$CPATH for zpool create is succeed
+#
+# STRATEGY:
+# 1. Attempt to create a pool with -o altroot=<path> -o cachefile=<value>
+# 2. Verify the command succeed
+#
+#
+
+TESTDIR=/altdir.$$
+
+function cleanup
+{
+       typeset file
+
+       if poolexists $TESTPOOL ; then
+               destroy_pool $TESTPOOL
+       fi
+
+        for file in $CPATH1 $CPATH2 ; do
+                if [[ -f $file ]] ; then
+                        log_must $RM $file
+                fi
+        done
+
+       if [ -d $TESTDIR ]
+       then
+               $RMDIR $TESTDIR
+       fi
+}
+
+verify_runnable "global"
+
+log_assert "Setting altroot=path and cachefile=$CPATH for zpool create succeed."
+log_onexit cleanup
+
+typeset -i i=0
+
+set -A opts "none" "none" \
+       "$CPATH" "-" \
+       "$CPATH1" "$CPATH1" \
+       "$CPATH2" "$CPATH2"
+
+
+while (( i < ${#opts[*]} )); do
+       log_must $ZPOOL create -o altroot=$TESTDIR -o cachefile=${opts[i]} \
+               $TESTPOOL $DISKS
+       if [[ ${opts[i]} != none ]]; then
+               log_must pool_in_cache $TESTPOOL ${opts[i]}
+       else
+               log_mustnot pool_in_cache $TESTPOOL
+       fi
+
+       PROP=$(get_pool_prop cachefile $TESTPOOL)
+       if [[ $PROP != ${opts[((i+1))]} ]]; then
+               log_fail "cachefile property not set as expected. " \
+                       "Expect: ${opts[((i+1))]}, Current: $PROP"
+       fi
+       log_must $ZPOOL destroy $TESTPOOL
+       (( i = i + 2 ))
+done
+
+log_pass "Setting altroot=path and cachefile=$CPATH for zpool create succeed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cachefile/cachefile_004_pos.ksh
new file mode 100755 (executable)
index 0000000..98adfd0
--- /dev/null
@@ -0,0 +1,124 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cachefile/cachefile.cfg
+. $STF_SUITE/tests/functional/cachefile/cachefile.kshlib
+
+#
+# DESCRIPTION:
+#      Verify set, export and destroy when cachefile is set on pool.
+#
+# STRATEGY:
+#      1. Create two pools with one same cahcefile1.
+#      2. Set cachefile of the two pools to another same cachefile2.
+#      3. Verify cachefile1 not exist.
+#      4. Export the two pools.
+#      5. Verify cachefile2 not exist.
+#      6. Import the two pools and set cachefile to cachefile2.
+#      7. Destroy the two pools.
+#      8. Verify cachefile2 not exist.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+       poolexists $TESTPOOL2 && destroy_pool $TESTPOOL2
+
+       mntpnt=$(get_prop mountpoint $TESTPOOL)
+       typeset -i i=0
+       while ((i < 2)); do
+               if [[ -e $mntpnt/vdev$i ]]; then
+                       log_must $RM -f $mntpnt/vdev$i
+               fi
+               ((i += 1))
+       done
+
+       if poolexists $TESTPOOL ; then
+               destroy_pool $TESTPOOL
+       fi
+
+       for file in $CPATH1 $CPATH2 ; do
+               if [[ -f $file ]] ; then
+                       log_must $RM $file
+               fi
+       done
+}
+
+
+log_assert "Verify set, export and destroy when cachefile is set on pool."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL $DISKS
+
+mntpnt=$(get_prop mountpoint $TESTPOOL)
+typeset -i i=0
+while ((i < 2)); do
+       log_must $MKFILE 64M $mntpnt/vdev$i
+       eval vdev$i=$mntpnt/vdev$i
+       ((i += 1))
+done
+
+log_must $ZPOOL create -o cachefile=$CPATH1 $TESTPOOL1 $vdev0
+log_must pool_in_cache $TESTPOOL1 $CPATH1
+log_must $ZPOOL create -o cachefile=$CPATH1 $TESTPOOL2 $vdev1
+log_must pool_in_cache $TESTPOOL2 $CPATH1
+
+log_must $ZPOOL set cachefile=$CPATH2 $TESTPOOL1
+log_must pool_in_cache $TESTPOOL1 $CPATH2
+log_must $ZPOOL set cachefile=$CPATH2 $TESTPOOL2
+log_must pool_in_cache $TESTPOOL2 $CPATH2
+if [[ -f $CPATH1 ]]; then
+       log_fail "Verify set when cachefile is set on pool."
+fi
+
+log_must $ZPOOL export $TESTPOOL1
+log_must $ZPOOL export $TESTPOOL2
+if [[ -f $CPATH2 ]]; then
+       log_fail "Verify export when cachefile is set on pool."
+fi
+
+log_must $ZPOOL import -d $mntpnt $TESTPOOL1
+log_must $ZPOOL set cachefile=$CPATH2 $TESTPOOL1
+log_must pool_in_cache $TESTPOOL1 $CPATH2
+log_must $ZPOOL import -d $mntpnt $TESTPOOL2
+log_must $ZPOOL set cachefile=$CPATH2 $TESTPOOL2
+log_must pool_in_cache $TESTPOOL2 $CPATH2
+
+log_must $ZPOOL destroy $TESTPOOL1
+log_must $ZPOOL destroy $TESTPOOL2
+if [[ -f $CPATH2 ]]; then
+       log_fail "Verify destroy when cachefile is set on pool."
+fi
+
+log_pass "Verify set, export and destroy when cachefile is set on pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/Makefile.am b/zfs/tests/zfs-tests/tests/functional/casenorm/Makefile.am
new file mode 100644 (file)
index 0000000..00a19c7
--- /dev/null
@@ -0,0 +1,22 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/casenorm
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       case_all_values.ksh \
+       casenorm.cfg \
+       casenorm.kshlib \
+       insensitive_formd_delete.ksh \
+       insensitive_formd_lookup.ksh \
+       insensitive_none_delete.ksh \
+       insensitive_none_lookup.ksh \
+       mixed_formd_delete.ksh \
+       mixed_formd_lookup_ci.ksh \
+       mixed_formd_lookup.ksh \
+       mixed_none_delete.ksh \
+       mixed_none_lookup_ci.ksh \
+       mixed_none_lookup.ksh \
+       norm_all_values.ksh \
+       sensitive_formd_delete.ksh \
+       sensitive_formd_lookup.ksh \
+       sensitive_none_delete.ksh \
+       sensitive_none_lookup.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/case_all_values.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/case_all_values.ksh
new file mode 100755 (executable)
index 0000000..af23e9d
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# Check that we can create FS with any supported casesensitivity value.
+#
+# STRATEGY:
+# For all suported casesensitivity values:
+# 1. Create FS with given casesensitivity value.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "Can create FS with any supported casesensitivity value"
+
+for caseval in sensitive insensitive mixed; do
+       create_testfs "-o casesensitivity=$caseval"
+       destroy_testfs
+done
+
+log_pass "Can create FS with any supported casesensitivity value"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/casenorm.cfg b/zfs/tests/zfs-tests/tests/functional/casenorm/casenorm.cfg
new file mode 100644 (file)
index 0000000..ffad2fb
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+NAME_C_ORIG=$($ECHO 'F\0303\0257L\0303\0253N\0303\0204m\0303\0253')
+NAME_C_UPPER=$($ECHO 'F\0303\0217L\0303\0213N\0303\0204M\0303\0213')
+NAME_C_LOWER=$($ECHO 'f\0303\0257l\0303\0253n\0303\0244m\0303\0253')
+NAME_D_ORIG=$($ECHO 'Fi\0314\0210Le\0314\0210NA\0314\0210me\0314\0210')
+NAME_D_UPPER=$($ECHO 'FI\0314\0210LE\0314\0210NA\0314\0210ME\0314\0210')
+NAME_D_LOWER=$($ECHO 'fi\0314\0210le\0314\0210na\0314\0210me\0314\0210')
+NAMES_ORIG="$NAME_C_ORIG $NAME_D_ORIG"
+NAMES_UPPER="$NAME_C_UPPER $NAME_D_UPPER"
+NAMES_LOWER="$NAME_C_LOWER $NAME_D_LOWER"
+NAMES_C="$NAME_C_ORIG $NAME_C_UPPER $NAME_C_LOWER"
+NAMES_D="$NAME_D_ORIG $NAME_D_UPPER $NAME_D_LOWER"
+NAMES_ALL="$NAMES_C $NAMES_D"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/casenorm.kshlib b/zfs/tests/zfs-tests/tests/functional/casenorm/casenorm.kshlib
new file mode 100755 (executable)
index 0000000..ff1206f
--- /dev/null
@@ -0,0 +1,119 @@
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/casenorm/casenorm.cfg
+
+function create_testfs
+{
+       typeset opts=$1
+
+       $RM -rf $TESTDIR || log_unresolved Could not remove $TESTDIR
+       $MKDIR -p $TESTDIR || log_unresolved Could not create $TESTDIR
+
+       log_must $ZFS create $opts $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+function destroy_testfs
+{
+       if datasetexists $TESTPOOL/$TESTFS ; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS
+               $RM -rf $TESTDIR || log_unresolved Could not remove $TESTDIR
+       fi
+}
+
+function create_file
+{
+       typeset name=$TESTDIR/$1
+
+       $ECHO $name > $name
+}
+
+function delete_file
+{
+       typeset name=$TESTDIR/$1
+
+       $RM $name >/dev/null 2>&1
+
+       if [[ $? -ne 0 ]] ; then
+               return 1
+       fi
+
+       if [[ -f $name ]] ; then
+               return 2
+       fi
+}
+
+function lookup_file
+{
+       typeset name=$1
+
+       $ZLOOK -l $TESTDIR $name >/dev/null 2>&1
+}
+
+function lookup_file_ci
+{
+       typeset name=$1
+
+       $ZLOOK -il $TESTDIR $name >/dev/null 2>&1
+}
+
+function lookup_any
+{
+       for name in $NAMES_ALL ; do
+               lookup_file $name
+               if [[ $? -eq 0 ]] ; then
+                       return 0
+               fi
+       done
+
+       return 1
+}
+
+function switch_norm
+{
+       typeset norm=$(get_norm $1)
+
+       if [[ $norm == "C" ]] ; then
+               print "D"
+       else
+               print "C"
+       fi
+}
+
+function get_norm
+{
+       if [[ "${NAMES_C#*$1}" != "${NAMES_C}" ]] ; then
+               print "C"
+       elif [[ "${NAMES_D#*$1}" != "${NAMES_D}" ]] ; then
+               print "D"
+       else
+               return 1
+       fi
+}
+
+function get_case
+{
+       if [[ ${NAMES_UPPER#*$1} != ${NAMES_UPPER} ]] ; then
+               print "UPPER"
+       elif [[ ${NAMES_LOWER#*$1} != ${NAMES_LOWER} ]] ; then
+               print "LOWER"
+       elif [[ ${NAMES_ORIG#*$1} != ${NAMES_ORIG} ]] ; then
+               print "ORIG"
+       else
+               return 1
+       fi
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/cleanup.ksh
new file mode 100755 (executable)
index 0000000..98af72d
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_formd_delete.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_formd_delete.ksh
new file mode 100755 (executable)
index 0000000..00caea9
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=insensitive, normalization=formD,
+# check that file can be deleted using any name form.
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that deleting file using other c/n name forms succeeds.
+# 3. Check that file isn't accessible by any c/n name form.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CI-UN FS: delete succeeds using any name form"
+
+# Can delete using any case/normalization form
+create_testfs "-o casesensitivity=insensitive -o normalization=formD"
+
+for name1 in $NAMES_ALL ; do
+       for name2 in $NAMES_ALL ; do
+               log_must create_file $name1
+               log_must delete_file $name2
+               log_mustnot lookup_any
+       done
+done
+
+destroy_testfs
+
+log_pass "CI-UN FS: delete succeeds using any name form"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_formd_lookup.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_formd_lookup.ksh
new file mode 100755 (executable)
index 0000000..d284313
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=insensitive, normalization=formD,
+# check that lookup succeds using any name form.
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that lookup succeeds for any other c/n name form.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CI-UN FS: lookup succeeds using any name form"
+
+create_testfs "-o casesensitivity=insensitive -o normalization=formD"
+
+for name1 in $NAMES_ALL ; do
+       log_must create_file $name1
+       for name2 in $NAMES_ALL ; do
+               log_must lookup_file $name2
+       done
+       delete_file $name1
+done
+
+destroy_testfs
+
+log_pass "CI-UN FS: lookup succeeds using any name form"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_none_delete.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_none_delete.ksh
new file mode 100755 (executable)
index 0000000..51f6a3c
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=insensitive, normalization=none,
+# check that delete succeeds if (norm=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that delete succeeds if (norm=same).
+# 3. Check that file is no longer accessible using any name form.
+# 4. Check that delete fails if (norm=other).
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CI-not-UN FS: delete succeeds if (norm=same)"
+
+create_testfs "-o casesensitivity=insensitive -o normalization=none"
+
+for name1 in $NAMES_C ; do
+       for name2 in $NAMES_C ; do
+               log_must create_file $name1
+               log_must delete_file $name2
+               log_mustnot lookup_any
+       done
+       for name2 in $NAMES_D ; do
+               log_must create_file $name1
+               log_mustnot delete_file $name2
+               delete_file $name1
+       done
+done
+
+for name1 in $NAMES_D ; do
+       for name2 in $NAMES_D ; do
+               log_must create_file $name1
+               log_must delete_file $name2
+               log_mustnot lookup_any
+       done
+       for name2 in $NAMES_C ; do
+               log_must create_file $name1
+               log_mustnot delete_file $name2
+               delete_file $name1
+       done
+done
+
+destroy_testfs
+
+log_pass "CI-not-UN FS: delete succeeds if (norm=same)"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_none_lookup.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/insensitive_none_lookup.ksh
new file mode 100755 (executable)
index 0000000..12b7951
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=insensitive, normalization=none,
+# check that lookup succeeds only if (norm=same)
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that lookup succeeds if (norm=same).
+# 3. Check that lookup fails if (norm=other).
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CI-not-UN FS: lookup succeeds only if (norm=same)"
+
+create_testfs "-o casesensitivity=insensitive -o normalization=none"
+
+for name1 in $NAMES_C ; do
+       log_must create_file $name1
+       for name2 in $NAMES_C ; do
+               log_must lookup_file $name2
+       done
+       for name2 in $NAMES_D; do
+               log_mustnot lookup_file $name2
+       done
+       delete_file $name1
+done
+
+for name1 in $NAMES_D ; do
+       log_must create_file $name1
+       for name2 in $NAMES_D ; do
+               log_must lookup_file $name2
+       done
+       for name2 in $NAMES_C; do
+               log_mustnot lookup_file $name2
+       done
+       delete_file $name1
+done
+
+destroy_testfs
+
+log_pass "CI-not-UN FS: lookup succeeds only if (norm=same)"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_delete.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_delete.ksh
new file mode 100755 (executable)
index 0000000..451acbb
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=mixed, normalization=formD,
+# check that delete succeeds if (case=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that delete succeeds if (case=same).
+# 3. Check that file is no longer accessible using any name form.
+# 4. Check that delete fails for all other name forms other than original.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CM-UN FS: delete succeeds if (case=same)"
+
+create_testfs "-o casesensitivity=mixed -o normalization=formD"
+
+for name1 in $NAMES_ALL; do
+       typeset -n namen=NAME_$(switch_norm $name1)_$(get_case $name1)
+       for name2 in $NAMES_ALL; do
+               log_must create_file $name1
+               if [[ $name2 == $namen || $name2 == $name1 ]]; then
+                       log_must delete_file $name2
+                       log_mustnot lookup_any
+               else
+                       log_mustnot delete_file $name2
+               fi
+               delete_file $name1
+       done
+done
+
+destroy_testfs
+
+log_pass "CM-UN FS: delete succeeds if (case=same)"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_lookup.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_lookup.ksh
new file mode 100755 (executable)
index 0000000..105415d
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=mixed, normalization=formD,
+# check that lookup succeeds only if (case=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that lookup succeeds if (case=same).
+# 3. Check that lookup fails if (case=other).
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CM-UN FS: lookup succeeds if (case=same)"
+
+create_testfs "-o casesensitivity=mixed -o normalization=formD"
+
+for name1 in $NAMES_ALL; do
+       log_must create_file $name1
+       for name2 in $NAMES_ALL; do
+               if [[ $(get_case $name2) == $(get_case $name1) ]]; then
+                       log_must lookup_file $name2
+               else
+                       log_mustnot lookup_file $name2
+               fi
+       done
+       delete_file $name1
+done
+
+destroy_testfs
+
+log_pass "CM-UN FS: lookup succeeds if (case=same)"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_lookup_ci.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_formd_lookup_ci.ksh
new file mode 100755 (executable)
index 0000000..50827ff
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=insensitive, normalization=formD,
+# check that CI lookup succeeds using any name form.
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that CI lookup succeeds for any c/n name form.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CM-UN FS: CI lookup succeeds using any name form"
+
+create_testfs "-o casesensitivity=mixed -o normalization=formD"
+
+for name1 in $NAMES_ALL ; do
+       log_must create_file $name1
+       for name2 in $NAMES_ALL ; do
+               log_must lookup_file_ci $name2
+       done
+       delete_file $name1
+done
+
+destroy_testfs
+
+log_pass "CM-UN FS: CI lookup succeeds using any name form"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_delete.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_delete.ksh
new file mode 100755 (executable)
index 0000000..708fea8
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=mixed, normalization=none,
+# check that delete succeeds only if (case=same and norm=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file in given c/n name form.
+# 2. Check that delete fails for all other name forms.
+# 3. Check that delete succeeds if (case=same and norm=same).
+# 4. Check that file is no longer accessible by any name form.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CM-not-UN FS: delete succeeds only if using exact name form"
+
+create_testfs "-o casesensitivity=mixed -o normalization=none"
+
+for name1 in $NAMES_ALL ; do
+       log_must create_file $name1
+       for name2 in $NAMES_ALL ; do
+               if [[ $name2 != $name1 ]] ; then
+                       log_mustnot delete_file $name2
+               fi
+       done
+       delete_file $name1
+       log_mustnot lookup_any
+done
+
+destroy_testfs
+
+log_pass "CM-not-UN FS: delete succeeds only if using exact name form"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_lookup.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_lookup.ksh
new file mode 100755 (executable)
index 0000000..12d8495
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=mixed, normalization=none,
+# check that lookup succeeds only if (case=same and norm=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that lookup fails for all other c/n name forms.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CM-not-UN FS: lookup succeeds only if using exact name form"
+
+create_testfs "-o casesensitivity=mixed -o normalization=none"
+
+for name1 in $NAMES_ALL; do
+       for name2 in $NAMES_ALL; do
+               log_must create_file $name1
+               if [[ $name2 != $name1 ]]; then
+                       log_mustnot lookup_file $name2
+               fi
+               delete_file $name1
+       done
+done
+
+destroy_testfs
+
+log_pass "CM-not-UN FS: lookup succeeds only if using exact name form"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_lookup_ci.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/mixed_none_lookup_ci.ksh
new file mode 100755 (executable)
index 0000000..c798ec7
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=mixed, normalization=none,
+# check that CI lookup succeeds only if (norm=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that CI lookup succeeds if (norm=same).
+# 3. Check that CI lookup fails if (norm=other).
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CM-not-UN FS: CI lookup succeeds only if (norm=same)"
+
+create_testfs "-o casesensitivity=mixed -o normalization=none"
+
+for name1 in $NAMES_C ; do
+       log_must create_file $name1
+       for name2 in $NAMES_C ; do
+               log_must lookup_file_ci $name2
+       done
+       for name2 in $NAMES_D; do
+               log_mustnot lookup_file_ci $name2
+       done
+       delete_file $name1
+done
+
+for name1 in $NAMES_D ; do
+       log_must create_file $name1
+       for name2 in $NAMES_D ; do
+               log_must lookup_file_ci $name2
+       done
+       for name2 in $NAMES_C; do
+               log_mustnot lookup_file_ci $name2
+       done
+       delete_file $name1
+done
+
+destroy_testfs
+
+log_pass "CM-not-UN FS: CI lookup succeeds only if (norm=same)"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/norm_all_values.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/norm_all_values.ksh
new file mode 100755 (executable)
index 0000000..90e625c
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# Check that we can create FS with all supported normalization forms.
+#
+# STRATEGY:
+# 1. Create FS with all supported normalization forms.
+# 2. Check that utf8only is set on except for normalization=none.
+# 3. Check that it's not possible to create FS with utf8only=off
+#    and normalization other than none.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "Can create FS with all supported normalization forms"
+
+for form in none formC formD formKC formKD; do
+       create_testfs "-o normalization=$form"
+       if [[ $form != "none" ]] ; then
+               utf8only=$($ZFS get -H -o value utf8only $TESTPOOL/$TESTFS)
+               if [[ $utf8only != "on" ]]; then
+                       log_fail "Turning on normalization didn't set " \
+                           "utf8only to on"
+               fi
+       fi
+       destroy_testfs
+done
+
+for form in formC formD formKC formKD; do
+       log_mustnot $ZFS create -o utf8only=off -o normalization=$form \
+           $TESTPOOL/$TESTFS
+       destroy_testfs
+done
+
+log_pass "Can create FS with all supported normalization forms"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_formd_delete.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_formd_delete.ksh
new file mode 100755 (executable)
index 0000000..285bd4e
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=sensitive, normalization=formD,
+# check that delete succeeds if (case=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that delete succeeds if (case=same).
+# 3. Check that file is no longer accessible using any name form.
+# 4. Check that delete fails for all other name forms.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CS-UN FS: delete succeeds if (case=same)"
+
+create_testfs "-o casesensitivity=sensitive -o normalization=formD"
+
+for name1 in $NAMES_ALL ; do
+       typeset -n namen=NAME_$(switch_norm $name1)_$(get_case $name1)
+       for name2 in $NAMES_ALL ; do
+               log_must create_file $name1
+               if [[ $name2 == $namen || $name2 == $name1 ]] ; then
+                       log_must delete_file $name2
+                       log_mustnot lookup_any
+               else
+                       log_mustnot delete_file $name2
+               fi
+               delete_file $name1
+       done
+done
+
+destroy_testfs
+
+log_pass "CS-UN FS: delete succeeds if (case=same)"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_formd_lookup.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_formd_lookup.ksh
new file mode 100755 (executable)
index 0000000..d00c7b5
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=sensitive, normalization=formD,
+# check that lookup only if (case=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that lookup succeeds if (case=same).
+# 3. Check that lookup fails if (case=other).
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CS-UN FS: lookup succeeds if (case=same)"
+
+create_testfs "-o casesensitivity=sensitive -o normalization=formD"
+
+for name1 in $NAMES_ALL; do
+       log_must create_file $name1
+       for name2 in $NAMES_ALL; do
+               if [[ $(get_case $name2) == $(get_case $name1) ]]; then
+                       log_must lookup_file $name2
+               else
+                       log_mustnot lookup_file $name2
+               fi
+       done
+       delete_file $name1
+done
+
+destroy_testfs
+
+log_pass "CS-UN FS: lookup succeeds if (case=same)"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_none_delete.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_none_delete.ksh
new file mode 100755 (executable)
index 0000000..addebcd
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=sensitive, normalization=none,
+# check that delete succeeds only if (case=same and norm=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file in given c/n name form.
+# 2. Check that delete fails for all other name forms.
+# 3. Check that delete succeeds if (case=same and norm=same).
+# 4. Check that file is no longer accessible by any name form.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CS-not-UN FS: delete succeeds only if using exact name form"
+
+create_testfs "-o casesensitivity=sensitive -o normalization=none"
+
+for name1 in $NAMES_ALL ; do
+       log_must create_file $name1
+       for name2 in $NAMES_ALL ; do
+               if [[ $name2 != $name1 ]] ; then
+                       log_mustnot delete_file $name2
+               fi
+       done
+       delete_file $name1
+       log_mustnot lookup_any
+done
+
+destroy_testfs
+
+log_pass "CS-not-UN FS: delete succeeds only if using exact name form"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_none_lookup.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/sensitive_none_lookup.ksh
new file mode 100755 (executable)
index 0000000..b945d81
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/casenorm/casenorm.kshlib
+
+# DESCRIPTION:
+# For the filesystem with casesensitivity=sensitive, normalization=none,
+# check that lookup succeeds only if (case=same and norm=same).
+#
+# STRATEGY:
+# For each c/n name form:
+# 1. Create file with given c/n name form.
+# 2. Check that lookup fails for all other c/n name forms.
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_testfs
+}
+
+log_onexit cleanup
+log_assert "CS-not-UN FS: lookup succeeds only if using exact name form"
+
+create_testfs "-o casesensitivity=sensitive -o normalization=none"
+
+for name1 in $NAMES_ALL; do
+       for name2 in $NAMES_ALL; do
+               log_must create_file $name1
+               if [[ $name2 != $name1 ]]; then
+                       log_mustnot lookup_file $name2
+               fi
+               delete_file $name1
+       done
+done
+
+destroy_testfs
+
+log_pass "CS-not-UN FS: lookup succeeds only if using exact name form"
diff --git a/zfs/tests/zfs-tests/tests/functional/casenorm/setup.ksh b/zfs/tests/zfs-tests/tests/functional/casenorm/setup.ksh
new file mode 100755 (executable)
index 0000000..b6c8498
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/ksh -p
+#
+#
+# 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 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+DISK=${DISKS%% *}
+log_must $ZPOOL create $TESTPOOL $DISK
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/Makefile.am b/zfs/tests/zfs-tests/tests/functional/checksum/Makefile.am
new file mode 100644 (file)
index 0000000..8132ea1
--- /dev/null
@@ -0,0 +1,27 @@
+include $(top_srcdir)/config/Rules.am
+AM_CPPFLAGS += -I$(top_srcdir)/include
+LDADD = $(top_srcdir)/lib/libicp/libicp.la
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/checksum
+
+dist_pkgdata_SCRIPTS = \
+       default.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       run_edonr_test.ksh \
+       run_sha2_test.ksh \
+       run_skein_test.ksh \
+       filetest_001_pos.ksh
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/checksum
+
+pkgexec_PROGRAMS = \
+       edonr_test \
+       skein_test \
+       sha2_test
+
+edonr_test_SOURCES = edonr_test.c
+skein_test_SOURCES = skein_test.c
+sha2_test_SOURCES = sha2_test.c
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/checksum/cleanup.ksh
new file mode 100755 (executable)
index 0000000..da628bc
--- /dev/null
@@ -0,0 +1,50 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/scrub_mirror/default.cfg
+
+
+verify_runnable "global"
+
+$DF -F zfs -h | $GREP "$TESTFS " >/dev/null
+[[ $? == 0 ]] && log_must $ZFS umount -f $TESTDIR
+destroy_pool $TESTPOOL
+
+# recreate and destroy a zpool over the disks to restore the partitions to
+# normal
+if [[ -n $SINGLE_DISK ]]; then
+       log_must cleanup_devices $MIRROR_PRIMARY
+else
+       log_must cleanup_devices $MIRROR_PRIMARY $MIRROR_SECONDARY
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/default.cfg b/zfs/tests/zfs-tests/tests/functional/checksum/default.cfg
new file mode 100644 (file)
index 0000000..c173cc1
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+typeset -i NUMBER_OF_DISKS=0
+for i in $DISKS; do
+       [[ -n $MIRROR_PRIMARY ]] && MIRROR_SECONDARY=$i
+       [[ -z $MIRROR_PRIMARY ]] && MIRROR_PRIMARY=$i
+done
+
+if [[ -z $MIRROR_SECONDARY ]]; then
+       # We need to repartition the single disk to two slices
+       SINGLE_DISK=$MIRROR_PRIMARY
+       MIRROR_SECONDARY=$MIRROR_PRIMARY
+       SIDE_PRIMARY_PART=0
+       SIDE_SECONDARY_PART=1
+       if is_linux; then
+               SIDE_PRIMARY=${SINGLE_DISK}p1
+               SIDE_SECONDARY=${SINGLE_DISK}p2
+       else
+               SIDE_PRIMARY=${SINGLE_DISK}s${SIDE_PRIMARY_PART}
+               SIDE_SECONDARY=${SINGLE_DISK}s${SIDE_SECONDARY_PART}
+       fi
+else
+       SIDE_PRIMARY_PART=0
+       SIDE_SECONDARY_PART=0
+       if is_linux; then
+               SIDE_PRIMARY=${MIRROR_PRIMARY}p1
+               SIDE_SECONDARY=${MIRROR_SECONDARY}p1
+       else
+               SIDE_PRIMARY=${MIRROR_PRIMARY}s${SIDE_PRIMARY_PART}
+               SIDE_SECONDARY=${MIRROR_SECONDARY}s${SIDE_SECONDARY_PART}
+       fi
+fi
+
+
+export MIRROR_PRIMARY MIRROR_SECONDARY SINGLE_DISK SIDE_PRIMARY SIDE_SECONDARY
+
+export MIRROR_MEGS=100
+export MIRROR_SIZE=${MIRROR_MEGS}m # default mirror size
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/edonr_test.c b/zfs/tests/zfs-tests/tests/functional/checksum/edonr_test.c
new file mode 100644 (file)
index 0000000..1ea8e99
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 2013 Saso Kiselkov. All rights reserved.
+ */
+
+/*
+ * This is just to keep the compiler happy about sys/time.h not declaring
+ * gettimeofday due to -D_KERNEL (we can do this since we're actually
+ * running in userspace, but we need -D_KERNEL for the remaining Edon-R code).
+ */
+#ifdef _KERNEL
+#undef _KERNEL
+#endif
+
+#include <sys/edonr.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/time.h>
+#define NOTE(x) 
+typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
+typedef        unsigned long long      u_longlong_t;
+
+/*
+ * Test messages from:
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+ */
+const char     *test_msg0 = "abc";
+const char     *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmn"
+       "lmnomnopnopq";
+const char     *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
+       "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
+
+/*
+ * Test digests computed by hand. There's no formal standard or spec for edonr.
+ */
+const uint8_t  edonr_224_test_digests[][28] = {
+       {
+               /* for test_msg0 */
+               0x56, 0x63, 0xc4, 0x93, 0x95, 0x20, 0xfa, 0xf6,
+               0x12, 0x31, 0x65, 0xa4, 0x66, 0xf2, 0x56, 0x01,
+               0x95, 0x2e, 0xa9, 0xe4, 0x24, 0xdd, 0xc9, 0x6b,
+               0xef, 0xd0, 0x40, 0x94
+       },
+       {
+               /* for test_msg1 */
+               0xd0, 0x13, 0xe4, 0x87, 0x4d, 0x06, 0x8d, 0xca,
+               0x4e, 0x14, 0xb9, 0x37, 0x2f, 0xce, 0x12, 0x20,
+               0x60, 0xf8, 0x5c, 0x0a, 0xfd, 0x7a, 0x7d, 0x97,
+               0x88, 0x2b, 0x05, 0x75
+       }
+       /* no test vector for test_msg2 */
+};
+
+const uint8_t  edonr_256_test_digests[][32] = {
+       {
+               /* for test_msg0 */
+               0x54, 0xd7, 0x8b, 0x13, 0xc7, 0x4e, 0xda, 0x5a,
+               0xed, 0xc2, 0x71, 0xcc, 0x88, 0x1f, 0xb2, 0x2f,
+               0x83, 0x99, 0xaf, 0xd3, 0x04, 0x0b, 0x6a, 0x39,
+               0x2d, 0x73, 0x94, 0x05, 0x50, 0x8d, 0xd8, 0x51
+       },
+       {
+               /* for test_msg1 */
+               0x49, 0x2d, 0x0b, 0x19, 0xab, 0x1e, 0xde, 0x3a,
+               0xea, 0x9b, 0xf2, 0x39, 0x3a, 0xb1, 0x21, 0xde,
+               0x21, 0xf6, 0x80, 0x1f, 0xad, 0xbe, 0x8b, 0x07,
+               0xc7, 0xfb, 0xe6, 0x99, 0x0e, 0x4d, 0x73, 0x63
+       }
+       /* no test vectorfor test_msg2 */
+};
+
+const uint8_t  edonr_384_test_digests[][48] = {
+       {
+               /* for test_msg0 */
+               0x0e, 0x7c, 0xd7, 0x85, 0x78, 0x77, 0xe0, 0x89,
+               0x5b, 0x1c, 0xdf, 0x49, 0xf4, 0x1d, 0x20, 0x9c,
+               0x72, 0x7d, 0x2e, 0x57, 0x9b, 0x9b, 0x9a, 0xdc,
+               0x60, 0x27, 0x97, 0x82, 0xb9, 0x90, 0x72, 0xec,
+               0x7e, 0xce, 0xd3, 0x16, 0x5f, 0x47, 0x75, 0x48,
+               0xfa, 0x60, 0x72, 0x7e, 0x01, 0xc7, 0x7c, 0xc6
+       },
+       {
+               /* no test vector for test_msg1 */
+               0
+       },
+       {
+               /* for test_msg2 */
+               0xe2, 0x34, 0xa1, 0x02, 0x83, 0x76, 0xae, 0xe6,
+               0x82, 0xd9, 0x38, 0x32, 0x0e, 0x00, 0x78, 0xd2,
+               0x34, 0xdb, 0xb9, 0xbd, 0xf0, 0x08, 0xa8, 0x0f,
+               0x63, 0x1c, 0x3d, 0x4a, 0xfd, 0x0a, 0xe9, 0x59,
+               0xdc, 0xd4, 0xce, 0xcd, 0x8d, 0x67, 0x6c, 0xea,
+               0xbb, 0x1a, 0x32, 0xed, 0x5c, 0x6b, 0xf1, 0x7f
+       }
+};
+
+const uint8_t  edonr_512_test_digests[][64] = {
+       {
+               /* for test_msg0 */
+               0x1b, 0x14, 0xdb, 0x15, 0x5f, 0x1d, 0x40, 0x65,
+               0x94, 0xb8, 0xce, 0xf7, 0x0a, 0x43, 0x62, 0xec,
+               0x6b, 0x5d, 0xe6, 0xa5, 0xda, 0xf5, 0x0e, 0xc9,
+               0x99, 0xe9, 0x87, 0xc1, 0x9d, 0x30, 0x49, 0xe2,
+               0xde, 0x59, 0x77, 0xbb, 0x05, 0xb1, 0xbb, 0x22,
+               0x00, 0x50, 0xa1, 0xea, 0x5b, 0x46, 0xa9, 0xf1,
+               0x74, 0x0a, 0xca, 0xfb, 0xf6, 0xb4, 0x50, 0x32,
+               0xad, 0xc9, 0x0c, 0x62, 0x83, 0x72, 0xc2, 0x2b
+       },
+       {
+               /* no test vector for test_msg1 */
+               0
+       },
+       {
+               /* for test_msg2 */
+               0x53, 0x51, 0x07, 0x0d, 0xc5, 0x1c, 0x3b, 0x2b,
+               0xac, 0xa5, 0xa6, 0x0d, 0x02, 0x52, 0xcc, 0xb4,
+               0xe4, 0x92, 0x1a, 0x96, 0xfe, 0x5a, 0x69, 0xe7,
+               0x6d, 0xad, 0x48, 0xfd, 0x21, 0xa0, 0x84, 0x5a,
+               0xd5, 0x7f, 0x88, 0x0b, 0x3e, 0x4a, 0x90, 0x7b,
+               0xc5, 0x03, 0x15, 0x18, 0x42, 0xbb, 0x94, 0x9e,
+               0x1c, 0xba, 0x74, 0x39, 0xa6, 0x40, 0x9a, 0x34,
+               0xb8, 0x43, 0x6c, 0xb4, 0x69, 0x21, 0x58, 0x3c
+       }
+};
+
+int
+main(int argc, char *argv[])
+{
+       boolean_t       failed = B_FALSE;
+       uint64_t        cpu_mhz = 0;
+
+       if (argc == 2)
+               cpu_mhz = atoi(argv[1]);
+
+#define        EDONR_ALGO_TEST(_m, mode, testdigest)                           \
+       do {                                                            \
+               EdonRState      ctx;                                    \
+               uint8_t         digest[mode / 8];                       \
+               EdonRInit(&ctx, mode);                                  \
+               EdonRUpdate(&ctx, (const uint8_t *) _m, strlen(_m) * 8);\
+               EdonRFinal(&ctx, digest);                               \
+               (void) printf("Edon-R-%-6sMessage: " #_m                \
+                   "\tResult: ", #mode);                               \
+               if (bcmp(digest, testdigest, mode / 8) == 0) {          \
+                       (void) printf("OK\n");                          \
+               } else {                                                \
+                       (void) printf("FAILED!\n");                     \
+                       failed = B_TRUE;                                \
+               }                                                       \
+               NOTE(CONSTCOND)                                         \
+       } while (0)
+
+#define        EDONR_PERF_TEST(mode)                                           \
+       do {                                                            \
+               EdonRState      ctx;                                    \
+               uint8_t         digest[mode / 8];                       \
+               uint8_t         block[131072];                          \
+               uint64_t        delta;                                  \
+               double          cpb = 0;                                \
+               int             i;                                      \
+               struct timeval  start, end;                             \
+               bzero(block, sizeof (block));                           \
+               (void) gettimeofday(&start, NULL);                      \
+               EdonRInit(&ctx, mode);                                  \
+               for (i = 0; i < 8192; i++)                              \
+                       EdonRUpdate(&ctx, block, sizeof (block) * 8);   \
+               EdonRFinal(&ctx, digest);                               \
+               (void) gettimeofday(&end, NULL);                        \
+               delta = (end.tv_sec * 1000000llu + end.tv_usec) -       \
+                   (start.tv_sec * 1000000llu + start.tv_usec);        \
+               if (cpu_mhz != 0) {                                     \
+                       cpb = (cpu_mhz * 1e6 * ((double)delta /         \
+                           1000000)) / (8192 * 128 * 1024);            \
+               }                                                       \
+               (void) printf("Edon-R-%-6s%llu us (%.02f CPB)\n", #mode,\
+                   (u_longlong_t)delta, cpb);                          \
+               NOTE(CONSTCOND)                                         \
+       } while (0)
+
+       (void) printf("Running algorithm correctness tests:\n");
+       EDONR_ALGO_TEST(test_msg0, 224, edonr_224_test_digests[0]);
+       EDONR_ALGO_TEST(test_msg1, 224, edonr_224_test_digests[1]);
+       EDONR_ALGO_TEST(test_msg0, 256, edonr_256_test_digests[0]);
+       EDONR_ALGO_TEST(test_msg1, 256, edonr_256_test_digests[1]);
+       EDONR_ALGO_TEST(test_msg0, 384, edonr_384_test_digests[0]);
+       EDONR_ALGO_TEST(test_msg2, 384, edonr_384_test_digests[2]);
+       EDONR_ALGO_TEST(test_msg0, 512, edonr_512_test_digests[0]);
+       EDONR_ALGO_TEST(test_msg2, 512, edonr_512_test_digests[2]);
+       if (failed)
+               return (1);
+
+       (void) printf("Running performance tests (hashing 1024 MiB of "
+           "data):\n");
+       EDONR_PERF_TEST(256);
+       EDONR_PERF_TEST(512);
+
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/filetest_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/checksum/filetest_001_pos.ksh
new file mode 100755 (executable)
index 0000000..a360dfd
--- /dev/null
@@ -0,0 +1,125 @@
+#! /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
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/properties.shlib
+
+# DESCRIPTION:
+# Sanity test to make sure checksum algorithms work.
+# For each checksum, create a file in the pool using that checksum.  Verify
+# that there are no checksum errors.  Next, for each checksum, create a single
+# file in the pool using that checksum, scramble the underlying vdev, and
+# verify that we correctly catch the checksum errors.
+#
+# STRATEGY:
+# Test 1
+# 1. Create a mirrored pool
+# 2. Create a file using each checksum
+# 3. Export/import/scrub the pool
+# 4. Verify there's no checksum errors.
+# 5. Clear the pool
+#
+# Test 2
+# 6. For each checksum:
+# 7.   Create a file using the checksum
+# 8.   Export the pool
+# 9.   Scramble the data on one of the underlying VDEVs
+# 10.  Import the pool
+# 11.  Scrub the pool
+# 12.  Verify that there are checksum errors
+
+verify_runnable "both"
+
+function cleanup
+{
+       $ECHO cleanup
+       [[ -e $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+}
+
+log_assert "Create and read back files with using different checksum algorithms"
+
+log_onexit cleanup
+
+FSSIZE=$($ZPOOL list -Hp -o size $TESTPOOL)
+WRITESZ=1048576
+WRITECNT=$((($FSSIZE) / $WRITESZ ))
+# Skip the first and last 4MB
+SKIP=4127518
+SKIPCNT=$((($SKIP / $WRITESZ )))
+SKIPCNT=$((($SKIPCNT * 2)))
+WRITECNT=$((($WRITECNT - $SKIPCNT)))
+
+# Get a list of vdevs in our pool
+set -A array $(get_disklist_fullpath)
+
+# Get the first vdev, since we will corrupt it later
+firstvdev=${array[0]}
+
+# First test each checksum by writing a file using it, and confirm there's no
+# errors.
+for ((count = 0; count < ${#checksum_props[*]} ; count++)); do
+       i=${checksum_props[$count]}
+       $ZFS set checksum=$i $TESTPOOL
+       $FILE_WRITE -o overwrite -f $TESTDIR/test_$i -b $WRITESZ -c 5 -d R
+done
+$ZPOOL export $TESTPOOL
+$ZPOOL import $TESTPOOL
+$ZPOOL scrub $TESTPOOL
+while is_pool_scrubbing $TESTPOOL; do
+       $SLEEP 1
+done
+$ZPOOL status -P -v $TESTPOOL | grep $firstvdev | read -r name state rd wr cksum
+log_assert "Normal file write test saw $cksum checksum errors"
+log_must [ $cksum -eq 0 ]
+
+rm -fr $TESTDIR/*
+
+log_assert "Test scrambling the disk and seeing checksum errors"
+for ((count = 0; count < ${#checksum_props[*]} ; count++)); do
+       i=${checksum_props[$count]}
+       $ZFS set checksum=$i $TESTPOOL
+       $FILE_WRITE -o overwrite -f $TESTDIR/test_$i -b $WRITESZ -c 5 -d R
+
+       $ZPOOL export $TESTPOOL
+
+       # Scramble the data on the first vdev in our pool.
+       # Skip the first and last 16MB of data, then scramble the rest after that
+       #
+       $FILE_WRITE -o overwrite -f $firstvdev -s $SKIP -c $WRITECNT -b $WRITESZ -d R
+
+       $ZPOOL import $TESTPOOL
+
+       i=${checksum_props[$count]}
+       $ZPOOL scrub $TESTPOOL
+       while is_pool_scrubbing $TESTPOOL; do
+                $SLEEP 1
+        done
+
+       $ZPOOL status -P -v $TESTPOOL | grep $firstvdev | read -r name state rd wr cksum
+
+       log_assert "Checksum '$i' caught $cksum checksum errors"
+       log_must [ $cksum -ne 0 ]
+
+       rm -f $TESTDIR/test_$i
+       $ZPOOL clear $TESTPOOL
+done
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/run_edonr_test.ksh b/zfs/tests/zfs-tests/tests/functional/checksum/run_edonr_test.ksh
new file mode 100755 (executable)
index 0000000..7bcb321
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/ksh -p
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Description:
+# Run the tests for the EdonR hash algorithm.
+#
+
+log_assert "Run the tests for the EdonR hash algorithm."
+
+freq=$(get_cpu_freq)
+log_must $STF_SUITE/tests/functional/checksum/edonr_test $freq
+
+log_pass "EdonR tests passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/run_sha2_test.ksh b/zfs/tests/zfs-tests/tests/functional/checksum/run_sha2_test.ksh
new file mode 100755 (executable)
index 0000000..589e28a
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/ksh -p
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Description:
+# Run the tests for the SHA-2 hash algorithm.
+#
+
+log_assert "Run the tests for the SHA-2 hash algorithm."
+
+freq=$(get_cpu_freq)
+log_must $STF_SUITE/tests/functional/checksum/sha2_test $freq
+
+log_pass "SHA-2 tests passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/run_skein_test.ksh b/zfs/tests/zfs-tests/tests/functional/checksum/run_skein_test.ksh
new file mode 100755 (executable)
index 0000000..4290bfc
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/ksh -p
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Description:
+# Run the tests for the Skein hash algorithm.
+#
+
+log_assert "Run the tests for the Skein hash algorithm."
+
+freq=$(get_cpu_freq)
+log_must $STF_SUITE/tests/functional/checksum/skein_test $freq
+
+log_pass "Skein tests passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/setup.ksh b/zfs/tests/zfs-tests/tests/functional/checksum/setup.ksh
new file mode 100755 (executable)
index 0000000..dba4883
--- /dev/null
@@ -0,0 +1,51 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/checksum/default.cfg
+
+verify_runnable "global"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+if [[ -n $SINGLE_DISK ]]; then
+       log_note "Partitioning a single disk ($SINGLE_DISK)"
+else
+       log_note "Partitioning disks ($MIRROR_PRIMARY $MIRROR_SECONDARY)"
+fi
+log_must set_partition $SIDE_PRIMARY_PART "" $MIRROR_SIZE $MIRROR_PRIMARY
+log_must set_partition $SIDE_SECONDARY_PART "" $MIRROR_SIZE $MIRROR_SECONDARY
+
+default_mirror_setup $SIDE_PRIMARY $SIDE_SECONDARY
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/sha2_test.c b/zfs/tests/zfs-tests/tests/functional/checksum/sha2_test.c
new file mode 100644 (file)
index 0000000..afd6f82
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 2013 Saso Kiselkov. All rights reserved.
+ */
+
+/*
+ * This is just to keep the compiler happy about sys/time.h not declaring
+ * gettimeofday due to -D_KERNEL (we can do this since we're actually
+ * running in userspace, but we need -D_KERNEL for the remaining SHA2 code).
+ */
+#ifdef _KERNEL
+#undef _KERNEL
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/time.h>
+#define        _SHA2_IMPL
+#include <sys/sha2.h>
+#define NOTE(x)
+typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
+typedef        unsigned long long      u_longlong_t;
+
+
+/*
+ * Test messages from:
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+ */
+
+const char     *test_msg0 = "abc";
+const char     *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmn"
+       "lmnomnopnopq";
+const char     *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfghi"
+       "jklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
+
+/*
+ * Test digests from:
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+ */
+const uint8_t  sha256_test_digests[][32] = {
+       {
+               /* for test_msg0 */
+               0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+               0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+               0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+               0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD
+       },
+       {
+               /* for test_msg1 */
+               0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+               0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+               0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+               0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1
+       }
+       /* no test vector for test_msg2 */
+};
+
+const uint8_t  sha384_test_digests[][48] = {
+       {
+               /* for test_msg0 */
+               0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B,
+               0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07,
+               0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63,
+               0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED,
+               0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23,
+               0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7
+       },
+       {
+               /* no test vector for test_msg1 */
+               0
+       },
+       {
+               /* for test_msg2 */
+               0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8,
+               0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47,
+               0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2,
+               0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12,
+               0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9,
+               0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39
+       }
+};
+
+const uint8_t  sha512_test_digests[][64] = {
+       {
+               /* for test_msg0 */
+               0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA,
+               0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31,
+               0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2,
+               0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A,
+               0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8,
+               0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD,
+               0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E,
+               0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F
+       },
+       {
+               /* no test vector for test_msg1 */
+               0
+       },
+       {
+               /* for test_msg2 */
+               0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
+               0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
+               0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
+               0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
+               0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
+               0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
+               0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
+               0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09
+       }
+};
+
+const uint8_t  sha512_224_test_digests[][28] = {
+       {
+               /* for test_msg0 */
+               0x46, 0x34, 0x27, 0x0F, 0x70, 0x7B, 0x6A, 0x54,
+               0xDA, 0xAE, 0x75, 0x30, 0x46, 0x08, 0x42, 0xE2,
+               0x0E, 0x37, 0xED, 0x26, 0x5C, 0xEE, 0xE9, 0xA4,
+               0x3E, 0x89, 0x24, 0xAA
+       },
+       {
+               /* no test vector for test_msg1 */
+               0
+       },
+       {
+               /* for test_msg2 */
+               0x23, 0xFE, 0xC5, 0xBB, 0x94, 0xD6, 0x0B, 0x23,
+               0x30, 0x81, 0x92, 0x64, 0x0B, 0x0C, 0x45, 0x33,
+               0x35, 0xD6, 0x64, 0x73, 0x4F, 0xE4, 0x0E, 0x72,
+               0x68, 0x67, 0x4A, 0xF9
+       }
+};
+
+const uint8_t  sha512_256_test_digests[][32] = {
+       {
+               /* for test_msg0 */
+               0x53, 0x04, 0x8E, 0x26, 0x81, 0x94, 0x1E, 0xF9,
+               0x9B, 0x2E, 0x29, 0xB7, 0x6B, 0x4C, 0x7D, 0xAB,
+               0xE4, 0xC2, 0xD0, 0xC6, 0x34, 0xFC, 0x6D, 0x46,
+               0xE0, 0xE2, 0xF1, 0x31, 0x07, 0xE7, 0xAF, 0x23
+       },
+       {
+               /* no test vector for test_msg1 */
+               0
+       },
+       {
+               /* for test_msg2 */
+               0x39, 0x28, 0xE1, 0x84, 0xFB, 0x86, 0x90, 0xF8,
+               0x40, 0xDA, 0x39, 0x88, 0x12, 0x1D, 0x31, 0xBE,
+               0x65, 0xCB, 0x9D, 0x3E, 0xF8, 0x3E, 0xE6, 0x14,
+               0x6F, 0xEA, 0xC8, 0x61, 0xE1, 0x9B, 0x56, 0x3A
+       }
+};
+
+/*
+ * Local reimplementation of cmn_err, since it's used in sha2.c.
+ */
+/*ARGSUSED*/
+void
+cmn_err(int level, char *format, ...)
+{
+       va_list ap;
+       va_start(ap, format);
+       /* LINTED: E_SEC_PRINTF_VAR_FMT */
+       (void) vfprintf(stderr, format, ap);
+       va_end(ap);
+}
+
+int
+main(int argc, char *argv[])
+{
+       boolean_t       failed = B_FALSE;
+       uint64_t        cpu_mhz = 0;
+
+       if (argc == 2)
+               cpu_mhz = atoi(argv[1]);
+
+#define        SHA2_ALGO_TEST(_m, mode, diglen, testdigest)                    \
+       do {                                                            \
+               SHA2_CTX                ctx;                            \
+               uint8_t                 digest[diglen / 8];             \
+               SHA2Init(SHA ## mode ## _MECH_INFO_TYPE, &ctx);         \
+               SHA2Update(&ctx, _m, strlen(_m));                       \
+               SHA2Final(digest, &ctx);                                \
+               (void) printf("SHA%-9sMessage: " #_m                    \
+                   "\tResult: ", #mode);                               \
+               if (bcmp(digest, testdigest, diglen / 8) == 0) {        \
+                       (void) printf("OK\n");                          \
+               } else {                                                \
+                       (void) printf("FAILED!\n");                     \
+                       failed = B_TRUE;                                \
+               }                                                       \
+               NOTE(CONSTCOND)                                         \
+       } while (0)
+
+#define        SHA2_PERF_TEST(mode, diglen)                                    \
+       do {                                                            \
+               SHA2_CTX        ctx;                                    \
+               uint8_t         digest[diglen / 8];                     \
+               uint8_t         block[131072];                          \
+               uint64_t        delta;                                  \
+               double          cpb = 0;                                \
+               int             i;                                      \
+               struct timeval  start, end;                             \
+               bzero(block, sizeof (block));                           \
+               (void) gettimeofday(&start, NULL);                      \
+               SHA2Init(SHA ## mode ## _MECH_INFO_TYPE, &ctx);         \
+               for (i = 0; i < 8192; i++)                              \
+                       SHA2Update(&ctx, block, sizeof (block));        \
+               SHA2Final(digest, &ctx);                                \
+               (void) gettimeofday(&end, NULL);                        \
+               delta = (end.tv_sec * 1000000llu + end.tv_usec) -       \
+                   (start.tv_sec * 1000000llu + start.tv_usec);        \
+               if (cpu_mhz != 0) {                                     \
+                       cpb = (cpu_mhz * 1e6 * ((double)delta /         \
+                           1000000)) / (8192 * 128 * 1024);            \
+               }                                                       \
+               (void) printf("SHA%-9s%llu us (%.02f CPB)\n", #mode,    \
+                   (u_longlong_t)delta, cpb);                          \
+               NOTE(CONSTCOND)                                         \
+       } while (0)
+
+       (void) printf("Running algorithm correctness tests:\n");
+       SHA2_ALGO_TEST(test_msg0, 256, 256, sha256_test_digests[0]);
+       SHA2_ALGO_TEST(test_msg1, 256, 256, sha256_test_digests[1]);
+       SHA2_ALGO_TEST(test_msg0, 384, 384, sha384_test_digests[0]);
+       SHA2_ALGO_TEST(test_msg2, 384, 384, sha384_test_digests[2]);
+       SHA2_ALGO_TEST(test_msg0, 512, 512, sha512_test_digests[0]);
+       SHA2_ALGO_TEST(test_msg2, 512, 512, sha512_test_digests[2]);
+       SHA2_ALGO_TEST(test_msg0, 512_224, 224, sha512_224_test_digests[0]);
+       SHA2_ALGO_TEST(test_msg2, 512_224, 224, sha512_224_test_digests[2]);
+       SHA2_ALGO_TEST(test_msg0, 512_256, 256, sha512_256_test_digests[0]);
+       SHA2_ALGO_TEST(test_msg2, 512_256, 256, sha512_256_test_digests[2]);
+
+       if (failed)
+               return (1);
+
+       (void) printf("Running performance tests (hashing 1024 MiB of "
+           "data):\n");
+       SHA2_PERF_TEST(256, 256);
+       SHA2_PERF_TEST(512, 512);
+
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/checksum/skein_test.c b/zfs/tests/zfs-tests/tests/functional/checksum/skein_test.c
new file mode 100644 (file)
index 0000000..37548f0
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * 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://opensource.org/licenses/CDDL-1.0.
+ * 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 2013 Saso Kiselkov. All rights reserved.
+ */
+
+/*
+ * This is just to keep the compiler happy about sys/time.h not declaring
+ * gettimeofday due to -D_KERNEL (we can do this since we're actually
+ * running in userspace, but we need -D_KERNEL for the remaining Skein code).
+ */
+#ifdef _KERNEL
+#undef _KERNEL
+#endif
+
+#include <sys/skein.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <stdio.h>
+#include <sys/time.h>
+#define NOTE(x)
+
+typedef        enum boolean { B_FALSE, B_TRUE } boolean_t;
+typedef        unsigned long long      u_longlong_t;
+
+/*
+ * Skein test suite using values from the Skein V1.3 specification found at:
+ * http://www.skein-hash.info/sites/default/files/skein1.3.pdf
+ */
+
+/*
+ * Test messages from the Skein spec, Appendix C.
+ */
+const uint8_t  test_msg0[] = {
+       0xFF
+};
+
+const uint8_t  test_msg1[] = {
+       0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
+       0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
+       0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
+       0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0
+};
+
+const uint8_t  test_msg2[] = {
+       0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
+       0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
+       0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
+       0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0,
+       0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8,
+       0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0,
+       0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8,
+       0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0
+};
+
+const uint8_t  test_msg3[] = {
+       0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
+       0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
+       0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
+       0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0,
+       0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8,
+       0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0,
+       0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8,
+       0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0,
+       0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8,
+       0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0,
+       0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8,
+       0xA7, 0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1, 0xA0,
+       0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98,
+       0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
+       0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88,
+       0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80
+};
+
+const uint8_t  test_msg4[] = {
+       0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8,
+       0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0,
+       0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8,
+       0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0,
+       0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8,
+       0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0,
+       0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8,
+       0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0,
+       0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8,
+       0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0,
+       0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8,
+       0xA7, 0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1, 0xA0,
+       0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98,
+       0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
+       0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88,
+       0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
+       0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78,
+       0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+       0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68,
+       0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
+       0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58,
+       0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+       0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
+       0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
+       0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38,
+       0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
+       0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28,
+       0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
+       0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18,
+       0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+       0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
+       0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
+};
+
+/*
+ * Test digests from the Skein spec, Appendix C.
+ */
+const uint8_t  skein_256_test_digests[][32] = {
+       {
+               /* for test_msg0 */
+               0x0B, 0x98, 0xDC, 0xD1, 0x98, 0xEA, 0x0E, 0x50,
+               0xA7, 0xA2, 0x44, 0xC4, 0x44, 0xE2, 0x5C, 0x23,
+               0xDA, 0x30, 0xC1, 0x0F, 0xC9, 0xA1, 0xF2, 0x70,
+               0xA6, 0x63, 0x7F, 0x1F, 0x34, 0xE6, 0x7E, 0xD2
+       },
+       {
+               /* for test_msg1 */
+               0x8D, 0x0F, 0xA4, 0xEF, 0x77, 0x7F, 0xD7, 0x59,
+               0xDF, 0xD4, 0x04, 0x4E, 0x6F, 0x6A, 0x5A, 0xC3,
+               0xC7, 0x74, 0xAE, 0xC9, 0x43, 0xDC, 0xFC, 0x07,
+               0x92, 0x7B, 0x72, 0x3B, 0x5D, 0xBF, 0x40, 0x8B
+       },
+       {
+               /* for test_msg2 */
+               0xDF, 0x28, 0xE9, 0x16, 0x63, 0x0D, 0x0B, 0x44,
+               0xC4, 0xA8, 0x49, 0xDC, 0x9A, 0x02, 0xF0, 0x7A,
+               0x07, 0xCB, 0x30, 0xF7, 0x32, 0x31, 0x82, 0x56,
+               0xB1, 0x5D, 0x86, 0x5A, 0xC4, 0xAE, 0x16, 0x2F
+       }
+       /* no test digests for test_msg3 and test_msg4 */
+};
+
+const uint8_t  skein_512_test_digests[][64] = {
+       {
+               /* for test_msg0 */
+               0x71, 0xB7, 0xBC, 0xE6, 0xFE, 0x64, 0x52, 0x22,
+               0x7B, 0x9C, 0xED, 0x60, 0x14, 0x24, 0x9E, 0x5B,
+               0xF9, 0xA9, 0x75, 0x4C, 0x3A, 0xD6, 0x18, 0xCC,
+               0xC4, 0xE0, 0xAA, 0xE1, 0x6B, 0x31, 0x6C, 0xC8,
+               0xCA, 0x69, 0x8D, 0x86, 0x43, 0x07, 0xED, 0x3E,
+               0x80, 0xB6, 0xEF, 0x15, 0x70, 0x81, 0x2A, 0xC5,
+               0x27, 0x2D, 0xC4, 0x09, 0xB5, 0xA0, 0x12, 0xDF,
+               0x2A, 0x57, 0x91, 0x02, 0xF3, 0x40, 0x61, 0x7A
+       },
+       {
+               /* no test vector for test_msg1 */
+               0,
+       },
+       {
+               /* for test_msg2 */
+               0x45, 0x86, 0x3B, 0xA3, 0xBE, 0x0C, 0x4D, 0xFC,
+               0x27, 0xE7, 0x5D, 0x35, 0x84, 0x96, 0xF4, 0xAC,
+               0x9A, 0x73, 0x6A, 0x50, 0x5D, 0x93, 0x13, 0xB4,
+               0x2B, 0x2F, 0x5E, 0xAD, 0xA7, 0x9F, 0xC1, 0x7F,
+               0x63, 0x86, 0x1E, 0x94, 0x7A, 0xFB, 0x1D, 0x05,
+               0x6A, 0xA1, 0x99, 0x57, 0x5A, 0xD3, 0xF8, 0xC9,
+               0xA3, 0xCC, 0x17, 0x80, 0xB5, 0xE5, 0xFA, 0x4C,
+               0xAE, 0x05, 0x0E, 0x98, 0x98, 0x76, 0x62, 0x5B
+       },
+       {
+               /* for test_msg3 */
+               0x91, 0xCC, 0xA5, 0x10, 0xC2, 0x63, 0xC4, 0xDD,
+               0xD0, 0x10, 0x53, 0x0A, 0x33, 0x07, 0x33, 0x09,
+               0x62, 0x86, 0x31, 0xF3, 0x08, 0x74, 0x7E, 0x1B,
+               0xCB, 0xAA, 0x90, 0xE4, 0x51, 0xCA, 0xB9, 0x2E,
+               0x51, 0x88, 0x08, 0x7A, 0xF4, 0x18, 0x87, 0x73,
+               0xA3, 0x32, 0x30, 0x3E, 0x66, 0x67, 0xA7, 0xA2,
+               0x10, 0x85, 0x6F, 0x74, 0x21, 0x39, 0x00, 0x00,
+               0x71, 0xF4, 0x8E, 0x8B, 0xA2, 0xA5, 0xAD, 0xB7
+       }
+       /* no test digests for test_msg4 */
+};
+
+const uint8_t  skein_1024_test_digests[][128] = {
+       {
+               /* for test_msg0 */
+               0xE6, 0x2C, 0x05, 0x80, 0x2E, 0xA0, 0x15, 0x24,
+               0x07, 0xCD, 0xD8, 0x78, 0x7F, 0xDA, 0x9E, 0x35,
+               0x70, 0x3D, 0xE8, 0x62, 0xA4, 0xFB, 0xC1, 0x19,
+               0xCF, 0xF8, 0x59, 0x0A, 0xFE, 0x79, 0x25, 0x0B,
+               0xCC, 0xC8, 0xB3, 0xFA, 0xF1, 0xBD, 0x24, 0x22,
+               0xAB, 0x5C, 0x0D, 0x26, 0x3F, 0xB2, 0xF8, 0xAF,
+               0xB3, 0xF7, 0x96, 0xF0, 0x48, 0x00, 0x03, 0x81,
+               0x53, 0x1B, 0x6F, 0x00, 0xD8, 0x51, 0x61, 0xBC,
+               0x0F, 0xFF, 0x4B, 0xEF, 0x24, 0x86, 0xB1, 0xEB,
+               0xCD, 0x37, 0x73, 0xFA, 0xBF, 0x50, 0xAD, 0x4A,
+               0xD5, 0x63, 0x9A, 0xF9, 0x04, 0x0E, 0x3F, 0x29,
+               0xC6, 0xC9, 0x31, 0x30, 0x1B, 0xF7, 0x98, 0x32,
+               0xE9, 0xDA, 0x09, 0x85, 0x7E, 0x83, 0x1E, 0x82,
+               0xEF, 0x8B, 0x46, 0x91, 0xC2, 0x35, 0x65, 0x65,
+               0x15, 0xD4, 0x37, 0xD2, 0xBD, 0xA3, 0x3B, 0xCE,
+               0xC0, 0x01, 0xC6, 0x7F, 0xFD, 0xE1, 0x5B, 0xA8
+       },
+       {
+               /* no test vector for test_msg1 */
+               0
+       },
+       {
+               /* no test vector for test_msg2 */
+               0
+       },
+       {
+               /* for test_msg3 */
+               0x1F, 0x3E, 0x02, 0xC4, 0x6F, 0xB8, 0x0A, 0x3F,
+               0xCD, 0x2D, 0xFB, 0xBC, 0x7C, 0x17, 0x38, 0x00,
+               0xB4, 0x0C, 0x60, 0xC2, 0x35, 0x4A, 0xF5, 0x51,
+               0x18, 0x9E, 0xBF, 0x43, 0x3C, 0x3D, 0x85, 0xF9,
+               0xFF, 0x18, 0x03, 0xE6, 0xD9, 0x20, 0x49, 0x31,
+               0x79, 0xED, 0x7A, 0xE7, 0xFC, 0xE6, 0x9C, 0x35,
+               0x81, 0xA5, 0xA2, 0xF8, 0x2D, 0x3E, 0x0C, 0x7A,
+               0x29, 0x55, 0x74, 0xD0, 0xCD, 0x7D, 0x21, 0x7C,
+               0x48, 0x4D, 0x2F, 0x63, 0x13, 0xD5, 0x9A, 0x77,
+               0x18, 0xEA, 0xD0, 0x7D, 0x07, 0x29, 0xC2, 0x48,
+               0x51, 0xD7, 0xE7, 0xD2, 0x49, 0x1B, 0x90, 0x2D,
+               0x48, 0x91, 0x94, 0xE6, 0xB7, 0xD3, 0x69, 0xDB,
+               0x0A, 0xB7, 0xAA, 0x10, 0x6F, 0x0E, 0xE0, 0xA3,
+               0x9A, 0x42, 0xEF, 0xC5, 0x4F, 0x18, 0xD9, 0x37,
+               0x76, 0x08, 0x09, 0x85, 0xF9, 0x07, 0x57, 0x4F,
+               0x99, 0x5E, 0xC6, 0xA3, 0x71, 0x53, 0xA5, 0x78
+       },
+       {
+               /* for test_msg4 */
+               0x84, 0x2A, 0x53, 0xC9, 0x9C, 0x12, 0xB0, 0xCF,
+               0x80, 0xCF, 0x69, 0x49, 0x1B, 0xE5, 0xE2, 0xF7,
+               0x51, 0x5D, 0xE8, 0x73, 0x3B, 0x6E, 0xA9, 0x42,
+               0x2D, 0xFD, 0x67, 0x66, 0x65, 0xB5, 0xFA, 0x42,
+               0xFF, 0xB3, 0xA9, 0xC4, 0x8C, 0x21, 0x77, 0x77,
+               0x95, 0x08, 0x48, 0xCE, 0xCD, 0xB4, 0x8F, 0x64,
+               0x0F, 0x81, 0xFB, 0x92, 0xBE, 0xF6, 0xF8, 0x8F,
+               0x7A, 0x85, 0xC1, 0xF7, 0xCD, 0x14, 0x46, 0xC9,
+               0x16, 0x1C, 0x0A, 0xFE, 0x8F, 0x25, 0xAE, 0x44,
+               0x4F, 0x40, 0xD3, 0x68, 0x00, 0x81, 0xC3, 0x5A,
+               0xA4, 0x3F, 0x64, 0x0F, 0xD5, 0xFA, 0x3C, 0x3C,
+               0x03, 0x0B, 0xCC, 0x06, 0xAB, 0xAC, 0x01, 0xD0,
+               0x98, 0xBC, 0xC9, 0x84, 0xEB, 0xD8, 0x32, 0x27,
+               0x12, 0x92, 0x1E, 0x00, 0xB1, 0xBA, 0x07, 0xD6,
+               0xD0, 0x1F, 0x26, 0x90, 0x70, 0x50, 0x25, 0x5E,
+               0xF2, 0xC8, 0xE2, 0x4F, 0x71, 0x6C, 0x52, 0xA5
+       }
+};
+
+int
+main(int argc, char *argv[])
+{
+       boolean_t       failed = B_FALSE;
+       uint64_t        cpu_mhz = 0;
+
+       if (argc == 2)
+               cpu_mhz = atoi(argv[1]);
+
+#define        SKEIN_ALGO_TEST(_m, mode, diglen, testdigest)                   \
+       do {                                                            \
+               Skein ## mode ## _Ctxt_t        ctx;                    \
+               uint8_t                         digest[diglen / 8];     \
+               (void) Skein ## mode ## _Init(&ctx, diglen);            \
+               (void) Skein ## mode ## _Update(&ctx, _m, sizeof (_m)); \
+               (void) Skein ## mode ## _Final(&ctx, digest);           \
+               (void) printf("Skein" #mode "/" #diglen                 \
+                   "\tMessage: " #_m "\tResult: ");                    \
+               if (bcmp(digest, testdigest, diglen / 8) == 0) {        \
+                       (void) printf("OK\n");                          \
+               } else {                                                \
+                       (void) printf("FAILED!\n");                     \
+                       failed = B_TRUE;                                \
+               }                                                       \
+               NOTE(CONSTCOND)                                         \
+       } while (0)
+
+#define        SKEIN_PERF_TEST(mode, diglen)                                   \
+       do {                                                            \
+               Skein ## mode ## _Ctxt_t ctx;                           \
+               uint8_t         digest[diglen / 8];                     \
+               uint8_t         block[131072];                          \
+               uint64_t        delta;                                  \
+               double          cpb = 0;                                \
+               int             i;                                      \
+               struct timeval  start, end;                             \
+               bzero(block, sizeof (block));                           \
+               (void) gettimeofday(&start, NULL);                      \
+               (void) Skein ## mode ## _Init(&ctx, diglen);            \
+               for (i = 0; i < 8192; i++) {                            \
+                       (void) Skein ## mode ## _Update(&ctx, block,    \
+                           sizeof (block));                            \
+               }                                                       \
+               (void) Skein ## mode ## _Final(&ctx, digest);           \
+               (void) gettimeofday(&end, NULL);                        \
+               delta = (end.tv_sec * 1000000llu + end.tv_usec) -       \
+                   (start.tv_sec * 1000000llu + start.tv_usec);        \
+               if (cpu_mhz != 0) {                                     \
+                       cpb = (cpu_mhz * 1e6 * ((double)delta /         \
+                           1000000)) / (8192 * 128 * 1024);            \
+               }                                                       \
+               (void) printf("Skein" #mode "/" #diglen "\t%llu us "    \
+                   "(%.02f CPB)\n", (u_longlong_t)delta, cpb);         \
+               NOTE(CONSTCOND)                                         \
+       } while (0)
+
+       (void) printf("Running algorithm correctness tests:\n");
+       SKEIN_ALGO_TEST(test_msg0, _256, 256, skein_256_test_digests[0]);
+       SKEIN_ALGO_TEST(test_msg1, _256, 256, skein_256_test_digests[1]);
+       SKEIN_ALGO_TEST(test_msg2, _256, 256, skein_256_test_digests[2]);
+       SKEIN_ALGO_TEST(test_msg0, _512, 512, skein_512_test_digests[0]);
+       SKEIN_ALGO_TEST(test_msg2, _512, 512, skein_512_test_digests[2]);
+       SKEIN_ALGO_TEST(test_msg3, _512, 512, skein_512_test_digests[3]);
+       SKEIN_ALGO_TEST(test_msg0, 1024, 1024, skein_1024_test_digests[0]);
+       SKEIN_ALGO_TEST(test_msg3, 1024, 1024, skein_1024_test_digests[3]);
+       SKEIN_ALGO_TEST(test_msg4, 1024, 1024, skein_1024_test_digests[4]);
+       if (failed)
+               return (1);
+
+       (void) printf("Running performance tests (hashing 1024 MiB of "
+           "data):\n");
+       SKEIN_PERF_TEST(_256, 256);
+       SKEIN_PERF_TEST(_512, 512);
+       SKEIN_PERF_TEST(1024, 1024);
+
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/Makefile.am b/zfs/tests/zfs-tests/tests/functional/clean_mirror/Makefile.am
new file mode 100644 (file)
index 0000000..2e37147
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/clean_mirror
+dist_pkgdata_SCRIPTS = \
+       clean_mirror_common.kshlib \
+       default.cfg \
+        cleanup.ksh \
+       setup.ksh \
+       clean_mirror_001_pos.ksh \
+       clean_mirror_002_pos.ksh \
+       clean_mirror_003_pos.ksh \
+       clean_mirror_004_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_001_pos.ksh
new file mode 100755 (executable)
index 0000000..8dd337a
--- /dev/null
@@ -0,0 +1,53 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/clean_mirror/clean_mirror_common.kshlib
+
+#
+# DESCRIPTION:
+# The primary side of a zpool mirror can be zeroed without causing damage
+# to the data in the pool
+#
+# STRATEGY:
+# 1) Write several files to the ZFS filesystem mirror
+# 2) dd from /dev/zero over the primary side of the mirror
+# 3) verify that all the file contents are unchanged on the file system
+#
+
+verify_runnable "global"
+
+log_assert "The primary side of a zpool mirror may be completely wiped" \
+       "without affecting the content of the pool"
+
+overwrite_verify_mirror $SIDE_PRIMARY /dev/zero
+
+log_pass "The overwrite had no effect on the data"
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_002_pos.ksh
new file mode 100755 (executable)
index 0000000..a156368
--- /dev/null
@@ -0,0 +1,53 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/clean_mirror/clean_mirror_common.kshlib
+
+#
+# DESCRIPTION:
+# The secondary side of a zpool mirror can be zeroed without causing damage
+# to the data in the pool
+#
+# STRATEGY:
+# 1) Write several files to the ZFS filesystem in the mirrored pool
+# 2) dd from /dev/zero over the secondary side of the mirror
+# 3) verify that all the file contents are unchanged on the file system
+#
+
+verify_runnable "global"
+
+log_assert "The primary side of a zpool mirror may be completely wiped" \
+       "without affecting the content of the pool"
+
+overwrite_verify_mirror $SIDE_SECONDARY /dev/zero
+
+log_pass "The overwrite had no effect on the data"
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_003_pos.ksh
new file mode 100755 (executable)
index 0000000..144dcf1
--- /dev/null
@@ -0,0 +1,53 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/clean_mirror/clean_mirror_common.kshlib
+
+#
+# DESCRIPTION:
+# The primary side of a zpool mirror can be mangled without causing damage
+# to the data in the pool
+#
+# STRATEGY:
+# 1) Write several files to the ZFS filesystem mirror
+# 2) dd from /dev/urandom over the primary side of the mirror
+# 3) verify that all the file contents are unchanged on the file system
+#
+
+verify_runnable "global"
+
+log_assert "The primary side of a zpool mirror may be completely mangled" \
+       "without affecting the content of the pool"
+
+overwrite_verify_mirror $SIDE_PRIMARY /dev/urandom
+
+log_pass "The overwrite did not have any effect on the data"
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_004_pos.ksh
new file mode 100755 (executable)
index 0000000..ce1aac5
--- /dev/null
@@ -0,0 +1,53 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/clean_mirror/clean_mirror_common.kshlib
+
+#
+# DESCRIPTION:
+# The secondary side of a zpool mirror can be mangled without causing damage
+# to the data in the pool
+#
+# STRATEGY:
+# 1) Write several files to the ZFS filesystem in the mirrored pool
+# 2) dd from /dev/urandom over the secondary side of the mirror
+# 3) verify that all the file contents are unchanged on the file system
+#
+
+verify_runnable "global"
+
+log_assert "The primary side of a zpool mirror may be completely mangled" \
+       "without affecting the content of the pool"
+
+overwrite_verify_mirror $SIDE_SECONDARY /dev/urandom
+
+log_pass "The overwrite had no effect on the data"
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib b/zfs/tests/zfs-tests/tests/functional/clean_mirror/clean_mirror_common.kshlib
new file mode 100644 (file)
index 0000000..328e940
--- /dev/null
@@ -0,0 +1,112 @@
+#
+# 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, 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/clean_mirror/default.cfg
+
+# Most of the code related to the clearing of mirrors is duplicated in all
+# the test cases below this directory, barring a few minor changes
+# involving the device to be affected and the 'object' to use to mangle
+# the contents of the mirror.
+# This code is sourced into each of these test cases.
+
+#
+# Synchronize all the data in pool
+#
+# $1 pool name
+#
+function sync_pool #pool
+{
+       typeset pool=$1
+
+       log_must $SYNC
+       log_must $SLEEP 2
+       # Flush all the pool data.
+       typeset -i ret
+       $ZPOOL scrub $pool >/dev/null 2>&1
+       ret=$?
+       (( $ret != 0 )) && \
+               log_fail "$ZPOOL scrub $pool failed."
+
+       while ! is_pool_scrubbed $pool; do
+               if is_pool_resilvered $pool ; then
+                       log_fail "$pool should not be resilver completed."
+               fi
+               log_must $SLEEP 2
+       done
+}
+
+function overwrite_verify_mirror
+{
+       typeset AFFECTED_DEVICE=$1
+       typeset OVERWRITING_DEVICE=$2
+
+       typeset atfile=0
+       set -A files
+       set -A cksums
+       set -A newcksums
+
+       while (( atfile < FILE_COUNT )); do
+               files[$atfile]=$TESTDIR/file.$atfile
+               log_must $FILE_WRITE -o create -f $TESTDIR/file.$atfile \
+                       -b $FILE_SIZE -c 1
+               cksums[$atfile]=$($CKSUM ${files[$atfile]})
+               (( atfile = atfile + 1 ))
+       done
+
+       # dd the primary side of the mirror
+       log_must $DD if=$OVERWRITING_DEVICE of=$AFFECTED_DEVICE \
+               seek=8 bs=$DD_BLOCK count=$(( DD_COUNT - 128 )) conv=notrunc
+
+       atfile=0
+
+       #
+       # Flush out the cache so that we ensure we're reading from disk.
+       #
+       log_must $ZPOOL export $TESTPOOL
+       log_must $ZPOOL import $TESTPOOL
+
+       typeset -i failedcount=0
+       while (( atfile < FILE_COUNT )); do
+               files[$atfile]=$TESTDIR/file.$atfile
+               newcksum=$($CKSUM ${files[$atfile]})
+               if [[ $newcksum != ${cksums[$atfile]} ]]; then
+                       (( failedcount = failedcount + 1 ))
+               fi
+               $RM -f ${files[$atfile]}
+               (( atfile = atfile + 1 ))
+       done
+
+       if (( $failedcount > 0 )); then
+               log_fail "of the $FILE_COUNT files $failedcount did not " \
+                   "have the same checksum before and after."
+       fi
+
+       sync_pool $TESTPOOL
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/clean_mirror/cleanup.ksh
new file mode 100755 (executable)
index 0000000..05ef9c1
--- /dev/null
@@ -0,0 +1,55 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/clean_mirror/default.cfg
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+$DF -F zfs -h | $GREP "$TESTFS " >/dev/null
+[[ $? == 0 ]] && log_must $ZFS umount -f $TESTDIR
+destroy_pool $TESTPOOL
+
+if is_mpath_device $MIRROR_PRIMARY; then
+       $FORMAT $DEV_DSKDIR/$MIRROR_PRIMARY -s rm 1
+fi
+if is_mpath_device $MIRROR_SECONDARY; then
+       $FORMAT $DEV_DSKDIR/$MIRROR_SECONDARY -s rm 1
+fi
+# recreate and destroy a zpool over the disks to restore the partitions to
+# normal
+if [[ -n $SINGLE_DISK ]]; then
+       log_must cleanup_devices $MIRROR_PRIMARY
+else
+       log_must cleanup_devices $MIRROR_PRIMARY $MIRROR_SECONDARY
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/default.cfg b/zfs/tests/zfs-tests/tests/functional/clean_mirror/default.cfg
new file mode 100644 (file)
index 0000000..756ce23
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+typeset -i NUMBER_OF_DISKS=0
+for i in $DISKS; do
+       [[ -n $MIRROR_PRIMARY ]] && MIRROR_SECONDARY=$i
+       [[ -z $MIRROR_PRIMARY ]] && MIRROR_PRIMARY=$i
+done
+
+if [[ -z $MIRROR_SECONDARY ]]; then
+       # We need to repartition the single disk to two slices
+       SINGLE_DISK=$MIRROR_PRIMARY
+       MIRROR_SECONDARY=$MIRROR_PRIMARY
+       SIDE_PRIMARY_PART=0
+       SIDE_SECONDARY_PART=1
+
+       if is_linux; then
+               if is_mpath_device $SINGLE_DISK; then
+                       export DEV_DSKDIR=$DEV_MPATHDIR
+               else
+                       export DEV_DSKDIR=$DEV_RDSKDIR
+               fi
+               if ( is_mpath_device $SINGLE_DISK ) && [[ -z $($ECHO $SINGLE_DISK | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $SINGLE_DISK ); then
+                       SIDE_PRIMARY=${SINGLE_DISK}1
+                       SIDE_SECONDARY=${SINGLE_DISK}2
+               elif ( is_mpath_device $SINGLE_DISK || is_loop_device $SINGLE_DISK ); then
+                       SIDE_PRIMARY=${SINGLE_DISK}p1
+                       SIDE_SECONDARY=${SINGLE_DISK}p2
+               else
+                       log_fail "$SINGLE_DISK not supported for partitioning."
+               fi
+       else
+               export DEV_DSKDIR="/dev"
+               SIDE_PRIMARY=${SINGLE_DISK}s${SIDE_PRIMARY_PART}
+               SIDE_SECONDARY=${SINGLE_DISK}s${SIDE_SECONDARY_PART}
+       fi
+else
+       SIDE_PRIMARY_PART=0
+       SIDE_SECONDARY_PART=0
+       if is_linux; then
+               if is_mpath_device $MIRROR_PRIMARY; then
+                       export DEV_DSKDIR=$DEV_MPATHDIR
+               else
+                       export DEV_DSKDIR=$DEV_RDSKDIR
+               fi
+               if ( is_mpath_device $MIRROR_PRIMARY ) && [[ -z $($ECHO $MIRROR_PRIMARY | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $MIRROR_PRIMARY ); then
+                       SIDE_PRIMARY=${MIRROR_PRIMARY}1
+               elif ( is_mpath_device $MIRROR_PRIMARY || is_loop_device $MIRROR_PRIMARY ); then
+                       SIDE_PRIMARY=${MIRROR_PRIMARY}p1
+               else
+                       log_fail "$MIRROR_PRIMARY not supported for partitioning."
+               fi
+               if ( is_mpath_device $MIRROR_SECONDARY ) && [[ -z $($ECHO $MIRROR_SECONDARY | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $MIRROR_SECONDARY ); then
+                       SIDE_SECONDARY=${MIRROR_SECONDARY}1
+               elif ( is_mpath_device $MIRROR_SECONDARY || is_loop_device $MIRROR_SECONDARY ); then
+                       SIDE_SECONDARY=${MIRROR_SECONDARY}p1
+               else
+                       log_fail "$MIRROR_SECONDARY not supported for partitioning."
+               fi
+
+       else
+               export DEV_DSKDIR="/dev"
+               SIDE_PRIMARY=${MIRROR_PRIMARY}s${SIDE_PRIMARY_PART}
+               SIDE_SECONDARY=${MIRROR_SECONDARY}s${SIDE_SECONDARY_PART}
+       fi
+fi
+
+export MIRROR_PRIMARY MIRROR_SECONDARY SINGLE_DISK SIDE_PRIMARY SIDE_SECONDARY
+
+export FILE_COUNT=10
+export FILE_SIZE=$(( 1024 * 1024 ))
+export MIRROR_MEGS=100
+export MIRROR_SIZE=${MIRROR_MEGS}m # default mirror size
+export DD_BLOCK=$(( 64 * 1024 ))
+export DD_COUNT=$(( MIRROR_MEGS * 1024 * 1024 / DD_BLOCK ))
diff --git a/zfs/tests/zfs-tests/tests/functional/clean_mirror/setup.ksh b/zfs/tests/zfs-tests/tests/functional/clean_mirror/setup.ksh
new file mode 100755 (executable)
index 0000000..2d17bf9
--- /dev/null
@@ -0,0 +1,52 @@
+#! /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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/clean_mirror/default.cfg
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+if ! is_physical_device $DISKS; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+if [[ -n $SINGLE_DISK ]]; then
+       log_note "Partitioning a single disk ($SINGLE_DISK)"
+else
+       log_note "Partitioning disks ($MIRROR_PRIMARY $MIRROR_SECONDARY)"
+fi
+
+log_must set_partition $SIDE_PRIMARY_PART "" $MIRROR_SIZE $MIRROR_PRIMARY
+log_must set_partition $SIDE_SECONDARY_PART "" $MIRROR_SIZE $MIRROR_SECONDARY
+
+default_mirror_setup $SIDE_PRIMARY $SIDE_SECONDARY
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/Makefile.am
new file mode 100644 (file)
index 0000000..5dc72de
--- /dev/null
@@ -0,0 +1,47 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root
+dist_pkgdata_SCRIPTS = \
+       cli_common.kshlib
+
+SUBDIRS = \
+       zdb \
+       zfs \
+       zfs_clone \
+       zfs_copies \
+       zfs_create \
+       zfs_destroy \
+       zfs_get \
+       zfs_inherit \
+       zfs_mount \
+       zfs_promote \
+       zfs_property \
+       zfs_receive \
+       zfs_rename \
+       zfs_reservation \
+       zfs_rollback \
+       zfs_send \
+       zfs_set \
+       zfs_share \
+       zfs_snapshot \
+       zfs_unmount \
+       zfs_unshare \
+       zfs_upgrade \
+       zpool \
+       zpool_add \
+       zpool_attach \
+       zpool_clear \
+       zpool_create \
+       zpool_destroy \
+       zpool_detach \
+       zpool_expand \
+       zpool_export \
+       zpool_get \
+       zpool_history \
+       zpool_import \
+       zpool_offline \
+       zpool_online \
+       zpool_remove \
+       zpool_replace \
+       zpool_scrub \
+       zpool_set \
+       zpool_status \
+       zpool_upgrade
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/cli_common.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/cli_common.kshlib
new file mode 100644 (file)
index 0000000..06e794e
--- /dev/null
@@ -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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Get the checksum and size of the file.
+#
+function get_cksum # <file path>
+{
+       return $($CKSUM $1 | $AWK '{print $1 $2}')
+}
+
+#
+# Compare the check sum of target files with the original file
+#
+
+function compare_cksum #<orig_data> <target_data1>...<target_datan>
+{
+       typeset orig_data=$1
+       typeset orig_sum=$(get_cksum $orig_data)
+       typeset target_sum=""
+       typeset bad_data_list=""
+       typeset -i bad_count=0
+
+       shift
+       for data in $@; do
+               if [[ ! -e $data ]]; then
+                       bad_data_list="$bad_data_list $data"
+                       (( bad_count +=1 ))
+                       continue
+               fi
+
+               target_sum=$(get_cksum $data)
+               if [[ $target_sum != $orig_sum ]]; then
+                       bad_data_list="$bad_data_list $data"
+                       (( bad_count +=1 ))
+               fi
+       done
+
+       [[ $bad_data_list != "" ]] && \
+               log_fail "Data corruptions appear during send->receive." \
+                       "There are total $bad_count corruptions. They are:\n"\
+                       "$bad_data_list"
+}
+
+#
+# Check the received dataset exists or not
+#
+function receive_check #<dataset1>...<datasetn>
+{
+       typeset bad_rst_tgts=""
+
+       for dataset in $@; do
+               ! datasetexists $dataset && \
+                       bad_rst_tgts="$bad_rst_tgts $dataset"
+       done
+
+       if [[ $bad_rst_tgts != "" ]]; then
+               log_fail "Restoring fails. The specified datasets"\
+                       "$bad_rst_tgts are not being received."
+       fi
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zdb/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zdb/Makefile.am
new file mode 100644 (file)
index 0000000..05711c2
--- /dev/null
@@ -0,0 +1,3 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zdb
+dist_pkgdata_SCRIPTS = \
+       zdb_001_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zdb/zdb_001_neg.ksh
new file mode 100755 (executable)
index 0000000..9ef8e1a
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# A badly formed parameter passed to zdb(1) should
+# return an error.
+#
+# STRATEGY:
+# 1. Create an array containg bad zdb parameters.
+# 2. For each element, execute the sub-command.
+# 3. Verify it returns an error.
+#
+
+verify_runnable "global"
+
+set -A args "create" "add" "destroy" "import fakepool" \
+    "export fakepool" "create fakepool" "add fakepool" \
+    "create mirror" "create raidz" \
+    "create mirror fakepool" "create raidz fakepool" \
+    "create raidz1 fakepool" "create raidz2 fakepool" \
+    "create fakepool mirror" "create fakepool raidz" \
+    "create fakepool raidz1" "create fakepool raidz2" \
+    "add fakepool mirror" "add fakepool raidz" \
+    "add fakepool raidz1" "add fakepool raidz2" \
+    "add mirror fakepool" "add raidz fakepool" \
+    "add raidz1 fakepool" "add raidz2 fakepool" \
+    "setvprop" "blah blah" "-%" "--?" "-*" "-=" \
+    "-a" "-f" "-g" "-h" "-j" "-k" "-m" "-n" "-o" "-p" "-p /tmp" \
+    "-q" "-r" "-t" "-w" "-x" "-y" "-z" \
+    "-D" "-E" "-G" "-H" "-I" "-J" "-K" "-M" \
+    "-N" "-Q" "-R" "-S" "-W" "-Y" "-Z"
+
+log_assert "Execute zdb using invalid parameters."
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZDB ${args[i]}
+
+       ((i = i + 1))
+done
+
+log_pass "Badly formed zdb parameters fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/Makefile.am
new file mode 100644 (file)
index 0000000..8b0ee27
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_001_neg.ksh \
+       zfs_002_pos.ksh \
+       zfs_003_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_001_neg.ksh
new file mode 100755 (executable)
index 0000000..bfcc864
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Try each zfs(1) sub-command without parameters to make sure
+# it returns an error.
+#
+# STRATEGY:
+# 1. Create an array of parameters
+# 2. For each parameter in the array, execute the sub-command
+# 3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+
+set -A args  "" "create" "create -s" "create -V" "create -s -V" \
+    "destroy" "destroy -f" "destroy -r" "destroy -R" "destroy -rRf" \
+    "snapshot" "snapshot -r" \
+    "rollback" "rollback -r" "rollback -R" "rollback -f" "rollback -rRf" \
+    "clone" "clone -p" "promote" "rename" "rename -p" "rename -r" "list blah" \
+    "set" "get" "get -rHp" "get -o" "get -s" \
+    "inherit" "inherit -r"  "quota=" \
+    "set reservation=" "set atime=" "set checksum=" "set compression=" \
+    "set type="  "set creation=" "set used=" "set available=" "set referenced=" \
+    "set compressratio=" "set mounted=" "set origin=" "set quota=" \
+    "set reservation=" "set volsize=" " set volblocksize=" "set recordsize=" \
+    "set mountpoint=" "set devices=" "set exec=" "set setuid=" "set readonly=" \
+    "set zoned=" "set snapdir=" "set aclmode=" "set aclinherit=" \
+    "set quota=blah" "set reservation=blah" "set atime=blah" "set checksum=blah" \
+    "set compression=blah" \
+    "upgrade blah" "mount blah" "mount -o" \
+    "umount blah" "unmount" "unmount blah" "unmount -f" \
+    "share" "unshare" "send" "send -i" "receive" "receive -d" "receive -vnF" \
+    "recv" "recv -d" "recv -vnF" "allow" "unallow" \
+    "blah blah" "-%" "--" "--?" "-*" "-="
+
+log_assert "Badly-formed zfs sub-command should return an error."
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZFS ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Badly formed zfs sub-commands fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_002_pos.ksh
new file mode 100755 (executable)
index 0000000..473bc65
--- /dev/null
@@ -0,0 +1,113 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# With ZFS_ABORT set, all zfs commands should be able to abort and generate a
+# core file.
+#
+# STRATEGY:
+# 1. Create an array of zfs command
+# 2. Execute each command in the array
+# 3. Verify the command aborts and generate a core file
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       unset ZFS_ABORT
+
+       if [[ -d $corepath ]]; then
+               $RM -rf $corepath
+       fi
+       for ds in $fs1 $fs $ctr; do
+               if datasetexists $ds; then
+                       log_must $ZFS destroy -rRf $ds
+               fi
+       done
+}
+
+log_assert "With ZFS_ABORT set, all zfs commands can abort and generate a " \
+    "core file."
+log_onexit cleanup
+
+#preparation work for testing
+corepath=$TESTDIR/core
+if [[ -d $corepath ]]; then
+       $RM -rf $corepath
+fi
+log_must $MKDIR $corepath
+
+ctr=$TESTPOOL/$TESTCTR
+log_must $ZFS create $ctr
+
+fs=$ctr/$TESTFS
+fs1=$ctr/$TESTFS1
+snap=$fs@$TESTSNAP
+clone=$ctr/$TESTCLONE
+streamf=$corepath/s.$$
+
+typeset cmds=("create $fs" "list $fs" "snapshot $snap" "set snapdir=hidden $fs" \
+    "get snapdir $fs" "rollback $snap" "inherit snapdir $fs" \
+    "rename $fs $fs-new" "rename $fs-new $fs" "unmount $fs" \
+    "mount $fs" "share $fs" "unshare $fs" "send $snap \>$streamf" \
+    "receive $fs1 \<$streamf" "clone $snap $clone" "promote $clone" \
+    "promote $fs" "destroy -rRf $fs")
+
+typeset badparams=("" "create" "destroy" "snapshot" "rollback" "clone" \
+    "promote" "rename" "list -*" "set" "get -*" "inherit" "mount -A" \
+    "unmount" "share" "unshare" "send" "receive")
+
+if is_linux; then
+       ulimit -c unlimited
+       echo "$corepath/core.zfs" >/proc/sys/kernel/core_pattern
+       echo 0 >/proc/sys/kernel/core_uses_pid
+else
+       log_must $COREADM -p ${corepath}/core.%f
+fi
+
+log_must export ZFS_ABORT=yes
+
+for subcmd in "${cmds[@]}" "${badparams[@]}"; do
+       $ZFS $subcmd >/dev/null 2>&1 && log_fail "$subcmd passed incorrectly."
+       corefile=${corepath}/core.zfs
+       if [[ ! -e $corefile ]]; then
+               log_fail "$ZFS $subcmd cannot generate core file with " \
+                   "ZFS_ABORT set."
+       fi
+       log_must $RM -f $corefile
+done
+
+log_pass "With ZFS_ABORT set, zfs command can abort and generate core file " \
+    "as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs/zfs_003_neg.ksh
new file mode 100755 (executable)
index 0000000..63c735f
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# zfs command will failed with unexpected scenarios:
+# (1) ZFS_DEV cannot be opened
+# (2) MNTTAB cannot be opened
+#
+# STRATEGY:
+# 1. Create an array of zfs command
+# 2. Execute each command in the array
+# 3. Verify the command aborts and generate a core file
+#
+
+verify_runnable "global"
+
+log_assert "zfs fails with unexpected scenario."
+
+#verify zfs failed if ZFS_DEV cannot be opened
+ZFS_DEV=/dev/zfs
+
+if is_linux; then
+       # On Linux, we use /proc/self/mounts, which cannot be moved.
+       MNTTAB=
+fi
+
+for file in $ZFS_DEV $MNTTAB; do
+       if [[ -e $file ]]; then
+               $MV $file ${file}.bak
+       fi
+       for cmd in "" "list" "get all" "mount"; do
+               log_mustnot eval "$ZFS $cmd >/dev/null 2>&1"
+       done
+       $MV ${file}.bak $file
+done
+
+log_pass "zfs fails with unexpected scenario as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/Makefile.am
new file mode 100644 (file)
index 0000000..7c7728c
--- /dev/null
@@ -0,0 +1,14 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_clone
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_clone_001_neg.ksh \
+       zfs_clone_002_pos.ksh \
+       zfs_clone_003_pos.ksh \
+       zfs_clone_004_pos.ksh \
+       zfs_clone_005_pos.ksh \
+       zfs_clone_006_pos.ksh \
+       zfs_clone_007_pos.ksh \
+       zfs_clone_008_neg.ksh \
+       zfs_clone_009_neg.ksh \
+       zfs_clone_010_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/cleanup.ksh
new file mode 100755 (executable)
index 0000000..d247991
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_container_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/setup.ksh
new file mode 100755 (executable)
index 0000000..985554f
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_container_volume_setup ${DISK}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_001_neg.ksh
new file mode 100755 (executable)
index 0000000..e98b0d8
--- /dev/null
@@ -0,0 +1,126 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs clone' should fail with inapplicable scenarios, including:
+#              * Null arguments
+#              * non-existant snapshots.
+#              * invalid characters in ZFS namesapec
+#              * Leading slash in the target clone name
+#              * The argument contains an empty component.
+#              * The pool specified in the target doesn't exist.
+#              * The parent dataset of the target doesn't exist.
+#              * The argument refer to a pool, not dataset.
+#              * The target clone already exists.
+#              * Null target clone argument.
+#              * Too many arguments.
+#               * Invalid record sizes.
+#
+# STRATEGY:
+#      1. Create an array of parameters
+#      2. For each parameter in the array, execute the sub-command
+#      3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+typeset target1=$TESTPOOL/$TESTFS1
+typeset target2=$TESTPOOL/$TESTCTR1/$TESTFS1
+typeset targets="$target1 $target2 $NONEXISTPOOLNAME/$TESTFS"
+
+set -A args "" \
+       "$TESTPOOL/$TESTFS@blah $target1" "$TESTPOOL/$TESTVOL@blah $target1" \
+       "$TESTPOOL/$TESTFS@blah* $target1" "$TESTPOOL/$TESTVOL@blah* $target1" \
+       "$SNAPFS $target1*" "$SNAPFS1 $target1*" \
+       "$SNAPFS /$target1" "$SNAPFS1 /$target1" \
+       "$SNAPFS $TESTPOOL//$TESTFS1" "$SNAPFS1 $TESTPOOL//$TESTFS1" \
+       "$SNAPFS $NONEXISTPOOLNAME/$TESTFS" "$SNAPFS1 $NONEXISTPOOLNAME/$TESTFS" \
+       "$SNAPFS" "$SNAPFS1" \
+       "$SNAPFS $target1 $target2" "$SNAPFS1 $target1 $target2" \
+        "-o recordsize=2M $SNAPFS1 $target1" \
+        "-o recordsize=128B $SNAPFS1 $target1"
+typeset -i argsnum=${#args[*]}
+typeset -i j=0
+while (( j < argsnum )); do
+       args[((argsnum+j))]="-p ${args[j]}"
+       ((j = j + 1))
+done
+
+set -A moreargs "$SNAPFS $target2" "$SNAPFS1 $target2" \
+       "$SNAPFS $TESTPOOL" "$SNAPFS1 $TESTPOOL" \
+       "$SNAPFS $TESTPOOL/$TESTCTR" "$SNAPFS $TESTPOOL/$TESTFS" \
+       "$SNAPFS1 $TESTPOOL/$TESTCTR" "$SNAPFS1 $TESTPOOL/$TESTFS"
+
+set -A args ${args[*]} ${moreargs[*]}
+
+function setup_all
+{
+       log_note "Create snapshots and mount them..."
+
+       for snap in $SNAPFS $SNAPFS1 ; do
+               if ! snapexists $snap ; then
+                       log_must $ZFS snapshot $snap
+               fi
+       done
+
+       return 0
+}
+
+function cleanup_all
+{
+       for fs in $targets; do
+               datasetexists $fs && log_must $ZFS destroy -f $fs
+       done
+
+       for snap in $SNAPFS $SNAPFS1 ; do
+               snapexists $snap && log_must $ZFS destroy -Rf $snap
+       done
+
+       return 0
+}
+
+log_assert "Badly-formed 'zfs clone' with inapplicable scenarios" \
+       "should return an error."
+log_onexit cleanup_all
+
+setup_all
+
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZFS clone ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Badly formed 'zfs clone' with inapplicable scenarios" \
+       "fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_002_pos.ksh
new file mode 100755 (executable)
index 0000000..1b376eb
--- /dev/null
@@ -0,0 +1,89 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs clone -p' should work as expected
+#
+# STRATEGY:
+#      1. prepare snapshots
+#      2. make sure without -p option, 'zfs clone' will fail
+#      3. with -p option, the clone can be created
+#      4. run 'zfs clone -p' again, the exit code should be zero
+#
+
+verify_runnable "both"
+
+function setup_all
+{
+       log_note "Create snapshots and mount them..."
+
+       for snap in $SNAPFS $SNAPFS1 ; do
+               if ! snapexists $snap ; then
+                       log_must $ZFS snapshot $snap
+               fi
+       done
+
+       return 0
+}
+
+function cleanup_all
+{
+
+       if datasetexists $TESTPOOL/notexist ; then
+               log_must $ZFS destroy -rRf $TESTPOOL/notexist
+       fi
+
+       for snap in $SNAPFS $SNAPFS1 ; do
+               if snapexists $snap ; then
+                       log_must $ZFS destroy -Rf $snap
+               fi
+       done
+
+       return 0
+}
+
+log_assert "clone -p should work as expected."
+log_onexit cleanup_all
+
+setup_all
+
+log_must verify_opt_p_ops "clone" "fs" $SNAPFS \
+        $TESTPOOL/notexist/new/clonefs$$
+
+if is_global_zone ; then
+       log_must verify_opt_p_ops "clone" "vol" $SNAPFS1 \
+                $TESTPOOL/notexist/new/clonevol$$
+fi
+
+log_pass "clone -p should work as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_003_pos.ksh
new file mode 100755 (executable)
index 0000000..103f2d3
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs clone -o property=value filesystem' can successfully create a ZFS
+# clone filesystem with correct property set.
+#
+# STRATEGY:
+# 1. Create a ZFS clone filesystem in the storage pool with -o option
+# 2. Verify the filesystem created successfully
+# 3. Verify the property is correctly set
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists $SNAPFS ; then
+               log_must $ZFS destroy -Rf $SNAPFS
+       fi
+}
+
+log_onexit cleanup
+
+
+log_assert "'zfs clone -o property=value filesystem' can successfully create" \
+          "a ZFS clone filesystem with correct property set."
+
+log_must $ZFS snapshot $SNAPFS
+
+typeset -i i=0
+while (( $i < ${#RW_FS_PROP[*]} )); do
+       log_must $ZFS clone -o ${RW_FS_PROP[$i]} $SNAPFS $TESTPOOL/$TESTCLONE
+       datasetexists $TESTPOOL/$TESTCLONE || \
+               log_fail "zfs clone $TESTPOOL/$TESTCLONE fail."
+       propertycheck $TESTPOOL/$TESTCLONE ${RW_FS_PROP[i]} || \
+               log_fail "${RW_FS_PROP[i]} is failed to set."
+       log_must $ZFS destroy -f $TESTPOOL/$TESTCLONE
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs clone -o property=value filesystem' can successfully create" \
+         "a ZFS clone filesystem with correct property set."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_004_pos.ksh
new file mode 100755 (executable)
index 0000000..03bf7d7
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs clone -o property=value filesystem' can successfully create a ZFS
+# clone filesystem with multiple properties set.
+#
+# STRATEGY:
+# 1. Create a ZFS clone filesystem in the storage pool with multiple -o options
+# 2. Verify the filesystem created successfully
+# 3. Verify the properties are correctly set
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists $SNAPFS ; then
+               log_must $ZFS destroy -Rf $SNAPFS
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "'zfs clone -o property=value filesystem' can successfully create" \
+          "a ZFS clone filesystem with multiple properties set."
+
+typeset -i i=0
+typeset opts=""
+
+log_must $ZFS snapshot $SNAPFS
+
+while (( $i < ${#RW_FS_PROP[*]} )); do
+        if [[ ${RW_FS_PROP[$i]} != *"checksum"* ]]; then
+               opts="$opts -o ${RW_FS_PROP[$i]}"
+       fi
+       (( i = i + 1 ))
+done
+
+log_must $ZFS clone $opts $SNAPFS $TESTPOOL/$TESTCLONE
+datasetexists $TESTPOOL/$TESTCLONE || \
+       log_fail "zfs create $TESTPOOL/$TESTCLONE fail."
+
+i=0
+while (( $i < ${#RW_FS_PROP[*]} )); do
+        if [[ ${RW_FS_PROP[$i]} != *"checksum"* ]]; then
+               propertycheck $TESTPOOL/$TESTCLONE ${RW_FS_PROP[i]} || \
+                       log_fail "${RW_FS_PROP[i]} is failed to set."
+       fi
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs clone -o property=value filesystem' can successfully create" \
+         "a ZFS clone filesystem with multiple properties set."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_005_pos.ksh
new file mode 100755 (executable)
index 0000000..776dfd5
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs clone -o property=value -V size volume' can successfully create a ZFS
+# clone volume with correct property set.
+#
+# STRATEGY:
+# 1. Create a ZFS clone volume in the storage pool with -o option
+# 2. Verify the volume created successfully
+# 3. Verify the property is correctly set
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if snapexists $SNAPFS1 ; then
+               log_must $ZFS destroy -Rf $SNAPFS1
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "'zfs clone -o property=value -V size volume' can successfully" \
+          "create a ZFS clone volume with correct property set."
+
+log_must $ZFS snapshot $SNAPFS1
+typeset -i i=0
+while (( $i < ${#RW_VOL_CLONE_PROP[*]} )); do
+       log_must $ZFS clone -o ${RW_VOL_CLONE_PROP[$i]} $SNAPFS1 $TESTPOOL/$TESTCLONE
+       datasetexists $TESTPOOL/$TESTCLONE || \
+               log_fail "zfs clone $TESTPOOL/$TESTCLONE fail."
+       propertycheck $TESTPOOL/$TESTCLONE ${RW_VOL_CLONE_PROP[i]} || \
+               log_fail "${RW_VOL_CLONE_PROP[i]} is failed to set."
+       log_must $ZFS destroy -f $TESTPOOL/$TESTCLONE
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs clone -o property=value volume' can successfully" \
+       "create a ZFS clone volume with correct property set."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_006_pos.ksh
new file mode 100755 (executable)
index 0000000..84f55c8
--- /dev/null
@@ -0,0 +1,86 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs clone -o property=value volume' can successfully create a ZFS
+# clone volume with multiple properties set.
+#
+# STRATEGY:
+# 1. Create a ZFS clone volume in the storage pool with -o option
+# 2. Verify the volume created successfully
+# 3. Verify the properties are correctly set
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if snapexists $SNAPFS1 ; then
+               log_must $ZFS destroy -Rf $SNAPFS1
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "'zfs clone -o property=value volume' can successfully" \
+          "create a ZFS clone volume with multiple correct properties set."
+
+typeset -i i=0
+typeset opts=""
+
+log_must $ZFS snapshot $SNAPFS1
+
+while (( $i < ${#RW_VOL_CLONE_PROP[*]} )); do
+       if [[ ${RW_VOL_CLONE_PROP[$i]} != *"checksum"* ]]; then
+               opts="$opts -o ${RW_VOL_CLONE_PROP[$i]}"
+       fi
+       (( i = i + 1 ))
+done
+
+log_must $ZFS clone $opts $SNAPFS1 $TESTPOOL/$TESTCLONE
+
+i=0
+while (( $i < ${#RW_VOL_CLONE_PROP[*]} )); do
+       if [[ ${RW_VOL_CLONE_PROP[$i]} != *"checksum"* ]]; then
+               propertycheck $TESTPOOL/$TESTCLONE ${RW_VOL_CLONE_PROP[i]} || \
+                       log_fail "${RW_VOL_CLONE_PROP[i]} is failed to set."
+       fi
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs clone -o property=value volume' can successfully" \
+       "create a ZFS clone volume with multiple correct properties set."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_007_pos.ksh
new file mode 100755 (executable)
index 0000000..370a98f
--- /dev/null
@@ -0,0 +1,85 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# 'zfs clone -o version=' could upgrade version, but downgrade is denied.
+#
+# STRATEGY:
+# 1. Create clone with "-o version=" specified
+# 2. Verify it succeed while upgrade, but fails while the version downgraded.
+#
+
+ZFS_VERSION=$($ZFS upgrade | $HEAD -1 | $AWK '{print $NF}' \
+       | $SED -e 's/\.//g')
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists $SNAPFS ; then
+                       log_must $ZFS destroy -Rf $SNAPFS
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "'zfs clone -o version=' could upgrade version," \
+       "but downgrade is denied."
+
+log_must $ZFS snapshot $SNAPFS
+
+typeset -i ver
+
+if (( ZFS_TEST_VERSION == 0 )) ; then
+       (( ZFS_TEST_VERSION = ZFS_VERSION ))
+fi
+
+(( ver = ZFS_TEST_VERSION ))
+while (( ver <= ZFS_VERSION )); do
+       log_must $ZFS clone -o version=$ver $SNAPFS $TESTPOOL/$TESTCLONE
+       cleanup
+       (( ver = ver + 1 ))
+done
+
+(( ver = 0 ))
+while (( ver < ZFS_TEST_VERSION  )); do
+       log_mustnot $ZFS clone -o version=$ver \
+               $SNAPFS $TESTPOOL/$TESTCLONE
+       log_mustnot datasetexists $TESTPOOL/$TESTCLONE
+       cleanup
+       (( ver = ver + 1 ))
+done
+
+log_pass "'zfs clone -o version=' could upgrade version," \
+       "but downgrade is denied."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_008_neg.ksh
new file mode 100755 (executable)
index 0000000..d54c87d
--- /dev/null
@@ -0,0 +1,80 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs clone -o <filesystem>' fails with bad <filesystem> arguments, including:
+#      *Same property set multiple times via '-o property=value'
+#      *Volume's property set on filesystem
+#
+# STRATEGY:
+# 1. Create an array of <filesystem> arguments
+# 2. Execute 'zfs clone -o <filesystem>' with each argument
+# 3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists $SNAPFS ; then
+               log_must $ZFS destroy -Rf $SNAPFS
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "Verify 'zfs clone -o <filesystem>' fails with bad <filesystem> argument."
+
+log_must $ZFS snapshot $SNAPFS
+
+typeset -i i=0
+while (( $i < ${#RW_FS_PROP[*]} )); do
+       log_mustnot $ZFS clone -o ${RW_FS_PROP[i]} -o ${RW_FS_PROP[i]} \
+               $SNAPFS $TESTPOOL/$TESTCLONE
+       log_mustnot $ZFS clone -p -o ${RW_FS_PROP[i]} -o ${RW_FS_PROP[i]} \
+               $SNAPFS $TESTPOOL/$TESTCLONE
+       ((i = i + 1))
+done
+
+i=0
+while (( $i < ${#VOL_ONLY_PROP[*]} )); do
+       log_mustnot $ZFS clone -o ${VOL_ONLY_PROP[i]} \
+               $SNAPFS $TESTPOOL/$TESTCLONE
+       log_mustnot $ZFS clone -p -o ${VOL_ONLY_PROP[i]} \
+               $SNAPFS $TESTPOOL/$TESTCLONE
+       ((i = i + 1))
+done
+
+log_pass "'zfs clone -o <filesystem>' fails with bad <filesystem> argument."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_009_neg.ksh
new file mode 100755 (executable)
index 0000000..286cbf8
--- /dev/null
@@ -0,0 +1,80 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs clone -o <volume>' fails with badly formed arguments,including:
+#       *Same property set multiple times via '-o property=value'
+#       *Filesystems's property set on volume
+#
+# STRATEGY:
+# 1. Create an array of badly formed arguments
+# 2. For each argument, execute 'zfs clone -o <volume>'
+# 3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if snapexists $SNAPFS1 ; then
+               log_must $ZFS destroy -Rf $SNAPFS1
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "Verify 'zfs clone -o <volume>' fails with bad <volume> argument."
+
+log_must $ZFS snapshot $SNAPFS1
+
+typeset -i i=0
+while (( $i < ${#RW_VOL_PROP[*]} )); do
+       log_mustnot $ZFS clone -o ${RW_VOL_PROP[i]} -o ${RW_VOL_PROP[i]} \
+               $SNAPFS1 $TESTPOOL/$TESTCLONE
+       log_mustnot $ZFS clone -p -o ${RW_VOL_PROP[i]} -o ${RW_VOL_PROP[i]} \
+               $SNAPFS1 $TESTPOOL/$TESTCLONE
+       ((i = i + 1))
+done
+
+i=0
+while (( $i < ${#FS_ONLY_PROP[*]} )); do
+       log_mustnot $ZFS clone  -o ${FS_ONLY_PROP[i]} \
+               $SNAPFS1 $TESTPOOL/$TESTCLONE
+       log_mustnot $ZFS clone -p -o ${FS_ONLY_PROP[i]} \
+               $SNAPFS1 $TESTPOOL/$TESTCLONE
+       ((i = i + 1))
+done
+
+log_pass "Verify 'zfs clone -o <volume>' fails with bad <volume> argument."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_010_pos.ksh
new file mode 100755 (executable)
index 0000000..f22e3a1
--- /dev/null
@@ -0,0 +1,238 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify 'zfs list -t all -o name,origin,clones' prints the correct
+#      clone information
+#
+# STRATEGY:
+#      1. Create datasets
+#      2. Create recursive snapshots and their clones
+#      3. Verify zfs clones property displays right information for different
+#         cases
+#
+
+verify_runnable "both"
+
+function local_cleanup
+{
+       typeset -i i=1
+       for ds in $datasets; do
+                datasetexists $ds/$TESTCLONE.$i && \
+                   log_must $ZFS destroy -rf $ds/$TESTCLONE.$i
+                datasetexists $ds && log_must $ZFS destroy -Rf $ds
+               ((i=i+1))
+       done
+}
+
+# Set up filesystem with clones
+function setup_ds
+{
+       typeset -i i=1
+       # create nested datasets
+       log_must $ZFS create -p $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3
+
+       # verify dataset creation
+       for ds in $datasets; do
+               datasetexists $ds || log_fail "Create $ds dataset fail."
+       done
+
+       # create recursive nested snapshot
+       log_must $ZFS snapshot -r $TESTPOOL/$TESTFS1@snap
+       for ds in $datasets; do
+               datasetexists $ds@snap || \
+                   log_fail "Create $ds@snap snapshot fail."
+       done
+       for ds in $datasets; do
+               for fs in $datasets; do
+                       log_must $ZFS clone $ds@snap $fs/$TESTCLONE.$i
+               done
+               ((i=i+1))
+       done
+}
+
+# Verify clone list
+function verify_clones
+{
+       typeset -i no_clones=$1
+       typeset unexpected=$2
+       typeset clone_snap=$3
+       typeset -i i=1
+       for ds in $datasets; do
+               if [[ -n $clone_snap ]]; then
+                       clone_snap=/$TESTCLONE.$i
+               fi
+               snapshot=$($ECHO "$names" | $GREP $ds$clone_snap@snap)
+               actual_clone=$($ZFS list -t all -o clones $snapshot | $TAIL -1)
+               save=$IFS
+               IFS=','
+               typeset -a clones=()
+               for token in $actual_clone; do
+                       clones=( "${clones[@]}" "$token" )
+               done
+               IFS=$save
+               [[ ${#clones[*]} -ne $no_clones ]] && \
+                   log_fail "$snapshot has unexpected number of clones" \
+                       " ${#clones[*]}"
+               expected_clone=""
+               unexpected_clone=""
+               if [[ $unexpected -eq 1 ]]; then
+                       for fs in $datasets; do
+                               if [[ $fs == $ds ]]; then
+                                       if [[ -z $clone_snap ]]; then
+                                               unexpected_clone=$fs/$TESTCLONE.$i
+                                               (for match in ${clones[@]};do
+                                               [[ $match != $unexpected_clone ]] && \
+                                                   exit 0; done) || log_fail \
+                                                   "Unexpected clones of the snapshot"
+                                       else
+                                               expected_clone=$fs
+                                               unexpected_clone=$fs/$TESTCLONE.$i
+                                               (for match in ${clones[@]};do
+                                               [[ $match == $expected_clone ]] && \
+                                                   [[ $match != $unexpected_clone ]] \
+                                                   && exit 0; done) || log_fail \
+                                                   "Unexpected clones of the snapshot"
+                                       fi
+                               else
+                                       expected_clone=$fs/$TESTCLONE.$i
+                                       (for match in ${clones[@]};do
+                                       [[ $match == $expected_clone ]] && \
+                                           exit 0; done) || log_fail \
+                                           "Unexpected clones of the snapshot"
+                               fi
+                       done
+               else
+                       for fs in $datasets; do
+                               expected_clone=$fs/$TESTCLONE.$i
+                               (for match in ${clones[@]};do
+                               [[ $match == $expected_clone ]] && exit 0; \
+                                   done) || log_fail "Unexpected clones" \
+                                   " of the snapshot"
+                       done
+               fi
+               ((i=i+1))
+       done
+}
+
+
+log_onexit local_cleanup
+datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS2
+    $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3"
+
+typeset -a d_clones
+typeset -a deferred_snaps
+typeset -i i
+i=1
+log_must setup_ds
+
+log_note "Verify zfs clone propery for multiple clones"
+names=$($ZFS list -rt all -o name $TESTPOOL)
+log_must verify_clones 3 0
+
+log_note "verfify clone property for clone deletion"
+i=1
+for ds in $datasets; do
+       log_must $ZFS destroy $ds/$TESTCLONE.$i
+       ((i=i+1))
+done
+names=$($ZFS list -rt all -o name $TESTPOOL)
+i=1
+log_must verify_clones 2 1
+
+log_must local_cleanup
+log_must setup_ds
+
+log_note "verify zfs deferred destroy on clones property"
+i=1
+names=$($ZFS list -rt all -o name $TESTPOOL)
+for ds in $datasets; do
+       log_must $ZFS destroy -d $ds@snap
+       deferred_snaps=( "${deferred_snaps[@]}" "$ds@snap" )
+       ((i=i+1))
+done
+log_must verify_clones 3 0
+
+log_note "verify zfs deferred destroy by destroying clones on clones property"
+d_clones=()
+i=1
+for ds in $datasets; do
+       for fs in $datasets; do
+               log_must $ZFS destroy $fs/$TESTCLONE.$i
+               d_clones=( "${d_clones[@]}" "$fs/$TESTCLONE.$i" )
+       done
+       ((i=i+1))
+done
+names=$($ZFS list -rtall -o name $TESTPOOL)
+for snap in ${deferred_snaps[@]}; do
+       status=$($ECHO "$names" | $GREP $snap)
+       [[ -z $status ]] || \
+           log_fail "$snap exist after deferred destroy"
+done
+for dclone in ${d_clones[@]}; do
+       log_note "D CLONE = $dclone"
+       status=$($ECHO "$names" | $GREP $dclone)
+       [[ -z $status ]] || \
+           log_fail "$dclone exist after deferred destroy"
+done
+
+log_must local_cleanup
+log_must setup_ds
+log_note "verify clone property for zfs promote"
+i=1
+for ds in $datasets; do
+       log_must $ZFS promote $ds/$TESTCLONE.$i
+       ((i=i+1))
+done
+names=$($ZFS list -rt all -o name,clones $TESTPOOL)
+log_must verify_clones 3 1 $TESTCLONE
+i=1
+for ds in $datasets; do
+       log_must $ZFS promote $ds
+       ((i=i+1))
+done
+log_must local_cleanup
+
+log_note "verify clone list truncated correctly"
+typeset -i j=200
+i=1
+fs=$TESTPOOL/$TESTFS1
+if is_linux; then
+       ZFS_MAXPROPLEN=4096
+else
+       ZFS_MAXPROPLEN=1024
+fi
+log_must $ZFS create $fs
+log_must $ZFS snapshot $fs@snap
+while((i <= $(( $ZFS_MAXPROPLEN/200+1 )))); do
+       log_must $ZFS clone $fs@snap $fs/$TESTCLONE$(python -c 'print "x" * 200').$i
+       ((i=i+1))
+       ((j=j+200))
+done
+clone_list=$($ZFS list -o clones $fs@snap)
+char_count=$($ECHO "$clone_list" | $TAIL -1 | wc | $AWK '{print $3}')
+[[ $char_count -eq $ZFS_MAXPROPLEN ]] || \
+    log_fail "Clone list not truncated correctly. Unexpected character count" \
+        "$char_count"
+
+log_pass "'zfs list -o name,origin,clones prints the correct clone information."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/Makefile.am
new file mode 100644 (file)
index 0000000..732126d
--- /dev/null
@@ -0,0 +1,12 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_copies
+dist_pkgdata_SCRIPTS = \
+       zfs_copies.cfg \
+       zfs_copies.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_copies_001_pos.ksh \
+       zfs_copies_002_pos.ksh \
+       zfs_copies_003_pos.ksh \
+       zfs_copies_004_neg.ksh \
+       zfs_copies_005_neg.ksh \
+       zfs_copies_006_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/cleanup.ksh
new file mode 100755 (executable)
index 0000000..39b52a8
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_copies/zfs_copies.cfg
+
+#
+# umount the ufs|ext2 fs if there is timedout in the ufs|ext2 test
+#
+
+if ismounted $FS_MNTPOINT $NEWFS_DEFAULT_FS ; then
+       log_must $UMOUNT -f $FS_MNTPOINT
+       $RM -fr $FS_MNTPOINT
+fi
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/setup.ksh
new file mode 100755 (executable)
index 0000000..d4cf209
--- /dev/null
@@ -0,0 +1,31 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_volume_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies.cfg
new file mode 100644 (file)
index 0000000..eb85e65
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+export ZPOOL_VERSION_1_FILES="zfs-pool-v1.dat.bz2"
+export ZPOOL_VERSION_1_NAME="v1-pool"
+
+export FILESIZE=10m
+export FILE=file.copies
+export SLEEPTIME=30
+export FS_MNTPOINT=/testdir_nfs_mntpoint
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib
new file mode 100644 (file)
index 0000000..4957c0f
--- /dev/null
@@ -0,0 +1,153 @@
+#
+# 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) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_copies/zfs_copies.cfg
+
+#
+# Compare the value of copies property with specified value
+# $1, the dataset name
+# $2, the expected copies value
+#
+function cmp_prop
+{
+       typeset ds=$1
+       typeset val_expect=$2
+       typeset val_actual
+
+       val_actual=$(get_prop copies $ds)
+       if [[ $val_actual != $val_expect ]]; then
+               log_fail "Expected value ($val_expect) != actual value " \
+                   "($val_actual)"
+       fi
+}
+
+#
+# Get the value of property used via zfs list
+# $1, the dataset name
+#
+function get_used_prop
+{
+       typeset ds=$1
+       typeset used
+
+       used=`$ZFS list -H -o used $ds`
+       used=${used%[m|M]}
+       if [[ $used == *K ]]; then
+               used=0
+       fi
+       $ECHO $used
+}
+
+#
+# Check the used space is charged correctly
+# $1, the number of used space
+# $2, the expected common factor between the used space and the file space
+#
+function check_used
+{
+       typeset charged_spc=$1
+       typeset -i used
+       typeset -i expected_cfactor=$2
+       typeset -i cfactor
+       typeset -i fsize=${FILESIZE%[m|M]}
+
+       ((used = ${charged_spc%[m|M]}))
+       ((cfactor = used / fsize))
+       if ((cfactor != expected_cfactor)); then
+               log_fail "The space is not charged correctly while setting" \
+                   "copies as $expected_cfactor."
+       fi
+}
+
+#
+# test ncopies on volume
+# $1  test type zfs|ufs, default zfs
+# $2  copies
+# $3  mntp for ufs test
+function do_vol_test
+{
+       typeset type=$1
+       typeset copy=$2
+       typeset mntp=$3
+
+       vol=$TESTPOOL/$TESTVOL1
+       vol_b_path=$ZVOL_DEVDIR/$TESTPOOL/$TESTVOL1
+       vol_r_path=$ZVOL_RDEVDIR/$TESTPOOL/$TESTVOL1
+
+       log_must $ZFS create -V $VOLSIZE -o copies=$copy $vol
+       log_must $ZFS set refreservation=none $vol
+       block_device_wait
+
+       if [[ $type == "ufs" ]]; then
+               log_must $ECHO y | $NEWFS $vol_r_path >/dev/null 2>&1
+               log_must $MOUNT -F ufs -o rw $vol_b_path $mntp
+       elif [[ $type == "ext2" ]]; then
+               log_must $ECHO y | $NEWFS $vol_r_path >/dev/null 2>&1
+               log_must $MOUNT -o rw $vol_b_path $mntp
+       else
+               log_must $ZPOOL create $TESTPOOL1 $vol_b_path
+               log_must $ZFS create $TESTPOOL1/$TESTFS1
+       fi
+
+       ((nfilesize = copy * ${FILESIZE%m}))
+       pre_used=$(get_used_prop $vol)
+       ((target_size = pre_used + nfilesize))
+
+       if [[ $type == "ufs" ]]; then
+               log_must $MKFILE $FILESIZE $mntp/$FILE
+       elif [[ $type == "ext2" ]]; then
+               log_must $MKFILE $FILESIZE $mntp/$FILE
+       else
+               log_must $MKFILE $FILESIZE /$TESTPOOL1/$TESTFS1/$FILE
+       fi
+
+       post_used=$(get_used_prop $vol)
+       while ((post_used < target_size)) ; do
+               sleep 1
+               post_used=$(get_used_prop $vol)
+       done
+
+       ((used = post_used - pre_used))
+       if ((used < nfilesize)); then
+               log_fail "The space is not charged correctly while setting" \
+                   "copies as $copy"
+       fi
+
+       if [[ $type == "ufs" ]]; then
+               $UMOUNT $mntp
+       elif [[ $type == "ext2" ]]; then
+               $UMOUNT $mntp
+       else
+               log_must $ZPOOL destroy $TESTPOOL1
+       fi
+
+       log_must $ZFS destroy $vol
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_001_pos.ksh
new file mode 100755 (executable)
index 0000000..79ec39c
--- /dev/null
@@ -0,0 +1,112 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib
+
+#
+# DESCRIPTION:
+#      Verify "copies" property can be correctly set as 1,2 and 3 and different
+#      filesystem can have different value of "copies" property within the same pool.
+#
+# STRATEGY:
+#      1. Create different filesystems with copies set as 1,2,3;
+#      2. Verify that the "copies" property has been set correctly
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset ds
+
+       for ds in $fs1 $fs2 $vol1 $vol2; do
+               if datasetexists $ds; then
+                       log_must $ZFS destroy $ds
+               fi
+       done
+}
+
+log_assert "Verify 'copies' property with correct arguments works or not."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+fs1=$TESTPOOL/$TESTFS1
+fs2=$TESTPOOL/$TESTFS2
+vol=$TESTPOOL/$TESTVOL
+vol1=$TESTPOOL/$TESTVOL1
+vol2=$TESTPOOL/$TESTVOL2
+
+#
+# Check the default value for copies property
+#
+for ds in $fs $vol; do
+       cmp_prop $ds 1
+done
+
+for val in 1 2 3; do
+       log_must $ZFS create -o copies=$val $fs1
+       if is_global_zone; then
+               log_must $ZFS create -V $VOLSIZE -o copies=$val $vol1
+               block_device_wait
+       else
+               log_must $ZFS create -o copies=$val $vol1
+       fi
+       for ds in $fs1 $vol1; do
+               cmp_prop $ds $val
+       done
+
+       for val2 in 3 2 1; do
+               log_must $ZFS create -o copies=$val2 $fs2
+               if is_global_zone; then
+                       log_must $ZFS create -V $VOLSIZE -o copies=$val2 $vol2
+                       block_device_wait
+               else
+                       log_must $ZFS create -o copies=$val2 $vol2
+               fi
+               for ds in $fs2 $vol2; do
+                       cmp_prop $ds $val2
+                       log_must $ZFS destroy $ds
+                       block_device_wait
+               done
+       done
+
+       for ds in $fs1 $vol1; do
+               log_must $ZFS destroy $ds
+               block_device_wait
+       done
+
+done
+
+for val in 3 2 1; do
+       for ds in $fs $vol; do
+               log_must $ZFS set copies=$val $ds
+               cmp_prop $ds $val
+       done
+done
+
+log_pass "'copies' property with correct arguments works as expected. "
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_002_pos.ksh
new file mode 100755 (executable)
index 0000000..45ebd2b
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/ksh
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib
+
+#
+# DESCRIPTION:
+#      Verify that the space used by multiple copies is charged correctly
+#
+# STRATEGY:
+#      1. Create filesystems with copies set as 2,3 respectively;
+#      2. Copy specified size data into each filesystem;
+#      3. Verify that the space is charged as expected with zfs list, ls -s, df(1m),
+#         du(1) commands;
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset val
+
+       for val in 1 2 3; do
+               if datasetexists $TESTPOOL/fs_$val; then
+                       log_must $ZFS destroy $TESTPOOL/fs_$val
+               fi
+       done
+}
+
+log_assert "Verify that the space used by multiple copies is charged correctly."
+log_onexit cleanup
+
+for val in 1 2 3; do
+       log_must $ZFS create -o copies=$val $TESTPOOL/fs_$val
+
+       log_must $MKFILE $FILESIZE /$TESTPOOL/fs_$val/$FILE
+done
+
+#
+# Sync up the filesystem
+#
+$SYNC
+
+#
+# Verify 'zfs list' can correctly list the space charged
+#
+log_note "Verify 'zfs list' can correctly list the space charged."
+fsize=${FILESIZE%[m|M]}
+for val in 1 2 3; do
+       used=$(get_used_prop $TESTPOOL/fs_$val)
+       check_used $used $val
+done
+
+log_note "Verify 'ls -s' can correctly list the space charged."
+if is_linux; then
+       blksize=1024
+else
+       blksize=512
+fi
+for val in 1 2 3; do
+       blks=`$LS -ls /$TESTPOOL/fs_$val/$FILE | $AWK '{print $1}'`
+       (( used = blks * $blksize / (1024 * 1024) ))
+       check_used $used $val
+done
+
+log_note "Verify df(1M) can corectly display the space charged."
+for val in 1 2 3; do
+       used=`$DF -F zfs -h /$TESTPOOL/fs_$val/$FILE | $GREP $TESTPOOL/fs_$val \
+               | $AWK '{print $3}'`
+       check_used $used $val
+done
+
+log_note "Verify du(1) can correctly display the space charged."
+for val in 1 2 3; do
+       used=`$DU -h /$TESTPOOL/fs_$val/$FILE | $AWK '{print $1}'`
+       check_used $used $val
+done
+
+log_pass "The space used by multiple copies is charged correctly as expected. "
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_003_pos.ksh
new file mode 100755 (executable)
index 0000000..4b67e69
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/ksh
+#
+# 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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib
+
+#
+# DESCRIPTION:
+#      Verify that the volume space used by multiple copies is charged correctly
+#
+# STRATEGY:
+#      1. Create volume;
+#      2. Create ZFS filesystem based on the volume;
+#      3. Set the copies property of volume to 1,2 or 3;
+#      4. Copy specified size data into each filesystem;
+#      5. Verify that the volume space is charged as expected.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if poolexists $TESTPOOL1; then
+               destroy_pool $TESTPOOL1
+       fi
+
+       if datasetexists $vol; then
+               log_must $ZFS destroy $vol
+       fi
+}
+
+log_assert "Verify that ZFS volume space used by multiple copies is charged correctly."
+log_onexit cleanup
+vol=$TESTPOOL/$TESTVOL1
+
+
+for val in 1 2 3; do
+       do_vol_test zfs $val
+done
+
+log_pass "The volume space used by multiple copies is charged correctly as expected. "
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_004_neg.ksh
new file mode 100755 (executable)
index 0000000..f98b9d5
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/ksh
+#
+# 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
+. $STF_SUITE/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib
+
+#
+# DESCRIPTION:
+#      Verify that copies cannot be set to other value except for 1, 2 or 3
+#
+# STRATEGY:
+#      1. Create filesystems with copies set as any value other than 1, 2 or 3
+#      2. Verify that the create operations fail
+#
+
+verify_runnable "both"
+
+log_assert "Verify that copies property cannot be set to any value other than 1,2 or 3"
+
+set -A badval 0 01 02 03 0 -1 -2 -3 10 20 30 4 5 6 blah
+
+for val in ${badval[@]}; do
+       log_mustnot $ZFS create -o copies=$val $TESTPOOL/$TESTFS1
+       log_mustnot $ZFS create -V $VOLSIZE -o copies=$val $TESTPOOL/$TESTVOL1
+       log_mustnot $ZFS set copies=$val $TESTPOOL/$TESTFS
+       log_mustnot $ZFS set copies=$val $TESTPOOL/$TESTVOL
+       block_device_wait
+done
+
+log_pass "The copies property cannot be set to any value other than 1,2 or 3 as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_005_neg.ksh
new file mode 100755 (executable)
index 0000000..a10ca59
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/ksh
+#
+# 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
+. $STF_SUITE/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib
+
+#
+# DESCRIPTION:
+#      Verify that copies cannot be set with pool version 1
+#
+# STRATEGY:
+#      1. Create filesystems with copies set in a pool with version 1
+#      2. Verify that the create operations fail
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if poolexists $ZPOOL_VERSION_1_NAME; then
+               destroy_pool $ZPOOL_VERSION_1_NAME
+       fi
+
+       if [[ -f $TESTDIR/$ZPOOL_VERSION_1_FILES ]]; then
+               rm -f $TESTDIR/$ZPOOL_VERSION_1_FILES
+       fi
+}
+
+log_assert "Verify that copies cannot be set with pool version 1"
+log_onexit cleanup
+
+$CP $STF_SUITE/tests/functional/cli_root/zpool_upgrade/blockfiles/$ZPOOL_VERSION_1_FILES $TESTDIR
+$BUNZIP2 $TESTDIR/$ZPOOL_VERSION_1_FILES
+log_must $ZPOOL import -d $TESTDIR $ZPOOL_VERSION_1_NAME
+log_must $ZFS create $ZPOOL_VERSION_1_NAME/$TESTFS
+log_must $ZFS create -V 1m $ZPOOL_VERSION_1_NAME/$TESTVOL
+
+for val in 3 2 1; do
+       for ds in $ZPOOL_VERSION_1_NAME/$TESTFS $ZPOOL_VERSION_1_NAME/$TESTVOL; do
+               log_mustnot $ZFS set copies=$val $ds
+       done
+       for ds in $ZPOOL_VERSION_1_NAME/$TESTFS1 $ZPOOL_VERSION_1_NAME/$TESTVOL1; do
+               log_mustnot $ZFS create -o copies=$val $ds
+       done
+done
+
+log_pass "Verification pass: copies cannot be set with pool version 1. "
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_copies/zfs_copies_006_pos.ksh
new file mode 100755 (executable)
index 0000000..40a8328
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/ksh
+#
+# 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/tests/functional/cli_root/zfs_copies/zfs_copies.kshlib
+
+#
+# DESCRIPTION:
+#      Verify that the volume space used by multiple copies is charged correctly
+#
+# STRATEGY:
+#      1. Create volume
+#      2. Create UFS filesystem based on the volume
+#      3. Set the copies property of volume to 1,2 or 3
+#      4. Copy specified size data into each filesystem
+#      5. Verify that the volume space is charged as expected
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if ismounted $mntp $NEWFS_DEFAULT_FS ; then
+               log_must $UMOUNT $mntp
+       fi
+
+       if datasetexists $vol; then
+               log_must $ZFS destroy $vol
+       fi
+
+       if [[ -d $mntp ]]; then
+                $RM -rf $mntp
+        fi
+}
+
+
+log_assert "Verify that ZFS volume space used by multiple copies is charged correctly."
+log_onexit cleanup
+mntp=$FS_MNTPOINT
+vol=$TESTPOOL/$TESTVOL1
+
+if [[ ! -d $mntp ]]; then
+       $MKDIR -p $mntp
+fi
+
+for val in 1 2 3; do
+       do_vol_test $NEWFS_DEFAULT_FS $val $mntp
+done
+
+log_pass "The volume space used by multiple copies is charged correctly as expected. "
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/Makefile.am
new file mode 100644 (file)
index 0000000..10d6b66
--- /dev/null
@@ -0,0 +1,20 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_create
+dist_pkgdata_SCRIPTS = \
+       properties.kshlib \
+       zfs_create_common.kshlib \
+       zfs_create.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_create_001_pos.ksh \
+       zfs_create_002_pos.ksh \
+       zfs_create_003_pos.ksh \
+       zfs_create_004_pos.ksh \
+       zfs_create_005_pos.ksh \
+       zfs_create_006_pos.ksh \
+       zfs_create_007_pos.ksh \
+       zfs_create_008_neg.ksh \
+       zfs_create_009_neg.ksh \
+       zfs_create_010_neg.ksh \
+       zfs_create_011_pos.ksh \
+       zfs_create_012_pos.ksh \
+       zfs_create_013_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/properties.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/properties.kshlib
new file mode 100644 (file)
index 0000000..cf35686
--- /dev/null
@@ -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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+#
+
+set -A RW_FS_PROP "quota=512M" \
+                 "reservation=512M" \
+                 "recordsize=256K" \
+                 "mountpoint=/tmp/mnt$$" \
+                 "checksum=fletcher2" \
+                 "compression=lzjb" \
+                 "atime=off" \
+                 "devices=off" \
+                 "exec=off" \
+                 "setuid=off" \
+                 "readonly=on" \
+                 "snapdir=visible" \
+                 "canmount=off" \
+                 "local:department=123"
+
+set -A RW_VOL_PROP "volblocksize=16K" \
+                  "checksum=fletcher2" \
+                  "compression=lzjb" \
+                  "readonly=on" \
+                  "local:department=123"
+
+set -A RW_VOL_CLONE_PROP "checksum=fletcher2" \
+                  "compression=lzjb" \
+                  "readonly=on" \
+                  "local:department=123"
+
+set -A FS_ONLY_PROP "quota=512M" \
+                    "recordsize=64K" \
+                    "mountpoint=/tmp/mnt$$" \
+                    "atime=off" \
+                    "devices=off" \
+                    "exec=off" \
+                    "setuid=off" \
+                    "zoned=on" \
+                    "snapdir=visible" \
+                   "canmount=off" \
+                   "version=1"
+
+set -A VOL_ONLY_PROP "volblocksize=16K" "volsize=512M"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create.cfg
new file mode 100644 (file)
index 0000000..c97e44d
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# 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.
+#
+
+export BYND_MAX_NAME="byondmaxnamelength\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789"
+
+# There're 3 different prompt messages while create
+# a volume that great than 1TB on 32-bit
+#       - volume size exceeds limit for this system. (happy gate)
+#       - max volume size is 1TB on 32-bit systems (s10u2)
+#       - value is too large (old)
+
+export VOL_LIMIT_KEYWORD1="1TB on 32-bit"
+export VOL_LIMIT_KEYWORD2="value is too large"
+export VOL_LIMIT_KEYWORD3="volume size exceeds limit"
+
+set -A size "8k" "8K" "1m" "1M" "1mb" "1mB" "1Mb" "1MB" "1g" "1G" \
+       "1p" "1P" "1z" "1Z" "1gb" "1gB" "1Gb" "1GB" "1pb" "1pB" "1Pb" \
+       "1PB" "1zb" "1zB" "1Zb" "1ZB"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_001_pos.ksh
new file mode 100755 (executable)
index 0000000..63cf619
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# 'zfs create <filesystem>' can create a ZFS filesystem in the namespace.
+#
+# STRATEGY:
+# 1. Create a ZFS filesystem in the storage pool
+# 2. Verify the filesystem created successfully
+#
+
+verify_runnable "both"
+
+
+function cleanup
+{
+       typeset -i i=0
+       while (( $i < ${#datasets[*]} )); do
+               datasetexists ${datasets[$i]} && \
+                       log_must $ZFS destroy -f ${datasets[$i]}
+               ((i = i + 1))
+       done
+}
+
+log_onexit cleanup
+
+set -A datasets "$TESTPOOL/$TESTFS1" "$TESTPOOL/$LONGFSNAME" "$TESTPOOL/..." \
+               "$TESTPOOL/_1234_"
+
+log_assert "'zfs create <filesystem>' can create a ZFS filesystem in the namespace."
+
+typeset -i i=0
+while (( $i < ${#datasets[*]} )); do
+       log_must $ZFS create ${datasets[$i]}
+       datasetexists ${datasets[$i]} || \
+               log_fail "zfs create ${datasets[$i]} fail."
+       ((i = i + 1))
+done
+
+log_pass "'zfs create <filesystem>' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_002_pos.ksh
new file mode 100755 (executable)
index 0000000..bb06646
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create.cfg
+
+#
+# DESCRIPTION:
+# 'zfs create -s -V <size> <volume>' can create various-size sparse volume.
+#
+# STRATEGY:
+# 1. Create a volume in the storage pool.
+# 2. Verify the volume is created correctly.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset -i j=0
+       while [[ $j -lt ${#size[*]} ]]; do
+               if datasetexists $TESTPOOL/${TESTVOL}${size[j]}; then
+                       log_must $ZFS destroy $TESTPOOL/${TESTVOL}${size[j]}
+               fi
+               ((j = j + 1))
+       done
+}
+
+log_onexit cleanup
+
+
+log_assert "'zfs create -s -V <size> <volume>' succeeds"
+
+typeset -i j=0
+while (( $j < ${#size[*]} )); do
+       typeset cmdline="$ZFS create -s -V ${size[j]}  \
+                        $TESTPOOL/${TESTVOL}${size[j]}"
+
+       str=$(eval $cmdline 2>&1)
+       if (( $? == 0 )); then
+               log_note "SUCCESS: $cmdline"
+               log_must datasetexists $TESTPOOL/${TESTVOL}${size[j]}
+       elif [[ $str == *${VOL_LIMIT_KEYWORD1}* || \
+               $str == *${VOL_LIMIT_KEYWORD2}* || \
+               $str == *${VOL_LIMIT_KEYWORD3}* ]]
+       then
+               log_note "UNSUPPORTED: $cmdline"
+       else
+               log_fail "$cmdline"
+       fi
+
+       ((j = j + 1))
+
+done
+log_pass "'zfs create -s -V <size> <volume>' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_003_pos.ksh
new file mode 100755 (executable)
index 0000000..dbb380e
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create.cfg
+
+#
+# DESCRIPTION:
+# 'zfs create [-b <blocksize>] -V <size> <volume>' can create a volume
+# with specified blocksize, which is power of 2 between 512 - 128k.
+#
+# STRATEGY:
+# 1. Create a volume with blocksize in the storage pool
+# 2. Verify the volume created successfully
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $vol && \
+               log_must $ZFS destroy -f $vol
+}
+
+log_assert "Verify creating volume with specified blocksize works."
+log_onexit cleanup
+
+set -A options "" "-b 1k" "-b 1K" "-b 1024" "-b 1024b"
+vol=$TESTPOOL/$TESTVOL
+
+typeset -i i=0
+while (( i < ${#options[*]} )); do
+       log_must $ZFS create ${options[i]} -V $VOLSIZE $vol
+       datasetexists $vol || \
+               log_fail "zfs create ${options[i]} -V $VOLSIZE $vol fail."
+
+       log_must_busy $ZFS destroy -f $vol
+       ((i = i + 1))
+done
+
+log_pass "'zfs create [-b <blocksize>] -V <size> <volume>' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_004_pos.ksh
new file mode 100755 (executable)
index 0000000..5d2a21a
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs create -o property=value filesystem' can successfully create a ZFS
+# filesystem with correct property set.
+#
+# STRATEGY:
+# 1. Create a ZFS filesystem in the storage pool with -o option
+# 2. Verify the filesystem created successfully
+# 3. Verify the property is correctly set
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTFS1 && \
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS1
+}
+
+log_onexit cleanup
+
+
+log_assert "'zfs create -o property=value filesystem' can successfully create \
+          a ZFS filesystem with correct property set."
+
+typeset -i i=0
+while (( $i < ${#RW_FS_PROP[*]} )); do
+       log_must $ZFS create -o ${RW_FS_PROP[$i]} $TESTPOOL/$TESTFS1
+       datasetexists $TESTPOOL/$TESTFS1 || \
+               log_fail "zfs create $TESTPOOL/$TESTFS1 fail."
+       propertycheck $TESTPOOL/$TESTFS1 ${RW_FS_PROP[i]} || \
+               log_fail "${RW_FS_PROP[i]} is failed to set."
+       log_must $ZFS destroy -f $TESTPOOL/$TESTFS1
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs create -o property=value filesystem' can successfully create \
+         a ZFS filesystem with correct property set."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_005_pos.ksh
new file mode 100755 (executable)
index 0000000..ce84a5c
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs create -o property=value filesystem' can successfully create a ZFS
+# filesystem with multiple properties set.
+#
+# STRATEGY:
+# 1. Create a ZFS filesystem in the storage pool with multiple -o options
+# 2. Verify the filesystem created successfully
+# 3. Verify the properties are correctly set
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTFS1 && \
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS1
+}
+
+log_onexit cleanup
+
+
+log_assert "'zfs create -o property=value filesystem' can successfully create \
+          a ZFS filesystem with multiple properties set."
+
+typeset -i i=0
+typeset opts=""
+
+while (( $i < ${#RW_FS_PROP[*]} )); do
+        if [[ ${RW_FS_PROP[$i]} != *"checksum"* ]]; then
+               opts="$opts -o ${RW_FS_PROP[$i]}"
+       fi
+       (( i = i + 1 ))
+done
+
+log_must $ZFS create $opts $TESTPOOL/$TESTFS1
+datasetexists $TESTPOOL/$TESTFS1 || \
+       log_fail "zfs create $TESTPOOL/$TESTFS1 fail."
+
+i=0
+while (( $i < ${#RW_FS_PROP[*]} )); do
+        if [[ ${RW_FS_PROP[$i]} != *"checksum"* ]]; then
+               propertycheck $TESTPOOL/$TESTFS1 ${RW_FS_PROP[i]} || \
+                       log_fail "${RW_FS_PROP[i]} is failed to set."
+       fi
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs create -o property=value filesystem' can successfully create \
+         a ZFS filesystem with multiple properties set."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_006_pos.ksh
new file mode 100755 (executable)
index 0000000..20a44ce
--- /dev/null
@@ -0,0 +1,84 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs create -o property=value -V size volume' can successfully create a ZFS
+# volume with correct property set.
+#
+# STRATEGY:
+# 1. Create a ZFS volume in the storage pool with -o option
+# 2. Verify the volume created successfully
+# 3. Verify the property is correctly set
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTVOL1 && \
+               log_must $ZFS destroy -f $TESTPOOL/$TESTVOL1
+}
+
+log_onexit cleanup
+
+
+log_assert "'zfs create -o property=value -V size volume' can successfully \
+          create a ZFS volume with correct property set."
+
+typeset -i i=0
+while (( $i < ${#RW_VOL_PROP[*]} )); do
+       log_must $ZFS create -o ${RW_VOL_PROP[$i]} -V $VOLSIZE \
+               $TESTPOOL/$TESTVOL1
+       datasetexists $TESTPOOL/$TESTVOL1 || \
+               log_fail "zfs create -V size $TESTPOOL/$TESTVOL1 fail."
+       propertycheck $TESTPOOL/$TESTVOL1 ${RW_VOL_PROP[i]} || \
+               log_fail "${RW_VOL_PROP[i]} is failed to set."
+       log_must_busy $ZFS destroy -f $TESTPOOL/$TESTVOL1
+
+       log_must $ZFS create -s -o ${RW_VOL_PROP[$i]} -V $VOLSIZE \
+               $TESTPOOL/$TESTVOL1
+       datasetexists $TESTPOOL/$TESTVOL1 || \
+               log_fail "zfs create -s -V $TESTPOOL/$TESTVOL1 fail."
+       propertycheck $TESTPOOL/$TESTVOL1 ${RW_VOL_PROP[i]} || \
+               log_fail "${RW_VOL_PROP[i]} is failed to set."
+       log_must_busy $ZFS destroy -f $TESTPOOL/$TESTVOL1
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs create -o property=value -V size volume' can successfully \
+          create a ZFS volume with correct property set."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_007_pos.ksh
new file mode 100755 (executable)
index 0000000..a34b46d
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs create -o property=value -V size volume' can successfully create a ZFS
+# volume with multiple properties set.
+#
+# STRATEGY:
+# 1. Create a ZFS volume in the storage pool with -o option
+# 2. Verify the volume created successfully
+# 3. Verify the properties are correctly set
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        datasetexists $TESTPOOL/$TESTVOL && \
+                log_must $ZFS destroy -f $TESTPOOL/$TESTVOL
+       datasetexists $TESTPOOL/$TESTVOL1 && \
+               log_must $ZFS destroy -f $TESTPOOL/$TESTVOL1
+}
+
+log_onexit cleanup
+
+
+log_assert "'zfs create -o property=value -V size volume' can successfully \
+          create a ZFS volume with correct property set."
+
+typeset -i i=0
+typeset opts=""
+
+while (( $i < ${#RW_VOL_PROP[*]} )); do
+       if [[ ${RW_VOL_PROP[$i]} != *"checksum"* ]]; then
+               opts="$opts -o ${RW_VOL_PROP[$i]}"
+       fi
+       (( i = i + 1 ))
+done
+
+log_must $ZFS create $opts -V $VOLSIZE $TESTPOOL/$TESTVOL
+datasetexists $TESTPOOL/$TESTVOL || \
+       log_fail "zfs create $TESTPOOL/$TESTVOL fail."
+log_must $ZFS create -s $opts -V $VOLSIZE $TESTPOOL/$TESTVOL1
+datasetexists $TESTPOOL/$TESTVOL1 || \
+       log_fail "zfs create $TESTPOOL/$TESTVOL1 fail."
+
+i=0
+while (( $i < ${#RW_VOL_PROP[*]} )); do
+       if [[ ${RW_VOL_PROP[$i]} != *"checksum"* ]]; then
+               propertycheck $TESTPOOL/$TESTVOL ${RW_VOL_PROP[i]} || \
+                       log_fail "${RW_VOL_PROP[i]} is failed to set."
+               propertycheck $TESTPOOL/$TESTVOL1 ${RW_VOL_PROP[i]} || \
+                       log_fail "${RW_VOL_PROP[i]} is failed to set."
+       fi
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs create -o property=value -V size volume' can successfully \
+          create a ZFS volume with correct property set."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_008_neg.ksh
new file mode 100755 (executable)
index 0000000..27b5f9c
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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, 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create.cfg
+
+#
+# DESCRIPTION:
+# 'zfs create' should return an error with badly formed parameters.
+#
+# STRATEGY:
+# 1. Create an array of parameters
+# 2. For each parameter in the array, execute 'zfs create'
+# 3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $TESTPOOL/$TESTFS1 ; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS1
+       fi
+}
+
+log_onexit cleanup
+
+set -A args "ab" "-?" "-cV" "-Vc" "-c -V" "c" "V" "--c" "-e" "-s" \
+    "-blah" "-cV 12k" "-s -cV 1P" "-sc" "-Vs 5g" "-o" "--o" "-O" "--O" \
+    "-o QuOta=none" "-o quota=non" "-o quota=abcd" "-o quota=0" "-o quota=" \
+    "-o ResErVaTi0n=none" "-o reserV=none" "-o reservation=abcd" "-o reserv=" \
+    "-o recorDSize=64k" "-o recordsize=2048K" "-o recordsize=2M" \
+    "-o recordsize=256" "-o recsize=" "-o recsize=zero" "-o recordsize=0" \
+    "-o mountPoint=/tmp/tmpfile$$" "-o mountpoint=non0" "-o mountpoint=" \
+    "-o mountpoint=LEGACY" "-o mounpoint=none" \
+    "-o sharenfs=ON" "-o ShareNFS=off" "-o sharenfs=sss" \
+    "-o checkSUM=on" "-o checksum=SHA256" "-o chsum=off" "-o checksum=aaa" \
+    "-o checkSUM=on -V $VOLSIZE" "-o checksum=SHA256 -V $VOLSIZE" \
+    "-o chsum=off -V $VOLSIZE" "-o checksum=aaa -V $VOLSIZE" \
+    "-o compression=of" "-o ComPression=lzjb" "-o compress=ON" "-o compress=a" \
+    "-o compression=of -V $VOLSIZE" "-o ComPression=lzjb -V $VOLSIZE" \
+    "-o compress=ON -V $VOLSIZE" "-o compress=a -V $VOLSIZE" \
+    "-o atime=ON" "-o ATime=off" "-o atime=bbb" \
+    "-o deviCes=on" "-o devices=OFF" "-o devices=aaa" \
+    "-o exec=ON" "-o EXec=off" "-o exec=aaa" \
+    "-o readonly=ON" "-o reADOnly=off" "-o rdonly=OFF" "-o rdonly=aaa" \
+    "-o readonly=ON -V $VOLSIZE" "-o reADOnly=off -V $VOLSIZE" \
+    "-o rdonly=OFF -V $VOLSIZE" "-o rdonly=aaa -V $VOLSIZE" \
+    "-o zoned=ON" "-o ZoNed=off" "-o zoned=aaa" \
+    "-o snapdIR=hidden" "-o snapdir=VISible" "-o snapdir=aaa" \
+    "-o aclmode=DIScard" "-o aclmODE=groupmask" "-o aclmode=aaa" \
+    "-o aclinherit=deny" "-o aclinHerit=secure" "-o aclinherit=aaa" \
+    "-o type=volume" "-o type=snapshot" "-o type=filesystem" \
+    "-o type=volume -V $VOLSIZE" "-o type=snapshot -V $VOLSIZE" \
+    "-o type=filesystem -V $VOLSIZE" \
+    "-o creation=aaa" "-o creation=aaa -V $VOLSIZE" \
+    "-o used=10K" "-o used=10K -V $VOLSIZE" \
+    "-o available=10K" "-o available=10K -V $VOLSIZE" \
+    "-o referenced=10K" "-o referenced=10K -V $VOLSIZE" \
+    "-o compressratio=1.00x" "-o compressratio=1.00x -V $VOLSIZE" \
+    "-o version=0" "-o version=1.234" "-o version=10K" "-o version=-1" \
+    "-o version=aaa" "-o version=999"
+
+log_assert "'zfs create' should return an error with badly-formed parameters."
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZFS create ${args[i]} $TESTPOOL/$TESTFS1
+       log_mustnot $ZFS create -p ${args[i]} $TESTPOOL/$TESTFS1
+       ((i = i + 1))
+done
+
+log_pass "'zfs create' with badly formed parameters failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_009_neg.ksh
new file mode 100755 (executable)
index 0000000..ed8195c
--- /dev/null
@@ -0,0 +1,127 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs create <filesystem>' fails with bad <filesystem> arguments, including:
+#      *Invalid character against the ZFS namespace
+#      *Incomplete component
+#      *Too many arguments
+#      *Filesystem already exists
+#      *Beyond maximal name length.
+#      *Same property set multiple times via '-o property=value'
+#      *Volume's property set on filesystem
+#
+# STRATEGY:
+# 1. Create an array of <filesystem> arguments
+# 2. Execute 'zfs create <filesystem>' with each argument
+# 3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset -i i
+       typeset found
+
+       #
+       # check to see if there is any new fs created during the test
+       # if so destroy it.
+       #
+       for dset in $($ZFS list -H | \
+               $AWK '{print $1}' | $GREP / ); do
+               found=false
+               i=0
+               while (( $i < ${#existed_fs[*]} )); do
+                       if [[ $dset == ${existed_fs[i]} ]]; then
+                               found=true
+                               break
+                       fi
+                       (( i = i  + 1 ))
+               done
+
+               #
+               # new fs created during the test, cleanup it
+               #
+               if [[ $found == "true" ]]; then
+                       log_must $ZFS destroy -f $dset
+               fi
+       done
+}
+
+log_onexit cleanup
+
+set -A args  "$TESTPOOL/" "$TESTPOOL//blah" "$TESTPOOL/@blah" \
+       "$TESTPOOL/blah@blah" "$TESTPOOL/blah^blah" "$TESTPOOL/blah%blah" \
+       "$TESTPOOL/blah*blah" "$TESTPOOL/blah blah" \
+       "-s $TESTPOOL/$TESTFS1" "-b 1092 $TESTPOOL/$TESTFS1" \
+       "-b 64k $TESTPOOL/$TESTFS1" "-s -b 32k $TESTPOOL/$TESTFS1" \
+       "$TESTPOOL/$BYND_MAX_NAME"
+
+log_assert "Verify 'zfs create <filesystem>' fails with bad <filesystem> argument."
+
+datasetexists $TESTPOOL/$TESTFS || \
+       log_must $ZFS create $TESTPOOL/$TESTFS
+
+set -A existed_fs $($ZFS list -H | $AWK '{print $1}' | $GREP / )
+
+log_mustnot $ZFS create $TESTPOOL
+log_mustnot $ZFS create $TESTPOOL/$TESTFS
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZFS create ${args[$i]}
+       log_mustnot $ZFS create -p ${args[$i]}
+       ((i = i + 1))
+done
+
+i=0
+while (( $i < ${#RW_FS_PROP[*]} )); do
+       log_mustnot $ZFS create -o ${RW_FS_PROP[i]} -o ${RW_FS_PROP[i]} \
+               $TESTPOOL/$TESTFS1
+       log_mustnot $ZFS create -p -o ${RW_FS_PROP[i]} -o ${RW_FS_PROP[i]} \
+               $TESTPOOL/$TESTFS1
+       ((i = i + 1))
+done
+
+i=0
+while (( $i < ${#VOL_ONLY_PROP[*]} )); do
+       log_mustnot $ZFS create -o ${VOL_ONLY_PROP[i]} $TESTPOOL/$TESTFS1
+       log_mustnot $ZFS create -p -o ${VOL_ONLY_PROP[i]} $TESTPOOL/$TESTFS1
+       ((i = i + 1))
+done
+
+log_pass "'zfs create <filesystem>' fails as expected with bad <filesystem> argument."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_010_neg.ksh
new file mode 100755 (executable)
index 0000000..b54203d
--- /dev/null
@@ -0,0 +1,149 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_create/properties.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs create [-b <blocksize> ] -V <size> <volume>' fails with badly formed
+# <size> or <volume> arguments,including:
+#      *Invalid volume size and volume name
+#      *Invalid blocksize
+#      *Incomplete component in the dataset tree
+#      *The volume already exists
+#      *The volume name beyond the maximal name length - 256.
+#       *Same property set multiple times via '-o property=value'
+#       *Filesystems's property set on volume
+#
+# STRATEGY:
+# 1. Create an array of badly formed arguments
+# 2. For each argument, execute 'zfs create -V <size> <volume>'
+# 3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset -i i
+       typeset found
+
+       #
+       # check to see if there is any new fs created during the test
+       # if so destroy it.
+       #
+       for dset in $($ZFS list -H | \
+               $AWK '{print $1}' | $GREP / ); do
+               found=false
+               i=0
+               while (( $i < ${#existed_fs[*]} )); do
+                       if [[ $dset == ${existed_fs[i]} ]]; then
+                               found=true
+                               break
+                       fi
+                       (( i = i  + 1 ))
+               done
+
+               #
+               # new fs created during the test, cleanup it
+               #
+               if [[ $found == "true" ]]; then
+                       log_must $ZFS destroy -f $dset
+               fi
+       done
+}
+
+log_onexit cleanup
+
+log_assert "Verify 'zfs create [-s] [-b <blocksize> ] -V <size> <volume>' fails with" \
+    "badly-formed <size> or <volume> arguments."
+
+set -A args "$VOLSIZE" "$TESTVOL1" \
+       "$VOLSIZE $TESTVOL1" "0 $TESTPOOL/$TESTVOL1" \
+       "-1gb $TESTPOOL/$TESTVOL1" "1g? $TESTPOOL/$TESTVOL1" \
+       "1.01BB $TESTPOOL/$TESTVOL1" "1%g $TESTPOOL/$TESTVOL1" \
+       "1g% $TESTPOOL/$TESTVOL1" "1g$ $TESTPOOL/$TESTVOL1" \
+       "$m $TESTPOOL/$TESTVOL1" "1m$ $TESTPOOL/$TESTVOL1" \
+       "1m! $TESTPOOL/$TESTVOL1" \
+       "1gbb $TESTPOOL/blah" "1blah $TESTPOOL/blah" "blah $TESTPOOL/blah" \
+       "$VOLSIZE $TESTPOOL" "$VOLSIZE $TESTPOOL/" "$VOLSIZE $TESTPOOL//blah"\
+       "$VOLSIZE $TESTPOOL/blah@blah" "$VOLSIZE $TESTPOOL/blah^blah" \
+       "$VOLSIZE $TESTPOOL/blah*blah" "$VOLSIZE $TESTPOOL/blah%blah" \
+       "$VOLSIZE blah" "$VOLSIZE $TESTPOOL/$BYND_MAX_NAME" \
+       "1m -b $TESTPOOL/$TESTVOL1" "1m -b 11k $TESTPOOL/$TESTVOL1" \
+       "1m -b 511 $TESTPOOL/$TESTVOL1"
+
+set -A options "" "-s"
+
+datasetexists $TESTPOOL/$TESTVOL || \
+               log_must $ZFS create -V $VOLSIZE $TESTPOOL/$TESTVOL
+
+set -A existed_fs $($ZFS list -H | $AWK '{print $1}' | $GREP / )
+
+log_mustnot $ZFS create -V $VOLSIZE $TESTPOOL/$TESTVOL
+log_mustnot $ZFS create -s -V $VOLSIZE $TESTPOOL/$TESTVOL
+
+typeset -i i=0
+typeset -i j=0
+while (( i < ${#options[*]} )); do
+
+       j=0
+       while (( j < ${#args[*]} )); do
+               log_mustnot $ZFS create ${options[$i]} -V ${args[$j]}
+               log_mustnot $ZFS create -p ${options[$i]} -V ${args[$j]}
+
+               ((j = j + 1))
+       done
+
+       j=0
+       while (( $j < ${#RW_VOL_PROP[*]} )); do
+               log_mustnot $ZFS create ${options[$i]} -o ${RW_VOL_PROP[j]} \
+                   -o ${RW_VOL_PROP[j]} -V $VOLSIZE $TESTPOOL/$TESTVOL1
+               log_mustnot $ZFS create -p ${options[$i]} -o ${RW_VOL_PROP[j]} \
+                   -o ${RW_VOL_PROP[j]} -V $VOLSIZE $TESTPOOL/$TESTVOL1
+               ((j = j + 1))
+       done
+
+       j=0
+       while (( $j < ${#FS_ONLY_PROP[*]} )); do
+               log_mustnot $ZFS create ${options[$i]} -o ${FS_ONLY_PROP[j]} \
+                   -V $VOLSIZE $TESTPOOL/$TESTVOL1
+               log_mustnot $ZFS create -p ${options[$i]} -o ${FS_ONLY_PROP[j]} \
+                   -V $VOLSIZE $TESTPOOL/$TESTVOL1
+               ((j = j + 1))
+       done
+
+       ((i = i + 1))
+done
+
+log_pass "'zfs create [-s][-b <blocksize>] -V <size> <volume>' fails as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_011_pos.ksh
new file mode 100755 (executable)
index 0000000..ba2e55f
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# 'zfs create -p'  should work as expecteed
+#
+# STRATEGY:
+# 1. To create $newdataset with -p option, first make sure the upper level
+#    of $newdataset does not exist
+# 2. Make sure without -p option, 'zfs create' will fail
+# 3. Create $newdataset with -p option, verify it is created
+# 4. Run 'zfs create -p $newdataset' again, the exit code should be zero
+#    even $newdataset exists
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $TESTPOOL/$TESTFS1 ; then
+               log_must $ZFS destroy -rf $TESTPOOL/$TESTFS1
+       fi
+}
+
+log_onexit cleanup
+
+typeset newdataset1="$TESTPOOL/$TESTFS1/$TESTFS/$TESTFS1"
+typeset newdataset2="$TESTPOOL/$TESTFS1/$TESTFS/$TESTVOL1"
+
+log_assert "'zfs create -p' works as expected."
+
+log_must verify_opt_p_ops "create" "fs" $newdataset1
+
+# verify volume creation
+if is_global_zone; then
+       log_must verify_opt_p_ops "create" "vol" $newdataset2
+fi
+
+log_pass "'zfs create -p' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_012_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_012_pos.ksh
new file mode 100755 (executable)
index 0000000..fe50460
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs create -p -o version=1' should only cause the leaf filesystem to be version=1
+#
+# STRATEGY:
+# 1. Create $newdataset with -p option, verify it is created
+# 2. Verify only the leaf filesystem to be version=1, others use the current version
+#
+
+ZFS_VERSION=$($ZFS upgrade | $HEAD -1 | $AWK '{print $NF}' \
+       | $SED -e 's/\.//g')
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $TESTPOOL/$TESTFS1 ; then
+               log_must $ZFS destroy -rf $TESTPOOL/$TESTFS1
+       fi
+}
+
+log_onexit cleanup
+
+
+typeset newdataset1="$TESTPOOL/$TESTFS1/$TESTFS/$TESTFS1"
+
+log_assert "'zfs create -p -o version=1' only cause the leaf filesystem to be version=1."
+
+log_must $ZFS create -p -o version=1 $newdataset1
+log_must datasetexists $newdataset1
+
+log_must check_fs_version $TESTPOOL/$TESTFS1/$TESTFS/$TESTFS1 1
+for fs in $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS ; do
+       log_must check_fs_version $fs $ZFS_VERSION
+done
+
+log_pass "'zfs create -p -o version=1' only cause the leaf filesystem to be version=1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_013_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_013_pos.ksh
new file mode 100755 (executable)
index 0000000..460ee8f
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create.cfg
+
+#
+# DESCRIPTION:
+# 'zfs create -s -V <size> <volume>' can create various-size sparse volume
+#  with long fs name
+#
+# STRATEGY:
+# 1. Create a volume in the storage pool.
+# 2. Verify the volume is created correctly.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset -i j=0
+       while [[ $j -lt ${#size[*]} ]]; do
+               datasetexists $TESTPOOL/${LONGFSNAME}${size[j]} && \
+                   log_must $ZFS destroy $TESTPOOL/${LONGFSNAME}${size[j]}
+               ((j = j + 1))
+       done
+}
+
+log_onexit cleanup
+
+
+log_assert "'zfs create -s -V <size> <volume>' succeeds"
+
+typeset -i j=0
+while (( $j < ${#size[*]} )); do
+       typeset cmdline="$ZFS create -s -V ${size[j]} \
+                        $TESTPOOL/${LONGFSNAME}${size[j]}"
+
+       str=$(eval $cmdline 2>&1)
+       if (( $? == 0 )); then
+               log_note "SUCCESS: $cmdline"
+               log_must datasetexists $TESTPOOL/${LONGFSNAME}${size[j]}
+       elif [[ $str == *${VOL_LIMIT_KEYWORD1}* || \
+               $str == *${VOL_LIMIT_KEYWORD2}* || \
+               $str == *${VOL_LIMIT_KEYWORD3}* ]]
+       then
+               log_note "UNSUPPORTED: $cmdline"
+       else
+               log_fail "$cmdline"
+       fi
+
+       ((j = j + 1))
+done
+
+log_pass "'zfs create -s -V <size> <volume>' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
new file mode 100644 (file)
index 0000000..bbc1273
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# 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
+#
+
+#!/bin/ksh -p
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Check if the user property is identical to the expected value.
+#
+# $1 dataset
+# $2 property string
+#
+function propertycheck
+{
+       typeset dtst=$1
+       typeset propstr=$2
+
+       typeset prop=$($ECHO $propstr | $AWK -F= '{print $1}')
+       typeset expect_value=$($ECHO $propstr | $AWK -F= '{print $2}')
+       typeset value=$($ZFS get -H -o value $prop $dtst)
+
+
+       if [[ "$expect_value" == "$value" ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/Makefile.am
new file mode 100644 (file)
index 0000000..5a4bd70
--- /dev/null
@@ -0,0 +1,22 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_destroy
+dist_pkgdata_SCRIPTS = \
+       zfs_destroy_common.kshlib \
+       zfs_destroy.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_destroy_001_pos.ksh \
+       zfs_destroy_002_pos.ksh \
+       zfs_destroy_003_pos.ksh \
+       zfs_destroy_004_pos.ksh \
+       zfs_destroy_005_neg.ksh \
+       zfs_destroy_006_neg.ksh \
+       zfs_destroy_007_neg.ksh \
+       zfs_destroy_008_pos.ksh \
+       zfs_destroy_009_pos.ksh \
+       zfs_destroy_010_pos.ksh \
+       zfs_destroy_011_pos.ksh \
+       zfs_destroy_012_pos.ksh \
+       zfs_destroy_013_neg.ksh \
+       zfs_destroy_014_pos.ksh \
+       zfs_destroy_015_pos.ksh \
+       zfs_destroy_016_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/cleanup.ksh
new file mode 100755 (executable)
index 0000000..e838ba8
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
new file mode 100644 (file)
index 0000000..a62739b
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+
+export TESTFSCLONE=${TESTFS}clone
+export TESTVOLCLONE=${TESTVOL}clone
+export CTR=$TESTPOOL/$TESTCTR
+export FS=$CTR/$TESTFS
+export VOL=$CTR/$TESTVOL
+export FSSNAP=$FS@$TESTSNAP
+export VOLSNAP=$VOL@$TESTSNAP
+export FSCLONE=$TESTPOOL/$TESTFSCLONE
+export VOLCLONE=$TESTPOOL/$TESTVOLCLONE
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_001_pos.ksh
new file mode 100755 (executable)
index 0000000..e942eae
--- /dev/null
@@ -0,0 +1,234 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+#
+# DESCRIPTION:
+#      'zfs destroy -r|-rf|-R|-Rf <fs|ctr|vol|snap>' should recursively destroy
+#      all children and clones based on options.
+#
+# STRATEGY:
+#      1. Create test environment according to options. There are three test
+#      models can be created. Only ctr, fs & vol; with snap; with clone.
+#      2. According to option, make the dataset busy or not.
+#      3. Run 'zfs destroy [-rRf] <dataset>'
+#      4. According to dataset and option, check if get the expected results.
+#
+
+verify_runnable "both"
+
+#
+# According to parameters, 1st, create suitable testing environment. 2nd,
+# run 'zfs destroy $opt <dataset>'. 3rd, check the system status.
+#
+# $1 option of 'zfs destroy'
+# $2 dataset will be destroied.
+#
+function test_n_check
+{
+       typeset opt=$1
+       typeset dtst=$2
+
+       if ! is_global_zone ; then
+               if [[ $dtst == $VOL || $dtst == $VOLSNAP ]]; then
+                       log_note "UNSUPPORTED: Volume are unavailable in LZ."
+                       return
+               fi
+       fi
+
+       # '-f' has no effect on non-filesystems
+       if [[ $opt == -f ]]; then
+               if [[ $dtst != $FS ]]; then
+                       log_note "UNSUPPORTED: '-f ' is only available for " \
+                           "leaf FS."
+                       return
+               fi
+       fi
+
+       # Clean the test environment and make it clear.
+       if datasetexists $CTR; then
+               log_must $ZFS destroy -Rf $CTR
+       fi
+
+       # According to option create test compatible environment.
+       case $opt in
+               -r|-rf) setup_testenv snap ;;
+               -R|-Rf) setup_testenv clone ;;
+               -f)     setup_testenv ;;
+               *)      log_fail "Incorrect option: '$opt'." ;;
+       esac
+
+       #
+       # According to different dataset type, create busy condition when try to
+       # destroy this dataset.
+       #
+       typeset mpt_dir
+       case $dtst in
+               $CTR|$FS)
+                       if [[ $opt == *f* ]]; then
+                               mpt_dir=$(get_prop mountpoint $FS)
+                               pidlist="$pidlist $($MKBUSY \
+                                   $mpt_dir/$TESTFILE0)"
+                               log_note "$MKBUSY $mpt_dir/$TESTFILE0 " \
+                                   "(pidlist: $pidlist)"
+                               [[ -z $pidlist ]] && \
+                                   log_fail "Failure from $MKBUSY"
+                               log_mustnot $ZFS destroy -rR $dtst
+                       fi
+                       ;;
+               $VOL)
+                       if [[ $opt == *f* ]]; then
+                               pidlist="$pidlist $($MKBUSY \
+                                   $TESTDIR1/$TESTFILE0)"
+                               log_note "$MKBUSY $TESTDIR1/$TESTFILE0 " \
+                                   "(pidlist: $pidlist)"
+                               [[ -z $pidlist ]] && \
+                                   log_fail "Failure from $MKBUSY"
+                               log_mustnot $ZFS destroy -rR $dtst
+                       fi
+                       ;;
+               $VOLSNAP)
+                       if [[ $opt == *f* ]]; then
+                               pidlist="$pidlist $($MKBUSY \
+                                   $TESTDIR1/$TESTFILE0)"
+                               log_note "$MKBUSY $TESTDIR1/$TESTFILE0 " \
+                                   "(pidlist: $pidlist)"
+                               [[ -z $pidlist ]] && \
+                                   log_fail "Failure from $MKBUSY"
+                               log_must_busy $ZFS destroy -rR $dtst
+                               log_must $ZFS snapshot $dtst
+                       fi
+                       ;;
+               $FSSNAP)
+                       if [[ $opt == *f* ]]; then
+                               mpt_dir=$(snapshot_mountpoint $dtst)
+                               pidlist="$pidlist $($MKBUSY $mpt_dir)"
+                               log_note "$MKBUSY $mpt_dir (pidlist: $pidlist)"
+                               [[ -z $pidlist ]] && \
+                                   log_fail "Failure from $MKBUSY"
+                               if is_linux ; then
+                                       log_mustnot $ZFS destroy -rR $dtst
+                               else
+                                       log_must $ZFS destroy -rR $dtst
+                                       log_must $ZFS snapshot $dtst
+                               fi
+                       fi
+                       ;;
+               *)      log_fail "Unsupported dataset: '$dtst'."
+       esac
+
+       # Kill any lingering instances of mkbusy, and clear the list.
+       if is_linux ; then
+               [[ -z $pidlist ]] || log_must $KILL -TERM $pidlist
+               pidlist=""
+               log_mustnot $PGREP -fl $MKBUSY
+       fi
+
+       # Firstly, umount ufs filesystem which was created by zfs volume.
+       if is_global_zone; then
+               log_must $UMOUNT -f $TESTDIR1
+       fi
+
+       # Invoke 'zfs destroy [-rRf] <dataset>'
+       log_must $ZFS destroy $opt $dtst
+
+       # Kill any lingering instances of mkbusy, and clear the list.
+       if ! is_linux ; then
+               [[ -z $pidlist ]] || log_must $KILL -TERM $pidlist
+               pidlist=""
+               log_mustnot $PGREP -fl $MKBUSY
+       fi
+
+       case $dtst in
+               $CTR)   check_dataset datasetnonexists \
+                                       $CTR $FS $VOL $FSSNAP $VOLSNAP
+                       if [[ $opt == *R* ]]; then
+                               check_dataset datasetnonexists \
+                                       $FSCLONE $VOLCLONE
+                       fi
+                       ;;
+               $FS)    check_dataset datasetexists $CTR $VOL
+                       check_dataset datasetnonexists $FS
+                       if [[ $opt != -f ]]; then
+                               check_dataset datasetexists $VOLSNAP
+                               check_dataset datasetnonexists $FSSNAP
+                       fi
+                       if [[ $opt == *R* ]]; then
+                               check_dataset datasetexists $VOLCLONE
+                               check_dataset datasetnonexists $FSCLONE
+                       fi
+                       ;;
+               $VOL)   check_dataset datasetexists $CTR $FS $FSSNAP
+                       check_dataset datasetnonexists $VOL $VOLSNAP
+                       if [[ $opt == *R* ]]; then
+                               check_dataset datasetexists $FSCLONE
+                               check_dataset datasetnonexists $VOLCLONE
+                       fi
+                       ;;
+               $FSSNAP)
+                       check_dataset datasetexists $CTR $FS $VOL $VOLSNAP
+                       check_dataset datasetnonexists $FSSNAP
+                       if [[ $opt == *R* ]]; then
+                               check_dataset datasetexists $VOLCLONE
+                               check_dataset datasetnonexists $FSCLONE
+                       fi
+                       ;;
+               $VOLSNAP)
+                       check_dataset datasetexists $CTR $FS $VOL $FSSNAP
+                       check_dataset datasetnonexists $VOLSNAP
+                       if [[ $opt == *R* ]]; then
+                               check_dataset datasetexists $FSCLONE
+                               check_dataset datasetnonexists $VOLCLONE
+                       fi
+                       ;;
+       esac
+
+       log_note "'$ZFS destroy $opt $dtst' passed."
+}
+
+log_assert "'zfs destroy -r|-R|-f|-rf|-Rf <fs|ctr|vol|snap>' should " \
+       "recursively destroy all children."
+log_onexit cleanup_testenv
+
+typeset dtst=""
+typeset opt=""
+typeset pidlist=""
+for dtst in $CTR $FS $VOL $FSSNAP $VOLSNAP; do
+       for opt in "-r" "-R" "-f" "-rf" "-Rf"; do
+               log_note "Starting test: $ZFS destroy $opt $dtst"
+               test_n_check $opt $dtst
+       done
+done
+
+log_pass "'zfs destroy -r|-R|-f|-rf|-Rf <fs|ctr|vol|snap>' passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_002_pos.ksh
new file mode 100755 (executable)
index 0000000..5e27ce1
--- /dev/null
@@ -0,0 +1,96 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+
+#
+# DESCRIPTION:
+#      'zfs destroy <filesystem|volume|snapshot>' can successfully destroy
+#      the specified dataset which has no active dependents.
+#
+# STRATEGY:
+#      1. Create a filesystem,volume and snapshot in the storage pool
+#      2. Destroy the filesystem,volume and snapshot
+#      3. Verify the datasets are destroyed successfully
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset -i i=0
+       while (( $i < ${#data_objs[*]} )); do
+               datasetexists "${data_objs[i]}" && \
+                       $ZFS destroy -rf ${data_objs[i]}
+               ((i = i + 1))
+       done
+}
+
+log_assert "Verify 'zfs destroy' can destroy the specified datasets without active" \
+       "dependents."
+log_onexit cleanup
+
+if is_global_zone ; then
+       set -A data_objs "$TESTPOOL/$TESTFS@$TESTSNAP" "$TESTPOOL/$TESTFS1" \
+               "$TESTPOOL/$TESTVOL" "$TESTPOOL/$TESTVOL1"
+else
+       set -A data_objs "$TESTPOOL/$TESTFS@$TESTSNAP" "$TESTPOOL/$TESTFS1"
+fi
+
+log_must $ZFS create $TESTPOOL/$TESTFS1
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+
+if is_global_zone ; then
+       log_must $ZFS create -V $VOLSIZE $TESTPOOL/$TESTVOL
+
+       # Max volume size is 1TB on 32-bit systems
+       [[ $($ISAINFO -b) == 32 ]] && \
+               BIGVOLSIZE=1Tb
+       log_must $ZFS create -sV $BIGVOLSIZE $TESTPOOL/$TESTVOL1
+fi
+
+typeset -i i=0
+while (( $i < ${#data_objs[*]} )); do
+       datasetexists ${data_objs[i]} || \
+               log_fail "Create <filesystem>|<volume>|<snapshot> fail."
+       ((i = i + 1))
+done
+
+i=0
+while (( $i < ${#data_objs[*]} )); do
+       log_must $ZFS destroy ${data_objs[i]}
+       datasetexists ${data_objs[i]} && \
+               log_fail "'zfs destroy <filesystem>|<volume>|<snapshot>' fail."
+       ((i = i + 1))
+done
+
+log_pass "'zfs destroy <filesystem>|<volume>|<snapshot>' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_003_pos.ksh
new file mode 100755 (executable)
index 0000000..a18c0d6
--- /dev/null
@@ -0,0 +1,156 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+
+#
+# DESCRIPTION:
+#      Verify 'zfs destroy [-rR]' succeeds as root.
+#
+# STRATEGY:
+#      1. Create two datasets in the storage pool
+#      2. Create fs,vol,ctr,snapshot and clones of snapshot in the two datasets
+#      3. Create clone in the second dataset for the snapshot in the first dataset
+#      4. Verify 'zfs destroy -r' fails to destroy dataset with clone outside it
+#      5. Verify 'zfs destroy -R' succeeds to destroy dataset with clone outside it
+#      6. Verify 'zfs destroy -r' succeeds to destroy dataset without clone outside it.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for obj in $ctr2 $ctr1 $ctr; do
+               datasetexists $obj && \
+                       log_must $ZFS destroy -Rf $obj
+       done
+
+       for mntp in $TESTDIR1 $TESTDIR2; do
+               [[ -d $mntp ]] && \
+                       log_must $RM -rf $mntp
+       done
+}
+
+log_assert "Verify that 'zfs destroy [-rR]' succeeds as root. "
+
+log_onexit cleanup
+
+#
+# Preparations for testing
+#
+for dir in $TESTDIR1 $TESTDIR2; do
+       [[ ! -d $dir ]] && \
+               log_must $MKDIR -p $dir
+done
+
+ctr=$TESTPOOL/$TESTCTR
+ctr1=$TESTPOOL/$TESTCTR1
+ctr2=$ctr/$TESTCTR2
+ctr3=$ctr1/$TESTCTR2
+child_fs=$ctr/$TESTFS1
+child_fs1=$ctr1/$TESTFS2
+child_fs_mntp=$TESTDIR1
+child_fs1_mntp=$TESTDIR2
+child_vol=$ctr/$TESTVOL
+child_vol1=$ctr1/$TESTVOL
+child_fs_snap=$child_fs@snap
+child_fs1_snap=$child_fs1@snap
+child_fs_snap_clone=$ctr/$TESTCLONE
+child_fs_snap_clone1=$ctr1/${TESTCLONE}_across_ctr
+child_fs_snap_clone2=$ctr2/$TESTCLONE2
+child_fs1_snap_clone=$ctr1/$TESTCLONE1
+child_fs1_snap_clone1=$ctr/${TESTCLONE1}_across_ctr
+
+#
+# Create two datasets in the storage pool
+#
+log_must $ZFS create $ctr
+log_must $ZFS create $ctr1
+
+#
+# Create children datasets fs,vol,snapshot in the datasets, and
+# clones across two datasets
+#
+log_must $ZFS create $ctr2
+
+for fs in $child_fs $child_fs1; do
+       log_must $ZFS create $fs
+done
+
+log_must $ZFS set mountpoint=$child_fs_mntp $child_fs
+log_must $ZFS set mountpoint=$child_fs1_mntp $child_fs1
+
+for snap in $child_fs_snap $child_fs1_snap; do
+       log_must $ZFS snapshot $snap
+done
+
+if is_global_zone ; then
+       for vol in $child_vol $child_vol1; do
+               log_must $ZFS create -V $VOLSIZE $vol
+       done
+fi
+
+for clone in $child_fs_snap_clone $child_fs_snap_clone1; do
+       log_must $ZFS clone $child_fs_snap $clone
+done
+
+
+for clone in $child_fs1_snap_clone $child_fs1_snap_clone1; do
+       log_must $ZFS clone $child_fs1_snap $clone
+done
+
+log_note "Verify that 'zfs destroy -r' fails to destroy dataset " \
+       "with clone dependant outside it."
+
+for obj in $child_fs $child_fs1 $ctr $ctr1; do
+       log_mustnot $ZFS destroy -r $obj
+       datasetexists $obj || \
+               log_fail "'zfs destroy -r' fails to keep clone " \
+                       "dependant outside the hirearchy."
+done
+
+
+log_note "Verify that 'zfs destroy -R' succeeds to destroy dataset " \
+       "with clone dependant outside it."
+
+log_must $ZFS destroy -R $ctr1
+datasetexists $ctr1 && \
+       log_fail "'zfs destroy -R' fails to destroy dataset with clone outside it."
+
+log_note "Verify that 'zfs destroy -r' succeeds to destroy dataset " \
+       "without clone dependant outside it."
+
+log_must $ZFS destroy -r $ctr
+datasetexists $ctr && \
+       log_fail "'zfs destroy -r' fails to destroy dataset with clone outside it."
+
+log_pass "'zfs destroy [-rR] succeeds as root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_004_pos.ksh
new file mode 100755 (executable)
index 0000000..317e378
--- /dev/null
@@ -0,0 +1,126 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+
+#
+# DESCRIPTION:
+#      Verify 'zfs destroy -f' succeeds as root.
+#
+# STRATEGY:
+#      1. Create filesystem in the storage pool
+#      2. Set mountpoint for the filesystem and make it busy
+#      3. Verify that 'zfs destroy' fails to destroy the filesystem
+#      4. Verify 'zfs destroy -f' succeeds to destroy the filesystem.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       cd $olddir
+
+       datasetexists $clone && \
+               log_must $ZFS destroy -f $clone
+
+       snapexists $snap && \
+               log_must $ZFS destroy -f $snap
+
+       for fs in $fs1 $fs2; do
+               datasetexists $fs && \
+                       log_must $ZFS destroy -f $fs
+       done
+
+       for dir in $TESTDIR1 $TESTDIR2; do
+               [[ -d $dir ]] && \
+                       log_must $RM -rf $dir
+       done
+}
+
+log_assert "Verify that 'zfs destroy -f' succeeds as root. "
+
+log_onexit cleanup
+
+#
+# Preparations for testing
+#
+olddir=$PWD
+
+for dir in $TESTDIR1 $TESTDIR2; do
+       [[ ! -d $dir ]] && \
+               log_must $MKDIR -p $dir
+done
+
+fs1=$TESTPOOL/$TESTFS1
+mntp1=$TESTDIR1
+fs2=$TESTPOOL/$TESTFS2
+snap=$TESTPOOL/$TESTFS2@snap
+clone=$TESTPOOL/$TESTCLONE
+mntp2=$TESTDIR2
+
+#
+# Create filesystem and clone in the storage pool,  mount them and
+# make the mountpoint busy
+#
+for fs in $fs1 $fs2; do
+       log_must $ZFS create $fs
+done
+
+log_must $ZFS snapshot $snap
+log_must $ZFS clone $snap $clone
+
+log_must $ZFS set mountpoint=$mntp1 $fs1
+log_must $ZFS set mountpoint=$mntp2 $clone
+
+for arg in "$fs1 $mntp1" "$clone $mntp2"; do
+       fs=`$ECHO $arg | $AWK '{print $1}'`
+       mntp=`$ECHO $arg | $AWK '{print $2}'`
+
+       log_note "Verify that 'zfs destroy' fails to" \
+                       "destroy filesystem when it is busy."
+       cd $mntp
+       log_mustnot $ZFS destroy $fs
+
+       if is_linux; then
+               log_mustnot $ZFS destroy -f $fs
+               datasetnonexists $fs && \
+                   log_fail "'zfs destroy -f' destroyed busy filesystem."
+       else
+               log_must $ZFS destroy -f $fs
+               datasetexists $fs && \
+                   log_fail "'zfs destroy -f' fail to destroy busy filesystem."
+       fi
+
+       cd $olddir
+done
+
+log_pass "'zfs destroy -f' succeeds as root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_005_neg.ksh
new file mode 100755 (executable)
index 0000000..baf182a
--- /dev/null
@@ -0,0 +1,212 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+#
+# DESCRIPTION:
+#      Seperately verify 'zfs destroy -f|-r|-rf|-R|-rR <dataset>' will fail in
+#       different conditions.
+#
+# STRATEGY:
+#      1. Create pool, fs & vol.
+#      2. Create snapshot for fs & vol.
+#      3. Invoke 'zfs destroy ''|-f <dataset>', it should fail.
+#      4. Create clone for fs & vol.
+#      5. Invoke 'zfs destroy -r|-rf <dataset>', it should fail.
+#      6. Write file to filesystem or enter snapshot mountpoint.
+#      7. Invoke 'zfs destroy -R|-rR <dataset>', it should fail.
+#
+
+verify_runnable "both"
+
+log_assert "Seperately verify 'zfs destroy -f|-r|-rf|-R|-rR <dataset>' will " \
+       "fail in different conditions."
+log_onexit cleanup_testenv
+
+#
+# Run 'zfs destroy [-rRf] <dataset>', make sure it fail.
+#
+# $1 the collection of options
+# $2 the collection of datasets
+#
+function negative_test
+{
+       typeset options=$1
+       typeset datasets=$2
+
+       for dtst in $datasets; do
+               if ! is_global_zone; then
+                       if [[ $dtst == $VOL || $dtst == $VOLSNAP || \
+                               $dtst == $VOLCLONE ]]
+                       then
+                               log_note "UNSUPPORTED: " \
+                                       "Volume is unavailable in LZ."
+                               continue
+                       fi
+               fi
+               for opt in $options; do
+                       log_mustnot $ZFS destroy $opt $dtst
+               done
+       done
+}
+
+#
+# Create snapshots for filesystem and volume,
+# and verify 'zfs destroy' fails without '-r' or '-R'.
+#
+setup_testenv snap
+negative_test "-f" "$CTR $FS $VOL"
+
+#
+# Create clones for filesystem and volume,
+# and verify 'zfs destroy' fails without '-R'.
+#
+setup_testenv clone
+negative_test "-r -rf" "$CTR $FS $VOL"
+
+#
+# Get $FS mountpoint and make it busy, and verify 'zfs destroy $CTR' fails
+# without '-f'. Then verify the remaining datasets are correct. See below for
+# an explanation of what 'correct' means for this test.
+#
+mntpt=$(get_prop mountpoint $FS)
+pidlist=$($MKBUSY $mntpt/$TESTFILE0)
+log_note "$MKBUSY $mntpt/$TESTFILE0 (pidlist: $pidlist)"
+[[ -z $pidlist ]] && log_fail "Failure from mkbusy"
+negative_test "-R -rR" $CTR
+
+#
+# Checking the outcome of the test above is tricky, because the order in
+# which datasets are destroyed is not deterministic. Both $FS and $VOL are
+# busy, and the remaining datasets will be different depending on whether we
+# tried (and failed) to delete $FS or $VOL first.
+
+# The following datasets will exist independent of the order
+check_dataset datasetexists $CTR $FS $VOL
+
+if datasetexists $VOLSNAP && datasetnonexists $FSSNAP; then
+       # The recursive destroy failed on $FS
+       check_dataset datasetnonexists $FSSNAP $FSCLONE
+       check_dataset datasetexists $VOLSNAP $VOLCLONE
+elif datasetexists $FSSNAP && datasetnonexists $VOLSNAP; then
+       # The recursive destroy failed on $VOL
+       check_dataset datasetnonexists $VOLSNAP $VOLCLONE
+       check_dataset datasetexists $FSSNAP $FSCLONE
+else
+       log_must $ZFS list -rtall
+       log_fail "Unexpected datasets remaining"
+fi
+
+#
+# Create the clones for test environment, and verify 'zfs destroy $FS' fails
+# without '-f'.  Then verify the FS snap and clone are the only datasets
+# that were removed.
+#
+setup_testenv clone
+negative_test "-R -rR" $FS
+check_dataset datasetexists $CTR $FS $VOL $VOLSNAP $VOLCLONE
+check_dataset datasetnonexists $FSSNAP $FSCLONE
+
+log_must $KILL $pidlist
+log_mustnot $PGREP -fl $MKBUSY
+pidlist=""
+
+#
+# Create the clones for test environment and make the volume busy.
+# Then verify 'zfs destroy $CTR' fails without '-f'.
+#
+# Then verify the expected datasets exist (see below).
+#
+if is_global_zone; then
+       setup_testenv clone
+       pidlist=$($MKBUSY $TESTDIR1/$TESTFILE0)
+       log_note "$MKBUSY $TESTDIR1/$TESTFILE0 (pidlist: $pidlist)"
+       [[ -z $pidlist ]] && log_fail "Failure from mkbusy"
+       negative_test "-R -rR" $CTR
+       check_dataset datasetexists $CTR $VOL
+       check_dataset datasetnonexists $VOLSNAP $VOLCLONE
+
+       # Here again, the non-determinism of destroy order is a factor. $FS,
+       # $FSSNAP and $FSCLONE will still exist here iff we attempted to destroy
+       # $VOL (and failed) first. So check that either all of the datasets are
+       # present, or they're all gone.
+       if datasetexists $FS; then
+               check_dataset datasetexists $FS $FSSNAP $FSCLONE
+       else
+               check_dataset datasetnonexists $FS $FSSNAP $FSCLONE
+       fi
+fi
+
+#
+# Create the clones for test environment and make the volume busy.
+# Then verify 'zfs destroy $VOL' fails without '-f'.
+#
+# Then verify the snapshot and clone are destroyed, but nothing else is.
+#
+if is_global_zone; then
+       setup_testenv clone
+       negative_test "-R -rR" $VOL
+       check_dataset datasetexists $CTR $VOL $FS $FSSNAP $FSCLONE
+       check_dataset datasetnonexists $VOLSNAP $VOLCLONE
+fi
+
+log_must $KILL $pidlist
+log_mustnot $PGREP -fl $MKBUSY
+pidlist=""
+
+#
+# Create the clones for test environment and make the snapshot busy.
+# Then verify 'zfs destroy $snap' succeeds without '-f'.
+#
+# Then verify the snapshot and clone are destroyed, but nothing else is.
+#
+
+mntpt=$(snapshot_mountpoint $FSSNAP)
+pidlist=$($MKBUSY $mntpt)
+log_note "$MKBUSY $mntpt (pidlist: $pidlist)"
+[[ -z $pidlist ]] && log_fail "Failure from mkbusy"
+
+for option in -R -rR ; do
+       setup_testenv clone
+       log_must $ZFS destroy $option $FSSNAP
+       check_dataset datasetexists $CTR $FS $VOL
+       check_dataset datasetnonexists $FSSNAP $FSCLONE
+done
+
+log_must $KILL $pidlist
+log_mustnot $PGREP -fl $MKBUSY
+pidlist=""
+
+log_pass "zfs destroy -f|-r|-rf|-R|-rR <dataset>' failed in different " \
+       "condition passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_006_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_006_neg.ksh
new file mode 100755 (executable)
index 0000000..7e383c2
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+
+#
+# DESCRIPTION:
+# 'zfs destroy' should return an error with badly formed parameters,
+# including null destroyed object parameter, invalid options excluding
+# '-r' and '-f', non-existent datasets.
+#
+# STRATEGY:
+# 1. Create an array of parameters
+# 2. For each parameter in the array, execute 'zfs destroy'
+# 3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+
+set -A args "" "-r" "-f" "-rf" "-fr" "$TESTPOOL" "-f $TESTPOOL" \
+       "-? $TESTPOOL/$TESTFS" "$TESTPOOL/blah"\
+        "-r $TESTPOOL/blah" "-f $TESTPOOL/blah" "-rf $TESTPOOL/blah" \
+       "-fr $TESTPOOL/blah" "-$ $TESTPOOL/$TESTFS" "-5 $TESTPOOL/$TESTFS" \
+       "-rfgh $TESTPOOL/$TESTFS" "-rghf $TESTPOOL/$TESTFS" \
+       "$TESTPOOL/$TESTFS@blah" "/$TESTPOOL/$TESTFS" "-f /$TESTPOOL/$TESTFS" \
+       "-rf /$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTFS $TESTPOOL/$TESTFS" \
+       "-rRf $TESTPOOL/$TESTFS $TESTPOOL/$TESTFS"
+
+log_assert "'zfs destroy' should return an error with badly-formed parameters."
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZFS destroy ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "'zfs destroy' badly formed parameters fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_007_neg.ksh
new file mode 100755 (executable)
index 0000000..72272a5
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+
+#
+# DESCRIPTION:
+#      'zpool destroy' failed if this filesystem is namespace-parent
+#      of origin.
+#
+# STRATEGY:
+#      1. Create pool, fs and snapshot.
+#      2. Create a namespace-parent of origin clone.
+#      3. Promote this clone
+#      4. Verify the original fs can not be destroyed.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $clonesnap; then
+               log_must $ZFS promote $fs
+       fi
+       datasetexists $clone && log_must $ZFS destroy $clone
+       datasetexists $fssnap && log_must $ZFS destroy $fssnap
+}
+
+log_assert "Destroy dataset which is namespace-parent of origin should failed."
+log_onexit cleanup
+
+# Define variable $fssnap & and namespace-parent of origin clone.
+fs=$TESTPOOL/$TESTFS
+fssnap=$fs@snap
+clone=$fs/clone
+clonesnap=$fs/clone@snap
+
+# Define key word for expected failure.
+KEY_WORDS="filesystem has children"
+
+log_must $ZFS snapshot $fssnap
+log_must $ZFS clone $fssnap $clone
+log_must $ZFS promote $clone
+log_mustnot_expect "$KEY_WORDS" $ZFS destroy $fs
+log_mustnot_expect "$KEY_WORDS" $ZFS destroy $clone
+
+log_pass "Destroy dataset which is namespace-parent of origin passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_008_pos.ksh
new file mode 100755 (executable)
index 0000000..3efc9c9
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+################################################################################
+#
+# 'zfs destroy -d <snap>' should destroy the snapshot when no clone exists.
+#
+# 1. Create test environment without clones.
+# 2. 'zfs destroy -d <snap>'
+# 3. Verify that the snapshot was destroyed.
+#
+################################################################################
+
+function test_s_run
+{
+    typeset snap=$1
+
+    log_must $ZFS destroy -d $snap
+    log_mustnot datasetexists $snap    
+}
+
+log_assert "'zfs destroy -d <snap>' destroys snapshot if there is no clone"
+log_onexit cleanup_testenv
+
+setup_testenv snap
+
+for snap in $FSSNAP $VOLSNAP; do
+    if [[ $snap == $VOLSNAP ]]; then
+               if is_global_zone; then
+                       test_s_run $snap
+               fi
+       else
+               test_s_run $snap
+       fi
+done
+
+log_pass "'zfs destroy -d <snap>' destroys snapshot if there is no clone"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_009_pos.ksh
new file mode 100755 (executable)
index 0000000..510776e
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+################################################################################
+#
+# 'zfs destroy -d <snap>' should mark snapshot for deferred destroy when
+# clone exists and destroy when clone is destroyed.
+#
+# 1. Create test environment with clones.
+# 2. 'zfs destroy -d <snap>'
+# 3. Verify snapshot is marked for deferred destroy.
+# 4. 'zfs destroy <clone>'
+# 3. Verify that the snapshot and clone are destroyed.
+#
+################################################################################
+
+function test_c_run
+{
+    typeset dstype=$1
+
+    snap=$(eval echo \$${dstype}SNAP)
+    clone=$(eval echo \$${dstype}CLONE)
+    log_must $ZFS destroy -d $snap
+    log_must datasetexists $snap
+    log_must eval "[[ $(get_prop defer_destroy $snap) == 'on' ]]"
+    log_must $ZFS destroy $clone
+    log_mustnot datasetexists $snap
+    log_mustnot datasetexists $clone
+}
+
+log_assert "'zfs destroy -d <snap>' marks cloned snapshot for deferred destroy"
+log_onexit cleanup_testenv
+
+setup_testenv clone
+
+for dstype in FS VOL; do
+    if [[ $dstype == VOL ]]; then
+               if is_global_zone; then
+                       test_c_run $dstype
+               fi
+       else
+               test_c_run $dstype
+       fi
+done
+
+log_pass "'zfs destroy -d <snap>' marks cloned snapshot for deferred destroy"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_010_pos.ksh
new file mode 100755 (executable)
index 0000000..77d9ed2
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+################################################################################
+#
+# When using 'zfs destroy -R' on a file system heirarchy that inclues a
+# snapshot and a clone of that snapshot, and the snapshot has been
+# defer-destroyed, make sure that the 'zfs destroy -R' works as expected.
+# In particular make sure that libzfs is not confused by the fact that the
+# kernel will automatically remove the defer-destroyed snapshot when the
+# clone is destroyed.
+#
+# 1. Create test environment.
+# 2. Create a clone of the snapshot.
+# 3. 'zfs destroy -d <snap>'
+# 4. 'zfs destroy -R'
+# 5. Verify that the snapshot and clone are destroyed.
+#
+################################################################################
+
+function test_clone_run
+{
+    typeset dstype=$1
+
+    ds=$(eval echo \$${dstype})
+    snap=$(eval echo \$${dstype}SNAP)
+    clone=$(eval echo \$${dstype}CLONE)
+    log_must $ZFS destroy -d $snap
+    log_must datasetexists $snap
+    log_must $ZFS destroy -R $clone
+    log_mustnot datasetexists $snap
+    log_mustnot datasetexists $clone
+}
+
+log_assert "'zfs destroy -R' works on deferred destroyed snapshots"
+log_onexit cleanup_testenv
+
+setup_testenv clone
+
+for dstype in FS VOL; do
+    if [[ $dstype == VOL ]]; then
+               if is_global_zone; then
+                       test_clone_run $dstype
+               fi
+       else
+               test_clone_run $dstype
+       fi
+done
+
+log_pass "'zfs destroy -R' works on deferred destroyed snapshots"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_011_pos.ksh
new file mode 100755 (executable)
index 0000000..b59fc9b
--- /dev/null
@@ -0,0 +1,63 @@
+#!/bin/ksh -p
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+################################################################################
+#
+# 'zfs destroy -d <snap>' should mark snapshot for deferred destroy when
+# there is a user hold.
+#
+# 1. Create test environment without clones.
+# 2. 'zfs hold <tag> <snap>'
+# 3. 'zfs destroy -d <snap>'
+# 4. Verify snapshot is marked for deferred destroy.
+# 5. 'zfs release <tag> <snap>'
+# 6. Verify that the snapshot is destroyed.
+#
+################################################################################
+
+function test_snap_run
+{
+    typeset dstype=$1
+
+    snap=$(eval echo \$${dstype}SNAP)
+    log_must $ZFS hold zfstest $snap
+    log_must $ZFS destroy -d $snap
+    log_must datasetexists $snap
+    log_must eval "[[ $(get_prop defer_destroy $snap) == 'on' ]]"
+    log_must $ZFS release zfstest $snap
+    log_mustnot datasetexists $snap
+}
+
+log_assert "'zfs destroy -d <snap>' marks held snapshot for deferred destroy"
+log_onexit cleanup_testenv
+
+setup_testenv snap
+
+for dstype in FS VOL; do
+    if [[ $dstype == VOL ]]; then
+               if is_global_zone; then
+                       test_snap_run $dstype
+               fi
+       else
+               test_snap_run $dstype
+       fi
+done
+
+log_pass "'zfs destroy -d <snap>' marks held snapshot for deferred destroy"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_012_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_012_pos.ksh
new file mode 100755 (executable)
index 0000000..d543f12
--- /dev/null
@@ -0,0 +1,75 @@
+#!/bin/ksh -p
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+################################################################################
+#
+# Deferred destroyed snapshots remain until the last hold is released.
+#
+# 1. Create test environment without clones.
+# 2. 'zfs hold <tag1> <snap>'
+# 3. 'zfs destroy -d <snap>'
+# 4. Sequence of holds/releases including invalid ones that should fail.
+# 4. Verify snapshot still exists.
+# 5. Release all holds.
+# 6. Verify that the snapshot is destroyed.
+#
+################################################################################
+
+function test_snap_run
+{
+    typeset dstype=$1
+
+    snap=$(eval echo \$${dstype}SNAP)
+    log_must $ZFS hold zfstest1 $snap
+    log_must $ZFS destroy -d $snap
+    log_must datasetexists $snap
+    log_must eval "[[ $(get_prop defer_destroy $snap) == 'on' ]]"
+
+    log_must $ZFS hold zfstest2 $snap
+    log_mustnot $ZFS hold zfstest1 $snap
+    log_mustnot $ZFS hold zfstest2 $snap
+
+    log_must $ZFS release zfstest1 $snap
+    log_must datasetexists $snap
+    log_mustnot $ZFS release zfstest1 $snap
+    log_must datasetexists $snap
+    log_mustnot $ZFS release zfstest3 $snap
+    log_must datasetexists $snap
+
+    log_must $ZFS release zfstest2 $snap
+    log_mustnot datasetexists $snap
+}
+
+log_assert "deferred destroyed snapshots remain until last hold is released"
+log_onexit cleanup_testenv
+
+setup_testenv snap
+
+for dstype in FS VOL; do
+    if [[ $dstype == VOL ]]; then
+               if is_global_zone; then
+                       test_snap_run $dstype
+               fi
+       else
+               test_snap_run $dstype
+       fi
+done
+
+log_pass "deferred destroyed snapshots remain until last hold is released"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_013_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_013_neg.ksh
new file mode 100755 (executable)
index 0000000..2a7ee20
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/ksh -p
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
+
+################################################################################
+#
+# Destroy of held snapshot should fail.
+#
+# 1. Create test environment without clones.
+# 2. 'zfs hold <tag> <snap>'
+# 3. 'zfs destroy <snap>' should fail.
+# 4. Verify snapshot still exists.
+# 5. 'zfs release <tag> <snap>'
+# 6. Verify that we can destroy the snapshot.
+#
+################################################################################
+
+function test_snap_run
+{
+    typeset dstype=$1
+
+    snap=$(eval echo \$${dstype}SNAP)
+    log_must $ZFS hold zfstest $snap
+    log_mustnot $ZFS destroy $snap
+    log_must datasetexists $snap
+    log_must $ZFS release zfstest $snap
+    log_must $ZFS destroy $snap
+    log_mustnot datasetexists $snap
+}
+
+log_assert "zfs destroy of held snapshots fails"
+log_onexit cleanup_testenv
+
+setup_testenv snap
+
+for dstype in FS VOL; do
+    if [[ $dstype == VOL ]]; then
+               if is_global_zone; then
+                       test_snap_run $dstype
+               fi
+       else
+               test_snap_run $dstype
+       fi
+done
+
+log_pass "zfs destroy of held snapshots fails"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_014_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_014_pos.ksh
new file mode 100755 (executable)
index 0000000..5625785
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+
+#
+# DESCRIPTION:
+#      'zfs destroy -R <snapshot>' can destroy all the child
+#       snapshots and preserves all the nested datasetss.
+#
+# STRATEGY:
+#      1. Create nested datasets in the storage pool.
+#      2. Create recursive snapshots for all the nested datasets.
+#      3. Verify when snapshots are destroyed recursively, all
+#          the nested datasets still exist.
+#
+
+verify_runnable "both"
+
+log_assert "Verify 'zfs destroy -R <snapshot>' does not destroy" \
+       "nested datasets."
+log_onexit cleanup
+
+datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS2
+    $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3"
+
+function cleanup
+{
+       for ds in $datasets; do
+               datasetexists $ds && $ZFS destroy -rf $ds
+       done
+}
+
+# create nested datasets
+log_must $ZFS create -p $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3
+
+# verify dataset creation
+for ds in $datasets; do
+       datasetexists $ds || log_fail "Create $ds dataset fail."
+done
+
+# create recursive nestedd snapshot
+log_must $ZFS snapshot -r $TESTPOOL/$TESTFS1@snap
+for ds in $datasets; do
+       datasetexists $ds@snap || log_fail "Create $ds@snap snapshot fail."
+done
+
+# destroy nested snapshot recursively
+log_must $ZFS destroy -R $TESTPOOL/$TESTFS1@snap
+
+# verify snapshot destroy
+for ds in $datasets; do
+       datasetexists $ds@snap && log_fail "$ds@snap exists. Destroy failed!"
+done
+
+# verify nested datasets still exist
+for ds in $datasets; do
+       datasetexists $ds || log_fail "Recursive snapshot destroy deleted $ds"
+done
+
+log_pass "'zfs destroy -R <snapshot>' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_015_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_015_pos.ksh
new file mode 100755 (executable)
index 0000000..579e747
--- /dev/null
@@ -0,0 +1,161 @@
+#!/bin/ksh
+#
+# 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.
+#
+
+# DESCRIPTION
+#      zfs destroy <dataset@snap1,snap2..> can destroy a list of multiple
+#      snapshots from the same datasets
+#
+# STRATEGY
+#      1. Create multiple snapshots for the same datset
+#      2. Run zfs destroy for these snapshots for a mix of valid and
+#         invalid snapshot names
+#      3. Run zfs destroy for snapshots from different datasets and
+#         pools
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTFS1 && $ZFS destroy -R $TESTPOOL/$TESTFS1
+       datasetexists $TESTPOOL/$TESTFS2 && $ZFS destroy -R $TESTPOOL/$TESTFS2
+       poolexists $TESTPOOL2 && $ZPOOL destroy $TESTPOOL2
+       $RM -rf $VIRTUAL_DISK
+}
+
+log_assert "zfs destroy for multiple snapshot is handled correctly"
+log_onexit cleanup
+
+$ZFS create $TESTPOOL/$TESTFS1
+typeset -i i=1
+snaplist=""
+log_note "zfs destroy on valid snapshot names"
+for i in 1 2 3 4 5; do
+       log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
+       snaplist=$snaplist,snap$i
+done
+snaplist=${snaplist#,}
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@$snaplist
+for i in 1 2 3 4 5; do
+       log_mustnot snapexists $TESTPOOL/$TESFS1@snap$i
+done
+
+log_note "zfs destroy with all bogus snapshot names"
+log_mustnot $ZFS destroy $TESTPOOL/$TESTFS1@snap12,snap21,sna@pple1@,s""nappy2
+
+log_note "zfs destroy with some bogus snapshot names"
+for i in 1 2 3; do
+       log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
+done
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap1,snap2,snapple1,snappy2,snap3
+for i in 1 2 3; do
+       log_mustnot snapexists $TESTPOOL/$TESTFS1@snap$i
+done
+
+log_note "zfs destroy with some snapshot names having special characters"
+for i in 1 2 3; do
+       log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
+done
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap1,@,snap2,,,,snap3,
+for i in 1 2 3; do
+       log_mustnot snapexists $TESTPOOL/$TESTFS1@snap$i
+done
+log_note "zfs destroy for too many snapshots"
+snaplist=""
+for i in {1..100}; do
+       log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
+       snaplist=$snaplist,snap$i
+done
+snaplist=${snaplist#,}
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@$snaplist
+for i in {1..100}; do
+       log_mustnot snapexists $TESTPOOL/$TESTFS1@snap$i
+done
+log_note "zfs destroy multiple snapshots with hold"
+snaplist=""
+for i in 1 2 3 4 5; do
+       log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
+       log_must $ZFS hold keep $TESTPOOL/$TESTFS1@snap$i
+       snaplist=$snaplist,snap$i
+done
+snaplist=${snaplist#,}
+log_mustnot $ZFS destroy $TESTPOOL/$TESTFS1@$snaplist
+for i in 1 2 3 4 5; do
+       log_must $ZFS release keep $TESTPOOL/$TESTFS1@snap$i
+done
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@$snaplist
+
+log_note "zfs destroy for multiple snapshots having clones"
+for i in 1 2 3 4 5; do
+       log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
+done
+snaplist=""
+for i in 1 2 3 4 5; do
+       log_must $ZFS clone $TESTPOOL/$TESTFS1@snap$i $TESTPOOL/$TESTFS1/clone$i
+       snaplist=$snaplist,snap$i
+done
+snaplist=${snaplist#,}
+log_mustnot $ZFS destroy $TESTPOOL/$TESTFS1@$snaplist
+for i in 1 2 3 4 5; do
+       log_must snapexists $TESTPOOL/$TESTFS1@snap$i
+       log_must $ZFS destroy $TESTPOOL/$TESTFS1/clone$i
+done
+
+log_note "zfs destroy for snapshots for different datasets"
+log_must $ZFS create $TESTPOOL/$TESTFS2
+log_must $ZFS snapshot $TESTPOOL/$TESTFS2@fs2snap
+log_must $ZFS create $TESTPOOL/$TESTFS1/$TESTFS2
+log_must $ZFS snapshot $TESTPOOL/$TESTFS1/$TESTFS2@fs12snap
+
+long_arg=$TESTPOOL/$TESTFS1@snap1,$TESTPOOL/$TESTFS2@fs2snap,
+long_arg=$long_arg$TESTPOOL/$TESTFS1/$TESTFS2@fs12snap
+log_must $ZFS destroy $long_arg
+log_mustnot snapexists $TESTPOOL/$TESTFS1@snap1
+log_must snapexists $TESTPOOL/$TESTFS2@fs2snap
+log_must snapexists $TESTPOOL/$TESTFS1/$TESTFS2@fs12snap
+
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@fs2snap,fs12snap,snap2
+log_must snapexists $TESTPOOL/$TESTFS2@fs2snap
+log_must snapexists $TESTPOOL/$TESTFS1/$TESTFS2@fs12snap
+log_mustnot snapexists $TESTPOOL/$TESTFS1@snap2
+
+log_must $ZFS destroy $TESTPOOL/$TESTFS2@fs2snap,fs12snap,snap3
+log_mustnot snapexists $TESTPOOL/$TESTFS2@fs2snap
+log_must snapexists $TESTPOOL/$TESTFS1/$TESTFS2@fs12snap
+log_must snapexists $TESTPOOL/$TESTFS1@snap3
+
+log_note "zfs destroy for snapshots from different pools"
+VIRTUAL_DISK=/var/tmp/disk
+log_must $DD if=/dev/urandom of=$VIRTUAL_DISK bs=1M count=64
+log_must $ZPOOL create $TESTPOOL2 $VIRTUAL_DISK
+log_must poolexists $TESTPOOL2
+
+log_must $ZFS create $TESTPOOL2/$TESTFS1
+log_must $ZFS snapshot $TESTPOOL2/$TESTFS1@snap
+long_arg=$TESTPOOL2/$TESTFS1@snap,$TESTPOOL/$TESTFS1@snap3,
+long_arg=$long_arg$TESTPOOL/$TESTFS1@snap5
+log_must $ZFS destroy $long_arg
+log_mustnot snapexists $TESTPOOL2/$TESTFS1@snap
+log_must snapexists $TESTPOOL/$TESTFS1@snap3
+log_must snapexists $TESTPOOL/$TESTFS1@snap5
+
+log_must $ZFS snapshot $TESTPOOL2/$TESTFS1@snap
+log_must $ZFS destroy $TESTPOOL2/$TESTFS1@snap5,snap3,snap
+log_mustnot snapexists $TESTPOOL2/$TESTFS1@snap
+log_must snapexists $TESTPOOL/$TESTFS1@snap3
+log_must snapexists $TESTPOOL/$TESTFS1@snap5
+
+log_pass "zfs destroy for multiple snapshots passes"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_016_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_016_pos.ksh
new file mode 100755 (executable)
index 0000000..0942bac
--- /dev/null
@@ -0,0 +1,186 @@
+#!/bin/ksh
+#
+# 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.
+#
+
+# DESCRIPTION
+# Verify zfs destroy test for range of snapshots by giving a list
+# of valid and invalid arguments.
+
+# STRATEGY
+# 1. Create a list of valid and invalid arguments for range snapshot
+#     destroy.
+# 2. Set up a filesystem and a volume with multiple snapshots
+# 3. Run zfs destroy for all the arguments and verify existence of snapshots
+# 4. Verify the destroy for snapshots with clones and hold
+
+. $STF_SUITE/include/libtest.shlib
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTFS1 && \
+           log_must $ZFS destroy -R $TESTPOOL/$TESTFS1
+       datasetexists $TESTPOOL/$TESTVOL && \
+           log_must $ZFS destroy -Rf $TESTPOOL/$TESTVOL
+}
+
+function setup_snapshots
+{
+       for i in $snaps; do
+               datasetexists $TESTPOOL/$TESTFS1@snap$i && \
+                   log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap$i
+               datasetexists $TESTPOOL/$TESTVOL@snap$i && \
+                   log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap$i
+               log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
+               log_must $ZFS snapshot $TESTPOOL/$TESTVOL@snap$i
+       done
+}
+
+function verify_snapshots
+{
+       typeset snap_exists=${1:-0}
+       if [[ $snap_exists == 1 ]]; then
+               for i in $range; do
+                       snapexists $TESTPOOL/$TESTFS1@snap$i || \
+                           log_fail "zfs destroy should not have destroyed" \
+                           "$TESTPOOL/$TESTFS1@snap$i"
+                       snapexists $TESTPOOL/$TESTVOL@snap$i || \
+                           log_fail "zfs destroy should not have destroyed" \
+                           "$TESTPOOL/$TESTVOL@snap$i"
+               done
+       else
+               for i in $range; do
+                       snapexists $TESTPOOL/$TESTFS1@snap$i && \
+                           log_fail "zfs destroy should have destroyed" \
+                           "$TESTPOOL/$TESTFS1@snap$i"
+                       snapexists $TESTPOOL/$TESTVOL@snap$i && \
+                           log_fail "zfs destroy should have destroyed" \
+                           "$TESTPOOL/$TESTVOL@snap$i"
+               done
+       fi
+}
+
+invalid_args="@snap0%snap5 @snap1%snap6 @snap0%snap6 @snap5%snap1 \
+    @snap1%$TESTPOOL/$TESTFS1@snap5 @snap1%%snap5 @snap1%@snap5 \
+    @@snap1%snap5 snap1%snap5 snap1%snap3%snap5"
+valid_args="@snap1%snap5 @%"
+log_assert "zfs destroy deletes ranges of snapshots"
+log_onexit cleanup
+
+log_must $ZFS create $TESTPOOL/$TESTFS1
+log_must $ZFS create -V $VOLSIZE $TESTPOOL/$TESTVOL
+snaps="1 2 3 4 5"
+log_note "Verify the valid arguments"
+range="1 2 3 4 5"
+for args in $valid_args; do
+       setup_snapshots
+       log_must $ZFS destroy $TESTPOOL/$TESTFS1$args
+       log_must $ZFS destroy $TESTPOOL/$TESTVOL$args
+       verify_snapshots
+done
+
+log_note "Verify invalid arguements"
+setup_snapshots
+for args in $invalid_args; do
+       log_mustnot $ZFS destroy $TESTPOOL/$TESTFS1$args
+       log_mustnot $ZFS destroy $TESTPOOL/$TESTVOL$args
+       log_must verify_snapshots 1
+done
+
+log_note "Destroy the begining range"
+
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@%snap3
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@%snap3
+range="1 2 3"
+verify_snapshots
+range="4 5"
+verify_snapshots 1
+
+setup_snapshots
+log_note "Destroy the mid range"
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap2%snap4
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap2%snap4
+range="2 3 4"
+verify_snapshots
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap1%snap5
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap1%snap5
+range="1 5"
+verify_snapshots
+
+setup_snapshots
+log_note "Destroy the end range"
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap3%
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap3%
+range="1 2"
+verify_snapshots 1
+range="3 4 5"
+verify_snapshots
+
+setup_snapshots
+log_note "Destroy a simple list"
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap2,snap4
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap2,snap4
+range="2 4"
+verify_snapshots
+range="1 3 5"
+verify_snapshots 1
+
+setup_snapshots
+log_note "Destroy a list and range together"
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap1%snap3,snap5
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap1%snap3,snap5
+range="1 2 3 5"
+verify_snapshots
+range=4
+verify_snapshots 1
+
+snaps="1 2 3 5 6 7 8 9 10"
+setup_snapshots
+log_note "Destroy a list of ranges"
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap1%snap3,snap5
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap1%snap3,snap5
+range="1 2 3 5"
+verify_snapshots
+range=4
+verify_snapshots 1
+
+snaps="1 2 3 4 5"
+setup_snapshots
+log_note "Snapshot destory with hold"
+range="1 2 3 4 5"
+for i in 1 2 3 4 5; do
+       log_must $ZFS hold keep $TESTPOOL/$TESTFS1@snap$i
+       log_must $ZFS hold keep $TESTPOOL/$TESTVOL@snap$i
+done
+log_mustnot $ZFS destroy $TESTPOOL/$TESTFS1@snap1%snap5
+log_mustnot $ZFS destroy $TESTPOOL/$TESTVOL@snap1%snap5
+verify_snapshots 1
+for i in 1 2 3 4 5; do
+       log_must $ZFS release keep $TESTPOOL/$TESTFS1@snap$i
+       log_must $ZFS release keep $TESTPOOL/$TESTVOL@snap$i
+done
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap1%snap5
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap1%snap5
+verify_snapshots
+
+log_note "Range destroy for snapshots having clones"
+setup_snapshots
+for i in 1 2 3 4 5; do
+       log_must $ZFS clone $TESTPOOL/$TESTFS1@snap$i $TESTPOOL/$TESTFS1/clone$i
+done
+log_must $ZFS destroy -R $TESTPOOL/$TESTFS1@snap1%snap5
+log_must $ZFS destroy $TESTPOOL/$TESTVOL@snap1%snap5
+verify_snapshots
+
+log_pass "'zfs destroy' successfully destroys ranges of snapshots"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_destroy/zfs_destroy_common.kshlib
new file mode 100644 (file)
index 0000000..41c1a4b
--- /dev/null
@@ -0,0 +1,147 @@
+#
+# 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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_destroy/zfs_destroy.cfg
+
+#
+# Create or recover a set of test environment which include ctr, vol, fs,
+# snap & clone. It looks like the following.
+#
+# pool
+#    |ctr
+#    |  |fs
+#    |  | |fssnap
+#    |  |vol
+#    |     |volsnap
+#    |fsclone
+#    |volclone
+#
+# $1 indicate which dependent dataset need be created. Such as 'snap', 'clone'.
+#
+function setup_testenv #[dtst]
+{
+       typeset dtst=$1
+
+       if ! datasetexists $CTR; then
+               log_must $ZFS create $CTR
+       fi
+       if ! datasetexists $FS; then
+               log_must $ZFS create $FS
+       fi
+       # Volume test is only availible on globle zone
+       if ! datasetexists $VOL && is_global_zone; then
+               log_must $ZFS create -V $VOLSIZE $VOL
+               block_device_wait
+
+               $ECHO "y" | $NEWFS $ZVOL_DEVDIR/$VOL > /dev/null 2>&1
+               if (( $? == 0 )); then
+                       log_note "SUCCESS: $NEWFS $ZVOL_DEVDIR/$VOL>/dev/null"
+               else
+                       log_fail "$NEWFS $ZVOL_DEVDIR/$VOL > /dev/null"
+               fi
+
+               if [[ ! -d $TESTDIR1 ]]; then
+                       log_must $MKDIR $TESTDIR1
+               fi
+               log_must $MOUNT $ZVOL_DEVDIR/$VOL $TESTDIR1
+       fi
+
+       if [[ $dtst == snap || $dtst == clone ]]; then
+               if ! datasetexists $FSSNAP; then
+                       log_must $ZFS snapshot $FSSNAP
+               fi
+               if ! datasetexists $VOLSNAP && is_global_zone; then
+                       log_must $ZFS snapshot $VOLSNAP
+               fi
+       fi
+
+       if [[ $dtst == clone ]]; then
+               if ! datasetexists $FSCLONE; then
+                       log_must $ZFS clone $FSSNAP $FSCLONE
+               fi
+               if ! datasetexists $VOLCLONE && is_global_zone; then
+                       log_must $ZFS clone $VOLSNAP $VOLCLONE
+               fi
+       fi
+}
+
+# Clean up the testing environment
+#
+function cleanup_testenv
+{
+       if is_global_zone && ismounted "$TESTDIR1" "$NEWFS_DEFAULT_FS" ; then
+               log_must $UMOUNT -f $TESTDIR1
+       fi
+       if [[ -d $TESTDIR1 ]]; then
+               log_must $RM -rf $TESTDIR1
+       fi
+
+       $PKILL $MKBUSY
+
+       if datasetexists $CTR; then
+               log_must $ZFS destroy -Rf $CTR
+       fi
+}
+
+#
+# Delete volume and related datasets from list, if the test cases was
+# runing in local zone. Then check them are existed or non-exists.
+#
+# $1   function name
+# $2-n datasets name
+#
+function check_dataset
+{
+       typeset funname=$1
+       typeset newlist=""
+       typeset dtst
+       shift
+
+       for dtst in "$@"; do
+               # Volume and related stuff are unvailable in local zone
+               if ! is_global_zone; then
+                       if [[ $dtst == $VOL || $dtst == $VOLSNAP || \
+                               $dtst == $VOLCLONE ]]
+                       then
+                               continue
+                       fi
+               fi
+               newlist="$newlist $dtst"
+       done
+
+       if (( ${#newlist} != 0 )); then
+               # Run each item in $newlist individually so on failure, the
+               # probelmatic dataset is listed in the logs.
+               for i in $newlist; do
+                       log_must $funname $i
+               done
+       fi
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/Makefile.am
new file mode 100644 (file)
index 0000000..880a845
--- /dev/null
@@ -0,0 +1,16 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_get
+dist_pkgdata_SCRIPTS = \
+       zfs_get_common.kshlib \
+       zfs_get_list_d.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_get_001_pos.ksh \
+       zfs_get_002_pos.ksh \
+       zfs_get_003_pos.ksh \
+       zfs_get_004_pos.ksh \
+       zfs_get_005_neg.ksh \
+       zfs_get_006_neg.ksh \
+       zfs_get_007_neg.ksh \
+       zfs_get_008_pos.ksh \
+       zfs_get_009_pos.ksh \
+       zfs_get_010_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/setup.ksh
new file mode 100755 (executable)
index 0000000..9692385
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_container_volume_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_001_pos.ksh
new file mode 100755 (executable)
index 0000000..dbac854
--- /dev/null
@@ -0,0 +1,131 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+
+#
+# DESCRIPTION:
+# Setting the valid option and properties, 'zfs get' should return the
+# correct property value.
+#
+# STRATEGY:
+# 1. Create pool, filesystem, volume and snapshot.
+# 2. Setting valid parameter, 'zfs get' should succeed.
+# 3. Compare the output property name with the original input property.
+#
+
+verify_runnable "both"
+
+typeset options=("" "-p" "-r" "-H")
+
+typeset -i i=${#options[*]}
+typeset -i j=0
+while ((j<${#depth_options[*]}));
+do
+       options[$i]=-"${depth_options[$j]}"
+       ((j+=1))
+       ((i+=1))
+done
+
+typeset zfs_props=("type" used available creation volsize referenced \
+    compressratio mounted origin recordsize quota reservation mountpoint \
+    sharenfs checksum compression atime devices exec readonly setuid zoned \
+    snapdir acltype aclinherit canmount primarycache secondarycache \
+    usedbychildren usedbydataset usedbyrefreservation usedbysnapshots \
+    version)
+
+typeset userquota_props=(userquota@root groupquota@root userused@root \
+    groupused@root)
+typeset all_props=("${zfs_props[@]}" "${userquota_props[@]}")
+typeset dataset=($TESTPOOL/$TESTCTR $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTVOL@$TESTSNAP)
+
+#
+# According to dataset and option, checking if 'zfs get' return correct
+# property information.
+#
+# $1 dataset
+# $2 properties which are expected to output into $TESTDIR/$TESTFILE0
+# $3 option
+#
+function check_return_value
+{
+       typeset dst=$1
+       typeset props=$2
+       typeset opt=$3
+       typeset -i found=0
+       typeset p
+
+       for p in $props; do
+               found=0
+
+               while read line; do
+                       typeset item
+                       item=$($ECHO $line | $AWK '{print $2}' 2>&1)
+
+                       if [[ $item == $p ]]; then
+                               ((found += 1))
+                               break
+                       fi
+               done < $TESTDIR/$TESTFILE0
+
+               if ((found == 0)); then
+                       log_fail "'zfs get $opt $props $dst' return " \
+                           "error message.'$p' haven't been found."
+               fi
+       done
+
+       log_note "SUCCESS: '$ZFS get $opt $prop $dst'."
+}
+
+log_assert "Setting the valid options and properties 'zfs get' should return " \
+    "the correct property value."
+log_onexit cleanup
+
+# Create filesystem and volume's snapshot
+create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
+create_snapshot $TESTPOOL/$TESTVOL $TESTSNAP
+
+typeset -i i=0
+while ((i < ${#dataset[@]})); do
+       for opt in "${options[@]}"; do
+               for prop in ${all_props[@]}; do
+                       eval "$ZFS get $opt $prop ${dataset[i]} > \
+                           $TESTDIR/$TESTFILE0"
+                       ret=$?
+                       if [[ $ret != 0 ]]; then
+                               log_fail "$ZFS get returned: $ret"
+                       fi
+                       check_return_value ${dataset[i]} "$prop" "$opt"
+               done
+       done
+       ((i += 1))
+done
+
+log_pass "Setting the valid options to dataset, it should succeed and return " \
+    "valid value. 'zfs get' pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_002_pos.ksh
new file mode 100755 (executable)
index 0000000..d425a26
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting the valid option and properties 'zfs get' return correct value.
+# It should be successful.
+#
+# STRATEGY:
+# 1. Create pool, filesystem, dataset, volume and snapshot.
+# 2. Getting the options and properties random combination.
+# 3. Using the combination as the parameters of 'zfs get' to check the
+# command line return value.
+#
+
+verify_runnable "both"
+
+typeset options=(" " p r H)
+
+typeset zfs_props=("type" used available creation volsize referenced \
+    compressratio mounted origin recordsize quota reservation mountpoint \
+    sharenfs checksum compression atime devices exec readonly setuid zoned \
+    snapdir acltype aclinherit canmount primarycache secondarycache \
+    usedbychildren usedbydataset usedbyrefreservation usedbysnapshots version)
+
+typeset userquota_props=(userquota@root groupquota@root userused@root \
+    groupused@root)
+typeset props=("${zfs_props[@]}" "${userquota_props[@]}")
+typeset dataset=($TESTPOOL/$TESTCTR $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTVOL@$TESTSNAP)
+
+log_assert "Setting the valid options and properties 'zfs get' return " \
+    "correct value. It should be successful."
+log_onexit cleanup
+
+# Create volume and filesystem's snapshot
+create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
+create_snapshot $TESTPOOL/$TESTVOL $TESTSNAP
+
+#
+# Begin to test 'get [-prH] <property[,property]...>
+#              <filesystem|dataset|volume|snapshot>'
+#              'get [-prH] <-a|-d> <filesystem|dataset|volume|snapshot>"
+#
+typeset -i opt_numb=8
+typeset -i prop_numb=20
+for dst in ${dataset[@]}; do
+       # option can be empty, so "" is necessary.
+       for opt in "" $(gen_option_str "${options[*]}" "-" "" $opt_numb); do
+               for prop in $(gen_option_str "${props[*]}" "" "," $prop_numb)
+               do
+                       $ZFS get $opt $prop $dst > /dev/null 2>&1
+                       ret=$?
+                       if [[ $ret != 0 ]]; then
+                               log_fail "$ZFS get $opt $prop $dst (Code: $ret)"
+                       fi
+               done
+       done
+done
+
+log_pass "Setting the valid options to dataset, 'zfs get' pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_003_pos.ksh
new file mode 100755 (executable)
index 0000000..77a58e1
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs get' should get consistent report with different options.
+#
+# STRATEGY:
+#      1. Create pool and filesystem.
+#      2. 'zfs mount -o remount,noatime <fs>.'
+#      3. Verify the value of 'zfs get atime' and 'zfs get all | grep atime'
+#         are identical.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS mount -o remount,atime $TESTPOOL/$TESTFS
+}
+
+log_assert "'zfs get' should get consistent report with different option."
+log_onexit cleanup
+
+log_must $ZFS set atime=on $TESTPOOL/$TESTFS
+log_must $ZFS mount -o remount,noatime $TESTPOOL/$TESTFS
+
+value1=$($ZFS get -H atime $TESTPOOL/$TESTFS | $AWK '{print $3}')
+value2=$($ZFS get -H all $TESTPOOL/$TESTFS | $AWK '{print $2 " " $3}' | \
+       $GREP ^atime | $AWK '{print $2}')
+if [[ $value1 != $value2 ]]; then
+       log_fail "value1($value1) != value2($value2)"
+fi
+
+log_pass "'zfs get'  get consistent report with different option passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_004_pos.ksh
new file mode 100755 (executable)
index 0000000..1dce6e9
--- /dev/null
@@ -0,0 +1,227 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify 'zfs get all' can get all properties for all datasets in the system
+#
+# STRATEGY:
+#      1. Create datasets for testing
+#      2. Issue 'zfs get all' command
+#      3. Verify the command gets all available properties of all datasets
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       [[ -e $propfile ]] && $RM -f $propfile
+
+       datasetexists $clone  && \
+               log_must $ZFS destroy $clone
+       for snap in $fssnap $volsnap ; do
+               snapexists $snap && \
+                       log_must $ZFS destroy $snap
+       done
+
+       if [[ -n $globalzone ]] ; then
+               for pool in $TESTPOOL1 $TESTPOOL2 $TESTPOOL3; do
+                       poolexists $pool && \
+                               log_must $ZPOOL destroy -f $pool
+               done
+               for file in `$LS $TESTDIR1/poolfile*`; do
+                       $RM -f $file
+               done
+       else
+               for fs in $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS2 $TESTPOOL/$TESTFS3; do
+                       datasetexists $fs && \
+                               log_must $ZFS destroy -rf $fs
+               done
+       fi
+}
+
+log_assert "Verify the functions of 'zfs get all' work."
+log_onexit cleanup
+
+typeset globalzone=""
+
+if is_global_zone ; then
+       globalzone="true"
+fi
+
+set -A opts "" "-r" "-H" "-p" "-rHp" "-o name" \
+       "-s local,default,temporary,inherited,none" \
+       "-o name -s local,default,temporary,inherited,none" \
+       "-rHp -o name -s local,default,temporary,inherited,none"
+set -A usrprops "a:b=c" "d_1:1_e=0f" "123:456=789"
+
+fs=$TESTPOOL/$TESTFS
+fssnap=$fs@$TESTSNAP
+clone=$TESTPOOL/$TESTCLONE
+volsnap=$TESTPOOL/$TESTVOL@$TESTSNAP
+
+#set user defined properties for $TESTPOOL
+for usrprop in ${usrprops[@]}; do
+       log_must $ZFS set $usrprop $TESTPOOL
+done
+# create snapshot and clone in $TESTPOOL
+log_must $ZFS snapshot $fssnap
+log_must $ZFS clone $fssnap $clone
+log_must $ZFS snapshot $volsnap
+
+# collect datasets which can be set user defined properties
+usrpropds="$clone $fs"
+
+# collect all datasets which we are creating
+allds="$fs $clone $fssnap $volsnap"
+
+#create pool and datasets to guarantee testing under multiple pools and datasets.
+file=$TESTDIR1/poolfile
+typeset -i FILESIZE=104857600    #100M
+(( DFILESIZE = FILESIZE * 2 ))   # double of FILESIZE
+typeset -i VOLSIZE=10485760      #10M
+availspace=$(get_prop available $TESTPOOL)
+typeset -i i=0
+
+# make sure 'availspace' is larger then twice of FILESIZE to create a new pool.
+# If any, we only totally create 3 pools for multple datasets testing to limit
+# testing time
+while (( availspace > DFILESIZE )) && (( i < 3 )) ; do
+       (( i += 1 ))
+
+       if [[ -n $globalzone ]] ; then
+               log_must $MKFILE $FILESIZE ${file}$i
+               eval pool=\$TESTPOOL$i
+               log_must $ZPOOL create $pool ${file}$i
+       else
+               eval pool=$TESTPOOL/\$TESTFS$i
+               log_must $ZFS create $pool
+       fi
+
+       #set user defined properties for testing
+       for usrprop in ${usrprops[@]}; do
+               log_must $ZFS set $usrprop $pool
+       done
+
+       #create datasets in pool
+       log_must $ZFS create $pool/$TESTFS
+       log_must $ZFS snapshot $pool/$TESTFS@$TESTSNAP
+       log_must $ZFS clone $pool/$TESTFS@$TESTSNAP $pool/$TESTCLONE
+
+       if [[ -n $globalzone ]] ; then
+               log_must $ZFS create -V $VOLSIZE $pool/$TESTVOL
+       else
+               log_must $ZFS create $pool/$TESTVOL
+       fi
+
+       ds=`$ZFS list -H -r -o name -t filesystem,volume $pool`
+       usrpropds="$usrpropds $pool/$TESTFS $pool/$TESTCLONE $pool/$TESTVOL"
+       allds="$allds $pool/$TESTFS $pool/$TESTCLONE $pool/$TESTVOL \
+               $pool/$TESTFS@$TESTSNAP"
+
+       availspace=$(get_prop available $TESTPOOL)
+done
+
+#the expected number of property for each type of dataset in this testing
+typeset -i fspropnum=27
+typeset -i snappropnum=8
+typeset -i volpropnum=15
+propfile=/var/tmp/allpropfile.$$
+
+typeset -i i=0
+typeset -i propnum=0
+typeset -i failflag=0
+while (( i < ${#opts[*]} )); do
+       [[ -e $propfile ]] && $RM -f $propfile
+       log_must eval "$ZFS get ${opts[i]} all >$propfile"
+
+       for ds in $allds; do
+               $GREP $ds $propfile >/dev/null 2>&1
+               (( $? != 0 )) && \
+                       log_fail "There is no property for" \
+                               "dataset $ds in 'get all' output."
+
+               propnum=`$CAT $propfile | $AWK '{print $1}' | \
+                       $GREP "${ds}$" | $WC -l`
+               ds_type=`$ZFS get -H -o value type $ds`
+               case $ds_type in
+                       filesystem )
+                               (( propnum < fspropnum )) && \
+                               (( failflag += 1 ))
+                               ;;
+                       snapshot )
+                               (( propnum < snappropnum )) && \
+                               (( failflag += 1 ))
+                               ;;
+                       volume )
+                               (( propnum < volpropnum )) && \
+                               (( failflag += 1 ))
+                               ;;
+               esac
+
+               (( failflag != 0 )) && \
+                       log_fail " 'zfs get all' fails to get out " \
+                               "all properties for dataset $ds."
+
+               (( propnum = 0 ))
+               (( failflag = 0 ))
+       done
+
+       (( i += 1 ))
+done
+
+log_note "'zfs get' can get particular property for all datasets with that property."
+
+function do_particular_prop_test #<property> <suitable datasets>
+{
+       typeset props="$1"
+       typeset ds="$2"
+
+       for prop in ${commprops[*]}; do
+               ds=`$ZFS get -H -o name $prop`
+
+               [[ "$ds" != "$allds" ]] && \
+                       log_fail "The result datasets are $ds, but all suitable" \
+                               "datasets are $allds for the property $prop"
+       done
+}
+
+# Here, we do a testing for user defined properties and the most common properties
+# for all datasets.
+commprop="type creation used referenced compressratio"
+usrprop="a:b d_1:1_e 123:456"
+
+do_particular_prop_test "$commprop" "$allds"
+do_particular_prop_test "$usrprop" "$usrpropds"
+
+log_pass "'zfs get all' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_005_neg.ksh
new file mode 100755 (executable)
index 0000000..c77f769
--- /dev/null
@@ -0,0 +1,112 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting the invalid option and properties, 'zfs get' should failed.
+#
+# STRATEGY:
+# 1. Create pool, filesystem, volume and snapshot.
+# 2. Getting incorrect combination by invalid parameters
+# 3. Using the combination as the parameters of 'zfs get' to check the
+# command line return value.
+#
+
+verify_runnable "both"
+
+typeset val_opts=(p r H)
+typeset v_props=(type used available creation volsize referenced compressratio \
+    mounted origin recordsize quota reservation mountpoint sharenfs checksum \
+    compression atime devices exec readonly setuid zoned snapdir acltype \
+    aclinherit canmount primarycache secondarycache \
+    usedbychildren usedbydataset usedbyrefreservation usedbysnapshots version)
+
+typeset  userquota_props=(userquota@root groupquota@root userused@root \
+    groupused@root)
+typeset val_pros=(-- "${v_props[@]}" "${userquota_props[@]}")
+set -f # Force shell does not parse '?' and '*' as the wildcard
+typeset inval_opts=(P R h ? *)
+typeset inval_props=(Type 0 ? * -on --on readonl time USED RATIO MOUNTED)
+
+typeset dataset=($TESTPOOL/$TESTFS $TESTPOOL/$TESTCTR $TESTPOOL/$TESTVOL \
+    $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTVOL@$TESTSNAP)
+
+typeset -i opt_numb=6
+typeset -i prop_numb=12
+
+val_opts_str=$(gen_option_str "${val_opts[*]}" "-" "" $opt_numb)
+val_props_str=$(gen_option_str "${val_props[*]}" "" "," $prop_numb)
+val_props_str="$val_props_str -a -d"
+
+inval_opts_str=$(gen_option_str "${inval_opts[*]}" "-" "" $opt_numb)
+inval_props_str=$(gen_option_str "${inval_props[*]}" "" "," $prop_numb)
+
+#
+# Test different options and properties combination.
+#
+# $1 options
+# $2 properties
+#
+function test_options
+{
+       typeset opts=$1
+       typeset props=$2
+
+       for dst in ${dataset[@]}; do
+               for opt in $opts; do
+                       for prop in $props; do
+                               $ZFS get $opt $prop $dst > /dev/null 2>&1
+                               ret=$?
+                               if [[ $ret == 0 ]]; then
+                                       log_fail "$ZFS get $opt $prop $dst " \
+                                           "unexpectedly succeeded."
+                               fi
+                       done
+               done
+       done
+}
+
+log_assert "Setting the invalid option and properties, 'zfs get' should be \
+    failed."
+log_onexit cleanup
+
+# Create filesystem and volume's snapshot
+create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
+create_snapshot $TESTPOOL/$TESTVOL $TESTSNAP
+
+log_note "Valid options + invalid properties, 'zfs get' should fail."
+test_options "$val_opts_str" "$inval_props_str"
+
+log_note "Invalid options + valid properties, 'zfs get' should fail."
+test_options "$inval_opts_str" "$val_props_str"
+
+log_note "Invalid options + invalid properties, 'zfs get' should fail."
+test_options "$inval_opts_str" "$inval_props_str"
+
+log_pass "Setting the invalid options to dataset, 'zfs get' pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_006_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_006_neg.ksh
new file mode 100755 (executable)
index 0000000..58b0826
--- /dev/null
@@ -0,0 +1,60 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
+
+#
+# DESCRIPTION:
+# Verify 'zfs get all' can deal with invalid scenarios
+#
+# STRATEGY:
+# 1. Define invalid scenarios for 'zfs get all'
+# 2. Run zfs get with those invalid scenarios
+# 3. Verify that zfs get fails with invalid scenarios
+#
+
+verify_runnable "both"
+
+log_assert "Verify 'zfs get all' fails with invalid combination scenarios."
+
+set -f # Force ksh ignore '?' and '*'
+set -A  bad_combine "ALL" "\-R all" "-P all" "-h all" "-rph all" "-RpH all" "-PrH all" \
+               "-o all" "-s all" "-? all" "-* all" "-?* all" "all -r" "all -p" \
+               "all -H" "all -rp" "all -rH" "all -ph" "all -rpH" "all -r $TESTPOOL" \
+               "all -H $TESTPOOL" "all -p $TESTPOOL" "all -r -p -H $TESTPOOL" \
+               "all -rph $TESTPOOL" "all,available,reservation $TESTPOOL" \
+               "all $TESTPOOL?" "all $TESTPOOL*" "all nonexistpool"
+
+typeset -i i=0
+while (( i < ${#bad_combine[*]} ))
+do
+       log_mustnot eval "$ZFS get ${bad_combine[i]} >/dev/null"
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs get all' fails with invalid combinations scenarios as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_007_neg.ksh
new file mode 100755 (executable)
index 0000000..850c1ca
--- /dev/null
@@ -0,0 +1,60 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs get -o' should fail with invalid column names
+#
+# STRATEGY:
+# 1. Run zfs get -o with invalid column name combinations
+# 2. Verify that zfs get returns error
+#
+
+verify_runnable "both"
+
+log_assert "'zfs get -o' fails with invalid options or column names"
+
+set -A  badargs "o name,property,value,resource" "o name" \
+       "-O name,property,value,source" "-oo name" "-o blah" \
+       "-o name,property,blah,source" "-o name,name,name,name,name" \
+       "-o name,property,value,," "-o *,*,*,*" "-o ?,?,?,?" \
+       "-o" "-o ,,,,," "-o -o -o -o" "-o NAME,PROPERTY,VALUE,SOURCE" \
+       "-o name,properTy,value,source" "-o name, property, value,source" \
+       "-o name:property:value:source" "-o name,property:value,source" \
+       "-o name;property;value;source"
+
+typeset -i i=0
+while (( i < ${#badargs[*]} ))
+do
+       log_mustnot eval "$ZFS get \"${badargs[i]}\" >/dev/null 2>&1"
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs get -o' fails with invalid options or column name as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_008_pos.ksh
new file mode 100755 (executable)
index 0000000..af1b568
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+
+#
+# DESCRIPTION:
+# Verify "-d <n>" can work with other options
+#
+# STRATEGY:
+# 1. Create pool, filesystem, dataset, volume and snapshot.
+# 2. Getting an -d option, other options and properties random combination.
+# 3. Using the combination as the parameters of 'zfs get' to check the
+# command line return value.
+#
+
+verify_runnable "both"
+
+set -A options " " "-r" "-H" "-p" "-rHp" "-o name" \
+       "-s local,default,temporary,inherited,none" \
+       "-o name -s local,default,temporary,inherited,none" \
+       "-rHp -o name -s local,default,temporary,inherited,none"
+
+set -A props type used available creation volsize referenced compressratio \
+       mounted origin recordsize quota reservation mountpoint sharenfs \
+       checksum compression atime devices exec readonly setuid zoned snapdir \
+       acltype aclinherit canmount primarycache secondarycache \
+       usedbychildren usedbydataset usedbyrefreservation usedbysnapshots \
+       userquota@root groupquota@root userused@root groupused@root
+
+$ZFS upgrade -v > /dev/null 2>&1
+if [[ $? -eq 0 ]]; then
+       set -A all_props ${all_props[*]} version
+fi
+
+set -A dataset $TESTPOOL/$TESTCTR $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTVOL@$TESTSNAP
+
+log_assert "Verify '-d <n>' can work with other options"
+log_onexit cleanup
+
+# Create volume and filesystem's snapshot
+create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
+create_snapshot $TESTPOOL/$TESTVOL $TESTSNAP
+
+typeset -i opt_numb=16
+typeset -i prop_numb=16
+typeset -i i=0
+typeset -i item=0
+typeset -i depth_item=0
+
+for dst in ${dataset[@]}; do
+       (( i=0 ))
+       while (( i < opt_numb )); do
+               (( item = $RANDOM % ${#options[@]} ))
+               (( depth_item = $RANDOM % ${#depth_options[@]} ))
+               for prop in $(gen_option_str "${props[*]}" "" "," $prop_numb)
+               do
+                       log_must eval "$ZFS get -${depth_options[depth_item]} ${options[item]} $prop $dst > /dev/null 2>&1"
+               done
+               (( i += 1 ))
+       done
+done
+
+log_pass "Verify '-d <n>' can work with other options"
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_009_pos.ksh
new file mode 100755 (executable)
index 0000000..11eadaa
--- /dev/null
@@ -0,0 +1,83 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+
+#
+# DESCRIPTION:
+#      'zfs get -d <n>' should get expected output.
+#
+# STRATEGY:
+#      1. Create a multiple depth filesystem.
+#      2. 'zfs get -d <n>' to get the output.
+#      3. 'zfs get -r|egrep' to get the expected output.
+#      4. Compare the two outputs, they shoud be same.
+#
+
+verify_runnable "both"
+
+log_assert "'zfs get -d <n>' should get expected output."
+log_onexit depth_fs_cleanup
+
+set -A all_props type used available creation volsize referenced \
+       compressratio mounted origin recordsize quota reservation mountpoint \
+       sharenfs checksum compression atime devices exec readonly setuid \
+       zoned snapdir acltype aclinherit canmount primarycache secondarycache \
+       usedbychildren usedbydataset usedbyrefreservation usedbysnapshots \
+       userquota@root groupquota@root userused@root groupused@root
+
+$ZFS upgrade -v > /dev/null 2>&1
+if [[ $? -eq 0 ]]; then
+       set -A all_props ${all_props[*]} version
+fi
+
+depth_fs_setup
+
+mntpnt=$(get_prop mountpoint $DEPTH_FS)
+DEPTH_OUTPUT="$mntpnt/depth_output"
+EXPECT_OUTPUT="$mntpnt/expect_output"
+typeset -i prop_numb=16
+typeset -i old_val=0
+typeset -i j=0
+typeset eg_opt="$DEPTH_FS"$
+for dp in ${depth_array[@]}; do
+       (( j=old_val+1 ))
+       while (( j<=dp && j<=MAX_DEPTH )); do
+               eg_opt="$eg_opt""|depth""$j"$
+               (( j+=1 ))
+       done
+       for prop in $(gen_option_str "${all_props[*]}" "" "," $prop_numb); do
+               log_must eval "$ZFS get -H -d $dp -o name $prop $DEPTH_FS > $DEPTH_OUTPUT"
+               log_must eval "$ZFS get -rH -o name $prop $DEPTH_FS | $EGREP -e '$eg_opt' > $EXPECT_OUTPUT"
+               log_must $DIFF $DEPTH_OUTPUT $EXPECT_OUTPUT
+       done
+       (( old_val=dp ))
+done
+
+log_pass "'zfs get -d <n>' should get expected output."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_010_neg.ksh
new file mode 100755 (executable)
index 0000000..e8c3607
--- /dev/null
@@ -0,0 +1,55 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+
+#
+# DESCRIPTION:
+# A negative depth or a non numeric depth should fail in 'zfs get -d <n>'
+#
+# STRATEGY:
+# 1. Run zfs get -d with negative depth or non numeric depth
+# 2. Verify that zfs get returns error
+#
+
+verify_runnable "both"
+
+log_assert "A negative depth or a non numeric depth should fail in 'zfs get -d <n>'"
+
+set -A  badargs "a" "AB" "aBc" "2A" "a2b" "aB2" "-1" "-32" "-999"
+
+typeset -i i=0
+while (( i < ${#badargs[*]} ))
+do
+       log_mustnot eval "$ZFS get -d ${badargs[i]} $TESTPOOL/$TESTFS >/dev/null 2>&1"
+       (( i = i + 1 ))
+done
+
+log_pass "A negative depth or a non numeric depth should fail in 'zfs get -d <n>'"
+
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_common.kshlib
new file mode 100644 (file)
index 0000000..b1978cb
--- /dev/null
@@ -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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# According to $elements, $prefix and $separator, the function random produce
+# the number of $counter combination.
+#
+# $1 elements which is used to get the combination.
+# $2 prefix is appended to the combination
+# $3 separator between the combination, such as ' ' or ','
+# $4 counter is the number of combination which you want to get.
+#
+function gen_option_str # $elements $prefix $separator $counter
+{
+       typeset elements=""
+       typeset prefix=${2}
+       typeset separator=${3}
+       typeset -i counter=${4:-0}
+       typeset -i i=0
+       typeset comb_str=""
+
+       for e in $1; do
+               elements[i]="$e"
+               (( i += 1 ))
+       done
+       (( ${#elements[@]} == 0 )) && log_fail "The elements can't be empty."
+
+       typeset -i item=0
+       typeset -i j=0
+       typeset -i numb_item=0
+
+       # Loop and get the specified number combination strings.
+       i=0
+       while (( i < counter )); do
+               j=0
+               numb_item=0
+               comb_str=""
+
+               # Get random number items for each combinations.
+               (( numb_item = ($RANDOM % ${#elements[@]}) + 1 ))
+
+               while (( j < numb_item )); do
+                       # Random select elements from the array
+                       (( item = $RANDOM % ${#elements[@]} ))
+
+                       if (( ${#comb_str} == 0 )); then
+                               comb_str=${elements[item]}
+                       else
+                               comb_str=$comb_str$separator${elements[item]}
+                       fi
+                       (( j += 1 ))
+               done
+
+               echo "$prefix$comb_str"
+
+               (( i += 1 ))
+       done
+}
+
+#
+# Cleanup the volume snapshot and filesystem snapshot were created for
+# this test case.
+#
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTVOL@$TESTSNAP && \
+               destroy_snapshot $TESTPOOL/$TESTVOL@$TESTSNAP
+       datasetexists $TESTPOOL/$TESTFS@$TESTSNAP && \
+               destroy_snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+
+       [[ -e $TESTFILE0 ]] && log_must $RM $TESTFILE0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
new file mode 100644 (file)
index 0000000..874cfa3
--- /dev/null
@@ -0,0 +1,79 @@
+#
+# 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/include/libtest.shlib
+
+DEPTH_FS=$TESTPOOL/depth_fs
+MAX_DEPTH=3
+DS_COUNT=3
+set -A depth_options  "d 0" "d 1" "d 2" "d 4" "d 32"
+set -A depth_array  0 1 2 4 32
+
+#
+# Setup multiple depths datasets, including fs, volume and snapshot.
+#
+function depth_fs_setup
+{
+       typeset -i i j k
+       typeset fslist
+
+       log_must $ZFS create $DEPTH_FS
+
+       (( i=1 ))
+       while (( i<=MAX_DEPTH )); do
+               if (( i==1 )); then
+                       fslist=$DEPTH_FS
+               else
+                       (( k=i-1 ))
+                       fslist=$($ZFS list -rH -t filesystem -o name $DEPTH_FS|$GREP depth"$k"$)
+                       if (( $? != 0 )); then
+                               log_fail "No depth$k filesystem"
+                       fi
+               fi
+               for fs in $fslist; do
+                       (( j=1 ))
+                       while (( j<=DS_COUNT )); do
+                               log_must $ZFS create $fs/fs_"$j"_depth"$i"
+                               if is_global_zone ; then
+                                       log_must $ZFS create -V 8M $fs/vol_"$j"_depth"$i"
+                               fi
+                               log_must $ZFS snapshot $fs@snap_"$j"_depth"$i"
+                               (( j=j+1 ))
+                       done
+               done
+               (( i=i+1 ))
+       done
+}
+
+#
+# Cleanup multiple depths filesystem.
+#
+function depth_fs_cleanup
+{
+       log_must $ZFS destroy -rR $DEPTH_FS
+}
+
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/Makefile.am
new file mode 100644 (file)
index 0000000..104ee06
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_inherit
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       zfs_inherit_001_neg.ksh \
+       zfs_inherit_002_neg.ksh \
+       zfs_inherit_003_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/setup.ksh
new file mode 100755 (executable)
index 0000000..9692385
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_container_volume_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_001_neg.ksh
new file mode 100755 (executable)
index 0000000..891e0e9
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# 'zfs inherit' should return an error when attempting to inherit
+# properties which are not inheritable.
+#
+# STRATEGY:
+# 1. Create an array of properties which cannot be inherited
+# 2. For each property in the array, execute 'zfs inherit'
+# 3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+# Define uninherited properties and their short name.
+typeset props_str="type used available avail creation referenced refer \
+               compressratio ratio mounted origin quota reservation \
+               reserv volsize volblocksize volblock"
+
+$ZFS upgrade -v > /dev/null 2>&1
+if [[ $? -eq 0 ]]; then
+       props_str="$props_str version"
+fi
+
+set -A prop $props_str canmount
+
+
+log_assert "'zfs inherit' should return an error when attempting to inherit" \
+       " un-inheritable properties."
+
+typeset -i i=0
+for obj in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL; do
+       i=0
+       while [[ $i -lt ${#prop[*]} ]]; do
+               orig_val=$(get_prop ${prop[i]} $obj)
+
+               log_mustnot $ZFS inherit ${prop[i]} $obj
+
+               new_val=$(get_prop ${prop[i]} $obj)
+
+               if [[ $new_val != $orig_val ]]; then
+                       log_fail "${prop[i]} property changed from $orig_val "
+                               " to $new_val"
+               fi
+               ((i = i + 1))
+       done
+done
+
+log_pass "'zfs inherit' failed as expected when attempting to inherit" \
+       " un-inheritable properties."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_002_neg.ksh
new file mode 100755 (executable)
index 0000000..3fefa31
--- /dev/null
@@ -0,0 +1,102 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2011 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# 'zfs inherit' should return an error with bad parameters in one command.
+#
+# STRATEGY:
+# 1. Set an array of bad options and invlid properties to 'zfs inherit'
+# 2. Execute 'zfs inherit' with bad options and passing invlid properties
+# 3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists $TESTPOOL/$TESTFS@$TESTSNAP; then
+               log_must $ZFS destroy $TESTPOOL/$TESTFS@$TESTSNAP
+       fi
+}
+
+log_assert "'zfs inherit' should return an error with bad parameters in" \
+    "one command."
+log_onexit cleanup
+
+set -A badopts "r" "R" "-R" "-rR" "-a" "-" "-?" "-1" "-2" "-v" "-n"
+set -A props "recordsize" "mountpoint" "sharenfs" "checksum" "compression" \
+    "atime" "devices" "exec" "setuid" "readonly" "zoned" "snapdir" "aclmode" \
+    "aclinherit" "xattr" "copies"
+set -A illprops "recordsiz" "mountpont" "sharen" "compres" "atme" "blah"
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+
+typeset -i i=0
+for ds in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTFS@$TESTSNAP; do
+
+       # zfs inherit should fail with bad options
+       for opt in ${badopts[@]}; do
+               for prop in ${props[@]}; do
+                       log_mustnot eval "$ZFS inherit $opt $prop $ds \
+                           >/dev/null 2>&1"
+               done
+       done
+
+       # zfs inherit should fail with invalid properties
+       for prop in "${illprops[@]}"; do
+               log_mustnot eval "$ZFS inherit $prop $ds >/dev/null 2>&1"
+               log_mustnot eval "$ZFS inherit -r $prop $ds >/dev/null 2>&1"
+       done
+
+       # zfs inherit should fail with too many arguments
+       (( i = 0 ))
+       while (( i < ${#props[*]} -1 )); do
+               log_mustnot eval "$ZFS inherit ${props[(( i ))]} \
+                               ${props[(( i + 1 ))]} $ds >/dev/null 2>&1"
+               log_mustnot eval "$ZFS inherit -r ${props[(( i ))]} \
+                               ${props[(( i + 1 ))]} $ds >/dev/null 2>&1"
+
+               (( i = i + 2 ))
+       done
+
+done
+
+# zfs inherit should fail with missing datasets
+for prop in ${props[@]}; do
+       log_mustnot eval "$ZFS inherit $prop >/dev/null 2>&1"
+       log_mustnot eval "$ZFS inherit -r $prop >/dev/null 2>&1"
+done
+
+log_pass "'zfs inherit' failed as expected when passing illegal arguments."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_inherit/zfs_inherit_003_pos.ksh
new file mode 100755 (executable)
index 0000000..b2f09db
--- /dev/null
@@ -0,0 +1,86 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs inherit' should return an error with bad parameters in one command.
+#
+# STRATEGY:
+# 1. Set an array of bad options and invlid properties to 'zfs inherit'
+# 2. Execute 'zfs inherit' with bad options and passing invlid properties
+# 3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for ds in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL ; do
+               if snapexists $ds@$TESTSNAP; then
+                       log_must $ZFS destroy $ds@$TESTSNAP
+               fi
+       done
+       cleanup_user_prop $TESTPOOL
+}
+
+log_assert "'zfs inherit' should inherit user property."
+log_onexit cleanup
+
+for ds in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL ; do
+        typeset prop_name=$(valid_user_property 10)
+        typeset value=$(user_property_value 16)
+
+       log_must eval "$ZFS set $prop_name='$value' $ds"
+
+       log_must $ZFS snapshot $ds@$TESTSNAP
+
+       typeset snapvalue=$(get_prop $prop_name $ds@$TESTSNAP)
+
+       if [[ "$snapvalue" != "$value" ]] ; then
+               log_fail "The '$ds@$TESTSNAP '$prop_name' value '$snapvalue' " \
+                       "not equal to the expected value '$value'."
+       fi
+
+       snapvalue=$(user_property_value 16)
+       log_must eval "$ZFS set $prop_name='$snapvalue' $ds@$TESTSNAP"
+
+       log_must $ZFS inherit $prop_name $ds@$TESTSNAP
+
+       snapvalue=$(get_prop $prop_name $ds@$TESTSNAP)
+
+       if [[ "$snapvalue" != "$value" ]] ; then
+               log_fail "The '$ds@$TESTSNAP '$prop_name' value '$snapvalue' " \
+                       "not equal to the expected value '$value'."
+       fi
+
+
+done
+
+log_pass "'zfs inherit' inherit user property."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am
new file mode 100644 (file)
index 0000000..c6ae99c
--- /dev/null
@@ -0,0 +1,18 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_mount
+dist_pkgdata_SCRIPTS = \
+       zfs_mount.cfg \
+       zfs_mount.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_mount_001_pos.ksh \
+       zfs_mount_002_pos.ksh \
+       zfs_mount_003_pos.ksh \
+       zfs_mount_004_pos.ksh  \
+       zfs_mount_005_pos.ksh \
+       zfs_mount_006_pos.ksh \
+       zfs_mount_007_pos.ksh \
+       zfs_mount_008_pos.ksh \
+       zfs_mount_009_neg.ksh \
+       zfs_mount_010_neg.ksh \
+       zfs_mount_011_neg.ksh \
+       zfs_mount_all_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount.cfg
new file mode 100644 (file)
index 0000000..c8e4689
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+
+export mountcmd=mount
+export mountforce="$mountcmd -f"
+export mountall="$mountcmd -a"
+
+export unmountcmd=unmount
+export unmountforce="$unmountcmd -f"
+export unmountall="$unmountcmd -a"
+
+export NONEXISTFSNAME="nonexistfs50charslong_0123456789012345678901234567"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
new file mode 100644 (file)
index 0000000..2f6194e
--- /dev/null
@@ -0,0 +1,132 @@
+#
+# 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/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.cfg
+
+function force_unmount #dev
+{
+       typeset dev=$1
+
+       ismounted $dev
+       if (( $? == 0 )); then
+               log_must $ZFS $unmountforce $dev
+       fi
+       return 0
+}
+
+# Create pool and  ( fs | container | vol ) with the given parameters,
+# it'll destroy prior exist one that has the same name.
+
+function setup_filesystem #disklist #pool #fs #mntpoint #type #vdev
+{
+       typeset disklist=$1
+       typeset pool=$2
+       typeset fs=${3##/}
+       typeset mntpoint=$4
+       typeset type=$5
+       typeset vdev=$6
+
+       if [[ -z $pool || -z $fs || -z $mntpoint ]]; then
+               log_note "Missing parameter: (\"$pool\", \"$fs\", \"$mntpoint\")"
+               return 1
+       fi
+
+       if is_global_zone && [[ -z $disklist ]] ; then
+               log_note "Missing disklist."
+               return 1
+       fi
+
+       if [[ $vdev != "" && \
+               $vdev != "mirror" && \
+               $vdev != "raidz" ]] ; then
+
+               log_note "Wrong vdev: (\"$vdev\")"
+               return 1
+       fi
+
+       poolexists $pool || \
+               create_pool $pool $vdev $disklist
+
+       datasetexists $pool/$fs && \
+               log_must cleanup_filesystem $pool $fs
+
+       $RMDIR $mntpoint > /dev/null 2>&1
+       if [[ ! -d $mntpoint ]]; then
+               log_must $MKDIR -p $mntpoint
+       fi
+
+       case "$type" in
+               'ctr')  log_must $ZFS create $pool/$fs
+                       log_must $ZFS set mountpoint=$mntpoint $pool/$fs
+                       ;;
+               'vol')  log_must $ZFS create -V $VOLSIZE $pool/$fs
+                       block_device_wait
+                       ;;
+               *)      log_must $ZFS create $pool/$fs
+                       log_must $ZFS set mountpoint=$mntpoint $pool/$fs
+                       ;;
+       esac
+
+       return 0
+}
+
+# Destroy ( fs | container | vol ) with the given parameters.
+function cleanup_filesystem #pool #fs
+{
+       typeset pool=$1
+       typeset fs=${2##/}
+       typeset mtpt=""
+
+       if [[ -z $pool || -z $fs ]]; then
+               log_note "Missing parameter: (\"$pool\", \"$fs\")"
+               return 1
+       fi
+
+       if datasetexists "$pool/$fs" ; then
+               mtpt=$(get_prop mountpoint "$pool/$fs")
+               log_must $ZFS destroy -r $pool/$fs
+
+               [[ -d $mtpt ]] && \
+                       log_must $RM -rf $mtpt
+       else
+               return 1
+       fi
+
+       return 0
+}
+
+# Make sure 'zfs mount' should display all ZFS filesystems currently mounted.
+# The results of 'zfs mount' and 'df -F zfs' should be identical.
+function verify_mount_display
+{
+       typeset fs
+
+       for fs in $($ZFS $mountcmd | $AWK '{print $1}') ; do
+               log_must mounted $fs
+       done
+       return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_001_pos.ksh
new file mode 100755 (executable)
index 0000000..b474dc8
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+# Invoke "zfs mount <filesystem>" with a regular name of filesystem,
+# will mount that filesystem successfully.
+#
+# STRATEGY:
+# 1. Make sure that the ZFS filesystem is unmounted.
+# 2. Invoke 'zfs mount <filesystem>'.
+# 3. Verify that the filesystem is mounted.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must force_unmount $TESTPOOL/$TESTFS
+       return 0
+}
+
+log_assert "Verify that '$ZFS $mountcmd <filesystem>' succeeds as root."
+
+log_onexit cleanup
+
+unmounted $TESTPOOL/$TESTFS || \
+       log_must cleanup
+
+log_must $ZFS $mountcmd $TESTPOOL/$TESTFS
+
+log_note "Make sure the filesystem $TESTPOOL/$TESTFS is mounted"
+mounted $TESTPOOL/$TESTFS || \
+       log_fail Filesystem $TESTPOOL/$TESTFS is unmounted
+
+log_pass "'$ZFS $mountcmd <filesystem>' succeeds as root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_002_pos.ksh
new file mode 100755 (executable)
index 0000000..8b39306
--- /dev/null
@@ -0,0 +1,74 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+# Invoking "zfs mount <filesystem>" with a filesystem whose name is not in
+# "zfs list", will fail with a return code of 1.
+#
+# STRATEGY:
+# 1. Make sure the NONEXISTFSNAME ZFS filesystem is not in 'zfs list'.
+# 2. Invoke 'zfs mount <filesystem>'.
+# 3. Verify that mount failed with return code of 1.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset fs
+       for fs in $NONEXISTFSNAME $TESTFS ; do
+               log_must force_unmount $TESTPOOL/$fs
+       done
+}
+
+
+log_assert "Verify that '$ZFS $mountcmd' with a filesystem " \
+       "whose name is not in 'zfs list' will fail with return code 1."
+
+log_onexit cleanup
+
+log_note "Make sure the filesystem $TESTPOOL/$NONEXISTFSNAME " \
+       "is not in 'zfs list'"
+log_mustnot $ZFS list $TESTPOOL/$NONEXISTFSNAME
+
+typeset -i ret=0
+$ZFS $mountcmd $TESTPOOL/$NONEXISTFSNAME
+ret=$?
+(( ret == 1 )) || \
+       log_fail "'$ZFS $mountcmd $TESTPOOL/$NONEXISTFSNAME' " \
+               "unexpected return code of $ret."
+
+log_note "Make sure the filesystem $TESTPOOL/$NONEXISTFSNAME is unmounted"
+unmounted $TESTPOOL/$NONEXISTFSNAME || \
+       log_fail Filesystem $TESTPOOL/$NONEXISTFSNAME is mounted
+
+log_pass "'$ZFS $mountcmd' with a filesystem " \
+       "whose name is not in 'zfs list' failed with return code 1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_003_pos.ksh
new file mode 100755 (executable)
index 0000000..2dd14da
--- /dev/null
@@ -0,0 +1,86 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+# Invoke "zfs mount <filesystem>" with a filesystem whose mountpoint property
+# is 'legacy' or 'none',
+# it will fail with a return code of 1 and issue an error message.
+#
+# STRATEGY:
+# 1. Make sure that the ZFS filesystem is unmounted.
+# 2. Mount the filesystem using the various combinations
+#      - zfs set mountpoint=legacy <filesystem>
+#      - zfs set mountpoint=none <filesystem>
+# 3. Verify that mount failed with return code of 1.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+       log_must force_unmount $TESTPOOL/$TESTFS
+       return 0
+}
+
+log_assert "Verify that '$ZFS $mountcmd' with a filesystem " \
+       "whose mountpoint property is 'legacy' or 'none' " \
+       "will fail with return code 1."
+
+log_onexit cleanup
+
+set -A mopt "legacy" "none"
+
+typeset -i ret=0
+typeset -i i=0
+
+while (( i < ${#mopt[*]} )); do
+       unmounted $TESTPOOL/$TESTFS || \
+               log_must cleanup
+
+       log_must $ZFS set mountpoint=${mopt[i]} $TESTPOOL/$TESTFS
+
+       $ZFS $mountcmd $TESTPOOL/$TESTFS
+       ret=$?
+       (( ret == 1)) || \
+               log_fail "'$ZFS $mountcmd $TESTPOOL/$TESTFS' " \
+                       "unexpected return code of $ret."
+
+       log_note "Make sure the filesystem $TESTPOOL/$TESTFS is unmounted"
+       unmounted $TESTPOOL/$TESTFS || \
+               log_fail Filesystem $TESTPOOL/$TESTFS is mounted
+
+       ((i = i + 1))
+done
+
+log_pass "Verify that '$ZFS $mountcmd' with a filesystem " \
+       "whose mountpoint property is 'legacy' or 'none' " \
+       "will fail with return code 1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_004_pos.ksh
new file mode 100755 (executable)
index 0000000..524aed1
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+# Invoke "zfs mount <filesystem>" with a filesystem
+# which has been already mounted,
+# it will fail with a return code of 1
+#
+# STRATEGY:
+# 1. Make sure that the ZFS filesystem is unmounted.
+# 2. Invoke 'zfs mount <filesystem>'.
+# 3. Verify that the filesystem is mounted.
+# 4. Invoke 'zfs mount <filesystem>' the second times.
+# 5. Verify the last mount operation failed with return code of 1.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must force_unmount $TESTPOOL/$TESTFS
+       return 0
+}
+
+typeset -i ret=0
+
+log_assert "Verify that '$ZFS $mountcmd <filesystem>' " \
+       "with a mounted filesystem will fail with return code 1."
+
+log_onexit cleanup
+
+unmounted $TESTPOOL/$TESTFS || \
+       log_must cleanup
+
+log_must $ZFS $mountcmd $TESTPOOL/$TESTFS
+
+mounted $TESTPOOL/$TESTFS || \
+       log_unresolved "Filesystem $TESTPOOL/$TESTFS is unmounted"
+
+$ZFS $mountcmd $TESTPOOL/$TESTFS
+ret=$?
+(( ret == 1 )) || \
+       log_fail "'$ZFS $mountcmd $TESTPOOL/$TESTFS' " \
+               "unexpected return code of $ret."
+
+log_note "Make sure the filesystem $TESTPOOL/$TESTFS is mounted"
+mounted $TESTPOOL/$TESTFS || \
+       log_fail Filesystem $TESTPOOL/$TESTFS is unmounted
+
+log_pass "'$ZFS $mountcmd <filesystem>' with a mounted filesystem " \
+       "will fail with return code 1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_005_pos.ksh
new file mode 100755 (executable)
index 0000000..7e9f138
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+# Invoke "zfs mount <filesystem>" with a filesystem but its mountpoint
+# is currently in use.  Under Linux this should succeed and is the
+# expected behavior, it will fail with a return code of 1 and issue
+# an error message on other platforms.
+#
+# STRATEGY:
+# 1. Make sure that the ZFS filesystem is unmounted.
+# 2. Apply 'zfs set mountpoint=path <filesystem>'.
+# 3. Change directory to that given mountpoint.
+# 3. Invoke 'zfs mount <filesystem>'.
+# 4. Verify that mount succeeds on Linux and fails for other platforms.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+       log_must force_unmount $TESTPOOL/$TESTFS
+       return 0
+}
+
+typeset -i ret=0
+
+log_assert "Verify that '$ZFS $mountcmd' with a filesystem " \
+       "whose mountpoint is currently in use will fail with return code 1."
+
+log_onexit cleanup
+
+unmounted $TESTPOOL/$TESTFS || \
+       log_must cleanup
+
+[[ -d $TESTDIR ]] || \
+       log_must $MKDIR -p $TESTDIR
+
+cd $TESTDIR || \
+       log_unresolved "Unable change directory to $TESTDIR"
+
+$ZFS $mountcmd $TESTPOOL/$TESTFS
+ret=$?
+if is_linux; then
+    (( ret == 0 )) || \
+        log_fail "'$ZFS $mountcmd $TESTPOOL/$TESTFS' " \
+            "unexpected return code of $ret."
+else
+    (( ret == 1 )) || \
+        log_fail "'$ZFS $mountcmd $TESTPOOL/$TESTFS' " \
+            "unexpected return code of $ret."
+fi
+
+log_note "Make sure the filesystem $TESTPOOL/$TESTFS is unmounted"
+if is_linux; then
+    mounted $TESTPOOL/$TESTFS || \
+        log_fail Filesystem $TESTPOOL/$TESTFS is unmounted
+else
+    unmounted $TESTPOOL/$TESTFS || \
+        log_fail Filesystem $TESTPOOL/$TESTFS is mounted
+fi
+
+log_pass "'$ZFS $mountcmd' with a filesystem " \
+       "whose mountpoint is currently in use failed with return code 1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_006_pos.ksh
new file mode 100755 (executable)
index 0000000..f8b4021
--- /dev/null
@@ -0,0 +1,120 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+#      Invoke "zfs mount <filesystem>" with a filesystem
+#      which mountpoint be the identical or the top of an existing one,
+#      it will fail with a return code of 1
+#
+# STRATEGY:
+#      1. Prepare an existing mounted filesystem.
+#      2. Setup a new filesystem and make sure that it is unmounted.
+#       3. Mount the new filesystem using the various combinations
+#              - zfs set mountpoint=<identical path> <filesystem>
+#              - zfs set mountpoint=<top path> <filesystem>
+#       4. Verify that mount failed with return code of 1.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must force_unmount $TESTPOOL/$TESTFS
+
+       datasetexists $TESTPOOL/$TESTFS1 && \
+               cleanup_filesystem $TESTPOOL $TESTFS1
+
+       [[ -d $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+       log_must force_unmount $TESTPOOL/$TESTFS
+
+       return 0
+}
+
+typeset -i ret=0
+
+log_assert "Verify that '$ZFS $mountcmd <filesystem>' " \
+       "which mountpoint be the identical or the top of an existing one " \
+       "will fail with return code 1."
+
+log_onexit cleanup
+
+unmounted $TESTPOOL/$TESTFS || \
+       log_must force_unmount $TESTPOOL/$TESTFS
+
+[[ -d $TESTDIR ]] && \
+       log_must $RM -rf $TESTDIR
+
+typeset -i MAXDEPTH=3
+typeset -i depth=0
+typeset mtpt=$TESTDIR
+
+while (( depth < MAXDEPTH )); do
+       mtpt=$mtpt/$depth
+       (( depth = depth + 1))
+done
+
+log_must $ZFS set mountpoint=$mtpt $TESTPOOL/$TESTFS
+log_must $ZFS $mountcmd $TESTPOOL/$TESTFS
+
+mounted $TESTPOOL/$TESTFS || \
+       log_unresolved "Filesystem $TESTPOOL/$TESTFS is unmounted"
+
+log_must $ZFS create $TESTPOOL/$TESTFS1
+
+unmounted $TESTPOOL/$TESTFS1 || \
+       log_must force_unmount $TESTPOOL/$TESTFS1
+
+while [[ -n $mtpt ]] ; do
+       (( depth == MAXDEPTH )) && \
+               log_note "Verify that '$ZFS $mountcmd <filesystem>' " \
+               "which mountpoint be the identical of an existing one " \
+               "will fail with return code 1."
+
+       log_must $ZFS set mountpoint=$mtpt $TESTPOOL/$TESTFS1
+       log_mustnot $ZFS $mountcmd $TESTPOOL/$TESTFS1
+
+       unmounted $TESTPOOL/$TESTFS1 || \
+               log_fail "Filesystem $TESTPOOL/$TESTFS1 is mounted."
+
+       mtpt=${mtpt%/*}
+
+       (( depth == MAXDEPTH )) && \
+               log_note "Verify that '$ZFS $mountcmd <filesystem>' " \
+               "which mountpoint be the top of an existing one " \
+               "will fail with return code 1."
+       (( depth = depth - 1 ))
+done
+
+log_pass "'$ZFS $mountcmd <filesystem>' " \
+       "which mountpoint be the identical or the top of an existing one " \
+       "will fail with return code 1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_007_pos.ksh
new file mode 100755 (executable)
index 0000000..577de09
--- /dev/null
@@ -0,0 +1,142 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+# The following options can be set on a temporary basis using the -o option
+# without affecting the on-disk property. The original on-disk value will be
+# restored when the file system is unmounted and mounted.
+#
+#         PROPERTY             MOUNT OPTION
+#        atime                 atime/noatime
+#        devices               devices/nodevices
+#        exec                  exec/noexec
+#        readonly              ro/rw
+#        setuid                setuid/nosetuid
+#
+# STRATEGY:
+#      1. Create filesystem and get origianl property value.
+#      2. Using 'zfs mount -o' to set filesystem property.
+#      3. Verify the property was set temporarily.
+#      4. Verify it will not affect the property that is stored on disk.
+#
+
+function cleanup
+{
+       if ! ismounted $TESTPOOL/$TESTFS; then
+               log_must $ZFS mount $TESTPOOL/$TESTFS
+       fi
+}
+
+log_assert "Verify '-o' will set filesystem property temporarily, " \
+       "without affecting the property that is stored on disk."
+log_onexit cleanup
+
+set -A properties "atime" "devices" "exec" "readonly" "setuid"
+
+#
+# Get the specified filesystem property reverse mount option.
+#
+# $1 filesystem
+# $2 property
+#
+function get_reverse_option
+{
+       typeset fs=$1
+       typeset prop=$2
+
+       # Define property value: "reverse if value=on" "reverse if value=off"
+       set -A values "noatime"   "atime" \
+                     "nodevices" "devices" \
+                     "noexec"    "exec" \
+                     "rw"        "ro" \
+                     "nosetuid"  "setuid"
+
+       typeset -i i=0
+       while (( i < ${#properties[@]} )); do
+               if [[ $prop == ${properties[$i]} ]]; then
+                       break
+               fi
+
+               (( i += 1 ))
+       done
+       if (( i >= ${#properties[@]} )); then
+               log_fail "Incorrect option: $prop"
+       fi
+
+       typeset val
+       typeset -i ind=0
+       val=$(get_prop $prop $fs) || log_fail "get_prop $prop $fs"
+       if [[ $val == "on" ]]; then
+               (( ind = i * 2 ))
+       else
+               (( ind = i * 2 + 1 ))
+       fi
+
+       $ECHO ${values[$ind]}
+}
+
+fs=$TESTPOOL/$TESTFS
+cleanup
+
+for property in ${properties[@]}; do
+       orig_val=$(get_prop $property $fs)
+       (($? != 0)) && log_fail "get_prop $property $fs"
+
+       # Set filesystem property temporarily
+       reverse_opt=$(get_reverse_option $fs $property)
+       log_must $ZFS mount -o remount,$reverse_opt $fs
+
+       cur_val=$(get_prop $property $fs)
+       (($? != 0)) && log_fail "get_prop $property $fs"
+
+       # In LZ, a user with all zone privileges can never with "devices"
+       if ! is_global_zone && [[ $property == devices ]] ; then
+               if [[ $cur_val != off || $orig_val != off ]]; then
+                       log_fail "'devices' property shouldn't " \
+                               "be enabled in LZ"
+               fi
+       elif [[ $orig_val == $cur_val ]]; then
+               log_fail "zfs mount -o remount,$reverse_opt " \
+                       "doesn't change property."
+       fi
+
+       # unmount & mount will revert property to the original value
+       log_must $ZFS unmount $fs
+       log_must $ZFS mount $fs
+
+       cur_val=$(get_prop $property $fs)
+       (($? != 0)) && log_fail "get_prop $property $fs"
+       if [[ $orig_val != $cur_val ]]; then
+               log_fail "zfs mount -o remount,$reverse_opt " \
+                       "change the property that is stored on disks"
+       fi
+done
+
+log_pass "Verify '-o' set filesystem property temporarily passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_008_pos.ksh
new file mode 100755 (executable)
index 0000000..a273272
--- /dev/null
@@ -0,0 +1,92 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+#      'zfs mount -O' allow the file system to be mounted over an existing
+#      mount point, making the underlying file system inaccessible.
+#
+# STRATEGY:
+#      1. Create two filesystem fs & fs1, and create two test files for them.
+#      2. Unmount fs1 and set mountpoint property is identical to fs.
+#      3. Verify 'zfs mount -O' will make the underlying filesystem fs
+#         inaccessible.
+#
+
+function cleanup
+{
+       ! ismounted $fs && log_must $ZFS mount $fs
+
+       if datasetexists $fs1; then
+               log_must $ZFS destroy $fs1
+       fi
+
+       if [[ -f $testfile ]]; then
+               log_must $RM -f $testfile
+       fi
+}
+
+log_assert "Verify 'zfs mount -O' will override existing mount point."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS; fs1=$TESTPOOL/$TESTFS1
+
+cleanup
+
+# Get the original mountpoint of $fs and $fs1
+mntpnt=$(get_prop mountpoint $fs)
+log_must $ZFS create $fs1
+mntpnt1=$(get_prop mountpoint $fs1)
+
+testfile=$mntpnt/$TESTFILE0; testfile1=$mntpnt1/$TESTFILE1
+log_must $MKFILE 1M $testfile $testfile1
+
+log_must $ZFS unmount $fs1
+log_must $ZFS set mountpoint=$mntpnt $fs1
+log_mustnot $ZFS mount $fs1
+log_must $ZFS mount -O $fs1
+
+# Create new file in override mountpoint
+log_must $MKFILE 1M $mntpnt/$TESTFILE2
+
+# Verify the underlying file system inaccessible
+log_mustnot $LS $testfile
+log_must $LS $mntpnt/$TESTFILE1 $mntpnt/$TESTFILE2
+
+# Verify $TESTFILE2 was created in $fs1, rather then $fs
+log_must $ZFS unmount $fs1
+log_must $ZFS set mountpoint=$mntpnt1 $fs1
+log_must $ZFS mount $fs1
+log_must $LS $testfile1 $mntpnt1/$TESTFILE2
+
+# Verify $TESTFILE2 was not created in $fs, and $fs is accessable again.
+log_mustnot $LS $mntpnt/$TESTFILE2
+log_must $LS $testfile
+
+log_pass "Verify 'zfs mount -O' override mount point passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_009_neg.ksh
new file mode 100755 (executable)
index 0000000..c6a372a
--- /dev/null
@@ -0,0 +1,111 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+#
+# DESCRIPTION:
+#      Try each 'zfs mount' with inapplicable scenarios to make sure
+#      it returns an error. include:
+#              * '-a', but also with a specific filesystem.
+#
+# STRATEGY:
+#      1. Create an array of parameters
+#      2. For each parameter in the array, execute the sub-command
+#      3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+multifs="$TESTFS $TESTFS1"
+datasets=""
+
+for fs in $multifs ; do
+       datasets="$datasets $TESTPOOL/$fs"
+done
+
+set -A args "$mountall $TESTPOOL/$TESTFS"
+
+function setup_all
+{
+       typeset fs
+
+       for fs in $multifs ; do
+               setup_filesystem "$DISKS" "$TESTPOOL" \
+                       "$fs" \
+                       "${TEST_BASE_DIR%%/}/testroot$$/$TESTPOOL/$fs"
+       done
+       return 0
+}
+
+function cleanup_all
+{
+       typeset fs
+
+       cleanup_filesystem "$TESTPOOL" "$TESTFS1"
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+       [[ -d ${TEST_BASE_DIR%%/}/testroot$$ ]] && \
+               $RM -rf ${TEST_BASE_DIR%%/}/testroot$$
+
+
+       return 0
+}
+
+function verify_all
+{
+       typeset fs
+
+       for fs in $multifs ; do
+               log_must unmounted $TESTPOOL/$fs
+       done
+       return 0
+}
+
+log_assert "Badly-formed 'zfs $mountcmd' with inapplicable scenarios " \
+       "should return an error."
+log_onexit cleanup_all
+
+log_must setup_all
+
+log_must $ZFS $unmountall
+
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZFS ${args[i]}
+       ((i = i + 1))
+done
+
+log_must verify_all
+
+log_pass "Badly formed 'zfs $mountcmd' with inapplicable scenarios " \
+       "fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_010_neg.ksh
new file mode 100755 (executable)
index 0000000..b6ab6d8
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that zfs mount should fail when mounting a mounted zfs filesystem or
+# the mountpoint is busy.  On Linux the mount should succeed.
+#
+# STRATEGY:
+# 1. Make a zfs filesystem mounted or mountpoint busy
+# 2. Use zfs mount to mount the filesystem
+# 3. Verify that zfs mount succeeds on Linux and fails for other platforms
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if ! ismounted $fs; then
+               log_must $ZFS mount $fs
+       fi
+}
+
+log_assert "zfs mount fails with mounted filesystem or busy mountpoint"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+if ! ismounted $fs; then
+       log_must $ZFS mount $fs
+fi
+
+log_mustnot $ZFS mount $fs
+
+mpt=$(get_prop mountpoint $fs)
+log_must $ZFS umount $fs
+curpath=`$DIRNAME $0`
+cd $mpt
+if is_linux; then
+    log_must $ZFS mount $fs
+else
+    log_mustnot $ZFS mount $fs
+fi
+cd $curpath
+
+log_pass "zfs mount fails with mounted filesystem or busy moutpoint as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_011_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_011_neg.ksh
new file mode 100755 (executable)
index 0000000..97fc4b3
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that zfs mount should fail with bad parameters
+#
+# STRATEGY:
+# 1. Make an array of bad parameters
+# 2. Use zfs mount to mount the filesystem
+# 3. Verify that zfs mount returns error
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists $TESTPOOL/$TESTFS@$TESTSNAP; then
+               log_must $ZFS destroy $TESTPOOL/$TESTFS@$TESTSNAP
+       fi
+
+       if is_global_zone && datasetexists $TESTPOOL/$TESTVOL; then
+               log_must $ZFS destroy $TESTPOOL/$TESTVOL
+       fi
+}
+
+log_assert "zfs mount fails with bad parameters"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+set -A badargs "A" "-A" "-" "-x" "-?" "=" "-o *" "-a"
+
+for arg in "${badargs[@]}"; do
+       log_mustnot eval "$ZFS mount $arg $fs >/dev/null 2>&1"
+done
+
+#verify that zfs mount fails with invalid dataset
+for opt in "-o abc" "-O"; do
+       log_mustnot eval "$ZFS mount $opt /$fs >/dev/null 2>&1"
+done
+
+#verify that zfs mount fails with volume and snapshot
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+log_mustnot eval "$ZFS mount $TESTPOOL/$TESTFS@$TESTSNAP >/dev/null 2>&1"
+
+if is_global_zone; then
+       log_must $ZFS create -V 10m $TESTPOOL/$TESTVOL
+       log_mustnot eval "$ZFS mount $TESTPOOL/$TESTVOL >/dev/null 2>&1"
+fi
+
+log_pass "zfs mount fails with bad parameters as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_all_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_mount/zfs_mount_all_001_pos.ksh
new file mode 100755 (executable)
index 0000000..8973558
--- /dev/null
@@ -0,0 +1,197 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+
+# DESCRIPTION:
+#       Verify that 'zfs mount -a' succeeds as root.
+#
+# STRATEGY:
+#       1. Create a group of pools with specified vdev.
+#       2. Create zfs filesystems within the given pools.
+#       3. Unmount all the filesystems.
+#       4. Verify that 'zfs mount -a' command succeed,
+#         and all available ZFS filesystems are mounted.
+#      5. Verify that 'zfs mount' is identical with 'df -F zfs'
+#
+
+verify_runnable "both"
+
+set -A fs "$TESTFS" "$TESTFS1"
+set -A ctr "" "$TESTCTR" "$TESTCTR/$TESTCTR1" "$TESTCTR1"
+set -A vol "$TESTVOL" "$TESTVOL1"
+
+function setup_all
+{
+       typeset -i i=0
+       typeset -i j=0
+       typeset path
+
+       while (( i < ${#ctr[*]} )); do
+
+               path=${TEST_BASE_DIR%%/}/testroot$$/$TESTPOOL
+               if [[ -n ${ctr[i]} ]]; then
+                       path=$path/${ctr[i]}
+
+                       setup_filesystem "$DISKS" "$TESTPOOL" \
+                               "${ctr[i]}" "$path" \
+                               "ctr"
+               fi
+
+               if is_global_zone ; then
+                       j=0
+                       while (( j < ${#vol[*]} )); do
+                               setup_filesystem "$DISKS" "$TESTPOOL" \
+                                       "${ctr[i]}/${vol[j]}" \
+                                       "$path/${vol[j]}" \
+                                       "vol"
+                               ((j = j + 1))
+                       done
+               fi
+
+               j=0
+               while (( j < ${#fs[*]} )); do
+                       setup_filesystem "$DISKS" "$TESTPOOL" \
+                               "${ctr[i]}/${fs[j]}" \
+                               "$path/${fs[j]}"
+                       ((j = j + 1))
+               done
+
+               ((i = i + 1))
+       done
+
+       return 0
+}
+
+function cleanup_all
+{
+       typeset -i i=0
+       typeset -i j=0
+       typeset path
+
+       ((i = ${#ctr[*]} - 1))
+
+       while (( i >= 0 )); do
+               if is_global_zone ; then
+                       j=0
+                       while (( j < ${#vol[*]} )); do
+                               cleanup_filesystem "$TESTPOOL" \
+                                       "${ctr[i]}/${vol[j]}"
+                               ((j = j + 1))
+                       done
+               fi
+
+               j=0
+               while (( j < ${#fs[*]} )); do
+                       cleanup_filesystem "$TESTPOOL" \
+                               "${ctr[i]}/${fs[j]}"
+                       ((j = j + 1))
+               done
+
+               [[ -n ${ctr[i]} ]] && \
+                       cleanup_filesystem "$TESTPOOL" "${ctr[i]}"
+
+               ((i = i - 1))
+       done
+
+       [[ -d ${TEST_BASE_DIR%%/}/testroot$$ ]] && \
+               $RM -rf ${TEST_BASE_DIR%%/}/testroot$$
+}
+
+#
+# This function takes a single true/false argument. If true it will verify that
+# all file systems are mounted. If false it will verify that they are not
+# mounted.
+#
+function verify_all
+{
+       typeset -i i=0
+       typeset -i j=0
+       typeset path
+       typeset logfunc
+
+       if $1; then
+               logfunc=log_must
+       else
+               logfunc=log_mustnot
+       fi
+
+       while (( i < ${#ctr[*]} )); do
+
+               path=$TESTPOOL
+               [[ -n ${ctr[i]} ]] && \
+                       path=$path/${ctr[i]}
+
+               if is_global_zone ; then
+                       j=0
+                       while (( j < ${#vol[*]} )); do
+                               log_mustnot mounted "$path/${vol[j]}"
+                               ((j = j + 1))
+                       done
+               fi
+
+               j=0
+               while (( j < ${#fs[*]} )); do
+                       $logfunc mounted "$path/${fs[j]}"
+                       ((j = j + 1))
+               done
+
+               $logfunc mounted "$path"
+
+               ((i = i + 1))
+       done
+
+       return 0
+}
+
+
+log_assert "Verify that 'zfs $mountall' succeeds as root, " \
+       "and all available ZFS filesystems are mounted."
+
+log_onexit cleanup_all
+
+log_must setup_all
+
+export __ZFS_POOL_RESTRICT="$TESTPOOL"
+log_must $ZFS $unmountall
+unset __ZFS_POOL_RESTRICT
+
+verify_all false
+
+export __ZFS_POOL_RESTRICT="$TESTPOOL"
+log_must $ZFS $mountall
+unset __ZFS_POOL_RESTRICT
+
+verify_all true
+
+log_note "Verify that 'zfs $mountcmd' will display " \
+       "all ZFS filesystems currently mounted."
+
+verify_mount_display
+
+log_pass "'zfs $mountall' succeeds as root, " \
+       "and all available ZFS filesystems are mounted."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/Makefile.am
new file mode 100644 (file)
index 0000000..fa0eae7
--- /dev/null
@@ -0,0 +1,13 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_promote
+dist_pkgdata_SCRIPTS = \
+       zfs_promote.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_promote_001_pos.ksh \
+       zfs_promote_002_pos.ksh \
+       zfs_promote_003_pos.ksh \
+       zfs_promote_004_pos.ksh \
+       zfs_promote_005_pos.ksh \
+       zfs_promote_006_neg.ksh \
+       zfs_promote_007_neg.ksh \
+       zfs_promote_008_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/setup.ksh
new file mode 100755 (executable)
index 0000000..3e2e2ce
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_volume_setup ${DISK}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote.cfg
new file mode 100644 (file)
index 0000000..6407328
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+export FILESIZE=1m
+
+export TESTSNAP3=testsnap3.promote
+export TESTSNAP4=testsnap4.promote
+export TESTSNAP5=testsnap5.promote
+export TESTFILE3=testfile3.promote
+
+export CLONEFILE=clonefile.promote
+export CLONEFILE1=clonefile1.promote
+export CLONEFILE2=clonefile2.promote
+export CLONEFILE3=clonefile3.promote
+
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_001_pos.ksh
new file mode 100755 (executable)
index 0000000..2c2b9a5
--- /dev/null
@@ -0,0 +1,127 @@
+#!/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_SUITE/tests/functional/cli_root/zfs_promote/zfs_promote.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs promote' can promote a clone filesystem to no longer be dependent
+#      on its "origin" snapshot.
+#
+# STRATEGY:
+#      1. Create a snapshot and a clone of the snapshot
+#      2. Promote the clone filesystem
+#      3. Verify the promoted filesystem become independent
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists $csnap; then
+               log_must $ZFS promote $fs
+       fi
+       snapexists $snap && \
+               log_must $ZFS destroy -rR $snap
+
+       typeset data
+       for data in $file0 $file1; do
+               [[ -e $data ]] && $RM -f $data
+       done
+}
+
+function testing_verify
+{
+       typeset ds=$1
+       typeset ds_file=$2
+       typeset snap_file=$3
+       typeset c_ds=$4
+       typeset c_file=$5
+       typeset csnap_file=$6
+       typeset origin_prop=""
+
+
+       snapexists $ds@$TESTSNAP && \
+               log_fail "zfs promote cannot promote $ds@$TESTSNAP."
+       ! snapexists $c_ds@$TESTSNAP && \
+               log_fail "The $c_ds@$TESTSNAP after zfs promote doesn't exist."
+
+       origin_prop=$(get_prop origin $ds)
+       [[ "$origin_prop" != "$c_ds@$TESTSNAP" ]] && \
+               log_fail "The dependency of $ds is not correct."
+       origin_prop=$(get_prop origin $c_ds)
+       [[ "$origin_prop" != "-" ]] && \
+               log_fail "The dependency of $c_ds is not correct."
+
+       if [[ -e $snap_file ]] || [[ ! -e $csnap_file ]]; then
+               log_fail "Data file $snap_file cannot be correctly promoted."
+       fi
+       if [[ ! -e $ds_file ]] || [[ ! -e $c_file ]]; then
+               log_fail "There exists data file losing after zfs promote."
+       fi
+
+       log_mustnot $ZFS destroy -r $c_ds
+}
+
+log_assert "'zfs promote' can promote a clone filesystem."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+file0=$TESTDIR/$TESTFILE0
+file1=$TESTDIR/$TESTFILE1
+snap=$fs@$TESTSNAP
+snapfile=$TESTDIR/.zfs/snapshot/$TESTSNAP/$TESTFILE0
+clone=$TESTPOOL/$TESTCLONE
+cfile=/$clone/$CLONEFILE
+csnap=$clone@$TESTSNAP
+csnapfile=/$clone/.zfs/snapshot/$TESTSNAP/$TESTFILE0
+
+# setup for promte testing
+log_must $MKFILE $FILESIZE $file0
+log_must $ZFS snapshot $snap
+log_must $MKFILE $FILESIZE $file1
+log_must $RM -f $file0
+log_must $ZFS clone $snap $clone
+log_must $MKFILE $FILESIZE $cfile
+
+log_must $ZFS promote $clone
+# verify the 'promote' operation
+testing_verify $fs $file1 $snapfile $clone $cfile $csnapfile
+
+log_note "Verify 'zfs promote' can change back the dependency relationship."
+log_must $ZFS promote $fs
+#verify the result
+testing_verify $clone $cfile $csnapfile $fs $file1 $snapfile
+
+log_pass "'zfs promote' reverses the clone parent-child dependency relationship"\
+       "as expected."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_002_pos.ksh
new file mode 100755 (executable)
index 0000000..b6ff94b
--- /dev/null
@@ -0,0 +1,102 @@
+#!/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_SUITE/tests/functional/cli_root/zfs_promote/zfs_promote.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs promote' can deal with multiple snapshots in the origin filesystem.
+#
+# STRATEGY:
+#      1. Create multiple snapshots and a clone of the last snapshot
+#      2. Promote the clone filesystem
+#      3. Verify the promoted filesystem included all snapshots
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists $csnap1; then
+               log_must $ZFS promote $fs
+       fi
+
+       typeset ds
+       typeset data
+       for ds in $snap $snap1; do
+               log_must $ZFS destroy -rR $ds
+       done
+       for file in $TESTDIR/$TESTFILE0 $TESTDIR/$TESTFILE1; do
+               [[ -e $file ]] && $RM -f $file
+       done
+}
+
+log_assert "'zfs promote' can deal with multiple snapshots in a filesystem."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+snap=$fs@$TESTSNAP
+snap1=$fs@$TESTSNAP1
+clone=$TESTPOOL/$TESTCLONE
+csnap=$clone@$TESTSNAP
+csnap1=$clone@$TESTSNAP1
+
+# setup for promote testing
+log_must $MKFILE $FILESIZE $TESTDIR/$TESTFILE0
+log_must $ZFS snapshot $snap
+log_must $MKFILE $FILESIZE $TESTDIR/$TESTFILE1
+log_must $RM -f $testdir/$TESTFILE0
+log_must $ZFS snapshot $snap1
+log_must $ZFS clone $snap1 $clone
+log_must $MKFILE $FILESIZE /$clone/$CLONEFILE
+
+log_must $ZFS promote $clone
+
+# verify the 'promote' operation
+for ds in $csnap $csnap1; do
+       ! snapexists $ds && \
+               log_fail "Snapshot $ds doesn't exist after zfs promote."
+done
+for ds in $snap $snap1; do
+       snapexists $ds && \
+               log_fail "Snapshot $ds is still there after zfs promote."
+done
+
+origin_prop=$(get_prop origin $fs)
+[[ "$origin_prop" != "$csnap1" ]] && \
+       log_fail "The dependency of $fs is not correct."
+origin_prop=$(get_prop origin $clone)
+[[ "$origin_prop" != "-" ]] && \
+        log_fail "The dependency of $clone is not correct."
+
+log_pass "'zfs promote' deal with multiple snapshots as expected."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_003_pos.ksh
new file mode 100755 (executable)
index 0000000..44a6aa9
--- /dev/null
@@ -0,0 +1,134 @@
+#!/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_SUITE/tests/functional/cli_root/zfs_promote/zfs_promote.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs promote' can deal with multi-point snapshots.
+#
+# STRATEGY:
+#      1. Create multiple snapshots and a clone to a middle point snapshot
+#      2. Promote the clone filesystem
+#      3. Verify the origin filesystem and promoted filesystem include
+#         correct datasets seperated by the clone point.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists ${csnap[2]}; then
+               log_must $ZFS promote $fs
+       fi
+
+       typeset ds
+       typeset data
+       for ds in ${snap[*]}; do
+               snapexists $ds && \
+                       log_must $ZFS destroy -rR $ds
+       done
+       for data in ${file[*]}; do
+               [[ -e $data ]] && $RM -f $data
+       done
+
+}
+
+log_assert "'zfs promote' can deal with multi-point snapshots."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+clone=$TESTPOOL/$TESTCLONE
+
+# Define some arrays here to use loop to reduce code amount
+
+# Array which stores the origin snapshots created in the origin filesystem
+set -A snap "${fs}@$TESTSNAP" "${fs}@$TESTSNAP1" "${fs}@$TESTSNAP2" "${fs}@$TESTSNAP3"
+# Array which stores the snapshots existing in the clone after promote operation
+set -A csnap "${clone}@$TESTSNAP" "${clone}@$TESTSNAP1" "${clone}@$TESTSNAP2" \
+       "${clone}@$TESTSNAP3"
+# The data will inject into the origin filesystem
+set -A file "$TESTDIR/$TESTFILE0" "$TESTDIR/$TESTFILE1" "$TESTDIR/$TESTFILE2" \
+               "$TESTDIR/$TESTFILE3"
+snapdir=$TESTDIR/.zfs/snapshot
+# The data which will exist in the snapshot after creation of snapshot
+set -A snapfile "$snapdir/$TESTSNAP/$TESTFILE0" "$snapdir/$TESTSNAP1/$TESTFILE1" \
+       "$snapdir/$TESTSNAP2/$TESTFILE2" "$snapdir/$TESTSNAP3/$TESTFILE3"
+csnapdir=/$clone/.zfs/snapshot
+# The data which will exist in the snapshot of clone filesystem after promote
+set -A csnapfile "${csnapdir}/$TESTSNAP/$TESTFILE0" "${csnapdir}/$TESTSNAP1/$TESTFILE1" \
+       "${csnapdir}/$TESTSNAP2/$TESTFILE2"
+
+# setup for promote testing
+typeset -i i=0
+while (( i < 4 )); do
+       log_must $MKFILE $FILESIZE ${file[i]}
+       (( i>0 )) && log_must $RM -f ${file[((i-1))]}
+       log_must $ZFS snapshot ${snap[i]}
+
+       (( i = i + 1 ))
+done
+log_must $ZFS clone ${snap[2]} $clone
+log_must $MKFILE $FILESIZE /$clone/$CLONEFILE
+log_must $RM -f /$clone/$TESTFILE2
+log_must $ZFS snapshot ${csnap[3]}
+
+log_must $ZFS promote $clone
+
+# verify the 'promote' operation
+for ds in ${snap[3]} ${csnap[*]}; do
+       ! snapexists $ds && \
+               log_fail "The snapshot $ds disappear after zfs promote."
+done
+for data in ${csnapfile[*]} $TESTDIR/$TESTFILE3 /$clone/$CLONEFILE; do
+       [[ ! -e $data ]] && \
+               log_fail "The data file $data loses after zfs promote."
+done
+
+for ds in ${snap[0]} ${snap[1]} ${snap[2]}; do
+       snapexists $ds && \
+               log_fail "zfs promote cannot promote the snapshot $ds."
+done
+for data in ${snapfile[0]} ${snapfile[1]} ${snapfile[2]}; do
+       [[ -e $data ]] && \
+               log_fail "zfs promote cannot promote the data $data."
+done
+
+origin_prop=$(get_prop origin $fs)
+[[ "$origin_prop" != "${csnap[2]}" ]] && \
+       log_fail "The dependency is not correct for $fs after zfs promote."
+origin_prop=$(get_prop origin $clone)
+[[ "$origin_prop" != "-" ]] && \
+       log_fail "The dependency is not correct for $clone after zfs promote."
+
+log_pass "'zfs promote' deal with multi-point snapshots as expected."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_004_pos.ksh
new file mode 100755 (executable)
index 0000000..a90da8e
--- /dev/null
@@ -0,0 +1,140 @@
+#!/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_SUITE/tests/functional/cli_root/zfs_promote/zfs_promote.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs promote' can deal with multi-level clones.
+#
+# STRATEGY:
+#      1. Create multiple snapshots and multi-level clones
+#      2. Promote a clone filesystem
+#      3. Verify the dataset dependency relationships are correct after promotion.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if snapexists ${c1snap[1]}; then
+               log_must $ZFS promote $clone
+       fi
+
+       typeset ds
+       typeset data
+       for ds in ${snap[*]}; do
+               snapexists $ds && \
+                       log_must $ZFS destroy -rR $ds
+       done
+       for data in ${file[*]}; do
+               [[ -e $data ]] && $RM -f $data
+       done
+}
+
+log_assert "'zfs promote' can deal with multi-level clone."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+clone=$TESTPOOL/$TESTCLONE
+clone1=$TESTPOOL/$TESTCLONE1
+
+# Define some arrays here to use loop to reduce code amount
+
+# Array which stores the origin snapshots created in the origin filesystem
+set -A snap "${fs}@$TESTSNAP" "${fs}@$TESTSNAP1" "${fs}@$TESTSNAP2" "${fs}@$TESTSNAP3"
+# Array which stores the snapshots existing in the first clone
+set -A csnap "${clone}@$TESTSNAP3" "${clone}@$TESTSNAP4" "${clone}@$TESTSNAP5"
+# Array which stores the snapshots existing in the second clone after promote operation
+set -A c1snap "${clone1}@$TESTSNAP3" "${clone1}@$TESTSNAP4" "${clone1}@$TESTSNAP5"
+# The data will inject into the origin filesystem
+set -A file "$TESTDIR/$TESTFILE0" "$TESTDIR/$TESTFILE1" "$TESTDIR/$TESTFILE2" \
+               "$TESTDIR/$TESTFILE3"
+cdir=/$TESTPOOL/$TESTCLONE
+# The data will inject into the first clone
+set -A cfile "${cdir}/$CLONEFILE" "${cdir}/$CLONEFILE1" "${cdir}/$CLONEFILE2"
+c1snapdir=/$TESTPOOL/$TESTCLONE1/.zfs/snapshot
+# The data which will exist in the snapshot of the second clone filesystem after promote
+set -A c1snapfile "${c1snapdir}/$TESTSNAP3/$CLONEFILE" \
+       "${c1snapdir}/$TESTSNAP4/$CLONEFILE1" \
+       "${c1snapdir}/$TESTSNAP5/$CLONEFILE2"
+
+# setup for promote testing
+typeset -i i=0
+while (( i < 4 )); do
+       log_must $MKFILE $FILESIZE ${file[i]}
+       (( i>0 )) && log_must $RM -f ${file[((i-1))]}
+       log_must $ZFS snapshot ${snap[i]}
+
+       (( i = i + 1 ))
+done
+log_must $ZFS clone ${snap[2]} $clone
+
+log_must $RM -f /$clone/$TESTFILE2
+i=0
+while (( i < 3 )); do
+       log_must $MKFILE $FILESIZE ${cfile[i]}
+       (( i>0 )) && log_must $RM -f ${cfile[(( i-1 ))]}
+       log_must $ZFS snapshot ${csnap[i]}
+
+       (( i = i + 1 ))
+done
+
+log_must $ZFS clone ${csnap[1]} $clone1
+log_must $MKFILE $FILESIZE /$clone1/$CLONEFILE2
+log_must $RM -f /$clone1/$CLONEFILE1
+log_must $ZFS snapshot ${c1snap[2]}
+
+log_must $ZFS promote $clone1
+
+# verify the 'promote' operation
+for ds in ${snap[*]} ${csnap[2]} ${c1snap[*]}; do
+       ! snapexists $ds && \
+               log_fail "The snapshot $ds disappear after zfs promote."
+done
+for data in ${c1snapfile[*]}; do
+       [[ ! -e $data ]] && \
+               log_fail "The data file $data loses after zfs promote."
+done
+
+origin_prop=$(get_prop origin $fs)
+[[ "$origin_prop" != "-" ]] && \
+       log_fail "The dependency is not correct for $fs after zfs promote."
+origin_prop=$(get_prop origin $clone)
+[[ "$origin_prop" != "${c1snap[1]}" ]] && \
+       log_fail "The dependency is not correct for $clone after zfs promote."
+origin_prop=$(get_prop origin $clone1)
+[[ "$origin_prop" != "${snap[2]}" ]] && \
+       log_fail "The dependency is not correct for $clone1 after zfs promote."
+
+log_pass "'zfs promote' deal with multi-level clones as expected."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_005_pos.ksh
new file mode 100755 (executable)
index 0000000..e505951
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      The original fs was unmounted, 'zfs promote' still should succeed.
+#
+# STRATEGY:
+#      1. Create pool, fs and snapshot.
+#      2. Create clone of fs.
+#      3. Unmount fs, then verify 'zfs promote' clone still succeed.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $fssnap ; then
+               datasetexists $clone && log_must $ZFS destroy $clone
+               log_must $ZFS destroy $fssnap
+       fi
+       if datasetexists $clone ; then
+               log_must $ZFS promote $fs
+               log_must $ZFS destroy $clone
+               log_must $ZFS destroy $fssnap
+       fi
+}
+
+log_assert "The original fs was unmounted, 'zfs promote' still should succeed."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+clone=$TESTPOOL/$TESTCLONE
+fssnap=$fs@fssnap
+
+log_must $ZFS snapshot $fssnap
+log_must $ZFS clone $fssnap $clone
+log_must $ZFS unmount $fs
+log_must $ZFS promote $clone
+log_must $ZFS unmount $clone
+log_must $ZFS promote $fs
+
+log_pass "Unmount original fs, 'zfs promote' passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_006_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_006_neg.ksh
new file mode 100755 (executable)
index 0000000..9c1fb3e
--- /dev/null
@@ -0,0 +1,80 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs promote' will fail with invalid arguments:
+#      (1) NULL arguments
+#      (2) non-existent clone
+#      (3) non-clone datasets:
+#              pool, fs, snapshot,volume
+#      (4) too many arguments.
+#      (5) invalid options
+#
+# STRATEGY:
+#      1. Create an array of invalid arguments
+#      2. For each invalid argument in the array, 'zfs promote' should fail
+#      3. Verify the return code from zfs promote
+#
+
+verify_runnable "both"
+
+snap=$TESTPOOL/$TESTFS@$TESTSNAP
+set -A args "" \
+       "$TESTPOOL/blah" \
+       "$TESTPOOL" "$TESTPOOL/$TESTFS" "$snap" \
+       "$TESTPOOL/$TESTVOL" "$TESTPOL $TESTPOOL/$TESTFS" \
+       "$clone $TESTPOOL/$TESTFS" "- $clone" "-? $clone"
+
+function cleanup
+{
+       if datasetexists $clone; then
+               log_must $ZFS destroy $clone
+       fi
+
+       if snapexists $snap; then
+               destroy_snapshot  $snap
+       fi
+}
+
+log_assert "'zfs promote' will fail with invalid arguments. "
+log_onexit cleanup
+
+snap=$TESTPOOL/$TESTFS@$TESTSNAP
+clone=$TESTPOOL/$TESTCLONE
+log_must $ZFS snapshot $snap
+log_must $ZFS clone $snap $clone
+
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZFS promote ${args[i]}
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs promote' fails with invalid argument as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_007_neg.ksh
new file mode 100755 (executable)
index 0000000..83a5231
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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_SUITE/tests/functional/cli_root/zfs_promote/zfs_promote.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs promote' can deal with conflicts in the namespaces.
+#
+# STRATEGY:
+#      1. Create a snapshot and a clone of the snapshot
+#      2. Create the same name snapshot for the clone
+#      3. Promote the clone filesystem
+#      4. Verify the promote operation fail due to the name conflicts.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       snapexists $snap && \
+               log_must $ZFS destroy -rR $snap
+
+       typeset data
+       for data in $TESTDIR/$TESTFILE0 $TESTDIR/$TESTFILE1; do
+               [[ -e $data ]] && $RM -f $data
+       done
+}
+
+log_assert "'zfs promote' can deal with name conflicts."
+log_onexit cleanup
+
+snap=$TESTPOOL/$TESTFS@$TESTSNAP
+clone=$TESTPOOL/$TESTCLONE
+clonesnap=$TESTPOOL/$TESTCLONE@$TESTSNAP
+
+# setup for promte testing
+log_must $MKFILE $FILESIZE $TESTDIR/$TESTFILE0
+log_must $ZFS snapshot $snap
+log_must $MKFILE $FILESIZE $TESTDIR/$TESTFILE1
+log_must $RM -f $TESTDIR/$TESTFILE0
+log_must $ZFS clone $snap $clone
+log_must $MKFILE $FILESIZE /$clone/$CLONEFILE
+log_must $ZFS snapshot $clonesnap
+
+log_mustnot $ZFS promote $clone
+
+log_pass "'zfs promote' deals with name conflicts as expected."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_008_pos.ksh
new file mode 100755 (executable)
index 0000000..e4e6aa6
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/ksh
+#
+# 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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs promote' can successfully promote a volume clone.
+#
+# STRATEGY:
+#      1. Create a volume clone
+#      2. Promote the volume clone
+#      3. Verify the dependency changed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if snapexists $csnap; then
+               log_must $ZFS promote $vol
+       fi
+
+       log_must $ZFS destroy -rR $snap
+}
+
+log_assert "'zfs promote' can promote a volume clone."
+log_onexit cleanup
+
+vol=$TESTPOOL/$TESTVOL
+snap=$vol@$TESTSNAP
+clone=$TESTPOOL/volclone
+csnap=$clone@$TESTSNAP
+
+if ! snapexists $snap ; then
+       log_must $ZFS snapshot $snap
+       log_must $ZFS clone $snap $clone
+fi
+
+log_must $ZFS promote $clone
+
+# verify the 'promote' operation
+! snapexists $csnap && \
+               log_fail "Snapshot $csnap doesn't exist after zfs promote."
+snapexists $snap && \
+       log_fail "Snapshot $snap is still there after zfs promote."
+
+origin_prop=$(get_prop origin $vol)
+[[ "$origin_prop" != "$csnap" ]] && \
+       log_fail "The dependency of $vol is not correct."
+origin_prop=$(get_prop origin $clone)
+[[ "$origin_prop" != "-" ]] && \
+        log_fail "The dependency of $clone is not correct."
+
+log_pass "'zfs promote' can promote volume clone as expected."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/Makefile.am
new file mode 100644 (file)
index 0000000..d8a5687
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_property
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_written_property_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/cleanup.ksh
new file mode 100755 (executable)
index 0000000..e499813
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/setup.ksh
new file mode 100755 (executable)
index 0000000..746a050
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/zfs_written_property_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_property/zfs_written_property_001_pos.ksh
new file mode 100755 (executable)
index 0000000..ad96879
--- /dev/null
@@ -0,0 +1,236 @@
+#!/bin/ksh
+#
+# 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.
+#
+
+#
+# DESCRIPTION
+# Verify that "zfs list" gives correct values for written and written@
+# proerties for the dataset when different operations are on done on it
+#
+#
+# STRATEGY
+# 1) Create recursive datasets
+# 2) Take snapshots, write data and verify  written/ written@ properties for
+#    following cases
+#    a) Delete data
+#    b) Write Data
+#    c) Clone
+#    d) Delete snapshot
+#    e) Recursive datasets
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/math.shlib
+
+function cleanup
+{
+       for ds in $datasets; do
+               datasetexists $ds && log_must $ZFS destroy -R $TESTPOOL/$TESTFS1
+       done
+}
+function get_prop_mb
+{
+       typeset prop=$1
+       typeset dataset=$2
+       typeset -l value=$(get_prop $prop $dataset)
+       ((value = value / mb_block))
+       $ECHO $value
+}
+
+datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS2 \
+    $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3"
+
+log_assert "verify zfs written and written@ property"
+log_onexit cleanup
+
+typeset -l i=1
+typeset -l blocks=50
+typeset -l expected_written=0
+typeset -l expected_writtenat=0
+typeset -l written=0
+typeset -l total=0
+typeset -l snap1_size=0
+typeset -l snap2_size=0
+typeset -l snap3_size=0
+typeset -l metadata=0
+typeset -l mb_block=0
+((mb_block = 1024 * 1024))
+# approximate metadata on dataset when empty is 32KB
+((metadata = 32 * 1024))
+
+log_note "verify written property statistics for dataset"
+log_must $ZFS create -p $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3
+for i in 1 2 3; do
+       log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
+       log_must $DD if=/dev/urandom of=/$TESTPOOL/$TESTFS1/testfile.$i bs=1M \
+           count=$blocks
+       log_must $SYNC
+       log_must $SLEEP 10
+       written=$(get_prop written $TESTPOOL/$TESTFS1)
+       ((expected_written=blocks * mb_block))
+       within_percent $written $expected_written 99.5 || \
+           log_fail "Unexpected written value $written $expected_written"
+       ((total = total + blocks))
+       ((blocks = blocks + 50))
+done
+
+log_note "verify written property statistics for snapshots"
+blocks=0
+for i in 1 2 3; do
+       written=$(get_prop written $TESTPOOL/$TESTFS1@snap$i)
+       if [[ $blocks -eq 0 ]]; then
+               expected_written=$metadata
+       else
+               ((expected_written = blocks * mb_block))
+       fi
+       within_percent $written $expected_written 99.5 || \
+           log_fail "Unexpected written value $written $expected_written $i"
+       ((blocks = blocks + 50))
+done
+
+snap1_size=$total
+((snap2_size = total-50))
+((snap3_size = total-100))
+
+log_note "verify written@ for the same dataset"
+blocks=50
+for i in 1 2 3; do
+       writtenat=$(get_prop written@snap$i $TESTPOOL/$TESTFS1)
+       ((expected_writtenat = total * mb_block))
+       within_percent $writtenat $expected_writtenat 99.5 || \
+           log_fail "Unexpected written@ value"
+       ((total = total - blocks))
+       ((blocks = blocks + 50))
+done
+log_note "delete data"
+before_written=$(get_prop written $TESTPOOL/$TESTFS1)
+log_must $RM /$TESTPOOL/$TESTFS1/testfile.3
+snap3_size=0
+log_must $SYNC
+log_must $SLEEP 10
+written=$(get_prop written $TESTPOOL/$TESTFS1)
+writtenat3=$(get_prop written@snap3 $TESTPOOL/$TESTFS1)
+[[ $written -eq $writtenat3 ]] || \
+    log_fail "Written and written@ dont match $written $writtenat3"
+within_percent $written $before_written 0.1 && \
+    log_fail "Unexpected written value after delete $written $before_written"
+writtenat=$(get_prop written@snap1 $TESTPOOL/$TESTFS1)
+((snap1_size = snap1_size - 150))
+((expected_writtenat = snap1_size * mb_block))
+within_percent $writtenat $expected_writtenat 99.5 || \
+    log_fail "Unexpected written value after delete $writtenat $expected_writtenat"
+writtenat=$(get_prop written@snap2 $TESTPOOL/$TESTFS1)
+((snap2_size = snap2_size - 150))
+((expected_writtenat = snap2_size * mb_block))
+within_percent $writtenat $expected_writtenat 99.5 || \
+    log_fail "Unexpected written value after delete"
+
+log_note "write data"
+blocks=20
+log_must $DD if=/dev/urandom of=/$TESTPOOL/$TESTFS1/testfile.3 bs=1M \
+    count=$blocks
+log_must $SYNC
+log_must $SLEEP 10
+written=$(get_prop written $TESTPOOL/$TESTFS1)
+writtenat1=$(get_prop written@snap1 $TESTPOOL/$TESTFS1)
+writtenat2=$(get_prop written@snap2 $TESTPOOL/$TESTFS1)
+writtenat3=$(get_prop written@snap3 $TESTPOOL/$TESTFS1)
+((snap3_size = snap3_size + blocks))
+((expected_writtenat = snap3_size * mb_block))
+[[ $written -eq $writtenat3 ]] || \
+    log_fail "Unexpected_written value"
+within_percent $writtenat3 $expected_writtenat 99.5 || \
+    log_fail "Unexpected_written@ value for snap3"
+((snap2_size = snap2_size + blocks))
+((expected_writtenat = snap2_size * mb_block))
+within_percent $writtenat2 $expected_writtenat 99.5 || \
+    log_fail "Unexpected_written@ value for snap2"
+((snap1_size = snap1_size + blocks))
+((expected_writtenat = snap1_size * mb_block))
+within_percent $writtenat1 $expected_writtenat 99.5 || \
+    log_fail "Unexpected_written@ value for snap1"
+
+log_note "write data to a clone"
+before_clone=$(get_prop written $TESTPOOL/$TESTFS1)
+log_must $ZFS clone $TESTPOOL/$TESTFS1@snap1 $TESTPOOL/$TESTFS1/snap1.clone
+log_must $DD if=/dev/urandom of=/$TESTPOOL/$TESTFS1/snap1.clone/testfile bs=1M \
+    count=40
+after_clone=$(get_prop written $TESTPOOL/$TESTFS1)
+[[ $before_clone -eq $after_clone ]] || \
+    log_fail "unexpected written for clone $before_clone $after_clone"
+
+log_note "deleted snapshot"
+typeset -l before_written1=$(get_prop_mb written@snap1 $TESTPOOL/$TESTFS1)
+typeset -l before_written3=$(get_prop_mb written@snap3 $TESTPOOL/$TESTFS1)
+typeset -l snap_before_written2=$(get_prop_mb written $TESTPOOL/$TESTFS1@snap2)
+typeset -l snap_before_written3=$(get_prop_mb written $TESTPOOL/$TESTFS1@snap3)
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap2
+log_mustnot snapexists $TESTPOOL/$TESTFS1@snap2
+log_must $SYNC
+log_must $SLEEP 10
+written1=$(get_prop_mb written@snap1 $TESTPOOL/$TESTFS1)
+written3=$(get_prop_mb written@snap3 $TESTPOOL/$TESTFS1)
+[[ $before_written1 -eq $written1 && $before_written3 -eq $written3 ]] || \
+    log_fail "unexpected written values $before_written1 $written1"
+typeset -l expected_written3
+((expected_written3 = snap_before_written2 + snap_before_written3))
+prev_written=$(get_prop_mb written $TESTPOOL/$TESTFS1@snap3)
+within_percent $prev_written $expected_written3 99.5 || \
+    log_fail "unexpected written value $prev_written $expected_written3"
+
+log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap3
+log_mustnot snapexists $TESTPOOL/$TESTFS1@snap3
+written=$(get_prop written $TESTPOOL/$TESTFS1)
+writtenat1=$(get_prop written@snap1 $TESTPOOL/$TESTFS1)
+[[ $written -ne $writtenat1 ]] && \
+    log_fail "Unexpected last snapshot written value"
+
+log_note "verify written@ property for recursive datasets"
+blocks=10
+log_must $ZFS snapshot -r $TESTPOOL/$TESTFS1@now
+for ds in $datasets; do
+       writtenat=$(get_prop written@now $ds)
+       [[ $writtenat -ne 0 ]] && \
+           log_fail "Unexpected written@ value"
+       log_must $DD if=/dev/urandom of=/$ds/testfile bs=1M count=$blocks
+       log_must $SYNC
+       log_must $SLEEP 10
+       writtenat=$(get_prop written@now $ds)
+       ((expected_writtenat = blocks * mb_block))
+       within_percent $writtenat $expected_writtenat 0.1 || \
+           log_fail "Unexpected written value"
+       ((blocks = blocks + 10))
+done
+
+log_note "verify written@ output for recursive datasets"
+blocks=20
+for ds in $datasets; do
+       log_must $ZFS snapshot $ds@current
+       log_must $DD if=/dev/urandom of=/$ds/testfile bs=1M \
+           count=$blocks
+       log_must $SYNC
+       log_must $SLEEP 10
+done
+recursive_output=$($ZFS get -r written@current $TESTPOOL | \
+    $GREP -v $TESTFS1@ | $GREP -v $TESTFS2@ | $GREP -v $TESTFS3@ | \
+    $GREP -v "VALUE" | $GREP -v "-")
+expected="20.0M"
+for ds in $datasets; do
+       writtenat=$($ECHO "$recursive_output" | $GREP -v $ds/)
+       writtenat=$($ECHO "$writtenat" | $GREP $ds | $AWK '{print $3}')
+       [[ $writtenat == $expected ]] || \
+           log_fail "recursive written property output mismatch"
+done
+
+log_pass "zfs written and written@ property fields print correct values"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile.am
new file mode 100644 (file)
index 0000000..8aadbf0
--- /dev/null
@@ -0,0 +1,17 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_receive
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_receive_001_pos.ksh \
+       zfs_receive_002_pos.ksh \
+       zfs_receive_003_pos.ksh \
+       zfs_receive_004_neg.ksh \
+       zfs_receive_005_neg.ksh \
+       zfs_receive_006_pos.ksh \
+       zfs_receive_007_neg.ksh \
+       zfs_receive_008_pos.ksh \
+       zfs_receive_009_neg.ksh \
+       zfs_receive_010_pos.ksh \
+       zfs_receive_011_pos.ksh \
+       zfs_receive_012_pos.ksh \
+       zfs_receive_013_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/cleanup.ksh
new file mode 100755 (executable)
index 0000000..cec69d4
--- /dev/null
@@ -0,0 +1,33 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+poolexists $TESTPOOL1 && \
+       destroy_pool $TESTPOOL1
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/setup.ksh
new file mode 100755 (executable)
index 0000000..aee38d2
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+if is_global_zone; then
+       default_volume_setup $DISK
+else
+       default_setup $DISK
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_001_pos.ksh
new file mode 100755 (executable)
index 0000000..288372a
--- /dev/null
@@ -0,0 +1,176 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verifying 'zfs receive [<filesystem|snapshot>] -d <filesystem>' works.
+#
+# STRATEGY:
+#      1. Fill in fs with some data
+#      2. Create full and incremental send stream
+#      3. Receive the send stream
+#      4. Verify the restoring results.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset -i i=0
+
+       datasetexists $rst_root && \
+               log_must $ZFS destroy -Rf $rst_root
+       while (( i < 2 )); do
+               snapexists ${orig_snap[$i]} && \
+                       log_must $ZFS destroy -f ${orig_snap[$i]}
+               log_must $RM -f ${bkup[$i]}
+
+               (( i = i + 1 ))
+       done
+
+       log_must $RM -rf $TESTDIR1
+}
+
+function recreate_root
+{
+       datasetexists $rst_root && \
+               log_must $ZFS destroy -Rf $rst_root
+       if [[ -d $TESTDIR1 ]] ; then
+               log_must $RM -rf $TESTDIR1
+       fi
+       log_must $ZFS create $rst_root
+       log_must $ZFS set mountpoint=$TESTDIR1 $rst_root
+}
+
+log_assert "Verifying 'zfs receive [<filesystem|snapshot>] -d <filesystem>' works."
+log_onexit cleanup
+
+typeset datasets="$TESTPOOL/$TESTFS $TESTPOOL"
+set -A bkup "/var/tmp/fullbkup" "/var/tmp/incbkup"
+orig_sum=""
+rst_sum=""
+rst_root=$TESTPOOL/rst_ctr
+rst_fs=${rst_root}/$TESTFS
+
+for orig_fs in $datasets ; do
+       #
+       # Preparations for testing
+       #
+       recreate_root
+
+       set -A orig_snap "${orig_fs}@init_snap" "${orig_fs}@inc_snap"
+       typeset mntpnt=$(get_prop mountpoint ${orig_fs})
+       set -A orig_data "${mntpnt}/$TESTFILE1" "${mntpnt}/$TESTFILE2"
+
+       typeset relative_path=""
+       if [[ ${orig_fs} == *"/"* ]]; then
+               relative_path=${orig_fs#*/}
+       fi
+
+       typeset leaf_fs=${rst_root}/${relative_path}
+       leaf_fs=${leaf_fs%/}
+       rst_snap=${leaf_fs}@snap
+
+       set -A rst_snap "$rst_root/$TESTFS@init_snap" "$rst_root/$TESTFS@inc_snap"
+       set -A rst_snap2 "${leaf_fs}@init_snap" "${leaf_fs}@inc_snap"
+       set -A rst_data "$TESTDIR1/$TESTFS/$TESTFILE1" "$TESTDIR1/$TESTFS/$TESTFILE2"
+       set -A rst_data2 "$TESTDIR1/${relative_path}/$TESTFILE1" "$TESTDIR1/${relative_path}/$TESTFILE2"
+
+       typeset -i i=0
+       while (( i < ${#orig_snap[*]} )); do
+               $FILE_WRITE -o create -f ${orig_data[$i]} -b 512 \
+                   -c 8 >/dev/null 2>&1
+               (( $? != 0 )) && \
+                       log_fail "Writing data into zfs filesystem fails."
+               log_must $ZFS snapshot ${orig_snap[$i]}
+               if (( i < 1 )); then
+                       log_must eval "$ZFS send ${orig_snap[$i]} > ${bkup[$i]}"
+               else
+                       log_must eval "$ZFS send -i ${orig_snap[(( i - 1 ))]} \
+                               ${orig_snap[$i]} > ${bkup[$i]}"
+               fi
+
+               (( i = i + 1 ))
+       done
+
+       log_note "Verifying 'zfs receive <filesystem>' works."
+       i=0
+       while (( i < ${#bkup[*]} )); do
+               if (( i > 0 )); then
+                       log_must $ZFS rollback ${rst_snap[0]}
+               fi
+               log_must eval "$ZFS receive $rst_fs < ${bkup[$i]}"
+               snapexists ${rst_snap[$i]} || \
+                       log_fail "Restoring filesystem fails. ${rst_snap[$i]} not exist"
+               compare_cksum ${orig_data[$i]} ${rst_data[$i]}
+
+               (( i = i + 1 ))
+       done
+
+       log_must $ZFS destroy -Rf $rst_fs
+
+       log_note "Verifying 'zfs receive <snapshot>' works."
+       i=0
+       while (( i < ${#bkup[*]} )); do
+               if (( i > 0 )); then
+                       log_must $ZFS rollback ${rst_snap[0]}
+               fi
+               log_must eval "$ZFS receive ${rst_snap[$i]} <${bkup[$i]}"
+               snapexists ${rst_snap[$i]} || \
+                       log_fail "Restoring filesystem fails. ${rst_snap[$i]} not exist"
+               compare_cksum ${orig_data[$i]} ${rst_data[$i]}
+
+               (( i = i + 1 ))
+       done
+
+       log_must $ZFS destroy -Rf $rst_fs
+
+       log_note "Verfiying 'zfs receive -d <filesystem>' works."
+
+       i=0
+       while (( i < ${#bkup[*]} )); do
+               if (( i > 0 )); then
+                       log_must $ZFS rollback ${rst_snap2[0]}
+               fi
+               log_must eval "$ZFS receive -d -F $rst_root <${bkup[$i]}"
+               snapexists ${rst_snap2[$i]} || \
+                       log_fail "Restoring filesystem fails. ${rst_snap2[$i]} not exist"
+               compare_cksum ${orig_data[$i]} ${rst_data2[$i]}
+
+               (( i = i + 1 ))
+       done
+
+       cleanup
+done
+
+log_pass "Verifying 'zfs receive [<filesystem|snapshot>] -d <filesystem>' succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_002_pos.ksh
new file mode 100755 (executable)
index 0000000..27f9ae2
--- /dev/null
@@ -0,0 +1,104 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verifying 'zfs receive <volume>' works.
+#
+# STRATEGY:
+#      1. Fill in volume with some data
+#      2. Create full and incremental send stream
+#      3. Restore the send stream
+#      4. Verify the restoring results.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset -i i=0
+       typeset ds
+
+       while (( i < ${#orig_snap[*]} )); do
+               snapexists ${rst_snap[$i]} && \
+                       log_must $ZFS destroy -f ${rst_snap[$i]}
+               snapexists ${orig_snap[$i]} && \
+                       log_must $ZFS destroy -f ${orig_snap[$i]}
+               [[ -e ${bkup[$i]} ]] && \
+                       log_must $RM -rf ${bkup[$i]}
+
+               (( i = i + 1 ))
+       done
+
+       for ds in $rst_vol $rst_root; do
+               datasetexists $ds && \
+                       log_must $ZFS destroy -Rf $ds
+       done
+}
+
+log_assert "Verifying 'zfs receive <volume>' works."
+log_onexit cleanup
+
+set -A orig_snap "$TESTPOOL/$TESTVOL@init_snap" "$TESTPOOL/$TESTVOL@inc_snap"
+set -A bkup "/var/tmp/fullbkup" "/var/tmp/incbkup"
+rst_root=$TESTPOOL/rst_ctr
+rst_vol=$rst_root/$TESTVOL
+set -A rst_snap "${rst_vol}@init_snap" "${rst_vol}@inc_snap"
+
+#
+# Preparations for testing
+#
+log_must $ZFS create $rst_root
+[[ ! -d $TESTDIR1 ]] && \
+       log_must $MKDIR -p $TESTDIR1
+log_must $ZFS set mountpoint=$TESTDIR1 $rst_root
+
+typeset -i i=0
+while (( i < ${#orig_snap[*]} )); do
+       log_must $ZFS snapshot ${orig_snap[$i]}
+       if (( i < 1 )); then
+               log_must eval "$ZFS send ${orig_snap[$i]} > ${bkup[$i]}"
+       else
+               log_must eval "$ZFS send -i ${orig_snap[(( i - 1 ))]} \
+                               ${orig_snap[$i]} > ${bkup[$i]}"
+       fi
+
+       (( i = i + 1 ))
+done
+
+i=0
+while (( i < ${#bkup[*]} )); do
+       log_must eval "$ZFS receive $rst_vol < ${bkup[$i]}"
+       ! datasetexists $rst_vol || ! snapexists ${rst_snap[$i]} && \
+               log_fail "Restoring volume fails."
+
+       (( i = i + 1 ))
+done
+
+log_pass "Verifying 'zfs receive <volume>' succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_003_pos.ksh
new file mode 100755 (executable)
index 0000000..e7d4bf4
--- /dev/null
@@ -0,0 +1,89 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs recv -F' to force rollback.
+#
+# STRATEGY:
+#      1. Create pool and fs.
+#      2. Create some files in fs and take a snapshot1.
+#      3. Create another files in fs and take snapshot2.
+#      4. Create incremental stream from snapshot1 to snapshot2.
+#      5. fs rollback to snapshot1 and modify fs.
+#      6. Verify 'zfs recv -F' can force rollback.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for snap in $snap2 $snap1; do
+               datasetexists $snap && log_must $ZFS destroy -rf $snap
+       done
+       for file in $ibackup $mntpnt/file1 $mntpnt/file2; do
+               [[ -f $file ]] && log_must $RM -f $file
+       done
+}
+
+log_assert "'zfs recv -F' to force rollback."
+log_onexit cleanup
+
+ibackup=/var/tmp/ibackup.$$
+fs=$TESTPOOL/$TESTFS; snap1=$fs@snap1; snap2=$fs@snap2
+
+mntpnt=$(get_prop mountpoint $fs) || log_fail "get_prop mountpoint $fs"
+log_must $MKFILE 10m $mntpnt/file1
+log_must $ZFS snapshot $snap1
+log_must $MKFILE 10m $mntpnt/file2
+log_must $ZFS snapshot $snap2
+
+log_must eval "$ZFS send -i $snap1 $snap2 > $ibackup"
+
+log_note "Verify 'zfs receive' succeed, if filesystem was not modified."
+log_must $ZFS rollback -r $snap1
+log_must eval "$ZFS receive $fs < $ibackup"
+if [[ ! -f $mntpnt/file1 || ! -f $mntpnt/file2 ]]; then
+       log_fail "'$ZFS receive' failed."
+fi
+
+log_note "Verify 'zfs receive' failed if filesystem was modified."
+log_must $ZFS rollback -r $snap1
+log_must $RM -rf $mntpnt/file1
+log_mustnot eval "$ZFS receive $fs < $ibackup"
+
+# Verify 'zfs receive -F' to force rollback whatever filesystem was modified.
+log_must $ZFS rollback -r $snap1
+log_must $RM -rf $mntpnt/file1
+log_must eval "$ZFS receive -F $fs < $ibackup"
+if [[ ! -f $mntpnt/file1 || ! -f $mntpnt/file2 ]]; then
+       log_fail "'$ZFS receive -F' failed."
+fi
+
+log_pass "'zfs recv -F' to force rollback passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_004_neg.ksh
new file mode 100755 (executable)
index 0000000..7f1c053
--- /dev/null
@@ -0,0 +1,115 @@
+#!/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_SUITE/tests/functional/cli_root/cli_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify 'zfs receive' fails with malformed parameters.
+#
+# STRATEGY:
+#      1. Denfine malformed parameters array
+#      2. Feed the malformed parameters to 'zfs receive'
+#      3. Verify the command should be failed
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset snap
+       typeset bkup
+
+       for snap in $init_snap $inc_snap $init_topsnap $inc_topsnap ; do
+               snapexists $snap && \
+                       log_must $ZFS destroy -Rf $snap
+       done
+
+       for bkup in $full_bkup $inc_bkup $full_topbkup $inc_topbkup; do
+               [[ -e $bkup ]] && \
+                       log_must $RM -f $bkup
+       done
+}
+
+log_assert "Verify that invalid parameters to 'zfs receive' are caught."
+log_onexit cleanup
+
+init_snap=$TESTPOOL/$TESTFS@initsnap
+inc_snap=$TESTPOOL/$TESTFS@incsnap
+full_bkup=/var/tmp/full_bkup.$$
+inc_bkup=/var/tmp/inc_bkup.$$
+
+init_topsnap=$TESTPOOL@initsnap
+inc_topsnap=$TESTPOOL@incsnap
+full_topbkup=/var/tmp/full_topbkup.$$
+inc_topbkup=/var/tmp/inc_topbkup.$$
+
+log_must $ZFS snapshot $init_topsnap
+log_must eval "$ZFS send $init_topsnap > $full_topbkup"
+log_must $TOUCH /$TESTPOOL/foo
+
+log_must $ZFS snapshot $inc_topsnap
+log_must eval "$ZFS send -i $init_topsnap $inc_topsnap > $inc_topbkup"
+log_must $TOUCH /$TESTPOOL/bar
+
+log_must $ZFS snapshot $init_snap
+log_must eval "$ZFS send $init_snap > $full_bkup"
+log_must $TOUCH /$TESTDIR/foo
+
+log_must $ZFS snapshot $inc_snap
+log_must eval "$ZFS send -i $init_snap $inc_snap > $inc_bkup"
+log_must $TOUCH /$TESTDIR/bar
+
+$SYNC
+
+set -A badargs \
+    "" "nonexistent-snap" "blah@blah" "-d" "-d nonexistent-dataset" \
+    "$TESTPOOL/$TESTFS" "$TESTPOOL1" "$TESTPOOL/fs@" "$TESTPOOL/fs@@mysnap" \
+    "$TESTPOOL/fs@@" "$TESTPOOL/fs/@mysnap" "$TESTPOOL/fs@/mysnap" \
+    "$TESTPOOL/nonexistent-fs/nonexistent-fs" "-d $TESTPOOL/nonexistent-fs" \
+    "-d $TESTPOOL/$TESTFS/nonexistent-fs"
+
+if is_global_zone ; then
+       typeset -i n=${#badargs[@]}
+       badargs[$n]="-d $TESTPOOL"
+fi
+
+typeset -i i=0
+while (( i < ${#badargs[*]} ))
+do
+       for bkup in $full_bkup $inc_bkup $full_topbkup $inc_topbkup ; do
+               log_mustnot eval "$ZFS receive ${badargs[i]} < $bkup"
+       done
+
+       (( i = i + 1 ))
+done
+
+log_pass "Invalid parameters to 'zfs receive' are caught as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_005_neg.ksh
new file mode 100755 (executable)
index 0000000..86bd944
--- /dev/null
@@ -0,0 +1,95 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify 'zfs receive' fails with unsupported scenarios.
+#      including:
+#      (1) Invalid send streams;
+#      (2) The received incremental send doesn't match the filesystem
+#          latest status.
+#
+# STRATEGY:
+#      1. Preparation for unsupported scenarios
+#      2. Execute 'zfs receive'
+#      3. Verify the results are failed
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset snap
+       typeset bkup
+
+       for snap in $init_snap $inc_snap; do
+               snapexists $snap && \
+                       log_must $ZFS destroy -f $snap
+       done
+
+       datasetexists $rst_root && \
+               log_must $ZFS destroy -Rf $rst_root
+
+       for bkup in $full_bkup $inc_bkup; do
+               [[ -e $bkup ]] && \
+                       log_must $RM -f $bkup
+       done
+}
+
+log_assert "Verify 'zfs receive' fails with unsupported scenarios."
+log_onexit cleanup
+
+init_snap=$TESTPOOL/$TESTFS@initsnap
+inc_snap=$TESTPOOL/$TESTFS@incsnap
+rst_root=$TESTPOOL/rst_ctr
+rst_init_snap=$rst_root/$TESTFS@init_snap
+rst_inc_snap=$rst_root/$TESTFS@inc_snap
+full_bkup=/var/tmp/full_bkup.$$
+inc_bkup=/var/tmp/inc_bkup.$$
+
+log_must $ZFS create $rst_root
+log_must $ZFS snapshot $init_snap
+log_must eval "$ZFS send $init_snap > $full_bkup"
+
+log_note "'zfs receive' fails with invalid send streams."
+log_mustnot eval "$ZFS receive $rst_init_snap < /dev/zero"
+log_mustnot eval "$ZFS receive -d $rst_root </dev/zero"
+
+log_must eval "$ZFS receive $rst_init_snap < $full_bkup"
+
+log_note "Unmatched send stream with restoring filesystem" \
+       " cannot be received."
+log_must $ZFS snapshot $inc_snap
+log_must eval "$ZFS send -i $init_snap $inc_snap > $inc_bkup"
+#make changes on the restoring filesystem
+log_must $TOUCH $ZFSROOT/$rst_root/$TESTFS/tmpfile
+log_mustnot eval "$ZFS receive $rst_inc_snap < $inc_bkup"
+log_mustnot eval "$ZFS receive -d $rst_root < $inc_bkup"
+
+log_pass "Unsupported scenarios to 'zfs receive' fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_006_pos.ksh
new file mode 100755 (executable)
index 0000000..8f973b1
--- /dev/null
@@ -0,0 +1,104 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs recv -d <fs>' should create ancestor filesystem if it does not
+#   exist and it should not fail if it exists
+#
+# STRATEGY:
+#      1. Create pool and fs.
+#      2. Create some files in fs and take snapshots.
+#      3. Keep the stream and restore the stream to the pool
+#      4. Verify receiving the stream succeeds, and the ancestor filesystem
+#         is created if it did not exist
+#      5. Verify receiving the stream still succeeds when ancestor filesystem
+#         exists
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for snap in $snap2 $snap1; do
+               datasetexists $snap && log_must $ZFS destroy -rf $snap
+       done
+       for file in $fbackup1 $fbackup2 $mntpnt/file1 $mntpnt/file2; do
+               [[ -f $file ]] && log_must $RM -f $file
+       done
+
+       if is_global_zone; then
+               datasetexists $TESTPOOL/$TESTFS/$TESTFS1 && \
+                       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS/$TESTFS1
+       else
+               datasetexists $TESTPOOL/${ZONE_CTR}0 && \
+                       log_must $ZFS destroy -rf $TESTPOOL/${ZONE_CTR}0
+       fi
+
+}
+
+log_assert "'zfs recv -d <fs>' should succeed no matter ancestor filesystem \
+       exists."
+log_onexit cleanup
+
+ancestor_fs=$TESTPOOL/$TESTFS
+fs=$TESTPOOL/$TESTFS/$TESTFS1
+snap1=$fs@snap1
+snap2=$fs@snap2
+fbackup1=/var/tmp/fbackup1.$$
+fbackup2=/var/tmp/fbackup2.$$
+
+datasetexists $ancestor_fs || \
+       log_must $ZFS create $ancestor_fs
+log_must $ZFS create $fs
+
+mntpnt=$(get_prop mountpoint $fs) || log_fail "get_prop mountpoint $fs"
+log_must $MKFILE 10m $mntpnt/file1
+log_must $ZFS snapshot $snap1
+log_must $MKFILE 10m $mntpnt/file2
+log_must $ZFS snapshot $snap2
+
+log_must eval "$ZFS send $snap1 > $fbackup1"
+log_must eval "$ZFS send $snap2 > $fbackup2"
+
+log_note "Verify 'zfs receive -d' succeed and create ancestor filesystem \
+        if it did not exist. "
+log_must $ZFS destroy -rf $ancestor_fs
+log_must eval "$ZFS receive -d $TESTPOOL < $fbackup1"
+is_global_zone || ancestor_fs=$TESTPOOL/${ZONE_CTR}0/$TESTFS
+datasetexists $ancestor_fs || \
+       log_fail "ancestor filesystem is not created"
+
+log_note "Verify 'zfs receive -d' still succeed if ancestor filesystem exists"
+is_global_zone || fs=$TESTPOOL/${ZONE_CTR}0/$TESTFS/$TESTFS1
+log_must $ZFS destroy -rf $fs
+log_must eval "$ZFS receive -d $TESTPOOL < $fbackup2"
+
+log_pass "'zfs recv -d <fs>' should succeed no matter ancestor filesystem \
+       exists."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_007_neg.ksh
new file mode 100755 (executable)
index 0000000..b2f6dc6
--- /dev/null
@@ -0,0 +1,80 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs recv -F' should fail if the incremental stream does not match
+#
+# STRATEGY:
+#      1. Create pool and fs.
+#      2. Create some files in fs and take snapshots.
+#      3. Keep the incremental stream and restore the stream to the pool
+#      4. Verify receiving the stream fails
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for snap in $snap2 $snap1; do
+               datasetexists $snap && log_must $ZFS destroy -rf $snap
+       done
+       for file in $ibackup $mntpnt/file1 $mntpnt/file2; do
+               [[ -f $file ]] && log_must $RM -f $file
+       done
+}
+
+log_assert "'zfs recv -F' should fail if the incremental stream does not match"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+snap1=$fs@snap1
+snap2=$fs@snap2
+ibackup=/var/tmp/ibackup.$$
+
+datasetexists $fs || log_must $ZFS create $fs
+
+mntpnt=$(get_prop mountpoint $fs) || log_fail "get_prop mountpoint $fs"
+log_must $MKFILE 10m $mntpnt/file1
+log_must $ZFS snapshot $snap1
+log_must $MKFILE 10m $mntpnt/file2
+log_must $ZFS snapshot $snap2
+
+log_must eval "$ZFS send -i $snap1 $snap2 > $ibackup"
+
+log_must $ZFS destroy $snap1
+log_must $ZFS destroy $snap2
+log_mustnot eval "$ZFS receive -F $fs < $ibackup"
+
+log_must $MKFILE 20m $mntpnt/file1
+log_must $RM -rf $mntpnt/file2
+log_must $ZFS snapshot $snap1
+log_mustnot eval "$ZFS receive -F $snap2 < $ibackup"
+
+log_pass "'zfs recv -F' should fail if the incremental stream does not match"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_008_pos.ksh
new file mode 100755 (executable)
index 0000000..6d9081e
--- /dev/null
@@ -0,0 +1,144 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verifying 'zfs receive -vn [<filesystem|snapshot>]
+#                 and zfs receive -vn -d <filesystem>'
+#
+# STRATEGY:
+#      1. Fill in fs with some data
+#      2. Create full and incremental send stream
+#      3. run zfs receive with -v option
+#      3. Dryrun zfs receive with -vn option
+#      3. Dryrun zfs receive with -vn -d option
+#      4. Verify receive output and result
+#
+function cleanup
+{
+       for dset in $rst_snap $rst_fs $orig_snap; do
+               if datasetexists $dset; then
+                       log_must $ZFS destroy -fr $dset
+               fi
+       done
+
+       for file in $fbackup $mnt_file $tmp_out; do
+               if [[ -f $file ]]; then
+                       log_must $RM -f $file
+               fi
+       done
+
+       if datasetexists $TESTPOOL/$TESTFS; then
+               log_must $ZFS destroy -Rf $TESTPOOL/$TESTFS
+               log_must $ZFS create $TESTPOOL/$TESTFS
+               log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+       fi
+}
+
+verify_runnable "both"
+log_assert "Verifying 'zfs receive -vn [<filesystem|snapshot>] " \
+               "and zfs receive -vn -d <filesystem>'"
+
+log_onexit cleanup
+
+typeset datasets="$TESTPOOL/$TESTFS $TESTPOOL"
+typeset rst_fs=$TESTPOOL/$TESTFS/$TESTFS
+typeset fbackup=/var/tmp/fbackup.$$
+typeset tmp_out=/var/tmp/tmpout.$$
+
+for orig_fs in $datasets ; do
+       typeset rst_snap=$rst_fs@snap
+       typeset orig_snap=$orig_fs@snap
+       typeset verb_msg="receiving full stream of ${orig_snap} into ${rst_snap}"
+       typeset dryrun_msg="would receive full stream of ${orig_snap} into ${rst_snap}"
+
+       if ! datasetexists $orig_fs; then
+               log_must $ZFS create $orig_fs
+       fi
+
+       typeset mntpnt
+       mntpnt=$(get_prop mountpoint $orig_fs)
+       if [[ $? -ne 0 ]] ; then
+               log_fail "get_prop mountpoint $orig_fs failed"
+       fi
+
+       typeset mnt_file=$mntpnt/file1
+
+       log_must $MKFILE 100m $mnt_file
+       log_must $ZFS snapshot $orig_snap
+       log_must eval "$ZFS send $orig_snap > $fbackup"
+
+       for opt in "-v"  "-vn"; do
+               if datasetexists $rst_fs; then
+                       log_must $ZFS destroy -fr $rst_fs
+               fi
+               log_note "Check ZFS receive $opt [<filesystem|snapshot>]"
+               log_must eval "$ZFS receive $opt $rst_fs < $fbackup > $tmp_out 2>&1"
+               if [[ $opt == "-v" ]]; then
+                       log_must eval "$GREP \"$verb_msg\" $tmp_out >/dev/null 2>&1"
+                       if ! datasetexists $rst_snap; then
+                               log_fail "dataset was not received, even though the"\
+                                       " -v flag was used."
+                       fi
+               else
+                       log_must eval "$GREP \"$dryrun_msg\" $tmp_out >/dev/null 2>&1"
+                       if datasetexists $rst_snap; then
+                               log_fail "dataset was received, even though the -nv"\
+                                       " flag was used."
+                       fi
+               fi
+       done
+
+       log_note "Check ZFS receive -vn -d <filesystem>"
+       if ! datasetexists $rst_fs; then
+               log_must $ZFS create $rst_fs
+       fi
+       log_must eval "$ZFS receive -vn -d -F $rst_fs <$fbackup >$tmp_out 2>&1"
+       typeset relative_path=""
+       if [[ ${orig_fs} == *"/"* ]]; then
+               relative_path=${orig_fs#*/}
+       fi
+
+       typeset leaf_fs=${rst_fs}/${relative_path}
+       leaf_fs=${leaf_fs%/}
+       rst_snap=${leaf_fs}@snap
+       dryrun_msg="would receive full stream of ${orig_snap} into ${rst_snap}"
+
+       log_must eval "$GREP \"$dryrun_msg\" $tmp_out > /dev/null 2>&1"
+
+       if datasetexists $rst_snap; then
+               log_fail "dataset $rst_snap should not existed."
+       fi
+       log_must $ZFS destroy -Rf $rst_fs
+
+       cleanup
+done
+
+log_pass "zfs receive -vn [<filesystem|snapshot>] and " \
+       "zfs receive -vn -d <filesystem>' succeed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_009_neg.ksh
new file mode 100755 (executable)
index 0000000..8d4b89b
--- /dev/null
@@ -0,0 +1,114 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify 'zfs receive' fails with bad options, missing argument or too many
+#      arguments.
+#
+# STRATEGY:
+#      1. Set a array of illegal arguments
+#      2. Execute 'zfs receive' with illegal arguments
+#      3. Verify the command should be failed
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset ds
+
+       if snapexists $snap; then
+               log_must $ZFS destroy $snap
+       fi
+       for ds in $ctr1 $ctr2 $fs1; do
+               if datasetexists $ds; then
+                       log_must $ZFS destroy -rf $ds
+               fi
+       done
+       if [[ -d $TESTDIR2 ]]; then
+               $RM -rf $TESTDIR2
+       fi
+}
+
+log_assert "Verify 'zfs receive' fails with bad option, missing or too many arguments"
+log_onexit cleanup
+
+set -A badopts "v" "n" "F" "d" "-V" "-N" "-f" "-D" "-VNfD" "-vNFd" "-vnFD" "-dVnF" \
+               "-vvvNfd" "-blah" "-12345" "-?" "-*" "-%"
+set -A validopts "" "-v" "-n" "-F" "-vn" "-nF" "-vnF" "-vd" "-nd" "-Fd" "-vnFd"
+
+ctr1=$TESTPOOL/$TESTCTR1
+ctr2=$TESTPOOL/$TESTCTR2
+fs1=$TESTPOOL/$TESTFS1
+fs2=$TESTPOOL/$TESTFS2
+fs3=$TESTPOOL/$TESTFS3
+snap=$TESTPOOL/$TESTFS@$TESTSNAP
+bkup=$TESTDIR2/bkup.$$
+
+# Preparations for negative testing
+for ctr in $ctr1 $ctr2; do
+       log_must $ZFS create $ctr
+done
+if [[ -d $TESTDIR2 ]]; then
+       $RM -rf $TESTDIR2
+fi
+log_must $ZFS create -o mountpoint=$TESTDIR2 $fs1
+log_must $ZFS snapshot $snap
+log_must eval "$ZFS send $snap > $bkup"
+
+#Testing zfs receive fails with input from terminal
+log_mustnot eval "$ZFS recv $fs3 </dev/console"
+
+# Testing with missing argument and too many arguments
+typeset -i i=0
+while (( i < ${#validopts[*]} )); do
+       log_mustnot eval "$ZFS recv < $bkup"
+
+       $ECHO ${validopts[i]} | $GREP "d" >/dev/null 2>&1
+       if (( $? != 0 )); then
+               log_mustnot eval "$ZFS recv ${validopts[i]} $fs2 $fs3 < $bkup"
+       else
+               log_mustnot eval "$ZFS recv ${validopts[i]} $ctr1 $ctr2 < $bkup"
+       fi
+
+       (( i += 1 ))
+done
+
+# Testing with bad options
+i=0
+while (( i < ${#badopts[*]} ))
+do
+       log_mustnot eval "$ZFS recv ${badopts[i]} $ctr1 < $bkup"
+       log_mustnot eval "$ZFS recv ${badopts[i]} $fs2 < $bkup"
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs receive' as expected with bad options, missing or too many arguments."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh
new file mode 100755 (executable)
index 0000000..511463f
--- /dev/null
@@ -0,0 +1,177 @@
+#!/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 (c) 2015, 2016 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Test that receiving a full send as a clone works correctly.
+#
+# STRATEGY:
+# 1. Create pool and filesystems.
+# 2. Send filesystem, receive as clone of itself.
+# 3. Verify that nop-write saves space.
+# 4. Send filesystem, receive as clone of other filesystem.
+# 5. Verify that contents are correct.
+# 6. Repeat steps 4 and 5 with filesystems swapped.
+#
+
+verify_runnable "both"
+
+fs=$TESTPOOL/$TESTFS/base/fs
+fs2=$TESTPOOL/$TESTFS/base/fs2
+rfs=$TESTPOOL/$TESTFS/base/rfs
+
+function make_object
+{
+       local objnum=$1
+       local mntpnt=$2
+       local type=$3
+       if [[ $type == "file" ]]; then
+               $DD if=/dev/urandom of=${mntpnt}/f$objnum bs=512 count=16
+       elif [[ $type == "hole1" ]]; then
+               $DD if=/dev/urandom of=${mntpnt}/fh$objnum bs=512 count=5 stride=4
+       elif [[ $type == "hole2" ]]; then
+               $DD if=/dev/urandom of=${mntpnt}/fh$objnum bs=512 count=4 stride=5
+       elif [[ $type == "directory" ]]; then
+               $MKDIR ${mntpnt}/d$objnum
+       elif [[ $type == "missing" ]]; then
+               $TOUCH ${mntpnt}/h$objnum
+       fi
+}
+
+function create_pair
+{
+       local objnum=$1
+       local mntpnt1=$2
+       local mntpnt2=$3
+       local type1=$4
+       local type2=$5
+       make_object $objnum $mntpnt1 $type1
+       make_object $objnum $mntpnt2 $type2
+}
+
+function cleanup
+{
+       $ZFS destroy -Rf $TESTPOOL/$TESTFS/base
+       rm /tmp/zr010p*
+}
+
+log_assert "zfs receive of full send as clone should work"
+log_onexit cleanup
+log_must $ZFS create -o checksum=sha256 -o compression=gzip -o recordsize=512 \
+       $TESTPOOL/$TESTFS/base
+
+log_must $ZFS create $fs
+log_must $ZFS create $fs2
+mntpnt=$(get_prop mountpoint $fs)
+mntpnt2=$(get_prop mountpoint $fs2)
+
+#
+# Now, we create the two filesystems.  By creating objects with
+# different types and the same object number in each filesystem, we
+# create a situation where, when you receive the full send of each as
+# a clone of the other, we will test to ensure that the code correctly
+# handles receiving all object types onto all other object types.
+#
+
+# Receive a file onto a file (and vice versa).
+create_pair 8 $mntpnt $mntpnt2 "file" "file"
+
+# Receive a file onto a file with holes (and vice versa).
+create_pair 9 $mntpnt $mntpnt2 "file" "hole1"
+
+# Receive a file onto a directory (and vice versa).
+create_pair 10 $mntpnt $mntpnt2 "file" "directory"
+
+# Receive a file onto a missing object (and vice versa).
+create_pair 11 $mntpnt $mntpnt2 "file" "missing"
+
+# Receive a file with holes onto a file with holes (and vice versa).
+create_pair 12 $mntpnt $mntpnt2 "hole1" "hole2"
+
+# Receive a file with holes onto a directory (and vice versa).
+create_pair 13 $mntpnt $mntpnt2 "hole1" "directory"
+
+# Receive a file with holes onto a missing object (and vice versa).
+create_pair 14 $mntpnt $mntpnt2 "hole1" "missing"
+
+# Receive a directory onto a directory (and vice versa).
+create_pair 15 $mntpnt $mntpnt2 "directory" "directory"
+
+# Receive a directory onto a missing object (and vice versa).
+create_pair 16 $mntpnt $mntpnt2 "directory" "missing"
+
+# Receive a missing object onto a missing object (and vice versa).
+create_pair 17 $mntpnt $mntpnt2 "missing" "missing"
+
+# Receive a file with a different record size onto a file (and vice versa).
+log_must $ZFS set recordsize=128k $fs
+$DD if=/dev/urandom of=$mntpnt/f18 bs=128k count=64
+$TOUCH $mntpnt2/f18
+
+# Remove objects that are intended to be missing.
+$RM $mntpnt/h17
+$RM $mntpnt2/h*
+
+# Add empty objects to $fs to exercise dmu_traverse code
+for i in {1..100}; do
+       log_must touch $mntpnt/uf$i
+done
+
+log_must $ZFS snapshot $fs@s1
+log_must $ZFS snapshot $fs2@s1
+
+log_must $ZFS send $fs@s1 > /tmp/zr010p
+log_must $ZFS send $fs2@s1 > /tmp/zr010p2
+
+
+#
+# Test that, when we receive a full send as a clone of itself,
+# nop-write saves us all the space used by data blocks.
+#
+cat /tmp/zr010p | log_must $ZFS receive -o origin=$fs@s1 $rfs
+size=$(get_prop used $rfs)
+size2=$(get_prop used $fs)
+if [[ $size -ge $(($size2 / 10)) ]] then
+        log_fail "nop-write failure; expected usage less than "\
+               "$(($size2 / 10)), but is using $size"
+fi
+log_must $ZFS destroy -fr $rfs
+
+# Correctness testing: receive each full send as a clone of the other fiesystem.
+cat /tmp/zr010p | log_must $ZFS receive -o origin=$fs2@s1 $rfs
+mntpnt_old=$(get_prop mountpoint $fs)
+mntpnt_new=$(get_prop mountpoint $rfs)
+log_must $DIFF -r $mntpnt_old $mntpnt_new
+log_must $ZFS destroy -r $rfs
+
+cat /tmp/zr010p2 | log_must $ZFS receive -o origin=$fs@s1 $rfs
+mntpnt_old=$(get_prop mountpoint $fs2)
+mntpnt_new=$(get_prop mountpoint $rfs)
+log_must $DIFF -r $mntpnt_old $mntpnt_new
+
+log_pass "zfs receive of full send as clone works"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_011_pos.ksh
new file mode 100755 (executable)
index 0000000..b905a87
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      refquota should be sent-and-received, but it should not interfere with
+#      the receipt of intermediate snapshots that may have preceded the
+#      final snapshot, where the refquota should hold.
+#
+# STRATEGY:
+#      1. Create a filesystem.
+#      2. Create two equal-sized large files.
+#      3. Snapshot the filesystem.
+#      4. Remove one of the two large files.
+#      5. Create a refquota larger than one file, but smaller than both.
+#      6. Snapshot the filesystem again.
+#      7. Send a replication stream of the second snapshot to a new filesystem.
+#
+#
+
+verify_runnable "both"
+
+typeset streamfile=/var/tmp/streamfile.$$
+
+function cleanup
+{
+       log_must $RM $streamfile
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS1
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS2
+}
+
+log_assert "refquota is properly sent-and-received, regardless of any " \
+       "intermediate snapshots sent by a replication stream."
+log_onexit cleanup
+
+orig=$TESTPOOL/$TESTFS1
+dest=$TESTPOOL/$TESTFS2
+#      1. Create a filesystem.
+log_must $ZFS create $orig
+origdir=$(get_prop mountpoint $orig)
+
+#      2. Create two equal-sized large files.
+log_must $MKFILE 5M $origdir/file1
+log_must $MKFILE 5M $origdir/file2
+log_must $SYNC
+
+#      3. Snapshot the filesystem.
+log_must $ZFS snapshot $orig@1
+
+#      4. Remove one of the two large files.
+log_must $RM $origdir/file2
+log_must $SYNC
+
+#      5. Create a refquota larger than one file, but smaller than both.
+log_must $ZFS set refquota=8M $orig
+
+#      6. Snapshot the filesystem again.
+log_must $ZFS snapshot $orig@2
+
+#      7. Send a replication stream of the second snapshot to a new filesystem.
+log_must eval "$ZFS send -R $orig@2 > $streamfile"
+log_must eval "$ZFS recv $dest < $streamfile"
+
+log_pass "refquota is properly sent-and-received, regardless of any " \
+       "intermediate snapshots sent by a replication stream."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_012_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_012_pos.ksh
new file mode 100755 (executable)
index 0000000..af9f91e
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2016, OmniTI Computer Consulting, Inc. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      refquota, like regular quota, is loosely enforced.  A dataset
+#      can exceed its refquota by one transaction.  This loose enforcement
+#      used to cause problems upon receiving a datastream where its
+#      refquota is slightly exceeded.  This test confirms that we can
+#      successfully receive a slightly over refquota stream.
+#
+# STRATEGY:
+#      1. Create a filesystem.
+#      2. Set a refquota.
+#      3. Snapshot the filesystem.
+#      4. Send a replication stream to a new filesystem.
+#      5. On the original filesystem, fill it up to its quota.
+#      6. Snapshot the original filesystem again.
+#      7. Send an incremental stream to the same new filesystem.
+#
+
+verify_runnable "both"
+
+typeset streamfile=/var/tmp/streamfile.$$
+
+function cleanup
+{
+       log_must $RM $streamfile
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS1
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS2
+}
+
+log_assert "The allowable slight refquota overage is properly sent-and-" \
+       "received."
+log_onexit cleanup
+
+orig=$TESTPOOL/$TESTFS1
+dest=$TESTPOOL/$TESTFS2
+
+#      1. Create a filesystem.
+log_must $ZFS create $orig
+origdir=$(get_prop mountpoint $orig)
+
+#      2. Set a refquota.
+log_must $ZFS set refquota=50M $orig
+
+#      3. Snapshot the filesystem.
+log_must $ZFS snapshot $orig@1
+
+#      4. Send a replication stream to a new filesystem.
+log_must eval "$ZFS send -R $orig@1 > $streamfile"
+log_must eval "$ZFS recv $dest < $streamfile"
+
+#      5. On the original filesystem, fill it up to its quota.
+cat < /dev/urandom > $origdir/fill-it-up
+
+#      6. Snapshot the original filesystem again.
+log_must $ZFS snapshot $orig@2
+
+#      7. Send an incremental stream to the same new filesystem.
+log_must eval "$ZFS send -I 1 -R $orig@2 > $streamfile"
+log_must eval "$ZFS recv $dest < $streamfile"
+
+log_pass "Verified receiving a slightly-over-refquota stream succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_013_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_013_pos.ksh
new file mode 100755 (executable)
index 0000000..11081bb
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2016, loli10K. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify ZFS can receive custom properties on both filesystems and
+#      snapshots from full and incremental streams.
+#
+# STRATEGY:
+#      1. Create a filesystem.
+#      2. Snapshot the filesystem.
+#      3. Set custom properties on both the fs and snapshots.
+#      4. Create different send streams with the properties.
+#      5. Receive the send streams and verify the properties.
+#
+
+verify_runnable "both"
+
+typeset streamfile_full=/var/tmp/streamfile_full.$$
+typeset streamfile_incr=/var/tmp/streamfile_incr.$$
+orig=$TESTPOOL/$TESTFS1
+dest=$TESTPOOL/$TESTFS2
+typeset user_prop=$(valid_user_property 8)
+typeset value=$(user_property_value 8)
+
+function cleanup
+{
+       log_must $RM $streamfile_full
+       log_must $RM $streamfile_incr
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS1
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS2
+}
+
+log_assert "ZFS can receive custom properties."
+log_onexit cleanup
+
+#      1. Create a filesystem.
+log_must $ZFS create $orig
+
+#      2. Snapshot the filesystem.
+log_must $ZFS snapshot $orig@snap1
+log_must $ZFS snapshot $orig@snap2
+log_must $ZFS snapshot $orig@snap3
+
+#      3. Set custom properties on both the fs and snapshots.
+log_must eval "$ZFS set '$user_prop'='$value' $orig"
+log_must eval "$ZFS set '$user_prop:snap1'='$value:snap1' $orig@snap1"
+log_must eval "$ZFS set '$user_prop:snap2'='$value:snap2' $orig@snap2"
+log_must eval "$ZFS set '$user_prop:snap3'='$value:snap3' $orig@snap3"
+
+#      4. Create different send streams with the properties.
+log_must eval "$ZFS send -p $orig@snap1 > $streamfile_full"
+log_must eval "$ZFS send -p -I $orig@snap1 $orig@snap3 > $streamfile_incr"
+
+#      5. Receive the send streams and verify the properties.
+log_must eval "$ZFS recv $dest < $streamfile_full"
+log_must eval "check_user_prop $dest $user_prop '$value'"
+log_must eval "check_user_prop $dest@snap1 '$user_prop:snap1' '$value:snap1'"
+log_must eval "$ZFS recv $dest < $streamfile_incr"
+log_must eval "check_user_prop $dest@snap2 '$user_prop:snap2' '$value:snap2'"
+log_must eval "check_user_prop $dest@snap3 '$user_prop:snap3' '$value:snap3'"
+
+log_pass "ZFS can receive custom properties passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/Makefile.am
new file mode 100644 (file)
index 0000000..fec9560
--- /dev/null
@@ -0,0 +1,19 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_rename
+dist_pkgdata_SCRIPTS = \
+       zfs_rename.cfg \
+       zfs_rename.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_rename_001_pos.ksh \
+       zfs_rename_002_pos.ksh \
+       zfs_rename_003_pos.ksh \
+       zfs_rename_004_neg.ksh \
+       zfs_rename_005_neg.ksh \
+       zfs_rename_006_pos.ksh \
+       zfs_rename_007_pos.ksh \
+       zfs_rename_008_pos.ksh \
+       zfs_rename_009_neg.ksh \
+       zfs_rename_010_neg.ksh \
+       zfs_rename_011_pos.ksh \
+       zfs_rename_012_neg.ksh \
+       zfs_rename_013_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/cleanup.ksh
new file mode 100755 (executable)
index 0000000..9316154
--- /dev/null
@@ -0,0 +1,39 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup_noexit
+
+if [[ -d $TESTDIR2 ]]; then
+        $RM -rf $TESTDIR2
+        if (( $? != 0 )); then
+                log_unresolved Could not remove $TESTDIR2
+        fi
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/setup.ksh
new file mode 100755 (executable)
index 0000000..dee3af8
--- /dev/null
@@ -0,0 +1,49 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
+
+DISK=${DISKS%% *}
+
+default_setup_noexit "$DISK" "true" "true"
+
+if [[ -d $TESTDIR2 ]]; then
+       $RM -rf $TESTDIR2
+       if (( $? != 0 )); then
+               log_unresolved Could not remove $TESTDIR2
+       fi
+fi
+log_must $ZFS create $TESTPOOL/$DATAFS
+log_must $ZFS set mountpoint=$TESTDIR2 $TESTPOOL/$DATAFS
+log_must eval "$DD if=$IF of=$OF bs=$BS count=$CNT >/dev/null 2>&1"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.cfg
new file mode 100644 (file)
index 0000000..8c33b58
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+export DATAFS=datafs.rename
+export DATA=$TESTDIR2/data.rename
+export IF=/dev/urandom
+export OF=$DATA
+export BS=512
+export CNT=2048
+export VOL_R_PATH=$ZVOL_RDEVDIR/$TESTPOOL/$TESTVOL
+export VOLDATA=$TESTDIR2/voldata.rename
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
new file mode 100644 (file)
index 0000000..d2a6a22
--- /dev/null
@@ -0,0 +1,124 @@
+#
+# 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_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.cfg
+
+function additional_setup
+{
+       # Create testfile
+       log_must $CP $DATA $TESTDIR/$TESTFILE0
+       log_must $CP $DATA $TESTDIR1/$TESTFILE0
+
+       # Create snapshot
+       if ! snapexists $TESTPOOL/$TESTFS@snapshot; then
+               log_must $ZFS snapshot $TESTPOOL/$TESTFS@snapshot
+               log_must $ZFS clone $TESTPOOL/$TESTFS@snapshot \
+                   $TESTPOOL/$TESTFS-clone
+       fi
+
+       # Create file system
+       datasetexists $TESTPOOL/$TESTFS1 || \
+               log_must $ZFS create $TESTPOOL/$TESTFS1
+
+       # Create testfile
+       log_must $CP $DATA $(get_prop mountpoint $TESTPOOL/$TESTFS1)/$TESTFILE0
+
+       # Create container
+       datasetexists $TESTPOOL/$TESTCTR1 || \
+               log_must $ZFS create $TESTPOOL/$TESTCTR1
+       log_must $CP $DATA $(get_prop mountpoint $TESTPOOL/$TESTCTR1)/$TESTFILE0
+
+       # Create data in zvol
+       if is_global_zone; then
+               log_must eval "$DD if=$DATA of=$VOL_R_PATH bs=$BS count=$CNT \
+                               >/dev/null 2>&1"
+       else
+               log_must $CP $DATA $(get_prop mountpoint $TESTPOOL/$TESTVOL)/$TESTFILE0
+       fi
+
+}
+
+function rename_dataset # src dest
+{
+       typeset src=$1
+       typeset dest=$2
+
+       log_must $ZFS rename $src $dest
+       block_device_wait
+
+       #
+       # Verify src name no longer in use
+       #
+       log_mustnot datasetexists $src
+       log_must datasetexists $dest
+}
+
+function cleanup
+{
+       typeset -i i=0
+       while ((i < ${#dataset[*]} )); do
+               if ! datasetexists ${dataset[i]}-new ; then
+                       ((i = i + 1))
+                       continue
+               fi
+
+                if [[ ${dataset[i]}-new != *@* ]] ; then
+                        $ZFS rename ${dataset[i]}-new ${dataset[i]}
+                        if [[ $? -ne 0 ]]; then
+                                typeset newfs=${dataset[i]}-new
+                                typeset oldfs=${dataset[i]}
+                                typeset mntp=$(get_prop mountpoint  $newfs)
+                                log_must $ZFS destroy -f $newfs
+                                log_must $ZFS create -p $oldfs
+                                log_must $ZFS set mountpoint=$mntp $oldfs
+                        fi
+                else
+                        log_must $ZFS destroy -fR ${dataset[i]}-new
+                fi
+
+                ((i = i + 1))
+       done
+
+       if snapexists $TESTPOOL/$TESTFS@snapshot; then
+               log_must $ZFS destroy -fR $TESTPOOL/$TESTFS@snapshot
+       fi
+
+}
+
+function cmp_data #<$1 src data, $2 tgt data>
+{
+        typeset src=$1
+        typeset tgt=$2
+
+        $CMP $src $tgt >/dev/null 2>&1
+
+        return $?
+}
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_001_pos.ksh
new file mode 100755 (executable)
index 0000000..dc178c4
--- /dev/null
@@ -0,0 +1,104 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
+
+#
+# DESCRIPTION:
+#       'zfs rename' should successfully rename valid datasets.
+#       As a sub-assertion we check to ensure the datasets that can
+#       be mounted are mounted.
+#
+# STRATEGY:
+#       1. Given a file system, snapshot and volume.
+#       2. Rename each dataset object to a new name.
+#       3. Verify that only the new name is displayed by zfs list.
+#       4. Verify mountable datasets are mounted.
+#
+###############################################################################
+
+verify_runnable "both"
+
+set -A dataset "$TESTPOOL/$TESTFS@snapshot" "$TESTPOOL/$TESTFS1" \
+   "$TESTPOOL/$TESTCTR/$TESTFS1" "$TESTPOOL/$TESTCTR1" \
+    "$TESTPOOL/$TESTVOL" "$TESTPOOL/$TESTFS-clone"
+set -A mountable "$TESTPOOL/$TESTFS1-new" "$TESTPOOL/$TESTFS@snapshot-new" \
+    "$TESTPOOL/$TESTCTR/$TESTFS1-new" "$TESTPOOL/$TESTFS-clone-new"
+
+#
+# cleanup defined in zfs_rename.kshlib
+#
+log_onexit cleanup
+
+log_assert "'zfs rename' should successfully rename valid datasets"
+
+additional_setup
+
+typeset -i i=0
+while (( i < ${#dataset[*]} )); do
+       rename_dataset ${dataset[i]} ${dataset[i]}-new
+
+       ((i = i + 1))
+done
+
+log_note "Verify mountable datasets are mounted in their new namespace."
+typeset mtpt
+i=0
+while (( i < ${#mountable[*]} )); do
+       # Snapshot have no mountpoint
+       if [[ ${mountable[i]} != *@* ]]; then
+               log_must mounted ${mountable[i]}
+               mtpt=$(get_prop mountpoint ${mountable[i]})
+       else
+               mtpt=$(snapshot_mountpoint ${mountable[i]})
+       fi
+
+       if ! cmp_data $DATA $mtpt/$TESTFILE0 ; then
+               log_fail "$mtpt/$TESTFILE0 gets corrupted after rename operation."
+       fi
+
+       ((i = i + 1))
+done
+
+#verify the data integrity in zvol
+if is_global_zone; then
+       log_must eval "$DD if=${VOL_R_PATH}-new of=$VOLDATA bs=$BS count=$CNT >/dev/null 2>&1"
+       if ! cmp_data $VOLDATA $DATA ; then
+               log_fail "$VOLDATA gets corrupted after rename operation."
+       fi
+fi
+
+# rename back fs
+typeset -i i=0
+while ((i < ${#dataset[*]} )); do
+       if datasetexists ${dataset[i]}-new ; then
+                log_must $ZFS rename ${dataset[i]}-new ${dataset[i]}
+       fi
+        ((i = i + 1))
+done
+
+log_pass "'zfs rename' successfully renamed each dataset type."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_002_pos.ksh
new file mode 100755 (executable)
index 0000000..6646df5
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
+
+#
+# DESCRIPTION:
+#       'zfs rename' should successfully be capable of renaming
+#       valid datasets back and forth multiple times.
+#
+# STRATEGY:
+#       1. Given a file system, snapshot and volume.
+#       2. Rename each dataset object to a new name.
+#       3. Rename each dataset back to its original name.
+#       4. Repeat steps 2 and 3 multiple times.
+#       5. Verify that the correct name is displayed by zfs list.
+#
+###############################################################################
+
+verify_runnable "both"
+
+set -A dataset "$TESTPOOL/$TESTFS@snapshot" "$TESTPOOL/$TESTFS1" \
+   "$TESTPOOL/$TESTCTR/$TESTFS1" "$TESTPOOL/$TESTCTR1" \
+    "$TESTPOOL/$TESTVOL" "$TESTPOOL/$TESTFS-clone"
+
+#
+# cleanup defined in zfs_rename.kshlib
+#
+log_onexit cleanup
+
+log_assert "'zfs rename' should successfully rename valid datasets"
+
+additional_setup
+
+typeset -i i=0
+typeset -i iters=10
+
+while ((i < ${#dataset[*]} )); do
+       j=0
+       while ((j < iters )); do
+               rename_dataset ${dataset[i]} ${dataset[i]}-new
+               rename_dataset ${dataset[i]}-new ${dataset[i]}
+
+               ((j = j + 1))
+       done
+
+       if [[ ${dataset[i]} == *@* ]]; then
+               data=$(snapshot_mountpoint ${dataset[i]})/$TESTFILE0
+       elif [[ ${dataset[i]} == "$TESTPOOL/$TESTVOL" ]] && is_global_zone; then
+               log_must eval "$DD if=$VOL_R_PATH of=$VOLDATA bs=$BS count=$CNT >/dev/null 2>&1"
+               data=$VOLDATA
+       else
+               data=$(get_prop mountpoint ${dataset[i]})/$TESTFILE0
+       fi
+
+       if ! cmp_data $DATA $data; then
+               log_fail "$data gets corrupted after $iters times rename operations."
+       fi
+
+       ((i = i + 1))
+done
+
+log_pass "'zfs rename' renamed each dataset type multiple times as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_003_pos.ksh
new file mode 100755 (executable)
index 0000000..9660641
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs rename' can address the abbreviated snapshot name.
+#
+# STRATEGY:
+#      1. Create pool, fs and snap.
+#      2. Verify 'zfs rename' support the abbreviated snapshot name.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $snap && log_must $ZFS destroy $snap
+}
+
+log_assert "'zfs rename' can address the abbreviated snapshot name."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS; snap=$fs@snap
+set -A newname "$fs@new-snap" "@new-snap" "new-snap"
+
+log_must $ZFS snapshot $snap
+log_must datasetexists $snap
+
+typeset -i i=0
+while ((i < ${#newname[*]} )); do
+        log_must $ZFS rename $snap ${newname[$i]}
+       log_must datasetexists ${snap%%@*}@${newname[$i]##*@}
+       log_must $ZFS rename ${snap%%@*}@${newname[$i]##*@} $snap
+
+       ((i += 1))
+done
+
+log_pass "'zfs rename' address the abbreviated snapshot name passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_004_neg.ksh
new file mode 100755 (executable)
index 0000000..19f8a80
--- /dev/null
@@ -0,0 +1,107 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
+
+#
+# DESCRIPTION:
+#       'zfs rename' should fail when this dataset was changed to an existed
+#      dataset name or datasets are of different types.
+#       For example, a filesystem cannot be renamed as a volume.
+#
+# STRATEGY:
+#       1. Given a file system, snapshot and volume.
+#       2. Rename each dataset object to a different type.
+#       3. Verify that only the original name is displayed by zfs list.
+#
+
+verify_runnable "both"
+
+#
+# This array is a list of pairs:
+#      item i: original type
+#      item i + 1: new type
+#
+set -A bad_dataset $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTCTR1 \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTCTR/$TESTFS1 \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS1 \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS@snapshot \
+       $TESTPOOL/$TESTCTR1 $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTCTR1 $TESTPOOL/$TESTFS@snapshot \
+       $TESTPOOL/$TESTCTR1 $TESTPOOL/$TESTFS1 \
+       $TESTPOOL/$TESTCTR1 $TESTPOOL/$TESTCTR/$TESTFS1 \
+       $TESTPOOL/$TESTCTR/$TESTFS1  $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTCTR/$TESTFS1  $TESTPOOL/$TESTFS@snapshot \
+       $TESTPOOL/$TESTCTR/$TESTFS1  $TESTPOOL/$TESTFS1 \
+       $TESTPOOL/$TESTCTR/$TESTFS1  $TESTPOOL/$TESTCTR1 \
+       $TESTPOOL/$TESTVOL $TESTPOOL/$TESTCTR1 \
+       $TESTPOOL/$TESTVOL $TESTPOOL/$TESTFS@snapshot \
+       $TESTPOOL/$TESTVOL $TESTPOOL/$TESTFS1 \
+       $TESTPOOL/$TESTVOL $TESTPOOL/$TESTCTR/$TESTFS1 \
+       $TESTPOOL/$TESTFS@snapshot $TESTPOOL/$TESTCTR1 \
+       $TESTPOOL/$TESTFS@snapshot $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTFS@snapshot $TESTPOOL/$TESTFS1 \
+       $TESTPOOL/$TESTFS@snapshot $TESTPOOL/$TESTCTR/$TESTFS1 \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/${TESTFS1}%c \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/${TESTFS1}%d \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/${TESTFS1}%x \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/${TESTFS1}%p \
+       $TESTPOOL/$TESTFS1 $TESTPOOL/${TESTFS1}%s \
+       $TESTPOOL/$TESTFS@snapshot \
+       $TESTPOOL/$TESTFS@snapshot/fs
+
+#
+# cleanup defined in zfs_rename.kshlib
+#
+log_onexit cleanup
+
+log_assert "'zfs rename' should fail when datasets are of a different type."
+
+additional_setup
+
+typeset -i i=0
+while ((i < ${#bad_dataset[*]} )); do
+        log_mustnot $ZFS rename ${bad_dataset[i]} ${bad_dataset[((i + 1))]}
+        log_must datasetexists ${bad_dataset[i]}
+
+        log_mustnot $ZFS rename -p ${bad_dataset[i]} ${bad_dataset[((i + 1))]}
+        log_must datasetexists ${bad_dataset[i]}
+
+       ((i = i + 2))
+done
+
+#verify 'rename -p' can not work with snapshots
+
+log_mustnot $ZFS rename -p $TESTPOOL/$TESTFS@snapshot \
+               $TESTPOOL/$TESTFS@snapshot2
+log_must datasetexists $TESTPOOL/$TESTFS@snapshot
+log_mustnot $ZFS rename -p $TESTPOOL/$TESTFS@snapshot \
+               $TESTPOOL/$TESTFS/$TESTFS@snapshot2
+log_must datasetexists $TESTPOOL/$TESTFS@snapshot
+
+log_pass "'zfs rename' fails as expected when given different dataset types."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_005_neg.ksh
new file mode 100755 (executable)
index 0000000..6010af1
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
+
+#
+# DESCRIPTION:
+#       'zfs rename' should fail when the dataset are not within the same pool
+#
+# STRATEGY:
+#       1. Given a file system, snapshot and volume.
+#       2. Rename each dataset object to a different pool.
+#       3. Verify the operation fails, and only the original name
+#         is displayed by zfs list.
+#
+
+verify_runnable "global"
+
+function my_cleanup
+{
+       poolexists $TESTPOOL1 && \
+               destroy_pool $TESTPOOL1
+       [[ -e $TESTDIR/$TESTFILE1 ]] && \
+               log_must $RM -f $TESTDIR/$TESTFILE1
+       cleanup
+}
+
+set -A src_dataset \
+    "$TESTPOOL/$TESTFS1" "$TESTPOOL/$TESTCTR1" \
+    "$TESTPOOL/$TESTCTR/$TESTFS1" "$TESTPOOL/$TESTVOL" \
+    "$TESTPOOL/$TESTFS@snapshot" "$TESTPOOL/$TESTFS-clone"
+
+#
+# cleanup defined in zfs_rename.kshlib
+#
+log_onexit my_cleanup
+
+log_assert "'zfs rename' should fail while datasets are within different pool."
+
+additional_setup
+
+typeset FILESIZE=64m
+log_must $MKFILE $FILESIZE $TESTDIR/$TESTFILE1
+create_pool $TESTPOOL1 $TESTDIR/$TESTFILE1
+
+for src in ${src_dataset[@]} ; do
+       dest=${src#$TESTPOOL/}
+       if [[ $dest == *"@"* ]]; then
+               dest=${dest#*@}
+               dest=${TESTPOOL1}@$dest
+       else
+               dest=${TESTPOOL1}/$dest
+       fi
+       log_mustnot $ZFS rename $src $dest
+       log_mustnot $ZFS rename -p $src $dest
+
+       #
+       # Verify original dataset name still in use
+       #
+       log_must datasetexists $src
+done
+
+log_pass "'zfs rename' fail while datasets are within different pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_006_pos.ksh
new file mode 100755 (executable)
index 0000000..32223b6
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/ksh
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
+
+#
+# DESCRIPTION:
+#       'zfs rename' can successfully rename a volume snapshot.
+#
+# STRATEGY:
+#       1. Create a snapshot of volume.
+#       2. Rename volume snapshot to a new one.
+#      3. Rename volume to a new one.
+#       4. Create a clone of the snapshot.
+#       5. Verify that the rename operations are successful and zfs list can
+#         list them.
+#
+###############################################################################
+
+verify_runnable "global"
+
+#
+# cleanup defined in zfs_rename.kshlib
+#
+log_onexit cleanup
+
+log_assert "'zfs rename' can successfully rename a volume snapshot."
+
+vol=$TESTPOOL/$TESTVOL
+snap=$TESTSNAP
+
+log_must eval "$DD if=$DATA of=$VOL_R_PATH bs=$BS count=$CNT >/dev/null 2>&1"
+if ! snapexists $vol@$snap; then
+       log_must $ZFS snapshot $vol@$snap
+fi
+
+rename_dataset $vol@$snap $vol@${snap}-new
+rename_dataset $vol ${vol}-new
+rename_dataset ${vol}-new@${snap}-new ${vol}-new@$snap
+rename_dataset ${vol}-new $vol
+
+clone=$TESTPOOL/${snap}_clone
+create_clone $vol@$snap $clone
+
+#verify data integrity
+for input in $VOL_R_PATH $ZVOL_RDEVDIR/$clone; do
+       log_must eval "$DD if=$input of=$VOLDATA bs=$BS count=$CNT >/dev/null 2>&1"
+       if ! cmp_data $VOLDATA $DATA ; then
+               log_fail "$input gets corrupted after rename operation."
+       fi
+done
+
+destroy_clone $clone
+log_must $ZFS destroy $vol@$snap
+
+log_pass "'zfs rename' can rename volume snapshot as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_007_pos.ksh
new file mode 100755 (executable)
index 0000000..5985eac
--- /dev/null
@@ -0,0 +1,155 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
+
+#
+# DESCRIPTION:
+#      Rename dataset, verify that the data haven't changed.
+#
+# STRATEGY:
+#      1. Create random data and copy to dataset.
+#      2. Perform renaming commands.
+#      3. Verify that the data haven't changed.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $TESTPOOL/$TESTFS ; then
+               log_must $ZFS destroy -Rf $TESTPOOL/$TESTFS
+       fi
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+       $RM -f $SRC_FILE $DST_FILE
+}
+
+function target_obj
+{
+       typeset dtst=$1
+
+       typeset obj
+       typeset type=$(get_prop type $dtst)
+       if [[ $type == "filesystem" ]]; then
+               obj=$(get_prop mountpoint $dtst)/${SRC_FILE##*/}
+       elif [[ $type == "volume" ]]; then
+               obj=$ZVOL_DEVDIR/$dtst
+       fi
+
+       echo $obj
+}
+
+log_assert "Rename dataset, verify that the data haven't changed."
+log_onexit cleanup
+
+# Generate random data
+#
+BS=512 ; CNT=2048
+SRC_FILE=/tmp/srcfile.$$
+DST_FILE=/tmp/dstfile.$$
+log_must $DD if=/dev/urandom of=$SRC_FILE bs=$BS count=$CNT
+
+fs=$TESTPOOL/$TESTFS/fs.$$
+fsclone=$TESTPOOL/$TESTFS/fsclone.$$
+log_must $ZFS create $fs
+
+obj=$(target_obj $fs)
+log_must $CP $SRC_FILE $obj
+
+snap=${fs}@snap.$$
+log_must $ZFS snapshot $snap
+log_must $ZFS clone $snap $fsclone
+
+# Rename dataset & clone
+#
+log_must $ZFS rename $fs ${fs}-new
+log_must $ZFS rename $fsclone ${fsclone}-new
+
+# Compare source file and target file
+#
+obj=$(target_obj ${fs}-new)
+log_must $DIFF $SRC_FILE $obj
+obj=$(target_obj ${fsclone}-new)
+log_must $DIFF $SRC_FILE $obj
+
+# Rename snapshot and re-clone dataset
+#
+log_must $ZFS rename ${fs}-new $fs
+log_must $ZFS rename $snap ${snap}-new
+log_must $ZFS clone ${snap}-new $fsclone
+
+# Compare source file and target file
+#
+obj=$(target_obj $fsclone)
+log_must $DIFF $SRC_FILE $obj
+
+if is_global_zone; then
+       vol=$TESTPOOL/$TESTFS/vol.$$ ;  volclone=$TESTPOOL/$TESTFS/volclone.$$
+       log_must $ZFS create -V 100M $vol
+       block_device_wait
+
+       obj=$(target_obj $vol)
+       log_must $DD if=$SRC_FILE of=$obj bs=$BS count=$CNT
+
+       snap=${vol}@snap.$$
+       log_must $ZFS snapshot $snap
+       log_must $ZFS clone $snap $volclone
+       block_device_wait
+
+       # Rename dataset & clone
+       log_must $ZFS rename $vol ${vol}-new
+       log_must $ZFS rename $volclone ${volclone}-new
+       block_device_wait
+
+       # Compare source file and target file
+       obj=$(target_obj ${vol}-new)
+       log_must $DD if=$obj of=$DST_FILE bs=$BS count=$CNT
+       log_must $DIFF $SRC_FILE $DST_FILE
+       obj=$(target_obj ${volclone}-new)
+       log_must $DD if=$obj of=$DST_FILE bs=$BS count=$CNT
+       log_must $DIFF $SRC_FILE $DST_FILE
+
+       # Rename snapshot and re-clone dataset
+       log_must $ZFS rename ${vol}-new $vol
+       log_must $ZFS rename $snap ${snap}-new
+       log_must $ZFS clone ${snap}-new $volclone
+       block_device_wait
+
+       # Compare source file and target file
+       obj=$(target_obj $volclone)
+       log_must $DD if=$obj of=$DST_FILE bs=$BS count=$CNT
+       log_must $DIFF $SRC_FILE $DST_FILE
+fi
+
+log_pass "Rename dataset, the data haven't changed passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_008_pos.ksh
new file mode 100755 (executable)
index 0000000..2552acc
--- /dev/null
@@ -0,0 +1,88 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      zfs rename -r can rename snapshot recursively.
+#
+# STRATEGY:
+#      1. Create snapshot recursively.
+#      2. Rename snapshot recursively.
+#      3. Verify rename -r snapshot correctly.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset -i i=0
+       while ((i < ${#datasets[@]})); do
+               if datasetexists ${datasets[$i]}@snap ; then
+                       log_must $ZFS destroy ${datasets[$i]}@snap
+               fi
+               if datasetexists ${datasets[$i]}@snap-new ; then
+                       log_must $ZFS destroy ${datasets[$i]}@snap-new
+               fi
+
+               ((i += 1))
+       done
+}
+
+log_assert "zfs rename -r can rename snapshot recursively."
+log_onexit cleanup
+
+set -A datasets $TESTPOOL              $TESTPOOL/$TESTCTR \
+       $TESTPOOL/$TESTCTR/$TESTFS1     $TESTPOOL/$TESTFS
+if is_global_zone; then
+       datasets[${#datasets[@]}]=$TESTPOOL/$TESTVOL
+fi
+
+log_must $ZFS snapshot -r ${TESTPOOL}@snap
+typeset -i i=0
+while ((i < ${#datasets[@]})); do
+       log_must datasetexists ${datasets[$i]}@snap
+
+       ((i += 1))
+done
+
+log_must $ZFS rename -r ${TESTPOOL}@snap ${TESTPOOL}@snap-new
+i=0
+while ((i < ${#datasets[@]})); do
+       log_must datasetexists ${datasets[$i]}@snap-new
+
+       ((i += 1))
+done
+
+log_must $ZFS destroy -rf ${TESTPOOL}@snap-new
+
+log_pass "Verify zfs rename -r passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_009_neg.ksh
new file mode 100755 (executable)
index 0000000..16d306d
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      A snapshot already exists with the new name, then none of the
+#      snapshots is renamed.
+#
+# STRATEGY:
+#      1. Create snapshot for a set of datasets.
+#      2. Create a new snapshot for one of datasets.
+#      3. Using rename -r command with exists snapshot name.
+#      4. Verify none of the snapshots is renamed.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset snaps=$($ZFS list -H -t snapshot -o name)
+       typeset exclude
+       typeset snap
+       typeset pool_name
+
+       if [[ -n $KEEP ]]; then
+               exclude=`eval $ECHO \"'(${KEEP})'\"`
+       fi
+
+       for snap in $snaps; do
+               pool_name=$($ECHO "$snap" | $AWK -F/ '{print $1}')
+               if [[ -n $exclude ]]; then
+                       $ECHO "$pool_name" | $EGREP -v "$exclude" > /dev/null 2>&1
+                       if [[ $? -eq 0 ]]; then
+                               log_must $ZFS destroy $snap
+                       fi
+               else
+                       log_must $ZFS destroy $snap
+               fi
+       done
+}
+
+log_assert "zfs rename -r failed, when snapshot name is already existing."
+log_onexit cleanup
+
+set -A datasets $TESTPOOL              $TESTPOOL/$TESTCTR \
+       $TESTPOOL/$TESTCTR/$TESTFS1     $TESTPOOL/$TESTFS
+if is_global_zone; then
+       datasets[${#datasets[@]}]=$TESTPOOL/$TESTVOL
+fi
+
+log_must $ZFS snapshot -r ${TESTPOOL}@snap
+typeset -i i=0
+while ((i < ${#datasets[@]})); do
+       # Create one more snapshot
+       log_must $ZFS snapshot ${datasets[$i]}@snap2
+       log_mustnot $ZFS rename -r ${TESTPOOL}@snap ${TESTPOOL}@snap2
+       log_must $ZFS destroy ${datasets[$i]}@snap2
+
+       # Check datasets, make sure none of them was renamed.
+       typeset -i j=0
+       while ((j < ${#datasets[@]})); do
+               if datasetexists ${datasets[$j]}@snap2 ; then
+                       log_fail "${datasets[$j]}@snap2 should not exist."
+               fi
+               ((j += 1))
+       done
+
+       ((i += 1))
+done
+
+log_pass "zfs rename -r failed, when snapshot name is already existing passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_010_neg.ksh
new file mode 100755 (executable)
index 0000000..2b96662
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      The recursive flag -r can only be used for snapshots and not for
+#      volumes/filesystems.
+#
+# STRATEGY:
+#      1. Loop pool, fs, container and volume.
+#      2. Verify none of them can be rename by rename -r.
+#
+
+verify_runnable "both"
+
+log_assert "The recursive flag -r can only be used for snapshots."
+
+set -A datasets $TESTPOOL              $TESTPOOL/$TESTCTR \
+       $TESTPOOL/$TESTCTR/$TESTFS1     $TESTPOOL/$TESTFS
+if is_global_zone; then
+       datasets[${#datasets[@]}]=$TESTPOOL/$TESTVOL
+fi
+
+for opts in "-r" "-r -p"; do
+       typeset -i i=0
+       while ((i < ${#datasets[@]})); do
+               log_mustnot $ZFS rename $opts ${datasets[$i]} \
+                       ${datasets[$i]}-new
+
+               # Check datasets, make sure none of them was renamed.
+               typeset -i j=0
+               while ((j < ${#datasets[@]})); do
+                       if datasetexists ${datasets[$j]}-new ; then
+                               log_fail "${datasets[$j]}-new should not exists."
+                       fi
+                       ((j += 1))
+               done
+
+               ((i += 1))
+       done
+done
+
+log_pass "The recursive flag -r can only be used for snapshots passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_011_pos.ksh
new file mode 100755 (executable)
index 0000000..e453e83
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib
+
+#
+# DESCRIPTION
+#       'zfs rename -p' should work as expected
+#
+# STRATEGY:
+#      1. Make sure the upper level of $newdataset does not exist
+#       2. Make sure without -p option, 'zfs rename' will fail
+#       3. With -p option, rename works
+#
+
+verify_runnable "both"
+
+function additional_cleanup
+{
+       if datasetexists $TESTPOOL/notexist ; then
+               log_must $ZFS destroy -Rf $TESTPOOL/notexist
+       fi
+
+       if datasetexists $TESTPOOL/$TESTFS ; then
+               log_must $ZFS destroy -Rf $TESTPOOL/$TESTFS
+       fi
+       log_must $ZFS create $TESTPOOL/$TESTFS
+
+       if is_global_zone ; then
+               if datasetexists $TESTPOOL/$TESTVOL ; then
+                       log_must $ZFS destroy -Rf $TESTPOOL/$TESTVOL
+               fi
+               log_must $ZFS create -V $VOLSIZE $TESTPOOL/$TESTVOL
+       fi
+}
+
+log_onexit additional_cleanup
+
+log_assert "'zfs rename -p' should work as expected"
+
+log_must verify_opt_p_ops "rename" "fs" "$TESTPOOL/$TESTFS" \
+       "$TESTPOOL/notexist/new/$TESTFS1"
+
+if is_global_zone; then
+       log_must verify_opt_p_ops "rename" "vol" "$TESTPOOL/$TESTVOL" \
+               "$TESTPOOL/notexist/new/$TESTVOL1"
+fi
+
+log_pass "'zfs rename -p' should work as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_012_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_012_neg.ksh
new file mode 100755 (executable)
index 0000000..495f663
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs rename' should be failed with bad option, null target dataset,
+#      too many datasets and long target dataset name.
+#
+# STRATEGY:
+#      1. Create a set of ZFS datasets;
+#      2. Try 'zfs rename' with various illegal scenarios;
+#      3. Verify 'zfs rename' command should be failed.
+#
+
+verify_runnable "both"
+
+log_assert "'zfs rename' should fail with bad option, null target dataset and" \
+               "too long target dataset name."
+
+badopts=( "r" "R" "-R" "-rR" "-Rr" "-P" "-pP" "-Pp" "-r*" "-p*" "-?" "-*" "-"
+    "-o")
+datasets=("$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTFS@$TESTSNAP"
+    "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTCTR/$TESTFS1" "$TESTPOOL/$TESTVOL")
+
+longname="$(gen_dataset_name 260 abcdefg)"
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+for ds in ${datasets[@]}; do
+       for opt in ${badopts[@]}; do
+               log_mustnot $ZFS rename $opt $ds ${ds}-new
+       done
+       log_mustnot $ZFS rename $ds
+       log_mustnot $ZFS rename $ds ${ds}-new ${ds}-new1
+       log_mustnot $ZFS rename $ds ${ds}.$longname
+done
+
+log_pass "'zfs rename' fails with illegal scenarios as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_013_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_013_pos.ksh
new file mode 100755 (executable)
index 0000000..3189be5
--- /dev/null
@@ -0,0 +1,85 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      zfs rename -r can rename snapshot when child datasets
+#      don't have a snapshot of the given name.
+#
+# STRATEGY:
+#      1. Create snapshot.
+#      2. Rename snapshot recursively.
+#      3. Verify rename -r snapshot correctly.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $TESTPOOL/$TESTCTR@snap-new ; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTCTR@snap-new
+       fi
+
+       if datasetexists $TESTPOOL/$TESTCTR@snap ; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTCTR@snap
+       fi
+
+       if datasetexists $TESTPOOL@snap-new ; then
+               log_must $ZFS destroy -f $TESTPOOL@snap-new
+       fi
+
+       if datasetexists $TESTPOOL@snap ; then
+               log_must $ZFS destroy -f $TESTPOOL@snap
+       fi
+}
+
+log_assert "zfs rename -r can rename snapshot when child datasets" \
+       "don't have a snapshot of the given name."
+
+log_onexit cleanup
+
+log_must $ZFS snapshot $TESTPOOL/$TESTCTR@snap
+log_must $ZFS rename -r $TESTPOOL/$TESTCTR@snap $TESTPOOL/$TESTCTR@snap-new
+log_must datasetexists $TESTPOOL/$TESTCTR@snap-new
+
+log_must $ZFS snapshot $TESTPOOL@snap
+log_must $ZFS rename -r $TESTPOOL@snap $TESTPOOL@snap-new
+log_must datasetexists $TESTPOOL/$TESTCTR@snap-new
+log_must datasetexists $TESTPOOL@snap-new
+
+log_must $ZFS destroy -f $TESTPOOL/$TESTCTR@snap-new
+log_must $ZFS destroy -f $TESTPOOL@snap-new
+
+log_pass "Verify zfs rename -r passed when child datasets" \
+       "don't have a snapshot of the given name."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/Makefile.am
new file mode 100644 (file)
index 0000000..5b7b758
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_reservation
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_reservation_001_pos.ksh \
+       zfs_reservation_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/zfs_reservation_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/zfs_reservation_001_pos.ksh
new file mode 100755 (executable)
index 0000000..d3a6a00
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Exceed the maximum limit for a reservation and ensure it fails.
+#
+# STRATEGY:
+# 1. Create a reservation file system.
+# 2. Set the reservation to an absurd value.
+# 3. Verify the return code is an error.
+#
+
+verify_runnable "both"
+
+RESERVATION="reserve"
+
+function cleanup
+{
+       if datasetexists $TESTPOOL/$RESERVATION ; then
+               log_must $ZFS unmount $TESTPOOL/$RESERVATION
+               log_must $ZFS destroy $TESTPOOL/$RESERVATION
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "Verify that a reservation > 2^64 -1 fails."
+
+log_must $ZFS create $TESTPOOL/$RESERVATION
+
+log_mustnot $ZFS set reservation=18446744073709551615 $TESTPOOL/$RESERVATION
+
+log_pass "Unable to set a reservation > 2^64 - 1"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/zfs_reservation_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_reservation/zfs_reservation_002_pos.ksh
new file mode 100755 (executable)
index 0000000..d308f75
--- /dev/null
@@ -0,0 +1,83 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# A reservation of 'none' (which is an alias for 0) should be allowed. This
+# test verifies that is true.
+#
+# STRATEGY:
+# 1. Create a new file system in the test pool.
+# 2. Set the reservation to 'none'.
+# 3. Verify the associated reservation is indeed 0.
+# 4. Repeat with reservation set to 0.
+#
+
+verify_runnable "both"
+
+# Use a unique value so earlier test failures will not impact this test.
+RESERVATION="reserve"-$$
+RESERVATION2="reserve2"-$$
+
+function cleanup
+{
+       typeset FS
+       for FS in $TESTPOOL/$RESERVATION $TESTPOOL/$RESERVATION2
+       do
+               if datasetexists $FS ; then
+                       log_must $ZFS unmount $FS
+                       log_must $ZFS destroy $FS
+               fi
+       done
+}
+
+log_onexit cleanup
+
+log_assert "Ensure a reservation of 0 or 'none' is allowed."
+
+log_must $ZFS create $TESTPOOL/$RESERVATION
+log_must $ZFS create $TESTPOOL/$RESERVATION2
+
+log_must $ZFS set reservation=0 $TESTPOOL/$RESERVATION
+log_must $ZFS set reservation=none $TESTPOOL/$RESERVATION2
+
+for FS in $TESTPOOL/$RESERVATION $TESTPOOL/$RESERVATION2
+do
+
+       reserve=`$ZFS get -pH reservation $FS | $AWK '{print $3}'`
+       if [[ $reserve -ne 0 ]]; then
+               log_fail "ZFS get -p reservation did not return 0"
+       fi
+
+       reserve=`$ZFS get -H reservation $FS | $AWK '{print $3}'`
+       if [[ $reserve != "none" ]]; then
+               log_fail "ZFS get reservation did not return 'none'"
+       fi
+done
+
+log_pass "Successfully set reservation to 0 and 'none'"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/Makefile.am
new file mode 100644 (file)
index 0000000..857959b
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_rollback
+dist_pkgdata_SCRIPTS = \
+       zfs_rollback.cfg \
+       zfs_rollback_common.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_rollback_001_pos.ksh \
+       zfs_rollback_002_pos.ksh \
+       zfs_rollback_003_neg.ksh \
+       zfs_rollback_004_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/cleanup.ksh
new file mode 100755 (executable)
index 0000000..707e8f1
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib
+
+cleanup_env
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/setup.ksh
new file mode 100755 (executable)
index 0000000..d3341b1
--- /dev/null
@@ -0,0 +1,31 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_volume_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback.cfg
new file mode 100644 (file)
index 0000000..d6c8934
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+export FS=$TESTPOOL/$TESTFS
+export VOL=$TESTPOOL/$TESTVOL
+
+export FSSNAP0=$FS@$TESTSNAP
+export FSSNAP1=$FS@$TESTSNAP1
+export FSSNAP2=$FS@$TESTSNAP2
+
+export VOLSNAP0=$VOL@$TESTSNAP
+export VOLSNAP1=$VOL@$TESTSNAP1
+export VOLSNAP2=$VOL@$TESTSNAP2
+
+export FSCLONE0=$FS$TESTCLONE
+export FSCLONE1=$FS$TESTCLONE1
+export FSCLONE2=$FS$TESTCLONE2
+
+export VOLCLONE0=$VOL$TESTCLONE
+export VOLCLONE1=$VOL$TESTCLONE1
+export VOLCLONE2=$VOL$TESTCLONE2
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_001_pos.ksh
new file mode 100755 (executable)
index 0000000..1697f62
--- /dev/null
@@ -0,0 +1,163 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib
+
+#
+# DESCRIPTION:
+#      'zfs rollback -r|-rf|-R|-Rf' will recursively destroy any snapshots
+#      more recent than the one specified.
+#
+# STRATEGY:
+#      1. Create pool, fs & volume.
+#      2. Separately create three snapshots or clones for fs & volume
+#      3. Roll back to the second snapshot and check the results.
+#      4. Create the third snapshot or clones for fs & volume again.
+#      5. Roll back to the first snapshot and check the results.
+#      6. Separately create two snapshots for fs & volume.
+#      7. Roll back to the first snapshot and check the results.
+#
+
+verify_runnable "both"
+
+log_assert "'zfs rollback -r|-rf|-R|-Rf' will recursively destroy any " \
+       "snapshots more recent than the one specified."
+log_onexit cleanup_env
+
+#
+# Create suitable test environment and run 'zfs rollback', then compare with
+# expected value to check the system status.
+#
+# $1 option.
+# $2 the number of snapshots or clones.
+# $3 the number of snapshot point which we want to rollback.
+#
+function test_n_check #opt num_snap_clone num_rollback
+{
+       typeset opt=$1
+       typeset -i cnt=$2
+       typeset -i pointcnt=$3
+       typeset dtst
+
+       (( cnt > 3 || pointcnt > cnt )) && \
+               log_fail "Unsupported testing condition."
+
+       # Clean up the test environment
+       datasetexists $FS && log_must $ZFS destroy -Rf $FS
+       if datasetexists $VOL; then
+               $DF -lhF ufs "$ZVOL_DEVDIR/$VOL" > /dev/null 2>&1
+               (( $? == 0 )) && log_must $UMOUNT -f $TESTDIR1
+
+               log_must $ZFS destroy -Rf $VOL
+       fi
+
+       # Create specified test environment
+       case $opt in
+               *r*) setup_snap_env $cnt ;;
+               *R*) setup_clone_env $cnt ;;
+       esac
+
+       all_snap="$TESTSNAP $TESTSNAP1 $TESTSNAP2"
+       all_clone="$TESTCLONE $TESTCLONE1 $TESTCLONE2"
+       typeset snap_point
+       typeset exist_snap
+       typeset exist_clone
+       case $pointcnt in
+               1) snap_point=$TESTSNAP
+                  exist_snap=$TESTSNAP
+                  [[ $opt == *R* ]] && exist_clone=$TESTCLONE
+                  ;;
+               2) snap_point=$TESTSNAP1
+                  exist_snap="$TESTSNAP $TESTSNAP1"
+                  [[ $opt == *R* ]] && exist_clone="$TESTCLONE $TESTCLONE1"
+                  ;;
+       esac
+
+       typeset snap
+       for dtst in $FS $VOL; do
+               # Volume is not available in Local Zone.
+               if [[ $dtst == $VOL ]]; then
+                       if ! is_global_zone; then
+                               break
+                       fi
+               fi
+               if [[ $opt == *f* ]]; then
+                       # To write data to the mountpoint directory,
+                       write_mountpoint_dir $dtst
+                       opt=${opt%f}
+               fi
+
+               if [[ $dtst == $VOL ]]; then
+                       log_must $UMOUNT -f $TESTDIR1
+                       log_must $ZFS rollback $opt $dtst@$snap_point
+                       log_must $MOUNT \
+                               $ZVOL_DEVDIR/$TESTPOOL/$TESTVOL $TESTDIR1
+               else
+                       log_must $ZFS rollback $opt $dtst@$snap_point
+               fi
+
+               for snap in $all_snap; do
+                       if [[ " $exist_snap " == *" $snap "* ]]; then
+                               log_must datasetexists $dtst@$snap
+                       else
+                               log_must datasetnonexists $dtst@$snap
+                       fi
+               done
+               for clone in $all_clone; do
+                       if [[ " $exist_clone " == *" $clone "* ]]; then
+                               log_must datasetexists $dtst$clone
+                       else
+                               log_must datasetnonexists $dtst$clone
+                       fi
+               done
+
+               check_files $dtst@$snap_point
+       done
+}
+
+typeset opt
+for opt in "-r" "-rf" "-R" "-Rf"; do
+       #
+       # Currently, the test case was limited to create and rollback
+       # in three snapshots
+       #
+       log_note "Create 3 snapshots, rollback to the 2nd snapshot " \
+               "using $opt."
+       test_n_check "$opt" 3 2
+
+       log_note "Create 3 snapshots and rollback to the 1st snapshot " \
+               "using $opt."
+       test_n_check "$opt" 3 1
+
+       log_note "Create 2 snapshots and rollback to the 1st snapshot " \
+               "using $opt."
+       test_n_check "$opt" 2 1
+done
+
+log_pass "'zfs rollback -r|-rf|-R|-Rf' recursively destroy any snapshots more "\
+       "recent than the one specified passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_002_pos.ksh
new file mode 100755 (executable)
index 0000000..8da6589
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib
+
+#
+# DESCRIPTION:
+#      'zfs rollback -f' will force unmount any filesystems.
+#
+# STRATEGY:
+#      1. Create pool & fs.
+#      2. Create the snapshot of this file system.
+#      3. Write the mountpoint directory of this file system.
+#      4. Make sure 'zfs rollback -f' succeeds.
+#
+
+verify_runnable "both"
+
+log_assert "'zfs rollback -f' will force unmount any filesystems."
+log_onexit cleanup_env
+
+# Create a snapshot of this file system: FSSNAP0
+setup_snap_env 1
+
+#
+# Write file and make the mountpoint directory busy when try to unmount
+# the file system that was mounted on it.
+#
+write_mountpoint_dir ${FSSNAP0%%@*}
+
+log_must $ZFS rollback $FSSNAP0
+log_must $ZFS rollback -f $FSSNAP0
+log_must datasetexists $FSSNAP0
+
+$PKILL ${DD##*/}
+
+check_files $FSSNAP0
+
+log_pass "'zfs rollback -f' force unmount any filesystem passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_003_neg.ksh
new file mode 100755 (executable)
index 0000000..1115ea6
--- /dev/null
@@ -0,0 +1,80 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib
+
+#
+# DESCRIPTION:
+#      Seperately verify 'zfs rollback ''|-f|-r|-rf|-R|-rR will fail in
+#      different conditions.
+#
+# STRATEGY:
+#      1. Create pool and file system
+#      2. Create 'snap' and 'snap1' of this file system.
+#      3. Run 'zfs rollback ""|-f <snap>' and it should fail.
+#      4. Create 'clone1' based on 'snap1'.
+#      5. Run 'zfs rollback -r|-rf <snap>' and it should fail.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $PKILL ${DD##*/}
+       for snap in $FSSNAP0 $FSSNAP1 $FSSNAP2; do
+               if snapexists $snap; then
+                       log_must $ZFS destroy -Rf $snap
+               fi
+       done
+}
+
+log_assert "Seperately verify 'zfs rollback ''|-f|-r|-rf will fail in " \
+       "different conditions."
+log_onexit cleanup
+
+# Create snapshot1 and snapshot2 for this file system.
+#
+create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
+create_snapshot $TESTPOOL/$TESTFS $TESTSNAP1
+
+# Run 'zfs rollback ""|-f <snap>' and it should fail.
+#
+log_mustnot $ZFS rollback $TESTPOOL/$TESTFS@$TESTSNAP
+log_mustnot $ZFS rollback -f $TESTPOOL/$TESTFS@$TESTSNAP
+
+# Create 'clone1' based on 'snap1'.
+#
+create_clone $TESTPOOL/$TESTFS@$TESTSNAP1 $TESTPOOL/$TESTCLONE1
+
+# Run 'zfs rollback -r|-rf <snap>' and it should fail.
+#
+log_mustnot $ZFS rollback -r $TESTPOOL/$TESTFS@$TESTSNAP
+log_mustnot $ZFS rollback -rf $TESTPOOL/$TESTFS@$TESTSNAP
+
+log_pass "zfs rollback ''|-f|-r|-rf will fail in different conditions " \
+       "passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_004_neg.ksh
new file mode 100755 (executable)
index 0000000..a0aab07
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib
+
+#
+# DESCRIPTION:
+#      'zfs rollback' should fail when passing invalid options, too many
+#      arguments,non-snapshot datasets or missing datasets
+#
+# STRATEGY:
+#      1. Create an array of invalid options
+#      2. Execute 'zfs rollback' with invalid options, too many arguments
+#         or missing datasets
+#      3. Verify 'zfs rollback' return with errors
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset ds
+
+       for ds in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL; do
+               if snapexists ${ds}@$TESTSNAP; then
+                       log_must $ZFS destroy ${ds}@$TESTSNAP
+               fi
+       done
+}
+
+log_assert "'zfs rollback' should fail with bad options,too many arguments," \
+       "non-snapshot datasets or missing datasets."
+log_onexit cleanup
+
+set -A badopts "r" "R" "f" "-F" "-rF" "-RF" "-fF" "-?" "-*" "-blah" "-1" "-2"
+
+for ds in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL; do
+       log_must $ZFS snapshot ${ds}@$TESTSNAP
+done
+
+for ds in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL; do
+       for opt in "" "-r" "-R" "-f" "-rR" "-rf" "-rRf"; do
+               log_mustnot eval "$ZFS rollback $opt $ds >/dev/null 2>&1"
+               log_mustnot eval "$ZFS rollback $opt ${ds}@$TESTSNAP \
+                       ${ds}@$TESTSNAP >/dev/null 2>&1"
+               log_mustnot eval "$ZFS rollback $opt >/dev/null 2>&1"
+               # zfs rollback should fail with non-existen snapshot
+               log_mustnot eval "$ZFS rollback $opt ${ds}@nosnap >/dev/null 2>&1"
+       done
+
+       for badopt in ${badopts[@]}; do
+               log_mustnot eval "$ZFS rollback $badopt ${ds}@$TESTSNAP \
+                               >/dev/null 2>&1"
+       done
+done
+
+log_pass "'zfs rollback' fails as expected with illegal arguments."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib
new file mode 100644 (file)
index 0000000..f9b9301
--- /dev/null
@@ -0,0 +1,308 @@
+#
+# 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) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback.cfg
+
+# Get file sum
+#
+# $1 full file name
+function getsum #fname
+{
+       (( ${#1} == 0 )) && \
+               log_fail "Need give file name."
+       return $($SUM $1 | $AWK '{print $1}')
+}
+
+# Define global variable checksum, get the original file sum.
+#
+origsum=$(getsum /etc/passwd)
+
+#
+# Setup or recover the test environment. Firstly, copy /etc/passwd to ZFS file
+# system or volume, then make a snapshot or clone. Repeat up to three times.
+#
+# $1 number of snapshot. Note: Currently only support three snapshots.
+# $2 indicate if it is necessary to create clone
+#
+function setup_snap_env
+{
+       typeset -i cnt=${1:-3}
+       typeset createclone=${2:-"false"}
+
+       if datasetnonexists $FS; then
+               log_must $ZFS create $FS
+               log_must $ZFS set mountpoint=$TESTDIR $FS
+       fi
+       # Volume can't be created in Local Zone.
+       if datasetnonexists $VOL && is_global_zone; then
+               log_must $ZFS create -V $VOLSIZE $VOL
+               block_device_wait
+       fi
+
+       # Make sure $VOL is volume
+       typeset type=$(get_prop type $VOL)
+       if datasetexists $VOL && \
+               [[ $type == 'volume' ]]; then
+               #
+               # At the first time, Make a UFS file system in volume and
+               # mount it. Otherwise, only check if this ufs|ext2 file system
+               # was mounted.
+               #
+               log_must eval "$ECHO "y" | \
+                       $NEWFS -v $ZVOL_DEVDIR/$VOL > /dev/null 2>&1"
+
+               [[ ! -d $TESTDIR1 ]] && log_must $MKDIR $TESTDIR1
+
+               # Make sure the ufs|ext2 filesystem hasn't been mounted,
+               # then mount the new ufs|ext2 filesystem.
+               if ! ismounted "$ZVOL_DEVDIR/$VOL" $NEWFS_DEFAULT_FS; then
+                       log_must $MOUNT \
+                               $ZVOL_DEVDIR/$TESTPOOL/$TESTVOL $TESTDIR1
+               fi
+       fi
+
+       # Separately Create three snapshots for file system & volume
+       typeset -i ind=0
+       typeset dtst
+       for dtst in $FS $VOL; do
+               # Volume can be created in Local Zone.
+               if [[ $dtst == $VOL ]]; then
+                       if ! is_global_zone; then
+                               break
+                       fi
+               fi
+
+               ind=0
+               while (( ind < cnt )); do
+                       case $dtst in
+                       $FS)
+                               eval typeset snap=\$FSSNAP$ind
+                               eval typeset clone=\$FSCLONE$ind
+                               eval typeset fname=\$TESTDIR/\$TESTFILE$ind
+                               ;;
+                       $VOL)
+                               eval typeset snap=\$VOLSNAP$ind
+                               eval typeset clone=\$VOLCLONE$ind
+                               eval typeset fname=\$TESTDIR1/\$TESTFILE$ind
+                               ;;
+                       esac
+
+                       if datasetnonexists $snap; then
+                               log_must $CP /etc/passwd $fname
+                               if is_linux; then
+                                       log_must $SYNC
+                               else
+                                       #
+                                       # using 'lockfs -f' to flush the writes
+                                       # to disk before taking a snapshot.
+                                       #
+                                       if [[ $dtst == $VOL ]]; then
+                                               log_must $LOCKFS -f $TESTDIR1
+                                       fi
+                               fi
+                               log_must $ZFS snapshot $snap
+                       fi
+                       if [[ $createclone == "true" ]]; then
+                               if datasetnonexists $clone; then
+                                       log_must $ZFS clone $snap $clone
+                               fi
+                       fi
+                       (( ind += 1 ))
+               done
+       done
+}
+
+function setup_clone_env
+{
+       setup_snap_env $1 "true"
+}
+
+#
+# Clean up the test environmnet
+#
+# $1 number of snapshot Note: Currently only support three snapshots.
+#
+function cleanup_env
+{
+       typeset -i cnt=${1:-3}
+       typeset -i ind=0
+       typeset dtst
+       typeset snap
+
+       $PKILL ${DD##*/}
+
+       if ismounted $TESTDIR1 $NEWFS_DEFAULT_FS; then
+               log_must $UMOUNT -f $TESTDIR1
+       fi
+
+       [[ -d $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+       [[ -d $TESTDIR1 ]] && log_must $RM -rf $TESTDIR1/*
+
+       for dtst in $FS $VOL; do
+               for snap in $TESTSNAP $TESTSNAP1 $TESTSNAP2; do
+                       if snapexists $dtst@$snap; then
+                                log_must $ZFS destroy -Rf $dtst@$snap
+                       fi
+               done
+       done
+
+       # Restore original test environment
+       if datasetnonexists $FS ; then
+               log_must $ZFS create $FS
+       fi
+       if datasetnonexists $VOL ; then
+               if is_global_zone ; then
+                       log_must $ZFS create -V $VOLSIZE $VOL
+               else
+                       log_must $ZFS create $VOL
+               fi
+       fi
+}
+
+#
+# check if the specified files have specified status.
+#
+# $1 expected status
+# $2-n full file name
+# If it is true return 0, else return 1
+#
+function file_status
+{
+       (( $# == 0 )) && \
+               log_fail "The file name is not defined."
+
+       typeset opt
+       case $1 in
+               exist)  opt="-e" ;;
+               nonexist) opt="! -e" ;;
+               *)      log_fail "Unsupported file status." ;;
+       esac
+
+       shift
+       while (( $# > 0 )); do
+               eval [[ $opt $1 ]] || return 1
+               shift
+       done
+
+       return 0
+}
+
+function files_exist
+{
+       file_status "exist" $@
+}
+
+function files_nonexist
+{
+       file_status "nonexist" $@
+}
+
+#
+# According to snapshot check if the file system was recovered to the right
+# point.
+#
+# $1 snapshot. fs@snap or vol@snap
+#
+function check_files
+{
+       typeset dtst=$1
+
+       if [[ $(get_prop type $dtst) != snapshot ]]; then
+               log_fail "Parameter must be a snapshot."
+       fi
+
+       typeset fsvol=${dtst%%@*}
+       typeset snap=${dtst##*@}
+       if [[ $(get_prop type $fsvol) == "filesystem" ]]; then
+               ind=""
+       else
+               ind="1"
+       fi
+
+       eval typeset file0=\$TESTDIR$ind/\$TESTFILE0
+       eval typeset file1=\$TESTDIR$ind/\$TESTFILE1
+       eval typeset file2=\$TESTDIR$ind/\$TESTFILE2
+
+       case $snap in
+               $TESTSNAP2)
+                       log_must files_exist $file0 $file1 $file2
+
+                       typeset sum0=$(getsum $file0)
+                       typeset sum1=$(getsum $file1)
+                       typeset sum2=$(getsum $file2)
+                       if [[ $sum0 != $origsum || \
+                               $sum1 != $origsum || sum2 != $origsum ]]
+                       then
+                               log_fail "After rollback, file sum is changed."
+                       fi
+                       ;;
+               $TESTSNAP1)
+                       log_must files_exist $file0 $file1
+                       log_must files_nonexist $file2
+
+                       typeset sum0=$(getsum $file0)
+                       typeset sum1=$(getsum $file1)
+                       if [[ $sum0 != $origsum || $sum1 != $origsum ]]
+                       then
+                               log_fail "After rollback, file sum is changed."
+                       fi
+                       ;;
+               $TESTSNAP)
+                       log_must files_exist $file0
+                       log_must files_nonexist $file1 $file2
+
+                       typeset sum0=$(getsum $file0)
+                       if [[ $sum0 != $origsum ]]; then
+                               log_fail "After rollback, file sum is changed."
+                       fi
+                       ;;
+       esac
+}
+
+# According to dataset type, write file to different directories.
+#
+# $1 dataset
+#
+function write_mountpoint_dir
+{
+       typeset dtst=$1
+       typeset dir
+
+       if [[ $dtst == $FS ]]; then
+               dir=$TESTDIR
+               log_must ismounted $dir
+       else
+               dir=$TESTDIR1
+               log_must ismounted $dir $NEWFS_DEFAULT_FS
+       fi
+       $DD if=/dev/urandom of=$dir/$TESTFILE1 &
+       log_must $SLEEP 3
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/Makefile.am
new file mode 100644 (file)
index 0000000..13faeab
--- /dev/null
@@ -0,0 +1,12 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_send
+dist_pkgdata_SCRIPTS = \
+       zfs_send.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_send_001_pos.ksh \
+       zfs_send_002_pos.ksh \
+       zfs_send_003_pos.ksh \
+       zfs_send_004_neg.ksh \
+       zfs_send_005_pos.ksh \
+       zfs_send_006_pos.ksh \
+       zfs_send_007_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/cleanup.ksh
new file mode 100755 (executable)
index 0000000..cec69d4
--- /dev/null
@@ -0,0 +1,33 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+poolexists $TESTPOOL1 && \
+       destroy_pool $TESTPOOL1
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send.cfg
new file mode 100644 (file)
index 0000000..bbc4d3a
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+export BLOCK_SIZE=512
+export WRITE_COUNT=8
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_001_pos.ksh
new file mode 100755 (executable)
index 0000000..0f3ae61
--- /dev/null
@@ -0,0 +1,127 @@
+#!/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_SUITE/tests/functional/cli_root/cli_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_send/zfs_send.cfg
+
+#
+# DESCRIPTION:
+#      Verify 'zfs send' can create valid send streams as expected.
+#
+# STRATEGY:
+#      1. Fill in fs with some data
+#      2. Create a full send streams with the fs
+#      3. Receive the send stream and verify the data integrity
+#      4. Fill in fs with some new data
+#      5. Create an incremental send stream with the fs
+#      6. Receive the incremental send stream and verify the data integrity.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for snap in $init_snap $inc_snap $rst_snap $rst_inc_snap; do
+                snapexists $snap && \
+                        log_must $ZFS destroy -f $snap
+        done
+
+       datasetexists $rst_root && \
+               log_must $ZFS destroy -Rf $rst_root
+
+       for file in $full_bkup $inc_bkup \
+                       $init_data $inc_data
+       do
+               [[ -e $file ]] && \
+                       log_must $RM -f $file
+       done
+
+       [[ -d $TESTDIR1 ]] && \
+               log_must $RM -rf $TESTDIR1
+
+}
+
+log_assert "Verify 'zfs send' can create valid send streams as expected."
+log_onexit cleanup
+
+init_snap=$TESTPOOL/$TESTFS@init_snap
+inc_snap=$TESTPOOL/$TESTFS@inc_snap
+full_bkup=/var/tmp/fullbkup.$$
+inc_bkup=/var/tmp/incbkup.$$
+init_data=$TESTDIR/$TESTFILE1
+inc_data=$TESTDIR/$TESTFILE2
+orig_sum=""
+rst_sum=""
+rst_root=$TESTPOOL/rst_ctr
+rst_snap=$rst_root/$TESTFS@init_snap
+rst_inc_snap=$rst_root/$TESTFS@inc_snap
+rst_data=$TESTDIR1/$TESTFS/$TESTFILE1
+rst_inc_data=$TESTDIR1/$TESTFS/$TESTFILE2
+
+
+log_note "Verify 'zfs send' can create full send stream."
+
+#Pre-paration
+log_must $ZFS create $rst_root
+[[ ! -d $TESTDIR1 ]] && \
+       log_must $MKDIR -p $TESTDIR1
+log_must $ZFS set mountpoint=$TESTDIR1 $rst_root
+
+$FILE_WRITE -o create -f $init_data -b $BLOCK_SIZE -c $WRITE_COUNT
+
+log_must $ZFS snapshot $init_snap
+$ZFS send $init_snap > $full_bkup
+(( $? != 0 )) && \
+       log_fail "'$ZFS send' fails to create full send"
+
+log_note "Verify the send stream is valid to receive."
+
+log_must $ZFS receive $rst_snap <$full_bkup
+receive_check $rst_snap ${rst_snap%%@*}
+compare_cksum $init_data $rst_data
+
+log_note "Verify 'zfs send -i' can create incremental send stream."
+
+$FILE_WRITE -o create -f $inc_data -b $BLOCK_SIZE -c $WRITE_COUNT -d 0
+
+log_must $ZFS snapshot $inc_snap
+$ZFS send -i $init_snap $inc_snap > $inc_bkup
+(( $? != 0 )) && \
+       log_fail "'$ZFS send -i' fails to create incremental send"
+
+log_note "Verify the incremental send stream is valid to receive."
+
+log_must $ZFS rollback $rst_snap
+log_must $ZFS receive $rst_inc_snap <$inc_bkup
+receive_check $rst_inc_snap
+compare_cksum $inc_data $rst_inc_data
+
+log_pass "Verifying 'zfs receive' succeed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_002_pos.ksh
new file mode 100755 (executable)
index 0000000..b542bf9
--- /dev/null
@@ -0,0 +1,139 @@
+#!/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_SUITE/tests/functional/cli_root/cli_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_send/zfs_send.cfg
+
+#
+# DESCRIPTION:
+#      Verify 'zfs send' can generate valid streams with a property setup.
+#
+# STRATEGY:
+#      1. Setup property for filesystem
+#      2. Fill in some data into filesystem
+#      3. Create a full send streams
+#      4. Receive the send stream
+#      5. Verify the receive result
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       snapexists $snap && \
+               log_must $ZFS destroy $snap
+
+       datasetexists $ctr && \
+               log_must $ZFS destroy -r $ctr
+
+       [[ -e $origfile ]] && \
+               log_must $RM -f $origfile
+
+       [[ -e $stream ]] && \
+               log_must $RM -f $stream
+}
+
+function do_testing # <prop> <prop_value>
+{
+       typeset property=$1
+       typeset prop_val=$2
+
+       log_must $ZFS set $property=$prop_val $fs
+       $FILE_WRITE -o create -f $origfile -b $BLOCK_SIZE -c $WRITE_COUNT
+       log_must $ZFS snapshot $snap
+       $ZFS send $snap > $stream
+       (( $? != 0 )) && \
+               log_fail "'$ZFS send' fails to create send streams."
+       $ZFS receive -d $ctr <$stream
+       (( $? != 0 )) && \
+               log_fail "'$ZFS receive' fails to receive send streams."
+
+       #verify receive result
+       ! datasetexists $rstfs && \
+               log_fail "'$ZFS receive' fails to restore $rstfs"
+       ! snapexists $rstfssnap && \
+               log_fail "'$ZFS receive' fails to restore $rstfssnap"
+       if [[ ! -e $rstfile ]] || [[ ! -e $rstsnapfile ]]; then
+               log_fail " Data lost after receiving stream"
+       fi
+
+       compare_cksum $origfile $rstfile
+       compare_cksum $origsnapfile $rstsnapfile
+
+       #Destroy datasets and stream for next testing
+       log_must $ZFS destroy $snap
+       if is_global_zone ; then
+               log_must $ZFS destroy -r $rstfs
+       else
+               log_must $ZFS destroy -r $ds_path
+       fi
+       log_must $RM -f $stream
+}
+
+log_assert "Verify 'zfs send' generates valid streams with a property setup"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+snap=$fs@$TESTSNAP
+ctr=$TESTPOOL/$TESTCTR
+if is_global_zone; then
+       rstfs=$ctr/$TESTFS
+else
+       ds_path=$ctr/${ZONE_CTR}0
+       rstfs=$ds_path/$TESTFS
+fi
+rstfssnap=$rstfs@$TESTSNAP
+snapdir=".zfs/snapshot/$TESTSNAP"
+origfile=$TESTDIR/$TESTFILE1
+rstfile=/$rstfs/$TESTFILE1
+origsnapfile=$TESTDIR/$snapdir/$TESTFILE1
+rstsnapfile=/$rstfs/$snapdir/$TESTFILE1
+stream=/var/tmp/streamfile.$$
+
+set -A props "compression" "checksum" "recordsize"
+set -A propval "on lzjb" "on fletcher2 fletcher4 sha256" \
+       "512 1k 4k 8k 16k 32k 64k 128k"
+
+#Create a dataset to receive the send stream
+log_must $ZFS create $ctr
+
+typeset -i i=0
+while (( i < ${#props[*]} ))
+do
+       for value in ${propval[i]}
+       do
+               do_testing ${props[i]} $value
+       done
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zfs send' generates streams with a property setup as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_003_pos.ksh
new file mode 100755 (executable)
index 0000000..749f074
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs send -i' can deal with abbreviated snapshot name.
+#
+# STRATEGY:
+#      1. Create pool, fs and two snapshots.
+#      2. Make sure 'zfs send -i' support abbreviated snapshot name.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $snap1 && log_must $ZFS destroy $snap1
+       datasetexists $snap2 && log_must $ZFS destroy $snap2
+}
+
+log_assert "'zfs send -i' can deal with abbreviated snapshot name."
+log_onexit cleanup
+
+snap1=$TESTPOOL/$TESTFS@snap1; snap2=$TESTPOOL/$TESTFS@snap2
+
+set -A args "$snap1 $snap2" \
+       "${snap1##*@} $snap2" "@${snap1##*@} $snap2"
+
+log_must $ZFS snapshot $snap1
+log_must $ZFS snapshot $snap2
+
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_must eval "$ZFS send -i ${args[i]} > /dev/null"
+
+       (( i += 1 ))
+done
+
+log_pass "'zfs send -i' deal with abbreviated snapshot name passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_004_neg.ksh
new file mode 100755 (executable)
index 0000000..4f0bf2b
--- /dev/null
@@ -0,0 +1,105 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify 'zfs send' fails with malformed parameters.
+#
+# STRATEGY:
+#      1. Define malformed parameters in array
+#      2. Feed the parameters to 'zfs send'
+#      3. Verify the result
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset snap f
+
+       for snap in $snap1 $snap2 $snap3; do
+               snapexists $snap && \
+                       log_must $ZFS destroy -f $snap
+       done
+
+       for f in $tmpfile1 $tmpfile2; do
+               if [[ -e $f ]]; then
+                       $RM -f $f
+               fi
+       done
+}
+
+fs=$TESTPOOL/$TESTFS
+snap1=$fs@snap1
+snap2=$fs@snap2
+snap3=$fs@snap3
+
+set -A badargs \
+       "" "$TESTPOOL" "$TESTFS" "$fs" "$fs@nonexisten_snap" "?" \
+       "$snap1/blah" "$snap1@blah" "-i" "-x" "-i $fs" \
+       "-x $snap1 $snap2" "-i $snap1" \
+       "-i $snap2 $snap1" "$snap1 $snap2" "-i $snap1 $snap2 $snap3" \
+       "-ii $snap1 $snap2" "-iii $snap1 $snap2" " -i $snap2 $snap1/blah" \
+       "-i $snap2/blah $snap1" \
+       "-i $snap2/blah $snap1/blah" \
+       "-i $snap1 blah@blah" \
+       "-i blah@blah $snap1" \
+       "-i $snap1 ${snap2##*@}" "-i $snap1 @${snap2##*@}" \
+       "-i ${snap1##*@} ${snap2##*@}" "-i @${snap1##*@} @${snap2##*@}" \
+       "-i ${snap1##*@} $snap2/blah" "-i @${snap1##*@} $snap2/blah" \
+       "-i @@${snap1##*@} $snap2" "-i $snap1 -i $snap1 $snap2" \
+       "-i snap1 snap2" "-i $snap1 snap2" \
+       "-i $snap1 $snap2 -i $snap1 $snap2" \
+       "-i snap1 $snap2 -i snap1 $snap2"
+
+log_assert "Verify that invalid parameters to 'zfs send' are caught."
+log_onexit cleanup
+
+log_must $ZFS snapshot $snap1
+tmpfile1=$TESTDIR/testfile1.$$
+log_must $TOUCH $tmpfile1
+log_must $ZFS snapshot $snap2
+tmpfile2=$TESTDIR/testfile2.$$
+log_must $TOUCH $tmpfile2
+log_must $ZFS snapshot $snap3
+
+typeset -i i=0
+while (( i < ${#badargs[*]} ))
+do
+       log_mustnot eval "$ZFS send ${badargs[i]} >/dev/null"
+
+       (( i = i + 1 ))
+done
+
+#Testing zfs send fails by send backup stream to terminal
+for arg in "$snap1" "-i $snap1 $snap2"; do
+       log_mustnot eval "$ZFS send $arg >/dev/console"
+done
+
+log_pass "Invalid parameters to 'zfs send' are caught as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_005_pos.ksh
new file mode 100755 (executable)
index 0000000..ffabfe1
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# 'zfs send -R' can send from read-only imported pool. It needs to
+# detect that the pool is read-only and not try to place holds on
+# datasets being sent.
+#
+# STRATEGY:
+# 1. Create a recursive snapshot on the whole pool.
+# 2. 'zfs send -R' the recursive snapshots.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       poolexists $TESTPOOL && log_must $ZPOOL export $TESTPOOL
+       log_must $ZPOOL import $TESTPOOL
+
+       datasetexists $TESTPOOL@snap && \
+           log_must $ZFS destroy -r $TESTPOOL@snap
+}
+
+log_assert "'zfs send -R' can send from read-only pools"
+log_onexit cleanup
+
+log_must $ZFS snapshot -r $TESTPOOL@snap
+
+log_must $ZPOOL export $TESTPOOL
+log_must $ZPOOL import -o readonly=on $TESTPOOL
+
+log_must eval "$ZFS send -R $TESTPOOL@snap >/dev/null"
+
+log_pass "'zfs send -R' can send from read-only pools"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_006_pos.ksh
new file mode 100755 (executable)
index 0000000..7580c6d
--- /dev/null
@@ -0,0 +1,194 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+#
+# DESCRIPTION:
+#      Verify 'zfs send' can generate valid streams with different options
+#
+# STRATEGY:
+#      1. Create datasets
+#      2. Write some data to the datasets
+#      3. Create a full send streams
+#      4. Receive the send stream
+#      5. Do a dry run with different options and verify the generated size
+#          estimate against the received stream
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for ds in $datasets; do
+                datasetexists $ds && $ZFS destroy -rf $ds
+       done
+}
+
+function cal_percentage
+{
+       typeset value=$1
+       return=$($ECHO "$PERCENT * $value" | bc)
+       return=$($ECHO "$return / 100" | bc)
+       echo $return
+}
+
+function get_estimate_size
+{
+       typeset snapshot=$1
+       typeset option=$2
+       typeset base_snapshot=${3:-""}
+       if [[ -z $3 ]];then
+               typeset total_size=$($ZFS send $option $snapshot 2>&1 | $TAIL -1)
+       else
+               typeset total_size=$($ZFS send $option $base_snapshot $snapshot \
+                    2>&1 | $TAIL -1)
+       fi
+       if [[ $options == *"P"* ]]; then
+               total_size=$($ECHO "$total_size" | $AWK '{print $2}')
+       else
+               total_size=$($ECHO "$total_size" | $AWK '{print $5}')
+               total_size=${total_size%M}
+               total_size=$($ECHO "$total_size * $block_count" | bc)
+       fi
+       $ECHO $total_size
+
+}
+
+function verify_size_estimates
+{
+       typeset options=$1
+       typeset file_size=$2
+       typeset refer_diff=$($ECHO "$refer_size - $estimate_size" | bc)
+       refer_diff=$($ECHO "$refer_diff / 1" | bc)
+       refer_diff=$($ECHO "$refer_diff" | $NAWK '{print ($1 < 0) ? ($1 * -1): $1'})
+       typeset file_diff=$($ECHO "$file_size - $estimate_size" | bc)
+       file_diff=$($ECHO "$file_diff / 1" | bc)
+       file_diff=$($ECHO "$file_diff" | $NAWK '{print ($1 < 0) ? ($1 * -1):$1'})
+       typeset expected_diff=$(cal_percentage $refer_size)
+
+       [[ -z $refer_diff && -z $file_diff && -z $expected_diff ]] && \
+           log_fail "zfs send $options failed"
+       [[ $refer_diff -le $expected_diff &&  \
+           $file_diff -le $expected_diff ]] || \
+           log_fail "zfs send $options gives wrong size estimates"
+}
+
+log_assert "Verify 'zfs send -nvP' generates valid stream estimates"
+log_onexit cleanup
+typeset -l block_count=0
+typeset -l block_size
+typeset -i PERCENT=1
+
+((block_count=1024*1024))
+
+# create dataset
+log_must $ZFS create $TESTPOOL/$TESTFS1
+
+# create multiple snapshot for the dataset with data
+for block_size in 64 128 256; do
+       log_must $DD if=/dev/urandom of=/$TESTPOOL/$TESTFS1/file$block_size \
+           bs=1M count=$block_size
+       log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$block_size
+done
+
+full_snapshot="$TESTPOOL/$TESTFS1@snap64"
+increamental_snapshot="$TESTPOOL/$TESTFS1@snap256"
+
+full_size=$($ZFS send $full_snapshot 2>&1 | wc -c)
+increamental_size=$($ZFS send $increamental_snapshot 2>&1 | wc -c)
+increamental_send=$($ZFS send -i $full_snapshot $increamental_snapshot 2>&1 | wc -c)
+
+log_note "verify zfs send -nv"
+options="-nv"
+refer_size=$(get_prop refer $full_snapshot)
+estimate_size=$(get_estimate_size $full_snapshot $options)
+log_must verify_size_estimates $options $full_size
+
+log_note "verify zfs send -Pnv"
+options="-Pnv"
+
+estimate_size=$(get_estimate_size $full_snapshot $options)
+log_must verify_size_estimates $options $full_size
+
+log_note "verify zfs send -nv for multiple snapshot send"
+options="-nv"
+refer_size=$(get_prop refer $increamental_snapshot)
+
+estimate_size=$(get_estimate_size $increamental_snapshot $options)
+log_must verify_size_estimates $options $increamental_size
+
+log_note "verify zfs send -vPn for multiple snapshot send"
+options="-vPn"
+
+estimate_size=$(get_estimate_size $increamental_snapshot $options)
+log_must verify_size_estimates $options $increamental_size
+
+log_note "verify zfs send -inv for increamental send"
+options="-nvi"
+refer_size=$(get_prop refer $increamental_snapshot)
+deduct_size=$(get_prop refer $full_snapshot)
+refer_size=$($ECHO "$refer_size - $deduct_size" | bc)
+
+estimate_size=$(get_estimate_size $increamental_snapshot $options $full_snapshot)
+log_must verify_size_estimates $options $increamental_send
+
+log_note "verify zfs send -ivPn for increamental send"
+options="-vPni"
+
+estimate_size=$(get_estimate_size $increamental_snapshot $options $full_snapshot)
+log_must verify_size_estimates $options $increamental_send
+
+log_must $ZFS destroy -r $TESTPOOL/$TESTFS1
+
+#setup_recursive_send
+datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS2
+    $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3"
+# create nested datasets
+log_must $ZFS create -p $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3
+
+# verify dataset creation
+for ds in $datasets; do
+        datasetexists $ds || log_fail "Create $ds dataset fail."
+done
+for ds in $datasets; do
+       log_must $DD if=/dev/urandom of=/$ds/file64 \
+           bs=1M count=64
+done
+
+# create recursive nested snapshot
+log_must $ZFS snapshot -r $TESTPOOL/$TESTFS1@snap64
+for ds in $datasets; do
+        datasetexists $ds@snap64 || log_fail "Create $ds@snap64 snapshot fail."
+done
+recursive_size=$($ZFS send -R $full_snapshot 2>&1 | wc -c)
+log_note "verify zfs send -Rnv for recursive send"
+options="-Rnv"
+refer_size=$(get_prop refer $full_snapshot)
+refer_size=$($ECHO "$refer_size * 3" | bc)
+
+estimate_size=$(get_estimate_size $full_snapshot $options)
+log_must verify_size_estimates $options $recursive_size
+
+log_note "verify zfs send -RvPn for recursive send"
+options="-RvPn"
+estimate_size=$(get_estimate_size $full_snapshot $options)
+log_must verify_size_estimates $options $recursive_size
+
+log_pass "'zfs send' prints the correct size estimates using '-n' and '-P' options."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_007_pos.ksh
new file mode 100755 (executable)
index 0000000..308903d
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2015, 2016 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+#
+# DESCRIPTION:
+#      Verify 'zfs send' drills holes appropriately when files are replaced
+#
+# STRATEGY:
+#      1. Create dataset
+#      2. Write block 0 in a bunch of files
+#      3. Snapshot the dataset
+#      4. Remove all the files and rewrite some files with just block 1
+#      5. Snapshot the dataset
+#      6. Send both snapshots and receive them locally
+#      7. diff the received dataset and the old datasets.
+#      8. Repeat steps 1-7 above with pool that never had hole birth enabled.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $ZFS destroy -rf $TESTPOOL/fs
+       $ZFS destroy -rf $TESTPOOL/recvfs
+       $RM $streamfile
+       $RM $vdev
+       $ZPOOL destroy testpool
+}
+
+
+log_assert "Verify that 'zfs send' drills appropriate holes"
+log_onexit cleanup
+streamfile=$(mktemp /var/tmp/file.XXXXXX)
+vdev=$(mktemp /var/tmp/file.XXXXXX)
+
+
+test_pool ()
+{
+       POOL=$1
+       log_must $ZFS create -o recordsize=512 $POOL/fs
+       mntpnt=$(get_prop mountpoint "$POOL/fs")
+       log_must $DD if=/dev/urandom of=${mntpnt}/file bs=512 count=1 2>/dev/null
+       first_object=$(ls -i $mntpnt | awk '{print $1}')
+       log_must $ZFS snapshot $POOL/fs@a
+       while true; do
+               log_must $FIND $mntpnt/* -delete
+               sync
+               log_must $MKFILES "$mntpnt/" 4000
+               FILE=$(ls -i $mntpnt | awk \
+                       '{if ($1 == '$first_object') {print $2}}')
+               if [[ -n "$FILE" ]]; then
+                       break
+               fi
+       done
+       $DD if=/dev/urandom of=${mntpnt}/$FILE bs=512 count=1 seek=1 2>/dev/null
+
+       log_must $ZFS snapshot $POOL/fs@b
+
+       log_must eval "$ZFS send $POOL/fs@a > $streamfile"
+       $CAT $streamfile | log_must $ZFS receive $POOL/recvfs
+
+       log_must eval "$ZFS send -i @a $POOL/fs@b > $streamfile"
+       $CAT $streamfile | log_must $ZFS receive $POOL/recvfs
+
+       recv_mntpnt=$(get_prop mountpoint "$POOL/recvfs")
+       log_must $DIFF -r $mntpnt $recv_mntpnt
+       log_must $ZFS destroy -rf $POOL/fs
+       log_must $ZFS destroy -rf $POOL/recvfs
+}
+
+test_pool $TESTPOOL
+log_must $TRUNCATE --size=1G $vdev
+log_must $ZPOOL create -o version=1 testpool $vdev
+test_pool testpool
+log_must $ZPOOL destroy testpool
+log_must $ZPOOL create -d testpool $vdev
+test_pool testpool
+log_must $ZPOOL destroy testpool
+
+
+log_pass "'zfs send' drills appropriate holes"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/Makefile.am
new file mode 100644 (file)
index 0000000..f47ff10
--- /dev/null
@@ -0,0 +1,31 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_set
+dist_pkgdata_SCRIPTS = \
+       zfs_set_common.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       cache_001_pos.ksh \
+       cache_002_neg.ksh \
+       canmount_001_pos.ksh \
+       canmount_002_pos.ksh \
+       canmount_003_pos.ksh \
+       canmount_004_pos.ksh \
+       checksum_001_pos.ksh \
+       compression_001_pos.ksh \
+       mountpoint_001_pos.ksh \
+       mountpoint_002_pos.ksh \
+       mountpoint_003_pos.ksh \
+       onoffs_001_pos.ksh \
+       property_alias_001_pos.ksh \
+       readonly_001_pos.ksh \
+       reservation_001_neg.ksh \
+       ro_props_001_pos.ksh \
+       share_mount_001_neg.ksh \
+       snapdir_001_pos.ksh \
+       user_property_001_pos.ksh \
+       user_property_002_pos.ksh \
+       user_property_003_neg.ksh \
+       user_property_004_pos.ksh \
+       version_001_neg.ksh \
+       zfs_set_001_neg.ksh \
+       zfs_set_002_neg.ksh \
+       zfs_set_003_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cache_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cache_001_pos.ksh
new file mode 100755 (executable)
index 0000000..bffc47f
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting a valid primarycache and secondarycache on file system or volume.
+# It should be successful.
+#
+# STRATEGY:
+# 1. Create pool, then create filesystem & volume within it.
+# 2. Setting valid cache value, it should be successful.
+#
+
+verify_runnable "both"
+
+set -A dataset "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTVOL"
+set -A values  "none" "all" "metadata"
+
+log_assert "Setting a valid {primary|secondary}cache on file system and volume, " \
+       "It should be successful."
+
+typeset -i i=0
+typeset -i j=0
+for propname in "primarycache" "secondarycache"
+do
+       while (( i < ${#dataset[@]} )); do
+               j=0
+               while (( j < ${#values[@]} )); do
+                       set_n_check_prop "${values[j]}" "$propname" "${dataset[i]}"
+                       (( j += 1 ))
+               done
+               (( i += 1 ))
+       done
+done
+
+log_pass "Setting a valid {primary|secondary}cache on file system or volume pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cache_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cache_002_neg.ksh
new file mode 100755 (executable)
index 0000000..653f31a
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting invalid primarycache and secondarycache on file system or volume.
+# It should fail.
+#
+# STRATEGY:
+# 1. Create pool, then create filesystem & volume within it.
+# 2. Setting invalid {primary|secondary}cache value, it should fail.
+#
+
+verify_runnable "both"
+
+set -A dataset "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTVOL"
+set -A values  "12345" "null" "not_existed" "abcd1234"
+
+log_assert "Setting invalid {primary|secondary}cache on fs and volume, " \
+       "It should fail."
+
+typeset -i i=0
+typeset -i j=0
+for propname in "primarycache" "secondarycache"
+do
+       while (( i < ${#dataset[@]} )); do
+               j=0
+               while (( j < ${#values[@]} )); do
+                       log_mustnot $ZFS set $propname=${values[j]} ${dataset[i]}
+                       (( j += 1 ))
+               done
+               (( i += 1 ))
+       done
+done
+
+log_pass "Setting invalid {primary|secondary}cache on fs or volume fail as expeced."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_001_pos.ksh
new file mode 100755 (executable)
index 0000000..de219c4
--- /dev/null
@@ -0,0 +1,119 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting valid canmount to filesystem, it is successful.
+# Whatever is set to volume or snapshot, it is failed.
+# 'zfs set canmount=on|off <fs>'
+#
+# STRATEGY:
+# 1. Setup a pool and create fs, volume, snapshot clone within it.
+# 2. Loop all the valid mountpoint value.
+# 3. Check the return value.
+#
+
+verify_runnable "both"
+
+set -A dataset_pos \
+       "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTCLONE"
+
+if is_global_zone ; then
+       set -A dataset_neg \
+               "$TESTPOOL/$TESTVOL" "$TESTPOOL/$TESTFS@$TESTSNAP" \
+               "$TESTPOOL/$TESTVOL@$TESTSNAP"  "$TESTPOOL/$TESTCLONE1"
+else
+       set -A dataset_neg \
+               "$TESTPOOL/$TESTFS@$TESTSNAP" "$TESTPOOL/$TESTVOL@$TESTSNAP"
+fi
+
+
+set -A values "on" "off"
+
+function cleanup
+{
+       if snapexists $TESTPOOL/$TESTFS@$TESTSNAP ; then
+               log_must $ZFS destroy -R $TESTPOOL/$TESTFS@$TESTSNAP
+       fi
+       if snapexists $TESTPOOL/$TESTVOL@$TESTSNAP ; then
+               log_must $ZFS destroy -R $TESTPOOL/$TESTVOL@$TESTSNAP
+       fi
+
+       [[ -n $old_ctr_canmount ]] && \
+               log_must $ZFS set canmount=$old_ctr_canmount $TESTPOOL/$TESTCTR
+       [[ -n $old_fs_canmount ]] && \
+               log_must $ZFS set canmount=$old_fs_canmount $TESTPOOL/$TESTFS
+
+       $ZFS unmount -a > /dev/null 2>&1
+       log_must $ZFS mount -a
+}
+
+log_assert "Setting a valid property of canmount to file system, it must be successful."
+log_onexit cleanup
+
+typeset old_fs_canmount="" old_ctr_canmount=""
+
+old_fs_canmount=$(get_prop canmount $TESTPOOL/$TESTFS)
+[[ $? != 0 ]] && \
+       log_fail "Get the $TESTPOOL/$TESTFS canmount error."
+old_ctr_canmount=$(get_prop canmount $TESTPOOL/$TESTCTR)
+[[ $? != 0 ]] && \
+       log_fail "Get the $TESTPOOL/$TESTCTR canmount error."
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+log_must $ZFS snapshot $TESTPOOL/$TESTVOL@$TESTSNAP
+log_must $ZFS clone $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTCLONE
+log_must $ZFS clone $TESTPOOL/$TESTVOL@$TESTSNAP $TESTPOOL/$TESTCLONE1
+
+for dataset in "${dataset_pos[@]}" ; do
+       for value in "${values[@]}" ; do
+               set_n_check_prop "$value" "canmount" "$dataset"
+               if [[ $value == "off" ]]; then
+                       log_mustnot ismounted $dataset
+                       log_mustnot $ZFS mount $dataset
+                       log_mustnot ismounted $dataset
+               else
+                       if ! ismounted $dataset ; then
+                               log_must $ZFS mount $dataset
+                       fi
+                       log_must ismounted $dataset
+               fi
+       done
+done
+
+for dataset in "${dataset_neg[@]}" ; do
+       for value in "${values[@]}" ; do
+               set_n_check_prop "$value" "canmount" \
+                       "$dataset" "false"
+               log_mustnot ismounted $dataset
+       done
+done
+
+log_pass "Setting canmount to filesystem pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_002_pos.ksh
new file mode 100755 (executable)
index 0000000..447a9e8
--- /dev/null
@@ -0,0 +1,150 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting valid canmount to filesystem, it is successful.
+# Whatever is set to volume or snapshot, it is failed.
+# 'zfs set canmount=noauto <fs>'
+#
+# STRATEGY:
+# 1. Setup a pool and create fs, volume, snapshot clone within it.
+# 2. Set canmount=noauto for each dataset and check the retuen value
+#    and check if it still can be mounted by mount -a.
+# 3. mount each dataset(except volume) to see if it can be mounted.
+#
+
+verify_runnable "both"
+
+set -A dataset_pos \
+       "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTCLONE"
+
+if is_global_zone ; then
+       set -A dataset_neg \
+               "$TESTPOOL/$TESTVOL" "$TESTPOOL/$TESTFS@$TESTSNAP" \
+               "$TESTPOOL/$TESTVOL@$TESTSNAP"  "$TESTPOOL/$TESTCLONE1"
+else
+       set -A dataset_neg \
+               "$TESTPOOL/$TESTFS@$TESTSNAP" "$TESTPOOL/$TESTVOL@$TESTSNAP"
+fi
+
+function cleanup
+{
+       i=0
+       while (( i < ${#dataset_pos[*]} )); do
+               ds=${dataset_pos[i]}
+               if datasetexists $ds; then
+                       log_must $ZFS set mountpoint=${old_mnt[i]} $ds
+                       log_must $ZFS set canmount=${old_canmount[i]} $ds
+               fi
+               (( i = i + 1 ))
+       done
+
+       ds=$TESTPOOL/$TESTCLONE
+       if datasetexists $ds; then
+               mntp=$(get_prop mountpoint $ds)
+               log_must $ZFS destroy $ds
+               if [[ -d $mntp ]]; then
+                       $RM -fr $mntp
+               fi
+       fi
+
+       if snapexists $TESTPOOL/$TESTFS@$TESTSNAP ; then
+               log_must $ZFS destroy -R $TESTPOOL/$TESTFS@$TESTSNAP
+       fi
+       if snapexists $TESTPOOL/$TESTVOL@$TESTSNAP ; then
+               log_must $ZFS destroy -R $TESTPOOL/$TESTVOL@$TESTSNAP
+       fi
+
+       $ZFS unmount -a > /dev/null 2>&1
+       log_must $ZFS mount -a
+
+       if [[ -d $tmpmnt ]]; then
+               $RM -fr $tmpmnt
+       fi
+}
+
+log_assert "Setting canmount=noauto to file system, it must be successful."
+log_onexit cleanup
+
+set -A old_mnt
+set -A old_canmount
+typeset tmpmnt=/tmpmount$$
+typeset ds
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+log_must $ZFS snapshot $TESTPOOL/$TESTVOL@$TESTSNAP
+log_must $ZFS clone $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTCLONE
+log_must $ZFS clone $TESTPOOL/$TESTVOL@$TESTSNAP $TESTPOOL/$TESTCLONE1
+
+typeset -i i=0
+while (( i < ${#dataset_pos[*]} )); do
+       ds=${dataset_pos[i]}
+       old_mnt[i]=$(get_prop mountpoint $ds)
+       old_canmount[i]=$(get_prop canmount $ds)
+       (( i = i + 1 ))
+done
+
+i=0
+while (( i < ${#dataset_pos[*]} )) ; do
+       dataset=${dataset_pos[i]}
+       set_n_check_prop "noauto" "canmount" "$dataset"
+       log_must $ZFS set mountpoint=$tmpmnt $dataset
+       if  ismounted $dataset; then
+               $ZFS unmount -a > /dev/null 2>&1
+               log_must mounted $dataset
+               log_must $ZFS unmount $dataset
+               log_must unmounted $dataset
+               log_must $ZFS mount -a
+               log_must unmounted $dataset
+       else
+               log_must $ZFS mount -a
+               log_must unmounted $dataset
+               $ZFS unmount -a > /dev/null 2>&1
+               log_must unmounted $dataset
+       fi
+
+       log_must $ZFS mount $dataset
+       log_must mounted $dataset
+       log_must $ZFS set canmount="${old_canmount[i]}" $dataset
+       log_must $ZFS set mountpoint="${old_mnt[i]}" $dataset
+       (( i = i + 1 ))
+done
+
+for dataset in "${dataset_neg[@]}" ; do
+       set_n_check_prop "noauto" "canmount" "$dataset" "false"
+       log_mustnot ismounted $dataset
+done
+
+log_pass "Setting canmount=noauto to filesystem pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_003_pos.ksh
new file mode 100755 (executable)
index 0000000..886b120
--- /dev/null
@@ -0,0 +1,111 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# While canmount=noauto and  the dataset is mounted,
+# zfs must not attempt to unmount it.
+#
+# STRATEGY:
+# 1. Setup a pool and create fs, volume, snapshot clone within it.
+# 2. Set canmount=noauto for each dataset and check the return value
+#    and check if it still can not be unmounted when the dataset is mounted
+#
+
+verify_runnable "both"
+
+set -A dataset_pos "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCLONE"
+
+function cleanup
+{
+       i=0
+       cd $pwd
+       while (( i < ${#dataset_pos[*]} )); do
+               ds=${dataset_pos[i]}
+               if datasetexists $ds; then
+                       log_must $ZFS set mountpoint=${old_mnt[i]} $ds
+                       log_must $ZFS set canmount=${old_canmount[i]} $ds
+               fi
+               (( i = i + 1 ))
+       done
+
+       ds=$TESTPOOL/$TESTCLONE
+       if datasetexists $ds; then
+               mntp=$(get_prop mountpoint $ds)
+               log_must $ZFS destroy $ds
+               if [[ -d $mntp ]]; then
+                       log_must $RM -fr $mntp
+               fi
+       fi
+
+       if snapexists $TESTPOOL/$TESTFS@$TESTSNAP ; then
+               log_must $ZFS destroy -R $TESTPOOL/$TESTFS@$TESTSNAP
+       fi
+
+       $ZFS unmount -a > /dev/null 2>&1
+       log_must $ZFS mount -a
+}
+
+log_assert "While canmount=noauto and  the dataset is mounted,"\
+               " zfs must not attempt to unmount it"
+log_onexit cleanup
+
+set -A old_mnt
+set -A old_canmount
+typeset ds
+typeset pwd=$PWD
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+log_must $ZFS clone $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTCLONE
+
+typeset -i i=0
+while (( i < ${#dataset_pos[*]} )); do
+       ds=${dataset_pos[i]}
+       old_mnt[i]=$(get_prop mountpoint $ds)
+       old_canmount[i]=$(get_prop canmount $ds)
+       (( i = i + 1 ))
+done
+
+i=0
+while (( i < ${#dataset_pos[*]} )) ; do
+       dataset=${dataset_pos[i]}
+       if  ismounted $dataset; then
+               log_must cd ${old_mnt[i]}
+               set_n_check_prop "noauto" "canmount" "$dataset"
+               log_must mounted $dataset
+       fi
+       (( i = i + 1 ))
+done
+
+log_pass "Setting canmount=noauto to filesystem while dataset busy pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/canmount_004_pos.ksh
new file mode 100755 (executable)
index 0000000..bc8e279
--- /dev/null
@@ -0,0 +1,92 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify canmount=noauto work fine when setting sharenfs or sharesmb.
+#
+# STRATEGY:
+# 1. Create a fs canmount=noauto.
+# 2. Set sharenfs or sharesmb.
+# 3. Verify the fs is umounted.
+#
+
+verify_runnable "global"
+
+# properties
+set -A sharenfs_prop "off" "on" "rw"
+set -A sharesmb_prop "off" "on"
+
+function cleanup
+{
+       log_must $ZFS destroy -rR $CS_FS
+}
+
+function assert_unmounted
+{
+       mnted=$(get_prop mounted $CS_FS)
+       if [[ "$mnted" == "yes" ]]; then
+               canmnt=$(get_prop canmount $CS_FS)
+               shnfs=$(get_prop sharenfs $CS_FS)
+               shsmb=$(get_prop sharesmb $CS_FS)
+               mntpt=$(get_prop mountpoint $CS_FS)
+               log_fail "$CS_FS should be unmounted" \
+               "[canmount=$canmnt,sharenfs=$shnfs,sharesmb=$shsmb,mountpoint=$mntpt]."
+       fi
+}
+
+log_assert "Verify canmount=noauto work fine when setting sharenfs or sharesmb."
+log_onexit cleanup
+
+CS_FS=$TESTPOOL/$TESTFS/cs_fs.$$
+oldmpt=$TESTDIR/old_cs_fs.$$
+newmpt=$TESTDIR/new_cs_fs.$$
+
+log_must $ZFS create -o canmount=noauto -o mountpoint=$oldmpt $CS_FS
+assert_unmounted
+
+for n in ${sharenfs_prop[@]}; do
+       log_must $ZFS set sharenfs="$n" $CS_FS
+       assert_unmounted
+       for s in ${sharesmb_prop[@]}; do
+               log_must $ZFS set sharesmb="$s" $CS_FS
+               assert_unmounted
+
+               mntpt=$(get_prop mountpoint $CS_FS)
+               if [[ "$mntpt" == "$oldmpt" ]]; then
+                       log_must $ZFS set mountpoint="$newmpt" $CS_FS
+               else
+                       log_must $ZFS set mountpoint="$oldmpt" $CS_FS
+               fi
+               assert_unmounted
+       done
+done
+
+log_pass "Verify canmount=noauto work fine when setting sharenfs or sharesmb."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/checksum_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/checksum_001_pos.ksh
new file mode 100755 (executable)
index 0000000..27003b2
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting a valid checksum on a pool, file system, volume, it should be
+# successful.
+#
+# STRATEGY:
+# 1. Create pool, then create filesystem and volume within it.
+# 2. Setting different valid checksum to each dataset.
+# 3. Check the return value and make sure it is 0.
+#
+
+verify_runnable "both"
+
+set -A dataset "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTVOL"
+set -A values "on" "off" "fletcher2" "fletcher4" "sha256" "sha512" "skein" "edonr" "noparity"
+
+log_assert "Setting a valid checksum on a file system, volume," \
+       "it should be successful."
+
+typeset -i i=0
+typeset -i j=0
+while (( i < ${#dataset[@]} )); do
+       j=0
+       while (( j < ${#values[@]} )); do
+               set_n_check_prop "${values[j]}" "checksum" "${dataset[i]}"
+               (( j += 1 ))
+       done
+       (( i += 1 ))
+done
+
+log_pass "Setting a valid checksum on a file system, volume pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/cleanup.ksh
new file mode 100755 (executable)
index 0000000..fad025c
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_container_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/compression_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/compression_001_pos.ksh
new file mode 100755 (executable)
index 0000000..f7d06ea
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting a valid compression on file system or volume.
+# It should be successful.
+#
+# STRATEGY:
+# 1. Create pool, then create filesystem & volume within it.
+# 2. Setting valid value, it should be successful.
+#
+
+verify_runnable "both"
+
+set -A dataset "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTVOL"
+set -A values $(get_compress_opts zfs_set)
+
+log_assert "Setting a valid compression on file system and volume, " \
+       "It should be successful."
+
+typeset -i i=0
+typeset -i j=0
+for propname in "compression" "compress"
+do
+       while (( i < ${#dataset[@]} )); do
+               j=0
+               while (( j < ${#values[@]} )); do
+                       set_n_check_prop "${values[j]}" "$propname" "${dataset[i]}"
+                       (( j += 1 ))
+               done
+               (( i += 1 ))
+       done
+done
+
+log_pass "Setting a valid compression on file system or volume pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_001_pos.ksh
new file mode 100755 (executable)
index 0000000..eaf9a62
--- /dev/null
@@ -0,0 +1,100 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting valid mountpoint to filesystem, it is successful.
+# Whatever is set to volume, it is failed.
+# 'zfs set mountpoint=<path>|legacy|none <fs|ctr|vol>'
+#
+# STRATEGY:
+# 1. Setup a pool and create fs, ctr within it.
+# 2. Loop all the valid mountpoint value.
+# 3. Check the return value.
+#
+
+verify_runnable "both"
+
+export TESTDIR_NOTEXISTING=${TEST_BASE_DIR%%/}/testdir_notexisting$$
+
+if is_global_zone ; then
+       set -A dataset \
+               "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTVOL"
+else
+       set -A dataset "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCTR"
+fi
+
+set -A values "$TESTDIR2" "legacy" "none" "$TESTDIR_NOTEXISTING"
+
+function cleanup
+{
+       log_must $ZFS set mountpoint=$old_ctr_mpt $TESTPOOL/$TESTCTR
+       log_must $ZFS set mountpoint=$old_fs_mpt $TESTPOOL/$TESTFS
+       [[ -d $TESTDIR2 ]] && log_must $RM -r $TESTDIR2
+       [[ -d $TESTDIR_NOTEXISTING ]] && log_must $RM -r $TESTDIR_NOTEXISTING
+}
+
+log_assert "Setting a valid mountpoint to file system, it must be successful."
+log_onexit cleanup
+
+old_fs_mpt=$(get_prop mountpoint $TESTPOOL/$TESTFS)
+[[ $? != 0 ]] && \
+       log_fail "Get the $TESTPOOL/$TESTFS mountpoint error."
+old_ctr_mpt=$(get_prop mountpoint $TESTPOOL/$TESTCTR)
+[[ $? != 0 ]] && \
+       log_fail "Get the $TESTPOOL/$TESTCTR mountpoint error."
+
+if [[ ! -d $TESTDIR2 ]]; then
+       log_must $MKDIR $TESTDIR2
+fi
+
+typeset -i i=0
+typeset -i j=0
+while (( i < ${#dataset[@]} )); do
+       j=0
+       while (( j < ${#values[@]} )); do
+               if [[ ${dataset[i]} == "$TESTPOOL/$TESTVOL" ]]; then
+                       set_n_check_prop "${values[j]}" "mountpoint" \
+                               "${dataset[i]}" "false"
+               else
+                       set_n_check_prop "${values[j]}" "mountpoint" \
+                               "${dataset[i]}"
+               fi
+               (( j += 1 ))
+       done
+       cleanup
+       (( i += 1 ))
+done
+
+log_pass "Setting mountpoint to filesystem pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_002_pos.ksh
new file mode 100755 (executable)
index 0000000..d827fbe
--- /dev/null
@@ -0,0 +1,98 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+#      If ZFS is currently managing the file system but it is currently unmoutned,
+#      and the mountpoint property is changed, the file system remains unmounted.
+#
+# STRATEGY:
+# 1. Setup a pool and create fs, ctr within it.
+# 2. Unmount that dataset
+# 2. Change the mountpoint to the valid mountpoint value.
+# 3. Check the file system remains unmounted.
+#
+
+verify_runnable "both"
+
+export TESTDIR_NOTEXISTING=${TEST_BASE_DIR%%/}/testdir_notexisting$$
+
+set -A dataset "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCTR"
+
+set -A values "$TESTDIR2" "$TESTDIR_NOTEXISTING"
+
+function cleanup
+{
+       log_must $ZFS set mountpoint=$old_ctr_mpt $TESTPOOL/$TESTCTR
+       log_must $ZFS set mountpoint=$old_fs_mpt $TESTPOOL/$TESTFS
+       log_must $ZFS mount -a
+       [[ -d $TESTDIR2 ]] && log_must $RM -r $TESTDIR2
+       [[ -d $TESTDIR_NOTEXISTING ]] && log_must $RM -r $TESTDIR_NOTEXISTING
+}
+
+log_assert "Setting a valid mountpoint for an unmounted file system, \
+       it remains unmounted."
+log_onexit cleanup
+
+old_fs_mpt=$(get_prop mountpoint $TESTPOOL/$TESTFS)
+[[ $? != 0 ]] && \
+       log_fail "Unable to get the mountpoint property for $TESTPOOL/$TESTFS"
+old_ctr_mpt=$(get_prop mountpoint $TESTPOOL/$TESTCTR)
+[[ $? != 0 ]] && \
+       log_fail "Unable to get the mountpoint property for $TESTPOOL/$TESTCTR"
+
+if [[ ! -d $TESTDIR2 ]]; then
+       log_must $MKDIR $TESTDIR2
+fi
+
+typeset -i i=0
+typeset -i j=0
+while (( i < ${#dataset[@]} )); do
+       j=0
+       if ismounted ${dataset[i]} ; then
+               log_must $ZFS unmount ${dataset[i]}
+       fi
+       log_mustnot ismounted ${dataset[i]}
+       while (( j < ${#values[@]} )); do
+               set_n_check_prop "${values[j]}" "mountpoint" \
+                       "${dataset[i]}"
+               log_mustnot ismounted ${dataset[i]}
+               (( j += 1 ))
+       done
+       cleanup
+       (( i += 1 ))
+done
+
+log_pass "Setting a valid mountpoint for an unmounted file system, \
+       it remains unmounted."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/mountpoint_003_pos.ksh
new file mode 100755 (executable)
index 0000000..ce427c1
--- /dev/null
@@ -0,0 +1,115 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify FSType-specific option works well with legacy mount.
+#
+# STRATEGY:
+#      1. Set up FSType-specific options and expected keywords array.
+#      2. Create a test ZFS file system and set mountpoint=legacy.
+#      3. Mount ZFS test filesystem with specific options.
+#      4. Verify the filesystem was mounted with specific option.
+#      5. Loop check all the options.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       ismounted $tmpmnt && log_must $UMOUNT $tmpmnt
+       [[ -d $tmpmnt ]] && log_must $RM -rf $tmpmnt
+       [[ -n $oldmpt ]] && log_must $ZFS set mountpoint=$oldmpt $testfs
+       ! ismounted $oldmpt && log_must $ZFS mount $testfs
+}
+
+log_assert "With legacy mount, FSType-specific option works well."
+log_onexit cleanup
+
+#
+#  /mnt on pool/fs read/write/setuid/devices/noexec/xattr/atime/dev=2d9009e
+#
+#      FSType-                         FSType-
+#      specific        Keyword         specific        Keyword
+#      option                          option
+#
+if is_linux; then
+       set -A args \
+       "dev"           "/dev/"         "nodev"         "/nodev/"       \
+       "exec"          "/exec/"        "noexec"        "/noexec/"      \
+       "mand"          "/mand/"        "nomand"        "/nomand/"      \
+       "ro"            "read only"     "rw"            "read/write"    \
+       "suid"          "/suid/"        "nosuid"        "/nosuid/"      \
+       "xattr"         "/xattr/"       "noxattr"       "/noxattr/"     \
+       "atime"         "/atime/"       "noatime"       "/noatime/"
+else
+       set -A args \
+       "devices"       "/devices/"     "nodevices"     "/nodevices/"   \
+       "exec"          "/exec/"        "noexec"        "/noexec/"      \
+       "nbmand"        "/nbmand/"      "nonbmand"      "/nonbmand/"    \
+       "ro"            "read only"     "rw"            "read/write"    \
+       "setuid"        "/setuid/"      "nosetuid"      "/nosetuid/"    \
+       "xattr"         "/xattr/"       "noxattr"       "/noxattr/"     \
+       "atime"         "/atime/"       "noatime"       "/noatime/"
+fi
+
+tmpmnt=/tmpmnt.$$
+[[ -d $tmpmnt ]] && $RM -rf $tmpmnt
+testfs=$TESTPOOL/$TESTFS
+log_must $MKDIR $tmpmnt
+oldmpt=$(get_prop mountpoint $testfs)
+log_must $ZFS set mountpoint=legacy $testfs
+
+typeset i=0
+while ((i < ${#args[@]})); do
+       if is_linux; then
+               log_must $MOUNT -t zfs -o ${args[$i]} $testfs $tmpmnt
+       else
+               log_must $MOUNT -F zfs -o ${args[$i]} $testfs $tmpmnt
+       fi
+       msg=$($MOUNT | $GREP "^$tmpmnt ")
+
+       if ! is_linux; then
+               # In LZ, a user with all zone privileges can never "devices"
+               if ! is_global_zone && [[ ${args[$i]} == devices ]] ; then
+                       args[((i+1))]="/nodevices/"
+               fi
+       fi
+
+       $ECHO $msg | $GREP "${args[((i+1))]}" > /dev/null 2>&1
+       if (($? != 0)) ; then
+               log_fail "Expected option: ${args[((i+1))]} \n" \
+                        "Real option: $msg"
+       fi
+
+       log_must $UMOUNT $tmpmnt
+       ((i += 2))
+done
+
+log_pass "With legacy mount, FSType-specific option works well passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/onoffs_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/onoffs_001_pos.ksh
new file mode 100755 (executable)
index 0000000..41ff4b7
--- /dev/null
@@ -0,0 +1,99 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting a valid value to atime, readonly, setuid or zoned on file
+# system or volume. It should be successful.
+#
+# STRATEGY:
+# 1. Create pool and filesystem & volume within it.
+# 2. Setting valid value, it should be successful.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS mount -a
+}
+
+log_onexit cleanup
+
+set -A props "atime" "readonly" "setuid" "zoned"
+set -A values "on" "off"
+
+if is_global_zone ; then
+       set -A dataset "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTVOL"
+else
+       set -A dataset "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCTR"
+fi
+
+log_assert "Setting a valid value to atime, readonly, setuid or zoned on file" \
+       "system or volume. It should be successful."
+
+typeset -i i=0
+typeset -i j=0
+typeset -i k=0
+while (( i < ${#dataset[@]} )); do
+       j=0
+       while (( j < ${#props[@]} )); do
+               k=0
+               while (( k < ${#values[@]} )); do
+                       if [[ ${dataset[i]} == "$TESTPOOL/$TESTVOL" &&  \
+                           ${props[j]} != "readonly" ]]
+                       then
+                               set_n_check_prop "${values[k]}" "${props[j]}" \
+                                   "${dataset[i]}" "false"
+                       elif [[ ${props[j]} == "zoned" ]] ; then
+                               if is_global_zone ; then
+                                       set_n_check_prop \
+                                           "${values[k]}" "${props[j]}" \
+                                           "${dataset[i]}"
+                               else
+                                       set_n_check_prop \
+                                           "${values[k]}" "${props[j]}" \
+                                           "${dataset[i]}" "false"
+                               fi
+
+                       else
+                               set_n_check_prop "${values[k]}" "${props[j]}" \
+                                       "${dataset[i]}"
+                       fi
+
+                       (( k += 1 ))
+               done
+               (( j += 1 ))
+       done
+       (( i += 1 ))
+done
+
+log_pass "Setting a valid value to atime, readonly, setuid or zoned on file" \
+       "system or volume pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/property_alias_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/property_alias_001_pos.ksh
new file mode 100755 (executable)
index 0000000..d2f8cee
--- /dev/null
@@ -0,0 +1,140 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Verify the properties with aliases also work with those aliases
+#
+# STRATEGY:
+# 1. Create pool, then create filesystem & volume within it.
+# 2. Set or retrieve property via alias with datasets.
+# 3. Verify the result should be successful.
+#
+
+verify_runnable "both"
+
+function set_and_check #<dataset><set_prop_name><set_value><check_prop_name>
+{
+       typeset ds=$1
+       typeset setprop=$2
+       typeset setval=$3
+       typeset chkprop=$4
+       typeset getval
+
+       log_must $ZFS set $setprop=$setval $ds
+       if [[ $setval == "gzip-6" ]]; then
+               setval="gzip"
+       fi
+       getval=$(get_prop $chkprop $ds)
+
+       case $setprop in
+               reservation|reserv )
+                       if [[ $setval == "none" ]]; then
+                                [[ $getval != "0" ]] && \
+                                       log_fail "Setting the property $setprop" \
+                                               "with value $setval fails."
+                        elif [[ $getval != $setval ]]; then
+                               log_fail "Setting the property $setprop with" \
+                                       "with $setval fails."
+                       fi
+                        ;;
+                 * )
+                        [[ $getval != $setval ]] && \
+                               log_fail "Setting the property $setprop with value \
+                                       $setval fails."
+                        ;;
+         esac
+}
+
+log_assert "Properties with aliases also work with those aliases."
+
+set -A ro_prop "available" "avail" "referenced" "refer"
+set -A rw_prop "readonly" "rdonly" "compression" "compress" "reservation" "reserv"
+set -A chk_prop "rdonly" "readonly" "compress" "compression" "reserv" "reservation"
+set -A size "512" "1024" "2048" "4096" "8192" "16384" "32768" "65536" "131072"
+
+pool=$TESTPOOL
+fs=$TESTPOOL/$TESTFS
+vol=$TESTPOOL/$TESTVOL
+typeset -l avail_space=$(get_prop avail $pool)
+typeset -l reservsize
+typeset -i i=0
+
+for ds in $pool $fs $vol; do
+       for propname in ${ro_prop[*]}; do
+               $ZFS get -pH -o value $propname $ds >/dev/null 2>&1
+               (( $? != 0 )) && \
+                       log_fail "Get the property $proname of $ds failed."
+       done
+       i=0
+       while (( i < ${#rw_prop[*]} )); do
+               case ${rw_prop[i]} in
+               readonly|rdonly )
+                       for val in "on" "off"; do
+                               set_and_check $ds ${rw_prop[i]} $val ${chk_prop[i]}
+                       done
+                       ;;
+               compression|compress )
+                       for val in $(get_compress_opts zfs_set); do
+                               set_and_check $ds ${rw_prop[i]} $val ${chk_prop[i]}
+                       done
+                       ;;
+               reservation|reserv )
+                       (( reservsize = $avail_space % $RANDOM ))
+                       for val in "0" "$reservsize" "none"; do
+                               set_and_check $ds ${rw_prop[i]} $val ${chk_prop[i]}
+                       done
+                       ;;
+               esac
+
+               (( i = i + 1 ))
+       done
+       if [[ $ds == $vol ]]; then
+               for propname in "volblocksize" "volblock" ; do
+                       $ZFS get -pH -o value $propname $ds >/dev/null 2>&1
+                       (( $? != 0 )) && \
+                               log_fail "Get the property $propname of $ds failed."
+               done
+       fi
+done
+
+for ds in $pool $fs; do
+       for propname in "recordsize" "recsize"; do
+               for val in ${size[*]}; do
+                       if [[ $propname == "recordsize" ]]; then
+                               set_and_check $ds $propname $val "recsize"
+                       else
+                               set_and_check $ds $propname $val "recordsize"
+                       fi
+               done
+       done
+done
+
+log_pass "The alias of a property works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/readonly_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/readonly_001_pos.ksh
new file mode 100755 (executable)
index 0000000..a4c04a8
--- /dev/null
@@ -0,0 +1,160 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting readonly on a dataset, it should keep the dataset as readonly.
+#
+# STRATEGY:
+# 1. Create pool, then create filesystem and volume within it.
+# 2. Setting readonly to each dataset.
+# 3. Check the return value and make sure it is 0.
+# 4. Verify the stuff under mountpoint is readonly.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for dataset in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL ; do
+               snapexists ${dataset}@$TESTSNAP && \
+                       log_must $ZFS destroy -R ${dataset}@$TESTSNAP
+       done
+}
+
+function initial_dataset # $1 dataset
+{
+       typeset dataset=$1
+
+       typeset fstype=$(get_prop type $dataset)
+
+       if [[ $fstype == "filesystem" ]] ; then
+               typeset mtpt=$(get_prop mountpoint $dataset)
+               log_must $TOUCH $mtpt/$TESTFILE0
+               log_must $MKDIR -p $mtpt/$TESTDIR0
+       fi
+}
+
+
+function cleanup_dataset # $1 dataset
+{
+       typeset dataset=$1
+
+       typeset fstype=$(get_prop type $dataset)
+
+       if [[ $fstype == "filesystem" ]] ; then
+               typeset mtpt=$(get_prop mountpoint $dataset)
+               log_must $RM -f $mtpt/$TESTFILE0
+               log_must $RM -rf $mtpt/$TESTDIR0
+       fi
+}
+
+function verify_readonly # $1 dataset, $2 on|off
+{
+       typeset dataset=$1
+       typeset value=$2
+
+       if datasetnonexists $dataset ; then
+               log_note "$dataset does not exist!"
+               return 1
+       fi
+
+       typeset fstype=$(get_prop type $dataset)
+
+       expect="log_must"
+
+       if [[ $2 == "on" ]] ; then
+               expect="log_mustnot"
+       fi
+
+       case $fstype in
+               filesystem)
+                       typeset mtpt=$(get_prop mountpoint $dataset)
+                       $expect $TOUCH $mtpt/$TESTFILE1
+                       $expect $MKDIR -p $mtpt/$TESTDIR1
+                       $expect eval "$ECHO 'y' | $RM $mtpt/$TESTFILE0"
+                       $expect $RMDIR $mtpt/$TESTDIR0
+
+                       if [[ $expect == "log_must" ]] ; then
+                               log_must eval "$ECHO 'y' | $RM $mtpt/$TESTFILE1"
+                               log_must $RMDIR $mtpt/$TESTDIR1
+                               log_must $TOUCH $mtpt/$TESTFILE0
+                               log_must $MKDIR -p $mtpt/$TESTDIR0
+                       fi
+                       ;;
+               volume)
+                       $expect eval "$ECHO 'y' | $NEWFS \
+                           ${ZVOL_DEVDIR}/$dataset > /dev/null 2>&1"
+                       ;;
+               *)
+                       ;;
+       esac
+
+       return 0
+}
+
+log_onexit cleanup
+
+log_assert "Setting a valid readonly property on a dataset succeeds."
+
+typeset all_datasets
+
+log_must $ZFS mount -a
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+log_must $ZFS clone $TESTPOOL/$TESTFS@$TESTSNAP $TESTPOOL/$TESTCLONE
+
+if is_global_zone ; then
+       log_must $ZFS snapshot $TESTPOOL/$TESTVOL@$TESTSNAP
+       log_must $ZFS clone $TESTPOOL/$TESTVOL@$TESTSNAP $TESTPOOL/$TESTCLONE1
+       all_datasets="$TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL "
+       all_datasets+="$TESTPOOL/$TESTCLONE $TESTPOOL/$TESTCLONE1"
+else
+       all_datasets="$TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTCLONE"
+fi
+
+
+for dataset in $all_datasets; do
+       for value in on off; do
+               set_n_check_prop "off" "readonly" "$dataset"
+               initial_dataset $dataset
+
+               set_n_check_prop "$value" "readonly" "$dataset"
+               verify_readonly $dataset $value
+
+               set_n_check_prop "off" "readonly" "$dataset"
+               cleanup_dataset $dataset
+       done
+done
+
+log_pass "Setting a valid readonly property on a dataset succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/reservation_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/reservation_001_neg.ksh
new file mode 100755 (executable)
index 0000000..511a506
--- /dev/null
@@ -0,0 +1,97 @@
+#! /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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Valid reservation values should be positive integers only.
+#
+# STRATEGY:
+# 1) Form an array of invalid reservation values (negative and
+# incorrectly formed)
+# 2) Attempt to set each invalid reservation value in turn on a
+# filesystem and volume.
+# 3) Verify that attempt fails and the reservation value remains
+# unchanged
+#
+
+verify_runnable "both"
+
+log_assert "Verify invalid reservation values are rejected"
+
+set -A suffix "b" "k" "m" "t" "p" "e" "K" "M" "G" "T" "P" "E" "kb" "Mb" "Gb" \
+       "Tb" "Pb" "Eb" "KB" "MB" "GB" "TB" "PB" "EB"
+
+set -A values '' '-1' '-1.0' '-1.8' '-9999999999999999' '0x1' '0b' '1b' '1.1b'
+
+#
+# Function to loop through a series of bad reservation
+# values, checking they are when we attempt to set them
+# on a dataset.
+#
+function set_n_check # data-set
+{
+       typeset obj=$1
+       typeset -i i=0
+       typeset -i j=0
+
+       orig_resv_val=$(get_prop reservation $obj)
+
+       while (( $i < ${#values[*]} )); do
+               j=0
+               while (( $j < ${#suffix[*]} )); do
+
+                       $ZFS set \
+                               reservation=${values[$i]}${suffix[$j]} $obj \
+                               > /dev/null 2>&1
+                       if [ $? -eq 0 ]
+                       then
+                               log_note "$ZFS set \
+                               reservation=${values[$i]}${suffix[$j]} $obj"
+                               log_fail "The above reservation set returned 0!"
+                       fi
+
+                       new_resv_val=$(get_prop reservation $obj)
+
+                       if [[ $new_resv_val != $orig_resv_val ]]; then
+                               log_fail "$obj : reservation values changed " \
+                                       "($orig_resv_val : $new_resv_val)"
+                       fi
+                       (( j = j + 1 ))
+               done
+
+       (( i = i + 1 ))
+       done
+}
+
+for dataset in $TESTPOOL/$TESTFS $TESTPOOL/$TESTCTR $TESTPOOL/$TESTVOL
+do
+       set_n_check $dataset
+done
+
+log_pass "Invalid reservation values correctly rejected"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/ro_props_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/ro_props_001_pos.ksh
new file mode 100755 (executable)
index 0000000..c9a7391
--- /dev/null
@@ -0,0 +1,113 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Verify that read-only properties are immutable.
+#
+# STRATEGY:
+# 1. Create pool, fs, vol, fs@snap & vol@snap.
+# 2. Get the original property value and set value to those properties.
+# 3. Check return value.
+# 4. Compare the current property value with the original one.
+#
+
+verify_runnable "both"
+
+set -A values filesystem volume snapshot -3 0 1 50K 10G 80G \
+       2005/06/17 30K 20x yes no \
+       on off default pool/fs@snap $TESTDIR
+set -A dataset $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTCTR/$TESTFS1 $TESTPOOL/$TESTFS@$TESTSNAP \
+       $TESTPOOL/$TESTVOL@$TESTSNAP
+typeset ro_props="type used available avail creation referenced refer compressratio \
+       mounted origin"
+typeset snap_ro_props="volsize recordsize recsize quota reservation reserv mountpoint \
+       sharenfs checksum compression compress atime devices exec readonly rdonly \
+       setuid zoned"
+
+$ZFS upgrade -v > /dev/null 2>&1
+if [[ $? -eq 0 ]]; then
+       snap_ro_props="$snap_ro_props version"
+fi
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTVOL@$TESTSNAP && \
+               destroy_snapshot $TESTPOOL/$TESTVOL@$TESTSNAP
+       datasetexists $TESTPOOL/$TESTFS@$TESTSNAP && \
+               destroy_snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+}
+
+log_assert "Verify that read-only properties are immutable."
+log_onexit cleanup
+
+# Create filesystem and volume's snapshot
+create_snapshot $TESTPOOL/$TESTFS $TESTSNAP
+create_snapshot $TESTPOOL/$TESTVOL $TESTSNAP
+
+typeset -i i=0
+typeset -i j=0
+typeset cur_value=""
+typeset props=""
+
+while (( i < ${#dataset[@]} )); do
+       props=$ro_props
+
+       dst_type=$(get_prop type ${dataset[i]})
+       if [[ $dst_type == 'snapshot' ]]; then
+               props="$ro_props $snap_ro_props"
+       fi
+
+       for prop in $props; do
+               cur_value=$(get_prop $prop ${dataset[i]})
+
+               j=0
+               while (( j < ${#values[@]} )); do
+                       #
+                       # If the current property value is equal to values[j],
+                       # just expect it failed. Otherwise, set it to dataset,
+                       # expecting it failed and the property value is not
+                       # equal to values[j].
+                       #
+                       if [[ $cur_value == ${values[j]} ]]; then
+                               log_mustnot $ZFS set $prop=${values[j]} \
+                                       ${dataset[i]}
+                       else
+                               set_n_check_prop ${values[j]} $prop \
+                                       ${dataset[i]} false
+                       fi
+                       (( j += 1 ))
+               done
+       done
+       (( i += 1 ))
+done
+
+log_pass "Setting uneditable properties should failed. It passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/setup.ksh
new file mode 100755 (executable)
index 0000000..312638d
--- /dev/null
@@ -0,0 +1,31 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_container_volume_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/share_mount_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/share_mount_001_neg.ksh
new file mode 100755 (executable)
index 0000000..05c8b63
--- /dev/null
@@ -0,0 +1,60 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Verify that we cannot share or mount legacy filesystems.
+#
+# STRATEGY:
+# 1. Set mountpoint as legacy or none
+# 2. Use zfs share or zfs mount to share or mount the filesystem
+# 3. Verify that the command returns error
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS set mountpoint=$oldmpt $fs
+}
+
+log_assert "Verify that we cannot share or mount legacy filesystems."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+oldmpt=$(get_prop mountpoint $fs)
+
+for propval in "legacy" "none"; do
+       log_must $ZFS set mountpoint=$propval $fs
+
+       log_mustnot $ZFS mount $fs
+       log_mustnot $ZFS share $fs
+done
+
+log_pass "We cannot share or mount legacy filesystems as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/snapdir_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/snapdir_001_pos.ksh
new file mode 100755 (executable)
index 0000000..9abd0ec
--- /dev/null
@@ -0,0 +1,108 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting a valid snapdir on a dataset, it should be successful.
+#
+# STRATEGY:
+# 1. Create pool, then create filesystem and volume within it.
+# 2. Create a snapshot for each dataset.
+# 3. Setting different valid snapdir to each dataset.
+# 4. Check the return value and make sure it is 0.
+# 5. Verify .zfs directory is hidden|visible according to the snapdir setting.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for dataset in $all_datasets; do
+               snapexists ${dataset}@snap && \
+                       log_must $ZFS destroy ${dataset}@snap
+       done
+}
+
+function verify_snapdir_visible # $1 dataset, $2 hidden|visible
+{
+       typeset dataset=$1
+       typeset value=$2
+       typeset mtpt=$(get_prop mountpoint $dataset)
+       typeset name
+
+       for name in `$LS -a $mtpt`; do
+               if [[ $name == ".zfs" ]]; then
+                       if [[ $value == "visible" ]]; then
+                               return 0
+                       else
+                               return 1
+                       fi
+               fi
+       done
+
+       if [[ $value == "visible" ]]; then
+               return 1
+       else
+               return 0
+       fi
+}
+
+
+typeset all_datasets
+
+if is_global_zone ; then
+       all_datasets="$TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL"
+else
+       all_datasets="$TESTPOOL $TESTPOOL/$TESTFS"
+fi
+
+log_onexit cleanup
+
+for dataset in $all_datasets; do
+       log_must $ZFS snapshot ${dataset}@snap
+done
+
+log_assert "Setting a valid snapdir property on a dataset succeeds."
+
+for dataset in $all_datasets; do
+       for value in hidden visible; do
+               if [[ $dataset == "$TESTPOOL/$TESTVOL" ]] ; then
+                       set_n_check_prop "$value" "snapdir" \
+                               "$dataset" "false"
+               else
+                       set_n_check_prop "$value" "snapdir" \
+                               "$dataset"
+                       verify_snapdir_visible $dataset $value
+                       [[ $? -eq 0 ]] || \
+                               log_fail "$dataset/.zfs is not $value as expect."
+               fi
+       done
+done
+
+log_pass "Setting a valid snapdir property on a dataset succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_001_pos.ksh
new file mode 100755 (executable)
index 0000000..be8c88c
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+#      ZFS can set any valid user defined property to the non-readonly dataset.
+#
+# STRATEGY:
+#      1. Loop pool, fs and volume.
+#      2. Combine all kind of valid characters into a valid user defined
+#         property name.
+#      3. Random get a string as the value.
+#      4. Verify all the valid user defined properties can be set to the
+#         dataset in #1.
+#
+
+verify_runnable "both"
+
+log_assert "ZFS can set any valid user defined property to the non-readonly " \
+       "dataset."
+log_onexit cleanup_user_prop $TESTPOOL
+
+typeset -i i=0
+while ((i < 10)); do
+       typeset -i len
+       ((len = RANDOM % 32))
+       typeset user_prop=$(valid_user_property $len)
+       ((len = RANDOM % 512))
+       typeset value=$(user_property_value $len)
+
+       for dtst in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL; do
+               log_must eval "$ZFS set $user_prop='$value' $dtst"
+               log_must eval "check_user_prop $dtst $user_prop '$value'"
+       done
+
+       ((i += 1))
+done
+
+log_pass "ZFS can set any valid user defined property passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_002_pos.ksh
new file mode 100755 (executable)
index 0000000..24fecfb
--- /dev/null
@@ -0,0 +1,118 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+#      User defined property are always inherited from its parent dataset
+#      directly.
+#
+# STRATEGY:
+#      1. Create pool, fs, volume, fsclone & volclone.
+#      2. Get random user property name and set to the pool
+#      3. Verify all dataset user property inherit from pool.
+#      4. Set intermediate dataset and verify its children will inherit user
+#         property from it directly.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $new_vol && log_must $ZFS rename $new_vol $vol
+
+       typeset dtst
+       for dtst in $new_fsclone $new_volclone $fsclone $volclone \
+           $fssnap $volsnap; do
+               if datasetexists $dtst; then
+                       log_must $ZFS destroy -f $dtst
+               fi
+       done
+
+       cleanup_user_prop $pool
+}
+
+#
+# Verify options datasets (3-n) inherit from the inherited dataset $2.
+#
+# $1 user property
+# $2 inherited dataset
+# $3-n datasets
+#
+function inherit_check
+{
+       typeset prop=$1
+       typeset inherited_dtst=$2
+       shift 2
+       [[ -z $@ ]] && return 1
+
+       typeset inherited_value=$(get_prop $prop $inherited_dtst)
+       for dtst in $@; do
+               typeset value=$(get_prop $prop $dtst)
+               typeset source=$(get_source $prop $dtst)
+               if [[ "$value" != "$inherited_value" || \
+                     "$source" != "inherited from $inherited_dtst" ]]
+               then
+                       return 1
+               fi
+
+               shift
+       done
+
+       return 0
+}
+
+log_assert "User defined property inherited from its parent."
+log_onexit cleanup
+
+pool=$TESTPOOL; fs=$pool/$TESTFS; vol=$pool/$TESTVOL
+fssnap=$fs@snap; volsnap=$vol@snap;
+log_must $ZFS snapshot $fssnap
+log_must $ZFS snapshot $volsnap
+fsclone=$pool/fsclone; volclone=$pool/volclone
+log_must $ZFS clone $fssnap $fsclone
+log_must $ZFS clone $volsnap $volclone
+
+prop_name=$(valid_user_property 10)
+value=$(user_property_value 16)
+log_must eval "$ZFS set $prop_name='$value' $pool"
+log_must eval "check_user_prop $pool $prop_name '$value'"
+log_must inherit_check $prop_name $pool $fs $vol $fsclone $volclone
+
+new_fsclone=$fs/fsclone; new_volclone=$fs/volclone
+log_must $ZFS rename $fsclone $new_fsclone
+log_must $ZFS rename $volclone $new_volclone
+log_must inherit_check $prop_name $pool $fs $new_fsclone $new_volclone
+
+log_note "Set intermediate dataset will change the inherited relationship."
+new_value=$(user_property_value 16)
+log_must eval "$ZFS set $prop_name='$new_value' $fs"
+log_must eval "check_user_prop $fs $prop_name '$new_value'"
+log_must inherit_check $prop_name $fs $new_fsclone $new_volclone
+
+log_pass "User defined property inherited from its parent passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_003_neg.ksh
new file mode 100755 (executable)
index 0000000..4c1c1bc
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+#      ZFS can handle any invalid user defined property.
+#
+# STRATEGY:
+#      1. Loop pool, fs and volume.
+#      2. Combine all kind of invalid user property names.
+#      3. Random get a string as the value.
+#      4. Verify all the invalid user defined properties can not be set to the
+#         dataset in #1.
+#
+
+verify_runnable "both"
+
+log_assert "ZFS can handle invalid user property."
+log_onexit cleanup_user_prop $TESTPOOL
+
+typeset -i i=0
+while ((i < 10)); do
+       typeset -i len
+       ((len = RANDOM % 32))
+       typeset user_prop=$(invalid_user_property $len)
+       ((len = RANDOM % 512))
+       typeset value=$(user_property_value $len)
+
+       for dtst in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL ; do
+               log_mustnot $ZFS set $user_prop=$value $dtst
+               log_mustnot check_user_prop $dtst \"$user_prop\" \"$value\"
+       done
+
+       ((i += 1))
+done
+
+log_pass "ZFS can handle invalid user property passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/user_property_004_pos.ksh
new file mode 100755 (executable)
index 0000000..1bce7a7
--- /dev/null
@@ -0,0 +1,97 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+#      User property has no effect to snapshot until 'Snapshot properties' supported.
+#
+# STRATEGY:
+#      1. Verify user properties could be transformed by 'zfs snapshot'
+#      2. Verify user properties could be set upon snapshot.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL ; do
+               typeset fssnap=$fs@snap
+               if datasetexists $fssnap ; then
+                       log_must $ZFS destroy -f $fssnap
+               fi
+       done
+       cleanup_user_prop $TESTPOOL
+}
+
+function nonexist_user_prop
+{
+       typeset user_prop=$1
+       typeset dtst=$2
+
+       typeset source=$(get_source $user_prop $dtst)
+       typeset value=$(get_prop $user_prop $dtst)
+       if [[ $source == '-' && $value == '-' ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
+
+log_assert "User property has no effect to snapshot until 'Snapshot properties' supported."
+log_onexit cleanup
+
+typeset snap_property=
+
+$ZPOOL upgrade -v | $GREP "Snapshot properties" > /dev/null 2>&1
+if (( $? == 0 )) ; then
+       snap_property="true"
+fi
+
+for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL ; do
+       typeset fssnap=$fs@snap
+       prop_name=$(valid_user_property 10)
+       value=$(user_property_value 16)
+       log_must eval "$ZFS set $prop_name='$value' $fs"
+       log_must eval "check_user_prop $fs $prop_name '$value'"
+
+       log_must $ZFS snapshot $fssnap
+
+       if [[ -n $snap_property ]] ; then
+               log_mustnot nonexist_user_prop $prop_name $fssnap
+
+               log_must eval "$ZFS set $prop_name='$value' $fssnap"
+               log_mustnot nonexist_user_prop $prop_name $fssnap
+       else
+               log_must nonexist_user_prop $prop_name $fssnap
+               log_mustnot eval "$ZFS set $prop_name='$value' $fssnap"
+               log_must nonexist_user_prop $prop_name $fssnap
+       fi
+done
+
+log_pass "User properties has effect upon snapshot."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/version_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/version_001_neg.ksh
new file mode 100755 (executable)
index 0000000..40a541a
--- /dev/null
@@ -0,0 +1,87 @@
+#! /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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# Valid version values should be positive integers only.
+#
+# STRATEGY:
+# 1) Form an array of invalid reservation values (negative and
+# incorrectly formed)
+# 2) Attempt to set each invalid version value in turn on a
+# filesystem and volume.
+# 3) Verify that attempt fails and the version value remains
+# unchanged
+#
+
+verify_runnable "both"
+
+log_assert "Verify invalid version values are rejected"
+
+typeset values=('' '-1' '-1.0' '-1.8' '-9999999999999999' \
+       '0x1' '0b' '1b' '1.1b' '0' '0.000' '1.234')
+
+#
+# Function to loop through a series of bad reservation
+# values, checking they are when we attempt to set them
+# on a dataset.
+#
+function set_n_check # data-set
+{
+       typeset obj=$1
+       typeset -i i=0
+       typeset -i j=0
+
+       orig_val=$(get_prop version $obj)
+
+       while (($i < ${#values[*]})); do
+               $ZFS set version=${values[$i]} $obj  > /dev/null 2>&1
+               if [[ $? -eq 0 ]]; then
+                       log_note "$ZFS set version=${values[$i]} $obj"
+                       log_fail "The above version set returned 0!"
+               fi
+
+               new_val=$(get_prop version $obj)
+
+               if [[ $new_val != $orig_val ]]; then
+                       log_fail "$obj : version values changed " \
+                               "($orig_val : $new_val)"
+               fi
+
+               ((i = i + 1))
+       done
+}
+
+for dataset in $TESTPOOL/$TESTFS $TESTPOOL/$TESTCTR $TESTPOOL/$TESTVOL
+do
+       set_n_check $dataset
+done
+
+log_pass "Invalid version values correctly rejected"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_001_neg.ksh
new file mode 100755 (executable)
index 0000000..4d8982c
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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) 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# Setting invalid value to mountpoint, checksum, atime, readonly, setuid,
+# zoned, recordsize, or canmount on a file system, volume. It should be failed.
+#
+# STRATEGY:
+# 1. Create pool, then create file system & volume within it.
+# 2. Setting invalid value, it should be failed.
+#
+
+verify_runnable "both"
+
+set -A props "" "mountpoint" "checksum" "compression" "atime" "readonly" \
+       "setuid" "zoned" "canmount"
+
+set -A values "" "mountpoint" "checksum" "compression" "atime" "readonly" \
+       "setuid" "zoned" "0" "-?" "-on" "--on" "*" "?" "Legacy" "NONE" "oN" \
+       "On" "ON" "ofF" "OFf" "oFF" "Off" "OfF" "OFF" "LzJb" "lZJb" "LZjB" \
+       "blad" "default" "TESTPOOL" "$TESTPOOL/$TESTCTR" \
+       "$TESTPOOL/$TESTCTR/$TESTFS" "$TESTPOOL/$TESTFS"
+set -A dataset "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTVOL"
+
+log_assert "Setting invalid value to mountpoint, checksum, compression, atime,"\
+       "readonly, setuid, zoned or canmount on a file system file system or volume." \
+       "It should be failed."
+
+typeset -i i=0
+typeset -i j=0
+typeset -i k=0
+while (( i < ${#dataset[@]} )); do
+       j=0
+       while (( j < ${#props[@]} )); do
+               k=0
+               while (( k < ${#values[@]} )); do
+                       set_n_check_prop "${values[k]}" "${props[j]}" \
+                               "${dataset[i]}" false
+                       (( k += 1 ))
+               done
+               (( j += 1 ))
+       done
+        # Additional recordsize
+        set_n_check_prop "recordsize" "2048K" "${dataset[i]}" false
+        set_n_check_prop "recordsize" "128B" "${dataset[i]}" false
+       (( i += 1 ))
+done
+
+log_pass "Setting invalid value to mountpoint, checksum, compression, atime, " \
+       "readonly, setuid, zoned or canmount on file system or volume pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_002_neg.ksh
new file mode 100755 (executable)
index 0000000..619a1ee
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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) 2011 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs set' should fail with invalid arguments
+#
+# STRATEGY:
+# 1. Create an array of invalid arguments
+# 1. Run zfs set with each invalid argument
+# 2. Verify that zfs set returns error
+#
+
+verify_runnable "both"
+
+log_assert "'zfs set' fails with invalid arguments"
+
+set -A editable_props "quota" "reservation" "reserv" "volsize" "recordsize" "recsize" \
+               "mountpoint" "checksum" "compression" "compress" "atime" \
+               "devices" "exec" "setuid" "readonly" "zoned" "snapdir" "aclmode" \
+               "aclinherit" "canmount" "xattr" "copies" "version"
+
+for ds in $TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL \
+       $TESTPOOL/$TESTFS@$TESTSNAP; do
+       for badarg in "" "-" "-?"; do
+               for prop in ${editable_props[@]}; do
+                       log_mustnot eval "$ZFS set $badarg $prop= $ds >/dev/null 2>&1"
+               done
+       done
+done
+
+log_pass "'zfs set' fails with invalid arguments as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_003_neg.ksh
new file mode 100755 (executable)
index 0000000..13260f1
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+# 'zfs set mountpoint/sharenfs' should fail when the mountpoint is invlid
+#
+# STRATEGY:
+# 1. Create invalid scenarios
+# 2. Run zfs set mountpoint/sharenfs with invalid value
+# 3. Verify that zfs set returns expected errors
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if [ -e $badpath ]; then
+               $RM -f $badpath
+       fi
+       if datasetexists $TESTPOOL/foo; then
+               log_must $ZFS destroy $TESTPOOL/foo
+       fi
+}
+
+log_assert "'zfs set mountpoint/sharenfs' fails with invalid scenarios"
+log_onexit cleanup
+
+badpath=/tmp/foo1.$$
+$TOUCH $badpath
+longpath=$(gen_dataset_name 1030 "abcdefg")
+
+log_must $ZFS create -o mountpoint=legacy $TESTPOOL/foo
+
+# Do the negative testing about "property may be set but unable to remount filesystem"
+log_mustnot eval "$ZFS set mountpoint=$badpath $TESTPOOL/foo >/dev/null 2>&1"
+
+# Do the negative testing about "property may be set but unable to reshare filesystem"
+log_mustnot eval "$ZFS set sharenfs=on $TESTPOOL/foo >/dev/null 2>&1"
+
+# Do the negative testing about "sharenfs property can not be set to null"
+log_mustnot eval "$ZFS set sharenfs= $TESTPOOL/foo >/dev/null 2>&1"
+
+# Do the too long pathname testing (>1024)
+log_mustnot eval "$ZFS set mountpoint=/$longpath $TESTPOOL/foo >/dev/null 2>&1"
+
+log_pass "'zfs set mountpoint/sharenfs' fails with invalid scenarios as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
new file mode 100644 (file)
index 0000000..5c4363b
--- /dev/null
@@ -0,0 +1,267 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+set -A VALID_NAME_CHAR a b c d e f g h i j k l m n o p q r s t u v w x y z \
+    0 1 2 3 4 5 6 7 8 9 ':' '-' '.' '_'
+set -A INVALID_NAME_CHAR A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
+    '`' '~' '!' '@' '#' '$' '%' '^' '&' '(' ')' '+' '=' '|' "\\" '{' '[' ']' \
+    '}' ';' '"' '<' ',' '>' '?' '/' ' '
+set -A ALL_CHAR ${VALID_NAME_CHAR[*]} ${INVALID_NAME_CHAR[*]}
+
+#
+# Firstly, set the property value to dataset. Then checking if the property
+# value is equal with the expected value, according to the expected result.
+#
+# $1 property value
+# $2 property name
+# $3 dataset
+# $4 expected result
+#
+function set_n_check_prop
+{
+       typeset expect_value=$1
+       typeset prop=$2
+       typeset dataset=$3
+       typeset expect_result=${4:-true}
+
+       typeset old_value=""
+       typeset cur_value=""
+
+       [[ -n $prop ]] && old_value=$(get_prop $prop $dataset)
+
+       if [[ $expect_result == true ]]; then
+               [[ -z $prop || -z $dataset ]] && \
+                       log_fail "property or dataset isn't defined."
+
+               log_must $ZFS set $prop=$expect_value $dataset
+               if [[ $expect_value == "gzip-6" ]]; then
+                       expect_value="gzip"
+               fi
+
+               [[ -n $prop ]] && cur_value=$(get_prop $prop $dataset)
+
+               case $prop in
+                       reservation|reserv|quota )
+                               if [[ $expect_value == "none" ]]; then
+                                       [[ $cur_value != "0" ]] && \
+                                               log_fail "The '$dataset' '$prop' value \
+                                               '$cur_value' is not expected."
+                               elif [[ $cur_value != $expect_value ]]; then
+                                       log_fail "The '$dataset' '$prop' value '$cur_value' \
+                                       does not equal the expected value '$expect_value'."
+                               fi
+                               ;;
+                       * )
+                               if [[ $cur_value != $expect_value ]]; then
+                                       log_fail "The '$dataset' '$prop' value '$cur_value' \
+                                       does not equal the expected value '$expect_value'."
+                               fi
+                               ;;
+               esac
+
+       else
+               log_mustnot $ZFS set $prop=$expect_value $dataset
+
+               [[ -n $prop ]] && cur_value=$(get_prop $prop $dataset)
+
+               if [[ "$expect_value" != "" && "$cur_value" != "$old_value" ]];
+               then
+                       log_fail "The '$dataset' '$prop' value '$cur_value' \
+                               should equal with '$old_value'."
+               fi
+       fi
+}
+
+#
+# Cleanup all the user properties of the pool and the dataset reside it.
+#
+# $1 pool name
+#
+function cleanup_user_prop
+{
+       typeset pool=$1
+       typeset dtst=$($ZFS list -H -r -o name -t filesystem,volume $pool)
+
+       typeset user_prop
+       for dt in $dtst; do
+               user_prop=$($ZFS get -H -o property all $dtst | grep ":")
+
+               typeset prop
+               for prop in $user_prop; do
+                       $ZFS inherit $prop $dt
+                       (($? != 0)) && log_must $ZFS inherit $prop $dt
+               done
+       done
+}
+
+#
+# Random select charactor from the specified charactor set and combine into a
+# random string
+#
+# $1 character set name
+# $2 String length
+#
+function random_string
+{
+       typeset char_set=${1:-VALID_NAME_CHAR}
+       typeset -i len=${2:-5}
+
+       eval typeset -i count=\${#$char_set[@]}
+
+       # No consumers want an empty string.
+       ((len == 0)) && len=3
+
+       typeset str
+       typeset -i i=0
+       while ((i < len)); do
+               typeset -i ind
+               ((ind = RANDOM % count))
+               eval str=\${str}\${$char_set[\$ind]}
+
+               ((i += 1))
+       done
+
+       $ECHO "$str"
+}
+
+#
+# Get vaild user defined property name
+#
+# $1 user defined property name length
+#
+function valid_user_property
+{
+       typeset -i sumlen=${1:-10}
+       ((sumlen < 2 )) && sumlen=2
+       typeset -i len
+       ((len = RANDOM % sumlen))
+       typeset part1 part2
+
+       while true; do
+               part1="$(random_string VALID_NAME_CHAR $len)"
+               if [[ "$part1" == "-"* ]]; then
+                       continue
+               fi
+               break
+       done
+       ((len = sumlen - (len + 1)))
+
+       while true; do
+               part2="$(random_string VALID_NAME_CHAR $len)"
+               if [[ -z $part1 && -z $part2 ]]; then
+                       continue
+               fi
+               break
+       done
+
+       $ECHO "${part1}:${part2}"
+}
+
+#
+# Get invaild user defined property name
+#
+# $1 user defined property name length
+#
+function invalid_user_property
+{
+       typeset -i sumlen=${1:-10}
+       ((sumlen == 0)) && sumlen=1
+       typeset -i len
+       ((len = RANDOM % sumlen))
+
+       typeset part1 part2
+       while true; do
+               part1="$(random_string VALID_NAME_CHAR $len)"
+               ((len = sumlen - len))
+               part2="$(random_string INVALID_NAME_CHAR $len)"
+
+               # Avoid $part1 is *:* and $part2 is "=*"
+               if [[ "$part1" == *":"* && "$part2" == "="* ]]; then
+                       continue
+               fi
+               break
+       done
+
+       $ECHO "${part1}${part2}"
+}
+
+#
+# Get user property value
+#
+# $1 user defined property name length
+#
+function user_property_value
+{
+       typeset -i len=${1:-100}
+
+       typeset value=$(random_string ALL_CHAR $len)
+
+       $ECHO "$value"
+}
+
+#
+# Check if the user property is identical to the expected value.
+#
+# $1 dataset
+# $2 user property
+# $3 expected value
+#
+function check_user_prop
+{
+       typeset dtst=$1
+       typeset user_prop="$2"
+       typeset expect_value="$3"
+       typeset value=$($ZFS get -p -H -o value "$user_prop" $dtst 2>&1)
+
+       if [[ "$expect_value" == "$value" ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
+
+#
+# Get source of the dataset
+#
+function get_source
+{
+       typeset prop=$1
+       typeset dataset=$2
+       typeset source
+
+       source=$($ZFS get -H -o source $prop $dataset)
+        if (($? != 0)); then
+                log_fail "Unable to get $prop source for dataset $dataset"
+        fi
+
+       $ECHO "$source"
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/Makefile.am
new file mode 100644 (file)
index 0000000..926531b
--- /dev/null
@@ -0,0 +1,16 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_share
+dist_pkgdata_SCRIPTS = \
+       zfs_share.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_share_001_pos.ksh \
+       zfs_share_002_pos.ksh \
+       zfs_share_003_pos.ksh \
+       zfs_share_004_pos.ksh \
+       zfs_share_005_pos.ksh \
+       zfs_share_006_pos.ksh \
+       zfs_share_007_neg.ksh \
+       zfs_share_008_neg.ksh \
+       zfs_share_009_neg.ksh \
+       zfs_share_010_neg.ksh \
+       zfs_share_011_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/setup.ksh
new file mode 100755 (executable)
index 0000000..9cfd997
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+# Make sure NFS server is running before testing.
+setup_nfs_server
+
+DISK=${DISKS%% *}
+default_container_volume_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share.cfg
new file mode 100644 (file)
index 0000000..5c31c8f
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+export SNAPROOT=".zfs/snapshot"
+export NONEXISTFSNAME="nonexistfs50charslong_0123456789012345678901234567"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_001_pos.ksh
new file mode 100755 (executable)
index 0000000..084b18d
--- /dev/null
@@ -0,0 +1,145 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that 'zfs set sharenfs' and 'zfs share' shares a given dataset.
+#
+# STRATEGY:
+# 1. Invoke 'zfs set sharenfs'.
+# 2. Verify that the file system is shared.
+# 3. Invoke 'zfs share'.
+# 4. Verify that the file system is shared.
+# 5. Verify that a shared filesystem cannot be shared again.
+# 6. Verify that share -a succeeds.
+#
+
+verify_runnable "global"
+
+set -A fs \
+    "$TESTDIR" "$TESTPOOL/$TESTFS" \
+    "$TESTDIR1" "$TESTPOOL/$TESTCTR/$TESTFS1" \
+    "$TESTDIR2" "$TESTPOOL/$TESTFS-clone"
+
+function cleanup
+{
+       typeset -i i=0
+       while (( i < ${#fs[*]} )); do
+               log_must $ZFS set sharenfs=off ${fs[((i+1))]}
+               unshare_fs ${fs[i]}
+
+               ((i = i + 2))
+       done
+
+       if mounted $TESTPOOL/$TESTFS-clone; then
+               log_must $ZFS unmount $TESTDIR2
+       fi
+
+       datasetexists $TESTPOOL/$TESTFS-clone && \
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS-clone
+
+       if snapexists "$TESTPOOL/$TESTFS@snapshot"; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS@snapshot
+       fi
+}
+
+
+#
+# Main test routine.
+#
+# Given a mountpoint and file system this routine will attempt
+# share the mountpoint and then verify it has been shared.
+#
+function test_share # mntp filesystem
+{
+       typeset mntp=$1
+       typeset filesystem=$2
+
+       not_shared $mntp || \
+           log_fail "File system $filesystem is already shared."
+
+       log_must $ZFS set sharenfs=on $filesystem
+       is_shared $mntp || \
+           log_fail "File system $filesystem is not shared (set sharenfs)."
+
+       #
+       # Verify 'zfs share' works as well.
+       #
+       log_must $ZFS unshare $filesystem
+       is_shared $mntp && \
+           log_fail "File system $filesystem is still shared."
+
+       log_must $ZFS share $filesystem
+       is_shared $mntp || \
+           log_fail "file system $filesystem is not shared (zfs share)."
+
+       log_note "Sharing a shared file system fails."
+       log_mustnot $ZFS share $filesystem
+}
+
+log_assert "Verify that 'zfs share' succeeds as root."
+log_onexit cleanup
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snapshot
+log_must $ZFS clone $TESTPOOL/$TESTFS@snapshot $TESTPOOL/$TESTFS-clone
+log_must $ZFS set mountpoint=$TESTDIR2 $TESTPOOL/$TESTFS-clone
+
+typeset -i i=0
+while (( i < ${#fs[*]} )); do
+       test_share ${fs[i]} ${fs[((i + 1))]}
+
+       ((i = i + 2))
+done
+
+log_note "Verify 'zfs share -a' succeeds."
+
+#
+# Unshare each of the file systems.
+#
+i=0
+while (( i < ${#fs[*]} )); do
+       unshare_fs ${fs[i]}
+
+       ((i = i + 2))
+done
+
+#
+# Try a zfs share -a and verify all file systems are shared.
+#
+log_must $ZFS share -a
+
+i=0
+while (( i < ${#fs[*]} )); do
+       is_shared ${fs[i]} || \
+           log_fail "File system ${fs[i]} is not shared (share -a)"
+
+       ((i = i + 2))
+done
+
+log_pass "'$ZFS share [ -a ] <filesystem>' succeeds as root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_002_pos.ksh
new file mode 100755 (executable)
index 0000000..4005bf0
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_share/zfs_share.cfg
+
+#
+# DESCRIPTION:
+# Verify that "zfs share" with a non-existent file system fails.
+#
+# STRATEGY:
+# 1. Make sure the NONEXISTFSNAME ZFS file system is not in 'zfs list'.
+# 2. Invoke 'zfs share <file system>'.
+# 3. Verify that share fails
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset fs
+       for fs in $NONEXISTFSNAME $TESTFS ; do
+               log_must unshare_fs $TESTPOOL/$fs
+       done
+}
+
+typeset -i ret=0
+
+log_assert "Verify that "zfs share" with a non-existent file system fails."
+
+log_onexit cleanup
+
+log_mustnot $ZFS list $TESTPOOL/$NONEXISTFSNAME
+
+$ZFS share $TESTPOOL/$NONEXISTFSNAME
+ret=$?
+(( ret == 1)) || \
+       log_fail "'$ZFS share $TESTPOOL/$NONEXISTFSNAME' " \
+               "failed with an unexpected return code of $ret."
+
+log_note "Make sure the file system $TESTPOOL/$NONEXISTFSNAME is unshared"
+not_shared $TESTPOOL/$NONEXISTFSNAME || \
+       log_fail "File system $TESTPOOL/$NONEXISTFSNAME is unexpectedly shared."
+
+log_pass "'$ZFS share' with a non-existent file system fails."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_003_pos.ksh
new file mode 100755 (executable)
index 0000000..e4ab8c6
--- /dev/null
@@ -0,0 +1,106 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Invoking "zfs share <file system>" with a file system
+# whose sharenfs property is 'off' , will fail with a
+# return code of 1 and issue an error message.
+#
+# STRATEGY:
+# 1. Make sure that the ZFS file system is unshared.
+# 2. Mount the file system using the various combinations
+# - zfs set sharenfs=off <file system>
+# - zfs set sharenfs=none <file system>
+# 3. Verify that share failed with return code of 1.
+#
+
+verify_runnable "both"
+
+set -A fs \
+    "$TESTDIR" "$TESTPOOL/$TESTFS" \
+    "$TESTDIR1" "$TESTPOOL/$TESTCTR/$TESTFS1"
+
+function cleanup
+{
+       typeset -i i=0
+       while (( i < ${#fs[*]} )); do
+               log_must $ZFS inherit -r sharenfs ${fs[((i + 1))]}
+               log_must unshare_fs ${fs[i]}
+
+               ((i = i + 2))
+       done
+}
+
+
+#
+# Main test routine.
+#
+# Given a mountpoint and file system this routine will attempt
+# to share a legacy mountpoint and then verify the share fails as
+# expected.
+#
+function test_legacy_share # mntp filesystem
+{
+       typeset mntp=$1
+       typeset filesystem=$2
+
+       not_shared $mntp || \
+           log_fail "File system $filesystem is already shared."
+
+       if is_global_zone ; then
+               log_must $ZFS set sharenfs=off $filesystem
+               not_shared $mntp || \
+                   log_fail "File system $filesystem is still shared (set sharenfs)."
+       fi
+
+       $ZFS share $filesystem
+       ret=$?
+       (( ret == 1)) || \
+           log_fail "'$ZFS share $filesystem' " \
+               "unexpected return code of $ret."
+
+       not_shared $mntp || \
+           log_fail "file system $filesystem is shared (zfs share)."
+}
+
+log_assert "Verify that '$ZFS share' with a file system " \
+        "whose sharenfs property is 'off'  " \
+        "will fail with return code 1."
+log_onexit cleanup
+
+typeset -i i=0
+while (( i < ${#fs[*]} )); do
+       test_legacy_share ${fs[i]} ${fs[((i + 1))]}
+
+       ((i = i + 2))
+done
+
+log_pass "Verify that '$ZFS share' with a file system " \
+        "whose sharenfs property is 'off' fails."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_004_pos.ksh
new file mode 100755 (executable)
index 0000000..04cf72e
--- /dev/null
@@ -0,0 +1,96 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_share/zfs_share.cfg
+
+#
+# DESCRIPTION:
+# Verify that a file system and its snapshot are shared.
+#
+# STRATEGY:
+# 1. Create a file system
+# 2. Set the sharenfs property on the file system
+# 3. Create a snapshot
+# 4. Verify that both are shared.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if snapexists $TESTPOOL/$TESTFS@snapshot; then
+               log_must $ZFS destroy $TESTPOOL/$TESTFS@snapshot
+       fi
+
+       log_must $ZFS set sharenfs=off $TESTPOOL/$TESTFS
+       log_must unshare_fs $TESTPOOL/$TESTFS
+}
+
+#
+# Main test routine.
+#
+# Given a mountpoint and file system this routine will attempt
+# share the mountpoint and then verify a snapshot of the mounpoint
+# is also shared.
+#
+function test_snap_share # mntp filesystem
+{
+        typeset mntp=$1
+        typeset filesystem=$2
+
+        not_shared $mntp || \
+            log_fail "File system $filesystem is already shared."
+
+        log_must $ZFS set sharenfs=on $filesystem
+        is_shared $mntp || \
+            log_fail "File system $filesystem is not shared (set sharenfs)."
+
+       log_must $LS -l  $mntp/$SNAPROOT/snapshot
+        #
+        # Verify 'zfs share' works as well.
+        #
+        log_must $ZFS unshare $filesystem
+        log_must $ZFS share $filesystem
+
+        is_shared $mntp || \
+            log_fail "file system $filesystem is not shared (zfs share)."
+
+       log_must $LS -l  $mntp/$SNAPROOT/snapshot
+}
+
+log_assert "Verify that a file system and its snapshot are shared."
+log_onexit cleanup
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snapshot
+test_snap_share $TESTDIR $TESTPOOL/$TESTFS
+
+log_pass "A file system and its snapshot are both shared as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_005_pos.ksh
new file mode 100755 (executable)
index 0000000..eed0eaa
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that NFS share options are propagated correctly.
+#
+# STRATEGY:
+# 1. Create a ZFS file system.
+# 2. For each option in the list, set the sharenfs property.
+# 3. Verify through the share command that the options are propagated.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       log_must $ZFS set sharenfs=off $TESTPOOL/$TESTFS
+       is_shared $TESTPOOL/$TESTFS && \
+               log_must unshare_fs $TESTPOOL/$TESTFS
+}
+
+set -A shareopts \
+    "ro" "ro=machine1" "ro=machine1:machine2" \
+    "rw" "rw=machine1" "rw=machine1:machine2" \
+    "ro=machine1:machine2,rw" "anon=0" "anon=0,sec=sys,rw" \
+    "nosuid" "root=machine1:machine2" "rw=.mydomain.mycompany.com" \
+    "rw=-terra:engineering" "log" "public"
+
+log_assert "Verify that NFS share options are propagated correctly."
+log_onexit cleanup
+
+cleanup
+
+typeset -i i=0
+while (( i < ${#shareopts[*]} ))
+do
+       log_must $ZFS set sharenfs="${shareopts[i]}" $TESTPOOL/$TESTFS
+
+       option=`get_prop sharenfs $TESTPOOL/$TESTFS`
+       if [[ $option != ${shareopts[i]} ]]; then
+               log_fail "get sharenfs failed. ($option != ${shareopts[i]})"
+       fi
+
+       $SHARE | $GREP $option > /dev/null 2>&1
+       if (( $? != 0 )); then
+               log_fail "The '$option' option was not found in share output."
+       fi
+
+       ((i = i + 1))
+done
+
+log_pass "NFS options were propagated correctly."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_006_pos.ksh
new file mode 100755 (executable)
index 0000000..2088489
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that a dataset could not be shared but filesystems are shared.
+#
+# STRATEGY:
+# 1. Create a dataset and file system
+# 2. Set the sharenfs property on the dataset
+# 3. Verify that the dataset is unable be shared.
+# 4. Add a new file system to the dataset.
+# 5. Verify that the newly added file system be shared.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       log_must $ZFS set sharenfs=off $TESTPOOL/$TESTCTR
+       if mounted $TESTDIR2; then
+               log_must $ZFS unmount $TESTDIR2
+       fi
+
+       datasetexists $TESTPOOL/$TESTCTR/$TESTFS2 && \
+               log_must $ZFS destroy $TESTPOOL/$TESTCTR/$TESTFS2
+
+       typeset fs=""
+       for fs in $mntp $TESTDIR1 $TESTDIR2
+       do
+               log_must unshare_fs $fs
+       done
+}
+
+#
+# Main test routine.
+#
+# Given a mountpoint and a dataset, this routine will set the
+# sharenfs property on the dataset and verify that dataset
+# is unable to be shared but the existing contained file systems
+# could be shared.
+#
+function test_ctr_share # mntp ctr
+{
+       typeset mntp=$1
+       typeset ctr=$2
+
+       not_shared $mntp || \
+           log_fail "Mountpoint: $mntp is already shared."
+
+       log_must $ZFS set sharenfs=on $ctr
+
+       not_shared $mntp || \
+               log_fail "File system $mntp is shared (set sharenfs)."
+
+       #
+       # Add a new file system to the dataset and verify it is shared.
+       #
+       typeset mntp2=$TESTDIR2
+       log_must $ZFS create $ctr/$TESTFS2
+       log_must $ZFS set mountpoint=$mntp2 $ctr/$TESTFS2
+
+       is_shared $mntp2 || \
+           log_fail "File system $mntp2 was not shared (set sharenfs)."
+}
+
+log_assert "Verify that a dataset could not be shared, " \
+       "but its sub-filesystems could be shared."
+log_onexit cleanup
+
+typeset mntp=$(get_prop mountpoint $TESTPOOL/$TESTCTR)
+test_ctr_share $mntp $TESTPOOL/$TESTCTR
+
+log_pass "A dataset could not be shared, " \
+       "but its sub-filesystems could be shared as expect."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_007_neg.ksh
new file mode 100755 (executable)
index 0000000..ace4e43
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that invalid share parameters and options are caught.
+#
+# STRATEGY:
+# 1. Create a ZFS file system.
+# 2. For each option in the list, set the sharenfs property.
+# 3. Verify that the error code and sharenfs property.
+#
+
+verify_runnable "both"
+
+function cleanup {
+       if is_global_zone; then
+               log_must $ZFS set sharenfs=off $TESTPOOL/$TESTFS
+       fi
+}
+
+set -A badopts \
+    "r0" "r0=machine1" "r0=machine1:machine2" \
+    "-g" "-b" "-c" "-d" "--invalid" \
+    "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL\$TESTCTR\$TESTFS1"
+
+log_assert "Verify that invalid share parameters and options are caught."
+log_onexit cleanup
+
+typeset -i i=0
+while (( i < ${#badopts[*]} ))
+do
+       log_note "Setting sharenfs=${badopts[i]} $i "
+       log_mustnot $ZFS set sharenfs="${badopts[i]}" $TESTPOOL/$TESTFS
+
+       $SHARE | $GREP $option > /dev/null 2>&1
+       if (( $? == 0 )); then
+               log_fail "An invalid setting '$option' was propagated."
+       fi
+
+       #
+       # To global zone, sharenfs must be set 'off' before malformed testing.
+       # Otherwise, the malformed test return '0'.
+       #
+       # To non-global zone, sharenfs can be set even 'off' or 'on'.
+       #
+       if is_global_zone; then
+               log_note "Resetting sharenfs option"
+               log_must $ZFS set sharenfs=off $TESTPOOL/$TESTFS
+       fi
+
+       ((i = i + 1))
+done
+
+log_pass "Invalid share parameters and options we caught as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_008_neg.ksh
new file mode 100755 (executable)
index 0000000..a945ddd
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that sharing a dataset other than filesystem fails.
+#
+# STRATEGY:
+# 1. Create a ZFS file system.
+# 2. For each dataset in the list, set the sharenfs property.
+# 3. Verify that the invalid datasets are not shared.
+#
+
+verify_runnable "global"
+
+if is_global_zone ; then
+       set -A datasets \
+           "$TESTPOOL/$TESTVOL" "$TESTDIR"
+fi
+
+log_assert "Verify that sharing a dataset other than filesystem fails."
+
+typeset -i i=0
+while (( i < ${#datasets[*]} ))
+do
+       log_mustnot $ZFS set sharenfs=on ${datasets[i]}
+
+       option=`get_prop sharenfs ${datasets[i]}`
+       if [[ $option == ${datasets[i]} ]]; then
+               log_fail "set sharenfs failed. ($option == ${datasets[i]})"
+       fi
+
+       not_shared ${datasets[i]} || \
+           log_fail "An invalid setting '$option' was propagated."
+
+       log_mustnot $ZFS share ${datasets[i]}
+
+       not_shared ${datasets[i]} || \
+           log_fail "An invalid dataset '${datasets[i]}' was shared."
+
+       ((i = i + 1))
+done
+
+log_pass "Sharing datasets other than filesystems failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_009_neg.ksh
new file mode 100755 (executable)
index 0000000..6b4f303
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that zfs share should fail when sharing a shared zfs filesystem
+#
+# STRATEGY:
+# 1. Make a zfs filesystem shared
+# 2. Use zfs share to share the filesystem
+# 3. Verify that zfs share returns error
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset val
+
+       val=$(get_prop sharenfs $fs)
+       if [[ $val == on ]]; then
+               log_must $ZFS set sharenfs=off $fs
+       fi
+}
+
+log_assert "zfs share fails with shared filesystem"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+sharenfs_val=$(get_prop sharenfs $fs)
+mpt=$(get_prop mountpoint $fs)
+if [[ $sharenfs_val == off ]]; then
+       log_must $ZFS set sharenfs=on $fs
+fi
+
+$SHARE | $GREP $mpt >/dev/null 2>&1
+if (( $? != 0 )); then
+       log_must $ZFS share $fs
+fi
+
+log_mustnot $ZFS share $fs
+
+log_pass "zfs share fails with shared filesystem as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_010_neg.ksh
new file mode 100755 (executable)
index 0000000..a56761e
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that zfs share should fail with bad parameters
+#
+# STRATEGY:
+# 1. Make an array of bad parameters
+# 2. Use zfs share to share the filesystem
+# 3. Verify that zfs share returns error
+#
+
+verify_runnable "both"
+
+log_assert "zfs share fails with bad parameters"
+
+fs=$TESTPOOL/$TESTFS
+set -A badargs "A" "-A" "-" "-x" "-?" "=" "-a *" "-a"
+
+for arg in "${badargs[@]}"; do
+       log_mustnot eval "$ZFS share $arg $fs >/dev/null 2>&1"
+done
+
+#zfs share failed when missing arguments or invalid datasetname
+for obj in "" "/$fs"; do
+       log_mustnot eval "$ZFS share $obj >/dev/null 2>&1"
+done
+
+log_pass "zfs share fails with bad parameters as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_share/zfs_share_011_pos.ksh
new file mode 100755 (executable)
index 0000000..8f519b3
--- /dev/null
@@ -0,0 +1,85 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that umount and destroy fail, and do not unshare the shared
+# file system
+#
+# STRATEGY:
+# 1. Share the filesystem via 'zfs set sharenfs'.
+# 2. Try umount failure, and verify that the file system is still shared.
+# 3. Try destroy failure, and verify that the file system is still shared.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       log_must cd $origdir
+
+       log_must $ZFS set sharenfs=off $TESTPOOL/$TESTFS
+       unshare_fs $TESTPOOL/$TESTFS
+
+       if snapexists "$TESTPOOL/$TESTFS@snapshot"; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS@snapshot
+       fi
+
+       if datasetexists $TESTPOOL/$TESTFS/fs2 ; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS/fs2
+       fi
+}
+
+log_assert "Verify that umount and destroy fail, and do not unshare the shared" \
+       "file system"
+log_onexit cleanup
+
+typeset origdir=$PWD
+
+# unmount fails will not unshare the shared filesystem
+log_must $ZFS set sharenfs=on $TESTPOOL/$TESTFS
+log_must is_shared $TESTDIR
+if cd $TESTDIR ; then
+       log_mustnot $ZFS umount $TESTPOOL/$TESTFS
+else
+       log_fail "cd $TESTDIR fails"
+fi
+log_must is_shared $TESTDIR
+
+# destroy fails will not unshare the shared filesystem
+log_must $ZFS create $TESTPOOL/$TESTFS/fs2
+if cd $TESTDIR/fs2 ; then
+       log_mustnot $ZFS destroy $TESTPOOL/$TESTFS/fs2
+else
+       log_fail "cd $TESTDIR/fs2 fails"
+fi
+log_must is_shared $TESTDIR/fs2
+
+log_pass "Verify that umount and destroy fail, and do not unshare the shared" \
+       "file system"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/Makefile.am
new file mode 100644 (file)
index 0000000..fd1db07
--- /dev/null
@@ -0,0 +1,14 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_snapshot
+dist_pkgdata_SCRIPTS = \
+       zfs_snapshot.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_snapshot_001_neg.ksh \
+       zfs_snapshot_002_neg.ksh \
+       zfs_snapshot_003_neg.ksh \
+       zfs_snapshot_004_neg.ksh \
+       zfs_snapshot_005_neg.ksh \
+       zfs_snapshot_006_pos.ksh \
+       zfs_snapshot_007_neg.ksh \
+       zfs_snapshot_008_neg.ksh \
+       zfs_snapshot_009_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/cleanup.ksh
new file mode 100755 (executable)
index 0000000..d247991
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_container_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/setup.ksh
new file mode 100755 (executable)
index 0000000..b3f2b02
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_container_volume_setup ${DISK}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot.cfg
new file mode 100644 (file)
index 0000000..fb22367
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# 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_SUITE/include/libtest.shlib
+
+export SNAPFS="$TESTPOOL/$TESTFS@$TESTSNAP"
+export SNAPFS1="$TESTPOOL/$TESTVOL@$TESTSNAP"
+export SNAPDIR="$TESTDIR@$TESTSNAP"
+export SNAPDIR1="$ZFSROOT/$SNAPFS1"
+export SNAPDEV1="/$TESTDIR/snap1.dat"
+export SNAPDEV2="/$TESTDIR/snap2.dat"
+
+# Name lengths for snappool1 and snappool2 must the same
+export SNAPPOOL1="snappool1"
+export SNAPPOOL2="snappool2"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_001_neg.ksh
new file mode 100755 (executable)
index 0000000..860dd6c
--- /dev/null
@@ -0,0 +1,117 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_snapshot/zfs_snapshot.cfg
+
+#
+# DESCRIPTION:
+#      Try each 'zfs snapshot' with inapplicable scenarios to make sure
+#      it returns an error. include:
+#              * No arguments given.
+#              * The argument contains invalid characters for the ZFS namesapec
+#              * Leading slash in snapshot name
+#              * The argument contains an empty component.
+#              * Missing '@' delimiter.
+#              * Multiple '@' delimiters in snapshot name.
+#              * The snapshot already exist.
+#              * Create snapshot upon the pool.
+#                      (Be removed since pool is treated as filesystem as well)
+#              * Create snapshot upon a non-existent filesystem.
+#              * Too many arguments.
+#
+# STRATEGY:
+#      1. Create an array of parameters
+#      2. For each parameter in the array, execute the sub-command
+#      3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+set -A args "" \
+       "$TESTPOOL/$TESTFS@blah*" "$TESTPOOL/$TESTFS@blah?" \
+       "$TESTPOOL/$TESTVOL@blah*" "$TESTPOOL/$TESTVOL@blah?" \
+       "/$TESTPOOL/$TESTFS@$TESTSNAP" "/$TESTPOOL/$TESTVOL@$TESTSNAP" \
+       "@$TESTSNAP" "$TESTPOOL/$TESTFS@" "$TESTPOOL/$TESTVOL@" \
+       "$TESTPOOL//$TESTFS@$TESTSNAP" "$TESTPOOL//$TESTVOL@$TESTSNAP" \
+       "$TESTPOOL/$TESTFS/$TESTSNAP" "$TESTPOOL/$TESTVOL/$TESTSNAP" \
+       "$TESTPOOL/$TESTFS@$TESTSNAP@$TESTSNAP1" \
+       "$TESTPOOL/$TESTVOL@$TESTSNAP@$TESTSNAP1" \
+       "$SNAPFS" "$SNAPFS1" \
+       "blah/blah@$TESTSNAP"
+
+
+
+function setup_all
+{
+       log_note "Create snapshots and mount them..."
+
+       for snap in $SNAPFS $SNAPFS1; do
+               if ! snapexists $snap; then
+                       log_must $ZFS snapshot $snap
+               fi
+       done
+
+       return 0
+}
+
+function cleanup_all
+{
+       typeset -i i=0
+
+       while (( i < ${#args[*]} )); do
+               for snap in ${args[i]}; do
+                       snapexists $snap && log_must $ZFS destroy -f $snap
+               done
+               (( i = i + 1 ))
+       done
+
+       for mtpt in $SNAPDIR $SNAPDIR1; do
+               [[ -d $mtpt ]] && log_must $RM -rf $mtpt
+       done
+
+       return 0
+}
+
+log_assert "Badly-formed 'zfs snapshot' with inapplicable scenarios " \
+       "should return an error."
+log_onexit cleanup_all
+
+setup_all
+
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZFS snapshot ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Badly formed 'zfs snapshot' with inapplicable scenarios " \
+       "fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_002_neg.ksh
new file mode 100755 (executable)
index 0000000..907d0dd
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      "zfs snapshot -r" fails with invalid arguments or scenarios.
+#      The invalid scenarios may include:
+#      (1) The child filesystem already has snapshot with the same name
+#      (2) The child volume already has snapshot with the same name
+#
+# STRATEGY:
+#      1. Create an array of invalid arguments
+#      2. Execute 'zfs snapshot -r' with each argument in the array,
+#      3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset snap
+
+       for snap in $TESTPOOL/$TESTCTR/$TESTFS1@$TESTSNAP \
+               $TESTPOOL/$TESTCTR/$TESTVOL@$TESTSNAP;
+       do
+               snapexists $snap && \
+                       log_must $ZFS destroy $snap
+       done
+
+       datasetexists $TESTPOOL/$TESTCTR/$TESTVOL && \
+               log_must $ZFS destroy -rf $TESTPOOL/$TESTCTR/$TESTVOL
+
+}
+
+log_assert "'zfs snapshot -r' fails with invalid arguments or scenarios. "
+log_onexit cleanup
+
+set -A args "" \
+    "$TESTPOOL/$TESTCTR@$TESTSNAP" "$TESTPOOL/$TESTCTR@blah?" \
+    "$TESTPOOL/$TESTCTR@blah*" "@$TESTSNAP" "$TESTPOOL/$TESTCTR@" \
+    "$TESTPOOL/$TESTFS/$TESTSNAP" "blah/blah@$TESTSNAP" \
+    "$TESTPOOL/$TESTCTR@$TESTSNAP@$TESTSNAP"
+
+# setup preparations
+log_must $ZFS snapshot $TESTPOOL/$TESTCTR/$TESTFS1@$TESTSNAP
+
+# testing
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZFS snapshot -r ${args[i]}
+
+       ((i = i + 1))
+done
+
+# Testing the invalid senario: the child volume already has an
+# identical name snapshot, zfs snapshot -r should fail when
+# creating snapshot with -r for the parent
+log_must $ZFS destroy $TESTPOOL/$TESTCTR/$TESTFS1@$TESTSNAP
+if is_global_zone; then
+       log_must $ZFS create -V $VOLSIZE $TESTPOOL/$TESTCTR/$TESTVOL
+else
+       log_must $ZFS create $TESTPOOL/$TESTCTR/$TESTVOL
+fi
+log_must $ZFS snapshot $TESTPOOL/$TESTCTR/$TESTVOL@$TESTSNAP
+
+log_mustnot $ZFS snapshot -r $TESTPOOL/$TESTCTR@$TESTSNAP
+
+log_pass "'zfs snapshot -r' fails with invalid arguments or scenarios as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_003_neg.ksh
new file mode 100755 (executable)
index 0000000..e424b9b
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      "zfs snapshot" fails with bad options,too many arguments or too long
+#      snapshot name
+#
+# STRATEGY:
+#      1. Create an array of invalid arguments
+#      2. Execute 'zfs snapshot' with each argument in the array,
+#      3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+log_assert "'zfs snapshot' fails with bad options, or too many arguments. "
+
+set -A badopts "r" "R" "-R" "-x" "-rR" "-?" "-*" "-123"
+
+# set too long snapshot name (>256)
+l_name="$(gen_dataset_name 260 abcdefg)"
+
+for ds in $TESTPOOL/$TESTFS $TESTPOOL/$TESTCTR $TESTPOOL/$TESTVOL; do
+       for opt in ${badopts[@]}; do
+               log_mustnot $ZFS snapshot $opt $ds@$TESTSNAP
+       done
+
+       log_mustnot $ZFS snapshot $ds@snap $ds@snap1
+       log_mustnot $ZFS snapshot -r $ds@snap $ds@snap1
+
+       log_mustnot $ZFS snapshot $ds@$l_name
+       log_mustnot $ZFS snapshot -r $ds@$l_name
+done
+
+log_pass "'zfs snapshot' fails with bad options or too many arguments as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_004_neg.ksh
new file mode 100755 (executable)
index 0000000..319e5c4
--- /dev/null
@@ -0,0 +1,92 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify recursive snapshotting could not break ZFS.
+#
+# STRATEGY:
+#      1. Create deeply-nested filesystems until it is too long to create snap
+#      2. Verify zfs snapshot -r pool@snap will not break ZFS
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $initfs ; then
+               log_must $ZFS destroy -rf $initfs
+       fi
+}
+
+log_assert "Verify recursive snapshotting could not break ZFS."
+log_onexit cleanup
+
+initfs=$TESTPOOL/$TESTFS/$TESTFS
+basefs=$initfs
+typeset -i ret=0 len snaplen
+while ((ret == 0)); do
+       $ZFS create $basefs
+       $ZFS snapshot $basefs@snap1
+       ret=$?
+
+       if ((ret != 0)); then
+               len=$($ECHO $basefs| $WC -c)
+               log_note "The deeply-nested filesystem len: $len"
+
+               #
+               # Make sure there are at lease 2 characters left
+               # for snapshot name space, otherwise snapshot name
+               # is incorrect
+               #
+               if ((len >= 255)); then
+                       if datasetexists $basefs; then
+                               log_must $ZFS destroy -r $basefs
+                       fi
+                       basefs=${basefs%/*}
+                       len=$($ECHO $basefs| $WC -c)
+               fi
+               break
+       fi
+
+       basefs=$basefs/$TESTFS
+done
+
+# Make snapshot name is longer than the max length
+((snaplen = 256 - len + 10))
+snap=$(gen_dataset_name $snaplen "s")
+log_mustnot $ZFS snapshot -r $TESTPOOL@$snap
+
+log_must datasetnonexists $TESTPOOL@$snap
+while [[ $basefs != $TESTPOOL ]]; do
+       log_must datasetnonexists $basefs@$snap
+       basefs=${basefs%/*}
+done
+
+log_pass "Verify recursive snapshotting could not break ZFS."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_005_neg.ksh
new file mode 100755 (executable)
index 0000000..8794cba
--- /dev/null
@@ -0,0 +1,92 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Long name filesystem with snapshot should not break ZFS.
+#
+# STRATEGY:
+#      1. Create filesystem and snapshot.
+#      2. When the snapshot length is 256, rename the filesystem.
+#      3. Verify it does not break ZFS
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $initfs ; then
+               log_must $ZFS destroy -rf $initfs
+       fi
+}
+
+log_assert "Verify long name filesystem with snapshot should not break ZFS."
+log_onexit cleanup
+
+initfs=$TESTPOOL/$TESTFS/$TESTFS
+basefs=$initfs
+typeset -i ret=0 len snaplen
+while ((ret == 0)); do
+       $ZFS create $basefs
+       $ZFS snapshot $basefs@snap1
+       ret=$?
+
+       if ((ret != 0)); then
+               len=$($ECHO $basefs | $WC -c)
+               log_note "The deeply-nested filesystem len: $len"
+
+               #
+               # Make sure there are at lease 2 characters left
+               # for snapshot name space, otherwise snapshot name
+               # is incorrect
+               #
+               if ((len >= 255)); then
+                       if datasetexists $basefs; then
+                               log_must $ZFS destroy -r $basefs
+                       fi
+                       basefs=${basefs%/*}
+                       len=$($ECHO $basefs| $WC -c)
+               fi
+               break
+       fi
+
+       basefs=$basefs/$TESTFS
+done
+
+# Make snapshot name length match the longest one
+((snaplen = 256 - len - 1)) # 1: @
+snap=$(gen_dataset_name $snaplen "s")
+log_must $ZFS snapshot $basefs@$snap
+
+log_mustnot $ZFS rename $basefs ${basefs}a
+log_mustnot $ZFS rename $basefs ${basefs}-new
+log_mustnot $ZFS rename $initfs ${initfs}-new
+log_mustnot $ZFS rename $TESTPOOL/$TESTFS $TESTPOOL/$TESTFS-new
+
+log_pass "Verify long name filesystem with snapshot should not break ZFS."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_006_pos.ksh
new file mode 100755 (executable)
index 0000000..6d5f03c
--- /dev/null
@@ -0,0 +1,124 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+#      User property could be set via creation time by 'zfs snapshot -o'
+#
+# STRATEGY:
+#      1. Create snapshot and give '-o property=value'
+#      2. Verify the snapshot be created and user property have been set.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL ; do
+               typeset fssnap=$fs@snap
+               if datasetexists $fssnap ; then
+                       log_must $ZFS destroy -rf $fssnap
+               fi
+       done
+       cleanup_user_prop $TESTPOOL
+}
+
+function nonexist_user_prop
+{
+       typeset user_prop=$1
+       typeset dtst=$2
+
+       typeset source=$(get_source $user_prop $dtst)
+       typeset value=$(get_prop $user_prop $dtst)
+       if [[ $source == '-' && $value == '-' ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
+
+log_assert "User property could be set upon snapshot via 'zfs snapshot -o'."
+log_onexit cleanup
+
+typeset snap_property=
+
+for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL ; do
+       typeset fssnap=$fs@snap
+       prop_name=$(valid_user_property 10)
+       value=$(user_property_value 16)
+
+       log_must eval "$ZFS snapshot -o $prop_name='$value' $fssnap"
+       log_must snapexists $fssnap
+       log_mustnot nonexist_user_prop $prop_name $fssnap
+
+       log_must $ZFS destroy -f $fssnap
+
+       prop_name2=$(valid_user_property 10)
+       value2=$(user_property_value 16)
+
+       log_must eval "$ZFS snapshot -o $prop_name='$value' -o $prop_name2='$value2' $fssnap"
+       log_must snapexists $fssnap
+       log_mustnot nonexist_user_prop $prop_name $fssnap
+       log_mustnot nonexist_user_prop $prop_name2 $fssnap
+done
+
+cleanup
+
+prop_name=$(valid_user_property 10)
+value=$(user_property_value 16)
+
+log_must eval "$ZFS snapshot -r -o $prop_name='$value' $TESTPOOL@snap"
+for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL ; do
+       typeset fssnap=$fs@snap
+       log_must snapexists $fssnap
+       log_mustnot nonexist_user_prop $prop_name $fssnap
+
+       log_must $ZFS destroy -rf $fssnap
+done
+
+cleanup
+
+prop_name2=$(valid_user_property 10)
+value2=$(user_property_value 16)
+
+log_must eval "$ZFS snapshot -r -o $prop_name='$value' -o $prop_name2='$value2' $TESTPOOL@snap"
+for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL ; do
+       typeset fssnap=$fs@snap
+       log_must snapexists $fssnap
+       log_mustnot nonexist_user_prop $prop_name $fssnap
+       log_mustnot nonexist_user_prop $prop_name2 $fssnap
+
+       log_must $ZFS destroy -rf $fssnap
+done
+
+log_pass "User property could be set upon snapshot via 'zfs snapshot -o'."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_007_neg.ksh
new file mode 100755 (executable)
index 0000000..1a80e4f
--- /dev/null
@@ -0,0 +1,128 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib
+
+#
+# DESCRIPTION:
+#      'zfs snapshot -o' cannot set properties other than user property
+#
+# STRATEGY:
+#      1. Create snapshot and give '-o property=value' with regular property.
+#      2. Verify the snapshot creation failed.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL/$TESTCTR $TESTPOOL ; do
+               typeset fssnap=$fs@snap
+               if datasetexists $fssnap ; then
+                       log_must $ZFS destroy -rf $fssnap
+               fi
+       done
+       cleanup_user_prop $TESTPOOL
+}
+
+function nonexist_user_prop
+{
+       typeset user_prop=$1
+       typeset dtst=$2
+
+       typeset source=$(get_source $user_prop $dtst)
+       typeset value=$(get_prop $user_prop $dtst)
+       if [[ $source == '-' && $value == '-' ]]; then
+               return 0
+       else
+               return 1
+       fi
+}
+
+log_assert "'zfs snapshot -o' cannot set properties other than user property."
+log_onexit cleanup
+
+typeset ro_props="type used available avail creation referenced refer compressratio \
+       mounted origin"
+typeset snap_ro_props="volsize recordsize recsize quota reservation reserv mountpoint \
+       sharenfs checksum compression compress atime devices exec readonly rdonly \
+       setuid zoned"
+
+$ZFS upgrade -v > /dev/null 2>&1
+if [[ $? -eq 0 ]]; then
+       snap_ro_props="$snap_ro_props version"
+fi
+
+
+for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL/$TESTCTR $TESTPOOL ; do
+       typeset fssnap=$fs@snap
+       prop_name=$(valid_user_property 10)
+       value=$(user_property_value 16)
+
+       log_must eval "$ZFS snapshot -o $prop_name='$value' $fssnap"
+       log_must snapexists $fssnap
+       log_mustnot nonexist_user_prop $prop_name $fssnap
+
+       log_must $ZFS destroy -f $fssnap
+
+       prop_name2=$(valid_user_property 10)
+       value2=$(user_property_value 16)
+
+       log_must eval "$ZFS snapshot -o $prop_name='$value' -o $prop_name2='$value2' $fssnap"
+       log_must snapexists $fssnap
+       log_mustnot nonexist_user_prop $prop_name $fssnap
+       log_mustnot nonexist_user_prop $prop_name2 $fssnap
+
+       log_must $ZFS destroy -f $fssnap
+done
+
+cleanup
+
+prop_name=$(valid_user_property 10)
+value=$(user_property_value 16)
+
+log_must eval "$ZFS snapshot -r -o $prop_name='$value' $TESTPOOL@snap"
+for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL/$TESTCTR $TESTPOOL ; do
+       typeset fssnap=$fs@snap
+       log_must snapexists $fssnap
+       log_mustnot nonexist_user_prop $prop_name $fssnap
+done
+
+cleanup
+
+prop_name2=$(valid_user_property 10)
+value2=$(user_property_value 16)
+
+log_must eval "$ZFS snapshot -r -o $prop_name='$value' -o $prop_name2='$value2' $TESTPOOL@snap"
+for fs in $TESTPOOL/$TESTFS $TESTPOOL/$TESTVOL $TESTPOOL/$TESTCTR $TESTPOOL ; do
+       typeset fssnap=$fs@snap
+       log_must snapexists $fssnap
+       log_mustnot nonexist_user_prop $prop_name $fssnap
+       log_mustnot nonexist_user_prop $prop_name2 $fssnap
+done
+
+log_pass "'zfs snapshot -o' cannot set properties other than user property."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_008_neg.ksh
new file mode 100755 (executable)
index 0000000..153a016
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_snapshot/zfs_snapshot.cfg
+
+#
+# DESCRIPTION:
+#      'zfs snapshot pool1@snap pool2@snap' should fail since both snapshots
+#      are not in the same pool.
+#
+# STRATEGY:
+#      1. Create 2 separate zpools, zpool name lenghts must be the same.
+#      2. Attempt to simultaneously create a snapshot of each pool.
+#      3. Veriy the snapshot creation failed.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for pool in $SNAPPOOL1 $SNAPPOOL2 ; do
+               if poolexists $pool ; then
+                       log_must $ZPOOL destroy -f $pool
+               fi
+       done
+
+       for dev in $SNAPDEV1 $SNAPDEV2 ; do
+               if [[ -f $dev ]] ; then
+                       log_must rm -f $dev
+               fi
+       done
+}
+
+log_assert "'zfs snapshot pool1@snap1 pool2@snap2' should fail since snapshots are in different pools."
+log_onexit cleanup
+
+log_must $MKFILE 64m $SNAPDEV1
+log_must $MKFILE 64m $SNAPDEV2
+
+log_must $ZPOOL create $SNAPPOOL1 $SNAPDEV1
+log_must $ZPOOL create $SNAPPOOL2 $SNAPDEV2
+
+log_mustnot $ZFS snapshot $SNAPPOOL1@snap1 $SNAPPOOL2@snap2
+
+log_pass "'zfs snapshot pool1@snap1 pool2@snap2' should fail since snapshots are in different pools."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/zfs_snapshot_009_pos.ksh
new file mode 100755 (executable)
index 0000000..318c3ad
--- /dev/null
@@ -0,0 +1,102 @@
+#!/bin/ksh
+#
+# 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.
+#
+
+#
+# DESCRIPTION
+# verify 'zfs snapshot <list of snapshots>' works correctly
+#
+# STRATEGY
+# 1. Create multiple datasets
+# 2. Create mutiple snapshots with a list of valid and invalid
+#    snapshot names
+# 3. Verify the valid snpashot creation
+
+. $STF_SUITE/include/libtest.shlib
+
+function cleanup
+{
+       for ds in $datasets; do
+               datasetexists $ds && log_must $ZFS destroy -r $ds
+       done
+       $ZFS destroy -r $TESTPOOL/TESTFS4
+}
+datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS2
+    $TESTPOOL/$TESTFS3"
+
+invalid_args=("$TESTPOOL/$TESTFS1@now $TESTPOOL/$TESTFS2@now \
+    $TESTPOOL/$TESTFS@blah?" "$TESTPOOL/$TESTFS1@blah* \
+    $TESTPOOL/$TESTFS2@blah? $TESTPOOL/$TESTFS3@blah%" \
+    "$TESTPOOL/$TESTFS1@$($PYTHON -c 'print "x" * 300') $TESTPOOL/$TESTFS2@300 \
+    $TESTPOOL/$TESTFS3@300")
+
+valid_args=("$TESTPOOL/$TESTFS1@snap $TESTPOOL/$TESTFS2@snap \
+    $TESTPOOL/$TESTFS3@snap" "$TESTPOOL/$TESTFS1@$($PYTHON -c 'print "x" * 200')\
+    $TESTPOOL/$TESTFS2@2 $TESTPOOL/$TESTFS3@s")
+
+log_assert "verify zfs supports multiple consistent snapshots"
+log_onexit cleanup
+typeset -i i=1
+test_data=$STF_SUITE/tests/functional/cli_root/zpool_upgrade/*.bz2
+
+log_note "destroy a list of valid snapshots"
+for ds in $datasets; do
+       log_must $ZFS create $ds
+       log_must $CP -r $test_data /$ds
+done
+i=0
+while (( i < ${#valid_args[*]} )); do
+       log_must $ZFS snapshot ${valid_args[i]}
+       for token in ${valid_args[i]}; do
+               log_must snapexists $token && \
+                   log_must $ZFS destroy $token
+       done
+       ((i = i + 1))
+done
+log_note "destroy a list of invalid snapshots"
+i=0
+while (( i < ${#invalid_args[*]} )); do
+       log_mustnot $ZFS snapshot ${invalid_args[i]}
+       for token in ${invalid_args[i]}; do
+               log_mustnot snapexists $token
+       done
+       ((i = i + 1))
+done
+log_note "verify multiple snapshot transaction group"
+txg_group=$($ZDB -Pd $TESTPOOL | $GREP snap | $AWK '{print $7}')
+for i in 1 2 3; do
+       txg_tag=$($ECHO "$txg_group" | $NAWK -v j=$i 'FNR == j {print}')
+       [[ $txg_tag != $($ECHO "$txg_group" | \
+           $NAWK -v j=$i 'FNR == j {print}') ]] \
+           && log_fail "snapshots belong to differnt transaction groups"
+done
+log_note "verify snapshot contents"
+for ds in $datasets; do
+       status=$($DIRCMP /$ds /$ds/.zfs/snapshot/snap | $GREP "different")
+       [[ -z $status ]] || log_fail "snapshot contents are different from" \
+           "the filesystem"
+done
+
+log_note "verify multiple snapshot with -r option"
+log_must $ZFS create $TESTPOOL/TESTFS4
+log_must $ZFS create -p $TESTPOOL/$TESTFS3/TESTFSA$($PYTHON -c 'print "x" * 210')/TESTFSB
+log_mustnot $ZFS snapshot -r $TESTPOOL/$TESTFS1@snap1 $TESTPOOL/$TESTFS2@snap1 \
+        $TESTPOOL/$TESTFS3@snap1 $TESTPOOL/TESTFS4@snap1
+log_must $ZFS rename  $TESTPOOL/$TESTFS3/TESTFSA$($PYTHON -c 'print "x" * 210') \
+    $TESTPOOL/$TESTFS3/TESTFSA
+log_must $ZFS snapshot -r $TESTPOOL/$TESTFS1@snap1 $TESTPOOL/$TESTFS2@snap1 \
+        $TESTPOOL/$TESTFS3@snap1 $TESTPOOL/TESTFS4@snap1
+
+log_pass "zfs multiple snapshot verified correctly"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/Makefile.am
new file mode 100644 (file)
index 0000000..57a7808
--- /dev/null
@@ -0,0 +1,16 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_unmount
+dist_pkgdata_SCRIPTS = \
+       zfs_unmount.cfg \
+       zfs_unmount.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_unmount_001_pos.ksh \
+       zfs_unmount_002_pos.ksh \
+       zfs_unmount_003_pos.ksh \
+       zfs_unmount_004_pos.ksh \
+       zfs_unmount_005_pos.ksh \
+       zfs_unmount_006_pos.ksh \
+       zfs_unmount_007_neg.ksh \
+       zfs_unmount_008_neg.ksh \
+       zfs_unmount_009_pos.ksh \
+       zfs_unmount_all_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount.cfg
new file mode 100644 (file)
index 0000000..c8e4689
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+
+export mountcmd=mount
+export mountforce="$mountcmd -f"
+export mountall="$mountcmd -a"
+
+export unmountcmd=unmount
+export unmountforce="$unmountcmd -f"
+export unmountall="$unmountcmd -a"
+
+export NONEXISTFSNAME="nonexistfs50charslong_0123456789012345678901234567"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib
new file mode 100644 (file)
index 0000000..9c9cb71
--- /dev/null
@@ -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.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_unmount/zfs_unmount.cfg
+
+function do_unmount #cmd #opt #mnt #expect
+{
+       typeset cmd=$1
+       typeset opt=$2
+       typeset mnt=$3
+       typeset -i expect=${4-0}
+       typeset -i ret
+       typeset -i wasmounted=1
+
+       mounted $mnt || wasmounted=0
+
+       if (( expect == 0 )) ; then
+               log_must $ZFS $cmd $opt $mnt
+
+               log_must unmounted $mnt
+
+               log_note "Successfully $ZFS $cmd $opt $mnt"
+
+       else
+               log_note "$ZFS $cmd $opt $mnt"
+
+               $ZFS $cmd $opt $mnt
+               ret=$?
+               if (( ret != expect)); then
+                       log_fail "'$ZFS $cmd $opt $mnt' " \
+                               "unexpected return code of $ret."
+               fi
+
+               if (( wasmounted == 1 )) ; then
+                       log_must mounted $mnt
+               else
+                       log_must unmounted $mnt
+               fi
+               log_note "Mount status of $mnt not changed."
+       fi
+}
+
+function cleanup
+{
+       [[ -n $cwd ]] && cd $cwd
+
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+       mounted $TESTPOOL/$TESTFS || \
+               log_must $ZFS $mountcmd $TESTPOOL/$TESTFS
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_001_pos.ksh
new file mode 100755 (executable)
index 0000000..924e6ac
--- /dev/null
@@ -0,0 +1,112 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Creates a file system and verifies that it can be unmounted
+# using each of the various unmount options and sub-command
+# variants.
+#
+# STRATEGY:
+# 1. Create and mount a file system as necessary.
+# 2. Umount the file system using the various combinations.
+#      - With force option.
+#      - Without force option.
+#      - Using the unmount sub-command.
+#      - Using the umount sub-command.
+#
+
+verify_runnable "both"
+
+
+function cleanup
+{
+       mounted $TESTDIR2 && \
+               log_must $ZFS umount -f $TESTDIR2
+
+       datasetexists $TESTPOOL/$TESTFS2 && \
+               log_must $ZFS destroy $TESTPOOL/$TESTFS2
+
+       [[ -d $TESTDIR2 ]] && \
+               log_must $RM -rf $TESTDIR2
+}
+function do_unmount
+{
+       typeset cmd=$1
+       typeset opt=$2
+       typeset mnt=$3
+
+       [[ ! -d $TESTDIR2 ]] && \
+           log_must $MKDIR $TESTDIR2
+
+       if ! datasetexists $TESTPOOL/$TESTFS2 ; then
+               log_must $ZFS create $TESTPOOL/$TESTFS2
+               log_must $ZFS set mountpoint=$TESTDIR2 \
+                   $TESTPOOL/$TESTFS2
+       fi
+
+       unmounted $TESTPOOL/$TESTFS2 && \
+               log_must $ZFS mount $TESTPOOL/$TESTFS2
+
+       log_must $ZFS $cmd $options $mnt
+
+       unmounted "$mnt" || \
+               log_fail "Unable to unmount $options $mnt"
+
+       log_note "Successfully unmounted $options $mnt"
+}
+
+log_onexit cleanup
+
+set -A cmd "umount" "unmount"
+set -A options "" "-f"
+set -A dev "$TESTPOOL/$TESTFS2" "$TESTDIR2"
+
+log_assert "Verify the u[n]mount [-f] sub-command."
+
+typeset -i i=0
+typeset -i j=0
+typeset -i k=0
+while [[ $i -lt ${#cmd[*]} ]]; do
+       j=0
+       while [[ $j -lt ${#options[*]} ]]; do
+               k=0
+               while [[ $k -lt ${#dev[*]} ]]; do
+                       do_unmount "${cmd[i]}" "${options[j]}" \
+                           "${dev[k]}"
+
+                       ((k = k + 1))
+               done
+
+               ((j = j + 1))
+       done
+
+       ((i = i + 1))
+done
+
+log_pass "zfs u[n]mount [-f] completed successfully."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_002_pos.ksh
new file mode 100755 (executable)
index 0000000..1b0e621
--- /dev/null
@@ -0,0 +1,94 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib
+
+#
+# DESCRIPTION:
+# If invoke "zfs unmount [-f]" with a filesystem|mountpoint
+# whose name is not in "zfs list",
+# it will fail with a return code of 1
+# and issue an error message.
+#
+# STRATEGY:
+# 1. Make sure that the non-existent ZFS filesystem|mountpoint
+# not in 'zfs list'.
+# 2. Unmount the file system using the various combinations.
+#      - Without force option. (FAILED)
+#      - With force option. (FAILED)
+# 3. Unmount the mountpoint using the various combinations.
+#      - Without force option. (FAILED)
+#      - With force option. (FAILED)
+# 4. Verify the above expected results of the filesystem|mountpoint.
+#
+
+verify_runnable "both"
+
+
+set -A cmd "umount" "unmount"
+set -A options "" "-f"
+set -A dev "$TESTPOOL/$NONEXISTFSNAME" "${TEST_BASE_DIR%%/}/$NONEXISTFSNAME"
+
+function do_unmount_multiple #options #expect
+{
+       typeset opt=$1
+       typeset -i expect=${2-0}
+
+       typeset -i i=0
+       typeset -i j=0
+
+       while (( i <  ${#cmd[*]} )); do
+               j=0
+               while (( j < ${#dev[*]} )); do
+                       log_note "Make sure ${dev[j]} is not in 'zfs list'"
+                       log_mustnot $ZFS list ${dev[j]}
+
+                       do_unmount "${cmd[i]}" "$opt" \
+                               "${dev[j]}" $expect
+
+                       ((j = j + 1))
+               done
+
+               ((i = i + 1))
+       done
+}
+
+log_assert "Verify that '$ZFS $unmountcmd [-f] <filesystem|mountpoint>' " \
+       "whose name is not in 'zfs list' will fail with return code 1."
+
+log_onexit cleanup
+
+typeset -i i=0
+
+while (( i <  ${#options[*]} )); do
+       do_unmount_multiple "${options[i]}" 1
+       ((i = i + 1))
+done
+
+log_pass "'$ZFS $unmountcmd [-f] <filesystem|mountpoint>' " \
+       "whose name is not in 'zfs list' failed with return code 1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_003_pos.ksh
new file mode 100755 (executable)
index 0000000..8f1b949
--- /dev/null
@@ -0,0 +1,105 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib
+
+#
+# DESCRIPTION:
+# If invoke "zfs unmount [-f]" with a filesystem|mountpoint
+# whose mountpoint property is 'legacy' or 'none',
+# it will fail with a return code of 1
+# and issue an error message.
+#
+# STRATEGY:
+# 1. Make sure that the ZFS filesystem is mounted.
+# 2. Apply 'zfs set mountpoint=legacy|none <filesystem>'.
+# 3. Unmount the file system using the various combinations.
+#      - Without force option. (FAILED)
+#      - With force option. (FAILED)
+# 4. Unmount the mountpoint using the various combinations.
+#      - Without force option. (FAILED)
+#      - With force option. (FAILED)
+# 5. Verify the above expected results of the filesystem|mountpoint.
+#
+
+verify_runnable "both"
+
+
+set -A cmd "umount" "unmount"
+set -A options "" "-f"
+set -A dev "$TESTPOOL/$TESTFS" "$TESTDIR"
+set -A mopts "legacy" "none"
+
+function do_unmount_multiple #options #expect #mountpoint
+{
+       typeset opt=$1
+       typeset -i expect=${2-0}
+       typeset mopt=$3
+
+       typeset -i i=0
+       typeset -i j=0
+
+       while (( i <  ${#cmd[*]} )); do
+               j=0
+               while (( j < ${#dev[*]} )); do
+                       [[ -n $mopt ]] && \
+                               log_must $ZFS set mountpoint=$mopt ${dev[0]}
+
+                       do_unmount "${cmd[i]}" "$opt" \
+                               "${dev[j]}" $expect
+
+                       cleanup
+
+                       ((j = j + 1))
+               done
+
+               ((i = i + 1))
+       done
+}
+
+log_assert "Verify that '$ZFS $unmountcmd [-f] <filesystem|mountpoint>' " \
+       "whose mountpoint property is 'legacy' or 'none' " \
+       "will fail with return code 1."
+
+log_onexit cleanup
+
+typeset -i i=0
+typeset -i j=0
+
+while (( i < ${#mopts[*]} )); do
+       j=0
+       while (( j <  ${#options[*]} )); do
+               do_unmount_multiple "${options[j]}" 1 "${mopts[i]}"
+               ((j = j + 1))
+       done
+       ((i = i + 1))
+done
+
+log_pass "'$ZFS $unmountcmd [-f] <filesystem|mountpoint>' " \
+       "whose mountpoint property is 'legacy' or 'none' " \
+       "will fail with return code 1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_004_pos.ksh
new file mode 100755 (executable)
index 0000000..8f3def6
--- /dev/null
@@ -0,0 +1,95 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib
+
+#
+# DESCRIPTION:
+# If invoke "zfs unmount [-f]" with a specific filesystem|mountpoint,
+# which is not currently mounted,
+# it will fail with a return code of 1
+# and issue an error message.
+#
+# STRATEGY:
+# 1. Make sure that the ZFS filesystem is mounted.
+# 2. Invoke 'zfs unmount <filesystem>'.
+# 3. Verify that the filesystem is unmounted.
+# 4. Unmount the file system using the various combinations.
+#      - Without force option. (FAILED)
+#      - With force option. (FAILED)
+# 5. Unmount the mountpoint using the various combinations.
+#      - Without force option. (FAILED)
+#      - With force option. (FAILED)
+# 6. Verify the above expected results of the filesystem|mountpoint.
+#
+
+verify_runnable "both"
+
+
+set -A cmd "umount" "unmount"
+set -A options "" "-f"
+set -A dev "$TESTPOOL/$TESTFS" "$TESTDIR"
+
+function do_unmount_multiple #options #expect
+{
+       typeset opt=$1
+       typeset -i expect=${2-0}
+
+       typeset -i i=0
+       typeset -i j=0
+
+       while (( i <  ${#cmd[*]} )); do
+               j=0
+               while (( j < ${#dev[*]} )); do
+                       unmounted ${dev[j]} || \
+                               log_must $ZFS $unmountforce ${dev[j]}
+
+                       do_unmount "${cmd[i]}" "$opt" \
+                               "${dev[j]}" $expect
+
+                       ((j = j + 1))
+               done
+
+               ((i = i + 1))
+       done
+}
+
+log_assert "Verify that '$ZFS $unmountcmd [-f] <filesystem|mountpoint>' " \
+       "with an unmounted filesystem will fail with return code 1."
+
+log_onexit cleanup
+
+typeset -i i=0
+
+while (( i <  ${#options[*]} )); do
+       do_unmount_multiple "${options[i]}" 1
+       ((i = i + 1))
+done
+
+log_pass "'$ZFS $unmountcmd [-f] <filesystem|mountpoint>' " \
+       "with an unmounted filesystem failed with return code 1."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_005_pos.ksh
new file mode 100755 (executable)
index 0000000..ac2de65
--- /dev/null
@@ -0,0 +1,109 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib
+
+#
+# DESCRIPTION:
+# If invoke "zfs unmount" with a specific filesystem|mountpoint
+# that have been mounted, but it's currently in use,
+# it will fail with a return code of 1
+# and issue an error message.
+# But unmount forcefully will bypass this restriction and
+# unmount that given filesystem successfully.
+#
+# STRATEGY:
+# 1. Make sure that the ZFS filesystem is mounted.
+# 2. Change directory to that given mountpoint.
+# 3. Unmount the file system using the various combinations.
+#      - Without force option. (FAILED)
+#      - With force option. (PASS)
+# 4. Unmount the mountpoint using the various combinations.
+#      - Without force option. (FAILED)
+#      - With force option. (PASS)
+# 5. Verify the above expected results of the filesystem|mountpoint.
+#
+
+verify_runnable "both"
+
+
+set -A cmd "umount" "unmount"
+set -A options "" "-f"
+set -A dev "$TESTPOOL/$TESTFS" "$TESTDIR"
+
+function do_unmount_multiple #options #expect
+{
+       typeset opt=$1
+       typeset -i expect=${2-0}
+
+       typeset -i i=0
+       typeset -i j=0
+
+       while (( i <  ${#cmd[*]} )); do
+               j=0
+               while (( j < ${#dev[*]} )); do
+                       mounted ${dev[j]} || \
+                               log_must $ZFS $mountcmd ${dev[0]}
+
+                       cd $TESTDIR || \
+                               log_unresolved "Unable change dir to $TESTDIR"
+
+                       do_unmount "${cmd[i]}" "$opt" \
+                               "${dev[j]}" $expect
+
+                       cleanup
+
+                       ((j = j + 1))
+               done
+
+               ((i = i + 1))
+       done
+}
+
+log_assert "Verify that '$ZFS $unmountcmd <filesystem|mountpoint>' " \
+       "with a filesystem which mountpoint is currently in use " \
+       "will fail with return code 1, and forcefully will succeeds as root."
+
+log_onexit cleanup
+
+cwd=$PWD
+
+typeset -i i=0
+
+while (( i <  ${#options[*]} )); do
+       if [[ ${options[i]} == "-f" ]]; then
+               do_unmount_multiple "${options[i]}"
+       else
+               do_unmount_multiple "${options[i]}" 1
+       fi
+        ((i = i + 1))
+done
+
+log_pass "'$ZFS $unmountcmd <filesystem|mountpoint>' " \
+       "with a filesystem which mountpoint is currently in use " \
+       "will fail with return code 1, and forcefully will succeeds as root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_006_pos.ksh
new file mode 100755 (executable)
index 0000000..3e2ac07
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Re-creating zfs files, 'zfs unmount' still succeed.
+#
+# STRATEGY:
+#      1. Create pool and filesystem.
+#      2. Recreating the same file in this fs for a while, then breaking out.
+#      3. Verify the filesystem can be unmount successfully.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if ! ismounted $TESTPOOL/$TESTFS ; then
+               log_must $ZFS mount $TESTPOOL/$TESTFS
+       fi
+}
+
+log_assert "Re-creating zfs files, 'zfs unmount' still succeed."
+log_onexit cleanup
+
+# Call cleanup to make sure the file system are mounted.
+cleanup
+mntpnt=$(get_prop mountpoint $TESTPOOL/$TESTFS)
+(($? != 0)) && log_fail "get_prop mountpoint $TESTPOOL/$TESTFS"
+
+typeset -i i=0
+while (( i < 10000 )); do
+       $CP $STF_SUITE/include/libtest.shlib $mntpnt
+
+       (( i += 1 ))
+done
+log_note "Recreating zfs files for 10000 times."
+
+log_must $ZFS unmount $TESTPOOL/$TESTFS
+
+log_pass "Re-creating zfs files, 'zfs unmount' passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_007_neg.ksh
new file mode 100755 (executable)
index 0000000..c1000e8
--- /dev/null
@@ -0,0 +1,106 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib
+
+#
+# DESCRIPTION:
+#      Try each 'zfs unmount' with inapplicable scenarios to make sure
+#      it returns an error. include:
+#              * Multiple filesystem|mountpoint specified
+#              * '-a', but also with a specific filesystem|mountpoint.
+#
+# STRATEGY:
+#      1. Create an array of parameters
+#      2. For each parameter in the array, execute the sub-command
+#      3. Verify an error is returned.
+#
+
+verify_runnable "both"
+
+multifs="$TESTFS $TESTFS1"
+datasets=""
+
+for fs in $multifs ; do
+       datasets="$datasets $TESTPOOL/$fs"
+done
+
+set -A args "$unmountall $TESTPOOL/$TESTFS" \
+       "$unmountcmd $datasets"
+
+function setup_all
+{
+       typeset fs
+
+       for fs in $multifs ; do
+               setup_filesystem "$DISKS" "$TESTPOOL" \
+                       "$fs" \
+                       "${TEST_BASE_DIR%%/}/testroot$$/$TESTPOOL/$fs"
+       done
+       return 0
+}
+
+function cleanup_all
+{
+       typeset fs
+
+       cleanup_filesystem "$TESTPOOL" "$TESTFS1"
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+       [[ -d ${TEST_BASE_DIR%%/}/testroot$$ ]] && \
+               $RM -rf ${TEST_BASE_DIR%%/}/testroot$$
+
+       return 0
+}
+
+function verify_all
+{
+       typeset fs
+
+       for fs in $multifs ; do
+               log_must mounted $TESTPOOL/$fs
+       done
+       return 0
+}
+
+log_assert "Badly-formed 'zfs $unmountcmd' with inapplicable scenarios " \
+       "should return an error."
+log_onexit cleanup_all
+
+log_must setup_all
+
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZFS ${args[i]}
+       ((i = i + 1))
+done
+
+log_must verify_all
+
+log_pass "Badly formed 'zfs $unmountcmd' with inapplicable scenarios " \
+       "fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_008_neg.ksh
new file mode 100755 (executable)
index 0000000..04a7e56
--- /dev/null
@@ -0,0 +1,143 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that zfs unmount should fail with bad parameters or scenarios:
+#      1. bad option;
+#      2. too many arguments;
+#      3. null arguments;
+#      4. invalid datasets;
+#      5. invalid mountpoint;
+#      6. already unmounted zfs filesystem;
+#      7. legacy mounted zfs filesystem
+#
+# STRATEGY:
+# 1. Make an array of bad parameters
+# 2. Use zfs unmount to unmount the filesystem
+# 3. Verify that zfs unmount returns error
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for ds in $vol $fs1; do
+               if datasetexists $ds; then
+                       log_must $ZFS destroy -f $ds
+               fi
+       done
+
+       if snapexists $snap; then
+               log_must $ZFS destroy $snap
+       fi
+
+       if [[ -e /tmp/$file ]]; then
+               $RM -f /tmp/$file
+       fi
+       if [[ -d /tmp/$dir ]]; then
+               $RM -rf /tmp/$dir
+       fi
+
+}
+
+log_assert "zfs unmount fails with bad parameters or scenarios"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+vol=$TESTPOOL/vol.$$
+snap=$TESTPOOL/$TESTFS@snap.$$
+set -A badargs "A" "-A" "F" "-F" "-" "-x" "-?"
+
+if ! ismounted $fs; then
+       log_must $ZFS mount $fs
+fi
+
+log_must $ZFS snapshot $snap
+if is_global_zone; then
+       log_must $ZFS create -V 10m $vol
+else
+       vol=""
+fi
+
+# Testing bad options
+for arg in ${badargs[@]}; do
+       log_mustnot eval "$ZFS unmount $arg $fs >/dev/null 2>&1"
+done
+
+
+#Testing invalid datasets
+for ds in $snap $vol "blah"; do
+       for opt in "" "-f"; do
+               log_mustnot eval "$ZFS unmount $opt $ds >/dev/null 2>&1"
+       done
+done
+
+#Testing invalid mountpoint
+dir=foodir.$$
+file=foo.$$
+fs1=$TESTPOOL/fs.$$
+$MKDIR /tmp/$dir
+$TOUCH /tmp/$file
+log_must $ZFS create -o mountpoint=/tmp/$dir $fs1
+curpath=`$DIRNAME $0`
+cd /tmp
+for mpt in "./$dir" "./$file" "/tmp"; do
+       for opt in "" "-f"; do
+               log_mustnot eval "$ZFS unmount $opt $mpt >/dev/null 2>&1"
+       done
+done
+cd $curpath
+
+#Testing null argument and too many arguments
+for opt in "" "-f"; do
+       log_mustnot eval "$ZFS unmount $opt >/dev/null 2>&1"
+       log_mustnot eval "$ZFS unmount $opt $fs $fs1 >/dev/null 2>&1"
+done
+
+#Testing already unmounted filesystem
+log_must $ZFS unmount $fs1
+for opt in "" "-f"; do
+       log_mustnot eval "$ZFS unmount $opt $fs1 >/dev/null 2>&1"
+       log_mustnot eval "$ZFS unmount /tmp/$dir >/dev/null 2>&1"
+done
+
+#Testing legacy mounted filesystem
+log_must $ZFS set mountpoint=legacy $fs1
+if is_linux; then
+       log_must $MOUNT -t zfs $fs1 /tmp/$dir
+else
+       log_must $MOUNT -F zfs $fs1 /tmp/$dir
+fi
+for opt in "" "-f"; do
+       log_mustnot eval "$ZFS unmount $opt $fs1 >/dev/null 2>&1"
+done
+$UMOUNT /tmp/$dir
+
+log_pass "zfs unmount fails with bad parameters or scenarios as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_009_pos.ksh
new file mode 100755 (executable)
index 0000000..79c6fda
--- /dev/null
@@ -0,0 +1,123 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that zfs unmount and destroy in a snapshot directory will not cause error.
+#
+# STRATEGY:
+# 1. Create a file in a zfs filesystem, snapshot it and change directory to snapshot directory
+# 2. Verify that 'zfs unmount -a'  will fail and 'zfs unmount -fa' will succeed
+# 3. Verify 'ls' and 'cd /' will succeed
+# 4. 'zfs mount -a' and change directory to snapshot directory again
+# 5. Verify that zfs destroy snapshot will succeed
+# 6. Verify 'ls' and 'cd /' will succeed
+# 7. Create zfs filesystem, create a file, snapshot it and change to snapshot directory
+# 8. Verify that zpool destroy the pool will succeed
+# 9. Verify 'ls' 'cd /' 'zpool list' and etc will succeed
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       DISK=${DISKS%% *}
+
+       for fs in $TESTPOOL/$TESTFS $TESTPOOL ; do
+               typeset snap=$fs@$TESTSNAP
+               if snapexists $snap; then
+                       log_must $ZFS destroy $snap
+               fi
+       done
+
+       if ! poolexists $TESTPOOL && is_global_zone; then
+               log_must $ZPOOL create $TESTPOOL $DISK
+       fi
+
+       if ! datasetexists $TESTPOOL/$TESTFS; then
+               log_must $ZFS create $TESTPOOL/$TESTFS
+               log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+       fi
+}
+
+function restore_dataset
+{
+       if ! datasetexists $TESTPOOL/$TESTFS ; then
+               log_must $ZFS create $TESTPOOL/$TESTFS
+               log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+               log_must cd $TESTDIR
+               $ECHO hello > world
+               log_must $ZFS snapshot $TESTPOOL/$TESTFS@$TESTSNAP
+               log_must cd .zfs/snapshot/$TESTSNAP
+       fi
+}
+
+
+log_assert "zfs fource unmount and destroy in snapshot directory will not cause error."
+log_onexit cleanup
+
+for fs in $TESTPOOL/$TESTFS $TESTPOOL ; do
+       typeset snap=$fs@$TESTSNAP
+       typeset mtpt=$(get_prop mountpoint $fs)
+
+       log_must cd $mtpt
+       $ECHO hello > world
+       log_must $ZFS snapshot $snap
+       log_must cd .zfs/snapshot/$TESTSNAP
+
+       log_mustnot $ZFS unmount -a
+       log_must $ZFS unmount -fa
+       log_mustnot $LS
+       log_must cd /
+
+       log_must $ZFS mount -a
+       log_must cd $mtpt
+       log_must cd .zfs/snapshot/$TESTSNAP
+
+       if is_global_zone || [[ $fs != $TESTPOOL ]] ; then
+               log_must $ZFS destroy -rf $fs
+               log_mustnot $LS
+               log_must cd /
+       fi
+
+       restore_dataset
+done
+
+if is_global_zone ; then
+       log_must $ZPOOL destroy -f $TESTPOOL
+       log_mustnot $LS
+       log_must cd /
+fi
+
+log_must eval $ZFS list > /dev/null 2>&1
+log_must eval $ZPOOL list > /dev/null 2>&1
+log_must eval $ZPOOL status > /dev/null 2>&1
+$ZPOOL iostat > /dev/null 2>&1
+
+log_pass "zfs fource unmount and destroy in snapshot directory will not cause error."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_all_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unmount/zfs_unmount_all_001_pos.ksh
new file mode 100755 (executable)
index 0000000..454293f
--- /dev/null
@@ -0,0 +1,195 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib
+
+#
+# DESCRIPTION:
+#       Verify that 'zfs unmount -a[f]' succeeds as root.
+#
+# STRATEGY:
+#       1. Create a group of pools with specified vdev.
+#       2. Create zfs filesystems within the given pools.
+#       3. Mount all the filesystems.
+#       4. Verify that 'zfs unmount -a[f]' command succeed,
+#         and all available ZFS filesystems are unmounted.
+#      5. Verify that 'zfs mount' is identical with 'df -F zfs'
+#
+
+verify_runnable "both"
+
+set -A fs "$TESTFS" "$TESTFS1"
+set -A ctr "" "$TESTCTR" "$TESTCTR1" "$TESTCTR/$TESTCTR1"
+set -A vol "$TESTVOL" "$TESTVOL1"
+
+function setup_all
+{
+       typeset -i i=0
+       typeset -i j=0
+       typeset path
+
+       while (( i < ${#ctr[*]} )); do
+
+               path=${TEST_BASE_DIR%%/}/testroot$$/$TESTPOOL
+               if [[ -n ${ctr[i]} ]]; then
+                       path=$path/${ctr[i]}
+
+                       setup_filesystem "$DISKS" "$TESTPOOL" \
+                               "${ctr[i]}" "$path" \
+                               "ctr"
+               fi
+
+               if is_global_zone ; then
+                       j=0
+                       while (( j < ${#vol[*]} )); do
+                               setup_filesystem "$DISKS" "$TESTPOOL" \
+                               "${ctr[i]}/${vol[j]}" \
+                                       "$path/${vol[j]}" \
+                                       "vol"
+                               ((j = j + 1))
+                       done
+               fi
+               j=0
+               while (( j < ${#fs[*]} )); do
+                       setup_filesystem "$DISKS" "$TESTPOOL" \
+                               "${ctr[i]}/${fs[j]}" \
+                               "$path/${fs[j]}"
+                       ((j = j + 1))
+               done
+
+               ((i = i + 1))
+       done
+
+       return 0
+}
+
+function cleanup_all
+{
+       typeset -i i=0
+       typeset -i j=0
+
+       ((i = ${#ctr[*]} - 1))
+
+       while (( i >= 0 )); do
+               if is_global_zone ; then
+                       j=0
+                       while (( j < ${#vol[*]} )); do
+                               cleanup_filesystem "$TESTPOOL" \
+                                       "${ctr[i]}/${vol[j]}"
+                               ((j = j + 1))
+                       done
+               fi
+
+               j=0
+               while (( j < ${#fs[*]} )); do
+                       cleanup_filesystem "$TESTPOOL" \
+                               "${ctr[i]}/${fs[j]}"
+                       ((j = j + 1))
+               done
+
+               [[ -n ${ctr[i]} ]] && \
+                       cleanup_filesystem "$TESTPOOL" "${ctr[i]}"
+
+               ((i = i - 1))
+       done
+
+       [[ -d ${TEST_BASE_DIR%%/}/testroot$$ ]] && \
+               $RM -rf ${TEST_BASE_DIR%%/}/testroot$$
+}
+
+function verify_all
+{
+       typeset -i i=0
+       typeset -i j=0
+       typeset path
+
+       while (( i < ${#ctr[*]} )); do
+
+               path=$TESTPOOL
+               [[ -n ${ctr[i]} ]] && \
+                       path=$path/${ctr[i]}
+
+               if is_global_zone ; then
+                       j=0
+                       while (( j < ${#vol[*]} )); do
+                               log_must unmounted "$path/${vol[j]}"
+                               ((j = j + 1))
+                       done
+               fi
+
+               j=0
+               while (( j < ${#fs[*]} )); do
+                       log_must unmounted "$path/${fs[j]}"
+                       ((j = j + 1))
+               done
+
+               log_must unmounted "$path"
+
+               ((i = i + 1))
+       done
+
+       return 0
+}
+
+
+log_assert "Verify that 'zfs $unmountall' succeeds as root, " \
+       "and all available ZFS filesystems are unmounted."
+
+log_onexit cleanup_all
+
+log_must setup_all
+
+typeset opt
+for opt in "-a" "-fa"; do
+       export __ZFS_POOL_RESTRICT="$TESTPOOL"
+       log_must $ZFS $mountall
+       unset __ZFS_POOL_RESTRICT
+
+       if [[ $opt == "-fa" ]]; then
+               mntpnt=$(get_prop mountpoint ${TESTPOOL}/${TESTCTR}/${TESTFS})
+               cd $mntpnt
+               log_mustnot $ZFS unmount -a
+       fi
+
+       export __ZFS_POOL_RESTRICT="$TESTPOOL"
+       log_must $ZFS unmount $opt
+       unset __ZFS_POOL_RESTRICT
+
+       if [[ $opt == "-fa" ]]; then
+               cd  /tmp
+       fi
+
+       log_must verify_all
+       log_note "Verify that 'zfs $mountcmd' will display " \
+       "all ZFS filesystems currently mounted."
+       log_must verify_mount_display
+
+done
+
+log_pass "'zfs mount -[f]a' succeeds as root, " \
+       "and all available ZFS filesystems are unmounted."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/Makefile.am
new file mode 100644 (file)
index 0000000..c454697
--- /dev/null
@@ -0,0 +1,9 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_unshare
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_unshare_001_pos.ksh \
+       zfs_unshare_002_pos.ksh \
+       zfs_unshare_003_pos.ksh \
+       zfs_unshare_004_neg.ksh \
+       zfs_unshare_005_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/setup.ksh
new file mode 100755 (executable)
index 0000000..9cfd997
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+# Make sure NFS server is running before testing.
+setup_nfs_server
+
+DISK=${DISKS%% *}
+default_container_volume_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_001_pos.ksh
new file mode 100755 (executable)
index 0000000..033865b
--- /dev/null
@@ -0,0 +1,173 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that 'zfs unshare <filesystem|mountpoint>' unshares a given shared
+# filesystem.
+#
+# STRATEGY:
+# 1. Share filesystems
+# 2. Invoke 'zfs unshare <filesystem|mountpoint>' to unshare zfs file system
+# 3. Verify that the file system is unshared
+# 4. Verify that unsharing an unshared file system fails
+# 5. Verify that "zfs unshare -a" succeeds to unshare all zfs file systems.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset -i i=0
+       while (( i < ${#mntp_fs[*]} )); do
+               log_must $ZFS set sharenfs=off ${mntp_fs[((i+1))]}
+
+               ((i = i + 2))
+       done
+
+       if mounted $TESTPOOL/$TESTCLONE; then
+               log_must $ZFS unmount $TESTDIR2
+       fi
+
+       [[ -d $TESTDIR2 ]] && \
+               log_must $RM -rf $TESTDIR2
+
+       if datasetexists "$TESTPOOL/$TESTCLONE"; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTCLONE
+       fi
+
+       if snapexists "$TESTPOOL/$TESTFS2@snapshot"; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS2@snapshot
+       fi
+
+       if datasetexists "$TESTPOOL/$TESTFS2"; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS2
+       fi
+}
+
+#
+# Main test routine.
+#
+# Given a mountpoint and file system this routine will attempt
+# unshare the filesystem via <filesystem|mountpoint> argument
+# and then verify it has been unshared.
+#
+function test_unshare # <mntp> <filesystem>
+{
+        typeset mntp=$1
+        typeset filesystem=$2
+       typeset prop_value
+
+       prop_value=$(get_prop "sharenfs" $filesystem)
+
+       if [[ $prop_value == "off" ]]; then
+               not_shared $mntp ||
+                       log_must $UNSHARE -F nfs $mntp
+               log_must $ZFS set sharenfs=on $filesystem
+               is_shared $mntp || \
+                       log_fail "'$ZFS set sharenfs=on' fails to make" \
+                               "file system $filesystem shared."
+       fi
+
+       is_shared $mntp || log_must $ZFS share $filesystem
+
+        #
+       # Verify 'zfs unshare <filesystem>' works as well.
+       #
+       log_must $ZFS unshare $filesystem
+       not_shared $mntp || log_fail "'zfs unshare <filesystem>' fails"
+
+       log_must $ZFS share $filesystem
+
+       log_must $ZFS unshare $mntp
+       not_shared $mntp || log_fail "'zfs unshare <mountpoint>' fails"
+
+        log_note "Unsharing an unshared file system fails."
+        log_mustnot $ZFS unshare $filesystem
+       log_mustnot $ZFS unshare $mntp
+}
+
+set -A mntp_fs \
+    "$TESTDIR" "$TESTPOOL/$TESTFS" \
+    "$TESTDIR1" "$TESTPOOL/$TESTCTR/$TESTFS1" \
+    "$TESTDIR2" "$TESTPOOL/$TESTCLONE"
+
+log_assert "Verify that 'zfs unshare [-a] <filesystem|mountpoint>' succeeds as root."
+log_onexit cleanup
+
+log_must $ZFS create $TESTPOOL/$TESTFS2
+log_must $ZFS snapshot $TESTPOOL/$TESTFS2@snapshot
+log_must $ZFS clone $TESTPOOL/$TESTFS2@snapshot $TESTPOOL/$TESTCLONE
+log_must $ZFS set mountpoint=$TESTDIR2 $TESTPOOL/$TESTCLONE
+
+#
+# Invoke 'test_unshare' routine to test 'zfs unshare <filesystem|mountpoint>'.
+#
+typeset -i i=0
+while (( i < ${#mntp_fs[*]} )); do
+       test_unshare ${mntp_fs[i]} ${mntp_fs[((i + 1 ))]}
+
+       ((i = i + 2))
+done
+
+log_note "Verify '$ZFS unshare -a' succeds as root."
+
+i=0
+typeset sharenfs_val
+while (( i < ${#mntp_fs[*]} )); do
+       sharenfs_val=$(get_prop "sharenfs" ${mntp_fs[((i+1))]})
+       if [[ $sharenfs_val == "on" ]]; then
+               not_shared ${mntp_fs[i]} && \
+                       log_must $ZFS share ${mntp_fs[((i+1))]}
+       else
+               log_must $ZFS set sharenfs=on ${mntp_fs[((i+1))]}
+               is_shared ${mntp_fs[i]} || \
+                       log_fail "'$ZFS set sharenfs=on' fails to share filesystem."
+       fi
+
+        ((i = i + 2))
+done
+
+#
+# test 'zfs unshare -a '
+#
+log_must $ZFS unshare -a
+
+#
+# verify all shared filesystems become unshared
+#
+i=0
+while (( i < ${#mntp_fs[*]} )); do
+        not_shared ${mntp_fs[i]} || \
+                log_fail "'$ZFS unshare -a' fails to unshare all shared zfs filesystems."
+
+        ((i = i + 2))
+done
+
+log_pass "'$ZFS unshare [-a] <filesystem|mountpoint>' succeeds as root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_002_pos.ksh
new file mode 100755 (executable)
index 0000000..ea1d079
--- /dev/null
@@ -0,0 +1,177 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that 'zfs unshare [-a] <filesystem|mountpoint>' is aware of legacy share.
+#
+# STRATEGY:
+# 1. Set 'zfs set sharenfs=off'
+# 2. Use 'share' to share given filesystem
+# 3. Verify that 'zfs unshare <filesystem|mountpoint>' is aware of legacy share
+# 4. Verify that 'zfs unshare -a' is aware of legacy share.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset -i i=0
+       while (( i < ${#mntp_fs[*]} )); do
+               is_shared ${mntp_fs[i]} && \
+                       log_must $UNSHARE -F nfs ${mntp_fs[i]}
+
+               ((i = i + 2))
+       done
+
+       if mounted $TESTPOOL/$TESTCLONE; then
+               log_must $ZFS unmount $TESTDIR2
+       fi
+
+       [[ -d $TESTDIR2 ]] && \
+               log_must $RM -rf $TESTDIR2
+
+       if datasetexists "$TESTPOOL/$TESTCLONE"; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTCLONE
+       fi
+
+       if snapexists "$TESTPOOL/$TESTFS2@snapshot"; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS2@snapshot
+       fi
+
+       if datasetexists "$TESTPOOL/$TESTFS2"; then
+               log_must $ZFS destroy -f $TESTPOOL/$TESTFS2
+       fi
+}
+
+#
+# Main test routine.
+#
+# Given a mountpoint and file system this routine will attempt
+# to verify 'zfs unshare' is aware of legacy share.
+#
+function test_legacy_unshare # <mntp> <filesystem>
+{
+        typeset mntp=$1
+        typeset filesystem=$2
+
+       log_must $ZFS set sharenfs=off $filesystem
+       not_shared $mntp || \
+           log_fail "'zfs set sharenfs=off' fails to make ZFS " \
+           "filesystem $filesystem unshared."
+
+       log_must $SHARE -F nfs $mntp
+       is_shared $mntp || \
+           log_fail "'share' command fails to share ZFS file system."
+       #
+       # Verify 'zfs unshare <filesystem>' is aware of legacy share.
+       #
+       log_mustnot $ZFS unshare $filesystem
+       is_shared $mntp || \
+           log_fail "'zfs unshare <filesystem>' fails to be aware" \
+           "of legacy share."
+
+       #
+       # Verify 'zfs unshare <filesystem>' is aware of legacy share.
+       #
+       log_mustnot $ZFS unshare $mntp
+       is_shared $mntp || \
+           log_fail "'zfs unshare <mountpoint>' fails to be aware" \
+           "of legacy share."
+}
+
+
+set -A mntp_fs \
+    "$TESTDIR" "$TESTPOOL/$TESTFS" \
+    "$TESTDIR1" "$TESTPOOL/$TESTCTR/$TESTFS1" \
+    "$TESTDIR2" "$TESTPOOL/$TESTCLONE"
+
+log_assert "Verify that 'zfs unshare [-a]' is aware of legacy share."
+log_onexit cleanup
+
+log_must $ZFS create $TESTPOOL/$TESTFS2
+log_must $ZFS snapshot $TESTPOOL/$TESTFS2@snapshot
+log_must $ZFS clone $TESTPOOL/$TESTFS2@snapshot $TESTPOOL/$TESTCLONE
+log_must $ZFS set mountpoint=$TESTDIR2 $TESTPOOL/$TESTCLONE
+
+#
+# Invoke 'test_legacy_unshare' routine to verify.
+#
+typeset -i i=0
+while (( i < ${#mntp_fs[*]} )); do
+       test_legacy_unshare ${mntp_fs[i]} ${mntp_fs[((i + 1 ))]}
+
+       ((i = i + 2))
+done
+
+
+log_note "Verify '$ZFS unshare -a' is aware of legacy share."
+
+#
+# set the 'sharenfs' property to 'off' for each filesystem
+#
+i=0
+while (( i < ${#mntp_fs[*]} )); do
+        log_must $ZFS set sharenfs=off ${mntp_fs[((i + 1))]}
+        not_shared ${mntp_fs[i]} || \
+                log_fail "'$ZFS set sharenfs=off' unshares file system failed."
+
+        ((i = i + 2))
+done
+
+#
+# Share each of the file systems via legacy share.
+#
+i=0
+while (( i < ${#mntp_fs[*]} )); do
+        $SHARE -F nfs ${mntp_fs[i]}
+        is_shared ${mntp_fs[i]} || \
+                log_fail "'$SHARE' shares ZFS filesystem failed."
+
+        ((i = i + 2))
+done
+
+#
+# Verify that 'zfs unshare -a' is aware of legacy share
+#
+log_must $ZFS unshare -a
+
+#
+# verify ZFS filesystems are still shared
+#
+i=0
+while (( i < ${#mntp_fs[*]} )); do
+        is_shared ${mntp_fs[i]} || \
+            log_fail "'$ZFS  unshare -a' fails to be aware of legacy share."
+
+        ((i = i + 2))
+done
+
+log_pass "'$ZFS unshare [-a]' succeeds to be aware of legacy share."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_003_pos.ksh
new file mode 100755 (executable)
index 0000000..74cc41d
--- /dev/null
@@ -0,0 +1,90 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that a file system and its dependant are unshared when turn off sharenfs
+# property.
+#
+# STRATEGY:
+# 1. Create a file system
+# 2. Set the sharenfs property on the file system
+# 3. Create a snapshot
+# 4. Verify that both are shared
+# 5. Turn off the sharenfs property
+# 6. Verify that both are unshared.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if snapexists $TESTPOOL/$TESTFS@snapshot; then
+               log_must $ZFS destroy $TESTPOOL/$TESTFS@snapshot
+       fi
+
+       log_must $ZFS set sharenfs=off $TESTPOOL/$TESTFS
+}
+
+#
+# Main test routine.
+#
+# Given a mountpoint and file system this routine will attempt
+# unshare the mountpoint and then verify a snapshot of the mounpoint
+# is also unshared.
+#
+function test_snap_unshare # <mntp> <filesystem>
+{
+        typeset mntp=$1
+        typeset filesystem=$2
+       typeset prop_value
+
+       prop_value=$(get_prop "sharenfs" $filesystem)
+
+       if [[ $prop_value == "off" ]]; then
+               is_shared $mntp || $UNSHARE -F nfs $mntp
+               log_must $ZFS set sharenfs=on $filesystem
+       fi
+
+       log_must $ZFS set sharenfs=off $filesystem
+
+       not_shared $mntp || \
+               log_fail "File system $filesystem is shared (set sharenfs)."
+
+       not_shared $mntp@snapshot || \
+           log_fail "Snapshot $mntpt@snapshot is shared (set sharenfs)."
+}
+
+log_assert "Verify that a file system and its dependant are unshared."
+log_onexit cleanup
+
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snapshot
+test_snap_unshare $TESTDIR $TESTPOOL/$TESTFS
+
+log_pass "A file system and its dependant are both unshared as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_004_neg.ksh
new file mode 100755 (executable)
index 0000000..29c5fb9
--- /dev/null
@@ -0,0 +1,84 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that "zfs unshare" issue error message with badly formed parameter.
+#
+# STRATEGY:
+# 1. Define badly formed parameters
+# 2. Invoke 'zfs unshare'
+# 3. Verify that unshare fails and issue error message.
+#
+
+verify_runnable "global"
+
+export NONEXISTFSNAME="nonexistfs50charslong_0123456789012345678901234567"
+export NONEXISTMOUNTPOINT="/nonexistmountpoint_0123456789"
+
+set -A opts "" "$TESTPOOL/$NONEXISTFSNAME" "$NONEEXISTMOUNTPOINT" "-?" "-1" \
+               "-a blah" "$TESTPOOL/$TESTFS $TESTPOOL/$TESTFS1" \
+               "-f $TESTPOOL/$TESTFS $TESTPOOL/$TESTFS1" \
+               "$TESTPOOL/$TESTFS $TESTDIR" "-f $TESTPOOL/$TESTFS $TESTDIR" \
+               "${TESTDIR#/}" "-f ${TESTDIR#/}"
+
+log_assert "Verify that '$ZFS unshare' issue error message with badly formed parameter."
+
+shareval=$(get_prop sharenfs $TESTPOOL/$TESTFS)
+if [[ $shareval == off ]]; then
+       log_must $ZFS set sharenfs=on $TESTPOOL/$TESTFS
+fi
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+        log_mustnot $ZFS unshare ${args[i]}
+
+        ((i = i + 1))
+done
+
+#Testing that unsharing unshared filesystem fails.
+mpt=$(get_prop mountpoint $TESTPOOL/$TESTFS)
+log_must $ZFS unshare $TESTPOOL/$TESTFS
+for opt in "" "-f"; do
+       log_mustnot eval "$ZFS unshare $opt $TESTPOOL/$TESTFS >/dev/null 2>&1"
+       log_mustnot eval "$ZFS unshare $opt $mpt >/dev/null 2>&1"
+done
+
+#Testing zfs unshare fails with legacy share set
+log_must $ZFS set sharenfs=off $TESTPOOL/$TESTFS
+for opt in "" "-f"; do
+       log_mustnot eval "$ZFS unshare $opt $TESTPOOL/$TESTFS >/dev/null 2>&1"
+       log_mustnot eval "$ZFS unshare $opt $mpt >/dev/null 2>&1"
+done
+
+log_pass "'$ZFS unshare' fails as expected with badly-formed parameters."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_unshare/zfs_unshare_005_neg.ksh
new file mode 100755 (executable)
index 0000000..fb582b9
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that unsharing a dataset and mountpoint other than filesystem fails.
+#
+# STRATEGY:
+# 1. Create a volume, dataset other than a ZFS file system
+# 2. Verify that the datasets other than file system are not support by 'zfs unshare'.
+#
+
+verify_runnable "both"
+
+set -A datasets \
+       "$TESTPOOL" "$ZFSROOT/$TESTPOOL" \
+       "$TESTPOOL/$TESTCTR" "$ZFSROOT/$TESTPOOL/$TESTCTR" \
+       "$TESTPOOL/$TESTVOL" "${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL"
+
+log_assert "Verify that unsharing a dataset other than filesystem fails."
+
+typeset -i i=0
+while (( i < ${#datasets[*]} ))
+do
+       log_mustnot $ZFS unshare ${datasets[i]}
+
+       ((i = i + 1))
+done
+
+log_pass "Unsharing datasets other than filesystem failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/Makefile.am
new file mode 100644 (file)
index 0000000..cd7a452
--- /dev/null
@@ -0,0 +1,12 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zfs_upgrade
+dist_pkgdata_SCRIPTS = \
+       zfs_upgrade.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_upgrade_001_pos.ksh \
+       zfs_upgrade_002_pos.ksh \
+       zfs_upgrade_003_pos.ksh \
+       zfs_upgrade_004_pos.ksh \
+       zfs_upgrade_005_pos.ksh \
+       zfs_upgrade_006_neg.ksh \
+       zfs_upgrade_007_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/cleanup.ksh
new file mode 100755 (executable)
index 0000000..e2d0604
--- /dev/null
@@ -0,0 +1,33 @@
+#!/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.
+#
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/setup.ksh
new file mode 100755 (executable)
index 0000000..4c1348a
--- /dev/null
@@ -0,0 +1,42 @@
+#!/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.
+#
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+
+# This should have been set by the .cfg script - verify it's set to something
+# (we check that something later on)
+if [ -z "$ZFS_VERSION" ]
+then
+   log_unresolved "Unable to determine ZFS Filesystem version of this machine"
+else
+   log_note "This machine is running ZFS Filesystem version $ZFS_VERSION"
+fi
+
+default_setup $DISKS
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
new file mode 100644 (file)
index 0000000..b622c94
--- /dev/null
@@ -0,0 +1,179 @@
+#
+# 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/include/libtest.shlib
+
+#
+# For zfs create.
+#
+set -A zpl_create_versions 3 4  5
+set -A spa_create_versions 9 15 24
+
+#
+# For zfs upgrade
+#
+set -A zpl_upgrade_versions 3 4  5
+set -A spa_upgrade_versions 9 15 24
+
+function default_setup_datasets #rootfs
+{
+       typeset rootfs=$1
+       typeset pool=${rootfs%%/*}
+       typeset -i vp=$(get_pool_prop version $pool)
+       typeset -i version
+       typeset -i m
+       typeset -i spa_version
+       typeset -i zpl_version
+
+       for version in $ZFS_ALL_VERSIONS ; do
+               typeset verfs
+               eval verfs=\$ZFS_VERSION_$version
+               typeset current_fs=$rootfs/$verfs
+               typeset current_snap=${current_fs}@snap
+               typeset current_clone=$rootfs/clone$verfs
+
+               (( m=0 ))
+               (( spa_version=0 ))
+               while (( m < ${#zpl_create_versions[@]} )); do
+                       (( zpl_version=${zpl_create_versions[m]} ))
+                       if (( version == zpl_version )); then
+                               (( spa_version=${spa_create_versions[m]} ))
+                               break
+                       fi
+                       (( m+=1 ))
+               done
+               if (( spa_version != 0 )) && (( vp < spa_version )); then
+                       log_mustnot $ZFS create -o version=${version} ${current_fs}
+                       continue
+               fi
+               log_must $ZFS create -o version=${version} ${current_fs}
+               log_must $ZFS snapshot ${current_snap}
+               log_must $ZFS clone ${current_snap} ${current_clone}
+
+               for subversion in $ZFS_ALL_VERSIONS ; do
+                       typeset subverfs
+                       eval subverfs=\$ZFS_VERSION_$subversion
+
+                       (( m=0 ))
+                       (( spa_version=0 ))
+                       while (( m < ${#zpl_create_versions[@]} )); do
+                               (( zpl_version=${zpl_create_versions[m]} ))
+                               if (( subversion == zpl_version )); then
+                                       (( spa_version=${spa_create_versions[m]} ))
+                                       break
+                               fi
+                               (( m+=1 ))
+                       done
+                       if (( spa_version != 0 )) && (( vp < spa_version )); then
+                               log_mustnot $ZFS create -o \
+                               version=${subversion} ${current_fs}/$subverfs
+                       else
+                               log_must $ZFS create -o \
+                               version=${subversion} ${current_fs}/$subverfs
+                       fi
+               done
+       done
+}
+
+function default_cleanup_datasets #rootfs
+{
+       typeset rootfs=$1
+
+       if datasetexists $rootfs ; then
+               log_must $ZFS destroy -Rf $rootfs
+       fi
+
+       if datasetnonexists $rootfs ; then
+               log_must $ZFS create $rootfs
+       fi
+}
+
+function default_check_zfs_upgrade #rootfs
+{
+       typeset rootfs=$1
+       typeset pool=${rootfs%%/*}
+       typeset -i vp=$(get_pool_prop version $pool)
+       typeset -i m
+       typeset -i spa_version
+       typeset -i zpl_version
+       typeset newv
+       typeset -i df_ret
+
+       $DF -F zfs / > /dev/null 2>&1
+       df_ret=$?
+
+       for newv in "" $ZFS_VERSION; do
+               default_setup_datasets $rootfs
+               if [[ -n $newv ]]; then
+                       opt="-V $newv"
+               else
+                       newv=$ZFS_VERSION
+               fi
+
+               (( m=0 ))
+               (( spa_version=0 ))
+               while (( m < ${#zpl_upgrade_versions[@]} )); do
+                       (( zpl_version=${zpl_upgrade_versions[m]} ))
+                       if (( newv == zpl_version )); then
+                               (( spa_version=${spa_upgrade_versions[m]} ))
+                               break
+                       fi
+                       (( m+=1 ))
+               done
+
+               if (( df_ret != 0 )); then
+                       if (( spa_version != 0 )) && (( vp < spa_version )); then
+                               log_mustnot eval '$ZFS upgrade $opt -a > /dev/null 2>&1'
+                               log_must eval '$ZPOOL upgrade $pool > /dev/null 2>&1'
+                               vp=$(get_pool_prop version $pool)
+                       fi
+
+                       log_must eval '$ZFS upgrade $opt -a > /dev/null 2>&1'
+
+                       for fs in $($ZFS list -rH -t filesystem -o name $rootfs) ; do
+                               log_must check_fs_version $fs $newv
+                       done
+               fi
+
+               default_cleanup_datasets $rootfs
+       done
+}
+
+function check_fs_version #filesystem version
+{
+       typeset fs=$1
+       typeset -i version=${2:-$ZFS_VERSION}
+
+       if [[ -z $fs ]]; then
+               log_fail "No filesystem specified."
+       fi
+
+       typeset -i curv=$(get_prop version $fs)
+       if (( curv != version )); then
+               return 1
+       fi
+       return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_001_pos.ksh
new file mode 100755 (executable)
index 0000000..32e76ff
--- /dev/null
@@ -0,0 +1,136 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+#      Executing 'zfs upgrade' command succeeds, it should report
+#      the current system version and list all old-version filesystems.
+#      If no old-version filesystems be founded, it prints out
+#      "All filesystems are formatted with the current version."
+#
+# STRATEGY:
+# 1. Prepare a set of datasets which contain old-version and current version.
+# 2. Execute 'zfs upgrade', verify return 0, and it prints out
+#      the current system version and list all old-version filesystems.
+# 3. Remove all old-version filesystems, then execute 'zfs upgrade' again,
+#      verify return 0, and get the expected message.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $rootfs ; then
+               log_must $ZFS destroy -Rf $rootfs
+       fi
+       log_must $ZFS create $rootfs
+
+       for file in $output $oldoutput ; do
+               if [[ -f $file ]]; then
+                       log_must $RM -f $file
+               fi
+       done
+}
+
+log_assert "Executing 'zfs upgrade' command succeeds."
+log_onexit cleanup
+
+rootfs=$TESTPOOL/$TESTFS
+typeset output=/tmp/zfs-versions.$$
+typeset oldoutput=/tmp/zfs-versions-old.$$
+typeset expect_str1="This system is currently running ZFS filesystem version"
+typeset expect_str2="All filesystems are formatted with the current version"
+typeset expect_str3="The following filesystems are out of date, and can be upgraded"
+typeset -i COUNT OLDCOUNT
+
+$ZFS upgrade | $NAWK '$1 ~ "^[0-9]+$" {print $2}'> $oldoutput
+OLDCOUNT=$( $WC -l $oldoutput | $AWK '{print $1}' )
+
+old_datasets=""
+for version in $ZFS_ALL_VERSIONS ; do
+       typeset verfs
+       eval verfs=\$ZFS_VERSION_$version
+       typeset current_fs=$rootfs/$verfs
+       typeset current_snap=${current_fs}@snap
+       typeset current_clone=$rootfs/clone$verfs
+       log_must $ZFS create -o version=${version} ${current_fs}
+       log_must $ZFS snapshot ${current_snap}
+       log_must $ZFS clone ${current_snap} ${current_clone}
+
+       if (( version != $ZFS_VERSION )); then
+               old_datasets="$old_datasets ${current_fs} ${current_clone}"
+       fi
+done
+
+if is_global_zone; then
+       log_must $ZFS create -V 100m $rootfs/$TESTVOL
+fi
+
+log_must eval '$ZFS upgrade > $output 2>&1'
+
+# we also check that the usage message contains at least a description
+# of the current ZFS version.
+log_must eval '$GREP "${expect_str1} $ZFS_VERSION" $output > /dev/null 2>&1'
+$ZFS upgrade | $NAWK '$1 ~ "^[0-9]+$" {print $2}'> $output
+COUNT=$( $WC -l $output | $AWK '{print $1}' )
+
+typeset -i i=0
+for fs in ${old_datasets}; do
+       log_must $GREP "^$fs$" $output
+       (( i = i + 1 ))
+done
+
+if (( i != COUNT - OLDCOUNT )); then
+       $CAT $output
+       log_fail "More old-version filesystems print out than expect."
+fi
+
+for fs in $old_datasets ; do
+       if datasetexists $fs ; then
+               log_must $ZFS destroy -Rf $fs
+       fi
+done
+
+log_must eval '$ZFS upgrade > $output 2>&1'
+log_must eval '$GREP "${expect_str1} $ZFS_VERSION" $output > /dev/null 2>&1'
+if (( OLDCOUNT == 0 )); then
+       log_must eval '$GREP "${expect_str2}" $output > /dev/null 2>&1'
+else
+       log_must eval '$GREP "${expect_str3}" $output > /dev/null 2>&1'
+fi
+$ZFS upgrade | $NAWK '$1 ~ "^[0-9]+$" {print $2}'> $output
+COUNT=$( $WC -l $output | $AWK '{print $1}' )
+
+if (( COUNT != OLDCOUNT )); then
+       $CAT $output
+       log_fail "Unexpect old-version filesystems print out."
+fi
+
+log_pass "Executing 'zfs upgrade' command succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_002_pos.ksh
new file mode 100755 (executable)
index 0000000..2de2ed3
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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.
+#
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+#      Executing 'zfs upgrade -v ' command succeeds, it should
+#      show the info of available versions.
+#
+# STRATEGY:
+# 1. Execute 'zfs upgrade -v', verify return value is 0.
+# 2, Verify all the available versions info are printed out.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if [[ -f $output ]]; then
+               log_must $RM -f $output
+       fi
+}
+
+log_assert "Executing 'zfs upgrade -v' command succeeds."
+log_onexit cleanup
+
+typeset output=/tmp/zfs-versions.$$
+typeset expect_str1="Initial ZFS filesystem version"
+typeset expect_str2="Enhanced directory entries"
+
+log_must eval '$ZFS upgrade -v > /dev/null 2>&1'
+
+$ZFS upgrade -v | $NAWK '$1 ~ "^[0-9]+$" {print $0}'> $output
+log_must eval '$GREP "${expect_str1}" $output > /dev/null 2>&1'
+log_must eval '$GREP "${expect_str2}" $output > /dev/null 2>&1'
+
+log_pass "Executing 'zfs upgrade -v' command succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_003_pos.ksh
new file mode 100755 (executable)
index 0000000..24fac02
--- /dev/null
@@ -0,0 +1,100 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+#      Executing 'zfs upgrade [-V version] filesystem' command succeeds,
+#      it could upgrade a filesystem to specific version or current version.
+#
+# STRATEGY:
+# 1. Prepare a set of datasets which contain old-version and current version.
+# 2. Execute 'zfs upgrade [-V version] filesystem', verify return 0,
+# 3. Verify the filesystem be updated as expected.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $rootfs ; then
+               log_must $ZFS destroy -Rf $rootfs
+       fi
+       log_must $ZFS create $rootfs
+}
+
+function setup_datasets
+{
+       datasets=""
+       for version in $ZFS_ALL_VERSIONS ; do
+               typeset verfs
+               eval verfs=\$ZFS_VERSION_$version
+               typeset current_fs=$rootfs/$verfs
+               typeset current_snap=${current_fs}@snap
+               typeset current_clone=$rootfs/clone$verfs
+               log_must $ZFS create -o version=${version} ${current_fs}
+               log_must $ZFS snapshot ${current_snap}
+               log_must $ZFS clone ${current_snap} ${current_clone}
+               datasets="$datasets ${current_fs} ${current_clone}"
+       done
+}
+
+log_assert "Executing 'zfs upgrade [-V version] filesystem' command succeeds."
+log_onexit cleanup
+
+rootfs=$TESTPOOL/$TESTFS
+typeset datasets
+
+typeset newv
+for newv in "" "current" $ZFS_ALL_VERSIONS; do
+       setup_datasets
+       for fs in $datasets ; do
+               typeset -i oldv=$(get_prop version $fs)
+
+               if [[ -n $newv ]]; then
+                       opt="-V $newv"
+                       if [[ $newv == current ]]; then
+                               newv=$ZFS_VERSION
+                       fi
+               else
+                       newv=$ZFS_VERSION
+               fi
+
+               if (( newv >= oldv )); then
+                       log_must eval '$ZFS upgrade $opt $fs > /dev/null 2>&1'
+                       log_must check_fs_version $fs $newv
+               else
+                       log_mustnot eval '$ZFS upgrade $opt $fs > /dev/null 2>&1'
+                       log_must check_fs_version $fs $oldv
+               fi
+       done
+       cleanup
+done
+
+log_pass "Executing 'zfs upgrade [-V version] filesystem' command succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_004_pos.ksh
new file mode 100755 (executable)
index 0000000..47cff6e
--- /dev/null
@@ -0,0 +1,104 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+#      Executing 'zfs upgrade -r [-V version] filesystem' command succeeds,
+#      it upgrade filesystem recursively to specific or current version.
+#
+# STRATEGY:
+# 1. Prepare a set of datasets which contain old-version and current version.
+# 2. Execute 'zfs upgrade -r [-V version] filesystem', verify return 0,
+# 3. Verify the filesystem be updated recursively as expected.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $rootfs ; then
+               log_must $ZFS destroy -Rf $rootfs
+       fi
+       log_must $ZFS create $rootfs
+}
+
+function setup_datasets
+{
+       datasets=""
+       for version in $ZFS_ALL_VERSIONS ; do
+               typeset verfs
+               eval verfs=\$ZFS_VERSION_$version
+               typeset current_fs=$rootfs/$verfs
+               typeset current_snap=${current_fs}@snap
+               typeset current_clone=$rootfs/clone$verfs
+               log_must $ZFS create -o version=${version} ${current_fs}
+               log_must $ZFS snapshot ${current_snap}
+               log_must $ZFS clone ${current_snap} ${current_clone}
+
+               for subversion in $ZFS_ALL_VERSIONS ; do
+                       typeset subverfs
+                       eval subverfs=\$ZFS_VERSION_$subversion
+                       log_must $ZFS create -o version=${subversion} \
+                               ${current_fs}/$subverfs
+               done
+               datasets="$datasets ${current_fs}"
+       done
+}
+
+log_assert "Executing 'zfs upgrade -r [-V version] filesystem' command succeeds."
+log_onexit cleanup
+
+rootfs=$TESTPOOL/$TESTFS
+
+typeset datasets
+
+typeset newv
+for newv in "" "current" $ZFS_VERSION; do
+       setup_datasets
+       for topfs in $datasets ; do
+               if [[ -n $newv ]]; then
+                       opt="-V $newv"
+                       if [[ $newv == current ]]; then
+                               newv=$ZFS_VERSION
+                       fi
+               else
+                       newv=$ZFS_VERSION
+               fi
+
+               log_must eval '$ZFS upgrade -r $opt $topfs > /dev/null 2>&1'
+
+               for fs in $($ZFS list -rH -t filesystem -o name $topfs) ; do
+                       log_must check_fs_version $fs $newv
+               done
+       done
+       cleanup
+done
+
+log_pass "Executing 'zfs upgrade -r [-V version] filesystem' command succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_005_pos.ksh
new file mode 100755 (executable)
index 0000000..764727c
--- /dev/null
@@ -0,0 +1,104 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+#      Executing 'zfs upgrade [-V version] -a' command succeeds,
+#      it upgrade all filesystems to specific or current version.
+#
+# STRATEGY:
+# 1. Prepare a set of datasets which contain old-version and current version.
+# 2. Execute 'zfs upgrade [-V version] -a', verify return 0,
+# 3. Verify all the filesystems be updated as expected.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $rootfs ; then
+               log_must $ZFS destroy -Rf $rootfs
+       fi
+       log_must $ZFS create $rootfs
+}
+
+function setup_datasets
+{
+       datasets=""
+       for version in $ZFS_ALL_VERSIONS ; do
+               typeset verfs
+               eval verfs=\$ZFS_VERSION_$version
+               typeset current_fs=$rootfs/$verfs
+               typeset current_snap=${current_fs}@snap
+               typeset current_clone=$rootfs/clone$verfs
+               log_must $ZFS create -o version=${version} ${current_fs}
+               log_must $ZFS snapshot ${current_snap}
+               log_must $ZFS clone ${current_snap} ${current_clone}
+
+               for subversion in $ZFS_ALL_VERSIONS ; do
+                       typeset subverfs
+                       eval subverfs=\$ZFS_VERSION_$subversion
+                       log_must $ZFS create -o version=${subversion} \
+                               ${current_fs}/$subverfs
+               done
+               datasets="$datasets ${current_fs}"
+       done
+}
+
+log_assert "Executing 'zfs upgrade [-V version] -a' command succeeds."
+log_onexit cleanup
+
+rootfs=$TESTPOOL/$TESTFS
+
+typeset datasets
+
+typeset newv
+for newv in "" "current" $ZFS_VERSION; do
+       setup_datasets
+       if [[ -n $newv ]]; then
+               opt="-V $newv"
+               if [[ $newv == current ]]; then
+                       newv=$ZFS_VERSION
+               fi
+       else
+               newv=$ZFS_VERSION
+       fi
+
+       export __ZFS_POOL_RESTRICT="$TESTPOOL"
+       log_must $ZFS upgrade $opt -a
+       unset __ZFS_POOL_RESTRICT
+
+       for fs in $($ZFS list -rH -t filesystem -o name $rootfs) ; do
+               log_must check_fs_version $fs $newv
+       done
+       cleanup
+done
+
+log_pass "Executing 'zfs upgrade [-V version] -a' command succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_006_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_006_neg.ksh
new file mode 100755 (executable)
index 0000000..6cd3bb4
--- /dev/null
@@ -0,0 +1,54 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# Verify that invalid upgrade parameters and options are caught.
+#
+# STRATEGY:
+# 1. Create a ZFS file system.
+# 2. For each option in the list, try 'zfs upgrade'.
+# 3. Verify that the operation fails as expected.
+#
+
+verify_runnable "both"
+
+set -A args "" "-?" "-A" "-R" "-b" "-c" "-d" "--invalid" \
+    "-V" "-V $TESTPOOL/$TESTFS" "-V $TESTPOOL $TESTPOOL/$TESTFS"
+
+log_assert "Badly-formed 'zfs upgrade' should return an error."
+
+typeset -i i=1
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZFS upgrade ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Badly-formed 'zfs upgrade' fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/zfs_upgrade_007_neg.ksh
new file mode 100755 (executable)
index 0000000..cdc7e41
--- /dev/null
@@ -0,0 +1,55 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# Verify that version should only by '1' '2' or current version,
+# non-digit input are invalid.
+#
+# STRATEGY:
+# 1. For each invalid value of version in the list, try 'zfs upgrade -V version'.
+# 2. Verify that the operation fails as expected.
+#
+
+verify_runnable "both"
+
+set -A args \
+       "0" "0.000" "0.5" "-1.234" "-1" "1234b" "5678x"
+
+log_assert "Set invalid value or non-digit version should fail as expected."
+
+typeset -i i=0
+while (( i < ${#args[*]} ))
+do
+       log_mustnot $ZFS upgrade -V ${args[i]} $TESTPOOL/$TESTFS
+       ((i = i + 1))
+done
+
+log_pass "Set invalid value or non-digit version fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/Makefile.am
new file mode 100644 (file)
index 0000000..2d0046c
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_001_neg.ksh \
+       zpool_002_pos.ksh \
+       zpool_003_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_001_neg.ksh
new file mode 100755 (executable)
index 0000000..7b37644
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# A badly formed sub-command passed to zpool(1) should
+# return an error.
+#
+# STRATEGY:
+# 1. Create an array containg each zpool sub-command name.
+# 2. For each element, execute the sub-command.
+# 3. Verify it returns an error.
+#
+
+verify_runnable "both"
+
+
+set -A args "" "create" "add" "destroy" "import fakepool" \
+    "export fakepool" "create fakepool" "add fakepool" \
+    "create mirror" "create raidz" "create raidz1" \
+    "create mirror fakepool" "create raidz fakepool" \
+    "create raidz1 fakepool" "create raidz2 fakepool" \
+    "create fakepool mirror" "create fakepool raidz" \
+    "create fakepool raidz1" "create fakepool raidz2" \
+    "add fakepool mirror" "add fakepool raidz" \
+    "add fakepool raidz1" "add fakepool raidz2" \
+    "add mirror fakepool" "add raidz fakepool" \
+    "add raidz1 fakepool" "add raidz2 fakepool" \
+    "setvprop" "blah blah" "-%" "--" "--?" "-*" "-="
+
+log_assert "Execute zpool sub-command without proper parameters."
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL ${args[i]}
+
+       ((i = i + 1))
+done
+
+log_pass "Badly formed zpool sub-commands fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_002_pos.ksh
new file mode 100755 (executable)
index 0000000..d4265af
--- /dev/null
@@ -0,0 +1,103 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# With ZFS_ABORT set, all zpool commands should be able to abort and generate a core file.
+#
+# STRATEGY:
+# 1. Create an array of zpool command
+# 2. Execute each command in the array
+# 3. Verify the command aborts and generate a core file
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       unset ZFS_ABORT
+
+       if [[ -d $corepath ]]; then
+               $RM -rf $corepath
+       fi
+
+       if poolexists $pool; then
+               log_must $ZPOOL destroy -f $pool
+       fi
+}
+
+log_assert "With ZFS_ABORT set, all zpool commands can abort and generate a core file."
+log_onexit cleanup
+
+#preparation work for testing
+corepath=$TESTDIR/core
+if [[ -d $corepath ]]; then
+       $RM -rf $corepath
+fi
+$MKDIR $corepath
+
+pool=pool.$$
+vdev1=$TESTDIR/file1
+vdev2=$TESTDIR/file2
+vdev3=$TESTDIR/file3
+for vdev in $vdev1 $vdev2 $vdev3; do
+       $MKFILE 64m $vdev
+done
+
+set -A cmds "create $pool mirror $vdev1 $vdev2" "list $pool" "iostat $pool" \
+       "status $pool" "upgrade $pool" "get delegation $pool" "set delegation=off $pool" \
+       "export $pool" "import -d $TESTDIR $pool" "offline $pool $vdev1" \
+       "online $pool $vdev1" "clear $pool" "detach $pool $vdev2" \
+       "attach $pool $vdev1 $vdev2" "replace $pool $vdev2 $vdev3" \
+       "scrub $pool" "destroy -f $pool"
+
+set -A badparams "" "create" "destroy" "add" "remove" "list *" "iostat" "status" \
+               "online" "offline" "clear" "attach" "detach" "replace" "scrub" \
+               "import" "export" "upgrade" "history -?" "get" "set"
+
+if is_linux; then
+       ulimit -c unlimited
+       echo "$corepath/core.zpool" >/proc/sys/kernel/core_pattern
+       echo 0 >/proc/sys/kernel/core_uses_pid
+else
+       $COREADM -p ${corepath}/core.%f
+fi
+
+export ZFS_ABORT=yes
+
+for subcmd in "${cmds[@]}" "${badparams[@]}"; do
+       corefile=${corepath}/core.zpool
+       $ZPOOL $subcmd >/dev/null 2>&1
+       ls -l $corepath >>/tmp/CORE
+       if [[ ! -e $corefile ]]; then
+               log_fail "$ZPOOL $subcmd cannot generate core file  with ZFS_ABORT set."
+       fi
+       $RM -f $corefile
+done
+
+log_pass "With ZFS_ABORT set, zpool command can abort and generate core file as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool/zpool_003_pos.ksh
new file mode 100755 (executable)
index 0000000..7012eaf
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify debugging features of zpool such as ABORT and freeze/unfreeze
+#      should run successfully.
+#
+# STRATEGY:
+# 1. Create an array containg each zpool options.
+# 2. For each element, execute the zpool command.
+# 3. Verify it run successfully.
+#
+
+verify_runnable "both"
+
+log_assert "Debugging features of zpool should succeed."
+
+log_must $ZPOOL -? > /dev/null 2>&1
+
+if is_global_zone ; then
+       log_must $ZPOOL freeze $TESTPOOL
+else
+       log_mustnot $ZPOOL freeze $TESTPOOL
+       log_mustnot $ZPOOL freeze ${TESTPOOL%%/*}
+fi
+
+log_mustnot $ZPOOL freeze fakepool
+
+# Remove corefile possibly left by previous failing run of this test.
+[[ -f core ]] && log_must rm -f core
+
+if is_linux; then
+        ulimit -c unlimited
+        echo "core" >/proc/sys/kernel/core_pattern
+        echo 0 >/proc/sys/kernel/core_uses_pid
+fi
+
+ZFS_ABORT=1; export ZFS_ABORT
+$ZPOOL > /dev/null 2>&1
+unset ZFS_ABORT
+
+[[ -f core ]] || log_fail "$ZPOOL did not dump core by request."
+[[ -f core ]] && log_must rm -f core
+
+log_pass "Debugging features of zpool succeed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/Makefile.am
new file mode 100644 (file)
index 0000000..fef9343
--- /dev/null
@@ -0,0 +1,15 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_add
+dist_pkgdata_SCRIPTS = \
+       zpool_add.cfg \
+       zpool_add.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_add_001_pos.ksh \
+       zpool_add_002_pos.ksh \
+       zpool_add_003_pos.ksh \
+       zpool_add_004_pos.ksh \
+       zpool_add_005_pos.ksh \
+       zpool_add_006_pos.ksh \
+       zpool_add_007_neg.ksh \
+       zpool_add_008_neg.ksh \
+       zpool_add_009_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/cleanup.ksh
new file mode 100755 (executable)
index 0000000..48a6bc3
--- /dev/null
@@ -0,0 +1,42 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+        delete_partitions
+fi
+
+cleanup_devices $DISKS
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/setup.ksh
new file mode 100755 (executable)
index 0000000..131876f
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+verify_runnable "global"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+disk1=${DISKS%% *}
+if is_mpath_device $disk1; then
+        delete_partitions
+fi
+
+if [[ -n $DISK ]]; then
+       #
+        # Use 'zpool create' to clean up the infomation in
+        # in the given disk to avoid slice overlapping.
+        #
+       cleanup_devices $DISK
+
+        partition_disk $SIZE $DISK 7
+else
+       for disk in `$ECHO $DISKSARRAY`; do
+               cleanup_devices $disk
+               partition_disk $SIZE $disk 7
+       done
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.cfg
new file mode 100644 (file)
index 0000000..f12a883
--- /dev/null
@@ -0,0 +1,94 @@
+#
+# 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) 2012, 2014 by Delphix. All rights reserved.
+#
+
+export DISK_ARRAY_NUM=0
+export DISK_ARRAY_LIMIT=4
+export DISKSARRAY=""
+
+#
+# Variables for zpool_add_006
+#
+export VDEVS_NUM=32
+
+function set_disks
+{
+        set -A disk_array $(find_disks $DISKS)
+
+        if (( ${#disk_array[*]} <= 1 )); then
+                export DISK=${DISKS%% *}
+        else
+                export DISK=""
+                typeset -i i=0
+                while (( i < ${#disk_array[*]} )); do
+                        export DISK${i}="${disk_array[$i]}"
+                        DISKSARRAY="$DISKSARRAY ${disk_array[$i]}"
+                        (( i = i + 1 ))
+                        (( i>$DISK_ARRAY_LIMIT )) && break
+                done
+                export DISK_ARRAY_NUM=$i
+                export DISKSARRAY
+        fi
+
+       if (( $DISK_ARRAY_NUM == 0 )); then
+               export disk=$DISK
+       else
+               export disk=$DISK0
+       fi
+
+}
+
+set_disks
+
+export FILESIZE="100m"
+export FILESIZE1="150m"
+export SIZE="150m"
+export SIZE1="250m"
+
+if is_linux; then
+       set_device_dir
+       set_slice_prefix
+       export SLICE0=1
+       export SLICE1=2
+       export SLICE3=4
+       export SLICE4=5
+       export SLICE5=6
+       export SLICE6=7
+else
+       export DEV_DSKDIR="/dev"
+       export SLICE_PREFIX="s"
+       export SLICE0=0
+       export SLICE1=1
+       export SLICE3=3
+       export SLICE4=4
+       export SLICE5=5
+       export SLICE6=6
+fi
+
+export VOLSIZE=84m
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add.kshlib
new file mode 100644 (file)
index 0000000..71d3027
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# 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, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.cfg
+
+#
+# Find the storage device in /etc/vfstab
+#
+function find_vfstab_dev
+{
+       typeset vfstab="/etc/vfstab"
+       typeset tmpfile="/tmp/vfstab.tmp"
+       typeset vfstabdev
+       typeset vfstabdevs=""
+       typeset line
+
+       $CAT $vfstab | $GREP "^${DEV_DSKDIR}" >$tmpfile
+       while read -r line
+       do
+               vfstabdev=`$ECHO "$line" | $AWK '{print $1}'`
+               vfstabdev=${vfstabdev%%:}
+               vfstabdevs="$vfstabdev $vfstabdevs"
+       done <$tmpfile
+
+       $RM -f $tmpfile
+       $ECHO $vfstabdevs
+}
+
+#
+# Find the storage device in /etc/mnttab
+#
+function find_mnttab_dev
+{
+       typeset mnttab="/etc/mnttab"
+       typeset tmpfile="/tmp/mnttab.tmp"
+       typeset mnttabdev
+       typeset mnttabdevs=""
+       typeset line
+
+       $CAT $mnttab | $GREP "^${DEV_DSKDIR}" >$tmpfile
+       while read -r line
+       do
+               mnttabdev=`$ECHO "$line" | $AWK '{print $1}'`
+               mnttabdev=${mnttabdev%%:}
+               mnttabdevs="$mnttabdev $mnttabdevs"
+       done <$tmpfile
+
+       $RM -f $tmpfile
+       $ECHO $mnttabdevs
+}
+
+#
+# Save the systme current dump device configuration
+#
+function save_dump_dev
+{
+
+       typeset dumpdev
+       typeset fnd="Dump device"
+
+       dumpdev=`$DUMPADM | $GREP "$fnd" | $CUT -f2 -d : | \
+               $AWK '{print $1}'`
+       $ECHO $dumpdev
+}
+
+#
+# Common cleanup routine for partitions used in testing
+#
+function partition_cleanup
+{
+
+        if [[ -n $DISK ]]; then
+                partition_disk $SIZE $DISK 7
+        else
+                typeset disk=""
+                for disk in $DISK0 $DISK1; do
+                        partition_disk $SIZE $disk 7
+                done
+        fi
+
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_001_pos.ksh
new file mode 100755 (executable)
index 0000000..1f179fd
--- /dev/null
@@ -0,0 +1,142 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+#      'zpool add <pool> <vdev> ...' can successfully add the specified
+# devices to the given pool
+#
+# STRATEGY:
+#      1. Create a storage pool
+#      2. Add spare devices to the pool
+#      3. Verify the devices are added to the pool successfully
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL && \
+               destroy_pool $TESTPOOL
+
+       partition_cleanup
+}
+
+log_assert "'zpool add <pool> <vdev> ...' can add devices to the pool."
+
+log_onexit cleanup
+
+set -A keywords "" "mirror" "raidz" "raidz1" "spare"
+
+case $DISK_ARRAY_NUM in
+0|1)
+       pooldevs="${disk}${SLICE_PREFIX}${SLICE0} \
+               ${DEV_DSKDIR}/${disk}${SLICE_PREFIX}${SLICE0} \
+               \"${disk}${SLICE_PREFIX}${SLICE0} \
+               ${disk}${SLICE_PREFIX}${SLICE1}\""
+       mirrordevs="\"${DEV_DSKDIR}/${disk}${SLICE_PREFIX}${SLICE0} \
+               ${disk}${SLICE_PREFIX}${SLICE1}\""
+       raidzdevs="\"${DEV_DSKDIR}/${disk}${SLICE_PREFIX}${SLICE0} \
+               ${disk}${SLICE_PREFIX}${SLICE1}\""
+
+       ;;
+2|*)
+       pooldevs="${DISK0}${SLICE_PREFIX}${SLICE0} \
+               \"${DEV_DSKDIR}/${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK1}${SLICE_PREFIX}${SLICE0}\" \
+               \"${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK0}${SLICE_PREFIX}${SLICE1} \
+               ${DISK1}${SLICE_PREFIX}${SLICE1}\"\
+               \"${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK1}${SLICE_PREFIX}${SLICE0} \
+               ${DISK0}${SLICE_PREFIX}${SLICE1}\
+               ${DISK1}${SLICE_PREFIX}${SLICE1}\""
+       mirrordevs="\"${DEV_DSKDIR}/${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK1}${SLICE_PREFIX}${SLICE0}\""
+       raidzdevs="\"${DEV_DSKDIR}/${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK1}${SLICE_PREFIX}${SLICE0}\""
+
+       ;;
+esac
+
+typeset -i i=0
+typeset vdev
+eval set -A poolarray $pooldevs
+eval set -A mirrorarray $mirrordevs
+eval set -A raidzarray $raidzdevs
+
+while (( $i < ${#keywords[*]} )); do
+       echo "I=$i keyword=${keywords[i]}" >>/tmp/LOG
+
+        case ${keywords[i]} in
+        ""|spare)
+               for vdev in "${poolarray[@]}"; do
+                       create_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE6}"
+                       log_must poolexists "$TESTPOOL"
+                       log_must $ZPOOL add -f "$TESTPOOL" ${keywords[i]} $vdev
+                       log_must vdevs_in_pool "$TESTPOOL" "$vdev"
+                       destroy_pool "$TESTPOOL"
+               done
+
+               ;;
+        mirror)
+               for vdev in "${mirrorarray[@]}"; do
+                       create_pool "$TESTPOOL" "${keywords[i]}" \
+                               "${disk}${SLICE_PREFIX}${SLICE4}" \
+                               "${disk}${SLICE_PREFIX}${SLICE5}"
+                       log_must poolexists "$TESTPOOL"
+                       log_must $ZPOOL add "$TESTPOOL" ${keywords[i]} $vdev
+                       log_must vdevs_in_pool "$TESTPOOL" "$vdev"
+                       destroy_pool "$TESTPOOL"
+               done
+
+               ;;
+        raidz|raidz1)
+               for vdev in "${raidzarray[@]}"; do
+                       create_pool "$TESTPOOL" "${keywords[i]}" \
+                               "${disk}${SLICE_PREFIX}${SLICE4}" \
+                               "${disk}${SLICE_PREFIX}${SLICE5}"
+                       log_must poolexists "$TESTPOOL"
+                       log_must $ZPOOL add "$TESTPOOL" ${keywords[i]} $vdev
+                       log_must vdevs_in_pool "$TESTPOOL" "$vdev"
+                       destroy_pool "$TESTPOOL"
+               done
+
+               ;;
+        esac
+
+        (( i = i+1 ))
+done
+
+log_pass "'zpool add <pool> <vdev> ...' executes successfully"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_002_pos.ksh
new file mode 100755 (executable)
index 0000000..a76bc9e
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2014 by Delphix. All rights reserved.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+#      'zpool add -f <pool> <vdev> ...' can successfully add the specified
+# devices to given pool in some cases.
+#
+# STRATEGY:
+#      1. Create a mirrored pool
+#      2. Without -f option to add 1-way device the mirrored pool will fail
+#      3. Use -f to override the errors to add 1-way device to the mirrored
+#      pool
+#      4. Verify the device is added successfully
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        poolexists $TESTPOOL && \
+                destroy_pool $TESTPOOL
+
+       partition_cleanup
+}
+
+log_assert "'zpool add -f <pool> <vdev> ...' can successfully add" \
+       "devices to the pool in some cases."
+
+log_onexit cleanup
+
+create_pool "$TESTPOOL" mirror "${disk}${SLICE_PREFIX}${SLICE0}" \
+       "${disk}${SLICE_PREFIX}${SLICE1}"
+log_must poolexists "$TESTPOOL"
+
+log_mustnot $ZPOOL add "$TESTPOOL" ${disk}${SLICE_PREFIX}${SLICE3}
+log_mustnot vdevs_in_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE3}"
+
+log_must $ZPOOL add -f "$TESTPOOL" ${disk}${SLICE_PREFIX}${SLICE3}
+log_must vdevs_in_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE3}"
+
+log_pass "'zpool add -f <pool> <vdev> ...' executes successfully."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_003_pos.ksh
new file mode 100755 (executable)
index 0000000..a422e51
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+#      'zpool add -n <pool> <vdev> ...' can display the configuration without
+# adding the specified devices to given pool
+#
+# STRATEGY:
+#      1. Create a storage pool
+#      2. Use -n to add a device to the pool
+#      3. Verify the device is not added actually
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        poolexists $TESTPOOL && \
+                destroy_pool $TESTPOOL
+
+       partition_cleanup
+
+       [[ -e $tmpfile ]] && \
+               log_must $RM -f $tmpfile
+}
+
+log_assert "'zpool add -n <pool> <vdev> ...' can display the configuration" \
+       "without actually adding devices to the pool."
+
+log_onexit cleanup
+
+tmpfile="/var/tmp/zpool_add_003.tmp$$"
+
+create_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE0}"
+log_must poolexists "$TESTPOOL"
+
+$ZPOOL add -n "$TESTPOOL" ${disk}${SLICE_PREFIX}${SLICE1} > $tmpfile
+
+log_mustnot vdevs_in_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE1}"
+
+str="would update '$TESTPOOL' to the following configuration:"
+$CAT $tmpfile | $GREP "$str" >/dev/null 2>&1
+(( $? != 0 )) && \
+        log_fail "'zpool add -n <pool> <vdev> ...' is executed as unexpected"
+
+log_pass "'zpool add -n <pool> <vdev> ...'executes successfully."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_004_pos.ksh
new file mode 100755 (executable)
index 0000000..a893c31
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+#      'zpool add <pool> <vdev> ...' can successfully add a zfs volume
+# to the given pool
+#
+# STRATEGY:
+#      1. Create a storage pool and a zfs volume
+#      2. Add the volume to the pool
+#      3. Verify the devices are added to the pool successfully
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL && \
+               destroy_pool "$TESTPOOL"
+
+       datasetexists $TESTPOOL1/$TESTVOL && \
+               log_must $ZFS destroy -f $TESTPOOL1/$TESTVOL
+       poolexists $TESTPOOL1 && \
+               destroy_pool "$TESTPOOL1"
+
+       partition_cleanup
+
+}
+
+log_assert "'zpool add <pool> <vdev> ...' can add zfs volume to the pool."
+
+log_onexit cleanup
+
+create_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE0}"
+log_must poolexists "$TESTPOOL"
+
+create_pool "$TESTPOOL1" "${disk}${SLICE_PREFIX}${SLICE1}"
+log_must poolexists "$TESTPOOL1"
+log_must $ZFS create -V $VOLSIZE $TESTPOOL1/$TESTVOL
+block_device_wait
+
+log_must $ZPOOL add "$TESTPOOL" $ZVOL_DEVDIR/$TESTPOOL1/$TESTVOL
+
+log_must vdevs_in_pool "$TESTPOOL" "$ZVOL_DEVDIR/$TESTPOOL1/$TESTVOL"
+
+log_pass "'zpool add <pool> <vdev> ...' adds zfs volume to the pool successfully"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_005_pos.ksh
new file mode 100755 (executable)
index 0000000..4cfc904
--- /dev/null
@@ -0,0 +1,84 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+#       'zpool add' should return fail if
+#      1. vdev is part of an active pool
+#      2. vdev is currently mounted
+#      3. vdev is in /etc/vfstab
+#      3. vdev is specified as the dedicated dump device
+#
+# STRATEGY:
+#      1. Create case scenarios
+#      2. For each scenario, try to add the device to the pool
+#      3. Verify the add operation get failed
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists "$TESTPOOL" && \
+               destroy_pool "$TESTPOOL"
+       poolexists "$TESTPOOL1" && \
+               destroy_pool "$TESTPOOL1"
+
+       if [[ -n $saved_dump_dev ]]; then
+               log_must eval "$DUMPADM -u -d $saved_dump_dev > /dev/null"
+       fi
+
+       partition_cleanup
+}
+
+log_assert "'zpool add' should fail with inapplicable scenarios."
+
+log_onexit cleanup
+
+mnttab_dev=$(find_mnttab_dev)
+vfstab_dev=$(find_vfstab_dev)
+saved_dump_dev=$(save_dump_dev)
+dump_dev=${disk}${SLICE_PREFIX}${SLICE3}
+
+create_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE0}"
+log_must poolexists "$TESTPOOL"
+
+create_pool "$TESTPOOL1" "${disk}${SLICE_PREFIX}${SLICE1}"
+log_must poolexists "$TESTPOOL1"
+log_mustnot $ZPOOL add -f "$TESTPOOL" ${disk}${SLICE_PREFIX}${SLICE1}
+
+log_mustnot $ZPOOL add -f "$TESTPOOL" $mnttab_dev
+
+log_mustnot $ZPOOL add -f "$TESTPOOL" $vfstab_dev
+
+log_must $ECHO "y" | $NEWFS ${DEV_DSKDIR}/$dump_dev > /dev/null 2>&1
+log_must $DUMPADM -u -d ${DEV_DSKDIR}/$dump_dev > /dev/null
+log_mustnot $ZPOOL add -f "$TESTPOOL" $dump_dev
+
+log_pass "'zpool add' should fail with inapplicable scenarios."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_006_pos.ksh
new file mode 100755 (executable)
index 0000000..c60814d
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+# Adding a large number of file based vdevs to a zpool works.
+#
+# STRATEGY:
+# 1. Create a file based pool.
+# 2. Add 32 file based vdevs to it.
+# 3. Attempt to add a file based vdev that's too small; verify failure.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 && \
+               destroy_pool $TESTPOOL1
+
+       poolexists $TESTPOOL && \
+               destroy_pool $TESTPOOL
+
+       [[ -d $TESTDIR ]] && log_must $RM -rf $TESTDIR
+       partition_cleanup
+}
+
+log_assert "Adding a large number of file based vdevs to a zpool works."
+log_onexit cleanup
+
+create_pool $TESTPOOL ${DISKS%% *}
+log_must $ZFS create -o mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+log_must $MKFILE 64m $TESTDIR/file.00
+create_pool "$TESTPOOL1" "$TESTDIR/file.00"
+
+vdevs_list=$($ECHO $TESTDIR/file.{01..32})
+log_must $MKFILE 64m $vdevs_list
+
+log_must $ZPOOL add -f "$TESTPOOL1" $vdevs_list
+log_must vdevs_in_pool "$TESTPOOL1" "$vdevs_list"
+
+# Attempt to add a file based vdev that's too small.
+log_must $MKFILE 32m $TESTDIR/broken_file
+log_mustnot $ZPOOL add -f "$TESTPOOL1" ${TESTDIR}/broken_file
+log_mustnot vdevs_in_pool "$TESTPOOL1" "${TESTDIR}/broken_file"
+
+log_pass "Adding a large number of file based vdevs to a zpool works."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_007_neg.ksh
new file mode 100755 (executable)
index 0000000..25225fc
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+#       'zpool add' should return an error with badly-formed parameters,
+#
+# STRATEGY:
+#      1. Create an array of parameters
+#      2. For each parameter in the array, execute 'zpool add'
+#      3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists "$TESTPOOL" && \
+               destroy_pool "$TESTPOOL"
+
+       partition_cleanup
+}
+
+log_assert "'zpool add' should return an error with badly-formed parameters."
+
+log_onexit cleanup
+
+set -A args "" "-f" "-n" "-?" "-nf" "-fn" "-f -n" "--f" "-blah" \
+       "-? $TESTPOOL ${disk}${SLICE_PREFIX}${SLICE1}"
+
+create_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE0}"
+log_must poolexists "$TESTPOOL"
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZPOOL add ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "'zpool add' badly formed parameters fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_008_neg.ksh
new file mode 100755 (executable)
index 0000000..ffb5910
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+#       'zpool add' should return an error with nonexistent pools or vdevs
+#
+# STRATEGY:
+#      1. Create an array of parameters which contains nonexistent pools/vdevs
+#      2. For each parameter in the array, execute 'zpool add'
+#      3. Verify an error is returned
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+
+        poolexists "$TESTPOOL" && \
+                destroy_pool "$TESTPOOL"
+
+       partition_cleanup
+}
+
+log_assert "'zpool add' should return an error with nonexistent pools and vdevs"
+
+log_onexit cleanup
+
+set -A args "" "-f nonexistent_pool ${disk}${SLICE_PREFIX}${SLICE1}" \
+       "-f $TESTPOOL nonexistent_vdev"
+
+create_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE0}"
+log_must poolexists "$TESTPOOL"
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZPOOL add ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "'zpool add' with nonexistent pools and vdevs fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_add/zpool_add_009_neg.ksh
new file mode 100755 (executable)
index 0000000..f547883
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_add/zpool_add.kshlib
+
+#
+# DESCRIPTION:
+#       'zpool add' should return fail if vdevs are the same or vdev is
+# contained in the given pool
+#
+# STRATEGY:
+#      1. Create a storage pool
+#      2. Add the two same devices to pool A
+#      3. Add the device in pool A to pool A again
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+
+        poolexists "$TESTPOOL" && \
+                destroy_pool "$TESTPOOL"
+
+       partition_cleanup
+
+}
+
+log_assert "'zpool add' should fail if vdevs are the same or vdev is " \
+       "contained in the given pool."
+
+log_onexit cleanup
+
+create_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE0}"
+log_must poolexists "$TESTPOOL"
+
+log_mustnot $ZPOOL add -f "$TESTPOOL" ${disk}${SLICE_PREFIX}${SLICE1} \
+       ${disk}${SLICE_PREFIX}${SLICE1}
+log_mustnot $ZPOOL add -f "$TESTPOOL" ${disk}${SLICE_PREFIX}${SLICE0}
+
+log_pass "'zpool add' get fail as expected if vdevs are the same or vdev is " \
+       "contained in the given pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/Makefile.am
new file mode 100644 (file)
index 0000000..f642108
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_attach
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_attach_001_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/cleanup.ksh
new file mode 100755 (executable)
index 0000000..89c1462
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/setup.ksh
new file mode 100755 (executable)
index 0000000..2229f87
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+DISK=${DISKS%% *}
+
+default_mirror_setup $DISKS
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/zpool_attach_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_attach/zpool_attach_001_neg.ksh
new file mode 100755 (executable)
index 0000000..df53b12
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool attach' command with bad options fails.
+#
+# STRATEGY:
+# 1. Create an array of badly formed 'zpool attach' options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "global"
+
+DISKLIST=$(get_disklist $TESTPOOL)
+
+set -A args "" "-f" "-?" "-z fakepool" "-f fakepool" "-ev fakepool" "fakepool" \
+       "$TESTPOOL" "-t $TESTPOOL/$TESTFS" "-t $TESTPOOL/$TESTFS $DISKLIST" \
+       "$TESTPOOL/$TESTCTR" "-t $TESTPOOL/$TESTCTR/$TESTFS1" \
+       "$TESTPOOL/$TESTCTR $DISKLIST" "-t $TESTPOOL/$TESTVOL" \
+       "$TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+       "$TESTPOOL/$TESTVOL $DISKLIST" \
+       "$DISKLIST" \
+       "fakepool fakedevice" "fakepool fakedevice fakenewdevice" \
+       "$TESTPOOL fakedevice" "$TESTPOOL $DISKLIST" \
+       "$TESTPOOL fakedevice fakenewdevice fakenewdevice" \
+        "-f $TESTPOOL" "-f $TESTPOOL/$TESTFS" "-f $TESTPOOL/$TESTFS $DISKLIST" \
+        "-f $TESTPOOL/$TESTCTR" "-f $TESTPOOL/$TESTCTR/$TESTFS1" \
+        "-f $TESTPOOL/$TESTCTR $DISKLIST" "-f $TESTPOOL/$TESTVOL" \
+        "-f $TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+        "-f $TESTPOOL/$TESTVOL $DISKLIST" \
+        "-f $DISKLIST" \
+       "-f fakepool fakedevice" "-f fakepool fakedevice fakenewdevice" \
+       "-f $TESTPOOL fakedevice fakenewdevice fakenewdevice" \
+       "-f $TESTPOOL fakedevice" "-f $TESTPOOL $DISKLIST"
+
+log_assert "Executing 'zpool attach' with bad options fails"
+
+if [[ -z $DISKLIST ]]; then
+       log_fail "DISKLIST is empty."
+fi
+
+typeset -i i=0
+
+while [[ $i -lt ${#args[*]} ]]; do
+
+       log_mustnot $ZPOOL attach ${args[$i]}
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool attach' command with bad options failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/Makefile.am
new file mode 100644 (file)
index 0000000..1d9a719
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_clear
+dist_pkgdata_SCRIPTS = \
+       zpool_clear.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_clear_001_pos.ksh \
+       zpool_clear_002_neg.ksh \
+       zpool_clear_003_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear.cfg
new file mode 100644 (file)
index 0000000..097a43b
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+export FILESIZE=100m
+export BLOCKSZ=$(( 1024 * 1024 ))
+export NUM_WRITES=40
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_001_pos.ksh
new file mode 100755 (executable)
index 0000000..b2a2ed5
--- /dev/null
@@ -0,0 +1,217 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_clear/zpool_clear.cfg
+
+#
+# DESCRIPTION:
+# Verify 'zpool clear' can clear pool errors.
+#
+# STRATEGY:
+# 1. Create various configuration pools
+# 2. Make errors to pool
+# 3. Use zpool clear to clear errors
+# 4. Verify the errors has been cleared.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        poolexists $TESTPOOL1 && \
+                log_must $ZPOOL destroy -f $TESTPOOL1
+
+        for file in `$LS $TESTDIR/file.*`; do
+               log_must $RM -f $file
+        done
+}
+
+
+log_assert "Verify 'zpool clear' can clear errors of a storage pool."
+log_onexit cleanup
+
+#make raw files to create various configuration pools
+typeset -i i=0
+while (( i < 3 )); do
+       log_must $MKFILE $FILESIZE $TESTDIR/file.$i
+
+       (( i = i + 1 ))
+done
+
+fbase=$TESTDIR/file
+set -A poolconf "mirror $fbase.0 $fbase.1 $fbase.2" \
+                "raidz1 $fbase.0 $fbase.1 $fbase.2" \
+                "raidz2 $fbase.0 $fbase.1 $fbase.2"
+
+function check_err # <pool> [<vdev>]
+{
+       typeset pool=$1
+       shift
+       if (( $# > 0 )); then
+               typeset checkvdev=$1
+       else
+               typeset checkvdev=""
+       fi
+       typeset -i errnum=0
+       typeset c_read=0
+       typeset c_write=0
+       typeset c_cksum=0
+       typeset tmpfile=/var/tmp/file.$$
+       typeset healthstr="pool '$pool' is healthy"
+       typeset output="`$ZPOOL status -x $pool`"
+
+       [[ "$output" ==  "$healthstr" ]] && return $errnum
+
+       $ZPOOL status -x $pool | $GREP -v "^$" | $GREP -v "pool:" \
+                       | $GREP -v "state:" | $GREP -v "config:" \
+                       | $GREP -v "errors:" > $tmpfile
+       typeset line
+       typeset -i fetchbegin=1
+       while read line; do
+               if (( $fetchbegin != 0 )); then
+                        $ECHO $line | $GREP "NAME" >/dev/null 2>&1
+                        (( $? == 0 )) && (( fetchbegin = 0 ))
+                         continue
+                fi
+
+               if [[ -n $checkvdev ]]; then
+                       $ECHO $line | $GREP $checkvdev >/dev/null 2>&1
+                       (( $? != 0 )) && continue
+                       c_read=`$ECHO $line | $AWK '{print $3}'`
+                       c_write=`$ECHO $line | $AWK '{print $4}'`
+                       c_cksum=`$ECHO $line | $AWK '{print $5}'`
+                       if [ $c_read != 0 ] || [ $c_write != 0 ] || \
+                           [ $c_cksum != 0 ]
+                       then
+                               (( errnum = errnum + 1 ))
+                       fi
+                       break
+               fi
+
+               c_read=`$ECHO $line | $AWK '{print $3}'`
+               c_write=`$ECHO $line | $AWK '{print $4}'`
+               c_cksum=`$ECHO $line | $AWK '{print $5}'`
+               if [ $c_read != 0 ] || [ $c_write != 0 ] || \
+                   [ $c_cksum != 0 ]
+               then
+                       (( errnum = errnum + 1 ))
+               fi
+       done <$tmpfile
+
+       return $errnum
+}
+
+function do_testing #<clear type> <vdevs>
+{
+       typeset FS=$TESTPOOL1/fs
+       typeset file=/$FS/f
+       typeset type=$1
+       shift
+       typeset vdev="$@"
+
+       log_must $ZPOOL create -f $TESTPOOL1 $vdev
+       log_must $ZFS create $FS
+       #
+       # Fully fill up the zfs filesystem in order to make data block errors
+       # zfs filesystem
+       #
+       typeset -i ret=0
+       typeset -i i=0
+       while $TRUE ; do
+               $FILE_WRITE -o create -f $file.$i -b $BLOCKSZ -c $NUM_WRITES
+               ret=$?
+               (( $ret != 0 )) && break
+               (( i = i + 1 ))
+       done
+       (( $ret != 28 )) && log_fail "$FILE_WRITE fails to fully fill up the $FS."
+
+       #
+       #Make errors to the testing pool by overwrite the vdev device with
+       #/usr/bin/dd command. We donot want to have a full overwrite. That
+       #may cause the system panic. So, we should skip the vdev label space.
+       #
+       (( i = $RANDOM % 3 ))
+       typeset -i wcount=0
+       typeset -i size
+       case $FILESIZE in
+               *g|*G)
+                       (( size = ${FILESIZE%%[g|G]} ))
+                       (( wcount = size*1024*1024 - 512 ))
+                       ;;
+               *m|*M)
+                       (( size = ${FILESIZE%%[m|M]} ))
+                       (( wcount = size*1024 - 512 ))
+                       ;;
+               *k|*K)
+                       (( size = ${FILESIZE%%[k|K]} ))
+                       (( wcount = size - 512 ))
+                       ;;
+               *)
+                       (( wcount = FILESIZE/1024 - 512 ))
+                       ;;
+       esac
+       $DD if=/dev/zero of=$fbase.$i seek=512 bs=1024 count=$wcount conv=notrunc \
+                       > /dev/null 2>&1
+       log_must $SYNC
+       log_must $ZPOOL scrub $TESTPOOL1
+       # Wait for the completion of scrub operation
+       while is_pool_scrubbing $TESTPOOL1; do
+               $SLEEP 1
+       done
+
+       check_err $TESTPOOL1 && \
+               log_fail "No error generated."
+       if [[ $type == "device" ]]; then
+               log_must $ZPOOL clear $TESTPOOL1 $fbase.$i
+               ! check_err $TESTPOOL1 $fbase.$i && \
+                   log_fail "'zpool clear' fails to clear error for $fbase.$i device."
+       fi
+
+       if [[ $type == "pool" ]]; then
+               log_must $ZPOOL clear $TESTPOOL1
+               ! check_err $TESTPOOL1 && \
+                   log_fail "'zpool clear' fails to clear error for pool $TESTPOOL1."
+       fi
+
+       log_must $ZPOOL destroy $TESTPOOL1
+}
+
+log_note "'zpool clear' clears leaf-device error."
+for devconf in "${poolconf[@]}"; do
+       do_testing "device" $devconf
+done
+log_note "'zpool clear' clears top-level pool error."
+for devconf in "${poolconf[@]}"; do
+       do_testing "pool" $devconf
+done
+
+log_pass "'zpool clear' clears pool errors as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_002_neg.ksh
new file mode 100755 (executable)
index 0000000..35c2b64
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_clear/zpool_clear.cfg
+
+#
+# DESCRIPTION:
+# A badly formed parameter passed to 'zpool clear' should
+# return an error.
+#
+# STRATEGY:
+# 1. Create an array containing bad 'zpool clear' parameters.
+# 2. For each element, execute the sub-command.
+# 3. Verify it returns an error.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 && \
+               log_must $ZPOOL destroy -f $TESTPOOL1
+       [[ -e $file ]] && \
+               log_must $RM -f $file
+}
+
+log_assert "Execute 'zpool clear' using invalid parameters."
+log_onexit cleanup
+
+# Create another pool for negative testing, which clears pool error
+# with vdev device not in the pool vdev devices.
+file=$TESTDIR/file.$$
+log_must $MKFILE $FILESIZE $file
+log_must $ZPOOL create $TESTPOOL1 $file
+
+set -A args "" "-?" "--%" "-1234567" "0.0001" "0.7644" "-0.7644" \
+               "blah" "blah $DISK" "$TESTPOOL c0txdx" "$TESTPOOL $file" \
+               "$TESTPOOL c0txdx blah" "$TESTPOOL $file blah"
+
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZPOOL clear ${args[i]}
+
+       ((i = i + 1))
+done
+
+log_pass "Invalid parameters to 'zpool clear' fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_clear/zpool_clear_003_neg.ksh
new file mode 100755 (executable)
index 0000000..241ac03
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_clear/zpool_clear.cfg
+
+#
+# DESCRIPTION:
+# Verify 'zpool clear' cannot used to spare device.
+#
+# STRATEGY:
+# 1. Create a spare pool.
+# 2. Try to clear the spare device
+# 3. Verify it returns an error.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        poolexists $TESTPOOL1 && \
+                log_must $ZPOOL destroy -f $TESTPOOL1
+
+        for file in `$LS $TESTDIR/file.*`; do
+               log_must $RM -f $file
+        done
+}
+
+
+log_assert "Verify 'zpool clear' cannot clear error for spare device."
+log_onexit cleanup
+
+#make raw files to create a spare pool
+typeset -i i=0
+while (( i < 5 )); do
+       log_must $MKFILE $FILESIZE $TESTDIR/file.$i
+
+       (( i = i + 1 ))
+done
+log_must $ZPOOL create $TESTPOOL1 raidz $TESTDIR/file.1 $TESTDIR/file.2 \
+       $TESTDIR/file.3 spare $TESTDIR/file.4
+
+log_mustnot $ZPOOL clear $TESTPOOL1 $TESTDIR/file.4
+
+log_pass "'zpool clear' works on spare device failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile.am
new file mode 100644 (file)
index 0000000..8cfc5bd
--- /dev/null
@@ -0,0 +1,34 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_create
+dist_pkgdata_SCRIPTS = \
+       zpool_create.cfg \
+       zpool_create.shlib \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_create_001_pos.ksh \
+       zpool_create_002_pos.ksh \
+       zpool_create_003_pos.ksh \
+       zpool_create_004_pos.ksh \
+       zpool_create_005_pos.ksh \
+       zpool_create_006_pos.ksh \
+       zpool_create_007_neg.ksh \
+       zpool_create_008_pos.ksh \
+       zpool_create_009_neg.ksh \
+       zpool_create_010_neg.ksh \
+       zpool_create_011_neg.ksh \
+       zpool_create_012_neg.ksh \
+       zpool_create_014_neg.ksh \
+       zpool_create_015_neg.ksh \
+       zpool_create_016_pos.ksh \
+       zpool_create_017_neg.ksh \
+       zpool_create_018_pos.ksh \
+       zpool_create_019_pos.ksh \
+       zpool_create_020_pos.ksh \
+       zpool_create_021_pos.ksh \
+       zpool_create_022_pos.ksh \
+       zpool_create_023_neg.ksh \
+       zpool_create_024_pos.ksh \
+       zpool_create_features_001_pos.ksh \
+       zpool_create_features_002_pos.ksh \
+       zpool_create_features_003_pos.ksh \
+       zpool_create_features_004_neg.ksh \
+       zpool_create_features_005_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/cleanup.ksh
new file mode 100755 (executable)
index 0000000..d3134a7
--- /dev/null
@@ -0,0 +1,39 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+clean_blockfile "$TESTDIR $TESTDIR0 $TESTDIR1"
+
+cleanup_devices $DISKS
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/setup.ksh
new file mode 100755 (executable)
index 0000000..fa79e0b
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+[[ -z $FORMAT ]] || \
+[[ -z $MKDIR ]] || \
+[[ -z $LSBLK ]] || \
+[[ -z $READLINK ]] || \
+[[ -z $TOUCH ]] && \
+       log_fail "Missing required commands"
+
+verify_runnable "global"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+if [[ -n $DISK ]]; then
+       #
+        # Use 'zpool create' to clean up the infomation in
+        # in the given disk to avoid slice overlapping.
+        #
+       cleanup_devices $DISK
+
+        partition_disk $SIZE $DISK 7
+else
+       for disk in `$ECHO $DISKSARRAY`; do
+               cleanup_devices $disk
+
+               partition_disk $SIZE $disk 7
+       done
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.cfg
new file mode 100644 (file)
index 0000000..33dd886
--- /dev/null
@@ -0,0 +1,115 @@
+#
+# 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) 2012, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export DISK_ARRAY_NUM=0
+export DISK_ARRAY_LIMIT=4
+export DISKSARRAY=""
+export VDEVS_NUM=32
+
+function set_disks
+{
+        typeset -a disk_array=($(find_disks $DISKS))
+
+       if (( ${#disk_array[*]} <= 1 )); then
+               export DISK=${DISKS%% *}
+               export DISK_ARRAY_NUM=1
+       else
+               export DISK=""
+               typeset -i i=0
+               while (( i < ${#disk_array[*]} )); do
+                       export DISK${i}="${disk_array[$i]}"
+                       DISKSARRAY="$DISKSARRAY ${disk_array[$i]}"
+                       (( i = i + 1 ))
+                       (( i>$DISK_ARRAY_LIMIT )) && break
+               done
+               export DISK_ARRAY_NUM=$i
+               export DISKSARRAY
+       fi
+}
+
+set_disks
+
+export FILESIZE="100m"
+export FILESIZE1="150m"
+export SIZE="200m"
+export SIZE1="250m"
+
+if is_linux; then
+       set_device_dir
+       set_slice_prefix
+       export SLICE0=1
+       export SLICE1=2
+       export SLICE2=3
+       export SLICE3=4
+       export SLICE4=5
+       export SLICE5=6
+       export SLICE6=7
+       export SLICE7=8
+       disk1=${DISKS%% *}
+       if is_mpath_device $disk1; then
+               delete_partitions
+       fi
+else
+       export SLICE_PREFIX="s"
+       export SLICE0=0
+       export SLICE1=1
+       export SLICE2=2
+       export SLICE3=3
+       export SLICE4=4
+       export SLICE5=5
+       export SLICE6=6
+       export SLICE7=7
+fi
+
+export FILEDISK=filedisk_create
+export FILEDISK0=filedisk0_create
+export FILEDISK1=filedisk1_create
+export FILEDISK2=filedisk2_create
+export FILEDISK3=filedisk3_create
+
+export BYND_MAX_NAME="byondmaxnamelength\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789\
+012345678901234567890123456789"
+
+export TOOSMALL="toosmall"
+
+export TESTPOOL4=testpool4.create
+export TESTPOOL5=testpool5.create
+export TESTPOOL6=testpool6.create
+
+export CPATH="/var/tmp/cachefile.create"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create.shlib
new file mode 100644 (file)
index 0000000..ff104f2
--- /dev/null
@@ -0,0 +1,154 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.cfg
+
+#
+# Given a pool vdevs list, create the pool,verify the created pool,
+# and destroy the pool
+# $1, pool name
+# $2, pool type, mirror, raidz, or none
+# $3, vdevs list
+#
+function create_pool_test
+{
+       typeset pool=$1
+       typeset keywd=$2
+       typeset vdevs
+       eval "typeset -a diskarray=($3)"
+
+       for vdevs in "${diskarray[@]}";do
+               create_pool $pool $keywd $vdevs
+               log_must poolexists $pool
+               destroy_pool $pool
+       done
+}
+
+#
+# Create a ufs|ext2 file system and make a file within the file
+# system for storage pool vdev
+# $1, file size
+# $2, file name
+# $3, disk name to create ufs|ext2 file system
+#
+function create_blockfile
+{
+       typeset size=$1
+       typeset file=$2
+       typeset disk=$3
+       typeset dir=`$DIRNAME $file`
+
+       if [[ -d $dir ]]; then
+               ismounted $dir $NEWFS_DEFAULT_FS
+               (( $? == 0 )) && \
+                       log_must $UMOUNT -f $dir
+       else
+               log_must $MKDIR -p $dir
+       fi
+
+       $ECHO "y" | $NEWFS ${DEV_RDSKDIR}/$disk >/dev/null 2>&1
+       (( $? != 0 )) &&
+               log_fail "Create file system fail."
+
+        log_must $MOUNT ${DEV_DSKDIR}/$disk $dir
+        log_must $MKFILE $size $file
+}
+
+#
+# Umount the ext2|ufs filesystem and remove the mountpoint
+# $1, the mount point
+#
+function clean_blockfile
+{
+       typeset dirs=$1
+
+       for dir in $dirs; do
+               if [[ -d $dir ]]; then
+                       if is_linux; then
+                               if ismounted $dir ext2; then
+                                       typeset dev=$($DF -lht ext2 | \
+                                               $GREP "$dir" | \
+                                               $AWK '{print $1}')
+                                       log_must $UMOUNT -f $dir
+                                       create_pool ${TESTPOOL}.tmp $dev
+                                       destroy_pool ${TESTPOOL}.tmp
+                               fi
+                       else
+                               if ismounted $dir ufs; then
+                                       typeset dev=$($DF -lhF ufs | \
+                                               $GREP "$dir" | \
+                                               $AWK '{print $1}')
+                                       log_must $UMOUNT -f $dir
+                                       create_pool ${TESTPOOL}.tmp $dev
+                                       destroy_pool ${TESTPOOL}.tmp
+                               fi
+                       fi
+                       log_must $RM -rf $dir
+               fi
+       done
+}
+
+#
+# Find the storage device in /etc/vfstab
+#
+function find_vfstab_dev
+{
+       typeset vfstab="/etc/vfstab"
+       typeset tmpfile="/tmp/vfstab.tmp"
+       typeset vfstabdev
+       typeset vfstabdevs=""
+       typeset line
+
+       $CAT $vfstab | $GREP "^${DEV_DSKDIR}" >$tmpfile
+       while read -r line
+       do
+               vfstabdev=`$ECHO "$line" | $AWK '{print $1}'`
+               vfstabdev=${vfstabdev%%:}
+               vfstabdevs="$vfstabdev $vfstabdevs"
+       done <$tmpfile
+
+       $RM -f $tmpfile
+       $ECHO $vfstabdevs
+}
+
+#
+# Save the systme current dump device configuration
+#
+function save_dump_dev
+{
+
+       typeset dumpdev
+       typeset fnd="Dump device"
+
+       dumpdev=`$DUMPADM | $GREP "$fnd" | $CUT -f2 -d : | \
+               $AWK '{print $1}'`
+       $ECHO $dumpdev
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_001_pos.ksh
new file mode 100755 (executable)
index 0000000..824c6dc
--- /dev/null
@@ -0,0 +1,145 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create <pool> <vspec> ...' can successfully create a
+# new pool with a name in ZFS namespace.
+#
+# STRATEGY:
+# 1. Create storage pools with a name in ZFS namespace with different
+# vdev specs.
+# 2. Verify the pool created successfully
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL && destroy_pool $TESTPOOL
+
+       clean_blockfile "$TESTDIR0 $TESTDIR1"
+
+       if [[ -n $DISK ]]; then
+               partition_disk $SIZE $DISK 7
+       else
+               typeset disk=""
+               for disk in $DISK0 $DISK1; do
+                       partition_disk $SIZE $disk 7
+               done
+       fi
+}
+
+log_assert "'zpool create <pool> <vspec> ...' can successfully create" \
+       "a new pool with a name in ZFS namespace."
+
+log_onexit cleanup
+
+set -A keywords "" "mirror" "raidz" "raidz1"
+
+case $DISK_ARRAY_NUM in
+0|1)
+       typeset disk=""
+       if (( $DISK_ARRAY_NUM == 0 )); then
+               disk=$DISK
+       else
+               disk=$DISK0
+       fi
+       create_blockfile $FILESIZE $TESTDIR0/$FILEDISK0 \
+               ${disk}${SLICE_PREFIX}${SLICE5}
+       create_blockfile $FILESIZE $TESTDIR1/$FILEDISK1 \
+               ${disk}${SLICE_PREFIX}${SLICE6}
+
+       pooldevs="${disk}${SLICE_PREFIX}${SLICE0} \
+               ${DEV_DSKDIR}/${disk}${SLICE_PREFIX}${SLICE0} \
+               \"${disk}${SLICE_PREFIX}${SLICE0} \
+               ${disk}${SLICE_PREFIX}${SLICE1}\" \
+                  $TESTDIR0/$FILEDISK0"
+       raidzdevs="\"${DEV_DSKDIR}/${disk}${SLICE_PREFIX}${SLICE0} \
+               ${disk}${SLICE_PREFIX}${SLICE1}\" \
+               \"${disk}${SLICE_PREFIX}${SLICE0} \
+               ${disk}${SLICE_PREFIX}${SLICE1} \
+               ${disk}${SLICE_PREFIX}${SLICE3}\" \
+               \"${disk}${SLICE_PREFIX}${SLICE0} \
+               ${disk}${SLICE_PREFIX}${SLICE1} \
+               ${disk}${SLICE_PREFIX}${SLICE3} \
+               ${disk}${SLICE_PREFIX}${SLICE4}\"\
+               \"$TESTDIR0/$FILEDISK0 $TESTDIR1/$FILEDISK1\""
+       mirrordevs=$raidzdevs
+       ;;
+2|*)
+       create_blockfile $FILESIZE $TESTDIR0/$FILEDISK0 \
+               ${DISK0}${SLICE_PREFIX}${SLICE5}
+        create_blockfile $FILESIZE $TESTDIR1/$FILEDISK1 \
+               ${DISK1}${SLICE_PREFIX}${SLICE5}
+
+       pooldevs="${DISK0}${SLICE_PREFIX}${SLICE0} \
+               \"${DEV_DSKDIR}/${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK1}${SLICE_PREFIX}${SLICE0}\" \
+               \"${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK0}${SLICE_PREFIX}${SLICE1} \
+               ${DISK1}${SLICE_PREFIX}${SLICE1}\"\
+               \"${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK1}${SLICE_PREFIX}${SLICE0} \
+               ${DISK0}${SLICE_PREFIX}${SLICE1}\
+               ${DISK1}${SLICE_PREFIX}${SLICE1}\" \
+               \"$TESTDIR0/$FILEDISK0 $TESTDIR1/$FILEDISK1\""
+       raidzdevs="\"${DEV_DSKDIR}/${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK1}${SLICE_PREFIX}${SLICE0}\" \
+               \"${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK0}${SLICE_PREFIX}${SLICE1} \
+               ${DISK1}${SLICE_PREFIX}${SLICE1}\" \
+               \"${DISK0}${SLICE_PREFIX}${SLICE0} \
+               ${DISK1}${SLICE_PREFIX}${SLICE0} \
+               ${DISK0}${SLICE_PREFIX}${SLICE1} \
+               ${DISK1}${SLICE_PREFIX}${SLICE1}\" \
+               \"$TESTDIR0/$FILEDISK0 $TESTDIR1/$FILEDISK1\""
+       mirrordevs=$raidzdevs
+       ;;
+esac
+
+typeset -i i=0
+while (( $i < ${#keywords[*]} )); do
+       case ${keywords[i]} in
+       "")
+               create_pool_test "$TESTPOOL" "${keywords[i]}" "$pooldevs";;
+       mirror)
+               create_pool_test "$TESTPOOL" "${keywords[i]}" "$mirrordevs";;
+       raidz|raidz1)
+               create_pool_test "$TESTPOOL" "${keywords[i]}" "$raidzdevs" ;;
+       esac
+       (( i = i+1 ))
+done
+
+log_pass "'zpool create <pool> <vspec> ...' success."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_002_pos.ksh
new file mode 100755 (executable)
index 0000000..bba3d94
--- /dev/null
@@ -0,0 +1,125 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create -f <pool> <vspec> ...' can successfully create a
+# new pool in some cases.
+#
+# STRATEGY:
+# 1. Prepare the scenarios for '-f' option
+# 2. Use -f to override the devices to create new pools
+# 3. Verify the pool created successfully
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       for pool in $TESTPOOL $TESTPOOL1 $TESTPOOL2 $TESTPOOL3 $TESTPOOL4 \
+               $TESTPOOL5 $TESTPOOL6
+       do
+               poolexists $pool && destroy_pool $pool
+       done
+
+       clean_blockfile "$TESTDIR0 $TESTDIR1"
+
+       for file in /var/tmp/$FILEDISK0 /var/tmp/$FILEDISK1 /var/tmp/$FILEDISK2
+       do
+               if [[ -e $file ]]; then
+                       $RM -rf $file
+               fi
+       done
+
+       partition_disk $SIZE $disk 6
+}
+
+log_onexit cleanup
+
+log_assert "'zpool create -f <pool> <vspec> ...' can successfully create" \
+       "a new pool in some cases."
+
+if [[ -n $DISK ]]; then
+       disk=$DISK
+else
+       disk=$DISK0
+fi
+create_pool "$TESTPOOL" "${disk}${SLICE_PREFIX}${SLICE0}"
+log_must $ECHO "y" | $NEWFS \
+       ${DEV_RDSKDIR}/${disk}${SLICE_PREFIX}${SLICE1} >/dev/null 2>&1
+create_blockfile $FILESIZE $TESTDIR0/$FILEDISK0 ${disk}${SLICE_PREFIX}${SLICE4}
+create_blockfile $FILESIZE1 $TESTDIR1/$FILEDISK1 ${disk}${SLICE_PREFIX}${SLICE5}
+log_must $MKFILE $SIZE /var/tmp/$FILEDISK0
+log_must $MKFILE $SIZE /var/tmp/$FILEDISK1
+log_must $MKFILE $SIZE /var/tmp/$FILEDISK2
+
+log_must $ZPOOL export $TESTPOOL
+log_note "'zpool create' without '-f' will fail " \
+       "while device is belong to an exported pool."
+log_mustnot $ZPOOL create "$TESTPOOL1" "${disk}${SLICE_PREFIX}${SLICE0}"
+create_pool "$TESTPOOL1" "${disk}${SLICE_PREFIX}${SLICE0}"
+log_must poolexists $TESTPOOL1
+
+log_note "'zpool create' without '-f' will fail " \
+       "while device is using by an ufs filesystem."
+log_mustnot $ZPOOL create "$TESTPOOL2" "${disk}${SLICE_PREFIX}${SLICE1}"
+create_pool "$TESTPOOL2" "${disk}${SLICE_PREFIX}${SLICE1}"
+log_must poolexists $TESTPOOL2
+
+log_note "'zpool create' mirror without '-f' will fail " \
+       "while devices have different size."
+log_mustnot $ZPOOL create "$TESTPOOL3" "mirror" $TESTDIR0/$FILEDISK0 \
+       $TESTDIR1/$FILEDISK1
+create_pool "$TESTPOOL3" "mirror" $TESTDIR0/$FILEDISK0 $TESTDIR1/$FILEDISK1
+log_must poolexists $TESTPOOL3
+
+log_note "'zpool create' mirror without '-f' will fail " \
+       "while devices are of different types."
+log_mustnot $ZPOOL create "$TESTPOOL4" "mirror" /var/tmp/$FILEDISK0 \
+       ${disk}${SLICE_PREFIX}${SLICE3}
+create_pool "$TESTPOOL4" "mirror" \
+       /var/tmp/$FILEDISK0 ${disk}${SLICE_PREFIX}${SLICE3}
+log_must poolexists $TESTPOOL4
+
+log_note "'zpool create' without '-f' will fail " \
+       "while device is part of potentially active pool."
+create_pool "$TESTPOOL5"  "mirror" /var/tmp/$FILEDISK1 \
+       /var/tmp/$FILEDISK2
+log_must $ZPOOL offline $TESTPOOL5 /var/tmp/$FILEDISK2
+log_must $ZPOOL export $TESTPOOL5
+log_mustnot $ZPOOL create "$TESTPOOL6" /var/tmp/$FILEDISK2
+create_pool $TESTPOOL6 /var/tmp/$FILEDISK2
+log_must poolexists $TESTPOOL6
+
+log_pass "'zpool create -f <pool> <vspec> ...' success."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_003_pos.ksh
new file mode 100755 (executable)
index 0000000..e7917e8
--- /dev/null
@@ -0,0 +1,86 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create -n <pool> <vspec> ...' can display the configuration without
+# actually creating the pool.
+#
+# STRATEGY:
+# 1. Create storage pool with -n option
+# 2. Verify the pool has not been actually created
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       [[ -e $tmpfile ]] && log_must $RM -f $tmpfile
+}
+
+tmpfile="/var/tmp/zpool_create_003.tmp$$"
+
+log_assert "'zpool create -n <pool> <vspec> ...' can display the configuration" \
+        "without actually creating the pool."
+
+log_onexit cleanup
+
+if [[ -n $DISK ]]; then
+        disk=$DISK
+else
+        disk=$DISK0
+fi
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+       partition_disk $SIZE $disk 1
+fi
+
+#
+# Make sure disk is clean before we use it
+#
+create_pool $TESTPOOL ${disk}${SLICE_PREFIX}${SLICE0} > $tmpfile
+destroy_pool $TESTPOOL
+
+$ZPOOL create -n  $TESTPOOL ${disk}${SLICE_PREFIX}${SLICE0} > $tmpfile
+
+poolexists $TESTPOOL && \
+        log_fail "'zpool create -n <pool> <vspec> ...' fail."
+
+str="would create '$TESTPOOL' with the following layout:"
+$CAT $tmpfile | $GREP "$str" >/dev/null 2>&1
+(( $? != 0 )) && \
+        log_fail "'zpool create -n <pool> <vspec>...' is executed as unexpected."
+
+log_pass "'zpool create -n <pool> <vspec>...' success."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_004_pos.ksh
new file mode 100755 (executable)
index 0000000..b5a3709
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/ksh
+#
+# 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) 2012, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# Create a storage pool with many file based vdevs.
+#
+# STRATEGY:
+# 1. Create assigned number of files in ZFS filesystem as vdevs.
+# 2. Creating a new pool based on the vdevs should work.
+# 3. Creating a pool with a file based vdev that is too small should fail.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset pool=""
+
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+       poolexists $TESTPOOL && destroy_pool $TESTPOOL
+
+       [[ -d $TESTDIR ]] && log_must $RM -rf $TESTDIR
+       partition_disk $SIZE $disk 6
+}
+
+log_assert "Storage pools with $VDEVS_NUM file based vdevs can be created."
+log_onexit cleanup
+
+disk=${DISKS%% *}
+create_pool $TESTPOOL $disk
+log_must $ZFS create -o mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+vdevs_list=$($ECHO $TESTDIR/file.{01..32})
+log_must $MKFILE 64m $vdevs_list
+
+create_pool "$TESTPOOL1" $vdevs_list
+log_must vdevs_in_pool "$TESTPOOL1" "$vdevs_list"
+
+if poolexists $TESTPOOL1; then
+       destroy_pool $TESTPOOL1
+else
+       log_fail "Creating pool with large numbers of file-vdevs failed."
+fi
+
+log_must $MKFILE 32m $TESTDIR/broken_file
+vdevs_list="$vdevs_list ${TESTDIR}/broken_file"
+log_mustnot $ZPOOL create -f $TESTPOOL1 $vdevs_list
+
+log_pass "Storage pools with many file based vdevs can be created."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_005_pos.ksh
new file mode 100755 (executable)
index 0000000..c2f3789
--- /dev/null
@@ -0,0 +1,130 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create [-R root][-m mountpoint] <pool> <vdev> ...' can create an
+#  alternate root pool or a new pool mounted at the specified mountpoint.
+#
+# STRATEGY:
+# 1. Create a pool with '-m' option
+# 2. Verify the pool is mounted at the specified mountpoint
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL && \
+               log_must $ZPOOL destroy -f $TESTPOOL
+
+       for dir in $TESTDIR $TESTDIR1; do
+               [[ -d $dir ]] && $RM -rf $dir
+       done
+}
+
+log_assert "'zpool create [-R root][-m mountpoint] <pool> <vdev> ...' can create" \
+       "an alternate pool or a new pool mounted at the specified mountpoint."
+log_onexit cleanup
+
+set -A pooltype "" "mirror" "raidz" "raidz1" "raidz2"
+
+#
+# cleanup the pools created in previous case if zpool_create_004_pos timedout
+#
+for pool in $TESTPOOL2 $TESTPOOL1 $TESTPOOL; do
+       if poolexists $pool; then
+               destroy_pool $pool
+       fi
+done
+
+#prepare raw file for file disk
+[[ -d $TESTDIR ]] && $RM -rf $TESTDIR
+log_must $MKDIR -p $TESTDIR
+typeset -i i=1
+while (( i < 4 )); do
+       log_must $MKFILE $FILESIZE $TESTDIR/file.$i
+
+       (( i = i + 1 ))
+done
+
+#Remove the directory with name as pool name if it exists
+[[ -d /$TESTPOOL ]] && $RM -rf /$TESTPOOL
+file=$TESTDIR/file
+
+for opt in "-R $TESTDIR1" "-m $TESTDIR1" \
+       "-R $TESTDIR1 -m $TESTDIR1" "-m $TESTDIR1 -R $TESTDIR1"
+do
+       i=0
+       while (( i < ${#pooltype[*]} )); do
+               #Remove the testing pool and its mount directory
+               poolexists $TESTPOOL && \
+                       log_must $ZPOOL destroy -f $TESTPOOL
+               [[ -d $TESTDIR1 ]] && $RM -rf $TESTDIR1
+               log_must $ZPOOL create $opt $TESTPOOL ${pooltype[i]} \
+                       $file.1 $file.2 $file.3
+               ! poolexists $TESTPOOL && \
+                       log_fail "Createing pool with $opt fails."
+               mpt=`$ZFS mount | $EGREP "^$TESTPOOL[^/]" | $AWK '{print $2}'`
+               (( ${#mpt} == 0 )) && \
+                       log_fail "$TESTPOOL created with $opt is not mounted."
+               mpt_val=$(get_prop "mountpoint" $TESTPOOL)
+               [[ "$mpt" != "$mpt_val" ]] && \
+                       log_fail "The value of mountpoint property is different\
+                               from the output of zfs mount"
+               if [[ "$opt" == "-m $TESTDIR1" ]]; then
+                       [[ ! -d $TESTDIR1 ]] && \
+                               log_fail "$TESTDIR1 is not created auotmatically."
+                       [[ "$mpt" != "$TESTDIR1" ]] && \
+                               log_fail "$TESTPOOL is not mounted on $TESTDIR1."
+               elif [[ "$opt" == "-R $TESTDIR1" ]]; then
+                       [[ ! -d $TESTDIR1/$TESTPOOL ]] && \
+                               log_fail "$TESTDIR1/$TESTPOOL is not created auotmatically."
+                       [[ "$mpt" != "$TESTDIR1/$TESTPOOL" ]] && \
+                               log_fail "$TESTPOOL is not mounted on $TESTDIR1/$TESTPOOL."
+               else
+                       [[ ! -d ${TESTDIR1}$TESTDIR1 ]] && \
+                               log_fail "${TESTDIR1}$TESTDIR1 is not created automatically."
+                       [[ "$mpt" != "${TESTDIR1}$TESTDIR1" ]] && \
+                               log_fail "$TESTPOOL is not mounted on ${TESTDIR1}$TESTDIR1."
+               fi
+               [[ -d /$TESTPOOL ]] && \
+                       log_fail "The default mountpoint /$TESTPOOL is created" \
+                               "while with $opt option."
+
+               (( i = i + 1 ))
+       done
+done
+
+log_pass "'zpool create [-R root][-m mountpoint] <pool> <vdev> ...' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_006_pos.ksh
new file mode 100755 (executable)
index 0000000..56c6e54
--- /dev/null
@@ -0,0 +1,124 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+#      Verify zpool create succeed with multiple keywords combination.
+#
+# STRATEGY:
+#      1. Create base filesystem to hold virtual disk files.
+#      2. Create several files >= 64M.
+#      3. Verify 'zpool create' succeed with valid keywords combination.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+       datasetexists $TESTPOOL && destroy_pool $TESTPOOL
+}
+
+
+log_assert "Verify 'zpool create' succeed with keywords combination."
+log_onexit cleanup
+
+create_pool $TESTPOOL $DISKS
+mntpnt=$(get_prop mountpoint $TESTPOOL)
+
+typeset -i i=0
+while ((i < 10)); do
+       log_must $MKFILE 64M $mntpnt/vdev$i
+
+       eval vdev$i=$mntpnt/vdev$i
+       ((i += 1))
+done
+
+set -A valid_args \
+       "mirror $vdev0 $vdev1 $vdev2 mirror $vdev3 $vdev4 $vdev5" \
+       "mirror $vdev0 $vdev1 mirror $vdev2 $vdev3 mirror $vdev4 $vdev5" \
+       "mirror $vdev0 $vdev1 $vdev2 mirror $vdev3 $vdev4 $vdev5 \
+               spare $vdev6" \
+       "mirror $vdev0 $vdev1 mirror $vdev2 $vdev3 mirror $vdev4 $vdev5 \
+               spare $vdev6 $vdev7" \
+       "mirror $vdev0 $vdev1 spare $vdev2 mirror $vdev3 $vdev4" \
+       "raidz $vdev0 $vdev1 $vdev2 raidz1 $vdev3 $vdev4 $vdev5" \
+       "raidz $vdev0 $vdev1 raidz1 $vdev2 $vdev3 raidz $vdev4 $vdev5" \
+       "raidz $vdev0 $vdev1 $vdev2 raidz1 $vdev3 $vdev4 $vdev5 \
+               spare $vdev6" \
+       "raidz $vdev0 $vdev1 raidz1 $vdev2 $vdev3 raidz $vdev4 $vdev5 \
+               spare $vdev6 $vdev7" \
+       "raidz $vdev0 $vdev1 spare $vdev2 raidz $vdev3 $vdev4" \
+       "raidz2 $vdev0 $vdev1 $vdev2 raidz2 $vdev3 $vdev4 $vdev5" \
+       "raidz2 $vdev0 $vdev1 $vdev2 raidz2 $vdev3 $vdev4 $vdev5 \
+               raidz2 $vdev6 $vdev7 $vdev8" \
+       "raidz2 $vdev0 $vdev1 $vdev2 raidz2 $vdev3 $vdev4 $vdev5 \
+               spare $vdev6" \
+       "raidz2 $vdev0 $vdev1 $vdev2 raidz2 $vdev3 $vdev4 $vdev5 \
+               raidz2 $vdev6 $vdev7 $vdev8 spare $vdev9" \
+       "raidz2 $vdev0 $vdev1 $vdev2 spare $vdev3 raidz2 $vdev4 $vdev5 $vdev6"
+
+set -A forced_args \
+       "$vdev0 raidz $vdev1 $vdev2 raidz1 $vdev3 $vdev4 $vdev5" \
+       "$vdev0 raidz2 $vdev1 $vdev2 $vdev3 raidz2 $vdev4 $vdev5 $vdev6" \
+       "$vdev0 mirror $vdev1 $vdev2 mirror $vdev3 $vdev4" \
+       "$vdev0 mirror $vdev1 $vdev2 raidz $vdev3 $vdev4 \
+               raidz2 $vdev5 $vdev6 $vdev7 spare $vdev8" \
+       "$vdev0 mirror $vdev1 $vdev2 spare $vdev3 raidz $vdev4 $vdev5" \
+       "raidz $vdev0 $vdev1 raidz2 $vdev2 $vdev3 $vdev4" \
+       "raidz $vdev0 $vdev1 raidz2 $vdev2 $vdev3 $vdev4 spare $vdev5" \
+       "raidz $vdev0 $vdev1 spare $vdev2 raidz2 $vdev3 $vdev4 $vdev5" \
+       "mirror $vdev0 $vdev1 raidz $vdev2 $vdev3 raidz2 $vdev4 $vdev5 $vdev6" \
+       "mirror $vdev0 $vdev1 raidz $vdev2 $vdev3 \
+               raidz2 $vdev4 $vdev5 $vdev6 spare $vdev7" \
+       "mirror $vdev0 $vdev1 raidz $vdev2 $vdev3 \
+               spare $vdev4 raidz2 $vdev5 $vdev6 $vdev7" \
+       "spare $vdev0 $vdev1 $vdev2 mirror $vdev3 $vdev4 raidz $vdev5 $vdev6"
+
+i=0
+while ((i < ${#valid_args[@]})); do
+       log_must $ZPOOL create $TESTPOOL1 ${valid_args[$i]}
+       $SYNC; $SYNC
+       log_must $ZPOOL destroy -f $TESTPOOL1
+
+       ((i += 1))
+done
+
+i=0
+while ((i < ${#forced_args[@]})); do
+       log_mustnot $ZPOOL create $TESTPOOL1 ${forced_args[$i]}
+       log_must $ZPOOL create -f $TESTPOOL1 ${forced_args[$i]}
+       $SYNC; $SYNC
+       log_must $ZPOOL destroy -f $TESTPOOL1
+
+       ((i += 1))
+done
+
+log_pass "'zpool create' succeed with keywords combination."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_007_neg.ksh
new file mode 100755 (executable)
index 0000000..3211b0b
--- /dev/null
@@ -0,0 +1,89 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create' should return an error with badly formed parameters.
+#
+# STRATEGY:
+# 1. Create an array of parameters
+# 2. For each parameter in the array, execute 'zpool create'
+# 3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+if [[ -n $DISK ]]; then
+       disk=$DISK
+else
+       disk=$DISK0
+fi
+
+set -A args  "" "-?" "-n" "-f" "-nf" "-fn" "-f -n" "--f" "-e" "-s" \
+       "-m" "-R" "-m -R" "-Rm" "-mR" "-m $TESTDIR $TESTPOOL" \
+       "-R $TESTDIR $TESTPOOL" "-m nodir $TESTPOOL $disk" \
+       "-R nodir $TESTPOOL $disk" "-m nodir -R nodir $TESTPOOL $disk" \
+       "-R nodir -m nodir $TESTPOOL $disk" "-R $TESTDIR -m nodir $TESTPOOL $disk" \
+       "-R nodir -m $TESTDIR $TESTPOOL $disk" \
+       "-blah" "$TESTPOOL" "$TESTPOOL blah" "$TESTPOOL c?t0d0" \
+       "$TESTPOOL c0txd0" "$TESTPOOL c0t0dx" "$TESTPOOL cxtxdx" \
+       "$TESTPOOL mirror" "$TESTPOOL raidz" "$TESTPOOL mirror raidz" \
+       "$TESTPOOL raidz1" "$TESTPOOL mirror raidz1" \
+       "$TESTPOOL mirror c?t?d?" "$TESTPOOL mirror $disk c0t1d?" \
+       "$TESTPOOL RAIDZ ${disk}${SLICE_PREFIX}${SLICE0} \
+       ${disk}${SLICE_PREFIX}${SLICE1}" \
+       "$TESTPOOL ${disk}${SLICE_PREFIX}${SLICE0} \
+       log ${disk}${SLICE_PREFIX}${SLICE1} \
+       log ${disk}${SLICE_PREFIX}${SLICE3}" \
+       "$TESTPOOL ${disk}${SLICE_PREFIX}${SLICE0} \
+       spare ${disk}${SLICE_PREFIX}${SLICE1} \
+       spare ${disk}${SLICE_PREFIX}${SLICE3}" \
+       "$TESTPOOL RAIDZ1 ${disk}${SLICE_PREFIX}${SLICE0} \
+       ${disk}${SLICE_PREFIX}${SLICE1}" \
+       "$TESTPOOL MIRROR $disk" "$TESTPOOL raidz $disk" \
+       "$TESTPOOL raidz1 $disk" \
+       "1tank $disk" "1234 $disk" "?tank $disk" \
+       "tan%k $disk" "ta@# $disk" "tan+k $disk" \
+       "$BYND_MAX_NAME $disk"
+
+log_assert "'zpool create' should return an error with badly-formed parameters."
+log_onexit default_cleanup_noexit
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL create ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "'zpool create' with badly formed parameters failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_008_pos.ksh
new file mode 100755 (executable)
index 0000000..27506a6
--- /dev/null
@@ -0,0 +1,152 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create' have to use '-f' scenarios
+#
+# STRATEGY:
+# 1. Prepare the scenarios
+# 2. Create pool without '-f' and verify it fails
+# 3. Create pool with '-f' and verify it succeeds
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if [[ $exported_pool == true ]]; then
+               if [[ $force_pool == true ]]; then
+                       log_must $ZPOOL create \
+                               -f $TESTPOOL ${disk}${SLICE_PREFIX}${SLICE0}
+               else
+                       log_must $ZPOOL import $TESTPOOL
+               fi
+       fi
+
+       if poolexists $TESTPOOL ; then
+                destroy_pool $TESTPOOL
+       fi
+
+       if poolexists $TESTPOOL1 ; then
+                destroy_pool $TESTPOOL1
+       fi
+
+       #
+       # recover it back to EFI label
+       #
+       create_pool $TESTPOOL $disk
+       destroy_pool $TESTPOOL
+
+        partition_disk $SIZE $disk 6
+}
+
+#
+# create overlap slice 0 and 1 on $disk
+#
+function create_overlap_slice
+{
+        typeset format_file=/var/tmp/format_overlap.$$
+        typeset disk=$1
+
+        $ECHO "partition" >$format_file
+        $ECHO "0" >> $format_file
+        $ECHO "" >> $format_file
+        $ECHO "" >> $format_file
+        $ECHO "0" >> $format_file
+        $ECHO "200m" >> $format_file
+        $ECHO "1" >> $format_file
+        $ECHO "" >> $format_file
+        $ECHO "" >> $format_file
+        $ECHO "0" >> $format_file
+        $ECHO "400m" >> $format_file
+        $ECHO "label" >> $format_file
+        $ECHO "" >> $format_file
+        $ECHO "q" >> $format_file
+        $ECHO "q" >> $format_file
+
+        $FORMAT -e -s -d $disk -f $format_file
+       typeset -i ret=$?
+        $RM -fr $format_file
+
+       if (( ret != 0 )); then
+                log_fail "unable to create overlap slice."
+        fi
+
+        return 0
+}
+
+log_assert "'zpool create' have to use '-f' scenarios"
+log_onexit cleanup
+
+typeset exported_pool=false
+typeset force_pool=false
+
+if [[ -n $DISK ]]; then
+        disk=$DISK
+else
+        disk=$DISK0
+fi
+
+# overlapped slices as vdev need -f to create pool
+
+# Make the disk is EFI labeled first via pool creation
+create_pool $TESTPOOL $disk
+destroy_pool $TESTPOOL
+
+# Make the disk is VTOC labeled since only VTOC label supports overlap
+log_must labelvtoc $disk
+log_must create_overlap_slice $disk
+
+log_mustnot $ZPOOL create $TESTPOOL ${disk}${SLICE_PREFIX}${SLICE0}
+log_must $ZPOOL create -f $TESTPOOL ${disk}${SLICE_PREFIX}${SLICE0}
+destroy_pool $TESTPOOL
+
+# exported device to be as spare vdev need -f to create pool
+
+log_must $ZPOOL create -f $TESTPOOL $disk
+destroy_pool $TESTPOOL
+log_must partition_disk $SIZE $disk 6
+create_pool $TESTPOOL ${disk}${SLICE_PREFIX}${SLICE0} \
+       ${disk}${SLICE_PREFIX}${SLICE1}
+log_must $ZPOOL export $TESTPOOL
+exported_pool=true
+log_mustnot $ZPOOL create $TESTPOOL1 ${disk}${SLICE_PREFIX}${SLICE3} \
+       spare ${disk}${SLICE_PREFIX}${SLICE1}
+create_pool $TESTPOOL1 ${disk}${SLICE_PREFIX}${SLICE3} \
+       spare ${disk}${SLICE_PREFIX}${SLICE1}
+force_pool=true
+destroy_pool $TESTPOOL1
+
+log_pass "'zpool create' have to use '-f' scenarios"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_009_neg.ksh
new file mode 100755 (executable)
index 0000000..089c475
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+#      Create a pool with same devices twice or create two pools with same
+#      devices, 'zpool create' should failed.
+#
+# STRATEGY:
+#      1. Loop to create the following three kinds of pools.
+#              - Regular pool
+#              - Mirror
+#              - Raidz
+#      2. Create two pools but using the same disks, expect failed.
+#      3. Create one pool but using the same disks twice, expect failed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dtst
+       typeset disk
+
+       for dtst in $TESTPOOL $TESTPOOL1; do
+               poolexists $dtst && destroy_pool $dtst
+       done
+
+       for disk in $DISKS; do
+               partition_disk $SIZE $disk 6
+       done
+}
+
+log_assert "Create a pool with same devices twice or create two pools with " \
+       "same devices, 'zpool create' should fail."
+log_onexit cleanup
+
+typeset opt
+for opt in "" "mirror" "raidz" "raidz1"; do
+       typeset disk="$DISKS"
+       (( ${#opt} == 0 )) && disk=${DISKS%% *}
+
+       typeset -i count=$(get_word_count $disk)
+       if (( count < 2  && ${#opt} != 0 )) ; then
+               continue
+       fi
+
+       # Create two pools but using the same disks.
+       create_pool $TESTPOOL $opt $disk
+       log_mustnot $ZPOOL create -f $TESTPOOL1 $opt $disk
+       destroy_pool $TESTPOOL
+
+       # Create two pools and part of the devices were overlapped
+       create_pool $TESTPOOL $opt $disk
+       log_mustnot $ZPOOL create -f $TESTPOOL1 $opt ${DISKS% *}
+       destroy_pool $TESTPOOL
+
+       # Create one pool but using the same disks twice.
+       log_mustnot $ZPOOL create -f $TESTPOOL $opt $disk $disk
+done
+
+log_pass "Using overlapping or in-use disks to create a new pool fails as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_010_neg.ksh
new file mode 100755 (executable)
index 0000000..7b555de
--- /dev/null
@@ -0,0 +1,88 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create' should return an error with VDEVsof size  <64mb
+#
+# STRATEGY:
+# 1. Create an array of parameters
+# 2. For each parameter in the array, execute 'zpool create'
+# 3. Verify an error is returned.
+#
+
+log_assert "'zpool create' should return an error with VDEVs <64mb"
+
+verify_runnable "global"
+
+function cleanup
+{
+        poolexists $TOOSMALL && destroy_pool $TOOSMALL
+        poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+        poolexists $TESTPOOL && destroy_pool $TESTPOOL
+
+       [[ -d $TESTDIR ]] && $RM -rf $TESTDIR
+
+       partition_disk $SIZE $disk 6
+}
+log_onexit cleanup
+
+if [[ -n $DISK ]]; then
+        disk=$DISK
+else
+        disk=$DISK0
+fi
+
+create_pool $TESTPOOL $disk
+log_must $ZFS create $TESTPOOL/$TESTFS
+log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+for files in $TESTDIR/file1 $TESTDIR/file2
+do
+       log_must $MKFILE 63m $files
+done
+
+set -A args \
+       "$TOOSMALL $TESTDIR/file1" "$TESTPOOL1 $TESTDIR/file1 $TESTDIR/file2" \
+        "$TOOSMALL mirror $TESTDIR/file1 $TESTDIR/file2" \
+       "$TOOSMALL raidz $TESTDIR/file1 $TESTDIR/file2"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL create ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "'zpool create' with badly formed parameters failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_011_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_011_neg.ksh
new file mode 100755 (executable)
index 0000000..6d8b26c
--- /dev/null
@@ -0,0 +1,130 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create' will fail in the following cases:
+# existent pool; device is part of an active pool; nested virtual devices;
+# differently sized devices without -f option; device being currently
+# mounted; devices in /etc/vfstab; specified as the dedicated dump device.
+#
+# STRATEGY:
+# 1. Create case scenarios
+# 2. For each scenario, try to create a new pool with the virtual devices
+# 3. Verify the creation is failed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        for pool in $TESTPOOL $TESTPOOL1
+        do
+                destroy_pool $pool
+        done
+
+       if [[ -n $saved_dump_dev ]]; then
+               log_must $DUMPADM -u -d $saved_dump_dev
+       fi
+
+        partition_disk $SIZE $disk 6
+}
+
+log_assert "'zpool create' should be failed with inapplicable scenarios."
+log_onexit cleanup
+
+if [[ -n $DISK ]]; then
+        disk=$DISK
+else
+        disk=$DISK0
+fi
+pooldev1=${disk}${SLICE_PREFIX}${SLICE0}
+pooldev2=${disk}${SLICE_PREFIX}${SLICE1}
+mirror1="${disk}${SLICE_PREFIX}${SLICE1} ${disk}${SLICE_PREFIX}${SLICE3}"
+mirror2="${disk}${SLICE_PREFIX}${SLICE4} ${disk}${SLICE_PREFIX}${SLICE5}"
+raidz1=$mirror1
+raidz2=$mirror2
+diff_size_dev="${disk}${SLICE_PREFIX}${SLICE6} ${disk}${SLICE_PREFIX}${SLICE7}"
+vfstab_dev=$(find_vfstab_dev)
+specified_dump_dev=${disk}${SLICE_PREFIX}${SLICE0}
+saved_dump_dev=$(save_dump_dev)
+
+cyl=$(get_endslice $disk $SLICE6)
+set_partition $SLICE7 "$cyl" $SIZE1 $disk
+create_pool "$TESTPOOL" "$pooldev1"
+
+#
+# Set up the testing scenarios parameters
+#
+set -A arg "$TESTPOOL $pooldev2" \
+        "$TESTPOOL1 $pooldev1" \
+        "$TESTPOOL1 $TESTDIR0/$FILEDISK0" \
+        "$TESTPOOL1 mirror mirror $mirror1 mirror $mirror2" \
+        "$TESTPOOL1 raidz raidz $raidz1 raidz $raidz2" \
+        "$TESTPOOL1 raidz1 raidz1 $raidz1 raidz1 $raidz2" \
+        "$TESTPOOL1 mirror raidz $raidz1 raidz $raidz2" \
+        "$TESTPOOL1 mirror raidz1 $raidz1 raidz1 $raidz2" \
+        "$TESTPOOL1 raidz mirror $mirror1 mirror $mirror2" \
+        "$TESTPOOL1 raidz1 mirror $mirror1 mirror $mirror2" \
+        "$TESTPOOL1 mirror $diff_size_dev" \
+        "$TESTPOOL1 raidz $diff_size_dev" \
+        "$TESTPOOL1 raidz1 $diff_size_dev" \
+       "$TESTPOOL1 mirror $mirror1 spare $mirror2 spare $diff_size_dev" \
+        "$TESTPOOL1 $vfstab_dev" \
+        "$TESTPOOL1 ${disk}s10" \
+       "$TESTPOOL1 spare $pooldev2"
+
+typeset -i i=0
+while (( i < ${#arg[*]} )); do
+        log_mustnot $ZPOOL create ${arg[i]}
+        (( i = i+1 ))
+done
+
+# now destroy the pool to be polite
+log_must $ZPOOL destroy -f $TESTPOOL
+
+# create/destroy a pool as a simple way to set the partitioning
+# back to something normal so we can use this $disk as a dump device
+log_must $ZPOOL create -f $TESTPOOL3 $disk
+log_must $ZPOOL destroy -f $TESTPOOL3
+
+log_must $DUMPADM -d ${DEV_DSKDIR}/$specified_dump_dev
+log_mustnot $ZPOOL create -f $TESTPOOL1 "$specified_dump_dev"
+
+# Also check to see that in-use checking prevents us from creating
+# a zpool from just the first slice on the disk.
+log_mustnot $ZPOOL create \
+       -f $TESTPOOL1 ${specified_dump_dev}${SLICE_PREFIX}${SLICE0}
+
+log_pass "'zpool create' is failed as expected with inapplicable scenarios."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_012_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_012_neg.ksh
new file mode 100755 (executable)
index 0000000..f3e438f
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+#
+# DESCRIPTION:
+# 'zpool create' will fail with formal disk slice in swap
+#
+#
+# STRATEGY:
+# 1. Get all the disk devices in swap
+# 2. For each device, try to create a new pool with this device
+# 3. Verify the creation is failed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if poolexists $TESTPOOL; then
+               destroy_pool $TESTPOOL
+       fi
+
+}
+typeset swap_disks=`$SWAP -l | $GREP "c[0-9].*d[0-9].*s[0-9]" | \
+            $AWK '{print $1}'`
+
+log_assert "'zpool create' should fail with disk slice in swap."
+log_onexit cleanup
+
+for sdisk in $swap_disks; do
+       for opt in "-n" "" "-f"; do
+               log_mustnot $ZPOOL create $opt $TESTPOOL $sdisk
+       done
+done
+
+log_pass "'zpool create' passed as expected with inapplicable scenario."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_014_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_014_neg.ksh
new file mode 100755 (executable)
index 0000000..ccc5b09
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+#
+# DESCRIPTION:
+# 'zpool create' will fail with ordinary file in swap
+#
+# STRATEGY:
+# 1. Create a regular file on top of UFS-zvol filesystem
+# 2. Try to create a new pool with regular file in swap
+# 3. Verify the creation is failed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if datasetexists $vol_name; then
+               $SWAP -l | $GREP $TMP_FILE > /dev/null 2>&1
+               if [[ $? -eq 0 ]]; then
+                       log_must $SWAP -d $TMP_FILE
+               fi
+               $RM -f $TMP_FILE
+               log_must $UMOUNT $mntp
+               $ZFS destroy $vol_name
+       fi
+
+       if poolexists $TESTPOOL; then
+               destroy_pool $TESTPOOL
+       fi
+}
+
+log_assert "'zpool create' should fail with regular file in swap."
+log_onexit cleanup
+
+if [[ -n $DISK ]]; then
+        disk=$DISK
+else
+        disk=$DISK0
+fi
+
+typeset pool_dev=${disk}${SLICE_PREFIX}${SLICE0}
+typeset vol_name=$TESTPOOL/$TESTVOL
+typeset mntp=/mnt
+typeset TMP_FILE=$mntp/tmpfile.$$
+
+create_pool $TESTPOOL $pool_dev
+log_must $ZFS create -V 100m $vol_name
+log_must $ECHO "y" | $NEWFS ${ZVOL_DEVDIR}/$vol_name > /dev/null 2>&1
+log_must $MOUNT ${ZVOL_DEVDIR}/$vol_name $mntp
+
+log_must $MKFILE 50m $TMP_FILE
+log_must $SWAP -a $TMP_FILE
+
+for opt in "-n" "" "-f"; do
+       log_mustnot $ZPOOL create $opt $TESTPOOL $TMP_FILE
+done
+
+log_pass "'zpool create' passed as expected with inapplicable scenario."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_015_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_015_neg.ksh
new file mode 100755 (executable)
index 0000000..c866c4d
--- /dev/null
@@ -0,0 +1,96 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+#
+# DESCRIPTION:
+# 'zpool create' will fail with zfs vol device in swap
+#
+#
+# STRATEGY:
+# 1. Create a zpool
+# 2. Create a zfs vol on zpool
+# 3. Add this zfs vol device to swap
+# 4. Try to create a new pool with devices in swap
+# 5. Verify the creation is failed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       # cleanup zfs pool and dataset
+       if datasetexists $vol_name; then
+               $SWAP -l | $GREP ${ZVOL_DEVDIR}/$vol_name > /dev/null 2>&1
+               if [[ $? -eq 0 ]]; then
+                       $SWAP -d ${ZVOL_DEVDIR}/${vol_name}
+               fi
+       fi
+
+       for pool in $TESTPOOL1 $TESTPOOL; do
+               if poolexists $pool; then
+                       destroy_pool $pool
+               fi
+       done
+
+}
+
+if [[ -n $DISK ]]; then
+        disk=$DISK
+else
+        disk=$DISK0
+fi
+
+typeset pool_dev=${disk}${SLICE_PREFIX}${SLICE0}
+typeset vol_name=$TESTPOOL/$TESTVOL
+
+log_assert "'zpool create' should fail with zfs vol device in swap."
+log_onexit cleanup
+
+#
+# use zfs vol device in swap to create pool which should fail.
+#
+create_pool $TESTPOOL $pool_dev
+log_must $ZFS create -V 100m $vol_name
+log_must $SWAP -a ${ZVOl_DEVDIR}/$vol_name
+for opt in "-n" "" "-f"; do
+       log_mustnot $ZPOOL create $opt $TESTPOOL1 ${ZVOL_DEVDIR}/${vol_name}
+done
+
+# cleanup
+log_must $SWAP -d ${ZVOL_DEVDIR}/${vol_name}
+log_must $ZFS destroy $vol_name
+log_must $ZPOOL destroy $TESTPOOL
+
+log_pass "'zpool create' passed as expected with inapplicable scenario."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_016_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_016_pos.ksh
new file mode 100755 (executable)
index 0000000..be8fb6f
--- /dev/null
@@ -0,0 +1,96 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+#
+# DESCRIPTION:
+# 'zpool create' will success with no device in swap
+#
+#
+# STRATEGY:
+# 1. delete all devices in the swap
+# 2. create a zpool
+# 3. Verify the creation is successed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if poolexists $TESTPOOL; then
+               destroy_pool $TESTPOOL
+       fi
+
+       #recover swap devices
+       FSTAB=/tmp/fstab_$$
+       $RM -f $FSTAB
+       for sdisk in $swap_disks; do
+               $ECHO "$sdisk   -       -       swap    -       no      -" >> $FSTAB
+       done
+       if [ -e $FSTAB ]
+       then
+               log_must $SWAPADD $FSTAB
+       fi
+       $RM -f $FSTAB
+       if [ $dump_device != "none" ]
+       then
+               log_must $DUMPADM -u -d $dump_device
+       fi
+}
+
+if [[ -n $DISK ]]; then
+       disk=$DISK
+else
+       disk=$DISK0
+fi
+typeset pool_dev=${disk}${SLICE_PREFIX}${SLICE0}
+typeset swap_disks=$($SWAP -l | $GREP -v "swapfile" | $AWK '{print $1}')
+typeset dump_device=$($DUMPADM | $GREP "Dump device" | $AWK '{print $3}')
+
+log_assert "'zpool create' should success with no device in swap."
+log_onexit cleanup
+
+for sdisk in $swap_disks; do
+       log_note "Executing: swap -d $sdisk"
+       $SWAP -d $sdisk >/dev/null 2>&1;
+       if [[ $? != 0 ]]; then
+               log_untested "Unable to delete swap device $sdisk because of" \
+                               "insufficient RAM"
+       fi
+done
+
+log_must $ZPOOL create $TESTPOOL $pool_dev
+log_must $ZPOOL destroy $TESTPOOL
+
+log_pass "'zpool create' passed as expected with applicable scenario."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_017_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_017_neg.ksh
new file mode 100755 (executable)
index 0000000..14cbf98
--- /dev/null
@@ -0,0 +1,90 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+#
+# DESCRIPTION:
+# 'zpool create' will fail with mountpoint exists and is not empty.
+#
+#
+# STRATEGY:
+# 1. Prepare the mountpoint put some stuff into it.
+# 2. Verify 'zpool create' over that mountpoint fails.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if poolexists $TESTPOOL; then
+               destroy_pool $TESTPOOL
+       fi
+
+       if [[ -d $TESTDIR ]]; then
+               log_must $RM -rf $TESTDIR
+       fi
+}
+
+if [[ -n $DISK ]]; then
+        disk=$DISK
+else
+        disk=$DISK0
+fi
+
+typeset pool_dev=${disk}${SLICE_PREFIX}${SLICE0}
+
+log_assert "'zpool create' should fail with mountpoint exists and not empty."
+log_onexit cleanup
+
+if [[ ! -d $TESTDIR ]]; then
+       log_must $MKDIR -p $TESTDIR
+fi
+
+typeset -i i=0
+
+while (( i < 2 )); do
+       log_must $RM -rf $TESTDIR/*
+       if (( i == 0 )); then
+               log_must $MKDIR $TESTDIR/testdir
+       else
+               log_must $TOUCH $TESTDIR/testfile
+       fi
+
+       log_mustnot $ZPOOL create -m $TESTDIR -f $TESTPOOL $pool_dev
+       log_mustnot poolexists $TESTPOOL
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool create' fail as expected with mountpoint exists and not empty."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_018_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_018_pos.ksh
new file mode 100755 (executable)
index 0000000..a42edff
--- /dev/null
@@ -0,0 +1,104 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+#
+# zpool create can create pools with specified properties
+#
+# STRATEGY:
+# 1. Create a pool with all editable properties
+# 2. Verify those properties are set
+# 3. Create a pool with two properties set
+# 4. Verify both properties are set correctly
+#
+
+function cleanup
+{
+       poolexists $TESTPOOL && destroy_pool $TESTPOOL
+       [[ -f $CPATH ]] && log_must $RM $CPATH
+}
+
+log_onexit cleanup
+log_assert "zpool create can create pools with specified properties"
+
+if [[ -n $DISK ]]; then
+       disk=$DISK
+else
+       disk=$DISK0
+fi
+
+#
+# we don't include "root" property in this list, as it requires both "cachefile"
+# and "root" to be set at the same time. A test for this is included in
+# ../../root.
+#
+typeset props=("autoreplace" "delegation" "cachefile" "version" "autoexpand")
+typeset vals=("off" "off" "$CPATH" "3" "on")
+
+typeset -i i=0;
+while [ $i -lt "${#props[@]}" ]
+do
+       log_must $ZPOOL create -o ${props[$i]}=${vals[$i]} $TESTPOOL $disk
+       RESULT=$(get_pool_prop ${props[$i]} $TESTPOOL)
+       if [[ $RESULT != ${vals[$i]} ]]
+       then
+               $ZPOOL get all $TESTPOOL
+               log_fail "Pool was created without setting the ${props[$i]} " \
+                   "property"
+       fi
+       log_must $ZPOOL destroy $TESTPOOL
+       ((i = i + 1))
+done
+
+# Destroy our pool
+poolexists $TESTPOOL && destroy_pool $TESTPOOL
+
+# pick two properties, and verify we can create with those as well
+log_must $ZPOOL create -o delegation=off -o cachefile=$CPATH $TESTPOOL $disk
+RESULT=$(get_pool_prop delegation $TESTPOOL)
+if [[ $RESULT != off ]]
+then
+       $ZPOOL get all $TESTPOOL
+       log_fail "Pool created without the delegation prop."
+fi
+
+RESULT=$(get_pool_prop cachefile $TESTPOOL)
+if [[ $RESULT != $CPATH ]]
+then
+       $ZPOOL get all $TESTPOOL
+       log_fail "Pool created without the cachefile prop."
+fi
+
+log_pass "zpool create can create pools with specified properties"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_019_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_019_pos.ksh
new file mode 100755 (executable)
index 0000000..277b91e
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# zpool create cannot create pools specifying readonly properties
+#
+# STRATEGY:
+# 1. Attempt to create a pool, specifying each readonly property in turn
+# 2. Verify the pool was not created
+#
+
+function cleanup
+{
+       if poolexists $TESTPOOL ; then
+                destroy_pool $TESTPOOL
+        fi
+}
+
+log_onexit cleanup
+
+log_assert "zpool create cannot create pools specifying readonly properties"
+
+if [[ -n $DISK ]]; then
+       disk=$DISK
+else
+       disk=$DISK0
+fi
+
+set -A props "available" "capacity" "guid"  "health"  "size" "used"
+set -A vals  "100"       "10"       "12345" "HEALTHY" "10"   "10"
+
+typeset -i i=0;
+while [ $i -lt "${#props[@]}" ]
+do
+        # try to set each property in the prop list with it's corresponding val
+        log_mustnot $ZPOOL create -o ${props[$i]}=${vals[$i]} $TESTPOOL $disk
+       if poolexists $TESTPOOL
+       then
+               log_fail "$TESTPOOL was created when setting ${props[$i]}!"
+       fi
+        i=$(( $i + 1))
+done
+
+log_pass "zpool create cannot create pools specifying readonly properties"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_020_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_020_pos.ksh
new file mode 100755 (executable)
index 0000000..2ab2f50
--- /dev/null
@@ -0,0 +1,111 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool create -R works as expected
+#
+# STRATEGY:
+# 1. Create a -R altroot pool
+# 2. Verify the pool is mounted at the correct location
+# 3. Verify that cachefile=none for the pool
+# 4. Verify that root=<mountpoint> for the pool
+# 5. Verify that no reference to the pool is found in /etc/zfs/zpool.cache
+
+function cleanup
+{
+       if poolexists $TESTPOOL ; then
+                destroy_pool $TESTPOOL
+        fi
+       if [ -d ${TESTPOOL}.root ]
+       then
+               log_must $RMDIR ${TESTPOOL}.root
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "zpool create -R works as expected"
+
+if [[ -n $DISK ]]; then
+       disk=$DISK
+else
+       disk=$DISK0
+fi
+
+log_must $MKDIR /${TESTPOOL}.root
+log_must $ZPOOL create -R /${TESTPOOL}.root $TESTPOOL $disk
+if [ ! -d /${TESTPOOL}.root ]
+then
+       log_fail "Mountpoint was not create when using zpool with -R flag!"
+fi
+
+FS=$($ZFS list $TESTPOOL)
+if [ -z "$FS" ]
+then
+       log_fail "Mounted filesystem at /${TESTPOOL}.root isn't ZFS!"
+fi
+
+log_must $ZPOOL get all $TESTPOOL
+$ZPOOL get all $TESTPOOL > /tmp/values.$$
+
+# check for the cachefile property, verifying that it's set to 'none'
+$GREP "$TESTPOOL[ ]*cachefile[ ]*none" /tmp/values.$$ > /dev/null 2>&1
+if [ $? -ne 0 ]
+then
+       log_fail "zpool property \'cachefile\' was not set to \'none\'."
+fi
+
+# check that the root = /mountpoint property is set correctly
+$GREP "$TESTPOOL[ ]*altroot[ ]*/${TESTPOOL}.root" /tmp/values.$$ > /dev/null 2>&1
+if [ $? -ne 0 ]
+then
+       log_fail "zpool property root was not found in pool output."
+fi
+
+$RM /tmp/values.$$
+
+# finally, check that the pool has no reference in /etc/zfs/zpool.cache
+if [[ -f /etc/zfs/zpool.cache ]] ; then
+       REF=$($STRINGS /etc/zfs/zpool.cache | $GREP ${TESTPOOL})
+       if [ ! -z "$REF" ]
+       then
+               $STRINGS /etc/zfs/zpool.cache
+               log_fail "/etc/zfs/zpool.cache appears to have a reference to $TESTPOOL"
+       fi
+fi
+
+
+log_pass "zpool create -R works as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_021_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_021_pos.ksh
new file mode 100755 (executable)
index 0000000..df40f40
--- /dev/null
@@ -0,0 +1,89 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create -O property=value pool' can successfully create a pool
+# with correct filesystem property set.
+#
+# STRATEGY:
+# 1. Create a storage pool with -O option
+# 2. Verify the pool created successfully
+# 3. Verify the filesystem property is correctly set
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL && destroy_pool $TESTPOOL
+}
+
+log_onexit cleanup
+
+log_assert "'zpool create -O property=value pool' can successfully create a pool \
+               with correct filesystem property set."
+
+set -A RW_FS_PROP "quota=512M" \
+                 "reservation=512M" \
+                 "recordsize=64K" \
+                 "mountpoint=/tmp/mnt$$" \
+                 "checksum=fletcher2" \
+                 "compression=lzjb" \
+                 "atime=off" \
+                 "devices=off" \
+                 "exec=off" \
+                 "setuid=off" \
+                 "readonly=on" \
+                 "snapdir=visible" \
+                 "acltype=posixacl" \
+                 "aclinherit=discard" \
+                 "canmount=off" \
+                 "zoned=on"
+
+typeset -i i=0
+while (( $i < ${#RW_FS_PROP[*]} )); do
+       log_must $ZPOOL create -O ${RW_FS_PROP[$i]} -f $TESTPOOL $DISKS
+       datasetexists $TESTPOOL || \
+               log_fail "zpool create $TESTPOOL fail."
+       propertycheck $TESTPOOL ${RW_FS_PROP[i]} || \
+               log_fail "${RW_FS_PROP[i]} is failed to set."
+       log_must $ZPOOL destroy $TESTPOOL
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool create -O property=value pool' can successfully create a pool \
+               with correct filesystem property set."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_022_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_022_pos.ksh
new file mode 100755 (executable)
index 0000000..2186d6c
--- /dev/null
@@ -0,0 +1,95 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_create/zfs_create_common.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create -O property=value pool' can successfully create a pool
+# with multiple filesystem properties set.
+#
+# STRATEGY:
+# 1. Create a storage pool with multiple -O options
+# 2. Verify the pool created successfully
+# 3. Verify the properties are correctly set
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL && log_must $ZPOOL destroy $TESTPOOL
+}
+
+log_onexit cleanup
+
+log_assert "'zpool create -O property=value pool' can successfully create a pool \
+               with multiple filesystem properties set."
+
+set -A RW_FS_PROP "quota=512M" \
+                 "reservation=512M" \
+                 "recordsize=64K" \
+                 "mountpoint=/tmp/mnt$$" \
+                 "checksum=fletcher2" \
+                 "compression=lzjb" \
+                 "atime=off" \
+                 "devices=off" \
+                 "exec=off" \
+                 "setuid=off" \
+                 "readonly=on" \
+                 "snapdir=visible" \
+                 "acltype=posixacl" \
+                 "aclinherit=discard" \
+                 "canmount=off"
+
+typeset -i i=0
+typeset opts=""
+
+while (( $i < ${#RW_FS_PROP[*]} )); do
+       opts="$opts -O ${RW_FS_PROP[$i]}"
+       (( i = i + 1 ))
+done
+
+log_must $ZPOOL create $opts -f $TESTPOOL $DISKS
+datasetexists $TESTPOOL || log_fail "zpool create $TESTPOOL fail."
+
+i=0
+while (( $i < ${#RW_FS_PROP[*]} )); do
+       propertycheck $TESTPOOL ${RW_FS_PROP[i]} || \
+                       log_fail "${RW_FS_PROP[i]} is failed to set."
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool create -O property=value pool' can successfully create a pool \
+               with multiple filesystem properties set."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_023_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_023_neg.ksh
new file mode 100755 (executable)
index 0000000..3b0f674
--- /dev/null
@@ -0,0 +1,85 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# 'zpool create -O' should return an error with badly formed parameters.
+#
+# STRATEGY:
+# 1. Create an array of parameters with '-O'
+# 2. For each parameter in the array, execute 'zpool create -O'
+# 3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL && log_must $ZPOOL destroy $TESTPOOL
+}
+
+log_onexit cleanup
+
+set -A args "QuOta=none" "quota=non" "quota=abcd" "quota=0" "quota=" \
+    "ResErVaTi0n=none" "reserV=none" "reservation=abcd" "reserv=" \
+    "recorDSize=64k" "recordsize=2M" "recordsize=2048K" \
+    "recordsize=256" "recsize=" "recsize=zero" "recordsize=0" \
+    "mountPoint=/tmp/tmpfile$$" "mountpoint=non0" "mountpoint=" \
+    "mountpoint=LEGACY" "mounpoint=none" \
+    "sharenfs=ON" "ShareNFS=off" "sharenfs=sss" \
+    "checkSUM=on" "checksum=SHA256" "chsum=off" "checksum=aaa" \
+    "compression=of" "ComPression=lzjb" "compress=ON" "compress=a" \
+    "atime=ON" "ATime=off" "atime=bbb" \
+    "deviCes=on" "devices=OFF" "devices=aaa" \
+    "exec=ON" "EXec=off" "exec=aaa" \
+    "readonly=ON" "reADOnly=off" "rdonly=OFF" "rdonly=aaa" \
+    "zoned=ON" "ZoNed=off" "zoned=aaa" \
+    "snapdIR=hidden" "snapdir=VISible" "snapdir=aaa" \
+    "acltype=DIScard" "acltYPE=groupmask" "acltype=aaa" \
+    "aclinherit=deny" "aclinHerit=secure" "aclinherit=aaa" \
+    "type=volume" "type=snapshot" "type=filesystem" \
+    "creation=aaa" "used=10K" "available=10K" \
+    "referenced=10K" "compressratio=1.00x" \
+    "version=0" "version=1.234" "version=10K" "version=-1" \
+    "version=aaa" "version=999"
+
+log_assert "'zpool create -O' should return an error with badly formed parameters."
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZPOOL create -O ${args[i]} -f $TESTPOOL $DISKS
+       ((i = i + 1))
+done
+
+log_pass "'zpool create -O' should return an error with badly formed parameters."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_024_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_024_pos.ksh
new file mode 100755 (executable)
index 0000000..1fa22d6
--- /dev/null
@@ -0,0 +1,148 @@
+#!/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 (c) 2016, Lawrence Livermore National Security, LLC.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.cfg
+
+#
+# DESCRIPTION:
+# Many 'zpool create' and 'zpool destroy' must succeed concurrently.
+#
+# STRATEGY:
+# 1. Create N process each of which create/destroy a pool M times.
+# 2. Allow all process to run to completion.
+# 3. Verify all pools and their vdevs were destroyed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if [[ -n "$child_pids" ]]; then
+               for wait_pid in $child_pids; do
+                       $KILL $wait_pid 2>/dev/null
+               done
+       fi
+
+       if [[ -n "$child_pools" ]]; then
+               for pool in $child_pools; do
+                       typeset vdev0="$TEST_BASE_DIR/$pool-vdev0.img"
+                       typeset vdev1="$TEST_BASE_DIR/$pool-vdev1.img"
+
+                       if poolexists $pool; then
+                               destroy_pool $pool
+                       fi
+
+                       $RM -f $vdev0 $vdev1
+               done
+       fi
+}
+
+log_onexit cleanup
+
+log_assert "Many 'zpool create' and 'zpool destroy' must succeed concurrently."
+
+child_pids=""
+child_pools=""
+
+function zpool_stress
+{
+       typeset pool=$1
+       typeset vdev0="$TEST_BASE_DIR/$pool-vdev0.img"
+       typeset vdev1="$TEST_BASE_DIR/$pool-vdev1.img"
+       typeset -i iters=$2
+       typeset retry=10
+       typeset j=0
+
+       $TRUNCATE -s $FILESIZE $vdev0
+       $TRUNCATE -s $FILESIZE $vdev1
+
+       while [[ $j -lt $iters ]]; do
+               ((j = j + 1))
+               $SLEEP 1
+
+               $ZPOOL create $pool $vdev0 $vdev1
+               if [ $? -ne 0 ]; then
+                       return 1;
+               fi
+
+               # The 'zfs destroy' command is retried because it can
+               # transiently return EBUSY when blkid is concurrently
+               # probing new volumes and therefore has them open.
+               typeset k=0;
+               while [[ $k -lt $retry ]]; do
+                       ((k = k + 1))
+
+                       $ZPOOL destroy $pool
+                       if [ $? -eq 0 ]; then
+                               break;
+                       elif [ $k -eq $retry ]; then
+                               return 1;
+                       fi
+
+                       $SLEEP 3
+               done
+       done
+
+       $RM -f $vdev0 $vdev1
+       return 0
+}
+
+# 1. Create 128 process each of which create/destroy a pool 5 times.
+typeset i=0
+while [[ $i -lt 128 ]]; do
+       typeset uuid=$($UUIDGEN | $CUT -c1-13)
+
+       zpool_stress $TESTPOOL-$uuid 5 &
+       typeset pid=$!
+
+       child_pids="$child_pids $pid"
+       child_pools="$child_pools $TESTPOOL-$uuid"
+       ((i = i + 1))
+done
+
+# 2. Allow all process to run to completion.
+wait
+
+# 3. Verify all pools and their vdevs were destroyed.
+for pool in $child_pools; do
+       typeset vdev0="$TEST_BASE_DIR/$pool-vdev0.img"
+       typeset vdev1="$TEST_BASE_DIR/$pool-vdev1.img"
+
+       if poolexists $pool; then
+               log_fail "pool $pool exists"
+       fi
+
+       if [ -e $vdev0 ]; then
+               log_fail "pool vdev $vdev0 exists"
+       fi
+
+       if [ -e $vdev1 ]; then
+               log_fail "pool vdev $vdev1 exists"
+       fi
+done
+
+log_pass "Many 'zpool create' and 'zpool destroy' must succeed concurrently."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_001_pos.ksh
new file mode 100755 (executable)
index 0000000..746c504
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+################################################################################
+#
+#  Newly created pools should have all features enabled.
+#  Specifying a feature to be enabled with '-o' should be a no-op.
+#
+#  1. Create a new pool.
+#  2. Verify that every feature@ property is in the 'enabled' or 'active' state
+#  3. Destroy the pool and create a new pool with
+#     '-o feature@async_destroy=enabled'
+#  4. Verify again.
+#
+################################################################################
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL && log_must $ZPOOL destroy $TESTPOOL
+}
+
+function check_features
+{
+       for state in $($ZPOOL get all $TESTPOOL | \
+           $AWK '$2 ~ /feature@/ { print $3 }'); do
+               if [[ "$state" != "enabled" && "$state" != "active" ]]; then
+                       log_fail "some features are not enabled on new pool"
+               fi
+       done
+}
+
+log_onexit cleanup
+
+log_assert "'zpool create' creates pools with all features enabled"
+
+log_must $ZPOOL create -f $TESTPOOL $DISKS
+check_features
+log_must $ZPOOL destroy -f $TESTPOOL
+
+log_must $ZPOOL create -f -o feature@async_destroy=enabled $TESTPOOL $DISKS
+check_features
+
+log_pass "'zpool create' creates pools with all features enabled"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_002_pos.ksh
new file mode 100755 (executable)
index 0000000..f0e2086
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+################################################################################
+#
+#  When using the '-d' option or specifying '-o version=X' new pools should
+#  have all features disabled.
+#
+#  1. Create a new pool with '-d'.
+#  2. Verify that every feature@ property is in the 'disabled' state
+#  3. Destroy pool and re-create with -o version=28
+#  4. Verify again.
+#
+################################################################################
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL && log_must $ZPOOL destroy $TESTPOOL
+}
+
+function check_features
+{
+       for prop in $($ZPOOL get all $TESTPOOL | $AWK '$2 ~ /feature@/ { print $2 }'); do
+               state=$($ZPOOL list -Ho "$prop" $TESTPOOL)
+                if [[ "$state" != "disabled" ]]; then
+                       log_fail "$prop is enabled on new pool"
+               fi
+       done
+}
+
+log_onexit cleanup
+
+log_assert "'zpool create -d' creates pools with all features disabled"
+
+log_must $ZPOOL create -f -d $TESTPOOL $DISKS
+check_features
+log_must $ZPOOL destroy -f $TESTPOOL
+
+log_must $ZPOOL create -f -o version=28 $TESTPOOL $DISKS
+check_features
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_003_pos.ksh
new file mode 100755 (executable)
index 0000000..9d45dfd
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+################################################################################
+#
+#  When using the '-d' option with '-o feature@XXX=enabled' only the specified
+#  feature is enabled.
+#
+#  1. Create a new pool with '-d' and '-o feature@async_destroy=enabled'.
+#     async_destroy does not depend on anything so it should be the only
+#     feature that gets enabled.
+#  2. Verify that every feature@ property except feature@async_destroy is in
+#     the 'disabled' state
+#
+################################################################################
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL && log_must $ZPOOL destroy $TESTPOOL
+}
+
+log_onexit cleanup
+
+log_assert "'zpool create -d -o feature@async_destroy=enabled' only " \
+    "enables async_destroy"
+
+log_must $ZPOOL create -f -d -o feature@async_destroy=enabled $TESTPOOL $DISKS
+
+state=$($ZPOOL list -Ho feature@async_destroy $TESTPOOL)
+if [[ "$state" != "enabled" ]]; then
+       log_fail "async_destroy has state $state"
+fi
+
+for prop in $($ZPOOL get all $TESTPOOL | $AWK '$2 ~ /feature@/ { print $2 }'); do
+       state=$($ZPOOL list -Ho "$prop" $TESTPOOL)
+       if [[ "$prop" != "feature@async_destroy" \
+           && "$state" != "disabled" ]]; then
+               log_fail "$prop is enabled on new pool"
+        fi
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_004_neg.ksh
new file mode 100755 (executable)
index 0000000..2b465d5
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+################################################################################
+#
+#  Specifying invalid feature names/states should cause the create to fail.
+#
+#  1. Try to create the pool with a variety of invalid feature names/states.
+#  2. Verify no pool was created.
+#
+################################################################################
+
+verify_runnable "global"
+
+properties="\
+feature@async_destroy=disable \
+feature@async_destroy=active \
+feature@xxx_fake_xxx=enabled \
+unsupported@some_feature=inactive \
+unsupported@some_feature=readonly \
+"
+
+function cleanup
+{
+       datasetexists $TESTPOOL && log_must $ZPOOL destroy $TESTPOOL
+}
+
+log_assert "'zpool create' with invalid feature names/states fails"
+log_onexit cleanup
+
+for prop in $properties; do
+       log_mustnot $ZPOOL create -f -o "$prop" $TESTPOOL $DISKS
+       log_mustnot datasetexists $TESTPOOL
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_create/zpool_create_features_005_pos.ksh
new file mode 100755 (executable)
index 0000000..488f11c
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib
+
+################################################################################
+#
+# Specifically disabling a feature, all other features should be enabled.
+#
+# 1. Loop through all existing features:
+#    a. Create a new pool with '-o feature@XXX=disabled'.
+#    b. Verify that every other feature is 'enabled' or 'active'.
+#
+################################################################################
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL && log_must $ZPOOL destroy $TESTPOOL
+}
+
+function check_features
+{
+       typeset feature="${1}"
+
+       ${ZPOOL} get all ${TESTPOOL} | $GREP feature@ | while read line; do
+               set -- $(echo "${line}")
+
+               if [[ "feature@${feature}" == "${2}" ]]; then
+                       # Failure passed feature must be disabled.
+                       if [[ "${3}" != "disabled" ]]; then
+                               return 1;
+                       fi
+               else
+                       # Failure other features must be enabled or active.
+                       if [[ "${3}" != "enabled" && "${3}" != "active" ]]; then
+                               return 2;
+                       fi
+               fi
+       done
+
+       # All features enabled or active except the expected one.
+       return 0
+}
+
+log_onexit cleanup
+
+# Several representative features are tested to keep the test time short.
+# The features 'extensible_dataset' and 'enabled_txg' are intentionally
+# excluded because other features depend on them.
+set -A features \
+    "hole_birth" \
+    "large_blocks"  \
+    "large_dnode" \
+    "userobj_accounting"
+
+typeset -i i=0
+while (( $i < ${#features[*]} )); do
+       log_assert "'zpool create' creates pools with ${features[i]} disabled"
+
+       log_must $ZPOOL create -f -o "feature@${features[i]}=disabled" \
+           $TESTPOOL $DISKS
+       log_must check_features "${features[i]}"
+       log_must $ZPOOL destroy -f $TESTPOOL
+       (( i = i+1 ))
+done
+
+log_pass "'zpool create -o feature@feature=disabled' disables features"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/Makefile.am
new file mode 100644 (file)
index 0000000..5130bcc
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_destroy
+dist_pkgdata_SCRIPTS = \
+       zpool_destroy.cfg \
+       zpool_destroy_001_pos.ksh \
+       zpool_destroy_002_pos.ksh \
+       zpool_destroy_003_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy.cfg
new file mode 100644 (file)
index 0000000..e9d8831
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+export DISK=${DISKS%% *}
+
+if is_linux; then
+       set_device_dir
+       set_slice_prefix
+       export SLICE0=1
+       export SLICE1=2
+else
+       export SLICE_PREFIX="s"
+       export SLICE0=0
+       export SLICE1=1
+
+fi
+export SLICE_SIZE=500m
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_001_pos.ksh
new file mode 100755 (executable)
index 0000000..d87d7fc
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_destroy/zpool_destroy.cfg
+
+
+#
+# DESCRIPTION:
+#      'zpool destroy <pool>' can successfully destroy the specified pool.
+#
+# STRATEGY:
+#      1. Create a storage pool
+#      2. Destroy the pool
+#      3. Verify the is destroyed successfully
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL2 && destroy_pool $TESTPOOL2
+       datasetexists $TESTPOOL1/$TESTVOL && \
+               log_must $ZFS destroy -f $TESTPOOL1/$TESTVOL
+
+       typeset pool
+       for pool in $TESTPOOL1 $TESTPOOL; do
+               poolexists $pool && destroy_pool $pool
+       done
+
+       zero_partitions $DISK
+}
+
+set -A datasets "$TESTPOOL" "$TESTPOOL2"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This case cannot be run on raw files."
+fi
+
+log_assert "'zpool destroy <pool>' can destroy a specified pool."
+
+log_onexit cleanup
+
+partition_disk $SLICE_SIZE $DISK 2
+
+create_pool "$TESTPOOL" "${DISK}${SLICE_PREFIX}${SLICE0}"
+create_pool "$TESTPOOL1" "${DISK}${SLICE_PREFIX}${SLICE1}"
+log_must $ZFS create -s -V $VOLSIZE $TESTPOOL1/$TESTVOL
+create_pool "$TESTPOOL2" "${ZVOL_DEVDIR}/$TESTPOOL1/$TESTVOL"
+
+typeset -i i=0
+while (( i < ${#datasets[*]} )); do
+       log_must poolexists "${datasets[i]}"
+       log_must $ZPOOL destroy "${datasets[i]}"
+       log_mustnot poolexists "${datasets[i]}"
+       ((i = i + 1))
+done
+
+log_pass "'zpool destroy <pool>' executes successfully"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_002_pos.ksh
new file mode 100755 (executable)
index 0000000..682e9c0
--- /dev/null
@@ -0,0 +1,117 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_destroy/zpool_destroy.cfg
+
+#
+# DESCRIPTION:
+#      'zpool destroy -f <pool>' can forcely destroy the specified pool.
+#
+# STRATEGY:
+#      1. Create a storage pool
+#      2. Create some datasets within the pool
+#      3. Change directory to any mountpoint of these datasets,
+#         Verify 'zpool destroy' without '-f' will fail.
+#      4. 'zpool destroy -f' the pool
+#      5. Verify the pool is destroyed successfully
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       [[ -n $cwd ]] && log_must cd $cwd
+
+       if [[ -d $TESTDIR ]]; then
+               ismounted $TESTDIR
+               ((  $? == 0 )) && \
+                       log_must $UNMOUNT $TESTDIR
+               log_must $RM -rf $TESTDIR
+       fi
+
+       typeset -i i=0
+       while (( $i < ${#datasets[*]} )); do
+               datasetexists ${datasets[i]} && \
+                       log_must $ZFS destroy ${datasets[i]}
+               (( i = i + 1 ))
+       done
+
+       poolexists $TESTPOOL && destroy_pool $TESTPOOL
+}
+
+set -A datasets "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTCTR/$TESTFS1" \
+       "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTVOL" \
+
+log_assert "'zpool destroy -f <pool>' can forcely destroy the specified pool"
+
+log_onexit cleanup
+
+typeset cwd=""
+
+create_pool "$TESTPOOL" "$DISK"
+log_must $ZFS create $TESTPOOL/$TESTFS
+log_must $MKDIR -p $TESTDIR
+log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+log_must $ZFS create $TESTPOOL/$TESTCTR
+log_must $ZFS create $TESTPOOL/$TESTCTR/$TESTFS1
+log_must $ZFS create -V $VOLSIZE $TESTPOOL/$TESTVOL
+
+typeset -i i=0
+while (( $i < ${#datasets[*]} )); do
+       datasetexists "${datasets[i]}" || \
+               log_fail "Create datasets fail."
+       ((i = i + 1))
+done
+
+cwd=$PWD
+log_note "'zpool destroy' without '-f' will fail " \
+       "while pool is busy."
+
+for dir in $TESTDIR /$TESTPOOL/$TESTCTR /$TESTPOOL/$TESTCTR/$TESTFS1 ; do
+       log_must cd $dir
+       log_mustnot $ZPOOL destroy $TESTPOOL
+
+       # Need mount here, otherwise some dataset may be unmounted.
+       log_must $ZFS mount -a
+
+       i=0
+       while (( i < ${#datasets[*]} )); do
+               datasetexists "${datasets[i]}" || \
+                       log_fail "Dataset ${datasets[i]} removed unexpected."
+               ((i = i + 1))
+       done
+done
+
+destroy_pool $TESTPOOL
+log_mustnot poolexists "$TESTPOOL"
+
+log_pass "'zpool destroy -f <pool>' success."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_destroy/zpool_destroy_003_neg.ksh
new file mode 100755 (executable)
index 0000000..fb104f1
--- /dev/null
@@ -0,0 +1,52 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#       'zpool destroy' should return an error with badly formed parameters,
+#
+# STRATEGY:
+#      1. Create an array of parameters
+#      2. For each parameter in the array, execute 'zpool destroy'
+#      3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+set -A args "" "-f" "-? $TESTPOOL" "nonexistent_pool" \
+       "$TESTPOOL abcd" "abcd $TESTPOOL"
+
+log_assert "'zpool destroy' should return an error with badly-formed parameters."
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZPOOL destroy ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "'zpool destroy' badly formed parameters fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/Makefile.am
new file mode 100644 (file)
index 0000000..b22018c
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_detach
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_detach_001_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/cleanup.ksh
new file mode 100755 (executable)
index 0000000..89c1462
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/setup.ksh
new file mode 100755 (executable)
index 0000000..2229f87
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+DISK=${DISKS%% *}
+
+default_mirror_setup $DISKS
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/zpool_detach_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_detach/zpool_detach_001_neg.ksh
new file mode 100755 (executable)
index 0000000..848ce8c
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool detach' command with bad options fails.
+#
+# STRATEGY:
+# 1. Create an array of badly formed 'zpool detach' options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "global"
+
+DISKLIST=$(get_disklist $TESTPOOL)
+
+set -A args "" "-?" "-t fakepool" "-f fakepool" "-ev fakepool" "fakepool" \
+       "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTFS $DISKLIST" \
+       "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTCTR/$TESTFS1" \
+       "$TESTPOOL/$TESTCTR $DISKLIST" "$TESTPOOL/$TESTVOL" \
+       "$TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" "$TESTPOOL/$TESTVOL $DISKLIST" \
+       "$DISKLIST"
+
+log_assert "Executing 'zpool detach' with bad options fails"
+
+if [[ -z $DISKLIST ]]; then
+       log_fail "DISKLIST is empty."
+fi
+
+typeset -i i=0
+
+while [[ $i -lt ${#args[*]} ]]; do
+
+       log_mustnot $ZPOOL detach ${args[$i]}
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool detach' command with bad options failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/Makefile.am
new file mode 100644 (file)
index 0000000..dc90f9f
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_expand
+dist_pkgdata_SCRIPTS = \
+       zpool_expand.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_expand_001_pos.ksh \
+       zpool_expand_002_pos.ksh \
+       zpool_expand_003_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/cleanup.ksh
new file mode 100755 (executable)
index 0000000..d00826b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/setup.ksh
new file mode 100755 (executable)
index 0000000..2069e97
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand.cfg
new file mode 100644 (file)
index 0000000..16df1d9
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+
+export org_size=1g
+export exp_size=2g
+
+export VFS=$TESTPOOL/$TESTFS
+
+export EX_1GB=1073741824
+export EX_3GB=3221225472
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_001_pos.ksh
new file mode 100755 (executable)
index 0000000..a063b08
--- /dev/null
@@ -0,0 +1,146 @@
+#! /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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_expand/zpool_expand.cfg
+
+#
+# DESCRIPTION:
+# Once zpool set autoexpand=on poolname, zpool can autoexpand by
+# Dynamic LUN Expansion
+#
+#
+# STRATEGY:
+# 1) Create a pool
+# 2) Create volume on top of the pool
+# 3) Create pool by using the zvols and set autoexpand=on
+# 4) Expand the vol size by 'zfs set volsize'
+# 5) Check that the pool size was expanded
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if poolexists $TESTPOOL1; then
+               log_must $ZPOOL destroy $TESTPOOL1
+       fi
+
+       for i in 1 2 3; do
+               if datasetexists $VFS/vol$i; then
+                       log_must $ZFS destroy $VFS/vol$i
+               fi
+       done
+}
+
+log_onexit cleanup
+
+log_assert "zpool can be autoexpanded after set autoexpand=on on LUN expansion"
+
+for i in 1 2 3; do
+       log_must $ZFS create -V $org_size $VFS/vol$i
+done
+
+for type in " " mirror raidz raidz2; do
+
+       log_must $ZPOOL create -o autoexpand=on $TESTPOOL1 $type \
+           ${ZVOL_DEVDIR}/$VFS/vol1  ${ZVOL_DEVDIR}/$VFS/vol2 \
+           ${ZVOL_DEVDIR}/$VFS/vol3
+
+       typeset autoexp=$(get_pool_prop autoexpand $TESTPOOL1)
+       if [[ $autoexp != "on" ]]; then
+               log_fail "zpool $TESTPOOL1 autoexpand should on but is $autoexp"
+       fi
+
+       typeset prev_size=$(get_pool_prop size $TESTPOOL1)
+       typeset zfs_prev_size=$($ZFS get -p avail $TESTPOOL1 | $TAIL -1 | \
+           $AWK '{print $3}')
+
+       for i in 1 2 3; do
+               log_must $ZFS set volsize=$exp_size $VFS/vol$i
+       done
+
+       $SYNC
+       $SLEEP 10
+       $SYNC
+
+       typeset expand_size=$(get_pool_prop size $TESTPOOL1)
+       typeset zfs_expand_size=$($ZFS get -p avail $TESTPOOL1 | $TAIL -1 | \
+           $AWK '{print $3}')
+
+       log_note "$TESTPOOL1 $type has previous size: $prev_size and " \
+           "expanded size: $expand_size"
+       # compare available pool size from zfs
+       if [[ $zfs_expand_size > $zfs_prev_size ]]; then
+       # check for zpool history for the pool size expansion
+               if [[ $type == " " ]]; then
+                       typeset size_addition=$($ZPOOL history -il $TESTPOOL1 |\
+                           $GREP "pool '$TESTPOOL1' size:" | \
+                           $GREP "vdev online" | \
+                           $GREP "(+${EX_1GB}" | wc -l)
+
+                       if [[ $size_addition -ne $i ]]; then
+                               log_fail "pool $TESTPOOL1 is not autoexpand " \
+                                   "after LUN expansion"
+                       fi
+               elif [[ $type == "mirror" ]]; then
+                       $ZPOOL history -il $TESTPOOL1 | \
+                           $GREP "pool '$TESTPOOL1' size:" | \
+                           $GREP "vdev online" | \
+                           $GREP "(+${EX_1GB})" >/dev/null 2>&1
+
+                       if [[ $? -ne 0 ]] ; then
+                               log_fail "pool $TESTPOOL1 is not autoexpand " \
+                                   "after LUN expansion"
+                       fi
+               else
+                       $ZPOOL history -il $TESTPOOL1 | \
+                           $GREP "pool '$TESTPOOL1' size:" | \
+                           $GREP "vdev online" | \
+                           $GREP "(+${EX_3GB})" >/dev/null 2>&1
+
+                       if [[ $? -ne 0 ]]; then
+                               log_fail "pool $TESTPOOL is not autoexpand " \
+                                   "after LUN expansion"
+                       fi
+               fi
+       else
+               log_fail "pool $TESTPOOL1 is not autoexpanded after LUN " \
+                   "expansion"
+       fi
+
+       log_must $ZPOOL destroy $TESTPOOL1
+       for i in 1 2 3; do
+               log_must $ZFS set volsize=$org_size $VFS/vol$i
+       done
+
+done
+log_pass "zpool can be autoexpanded after set autoexpand=on on LUN expansion"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_002_pos.ksh
new file mode 100755 (executable)
index 0000000..d7ce33d
--- /dev/null
@@ -0,0 +1,148 @@
+#! /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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_expand/zpool_expand.cfg
+
+#
+# DESCRIPTION:
+# After zpool online -e poolname zvol vdevs, zpool can autoexpand by
+# Dynamic LUN Expansion
+#
+#
+# STRATEGY:
+# 1) Create a pool
+# 2) Create volume on top of the pool
+# 3) Create pool by using the zvols
+# 4) Expand the vol size by zfs set volsize
+# 5  Use zpool online -e to online the zvol vdevs
+# 6) Check that the pool size was expaned
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        if poolexists $TESTPOOL1; then
+                log_must $ZPOOL destroy $TESTPOOL1
+        fi
+
+       for i in 1 2 3; do
+               if datasetexists $VFS/vol$i; then
+                       log_must $ZFS destroy $VFS/vol$i
+               fi
+       done
+}
+
+log_onexit cleanup
+
+log_assert "zpool can expand after zpool online -e zvol vdevs on LUN expansion"
+
+for i in 1 2 3; do
+       log_must $ZFS create -V $org_size $VFS/vol$i
+done
+
+for type in " " mirror raidz raidz2; do
+       log_must $ZPOOL create $TESTPOOL1 $type ${ZVOL_DEVDIR}/$VFS/vol1 \
+           ${ZVOL_DEVDIR}/$VFS/vol2 ${ZVOL_DEVDIR}/$VFS/vol3
+
+       typeset autoexp=$(get_pool_prop autoexpand $TESTPOOL1)
+
+       if [[ $autoexp != "off" ]]; then
+               log_fail "zpool $TESTPOOL1 autoexpand should off but is " \
+                   "$autoexp"
+       fi
+       typeset prev_size=$(get_pool_prop size $TESTPOOL1)
+       typeset zfs_prev_size=$($ZFS get -p avail $TESTPOOL1 | $TAIL -1 | \
+           $AWK '{print $3}')
+
+       for i in 1 2 3; do
+               log_must $ZFS set volsize=$exp_size $VFS/vol$i
+       done
+
+       for i in 1 2 3; do
+               log_must $ZPOOL online -e $TESTPOOL1 ${ZVOL_DEVDIR}/$VFS/vol$i
+       done
+
+       $SYNC
+       $SLEEP 10
+       $SYNC
+
+       typeset expand_size=$(get_pool_prop size $TESTPOOL1)
+       typeset zfs_expand_size=$($ZFS get -p avail $TESTPOOL1 | $TAIL -1 | \
+           $AWK '{print $3}')
+       log_note "$TESTPOOL1 $type has previous size: $prev_size and " \
+           "expanded size: $expand_size"
+
+       # compare available pool size from zfs
+       if [[ $zfs_expand_size > $zfs_prev_size ]]; then
+       # check for zpool history for the pool size expansion
+               if [[ $type == " " ]]; then
+                       typeset size_addition=$($ZPOOL history -il $TESTPOOL1 \
+                           | $GREP "pool '$TESTPOOL1' size:" | \
+                           $GREP "vdev online" | \
+                           $GREP "(+${EX_1GB}" | wc -l)
+
+                       if [[ $size_addition -ne $i ]]; then
+                               log_fail "pool $TESTPOOL1 is not autoexpand " \
+                                   "after LUN expansion"
+                       fi
+               elif [[ $type == "mirror" ]]; then
+                       $ZPOOL history -il $TESTPOOL1 | \
+                           $GREP "pool '$TESTPOOL1' size:" | \
+                           $GREP "vdev online" | \
+                           $GREP "(+${EX_1GB})" >/dev/null 2>&1
+
+                       if [[ $? -ne 0 ]]; then
+                               log_fail "pool $TESTPOOL1 is not autoexpand " \
+                                   "after LUN expansion"
+                       fi
+               else
+                       $ZPOOL history -il $TESTPOOL1 | \
+                           $GREP "pool '$TESTPOOL1' size:" | \
+                           $GREP "vdev online" | \
+                           $GREP "(+${EX_3GB})" >/dev/null 2>&1
+
+                       if [[ $? -ne 0 ]] ; then
+                               log_fail "pool $TESTPOOL1 is not autoexpand " \
+                                   "after LUN expansion"
+                       fi
+               fi
+       else
+               log_fail "pool $TESTPOOL1 is not autoexpanded after LUN " \
+                   "expansion"
+       fi
+       log_must $ZPOOL destroy $TESTPOOL1
+       for i in 1 2 3; do
+               log_must $ZFS set volsize=$org_size $VFS/vol$i
+       done
+done
+log_pass "zpool can expand after zpool online -e zvol vdevs on LUN expansion"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_expand/zpool_expand_003_neg.ksh
new file mode 100755 (executable)
index 0000000..36e8d49
--- /dev/null
@@ -0,0 +1,115 @@
+#! /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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_expand/zpool_expand.cfg
+
+#
+# Description:
+# Once set zpool autoexpand=off, zpool can *NOT* autoexpand by
+# Dynamic LUN Expansion
+#
+#
+# STRATEGY:
+# 1) Create a pool
+# 2) Create volumes on top of the pool
+# 3) Create pool by using the zvols and set autoexpand=off
+# 4) Expand the vol size by zfs set volsize
+# 5) Check that the pool size is not changed
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        if poolexists $TESTPOOL1; then
+                log_must $ZPOOL destroy $TESTPOOL1
+        fi
+
+       for i in 1 2 3; do
+               if datasetexists $VFS/vol$i; then
+                       log_must $ZFS destroy $VFS/vol$i
+               fi
+       done
+}
+
+log_onexit cleanup
+
+log_assert "zpool can not expand if set autoexpand=off after LUN expansion"
+
+for i  in 1 2 3; do
+       log_must $ZFS create -V $org_size $VFS/vol$i
+done
+
+for type in " " mirror raidz raidz2; do
+       log_must $ZPOOL create $TESTPOOL1 $type ${ZVOL_DEVDIR}/$VFS/vol1 \
+           ${ZVOL_DEVDIR}/$VFS/vol2 ${ZVOL_DEVDIR}/$VFS/vol3
+
+       typeset autoexp=$(get_pool_prop autoexpand $TESTPOOL1)
+       if [[ $autoexp != "off" ]]; then
+               log_fail "zpool $TESTPOOL1 autoexpand should off but is " \
+                   "$autoexp"
+       fi
+
+       typeset prev_size=$(get_pool_prop size $TESTPOOL1)
+
+       for i in 1 2 3; do
+               log_must $ZFS set volsize=$exp_size $VFS/vol$i
+       done
+
+       $SYNC
+       $SLEEP 10
+       $SYNC
+
+       # check for zpool history for the pool size expansion
+       $ZPOOL history -il $TESTPOOL1 | $GREP "pool '$TESTPOOL1' size:" | \
+           $GREP "vdev online" >/dev/null 2>&1
+
+       if [[ $? -eq 0 ]]; then
+               log_fail "pool $TESTPOOL1 is not autoexpand after LUN " \
+                   "expansion"
+       fi
+
+       typeset expand_size=$(get_pool_prop size $TESTPOOL1)
+
+       if [[ "$prev_size" != "$expand_size" ]]; then
+               log_fail "pool $TESTPOOL1 size changed after LUN expansion"
+       fi
+
+       log_must $ZPOOL destroy $TESTPOOL1
+
+       for i in 1 2 3; do
+               log_must $ZFS set volsize=$org_size $VFS/vol$i
+       done
+
+done
+
+log_pass "zpool can not expand if set autoexpand=off after LUN expansion"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/Makefile.am
new file mode 100644 (file)
index 0000000..d0af877
--- /dev/null
@@ -0,0 +1,9 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_export
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_export.cfg \
+       zpool_export_001_pos.ksh \
+       zpool_export_002_pos.ksh \
+       zpool_export_003_neg.ksh \
+       zpool_export_004_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/setup.ksh
new file mode 100755 (executable)
index 0000000..925f3e4
--- /dev/null
@@ -0,0 +1,37 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_export/zpool_export.cfg
+
+DISK=${DISKS%% *}
+
+if ! $(is_physical_device $DISK) ; then
+       log_unsupported "Only partitionable physical disks can be used"
+fi
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export.cfg
new file mode 100644 (file)
index 0000000..1501c04
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# 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) 2012, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export DISK_ARRAY_NUM=0
+export DISK_ARRAY_LIMIT=4
+export DISKSARRAY=""
+export VDEVS_NUM=32
+
+function set_disks
+{
+        typeset -a disk_array=($(find_disks $DISKS))
+
+       if (( ${#disk_array[*]} <= 1 )); then
+               export DISK=${DISKS%% *}
+       else
+               export DISK=""
+               typeset -i i=0
+               while (( i < ${#disk_array[*]} )); do
+                       export DISK${i}="${disk_array[$i]}"
+                       DISKSARRAY="$DISKSARRAY ${disk_array[$i]}"
+                       (( i = i + 1 ))
+                       (( i>$DISK_ARRAY_LIMIT )) && break
+               done
+               export DISK_ARRAY_NUM=$i
+               export DISKSARRAY
+       fi
+}
+
+set_disks
+set_device_dir
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_001_pos.ksh
new file mode 100755 (executable)
index 0000000..af7c6f2
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_export/zpool_export.cfg
+
+#
+# DESCRIPTION:
+# Exported pools should no longer be visible from 'zpool list'.
+# Therefore, we export an existing pool and verify it cannot
+# be accessed.
+#
+# STRATEGY:
+# 1. Unmount the test directory.
+# 2. Export the pool.
+# 3. Verify the pool is no longer present in the list output.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dir=$(get_device_dir $DISKS)
+
+       datasetexists "$TESTPOOL/$TESTFS" || \
+               log_must $ZPOOL import -d $dir $TESTPOOL
+
+       ismounted "$TESTPOOL/$TESTFS"
+       (( $? != 0 )) && \
+           log_must $ZFS mount $TESTPOOL/$TESTFS
+}
+
+log_onexit cleanup
+
+log_assert "Verify a pool can be exported."
+
+log_must $ZFS umount $TESTDIR
+log_must $ZPOOL export $TESTPOOL
+
+poolexists $TESTPOOL && \
+        log_fail "$TESTPOOL unexpectedly found in 'zpool list' output."
+
+log_pass "Successfully exported a ZPOOL."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_002_pos.ksh
new file mode 100755 (executable)
index 0000000..ee1895e
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# The 'zpool export' command must fail when a pool is
+# busy i.e. mounted.
+#
+# STRATEGY:
+# 1. Try and export the default pool when mounted and busy.
+# 2. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dir=$(get_device_dir $DISKS)
+       cd $olddir || \
+           log_fail "Couldn't cd back to $olddir"
+
+       datasetexists "$TESTPOOL/$TESTFS" || \
+           log_must $ZPOOL import -d $dir $TESTPOOL
+
+       ismounted "$TESTPOOL/$TESTFS"
+       (( $? != 0 )) && \
+           log_must $ZFS mount $TESTPOOL/$TESTFS
+
+       [[ -e $TESTDIR/$TESTFILE0 ]] && \
+           log_must $RM -rf $TESTDIR/$TESTFILE0
+}
+
+olddir=$PWD
+
+log_onexit cleanup
+
+log_assert "Verify a busy ZPOOL cannot be exported."
+
+ismounted "$TESTPOOL/$TESTFS"
+(( $? != 0 )) && \
+    log_fail "$TESTDIR not mounted. Unable to continue."
+
+cd $TESTDIR || \
+    log_fail "Couldn't cd to $TESTDIR"
+
+log_mustnot $ZPOOL export $TESTPOOL
+
+poolexists $TESTPOOL || \
+       log_fail "$TESTPOOL not found in 'zpool list' output."
+
+log_pass "Unable to export a busy ZPOOL as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_003_neg.ksh
new file mode 100755 (executable)
index 0000000..c3d6c63
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#       'zpool export' should return an error with badly formed parameters,
+#
+# STRATEGY:
+#      1. Create an array of parameters
+#      2. For each parameter in the array, execute 'zpool export'
+#      3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dir=$(get_device_dir $DISKS)
+       datasetexists "$TESTPOOL/$TESTFS" || \
+               log_must $ZPOOL import -d $dir $TESTPOOL
+
+       ismounted "$TESTPOOL/$TESTFS"
+       (( $? != 0 )) && \
+           log_must $ZFS mount $TESTPOOL/$TESTFS
+}
+
+log_onexit cleanup
+
+set -A args "" "-f" "-? $TESTPOOL" "-QWERTYUIO $TESTPOOL"
+
+log_assert "'zpool export' should return an error with badly-formed parameters."
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZPOOL export ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "'zpool export' badly formed parameters fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_export/zpool_export_004_pos.ksh
new file mode 100755 (executable)
index 0000000..91f2968
--- /dev/null
@@ -0,0 +1,95 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify zpool export succeed or fail with spare.
+#
+# STRATEGY:
+#      1. Create two mirror pools with same spare.
+#      2. Verify zpool export one pool succeed.
+#      3. Import the pool.
+#      4. Replace one device with the spare and detach it in one pool.
+#      5. Verify zpool export the pool succeed.
+#      6. Import the pool.
+#      7. Replace one device with the spare in one pool.
+#      8. Verify zpool export the pool fail.
+#      9. Verify zpool export the pool with "-f" succeed.
+#      10. Import the pool.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       mntpnt=$(get_prop mountpoint $TESTPOOL)
+        datasetexists $TESTPOOL1 || log_must $ZPOOL import -d $mntpnt $TESTPOOL1
+       datasetexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+       datasetexists $TESTPOOL2 && destroy_pool $TESTPOOL2
+       typeset -i i=0
+       while ((i < 5)); do
+               if [[ -e $mntpnt/vdev$i ]]; then
+                       log_must $RM -f $mntpnt/vdev$i
+               fi
+               ((i += 1))
+       done
+}
+
+
+log_assert "Verify zpool export succeed or fail with spare."
+log_onexit cleanup
+
+mntpnt=$(get_prop mountpoint $TESTPOOL)
+
+typeset -i i=0
+while ((i < 5)); do
+       log_must $MKFILE 64M $mntpnt/vdev$i
+       eval vdev$i=$mntpnt/vdev$i
+       ((i += 1))
+done
+
+log_must $ZPOOL create $TESTPOOL1 mirror $vdev0 $vdev1 spare $vdev4
+log_must $ZPOOL create $TESTPOOL2 mirror $vdev2 $vdev3 spare $vdev4
+
+log_must $ZPOOL export $TESTPOOL1
+log_must $ZPOOL import -d $mntpnt $TESTPOOL1
+
+log_must $ZPOOL replace $TESTPOOL1 $vdev0 $vdev4
+log_must $ZPOOL detach $TESTPOOL1 $vdev4
+log_must $ZPOOL export $TESTPOOL1
+log_must $ZPOOL import -d $mntpnt $TESTPOOL1
+
+log_must $ZPOOL replace $TESTPOOL1 $vdev0 $vdev4
+log_mustnot $ZPOOL export $TESTPOOL1
+
+log_must $ZPOOL export -f $TESTPOOL1
+log_must $ZPOOL import -d $mntpnt  $TESTPOOL1
+
+log_pass "Verify zpool export succeed or fail with spare."
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/Makefile.am
new file mode 100644 (file)
index 0000000..bc42ee4
--- /dev/null
@@ -0,0 +1,9 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_get
+dist_pkgdata_SCRIPTS = \
+       zpool_get.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_get_001_pos.ksh \
+       zpool_get_002_pos.ksh \
+       zpool_get_003_pos.ksh \
+       zpool_get_004_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/cleanup.ksh
new file mode 100755 (executable)
index 0000000..6c992b5
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/setup.ksh
new file mode 100755 (executable)
index 0000000..063ad74
--- /dev/null
@@ -0,0 +1,37 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+verify_runnable "both"
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
new file mode 100644 (file)
index 0000000..699229f
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+# Set the expected properties of zpool
+if is_linux; then
+typeset -a properties=("size" "capacity" "altroot" "health" "guid" "version"
+    "bootfs" "delegation" "autoreplace" "cachefile" "dedupditto" "dedupratio"
+    "free" "allocated" "readonly" "comment" "expandsize" "freeing" "failmode"
+    "listsnapshots" "autoexpand" "fragmentation" "leaked" "ashift"
+    "feature@async_destroy" "feature@empty_bpobj" "feature@lz4_compress"
+    "feature@large_blocks" "feature@large_dnode" "feature@filesystem_limits"
+    "feature@spacemap_histogram" "feature@enabled_txg" "feature@hole_birth"
+    "feature@extensible_dataset" "feature@bookmarks" "feature@embedded_data"
+    "feature@sha512" "feature@skein" "feature@edonr"
+    "feature@userobj_accounting")
+else
+typeset -a properties=("size" "capacity" "altroot" "health" "guid" "version"
+    "bootfs" ""leaked" delegation" "autoreplace" "cachefile" "dedupditto" "dedupratio"
+    "free" "allocated" "readonly" "comment" "expandsize" "freeing" "failmode"
+    "listsnapshots" "autoexpand" "feature@async_destroy" "feature@empty_bpobj"
+    "feature@lz4_compress" "feature@multi_vdev_crash_dump"
+    "feature@spacemap_histogram" "feature@enabled_txg" "feature@hole_birth"
+    "feature@extensible_dataset" "feature@bookmarks" "feature@sha512"
+    "feature@skein" "feature@edonr")
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_001_pos.ksh
new file mode 100755 (executable)
index 0000000..dbf3042
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Zpool get usage message is displayed when called with no arguments
+#
+# STRATEGY:
+#      1. Run zpool get
+#      2. Check that exit status is set to 2
+#      3. Check usage message contains text "usage"
+#
+
+log_assert "Zpool get usage message is displayed when called with no arguments."
+
+$ZPOOL get > /dev/null 2>&1
+RET=$?
+if [ $RET != 2 ]
+then
+       log_fail "\"zpool get\" exit status $RET should be equal to 2."
+fi
+
+OUTPUT=$($ZPOOL get 2>&1 | $GREP -i usage)
+RET=$?
+if [ $RET != 0 ]
+then
+       log_fail "Usage message for zpool get did not contain the word 'usage'."
+fi
+
+log_pass "Zpool get usage message is displayed when called with no arguments."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_002_pos.ksh
new file mode 100755 (executable)
index 0000000..346811e
--- /dev/null
@@ -0,0 +1,94 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_get/zpool_get.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool get all works as expected
+#
+# STRATEGY:
+#
+# 1. Using zpool get, retrieve all default values
+# 2. Verify that the header is printed
+# 3. Verify that we can see all the properties we expect to see
+# 4. Verify that the total output contains just those properties + header.
+#
+# Test for those properties are expected to check whether their
+# default values are sane, or whether they can be changed with zpool set.
+#
+
+log_assert "Zpool get all works as expected"
+
+typeset -i i=0;
+
+if ! is_global_zone ; then
+       TESTPOOL=${TESTPOOL%%/*}
+fi
+
+log_must $ZPOOL get all $TESTPOOL
+$ZPOOL get all $TESTPOOL > /tmp/values.$$
+
+log_note "Checking zpool get all output for a header."
+$GREP ^"NAME " /tmp/values.$$ > /dev/null 2>&1
+if [ $? -ne 0 ]
+then
+       log_fail "The header was not printed from zpool get all"
+fi
+
+
+while [ $i -lt "${#properties[@]}" ]
+do
+       log_note "Checking for ${properties[$i]} property"
+       $GREP "$TESTPOOL *${properties[$i]}" /tmp/values.$$ > /dev/null 2>&1
+       if [ $? -ne 0 ]
+       then
+               log_fail "zpool property ${properties[$i]} was not found\
+ in pool output."
+       fi
+       i=$(( $i + 1 ))
+done
+
+# increment the counter to include the header line
+i=$(( $i + 1 ))
+
+COUNT=$($WC /tmp/values.$$ | $AWK '{print $1}')
+if [ $i -ne $COUNT ]
+then
+       log_fail "Found zpool features not in the zpool_get test config $i/$COUNT."
+fi
+
+
+
+$RM /tmp/values.$$
+log_pass "Zpool get all works as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_003_pos.ksh
new file mode 100755 (executable)
index 0000000..a816b6b
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_get/zpool_get.cfg
+
+#
+# DESCRIPTION:
+#
+# Zpool get returns values for all known properties
+#
+# STRATEGY:
+# 1. For all properties, verify zpool get retrieves a value
+#
+
+log_assert "Zpool get returns values for all known properties"
+
+if ! is_global_zone ; then
+       TESTPOOL=${TESTPOOL%%/*}
+fi
+
+typeset -i i=0;
+
+while [ $i -lt "${#properties[@]}" ]
+do
+       log_note "Checking for ${properties[$i]} property"
+       log_must eval "$ZPOOL get ${properties[$i]} $TESTPOOL > /tmp/value.$$"
+       $GREP "${properties[$i]}" /tmp/value.$$ > /dev/null 2>&1
+       if [ $? -ne 0 ]
+       then
+               log_fail "${properties[$i]} not seen in output"
+       fi
+       $GREP "^NAME " /tmp/value.$$ > /dev/null 2>&1
+       # only need to check this once.
+       if [ $i -eq 0 ] && [ $? -ne 0 ]
+       then
+               log_fail "Header not seen in zpool get output"
+       fi
+       i=$(( $i + 1 ))
+done
+
+$RM /tmp/value.$$
+log_pass "Zpool get returns values for all known properties"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get_004_neg.ksh
new file mode 100755 (executable)
index 0000000..c4729d8
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Malformed zpool get commands are rejected
+#
+# STRATEGY:
+#
+# 1. Run several different "zpool get" commands that should fail.
+#
+
+log_assert "Malformed zpool get commands are rejected"
+
+if ! is_global_zone ; then
+       TESTPOOL=${TESTPOOL%%/*}
+fi
+
+set -A arguments "$TESTPOOL $TESTPOOL" "$TESTPOOL rubbish" "-v $TESTPOOL" \
+               "nosuchproperty $TESTPOOL" "--$TESTPOOL" "all all" \
+               "type $TESTPOOL" "usage: $TESTPOOL" "bootfs $TESTPOOL@" \
+               "bootfs,bootfs $TESTPOOL" "name $TESTPOOL" "t%d%s" \
+               "bootfs,delegation $TESTPOOL" "delegation $TESTPOOL@"
+
+for arg in $arguments
+do
+       log_mustnot $ZPOOL get $arg
+done
+
+log_pass "Malformed zpool get commands are rejected"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/Makefile.am
new file mode 100644 (file)
index 0000000..8755f8f
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_history
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_history_001_neg.ksh \
+       zpool_history_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/cleanup.ksh
new file mode 100755 (executable)
index 0000000..e499813
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/setup.ksh
new file mode 100755 (executable)
index 0000000..b2a852a
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_container_volume_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/zpool_history_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/zpool_history_001_neg.ksh
new file mode 100755 (executable)
index 0000000..a722fe7
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify 'zpool history' can deal with non-existent pools and garbage
+#      to the command.
+#
+# STRATEGY:
+#      1. Create pool, volume & snap
+#      2. Verify 'zpool history' can cope with incorret arguments.
+#
+
+verify_runnable "global"
+
+snap=$TESTPOOL/$TESTFS@snap
+clone=$TESTPOOL/clone
+
+set -A neg_opt "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTVOL" "-t $TESTPOOL" \
+       "-v $TESTPOOL" "$snap" "$clone" "nonexist" "TESTPOOL"
+
+function cleanup
+{
+       datasetexists $clone && log_must $ZFS destroy $clone
+       datasetexists $snap && log_must $ZFS destroy $snap
+}
+
+log_assert "Verify 'zpool history' can deal with non-existent pools and " \
+       "garbage to the command."
+log_onexit cleanup
+
+log_must $ZFS snapshot $snap
+log_must $ZFS clone $snap $clone
+
+for opt in "${neg_opt[@]}"; do
+       log_mustnot eval "$ZPOOL history $opt > /dev/null"
+done
+
+log_pass "'zpool history' command line negation test passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/zpool_history_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_history/zpool_history_002_pos.ksh
new file mode 100755 (executable)
index 0000000..bd5bf19
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify zpool history can handle options [-il] correctly.
+#
+# STRATEGY:
+#      1. Create varied combinations of option -i & -l.
+#      2. Verify 'zpool history' can cope with these combination correctly.
+#
+
+verify_runnable "global"
+
+log_assert "Verify zpool history can handle options [-il] correctly."
+
+options="-i -l -il -li -lil -ili -lli -iill -liil"
+
+for opt in $options; do
+       log_must eval "$ZPOOL history $opt $TESTPOOL > /dev/null 2>&1"
+done
+
+log_pass "Verify zpool history can handle options [-il] passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile.am
new file mode 100644 (file)
index 0000000..bdc631a
--- /dev/null
@@ -0,0 +1,32 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_import
+dist_pkgdata_SCRIPTS = \
+       zpool_import.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_import_001_pos.ksh \
+       zpool_import_002_pos.ksh \
+       zpool_import_003_pos.ksh \
+       zpool_import_004_pos.ksh \
+       zpool_import_005_pos.ksh \
+       zpool_import_006_pos.ksh \
+       zpool_import_007_pos.ksh \
+       zpool_import_008_pos.ksh \
+       zpool_import_009_neg.ksh \
+       zpool_import_010_pos.ksh \
+       zpool_import_011_neg.ksh \
+       zpool_import_012_pos.ksh \
+       zpool_import_013_neg.ksh \
+       zpool_import_all_001_pos.ksh \
+       zpool_import_features_001_pos.ksh \
+       zpool_import_features_002_neg.ksh \
+       zpool_import_features_003_pos.ksh \
+       zpool_import_missing_001_pos.ksh \
+       zpool_import_missing_002_pos.ksh \
+       zpool_import_missing_003_pos.ksh \
+       zpool_import_rename_001_pos.ksh
+
+BLOCKFILES = \
+       unclean_export.dat.bz2
+
+dist_pkgdata_DATA = $(BLOCKFILES)
+EXTRA_DIST = $(BLOCKFILES)
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/cleanup.ksh
new file mode 100755 (executable)
index 0000000..c55d70c
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+verify_runnable "global"
+
+for pool in "$TESTPOOL" "$TESTPOOL1"; do
+       datasetexists $pool/$TESTFS && \
+               log_must $ZFS destroy -Rf $pool/$TESTFS
+       destroy_pool "$pool"
+done
+
+ismounted $DEVICE_DIR $NEWFS_DEFAULT_FS
+(( $? == 0 )) && log_must $UMOUNT -f $DEVICE_DIR
+
+for dir in "$TESTDIR" "$TESTDIR1" "$DEVICE_DIR" ; do
+       [[ -d $dir ]] && \
+               log_must $RM -rf $dir
+done
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+       delete_partitions
+fi
+# recreate and destroy a zpool over the disks to restore the partitions to
+# normal
+case $DISK_COUNT in
+0|1)
+       log_note "No disk devices to restore"
+       ;;
+*)
+       log_must cleanup_devices $ZFS_DISK1
+       log_must cleanup_devices $ZFS_DISK2
+       ;;
+esac
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/setup.ksh
new file mode 100755 (executable)
index 0000000..9d0b913
--- /dev/null
@@ -0,0 +1,99 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+if ! $(is_physical_device $ZFS_DISK1) ; then
+       log_unsupported "Only partitionable physical disks can be used"
+fi
+
+DISK=${DISKS%% *}
+
+for dev in $ZFS_DISK1 $ZFS_DISK2 ; do
+       log_must cleanup_devices $dev
+done
+
+typeset -i i=0
+while (( i <= $GROUP_NUM )); do
+       if ! is_linux; then
+               if (( i == 2 )); then
+                       (( i = i + 1 ))
+                       continue
+               fi
+       fi
+       log_must set_partition $i "$cyl" $SLICE_SIZE $ZFS_DISK1
+       cyl=$(get_endslice $ZFS_DISK1 $i)
+       (( i = i + 1 ))
+done
+
+create_pool "$TESTPOOL" "$ZFSSIDE_DISK1"
+
+if [[ -d $TESTDIR ]]; then
+       $RM -rf $TESTDIR  || log_unresolved Could not remove $TESTDIR
+       $MKDIR -p $TESTDIR || log_unresolved Could not create $TESTDIR
+fi
+
+log_must $ZFS create $TESTPOOL/$TESTFS
+log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+DISK2="$($ECHO $DISKS | $NAWK '{print $2}')"
+if is_mpath_device $DISK2; then
+       $ECHO "y" | $NEWFS -v $DEV_DSKDIR/$DISK2 >/dev/null 2>&1
+       (( $? != 0 )) &&
+               log_untested "Unable to setup a $NEWFS_DEFAULT_FS file system"
+
+       [[ ! -d $DEVICE_DIR ]] && \
+               log_must $MKDIR -p $DEVICE_DIR
+
+       log_must $MOUNT $DEV_DSKDIR/$DISK2 $DEVICE_DIR
+else
+       log_must set_partition 0 "" $FS_SIZE $ZFS_DISK2
+       $ECHO "y" | $NEWFS -v $DEV_DSKDIR/$ZFSSIDE_DISK2 >/dev/null 2>&1
+       (( $? != 0 )) &&
+               log_untested "Unable to setup a $NEWFS_DEFAULT_FS file system"
+
+       [[ ! -d $DEVICE_DIR ]] && \
+               log_must $MKDIR -p $DEVICE_DIR
+
+       log_must $MOUNT $DEV_DSKDIR/$ZFSSIDE_DISK2 $DEVICE_DIR
+fi
+
+i=0
+while (( i < $MAX_NUM )); do
+       log_must $MKFILE $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
+       (( i = i + 1 ))
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import.cfg
new file mode 100644 (file)
index 0000000..017874e
--- /dev/null
@@ -0,0 +1,137 @@
+#
+# 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) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export DISKSARRAY=$DISKS
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+typeset -a disk_array=($(find_disks $DISKS))
+case "${#disk_array[*]}" in
+0)
+       #
+       # on stf_configure, disk_freelist returns empty.
+       #
+       DISK_COUNT=0
+       ;;
+1)
+       # We need to repartition the single disk to two slices.
+       if is_linux; then
+               DISK_COUNT=1
+               ZFS_DISK1=${disk_array[0]}
+               ZFS_DISK2=${disk_array[0]}
+               if is_mpath_device $ZFS_DISK1; then
+                       export DEV_DSKDIR=$DEV_MPATHDIR
+               else
+                       export DEV_DSKDIR=$DEV_RDSKDIR
+               fi
+               if ( is_mpath_device $ZFS_DISK1 ) && [[ -z $($ECHO $ZFS_DISK1 | awk 'substr($1,18,1)\
+                    ~ /^[[:digit:]]+$/') ]] || ( is_real_device $ZFS_DISK1 ); then
+                       ZFSSIDE_DISK1=${ZFS_DISK1}1
+                       ZFSSIDE_DISK2=${ZFS_DISK2}2
+               elif ( is_mpath_device $ZFS_DISK1 || is_loop_device $ZFS_DISK1 ); then
+                       ZFSSIDE_DISK1=${ZFS_DISK1}p1
+                       ZFSSIDE_DISK2=${ZFS_DISK2}p2
+               else
+                       log_fail "$ZFS_DISK1 not supported for partitioning."
+               fi
+       else
+               export DEV_DSKDIR="/dev"
+               DISK_COUNT=1
+               ZFS_DISK1=${disk_array[0]}
+               ZFSSIDE_DISK1=${ZFS_DISK1}s0
+               ZFS_DISK2=${disk_array[0]}
+               ZFSSIDE_DISK2=${ZFS_DISK2}s1
+       fi
+       ;;
+*)
+       # We need to repartition the single disk to two slices.
+       if is_linux; then
+               DISK_COUNT=2
+               ZFS_DISK1=${disk_array[0]}
+               if is_mpath_device $ZFS_DISK1; then
+                       export DEV_DSKDIR=$DEV_MPATHDIR
+               else
+                       export DEV_DSKDIR=$DEV_RDSKDIR
+               fi
+               if ( is_mpath_device $ZFS_DISK1 ) && [[ -z $($ECHO $ZFS_DISK1 | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $ZFS_DISK1 ); then
+                       ZFSSIDE_DISK1=${ZFS_DISK1}1
+               elif ( is_mpath_device $ZFS_DISK1 || is_loop_device $ZFS_DISK1 ); then
+                       ZFSSIDE_DISK1=${ZFS_DISK1}p1
+               else
+                       log_fail "$ZFS_DISK1 not supported for partitioning."
+               fi
+               ZFS_DISK2=${disk_array[1]}
+               if ( is_mpath_device $ZFS_DISK2 ) && [[ -z $($ECHO $ZFS_DISK2 | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $ZFS_DISK2 ); then
+                       ZFSSIDE_DISK2=${ZFS_DISK2}1
+               elif ( is_mpath_device $ZFS_DISK2 || is_loop_device $ZFS_DISK2 ); then
+                       ZFSSIDE_DISK2=${ZFS_DISK2}p1
+               else
+                       log_fail "$ZFS_DISK2 not supported for partitioning."
+               fi
+       else
+               export DEV_DSKDIR="/dev"
+               DISK_COUNT=2
+               ZFS_DISK1=${disk_array[0]}
+               ZFSSIDE_DISK1=${ZFS_DISK1}s0
+               ZFS_DISK2=${disk_array[1]}
+               ZFSSIDE_DISK2=${ZFS_DISK2}s0
+       fi
+       ;;
+esac
+
+export DISK_COUNT ZFS_DISK1 ZFSSIDE_DISK1 ZFS_DISK2 ZFSSIDE_DISK2
+
+export FS_SIZE=1g
+export FILE_SIZE=64m
+export SLICE_SIZE=128m
+export MAX_NUM=5
+export GROUP_NUM=3
+export DEVICE_DIR=$TEST_BASE_DIR/dev_import-test
+export BACKUP_DEVICE_DIR=$TEST_BASE_DIR/bakdev_import-test
+export DEVICE_FILE=disk
+export DEVICE_ARCHIVE=archive_import-test
+export MYTESTFILE=$STF_SUITE/include/libtest.shlib
+
+typeset -i num=0
+while (( num < $GROUP_NUM )); do
+       DEVICE_FILES="$DEVICE_FILES ${DEVICE_DIR}/${DEVICE_FILE}$num"
+       (( num = num + 1 ))
+done
+export DEVICE_FILES
+
+export VDEV0=$DEVICE_DIR/${DEVICE_FILE}0
+export VDEV1=$DEVICE_DIR/${DEVICE_FILE}1
+export VDEV2=$DEVICE_DIR/${DEVICE_FILE}2
+export VDEV3=$DEVICE_DIR/${DEVICE_FILE}3
+export VDEV4=$DEVICE_DIR/${DEVICE_FILE}4
+
+export ALTER_ROOT=/alter_import-test
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_001_pos.ksh
new file mode 100755 (executable)
index 0000000..ef35865
--- /dev/null
@@ -0,0 +1,138 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+# Once a pool has been exported, it should be recreated after a
+# successful import. Verify that is true.
+#
+# STRATEGY:
+#      1. Populate the default test directory and unmount it.
+#      2. Export the default test pool.
+#      3. Import it using the various combinations.
+#              - Regular import
+#              - Alternate Root Specified
+#         Try to import it by name or guid randomly.
+#      4. Verify it shows up under 'zpool list'.
+#      5. Verify it can be mounted again and contains a file.
+#
+
+verify_runnable "global"
+
+set -A pools "$TESTPOOL" "$TESTPOOL1"
+set -A devs " -s" "-d $DEVICE_DIR"
+set -A options "" "-R $ALTER_ROOT"
+set -A mtpts "$TESTDIR" "$TESTDIR1"
+
+
+function cleanup
+{
+       typeset -i i=0
+
+       while (( i < ${#pools[*]} )); do
+               poolexists ${pools[i]} && \
+                       log_must $ZPOOL export ${pools[i]}
+
+               datasetexists "${pools[i]}/$TESTFS" || \
+                       log_must $ZPOOL import ${devs[i]} ${pools[i]}
+
+               ismounted "${pools[i]}/$TESTFS" || \
+                       log_must $ZFS mount ${pools[i]}/$TESTFS
+
+               [[ -e ${mtpts[i]}/$TESTFILE0 ]] && \
+                       log_must $RM -rf ${mtpts[i]}/$TESTFILE0
+
+               ((i = i + 1))
+       done
+
+       cleanup_filesystem $TESTPOOL1 $TESTFS
+
+        destroy_pool $TESTPOOL1
+
+       [[ -d $ALTER_ROOT ]] && \
+               log_must $RM -rf $ALTER_ROOT
+}
+
+log_onexit cleanup
+
+log_assert "Verify that an exported pool can be imported."
+
+setup_filesystem "$DEVICE_FILES" $TESTPOOL1 $TESTFS $TESTDIR1
+
+checksum1=$($SUM $MYTESTFILE | $AWK '{print $1}')
+
+typeset -i i=0
+typeset -i j=0
+typeset basedir
+
+while (( i < ${#pools[*]} )); do
+       guid=$(get_config ${pools[i]} pool_guid)
+       log_must $CP $MYTESTFILE ${mtpts[i]}/$TESTFILE0
+
+       log_must $ZFS umount ${mtpts[i]}
+
+       j=0
+       while (( j <  ${#options[*]} )); do
+               log_must $ZPOOL export ${pools[i]}
+
+               typeset target=${pools[i]}
+               if (( RANDOM % 2 == 0 )) ; then
+                       target=$guid
+                       log_note "Import by guid."
+               fi
+               log_must $ZPOOL import ${devs[i]} ${options[j]} $target
+
+               log_must poolexists ${pools[i]}
+
+               log_must ismounted ${pools[i]}/$TESTFS
+
+               basedir=${mtpts[i]}
+               [[ -n ${options[j]} ]] && \
+                       basedir=$ALTER_ROOT/${mtpts[i]}
+
+               [[ ! -e $basedir/$TESTFILE0 ]] && \
+                       log_fail "$basedir/$TESTFILE0 missing after import."
+
+               checksum2=$($SUM $basedir/$TESTFILE0 | $AWK '{print $1}')
+               [[ "$checksum1" != "$checksum2" ]] && \
+                       log_fail "Checksums differ ($checksum1 != $checksum2)"
+
+               ((j = j + 1))
+       done
+
+       ((i = i + 1))
+done
+
+log_pass "Successfully imported a ZPOOL"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_002_pos.ksh
new file mode 100755 (executable)
index 0000000..73f24a4
--- /dev/null
@@ -0,0 +1,142 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+# Verify that an exported pool cannot be imported
+# more than once.
+#
+# STRATEGY:
+#      1. Populate the default test directory and unmount it.
+#      2. Export the default test pool.
+#      3. Import it using the various combinations.
+#              - Regular import
+#              - Alternate Root Specified
+#      4. Verify it shows up under 'zpool list'.
+#      5. Verify it contains a file.
+#      6. Attempt to import it for a second time. Verify this fails.
+#
+
+verify_runnable "global"
+
+set -A pools "$TESTPOOL" "$TESTPOOL1"
+set -A devs "" "-d $DEVICE_DIR"
+set -A options "" "-R $ALTER_ROOT"
+set -A mtpts "$TESTDIR" "$TESTDIR1"
+
+
+function cleanup
+{
+       typeset -i i=0
+       while (( i < ${#pools[*]} )); do
+               poolexists ${pools[i]} && \
+                       log_must $ZPOOL export ${pools[i]}
+
+               datasetexists "${pools[i]}/$TESTFS" || \
+                       log_must $ZPOOL import ${devs[i]} ${pools[i]}
+
+               ismounted "${pools[i]}/$TESTFS" || \
+                       log_must $ZFS mount ${pools[i]}/$TESTFS
+
+               [[ -e ${mtpts[i]}/$TESTFILE0 ]] && \
+                       log_must $RM -rf ${mtpts[i]}/$TESTFILE0
+
+               ((i = i + 1))
+       done
+
+       cleanup_filesystem $TESTPOOL1 $TESTFS
+
+       destroy_pool $TESTPOOL1
+
+       [[ -d $ALTER_ROOT ]] && \
+               log_must $RM -rf $ALTER_ROOT
+}
+
+log_onexit cleanup
+
+log_assert "Verify that an exported pool cannot be imported more than once."
+
+setup_filesystem "$DEVICE_FILES" $TESTPOOL1 $TESTFS $TESTDIR1
+
+checksum1=$($SUM $MYTESTFILE | $AWK '{print $1}')
+
+typeset -i i=0
+typeset -i j=0
+typeset basedir
+
+while (( i < ${#pools[*]} )); do
+       guid=$(get_config ${pools[i]} pool_guid)
+
+       log_must $CP $MYTESTFILE ${mtpts[i]}/$TESTFILE0
+
+       log_must $ZFS umount ${mtpts[i]}
+
+       j=0
+       while (( j <  ${#options[*]} )); do
+               log_must $ZPOOL export ${pools[i]}
+
+               typeset target=${pools[i]}
+               if (( RANDOM % 2 == 0 )) ; then
+                       target=$guid
+                       log_note "Import by guid."
+               fi
+
+               log_must $ZPOOL import ${devs[i]} ${options[j]} $target
+
+               log_must poolexists ${pools[i]}
+
+               log_must ismounted ${pools[i]}/$TESTFS
+
+               basedir=${mtpts[i]}
+               [[ -n ${options[j]} ]] && \
+                       basedir=$ALTER_ROOT/${mtpts[i]}
+
+               [[ ! -e $basedir/$TESTFILE0 ]] && \
+                       log_fail "$basedir/$TESTFILE0 missing after import."
+
+               checksum2=$($SUM $basedir/$TESTFILE0 | $AWK '{print $1}')
+               [[ "$checksum1" != "$checksum2" ]] && \
+                       log_fail "Checksums differ ($checksum1 != $checksum2)"
+
+               log_mustnot $ZPOOL import ${devs[i]} $target
+
+               ((j = j + 1))
+       done
+
+       ((i = i + 1))
+
+done
+
+log_pass "Unable to import the same pool twice as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_003_pos.ksh
new file mode 100755 (executable)
index 0000000..26ed492
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      Destroyed pools are not listed unless with -D option is specified.
+#
+# STRATEGY:
+#      1. Create test pool A.
+#      2. Destroy pool A.
+#      3. Verify only 'import -D' can list pool A.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_pool $TESTPOOL1
+
+       log_must $RM $VDEV0 $VDEV1
+       log_must $MKFILE $FILE_SIZE $VDEV0 $VDEV1
+}
+
+log_assert "Destroyed pools are not listed unless with -D option is specified."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 $VDEV0 $VDEV1
+log_must $ZPOOL destroy $TESTPOOL1
+
+#
+# 'pool:' is the keywords of 'zpool import -D' output.
+#
+log_mustnot eval "$ZPOOL import -d $DEVICE_DIR | $GREP pool:"
+log_must eval "$ZPOOL import -d $DEVICE_DIR -D | $GREP pool:"
+
+log_pass "Destroyed pool only can be listed with -D option."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_004_pos.ksh
new file mode 100755 (executable)
index 0000000..f584200
--- /dev/null
@@ -0,0 +1,88 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      Destroyed pools devices was moved to another directory, it still can be
+#      imported correctly.
+#
+# STRATEGY:
+#      1. Create test pool A with several devices.
+#      2. Destroy pool A.
+#      3. Move devices to another directory.
+#      4. Verify 'zpool import -D' succeed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_pool $TESTPOOL1
+
+       log_must $RM -rf $DEVICE_DIR/*
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               log_must $MKFILE $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
+               ((i += 1))
+       done
+}
+
+log_assert "Destroyed pools devices was moved to another directory," \
+       "it still can be imported correctly."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 $VDEV0 $VDEV1 $VDEV2
+typeset guid=$(get_config $TESTPOOL1 pool_guid)
+typeset target=$TESTPOOL1
+if (( RANDOM % 2 == 0 )) ; then
+       target=$guid
+       log_note "Import by guid."
+fi
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_note "Devices was moved to different directories."
+log_must $MKDIR $DEVICE_DIR/newdir1 $DEVICE_DIR/newdir2
+log_must $MV $VDEV1 $DEVICE_DIR/newdir1
+log_must $MV $VDEV2 $DEVICE_DIR/newdir2
+log_must $ZPOOL import -d $DEVICE_DIR/newdir1 -d $DEVICE_DIR/newdir2 \
+       -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy -f $TESTPOOL1
+
+log_note "Devices was moved to same directory."
+log_must $MV $VDEV0 $DEVICE_DIR/newdir2
+log_must $MV $DEVICE_DIR/newdir1/* $DEVICE_DIR/newdir2
+log_must $ZPOOL import -d $DEVICE_DIR/newdir2 -D -f $target
+log_must $ZPOOL destroy -f $TESTPOOL1
+
+log_pass "Destroyed pools devices was moved, 'zpool import -D' passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_005_pos.ksh
new file mode 100755 (executable)
index 0000000..12bd14d
--- /dev/null
@@ -0,0 +1,85 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      Destroyed pools devices was renamed, it still can be imported correctly.
+#
+# STRATEGY:
+#      1. Create test pool A with several devices.
+#      2. Destroy pool A and rename devices name.
+#      3. Verify 'zpool import -D' succeed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_pool $TESTPOOL1
+
+       log_must $RM -rf $DEVICE_DIR/*
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               log_must $MKFILE $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
+               ((i += 1))
+       done
+}
+
+log_assert "Destroyed pools devices was renamed, it still can be imported " \
+       "correctly."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 $VDEV0 $VDEV1 $VDEV2
+typeset guid=$(get_config $TESTPOOL1 pool_guid)
+typeset target=$TESTPOOL1
+if (( RANDOM % 2 == 0 )) ; then
+       target=$guid
+       log_note "Import by guid."
+fi
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_note "Part of devices was renamed in the same directory."
+log_must $MV $VDEV0 $DEVICE_DIR/vdev0-new
+log_must $ZPOOL import -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy -f $TESTPOOL1
+
+log_note "All of devices was rename to different directories."
+log_must $MKDIR $DEVICE_DIR/newdir1 $DEVICE_DIR/newdir2
+log_must $MV $VDEV1 $DEVICE_DIR/newdir1/vdev1-new
+log_must $MV $VDEV2 $DEVICE_DIR/newdir2/vdev2-new
+log_must $ZPOOL import -d $DEVICE_DIR/newdir1 -d $DEVICE_DIR/newdir2 \
+       -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy -f $TESTPOOL1
+
+log_pass "Destroyed pools devices was renamed, 'zpool import -D' passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_006_pos.ksh
new file mode 100755 (executable)
index 0000000..b35e3cc
--- /dev/null
@@ -0,0 +1,83 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      For mirror, N-1 destroyed pools devices was removed or used by other
+#      pool, it still can be imported correctly.
+#
+# STRATEGY:
+#      1. Create mirror with N disks.
+#      2. Destroy this mirror.
+#      3. Create another pool with N-1 disks which was used by this mirror.
+#      4. Verify import mirror can succeed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_pool $TESTPOOL2
+       destroy_pool $TESTPOOL1
+
+       log_must $RM -rf $DEVICE_DIR/*
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               log_must $MKFILE $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
+               ((i += 1))
+       done
+}
+
+log_assert "For mirror, N-1 destroyed pools devices was removed or used " \
+       "by other pool, it still can be imported correctly."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 mirror $VDEV0 $VDEV1 $VDEV2
+typeset guid=$(get_config $TESTPOOL1 pool_guid)
+typeset target=$TESTPOOL1
+if (( RANDOM % 2 == 0 )) ; then
+       target=$guid
+       log_note "Import by guid."
+fi
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_must $ZPOOL create $TESTPOOL2 $VDEV0 $VDEV2
+log_must $ZPOOL import -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_must $ZPOOL destroy $TESTPOOL2
+log_must $RM -rf $VDEV2
+log_must $ZPOOL import -d $DEVICE_DIR -D -f $target
+
+log_pass "zpool import -D mirror passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_007_pos.ksh
new file mode 100755 (executable)
index 0000000..ec7a867
--- /dev/null
@@ -0,0 +1,90 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      For raidz, one destroyed pools devices was removed or used by other
+#      pool, it still can be imported correctly.
+#
+# STRATEGY:
+#      1. Create a raidz pool A with N disks.
+#      2. Destroy this pool A.
+#      3. Create another pool B with 1 disk which was used by pool A.
+#      4. Verify import this raidz pool can succeed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_pool $TESTPOOL2
+       destroy_pool $TESTPOOL1
+
+       log_must $RM -rf $DEVICE_DIR/*
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               log_must $MKFILE $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
+               ((i += 1))
+       done
+}
+
+log_assert "For raidz, one destroyed pools devices was removed or used by " \
+       "other pool, it still can be imported correctly."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 raidz $VDEV0 $VDEV1 $VDEV2 $VDIV3
+typeset guid=$(get_config $TESTPOOL1 pool_guid)
+typeset target=$TESTPOOL1
+if (( RANDOM % 2 == 0 )) ; then
+       target=$guid
+       log_note "Import by guid."
+fi
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_must $ZPOOL create $TESTPOOL2 $VDEV0
+log_must $ZPOOL import -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_must $ZPOOL destroy $TESTPOOL2
+log_must $RM -rf $VDEV0
+log_must $ZPOOL import -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_note "For raidz, two destroyed pool's devices were used, import failed."
+log_must $MKFILE $FILE_SIZE $VDEV0
+log_must $ZPOOL create $TESTPOOL2 $VDEV0 $VDEV1
+log_mustnot $ZPOOL import -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy $TESTPOOL2
+
+log_pass "zpool import -D raidz passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_008_pos.ksh
new file mode 100755 (executable)
index 0000000..45d76b3
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      For raidz2, two destroyed pool's devices were removed or used by other
+#      pool, it still can be imported correctly.
+#
+# STRATEGY:
+#      1. Create a raidz2 pool A with N disks.
+#      2. Destroy this pool A.
+#      3. Create another pool B with two disks which were used by pool A.
+#      4. Verify import this raidz2 pool can succeed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_pool $TESTPOOL2
+       destroy_pool $TESTPOOL1
+
+       log_must $RM -rf $DEVICE_DIR/*
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               log_must $MKFILE $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
+               ((i += 1))
+       done
+}
+
+log_assert "For raidz2, two destroyed pools devices was removed or used by " \
+       "other pool, it still can be imported correctly."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 raidz2 $VDEV0 $VDEV1 $VDEV2 $VDIV3
+typeset guid=$(get_config $TESTPOOL1 pool_guid)
+typeset target=$TESTPOOL1
+if (( RANDOM % 2 == 0 )) ; then
+       target=$guid
+       log_note "Import by guid."
+fi
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_must $ZPOOL create $TESTPOOL2 $VDEV0 $VDEV1
+log_must $ZPOOL import -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_must $ZPOOL destroy $TESTPOOL2
+log_must $RM -rf $VDEV0 $VDEV1
+log_must $ZPOOL import -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy $TESTPOOL1
+
+log_note "For raidz2, more than two destroyed pool's devices were used, " \
+       "import failed."
+log_must $MKFILE $FILE_SIZE $VDEV0 $VDEV1
+log_must $ZPOOL create $TESTPOOL2 $VDEV0 $VDEV1 $VDEV2
+log_mustnot $ZPOOL import -d $DEVICE_DIR -D -f $target
+log_must $ZPOOL destroy $TESTPOOL2
+
+log_pass "zpool import -D raidz2 passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_009_neg.ksh
new file mode 100755 (executable)
index 0000000..a572ba0
--- /dev/null
@@ -0,0 +1,103 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+# DESCRIPTION:
+#      Try each 'zpool import' with inapplicable scenarios to make sure
+#      it returns an error. include:
+#              * A non-existent pool name is given
+#              * '-d', but no device directory specified
+#              * '-R', but no alter root directory specified
+#              * '-a', but a pool name specified either
+#              * more than 2 pool names is given
+#              * The new pool name specified already exists
+#              * Contain invalid characters not allowed in the ZFS namespace
+#
+# STRATEGY:
+#      1. Create an array of parameters
+#      2. For each parameter in the array, execute the sub-command
+#      3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+set -A args "blah" "-d" "-R" "-a $TESTPOOL" \
+       "$TESTPOOL ${TESTPOOL}-new ${TESTPOOL}-new" \
+       "$TESTPOOL $TESTPOOL1" \
+       "$TESTPOOL ${TESTPOOL1}*" "$TESTPOOL ${TESTPOOL1}?"
+
+set -A pools "$TESTPOOL" "$TESTPOOL1"
+set -A devs "" "-d $DEVICE_DIR"
+
+function cleanup
+{
+       typeset -i i=0
+       typeset -i j=0
+
+       while (( i < ${#pools[*]} )); do
+
+               poolexists ${pools[i]} && \
+                       log_must $ZPOOL export ${pools[i]}
+
+               datasetexists "${pools[i]}/$TESTFS" || \
+                       log_must $ZPOOL import ${devs[i]} ${pools[i]}
+
+               ismounted "${pools[i]}/$TESTFS" || \
+                       log_must $ZFS mount ${pools[i]}/$TESTFS
+
+               ((i = i + 1))
+       done
+
+       cleanup_filesystem $TESTPOOL1 $TESTFS
+
+        destroy_pool $TESTPOOL1
+}
+
+log_onexit cleanup
+
+log_assert "Badly-formed 'zpool import' with inapplicable scenarios " \
+       "should return an error."
+
+setup_filesystem "$DEVICE_FILES" $TESTPOOL1 $TESTFS $TESTDIR1
+
+log_must $ZPOOL export $TESTPOOL
+
+typeset -i i=0
+while (( i < ${#args[*]} )); do
+       log_mustnot $ZPOOL import ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Badly formed 'zpool import' with inapplicable scenarios " \
+       "fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_010_pos.ksh
new file mode 100755 (executable)
index 0000000..23d7f91
--- /dev/null
@@ -0,0 +1,92 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      'zpool -D -a' can import all the specified directories destroyed pools.
+#
+# STRATEGY:
+#      1. Create a 5 ways mirror pool A with dev0/1/2/3/4, then destroy it.
+#      2. Create a stripe pool B with dev1. Then destroy it.
+#      3. Create a raidz2 pool C with dev2/3/4. Then destroy it.
+#      4. Create a raidz pool D with dev3/4. Then destroy it.
+#      5. Create a stripe pool E with dev4. Then destroy it.
+#      6. Verify 'zpool import -D -a' recover all the pools.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dt
+       for dt in $poolE $poolD $poolC $poolB $poolA; do
+               destroy_pool $dt
+       done
+
+       log_must $RM -rf $DEVICE_DIR/*
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               log_must $MKFILE $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
+               ((i += 1))
+       done
+}
+
+log_assert "'zpool -D -a' can import all the specified directories " \
+       "destroyed pools."
+log_onexit cleanup
+
+poolA=poolA.$$; poolB=poolB.$$; poolC=poolC.$$; poolD=poolD.$$; poolE=poolE.$$
+
+log_must $ZPOOL create $poolA mirror $VDEV0 $VDEV1 $VDEV2 $VDEV3 $VDEV4
+log_must $ZPOOL destroy $poolA
+
+log_must $ZPOOL create $poolB $VDEV1
+log_must $ZPOOL destroy $poolB
+
+log_must $ZPOOL create $poolC raidz2 $VDEV2 $VDEV3 $VDEV4
+log_must $ZPOOL destroy $poolC
+
+log_must $ZPOOL create $poolD raidz $VDEV3 $VDEV4
+log_must $ZPOOL destroy $poolD
+
+log_must $ZPOOL create $poolE $VDEV4
+log_must $ZPOOL destroy $poolE
+
+log_must $ZPOOL import -d $DEVICE_DIR -D -f -a
+
+for dt in $poolA $poolB $poolC $poolD $poolE; do
+       log_must datasetexists $dt
+done
+
+log_pass "'zpool -D -a' test passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_011_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_011_neg.ksh
new file mode 100755 (executable)
index 0000000..fbc6e6d
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      For strip pool, any destroyed pool devices was demaged, zpool import -D
+#      will failed.
+#
+# STRATEGY:
+#      1. Create strip pool A with three devices.
+#      2. Destroy this pool B.
+#      3. Create pool B with one of devices in step 1.
+#      4. Verify 'import -D' pool A will failed whenever pool B was destroyed
+#         or not.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_pool $TESTPOOL1
+       destroy_pool $TESTPOOL2
+
+       #
+       # Recreate virtual devices to avoid destroyed pool information on files.
+       #
+       log_must $RM -rf $VDEV0 $VDEV1 $VDEV2
+       log_must $MKFILE $FILE_SIZE $VDEV0 $VDEV1 $VDEV2
+}
+
+log_assert "For strip pool, any destroyed pool devices was demaged," \
+       "zpool import -D will failed."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 $VDEV0 $VDEV1 $VDEV2
+typeset guid=$(get_config $TESTPOOL1 pool_guid)
+typeset target=$TESTPOOL1
+if (( RANDOM % 2 == 0 )) ; then
+       target=$guid
+       log_note "Import by guid."
+fi
+log_must $ZPOOL destroy $TESTPOOL1
+log_must $ZPOOL create $TESTPOOL2 $VDEV2
+
+log_mustnot $ZPOOL import -d $DEVICE_DIR -D -f $target
+
+log_must $ZPOOL destroy $TESTPOOL2
+log_mustnot $ZPOOL import -d $DEVICE_DIR -D -f $target
+
+log_pass "Any strip pool devices damaged, pool can't be import passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_012_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_012_pos.ksh
new file mode 100755 (executable)
index 0000000..b4453b8
--- /dev/null
@@ -0,0 +1,209 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+# Once a pool has been exported, it should be recreated after a
+# successful import, all the sub-filesystems within it should all be restored,
+# include mount & share status. Verify that is true.
+#
+# STRATEGY:
+#      1. Create the test pool and hierarchical filesystems.
+#      2. Export the test pool, or destroy the test pool,
+#              depend on testing import [-Df].
+#      3. Import it using the various combinations.
+#              - Regular import
+#              - Alternate Root Specified
+#      4. Verify the mount & share status is restored.
+#
+
+verify_runnable "global"
+
+set -A pools "$TESTPOOL" "$TESTPOOL1"
+set -A devs "" "-d $DEVICE_DIR"
+set -A options "" "-R $ALTER_ROOT"
+set -A mtpts "$TESTDIR" "$TESTDIR1"
+
+
+function cleanup
+{
+       typeset -i i=0
+
+       while ((i < ${#pools[*]})); do
+               if poolexists ${pools[i]}; then
+                       log_must $ZPOOL export ${pools[i]}
+                       log_note "Try to import ${devs[i]} ${pools[i]}"
+                       $ZPOOL import ${devs[i]} ${pools[i]}
+               else
+                       log_note "Try to import $option ${devs[i]} ${pools[i]}"
+                       $ZPOOL import $option ${devs[i]} ${pools[i]}
+               fi
+
+               if poolexists ${pools[i]}; then
+                       is_shared ${pools[i]} && \
+                           log_must $ZFS set sharenfs=off ${pools[i]}
+
+                       ismounted "${pools[i]}/$TESTFS" || \
+                           log_must $ZFS mount ${pools[i]}/$TESTFS
+               fi
+
+               ((i = i + 1))
+       done
+
+       destroy_pool $TESTPOOL1
+
+       if datasetexists $TESTPOOL/$TESTFS; then
+               log_must $ZFS destroy -Rf $TESTPOOL/$TESTFS
+       fi
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+       [[ -d $ALTER_ROOT ]] && \
+               log_must $RM -rf $ALTER_ROOT
+}
+
+log_onexit cleanup
+
+log_assert "Verify all mount & share status of sub-filesystems within a pool \
+       can be restored after import [-Df]."
+
+setup_filesystem "$DEVICE_FILES" $TESTPOOL1 $TESTFS $TESTDIR1
+# create a heirarchy of filesystem
+for pool in ${pools[@]} ; do
+       log_must $ZFS create $pool/$TESTFS/$TESTCTR
+       log_must $ZFS create $pool/$TESTFS/$TESTCTR/$TESTCTR1
+       log_must $ZFS set canmount=off $pool/$TESTFS/$TESTCTR
+       log_must $ZFS set canmount=off $pool/$TESTFS/$TESTCTR/$TESTCTR1
+       log_must $ZFS create $pool/$TESTFS/$TESTCTR/$TESTFS1
+       log_must $ZFS create $pool/$TESTFS/$TESTCTR/$TESTCTR1/$TESTFS1
+       log_must $ZFS create $pool/$TESTFS/$TESTFS1
+       log_must $ZFS snapshot $pool/$TESTFS/$TESTFS1@snap
+       log_must $ZFS clone $pool/$TESTFS/$TESTFS1@snap $pool/$TESTCLONE1
+done
+
+typeset mount_fs="$TESTFS $TESTFS/$TESTFS1 $TESTCLONE1 \
+               $TESTFS/$TESTCTR/$TESTFS1 $TESTFS/$TESTCTR/$TESTCTR1/$TESTFS1"
+typeset nomount_fs="$TESTFS/$TESTCTR $TESTFS/$TESTCTR/$TESTCTR1"
+
+typeset -i i=0
+typeset -i j=0
+typeset -i nfs_share_bit=0
+typeset -i guid_bit=0
+typeset basedir
+
+for option in "" "-Df"; do
+       i=0
+       while ((i < ${#pools[*]})); do
+               pool=${pools[i]}
+               guid=$(get_pool_prop guid $pool)
+               j=0
+               while ((j < ${#options[*]})); do
+                       # set sharenfs property off/on
+                       nfs_share_bit=0
+                       while ((nfs_share_bit <= 1)); do
+                               typeset f_share=""
+                               typeset nfs_flag="sharenfs=off"
+                               if ((nfs_share_bit == 1)); then
+                                       log_note "Set sharenfs=on $pool"
+                                       log_must $ZFS set sharenfs=on $pool
+                                       log_must is_shared $pool
+                                       f_share="true"
+                                       nfs_flag="sharenfs=on"
+                               fi
+                               # for every off/on nfs bit import guid/pool_name
+                               guid_bit=0
+                               while ((guid_bit <= 1)); do
+                                       typeset guid_flag="pool name"
+                                       if [[ -z $option ]]; then
+                                               log_must $ZPOOL export $pool
+                                       else
+                                               log_must $ZPOOL destroy $pool
+                                       fi
+
+                                       typeset target=$pool
+                                       if ((guid_bit == 1)); then
+                                               log_note "Import by guid."
+                                               if [[ -z $guid ]]; then
+                                                       log_fail "guid should "\
+                                                           "not be empty!"
+                                               else
+                                                       target=$guid
+                                                       guid_flag="$guid"
+                                               fi
+                                       fi
+                                       log_note "Import with $nfs_flag and " \
+                                           "$guid_flag"
+                                       $ZPOOL import $option ${devs[i]} \
+                                           ${options[j]} $target
+                                       #import by GUID if import by pool name fails
+                                       if [[ $? != 0 ]]; then
+                                               log_note "Possible pool name" \
+                                                   "duplicates. Try GUID import"
+                                               target=$guid
+                                               log_must $ZPOOL import $option \
+                                                   ${devs[i]} ${options[j]} \
+                                                   $target
+                                       fi
+                                       log_must poolexists $pool
+
+                                       for fs in $mount_fs; do
+                                               log_must ismounted $pool/$fs
+                                               [[ -n $f_share ]] && \
+                                                   log_must is_shared $pool/$fs
+                                       done
+
+                                       for fs in $nomount_fs; do
+                                               log_mustnot ismounted $pool/$fs
+                                               log_mustnot is_shared $pool/$fs
+                                       done
+                                       ((guid_bit = guid_bit + 1))
+                               done
+                               # reset nfsshare=off
+                               if [[ -n $f_share ]]; then
+                                       log_must $ZFS set sharenfs=off $pool
+                                       log_mustnot is_shared $pool
+                               fi
+                               ((nfs_share_bit = nfs_share_bit + 1))
+                       done
+
+                       ((j = j + 1))
+               done
+
+               ((i = i + 1))
+       done
+done
+
+log_pass "All mount & share status of sub-filesystems within a pool \
+       can be restored after import [-Df]."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_013_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_013_neg.ksh
new file mode 100755 (executable)
index 0000000..f81738c
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      For pool may be in use from other system,
+#      'zpool import' will prompt the warning and fails.
+#
+# STRATEGY:
+#      1. Prepare rawfile that are created from other system.
+#      2. Verify 'zpool import' will fail.
+#      3. Verify 'zpool import -f' succeed.
+#
+
+verify_runnable "global"
+
+POOL_NAME=unclean_export
+POOL_FILE=unclean_export.dat
+
+function uncompress_pool
+{
+
+       log_note "Creating pool from $POOL_FILE"
+       log_must $BZCAT \
+           $STF_SUITE/tests/functional/cli_root/zpool_import/$POOL_FILE.bz2 \
+           > /$TESTPOOL/$POOL_FILE
+       return 0
+}
+
+function cleanup
+{
+       poolexists $POOL_NAME && log_must $ZPOOL destroy $POOL_NAME
+       [[ -e /$TESTPOOL/$POOL_FILE ]] && $RM /$TESTPOOL/$POOL_FILE
+       return 0
+}
+
+log_assert "'zpool import' fails for pool that was not cleanly exported"
+log_onexit cleanup
+
+uncompress_pool
+log_mustnot $ZPOOL import -d /$TESTPOOL $POOL_NAME
+log_must $ZPOOL import -d /$TESTPOOL -f $POOL_NAME
+
+log_pass "'zpool import' fails for pool that was not cleanly exported"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_all_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_all_001_pos.ksh
new file mode 100755 (executable)
index 0000000..6b83935
--- /dev/null
@@ -0,0 +1,223 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zpool import -a' succeeds as root.
+#
+# STRATEGY:
+# 1. Create a group of pools with specified vdev.
+# 2. Create zfs filesystems within the given pools.
+# 3. Export the pools.
+# 4. Verify that import command succeed.
+#
+
+verify_runnable "global"
+
+set -A options "" "-R $ALTER_ROOT"
+
+typeset -i number=0
+typeset -i id=0
+typeset -i i=0
+typeset checksum1
+typeset unwantedpool
+
+function setup_single_disk #disk #pool #fs #mtpt
+{
+       typeset disk=$1
+       typeset pool=$2
+       typeset fs=${3##/}
+       typeset mtpt=$4
+
+       setup_filesystem "$disk" "$pool" "$fs" "$mtpt"
+
+       log_must $CP $MYTESTFILE $mtpt/$TESTFILE0
+
+       log_must $ZPOOL export $pool
+
+       [[ -d $mtpt ]] && \
+               $RM -rf $mtpt
+}
+
+function cleanup_all
+{
+       typeset -i id=0
+
+       #
+       # Try import individually if 'import -a' failed.
+       #
+       for pool in `$ZPOOL import | $GREP "pool:" | $AWK '{print $2}'`; do
+               $ZPOOL import -f $pool
+       done
+
+       for pool in `$ZPOOL import -d $DEVICE_DIR | $GREP "pool:" | $AWK '{print $2}'`; do
+               log_must $ZPOOL import -d $DEVICE_DIR -f $pool
+       done
+
+       while (( id < number )); do
+               if ! poolexists ${TESTPOOL}-$id ; then
+                       (( id = id + 1 ))
+                       continue
+               fi
+
+               if (( id == 0 )); then
+                       log_must $ZPOOL export ${TESTPOOL}-$id
+
+                       [[ -d /${TESTPOOL}-$id ]] && \
+                               log_must $RM -rf /${TESTPOOL}-$id
+
+                       log_must $ZPOOL import -f ${TESTPOOL}-$id $TESTPOOL
+
+                       [[ -e $TESTDIR/$TESTFILE0 ]] && \
+                               log_must $RM -rf $TESTDIR/$TESTFILE0
+               else
+                       cleanup_filesystem "${TESTPOOL}-$id" $TESTFS
+
+                       destroy_pool ${TESTPOOL}-$id
+               fi
+
+               (( id = id + 1 ))
+        done
+
+       [[ -d $ALTER_ROOT ]] && \
+               $RM -rf $ALTER_ROOT
+}
+
+function checksum_all #alter_root
+{
+       typeset alter_root=$1
+       typeset -i id=0
+       typeset file
+       typeset checksum2
+
+       while (( id < number )); do
+               if (( id == 2 )); then
+                       (( id = id + 1 ))
+                       continue
+               fi
+
+               if (( id == 0 )); then
+                       file=${alter_root}/$TESTDIR/$TESTFILE0
+               else
+                       file=${alter_root}/$TESTDIR.$id/$TESTFILE0
+               fi
+               [[ ! -e $file ]] && \
+                       log_fail "$file missing after import."
+
+               checksum2=$($SUM $file | $AWK '{print $1}')
+               [[ "$checksum1" != "$checksum2" ]] && \
+                       log_fail "Checksums differ ($checksum1 != $checksum2)"
+
+               (( id = id + 1 ))
+       done
+
+       return 0
+}
+
+
+log_assert "Verify that 'zpool import -a' succeeds as root."
+
+log_onexit cleanup_all
+
+checksum1=$($SUM $MYTESTFILE | $AWK '{print $1}')
+
+log_must $ZPOOL export $TESTPOOL
+log_must $ZPOOL import $TESTPOOL ${TESTPOOL}-0
+log_must $CP $MYTESTFILE $TESTDIR/$TESTFILE0
+log_must $ZPOOL export ${TESTPOOL}-0
+[[ -d /${TESTPOOL}-0 ]] && \
+       log_must $RM -rf /${TESTPOOL}-0
+
+#
+# setup exported pools on normal devices
+#
+number=1
+while (( number <= $GROUP_NUM )); do
+       if (( number == 2)); then
+               (( number = number + 1 ))
+               continue
+       fi
+
+       setup_single_disk "${ZFS_DISK1}s${number}" \
+               "${TESTPOOL}-$number" \
+               "$TESTFS" \
+               "$TESTDIR.$number"
+
+       (( number = number + 1 ))
+done
+
+#
+# setup exported pools on raw files
+#
+for disk in $DEVICE_FILES
+do
+
+       setup_single_disk "$disk" \
+               "${TESTPOOL}-$number" \
+               "$TESTFS" \
+               "$TESTDIR.$number"
+
+       (( number = number + 1 ))
+done
+
+while (( i < ${#options[*]} )); do
+
+       log_must $ZPOOL import -d ${DEV_DSKDIR} -d $DEVICE_DIR ${options[i]} -a -f
+
+       # destroy unintentional imported pools
+       typeset exclude=`eval $ECHO \"'(${KEEP})'\"`
+       for unwantedpool in $($ZPOOL list -H -o name \
+            | $EGREP -v "$exclude" | $GREP -v $TESTPOOL); do
+               log_must $ZPOOL export $unwantedpool
+       done
+
+       if [[ -n ${options[i]} ]]; then
+               checksum_all $ALTER_ROOT
+       else
+               checksum_all
+       fi
+
+       id=0
+       while (( id < number )); do
+               if poolexists ${TESTPOOL}-$id ; then
+                       log_must $ZPOOL export ${TESTPOOL}-$id
+               fi
+               (( id = id + 1 ))
+       done
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool import -a' succeeds as root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_001_pos.ksh
new file mode 100755 (executable)
index 0000000..ea71acf
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#################################################################################
+#
+#  Pool can be imported with inactive unsupported features.
+#
+#  1. Create new pool.
+#  2. Export and inject unsuppored features with zhack.
+#  3. Import pool normally with no problems.
+#  4. Verify that unsupported@ properties exist for the unsupported features.
+#
+################################################################################
+
+verify_runnable "global"
+
+features="com.test:xxx_unsup0 com.test:xxx_unsup1 com.test:xxx_unsup2"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       log_must $RM $VDEV0
+       log_must $MKFILE $FILE_SIZE $VDEV0
+}
+
+log_assert "Pool with inactive unsupported features can be imported."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 $VDEV0
+log_must $ZPOOL export $TESTPOOL1
+
+for feature in $features; do
+       log_must $ZHACK -d $DEVICE_DIR feature enable $TESTPOOL1 $feature
+done
+
+log_must $ZPOOL import -d $DEVICE_DIR $TESTPOOL1
+for feature in $features; do
+       state=$($ZPOOL list -Ho unsupported@$feature $TESTPOOL1)
+        if [[ "$state" != "inactive" ]]; then
+               log_fail "unsupported@$feature is '$state'"
+        fi
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_002_neg.ksh
new file mode 100755 (executable)
index 0000000..26b99f0
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#################################################################################
+#
+#  Pool cannot be opened with active unsupported features. Error message should
+#  list active unsupported features.
+#
+#  1. Create new pool.
+#  2. Export and inject unsuppored features with zhack, make some of them active.
+#  3. Try to import pool, error should only list active features. It should
+#     not say anything about being able to import the pool in readonly mode.
+#
+################################################################################
+
+verify_runnable "global"
+
+enabled_features="com.test:xxx_unsup1 com.test:xxx_unsup3"
+active_features="com.test:xxx_unsup0 com.test:xxx_unsup2"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       log_must $RM $VDEV0
+       log_must $MKFILE $FILE_SIZE $VDEV0
+}
+
+log_assert "Pool with active unsupported features cannot be imported."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 $VDEV0
+log_must $ZPOOL export $TESTPOOL1
+
+for feature in $enabled_features $active_features; do
+       log_must $ZHACK -d $DEVICE_DIR feature enable $TESTPOOL1 $feature
+done
+
+for feature in $active_features; do
+       log_must $ZHACK -d $DEVICE_DIR feature ref $TESTPOOL1 $feature
+done
+
+log_mustnot $ZPOOL import -d $DEVICE_DIR $TESTPOOL1
+
+# error message should not mention "readonly"
+log_mustnot eval "$ZPOOL import -d $DEVICE_DIR $TESTPOOL1 | $GREP readonly"
+log_mustnot poolexists $TESTPOOL1
+
+for feature in $active_features; do
+       log_must eval "$ZPOOL import -d $DEVICE_DIR $TESTPOOL1 \
+           | $GREP $feature"
+       log_mustnot poolexists $TESTPOOL1
+done
+
+for feature in $enabled_features; do
+       log_mustnot eval "$ZPOOL import -d $DEVICE_DIR $TESTPOOL1 \
+           | $GREP $feature"
+       log_mustnot poolexists $TESTPOOL1
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_features_003_pos.ksh
new file mode 100755 (executable)
index 0000000..3f0ea63
--- /dev/null
@@ -0,0 +1,106 @@
+#!/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 (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#################################################################################
+#
+#  Pool can be imported with active read-only compatible features. If a feature
+#  is read-only compatible but also inactive its property status should be
+#  "inactive" rather than "readonly".
+#
+#  1. Create new pool.
+#  2. Export and inject variety of unsupported features.
+#  3. Try to import read-write, this should fail. The error should only list
+#     the active read-only compatible feature and mention "readonly=on".
+#  4. Import the pool in read-only mode.
+#  5. Verify values of unsupported@ properties.
+#
+################################################################################
+
+verify_runnable "global"
+
+enabled_features="com.test:xxx_unsup0 com.test:xxx_unsup2"
+active_features="com.test:xxx_unsup1 com.test:xxx_unsup3"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       log_must $RM $VDEV0
+       log_must $MKFILE $FILE_SIZE $VDEV0
+}
+
+log_assert "Pool with active read-only compatible features can be imported."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL1 $VDEV0
+log_must $ZPOOL export $TESTPOOL1
+
+for feature in $enabled_features $active_features; do
+       log_must $ZHACK -d $DEVICE_DIR feature enable -r $TESTPOOL1 $feature
+done
+
+for feature in $active_features; do
+       log_must $ZHACK -d $DEVICE_DIR feature ref $TESTPOOL1 $feature
+done
+
+log_mustnot $ZPOOL import -d $DEVICE_DIR $TESTPOOL1
+
+# error message should mention "readonly"
+log_must eval "$ZPOOL import -d $DEVICE_DIR $TESTPOOL1 | $GREP readonly"
+log_mustnot poolexists $TESTPOOL1
+
+for feature in $enabled_features; do
+       log_mustnot eval "$ZPOOL import -d $DEVICE_DIR $TESTPOOL1 \
+           | $GREP $feature"
+       log_mustnot poolexists $TESTPOOL1
+done
+
+for feature in $active_features; do
+       log_must eval "$ZPOOL import -d $DEVICE_DIR $TESTPOOL1 \
+           | $GREP $feature"
+       log_mustnot poolexists $TESTPOOL1
+done
+
+log_must $ZPOOL import -o readonly=on -d $DEVICE_DIR $TESTPOOL1
+
+for feature in $enabled_features; do
+       state=$($ZPOOL list -Ho unsupported@$feature $TESTPOOL1)
+        if [[ "$state" != "inactive" ]]; then
+               log_fail "unsupported@$feature is '$state'"
+        fi
+done
+
+for feature in $active_features; do
+       state=$($ZPOOL list -Ho unsupported@$feature $TESTPOOL1)
+        if [[ "$state" != "readonly" ]]; then
+               log_fail "unsupported@$feature is '$state'"
+        fi
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_001_pos.ksh
new file mode 100755 (executable)
index 0000000..d044759
--- /dev/null
@@ -0,0 +1,203 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      Once a pool has been exported, and one or more devices are
+#      damaged or missing (d/m), import should handle this kind of situation
+#      as described:
+#              - Regular, report error while any number of devices failing.
+#              - Mirror could withstand (N-1) devices failing
+#                before data integrity is compromised
+#              - Raidz could withstand one devices failing
+#                before data integrity is compromised
+#      Verify those are true.
+#
+# STRATEGY:
+#      1. Create test pool upon device files using the various combinations.
+#              - Regular pool
+#              - Mirror
+#              - Raidz
+#      2. Create necessary filesystem and test files.
+#      3. Export the test pool.
+#      4. Remove one or more devices
+#      5. Verify 'zpool import' will handle d/m device successfully.
+#         Using the various combinations.
+#              - Regular import
+#              - Alternate Root Specified
+#         It should be succeed with single d/m device upon 'raidz' & 'mirror',
+#         but failed against 'regular' or more d/m devices.
+#      6. If import succeed, verify following is true:
+#              - The pool shows up under 'zpool list'.
+#              - The pool's health should be DEGRADED.
+#              - It contains the correct test file
+#
+
+verify_runnable "global"
+
+set -A vdevs "" "mirror" "raidz"
+set -A options "" "-R $ALTER_ROOT"
+
+function cleanup
+{
+       # recover the vdevs
+       recreate_files
+
+       [[ -d $ALTER_ROOT ]] && \
+               log_must $RM -rf $ALTER_ROOT
+}
+
+function recreate_files
+{
+       if poolexists "$TESTPOOL1" ; then
+               cleanup_filesystem $TESTPOOL1 $TESTFS
+               destroy_pool $TESTPOOL1
+       fi
+
+       log_must $RM -rf $DEVICE_DIR/*
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               log_must $MKFILE $FILE_SIZE ${DEVICE_DIR}/${DEVICE_FILE}$i
+               ((i += 1))
+       done
+}
+
+log_onexit cleanup
+
+log_assert "Verify that import could handle damaged or missing device."
+
+CWD=$PWD
+cd $DEVICE_DIR || log_fail "Unable change directory to $DEVICE_DIR"
+
+checksum1=$($SUM $MYTESTFILE | $AWK '{print $1}')
+
+typeset -i i=0
+typeset -i j=0
+typeset -i count=0
+typeset basedir backup
+
+while (( i < ${#vdevs[*]} )); do
+
+       setup_filesystem "$DEVICE_FILES" \
+               $TESTPOOL1 $TESTFS $TESTDIR1 \
+               "" ${vdevs[i]}
+
+       backup=""
+
+       guid=$(get_config $TESTPOOL1 pool_guid)
+       log_must $CP $MYTESTFILE $TESTDIR1/$TESTFILE0
+
+       log_must $ZFS umount $TESTDIR1
+
+       j=0
+       while (( j <  ${#options[*]} )); do
+
+               count=0
+               action=log_must
+
+               #
+               # Restore all device files.
+               #
+               [[ -n $backup ]] && \
+                       log_must $TAR xf $DEVICE_DIR/$DEVICE_ARCHIVE
+
+               for device in $DEVICE_FILES ; do
+                       log_must $RM -f $device
+
+                       poolexists $TESTPOOL1 && \
+                               log_must $ZPOOL export $TESTPOOL1
+
+                       #
+                       # Backup all device files while filesystem prepared.
+                       #
+                       if [[ -z $backup ]]; then
+                               log_must $TAR cf $DEVICE_DIR/$DEVICE_ARCHIVE \
+                                       ${DEVICE_FILE}*
+                               backup="true"
+                       fi
+
+                       (( count = count + 1 ))
+
+                       case "${vdevs[i]}" in
+                               'mirror') (( count == $GROUP_NUM )) && \
+                                               action=log_mustnot
+                                       ;;
+                               'raidz')  (( count > 1 )) && \
+                                               action=log_mustnot
+                                       ;;
+                               '')  action=log_mustnot
+                                       ;;
+                       esac
+
+                       typeset target=$TESTPOOL1
+                       if (( RANDOM % 2 == 0 )) ; then
+                               target=$guid
+                               log_note "Import by guid."
+                       fi
+                       $action $ZPOOL import \
+                               -d $DEVICE_DIR ${options[j]} $target
+
+                       [[ $action == "log_mustnot" ]] && continue
+
+                       log_must poolexists $TESTPOOL1
+
+                       health=$($ZPOOL list -H -o health $TESTPOOL1)
+
+                       [[ $health == "DEGRADED" ]] || \
+                               log_fail "$TESTPOOL1: Incorrect health($health)"
+                       log_must ismounted $TESTPOOL1/$TESTFS
+
+                       basedir=$TESTDIR1
+                       [[ -n ${options[j]} ]] && \
+                               basedir=$ALTER_ROOT/$TESTDIR1
+
+                       [[ ! -e $basedir/$TESTFILE0 ]] && \
+                               log_fail "$basedir/$TESTFILE0 missing after import."
+
+                       checksum2=$($SUM $basedir/$TESTFILE0 | $AWK '{print $1}')
+                       [[ "$checksum1" != "$checksum2" ]] && \
+                               log_fail "Checksums differ ($checksum1 != $checksum2)"
+
+               done
+
+               ((j = j + 1))
+       done
+
+       recreate_files
+
+       ((i = i + 1))
+done
+
+log_pass "Import could handle damaged or missing device."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_002_pos.ksh
new file mode 100755 (executable)
index 0000000..36fbe44
--- /dev/null
@@ -0,0 +1,197 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      Once a pool has been exported, and one or more devices are
+#      move to other place, import should handle this kind of situation
+#      as described:
+#              - Regular, report error while any number of devices failing.
+#              - Mirror could withstand (N-1) devices failing
+#                before data integrity is compromised
+#              - Raidz could withstand one devices failing
+#                before data integrity is compromised
+#      Verify that is true.
+#
+# STRATEGY:
+#      1. Create test pool upon device files using the various combinations.
+#              - Regular pool
+#              - Mirror
+#              - Raidz
+#      2. Create necessary filesystem and test files.
+#      3. Export the test pool.
+#      4. Move one or more device files to other directory
+#      5. Verify 'zpool import -d' with the new directory
+#         will handle moved files successfullly.
+#         Using the various combinations.
+#              - Regular import
+#              - Alternate Root Specified
+#
+
+verify_runnable "global"
+
+set -A vdevs "" "mirror" "raidz"
+set -A options "" "-R $ALTER_ROOT"
+
+function cleanup
+{
+       cd $DEVICE_DIR || log_fail "Unable change directory to $DEVICE_DIR"
+       [[ -e $DEVICE_DIR/$DEVICE_ARCHIVE ]] && \
+               log_must $TAR xf $DEVICE_DIR/$DEVICE_ARCHIVE
+
+       poolexists $TESTPOOL1 || \
+               log_must $ZPOOL import -d $DEVICE_DIR $TESTPOOL1
+
+       cleanup_filesystem $TESTPOOL1 $TESTFS
+
+       destroy_pool $TESTPOOL1
+}
+
+function cleanup_all
+{
+       cleanup
+
+       # recover dev files
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               typeset dev_file=${DEVICE_DIR}/${DEVICE_FILE}$i
+               if [[ ! -e ${dev_file} ]]; then
+                       log_must $MKFILE $FILE_SIZE ${dev_file}
+               fi
+               ((i += 1))
+       done
+
+       log_must $RM -f $DEVICE_DIR/$DEVICE_ARCHIVE
+       cd $CWD || log_fail "Unable change directory to $CWD"
+
+       [[ -d $ALTER_ROOT ]] && \
+               log_must $RM -rf $ALTER_ROOT
+
+       [[ -d $BACKUP_DEVICE_DIR ]] && \
+               log_must $RM -rf $BACKUP_DEVICE_DIR
+}
+
+log_onexit cleanup_all
+
+log_assert "Verify that import could handle moving device."
+
+CWD=$PWD
+
+[[ ! -d $BACKUP_DEVICE_DIR ]] &&
+       log_must $MKDIR -p $BACKUP_DEVICE_DIR
+
+cd $DEVICE_DIR || log_fail "Unable change directory to $DEVICE_DIR"
+
+typeset -i i=0
+typeset -i j=0
+typeset -i count=0
+typeset basedir backup
+typeset action
+
+while (( i < ${#vdevs[*]} )); do
+
+       (( i != 0 )) && \
+               log_must $TAR xf $DEVICE_DIR/$DEVICE_ARCHIVE
+
+       setup_filesystem "$DEVICE_FILES" \
+               $TESTPOOL1 $TESTFS $TESTDIR1 \
+               "" ${vdevs[i]}
+
+       guid=$(get_config $TESTPOOL1 pool_guid)
+       backup=""
+
+       log_must $CP $MYTESTFILE $TESTDIR1/$TESTFILE0
+
+       log_must $ZFS umount $TESTDIR1
+
+       j=0
+       while (( j <  ${#options[*]} )); do
+
+               count=0
+
+               #
+               # Restore all device files.
+               #
+               [[ -n $backup ]] && \
+                       log_must $TAR xf $DEVICE_DIR/$DEVICE_ARCHIVE
+
+               log_must $RM -f $BACKUP_DEVICE_DIR/*
+
+               for device in $DEVICE_FILES ; do
+
+                       poolexists $TESTPOOL1 && \
+                               log_must $ZPOOL export $TESTPOOL1
+
+                       #
+                       # Backup all device files while filesystem prepared.
+                       #
+                       if [[ -z $backup ]] ; then
+                               log_must $TAR cf $DEVICE_DIR/$DEVICE_ARCHIVE ${DEVICE_FILE}*
+                               backup="true"
+                       fi
+
+                       log_must $MV $device $BACKUP_DEVICE_DIR
+
+                       (( count = count + 1 ))
+
+                       action=log_mustnot
+                       case "${vdevs[i]}" in
+                               'mirror') (( count < $GROUP_NUM )) && \
+                                       action=log_must
+                                       ;;
+                               'raidz')  (( count == 1 )) && \
+                                       action=log_must
+                                       ;;
+                       esac
+
+                       typeset target=$TESTPOOL1
+                       if (( RANDOM % 2 == 0 )) ; then
+                               target=$guid
+                               log_note "Import by guid."
+                       fi
+                       $action $ZPOOL import \
+                               -d $DEVICE_DIR ${options[j]} $target
+
+               done
+
+               ((j = j + 1))
+       done
+
+       cleanup
+
+       ((i = i + 1))
+done
+
+log_pass "Import could handle moving device."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_missing_003_pos.ksh
new file mode 100755 (executable)
index 0000000..7f2d4f4
--- /dev/null
@@ -0,0 +1,232 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+#      Once a pool has been exported, but one or more devices are
+#      overlapped with other exported pool, import should handle
+#      this kind of situation properly.
+#
+# STRATEGY:
+#      1. Repeat 1-3, create two test pools upon device files separately.
+#         These two pools should have one or more devices are overlapped.
+#         using the various combinations.
+#              - Regular pool
+#              - Mirror
+#              - Raidz
+#      2. Create necessary filesystem and test files.
+#      3. Export the test pool.
+#      4. Verify 'zpool import -d' with these two pools will have results
+#         as described:
+#              - Regular, report error while any number of devices failing.
+#              - Mirror could withstand (N-1) devices failing
+#                before data integrity is compromised
+#              - Raidz could withstand one devices failing
+#                before data integrity is compromised
+#
+
+verify_runnable "global"
+
+set -A vdevs "" "mirror" "raidz"
+
+function verify
+{
+       typeset pool=$1
+       typeset fs=$2
+       typeset mtpt=$3
+       typeset health=$4
+       typeset file=$5
+       typeset checksum1=$6
+
+       typeset myhealth
+       typeset mymtpt
+       typeset checksum2
+
+       log_must poolexists $pool
+
+       myhealth=$($ZPOOL list -H -o health $pool)
+
+       [[ $myhealth == $health ]] || \
+               log_fail "$pool: Incorrect health ($myhealth), " \
+                       "expected ($health)."
+
+       log_must ismounted $pool/$fs
+
+       mymtpt=$(get_prop mountpoint $pool/$fs)
+       [[ $mymtpt == $mtpt ]] || \
+               log_fail "$pool/$fs: Incorrect mountpoint ($mymtpt), " \
+                       "expected ($mtpt)."
+
+       [[ ! -e $mtpt/$file ]] && \
+               log_fail "$mtpt/$file missing after import."
+
+       checksum2=$($SUM $mymtpt/$file | $AWK '{print $1}')
+       [[ "$checksum1" != "$checksum2" ]] && \
+               log_fail "Checksums differ ($checksum1 != $checksum2)"
+
+       return 0
+
+}
+
+function cleanup
+{
+       cd $DEVICE_DIR || log_fail "Unable change directory to $DEVICE_DIR"
+
+       for pool in $TESTPOOL1 $TESTPOOL2; do
+               if poolexists "$pool" ; then
+                       cleanup_filesystem $pool $TESTFS
+                       destroy_pool $pool
+               fi
+       done
+
+       [[ -e $DEVICE_DIR/$DEVICE_ARCHIVE ]] && \
+               log_must $TAR xf $DEVICE_DIR/$DEVICE_ARCHIVE
+}
+
+function cleanup_all
+{
+       cleanup
+
+       # recover dev files
+       typeset i=0
+       while (( i < $MAX_NUM )); do
+               typeset file=${DEVICE_DIR}/${DEVICE_FILE}$i
+               if  [[ -e $file ]]; then
+                       log_must $RM $file
+               fi
+               log_must $MKFILE $FILE_SIZE $file
+               ((i += 1))
+       done
+
+       log_must $RM -f $DEVICE_DIR/$DEVICE_ARCHIVE
+       cd $CWD || log_fail "Unable change directory to $CWD"
+
+}
+
+log_onexit cleanup_all
+
+log_assert "Verify that import could handle device overlapped."
+
+CWD=$PWD
+
+cd $DEVICE_DIR || log_fail "Unable change directory to $DEVICE_DIR"
+log_must $TAR cf $DEVICE_DIR/$DEVICE_ARCHIVE ${DEVICE_FILE}*
+
+checksum1=$($SUM $MYTESTFILE | $AWK '{print $1}')
+
+typeset -i i=0
+typeset -i j=0
+typeset -i count=0
+typeset -i num=0
+typeset vdev1=""
+typeset vdev2=""
+typeset action
+
+while (( num < $GROUP_NUM )); do
+       vdev1="$vdev1 ${DEVICE_DIR}/${DEVICE_FILE}$num"
+       (( num = num + 1 ))
+done
+
+while (( i < ${#vdevs[*]} )); do
+       j=0
+       while (( j < ${#vdevs[*]} )); do
+
+               (( j != 0 )) && \
+                       log_must $TAR xf $DEVICE_DIR/$DEVICE_ARCHIVE
+
+               typeset -i overlap=1
+               typeset -i begin
+               typeset -i end
+
+               while (( overlap <= $GROUP_NUM )); do
+                       vdev2=""
+                       (( begin = $GROUP_NUM - overlap ))
+                       (( end = 2 * $GROUP_NUM - overlap - 1 ))
+                       (( num = begin ))
+                       while (( num <= end )); do
+                               vdev2="$vdev2 ${DEVICE_DIR}/${DEVICE_FILE}$num"
+                               (( num = num + 1 ))
+                       done
+
+                       setup_filesystem "$vdev1" $TESTPOOL1 $TESTFS $TESTDIR1 \
+                               "" ${vdevs[i]}
+                       log_must $CP $MYTESTFILE $TESTDIR1/$TESTFILE0
+                       log_must $ZFS umount $TESTDIR1
+                       poolexists $TESTPOOL1 && \
+                               log_must $ZPOOL export $TESTPOOL1
+
+                       setup_filesystem "$vdev2" $TESTPOOL2 $TESTFS $TESTDIR2 \
+                               "" ${vdevs[j]}
+                       log_must $CP $MYTESTFILE $TESTDIR2/$TESTFILE0
+                       log_must $ZFS umount $TESTDIR2
+                       poolexists $TESTPOOL2 && \
+                               log_must $ZPOOL export $TESTPOOL2
+
+                       action=log_must
+                       case "${vdevs[i]}" in
+                               'mirror') (( overlap == $GROUP_NUM )) && \
+                                       action=log_mustnot
+                                       ;;
+                               'raidz')  (( overlap > 1 )) && \
+                                       action=log_mustnot
+                                       ;;
+                               '')  action=log_mustnot
+                                       ;;
+                       esac
+
+                       $action $ZPOOL import -d $DEVICE_DIR $TESTPOOL1
+                       log_must $ZPOOL import -d $DEVICE_DIR $TESTPOOL2
+
+                       if [[ $action == log_must ]]; then
+                               verify "$TESTPOOL1" "$TESTFS" "$TESTDIR1" \
+                                       "DEGRADED" "$TESTFILE0" "$checksum1"
+                       fi
+
+                       verify "$TESTPOOL2" "$TESTFS" "$TESTDIR2" \
+                               "ONLINE" "$TESTFILE0" "$checksum1"
+
+                       cleanup
+
+                       (( overlap = overlap + 1 ))
+
+               done
+
+               ((j = j + 1))
+       done
+
+       ((i = i + 1))
+done
+
+log_pass "Import could handle device overlapped."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_rename_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_import/zpool_import_rename_001_pos.ksh
new file mode 100755 (executable)
index 0000000..441f7a7
--- /dev/null
@@ -0,0 +1,173 @@
+#!/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, 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
+. $STF_SUITE/tests/functional/cli_root/zpool_import/zpool_import.cfg
+
+#
+# DESCRIPTION:
+# An exported pool can be imported under a different name. Hence
+# we test that a previously exported pool can be renamed.
+#
+# STRATEGY:
+#      1. Copy a file into the default test directory.
+#      2. Umount the default directory.
+#      3. Export the pool.
+#      4. Import the pool using the name ${TESTPOOL}-new,
+#         and using the various combinations.
+#               - Regular import
+#               - Alternate Root Specified
+#      5. Verify it exists in the 'zpool list' output.
+#      6. Verify the default file system is mounted and that the file
+#         from step (1) is present.
+#
+
+verify_runnable "global"
+
+set -A pools "$TESTPOOL" "$TESTPOOL1"
+set -A devs "" "-d $DEVICE_DIR"
+set -A options "" "-R $ALTER_ROOT"
+set -A mtpts "$TESTDIR" "$TESTDIR1"
+
+
+function cleanup
+{
+       typeset -i i=0
+       while (( i < ${#pools[*]} )); do
+               if poolexists "${pools[i]}-new" ; then
+                       log_must $ZPOOL export "${pools[i]}-new"
+
+                       [[ -d /${pools[i]}-new ]] && \
+                               log_must $RM -rf /${pools[i]}-new
+
+                       log_must $ZPOOL import ${devs[i]} \
+                               "${pools[i]}-new" ${pools[i]}
+               fi
+
+               datasetexists "${pools[i]}" || \
+                       log_must $ZPOOL import ${devs[i]} ${pools[i]}
+
+               ismounted "${pools[i]}/$TESTFS" || \
+                       log_must $ZFS mount ${pools[i]}/$TESTFS
+
+               [[ -e ${mtpts[i]}/$TESTFILE0 ]] && \
+                       log_must $RM -rf ${mtpts[i]}/$TESTFILE0
+
+               ((i = i + 1))
+
+       done
+
+       cleanup_filesystem $TESTPOOL1 $TESTFS $TESTDIR1
+
+       destroy_pool $TESTPOOL1
+
+       [[ -d $ALTER_ROOT ]] && \
+               log_must $RM -rf $ALTER_ROOT
+       [[ -e $VDEV_FILE ]] && \
+               log_must $RM $VDEV_FILE
+}
+
+log_onexit cleanup
+
+log_assert "Verify that an imported pool can be renamed."
+
+setup_filesystem "$DEVICE_FILES" $TESTPOOL1 $TESTFS $TESTDIR1
+checksum1=$($SUM $MYTESTFILE | $AWK '{print $1}')
+
+typeset -i i=0
+typeset -i j=0
+typeset basedir
+
+while (( i < ${#pools[*]} )); do
+       guid=$(get_config ${pools[i]} pool_guid)
+       log_must $CP $MYTESTFILE ${mtpts[i]}/$TESTFILE0
+
+       log_must $ZFS umount ${mtpts[i]}
+
+       j=0
+       while (( j <  ${#options[*]} )); do
+               log_must $ZPOOL export ${pools[i]}
+
+               [[ -d /${pools[i]} ]] && \
+                       log_must $RM -rf /${pools[i]}
+
+               typeset target=${pools[i]}
+               if (( RANDOM % 2 == 0 )) ; then
+                       target=$guid
+                       log_note "Import by guid."
+               fi
+
+               log_must $ZPOOL import ${devs[i]} ${options[j]} \
+                       $target ${pools[i]}-new
+
+               log_must poolexists "${pools[i]}-new"
+
+               log_must ismounted ${pools[i]}-new/$TESTFS
+
+               basedir=${mtpts[i]}
+               [[ -n ${options[j]} ]] && \
+                       basedir=$ALTER_ROOT/${mtpts[i]}
+
+               [[ ! -e $basedir/$TESTFILE0 ]] && \
+                       log_fail "$basedir/$TESTFILE0 missing after import."
+
+               checksum2=$($SUM $basedir/$TESTFILE0 | $AWK '{print $1}')
+               [[ "$checksum1" != "$checksum2" ]] && \
+                       log_fail "Checksums differ ($checksum1 != $checksum2)"
+
+               log_must $ZPOOL export "${pools[i]}-new"
+
+               [[ -d /${pools[i]}-new ]] && \
+                       log_must $RM -rf /${pools[i]}-new
+
+               target=${pools[i]}-new
+               if (( RANDOM % 2 == 0 )) ; then
+                       target=$guid
+               fi
+               log_must $ZPOOL import ${devs[i]} $target ${pools[i]}
+
+               ((j = j + 1))
+       done
+
+       ((i = i + 1))
+done
+
+VDEV_FILE=$(mktemp /tmp/tmp.XXXXXX)
+
+log_must $MKFILE -n 128M $VDEV_FILE
+log_must $ZPOOL create testpool $VDEV_FILE
+log_must $ZFS create testpool/testfs
+ID=$($ZPOOL get -Ho value guid testpool)
+log_must $ZPOOL export testpool
+log_mustnot $ZPOOL import $(echo $ID) $($PRINTF "%*s\n" 250 "" | $TR ' ' 'c')
+
+log_pass "Successfully imported and renamed a ZPOOL"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/Makefile.am
new file mode 100644 (file)
index 0000000..6bb5fbf
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_offline
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_offline_001_pos.ksh \
+       zpool_offline_002_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/cleanup.ksh
new file mode 100755 (executable)
index 0000000..89c1462
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/setup.ksh
new file mode 100755 (executable)
index 0000000..2229f87
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+DISK=${DISKS%% *}
+
+default_mirror_setup $DISKS
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/zpool_offline_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/zpool_offline_001_pos.ksh
new file mode 100755 (executable)
index 0000000..ddd6574
--- /dev/null
@@ -0,0 +1,120 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool offline' with valid parameters succeeds.
+#
+# STRATEGY:
+# 1. Create an array of correctly formed 'zpool offline' options
+# 2. Execute each element of the array.
+# 3. Verify use of each option is successful.
+#
+
+verify_runnable "global"
+
+DISKLIST=$(get_disklist $TESTPOOL)
+set -A disks $DISKLIST
+typeset -i num=${#disks[*]}
+
+set -A args "" "-t"
+
+function cleanup
+{
+       #
+       # Ensure we don't leave disks in the offline state
+       #
+       for disk in $DISKLIST; do
+               log_must $ZPOOL online $TESTPOOL $disk
+               check_state $TESTPOOL $disk "online"
+               if [[ $? != 0 ]]; then
+                       log_fail "Unable to online $disk"
+               fi
+
+       done
+}
+
+log_assert "Executing 'zpool offline' with correct options succeeds"
+
+log_onexit cleanup
+
+if [[ -z $DISKLIST ]]; then
+       log_fail "DISKLIST is empty."
+fi
+
+typeset -i i=0
+typeset -i j=1
+
+for disk in $DISKLIST; do
+       i=0
+       while [[ $i -lt ${#args[*]} ]]; do
+               if (( j < num )) ; then
+                       log_must $ZPOOL offline ${args[$i]} $TESTPOOL $disk
+                       check_state $TESTPOOL $disk "offline"
+                       if [[ $? != 0 ]]; then
+                               log_fail "$disk of $TESTPOOL did not match offline state"
+                       fi
+               else
+                       log_mustnot $ZPOOL offline ${args[$i]} $TESTPOOL $disk
+                       check_state $TESTPOOL $disk "online"
+                       if [[ $? != 0 ]]; then
+                               log_fail "$disk of $TESTPOOL did not match online state"
+                       fi
+               fi
+
+               (( i = i + 1 ))
+       done
+       (( j = j + 1 ))
+done
+
+log_note "Issuing repeated 'zpool offline' commands succeeds."
+
+typeset -i iters=20
+typeset -i index=0
+
+for disk in $DISKLIST; do
+        i=0
+        while [[ $i -lt $iters ]]; do
+               index=`expr $RANDOM % ${#args[*]}`
+                log_must $ZPOOL offline ${args[$index]} $TESTPOOL $disk
+                check_state $TESTPOOL $disk "offline"
+                if [[ $? != 0 ]]; then
+                        log_fail "$disk of $TESTPOOL is not offline."
+                fi
+
+                (( i = i + 1 ))
+        done
+
+       log_must $ZPOOL online $TESTPOOL $disk
+       check_state $TESTPOOL $disk "online"
+       if [[ $? != 0 ]]; then
+               log_fail "$disk of $TESTPOOL did not match online state"
+       fi
+done
+
+log_pass "'zpool offline' with correct options succeeded"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/zpool_offline_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_offline/zpool_offline_002_neg.ksh
new file mode 100755 (executable)
index 0000000..9834d07
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool offline' command with bad options fails.
+#
+# STRATEGY:
+# 1. Create an array of badly formed 'zpool offline' options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "global"
+
+DISKLIST=$(get_disklist $TESTPOOL)
+
+set -A args "" "-?" "-t fakepool" "-f fakepool" "-ev fakepool" "fakepool" \
+       "-t $TESTPOOL" "-t $TESTPOOL/$TESTFS" "-t $TESTPOOL/$TESTFS $DISKLIST" \
+       "-t $TESTPOOL/$TESTCTR" "-t $TESTPOOL/$TESTCTR/$TESTFS1" \
+       "-t $TESTPOOL/$TESTCTR $DISKLIST" "-t $TESTPOOL/$TESTVOL" \
+       "-t $TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+       "-t $TESTPOOL/$TESTVOL $DISKLIST" \
+       "-t $DISKLIST" \
+        "-f $TESTPOOL" "-f $TESTPOOL/$TESTFS" "-f $TESTPOOL/$TESTFS $DISKLIST" \
+        "-f $TESTPOOL/$TESTCTR" "-f $TESTPOOL/$TESTCTR/$TESTFS1" \
+        "-f $TESTPOOL/$TESTCTR $DISKLIST" "-f $TESTPOOL/$TESTVOL" \
+        "-f $TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+        "-f $TESTPOOL/$TESTVOL $DISKLIST" \
+        "-f $DISKLIST" \
+        "-ft $TESTPOOL" "-ft $TESTPOOL/$TESTFS" \
+       "-ft $TESTPOOL/$TESTFS $DISKLIST" \
+        "-ft $TESTPOOL/$TESTCTR" "-ft $TESTPOOL/$TESTCTR/$TESTFS1" \
+        "-ft $TESTPOOL/$TESTCTR $DISKLIST" "-ft $TESTPOOL/$TESTVOL" \
+        "-ft $TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+        "-ft $TESTPOOL/$TESTVOL $DISKLIST" \
+        "-ft $DISKLIST" \
+        "-tf $TESTPOOL" "-tf $TESTPOOL/$TESTFS" \
+       "-tf $TESTPOOL/$TESTFS $DISKLIST" \
+        "-tf $TESTPOOL/$TESTCTR" "-tf $TESTPOOL/$TESTCTR/$TESTFS1" \
+        "-tf $TESTPOOL/$TESTCTR $DISKLIST" "-tf $TESTPOOL/$TESTVOL" \
+        "-tf $TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+        "-tf $TESTPOOL/$TESTVOL $DISKLIST" \
+        "-tf $DISKLIST" \
+       "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTFS $DISKLIST" \
+       "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTCTR/$TESTFS1" \
+       "$TESTPOOL/$TESTCTR $DISKLIST" "$TESTPOOL/$TESTVOL" \
+       "$TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" "$TESTPOOL/$TESTVOL $DISKLIST" \
+       "$DISKLIST"
+
+log_assert "Executing 'zpool offline' with bad options fails"
+
+if [[ -z $DISKLIST ]]; then
+       log_fail "DISKLIST is empty."
+fi
+
+typeset -i i=0
+
+while [[ $i -lt ${#args[*]} ]]; do
+
+       log_mustnot $ZPOOL offline ${args[$i]}
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool offline' command with bad options failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/Makefile.am
new file mode 100644 (file)
index 0000000..12681e3
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_online
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_online_001_pos.ksh \
+       zpool_online_002_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/cleanup.ksh
new file mode 100755 (executable)
index 0000000..89c1462
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/setup.ksh
new file mode 100755 (executable)
index 0000000..2229f87
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+DISK=${DISKS%% *}
+
+default_mirror_setup $DISKS
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/zpool_online_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/zpool_online_001_pos.ksh
new file mode 100755 (executable)
index 0000000..f1ed6a0
--- /dev/null
@@ -0,0 +1,108 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool online' with valid parameters succeeds.
+#
+# STRATEGY:
+# 1. Create an array of correctly formed 'zpool online' options
+# 2. Execute each element of the array.
+# 3. Verify use of each option is successful.
+#
+
+verify_runnable "global"
+
+DISKLIST=$(get_disklist $TESTPOOL)
+
+set -A args ""
+
+function cleanup
+{
+       #
+       # Ensure we don't leave disks in temporary online state (-t)
+       #
+       for disk in $DISKLIST; do
+               log_must $ZPOOL online $TESTPOOL $disk
+               check_state $TESTPOOL $disk "online"
+               if [[ $? != 0 ]]; then
+                       log_fail "Unable to online $disk"
+               fi
+
+       done
+}
+
+log_assert "Executing 'zpool online' with correct options succeeds"
+
+log_onexit cleanup
+
+if [[ -z $DISKLIST ]]; then
+       log_fail "DISKLIST is empty."
+fi
+
+typeset -i i=0
+
+for disk in $DISKLIST; do
+       i=0
+       while [[ $i -lt ${#args[*]} ]]; do
+               log_must $ZPOOL offline $TESTPOOL $disk
+               check_state $TESTPOOL $disk "offline"
+               if [[ $? != 0 ]]; then
+                       log_fail "$disk of $TESTPOOL did not match offline state"
+               fi
+
+               log_must $ZPOOL online ${args[$i]} $TESTPOOL $disk
+               check_state $TESTPOOL $disk "online"
+               if [[ $? != 0 ]]; then
+                       log_fail "$disk of $TESTPOOL did not match online state"
+               fi
+
+               (( i = i + 1 ))
+       done
+done
+
+log_note "Issuing repeated 'zpool online' commands succeeds."
+
+typeset -i iters=20
+typeset -i index=0
+
+for disk in $DISKLIST; do
+        i=0
+        while [[ $i -lt $iters ]]; do
+               index=`expr $RANDOM % ${#args[*]}`
+                log_must $ZPOOL online ${args[$index]} $TESTPOOL $disk
+                check_state $TESTPOOL $disk "online"
+                if [[ $? != 0 ]]; then
+                        log_fail "$disk of $TESTPOOL did not match online state"
+                fi
+
+                (( i = i + 1 ))
+        done
+done
+
+log_pass "'zpool online' with correct options succeeded"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/zpool_online_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_online/zpool_online_002_neg.ksh
new file mode 100755 (executable)
index 0000000..307d196
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool online' command with bad options fails.
+#
+# STRATEGY:
+# 1. Create an array of badly formed 'zpool online' options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+verify_runnable "global"
+
+DISKLIST=$(get_disklist $TESTPOOL)
+
+set -A args "" "-?" "-e fakepool" "-v fakepool" "-ev fakepool" "-ve fakepool" \
+       "-t $TESTPOOL" "-t $TESTPOOL/$TESTFS" "-t $TESTPOOL/$TESTFS $DISKLIST" \
+       "-t $TESTPOOL/$TESTCTR" "-t $TESTPOOL/$TESTCTR/$TESTFS1" \
+       "-t $TESTPOOL/$TESTCTR $DISKLIST" "-t $TESTPOOL/$TESTVOL" \
+       "-t $TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+       "-t $TESTPOOL/$TESTVOL $DISKLIST" \
+       "-t $DISKLIST" \
+       "$TESTPOOL" "$TESTPOOL/$TESTFS" "$TESTPOOL/$TESTFS $DISKLIST" \
+       "$TESTPOOL/$TESTCTR" "$TESTPOOL/$TESTCTR/$TESTFS1" \
+       "$TESTPOOL/$TESTCTR $DISKLIST" "$TESTPOOL/$TESTVOL" \
+       "$TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" "$TESTPOOL/$TESTVOL $DISKLIST" \
+       "$DISKLIST"
+
+log_assert "Executing 'zpool online' with bad options fails"
+
+if [[ -z $DISKLIST ]]; then
+        log_fail "DISKLIST is empty."
+fi
+
+typeset -i i=0
+
+while [[ $i -lt ${#args[*]} ]]; do
+
+       log_mustnot $ZPOOL online ${args[$i]}
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool online' command with bad options failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/Makefile.am
new file mode 100644 (file)
index 0000000..9890265
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_remove
+dist_pkgdata_SCRIPTS = \
+       zpool_remove.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_remove_001_neg.ksh \
+       zpool_remove_002_pos.ksh \
+       zpool_remove_003_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/cleanup.ksh
new file mode 100755 (executable)
index 0000000..307fae7
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_remove/zpool_remove.cfg
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+        delete_partitions
+fi
+
+cleanup_devices $DISKS
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/setup.ksh
new file mode 100755 (executable)
index 0000000..f3e3606
--- /dev/null
@@ -0,0 +1,43 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_remove/zpool_remove.cfg
+
+verify_runnable "global"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+partition_disk $SIZE $DISK 6
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove.cfg
new file mode 100644 (file)
index 0000000..345941b
--- /dev/null
@@ -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.
+#
+
+export DISK=${DISKS%% *}
+export SIZE="200m"
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+export DISKSARRAY=$DISKS
+
+if is_linux; then
+       set_device_dir
+       set_slice_prefix
+       export SLICE0=1
+       export SLICE1=2
+       export SLICE2=3
+       export SLICE3=4
+       export SLICE4=5
+       export SLICE5=6
+       export SLICE6=7
+       export SLICE7=8
+else
+       export SLICE_PREFIX="s"
+       export SLICE0=0
+       export SLICE1=1
+       export SLICE2=2
+       export SLICE3=3
+       export SLICE4=4
+       export SLICE5=5
+       export SLICE6=6
+       export SLICE7=7
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_001_neg.ksh
new file mode 100755 (executable)
index 0000000..495d803
--- /dev/null
@@ -0,0 +1,96 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_remove/zpool_remove.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zpool can not remove device except inactive hot spares from pool'
+#
+# STRATEGY:
+# 1. Create all kinds of pool (strip, mirror, raidz, hotspare)
+# 2. Try to remove device from the pool
+# 3. Verify that the remove failed.
+#
+
+typeset disk=${DISK}
+typeset vdev_devs="${disk}${SLICE_PREFIX}${SLICE0}"
+typeset mirror_devs="${disk}${SLICE_PREFIX}${SLICE0} ${disk}${SLICE_PREFIX}${SLICE1}"
+typeset raidz_devs=${mirror_devs}
+typeset raidz1_devs=${mirror_devs}
+typeset raidz2_devs="${mirror_devs} ${disk}${SLICE_PREFIX}${SLICE3}"
+typeset spare_devs1="${disk}${SLICE_PREFIX}${SLICE0}"
+typeset spare_devs2="${disk}${SLICE_PREFIX}${SLICE1}"
+
+function check_remove
+{
+        typeset pool=$1
+        typeset devs="$2"
+        typeset dev
+
+        for dev in $devs; do
+                log_mustnot $ZPOOL remove $dev
+        done
+
+        destroy_pool $pool
+
+}
+
+function cleanup
+{
+        if poolexists $TESTPOOL; then
+                destroy_pool $TESTPOOL
+        fi
+}
+
+set -A create_args "$vdev_devs" "mirror $mirror_devs"  \
+               "raidz $raidz_devs" "raidz $raidz1_devs" \
+               "raidz2 $raidz2_devs" \
+               "$spare_devs1 spare $spare_devs2"
+
+set -A verify_disks "$vdev_devs" "$mirror_devs" "$raidz_devs" \
+               "$raidz1_devs" "$raidz2_devs" "$spare_devs1"
+
+
+log_assert "Check zpool remove <pool> <device> can not remove " \
+       "active device from pool"
+
+log_onexit cleanup
+
+typeset -i i=0
+while [[ $i -lt ${#create_args[*]} ]]; do
+       log_must $ZPOOL create $TESTPOOL ${create_args[i]}
+       check_remove $TESTPOOL "${verify_disks[i]}"
+       (( i = i + 1))
+done
+
+log_pass "'zpool remove <pool> <device> fail as expected .'"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_002_pos.ksh
new file mode 100755 (executable)
index 0000000..c4ef652
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_remove/zpool_remove.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zpool can only remove inactive hot spare devices from pool'
+#
+# STRATEGY:
+# 1. Create a hotspare pool
+# 2. Try to remove the inactive hotspare device from the pool
+# 3. Verify that the remove succeed.
+#
+
+function cleanup
+{
+       if poolexists $TESTPOOL; then
+               destroy_pool $TESTPOOL
+       fi
+}
+
+log_onexit cleanup
+typeset disk=${DISK}
+
+typeset spare_devs1="${disk}${SLICE_PREFIX}${SLICE0}"
+typeset spare_devs2="${disk}${SLICE_PREFIX}${SLICE1}"
+
+log_assert "zpool remove can only remove inactive hotspare device from pool"
+
+log_note "check hotspare device which is created by zpool create"
+log_must $ZPOOL create $TESTPOOL $spare_devs1 spare $spare_devs2
+log_must $ZPOOL remove $TESTPOOL $spare_devs2
+
+log_note "check hotspare device which is created by zpool add"
+log_must $ZPOOL add $TESTPOOL spare $spare_devs2
+log_must $ZPOOL remove $TESTPOOL $spare_devs2
+log_must $ZPOOL destroy $TESTPOOL
+
+log_pass "zpool remove can only remove inactive hotspare device from pool"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_remove/zpool_remove_003_pos.ksh
new file mode 100755 (executable)
index 0000000..cb2d56e
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_remove/zpool_remove.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zpool can remove hotspare devices from pool when it state
+#              switch from active to inactive'
+#
+# STRATEGY:
+# 1. Create a hotspare pool
+# 2. Try to replace the inactive hotspare device to active device in the pool
+# 3. Try to detach active (spare) device to make it inactive
+# 3. Verify that the zpool remove succeed.
+#
+
+function cleanup
+{
+       if poolexists $TESTPOOL; then
+               destroy_pool $TESTPOOL
+       fi
+}
+
+log_onexit cleanup
+typeset disk=${DISK}
+
+typeset spare_devs1="${disk}${SLICE_PREFIX}${SLICE0}"
+typeset spare_devs2="${disk}${SLICE_PREFIX}${SLICE1}"
+typeset spare_devs3="${disk}${SLICE_PREFIX}${SLICE3}"
+typeset spare_devs4="${disk}${SLICE_PREFIX}${SLICE4}"
+
+log_assert "zpool remove can remove hotspare device which state go though" \
+       " active to inactive in pool"
+
+log_note "Check spare device which state go through active to inactive"
+log_must $ZPOOL create $TESTPOOL $spare_devs1 $spare_devs2 spare \
+                 $spare_devs3 $spare_devs4
+log_must $ZPOOL replace $TESTPOOL $spare_devs2 $spare_devs3
+log_mustnot $ZPOOL remove $TESTPOOL $spare_devs3
+log_must $ZPOOL detach $TESTPOOL $spare_devs3
+log_must $ZPOOL remove $TESTPOOL $spare_devs3
+
+log_pass "'zpool remove device passed as expected.'"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/Makefile.am
new file mode 100644 (file)
index 0000000..ce1b630
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_replace
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_replace_001_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/cleanup.ksh
new file mode 100755 (executable)
index 0000000..89c1462
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/setup.ksh
new file mode 100755 (executable)
index 0000000..2229f87
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+DISK=${DISKS%% *}
+
+default_mirror_setup $DISKS
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/zpool_replace_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_replace/zpool_replace_001_neg.ksh
new file mode 100755 (executable)
index 0000000..8533877
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool replace' command with bad options fails.
+#
+# STRATEGY:
+# 1. Create an array of badly formed 'zpool replace' options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "global"
+
+DISKLIST=$(get_disklist $TESTPOOL)
+
+set -A args "" "-f" "-?" "-z fakepool" "-f fakepool" "-ev fakepool" "fakepool" \
+        "$TESTPOOL" "-t $TESTPOOL/$TESTFS" "-t $TESTPOOL/$TESTFS $DISKLIST" \
+        "$TESTPOOL/$TESTCTR" "-t $TESTPOOL/$TESTCTR/$TESTFS1" \
+        "$TESTPOOL/$TESTCTR $DISKLIST" "-t $TESTPOOL/$TESTVOL" \
+        "$TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+        "$TESTPOOL/$TESTVOL $DISKLIST" \
+        "$DISKLIST" \
+        "fakepool fakedevice" "fakepool fakedevice fakenewdevice" \
+        "$TESTPOOL fakedevice" "$TESTPOOL $DISKLIST" \
+       "$TESTPOOL fakedevice fakenewdevice fakenewdevice" \
+        "-f $TESTPOOL" "-f $TESTPOOL/$TESTFS" "-f $TESTPOOL/$TESTFS $DISKLIST" \
+        "-f $TESTPOOL/$TESTCTR" "-f $TESTPOOL/$TESTCTR/$TESTFS1" \
+        "-f $TESTPOOL/$TESTCTR $DISKLIST" "-f $TESTPOOL/$TESTVOL" \
+        "-f $TESTPOOL/$TESTCTR/$TESTFS1 $DISKLIST" \
+        "-f $TESTPOOL/$TESTVOL $DISKLIST" \
+        "-f $DISKLIST" \
+        "-f fakepool fakedevice" "-f fakepool fakedevice fakenewdevice" \
+       "-f $TESTPOOL fakedevice fakenewdevice fakenewdevice" \
+        "-f $TESTPOOL fakedevice" "-f $TESTPOOL $DISKLIST"
+
+log_assert "Executing 'zpool replace' with bad options fails"
+
+if [[ -z $DISKLIST ]]; then
+       log_fail "DISKLIST is empty."
+fi
+
+typeset -i i=0
+
+while [[ $i -lt ${#args[*]} ]]; do
+
+       log_mustnot $ZPOOL replace ${args[$i]}
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool replace' command with bad options failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/Makefile.am
new file mode 100644 (file)
index 0000000..ee6a839
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_scrub
+dist_pkgdata_SCRIPTS = \
+       zpool_scrub.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_scrub_001_neg.ksh \
+       zpool_scrub_002_pos.ksh \
+       zpool_scrub_003_pos.ksh \
+       zpool_scrub_004_pos.ksh \
+       zpool_scrub_005_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/cleanup.ksh
new file mode 100755 (executable)
index 0000000..74396de
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+destroy_mirrors
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/setup.ksh
new file mode 100755 (executable)
index 0000000..ae6a8e1
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+default_mirror_setup_noexit $DISK1 $DISK2
+
+mntpnt=$(get_prop mountpoint $TESTPOOL)
+
+# Create 100MB of data
+log_must $FILE_WRITE -b 1048576 -c 100 -o create -d 0 -f $mntpnt/bigfile
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg
new file mode 100644 (file)
index 0000000..d032563
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+export DISK1=${DISKS%% *}
+export DISK2=$($ECHO $DISKS | $AWK '{print $2}')
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_001_neg.ksh
new file mode 100755 (executable)
index 0000000..c3214c1
--- /dev/null
@@ -0,0 +1,58 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# A badly formed parameter passed to 'zpool scrub' should
+# return an error.
+#
+# STRATEGY:
+# 1. Create an array containing bad 'zpool scrub' parameters.
+# 2. For each element, execute the sub-command.
+# 3. Verify it returns an error.
+#
+
+verify_runnable "global"
+
+set -A args "" "-?" "blah blah" "-%" "--?" "-*" "-=" \
+    "-a" "-b" "-c" "-d" "-e" "-f" "-g" "-h" "-i" "-j" "-k" "-l" \
+    "-m" "-n" "-o" "-p" "-q" "-r" "-s" "-t" "-u" "-v" "-w" "-x" "-y" "-z" \
+    "-A" "-B" "-C" "-D" "-E" "-F" "-G" "-H" "-I" "-J" "-K" "-L" \
+    "-M" "-N" "-O" "-P" "-Q" "-R" "-S" "-T" "-U" "-V" "-W" "-X" "-W" "-Z"
+
+
+log_assert "Execute 'zpool scrub' using invalid parameters."
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL scrub ${args[i]}
+
+       ((i = i + 1))
+done
+
+log_pass "Badly formed 'zpool scrub' parameters fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_002_pos.ksh
new file mode 100755 (executable)
index 0000000..ce07fd5
--- /dev/null
@@ -0,0 +1,55 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg
+
+#
+# DESCRIPTION:
+#      Verify scrub -s works correctly.
+#
+# STRATEGY:
+#      1. Create pool and fill with hundreds data.
+#      2. zpool scrub the pool
+#      3. Verify zpool scrub -s succeed when the system is scrubbing.
+#
+# NOTES:
+#      A 10ms delay is added to the ZIOs in order to ensure that the
+#      scrub does not complete before it has a chance to be cancelled.
+#      This can occur when testing with small pools or very fast hardware.
+#
+
+verify_runnable "global"
+
+log_assert "Verify scrub -s works correctly."
+log_must $ZINJECT -d $DISK1 -D10:1 $TESTPOOL
+log_must $ZPOOL scrub $TESTPOOL
+log_must $ZPOOL scrub -s $TESTPOOL
+log_must is_pool_scrub_stopped $TESTPOOL
+
+log_must $ZINJECT -c all
+log_pass "Verify scrub -s works correctly."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_003_pos.ksh
new file mode 100755 (executable)
index 0000000..b1b6df1
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg
+
+#
+# DESCRIPTION:
+#      scrub command terminates the existing scrub process and starts
+#      a new scrub.
+#
+# STRATEGY:
+#      1. Setup a pool and fill with data
+#      2. Kick off a scrub
+#      3. Check the completed percent and invoke another scrub
+#      4. Check the percent again, verify a new scrub started.
+#
+# NOTES:
+#      A 10ms delay is added to the ZIOs in order to ensure that the
+#      scrub does not complete before it has a chance to be restarted.
+#      This can occur when testing with small pools or very fast hardware.
+#
+
+verify_runnable "global"
+
+function get_scrub_percent
+{
+       typeset -i percent
+       percent=$($ZPOOL status $TESTPOOL | $GREP "^ scrub" | \
+           $AWK '{print $7}' | $AWK -F. '{print $1}')
+       if is_pool_scrubbed $TESTPOOL ; then
+               percent=100
+       fi
+       $ECHO $percent
+}
+
+log_assert "scrub command terminates the existing scrub process and starts" \
+       "a new scrub."
+
+log_must $ZINJECT -d $DISK1 -D10:1 $TESTPOOL
+log_must $ZPOOL scrub $TESTPOOL
+typeset -i PERCENT=30 percent=0
+while ((percent < PERCENT)) ; do
+       percent=$(get_scrub_percent)
+done
+
+log_must $ZPOOL scrub $TESTPOOL
+percent=$(get_scrub_percent)
+if ((percent > PERCENT)); then
+       log_fail "zpool scrub don't stop existing scrubbing process."
+fi
+
+log_must $ZINJECT -c all
+log_pass "scrub command terminates the existing scrub process and starts" \
+       "a new scrub."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_004_pos.ksh
new file mode 100755 (executable)
index 0000000..ca07769
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg
+
+#
+# DESCRIPTION:
+#      Resilver prevent scrub from starting until the resilver completes
+#
+# STRATEGY:
+#      1. Setup a mirror pool and filled with data.
+#      2. Detach one of devices
+#      3. Verify scrub failed until the resilver completed
+#
+# NOTES:
+#      A 10ms delay is added to 10% of zio's in order to ensure that the
+#      resilver does not complete before the scrub can be issued.  This
+#      can occur when testing with small pools or very fast hardware.
+
+verify_runnable "global"
+
+log_assert "Resilver prevent scrub from starting until the resilver completes"
+
+log_must $ZPOOL detach $TESTPOOL $DISK2
+log_must $ZINJECT -d $DISK1 -D10:1 $TESTPOOL
+log_must $ZPOOL attach $TESTPOOL $DISK1 $DISK2
+log_must is_pool_resilvering $TESTPOOL
+log_mustnot $ZPOOL scrub $TESTPOOL
+
+# Allow the resilver to finish, or it will interfere with the next test.
+while ! is_pool_resilvered $TESTPOOL; do
+       $SLEEP 1
+done
+
+log_must $ZINJECT -c all
+log_pass "Resilver prevent scrub from starting until the resilver completes"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_scrub/zpool_scrub_005_pos.ksh
new file mode 100755 (executable)
index 0000000..39e43fd
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_scrub/zpool_scrub.cfg
+
+#
+# DESCRIPTION:
+#      When scrubbing, detach device should not break system.
+#
+# STRATEGY:
+#      1. Setup filesys with data.
+#      2. Detaching and attaching the device when scrubbing.
+#      3. Try it twice, verify both of them work fine.
+#
+
+verify_runnable "global"
+
+log_assert "When scrubbing, detach device should not break system."
+
+log_must $ZPOOL scrub $TESTPOOL
+log_must $ZPOOL detach $TESTPOOL $DISK2
+log_must $ZPOOL attach $TESTPOOL $DISK1 $DISK2
+
+while ! is_pool_resilvered $TESTPOOL; do
+       $SLEEP 1
+done
+
+log_must $ZPOOL scrub $TESTPOOL
+log_must $ZPOOL detach $TESTPOOL $DISK1
+log_must $ZPOOL attach $TESTPOOL $DISK2 $DISK1
+
+log_pass "When scrubbing, detach device should not break system."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/Makefile.am
new file mode 100644 (file)
index 0000000..185d4b1
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_set
+dist_pkgdata_SCRIPTS = \
+       zpool_set_001_pos.ksh \
+       zpool_set_002_neg.ksh \
+       zpool_set_003_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_001_pos.ksh
new file mode 100755 (executable)
index 0000000..570e1ba
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+#
+# DESCRIPTION:
+#
+# Zpool set usage message is displayed when called with no arguments
+#
+# STRATEGY:
+#      1. Run zpool set
+#      2. Check that exit status is set to 2
+#      3. Check usage message contains text "usage"
+#
+#
+
+log_assert "zpool set usage message is displayed when called with no arguments"
+
+$ZPOOL set > /dev/null 2>&1
+RET=$?
+if [ $RET != 2 ]
+then
+       log_fail "\"zpool set\" exit status $RET should be equal to 2."
+fi
+
+OUTPUT=$($ZPOOL set 2>&1 | $GREP -i usage)
+if [ $? != 0 ]
+then
+       log_fail "Usage message for zpool set did not contain the word 'usage'."
+fi
+
+log_pass "zpool set usage message is displayed when called with no arguments"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_002_neg.ksh
new file mode 100755 (executable)
index 0000000..4f8e548
--- /dev/null
@@ -0,0 +1,119 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Malformed zpool set commands are rejected
+#
+# STRATEGY:
+#      1. Create an array of many different malformed zfs set arguments
+#      2. Run zpool set for each arg checking each will exit with status code 1
+#
+#
+
+verify_runnable "global"
+
+# note to self - need to make sure there isn't a pool called bootfs
+# before running this test...
+function cleanup {
+
+       $ZPOOL destroy bootfs
+       $RM /tmp/zpool_set_002.$$.dat
+}
+
+log_assert "Malformed zpool set commands are rejected"
+
+if poolexists bootfs
+then
+       log_unsupported "Unable to run test on a machine with a pool called \
+ bootfs"
+fi
+
+log_onexit cleanup
+
+# build up an array of bad arguments.
+set -A arguments "rubbish " \
+               "foo@bar= " \
+               "@@@= +pool " \
+               "zpool bootfs " \
+               "bootfs " \
+               "bootfs +" \
+               "bootfs=bootfs/123 " \
+               "bootfs=bootfs@val " \
+               "Bootfs=bootfs " \
+               "- " \
+               "== " \
+               "set " \
+               "@@ " \
+               "12345 " \
+               "€にほんご " \
+               "/ " \
+               "bootfs=bootfs /" \
+               "bootfs=a%d%s "
+
+
+# here, we build up a large string.
+# a word to the ksh-wary, ${#array[@]} gives you the
+# total number of entries in an array, so array[${#array[@]}]
+# will index the last entry+1, ksh arrays start at index 0.
+COUNT=0
+while [ $COUNT -le 1025 ]
+do
+       bigname="${bigname}o"
+       COUNT=$(( $COUNT + 1 ))
+done
+
+# add an argument of maximum length property name
+arguments[${#arguments[@]}]="$bigname=value"
+
+# add an argument of maximum length property value
+arguments[${#arguments[@]}]="bootfs=$bigname"
+
+# Create a pool called bootfs (so-called, so as to trip any clashes between
+# property name, and pool name)
+# Also create a filesystem in this pool
+log_must $MKFILE 64m /tmp/zpool_set_002.$$.dat
+log_must $ZPOOL create bootfs /tmp/zpool_set_002.$$.dat
+log_must $ZFS create bootfs/root
+
+typeset -i i=0;
+while [ $i -lt "${#arguments[@]}" ]
+do
+       log_mustnot eval "$ZPOOL set ${arguments[$i]} > /dev/null 2>&1"
+
+       # now also try with a valid pool in the argument list
+       log_mustnot eval "$ZPOOL set ${arguments[$i]}bootfs > /dev/null 2>&1"
+
+       # now also try with two valid pools in the argument list
+       log_mustnot eval "$ZPOOL set ${arguments[$i]}bootfs bootfs > /dev/null"
+       i=$(( $i + 1))
+done
+
+log_pass "Malformed zpool set commands are rejected"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_set/zpool_set_003_neg.ksh
new file mode 100755 (executable)
index 0000000..614939b
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# zpool set cannot set a readonly property
+#
+# STRATEGY:
+# 1. Create a pool
+# 2. Verify that we can't set readonly properties on that pool
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+        $ZPOOL destroy $TESTPOOL
+        $RM /tmp/zpool_set_003.$$.dat
+}
+
+set -A props "available" "capacity" "guid"  "health"  "size" "used"
+set -A vals  "100"       "10"       "12345" "HEALTHY" "10"   "10"
+
+log_onexit cleanup
+
+log_assert "zpool set cannot set a readonly property"
+
+log_must $MKFILE 64m /tmp/zpool_set_003.$$.dat
+log_must $ZPOOL create $TESTPOOL /tmp/zpool_set_003.$$.dat
+
+typeset -i i=0;
+while [ $i -lt "${#props[@]}" ]
+do
+       # try to set each property in the prop list with it's corresponding val
+        log_mustnot eval "$ZPOOL set ${props[$i]}=${vals[$i]} $TESTPOOL \
+ > /dev/null 2>&1"
+        i=$(( $i + 1))
+done
+
+log_pass "zpool set cannot set a readonly property"
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile.am
new file mode 100644 (file)
index 0000000..beb59e3
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_status
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_status_001_pos.ksh \
+       zpool_status_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79cd6e9
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/setup.ksh
new file mode 100755 (executable)
index 0000000..6a9af3b
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_001_pos.ksh
new file mode 100755 (executable)
index 0000000..d582e55
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool status' command with bad options fails.
+#
+# STRATEGY:
+# 1. Create an array of badly formed 'zpool status' options
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "both"
+
+
+set -A args "" "-?" "-x fakepool" "-v fakepool" "-xv fakepool" "-vx fakepool" \
+       "-x $TESTPOOL/$TESTFS" "-v $TESTPOOL/$TESTFS" "-xv $TESTPOOL/$TESTFS" \
+       "-vx $TESTPOOL/$TESTFS"
+
+log_assert "Executing 'zpool status' with bad options fails"
+
+typeset -i i=1
+
+while [[ $i -lt ${#args[*]} ]]; do
+
+       log_mustnot $ZPOOL status ${args[$i]}
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool status' command with bad options failed as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_002_pos.ksh
new file mode 100755 (executable)
index 0000000..5ae84a8
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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.
+#
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool status' with correct options succeeds
+#
+# STRATEGY:
+# 1. Create an array of correctly formed 'zpool status' options
+# 2. Execute each element of the array.
+# 3. Verify use of each option is successful.
+#
+
+verify_runnable "both"
+
+typeset testpool
+if is_global_zone; then
+       testpool=$TESTPOOL
+else
+       testpool=${TESTPOOL%%/*}
+fi
+
+set -A args "" "-x" "-v" "-x $testpool" "-v $testpool" "-xv $testpool" \
+       "-vx $testpool"
+
+log_assert "Executing 'zpool status' with correct options succeeds"
+
+typeset -i i=0
+
+while [[ $i -lt ${#args[*]} ]]; do
+
+       log_must $ZPOOL status ${args[$i]}
+
+       (( i = i + 1 ))
+done
+
+log_pass "'zpool status' with correct options succeeded"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/Makefile.am
new file mode 100644 (file)
index 0000000..71cdb29
--- /dev/null
@@ -0,0 +1,72 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_root/zpool_upgrade
+dist_pkgdata_SCRIPTS = \
+       zpool_upgrade.cfg \
+       zpool_upgrade.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_upgrade_001_pos.ksh \
+       zpool_upgrade_002_pos.ksh \
+       zpool_upgrade_003_pos.ksh \
+       zpool_upgrade_004_pos.ksh \
+       zpool_upgrade_005_neg.ksh \
+       zpool_upgrade_006_neg.ksh \
+       zpool_upgrade_007_pos.ksh \
+       zpool_upgrade_008_pos.ksh \
+       zpool_upgrade_009_neg.ksh
+
+BLOCKFILES = \
+       zfs-broken-mirror1.dat.bz2 \
+       zfs-broken-mirror2.dat.bz2 \
+       zfs-pool-v1.dat.bz2 \
+       zfs-pool-v10.dat.bz2 \
+       zfs-pool-v11.dat.bz2 \
+       zfs-pool-v12.dat.bz2 \
+       zfs-pool-v13.dat.bz2 \
+       zfs-pool-v14.dat.bz2 \
+       zfs-pool-v15.dat.bz2 \
+       zfs-pool-v1mirror1.dat.bz2 \
+       zfs-pool-v1mirror2.dat.bz2 \
+       zfs-pool-v1mirror3.dat.bz2 \
+       zfs-pool-v1raidz1.dat.bz2 \
+       zfs-pool-v1raidz2.dat.bz2 \
+       zfs-pool-v1raidz3.dat.bz2 \
+       zfs-pool-v1stripe1.dat.bz2 \
+       zfs-pool-v1stripe2.dat.bz2 \
+       zfs-pool-v1stripe3.dat.bz2 \
+       zfs-pool-v2.dat.bz2 \
+       zfs-pool-v2mirror1.dat.bz2 \
+       zfs-pool-v2mirror2.dat.bz2 \
+       zfs-pool-v2mirror3.dat.bz2 \
+       zfs-pool-v2raidz1.dat.bz2 \
+       zfs-pool-v2raidz2.dat.bz2 \
+       zfs-pool-v2raidz3.dat.bz2 \
+       zfs-pool-v2stripe1.dat.bz2 \
+       zfs-pool-v2stripe2.dat.bz2 \
+       zfs-pool-v2stripe3.dat.bz2 \
+       zfs-pool-v3.dat.bz2 \
+       zfs-pool-v3hotspare1.dat.bz2 \
+       zfs-pool-v3hotspare2.dat.bz2 \
+       zfs-pool-v3hotspare3.dat.bz2 \
+       zfs-pool-v3mirror1.dat.bz2 \
+       zfs-pool-v3mirror2.dat.bz2 \
+       zfs-pool-v3mirror3.dat.bz2 \
+       zfs-pool-v3raidz1.dat.bz2 \
+       zfs-pool-v3raidz2.dat.bz2 \
+       zfs-pool-v3raidz21.dat.bz2 \
+       zfs-pool-v3raidz22.dat.bz2 \
+       zfs-pool-v3raidz23.dat.bz2 \
+       zfs-pool-v3raidz3.dat.bz2 \
+       zfs-pool-v3stripe1.dat.bz2 \
+       zfs-pool-v3stripe2.dat.bz2 \
+       zfs-pool-v3stripe3.dat.bz2 \
+       zfs-pool-v4.dat.bz2 \
+       zfs-pool-v5.dat.bz2 \
+       zfs-pool-v6.dat.bz2 \
+       zfs-pool-v7.dat.bz2 \
+       zfs-pool-v8.dat.bz2 \
+       zfs-pool-v9.dat.bz2 \
+       zfs-pool-v999.dat.bz2 \
+       zfs-pool-vBROKEN.dat.bz2
+
+dist_pkgdata_DATA = $(BLOCKFILES)
+EXTRA_DIST = $(BLOCKFILES)
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/cleanup.ksh
new file mode 100755 (executable)
index 0000000..1fab530
--- /dev/null
@@ -0,0 +1,39 @@
+#!/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.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+for config in $CONFIGS; do
+       destroy_upgraded_pool $config
+done
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/setup.ksh
new file mode 100755 (executable)
index 0000000..860ba0f
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+# give us a pool to play in
+default_setup "$DISKS"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.cfg b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.cfg
new file mode 100644 (file)
index 0000000..993fafc
--- /dev/null
@@ -0,0 +1,161 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+# The following variable names describe files, stored as gzip compressed files
+# in the test directory which can be used to construct a pool of a given
+# version. The variable names are important, in that the construction
+# ZPOOL_VERSION_$var_FILES describes the files the pool is made from, and
+# ZPOOL_VERSION_$var_NAME describes the pool name.
+
+# v1 pools
+ZPOOL_VERSION_1_FILES="zfs-pool-v1.dat"
+ZPOOL_VERSION_1_NAME="v1-pool"
+# v1 stripe
+ZPOOL_VERSION_1stripe_FILES="zfs-pool-v1stripe1.dat \
+zfs-pool-v1stripe2.dat  zfs-pool-v1stripe3.dat"
+ZPOOL_VERSION_1stripe_NAME="pool-v1stripe"
+# v1 raidz
+ZPOOL_VERSION_1raidz_FILES="zfs-pool-v1raidz1.dat zfs-pool-v1raidz2.dat \
+zfs-pool-v1raidz3.dat"
+ZPOOL_VERSION_1raidz_NAME="pool-v1raidz"
+# v1 mirror
+ZPOOL_VERSION_1mirror_FILES="zfs-pool-v1mirror1.dat zfs-pool-v1mirror2.dat \
+zfs-pool-v1mirror3.dat"
+ZPOOL_VERSION_1mirror_NAME="pool-v1mirror"
+
+# v2 pools
+ZPOOL_VERSION_2_FILES="zfs-pool-v2.dat"
+ZPOOL_VERSION_2_NAME="v2-pool"
+# v2 stripe
+ZPOOL_VERSION_2stripe_FILES="zfs-pool-v2stripe1.dat zfs-pool-v2stripe2.dat \
+zfs-pool-v2stripe3.dat"
+ZPOOL_VERSION_2stripe_NAME="pool-v2stripe"
+# v2 raidz
+ZPOOL_VERSION_2raidz_FILES="zfs-pool-v2raidz1.dat zfs-pool-v2raidz2.dat \
+zfs-pool-v2raidz3.dat"
+ZPOOL_VERSION_2raidz_NAME="pool-v2raidz"
+# v2 mirror
+ZPOOL_VERSION_2mirror_FILES="zfs-pool-v2mirror1.dat zfs-pool-v2mirror2.dat \
+zfs-pool-v2mirror3.dat"
+ZPOOL_VERSION_2mirror_NAME="pool-v2mirror"
+
+# v3 pools
+ZPOOL_VERSION_3_FILES="zfs-pool-v3.dat"
+ZPOOL_VERSION_3_NAME="v3-pool"
+# v3 stripe
+ZPOOL_VERSION_3stripe_FILES="zfs-pool-v3stripe1.dat zfs-pool-v3stripe2.dat \
+zfs-pool-v3stripe3.dat"
+ZPOOL_VERSION_3stripe_NAME="pool-v3stripe"
+# v3 raidz
+ZPOOL_VERSION_3raidz_FILES="zfs-pool-v3raidz1.dat zfs-pool-v3raidz2.dat \
+zfs-pool-v3raidz3.dat"
+ZPOOL_VERSION_3raidz_NAME="pool-v3raidz"
+# v3 mirror
+ZPOOL_VERSION_3mirror_FILES="zfs-pool-v3mirror1.dat zfs-pool-v3mirror2.dat \
+zfs-pool-v3mirror3.dat"
+ZPOOL_VERSION_3mirror_NAME="pool-v3mirror"
+# v3 raidz2
+ZPOOL_VERSION_3dblraidz_FILES="zfs-pool-v3raidz21.dat zfs-pool-v3raidz22.dat \
+zfs-pool-v3raidz23.dat"
+ZPOOL_VERSION_3dblraidz_NAME="pool-v3raidz2"
+# v3 hotspares
+ZPOOL_VERSION_3hotspare_FILES="zfs-pool-v3hotspare1.dat \
+zfs-pool-v3hotspare2.dat zfs-pool-v3hotspare3.dat"
+ZPOOL_VERSION_3hotspare_NAME="pool-v3hotspare"
+
+# v4 pool
+ZPOOL_VERSION_4_FILES="zfs-pool-v4.dat"
+ZPOOL_VERSION_4_NAME="v4-pool"
+
+# v5 pool
+ZPOOL_VERSION_5_FILES="zfs-pool-v5.dat"
+ZPOOL_VERSION_5_NAME="v5-pool"
+
+# v6 pool
+ZPOOL_VERSION_6_FILES="zfs-pool-v6.dat"
+ZPOOL_VERSION_6_NAME="v6-pool"
+
+# v7 pool
+ZPOOL_VERSION_7_FILES="zfs-pool-v7.dat"
+ZPOOL_VERSION_7_NAME="v7-pool"
+
+# v8 pool
+ZPOOL_VERSION_8_FILES="zfs-pool-v8.dat"
+ZPOOL_VERSION_8_NAME="v8-pool"
+
+# v9 pool
+ZPOOL_VERSION_9_FILES="zfs-pool-v9.dat"
+ZPOOL_VERSION_9_NAME="v9-pool"
+
+# v10 pool
+ZPOOL_VERSION_10_FILES="zfs-pool-v10.dat"
+ZPOOL_VERSION_10_NAME="v10-pool"
+
+# v11 pool
+ZPOOL_VERSION_11_FILES="zfs-pool-v11.dat"
+ZPOOL_VERSION_11_NAME="v11-pool"
+
+# v12 pool
+ZPOOL_VERSION_12_FILES="zfs-pool-v12.dat"
+ZPOOL_VERSION_12_NAME="v12-pool"
+
+# v13 pool
+ZPOOL_VERSION_13_FILES="zfs-pool-v13.dat"
+ZPOOL_VERSION_13_NAME="v13-pool"
+
+# v14 pool
+ZPOOL_VERSION_14_FILES="zfs-pool-v14.dat"
+ZPOOL_VERSION_14_NAME="v14-pool"
+
+# v15 pool
+ZPOOL_VERSION_15_FILES="zfs-pool-v15.dat"
+ZPOOL_VERSION_15_NAME="v15-pool"
+
+# v2 pool, with device problems on one side of the mirror
+# so that the pool appears as DEGRADED
+ZPOOL_VERSION_2brokenmirror_FILES="zfs-broken-mirror1.dat \
+zfs-broken-mirror2.dat"
+ZPOOL_VERSION_2brokenmirror_NAME="zfs-broken-mirror"
+
+# v999 pool (an unknown version) which can be used to check whether upgrade,
+# import or other tests that should fail against unknown pool version.
+# It should not be listed in the CONFIGS variable below, as these are pool
+# versions that can be imported and upgraded.
+ZPOOL_VERSION_9999_FILES="zfs-pool-v999.dat"
+ZPOOL_VERSION_9999_NAME="v999-pool"
+
+# This is a list of pool configurations we should be able to upgrade from,
+# each entry should have corresponding ZPOOL_VERSION_*_FILES and
+# ZPOOL_VERSION_*_NAME variables defined above.
+CONFIGS="1 1stripe 1raidz 1mirror \
+2 2stripe 2raidz 2mirror 2brokenmirror \
+3 3stripe 3raidz 3mirror 3dblraidz 3hotspare \
+4 5 6 7 8 9 10 11 12 13 14 15"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
new file mode 100644 (file)
index 0000000..d2d0eaf
--- /dev/null
@@ -0,0 +1,160 @@
+#
+# 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) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.cfg
+
+# This part of the test suite relies on variables being setup in the
+# zpool_upgrade.cfg script. Those variables give us details about which
+# files make up the pool, and what the pool name is.
+
+
+# A function to import a pool from files we have stored in the test suite
+# We import the pool, and create some random data in the pool.
+# $1 a version number we can use to get information about the pool
+function create_old_pool
+{
+       typeset vers=$1
+       typeset -n pool_files=ZPOOL_VERSION_${vers}_FILES
+       typeset -n pool_name=ZPOOL_VERSION_${vers}_NAME
+
+       log_note "Creating $pool_name from $pool_files"
+       for pool_file in $pool_files; do
+               log_must $BZCAT \
+                   $STF_SUITE/tests/functional/cli_root/zpool_upgrade/$pool_file.bz2 \
+                   >/$TESTPOOL/$pool_file
+       done
+       log_must $ZPOOL import -d /$TESTPOOL $pool_name
+
+       # Put some random contents into the pool
+       for i in {1..1024} ; do
+               $DD if=/dev/urandom of=/$pool_name/random.$i \
+                   count=1 bs=1024 > /dev/null 2>&1
+       done
+}
+
+
+# A function to check the contents of a pool, upgrade it to the current version
+# and then verify that the data is consistent after upgrading. Note that we're
+# not using "zpool status -x" to see if the pool is healthy, as it's possible
+# to also upgrade faulted, or degraded pools.
+# $1 a version number we can use to get information about the pool
+function check_upgrade
+{
+       typeset vers=$1
+       typeset -n pool_files=ZPOOL_VERSION_${vers}_FILES
+       typeset -n pool_name=ZPOOL_VERSION_${vers}_NAME
+       typeset pre_upgrade_checksum
+       typeset post_upgrade_checksum
+
+       log_note "Checking if we can upgrade from ZFS version $vers"
+       pre_upgrade_checksum=$(check_pool $pool_name pre)
+       log_must $ZPOOL upgrade $pool_name
+       post_upgrade_checksum=$(check_pool $pool_name post)
+
+       log_note "Checking that there are no differences between checksum output"
+       log_must $DIFF $pre_upgrade_checksum $post_upgrade_checksum
+       $RM $pre_upgrade_checksum $post_upgrade_checksum
+}
+
+# A function to destroy an upgraded pool, plus the files it was based on.
+# $1 a version number we can use to get information about the pool
+function destroy_upgraded_pool
+{
+       typeset vers=$1
+       typeset -n pool_files=ZPOOL_VERSION_${vers}_FILES
+       typeset -n pool_name=ZPOOL_VERSION_${vers}_NAME
+
+       if poolexists $pool_name; then
+               log_must $ZPOOL destroy $pool_name
+       fi
+       for file in $pool_files; do
+               $RM -f /$TESTPOOL/$file
+       done
+}
+
+# This function does a basic sanity check on the pool by computing the
+# checksums of all files in the pool, echoing the name of the file containing
+# the checksum results.
+# $1 the name of the pool
+# $2 a flag we can use to determine when this check is being performed
+#    (ie. pre or post pool-upgrade)
+function check_pool
+{
+       typeset pool=$1
+       typeset flag=$2
+       $FIND /$pool -type f -exec $CKSUM {} + > \
+               /$TESTPOOL/pool-checksums.$pool.$flag
+       echo /$TESTPOOL/pool-checksums.$pool.$flag
+}
+
+# This function simply checks that a pool has a particular version number
+# as reported by zdb and zpool upgrade -v
+# $1 the name of the pool
+# $2 the version of the pool we expect to see
+function check_poolversion
+{
+       typeset pool=$1
+       typeset vers=$2
+       typeset actual
+
+       # check version using zdb
+       actual=$($ZDB -C $pool | $SED -n 's/^.*version: \(.*\)$/\1/p')
+       if [[ $actual != $vers ]] ; then
+               log_fail "$pool: zdb reported version $actual, expected $vers"
+       fi
+
+       # check version using zpool upgrade
+       actual=$($ZPOOL upgrade | $GREP $pool$ | \
+           $AWK '{print $1}' | $SED -e 's/ //g')
+       if [[ $actual != $vers ]] ; then
+               log_fail "$pool: zpool reported version $actual, expected $vers"
+       fi
+}
+
+# A simple function to get a random number between two bounds
+# probably not the most efficient for large ranges, but it's okay.
+# Note since we're using $RANDOM, 32767 is the largest number we
+# can accept as the upper bound.
+# $1 lower bound
+# $2 upper bound
+function random
+{
+       typeset min=$1
+       typeset max=$2
+       typeset rand=0
+
+       while [[ $rand -lt $min ]] ; do
+               rand=$(( $RANDOM % $max + 1))
+       done
+
+       echo $rand
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_001_pos.ksh
new file mode 100755 (executable)
index 0000000..f32d1ca
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool upgrade -v' command succeeds, prints a description of legacy
+# versions, and mentions feature flags.
+#
+# STRATEGY:
+# 1. Execute the command
+# 2. Verify a 0 exit status
+# 3. Grep for version descriptions and 'feature flags'
+#
+
+verify_runnable "global"
+
+log_assert "Executing 'zpool upgrade -v' command succeeds"
+
+log_must $ZPOOL upgrade -v
+
+# We also check that the usage message contains a description of legacy
+# versions and a note about feature flags.
+
+log_must eval "$ZPOOL upgrade -v | $HEAD -1 | $GREP 'feature flags'"
+
+$ZPOOL upgrade -v > /tmp/zpool-versions.$$
+
+#
+# Current output for 'zpool upgrade -v' has different indent space
+# for single and double digit version number. For example,
+#  9   refquota and refreservation properties
+#  10  Cache devices
+#
+for version in {1..28}; do
+       log_note "Checking for a description of pool version $version"
+       log_must eval "$AWK '/^ $version / { print $1 }' /tmp/zpool-versions.$$ | $GREP $version"
+done
+$RM /tmp/zpool-versions.$$
+
+log_pass "Executing 'zpool upgrade -v' command succeeds"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_002_pos.ksh
new file mode 100755 (executable)
index 0000000..16ab149
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# import pools of all versions - zpool upgrade on each pools works
+#
+# STRATEGY:
+# 1. Execute the command with several invalid options
+# 2. Verify a 0 exit status for each
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_upgraded_pool $config
+}
+
+log_assert "Import pools of all versions - zpool upgrade on each pool works"
+log_onexit cleanup
+
+for config in $CONFIGS; do
+    create_old_pool $config
+    check_upgrade $config
+    destroy_upgraded_pool $config
+done
+
+log_pass "Import pools of all versions - zpool upgrade on each pool works"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_003_pos.ksh
new file mode 100755 (executable)
index 0000000..0ac3470
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# Upgrading a pool that has already been upgraded succeeds.
+#
+# STRATEGY:
+# 1. Upgrade a pool, then try to upgrade it again
+# 2. Verify a 0 exit status
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_upgraded_pool 1
+}
+
+log_assert "Upgrading a pool that has already been upgraded succeeds"
+log_onexit cleanup
+
+# Create a version 1 pool
+create_old_pool 1
+check_upgrade 1
+check_upgrade 1
+destroy_upgraded_pool 1
+
+log_pass "Upgrading a pool that has already been upgraded succeeds"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_004_pos.ksh
new file mode 100755 (executable)
index 0000000..ba3cdd0
--- /dev/null
@@ -0,0 +1,83 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# zpool upgrade -a works
+#
+# STRATEGY:
+# 1. Create all upgradable pools for this system, then upgrade -a
+# 2. Verify a 0 exit status
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       for config in $CONFIGS; do
+               destroy_upgraded_pool $config
+       done
+}
+
+log_assert "zpool upgrade -a works"
+log_onexit cleanup
+
+TEST_POOLS=
+# Now build all of our pools
+for config in $CONFIGS; do
+       typeset -n pool_name=ZPOOL_VERSION_${config}_NAME
+
+       TEST_POOLS="$TEST_POOLS $pool_name"
+       create_old_pool $config
+       check_pool $pool_name pre > /dev/null
+done
+
+# upgrade them all at once
+export __ZFS_POOL_RESTRICT="$TEST_POOLS"
+log_must $ZPOOL upgrade -a
+unset __ZFS_POOL_RESTRICT
+
+# verify their contents then destroy them
+for config in $CONFIGS ; do
+       typeset -n pool_name=ZPOOL_VERSION_${config}_NAME
+
+       check_pool $pool_name post > /dev/null
+       log_must $DIFF /$TESTPOOL/pool-checksums.$pool_name.pre \
+           /$TESTPOOL/pool-checksums.$pool_name.post
+       $RM /$TESTPOOL/pool-checksums.$pool_name.pre \
+           /$TESTPOOL/pool-checksums.$pool_name.post
+       destroy_upgraded_pool $config
+done
+
+log_pass "zpool upgrade -a works"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_005_neg.ksh
new file mode 100755 (executable)
index 0000000..d32ae3e
--- /dev/null
@@ -0,0 +1,54 @@
+#!/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.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# Variations of upgrade -v print usage message, return with non-zero status
+#
+# STRATEGY:
+# 1. Execute the command with several invalid options
+# 2. Verify a 0 exit status for each
+#
+
+verify_runnable "global"
+
+log_assert "Variations of upgrade -v print usage message," \
+    "return with non-zero status"
+
+for arg in "/tmp" "-?" "-va" "-v fakepool" "-a fakepool" ; do
+        log_mustnot $ZPOOL upgrade $arg
+done
+
+log_pass "Variations of upgrade -v print usage message," \
+    "return with non-zero status"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_006_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_006_neg.ksh
new file mode 100755 (executable)
index 0000000..a66ac6c
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# Attempting to upgrade a non-existent pool will return an error
+#
+# STRATEGY:
+# 1. Compose non-existent pool name, try to upgrade it
+# 2. Verify non-zero exit status
+#
+
+log_assert "Attempting to upgrade a non-existent pool will return an error"
+
+NO_POOL=notapool
+
+while true ; do
+       if poolexists $NO_POOL ; then
+               NO_POOL="${NO_POOL}x"
+       else
+               log_mustnot $ZPOOL upgrade $NO_POOL
+               break
+       fi
+done
+
+log_pass "Attempting to upgrade a non-existent pool will return an error"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_007_pos.ksh
new file mode 100755 (executable)
index 0000000..346d3da
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+. $STF_SUITE/tests/functional/cli_root/zfs_upgrade/zfs_upgrade.kshlib
+
+#
+# DESCRIPTION:
+# import pools of all versions - verify the following operation not break.
+#      * zfs create -o version=<vers> <filesystem>
+#      * zfs upgrade [-V vers] <filesystem>
+#      * zfs set version=<vers> <filesystem>
+#
+# STRATEGY:
+# 1. Import pools of all versions
+# 2. Setup a test enviorment over the old pools.
+# 3. Verify the commands related to 'zfs upgrade' succeed as expected.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_upgraded_pool $config
+}
+
+log_assert "Import pools of all versions - 'zfs upgrade' on each pool works"
+log_onexit cleanup
+
+# $CONFIGS gets set in the .cfg script
+for config in $CONFIGS; do
+       typeset -n pool_name=ZPOOL_VERSION_${config}_NAME
+
+       create_old_pool $config
+       default_check_zfs_upgrade $pool_name
+       destroy_upgraded_pool $config
+done
+
+log_pass "Import pools of all versions - 'zfs upgrade' on each pool works"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_008_pos.ksh
new file mode 100755 (executable)
index 0000000..0809f95
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+#
+# zpool upgrade should be able to upgrade pools to a given version using -V
+#
+# STRATEGY:
+# 1. For all versions pools that can be upgraded on a given OS version
+#    (latest pool version - 1)
+# 2. Pick a version that's a random number, greater than the version
+#    we're running.
+# 3. Attempt to upgrade that pool to the given version
+# 4. Check the pool was upgraded correctly.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_upgraded_pool $ver_old
+}
+
+log_assert "zpool upgrade should be able to upgrade pools to a given version" \
+    "using -V"
+
+log_onexit cleanup
+
+# We're just using the single disk version of the pool, which should be
+# enough to determine if upgrade works correctly. Also set a MAX_VER
+# variable, which specifies the highest version that we should expect
+# a zpool upgrade operation to succeed from.
+VERSIONS="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
+MAX_VER=15
+
+for ver_old in $VERSIONS; do
+       typeset -n pool_name=ZPOOL_VERSION_${ver_old}_NAME
+       typeset ver_new=$(random $ver_old $MAX_VER)
+
+       create_old_pool $ver_old
+       log_must $ZPOOL upgrade -V $ver_new $pool_name > /dev/null
+       check_poolversion $pool_name $ver_new
+       destroy_upgraded_pool $ver_old
+done
+
+log_pass "zpool upgrade should be able to upgrade pools to a given version" \
+    "using -V"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/zpool_upgrade_009_neg.ksh
new file mode 100755 (executable)
index 0000000..dce9268
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zpool_upgrade.kshlib
+
+#
+# DESCRIPTION:
+#
+# zpool upgrade -V shouldn't be able to upgrade a pool to an unknown version
+#
+# STRATEGY:
+# 1. Take an existing pool
+# 2. Attempt to upgrade it to an unknown version
+# 3. Verify that the upgrade failed, and the pool version was still the original
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_upgraded_pool $config
+}
+
+log_assert "zpool upgrade -V shouldn't be able to upgrade a pool to" \
+    "unknown version"
+
+typeset -i config=2
+typeset -n pool_name=ZPOOL_VERSION_${config}_NAME
+
+create_old_pool $config
+log_mustnot $ZPOOL upgrade -V 999 $pool_name
+log_mustnot $ZPOOL upgrade -V 999
+check_poolversion $pool_name $config
+destroy_upgraded_pool $config
+
+log_pass "zpool upgrade -V shouldn't be able to upgrade a pool to" \
+    "unknown version"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_user/Makefile.am
new file mode 100644 (file)
index 0000000..f1ff32e
--- /dev/null
@@ -0,0 +1,5 @@
+SUBDIRS = \
+       misc \
+       zfs_list \
+       zpool_iostat \
+       zpool_list
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/Makefile.am
new file mode 100644 (file)
index 0000000..cf7502c
--- /dev/null
@@ -0,0 +1,49 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_user/misc
+dist_pkgdata_SCRIPTS = \
+       misc.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       zdb_001_neg.ksh \
+       zfs_001_neg.ksh \
+       zfs_allow_001_neg.ksh \
+       zfs_clone_001_neg.ksh \
+       zfs_create_001_neg.ksh \
+       zfs_destroy_001_neg.ksh \
+       zfs_get_001_neg.ksh \
+       zfs_inherit_001_neg.ksh \
+       zfs_mount_001_neg.ksh \
+       zfs_promote_001_neg.ksh \
+       zfs_receive_001_neg.ksh \
+       zfs_rename_001_neg.ksh \
+       zfs_rollback_001_neg.ksh \
+       zfs_send_001_neg.ksh \
+       zfs_set_001_neg.ksh \
+       zfs_share_001_neg.ksh \
+       zfs_snapshot_001_neg.ksh \
+       zfs_unallow_001_neg.ksh \
+       zfs_unmount_001_neg.ksh \
+       zfs_unshare_001_neg.ksh \
+       zfs_upgrade_001_neg.ksh \
+       zpool_001_neg.ksh \
+       zpool_add_001_neg.ksh \
+       zpool_attach_001_neg.ksh \
+       zpool_clear_001_neg.ksh \
+       zpool_create_001_neg.ksh \
+       zpool_destroy_001_neg.ksh \
+       zpool_detach_001_neg.ksh \
+       zpool_export_001_neg.ksh \
+       zpool_get_001_neg.ksh \
+       zpool_history_001_neg.ksh \
+       zpool_import_001_neg.ksh \
+       zpool_import_002_neg.ksh \
+       zpool_offline_001_neg.ksh \
+       zpool_online_001_neg.ksh \
+       zpool_remove_001_neg.ksh \
+       zpool_replace_001_neg.ksh \
+       zpool_scrub_001_neg.ksh \
+       zpool_set_001_neg.ksh \
+       zpool_status_001_neg.ksh \
+       zpool_upgrade_001_neg.ksh \
+       arcstat_001_pos.ksh \
+       arc_summary_001_pos.ksh \
+       dbufstat_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/arc_summary_001_pos.ksh
new file mode 100755 (executable)
index 0000000..e65fbe6
--- /dev/null
@@ -0,0 +1,40 @@
+#! /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 (c) 2015 by Lawrence Livermore National Security, LLC.
+# All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+set -A args  "" "-a" "-d" "-p 1"
+
+log_assert "arc_summary.py generates output and doesn't return an error code"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+        log_must eval "$ARC_SUMMARY ${args[i]} > /dev/null"
+        ((i = i + 1))
+done
+
+log_pass "arc_summary.py generates output and doesn't return an error code"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/arcstat_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/arcstat_001_pos.ksh
new file mode 100755 (executable)
index 0000000..edf80b1
--- /dev/null
@@ -0,0 +1,41 @@
+#! /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 (c) 2015 by Lawrence Livermore National Security, LLC.
+# All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+set -A args  "" "-s \",\"" "-x" "-v" \
+    "-f time,hit%,dh%,ph%,mh%"
+
+log_assert "arcstat.py generates output and doesn't return an error code"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+        log_must eval "$ARCSTAT ${args[i]} > /dev/null"
+        ((i = i + 1))
+done
+log_pass "arcstat.py generates output and doesn't return an error code"
+
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/cleanup.ksh
new file mode 100755 (executable)
index 0000000..4bb4991
--- /dev/null
@@ -0,0 +1,50 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+if poolexists $TESTPOOL.virt
+then
+       log_must $ZPOOL destroy $TESTPOOL.virt
+fi
+
+if poolexists v1-pool
+then
+       log_must $ZPOOL destroy v1-pool
+fi
+
+if [[ -f /tmp/zfstest_datastream.dat ]]
+then
+       log_must $RM -f /tmp/zfstest_datastream.dat
+fi
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/dbufstat_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/dbufstat_001_pos.ksh
new file mode 100755 (executable)
index 0000000..229ba72
--- /dev/null
@@ -0,0 +1,40 @@
+#! /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 (c) 2015 by Lawrence Livermore National Security, LLC.
+# All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+set -A args  "" "-b" "-d" "-r" "-v" "-s \",\"" "-x"
+
+log_assert "dbufstat.py generates output and doesn't return an error code"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+        log_must eval "$DBUFSTAT ${args[i]} > /dev/null"
+        ((i = i + 1))
+done
+
+log_pass "dbufstat.py generates output and doesn't return an error code"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/misc.cfg b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/misc.cfg
new file mode 100644 (file)
index 0000000..8054f0e
--- /dev/null
@@ -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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+if is_linux; then
+       # these are the set of setable ZFS properties
+       PROP_NAMES="\
+               aclinherit      acltype         atime            \
+               checksum        compression                     devices \
+               exec            mountpoint      quota           readonly \
+               recordsize      reservation     setuid           \
+               snapdir"
+
+       # these are a set of values we apply, for use when testing the
+       # zfs get/set subcommands - ordered as per the list above so we
+       # can iterate over both sets in an array
+       PROP_VALS="\
+               secure          posixacl        on               \
+               fletcher2       on                              on \
+               on              legacy          none            on \
+               128k            none            on               \
+               visible"
+
+       # these are an alternate set of property values
+       PROP_ALTVALS="\
+               noallow         noacl           off              \
+               fletcher4       lzjb                            off \
+               off             /tmp/zfstest    100m            off \
+               512             10m             off              \
+               hidden"
+else
+       # these are the set of setable ZFS properties
+       PROP_NAMES="\
+               aclinherit      aclmode         atime            \
+               checksum        compression                     devices \
+               exec            mountpoint      quota           readonly \
+               recordsize      reservation     setuid          sharenfs \
+               snapdir"
+
+       # these are a set of values we apply, for use when testing the
+       # zfs get/set subcommands - ordered as per the list above so we
+       # can iterate over both sets in an array
+       PROP_VALS="\
+               secure          discard         on               \
+               fletcher2       on                              on \
+               on              legacy          none            on \
+               128k            none            on              on \
+               visible"
+
+       # these are an alternate set of property values
+       PROP_ALTVALS="\
+               noallow         noacl           off              \
+               fletcher4       lzjb                            off \
+               off             /tmp/zfstest    100m            off \
+               512             10m             off             off \
+               hidden"
+fi
+
+# additional properties to worry about: canmount copies xattr zoned version
+
+POOL_PROPS="\
+       failmode        autoreplace"
+
+POOL_VALS="\
+       continue        on"
+
+POOL_ALTVALS="\
+       panic           off"
+
+export TESTSNAP=testsnap-misc
+export TESTCLCT=testclct-misc
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/setup.ksh
new file mode 100755 (executable)
index 0000000..ac5b934
--- /dev/null
@@ -0,0 +1,161 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+# This setup script is moderately complex, as it creates scenarios for all
+# of the tests included in this directory. Usually we'd want each test case
+# to setup/teardown it's own configuration, but this would be time consuming
+# given the nature of these tests. However, as a side-effect, one test
+# leaving the system in an unknown state could impact other test cases.
+
+
+DISK=${DISKS%% *}
+VOLSIZE=150m
+TESTVOL=testvol
+
+# Create a default setup that includes a volume
+default_setup_noexit "$DISK" "" "volume"
+
+#
+# The rest of this setup script creates a ZFS filesystem configuration
+# that is used to test the rest of the zfs subcommands in this directory.
+#
+
+# create a snapshot and a clone to test clone promote
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snap
+log_must $ZFS clone $TESTPOOL/$TESTFS@snap $TESTPOOL/$TESTFS/clone
+# create a file in the filesystem that isn't in the above snapshot
+$TOUCH /$TESTDIR/file.txt
+
+
+# create a non-default property and a child we can use to test inherit
+log_must $ZFS create $TESTPOOL/$TESTFS/$TESTFS2
+log_must $ZFS set snapdir=hidden $TESTPOOL/$TESTFS
+
+
+# create an unmounted filesystem to test unmount
+log_must $ZFS create $TESTPOOL/$TESTFS/$TESTFS2.unmounted
+log_must $ZFS unmount $TESTPOOL/$TESTFS/$TESTFS2.unmounted
+
+
+# send our snapshot to a known file in /tmp
+$ZFS send $TESTPOOL/$TESTFS@snap > /tmp/zfstest_datastream.dat
+if [ ! -s /tmp/zfstest_datastream.dat ]
+then
+       log_fail "ZFS send datafile was not created!"
+fi
+log_must $CHMOD 644 /tmp/zfstest_datastream.dat
+
+
+# create a filesystem that has particular properties to test set/get
+log_must $ZFS create -o version=1 $TESTPOOL/$TESTFS/prop
+set -A props $PROP_NAMES
+set -A prop_vals $PROP_VALS
+typeset -i i=0
+
+while [[ $i -lt ${#props[*]} ]]
+do
+       prop_name=${props[$i]}
+       prop_val=${prop_vals[$i]}
+       log_must $ZFS set $prop_name=$prop_val $TESTPOOL/$TESTFS/prop
+       i=$(( $i + 1 ))
+done
+
+# create a filesystem we don't mind renaming
+log_must $ZFS create $TESTPOOL/$TESTFS/renameme
+
+
+if is_global_zone && !is_linux
+then
+       # create a filesystem we can share
+       log_must $ZFS create $TESTPOOL/$TESTFS/unshared
+       log_must $ZFS set sharenfs=off $TESTPOOL/$TESTFS/unshared
+
+       # create a filesystem that we can unshare
+       log_must $ZFS create $TESTPOOL/$TESTFS/shared
+       log_must $ZFS set sharenfs=on $TESTPOOL/$TESTFS/shared
+fi
+
+
+log_must $ZFS create -o version=1 $TESTPOOL/$TESTFS/version1
+log_must $ZFS create -o version=1 $TESTPOOL/$TESTFS/allowed
+log_must $ZFS allow everyone create $TESTPOOL/$TESTFS/allowed
+
+if is_global_zone
+then
+
+       # Now create several virtual disks to test zpool with
+
+       $MKFILE 100m /$TESTDIR/disk1.dat
+       $MKFILE 100m /$TESTDIR/disk2.dat
+       $MKFILE 100m /$TESTDIR/disk3.dat
+       $MKFILE 100m /$TESTDIR/disk-additional.dat
+       $MKFILE 100m /$TESTDIR/disk-export.dat
+       $MKFILE 100m /$TESTDIR/disk-offline.dat
+       $MKFILE 100m /$TESTDIR/disk-spare1.dat
+       $MKFILE 100m /$TESTDIR/disk-spare2.dat
+
+       # and create a pool we can perform attach remove replace,
+       # etc. operations with
+       log_must $ZPOOL create $TESTPOOL.virt mirror /$TESTDIR/disk1.dat \
+       /$TESTDIR/disk2.dat /$TESTDIR/disk3.dat /$TESTDIR/disk-offline.dat \
+       spare /$TESTDIR/disk-spare1.dat
+
+
+       # Offline one of the disks to test online
+       log_must $ZPOOL offline $TESTPOOL.virt /$TESTDIR/disk-offline.dat
+
+
+       # create an exported pool to test import
+       log_must $ZPOOL create $TESTPOOL.exported /$TESTDIR/disk-export.dat
+       log_must $ZPOOL export $TESTPOOL.exported
+
+       set -A props $POOL_PROPS
+       set -A prop_vals $POOL_VALS
+       typeset -i i=0
+
+       while [[ $i -lt ${#props[*]} ]]
+       do
+               prop_name=${props[$i]}
+               prop_val=${prop_vals[$i]}
+               log_must $ZPOOL set $prop_name=$prop_val $TESTPOOL
+               i=$(( $i + 1 ))
+       done
+
+       # copy a v1 pool from cli_root
+       $CP $STF_SUITE/tests/functional/cli_root/zpool_upgrade/zfs-pool-v1.dat.bz2 \
+           /$TESTDIR
+       log_must $BUNZIP2 /$TESTDIR/zfs-pool-v1.dat.bz2
+       log_must $ZPOOL import -d /$TESTDIR v1-pool
+fi
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zdb_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zdb_001_neg.ksh
new file mode 100755 (executable)
index 0000000..4e4276f
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zdb can't run as a user on datasets, but can run without arguments
+#
+# STRATEGY:
+# 1. Run zdb as a user, it should print information
+# 2. Run zdb as a user on different datasets, it should fail
+#
+
+function check_zdb
+{
+       $@ > /tmp/zdb.$$
+       $GREP "Dataset mos" /tmp/zdb.$$
+       if [ $? -eq 0 ]
+       then
+               log_fail "$@ exited 0 when run as a non root user!"
+       fi
+       $RM /tmp/zdb.$$
+}
+
+
+function cleanup
+{
+       if [ -e /tmp/zdb_001_neg.$$.txt ]
+       then
+               $RM /tmp/zdb_001_neg.$$.txt
+       fi
+
+}
+
+verify_runnable "global"
+
+log_assert "zdb can't run as a user on datasets, but can run without arguments"
+log_onexit cleanup
+
+log_must eval "$ZDB > /tmp/zdb_001_neg.$$.txt"
+# verify the output looks okay
+log_must $GREP pool_guid /tmp/zdb_001_neg.$$.txt
+log_must $RM /tmp/zdb_001_neg.$$.txt
+
+# we shouldn't able to run it on any dataset
+check_zdb $ZDB $TESTPOOL
+check_zdb $ZDB $TESTPOOL/$TESTFS
+check_zdb $ZDB $TESTPOOL/$TESTFS@snap
+check_zdb $ZDB $TESTPOOL/$TESTFS.clone
+
+log_pass "zdb can't run as a user on datasets, but can run without arguments"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_001_neg.ksh
new file mode 100755 (executable)
index 0000000..f055e2b
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs shows a usage message when run as a user
+#
+# STRATEGY:
+# 1. Run zfs as a user
+# 2. Verify it produces a usage message
+#
+
+function cleanup
+{
+       if [ -e /tmp/zfs_001_neg.$$.txt ]
+       then
+               $RM /tmp/zfs_001_neg.$$.txt
+       fi
+}
+
+log_onexit cleanup
+log_assert "zfs shows a usage message when run as a user"
+
+eval "$ZFS > /tmp/zfs_001_neg.$$.txt 2>&1"
+log_must $GREP "usage: zfs command args" /tmp/zfs_001_neg.$$.txt
+
+log_pass "zfs shows a usage message when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_allow_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_allow_001_neg.ksh
new file mode 100755 (executable)
index 0000000..40f9937
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs allow returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Verify that trying to show allows works as a user
+# 2. Verify that trying to set allows fails as a user
+#
+#
+
+# check to see if we have zfs allow
+$ZFS 2>&1 | $GREP "allow" > /dev/null
+if (($? != 0)) then
+       log_unsupported "ZFS allow not supported on this machine."
+fi
+
+log_assert "zfs allow returns an error when run as a user"
+
+log_must $ZFS allow $TESTPOOL/$TESTFS
+log_mustnot $ZFS allow $($LOGNAME) create $TESTPOOL/$TESTFS
+
+# now verify that the above command actually did nothing by
+# checking for any allow output. ( if no allows are granted,
+# nothing should be output )
+OUTPUT=$($ZFS allow $TESTPOOL/$TESTFS | $GREP "Local+Descendent" )
+if [ -n "$OUTPUT" ]
+then
+       log_fail "zfs allow permissions were granted on $TESTPOOL/$TESTFS"
+fi
+
+log_pass "zfs allow returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_clone_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_clone_001_neg.ksh
new file mode 100755 (executable)
index 0000000..ccf5b4d
--- /dev/null
@@ -0,0 +1,54 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs clone returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Verify that we're unable to clone snapshots as a user
+#
+#
+
+log_assert "zfs clone returns an error when run as a user"
+log_mustnot $ZFS clone $TESTPOOL/$TESTFS@snap $TESTPOOL/$TESTFS.myclone
+
+# check to see that the above command really did nothing
+if datasetexists $TESTPOOL/$TESTFS.myclone
+then
+       log_fail "Dataset $TESTPOOL/$TESTFS.myclone should not exist!"
+fi
+log_pass "zfs clone returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_create_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_create_001_neg.ksh
new file mode 100755 (executable)
index 0000000..2b5d9bf
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+# Executing various badly formed 'zfs create' should fail.
+#
+# STRATEGY:
+# 1. Create an array of badly formed sub-commands.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "both"
+
+
+set -A args  "" "create $TESTPOOL/$TESTFS" \
+    "create $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "create $TESTPOOL/$TESTCLCT/$TESTFS" \
+    "create $TESTFS/$TESTPOOL/$TESTCLCT"
+
+log_assert "Verify zfs create without parameters fails."
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZFS ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'create' fails as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_destroy_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_destroy_001_neg.ksh
new file mode 100755 (executable)
index 0000000..3beb68f
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zfs destroy' fails as non-root.
+#
+# STRATEGY:
+# 1. Create an array of options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "both"
+
+
+set -A args "destroy" "destroy $TESTPOOL/$TESTFS" \
+    "destroy -f" "destroy -f $TESTPOOL/$TESTFS" \
+    "destroy -r" "destroy -r $TESTPOOL/$TESTFS" \
+    "destroy -rf $TESTPOOL/$TESTFS" \
+    "destroy -fr $TESTPOOL/$TESTFS" \
+    "destroy $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "destroy -f $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "destroy -r $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "destroy -rf $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "destroy -fr $TESTPOOL/$TESTFS@$TESTSNAP"
+
+log_assert "zfs destroy [-f|-r] [fs|snap]"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZFS ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'destroy' fails as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_get_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_get_001_neg.ksh
new file mode 100755 (executable)
index 0000000..c2d61a2
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs get works when run as a user
+#
+# STRATEGY:
+# 1. Run zfs get with an array of different arguments
+# 2. Verify for each property, we get the value that's expected
+#
+#
+
+log_assert "zfs get works when run as a user"
+
+typeset -i i=0
+
+set -A props $PROP_NAMES
+set -A prop_vals $PROP_VALS
+
+while [[ $i -lt ${#args[*]} ]]
+do
+       PROP=${props[$i]}
+       EXPECTED=${prop_vals[$i]}
+       ACTUAL=$( $ZFS get $PROP -o value -H snapdir $TESTPOOl/$TESTFS/prop )
+       if [ "$ACTUAL" != "$EXPECTED" ]
+       then
+               log_fail "Property $PROP value was $ACTUAL, expected $EXPECTED"
+       fi
+        i=$(( $i + 1 ))
+done
+
+log_pass "zfs get works when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_inherit_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_inherit_001_neg.ksh
new file mode 100755 (executable)
index 0000000..61b9c87
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs inherit returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Verify that we can't inherit a property when running as a user
+#
+#
+
+log_assert "zfs inherit returns an error when run as a user"
+log_mustnot $ZFS inherit snapdir $TESTPOOL/$TESTFS/$TESTFS2
+
+# check to see that the above command really did nothing
+PROP=$($ZFS get snapdir $TESTPOOL/$TESTFS)
+if [ "$PROP" = "visible" ]
+then
+       log_fail "snapdir property inherited from the $TESTPOOL/$TESTFS!"
+fi
+
+log_pass "zfs inherit returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_mount_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_mount_001_neg.ksh
new file mode 100755 (executable)
index 0000000..d324f1c
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs mount returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Verify that we can't mount the unmounted filesystem created in setup
+#
+#
+
+log_assert "zfs mount returns an error when run as a user"
+
+log_mustnot $ZFS mount $TESTPOOL/$TESTFS/$TESTFS2.unmounted
+
+# now verify that the above command didn't do anything
+MOUNTED=$($MOUNT | $GREP $TESTPOOL/$TESTFS/$TESTFS2.unmounted)
+if [ -n "$MOUNTED" ]
+then
+       log_fail "Filesystem $TESTPOOL/$TESTFS/$TESTFS2.unmounted was mounted!"
+fi
+
+log_pass "zfs mount returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_promote_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_promote_001_neg.ksh
new file mode 100755 (executable)
index 0000000..d6b1718
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs promote returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Verify we don't have permissions to promote a clone
+#
+#
+
+log_assert "zfs promote returns an error when run as a user"
+
+log_mustnot $ZFS promote $TESTPOOL/$TESTFS/clone
+
+# Now verify that the above command didn't do anything
+if datasetexists $TESTPOOL/$TESTFS/clone@snap
+then
+       log_fail "Clone $TESTPOOl/$TESTFS/clone was actually promoted!"
+fi
+
+log_pass "zfs promote returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_receive_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_receive_001_neg.ksh
new file mode 100755 (executable)
index 0000000..ae07fef
--- /dev/null
@@ -0,0 +1,58 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs receive returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Attempt to receive a datastream as a user
+# 2. Verify that the dataset wasn't created
+#
+
+log_assert "zfs receive returns an error when run as a user"
+
+log_mustnot eval "$ZFS receive -d $TESTPOOL/$TESTFS/$TESTFS2 \
+ < /tmp/zfstest_datastream.dat"
+
+# verify that command actually did nothing
+
+if datasetexists $TESTPOOL/$TESTFS/$TESTFS2/$TESTFS
+then
+       log_fail "$TESTPOOL/$TESTFS/$TESTFS2/$TESTFS was received!"
+fi
+
+log_pass "zfs receive returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_rename_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_rename_001_neg.ksh
new file mode 100755 (executable)
index 0000000..118b420
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs rename returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to rename a dataset
+# 2. Verify that the renamed dataset does not exist.
+#
+#
+
+log_assert "zfs rename returns an error when run as a user"
+
+log_mustnot $ZFS rename $TESTPOOL/$TESTFS/renameme $TESTPOOL/$TESTFS/renameme1
+
+# now verify the above command didn't actually do anything
+if datasetexists $TESTPOOL/$TESTFS/renameme1
+then
+       log_fail "The dataset $TESTPOOL/$TESTFS/renameme was renamed!"
+fi
+
+log_pass "zfs rename returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_rollback_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_rollback_001_neg.ksh
new file mode 100755 (executable)
index 0000000..02f3422
--- /dev/null
@@ -0,0 +1,60 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs rollback returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to rollback a snapshot
+# 2. Verify that a file which doesn't exist in the snapshot still exists
+#    (showing the snapshot rollback failed)
+#
+#
+
+log_assert "zfs rollback returns an error when run as a user"
+
+log_mustnot $ZFS rollback $TESTPOOL/$TESTFS@snap
+
+# now verify the above command didn't actually do anything
+
+# in the above filesystem there's a file that should not exist once
+# the snapshot is rolled back - we check for it
+if [ ! -e /$TESTDIR/file.txt ]
+then
+       log_fail "Rollback of snapshot $TESTPOOL/$TESTFS@snap succeeded!"
+fi
+
+log_pass "zfs rollback returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_send_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_send_001_neg.ksh
new file mode 100755 (executable)
index 0000000..0e3af12
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs send returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to send a dataset to a file
+# 2. Verify the file created has zero-size
+#
+#
+
+function cleanup
+{
+       if [ -e /tmp/zfstest_datastream.$$ ]
+       then
+               log_must $RM /tmp/zfstest_datastream.$$
+       fi
+}
+
+log_assert "zfs send returns an error when run as a user"
+log_onexit cleanup
+
+log_mustnot eval "$ZFS send $TESTPOOL/$TESTFS@snap > /tmp/zfstest_datastream.$$"
+
+# Now check that the above command actually did nothing
+
+# We should have a non-zero-length file in /tmp
+if [ -s /tmp/zfstest_datastream.$$ ]
+then
+       log_fail "A zfs send file was created in /tmp/zfstest_datastream.$$ !"
+fi
+
+log_pass "zfs send returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_set_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_set_001_neg.ksh
new file mode 100755 (executable)
index 0000000..9f1c57c
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs set returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to set an array of properties on a dataset
+# 2. Verify that those properties were not set and retain their original values.
+#
+#
+
+log_assert "zfs set returns an error when run as a user"
+
+typeset -i i=0
+
+set -A props $PROP_NAMES
+set -A prop_vals $PROP_VALS
+set -A prop_new $PROP_ALTVALS
+
+while [[ $i -lt ${#args[*]} ]]
+do
+       PROP=${props[$i]}
+       EXPECTED=${prop_vals[$i]}
+       NEW=${prop_new[$i]}
+       log_mustnot $ZFS set $PROP=$NEW $TESTPOOL/$TESTFS/prop
+
+       # Now verify that the above command did nothing
+       ACTUAL=$($ZFS get $PROP -o value -H snapdir $TESTPOOl/$TESTFS/prop )
+       if [ "$ACTUAL" != "$EXPECTED" ]
+       then
+               log_fail "Property $PROP was set to $ACTUAL, expected $EXPECTED"
+       fi
+        i=$(( $i + 1 ))
+done
+
+log_pass "zfs set returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_share_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_share_001_neg.ksh
new file mode 100755 (executable)
index 0000000..4127234
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs share returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to share a dataset
+# 2. Verify the dataset was not shared.
+#
+#
+
+verify_runnable "global"
+
+log_assert "zfs share returns an error when run as a user"
+
+if is_shared $TESTDIR/unshared
+then
+       log_fail "$TESTPOOL/$TESTFS/unshared was incorrectly shared initially!"
+fi
+
+log_mustnot $ZFS share $TESTPOOL/$TESTFS/unshared
+
+# Now verify that the above command didn't actually do anything
+if is_shared $TESTDIR/unshared
+then
+       log_fail "$TESTPOOL/$TESTFS/unshared was actually shared!"
+fi
+
+log_pass "zfs share returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_snapshot_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_snapshot_001_neg.ksh
new file mode 100755 (executable)
index 0000000..88183b1
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs snapshot returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to snapshot a dataset
+# 2. Verify the snapshot wasn't taken
+#
+#
+
+log_assert "zfs snapshot returns an error when run as a user"
+
+log_mustnot $ZFS snapshot $TESTPOOL/$TESTFS@usersnap1
+
+# Now verify that the above command didn't actually do anything
+if datasetexists $TESTPOOL/$TESTFS@usersnap1
+then
+       log_fail "Snapshot $TESTPOOL/$TESTFS@usersnap1 was taken !"
+fi
+
+log_pass "zfs snapshot returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unallow_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unallow_001_neg.ksh
new file mode 100755 (executable)
index 0000000..106e0f8
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs unallow returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to unallow a set of permissions
+# 2. Verify the unallow wasn't performed
+#
+#
+
+# check to see if we have zfs unallow
+$ZFS 2>&1 | $GREP "unallow" > /dev/null
+if (($? != 0)) then
+        log_unsupported "ZFS unallow not supported on this machine."
+fi
+
+log_assert "zfs unallow returns an error when run as a user"
+
+log_mustnot $ZFS unallow everyone $TESTPOOL/$TESTFS/allowed
+
+# now check with zfs allow to see if the permissions are still there
+OUTPUT=$($ZFS allow $TESTPOOL/$TESTFS/allowed | $GREP "Local+Descendent" )
+if [ -z "$OUTPUT" ]
+then
+       log_fail "Error - create permissions were unallowed on \
+       $TESTPOOL/$TESTFS/allowed"
+fi
+
+log_pass "zfs unallow returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unmount_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unmount_001_neg.ksh
new file mode 100755 (executable)
index 0000000..e0c703f
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zfs umount' and its variants fail as non-root.
+#
+# STRATEGY:
+# 1. Create an array of options.
+# 2. Execute each element of the array.
+# 3. Verify that the commands fail with an error code.
+#
+
+verify_runnable "both"
+
+set -A args "umount" "umount -f" "unmount" "unmount -f" \
+    "umount $TESTPOOL/$TESTFS" "umount -f $TESTPOOL/$TESTFS" \
+    "unmount $TESTPOOL/$TESTFS" "unmount -f $TESTPOOL/$TESTFS" \
+    "umount $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "umount -f $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "unmount $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "unmount -f $TESTPOOL/$TESTFS@$TESTSNAP" \
+    "umount $TESTDIR" "umount -f $TESTDIR" \
+    "unmount $TESTDIR" "unmount -f $TESTDIR"
+
+log_assert "zfs u[n]mount [-f] [mountpoint|fs|snap]"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZFS ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'u[n]mount' fails as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unshare_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_unshare_001_neg.ksh
new file mode 100755 (executable)
index 0000000..4849244
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs unshare returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to unshare a shared dataset
+# 2. Verify the dataset is still shared
+#
+#
+
+verify_runnable "global"
+
+log_assert "zfs unshare returns an error when run as a user"
+
+#  verify that the filesystem was shared initially
+if not_shared $TESTDIR/shared
+then
+       log_fail "$TESTPOOL/$TESTFS/shared was not shared initially at all!"
+fi
+
+log_mustnot $ZFS unshare $TESTPOOL/$TESTFS/shared
+
+# now verify that the above command didn't do anything
+if not_shared $TESTDIR/shared
+then
+       log_fail "$TESTPOOL/$TESTFS/shared was actually unshared!"
+fi
+
+log_pass "zfs unshare returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_upgrade_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zfs_upgrade_001_neg.ksh
new file mode 100755 (executable)
index 0000000..290827d
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zfs upgrade returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to upgrade a version1 dataset
+# 2. Verify the dataset wasn't upgraded
+#
+#
+
+# check to see if we have upgrade capability
+$ZFS upgrade > /dev/null 2>&1
+HAS_UPGRADE=$?
+if [ $HAS_UPGRADE -ne 0 ]
+then
+       log_unsupported "Zfs upgrade not supported"
+fi
+
+log_assert "zfs upgrade returns an error when run as a user"
+
+
+log_mustnot $ZFS upgrade $TESTPOOL/$TESTFS/version1
+
+# now check to see the above command didn't do anything
+VERSION=$($ZFS upgrade $TESTPOOL/$TESTFS/version1 2>&1 \
+        | $GREP "already at this version")
+if [ -n "$VERSION" ]
+then
+       log_fail "A filesystem was upgraded!"
+fi
+
+log_pass "zfs upgrade returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_001_neg.ksh
new file mode 100755 (executable)
index 0000000..e4512bc
--- /dev/null
@@ -0,0 +1,60 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool shows a usage message when run as a user
+#
+# STRATEGY:
+# 1. Run the zpool command
+# 2. Verify that a usage message is produced
+#
+#
+
+function cleanup
+{
+       if [ -e /tmp/zpool_001_neg.$$.txt ]
+       then
+               $RM /tmp/zpool_001_neg.$$.txt
+       fi
+}
+
+log_onexit cleanup
+log_assert "zpool shows a usage message when run as a user"
+
+eval "$ZPOOL > /tmp/zpool_001_neg.$$.txt 2>&1"
+log_must $GREP "usage: zpool command args" /tmp/zpool_001_neg.$$.txt
+
+log_pass "zpool shows a usage message when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_add_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_add_001_neg.ksh
new file mode 100755 (executable)
index 0000000..9858f28
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zpool add' fails as non-root.
+#
+# STRATEGY:
+# 1. Create an array of options.
+# 2. Execute each element of the array.
+# 3. Verify that an error is returned.
+#
+
+verify_runnable "global"
+
+ADD_DISK="${DISKS%% }"
+ADD_DISK="${ADD_DISK##* }"
+
+[[ -z $ADD_DISK ]] && \
+        log_fail "No spare disks available."
+
+# Under Linux dry-run commands have no legitimate reason to fail.
+if is_linux; then
+       set -A args "add" "add -f" "add -n" \
+           "add $TESTPOOL" "add -f $TESTPOOL" "add -n $TESTPOOL" \
+           "add -fn $TESTPOOL" "add -nf $TESTPOOL" \
+           "add $TESTPOOL $ADD_DISK" "add -f $TESTPOOL $ADD_DISK"
+else
+       set -A args "add" "add -f" "add -n" \
+           "add $TESTPOOL" "add -f $TESTPOOL" "add -n $TESTPOOL" \
+           "add -fn $TESTPOOL" "add -nf $TESTPOOL" \
+           "add $TESTPOOL $ADD_DISK" "add -f $TESTPOOL $ADD_DISK" \
+           "add -n $TESTPOOL $ADD_DISK" \
+           "add -fn $TESTPOOL $ADD_DISK" \
+           "add -nf $TESTPOOL $ADD_DISK"
+fi
+
+log_assert "zpool add [-fn] pool_name vdev"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'add' and its options fail as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_attach_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_attach_001_neg.ksh
new file mode 100755 (executable)
index 0000000..e1d883d
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool attach returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to attach a disk to a pool
+# 2.Verify that the attach failed
+#
+#
+
+function check_for_attach
+{
+       RESULT=$($ZPOOL status -v $TESTPOOL.virt | $GREP disk-additional.dat)
+       if [ -n "$RESULT" ]
+       then
+               log_fail "A disk was attached to the pool!"
+       fi
+}
+
+verify_runnable "global"
+
+log_assert "zpool attach returns an error when run as a user"
+
+log_mustnot $ZPOOL attach $TESTPOOL.virt /$TESTDIR/disk1.dat \
+       /$TESTDIR/disk-additional.dat
+check_for_attach
+
+log_mustnot $ZPOOL attach -f $TESTPOOL.virt /$TESTDIR/disk1.dat \
+        /$TESTDIR/disk-additional.dat
+check_for_attach
+
+log_pass "zpool attach returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_clear_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_clear_001_neg.ksh
new file mode 100755 (executable)
index 0000000..0100bed
--- /dev/null
@@ -0,0 +1,52 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool clear returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Attempt to clear errors on a zpool
+# 2. Verify that the command fails
+#
+
+verify_runnable "global"
+
+log_assert "zpool clear returns an error when run as a user"
+
+log_mustnot $ZPOOL clear $TESTPOOL
+
+log_pass "zpool clear returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_create_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_create_001_neg.ksh
new file mode 100755 (executable)
index 0000000..592c51a
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zpool create' fails as a non-root user.
+#
+# STRATEGY:
+# 1. Create an array of options.
+# 2. Execute each element of the array.
+# 3. Verify that an error is returned.
+#
+
+verify_runnable "global"
+
+ADD_DISK="${DISKS%% }"
+ADD_DISK="${ADD_DISK##* }"
+
+[[ -z $ADD_DISK ]] && \
+        log_fail "No spare disks available."
+
+# Under Linux dry-run commands have no legitimate reason to fail.
+if is_linux; then
+       set -A args "create" "create -f" "create -n" \
+           "create $TESTPOOL" "create -f $TESTPOOL" "create -n $TESTPOOL" \
+           "create -fn $TESTPOOL" "create -nf $TESTPOOL" \
+           "create $TESTPOOL $ADD_DISK" "create -f $TESTPOOL $ADD_DISK"
+else
+       set -A args "create" "create -f" "create -n" \
+           "create $TESTPOOL" "create -f $TESTPOOL" "create -n $TESTPOOL" \
+           "create -fn $TESTPOOL" "create -nf $TESTPOOL" \
+           "create $TESTPOOL $ADD_DISK" "create -f $TESTPOOL $ADD_DISK" \
+           "create -n $TESTPOOL $ADD_DISK" \
+           "create -fn $TESTPOOL $ADD_DISK" \
+           "create -nf $TESTPOOL $ADD_DISK"
+fi
+
+log_assert "zpool create [-fn] pool_name vdev"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'create' and its options fail as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_destroy_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_destroy_001_neg.ksh
new file mode 100755 (executable)
index 0000000..4deb228
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+# Verify that 'zpool destroy' fails as non-root.
+#
+# STRATEGY:
+# 1. Create an array of options.
+# 2. Execute each element of the array.
+# 3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+set -A args "destroy" "destroy -f" \
+    "destroy $TESTPOOL" "destroy -f $TESTPOOL" \
+    "destroy $TESTPOOL $TESTPOOL"
+
+log_assert "zpool destroy [-f] [pool_name ...]"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'destroy' and its options fail as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_detach_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_detach_001_neg.ksh
new file mode 100755 (executable)
index 0000000..c5e8ab1
--- /dev/null
@@ -0,0 +1,58 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool detach returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Attempt to detach a device from a pool
+# 2. Verify the command fails
+#
+
+verify_runnable "global"
+
+log_assert "zpool detach returns an error when run as a user"
+
+log_mustnot $ZPOOL detach $TESTPOOL.virt /$TESTDIR/disk1.dat
+
+RESULT=$($ZPOOL status -v $TESTPOOL.virt | $GREP disk1.dat)
+if [ -z "$RESULT" ]
+then
+       log_fail "A disk was detached from the pool!"
+fi
+
+log_pass "zpool detach returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_export_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_export_001_neg.ksh
new file mode 100755 (executable)
index 0000000..4915190
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool export returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to export a pool
+# 2. Verify the command fails
+#
+
+function check_for_export
+{
+       RESULT=$($ZPOOL list | $GREP $TESTPOOL.virt )
+       if [ -z "$RESULT" ]
+       then
+               log_fail "A pool was exported!"
+       fi
+
+}
+
+verify_runnable "global"
+
+log_assert "zpool export returns an error when run as a user"
+
+log_mustnot $ZPOOL export $TESTPOOL.virt
+check_for_export
+
+log_mustnot $ZPOOL export -f $TESTPOOL.virt
+check_for_export
+
+log_pass "zpool export returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_get_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_get_001_neg.ksh
new file mode 100755 (executable)
index 0000000..697ec6e
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool get works when run as a user
+#
+# STRATEGY:
+#
+# 1. For each property, get that property
+# 2. Verify the property was the same as that set in setup
+#
+
+verify_runnable "global"
+
+log_assert "zpool get works when run as a user"
+
+set -A props $POOL_PROPS
+set -A prop_vals $POOL_VALS
+
+while [[ $i -lt ${#args[*]} ]]
+do
+       PROP=${props[$i]}
+       EXPECTED=${prop_vals[$i]}
+       ACTUAL=$( $ZPOOL get $PROP $TESTPOOL | $GREP $PROP | $AWK '{print $1}' )
+       if [ "$ACTUAL" != "$EXPECTED" ]
+       then
+               log_fail "Property $PROP value was $ACTUAL, expected $EXPECTED"
+       fi
+        i=$(( $i + 1 ))
+done
+
+log_must $ZPOOL get all $TESTPOOL
+
+log_pass "zpool get works when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_history_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_history_001_neg.ksh
new file mode 100755 (executable)
index 0000000..9a304b7
--- /dev/null
@@ -0,0 +1,55 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool history works when run as a user
+#
+# STRATEGY:
+# 1. Attempt to get history on a test pool
+# 2. Verify the command fails
+#
+
+verify_runnable "global"
+
+log_assert "zpool history returns an error when run as a user"
+
+log_mustnot $ZPOOL history
+log_mustnot $ZPOOL history $TESTPOOL
+log_mustnot $ZPOOL history -i $TESTPOOL
+log_mustnot $ZPOOL history -l $TESTPOOL
+log_mustnot $ZPOOL history -il $TESTPOOL
+
+log_assert "zpool history returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_import_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_import_001_neg.ksh
new file mode 100755 (executable)
index 0000000..b15a451
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool import returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to import an exported pool
+# 2. Verify the command fails
+#
+#
+
+function check_for_import
+{
+       RESULT=$($ZPOOL list -H -o name | $GREP $TESTPOOL.exported)
+       if [ -n "$RESULT" ]
+       then
+               log_fail "Pool $TESTPOOL.export was successfully imported!"
+       fi
+}
+
+verify_runnable "global"
+
+log_assert "zpool import returns an error when run as a user"
+log_mustnot $ZPOOL import
+
+log_mustnot $ZPOOL import -a
+check_for_import
+
+log_mustnot $ZPOOL import -d /$TESTDIR $TESTPOOL.exported
+check_for_import
+
+log_pass "zpool import returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_import_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_import_002_neg.ksh
new file mode 100755 (executable)
index 0000000..dfcef4d
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+# Executing 'zpool import' as regular user should denied.
+#
+# STRATEGY:
+# 1. Create an array of options try to detect exported/destroyed pools.
+# 2. Execute 'zpool import' with each element of the array by regular user.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "both"
+
+typeset testpool
+if is_global_zone ; then
+        testpool=$TESTPOOL.exported
+else
+        testpool=${TESTPOOL%%/*}
+fi
+
+set -A args "" "-D" "-Df" "-f" "-f $TESTPOOL" "-Df $TESTPOOL" "-a"
+
+log_assert "Executing 'zpool import' by regular user fails"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL import ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Executing 'zpool import' by regular user fails as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_offline_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_offline_001_neg.ksh
new file mode 100755 (executable)
index 0000000..952c921
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool offline returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to offline a device in a pool
+# 2. Verify that the command fails
+#
+#
+
+function check_for_offline
+{
+       RESULT=$($ZPOOL status -v $TESTPOOL.virt | $GREP disk-1.dat \
+                | $GREP OFFLINE )
+       if [ -n "$RESULT" ]
+       then
+               log_fail "A disk was taken offline!"
+       fi
+}
+
+verify_runnable "global"
+
+log_assert "zpool offline returns an error when run as a user"
+
+log_mustnot $ZPOOL offline $TESTPOOL.virt /$TESTDIR/disk-1.dat
+check_for_offline
+
+log_mustnot $ZPOOL offline -t $TESTPOOL.virt /$TESTDIR/disk-1.dat
+check_for_offline
+
+log_pass "zpool offline returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_online_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_online_001_neg.ksh
new file mode 100755 (executable)
index 0000000..36d3aef
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool online returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to online a device in a pool
+# 2. Verify the command fails
+#
+#
+
+function check_for_online
+{
+       RESULT=$($ZPOOL status -v $TESTPOOL.virt | $GREP disk-offline.dat \
+                | $GREP ONLINE )
+       if [ -n "$RESULT" ]
+       then
+               log_fail "A disk was brough online!"
+       fi
+}
+
+verify_runnable "global"
+
+log_assert "zpool online returns an error when run as a user"
+
+log_mustnot $ZPOOL online $TESTPOOL.virt /$TESTDIR/disk-offline.dat
+check_for_online
+
+log_mustnot $ZPOOL online -t $TESTPOOL.virt /$TESTDIR/disk-offline.dat
+check_for_online
+
+log_pass "zpool online returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_remove_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_remove_001_neg.ksh
new file mode 100755 (executable)
index 0000000..38acd5f
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool remove returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to remove a device from a pool
+# 2. Verify the command fails
+#
+#
+
+verify_runnable "global"
+
+log_assert "zpool remove returns an error when run as a user"
+
+log_mustnot $ZPOOL remove $TESTPOOL.virt /$TESTDIR/disk-spare1.dat
+
+RESULT=$($ZPOOL status -v $TESTPOOL.virt | $GREP disk-spare1.dat)
+if [ -z "$RESULT" ]
+then
+       log_fail "A disk was removed from the pool!"
+fi
+
+
+log_pass "zpool remove returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_replace_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_replace_001_neg.ksh
new file mode 100755 (executable)
index 0000000..b933d41
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool replace returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to replace a device in a pool
+# 2. Verify the command fails
+#
+#
+
+function check_for_replace
+{
+       $SLEEP 10
+       RESULT=$($ZPOOL status -v $TESTPOOL.virt | $GREP disk-additional.dat)
+       if [ -n "$RESULT" ]
+       then
+               log_fail "A disk was replaced in the pool!"
+       fi
+}
+
+verify_runnable "global"
+
+log_assert "zpool replace returns an error when run as a user"
+
+log_mustnot $ZPOOL replace $TESTPOOL.virt /$TESTDIR/disk-1.dat \
+        /$TESTDIR/disk-additional.dat
+check_for_replace
+
+log_mustnot $ZPOOL replace -f $TESTPOOL.virt /$TESTDIR/disk-1.dat \
+ /$TESTDIR/disk-additional.dat
+check_for_replace
+
+log_pass "zpool replace returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_scrub_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_scrub_001_neg.ksh
new file mode 100755 (executable)
index 0000000..ddc06f8
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool scrub returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to start a scrub on a pool
+# 2. Verify the command fails
+#
+#
+
+verify_runnable "global"
+
+log_assert "zpool scrub returns an error when run as a user"
+
+log_mustnot $ZPOOL scrub $TESTPOOL
+log_mustnot $ZPOOL scrub -s $TESTPOOL
+
+log_pass "zpool scrub returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_set_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_set_001_neg.ksh
new file mode 100755 (executable)
index 0000000..bcf3a90
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool set returns an error when run as a user
+#
+# STRATEGY:
+# 1. Attempt to set some properties on a pool
+# 2. Verify the command fails
+#
+#
+
+verify_runnable "global"
+
+log_assert "zpool set returns an error when run as a user"
+
+set -A props $POOL_NAMES
+set -A prop_vals $POOL_VALS
+set -A prop_new $POOL_ALTVALS
+
+while [[ $i -lt ${#args[*]} ]]
+do
+       PROP=${props[$i]}
+       EXPECTED=${prop_vals[$i]}
+       NEW=${prop_new[$i]}
+       log_mustnot $POOL set $PROP=$NEW $TESTPOOL
+
+       # Now verify that the above command did nothing
+       ACTUAL=$( $ZPOOL get $PROP $TESTPOOL | $GREP $PROP | $AWK '{print $1}' )
+       if [ "$ACTUAL" != "$EXPECTED" ]
+       then
+               log_fail "Property $PROP was set to $ACTUAL, expected $EXPECTED"
+       fi
+        i=$(( $i + 1 ))
+done
+
+
+log_pass "zpool set returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_status_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_status_001_neg.ksh
new file mode 100755 (executable)
index 0000000..42111a6
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool status works when run as a user
+#
+# STRATEGY:
+#
+# 1. Run zpool status as a user
+# 2. Verify we get output
+#
+
+function check_pool_status
+{
+       RESULT=$($GREP "pool:" /tmp/pool-status.$$)
+       if [ -z "$RESULT" ]
+       then
+               log_fail "No pool: string found in zpool status output!"
+       fi
+       $RM /tmp/pool-status.$$
+}
+
+verify_runnable "global"
+
+log_assert "zpool status works when run as a user"
+
+log_must eval "$ZPOOL status > /tmp/pool-status.$$"
+check_pool_status
+
+log_must eval "$ZPOOL status -v > /tmp/pool-status.$$"
+check_pool_status
+
+log_must eval "$ZPOOL status $TESTPOOL> /tmp/pool-status.$$"
+check_pool_status
+
+log_must eval "$ZPOOL status -v $TESTPOOL > /tmp/pool-status.$$"
+check_pool_status
+
+# $TESTPOOL.virt has an offline device, so -x will show it
+log_must eval "$ZPOOL status -x $TESTPOOL.virt > /tmp/pool-status.$$"
+check_pool_status
+
+log_pass "zpool status works when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_upgrade_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/misc/zpool_upgrade_001_neg.ksh
new file mode 100755 (executable)
index 0000000..02c33ca
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_user/misc/misc.cfg
+
+#
+# DESCRIPTION:
+#
+# zpool upgrade returns an error when run as a user
+#
+# STRATEGY:
+#
+# 1. Attempt to upgrade a pool
+# 2. Verify the command fails
+#
+
+verify_runnable "global"
+
+log_assert "zpool upgrade returns an error when run as a user"
+
+log_onexit cleanup
+# zpool upgrade returns 0 when it can't do anything
+log_must $ZPOOL upgrade $TESTPOOL.virt
+
+# Now try to upgrade our version 1 pool
+log_mustnot $ZPOOL upgrade v1-pool
+
+# if the pool has been upgraded, then v1-pool won't be listed in the output
+# of zpool upgrade anymore
+RESULT=$($ZPOOL upgrade | $GREP v1-pool)
+if [ -z "$RESULT" ]
+then
+       log_fail "A pool was upgraded successfully!"
+fi
+
+log_pass "zpool upgrade returns an error when run as a user"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/Makefile.am
new file mode 100644 (file)
index 0000000..34390af
--- /dev/null
@@ -0,0 +1,12 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_user/zfs_list
+dist_pkgdata_SCRIPTS = \
+       zfs_list.cfg \
+       zfs_list.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       zfs_list_001_pos.ksh \
+       zfs_list_002_pos.ksh \
+       zfs_list_003_pos.ksh \
+       zfs_list_004_neg.ksh \
+       zfs_list_007_pos.ksh \
+       zfs_list_008_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/cleanup.ksh
new file mode 100755 (executable)
index 0000000..115e00c
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+
+depth_fs_cleanup
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/setup.ksh
new file mode 100755 (executable)
index 0000000..66bcc06
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+. $STF_SUITE/tests/functional/cli_user/zfs_list/zfs_list.cfg
+
+DISK=${DISKS%% *}
+
+default_setup_noexit $DISK
+
+# create datasets and set checksum options
+set -A cksumarray $CKSUMOPTS
+typeset -i index=0
+for dataset in $DATASETS
+do
+       log_must $ZFS create $TESTPOOL/$TESTFS/$dataset
+       $SLEEP 1
+        log_must $ZFS snapshot $TESTPOOL/$TESTFS/${dataset}@snap
+
+       $SLEEP 1
+       if is_global_zone ; then
+               log_must $ZFS create -V 64M $TESTPOOL/$TESTFS/${dataset}-vol
+               $SLEEP 1
+               log_must $ZFS snapshot $TESTPOOL/$TESTFS/${dataset}-vol@snap
+       fi
+
+       # sleep to ensure that the datasets have different creation dates
+       $SLEEP 1
+       log_must $ZFS set checksum=${cksumarray[$index]} \
+               $TESTPOOL/$TESTFS/$dataset
+       if datasetexists $TESTPOOL/$TESTFS/${dataset}-vol; then
+               log_must $ZFS set checksum=${cksumarray[$index]} \
+                       $TESTPOOL/$TESTFS/${dataset}-vol
+       fi
+
+        index=$((index + 1))
+done
+
+depth_fs_setup
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list.cfg b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list.cfg
new file mode 100644 (file)
index 0000000..59f367c
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+# Datasets (in order of creation date) and which checksum options
+# we want to set for each dataset.
+# These are used by various zfs list tests
+export DATASETS="Apple Banana Carrot Orange apple banana carrot"
+export CKSUMOPTS="on sha256 sha256 sha256 fletcher4 off fletcher2"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list.kshlib b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list.kshlib
new file mode 100644 (file)
index 0000000..e64739d
--- /dev/null
@@ -0,0 +1,118 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# A function that verifies sort order. It takes as input
+# a command, which gets executed. We then iterate over the results
+# comparing that the sort order passed in via the list
+#
+function verify_sort { # command list name
+
+       # now verify we've sorted by creation date:
+       typeset CMD=$1
+       typeset list=$2
+       typeset name=$3
+
+       typeset -i RET=0
+       typeset -i index=1
+
+       # run the command to verify that it works
+       log_must eval "$CMD > /dev/null"
+
+       # Now check the sort order
+       for dataset in $( $CMD )
+       do
+               ACTUAL=$(basename $dataset)
+               if [ "$dataset" != "$TESTPOOL/$TESTFS" ]
+               then
+                       EXPECTED=$($ECHO $list | $AWK "{print \$$index}")
+                       if [ "$ACTUAL" != "$EXPECTED" ]
+                       then
+                               log_note "WARNING:" \
+                                       "'$ACTUAL' does not equal '$EXPECTED'"
+                               log_fail "ERROR: Sort by $name fails."
+                       fi
+
+                       ((index = index + 1))
+               fi
+       done
+
+       # finally check to see if we have the expected number of elements
+       if [ $index -ne $($ECHO $list | $AWK '{print split($0,arr)+1}') ]
+       then
+               log_fail "Warning: " \
+                       "unexpected number of filesystems found in list output!"
+       fi
+}
+
+# A function that verifies reverse sort order. It takes as input
+# a command, which gets executed. We then iterate over the results
+# comparing that the sort order passed in via the list
+#
+function verify_reverse_sort { # command list name
+
+       typeset CMD=$1
+       typeset list=$2
+       typeset name=$3
+
+       # set our index to the be number of elements in the list
+       typeset -i index=$($ECHO $list | $AWK '{print split($0,arr)}')
+
+       log_note "Checking reverse sort by '$name'," \
+               "expecting the reverse of '$list'"
+       log_must eval "$CMD > /dev/null"
+
+       for dataset in $( $CMD )
+       do
+               ACTUAL=$(basename $dataset)
+               if [ "$dataset" != "$TESTPOOL/$TESTFS" ]
+               then
+                       EXPECTED=$($ECHO $list | $AWK "{print \$$index}")
+                       if [ "$ACTUAL" != "$EXPECTED" ]
+                       then
+                               log_note "Warning:" \
+                                       "'$ACTUAL' does not equal to" \
+                                       "the reverse of '$EXPECTED'"
+                               log_fail "ERROR: Reverse sort by '$name' fails."
+                       fi
+
+                       ((index = index - 1))
+               fi
+       done
+
+       # finally check to see if we have the expected number of elements
+       if [ $index -ne 0 ]
+       then
+               log_fail "Warning: " \
+                       "unexpected number of filesystems found in list output!"
+       fi
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_001_pos.ksh
new file mode 100755 (executable)
index 0000000..b0af4eb
--- /dev/null
@@ -0,0 +1,116 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+
+#
+# DESCRIPTION:
+# Executing well-formed 'zfs list' commands should return success.
+#
+# STRATEGY:
+# 1. Create an array of valid options.
+# 2. Execute each element in the array.
+# 3. Verify success is returned.
+#
+
+verify_runnable "both"
+
+set -A args "list" "list -r" "list -H" \
+        "list $TESTPOOL/$TESTFS" \
+        "list -r $TESTPOOL/$TESTFS" "list -H $TESTPOOL/$TESTFS" \
+        "list -rH $TESTPOOL/$TESTFS" "list -Hr $TESTPOOL/$TESTFS" \
+        "list -o name $TESTPOOL/$TESTFS" "list -r -o name $TESTPOOL/$TESTFS" \
+        "list -H -o name $TESTPOOL/$TESTFS" "list -rH -o name $TESTPOOL/$TESTFS" \
+        "list -Hr -o name $TESTPOOL/$TESTFS"
+
+set -A d_args " " "-r" "-H" \
+        "$TESTPOOL/$TESTFS" \
+        "-r $TESTPOOL/$TESTFS" "-H $TESTPOOL/$TESTFS" \
+        "-rH $TESTPOOL/$TESTFS" "-Hr $TESTPOOL/$TESTFS" \
+        "-o name $TESTPOOL/$TESTFS" "-r -o name $TESTPOOL/$TESTFS" \
+        "-H -o name $TESTPOOL/$TESTFS" "-rH -o name $TESTPOOL/$TESTFS" \
+        "-Hr -o name $TESTPOOL/$TESTFS"
+
+typeset -i m=${#args[*]}
+typeset -i n=0
+typeset -i k=0
+while (( n<${#depth_options[*]} ));
+do
+       (( k=0 ))
+       while (( k<${#d_args[*]} ));
+       do
+               args[$m]="list"" -${depth_options[$n]}"" ${d_args[$k]}"
+               (( k+=1 ))
+               (( m+=1 ))
+       done
+       (( n+=1 ))
+done
+
+set -A pathargs "list -r $TESTDIR" "list -H $TESTDIR" \
+       "list -r ./../$TESTDIR" "list -H ./../$TESTDIR"
+
+set -A d_pathargs " $TESTDIR" "-r $TESTDIR" "-H $TESTDIR" \
+       "-r ./../$TESTDIR" "-H ./../$TESTDIR"
+
+(( m=${#pathargs[*]} ))
+(( n=0 ))
+(( k=0 ))
+while (( n<${#depth_options[*]} ));
+do
+       (( k=0 ))
+       while (( k<${#d_pathargs[*]} ));
+       do
+               pathargs[$m]="list"" -${depth_options[$n]}"" ${d_pathargs[$k]}"
+               (( k+=1 ))
+               (( m+=1 ))
+       done
+       (( n+=1 ))
+done
+
+log_assert "Verify 'zfs list [-rH] [-o property[,prop]*] [fs|clct|vol]'."
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_must eval "$ZFS ${args[i]} > /dev/null"
+       ((i = i + 1))
+done
+
+# Verify 'zfs list <path>' will succeed on absolute or relative path.
+
+cd /tmp
+typeset -i i=0
+while [[ $i -lt ${#pathargs[*]} ]]; do
+       log_must eval "$ZFS ${pathargs[i]} > /dev/null"
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'list' succeeds as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_002_pos.ksh
new file mode 100755 (executable)
index 0000000..3d546ec
--- /dev/null
@@ -0,0 +1,176 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_user/zfs_list/zfs_list.kshlib
+
+#
+# DESCRIPTION:
+# The sort functionality in 'zfs list' works as expected.
+#
+# STRATEGY:
+# 1. Using several zfs datasets with names, creation dates, checksum options
+# 2. Sort the datasets by name, checksum options, creation date.
+# 3. Verify that the datasets are sorted correctly.
+#
+
+verify_runnable "both"
+
+# datasets ordered by name
+fs_name="Apple Banana Carrot Orange apple banana carrot"
+vol_name="Apple-vol Banana-vol Carrot-vol Orange-vol apple-vol"
+vol_name="$vol_name banana-vol carrot-vol"
+if is_global_zone ; then
+       snap_name="Apple-vol@snap Apple@snap Banana-vol@snap Banana@snap"
+       snap_name="$snap_name Carrot-vol@snap Carrot@snap Orange-vol@snap Orange@snap"
+       snap_name="$snap_name apple-vol@snap apple@snap banana-vol@snap banana@snap"
+       snap_name="$snap_name carrot-vol@snap carrot@snap"
+else
+       snap_name="Apple@snap Banana@snap"
+       snap_name="$snap_name Carrot@snap Orange@snap"
+       snap_name="$snap_name apple@snap banana@snap"
+       snap_name="$snap_name carrot@snap"
+fi
+
+fs_creation=$fs_name
+vol_creation=$vol_name
+if is_global_zone ; then
+       snap_creation="Apple@snap Apple-vol@snap Banana@snap Banana-vol@snap"
+       snap_creation="$snap_creation Carrot@snap Carrot-vol@snap Orange@snap Orange-vol@snap"
+       snap_creation="$snap_creation apple@snap apple-vol@snap banana@snap banana-vol@snap"
+       snap_creation="$snap_creation carrot@snap carrot-vol@snap"
+else
+       snap_creation="Apple@snap Banana@snap"
+       snap_creation="$snap_creation Carrot@snap Orange@snap"
+       snap_creation="$snap_creation apple@snap banana@snap"
+       snap_creation="$snap_creation carrot@snap"
+fi
+
+#
+# datsets ordered by checksum options (note, Orange, Carrot & Banana have the
+# same checksum options, so ZFS should revert to sorting them alphabetically by
+# name)
+#
+fs_cksum="carrot apple banana Apple Banana Carrot Orange"
+vol_cksum="carrot-vol apple-vol banana-vol Apple-vol Banana-vol"
+vol_cksum="$vol_cksum Carrot-vol Orange-vol"
+snap_cksum=$snap_creation
+
+fs_rev_cksum="carrot apple banana Apple Orange Carrot Banana"
+vol_rev_cksum="carrot-vol apple-vol banana-vol Apple-vol Orange-vol"
+vol_rev_cksum="$vol_rev_cksum Carrot-vol Banana-vol"
+
+log_assert "The sort functionality in 'zfs list' works as expected."
+
+#
+# we must be in the C locale here, as running in other locales
+# will make zfs use that locale's sort order.
+#
+LC_ALL=C; export LC_ALL
+
+# sort by creation
+verify_sort \
+       "$ZFS list -H -r -o name -s creation -t filesystem $TESTPOOL/$TESTFS" \
+       "$fs_creation" "creation date"
+if is_global_zone ; then
+       verify_sort \
+       "$ZFS list -H -r -o name -s creation -t volume $TESTPOOL/$TESTFS" \
+       "$vol_creation" "creation date"
+fi
+verify_sort \
+       "$ZFS list -H -r -o name -s creation -t snapshot $TESTPOOL/$TESTFS" \
+       "$snap_creation" "creation date"
+
+# sort by checksum
+verify_sort \
+       "$ZFS list -H -r -o name -s checksum -t filesystem $TESTPOOL/$TESTFS" \
+       "$fs_cksum" "checksum"
+if is_global_zone ; then
+       verify_sort \
+       "$ZFS list -H -r -o name -s checksum -t volume $TESTPOOL/$TESTFS" \
+       "$vol_cksum" "checksum"
+fi
+verify_sort \
+       "$ZFS list -H -r -o name -s checksum -t snapshot $TESTPOOL/$TESTFS" \
+       "$snap_cksum" "checksum"
+verify_sort \
+       "$ZFS list -H -r -o name -S checksum -t snapshot $TESTPOOL/$TESTFS" \
+       "$snap_cksum" "checksum"
+
+# sort by name
+verify_sort \
+       "$ZFS list -H -r -o name -s name -t filesystem $TESTPOOL/$TESTFS" \
+       "$fs_name" "name"
+if is_global_zone ; then
+       verify_sort \
+       "$ZFS list -H -r -o name -s name -t volume $TESTPOOL/$TESTFS" \
+       "$vol_name" "name"
+fi
+verify_sort \
+       "$ZFS list -H -r -o name -s name -t snapshot $TESTPOOL/$TESTFS" \
+       "$snap_name" "name"
+
+# reverse sort by creation
+verify_reverse_sort \
+       "$ZFS list -H -r -o name -S creation -t filesystem $TESTPOOL/$TESTFS" \
+       "$fs_creation" "creation date"
+if is_global_zone ; then
+       verify_reverse_sort \
+       "$ZFS list -H -r -o name -S creation -t volume $TESTPOOL/$TESTFS" \
+       "$vol_creation" "creation date"
+fi
+verify_reverse_sort \
+       "$ZFS list -H -r -o name -S creation -t snapshot $TESTPOOL/$TESTFS" \
+       "$snap_creation" "creation date"
+
+# reverse sort by checksum
+verify_reverse_sort \
+       "$ZFS list -H -r -o name -S checksum -t filesystem $TESTPOOL/$TESTFS" \
+       "$fs_rev_cksum" "checksum"
+if is_global_zone ; then
+       verify_reverse_sort \
+       "$ZFS list -H -r -o name -S checksum -t volume $TESTPOOL/$TESTFS" \
+       "$vol_rev_cksum" "checksum"
+fi
+
+# reverse sort by name
+verify_reverse_sort \
+       "$ZFS list -H -r -o name -S name -t filesystem $TESTPOOL/$TESTFS"\
+       "$fs_name" "name"
+if is_global_zone ; then
+       verify_reverse_sort \
+       "$ZFS list -H -r -o name -S name -t volume $TESTPOOL/$TESTFS"\
+       "$vol_name" "name"
+fi
+verify_reverse_sort \
+       "$ZFS list -H -r -o name -S name -t snapshot $TESTPOOL/$TESTFS"\
+       "$snap_name" "name"
+
+log_pass "The sort functionality in 'zfs list' works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_003_pos.ksh
new file mode 100755 (executable)
index 0000000..f685456
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify 'zfs list -r' could recursively display any children
+#      of the dataset.
+#
+# STRATEGY:
+# 1. Prepare a set of datasets by hierarchy.
+# 2. Execute 'zfs list -r' at the top of these datasets.
+# 3. Verify all child datasets are all be shown.
+#
+
+function cleanup
+{
+       if [[ -f $tmpfile ]]; then
+               $RM -f $tmpfile
+       fi
+}
+
+verify_runnable "both"
+log_onexit cleanup
+
+log_assert "Verify 'zfs list -r' could display any children recursively."
+
+tmpfile=/var/tmp/zfslist.out.$$
+children="$TESTPOOL/$TESTFS"
+
+for fs in $DATASETS ; do
+       children="$children $TESTPOOL/$TESTFS/$fs"
+done
+
+cd /tmp
+
+for path in $TESTPOOL/$TESTFS $TESTDIR ./../$TESTDIR ; do
+       $ZFS list -rH -o name $path > $tmpfile
+       for fs in $children ; do
+               $GREP "^${fs}$" $tmpfile > /dev/null 2>&1
+               if (( $? != 0 )); then
+                       log_fail "$fs not shown in the output list."
+               fi
+       done
+done
+
+log_pass "'zfs list -r' could display any children recursively."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_004_neg.ksh
new file mode 100755 (executable)
index 0000000..13d6233
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify 'zfs list [-r]' should fail while
+#              * the given dataset does not exist
+#              * the given path does not exist.
+#              * the given path does not belong to zfs.
+#
+# STRATEGY:
+# 1. Create an array of invalid options.
+# 2. Execute each element in the array.
+# 3. Verify failure is returned.
+#
+
+verify_runnable "both"
+
+log_assert "Verify 'zfs list [-r]' should fail while the given " \
+       "dataset/path does not exist or not belong to zfs."
+
+paths="$TESTPOOL/NONEXISTFS $TESTPOOL/$TESTFS/NONEXISTFS \
+       /$TESTDIR/NONEXISTFS /devices /tmp ./../devices ./../tmp"
+
+cd /tmp
+
+for fs in $paths ; do
+       log_mustnot $ZFS list $fs
+       log_mustnot $ZFS list -r $fs
+done
+
+log_pass "'zfs list [-r]' fails while the given dataset/path does not exist " \
+       "or not belong to zfs."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_007_pos.ksh
new file mode 100755 (executable)
index 0000000..984bc77
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+
+#
+# DESCRIPTION:
+#      'zfs list -d <n>' should get expected output.
+#
+# STRATEGY:
+#      1. 'zfs list -d <n>' to get the output.
+#      2. 'zfs list -r|egrep' to get the expected output.
+#      3. Compare the two outputs, they shoud be same.
+#
+
+verify_runnable "both"
+
+set -A fs_type "all" "filesystem" "snapshot"
+if is_global_zone ; then
+       set -A fs_type ${fs_type[*]} "volume"
+fi
+
+function cleanup
+{
+       log_must $RM -f $DEPTH_OUTPUT
+       log_must $RM -f $EXPECT_OUTPUT
+}
+
+log_onexit cleanup
+log_assert "'zfs list -d <n>' should get expected output."
+
+mntpnt=/var/tmp
+DEPTH_OUTPUT="$mntpnt/depth_output"
+EXPECT_OUTPUT="$mntpnt/expect_output"
+typeset -i old_val=0
+typeset -i j=0
+typeset -i fs=0
+typeset eg_opt="$DEPTH_FS"$
+for dp in ${depth_array[@]}; do
+       (( j=old_val+1 ))
+       while (( j<=dp && j<=MAX_DEPTH )); do
+               eg_opt="$eg_opt""|depth""$j"$
+               (( j+=1 ))
+       done
+       (( fs=0 ))
+       while (( fs<${#fs_type[*]} )); do
+               if [[ "$dp" == "0" ]] && \
+                 [[ "${fs_type[$fs]}" == "volume" || "${fs_type[$fs]}" == "snapshot" ]]; then
+                       log_must eval "$ZFS list -H -d $dp -o name -t ${fs_type[$fs]} $DEPTH_FS > $DEPTH_OUTPUT"
+                       [[ -s "$DEPTH_OUTPUT" ]] && \
+                               log_fail "$DEPTH_OUTPUT should be null."
+                       log_mustnot $ZFS list -rH -o name -t ${fs_type[$fs]} $DEPTH_FS | $EGREP -e '$eg_opt'
+               else
+                       log_must eval "$ZFS list -H -d $dp -o name -t ${fs_type[$fs]} $DEPTH_FS > $DEPTH_OUTPUT"
+                       log_must eval "$ZFS list -rH -o name -t ${fs_type[$fs]} $DEPTH_FS | $EGREP -e '$eg_opt' > $EXPECT_OUTPUT"
+                       log_must $DIFF $DEPTH_OUTPUT $EXPECT_OUTPUT
+               fi
+               (( fs+=1 ))
+       done
+       (( old_val=dp ))
+done
+
+log_pass "'zfs list -d <n>' should get expected output."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zfs_list/zfs_list_008_neg.ksh
new file mode 100755 (executable)
index 0000000..74c0b8b
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/cli_root/zfs_get/zfs_get_list_d.kshlib
+
+#
+# DESCRIPTION:
+# A negative depth or a non numeric depth should fail in 'zfs list -d <n>'
+#
+# STRATEGY:
+# 1. Run zfs list -d with negative depth or non numeric depth
+# 2. Verify that zfs list returns error
+#
+
+verify_runnable "both"
+
+log_assert "A negative depth or a non numeric depth should fail in 'zfs list -d <n>'"
+
+set -A  badargs "a" "AB" "aBc" "2A" "a2b" "aB2" "-1" "-32" "-999"
+
+typeset -i i=0
+while (( i < ${#badargs[*]} ))
+do
+       log_mustnot eval "$ZFS list -d ${badargs[i]} $DEPTH_FS >/dev/null 2>&1"
+       (( i = i + 1 ))
+done
+
+log_pass "A negative depth or a non numeric depth should fail in 'zfs list -d <n>'"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/Makefile.am
new file mode 100644 (file)
index 0000000..621dff9
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_user/zpool_iostat
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_iostat_001_neg.ksh \
+       zpool_iostat_002_pos.ksh \
+       zpool_iostat_003_neg.ksh \
+       zpool_iostat_004_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/setup.ksh
new file mode 100755 (executable)
index 0000000..77eb6bd
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_raidz_setup $DISKS
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_001_neg.ksh
new file mode 100755 (executable)
index 0000000..a1fac98
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that 'zpool iostat' can be executed as non-root.
+#
+# STRATEGY:
+# 1. Create an array of options.
+# 2. Execute each element of the array.
+# 3. Verify that a success is returned.
+#
+
+verify_runnable "both"
+
+typeset testpool
+if is_global_zone ; then
+       testpool=$TESTPOOL
+else
+       testpool=${TESTPOOL%%/*}
+fi
+
+set -A args "iostat" "iostat $testpool"
+
+log_assert "zpool iostat [pool_name ...] [interval]"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_must $ZPOOL ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'iostat' succeeds as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_002_pos.ksh
new file mode 100755 (executable)
index 0000000..ec5599a
--- /dev/null
@@ -0,0 +1,74 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that 'zpool iostat [interval [count]]' can be executed as non-root.
+#
+# STRATEGY:
+# 1. Set the interval to 1 and count to 4.
+# 2. Sleep for 4 seconds.
+# 3. Verify that the output has 4 records.
+# 4. Set interval to 0.5 and count to 1 to test floating point intervals.
+
+verify_runnable "both"
+
+typeset tmpfile=/var/tmp/zfsiostat.out.$$
+typeset -i stat_count=0
+
+function cleanup
+{
+       if [[ -f $tmpfile ]]; then
+               $RM -f $tmpfile
+       fi
+}
+
+log_onexit cleanup
+log_assert "zpool iostat [pool_name ...] [interval] [count]"
+
+if ! is_global_zone ; then
+       TESTPOOL=${TESTPOOL%%/*}
+fi
+
+$ZPOOL iostat $TESTPOOL 1 4 > $tmpfile 2>&1 &
+sleep 4
+stat_count=$($GREP $TESTPOOL $tmpfile | $WC -l)
+
+if [[ $stat_count -ne 4 ]]; then
+       log_fail "zpool iostat [pool_name] [interval] [count] failed"
+fi
+
+# Test a floating point interval value
+log_must $ZPOOL iostat -v 0.5 1
+
+log_pass "zpool iostat [pool_name ...] [interval] [count] passed"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_003_neg.ksh
new file mode 100755 (executable)
index 0000000..097be9e
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool iostat' command with bad options fails.
+#
+# STRATEGY:
+# 1. Create an array of badly formed 'zpool iostat' options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "both"
+
+typeset testpool
+if is_global_zone ; then
+        testpool=$TESTPOOL
+else
+        testpool=${TESTPOOL%%/*}
+fi
+
+set -A args "" "-?" "-f" "nonexistpool" "$TESTPOOL/$TESTFS" \
+       "$testpool 0" "$testpool -1" "$testpool 1 0" \
+       "$testpool 0 0" "$testpool -wl" "$testpool -wq" "$testpool -wr" \
+       "$testpool -rq" "$testpool -lr"
+
+log_assert "Executing 'zpool iostat' with bad options fails"
+
+typeset -i i=1
+while [[ $i -lt ${#args[*]} ]]; do
+       log_assert "doing $ZPOOL iostat ${args[i]}"
+       log_mustnot $ZPOOL iostat ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Executing 'zpool iostat' with bad options fails"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_004_pos.ksh
new file mode 100755 (executable)
index 0000000..0119a70
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+# Copyright (C) 2016 Lawrence Livermore National Security, LLC.
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool iostat' command with various combinations of extended
+# stats (-lqwr), parsable/script options (-pH), and misc lists of pools
+# and vdevs.
+#
+# STRATEGY:
+# 1. Create an array of mixed 'zpool iostat' options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "both"
+
+typeset testpool
+if is_global_zone ; then
+        testpool=$TESTPOOL
+else
+        testpool=${TESTPOOL%%/*}
+fi
+
+set -A args "" "-v" "-q" "-l" "-lq $TESTPOOL" "-ql ${DISKS[0]} ${DISKS[1]}" \
+       "-w $TESTPOOL ${DISKS[0]} ${DISKS[1]}" \
+       "-wp $TESTPOOL" \
+       "-qlH $TESTPOOL ${DISKS[0]}" \
+       "-vpH ${DISKS[0]}" \
+       "-wpH ${DISKS[0]}" \
+       "-r ${DISKS[0]}" \
+       "-rpH ${DISKS[0]}"
+
+log_assert "Executing 'zpool iostat' with extended stat options succeeds"
+log_note "testpool: $TESTPOOL, disks $DISKS"
+
+typeset -i i=1
+while [[ $i -lt ${#args[*]} ]]; do
+       log_note "doing $ZPOOL iostat ${args[i]}"
+       log_must $ZPOOL iostat ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Executing 'zpool iostat' with extended stat options succeeds"
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/Makefile.am b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/Makefile.am
new file mode 100644 (file)
index 0000000..de8cb36
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/cli_user/zpool_list
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       zpool_list_001_pos.ksh \
+       zpool_list_002_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/setup.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/setup.ksh
new file mode 100755 (executable)
index 0000000..d275e06
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/zpool_list_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/zpool_list_001_pos.ksh
new file mode 100755 (executable)
index 0000000..4de8867
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that 'zpool list' succeeds as non-root.
+#
+# STRATEGY:
+# 1. Create an array of options.
+# 2. Execute each element of the array.
+# 3. Verify the command succeeds.
+#
+
+verify_runnable "both"
+
+if ! is_global_zone; then
+       TESTPOOL=${TESTPOOL%%/*}
+fi
+
+set -A args "list $TESTPOOL" "list -H $TESTPOOL" "list" "list -H" \
+    "list -H -o name $TESTPOOL" "list -o name $TESTPOOL" \
+    "list -o name,size,capacity,health,altroot $TESTPOOL" \
+    "list -H -o name,size,capacity,health,altroot $TESTPOOL"
+
+log_assert "zpool list [-H] [-o filed[,filed]*] [<pool_name> ...]"
+
+typeset -i i=0
+while [[ $i -lt ${#args[*]} ]]; do
+       log_must $ZPOOL ${args[i]}
+
+       ((i = i + 1))
+done
+
+log_pass "The sub-command 'list' succeeds as non-root."
diff --git a/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/zpool_list_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/cli_user/zpool_list/zpool_list_002_neg.ksh
new file mode 100755 (executable)
index 0000000..469437a
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing 'zpool list' command with bad options fails.
+#
+# STRATEGY:
+# 1. Create an array of badly formed 'zpool list' options.
+# 2. Execute each element of the array.
+# 3. Verify an error code is returned.
+#
+
+verify_runnable "both"
+
+set -A args "" "-?" "-f" "-o" \
+       "-o fakeproperty" "-o name,size,fakeproperty"
+
+log_assert "Executing 'zpool list' with bad options fails"
+
+typeset -i i=1
+while [[ $i -lt ${#args[*]} ]]; do
+       log_mustnot $ZPOOL list ${args[i]}
+       ((i = i + 1))
+done
+
+log_pass "Executing 'zpool list' with bad options fails"
diff --git a/zfs/tests/zfs-tests/tests/functional/compression/Makefile.am b/zfs/tests/zfs-tests/tests/functional/compression/Makefile.am
new file mode 100644 (file)
index 0000000..d11b0a7
--- /dev/null
@@ -0,0 +1,9 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/compression
+dist_pkgdata_SCRIPTS = \
+       compress.cfg \
+       cleanup.ksh \
+       setup.ksh \
+       compress_001_pos.ksh \
+       compress_002_pos.ksh \
+       compress_003_pos.ksh \
+       compress_004_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/compression/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/compression/cleanup.ksh
new file mode 100755 (executable)
index 0000000..0573003
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. ${STF_SUITE}/include/libtest.shlib
+
+default_container_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/compression/compress.cfg b/zfs/tests/zfs-tests/tests/functional/compression/compress.cfg
new file mode 100644 (file)
index 0000000..b237306
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export BLOCKSZ=8192
+export NUM_WRITES=16384
+export DATA=13
diff --git a/zfs/tests/zfs-tests/tests/functional/compression/compress_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/compression/compress_001_pos.ksh
new file mode 100755 (executable)
index 0000000..ce2c26b
--- /dev/null
@@ -0,0 +1,74 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/compression/compress.cfg
+
+#
+# DESCRIPTION:
+# Create two files of exactly the same size. One with compression
+# and one without. Ensure the compressed file is smaller.
+#
+# STRATEGY:
+# Use "zfs set" to turn on compression and create files before
+# and after the set call. The compressed file should be smaller.
+#
+
+verify_runnable "both"
+
+typeset OP=create
+
+log_assert "Ensure that compressed files are smaller."
+
+log_note "Ensure compression is off"
+log_must $ZFS set compression=off $TESTPOOL/$TESTFS
+
+log_note "Writing file without compression..."
+log_must $FILE_WRITE -o $OP -f $TESTDIR/$TESTFILE0 -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+
+log_note "Add compression property to the dataset and write another file"
+log_must $ZFS set compression=on $TESTPOOL/$TESTFS
+
+log_must $FILE_WRITE -o $OP -f $TESTDIR/$TESTFILE1 -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+
+$SLEEP 60
+
+FILE0_BLKS=`$DU -k $TESTDIR/$TESTFILE0 | $AWK '{ print $1}'`
+FILE1_BLKS=`$DU -k $TESTDIR/$TESTFILE1 | $AWK '{ print $1}'`
+
+if [[ $FILE0_BLKS -le $FILE1_BLKS ]]; then
+       log_fail "$TESTFILE0 is smaller than $TESTFILE1" \
+                       "($FILE0_BLKS <= $FILE1_BLKS)"
+fi
+
+log_pass "$TESTFILE0 is bigger than $TESTFILE1 ($FILE0_BLKS > $FILE1_BLKS)"
diff --git a/zfs/tests/zfs-tests/tests/functional/compression/compress_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/compression/compress_002_pos.ksh
new file mode 100755 (executable)
index 0000000..88e1556
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/compression/compress.cfg
+
+#
+# DESCRIPTION:
+# Create two files of exactly the same size. One with compression
+# and one without. Ensure the compressed file is smaller.
+#
+# NOTE: This test uses a dataset rather than a simple file system.
+#
+# STRATEGY:
+# Create a dataset, turn on compression and create files before
+# and after the property change. The compressed file should be smaller.
+#
+
+verify_runnable "both"
+
+typeset OP=create
+
+log_assert "Ensure that compressed files in a dataset are smaller."
+
+log_note "Ensure compression is off"
+log_must $ZFS set compression=off $TESTPOOL/$TESTCTR
+
+log_note "Writing file without compression..."
+log_must $FILE_WRITE -o $OP -f $TESTDIR1/$TESTFILE0 -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+
+log_note "Add compression property to the dataset and write another file"
+log_must $ZFS set compression=on $TESTPOOL/$TESTCTR
+
+log_must $FILE_WRITE -o $OP -f $TESTDIR1/$TESTFILE1 -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+
+$SLEEP 60
+
+FILE0_BLKS=`$DU -k $TESTDIR1/$TESTFILE0 | $AWK '{ print $1}'`
+FILE1_BLKS=`$DU -k $TESTDIR1/$TESTFILE1 | $AWK '{ print $1}'`
+
+if [[ $FILE0_BLKS -le $FILE1_BLKS ]]; then
+       log_fail "$TESTFILE0 is smaller than $TESTFILE1" \
+                       "($FILE0_BLKS <= $FILE1_BLKS)"
+fi
+
+log_pass "$TESTFILE0 is bigger than $TESTFILE1 ($FILE0_BLKS > $FILE1_BLKS)"
diff --git a/zfs/tests/zfs-tests/tests/functional/compression/compress_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/compression/compress_003_pos.ksh
new file mode 100755 (executable)
index 0000000..c995b53
--- /dev/null
@@ -0,0 +1,96 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# With 'compression' or 'compress'  set, changing filesystem blocksize cannot
+# cause system panic
+#
+# STRATEGY:
+#      1. Set 'compression' or "compress" to on
+#      2. Set different blocksize with ZFS filesystem
+#      3. Use 'mkfile' create single block and multi-block files
+#      4. Verify the system continued work
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -f $TESTDIR/*
+}
+
+log_assert "Changing blocksize doesn't casue system panic with compression settings"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+single_blk_file=$TESTDIR/singleblkfile.$$
+multi_blk_file=$TESTDIR/multiblkfile.$$
+typeset -i blksize=512
+typeset -i fsize=0
+typeset -i offset=0
+
+for propname in "compression" "compress"
+do
+       for value in $(get_compress_opts zfs_compress)
+       do
+               log_must $ZFS set $propname=$value $fs
+               if [[ $value == "gzip-6" ]]; then
+                       value="gzip"
+               fi
+               real_val=$(get_prop $propname $fs)
+               [[ $real_val != $value ]] && \
+                       log_fail "Set property $propname=$value failed."
+
+               (( blksize = 512 ))
+               while (( blksize <= 131072 )); do
+                       log_must $ZFS set recordsize=$blksize $fs
+                       (( offset = $RANDOM ))
+                       if (( offset > blksize )); then
+                               (( offset = offset % blksize ))
+                       fi
+                       if (( (offset % 2) == 0 )); then
+                               #keep offset as non-power-of-2
+                               (( offset = offset + 1 ))
+                       fi
+                       (( fsize = offset ))
+                       log_must $MKFILE $fsize $single_blk_file
+                       (( fsize = blksize + offset ))
+                       log_must $MKFILE $fsize $multi_blk_file
+
+                       (( blksize = blksize * 2 ))
+               done
+       done
+done
+
+log_pass "The system works as expected while changing blocksize with compression settings"
diff --git a/zfs/tests/zfs-tests/tests/functional/compression/compress_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/compression/compress_004_pos.ksh
new file mode 100755 (executable)
index 0000000..8b9054e
--- /dev/null
@@ -0,0 +1,141 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# With 'compression' set, a file with non-power-of-2 blocksize storage space
+# can be freed as will normally.
+#
+# STRATEGY:
+#      1. Set 'compression' or 'compress' to on or lzjb
+#      2. Set different recordsize with ZFS filesystem
+#      3. Repeatedly using 'randfree_file' to create a file and then free its
+#         storage space with different range, the system should work normally.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -f $TESTDIR/*
+}
+
+function create_free_testing #<file size> <file>
+{
+       typeset -i fsz=$1
+       typeset file=$2
+       typeset -i start=0
+       typeset -i len=0
+       typeset -i dist=0
+
+       for start in 0 `expr $RANDOM % $fsz`
+       do
+               (( dist = fsz - start ))
+               for len in `expr $RANDOM % $dist` $dist \
+                       `expr $start + $dist`; do
+
+                       # Zero length results in EINVAL for fallocate(2).
+                       if is_linux; then
+                               if (( len == 0 )); then
+                                       continue
+                               fi
+                       fi
+
+                       log_must $RANDFREE_FILE -l fsz -s $start \
+                               -n $len $file
+                       [[ -e $file ]] && \
+                               log_must $RM -f $file
+               done
+       done
+}
+
+
+log_assert "Creating non-power-of-2 blocksize file and freeing the file \
+       storage space at will should work normally with compression setting"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+single_blk_file=$TESTDIR/singleblkfile.$$
+multi_blk_file=$TESTDIR/multiblkfile.$$
+typeset -i blksize=512
+typeset -i fsize=0
+typeset -i avail=0
+typeset -i blknum=0
+
+for propname in "compression" "compress"
+do
+       for value in $(get_compress_opts zfs_compress)
+       do
+               log_must $ZFS set compression=$value $fs
+               real_val=$(get_prop $propname $fs)
+               if [[ $value == "gzip-6" ]]; then
+                       value="gzip"
+               fi
+               [[ $real_val != $value ]] && \
+                       log_fail "Set property $propname=$value failed."
+
+               (( blksize = 512 ))
+               while (( blksize <= 131072 )); do
+                       log_must $ZFS set recordsize=$blksize $fs
+
+                       # doing single block testing
+                       (( fsize = $RANDOM ))
+                       if (( fsize > blksize )); then
+                               (( fsize = fsize % blksize ))
+                       fi
+                       if (( (fsize % 2) == 0 )); then
+                               #make sure fsize is non-power-of-2
+                               (( fsize = fsize + 1 ))
+                       fi
+                       create_free_testing $fsize $single_blk_file
+
+                       # doing multiple blocks testing
+                       avail=$(get_prop available $fs)
+                       (( blknum = avail / blksize ))
+                       # we just test <10 multi-blocks to limit testing time
+                       (( blknum = blknum % 9 ))
+                       while (( blknum < 2 )); do
+                               (( blknum = blknum + $RANDOM % 9 ))
+                       done
+                       if (( (blknum % 2) == 0 )); then
+                               (( blknum = blknum + 1 )) # keep blknum as odd
+                       fi
+                       (( fsize = blknum * blksize ))
+                       create_free_testing $fsize $multi_blk_file
+
+                       (( blksize = blksize * 2 ))
+               done
+       done
+done
+
+log_pass "Creating and freeing non-power-of-2 blocksize file work as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/compression/setup.ksh b/zfs/tests/zfs-tests/tests/functional/compression/setup.ksh
new file mode 100755 (executable)
index 0000000..677cb12
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_container_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/ctime/Makefile.am b/zfs/tests/zfs-tests/tests/functional/ctime/Makefile.am
new file mode 100644 (file)
index 0000000..1c7c26d
--- /dev/null
@@ -0,0 +1,12 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/ctime
+
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh
+
+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/ctime
+
+pkgexec_PROGRAMS = ctime_001_pos
+ctime_001_pos_SOURCES = ctime_001_pos.c
diff --git a/zfs/tests/zfs-tests/tests/functional/ctime/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/ctime/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/ctime/ctime_001_pos.c b/zfs/tests/zfs-tests/tests/functional/ctime/ctime_001_pos.c
new file mode 100644 (file)
index 0000000..73528d2
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * 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 <utime.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <string.h>
+
+#define        ST_ATIME 0
+#define        ST_CTIME 1
+#define        ST_MTIME 2
+
+#define        ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
+
+typedef struct timetest {
+       int     type;
+       char    *name;
+       int     (*func)(const char *pfile);
+} timetest_t;
+
+static char tfile[BUFSIZ] = { 0 };
+
+/*
+ * DESCRIPTION:
+ *     Verify time will be changed correctly after each operation.
+ *
+ * STRATEGY:
+ *     1. Define time test array.
+ *     2. Loop through each item in this array.
+ *     3. Verify the time is changed after each operation.
+ *
+ */
+
+static int
+get_file_time(const char *pfile, int what, time_t *ptr)
+{
+       struct stat stat_buf;
+
+       if (pfile == NULL || ptr == NULL) {
+               return (-1);
+       }
+
+       if (stat(pfile, &stat_buf) == -1) {
+               return (-1);
+       }
+
+       switch (what) {
+               case ST_ATIME:
+                       *ptr = stat_buf.st_atime;
+                       return (0);
+               case ST_CTIME:
+                       *ptr = stat_buf.st_ctime;
+                       return (0);
+               case ST_MTIME:
+                       *ptr = stat_buf.st_mtime;
+                       return (0);
+               default:
+                       return (-1);
+       }
+}
+
+static int
+do_read(const char *pfile)
+{
+       int fd, ret = 0;
+       char buf[BUFSIZ] = { 0 };
+
+       if (pfile == NULL) {
+               return (-1);
+       }
+
+       if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {
+               return (-1);
+       }
+       if (read(fd, buf, sizeof (buf)) == -1) {
+               (void) fprintf(stderr, "read(%d, buf, %zd) failed with errno "
+                   "%d\n", fd, sizeof (buf), errno);
+               (void) close(fd);
+               return (1);
+       }
+       (void) close(fd);
+
+       return (ret);
+}
+
+static int
+do_write(const char *pfile)
+{
+       int fd, ret = 0;
+       char buf[BUFSIZ] = "call function do_write()";
+
+       if (pfile == NULL) {
+               return (-1);
+       }
+
+       if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) {
+               return (-1);
+       }
+       if (write(fd, buf, strlen(buf)) == -1) {
+               (void) fprintf(stderr, "write(%d, buf, %d) failed with errno "
+                   "%d\n", fd, (int)strlen(buf), errno);
+               (void) close(fd);
+               return (1);
+       }
+       (void) close(fd);
+
+       return (ret);
+}
+
+static int
+do_link(const char *pfile)
+{
+       int ret = 0;
+       char link_file[BUFSIZ] = { 0 };
+       char pfile_copy[BUFSIZ] = { 0 };
+       char *dname;
+
+       if (pfile == NULL) {
+               return (-1);
+       }
+
+       strncpy(pfile_copy, pfile, sizeof (pfile_copy));
+       pfile_copy[sizeof (pfile_copy) - 1] = '\0';
+       /*
+        * Figure out source file directory name, and create
+        * the link file in the same directory.
+        */
+       dname = dirname((char *)pfile_copy);
+       (void) snprintf(link_file, BUFSIZ, "%s/%s", dname, "link_file");
+
+       if (link(pfile, link_file) == -1) {
+               (void) fprintf(stderr, "link(%s, %s) failed with errno %d\n",
+                   pfile, link_file, errno);
+               return (1);
+       }
+
+       (void) unlink(link_file);
+
+       return (ret);
+}
+
+static int
+do_creat(const char *pfile)
+{
+       int fd, ret = 0;
+
+       if (pfile == NULL) {
+               return (-1);
+       }
+
+       if ((fd = creat(pfile, ALL_MODE)) == -1) {
+               (void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno "
+                   "%d\n", pfile, errno);
+               return (1);
+       }
+       (void) close(fd);
+
+       return (ret);
+}
+
+static int
+do_utime(const char *pfile)
+{
+       int ret = 0;
+
+       if (pfile == NULL) {
+               return (-1);
+       }
+
+       /*
+        * Times of the file are set to the current time
+        */
+       if (utime(pfile, NULL) == -1) {
+               (void) fprintf(stderr, "utime(%s, NULL) failed with errno "
+                   "%d\n", pfile, errno);
+               return (1);
+       }
+
+       return (ret);
+}
+
+static int
+do_chmod(const char *pfile)
+{
+       int ret = 0;
+
+       if (pfile == NULL) {
+               return (-1);
+       }
+
+       if (chmod(pfile, ALL_MODE) == -1) {
+               (void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with "
+                   "errno %d\n", pfile, errno);
+               return (1);
+       }
+
+       return (ret);
+}
+
+static int
+do_chown(const char *pfile)
+{
+       int ret = 0;
+
+       if (pfile == NULL) {
+               return (-1);
+       }
+
+       if (chown(pfile, getuid(), getgid()) == -1) {
+               (void) fprintf(stderr, "chown(%s, %d, %d) failed with errno "
+                   "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
+               return (1);
+       }
+
+       return (ret);
+}
+
+static void
+cleanup(void)
+{
+       if ((strlen(tfile) != 0) && (access(tfile, F_OK) == 0)) {
+               (void) unlink(tfile);
+       }
+}
+
+static timetest_t timetest_table[] = {
+       { ST_ATIME,     "st_atime",     do_read         },
+       { ST_ATIME,     "st_atime",     do_utime        },
+       { ST_MTIME,     "st_mtime",     do_creat        },
+       { ST_MTIME,     "st_mtime",     do_write        },
+       { ST_MTIME,     "st_mtime",     do_utime        },
+       { ST_CTIME,     "st_ctime",     do_creat        },
+       { ST_CTIME,     "st_ctime",     do_write        },
+       { ST_CTIME,     "st_ctime",     do_chmod        },
+       { ST_CTIME,     "st_ctime",     do_chown        },
+       { ST_CTIME,     "st_ctime",     do_link         },
+       { ST_CTIME,     "st_ctime",     do_utime        },
+};
+
+#define        NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
+
+/* ARGSUSED */
+int
+main(int argc, char *argv[])
+{
+       int i, ret, fd;
+       char *penv[] = {"TESTDIR", "TESTFILE0"};
+
+       (void) fprintf(stdout, "Verify [acm]time is modified appropriately.\n");
+       (void) atexit(cleanup);
+
+       /*
+        * Get the environment variable values.
+        */
+       for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {
+               if ((penv[i] = getenv(penv[i])) == NULL) {
+                       (void) fprintf(stderr, "getenv(penv[%d])\n", i);
+                       return (1);
+               }
+       }
+       (void) snprintf(tfile, sizeof (tfile), "%s/%s", penv[0], penv[1]);
+
+       /*
+        * If the test file is exists, remove it first.
+        */
+       if (access(tfile, F_OK) == 0) {
+               (void) unlink(tfile);
+       }
+       ret = 0;
+       if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) {
+               (void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno);
+               return (1);
+       }
+       (void) close(fd);
+
+       for (i = 0; i < NCOMMAND; i++) {
+               time_t t1, t2;
+
+               /*
+                * Get original time before operating.
+                */
+               ret = get_file_time(tfile, timetest_table[i].type, &t1);
+               if (ret != 0) {
+                       (void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
+                           tfile, timetest_table[i].type, ret);
+                       return (1);
+               }
+
+               /*
+                * Sleep 2 seconds, then invoke command on given file
+                */
+               (void) sleep(2);
+               timetest_table[i].func(tfile);
+
+               /*
+                * Get time after operating.
+                */
+               ret = get_file_time(tfile, timetest_table[i].type, &t2);
+               if (ret != 0) {
+                       (void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
+                           tfile, timetest_table[i].type, ret);
+                       return (1);
+               }
+
+               if (t1 == t2) {
+                       (void) fprintf(stderr, "%s: t1(%ld) == t2(%ld)\n",
+                           timetest_table[i].name, (long)t1, (long)t2);
+                       return (1);
+               } else {
+                       (void) fprintf(stderr, "%s: t1(%ld) != t2(%ld)\n",
+                           timetest_table[i].name, (long)t1, (long)t2);
+               }
+       }
+
+       (void) fprintf(stdout, "PASS\n");
+       return (0);
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/ctime/setup.ksh b/zfs/tests/zfs-tests/tests/functional/ctime/setup.ksh
new file mode 100755 (executable)
index 0000000..fc5cec3
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/Makefile.am b/zfs/tests/zfs-tests/tests/functional/delegate/Makefile.am
new file mode 100644 (file)
index 0000000..6ccd65d
--- /dev/null
@@ -0,0 +1,26 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/delegate
+dist_pkgdata_SCRIPTS = \
+       delegate.cfg \
+       delegate_common.kshlib \
+       cleanup.ksh \
+       setup.ksh \
+       zfs_allow_001_pos.ksh \
+       zfs_allow_002_pos.ksh \
+       zfs_allow_003_pos.ksh \
+       zfs_allow_004_pos.ksh \
+       zfs_allow_005_pos.ksh \
+       zfs_allow_006_pos.ksh \
+       zfs_allow_007_pos.ksh \
+       zfs_allow_008_pos.ksh \
+       zfs_allow_009_neg.ksh \
+       zfs_allow_010_pos.ksh \
+       zfs_allow_011_neg.ksh \
+       zfs_allow_012_neg.ksh \
+       zfs_unallow_001_pos.ksh \
+       zfs_unallow_002_pos.ksh \
+       zfs_unallow_003_pos.ksh \
+       zfs_unallow_004_pos.ksh \
+       zfs_unallow_005_pos.ksh \
+       zfs_unallow_006_pos.ksh \
+       zfs_unallow_007_neg.ksh \
+       zfs_unallow_008_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/cleanup.ksh
new file mode 100755 (executable)
index 0000000..e14979d
--- /dev/null
@@ -0,0 +1,47 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+cleanup_user_group
+
+if ! is_linux; then
+       # restore the state of svc:/network/nis/client:default
+       if [[ -e $NISSTAFILE ]]; then
+               log_must $SVCADM enable svc:/network/nis/client:default
+               log_must $RM -f $NISSTAFILE
+       fi
+fi
+
+default_cleanup
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/delegate.cfg b/zfs/tests/zfs-tests/tests/functional/delegate/delegate.cfg
new file mode 100644 (file)
index 0000000..aaa6760
--- /dev/null
@@ -0,0 +1,72 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export NISSTAFILE=/var/tmp/nis_state
+
+export STAFF_GROUP=zfsgrp
+export STAFF1=staff1
+export STAFF2=staff2
+
+export OTHER_GROUP=othergrp
+export OTHER1=other1
+export OTHER2=other2
+
+export EVERYONE="$STAFF1 $STAFF2 $OTHER1 $OTHER2"
+
+#
+# 'readonly' is disabled for Linux because it requires remounting the
+# filesystem which is restricted to root for older versions of mount(8).
+#
+if is_linux; then
+       LOCAL_SET="snapshot"
+       LOCAL_DESC_SET="checksum"
+       DESC_SET="compression"
+else
+       LOCAL_SET="snapshot"
+       LOCAL_DESC_SET="readonly,checksum"
+       DESC_SET="compression"
+fi
+export LOCAL_SET
+export LOCAL_DESC_SET
+export DESC_SET
+
+export TESTVOL=testvol.delegate
+export VOLSIZE=150m
+
+export ROOT_TESTVOL=$TESTPOOL/$TESTVOL
+export ROOT_TESTFS=$TESTPOOL/$TESTFS
+export SUBFS=$ROOT_TESTFS/SUBFS
+export SUBFS2=$ROOT_TESTFS/SUBFS2
+
+DATASETS="$ROOT_TESTFS"
+if is_global_zone ; then
+       DATASETS=$DATASETS
+fi
+export DATASETS
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib b/zfs/tests/zfs-tests/tests/functional/delegate/delegate_common.kshlib
new file mode 100644 (file)
index 0000000..796cda9
--- /dev/null
@@ -0,0 +1,1712 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+# Copyright 2016 Nexenta Systems, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/delegate/delegate.cfg
+
+#
+# Cleanup exist user/group.
+#
+function cleanup_user_group
+{
+       typeset i
+       for i in $STAFF1 $STAFF2 $OTHER1 $OTHER2 ; do
+               del_user $i
+       done
+       for i in $STAFF_GROUP $OTHER_GROUP ; do
+               del_group $i
+       done
+
+       return 0
+}
+
+#
+# Restore test file system to the original status.
+#
+function restore_root_datasets
+{
+       if datasetexists $ROOT_TESTFS ; then
+               log_must $ZFS destroy -Rf $ROOT_TESTFS
+       fi
+       log_must $ZFS create $ROOT_TESTFS
+
+       if is_global_zone ; then
+               if datasetexists $ROOT_TESTVOL ; then
+                       log_must $ZFS destroy -Rf $ROOT_TESTVOL
+               fi
+               log_must $ZFS create -V $VOLSIZE $ROOT_TESTVOL
+               block_device_wait
+       fi
+
+       return 0
+}
+
+#
+# Verify the specified user have permission on the dataset
+#
+# $1 dataset
+# $2 permissions which are separated by comma(,)
+# $3-n users
+#
+function verify_perm
+{
+       typeset dtst=$1
+       typeset permissions=$2
+       shift 2
+
+       if [[ -z $@ || -z $permissions || -z $dtst ]]; then
+               return 1
+       fi
+
+       typeset type=$(get_prop type $dtst)
+       permissions=$($ECHO $permissions | $TR -s "," " ")
+
+       typeset user
+       for user in $@; do
+               typeset perm
+               for perm in $permissions; do
+                       typeset -i ret=1
+                       if [[ $type == "filesystem" ]]; then
+                               check_fs_perm $user $perm $dtst
+                               ret=$?
+                       elif [[ $type == "volume" ]]; then
+                               check_vol_perm $user $perm $dtst
+                               ret=$?
+                       fi
+
+                       log_note "Check $type $user $perm $dtst"
+                       if ((ret != 0)) ; then
+                               log_note "Fail: $user should have $perm " \
+                                       "on $dtst"
+                               return 1
+                       fi
+               done
+       done
+
+       return 0
+}
+
+#
+# Verify the specified user have no permission on the dataset
+#
+# $1 dataset
+# $2 permissions which are separated by comma(,)
+# $3-n users
+#
+function verify_noperm
+{
+       typeset dtst=$1
+       typeset permissions=$2
+       shift 2
+
+       if [[ -z $@ || -z $permissions || -z $dtst ]]; then
+               return 1
+       fi
+
+       typeset type=$(get_prop type $dtst)
+       permissions=$($ECHO $permissions | $TR -s "," " ")
+
+       typeset user
+       for user in $@; do
+               typeset perm
+               for perm in $permissions; do
+                       typeset -i ret=1
+                       if [[ $type == "filesystem" ]]; then
+                               check_fs_perm $user $perm $dtst
+                               ret=$?
+                       elif [[ $type == "volume" ]]; then
+                               check_vol_perm $user $perm $dtst
+                               ret=$?
+                       fi
+
+                       if ((ret == 0)) ; then
+                               log_note "Fail: $user should not have $perm " \
+                                       "on $dtst"
+                               return 1
+                       fi
+               done
+       done
+
+       return 0
+}
+
+function common_perm
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset dtst=$3
+
+       typeset -i ret=1
+       case $perm in
+               send)
+                       verify_send $user $perm $dtst
+                       ret=$?
+                       ;;
+               allow)
+                       verify_allow $user $perm $dtst
+                       ret=$?
+                       ;;
+               userprop)
+                       verify_userprop $user $perm $dtst
+                       ret=$?
+                       ;;
+               compression|checksum|readonly)
+                       verify_ccr $user $perm $dtst
+                       ret=$?
+                       ;;
+               copies)
+                       verify_copies $user $perm $dtst
+                       ret=$?
+                       ;;
+               reservation)
+                       verify_reservation $user $perm $dtst
+                       ret=$?
+                       ;;
+               *)
+                       ret=1
+                       ;;
+       esac
+
+       return $ret
+}
+
+function check_fs_perm
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset -i ret=1
+       case $perm in
+               create)
+                       verify_fs_create $user $perm $fs
+                       ret=$?
+                       ;;
+               destroy)
+                       verify_fs_destroy $user $perm $fs
+                       ret=$?
+                       ;;
+               snapshot)
+                       verify_fs_snapshot $user $perm $fs
+                       ret=$?
+                       ;;
+               rollback)
+                       verify_fs_rollback $user $perm $fs
+                       ret=$?
+                       ;;
+               clone)
+                       verify_fs_clone $user $perm $fs
+                       ret=$?
+                       ;;
+               rename)
+                       verify_fs_rename $user $perm $fs
+                       ret=$?
+                       ;;
+               mount)
+                       verify_fs_mount $user $perm $fs
+                       ret=$?
+                       ;;
+               share)
+                       verify_fs_share $user $perm $fs
+                       ret=$?
+                       ;;
+               mountpoint)
+                       verify_fs_mountpoint $user $perm $fs
+                       ret=$?
+                       ;;
+               promote)
+                       verify_fs_promote $user $perm $fs
+                       ret=$?
+                       ;;
+               canmount)
+                       verify_fs_canmount $user $perm $fs
+                       ret=$?
+                       ;;
+               dnodesize)
+                       verify_fs_dnodesize $user $perm $fs
+                       ret=$?
+                       ;;
+               recordsize)
+                       verify_fs_recordsize $user $perm $fs
+                       ret=$?
+                       ;;
+               quota)
+                       verify_fs_quota $user $perm $fs
+                       ret=$?
+                       ;;
+               aclmode)
+                       verify_fs_aclmode $user $perm $fs
+                       ret=$?
+                       ;;
+               aclinherit)
+                       verify_fs_aclinherit $user $perm $fs
+                       ret=$?
+                       ;;
+               snapdir)
+                       verify_fs_snapdir $user $perm $fs
+                       ret=$?
+                       ;;
+               atime|exec|devices|setuid|xattr)
+                       verify_fs_aedsx $user $perm $fs
+                       ret=$?
+                       ;;
+               zoned)
+                       verify_fs_zoned $user $perm $fs
+                       ret=$?
+                       ;;
+               sharenfs)
+                       verify_fs_sharenfs $user $perm $fs
+                       ret=$?
+                       ;;
+               receive)
+                       verify_fs_receive $user $perm $fs
+                       ret=$?
+                       ;;
+               *)
+                       common_perm $user $perm $fs
+                       ret=$?
+                       ;;
+       esac
+
+       return $ret
+}
+
+function check_vol_perm
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset vol=$3
+
+       typeset -i ret=1
+       case $perm in
+               destroy)
+                       verify_vol_destroy $user $perm $vol
+                       ret=$?
+                       ;;
+               snapshot)
+                       verify_vol_snapshot $user $perm $vol
+                       ret=$?
+                       ;;
+               rollback)
+                       verify_vol_rollback $user $perm $vol
+                       ret=$?
+                       ;;
+               clone)
+                       verify_vol_clone $user $perm $vol
+                       ret=$?
+                       ;;
+               rename)
+                       verify_vol_rename $user $perm $vol
+                       ret=$?
+                       ;;
+               promote)
+                       verify_vol_promote $user $perm $vol
+                       ret=$?
+                       ;;
+               volsize)
+                       verify_vol_volsize $user $perm $vol
+                       ret=$?
+                       ;;
+               *)
+                       common_perm $user $perm $vol
+                       ret=$?
+                       ;;
+       esac
+
+       return $ret
+}
+
+function setup_unallow_testenv
+{
+       log_must restore_root_datasets
+
+       log_must $ZFS create $SUBFS
+
+       for dtst in $DATASETS ; do
+               log_must $ZFS allow -l $STAFF1 $LOCAL_SET $dtst
+               log_must $ZFS allow -d $STAFF2 $DESC_SET  $dtst
+               log_must $ZFS allow $OTHER1 $LOCAL_DESC_SET $dtst
+               log_must $ZFS allow $OTHER2 $LOCAL_DESC_SET $dtst
+
+               log_must verify_perm $dtst $LOCAL_SET $STAFF1
+               log_must verify_perm $dtst $LOCAL_DESC_SET $OTHER1
+               log_must verify_perm $dtst $LOCAL_DESC_SET $OTHER2
+               if [[ $dtst == $ROOT_TESTFS ]]; then
+                       log_must verify_perm $SUBFS $DESC_SET $STAFF2
+                       log_must verify_perm $SUBFS $LOCAL_DESC_SET $OTHER1
+                       log_must verify_perm $SUBFS $LOCAL_DESC_SET $OTHER2
+               fi
+       done
+
+       return 0
+}
+
+#
+# Verify permission send for specified user on the dataset
+# $1 user
+# $2 permission
+# $3 dataset
+#
+function verify_send
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset dtst=$3
+
+       typeset oldval
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+       typeset snap=$dtst@snap.$stamp
+
+       typeset -i ret=1
+
+       log_must $ZFS snapshot $snap
+       typeset bak_user=/tmp/bak.$user.$stamp
+       typeset bak_root=/tmp/bak.root.$stamp
+
+       user_run $user eval "$ZFS send $snap > $bak_user"
+       log_must eval "$ZFS send $snap > $bak_root"
+
+       if [[ $(checksum $bak_user) == $(checksum $bak_root) ]]; then
+               ret=0
+       fi
+
+       $RM -rf $bak_user > /dev/null
+       $RM -rf $bak_root > /dev/null
+
+       return $ret
+}
+
+function verify_fs_receive
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset dtst
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+       typeset newfs=$fs/newfs.$stamp
+       typeset newvol=$fs/newvol.$stamp
+       typeset bak_user=/tmp/bak.$user.$stamp
+       typeset bak_root=/tmp/bak.root.$stamp
+
+       log_must $ZFS create $newfs
+       typeset datasets="$newfs"
+       if is_global_zone ; then
+               log_must $ZFS create -V $VOLSIZE $newvol
+               block_device_wait
+               datasets="$newfs $newvol"
+       fi
+
+       for dtst in $datasets ; do
+
+               typeset dtstsnap=$dtst@snap.$stamp
+               log_must $ZFS snapshot $dtstsnap
+
+               log_must eval "$ZFS send $dtstsnap > $bak_root"
+               log_must $ZFS destroy -rf $dtst
+
+               user_run $user eval "$ZFS receive $dtst < $bak_root"
+               if datasetexists $dtstsnap ; then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user create $fs
+               user_run $user eval "$ZFS receive $dtst < $bak_root"
+               log_must $ZFS unallow $user create $fs
+               if datasetexists $dtstsnap ; then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user mount $fs
+               user_run $user eval "$ZFS receive $dtst < $bak_root"
+               log_must $ZFS unallow $user mount $fs
+               if datasetexists $dtstsnap ; then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user mount,create $fs
+               user_run $user eval "$ZFS receive $dtst < $bak_root"
+               log_must $ZFS unallow $user mount,create $fs
+               if ! datasetexists $dtstsnap ; then
+                       return 1
+               fi
+
+               # check the data integrity
+               log_must eval "$ZFS send $dtstsnap > $bak_user"
+               log_must $ZFS destroy -rf $dtst
+               log_must eval "$ZFS receive $dtst < $bak_root"
+               log_must eval "$ZFS send $dtstsnap > $bak_root"
+               log_must $ZFS destroy -rf $dtst
+               if [[ $(checksum $bak_user) != $(checksum $bak_root) ]]; then
+                       return 1
+               fi
+
+               $RM -rf $bak_user > /dev/null
+               $RM -rf $bak_root > /dev/null
+
+       done
+
+       return 0
+}
+
+function verify_userprop
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset dtst=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+
+       user_run $user $ZFS set "$user:ts=$stamp" $dtst
+       if [[ $stamp != $(get_prop "$user:ts" $dtst) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_ccr
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset dtst=$3
+
+       typeset oldval
+
+       set -A modes "on" "off"
+       oldval=$(get_prop $perm $dtst)
+       if [[ $oldval == "on" ]]; then
+               n=1
+       elif [[ $oldval == "off" ]]; then
+               n=0
+       fi
+       log_note "$user $ZFS set $perm=${modes[$n]} $dtst"
+       user_run $user $ZFS set $perm=${modes[$n]} $dtst
+       if [[ ${modes[$n]} != $(get_prop $perm $dtst) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_copies
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset dtst=$3
+
+       typeset oldval
+
+       set -A modes 1 2 3
+       oldval=$(get_prop $perm $dtst)
+       if [[ $oldval -eq 1 ]]; then
+               n=1
+       elif [[ $oldval -eq 2 ]]; then
+               n=2
+       elif [[ $oldval -eq 3 ]]; then
+               n=0
+       fi
+       log_note "$user $ZFS set $perm=${modes[$n]} $dtst"
+       user_run $user $ZFS set $perm=${modes[$n]} $dtst
+       if [[ ${modes[$n]} != $(get_prop $perm $dtst) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_reservation
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset dtst=$3
+
+       typeset value32m=$(( 1024 * 1024 * 32 ))
+       typeset oldval=$(get_prop reservation $dtst)
+       user_run $user $ZFS set reservation=$value32m $dtst
+       if [[ $value32m != $(get_prop reservation $dtst) ]]; then
+               log_must $ZFS set reservation=$oldval $dtst
+               return 1
+       fi
+
+       log_must $ZFS set reservation=$oldval $dtst
+       return 0
+}
+
+function verify_fs_create
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+       typeset newfs=$fs/nfs.$stamp
+       typeset newvol=$fs/nvol.$stamp
+
+       user_run $user $ZFS create $newfs
+       if datasetexists $newfs ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user mount $fs
+       user_run $user $ZFS create $newfs
+       log_must $ZFS unallow $user mount $fs
+       if ! datasetexists $newfs ; then
+               return 1
+       fi
+
+       log_must $ZFS destroy $newfs
+
+       if is_global_zone ; then
+               # mount permission is required for sparse volume
+               user_run $user $ZFS create -V 150m -s $newvol
+               block_device_wait
+               if datasetexists $newvol ; then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user mount $fs
+               user_run $user $ZFS create -V 150m -s $newvol
+               log_must $ZFS unallow $user mount $fs
+               if ! datasetexists $newvol ; then
+                       return 1
+               fi
+
+               block_device_wait
+               log_must $ZFS destroy $newvol
+               block_device_wait
+
+               # mount and reserveration permission are
+               # required for normal volume
+               user_run $user $ZFS create -V 150m $newvol
+               block_device_wait
+               if datasetexists $newvol ; then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user mount $fs
+               user_run $user $ZFS create -V 150m $newvol
+               block_device_wait
+               log_must $ZFS unallow $user mount $fs
+               if datasetexists $newvol ; then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user reservation $fs
+               user_run $user $ZFS create -V 150m $newvol
+               block_device_wait
+               log_must $ZFS unallow $user reservation $fs
+               if datasetexists $newvol ; then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user refreservation $fs
+               user_run $user $ZFS create -V 150m $newvol
+               block_device_wait
+               log_must $ZFS unallow $user refreservation $fs
+               if datasetexists $newvol ; then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user mount $fs
+               log_must $ZFS allow $user reservation $fs
+               log_must $ZFS allow $user refreservation $fs
+               user_run $user $ZFS create -V 150m $newvol
+               log_must $ZFS unallow $user mount $fs
+               log_must $ZFS unallow $user reservation $fs
+               log_must $ZFS unallow $user refreservation $fs
+               if ! datasetexists $newvol ; then
+                       return 1
+               fi
+
+               block_device_wait
+               log_must $ZFS destroy $newvol
+               block_device_wait
+       fi
+
+       return 0
+}
+
+function verify_fs_destroy
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       if ! ismounted $fs ; then
+               user_run $user $ZFS destroy $fs
+               if datasetexists $fs ; then
+                       return 1
+               fi
+       fi
+
+       if ismounted $fs ; then
+               user_run $user $ZFS destroy $fs
+               if ! datasetexists $fs ; then
+                       return 1
+               fi
+
+               # mount permission is required
+               log_must $ZFS allow $user mount $fs
+               user_run $user $ZFS destroy $fs
+               if datasetexists $fs ; then
+                       return 1
+               fi
+       fi
+
+       return 0
+}
+
+# Verify that given the correct delegation, a regular user can:
+#      Take a snapshot of an unmounted dataset
+#      Take a snapshot of an mounted dataset
+#      Create a snapshot by making a directory in the .zfs/snapshot directory
+function verify_fs_snapshot
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+       typeset snap=$fs@snap.$stamp
+       typeset mntpt=$(get_prop mountpoint $fs)
+
+       if [[ "yes" == $(get_prop mounted $fs) ]]; then
+               log_must $ZFS umount $fs
+       fi
+
+       user_run $user $ZFS snapshot $snap
+       if ! datasetexists $snap ; then
+               return 1
+       fi
+       log_must $ZFS destroy $snap
+
+       if [[ "no" == $(get_prop mounted $fs) ]]; then
+               log_must $ZFS mount $fs
+       fi
+
+       user_run $user $ZFS snapshot $snap
+       if ! datasetexists $snap ; then
+               return 1
+       fi
+       log_must $ZFS destroy $snap
+
+       typeset snapdir=${mntpt}/.zfs/snapshot/snap.$stamp
+       user_run $user $MKDIR $snapdir
+       if ! datasetexists $snap ; then
+               return 1
+       fi
+       log_must $ZFS destroy $snap
+
+       return 0
+}
+
+function verify_fs_rollback
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset oldval
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+       typeset snap=$fs@snap.$stamp
+       typeset mntpt=$(get_prop mountpoint $fs)
+
+       oldval=$(datasetcksum $fs)
+       log_must $ZFS snapshot $snap
+
+       if ! ismounted $fs; then
+               log_must $ZFS mount $fs
+       fi
+       log_must $TOUCH $mntpt/testfile.$stamp
+
+       user_run $user $ZFS rollback -R $snap
+       if is_global_zone ; then
+               if [[ $oldval != $(datasetcksum $fs) ]]; then
+                       return 1
+               fi
+       else
+               # datasetcksum can not be used in local zone
+               if [[ -e $mntpt/testfile.$stamp ]]; then
+                       return 1
+               fi
+       fi
+
+       return 0
+}
+
+function verify_fs_clone
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+        typeset basefs=${fs%/*}
+       typeset snap=$fs@snap.$stamp
+       typeset clone=$basefs/cfs.$stamp
+
+       log_must $ZFS snapshot $snap
+       user_run $user $ZFS clone $snap $clone
+       if datasetexists $clone ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user create $basefs
+       user_run $user $ZFS clone $snap $clone
+       log_must $ZFS unallow $user create $basefs
+       if datasetexists $clone ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user mount $basefs
+       user_run $user $ZFS clone $snap $clone
+       log_must $ZFS unallow $user mount $basefs
+       if datasetexists $clone ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user mount $basefs
+       log_must $ZFS allow $user create $basefs
+       user_run $user $ZFS clone $snap $clone
+       log_must $ZFS unallow $user create $basefs
+       log_must $ZFS unallow $user mount $basefs
+       if ! datasetexists $clone ; then
+               return 1
+       fi
+
+       log_must $ZFS destroy -R $snap
+
+       return 0
+}
+
+function verify_fs_rename
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+        typeset basefs=${fs%/*}
+       typeset snap=$fs@snap.$stamp
+       typeset renamefs=$basefs/nfs.$stamp
+
+       if ! ismounted $fs; then
+               log_must $ZFS mount $fs
+       fi
+
+       # case 1
+       user_run $user $ZFS rename $fs $renamefs
+       if datasetexists $renamefs ; then
+               return 1
+       fi
+
+       # case 2
+       log_must $ZFS allow $user create $basefs
+       user_run $user $ZFS rename $fs $renamefs
+       log_must $ZFS unallow $user create $basefs
+       if datasetexists $renamefs ; then
+               return 1
+       fi
+
+       # case 3
+       log_must $ZFS allow $user mount $basefs
+       user_run $user $ZFS rename $fs $renamefs
+       log_must $ZFS unallow $user mount $basefs
+       if datasetexists $renamefs ; then
+               return 1
+       fi
+
+       # case 4
+       log_must $ZFS allow $user mount $fs
+       user_run $user $ZFS rename $fs $renamefs
+       if datasetexists $renamefs ; then
+               log_must $ZFS unallow $user mount $renamefs
+               return 1
+       fi
+       log_must $ZFS unallow $user mount $fs
+
+       # case 5
+       log_must $ZFS allow $user create $basefs
+       log_must $ZFS allow $user mount $fs
+       user_run $user $ZFS rename $fs $renamefs
+       log_must $ZFS unallow $user create $basefs
+       if datasetexists $renamefs ; then
+               log_must $ZFS unallow $user mount $renamefs
+               return 1
+       fi
+       log_must $ZFS unallow $user mount $fs
+
+       # case 6
+       log_must $ZFS allow $user mount $basefs
+       log_must $ZFS allow $user mount $fs
+       user_run $user $ZFS rename $fs $renamefs
+       log_must $ZFS unallow $user mount $basefs
+       if datasetexists $renamefs ; then
+               log_must $ZFS unallow $user mount $renamefs
+               return 1
+       fi
+       log_must $ZFS unallow $user mount $fs
+
+       # case 7
+       log_must $ZFS allow $user create $basefs
+       log_must $ZFS allow $user mount $basefs
+       user_run $user $ZFS rename $fs $renamefs
+       log_must $ZFS unallow $user mount $basefs
+       log_must $ZFS unallow $user create $basefs
+       if ! datasetexists $renamefs ; then
+               return 1
+       fi
+
+       log_must $ZFS rename $renamefs $fs
+
+       return 0
+}
+
+function verify_fs_mount
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+       typeset mntpt=$(get_prop mountpoint $fs)
+       typeset newmntpt=/tmp/mnt.$stamp
+
+       if ismounted $fs ; then
+               user_run $user $ZFS unmount $fs
+               if ismounted $fs ; then
+                       return 1
+               fi
+       fi
+
+       if ! ismounted $fs ; then
+               log_must $ZFS set mountpoint=$newmntpt $fs
+               log_must $RM -rf $newmntpt
+               log_must $MKDIR $newmntpt
+
+               user_run $user $ZFS mount $fs
+               if ismounted $fs ; then
+                       return 1
+               fi
+
+               # mountpoint's owner must be the user
+               log_must $CHOWN $user $newmntpt
+               user_run $user $ZFS mount $fs
+               if ! ismounted $fs ; then
+                       return 1
+               fi
+               log_must $ZFS umount $fs
+               log_must $RM -rf $newmntpt
+               log_must $ZFS set mountpoint=$mntpt $fs
+       fi
+
+       return 0
+}
+
+function verify_fs_share
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+       typeset -i ret=0
+
+       $SVCADM enable -rs nfs/server
+       typeset stat=$($SVCS -H -o STA nfs/server:default)
+       if [[ $stat != "ON" ]]; then
+               log_fail "Could not enable nfs/server"
+       fi
+
+       log_must $ZFS set sharenfs=on $fs
+       $ZFS unshare $fs
+
+       user_run $user $ZFS share $fs
+       if ! is_shared $fs; then
+               ret=1
+       fi
+
+       $ZFS unshare $fs
+       log_must $ZFS set sharenfs=off $fs
+
+       return $ret
+}
+
+function verify_fs_mountpoint
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+       typeset mntpt=$(get_prop mountpoint $fs)
+       typeset newmntpt=/tmp/mnt.$stamp
+
+       if ! ismounted $fs ; then
+               user_run $user $ZFS set mountpoint=$newmntpt $fs
+               if [[ $newmntpt != \
+                       $(get_prop mountpoint $fs) ]] ; then
+                       return 1
+               fi
+               log_must $ZFS set mountpoint=$mntpt $fs
+       fi
+
+       if ismounted $fs ; then
+               user_run $user $ZFS set mountpoint=$newmntpt $fs
+               if [[ $mntpt != $(get_prop mountpoint $fs) ]]; then
+                       return 1
+               fi
+
+               # require mount permission when fs is mounted
+               log_must $ZFS allow $user mount $fs
+               user_run $user $ZFS set mountpoint=$newmntpt $fs
+               log_must $ZFS unallow $user mount $fs
+               if [[ $newmntpt != \
+                       $(get_prop mountpoint $fs) ]] ; then
+                       return 1
+               fi
+               log_must $ZFS set mountpoint=$mntpt $fs
+       fi
+
+       return 0
+}
+
+function verify_fs_promote
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+        typeset basefs=${fs%/*}
+       typeset snap=$fs@snap.$stamp
+       typeset clone=$basefs/cfs.$stamp
+
+       log_must $ZFS snapshot $snap
+       log_must $ZFS clone $snap $clone
+       log_must $ZFS promote $clone
+
+       typeset fs_orig=$(get_prop origin $fs)
+       typeset clone_orig=$(get_prop origin $clone)
+
+       user_run $user $ZFS promote $fs
+       # promote should fail if original fs does not have
+       # promote permission
+       if [[ $fs_orig != $(get_prop origin $fs) || \
+               $clone_orig != $(get_prop origin $clone) ]]; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user promote $clone
+       user_run $user $ZFS promote $fs
+       log_must $ZFS unallow $user promote $clone
+       if [[ $fs_orig != $(get_prop origin $fs) || \
+               $clone_orig != $(get_prop origin $clone) ]]; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user mount $fs
+       user_run $user $ZFS promote $fs
+       log_must $ZFS unallow $user mount $fs
+       if [[ $fs_orig != $(get_prop origin $fs) || \
+               $clone_orig != $(get_prop origin $clone) ]]; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user mount $fs
+       log_must $ZFS allow $user promote $clone
+       user_run $user $ZFS promote $fs
+       log_must $ZFS unallow $user promote $clone
+       log_must $ZFS unallow $user mount $fs
+       if [[ $snap != $(get_prop origin $clone) || \
+               $clone_orig != $(get_prop origin $fs) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_fs_canmount
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset oldval
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+
+       if ! ismounted $fs ; then
+               set -A modes "on" "off"
+               oldval=$(get_prop $perm $fs)
+               if [[ $oldval == "on" ]]; then
+                       n=1
+               elif [[ $oldval == "off" ]]; then
+                       n=0
+               fi
+               log_note "$user $ZFS set $perm=${modes[$n]} $fs"
+               user_run $user $ZFS set $perm=${modes[$n]} $fs
+               if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
+                       return 1
+               fi
+       fi
+
+
+       # fs is mounted
+       if ismounted $fs ; then
+               # property value does not change if
+               # no mount permission
+               set -A modes "on" "off"
+               oldval=$(get_prop $perm $fs)
+               if [[ $oldval == "on" ]]; then
+                       n=1
+               elif [[ $oldval == "off" ]]; then
+                       n=0
+               fi
+               log_note "$user $ZFS set $perm=${modes[$n]} $fs"
+               log_must $ZFS allow $user mount $fs
+               user_run $user $ZFS set $perm=${modes[$n]} $fs
+               log_must $ZFS unallow $user mount $fs
+               if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
+                       return 1
+               fi
+       fi
+
+       return 0
+}
+
+function verify_fs_recordsize
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset value8k=$(( 1024 * 8 ))
+       user_run $user $ZFS set recordsize=$value8k $fs
+       if [[ $value8k != $(get_prop recordsize $fs) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_fs_dnodesize
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+       value="2k"
+
+       user_run $user $ZFS set dnodesize=$value $fs
+       if [[ $value != $(get_prop dnodesize $fs) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_fs_quota
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset value32m=$(( 1024 * 1024 * 32 ))
+       user_run $user $ZFS set quota=$value32m $fs
+       if [[ $value32m != $(get_prop quota $fs) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_fs_aclmode
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset oldval
+       set -A modes "discard" "groupmask" "passthrough"
+       oldval=$(get_prop $perm $fs)
+       if [[ $oldval == "discard" ]]; then
+               n=1
+       elif [[ $oldval == "groupmask" ]]; then
+               n=2
+       elif [[ $oldval == "passthrough" ]]; then
+               n=0
+       fi
+       log_note "$user $ZFS set aclmode=${modes[$n]} $fs"
+       user_run $user $ZFS set aclmode=${modes[$n]} $fs
+       if [[ ${modes[$n]} != $(get_prop aclmode $fs) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_fs_aclinherit
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       #
+       # PSARC/2008/231 change the default value of aclinherit to "restricted"
+       # but still keep the old interface of "secure"
+       #
+
+       typeset oldval
+       set -A modes "discard" "noallow" "secure" "passthrough"
+       oldval=$(get_prop $perm $fs)
+       if [[ $oldval == "discard" ]]; then
+               n=1
+       elif [[ $oldval == "noallow" ]]; then
+               n=2
+       elif [[ $oldval == "secure" || $oldval == "restricted" ]]; then
+               n=3
+       elif [[ $oldval == "passthrough" ]]; then
+               n=0
+       fi
+       log_note "$user $ZFS set aclinherit=${modes[$n]} $fs"
+       user_run $user $ZFS set aclinherit=${modes[$n]} $fs
+
+       typeset newval=$(get_prop aclinherit $fs)
+       if [[ ${modes[$n]} == "secure" && $newval == "restricted" ]]; then
+               return 0
+       elif [[ ${modes[$n]} != $(get_prop aclinherit $fs) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_fs_snapdir
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset oldval
+       set -A modes "visible" "hidden"
+       oldval=$(get_prop $perm $fs)
+       if [[ $oldval == "visible" ]]; then
+               n=1
+       elif [[ $oldval == "hidden" ]]; then
+               n=0
+       fi
+       log_note "$user $ZFS set snapdir=${modes[$n]} $fs"
+       user_run $user $ZFS set snapdir=${modes[$n]} $fs
+       if [[ ${modes[$n]} != $(get_prop snapdir $fs) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_fs_aedsx
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset oldval
+       set -A modes "on" "off"
+       oldval=$(get_prop $perm $fs)
+       if [[ $oldval == "on" ]]; then
+               n=1
+       elif [[ $oldval == "off" ]]; then
+               n=0
+       fi
+       log_note "$user $ZFS set $perm=${modes[$n]} $fs"
+       user_run $user $ZFS set $perm=${modes[$n]} $fs
+       if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_fs_zoned
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+
+       typeset oldval
+       set -A modes "on" "off"
+       oldval=$(get_prop $perm $fs)
+       if [[ $oldval == "on" ]]; then
+               n=1
+       elif [[ $oldval == "off" ]]; then
+               n=0
+       fi
+       log_note "$user $ZFS set $perm=${modes[$n]} $fs"
+       if is_global_zone ; then
+               if ! ismounted $fs ; then
+                       user_run $user $ZFS set \
+                               $perm=${modes[$n]} $fs
+                       if [[ ${modes[$n]} != \
+                               $(get_prop $perm $fs) ]]; then
+                               return 1
+                       fi
+                       if [[ $n -eq 0 ]]; then
+                               log_mustnot $ZFS mount $fs
+                       else
+                               log_must $ZFS mount $fs
+                       fi
+               fi
+
+               if ismounted $fs; then
+                       # n always is 1 in this case
+                       user_run $user $ZFS set \
+                               $perm=${modes[$n]} $fs
+                       if [[ $oldval != \
+                               $(get_prop $perm $fs) ]]; then
+                               return 1
+                       fi
+
+                       # mount permission is needed
+                       # to make zoned=on
+                       log_must $ZFS allow $user mount $fs
+                       user_run $user $ZFS set \
+                               $perm=${modes[$n]} $fs
+                       log_must $ZFS unallow $user mount $fs
+                       if [[ ${modes[$n]} != \
+                               $(get_prop $perm $fs) ]]; then
+                               return 1
+                       fi
+               fi
+       fi
+
+       if ! is_global_zone; then
+               user_run $user $ZFS set $perm=${modes[$n]} $fs
+               if [[ $oldval != $(get_prop $perm $fs) ]]; then
+                       return 1
+               fi
+       fi
+
+       return 0
+}
+
+function verify_fs_sharenfs
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset fs=$3
+       typeset nmode omode
+
+       omode=$(get_prop $perm $fs)
+       if [[ $omode == "off" ]]; then
+               nmode="on"
+       else
+               nmode="off"
+       fi
+
+       log_note "$user $ZFS set $perm=$nmode $fs"
+       user_run $user $ZFS set $perm=$nmode $fs
+       if [[ $(get_prop $perm $fs) != $nmode ]]; then
+               return 1
+       fi
+
+       log_note "$user $ZFS set $perm=$omode $fs"
+       user_run $user $ZFS set $perm=$omode $fs
+       if [[ $(get_prop $perm $fs) != $omode ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_vol_destroy
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset vol=$3
+
+       user_run $user $ZFS destroy $vol
+       if ! datasetexists $vol ; then
+               return 1
+       fi
+
+       # mount permission is required
+       log_must $ZFS allow $user mount $vol
+       user_run $user $ZFS destroy $vol
+       if datasetexists $vol ; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_vol_snapshot
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset vol=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+        typeset basevol=${vol%/*}
+       typeset snap=$vol@snap.$stamp
+
+       user_run $user $ZFS snapshot $snap
+       if datasetexists $snap ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user mount $vol
+       user_run $user $ZFS snapshot $snap
+       log_must $ZFS unallow $user mount $vol
+       if ! datasetexists $snap ; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_vol_rollback
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset vol=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+        typeset basevol=${vol%/*}
+       typeset snap=$vol@snap.$stamp
+
+       typeset oldval
+       log_must $ZFS snapshot $snap
+       oldval=$(datasetcksum $vol)
+
+       log_must $DD if=/dev/urandom of=$ZVOL_RDEVDIR/$vol \
+               bs=512 count=1
+
+       user_run $user $ZFS rollback -R $snap
+       $SLEEP 10
+       if [[ $oldval == $(datasetcksum $vol) ]]; then
+               return 1
+       fi
+
+       # rollback on volume has to be with mount permission
+       log_must $ZFS allow $user mount $vol
+       user_run $user $ZFS rollback -R $snap
+       $SLEEP 10
+       log_must $ZFS unallow $user mount $vol
+       if [[ $oldval != $(datasetcksum $vol) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_vol_clone
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset vol=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+        typeset basevol=${vol%/*}
+       typeset snap=$vol@snap.$stamp
+       typeset clone=$basevol/cvol.$stamp
+
+       log_must $ZFS snapshot $snap
+
+       user_run $user $ZFS clone $snap $clone
+       if datasetexists $clone ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user create $basevol
+       user_run $user $ZFS clone $snap $clone
+       log_must $ZFS unallow $user create $basevol
+       if datasetexists $clone ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user mount $basevol
+       user_run $user $ZFS clone $snap $clone
+       log_must $ZFS unallow $user mount $basevol
+       if datasetexists $clone ; then
+               return 1
+       fi
+
+       # require create permission on parent and
+       # mount permission on itself as well
+       log_must $ZFS allow $user mount $basevol
+       log_must $ZFS allow $user create $basevol
+       user_run $user $ZFS clone $snap $clone
+       log_must $ZFS unallow $user create $basevol
+       log_must $ZFS unallow $user mount $basevol
+       if ! datasetexists $clone ; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_vol_rename
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset vol=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+        typeset basevol=${vol%/*}
+       typeset snap=$vol@snap.$stamp
+       typeset clone=$basevol/cvol.$stamp
+       typeset renamevol=$basevol/nvol.$stamp
+
+       user_run $user $ZFS rename $vol $renamevol
+       if datasetexists $renamevol ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user create $basevol
+       user_run $user $ZFS rename $vol $renamevol
+       log_must $ZFS unallow $user create $basevol
+       if datasetexists $renamevol ; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user mount $basevol
+       user_run $user $ZFS rename $vol $renamevol
+       log_must $ZFS unallow $user mount $basevol
+       if datasetexists $renamevol ; then
+               return 1
+       fi
+
+       # require both create permission on parent and
+       # mount permission on parent as well
+       log_must $ZFS allow $user mount $basevol
+       log_must $ZFS allow $user create $basevol
+       user_run $user $ZFS rename $vol $renamevol
+       log_must $ZFS unallow $user mount $basevol
+       log_must $ZFS unallow $user create $basevol
+       if ! datasetexists $renamevol ; then
+               return 1
+       fi
+
+       log_must $ZFS rename $renamevol $vol
+
+       return 0
+}
+
+function verify_vol_promote
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset vol=$3
+
+       typeset stamp=${perm}.${user}.$($DATE +'%F-%T-%N')
+        typeset basevol=${vol%/*}
+       typeset snap=$vol@snap.$stamp
+       typeset clone=$basevol/cvol.$stamp
+
+       log_must $ZFS snapshot $snap
+       log_must $ZFS clone $snap $clone
+       log_must $ZFS promote $clone
+
+       typeset vol_orig=$(get_prop origin $vol)
+       typeset clone_orig=$(get_prop origin $clone)
+
+       # promote should fail if $vol and $clone
+       # miss either mount or promote permission
+       # case 1
+       user_run $user $ZFS promote $vol
+       if [[ $vol_orig != $(get_prop origin $vol) || \
+               $clone_orig != $(get_prop origin $clone) ]];
+       then
+               return 1
+       fi
+
+       # promote should fail if $vol and $clone
+       # miss either mount or promote permission
+       # case 2
+       log_must $ZFS allow $user promote $clone
+       user_run $user $ZFS promote $vol
+       log_must $ZFS unallow $user promote $clone
+       if [[ $vol_orig != $(get_prop origin $vol) || \
+               $clone_orig != $(get_prop origin $clone) ]];
+       then
+               return 1
+       fi
+
+       # promote should fail if $vol and $clone
+       # miss either mount or promote permission
+       # case 3
+       log_must $ZFS allow $user mount $vol
+       user_run $user $ZFS promote $vol
+       log_must $ZFS unallow $user mount $vol
+       if [[ $vol_orig != $(get_prop origin $vol) || \
+               $clone_orig != $(get_prop origin $clone) ]];
+       then
+               return 1
+       fi
+
+       # promote should fail if $vol and $clone
+       # miss either mount or promote permission
+       # case 4
+       log_must $ZFS allow $user mount $clone
+       user_run $user $ZFS promote $vol
+       log_must $ZFS unallow $user mount $clone
+       if [[ $vol_orig != $(get_prop origin $vol) || \
+               $clone_orig != $(get_prop origin $clone) ]];
+       then
+               return 1
+       fi
+
+       # promote should fail if $vol and $clone
+       # miss either mount or promote permission
+       # case 5
+       log_must $ZFS allow $user promote $clone
+       log_must $ZFS allow $user mount $vol
+       user_run $user $ZFS promote $vol
+       log_must $ZFS unallow $user promote $clone
+       log_must $ZFS unallow $user mount $vol
+       if [[ $vol_orig != $(get_prop origin $vol) || \
+               $clone_orig != $(get_prop origin $clone) ]];
+       then
+               return 1
+       fi
+
+       # promote should fail if $vol and $clone
+       # miss either mount or promote permission
+       # case 6
+       log_must $ZFS allow $user promote $clone
+       log_must $ZFS allow $user mount $clone
+       user_run $user $ZFS promote $vol
+       log_must $ZFS unallow $user promote $clone
+       log_must $ZFS unallow $user mount $vol
+       if [[ $vol_orig != $(get_prop origin $vol) || \
+               $clone_orig != $(get_prop origin $clone) ]];
+       then
+               return 1
+       fi
+
+       # promote should fail if $vol and $clone
+       # miss either mount or promote permission
+       # case 7
+       log_must $ZFS allow $user mount $vol
+       log_must $ZFS allow $user mount $clone
+       user_run $user $ZFS promote $vol
+       log_must $ZFS unallow $user mount $vol
+       log_must $ZFS unallow $user mount $clone
+       if [[ $vol_orig != $(get_prop origin $vol) || \
+               $clone_orig != $(get_prop origin $clone) ]];
+       then
+               return 1
+       fi
+
+       # promote only succeeds when $vol and $clone
+       # have both mount and promote permission
+       # case 8
+       log_must $ZFS allow $user promote $clone
+       log_must $ZFS allow $user mount $vol
+       log_must $ZFS allow $user mount $clone
+       user_run $user $ZFS promote $vol
+       log_must $ZFS unallow $user promote $clone
+       log_must $ZFS unallow $user mount $vol
+       log_must $ZFS unallow $user mount $clone
+       if [[ $snap != $(get_prop origin $clone) || \
+               $clone_orig != $(get_prop origin $vol) ]]; then
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_vol_volsize
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset vol=$3
+
+       typeset oldval
+       oldval=$(get_prop volsize $vol)
+       (( newval = oldval * 2 ))
+
+       reserv_size=$(get_prop refreservation $vol)
+
+       if [[ "0" == $reserv_size ]]; then
+               # sparse volume
+               user_run $user $ZFS set volsize=$newval $vol
+               if [[ $oldval == $(get_prop volsize $vol) ]];
+               then
+                       return 1
+               fi
+
+       else
+               # normal volume, reservation permission
+               # is required
+               user_run $user $ZFS set volsize=$newval $vol
+               if [[ $newval == $(get_prop volsize $vol) ]];
+               then
+                       return 1
+               fi
+
+               log_must $ZFS allow $user reservation $vol
+               log_must $ZFS allow $user refreservation $vol
+               user_run $user $ZFS set volsize=$newval $vol
+               log_must $ZFS unallow $user reservation $vol
+               log_must $ZFS unallow $user refreservation $vol
+               if [[ $oldval == $(get_prop volsize $vol) ]];
+               then
+                       return 1
+               fi
+       fi
+
+       return 0
+}
+
+function verify_allow
+{
+       typeset user=$1
+       typeset perm=$2
+       typeset dtst=$3
+
+       typeset -i ret
+
+       user_run $user $ZFS allow $user allow $dtst
+       ret=$?
+       if [[ $ret -eq 0 ]]; then
+               return 1
+       fi
+
+       log_must $ZFS allow $user copies $dtst
+       user_run $user $ZFS allow $user copies $dtst
+       ret=$?
+       log_must $ZFS unallow $user copies $dtst
+       if [[ $ret -eq 1 ]]; then
+               return 1
+       fi
+
+       return 0
+
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/setup.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/setup.ksh
new file mode 100755 (executable)
index 0000000..6533f27
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+if ! is_linux; then
+       # check svc:/network/nis/client:default state
+       # disable it if the state is ON
+       # and the state will be restored during cleanup.ksh
+       log_must $RM -f $NISSTAFILE
+       if [[ "ON" == $($SVCS -H -o sta svc:/network/nis/client:default) ]]; then
+               log_must $SVCADM disable -t svc:/network/nis/client:default
+               log_must $TOUCH $NISSTAFILE
+       fi
+fi
+
+cleanup_user_group
+
+# Create staff group and add two user to it
+log_must add_group $STAFF_GROUP
+log_must add_user $STAFF_GROUP $STAFF1
+log_must add_user $STAFF_GROUP $STAFF2
+
+# Create other group and add two user to it
+log_must add_group $OTHER_GROUP
+log_must add_user $OTHER_GROUP $OTHER1
+log_must add_user $OTHER_GROUP $OTHER2
+
+DISK=${DISKS%% *}
+default_volume_setup $DISK
+log_must $CHMOD 777 $TESTDIR
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_001_pos.ksh
new file mode 100755 (executable)
index 0000000..14a3bc1
--- /dev/null
@@ -0,0 +1,98 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      "everyone" is interpreted as the keyword "everyone" whatever the same
+#      name user or group is existing.
+#
+# STRATEGY:
+#      1. Create user 'everyone'.
+#      2. Verify 'everyone' is interpreted as keywords.
+#      3. Create group 'everyone'.
+#      4. Verify 'everyone' is interpreted as keywords.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if [[ $user_added == "TRUE" ]] ; then
+               del_user everyone
+       fi
+       if [[ $group_added == "TRUE" ]] ; then
+               del_group everyone
+       fi
+
+       restore_root_datasets
+}
+
+log_assert "everyone' is interpreted as a keyword even if a user " \
+       "or group named 'everyone' exists."
+log_onexit cleanup
+
+eval set -A dataset $DATASETS
+typeset perms="snapshot,reservation,compression,checksum,send,userprop"
+
+log_note "Create a user called 'everyone'."
+if ! $ID everyone > /dev/null 2>&1; then
+       user_added="TRUE"
+       log_must add_user $STAFF_GROUP everyone
+fi
+for dtst in $DATASETS ; do
+       log_must $ZFS allow everyone $perms $dtst
+       log_must verify_perm $dtst $perms $EVERYONE "everyone"
+done
+log_must restore_root_datasets
+if [[ $user_added == "TRUE" ]]; then
+       log_must del_user everyone
+fi
+
+log_note "Created a group called 'everyone'."
+if ! $CAT /etc/group | $AWK -F: '{print $1}' | \
+       $GREP -w 'everyone' > /dev/null 2>&1
+then
+       group_added="TRUE"
+       log_must $GROUPADD everyone
+fi
+
+for dtst in $DATASETS ; do
+       log_must $ZFS allow everyone $perms $dtst
+       log_must verify_perm $dtst $perms $EVERYONE
+done
+log_must restore_root_datasets
+if [[ $group_added == "TRUE" ]]; then
+       log_must $GROUPDEL everyone
+fi
+
+log_pass "everyone is always interpreted as keyword passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_002_pos.ksh
new file mode 100755 (executable)
index 0000000..e11051a
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+# <user|group> argument is interpreted as a user if possible, then as a group as
+# possible.
+#
+# STRATEGY:
+#      1. Create user $STAFF_GROUP
+#      2. Delegate permissions to $STAFF_GROUP
+#      3. Verify user $STAFF_GROUP has the permissions.
+#      4. Delete user $STAFF_GROUP and allow the permission to $STAFF_GROUP
+#      5. Verify $STAFF_GROUP is interpreted as group.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if $ID $STAFF_GROUP > /dev/null 2>&1; then
+               log_must del_user $STAFF_GROUP
+       fi
+
+       restore_root_datasets
+}
+
+log_assert "<user|group> is interpreted as user if possible, then as group."
+log_onexit cleanup
+
+eval set -A dataset $DATASETS
+typeset perms="snapshot,reservation,compression,checksum,send,userprop"
+
+log_must add_user $STAFF_GROUP $STAFF_GROUP
+for dtst in $DATASETS ; do
+       log_must $ZFS allow $STAFF_GROUP $perms $dtst
+       log_must verify_perm $dtst $perms $STAFF_GROUP
+       log_must verify_noperm $dtst $perms $STAFF1 $STAFF2
+done
+
+log_must restore_root_datasets
+
+log_must del_user $STAFF_GROUP
+for dtst in $datasets ; do
+       log_must $ZFS allow $STAFF_GROUP $perms $dtst
+       log_must verify_perm $dtst $perms $STAFF1 $STAFF2
+done
+
+log_pass "<user|group> is interpreted as user if possible, then as group passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_003_pos.ksh
new file mode 100755 (executable)
index 0000000..21cf4a0
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify option '-l' only allow permission to the dataset itself.
+#
+# STRATEGY:
+#      1. Create descendent datasets of $ROOT_TESTFS
+#      2. Select user, group and everyone and set local permission separately.
+#      3. Set locally permissions to $ROOT_TESTFS or $ROOT_TESTVOL.
+#      4. Verify the permissions are only allow on $ROOT_TESTFS or
+#         $ROOT_TESTVOL.
+#
+
+verify_runnable "both"
+
+log_assert "Verify option '-l' only allow permission to the dataset itself."
+log_onexit restore_root_datasets
+
+childfs=$ROOT_TESTFS/childfs
+
+eval set -A dataset $DATASETS
+typeset perms="snapshot,reservation,compression,checksum,userprop"
+
+log_must $ZFS create $childfs
+
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -l $STAFF1 $perms $dtst
+       log_must verify_perm $dtst $perms $STAFF1
+       if [[ $dtst == $ROOT_TESTFS ]] ; then
+               log_must verify_noperm $childfs $perms \
+                       $STAFF1 $STAFF2 $OTHER1 $OTHER2
+       fi
+done
+
+log_must restore_root_datasets
+
+log_must $ZFS create $childfs
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -l -g $STAFF_GROUP $perms $dtst
+       log_must verify_perm $dtst $perms $STAFF1 $STAFF2
+       if [[ $dtst == $ROOT_TESTFS ]] ; then
+               log_must verify_noperm $childfs $perms \
+                       $STAFF1 $STAFF2 $OTHER1 $OTHER2
+       fi
+done
+
+log_must restore_root_datasets
+
+log_must $ZFS create $childfs
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -l -e $perms $dtst
+       log_must verify_perm $dtst $perms $STAFF1 $STAFF2 $OTHER1 $OTHER2
+       if [[ $dtst == $ROOT_TESTFS ]] ; then
+               log_must verify_noperm $childfs $perms \
+                       $STAFF1 $STAFF2 $OTHER1 $OTHER2
+       fi
+done
+
+log_must restore_root_datasets
+
+log_pass "Verify option '-l' only allow permission to the dataset itself pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_004_pos.ksh
new file mode 100755 (executable)
index 0000000..c1cdb3c
--- /dev/null
@@ -0,0 +1,96 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify option '-d' allow permission to the descendent datasets, and not
+#      for this dataset itself.
+#
+# STRATEGY:
+#      1. Create descendent datasets of $ROOT_TESTFS
+#      2. Select user, group and everyone and set descendent permission
+#         separately.
+#      3. Set descendent permissions to $ROOT_TESTFS or $ROOT_TESTVOL.
+#      4. Verify those permissions are allowed to $ROOT_TESTFS's
+#         descendent dataset.
+#      5. Verify the permissions are not allowed to $ROOT_TESTFS or
+#         $ROOT_TESTVOL.
+#
+
+verify_runnable "both"
+
+log_assert "Verify option '-d' allow permission to the descendent datasets."
+log_onexit restore_root_datasets
+
+childfs=$ROOT_TESTFS/childfs
+
+eval set -A dataset $DATASETS
+typeset perms="snapshot,reservation,compression,checksum,userprop"
+
+# Verify option '-d' only affect sub-datasets
+log_must $ZFS create $childfs
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -d $STAFF1 $perms $dtst
+       log_must verify_noperm $dtst $perms $STAFF1
+       if [[ $dtst == $ROOT_TESTFS ]]; then
+               log_must verify_perm $childfs $perms $STAFF1
+       fi
+done
+
+log_must restore_root_datasets
+
+# Verify option '-d + -g' affect group in sub-datasets.
+log_must $ZFS create $childfs
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -d -g $STAFF_GROUP $perms $dtst
+       log_must verify_noperm $dtst $perms $STAFF2
+       if [[ $dtst == $ROOT_TESTFS ]]; then
+               log_must verify_perm $childfs $perms $STAFF2
+       fi
+done
+
+log_must restore_root_datasets
+
+# Verify option '-d + -e' affect everyone in sub-datasets.
+log_must $ZFS create $childfs
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -d -e $perms $dtst
+       log_must verify_noperm $dtst $perms $OTHER1 $OTHER2
+       if [[ $dtst == $ROOT_TESTFS ]]; then
+               log_must verify_perm $childfs $perms $OTHER1 $OTHER2
+       fi
+done
+
+log_must restore_root_datasets
+
+log_pass "Verify option '-d' allow permission to the descendent datasets pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_005_pos.ksh
new file mode 100755 (executable)
index 0000000..9342643
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify option '-c' will be granted locally to the creator on any
+#      newly-created descendent file systems.
+#
+# STRATEGY:
+#      1. Allow create permissions to everyone on $ROOT_TESTFS locally.
+#      2. Allow '-c' create to $ROOT_TESTFS.
+#      3. chmod 777 the mountpoint of $ROOT_TESTFS
+#      4. Verify only creator can create descendent dataset on
+#         $ROOT_TESTFS/$user.
+#
+
+verify_runnable "both"
+
+log_assert "Verify option '-c' will be granted locally to the creator."
+log_onexit restore_root_datasets
+
+eval set -A dataset $DATASETS
+typeset perms="snapshot,reservation,compression,checksum,userprop"
+
+log_must $ZFS allow -l everyone create,mount $ROOT_TESTFS
+log_must $ZFS allow -c $perms $ROOT_TESTFS
+
+mntpnt=$(get_prop mountpoint $ROOT_TESTFS)
+log_must $CHMOD 777 $mntpnt
+
+for user in $EVERYONE; do
+       childfs=$ROOT_TESTFS/$user
+
+       user_run $user $ZFS create $childfs
+
+       for other in $EVERYONE; do
+               #
+               # Verify only the creator has the $perm time permissions.
+               #
+               if [[ $other == $user ]]; then
+                       log_must verify_perm $childfs $perms $user
+               else
+                       log_must verify_noperm $childfs $perms $other
+               fi
+       done
+done
+
+log_pass "Verify option '-c' will be granted locally to the creator passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_006_pos.ksh
new file mode 100755 (executable)
index 0000000..e8cdf25
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Changing permissions in a set will change what is allowed wherever the
+#      set is used.
+#
+# STRATEGY:
+#      1. Set create as set @basic.
+#      2. Allow set @basic to $STAFF1 on $ROOT_TESTFS or $ROOT_TESTVOL
+#      3. Verify $STAFF1 has create permissions.
+#      4. Reset snapshot,allow to $basic
+#      5. Verify now $STAFF1 have create,allow,destroy permissions.
+#
+
+verify_runnable "both"
+
+log_assert "Changing permissions in a set will change what is allowed " \
+       "wherever the set is used."
+log_onexit restore_root_datasets
+
+fs1=$ROOT_TESTFS/fs1; fs2=$ROOT_TESTFS/fs2
+log_must $ZFS create $fs1
+log_must $ZFS create $fs2
+
+eval set -A dataset $DATASETS
+perms1="snapshot,checksum,reservation"
+
+for dtst in $DATASETS $fs1 $fs2; do
+       log_must $ZFS allow -s @basic $perms1 $dtst
+       log_must $ZFS allow $STAFF1 @basic $dtst
+       log_must verify_perm $dtst $perms1 $STAFF1
+done
+
+perms2="send,compression,userprop"
+for dtst in $DATASETS $fs1 $fs2; do
+       log_must $ZFS allow -s @basic $perms2 $dtst
+       log_must verify_perm $dtst ${perms1},${perms2} $STAFF1
+done
+
+log_pass "Changing permissions in a set will change what is allowed passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_007_pos.ksh
new file mode 100755 (executable)
index 0000000..5305deb
--- /dev/null
@@ -0,0 +1,103 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify the permissions set will be masked on its descendent
+#      datasets by same name set.
+#
+# STRATEGY:
+#      1. Create $ROOT_TESTFS/childfs
+#      2. Set permission $perms1 to @set on $ROOT_TESTFS
+#      3. Reset permission $perms2 to @set on $ROOT_TESTFS/childfs
+#      4. Allow @set to $STAFF1 on $ROOT_TESTFS/childfs
+#      5. Verify $perms2 is delegated on $ROOT_TESTFS/childfs and its
+#         descendent.
+#      6. Allow @set to $STAFF1 on $ROOT_TESTFS
+#      7. Verify $perms1 is not appended to $STAFF1 on $ROOT_TESTFS/childfs and
+#         its descendent since it is masked
+#
+
+verify_runnable "both"
+
+log_assert "Verify permission set can be masked on descendent dataset."
+log_onexit restore_root_datasets
+
+typeset perms1="snapshot,reservation,compression"
+eval set -A dataset $DATASETS
+typeset perms2="checksum,send,userprop"
+
+#
+# Define three level filesystems
+#
+childfs=$ROOT_TESTFS/childfs
+grandchild=$childfs/grandchild
+log_must $ZFS create $childfs
+log_must $ZFS create $grandchild
+
+#
+# Setting different permissions to the same set on two level.
+# But only assign the user at one level.
+#
+log_must $ZFS allow -s @set $perms1 $ROOT_TESTFS
+log_must $ZFS allow -s @set $perms2 $childfs
+log_must $ZFS allow $STAFF1 @set $childfs
+
+#
+# Verify only perms2 is valid to user on the level which he was assigned.
+#
+log_must verify_noperm $ROOT_TESTFS $perms1 $STAFF1
+for fs in $childfs $grandchild ; do
+       log_must verify_noperm $fs $perms1 $STAFF1
+       log_must verify_perm $fs $perms2 $STAFF1
+done
+
+#
+# Delegate @set to STAFF1 on ROOT_TESTFS, verify $perms1 will not be appended
+# to its descendent datasets since it is masked
+#
+log_must $ZFS allow $STAFF1 @set $ROOT_TESTFS
+log_must verify_perm $ROOT_TESTFS $perms1 $STAFF1
+for fs in $childfs $grandchild ; do
+       log_must verify_noperm $fs $perms1 $STAFF1
+       log_must verify_perm $fs $perms2 $STAFF1
+done
+
+# Remove the mask, $perms1 will be allowed to its descendent datasets
+log_must $ZFS unallow -s @set $childfs
+for fs in $childfs $grandchild ; do
+       log_must verify_noperm $fs $perms2 $STAFF1
+       log_must verify_perm $fs $perms1 $STAFF1
+done
+
+log_pass "Verify permission set can be masked on descendent dataset pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_008_pos.ksh
new file mode 100755 (executable)
index 0000000..fb02b9a
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      non-root user can allow any permissions which he is holding to
+#      other else user when it get 'allow' permission.
+#
+# STRATEGY:
+#      1. Set two set permissions to two datasets locally.
+#      2. Verify the non-root user can allow permission if he has allow
+#         permission.
+#
+
+verify_runnable "both"
+
+log_assert "Verify non-root user can allow permissions."
+log_onexit restore_root_datasets
+
+perms1="snapshot,reservation"
+perms2="send,compression,checksum,userprop"
+childfs=$ROOT_TESTFS/childfs
+
+log_must $ZFS create $childfs
+
+for dtst in $DATASETS ; do
+       # Delegate local permission to $STAFF1
+       log_must $ZFS allow -l $STAFF1 $perms1 $dtst
+       log_must $ZFS allow -l $STAFF1 allow $dtst
+
+       if [[ $dtst == $ROOT_TESTFS ]]; then
+               log_must $ZFS allow -l $STAFF1 $perms2 $childfs
+               # $perms1 is local permission in $ROOT_TESTFS
+               log_mustnot user_run $STAFF1 $ZFS allow $OTHER1 $perms1 $childfs
+               log_must verify_noperm $childfs $perms1 $OTHER1
+       fi
+
+       # Verify 'allow' give non-privilege user delegated permission.
+       log_must user_run $STAFF1 $ZFS allow -l $OTHER1 $perms1 $dtst
+       log_must verify_perm $dtst $perms1 $OTHER1
+
+       # $perms2 was not allow to $STAFF1, so he have no permission to
+       # delegate permission to other else.
+       log_mustnot user_run $STAFF1 $ZFS allow $OTHER1 $perms2 $dtst
+       log_must verify_noperm $dtst $perms2 $OTHER1
+done
+
+log_pass "Verify non-root user can allow permissions passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_009_neg.ksh
new file mode 100755 (executable)
index 0000000..4da1653
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      zfs allow can deal with invalid arguments.(Invalid options or combination)
+#
+# STRATEGY:
+#      1. Verify invalid argumets will cause error.
+#      2. Verify non-optional argument was missing will cause error.
+#      3. Verify invalid options cause error.
+#
+
+verify_runnable "both"
+
+log_assert "Verify invalid arguments are handled correctly."
+log_onexit restore_root_datasets
+
+# Permission sets are limited to 64 characters in length.
+longset="set123456789012345678901234567890123456789012345678901234567890123"
+for dtst in $DATASETS ; do
+       log_mustnot eval "$ZFS allow -s @$longset $dtst"
+       # Create non-existent permission set
+       typeset timestamp=$($DATE +'%F-%R:%S')
+       log_mustnot $ZFS allow -s @non-existent $dtst
+       log_mustnot $ZFS allow $STAFF "atime,created,mounted" $dtst
+       log_mustnot $ZFS allow $dtst $TESTPOOL
+       log_mustnot $ZFS allow -c $dtst
+       log_mustnot $ZFS allow -u $STAFF1 $dtst
+       log_mustnot $ZFS allow -u $STAFF1 -g $STAFF_GROUP "create,destroy" $dtst
+       log_mustnot $ZFS allow -u $STAFF1 -e "mountpoint" $dtst
+done
+
+log_pass "Invalid arguments are handled correctly."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_010_pos.ksh
new file mode 100755 (executable)
index 0000000..2e3be0c
--- /dev/null
@@ -0,0 +1,153 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Scan the following permissions one by one to verify privileged user
+#      has correct permission delegation in datasets.
+#
+# STRATEGY:
+#      1. Delegate all the permission one by one to user on dataset.
+#      2. Verify privileged user has correct permission without any other
+#         permissions allowed.
+#
+
+verify_runnable "both"
+
+log_assert "Verify privileged user has correct permissions once which was "\
+       "delegated to him in datasets"
+log_onexit restore_root_datasets
+
+if is_linux; then
+#
+#                              Results in      Results in
+#              Permission      Filesystem      Volume
+#
+# Removed for Linux:
+# - mount      - mount(8) does not permit non-superuser mounts
+# - mountpoint - mount(8) does not permit non-superuser mounts
+# - canmount   - mount(8) does not permit non-superuser mounts
+# - rename      - mount(8) does not permit non-superuser mounts
+# - zoned      - zones are not supported
+# - destroy     - umount(8) does not permit non-superuser umounts
+# - sharenfs   - sharing requires superuser priviliges
+# - share      - sharing requires superuser priviliges
+# - readonly   - mount(8) does not permit non-superuser remounts
+#
+set -A perms   create          true            false   \
+               snapshot        true            true    \
+               send            true            true    \
+               allow           true            true    \
+               quota           true            false   \
+               reservation     true            true    \
+               dnodesize       true            false   \
+               recordsize      true            false   \
+               checksum        true            true    \
+               compression     true            true    \
+               atime           true            false   \
+               devices         true            false   \
+               exec            true            false   \
+               volsize         false           true    \
+               setuid          true            false   \
+               snapdir         true            false   \
+               userprop        true            true    \
+               aclinherit      true            false   \
+               rollback        true            true    \
+               clone           true            true    \
+               promote         true            true    \
+               xattr           true            false   \
+               receive         true            false
+else
+
+set -A perms   create          true            false   \
+               snapshot        true            true    \
+               mount           true            false   \
+               send            true            true    \
+               allow           true            true    \
+               quota           true            false   \
+               reservation     true            true    \
+               dnodesize       true            false   \
+               recordsize      true            false   \
+               mountpoint      true            false   \
+               checksum        true            true    \
+               compression     true            true    \
+               canmount        true            false   \
+               atime           true            false   \
+               devices         true            false   \
+               exec            true            false   \
+               volsize         false           true    \
+               setuid          true            false   \
+               readonly        true            true    \
+               snapdir         true            false   \
+               userprop        true            true    \
+               aclmode         true            false   \
+               aclinherit      true            false   \
+               rollback        true            true    \
+               clone           true            true    \
+               rename          true            true    \
+               promote         true            true    \
+               zoned           true            false   \
+               xattr           true            false   \
+               receive         true            false   \
+               destroy         true            true
+
+if is_global_zone; then
+       typeset -i n=${#perms[@]}
+       perms[((n))]="sharenfs"; perms[((n+1))]="true"; perms[((n+2))]="false"
+       perms[((n+3))]="share"; perms[((n+4))]="true"; perms[((n+5))]="false"
+fi
+fi
+
+for dtst in $DATASETS; do
+       typeset -i k=1
+       typeset type=$(get_prop type $dtst)
+       [[ $type == "volume" ]] && k=2
+
+       typeset -i i=0
+       while (( i < ${#perms[@]} )); do
+               log_must $ZFS allow $STAFF1 ${perms[$i]} $dtst
+
+               if [[ ${perms[((i+k))]} == "true" ]]; then
+                       log_must verify_perm $dtst ${perms[$i]} $STAFF1
+               else
+                       log_must verify_noperm $dtst ${perms[$i]} $STAFF1
+               fi
+
+               log_must restore_root_datasets
+
+               ((i += 3))
+       done
+done
+
+log_pass "Verify privileged user has correct permissions " \
+       "in datasets passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_011_neg.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_011_neg.ksh
new file mode 100755 (executable)
index 0000000..60031c9
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify zpool subcmds and system readonly properties can't be delegated.
+#
+# STRATEGY:
+#      1. Loop all the zpool subcmds and readonly properties, except permission
+#         'create' & 'destroy'.
+#      2. Verify those subcmd or properties can't be delegated.
+#
+
+verify_runnable "both"
+
+log_assert "Verify zpool subcmds and system readonly properties can't be " \
+       "delegated."
+log_onexit restore_root_datasets
+
+set -A invalid_perms   \
+       add             remove          list            iostat          \
+       status          offline         online          clear           \
+       attach          detach          replace         scrub           \
+       export          import          upgrade                         \
+       type            creation        used            available       \
+       referenced      compressratio   mounted
+
+for dtst in $DATASETS ; do
+       typeset -i i=0
+
+       while ((i < ${#invalid_perms[@]})); do
+               log_mustnot $ZFS allow $STAFF1 ${invalid_perms[$i]} $dtst
+
+               ((i += 1))
+       done
+done
+
+log_pass "Verify zpool subcmds and system readonly properties passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_012_neg.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_allow_012_neg.ksh
new file mode 100755 (executable)
index 0000000..723fb92
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Scan all permissions one by one to verify privileged user
+#      can not use permissions properly when delegation property is set off
+#
+# STRATEGY:
+#      1. Delegate all the permission one by one to user on dataset.
+#      2. Verify privileged user can not use permissions properly when
+#      delegation property is off
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       log_must $ZPOOL set delegation=on $TESTPOOL
+       log_must restore_root_datasets
+}
+
+log_assert "Verify privileged user can not use permissions properly when " \
+       "delegation property is set off"
+log_onexit cleanup
+
+
+if is_linux; then
+set -A perms   create snapshot mount send allow quota reservation \
+               recordsize mountpoint checksum compression canmount atime \
+               devices exec volsize setuid readonly snapdir userprop \
+               rollback clone rename promote dnodesize \
+               zoned xattr receive destroy
+else
+set -A perms   create snapshot mount send allow quota reservation \
+               recordsize mountpoint checksum compression canmount atime \
+               devices exec volsize setuid readonly snapdir userprop \
+               aclmode aclinherit rollback clone rename promote dnodesize \
+               zoned xattr receive destroy sharenfs share
+fi
+
+log_must $ZPOOL set delegation=off $TESTPOOL
+
+for dtst in $DATASETS; do
+       typeset -i i=0
+       while (( i < ${#perms[@]} )); do
+
+               log_must $ZFS allow $STAFF1 ${perms[$i]} $dtst
+               log_must verify_noperm $dtst ${perms[$i]} $STAFF1
+
+               log_must restore_root_datasets
+               ((i += 1))
+       done
+done
+
+log_pass "Verify privileged user can not use permissions properly when " \
+       "delegation property is set off"
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_001_pos.ksh
new file mode 100755 (executable)
index 0000000..a2c34de
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify '-l' only removed the local permissions.
+#
+# STRATEGY:
+#      1. Set up unallow test model.
+#      2. Implement unallow -l to $ROOT_TESTFS or $TESTVOL
+#      3. Verify '-l' only remove the local permissions.
+#
+
+verify_runnable "both"
+
+log_assert "Verify '-l' only removed the local permissions."
+log_onexit restore_root_datasets
+
+log_must setup_unallow_testenv
+
+for dtst in $DATASETS ; do
+       log_must $ZFS unallow -l $STAFF1 $dtst
+       log_must verify_noperm $dtst $LOCAL_SET $STAFF1
+
+       log_must $ZFS unallow -l $OTHER1 $dtst
+       log_must verify_noperm $dtst $LOCAL_DESC_SET $OTHER1
+
+       log_must verify_perm $dtst $LOCAL_DESC_SET $OTHER2
+       if [[ $dtst == $ROOT_TESTFS ]]; then
+               log_must verify_perm $SUBFS $LOCAL_DESC_SET $OTHER1 $OTHER2
+               log_must verify_perm $SUBFS $DESC_SET $STAFF2
+       fi
+done
+
+log_pass "Verify '-l' only removed the local permissions passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_002_pos.ksh
new file mode 100755 (executable)
index 0000000..c48df76
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify '-d' only remove the permissions on descendent filesystem.
+#
+# STRATEGY:
+#      1. Set up unallow test model.
+#      2. Implement unallow -d to $ROOT_TESTFS
+#      3. Verify '-d' only remove the permissions on descendent filesystem.
+#
+
+verify_runnable "both"
+
+log_assert "Verify '-d' only removed the descendent permissions."
+log_onexit restore_root_datasets
+
+log_must setup_unallow_testenv
+
+log_must $ZFS unallow -d $STAFF2 $ROOT_TESTFS
+log_must verify_noperm $SUBFS $DESC_SET $STAFF2
+
+log_must $ZFS unallow -d $OTHER1 $ROOT_TESTFS
+log_must verify_noperm $SUBFS $LOCAL_DESC_SET $OTHER1
+log_must verify_perm $ROOT_TESTFS $LOCAL_DESC_SET $OTHER1
+
+log_must verify_perm $ROOT_TESTFS $LOCAL_DESC_SET $OTHER2
+log_must verify_perm $SUBFS $LOCAL_DESC_SET $OTHER2
+
+log_pass "Verify '-d' only removed the descendent permissions passed"
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_003_pos.ksh
new file mode 100755 (executable)
index 0000000..57dff54
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify options '-r' or '-l' + '-d' will unallow permission to this
+#      dataset and the descendent datasets.
+#
+# STRATEGY:
+#      1. Set up unallow test model.
+#      2. Implement unallow -l -d to $ROOT_TESTFS or $ROOT_TESTVOL without
+#         options.
+#      3. Verify '-l' + '-d' will unallow local + descendent permission.
+#      4. Verify '-r' will unallow local + descendent permission.
+#
+
+verify_runnable "both"
+
+log_assert "Verify options '-r' and '-l'+'-d' will unallow permission to " \
+       "this dataset and the descendent datasets."
+log_onexit restore_root_datasets
+
+log_must setup_unallow_testenv
+
+for dtst in $DATASETS ; do
+       log_must $ZFS unallow $STAFF1 $dtst
+       log_must $ZFS unallow -l -d $STAFF2 $dtst
+       log_must verify_noperm $dtst $LOCAL_SET $STAFF1
+       if [[ $dtst == $ROOT_TESTFS ]]; then
+               log_must verify_noperm $SUBFS $DESC_SET $STAFF2
+       fi
+
+       log_must $ZFS unallow -l -d $OTHER1 $dtst
+       log_must $ZFS unallow -r $OTHER2 $dtst
+       log_must verify_noperm $dtst $LOCAL_DESC_SET $OTHER1 $OTHER2
+       if [[ $dtst == $ROOT_TESTFS ]]; then
+               log_must verify_noperm $SUBFS $LOCAL_DESC_SET $OTHER1 $OTHER2
+       fi
+done
+
+log_pass "Verify options '-r' and '-l'+'-d' function passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_004_pos.ksh
new file mode 100755 (executable)
index 0000000..0c55551
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify '-s' will remove permissions from the named set.
+#
+# STRATEGY:
+#      1. Set @basic set to $ROOT_TESTFS or $ROOT_TESTVOL and allow @basic
+#         to $STAFF1
+#      2. Verify $STAFF1 have @basic permissions.
+#      3. Verify '-s' will remove permission from the named set.
+#
+
+verify_runnable "both"
+
+log_assert "Verify '-s' will remove permissions from the named set."
+log_onexit restore_root_datasets
+
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -s @basic $LOCAL_DESC_SET $dtst
+       log_must $ZFS allow -u $STAFF1 @basic $dtst
+
+       log_must verify_perm $dtst $LOCAL_DESC_SET $STAFF1
+       log_must $ZFS unallow -s @basic $LOCAL_DESC_SET $dtst
+       log_must verify_noperm $dtst $LOCAL_DESC_SET $STAFF1
+done
+
+log_pass "Verify '-s' will remove permissions from the named set passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_005_pos.ksh
new file mode 100755 (executable)
index 0000000..a723e8f
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify option '-c' will remove the created permission set.
+#
+# STRATEGY:
+#      1. Set created time set to $ROOT_TESTFS.
+#      2. Allow permission create to $STAFF1 on $ROOT_TESTFS.
+#      3. Create $SUBFS and verify $STAFF1 have created time permissions.
+#      4. Verify $STAFF1 has created time permission.
+#      5. Unallow created time permission with option '-c'.
+#      6. Created $SUBFS and verify $STAFF1 have not created time permissions.
+#
+
+verify_runnable "both"
+
+log_assert "Verify option '-c' will remove the created permission set."
+log_onexit restore_root_datasets
+
+log_must $ZFS allow -c $LOCAL_SET $ROOT_TESTFS
+log_must $ZFS allow -l $STAFF1 create,mount $ROOT_TESTFS
+
+# Create $SUBFS and verify $SUBFS has created time permissions.
+user_run $STAFF1 $ZFS create $SUBFS
+if ! datasetexists $SUBFS ; then
+       log_fail "ERROR: ($STAFF1): $ZFS create $SUBFS"
+fi
+log_must verify_perm $SUBFS $LOCAL_SET $STAFF1
+
+#
+# After unallow -c, create $SUBFS2 and verify $SUBFS2 has not created time
+# permissions any more.
+#
+log_must $ZFS unallow -c $LOCAL_SET $ROOT_TESTFS
+user_run $STAFF1 $ZFS create $SUBFS2
+if ! datasetexists $SUBFS2 ; then
+       log_fail "ERROR: ($STAFF1): $ZFS create $SUBFS2"
+fi
+log_must verify_noperm $SUBFS2 $LOCAL_SET $STAFF1
+
+log_pass "Verify option '-c' will remove the created permission set passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_006_pos.ksh
new file mode 100755 (executable)
index 0000000..af9ea49
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify option '-u', '-g' and '-e' only removed the specified type
+#      permissions set.
+#
+# STRATEGY:
+#      1. Allow '-u' '-g' & '-e' to $STAFF1 on ROOT_TESTFS or $ROOT_TESTVOL.
+#      2. Unallow '-u' '-g' & '-e' on $ROOT_TESTFS or $ROOT_TESTVOL separately.
+#      3. Verify permissions on $ROOT_TESTFS or $ROOT_TESTVOL separately.
+#
+
+verify_runnable "both"
+
+log_assert "Verify option '-u', '-g' and '-e' only removed the specified type "\
+       "permissions set."
+log_onexit restore_root_datasets
+
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -u $STAFF1 $LOCAL_DESC_SET $dtst
+       log_must $ZFS allow -g $STAFF_GROUP $LOCAL_DESC_SET $dtst
+       log_must $ZFS allow -e $LOCAL_DESC_SET $dtst
+
+       log_must verify_perm $dtst $LOCAL_DESC_SET \
+               $STAFF1 $STAFF2 $OTHER1 $OTHER2
+
+       log_must $ZFS unallow -e $dtst
+       log_must verify_perm $dtst $LOCAL_DESC_SET $STAFF1 $STAFF2
+       log_must verify_noperm $dtst $LOCAL_DESC_SET $OTHER1 $OTHER2
+
+       log_must $ZFS unallow -g $STAFF_GROUP $dtst
+       log_must verify_perm $dtst $LOCAL_DESC_SET $STAFF1
+       log_must verify_noperm $dtst $LOCAL_DESC_SET $STAFF2
+
+       log_must $ZFS unallow -u $STAFF1 $dtst
+       log_must verify_noperm $dtst $LOCAL_DESC_SET $STAFF1
+done
+
+log_pass "Verify option '-u', '-g' and '-e' passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_007_neg.ksh
new file mode 100755 (executable)
index 0000000..e9bd3bf
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      zfs unallow will not remove those permissions which inherited from
+#      its parent filesystem.
+#
+# STRATEGY:
+#      1. Assign perm1 to $ROOT_TESTFS
+#      2. Create $SUBFS and assign perm2 to it.
+#      3. Verify unallow can not affect perm1 on $SUBFS
+#
+
+verify_runnable "both"
+
+log_assert "zfs unallow won't remove those permissions which inherited from " \
+       "its parent dataset."
+log_onexit restore_root_datasets
+
+perm1="atime,devices"; perm2="compression,checksum"
+log_must $ZFS create $SUBFS
+log_must $ZFS allow $STAFF1 $perm1 $ROOT_TESTFS
+log_must $ZFS allow $STAFF1 $perm2 $SUBFS
+
+log_must verify_perm $SUBFS ${perm1},${perm2} $STAFF1
+#
+# Athrough unallow the permissions which don't exists on the specific dataset
+# return 0, the inherited permissions can't be removed in fact.
+#
+log_must $ZFS unallow -u $STAFF1 $perm1 $SUBFS
+log_must verify_perm $SUBFS ${perm1},${perm2} $STAFF1
+
+log_pass "Verify zfs unallow won't remove inherited permissions passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/delegate/zfs_unallow_008_neg.ksh
new file mode 100755 (executable)
index 0000000..b00119d
--- /dev/null
@@ -0,0 +1,84 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/delegate/delegate_common.kshlib
+
+#
+# DESCRIPTION:
+#      zfs unallow can handle invalid arguments.
+#
+# STRATEGY:
+#      1. Set up basic test environment.
+#      2. Verify zfs unallow handle invalid arguments correctly.
+#
+
+verify_runnable "both"
+
+log_assert "zfs unallow can handle invalid arguments."
+log_onexit restore_root_datasets
+
+function neg_test
+{
+       log_mustnot eval "$@ >/dev/null 2>&1"
+}
+
+# Options that cause this test to fail:
+# "-r"
+set -A badopts "everyone -e" "everyone -u $STAFF1" "everyone everyone" \
+       "-c -l" "-c -d" "-c -e" "-c -s" "-u -e" "-s -e" "-s -l -d" \
+       "-s @non-exist-set -l" "-s @non-existen-set -d" \
+       "-s @non-existen-set -e" "-r -u $STAFF1 $STAFF1" \
+       "-u $STAFF1 -g $STAFF_GROUP" "-u $STAFF1 -e"
+
+log_must setup_unallow_testenv
+
+#
+# The GNU getopt(3) implementation will reorder these arguments such the
+# the parser can handle them and the test doesn't fail.  POSIXLY_CORRECT
+# is set to disable the reordering so the original test cases will fail.
+#
+export POSIXLY_CORRECT=1
+
+for dtst in $DATASETS ; do
+       log_must $ZFS allow -c create $dtst
+
+       typeset -i i=0
+       while ((i < ${#badopts[@]})); do
+               neg_test $ZFS unallow ${badopts[$i]} $dtst
+               ((i += 1))
+       done
+
+       # Causes test failure: neg_test user_run $STAFF1 $ZFS unallow $dtst
+done
+
+unset POSIXLY_CORRECT
+
+log_pass "zfs unallow can handle invalid arguments passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/devices/Makefile.am b/zfs/tests/zfs-tests/tests/functional/devices/Makefile.am
new file mode 100644 (file)
index 0000000..ebbfa9a
--- /dev/null
@@ -0,0 +1,9 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/devices
+dist_pkgdata_SCRIPTS = \
+       devices.cfg \
+       devices_common.kshlib \
+       cleanup.ksh \
+       setup.ksh \
+       devices_001_pos.ksh \
+       devices_002_neg.ksh \
+       devices_003_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/devices/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/devices/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/devices/devices.cfg b/zfs/tests/zfs-tests/tests/functional/devices/devices.cfg
new file mode 100644 (file)
index 0000000..ba3c36a
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export TESTFILE1=testfile1$$
+export TESTFILE2=testfile2$$
diff --git a/zfs/tests/zfs-tests/tests/functional/devices/devices_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/devices/devices_001_pos.ksh
new file mode 100755 (executable)
index 0000000..acea6e2
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/devices/devices.cfg
+. $STF_SUITE/tests/functional/devices/devices_common.kshlib
+
+#
+# DESCRIPTION:
+# When set property devices=on on file system, devices files can be used in
+# this file system.
+#
+# STRATEGY:
+# 1. Create pool and file system.
+# 2. Set devices=on on this file system.
+# 3. Separately create block device file and character file.
+# 4. Separately read from those two device files.
+# 5. Check the return value, and make sure it succeeds.
+#
+
+verify_runnable "global"
+
+log_assert "Setting devices=on on file system, the devices files in this file" \
+       "system can be used."
+log_onexit cleanup
+
+log_must $ZFS set devices=on $TESTPOOL/$TESTFS
+
+#
+# Separately create block device file and character device file, then try to
+# open them and make sure it succeed.
+#
+create_dev_file b $TESTDIR/$TESTFILE1
+log_must $DD if=$TESTDIR/$TESTFILE1 of=$TESTDIR/$TESTFILE1.out count=1
+create_dev_file c $TESTDIR/$TESTFILE2
+log_must $DD if=$TESTDIR/$TESTFILE2 of=$TESTDIR/$TESTFILE2.out count=1
+
+log_pass "Setting devices=on on file system and testing it pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/devices/devices_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/devices/devices_002_neg.ksh
new file mode 100755 (executable)
index 0000000..8a1f828
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/devices/devices.cfg
+. $STF_SUITE/tests/functional/devices/devices_common.kshlib
+
+#
+# DESCRIPTION:
+# When set property devices=off on file system, device files cannot be used
+# in this file system.
+#
+# STRATEGY:
+# 1. Create pool and file system.
+# 2. Set devices=off on this file system.
+# 3. Separately create block device file and character file.
+# 4. Separately read from those two device files.
+# 5. Check the return value, and make sure it failed.
+#
+
+verify_runnable "global"
+
+log_assert "Setting devices=off on file system, the devices files in this file"\
+       "system can not be used."
+log_onexit cleanup
+
+log_must $ZFS set devices=off $TESTPOOL/$TESTFS
+
+#
+# Separately create block device file and character device file, then try to
+# open them and make sure it failed.
+#
+create_dev_file b $TESTDIR/$TESTFILE1
+log_mustnot $DD if=$TESTDIR/$TESTFILE1 of=$TESTDIR/$TESTFILE1.out count=1
+create_dev_file c $TESTDIR/$TESTFILE2
+log_mustnot $DD if=$TESTDIR/$TESTFILE2 of=$TESTDIR/$TESTFILE2.out count=1
+
+log_pass "Setting devices=off on file system and testing it pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/devices/devices_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/devices/devices_003_pos.ksh
new file mode 100755 (executable)
index 0000000..837478c
--- /dev/null
@@ -0,0 +1,49 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Writing random data into /dev/zfs should do no harm.
+#
+# STRATEGY:
+# 1. Write some random data into /dev/zfs
+# 2. Verify that this should fail.
+#
+#
+
+log_assert "Writing random data into /dev/zfs should do no harm."
+
+log_mustnot $DD if=/dev/urandom of=/dev/zfs count=1024
+
+log_pass "Writing random data into /dev/zfs should do no harm."
diff --git a/zfs/tests/zfs-tests/tests/functional/devices/devices_common.kshlib b/zfs/tests/zfs-tests/tests/functional/devices/devices_common.kshlib
new file mode 100644 (file)
index 0000000..597ca94
--- /dev/null
@@ -0,0 +1,126 @@
+#
+# 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.
+#
+
+. $STF_SUITE/tests/functional/devices/devices.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# Create block file or charactor file according to parameter.
+#
+# $1 device file type
+# $2 file name
+#
+function create_dev_file
+{
+       typeset filetype=$1
+       typeset filename=$2
+
+       case $filetype in
+               b)
+                       if is_linux; then
+                               devtype=$($DF -T / | $AWK '{print $2}')
+                       else
+                               devtype=$($DF -n / | $AWK '{print $3}')
+                       fi
+                       case $devtype in
+                               zfs)
+                                       rootpool=$($DF / | \
+                                               $AWK '{print $2}')
+                                       rootpool=${rootpool#\(}
+                                       rootpool=${rootpool%%/*}
+
+                                       devstr=$(get_disklist $rootpool)
+                                       devstr=$($ECHO "$devstr" | \
+                                               $AWK '{print $1}')
+                                       [[ -z $devstr ]] && \
+                                               log_fail "Can not get block device file."
+                                       devstr=$DEV_DSKDIR/${devstr}
+                                       ;;
+                               ufs)
+                       #
+                       # Get the existing block device file in current system.
+                       # And bring out the first one.
+                       #
+                                       devstr=$($DF -lhF ufs | \
+                                               $GREP "^${DEV_DSKDIR}" | \
+                                               $AWK '{print $1}')
+                                       devstr=$($ECHO "$devstr" | \
+                                               $AWK '{print $1}')
+                                       [[ -z $devstr ]] && \
+                                               log_fail "Can not get block device file."
+                                       ;;
+                               ext2)
+                                       # TODO: Linux version
+                                       ;;
+                               *)
+                                       log_unsupported "Unsupported fstype " \
+                                               "for / ($devtype)," \
+                                               "only ufs|zfs is supported."
+                                       ;;
+                       esac
+
+                       #
+                       # Get the device file information. i.e:
+                       # $DEV_DSKDIR/c0t0d0s0:      block special (28/768)
+                       #
+                       devstr=$($FILE $devstr)
+
+                       #
+                       # Bring out major and minor number.
+                       #
+                       major=${devstr##*\(}
+                       major=${major%%/*}
+                       minor=${devstr##*/}
+                       minor=${minor%\)}
+
+                       log_must $MKNOD $filename b $major $minor
+                       ;;
+               c)
+                       #
+                       # Create device file '/dev/null'
+                       #
+                       log_must $MKNOD $filename c $($GETMAJOR mm) 2
+                       ;;
+               *)
+                       log_fail "'$filetype' is wrong."
+                       ;;
+       esac
+
+       return 0
+}
+
+function cleanup
+{
+       log_must $ZFS set devices=on $TESTPOOL/$TESTFS
+       log_must $RM -f $TESTDIR/$TESTFILE1
+       log_must $RM -f $TESTDIR/$TESTFILE2
+       log_must $RM -f $TESTDIR/$TESTFILE1.out
+       log_must $RM -f $TESTDIR/$TESTFILE2.out
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/devices/setup.ksh b/zfs/tests/zfs-tests/tests/functional/devices/setup.ksh
new file mode 100755 (executable)
index 0000000..fc5cec3
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/exec/Makefile.am b/zfs/tests/zfs-tests/tests/functional/exec/Makefile.am
new file mode 100644 (file)
index 0000000..524bf27
--- /dev/null
@@ -0,0 +1,9 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/exec
+
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       exec_001_pos.ksh \
+       exec_002_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/exec/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/exec/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/exec/exec_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/exec/exec_001_pos.ksh
new file mode 100755 (executable)
index 0000000..f6e44d2
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# When set property exec=on on a filesystem, processes can be executed from
+# this filesystem.
+#
+# STRATEGY:
+# 1. Create pool and file system.
+# 2. Copy '/usr/bin/ls' to the ZFS file system.
+# 3. Setting exec=on on this file system.
+# 4. Make sure '/usr/bin/ls' can work in this ZFS file system.
+# 5. Make sure mmap which is using the PROT_EXEC calls succeed.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $RM $TESTDIR/myls
+}
+
+log_assert "Setting exec=on on a filesystem, processes can be executed from " \
+       "this file system."
+log_onexit cleanup
+
+log_must $CP $LS $TESTDIR/myls
+log_must $ZFS set exec=on $TESTPOOL/$TESTFS
+log_must $TESTDIR/myls
+log_must $MMAP_EXEC $TESTDIR/myls
+
+log_pass "Setting exec=on on filesystem testing passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/exec/exec_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/exec/exec_002_neg.ksh
new file mode 100755 (executable)
index 0000000..34a7f6c
--- /dev/null
@@ -0,0 +1,84 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# When set property exec=off on a filesystem, processes can not be executed from
+# this filesystem.
+#
+# STRATEGY:
+# 1. Create pool and file system.
+# 2. Copy '/usr/bin/ls' to the ZFS file system.
+# 3. Setting exec=off on this file system.
+# 4. Make sure '/usr/bin/ls' can not work in this ZFS file system.
+# 5. Make sure mmap which is using the PROT_EXEC calls failed.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $RM $TESTDIR/myls
+}
+
+#
+# Execute and check if the return value is equal to expected.
+#
+# $1 expected value
+# $2..$n executed item
+#
+function exec_n_check
+{
+       typeset expect_value=$1
+
+       shift
+       $@
+       ret=$?
+       if [[ $ret != $expect_value ]]; then
+               log_fail "Unexpected return code: '$ret'"
+       fi
+
+       return 0
+}
+
+log_assert "Setting exec=off on a filesystem, processes can not be executed " \
+       "from this file system."
+log_onexit cleanup
+
+log_must $CP $LS $TESTDIR/myls
+log_must $ZFS set exec=off $TESTPOOL/$TESTFS
+
+log_must exec_n_check 126 $TESTDIR/myls
+log_must exec_n_check 13 $MMAP_EXEC $TESTDIR/myls
+
+log_pass "Setting exec=off on filesystem testing passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/exec/setup.ksh b/zfs/tests/zfs-tests/tests/functional/exec/setup.ksh
new file mode 100755 (executable)
index 0000000..fc5cec3
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/features/Makefile.am b/zfs/tests/zfs-tests/tests/functional/features/Makefile.am
new file mode 100644 (file)
index 0000000..3657461
--- /dev/null
@@ -0,0 +1,3 @@
+SUBDIRS = \
+       async_destroy \
+       large_dnode
diff --git a/zfs/tests/zfs-tests/tests/functional/features/async_destroy/Makefile.am b/zfs/tests/zfs-tests/tests/functional/features/async_destroy/Makefile.am
new file mode 100644 (file)
index 0000000..4c77787
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/features/async_destroy
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       async_destroy_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/features/async_destroy/async_destroy_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/features/async_destroy/async_destroy_001_pos.ksh
new file mode 100755 (executable)
index 0000000..130c8f2
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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 (c) 2013, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Exercise the traversal suspend/resume code in async_destroy by
+# destroying a file system that has more blocks than we can free
+# in a single txg.
+#
+# STRATEGY:
+# 1. Create a file system
+# 2. Set recordsize to 512 to create the maximum number of blocks
+# 3. Set compression to off to force zero-ed blocks to be written
+# 4. dd a lot of data from /dev/zero to the file system
+# 5. Destroy the file system
+# 6. Wait for the freeing property to go to 0
+# 7. Use zdb to check for leaked blocks
+#
+
+TEST_FS=$TESTPOOL/async_destroy
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $TEST_FS && log_must $ZFS destroy $TEST_FS
+}
+
+log_onexit cleanup
+log_assert "async_destroy can suspend and resume traversal"
+
+log_must $ZFS create -o recordsize=512 -o compression=off $TEST_FS
+
+# Fill with 1G
+log_must $DD bs=1024k count=1024 if=/dev/zero of=/$TEST_FS/file
+
+log_must $ZFS destroy $TEST_FS
+
+#
+# We monitor the freeing property, to verify we can see blocks being
+# freed while the suspend/resume code is exerciesd.
+#
+t0=$SECONDS
+count=0
+while [[ $((SECONDS - t0)) -lt 10 ]]; do
+       [[ "0" != "$($ZPOOL list -Ho freeing $TESTPOOL)" ]] && ((count++))
+       [[ $count -gt 1 ]] && break
+       $SLEEP 1
+done
+
+[[ $count -eq 0 ]] && log_fail "Freeing property remained empty"
+
+# Wait for everything to be freed.
+while [[ "0" != "$($ZPOOL list -Ho freeing $TESTPOOL)" ]]; do
+       [[ $((SECONDS - t0)) -gt 180 ]] && \
+           log_fail "Timed out waiting for freeing to drop to zero"
+done
+
+# Check for leaked blocks.
+log_must $ZDB -b $TESTPOOL
+
+log_pass "async_destroy can suspend and resume traversal"
diff --git a/zfs/tests/zfs-tests/tests/functional/features/async_destroy/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/features/async_destroy/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/features/async_destroy/setup.ksh b/zfs/tests/zfs-tests/tests/functional/features/async_destroy/setup.ksh
new file mode 100755 (executable)
index 0000000..d275e06
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/Makefile.am b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/Makefile.am
new file mode 100644 (file)
index 0000000..6afda53
--- /dev/null
@@ -0,0 +1,11 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/features/large_dnode
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       large_dnode_001_pos.ksh \
+       large_dnode_002_pos.ksh \
+       large_dnode_003_pos.ksh \
+       large_dnode_004_neg.ksh \
+       large_dnode_005_pos.ksh \
+       large_dnode_006_pos.ksh \
+       large_dnode_007_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/cleanup.ksh
new file mode 100755 (executable)
index 0000000..61caf39
--- /dev/null
@@ -0,0 +1,25 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_001_pos.ksh
new file mode 100755 (executable)
index 0000000..a05acb9
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that the dnode sizes of newly created files are consistent
+# with the dnodesize dataset property.
+#
+# STRATEGY:
+# 1. Create a file system
+# 2. Set dnodesize to a legal literal value
+# 3. Create a file
+# 4. Repeat 2-3 for all legal literal values of dnodesize values
+# 5. Unmount the file system
+# 6. Use zdb to check expected dnode sizes
+#
+
+TEST_FS=$TESTPOOL/large_dnode
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $TEST_FS && log_must $ZFS destroy $TEST_FS
+}
+
+log_onexit cleanup
+log_assert "dnode sizes are consistent with dnodesize dataset property"
+
+log_must $ZFS create $TEST_FS
+
+set -A dnsizes "512" "1k" "2k" "4k" "8k" "16k"
+set -A inodes
+
+for ((i=0; i < ${#dnsizes[*]}; i++)) ; do
+       size=${dnsizes[$i]}
+       if [[ $size == "512" ]] ; then
+               size="legacy"
+       fi
+       file=/$TEST_FS/file.$size
+       log_must $ZFS set dnsize=$size $TEST_FS
+       touch $file
+       inodes[$i]=$(ls -li $file | awk '{print $1}')
+done
+
+log_must $ZFS umount $TEST_FS
+
+for ((i=0; i < ${#dnsizes[*]}; i++)) ; do
+       dnsize=$($ZDB -dddd $TEST_FS ${inodes[$i]} |
+           awk '/ZFS plain file/ {print $6}' | tr K k)
+       if [[ "$dnsize" != "${dnsizes[$i]}" ]]; then
+               log_fail "dnode size is $dnsize (expected ${dnsizes[$i]})"
+       fi
+done
+
+log_pass "dnode sizes are consistent with dnodesize dataset property"
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_002_pos.ksh
new file mode 100755 (executable)
index 0000000..788e33a
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that extended attributes can use extra bonus space of a large
+# dnode without kicking in a spill block.
+#
+# STRATEGY:
+# 1. Create a file system with xattr=sa
+# 2. Set dnodesize to a legal literal value
+# 3. Create a file
+# 4  Store an xattr that fits within the dnode size
+# 4. Repeat 2-3 for all legal literal values of dnodesize values
+# 5. Unmount the file system
+# 6. Use zdb to check for missing SPILL_BLKPTR flag
+#
+
+TEST_FS=$TESTPOOL/large_dnode
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $TEST_FS && log_must $ZFS destroy $TEST_FS
+}
+
+log_onexit cleanup
+log_assert "extended attributes use extra bonus space of a large dnode"
+
+log_must $ZFS create -o xattr=sa $TEST_FS
+
+# Store dnode size minus 512 in an xattr
+set -A xattr_sizes "512" "1536" "3584" "7680" "15872"
+set -A prop_values "1k"  "2k"   "4k"   "8k"   "16k"
+set -A inodes
+
+for ((i=0; i < ${#prop_values[*]}; i++)) ; do
+       prop_val=${prop_values[$i]}
+       file=/$TEST_FS/file.$prop_val
+       log_must $ZFS set dnsize=$prop_val $TEST_FS
+       touch $file
+       xattr_size=${xattr_sizes[$i]}
+       xattr_name=user.foo
+       xattr_val=$(dd if=/dev/urandom bs=1 count=$xattr_size |
+           openssl enc -a -A)
+       log_must setfattr -n $xattr_name -v 0s$xattr_val $file
+       inodes[$i]=$(ls -li $file | awk '{print $1}')
+done
+
+log_must $ZFS umount $TEST_FS
+
+for ((i=0; i < ${#inodes[*]}; i++)) ; do
+       log_mustnot eval "$ZDB -dddd $TEST_FS ${inodes[$i]} | grep SPILL_BLKPTR"
+done
+
+log_pass "extended attributes use extra bonus space of a large dnode"
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_003_pos.ksh
new file mode 100755 (executable)
index 0000000..3f5779d
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+
+function cleanup
+{
+        if datasetexists $LDNPOOL ; then
+                log_must $ZPOOL destroy -f $LDNPOOL
+        fi
+}
+
+log_onexit cleanup
+
+log_assert "feature correctly switches between enabled and active"
+
+LDNPOOL=ldnpool
+LDNFS=$LDNPOOL/large_dnode
+log_must $MKFILE 64M  $TESTDIR/$LDNPOOL
+log_must $ZPOOL create $LDNPOOL $TESTDIR/$LDNPOOL
+
+
+state=$($ZPOOL list -Ho feature@large_dnode $LDNPOOL)
+if [[ "$state" != "enabled" ]]; then
+        log_fail "large_dnode has state $state (expected enabled)"
+fi
+
+log_must $ZFS create -o dnodesize=1k $LDNFS
+log_must touch /$LDNFS/foo
+log_must $ZFS unmount $LDNFS
+
+state=$($ZPOOL list -Ho feature@large_dnode $LDNPOOL)
+if [[ "$state" != "active" ]]; then
+        log_fail "large_dnode has state $state (expected active)"
+fi
+
+log_must $ZFS destroy $LDNFS
+
+state=$($ZPOOL list -Ho feature@large_dnode $LDNPOOL)
+if [[ "$state" != "enabled" ]]; then
+        log_fail "large_dnode has state $state (expected enabled)"
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_004_neg.ksh
new file mode 100755 (executable)
index 0000000..26ed669
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+
+TEST_FS=$TESTPOOL/large_dnode
+TEST_SNAP=$TESTPOOL/large_dnode@ldnsnap
+TEST_STREAM=$TESTDIR/ldnsnap
+
+function cleanup
+{
+       if datasetexists $TEST_FS ; then
+               log_must $ZFS destroy -r $TEST_FS
+       fi
+
+       if datasetexists $LGCYPOOL ; then
+               log_must $ZPOOL destroy -f $LGCYPOOL
+       fi
+
+       rm -f $TEST_STREAM
+}
+
+log_onexit cleanup
+log_assert "zfs send stream with large dnodes not accepted by legacy pool"
+
+log_must $ZFS create -o dnodesize=1k $TEST_FS
+log_must touch /$TEST_FS/foo
+log_must $ZFS umount $TEST_FS
+log_must $ZFS snap $TEST_SNAP
+log_must eval "$ZFS send $TEST_SNAP > $TEST_STREAM"
+
+LGCYPOOL=ldnpool
+LGCYFS=$LGCYPOOL/legacy
+log_must $MKFILE 64M  $TESTDIR/$LGCYPOOL
+log_must $ZPOOL create -d $LGCYPOOL $TESTDIR/$LGCYPOOL
+log_mustnot eval "$ZFS recv $LGCYFS < $TEST_STREAM"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_005_pos.ksh
new file mode 100755 (executable)
index 0000000..e03d127
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+
+TEST_SEND_FS=$TESTPOOL/send_large_dnode
+TEST_RECV_FS=$TESTPOOL/recv_large_dnode
+TEST_SNAP=$TEST_SEND_FS@ldnsnap
+TEST_STREAM=$TESTDIR/ldnsnap
+TEST_FILE=foo
+
+
+function cleanup
+{
+       if datasetexists $TEST_SEND_FS ; then
+               log_must $ZFS destroy -r $TEST_SEND_FS
+       fi
+
+       if datasetexists $TEST_RECV_FS ; then
+               log_must $ZFS destroy -r $TEST_RECV_FS
+       fi
+
+       rm -f $TEST_STREAM
+}
+
+log_onexit cleanup
+
+log_assert "zfs send stream with large dnodes accepted by new pool"
+
+log_must $ZFS create -o dnodesize=1k $TEST_SEND_FS
+log_must touch /$TEST_SEND_FS/$TEST_FILE
+log_must $ZFS umount $TEST_SEND_FS
+log_must $ZFS snap $TEST_SNAP
+log_must $ZFS send $TEST_SNAP > $TEST_STREAM
+
+log_must eval "$ZFS recv $TEST_RECV_FS < $TEST_STREAM"
+inode=$(ls -li /$TEST_RECV_FS/$TEST_FILE | awk '{print $1}')
+dnsize=$($ZDB -dddd $TEST_RECV_FS $inode | awk '/ZFS plain file/ {print $6}')
+if [[ "$dnsize" != "1K" ]]; then
+       log_fail "dnode size is $dnsize (expected 1K)"
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_006_pos.ksh
new file mode 100755 (executable)
index 0000000..198b69b
--- /dev/null
@@ -0,0 +1,58 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Run xattrtest on a dataset with large dnodes and xattr=sa
+# to stress xattr usage of the extra bonus space and verify
+# contents
+#
+
+TEST_FS=$TESTPOOL/large_dnode
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $TEST_FS && log_must $ZFS destroy $TEST_FS
+}
+
+log_onexit cleanup
+log_assert "xattrtest runs cleanly on dataset with large dnodes"
+
+log_must $ZFS create $TEST_FS
+
+set -A xattr_sizes "512" "1536" "3584" "7680" "15872"
+set -A prop_values "1k"  "2k"   "4k"   "8k"   "16k"
+
+for ((i=0; i < ${#prop_values[*]}; i++)) ; do
+       prop_val=${prop_values[$i]}
+       dir=/$TEST_FS/$prop_val
+       xattr_size=${xattr_sizes[$i]}
+       log_must $ZFS set dnsize=$prop_val $TEST_FS
+       log_must mkdir $dir
+       log_must $XATTRTEST -R -y -s $xattr_size -f 1024 -p $dir
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/large_dnode_007_neg.ksh
new file mode 100755 (executable)
index 0000000..d6cc17e
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that the dnodesize dataset property won't accept a value
+# other than "legacy" if the large_dnode feature is not enabled.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+        if datasetexists $LGCYPOOL ; then
+                log_must $ZPOOL destroy -f $LGCYPOOL
+        fi
+}
+
+log_onexit cleanup
+
+log_assert "values other than dnodesize=legacy rejected by legacy pool"
+
+set -A prop_vals "auto" "1k" "2k" "4k" "8k" "16k"
+
+LGCYPOOL=lgcypool
+LGCYFS=$LGCYPOOL/legacy
+log_must $MKFILE 64M  $TESTDIR/$LGCYPOOL
+log_must $ZPOOL create -d $LGCYPOOL $TESTDIR/$LGCYPOOL
+log_must $ZFS create $LGCYFS
+
+for val in ${prop_vals[@]} ; do
+       log_mustnot $ZFS set dnodesize=$val $LGCYFS
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/features/large_dnode/setup.ksh b/zfs/tests/zfs-tests/tests/functional/features/large_dnode/setup.ksh
new file mode 100755 (executable)
index 0000000..d9b1a6e
--- /dev/null
@@ -0,0 +1,27 @@
+#!/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
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/grow_pool/Makefile.am b/zfs/tests/zfs-tests/tests/functional/grow_pool/Makefile.am
new file mode 100644 (file)
index 0000000..4fc98ff
--- /dev/null
@@ -0,0 +1,4 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/grow_pool
+dist_pkgdata_SCRIPTS = \
+       grow_pool.cfg \
+       grow_pool_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/grow_pool/grow_pool.cfg b/zfs/tests/zfs-tests/tests/functional/grow_pool/grow_pool.cfg
new file mode 100644 (file)
index 0000000..8b05632
--- /dev/null
@@ -0,0 +1,73 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+function set_disks
+{
+       set -A disk_array $(find_disks $DISKS)
+       typeset -i i=0
+       typeset -i limit=2
+       while  (( i < limit )); do
+               if [[ -n ${disk_array[$i]} ]]; then
+                       export DISK${i}="${disk_array[$i]}"
+               else
+                       export DISK=${DISKS%% *}
+                       return
+               fi
+               ((i = i + 1))
+       done
+       export DISK=""
+}
+
+export BLOCK_SIZE=8192
+set_disks
+#
+# Do not make SIZE too large as the three slices may exceed
+# the size of the disk, and also slow down the test
+# which involves filling until ENOSPC
+#
+export SIZE="100mb"
+export SMALL_WRITE_COUNT=100
+export TESTFILE1=file$$.1
+export WRITE_COUNT=65536000
+
+if is_linux; then
+       set_device_dir
+       set_slice_prefix
+       export SLICE=1
+       export SLICE0=1
+       export SLICE1=2
+else
+       export SLICE_PREFIX="s"
+       export SLICE=0
+       export SLICE0=0
+       export SLICE1=1
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/grow_pool/grow_pool_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/grow_pool/grow_pool_001_pos.ksh
new file mode 100755 (executable)
index 0000000..ac3e09b
--- /dev/null
@@ -0,0 +1,74 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/grow_pool/grow_pool.cfg
+
+#
+# DESCRIPTION:
+# A ZFS file system is limited by the amount of disk space
+# available to the pool. Growing the pool by adding a disk
+# increases the amount of space.
+#
+# STRATEGY:
+# 1) Fill a ZFS filesystem until ENOSPC by creating a large file
+# 2) Grow the pool by adding a disk
+# 3) Verify that more data can now be written to the file system
+#
+
+verify_runnable "global"
+
+log_assert "A zpool may be increased in capacity by adding a disk"
+
+log_must $ZFS set compression=off $TESTPOOL/$TESTFS
+$FILE_WRITE -o create -f $TESTDIR/$TESTFILE1 \
+       -b $BLOCK_SIZE -c $WRITE_COUNT -d 0
+typeset -i zret=$?
+readonly ENOSPC=28
+if [[ $zret -ne $ENOSPC ]]; then
+       log_fail "file_write completed w/o ENOSPC, aborting!!!"
+fi
+
+if [[ ! -s $TESTDIR/$TESTFILE1 ]]; then
+       log_fail "$TESTDIR/$TESTFILE1 was not created"
+fi
+
+if [[ -n $DISK ]]; then
+       log_must $ZPOOL add $TESTPOOL $DISK"s"$SLICE1
+else
+       log_must $ZPOOL add $TESTPOOL $DISK1
+fi
+
+log_must $FILE_WRITE -o append -f $TESTDIR/$TESTFILE1 \
+       -b $BLOCK_SIZE -c $SMALL_WRITE_COUNT -d 0
+
+log_must $ZFS inherit compression $TESTPOOL/$TESTFS
+log_pass "TESTPOOL successfully grown"
diff --git a/zfs/tests/zfs-tests/tests/functional/grow_replicas/Makefile.am b/zfs/tests/zfs-tests/tests/functional/grow_replicas/Makefile.am
new file mode 100644 (file)
index 0000000..7fdcd95
--- /dev/null
@@ -0,0 +1,4 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/grow_replicas
+dist_pkgdata_SCRIPTS = \
+       grow_replicas.cfg \
+       grow_replicas_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/grow_replicas/grow_replicas.cfg b/zfs/tests/zfs-tests/tests/functional/grow_replicas/grow_replicas.cfg
new file mode 100644 (file)
index 0000000..ebf3226
--- /dev/null
@@ -0,0 +1,79 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+# Copyright 2016 Nexenta Systems, Inc.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+function set_disks
+{
+       set -A disk_array $(find_disks $DISKS)
+       typeset -i i=0
+       typeset -i limit=4
+       while  (( i < limit )); do
+               if [[ -n ${disk_array[$i]} ]]; then
+                       export DISK${i}="${disk_array[$i]}"
+               else
+                       export DISK=${DISKS%% *}
+                       return
+               fi
+               ((i = i + 1))
+       done
+       export DISK=""
+}
+
+export BLOCK_SIZE=8192
+set_disks
+
+# Do not make SIZE too large as the three slices may exceed
+# the size of the disk, and also slow down the test
+# which involves filling until ENOSPC.
+export SIZE="100mb"
+export SMALL_WRITE_COUNT=100
+export TESTFILE1=file$$.1
+export WRITE_COUNT=65536000
+
+if is_linux; then
+       export SLICES="0 1 2 3 4"
+       set_device_dir
+       set_slice_prefix
+       export SLICE0=1
+       export SLICE1=2
+       export SLICE2=3
+       export SLICE3=4
+       export SLICE4=5
+else
+       export SLICES="0 1 3 4"
+       export SLICE_PREFIX="s"
+       export SLICE0=0
+       export SLICE1=1
+       export SLICE2=2
+       export SLICE3=3
+       export SLICE4=4
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/grow_replicas/grow_replicas_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/grow_replicas/grow_replicas_001_pos.ksh
new file mode 100755 (executable)
index 0000000..aaf3e53
--- /dev/null
@@ -0,0 +1,114 @@
+#! /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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+# Copyright 2016 Nexenta Systems, Inc.
+#
+
+. $STF_SUITE/tests/functional/grow_replicas/grow_replicas.cfg
+
+# DESCRIPTION:
+# A ZFS filesystem is limited by the amount of disk space
+# available to the pool. Growing the pool by adding a disk
+# increases the amount of space.
+#
+# STRATEGY:
+# 1. Fill the filesystem on mirror/raidz pool by writing a file until ENOSPC.
+# 2. Grow the mirror/raidz pool by adding another mirror/raidz vdev.
+# 3. Verify that more data can now be written to the filesystem.
+
+verify_runnable "global"
+
+if ! is_physical_device $DISKS; then
+       log_unsupported "This test case cannot be run on raw files"
+fi
+
+function cleanup
+{
+       datasetexists $TESTPOOL && log_must destroy_pool $TESTPOOL
+       [[ -d $TESTDIR ]] && log_must $RM -rf $TESTDIR
+}
+
+log_assert "mirror/raidz pool may be increased in capacity by adding a disk"
+
+log_onexit cleanup
+
+readonly ENOSPC=28
+
+for pooltype in "mirror" "raidz"; do
+       log_note "Creating pool type: $pooltype"
+
+       if [[ -n $DISK ]]; then
+               log_note "No spare disks available. Using slices on $DISK"
+               for slice in $SLICES; do
+                       log_must set_partition $slice "$cyl" $SIZE $DISK
+                       cyl=$(get_endslice $DISK $slice)
+               done
+               create_pool $TESTPOOL $pooltype \
+                       ${DISK}${SLICE_PREFIX}${SLICE0} \
+                       ${DISK}${SLICE_PREFIX}${SLICE1}
+       else
+               log_must set_partition 0 "" $SIZE $DISK0
+               log_must set_partition 0 "" $SIZE $DISK1
+               create_pool $TESTPOOL $pooltype \
+                       ${DISK0}${SLICE_PREFIX}${SLICE0} \
+                       ${DISK1}${SLICE_PREFIX}${SLICE0}
+       fi
+
+       [[ -d $TESTDIR ]] && log_must $RM -rf $TESTDIR
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+       log_must $ZFS set compression=off $TESTPOOL/$TESTFS
+       $FILE_WRITE -o create -f $TESTDIR/$TESTFILE1 \
+            -b $BLOCK_SIZE -c $WRITE_COUNT -d 0
+
+       [[ $? -ne $ENOSPC ]] && \
+           log_fail "file_write completed w/o ENOSPC"
+
+       [[ ! -s $TESTDIR/$TESTFILE1 ]] && \
+           log_fail "$TESTDIR/$TESTFILE1 was not created"
+
+       # $DISK will be set if we're using slices on one disk
+       if [[ -n $DISK ]]; then
+               log_must $ZPOOL add $TESTPOOL $pooltype ${DISK}s3 ${DISK}s4
+       else
+               [[ -z $DISK2 || -z $DISK3 ]] && 
+                   log_unsupported "No spare disks available"
+               log_must $ZPOOL add $TESTPOOL $pooltype \
+                       ${DISK2}${SLICE_PREFIX}${SLICE0} \
+                       ${DISK3}${SLICE_PREFIX}${SLICE0}
+       fi
+
+       log_must $FILE_WRITE -o append -f $TESTDIR/$TESTFILE1 \
+           -b $BLOCK_SIZE -c $SMALL_WRITE_COUNT -d 0
+
+       log_must destroy_pool $TESTPOOL
+done
+
+log_pass "mirror/raidz pool successfully grown"
diff --git a/zfs/tests/zfs-tests/tests/functional/history/Makefile.am b/zfs/tests/zfs-tests/tests/functional/history/Makefile.am
new file mode 100644 (file)
index 0000000..861f412
--- /dev/null
@@ -0,0 +1,21 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/history
+dist_pkgdata_SCRIPTS = \
+       history.cfg \
+       history_common.kshlib \
+       cleanup.ksh \
+       setup.ksh \
+       history_001_pos.ksh \
+       history_002_pos.ksh \
+       history_003_pos.ksh \
+       history_004_pos.ksh \
+       history_005_neg.ksh \
+       history_006_neg.ksh \
+       history_007_pos.ksh \
+       history_008_pos.ksh \
+       history_009_pos.ksh \
+       history_010_pos.ksh \
+       i386.migratedpool.DAT.Z \
+       i386.orig_history.txt \
+       sparc.migratedpool.DAT.Z \
+       sparc.orig_history.txt \
+       zfs-pool-v4.dat.Z
diff --git a/zfs/tests/zfs-tests/tests/functional/history/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/history/cleanup.ksh
new file mode 100755 (executable)
index 0000000..a09846a
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+[[ -f $OLD_HISTORY ]] && $RM -f $OLD_HISTORY
+[[ -f $TMP_HISTORY ]] && $RM -f $TMP_HISTORY
+[[ -f $NEW_HISTORY ]] && $RM -f $NEW_HISTORY
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history.cfg b/zfs/tests/zfs-tests/tests/functional/history/history.cfg
new file mode 100644 (file)
index 0000000..e1ed76e
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export ZFSROOT=
+
+export MPOOL=mpool.$$
+
+export OLD_HISTORY=/tmp/old_history.$$
+export TMP_HISTORY=/tmp/tmp_history.$$
+export NEW_HISTORY=/tmp/new_history.$$
+
+export MIGRATEDPOOLNAME=${MIGRATEDPOOLNAME:-history_pool}
+export TIMEZONE=${TIMEZONE:-US/Mountain}
+
+export HIST_USER="huser"
+export HIST_GROUP="hgroup"
+
+export TESTVOL=testvol.$$
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_001_pos.ksh
new file mode 100755 (executable)
index 0000000..e63d5ac
--- /dev/null
@@ -0,0 +1,122 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/history/history_common.kshlib
+
+#
+# DESCRIPTION:
+#      Create a scenario to verify the following zpool subcommands are logged.
+#      create, destroy, add, remove, offline, online, attach, detach, replace,
+#      scrub, export, import, clear, upgrade.
+#
+# STRATEGY:
+#      1. Create three virtual disk files and create a mirror.
+#      2. Run and verify pool commands, with special casing for destroy/export.
+#      3. Import a pool and upgrade it, verifying 'upgrade' was logged.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       destroy_pool $MPOOL
+       destroy_pool $upgrade_pool
+
+       [[ -d $import_dir ]] && $RM -rf $import_dir
+       for file in $VDEV1 $VDEV2 $VDEV3 $VDEV4; do
+               [[ -f $file ]] && $RM -f $file
+       done
+}
+
+log_assert "Verify zpool sub-commands which modify state are logged."
+log_onexit cleanup
+
+mntpnt=$(get_prop mountpoint $TESTPOOL)
+(( $? != 0)) && log_fail "get_prop($TESTPOOL mountpoint)"
+VDEV1=$mntpnt/vdev1; VDEV2=$mntpnt/vdev2;
+VDEV3=$mntpnt/vdev3; VDEV4=$mntpnt/vdev4;
+
+log_must $MKFILE 64m $VDEV1 $VDEV2 $VDEV3
+log_must $MKFILE 100m $VDEV4
+
+run_and_verify -p "$MPOOL" "$ZPOOL create $MPOOL mirror $VDEV1 $VDEV2"
+run_and_verify -p "$MPOOL" "$ZPOOL add -f $MPOOL spare $VDEV3"
+run_and_verify -p "$MPOOL" "$ZPOOL remove $MPOOL $VDEV3"
+run_and_verify -p "$MPOOL" "$ZPOOL offline $MPOOL $VDEV1"
+run_and_verify -p "$MPOOL" "$ZPOOL online $MPOOL $VDEV1"
+run_and_verify -p "$MPOOL" "$ZPOOL attach $MPOOL $VDEV1 $VDEV4"
+run_and_verify -p "$MPOOL" "$ZPOOL detach $MPOOL $VDEV4"
+run_and_verify -p "$MPOOL" "$ZPOOL replace -f $MPOOL $VDEV1 $VDEV4"
+run_and_verify -p "$MPOOL" "$ZPOOL scrub $MPOOL"
+run_and_verify -p "$MPOOL" "$ZPOOL clear $MPOOL"
+
+# For export and destroy, mimic the behavior of run_and_verify using two
+# commands since the history will be unavailable until the pool is imported
+# again.
+commands=("$ZPOOL export $MPOOL" "$ZPOOL import -d $mntpnt $MPOOL"
+    "$ZPOOL destroy $MPOOL" "$ZPOOL import -D -f -d $mntpnt $MPOOL")
+for i in 0 2; do
+       cmd1="${commands[$i]}"
+       cmd2="${commands[(($i + 1 ))]}"
+
+       $ZPOOL history $MPOOL > $OLD_HISTORY 2>/dev/null
+       log_must $cmd1
+       log_must $cmd2
+       $ZPOOL history $MPOOL > $TMP_HISTORY 2>/dev/null
+       $DIFF $OLD_HISTORY $TMP_HISTORY | $GREP "^> " | $SED 's/^> //g' > \
+           $NEW_HISTORY
+        if is_linux; then
+               $GREP "$($ECHO "$cmd1" | $SED 's/^.*\/\(zpool .*\).*$/\1/')" \
+                   $NEW_HISTORY >/dev/null 2>&1 || \
+                   log_fail "Didn't find \"$cmd1\" in pool history"
+               $GREP "$($ECHO "$cmd2" | $SED 's/^.*\/\(zpool .*\).*$/\1/')" \
+                   $NEW_HISTORY >/dev/null 2>&1 || \
+                   log_fail "Didn't find \"$cmd2\" in pool history"
+        else
+               $GREP "$($ECHO "$cmd1" | $SED 's/\/usr\/sbin\///g')" \
+                   $NEW_HISTORY >/dev/null 2>&1 || \
+                   log_fail "Didn't find \"$cmd1\" in pool history"
+               $GREP "$($ECHO "$cmd2" | $SED 's/\/usr\/sbin\///g')" \
+                   $NEW_HISTORY >/dev/null 2>&1 || \
+                   log_fail "Didn't find \"$cmd2\" in pool history"
+        fi
+done
+
+run_and_verify -p "$MPOOL" "$ZPOOL split $MPOOL ${MPOOL}_split"
+
+import_dir=/var/tmp/import_dir.$$
+log_must $MKDIR $import_dir
+log_must $CP $STF_SUITE/tests/functional/history/zfs-pool-v4.dat.Z $import_dir
+log_must $UNCOMPRESS $import_dir/zfs-pool-v4.dat.Z
+upgrade_pool=$($ZPOOL import -d $import_dir | $GREP "pool:" | $AWK '{print $2}')
+log_must $ZPOOL import -d $import_dir $upgrade_pool
+run_and_verify -p "$upgrade_pool" "$ZPOOL upgrade $upgrade_pool"
+
+log_pass "zpool sub-commands which modify state are logged passed. "
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_002_pos.ksh
new file mode 100755 (executable)
index 0000000..06edc67
--- /dev/null
@@ -0,0 +1,169 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/history/history_common.kshlib
+
+#
+# DESCRIPTION:
+#      Create a  scenario to verify the following zfs subcommands are logged.
+#      create, destroy, clone, rename, snapshot, rollback, set, inherit,
+#      receive, promote, hold and release.
+#
+# STRATEGY:
+#      1. Verify that all the zfs commands listed (barring send) produce an
+#         entry in the pool history.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+
+       [[ -f $tmpfile ]] && $RM -f $tmpfile
+       [[ -f $tmpfile2 ]] && $RM -f $tmpfile2
+       for dataset in $fs $newfs $fsclone $vol $newvol $volclone; do
+               datasetexists $dataset && $ZFS destroy -Rf $dataset
+       done
+       $RM -rf /history.$$
+}
+
+log_assert "Verify zfs sub-commands which modify state are logged."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS1; newfs=$TESTPOOL/newfs; fsclone=$TESTPOOL/clone
+vol=$TESTPOOL/$TESTVOL ; newvol=$TESTPOOL/newvol; volclone=$TESTPOOL/volclone
+fssnap=$fs@fssnap; fssnap2=$fs@fssnap2
+volsnap=$vol@volsnap; volsnap2=$vol@volsnap2
+tmpfile=/tmp/tmpfile.$$ ; tmpfile2=/tmp/tmpfile2.$$
+
+if is_linux; then
+#      property        value           property        value
+#
+props=(
+       quota           64M             recordsize      512
+       reservation     32M             reservation     none
+       mountpoint      /history.$$     mountpoint      legacy
+       mountpoint      none            compression     lz4
+       compression     on              compression     off
+       compression     lzjb            acltype         noacl
+       acltype         posixacl        xattr           sa
+       atime           on              atime           off
+       devices         on              devices         off
+       exec            on              exec            off
+       setuid          on              setuid          off
+       readonly        on              readonly        off
+       zoned           on              zoned           off
+       snapdir         hidden          snapdir         visible
+       aclinherit      discard         aclinherit      noallow
+       aclinherit      secure          aclinherit      passthrough
+       canmount        off             canmount        on
+       xattr           on              xattr           off
+       compression     gzip            compression     gzip-$((RANDOM%9 + 1))
+       copies          $((RANDOM%3 + 1))
+)
+else
+#      property        value           property        value
+#
+props=(
+       quota           64M             recordsize      512
+       reservation     32M             reservation     none
+       mountpoint      /history.$$     mountpoint      legacy
+       mountpoint      none            sharenfs        on
+       sharenfs        off
+       compression     on              compression     off
+       compression     lzjb            aclmode         discard
+       aclmode         groupmask       aclmode         passthrough
+       atime           on              atime           off
+       devices         on              devices         off
+       exec            on              exec            off
+       setuid          on              setuid          off
+       readonly        on              readonly        off
+       zoned           on              zoned           off
+       snapdir         hidden          snapdir         visible
+       aclinherit      discard         aclinherit      noallow
+       aclinherit      secure          aclinherit      passthrough
+       canmount        off             canmount        on
+       xattr           on              xattr           off
+       compression     gzip            compression     gzip-$((RANDOM%9 + 1))
+       copies          $((RANDOM%3 + 1))
+)
+fi
+
+run_and_verify "$ZFS create $fs"
+# Set all the property for filesystem
+typeset -i i=0
+while ((i < ${#props[@]})) ; do
+       run_and_verify "$ZFS set ${props[$i]}=${props[((i+1))]} $fs"
+
+       # quota, reservation, canmount can not be inherited.
+       #
+       if [[ ${props[$i]} != "quota" && ${props[$i]} != "reservation" && \
+           ${props[$i]} != "canmount" ]];
+       then
+               run_and_verify "$ZFS inherit ${props[$i]} $fs"
+       fi
+
+       ((i += 2))
+done
+
+run_and_verify "$ZFS create -V 64M $vol"
+run_and_verify "$ZFS set volsize=32M $vol"
+run_and_verify "$ZFS snapshot $fssnap"
+run_and_verify "$ZFS hold tag $fssnap"
+run_and_verify "$ZFS release tag $fssnap"
+run_and_verify "$ZFS snapshot $volsnap"
+run_and_verify "$ZFS snapshot $fssnap2"
+run_and_verify "$ZFS snapshot $volsnap2"
+
+# Send isn't logged...
+log_must $ZFS send -i $fssnap $fssnap2 > $tmpfile
+log_must $ZFS send -i $volsnap $volsnap2 > $tmpfile2
+# Verify that's true
+$ZPOOL history $TESTPOOL | $GREP 'zfs send' >/dev/null 2>&1 && \
+    log_fail "'zfs send' found in history of \"$TESTPOOL\""
+
+run_and_verify "$ZFS destroy $fssnap2"
+run_and_verify "$ZFS destroy $volsnap2"
+run_and_verify "$ZFS receive $fs < $tmpfile"
+run_and_verify "$ZFS receive $vol < $tmpfile2"
+run_and_verify "$ZFS rollback -r $fssnap"
+run_and_verify "$ZFS rollback -r $volsnap"
+run_and_verify "$ZFS clone $fssnap $fsclone"
+run_and_verify "$ZFS clone $volsnap $volclone"
+run_and_verify "$ZFS rename $fs $newfs"
+run_and_verify "$ZFS rename $vol $newvol"
+run_and_verify "$ZFS promote $fsclone"
+run_and_verify "$ZFS promote $volclone"
+run_and_verify "$ZFS destroy $newfs"
+run_and_verify "$ZFS destroy $newvol"
+run_and_verify "$ZFS destroy -rf $fsclone"
+run_and_verify "$ZFS destroy -rf $volclone"
+
+log_pass "zfs sub-commands which modify state are logged passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_003_pos.ksh
new file mode 100755 (executable)
index 0000000..224ee15
--- /dev/null
@@ -0,0 +1,103 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      zpool history will truncate on small pools, leaving pool creation intact
+#
+# STRATEGY:
+#      1. Create two 100M virtual disk files.
+#      2. Create test pool using the two virtual files.
+#      3. Loop 100 times to set and remove compression to test dataset.
+#      4. Make sure 'zpool history' output is truncated
+#      5. Verify that the initial pool creation is preserved.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $spool && log_must $ZPOOL destroy $spool
+       [[ -f $VDEV0 ]] && log_must $RM -f $VDEV0
+       [[ -f $VDEV1 ]] && log_must $RM -f $VDEV1
+       [[ -f $TMPFILE ]] && log_must $RM -f $TMPFILE
+}
+
+log_assert "zpool history limitation test."
+log_onexit cleanup
+
+mntpnt=$(get_prop mountpoint $TESTPOOL)
+(( $? != 0 )) && log_fail "get_prop mountpoint $TESTPOOL"
+
+VDEV0=$mntpnt/vdev0; VDEV1=$mntpnt/vdev1
+log_must $MKFILE 100m $VDEV0 $VDEV1
+
+spool=smallpool.$$; sfs=smallfs.$$
+log_must $ZPOOL create $spool $VDEV0 $VDEV1
+log_must $ZFS create $spool/$sfs
+
+typeset -i orig_count=$($ZPOOL history $spool | $WC -l)
+typeset orig_md5=$($ZPOOL history $spool | $HEAD -2 | $MD5SUM | \
+    $AWK '{print $1}')
+
+typeset -i i=0
+while ((i < 100)); do
+       $ZFS set compression=off $spool/$sfs
+       $ZFS set compression=on $spool/$sfs
+       $ZFS set compression=off $spool/$sfs
+       $ZFS set compression=on $spool/$sfs
+       $ZFS set compression=off $spool/$sfs
+
+       ((i += 1))
+done
+
+TMPFILE=/tmp/spool.$$
+$ZPOOL history $spool >$TMPFILE
+typeset -i entry_count=$($WC -l $TMPFILE | $AWK '{print $1}')
+typeset final_md5=$($HEAD -2 $TMPFILE | $MD5SUM | $AWK '{print $1}')
+
+$GREP 'zpool create' $TMPFILE >/dev/null 2>&1 ||
+    log_fail "'zpool create' was not found in pool history"
+
+$GREP 'zfs create' $TMPFILE >/dev/null 2>&1 &&
+    log_fail "'zfs create' was found in pool history"
+
+$GREP 'zfs set compress' $TMPFILE >/dev/null 2>&1 ||
+    log_fail "'zfs set compress' was found in pool history"
+
+# Verify that the creation of the pool was preserved in the history.
+if [[ $orig_md5 != $final_md5 ]]; then
+       log_fail "zpool creation history was not preserved."
+fi
+
+log_pass "zpool history limitation test passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_004_pos.ksh
new file mode 100755 (executable)
index 0000000..e29173f
--- /dev/null
@@ -0,0 +1,100 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zpool history' can cope with simultaneous commands.
+#
+# STRATEGY:
+#      1. Create test pool and test fs.
+#      2. Loop 100 times, set properties to test fs simultaneously.
+#      3. Wait for all the command execution complete.
+#      4. Make sure all the commands was logged by 'zpool history'.
+#
+
+verify_runnable "global"
+
+log_assert "'zpool history' can cope with simultaneous commands."
+
+typeset -i orig_count=$($ZPOOL history $spool | $WC -l | $AWK '{print $1}')
+
+typeset -i i=0
+while ((i < 10)); do
+       $ZFS set compression=off $TESTPOOL/$TESTFS &
+       $ZFS set atime=off $TESTPOOL/$TESTFS &
+       $ZFS create $TESTPOOL/$TESTFS1 &
+       $ZFS create $TESTPOOL/$TESTFS2 &
+       $ZFS create $TESTPOOL/$TESTFS3 &
+
+       wait
+
+       $ZFS snapshot $TESTPOOL/$TESTFS1@snap &
+       $ZFS snapshot $TESTPOOL/$TESTFS2@snap &
+       $ZFS snapshot $TESTPOOL/$TESTFS3@snap &
+
+       wait
+
+       $ZFS clone $TESTPOOL/$TESTFS1@snap $TESTPOOL/clone1 &
+       $ZFS clone $TESTPOOL/$TESTFS2@snap $TESTPOOL/clone2 &
+       $ZFS clone $TESTPOOL/$TESTFS3@snap $TESTPOOL/clone3 &
+
+       wait
+
+       $ZFS promote $TESTPOOL/clone1 &
+       $ZFS promote $TESTPOOL/clone2 &
+       $ZFS promote $TESTPOOL/clone3 &
+
+       wait
+
+       $ZFS destroy $TESTPOOL/$TESTFS1 &
+       $ZFS destroy $TESTPOOL/$TESTFS2 &
+       $ZFS destroy $TESTPOOL/$TESTFS3 &
+
+       wait
+
+       $ZFS destroy -Rf $TESTPOOL/clone1 &
+       $ZFS destroy -Rf $TESTPOOL/clone2 &
+       $ZFS destroy -Rf $TESTPOOL/clone3 &
+
+       wait
+       ((i += 1))
+done
+
+typeset -i entry_count=$($ZPOOL history $spool | $WC -l | $AWK '{print $1}')
+
+if ((entry_count - orig_count != 200)); then
+       log_fail "The entries count error: entry_count=$entry_count " \
+                "orig_count = $orig_count"
+fi
+
+log_pass "'zpool history' can cope with simultaneous commands."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_005_neg.ksh
new file mode 100755 (executable)
index 0000000..7a3ac27
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/history/history_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify the following zpool subcommands are not logged.
+#              zpool get
+#              zpool history
+#              zpool list
+#              zpool status
+#              zpool iostat
+#
+# STRATEGY:
+#      1. Create a test pool.
+#      2. Separately invoke zpool list|status|iostat
+#      3. Verify they was not recored in pool history.
+#
+
+verify_runnable "global"
+
+log_assert "Verify 'zpool get|history|list|status|iostat' will not be logged."
+
+# Save initial TESTPOOL history
+log_must eval "$ZPOOL history $TESTPOOL >$OLD_HISTORY"
+
+log_must $ZPOOL get all $TESTPOOL >/dev/null
+log_must $ZPOOL list $TESTPOOL >/dev/null
+log_must $ZPOOL status $TESTPOOL >/dev/null
+log_must $ZPOOL iostat $TESTPOOL >/dev/null
+
+log_must eval "$ZPOOL history $TESTPOOL >$NEW_HISTORY"
+log_must $DIFF $OLD_HISTORY $NEW_HISTORY
+
+log_pass "Verify 'zpool get|history|list|status|iostat' will not be logged."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_006_neg.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_006_neg.ksh
new file mode 100755 (executable)
index 0000000..d1ed414
--- /dev/null
@@ -0,0 +1,88 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/history/history_common.kshlib
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Verify the following zfs subcommands are not logged.
+#      list, get, holds, mount, unmount, share, unshare, send
+#
+# STRATEGY:
+#      1. Create a test pool.
+#      2. Separately invoke zfs list|get|holds|mount|unmount|share|unshare|send
+#      3. Verify they were not recored in pool history.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if datasetexists $fs ; then
+               log_must $ZFS destroy -rf $fs
+       fi
+       log_must $ZFS create $fs
+}
+
+log_assert "Verify 'zfs list|get|holds|mount|unmount|share|unshare|send' " \
+    "will not be logged."
+log_onexit cleanup
+
+# Create initial test environment
+fs=$TESTPOOL/$TESTFS; snap1=$fs@snap1; snap2=$fs@snap2
+if ! is_linux; then
+       log_must $ZFS set sharenfs=on $fs
+fi
+log_must $ZFS snapshot $snap1
+log_must $ZFS hold tag $snap1
+log_must $ZFS snapshot $snap2
+
+# Save initial TESTPOOL history
+log_must eval "$ZPOOL history $TESTPOOL > $OLD_HISTORY"
+
+log_must $ZFS list $fs > /dev/null
+log_must $ZFS get mountpoint $fs > /dev/null
+log_must $ZFS unmount $fs
+log_must $ZFS mount $fs
+if ! is_linux; then
+       log_must $ZFS share $fs
+       log_must $ZFS unshare $fs
+fi
+log_must $ZFS send -i $snap1 $snap2 > /dev/null
+log_must $ZFS holds $snap1
+
+log_must eval "$ZPOOL history $TESTPOOL > $NEW_HISTORY"
+log_must $DIFF $OLD_HISTORY $NEW_HISTORY
+
+log_must $ZFS release tag $snap1
+
+log_pass "Verify 'zfs list|get|mount|unmount|share|unshare|send' passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_007_pos.ksh
new file mode 100755 (executable)
index 0000000..66d2191
--- /dev/null
@@ -0,0 +1,112 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/history/history_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify command history moves with pool while pool being migrated
+#
+# STRATEGY:
+#      1. Import uniform platform and cross platform pools
+#      2. Contract the command history of the imported pool
+#      3. Compare imported history log with the previous log.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $migratedpoolname &&  \
+               log_must $ZPOOL destroy -f $migratedpoolname
+
+       [[ -d $import_dir ]] && $RM -rf $import_dir
+}
+
+log_assert "Verify command history moves with migrated pool."
+log_onexit cleanup
+
+tst_dir=$STF_SUITE/tests/functional/history
+import_dir=$TESTDIR/importdir.$$
+migrated_cmds_f=$import_dir/migrated_history.$$
+migratedpoolname=$MIGRATEDPOOLNAME
+typeset -i RET=1
+typeset -i linenum=0
+
+[[ ! -d $import_dir ]] && log_must $MKDIR $import_dir
+
+# We test the migrations on both uniform platform and cross platform
+for arch in "i386" "sparc"; do
+       log_must $CP $tst_dir/${arch}.orig_history.txt $import_dir
+       orig_cmds_f=$import_dir/${arch}.orig_history.txt
+       # remove blank line
+       orig_cmds_f1=$import_dir/${arch}.orig_history_1.txt
+       $CAT $orig_cmds_f | $GREP -v "^$" > $orig_cmds_f1
+
+       log_must $CP $tst_dir/${arch}.migratedpool.DAT.Z $import_dir
+       log_must $UNCOMPRESS $import_dir/${arch}.migratedpool.DAT.Z
+
+       # destroy the pool with same name, so that import operation succeeds.
+       poolexists $migratedpoolname && \
+           log_must $ZPOOL destroy -f $migratedpoolname
+
+       log_must $ZPOOL import -d $import_dir $migratedpoolname
+       TZ=$TIMEZONE $ZPOOL history $migratedpoolname | $GREP -v "^$" \
+           >$migrated_cmds_f
+       RET=$?
+       (( $RET != 0 )) && log_fail "$ZPOOL histroy $migratedpoolname fails."
+
+       # The migrated history file should differ with original history file on
+       # two commands -- 'export' and 'import', which are included in migrated
+       # history file but not in original history file. so, check the two
+       # commands firstly in migrated history file and then delete them, and
+       # then compare this filtered file with the original history file. They
+       # should be identical at this time.
+       for subcmd in "export" "import"; do
+               $GREP "$subcmd" $migrated_cmds_f >/dev/null 2>&1
+               RET=$?
+               (( $RET != 0 )) && log_fail "zpool $subcmd is not logged for" \
+                   "the imported pool $migratedpoolname."
+       done
+
+       tmpfile=$import_dir/cmds_tmp.$$
+       linenum=`$CAT $migrated_cmds_f | $WC -l`
+       (( linenum = linenum - 2 ))
+       $HEAD -n $linenum $migrated_cmds_f > $tmpfile
+       log_must $DIFF $tmpfile $orig_cmds_f1
+
+       # cleanup for next loop testing
+       log_must $ZPOOL destroy -f $migratedpoolname
+       log_must $RM -f `$LS $import_dir`
+done
+
+log_pass "Verify command history moves with migrated pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_008_pos.ksh
new file mode 100755 (executable)
index 0000000..56df293
--- /dev/null
@@ -0,0 +1,74 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/history/history_common.kshlib
+
+#
+# DESCRIPTION:
+#      Pool history records all recursive operations.
+#
+# STRATEGY:
+#      1. Create a filesystem and several sub-filesystems in it.
+#      2. Make a recursive snapshot.
+#      3. Verify pool history records all the recursive operations.
+#      4. Do the same verification for hold, release, inherit, rollback and
+#         destroy.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if datasetexists $root_testfs; then
+               log_must $ZFS destroy -rf $root_testfs
+       fi
+       log_must $ZFS create $root_testfs
+}
+
+log_assert "Pool history records all recursive operations."
+log_onexit cleanup
+
+root_testfs=$TESTPOOL/$TESTFS
+fs1=$root_testfs/fs1; fs2=$root_testfs/fs2; fs3=$root_testfs/fs3
+for fs in $fs1 $fs2 $fs3; do
+       log_must $ZFS create $fs
+done
+
+run_and_verify "$ZFS snapshot -r $root_testfs@snap" "-i"
+run_and_verify "$ZFS hold -r tag $root_testfs@snap" "-i"
+run_and_verify "$ZFS release -r tag $root_testfs@snap" "-i"
+log_must $ZFS snapshot $root_testfs@snap2
+log_must $ZFS snapshot $root_testfs@snap3
+run_and_verify "$ZFS rollback -r $root_testfs@snap" "-i"
+run_and_verify "$ZFS inherit -r mountpoint $root_testfs" "-i"
+run_and_verify "$ZFS destroy -r $root_testfs" "-i"
+
+log_pass "Pool history records all recursive operations."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_009_pos.ksh
new file mode 100755 (executable)
index 0000000..8a10d16
--- /dev/null
@@ -0,0 +1,114 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/history/history_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify the delegation internal history are correctly.
+#
+# STRATEGY:
+#      1. Create test group and user.
+#      2. Define permission sets and verify the internal history correctly.
+#      3. Separately verify the internal history above is correct.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       del_user $HIST_USER
+       del_group $HIST_GROUP
+}
+
+log_assert "Verify delegated commands are logged in the pool history."
+log_onexit cleanup
+
+testfs=$TESTPOOL/$TESTFS
+# Create history test group and user and get user id and group id
+add_group $HIST_GROUP
+add_user $HIST_GROUP $HIST_USER
+
+#      subcmd          allow_options
+array=(        "allow"         "-s @basic snapshot"
+       "allow"         "-s @set @basic"
+       "allow"         "-c create"
+       "unallow"       "-c create"
+       "allow"         "-c @set"
+       "unallow"       "-c @set"
+       "allow"         "-l -u $HIST_USER snapshot"
+       "allow"         "-u $HIST_USER snapshot"
+       "unallow"       "-u $HIST_USER snapshot"
+       "allow"         "-l -u $HIST_USER @set"
+       "allow"         "-u $HIST_USER @set"
+       "unallow"       "-u $HIST_USER @set"
+       "allow"         "-d -u $HIST_USER snapshot"
+       "allow"         "-u $HIST_USER snapshot"
+       "unallow"       "-u $HIST_USER snapshot"
+       "allow"         "-d -u $HIST_USER @set"
+       "allow"         "-u $HIST_USER @set"
+       "unallow"       "-u $HIST_USER @set"
+       "allow"         "-l -g $HIST_GROUP snapshot"
+       "allow"         "-g $HIST_GROUP snapshot"
+       "unallow"       "-g $HIST_GROUP snapshot"
+       "allow"         "-l -g $HIST_GROUP @set"
+       "allow"         "-g $HIST_GROUP @set"
+       "unallow"       "-g $HIST_GROUP @set"
+       "allow"         "-d -g $HIST_GROUP snapshot"
+       "allow"         "-g $HIST_GROUP snapshot"
+       "unallow"       "-g $HIST_GROUP snapshot"
+       "allow"         "-d -g $HIST_GROUP @set"
+       "allow"         "-g $HIST_GROUP @set"
+       "unallow"       "-g $HIST_GROUP @set"
+       "allow"         "-l -e snapshot"
+       "allow"         "-e snapshot"
+       "unallow"       "-e snapshot"
+       "allow"         "-l -e @set"
+       "allow"         "-e @set"
+       "unallow"       "-e @set"
+       "allow"         "-d -e snapshot"
+       "allow"         "-e snapshot"
+       "unallow"       "-e snapshot"
+       "allow"         "-d -e @set"
+       "allow"         "-e @set"
+       "unallow"       "-e @set"
+)
+
+typeset -i i=0
+while ((i < ${#array[@]})); do
+       subcmd=${array[$i]}
+       options=${array[((i + 1))]}
+
+       run_and_verify "$ZFS $subcmd $options $testfs" "-i"
+       ((i += 2))
+done
+
+log_pass "Verify delegated commands are logged in the pool history."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/history/history_010_pos.ksh
new file mode 100755 (executable)
index 0000000..4c146d8
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/history/history_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify internal long history information are correct.
+#
+# STRATEGY:
+#      1. Create non-root test user and group.
+#      2. Do some zfs operations as a root and non-root user.
+#      3. Verify the long history information is correct.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       del_user $HIST_USER
+       del_group $HIST_GROUP
+       datasetexists $root_testfs && log_must $ZFS destroy -rf $root_testfs
+}
+
+log_assert "Verify internal long history information are correct."
+log_onexit cleanup
+
+root_testfs=$TESTPOOL/$TESTFS1
+
+# Create history test group and user and get user id and group id
+add_group $HIST_GROUP
+add_user $HIST_GROUP $HIST_USER
+
+run_and_verify "$ZFS create $root_testfs" "-l"
+run_and_verify "$ZFS allow $HIST_GROUP snapshot,mount $root_testfs" "-l"
+run_and_verify "$ZFS allow $HIST_USER destroy,mount $root_testfs" "-l"
+run_and_verify "$ZFS allow $HIST_USER reservation $root_testfs" "-l"
+run_and_verify "$ZFS allow $HIST_USER allow $root_testfs" "-l"
+run_and_verify -u "$HIST_USER" "$ZFS snapshot $root_testfs@snap" "-l"
+run_and_verify -u "$HIST_USER" "$ZFS destroy $root_testfs@snap" "-l"
+run_and_verify -u "$HIST_USER" "$ZFS set reservation=64M $root_testfs" "-l"
+run_and_verify -u "$HIST_USER" \
+    "$ZFS allow $HIST_USER reservation $root_testfs" "-l"
+run_and_verify "$ZFS unallow $HIST_USER create $root_testfs" "-l"
+run_and_verify "$ZFS unallow $HIST_GROUP snapshot $root_testfs" "-l"
+run_and_verify "$ZFS destroy -r $root_testfs" "-l"
+
+log_pass "Verify internal long history information pass."
diff --git a/zfs/tests/zfs-tests/tests/functional/history/history_common.kshlib b/zfs/tests/zfs-tests/tests/functional/history/history_common.kshlib
new file mode 100644 (file)
index 0000000..640666c
--- /dev/null
@@ -0,0 +1,421 @@
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/history/history.cfg
+
+function run_and_verify
+{
+       typeset user pool
+       while getopts "p:u:" opt; do
+               case $opt in
+               p)
+                       pool=$OPTARG
+                       ;;
+               u)
+                       user=$OPTARG
+                       ;;
+               esac
+       done
+       shift $(($OPTIND - 1))
+
+       pool=${pool:-$TESTPOOL}
+       user=${user:-"root"}
+       fullcmd="$1"
+       flags="$2"
+
+       if is_linux; then
+               histcmd=$($ECHO $fullcmd | $SED 's/^.*\/\(zpool .*\).*$/\1/')
+               histcmd=$($ECHO $histcmd | $SED 's/^.*\/\(zfs .*\).*$/\1/')
+       else
+               histcmd=$($ECHO $fullcmd | $SED 's/\/usr\/sbin\///g')
+       fi
+
+       cmd=$($ECHO $histcmd | $AWK '{print $1}')
+       subcmd=$($ECHO $histcmd | $AWK '{print $2}')
+
+       # If we aren't running zpool or zfs, something is wrong
+       [[ $cmd == "zpool" || $cmd == "zfs" ]] || \
+           log_fail "run_and_verify called with \"$cmd ($fullcmd)\""
+
+       # If this is a 'zfs receive' truncate the stdin redirect
+       [[ $subcmd == "receive" || $subcmd == "recv" ]] && \
+           histcmd=${histcmd%% <*}
+
+       # Run the command as the specified user, and find the new history.
+       $ZPOOL history $flags $pool > $OLD_HISTORY 2>/dev/null
+       if [[ $user == "root" ]]; then
+               log_must eval "$fullcmd"
+       else
+               log_must $SU $user -c "eval $fullcmd"
+       fi
+       $ZPOOL history $flags $pool > $TMP_HISTORY 2>/dev/null
+       $DIFF $OLD_HISTORY $TMP_HISTORY | $GREP "^> " | $SED 's/^> //g' \
+           > $NEW_HISTORY
+
+       # Verify what's common to every case, regardless of zpool history flags.
+       $GREP "$histcmd" $NEW_HISTORY >/dev/null 2>&1 || \
+           log_fail "Didn't find \"$histcmd\" in pool history"
+
+       # If 'zpool history' was called without any flags, then we're done.
+       [[ -z $flags ]] && return
+
+       # Verify the new history in cases that are more interesting because
+       # additional information is logged with -i or -l.
+
+       [[ $flags =~ "i" ]] && log_must verify_$subcmd "$histcmd" "$subcmd" \
+           "$flags"
+       [[ $flags =~ "l" ]] && log_must verify_long "$histcmd" "$user" "$flags"
+}
+
+function verify_long
+{
+       typeset cmd=$1
+       typeset user=$2
+       typeset flags=$3
+
+       [[ $flags =~ "l" ]] || return 1
+
+       typeset uid=$($ID -u $user)
+       typeset hname=$($HOSTNAME)
+       if ! is_global_zone; then
+               hname=$hname:$($ZONENAME)
+       fi
+
+       typeset suffix=""
+       if [ is_linux ]; then
+               suffix=":linux"
+       fi
+
+       $GREP "$cmd \[user $uid ($user) on $hname$suffix\]" \
+           $NEW_HISTORY >/dev/null 2>&1
+       if [[ $? != 0 ]]; then
+               log_note "Couldn't find long information for \"$cmd\""
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_hold
+{
+       typeset cmd=$1
+       typeset subcmd=$2
+       typeset flags=$3
+
+       [[ $flags =~ "i" ]] || return 1
+
+       typeset tag=$($ECHO $cmd | $AWK '{print $4}')
+       typeset fullname=${cmd##* }
+       typeset dsname=${fullname%%@*}
+       typeset snapname=${fullname##*@}
+
+       # This works whether or not the hold was recursive
+       for ds in $($ZFS list -r -Ho name -t snapshot $dsname | \
+           $GREP "@$snapname"); do
+               $GREP "$subcmd $ds ([0-9]*) tag=$tag" $NEW_HISTORY \
+                   >/dev/null 2>&1
+               if [[ $? != 0 ]]; then
+                       log_note "Didn't find hold on $ds with $tag"
+                       return 1
+               fi
+       done
+
+       return 0
+}
+
+function verify_release
+{
+       # hold and release formats only differ by the subcommand name, so
+       # simply reuse the hold function.
+       verify_hold "$1" "release" "$3"
+}
+
+function verify_rollback
+{
+       typeset cmd=$1
+       typeset flags=$3
+
+       [[ $flags =~ "i" ]] || return 1
+
+       typeset fullname=${cmd##* }
+       typeset dsname=${fullname%%@*}
+       typeset parent_fs=${dsname##*/}
+       typeset rb_fs=${dsname}/%rollback
+       typeset snapname=${fullname##*@}
+
+       $GREP "clone swap $rb_fs ([0-9]*) parent=$parent_fs" $NEW_HISTORY \
+           >/dev/null 2>&1
+       if [[ $? != 0 ]]; then
+               log_note "Didn't find rollback clone swap in pool history"
+               return 1
+       fi
+
+       $GREP "destroy $rb_fs" $NEW_HISTORY >/dev/null 2>&1
+       if [[ $? != 0 ]]; then
+               log_note "Didn't find rollback destroy in pool history"
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_inherit
+{
+       typeset cmd=$1
+       typeset flags=$3
+
+       [[ $flags =~ "i" ]] || return 1
+
+       typeset dsname=${cmd##* }
+       typeset prop=${cmd% *}
+       prop=${prop##* }
+
+       # This works whether or not the inherit was recursive
+       for ds in $($ZFS list -r -Ho name -t filesystem $dsname); do
+               $GREP "$subcmd $ds ([0-9]*) ${prop}=" $NEW_HISTORY >/dev/null \
+                   2>&1
+               if [[ $? != 0 ]]; then
+                       log_note "Didn't find inherit history for $ds"
+                       return 1
+               fi
+       done
+
+       return 0
+}
+
+function verify_allow
+{
+       typeset cmd=$1
+       typeset subcmd=$2
+       typeset flags=$3
+
+       [[ $flags =~ "i" ]] || return 1
+       [[ $subcmd == "allow" ]] && subcmd="update"
+       [[ $subcmd == "unallow" ]] && subcmd="remove"
+       typeset is_set lflag dflag dsname gname gid uname uid opt str code tmp
+
+       #
+       # Here, we determine three things:
+       # - Whether we're operating on a set or an indivdual permission (which
+       #   dictates the case of the first character in the code)
+       # - The name of the dataset we're operating on.
+       # - Whether the operation applies locally or to descendent datasets (or
+       #   both)
+       #
+       $ECHO $cmd  | $AWK '{i = NF - 1; print $i}' | $GREP '@' >/dev/null \
+           2>&1 && is_set=1
+       dsname=${cmd##* }
+       [[ $cmd =~ "-l " ]] && lflag=1
+       [[ $cmd =~ "-d " ]] && dflag=1
+       if [[ -z $lflag && -z $dflag ]]; then
+               lflag=1
+               dflag=1
+       fi
+
+       #
+       # For each of the five cases below, the operation is essentially the
+       # same. First, use the command passed in to determine what the code at
+       # the end of the pool history will be. The specifics of the code are
+       # described in a block comment at the top of dsl_deleg.c. Once that's
+       # been assembled, check for its presence in the history, and return
+       # success or failure accordingly.
+       #
+       if [[ $cmd =~ "-s " ]]; then
+               str="s-\$@"
+               [[ -n $is_set ]] && str="S-\$@"
+               tmp=${cmd#*@}
+               code="$str${tmp% *}"
+               $GREP "permission $subcmd $dsname ([0-9]*) $code" \
+                   $NEW_HISTORY >/dev/null 2>&1
+               if [[ $? != 0 ]]; then
+                        log_note "Couldn't find $code in $NEW_HISTORY"
+                        return 1
+                fi
+       elif [[ $cmd =~ "-c " ]]; then
+               str="c-\$"
+               [[ -n $is_set ]] && str="C-\$"
+               tmp=${cmd#*-c}
+               code="$str${tmp% *}"
+               $GREP "permission $subcmd $dsname ([0-9]*) $code" \
+                   $NEW_HISTORY >/dev/null 2>&1
+               if [ $? != 0 ]]; then
+                        log_note "Couldn't find $code in $NEW_HISTORY"
+                        return 1
+               fi
+       elif [[ $cmd =~ "-u " ]]; then
+               str="u"
+               [[ -n $is_set ]] && str="U"
+               tmp=${cmd##*-u }
+               opt=$($ECHO $tmp | $AWK '{print $2}')
+               uid=$($ID -u ${tmp%% *})
+               if [[ -n $lflag ]]; then
+                       code="${str}l\$$uid $opt"
+                       $GREP "permission $subcmd $dsname ([0-9]*) $code" \
+                           $NEW_HISTORY >/dev/null 2>&1
+                       if [ $? != 0 ]]; then
+                                log_note "Couldn't find $code in $NEW_HISTORY"
+                                return 1
+                       fi
+               fi
+               if [[ -n $dflag ]]; then
+                       code="${str}d\$$uid $opt"
+                       $GREP "permission $subcmd $dsname ([0-9]*) $code" \
+                           $NEW_HISTORY >/dev/null 2>&1
+                       if [ $? != 0 ]]; then
+                                log_note "Couldn't find $code in $NEW_HISTORY"
+                                return 1
+                       fi
+               fi
+       elif [[ $cmd =~ "-g " ]]; then
+               str="g"
+               [[ -n $is_set ]] && str="G"
+               tmp=${cmd##*-g }
+               opt=$($ECHO $tmp | $AWK '{print $2}')
+               gid=$($AWK -F: "/^${tmp%% *}:/ {print \$3}" /etc/group)
+               if [[ -n $lflag ]]; then
+                       code="${str}l\$$gid $opt"
+                       $GREP "permission $subcmd $dsname ([0-9]*) $code" \
+                           $NEW_HISTORY >/dev/null 2>&1
+                       if [ $? != 0 ]]; then
+                                log_note "Couldn't find $code in $NEW_HISTORY"
+                                return 1
+                       fi
+               fi
+               if [[ -n $dflag ]]; then
+                       code="${str}d\$$gid $opt"
+                       $GREP "permission $subcmd $dsname ([0-9]*) $code" \
+                           $NEW_HISTORY >/dev/null 2>&1
+                       if [ $? != 0 ]]; then
+                                log_note "Couldn't find $code in $NEW_HISTORY"
+                                return 1
+                       fi
+               fi
+       elif [[ $cmd =~ "-e " ]]; then
+               str="e"
+               [[ -n $is_set ]] && str="E"
+               opt=${cmd##*-e }
+               opt=${opt%% *}
+               if [[ -n $lflag ]]; then
+                       code="${str}l\$ $opt"
+                       $GREP "permission $subcmd $dsname ([0-9]*) $code" \
+                           $NEW_HISTORY >/dev/null 2>&1
+                       if [ $? != 0 ]]; then
+                                log_note "Couldn't find $code in $NEW_HISTORY"
+                                return 1
+                       fi
+               fi
+               if [[ -n $dflag ]]; then
+                       code="${str}d\$ $opt"
+                       $GREP "permission $subcmd $dsname ([0-9]*) $code" \
+                           $NEW_HISTORY >/dev/null 2>&1
+                       if [ $? != 0 ]]; then
+                                log_note "Couldn't find $code in $NEW_HISTORY"
+                                return 1
+                       fi
+               fi
+       else
+               log_note "Can't parse command \"$cmd\""
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_unallow
+{
+       #
+       # The unallow and allow history have the same format, except the former
+       # logs "permission removed" and the latter "permission updated" so
+       # simply reuse the allow function.
+       #
+       verify_allow "$1" "unallow" "$3"
+}
+
+function verify_destroy
+{
+       typeset cmd=$1
+       typeset flags=$3
+
+       # This function doesn't currently verifiy the zpool command.
+       [[ ${cmd%% *} == "zfs" ]] || return 1
+       [[ $flags =~ "i" ]] || return 1
+
+       typeset dsname=${cmd##* }
+       [[ $dsname =~ "@" ]] && typeset is_snap=1
+
+       if [[ -n $is_snap ]]; then
+               $GREP "ioctl destroy_snaps" $NEW_HISTORY >/dev/null 2>&1
+               if [[ $? != 0 ]]; then
+                       log_note "Didn't find ioctl while destroying $dsname"
+                       return 1
+               fi
+       fi
+
+       # This should be present for datasets and snapshots alike
+       $GREP "destroy $dsname" $NEW_HISTORY >/dev/null 2>&1
+       if [[ $? != 0 ]]; then
+               log_note "Didn't find \"destroy\" for $dsname"
+               return 1
+       fi
+
+       return 0
+}
+
+function verify_snapshot
+{
+       typeset cmd=$1
+       typeset flags=$3
+
+       [[ $flags =~ "i" ]] || return 1
+
+       typeset fullname=${cmd##* }
+       typeset dsname=${fullname%%@*}
+       typeset snapname=${fullname##*@}
+
+       $GREP "\[txg:[0-9]*\] $subcmd $fullname ([0-9]*)" $NEW_HISTORY \
+           >/dev/null 2>&1
+       if [[ $? != 0 ]]; then
+               log_note "Didn't find snapshot command for $fullname"
+               return 1
+       fi
+
+       # This works whether or not the snapshot was recursive
+       for ds in $($ZFS list -r -Ho name -t snapshot $dsname | \
+           $GREP "@$snapname"); do
+               $GREP "^[ ]* $ds$" $NEW_HISTORY >/dev/null 2>&1
+               if [[ $? != 0 ]]; then
+                       log_note "Didn't find \"ioctl snapshot\" for $ds"
+                       return 1
+               fi
+       done
+
+       return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/history/i386.migratedpool.DAT.Z b/zfs/tests/zfs-tests/tests/functional/history/i386.migratedpool.DAT.Z
new file mode 100644 (file)
index 0000000..21cd7fc
Binary files /dev/null and b/zfs/tests/zfs-tests/tests/functional/history/i386.migratedpool.DAT.Z differ
diff --git a/zfs/tests/zfs-tests/tests/functional/history/i386.orig_history.txt b/zfs/tests/zfs-tests/tests/functional/history/i386.orig_history.txt
new file mode 100644 (file)
index 0000000..148b825
--- /dev/null
@@ -0,0 +1,12 @@
+History for 'history_pool':
+2006-10-20.13:18:37 zpool create history_pool /var/tmp/i386.migratedpool.DAT
+2006-10-20.13:18:37 zfs create history_pool/fs
+2006-10-20.13:18:37 zfs set compression=on history_pool/fs
+2006-10-20.13:18:37 zfs set checksum=on history_pool
+2006-10-20.13:18:37 zfs snapshot history_pool/fs@snap
+2006-10-20.13:18:37 zfs clone history_pool/fs@snap history_pool/clone
+2006-10-20.13:18:37 zfs promote history_pool/clone
+2006-10-20.13:18:37 zfs promote history_pool/fs
+2006-10-20.13:18:37 zfs destroy -r -R history_pool/fs
+2006-10-20.13:18:37 zpool export history_pool
+2007-04-05.00:05:38 zpool upgrade history_pool
diff --git a/zfs/tests/zfs-tests/tests/functional/history/setup.ksh b/zfs/tests/zfs-tests/tests/functional/history/setup.ksh
new file mode 100755 (executable)
index 0000000..fc5cec3
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/history/sparc.migratedpool.DAT.Z b/zfs/tests/zfs-tests/tests/functional/history/sparc.migratedpool.DAT.Z
new file mode 100644 (file)
index 0000000..47a61ff
Binary files /dev/null and b/zfs/tests/zfs-tests/tests/functional/history/sparc.migratedpool.DAT.Z differ
diff --git a/zfs/tests/zfs-tests/tests/functional/history/sparc.orig_history.txt b/zfs/tests/zfs-tests/tests/functional/history/sparc.orig_history.txt
new file mode 100644 (file)
index 0000000..2d0e342
--- /dev/null
@@ -0,0 +1,12 @@
+History for 'history_pool':
+2006-10-27.03:13:47 zpool create history_pool /var/tmp/sparc.migratedpool.DAT
+2006-10-27.03:13:48 zfs create history_pool/fs
+2006-10-27.03:13:48 zfs set compression=on history_pool/fs
+2006-10-27.03:13:48 zfs set checksum=on history_pool
+2006-10-27.03:13:48 zfs snapshot history_pool/fs@snap
+2006-10-27.03:13:48 zfs clone history_pool/fs@snap history_pool/clone
+2006-10-27.03:13:49 zfs promote history_pool/clone
+2006-10-27.03:13:49 zfs promote history_pool/fs
+2006-10-27.03:13:49 zfs destroy -r -R history_pool/fs
+2006-10-27.03:13:49 zpool export history_pool
+2007-04-05.00:41:55 zpool upgrade history_pool
diff --git a/zfs/tests/zfs-tests/tests/functional/history/zfs-pool-v4.dat.Z b/zfs/tests/zfs-tests/tests/functional/history/zfs-pool-v4.dat.Z
new file mode 100644 (file)
index 0000000..bc32472
Binary files /dev/null and b/zfs/tests/zfs-tests/tests/functional/history/zfs-pool-v4.dat.Z differ
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/Makefile.am b/zfs/tests/zfs-tests/tests/functional/inheritance/Makefile.am
new file mode 100644 (file)
index 0000000..d07e2b1
--- /dev/null
@@ -0,0 +1,53 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/inheritance
+dist_pkgdata_SCRIPTS = \
+       inherit.kshlib \
+       cleanup.ksh \
+       inherit_001_pos.ksh \
+       config001.cfg \
+       config002.cfg \
+       config003.cfg \
+       config004.cfg \
+       config005.cfg \
+       config006.cfg \
+       config007.cfg \
+       config008.cfg \
+       config009.cfg \
+       config010.cfg \
+       config011.cfg \
+       config012.cfg \
+       config013.cfg \
+       config014.cfg \
+       config015.cfg \
+       config016.cfg \
+       config017.cfg \
+       config018.cfg \
+       config019.cfg \
+       config020.cfg \
+       config021.cfg \
+       config022.cfg \
+       config023.cfg \
+       config024.cfg \
+       state001.cfg \
+       state002.cfg \
+       state003.cfg \
+       state004.cfg \
+       state005.cfg \
+       state006.cfg \
+       state007.cfg \
+       state008.cfg \
+       state009.cfg \
+       state010.cfg \
+       state011.cfg \
+       state012.cfg \
+       state013.cfg \
+       state014.cfg \
+       state015.cfg \
+       state016.cfg \
+       state017.cfg \
+       state018.cfg \
+       state019.cfg \
+       state020.cfg \
+       state021.cfg \
+       state022.cfg \
+       state023.cfg \
+       state024.cfg
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/README.config b/zfs/tests/zfs-tests/tests/functional/inheritance/README.config
new file mode 100644 (file)
index 0000000..6e04a3f
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# 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.
+#
+# The configX.cfg files describe both the dataset hierarchy to
+# be created but also the initial source values for the datasets
+# properties, i.e. whether they should be left with their default values
+# or set locally.
+#
+# Format for this file is as follows:
+#      <dataset name>  <dataset type>  <inital property setting>
+#
+# <dataset name> - must be the full dataset name
+#
+# <dataset type> - recognised types are POOL, CTR and FS
+#
+#
+# <initial property setting> - can have one of the following
+# values:
+#
+#      default         property values are left unchanged
+#
+#      local           property values are set locally
+#
+#        -             property values are left unchanged (has the
+#                      same effect as 'default' but is used to indicate
+#                      that the property 'source' field may be 'inherited
+#                      from..' depending on the actions further up the
+#                      dataset hierarchy.
+#
+#
+# The configuration below creates a three tier dataset layout, consisting
+# of a pool, container and filesystem.
+#
+# The top tier pool's properties being set locally, and the two
+# lower tier properties each inheriting their values from the next tier
+# up.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     -
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/README.state b/zfs/tests/zfs-tests/tests/functional/inheritance/README.state
new file mode 100644 (file)
index 0000000..c1d3cc0
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# 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.
+#
+#
+# For every configX.cfg file there must be a corresponding stateX.cfg
+# file. The state file both drives the operations to be performed on the
+# dataset hierarchy which has been specified by the corresponding
+# configX.cfg file, and also specifies the expected state of the
+# properties after the operation has been completed.
+#
+# The format of the file is:
+#       <target dataset>:<command>
+#       <property source before command>        <property src after command>
+#       <property source before command>        <property src after command>
+#       ....                                    ....
+#       ....                                    ....
+#
+# <target dataset> - dataset upon which the <command> is to be executed. Can
+#                    be any of the datasets specified in the corresponding
+#                    configX.cfg file. If no command is to be executed
+#                    then must be set to '-'
+#
+#
+# <command>        - command to be executed upon the specified dataset.
+#                    Currently the only supported commands are 'inherit'
+#                    or 'inherit -r'. If no command is to be executed,
+#                    then must be set to '-'.
+#
+# <property src before command>
+#                  - the 'source' (as reported in 'zfs get') for the
+#                    the properties before <command> is executed. This
+#                    can be 'default', 'local' or the name of a dataset
+#                    from which the property is inherited. (The code
+#                    automatically adds in the 'inherited from..' part
+#                    of the string when doing the check.
+#
+#                    This field is for informational purposes only, to
+#                    aid the user in seeing how the changes trickle down
+#                    the data hierarchy.
+#
+# <property src after command>
+#                  - the expected value of the 'source' field after the
+#                    <command> has been executed on the <target dataset>.
+#                    As above can be 'default', 'local', or the dataset
+#                    from which the property is inherited.
+#
+# Two important things to note:
+# 1) there must be a <property src..> line corresponding to each dataset
+#    line specified in the configX.cfg file.
+#
+#
+# 2) There can be as many <command>/<property src> blocks as desired, but
+#    there must be at least one, and the effect of each block is cumulative
+#    (i.e. the properties are not reset back to their default values between
+#    each block. If that is desired then each block must be placed in its
+#    own state file with its own corresponding configX.cfg file).
+#
+#
+# Below are two sample <command>/<property src> blocks.
+#
+# The first simply verifies that the properties on the top level dataset
+# were set locally, and that the middle and bottom datasets properties
+# were inherited from the top level pool (called TESTPOOL). Note the '-:-'
+# which means that no command is to be executed, but simply that the
+# properties settings are to be verified.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+-:-
+#
+local                           local
+TESTPOOL                        TESTPOOL
+TESTPOOL                        TESTPOOL
+#
+#
+# The block below describes the expected state of the properties after
+# an 'inherit -r' command has been run on the top level pool (called
+# TESTPOOL).
+#
+TESTPOOL:inherit -r
+#
+local                          default
+TESTPOOL                       default
+TESTPOOL                       default
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/inheritance/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3c631a2
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. ${STF_SUITE}/include/libtest.shlib
+
+$RM -rf $TESTDIR.*
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config001.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config001.cfg
new file mode 100644 (file)
index 0000000..23616cb
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     -
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config002.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config002.cfg
new file mode 100644 (file)
index 0000000..3129411
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config003.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config003.cfg
new file mode 100644 (file)
index 0000000..57a73b9
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     default
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config004.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config004.cfg
new file mode 100644 (file)
index 0000000..1052526
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config005.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config005.cfg
new file mode 100644 (file)
index 0000000..d15beb2
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config006.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config006.cfg
new file mode 100644 (file)
index 0000000..a059d17
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     -
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config007.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config007.cfg
new file mode 100644 (file)
index 0000000..b416c9f
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config008.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config008.cfg
new file mode 100644 (file)
index 0000000..4f7e7b0
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     default
+TESTPOOL/TESTCTR/TESTFS1        FS      default
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config009.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config009.cfg
new file mode 100644 (file)
index 0000000..4f7e7b0
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     default
+TESTPOOL/TESTCTR/TESTFS1        FS      default
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config010.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config010.cfg
new file mode 100644 (file)
index 0000000..4f7e7b0
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     default
+TESTPOOL/TESTCTR/TESTFS1        FS      default
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config011.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config011.cfg
new file mode 100644 (file)
index 0000000..57a73b9
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     default
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config012.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config012.cfg
new file mode 100644 (file)
index 0000000..57a73b9
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     default
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config013.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config013.cfg
new file mode 100644 (file)
index 0000000..1052526
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config014.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config014.cfg
new file mode 100644 (file)
index 0000000..1052526
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config015.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config015.cfg
new file mode 100644 (file)
index 0000000..3129411
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config016.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config016.cfg
new file mode 100644 (file)
index 0000000..3129411
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    default
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config017.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config017.cfg
new file mode 100644 (file)
index 0000000..d15beb2
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config018.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config018.cfg
new file mode 100644 (file)
index 0000000..d15beb2
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config019.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config019.cfg
new file mode 100644 (file)
index 0000000..23616cb
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     -
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config020.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config020.cfg
new file mode 100644 (file)
index 0000000..23616cb
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     -
+TESTPOOL/TESTCTR/TESTFS1        FS      -
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config021.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config021.cfg
new file mode 100644 (file)
index 0000000..a059d17
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     -
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config022.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config022.cfg
new file mode 100644 (file)
index 0000000..a059d17
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     -
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config023.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config023.cfg
new file mode 100644 (file)
index 0000000..b416c9f
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/config024.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/config024.cfg
new file mode 100644 (file)
index 0000000..b416c9f
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+TESTPOOL                        POOL    local
+TESTPOOL/TESTCTR                CTR     local
+TESTPOOL/TESTCTR/TESTFS1        FS      local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/inherit.kshlib b/zfs/tests/zfs-tests/tests/functional/inheritance/inherit.kshlib
new file mode 100644 (file)
index 0000000..cee0cfd
--- /dev/null
@@ -0,0 +1,114 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+#
+# Simple function to get the source of the specified property.
+# If unable to get the property then exits.
+#
+function get_prop_src # property dataset
+{
+        typeset prop_val
+        typeset prop=$1
+        typeset dataset=$2
+
+       prop_val=`$ZFS get -H -o source $prop $dataset`
+
+        if [[ $? -ne 0 ]]; then
+                log_fail "Unable to determine the source of $prop " \
+                        "property for dataset $dataset"
+        else
+                echo $prop_val
+        fi
+}
+
+#
+# Function to check the 'source' of a property. The source can
+# either be "default", "local", or "inherited from <parent dataset>".
+#
+# The 'expected src' argument must be either "default", "local", or
+# a dataset name.
+#
+# Returns 0 on success, 1 on failure.
+#
+function verify_prop_src # child_dataset property expected_src
+{
+        typeset target=$1
+        typeset prop=$2
+        typeset expected=$3
+
+        prop_src=`get_prop_src $prop $target`
+
+       #
+       # Rather than just checking if $prop_src == $expected
+       # we first determine what value $expected should have.
+       # This allows us to catch the case where a property
+       # has a source of "local" but we expected it to be
+       # "default"
+       #
+       if [[ $expected == "default" ]]; then
+               if [[ $prop_src != $expected ]]; then
+                       log_note "Property $prop of $target has source"\
+                               " $prop_src rather than $expected"
+                       return 1
+               fi
+       elif [[ $expected == "local" ]]; then
+               if [[ $prop_src != $expected ]]; then
+                       log_note "Property $prop of $target has source"\
+                               " $prop_src rather than $expected"
+                       return 1
+               fi
+       elif [[ $prop_src != "inherited from $expected" ]]; then
+               log_note "Property $prop of $expected has source $prop_src"\
+                       " rather than 'inherited from $expected'"
+                return 1
+       fi
+
+       return 0
+}
+
+#
+# Simple function to set a property to a
+# specified value and verify it has changed
+# correctly.
+#
+function set_n_verify_prop #property value dataset
+{
+       typeset prop=$1
+       typeset prop_val=$2
+       typeset dataset=$3
+
+       $ZFS set $prop=$prop_val $dataset
+       check_val=`get_prop $prop $dataset`
+
+       if [[ $check_val != $prop_val ]]; then
+               log_fail "Property $prop of $dataset has value $check_val"\
+                       " rather than $prop_val"
+       fi
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inheritance/inherit_001_pos.ksh
new file mode 100755 (executable)
index 0000000..6677d11
--- /dev/null
@@ -0,0 +1,456 @@
+#! /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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inheritance/inherit.kshlib
+
+#
+# DESCRIPTION:
+# Test that properties are correctly inherited using 'zfs set',
+# 'zfs inherit' and 'zfs inherit -r'.
+#
+# STRATEGY:
+# 1) Read a configX.cfg file and create the specified datasets
+# 2) Read a stateX.cfg file and execute the commands within it
+# and verify that the properties have the correct values
+# 3) Repeat steps 1-2 for each configX and stateX files found.
+#
+
+verify_runnable "global"
+
+log_assert "Test properties are inherited correctly"
+
+#
+# Simple function to create specified datasets.
+#
+function create_dataset { #name type disks
+       typeset dataset=$1
+       typeset type=$2
+       typeset disks=$3
+
+       if [[ $type == "POOL" ]]; then
+               create_pool "$dataset" "$disks"
+       elif [[ $type == "CTR" ]]; then
+               log_must $ZFS create $dataset
+               log_must $ZFS set canmount=off $dataset
+       elif [[ $type == "FS" ]]; then
+               log_must $ZFS create $dataset
+       else
+               log_fail "Unrecognised type $type"
+       fi
+
+       list="$list $dataset"
+}
+
+#
+# Function to walk through all the properties in a
+# dataset, setting them to a 'local' value if required.
+#
+function init_props { #dataset init_code
+       typeset dataset=$1
+       typeset init_code=$2
+       typeset dir=$3
+
+       typeset -i i=0
+
+       #
+       # Though the effect of '-' and 'default' is the same we
+       # call them out via a log_note to aid in debugging the
+       # config files
+       #
+       if [[ $init_code == "-" ]]; then
+               log_note "Leaving properties for $dataset unchanged."
+               [[ $def_recordsize == 0 ]] && \
+                   update_recordsize $dataset $init_code
+               return;
+       elif [[ $init_code == "default" ]]; then
+               log_note "Leaving properties for $dataset at default values."
+               [[ $def_recordsize == 0 ]] && \
+                   update_recordsize $dataset $init_code
+               return;
+       elif [[ $init_code == "local" ]]; then
+               log_note "Setting properties for $dataset to local values."
+               while (( i <  ${#prop[*]} )); do
+                       if [[ ${prop[i]} == "recordsize" ]]; then
+                               update_recordsize $dataset $init_code
+                       else
+                               if [[ ${prop[i]} == "mountpoint" ]]; then
+                                       set_n_verify_prop ${prop[i]} \
+                                           ${local_val[((i/2))]}.$dir $dataset
+                               else
+                                       set_n_verify_prop ${prop[i]} \
+                                           ${local_val[((i/2))]} $dataset
+                               fi
+                       fi
+
+                       ((i = i + 2))
+               done
+       else
+               log_fail "Unrecognised init code $init_code"
+       fi
+}
+
+#
+# We enter this function either to update the recordsize value
+# in the default array, or to update the local value array.
+#
+function update_recordsize { #dataset init_code
+       typeset dataset=$1
+       typeset init_code=$2
+       typeset idx=0
+       typeset record_val
+
+       #
+       # First need to find where the recordsize property is
+       # located in the arrays
+       #
+       while (( idx <  ${#prop[*]} )); do
+               [[ ${prop[idx]} == "recordsize" ]] && break
+
+               ((idx = idx + 2))
+       done
+
+       ((idx = idx / 2))
+       record_val=`get_prop recordsize $dataset`
+       if [[ $init_code == "-" || $init_code == "default" ]]; then
+               def_val[idx]=$record_val
+               def_recordsize=1
+       elif [[ $init_code == "local" ]]; then
+               log_must $ZFS set recordsize=$record_val $dataset
+               local_val[idx]=$record_val
+       fi
+}
+
+#
+# The mountpoint property is slightly different from other properties and
+# so is handled here. For all other properties if they are set to a specific
+# value at a higher level in the data hierarchy (i.e. checksum=on) then that
+# value propogates down the hierarchy unchanged, with the source field being
+# set to 'inherited from <higher dataset>'.
+#
+# The mountpoint property is different in that while the value propogates
+# down the hierarchy, the value at each level is determined by a combination
+# of the top-level value and the current level in the hierarchy.
+#
+# For example consider the case where we have a pool (called pool1), containing
+# a dataset (ctr) which in turn contains a filesystem (fs). If we set the
+# mountpoint of the pool to '/mnt2' then the mountpoints for the dataset and
+# filesystem are '/mnt2/ctr' and /mnt2/ctr/fs' respectively, with the 'source'
+# field being set to 'inherited from pool1'.
+#
+# So at the filesystem level to calculate what our mountpoint property should
+# be set to we walk back up the hierarchy sampling the mountpoint property at
+# each level and forming up the expected mountpoint value piece by piece until
+# we reach the level specified in the 'source' field, which in this example is
+# the top-level pool.
+#
+function get_mntpt_val #dataset src index
+{
+       typeset dataset=$1
+       typeset src=$2
+       typeset idx=$3
+       typeset new_path=""
+       typeset dset
+       typeset mntpt=""
+
+       if [[ $src == "local" ]]; then
+               # Extract mount points specific to datasets
+               if [[ $dataset == "TESTPOOL" ]]; then
+                       mntpt=${local_val[idx]}.1
+               elif [[ $dataset == "TESTPOOL/TESTCTR" ]]; then
+                       mntpt=${local_val[idx]}.2
+               else
+                       mntpt=${local_val[idx]}.3
+               fi
+       elif [[ $src == "default" ]]; then
+               mntpt="/$dataset"
+       else
+               # Walk back up the hierarchy building up the
+               # expected mountpoint property value.
+               obj_name=${dataset##*/}
+
+               while [[ $src != $dataset ]]; do
+                       dset=${dataset%/*}
+
+                       mnt_val=`get_prop mountpoint $dset`
+
+                       mod_prop_val=${mnt_val##*/}
+                       new_path="/"$mod_prop_val$new_path
+                       dataset=$dset
+               done
+
+               mntpt=$new_path"/"$obj_name
+       fi
+       echo $mntpt
+}
+
+#
+# Simple function to verify that a property has the
+# expected value.
+#
+function verify_prop_val #property dataset src index
+{
+       typeset prop=$1
+       typeset dataset=$2
+       typeset src=$3
+       typeset idx=$4
+       typeset new_path=""
+       typeset dset
+       typeset exp_val
+       typeset prop_val
+
+       prop_val=`get_prop $prop $dataset`
+
+       # mountpoint property is handled as a special case
+       if [[ $prop == "mountpoint" ]]; then
+               exp_val=`get_mntpt_val $dataset $src $idx`
+       else
+               if [[ $src == "local" ]]; then
+                       exp_val=${local_val[idx]}
+               elif [[ $src == "default" ]]; then
+                       exp_val=${def_val[idx]}
+               else
+                       #
+                       # We are inheriting the value from somewhere
+                       # up the hierarchy.
+                       #
+                       exp_val=`get_prop $prop $src`
+               fi
+       fi
+
+       if [[ $prop_val != $exp_val ]]; then
+               # After putback PSARC/2008/231 Apr,09,2008,
+               # the default value of aclinherit has changed to be
+               # 'restricted' instead of 'secure',
+               # but the old interface of 'secure' still exist
+
+               if [[ $prop != "aclinherit" || \
+                   $exp_val != "secure" || \
+                   $prop_val != "restricted" ]]; then
+
+                       log_fail "$prop of $dataset is [$prop_val] rather "\
+                           "than [$exp_val]"
+               fi
+       fi
+}
+
+#
+# Function to read the configX.cfg files and create the specified
+# dataset hierarchy
+#
+function scan_config { #config-file
+       typeset config_file=$1
+
+       DISK=${DISKS%% *}
+
+       list=""
+       typeset -i mount_dir=1
+
+       grep "^[^#]" $config_file | {
+               while read name type init ; do
+                       create_dataset $name $type $DISK
+                       init_props $name $init $mount_dir
+                       ((mount_dir = mount_dir + 1))
+               done
+       }
+}
+
+#
+# Function to check an exit flag, calling log_fail if that exit flag
+# is non-zero. Can be used from code that runs in a tight loop, which
+# would otherwise result in a lot of journal output.
+#
+function check_failure { # int status, error message to use
+
+       typeset -i exit_flag=$1
+       error_message=$2
+
+       if [[ $exit_flag -ne 0 ]]; then
+               log_fail "$error_message"
+       fi
+}
+
+
+#
+# Main function. Executes the commands specified in the stateX.cfg
+# files and then verifies that all the properties have the correct
+# values and 'source' fields.
+#
+function scan_state { #state-file
+       typeset state_file=$1
+       typeset -i i=0
+       typeset -i j=0
+
+       log_note "Reading state from $state_file"
+
+       while ((i <  ${#prop[*]})); do
+               grep "^[^#]" $state_file | {
+                       while IFS=: read target op; do
+                               #
+                               # The user can if they wish specify that no
+                               # operation be performed (by specifying '-'
+                               # rather than a command). This is not as
+                               # useless as it sounds as it allows us to
+                               # verify that the dataset hierarchy has been
+                               # set up correctly as specified in the
+                               # configX.cfg file (which includes 'set'ting
+                               # properties at a higher level and checking
+                               # that they propogate down to the lower levels.
+                               #
+                               # Note in a few places here, we use
+                               # check_failure, rather than log_must - this
+                               # substantially reduces journal output.
+                               #
+                               if [[ $op == "-" ]]; then
+                                       log_note "No operation specified"
+                               else
+                                       export __ZFS_POOL_RESTRICT="$TESTPOOL"
+                                       log_must $ZFS unmount -a
+                                       unset __ZFS_POOL_RESTRICT
+
+                                       for p in ${prop[i]} ${prop[((i+1))]}; do
+                                               $ZFS $op $p $target
+                                               ret=$?
+                                               check_failure $ret "$ZFS $op $p \
+                                                   $target"
+                                       done
+                               fi
+                               for check_obj in $list; do
+                                       read init_src final_src
+
+                                       for p in ${prop[i]} ${prop[((i+1))]}; do
+                                       # check_failure to keep journal small
+                                               verify_prop_src $check_obj $p \
+                                                   $final_src
+                                               ret=$?
+                                               check_failure $ret "verify" \
+                                                   "_prop_src $check_obj $p" \
+                                                   "$final_src"
+
+                                       # Again, to keep journal size down.
+                                               verify_prop_val $p $check_obj \
+                                                   $final_src $j
+                                               ret=$?
+                                               check_failure $ret "verify" \
+                                                   "_prop_val $check_obj $p" \
+                                                   "$final_src"
+                                       done
+                               done
+                       done
+               }
+               ((i = i + 2))
+               ((j = j + 1))
+       done
+}
+
+#
+# Note except for the mountpoint default value (which is handled in
+# the routine itself), each property specified in the 'prop' array
+# above must have a corresponding entry in the two arrays below.
+#
+if is_linux; then
+       set -A prop "checksum" "" \
+               "compression" "compress" \
+               "atime" "" \
+               "devices" "" \
+               "exec" "" \
+               "setuid" "" \
+               "recordsize" "recsize" \
+               "snapdir" "" \
+               "acltype"
+
+       set -A def_val "on" "off" "on" "on" "on" \
+               "on" "" \
+               "hidden" "off"
+
+       set -A local_val "off" "on" "off" "off" "off" \
+               "off" "" \
+               "visible" "off"
+else
+       set -A prop "checksum" "" \
+               "compression" "compress" \
+               "atime" "" \
+               "devices" "" \
+               "exec" "" \
+               "setuid" "" \
+               "sharenfs", "" \
+               "recordsize" "recsize" \
+               "mountpoint" "" \
+               "snapdir" "" \
+               "aclmode", "" \
+               "aclinherit" "" \
+               "readonly" "rdonly"
+
+       set -A def_val "on" "off" "on" "on" "on" \
+               "on" "off" "" \
+               "" "hidden" "discard" "secure" \
+               "off"
+
+       set -A local_val "off" "on" "off" "off" "off" \
+               "off" "on" "" \
+               "$TESTDIR" "visible" "groupmask" "discard" \
+               "off"
+fi
+
+
+#
+# Global flag indicating whether the default record size had been
+# read.
+#
+typeset def_recordsize=0
+
+set -A config_files $(ls $STF_SUITE/tests/functional/inheritance/config*[1-9]*.cfg)
+set -A state_files $(ls $STF_SUITE/tests/functional/inheritance/state*.cfg)
+
+#
+# Global list of datasets created.
+#
+list=""
+
+typeset -i k=0
+
+if [[ ${#config_files[*]} != ${#state_files[*]} ]]; then
+       log_fail "Must have the same number of config files " \
+           " (${#config_files[*]}) and state files ${#state_files[*]}"
+fi
+
+while ((k < ${#config_files[*]})); do
+       default_cleanup_noexit
+       def_recordsize=0
+
+       log_note "Testing configuration ${config_files[k]}"
+
+       scan_config ${config_files[k]}
+       scan_state ${state_files[k]}
+
+       ((k = k + 1))
+done
+
+log_pass "Properties correctly inherited as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state001.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state001.cfg
new file mode 100644 (file)
index 0000000..68e4379
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# No command is actually run (hence '-:-') but rather this state file is
+# used to verify that the property that was set on the top level pool
+# via the 'local' keyword (in the config1.cfg file) has correctly
+# propogated down the hierarchy.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+-:-
+#
+local                           local
+TESTPOOL                        TESTPOOL
+TESTPOOL                        TESTPOOL
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state002.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state002.cfg
new file mode 100644 (file)
index 0000000..c3b9b15
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# No command is actually run (hence '-:-') but rather this state file is
+# used to verify that the property that was set on the middle level
+# dataset via the 'local' keyword (in the configX.cfg file) has
+# correctly propogated down the hierarchy to the filesystem underneath,
+# while leaving the top level pools properties unchanged.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+-:-
+#
+default                                default
+local                           local
+TESTPOOL/TESTCTR               TESTPOOL/TESTCTR
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state003.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state003.cfg
new file mode 100644 (file)
index 0000000..5780065
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# No command is actually run (hence '-:-') but rather this state file is
+# used to verify that setting the filesystem's properties does not affect
+# the properties of datasets above it in the hierarchy.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+-:-
+#
+default                                default
+default                                default
+local                           local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state004.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state004.cfg
new file mode 100644 (file)
index 0000000..e62979a
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# No command is actually run (hence '-:-') but rather this state file is
+# used to verify that setting a property on a middle level dataset does
+# not prevent us from setting a property on the bottom level filesystem,
+# and that neither affects the top level pools properties.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+-:-
+#
+default                                default
+local                           local
+local                           local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state005.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state005.cfg
new file mode 100644 (file)
index 0000000..097459f
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# No command is actually run (hence '-:-') but rather this state file is
+# used to verify that when we set a property on a top level pool, followed
+# by a middle level dataset, that the bottom level filesystem inherits
+# the property from the middle level dataset, and not from the top level
+# pool.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+-:-
+#
+local                           local
+local                           local
+TESTPOOL/TESTCTR               TESTPOOL/TESTCTR
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state006.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state006.cfg
new file mode 100644 (file)
index 0000000..9863b29
--- /dev/null
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# No command is actually run (hence '-:-') but rather this state file is
+# used to verify that when we set a property on a top level pool, followed
+# by a bottom level filesystem, that the middle level dataset inherits
+# the property from the top level pool, and not from the bottom level
+# filesystem.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+-:-
+#
+# <prop src before cmd>                <prop src after cmd>
+#
+local                           local
+TESTPOOL                       TESTPOOL
+local                           local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state007.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state007.cfg
new file mode 100644 (file)
index 0000000..731ec95
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# No command is actually run (hence '-:-') but rather this state file is
+# used to verify that when we can set properties on each level of the
+# hierarchy independently.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+-:-
+#
+# <prop src before cmd>         <prop src after cmd>
+#
+local                           local
+local                           local
+local                           local
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state008.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state008.cfg
new file mode 100644 (file)
index 0000000..7385c98
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# No command is actually run (hence '-:-') but rather this state file is
+# used to verify that when we create a dataset hierarchy that the
+# properties of each dataset have their default values.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+-:-
+#
+# <prop src before cmd>         <prop src after cmd>
+default                                default
+default                                default
+default                                default
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state009.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state009.cfg
new file mode 100644 (file)
index 0000000..3fb2841
--- /dev/null
@@ -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) 2013 by Delphix. All rights reserved.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit' at different levels of a
+# data hierarchy where the properties of each dataset have their
+# default values leaves the values unchanged.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit
+#
+default                                default
+default                                default
+default                                default
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                                default
+default                                default
+default                                default
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state010.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state010.cfg
new file mode 100644 (file)
index 0000000..4c51e80
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit -r' at different levels of a
+# data hierarchy where the properties of each dataset have their
+# default values leaves the values unchanged.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+TESTPOOL:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
+TESTPOOL/TESTCTR:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state011.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state011.cfg
new file mode 100644 (file)
index 0000000..f6e791e
--- /dev/null
@@ -0,0 +1,58 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that running 'zfs inherit' at each level of the data hierarchy
+# when the bottom filesystem level properties have been set locally has
+# no effect except at the bottom level where the property values are
+# inherited from the middle level dataset.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit
+#
+default                                default
+default                                default
+local                          local
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                                default
+default                                default
+local                          local
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                                default
+default                                default
+local                          default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state012.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state012.cfg
new file mode 100644 (file)
index 0000000..6f3f389
--- /dev/null
@@ -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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that running 'zfs inherit -r' at each level of the data hierarchy
+# when the bottom filesystem level properties have been set locally results
+# in the top level property values being propogated down the data
+# hierarchy.
+#
+# Executing inherit -r at the middle level and bottom levels after
+# running it at the top level is somewhat redundant as the top level value
+# should propogate down the entire data hierarchy. Done for completeness
+# sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+TESTPOOL:inherit -r
+#
+default                                default
+default                                default
+local                          default
+#
+TESTPOOL/TESTCTR:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state013.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state013.cfg
new file mode 100644 (file)
index 0000000..ae59192
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit' on each level when the middle
+# and bottom levels properties are set locally results in the middle and
+# bottom levels inheriting values from the next level up in the hierarchy.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+TESTPOOL:inherit
+#
+default                                default
+local                          local
+local                          local
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                                default
+local                          default
+local                          local
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                                default
+default                                default
+local                          default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state014.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state014.cfg
new file mode 100644 (file)
index 0000000..3322123
--- /dev/null
@@ -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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that running 'zfs inherit -r' at each level of the data hierarchy
+# when the bottom and middle level properties have been set locally results
+# in the top level property values being propogated down the data
+# hierarchy.
+#
+# Note : executing inherit -r at the middle level and bottom levels after
+# running it at the top level is somewhat redundant as the top level value
+# should propogate down the entire data hierarchy. Done for completeness
+# sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+TESTPOOL:inherit -r
+#
+default                                default
+local                          default
+local                          default
+#
+TESTPOOL/TESTCTR:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state015.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state015.cfg
new file mode 100644 (file)
index 0000000..bab7bc2
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit' at the top level in the hierarchy
+# when the middle level properties are set locally, and the bottom
+# level has inherited its value from the middle level, results in no change
+# to the top level properties.
+#
+# Executing 'zfs inherit' at the middle level results in the middle level
+# inheriting its value from the top level, and passing the values down to
+# the bottom level.
+#
+# Executing 'zfs inherit' at the bottom level is somewhat redundant but
+# is done for completness sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit
+#
+default                         default
+local                           local
+TESTPOOL/TESTCTR                TESTPOOL/TESTCTR
+#
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                         default
+local                           default
+TESTPOOL/TESTCTR                default
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                         default
+default                         default
+default                         default
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state016.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state016.cfg
new file mode 100644 (file)
index 0000000..50601c6
--- /dev/null
@@ -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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit -r' at the top level in the hierarchy
+# when the middle level properties are set locally, and the bottom
+# level has inherited its value from the middle level, results in no change
+# to the top level properties and the middle and bottom properties changing
+# to the top level (default) values.
+#
+# Executing 'zfs inherit -r' at the bottom and middle levels after executing
+# at the top level is somewhat redundant but ss done for completness sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit -r
+#
+default                                default
+local                          default
+TESTPOOL                       default
+#
+TESTPOOL/TESTCTR:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state017.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state017.cfg
new file mode 100644 (file)
index 0000000..a4a127d
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit' at the top level in the hierarchy
+# when the top level and middle level datasets properties are set locally,
+# and the bottom level has inherited its properties from the middle
+# level, results in the top level properties reverting back to their
+# default values.
+#
+# Executing 'zfs inherit' at the middle level results in the middle level
+# inheriting its value from the top level (which is now default), and passing
+# the values down to the bottom level.
+#
+# Executing 'zfs inherit' at the bottom level is somewhat redundant but
+# is done for completness sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit
+#
+local                           default
+local                           local
+TESTPOOL/TESTCTR                TESTPOOL/TESTCTR
+#
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                         default
+local                           default
+TESTPOOL/TESTCTR                default
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                         default
+default                         default
+default                         default
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state018.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state018.cfg
new file mode 100644 (file)
index 0000000..b76bbac
--- /dev/null
@@ -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 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit -r' at the top level in the hierarchy
+# when the top level and middle level datasets properties are set locally,
+# and the bottom level has inherited its properties from the middle
+# level, results in the top level properties reverting back to their
+# default values and being propogated down to the other datasets in the
+# hierarchy.
+#
+# Executing 'zfs inherit -r' at the middle and bottom levels after executing
+# it at the top level is somewhat redundant but is done for completness sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit -r
+#
+local                          default
+local                          default
+TESTPOOL/TESTCTR               default
+#
+#
+TESTPOOL/TESTCTR:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                                default
+default                                default
+default                                default
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state019.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state019.cfg
new file mode 100644 (file)
index 0000000..652d3b1
--- /dev/null
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit' at the top level in the hierarchy
+# when the top level properties are set locally and the middle and bottom
+# datasets have inherited from the top level, results in the top level
+# properties reverting back to their default values, the middle and bottom
+# levels inheriting the changed values.
+#
+# Executing 'zfs inherit' at the middle and bottom levels is somewhat
+# redundant but is done for completness sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+TESTPOOL:inherit
+#
+local                          default
+TESTPOOL                       default
+TESTPOOL                       default
+#
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                                default
+default                                default
+default                                default
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state020.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state020.cfg
new file mode 100644 (file)
index 0000000..fc869f8
--- /dev/null
@@ -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 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit -r' at the top level in the hierarchy
+# when the top level properties are set locally and the middle and bottom
+# datasets have inherited from the top level, results in the top level
+# properties reverting back to their default values, the middle and bottom
+# levels inheriting the changed values.
+#
+# Executing 'zfs inherit -r' at the middle and bottom levels is somewhat
+# redundant but is done for completness sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit -r
+#
+local                          default
+TESTPOOL                       default
+TESTPOOL                       default
+#
+#
+TESTPOOL/TESTCTR:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state021.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state021.cfg
new file mode 100644 (file)
index 0000000..f61472e
--- /dev/null
@@ -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 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit' at the top level in the hierarchy
+# when the top level and bottom level properties are set locally and the
+# middle dataset has inherited from the top level, results in the top level
+# properties reverting back to their default values, and the middle level
+# inheriting the new top level value.
+#
+# Executing 'zfs inherit' at the bottom level results in it inheriting
+# the middle level values.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit
+#
+local                          default
+TESTPOOL                       default
+local                          local
+#
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                                default
+default                                default
+local                          local
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                                default
+default                                default
+local                          default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state022.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state022.cfg
new file mode 100644 (file)
index 0000000..a00f3bb
--- /dev/null
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit -r' at the top level in the hierarchy
+# when the top level and bottom level properties are set locally and the
+# middle dataset has inherited from the top level, results in the top level
+# properties reverting back to their default values, the middle and bottom
+# levels inheriting the changed values.
+#
+# Executing 'zfs inherit -r' at the middle and bottom levels is somewhat
+# redundant but is done for completness sake.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+TESTPOOL:inherit -r
+#
+local                          default
+TESTPOOL                       default
+local                          default
+#
+#
+TESTPOOL/TESTCTR:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit -r
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state023.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state023.cfg
new file mode 100644 (file)
index 0000000..8219a2a
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit' at the top level in the hierarchy
+# when each levels properties are set locally, results in the top level
+# properties reverting back to their default values.
+#
+# Executing 'zfs inherit' at the middle level results in it inheriting
+# the top levels (now default) values
+#
+# Executing 'zfs inherit' at the bottom level results in it inheriting
+# the middle levels (now default) values
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit
+#
+local                          default
+local                          local
+local                          local
+#
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                                default
+local                          default
+local                          local
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                                default
+default                                default
+local                          default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inheritance/state024.cfg b/zfs/tests/zfs-tests/tests/functional/inheritance/state024.cfg
new file mode 100644 (file)
index 0000000..22d605c
--- /dev/null
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+
+# *** ASSERTION DESCRIPTION ***
+#
+# Verify that executing 'zfs inherit -r' at the top level in the hierarchy
+# when each levels properties are set locally, results in the top level
+# properties reverting back to their default values, and the changed
+# values being propogated down the hierarchy.
+#
+# Executing 'zfs inherit -r' at the middle and bottom levels after doing so
+# at the top level is somewhat redundant but is done for completeness.
+#
+# *** ASSERTION DESCRIPTION ***
+#
+#
+TESTPOOL:inherit -r
+#
+local                          default
+local                          default
+local                          default
+#
+#
+TESTPOOL/TESTCTR:inherit
+#
+default                                default
+default                                default
+default                                default
+#
+#
+TESTPOOL/TESTCTR/TESTFS1:inherit
+#
+default                                default
+default                                default
+default                                default
+#
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/Makefile.am b/zfs/tests/zfs-tests/tests/functional/inuse/Makefile.am
new file mode 100644 (file)
index 0000000..efc00ea
--- /dev/null
@@ -0,0 +1,12 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/inuse
+dist_pkgdata_SCRIPTS = \
+       inuse.cfg \
+       setup.ksh \
+       inuse_001_pos.ksh \
+       inuse_003_pos.ksh \
+       inuse_004_pos.ksh \
+       inuse_005_pos.ksh \
+       inuse_006_pos.ksh \
+       inuse_007_pos.ksh \
+       inuse_008_pos.ksh \
+       inuse_009_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse.cfg b/zfs/tests/zfs-tests/tests/functional/inuse/inuse.cfg
new file mode 100644 (file)
index 0000000..7d2b631
--- /dev/null
@@ -0,0 +1,136 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+if is_linux; then
+       set_device_dir
+       set_slice_prefix
+       export SLICE0=1
+       export SLICE1=2
+else
+       export SLICE_PREFIX="s"
+       export SLICE0=0
+       export SLICE1=1
+fi
+
+verify_disk_count "$DISKS" 2
+set -A disk_array $(find_disks $DISKS)
+case "${#disk_array[@]}" in
+2)
+       FS_DISK0=${disk_array[0]}
+       FS_DISK1=${disk_array[1]}
+       FS_DISK2=${disk_array[0]}
+       FS_DISK3=${disk_array[1]}
+       FS_SIDE0=${FS_DISK0}${SLICE_PREFIX}${SLICE0}
+       FS_SIDE1=${FS_DISK0}${SLICE_PREFIX}${SLICE1}
+       FS_SIDE2=${FS_DISK1}${SLICE_PREFIX}${SLICE0}
+       FS_SIDE3=${FS_DISK1}${SLICE_PREFIX}${SLICE1}
+       disk0="${DEV_DSKDIR}/$FS_SIDE0"
+       disk1="${DEV_DSKDIR}/$FS_SIDE1"
+       disk2="${DEV_DSKDIR}/$FS_SIDE2"
+       disk3="${DEV_DSKDIR}/$FS_SIDE3"
+       disktargets="$disk0 $disk2"
+       rawdisk0="${DEV_RDSKDIR}/$FS_SIDE0"
+       rawdisk1="${DEV_RDSKDIR}/$FS_SIDE1"
+       rawdisk2="${DEV_RDSKDIR}/$FS_SIDE2"
+       rawdisk3="${DEV_RDSKDIR}/$FS_SIDE3"
+       rawtargets="$rawdisk0 $rawdisk2"
+       vdisks="$FS_DISK0"
+       sdisks="$FS_DISK1"
+       vslices="$FS_SIDE0 $FS_SIDE1 $FS_SIDE2"
+       sslices="$FS_SIDE3"
+       ;;
+3)
+       FS_DISK0=${disk_array[0]}
+       FS_DISK1=${disk_array[1]}
+       FS_DISK2=${disk_array[2]}
+       FS_DISK3=${disk_array[0]}
+       FS_SIDE0=${FS_DISK0}${SLICE_PREFIX}${SLICE0}
+       FS_SIDE1=${FS_DISK0}${SLICE_PREFIX}${SLICE1}
+       FS_SIDE2=${FS_DISK1}${SLICE_PREFIX}${SLICE0}
+       FS_SIDE3=${FS_DISK2}${SLICE_PREFIX}${SLICE0}
+       disk0="${DEV_DSKDIR}/$FS_SIDE0"
+       disk1="${DEV_DSKDIR}/$FS_SIDE1"
+       disk2="${DEV_DSKDIR}/$FS_SIDE2"
+       disk3="${DEV_DSKDIR}/$FS_SIDE3"
+       disktargets="$disk0 $disk2 $disk3"
+       rawdisk0="${DEV_RDSKDIR}/$FS_SIDE0"
+       rawdisk1="${DEV_RDSKDIR}/$FS_SIDE1"
+       rawdisk2="${DEV_RDSKDIR}/$FS_SIDE2"
+       rawdisk3="${DEV_RDSKDIR}/$FS_SIDE3"
+       rawtargets="$rawdisk0 $rawdisk2 $rawdisk3"
+       vdisks="$FS_DISK0 $FS_DISK1"
+       sdisks="$FS_DISK2"
+       vslices="$FS_SIDE0 $FS_SIDE2 $FS_SIDE3"
+       sslices="$FS_SIDE1"
+       ;;
+*)
+       FS_DISK0=${disk_array[0]}
+       FS_DISK1=${disk_array[1]}
+       FS_DISK2=${disk_array[2]}
+       FS_DISK3=${disk_array[3]}
+       FS_SIDE0=${FS_DISK0}${SLICE_PREFIX}${SLICE0}
+       FS_SIDE1=${FS_DISK1}${SLICE_PREFIX}${SLICE0}
+       FS_SIDE2=${FS_DISK2}${SLICE_PREFIX}${SLICE0}
+       FS_SIDE3=${FS_DISK3}${SLICE_PREFIX}${SLICE0}
+       disk0="${DEV_DSKDIR}/$FS_SIDE0"
+       disk1="${DEV_DSKDIR}/$FS_SIDE1"
+       disk2="${DEV_DSKDIR}/$FS_SIDE2"
+       disk3="${DEV_DSKDIR}/$FS_SIDE3"
+       disktargets="$disk0 $disk1 $disk2 $disk3"
+       rawdisk0="${DEV_RDSKDIR}/$FS_SIDE0"
+       rawdisk1="${DEV_RDSKDIR}/$FS_SIDE1"
+       rawdisk2="${DEV_RDSKDIR}/$FS_SIDE2"
+       rawdisk3="${DEV_RDSKDIR}/$FS_SIDE3"
+       rawtargets="$rawdisk0 $rawdisk1 $rawdisk2 $rawdisk3"
+       vdisks="$FS_DISK0 $FS_DISK1 $FS_DISK2"
+       sdisks="$FS_DISK3"
+       vslices="$FS_SIDE0 $FS_SIDE1 $FS_SIDE2"
+       sslices="$FS_SIDE3"
+       ;;
+esac
+
+export FS_DISK0 FS_DISK1 FS_DISK2 FS_DISK3 SINGLE_DISK
+export FS_SIDE0 FS_SIDE1 FS_SIDE2 FS_SIDE3
+export disk0 disk1 disk2 disk3 disktargets
+export rawdisk0 rawdisk1 rawdisk2 rawdisk3 rawtargets
+export vdisks sdisks vslices sslices
+
+export UFSMP=$TESTDIR/testinuseufsdump
+export FS_SIZE=1g
+export PREVDUMPDEV=""
+export PIDUFSDUMP=""
+export PIDUFSRESTORE=""
+# size of block to be written to test file - currently 1mb
+export BLOCK_SIZE=$(( 1024 * 1024 ))
+# number of blocks to write == size of file
+export BLOCK_COUNT=100
+export STF_TIMEOUT=1200                        # 20 minutes max.
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/inuse_001_pos.ksh
new file mode 100755 (executable)
index 0000000..1feb681
--- /dev/null
@@ -0,0 +1,90 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inuse/inuse.cfg
+
+#
+# DESCRIPTION:
+# ZFS will not interfere with devices that are in use by dumpadm.
+#
+# STRATEGY:
+# 1. Create crash dump device using 'dumpadm'
+# 2. Try to create a ZFS pool using the 'dumpadm' crash dump device.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       #
+       # Remove dump device.
+       #
+       if [[ -n $PREVDUMPDEV ]]; then
+               log_must $DUMPADM -u -d $PREVDUMPDEV > /dev/null
+       fi
+
+       destroy_pool $TESTPOOL
+}
+
+log_assert "Ensure ZFS cannot use a device designated as a dump device"
+
+log_onexit cleanup
+
+typeset dumpdev=""
+typeset diskslice=""
+
+PREVDUMPDEV=`$DUMPADM | $GREP "Dump device" | $AWK '{print $3}'`
+
+log_note "Zero $FS_DISK0 and place free space in to slice 0"
+log_must cleanup_devices $FS_DISK0
+
+if [[ $WRAPPER == *"smi"* ]]; then
+       diskslice="${DEV_DSKDIR}/${FS_DISK0}${SLICE_PREFIX}${SLICE2}"
+else
+       diskslice="${DEV_DSKDIR}/${FS_DISK0}${SLICE_PREFIX}${SLICE0}"
+fi
+
+log_note "Configuring $diskslice as dump device"
+log_must $DUMPADM -d $diskslice > /dev/null
+
+log_note "Confirm that dump device has been setup"
+dumpdev=`$DUMPADM | $GREP "Dump device" | $AWK '{print $3}'`
+[[ -z "$dumpdev" ]] && log_untested "No dump device has been configured"
+
+[[ "$dumpdev" != "$diskslice" ]] && \
+    log_untested "Dump device has not been been configured to $diskslice"
+
+log_note "Attempt to zpool the dump device"
+log_mustnot $ZPOOL create $TESTPOOL "$diskslice"
+log_mustnot poolexists $TESTPOOL
+
+log_pass "Unable to zpool a device in use by dumpadm"
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/inuse_003_pos.ksh
new file mode 100755 (executable)
index 0000000..81bf0b4
--- /dev/null
@@ -0,0 +1,185 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inuse/inuse.cfg
+
+#
+# DESCRIPTION:
+# ZFS will not interfere with devices that are in use by ufsdump or
+# ufsrestore.
+#
+# STRATEGY:
+# 1. newfs a disk
+# 2. mount the disk
+# 3. create files and dirs on disk
+# 4. umount the disk
+# 5. ufsdump this disk to a backup disk
+# 6. Try to create a ZFS pool with same disk (also as a spare device)
+# 7. ufsrestore the disk from backup
+# 8. try to create a zpool during the ufsrestore
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       poolexists $TESTPOOL2 && destroy_pool $TESTPOOL2
+
+       log_note "Kill off ufsdump process if still running"
+       $KILL -0 $PIDUFSDUMP > /dev/null 2>&1 && \
+           log_must $KILL -9 $PIDUFSDUMP  > /dev/null 2>&1
+       #
+       # Note: It would appear that ufsdump spawns a number of processes
+       # which are not killed when the $PIDUFSDUMP is whacked.  So best bet
+       # is to find the rest of the them and deal with them individually.
+       #
+       for all in `$PGREP ufsdump`
+       do
+               $KILL -9 $all > /dev/null 2>&1
+       done
+
+       log_note "Kill off ufsrestore process if still running"
+       $KILL -0 $PIDUFSRESTORE > /dev/null 2>&1 && \
+           log_must $KILL -9 $PIDUFSRESTORE  > /dev/null 2>&1
+
+       ismounted $UFSMP ufs && log_must $UMOUNT $UFSMP
+
+       $RM -rf $UFSMP
+       $RM -rf $TESTDIR
+
+       #
+       # Tidy up the disks we used.
+       #
+       log_must cleanup_devices $vdisks $sdisks
+}
+
+log_assert "Ensure ZFS does not interfere with devices that are in use by " \
+    "ufsdump or ufsrestore"
+
+log_onexit cleanup
+
+typeset bigdir="${UFSMP}/bigdirectory"
+typeset restored_files="${UFSMP}/restored_files"
+typeset -i dirnum=0
+typeset -i filenum=0
+typeset cwd=""
+
+for num in 0 1 2; do
+       eval typeset slice=\${FS_SIDE$num}
+       disk=${slice%${SLICE_PREFIX}*}
+       slice=${slice##*${SLICE_PREFIX}}
+       if [[ $WRAPPER == *"smi"* && $disk == ${saved_disk} ]]; then
+               cyl=$(get_endslice $disk ${saved_slice})
+               log_must set_partition $slice "$cyl" $FS_SIZE $disk
+       else
+               log_must set_partition $slice "" $FS_SIZE $disk
+       fi
+       saved_disk=$disk
+       saved_slice=$slice
+done
+
+log_note "Make a ufs filesystem on source $rawdisk1"
+$ECHO "y" | $NEWFS -v $rawdisk1 > /dev/null 2>&1
+(($? != 0)) && log_untested "Unable to create ufs filesystem on $rawdisk1"
+
+log_must $MKDIR -p $UFSMP
+
+log_note "mount source $disk1 on $UFSMP"
+log_must $MOUNT $disk1 $UFSMP
+
+log_note "Now create some directories and files to be ufsdump'ed"
+while (($dirnum <= 2)); do
+       log_must $MKDIR $bigdir${dirnum}
+       while (( $filenum <= 2 )); do
+               $FILE_WRITE -o create -f $bigdir${dirnum}/file${filenum} \
+                   -b $BLOCK_SIZE -c $BLOCK_COUNT
+               if [[ $? -ne 0 ]]; then
+                       if [[ $dirnum -lt 3 ]]; then
+                               log_fail "$FILE_WRITE only wrote" \
+                                   "<(( $dirnum * 3 + $filenum ))>" \
+                                   "files, this is not enough"
+                       fi
+               fi
+               ((filenum = filenum + 1))
+       done
+       filenum=0
+       ((dirnum = dirnum + 1))
+done
+
+log_must $UMOUNT $UFSMP
+
+log_note "Start ufsdump in the background"
+log_note "$UFSDUMP 0bf 512 $rawdisk0 $disk1"
+$UFSDUMP 0bf 512 $rawdisk0 $disk1 &
+PIDUFSDUMP=$!
+
+log_note "Attempt to zpool the source device in use by ufsdump"
+log_mustnot $ZPOOL create $TESTPOOL1 "$disk1"
+log_mustnot poolexists $TESTPOOL1
+
+log_note "Attempt to take the source device in use by ufsdump as spare device"
+log_mustnot $ZPOOL create $TESTPOOL1 "$FS_SIDE2" spare "$disk1"
+log_mustnot poolexists $TESTPOOL1
+
+wait $PIDUFSDUMP
+typeset -i retval=$?
+(($retval != 0)) && log_fail "$UFSDUMP failed with error code $ret_val"
+
+log_must $MOUNT $disk1 $UFSMP
+
+log_must $RM -rf $UFSMP/*
+log_must $MKDIR $restored_files
+
+cwd=$PWD
+log_must cd $restored_files
+log_note "Start ufsrestore in the background from the target device"
+log_note "$UFSRESTORE rbf 512 $rawdisk0"
+$UFSRESTORE rbf 512 $rawdisk0 &
+PIDUFSRESTORE=$!
+log_must cd $cwd
+
+log_note "Attempt to zpool the restored device in use by ufsrestore"
+log_mustnot $ZPOOL create -f $TESTPOOL2 "$disk1"
+log_mustnot poolexists $TESTPOOL2
+
+log_note "Attempt to take the restored device in use by ufsrestore as spare" \
+    "device"
+log_mustnot $ZPOOL create -f $TESTPOOL2 "$FS_SIDE2" spare "$disk1"
+log_mustnot poolexists $TESTPOOL2
+
+log_pass "Unable to zpool over a device in use by ufsdump or ufsrestore"
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/inuse_004_pos.ksh
new file mode 100755 (executable)
index 0000000..5dfbd7a
--- /dev/null
@@ -0,0 +1,94 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inuse/inuse.cfg
+
+#
+# DESCRIPTION:
+# format will disallow modification of a mounted zfs disk partition or a spare
+# device
+#
+# STRATEGY:
+# 1. Create a ZFS filesystem
+# 2. Add a spare device to the ZFS pool
+# 3. Attempt to format the disk and the spare device.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       #
+       # Essentailly this is the default_cleanup rountine but I cannot get it
+       # to work correctly.  So its reproduced below.  Still need to full
+       # understand why default_cleanup does not work correctly from here.
+       #
+        log_must $ZFS umount $TESTPOOL/$TESTFS
+
+        $RM -rf $TESTDIR || \
+            log_unresolved Could not remove $TESTDIR
+
+       log_must $ZFS destroy $TESTPOOL/$TESTFS
+       destroy_pool $TESTPOOL
+}
+#
+# Currently, if a ZFS disk gets formatted things go horribly wrong, hence the
+# mini_format function.  If the modify option is reached, then we know format
+# would happily continue - best to not go further.
+#
+function mini_format
+{
+        typeset disk=$1
+
+       typeset format_file=/var/tmp/format_in.$$.1
+       $ECHO "partition" > $format_file
+       $ECHO "modify" >> $format_file
+
+       $FORMAT -e -s -d $disk -f $format_file
+       typeset -i retval=$?
+       $RM -rf $format_file
+       return $retval
+}
+
+log_assert "format will disallow modification of a mounted zfs disk partition"\
+ " or a spare device"
+
+log_onexit cleanup
+log_must default_setup_noexit $FS_DISK0
+log_must $ZPOOL add $TESTPOOL spare $FS_DISK1
+
+log_note "Attempt to format a ZFS disk"
+log_mustnot mini_format $FS_DISK0
+log_note "Attempt to format a ZFS spare device"
+log_mustnot mini_format $FS_DISK1
+
+log_pass "Unable to format a disk in use by ZFS"
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/inuse_005_pos.ksh
new file mode 100755 (executable)
index 0000000..dadb191
--- /dev/null
@@ -0,0 +1,122 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inuse/inuse.cfg
+
+#
+# DESCRIPTION:
+# newfs will not interfere with devices and spare devices that are in use
+# by active pool.
+#
+# STRATEGY:
+# 1. Create a regular|mirror|raidz|raidz2 pool with the given disk
+# 2. Try to newfs against the disk, verify it fails as expect.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       #
+       # Tidy up the disks we used.
+       #
+       cleanup_devices $vdisks $sdisks
+}
+
+function verify_assertion #slices
+{
+       typeset targets=$1
+
+       for t in $targets; do
+               $ECHO "y" | $NEWFS -v $t > /dev/null 2>&1
+               (( $? !=0 )) || \
+                       log_fail "newfs over active pool " \
+                       "unexpected return code of 0"
+       done
+
+       return 0
+}
+
+log_assert "Verify newfs over active pool fails."
+
+log_onexit cleanup
+
+set -A vdevs "" "mirror" "raidz" "raidz1" "raidz2"
+
+typeset -i i=0
+
+while (( i < ${#vdevs[*]} )); do
+
+       for num in 0 1 2 3 ; do
+               eval typeset slice=\${FS_SIDE$num}
+               disk=${slice%${SLICE_PREFIX}*}
+               slice=${slice##*${SLICE_PREFIX}}
+               if [[ $WRAPPER == *"smi"* && \
+                       $disk == ${saved_disk} ]]; then
+                       cyl=$(get_endslice $disk ${saved_slice})
+                       log_must set_partition $slice "$cyl" $FS_SIZE $disk
+               else
+                       log_must set_partition $slice "" $FS_SIZE $disk
+               fi
+               saved_disk=$disk
+               saved_slice=$slice
+       done
+
+       if [[ -n $SINGLE_DISK && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vslices spare $sslices
+       verify_assertion "$rawtargets"
+       destroy_pool $TESTPOOL1
+
+       if [[ ( $FS_DISK0 == $FS_DISK2 ) && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       if [[ ( $FS_DISK0 == $FS_DISK3 ) && ( ${vdevs[i]} == "raidz2" ) ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vdisks spare $sdisks
+       verify_assertion "$rawtargets"
+       destroy_pool $TESTPOOL1
+
+       (( i = i + 1 ))
+done
+
+log_pass "Newfs over active pool fails."
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/inuse_006_pos.ksh
new file mode 100755 (executable)
index 0000000..d79e318
--- /dev/null
@@ -0,0 +1,125 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inuse/inuse.cfg
+
+#
+# DESCRIPTION:
+# dumpadm will not interfere with devices and spare devices that are in use
+# by active pool.
+#
+# STRATEGY:
+# 1. Create a regular|mirror|raidz|raidz2 pool with the given disk
+# 2. Try to dumpadm against the disk, verify it fails as expect.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if [[ -n $PREVDUMPDEV ]]; then
+               log_must $DUMPADM -u -d $PREVDUMPDEV
+       fi
+
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       #
+       # Tidy up the disks we used.
+       #
+       cleanup_devices $vdisks $sdisks
+}
+
+function verify_assertion #slices
+{
+       typeset targets=$1
+
+       for t in $targets; do
+               log_mustnot $DUMPADM -d $t
+       done
+
+        return 0
+}
+
+log_assert "Verify dumpadm over active pool fails."
+
+log_onexit cleanup
+
+set -A vdevs "" "mirror" "raidz" "raidz1" "raidz2"
+
+typeset -i i=0
+
+PREVDUMPDEV=`$DUMPADM | $GREP "Dump device" | $AWK '{print $3}'`
+
+while (( i < ${#vdevs[*]} )); do
+
+       for num in 0 1 2 3 ; do
+               eval typeset slice=\${FS_SIDE$num}
+               disk=${slice%${SLICE_PREFIX}*}
+               slice=${slice##*${SLICE_PREFIX}}
+               if [[ $WRAPPER == *"smi"* && \
+                       $disk == ${saved_disk} ]]; then
+                       cyl=$(get_endslice $disk ${saved_slice})
+                       log_must set_partition $slice "$cyl" $FS_SIZE $disk
+               else
+                       log_must set_partition $slice "" $FS_SIZE $disk
+               fi
+               saved_disk=$disk
+               saved_slice=$slice
+       done
+
+       if [[ -n $SINGLE_DISK && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vslices spare $sslices
+       verify_assertion "$disktargets"
+       destroy_pool $TESTPOOL1
+
+       if [[ ( $FS_DISK0 == $FS_DISK2 ) && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       if [[ ( $FS_DISK0 == $FS_DISK3 ) && ( ${vdevs[i]} == "raidz2" ) ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vdisks spare $sdisks
+       verify_assertion "$disktargets"
+       destroy_pool $TESTPOOL1
+
+       (( i = i + 1 ))
+done
+
+log_pass "Dumpadm over active pool fails."
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/inuse_007_pos.ksh
new file mode 100755 (executable)
index 0000000..cb50689
--- /dev/null
@@ -0,0 +1,134 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inuse/inuse.cfg
+
+#
+# DESCRIPTION:
+# dumpadm will interfere with devices and spare devices that are in use
+# by exported pool.
+#
+# STRATEGY:
+# 1. Create a regular|mirror|raidz|raidz2 pool with the given disk
+# 2. Export the pool
+# 3. Try to dumpadm against the disk, verify it succeeds as expect.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if [[ -n $PREVDUMPDEV ]]; then
+               log_must $DUMPADM -u -d $PREVDUMPDEV
+       fi
+
+       poolexists $TESTPOOL1 || $ZPOOL import $TESTPOOL1 >/dev/null 2>&1
+
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       #
+       # Tidy up the disks we used.
+       #
+       cleanup_devices $vdisks $sdisks
+}
+
+function verify_assertion #slices
+{
+       typeset targets=$1
+
+       for t in $targets; do
+               log_must $DUMPADM -u -d $t
+
+               log_must $DUMPADM -u -d $PREVDUMPDEV
+       done
+
+       return 0
+}
+
+log_assert "Verify dumpadm over exported pool succeed."
+
+log_onexit cleanup
+
+set -A vdevs "" "mirror" "raidz" "raidz1" "raidz2"
+
+typeset -i i=0
+
+PREVDUMPDEV=`$DUMPADM | $GREP "Dump device" | $AWK '{print $3}'`
+
+while (( i < ${#vdevs[*]} )); do
+
+       for num in 0 1 2 3 ; do
+               eval typeset slice=\${FS_SIDE$num}
+               disk=${slice%${SLICE_PREFIX}*}
+               slice=${slice##*${SLICE_PREFIX}}
+               if [[ $WRAPPER == *"smi"* && \
+                       $disk == ${saved_disk} ]]; then
+                       cyl=$(get_endslice $disk ${saved_slice})
+                       log_must set_partition $slice "$cyl" $FS_SIZE $disk
+               else
+                       log_must set_partition $slice "" $FS_SIZE $disk
+               fi
+               saved_disk=$disk
+               saved_slice=$slice
+       done
+
+       if [[ -n $SINGLE_DISK && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vslices spare $sslices
+       log_must $ZPOOL export $TESTPOOL1
+       verify_assertion "$disktargets"
+       log_must $ZPOOL import $TESTPOOL1
+       destroy_pool $TESTPOOL1
+
+       if [[ ( $FS_DISK0 == $FS_DISK2 ) && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       if [[ ( $FS_DISK0 == $FS_DISK3 ) && ( ${vdevs[i]} == "raidz2" ) ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vdisks spare $sdisks
+       log_must $ZPOOL export $TESTPOOL1
+       verify_assertion "$disktargets"
+       log_must $ZPOOL import $TESTPOOL1
+       destroy_pool $TESTPOOL1
+
+       (( i = i + 1 ))
+done
+
+log_pass "Dumpadm over exported pool succeed."
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/inuse_008_pos.ksh
new file mode 100755 (executable)
index 0000000..80dad47
--- /dev/null
@@ -0,0 +1,111 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inuse/inuse.cfg
+
+#
+# DESCRIPTION:
+# Newfs will interfere with devices and spare devices that are in use
+# by exported pool.
+#
+# STRATEGY:
+# 1. Create a regular|mirror|raidz|raidz2 pool with the given disk
+# 2. Export the pool
+# 3. Try to newfs against the disk, verify it succeeds as expect.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 || $ZPOOL import $TESTPOOL1 >/dev/null 2>&1
+
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       #
+       # Tidy up the disks we used.
+       #
+       cleanup_devices $vdisks $sdisks
+}
+
+function verify_assertion #slices
+{
+       typeset targets=$1
+
+       for t in $targets; do
+               $ECHO "y" | $NEWFS -v $t > /dev/null 2>&1
+               (( $? !=0 )) && \
+                       log_fail "newfs over exported pool " \
+                               "failes unexpected."
+       done
+
+       return 0
+}
+
+log_assert "Verify newfs over exported pool succeed."
+
+log_onexit cleanup
+
+set -A vdevs "" "mirror" "raidz" "raidz1" "raidz2"
+
+typeset -i i=0
+
+for num in 0 1 2 3 ; do
+       eval typeset slice=\${FS_SIDE$num}
+       disk=${slice%${SLICE_PREFIX}*}
+       slice=${slice##*${SLICE_PREFIX}}
+       if [[ $WRAPPER == *"smi"* && \
+               $disk == ${saved_disk} ]]; then
+               cyl=$(get_endslice $disk ${saved_slice})
+               log_must set_partition $slice "$cyl" $FS_SIZE $disk
+       else
+               log_must set_partition $slice "" $FS_SIZE $disk
+       fi
+       saved_disk=$disk
+       saved_slice=$slice
+done
+
+while (( i < ${#vdevs[*]} )); do
+       if [[ -n $SINGLE_DISK && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vslices spare $sslices
+       log_must $ZPOOL export $TESTPOOL1
+       verify_assertion "$rawtargets"
+       cleanup_devices $vslices $sslices
+
+       (( i = i + 1 ))
+done
+
+log_pass "Newfs over exported pool succeed."
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/inuse_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/inuse_009_pos.ksh
new file mode 100755 (executable)
index 0000000..a5b1fe2
--- /dev/null
@@ -0,0 +1,122 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/inuse/inuse.cfg
+
+#
+# DESCRIPTION:
+# format command will interfere with devices and spare devices that are in use
+# by exported pool.
+#
+# STRATEGY:
+# 1. Create a regular|mirror|raidz|raidz2 pool with the given disk
+# 2. Export the pool
+# 3. Try to format against the disk, verify it succeeds as expect.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       poolexists $TESTPOOL1 || $ZPOOL import $TESTPOOL1 >/dev/null 2>&1
+
+       poolexists $TESTPOOL1 && destroy_pool $TESTPOOL1
+
+       #
+       # Tidy up the disks we used.
+       #
+       cleanup_devices $vdisks $sdisks
+}
+
+function verify_assertion #disks
+{
+       typeset targets=$1
+
+       for t in $targets; do
+               log_must set_partition 0 "" 0mb $t
+       done
+
+       return 0
+}
+
+log_assert "Verify format over exported pool succeed."
+
+log_onexit cleanup
+
+set -A vdevs "" "mirror" "raidz" "raidz1" "raidz2"
+
+typeset -i i=0
+
+while (( i < ${#vdevs[*]} )); do
+
+       for num in 0 1 2 3 ; do
+               eval typeset slice=\${FS_SIDE$num}
+               disk=${slice%${SLICE_PREFIX}*}
+               slice=${slice##*${SLICE_PREFIX}}
+               if [[ $WRAPPER == *"smi"* && \
+                       $disk == ${saved_disk} ]]; then
+                       cyl=$(get_endslice $disk ${saved_slice})
+                       log_must set_partition $slice "$cyl" $FS_SIZE $disk
+               else
+                       log_must set_partition $slice "" $FS_SIZE $disk
+               fi
+               saved_disk=$disk
+               saved_slice=$slice
+       done
+
+       if [[ -n $SINGLE_DISK && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vslices spare $sslices
+       log_must $ZPOOL export $TESTPOOL1
+       verify_assertion "$vdisks $sdisks"
+
+       if [[ ( $FS_DISK0 == $FS_DISK2 ) && -n ${vdevs[i]} ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       if [[ ( $FS_DISK0 == $FS_DISK3 ) && ( ${vdevs[i]} == "raidz2" ) ]]; then
+               (( i = i + 1 ))
+               continue
+       fi
+
+       create_pool $TESTPOOL1 ${vdevs[i]} $vdisks spare $sdisks
+       log_must $ZPOOL export $TESTPOOL1
+       verify_assertion "$vdisks $sdisks"
+
+       (( i = i + 1 ))
+done
+
+log_pass "Format over exported pool succeed."
diff --git a/zfs/tests/zfs-tests/tests/functional/inuse/setup.ksh b/zfs/tests/zfs-tests/tests/functional/inuse/setup.ksh
new file mode 100755 (executable)
index 0000000..962a0c9
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/large_files/Makefile.am b/zfs/tests/zfs-tests/tests/functional/large_files/Makefile.am
new file mode 100644 (file)
index 0000000..d78ea47
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/large_files
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       large_files_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/large_files/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/large_files/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/large_files/large_files_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/large_files/large_files_001_pos.ksh
new file mode 100755 (executable)
index 0000000..b973d6e
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Write a file to the allowable ZFS fs size.
+#
+# STRATEGY:
+# 1. largest_file will write to a file and increase its size
+# to the maximum allowable.
+# 2. The last byte of the file should be accessbile without error.
+# 3. Writing beyond the maximum file size generates an 'errno' of
+# EFBIG.
+#
+
+verify_runnable "both"
+
+log_assert "Write a file to the allowable ZFS fs size."
+
+log_note "Invoke 'largest_file' with $TESTDIR/bigfile"
+log_must $LARGEST_FILE $TESTDIR/bigfile
+
+log_pass "Successfully created a file to the maximum allowable size."
diff --git a/zfs/tests/zfs-tests/tests/functional/large_files/setup.ksh b/zfs/tests/zfs-tests/tests/functional/large_files/setup.ksh
new file mode 100755 (executable)
index 0000000..3a45ec8
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+disk=${DISKS%% *}
+
+default_setup $disk
diff --git a/zfs/tests/zfs-tests/tests/functional/largest_pool/Makefile.am b/zfs/tests/zfs-tests/tests/functional/largest_pool/Makefile.am
new file mode 100644 (file)
index 0000000..474a15a
--- /dev/null
@@ -0,0 +1,4 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/largest_pool
+dist_pkgdata_SCRIPTS = \
+       largest_pool.cfg \
+       largest_pool_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/largest_pool/largest_pool.cfg b/zfs/tests/zfs-tests/tests/functional/largest_pool/largest_pool.cfg
new file mode 100644 (file)
index 0000000..bcb93d4
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export TESTVOL=testvol$$
+export VOL_PATH=${ZVOL_DEVDIR}/${TESTPOOL2}/$TESTVOL
+export VOLSIZES=${VOLSIZES-"2pb 5pb 10pb 2eb 5eb 8eb 9eb"}
+
+# There're 3 different prompt messages while create
+# a volume that great than 1TB on 32-bit
+#       - volume size exceeds limit for this system. (happy gate)
+#       - max volume size is 1TB on 32-bit systems (s10u2)
+#       - value is too large (old)
+
+export VOL_LIMIT_KEYWORD1="1TB on 32-bit"
+export VOL_LIMIT_KEYWORD2="value is too large"
+export VOL_LIMIT_KEYWORD3="volume size exceeds limit"
diff --git a/zfs/tests/zfs-tests/tests/functional/largest_pool/largest_pool_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/largest_pool/largest_pool_001_pos.ksh
new file mode 100755 (executable)
index 0000000..8ca4d9d
--- /dev/null
@@ -0,0 +1,160 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/largest_pool/largest_pool.cfg
+
+# DESCRIPTION:
+#      The largest pool can be created and a dataset in that
+#      pool can be created and mounted.
+#
+# STRATEGY:
+#      create a pool which will contain a volume device.
+#      create a volume device of desired sizes.
+#      create the largest pool allowed using the volume vdev.
+#      create and mount a dataset in the largest pool.
+#      create some files in the zfs file system.
+#      do some zpool list commands and parse the output.
+
+verify_runnable "global"
+
+#
+# Parse the results of zpool & zfs creation with specified size
+#
+# $1: volume size
+#
+# return value:
+# 0 -> success
+# 1 -> failure
+#
+function parse_expected_output
+{
+       UNITS=`$ECHO $1 | $SED -e 's/^\([0-9].*\)\([a-z].\)/\2/'`
+       case "$UNITS" in
+               'mb') CHKUNIT="M" ;;
+               'gb') CHKUNIT="G" ;;
+               'tb') CHKUNIT="T" ;;
+               'pb') CHKUNIT="P" ;;
+               'eb') CHKUNIT="E" ;;
+               *) CHKUNIT="M" ;;
+       esac
+
+       log_note "Detect zpool $TESTPOOL in this test machine."
+       log_must eval "$ZPOOL list $TESTPOOL > /tmp/j.$$"
+       log_must eval "$GREP $TESTPOOL /tmp/j.$$ | \
+               $AWK '{print $2}' | $GREP $CHKUNIT"
+
+       log_note "Detect the file system in this test machine."
+       log_must eval "$DF -F zfs -h > /tmp/j.$$"
+       log_must eval "$GREP $TESTPOOL /tmp/j.$$ | \
+               $AWK '{print $2}' | $GREP $CHKUNIT"
+
+       return 0
+}
+
+#
+# Check and destroy zfs, volume & zpool remove the temporary files
+#
+function cleanup
+{
+       log_note "Start cleanup the zfs and pool"
+
+       if datasetexists $TESTPOOL/$TESTFS ; then
+               if ismounted $TESTPOOL/$TESTFS ; then
+                       log_must $ZFS unmount $TESTPOOL/$TESTFS
+               fi
+               log_must $ZFS destroy $TESTPOOL/$TESTFS
+       fi
+
+       destroy_pool $TESTPOOL
+
+       datasetexists $TESTPOOL2/$TESTVOL && \
+               log_must $ZFS destroy $TESTPOOL2/$TESTVOL
+
+       destroy_pool $TESTPOOL2
+
+       $RM -f /tmp/j.* > /dev/null
+}
+
+log_assert "The largest pool can be created and a dataset in that" \
+       "pool can be created and mounted."
+
+# Set trigger. When the test case exit, cleanup is executed.
+log_onexit cleanup
+
+# -----------------------------------------------------------------------
+# volume sizes with unit designations.
+#
+# Note: specifying the number '1' as size will not give the correct
+# units for 'df'.  It must be greater than one.
+# -----------------------------------------------------------------------
+typeset str
+typeset -i ret
+for volsize in $VOLSIZES; do
+       log_note "Create a pool which will contain a volume device"
+       create_pool $TESTPOOL2 "$DISKS"
+
+       log_note "Create a volume device of desired sizes: $volsize"
+       str=$($ZFS create -sV $volsize $TESTPOOL2/$TESTVOL 2>&1)
+       ret=$?
+       if (( ret != 0 )); then
+               if [[ $($ISAINFO -b) == 32 && \
+                       $str == *${VOL_LIMIT_KEYWORD1}* || \
+                       $str == *${VOL_LIMIT_KEYWORD2}* || \
+                       $str == *${VOL_LIMIT_KEYWORD3}* ]]
+               then
+                       log_unsupported \
+                               "Max volume size is 1TB on 32-bit systems."
+               else
+                       log_fail "$ZFS create -sV $volsize $TESTPOOL2/$TESTVOL"
+               fi
+       fi
+
+       log_note "Create the largest pool allowed using the volume vdev"
+       create_pool $TESTPOOL "$VOL_PATH"
+
+       log_note "Create a zfs file system in the largest pool"
+       log_must $ZFS create $TESTPOOL/$TESTFS
+
+       log_note "Parse the execution result"
+       parse_expected_output $volsize
+
+       log_note "unmount this zfs file system $TESTPOOL/$TESTFS"
+       log_must $ZFS unmount $TESTPOOL/$TESTFS
+
+       log_note "Destroy zfs, volume & zpool"
+       log_must $ZFS destroy $TESTPOOL/$TESTFS
+       destroy_pool $TESTPOOL
+       log_must $ZFS destroy $TESTPOOL2/$TESTVOL
+       destroy_pool $TESTPOOL2
+done
+
+log_pass "Dateset can be created, mounted & destroy in largest pool succeeded."
diff --git a/zfs/tests/zfs-tests/tests/functional/link_count/Makefile.am b/zfs/tests/zfs-tests/tests/functional/link_count/Makefile.am
new file mode 100644 (file)
index 0000000..669f3c1
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/link_count
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       link_count_001.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/link_count/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/link_count/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/link_count/link_count_001.ksh b/zfs/tests/zfs-tests/tests/functional/link_count/link_count_001.ksh
new file mode 100755 (executable)
index 0000000..53e89ae
--- /dev/null
@@ -0,0 +1,89 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify file link count is zero on zfs
+#
+# STRATEGY:
+# 1. Make sure this test executes on multi-processes system
+# 2. Make zero size files and remove them in the background
+# 3. Call the binary
+# 4. Make sure the files can be removed successfully
+#
+
+verify_runnable "both"
+
+log_assert "Verify file link count is zero on zfs"
+
+export ITERS=10
+export NUMFILES=10000
+
+# Detect and make sure this test must be executed on a multi-process system
+is_mp || log_fail "This test requires a multi-processor system."
+
+log_must $MKDIR -p ${TESTDIR}/tmp
+
+typeset -i i=0
+while [ $i -lt $NUMFILES ]; do
+        (( i = i + 1 ))
+        $TOUCH ${TESTDIR}/tmp/x$i > /dev/null 2>&1
+done
+
+sleep 3
+
+$RM -f ${TESTDIR}/tmp/x* >/dev/null 2>&1
+
+$RM_LNKCNT_ZERO_FILE ${TESTDIR}/tmp/test$$ > /dev/null 2>&1 &
+PID=$!
+log_note "$RM_LNKCNT_ZERO_FILE ${TESTDIR}/tmp/test$$ pid: $PID"
+
+i=0
+while [ $i -lt $ITERS ]; do
+       if ! $PGREP $RM_LNKCNT_ZERO_FILE > /dev/null ; then
+               log_note "$RM_LNKCNT_ZERO_FILE completes"
+               break
+       fi
+       log_must $SLEEP 10
+       (( i = i + 1 ))
+done
+
+if $PGREP $RM_LNKCNT_ZERO_FILE > /dev/null; then
+       log_must $KILL -TERM $PID
+       log_fail "file link count is zero"
+fi
+
+log_must $KILL -TERM $PID
+log_must $RM -f ${TESTDIR}/tmp/test$$*
+
+log_pass "Verify file link count is zero on zfs"
diff --git a/zfs/tests/zfs-tests/tests/functional/link_count/setup.ksh b/zfs/tests/zfs-tests/tests/functional/link_count/setup.ksh
new file mode 100755 (executable)
index 0000000..d275e06
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/Makefile.am b/zfs/tests/zfs-tests/tests/functional/migration/Makefile.am
new file mode 100644 (file)
index 0000000..53fb30b
--- /dev/null
@@ -0,0 +1,18 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/migration
+dist_pkgdata_SCRIPTS = \
+       migration.cfg \
+       migration.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       migration_001_pos.ksh \
+       migration_002_pos.ksh \
+       migration_003_pos.ksh \
+       migration_004_pos.ksh \
+       migration_005_pos.ksh \
+       migration_006_pos.ksh \
+       migration_007_pos.ksh \
+       migration_008_pos.ksh \
+       migration_009_pos.ksh \
+       migration_010_pos.ksh \
+       migration_011_pos.ksh \
+       migration_012_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/migration/cleanup.ksh
new file mode 100755 (executable)
index 0000000..0b6efce
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.cfg
+
+verify_runnable "global"
+
+ismounted $NONZFS_TESTDIR $NEWFS_DEFAULT_FS
+(( $? == 0 )) && log_must $UMOUNT -f $NONZFS_TESTDIR
+
+ismounted $TESTPOOL/$TESTFS
+[[ $? == 0 ]] && log_must $ZFS umount -f $TESTDIR
+destroy_pool $TESTPOOL
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+        delete_partitions
+fi
+
+# recreate and destroy a zpool over the disks to restore the partitions to
+# normal
+case $DISK_COUNT in
+0)
+       log_note "No disk devices to restore"
+       ;;
+1)
+       log_must cleanup_devices $ZFS_DISK
+       ;;
+*)
+       log_must cleanup_devices $ZFS_DISK $NONZFS_DISK
+       ;;
+esac
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration.cfg b/zfs/tests/zfs-tests/tests/functional/migration/migration.cfg
new file mode 100644 (file)
index 0000000..3402880
--- /dev/null
@@ -0,0 +1,112 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export DISKSARRAY=$DISKS
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+set -A disk_array $(find_disks $DISKS)
+case "${#disk_array[*]}" in
+0)
+       DISK_COUNT=0
+       ;;
+1)
+       # We need to repartition the single disk to two slices.
+       DISK_COUNT=1
+       ZFS_DISK=${disk_array[0]}
+       SINGLE_DISK=$ZFS_DISK
+       NONZFS_DISK=$ZFS_DISK
+       if is_linux; then
+               if is_mpath_device $ZFS_DISK; then
+                       export DEV_DSKDIR=$DEV_MPATHDIR
+               else
+                       export DEV_DSKDIR=$DEV_RDSKDIR
+               fi
+               if ( is_mpath_device $ZFS_DISK ) && [[ -z $($ECHO $ZFS_DISK | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $ZFS_DISK ); then
+                       ZFSSIDE_DISK=${SINGLE_DISK}1
+                       NONZFSSIDE_DISK=${SINGLE_DISK}2
+               elif ( is_mpath_device $ZFS_DISK || is_loop_device $ZFS_DISK ); then
+                       ZFSSIDE_DISK=${SINGLE_DISK}p1
+                       NONZFSSIDE_DISK=${SINGLE_DISK}p2
+               else
+                       log_fail "$ZFS_DISK not supported for partitioning."
+               fi
+       else
+               export DEV_DSKDIR="/dev"
+               ZFSSIDE_DISK=${SINGLE_DISK}s0
+               NONZFSSIDE_DISK=${SINGLE_DISK}s1
+       fi
+       ;;
+*)
+       # In this case there are at least enough disks to use.
+       DISK_COUNT=2
+       ZFS_DISK=${disk_array[0]}
+       NONZFS_DISK=${disk_array[1]}
+       if is_linux; then
+               if is_mpath_device $ZFS_DISK; then
+                       export DEV_DSKDIR=$DEV_MPATHDIR
+               else
+                       export DEV_DSKDIR=$DEV_RDSKDIR
+               fi
+               if ( is_mpath_device $ZFS_DISK ) && [[ -z $($ECHO $ZFS_DISK | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $ZFS_DISK ); then
+                       ZFSSIDE_DISK=${ZFS_DISK}1
+               elif ( is_mpath_device $ZFS_DISK || is_loop_device $ZFS_DISK ); then
+                       ZFSSIDE_DISK=${ZFS_DISK}p1
+               else
+                       log_fail "$ZFS_DISK not supported for partitioning."
+               fi
+               if ( is_mpath_device $NONZFS_DISK ) && [[ -z $($ECHO $NONZFS_DISK | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $NONZFS_DISK ); then
+                       NONZFSSIDE_DISK=${NONZFS_DISK}1
+               elif ( is_mpath_device $NONZFS_DISK || is_loop_device $NONZFS_DISK ); then
+                       NONZFSSIDE_DISK=${NONZFS_DISK}p1
+               else
+                       log_fail "$NONZFS_DISK not supported for partitioning."
+               fi
+       else
+               export DEV_DSKDIR="/dev"
+               ZFSSIDE_DISK=${ZFS_DISK}s0
+               NONZFSSIDE_DISK=${NONZFS_DISK}s0
+       fi
+       ;;
+esac
+
+export DISK_COUNT ZFS_DISK NONZFS_DISK SINGLE_DISK ZFSSIDE_DISK NONZFSSIDE_DISK
+
+export TESTFILE=/etc/passwd
+export NONZFS_TESTDIR=$TESTDIR/nonzfstestdir
+tmp=`$SUM $TESTFILE`
+export SUMA=`$ECHO $tmp | $AWK '{print $1}'`
+export SUMB=`$ECHO $tmp | $AWK '{print $2}'`
+export FS_SIZE=1g
+export BNAME=`$BASENAME $TESTFILE`
+export DNAME=`$DIRNAME $TESTFILE`
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration.kshlib b/zfs/tests/zfs-tests/tests/functional/migration/migration.kshlib
new file mode 100644 (file)
index 0000000..e0799af
--- /dev/null
@@ -0,0 +1,153 @@
+#
+# 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.
+#
+
+. $STF_SUITE/tests/functional/migration/migration.cfg
+
+#
+# This function creates the test archive for migration.
+#
+# Usage:
+# prepare srcdir cmd
+#
+# Return value: 0 on success
+#              1 on failure
+#
+# Where:
+#      srcdir: is the directory where the testfile is
+#      cmd:    is the command to be executed.
+#              E.g.
+#              $TAR cf $TESTDIR/tar$$.tar
+#
+function prepare #srcdir cmd
+{
+       typeset srcdir=$1
+       typeset cmd=$2
+       typeset -i retval=0
+
+       cwd=$PWD
+       cd $srcdir
+       (( $? != 0 )) && return 1
+
+       $cmd
+       (( $? != 0 )) && return 1
+
+       cd $cwd
+       (( $? != 0 )) && return 1
+
+       return 0
+}
+
+#
+# This function executes a passed in command and then determines the chksum
+# of the resulting file.  The chksum components are checked against the ones
+# passed in to determine if they are equal.  If they are equal, 0 is returned
+# otherwise 1 is returned.
+#
+# Usage:
+# migrate destdir oldsuma oldsumb command_to_execute
+#
+# Return value: 0 on success
+#              1 on failure
+#
+# Where:
+#      destdir: is the directory where the command is to be executed on
+#      oldsuma: is the first part of the values returned by sum
+#      oldsumb: is the second part of the values returned by sum
+#      cmd: is the command to be executed;
+#              E.g.
+#              "$TAR xf $TESTDIR/tar$$.tar"
+#
+function migrate #destdir oldsuma oldsumb cmd
+{
+       typeset destdir=$1
+       typeset oldsuma=$2
+       typeset oldsumb=$3
+       typeset cmd=$4
+       typeset -i retval=0
+
+       cwd=$PWD
+       cd $destdir
+       (( $? != 0 )) && return 1
+
+       $cmd
+       (( $? != 0 )) && return 1
+
+       sumy=`$SUM ./$BNAME`
+       suma=`$ECHO $sumy | $AWK '{print $1}'`
+       sumb=`$ECHO $sumy | $AWK '{print $2}'`
+
+       if (( $oldsuma != $suma )); then
+               log_note "$SUM values are not the same"
+               retval=1
+       fi
+
+       if (( $oldsumb != $sumb )); then
+               log_note "$SUM values are not the same"
+               retval=1
+       fi
+
+       cd $cwd
+       (( $? != 0 )) && return 1
+       return $retval
+}
+
+function migrate_cpio
+{
+       typeset destdir=$1
+       typeset archive=$2
+       typeset oldsuma=$3
+       typeset oldsumb=$4
+       typeset -i retval=0
+
+       cwd=$PWD
+       cd $destdir
+       (( $? != 0 )) && return 1
+
+       $CPIO -iv < $archive
+       (( $? != 0 )) && return 1
+
+       sumy=`$SUM ./$BNAME`
+       suma=`$ECHO $sumy | $AWK '{print $1}'`
+       sumb=`$ECHO $sumy | $AWK '{print $2}'`
+
+       if (( $oldsuma != $suma )); then
+               log_note "$SUM values are not the same"
+               retval=1
+       fi
+
+       if (( $oldsumb != $sumb )); then
+               log_note "$SUM values are not the same"
+               retval=1
+       fi
+
+       cd $cwd
+       (( $? != 0 )) && return 1
+       return $retval
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_001_pos.ksh
new file mode 100755 (executable)
index 0000000..5286461
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from ZFS fs to ZFS fs using tar.
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Tar up test file and place on a ZFS filesystem
+# 3. Extract tar contents to a ZFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/tar$$.tar
+       $RM -rf $TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from ZFS fs to ZFS fs using tar"
+
+log_onexit cleanup
+
+prepare $DNAME "$TAR cf $TESTDIR/tar$$.tar $BNAME"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $TESTDIR $SUMA $SUMB "$TAR xf $TESTDIR/tar$$.tar"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from ZFS fs to ZFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_002_pos.ksh
new file mode 100755 (executable)
index 0000000..54fbc04
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from ZFS fs to UFS fs using tar.
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Tar up test file and place on a ZFS filesystem
+# 3. Extract tar contents to a UFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/tar$$.tar
+       $RM -rf $NONZFS_TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from ZFS fs to UFS fs using tar"
+
+log_onexit cleanup
+
+prepare $DNAME "$TAR cf $TESTDIR/tar$$.tar $BNAME"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $NONZFS_TESTDIR $SUMA $SUMB "$TAR xf $TESTDIR/tar$$.tar"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to UFS fs"
+
+log_pass "Successully migrated test file from ZFS fs to UFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_003_pos.ksh
new file mode 100755 (executable)
index 0000000..c8d67c1
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from UFS fs to ZFS fs using tar.
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Tar up test file and place on a UFS filesystem
+# 3. Extract tar contents to a ZFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $NONZFS_TESTDIR/tar$$.tar
+       $RM -rf $TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from UFS fs to ZFS fs using tar"
+
+log_onexit cleanup
+
+prepare $DNAME "$TAR cf $NONZFS_TESTDIR/tar$$.tar $BNAME"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $TESTDIR $SUMA $SUMB "$TAR xvf $NONZFS_TESTDIR/tar$$.tar"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "UFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from UFS fs to ZFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_004_pos.ksh
new file mode 100755 (executable)
index 0000000..81b822d
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from ZFS fs to ZFS fs using cpio
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Cpio up test file and place on a ZFS filesystem
+# 3. Extract cpio contents to a ZFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/cpio$$.cpio
+       $RM -rf $TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from ZFS fs to ZFS fs using cpio"
+
+log_onexit cleanup
+
+cwd=$PWD
+cd $DNAME
+(( $? != 0 )) && log_untested "Could not change directory to $DNAME"
+
+$LS $BNAME | $CPIO -oc > $TESTDIR/cpio$$.cpio
+(( $? != 0 )) && log_fail "Unable to create cpio archive"
+
+cd $cwd
+(( $? != 0 )) && log_untested "Could not change directory to $cwd"
+
+migrate_cpio $TESTDIR "$TESTDIR/cpio$$.cpio" $SUMA $SUMB
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from ZFS fs to ZFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_005_pos.ksh
new file mode 100755 (executable)
index 0000000..95ca47a
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from ZFS fs to UFS fs using cpio
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Cpio up test file and place on a ZFS filesystem
+# 3. Extract cpio contents to a UFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/cpio$$.cpio
+       $RM -rf $NONZFS_TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from ZFS fs to uFS fs using cpio"
+
+log_onexit cleanup
+
+cwd=$PWD
+cd $DNAME
+(( $? != 0 )) && log_untested "Could not change directory to $DNAME"
+
+$LS $BNAME | $CPIO -oc > $TESTDIR/cpio$$.cpio
+(( $? != 0 )) && log_fail "Unable to create cpio archive"
+
+cd $cwd
+(( $? != 0 )) && log_untested "Could not change directory to $cwd"
+
+migrate_cpio $NONZFS_TESTDIR "$TESTDIR/cpio$$.cpio" $SUMA $SUMB
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to UFS fs"
+
+log_pass "Successully migrated test file from ZFS fs to UFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_006_pos.ksh
new file mode 100755 (executable)
index 0000000..d889479
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from UFS fs to ZFS fs using cpio
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Cpio up test file and place on a UFS filesystem
+# 3. Extract cpio contents to a ZFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $NONZFS_TESTDIR/cpio$$.cpio
+       $RM -rf $TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from UFS fs to ZFS fs using cpio"
+
+log_onexit cleanup
+
+cwd=$PWD
+cd $DNAME
+(( $? != 0 )) && log_untested "Could not change directory to $DNAME"
+
+$LS $BNAME | $CPIO -oc > $NONZFS_TESTDIR/cpio$$.cpio
+(( $? != 0 )) && log_fail "Unable to create cpio archive"
+
+cd $cwd
+(( $? != 0 )) && log_untested "Could not change directory to $cwd"
+
+migrate_cpio $TESTDIR "$NONZFS_TESTDIR/cpio$$.cpio" $SUMA $SUMB
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from UFS fs to ZFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_007_pos.ksh
new file mode 100755 (executable)
index 0000000..ee0927b
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from ZFS fs to ZFS fs using dd.
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Dd up test file and place on a ZFS filesystem
+# 3. Extract dd contents to a ZFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/dd$$.dd
+       $RM -rf $TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from ZFS fs to ZFS fs using dd"
+
+log_onexit cleanup
+
+prepare $DNAME "$DD if=$BNAME obs=128k of=$TESTDIR/dd$$.dd"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $TESTDIR $SUMA $SUMB "$DD if=$TESTDIR/dd$$.dd obs=128k of=$BNAME"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from ZFS fs to ZFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_008_pos.ksh
new file mode 100755 (executable)
index 0000000..92d2a45
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from ZFS fs to UFS fs using dd.
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Dd up test file and place on a ZFS filesystem
+# 3. Extract dd contents to a UFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/dd$$.dd
+       $RM -rf $NONZFS_TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from ZFS fs to UFS fs using dd"
+
+log_onexit cleanup
+
+prepare $DNAME "$DD if=$BNAME obs=128k of=$TESTDIR/dd$$.dd"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $NONZFS_TESTDIR $SUMA $SUMB "$DD if=$TESTDIR/dd$$.dd obs=128k of=$BNAME"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from ZFS fs to UFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_009_pos.ksh
new file mode 100755 (executable)
index 0000000..317eefd
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from UFS fs to ZFS fs using dd.
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. Dd up test file and place on a UFS filesystem
+# 3. Extract dd contents to a ZFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/dd$$.dd
+       $RM -rf $NONZFS_TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from UFS fs to ZFS fs using dd"
+
+log_onexit cleanup
+
+prepare $DNAME "$DD if=$BNAME obs=128k of=$NONZFS_TESTDIR/dd$$.dd"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $TESTDIR $SUMA $SUMB "$DD if=$NONZFS_TESTDIR/dd$$.dd obs=128k of=$BNAME"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from UFS fs to ZFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_010_pos.ksh
new file mode 100755 (executable)
index 0000000..462bfb1
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from ZFS fs to ZFS fs using cp
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. CP up test file and place on a ZFS filesystem
+# 3. Extract cp contents to a ZFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/cp$$.cp
+       $RM -rf $TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from ZFS fs to ZFS fs using cp"
+
+log_onexit cleanup
+
+prepare $DNAME "$CP $BNAME $TESTDIR/cp$$.cp"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $TESTDIR $SUMA $SUMB "$CP $TESTDIR/cp$$.cp $BNAME"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from ZFS fs to ZFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_011_pos.ksh
new file mode 100755 (executable)
index 0000000..2fcd291
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from ZFS fs to UFS fs using cp
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. CP up test file and place on a ZFS filesystem
+# 3. Extract cp contents to a UFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $NONZFS_TESTDIR/cp$$.cp
+       $RM -rf $TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from ZFS fs to UFS fs using cp"
+
+log_onexit cleanup
+
+prepare $DNAME "$CP $BNAME $TESTDIR/cp$$.cp"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $NONZFS_TESTDIR $SUMA $SUMB "$CP $TESTDIR/cp$$.cp $BNAME"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "ZFS fs to UFS fs"
+
+log_pass "Successully migrated test file from ZFS fs to UFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/migration_012_pos.ksh b/zfs/tests/zfs-tests/tests/functional/migration/migration_012_pos.ksh
new file mode 100755 (executable)
index 0000000..427467e
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.kshlib
+
+#
+# DESCRIPTION:
+# Migrating test file from UFS fs to ZFS fs using cp
+#
+# STRATEGY:
+# 1. Calculate chksum of testfile
+# 2. CP up test file and place on a UFS filesystem
+# 3. Extract cp contents to a ZFS file system
+# 4. Calculate chksum of extracted file
+# 5. Compare old and new chksums.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/cp$$.cp
+       $RM -rf $NONZFS_TESTDIR/$BNAME
+}
+
+log_assert "Migrating test file from UFS fs to ZFS fs using cp"
+
+log_onexit cleanup
+
+prepare $DNAME "$CP $BNAME $NONZFS_TESTDIR/cp$$.cp"
+(( $? != 0 )) && log_fail "Unable to create src archive"
+
+migrate $TESTDIR $SUMA $SUMB "$CP $NONZFS_TESTDIR/cp$$.cp $BNAME"
+(( $? != 0 )) && log_fail "Uable to successfully migrate test file from" \
+    "UFS fs to ZFS fs"
+
+log_pass "Successully migrated test file from UFS fs to ZFS fs".
diff --git a/zfs/tests/zfs-tests/tests/functional/migration/setup.ksh b/zfs/tests/zfs-tests/tests/functional/migration/setup.ksh
new file mode 100755 (executable)
index 0000000..2381b5f
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/migration/migration.cfg
+
+verify_runnable "global"
+
+if ! $(is_physical_device $ZFS_DISK) ; then
+       log_unsupported "Only partitionable physical disks can be used"
+fi
+
+case $DISK_COUNT in
+0)
+       log_untested "Need at least 1 disk device for test"
+       ;;
+1)
+       log_note "Partitioning a single disk ($SINGLE_DISK)"
+       ;;
+*)
+       log_note "Partitioning disks ($ZFS_DISK $NONZFS_DISK)"
+       ;;
+esac
+
+set_partition ${ZFSSIDE_DISK##*s} "" $FS_SIZE $ZFS_DISK
+set_partition ${NONZFSSIDE_DISK##*s} "" $FS_SIZE $NONZFS_DISK
+
+create_pool $TESTPOOL "$ZFSSIDE_DISK"
+
+$RM -rf $TESTDIR  || log_unresolved Could not remove $TESTDIR
+$MKDIR -p $TESTDIR || log_unresolved Could not create $TESTDIR
+
+log_must $ZFS create $TESTPOOL/$TESTFS
+log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+$RM -rf $NONZFS_TESTDIR  || log_unresolved Could not remove $NONZFS_TESTDIR
+$MKDIR -p $NONZFS_TESTDIR || log_unresolved Could not create $NONZFS_TESTDIR
+
+$ECHO "y" | $NEWFS -v ${DEV_DSKDIR}/$NONZFSSIDE_DISK
+(( $? != 0 )) &&
+       log_untested "Unable to setup a UFS file system"
+
+log_must $MOUNT ${DEV_DSKDIR}/$NONZFSSIDE_DISK $NONZFS_TESTDIR
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/mmap/Makefile.am b/zfs/tests/zfs-tests/tests/functional/mmap/Makefile.am
new file mode 100644 (file)
index 0000000..cb444ec
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/mmap
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       mmap.cfg \
+       mmap_read_001_pos.ksh \
+       mmap_write_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/mmap/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/mmap/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/mmap/mmap.cfg b/zfs/tests/zfs-tests/tests/functional/mmap/mmap.cfg
new file mode 100644 (file)
index 0000000..1501c04
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# 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) 2012, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export DISK_ARRAY_NUM=0
+export DISK_ARRAY_LIMIT=4
+export DISKSARRAY=""
+export VDEVS_NUM=32
+
+function set_disks
+{
+        typeset -a disk_array=($(find_disks $DISKS))
+
+       if (( ${#disk_array[*]} <= 1 )); then
+               export DISK=${DISKS%% *}
+       else
+               export DISK=""
+               typeset -i i=0
+               while (( i < ${#disk_array[*]} )); do
+                       export DISK${i}="${disk_array[$i]}"
+                       DISKSARRAY="$DISKSARRAY ${disk_array[$i]}"
+                       (( i = i + 1 ))
+                       (( i>$DISK_ARRAY_LIMIT )) && break
+               done
+               export DISK_ARRAY_NUM=$i
+               export DISKSARRAY
+       fi
+}
+
+set_disks
+set_device_dir
diff --git a/zfs/tests/zfs-tests/tests/functional/mmap/mmap_read_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/mmap/mmap_read_001_pos.ksh
new file mode 100755 (executable)
index 0000000..36bcaa8
--- /dev/null
@@ -0,0 +1,57 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/mmap/mmap.cfg
+
+#
+# DESCRIPTION:
+# read()s from mmap()'ed file contain correct data.
+#
+# STRATEGY:
+# 1. Create a pool & dataset
+# 2. Call readmmap binary
+# 3. unmount this file system
+# 4. Verify the integrity of this pool & dateset
+#
+
+verify_runnable "global"
+
+log_assert "read()s from mmap()'ed file contain correct data."
+
+log_must $CHMOD 777 $TESTDIR
+log_must $READMMAP $TESTDIR/test-read-file
+log_must $ZFS unmount $TESTPOOL/$TESTFS
+
+typeset dir=$(get_device_dir $DISKS)
+verify_filesys "$TESTPOOL" "$TESTPOOL/$TESTFS" "$dir"
+
+log_pass "read(2) calls from a mmap(2)'ed file succeeded."
diff --git a/zfs/tests/zfs-tests/tests/functional/mmap/mmap_write_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/mmap/mmap_write_001_pos.ksh
new file mode 100755 (executable)
index 0000000..6bede53
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Writing to a file and mmaping that file at the
+# same time does not result in a deadlock.
+#
+# STRATEGY:
+# 1. Make sure this test executes on multi-processes system.
+# 2. Call mmapwrite binary.
+# 3. wait 30s and make sure the test file existed.
+#
+
+verify_runnable "both"
+
+log_assert "write()s to a file and mmap() that file at the same time does not "\
+       "result in a deadlock."
+
+# Detect and make sure this test must be executed on a multi-process system
+is_mp || log_fail "This test requires a multi-processor system."
+
+log_must $CHMOD 777 $TESTDIR
+$MMAPWRITE $TESTDIR/test-write-file &
+PID_MMAPWRITE=$!
+log_note "$MMAPWRITE $TESTDIR/test-write-file pid: $PID_MMAPWRITE"
+log_must $SLEEP 30
+
+log_must $KILL -9 $PID_MMAPWRITE
+log_must $LS -l $TESTDIR/test-write-file
+
+log_pass "write(2) a mmap(2)'ing file succeeded."
diff --git a/zfs/tests/zfs-tests/tests/functional/mmap/setup.ksh b/zfs/tests/zfs-tests/tests/functional/mmap/setup.ksh
new file mode 100755 (executable)
index 0000000..d275e06
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/mount/Makefile.am b/zfs/tests/zfs-tests/tests/functional/mount/Makefile.am
new file mode 100644 (file)
index 0000000..9898e05
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/mount
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       umount_001.ksh \
+       umountall_001.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/mount/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/mount/cleanup.ksh
new file mode 100755 (executable)
index 0000000..36ff7c0
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+log_must destroy_pool $TESTPOOL
+
+for dir in $TESTDIRS; do
+       $RM -rf $dir
+done
diff --git a/zfs/tests/zfs-tests/tests/functional/mount/setup.ksh b/zfs/tests/zfs-tests/tests/functional/mount/setup.ksh
new file mode 100755 (executable)
index 0000000..7255e7d
--- /dev/null
@@ -0,0 +1,48 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+create_pool $TESTPOOL "$DISK"
+
+for i in 1 2 3; do
+       dir=$TESTDIR.$i
+       fs=$TESTPOOL/$TESTFS.$i
+
+       log_must $ZFS create $fs
+       log_must $MKDIR -p $dir
+       log_must $ZFS set mountpoint=$dir $fs
+
+       log_must mounted $fs
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/mount/umount_001.ksh b/zfs/tests/zfs-tests/tests/functional/mount/umount_001.ksh
new file mode 100755 (executable)
index 0000000..55b46ff
--- /dev/null
@@ -0,0 +1,54 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# zfs mount and unmount commands should mount and unmount existing
+# file systems.
+#
+# STRATEGY:
+# 1. Call zfs mount command
+# 2. Make sure the file systems were mounted
+# 3. Call zfs unmount command
+# 4. Make sure the file systems were unmounted
+#
+
+for fs in 1 2 3; do
+       log_must mounted $TESTDIR.$fs
+       log_must $ZFS umount $TESTPOOL/$TESTFS.$fs
+       log_must unmounted $TESTDIR.$fs
+       log_must $ZFS mount $TESTPOOL/$TESTFS.$fs
+       log_must mounted $TESTDIR.$fs
+done
+
+log_pass "All file systems are unmounted"
diff --git a/zfs/tests/zfs-tests/tests/functional/mount/umountall_001.ksh b/zfs/tests/zfs-tests/tests/functional/mount/umountall_001.ksh
new file mode 100755 (executable)
index 0000000..6b07542
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/ksh -p
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# There are myriad problems associated with trying to test umountall in a way
+# that works reliable across different systems. Some filesystems won't unmount
+# because they're busy. Some won't remount because they were legacy mounts in
+# the first place. etc...
+# Make a best approximation by calling umountall with the -n option, and verify
+# that the list of things it would try to unmout makes sense.
+#
+# STRATEGY:
+# 1. Make a list of file systems umountall is known to ignore.
+# 2. Append all ZFS file systems on this system.
+# 3. Run umountall -n and verify the file systems it reports are in the list.
+#
+
+log_must $ZFS mount -a
+for fs in 1 2 3 ; do
+       log_must mounted $TESTPOOL/$TESTFS.$fs
+done
+
+# This is the list we check the output of umountall -n against. We seed it
+# with these values because umountall will ignore them, and they're possible
+# (though most are improbable) ZFS filesystem mountpoints.
+zfs_list="/ /lib /sbin /tmp /usr /var /var/adm /var/run"
+
+# Append our ZFS filesystems to the list, not worrying about duplicates.
+for fs in $($MOUNT -p | $AWK '{if ($4 == "zfs") print $3}'); do
+       zfs_list="$zfs_list $fs"
+done
+
+fs=''
+for fs in $($UMOUNTALL -n -F zfs 2>&1 | $AWK '{print $2}'); do
+       for i in $zfs_list; do
+               [[ $fs = $i ]] && continue 2
+       done
+       log_fail "umountall -n -F zfs tried to unmount $fs"
+done
+[[ -n $fs ]] || log_fail "umountall -n -F zfs produced no output"
+
+log_pass "All ZFS file systems would have been unmounted"
diff --git a/zfs/tests/zfs-tests/tests/functional/mv_files/Makefile.am b/zfs/tests/zfs-tests/tests/functional/mv_files/Makefile.am
new file mode 100644 (file)
index 0000000..574af15
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/mv_files
+dist_pkgdata_SCRIPTS = \
+       mv_files.cfg \
+       mv_files_common.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       mv_files_001_pos.ksh \
+       mv_files_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/mv_files/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/mv_files/cleanup.ksh
new file mode 100755 (executable)
index 0000000..ecec91f
--- /dev/null
@@ -0,0 +1,48 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/mv_files/mv_files_common.kshlib
+
+verify_runnable "global"
+
+[[ -f /var/tmp/exitsZero.ksh ]] && \
+       log_must $RM -f /var/tmp/exitsZero.ksh
+[[ -f /var/tmp/testbackgprocs.ksh ]] && \
+       log_must $RM -f /var/tmp/testbackgprocs.ksh
+
+ismounted $TESTPOOL/$TESTFS_TGT
+(( $? == 0 )) && log_must $ZFS umount $TESTPOOL/$TESTFS_TGT
+log_must $ZFS destroy $TESTPOOL/$TESTFS_TGT
+
+[[ -d $TESTDIR_TGT ]] && log_must $RM -rf $TESTDIR_TGT
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/mv_files/mv_files.cfg b/zfs/tests/zfs-tests/tests/functional/mv_files/mv_files.cfg
new file mode 100644 (file)
index 0000000..e0c4166
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export DISK=${DISKS%% *}
+export DISKSARRAY=$DISKS
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+set_device_dir
+
+export TESTFILE=testfile
+
+export TESTDIR_TGT=${TEST_BASE_DIR%%/}/testdir_tgt
+export TESTFS_TGT=testzfs_tgt
+export OLDDIR=$TESTDIR/olddir
+export NEWDIR_IN_FS=$TESTDIR/newdir
+export NEWDIR_ACROSS_FS=$TESTDIR_TGT/newdir
+
+export MVNUMFILES=2000 # <number of files to start>
+export MVNUMINCR=1000  # <number of files to be increased to>
+export GANGPIDS=50     # <number of limit for parallel background running process>
diff --git a/zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_001_pos.ksh
new file mode 100755 (executable)
index 0000000..834ee3b
--- /dev/null
@@ -0,0 +1,69 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/mv_files/mv_files_common.kshlib
+
+#
+# DESCRIPTION:
+# Doing a 'mv' of a large amount of files between two directories
+# within a zfs filesystem works without errors.
+#
+# STRATEGY:
+#
+# 1. create a pool and a zfs filesystem
+# 2. create two directories within the filesystem
+# 3. create a large number of files within a directory
+# 4. Move files from one directory to another and back again
+# 5. validate file number
+# 6. increase the number of files to $MVNUMFILES + $MVNUMINCR
+# 7. repeat steps 3,4,5,6 above
+# 8. verify the data integrity
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       PIDS=""
+       $RM -f $OLDDIR/* >/dev/null 2>&1
+       $RM -f $NEWDIR_IN_FS/* >/dev/null 2>&1
+}
+
+log_assert "Doing a 'mv' of a large amount of files within a zfs filesystem" \
+           "works without errors."
+
+log_onexit cleanup
+
+mv_test $OLDDIR $NEWDIR_IN_FS
+(($? != 0 )) &&  log_fail "'mv' test failed to complete."
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_002_pos.ksh
new file mode 100755 (executable)
index 0000000..f80447f
--- /dev/null
@@ -0,0 +1,71 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/mv_files/mv_files_common.kshlib
+
+#
+# DESCRIPTION:
+# Doing a 'mv' of a large amount of files between two directories across
+# two zfs filesystems works without errors.
+#
+# STRATEGY:
+#
+# 1. create a pool and two zfs filesystems
+# 2. create a directory in each filesystem
+# 3. create a large number of files in a directory of a filesystem
+# 4. Move files from the directory to another directory in another
+# filesystem and back again
+# 5. validate file number
+# 6. increase the number of files to $MVNUMFILES + $MVNUMINCR
+# 7. repeat steps 3,4,5,6 above
+# 8. verify the data integrity
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       PIDS=""
+       $RM -f $OLDDIR/* >/dev/null 2>&1
+       $RM -f $NEWDIR_ACROSS_FS/* >/dev/null 2>&1
+}
+
+log_assert "Doing a 'mv' of a large amount of files across two zfs filesystems" \
+           "works without errors."
+
+log_onexit cleanup
+
+mv_test $OLDDIR $NEWDIR_ACROSS_FS
+(($? != 0 )) && \
+        log_fail "'mv' test failed to complete."
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_common.kshlib b/zfs/tests/zfs-tests/tests/functional/mv_files/mv_files_common.kshlib
new file mode 100644 (file)
index 0000000..32190d8
--- /dev/null
@@ -0,0 +1,217 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/mv_files/mv_files.cfg
+
+#
+# Determine whether this version of the ksh being
+# executed has a bug where the limit of background
+# processes of 25.
+#
+function check_bg_procs_limit_num
+{
+$ECHO "#!/bin/ksh" > /var/tmp/exitsZero.ksh
+$ECHO  "exit 0" >> /var/tmp/exitsZero.ksh
+$CHMOD 777 /var/tmp/exitsZero.ksh
+
+$CAT <<EOF > /var/tmp/testbackgprocs.ksh
+#!/bin/ksh
+#
+# exitsZero.ksh is a one line script
+# that exit with status of "0"
+#
+
+PIDS=""
+typeset -i i=1
+while [ \$i -le 50 ]
+do
+       /var/tmp/exitsZero.ksh &
+        PIDS="\$PIDS \$!"
+        (( i = i + 1 ))
+done
+
+\$SLEEP 1
+
+for pid in \$PIDS
+do
+       \$WAIT \$pid
+        (( \$? == 127 )) && exit 1
+done
+exit 0
+EOF
+
+$KSH /var/tmp/testbackgprocs.ksh
+if [[ $? -eq 1 ]]; then
+#
+# Current ksh being executed has a limit
+# of 25 background processes.
+#
+       return 1
+else
+        return 0
+fi
+}
+
+function init_setup
+{
+
+       typeset disklist=$1
+
+        create_pool $TESTPOOL "$disklist"
+
+       if ! is_global_zone ; then
+               reexport_pool
+       fi
+
+        $RM -rf $TESTDIR  || log_unresolved Could not remove $TESTDIR
+        $MKDIR -p $TESTDIR || log_unresolved Could not create $TESTDIR
+
+        $RM -rf $TESTDIR_TGT  || log_unresolved Could not remove $TESTDIR_TGT
+        $MKDIR -p $TESTDIR_TGT || log_unresolved Could not create $TESTDIR_TGT
+
+        log_must $ZFS create $TESTPOOL/$TESTFS
+        log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+
+        log_must $ZFS create $TESTPOOL/$TESTFS_TGT
+        log_must $ZFS set mountpoint=$TESTDIR_TGT $TESTPOOL/$TESTFS_TGT
+
+        $MKDIR -p $OLDDIR || log_unresolved Could not create $OLDDIR
+        $MKDIR -p $NEWDIR_IN_FS || log_unresolved Could not create $NEWDIR_IN_FS
+        $MKDIR -p $NEWDIR_ACROSS_FS || log_unresolved Could not create $NEWDIR_ACROSS_FS
+
+}
+
+function wait_pid
+{
+       for pid in $1
+       do
+               $PS -e | $GREP $pid >/dev/null 2>&1
+               (( $? == 0 )) && $WAIT $pid
+        done
+}
+
+
+#
+# Generate given number files in a
+# directory of zfs file system
+# $1 - the directory holds the generated files
+# $2 - number of to-be-generated files
+#
+
+function generate_files
+{
+       typeset -i count
+        typeset -i proc_num=0
+
+       if (( $2 == $MVNUMFILES )); then
+               count=1
+       else
+               count=$MVNUMFILES+1
+       fi
+
+        while (( count <= $2 ))
+        do
+                $CP /etc/passwd $1/file_$count \
+                         > /dev/null 2>&1 &
+
+                PIDS="$PIDS $!"
+
+                proc_num=`$ECHO $PIDS | $WC -w`
+                if (( proc_num >= GANGPIDS )); then
+                        wait_pid "$PIDS"
+                        proc_num=0
+                        PIDS=""
+                fi
+
+               (( count = count + 1 ))
+        done
+
+}
+
+#
+# Move given number files from one directory to
+# another directory in parallel
+# $1 - source directory
+# $2 - target directory
+#
+function mv_files
+{
+
+        $FIND $1 -type f -print | xargs -i \
+                $MV {} $2 > /dev/null 2>&1
+}
+
+#
+# Count the files number after moving, and
+# compare it with the original number
+# $1 - directory that to be operated
+# $2 - original files number
+#
+function count_files
+{
+        typeset -i file_num
+        file_num=`$FIND $1  -type f -print | \
+                wc -l`
+        (( file_num != $2 )) && \
+                log_fail "The file number of target directory"\
+                        "$2 is not equal to that of the source "\
+                        "directory $1"
+
+}
+
+#
+# Running the 'mv' test
+# $1 - old directory
+# $2 - new directory
+#
+function mv_test
+{
+        typeset old=$1
+        typeset new=$2
+
+        typeset -i inc_num=$(( MVNUMFILES + MVNUMINCR ))
+        typeset -i num=0
+
+        for num in $MVNUMFILES $inc_num
+        do
+                generate_files $old $num
+
+                mv_files $old $new
+                count_files $new $num
+
+                mv_files $new $old
+                count_files $old $num
+        done
+
+       typeset dir=$(get_device_dir $DISKS)
+        verify_filesys "$TESTPOOL" "$TESTPOOL/$TESTFS" "$dir"
+
+        return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/mv_files/setup.ksh b/zfs/tests/zfs-tests/tests/functional/mv_files/setup.ksh
new file mode 100755 (executable)
index 0000000..e4e97b1
--- /dev/null
@@ -0,0 +1,47 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/mv_files/mv_files_common.kshlib
+
+verify_runnable "global"
+
+check_bg_procs_limit_num
+if [[ $? -ne 0 ]]; then
+       log_note "ksh background process limit number is 25"
+       export GANGPIDS=25
+fi
+
+export PIDS=""
+
+init_setup $DISK
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/nestedfs/Makefile.am b/zfs/tests/zfs-tests/tests/functional/nestedfs/Makefile.am
new file mode 100644 (file)
index 0000000..6a5ecf2
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/nestedfs
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       nestedfs_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/nestedfs/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/nestedfs/cleanup.ksh
new file mode 100755 (executable)
index 0000000..c4c3691
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_container_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/nestedfs/nestedfs_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/nestedfs/nestedfs_001_pos.ksh
new file mode 100755 (executable)
index 0000000..b27dd6e
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Given a pool create a nested file system and a ZFS file system
+# in the nested file system. Populate the file system.
+#
+# As a sub-assertion, the test verifies that a nested file system with
+# a mounted file system cannot be destroyed.
+#
+# STRATEGY:
+# 1. Create a file in the new mountpoint
+# 2. Unmount the new mountpoint
+# 3. Show a nested file system with file systems cannot be destroyed
+#
+
+verify_runnable "both"
+
+log_assert "Verify a nested file system can be created/destroyed."
+
+log_must $FILE_WRITE -o create -f $TESTDIR1/file -b 8192 -c 600 -d 0
+log_must $ZFS unmount $TESTDIR1
+
+log_note "Verify that a nested file system with a mounted file system "\
+    "cannot be destroyed."
+log_mustnot $ZFS destroy $TESTPOOL/$TESTCTR
+
+log_pass "A nested file system was successfully populated."
diff --git a/zfs/tests/zfs-tests/tests/functional/nestedfs/setup.ksh b/zfs/tests/zfs-tests/tests/functional/nestedfs/setup.ksh
new file mode 100755 (executable)
index 0000000..677cb12
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_container_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/no_space/Makefile.am b/zfs/tests/zfs-tests/tests/functional/no_space/Makefile.am
new file mode 100644 (file)
index 0000000..19a5313
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/no_space
+dist_pkgdata_SCRIPTS = \
+       enospc.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       enospc_001_pos.ksh \
+       enospc_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/no_space/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/no_space/cleanup.ksh
new file mode 100755 (executable)
index 0000000..6fedeaa
--- /dev/null
@@ -0,0 +1,54 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/no_space/enospc.cfg
+
+verify_runnable "global"
+
+DISK=${DISKS%% *}
+
+ismounted "$TESTPOOL/$TESTFS"
+(( $? == 0 )) && \
+        log_must $ZFS umount $TESTDIR
+
+destroy_pool $TESTPOOL
+
+if is_mpath_device $DISK; then
+       delete_partitions
+fi
+
+#
+# Remove 100mb partition.
+#
+create_pool dummy$$ "$DISK"
+destroy_pool dummy$$
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/no_space/enospc.cfg b/zfs/tests/zfs-tests/tests/functional/no_space/enospc.cfg
new file mode 100644 (file)
index 0000000..df1c939
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export TESTFILE0=testfile0.$$
+export TESTFILE1=testfile1.$$
+
+export SIZE=100mb
+export ENOSPC=28
+export BLOCKSZ=8192
+export NUM_WRITES=65536
+export DATA=0
+
+export DISKSARRAY=$DISKS
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+set_device_dir
diff --git a/zfs/tests/zfs-tests/tests/functional/no_space/enospc_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/no_space/enospc_001_pos.ksh
new file mode 100755 (executable)
index 0000000..7b20eb7
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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) 2013, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/no_space/enospc.cfg
+
+#
+# DESCRIPTION:
+# ENOSPC is returned on an attempt to write a second file
+# to a file system after a first file was written that terminated
+# with ENOSPC on a cleanly initialized file system.
+#
+# STRATEGY:
+# 1. Write a file until the file system is full.
+# 2. Ensure that ENOSPC is returned.
+# 3. Write a second file while the file system remains full.
+# 4. Verify the return code is ENOSPC.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       rm -f $TESTDIR/$TESTFILE0
+       rm -f $TESTDIR/$TESTFILE1
+}
+
+log_onexit cleanup
+
+log_assert "ENOSPC is returned when file system is full."
+log_must $ZFS set compression=off $TESTPOOL/$TESTFS
+
+log_note "Writing file: $TESTFILE0 until ENOSPC."
+$FILE_WRITE -o create -f $TESTDIR/$TESTFILE0 -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+ret=$?
+
+(( $ret != $ENOSPC )) && \
+    log_fail "$TESTFILE0 returned: $ret rather than ENOSPC."
+
+log_note "Write another file: $TESTFILE1 but expect ENOSPC."
+$FILE_WRITE -o create -f $TESTDIR/$TESTFILE1 -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+ret=$?
+
+(( $ret != $ENOSPC )) && \
+    log_fail "$TESTFILE1 returned: $ret rather than ENOSPC."
+
+log_pass "ENOSPC returned as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/no_space/enospc_002_pos.ksh
new file mode 100644 (file)
index 0000000..25d88d7
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/no_space/enospc.cfg
+
+#
+# DESCRIPTION:
+# After filling a filesystem, certain zfs commands are allowed.
+#
+
+verify_runnable "both"
+
+log_assert "ENOSPC is returned when file system is full."
+sync
+log_must $ZFS set compression=off $TESTPOOL/$TESTFS
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snap
+
+log_note "Writing file: $TESTFILE0 until ENOSPC."
+$FILE_WRITE -o create -f $TESTDIR/$TESTFILE0 -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+ret=$?
+
+(( $ret != $ENOSPC )) && \
+    log_fail "$TESTFILE0 returned: $ret rather than ENOSPC."
+
+log_mustnot_expect space $ZFS create $TESTPOOL/$TESTFS/subfs
+log_mustnot_expect space $ZFS clone $TESTPOOL/$TESTFS@snap $TESTPOOL/clone
+log_mustnot_expect space $ZFS snapshot $TESTPOOL/$TESTFS@snap2
+log_mustnot_expect space $ZFS bookmark \
+    $TESTPOOL/$TESTFS@snap $TESTPOOL/$TESTFS#bookmark
+
+log_must $ZFS send $TESTPOOL/$TESTFS@snap >/tmp/stream.$$
+log_mustnot_expect space $ZFS receive $TESTPOOL/$TESTFS/recvd </tmp/stream.$$
+log_must rm /tmp/stream.$$
+
+log_must $ZFS rename $TESTPOOL/$TESTFS@snap $TESTPOOL/$TESTFS@snap_newname
+log_must $ZFS rename $TESTPOOL/$TESTFS@snap_newname $TESTPOOL/$TESTFS@snap
+log_must $ZFS rename $TESTPOOL/$TESTFS $TESTPOOL/${TESTFS}_newname
+log_must $ZFS rename $TESTPOOL/${TESTFS}_newname $TESTPOOL/$TESTFS
+log_must $ZFS allow staff snapshot $TESTPOOL/$TESTFS
+log_must $ZFS unallow staff snapshot $TESTPOOL/$TESTFS
+log_must $ZFS set user:prop=value $TESTPOOL/$TESTFS
+log_must $ZFS set quota=1EB $TESTPOOL/$TESTFS
+log_must $ZFS set quota=none $TESTPOOL/$TESTFS
+log_must $ZFS set reservation=1KB $TESTPOOL/$TESTFS
+log_must $ZFS set reservation=none $TESTPOOL/$TESTFS
+log_must $ZPOOL scrub $TESTPOOL
+$ZPOOL scrub -s $TESTPOOL
+log_must $ZPOOL set comment="Use the force, Luke." $TESTPOOL
+log_must $ZPOOL set comment="" $TESTPOOL
+
+# destructive tests must come last
+log_must $ZFS rollback $TESTPOOL/$TESTFS@snap
+log_must $ZFS destroy $TESTPOOL/$TESTFS@snap
+
+log_pass "ENOSPC returned as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/no_space/setup.ksh b/zfs/tests/zfs-tests/tests/functional/no_space/setup.ksh
new file mode 100755 (executable)
index 0000000..7d177c7
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/no_space/enospc.cfg
+
+verify_runnable "global"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+DISK=${DISKS%% *}
+
+log_must set_partition 0 "" $SIZE $DISK
+
+if is_linux; then
+       if ( is_mpath_device $DISK ) && [[ -z $($ECHO $DISK | awk 'substr($1,18,1)\
+           ~ /^[[:digit:]]+$/') ]] || ( is_real_device $DISK ); then
+               default_setup $DISK"1"
+       elif ( is_mpath_device $DISK || is_loop_device $DISK ); then
+               default_setup $DISK"p1"
+       else
+               log_fail "$DISK not supported for partitioning."
+       fi
+else
+       default_setup $DISK"s0"
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/Makefile.am b/zfs/tests/zfs-tests/tests/functional/nopwrite/Makefile.am
new file mode 100644 (file)
index 0000000..c7c90e3
--- /dev/null
@@ -0,0 +1,13 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/nopwrite
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       nopwrite.shlib \
+       nopwrite_copies.ksh \
+       nopwrite_mtime.ksh \
+       nopwrite_negative.ksh \
+       nopwrite_promoted_clone.ksh \
+       nopwrite_recsize.ksh \
+       nopwrite_sync.ksh \
+       nopwrite_varying_compression.ksh \
+       nopwrite_volume.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/cleanup.ksh
new file mode 100755 (executable)
index 0000000..2d7b69a
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. ${STF_SUITE}/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite.shlib b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite.shlib
new file mode 100644 (file)
index 0000000..a03bc54
--- /dev/null
@@ -0,0 +1,68 @@
+#
+# 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.
+#
+
+. $STF_SUITE/include/math.shlib
+
+export TESTVOL="testvol.nopwrite"
+export VOLSIZE="256M"
+export MEGS="64"
+
+function verify_nopwrite
+{
+       typeset origin=$1
+       typeset snap=$2
+       typeset clone=$3
+       typeset low=1
+       typeset high=99
+
+       $SYNC
+       for i in origin snap clone; do
+               for j in used refer usedbychildren written; do
+                       typeset ${i}_$j=$(get_prop $j $(eval echo \$$i))
+               done
+       done
+
+       #
+       # If we are dealing with a volume, deduct the refreserv from the used
+       # value to prevent real failures from being masked by the unexpected
+       # extra space. Also, volumes use more space for metadata, so adjust the
+       # percentages to be more forgiving.
+       #
+       if [[ "$(get_prop type $origin)" = "volume" ]]; then
+               typeset rr=$(get_prop refreserv $origin)
+               ((origin_used -= rr ))
+               low=2
+               high=98
+       fi
+
+       # These values should differ greatly with nopwrite.
+       within_percent $origin_used $clone_used $low && return 1
+       within_percent $origin_refer $origin_usedbychildren $low && return 1
+       within_percent $snap_written $clone_written $low && return 1
+
+       # These values should be nearly the same with nopwrite.
+       within_percent $origin_used $clone_refer $high || return 1
+       within_percent $origin_used $snap_refer $high || return 1
+
+       #
+       # The comparisons below should pass regardless of nopwrite. They're
+       # here for sanity.
+       #
+       typeset deadlist=$($ZDB -Pddd $clone | $AWK '/Deadlist:/ {print $2}')
+       within_percent $deadlist $clone_written $high || return 1
+       within_percent $snap_refer $snap_written $high || return 1
+
+       return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_copies.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_copies.ksh
new file mode 100755 (executable)
index 0000000..94a846a
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/nopwrite/nopwrite.shlib
+
+#
+# Description:
+# Verify that nopwrite is not enabled if the copies property changes
+#
+# Strategy:
+# 1. Create a clone with copies set higher than the origin fs
+# 2. Verify that nopwrite is in use.
+# 3. Repeat with the number of copies decreased.
+#
+
+verify_runnable "global"
+origin="$TESTPOOL/$TESTFS"
+log_onexit cleanup
+
+function cleanup
+{
+       datasetexists $origin && log_must $ZFS destroy -R $origin
+       log_must $ZFS create -o mountpoint=$TESTDIR $origin
+}
+
+log_assert "nopwrite requires copies property to remain constant"
+
+# Verify nopwrite is disabled with increased redundancy
+log_must $ZFS set compress=on $origin
+log_must $ZFS set checksum=sha256 $origin
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone $origin@a $origin/clone
+$ZFS set copies=3 $origin/clone
+$DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+log_mustnot verify_nopwrite $origin $origin@a $origin/clone
+
+# Verify nopwrite is disabled with decreased redundancy
+$ZFS destroy -R $origin || log_fail "Couldn't destroy $origin"
+$ZFS create -o mountpoint=$TESTDIR $origin || \
+    log_fail "Couldn't recreate $origin"
+log_must $ZFS set compress=on $origin
+log_must $ZFS set copies=3 $origin
+log_must $ZFS set checksum=sha256 $origin
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone $origin@a $origin/clone
+$ZFS set copies=1 $origin/clone
+$DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+log_mustnot verify_nopwrite $origin $origin@a $origin/clone
+
+log_pass "nopwrite requires copies property to remain constant"
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_mtime.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_mtime.ksh
new file mode 100755 (executable)
index 0000000..23d4be2
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/nopwrite/nopwrite.shlib
+
+#
+# Description:
+# Verify that nopwrite still updates file metadata correctly
+#
+# Strategy:
+# 1. Create a clone with nopwrite enabled.
+# 2. Write to the file in that clone and verify the mtime and ctime change,
+# but the atime does not.
+#
+
+verify_runnable "global"
+origin="$TESTPOOL/$TESTFS"
+log_onexit cleanup
+
+function cleanup
+{
+       datasetexists $origin && log_must $ZFS destroy -R $origin
+       log_must $ZFS create -o mountpoint=$TESTDIR $origin
+}
+
+log_assert "nopwrite updates file metadata correctly"
+
+log_must $ZFS set compress=on $origin
+log_must $ZFS set checksum=sha256 $origin
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone $origin@a $origin/clone
+
+if is_linux; then
+       o_atime=$(stat -c %X $TESTDIR/clone/file)
+       o_ctime=$(stat -c %Z $TESTDIR/clone/file)
+       o_mtime=$(stat -c %Y $TESTDIR/clone/file)
+else
+       o_atime=$($LS -E% all $TESTDIR/clone/file | $AWK '/atime/ {print $4}')
+       o_ctime=$($LS -E% all $TESTDIR/clone/file | $AWK '/ctime/ {print $4}')
+       o_mtime=$($LS -E% all $TESTDIR/clone/file | $AWK '/mtime/ {print $4}')
+fi
+
+$SLEEP 1
+$DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+$SLEEP 1
+
+if is_linux; then
+       atime=$(stat -c %X $TESTDIR/clone/file)
+       ctime=$(stat -c %Z $TESTDIR/clone/file)
+       mtime=$(stat -c %Y $TESTDIR/clone/file)
+else
+       atime=$($LS -E% all $TESTDIR/clone/file | $AWK '/atime/ {print $4}')
+       ctime=$($LS -E% all $TESTDIR/clone/file | $AWK '/ctime/ {print $4}')
+       mtime=$($LS -E% all $TESTDIR/clone/file | $AWK '/mtime/ {print $4}')
+fi
+
+[[ $o_atime = $atime ]] || log_fail "atime changed: $o_atime $atime"
+[[ $o_ctime = $ctime ]] && log_fail "ctime unchanged: $o_ctime $ctime"
+[[ $o_mtime = $mtime ]] && log_fail "mtime unchanged: $o_mtime $mtime"
+
+log_must verify_nopwrite $origin $origin@a $origin/clone
+
+log_pass "nopwrite updates file metadata correctly"
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_negative.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_negative.ksh
new file mode 100755 (executable)
index 0000000..921d17f
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/nopwrite/nopwrite.shlib
+
+#
+# Description:
+# Verify that duplicate writes to a clone are accounted as new data if the
+# prerequisites for nopwrite are not met.
+#
+# Scenarios:
+# 1. The file in the origin ds is written without compression or sha256.
+# 2. The file in the origin ds is written before sha256 checksum is turned on.
+# 3. The clone does not have compression.
+# 4. The clone does not have the appropriate checksum.
+#
+
+verify_runnable "global"
+origin="$TESTPOOL/$TESTFS"
+log_onexit cleanup
+
+function cleanup
+{
+       datasetexists $origin && log_must $ZFS destroy -R $origin
+       log_must $ZFS create -o mountpoint=$TESTDIR $origin
+}
+
+log_assert "nopwrite isn't enabled without the prerequisites"
+
+# Data written into origin fs without compression or sha256
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd of $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone -o compress=on $origin@a $origin/clone
+log_must $ZFS set checksum=sha256 $origin/clone
+$DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+log_mustnot verify_nopwrite $origin $origin@a $origin/clone
+$ZFS destroy -R $origin@a || log_fail "zfs destroy failed"
+log_must $RM -f $TESTDIR/file
+
+# Data written to origin fs before checksum enabled
+log_must $ZFS set compress=on $origin
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+log_must $ZFS set checksum=sha256 $origin
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone $origin@a $origin/clone
+$DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+log_mustnot verify_nopwrite $origin $origin@a $origin/clone
+$ZFS destroy -R $origin@a || log_fail "zfs destroy failed"
+log_must $RM -f $TESTDIR/file
+
+# Clone with compression=off
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone -o compress=off $origin@a $origin/clone
+$DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+log_mustnot verify_nopwrite $origin $origin@a $origin/clone
+$ZFS destroy -R $origin@a || log_fail "zfs destroy failed"
+log_must $RM -f $TESTDIR/file
+
+# Clone with fletcher4, rather than sha256
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone -o checksum=fletcher4 $origin@a $origin/clone
+$DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+log_mustnot verify_nopwrite $origin $origin@a $origin/clone
+
+log_pass "nopwrite isn't enabled without the prerequisites"
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_promoted_clone.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_promoted_clone.ksh
new file mode 100755 (executable)
index 0000000..7a21aa5
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/nopwrite/nopwrite.shlib
+
+#
+# Description:
+# Verify that nopwrite still works for a dataset that becomes a clone via
+# promotion.
+#
+# Strategy:
+# 1. Create a clone suitable for nopwrite.
+# 2. Disable compression and checksum on the clone, and promote it.
+# 3. Overwrite the file in the clone (former origin fs) and verify it
+# consumes no additional space.
+#
+
+verify_runnable "global"
+origin="$TESTPOOL/$TESTFS"
+log_onexit cleanup
+
+function cleanup
+{
+       datasetexists $origin && log_must $ZFS destroy -R $TESTPOOL/clone
+       log_must $ZFS create -o mountpoint=$TESTDIR $origin
+}
+
+log_assert "nopwrite works on a dataset that becomes a clone via promotion."
+
+log_must $ZFS set compress=on $origin
+log_must $ZFS set checksum=sha256 $origin
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone $origin@a $TESTPOOL/clone
+log_must $ZFS set compress=off $TESTPOOL/clone
+log_must $ZFS set checksum=off $TESTPOOL/clone
+log_must $ZFS promote $TESTPOOL/clone
+$DD if=/$TESTPOOL/clone/file of=/$TESTDIR/file bs=1024k count=$MEGS \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+log_must verify_nopwrite $TESTPOOL/clone $TESTPOOL/clone@a $origin
+
+log_pass "nopwrite works on a dataset that becomes a clone via promotion."
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_recsize.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_recsize.ksh
new file mode 100755 (executable)
index 0000000..a3c272c
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/nopwrite/nopwrite.shlib
+
+#
+# Description:
+# Verify that nopwrite works regardless of recsize property setting.
+#
+# Strategy:
+# 1. Create an origin fs that's suitable to make nopwrite clones.
+# 2. For each possible recsize, create a clone that inherits the compress and
+# checksum, and verify overwriting the origin file consumes no new space.
+#
+
+verify_runnable "global"
+origin="$TESTPOOL/$TESTFS"
+log_onexit cleanup
+
+function cleanup
+{
+       datasetexists $origin && log_must $ZFS destroy -R $origin
+       log_must $ZFS create -o mountpoint=$TESTDIR $origin
+}
+
+log_assert "nopwrite updates file metadata correctly"
+
+log_must $ZFS set compress=on $origin
+log_must $ZFS set checksum=sha256 $origin
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone $origin@a $origin/clone
+
+for rs in 512 1024 2048 4096 8192 16384 32768 65536 131072 ; do
+       log_must $ZFS set recsize=$rs $origin/clone
+       $DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+           conv=notrunc >/tmp/null 2>&1 || log_fail "dd failed."
+       log_must verify_nopwrite $origin $origin@a $origin/clone
+done
+
+log_pass "nopwrite updates file metadata correctly"
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_sync.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_sync.ksh
new file mode 100755 (executable)
index 0000000..d6cc66f
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/nopwrite/nopwrite.shlib
+
+#
+# Description:
+# Verify that nopwrite works for sync writes
+#
+# Strategy:
+# 1. Create an origin fs with compression and sha256.
+# 2. Clone origin such that it inherits the properies.
+# 3. Use dd with the sync flag to test the sync write path.
+#
+
+verify_runnable "global"
+origin="$TESTPOOL/$TESTFS"
+log_onexit cleanup
+
+function cleanup
+{
+       datasetexists $origin && log_must $ZFS destroy -R $origin
+       log_must $ZFS create -o mountpoint=$TESTDIR $origin
+}
+
+log_assert "nopwrite works for sync writes"
+
+log_must $ZFS set compress=on $origin
+log_must $ZFS set checksum=sha256 $origin
+$GNUDD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS oflag=sync \
+    conv=notrunc >/dev/null 2>&1 || log_fail "dd into $TESTDIR/file failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone $origin@a $origin/clone
+
+$GNUDD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+    oflag=sync conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+
+log_must verify_nopwrite $origin $origin@a $origin/clone
+
+log_pass "nopwrite works for sync writes"
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_varying_compression.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_varying_compression.ksh
new file mode 100755 (executable)
index 0000000..12450f8
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/properties.shlib
+. $STF_SUITE/tests/functional/nopwrite/nopwrite.shlib
+
+#
+# Description:
+# Verify that if the checksum on the origin and clone is sha256, any compression
+# algorithm enables nopwrite.
+#
+# Strategy:
+# 1. Create an origin dataset with compression and sha256 checksum.
+# 2. Write a 64M file into the origin dataset.
+# 3. For each of 4 randomly chosen compression types:
+# 3a. Create a snap and clone (inheriting the checksum property) of the origin.
+# 3b. Apply the compression property to the clone.
+# 3c. Write the same 64M of data into the file that exists in the clone.
+# 3d. Verify that no new space was consumed.
+#
+
+verify_runnable "global"
+origin="$TESTPOOL/$TESTFS"
+log_onexit cleanup
+
+function cleanup
+{
+       datasetexists $origin && log_must $ZFS destroy -R $origin
+       log_must $ZFS create -o mountpoint=$TESTDIR $origin
+}
+
+log_assert "nopwrite works with sha256 and any compression algorithm"
+
+log_must $ZFS set compress=on $origin
+log_must $ZFS set checksum=sha256 $origin
+$DD if=/dev/urandom of=$TESTDIR/file bs=1024k count=$MEGS conv=notrunc \
+    >/dev/null 2>&1 || log_fail "initial dd failed."
+
+# Verify nop_write for 4 random compression algorithms
+for i in $(get_rand_compress 4); do
+       $ZFS snapshot $origin@a || log_fail "zfs snap failed"
+       log_must $ZFS clone -o compress=$i $origin@a $origin/clone
+       $DD if=/$TESTDIR/file of=/$TESTDIR/clone/file bs=1024k count=$MEGS \
+           conv=notrunc >/dev/null 2>&1 || log_fail "dd failed."
+       log_must verify_nopwrite $origin $origin@a $origin/clone
+       $ZFS destroy -R $origin@a || log_fail "zfs destroy failed"
+done
+
+log_pass "nopwrite works with sha256 and any compression algorithm"
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_volume.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/nopwrite_volume.ksh
new file mode 100755 (executable)
index 0000000..28c1dfa
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/nopwrite/nopwrite.shlib
+
+#
+# Description:
+# Verify that nopwrite cannot be enabled on volumes
+#
+# Strategy:
+# 1. Create a clone of a volume that fits the criteria for nopwrite.
+# 2. Overwrite the same blocks from the origin vol and verify that
+# new space is consumed.
+#
+
+verify_runnable "global"
+origin="$TESTPOOL/$TESTVOL"
+clone="$TESTPOOL/clone"
+vol="${ZVOL_RDEVDIR}/$origin"
+volclone="${ZVOL_RDEVDIR}/$clone"
+log_onexit cleanup
+
+function cleanup
+{
+       datasetexists $origin && log_must $ZFS destroy -R $origin
+       # No need to recreate the volume as no other tests expect it.
+}
+
+log_assert "nopwrite works on volumes"
+
+log_must $ZFS set compress=on $origin
+log_must $ZFS set checksum=sha256 $origin
+$DD if=/dev/urandom of=$vol bs=8192 count=4096 conv=notrunc >/dev/null \
+    2>&1 || log_fail "dd into $orgin failed."
+$ZFS snapshot $origin@a || log_fail "zfs snap failed"
+log_must $ZFS clone $origin@a $clone
+log_must $ZFS set compress=on $clone
+log_must $ZFS set checksum=sha256 $clone
+$DD if=$vol of=$volclone bs=8192 count=4096 conv=notrunc >/dev/null 2>&1 || \
+    log_fail "dd into $clone failed."
+log_must verify_nopwrite $origin $origin@a $clone
+
+log_pass "nopwrite works on volumes"
diff --git a/zfs/tests/zfs-tests/tests/functional/nopwrite/setup.ksh b/zfs/tests/zfs-tests/tests/functional/nopwrite/setup.ksh
new file mode 100755 (executable)
index 0000000..17c68a6
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/ksh
+
+#
+# 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.
+#
+
+. ${STF_SUITE}/include/libtest.shlib
+. ${STF_SUITE}/tests/functional/nopwrite/nopwrite.shlib
+
+disk=${DISKS%% *}
+
+default_volume_setup $disk
diff --git a/zfs/tests/zfs-tests/tests/functional/online_offline/Makefile.am b/zfs/tests/zfs-tests/tests/functional/online_offline/Makefile.am
new file mode 100644 (file)
index 0000000..9562ba5
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/online_offline
+dist_pkgdata_SCRIPTS = \
+       online_offline.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       online_offline_001_pos.ksh \
+       online_offline_002_neg.ksh \
+       online_offline_003_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/online_offline/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/online_offline/cleanup.ksh
new file mode 100755 (executable)
index 0000000..b81a372
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/online_offline/online_offline.cfg b/zfs/tests/zfs-tests/tests/functional/online_offline/online_offline.cfg
new file mode 100644 (file)
index 0000000..42be907
--- /dev/null
@@ -0,0 +1,42 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export TESTFILE=testfile.$$
+export TESTFILE1=testfile1.$$
+export HOLES_FILESIZE=${HOLES_FILESIZE-"67108864"} # 64 Mb
+export HOLES_BLKSIZE=${HOLES_BLKSIZE-"512"}
+export HOLES_SEED=${HOLES_SEED-""}
+export HOLES_FILEOFFSET=${HOLES_FILEOFFSET-""}
+export HOLES_COUNT=${HOLES_COUNT-"16384"}         # FILESIZE/BLKSIZE/8
+export STF_TIMEOUT=3600
+
+export DISKSARRAY=$DISKS
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+set_device_dir
diff --git a/zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_001_pos.ksh
new file mode 100755 (executable)
index 0000000..d98ef7f
--- /dev/null
@@ -0,0 +1,94 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Turning a disk offline and back online during I/O completes.
+#
+# STRATEGY:
+# 1. Create a mirror and start some random I/O
+# 2. For each disk in the mirror, set it offline and online
+# 3. Verify the integrity of the file system and the resilvering.
+#
+
+verify_runnable "global"
+log_onexit cleanup
+
+DISKLIST=$(get_disklist $TESTPOOL)
+
+function cleanup
+{
+       #
+       # Ensure we don't leave disks in the offline state
+       #
+       for disk in $DISKLIST; do
+               log_must $ZPOOL online $TESTPOOL $disk
+               check_state $TESTPOOL $disk "online"
+               if [[ $? != 0 ]]; then
+                       log_fail "Unable to online $disk"
+               fi
+
+       done
+
+       $KILL $killpid >/dev/null 2>&1
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "Turning a disk offline and back online during I/O completes."
+
+$FILE_TRUNC -f $((64 * 1024 * 1024)) -b 8192 -c 0 -r $TESTDIR/$TESTFILE1 &
+typeset killpid="$! "
+
+for disk in $DISKLIST; do
+        for i in 'do_offline' 'do_offline_while_already_offline'; do
+               log_must $ZPOOL offline $TESTPOOL $disk
+               check_state $TESTPOOL $disk "offline"
+                if [[ $? != 0 ]]; then
+                        log_fail "$disk of $TESTPOOL is not offline."
+                fi
+        done
+
+        log_must $ZPOOL online $TESTPOOL $disk
+        check_state $TESTPOOL $disk "online"
+        if [[ $? != 0 ]]; then
+                log_fail "$disk of $TESTPOOL did not match online state"
+        fi
+done
+
+log_must $KILL $killpid
+$SYNC
+
+typeset dir=$(get_device_dir $DISKS)
+verify_filesys "$TESTPOOL" "$TESTPOOL/$TESTFS" "$dir"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_002_neg.ksh
new file mode 100755 (executable)
index 0000000..12c191a
--- /dev/null
@@ -0,0 +1,132 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Turning disks in a pool offline should fail when there is no longer
+# sufficient redundancy.
+#
+# STRATEGY:
+# 1. Start some random I/O on the mirror or raidz.
+# 2. Verify that we can offline as many disks as the redundancy level
+# will support, but not more.
+# 3. Verify the integrity of the file system and the resilvering.
+#
+
+verify_runnable "global"
+
+DISKLIST=$(get_disklist $TESTPOOL)
+
+function cleanup
+{
+       #
+       # Ensure we don't leave disks in the offline state
+       #
+       for disk in $DISKLIST; do
+               log_must $ZPOOL online $TESTPOOL $disk
+               check_state $TESTPOOL $disk "online"
+               if [[ $? != 0 ]]; then
+                       log_fail "Unable to online $disk"
+               fi
+
+       done
+
+       $KILL $killpid >/dev/null 2>&1
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "Turning both disks offline should fail."
+
+log_onexit cleanup
+
+$FILE_TRUNC -f $((64 * 1024 * 1024)) -b 8192 -c 0 -r $TESTDIR/$TESTFILE1 &
+typeset killpid="$! "
+
+disks=($DISKLIST)
+
+#
+# The setup script will give us either a mirror or a raidz. The former can have
+# all but one vdev offlined, whereas with raidz there can be only one.
+#
+pooltype='mirror'
+$ZPOOL list -v $TESTPOOL | $GREP raidz >/dev/null 2>&1 && pooltype='raidz'
+
+typeset -i i=0
+while [[ $i -lt ${#disks[*]} ]]; do
+       typeset -i j=0
+       if [[ $pooltype = 'mirror' ]]; then
+               # Hold one disk online, verify the others can be offlined.
+               log_must $ZPOOL online $TESTPOOL ${disks[$i]}
+               check_state $TESTPOOL ${disks[$i]} "online" || \
+                   log_fail "Failed to set ${disks[$i]} online"
+               while [[ $j -lt ${#disks[*]} ]]; do
+                       if [[ $j -eq $i ]]; then
+                               ((j++))
+                               continue
+                       fi
+                       log_must $ZPOOL offline $TESTPOOL ${disks[$j]}
+                       check_state $TESTPOOL ${disks[$j]} "offline" || \
+                           log_fail "Failed to set ${disks[$j]} offline"
+                       ((j++))
+               done
+       elif [[ $pooltype = 'raidz' ]]; then
+               # Hold one disk offline, verify the others can't be offlined.
+               log_must $ZPOOL offline $TESTPOOL ${disks[$i]}
+               check_state $TESTPOOL ${disks[$i]} "offline" || \
+                   log_fail "Failed to set ${disks[$i]} offline"
+               while [[ $j -lt ${#disks[*]} ]]; do
+                       if [[ $j -eq $i ]]; then
+                               ((j++))
+                               continue
+                       fi
+                       log_mustnot $ZPOOL offline $TESTPOOL ${disks[$j]}
+                       check_state $TESTPOOL ${disks[$j]} "online" || \
+                           log_fail "Failed to set ${disks[$j]} online"
+                       check_state $TESTPOOL ${disks[$i]} "offline" || \
+                           log_fail "Failed to set ${disks[$i]} offline"
+                       ((j++))
+               done
+               log_must $ZPOOL online $TESTPOOL ${disks[$i]}
+               check_state $TESTPOOL ${disks[$i]} "online" || \
+                   log_fail "Failed to set ${disks[$i]} online"
+       fi
+       ((i++))
+done
+
+log_must $KILL $killpid
+$SYNC
+
+typeset dir=$(get_device_dir $DISKS)
+verify_filesys "$TESTPOOL" "$TESTPOOL/$TESTFS" "$dir"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/online_offline/online_offline_003_neg.ksh
new file mode 100755 (executable)
index 0000000..a9d0c33
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Offlining disks in a non-redundant pool should fail.
+#
+# STRATEGY:
+# 1. Create a multidisk stripe and start some random I/O
+# 2. zpool offline should fail on each disk.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if poolexists $TESTPOOL1; then
+               destroy_pool $TESTPOOL1
+       fi
+
+       $KILL $killpid >/dev/null 2>&1
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "Offlining disks in a non-redundant pool should fail."
+
+log_onexit cleanup
+
+specials_list=""
+for i in 0 1 2; do
+       $MKFILE 64m $TESTDIR/$TESTFILE1.$i
+       specials_list="$specials_list $TESTDIR/$TESTFILE1.$i"
+done
+disk=($specials_list)
+
+create_pool $TESTPOOL1 $specials_list
+log_must $ZFS create $TESTPOOL1/$TESTFS1
+log_must $ZFS set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
+
+$FILE_TRUNC -f $((64 * 1024 * 1024)) -b 8192 -c 0 -r $TESTDIR/$TESTFILE1 &
+typeset killpid="$! "
+
+for i in 0 1 2; do
+       log_mustnot $ZPOOL offline $TESTPOOL1 ${disk[$i]}
+       check_state $TESTPOOL1 ${disk[$i]} "online"
+done
+
+log_must $KILL $killpid
+$SYNC
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/online_offline/setup.ksh b/zfs/tests/zfs-tests/tests/functional/online_offline/setup.ksh
new file mode 100755 (executable)
index 0000000..4132392
--- /dev/null
@@ -0,0 +1,47 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+index=`expr $RANDOM % 2`
+case $index in
+0)     log_note "Pool Type: Mirror"
+       default_mirror_setup $DISKS
+       ;;
+1)     log_note "Pool Type: RAID-Z"
+       default_raidz_setup $DISKS
+       ;;
+esac
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/pool_names/Makefile.am b/zfs/tests/zfs-tests/tests/functional/pool_names/Makefile.am
new file mode 100644 (file)
index 0000000..cd87486
--- /dev/null
@@ -0,0 +1,4 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/pool_names
+dist_pkgdata_SCRIPTS = \
+       pool_names_001_pos.ksh \
+       pool_names_002_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/pool_names/pool_names_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/pool_names/pool_names_001_pos.ksh
new file mode 100755 (executable)
index 0000000..ad10740
--- /dev/null
@@ -0,0 +1,115 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Test that a set of valid names can be used to create pools. Further
+# verify that the created pools can be destroyed.
+#
+# STRATEGY:
+# 1) For each valid character in the character set, try to create
+# and destroy the pool.
+# 2) Given a list of valid pool names, try to create and destroy
+# pools with the given names.
+#
+
+verify_runnable "global"
+
+log_assert "Ensure that pool names can use the ASCII subset of UTF-8"
+
+function cleanup
+{
+       if [[ -n $name ]] && poolexists $name ; then
+               log_must $ZPOOL destroy $name
+       fi
+
+       if [[ -d $TESTDIR ]]; then
+               log_must $RM -rf $TESTDIR
+       fi
+
+}
+
+log_onexit cleanup
+
+DISK=${DISKS%% *}
+if [[ ! -e $TESTDIR ]]; then
+       log_must $MKDIR $TESTDIR
+fi
+
+log_note "Ensure letters of the alphabet are allowable"
+
+typeset name=""
+
+for name in A B C D E F G H I J K L M \
+    N O P Q R S T U V W X Y Z \
+    a b c d e f g h i j k l m \
+    n o p q r s t u v w x y z
+do
+       log_must $ZPOOL create -m $TESTDIR $name $DISK
+       if ! poolexists $name; then
+               log_fail "Could not create a pool called '$name'"
+       fi
+
+       log_must $ZPOOL destroy $name
+done
+
+log_note "Ensure a variety of unusual names passes"
+
+name=""
+
+for name in "a.............................." "a_" "a-" "a:" \
+    "a." "a123456" "bc0t0d0" "m1rr0r_p00l" "ra1dz_p00l" \
+    "araidz2" "C0t2d0" "cc0t0" "raid2:-_." "mirr_:-." \
+    "m1rr0r-p00l" "ra1dz-p00l" "spar3_p00l" \
+    "spar3-p00l" "hiddenmirrorpool" "hiddenraidzpool" \
+    "hiddensparepool"
+do
+       log_must $ZPOOL create -m $TESTDIR $name $DISK
+       if ! poolexists $name; then
+               log_fail "Could not create a pool called '$name'"
+       fi
+
+       #
+       # Since the naming convention applies to datasets too,
+       # create datasets with the same names as above.
+       #
+       log_must $ZFS create $name/$name
+       log_must $ZFS snapshot $name/$name@$name
+       log_must $ZFS clone $name/$name@$name $name/clone_$name
+       log_must $ZFS create -V 150m $name/$name/$name
+
+       log_must $ZPOOL destroy $name
+done
+
+log_pass "Valid pool names were accepted correctly."
diff --git a/zfs/tests/zfs-tests/tests/functional/pool_names/pool_names_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/pool_names/pool_names_002_neg.ksh
new file mode 100755 (executable)
index 0000000..d54fddf
--- /dev/null
@@ -0,0 +1,131 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Ensure that a set of invalid names cannot be used to create pools.
+#
+# STRATEGY:
+# 1) For each invalid character in the character set, try to create
+# and destroy the pool. Verify it fails.
+# 2) Given a list of invalid pool names, ensure the pools are not
+# created.
+#
+
+verify_runnable "global"
+
+log_assert "Ensure that a set of invalid names cannot be used to create pools."
+
+# Global variable use to cleanup failures.
+POOLNAME=""
+
+function cleanup
+{
+       if poolexists $POOLNAME; then
+               log_must $ZPOOL destroy $POOLNAME
+       fi
+
+       if [[ -d $TESTDIR ]]; then
+               log_must $RM -rf $TESTDIR
+       fi
+}
+
+log_onexit cleanup
+
+typeset exclude=`eval $ECHO \"'(${KEEP})'\"`
+for pool in $($ZPOOL list -H -o name | \
+       $EGREP -v "$exclude" | \
+       $GREP -v "$TESTPOOL" | \
+       $EGREP -v "$NO_POOLS"); do
+       log_must $ZPOOL destroy $pool
+done
+
+DISK=${DISKS%% *}
+if [[ ! -e $TESTDIR ]]; then
+        log_must $MKDIR $TESTDIR
+fi
+
+log_note "Ensure invalid characters fail"
+for POOLNAME in "!" "\"" "#" "$" "%" "&" "'" "(" ")" \
+    "\*" "+" "," "-" "\." "/" "\\" \
+    0 1 2 3 4 5 6 7 8 9 \
+    ":" ";" "<" "=" ">" "\?" "@" \
+    "[" "]" "^" "_" "\`" "{" "|" "}" "~"
+do
+       log_mustnot $ZPOOL create -m $TESTDIR $POOLNAME $DISK
+        if poolexists $POOLNAME; then
+                log_fail "Unexpectedly created pool: '$POOLNAME'"
+        fi
+
+       log_mustnot $ZPOOL destroy $POOLNAME
+done
+
+log_note "Check that invalid octal values fail"
+for oct in "\000" "\001" "\002" "\003" "\004" "\005" "\006" "\007" \
+    "\010" "\011" "\012" "\013" "\014" "\015" "\017" \
+    "\020" "\021" "\022" "\023" "\024" "\025" "\026" "\027" \
+    "\030" "\031" "\032" "\033" "\034" "\035" "\036" "\037" \
+    "\040" "\177"
+do
+       POOLNAME=`eval "echo x | tr 'x' '$oct'"`
+       log_mustnot $ZPOOL create -m $TESTDIR $POOLNAME $DISK
+        if poolexists $POOLNAME; then
+                log_fail "Unexpectedly created pool: '$POOLNAME'"
+        fi
+
+       log_mustnot $ZPOOL destroy $POOLNAME
+done
+
+log_note "Verify invalid pool names fail"
+set -A POOLNAME "c0t0d0s0" "c0t0d0" "c0t0d19" "c0t50000E0108D279d0" \
+    "mirror" "raidz" ",," ",,,,,,,,,,,,,,,,,,,,,,,,," \
+    "2222222222222222222" "mirror_pool" "raidz_pool" \
+    "mirror-pool" "raidz-pool" "spare" "spare_pool" \
+    "spare-pool" "raidz1-" "raidz2:" ":aaa" "-bbb" "_ccc" ".ddd"
+if verify_slog_support ; then
+       POOLNAME[${#POOLNAME[@]}]='log'
+fi
+typeset -i i=0
+while ((i < ${#POOLNAME[@]})); do
+       log_mustnot $ZPOOL create -m $TESTDIR ${POOLNAME[$i]} $DISK
+        if poolexists ${POOLNAME[$i]}; then
+                log_fail "Unexpectedly created pool: '${POOLNAME[$i]}'"
+        fi
+
+       log_mustnot $ZPOOL destroy ${POOLNAME[$i]}
+
+       ((i += 1))
+done
+
+log_pass "Invalid names and characters were caught correctly"
diff --git a/zfs/tests/zfs-tests/tests/functional/poolversion/Makefile.am b/zfs/tests/zfs-tests/tests/functional/poolversion/Makefile.am
new file mode 100644 (file)
index 0000000..51c2046
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/poolversion
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       poolversion_001_pos.ksh \
+       poolversion_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/poolversion/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/poolversion/cleanup.ksh
new file mode 100755 (executable)
index 0000000..6555a0d
--- /dev/null
@@ -0,0 +1,42 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+log_must $ZPOOL destroy $TESTPOOL
+log_must $ZPOOL destroy $TESTPOOL2
+
+log_must $RM /tmp/zpool_version_1.dat
+log_must $RM /tmp/zpool2_version_1.dat
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/poolversion/poolversion_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/poolversion/poolversion_001_pos.ksh
new file mode 100755 (executable)
index 0000000..6622213
--- /dev/null
@@ -0,0 +1,58 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# zpool set version can upgrade a pool
+#
+# STRATEGY:
+# 1. Taking a version 1 pool
+# 2. For all known versions, set the version of the pool using zpool set
+# 3. Verify that pools version
+#
+
+verify_runnable "global"
+log_assert "zpool set version can upgrade a pool"
+for version in 1 2 3 4 5 6 7 8
+do
+       log_must $ZPOOL set version=$version $TESTPOOL
+       ACTUAL=$($ZPOOL get version $TESTPOOL | $GREP version \
+               | $AWK '{print $3}')
+       if [ "$ACTUAL" != "$version" ]
+       then
+               log_fail "v. $ACTUAL set for $TESTPOOL, expected v. $version!"
+       fi
+done
+
+log_pass "zpool set version can upgrade a pool"
diff --git a/zfs/tests/zfs-tests/tests/functional/poolversion/poolversion_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/poolversion/poolversion_002_pos.ksh
new file mode 100755 (executable)
index 0000000..9c51a88
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# zpool set version can only increment pool version
+#
+# STRATEGY:
+# 1. Set a version 1 pool to be a version 6 pool
+# 2. Verify it's set to version 6
+# 3. Attempt to set prior versions
+# 4. Verify it's still set to version 6
+#
+
+verify_runnable "global"
+log_assert "zpool set version can only increment pool version"
+
+log_must $ZPOOL set version=6 $TESTPOOL2
+# verify it's actually that version - by checking the version property
+# and also by trying to set bootfs (which should fail if it is not version 6)
+
+VERSION=$($ZPOOL get version $TESTPOOL2| $GREP version | $AWK '{print $3}')
+if [ "$VERSION" != "6" ]
+then
+       log_fail "Version $VERSION set for $TESTPOOL2 expected version 6!"
+fi
+log_must $ZPOOL set bootfs=$TESTPOOL2 $TESTPOOL2
+
+# now verify we can't downgrade the version
+log_mustnot $ZPOOL set version=5 $TESTPOOL2
+log_mustnot $ZPOOL set version=-1 $TESTPOOL2
+
+# verify the version is still 6
+VERSION=$($ZPOOL get version $TESTPOOL2 | $GREP version | $AWK '{print $3}')
+if [ "$VERSION" != "6" ]
+then
+       log_fail "Version $VERSION set for $TESTPOOL2, expected version 6!"
+fi
+
+log_pass "zpool set version can only increment pool version"
diff --git a/zfs/tests/zfs-tests/tests/functional/poolversion/setup.ksh b/zfs/tests/zfs-tests/tests/functional/poolversion/setup.ksh
new file mode 100755 (executable)
index 0000000..cfe14a0
--- /dev/null
@@ -0,0 +1,45 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+# create a version 1 pool
+log_must $MKFILE 64m /tmp/zpool_version_1.dat
+log_must $ZPOOL create -o version=1 $TESTPOOL /tmp/zpool_version_1.dat
+
+
+# create another version 1 pool
+log_must $MKFILE 64m /tmp/zpool2_version_1.dat
+log_must $ZPOOL create -o version=1 $TESTPOOL2 /tmp/zpool2_version_1.dat
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/privilege/Makefile.am b/zfs/tests/zfs-tests/tests/functional/privilege/Makefile.am
new file mode 100644 (file)
index 0000000..ef26a75
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/privilege
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       privilege_001_pos.ksh \
+       privilege_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/privilege/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/privilege/cleanup.ksh
new file mode 100755 (executable)
index 0000000..ee50ad4
--- /dev/null
@@ -0,0 +1,49 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+ZFS_USER=$($CAT /tmp/zfs-privs-test-user.txt)
+USES_NIS=$($CAT /tmp/zfs-privs-test-nis.txt)
+
+if [ "${USES_NIS}" == "true" ]
+then
+    $SVCADM enable svc:/network/nis/client:default
+fi
+
+$USERDEL $ZFS_USER
+[[ -d /export/home/$ZFS_USER ]] && $RM -rf /export/home/$ZFS_USER
+$RM /tmp/zfs-privs-test-nis.txt
+$RM /tmp/zfs-privs-test-user.txt
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/privilege/privilege_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/privilege/privilege_001_pos.ksh
new file mode 100755 (executable)
index 0000000..5beabad
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# The RBAC profile "ZFS Storage Management" works
+#
+# STRATEGY:
+#      (create)
+#      1. As a normal user, try to create a pool - which should fail.
+#       2. Assign "ZFS Storage Management" profile, try to create pool again,
+#         which should succeed.
+#
+#      (works well with other ZFS profile tests)
+#      3. Attempt to create a ZFS filesystem, which should fail.
+#      4. Add the "ZFS File System Management" profile, attempt to create a FS
+#         which should succeed.
+#
+#      (destroy)
+#       5. Remove the FS profile, then attempt to destroy the pool, which
+#         should succeed.
+#      6. Remove the Storage profile, then attempt to recreate the pool, which
+#         should fail.
+#
+
+# We can only run this in the global zone
+verify_runnable "global"
+
+log_assert "The RBAC profile \"ZFS Storage Management\" works"
+
+ZFS_USER=$($CAT /tmp/zfs-privs-test-user.txt)
+
+# the user shouldn't be able to do anything initially
+log_mustnot $SU $ZFS_USER -c "$ZPOOL create $TESTPOOL $DISKS"
+log_mustnot $SU $ZFS_USER -c "$PFEXEC $ZPOOL create $TESTPOOL $DISKS"
+
+# the first time we assign the profile, we insist it should work
+log_must $USERMOD -P "ZFS Storage Management" $ZFS_USER
+log_must $SU $ZFS_USER -c "$PFEXEC $ZPOOL create -f $TESTPOOL $DISKS"
+
+# ensure the user can't create a filesystem with this profile
+log_mustnot $SU $ZFS_USER -c "$ZFS create $TESTPOOL/fs"
+
+# add ZFS File System Management profile, and try to create a fs
+log_must $USERMOD -P "ZFS File System Management" $ZFS_USER
+log_must $SU $ZFS_USER -c "$PFEXEC $ZFS create $TESTPOOL/fs"
+
+# revoke File System Management profile
+$USERMOD -P, $ZFS_USER
+$USERMOD -P "ZFS Storage Management" $ZFS_USER
+
+# ensure the user can destroy pools
+log_mustnot $SU $ZFS_USER -c "$ZPOOL destroy $TESTPOOL"
+log_must $SU $ZFS_USER -c "$PFEXEC $ZPOOL destroy $TESTPOOL"
+
+# revoke Storage Management profile
+$USERMOD -P, $ZFS_USER
+log_mustnot $SU $ZFS_USER -c "$PFEXEC $ZPOOL create -f $TESTPOOL $DISKS"
+
+log_pass "The RBAC profile \"ZFS Storage Management\" works"
diff --git a/zfs/tests/zfs-tests/tests/functional/privilege/privilege_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/privilege/privilege_002_pos.ksh
new file mode 100755 (executable)
index 0000000..7935985
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# The RBAC profile "ZFS File System Management" works
+#
+# STRATEGY:
+#
+#      The following actions are taken, both using profile execution (pfexec)
+#      and without profile execution - we make sure that the latter should
+#      always fail.
+#
+#      (create)
+#      1. As a normal user, try to create a filesystem - which should fail.
+#       2. Assign "ZFS File System Management" profile, try to create fs again,
+#         which should succeed.
+#
+#      (pools)
+#      3. Ensure a user with this profile can't perform pool administration
+#         by attempting to destroy a pool.
+#
+#      (destroy)
+#       5. Remove the FS profile, then attempt to destroy the fs, which
+#         should fail.
+#      6. Assign the FS profile, then attempt to destroy the fs, which
+#         should succeed.
+#
+
+verify_runnable "both"
+
+log_assert "The RBAC profile \"ZFS File System Management\" works"
+
+ZFS_USER=$($CAT /tmp/zfs-privs-test-user.txt)
+
+# Set a $DATASET where we can create child files systems
+if is_global_zone; then
+       log_must $ZPOOL create -f $TESTPOOL $DISKS
+       DATASET=$TESTPOOL
+else
+       DATASET=zonepool/zonectr0
+fi
+
+# A user shouldn't be able to create filesystems
+log_mustnot $SU $ZFS_USER -c "$ZFS create $DATASET/zfsprivfs"
+
+# Insist this invocation of usermod works
+log_must $USERMOD -P "ZFS File System Management" $ZFS_USER
+
+# Now try to create file systems as the user
+log_mustnot $SU $ZFS_USER -c "$ZFS create $DATASET/zfsprivfs"
+log_must $SU $ZFS_USER -c "$PFEXEC $ZFS create $DATASET/zfsprivfs"
+
+# Ensure the user can't do anything to pools in this state:
+log_mustnot $SU $ZFS_USER -c "$ZPOOL destroy $DATASET"
+log_mustnot $SU $ZFS_USER -c "$PFEXEC $ZPOOL destroy $DATASET"
+
+# revoke File System Management profile
+$USERMOD -P, $ZFS_USER
+
+# Ensure the user can't create more filesystems
+log_mustnot $SU $ZFS_USER -c "$ZFS create $DATASET/zfsprivfs2"
+log_mustnot $SU $ZFS_USER -c "$PFEXEC $ZFS create $DATASET/zfsprivfs2"
+
+# assign the profile again and destroy the fs.
+$USERMOD -P "ZFS File System Management" $ZFS_USER
+log_must $SU $ZFS_USER -c "$PFEXEC $ZFS destroy $DATASET/zfsprivfs"
+$USERMOD -P, $ZFS_USER
+
+log_pass "The RBAC profile \"ZFS File System Management\" works"
diff --git a/zfs/tests/zfs-tests/tests/functional/privilege/setup.ksh b/zfs/tests/zfs-tests/tests/functional/privilege/setup.ksh
new file mode 100755 (executable)
index 0000000..0f53b8c
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+ZFS_USER=zfsrbac
+USES_NIS=false
+
+# if we're running NIS, turn it off until we clean up
+# (it can cause useradd to take a long time, hitting our TIMEOUT)
+$SVCS svc:/network/nis/client:default | $GREP online > /dev/null
+if [ $? -eq 0 ]
+then
+  $SVCADM disable svc:/network/nis/client:default
+  USES_NIS=true
+fi
+
+
+# create a unique user that we can use to run the tests,
+# making sure not to clobber any existing users.
+FOUND=""
+while [ -z "${FOUND}" ]
+do
+  USER_EXISTS=$( grep $ZFS_USER /etc/passwd )
+  if [ ! -z "${USER_EXISTS}" ]
+  then
+      ZFS_USER="${ZFS_USER}x"
+  else
+      FOUND="true"
+  fi
+done
+
+log_must $MKDIR -p /export/home/$ZFS_USER
+log_must $USERADD -c "ZFS Privileges Test User" -d /export/home/$ZFS_USER $ZFS_USER
+
+echo $ZFS_USER > /tmp/zfs-privs-test-user.txt
+echo $USES_NIS > /tmp/zfs-privs-test-nis.txt
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/Makefile.am b/zfs/tests/zfs-tests/tests/functional/quota/Makefile.am
new file mode 100644 (file)
index 0000000..6318684
--- /dev/null
@@ -0,0 +1,12 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/quota
+dist_pkgdata_SCRIPTS = \
+       quota.cfg \
+       quota.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       quota_001_pos.ksh \
+       quota_002_pos.ksh \
+       quota_003_pos.ksh \
+       quota_004_pos.ksh \
+       quota_005_pos.ksh \
+       quota_006_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/quota/cleanup.ksh
new file mode 100755 (executable)
index 0000000..c4c3691
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_container_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/quota.cfg b/zfs/tests/zfs-tests/tests/functional/quota/quota.cfg
new file mode 100644 (file)
index 0000000..5b19f40
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export BLOCK_SIZE=8192
+export QUOTA_VALUE=10000000
+export TESTFILE1=file1
+export TESTFILE2=file2
+export TOLERANCE=131071
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/quota.kshlib b/zfs/tests/zfs-tests/tests/functional/quota/quota.kshlib
new file mode 100644 (file)
index 0000000..bde0a37
--- /dev/null
@@ -0,0 +1,95 @@
+#
+# 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.
+#
+
+. $STF_SUITE/tests/functional/quota/quota.cfg
+
+# BLOCK_SIZE, QUOTA_VALUE and TOLERANCE set in quota.cfg
+if is_linux; then
+       readonly EDQUOT=122
+else
+       readonly EDQUOT=49
+fi
+
+#
+# Function to fill the quota of a zfs filesystem
+#
+# $1 - The File system or container to fill.
+# $2 - The mountpoint to use.
+#
+function fill_quota
+{
+       typeset FILESYSTEM="$1"
+       typeset MNTPT="$2"
+
+       log_must $ZFS set quota=$QUOTA_VALUE $FILESYSTEM
+
+       typeset -i write_size=0
+       (( write_size = 2 * QUOTA_VALUE ))
+
+       typeset -i zret=0
+       $FILE_WRITE -o create -f $MNTPT/$TESTFILE1 -b $BLOCK_SIZE \
+                -c $write_size -d 0
+       zret=$?
+        [[ $zret -ne $EDQUOT ]] && \
+            log_fail "Returned error code: $zret. Expected: $EDQUOT."
+
+       typeset -i file_size=`$LS -lsk $MNTPT/$TESTFILE1 | $AWK '{ print $1 }'`
+       typeset -i limit=0
+       (( file_size = file_size * 1024 ))
+       (( limit = QUOTA_VALUE + TOLERANCE ))
+       (( file_size > limit )) && \
+           log_fail "File was created larger than the quota value, aborting!!!"
+       return 0
+}
+
+#
+# Function attempts to write another file in a ZFS filesystem
+# that has already filled its quota
+#
+function exceed_quota
+{
+       typeset FILESYSTEM="$1"
+       typeset MNTPT="$2"
+
+       log_must fill_quota $FILESYSTEM $MNTPT
+       typeset -i write_size=0
+        (( write_size = 2 * QUOTA_VALUE ))
+       typeset -i zret=0
+       #
+       # Writing a file without API to access return code
+       #
+       log_note "Creating a file in a FS that has already exceeded its quota"
+       $FILE_WRITE -o create -f $MNTPT/$TESTFILE2 \
+               -b $BLOCK_SIZE -c $write_size -d 0
+       zret=$?
+       [[ $zret -ne $EDQUOT ]] && \
+           log_fail "Returned error code: $zret. Expected: $EDQUOT."
+       return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/quota_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/quota/quota_001_pos.ksh
new file mode 100755 (executable)
index 0000000..6c5cf36
--- /dev/null
@@ -0,0 +1,76 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/quota/quota.kshlib
+
+#
+# DESCRIPTION:
+#
+# A ZFS file system quota limits the amount of pool space
+# available to a file system. Apply a quota and verify
+# that no more file creates are permitted.
+#
+# STRATEGY:
+# 1) Apply quota to ZFS file system
+# 2) Create a file which is larger than the set quota
+# 3) Verify that the resulting file size is less than the quota limit
+#
+
+verify_runnable "both"
+
+log_assert "Verify that file size is limited by the file system quota"
+
+#
+# cleanup to be used internally as otherwise quota assertions cannot be
+# run independently or out of order
+#
+function cleanup
+{
+       [[ -e $TESTDIR/$TESTFILE1 ]] && \
+           log_must $RM $TESTDIR/$TESTFILE1
+       #
+       # Need to allow time for space to be released back to
+       # pool, otherwise next test will fail trying to set a
+       # quota which is less than the space used.
+       #
+       sleep 5
+}
+
+log_onexit cleanup
+
+#
+# Sets the quota value and attempts to fill it with a file
+# twice the size of the quota
+#
+log_must fill_quota $TESTPOOL/$TESTFS $TESTDIR
+
+log_pass "File size limited by quota"
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/quota_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/quota/quota_002_pos.ksh
new file mode 100755 (executable)
index 0000000..6de5fea
--- /dev/null
@@ -0,0 +1,73 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/quota/quota.kshlib
+
+#
+# DESCRIPTION:
+# A zfs file system quota limits the amount of pool space
+# available to a given ZFS file system. Once exceeded, it is impossible
+# to write any more files to the file system.
+#
+# STRATEGY:
+# 1) Apply quota to the ZFS file system
+# 2) Exceed the quota
+# 3) Attempt to write another file
+# 4) Verify the attempt fails with error code EDQUOTA (linux 122, others 49)
+#
+#
+
+verify_runnable "both"
+
+log_assert "Verify that a file write cannot exceed the file system quota"
+
+#
+# cleanup to be used internally as otherwise quota assertions cannot be
+# run independently or out of order
+#
+function cleanup
+{
+        [[ -e $TESTDIR/$TESTFILE1 ]] && \
+            log_must $RM $TESTDIR/$TESTFILE1
+
+       [[ -e $TESTDIR/$TESTFILE2 ]] && \
+            log_must $RM $TESTDIR/$TESTFILE2
+}
+
+log_onexit cleanup
+
+#
+# Fills the quota & attempts to write another file
+#
+log_must exceed_quota $TESTPOOL/$TESTFS $TESTDIR
+
+log_pass "Could not write file. Quota limit enforced as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/quota_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/quota/quota_003_pos.ksh
new file mode 100755 (executable)
index 0000000..afcc4a1
--- /dev/null
@@ -0,0 +1,79 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/quota/quota.kshlib
+
+#
+# DESCRIPTION:
+# A ZFS file system quota limits the amount of pool space
+# available to a file system dataset. Apply a quota and verify
+# that no more file creates are permitted.
+#
+# NOTE: THis test applies to a dataset rather than a file system.
+#
+# STRATEGY:
+# 1) Apply quota to ZFS file system dataset
+# 2) Create a file which is larger than the set quota
+# 3) Verify that the resulting file size is less than the quota limit
+#
+
+verify_runnable "both"
+
+log_assert "Verify that file size is limited by the file system quota" \
+    "(dataset version)"
+
+#
+# cleanup to be used internally as otherwise quota assertions cannot be
+# run independently or out of order
+#
+function cleanup
+{
+       [[ -e $TESTDIR1/$TESTFILE1 ]] && \
+           log_must $RM $TESTDIR1/$TESTFILE1
+
+       #
+        # Need to allow time for space to be released back to
+        # pool, otherwise next test will fail trying to set a
+        # quota which is less than the space used.
+        #
+        sleep 5
+}
+
+log_onexit cleanup
+
+#
+# Sets the quota value and attempts to fill it with a file
+# twice the size of the quota
+#
+log_must fill_quota $TESTPOOL/$TESTCTR/$TESTFS1 $TESTDIR1
+
+log_pass "File size limited by quota"
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/quota_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/quota/quota_004_pos.ksh
new file mode 100755 (executable)
index 0000000..50106ca
--- /dev/null
@@ -0,0 +1,74 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/quota/quota.kshlib
+
+#
+# DESCRIPTION:
+# A zfs file system quota limits the amount of pool space
+# available to a given ZFS file system dataset. Once exceeded, it
+# is impossible to write any more files to the file system.
+#
+# STRATEGY:
+# 1) Apply quota to the ZFS file system dataset
+# 2) Exceed the quota
+# 3) Attempt to write another file
+# 4) Verify the attempt fails with error code EDQUOTA (linux 122, others 49)
+#
+#
+
+verify_runnable "both"
+
+log_assert "Verify that a file write cannot exceed the file system quota" \
+    "(dataset version)"
+
+#
+# cleanup to be used internally as otherwise quota assertions cannot be
+# run independently or out of order
+#
+function cleanup
+{
+        [[ -e $TESTDIR1/$TESTFILE1 ]] && \
+            log_must $RM $TESTDIR1/$TESTFILE1
+
+       [[ -e $TESTDIR1/$TESTFILE2 ]] && \
+            log_must $RM $TESTDIR1/$TESTFILE2
+}
+
+log_onexit cleanup
+
+#
+# Fills the quota & attempts to write another file
+#
+log_must exceed_quota $TESTPOOL/$TESTCTR/$TESTFS1 $TESTDIR1
+
+log_pass "Could not write file. Quota limit enforced as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/quota_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/quota/quota_005_pos.ksh
new file mode 100755 (executable)
index 0000000..55bddb5
--- /dev/null
@@ -0,0 +1,76 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/quota/quota.kshlib
+
+#
+# DESCRIPTION:
+#
+# Verify that quota doesn't inherit its value from parent.
+#
+# STRATEGY:
+# 1) Set quota for parents
+# 2) Create a filesystem tree
+# 3) Verify that the 'quota' for descendent doesnot inherit the value.
+#
+###############################################################################
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $fs_child && \
+               log_must $ZFS destroy $fs_child
+
+       log_must $ZFS set quota=$quota_val $fs
+}
+
+log_onexit cleanup
+
+log_assert "Verify that quota doesnot inherit its value from parent."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+fs_child=$TESTPOOL/$TESTFS/$TESTFS
+
+space_avail=$(get_prop available $fs)
+quota_val=$(get_prop quota $fs)
+typeset -i quotasize=$space_avail
+((quotasize = quotasize * 2 ))
+log_must $ZFS set quota=$quotasize $fs
+
+log_must $ZFS create $fs_child
+quota_space=$(get_prop quota $fs_child)
+[[ $quota_space == $quotasize ]] && \
+       log_fail "The quota of child dataset inherits its value from parent."
+
+log_pass "quota doesnot inherit its value from parent as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/quota_006_neg.ksh b/zfs/tests/zfs-tests/tests/functional/quota/quota_006_neg.ksh
new file mode 100755 (executable)
index 0000000..a22520c
--- /dev/null
@@ -0,0 +1,71 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/quota/quota.kshlib
+
+#
+# DESCRIPTION:
+#
+# Can't set a quota to less than currently being used by the dataset.
+#
+# STRATEGY:
+# 1) Create a filesystem
+# 2) Set a quota on the filesystem that is lower than the space
+#      currently in use.
+# 3) Verify that the attempt fails.
+#
+
+verify_runnable "both"
+
+log_assert "Verify cannot set quota lower than the space currently in use"
+
+function cleanup
+{
+       log_must $ZFS set quota=none $TESTPOOL/$TESTFS
+}
+
+log_onexit cleanup
+
+typeset -i quota_integer_size=0
+typeset invalid_size="123! @456 7#89 0\$ abc123% 123%s 12%s3 %c123 123%d %x123 12%p3 \
+       ^def456 789&ghi"
+typeset -i space_used=`get_prop used $TESTPOOL/$TESTFS`
+(( quota_integer_size = space_used  - 1 ))
+quota_fp_size=${quota_integer_size}.123
+
+for size in 0 -1 $quota_integer_size -$quota_integer_size $quota_fp_size -$quota_fp_size \
+       $invalid_size ; do
+       log_mustnot $ZFS set quota=$size $TESTPOOL/$TESTFS
+done
+log_must $ZFS set quota=$space_used $TESTPOOL/$TESTFS
+
+log_pass "As expected cannot set quota lower than space currently in use"
diff --git a/zfs/tests/zfs-tests/tests/functional/quota/setup.ksh b/zfs/tests/zfs-tests/tests/functional/quota/setup.ksh
new file mode 100755 (executable)
index 0000000..677cb12
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_container_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/raidz/Makefile.am b/zfs/tests/zfs-tests/tests/functional/raidz/Makefile.am
new file mode 100644 (file)
index 0000000..694de18
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/raidz
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       raidz_001_neg.ksh \
+       raidz_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/raidz/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/raidz/cleanup.ksh
new file mode 100755 (executable)
index 0000000..c92c54c
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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 (c) 2016 by Gvozden Neskovic. All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+# default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/raidz/raidz_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/raidz/raidz_001_neg.ksh
new file mode 100755 (executable)
index 0000000..158ce67
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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 (c) 2016 by Gvozden Neskovic. All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Call the raidz_test tool with -T options to test the infrastructure.
+#      This option should make raidz_test to return non 0.
+#
+
+log_mustnot $RAIDZ_TEST -T
+
+log_pass "raidz_test detects errors as espected."
diff --git a/zfs/tests/zfs-tests/tests/functional/raidz/raidz_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/raidz/raidz_002_pos.ksh
new file mode 100755 (executable)
index 0000000..b33bd1b
--- /dev/null
@@ -0,0 +1,41 @@
+#!/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 (c) 2016 by Gvozden Neskovic. All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Call the raidz_test tool with -S to test all supported raidz
+#      implementations. This options will test several raidz block geometries
+#      and several zio parameters that affect raidz block layout. Data
+#      reconstruction performs all combinations of failed disks. Wall time
+#      is set to 5min, but actual runtime might be longer.
+#
+
+log_must $RAIDZ_TEST -S -t 300
+
+log_pass "raidz_test parameter sweep test succeeded."
diff --git a/zfs/tests/zfs-tests/tests/functional/raidz/setup.ksh b/zfs/tests/zfs-tests/tests/functional/raidz/setup.ksh
new file mode 100755 (executable)
index 0000000..4e155d2
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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 (c) 2016 by Gvozden Neskovic. All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/Makefile.am b/zfs/tests/zfs-tests/tests/functional/redundancy/Makefile.am
new file mode 100644 (file)
index 0000000..ef7dd91
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/redundancy
+dist_pkgdata_SCRIPTS = \
+       redundancy.cfg \
+       redundancy.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       redundancy_001_pos.ksh \
+       redundancy_002_pos.ksh \
+       redundancy_003_pos.ksh \
+       redundancy_004_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/redundancy/cleanup.ksh
new file mode 100755 (executable)
index 0000000..ba8d980
--- /dev/null
@@ -0,0 +1,38 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/redundancy/redundancy.kshlib
+
+verify_runnable "global"
+
+cleanup
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy.cfg b/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy.cfg
new file mode 100644 (file)
index 0000000..079ff8b
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export BASEDIR=/var/tmp/basedir.$$
+export TESTFILE=testfile.$$
+
+export PRE_RECORD_FILE=$BASEDIR/pre-record-file.$$
+export PST_RECORD_FILE=$BASEDIR/pst-record-file.$$
+
+export DEV_SIZE=64M
+
+export BLOCKSZ=$(( 1024 * 1024 ))
+export NUM_WRITES=40
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib b/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy.kshlib
new file mode 100644 (file)
index 0000000..56e2bd1
--- /dev/null
@@ -0,0 +1,339 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/redundancy/redundancy.cfg
+
+function cleanup
+{
+       if poolexists $TESTPOOL; then
+               destroy_pool $TESTPOOL
+       fi
+       typeset dir
+       for dir in $TESTDIR $BASEDIR; do
+               if [[ -d $dir ]]; then
+                       log_must $RM -rf $dir
+               fi
+       done
+}
+
+#
+# Get random number between min and max number.
+#
+# $1 Minimal value
+# $2 Maximal value
+#
+function random
+{
+       typeset -i min=$1
+       typeset -i max=$2
+       typeset -i value
+
+       while true; do
+               ((value = RANDOM % (max + 1)))
+               if ((value >= min)); then
+                       break
+               fi
+       done
+
+       $ECHO $value
+}
+
+#
+# Record the directories construction and checksum all the files which reside
+# within the specified pool
+#
+# $1 The specified pool
+# $2 The file which save the record.
+#
+function record_data
+{
+       typeset pool=$1
+       typeset recordfile=$2
+
+       [[ -z $pool ]] && log_fail "No specified pool."
+       [[ -f $recordfile ]] && log_must $RM -f $recordfile
+
+       typeset mntpnt
+       mntpnt=$(get_prop mountpoint $pool)
+       log_must eval "$DU -a $mntpnt > $recordfile 2>&1"
+       #
+       # When the data was damaged, checksum is failing and return 1
+       # So, will not use log_must
+       #
+       $FIND $mntpnt -type f -exec $CKSUM {} + >> $recordfile 2>&1
+}
+
+#
+# Create test pool and fill with files and directories.
+#
+# $1 pool name
+# $2 pool type
+# $3 virtual devices number
+#
+function setup_test_env
+{
+       typeset pool=$1
+       typeset keyword=$2
+       typeset -i vdev_cnt=$3
+       typeset vdevs
+
+       typeset -i i=0
+       while (( i < vdev_cnt )); do
+               vdevs="$vdevs $BASEDIR/vdev$i"
+               ((i += 1))
+       done
+
+       if [[ ! -d $BASEDIR ]]; then
+               log_must $MKDIR $BASEDIR
+       fi
+
+       if poolexists $pool ; then
+               destroy_pool $pool
+       fi
+
+       log_must $MKFILE $DEV_SIZE $vdevs
+
+       log_must $ZPOOL create -m $TESTDIR $pool $keyword $vdevs
+
+       log_note "Filling up the filesystem ..."
+       typeset -i ret=0
+       typeset -i i=0
+       typeset file=$TESTDIR/file
+       while $TRUE ; do
+               $FILE_WRITE -o create -f $file.$i \
+                       -b $BLOCKSZ -c $NUM_WRITES
+               ret=$?
+               (( $ret != 0 )) && break
+               (( i = i + 1 ))
+       done
+       (($ret != 28 )) && log_note "$FILE_WRITE return value($ret) is unexpected."
+
+       record_data $TESTPOOL $PRE_RECORD_FILE
+}
+
+#
+# Check pool status is healthy
+#
+# $1 pool
+#
+function is_healthy
+{
+       typeset pool=$1
+
+       typeset healthy_output="pool '$pool' is healthy"
+       typeset real_output=$($ZPOOL status -x $pool)
+
+       if [[ "$real_output" == "$healthy_output" ]]; then
+               return 0
+       else
+               typeset -i ret
+               $ZPOOL status -x $pool | $GREP "state:" | \
+                       $GREP "FAULTED" >/dev/null 2>&1
+               ret=$?
+               (( $ret == 0 )) && return 1
+               typeset l_scan
+               typeset errnum
+               l_scan=$($ZPOOL status -x $pool | $GREP "scan:")
+               l_scan=${l_scan##*"with"}
+               errnum=$($ECHO $l_scan | $AWK '{print $1}')
+
+               return $errnum
+       fi
+}
+
+#
+# Check pool data is valid
+#
+# $1 pool
+#
+function is_data_valid
+{
+       typeset pool=$1
+
+       record_data $pool $PST_RECORD_FILE
+       if ! $DIFF $PRE_RECORD_FILE $PST_RECORD_FILE > /dev/null 2>&1; then
+               return 1
+       fi
+
+       return 0
+}
+
+#
+# Get the specified count devices name
+#
+# $1 pool name
+# $2 devices count
+#
+function get_vdevs #pool cnt
+{
+       typeset pool=$1
+       typeset -i cnt=$2
+
+       typeset all_devs=$($ZPOOL iostat -v $pool | $AWK '{print $1}'| \
+               $EGREP -v "^pool$|^capacity$|^mirror$|^raidz1$|^raidz2$|---" | \
+               $EGREP -v "/old$|^$pool$")
+       typeset -i i=0
+       typeset vdevs
+       while ((i < cnt)); do
+               typeset dev=$($ECHO $all_devs | $AWK '{print $1}')
+               eval all_devs=\${all_devs##*$dev}
+
+               vdevs="$dev $vdevs"
+               ((i += 1))
+       done
+
+       $ECHO "$vdevs"
+}
+
+#
+# Create and replace the same name virtual device files
+#
+# $1 pool name
+# $2-n virtual device files
+#
+function replace_missing_devs
+{
+       typeset pool=$1
+       shift
+
+       typeset vdev
+       for vdev in $@; do
+               log_must $MKFILE $DEV_SIZE $vdev
+               log_must $ZPOOL replace -f $pool $vdev $vdev
+               while true; do
+                       if ! is_pool_resilvered $pool ; then
+                               log_must $SLEEP 2
+                       else
+                               break
+                       fi
+               done
+       done
+}
+
+#
+# Damage the pool's virtual device files.
+#
+# $1 pool name
+# $2 Failing devices count
+# $3 damage vdevs method, if not null, we keep
+#    the label for the vdevs
+#
+function damage_devs
+{
+       typeset pool=$1
+       typeset -i cnt=$2
+       typeset label="$3"
+       typeset vdevs
+       typeset -i bs_count
+
+       vdevs=$(get_vdevs $pool $cnt)
+       if [[ -n $label ]]; then
+               typeset dev
+               for dev in $vdevs; do
+                       bs_count=$($LS -l $dev | $AWK '{print $5}')
+                       (( bs_count = bs_count/1024 - 512 ))
+                       $DD if=/dev/zero of=$dev seek=512 bs=1024 \
+                               count=$bs_count conv=notrunc >/dev/null 2>&1
+               done
+       else
+               log_must $MKFILE $DEV_SIZE $vdevs
+       fi
+
+       sync_pool $pool
+}
+
+#
+# Clear errors in the pool caused by data corruptions
+#
+# $1 pool name
+#
+function clear_errors
+{
+       typeset pool=$1
+
+       log_must $ZPOOL clear $pool
+
+       if ! is_healthy $pool ; then
+               log_note "$pool should be healthy."
+               return 1
+       fi
+       if ! is_data_valid $pool ; then
+               log_note "Data should be valid in $pool."
+               return 1
+       fi
+
+       return 0
+}
+
+#
+# Remove the specified pool's virtual device files
+#
+# $1 Pool name
+# $2 Missing devices count
+#
+function remove_devs
+{
+       typeset pool=$1
+       typeset -i cnt=$2
+       typeset vdevs
+
+       vdevs=$(get_vdevs $pool $cnt)
+       log_must $RM -f $vdevs
+
+       sync_pool $pool
+}
+
+#
+# Recover the bad or missing device files in the pool
+#
+# $1 Pool name
+# $2 Missing devices count
+#
+function recover_bad_missing_devs
+{
+       typeset pool=$1
+       typeset -i cnt=$2
+       typeset vdevs
+
+       vdevs=$(get_vdevs $pool $cnt)
+       replace_missing_devs $pool $vdevs
+
+       if ! is_healthy $pool ; then
+               log_note "$pool should be healthy."
+               return 1
+       fi
+       if ! is_data_valid $pool ; then
+               log_note "Data should be valid in $pool."
+               return 1
+       fi
+
+       return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_001_pos.ksh
new file mode 100755 (executable)
index 0000000..e25a48b
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/redundancy/redundancy.kshlib
+
+#
+# DESCRIPTION:
+#      A raidz pool can withstand at most 1 device failing or missing.
+#
+# STRATEGY:
+#      1. Create N(>2,<5) virtual disk files.
+#      2. Create raidz pool based on the virtual disk files.
+#      3. Fill the filesystem with directories and files.
+#      4. Record all the files and directories checksum information.
+#      5. Damaged one of the virtual disk file.
+#      6. Verify the data is correct to prove raidz can withstand 1 devicd is
+#         failing.
+#
+
+verify_runnable "global"
+
+log_assert "Verify raidz pool can withstand one device is failing."
+log_onexit cleanup
+
+typeset -i cnt=$(random 2 5)
+setup_test_env $TESTPOOL raidz $cnt
+
+#
+# Inject data corruption error for raidz pool
+#
+damage_devs $TESTPOOL 1 "label"
+log_must is_data_valid $TESTPOOL
+log_must clear_errors $TESTPOOL
+
+#
+# Inject bad device error for raidz pool
+#
+damage_devs $TESTPOOL 1
+log_must is_data_valid $TESTPOOL
+log_must recover_bad_missing_devs $TESTPOOL 1
+
+#
+# Inject missing device error for raidz pool
+#
+remove_devs $TESTPOOL 1
+log_must is_data_valid $TESTPOOL
+
+log_pass "Raidz pool can withstand one devices is failing passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_002_pos.ksh
new file mode 100755 (executable)
index 0000000..b16687d
--- /dev/null
@@ -0,0 +1,83 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/redundancy/redundancy.kshlib
+
+#
+# DESCRIPTION:
+#      A raidz2 pool can withstand 2 devices are failing or missing.
+#
+# STRATEGY:
+#      1. Create N(>3,<5) virtual disk files.
+#      2. Create raidz2 pool based on the virtual disk files.
+#      3. Fill the filesystem with directories and files.
+#      4. Record all the files and directories checksum information.
+#      5. Damaged at most two of the virtual disk files.
+#      6. Verify the data is correct to prove raidz2 can withstand 2 devices
+#         are failing.
+#
+
+verify_runnable "global"
+
+log_assert "Verify raidz2 pool can withstand two devices are failing."
+log_onexit cleanup
+
+typeset -i cnt=$(random 3 5)
+setup_test_env $TESTPOOL raidz2 $cnt
+
+#
+# Inject data corruption errors for raidz2 pool
+#
+for i in 1 2; do
+       damage_devs $TESTPOOL $i "label"
+       log_must is_data_valid $TESTPOOL
+       log_must clear_errors $TESTPOOL
+done
+
+#
+# Inject bad devices errors for raidz2 pool
+#
+for i in 1 2; do
+       damage_devs $TESTPOOL $i
+       log_must is_data_valid $TESTPOOL
+       log_must recover_bad_missing_devs $TESTPOOL $i
+done
+
+#
+# Inject missing device errors for raidz2 pool
+#
+for i in 1 2; do
+       remove_devs $TESTPOOL $i
+       log_must is_data_valid $TESTPOOL
+       log_must recover_bad_missing_devs $TESTPOOL $i
+done
+
+log_pass "Raidz2 pool can withstand two devices are failing passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_003_pos.ksh
new file mode 100755 (executable)
index 0000000..a1ca2cb
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/redundancy/redundancy.kshlib
+
+#
+# DESCRIPTION:
+#      A mirrored pool can withstand N-1 device are failing or missing.
+#
+# STRATEGY:
+#      1. Create N(>2,<5) virtual disk files.
+#      2. Create mirror pool based on the virtual disk files.
+#      3. Fill the filesystem with directories and files.
+#      4. Record all the files and directories checksum information.
+#      5. Damaged at most N-1 of the virtual disk files.
+#      6. Verify the data are correct to prove mirror can withstand N-1 devices
+#         are failing.
+#
+
+verify_runnable "global"
+
+log_assert "Verify mirrored pool can withstand N-1 devices are failing or missing."
+log_onexit cleanup
+
+typeset -i cnt=$(random 2 5)
+setup_test_env $TESTPOOL mirror $cnt
+
+typeset -i i=1
+
+#
+# Inject data corruption errors for mirrored pool
+#
+while (( i < cnt )); do
+       damage_devs $TESTPOOL $i "label"
+       log_must is_data_valid $TESTPOOL
+       log_must clear_errors $TESTPOOL
+
+       (( i +=1 ))
+done
+
+#
+# Inject  bad devices errors for mirrored pool
+#
+i=1
+while (( i < cnt )); do
+        damage_devs $TESTPOOL $i
+        log_must is_data_valid $TESTPOOL
+       log_must recover_bad_missing_devs $TESTPOOL $i
+
+       (( i +=1 ))
+done
+
+#
+# Inject missing device errors for mirrored pool
+#
+i=1
+while (( i < cnt )); do
+        remove_devs $TESTPOOL $i
+        log_must is_data_valid $TESTPOOL
+       log_must recover_bad_missing_devs $TESTPOOL $i
+
+       (( i +=1 ))
+done
+
+log_pass "Mirrored pool can withstand N-1 devices failing as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_004_neg.ksh b/zfs/tests/zfs-tests/tests/functional/redundancy/redundancy_004_neg.ksh
new file mode 100755 (executable)
index 0000000..0d40c57
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/redundancy/redundancy.kshlib
+
+#
+# DESCRIPTION:
+#      Striped pool have no data redundancy. Any device errors will
+#      cause data corruption.
+#
+# STRATEGY:
+#      1. Create N virtual disk file.
+#      2. Create stripe pool based on the virtual disk files.
+#      3. Fill the filesystem with directories and files.
+#      4. Record all the files and directories checksum information.
+#      5. Damage one of the virtual disk file.
+#      6. Verify the data is error.
+#
+
+verify_runnable "global"
+
+log_assert "Verify striped pool have no data redundancy."
+log_onexit cleanup
+
+typeset -i cnt=$(random 2 5)
+setup_test_env $TESTPOOL "" $cnt
+
+damage_devs $TESTPOOL 1 "keep_label"
+log_must $ZPOOL clear $TESTPOOL
+
+# Wait for the scrub intiated by the clear to wrap, or is_healthy will be wrong.
+while ! is_pool_scrubbed $TESTPOOL; do
+       sync
+done
+
+log_mustnot is_healthy $TESTPOOL
+
+log_pass "Striped pool has no data redundancy as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/redundancy/setup.ksh b/zfs/tests/zfs-tests/tests/functional/redundancy/setup.ksh
new file mode 100755 (executable)
index 0000000..e2c04fe
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/Makefile.am b/zfs/tests/zfs-tests/tests/functional/refquota/Makefile.am
new file mode 100644 (file)
index 0000000..5f7c7b6
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/refquota
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       refquota_001_pos.ksh \
+       refquota_002_pos.ksh \
+       refquota_003_pos.ksh \
+       refquota_004_pos.ksh \
+       refquota_005_pos.ksh \
+       refquota_006_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/refquota/cleanup.ksh
new file mode 100755 (executable)
index 0000000..ea139ae
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/refquota_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refquota/refquota_001_pos.ksh
new file mode 100755 (executable)
index 0000000..9f974d8
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      refquota limits the amount of space a dataset can consume, but does
+#      not include space used by descendents.
+#
+# STRATEGY:
+#      1. Setting refquota in given filesystem
+#      2. Create descendent filesystem
+#      3. Verify refquota limits the amount of space a dataset can consume
+#      4. Verify the limit does not impact descendents
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "refquota limits the amount of space a dataset can consume, " \
+       "but does not include space used by descendents."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+sub=$fs/sub
+log_must $ZFS create $sub
+
+log_must $ZFS set refquota=10M $fs
+mntpnt=$(get_prop mountpoint $fs)
+
+log_mustnot $MKFILE 11M $mntpnt/file
+log_must $MKFILE 9M $mntpnt/file
+log_must $ZFS snapshot $fs@snap
+log_mustnot $MKFILE 2M $mntpnt/file2
+
+mntpnt=$(get_prop mountpoint $sub)
+log_must $MKFILE 10M $mntpnt/file
+log_must $ZFS snapshot $sub@snap
+log_must $MKFILE 10 $mntpnt/file2
+
+log_pass "refquota limits the amount of space a dataset can consume, " \
+       "but does not include space used by descendents."
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/refquota_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refquota/refquota_002_pos.ksh
new file mode 100755 (executable)
index 0000000..7ee5967
--- /dev/null
@@ -0,0 +1,90 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Quotas are enforced using the minimum of the two properties:
+#      quota & refquota
+#
+# STRATEGY:
+#      1. Set value for quota and refquota. Quota less than refquota.
+#      2. Creating file which should be limited by quota.
+#      3. Switch the value of quota and refquota.
+#      4. Verify file should be limited by refquota.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "Quotas are enforced using the minimum of the two properties"
+log_onexit cleanup
+
+TESTFILE='testfile'
+fs=$TESTPOOL/$TESTFS
+log_must $ZFS set quota=15M $fs
+log_must $ZFS set refquota=25M $fs
+
+mntpnt=$(get_prop mountpoint $fs)
+log_mustnot $MKFILE 20M $mntpnt/$TESTFILE
+typeset -i used quota
+used=$(get_prop used $fs)
+quota=$(get_prop quota $fs)
+((used = used / (1024 * 1024)))
+((quota = quota / (1024 * 1024)))
+if [[ $used -ne $quota ]]; then
+       log_fail "ERROR: $used -ne $quota Quotas are not limited by quota"
+fi
+
+#
+# Switch the value of them and try again
+#
+log_must $RM $mntpnt/$TESTFILE
+log_must $ZFS set quota=25M $fs
+log_must $ZFS set refquota=15M $fs
+
+log_mustnot $MKFILE 20M $mntpnt/$TESTFILE
+used=$(get_prop used $fs)
+refquota=$(get_prop refquota $fs)
+((used = used / (1024 * 1024)))
+((refquota = refquota / (1024 * 1024)))
+if [[ $used -ne $refquota ]]; then
+       log_fail "ERROR: $used -ne $refquota Quotas are not limited by refquota"
+fi
+
+log_pass "Quotas are enforced using the minimum of the two properties"
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/refquota_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refquota/refquota_003_pos.ksh
new file mode 100755 (executable)
index 0000000..8026e7d
--- /dev/null
@@ -0,0 +1,83 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Sub-filesystem quotas are not enforced by property 'refquota'
+#
+# STRATEGY:
+#      1. Setting quota and refquota for parent. refquota < quota
+#      2. Verify sub-filesystem will not be limited by refquota
+#      3. Verify sub-filesystem will only be limited by quota
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "Sub-filesystem quotas are not enforced by property 'refquota'"
+log_onexit cleanup
+
+TESTFILE='testfile'
+fs=$TESTPOOL/$TESTFS
+log_must $ZFS set quota=25M $fs
+log_must $ZFS set refquota=10M $fs
+log_must $ZFS create $fs/subfs
+
+mntpnt=$(get_prop mountpoint $fs/subfs)
+log_must $MKFILE 20M $mntpnt/$TESTFILE
+
+typeset -i used quota refquota
+used=$(get_prop used $fs)
+refquota=$(get_prop refquota $fs)
+((used = used / (1024 * 1024)))
+((refquota = refquota / (1024 * 1024)))
+if [[ $used -lt $refquota ]]; then
+       log_fail "ERROR: $used < $refquota subfs quotas are limited by refquota"
+fi
+
+log_mustnot $MKFILE 20M $mntpnt/$TESTFILE.2
+used=$(get_prop used $fs)
+quota=$(get_prop quota $fs)
+((used = used / (1024 * 1024)))
+((quota = quota / (1024 * 1024)))
+if [[ $used -gt $quota ]]; then
+       log_fail "ERROR: $used > $quota subfs quotas aren't limited by quota"
+fi
+
+log_pass "Sub-filesystem quotas are not enforced by property 'refquota'"
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/refquota_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refquota/refquota_004_pos.ksh
new file mode 100755 (executable)
index 0000000..2d7902e
--- /dev/null
@@ -0,0 +1,76 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      refquotas are not limited by snapshots.
+#
+# STRATEGY:
+#      1. Setting refquota < quota
+#      2. Create file in filesytem, take snapshot and remove the file
+#      3. Verify snapshot will not consume refquota
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "refquotas are not limited by snapshots."
+log_onexit cleanup
+
+TESTFILE='testfile'
+fs=$TESTPOOL/$TESTFS
+log_must $ZFS set quota=25M $fs
+log_must $ZFS set refquota=15M $fs
+
+mntpnt=$(get_prop mountpoint $fs)
+typeset -i i=0
+while ((i < 3)); do
+       log_must $MKFILE 7M $mntpnt/$TESTFILE.$i
+       log_must $ZFS snapshot $fs@snap.$i
+       log_must $RM $mntpnt/$TESTFILE.$i
+
+       ((i += 1))
+done
+
+#
+# Verify out of the limitation of 'quota'
+#
+log_mustnot $MKFILE 7M $mntpnt/$TESTFILE
+
+log_pass "refquotas are not limited by snapshots."
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/refquota_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refquota/refquota_005_pos.ksh
new file mode 100755 (executable)
index 0000000..5e6ad12
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      refquotas are not limited by sub-filesystem snapshots.
+#
+# STRATEGY:
+#      1. Setting refquota < quota for parent
+#      2. Create file in sub-filesytem, take snapshot and remove the file
+#      3. Verify sub-filesystem snapshot will not consume refquota
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "refquotas are not limited by sub-filesystem snapshots."
+log_onexit cleanup
+
+TESTFILE='testfile'
+fs=$TESTPOOL/$TESTFS
+log_must $ZFS set quota=25M $fs
+log_must $ZFS set refquota=15M $fs
+log_must $ZFS create $fs/subfs
+
+mntpnt=$(get_prop mountpoint $fs/subfs)
+typeset -i i=0
+while ((i < 3)); do
+       log_must $MKFILE 7M $mntpnt/$TESTFILE.$i
+       log_must $ZFS snapshot $fs/subfs@snap.$i
+       log_must $RM $mntpnt/$TESTFILE.$i
+
+       ((i += 1))
+done
+
+#
+# Verify out of the limitation of 'quota'
+#
+log_mustnot $MKFILE 7M $mntpnt/$TESTFILE
+
+log_pass "refquotas are not limited by sub-filesystem snapshots"
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/refquota_006_neg.ksh b/zfs/tests/zfs-tests/tests/functional/refquota/refquota_006_neg.ksh
new file mode 100755 (executable)
index 0000000..18b0a4f
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      'zfs set refquota/refreserv' can handle incorrect arguments correctly.
+#
+# STRATEGY:
+#      1. Setup incorrect arguments arrays.
+#      2. Set the bad argument to refquota.
+#      3. Verify zfs can handle it correctly.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS set refquota=none $TESTPOOL/$TESTFS
+       log_must $ZFS set refreserv=none $TESTPOOL/$TESTFS
+}
+
+log_assert "'zfs set refquota' can handle incorrect arguments correctly."
+log_onexit cleanup
+
+set -A badopt  \
+       "None"          "-1"            "1TT"           "%5"            \
+       "123!"          "@456"          "7#89"          "0\$"           \
+       "abc123%"       "123%s"         "12%s3"         "%c123"         \
+       "123%d"         "%x123"         "12%p3"         "^def456"       \
+       "\0"            "x0"
+
+typeset -i i=0
+while ((i < ${#badopt[@]})); do
+       log_mustnot $ZFS set refquota=${badopt[$i]} $TESTPOOL/$TESTFS
+       log_mustnot $ZFS set refreserv=${badopt[$i]} $TESTPOOL/$TESTFS
+
+       ((i += 1))
+done
+
+log_pass "'zfs set refquota' can handle incorrect arguments correctly."
diff --git a/zfs/tests/zfs-tests/tests/functional/refquota/setup.ksh b/zfs/tests/zfs-tests/tests/functional/refquota/setup.ksh
new file mode 100755 (executable)
index 0000000..a34453b
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/Makefile.am b/zfs/tests/zfs-tests/tests/functional/refreserv/Makefile.am
new file mode 100644 (file)
index 0000000..41c88a6
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/refreserv
+dist_pkgdata_SCRIPTS = \
+       refreserv.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       refreserv_001_pos.ksh \
+       refreserv_002_pos.ksh \
+       refreserv_003_pos.ksh \
+       refreserv_004_pos.ksh \
+       refreserv_005_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/refreserv/cleanup.ksh
new file mode 100755 (executable)
index 0000000..ea139ae
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv.cfg b/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv.cfg
new file mode 100644 (file)
index 0000000..8c892db
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export TESTFILE=testfile
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_001_pos.ksh
new file mode 100755 (executable)
index 0000000..f0f45ac
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/refreserv/refreserv.cfg
+
+#
+# DESCRIPTION:
+#      Reservations are enforced using the maximum of 'reserv' and 'refreserv'
+#
+# STRATEGY:
+#      1. Setting quota for parent filesystem.
+#      2. Setting reservation and refreservation for sub-filesystem.
+#      3. Verify the sub-fs reservation are enforced by the maximum of 'reserv'
+#         and 'refreserv'.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "Reservations are enforced using the maximum of " \
+       "'reserv' and 'refreserv'"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS ; subfs=$fs/subfs
+log_must $ZFS create $subfs
+log_must $ZFS set quota=25M $fs
+
+log_must $ZFS set reserv=10M $subfs
+log_must $ZFS set refreserv=20M $subfs
+mntpnt=$(get_prop mountpoint $fs)
+log_mustnot $MKFILE 15M $mntpnt/$TESTFILE
+
+log_must $RM -f $mntpnt/$TESTFILE
+
+log_must $ZFS set reserv=20M $subfs
+log_must $ZFS set refreserv=10M $subfs
+log_mustnot $MKFILE 15M $mntpnt/$TESTFILE
+
+log_pass "Reservations are enforced using the maximum of " \
+       "'reserv' and 'refreserv'"
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_002_pos.ksh
new file mode 100755 (executable)
index 0000000..7a39a8d
--- /dev/null
@@ -0,0 +1,114 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/refreserv/refreserv.cfg
+
+#
+# DESCRIPTION:
+#      Setting full size as refreservation, verify no snapshot can be created.
+#
+# STRATEGY:
+#      1. Setting full size as refreservation on pool
+#      2. Verify no snapshot can be created on this pool
+#      3. Setting full size as refreservation on filesystem
+#      4. Verify no snapshot can be created on it and its subfs
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if is_global_zone ; then
+               log_must $ZFS set refreservation=none $TESTPOOL
+
+               if datasetexists $TESTPOOL@snap ; then
+                       log_must $ZFS destroy -f $TESTPOOL@snap
+               fi
+       fi
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+# This function iteratively increases refreserv to its highest possible
+# value. Simply setting refreserv == quota can allow enough writes to
+# complete that the test fails.
+function max_refreserv
+{
+       typeset ds=$1
+       typeset -i incsize=131072
+       typeset -i rr=$(get_prop available $ds)
+
+       log_must $ZFS set refreserv=$rr $ds
+       while :; do
+               $ZFS set refreserv=$((rr + incsize)) $ds >/dev/null 2>&1
+               if [[ $? == 0 ]]; then
+                       ((rr += incsize))
+                       continue
+               else
+                       ((incsize /= 2))
+                       ((incsize == 0)) && break
+               fi
+       done
+}
+
+
+log_assert "Setting full size as refreservation, verify no snapshot " \
+       "can be created."
+log_onexit cleanup
+
+log_must $ZFS create $TESTPOOL/$TESTFS/subfs
+
+typeset datasets
+if is_global_zone; then
+       datasets="$TESTPOOL $TESTPOOL/$TESTFS $TESTPOOL/$TESTFS/subfs"
+else
+       datasets="$TESTPOOL/$TESTFS $TESTPOOL/$TESTFS/subfs"
+fi
+
+for ds in $datasets; do
+       #
+       # Verify refreservation on dataset
+       #
+       log_must $ZFS set quota=25M $ds
+       max_refreserv $ds
+       log_mustnot $ZFS snapshot $ds@snap
+       if datasetexists $ds@snap ; then
+               log_fail "ERROR: $ds@snap should not exists."
+       fi
+
+       log_must $ZFS set quota=none $ds
+       log_must $ZFS set refreservation=none $ds
+done
+
+log_pass "Setting full size as refreservation, verify no snapshot " \
+       "can be created."
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_003_pos.ksh
new file mode 100755 (executable)
index 0000000..1738291
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/refreserv/refreserv.cfg
+
+#
+# DESCRIPTION:
+#      Verify a snapshot will only be allowed if there is enough free pool
+#      space outside of this refreservation.
+#
+# STRATEGY:
+#      1. Setting quota and refservation
+#      2. Verify snapshot can be created, when used =< quota - refreserv
+#      3. Verify failed to create snapshot, when used > quota - refreserv
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "Verify a snapshot will only be allowed if there is enough " \
+       "free space outside of this refreservation."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+log_must $ZFS set quota=25M $fs
+log_must $ZFS set refreservation=10M $fs
+
+mntpnt=$(get_prop mountpoint $fs)
+log_must $MKFILE 7M $mntpnt/$TESTFILE
+log_must $ZFS snapshot $fs@snap
+
+log_must $MKFILE 7M $mntpnt/$TESTFILE.2
+log_must $ZFS snapshot $fs@snap2
+
+log_must $MKFILE 7M $mntpnt/$TESTFILE.3
+log_mustnot $ZFS snapshot $fs@snap3
+if datasetexists $fs@snap3 ; then
+       log_fail "ERROR: $fs@snap3 should not exists."
+fi
+
+log_pass "Verify a snapshot will only be allowed if there is enough " \
+       "free space outside of this refreservation."
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_004_pos.ksh
new file mode 100755 (executable)
index 0000000..8238573
--- /dev/null
@@ -0,0 +1,90 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/refreserv/refreserv.cfg
+
+#
+# DESCRIPTION:
+#      Verify refreservation is limited by available space.
+#
+# STRATEGY:
+#      1. Setting quota and refreservation on parent filesystem.
+#      2. Get available space on sub-filesystem.
+#      3. Verify refreservation is limited by available on it.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if is_global_zone ; then
+               log_must $ZFS set refreservation=none $TESTPOOL
+       fi
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "Verify refreservation is limited by available space."
+log_onexit cleanup
+
+pool=$TESTPOOL ; fs=$pool/$TESTFS ; subfs=$fs/subfs
+log_must $ZFS create $subfs
+
+typeset datasets
+if is_global_zone; then
+        datasets="$pool $fs"
+else
+        datasets="$fs"
+fi
+
+for ds in $datasets; do
+       log_must $ZFS set quota=25M $ds
+       log_must $ZFS set refreservation=15M $ds
+
+       typeset -i avail
+       avail=$(get_prop avail $subfs)
+       log_must $ZFS set refreservation=$avail $subfs
+       typeset mntpnt
+       mntpnt=$(get_prop mountpoint $subfs)
+       log_must $MKFILE $avail $mntpnt/$TESTFILE
+
+       typeset -i exceed
+       ((exceed = avail + 1))
+       log_mustnot $ZFS set refreservation=$exceed $subfs
+       log_mustnot $MKFILE $avail $mntpnt/$TESTFILE
+
+       log_must $ZFS set quota=none $ds
+       log_must $ZFS set reservation=15M $ds
+done
+
+log_pass "Verify refreservation is limited by available space."
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/refreserv/refreserv_005_pos.ksh
new file mode 100755 (executable)
index 0000000..5a3adbb
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      Volume refreservation is limited by volsize
+#
+# STRATEGY:
+#      1. Create volume on filesystem
+#      2. Setting quota for parenet filesytem
+#      3. Verify volume refreservation is only limited by volsize
+#      4. Verify volume refreservation can be changed when volsize changed
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       log_must $ZFS destroy -rf $TESTPOOL/$TESTFS
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "Volume refreservation is limited by volsize"
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS; vol=$fs/vol
+log_must $ZFS create -V 10M $vol
+
+# Verify the parent filesystem does not affect volume
+log_must $ZFS set quota=25M $fs
+log_must $ZFS set refreservation=10M $vol
+avail=$(get_prop mountpoint $vol)
+log_mustnot $ZFS set refreservation=$avail $vol
+
+# Verify it is affected by volsize
+log_must $ZFS set volsize=15M $vol
+log_must $ZFS set refreservation=15M $vol
+log_mustnot $ZFS set refreservation=16M $vol
+
+log_pass "Volume refreservation is limited by volsize"
diff --git a/zfs/tests/zfs-tests/tests/functional/refreserv/setup.ksh b/zfs/tests/zfs-tests/tests/functional/refreserv/setup.ksh
new file mode 100755 (executable)
index 0000000..a34453b
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "both"
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/rename_dirs/Makefile.am b/zfs/tests/zfs-tests/tests/functional/rename_dirs/Makefile.am
new file mode 100644 (file)
index 0000000..029daf1
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/rename_dirs
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       rename_dirs_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/rename_dirs/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/rename_dirs/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/rename_dirs/rename_dirs_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rename_dirs/rename_dirs_001_pos.ksh
new file mode 100755 (executable)
index 0000000..f84a2b6
--- /dev/null
@@ -0,0 +1,71 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Create two directory trees in ZFS filesystem, and concurently rename
+# directory across the two trees. ZFS should be able to handle the race
+# situation.
+#
+# STRATEGY:
+# 1. Create a ZFS filesystem
+# 2. Make two directory tree in the zfs file system
+# 3. Continually rename directory from one tree to another tree in two process
+# 4. After the specified time duration, the system should not be panic.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "ZFS can handle race directory rename operation."
+
+log_onexit cleanup
+
+$CD $TESTDIR
+$MKDIR -p 1/2/3/4/5 a/b/c/d/e
+
+$RENAME_DIRS &
+
+$SLEEP 500
+typeset -i retval=1
+$PGREP $RENAME_DIRS >/dev/null 2>&1
+retval=$?
+if (( $retval == 0 )); then
+       $PKILL -9 $RENAME_DIRS >/dev/null 2>&1
+fi
+
+log_pass "ZFS handle race directory rename operation as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/rename_dirs/setup.ksh b/zfs/tests/zfs-tests/tests/functional/rename_dirs/setup.ksh
new file mode 100755 (executable)
index 0000000..fc5cec3
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/replacement/Makefile.am b/zfs/tests/zfs-tests/tests/functional/replacement/Makefile.am
new file mode 100644 (file)
index 0000000..ff3a7df
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/replacement
+dist_pkgdata_SCRIPTS = \
+       replacement.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       replacement_001_pos.ksh \
+       replacement_002_pos.ksh \
+       replacement_003_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/replacement/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/replacement/cleanup.ksh
new file mode 100755 (executable)
index 0000000..b81a372
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/replacement/replacement.cfg b/zfs/tests/zfs-tests/tests/functional/replacement/replacement.cfg
new file mode 100644 (file)
index 0000000..b2ba1b8
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export TESTFILE=testfile
+export TESTFILE1=testfile1
+export HOLES_FILESIZE=${HOLES_FILESIZE-"67108864"} # 64 Mb
+export HOLES_BLKSIZE=${HOLES_BLKSIZE-"512"}
+export HOLES_SEED=${HOLES_SEED-""}
+export HOLES_FILEOFFSET=${HOLES_FILEOFFSET-""}
+export HOLES_COUNT=${HOLES_COUNT-"16384"}         # FILESIZE/BLKSIZE/8
+export REPLACEFILE="sparedisk"
diff --git a/zfs/tests/zfs-tests/tests/functional/replacement/replacement_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/replacement/replacement_001_pos.ksh
new file mode 100755 (executable)
index 0000000..fcc575f
--- /dev/null
@@ -0,0 +1,157 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/replacement/replacement.cfg
+
+#
+# DESCRIPTION:
+#      Replacing disks during I/O should pass for supported pools.
+#
+# STRATEGY:
+#      1. Create multidisk pools (stripe/mirror/raidz) and
+#         start some random I/O
+#      2. Replace a disk in the pool with anbother disk.
+#      3. Verify the integrity of the file system and the resilvering.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if [[ -n "$child_pids" ]]; then
+               for wait_pid in $child_pids
+               do
+                       $KILL $wait_pid
+               done
+       fi
+
+       if poolexists $TESTPOOL1; then
+               destroy_pool $TESTPOOL1
+       fi
+
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "Replacing a disk during I/O completes."
+
+options=""
+options_display="default options"
+
+log_onexit cleanup
+
+[[ -n "$HOLES_FILESIZE" ]] && options=" $options -f $HOLES_FILESIZE "
+
+[[ -n "$HOLES_BLKSIZE" ]] && options="$options -b $HOLES_BLKSIZE "
+
+[[ -n "$HOLES_COUNT" ]] && options="$options -c $HOLES_COUNT "
+
+[[ -n "$HOLES_SEED" ]] && options="$options -s $HOLES_SEED "
+
+[[ -n "$HOLES_FILEOFFSET" ]] && options="$options -o $HOLES_FILEOFFSET "
+
+options="$options -r "
+
+[[ -n "$options" ]] && options_display=$options
+
+child_pids=""
+
+function replace_test
+{
+       typeset -i iters=2
+       typeset -i index=0
+       typeset opt=$1
+       typeset disk1=$2
+       typeset disk2=$3
+
+       typeset i=0
+       while [[ $i -lt $iters ]]; do
+               log_note "Invoking $FILE_TRUNC with: $options_display"
+               $FILE_TRUNC $options $TESTDIR/$TESTFILE.$i &
+               typeset pid=$!
+
+               $SLEEP 1
+
+               child_pids="$child_pids $pid"
+               ((i = i + 1))
+       done
+
+       log_must $ZPOOL replace $opt $TESTPOOL1 $disk1 $disk2
+
+       $SLEEP 10
+
+       for wait_pid in $child_pids
+       do
+               $KILL $wait_pid
+       done
+       child_pids=""
+
+        log_must $ZPOOL export $TESTPOOL1
+        log_must $ZPOOL import -d $TESTDIR $TESTPOOL1
+        log_must $ZFS umount $TESTPOOL1/$TESTFS1
+        log_must $ZDB -cdui $TESTPOOL1/$TESTFS1
+        log_must $ZFS mount $TESTPOOL1/$TESTFS1
+
+}
+
+specials_list=""
+i=0
+while [[ $i != 2 ]]; do
+        $MKFILE 100m $TESTDIR/$TESTFILE1.$i
+        specials_list="$specials_list $TESTDIR/$TESTFILE1.$i"
+
+        ((i = i + 1))
+done
+
+#
+# Create a replacement disk special file.
+#
+$MKFILE 100m $TESTDIR/$REPLACEFILE
+
+for type in "" "raidz" "raidz1" "mirror"; do
+       for op in "" "-f"; do
+               create_pool $TESTPOOL1 $type $specials_list
+               log_must $ZFS create $TESTPOOL1/$TESTFS1
+               log_must $ZFS set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
+
+               replace_test "$opt" $TESTDIR/$TESTFILE1.1 $TESTDIR/$REPLACEFILE
+
+               $ZPOOL iostat -v $TESTPOOL1 | grep "$TESTDIR/$REPLACEFILE"
+               if [[ $? -ne 0 ]]; then
+                       log_fail "$REPLACEFILE is not present."
+               fi
+
+               destroy_pool $TESTPOOL1
+               log_must $RM -rf /$TESTPOOL1
+       done
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/replacement/replacement_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/replacement/replacement_002_pos.ksh
new file mode 100755 (executable)
index 0000000..aae6d78
--- /dev/null
@@ -0,0 +1,174 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/replacement/replacement.cfg
+
+#
+# DESCRIPTION:
+#      Attaching disks during I/O should pass for supported pools.
+#
+# STRATEGY:
+#      1. Create multidisk pools (stripe/mirror/raidz) and
+#         start some random I/O
+#      2. Attach a disk to the pool.
+#      3. Verify the integrity of the file system and the resilvering.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if [[ -n "$child_pids" ]]; then
+               for wait_pid in $child_pids
+               do
+                       $KILL $wait_pid
+               done
+       fi
+
+       if poolexists $TESTPOOL1; then
+               destroy_pool $TESTPOOL1
+       fi
+
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "Replacing a disk during I/O completes."
+
+options=""
+options_display="default options"
+
+log_onexit cleanup
+
+[[ -n "$HOLES_FILESIZE" ]] && options=" $options -f $HOLES_FILESIZE "
+
+[[ -n "$HOLES_BLKSIZE" ]] && options="$options -b $HOLES_BLKSIZE "
+
+[[ -n "$HOLES_COUNT" ]] && options="$options -c $HOLES_COUNT "
+
+[[ -n "$HOLES_SEED" ]] && options="$options -s $HOLES_SEED "
+
+[[ -n "$HOLES_FILEOFFSET" ]] && options="$options -o $HOLES_FILEOFFSET "
+
+options="$options -r "
+
+[[ -n "$options" ]] && options_display=$options
+
+child_pids=""
+
+function attach_test
+{
+       typeset -i iters=2
+       typeset -i index=0
+       typeset opt=$1
+       typeset disk1=$2
+       typeset disk2=$3
+
+       typeset i=0
+       while [[ $i -lt $iters ]]; do
+               log_note "Invoking $FILE_TRUNC with: $options_display"
+               $FILE_TRUNC $options $TESTDIR/$TESTFILE.$i &
+               typeset pid=$!
+
+               $SLEEP 1
+
+               child_pids="$child_pids $pid"
+               ((i = i + 1))
+       done
+
+       log_must $ZPOOL attach $opt $TESTPOOL1 $disk1 $disk2
+
+       $SLEEP 10
+
+       for wait_pid in $child_pids
+       do
+               $KILL $wait_pid
+       done
+       child_pids=""
+
+        log_must $ZPOOL export $TESTPOOL1
+        log_must $ZPOOL import -d $TESTDIR $TESTPOOL1
+        log_must $ZFS umount $TESTPOOL1/$TESTFS1
+        log_must $ZDB -cdui $TESTPOOL1/$TESTFS1
+        log_must $ZFS mount $TESTPOOL1/$TESTFS1
+
+}
+
+specials_list=""
+i=0
+while [[ $i != 2 ]]; do
+       $MKFILE 100m $TESTDIR/$TESTFILE1.$i
+       specials_list="$specials_list $TESTDIR/$TESTFILE1.$i"
+
+       ((i = i + 1))
+done
+
+#
+# Create a replacement disk special file.
+#
+$MKFILE 100m $TESTDIR/$REPLACEFILE
+
+for op in "" "-f"; do
+       create_pool $TESTPOOL1 mirror $specials_list
+       log_must $ZFS create $TESTPOOL1/$TESTFS1
+       log_must $ZFS set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
+
+       attach_test "$opt" $TESTDIR/$TESTFILE1.1 $TESTDIR/$REPLACEFILE
+
+       $ZPOOL iostat -v $TESTPOOL1 | grep "$TESTDIR/$REPLACEFILE"
+       if [[ $? -ne 0 ]]; then
+               log_fail "$REPLACEFILE is not present."
+       fi
+
+       destroy_pool $TESTPOOL1
+done
+
+log_note "Verify 'zpool attach' fails with non-mirrors."
+
+for type in "" "raidz" "raidz1"; do
+       for op in "" "-f"; do
+               create_pool $TESTPOOL1 $type $specials_list
+               log_must $ZFS create $TESTPOOL1/$TESTFS1
+               log_must $ZFS set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
+
+               log_mustnot $ZPOOL attach "$opt" $TESTDIR/$TESTFILE1.1 \
+                   $TESTDIR/$REPLACEFILE
+
+               $ZPOOL iostat -v $TESTPOOL1 | grep "$TESTDIR/$REPLACEFILE"
+               if [[ $? -eq 0 ]]; then
+                       log_fail "$REPLACEFILE should not be present."
+               fi
+
+               destroy_pool $TESTPOOL1
+       done
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/replacement/replacement_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/replacement/replacement_003_pos.ksh
new file mode 100755 (executable)
index 0000000..1a7a7d8
--- /dev/null
@@ -0,0 +1,161 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/replacement/replacement.cfg
+
+#
+# DESCRIPTION:
+#      Detaching disks during I/O should pass for supported pools.
+#
+# STRATEGY:
+#      1. Create multidisk pools (stripe/mirror/raidz) and
+#         start some random I/O
+#      2. Detach a disk from the pool.
+#      3. Verify the integrity of the file system and the resilvering.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if [[ -n "$child_pids" ]]; then
+               for wait_pid in $child_pids
+               do
+                       $KILL $wait_pid
+               done
+       fi
+
+       if poolexists $TESTPOOL1; then
+               destroy_pool $TESTPOOL1
+       fi
+
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "Replacing a disk during I/O completes."
+
+options=""
+options_display="default options"
+
+log_onexit cleanup
+
+[[ -n "$HOLES_FILESIZE" ]] && options=" $options -f $HOLES_FILESIZE "
+
+[[ -n "$HOLES_BLKSIZE" ]] && options="$options -b $HOLES_BLKSIZE "
+
+[[ -n "$HOLES_COUNT" ]] && options="$options -c $HOLES_COUNT "
+
+[[ -n "$HOLES_SEED" ]] && options="$options -s $HOLES_SEED "
+
+[[ -n "$HOLES_FILEOFFSET" ]] && options="$options -o $HOLES_FILEOFFSET "
+
+ptions="$options -r "
+
+[[ -n "$options" ]] && options_display=$options
+
+child_pids=""
+
+function detach_test
+{
+       typeset -i iters=2
+       typeset -i index=0
+       typeset disk1=$1
+
+       typeset i=0
+       while [[ $i -lt $iters ]]; do
+               log_note "Invoking $FILE_TRUNC with: $options_display"
+               $FILE_TRUNC $options $TESTDIR/$TESTFILE.$i &
+               typeset pid=$!
+
+               $SLEEP 1
+
+               child_pids="$child_pids $pid"
+               ((i = i + 1))
+       done
+
+       log_must $ZPOOL detach $TESTPOOL1 $disk1
+
+       $SLEEP 10
+
+       for wait_pid in $child_pids
+       do
+               $KILL $wait_pid
+       done
+       child_pids=""
+
+        log_must $ZPOOL export $TESTPOOL1
+        log_must $ZPOOL import -d $TESTDIR $TESTPOOL1
+        log_must $ZFS umount $TESTPOOL1/$TESTFS1
+        log_must $ZDB -cdui $TESTPOOL1/$TESTFS1
+        log_must $ZFS mount $TESTPOOL1/$TESTFS1
+}
+
+specials_list=""
+i=0
+while [[ $i != 2 ]]; do
+       $MKFILE 100m $TESTDIR/$TESTFILE1.$i
+       specials_list="$specials_list $TESTDIR/$TESTFILE1.$i"
+
+       ((i = i + 1))
+done
+
+create_pool $TESTPOOL1 mirror $specials_list
+log_must $ZFS create $TESTPOOL1/$TESTFS1
+log_must $ZFS set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
+
+detach_test $TESTDIR/$TESTFILE1.1
+
+$ZPOOL iostat -v $TESTPOOL1 | grep "$TESTDIR/$TESTFILE1.1"
+if [[ $? -eq 0 ]]; then
+       log_fail "$TESTFILE1.1 should no longer be present."
+fi
+
+destroy_pool $TESTPOOL1
+
+log_note "Verify 'zpool detach' fails with non-mirrors."
+
+for type in "" "raidz" "raidz1" ; do
+       create_pool $TESTPOOL1 $type $specials_list
+       log_must $ZFS create $TESTPOOL1/$TESTFS1
+       log_must $ZFS set mountpoint=$TESTDIR1 $TESTPOOL1/$TESTFS1
+
+       log_mustnot $ZPOOL detach $TESTDIR/$TESTFILE1.1
+
+       $ZPOOL iostat -v $TESTPOOL1 | grep "$TESTDIR/$TESTFILE1.1"
+       if [[ $? -ne 0 ]]; then
+               log_fail "$TESTFILE1.1 is not present."
+       fi
+
+       destroy_pool $TESTPOOL1
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/replacement/setup.ksh b/zfs/tests/zfs-tests/tests/functional/replacement/setup.ksh
new file mode 100755 (executable)
index 0000000..4132392
--- /dev/null
@@ -0,0 +1,47 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 2
+
+index=`expr $RANDOM % 2`
+case $index in
+0)     log_note "Pool Type: Mirror"
+       default_mirror_setup $DISKS
+       ;;
+1)     log_note "Pool Type: RAID-Z"
+       default_raidz_setup $DISKS
+       ;;
+esac
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/Makefile.am b/zfs/tests/zfs-tests/tests/functional/reservation/Makefile.am
new file mode 100644 (file)
index 0000000..c346ca3
--- /dev/null
@@ -0,0 +1,24 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/reservation
+dist_pkgdata_SCRIPTS = \
+       reservation.cfg \
+       reservation.shlib \
+       setup.ksh \
+       cleanup.ksh \
+       reservation_001_pos.sh \
+       reservation_002_pos.sh \
+       reservation_003_pos.sh \
+       reservation_004_pos.sh \
+       reservation_005_pos.sh \
+       reservation_006_pos.sh \
+       reservation_007_pos.sh \
+       reservation_008_pos.sh \
+       reservation_009_pos.sh \
+       reservation_010_pos.sh \
+       reservation_011_pos.sh \
+       reservation_012_pos.sh \
+       reservation_013_pos.sh \
+       reservation_014_pos.sh \
+       reservation_015_pos.sh \
+       reservation_016_pos.sh \
+       reservation_017_pos.sh \
+       reservation_018_pos.sh
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/reservation/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation.cfg b/zfs/tests/zfs-tests/tests/functional/reservation/reservation.cfg
new file mode 100644 (file)
index 0000000..c12ad07
--- /dev/null
@@ -0,0 +1,44 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export RESV_DELTA=5242880
+export RESV_TOLERANCE=5242880  # Acceptable limit (5MB) for diff in space stats
+export RESV_SIZE=52428800      # Default reservation size (50MB)
+export RESV_FREE_SPACE=52428800        # Amount of space (50MB) to leave free in a pool
+export RESV_NUM_FS=10          # Number of filesystems to create
+export RESV_ITER=10            # Number of iterations
+
+export BLOCK_SIZE=1048576
+export ENOSPC=28
+
+export TESTVOL=testvol$$
+export TESTVOL2=testvol2-$$
+export TESTFILE1=file1.$$
+export TESTFILE2=file2.$$
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation.shlib b/zfs/tests/zfs-tests/tests/functional/reservation/reservation.shlib
new file mode 100644 (file)
index 0000000..e58e198
--- /dev/null
@@ -0,0 +1,201 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/reservation/reservation.cfg
+
+#
+# Function to set the reservation property of a dataset to
+# 'none' and verify that it is correctly set using both the
+# "normal" 'zfs get reservation' and the '-p' option which
+# gives a numerical value.
+#
+function zero_reservation
+{
+       typeset resv_val
+       dataset=$1
+
+       log_must $ZFS set reservation=none $dataset
+
+       resv_val=`$ZFS get -H reservation $dataset | awk '{print $3}'`
+       if [[ $? -ne 0 ]]; then
+               log_fail "Unable to get reservation prop on $dataset"
+       elif [[ $resv_val != "none" ]]; then
+               log_fail "Reservation not 'none' ($resv_val) as expected"
+       fi
+
+
+       resv_val=`$ZFS get -pH reservation $dataset | awk '{print $3}'`
+       if [[ $? -ne 0 ]]; then
+               log_fail "Unable to get reservation prop on $dataset"
+       elif [[ $resv_val -ne 0 ]]; then
+               log_fail "Reservation not 0 ($resv_val) as expected"
+       fi
+
+       return 0
+}
+
+#
+# Utility function to see if two values are within a certain specified
+# limit of each other. Used primarily to check that a dataset's parent
+# is correctly accounting for space used/available. Need this function as
+# currently there is some slop in the way space is accounted (i.e. can't
+# do a direct comparison).
+#
+function within_limits
+{
+       typeset -l valA=$1
+       typeset -l valB=$2
+       typeset -l delta=$3
+
+       if ((valA <= valB)); then
+               if (((valB - valA) <= delta)); then
+                       return 0
+               fi
+       elif ((valB <= valA)); then
+               if (((valA - valB) <= delta)); then
+                       return 0
+               fi
+       fi
+
+       return 1
+}
+
+#
+# Function to create and mount multiple filesystems. The filesystem
+# will be named according to the name specified with a suffix value
+# taken from the loop counter.
+#
+function create_multiple_fs # num_fs base_fs_name base_mnt_name
+{
+       typeset -i iter=0
+       typeset -i count=$1
+       typeset FS_NAME=$2
+       typeset MNT_NAME=$3
+
+       while  (($iter < $count)); do
+               log_must $ZFS create ${FS_NAME}$iter
+               log_must $ZFS set mountpoint=${MNT_NAME}$iter ${FS_NAME}$iter
+               ((iter = iter + 1))
+       done
+}
+
+#
+# This function compute the largest volume size which is multiple of volume
+# block size (default 8K) and not greater than the largest expected volsize.
+#
+# $1 The largest expected volume size.
+# $2 The volume block size
+#
+function floor_volsize #<largest_volsize> [volblksize]
+{
+       typeset -l largest_volsize=$1
+       typeset -l volblksize=${2:-8192}
+
+       if ((largest_volsize < volblksize)); then
+               log_fail "The largest_volsize must be greater than volblksize."
+       fi
+       typeset -l real_volsize
+       typeset -l n
+
+       ((n = largest_volsize / volblksize))
+       ((largest_volsize = volblksize * n))
+
+       print $largest_volsize
+}
+
+#
+# This function is a copy of a function by the same name in libzfs_dataset.c
+# Its purpose is to reserve additional space for volume metadata so volumes
+# don't unexpectedly run out of room.
+#
+# Note: This function can be used to do an estimate for a volume that has not
+# yet been created. In this case, $vol is not a volume, but rather a pool in
+# which a volume is going to be created. In this case, use default properties.
+#
+function volsize_to_reservation
+{
+       typeset vol=$1
+       typeset -i volsize=$2
+
+       typeset -i DN_MAX_INDBLKSHIFT=14
+       typeset -i SPA_BLKPTRSHIFT=7
+       typeset -i SPA_DVAS_PER_BP=3
+
+       typeset -i DNODES_PER_LEVEL_SHIFT=$((DN_MAX_INDBLKSHIFT - \
+           SPA_BLKPTRSHIFT))
+       typeset -i DNODES_PER_LEVEL=$((1 << $DNODES_PER_LEVEL_SHIFT))
+
+       if ds_is_volume $vol; then
+               typeset -i ncopies=$(get_prop copies $vol)
+               typeset -i volblocksize=$(get_prop volblocksize $vol)
+       else
+               typeset -i ncopies=1
+               typeset -i volblocksize=8192
+       fi
+       typeset -i nblocks=$((volsize / volblocksize))
+
+       typeset -i numdb=7
+       while ((nblocks > 1)); do
+               ((nblocks += DNODES_PER_LEVEL - 1))
+               ((nblocks /= DNODES_PER_LEVEL))
+               ((numdb += nblocks))
+       done
+
+       ((numdb *= SPA_DVAS_PER_BP < ncopies + 1 ? SPA_DVAS_PER_BP : \
+           ncopies + 1))
+       ((volsize *= ncopies))
+       ((numdb *= 1 << DN_MAX_INDBLKSHIFT))
+       ((volsize += numdb))
+       echo $volsize
+}
+
+#
+# This function takes a pool name as an argument, and returns the largest (give
+# or take some slop) -V value that can be used to create a volume in that pool.
+# This is necessary because during volume creation, a reservation is created
+# that will be larger than the value specified with -V, and potentially larger
+# than the available space in the pool. See volsize_to_reservation().
+#
+function largest_volsize_from_pool
+{
+       typeset pool=$1
+       typeset -i poolsize=$(get_prop available $pool)
+       typeset -i volsize=$poolsize
+       typeset -i nvolsize
+
+       while :; do
+               # knock 50M off the volsize each time through
+               ((volsize -= 50 * 1024 * 1024))
+               nvolsize=$(volsize_to_reservation $pool $volsize)
+               nvolsize=$(floor_volsize $nvolsize)
+               ((nvolsize < poolsize)) && break
+       done
+       echo $volsize
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_001_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_001_pos.sh
new file mode 100755 (executable)
index 0000000..cef3187
--- /dev/null
@@ -0,0 +1,124 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# ZFS allows reservations to be set on filesystems and volumes, provided
+# the reservation is less than the space available in the pool.
+#
+# STRATEGY:
+# 1) Create a regular and sparse volume
+#   (filesystem already created by default_setup)
+# 2) Get the space available in the pool
+# 3) Set a reservation on the filesystem less than the space available.
+# 4) Verify that the 'reservation' property for the filesystem has
+#    the correct value.
+# 5) Reset the reservation to 'none'
+# 6) Repeat steps 2-5 for both volume types
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for obj in $OBJ_LIST; do
+               datasetexists $obj && log_must $ZFS destroy -f $obj
+       done
+}
+
+log_onexit cleanup
+
+log_assert "Verify that to set a reservation on a filesystem or volume must " \
+    "use value smaller than space available property of pool"
+
+space_avail=`get_prop available $TESTPOOL`
+
+if ! is_global_zone ; then
+       OBJ_LIST=""
+else
+       OBJ_LIST="$TESTPOOL/$TESTVOL $TESTPOOL/$TESTVOL2"
+
+       ((vol_set_size = space_avail / 4))
+       vol_set_size=$(floor_volsize $vol_set_size)
+       ((sparse_vol_set_size = space_avail * 4))
+       sparse_vol_set_size=$(floor_volsize $sparse_vol_set_size)
+
+       #
+       # Note that when creating a regular volume we are implicitly
+       # setting a reservation upon it (i.e. the size of the volume)
+       # which we reset back to zero initially.
+       #
+       log_must $ZFS create -V $vol_set_size $TESTPOOL/$TESTVOL
+       log_must $ZFS set reservation=none $TESTPOOL/$TESTVOL
+       log_must $ZFS set refreservation=none $TESTPOOL/$TESTVOL
+       log_must $ZFS create -s -V $sparse_vol_set_size $TESTPOOL/$TESTVOL2
+fi
+
+
+for obj in $TESTPOOL/$TESTFS $OBJ_LIST; do
+
+       space_avail=`get_prop available $TESTPOOL`
+       resv_size_set=`expr $space_avail - $RESV_DELTA`
+
+       #
+       # For a regular (non-sparse) volume the upper limit
+       # for reservations is not determined by the space
+       # available in the pool but rather by the size of
+       # the volume itself.
+       #
+       [[ $obj == $TESTPOOL/$TESTVOL ]] && \
+           ((resv_size_set = vol_set_size - RESV_DELTA))
+
+       log_must $ZFS set reservation=$resv_size_set $obj
+
+       resv_size_get=`get_prop reservation $obj`
+       if [[ $resv_size_set != $resv_size_get ]]; then
+               log_fail "Reservation not the expected value " \
+                   "($resv_size_set != $resv_size_get)"
+       fi
+
+       log_must zero_reservation $obj
+
+       new_space_avail=`get_prop available $obj`
+
+       #
+       # Due to the way space is consumed and released by metadata we
+       # can't do an exact check here, but we do do a basic sanity
+       # check.
+       #
+       log_must within_limits $space_avail $new_space_avail $RESV_TOLERANCE
+done
+
+log_pass "Successfully set reservation on filesystem and volume"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_002_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_002_pos.sh
new file mode 100755 (executable)
index 0000000..fdf4ce3
--- /dev/null
@@ -0,0 +1,108 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# Reservation values cannot exceed the amount of space available
+# in the pool. Verify that attempting to set a reservation greater
+# than this value fails.
+#
+# STRATEGY:
+# 1) Create a filesystem, regular and sparse volume
+# 2) Get the space available in the pool
+# 3) Attempt to set a reservation greater than the available space
+# on the filesystem and verify it fails.
+# 4) Verify that the reservation is still set to 'none' (or 0) on
+# the filesystem.
+# 5) Repeat 3-4 for regular and sparse volume
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for obj in $OBJ_LIST; do
+               datasetexists $obj && log_must $ZFS destroy -f $obj
+       done
+
+       log_must zero_reservation $TESTPOOL/$TESTFS
+}
+
+log_onexit cleanup
+
+log_assert "Reservation values cannot exceed the amount of space" \
+       " available in the pool"
+
+space_avail=`get_prop available $TESTPOOL`
+
+if ! is_global_zone ; then
+       OBJ_LIST=""
+else
+       OBJ_LIST="$TESTPOOL/$TESTVOL $TESTPOOL/$TESTVOL2"
+
+       ((vol_set_size = space_avail / 4))
+       vol_set_size=$(floor_volsize $vol_set_size)
+       ((sparse_vol_set_size = space_avail * 4))
+       sparse_vol_set_size=$(floor_volsize $sparse_vol_set_size)
+
+       log_must $ZFS create -V $vol_set_size $TESTPOOL/$TESTVOL
+       log_must $ZFS set reservation=none $TESTPOOL/$TESTVOL
+       log_must $ZFS create -s -V $sparse_vol_set_size $TESTPOOL/$TESTVOL2
+fi
+
+for obj in $TESTPOOL/$TESTFS $OBJ_LIST ; do
+
+       space_avail=`get_prop available $TESTPOOL`
+       resv_size_set=`expr $space_avail + $RESV_DELTA`
+
+       #
+       # For regular (non-sparse) volumes the upper limit is determined
+       # not by the space available in the pool but rather by the size
+       # of the volume itself.
+       #
+       [[ $obj == $TESTPOOL/$TESTVOL ]] && \
+           ((resv_size_set = vol_set_size + RESV_DELTA))
+
+       log_must zero_reservation $obj
+       log_mustnot $ZFS set reservation=$resv_size_set $obj
+
+       resv_size_get=`get_prop reservation $obj`
+
+       if (($resv_size_get != 0)); then
+               log_fail "Reservation value non-zero ($resv_size_get)"
+       fi
+done
+
+log_pass "Attempting to set too large reservation failed as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_003_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_003_pos.sh
new file mode 100755 (executable)
index 0000000..81096e8
--- /dev/null
@@ -0,0 +1,134 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# Verify that it's possible to set a reservation on a filesystem,
+# or volume multiple times, without resetting the reservation
+# to none.
+#
+# STRATEGY:
+# 1) Create a regular volume and a sparse volume
+# 2) Get the space available in the pool
+# 3) Set a reservation on the filesystem less than the space available.
+# 4) Verify that the 'reservation' property for the filesystem has
+# the correct value.
+# 5) Repeat 2-4 for different reservation values
+# 6) Repeat 3-5 for regular and sparse volume
+#
+
+verify_runnable "both"
+
+log_assert "Verify it is possible to set reservations multiple times " \
+       "on a filesystem regular and sparse volume"
+
+function cleanup
+{
+       log_must zero_reservation $TESTPOOL/$TESTFS
+
+       for obj in $OBJ_LIST; do
+       datasetexists $obj && log_must $ZFS destroy -f $obj
+       done
+}
+
+log_onexit cleanup
+
+
+#
+# Set a reservation $RESV_ITER times on a dataset and verify that
+# the reservation is correctly set each time.
+#
+function multiple_resv { #dataset
+       typeset -i i=0
+
+       dataset=$1
+
+       log_must zero_reservation $dataset
+       space_avail=`get_prop available $TESTPOOL`
+
+       ((resv_size = (space_avail - RESV_DELTA) / RESV_ITER))
+
+       #
+       # For regular (non-sparse) volumes the upper limit is determined
+       # not by the space available in the pool but rather by the size
+       # of the volume itself.
+       #
+       [[ $obj == $TESTPOOL/$TESTVOL ]] && \
+           ((resv_size = (vol_set_size - RESV_DELTA) / RESV_ITER))
+
+       resv_size_set=$resv_size
+
+       while (($i < $RESV_ITER)); do
+
+               ((i = i + 1))
+
+               ((resv_size_set = resv_size * i))
+
+               log_must $ZFS set reservation=$resv_size_set $dataset
+
+               resv_size_get=`get_prop reservation $dataset`
+               if [[ $resv_size_set != $resv_size_get ]]; then
+                       log_fail "Reservation not the expected value " \
+                           "($resv_size_set != $resv_size_get)"
+               fi
+       done
+
+       log_must zero_reservation $dataset
+}
+
+space_avail=`get_prop available $TESTPOOL`
+
+if ! is_global_zone ; then
+       OBJ_LIST=""
+else
+       OBJ_LIST="$TESTPOOL/$TESTVOL $TESTPOOL/$TESTVOL2"
+
+       ((vol_set_size = space_avail / 4))
+       vol_set_size=$(floor_volsize $vol_set_size)
+       ((sparse_vol_set_size = space_avail * 4))
+       sparse_vol_set_size=$(floor_volsize $sparse_vol_set_size)
+
+
+       log_must $ZFS create -V $vol_set_size $TESTPOOL/$TESTVOL
+       log_must $ZFS set reservation=none $TESTPOOL/$TESTVOL
+       log_must $ZFS create -s -V $sparse_vol_set_size $TESTPOOL/$TESTVOL2
+fi
+
+for obj in $TESTPOOL/$TESTFS $OBJ_LIST ; do
+       multiple_resv $obj
+done
+
+log_pass "Multiple reservations successfully set on filesystem" \
+    " and both volume types"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_004_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_004_pos.sh
new file mode 100755 (executable)
index 0000000..3734002
--- /dev/null
@@ -0,0 +1,124 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# When a dataset which has a reservation set on it is destroyed,
+# the space consumed or reserved by that dataset should be released
+# back into the pool.
+#
+# STRATEGY:
+# 1) Create a filesystem, regular and sparse volume
+# 2) Get the space used and available in the pool
+# 3) Set a reservation on the filesystem less than the space available.
+# 4) Verify that the 'reservation' property for the filesystem has
+# the correct value.
+# 5) Destroy the filesystem without resetting the reservation value.
+# 6) Verify that the space used and available totals for the pool have
+# changed by the expected amounts (within tolerances).
+# 7) Repeat steps 3-6 for a regular volume and sparse volume
+#
+
+verify_runnable "both"
+
+function cleanup {
+
+       for obj in $OBJ_LIST; do
+               datasetexists $obj && log_must $ZFS destroy -f $obj
+       done
+}
+
+log_assert "Verify space released when a dataset with reservation is destroyed"
+
+log_onexit cleanup
+
+log_must $ZFS create $TESTPOOL/$TESTFS2
+
+space_avail=`get_prop available $TESTPOOL`
+
+if ! is_global_zone ; then
+       OBJ_LIST="$TESTPOOL/$TESTFS2"
+else
+       OBJ_LIST="$TESTPOOL/$TESTFS2 \
+               $TESTPOOL/$TESTVOL $TESTPOOL/$TESTVOL2"
+
+       ((vol_set_size = space_avail / 4))
+       vol_set_size=$(floor_volsize $vol_set_size)
+       ((sparse_vol_set_size = space_avail * 4))
+       sparse_vol_set_size=$(floor_volsize $sparse_vol_set_size)
+
+       log_must $ZFS create -V $vol_set_size $TESTPOOL/$TESTVOL
+       log_must $ZFS set refreservation=none $TESTPOOL/$TESTVOL
+       log_must $ZFS set reservation=none $TESTPOOL/$TESTVOL
+       log_must $ZFS create -s -V $sparse_vol_set_size $TESTPOOL/$TESTVOL2
+fi
+
+# re-calculate space available.
+space_avail=`get_prop available $TESTPOOL`
+
+# Calculate a large but valid reservation value.
+resv_size_set=`expr $space_avail - $RESV_DELTA`
+
+for obj in $OBJ_LIST ; do
+
+       space_avail=`get_prop available $TESTPOOL`
+       space_used=`get_prop used $TESTPOOL`
+
+       #
+       # For regular (non-sparse) volumes the upper limit is determined
+       # not by the space available in the pool but rather by the size
+       # of the volume itself.
+       #
+       [[ $obj == $TESTPOOL/$TESTVOL ]] && \
+           ((resv_size_set = vol_set_size - RESV_DELTA))
+
+       log_must $ZFS set reservation=$resv_size_set $obj
+
+       resv_size_get=`get_prop reservation $obj`
+       if [[ $resv_size_set != $resv_size_get ]]; then
+               log_fail "Reservation not the expected value " \
+               "($resv_size_set != $resv_size_get)"
+       fi
+
+       log_must $ZFS destroy -f $obj
+
+       new_space_avail=`get_prop available $TESTPOOL`
+       new_space_used=`get_prop used $TESTPOOL`
+
+       log_must within_limits $space_used $new_space_used $RESV_TOLERANCE
+       log_must within_limits $space_avail $new_space_avail $RESV_TOLERANCE
+done
+
+log_pass "Space correctly released when dataset is destroyed"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_005_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_005_pos.sh
new file mode 100755 (executable)
index 0000000..19b07fe
--- /dev/null
@@ -0,0 +1,118 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# When a reservation property of a filesystem, regular volume
+# or sparse volume is set to 'none' the space previously consumed by the
+# reservation should be released back to the pool
+#
+# STRATEGY:
+# 1) Create a filesystem, regular volume and sparse volume
+# 2) Get the space used and available in the pool
+# 3) Set a reservation on the filesystem less than the space available.
+# 4) Verify that the 'reservation' property for the filesystem has
+# the correct value.
+# 5) Reset the reservation value back to zero (or 'none')
+# 6) Verify that the space used and available totals for the pool have
+# changed by the expected amounts (within tolerances).
+# 7) Repeat steps 3-6 for a regular volume, sparse volume
+#
+
+verify_runnable "both"
+
+log_assert "Verify space released when reservation on a dataset is set "\
+       "to 'none'"
+
+function cleanup
+{
+       for obj in $OBJ_LIST; do
+               datasetexists $obj && log_must $ZFS destroy -f $obj
+       done
+}
+
+log_onexit cleanup
+
+space_avail=`get_prop available $TESTPOOL`
+
+if ! is_global_zone ; then
+       OBJ_LIST=""
+else
+       OBJ_LIST="$TESTPOOL/$TESTVOL $TESTPOOL/$TESTVOL2"
+       ((vol_set_size = space_avail / 4))
+       vol_set_size=$(floor_volsize $vol_set_size)
+       ((sparse_vol_set_size = space_avail * 4))
+       sparse_vol_set_size=$(floor_volsize $sparse_vol_set_size)
+
+
+       log_must $ZFS create -V $vol_set_size $TESTPOOL/$TESTVOL
+       log_must $ZFS set reservation=none $TESTPOOL/$TESTVOL
+       log_must $ZFS create -s -V $sparse_vol_set_size $TESTPOOL/$TESTVOL2
+fi
+
+space_avail=`get_prop available $TESTPOOL`
+space_used=`get_prop used $TESTPOOL`
+
+# Calculate a large but valid reservation value.
+resv_size_set=`expr $space_avail - $RESV_DELTA`
+
+for obj in $TESTPOOL/$TESTFS $OBJ_LIST ; do
+
+       #
+       # For regular (non-sparse) volumes the upper limit is determined
+       # not by the space available in the pool but rather by the size
+       # of the volume itself.
+       #
+       [[ $obj == $TESTPOOL/$TESTVOL ]] && \
+           ((resv_size_set = vol_set_size - RESV_DELTA))
+
+       log_must $ZFS set reservation=$resv_size_set $obj
+
+       resv_size_get=`get_prop reservation $obj`
+       if [[ $resv_size_set != $resv_size_get ]]; then
+               log_fail "Reservation not the expected value "\
+                       "($resv_size_set != $resv_size_get)"
+       fi
+
+       log_must $ZFS set reservation=none $obj
+
+       new_space_avail=`get_prop available $TESTPOOL`
+       new_space_used=`get_prop used $TESTPOOL`
+
+       log_must within_limits $space_used $new_space_used $RESV_TOLERANCE
+       log_must within_limits $space_avail $new_space_avail $RESV_TOLERANCE
+done
+
+log_pass "Space correctly released when dataset reservation set to 'none'"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_006_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_006_pos.sh
new file mode 100755 (executable)
index 0000000..87359aa
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# Reservations (if successfully set) guarantee a minimum amount of space
+# for a dataset. Unlike quotas however there should be no restrictions
+# on accessing space outside of the limits of the reservation (if the
+# space is available in the pool). Verify that in a filesystem with a
+# reservation set that its possible to create files both within the
+# reserved space and also outside.
+#
+# STRATEGY:
+# 1) Create a filesystem
+# 2) Get the space used and available in the pool
+# 3) Set a reservation on the filesystem
+# 4) Verify can write a file that is bigger than the reserved space
+#
+# i.e. we start writing within the reserved region and then continue
+# for 20MB outside it.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       [[ -e $TESTDIR/$TESTFILE1 ]] && log_must $RM -rf $TESTDIR/$TESTFILE1
+       log_must $ZFS set reservation=none $TESTPOOL/$TESTFS
+}
+
+log_onexit cleanup
+
+log_assert "Verify can create files both inside and outside reserved areas"
+
+space_used=`get_prop used $TESTPOOL`
+
+log_must $ZFS set reservation=$RESV_SIZE $TESTPOOL/$TESTFS
+
+#
+# Calculate how many writes of BLOCK_SIZE it would take to fill
+# up RESV_SIZE + 20971520 (20 MB).
+#
+fill_size=`expr $RESV_SIZE + 20971520`
+write_count=`expr $fill_size / $BLOCK_SIZE`
+
+log_must $FILE_WRITE -o create -f $TESTDIR/$TESTFILE1 -b $BLOCK_SIZE \
+    -c $write_count -d 0
+
+log_pass "Able to create files inside and outside reserved area"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_007_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_007_pos.sh
new file mode 100755 (executable)
index 0000000..0765f2b
--- /dev/null
@@ -0,0 +1,128 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# Setting a reservation on dataset should have no effect on any other
+# dataset at the same level in the hierarchy beyond using up available
+# space in the pool.
+#
+# STRATEGY:
+# 1) Create a filesystem
+# 2) Set a reservation on the filesystem
+# 3) Create another filesystem at the same level
+# 4) Set a reservation on the second filesystem
+# 5) Destroy both the filesystems
+# 6) Verify space accounted for correctly
+#
+
+verify_runnable "both"
+
+log_assert "Verify reservations on data sets doesn't affect other data sets " \
+    "at same level except for consuming space from common pool"
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTFS2 && \
+           log_must $ZFS destroy -f $TESTPOOL/$TESTFS2
+
+       datasetexists $TESTPOOL/$TESTFS1 && \
+           log_must $ZFS destroy -f $TESTPOOL/$TESTFS1
+}
+
+log_onexit cleanup
+
+space_avail=`get_prop available $TESTPOOL`
+space_used=`get_prop used $TESTPOOL`
+
+resv_size_set=`expr $space_avail / 3`
+
+#
+# Function which creates two datasets, sets reservations on them,
+# then destroys them and ensures that space is correctly accounted
+# for.
+#
+# Any special arguments for create are passed in via the args
+# paramater.
+#
+function create_resv_destroy { # args1 dataset1 args2 dataset2
+
+       args1=$1
+       dataset1=$2
+       args2=$3
+       dataset2=$4
+
+       log_must $ZFS create $args1 $dataset1
+
+       log_must $ZFS set reservation=$RESV_SIZE $dataset1
+
+       avail_aft_dset1=`get_prop available $TESTPOOL`
+       used_aft_dset1=`get_prop used $TESTPOOL`
+
+       log_must $ZFS create $args2 $dataset2
+
+       log_must $ZFS set reservation=$RESV_SIZE $dataset2
+
+       #
+       # After destroying the second dataset the space used and
+       # available totals should revert back to the values they
+       # had after creating the first dataset.
+       #
+       log_must $ZFS destroy -f $dataset2
+
+       avail_dest_dset2=`get_prop available $TESTPOOL`
+       used_dest_dset2=`get_prop used $TESTPOOL`
+
+       log_must within_limits $avail_aft_dset1 $avail_dest_dset2 $RESV_TOLERANCE
+       log_must within_limits $used_aft_dset1 $used_dest_dset2 $RESV_TOLERANCE
+
+
+       # After destroying the first dataset the space used and
+       # space available totals should revert back to the values
+       # they had when the pool was first created.
+       log_must $ZFS destroy -f $dataset1
+
+       avail_dest_dset1=`get_prop available $TESTPOOL`
+       used_dest_dset1=`get_prop used $TESTPOOL`
+
+       log_must within_limits $avail_dest_dset1 $space_avail $RESV_TOLERANCE
+       log_must within_limits $used_dest_dset1 $space_used $RESV_TOLERANCE
+}
+
+create_resv_destroy "" $TESTPOOL/$TESTFS1 ""  $TESTPOOL/$TESTFS2
+create_resv_destroy "" $TESTPOOL/$TESTFS2 "" $TESTPOOL/$TESTFS1
+
+log_pass "Verify reservations on data sets doesn't affect other data sets at" \
+       " same level except for consuming space from common pool"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_008_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_008_pos.sh
new file mode 100755 (executable)
index 0000000..5753d99
--- /dev/null
@@ -0,0 +1,124 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# Setting a reservation reserves a defined minimum amount of space for
+# a dataset, and prevents other datasets using that space. Verify that
+# reducing the reservation on a filesystem allows other datasets in
+# the pool to use that space.
+#
+# STRATEGY:
+# 1) Create multiple filesystems
+# 2) Set reservations on all bar one of the filesystems
+# 3) Fill up the one non-reserved filesystem
+# 4) Reduce one of the reservations and verify can write more
+# data into the non-reserved filesystem
+#
+
+verify_runnable "both"
+
+log_assert "Verify reducing reservation allows other datasets to use space"
+
+function cleanup
+{
+       typeset -i loop=0
+       while (($loop < $RESV_NUM_FS)); do
+               datasetexists $TESTPOOL/${TESTFS}$loop && \
+                   log_must $ZFS destroy -f $TESTPOOL/${TESTFS}$loop
+
+               [[ -d ${TESTDIR}$loop ]] && log_must $RM -r ${TESTDIR}$loop
+
+               ((loop = loop + 1))
+       done
+}
+
+log_onexit cleanup
+
+log_must create_multiple_fs $RESV_NUM_FS $TESTPOOL/$TESTFS $TESTDIR
+
+space_avail=`get_prop available $TESTPOOL`
+space_used=`get_prop used $TESTPOOL`
+
+#
+# To make sure this test doesn't take too long to execute on
+# large pools, we calculate a reservation setting which when
+# applied to all bar one of the filesystems (RESV_NUM_FS-1) will
+# ensure we have RESV_FREE_SPACE left free in the pool, which we will
+# be able to quickly fill.
+#
+resv_space_avail=`expr $space_avail - $RESV_FREE_SPACE`
+num_resv_fs=`expr $RESV_NUM_FS - 1` # Number of FS to which resv will be applied
+resv_size_set=`expr $resv_space_avail / $num_resv_fs`
+
+#
+# We set the reservations now, rather than when we created the filesystems
+# to allow us to take into account space used by the filsystem metadata
+#
+# Note we don't set a reservation on the first filesystem we created,
+# hence num=1 rather than zero below.
+#
+typeset -i num=1
+while (($num < $RESV_NUM_FS)); do
+       log_must $ZFS set reservation=$resv_size_set $TESTPOOL/$TESTFS$num
+       ((num = num + 1))
+done
+
+space_avail_still=`get_prop available $TESTPOOL`
+
+fill_size=`expr $space_avail_still + $RESV_TOLERANCE`
+write_count=`expr $fill_size / $BLOCK_SIZE`
+
+# Now fill up the first filesystem (which doesn't have a reservation set
+# and thus will use up whatever free space is left in the pool).
+num=0
+log_note "Writing to $TESTDIR$num/$TESTFILE1"
+
+$FILE_WRITE -o create -f $TESTDIR$num/$TESTFILE1 -b $BLOCK_SIZE \
+    -c $write_count -d 0
+ret=$?
+if (($ret != $ENOSPC)); then
+       log_fail "Did not get ENOSPC as expected (got $ret)."
+fi
+
+# Remove the reservation on one of the other filesystems and verify
+# can write more data to the original non-reservation filesystem.
+num=1
+log_must $ZFS set reservation=none $TESTPOOL/${TESTFS}$num
+num=0
+log_must $FILE_WRITE -o create -f ${TESTDIR}$num/$TESTFILE2 -b $PAGESIZE \
+    -c 1000 -d 0
+
+log_pass "reducing reservation allows other datasets to use space"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_009_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_009_pos.sh
new file mode 100755 (executable)
index 0000000..67c6524
--- /dev/null
@@ -0,0 +1,100 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# In pool with a full filesystem and another filesystem with a reservation
+# setting the reservation on the second filesystem to 'none' should allow more
+# data to be written to the first filesystem.
+#
+#
+# STRATEGY:
+# 1) Create a filesystem as a dataset
+# 2) Create a filesystem at the same level
+# 3) Set a reservation on the dataset filesystem
+# 4) Fill up the filesystem
+# 5) Set the reservation on the dataset filesystem to 'none'
+# 6) Verify we can write more data to the first filesystem
+#
+
+verify_runnable "both"
+
+log_assert "Setting top level dataset reservation to 'none' allows more data "
+    "to be written to top level filesystem"
+
+function cleanup
+{
+       log_must $RM -rf $TESTDIR/$TESTFILE1
+       log_must $RM -rf $TESTDIR/$TESTFILE2
+       log_must $ZFS destroy -f $TESTPOOL/$TESTFS1
+}
+
+log_onexit cleanup
+
+log_must $ZFS create $TESTPOOL/$TESTFS1
+
+space_avail=`get_prop available $TESTPOOL`
+
+#
+# To make sure this test doesn't take too long to execute on
+# large pools, we calculate a reservation setting which when
+# applied to the dataset will ensure we have RESV_FREE_SPACE
+# left free in the pool which we can quickly fill.
+#
+((resv_size_set = space_avail - RESV_FREE_SPACE))
+
+log_must $ZFS set reservation=$resv_size_set $TESTPOOL/$TESTFS1
+
+space_avail_still=`get_prop available $TESTPOOL`
+
+fill_size=`expr $space_avail_still + $RESV_TOLERANCE`
+write_count=`expr $fill_size / $BLOCK_SIZE`
+
+# Now fill up the filesystem (which doesn't have a reservation set
+# and thus will use up whatever free space is left in the pool).
+$FILE_WRITE -o create -f $TESTDIR/$TESTFILE1 -b $BLOCK_SIZE \
+        -c $write_count -d 0
+ret=$?
+if (($ret != $ENOSPC)); then
+       log_fail "Did not get ENOSPC as expected (got $ret)."
+fi
+
+log_must $ZFS set reservation=none $TESTPOOL/$TESTFS1
+
+log_must $FILE_WRITE -o create -f $TESTDIR/$TESTFILE2 -b $PAGESIZE \
+    -c 1000 -d 0
+
+log_pass "Setting top level dataset reservation to 'none' allows more " \
+    "data to be written to the top level filesystem"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_010_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_010_pos.sh
new file mode 100755 (executable)
index 0000000..23e78bd
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# In pool with a full filesystem and a filesystem with a reservation
+# destroying another filesystem should allow more data to be written to
+# the full filesystem
+#
+#
+# STRATEGY:
+# 1) Create a filesystem as dataset
+# 2) Create a filesystem at the same level
+# 3) Set a reservation on the dataset filesystem
+# 4) Fill up the second filesystem
+# 5) Destroy the dataset filesystem
+# 6) Verify can write more data to the full filesystem
+#
+
+verify_runnable "both"
+
+log_assert "Destroying top level filesystem with reservation allows more " \
+    "data to be written to another top level filesystem"
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTFS1 && \
+           log_must $ZFS destroy $TESTPOOL/$TESTFS1
+
+       [[ -e $TESTDIR/$TESTFILE1 ]] && log_must $RM -rf $TESTDIR/$TESTFILE1
+       [[ -e $TESTDIR/$TESTFILE2 ]] && log_must $RM -rf $TESTDIR/$TESTFILE2
+}
+
+log_onexit cleanup
+
+log_must $ZFS create $TESTPOOL/$TESTFS1
+
+space_avail=`get_prop available $TESTPOOL`
+
+#
+# To make sure this test doesn't take too long to execute on
+# large pools, we calculate a reservation setting which when
+# applied to the dataset filesystem  will ensure we have
+# RESV_FREE_SPACE left free in the pool.
+#
+((resv_size_set = space_avail - RESV_FREE_SPACE))
+
+log_must $ZFS set reservation=$resv_size_set $TESTPOOL/$TESTFS1
+
+space_avail_still=`get_prop available $TESTPOOL`
+
+fill_size=`expr $space_avail_still + $RESV_TOLERANCE`
+write_count=`expr $fill_size / $BLOCK_SIZE`
+
+# Now fill up the filesystem (which doesn't have a reservation set
+# and thus will use up whatever free space is left in the pool).
+$FILE_WRITE -o create -f $TESTDIR/$TESTFILE1 -b $BLOCK_SIZE -c $write_count -d 0
+ret=$?
+if (($ret != $ENOSPC)); then
+       log_fail "Did not get ENOSPC as expected (got $ret)."
+fi
+
+log_must $ZFS destroy -f $TESTPOOL/$TESTFS1
+
+log_must $FILE_WRITE -o create -f $TESTDIR/$TESTFILE2 -b $PAGESIZE \
+    -c 1000 -d 0
+
+log_pass "Destroying top level filesystem with reservation allows more data " \
+    "to be written to another top level filesystem"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_011_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_011_pos.sh
new file mode 100755 (executable)
index 0000000..1260e04
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# ZFS has two mechanisms dealing with space for datasets, namely
+# reservations and quotas. Setting one should not affect the other,
+# provided the values are legal (i.e. enough space in pool etc).
+#
+# STRATEGY:
+# 1) Create one filesystem
+# 2) Get the current quota setting
+# 3) Set a reservation
+# 4) Verify that the quota value remains unchanged
+#
+
+verify_runnable "both"
+
+log_assert "Verify reservation settings do not affect quota settings"
+
+function cleanup
+{
+       log_must zero_reservation $TESTPOOL/$TESTFS
+}
+
+log_onexit cleanup
+
+space_avail=`get_prop available $TESTPOOL`
+
+((resv_size_set = (space_avail - RESV_DELTA) / 2))
+
+fs_quota=`$ZFS get quota $TESTPOOL/$TESTFS`
+
+log_must $ZFS set reservation=$resv_size_set $TESTPOOL/$TESTFS
+
+new_fs_quota=`$ZFS get quota $TESTPOOL/$TESTFS`
+
+if [[ $fs_quota != $new_fs_quota ]]; then
+       log_fail "Quota value on $TESTFS has changed " \
+           "($fs_quota != $new_fs_quota)"
+fi
+
+log_pass "Quota settings unaffected by reservation settings"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_012_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_012_pos.sh
new file mode 100755 (executable)
index 0000000..cc412a0
--- /dev/null
@@ -0,0 +1,88 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# A reservation guarantees a certain amount of space for a dataset.
+# Nothing else which happens in the same pool should affect that
+# space, i.e. even if the rest of the pool fills up the reserved
+# space should still be accessible.
+#
+# STRATEGY:
+# 1) Create 2 filesystems
+# 2) Set a reservation on one filesystem
+# 3) Fill up the other filesystem (which does not have a reservation
+# set) until all space is consumed
+# 4) Verify can still write to the filesystem which has a reservation
+#
+
+verify_runnable "both"
+
+log_assert "Verify reservations protect space"
+
+function cleanup
+{
+       log_must $ZFS destroy -f $TESTPOOL/$TESTFS2
+       log_must zero_reservation $TESTPOOL/$TESTFS
+
+       [[ -e $TESTDIR/$TESTFILE2 ]] && log_must $RM -rf $TESTDIR/$TESTFILE2
+       [[ -d $TESTDIR2 ]] && log_must $RM -rf $TESTDIR2
+}
+
+log_onexit cleanup
+
+log_must $ZFS create $TESTPOOL/$TESTFS2
+log_must $ZFS set mountpoint=$TESTDIR2 $TESTPOOL/$TESTFS2
+
+space_avail=`get_prop available $TESTPOOL`
+
+((resv_size_set = space_avail - RESV_FREE_SPACE))
+
+log_must $ZFS set reservation=$resv_size_set $TESTPOOL/$TESTFS
+
+((write_count = (RESV_FREE_SPACE + RESV_TOLERANCE) / BLOCK_SIZE))
+
+$FILE_WRITE -o create -f $TESTDIR2/$TESTFILE1 -b $BLOCK_SIZE -c $write_count \
+    -d 0
+ret=$?
+if [[ $ret != $ENOSPC ]]; then
+       log_fail "Did not get ENOSPC (got $ret) for non-reserved filesystem"
+fi
+
+((write_count = (RESV_FREE_SPACE - RESV_TOLERANCE) / BLOCK_SIZE))
+log_must $FILE_WRITE -o create -f $TESTDIR/$TESTFILE2 -b $BLOCK_SIZE -c \
+    $write_count -d 0
+
+log_pass "Reserved space preserved correctly"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_013_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_013_pos.sh
new file mode 100755 (executable)
index 0000000..3ddd9cc
--- /dev/null
@@ -0,0 +1,112 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# Reservation properties on data objects should be preserved when the
+# pool within which they are contained is exported and then re-imported.
+#
+#
+# STRATEGY:
+# 1) Create a filesystem as dataset
+# 2) Create another filesystem at the same level
+# 3) Create a regular volume at the same level
+# 4) Create a sparse volume at the same level
+# 5) Create a filesystem within the dataset filesystem
+# 6) Set reservations on all filesystems
+# 7) Export the pool
+# 8) Re-import the pool
+# 9) Verify that the reservation settings are correct
+#
+
+verify_runnable "global"
+
+log_assert "Reservation properties preserved across exports and imports"
+
+function cleanup
+{
+       for obj in $OBJ_LIST; do
+                datasetexists $obj && log_must $ZFS destroy -f $obj
+        done
+
+       log_must zero_reservation $TESTPOOL/$TESTFS
+}
+log_onexit cleanup
+
+OBJ_LIST="$TESTPOOL/$TESTFS1/$TESTFS2 $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTVOL \
+    $TESTPOOL/$TESTVOL2"
+
+log_must $ZFS create $TESTPOOL/$TESTFS1
+log_must $ZFS create $TESTPOOL/$TESTFS1/$TESTFS2
+
+space_avail=$(get_prop available $TESTPOOL)
+[[ $? -ne 0 ]] && \
+    log_fail "Unable to get space available property for $TESTPOOL"
+
+((resv_set = space_avail / 5))
+resv_set=$(floor_volsize $resv_set)
+((sparse_vol_set_size = space_avail * 5))
+sparse_vol_set_size=$(floor_volsize $sparse_vol_set_size)
+
+# When initially created, a regular volume's reservation property is set
+# equal to its size (unlike a sparse volume), so we don't need to set it
+# explictly later on
+log_must $ZFS create -V $resv_set $TESTPOOL/$TESTVOL
+log_must $ZFS create -s -V $sparse_vol_set_size $TESTPOOL/$TESTVOL2
+
+log_must $ZFS set reservation=$resv_set $TESTPOOL/$TESTFS
+log_must $ZFS set reservation=$resv_set $TESTPOOL/$TESTFS1
+log_must $ZFS set reservation=$resv_set $TESTPOOL/$TESTFS1/$TESTFS2
+log_must $ZFS set reservation=$resv_set $TESTPOOL/$TESTVOL2
+
+log_must $ZPOOL export $TESTPOOL
+log_must $ZPOOL import $TESTPOOL
+
+for obj in $TESTPOOL/$TESTFS $OBJ_LIST; do
+
+       if [[ $obj == $TESTPOOL/$TESTVOL ]]; then
+               expected=$(volsize_to_reservation $obj $resv_set)
+               found=$(get_prop refreservation $obj)
+       else
+               expected=$resv_set
+               found=$(get_prop reservation $obj)
+       fi
+
+       [[ $found != $expected ]] && \
+           log_fail "Reservation property for $obj incorrect. Expected " \
+           "$expected but got $found."
+done
+
+log_pass "Reservation properties preserved across exports and imports"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_014_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_014_pos.sh
new file mode 100755 (executable)
index 0000000..dbc6889
--- /dev/null
@@ -0,0 +1,123 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# A reservation cannot exceed the quota on a dataset
+#
+# STRATEGY:
+# 1) Create a filesystem and volume
+# 2) Set a quota on the filesystem
+# 3) Attempt to set a reservation larger than the quota. Verify
+# that the attempt fails.
+# 4) Repeat 2-3 for volume
+#
+
+verify_runnable "both"
+
+log_assert "Verify cannot set reservation larger than quota"
+
+function cleanup
+{
+       #
+       # Note we don't destroy $TESTFS as it's used by other tests
+       for obj in $OBJ_LIST ; do
+               datasetexists $obj && log_must $ZFS destroy -f $obj
+       done
+
+       log_must zero_reservation $TESTPOOL/$TESTFS
+}
+log_onexit cleanup
+
+space_avail=`get_prop available $TESTPOOL`
+
+if ! is_global_zone ; then
+       OBJ_LIST=""
+else
+       OBJ_LIST="$TESTPOOL/$TESTVOL $TESTPOOL/$TESTVOL2"
+
+        ((vol_set_size = space_avail / 4))
+       vol_set_size=$(floor_volsize $vol_set_size)
+       ((sparse_vol_set_size = space_avail * 4))
+       sparse_vol_set_size=$(floor_volsize $sparse_vol_set_size)
+
+       log_must $ZFS create -V $vol_set_size $TESTPOOL/$TESTVOL
+       log_must $ZFS create -s -V $sparse_vol_set_size $TESTPOOL/$TESTVOL2
+fi
+
+for obj in $TESTPOOL/$TESTFS $OBJ_LIST ; do
+
+       space_avail=`get_prop available $TESTPOOL`
+       ((quota_set_size = space_avail / 3))
+
+       #
+       # A regular (non-sparse) volume's size is effectively
+       # its quota so only need to explicitly set quotas for
+       # filesystems and datasets.
+       #
+       # A volumes size is effectively its quota. The maximum
+       # reservation value that can be set on a volume is
+       # determined by the size of the volume or the amount of
+       # space in the pool, whichever is smaller.
+       #
+       if [[ $obj == $TESTPOOL/$TESTFS ]]; then
+               log_must $ZFS set quota=$quota_set_size $obj
+               ((resv_set_size = quota_set_size + RESV_SIZE))
+
+       elif [[ $obj == $TESTPOOL/$TESTVOL2 ]] ; then
+
+               ((resv_set_size = sparse_vol_set_size + RESV_SIZE))
+
+       elif [[ $obj == $TESTPOOL/$TESTVOL ]] ; then
+
+               ((resv_set_size = vol_set_size + RESV_SIZE))
+       fi
+
+       orig_quota=`get_prop quota $obj`
+
+       log_mustnot $ZFS set reservation=$resv_set_size $obj
+       new_quota=`get_prop quota $obj`
+
+       if [[ $orig_quota != $new_quota ]]; then
+               log_fail "Quota value changed from $orig_quota " \
+                               "to $new_quota"
+       fi
+
+       if [[ $obj == $TESTPOOL/$TESTFS ]]; then
+               log_must $ZFS set quota=none $obj
+       fi
+done
+
+log_pass "As expected cannot set reservation larger than quota"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_015_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_015_pos.sh
new file mode 100755 (executable)
index 0000000..c8779a4
--- /dev/null
@@ -0,0 +1,99 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# In pool with a full filesystem and a regular volume with an implicit
+# reservation, setting the reservation on the volume to 'none' should allow
+# more data to be written to the filesystem.
+#
+#
+# STRATEGY:
+# 1) Create a regular non-sparse volume (which implicitly sets the reservation
+#    property to a value equal to the volume size)
+# 2) Create a filesystem at the same level
+# 3) Fill up the filesystem
+# 4) Set the reservation on the volume to 'none'
+# 5) Verify can write more data to the filesystem
+#
+
+verify_runnable "global"
+
+log_assert "Setting volume reservation to 'none' allows more data to be " \
+    "written to top level filesystem"
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTVOL && \
+       log_must $ZFS destroy $TESTPOOL/$TESTVOL
+
+       [[ -e $TESTDIR/$TESTFILE1 ]] && log_must $RM -rf $TESTDIR/$TESTFILE1
+       [[ -e $TESTDIR/$TESTFILE2 ]] && log_must $RM -rf $TESTDIR/$TESTFILE2
+}
+log_onexit cleanup
+
+space_avail=$(largest_volsize_from_pool $TESTPOOL)
+
+#
+# To make sure this test doesn't take too long to execute on
+# large pools, we calculate a volume size which when applied
+# to the volume will ensure we have RESV_FREE_SPACE
+# left free in the pool which we can quickly fill.
+#
+((resv_size_set = space_avail - RESV_FREE_SPACE))
+resv_size_set=$(floor_volsize $resv_size_set)
+
+log_must $ZFS create -V $resv_size_set $TESTPOOL/$TESTVOL
+
+space_avail_still=`get_prop available $TESTPOOL`
+
+fill_size=$((space_avail_still + $RESV_TOLERANCE))
+write_count=$((fill_size / BLOCK_SIZE))
+
+# Now fill up the filesystem (which doesn't have a reservation set
+# and thus will use up whatever free space is left in the pool).
+$FILE_WRITE -o create -f $TESTDIR/$TESTFILE1 -b $BLOCK_SIZE -c $write_count -d 0
+ret=$?
+if (($ret != $ENOSPC)); then
+       log_fail "Did not get ENOSPC as expected (got $ret)."
+fi
+
+log_must $ZFS set refreservation=none $TESTPOOL/$TESTVOL
+
+log_must $FILE_WRITE -o create -f $TESTDIR/$TESTFILE2 -b $PAGESIZE \
+    -c 1000 -d 0
+
+log_pass "Setting top level volume reservation to 'none' allows more " \
+    "data to be written to the top level filesystem"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_016_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_016_pos.sh
new file mode 100755 (executable)
index 0000000..04c0165
--- /dev/null
@@ -0,0 +1,98 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# In pool with a full filesystem and a regular volume (with implicit
+# reservation) destroying the volume should allow more data to be written
+# to the filesystem
+#
+#
+# STRATEGY:
+# 1) Create a regular (non-sparse) volume
+# 2) Create a filesystem at the same level
+# 3) Fill up the filesystem
+# 4) Destroy the volume
+# 5) Verify can write more data to the filesystem
+#
+
+verify_runnable "global"
+
+log_assert "Destroying a regular volume with reservation allows more data to" \
+    " be written to top level filesystem"
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$TESTVOL && \
+           log_must $ZFS destroy $TESTPOOL/$TESTVOL
+
+       [[ -e $TESTDIR/$TESTFILE1 ]] && log_must $RM -rf $TESTDIR/$TESTFILE1
+       [[ -e $TESTDIR/$TESTFILE2 ]] && log_must $RM -rf $TESTDIR/$TESTFILE2
+}
+log_onexit cleanup
+
+space_avail=$(largest_volsize_from_pool $TESTPOOL)
+
+#
+# To make sure this test doesn't take too long to execute on
+# large pools, we calculate a volume size which will ensure we
+# have RESV_FREE_SPACE left free in the pool.
+#
+((vol_set_size = space_avail - RESV_FREE_SPACE))
+vol_set_size=$(floor_volsize $vol_set_size)
+
+# Creating a regular volume implicitly sets its reservation
+# property to the same value.
+log_must $ZFS create -V $vol_set_size $TESTPOOL/$TESTVOL
+
+space_avail_still=$(get_prop available $TESTPOOL)
+fill_size=$((space_avail_still + $RESV_TOLERANCE))
+write_count=$((fill_size / BLOCK_SIZE))
+
+# Now fill up the filesystem (which doesn't have a reservation set
+# and thus will use up whatever free space is left in the pool).
+$FILE_WRITE -o create -f $TESTDIR/$TESTFILE1 -b $BLOCK_SIZE -c $write_count -d 0
+ret=$?
+if (($ret != $ENOSPC)); then
+       log_fail "Did not get ENOSPC as expected (got $ret)."
+fi
+
+log_must $ZFS destroy -f $TESTPOOL/$TESTVOL
+
+log_must $FILE_WRITE -o create -f $TESTDIR/$TESTFILE2 -b $PAGESIZE \
+    -c 1000 -d 0
+
+log_pass "Destroying volume with reservation allows more data to be written " \
+    "to top level filesystem"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_017_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_017_pos.sh
new file mode 100755 (executable)
index 0000000..b0a5f45
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# For a sparse volume changes to the volsize are not reflected in the
+# reservation.
+#
+# STRATEGY:
+# 1) Create a regular and sparse volume
+# 2) Get the space available in the pool
+# 3) Set reservation with various sizes on the regular and sparse volumes
+# 4) Verify that the 'reservation' property for the regular volume has
+#    the correct value.
+# 5) Verify that the 'reservation' property for the sparse volume is set to
+#    'none'
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset vol
+
+       for vol in $regvol $sparsevol; do
+               datasetexists $vol &&  log_must $ZFS destroy $vol
+       done
+}
+log_onexit cleanup
+
+log_assert "Verify that the volsize changes of sparse volumes are not " \
+    "reflected in the reservation."
+log_onexit cleanup
+
+# Create a regular and sparse volume for testing.
+regvol=$TESTPOOL/$TESTVOL
+sparsevol=$TESTPOOL/$TESTVOL2
+log_must $ZFS create -V 64M $regvol
+log_must $ZFS create -s -V 64M $sparsevol
+
+typeset -i vsize=$(get_prop available $TESTPOOL)
+typeset -i iterate=10
+typeset -i regreserv
+typeset -i sparsereserv
+typeset -i volblocksize=$(get_prop volblocksize $regvol)
+typeset -i blknum=0
+typeset -i randomblknum
+((blknum = vsize / volblocksize))
+
+while ((iterate > 1)); do
+       ((randomblknum = 1 + RANDOM % blknum))
+       # Make sure volsize is a multiple of volume block size
+       ((vsize = randomblknum * volblocksize))
+       log_must $ZFS set volsize=$vsize $regvol
+       log_must $ZFS set volsize=$vsize $sparsevol
+       vsize=$(volsize_to_reservation $regvol $vsize)
+       regreserv=$(get_prop refreservation $regvol)
+       sparsereserv=$(get_prop reservation $sparsevol)
+       ((sparsereserv == vsize)) && \
+               log_fail "volsize changes of sparse volume is reflected in " \
+                   "reservation (expected $vsize, got $sparsereserv)."
+       ((regreserv != vsize)) && \
+               log_fail "volsize changes of regular volume is not reflected " \
+                   "in reservation (expected $vsize, got $regreserv)."
+       ((iterate = iterate - 1))
+done
+
+log_pass "The volsize changes of sparse volumes are not reflected in the " \
+    "reservation"
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/reservation_018_pos.sh b/zfs/tests/zfs-tests/tests/functional/reservation/reservation_018_pos.sh
new file mode 100755 (executable)
index 0000000..9236fd0
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/reservation/reservation.shlib
+
+#
+# DESCRIPTION:
+#
+# Verify that reservation doesn't inherit its value from parent.
+#
+# STRATEGY:
+# 1) Create a filesystem tree
+# 2) Set reservation for parents
+# 3) Verify that the 'reservation' for descendent doesnot inherit the value.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $fs_child && log_must $ZFS destroy $fs_child
+       log_must $ZFS set reservation=$reserv_val $fs
+}
+
+log_onexit cleanup
+
+log_assert "Verify that reservation doesnot inherit its value from parent."
+
+fs=$TESTPOOL/$TESTFS
+fs_child=$TESTPOOL/$TESTFS/$TESTFS
+
+space_avail=$(get_prop available $fs)
+reserv_val=$(get_prop reservation $fs)
+typeset -l reservsize=$space_avail
+((reservsize = reservsize / 2))
+log_must $ZFS set reservation=$reservsize $fs
+
+log_must $ZFS create $fs_child
+rsv_space=$(get_prop reservation $fs_child)
+[[ $rsv_space == $reservsize ]] && \
+    log_fail "The reservation of child dataset inherits its value from parent."
+
+log_pass "reservation doesnot inherit its value from parent as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/reservation/setup.ksh b/zfs/tests/zfs-tests/tests/functional/reservation/setup.ksh
new file mode 100755 (executable)
index 0000000..c390347
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_setup_noexit ${DISKS%% *}
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/rootpool/Makefile.am b/zfs/tests/zfs-tests/tests/functional/rootpool/Makefile.am
new file mode 100644 (file)
index 0000000..9800fa0
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/rootpool
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       rootpool_002_neg.ksh \
+       rootpool_003_neg.ksh \
+       rootpool_007_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/rootpool/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/rootpool/cleanup.ksh
new file mode 100755 (executable)
index 0000000..8f04325
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_002_neg.ksh
new file mode 100755 (executable)
index 0000000..1c66669
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# the zfs rootpool can not be destroyed
+#
+# STRATEGY:
+# 1) check if the current system is installed as zfs root
+# 2) get the rootpool
+# 3) try to destroy the rootpool, which should fail.
+# 4) try to destroy the rootpool filesystem, which should fail.
+#
+
+verify_runnable "global"
+log_assert "zpool/zfs destory <rootpool> should return error"
+
+typeset rootpool=$(get_rootpool)
+typeset tmpfile="/tmp/mounted-datasets.$$"
+
+# Collect the currently mounted ZFS filesystems, so that we can repair any
+# damage done by the attempted pool destroy. The destroy itself should fail, but
+# some filesystems can become unmounted in the process, and aren't automatically
+# remounted.
+$MOUNT -p | $AWK '{if ($4 == "zfs") print $1" "$3}' > $tmpfile
+
+log_mustnot $ZPOOL destroy $rootpool
+
+# Remount any filesystems that the destroy attempt unmounted.
+while read ds mntpt; do
+       mounted $ds || log_must $MOUNT -Fzfs $ds $mntpt
+done < $tmpfile
+$RM -f $tmpfile
+
+log_mustnot $ZFS destroy $rootpool
+
+log_pass "rootpool can not be destroyed"
diff --git a/zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_003_neg.ksh
new file mode 100755 (executable)
index 0000000..469e7ad
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+#  system related filesystems can not be renamed or destroyed
+#
+# STRATEGY:
+#
+# 1) check if the current system is installed as zfs rootfs
+# 2) get the rootfs
+# 3) try to rename the rootfs to some newfs, which should fail.
+# 4) try to destroy the rootfs, which should fail.
+# 5) try to destroy the rootfs with -f which should fail
+# 6) try to destroy the rootfs with -fR which should fail
+#
+
+verify_runnable "global"
+log_assert "system related filesytems can not be renamed or destroyed"
+
+typeset rootpool=$(get_rootpool)
+typeset rootfs=$(get_rootfs)
+
+log_mustnot $ZFS rename $rootfs $rootpool/newfs
+log_mustnot $ZFS rename -f $rootfs $rootpool/newfs
+
+log_mustnot $ZFS destroy $rootfs
+log_mustnot $ZFS destroy -f $rootfs
+
+log_pass "system related filesystems can not be renamed or destroyed"
diff --git a/zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/rootpool/rootpool_007_neg.ksh
new file mode 100755 (executable)
index 0000000..4f715d5
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# the zfs rootfilesystem's compression property can not set to gzip[1-9]
+#
+# STRATEGY:
+# 1) check if the current system is installed as zfs root
+# 2) get the rootfs
+# 3) set the rootfs's compression to gzip 1-9 which should fail.
+#
+
+verify_runnable "global"
+
+function cleanup {
+       log_must $ZFS set compression=$orig_compress $rootfs
+}
+
+log_onexit cleanup
+log_assert $assert_msg
+
+typeset rootpool=$(get_rootpool)
+typeset rootfs=$(get_pool_prop bootfs $rootpool)
+typeset orig_compress=$(get_prop compression $rootfs)
+
+typeset assert_msg="the zfs rootfs's compression property can not set to \
+                  gzip and gzip[1-9]"
+
+set -A gtype "gzip" "gzip-1" "gzip-2" "gzip-3" "gzip-4" "gzip-5" \
+            "gzip-6" "gzip-7" "gzip-8" "gzip-9"
+
+typeset -i i=0
+while (( i < ${#gtype[@]} )); do
+       log_mustnot $ZFS set compression=${gtype[i]} $rootfs
+       (( i += 1 ))
+done
+
+log_pass $assert_msg
diff --git a/zfs/tests/zfs-tests/tests/functional/rootpool/setup.ksh b/zfs/tests/zfs-tests/tests/functional/rootpool/setup.ksh
new file mode 100755 (executable)
index 0000000..a5baac5
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/Makefile.am b/zfs/tests/zfs-tests/tests/functional/rsend/Makefile.am
new file mode 100644 (file)
index 0000000..6be0000
--- /dev/null
@@ -0,0 +1,25 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/rsend
+dist_pkgdata_SCRIPTS = \
+       rsend.cfg \
+       rsend.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       rsend_001_pos.ksh \
+       rsend_002_pos.ksh \
+       rsend_003_pos.ksh \
+       rsend_004_pos.ksh \
+       rsend_005_pos.ksh \
+       rsend_006_pos.ksh \
+       rsend_007_pos.ksh \
+       rsend_008_pos.ksh \
+       rsend_009_pos.ksh \
+       rsend_010_pos.ksh \
+       rsend_011_pos.ksh \
+       rsend_012_pos.ksh \
+       rsend_013_pos.ksh \
+       rsend_014_pos.ksh \
+       rsend_019_pos.ksh \
+       rsend_020_pos.ksh \
+       rsend_021_pos.ksh \
+       rsend_022_pos.ksh \
+       rsend_024_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/cleanup.ksh
new file mode 100755 (executable)
index 0000000..6787660
--- /dev/null
@@ -0,0 +1,45 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+verify_runnable "both"
+
+if is_global_zone ; then
+       destroy_pool $POOL
+       destroy_pool $POOL2
+else
+       cleanup_pool $POOL
+       cleanup_pool $POOL2
+fi
+log_must $RM -rf $BACKDIR $TESTDIR
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend.cfg b/zfs/tests/zfs-tests/tests/functional/rsend/rsend.cfg
new file mode 100644 (file)
index 0000000..29aede5
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+export BACKDIR=${TEST_BASE_DIR%%/}/backdir-rsend
+
+export DISK1=${DISKS%% *}
+export DISK2=$($ECHO $DISKS | $AWK '{print $2}')
+
+export POOL=$TESTPOOL
+export POOL2=$TESTPOOL1
+export FS=$TESTFS
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend.kshlib b/zfs/tests/zfs-tests/tests/functional/rsend/rsend.kshlib
new file mode 100644 (file)
index 0000000..4cdf6b7
--- /dev/null
@@ -0,0 +1,553 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013, 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.cfg
+
+#
+# Set up test model which includes various datasets
+#
+#               @final
+#               @snapB
+#               @init
+#               |
+#   ______ pclone
+#  |      /
+#  |@psnap
+#  ||                         @final
+#  ||@final       @final      @snapC
+#  ||@snapC       @snapC      @snapB
+#  ||@snapA       @snapB      @snapA
+#  ||@init        @init       @init
+#  |||            |           |
+# $pool -------- $FS ------- fs1 ------- fs2
+#    \             \\_____     \          |
+#     vol           vol   \____ \         @fsnap
+#      |              |        \ \              \
+#      @init          @vsnap   |  ------------ fclone
+#      @snapA         @init \  |                    |
+#      @final         @snapB \ |                    @init
+#                     @snapC  vclone                @snapA
+#                     @final       |                @final
+#                                 @init
+#                                 @snapC
+#                                 @final
+#
+# $1 pool name
+#
+function setup_test_model
+{
+       typeset pool=$1
+
+       log_must $ZFS create -p $pool/$FS/fs1/fs2
+
+       log_must $ZFS snapshot $pool@psnap
+       log_must $ZFS clone $pool@psnap $pool/pclone
+
+       if is_global_zone ; then
+               log_must $ZFS create -V 16M $pool/vol
+               log_must $ZFS create -V 16M $pool/$FS/vol
+               block_device_wait
+
+               log_must $ZFS snapshot $pool/$FS/vol@vsnap
+               log_must $ZFS clone $pool/$FS/vol@vsnap $pool/$FS/vclone
+               block_device_wait
+       fi
+
+       log_must snapshot_tree $pool/$FS/fs1/fs2@fsnap
+       log_must $ZFS clone $pool/$FS/fs1/fs2@fsnap $pool/$FS/fs1/fclone
+       log_must $ZFS snapshot -r $pool@init
+
+       log_must snapshot_tree $pool@snapA
+       log_must snapshot_tree $pool@snapC
+       log_must snapshot_tree $pool/pclone@snapB
+       log_must snapshot_tree $pool/$FS@snapB
+       log_must snapshot_tree $pool/$FS@snapC
+       log_must snapshot_tree $pool/$FS/fs1@snapA
+       log_must snapshot_tree $pool/$FS/fs1@snapB
+       log_must snapshot_tree $pool/$FS/fs1@snapC
+       log_must snapshot_tree $pool/$FS/fs1/fclone@snapA
+
+       if is_global_zone ; then
+               log_must $ZFS snapshot $pool/vol@snapA
+               log_must $ZFS snapshot $pool/$FS/vol@snapB
+               log_must $ZFS snapshot $pool/$FS/vol@snapC
+               log_must $ZFS snapshot $pool/$FS/vclone@snapC
+       fi
+
+       log_must $ZFS snapshot -r $pool@final
+
+       return 0
+}
+
+#
+# Cleanup the BACKDIR and given pool content and all the sub datasets
+#
+# $1 pool name
+#
+function cleanup_pool
+{
+       typeset pool=$1
+       log_must $RM -rf $BACKDIR/*
+
+       if is_global_zone ; then
+               log_must $ZFS destroy -Rf $pool
+       else
+               typeset list=$($ZFS list -H -r -t filesystem,snapshot,volume -o name $pool)
+               for ds in $list ; do
+                       if [[ $ds != $pool ]] ; then
+                               if datasetexists $ds ; then
+                                       log_must $ZFS destroy -Rf $ds
+                               fi
+                       fi
+               done
+       fi
+
+       typeset mntpnt=$(get_prop mountpoint $pool)
+       if ! ismounted $pool ; then
+               # Make sure mountpoint directory is empty
+               if [[ -d $mntpnt ]]; then
+                       log_must $RM -rf $mntpnt/*
+               fi
+
+               log_must $ZFS mount $pool
+       fi
+       if [[ -d $mntpnt ]]; then
+               log_must $RM -rf $mntpnt/*
+       fi
+
+       return 0
+}
+
+#
+# Detect if the given two filesystems have same sub-datasets
+#
+# $1 source filesystem
+# $2 destination filesystem
+#
+function cmp_ds_subs
+{
+       typeset src_fs=$1
+       typeset dst_fs=$2
+
+       $ZFS list -r -H -t filesystem,snapshot,volume -o name $src_fs > $BACKDIR/src1
+       $ZFS list -r -H -t filesystem,snapshot,volume -o name $dst_fs > $BACKDIR/dst1
+
+       eval $SED -e 's:^$src_fs:PREFIX:g' < $BACKDIR/src1 > $BACKDIR/src
+       eval $SED -e 's:^$dst_fs:PREFIX:g' < $BACKDIR/dst1 > $BACKDIR/dst
+
+       $DIFF $BACKDIR/src $BACKDIR/dst
+       typeset -i ret=$?
+
+       $RM -f $BACKDIR/src $BACKDIR/dst $BACKDIR/src1 $BACKDIR/dst1
+
+       return $ret
+}
+
+#
+# Compare all the directores and files in two filesystems
+#
+# $1 source filesystem
+# $2 destination filesystem
+#
+function cmp_ds_cont
+{
+       typeset src_fs=$1
+       typeset dst_fs=$2
+
+       typeset srcdir dstdir
+       srcdir=$(get_prop mountpoint $src_fs)
+       dstdir=$(get_prop mountpoint $dst_fs)
+
+       $DIFF -r $srcdir $dstdir > /dev/null 2>&1
+       echo $?
+}
+
+#
+# Compare the given two dataset properties
+#
+# $1 dataset 1
+# $2 dataset 2
+#
+function cmp_ds_prop
+{
+       typeset dtst1=$1
+       typeset dtst2=$2
+
+       for item in "type" "origin" "volblocksize" "aclinherit" "acltype" \
+           "atime" "canmount" "checksum" "compression" "copies" "devices" \
+           "dnodesize" "exec" "quota" "readonly" "recordsize" "reservation" \
+           "setuid" "snapdir" "version" "volsize" "xattr" "zoned" \
+           "mountpoint";
+       do
+               $ZFS get -H -o property,value,source $item $dtst1 >> \
+                   $BACKDIR/dtst1
+               $ZFS get -H -o property,value,source $item $dtst2 >> \
+                   $BACKDIR/dtst2
+       done
+
+       eval $SED -e 's:$dtst1:PREFIX:g' < $BACKDIR/dtst1 > $BACKDIR/dtst1
+       eval $SED -e 's:$dtst2:PREFIX:g' < $BACKDIR/dtst2 > $BACKDIR/dtst2
+
+       $DIFF $BACKDIR/dtst1 $BACKDIR/dtst2
+       typeset -i ret=$?
+
+       $RM -f $BACKDIR/dtst1 $BACKDIR/dtst2
+
+       return $ret
+
+}
+
+#
+# Random create directories and files
+#
+# $1 directory
+#
+function random_tree
+{
+       typeset dir=$1
+
+       if [[ -d $dir ]]; then
+               $RM -rf $dir
+       fi
+       $MKDIR -p $dir
+       typeset -i ret=$?
+
+       typeset -i nl nd nf
+       ((nl = RANDOM % 6 + 1))
+       ((nd = RANDOM % 3 ))
+       ((nf = RANDOM % 5 ))
+       $MKTREE -b $dir -l $nl -d $nd -f $nf
+       ((ret |= $?))
+
+       return $ret
+}
+
+#
+# Put data in filesystem and take snapshot
+#
+# $1 snapshot name
+#
+function snapshot_tree
+{
+       typeset snap=$1
+       typeset ds=${snap%%@*}
+       typeset type=$(get_prop "type" $ds)
+
+       typeset -i ret=0
+       if [[ $type == "filesystem" ]]; then
+               typeset mntpnt=$(get_prop mountpoint $ds)
+               ((ret |= $?))
+
+               if ((ret == 0)) ; then
+                       eval random_tree $mntpnt/${snap##$ds}
+                       ((ret |= $?))
+               fi
+       fi
+
+       if ((ret == 0)) ; then
+               $ZFS snapshot $snap
+               ((ret |= $?))
+       fi
+
+       return $ret
+}
+
+#
+# Destroy the given snapshot and stuff
+#
+# $1 snapshot
+#
+function destroy_tree
+{
+       typeset -i ret=0
+       typeset snap
+       for snap in "$@" ; do
+               $ZFS destroy $snap
+               ret=$?
+
+               typeset ds=${snap%%@*}
+               typeset type=$(get_prop "type" $ds)
+               if [[ $type == "filesystem" ]]; then
+                       typeset mntpnt=$(get_prop mountpoint $ds)
+                       ((ret |= $?))
+
+                       if ((ret != 0)); then
+                               $RM -r $mntpnt/$snap
+                               ((ret |= $?))
+                       fi
+               fi
+
+               if ((ret != 0)); then
+                       return $ret
+               fi
+       done
+
+       return 0
+}
+
+#
+# Get all the sub-datasets of give dataset with specific suffix
+#
+# $1 Given dataset
+# $2 Suffix
+#
+function getds_with_suffix
+{
+       typeset ds=$1
+       typeset suffix=$2
+
+       typeset list=$($ZFS list -r -H -t filesystem,snapshot,volume -o name $ds \
+           | $GREP "$suffix$")
+
+       $ECHO $list
+}
+
+#
+# Output inherited properties whitch is edited for file system
+#
+function fs_inherit_prop
+{
+       typeset fs_prop
+       if is_global_zone ; then
+               fs_prop=$($ZFS inherit 2>&1 | \
+                   $AWK '$2=="YES" && $3=="YES" {print $1}')
+               if ! is_te_enabled ; then
+                       fs_prop=$(echo $fs_prop | $GREP -v "mlslabel")
+               fi
+       else
+               fs_prop=$($ZFS inherit 2>&1 | \
+                   $AWK '$2=="YES" && $3=="YES" {print $1}'|
+                   $EGREP -v "devices|mlslabel|sharenfs|sharesmb|zoned")
+       fi
+
+       $ECHO $fs_prop
+}
+
+#
+# Output inherited properties for volume
+#
+function vol_inherit_prop
+{
+       $ECHO "checksum readonly"
+}
+
+#
+# Get the destination dataset to compare
+#
+function get_dst_ds
+{
+       typeset srcfs=$1
+       typeset dstfs=$2
+
+       #
+       # If the srcfs is not pool
+       #
+       if ! $ZPOOL list $srcfs > /dev/null 2>&1 ; then
+               eval dstfs="$dstfs/${srcfs#*/}"
+       fi
+
+       $ECHO $dstfs
+}
+
+#
+# Make test files
+#
+# $1 Number of files to create
+# $2 Maximum file size
+# $3 File ID offset
+# $4 File system to create the files on
+#
+function mk_files
+{
+       nfiles=$1
+       maxsize=$2
+       file_id_offset=$3
+       fs=$4
+
+       for ((i=0; i<$nfiles; i=i+1)); do
+               $DD if=/dev/urandom \
+                   of=/$fs/file-$maxsize-$((i+$file_id_offset)) \
+                   bs=$((($RANDOM * $RANDOM % ($maxsize - 1)) + 1)) \
+                   count=1 >/dev/null 2>&1 || log_fail \
+                   "Failed to create /$fs/file-$maxsize-$((i+$file_id_offset))"
+       done
+       $ECHO Created $nfiles files of random sizes up to $maxsize bytes
+}
+
+#
+# Remove test files
+#
+# $1 Number of files to remove
+# $2 Maximum file size
+# $3 File ID offset
+# $4 File system to remove the files from
+#
+function rm_files
+{
+       nfiles=$1
+       maxsize=$2
+       file_id_offset=$3
+       fs=$4
+
+       for ((i=0; i<$nfiles; i=i+1)); do
+               $RM -f /$fs/file-$maxsize-$((i+$file_id_offset))
+       done
+       $ECHO Removed $nfiles files of random sizes up to $maxsize bytes
+}
+
+#
+# Mess up file contents
+#
+# $1 The file path
+#
+function mess_file
+{
+       file=$1
+
+       filesize=$($STAT -c '%s' $file)
+       offset=$(($RANDOM * $RANDOM % $filesize))
+       if (($RANDOM % 7 <= 1)); then
+               #
+               # We corrupt 2 bytes to minimize the chance that we
+               # write the same value that's already there.
+               #
+               log_must eval "$DD if=/dev/urandom of=$file conv=notrunc " \
+                   "bs=1 count=2 seek=$offset >/dev/null 2>&1"
+       else
+               log_must $TRUNCATE -s $offset $file
+       fi
+}
+
+#
+# Diff the send/receive filesystems
+#
+# $1 The sent filesystem
+# $2 The received filesystem
+#
+function file_check
+{
+       sendfs=$1
+       recvfs=$2
+
+       if [[ -d /$recvfs/.zfs/snapshot/a && -d \
+           /$sendfs/.zfs/snapshot/a ]]; then
+               $DIFF -r /$recvfs/.zfs/snapshot/a /$sendfs/.zfs/snapshot/a
+               [[ $? -eq 0 ]] || log_fail "Differences found in snap a"
+       fi
+       if [[ -d /$recvfs/.zfs/snapshot/b && -d \
+           /$sendfs/.zfs/snapshot/b ]]; then
+               $DIFF -r /$recvfs/.zfs/snapshot/b /$sendfs/.zfs/snapshot/b
+               [[ $? -eq 0 ]] || log_fail "Differences found in snap b"
+       fi
+}
+
+#
+# Resume test helper
+#
+# $1 The ZFS send command
+# $2 The filesystem where the streams are sent
+# $3 The receive filesystem
+#
+function resume_test
+{
+       sendcmd=$1
+       streamfs=$2
+       recvfs=$3
+
+       stream_num=1
+       log_must eval "$sendcmd >/$streamfs/$stream_num"
+
+       for ((i=0; i<2; i=i+1)); do
+               mess_file /$streamfs/$stream_num
+               log_mustnot $ZFS recv -sv $recvfs </$streamfs/$stream_num
+               stream_num=$((stream_num+1))
+
+               token=$($ZFS get -Hp -o value receive_resume_token $recvfs)
+               log_must eval "$ZFS send -v -t $token >/$streamfs/$stream_num"
+               [[ -f /$streamfs/$stream_num ]] || \
+                   log_fail "NO FILE /$streamfs/$stream_num"
+       done
+       log_must $ZFS recv -sv $recvfs </$streamfs/$stream_num
+}
+
+#
+# Setup filesystems for the resumable send/receive tests
+#
+# $1 The pool to set up with the "send" filesystems
+# $2 The pool for receive
+#
+function test_fs_setup
+{
+       sendpool=$1
+       recvpool=$2
+
+       sendfs=$sendpool/sendfs
+       recvfs=$recvpool/recvfs
+       streamfs=$sendpool/stream
+
+       if datasetexists $recvfs; then
+               log_must $ZFS destroy -r $recvfs
+       fi
+       if datasetexists $sendfs; then
+               log_must $ZFS destroy -r $sendfs
+       fi
+       if $($ZFS create -o compress=lz4 $sendfs); then
+               mk_files 1000 256 0 $sendfs &
+               mk_files 1000 131072 0 $sendfs &
+               mk_files 100 1048576 0 $sendfs &
+               mk_files 10 10485760 0 $sendfs &
+               mk_files 1 104857600 0 $sendfs &
+               wait
+               log_must $ZFS snapshot $sendfs@a
+
+               rm_files 200 256 0 $sendfs &
+               rm_files 200 131072 0 $sendfs &
+               rm_files 20 1048576 0 $sendfs &
+               rm_files 2 10485760 0 $sendfs &
+               wait
+
+               mk_files 400 256 0 $sendfs &
+               mk_files 400 131072 0 $sendfs &
+               mk_files 40 1048576 0 $sendfs &
+               mk_files 4 10485760 0 $sendfs &
+               wait
+
+               log_must $ZFS snapshot $sendfs@b
+               log_must eval "$ZFS send -v $sendfs@a >/$sendpool/initial.zsend"
+               log_must eval "$ZFS send -v -i @a $sendfs@b " \
+                   ">/$sendpool/incremental.zsend"
+       fi
+
+       if datasetexists $streamfs; then
+               log_must $ZFS destroy -r $streamfs
+       fi
+       log_must $ZFS create -o compress=lz4 $sendpool/stream
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_001_pos.ksh
new file mode 100755 (executable)
index 0000000..6087dd3
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      zfs send -R send replication stream up to the named snap.
+#
+# STRATEGY:
+#      1. Back up all the data from POOL/FS
+#      2. Verify all the datasets and data can be recovered in POOL2
+#      3. Back up all the data from root filesystem POOL2
+#      4. Verify all the data can be recovered, too
+#
+
+verify_runnable "both"
+
+log_assert "zfs send -R send replication stream up to the named snap."
+log_onexit cleanup_pool $POOL2
+
+#
+# Verify the entire pool and sub-ds can be backup and restored.
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-final-R"
+
+dstds=$(get_dst_ds $POOL $POOL2)
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+# Cleanup POOL2
+log_must cleanup_pool $POOL2
+
+#
+# Verify all the filesystem and sub-fs can be backup and restored.
+#
+log_must eval "$ZFS send -R $POOL/$FS@final > $BACKDIR/fs-final-R"
+log_must eval "$ZFS receive -d $POOL2 < $BACKDIR/fs-final-R"
+
+dstds=$(get_dst_ds $POOL/$FS $POOL2)
+log_must cmp_ds_subs $POOL/$FS $dstds
+log_must cmp_ds_cont $POOL/$FS $dstds
+
+log_pass "zfs send -R send replication stream up to the named snap."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_002_pos.ksh
new file mode 100755 (executable)
index 0000000..9a495d3
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      zfs send -I sends all incrementals from fs@init to fs@final.
+#
+# STRATEGY:
+#      1. Create several snapshots in pool2
+#      2. Send -I @snapA @final
+#      3. Destroy all the snapshot except @snapA
+#      4. Make sure all the snapshots and content are recovered
+#
+
+verify_runnable "both"
+
+log_assert "zfs send -I sends all incrementals from fs@init to fs@final."
+log_onexit cleanup_pool $POOL2
+
+#
+# Duplicate POOL2
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-R"
+
+if is_global_zone ; then
+       #
+       # Verify send -I will backup all the incrementals in pool
+       #
+       log_must eval "$ZFS send -I $POOL2@init $POOL2@final > " \
+               "$BACKDIR/pool-init-final-I"
+       log_must destroy_tree $POOL2@final $POOL2@snapC $POOL2@snapA
+       log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-init-final-I"
+       log_must cmp_ds_subs $POOL $POOL2
+       log_must cmp_ds_cont $POOL $POOL2
+fi
+
+dstds=$(get_dst_ds $POOL $POOL2)
+
+#
+# Verify send -I will backup all the incrementals in filesystem
+#
+log_must eval "$ZFS send -I @init $dstds/$FS@final > $BACKDIR/fs-init-final-I"
+log_must destroy_tree $dstds/$FS@final $dstds/$FS@snapC $dstds/$FS@snapB
+log_must eval "$ZFS receive -d -F $dstds < $BACKDIR/fs-init-final-I"
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+if is_global_zone ; then
+       #
+       # Verify send -I will backup all the incrementals in volume
+       #
+       dataset=$POOL2/$FS/vol
+       log_must eval "$ZFS send -I @vsnap $dataset@final > " \
+               "$BACKDIR/vol-vsnap-final-I"
+       log_must destroy_tree $dataset@final $dataset@snapC  \
+               $dataset@snapB $dataset@init
+       log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/vol-vsnap-final-I"
+       log_must cmp_ds_subs $POOL $POOL2
+       log_must cmp_ds_cont $POOL $POOL2
+fi
+
+log_pass "zfs send -I sends all incrementals from fs@init to fs@final."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_003_pos.ksh
new file mode 100755 (executable)
index 0000000..85d789d
--- /dev/null
@@ -0,0 +1,95 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      zfs send -I dataset@init to clone@snap can create a clone
+#
+# STRATEGY:
+#      1. Setup test model
+#      2. send -I pool@init to clone@snap
+#      3. Verify the clone and snapshot can be recovered via receive
+#      4. Verify the similar operating in filesystem and volume
+#
+
+verify_runnable "both"
+
+log_assert "zfs send -I send all incrementals from dataset@init to clone@snap"
+log_onexit cleanup_pool $POOL2
+
+#
+# Duplicate POOL2
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-R"
+
+if is_global_zone ; then
+       #
+       # Verify send -I backup all incrementals from pool
+       #
+       log_must eval "$ZFS send -I $POOL2@psnap $POOL2/pclone@final > " \
+               "$BACKDIR/pool-clone-I"
+       log_must $ZFS destroy -rf $POOL2/pclone
+       log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-clone-I"
+       log_must cmp_ds_subs $POOL $POOL2
+       log_must cmp_ds_cont $POOL $POOL2
+fi
+
+dstds=$(get_dst_ds $POOL $POOL2)
+
+#
+# Verify send -I backup all incrementals from filesystem
+#
+ds=$dstds/$FS/fs1
+log_must eval "$ZFS send -I $ds/fs2@fsnap $ds/fclone@final > " \
+       "$BACKDIR/fs-clone-I"
+log_must $ZFS destroy -rf $ds/fclone
+log_must eval "$ZFS receive -F $ds/fclone < $BACKDIR/fs-clone-I"
+
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+if is_global_zone ; then
+       #
+       # Verify send -I backup all incrementals from volume
+       #
+       ds=$POOL2/$FS
+       log_must eval "$ZFS send -I $ds/vol@vsnap $ds/vclone@final > " \
+               "$BACKDIR/vol-clone-I"
+       log_must $ZFS destroy -rf $ds/vclone
+       log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/vol-clone-I"
+       log_must cmp_ds_subs $POOL $POOL2
+       log_must cmp_ds_cont $POOL $POOL2
+fi
+
+log_pass "zfs send -I send all incrementals from dataset@init to clone@snap"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_004_pos.ksh
new file mode 100755 (executable)
index 0000000..18cdac3
--- /dev/null
@@ -0,0 +1,120 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      zfs send -R -i send incremental from fs@init to fs@final.
+#
+# STRATEGY:
+#      1. Create a set of snapshots and fill with data.
+#      2. Create sub filesystems.
+#      3. Create final snapshot
+#      4. Verify zfs send -R -i will backup all the datasets which has
+#         snapshot suffix @final
+#
+
+verify_runnable "both"
+
+log_assert "zfs send -R -i send incremental from fs@init to fs@final."
+log_onexit cleanup_pool $POOL2
+
+#
+# Duplicate POOL2 for testing
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-final-R"
+
+if is_global_zone ; then
+       #
+       # Testing send -R -i backup from pool
+       #
+       srclist=$(getds_with_suffix $POOL2 @final)
+       interlist="$srclist $(getds_with_suffix $POOL2 @snapC)"
+       interlist="$interlist $(getds_with_suffix $POOL2 @snapB)"
+       interlist="$interlist $(getds_with_suffix $POOL2 @snapA)"
+
+       log_must eval "$ZFS send -R -i @init $POOL2@final > " \
+               "$BACKDIR/pool-init-final-iR"
+       log_must destroy_tree $interlist
+       log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-init-final-iR"
+
+       # Get current datasets with suffix @final
+       dstlist=$(getds_with_suffix $POOL2 @final)
+       if [[ $srclist != $dstlist ]]; then
+               log_fail "Unexpected: srclist($srclist) != dstlist($dstlist)"
+       fi
+       log_must cmp_ds_cont $POOL $POOL2
+fi
+
+dstds=$(get_dst_ds $POOL $POOL2)
+#
+# Testing send -R -i backup from filesystem
+#
+log_must eval "$ZFS send -R -i @init $dstds/$FS@final > " \
+       "$BACKDIR/fs-init-final-iR"
+
+srclist=$(getds_with_suffix $dstds/$FS @final)
+interlist="$srclist $(getds_with_suffix $dstds/$FS @snapC)"
+interlist="$interlist $(getds_with_suffix $dstds/$FS @snapB)"
+interlist="$interlist $(getds_with_suffix $dstds/$FS @snapA)"
+log_must destroy_tree $interlist
+if is_global_zone ; then
+       log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/fs-init-final-iR"
+else
+       $ZFS receive -F -d $dstds/$FS < $BACKDIR/fs-init-final-iR
+fi
+
+dstlist=$(getds_with_suffix $dstds/$FS @final)
+if [[ $srclist != $dstlist ]]; then
+       log_fail "Unexpected: srclist($srclist) != dstlist($dstlist)"
+fi
+log_must cmp_ds_cont $POOL $POOL2
+
+if is_global_zone ; then
+       #
+       # Testing send -R -i backup from volume
+       #
+       srclist=$(getds_with_suffix $POOL2/$FS/vol @final)
+       log_must eval "$ZFS send -R -i @init $POOL2/$FS/vol@final > " \
+               "$BACKDIR/vol-init-final-iR"
+       log_must destroy_tree $srclist
+       log_must eval "$ZFS receive -d $POOL2 < $BACKDIR/vol-init-final-iR"
+
+       dstlist=$(getds_with_suffix $POOL2/$FS/vol @final)
+       if [[ $srclist != $dstlist ]]; then
+               log_fail "Unexpected: srclist($srclist) != dstlist($dstlist)"
+       fi
+       log_must cmp_ds_cont $POOL $POOL2
+fi
+
+log_pass "zfs send -R -i send incremental from fs@init to fs@final."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_005_pos.ksh
new file mode 100755 (executable)
index 0000000..154072d
--- /dev/null
@@ -0,0 +1,104 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      zfs send -R -I send all the incremental between fs@init with fs@final
+#
+# STRATEGY:
+#      1. Setup test model
+#      2. Send -R -I @init @final on pool
+#      3. Destroy all the snapshots which is later than @init
+#      4. Verify receive can restore all the snapshots and data
+#      5. Do the same test on filesystem and volume
+#
+
+verify_runnable "both"
+
+log_assert "zfs send -R -I send all the incremental between @init with @final"
+log_onexit cleanup_pool $POOL2
+
+#
+# Duplicate POOL2 for testing
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-final-R"
+
+if is_global_zone ; then
+       #
+       # Testing send -R -I from pool
+       #
+       log_must eval "$ZFS send -R -I @init $POOL2@final > " \
+               "$BACKDIR/pool-init-final-IR"
+       list=$(getds_with_suffix $POOL2 @snapA)
+       list="$list $(getds_with_suffix $POOL2 @snapB)"
+       list="$list $(getds_with_suffix $POOL2 @snapC)"
+       list="$list $(getds_with_suffix $POOL2 @final)"
+       log_must destroy_tree $list
+       log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-init-final-IR"
+       log_must cmp_ds_cont $POOL $POOL2
+fi
+
+dstds=$(get_dst_ds $POOL $POOL2)
+#
+# Testing send -R -I from filesystem
+#
+log_must eval "$ZFS send -R -I @init $dstds/$FS@final > " \
+       "$BACKDIR/fs-init-final-IR"
+list=$(getds_with_suffix $dstds/$FS @snapA)
+list="$list $(getds_with_suffix $dstds/$FS @snapB)"
+list="$list $(getds_with_suffix $dstds/$FS @snapC)"
+list="$list $(getds_with_suffix $dstds/$FS @final)"
+log_must destroy_tree $list
+if is_global_zone ; then
+       log_must eval "$ZFS receive -d -F $dstds < $BACKDIR/fs-init-final-IR"
+else
+       $ZFS receive -d -F $dstds < $BACKDIR/fs-init-final-IR
+fi
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+if is_global_zone ; then
+       #
+       # Testing send -I -R for volume
+       #
+       vol=$POOL2/$FS/vol
+       log_must eval "$ZFS send -R -I @init $vol@final > " \
+               "$BACKDIR/vol-init-final-IR"
+       log_must destroy_tree $vol@snapB $vol@snapC $vol@final
+       log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/vol-init-final-IR"
+       log_must cmp_ds_subs $POOL $POOL2
+       log_must cmp_ds_cont $POOL $POOL2
+fi
+
+log_pass "zfs send -R -I send all the incremental between @init with @final"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_006_pos.ksh
new file mode 100755 (executable)
index 0000000..78f3d26
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      Rename snapshot name will not change the dependent order.
+#
+# STRATEGY:
+#      1. Set up a set of datasets.
+#      2. Rename part of snapshots.
+#      3. Send -R all the POOL
+#      4. Verify snapshot name will not change the dependent order.
+#
+
+verify_runnable "both"
+
+#              Source                  Target
+#
+set -A snaps   "$POOL@init"            "$POOL@snap0"   \
+               "$POOL@snapA"           "$POOL@snap1"   \
+               "$POOL@snapC"           "$POOL@snap2"   \
+               "$POOL@final"           "$POOL@init"
+
+function cleanup
+{
+       log_must cleanup_pool $POOL
+       log_must cleanup_pool $POOL2
+
+       log_must setup_test_model $POOL
+}
+
+log_assert "Rename snapshot name will not change the dependent order."
+log_onexit cleanup
+
+typeset -i i=0
+while ((i < ${#snaps[@]})); do
+       log_must $ZFS rename -r ${snaps[$i]} ${snaps[((i+1))]}
+
+       ((i += 2))
+done
+
+#
+# Duplicate POOL2 for testing
+#
+log_must eval "$ZFS send -R $POOL@init > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-final-R"
+
+dstds=$(get_dst_ds $POOL $POOL2)
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+log_pass "Rename snapshot name will not change the dependent order."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_007_pos.ksh
new file mode 100755 (executable)
index 0000000..b057953
--- /dev/null
@@ -0,0 +1,99 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      Rename parent filesystem name will not change the dependent order.
+#
+# STRATEGY:
+#      1. Separately rename pool clone, filesystem and volume name.
+#      2. Send -R all the POOL
+#      3. Verify renamed dataset will not change the snapshot dependent order.
+#
+
+verify_runnable "both"
+
+set -A         dtst \
+       "$POOL/pclone"          "$POOL/$FS/pclone"      \
+       "$POOL/$FS/fs1/fs2"     "$POOL/fs2"
+if is_global_zone ; then
+       typeset -i n=${#dtst[@]}
+       dtst[((n))]="$POOL/vol";        dtst[((n+1))]="$POOL/$FS/fs1/vol"
+fi
+
+function cleanup
+{
+       log_must cleanup_pool $POOL
+       log_must cleanup_pool $POOL2
+
+       log_must setup_test_model $POOL
+}
+
+log_assert "Rename parent filesystem name will not change the dependent order."
+log_onexit cleanup
+
+typeset -i i=0
+while ((i < ${#dtst[@]})); do
+       log_must $ZFS rename ${dtst[$i]} ${dtst[((i+1))]}
+
+       ((i += 2))
+done
+
+#
+# Verify zfs send -R should succeed
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-final-R"
+dstds=$(get_dst_ds $POOL $POOL2)
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+#
+# Verify zfs send -R -I should succeed
+#
+log_must eval "$ZFS send -R -I @init $dstds@final > " \
+        "$BACKDIR/pool-init-final-IR"
+list=$(getds_with_suffix $dstds @snapA)
+list="$list $(getds_with_suffix $dstds @snapB)"
+list="$list $(getds_with_suffix $dstds @snapC)"
+list="$list $(getds_with_suffix $dstds @final)"
+log_must destroy_tree $list
+if is_global_zone ; then
+       log_must eval "$ZFS receive -d -F $dstds < $BACKDIR/pool-init-final-IR"
+else
+       $ZFS receive -d -F $dstds < $BACKDIR/pool-init-final-IR
+fi
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+log_pass "Rename parent filesystem name will not change the dependent order."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_008_pos.ksh
new file mode 100755 (executable)
index 0000000..de5543e
--- /dev/null
@@ -0,0 +1,128 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      Changes made by 'zfs promote' can be properly received.
+#
+# STRATEGY:
+#      1. Seperatly promote pool clone, filesystem clone and volume clone.
+#      2. Recursively backup all the POOL and restore in POOL2
+#      3. Verify all the datesets and property be properly received.
+#
+
+verify_runnable "both"
+
+#              Origin                  Clone
+#
+set -A dtst    "$POOL"                 "$POOL/pclone"          \
+               "$POOL/$FS/fs1/fs2"     "$POOL/$FS/fs1/fclone"
+if is_global_zone ; then
+       typeset -i n=${#dtst[@]}
+       dtst[((n))]="$POOL/$FS/vol";    dtst[((n+1))]="$POOL/$FS/vclone"
+fi
+
+function cleanup
+{
+       typeset origin
+       typeset -i i=0
+       while ((i < ${#dtst[@]})); do
+               origin=$(get_prop origin ${dtst[$i]})
+
+               if [[ $origin != "-" ]]; then
+                       log_must $ZFS promote ${dtst[$i]}
+               fi
+
+               ((i += 2))
+       done
+
+       origin=$(get_prop origin $POOL2)
+       if [[ $origin != "-" ]]; then
+               log_must $ZFS promote $POOL2
+       fi
+       log_must cleanup_pool $POOL2
+}
+
+log_assert "Changes made by 'zfs promote' can be properly received."
+log_onexit cleanup
+
+typeset -i i=0
+while ((i < ${#dtst[@]})); do
+       log_must $ZFS promote ${dtst[((i+1))]}
+
+       ((i += 2))
+done
+
+#
+# Verify zfs send -R should succeed
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-final-R"
+
+dstds=$(get_dst_ds $POOL $POOL2)
+#
+# Define all the POOL/POOL2 datasets pair
+#
+set -A pair    "$POOL"                 "$dstds"                \
+               "$POOL/$FS"             "$dstds/$FS"            \
+               "$POOL/$FS/fs1"         "$dstds/$FS/fs1"        \
+               "$POOL/$FS/fs1/fs2"     "$dstds/$FS/fs1/fs2"    \
+               "$POOL/pclone"          "$dstds/pclone"         \
+               "$POOL/$FS/fs1/fclone"  "$dstds/$FS/fs1/fclone"
+
+if is_global_zone ; then
+       typeset -i n=${#pair[@]}
+       pair[((n))]="$POOL/vol";        pair[((n+1))]="$dstds/vol"
+       pair[((n+2))]="$POOL/$FS/vol"   pair[((n+3))]="$dstds/$FS/vol"
+fi
+
+#
+# Verify all the sub-datasets can be properly received.
+#
+log_must cmp_ds_subs $POOL $dstds
+typeset -i i=0
+while ((i < ${#pair[@]})); do
+       log_must cmp_ds_cont ${pair[$i]} ${pair[((i+1))]}
+       log_must cmp_ds_prop ${pair[$i]} ${pair[((i+1))]}
+
+       ((i += 2))
+done
+
+# Verify the original filesystem can be promoted
+log_must $ZFS promote $dstds
+if is_global_zone ; then
+       log_must $ZFS promote $dstds/$FS/vol
+fi
+log_must $ZFS promote $dstds/$FS/fs1/fs2
+
+log_pass "Changes made by 'zfs promote' can be properly received."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_009_pos.ksh
new file mode 100755 (executable)
index 0000000..0e6fcf1
--- /dev/null
@@ -0,0 +1,94 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      zfs receive can handle out of space correctly.
+#
+# STRATEGY:
+#      1. Create two pools, one is big and another is small.
+#      2. Fill the big pool with data.
+#      3. Take snapshot and backup the whole pool.
+#      4. Receive this stream in small pool.
+#      5. Verify zfs receive can handle the out of space error correctly.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if datasetexists bpool ; then
+               log_must $ZPOOL destroy -f bpool
+       fi
+       if datasetexists spool ; then
+               log_must $ZPOOL destroy -f spool
+       fi
+}
+
+log_assert "Verify zfs receive can handle out of space correctly."
+log_onexit cleanup
+
+log_must $MKFILE 100M $TESTDIR/bfile
+log_must $MKFILE 64M  $TESTDIR/sfile
+log_must $ZPOOL create bpool $TESTDIR/bfile
+log_must $ZPOOL create spool $TESTDIR/sfile
+
+#
+# Test out of space on sub-filesystem
+#
+log_must $ZFS create bpool/fs
+mntpnt=$(get_prop mountpoint bpool/fs)
+log_must $MKFILE 30M $mntpnt/file
+
+log_must $ZFS snapshot bpool/fs@snap
+log_must eval "$ZFS send -R bpool/fs@snap > $BACKDIR/fs-R"
+log_mustnot eval "$ZFS receive -d -F spool < $BACKDIR/fs-R"
+
+log_must datasetnonexists spool/fs
+log_must ismounted spool
+
+#
+# Test out of space on top filesystem
+#
+mntpnt2=$(get_prop mountpoint bpool)
+log_must $MV $mntpnt/file $mntpnt2
+log_must $ZFS destroy -rf bpool/fs
+
+log_must $ZFS snapshot bpool@snap
+log_must eval "$ZFS send -R bpool@snap > $BACKDIR/bpool-R"
+log_mustnot eval "$ZFS receive -d -F spool < $BACKDIR/bpool-R"
+
+log_must datasetnonexists spool/fs
+log_must ismounted spool
+
+log_pass "zfs receive can handle out of space correctly."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_010_pos.ksh
new file mode 100755 (executable)
index 0000000..503a8c2
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      ZFS can handle stream with multiple identical (same GUID) snapshots
+#
+# STRATEGY:
+#      1. Recursively backup snapshot
+#      2. Restore it to the given filesystem
+#      3. Resend the snapshot again
+#      4. Verify this stream can be restore to this filesystem again
+#
+
+verify_runnable "both"
+
+log_assert "ZFS can handle stream with multiple identical (same GUID) snapshots"
+log_onexit cleanup_pool $POOL2
+
+log_must $ZFS create $POOL2/$FS
+log_must $ZFS snapshot $POOL2/$FS@snap
+
+#
+# First round restore the stream
+#
+log_must eval "$ZFS send -R $POOL2/$FS@snap > $BACKDIR/fs-R"
+log_must eval "$ZFS receive -d -F $POOL2/$FS < $BACKDIR/fs-R"
+
+#
+# In order to avoid 'zfs send -R' failed, create snapshot for
+# all the sub-systems
+#
+list=$($ZFS list -r -H -o name -t filesystem $POOL2/$FS)
+for item in $list ; do
+       if datasetnonexists $item@snap ; then
+               log_must $ZFS snapshot $item@snap
+       fi
+done
+
+#
+# Second round restore the stream
+#
+log_must eval "$ZFS send -R $POOL2/$FS@snap > $BACKDIR/fs-R"
+dstds=$(get_dst_ds $POOL2/$FS $POOL2/$FS)
+log_must eval "$ZFS receive -d -F $dstds < $BACKDIR/fs-R"
+
+log_pass "ZFS can handle stream with multiple identical (same GUID) snapshots"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_011_pos.ksh
new file mode 100755 (executable)
index 0000000..d771a83
--- /dev/null
@@ -0,0 +1,125 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      Changes made by 'zfs inherit' can be properly received.
+#
+# STRATEGY:
+#      1. Inherit property for filesystem and volume
+#      2. Send and restore them in the target pool
+#      3. Verify all the datasets can be properly backup and receive
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       export __ZFS_POOL_RESTRICT="$POOL $POOL2"
+       log_must $ZFS unmount -a
+       unset __ZFS_POOL_RESTRICT
+       log_must cleanup_pool $POOL
+       log_must cleanup_pool $POOL2
+
+       log_must setup_test_model $POOL
+}
+
+log_assert "Verify changes made by 'zfs inherit' can be properly received."
+log_onexit cleanup
+
+#
+# Setting all the $FS properties as local value,
+#
+for prop in $(fs_inherit_prop); do
+       value=$(get_prop $prop $POOL/$FS)
+       log_must $ZFS set $prop=$value $POOL/$FS
+done
+
+#
+# Inherit propertes in sub-datasets
+#
+for ds in "$POOL/$FS/fs1" "$POOL/$FS/fs1/fs2" "$POOL/$FS/fs1/fclone" ; do
+       for prop in $(fs_inherit_prop) ; do
+               $ZFS inherit $prop $ds
+               if (($? !=0 )); then
+                       log_fail "$ZFS inherit $prop $ds"
+               fi
+       done
+done
+if is_global_zone ; then
+       for prop in $(vol_inherit_prop) ; do
+               $ZFS inherit $prop $POOL/$FS/vol
+               if (($? !=0 )); then
+                       log_fail "$ZFS inherit $prop $POOL/$FS/vol"
+               fi
+       done
+fi
+
+#
+# Verify datasets can be backup and restore correctly
+# Unmount $POOL/$FS to avoid two fs mount in the same mountpoint
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-R"
+log_must $ZFS unmount -f $POOL/$FS
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-R"
+
+dstds=$(get_dst_ds $POOL $POOL2)
+#
+# Define all the POOL/POOL2 datasets pair
+#
+set -A pair    "$POOL"                 "$dstds"                \
+               "$POOL/$FS"             "$dstds/$FS"            \
+               "$POOL/$FS/fs1"         "$dstds/$FS/fs1"        \
+               "$POOL/$FS/fs1/fs2"     "$dstds/$FS/fs1/fs2"    \
+               "$POOL/pclone"          "$dstds/pclone"         \
+               "$POOL/$FS/fs1/fclone"  "$dstds/$FS/fs1/fclone"
+
+if is_global_zone ; then
+       typeset -i n=${#pair[@]}
+       pair[((n))]="$POOL/vol";        pair[((n+1))]="$dstds/vol"
+       pair[((n+2))]="$POOL/$FS/vol"   pair[((n+3))]="$dstds/$FS/vol"
+fi
+
+#
+# Verify all the sub-datasets can be properly received.
+#
+log_must cmp_ds_subs $POOL $dstds
+typeset -i i=0
+while ((i < ${#pair[@]})); do
+       log_must cmp_ds_cont ${pair[$i]} ${pair[((i+1))]}
+       log_must cmp_ds_prop ${pair[$i]} ${pair[((i+1))]}
+
+       ((i += 2))
+done
+
+log_pass "Changes made by 'zfs inherit' can be properly received."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_012_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_012_pos.ksh
new file mode 100755 (executable)
index 0000000..a7698da
--- /dev/null
@@ -0,0 +1,200 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      zfs send -R will backup all the filesystem properties correctly.
+#
+# STRATEGY:
+#      1. Setting properties for all the filesystem and volumes randomly
+#      2. Backup all the data from POOL by send -R
+#      3. Restore all the data in POOL2
+#      4. Verify all the perperties in two pools are same
+#
+
+verify_runnable "global"
+
+function rand_set_prop
+{
+       typeset dtst=$1
+       typeset prop=$2
+       shift 2
+       typeset value=$(random_get $@)
+
+       log_must eval "$ZFS set $prop='$value' $dtst"
+}
+
+function edited_prop
+{
+       typeset behaviour=$1
+       typeset ds=$2
+       typeset backfile=$TESTDIR/edited_prop_$ds
+
+       case $behaviour in
+               "get")
+                       typeset props=$($ZFS inherit 2>&1 | \
+                               $AWK '$2=="YES" {print $1}' | \
+                               $EGREP -v "^vol|\.\.\.$")
+                       for item in $props ; do
+                               if [[ $item == "mlslabel" ]] && \
+                                       ! is_te_enabled ; then
+                                       continue
+                               fi
+                               $ZFS get -H -o property,value $item $ds >> \
+                                       $backfile
+                               if (($? != 0)); then
+                                       log_fail "zfs get -H -o property,value"\
+                                               "$item $ds > $backfile"
+                               fi
+                       done
+                       ;;
+               "set")
+                       if [[ ! -f $backfile ]] ; then
+                               log_fail "$ds need backup properties firstly."
+                       fi
+
+                       typeset prop value
+                       while read prop value ; do
+                               eval $ZFS set $prop='$value' $ds
+                               if (($? != 0)); then
+                                       log_fail "$ZFS set $prop=$value $ds"
+                               fi
+                       done < $backfile
+                       ;;
+               *)
+                       log_fail "Unrecognized behaviour: $behaviour"
+       esac
+}
+
+function cleanup
+{
+       log_must cleanup_pool $POOL
+       log_must cleanup_pool $POOL2
+
+       log_must edited_prop "set" $POOL
+       log_must edited_prop "set" $POOL2
+
+       typeset prop
+       for prop in $(fs_inherit_prop) ; do
+               log_must $ZFS inherit $prop $POOL
+               log_must $ZFS inherit $prop $POOL2
+       done
+
+       log_must setup_test_model $POOL
+
+       if [[ -d $TESTDIR ]]; then
+               log_must $RM -rf $TESTDIR/*
+       fi
+}
+
+log_assert "Verify zfs send -R will backup all the filesystem properties " \
+       "correctly."
+log_onexit cleanup
+
+log_must edited_prop "get" $POOL
+log_must edited_prop "get" $POOL2
+
+for fs in "$POOL" "$POOL/pclone" "$POOL/$FS" "$POOL/$FS/fs1" \
+       "$POOL/$FS/fs1/fs2" "$POOL/$FS/fs1/fclone" ; do
+       rand_set_prop $fs aclinherit "discard" "noallow" "secure" "passthrough"
+       rand_set_prop $fs checksum "on" "off" "fletcher2" "fletcher4" "sha256"
+       rand_set_prop $fs acltype "off" "noacl" "posixacl"
+       rand_set_prop $fs atime "on" "off"
+       rand_set_prop $fs checksum "on" "off" "fletcher2" "fletcher4" "sha256"
+       rand_set_prop $fs compression "on" "off" "lzjb" "gzip" \
+               "gzip-1" "gzip-2" "gzip-3" "gzip-4" "gzip-5" "gzip-6"   \
+               "gzip-7" "gzip-8" "gzip-9"
+       rand_set_prop $fs copies "1" "2" "3"
+       rand_set_prop $fs devices "on" "off"
+       rand_set_prop $fs exec "on" "off"
+       rand_set_prop $fs quota "512M" "1024M"
+       rand_set_prop $fs recordsize "512" "2K" "8K" "32K" "128K"
+       rand_set_prop $fs dnodesize "legacy" "auto" "1k" "2k" "4k" "8k" "16k"
+       rand_set_prop $fs setuid "on" "off"
+       rand_set_prop $fs snapdir "hidden" "visible"
+       rand_set_prop $fs xattr "on" "off"
+       rand_set_prop $fs user:prop "aaa" "bbb" "23421" "()-+?"
+done
+
+for vol in "$POOL/vol" "$POOL/$FS/vol" ; do
+       rand_set_prop $vol checksum "on" "off" "fletcher2" "fletcher4" "sha256"
+       rand_set_prop $vol compression "on" "off" "lzjb" "gzip" \
+               "gzip-1" "gzip-2" "gzip-3" "gzip-4" "gzip-5" "gzip-6"   \
+               "gzip-7" "gzip-8" "gzip-9"
+       rand_set_prop $vol readonly "on" "off"
+       rand_set_prop $vol copies "1" "2" "3"
+       rand_set_prop $vol user:prop "aaa" "bbb" "23421" "()-+?"
+done
+
+
+# Verify inherited property can be received
+rand_set_prop $POOL redundant_metadata "all" "most"
+rand_set_prop $POOL sync "standard" "always" "disabled"
+
+#
+# Duplicate POOL2 for testing
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-final-R"
+
+#
+# Define all the POOL/POOL2 datasets pair
+#
+set -A pair    "$POOL"                 "$POOL2"                \
+               "$POOL/$FS"             "$POOL2/$FS"            \
+               "$POOL/$FS/fs1"         "$POOL2/$FS/fs1"        \
+               "$POOL/$FS/fs1/fs2"     "$POOL2/$FS/fs1/fs2"    \
+               "$POOL/pclone"          "$POOL2/pclone"         \
+               "$POOL/$FS/fs1/fclone"  "$POOL2/$FS/fs1/fclone" \
+               "$POOL/vol"             "$POOL2/vol"            \
+               "$POOL/$FS/vol"         "$POOL2/$FS/vol"
+
+typeset -i i=0
+while ((i < ${#pair[@]})); do
+       log_must cmp_ds_prop ${pair[$i]} ${pair[((i+1))]}
+
+       ((i += 2))
+done
+
+
+$ZPOOL upgrade -v | $GREP "Snapshot properties" > /dev/null 2>&1
+if (( $? == 0 )) ; then
+       i=0
+       while ((i < ${#pair[@]})); do
+               log_must cmp_ds_prop ${pair[$i]}@final ${pair[((i+1))]}@final
+               ((i += 2))
+       done
+fi
+
+log_pass "Verify zfs send -R will backup all the filesystem properties " \
+       "correctly."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_013_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_013_pos.ksh
new file mode 100755 (executable)
index 0000000..fefcfa7
--- /dev/null
@@ -0,0 +1,86 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# DESCRIPTION:
+#      zfs receive -dF with incremental stream will destroy all the
+#      dataset that not exist on the sender side.
+#
+# STRATEGY:
+#      1. Setup test model
+#      2. Send -R @final on pool
+#      3. Destroy some dataset within the @final, and create @destroy
+#      4. Send -R -I @final @destroy on pool
+#      5. Verify receive -dF will destroy all the dataset that not exist
+#         on the sender side.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       cleanup_pool $POOL2
+       cleanup_pool $POOL
+       log_must setup_test_model $POOL
+}
+
+log_assert "zfs receive -dF will destroy all the dataset that not exist" \
+       "on the sender side"
+log_onexit cleanup
+
+cleanup
+
+#
+# Duplicate POOL2 for testing
+#
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -dF $POOL2 < $BACKDIR/pool-final-R"
+
+log_must $ZFS destroy -Rf $POOL/$FS
+log_must $ZFS destroy -Rf $POOL/pclone
+
+if is_global_zone ; then
+       log_must $ZFS destroy -Rf $POOL/vol
+fi
+log_must $ZFS snapshot -r $POOL@destroy
+
+log_must eval "$ZFS send -R -I @final $POOL@destroy > " \
+       "$BACKDIR/pool-final-destroy-IR"
+log_must eval "$ZFS receive -dF $POOL2 < $BACKDIR/pool-final-destroy-IR"
+
+dstds=$(get_dst_ds $POOL $POOL2)
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+log_pass "zfs receive -dF will destroy all the dataset that not exist" \
+       "on the sender side"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_014_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_014_pos.ksh
new file mode 100755 (executable)
index 0000000..6857681
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/ksh
+
+#
+# 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) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify that a pool imported readonly can be sent and received.
+#
+# Strategy:
+# 1. Make the source pool readonly, and receive it into pool2.
+# 2. Reset pool2, and repeat the send from a non-root fs of the source pool.
+# 3. Make the source pool read-write again.
+#
+
+verify_runnable "both"
+
+log_assert "zfs send will work on filesystems and volumes in a read-only pool."
+log_onexit cleanup_pool $POOL2
+
+log_must eval "$ZPOOL export $POOL"
+log_must eval "$ZPOOL import -o readonly=on $POOL"
+log_must eval "$ZFS send -R $POOL@final > $BACKDIR/pool-final-R"
+log_must eval "$ZFS receive -d -F $POOL2 < $BACKDIR/pool-final-R"
+
+dstds=$(get_dst_ds $POOL $POOL2)
+log_must cmp_ds_subs $POOL $dstds
+log_must cmp_ds_cont $POOL $dstds
+
+log_must cleanup_pool $POOL2
+
+log_must eval "$ZFS send -R $POOL/$FS@final > $BACKDIR/fs-final-R"
+log_must eval "$ZFS receive -d $POOL2 < $BACKDIR/fs-final-R"
+block_device_wait
+log_must eval "$ZPOOL export $POOL"
+log_must eval "$ZPOOL import $POOL"
+
+dstds=$(get_dst_ds $POOL/$FS $POOL2)
+log_must cmp_ds_subs $POOL/$FS $dstds
+log_must cmp_ds_cont $POOL/$FS $dstds
+
+log_pass "zfs send will work on filesystems and volumes in a read-only pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_019_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_019_pos.ksh
new file mode 100755 (executable)
index 0000000..26f475e
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/ksh
+
+#
+# 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) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify resumability of a full and incremental ZFS send/receive in the
+# presence of a corrupted stream.
+#
+# Strategy:
+# 1. Start a full ZFS send, redirect output to a file
+# 2. Mess up the contents of the stream state file on disk
+# 3. Try ZFS receive, which should fail with a checksum mismatch error
+# 4. ZFS send to the stream state file again using the receive_resume_token
+# 5. ZFS receieve and verify the receive completes successfully
+# 6. Repeat steps on an incremental ZFS send
+#
+
+verify_runnable "both"
+
+log_assert "Verify resumability of a full and incremental ZFS send/receive " \
+    "in the presence of a corrupted stream"
+log_onexit cleanup_pool $POOL2
+
+sendfs=$POOL/sendfs
+recvfs=$POOL2/recvfs
+streamfs=$POOL/stream
+
+test_fs_setup $POOL $POOL2
+resume_test "$ZFS send -v $sendfs@a" $streamfs $recvfs
+resume_test "$ZFS send -v -i @a $sendfs@b" $streamfs $recvfs
+file_check $sendfs $recvfs
+
+log_pass "Verify resumability of a full and incremental ZFS send/receive " \
+    "in the presence of a corrupted stream"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_020_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_020_pos.ksh
new file mode 100755 (executable)
index 0000000..43cf345
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/ksh
+
+#
+# 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) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify resumability of a full ZFS send/receive with the -D (dedup) flag in
+# the presence of a corrupted stream.
+#
+# Strategy:
+# 1. Start a full ZFS send with the -D flag (dedup), redirect output to a file
+# 2. Mess up the contents of the stream state file on disk
+# 3. Try ZFS receive, which should fail with a checksum mismatch error
+# 4. ZFS send to the stream state file again using the receive_resume_token
+# 5. ZFS receieve and verify the receive completes successfully
+#
+
+verify_runnable "both"
+
+log_assert "Verify resumability of full ZFS send/receive with the -D " \
+    "(dedup) flag"
+log_onexit cleanup_pool $POOL2
+
+sendfs=$POOL/sendfs
+recvfs=$POOL2/recvfs
+streamfs=$POOL/stream
+
+test_fs_setup $POOL $POOL2
+resume_test "$ZFS send -D -v $sendfs@a" $streamfs $recvfs
+file_check $sendfs $recvfs
+
+log_pass "Verify resumability of full ZFS send/receive with the -D " \
+    "(dedup) flag"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_021_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_021_pos.ksh
new file mode 100755 (executable)
index 0000000..3790121
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/ksh
+
+#
+# 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) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify resumability of a full and incremental ZFS send/receive with the
+# -e (embedded) flag in the presence of a corrupted stream.
+#
+# Strategy:
+# 1. Start a full ZFS send with the -e flag (embedded), redirect output to
+#    a file
+# 2. Mess up the contents of the stream state file on disk
+# 3. Try ZFS receive, which should fail with a checksum mismatch error
+# 4. ZFS send to the stream state file again using the receive_resume_token
+# 5. ZFS receieve and verify the receive completes successfully
+# 6. Repeat steps on an incremental ZFS send
+#
+
+verify_runnable "both"
+
+log_assert "Verify resumability of a full and incremental ZFS send/receive " \
+    "with the -e (embedded) flag"
+log_onexit cleanup_pool $POOL2
+
+sendfs=$POOL/sendfs
+recvfs=$POOL2/recvfs
+streamfs=$POOL/stream
+
+test_fs_setup $POOL $POOL2
+resume_test "$ZFS send -v -e $sendfs@a" $streamfs $recvfs
+resume_test "$ZFS send -v -e -i @a $sendfs@b" $streamfs $recvfs
+file_check $sendfs $recvfs
+
+log_pass "Verify resumability of a full and incremental ZFS send/receive " \
+    "with the -e (embedded) flag"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_022_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_022_pos.ksh
new file mode 100755 (executable)
index 0000000..fd06b06
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/ksh
+
+#
+# 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) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify resumability of an incremental ZFS send/receive with ZFS bookmarks in
+# the presence of a corrupted stream.
+#
+# Strategy:
+# 1. Bookmark a ZFS snapshot
+# 2. Destroy the ZFS sanpshot
+# 3. Destroy the filesystem for the receive
+# 4. Verify receive of the full send stream
+# 5. Start an incremental ZFS send of the ZFS bookmark, redirect output to a
+#    file
+# 6. Mess up the contents of the stream state file on disk
+# 7. Try ZFS receive, which should fail with a checksum mismatch error
+# 8. ZFS send to the stream state file again using the receive_resume_token
+# 9. ZFS receieve and verify the receive completes successfully
+#
+
+verify_runnable "both"
+
+log_assert "Verify resumability of an incremental ZFS send/receive with ZFS " \
+    "bookmarks"
+log_onexit cleanup_pool $POOL2
+
+sendfs=$POOL/sendfs
+recvfs=$POOL2/recvfs
+streamfs=$POOL/stream
+
+test_fs_setup $POOL $POOL2
+log_must $ZFS bookmark $sendfs@a $sendfs#bm_a
+log_must $ZFS destroy $sendfs@a
+log_must $ZFS receive -v $recvfs </$POOL/initial.zsend
+resume_test "$ZFS send -i \#bm_a $sendfs@b" $streamfs $recvfs
+log_must $ZFS destroy -r -f $sendfs
+log_must $ZFS receive -v $sendfs </$POOL/initial.zsend
+log_must $ZFS receive -v $sendfs </$POOL/incremental.zsend
+file_check $sendfs $recvfs
+
+log_pass "Verify resumability of an incremental ZFS send/receive with ZFS " \
+    "bookmarks"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/rsend_024_pos.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/rsend_024_pos.ksh
new file mode 100755 (executable)
index 0000000..2f8f3f7
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/ksh
+
+#
+# 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) 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+#
+# Description:
+# Verify resumability of a full ZFS send/receive with the source filesystem
+# unmounted.
+#
+# Strategy:
+# 1. Destroy the filesystem for the receive
+# 2. Unmount the source filsesystem
+# 3. Start a full ZFS send, redirect output to a file
+# 4. Mess up the contents of the stream state file on disk
+# 5. Try ZFS receive, which should fail with a checksum mismatch error
+# 6. ZFS send to the stream state file again using the receive_resume_token
+# 7. ZFS receieve and verify the receive completes successfully
+#
+
+verify_runnable "both"
+
+log_assert "Verify resumability of a full ZFS send/receive with the source " \
+    "filesystem unmounted"
+log_onexit cleanup_pool $POOL2
+
+sendfs=$POOL/sendfs
+recvfs=$POOL2/recvfs
+streamfs=$POOL/stream
+
+test_fs_setup $POOL $POOL2
+log_must $ZFS unmount $sendfs
+resume_test "$ZFS send $sendfs" $streamfs $recvfs
+file_check $sendfs $recvfs
+
+log_pass "Verify resumability of a full ZFS send/receive with the source " \
+    "filesystem unmounted"
diff --git a/zfs/tests/zfs-tests/tests/functional/rsend/setup.ksh b/zfs/tests/zfs-tests/tests/functional/rsend/setup.ksh
new file mode 100755 (executable)
index 0000000..8423adf
--- /dev/null
@@ -0,0 +1,45 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/rsend/rsend.kshlib
+
+verify_runnable "both"
+verify_disk_count "$DISKS" 2
+
+if is_global_zone ; then
+       log_must $ZPOOL create $POOL $DISK1
+       log_must $ZPOOL create $POOL2 $DISK2
+fi
+log_must $MKDIR $BACKDIR $TESTDIR
+
+log_must setup_test_model $POOL
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/Makefile.am b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/Makefile.am
new file mode 100644 (file)
index 0000000..a14d32d
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/scrub_mirror
+dist_pkgdata_SCRIPTS = \
+       default.cfg \
+       scrub_mirror_common.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       scrub_mirror_001_pos.ksh \
+       scrub_mirror_002_pos.ksh \
+       scrub_mirror_003_pos.ksh \
+       scrub_mirror_004_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/cleanup.ksh
new file mode 100755 (executable)
index 0000000..d0d77b7
--- /dev/null
@@ -0,0 +1,55 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/scrub_mirror/default.cfg
+
+
+verify_runnable "global"
+
+$DF -F zfs -h | $GREP "$TESTFS " >/dev/null
+[[ $? == 0 ]] && log_must $ZFS umount -f $TESTDIR
+destroy_pool $TESTPOOL
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+       delete_partitions
+fi
+
+# recreate and destroy a zpool over the disks to restore the partitions to
+# normal
+if [[ -n $SINGLE_DISK ]]; then
+       log_must cleanup_devices $MIRROR_PRIMARY
+else
+       log_must cleanup_devices $MIRROR_PRIMARY $MIRROR_SECONDARY
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/default.cfg b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/default.cfg
new file mode 100644 (file)
index 0000000..ee05dae
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export DISKSARRAY=$DISKS
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+
+typeset -i NUMBER_OF_DISKS=0
+for i in $DISKS; do
+       [[ -n $MIRROR_PRIMARY ]] && MIRROR_SECONDARY=$i
+       [[ -z $MIRROR_PRIMARY ]] && MIRROR_PRIMARY=$i
+done
+
+if [[ -z $MIRROR_SECONDARY ]]; then
+       # We need to repartition the single disk to two slices
+       SINGLE_DISK=$MIRROR_PRIMARY
+       MIRROR_SECONDARY=$MIRROR_PRIMARY
+       SIDE_PRIMARY_PART=0
+       SIDE_SECONDARY_PART=1
+       if is_linux; then
+               if is_mpath_device $MIRROR_PRIMARY; then
+                       export DEV_DSKDIR=$DEV_MPATHDIR
+               else
+                       export DEV_DSKDIR=$DEV_RDSKDIR
+               fi
+               if ( is_mpath_device $SINGLE_DISK ) && [[ -z $($ECHO $SINGLE_DISK | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $SINGLE_DISK ); then
+                       SIDE_PRIMARY=${SINGLE_DISK}1
+                       SIDE_SECONDARY=${SINGLE_DISK}2
+               elif ( is_mpath_device $SINGLE_DISK || is_loop_device $SINGLE_DISK ); then
+                       SIDE_PRIMARY=${SINGLE_DISK}p1
+                       SIDE_SECONDARY=${SINGLE_DISK}p2
+               else
+                       log_fail "$SINGLE_DISK not supported for partitioning."
+               fi
+       else
+               export DEV_DSKDIR="/dev"
+               SIDE_PRIMARY=${SINGLE_DISK}s${SIDE_PRIMARY_PART}
+               SIDE_SECONDARY=${SINGLE_DISK}s${SIDE_SECONDARY_PART}
+       fi
+else
+       SIDE_PRIMARY_PART=0
+       SIDE_SECONDARY_PART=0
+       if is_linux; then
+               if is_mpath_device $MIRROR_PRIMARY; then
+                       export DEV_DSKDIR=$DEV_MPATHDIR
+               else
+                       export DEV_DSKDIR=$DEV_RDSKDIR
+               fi
+               if ( is_mpath_device $MIRROR_PRIMARY ) && [[ -z $($ECHO $MIRROR_PRIMARY | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $MIRROR_PRIMARY ); then
+                       SIDE_PRIMARY=${MIRROR_PRIMARY}1
+               elif ( is_mpath_device $MIRROR_PRIMARY || is_loop_device $MIRROR_PRIMARY ); then
+                       SIDE_PRIMARY=${MIRROR_PRIMARY}p1
+               else
+                       log_fail "$MIRROR_PRIMARY not supported for partitioning."
+               fi
+               if ( is_mpath_device $MIRROR_SECONDARY ) && [[ -z $($ECHO $MIRROR_SECONDARY | awk 'substr($1,18,1)\
+                   ~ /^[[:digit:]]+$/') ]] || ( is_real_device $MIRROR_SECONDARY ); then
+                       SIDE_SECONDARY=${MIRROR_SECONDARY}1
+               elif ( is_mpath_device $MIRROR_SECONDARY || is_loop_device $MIRROR_SECONDARY ); then
+                       SIDE_SECONDARY=${MIRROR_SECONDARY}p1
+               else
+                       log_fail "$MIRROR_SECONDARY not supported for partitioning."
+               fi
+       else
+               export DEV_DSKDIR="/dev"
+               SIDE_PRIMARY=${MIRROR_PRIMARY}s${SIDE_PRIMARY_PART}
+               SIDE_SECONDARY=${MIRROR_SECONDARY}s${SIDE_SECONDARY_PART}
+       fi
+fi
+
+
+export MIRROR_PRIMARY MIRROR_SECONDARY SINGLE_DISK SIDE_PRIMARY SIDE_SECONDARY
+
+export FILE_COUNT=10
+export FILE_SIZE=$(( 1024 * 1024 ))
+export MIRROR_MEGS=100
+export MIRROR_SIZE=${MIRROR_MEGS}m # default mirror size
+export DD_BLOCK=$(( 64 * 1024 ))
+export DD_COUNT=$(( MIRROR_MEGS * 1024 * 1024 / DD_BLOCK ))
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_001_pos.ksh
new file mode 100755 (executable)
index 0000000..841d8ab
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/scrub_mirror/scrub_mirror_common.kshlib
+
+#
+# DESCRIPTION:
+# The primary side of a zpool mirror can be zeroed without causing damage
+# to the data in the pool
+#
+# STRATEGY:
+# 1) Write several files to the ZFS filesystem mirror
+# 2) dd from /dev/zero over the primary side of the mirror
+# 3) verify that all the file contents are unchanged on the file system
+#
+
+verify_runnable "global"
+
+log_assert "The primary side of a zpool mirror may be completely wiped" \
+       "without affecting the content of the pool"
+
+overwrite_verify_mirror $TESTPOOL $SIDE_PRIMARY /dev/zero
+
+log_pass "The overwrite had no effect on the data"
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_002_pos.ksh
new file mode 100755 (executable)
index 0000000..92cabd6
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/scrub_mirror/scrub_mirror_common.kshlib
+
+#
+# DESCRIPTION:
+# The secondary side of a zpool mirror can be zeroed without causing damage
+# to the data in the pool
+#
+# STRATEGY:
+# 1) Write several files to the ZFS filesystem in the mirrored pool
+# 2) dd from /dev/zero over the secondary side of the mirror
+# 3) verify that all the file contents are unchanged on the file system
+#
+
+verify_runnable "global"
+
+log_assert "The primary side of a zpool mirror may be completely wiped" \
+       "without affecting the content of the pool"
+
+overwrite_verify_mirror $TESTPOOL $SIDE_SECONDARY /dev/zero
+
+log_pass "The overwrite had no effect on the data"
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_003_pos.ksh
new file mode 100755 (executable)
index 0000000..ecb4229
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/scrub_mirror/scrub_mirror_common.kshlib
+
+#
+# DESCRIPTION:
+# The primary side of a zpool mirror can be mangled causing without damage
+# to the data in the pool
+#
+# STRATEGY:
+# 1) Write several files to the ZFS filesystem mirror
+# 2) dd from /dev/urandom over the primary side of the mirror
+# 3) verify that all the file contents are unchanged on the file system
+#
+
+verify_runnable "global"
+
+log_assert "The primary side of a zpool mirror may be completely mangled" \
+       "without affecting the content of the pool"
+
+overwrite_verify_mirror $TESTPOOL $SIDE_PRIMARY /dev/urandom
+
+log_pass "The overwrite did not have any effect on the data"
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_004_pos.ksh
new file mode 100755 (executable)
index 0000000..b863380
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/scrub_mirror/scrub_mirror_common.kshlib
+
+#
+# DESCRIPTION:
+# The secondary side of a zpool mirror can be mangled causing without damage
+# to the data in the pool
+#
+# STRATEGY:
+# 1) Write several files to the ZFS filesystem in the mirrored pool
+# 2) dd from /dev/urandom over the secondary side of the mirror
+# 3) verify that all the file contents are unchanged on the file system
+#
+
+verify_runnable "global"
+
+log_assert "The primary side of a zpool mirror may be completely mangled" \
+       "without affecting the content of the pool"
+
+overwrite_verify_mirror $TESTPOOL $SIDE_SECONDARY /dev/urandom
+
+log_pass "The overwrite had no effect on the data"
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_common.kshlib b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/scrub_mirror_common.kshlib
new file mode 100644 (file)
index 0000000..08450dc
--- /dev/null
@@ -0,0 +1,78 @@
+#
+# 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.
+#
+. $STF_SUITE/tests/functional/scrub_mirror/default.cfg
+
+function overwrite_verify_mirror
+{
+       typeset POOL=$1
+       typeset AFFECTED_DEVICE=$2
+       typeset OVERWRITING_DEVICE=$3
+
+       typeset atfile=0
+       set -A files
+       set -A cksums
+       set -A newcksums
+
+       while (( atfile < FILE_COUNT )); do
+               files[$atfile]=$TESTDIR/file.$atfile
+               log_must $FILE_WRITE -o create -f $TESTDIR/file.$atfile \
+                       -b $FILE_SIZE -c 1
+               cksums[$atfile]=$($CKSUM ${files[$atfile]})
+               (( atfile = atfile + 1 ))
+       done
+
+       # dd the affected side of the mirror
+       log_must $DD if=$OVERWRITING_DEVICE of=${DEV_DSKDIR}/$AFFECTED_DEVICE \
+               seek=8 bs=$DD_BLOCK count=$(( DD_COUNT - 128 )) conv=notrunc
+
+       log_must $ZPOOL scrub $POOL
+
+       while is_pool_scrubbing $POOL; do
+               $SLEEP 2
+       done
+
+       atfile=0
+
+       typeset -i failedcount=0
+       while (( atfile < FILE_COUNT )); do
+               files[$atfile]=$TESTDIR/file.$atfile
+               newcksum=$($CKSUM ${files[$atfile]})
+               if [[ $newcksum != ${cksums[$atfile]} ]]; then
+                       (( failedcount = failedcount + 1 ))
+               fi
+               $RM -f ${files[$atfile]}
+               (( atfile = atfile + 1 ))
+       done
+
+       if (( $failedcount > 0 )); then
+               log_fail "of the $FILE_COUNT files $failedcount did not " \
+                   "have the same checksum before and after."
+       fi
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/scrub_mirror/setup.ksh b/zfs/tests/zfs-tests/tests/functional/scrub_mirror/setup.ksh
new file mode 100755 (executable)
index 0000000..97a70d8
--- /dev/null
@@ -0,0 +1,51 @@
+#! /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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/scrub_mirror/default.cfg
+
+verify_runnable "global"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+if [[ -n $SINGLE_DISK ]]; then
+       log_note "Partitioning a single disk ($SINGLE_DISK)"
+else
+       log_note "Partitioning disks ($MIRROR_PRIMARY $MIRROR_SECONDARY)"
+fi
+log_must set_partition $SIDE_PRIMARY_PART "" $MIRROR_SIZE $MIRROR_PRIMARY
+log_must set_partition $SIDE_SECONDARY_PART "" $MIRROR_SIZE $MIRROR_SECONDARY
+
+default_mirror_setup $SIDE_PRIMARY $SIDE_SECONDARY
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/Makefile.am b/zfs/tests/zfs-tests/tests/functional/slog/Makefile.am
new file mode 100644 (file)
index 0000000..c370472
--- /dev/null
@@ -0,0 +1,20 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/slog
+dist_pkgdata_SCRIPTS = \
+       slog.cfg \
+       slog.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       slog_001_pos.ksh \
+       slog_002_pos.ksh \
+       slog_003_pos.ksh \
+       slog_004_pos.ksh \
+       slog_005_pos.ksh \
+       slog_006_pos.ksh \
+       slog_007_pos.ksh \
+       slog_008_neg.ksh \
+       slog_009_neg.ksh \
+       slog_010_neg.ksh \
+       slog_011_neg.ksh \
+       slog_012_neg.ksh \
+       slog_013_pos.ksh \
+       slog_014_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/slog/cleanup.ksh
new file mode 100755 (executable)
index 0000000..039135c
--- /dev/null
@@ -0,0 +1,54 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/slog/slog.cfg
+
+verify_runnable "global"
+
+if ! verify_slog_support ; then
+       log_unsupported "This system doesn't support separate intent logs"
+fi
+
+if datasetexists $TESTPOOL ; then
+       log_must $ZPOOL destroy -f $TESTPOOL
+fi
+if datasetexists $TESTPOOL2 ; then
+       log_must $ZPOOL destroy -f $TESTPOOL2
+fi
+if [[ -d $VDIR ]]; then
+       log_must $RM -rf $VDIR
+fi
+if [[ -d $VDIR2 ]]; then
+       log_must $RM -rf $VDIR2
+fi
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/setup.ksh b/zfs/tests/zfs-tests/tests/functional/slog/setup.ksh
new file mode 100755 (executable)
index 0000000..28c07c9
--- /dev/null
@@ -0,0 +1,50 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/slog/slog.cfg
+
+verify_runnable "global"
+
+if ! verify_slog_support ; then
+       log_unsupported "This system doesn't support separate intent logs"
+fi
+
+if [[ -d $VDEV ]]; then
+       log_must $RM -rf $VDIR
+fi
+if [[ -d $VDEV2 ]]; then
+       log_must $RM -rf $VDIR2
+fi
+log_must $MKDIR -p $VDIR $VDIR2
+log_must $MKFILE $SIZE $VDEV $SDEV $LDEV $VDEV2 $SDEV2 $LDEV2
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog.cfg b/zfs/tests/zfs-tests/tests/functional/slog/slog.cfg
new file mode 100644 (file)
index 0000000..28cce1a
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+export SIZE=64M
+
+export VDIR=/disk-slog
+export VDIR2=/disk2-slog
+
+export VDEV="$VDIR/a $VDIR/b $VDIR/c"
+export SDEV="$VDIR/d"
+export LDEV="$VDIR/e $VDIR/f"
+export VDEV2="$VDIR2/a $VDIR2/b $VDIR2/c"
+export SDEV2="$VDIR2/d"
+export LDEV2="$VDIR2/e $VDIR2/f"
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog.kshlib b/zfs/tests/zfs-tests/tests/functional/slog/slog.kshlib
new file mode 100644 (file)
index 0000000..124bfe6
--- /dev/null
@@ -0,0 +1,157 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/slog/slog.cfg
+
+function cleanup
+{
+       if datasetexists $TESTPOOL ; then
+               log_must $ZPOOL destroy -f $TESTPOOL
+       fi
+       if datasetexists $TESTPOOL2 ; then
+               log_must $ZPOOL destroy -f $TESTPOOL2
+       fi
+}
+
+#
+# Try zpool status/iostat for given pool
+#
+# $1 pool
+#
+function display_status
+{
+       typeset pool=$1
+
+       typeset -i ret=0
+       $ZPOOL status -xv $pool > /dev/null 2>&1
+       ret=$?
+
+       $ZPOOL iostat > /dev/null 2>&1
+       ((ret |= $?))
+
+       typeset mntpnt=$(get_prop mountpoint $pool)
+       $DD if=/dev/random of=$mntpnt/testfile.$$ &
+       typeset pid=$!
+
+       $ZPOOL iostat -v 1 3 > /dev/null
+       ((ret |= $?))
+
+       kill -9 $pid
+
+       return $ret
+}
+
+#
+# Verify the give slog device have correct type and status
+#
+# $1 pool name
+# $2 device name
+# $3 device status
+# $4 device type
+#
+function verify_slog_device
+{
+       typeset pool=$1
+       typeset device=$2
+       typeset status=$3
+       typeset type=$4
+
+       if [[ -z $pool || -z $device || -z $status ]]; then
+               log_fail "Usage: verify_slog_device <pool> <device> " \
+                       "<status> [type]"
+       fi
+
+       if [[ $WRAPPER == *"smi"* ]]; then
+               $ECHO $device | $EGREP "^c[0-F]+([td][0-F]+)+$" > /dev/null 2>&1
+               if (( $? == 0 )); then
+                       device=${device}s2
+               fi
+       fi
+
+       #
+       # Get all the slog devices and status table like below
+       #
+       # mirror:/disks/d ONLINE mirror:/disks/e ONLINE stripe:/disks/f ONLINE
+       #
+       set -A dev_stat_tab $($ZPOOL status -v $pool | $NAWK 'BEGIN {start=0} \
+                               /\tlogs/ {start=1}
+                               /\tmirror/ || /\tspares/ || /^$/ {start=0}
+                               (start==1) && /\t  (\/|[a-zA-Z])/ \
+                                       {print "stripe:" $1 " " $2}
+                               (start==1) && /\t    (\/|[a-zA-Z])/ \
+                                       {print "mirror:" $1 " " $2}
+                               # When hotspare is replacing
+                               (start==1) && /\t      (\/|[a-zA-Z])/ \
+                                       {print "mirror:" $1 " " $2}'
+                            )
+
+       typeset -i i=0
+       typeset find=0
+       while (( i < ${#dev_stat_tab[@]} )); do
+               typeset dev=${dev_stat_tab[$i]}
+               typeset stat=${dev_stat_tab[((i+1))]}
+
+               case $dev in
+                       stripe:$device)
+                               if [[ "$type" == 'mirror' ]]; then
+                                       log_note "Unexpected type: mirror"
+                                       return 1
+                               else
+                                       if [[ $stat != $status ]]; then
+                                               log_note "Status($stat) " \
+                                                       "!= Expected stat($status)"
+                                               return 1
+                                       fi
+                                       return 0
+                               fi
+                               ;;
+                       mirror:$device)
+                               if [[ -z "$type" || $type == 'stripe' ]]; then
+                                       log_note "Unexpected type: stripe"
+                                       return 1
+                               else
+                                       if [[ $stat != $status ]]; then
+                                               log_note "Status($stat) " \
+                                                       "!= Expected stat($status)"
+                                               return 1
+                                       fi
+                                       return 0
+                               fi
+                               ;;
+               esac
+
+               ((i += 2))
+       done
+
+       log_note "Can not find device: $device"
+
+       return 1
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_001_pos.ksh
new file mode 100755 (executable)
index 0000000..c6adaa4
--- /dev/null
@@ -0,0 +1,68 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Creating a pool with a log device succeeds.
+#
+# STRATEGY:
+#      1. Create pool with separated log devices.
+#      2. Display pool status
+#      3. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Creating a pool with a log device succeeds."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               for logtype in "" "mirror"
+               do
+                       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+                               $spare $SDEV log $logtype $LDEV
+                       log_must display_status $TESTPOOL
+
+                       ldev=$(random_get $LDEV)
+                       log_must verify_slog_device \
+                               $TESTPOOL $ldev 'ONLINE' $logtype
+
+                       log_must $ZPOOL destroy -f $TESTPOOL
+               done
+       done
+done
+
+log_pass "Creating a pool with a log device succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_002_pos.ksh
new file mode 100755 (executable)
index 0000000..9062772
--- /dev/null
@@ -0,0 +1,67 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Adding a log device to normal pool works.
+#
+# STRATEGY:
+#      1. Create pool
+#      2. Add log devices with different configuration
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Adding a log device to normal pool works."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               for logtype in "" "mirror"
+               do
+                       log_must $ZPOOL create $TESTPOOL $type $VDEV $spare $SDEV
+                       log_must $ZPOOL add $TESTPOOL log $logtype $LDEV
+                       log_must display_status $TESTPOOL
+                       typeset ldev=$(random_get $LDEV)
+                       log_must verify_slog_device \
+                               $TESTPOOL $ldev 'ONLINE' $logtype
+                       log_must $ZPOOL destroy -f $TESTPOOL
+               done
+       done
+done
+
+log_pass "Adding a log device to normal pool works."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_003_pos.ksh
new file mode 100755 (executable)
index 0000000..5a28066
--- /dev/null
@@ -0,0 +1,74 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Adding an extra log device works
+#
+# STRATEGY:
+#      1. Create pool with separated log devices.
+#      2. Add an extra log devices
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Adding an extra log device works."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               for logtype in "" "mirror"
+               do
+                       for newtype in "" "mirror"
+                       do
+                               log_must $ZPOOL create $TESTPOOL $type $VDEV \
+                                       $spare $SDEV log $logtype $LDEV
+                               log_must $ZPOOL add $TESTPOOL \
+                                       log $newtype $LDEV2
+
+                               log_must display_status $TESTPOOL
+                               ldev=$(random_get $LDEV2)
+                               log_must verify_slog_device \
+                                       $TESTPOOL $ldev 'ONLINE' $newtype
+
+                               log_must $ZPOOL destroy -f $TESTPOOL
+                       done
+               done
+       done
+done
+
+log_pass "Adding an extra log device works."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_004_pos.ksh
new file mode 100755 (executable)
index 0000000..83806d0
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Attaching a log device passes.
+#
+# STRATEGY:
+#      1. Create pool with separated log devices.
+#      2. Attaching a log device for existing log device
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Attaching a log device passes."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               for logtype in "" "mirror"
+               do
+                       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+                               $spare $SDEV log $logtype $LDEV
+
+                       ldev=$(random_get $LDEV)
+                       typeset ldev2=$(random_get $LDEV2)
+                       log_must $ZPOOL attach $TESTPOOL $ldev $ldev2
+                       log_must display_status $TESTPOOL
+                       log_must verify_slog_device \
+                               $TESTPOOL $ldev 'ONLINE' 'mirror'
+                       log_must verify_slog_device \
+                               $TESTPOOL $ldev2 'ONLINE' 'mirror'
+
+                       log_must $ZPOOL destroy -f $TESTPOOL
+               done
+       done
+done
+
+log_pass "Attaching a log device passes."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_005_pos.ksh
new file mode 100755 (executable)
index 0000000..f40fc5a
--- /dev/null
@@ -0,0 +1,65 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Detaching a log device passes.
+#
+# STRATEGY:
+#      1. Create pool with mirror log devices.
+#      2. Detaching a log device
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Detaching a log device passes."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               log_must $ZPOOL create $TESTPOOL $type $VDEV $spare $SDEV \
+                       log mirror $LDEV mirror $LDEV2
+               ldev=$(random_get $LDEV $LDEV2)
+               log_must $ZPOOL detach $TESTPOOL $ldev
+               log_must display_status $TESTPOOL
+               log_mustnot verify_slog_device $TESTPOOL $ldev 'ONLINE' 'mirror'
+
+               log_must $ZPOOL destroy -f $TESTPOOL
+       done
+done
+
+log_pass "Detaching a log device passes."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_006_pos.ksh
new file mode 100755 (executable)
index 0000000..b93f64a
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Replacing a log device passes.
+#
+# STRATEGY:
+#      1. Create pool with log devices.
+#      2. Replacing one log device
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Replacing a log device passes."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               for logtype in "" "mirror"
+               do
+                       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+                               $spare $SDEV log $logtype $LDEV
+                       sdev=$(random_get $LDEV)
+                       tdev=$(random_get $LDEV2)
+                       log_must $ZPOOL replace $TESTPOOL $sdev $tdev
+                       log_must display_status $TESTPOOL
+                       # sleep 15 to make sure replacement completely.
+                       log_must $SLEEP 15
+                       log_must verify_slog_device \
+                               $TESTPOOL $tdev 'ONLINE' $logtype
+
+                       log_must $ZPOOL destroy -f $TESTPOOL
+               done
+       done
+done
+
+log_pass "Replacing a log device passes."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_007_pos.ksh
new file mode 100755 (executable)
index 0000000..c643301
--- /dev/null
@@ -0,0 +1,93 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Exporting and importing pool with log devices passes.
+#
+# STRATEGY:
+#      1. Create pool with log devices.
+#      2. Export and import the pool
+#      3. Display pool status
+#      4. Destroy and import the pool again
+#      5. Display pool status
+#      6. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Exporting and importing pool with log devices passes."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               for logtype in "" "mirror"
+               do
+                       #
+                       # Create pool which devices resider in different
+                       # directory
+                       #
+                       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+                               $spare $SDEV log $logtype $LDEV $LDEV2
+                       ldev=$(random_get $LDEV $LDEV2)
+                       log_must verify_slog_device \
+                               $TESTPOOL $ldev 'ONLINE' $logtype
+
+                       #
+                       # Nomal export/import operating
+                       #
+                       log_must $ZPOOL export $TESTPOOL
+                       log_must $ZPOOL import -d $VDIR -d $VDIR2 $TESTPOOL
+                       log_must display_status $TESTPOOL
+                       ldev=$(random_get $LDEV $LDEV2)
+                       log_must verify_slog_device \
+                               $TESTPOOL $ldev 'ONLINE' $logtype
+
+                       #
+                       # Destroy the pool and import again
+                       #
+                       log_must $ZPOOL destroy $TESTPOOL
+                       log_must $ZPOOL import -Df -d $VDIR -d $VDIR2 $TESTPOOL
+                       log_must display_status $TESTPOOL
+                       ldev=$(random_get $LDEV $LDEV2)
+                       log_must verify_slog_device \
+                               $TESTPOOL $ldev 'ONLINE' $logtype
+
+                       log_must $ZPOOL destroy -f $TESTPOOL
+               done
+       done
+done
+
+log_pass "Exporting and importing pool with log devices passes."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_008_neg.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_008_neg.ksh
new file mode 100755 (executable)
index 0000000..b924356
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      A raidz/raidz2 log is not supported.
+#
+# STRATEGY:
+#      1. Try to create pool with unsupported type
+#      2. Verify failed to create pool.
+#
+
+verify_runnable "global"
+
+log_assert "A raidz/raidz2 log is not supported."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               for logtype in "raidz" "raidz1" "raidz2"
+               do
+                       log_mustnot $ZPOOL create $TESTPOOL $type $VDEV \
+                               $spare $SDEV log $logtype $LDEV $LDEV2
+                       ldev=$(random_get $LDEV $LDEV2)
+                       log_mustnot verify_slog_device \
+                               $TESTPOOL $ldev 'ONLINE' $logtype
+                       log_must datasetnonexists $TESTPOOL
+               done
+       done
+done
+
+log_pass "A raidz/raidz2 log is not supported."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_009_neg.ksh
new file mode 100755 (executable)
index 0000000..9b195bd
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      A raidz/raidz2 log can not be added to existed pool.
+#
+# STRATEGY:
+#      1. Create pool with or without log.
+#      2. Add a raidz/raidz2 log to this pool.
+#      3. Verify failed to add.
+#
+
+verify_runnable "global"
+
+log_assert "A raidz/raidz2 log can not be added to existed pool."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               for logtype in "raidz" "raidz1" "raidz2"
+               do
+                       log=$(random_get_with_non "log")
+                       log_must $ZPOOL create $TESTPOOL $type $VDEV \
+                               $spare $SDEV $log $LDEV
+
+                       log_mustnot $ZPOOL add $TESTPOOL log $logtype $LDEV2
+                       ldev=$(random_get $LDEV2)
+                       log_mustnot verify_slog_device \
+                               $TESTPOOL $ldev 'ONLINE' $logtype
+
+                       log_must $ZPOOL destroy $TESTPOOL
+               done
+       done
+done
+
+log_pass "A raidz/raidz2 log can not be added to existed pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_010_neg.ksh
new file mode 100755 (executable)
index 0000000..a5e79f0
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Slog device can not be replaced with spare device
+#
+# STRATEGY:
+#      1. Create a pool with hotspare and log devices.
+#      2. Verify slog device can not be replaced with hotspare device.
+#      3. Create pool2 with hotspare
+#      4. Verify slog device can not be replaced with hotspare device in pool2.
+#
+
+verify_runnable "global"
+
+log_assert "Slog device can not be replaced with spare device."
+log_onexit cleanup
+
+log_must $ZPOOL create $TESTPOOL $VDEV spare $SDEV log $LDEV
+sdev=$(random_get $SDEV)
+ldev=$(random_get $LDEV)
+log_mustnot $ZPOOL replace $TESTPOOL $ldev $sdev
+log_mustnot verify_slog_device $TESTPOOL $sdev 'ONLINE'
+log_must verify_slog_device $TESTPOOL $ldev 'ONLINE'
+
+log_must $ZPOOL create $TESTPOOL2 $VDEV2 spare $SDEV2
+sdev2=$(random_get $SDEV2)
+log_mustnot $ZPOOL replace $TESTPOOL $ldev $sdev2
+log_mustnot $ZPOOL replace -f $TESTPOOL $ldev $sdev2
+log_mustnot verify_slog_device $TESTPOOL $sdev2 'ONLINE'
+log_must verify_slog_device $TESTPOOL $ldev 'ONLINE'
+
+log_pass "Slog device can not be replaced with spare device."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_011_neg.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_011_neg.ksh
new file mode 100755 (executable)
index 0000000..d2fd334
--- /dev/null
@@ -0,0 +1,70 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Offline and online a log device passes.
+#
+# STRATEGY:
+#      1. Create pool with mirror log devices.
+#      2. Offine and online a log device
+#      3. Display pool status
+#      4. Destroy and loop to create pool with different configuration.
+#
+
+verify_runnable "global"
+
+log_assert "Offline and online a log device passes."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               log_must $ZPOOL create $TESTPOOL $type $VDEV $spare $SDEV \
+                       log mirror $LDEV mirror $LDEV2
+
+               ldev=$(random_get $LDEV $LDEV2)
+               log_must $ZPOOL offline $TESTPOOL $ldev
+               log_must display_status $TESTPOOL
+               log_must verify_slog_device $TESTPOOL $ldev 'OFFLINE' 'mirror'
+
+               log_must $ZPOOL online $TESTPOOL $ldev
+               log_must display_status $TESTPOOL
+               log_must verify_slog_device $TESTPOOL $ldev 'ONLINE' 'mirror'
+
+               log_must $ZPOOL destroy -f $TESTPOOL
+       done
+done
+
+log_pass "Offline and online a log device passes."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_012_neg.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_012_neg.ksh
new file mode 100755 (executable)
index 0000000..76cbf15
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Pool can survive when one of mirror log device get corrupted
+#
+# STRATEGY:
+#      1. Create pool with mirror slog devices
+#      2. Make corrupted on one disk
+#      3. Verify the pool is fine
+#
+
+verify_runnable "global"
+
+log_assert "Pool can survive when one of mirror log device get corrupted."
+log_onexit cleanup
+
+for type in "" "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               log_must $ZPOOL create $TESTPOOL $type $VDEV $spare $SDEV \
+                       log mirror $LDEV
+
+               mntpnt=$(get_prop mountpoint $TESTPOOL)
+               #
+               # Create file in pool to trigger writting in slog devices
+               #
+               log_must $DD if=/dev/urandom of=$mntpnt/testfile.$$ count=100
+
+               ldev=$(random_get $LDEV)
+               log_must $MKFILE $SIZE $ldev
+               log_must $ZPOOL scrub $TESTPOOL
+
+               log_must display_status $TESTPOOL
+               log_must verify_slog_device $TESTPOOL $ldev 'UNAVAIL' 'mirror'
+
+               log_must $ZPOOL destroy -f $TESTPOOL
+       done
+done
+
+log_pass "Pool can survive when one of mirror log device get corrupted."
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_013_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_013_pos.ksh
new file mode 100755 (executable)
index 0000000..b2a16b0
--- /dev/null
@@ -0,0 +1,94 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      Verify slog device can be disk, file, lofi device or any device that
+#      presents a block interface.
+#
+# STRATEGY:
+#      1. Create a pool
+#      2. Loop to add different object as slog
+#      3. Verify it passes
+#
+
+verify_runnable "global"
+
+function cleanup_testenv
+{
+       cleanup
+       if datasetexists $TESTPOOL2 ; then
+               log_must $ZPOOL destroy -f $TESTPOOL2
+       fi
+       if [[ -n $lofidev ]]; then
+               $LOFIADM -d $lofidev
+       fi
+}
+
+log_assert "Verify slog device can be disk, file, lofi device or any device " \
+       "that presents a block interface."
+verify_disk_count "$DISKS" 2
+log_onexit cleanup_testenv
+
+dsk1=${DISKS%% *}
+log_must $ZPOOL create $TESTPOOL ${DISKS#$dsk1}
+
+# Add nomal disk
+log_must $ZPOOL add $TESTPOOL log $dsk1
+log_must verify_slog_device $TESTPOOL $dsk1 'ONLINE'
+# Add nomal file
+log_must $ZPOOL add $TESTPOOL log $LDEV
+ldev=$(random_get $LDEV)
+log_must verify_slog_device $TESTPOOL $ldev 'ONLINE'
+
+# Add lofi device
+lofidev=${LDEV2%% *}
+log_must $LOFIADM -a $lofidev
+lofidev=$($LOFIADM $lofidev)
+log_must $ZPOOL add $TESTPOOL log $lofidev
+log_must verify_slog_device $TESTPOOL $lofidev 'ONLINE'
+
+log_pass "Verify slog device can be disk, file, lofi device or any device " \
+       "that presents a block interface."
+
+# Temp disable fore bug 6569095
+# Add file which reside in the itself
+mntpnt=$(get_prop mountpoint $TESTPOOL)
+log_must $MKFILE 100M $mntpnt/vdev
+log_must $ZPOOL add $TESTPOOL $mntpnt/vdev
+
+# Temp disable fore bug 6569072
+# Add ZFS volume
+vol=$TESTPOOL/vol
+log_must $ZPOOL create -V 64M $vol
+log_must $ZPOOL add $TESTPOOL ${ZVOL_DEVDIR}/$vol
diff --git a/zfs/tests/zfs-tests/tests/functional/slog/slog_014_pos.ksh b/zfs/tests/zfs-tests/tests/functional/slog/slog_014_pos.ksh
new file mode 100755 (executable)
index 0000000..5f69b19
--- /dev/null
@@ -0,0 +1,85 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/tests/functional/slog/slog.kshlib
+
+#
+# DESCRIPTION:
+#      log device can survive when one of pool device get corrupted
+#
+# STRATEGY:
+#      1. Create pool with slog devices
+#      2. Corrupt the data on one disk.
+#      3. Verify the log is fine
+#
+
+verify_runnable "global"
+
+log_assert "log device can survive when one of the pool device get corrupted."
+
+for type in "mirror" "raidz" "raidz2"
+do
+       for spare in "" "spare"
+       do
+               log_must $ZPOOL create $TESTPOOL $type $VDEV $spare $SDEV \
+                       log $LDEV
+
+               # Corrupt a pool device to make the pool DEGRADED
+               $DD if=/dev/urandom of=/$TESTPOOL/filler bs=1024k count=50
+               # The oseek value below is to skip past the vdev label.
+               if is_linux; then
+                       log_must $DD if=/dev/urandom of=$VDIR/a bs=1024k \
+                          seek=4 conv=notrunc count=50
+               else
+                       log_must $DD if=/dev/urandom of=$VDIR/a bs=1024k \
+                          oseek=4 conv=notrunc count=50
+               fi
+               log_must $ZPOOL scrub $TESTPOOL
+               log_must display_status $TESTPOOL
+               log_must $ZPOOL status $TESTPOOL 2>&1 >/dev/null
+
+               $ZPOOL status -v $TESTPOOL | \
+                       $GREP "state: DEGRADED" 2>&1 >/dev/null
+               if (( $? != 0 )); then
+                       log_fail "pool $TESTPOOL status should be DEGRADED"
+               fi
+
+               $ZPOOL status -v $TESTPOOL | $GREP logs | \
+                       $GREP "DEGRADED" 2>&1 >/dev/null
+               if (( $? == 0 )); then
+                       log_fail "log device should display correct status"
+               fi
+
+               log_must $ZPOOL destroy -f $TESTPOOL
+       done
+done
+
+log_pass "log device can survive when one of the pool device get corrupted."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/Makefile.am b/zfs/tests/zfs-tests/tests/functional/snapshot/Makefile.am
new file mode 100644 (file)
index 0000000..091434d
--- /dev/null
@@ -0,0 +1,26 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/snapshot
+dist_pkgdata_SCRIPTS = \
+       snapshot.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       clone_001_pos.ksh \
+       rollback_001_pos.ksh \
+       rollback_002_pos.ksh \
+       rollback_003_pos.ksh \
+       snapshot_001_pos.ksh \
+       snapshot_002_pos.ksh \
+       snapshot_003_pos.ksh \
+       snapshot_004_pos.ksh \
+       snapshot_005_pos.ksh \
+       snapshot_006_pos.ksh \
+       snapshot_007_pos.ksh \
+       snapshot_008_pos.ksh \
+       snapshot_009_pos.ksh \
+       snapshot_010_pos.ksh \
+       snapshot_011_pos.ksh \
+       snapshot_012_pos.ksh \
+       snapshot_013_pos.ksh \
+       snapshot_014_pos.ksh \
+       snapshot_015_pos.ksh \
+       snapshot_016_pos.ksh \
+       snapshot_017_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/cleanup.ksh
new file mode 100755 (executable)
index 0000000..c4c3691
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_container_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/clone_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/clone_001_pos.ksh
new file mode 100755 (executable)
index 0000000..9833087
--- /dev/null
@@ -0,0 +1,161 @@
+#! /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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#      Create a snapshot from regular filesystem, volume,
+#      or filesystem upon volume, Build a clone file system
+#      from the snapshot and verify new files can be written.
+#
+# STRATEGY:
+#      1. Create snapshot use 3 combination:
+#              - Regular filesystem
+#              - Regular volume
+#              - Filesystem upon volume
+#      2. Clone a new file system from the snapshot
+#      3. Verify the cloned file system is writable
+#
+
+verify_runnable "both"
+
+# Setup array, 4 elements as a group, refer to:
+# i+0: name of a snapshot
+# i+1: mountpoint of the snapshot
+# i+2: clone created from the snapshot
+# i+3: mountpoint of the clone
+
+set -A args "$SNAPFS" "$SNAPDIR" "$TESTPOOL/$TESTCLONE" "$TESTDIR.0" \
+       "$SNAPFS1" "$SNAPDIR3" "$TESTPOOL/$TESTCLONE1" "" \
+       "$SNAPFS2" "$SNAPDIR2" "$TESTPOOL1/$TESTCLONE2" "$TESTDIR.2"
+
+function setup_all
+{
+       create_pool $TESTPOOL1 ${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+       log_must $ZFS create $TESTPOOL1/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR2 $TESTPOOL1/$TESTFS
+
+       return 0
+}
+
+function cleanup_all
+{
+       typeset -i i=0
+
+       i=0
+       while (( i < ${#args[*]} )); do
+               snapexists ${args[i]} && \
+                       log_must $ZFS destroy -Rf ${args[i]}
+
+               [[ -d ${args[i+3]} ]] && \
+                       log_must $RM -rf ${args[i+3]}
+
+               [[ -d ${args[i+1]} ]] && \
+                       log_must $RM -rf ${args[i+1]}
+
+               (( i = i + 4 ))
+       done
+
+       datasetexists $TESTPOOL1/$TESTFS  && \
+               log_must $ZFS destroy -f $TESTPOOL1/$TESTFS
+
+       destroy_pool $TESTPOOL1
+
+       [[ -d $TESTDIR2 ]] && \
+               log_must $RM -rf $TESTDIR2
+
+       return 0
+}
+
+log_assert "Verify a cloned file system is writable."
+
+log_onexit cleanup_all
+
+setup_all
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+typeset -i COUNT=10
+typeset -i i=0
+
+for mtpt in $TESTDIR $TESTDIR2 ; do
+       log_note "Populate the $mtpt directory (prior to snapshot)"
+       typeset -i j=1
+       while [[ $j -le $COUNT ]]; do
+               log_must $FILE_WRITE -o create -f $mtpt/before_file$j \
+                       -b $BLOCKSZ -c $NUM_WRITES -d $j
+
+               (( j = j + 1 ))
+       done
+done
+
+while (( i < ${#args[*]} )); do
+       #
+       # Take a snapshot of the test file system.
+       #
+       log_must $ZFS snapshot ${args[i]}
+
+       #
+       # Clone a new file system from the snapshot
+       #
+       log_must $ZFS clone ${args[i]} ${args[i+2]}
+       if [[ -n ${args[i+3]} ]] ; then
+               log_must $ZFS set mountpoint=${args[i+3]} ${args[i+2]}
+
+               FILE_COUNT=`$LS -Al ${args[i+3]} | $GREP -v "total" \
+                   | $GREP -v "\.zfs" | wc -l`
+               if [[ $FILE_COUNT -ne $COUNT ]]; then
+                       $LS -Al ${args[i+3]}
+                       log_fail "AFTER: ${args[i+3]} contains $FILE_COUNT files(s)."
+               fi
+
+               log_note "Verify the ${args[i+3]} directory is writable"
+               j=1
+               while [[ $j -le $COUNT ]]; do
+                       log_must $FILE_WRITE -o create -f ${args[i+3]}/after_file$j \
+                       -b $BLOCKSZ -c $NUM_WRITES -d $j
+                       (( j = j + 1 ))
+               done
+
+               FILE_COUNT=`$LS -Al ${args[i+3]}/after* | $GREP -v "total" | wc -l`
+               if [[ $FILE_COUNT -ne $COUNT ]]; then
+                       $LS -Al ${args[i+3]}
+                       log_fail "${args[i+3]} contains $FILE_COUNT after* files(s)."
+               fi
+       fi
+
+       (( i = i + 4 ))
+done
+
+log_pass "The clone file system is writable."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/rollback_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/rollback_001_pos.ksh
new file mode 100755 (executable)
index 0000000..e5df02d
--- /dev/null
@@ -0,0 +1,115 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# Populate a file system and take a snapshot. Add some more files to the
+# file system and rollback to the last snapshot. Verify no post snapshot
+# file exist.
+#
+# STRATEGY:
+# 1. Empty a file system
+# 2. Populate the file system
+# 3. Take a snapshot of the file system
+# 4. Add new files to the file system
+# 5. Perform a rollback
+# 6. Verify the snapshot and file system agree
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       snapexists $SNAPFS
+       [[ $? -eq 0 ]] && \
+               log_must $ZFS destroy $SNAPFS
+
+       [[ -e $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+}
+
+log_assert "Verify that a rollback to a previous snapshot succeeds."
+
+log_onexit cleanup
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+typeset -i COUNT=10
+
+log_note "Populate the $TESTDIR directory (prior to snapshot)"
+typeset -i i=1
+while [[ $i -le $COUNT ]]; do
+       log_must $FILE_WRITE -o create -f $TESTDIR/before_file$i \
+          -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+       (( i = i + 1 ))
+done
+
+log_must $ZFS snapshot $SNAPFS
+
+FILE_COUNT=`$LS -Al $SNAPDIR | $GREP -v "total" | wc -l`
+if [[ $FILE_COUNT -ne $COUNT ]]; then
+        $LS -Al $SNAPDIR
+        log_fail "AFTER: $SNAPFS contains $FILE_COUNT files(s)."
+fi
+
+log_note "Populate the $TESTDIR directory (post snapshot)"
+typeset -i i=1
+while [[ $i -le $COUNT ]]; do
+        log_must $FILE_WRITE -o create -f $TESTDIR/after_file$i \
+           -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+        (( i = i + 1 ))
+done
+
+#
+# Now rollback to latest snapshot
+#
+log_must $ZFS rollback $SNAPFS
+
+FILE_COUNT=`$LS -Al $TESTDIR/after* 2> /dev/null | $GREP -v "total" | wc -l`
+if [[ $FILE_COUNT -ne 0 ]]; then
+        $LS -Al $TESTDIR
+        log_fail "$TESTDIR contains $FILE_COUNT after* files(s)."
+fi
+
+FILE_COUNT=`$LS -Al $TESTDIR/before* 2> /dev/null \
+    | $GREP -v "total" | wc -l`
+if [[ $FILE_COUNT -ne $COUNT ]]; then
+       $LS -Al $TESTDIR
+       log_fail "$TESTDIR contains $FILE_COUNT before* files(s)."
+fi
+
+log_pass "The rollback operation succeeded."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/rollback_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/rollback_002_pos.ksh
new file mode 100755 (executable)
index 0000000..76b8c84
--- /dev/null
@@ -0,0 +1,133 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# Verify that rollbacks are with respect to the latest snapshot.
+#
+# STRATEGY:
+# 1. Empty a file system
+# 2. Populate the file system
+# 3. Take a snapshot of the file system
+# 4. Add new files to the file system
+# 5. Take a snapshot
+# 6. Remove the original files
+# 7. Perform a rollback
+# 8. Verify the latest snapshot and file system agree
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       snapexists $SNAPFS.1
+       [[ $? -eq 0 ]] && \
+               log_must $ZFS destroy $SNAPFS.1
+
+       snapexists $SNAPFS
+       [[ $? -eq 0 ]] && \
+               log_must $ZFS destroy $SNAPFS
+
+       [[ -e $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+}
+
+log_assert "Verify rollback is with respect to latest snapshot."
+
+log_onexit cleanup
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+typeset -i COUNT=10
+
+log_note "Populate the $TESTDIR directory (prior to first snapshot)"
+typeset -i i=1
+while [[ $i -le $COUNT ]]; do
+       log_must $FILE_WRITE -o create -f $TESTDIR/original_file$i \
+          -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+       (( i = i + 1 ))
+done
+
+log_must $ZFS snapshot $SNAPFS
+
+FILE_COUNT=`$LS -Al $SNAPDIR | $GREP -v "total" | wc -l`
+if [[ $FILE_COUNT -ne $COUNT ]]; then
+        $LS -Al $SNAPDIR
+        log_fail "AFTER: $SNAPFS contains $FILE_COUNT files(s)."
+fi
+
+log_note "Populate the $TESTDIR directory (prior to second snapshot)"
+typeset -i i=1
+while [[ $i -le $COUNT ]]; do
+        log_must $FILE_WRITE -o create -f $TESTDIR/afterfirst_file$i \
+           -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+        (( i = i + 1 ))
+done
+
+log_must $ZFS snapshot $SNAPFS.1
+
+log_note "Populate the $TESTDIR directory (Post second snapshot)"
+typeset -i i=1
+while [[ $i -le $COUNT ]]; do
+        log_must $FILE_WRITE -o create -f $TESTDIR/aftersecond_file$i \
+           -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+        (( i = i + 1 ))
+done
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/original_file* > /dev/null 2>&1
+
+#
+# Now rollback to latest snapshot
+#
+log_must $ZFS rollback $SNAPFS.1
+
+FILE_COUNT=`$LS -Al $TESTDIR/aftersecond* 2> /dev/null \
+    | $GREP -v "total" | wc -l`
+if [[ $FILE_COUNT -ne 0 ]]; then
+        $LS -Al $TESTDIR
+        log_fail "$TESTDIR contains $FILE_COUNT aftersecond* files(s)."
+fi
+
+FILE_COUNT=`$LS -Al $TESTDIR/original* $TESTDIR/afterfirst*| $GREP -v "total" | wc -l`
+if [[ $FILE_COUNT -ne 20 ]]; then
+        $LS -Al $TESTDIR
+        log_fail "$TESTDIR contains $FILE_COUNT original* files(s)."
+fi
+
+log_pass "The rollback to the latest snapshot succeeded."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/rollback_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/rollback_003_pos.ksh
new file mode 100755 (executable)
index 0000000..4c9ef68
--- /dev/null
@@ -0,0 +1,106 @@
+#! /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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+
+#
+# DESCRIPTION:
+# Verify that rollbacks succeed when there are nested file systems.
+#
+# STRATEGY:
+# 1) Snapshot an empty file system and rollback
+# 2) Create a file in the file system
+# 3) Rollback the file system to empty
+# 4) Create a nested file system with the same name as the file created in (2)
+# 5) Verify a rollback succeeds
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset snap=""
+       typeset fs=""
+
+       export __ZFS_POOL_RESTRICT="$TESTPOOL"
+       log_must $ZFS mount -a
+       unset __ZFS_POOL_RESTRICT
+
+       for snap in "$SNAPPOOL.1" "$SNAPPOOL"
+       do
+               snapexists $snap
+               [[ $? -eq 0 ]] && \
+                       log_must $ZFS destroy $snap
+       done
+
+       for fs in "$TESTPOOL/$TESTFILE/$TESTFILE.1" "$TESTPOOL/$TESTFILE"
+       do
+               datasetexists $fs
+               [[ $? -eq 0 ]] && \
+                       log_must $ZFS destroy -r $fs
+       done
+
+       [[ -e /$TESTPOOL ]] && \
+               log_must $RM -rf $TESTPOOL/*
+}
+
+log_assert "Verify rollback succeeds when there are nested file systems."
+
+log_onexit cleanup
+
+log_must $ZFS snapshot $SNAPPOOL
+log_must $ZFS rollback $SNAPPOOL
+log_mustnot $ZFS snapshot $SNAPPOOL
+
+log_must $TOUCH /$TESTPOOL/$TESTFILE
+
+log_must $ZFS rollback $SNAPPOOL
+log_must $ZFS create $TESTPOOL/$TESTFILE
+
+log_must $ZFS rollback $SNAPPOOL
+
+log_note "Verify rollback of multiple nested file systems succeeds."
+log_must $ZFS snapshot $TESTPOOL/$TESTFILE@$TESTSNAP
+log_must $ZFS snapshot $SNAPPOOL.1
+
+export __ZFS_POOL_RESTRICT="$TESTPOOL"
+log_must $ZFS unmount -a
+log_must $ZFS mount -a
+unset __ZFS_POOL_RESTRICT
+
+log_must $TOUCH /$TESTPOOL/$TESTFILE/$TESTFILE.1
+
+log_must $ZFS rollback $SNAPPOOL.1
+
+log_pass "Rollbacks succeed when nested file systems are present."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/setup.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/setup.ksh
new file mode 100755 (executable)
index 0000000..d8733f3
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_container_volume_setup ${DISK}
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot.cfg b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot.cfg
new file mode 100644 (file)
index 0000000..fa31645
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export TESTFILE=testfile-snapshot
+export SNAPROOT=".zfs/snapshot"
+
+export SNAPPOOL="$TESTPOOL@$TESTSNAP"
+export SNAPFS="$TESTPOOL/$TESTFS@$TESTSNAP"
+export SNAPFS1="$TESTPOOL/$TESTVOL@$TESTSNAP"
+export SNAPFS2="$TESTPOOL1/$TESTFS@$TESTSNAP"
+export SNAPCTR="$TESTPOOL/$TESTCTR/$TESTFS1@$TESTSNAP"
+export SNAPDIR="$TESTDIR/$SNAPROOT/$TESTSNAP"
+export SNAPDIR1="$TESTDIR1/$SNAPROOT/$TESTSNAP"
+export SNAPDIR2="$TESTDIR2/$SNAPROOT/$TESTSNAP"
+export SNAPDIR3="/$SNAPFS1"
+
+export VOLSIZE=1gb
+export BLOCKSZ=8192
+export NUM_WRITES=20
+export DATA=0
+export LIMIT=524288 # tolerance measured in bytes, 512K
+export FSQUOTA=500m
+export FILESIZE=400m
+export FILESIZE1=200m
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_001_pos.ksh
new file mode 100755 (executable)
index 0000000..832ca1e
--- /dev/null
@@ -0,0 +1,91 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# A zfs file system snapshot is identical to
+# the originally snapshot'd file system, after the file
+# system has been changed. Uses 'sum -r'.
+#
+# STRATEGY:
+# 1. Create a file in the zfs file system
+# 2. Checksum the file for later comparison
+# 3. Create a snapshot of the dataset
+# 4. Append to the original file
+# 5. Verify the snapshot and file agree
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       snapexists $SNAPFS
+       if [[ $? -eq 0 ]]; then
+               log_must $ZFS destroy $SNAPFS
+       fi
+
+       if [[ -e $SNAPDIR ]]; then
+               log_must $RM -rf $SNAPDIR > /dev/null 2>&1
+       fi
+
+       if [[ -e $TESTDIR ]]; then
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+       fi
+}
+
+log_assert "Verify a file system snapshot is identical to original."
+
+log_onexit cleanup
+
+log_note "Create a file in the zfs filesystem..."
+log_must $FILE_WRITE -o create -f $TESTDIR/$TESTFILE -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+
+log_note "Sum the file, save for later comparison..."
+FILE_SUM=`$SUM -r $TESTDIR/$TESTFILE | $AWK  '{ print $1 }'`
+log_note "FILE_SUM = $FILE_SUM"
+
+log_note "Create a snapshot and mount it..."
+log_must $ZFS snapshot $SNAPFS
+
+log_note "Append to the original file..."
+log_must $FILE_WRITE -o append -f $TESTDIR/$TESTFILE -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+
+SNAP_FILE_SUM=`$SUM -r $SNAPDIR/$TESTFILE | $AWK '{ print $1 }'`
+if [[ $SNAP_FILE_SUM -ne $FILE_SUM ]]; then
+       log_fail "Sums do not match, aborting!! ($SNAP_FILE_SUM != $FILE_SUM)"
+fi
+
+log_pass "Both Sums match. ($SNAP_FILE_SUM == $FILE_SUM)"
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_002_pos.ksh
new file mode 100755 (executable)
index 0000000..040f3ac
--- /dev/null
@@ -0,0 +1,134 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# An archive of a zfs file system and an archive of its snapshot
+# is identical even though the original file system has
+# changed sinced the snapshot was taken.
+#
+# STRATEGY:
+# 1) Create files in all of the zfs file systems
+# 2) Create a tarball of the file system
+# 3) Create a snapshot of the dataset
+# 4) Remove all the files in the original file system
+# 5) Create a tarball of the snapshot
+# 6) Extract each tarball and compare directory structures
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if [[ -d $CWD ]]; then
+               cd $CWD || log_fail "Could not cd $CWD"
+       fi
+
+        snapexists $SNAPFS
+        if [[ $? -eq 0 ]]; then
+                log_must $ZFS destroy $SNAPFS
+        fi
+
+        if [[ -e $SNAPDIR ]]; then
+                log_must $RM -rf $SNAPDIR > /dev/null 2>&1
+        fi
+
+        if [[ -e $TESTDIR ]]; then
+                log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+        fi
+
+       if [[ -e /tmp/zfs_snapshot2.$$ ]]; then
+               log_must $RM -rf /tmp/zfs_snapshot2.$$ > /dev/null 2>&1
+       fi
+
+}
+
+log_assert "Verify an archive of a file system is identical to " \
+    "an archive of its snapshot."
+
+log_onexit cleanup
+
+typeset -i COUNT=21
+typeset OP=create
+
+[[ -n $TESTDIR ]] && \
+    $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+log_note "Create files in the zfs filesystem..."
+
+typeset i=1
+while [ $i -lt $COUNT ]; do
+       log_must $FILE_WRITE -o $OP -f $TESTDIR/file$i \
+           -b $BLOCKSZ -c $NUM_WRITES -d $DATA
+
+       (( i = i + 1 ))
+done
+
+log_note "Create a tarball from $TESTDIR contents..."
+CWD=$PWD
+cd $TESTDIR || log_fail "Could not cd $TESTDIR"
+log_must $TAR cf $TESTDIR/tarball.original.tar file*
+cd $CWD || log_fail "Could not cd $CWD"
+
+log_note "Create a snapshot and mount it..."
+log_must $ZFS snapshot $SNAPFS
+
+log_note "Remove all of the original files..."
+log_must $RM -f $TESTDIR/file* > /dev/null 2>&1
+
+log_note "Create tarball of snapshot..."
+CWD=$PWD
+cd $SNAPDIR || log_fail "Could not cd $SNAPDIR"
+log_must $TAR cf $TESTDIR/tarball.snapshot.tar file*
+cd $CWD || log_fail "Could not cd $CWD"
+
+log_must $MKDIR $TESTDIR/original
+log_must $MKDIR $TESTDIR/snapshot
+
+CWD=$PWD
+cd $TESTDIR/original || log_fail "Could not cd $TESTDIR/original"
+log_must $TAR xf $TESTDIR/tarball.original.tar
+
+cd $TESTDIR/snapshot || log_fail "Could not cd $TESTDIR/snapshot"
+log_must $TAR xf $TESTDIR/tarball.snapshot.tar
+
+cd $CWD || log_fail "Could not cd $CWD"
+
+$DIRCMP $TESTDIR/original $TESTDIR/snapshot > /tmp/zfs_snapshot2.$$
+$GREP different /tmp/zfs_snapshot2.$$ >/dev/null 2>&1
+if [[ $? -ne 1 ]]; then
+       log_fail "Directory structures differ."
+fi
+
+log_pass "Directory structures match."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_003_pos.ksh
new file mode 100755 (executable)
index 0000000..f30629f
--- /dev/null
@@ -0,0 +1,103 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# Verify that many snapshots can be made on a zfs file system.
+#
+# STRATEGY:
+# 1) Create a files in the zfs file system
+# 2) Create a snapshot of the dataset
+# 3) Remove all the files from the original file system
+# 4) Verify consistency of each snapshot directory
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset -i i=1
+       while [ $i -lt $COUNT ]; do
+               snapexists $SNAPFS.$i
+               if [[ $? -eq 0 ]]; then
+                       log_must $ZFS destroy $SNAPFS.$i
+               fi
+
+               if [[ -e $SNAPDIR.$i ]]; then
+                       log_must $RM -rf $SNAPDIR.$i > /dev/null 2>&1
+               fi
+
+               (( i = i + 1 ))
+       done
+
+       if [[ -e $TESTDIR ]]; then
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+       fi
+}
+
+log_assert "Verify many snapshots of a file system can be taken."
+
+log_onexit cleanup
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+typeset -i COUNT=10
+
+log_note "Create some files in the $TESTDIR directory..."
+typeset -i i=1
+while [[ $i -lt $COUNT ]]; do
+       log_must $FILE_WRITE -o create -f $TESTDIR/file$i \
+          -b $BLOCKSZ -c $NUM_WRITES -d $i
+       log_must $ZFS snapshot $SNAPFS.$i
+
+       (( i = i + 1 ))
+done
+
+log_note "Remove all of the original files"
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/file* > /dev/null 2>&1
+
+i=1
+while [[ $i -lt $COUNT ]]; do
+       FILECOUNT=`$LS $SNAPDIR.$i/file* | wc -l`
+       typeset j=1
+       while [ $j -lt $FILECOUNT ]; do
+               log_must $FILE_CHECK $SNAPDIR.$i/file$j $j
+               (( j = j + 1 ))
+       done
+       (( i = i + 1 ))
+done
+
+log_pass "All files are consistent"
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_004_pos.ksh
new file mode 100755 (executable)
index 0000000..e104007
--- /dev/null
@@ -0,0 +1,90 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# Create a null snapshot i.e. a snapshot created before file system
+# activity is empty.
+#
+# STRATEGY:
+# 1. Empty a file system
+# 2. Take a snapshot of the empty file system.
+# 3. Populate the file system
+# 4. Verify the snapshot is still empty
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       snapexists $SNAPFS
+       [[ $? -eq 0 ]] && \
+               log_must $ZFS destroy $SNAPFS
+
+       [[ -e $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+}
+
+log_assert "Verify that a snapshot of an empty file system remains empty."
+
+log_onexit cleanup
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+log_must $ZFS snapshot $SNAPFS
+FILE_COUNT=`$LS -Al $SNAPDIR | $GREP -v "total 0" | wc -l`
+if [[ $FILE_COUNT -ne 0 ]]; then
+       $LS $SNAPDIR
+       log_fail "BEFORE: $SNAPDIR contains $FILE_COUNT files(s)."
+fi
+
+typeset -i COUNT=10
+
+log_note "Populate the $TESTDIR directory"
+typeset -i i=1
+while [[ $i -lt $COUNT ]]; do
+       log_must $FILE_WRITE -o create -f $TESTDIR/file$i \
+          -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+       (( i = i + 1 ))
+done
+
+FILE_COUNT=`$LS -Al $SNAPDIR | $GREP -v "total 0" | wc -l`
+if [[ $FILE_COUNT -ne 0 ]]; then
+        $LS $SNAPDIR
+        log_fail "AFTER: $SNAPDIR contains $FILE_COUNT files(s)."
+fi
+
+log_pass "The NULL snapshot remains empty."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_005_pos.ksh
new file mode 100755 (executable)
index 0000000..8c73639
--- /dev/null
@@ -0,0 +1,90 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# to the originally snapshot'd file system, after the file
+# system has been changed. Uses 'sum -r'.
+#
+# STRATEGY:
+# 1) Create a file in the zfs dataset
+# 2) Sum the file for later comparison
+# 3) Create a snapshot of the dataset
+# 4) Append to the original file
+# 5) Verify both checksums match
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       snapexists $SNAPCTR
+       if [[ $? -eq 0 ]]; then
+               log_must $ZFS destroy $SNAPCTR
+       fi
+
+       if [[ -e $SNAPDIR1 ]]; then
+               log_must $RM -rf $SNAPDIR1 > /dev/null 2>&1
+       fi
+
+       if [[ -e $TESTDIR ]]; then
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+       fi
+}
+
+log_assert "Verify that a snapshot of a dataset is identical to " \
+    "the original dataset."
+log_onexit cleanup
+
+log_note "Create a file in the zfs filesystem..."
+log_must $FILE_WRITE -o create -f $TESTDIR1/$TESTFILE -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+
+log_note "Sum the file, save for later comparison..."
+FILE_SUM=`$SUM -r $TESTDIR1/$TESTFILE | $AWK  '{ print $1 }'`
+log_note "FILE_SUM = $FILE_SUM"
+
+log_note "Create a snapshot and mount it..."
+log_must $ZFS snapshot $SNAPCTR
+
+log_note "Append to the original file..."
+log_must $FILE_WRITE -o append -f $TESTDIR1/$TESTFILE -b $BLOCKSZ \
+    -c $NUM_WRITES -d $DATA
+
+SNAP_FILE_SUM=`$SUM -r $SNAPDIR1/$TESTFILE | $AWK '{ print $1 }'`
+if [[ $SNAP_FILE_SUM -ne $FILE_SUM ]]; then
+       log_fail "Sums do not match, aborting!! ($SNAP_FILE_SUM != $FILE_SUM)"
+fi
+
+log_pass "Both Sums match. ($SNAP_FILE_SUM == $FILE_SUM)"
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_006_pos.ksh
new file mode 100755 (executable)
index 0000000..cc2c6ed
--- /dev/null
@@ -0,0 +1,132 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# An archive of a zfs dataset and an archive of its snapshot
+# changed sinced the snapshot was taken.
+#
+# STRATEGY:
+# 1) Create some files in a ZFS dataset
+# 2) Create a tarball of the dataset
+# 3) Create a snapshot of the dataset
+# 4) Remove all the files in the original dataset
+# 5) Create a tarball of the snapshot
+# 6) Extract each tarball and compare directory structures
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if [[ -d $CWD ]]; then
+               cd $CWD || log_fail "Could not cd $CWD"
+       fi
+
+        snapexists $SNAPCTR
+        if [[ $? -eq 0 ]]; then
+                log_must $ZFS destroy $SNAPCTR
+        fi
+
+        if [[ -e $SNAPDIR1 ]]; then
+                log_must $RM -rf $SNAPDIR1 > /dev/null 2>&1
+        fi
+
+        if [[ -e $TESTDIR1 ]]; then
+                log_must $RM -rf $TESTDIR1/* > /dev/null 2>&1
+        fi
+
+       if [[ -e /tmp/zfs_snapshot2.$$ ]]; then
+               log_must $RM -rf /tmp/zfs_snapshot2.$$ > /dev/null 2>&1
+       fi
+
+}
+
+log_assert "Verify that an archive of a dataset is identical to " \
+   "an archive of the dataset's snapshot."
+
+log_onexit cleanup
+
+typeset -i COUNT=21
+typeset OP=create
+
+[[ -n $TESTDIR1 ]] && $RM -rf $TESTDIR1/* > /dev/null 2>&1
+
+log_note "Create files in the zfs dataset ..."
+
+typeset i=1
+while [ $i -lt $COUNT ]; do
+       log_must $FILE_WRITE -o $OP -f $TESTDIR1/file$i \
+           -b $BLOCKSZ -c $NUM_WRITES -d $DATA
+
+       (( i = i + 1 ))
+done
+
+log_note "Create a tarball from $TESTDIR1 contents..."
+CWD=$PWD
+cd $TESTDIR1 || log_fail "Could not cd $TESTDIR1"
+log_must $TAR cf $TESTDIR1/tarball.original.tar file*
+cd $CWD || log_fail "Could not cd $CWD"
+
+log_note "Create a snapshot and mount it..."
+log_must $ZFS snapshot $SNAPCTR
+
+log_note "Remove all of the original files..."
+log_must $RM -f $TESTDIR1/file* > /dev/null 2>&1
+
+log_note "Create tarball of snapshot..."
+CWD=$PWD
+cd $SNAPDIR1 || log_fail "Could not cd $SNAPDIR1"
+log_must $TAR cf $TESTDIR1/tarball.snapshot.tar file*
+cd $CWD || log_fail "Could not cd $CWD"
+
+log_must $MKDIR $TESTDIR1/original
+log_must $MKDIR $TESTDIR1/snapshot
+
+CWD=$PWD
+cd $TESTDIR1/original || log_fail "Could not cd $TESTDIR1/original"
+log_must $TAR xf $TESTDIR1/tarball.original.tar
+
+cd $TESTDIR1/snapshot || log_fail "Could not cd $TESTDIR1/snapshot"
+log_must $TAR xf $TESTDIR1/tarball.snapshot.tar
+
+cd $CWD || log_fail "Could not cd $CWD"
+
+$DIRCMP $TESTDIR1/original $TESTDIR1/snapshot > /tmp/zfs_snapshot2.$$
+$GREP different /tmp/zfs_snapshot2.$$ >/dev/null 2>&1
+if [[ $? -ne 1 ]]; then
+       log_fail "Directory structures differ."
+fi
+
+log_pass "Directory structures match."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_007_pos.ksh
new file mode 100755 (executable)
index 0000000..5ee9f5d
--- /dev/null
@@ -0,0 +1,107 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# Verify that many snapshots can be made on a zfs dataset.
+#
+# STRATEGY:
+# 1) Create a file in the zfs dataset
+# 2) Create a snapshot of the dataset
+# 3) Remove all the files from the original dataset
+# 4) For each snapshot directory verify consistency
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset -i i=1
+       while [ $i -lt $COUNT ]; do
+               snapexists $SNAPCTR.$i
+               if [[ $? -eq 0 ]]; then
+                       log_must $ZFS destroy $SNAPCTR.$i
+               fi
+
+               if [[ -e $SNAPDIR.$i ]]; then
+                       log_must $RM -rf $SNAPDIR1.$i > /dev/null 2>&1
+               fi
+
+               (( i = i + 1 ))
+       done
+
+       if [[ -e $SNAPDIR1 ]]; then
+               log_must $RM -rf $SNAPDIR1 > /dev/null 2>&1
+       fi
+
+       if [[ -e $TESTDIR ]]; then
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+       fi
+}
+
+log_assert "Verify that many snapshots can be made on a zfs dataset."
+
+log_onexit cleanup
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+typeset -i COUNT=10
+
+log_note "Create some files in the $TESTDIR directory..."
+typeset -i i=1
+while [[ $i -lt $COUNT ]]; do
+       log_must $FILE_WRITE -o create -f $TESTDIR1/file$i \
+          -b $BLOCKSZ -c $NUM_WRITES -d $i
+       log_must $ZFS snapshot $SNAPCTR.$i
+
+       (( i = i + 1 ))
+done
+
+log_note "Remove all of the original files"
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR1/file* > /dev/null 2>&1
+
+i=1
+while [[ $i -lt $COUNT ]]; do
+       FILECOUNT=`$LS $SNAPDIR1.$i/file* | wc -l`
+       typeset j=1
+       while [ $j -lt $FILECOUNT ]; do
+               log_must $FILE_CHECK $SNAPDIR1.$i/file$j $j
+               (( j = j + 1 ))
+       done
+       (( i = i + 1 ))
+done
+
+log_pass "All files are consistent"
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_008_pos.ksh
new file mode 100755 (executable)
index 0000000..3610491
--- /dev/null
@@ -0,0 +1,100 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+# Verify that destroying snapshots returns space to the pool.
+#
+# STRATEGY:
+# 1. Create a file system and populate it while snapshotting.
+# 2. Destroy the snapshots and remove the files.
+# 3. Verify the space returns to the pool.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset -i i=1
+       while [[ $i -lt $COUNT ]]; do
+               snapexists $SNAPFS.$i
+               [[ $? -eq 0 ]] && \
+                       log_must $ZFS destroy $SNAPFS.$i
+
+               (( i = i + 1 ))
+       done
+
+       [[ -e $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+}
+
+log_assert "Verify that destroying snapshots returns space to the pool."
+
+log_onexit cleanup
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+typeset -i COUNT=10
+
+orig_size=`get_prop available $TESTPOOL`
+
+log_note "Populate the $TESTDIR directory"
+typeset -i i=1
+while [[ $i -lt $COUNT ]]; do
+       log_must $FILE_WRITE -o create -f $TESTDIR/file$i \
+          -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+       log_must $ZFS snapshot $SNAPFS.$i
+       (( i = i + 1 ))
+done
+
+typeset -i i=1
+while [[ $i -lt $COUNT ]]; do
+       log_must rm -rf $TESTDIR/file$i > /dev/null 2>&1
+       log_must $ZFS destroy $SNAPFS.$i
+
+       (( i = i + 1 ))
+done
+
+new_size=`get_prop available $TESTPOOL`
+
+typeset -i tolerance=0
+
+(( tolerance = new_size - orig_size))
+if (( tolerance > LIMIT )); then
+        log_fail "Space not freed. ($orig_size != $new_size)"
+fi
+
+log_pass "After destroying snapshots, the space is returned to the pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_009_pos.ksh
new file mode 100755 (executable)
index 0000000..dfc75d8
--- /dev/null
@@ -0,0 +1,119 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#      Verify 'snapshot -r' and 'destroy -r' can correctly create and destroy
+#      snapshot tree respectively.
+#
+# STRATEGY:
+# 1. Use the snapshot -r to create snapshot for top level pool
+# 2. Verify the children snapshots are created correctly.
+# 3. Use destroy -r to destroy the top level snapshot
+# 4. Verify that all children snapshots are destroyed too.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset ds
+       typeset snap
+
+       for ds in $ctr/$TESTVOL1 $ctr/$TESTCLONE; do
+               datasetexists $ds && \
+                       log_must $ZFS destroy -f $ds
+       done
+
+       for snap in $ctr/$TESTFS1@$TESTSNAP1 \
+               $snappool $snapvol $snapctr $snapctrvol \
+               $snapctrclone $snapctrfs
+       do
+               snapexists $snap && \
+                       log_must $ZFS destroy -rf $snap
+       done
+
+}
+
+log_assert "Verify snapshot -r can correctly create a snapshot tree."
+log_onexit cleanup
+
+ctr=$TESTPOOL/$TESTCTR
+ctrfs=$ctr/$TESTFS1
+ctrclone=$ctr/$TESTCLONE
+ctrvol=$ctr/$TESTVOL1
+snappool=$SNAPPOOL
+snapfs=$SNAPFS
+snapctr=$ctr@$TESTSNAP
+snapvol=$SNAPFS1
+snapctrvol=$ctrvol@$TESTSNAP
+snapctrclone=$ctrclone@$TESTSNAP
+snapctrfs=$SNAPCTR
+
+#preparation for testing
+log_must $ZFS snapshot $ctrfs@$TESTSNAP1
+log_must $ZFS clone $ctrfs@$TESTSNAP1 $ctrclone
+if is_global_zone; then
+       log_must $ZFS create -V $VOLSIZE $ctrvol
+else
+       log_must $ZFS create $ctrvol
+fi
+
+log_must $ZFS snapshot -r $snappool
+
+#verify the snapshot -r results
+for snap in $snappool $snapfs $snapvol $snapctr $snapctrvol \
+               $snapctrclone $snapctrfs
+do
+       ! snapexists $snap && \
+               log_fail "The snapshot $snap is not created via -r option."
+done
+
+log_note "Verify that destroy -r can destroy the snapshot tree."
+
+log_must $ZFS destroy -r $snappool
+for snap in $snappool $snapfs $snapvol $snapctr $snapctrvol \
+               $snapctrclone $snapctrfs
+do
+       snapexists $snap && \
+               log_fail "The snapshot $snap is not destroyed correctly."
+done
+
+log_note "Verify that the snapshot with different name should \
+               be not destroyed."
+! snapexists $ctrfs@$TESTSNAP1 && \
+       log_fail "destroy -r incorrectly destroys the snapshot \
+               $ctrfs@$TESTSNAP1."
+
+log_pass  "snapshot|destroy -r with snapshot tree works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_010_pos.ksh
new file mode 100755 (executable)
index 0000000..cb9ff88
--- /dev/null
@@ -0,0 +1,101 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#      Verify 'destroy -r' can correctly destroy a snapshot tree at any point.
+#
+# STRATEGY:
+# 1. Use the snapshot -r to create snapshot for top level pool
+# 2. Select a middle point of the snapshot tree, use destroy -r to destroy all
+#      snapshots beneath the point.
+# 3. Verify the destroy results.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset snap
+
+       datasetexists $ctrvol && \
+               log_must $ZFS destroy -f $ctrvol
+
+       for snap in $ctrfs@$TESTSNAP1 \
+               $snappool $snapvol $snapctr $snapctrvol \
+               $snapctrclone $snapctrfs
+       do
+               snapexists $snap && \
+                       log_must $ZFS destroy -rf $snap
+       done
+
+}
+
+log_assert "Verify 'destroy -r' can correctly destroy a snapshot subtree at any point."
+log_onexit cleanup
+
+ctr=$TESTPOOL/$TESTCTR
+ctrfs=$ctr/$TESTFS1
+ctrvol=$ctr/$TESTVOL1
+snappool=$SNAPPOOL
+snapfs=$SNAPFS
+snapctr=$ctr@$TESTSNAP
+snapvol=$SNAPFS1
+snapctrvol=$ctr/$TESTVOL1@$TESTSNAP
+snapctrclone=$ctr/$TESTCLONE@$TESTSNAP
+snapctrfs=$SNAPCTR
+
+#preparation for testing
+log_must $ZFS snapshot $ctrfs@$TESTSNAP1
+if is_global_zone; then
+       log_must $ZFS create -V $VOLSIZE $ctrvol
+else
+       log_must $ZFS create $ctrvol
+fi
+
+log_must $ZFS snapshot -r $snappool
+
+#select the $TESTCTR as destroy point, $TESTCTR is a child of $TESTPOOL
+log_must $ZFS destroy -r $snapctr
+for snap in $snapctr $snapctrvol $snapctrclone $snapctrfs; do
+       snapexists $snap && \
+               log_fail "The snapshot $snap is not destroyed correctly."
+done
+
+for snap in $snappool $snapfs $snapvol $ctrfs@$TESTSNAP1;do
+       ! snapexists $snap && \
+               log_fail "The snapshot $snap should be not destroyed."
+done
+
+log_pass  "'destroy -r' destroys snapshot subtree as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_011_pos.ksh
new file mode 100755 (executable)
index 0000000..9774035
--- /dev/null
@@ -0,0 +1,113 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#      use 'snapshot -r' to create a snapshot tree, add some files to one child
+#      filesystem, rollback the child filesystem snapshot, verify that the child
+#      filesystem gets back to the status while taking the snapshot.
+#
+# STRATEGY:
+#      1. Add some files to a target child filesystem
+#      2. snapshot -r the parent filesystem
+#      3. Add some other files to the target child filesystem
+#      4. rollback the child filesystem snapshot
+#      5. verify that the child filesystem get back to the status while being
+#         snapshot'd
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       snapexists $SNAPPOOL && \
+               log_must $ZFS destroy -r $SNAPPOOL
+
+       [[ -e $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+}
+
+log_assert "Verify that rollback to a snapshot created by snapshot -r succeeds."
+log_onexit cleanup
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+typeset -i COUNT=10
+
+log_note "Populate the $TESTDIR directory (prior to snapshot)"
+typeset -i i=0
+while (( i < COUNT )); do
+       log_must $FILE_WRITE -o create -f $TESTDIR/before_file$i \
+          -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+       (( i = i + 1 ))
+done
+
+log_must $ZFS snapshot -r $SNAPPOOL
+
+FILE_COUNT=`$LS -Al $SNAPDIR | $GREP -v "total" | wc -l`
+if (( FILE_COUNT != COUNT )); then
+        $LS -Al $SNAPDIR
+        log_fail "AFTER: $SNAPFS contains $FILE_COUNT files(s)."
+fi
+
+log_note "Populate the $TESTDIR directory (post snapshot)"
+typeset -i i=0
+while (( i < COUNT )); do
+        log_must $FILE_WRITE -o create -f $TESTDIR/after_file$i \
+           -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+        (( i = i + 1 ))
+done
+
+#
+# Now rollback to latest snapshot
+#
+log_must $ZFS rollback $SNAPFS
+
+FILE_COUNT=`$LS -Al $TESTDIR/after* 2> /dev/null | $GREP -v "total" | wc -l`
+if (( FILE_COUNT != 0 )); then
+        $LS -Al $TESTDIR
+        log_fail "$TESTDIR contains $FILE_COUNT after* files(s)."
+fi
+
+FILE_COUNT=`$LS -Al $TESTDIR/before* 2> /dev/null \
+    | $GREP -v "total" | wc -l`
+if (( FILE_COUNT != $COUNT )); then
+       $LS -Al $TESTDIR
+       log_fail "$TESTDIR contains $FILE_COUNT before* files(s)."
+fi
+
+log_pass "Rollback with child snapshot works as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_012_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_012_pos.ksh
new file mode 100755 (executable)
index 0000000..6f75861
--- /dev/null
@@ -0,0 +1,104 @@
+#! /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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#      Verify 'snapshot -r' can create snapshot for promoted clone, and vice
+#      versa, a clone filesystem from the snapshot created by 'snapshot -r'
+#      can be correctly promoted.
+#
+# STRATEGY:
+#      1. Create a dataset tree
+#      2. snapshot a filesystem and clone the snapshot
+#      3. promote the clone
+#      4. snapshot -r the dataset tree
+#      5. verify that the snapshot of cloned filesystem is created correctly
+#      6. clone a snapshot from the snapshot tree
+#      7. promote the clone
+#      8. verify that the clone is promoted correctly.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       if datasetexists $clone1; then
+               log_must $ZFS promote $ctrfs
+               log_must $ZFS destroy $clone1
+       fi
+
+       snapexists $snapctr && \
+               log_must $ZFS destroy -r $snapctr
+
+       if snapexists $clone@$TESTSNAP1; then
+               log_must $ZFS promote $ctrfs
+               log_must $ZFS destroy -rR $ctrfs@$TESTSNAP1
+       fi
+}
+
+log_assert "Verify that 'snapshot -r' can work with 'zfs promote'."
+log_onexit cleanup
+
+ctr=$TESTPOOL/$TESTCTR
+ctrfs=$ctr/$TESTFS1
+clone=$ctr/$TESTCLONE
+clone1=$ctr/$TESTCLONE1
+snappool=$SNAPPOOL
+snapfs=$SNAPFS
+snapctr=$ctr@$TESTSNAP
+snapctrclone=$clone@$TESTSNAP
+snapctrclone1=$clone1@$TESTSNAP
+snapctrfs=$SNAPCTR
+
+#preparation for testing
+log_must $ZFS snapshot $ctrfs@$TESTSNAP1
+log_must $ZFS clone $ctrfs@$TESTSNAP1 $clone
+log_must $ZFS promote $clone
+
+log_must $ZFS snapshot -r $snapctr
+
+! snapexists $snapctrclone && \
+       log_fail "'snapshot -r' fails to create $snapctrclone for $ctr/$TESTCLONE."
+
+log_must $ZFS clone $snapctrfs $clone1
+log_must $ZFS promote $clone1
+
+#verify the origin value is correct.
+orig_value=$(get_prop origin $ctrfs)
+if ! snapexists $snapctrclone1 || [[ "$orig_value" != "$snapctrclone1" ]]; then
+       log_fail "'zfs promote' fails to promote $clone which is cloned from \
+               $snapctrfs."
+fi
+
+log_pass "'snapshot -r' can work with 'zfs promote' as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_013_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_013_pos.ksh
new file mode 100755 (executable)
index 0000000..65315ee
--- /dev/null
@@ -0,0 +1,99 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#      verify that the snapshots created by 'snapshot -r' can be used for
+#      zfs send/recv
+#
+# STRATEGY:
+#      1. create a dataset tree and populate a filesystem
+#      2. snapshot -r the dataset tree
+#      3. select one snapshot used  for zfs send/recv
+#      4. verify the data integrity after zfs send/recv
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $ctrfs && \
+               $ZFS destroy -r $ctrfs
+
+       snapexists $snappool && \
+               log_must $ZFS destroy -r $snappool
+
+       [[ -e $TESTDIR ]] && \
+               log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+}
+
+log_assert "Verify snapshots from 'snapshot -r' can be used for zfs send/recv"
+log_onexit cleanup
+
+ctr=$TESTPOOL/$TESTCTR
+ctrfs=$ctr/$TESTFS
+snappool=$SNAPPOOL
+snapfs=$SNAPFS
+snapctr=$ctr@$TESTSNAP
+snapctrfs=$ctrfs@$TESTSNAP
+fsdir=/$ctrfs
+snapdir=$fsdir/.zfs/snapshot/$TESTSNAP
+
+[[ -n $TESTDIR ]] && \
+    log_must $RM -rf $TESTDIR/* > /dev/null 2>&1
+
+typeset -i COUNT=10
+
+log_note "Populate the $TESTDIR directory (prior to snapshot)"
+typeset -i i=0
+while (( i < COUNT )); do
+       log_must $FILE_WRITE -o create -f $TESTDIR/file$i \
+          -b $BLOCKSZ -c $NUM_WRITES -d $i
+
+       (( i = i + 1 ))
+done
+
+log_must $ZFS snapshot -r $snappool
+
+$ZFS send $snapfs | $ZFS receive $ctrfs >/dev/null 2>&1
+if ! datasetexists $ctrfs || ! snapexists $snapctrfs; then
+       log_fail "zfs send/receive fails with snapshot $snapfs."
+fi
+
+for dir in $fsdir $snapdir; do
+       FILE_COUNT=`$LS -Al $dir | $GREP -v "total" | wc -l`
+       (( FILE_COUNT != COUNT )) && log_fail "Got $FILE_COUNT expected $COUNT"
+done
+
+log_pass "'zfs send/receive' works as expected with snapshots from 'snapshot -r'"
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_014_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_014_pos.ksh
new file mode 100755 (executable)
index 0000000..39a8ff3
--- /dev/null
@@ -0,0 +1,78 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#      verify that creating/destroying snapshots do things clean
+#
+# STRATEGY:
+#      1. create a dataset and set a quota with 500m
+#      2. create file of size 400m on the dataset
+#      3. take a snapshot and destroy it
+#      4. then create file to use all spaces in the dataset
+#      5. verify removing the first file should succeed
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       [[ -e $TESTDIR1 ]] && \
+               log_must $RM -rf $TESTDIR1/* > /dev/null 2>&1
+
+       snapexists $SNAPCTR && \
+               log_must $ZFS destroy $SNAPCTR
+
+       datasetexists $TESTPOOL/$TESTCTR/$TESTFS1 && \
+               log_must $ZFS set quota=none $TESTPOOL/$TESTCTR/$TESTFS1
+
+}
+
+log_assert "Verify creating/destroying snapshots do things clean"
+log_onexit cleanup
+
+log_must $ZFS set quota=$FSQUOTA $TESTPOOL/$TESTCTR/$TESTFS1
+log_must $MKFILE $FILESIZE $TESTDIR1/$TESTFILE
+
+log_must $ZFS snapshot $SNAPCTR
+log_must $ZFS destroy $SNAPCTR
+
+log_note "Make the quota of filesystem is reached"
+log_mustnot $MKFILE $FILESIZE1 $TESTDIR1/$TESTFILE1
+
+log_note "Verify removing the first file should succeed after the snapshot is \
+       removed"
+log_must $RM $TESTDIR1/$TESTFILE
+
+log_pass "Verify creating/destroying snapshots do things clean"
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_015_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_015_pos.ksh
new file mode 100755 (executable)
index 0000000..cf819dd
--- /dev/null
@@ -0,0 +1,121 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+. $STF_SUITE/tests/functional/cli_root/zfs_rollback/zfs_rollback_common.kshlib
+
+#
+# DESCRIPTION:
+#      Verify snapshot can be created or destroy via mkdir or rm
+#      in .zfs/snapshot.
+#
+# STRATEGY:
+#      1. Verify make directories only successfully in .zfs/snapshot.
+#      2. Verify snapshot can be created and destroy via mkdir and remove
+#      directories in .zfs/snapshot.
+#      3. Verify rollback to previous snapshot can succeed.
+#      4. Verify remove directory in snapdir can destroy snapshot.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       typeset -i i=0
+       while ((i < snap_cnt)); do
+               typeset snap=$fs@snap.$i
+               datasetexists $snap && log_must $ZFS destroy -f $snap
+
+               ((i += 1))
+       done
+}
+
+$ZFS 2>&1 | $GREP "allow" > /dev/null
+(($? != 0)) && log_unsupported
+
+log_assert "Verify snapshot can be created via mkdir in .zfs/snapshot."
+log_onexit cleanup
+
+fs=$TESTPOOL/$TESTFS
+# Verify all the other directories are readonly.
+mntpnt=$(get_prop mountpoint $fs)
+snapdir=$mntpnt/.zfs
+set -A ro_dirs "$snapdir" "$snapdir/snap" "$snapdir/snapshot"
+for dir in ${ro_dirs[@]}; do
+       if [[ -d $dir ]]; then
+               log_mustnot $RM -rf $dir
+               log_mustnot $TOUCH $dir/testfile
+       else
+               log_mustnot $MKDIR $dir
+       fi
+done
+
+# Verify snapshot can be created via mkdir in .zfs/snapshot
+typeset -i snap_cnt=5
+typeset -i cnt=0
+while ((cnt < snap_cnt)); do
+       testfile=$mntpnt/testfile.$cnt
+       log_must $MKFILE 1M $testfile
+       log_must $MKDIR $snapdir/snapshot/snap.$cnt
+       if ! datasetexists $fs@snap.$cnt ; then
+               log_fail "ERROR: $fs@snap.$cnt should exists."
+       fi
+
+       ((cnt += 1))
+done
+
+# Verify rollback to previous snapshot succeed.
+((cnt = RANDOM % snap_cnt))
+log_must $ZFS rollback -r $fs@snap.$cnt
+
+typeset -i i=0
+while ((i < snap_cnt)); do
+       testfile=$mntpnt/testfile.$i
+       if ((i <= cnt)); then
+               if [[ ! -f $testfile ]]; then
+                       log_fail "ERROR: $testfile should exists."
+               fi
+       else
+               if [[ -f $testfile ]]; then
+                       log_fail "ERROR: $testfile should not exists."
+               fi
+       fi
+
+       ((i += 1))
+done
+
+# Verify remove directory in snapdir can destroy snapshot.
+log_must $RMDIR $snapdir/snapshot/snap.$cnt
+log_mustnot datasetexists $fs@snap.$cnt
+
+log_pass "Verify snapshot can be created via mkdir in .zfs/snapshot passed."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_016_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_016_pos.ksh
new file mode 100755 (executable)
index 0000000..9d957c7
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#      Verify renamed snapshots via mv can be destroyed
+#
+# STRATEGY:
+#      1. Create snapshot
+#      2. Rename the snapshot via mv command
+#      2. Verify destroying the renamed snapshot via 'zfs destroy' succeeds
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       datasetexists $SNAPFS && \
+               log_must $ZFS destroy -Rf $SNAPFS
+       datasetexists $TESTPOOL/$TESTFS@snap_a && \
+               log_must $ZFS destroy -Rf $TESTPOOL/$TESTFS@snap_a
+       datasetexists $TESTPOOL/$TESTCLONE@snap_a && \
+               log_must $ZFS destroy -Rf $TESTPOOL/$TESTCLONE@snap_a
+
+       datasetexists $TESTPOOL/$TESTCLONE && \
+               log_must $ZFS destroy $TESTPOOL/$TESTCLONE
+       datasetexists $TESTPOOL/$TESTFS && \
+               log_must $ZFS destroy $TESTPOOL/$TESTFS
+
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+log_assert "Verify renamed snapshots via mv can be destroyed."
+log_onexit cleanup
+
+# scenario 1
+
+log_must $ZFS snapshot $SNAPFS
+log_must $MV $TESTDIR/$SNAPROOT/$TESTSNAP $TESTDIR/$SNAPROOT/snap_a
+
+datasetexists $TESTPOOL/$TESTFS@snap_a || \
+       log_fail "rename snapshot via mv in .zfs/snapshot fails."
+log_must $ZFS destroy $TESTPOOL/$TESTFS@snap_a
+
+# scenario 2
+
+log_must $ZFS snapshot $SNAPFS
+log_must $ZFS clone $SNAPFS $TESTPOOL/$TESTCLONE
+log_must $MV $TESTDIR/$SNAPROOT/$TESTSNAP $TESTDIR/$SNAPROOT/snap_a
+
+datasetexists $TESTPOOL/$TESTFS@snap_a || \
+        log_fail "rename snapshot via mv in .zfs/snapshot fails."
+log_must $ZFS promote $TESTPOOL/$TESTCLONE
+# promote back to $TESTPOOL/$TESTFS for scenario 3
+log_must $ZFS promote $TESTPOOL/$TESTFS
+log_must $ZFS destroy $TESTPOOL/$TESTCLONE
+log_must $ZFS destroy $TESTPOOL/$TESTFS@snap_a
+
+# scenario 3
+
+log_must $ZFS snapshot $SNAPFS
+log_must $ZFS clone $SNAPFS $TESTPOOL/$TESTCLONE
+log_must $ZFS rename $SNAPFS $TESTPOOL/$TESTFS@snap_a
+log_must $ZFS promote $TESTPOOL/$TESTCLONE
+log_must $ZFS destroy $TESTPOOL/$TESTFS
+log_must $ZFS destroy $TESTPOOL/$TESTCLONE@snap_a
+
+log_pass "Verify renamed snapshots via mv can be destroyed."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_017_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapshot/snapshot_017_pos.ksh
new file mode 100755 (executable)
index 0000000..89d89ff
--- /dev/null
@@ -0,0 +1,202 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapshot/snapshot.cfg
+
+#
+# DESCRIPTION:
+#
+# Directory structure of snapshots reflects filesystem structure.
+#
+# STRATEGY:
+#
+# This test makes sure that the directory structure of snapshots is
+# a proper reflection of the filesystem the snapshot was taken of.
+#
+# 1. Create a simple directory structure of files and directories
+# 2. Take a snapshot of the filesystem
+# 3. Modify original filesystem
+# 4. Walk down the snapshot directory structure verifying it
+#    checking with both absolute and relative paths
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       cd $SAVED_DIR
+
+       if datasetexists $TESTPOOL/$TESTFS ; then
+               log_must $ZFS destroy -Rf $TESTPOOL/$TESTFS
+       fi
+
+       log_must $ZFS create $TESTPOOL/$TESTFS
+       log_must $ZFS set mountpoint=$TESTDIR $TESTPOOL/$TESTFS
+}
+
+function verify_structure {
+
+       # check absolute paths
+       DIR=$PWD
+       verify_file $DIR/file1
+       verify_file $DIR/file2
+       verify_file $DIR/dir1/file3
+       verify_file $DIR/dir1/file4
+       verify_file $DIR/dir1/dir2/file5
+       verify_file $DIR/dir1/dir2/file6
+
+       verify_no_file $DIR/file99
+
+       # check relative paths
+       verify_file ./file1
+       verify_file ./file2
+       verify_file ./dir1/file3
+       verify_file ./dir1/file4
+       verify_file ./dir1/dir2/file5
+       verify_file ./dir1/dir2/file6
+
+       cd dir1
+       verify_file ../file1
+       verify_file ../file2
+       verify_file ./file3
+       verify_file ./file4
+
+       verify_no_file ../file99
+
+       cd dir2
+       verify_file ./file5
+       verify_file ./file6
+       verify_file ../file3
+       verify_file ../file4
+       verify_no_file ../file99
+
+       verify_file ../../file1
+       verify_file ../../file2
+       verify_no_file ../../file99
+}
+
+function verify_file {
+       if [ ! -e $1 ]
+       then
+               log_note "Working dir is $PWD"
+               log_fail "File $1 does not exist!"
+       fi
+}
+
+function verify_no_file {
+       if [ -e $1 ]
+       then
+               log_note "Working dir is $PWD"
+               log_fail "File $1 exists when it should not!"
+       fi
+}
+
+function verify_dir {
+       if [ ! -d $1 ]
+       then
+               log_note "Working dir is $PWD"
+               log_fail "Directory $1 does not exist!"
+       fi
+}
+
+log_assert "Directory structure of snapshots reflects filesystem structure."
+log_onexit cleanup
+
+SAVED_DIR=$PWD
+
+#
+# Create a directory structure with the following files
+#
+# ./file1
+# ./file2
+# ./dir1/file3
+# ./dir1/file4
+# ./dir1/dir2/file5
+# ./dir1/dir2/file6
+
+cd $TESTDIR
+$MKFILE 10m file1
+$MKFILE 20m file2
+$MKDIR dir1
+cd dir1
+$MKFILE 10m file3
+$MKFILE 20m file4
+$MKDIR dir2
+cd dir2
+$MKFILE 10m file5
+$MKFILE 20m file6
+
+# Now walk the directory structure verifying it
+cd $TESTDIR
+verify_structure
+
+# Take snapshots
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snap_a
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snap_b
+
+# Change the filesystem structure by renaming files in the original structure
+# The snapshot file structure should not change
+cd $TESTDIR
+log_must $MV file2 file99
+cd dir1
+log_must $MV file4 file99
+cd dir2
+log_must $MV file6 file99
+
+# verify the top level snapshot directories
+verify_dir $TESTDIR/.zfs
+verify_dir $TESTDIR/.zfs/snapshot
+verify_dir $TESTDIR/.zfs/snapshot/snap_a
+verify_dir $TESTDIR/.zfs/snapshot/snap_b
+
+cd $TESTDIR/.zfs/snapshot/snap_a
+verify_structure
+
+cd $TESTDIR/.zfs/snapshot/snap_b
+verify_structure
+
+cd $TESTDIR/.zfs
+verify_dir snapshot
+cd $TESTDIR/.zfs/snapshot
+verify_dir snap_a
+verify_dir snap_b
+
+cd snap_a
+verify_dir ../snap_a
+verify_dir ../snap_b
+
+cd ..
+verify_dir snap_a
+verify_dir snap_b
+
+log_pass "Directory structure of snapshots reflects filesystem structure."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/Makefile.am b/zfs/tests/zfs-tests/tests/functional/snapused/Makefile.am
new file mode 100644 (file)
index 0000000..f19320a
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/snapused
+dist_pkgdata_SCRIPTS = \
+       snapused.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       snapused_001_pos.ksh \
+       snapused_002_pos.ksh \
+       snapused_003_pos.ksh \
+       snapused_004_pos.ksh \
+       snapused_005_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/snapused/cleanup.ksh
new file mode 100755 (executable)
index 0000000..2f536ca
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/setup.ksh b/zfs/tests/zfs-tests/tests/functional/snapused/setup.ksh
new file mode 100755 (executable)
index 0000000..dfe8696
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/snapused.kshlib b/zfs/tests/zfs-tests/tests/functional/snapused/snapused.kshlib
new file mode 100644 (file)
index 0000000..5e3a765
--- /dev/null
@@ -0,0 +1,185 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export USEDTEST=$TESTPOOL/$TESTFS/usedtest-snapused
+
+function _check_used # dataset
+{
+        typeset dataset=$1
+
+       if [[ "$(get_prop type $dataset)" == "snapshot" ]]; then
+               return
+       fi
+
+       used=$(get_prop used $dataset)
+       usedbychildren=$(get_prop usedbychildren $dataset)
+       usedbydataset=$(get_prop usedbydataset $dataset)
+       usedbyrefreservation=$(get_prop usedbyrefreservation $dataset)
+       usedbysnapshots=$(get_prop usedbysnapshots $dataset)
+       ((used_sum = usedbychildren + usedbydataset + \
+               usedbyrefreservation + usedbysnapshots))
+       if ((used != used_sum)); then
+               log_fail "$dataset: used($used) is not the sum($used_sum) of usedby*"
+       fi
+}
+
+function check_used # dataset
+{
+       typeset dataset=$1
+       for child in $($ZFS list -rH -t filesystem,volume -o name $dataset)
+       do
+               _check_used $child
+       done
+}
+
+function check_usedbychildren # dataset
+{
+       typeset dataset=$1
+       typeset -i usedbychildren_sum=0
+       typeset -i parent_usedbychildren=0
+       for child in $($ZFS list -rH -t filesystem,volume -o name $dataset)
+       do
+               if [[ "$(get_prop type $child)" == "snapshot" ]]; then
+                       continue
+               fi
+
+               # parent
+               if [[ "$child" == "$dataset" ]]; then
+                       parent_usedbychildren=$(get_prop usedbychildren $child)
+               else #child
+                       reservation=$(get_prop reservation $child)
+                       used=$(get_prop used $child)
+                       if ((reservation > used)); then
+                               ((usedbychildren_sum += reservation))
+                       else
+                               ((usedbychildren_sum += used))
+                       fi
+               fi
+       done
+
+        if ((parent_usedbychildren != usedbychildren_sum)); then
+                log_fail "$dataset: usedbychildren($parent_usedbychildren) is not the sum($usedbychildren_sum) of used by children"
+        fi
+}
+
+function _check_usedbydataset # dataset
+{
+        typeset dataset=$1
+       if [[ "$(get_prop type $dataset)" == "snapshot" ]]; then
+               return
+       fi
+
+       usedbydataset=$(get_prop usedbydataset $dataset)
+       referenced=$(get_prop referenced $dataset)
+
+       is_cloned=$(get_prop is:cloned $dataset)
+
+       if [[ "$is_cloned" == "yes" ]]; then
+               if ((usedbydataset > referenced)); then
+                       log_fail "$dataset(cloned): usedbydataset($usedbydataset) is more than referenced($referenced)"
+               fi
+       else
+               #
+               # if non-clones, should usedbydataset == referenced
+               #
+               if ((usedbydataset != referenced)); then
+                       log_fail "$dataset: usedbydataset($usedbydataset) is not equal to referenced($referenced)"
+               fi
+       fi
+}
+
+function check_usedbydataset # dataset
+{
+       typeset dataset=$1
+       for child in $($ZFS list -rH -t filesystem,volume -o name $dataset)
+       do
+               _check_usedbydataset $child
+       done
+}
+
+function _check_usedbyrefreservation # dataset
+{
+        typeset dataset=$1
+       if [[ "$(get_prop type $dataset)" == "snapshot" ]]; then
+               return
+       fi
+
+       usedbyrefreservation=$(get_prop usedbyrefreservation $dataset)
+       referenced=$(get_prop referenced $dataset)
+       refreservation=$(get_prop refreservation $dataset)
+       ((diff_ref = refreservation - referenced))
+       if ((usedbyrefreservation > refreservation || \
+               usedbyrefreservation < diff_ref)); then
+               log_fail "$dataset: usedbyrefreservation($usedbyrefreservation) checking is not ok"
+       fi
+}
+
+function check_usedbyrefreservation # dataset
+{
+       typeset dataset=$1
+       for child in $($ZFS list -rH -t filesystem,volume -o name $dataset)
+       do
+               _check_usedbyrefreservation $child
+       done
+}
+
+function check_usedbysnapshots # dataset
+{
+       typeset dataset=$1
+       typeset -i usedbysnapshots_sum=0
+       typeset -i parent_usedbysnapshots=0
+       for child in $($ZFS list -rH -t filesystem,volume,snapshot -o name $dataset)
+       do
+               # parent
+               if [[ "$child" == "$dataset" ]]; then
+                       parent_usedbysnapshots=$(get_prop usedbysnapshots $child)
+                       continue
+               fi
+
+               if [[ "$(get_prop type $child)" != "snapshot" ]]; then
+                       continue
+               fi
+
+               if [[ "$child" != "$dataset@"* ]]; then
+                       continue
+               fi
+
+               # snapshot
+               used=$(get_prop used $child)
+               ((usedbysnapshots_sum += used))
+       done
+
+        if ((parent_usedbysnapshots < usedbysnapshots_sum)); then
+                log_fail "$dataset: usedbysnapshots($parent_usedbysnapshots) is not more than or equal to" \
+                               "the sum($usedbysnapshots_sum) of used of snapshots"
+        fi
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/snapused_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapused/snapused_001_pos.ksh
new file mode 100755 (executable)
index 0000000..3182ded
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapused/snapused.kshlib
+
+#
+# DESCRIPTION:
+#      Verify used is correct.
+#
+# STRATEGY:
+#      1. Create a filesystem.
+#      2. Set refreservation of the filesystem.
+#      3. Make file in the filesystem.
+#      4. Create sub filesystem and make file in it.
+#      5. Create volume under it.
+#      6. Snapshot it.
+#      7. Check used=usedbychildren+usedbydataset+
+#              usedbyrefreservation+usedbysnapshots.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rR $USEDTEST
+}
+
+log_assert "Verify used is correct."
+log_onexit cleanup
+
+log_must $ZFS create $USEDTEST
+check_used $USEDTEST
+
+typeset -i i=0
+typeset -i r_size=0
+mntpnt=$(get_prop mountpoint $USEDTEST)
+while ((i < 5)); do
+       ((r_size=(i+1)*16))
+
+       #usedbyrefreservation
+       log_must $ZFS set refreservation="$r_size"M $USEDTEST
+
+       #usedbydataset
+       log_must $MKFILE 16M $mntpnt/file$i
+
+       #usedbychildren
+       log_must $ZFS create $USEDTEST/fs$i
+       log_must $MKFILE 16M $mntpnt/fs$i/file$i
+
+       if is_global_zone; then
+               log_must $ZFS create -V 16M $USEDTEST/vol$i
+       fi
+
+       #usedbysnapshots
+       log_must $ZFS snapshot -r $USEDTEST@snap$i
+
+       check_used $USEDTEST
+
+        ((i = i + 1))
+done
+
+log_pass "Verify used is correct."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/snapused_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapused/snapused_002_pos.ksh
new file mode 100755 (executable)
index 0000000..db6ac3d
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapused/snapused.kshlib
+
+#
+# DESCRIPTION:
+#      Verify usedbychildren is correct.
+#
+# STRATEGY:
+#      1. Create a filesystem.
+#      2. Create sub filesystem and make file in it.
+#      3. Set reservation of the sub filesystem.
+#      4. Create volume under it.
+#      5. Snapshot it.
+#      6. Check usedbychildren is correct.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rR $USEDTEST
+}
+
+log_assert "Verify usedbychildren is correct."
+log_onexit cleanup
+
+log_must $ZFS create $USEDTEST
+check_usedbychildren $USEDTEST
+
+typeset -i i=0
+typeset -i r_size=0
+mntpnt=$(get_prop mountpoint $USEDTEST)
+while ((i < 5)); do
+       ((r_size=(i+1)*16))
+
+       log_must $ZFS create $USEDTEST/fs$i
+       log_must $ZFS set reservation="$r_size"M $USEDTEST/fs$i
+       log_must $MKFILE 48M $mntpnt/fs$i/file$i
+
+       if is_global_zone; then
+               log_must $ZFS create -V 32M $USEDTEST/vol$i
+       fi
+
+       log_must $ZFS snapshot -r $USEDTEST@snap$i
+
+       check_usedbychildren $USEDTEST
+
+        ((i = i + 1))
+done
+
+log_pass "Verify usedbychildren is correct."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/snapused_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapused/snapused_003_pos.ksh
new file mode 100755 (executable)
index 0000000..9dee1f3
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapused/snapused.kshlib
+
+#
+# DESCRIPTION:
+#      Verify usedbydataset is correct.
+#
+# STRATEGY:
+#      1. Create a filesystem.
+#      2. Make file in the filesystem.
+#      3. Snapshot it.
+#      4. Clone it and make file in the cloned filesystem.
+#      5. Check usedbydataset is correct.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rR $USEDTEST
+}
+
+log_assert "Verify usedbydataset is correct."
+log_onexit cleanup
+
+log_must $ZFS create $USEDTEST
+check_usedbydataset $USEDTEST
+
+typeset -i i=0
+typeset -i r_size=0
+mntpnt=$(get_prop mountpoint $USEDTEST)
+while ((i < 5)); do
+       ((r_size=(i+1)*16))
+
+       log_must $MKFILE 16M $mntpnt/file$i
+       log_must $MKFILE "$r_size"M $mntpnt/file_var$i
+       log_must $ZFS snapshot -r $USEDTEST@snap$i
+
+       log_must $ZFS clone $USEDTEST@snap$i $USEDTEST/cln$i
+       log_must $ZFS set is:cloned=yes $USEDTEST/cln$i
+
+       mntpnt_cln=$(get_prop mountpoint $USEDTEST/cln$i)
+       log_must $MKFILE 16M $mntpnt_cln/file_cln$i
+       log_must $MKFILE "$r_size"M $mntpnt_cln/file_cln_var$i
+
+       check_usedbydataset $USEDTEST
+
+        ((i = i + 1))
+done
+
+log_pass "Verify usedbydataset is correct."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/snapused_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapused/snapused_004_pos.ksh
new file mode 100755 (executable)
index 0000000..2cc4cad
--- /dev/null
@@ -0,0 +1,95 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapused/snapused.kshlib
+
+#
+# DESCRIPTION:
+#      Verify usedbyrefreservation is correct.
+#
+# STRATEGY:
+#      1. Create a filesystem.
+#      2. Set refreservation of the filesystem.
+#      3. Make file in the filesystem.
+#      4. Create sub filesystem and make file in it.
+#      5. Set refreservation of the sub filesystem.
+#      6. Create volume under it.
+#      7. Snapshot it.
+#      8. Clone it and set refreservation of the cloned filesystem.
+#      9. Makefile the cloned filesystem.
+#      10. Check usedbyrefreservation is correct.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rR $USEDTEST
+}
+
+log_assert "Verify usedbyrefreservation is correct."
+log_onexit cleanup
+
+log_must $ZFS create $USEDTEST
+check_usedbyrefreservation $USEDTEST
+
+typeset -i i=0
+typeset -i r_size=0
+mntpnt=$(get_prop mountpoint $USEDTEST)
+while ((i < 5)); do
+       ((r_size=(i+1)*16))
+       log_must $ZFS set refreservation="$r_size"M $USEDTEST
+
+       log_must $MKFILE 16M $mntpnt/file$i
+
+       log_must $ZFS create $USEDTEST/fs$i
+       log_must $ZFS set refreservation="$r_size"M $USEDTEST/fs$i
+       log_must $MKFILE 16M $mntpnt/fs$i/file$i
+
+       if is_global_zone; then
+               log_must $ZFS create -V 16M $USEDTEST/vol$i
+       fi
+
+       log_must $ZFS snapshot -r $USEDTEST@snap$i
+
+       log_must $ZFS clone $USEDTEST@snap$i $USEDTEST/cln$i
+
+       mntpnt_cln=$(get_prop mountpoint $USEDTEST/cln$i)
+       log_must $ZFS set refreservation="$r_size"M $USEDTEST/cln$i
+       log_must $MKFILE 16M $mntpnt_cln/file_cln$i
+
+       check_usedbyrefreservation $USEDTEST
+
+        ((i = i + 1))
+done
+
+log_pass "Verify usedbyrefreservation is correct."
diff --git a/zfs/tests/zfs-tests/tests/functional/snapused/snapused_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/snapused/snapused_005_pos.ksh
new file mode 100755 (executable)
index 0000000..f4099c8
--- /dev/null
@@ -0,0 +1,73 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/snapused/snapused.kshlib
+
+#
+# DESCRIPTION:
+#      Verify usedbysnapshots is correct.
+#
+# STRATEGY:
+#      1. Create a filesystem.
+#      2. Make file in the filesystem.
+#      3. Snapshot it.
+#      4. Check check_usedbysnapshots is correct.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       log_must $ZFS destroy -rR $USEDTEST
+}
+
+log_assert "Verify usedbysnapshots is correct."
+log_onexit cleanup
+
+log_must $ZFS create $USEDTEST
+check_usedbysnapshots $USEDTEST
+
+typeset -i i=0
+typeset -i r_size=0
+mntpnt=$(get_prop mountpoint $USEDTEST)
+while ((i < 5)); do
+       ((r_size=(i+1)*16))
+
+       log_must $MKFILE "$r_size"M $mntpnt/file$i
+
+       log_must $ZFS snapshot $USEDTEST@snap$i
+       check_usedbysnapshots $USEDTEST
+
+        ((i = i + 1))
+done
+
+log_pass "Verify usedbysnapshots is correct."
diff --git a/zfs/tests/zfs-tests/tests/functional/sparse/Makefile.am b/zfs/tests/zfs-tests/tests/functional/sparse/Makefile.am
new file mode 100644 (file)
index 0000000..33256b9
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/sparse
+dist_pkgdata_SCRIPTS = \
+       sparse.cfg \
+       setup.ksh \
+       cleanup.ksh \
+       sparse_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/sparse/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/sparse/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/sparse/setup.ksh b/zfs/tests/zfs-tests/tests/functional/sparse/setup.ksh
new file mode 100755 (executable)
index 0000000..3a45ec8
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+disk=${DISKS%% *}
+
+default_setup $disk
diff --git a/zfs/tests/zfs-tests/tests/functional/sparse/sparse.cfg b/zfs/tests/zfs-tests/tests/functional/sparse/sparse.cfg
new file mode 100644 (file)
index 0000000..a01677d
--- /dev/null
@@ -0,0 +1,43 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+export TESTFILE=testfile.sparse
+export HOLES_FILESIZE=${HOLES_FILESIZE-"67108864"} # 64 Mb
+export HOLES_BLKSIZE=${HOLES_BLKSIZE-"512"}
+export HOLES_SEED=${HOLES_SEED-""}
+export HOLES_FILEOFFSET=${HOLES_FILEOFFSET-""}
+export HOLES_COUNT=${HOLES_COUNT-"16384"}         # FILESIZE/BLKSIZE/8
+export STF_TIMEOUT=3600
+
+export DISKSARRAY=$DISKS
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+set_device_dir
diff --git a/zfs/tests/zfs-tests/tests/functional/sparse/sparse_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/sparse/sparse_001_pos.ksh
new file mode 100755 (executable)
index 0000000..f5d7546
--- /dev/null
@@ -0,0 +1,80 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/sparse/sparse.cfg
+
+#
+# DESCRIPTION:
+# Holes in ZFS files work correctly.
+#
+# STRATEGY:
+# 1. Open file
+# 2. Write random blocks in random places
+# 3. Read each block back to check for correctness.
+# 4. Repeat steps 2 and 3 lots of times
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "Ensure random blocks are read back correctly"
+
+options=""
+options_display="default options"
+
+log_onexit cleanup
+
+[[ -n "$HOLES_FILESIZE" ]] && options=" $options -f $HOLES_FILESIZE "
+
+[[ -n "$HOLES_BLKSIZE" ]] && options="$options -b $HOLES_BLKSIZE "
+
+[[ -n "$HOLES_COUNT" ]] && options="$options -c $HOLES_COUNT "
+
+[[ -n "$HOLES_SEED" ]] && options="$options -s $HOLES_SEED "
+
+[[ -n "$HOLES_FILEOFFSET" ]] && options="$options -o $HOLES_FILEOFFSET "
+
+options="$options -r "
+
+[[ -n "$options" ]] && options_display=$options
+
+log_note "Invoking $FILE_TRUNC with: $options_display"
+log_must $FILE_TRUNC $options $TESTDIR/$TESTFILE
+
+typeset dir=$(get_device_dir $DISKS)
+verify_filesys "$TESTPOOL" "$TESTPOOL/$TESTFS" "$dir"
+
+log_pass "Random blocks have been read back correctly."
diff --git a/zfs/tests/zfs-tests/tests/functional/threadsappend/Makefile.am b/zfs/tests/zfs-tests/tests/functional/threadsappend/Makefile.am
new file mode 100644 (file)
index 0000000..80f7788
--- /dev/null
@@ -0,0 +1,8 @@
+include $(top_srcdir)/config/Rules.am
+
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/threadsappend
+
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       threadsappend_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/threadsappend/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/threadsappend/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3166bd6
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/threadsappend/setup.ksh b/zfs/tests/zfs-tests/tests/functional/threadsappend/setup.ksh
new file mode 100755 (executable)
index 0000000..4fc55cd
--- /dev/null
@@ -0,0 +1,36 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+DISK=${DISKS%% *}
+
+default_setup ${DISK}
diff --git a/zfs/tests/zfs-tests/tests/functional/threadsappend/threadsappend_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/threadsappend/threadsappend_001_pos.ksh
new file mode 100755 (executable)
index 0000000..3c445a5
--- /dev/null
@@ -0,0 +1,80 @@
+#! /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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Ensure multiple threads performing write appends to the same ZFS
+# file succeed.
+#
+# STRATEGY:
+#      1) Verify this is a multi-processor system
+#      2) Create multiple threads with each appending to a file
+#       3) Verify that the resulting file is the expected size
+#
+
+verify_runnable "both"
+
+log_assert "Ensure multiple threads performing write appends to the same" \
+       "ZFS file succeed"
+
+#
+# $FILE_SIZE is hardcoded into threadsappend.c and is the expected
+# size of the file after all the threads have appended to it
+#
+typeset -i FILE_SIZE=1310720
+TESTFILE='testfile-threadsappend'
+
+#
+# This test should be run on a multi-processor system because otherwise the FS
+# will not be concurrently used by the threads
+#
+if ! is_mp; then
+       log_fail "This test should be executed on a multi-processor system."
+fi
+
+#
+# zfs_threadsappend tries to append to $TESTFILE using threads
+# so that the resulting file is $FILE_SIZE bytes in size
+#
+log_must $THREADSAPPEND ${TESTDIR}/${TESTFILE}
+
+#
+# Check the size of the resulting file
+#
+SIZE=`$LS -l ${TESTDIR}/${TESTFILE} | $AWK '{print $5}'`
+if [[ $SIZE -ne $FILE_SIZE ]]; then
+       log_fail "'The length of ${TESTDIR}/${TESTFILE}' doesnt equal 1310720."
+fi
+
+log_pass "Multiple thread appends succeeded. File size as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/truncate/Makefile.am b/zfs/tests/zfs-tests/tests/functional/truncate/Makefile.am
new file mode 100644 (file)
index 0000000..16cadf2
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/truncate
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       truncate.cfg \
+       truncate_001_pos.ksh \
+       truncate_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/truncate/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/truncate/cleanup.ksh
new file mode 100755 (executable)
index 0000000..9756c0f
--- /dev/null
@@ -0,0 +1,30 @@
+#!/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.
+#
+
+. ${STF_SUITE}/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/truncate/setup.ksh b/zfs/tests/zfs-tests/tests/functional/truncate/setup.ksh
new file mode 100755 (executable)
index 0000000..863492d
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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.
+#
+
+. ${STF_SUITE}/include/libtest.shlib
+
+disk=${DISKS%% *}
+
+default_setup $disk
diff --git a/zfs/tests/zfs-tests/tests/functional/truncate/truncate.cfg b/zfs/tests/zfs-tests/tests/functional/truncate/truncate.cfg
new file mode 100644 (file)
index 0000000..e9449da
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# 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 TESTFILE=testfile.$$
+export TRUNC_FILESIZE=${TRUNC_FILESIZE-"67108864"} # 64 Mb
+export TRUNC_BLKSIZE=${TRUNC_BLKSIZE-"512"}
+export TRUNC_SEED=${TRUNC_SEED-""}
+export TRUNC_FILEOFFSET=${TRUNC_FILEOFFSET-""}
+export TRUNC_COUNT=${TRUNC_COUNT-"16384"}         # FILESIZE/BLKSIZE/8
+
+export DISKSARRAY=$DISKS
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+
+set_device_dir
diff --git a/zfs/tests/zfs-tests/tests/functional/truncate/truncate_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/truncate/truncate_001_pos.ksh
new file mode 100755 (executable)
index 0000000..a6b379a
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+. $STF_SUITE/tests/functional/truncate/truncate.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Tests file truncation within ZFS.
+#
+# STRATEGY:
+# 1. Open file
+# 2. Write random blocks in random places
+# 3. Truncate the file
+# 4. Repeat steps 2 and 3 lots of times
+# 5. Close the file.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+}
+
+log_assert "Ensure file with random blocks is truncated properly"
+
+options=""
+options_display="default options"
+
+log_onexit cleanup
+
+[[ -n "$TRUNC_FILESIZE" ]] && options=" $options -f $TRUNC_FILESIZE "
+
+[[ -n "$TRUNC_BLKSIZE" ]] && options="$options -b $TRUNC_BLKSIZE "
+
+[[ -n "$TRUNC_COUNT" ]] && options="$options -c $TRUNC_COUNT "
+
+[[ -n "$TRUNC_SEED" ]] && options="$options -s $TRUNC_SEED "
+
+[[ -n "$TRUNC_FILEOFFSET" ]] && options="$options -o $TRUNC_FILEOFFSET "
+
+[[ -n "$options" ]] && options_display=$options
+
+log_note "Invoking $FILE_TRUNC with: $options_display"
+log_must $FILE_TRUNC $options $TESTDIR/$TESTFILE
+
+typeset dir=$(get_device_dir $DISKS)
+verify_filesys "$TESTPOOL" "$TESTPOOL/$TESTFS" "$dir"
+
+log_pass "Random blocks have been truncated properly."
diff --git a/zfs/tests/zfs-tests/tests/functional/truncate/truncate_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/truncate/truncate_002_pos.ksh
new file mode 100755 (executable)
index 0000000..fe9584a
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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.
+#
+
+. $STF_SUITE/tests/functional/truncate/truncate.cfg
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Tests file truncation within ZFS while a sync operation is in progress.
+#
+# STRATEGY:
+# 1. Copy a file to ZFS filesystem
+# 2. Copy /dev/null to same file on ZFS filesystem
+# 3. Execute a sync command
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       [[ -e $TESTDIR ]] && log_must $RM -rf $TESTDIR/*
+       [[ -f $srcfile ]] && $RM -f $srcfile
+}
+
+log_assert "Ensure zeroed file gets written correctly during a sync operation"
+
+srcfile="/tmp/cosmo.$$"
+log_must $DD if=/dev/urandom of=$srcfile bs=1024k count=1
+
+log_onexit cleanup
+log_must $CP $srcfile $TESTDIR/$TESTFILE
+log_must $CP /dev/null $TESTDIR/$TESTFILE
+log_must $SYNC
+if [[ -s $TESTDIR/$TESTFILE ]]; then
+       log_note "$($LS -l $TESTDIR/$TESTFILE)"
+       log_fail "testfile not truncated"
+fi
+
+log_pass "Successful truncation while a sync operation is in progress."
diff --git a/zfs/tests/zfs-tests/tests/functional/upgrade/Makefile.am b/zfs/tests/zfs-tests/tests/functional/upgrade/Makefile.am
new file mode 100644 (file)
index 0000000..3103434
--- /dev/null
@@ -0,0 +1,5 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/upgrade
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       upgrade_userobj_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/upgrade/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/upgrade/cleanup.ksh
new file mode 100755 (executable)
index 0000000..6b0eb9d
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+#
+# Copyright (c) 2016 by Jinshan Xiong. No rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+log_must $ZPOOL destroy $TESTPOOL
+
+log_must $RM /tmp/zpool_upgrade_test.dat
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh b/zfs/tests/zfs-tests/tests/functional/upgrade/setup.ksh
new file mode 100755 (executable)
index 0000000..57b4835
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+#
+# Copyright (c) 2016 by Jinshan Xiong. No rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+# create a pool without any features
+log_must $MKFILE 128m /tmp/zpool_upgrade_test.dat
+log_must $ZPOOL create -d -m $TESTDIR $TESTPOOL /tmp/zpool_upgrade_test.dat
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/upgrade/upgrade_userobj_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/upgrade/upgrade_userobj_001_pos.ksh
new file mode 100755 (executable)
index 0000000..49087f5
--- /dev/null
@@ -0,0 +1,98 @@
+#!/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 (c) 2013 by Jinshan Xiong. No rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#
+# Check that zfs upgrade for object count accounting works.
+# Since userobjaccounting is a per dataset feature, this test case
+# will create multiple dataset and try different upgrade method.
+#
+# STRATEGY:
+# 1. Create a pool with all features disabled
+# 2. Create a few dataset for testing
+# 3. Make sure automatic upgrade work
+# 4. Make sure manual upgrade work
+#
+
+function cleanup
+{
+       datasetexists $TESTPOOL/fs1 && log_must $ZFS destroy $TESTPOOL/fs1
+       datasetexists $TESTPOOL/fs2 && log_must $ZFS destroy $TESTPOOL/fs2
+}
+
+verify_runnable "global"
+
+log_assert "pool upgrade for userobj accounting should work"
+log_onexit cleanup
+
+log_must $MKFILES $TESTDIR/tf $((RANDOM % 1000 + 1))
+log_must $ZFS create $TESTPOOL/fs1
+log_must $MKFILES $TESTDIR/fs1/tf $((RANDOM % 1000 + 1))
+log_must $ZFS create $TESTPOOL/fs2
+log_must $MKFILES $TESTDIR/fs2/tf $((RANDOM % 1000 + 1))
+log_must $ZFS umount $TESTPOOL/fs2
+
+# Make sure userobj accounting is disabled
+$ZFS userspace -o objused -H $TESTPOOL | $HEAD -n 1 | $GREP -q "-" ||
+       log_fail "userobj accounting should be disabled initially"
+
+# Upgrade zpool to support all features
+log_must $ZPOOL upgrade $TESTPOOL
+
+# Make sure userobj accounting is disabled again
+$ZFS userspace -o objused -H $TESTPOOL | $HEAD -n 1 | $GREP -q "-" ||
+       log_fail "userobj accounting should be disabled after pool upgrade"
+
+# Create a file in fs1 should trigger dataset upgrade
+log_must $MKFILE 1m $TESTDIR/fs1/tf
+sync_pool
+
+# Make sure userobj accounting is working for fs1
+$ZFS userspace -o objused -H $TESTPOOL/fs1 | $HEAD -n 1 | $GREP -q "-" &&
+       log_fail "userobj accounting should be enabled for $TESTPOOL/fs1"
+
+# Mount a dataset should trigger upgrade
+log_must $ZFS mount $TESTPOOL/fs2
+sync_pool
+
+# Make sure userobj accounting is working for fs2
+$ZFS userspace -o objused -H $TESTPOOL/fs2 | $HEAD -n 1 | $GREP -q "-" &&
+       log_fail "userobj accounting should be enabled for $TESTPOOL/fs2"
+
+# All in all, after having been through this, the dataset for testpool
+# still shouldn't be upgraded
+$ZFS userspace -o objused -H $TESTPOOL | $HEAD -n 1 | $GREP -q "-" ||
+       log_fail "userobj accounting should be disabled for $TESTPOOL"
+
+# Manual upgrade root dataset
+log_must $ZFS set version=current $TESTPOOL
+$ZFS userspace -o objused -H $TESTPOOL | $HEAD -n 1 | $GREP -q "-" &&
+       log_fail "userobj accounting should be enabled for $TESTPOOL"
+
+log_pass "all tests passed - what a lucky day!"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/Makefile.am b/zfs/tests/zfs-tests/tests/functional/userquota/Makefile.am
new file mode 100644 (file)
index 0000000..b7f38f9
--- /dev/null
@@ -0,0 +1,25 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/userquota
+dist_pkgdata_SCRIPTS = \
+       userquota.cfg \
+       userquota_common.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       groupspace_001_pos.ksh \
+       groupspace_002_pos.ksh \
+       groupspace_003_pos.ksh \
+       userquota_001_pos.ksh \
+       userquota_002_pos.ksh \
+       userquota_003_pos.ksh \
+       userquota_004_pos.ksh \
+       userquota_005_neg.ksh \
+       userquota_006_pos.ksh \
+       userquota_007_pos.ksh \
+       userquota_008_pos.ksh \
+       userquota_009_pos.ksh \
+       userquota_010_pos.ksh \
+       userquota_011_pos.ksh \
+       userquota_012_neg.ksh \
+       userquota_013_pos.ksh \
+       userspace_001_pos.ksh \
+       userspace_002_pos.ksh \
+       userspace_003_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/cleanup.ksh
new file mode 100755 (executable)
index 0000000..5931acb
--- /dev/null
@@ -0,0 +1,41 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+log_must cleanup_quota
+log_must clean_user_group
+
+typeset mntp=$(get_prop mountpoint $QFS)
+log_must $CHMOD 0755 $mntp
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/groupspace_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/groupspace_001_pos.ksh
new file mode 100755 (executable)
index 0000000..800285e
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the zfs groupspace with all parameters
+#
+#
+# STRATEGY:
+#       1. set zfs groupquota to a fs
+#       2. write some data to the fs with specified user and group
+#      3. use zfs groupspace with all possible parameters to check the result
+#
+
+function cleanup
+{
+       if datasetexists $snap_fs; then
+               log_must $ZFS destroy $snap_fs
+       fi
+
+       log_must cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the zfs groupspace with all possible parameters"
+
+set -A params -- "-n" "-H" "-p" "-o type,name,used,quota" \
+    "-o name,used,quota" "-o used,quota" "-o used" "-o quota" "-s type" \
+    "-s name" "-s used" "-s quota" "-S type" "-S name" "-S used" "-S quota" \
+    "-t posixuser" "-t posixgroup" "-t all" "-i" "-t smbuser" "-t smbgroup"
+
+typeset snap_fs=$QFS@snap
+
+log_must $ZFS set groupquota@$QGROUP=500m $QFS
+mkmount_writable $QFS
+log_must user_run $QUSER1 $MKFILE 50m $QFILE
+
+$SYNC
+
+log_must $ZFS snapshot $snap_fs
+
+for param in "${params[@]}"; do
+       log_must eval "$ZFS groupspace $param $QFS >/dev/null 2>&1"
+       log_must eval "$ZFS groupspace $param $snap_fs >/dev/null 2>&1"
+done
+
+log_pass "Check the zfs groupspace with all possible parameters"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/groupspace_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/groupspace_002_pos.ksh
new file mode 100755 (executable)
index 0000000..92d8dd9
--- /dev/null
@@ -0,0 +1,79 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the user used and groupspace size in zfs groupspace
+#
+#
+# STRATEGY:
+#       1. set zfs groupquota to a fs
+#       2. write some data to the fs with specified user and size
+#      3. use zfs groupspace to check the used size and quota size
+#
+
+function cleanup
+{
+       if datasetexists $snapfs; then
+               log_must $ZFS destroy $snapfs
+       fi
+       log_must cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the zfs groupspace used and quota"
+
+log_must $ZFS set groupquota@$QGROUP=500m $QFS
+mkmount_writable $QFS
+log_must user_run $QUSER1 $MKFILE 100m $QFILE
+
+$SYNC
+
+typeset snapfs=$QFS@snap
+
+log_must $ZFS snapshot $snapfs
+
+log_must eval "$ZFS groupspace $QFS >/dev/null 2>&1"
+log_must eval "$ZFS groupspace $snapfs >/dev/null 2>&1"
+
+for fs in "$QFS" "$snapfs"; do
+       log_note "check the quota size in zfs groupspace $fs"
+       log_must eval "$ZFS groupspace $fs | $GREP $QGROUP | $GREP 500M"
+
+       log_note "check the user used size in zfs groupspace $fs"
+       log_must eval "$ZFS groupspace $fs | $GREP $QGROUP | $GREP 100M"
+done
+
+log_pass "Check the zfs groupspace used and quota pass as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/groupspace_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/groupspace_003_pos.ksh
new file mode 100755 (executable)
index 0000000..7ea8cd5
--- /dev/null
@@ -0,0 +1,103 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the user used and groupspace object counts in zfs groupspace
+#
+#
+# STRATEGY:
+#      1. set zfs groupquota to a fs
+#      2. create objects for different users in the same group
+#      3. use zfs groupspace to check the object count
+#
+
+function cleanup
+{
+       if datasetexists $snapfs; then
+               log_must $ZFS destroy $snapfs
+       fi
+
+       log_must $RM -f ${QFILE}_*
+       log_must cleanup_quota
+}
+
+function group_object_count
+{
+       typeset fs=$1
+       typeset user=$2
+       typeset cnt=$($ZFS groupspace -oname,objused $fs | $GREP $user |
+                       $AWK '{print $2}')
+       echo $cnt
+}
+
+log_onexit cleanup
+
+log_assert "Check the zfs groupspace object used"
+
+mkmount_writable $QFS
+log_must $ZFS set xattr=sa $QFS
+
+((user1_cnt = RANDOM % 100 + 1))
+((user2_cnt = RANDOM % 100 + 1))
+log_must user_run $QUSER1 $MKFILES ${QFILE}_1 $user1_cnt
+log_must user_run $QUSER2 $MKFILES ${QFILE}_2 $user2_cnt
+((grp_cnt = user1_cnt + user2_cnt))
+sync_pool
+
+typeset snapfs=$QFS@snap
+
+log_must $ZFS snapshot $snapfs
+
+log_must eval "$ZFS groupspace $QFS >/dev/null 2>&1"
+log_must eval "$ZFS groupspace $snapfs >/dev/null 2>&1"
+
+for fs in "$QFS" "$snapfs"; do
+       log_note "check the object count in zfs groupspace $fs"
+        [[ $(group_object_count $fs $QGROUP) -eq $grp_cnt ]] ||
+                log_fail "expected $grp_cnt"
+done
+
+log_note "file removal"
+log_must $RM ${QFILE}_*
+sync_pool
+
+[[ $(group_object_count $QFS $QGROUP) -eq 0 ]] ||
+        log_fail "expected 0 files for $QGROUP"
+
+[[ $(group_object_count $snapfs $QGROUP) -eq $grp_cnt ]] ||
+        log_fail "expected $grp_cnt files for $QGROUP"
+
+cleanup
+log_pass "Check the zfs groupspace object used pass as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/setup.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/setup.ksh
new file mode 100755 (executable)
index 0000000..1c27075
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+verify_runnable "both"
+
+log_must clean_user_group
+
+log_must add_group $QGROUP
+log_must add_user $QGROUP $QUSER1
+log_must add_user $QGROUP $QUSER2
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota.cfg b/zfs/tests/zfs-tests/tests/functional/userquota/userquota.cfg
new file mode 100644 (file)
index 0000000..893428d
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+export QUSER1=quser1
+export QUSER2=quser2
+
+export QGROUP=qgroup
+export QGROUP1=qgroup1
+export QGROUP1=qgroup2
+
+export UQUOTA_SIZE=1000000
+export GQUOTA_SIZE=4000000
+
+export QFS=$TESTPOOL/$TESTFS
+export QFILE=$TESTDIR/qf
+export OFILE=$TESTDIR/of
+
+export SNAP_QUOTA=100m
+export TEST_QUOTA=88888
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_001_pos.ksh
new file mode 100755 (executable)
index 0000000..7a4f8f3
--- /dev/null
@@ -0,0 +1,74 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+#
+# DESCRIPTION:
+#       Check the basic function of the userquota and groupquota
+#
+#
+# STRATEGY:
+#       1. Set userquota and overwrite the quota size
+#       2. The write operation should fail with Disc quota exceeded
+#       3. Set groupquota and overwrite the quota size
+#       4. The write operation should fail with Disc quota exceeded
+#
+#
+
+function cleanup
+{
+       cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "If write operation overwrite {user|group}quota size, it will fail"
+
+mkmount_writable $QFS
+log_note "Check the userquota@$QUSER1"
+log_must $ZFS set userquota@$QUSER1=$UQUOTA_SIZE $QFS
+log_must user_run $QUSER1 $MKFILE $UQUOTA_SIZE $QFILE
+sync_pool
+log_mustnot user_run $QUSER1 $MKFILE 1 $OFILE
+cleanup_quota
+
+log_note "Check the groupquota@$QGROUP"
+log_must $ZFS set groupquota@$QGROUP=$GQUOTA_SIZE $QFS
+mkmount_writable $QFS
+log_must user_run $QUSER1 $MKFILE $GQUOTA_SIZE $QFILE
+sync_pool
+log_mustnot user_run $QUSER1 $MKFILE 1 $OFILE
+
+cleanup_quota
+
+log_pass "Write operation overwrite {user|group}quota size, it as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_002_pos.ksh
new file mode 100755 (executable)
index 0000000..aa52c1d
--- /dev/null
@@ -0,0 +1,89 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       the userquota and groupquota can be set during zpool or zfs creation"
+#
+#
+# STRATEGY:
+#       1. Set userquota and groupquota via "zpool -O or zfs create -o"
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       if poolexists $TESTPOOL1; then
+               log_must $ZPOOL destroy $TESTPOOL1
+       fi
+
+       if [[ -f $pool_vdev ]]; then
+               $RM -f $pool_vdev
+       fi
+}
+
+log_onexit cleanup
+
+log_assert \
+       "the userquota and groupquota can be set during zpool,zfs creation"
+
+typeset pool_vdev=/var/tmp/pool_dev.$$
+
+log_must $MKFILE 500m $pool_vdev
+
+if poolexists $TESTPOOL1; then
+       $ZPOOL destroy $TESTPOOL1
+fi
+
+log_must $ZPOOL create -O userquota@$QUSER1=$UQUOTA_SIZE \
+       -O groupquota@$QGROUP=$GQUOTA_SIZE $TESTPOOL1 $pool_vdev
+
+log_must eval "$ZFS list -r -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL1 > /dev/null 2>&1"
+
+log_must check_quota "userquota@$QUSER1" $TESTPOOL1 "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $TESTPOOL1 "$GQUOTA_SIZE"
+
+log_must $ZFS create -o userquota@$QUSER1=$UQUOTA_SIZE \
+       -o groupquota@$QGROUP=$GQUOTA_SIZE $TESTPOOL1/fs
+
+log_must eval "$ZFS list -r -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL1 > /dev/null 2>&1"
+
+log_must check_quota "userquota@$QUSER1" $TESTPOOL1/fs "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $TESTPOOL1/fs "$GQUOTA_SIZE"
+
+log_pass \
+       "the userquota and groupquota can be set during zpool,zfs creation"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_003_pos.ksh
new file mode 100755 (executable)
index 0000000..40903db
--- /dev/null
@@ -0,0 +1,61 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the basic function of set/get userquota and groupquota on fs
+#
+#
+# STRATEGY:
+#       1. Set userquota on fs and check the zfs get
+#       2. Set groupquota on fs and check the zfs get
+#
+
+function cleanup
+{
+       cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the basic function of set/get userquota and groupquota on fs"
+
+log_note "Check the set|get userquota@$QUSER1 and groupquota@QGROUP"
+log_must $ZFS set userquota@$QUSER1=$UQUOTA_SIZE $QFS
+log_must check_quota "userquota@$QUSER1" $QFS "$UQUOTA_SIZE"
+
+log_must $ZFS set groupquota@$QGROUP=$GQUOTA_SIZE $QFS
+log_must check_quota "groupquota@$QGROUP" $QFS "$GQUOTA_SIZE"
+
+log_pass "Check the basic function of set/get userquota on fs passed as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_004_pos.ksh
new file mode 100755 (executable)
index 0000000..7490632
--- /dev/null
@@ -0,0 +1,82 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the basic function user|group used
+#
+#
+# STRATEGY:
+#       1. Write some data to fs by normal user and check the user|group used
+#
+
+function cleanup
+{
+       cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the basic function of {user|group} used"
+
+sync_pool
+typeset user_used=$(get_value "userused@$QUSER1" $QFS)
+typeset group_used=$(get_value "groupused@$QGROUP" $QFS)
+
+if [[ $user_used != 0 ]]; then
+       log_fail "FAIL: userused is $user_used, should be 0"
+fi
+if [[ $group_used != 0 ]]; then
+       log_fail "FAIL: groupused is $group_used, should be 0"
+fi
+
+mkmount_writable $QFS
+log_must user_run $QUSER1 $MKFILE 100m $QFILE
+sync_pool
+
+user_used=$(get_value "userused@$QUSER1" $QFS)
+group_used=$(get_value "groupused@$QGROUP" $QFS)
+
+if [[ $user_used != "100M" ]]; then
+       log_note "user $QUSER1 used is $user_used"
+       log_fail "userused for user $QUSER1 expected to be 50.0M, not $user_used"
+fi
+
+if [[ $user_used != $group_used ]]; then
+       log_note "user $QUSER1 used is $user_used"
+       log_note "group $QGROUP used is $group_used"
+       log_fail "FAIL: userused should equal to groupused"
+fi
+
+log_pass "Check the basic function of {user|group}used pass as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_005_neg.ksh
new file mode 100755 (executable)
index 0000000..1b405fb
--- /dev/null
@@ -0,0 +1,94 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the invalid parameter of zfs set user|group quota
+#
+#
+# STRATEGY:
+#       1. check the invalid zfs set user|group quota to fs
+#       1. check the valid zfs set user|group quota to snapshots
+#
+
+function cleanup
+{
+       if datasetexists $snap_fs; then
+               log_must $ZFS destroy $snap_fs
+       fi
+
+       log_must cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the invalid parameter of zfs set user|group quota"
+typeset snap_fs=$QFS@snap
+
+log_must $ZFS snapshot $snap_fs
+
+set -A no_users "mms1234" "ss@#" "root-122"
+for user in "${no_users[@]}"; do
+       log_mustnot $ID $user
+       log_mustnot $ZFS set userquota@$user=100m $QFS
+done
+
+log_note "can set all numberic id even that id is not existed"
+log_must $ZFS set userquota@12345678=100m $QFS
+log_mustnot $ZFS set userquota@12345678=100m $snap_fs
+
+set -A sizes "100mfsd" "m0.12m" "GGM" "-1234-m" "123m-m"
+
+for size in "${sizes[@]}"; do
+       log_note "can not set user quota with invalid size parameter"
+       log_mustnot $ZFS set userquota@root=$size $QFS
+done
+
+log_note "can not set user quota to snapshot $snap_fs"
+log_mustnot $ZFS set userquota@root=100m $snap_fs
+
+
+set -A no_groups "aidsf@dfsd@" "123223-dsfds#sdfsd" "mss_#ss" "@@@@"
+for group in "${no_groups[@]}"; do
+       log_mustnot eval "$GREP $group /etc/group"
+       log_mustnot $ZFS set groupquota@$group=100m $QFS
+done
+
+log_note "can not set group quota with invalid size parameter"
+log_mustnot $ZFS set groupquota@root=100msfsd $QFS
+
+log_note "can not set group quota to snapshot $snap_fs"
+log_mustnot $ZFS set groupquota@root=100m $snap_fs
+
+log_pass "Check the invalid parameter of zfs set user|group quota pas as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_006_pos.ksh
new file mode 100755 (executable)
index 0000000..92b4f83
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the invalid parameter of zfs get user|group quota
+#
+#
+# STRATEGY:
+#       1. check the invalid zfs get user|group quota to fs
+#       2. check the valid zfs get user|group quota to snapshots
+#
+
+function cleanup
+{
+       if datasetexists $snap_fs; then
+               log_must $ZFS destroy $snap_fs
+       fi
+
+       log_must cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the invalid parameter of zfs get user|group quota"
+typeset snap_fs=$QFS@snap
+
+log_must $ZFS snapshot $snap_fs
+
+set -A no_users "mms1234" "ss@#" "root-122" "1234"
+for user in "${no_users[@]}"; do
+       log_mustnot eval "$ID $user >/dev/null 2>&1"
+       log_must eval "$ZFS get userquota@$user $QFS >/dev/null 2>&1"
+       log_must eval "$ZFS get userquota@$user $snap_fs >/dev/null 2>&1"
+done
+
+set -A no_groups "aidsf@dfsd@" "123223-dsfds#sdfsd" "mss_#ss" "1234"
+for group in "${no_groups[@]}"; do
+       log_mustnot eval "$GROUPDEL $group > /dev/null 2>&1"
+       log_must eval "$ZFS get groupquota@$group $QFS >/dev/null 2>&1"
+       log_must eval "$ZFS get groupquota@$group $snap_fs >/dev/null 2>&1"
+done
+
+log_pass "Check the invalid parameter of zfs get user|group quota pass as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_007_pos.ksh
new file mode 100755 (executable)
index 0000000..ec9158d
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#
+#      userquota/groupquota can be set beyond the fs quota
+#      userquota/groupquota can be set at a smaller size than its current usage.
+#
+# STRATEGY:
+#       1. set quota to a fs and set a larger size of userquota and groupquota
+#       2. write some data to the fs and set a smaller userquota and groupquota
+#
+
+function cleanup
+{
+       log_must cleanup_quota
+       log_must $ZFS set quota=none $QFS
+}
+
+log_onexit cleanup
+
+log_assert "Check set user|group quota to larger than the quota size of a fs"
+
+log_must $ZFS set quota=200m $QFS
+log_must $ZFS set userquota@$QUSER1=500m $QFS
+log_must $ZFS set groupquota@$QGROUP=600m $QFS
+
+log_must $ZFS get userquota@$QUSER1 $QFS
+log_must $ZFS get groupquota@$QGROUP $QFS
+
+log_note "write some data to the $QFS"
+mkmount_writable $QFS
+log_must user_run $QUSER1 $MKFILE 100m $QFILE
+$SYNC
+
+log_note "set user|group quota at a smaller size than it current usage"
+log_must $ZFS set userquota@$QUSER1=90m $QFS
+log_must $ZFS set groupquota@$QGROUP=90m $QFS
+
+log_must $ZFS get userquota@$QUSER1 $QFS
+log_must $ZFS get groupquota@$QGROUP $QFS
+
+log_pass "set user|group quota to larger than quota size of a fs pass as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_008_pos.ksh
new file mode 100755 (executable)
index 0000000..23ea117
--- /dev/null
@@ -0,0 +1,60 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#
+#      zfs get all <fs> does not print out userquota/groupquota
+#
+# STRATEGY:
+#       1. set userquota and groupquota to a fs
+#       2. check zfs get all fs
+#
+
+function cleanup
+{
+       log_must cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check zfs get all will not print out user|group quota"
+
+log_must $ZFS set userquota@$QUSER1=50m $QFS
+log_must $ZFS set groupquota@$QGROUP=100m $QFS
+
+log_mustnot $ZFS get all $QFS | $GREP userquota
+log_mustnot $ZFS get all $QFS | $GREP groupquota
+
+log_pass "zfs get all will not print out user|group quota"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_009_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_009_pos.ksh
new file mode 100755 (executable)
index 0000000..18c0de8
--- /dev/null
@@ -0,0 +1,92 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check user|group quota to snapshot that:
+#      1) can not set user|group quota to snapshot directly
+#      2) snapshot can inherit the parent fs's user|groupquota
+#      3) the user|group quota will not change even the parent fs's quota changed.
+#
+#
+# STRATEGY:
+#       1. create a snapshot of a fs
+#       2. set the user|group quota to snapshot and expect fail
+#      3. set user|group quota to fs and check the snapshot
+#      4. re-set user|group quota to fs and check the snapshot's value
+#
+
+function cleanup
+{
+       if datasetexists $snap_fs; then
+               log_must $ZFS destroy $snap_fs
+       fi
+
+       log_must cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the snapshot's user|group quota"
+typeset snap_fs=$QFS@snap
+
+
+log_must $ZFS set userquota@$QUSER1=$UQUOTA_SIZE $QFS
+log_must check_quota "userquota@$QUSER1" $QFS "$UQUOTA_SIZE"
+
+log_must $ZFS set groupquota@$QGROUP=$GQUOTA_SIZE $QFS
+log_must check_quota "groupquota@$QGROUP" $QFS "$GQUOTA_SIZE"
+
+log_must $ZFS snapshot $snap_fs
+
+log_note "check the snapshot $snap_fs user|group quota"
+log_must check_quota "userquota@$QUSER1" $snap_fs "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $snap_fs "$GQUOTA_SIZE"
+
+log_note  "set userquota and groupquota to $snap_fs which will fail"
+log_mustnot $ZFS set userquota@$QUSER1=$SNAP_QUOTA $snap_fs
+log_mustnot $ZFS set groupquota@$QGROUP=$SNAP_QUOTA $snap_fs
+
+log_note "change the parent's userquota and groupquota"
+log_must $ZFS set userquota@$QUSER1=$TEST_QUOTA $QFS
+log_must $ZFS set groupquota@$QGROUP=$TEST_QUOTA $QFS
+
+log_must check_quota "userquota@$QUSER1" $QFS $TEST_QUOTA
+log_must check_quota "groupquota@$QGROUP" $QFS $TEST_QUOTA
+
+log_note "check the snapshot $snap_fs userquota and groupquota"
+log_must check_quota "userquota@$QUSER1" $snap_fs "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $snap_fs "$GQUOTA_SIZE"
+
+log_pass "Check the snapshot's user|group quota pass as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_010_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_010_pos.ksh
new file mode 100755 (executable)
index 0000000..7f7f967
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check userquota and groupquota be overwrited at same time
+#
+#
+# STRATEGY:
+#       1. Set userquota and groupquota to a fs
+#       2. write to exceed the userquota size to check the result
+#       3. write to exceed the groupquota size to check the result
+#
+
+function cleanup
+{
+       cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "overwrite any of the {user|group}quota size, it will fail"
+
+log_note "overwrite to $QFS to make it exceed userquota"
+log_must $ZFS set userquota@$QUSER1=$UQUOTA_SIZE $QFS
+log_must $ZFS set groupquota@$QGROUP=$GQUOTA_SIZE $QFS
+
+mkmount_writable $QFS
+log_must user_run $QUSER1 $MKFILE $UQUOTA_SIZE $QFILE
+sync_pool
+
+log_must eval "$ZFS get -p userused@$QUSER1 $QFS >/dev/null 2>&1"
+log_must eval "$ZFS get -p groupused@$GROUPUSED $QFS >/dev/null 2>&1"
+
+log_mustnot user_run $QUSER1 $MKFILE 1 $OFILE
+
+log_must $RM -f $QFILE
+
+log_note "overwrite to $QFS to make it exceed userquota"
+log_mustnot user_run $QUSER1 $MKFILE $GQUOTA_SIZE $QFILE
+
+log_must eval "$ZFS get -p userused@$QUSER1 $QFS >/dev/null 2>&1"
+log_must eval "$ZFS get -p groupused@$GROUPUSED $QFS >/dev/null 2>&1"
+
+log_pass "overwrite any of the {user|group}quota size, it fail as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_011_pos.ksh
new file mode 100755 (executable)
index 0000000..7e04377
--- /dev/null
@@ -0,0 +1,127 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       the userquota and groupquota will not change during zfs actions, such as
+#      snapshot,clone,rename,upgrade,send,receive.
+#
+#
+# STRATEGY:
+#       1. Create a pool, and create fs with preset user,group quota
+#       2. Check set user|group quota via zfs snapshot|clone|list -o
+#       3. Check the user|group quota can not change during zfs rename|upgrade|promote
+#       4. Check the user|group quota can not change during zfs clone
+#       5. Check the user|group quota can not change during zfs send/receive
+#
+
+function cleanup
+{
+       for ds in $TESTPOOL/fs $TESTPOOL/fs-rename $TESTPOOL/fs-clone; do
+               if datasetexists $ds; then
+                       log_must $ZFS destroy -rRf $ds
+               fi
+       done
+}
+
+log_onexit cleanup
+
+log_assert \
+       "the userquota and groupquota can't change during zfs actions"
+
+cleanup
+
+log_must $ZFS create -o userquota@$QUSER1=$UQUOTA_SIZE \
+       -o groupquota@$QGROUP=$GQUOTA_SIZE $TESTPOOL/fs
+
+log_must $ZFS snapshot $TESTPOOL/fs@snap
+log_must eval "$ZFS list -r -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "userquota@$QUSER1" $TESTPOOL/fs@snap "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $TESTPOOL/fs@snap "$GQUOTA_SIZE"
+
+
+log_note "clone fs gets its parent's userquota/groupquota initially"
+log_must $ZFS clone  -o userquota@$QUSER1=$UQUOTA_SIZE \
+               -o groupquota@$QGROUP=$GQUOTA_SIZE \
+               $TESTPOOL/fs@snap $TESTPOOL/fs-clone
+
+log_must eval "$ZFS list -r -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "userquota@$QUSER1" $TESTPOOL/fs-clone "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $TESTPOOL/fs-clone "$GQUOTA_SIZE"
+
+log_must eval "$ZFS list -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL/fs-clone >/dev/null 2>&1"
+
+log_note "zfs promote can not change the previously set user|group quota"
+log_must $ZFS promote $TESTPOOL/fs-clone
+
+log_must eval "$ZFS list -r -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "userquota@$QUSER1" $TESTPOOL/fs-clone "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $TESTPOOL/fs-clone "$GQUOTA_SIZE"
+
+log_note "zfs send receive can not change the previously set user|group quota"
+log_must $ZFS send $TESTPOOL/fs-clone@snap | $ZFS receive $TESTPOOL/fs-rev
+
+log_must eval "$ZFS list -r -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "userquota@$QUSER1" $TESTPOOL/fs-rev "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $TESTPOOL/fs-rev "$GQUOTA_SIZE"
+
+log_note "zfs rename can not change the previously set user|group quota"
+log_must $ZFS rename $TESTPOOL/fs-rev $TESTPOOL/fs-rename
+
+log_must eval "$ZFS list -r -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL  >/dev/null 2>&1"
+
+log_must check_quota "userquota@$QUSER1" $TESTPOOL/fs-rename "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $TESTPOOL/fs-rename "$GQUOTA_SIZE"
+
+log_note "zfs upgrade can not change the previously set user|group quota"
+log_must $ZFS upgrade $TESTPOOL/fs-rename
+
+log_must eval "$ZFS list -r -o userquota@$QUSER1,groupquota@$QGROUP \
+       $TESTPOOL >/dev/null 2>&1"
+
+log_must check_quota "userquota@$QUSER1" $TESTPOOL/fs-rename "$UQUOTA_SIZE"
+log_must check_quota "groupquota@$QGROUP" $TESTPOOL/fs-rename "$GQUOTA_SIZE"
+
+log_pass \
+       "the userquota and groupquota can't change during zfs actions"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_012_neg.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_012_neg.ksh
new file mode 100755 (executable)
index 0000000..c1d790b
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       userquota and groupquota can not be set against snapshot
+#
+#
+# STRATEGY:
+#       1. Set userquota on snap and check the zfs get
+#       2. Set groupquota on snap and check the zfs get
+#
+
+function cleanup
+{
+       cleanup_quota
+
+       if datasetexists $snap_fs; then
+               log_must $ZFS destroy $snap_fs
+       fi
+}
+
+log_onexit cleanup
+
+typeset snap_fs=$QFS@snap
+log_assert "Check  set userquota and groupquota on snapshot"
+
+log_note "Check can not set user|group quuota on snapshot"
+log_must $ZFS snapshot $snap_fs
+
+log_mustnot $ZFS set userquota@$QUSER1=$UQUOTA_SIZE $snap_fs
+
+log_mustnot $ZFS set groupquota@$QGROUP=$GQUOTA_SIZE $snap_fs
+
+log_pass "Check  set userquota and groupquota on snapshot"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_013_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_013_pos.ksh
new file mode 100755 (executable)
index 0000000..a84a455
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2016 by Jinshan Xiong. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+#
+# DESCRIPTION:
+#       Check the basic function of the userobjquota and groupobjquota
+#
+#
+# STRATEGY:
+#       1. Set userobjquota and overwrite the quota size
+#       2. Creating new object should fail with Disc quota exceeded
+#       3. Set groupobjquota and overwrite the quota size
+#       4. Creating new object should fail with Disc quota exceeded
+#
+#
+
+function cleanup
+{
+       log_must $RM -f ${QFILE}_*
+       cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "If creating object exceeds {user|group}objquota count, it will fail"
+
+mkmount_writable $QFS
+log_must $ZFS set xattr=sa $QFS
+
+log_note "Check the userobjquota@$QUSER1"
+log_must $ZFS set userobjquota@$QUSER1=100 $QFS
+log_must user_run $QUSER1 $MKFILES ${QFILE}_1 100
+sync_pool
+log_mustnot user_run $QUSER1 $MKFILE 1 $OFILE
+cleanup_quota
+
+log_note "Check the groupobjquota@$QGROUP"
+log_must $ZFS set groupobjquota@$QGROUP=200 $QFS
+mkmount_writable $QFS
+log_must user_run $QUSER1 $MKFILES ${QFILE}_2 100
+sync_pool
+log_mustnot user_run $QUSER2 $MKFILE 1 $OFILE
+
+cleanup
+log_pass "Creating objects exceeds {user|group}objquota count, it as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userquota_common.kshlib b/zfs/tests/zfs-tests/tests/functional/userquota/userquota_common.kshlib
new file mode 100644 (file)
index 0000000..2b50e29
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota.cfg
+
+#
+# reset the userquota and groupquota and delete temporary files
+#
+function cleanup_quota
+{
+       if datasetexists $QFS; then
+               log_must $ZFS set userquota@$QUSER1=none $QFS
+               log_must $ZFS set userobjquota@$QUSER1=none $QFS
+               log_must $ZFS set userquota@$QUSER2=none $QFS
+               log_must $ZFS set userobjquota@$QUSER2=none $QFS
+               log_must $ZFS set groupquota@$QGROUP=none $QFS
+               log_must $ZFS set groupobjquota@$QGROUP=none $QFS
+               recovery_writable $QFS
+       fi
+
+       [[ -f $QFILE ]] && log_must $RM -f $QFILE
+       [[ -f $OFILE ]] && log_must $RM -f $OFILE
+       $SYNC
+
+       return 0
+}
+
+#
+# delete user and group that created during the test
+#
+function clean_user_group
+{
+       for usr in $QUSER1 $QUSER2; do
+               log_must del_user $usr
+       done
+
+       log_must del_group $QGROUP
+
+       return 0
+}
+
+#
+#  make the $QFS's mountpoint writable for all users
+#
+function mkmount_writable
+{
+       typeset fs=$1
+       typeset mntp=$(get_prop mountpoint $fs)
+       log_must $CHMOD 0777 $mntp
+}
+
+#
+# recovery the directory permission for $QFS
+#
+function recovery_writable
+{
+       typeset fs=$1
+       typeset mntp=$(get_prop mountpoint $fs)
+       log_must $CHMOD 0755 $mntp
+}
+
+#
+# check the quota value of a specific FS
+#
+function check_quota
+{
+       typeset fs=$2
+       typeset prop=$1
+       typeset expected=$3
+       typeset value=$(get_prop $prop $fs)
+
+       if (($value != $expected)); then
+               return 1
+       fi
+}
+
+#
+# zfs get prop, which return raw value not -p value.
+#
+function get_value # property dataset
+{
+        typeset prop_val
+        typeset prop=$1
+        typeset dataset=$2
+
+        prop_val=$($ZFS get -H -o value $prop $dataset 2>/dev/null)
+        if [[ $? -ne 0 ]]; then
+                log_note "Unable to get $prop property for dataset " \
+                "$dataset"
+                return 1
+        fi
+
+        $ECHO $prop_val
+        return 0
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userspace_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userspace_001_pos.ksh
new file mode 100755 (executable)
index 0000000..c336ad2
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the zfs userspace with all parameters
+#
+#
+# STRATEGY:
+#       1. set zfs userspace to a fs
+#       2. write some data to the fs with specified user
+#      3. use zfs userspace with all possible parameters to check the result
+#
+
+function cleanup
+{
+       if datasetexists $snap_fs; then
+               log_must $ZFS destroy $snap_fs
+       fi
+
+       log_must cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the zfs userspace with all possible parameters"
+
+set -A params -- "-n" "-H" "-p" "-o type,name,used,quota" \
+    "-o name,used,quota" "-o used,quota" "-o used" "-o quota" "-s type" \
+    "-s name" "-s used" "-s quota" "-S type" "-S name" "-S used" "-S quota" \
+    "-t posixuser" "-t posixgroup" "-t all" "-i" "-tsmbuser" "-t smbgroup"
+
+typeset snap_fs=$QFS@snap
+
+log_must $ZFS set userquota@$QUSER1=100m $QFS
+mkmount_writable $QFS
+log_must user_run $QUSER1 $MKFILE 50m $QFILE
+$SYNC
+
+log_must $ZFS snapshot $snap_fs
+
+for param in "${params[@]}"; do
+       log_must eval "$ZFS userspace $param $QFS >/dev/null 2>&1"
+       log_must eval "$ZFS userspace $param $snap_fs >/dev/null 2>&1"
+done
+
+log_pass "zfs userspace with all possible parameters pass as expect"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userspace_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userspace_002_pos.ksh
new file mode 100755 (executable)
index 0000000..cb84cf9
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the user used size and quota in zfs userspace
+#
+#
+# STRATEGY:
+#       1. set zfs userquota to a fs
+#       2. write some data to the fs with specified user and size
+#      3. use zfs userspace to check the used size and quota size
+#
+
+function cleanup
+{
+       if datasetexists $snapfs; then
+               log_must $ZFS destroy $snapfs
+       fi
+
+       log_must cleanup_quota
+}
+
+log_onexit cleanup
+
+log_assert "Check the zfs userspace used and quota"
+
+log_must $ZFS set userquota@$QUSER1=100m $QFS
+
+mkmount_writable $QFS
+
+log_must user_run $QUSER1 $MKFILE 50m $QFILE
+$SYNC
+
+typeset snapfs=$QFS@snap
+
+log_must $ZFS snapshot $snapfs
+
+log_must eval "$ZFS userspace $QFS >/dev/null 2>&1"
+log_must eval "$ZFS userspace $snapfs >/dev/null 2>&1"
+
+for fs in "$QFS" "$snapfs"; do
+       log_note "check the quota size in zfs userspace $fs"
+       log_must eval "$ZFS userspace $fs | $GREP $QUSER1 | $GREP 100M"
+
+       log_note "check the user used size in zfs userspace $fs"
+       log_must eval "$ZFS userspace $fs | $GREP $QUSER1 | $GREP 50\\.\*M"
+done
+
+log_pass "Check the zfs userspace used and quota"
diff --git a/zfs/tests/zfs-tests/tests/functional/userquota/userspace_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/userquota/userspace_003_pos.ksh
new file mode 100755 (executable)
index 0000000..421de65
--- /dev/null
@@ -0,0 +1,116 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2016 by Jinshan Xiong. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/userquota/userquota_common.kshlib
+
+#
+# DESCRIPTION:
+#       Check the user used object accounting in zfs userspace
+#
+#
+# STRATEGY:
+#       1. create a bunch of files by specific users
+#      2. use zfs userspace to check the used objects
+#      3. change the owner of test files and verify object count
+#      4. delete files and verify object count
+#
+
+function cleanup
+{
+       if datasetexists $snapfs; then
+               log_must $ZFS destroy $snapfs
+       fi
+
+       log_must $RM -f ${QFILE}_*
+       log_must cleanup_quota
+}
+
+function user_object_count
+{
+       typeset fs=$1
+       typeset user=$2
+       typeset cnt=$($ZFS userspace -oname,objused $fs |
+           $AWK /$user/'{print $2}')
+       echo $cnt
+}
+
+log_onexit cleanup
+
+log_assert "Check the zfs userspace object used"
+
+mkmount_writable $QFS
+log_must $ZFS set xattr=sa $QFS
+
+((user1_cnt = RANDOM % 100 + 1))
+((user2_cnt = RANDOM % 100 + 1))
+
+log_must user_run $QUSER1 $MKFILES ${QFILE}_1 $user1_cnt
+log_must user_run $QUSER2 $MKFILES ${QFILE}_2 $user2_cnt
+sync_pool
+
+typeset snapfs=$QFS@snap
+
+log_must $ZFS snapshot $snapfs
+
+log_must eval "$ZFS userspace $QFS >/dev/null 2>&1"
+log_must eval "$ZFS userspace $snapfs >/dev/null 2>&1"
+
+for fs in "$QFS" "$snapfs"; do
+       log_note "check the user used objects in zfs userspace $fs"
+       [[ $(user_object_count $fs $QUSER1) -eq $user1_cnt ]] ||
+               log_fail "expected $user1_cnt"
+       [[ $(user_object_count $fs $QUSER2) -eq $user2_cnt ]] ||
+               log_fail "expected $user2_cnt"
+done
+
+log_note "change the owner of files"
+log_must $CHOWN $QUSER2 ${QFILE}_1*
+sync_pool
+
+[[ $(user_object_count $QFS $QUSER1) -eq 0 ]] ||
+       log_fail "expected 0 files for $QUSER1"
+
+[[ $(user_object_count $snapfs $QUSER1) -eq $user1_cnt ]] ||
+       log_fail "expected $user_cnt files for $QUSER1 in snapfs"
+
+[[ $(user_object_count $QFS $QUSER2) -eq $((user1_cnt+user2_cnt)) ]] ||
+       log_fail "expected $((user1_cnt+user2_cnt)) files for $QUSER2"
+
+log_note "file removal"
+log_must $RM ${QFILE}_*
+sync_pool
+
+[[ $(user_object_count $QFS $QUSER2) -eq 0 ]] ||
+        log_fail "expected 0 files for $QUSER2"
+
+cleanup
+log_pass "Check the zfs userspace object used"
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/Makefile.am b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/Makefile.am
new file mode 100644 (file)
index 0000000..95dda3e
--- /dev/null
@@ -0,0 +1,12 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/vdev_zaps
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       vdev_zaps_001_pos.ksh \
+       vdev_zaps_002_pos.ksh \
+       vdev_zaps_003_pos.ksh \
+       vdev_zaps_004_pos.ksh \
+       vdev_zaps_005_pos.ksh \
+       vdev_zaps_006_pos.ksh \
+       vdev_zaps_007_pos.ksh \
+       vdev_zaps.kshlib
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/cleanup.ksh
new file mode 100755 (executable)
index 0000000..6c91119
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/ksh -p
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/setup.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/setup.ksh
new file mode 100755 (executable)
index 0000000..b52cf92
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/ksh -p
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+rm -rf $TESTDIR || log_fail Could not remove $TESTDIR
+mkdir -p $TESTDIR || log_fail Could not create $TESTDIR
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps.kshlib b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps.kshlib
new file mode 100644 (file)
index 0000000..dcd5ade
--- /dev/null
@@ -0,0 +1,114 @@
+#
+# CDDL HEADER START
+#
+# 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.
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2015 by Delphix. All rights reserved.
+#
+
+function get_conf_section # regex conf
+{
+        typeset dsk_line next_vd_line conf section
+        typeset regex="$1"
+        typeset conf="$2"
+
+        dsk_line=$(grep -n "$regex" "$conf" | awk -F: '{print $1}')
+        if [[ -z "$dsk_line" ]]; then
+                return
+        fi
+        next_vd_line=$(tail -n +$dsk_line "$conf" | \
+                grep -n "children\[" | awk -F: '{print $1}' | head -n 1)
+
+        if [[ -n "$next_vd_line" ]]; then
+                section=$(cat "$conf" | sed "1,${dsk_line}d" | head -n \
+                        $(($next_vd_line - 2)))
+
+        else
+                section=$(tail -n +$dsk_line "$conf")
+        fi
+        echo "$section"
+}
+
+function get_leaf_vd_zap # dsk conf
+{
+        typeset section=$(get_conf_section "$1" "$2")
+        echo "$section" | egrep \
+                "com.delphix:vdev_zap_leaf: [0-9]+" | awk '{print $2}'
+}
+
+function get_top_vd_zap # dsk conf
+{
+        typeset section=$(get_conf_section "$1" "$2")
+        echo "$section" | egrep \
+                "com.delphix:vdev_zap_top: [0-9]+" | awk '{print $2}'
+}
+
+function assert_has_sentinel # conf
+{
+        res=$(grep "com.delphix:has_per_vdev_zaps" "$1")
+        [[ -z "$res" ]] && log_fail "Pool missing ZAP feature sentinel value"
+}
+
+function assert_zap_common # pool vd lvl zapobj
+{
+        typeset pool=$1
+        typeset vd="$2"
+        typeset lvl=$3
+        typeset zapobj=$4
+
+        if [[ -z "$zapobj" ]]; then
+                log_fail "$vd on $pool has no $lvl ZAP in config"
+        elif [[ -z "$($ZDB -d $pool $zapobj | grep 'zap')" ]]; then
+                log_fail "$vd on $pool has no $lvl ZAP in MOS"
+        fi
+}
+
+function assert_top_zap # pool vd conf
+{
+        typeset pool=$1
+        typeset vd="$2"
+        typeset conf=$3
+
+        top_zap=$(get_top_vd_zap "$vd" $conf)
+        assert_zap_common $pool "$vd" "top" $top_zap
+}
+
+function assert_leaf_zap # pool vd conf
+{
+        typeset pool=$1
+        typeset vd="$2"
+        typeset conf=$3
+
+        leaf_zap=$(get_leaf_vd_zap "$vd" $conf)
+        assert_zap_common $pool "$vd" "leaf" $leaf_zap
+}
+
+#
+# Code common to setup/teardown for each test.
+#
+
+function cleanup
+{
+        if datasetexists $TESTPOOL ; then
+                log_must $ZPOOL destroy -f $TESTPOOL
+        fi
+        if [[ -e $conf ]]; then
+                log_must $RM -f "$conf"
+        fi
+        if [[ -e $POOL2 ]]; then
+                log_must $ZPOOL destroy -f $POOL2
+        fi
+}
+
+log_onexit cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_001_pos.ksh
new file mode 100755 (executable)
index 0000000..95a5864
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Verify that per-vdev ZAPs are created with one vdev.
+#
+# Strategy:
+# 1. Create a pool with one disk.
+# 2. Verify that the disk has a top and leaf ZAP in its config and the MOS.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
+
+log_assert "Per-vdev ZAPs are created on pool creation with one disk."
+
+DISK=${DISKS%% *}
+
+log_must $ZPOOL create -f $TESTPOOL $DISK
+conf="$TESTDIR/vz001"
+log_must $ZDB -PC $TESTPOOL > $conf
+
+assert_top_zap $TESTPOOL $DISK "$conf"
+assert_leaf_zap $TESTPOOL $DISK "$conf"
+assert_has_sentinel "$conf"
+
+log_pass "Per-vdev ZAPs are created in a one-disk pool."
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_002_pos.ksh
new file mode 100755 (executable)
index 0000000..c09facd
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Verify that per-vdev ZAPs are created with multiple vdevs.
+#
+# Strategy:
+# 1. Create a pool with multiple disks.
+# 2. Verify that each has both a top and leaf zap.
+# 3. Verify that each of those ZAPs exists in the MOS.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
+
+log_assert "Per-vdev ZAPs are created on pool creation with many disks."
+
+log_must $ZPOOL create -f $TESTPOOL $DISKS
+
+conf="$TESTDIR/vz002"
+log_must $ZDB -PC $TESTPOOL > $conf
+
+assert_has_sentinel "$conf"
+for DISK in $DISKS; do
+       assert_top_zap $TESTPOOL $DISK "$conf"
+       assert_leaf_zap $TESTPOOL $DISK "$conf"
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_003_pos.ksh
new file mode 100755 (executable)
index 0000000..fa92975
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Verify that per-vdev ZAPs are created with multi-level vdev tree.
+#
+# Strategy:
+# 1. Create a pool with a multi-disk mirror.
+# 2. Verify that mirror has top ZAP but no leaf ZAP.
+# 3. Verify that each disk has a leaf ZAP but no top ZAP.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
+
+log_assert "Per-vdev ZAPs are created on pool creation with multi-level vdev "\
+        "trees."
+
+log_must $ZPOOL create -f $TESTPOOL mirror $DISKS
+
+conf="$TESTDIR/vz003"
+log_must $ZDB -PC $TESTPOOL > $conf
+
+assert_has_sentinel "$conf"
+assert_top_zap $TESTPOOL "type: 'mirror'" "$conf"
+for DISK in $DISKS; do
+       assert_leaf_zap $TESTPOOL $DISK "$conf"
+        top_zap=$(get_top_vd_zap $DISK "$conf")
+        [[ -n "$top_zap" ]] && log_fail "Leaf vdev $DISK has top-level ZAP."
+done
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_004_pos.ksh
new file mode 100755 (executable)
index 0000000..16fbbc8
--- /dev/null
@@ -0,0 +1,94 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Verify that per-vdev ZAPs are properly transferred on attach/detach.
+#
+# Strategy:
+# 1. Create a pool with one disk. Verify that it has a top and leaf ZAP.
+# 2. Attach a disk.
+# 3. Verify that top-level and leaf-level ZAPs were transferred properly.
+# 4. Verify that the newly-attached disk has a leaf ZAP.
+# 5. Detach the original disk.
+# 6. Verify that top-level and leaf-level ZAPs were transferred properly.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
+
+log_assert "Per-vdev ZAPs are transferred properly on attach/detach"
+
+DISK=${DISKS%% *}
+log_must $ZPOOL create -f $TESTPOOL $DISK
+
+# Make the pool.
+conf="$TESTDIR/vz004"
+log_must $ZDB -PC $TESTPOOL > $conf
+assert_has_sentinel "$conf"
+orig_top=$(get_top_vd_zap $DISK $conf)
+orig_leaf=$(get_leaf_vd_zap $DISK $conf)
+assert_zap_common $TESTPOOL $DISK "top" $orig_top
+
+#
+# Attach a disk.
+#
+
+disk2=$(echo $DISKS | awk '{print $2}')
+log_must $ZPOOL attach $TESTPOOL $DISK $disk2
+log_must $ZDB -PC $TESTPOOL > $conf
+
+# Ensure top-level ZAP was transferred successfully.
+new_top=$(get_top_vd_zap "type: 'mirror'" $conf)
+if [[ "$new_top" -ne "$orig_top" ]]; then
+        log_fail "Top-level ZAP wasn't transferred successfully on attach."
+fi
+
+# Ensure leaf ZAP of original disk was transferred successfully.
+new_leaf=$(get_leaf_vd_zap $DISK $conf)
+if [[ "$new_leaf" -ne "$orig_leaf" ]]; then
+        log_fail "$DISK used to have leaf-level ZAP $orig_leaf, now has "\
+                "$new_leaf"
+fi
+# Ensure original disk no longer has top-level ZAP.
+dsk1_top=$(get_top_vd_zap $DISK $conf)
+[[ -n "$dsk1_top" ]] && log_fail "$DISK has top-level ZAP, but is only leaf."
+
+# Ensure attached disk got a leaf-level ZAP but not a top-level ZAP.
+dsk2_top=$(get_top_vd_zap $disk2 $conf)
+dsk2_leaf=$(get_leaf_vd_zap $disk2 $conf)
+[[ -n "$dsk2_top" ]] && log_fail "Attached disk $disk2 has top ZAP."
+[[ -z "$dsk2_leaf" ]] && log_fail "Attached disk $disk2 has no leaf ZAP."
+
+#
+# Detach original disk.
+#
+
+log_must $ZPOOL detach $TESTPOOL $DISK
+log_must $ZDB -PC $TESTPOOL > $conf
+
+final_top=$(get_top_vd_zap $disk2 $conf)
+final_leaf=$(get_leaf_vd_zap $disk2 $conf)
+# Make sure top ZAP was successfully transferred.
+[[ "$final_top" -ne "$orig_top" ]] && log_fail "Lost top-level ZAP when "\
+        "promoting $disk2 (expected $orig_top, found $final_top)"
+
+# Make sure leaf ZAP was successfully transferred.
+[[ "$final_leaf" -ne "$dsk2_leaf" ]] && log_fail "$disk2 lost its leaf ZAP "\
+        "on promotion (expected $dsk2_leaf, got $final_leaf)"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_005_pos.ksh
new file mode 100755 (executable)
index 0000000..b824c9c
--- /dev/null
@@ -0,0 +1,62 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Verify that per-vdev ZAPs persist when the pool is exported and imported.
+#
+# Strategy:
+# 1. Create a pool with a disk.
+# 2. Export the pool and re-import it.
+# 3. Verify that the ZAPs aren't different.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
+
+log_assert "Per-vdev ZAPs persist across export/import."
+
+DISK=${DISKS%% *}
+log_must $ZPOOL create -f $TESTPOOL $DISK
+
+# Make the pool.
+conf="$TESTDIR/vz005"
+log_must $ZDB -PC $TESTPOOL > $conf
+assert_has_sentinel "$conf"
+orig_top=$(get_top_vd_zap $DISK $conf)
+orig_leaf=$(get_leaf_vd_zap $DISK $conf)
+assert_zap_common $TESTPOOL $DISK "top" $orig_top
+assert_zap_common $TESTPOOL $DISK "leaf" $orig_leaf
+
+# Export the pool.
+log_must $ZPOOL export $TESTPOOL
+
+# Import the pool.
+log_must $ZPOOL import $TESTPOOL
+
+# Verify that ZAPs persisted.
+log_must $ZDB -PC $TESTPOOL > $conf
+
+new_top=$(get_top_vd_zap $DISK $conf)
+new_leaf=$(get_leaf_vd_zap $DISK $conf)
+
+[[ "$new_top" -ne "$orig_top" ]] && log_fail "Top ZAP ($new_top) after "\
+        "import does not match top ZAP before export ($orig_top)"
+[[ "$new_leaf" -ne "$orig_leaf" ]] && log_fail "Leaf ZAP ($new_leaf) after "\
+        "import does not match leaf ZAP before export ($orig_leaf)"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_006_pos.ksh
new file mode 100755 (executable)
index 0000000..3ea3867
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/ksh
+
+#
+# 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) 2015, 2016 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Verify that top-level per-vdev ZAPs are created for added devices
+#
+# Strategy:
+# 1. Create a pool with one disk.
+# 2. Add a disk.
+# 3. Verify its ZAPs were created.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
+
+DISK_ARR=($DISKS)
+DISK=${DISK_ARR[0]}
+log_must $ZPOOL create -f $TESTPOOL $DISK
+
+log_assert "Per-vdev ZAPs are created for added vdevs."
+
+log_must $ZPOOL add -f $TESTPOOL ${DISK_ARR[1]}
+conf="$TESTDIR/vz006"
+log_must $ZDB -PC $TESTPOOL > $conf
+
+assert_has_sentinel "$conf"
+orig_top=$(get_top_vd_zap ${DISK_ARR[1]} $conf)
+assert_zap_common $TESTPOOL ${DISK_ARR[1]} "top" $orig_top
+assert_leaf_zap $TESTPOOL ${DISK_ARR[1]} "$conf"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_007_pos.ksh b/zfs/tests/zfs-tests/tests/functional/vdev_zaps/vdev_zaps_007_pos.ksh
new file mode 100755 (executable)
index 0000000..daf65b2
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Verify that ZAPs are handled properly during mirror pool splitting.
+#
+# Strategy:
+# 1. Create a pool with a two-way mirror.
+# 2. Split the pool.
+# 3. Verify that the ZAPs in the old pool persisted.
+# 4. Import the new pool.
+# 5. Verify that the ZAPs in the new pool persisted.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/vdev_zaps/vdev_zaps.kshlib
+
+DISK_ARR=($DISKS)
+POOL2=${TESTPOOL}2
+log_must $ZPOOL create -f $TESTPOOL mirror ${DISK_ARR[0]} ${DISK_ARR[1]}
+
+log_assert "Per-vdev ZAPs persist correctly on the original pool after split."
+conf="$TESTDIR/vz007"
+log_must $ZDB -PC $TESTPOOL > $conf
+
+assert_has_sentinel "$conf"
+orig_top=$(get_top_vd_zap "type: 'mirror'" $conf)
+orig_leaf0=$(get_leaf_vd_zap ${DISK_ARR[0]} $conf)
+orig_leaf1=$(get_leaf_vd_zap ${DISK_ARR[1]} $conf)
+assert_zap_common $TESTPOOL "type: 'mirror'" "top" $orig_top
+assert_zap_common $TESTPOOL ${DISK_ARR[0]} "leaf" $orig_leaf0
+assert_zap_common $TESTPOOL ${DISK_ARR[1]} "leaf" $orig_leaf1
+
+log_must $ZPOOL split $TESTPOOL $POOL2 ${DISK_ARR[1]}
+
+# Make sure old pool's ZAPs are consistent.
+log_must $ZDB -PC $TESTPOOL > $conf
+new_leaf0=$(get_leaf_vd_zap ${DISK_ARR[0]} $conf)
+new_top_s0=$(get_top_vd_zap ${DISK_ARR[0]} $conf)
+
+[[ "$new_leaf0" -ne "$orig_leaf0" ]] && log_fail "Leaf ZAP in original pool "\
+        "didn't persist (expected $orig_leaf0, got $new_leaf0)"
+[[ "$new_top_s0" -ne "$orig_top" ]] && log_fail "Top ZAP in original pool "\
+        "didn't persist (expected $orig_top, got $new_top_s0)"
+
+log_assert "Per-vdev ZAPs persist on the new pool after import."
+
+# Import the split pool.
+log_must $ZPOOL import $POOL2
+log_must $ZDB -PC $TESTPOOL > $conf
+
+new_leaf1=$(get_leaf_vd_zap ${DISK_ARR[1]} $conf)
+new_top_s1=$(get_top_vd_zap ${DISK_ARR[1]} $conf)
+[[ "$new_leaf1" -ne "$orig_leaf1" ]] && log_fail "Leaf ZAP in new pool "\
+        "didn't persist (expected $orig_leaf1, got $new_leaf1)"
+[[ "$new_top_s1" -ne "$orig_top" ]] && log_fail "Top ZAP in new pool "\
+        "didn't persist (expected $orig_top, got $new_top_s1)"
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/write_dirs/Makefile.am b/zfs/tests/zfs-tests/tests/functional/write_dirs/Makefile.am
new file mode 100644 (file)
index 0000000..80493ab
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/write_dirs
+dist_pkgdata_SCRIPTS = \
+       setup.ksh \
+       cleanup.ksh \
+       write_dirs.cfg \
+       write_dirs_001_pos.ksh \
+       write_dirs_002_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/write_dirs/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/write_dirs/cleanup.ksh
new file mode 100755 (executable)
index 0000000..5052615
--- /dev/null
@@ -0,0 +1,35 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/write_dirs/write_dirs.cfg
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/write_dirs/setup.ksh b/zfs/tests/zfs-tests/tests/functional/write_dirs/setup.ksh
new file mode 100755 (executable)
index 0000000..3f10c7f
--- /dev/null
@@ -0,0 +1,47 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/write_dirs/write_dirs.cfg
+
+verify_runnable "global"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+         delete_partitions
+fi
+log_must set_partition 0 "" $SIZE $DISK
+
+default_setup "${DISK}${SLICE_PREFIX}${SLICE}"
diff --git a/zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs.cfg b/zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs.cfg
new file mode 100644 (file)
index 0000000..fe7b5ab
--- /dev/null
@@ -0,0 +1,48 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+export SIZE="1gb"
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+export DISKSARRAY=$DISKS
+
+if is_linux; then
+       set_slice_prefix
+       set_device_dir
+       export SLICE=1
+else
+       DEV_DSKDIR="/dev"
+       export SLICE_PREFIX="s"
+       export SLICE=0
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs_001_pos.ksh
new file mode 100755 (executable)
index 0000000..3261af1
--- /dev/null
@@ -0,0 +1,77 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/write_dirs/write_dirs.cfg
+
+#
+# DESCRIPTION:
+# Create as many directories with 50 big files each until the file system
+# is full. The zfs file system should be stable and works well.
+#
+# STRATEGY:
+# 1. Create a pool & dateset
+# 2. Make directories in the zfs file system
+# 3. Create 50 big files in each directories
+# 4. Test case exit when the disk is full.
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for file in `$FIND $TESTDIR -type f`; do
+               $CAT /dev/null > $file
+       done
+       log_must $SYNC
+       log_must $RM -rf $TESTDIR/*
+}
+
+typeset -i retval=0
+log_assert "Creating directories with 50 big files in each, until file system "\
+       "is full."
+
+log_onexit cleanup
+
+typeset -i bytes=8192
+typeset -i num_writes=300000
+typeset -i dirnum=50
+typeset -i filenum=50
+
+fill_fs "" $dirnum $filenum $bytes $num_writes
+retval=$?
+if (( retval == 28 )); then
+       log_note "No space left on device."
+elif (( retval != 0 )); then
+       log_fail "Unexpected exit: $retval"
+fi
+
+log_pass "Write big files in a directory succeeded."
diff --git a/zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/write_dirs/write_dirs_002_pos.ksh
new file mode 100755 (executable)
index 0000000..39c410b
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/write_dirs/write_dirs.cfg
+
+#
+# DESCRIPTION:
+# Create as many directories with 5000 files each until the file system
+# is full. The zfs file system should be work well and stable.
+#
+# STRATEGY:
+# 1. Create a pool & dateset
+# 2. Make directories in the zfs file system
+# 3. Create 5000 files in each directories
+# 4. Test case exit when the disk is full
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+       for file in `$FIND $TESTDIR -type f`; do
+               $CAT /dev/null > $file
+       done
+       log_must $SYNC
+       log_must $RM -rf $TESTDIR/*
+}
+
+typeset -i retval=0
+
+log_assert "Creating directories with 5000 files in each, until file system " \
+       "is full."
+
+log_onexit cleanup
+
+typeset -i bytes=8192
+typeset -i num_writes=20
+typeset -i dirnum=50
+typeset -i filenum=5000
+
+fill_fs "" $dirnum $filenum $bytes $num_writes
+retval=$?
+if (( retval == 28 )); then
+       log_note "No space left on device."
+elif (( retval != 0 )); then
+       log_fail "Unexpected exit: $retval"
+fi
+
+log_pass "Create many files in a directory succeeded."
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/Makefile.am b/zfs/tests/zfs-tests/tests/functional/xattr/Makefile.am
new file mode 100644 (file)
index 0000000..ac2cb54
--- /dev/null
@@ -0,0 +1,18 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/xattr
+dist_pkgdata_SCRIPTS = \
+       xattr_common.kshlib \
+       setup.ksh \
+       cleanup.ksh \
+       xattr_001_pos.ksh \
+       xattr_002_neg.ksh \
+       xattr_003_neg.ksh \
+       xattr_004_pos.ksh \
+       xattr_005_pos.ksh \
+       xattr_006_pos.ksh \
+       xattr_007_neg.ksh \
+       xattr_008_pos.ksh \
+       xattr_009_neg.ksh \
+       xattr_010_neg.ksh \
+       xattr_011_pos.ksh \
+       xattr_012_pos.ksh \
+       xattr_013_pos.ksh 
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/cleanup.ksh
new file mode 100755 (executable)
index 0000000..b52c07d
--- /dev/null
@@ -0,0 +1,45 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+ZFS_USER=$($CAT /tmp/zfs-xattr-test-user.txt)
+$RM /tmp/zfs-xattr-test-user.txt
+
+USES_NIS=$($CAT /tmp/zfs-xattr-test-nis.txt)
+$RM /tmp/zfs-xattr-test-nis.txt
+
+del_user $ZFS_USER
+
+if [ "${USES_NIS}" == "true" ]
+then
+    $SVCADM enable svc:/network/nis/client:default
+fi
+
+default_cleanup
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/setup.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/setup.ksh
new file mode 100755 (executable)
index 0000000..d359eb0
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+# if we're running NIS, turn it off until we clean up
+# (it can cause useradd to take a long time, hitting our TIMEOUT)
+USES_NIS=FALSE
+$SVCS svc:/network/nis/client:default | $GREP online > /dev/null
+if [ $? -eq 0 ]
+then
+       $SVCADM disable -t svc:/network/nis/client:default
+       USES_NIS=true
+fi
+
+# Make sure we use a brand new user for this
+ZFS_USER=zxtr
+ZFS_GROUP=staff
+while [ -z "${FOUND}" ]
+do
+       COUNT=0
+       USER_EXISTS=$( $GREP $ZFS_USER /etc/passwd )
+       if [ ! -z "${USER_EXISTS}" ]
+       then
+               ZFS_USER="${ZFS_USER}${COUNT}"
+               COUNT=$(( $COUNT + 1 ))
+       else
+               FOUND="true"
+       fi
+done
+
+log_must add_user $ZFS_GROUP $ZFS_USER
+
+$ECHO $ZFS_USER > /tmp/zfs-xattr-test-user.txt
+$ECHO $USES_NIS > /tmp/zfs-xattr-test-nis.txt
+
+DISK=${DISKS%% *}
+default_setup $DISK
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_001_pos.ksh
new file mode 100755 (executable)
index 0000000..1bc7e5c
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+#
+# Creating, reading and writing xattrs on ZFS filesystems works as expected
+#
+# STRATEGY:
+#      1. Create an xattr on a ZFS-based file using runat
+#      2. Read an empty xattr directory
+#       3. Write the xattr using runat and cat
+#      3. Read the xattr using runat
+#      4. Delete the xattr
+#      5. List the xattr namespace successfully, checking for deletion
+#
+
+function cleanup {
+
+       if [ -f $TESTDIR/myfile.$$ ]
+       then
+               log_must $RM $TESTDIR/myfile.$$
+       fi
+}
+
+log_assert "Create/read/write/append of xattrs works"
+log_onexit cleanup
+
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+verify_write_xattr $TESTDIR/myfile.$$ passwd
+delete_xattr $TESTDIR/myfile.$$ passwd
+
+log_pass "Create/read/write of xattrs works"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_002_neg.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_002_neg.ksh
new file mode 100755 (executable)
index 0000000..cd57b35
--- /dev/null
@@ -0,0 +1,56 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+#
+# Trying to read a non-existent xattr should fail.
+#
+# STRATEGY:
+#      1. Create a file
+#       2. Try to read a non-existent xattr, check that an error is returned.
+#
+
+function cleanup {
+
+       log_must $RM $TESTDIR/myfile.$$
+
+}
+
+log_assert "A read of a non-existent xattr fails"
+log_onexit cleanup
+
+# create a file
+log_must $TOUCH $TESTDIR/myfile.$$
+log_mustnot eval "$CAT $TESTDIR/myfile.$$ not-here.txt > /dev/null 2>&1"
+
+log_pass "A read of a non-existent xattr fails"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_003_neg.ksh
new file mode 100755 (executable)
index 0000000..90d7860
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+#
+# Attempting to read an xattr on a file for which we have no permissions
+# should fail.
+#
+# STRATEGY:
+#      1. Create a file, and set an with an xattr
+#       2. Set the octal file permissions to 000 on the file.
+#      3. Check that we're unable to read the xattr as a non-root user
+#      4. Check that we're unable to write an xattr as a non-root user
+#
+
+function cleanup {
+
+       log_must $RM $TESTDIR/myfile.$$
+
+}
+
+log_assert "read/write xattr on a file with no permissions fails"
+log_onexit cleanup
+
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+log_must $CHMOD 000 $TESTDIR/myfile.$$
+log_mustnot $SU $ZFS_USER -c "$RUNAT $TESTDIR/myfile.$$ $CAT passwd"
+log_mustnot $SU $ZFS_USER -c "$RUNAT $TESTDIR/myfile.$$ $CP /etc/passwd ."
+
+log_pass "read/write xattr on a file with no permissions fails"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_004_pos.ksh
new file mode 100755 (executable)
index 0000000..f0f301f
--- /dev/null
@@ -0,0 +1,87 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+#
+# Creating files on ufs|ext2 and tmpfs, and copying those files to ZFS with
+# appropriate cp flags, the xattrs will still be readable.
+#
+# STRATEGY:
+#      1. Create files in ufs|ext2 and tmpfs with xattrs
+#       2. Copy those files to zfs
+#      3. Ensure the xattrs can be read and written
+#      4. Do the same in reverse.
+#
+
+# we need to be able to create zvols to hold our test
+# ufs|ext2 filesystem.
+verify_runnable "global"
+
+# Make sure we clean up properly
+function cleanup {
+
+       if [ $( ismounted /tmp/$NEWFS_DEFAULT_FS.$$ $NEWFS_DEFAULT_FS ) ]
+       then
+               log_must $UMOUNT /tmp/$NEWFS_DEFAULT_FS.$$
+               log_must $RM -rf /tmp/$NEWFS_DEFAULT_FS.$$
+       fi
+}
+
+log_assert "Files from $NEWFS_DEFAULT_FS,tmpfs with xattrs copied to zfs retain xattr info."
+log_onexit cleanup
+
+# Create a UFS|EXT2 file system that we can work in
+log_must $ZFS create -V128m $TESTPOOL/$TESTFS/zvol
+block_device_wait
+log_must eval "$ECHO y | $NEWFS $ZVOL_DEVDIR/$TESTPOOL/$TESTFS/zvol > /dev/null 2>&1"
+
+log_must $MKDIR /tmp/$NEWFS_DEFAULT_FS.$$
+log_must $MOUNT $ZVOL_DEVDIR/$TESTPOOL/$TESTFS/zvol /tmp/$NEWFS_DEFAULT_FS.$$
+
+# Create files in ufs|ext2 and tmpfs, and set some xattrs on them.
+log_must $TOUCH /tmp/$NEWFS_DEFAULT_FS.$$/$NEWFS_DEFAULT_FS-file.$$
+log_must $TOUCH /tmp/tmpfs-file.$$
+
+log_must $RUNAT /tmp/$NEWFS_DEFAULT_FS.$$/$NEWFS_DEFAULT_FS-file.$$ $CP /etc/passwd .
+log_must $RUNAT /tmp/tmpfs-file.$$ $CP /etc/group .
+
+# copy those files to ZFS
+log_must $CP -@ /tmp/$NEWFS_DEFAULT_FS.$$/$NEWFS_DEFAULT_FS-file.$$ $TESTDIR
+log_must $CP -@ /tmp/tmpfs-file.$$ $TESTDIR
+
+# ensure the xattr information has been copied correctly
+log_must $RUNAT $TESTDIR/$NEWFS_DEFAULT_FS-file.$$ $DIFF passwd /etc/passwd
+log_must $RUNAT $TESTDIR/tmpfs-file.$$ $DIFF group /etc/group
+
+log_must $UMOUNT /tmp/$NEWFS_DEFAULT_FS.$$
+log_pass "Files from $NEWFS_DEFAULT_FS,tmpfs with xattrs copied to zfs retain xattr info."
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_005_pos.ksh
new file mode 100755 (executable)
index 0000000..f7be58e
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# read/write/create/delete xattr on a clone filesystem
+#
+#
+# STRATEGY:
+#      1. Create an xattr on a filesystem
+#      2. Snapshot the filesystem and clone it
+#       3. Verify the xattr can still be read, written, deleted
+#      4. Verify we can create new xattrs on new files created on the clone
+#
+
+function cleanup {
+
+       log_must $ZFS destroy $TESTPOOL/$TESTFS/clone
+       log_must $ZFS destroy $TESTPOOL/$TESTFS@snapshot1
+       log_must $RM $TESTDIR/myfile.$$
+}
+
+log_assert "read/write/create/delete xattr on a clone filesystem"
+log_onexit cleanup
+
+# create a file, and an xattr on it
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+# snapshot & clone the filesystem
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snapshot1
+log_must $ZFS clone $TESTPOOL/$TESTFS@snapshot1 $TESTPOOL/$TESTFS/clone
+log_must $ZFS set mountpoint=$TESTDIR/clone $TESTPOOL/$TESTFS/clone
+
+# check for the xattrs on the clone
+verify_xattr $TESTDIR/clone/myfile.$$ passwd /etc/passwd
+
+# check we can create xattrs on the clone
+create_xattr $TESTDIR/clone/myfile.$$ foo /etc/passwd
+delete_xattr $TESTDIR/clone/myfile.$$ foo
+
+# delete the original dataset xattr
+delete_xattr $TESTDIR/myfile.$$ passwd
+
+# verify it's still there on the clone
+verify_xattr $TESTDIR/clone/myfile.$$ passwd /etc/passwd
+delete_xattr $TESTDIR/clone/myfile.$$ passwd
+
+log_pass "read/write/create/delete xattr on a clone filesystem"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_006_pos.ksh
new file mode 100755 (executable)
index 0000000..24915fd
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# Xattrs present on a file in a snapshot should be visible.
+#
+# STRATEGY:
+#      1. Create a file and give it an xattr
+#       2. Take a snapshot of the filesystem
+#      3. Verify that we can take a snapshot of it.
+#
+
+function cleanup {
+
+       log_must $ZFS destroy $TESTPOOL/$TESTFS@snap
+       log_must $RM $TESTDIR/myfile.$$
+
+}
+
+log_assert "read xattr on a snapshot"
+log_onexit cleanup
+
+# create a file, and an xattr on it
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+# snapshot the filesystem
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snap
+
+# check for the xattr on the snapshot
+verify_xattr $TESTDIR/.zfs/snapshot/snap/myfile.$$ passwd /etc/passwd
+
+log_pass "read xattr on a snapshot"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_007_neg.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_007_neg.ksh
new file mode 100755 (executable)
index 0000000..bef6020
--- /dev/null
@@ -0,0 +1,81 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# Creating and writing xattrs on files in snapshot directories fails. Also,
+# we shouldn't be able to list the xattrs of files in snapshots who didn't have
+# xattrs when the snapshot was created (the xattr namespace wouldn't have been
+# created yet, and snapshots are read-only) See fsattr(5) for more details.
+#
+# STRATEGY:
+#      1. Create a file and add an xattr to it.
+#      2. Create another file, but don't add an xattr to it.
+#       3. Snapshot the filesystem
+#      4. Verify we're unable to alter the xattr on the first file
+#      5. Verify we're unable to list the xattrs on the second file
+#
+
+function cleanup {
+       log_must $ZFS destroy $TESTPOOL/$TESTFS@snap
+       log_must $RM $TESTDIR/myfile2.$$
+       log_must $RM $TESTDIR/myfile.$$
+       log_must $RM /tmp/output.$$
+       [[ -e /tmp/expected_output.$$ ]]  && log_must $RM  \
+       /tmp/expected_output.$$
+
+}
+
+log_assert "create/write xattr on a snapshot fails"
+log_onexit cleanup
+
+# create a file, and an xattr on it
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+# create another file that doesn't have an xattr
+log_must $TOUCH $TESTDIR/myfile2.$$
+
+# snapshot the filesystem
+log_must $ZFS snapshot $TESTPOOL/$TESTFS@snap
+
+# we shouldn't be able to alter the first file's xattr
+log_mustnot eval " $RUNAT $TESTDIR/.zfs/snapshot/snap/myfile.$$ \
+    $CP /etc/passwd .  >/tmp/output.$$  2>&1"
+log_must $GREP  -i  Read-only  /tmp/output.$$
+
+log_must eval "$RUNAT $TESTDIR/.zfs/snapshot/snap/myfile2.$$  \
+    $LS >/tmp/output.$$  2>&1"
+create_expected_output  /tmp/expected_output.$$ SUNWattr_ro SUNWattr_rw
+log_must $DIFF /tmp/output.$$ /tmp/expected_output.$$
+
+log_pass "create/write xattr on a snapshot fails"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_008_pos.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_008_pos.ksh
new file mode 100755 (executable)
index 0000000..40cc4a0
--- /dev/null
@@ -0,0 +1,80 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# We verify that the special . and .. dirs work as expected for xattrs.
+#
+# STRATEGY:
+#      1. Create a file and an xattr on that file
+#      2. List the . directory, verifying the output
+#      3. Verify we're unable to list the ../ directory
+#
+
+function cleanup {
+       typeset file
+
+       for file in /tmp/output.$$ /tmp/expected-output.$$ \
+               $TESTDIR/myfile.$$ ; do
+               log_must $RM -f $file
+       done
+}
+
+log_assert "special . and .. dirs work as expected for xattrs"
+log_onexit cleanup
+
+# create a file, and an xattr on it
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+# listing the directory .
+log_must eval "$RUNAT $TESTDIR/myfile.$$ $LS  . > /tmp/output.$$"
+create_expected_output  /tmp/expected-output.$$  \
+    SUNWattr_ro  SUNWattr_rw  passwd
+log_must $DIFF /tmp/output.$$ /tmp/expected-output.$$
+# list the directory . long form
+log_must eval "$RUNAT $TESTDIR/myfile.$$ $LS -a . > /tmp/output.$$"
+create_expected_output  /tmp/expected-output.$$ . ..  \
+    SUNWattr_ro  SUNWattr_rw  passwd
+log_must $DIFF /tmp/output.$$ /tmp/expected-output.$$
+
+# list the directory .. expecting one file
+OUTPUT=$($RUNAT $TESTDIR/myfile.$$ $LS ..)
+if [ "$OUTPUT" != ".." ]
+then
+       log_fail "Listing the .. directory doesn't show \"..\" as expected."
+fi
+
+# verify we can't list ../
+log_mustnot eval "$RUNAT $TESTDIR/myfile.$$ $LS ../ > /dev/null 2>&1"
+
+log_pass "special . and .. dirs work as expected for xattrs"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_009_neg.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_009_neg.ksh
new file mode 100755 (executable)
index 0000000..40b3617
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# links between xattr and normal file namespace fail
+#
+# STRATEGY:
+#      1. Create a file and add an xattr to it (to ensure the namespace exists)
+#       2. Verify we're unable to create a symbolic link
+#      3. Verify we're unable to create a hard link
+#
+
+function cleanup {
+
+       log_must $RM $TESTDIR/myfile.$$
+
+}
+
+log_assert "links between xattr and normal file namespace fail"
+log_onexit cleanup
+
+# create a file, and an xattr on it
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+# Try to create a soft link from the xattr namespace to the default namespace
+log_mustnot $RUNAT $TESTDIR/myfile.$$ $LN -s /etc/passwd foo
+
+# Try to create a hard link from the xattr namespace to the default namespace
+log_mustnot $RUNAT $TESTDIR/myfile.$$ $LN /etc/passwd foo
+
+log_pass "links between xattr and normal file namespace fail"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_010_neg.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_010_neg.ksh
new file mode 100755 (executable)
index 0000000..e3e23a4
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# Verify that mkdir and various mknods fail inside the xattr namespace
+#
+# STRATEGY:
+#      1. Create a file and add an xattr to it (to ensure the namespace exists)
+#       2. Verify that mkdir fails inside the xattr namespace
+#      3. Verify that various mknods fails inside the xattr namespace
+#
+#
+
+function cleanup {
+
+       log_must $RM $TESTDIR/myfile.$$
+}
+
+log_assert "mkdir, mknod fail"
+log_onexit cleanup
+
+# create a file, and an xattr on it
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+# Try to create directory in the xattr namespace
+log_mustnot $RUNAT $TESTDIR/myfile.$$ $MKDIR foo
+
+# Try to create a range of different filetypes in the xattr namespace
+log_mustnot $RUNAT $TESTDIR/myfile.$$ $MKNOD block b 888 888
+
+log_mustnot $RUNAT $TESTDIR/myfile.$$ $MKNOD char c
+
+log_mustnot $RUNAT $TESTDIR/myfile.$$ $MKNOD fifo p
+
+log_pass "mkdir, mknod fail"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_011_pos.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_011_pos.ksh
new file mode 100755 (executable)
index 0000000..e3a8d26
--- /dev/null
@@ -0,0 +1,193 @@
+#!/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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+#
+# Basic applications work with xattrs: cpio cp find mv pax tar
+#
+# STRATEGY:
+#      1. For each application
+#       2. Create an xattr and archive/move/copy/find files with xattr support
+#      3. Also check that when appropriate flag is not used, the xattr
+#         doesn't get copied
+#
+
+function cleanup {
+
+       log_must $RM $TESTDIR/myfile.$$
+}
+
+log_assert "Basic applications work with xattrs: cpio cp find mv pax tar"
+log_onexit cleanup
+
+# Create a file, and set an xattr on it. This file is used in several of the
+# test scenarios below.
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+
+# For the archive applications below (tar, cpio, pax)
+# we create two archives, one with xattrs, one without
+# and try various cpio options extracting the archives
+# with and without xattr support, checking for correct behaviour
+
+
+log_note "Checking cpio"
+log_must $TOUCH $TESTDIR/cpio.$$
+create_xattr $TESTDIR/cpio.$$ passwd /etc/passwd
+$ECHO $TESTDIR/cpio.$$ | $CPIO -o@ > /tmp/xattr.$$.cpio
+$ECHO $TESTDIR/cpio.$$ | $CPIO -o > /tmp/noxattr.$$.cpio
+
+# we should have no xattr here
+log_must $CPIO -iu < /tmp/xattr.$$.cpio
+log_mustnot eval "$RUNAT $TESTDIR/cpio.$$ $CAT passwd > /dev/null 2>&1"
+
+# we should have an xattr here
+log_must $CPIO -iu@ < /tmp/xattr.$$.cpio
+log_must eval "$RUNAT $TESTDIR/cpio.$$ $CAT passwd > /dev/null 2>&1"
+
+# we should have no xattr here
+log_must $CPIO -iu < /tmp/noxattr.$$.cpio
+log_mustnot eval "$RUNAT $TESTDIR/cpio.$$ $CAT passwd > /dev/null 2>&1"
+
+# we should have no xattr here
+log_must $CPIO -iu@ < /tmp/noxattr.$$.cpio
+log_mustnot eval "$RUNAT $TESTDIR/cpio.$$ $CAT passwd > /dev/null 2>&1"
+log_must $RM $TESTDIR/cpio.$$ /tmp/xattr.$$.cpio /tmp/noxattr.$$.cpio
+
+
+
+log_note "Checking cp"
+# check that with the right flag, the xattr is preserved
+log_must $CP -@ $TESTDIR/myfile.$$ $TESTDIR/myfile2.$$
+compare_xattrs $TESTDIR/myfile.$$ $TESTDIR/myfile2.$$ passwd
+log_must $RM $TESTDIR/myfile2.$$
+
+# without the right flag, there should be no xattr
+log_must $CP $TESTDIR/myfile.$$ $TESTDIR/myfile2.$$
+log_mustnot eval "$RUNAT $TESTDIR/myfile2.$$ $LS passwd > /dev/null 2>&1"
+log_must $RM $TESTDIR/myfile2.$$
+
+
+
+log_note "Checking find"
+# create a file without xattrs, and check that find -xattr only finds
+# our test file that has an xattr.
+log_must $MKDIR $TESTDIR/noxattrs
+log_must $TOUCH $TESTDIR/noxattrs/no-xattr
+
+$FIND $TESTDIR -xattr | $GREP myfile.$$
+[[ $? -ne 0 ]] && \
+       log_fail "find -xattr didn't find our file that had an xattr."
+$FIND $TESTDIR -xattr | $GREP no-xattr
+[[ $? -eq 0 ]] && \
+       log_fail "find -xattr found a file that didn't have an xattr."
+log_must $RM -rf $TESTDIR/noxattrs
+
+
+
+log_note "Checking mv"
+# mv doesn't have any flags to preserve/ommit xattrs - they're
+# always moved.
+log_must $TOUCH $TESTDIR/mvfile.$$
+create_xattr $TESTDIR/mvfile.$$ passwd /etc/passwd
+log_must $MV $TESTDIR/mvfile.$$ $TESTDIR/mvfile2.$$
+verify_xattr $TESTDIR/mvfile2.$$ passwd /etc/passwd
+log_must $RM $TESTDIR/mvfile2.$$
+
+
+log_note "Checking pax"
+log_must $TOUCH $TESTDIR/pax.$$
+create_xattr $TESTDIR/pax.$$ passwd /etc/passwd
+log_must $PAX -w -f $TESTDIR/noxattr.pax $TESTDIR/pax.$$
+log_must $PAX -w@ -f $TESTDIR/xattr.pax $TESTDIR/pax.$$
+log_must $RM $TESTDIR/pax.$$
+
+# we should have no xattr here
+log_must $PAX -r -f $TESTDIR/noxattr.pax
+log_mustnot eval "$RUNAT $TESTDIR/pax.$$ $CAT passwd > /dev/null 2>&1"
+log_must $RM $TESTDIR/pax.$$
+
+# we should have no xattr here
+log_must $PAX -r@ -f $TESTDIR/noxattr.pax
+log_mustnot eval "$RUNAT $TESTDIR/pax.$$ $CAT passwd > /dev/null 2>&1"
+log_must $RM $TESTDIR/pax.$$
+
+
+# we should have an xattr here
+log_must $PAX -r@ -f $TESTDIR/xattr.pax
+verify_xattr $TESTDIR/pax.$$ passwd /etc/passwd
+log_must $RM $TESTDIR/pax.$$
+
+# we should have no xattr here
+log_must $PAX -r -f $TESTDIR/xattr.pax $TESTDIR
+log_mustnot eval "$RUNAT $TESTDIR/pax.$$ $CAT passwd > /dev/null 2>&1"
+log_must $RM $TESTDIR/pax.$$ $TESTDIR/noxattr.pax $TESTDIR/xattr.pax
+
+
+log_note "Checking tar"
+log_must $TOUCH $TESTDIR/tar.$$
+create_xattr $TESTDIR/tar.$$ passwd /etc/passwd
+
+log_must cd $TESTDIR
+
+log_must $TAR cf noxattr.tar tar.$$
+log_must $TAR c@f xattr.tar tar.$$
+log_must $RM $TESTDIR/tar.$$
+
+# we should have no xattr here
+log_must $TAR xf xattr.tar
+log_mustnot eval "$RUNAT $TESTDIR/tar.$$ $CAT passwd > /dev/null 2>&1"
+log_must $RM $TESTDIR/tar.$$
+
+# we should have an xattr here
+log_must $TAR x@f xattr.tar
+verify_xattr tar.$$ passwd /etc/passwd
+log_must $RM $TESTDIR/tar.$$
+
+# we should have no xattr here
+log_must $TAR xf $TESTDIR/noxattr.tar
+log_mustnot eval "$RUNAT $TESTDIR/tar.$$ $CAT passwd > /dev/null 2>&1"
+log_must $RM $TESTDIR/tar.$$
+
+# we should have no xattr here
+log_must $TAR x@f $TESTDIR/noxattr.tar
+log_mustnot eval "$RUNAT $TESTDIR/tar.$$ $CAT passwd > /dev/null 2>&1"
+log_must $RM $TESTDIR/tar.$$ $TESTDIR/noxattr.tar $TESTDIR/xattr.tar
+
+
+log_assert "Basic applications work with xattrs: cpio cp find mv pax tar"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_012_pos.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_012_pos.ksh
new file mode 100755 (executable)
index 0000000..477e155
--- /dev/null
@@ -0,0 +1,103 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# xattr file sizes count towards normal disk usage
+#
+# STRATEGY:
+#      1. Create a file, and check pool and filesystem usage
+#       2. Create a 200mb xattr in that file
+#      3. Check pool and filesystem usage, to ensure it reflects the size
+#         of the xattr
+#
+
+function cleanup {
+       log_must $RM $TESTDIR/myfile.$$
+}
+
+function get_pool_size {
+       poolname=$1
+       psize=$($ZPOOL list -H -o allocated $poolname)
+       if [[ $psize == *[mM] ]]
+       then
+               returnvalue=$($ECHO $psize | $SED -e 's/m//g' -e 's/M//g')
+               returnvalue=$((returnvalue * 1024))
+       else
+               returnvalue=$($ECHO $psize | $SED -e 's/k//g' -e 's/K//g')
+       fi
+       echo $returnvalue
+}
+
+log_assert "xattr file sizes count towards normal disk usage"
+log_onexit cleanup
+
+log_must $TOUCH $TESTDIR/myfile.$$
+
+POOL_SIZE=0
+NEW_POOL_SIZE=0
+
+if is_global_zone
+then
+       # get pool and filesystem sizes. Since we're starting with an empty
+       # pool, the usage should be small - a few k.
+       POOL_SIZE=$(get_pool_size $TESTPOOL)
+fi
+
+FS_SIZE=$($ZFS get -p -H -o value used $TESTPOOL/$TESTFS)
+
+log_must $RUNAT $TESTDIR/myfile.$$ $MKFILE 200m xattr
+
+#Make sure the newly created file is counted into zpool usage
+log_must $SYNC
+
+# now check to see if our pool disk usage has increased
+if is_global_zone
+then
+       NEW_POOL_SIZE=$(get_pool_size $TESTPOOL)
+       (($NEW_POOL_SIZE <= $POOL_SIZE)) && \
+           log_fail "The new pool size $NEW_POOL_SIZE was less \
+            than or equal to the old pool size $POOL_SIZE."
+
+fi
+
+# also make sure our filesystem usage has increased
+NEW_FS_SIZE=$($ZFS get -p -H -o value used $TESTPOOL/$TESTFS)
+(($NEW_FS_SIZE <= $FS_SIZE)) && \
+    log_fail "The new filesystem size $NEW_FS_SIZE was less \
+    than or equal to the old filesystem size $FS_SIZE."
+
+log_pass "xattr file sizes count towards normal disk usage"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_013_pos.ksh b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_013_pos.ksh
new file mode 100755 (executable)
index 0000000..4e9e12e
--- /dev/null
@@ -0,0 +1,88 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/xattr/xattr_common.kshlib
+
+#
+# DESCRIPTION:
+# The noxattr mount option functions as expected
+#
+# STRATEGY:
+#      1. Create a file on a filesystem and add an xattr to it
+#      2. Unmount the filesystem, and mount it -o noxattr
+#      3. Verify that the xattr cannot be read and new files
+#         cannot have xattrs set on them.
+#      4. Unmount and mount the filesystem normally
+#      5. Verify that xattrs can be set and accessed again
+#
+
+function cleanup {
+
+       log_must $RM $TESTDIR/myfile.$$
+}
+
+
+log_assert "The noxattr mount option functions as expected"
+log_onexit cleanup
+
+$ZFS set 2>&1 | $GREP xattr > /dev/null
+if [ $? -ne 0 ]
+then
+       log_unsupported "noxattr mount option not supported on this release."
+fi
+
+log_must $TOUCH $TESTDIR/myfile.$$
+create_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+log_must $UMOUNT $TESTDIR
+log_must $ZFS mount -o noxattr $TESTPOOL/$TESTFS
+
+# check that we can't perform xattr operations
+log_mustnot eval "$RUNAT $TESTDIR/myfile.$$ $CAT passwd > /dev/null 2>&1"
+log_mustnot eval "$RUNAT $TESTDIR/myfile.$$ $RM passwd > /dev/null 2>&1"
+log_mustnot eval "$RUNAT $TESTDIR/myfile.$$ $CP /etc/passwd . > /dev/null 2>&1"
+
+log_must $TOUCH $TESTDIR/new.$$
+log_mustnot eval "$RUNAT $TESTDIR/new.$$ $CP /etc/passwd . > /dev/null 2>&1"
+log_mustnot eval "$RUNAT $TESTDIR/new.$$ $RM passwd > /dev/null 2>&1"
+
+# now mount the filesystem again as normal
+log_must $UMOUNT $TESTDIR
+log_must $ZFS mount $TESTPOOL/$TESTFS
+
+# we should still have an xattr on the first file
+verify_xattr $TESTDIR/myfile.$$ passwd /etc/passwd
+
+# there should be no xattr on the file we created while the fs was mounted
+# -o noxattr
+log_mustnot eval "$RUNAT $TESTDIR/new.$$ $CAT passwd > /dev/null 2>&1"
+create_xattr $TESTDIR/new.$$ passwd /etc/passwd
+
+log_pass "The noxattr mount option functions as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/xattr/xattr_common.kshlib b/zfs/tests/zfs-tests/tests/functional/xattr/xattr_common.kshlib
new file mode 100644 (file)
index 0000000..d6509a5
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+# a function that takes a file, then creates and verifies
+# an xattr on that file. The xattr_contents is the file
+# that should appear in the xattr namespace.
+function create_xattr { # filename xattr_name xattr_contents
+       typeset FILE=$1
+       typeset XATTR_NAME=$2
+       typeset XATTR_CONTENTS=$3
+
+       # read any empty xattr on that file
+       log_must $RUNAT $FILE $LS
+       # create the xattr
+       log_must $RUNAT $FILE $CP $XATTR_CONTENTS $XATTR_NAME
+
+       verify_xattr $FILE $XATTR_NAME $XATTR_CONTENTS
+}
+
+# a function that compares the a single xattr between two files
+# and checks to see if their contents are identical
+function compare_xattrs { # filename1 filename2 xattr_name
+       typeset FILE1=$1
+       typeset FILE2=$2
+       typeset XATTR_NAME=$3
+
+       $RUNAT $FILE1 $CAT $XATTR_NAME > /tmp/file1.$$
+       $RUNAT $FILE2 $CAT $XATTR_NAME > /tmp/file2.$$
+
+       log_must $DIFF /tmp/file1.$$ /tmp/file2.$$
+       log_must $RM /tmp/file1.$$ /tmp/file2.$$
+}
+
+function verify_xattr { # filename xattr_name xattr_contents
+       typeset FILE=$1
+       typeset XATTR_NAME=$2
+       typeset XATTR_CONTENTS=$3
+
+       # read the xattr, writing it to a temp file
+       log_must eval "$RUNAT $FILE $CAT $XATTR_NAME > /tmp/$XATTR_NAME.$$ 2>&1"
+       log_must $DIFF $XATTR_CONTENTS /tmp/$XATTR_NAME.$$
+       $RM /tmp/$XATTR_NAME.$$
+}
+
+function delete_xattr { # filename xattr_name
+        typeset FILE=$1
+        typeset XATTR_NAME=$2
+
+        # delete the xattr
+        log_must $RUNAT $FILE $RM $XATTR_NAME
+        log_mustnot eval "$RUNAT $FILE $LS $XATTR_NAME > /dev/null 2>&1"
+}
+
+# not sure about this : really this should be testing write/append
+function verify_write_xattr { # filename xattr_name
+        typeset FILE=$1
+        typeset XATTR_NAME=$2
+
+        log_must eval "$RUNAT $FILE $DD if=/etc/passwd of=$XATTR_NAME"
+        log_must eval "$RUNAT $FILE $CAT $XATTR_NAME > /tmp/$XATTR_NAME.$$ 2>&1"
+        log_must $DD if=/etc/passwd of=/tmp/passwd_dd.$$
+        log_must $DIFF /tmp/passwd_dd.$$ /tmp/$XATTR_NAME.$$
+        log_must $RM /tmp/passwd_dd.$$ /tmp/$XATTR_NAME.$$
+}
+
+# this function is to create the expected output
+function create_expected_output  { # expected_output_file  contents_of_the_output
+   typeset FILE=$1
+   shift
+   if [[ -f $FILE ]]; then
+      log_must $RM $FILE
+   fi
+
+   for line in $@
+   do
+      log_must eval "$ECHO $line >> $FILE"
+   done
+ }
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/Makefile.am b/zfs/tests/zfs-tests/tests/functional/zvol/Makefile.am
new file mode 100644 (file)
index 0000000..8aba099
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/zvol
+dist_pkgdata_SCRIPTS = \
+       zvol.cfg \
+       zvol_common.shlib
+
+SUBDIRS = \
+       zvol_ENOSPC \
+       zvol_cli \
+       zvol_misc \
+       zvol_swap
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol.cfg b/zfs/tests/zfs-tests/tests/functional/zvol/zvol.cfg
new file mode 100644 (file)
index 0000000..71f3d03
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# 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) 2013 by Delphix. All rights reserved.
+#
+
+export DISK=${DISKS%% *}
+
+export TESTVOL=testvol
+export TESTFILE=testfile
+export TESTSNAP=testsnap
+export VOLSIZE=1g
+export DATA=0
+export ENOSPC=28
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/Makefile.am b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/Makefile.am
new file mode 100644 (file)
index 0000000..7007c8c
--- /dev/null
@@ -0,0 +1,6 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/zvol/zvol_ENOSPC
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       zvol_ENOSPC.cfg \
+       zvol_ENOSPC_001_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/cleanup.ksh
new file mode 100755 (executable)
index 0000000..3242298
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+verify_runnable "global"
+
+ismounted $TESTDIR $NEWFS_DEFAULT_FS
+(( $? == 0 )) && log_must $UMOUNT -f $TESTDIR
+
+[[ -e $TESTDIR ]] && $RM -rf $TESTDIR
+
+default_zvol_cleanup
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/setup.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/setup.ksh
new file mode 100755 (executable)
index 0000000..e5feb6b
--- /dev/null
@@ -0,0 +1,51 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_ENOSPC/zvol_ENOSPC.cfg
+
+verify_runnable "global"
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+       delete_partitions
+fi
+
+default_zvol_setup $DISK $VOLSIZE
+
+$ECHO "y" | $NEWFS -v ${ZVOL_RDEVDIR}/$TESTPOOL/$TESTVOL >/dev/null 2>&1
+(( $? != 0 )) && log_fail "Unable to newfs(1M) $TESTPOOL/$TESTVOL"
+
+log_must $MKDIR $TESTDIR
+log_must $MOUNT ${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL $TESTDIR
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/zvol_ENOSPC.cfg b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/zvol_ENOSPC.cfg
new file mode 100644 (file)
index 0000000..8284ffb
--- /dev/null
@@ -0,0 +1,49 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+#export SIZE="1gb"
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+export DISKSARRAY=$DISKS
+
+
+if is_linux; then
+       set_slice_prefix
+       set_device_dir
+#      export SLICE=1
+else
+       DEV_DSKDIR="/dev"
+       export SLICE_PREFIX="s"
+#      export SLICE=0
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/zvol_ENOSPC_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/zvol_ENOSPC_001_pos.ksh
new file mode 100755 (executable)
index 0000000..418ba72
--- /dev/null
@@ -0,0 +1,80 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol.cfg
+
+#
+# DESCRIPTION:
+# A zvol volume will return ENOSPC when the underlying pool runs out of
+# space.
+#
+# STRATEGY:
+# 1. Create a pool
+# 2. Create a zvol volume
+# 3. Create a ufs file system ontop of the zvol
+# 4. Mount the ufs file system
+# 5. Fill volume until ENOSPC is returned
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       $RM -rf $TESTDIR/*
+}
+
+log_assert "A zvol volume will return ENOSPC when the underlying pool " \
+    "runs out of space."
+
+log_onexit cleanup
+
+typeset -i fn=0
+typeset -i retval=0
+
+BLOCKSZ=$(( 1024 * 1024 ))
+NUM_WRITES=40
+
+while (( 1 )); do
+        $FILE_WRITE -o create -f $TESTDIR/testfile$$.$fn \
+            -b $BLOCKSZ -c $NUM_WRITES
+        retval=$?
+        if (( $retval != 0 )); then
+                break
+        fi
+
+        (( fn = fn + 1 ))
+done
+
+(( $retval != $ENOSPC )) &&
+    log_fail "ENOSPC was not returned, $retval was received instead"
+
+log_pass "ENOSPC was returned as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/Makefile.am b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/Makefile.am
new file mode 100644 (file)
index 0000000..c4b8038
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/zvol/zvol_cli
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       zvol_cli.cfg \
+       zvol_cli_001_pos.ksh \
+       zvol_cli_002_pos.ksh \
+       zvol_cli_003_neg.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79836c2
--- /dev/null
@@ -0,0 +1,39 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+verify_runnable "global"
+
+default_zvol_cleanup
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/setup.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/setup.ksh
new file mode 100755 (executable)
index 0000000..c24933d
--- /dev/null
@@ -0,0 +1,45 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_cli/zvol_cli.cfg
+
+verify_runnable "global"
+
+DISK=${DISKS%% *}
+if is_mpath_device $DISK; then
+       delete_partitions
+fi
+
+default_zvol_setup $DISK $VOLSIZE
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli.cfg b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli.cfg
new file mode 100644 (file)
index 0000000..ebfbe5c
--- /dev/null
@@ -0,0 +1,46 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+verify_runnable "global"
+
+export DISK_ARRAY_NUM=$($ECHO ${DISKS} | $NAWK '{print NF}')
+export DISKSARRAY=$DISKS
+
+
+if is_linux; then
+       set_slice_prefix
+       set_device_dir
+else
+       DEV_DSKDIR="/dev"
+       export SLICE_PREFIX="s"
+fi
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_001_pos.ksh
new file mode 100755 (executable)
index 0000000..4a4c6fb
--- /dev/null
@@ -0,0 +1,63 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Executing well-formed 'zfs list' commands should return success
+#
+# STRATEGY:
+# 1. Create an array of valid options.
+# 2. Execute each element in the array.
+# 3. Verify success is returned.
+#
+
+verify_runnable "global"
+
+TESTVOL='testvol'
+
+set -A args  "list" "list -r" \
+    "list $TESTPOOL/$TESTVOL" "list -r $TESTPOOL/$TESTVOL"  \
+    "list -H $TESTPOOL/$TESTVOL" "list -Hr $TESTPOOL/$TESTVOL"  \
+    "list -rH $TESTPOOL/$TESTVOL" "list -o name $TESTPOOL/$TESTVOL" \
+    "list -r -o name $TESTPOOL/$TESTVOL" "list -H -o name $TESTPOOL/$TESTVOL" \
+    "list -rH -o name $TESTPOOL/$TESTVOL"
+
+log_assert "Executing well-formed 'zfs list' commands should return success"
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_must eval "$ZFS ${args[i]} > /dev/null"
+       ((i = i + 1))
+done
+
+log_pass "Executing zfs list on volume works as expected"
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_002_pos.ksh
new file mode 100755 (executable)
index 0000000..65315ed
--- /dev/null
@@ -0,0 +1,62 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Creating a volume with a 50 letter name should work.
+#
+# STRATEGY:
+# 1. Using a very long name, create a zvol
+# 2. Verify volume exists
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       datasetexists $TESTPOOL/$LONGVOLNAME && \
+               $ZFS destroy $TESTPOOL/$LONGVOLNAME
+}
+
+log_onexit cleanup
+
+log_assert "Creating a volume a 50 letter name should work."
+
+LONGVOLNAME="volumename50charslong_0123456789012345678901234567"
+
+log_must $ZFS create -V $VOLSIZE $TESTPOOL/$LONGVOLNAME
+
+datasetexists $TESTPOOL/$LONGVOLNAME || \
+       log_fail "Couldn't find long volume name"
+
+log_pass "Created a 50-letter zvol volume name"
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_cli/zvol_cli_003_neg.ksh
new file mode 100755 (executable)
index 0000000..f092e48
--- /dev/null
@@ -0,0 +1,59 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Try each ZFS volume sub-command without parameters to make sure
+# it returns an error.
+#
+# STRATEGY:
+# 1. Create an array of parameters
+# 2. For each parameter in the array, execute the sub-command
+# 3. Verify an error is returned.
+#
+
+verify_runnable "global"
+
+set -A args "" "create -V" "create -V $TESTPOOL" \
+       "create -V $TESTPOOL/$TESTVOL@" "create -V blah" "destroy"
+
+log_assert "Try each ZFS volume sub-command without parameters to make sure" \
+    " it returns an error."
+
+typeset -i i=0
+while (( $i < ${#args[*]} )); do
+       log_mustnot $ZFS ${args[i]}
+       (( i = i + 1 ))
+done
+
+log_pass "Badly formed ZFS volume sub-commands fail as expected."
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_common.shlib b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_common.shlib
new file mode 100644 (file)
index 0000000..3014979
--- /dev/null
@@ -0,0 +1,144 @@
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol.cfg
+
+#
+# Create a simple zvol volume
+#
+# Where disk_device: is the name of the disk to be used
+#       volume_size: is the size of the volume, e.g. 2G
+#
+function default_zvol_setup # disk_device volume_size
+{
+        typeset disk=$1
+        typeset size=$2
+       typeset savedumpdev
+       typeset -i output
+
+        create_pool $TESTPOOL "$disk"
+
+        log_must $ZFS create -V $size $TESTPOOL/$TESTVOL
+       block_device_wait
+
+       set_dumpsize $TESTPOOL/$TESTVOL
+}
+
+#
+# Destroy the default zvol which was setup using
+# default_zvol_setup().
+#
+function default_zvol_cleanup
+{
+        if datasetexists $TESTPOOL/$TESTVOL ; then
+               log_must $ZFS destroy $TESTPOOL/$TESTVOL
+       fi
+
+        destroy_pool $TESTPOOL
+}
+
+function get_dumpdevice
+{
+       typeset ret=$($DUMPADM | $GREP "Dump device:" | $AWK '{print $3}')
+       echo $ret
+}
+
+function set_dumpsize
+{
+       typeset volume=$1
+
+       if [[ -z $volume ]] ; then
+               log_note "No volume specified."
+               return 1
+       fi
+
+       log_must $ZFS set volsize=64m $volume
+
+       if ! is_linux; then
+               output=$($DUMPADM -d ${ZVOL_DEVDIR}/$volume 2>&1 | \
+                               $TAIL -1 | $AWK '{print $3}')
+
+               if [[ -n $output ]]; then
+                       (( output = output / 1024 / 1024 ))
+                       (( output = output + output / 5 ))
+                       log_must $ZFS set volsize=${output}m $volume
+               fi
+       fi
+
+       return 0
+}
+
+function safe_dumpadm
+{
+       typeset device=$1
+
+       if [[ -z $device || $device == "none" ]] ; then
+               log_note "No dump device volume specified."
+               return 1
+       fi
+       if [[ $device == "${ZVOL_DEVDIR}/"* ]] ; then
+               typeset volume=${device#${ZVOL_DEVDIR}/}
+               set_dumpsize $volume
+               log_must $DUMPADM -d $device
+       else
+               log_must $SWAPADD
+               if ! is_swap_inuse $device ; then
+                       log_must $SWAP -a $device
+               fi
+               log_must $DUMPADM -d swap
+       fi
+}
+
+function is_zvol_dumpified
+{
+       typeset volume=$1
+
+       if [[ -z $volume ]] ; then
+               log_note "No volume specified."
+               return 1
+       fi
+
+       $ZDB -dddd $volume 2 | $GREP "dumpsize" > /dev/null 2>&1
+       return $?
+}
+
+function is_swap_inuse
+{
+       typeset device=$1
+
+       if [[ -z $device ]] ; then
+               log_note "No device specified."
+               return 1
+       fi
+
+       $SWAP -l | $GREP -w $device > /dev/null 2>&1
+       return $?
+}
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/Makefile.am b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/Makefile.am
new file mode 100644 (file)
index 0000000..b52088c
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/zvol/zvol_misc
+dist_pkgdata_SCRIPTS = \
+       cleanup.ksh \
+       setup.ksh \
+       zvol_misc_001_neg.ksh \
+       zvol_misc_002_pos.ksh \
+       zvol_misc_003_neg.ksh \
+       zvol_misc_004_pos.ksh \
+       zvol_misc_005_neg.ksh \
+       zvol_misc_006_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/cleanup.ksh
new file mode 100755 (executable)
index 0000000..79836c2
--- /dev/null
@@ -0,0 +1,39 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+verify_runnable "global"
+
+default_zvol_cleanup
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/setup.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/setup.ksh
new file mode 100755 (executable)
index 0000000..0fb3f1b
--- /dev/null
@@ -0,0 +1,43 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+verify_runnable "global"
+
+if ! $(is_physical_device $DISKS) ; then
+       log_unsupported "This directory cannot be run on raw files."
+fi
+
+default_zvol_setup $DISK $VOLSIZE
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_001_neg.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_001_neg.ksh
new file mode 100755 (executable)
index 0000000..9c47451
--- /dev/null
@@ -0,0 +1,64 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+#
+# DESCRIPTION:
+#      Verify that using a zvol as a dump device works.
+#
+# STRATEGY:
+# 1. Create a ZFS volume
+# 2. Use dumpadm add the volume as dump device
+# 3. Verify the return code as expected.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dumpdev=$(get_dumpdevice)
+
+       if [[ $dumpdev != $savedumpdev ]] ; then
+               safe_dumpadm $savedumpdev
+       fi
+}
+
+log_assert "Verify that a ZFS volume can act as dump device."
+log_onexit cleanup
+
+voldev=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+savedumpdev=$(get_dumpdevice)
+
+safe_dumpadm $voldev
+
+log_pass "Verify that a ZFS volume can act as dump device."
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_002_pos.ksh
new file mode 100755 (executable)
index 0000000..3a5aa9f
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# Verify that ZFS volume snapshot could be fscked
+#
+# STRATEGY:
+# 1. Create a ZFS volume
+# 2. Copy some files and create snapshot
+# 3. Verify fsck on the snapshot is OK
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       snapexists $TESTPOOL/$TESTVOL@snap && \
+               $ZFS destroy $TESTPOOL/$TESTVOL@snap
+
+       ismounted $TESTDIR ufs
+       (( $? == 0 )) && log_must $UMOUNT $TESTDIR
+
+       [[ -e $TESTDIR ]] && $RM -rf $TESTDIR
+}
+
+log_assert "Verify that ZFS volume snapshot could be fscked"
+log_onexit cleanup
+
+TESTVOL='testvol'
+BLOCKSZ=$(( 1024 * 1024 ))
+NUM_WRITES=40
+
+$ECHO "y" | $NEWFS -v ${ZVOL_RDEVDIR}/$TESTPOOL/$TESTVOL >/dev/null 2>&1
+(( $? != 0 )) && log_fail "Unable to newfs(1M) $TESTPOOL/$TESTVOL"
+
+log_must $MKDIR $TESTDIR
+log_must $MOUNT ${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL $TESTDIR
+
+typeset -i fn=0
+typeset -i retval=0
+
+while (( 1 )); do
+        $FILE_WRITE -o create -f $TESTDIR/testfile$$.$fn \
+            -b $BLOCKSZ -c $NUM_WRITES
+        retval=$?
+        if (( $retval != 0 )); then
+                break
+        fi
+
+        (( fn = fn + 1 ))
+done
+
+log_must $LOCKFS -f $TESTDIR
+log_must $ZFS snapshot $TESTPOOL/$TESTVOL@snap
+
+$FSCK -n ${ZVOL_RDEVDIR}/$TESTPOOL/$TESTVOL@snap >/dev/null 2>&1
+retval=$?
+(( $retval == 39 )) || log_fail "$FSCK exited with wrong value $retval "
+
+log_pass "Verify that ZFS volume snapshot could be fscked"
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_003_neg.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_003_neg.ksh
new file mode 100755 (executable)
index 0000000..04b3014
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+#
+# DESCRIPTION:
+#      Verify creating a storage pool or running newfs on a zvol used as a
+#      dump device is denied.
+#
+# STRATEGY:
+# 1. Create a ZFS volume
+# 2. Use dumpadm to set the volume as dump device
+# 3. Verify creating a pool & running newfs on the zvol returns an error.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dumpdev=$(get_dumpdevice)
+       if [[ $dumpdev != $savedumpdev ]] ; then
+               safe_dumpadm $savedumpdev
+       fi
+
+       if poolexists $TESTPOOL1 ; then
+               destroy_pool $TESTPOOL1
+       fi
+}
+
+log_assert "Verify zpool creation and newfs on dump zvol is denied."
+log_onexit cleanup
+
+voldev=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+savedumpdev=$(get_dumpdevice)
+
+safe_dumpadm $voldev
+
+$ECHO "y" | $NEWFS -v $voldev > /dev/null 2>&1
+if (( $? == 0 )) ; then
+       log_fail "newfs on dump zvol succeeded unexpectedly"
+fi
+
+log_mustnot $ZPOOL create $TESTPOOL1 $voldev
+
+log_pass "Verify zpool creation and newfs on dump zvol is denied."
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_004_pos.ksh
new file mode 100755 (executable)
index 0000000..176379e
--- /dev/null
@@ -0,0 +1,109 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+#
+# DESCRIPTION:
+# Verify the ability to take snapshots of zvols used as dump or swap.
+#
+# STRATEGY:
+# 1. Create a ZFS volume
+# 2. Set the volume as dump or swap
+# 3. Verify creating a snapshot of the zvol succeeds.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dumpdev=$(get_dumpdevice)
+       if [[ $dumpdev != $savedumpdev ]] ; then
+               safe_dumpadm $savedumpdev
+       fi
+
+       $SWAP -l | $GREP -w $voldev > /dev/null 2>&1
+        if (( $? == 0 ));  then
+               log_must $SWAP -d $voldev
+       fi
+
+       typeset snap
+       for snap in snap0 snap1 ; do
+               if datasetexists $TESTPOOL/$TESTVOL@$snap ; then
+                       log_must $ZFS destroy $TESTPOOL/$TESTVOL@$snap
+               fi
+       done
+}
+
+function verify_snapshot
+{
+       typeset volume=$1
+
+       log_must $ZFS snapshot $volume@snap0
+       log_must $ZFS snapshot $volume@snap1
+       log_must datasetexists $volume@snap0 $volume@snap1
+
+       log_must $ZFS destroy $volume@snap1
+       log_must $ZFS snapshot $volume@snap1
+
+       log_mustnot $ZFS rollback -r $volume@snap0
+       log_must datasetexists $volume@snap0
+
+       log_must $ZFS destroy -r $volume@snap0
+}
+
+log_assert "Verify the ability to take snapshots of zvols used as dump or swap."
+log_onexit cleanup
+
+voldev=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+savedumpdev=$(get_dumpdevice)
+
+# create snapshot over dump zvol
+safe_dumpadm $voldev
+log_must is_zvol_dumpified $TESTPOOL/$TESTVOL
+
+verify_snapshot $TESTPOOL/$TESTVOL
+
+safe_dumpadm $savedumpdev
+log_mustnot is_zvol_dumpified $TESTPOOL/$TESTVOL
+
+# create snapshot over swap zvol
+
+log_must $SWAP -a $voldev
+log_mustnot is_zvol_dumpified $TESTPOOL/$TESTVOL
+
+verify_snapshot $TESTPOOL/$TESTVOL
+
+log_must $SWAP -d $voldev
+log_mustnot is_zvol_dumpified $TESTPOOL/$TESTVOL
+
+log_pass "Creating snapshots from dump/swap zvols succeeds."
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_005_neg.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_005_neg.ksh
new file mode 100755 (executable)
index 0000000..f2cec94
--- /dev/null
@@ -0,0 +1,75 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+#
+# DESCRIPTION:
+#      Verify a device cannot be dump and swap at the same time.
+#
+# STRATEGY:
+# 1. Create a ZFS volume
+# 2. Set it as swap device.
+# 3. Verify dumpadm with this zvol will fail.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       $SWAP -l | $GREP $voldev > /dev/null 2>&1
+       if (( $? == 0 )) ; then
+               log_must $SWAP -d $voldev
+       fi
+
+       typeset dumpdev=$(get_dumpdevice)
+       if [[ $dumpdev != $savedumpdev ]] ; then
+               safe_dumpadm $savedumpdev
+       fi
+}
+
+log_assert "Verify a device cannot be dump and swap at the same time."
+log_onexit cleanup
+
+voldev=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+savedumpdev=$(get_dumpdevice)
+
+# If device in swap list, it cannot be dump device
+log_must $SWAP -a $voldev
+log_mustnot $DUMPADM -d $voldev
+log_must $SWAP -d $voldev
+
+# If device has dedicated as dump device, it cannot add into swap list
+safe_dumpadm $voldev
+log_mustnot $SWAP -a $voldev
+
+log_pass "A device cannot be dump and swap at the same time."
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_misc/zvol_misc_006_pos.ksh
new file mode 100755 (executable)
index 0000000..3b8737f
--- /dev/null
@@ -0,0 +1,72 @@
+#!/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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+#
+# DESCRIPTION:
+# ZFS volume as dump device, it should always have 128k volblocksize
+#
+# STRATEGY:
+# 1. Create a ZFS volume
+# 2. Use dumpadm set the volume as dump device
+# 3. Verify the volume's volblocksize=128k
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset dumpdev=$(get_dumpdevice)
+       if [[ $dumpdev != $savedumpdev ]] ; then
+               safe_dumpadm $savedumpdev
+       fi
+}
+
+log_assert "zfs volume as dumpdevice should have 128k volblocksize"
+log_onexit cleanup
+
+voldev=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+savedumpdev=$(get_dumpdevice)
+
+typeset oblksize=$($ZFS get -H -o value volblocksize $TESTPOOL/$TESTVOL)
+log_note "original $TESTPOOL/$TESTVOL volblocksize=$oblksize"
+
+safe_dumpadm $voldev
+
+typeset blksize=$($ZFS get -H -o value volblocksize $TESTPOOL/$TESTVOL)
+
+if [[ $blksize != "128K" ]]; then
+       log_fail "ZFS volume $TESTPOOL/$TESTVOL volblocksize=$blksize"
+fi
+
+log_pass "zfs volume as dumpdevice should have 128k volblocksize"
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/Makefile.am b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/Makefile.am
new file mode 100644 (file)
index 0000000..7d68d0c
--- /dev/null
@@ -0,0 +1,11 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/zvol/zvol_swap
+dist_pkgdata_SCRIPTS = \
+       zvol_swap.cfg \
+       cleanup.ksh \
+       setup.ksh \
+       zvol_swap_001_pos.ksh \
+       zvol_swap_002_pos.ksh \
+       zvol_swap_003_pos.ksh \
+       zvol_swap_004_pos.ksh \
+       zvol_swap_005_pos.ksh \
+       zvol_swap_006_pos.ksh
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/cleanup.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/cleanup.ksh
new file mode 100755 (executable)
index 0000000..610bc85
--- /dev/null
@@ -0,0 +1,53 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_swap/zvol_swap.cfg
+
+verify_runnable "global"
+
+log_must $SWAPADD
+for swapdev in $SAVESWAPDEVS
+do
+       if ! is_swap_inuse $swapdev ; then
+               log_must $SWAP -a $swapdev >/dev/null 2>&1
+       fi
+done
+
+voldev=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+if is_swap_inuse $voldev ; then
+       log_must $SWAP -d $voldev
+fi
+
+default_zvol_cleanup
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/setup.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/setup.ksh
new file mode 100755 (executable)
index 0000000..9886bbe
--- /dev/null
@@ -0,0 +1,49 @@
+#!/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) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_swap/zvol_swap.cfg
+
+verify_runnable "global"
+
+for i in $SAVESWAPDEVS ; do
+       log_note "Executing: swap -d $i"
+       $SWAP -d $i >/dev/null 2>&1
+       if [[ $? != 0 ]]; then
+               log_untested "Unable to delete swap device $i because of" \
+                               "insufficient RAM"
+       fi
+done
+
+default_zvol_setup $DISK $VOLSIZE
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap.cfg b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap.cfg
new file mode 100644 (file)
index 0000000..abc31a9
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+. $STF_SUITE/tests/functional/zvol/zvol.cfg
+
+#
+# Remember swap devices
+#
+SAVESWAPDEVS=$($SWAP -l | $NAWK '(NR != 1) {print $1}')
+
+export BLOCKSZ=$(( 1024 * 1024 ))
+export NUM_WRITES=40
+export SAVESWAPDEVS
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_001_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_001_pos.ksh
new file mode 100755 (executable)
index 0000000..68d8ebb
--- /dev/null
@@ -0,0 +1,78 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_swap/zvol_swap.cfg
+
+#
+# DESCRIPTION:
+# Verify that a zvol can be used as a swap device
+#
+# STRATEGY:
+# 1. Create a pool
+# 2. Create a zvol volume
+# 3. Use zvol as swap space
+# 4. Create a file under /tmp
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       $RM -rf /tmp/$TESTFILE
+
+       if is_swap_inuse $voldev ; then
+               log_must $SWAP -d $voldev
+       fi
+}
+
+log_assert "Verify that a zvol can be used as a swap device"
+
+log_onexit cleanup
+
+voldev=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+log_note "Add zvol volume as swap space"
+log_must $SWAP -a $voldev
+
+log_note "Create a file under /tmp"
+log_must $FILE_WRITE -o create -f /tmp/$TESTFILE \
+    -b $BLOCKSZ -c $NUM_WRITES -d $DATA
+
+[[ ! -f /tmp/$TESTFILE ]] &&
+    log_fail "Unable to create file under /tmp"
+
+filesize=`$LS -l /tmp/$TESTFILE | $AWK '{print $5}'`
+tf_size=$(( BLOCKSZ * NUM_WRITES ))
+(( $tf_size != $filesize )) &&
+    log_fail "testfile is ($filesize bytes), expected ($tf_size bytes)"
+
+log_pass "Successfully added a zvol to swap area."
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_002_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_002_pos.ksh
new file mode 100755 (executable)
index 0000000..1657be1
--- /dev/null
@@ -0,0 +1,64 @@
+#!/bin/bash
+#
+# 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.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+#
+# DESCRIPTION:
+#      Add a swap zvol, and consume most (not all) of the space. This test
+#      used to fill up swap, which can hang the system.
+#
+# STRATEGY:
+#      1. Create a new zvol and add it as swap
+#      2. Fill /tmp with 80% the size of the zvol
+#      5. Remove the new zvol, and restore original swap devices
+#
+
+verify_runnable "global"
+log_assert "Using a zvol as swap space, fill /tmp to 80%."
+
+vol=$TESTPOOL/$TESTVOL
+swapdev=${ZVOL_DEVDIR}/$vol
+log_must $SWAP -a $swapdev
+
+# Get 80% of the number of 512 blocks in the zvol
+typeset -i count blks volsize=$(get_prop volsize $vol)
+((blks = (volsize / 512) * 80 / 100))
+# Use 'blks' to determine a count for dd based on a 1M block size.
+((count = blks / 2048))
+
+log_note "Fill 80% of swap"
+log_must $DD if=/dev/urandom of=/tmp/$TESTFILE bs=1048576 count=$count
+log_must $RM -f /tmp/$TESTFILE
+log_must $SWAP -d $swapdev
+
+log_pass "Using a zvol as swap space, fill /tmp to 80%."
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_003_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_003_pos.ksh
new file mode 100755 (executable)
index 0000000..0817caa
--- /dev/null
@@ -0,0 +1,96 @@
+#! /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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_swap/zvol_swap.cfg
+
+#
+# DESCRIPTION:
+# Verify that a zvol device can be used as a swap device
+# through /etc/vfstab configuration.
+#
+# STRATEGY:
+# 1. Modify /etc/vfstab to add the test zvol as swap device.
+# 2. Use /sbin/swapadd to add zvol as swap device throuth /etc/vfstab
+# 3. Create a file under /tmp and verify the file
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       [[ -f /tmp/$TESTFILE ]] && log_must $RM -f /tmp/$TESTFILE
+       [[ -f $NEW_VFSTAB_FILE ]] && log_must $RM -f $NEW_VFSTAB_FILE
+       [[ -f $PREV_VFSTAB_FILE ]] && \
+           log_must $MV $PREV_VFSTAB_FILE $VFSTAB_FILE
+       [[ -f $PREV_VFSTAB_FILE ]] && $RM -f $PREV_VFSTAB_FILE
+
+       log_must $SWAPADD $VFSTAB_FILE
+
+        if is_swap_inuse $voldev ; then
+               log_must $SWAP -d $voldev
+       fi
+
+}
+
+log_assert "Verify that a zvol device can be used as a swap device" \
+    "through /etc/vfstab configuration."
+
+log_onexit cleanup
+
+voldev=${ZVOL_DEVDIR}/$TESTPOOL/$TESTVOL
+VFSTAB_FILE=/etc/vfstab
+NEW_VFSTAB_FILE=/var/tmp/zvol_vfstab.$$
+PREV_VFSTAB_FILE=/var/tmp/zvol_vfstab.PREV.$$
+
+[[ -f $NEW_VFSTAB_FILE ]] && $CP /dev/null $NEW_VFSTAB_FILE
+
+$AWK '{if ($4 != "swap") print $1}' /etc/vfstab > $NEW_VFSTAB_FILE
+$ECHO "$voldev\t-\t-\tswap\t-\tno\t-"  >> $NEW_VFSTAB_FILE
+
+# Copy off the original vfstab, and run swapadd on the newly constructed one.
+log_must $CP $VFSTAB_FILE $PREV_VFSTAB_FILE
+log_must $CP $NEW_VFSTAB_FILE $VFSTAB_FILE
+log_must $SWAPADD $VFSTAB_FILE
+
+log_must $FILE_WRITE -o create -f /tmp/$TESTFILE \
+    -b $BLOCKSZ -c $NUM_WRITES -d $DATA
+
+[[ ! -f /tmp/$TESTFILE ]] &&
+    log_fail "Unable to create file under /tmp"
+
+filesize=`$LS -l /tmp/$TESTFILE | $AWK '{print $5}'`
+tf_size=$((BLOCKSZ * NUM_WRITES))
+(($tf_size != $filesize)) && \
+    log_fail "testfile is ($filesize bytes), expected ($tf_size bytes)"
+
+log_pass "Successfully added a zvol to swap area through /etc/vfstab."
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_004_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_004_pos.ksh
new file mode 100755 (executable)
index 0000000..5fc777a
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/bash
+#
+# 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.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+#      When a swap zvol is added it is resized to be equal to 1/4 c_max,
+#      capped between 2G and 16G.
+#
+# STRATEGY:
+#      1. Determine what 1/4 arc_c_max is.
+#      2. Create a zvols in a variety of sizes.
+#      3. Add them as swap, and verify the volsize is resized correctly.
+#
+
+verify_runnable "global"
+
+log_assert "For an added swap zvol, (2G <= volsize <= 16G)"
+
+typeset -i min max mem
+((mem = $($KSTAT -p ::arcstats:c_max | $AWK '{print $2}') / 4))
+((min = 2 * 1024 * 1024 * 1024))
+((max = 16 * 1024 * 1024 * 1024))
+
+for vbs in 512 1024 2048 4096 8192 16384 32768 65536 131072; do
+       for multiplier in 1 32 16384 131072; do
+               ((volsize = vbs * multiplier))
+               vol="$TESTPOOL/vol_$volsize"
+               swapname="${ZVOL_DEVDIR}/$vol"
+
+               # Create a sparse volume to test larger sizes
+               log_must $ZFS create -s -b $vbs -V $volsize $vol
+               log_must $SWAP -a $swapname
+
+               if ((mem <= min)); then         # volsize should be 2G
+                       new_volsize=$(get_prop volsize $vol)
+                       ((new_volsize == min)) || log_fail \
+                           "Unexpected volsize: $new_volsize"
+               elif ((mem >= max)); then       # volsize should be 16G
+                       new_volsize=$(get_prop volsize $vol)
+                       ((new_volsize == max)) || log_fail \
+                           "Unexpected volsize: $new_volsize"
+               else                            # volsize should be 'mem'
+                       new_volsize=$(get_prop volsize $vol)
+                       ((new_volsize == mem)) || log_fail \
+                           "Unexpected volsize: $new_volsize"
+               fi
+
+               log_must $SWAP -d $swapname
+               log_must $ZFS destroy $vol
+       done
+done
+
+log_pass "For an added swap zvol, (2G <= volsize <= 16G)"
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_005_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_005_pos.ksh
new file mode 100755 (executable)
index 0000000..7710b38
--- /dev/null
@@ -0,0 +1,69 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+#
+# DESCRIPTION:
+#      swaplow + swaplen must be less than or equal to the volume size.
+#
+# STRATEGY:
+#      1. Get test system page size and test volume size.
+#      2. Random get swaplow and swaplen.
+#      3. Verify swap -a should succeed when swaplow + swaplen <= volume size.
+#
+
+verify_runnable "global"
+
+assertion="Verify the sum of swaplow and swaplen is less or equal to volsize"
+log_assert $assertion
+
+typeset vol=$TESTPOOL/$TESTVOL
+typeset swapname="${ZVOL_DEVDIR}/$vol"
+typeset -i pageblocks volblocks max_swaplow
+#
+# Both swaplow and swaplen are the desired length of
+# the swap area in 512-byte blocks.
+#
+((pageblocks = $($PAGESIZE) / 512))
+((volblocks = $(get_prop volsize $vol) / 512))
+((max_swaplow = (volblocks - (pageblocks * 2))))
+
+for i in {0..10}; do
+       swaplow=$($SHUF -n 1 -i ${pageblocks}-${max_swaplow})
+       ((maxlen = max_swaplow - swaplow))
+       swaplen=$($SHUF -n 1 -i ${pageblocks}-${maxlen})
+       log_must $SWAP -a $swapname $swaplow $swaplen
+       log_must $SWAP -d $swapname $swaplow
+done
+
+log_pass $assertion
diff --git a/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_006_pos.ksh b/zfs/tests/zfs-tests/tests/functional/zvol/zvol_swap/zvol_swap_006_pos.ksh
new file mode 100755 (executable)
index 0000000..fcbbefc
--- /dev/null
@@ -0,0 +1,108 @@
+#!/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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Copyright (c) 2013 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/functional/zvol/zvol_common.shlib
+
+#
+# DESCRIPTION:
+#      A volume can be added as several segments, but overlapping segments
+#      are not allowed.
+#
+# STRATEGY:
+#      1. Figure out three groups swaplow and swaplen.
+#      2. Verify different volume segments can be added correctly.
+#      3. Verify overlapping swap volume are not allowed.
+#
+
+verify_runnable "global"
+
+function cleanup
+{
+       typeset -i i=0
+
+       while ((count > 0)); do
+               log_must $SWAP -d $swapname ${swap_opt[$i]}
+
+               ((i += 2))
+               ((count -= 1))
+       done
+}
+
+log_assert "Verify volume can be add as several segments, but overlapping " \
+       "are not allowed."
+log_onexit cleanup
+
+# swap -a won't allow the use of multiple segments of the same volume unless
+# libdiskmgmt is disabled with the environment variable below.
+typeset -x NOINUSE_CHECK=1
+
+typeset vol=$TESTPOOL/$TESTVOL
+typeset -i pageblocks volblocks
+((pageblocks = $($PAGESIZE) / 512))
+((volblocks = $(get_prop volsize $vol) / 512))
+
+log_note "Verify volume can be add as several segments."
+
+#
+#              swaplow                 swaplen
+set -A swap_opt        $((pageblocks))     \
+               $((pageblocks * ((RANDOM % 50) + 1) + (RANDOM % pageblocks) )) \
+               $((volblocks / 3))  \
+               $((pageblocks * ((RANDOM % 50) + 1) + (RANDOM % pageblocks) )) \
+               $((volblocks / 2))  \
+               $((pageblocks * ((RANDOM % 50) + 1) + (RANDOM % pageblocks) )) \
+               $(((volblocks*2) / 3))  \
+               $((pageblocks * ((RANDOM % 50) + 1) + (RANDOM % pageblocks) ))
+
+swapname=${ZVOL_DEVDIR}/$vol
+typeset -i i=0 count=0
+
+if is_swap_inuse $swapname ; then
+       log_must $SWAP -d $swapname
+fi
+
+while ((i < ${#swap_opt[@]})); do
+       log_must $SWAP -a $swapname ${swap_opt[$i]} ${swap_opt[((i+1))]}
+
+       ((i += 2))
+       ((count += 1))
+done
+
+log_note "Verify overlapping swap volume are not allowed"
+i=0
+while ((i < ${#swap_opt[@]})); do
+       log_mustnot $SWAP -a $swapname ${swap_opt[$i]}
+
+       ((i += 2))
+done
+
+log_pass "Verify volume can be added as several segments passed."
diff --git a/zfs/tests/zfs-tests/tests/perf/Makefile.am b/zfs/tests/zfs-tests/tests/perf/Makefile.am
new file mode 100644 (file)
index 0000000..a050203
--- /dev/null
@@ -0,0 +1,7 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/perf
+dist_pkgdata_SCRIPTS = perf.shlib
+
+SUBDIRS = \
+       fio \
+       regression \
+       scripts
diff --git a/zfs/tests/zfs-tests/tests/perf/fio/Makefile.am b/zfs/tests/zfs-tests/tests/perf/fio/Makefile.am
new file mode 100644 (file)
index 0000000..9604a9d
--- /dev/null
@@ -0,0 +1,8 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/perf/fio
+dist_pkgdata_SCRIPTS = \
+       mkfiles.fio \
+       random_reads.fio \
+       random_readwrite.fio \
+       random_writes.fio \
+       sequential_reads.fio \
+       sequential_writes.fio
diff --git a/zfs/tests/zfs-tests/tests/perf/fio/mkfiles.fio b/zfs/tests/zfs-tests/tests/perf/fio/mkfiles.fio
new file mode 100644 (file)
index 0000000..f876bd6
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+[global]
+filename_format=file$jobnum
+group_reporting=1
+fallocate=0
+ioengine=psync
+bs=1024k
+rw=write
+thread=1
+directory=/${TESTFS}
+numjobs=${NUMJOBS}
+filesize=${FILE_SIZE}
+buffer_compress_percentage=33
+buffer_compress_chunk=4096
+
+[job]
diff --git a/zfs/tests/zfs-tests/tests/perf/fio/random_reads.fio b/zfs/tests/zfs-tests/tests/perf/fio/random_reads.fio
new file mode 100644 (file)
index 0000000..25dd2ff
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+[global]
+filename_format=file$jobnum
+group_reporting=1
+fallocate=0
+overwrite=0
+thread=1
+rw=randread
+time_based=1
+directory=/${TESTFS}
+runtime=${RUNTIME}
+bs=${BLOCKSIZE}
+ioengine=psync
+sync=${SYNC_TYPE}
+numjobs=${NUMJOBS}
+
+[job]
diff --git a/zfs/tests/zfs-tests/tests/perf/fio/random_readwrite.fio b/zfs/tests/zfs-tests/tests/perf/fio/random_readwrite.fio
new file mode 100644 (file)
index 0000000..0b75026
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+[global]
+filename_format=file$jobnum
+nrfiles=16
+group_reporting=1
+fallocate=0
+overwrite=0
+thread=1
+rw=randrw
+rwmixread=80
+time_based=1
+directory=/${TESTFS}
+runtime=${RUNTIME}
+bssplit=4k/50:8k/30:128k/10:1m/10
+ioengine=psync
+sync=${SYNC_TYPE}
+numjobs=${NUMJOBS}
+buffer_compress_percentage=33
+buffer_compress_chunk=4096
+
+[job]
diff --git a/zfs/tests/zfs-tests/tests/perf/fio/random_writes.fio b/zfs/tests/zfs-tests/tests/perf/fio/random_writes.fio
new file mode 100644 (file)
index 0000000..b1860a7
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+[global]
+filename_format=file$jobnum
+group_reporting=1
+fallocate=0
+thread=1
+rw=randwrite
+time_based=1
+directory=/${TESTFS}
+runtime=${RUNTIME}
+bs=${BLOCKSIZE}
+ioengine=psync
+sync=${SYNC_TYPE}
+numjobs=${NUMJOBS}
+filesize=${FILESIZE}
+buffer_compress_percentage=33
+buffer_compress_chunk=4096
+
+[job]
diff --git a/zfs/tests/zfs-tests/tests/perf/fio/sequential_reads.fio b/zfs/tests/zfs-tests/tests/perf/fio/sequential_reads.fio
new file mode 100644 (file)
index 0000000..b7d9fea
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+[global]
+filename_format=file$jobnum
+group_reporting=1
+fallocate=0
+overwrite=0
+thread=1
+rw=read
+time_based=1
+directory=/${TESTFS}
+runtime=${RUNTIME}
+bs=${BLOCKSIZE}
+ioengine=psync
+sync=${SYNC_TYPE}
+numjobs=${NUMJOBS}
+
+[job]
diff --git a/zfs/tests/zfs-tests/tests/perf/fio/sequential_writes.fio b/zfs/tests/zfs-tests/tests/perf/fio/sequential_writes.fio
new file mode 100644 (file)
index 0000000..df1590c
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+[global]
+filename_format=file$jobnum
+group_reporting=1
+fallocate=0
+thread=1
+rw=write
+time_based=1
+directory=/${TESTFS}
+runtime=${RUNTIME}
+bs=${BLOCKSIZE}
+ioengine=psync
+sync=${SYNC_TYPE}
+numjobs=${NUMJOBS}
+filesize=${FILESIZE}
+buffer_compress_percentage=33
+buffer_compress_chunk=4096
+
+[job]
diff --git a/zfs/tests/zfs-tests/tests/perf/perf.shlib b/zfs/tests/zfs-tests/tests/perf/perf.shlib
new file mode 100644 (file)
index 0000000..cb2b85a
--- /dev/null
@@ -0,0 +1,308 @@
+#
+# 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) 2015 by Delphix. All rights reserved.
+# Copyright (c) 2016, Intel Corporation.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+# If neither is specified, do a nightly run.
+[[ -z $PERF_REGRESSION_WEEKLY ]] && export PERF_REGRESSION_NIGHTLY=1
+
+# Default runtime for each type of test run.
+export PERF_RUNTIME_WEEKLY=$((30 * 60))
+export PERF_RUNTIME_NIGHTLY=$((10 * 60))
+
+# Default fs creation options
+export PERF_FS_OPTS=${PERF_FS_OPTS:-'-o recsize=8k -o compress=lz4' \
+    ' -o checksum=sha256 -o redundant_metadata=most'}
+
+function get_sync_str
+{
+       typeset sync=$1
+       typeset sync_str=''
+
+       [[ $sync -eq 0 ]] && sync_str='async'
+       [[ $sync -eq 1 ]] && sync_str='sync'
+       $ECHO $sync_str
+}
+
+#
+# This function will run fio in a loop, according to the .fio file passed
+# in and a number of environment variables. The following variables can be
+# set before launching zfstest to override the defaults.
+#
+# PERF_RUNTIME: The time in seconds each fio invocation should run.
+# PERF_RUNTYPE: A human readable tag that appears in logs. The defaults are
+#    nightly and weekly.
+# PERF_NTHREADS: A list of how many threads each fio invocation will use.
+# PERF_SYNC_TYPES: Whether to use (O_SYNC) or not. 1 is sync IO, 0 is async IO.
+# PERF_IOSIZES: A list of blocksizes in which each fio invocation will do IO.
+# PERF_COLLECT_SCRIPTS: A comma delimited list of 'command args, logfile_tag'
+#    pairs that will be added to the scripts specified in each test.
+#
+function do_fio_run
+{
+       typeset script=$1
+       typeset do_recreate=$2
+       typeset clear_cache=$3
+       typeset threads sync iosize
+
+       for threads in $PERF_NTHREADS; do
+               for sync in $PERF_SYNC_TYPES; do
+                       for iosize in $PERF_IOSIZES; do
+                               log_note "Running with $threads" \
+                                   "$(get_sync_str $sync) threads, $iosize ios"
+
+                               if $do_recreate; then
+                                       recreate_perfpool
+                                       log_must $ZFS create $PERF_FS_OPTS \
+                                           $TESTFS
+                               fi
+
+                               if $clear_cache; then
+                                       # Clear the ARC
+                                       $ZPOOL export $PERFPOOL
+                                       $ZPOOL import $PERFPOOL
+                               fi
+
+                               export RUNTIME=$PERF_RUNTIME
+                               export FILESIZE=$((TOTAL_SIZE / threads))
+                               export NUMJOBS=$threads
+                               export SYNC_TYPE=$sync
+                               export BLOCKSIZE=$iosize
+                               $SYNC
+
+                               # Start the data collection
+                               do_collect_scripts $threads $sync $iosize
+
+                               # Start the load
+                               log_must $FIO $FIO_SCRIPTS/$script
+                       done
+               done
+       done
+}
+
+#
+# This function iterates through the value pairs in $PERF_COLLECT_SCRIPTS.
+# The script at index N is launched in the background, with its output
+# redirected to a logfile containing the tag specified at index N + 1.
+#
+function do_collect_scripts
+{
+       typeset threads=$1
+       typeset sync=$2
+       typeset iosize=$3
+
+       [[ -n $collect_scripts ]] || log_fail "No data collection scripts."
+       [[ -n $PERF_RUNTIME ]] || log_fail "No runtime specified."
+
+       # This will be part of the output filename.
+       typeset sync_str=$(get_sync_str $sync)
+       typeset suffix="$sync_str.$iosize-ios.$threads-threads"
+
+       # Add in user supplied scripts and logfiles, if any.
+       typeset oIFS=$IFS
+       IFS=','
+       for item in $PERF_COLLECT_SCRIPTS; do
+               collect_scripts+=($($ECHO $item | $SED 's/^ *//g'))
+       done
+       IFS=$oIFS
+
+       typeset idx=0
+       while [[ $idx -lt "${#collect_scripts[@]}" ]]; do
+               typeset logbase="$(get_perf_output_dir)/$($BASENAME \
+                   $SUDO_COMMAND)"
+               typeset outfile="$logbase.${collect_scripts[$idx + 1]}.$suffix"
+
+               $TIMEOUT $PERF_RUNTIME ${collect_scripts[$idx]} >$outfile 2>&1 &
+               ((idx += 2))
+       done
+
+       # Need to explicitly return 0 because timeout(1) will kill
+       # a child process and cause us to return non-zero.
+       return 0
+}
+
+# Find a place to deposit performance data collected while under load.
+function get_perf_output_dir
+{
+       typeset dir="$(pwd)/perf_data"
+       [[ -d $dir ]] || $MKDIR -p $dir
+
+       $ECHO $dir
+}
+
+#
+# Destroy and create the pool used for performance tests. The
+# PERFPOOL_CREATE_CMD variable allows users to test with a custom pool
+# configuration by specifying the pool creation command in their environment.
+# If PERFPOOL_CREATE_CMD is empty, a pool using all available disks is created.
+#
+function recreate_perfpool
+{
+       [[ -n $PERFPOOL ]] || log_fail "The \$PERFPOOL variable isn't set."
+
+       poolexists $PERFPOOL && destroy_pool $PERFPOOL
+
+       if [[ -n $PERFPOOL_CREATE_CMD ]]; then
+               log_must $PERFPOOL_CREATE_CMD
+       else
+               log_must eval "$ZPOOL create -f $PERFPOOL $DISKS"
+       fi
+}
+
+function get_max_arc_size
+{
+       if is_linux; then
+               typeset -l max_arc_size=`$AWK '$1 == "c_max" { print $3 }' \
+                   /proc/spl/kstat/zfs/arcstats`
+       else
+               typeset -l max_arc_size=$(dtrace -qn 'BEGIN {
+                   printf("%u\n", `arc_stats.arcstat_c_max.value.ui64);
+                   exit(0);
+               }')
+       fi
+
+       [[ $? -eq 0 ]] || log_fail "get_max_arc_size failed"
+
+       $ECHO $max_arc_size
+}
+
+# Create a file with some information about how this system is configured.
+function get_system_config
+{
+       typeset config=$PERF_DATA_DIR/$1
+
+       $ECHO "{" >>$config
+       if is_linux; then
+               $ECHO "  \"ncpus\": \"$($NPROC --all)\"," >>$config
+               $ECHO "  \"physmem\": \"$($FREE -b | \
+                   $AWK '$1 == "Mem:" { print $2 }')\"," >>$config
+               $ECHO "  \"c_max\": \"$(get_max_arc_size)\"," >>$config
+               $ECHO "  \"hostname\": \"$($UNAME -n)\"," >>$config
+               $ECHO "  \"kernel version\": \"$($UNAME -sr)\"," >>$config
+       else
+               $DTRACE -qn 'BEGIN{
+                   printf("  \"ncpus\": %d,\n", `ncpus);
+                   printf("  \"physmem\": %u,\n", `physmem * `_pagesize);
+                   printf("  \"c_max\": %u,\n", `arc_stats.arcstat_c_max.value.ui64);
+                   printf("  \"kmem_flags\": \"0x%x\",", `kmem_flags);
+                   exit(0)}' >>$config
+               $ECHO "  \"hostname\": \"$($UNAME -n)\"," >>$config
+               $ECHO "  \"kernel version\": \"$($UNAME -v)\"," >>$config
+       fi
+       if is_linux; then
+               $LSBLK -dino NAME,SIZE | $AWK 'BEGIN {
+                   printf("  \"disks\": {\n"); first = 1}
+                   {disk = $1} {size = $2;
+                   if (first != 1) {printf(",\n")} else {first = 0}
+                   printf("    \"%s\": \"%s\"", disk, size)}
+                   END {printf("\n  },\n")}' >>$config
+
+               zfs_tunables="/sys/module/zfs/parameters"
+
+               printf "  \"tunables\": {\n" >>$config
+               for tunable in \
+                   zfs_arc_max \
+                   zfs_arc_meta_limit \
+                   zfs_arc_sys_free \
+                   zfs_dirty_data_max \
+                   zfs_flags \
+                   zfs_prefetch_disable \
+                   zfs_txg_timeout \
+                   zfs_vdev_aggregation_limit \
+                   zfs_vdev_async_read_max_active \
+                   zfs_vdev_async_write_max_active \
+                   zfs_vdev_sync_read_max_active \
+                   zfs_vdev_sync_write_max_active \
+                   zio_delay_max
+               do
+                       if [ "$tunable" != "zfs_arc_max" ]
+                       then
+                               printf ",\n" >>$config
+                       fi
+                       printf  "    \"$tunable\": \"$(cat $zfs_tunables/$tunable)\"" \
+                           >>$config
+               done
+               printf "\n  }\n" >>$config
+       else
+               $IOSTAT -En | $AWK 'BEGIN {
+                   printf("  \"disks\": {\n"); first = 1}
+                   /^c/ {disk = $1}
+                   /^Size: [^0]/ {size = $2;
+                   if (first != 1) {printf(",\n")} else {first = 0}
+                   printf("    \"%s\": \"%s\"", disk, size)}
+                   END {printf("\n  },\n")}' >>$config
+
+               $SED -n 's/^set \(.*\)[ ]=[ ]\(.*\)/\1=\2/p' /etc/system | \
+                   $AWK -F= 'BEGIN {printf("  \"system\": {\n"); first = 1}
+                   {if (first != 1) {printf(",\n")} else {first = 0};
+                   printf("    \"%s\": %s", $1, $2)}
+                   END {printf("\n  }\n")}' >>$config
+       fi
+       $ECHO "}" >>$config
+}
+
+function num_jobs_by_cpu
+{
+       if is_linux; then
+               typeset ncpu=$($NPROC --all)
+       else
+               typeset ncpu=$($PSRINFO | $WC -l)
+       fi
+       typeset num_jobs=$ncpu
+
+       [[ $ncpu -gt 8 ]] && num_jobs=$($ECHO "$ncpu * 3 / 4" | $BC)
+
+       $ECHO $num_jobs
+}
+
+#
+# On illumos this looks like: ":sd3:sd4:sd1:sd2:"
+#
+function pool_to_lun_list
+{
+       typeset pool=$1
+       typeset ctd ctds devname lun
+       typeset lun_list=':'
+
+       if is_linux; then
+               ctds=$($ZPOOL list -HLv $pool | \
+                   $AWK '/sd[a-z]*|loop[0-9]*|dm-[0-9]*/ {print $1}')
+
+               for ctd in $ctds; do
+                       lun_list="$lun_list$ctd:"
+               done
+       else
+               ctds=$($ZPOOL list -v $pool |
+                   $AWK '/c[0-9]*t[0-9a-fA-F]*d[0-9]*/ {print $1}')
+
+               for ctd in $ctds; do
+               # Get the device name as it appears in /etc/path_to_inst
+               devname=$($READLINK -f /dev/dsk/${ctd}s0 | $SED -n \
+                   's/\/devices\([^:]*\):.*/\1/p')
+               # Add a string composed of the driver name and instance
+               # number to the list for comparison with dev_statname.
+               lun=$($SED 's/"//g' /etc/path_to_inst | $GREP \
+                   $devname | $AWK '{print $3$2}')
+               un_list="$lun_list$lun:"
+               done
+       fi
+       $ECHO $lun_list
+}
+
+# Create a perf_data directory to hold performance statistics and
+# configuration information.
+export PERF_DATA_DIR=$(get_perf_output_dir)
+[[ -f $PERF_DATA_DIR/config.json ]] || get_system_config config.json
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/Makefile.am b/zfs/tests/zfs-tests/tests/perf/regression/Makefile.am
new file mode 100644 (file)
index 0000000..c9032a2
--- /dev/null
@@ -0,0 +1,10 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/perf/regression
+dist_pkgdata_SCRIPTS = \
+       random_reads.ksh \
+       random_readwrite.ksh \
+       random_writes.ksh \
+       sequential_reads_cached_clone.ksh \
+       sequential_reads_cached.ksh \
+       sequential_reads.ksh \
+       sequential_writes.ksh \
+       setup.ksh
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/random_reads.ksh b/zfs/tests/zfs-tests/tests/perf/regression/random_reads.ksh
new file mode 100755 (executable)
index 0000000..0e9187f
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Trigger fio runs using the random_reads job file. The number of runs and
+# data collected is determined by the PERF_* variables. See do_fio_run for
+# details about these variables.
+#
+# The files to read from are created prior to the first fio run, and used
+# for all fio runs. The ARC is cleared with `zinject -a` prior to each run
+# so reads will go to disk.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/perf/perf.shlib
+
+function cleanup
+{
+       log_must $ZFS destroy $TESTFS
+}
+
+log_assert "Measure IO stats during random read load"
+log_onexit cleanup
+
+export TESTFS=$PERFPOOL/testfs
+recreate_perfpool
+log_must $ZFS create $PERF_FS_OPTS $TESTFS
+
+# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
+export TOTAL_SIZE=$(($(get_prop avail $TESTFS) * 3 / 2))
+
+# Variables for use by fio.
+if [[ -n $PERF_REGRESSION_WEEKLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_WEEKLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'weekly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'8 16 64'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'8k'}
+elif [[ -n $PERF_REGRESSION_NIGHTLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_NIGHTLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'nightly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'8k'}
+fi
+
+# Layout the files to be used by the read tests. Create as many files as the
+# largest number of threads. An fio run with fewer threads will use a subset
+# of the available files.
+export NUMJOBS=$(get_max $PERF_NTHREADS)
+export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
+log_must $FIO $FIO_SCRIPTS/mkfiles.fio
+
+# Set up the scripts and output files that will log performance data.
+lun_list=$(pool_to_lun_list $PERFPOOL)
+log_note "Collecting backend IO stats with lun list $lun_list"
+if is_linux; then
+        export collect_scripts=("$ZPOOL iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
+            "$VMSTAT 1" "vmstat" "$MPSTAT -P ALL 1" "mpstat" "$IOSTAT -dxyz 1"
+            "iostat")
+else
+       export collect_scripts=("$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
+           "$VMSTAT 1" "vmstat" "$MPSTAT 1" "mpstat" "$IOSTAT -xcnz 1" "iostat")
+fi
+
+log_note "Random reads with $PERF_RUNTYPE settings"
+do_fio_run random_reads.fio $FALSE $TRUE
+log_pass "Measure IO stats during random read load"
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/random_readwrite.ksh b/zfs/tests/zfs-tests/tests/perf/regression/random_readwrite.ksh
new file mode 100755 (executable)
index 0000000..c360cd5
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Trigger fio runs using the random_readwrite job file. The number of runs and
+# data collected is determined by the PERF_* variables. See do_fio_run for
+# details about these variables.
+#
+# The files to read and write from are created prior to the first fio run,
+# and used for all fio runs. The ARC is cleared with `zinject -a` prior to
+# each run so reads will go to disk.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/perf/perf.shlib
+
+function cleanup
+{
+       log_must $ZFS destroy $TESTFS
+}
+
+log_assert "Measure IO stats during random read-write load"
+log_onexit cleanup
+
+export TESTFS=$PERFPOOL/testfs
+recreate_perfpool
+log_must $ZFS create $PERF_FS_OPTS $TESTFS
+
+# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
+export TOTAL_SIZE=$(($(get_prop avail $TESTFS) * 3 / 2))
+
+# Variables for use by fio.
+if [[ -n $PERF_REGRESSION_WEEKLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_WEEKLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'weekly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'8 16 64'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'0 1'}
+       export PERF_IOSIZES=''          # bssplit used instead
+elif [[ -n $PERF_REGRESSION_NIGHTLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_NIGHTLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'nightly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=''          # bssplit used instead
+fi
+
+# Layout the files to be used by the readwrite tests. Create as many files
+# as the largest number of threads. An fio run with fewer threads will use
+# a subset of the available files.
+export NUMJOBS=$(get_max $PERF_NTHREADS)
+export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
+log_must $FIO $FIO_SCRIPTS/mkfiles.fio
+
+# Set up the scripts and output files that will log performance data.
+lun_list=$(pool_to_lun_list $PERFPOOL)
+log_note "Collecting backend IO stats with lun list $lun_list"
+if is_linux; then
+       export collect_scripts=("$ZPOOL iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
+           "$VMSTAT 1" "vmstat" "$MPSTAT -P ALL 1" "mpstat" "$IOSTAT -dxyz 1"
+           "iostat")
+else
+       export collect_scripts=("$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
+           "$VMSTAT 1" "vmstat" "$MPSTAT 1" "mpstat" "$IOSTAT -xcnz 1" "iostat")
+fi
+
+log_note "Random reads and writes with $PERF_RUNTYPE settings"
+do_fio_run random_readwrite.fio $FALSE $TRUE
+log_pass "Measure IO stats during random read and write load"
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/random_writes.ksh b/zfs/tests/zfs-tests/tests/perf/regression/random_writes.ksh
new file mode 100755 (executable)
index 0000000..3e5d0f5
--- /dev/null
@@ -0,0 +1,75 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Trigger fio runs using the random_writes job file. The number of runs and
+# data collected is determined by the PERF_* variables. See do_fio_run for
+# details about these variables.
+#
+# Prior to each fio run the dataset is recreated, and fio writes new files
+# into an otherwise empty pool.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/perf/perf.shlib
+
+function cleanup
+{
+       log_must $ZFS destroy $TESTFS
+}
+
+log_assert "Measure IO stats during random write load"
+log_onexit cleanup
+
+export TESTFS=$PERFPOOL/testfs
+recreate_perfpool
+log_must $ZFS create $PERF_FS_OPTS $TESTFS
+
+# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
+export TOTAL_SIZE=$(($(get_prop avail $TESTFS) * 3 / 2))
+
+# Variables for use by fio.
+if [[ -n $PERF_REGRESSION_WEEKLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_WEEKLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'weekly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'8 16 64'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'0 1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'8k'}
+elif [[ -n $PERF_REGRESSION_NIGHTLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_NIGHTLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'nightly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'8k'}
+fi
+
+# Set up the scripts and output files that will log performance data.
+lun_list=$(pool_to_lun_list $PERFPOOL)
+log_note "Collecting backend IO stats with lun list $lun_list"
+if is_linux; then
+       export collect_scripts=("$ZPOOL iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
+           "$VMSTAT 1" "vmstat" "$MPSTAT -P ALL 1" "mpstat" "$IOSTAT -dxyz 1"
+           "iostat")
+else
+       export collect_scripts=("$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
+           "$VMSTAT 1" "vmstat" "$MPSTAT 1" "mpstat" "$IOSTAT -xcnz 1" "iostat")
+fi
+
+log_note "Random writes with $PERF_RUNTYPE settings"
+do_fio_run random_writes.fio $TRUE $FALSE
+log_pass "Measure IO stats during random write load"
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/sequential_reads.ksh b/zfs/tests/zfs-tests/tests/perf/regression/sequential_reads.ksh
new file mode 100755 (executable)
index 0000000..75680e0
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Trigger fio runs using the sequential_reads job file. The number of runs and
+# data collected is determined by the PERF_* variables. See do_fio_run for
+# details about these variables.
+#
+# The files to read from are created prior to the first fio run, and used
+# for all fio runs. The ARC is cleared with `zinject -a` prior to each run
+# so reads will go to disk.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/perf/perf.shlib
+
+function cleanup
+{
+       log_must $ZFS destroy $TESTFS
+}
+
+log_assert "Measure IO stats during sequential read load"
+log_onexit cleanup
+
+export TESTFS=$PERFPOOL/testfs
+recreate_perfpool
+log_must $ZFS create $PERF_FS_OPTS $TESTFS
+
+# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
+export TOTAL_SIZE=$(($(get_prop avail $TESTFS) * 3 / 2))
+
+# Variables for use by fio.
+if [[ -n $PERF_REGRESSION_WEEKLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_WEEKLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'weekly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'16 64'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'64k 128k 1m'}
+elif [[ -n $PERF_REGRESSION_NIGHTLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_NIGHTLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'nightly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'128k 1m'}
+fi
+
+# Layout the files to be used by the read tests. Create as many files as the
+# largest number of threads. An fio run with fewer threads will use a subset
+# of the available files.
+export NUMJOBS=$(get_max $PERF_NTHREADS)
+export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
+log_must $FIO $FIO_SCRIPTS/mkfiles.fio
+
+# Set up the scripts and output files that will log performance data.
+lun_list=$(pool_to_lun_list $PERFPOOL)
+log_note "Collecting backend IO stats with lun list $lun_list"
+if is_linux; then
+       export collect_scripts=("$ZPOOL iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
+           "$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch" "$VMSTAT 1"
+           "vmstat" "$MPSTAT  -P ALL 1" "mpstat" "$IOSTAT -dxyz 1" "iostat")
+else
+       export collect_scripts=("$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
+           "$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch" "$VMSTAT 1"
+           "vmstat" "$MPSTAT 1" "mpstat" "$IOSTAT -xcnz 1" "iostat")
+fi
+
+log_note "Sequential reads with $PERF_RUNTYPE settings"
+do_fio_run sequential_reads.fio $FALSE $TRUE
+log_pass "Measure IO stats during sequential read load"
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/sequential_reads_cached.ksh b/zfs/tests/zfs-tests/tests/perf/regression/sequential_reads_cached.ksh
new file mode 100755 (executable)
index 0000000..54a4d4a
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Trigger fio runs using the sequential_reads job file. The number of runs and
+# data collected is determined by the PERF_* variables. See do_fio_run for
+# details about these variables.
+#
+# The files to read from are created prior to the first fio run, and used
+# for all fio runs. The ARC is not cleared to ensure that all data is cached.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/perf/perf.shlib
+
+function cleanup
+{
+       log_must $ZFS destroy $TESTFS
+}
+
+log_assert "Measure IO stats during sequential read load"
+log_onexit cleanup
+
+export TESTFS=$PERFPOOL/testfs
+recreate_perfpool
+log_must $ZFS create $PERF_FS_OPTS $TESTFS
+
+# Make sure the working set can be cached in the arc. Aim for 1/2 of arc.
+export TOTAL_SIZE=$(($(get_max_arc_size) / 2))
+
+# Variables for use by fio.
+if [[ -n $PERF_REGRESSION_WEEKLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_WEEKLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'weekly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'16 64'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'64k 128k 1m'}
+elif [[ -n $PERF_REGRESSION_NIGHTLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_NIGHTLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'nightly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'128k 1m'}
+fi
+
+# Layout the files to be used by the read tests. Create as many files as the
+# largest number of threads. An fio run with fewer threads will use a subset
+# of the available files.
+export NUMJOBS=$(get_max $PERF_NTHREADS)
+export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
+log_must $FIO $FIO_SCRIPTS/mkfiles.fio
+
+# Set up the scripts and output files that will log performance data.
+lun_list=$(pool_to_lun_list $PERFPOOL)
+log_note "Collecting backend IO stats with lun list $lun_list"
+if is_linux; then
+       export collect_scripts=("$ZPOOL iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
+           "$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch" "$VMSTAT 1"
+           "vmstat" "$MPSTAT -P ALL 1" "mpstat" "$IOSTAT -dxyz 1" "iostat")
+else
+       export collect_scripts=("$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
+           "$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch" "$VMSTAT 1"
+           "vmstat" "$MPSTAT 1" "mpstat" "$IOSTAT -xcnz 1" "iostat")
+fi
+
+log_note "Sequential cached reads with $PERF_RUNTYPE settings"
+do_fio_run sequential_reads.fio $FALSE $FALSE
+log_pass "Measure IO stats during sequential cached read load"
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/sequential_reads_cached_clone.ksh b/zfs/tests/zfs-tests/tests/perf/regression/sequential_reads_cached_clone.ksh
new file mode 100755 (executable)
index 0000000..bbc053a
--- /dev/null
@@ -0,0 +1,99 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Trigger fio runs using the sequential_reads job file. The number of runs and
+# data collected is determined by the PERF_* variables. See do_fio_run for
+# details about these variables.
+#
+# The files to read from are created prior to the first fio run, and used
+# for all fio runs. This test will exercise cached read performance from
+# a clone filesystem. The data is initially cached in the ARC and then
+# a snapshot and clone are created. All the performance runs are then
+# initiated against the clone filesystem to exercise the performance of
+# reads when the ARC has to create another buffer from a different dataset.
+# It will also exercise the need to evict the duplicate buffer once the last
+# reference on that buffer is released.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/perf/perf.shlib
+
+function cleanup
+{
+       log_must $ZFS destroy $TESTFS
+}
+
+log_assert "Measure IO stats during sequential read load"
+log_onexit cleanup
+
+export TESTFS=$PERFPOOL/testfs
+recreate_perfpool
+log_must $ZFS create $PERF_FS_OPTS $TESTFS
+
+# Make sure the working set can be cached in the arc. Aim for 1/2 of arc.
+export TOTAL_SIZE=$(($(get_max_arc_size) / 2))
+
+# Variables for use by fio.
+if [[ -n $PERF_REGRESSION_WEEKLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_WEEKLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'weekly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'16 64'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'64k 128k 1m'}
+elif [[ -n $PERF_REGRESSION_NIGHTLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_NIGHTLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'nightly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'128k 1m'}
+fi
+
+# Layout the files to be used by the read tests. Create as many files as the
+# largest number of threads. An fio run with fewer threads will use a subset
+# of the available files.
+export NUMJOBS=$(get_max $PERF_NTHREADS)
+export FILE_SIZE=$((TOTAL_SIZE / NUMJOBS))
+log_must $FIO $FIO_SCRIPTS/mkfiles.fio
+
+log_note "Creating snapshot, $TESTSNAP, of $TESTFS"
+create_snapshot $TESTFS $TESTSNAP
+log_note "Creating clone, $PERFPOOL/$TESTCLONE, from $TESTFS@$TESTSNAP"
+create_clone $TESTFS@$TESTSNAP $PERFPOOL/$TESTCLONE
+
+#
+# Reset the TESTFS to point to the clone
+#
+export TESTFS=$PERFPOOL/$TESTCLONE
+
+# Set up the scripts and output files that will log performance data.
+lun_list=$(pool_to_lun_list $PERFPOOL)
+log_note "Collecting backend IO stats with lun list $lun_list"
+if is_linux; then
+       export collect_scripts=("$ZPOOL iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
+           "$PERF_SCRIPTS/prefetch_io.sh $PERFPOOL 1" "prefetch" "$VMSTAT 1"
+           "vmstat" "$MPSTAT -P ALL 1" "mpstat" "$IOSTAT -dxyz 1" "iostat")
+else
+       export collect_scripts=("$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
+           "$PERF_SCRIPTS/prefetch_io.d $PERFPOOL 1" "prefetch" "$VMSTAT 1"
+           "vmstat" "$MPSTAT 1" "mpstat" "$IOSTAT -xcnz 1" "iostat")
+fi
+
+log_note "Sequential cached reads from $TESTFS with $PERF_RUNTYPE settings"
+do_fio_run sequential_reads.fio $FALSE $FALSE
+log_pass "Measure IO stats during sequential cached read load"
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/sequential_writes.ksh b/zfs/tests/zfs-tests/tests/perf/regression/sequential_writes.ksh
new file mode 100755 (executable)
index 0000000..7865afa
--- /dev/null
@@ -0,0 +1,75 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+#
+# Description:
+# Trigger fio runs using the sequential_writes job file. The number of runs and
+# data collected is determined by the PERF_* variables. See do_fio_run for
+# details about these variables.
+#
+# Prior to each fio run the dataset is recreated, and fio writes new files
+# into an otherwise empty pool.
+#
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/tests/perf/perf.shlib
+
+log_assert "Measure IO stats during sequential write load"
+log_onexit cleanup
+
+function cleanup
+{
+       log_must $ZFS destroy $TESTFS
+}
+
+export TESTFS=$PERFPOOL/testfs
+recreate_perfpool
+log_must $ZFS create $PERF_FS_OPTS $TESTFS
+
+# Aim to fill the pool to 50% capacity while accounting for a 3x compressratio.
+export TOTAL_SIZE=$(($(get_prop avail $TESTFS) * 3 / 2))
+
+# Variables for use by fio.
+if [[ -n $PERF_REGRESSION_WEEKLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_WEEKLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'weekly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'8 16'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'0 1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'8k 128k 1m'}
+elif [[ -n $PERF_REGRESSION_NIGHTLY ]]; then
+       export PERF_RUNTIME=${PERF_RUNTIME:-$PERF_RUNTIME_NIGHTLY}
+       export PERF_RUNTYPE=${PERF_RUNTYPE:-'nightly'}
+       export PERF_NTHREADS=${PERF_NTHREADS:-'64 128'}
+       export PERF_SYNC_TYPES=${PERF_SYNC_TYPES:-'1'}
+       export PERF_IOSIZES=${PERF_IOSIZES:-'8k 128k 1m'}
+fi
+
+# Set up the scripts and output files that will log performance data.
+lun_list=$(pool_to_lun_list $PERFPOOL)
+log_note "Collecting backend IO stats with lun list $lun_list"
+if is_linux; then
+       export collect_scripts=("$ZPOOL iostat -lpvyL $PERFPOOL 1" "zpool.iostat"
+           "$VMSTAT 1" "vmstat" "$MPSTAT -P ALL 1" "mpstat" "$IOSTAT -dxyz 1"
+           "iostat")
+else
+       export collect_scripts=("$PERF_SCRIPTS/io.d $PERFPOOL $lun_list 1" "io"
+           "$VMSTAT 1" "vmstat" "$MPSTAT 1" "mpstat" "$IOSTAT -xcnz 1" "iostat")
+fi
+
+log_note "Sequential writes with $PERF_RUNTYPE settings"
+do_fio_run sequential_writes.fio $TRUE $FALSE
+log_pass "Measure IO stats during sequential write load"
diff --git a/zfs/tests/zfs-tests/tests/perf/regression/setup.ksh b/zfs/tests/zfs-tests/tests/perf/regression/setup.ksh
new file mode 100755 (executable)
index 0000000..5e6fe37
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/ksh
+
+#
+# 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) 2015 by Delphix. All rights reserved.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+[[ -z $FIO ]] && log_fail "Missing fio"
+[[ -z $FREE ]] && log_fail "Missing free"
+[[ -z $IOSTAT ]] && log_fail "Missing iostat"
+[[ -z $LSBLK ]] && log_fail "Missing lsblk"
+[[ -z $MPSTAT ]] && log_fail "Missing mpstat"
+[[ -z $VMSTAT ]] && log_fail "Missing vmstat"
+
+verify_runnable "global"
+verify_disk_count "$DISKS" 3
+
+log_pass
diff --git a/zfs/tests/zfs-tests/tests/perf/scripts/Makefile.am b/zfs/tests/zfs-tests/tests/perf/scripts/Makefile.am
new file mode 100644 (file)
index 0000000..f0d45e1
--- /dev/null
@@ -0,0 +1,2 @@
+pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/perf/scripts
+dist_pkgdata_SCRIPTS = prefetch_io.sh
diff --git a/zfs/tests/zfs-tests/tests/perf/scripts/prefetch_io.sh b/zfs/tests/zfs-tests/tests/perf/scripts/prefetch_io.sh
new file mode 100755 (executable)
index 0000000..3dd9e6c
--- /dev/null
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+#
+# 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 Intel, Corp.
+#
+
+#
+# Linux platform placeholder for collecting prefetch I/O stats
+# TBD if we can add additional kstats to achieve the desired results
+#
+
+zfs_kstats="/proc/spl/kstat/zfs"
+
+AWK=${AWK:-awk}
+DATE=${DATE:-date}
+
+function get_prefetch_ios
+{
+        typeset -l data_misses=`$AWK '$1 == "prefetch_data_misses" \
+            { print $3 }' $zfs_kstats/arcstats`
+        typeset -l metadata_misses=`$AWK '$1 == "prefetch_metadata_misses" \
+            { print $3 }' $zfs_kstats/arcstats`
+        typeset -l total_misses=$(( $data_misses + $metadata_misses ))
+
+        echo $total_misses
+}
+
+function get_prefetched_demand_reads
+{
+       typeset -l demand_reads=`$AWK '$1 == "demand_hit_predictive_prefetch" \
+           { print $3 }' $zfs_kstats/arcstats`
+
+       echo $demand_reads
+}
+
+function get_sync_wait_for_async
+{
+       typeset -l sync_wait=`$AWK '$1 == "sync_wait_for_async" \
+           { print $3 }' $zfs_kstats/arcstats`
+
+       echo $sync_wait
+}
+
+if [ $# -ne 2 ]
+then
+       echo "Usage: `basename $0` <poolname> interval" >&2
+       exit 1
+fi
+
+poolname=$1
+interval=$2
+prefetch_ios=$(get_prefetch_ios)
+prefetched_demand_reads=$(get_prefetched_demand_reads)
+sync_wait_for_async=$(get_sync_wait_for_async)
+
+while true
+do
+       new_prefetch_ios=$(get_prefetch_ios)
+       printf "%u\n%-24s\t%u\n" $($DATE +%s) "prefetch_ios" \
+           $(( $new_prefetch_ios - $prefetch_ios ))
+       prefetch_ios=$new_prefetch_ios
+
+       new_prefetched_demand_reads=$(get_prefetched_demand_reads)
+       printf "%-24s\t%u\n" "prefetched_demand_reads" \
+           $(( $new_prefetched_demand_reads - $prefetched_demand_reads ))
+       prefetched_demand_reads=$new_prefetched_demand_reads
+
+       new_sync_wait_for_async=$(get_sync_wait_for_async)
+       printf "%-24s\t%u\n" "sync_wait_for_async" \
+           $(( $new_sync_wait_for_async - $sync_wait_for_async ))
+       sync_wait_for_async=$new_sync_wait_for_async
+
+       sleep $interval
+done
diff --git a/zfs/tests/zfs-tests/tests/stress/Makefile.am b/zfs/tests/zfs-tests/tests/stress/Makefile.am
new file mode 100644 (file)
index 0000000..741f850
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS =
diff --git a/zfs/udev/Makefile.am b/zfs/udev/Makefile.am
new file mode 100644 (file)
index 0000000..f930941
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = rules.d
diff --git a/zfs/udev/Makefile.in b/zfs/udev/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
index b3e8c1303bda612cfbec58359220e20cc62e48d7..199f77e0ceb944d9b4be65ff6432a66a5d3149c1 100644 (file)
@@ -1,2 +1,6 @@
-%:
-       #
+# Persistent links for zvol
+#
+# persistent disk links: /dev/zvol/dataset_name
+# also creates compatibilty symlink of /dev/dataset_name
+
+KERNEL=="zd*" SUBSYSTEM=="block" ACTION=="add|change" PROGRAM="@udevdir@/zvol_id $tempnode" SYMLINK+="zvol/%c %c"
index b3e8c1303bda612cfbec58359220e20cc62e48d7..2b9e5d600062afbb09c6fb9d59fb932e7a8f2efe 100644 (file)
@@ -1,2 +1,10 @@
-%:
-       #
+#
+# @udevdir@/rules.d/69-vdev.rules
+#
+
+ENV{DEVTYPE}=="disk", IMPORT{program}="@udevdir@/vdev_id -d %k"
+ENV{DEVTYPE}=="partition", IMPORT{program}="@udevdir@/vdev_id -d %k"
+
+KERNEL=="*[!0-9]", ENV{SUBSYSTEM}=="block", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}"
+KERNEL=="*[0-9]", ENV{SUBSYSTEM}=="block", ENV{DEVTYPE}=="partition", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}-part%n"
+KERNEL=="dm-[0-9]*", ENV{SUBSYSTEM}=="block", ENV{ID_VDEV}=="?*", SYMLINK+="$env{ID_VDEV_PATH}"
index b3e8c1303bda612cfbec58359220e20cc62e48d7..855c154040f5a9b17fe67c8d6e22f15c1f0cf3d3 100644 (file)
@@ -1,2 +1,12 @@
-%:
-       #
+SUBSYSTEM!="block|misc", GOTO="zfs_end"
+ACTION!="add|change", GOTO="zfs_end"
+
+ENV{ID_FS_TYPE}=="zfs", RUN+="/sbin/modprobe zfs"
+ENV{ID_FS_TYPE}=="zfs_member", RUN+="/sbin/modprobe zfs"
+
+KERNEL=="null", SYMLINK+="root"
+SYMLINK=="null", SYMLINK+="root"
+
+SUBSYSTEM=="misc", KERNEL=="zfs", MODE="0666"
+
+LABEL="zfs_end"
diff --git a/zfs/udev/rules.d/Makefile.am b/zfs/udev/rules.d/Makefile.am
new file mode 100644 (file)
index 0000000..f79ea4b
--- /dev/null
@@ -0,0 +1,20 @@
+udevrule_DATA = \
+       69-vdev.rules \
+       60-zvol.rules \
+       90-zfs.rules
+
+EXTRA_DIST = \
+       $(top_srcdir)/udev/rules.d/69-vdev.rules.in \
+       $(top_srcdir)/udev/rules.d/60-zvol.rules.in \
+       $(top_srcdir)/udev/rules.d/90-zfs.rules.in
+
+$(udevrule_DATA):%:%.in
+       -$(SED) -e 's,@bindir\@,$(bindir),g' \
+               -e 's,@sbindir\@,$(sbindir),g' \
+               -e 's,@udevdir\@,$(udevdir),g' \
+               -e 's,@udevruledir\@,$(udevruledir),g' \
+               -e 's,@sysconfdir\@,$(sysconfdir),g' \
+               $< > '$@'
+
+distclean-local::
+       -$(RM) $(udevrule_DATA)
diff --git a/zfs/udev/rules.d/Makefile.in b/zfs/udev/rules.d/Makefile.in
deleted file mode 100644 (file)
index b3e8c13..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-%:
-       #
index 10d24f027f2f3725c624e3124a33fbe257715b21..d1ba71d7641b45ee6c820e52bd6b44cf9d391423 100644 (file)
@@ -1,66 +1,99 @@
-#!/bin/bash
+export KERNELSRC=@LINUX@
+export KERNELBUILD=@LINUX_OBJ@
+export KERNELSRCVER=@LINUX_VERSION@
+export KERNELMOD=/lib/modules/${KERNELSRCVER}/kernel
 
-KERNELSRC=@LINUX@
-KERNELBUILD=@LINUX_OBJ@
-KERNELSRCVER=@LINUX_VERSION@
-KERNELMOD=/lib/modules/${KERNELSRCVER}/kernel
+export SPLSRC=@SPL@
+export SPLBUILD=@SPL_OBJ@
+export SPLSRCVER=@SPL_VERSION@
 
-SPLSRC=@SPL@
-SPLBUILD=@SPL_OBJ@
-SPLSRCVER=@SPL_VERSION@
+export SRCDIR=@abs_top_srcdir@
+export BUILDDIR=@abs_top_builddir@
+export LIBDIR=${BUILDDIR}/lib
+export CMDDIR=${BUILDDIR}/cmd
+export MODDIR=${BUILDDIR}/module
+export SCRIPTDIR=${BUILDDIR}/scripts
+export ZPOOLDIR=${BUILDDIR}/scripts/zpool-config
+export ZPIOSDIR=${BUILDDIR}/scripts/zpios-test
+export ZPIOSPROFILEDIR=${BUILDDIR}/scripts/zpios-profile
+export ETCDIR=${SRCDIR}/etc
+export TESTSDIR=${SRCDIR}/tests
+export RUNFILEDIR=${TESTSDIR}/runfiles
+export UDEVRULEDIR=${BUILDDIR}/udev/rules.d
 
-SRCDIR=@abs_top_srcdir@
-BUILDDIR=@abs_top_builddir@
-LIBDIR=${BUILDDIR}/lib
-CMDDIR=${BUILDDIR}/cmd
-MODDIR=${BUILDDIR}/module
-SCRIPTDIR=${BUILDDIR}/scripts
-ZPOOLDIR=${BUILDDIR}/scripts/zpool-config
-ZPIOSDIR=${BUILDDIR}/scripts/zpios-test
-ZPIOSPROFILEDIR=${BUILDDIR}/scripts/zpios-profile
-ETCDIR=${SRCDIR}/etc
+export ZDB=${CMDDIR}/zdb/zdb
+export ZFS=${CMDDIR}/zfs/zfs
+export ZHACK=${CMDDIR}/zhack/zhack
+export ZINJECT=${CMDDIR}/zinject/zinject
+export ZPOOL=${CMDDIR}/zpool/zpool
+export ZTEST=${CMDDIR}/ztest/ztest
+export ZPIOS=${CMDDIR}/zpios/zpios
+export RAIDZ_TEST=${CMDDIR}/raidz_test/raidz_test
+export ARC_SUMMARY=${CMDDIR}/arc_summary/arc_summary.py
+export ARCSTAT=${CMDDIR}/arcstat/arcstat.py
+export DBUFSTAT=${CMDDIR}/dbufstat/dbufstat.py
 
-ZDB=${CMDDIR}/zdb/zdb
-ZFS=${CMDDIR}/zfs/zfs
-ZINJECT=${CMDDIR}/zinject/zinject
-ZPOOL=${CMDDIR}/zpool/zpool
-ZTEST=${CMDDIR}/ztest/ztest
-ZPIOS=${CMDDIR}/zpios/zpios
+export COMMON_SH=${SCRIPTDIR}/common.sh
+export ZFS_SH=${SCRIPTDIR}/zfs.sh
+export ZPOOL_CREATE_SH=${SCRIPTDIR}/zpool-create.sh
+export ZPIOS_SH=${SCRIPTDIR}/zpios.sh
+export ZPIOS_SURVEY_SH=${SCRIPTDIR}/zpios-survey.sh
 
-COMMON_SH=${SCRIPTDIR}/common.sh
-ZFS_SH=${SCRIPTDIR}/zfs.sh
-ZPOOL_CREATE_SH=${SCRIPTDIR}/zpool-create.sh
-ZPIOS_SH=${SCRIPTDIR}/zpios.sh
-ZPIOS_SURVEY_SH=${SCRIPTDIR}/zpios-survey.sh
+# Test Suite Specific Commands
+export TEST_RUNNER=${TESTSDIR}/test-runner/cmd/test-runner.py
+export STF_TOOLS=${TESTSDIR}/test-runner
+export STF_SUITE=${TESTSDIR}/zfs-tests
 
-INTREE=1
-LDMOD=/sbin/insmod
+export CHG_USR_EXEC=${TESTSDIR}/zfs-tests/cmd/chg_usr_exec/chg_usr_exec
+export DEVNAME2DEVID=${TESTSDIR}/zfs-tests/cmd/devname2devid/devname2devid
+export DIR_RD_UPDATE=${TESTSDIR}/zfs-tests/cmd/dir_rd_update/dir_rd_update
+export FILE_CHECK=${TESTSDIR}/zfs-tests/cmd/file_check/file_check
+export FILE_TRUNC=${TESTSDIR}/zfs-tests/cmd/file_trunc/file_trunc
+export FILE_WRITE=${TESTSDIR}/zfs-tests/cmd/file_write/file_write
+export LARGEST_FILE=${TESTSDIR}/zfs-tests/cmd/largest_file/largest_file
+export MKBUSY=${TESTSDIR}/zfs-tests/cmd/mkbusy/mkbusy
+export MKFILE=${TESTSDIR}/zfs-tests/cmd/mkfile/mkfile
+export MKFILES=${TESTSDIR}/zfs-tests/cmd/mkfiles/mkfiles
+export MKTREE=${TESTSDIR}/zfs-tests/cmd/mktree/mktree
+export MMAP_EXEC=${TESTSDIR}/zfs-tests/cmd/mmap_exec/mmap_exec
+export MMAPWRITE=${TESTSDIR}/zfs-tests/cmd/mmapwrite/mmapwrite
+export RANDFREE_FILE=${TESTSDIR}/zfs-tests/cmd/randfree_file/randfree_file
+export READMMAP=${TESTSDIR}/zfs-tests/cmd/readmmap/readmmap
+export RENAME_DIR=${TESTSDIR}/zfs-tests/cmd/rename_dir/rename_dir
+export RM_LNKCNT_ZERO_FILE=${TESTSDIR}/zfs-tests/cmd/rm_lnkcnt_zero_file/rm_lnkcnt_zero_file
+export THREADSAPPEND=${TESTSDIR}/zfs-tests/cmd/threadsappend/threadsappend
+export XATTRTEST=${TESTSDIR}/zfs-tests/cmd/xattrtest/xattrtest
 
-ZED_PIDFILE=@runstatedir@/zed.pid
+export INTREE=1
+export LDMOD=/sbin/insmod
+export GDB="/usr/bin/libtool --mode=execute gdb"
 
-KERNEL_MODULES=(                                      \
+export ZED_PIDFILE=@runstatedir@/zed.pid
+
+export KERNEL_MODULES=(                               \
         ${KERNELMOD}/lib/zlib_deflate/zlib_deflate.ko \
         ${KERNELMOD}/lib/zlib_inflate/zlib_inflate.ko \
 )
 
-SPL_MODULES=(                                         \
+export SPL_MODULES=(                                  \
         ${SPLBUILD}/module/spl/spl.ko                 \
         ${SPLBUILD}/module/splat/splat.ko             \
 )
 
-ZFS_MODULES=(                                         \
+export ZFS_MODULES=(                                  \
         ${MODDIR}/avl/zavl.ko                         \
         ${MODDIR}/nvpair/znvpair.ko                   \
         ${MODDIR}/unicode/zunicode.ko                 \
         ${MODDIR}/zcommon/zcommon.ko                  \
+        ${MODDIR}/icp/icp.ko                          \
         ${MODDIR}/zfs/zfs.ko                          \
 )
 
-ZPIOS_MODULES=(                                       \
+export ZPIOS_MODULES=(                                \
         ${MODDIR}/zpios/zpios.ko                      \
 )
 
-MODULES=(                                             \
+export MODULES=(                                      \
         ${SPL_MODULES[*]}                             \
         ${ZFS_MODULES[*]}                             \
 )
diff --git a/zfs/zfs_config.h.in b/zfs/zfs_config.h.in
deleted file mode 100644 (file)
index c83bfeb..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-/* zfs_config.h.in.  Generated from configure.ac by autoheader.  */
-
-/* Define to 1 to enabled dmu tx validation */
-#undef DEBUG_DMU_TX
-
-/* bio_end_io_t wants 1 arg */
-#undef HAVE_1ARG_BIO_END_IO_T
-
-/* invalidate_bdev() wants 1 arg */
-#undef HAVE_1ARG_INVALIDATE_BDEV
-
-/* kmap_atomic wants 1 args */
-#undef HAVE_1ARG_KMAP_ATOMIC
-
-/* submit_bio() wants 1 arg */
-#undef HAVE_1ARG_SUBMIT_BIO
-
-/* bdi_setup_and_register() wants 2 args */
-#undef HAVE_2ARGS_BDI_SETUP_AND_REGISTER
-
-/* bdi_setup_and_register() wants 3 args */
-#undef HAVE_3ARGS_BDI_SETUP_AND_REGISTER
-
-/* blkdev_get() wants 3 args */
-#undef HAVE_3ARG_BLKDEV_GET
-
-/* sget() wants 5 args */
-#undef HAVE_5ARG_SGET
-
-/* security_inode_init_security wants 6 args */
-#undef HAVE_6ARGS_SECURITY_INODE_INIT_SECURITY
-
-/* dops->automount() exists */
-#undef HAVE_AUTOMOUNT
-
-/* struct block_device_operations use bdevs */
-#undef HAVE_BDEV_BLOCK_DEVICE_OPERATIONS
-
-/* bdev_logical_block_size() is available */
-#undef HAVE_BDEV_LOGICAL_BLOCK_SIZE
-
-/* bdev_physical_block_size() is available */
-#undef HAVE_BDEV_PHYSICAL_BLOCK_SIZE
-
-/* bio->bi_opf is defined */
-#undef HAVE_BIO_BI_OPF
-
-/* bio has bi_iter */
-#undef HAVE_BIO_BVEC_ITER
-
-/* BIO_RW_BARRIER is defined */
-#undef HAVE_BIO_RW_BARRIER
-
-/* BIO_RW_DISCARD is defined */
-#undef HAVE_BIO_RW_DISCARD
-
-/* BIO_RW_FAILFAST_* are defined */
-#undef HAVE_BIO_RW_FAILFAST_DTD
-
-/* blkdev_get_by_path() is available */
-#undef HAVE_BLKDEV_GET_BY_PATH
-
-/* blk_queue_flush() is available */
-#undef HAVE_BLK_QUEUE_FLUSH
-
-/* blk_queue_flush() is GPL-only */
-#undef HAVE_BLK_QUEUE_FLUSH_GPL_ONLY
-
-/* blk_queue_max_hw_sectors() is available */
-#undef HAVE_BLK_QUEUE_MAX_HW_SECTORS
-
-/* blk_queue_max_segments() is available */
-#undef HAVE_BLK_QUEUE_MAX_SEGMENTS
-
-/* blk_queue_write_cache() exists */
-#undef HAVE_BLK_QUEUE_WRITE_CACHE
-
-/* blk_queue_write_cache() is GPL-only */
-#undef HAVE_BLK_QUEUE_WRITE_CACHE_GPL_ONLY
-
-/* struct block_device_operations.release returns void */
-#undef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
-
-/* security_inode_init_security wants callback */
-#undef HAVE_CALLBACK_SECURITY_INODE_INIT_SECURITY
-
-/* iops->check_acl() exists */
-#undef HAVE_CHECK_ACL
-
-/* iops->check_acl() wants flags */
-#undef HAVE_CHECK_ACL_WITH_FLAGS
-
-/* check_disk_size_change() is available */
-#undef HAVE_CHECK_DISK_SIZE_CHANGE
-
-/* clear_inode() is available */
-#undef HAVE_CLEAR_INODE
-
-/* eops->commit_metadata() exists */
-#undef HAVE_COMMIT_METADATA
-
-/* dentry uses const struct dentry_operations */
-#undef HAVE_CONST_DENTRY_OPERATIONS
-
-/* super_block uses const struct xattr_handler */
-#undef HAVE_CONST_XATTR_HANDLER
-
-/* iops->create() passes nameidata */
-#undef HAVE_CREATE_NAMEIDATA
-
-/* current->bio_list exists */
-#undef HAVE_CURRENT_BIO_LIST
-
-/* current->bio_tail exists */
-#undef HAVE_CURRENT_BIO_TAIL
-
-/* DECLARE_EVENT_CLASS() is available */
-#undef HAVE_DECLARE_EVENT_CLASS
-
-/* sops->dirty_inode() wants flags */
-#undef HAVE_DIRTY_INODE_WITH_FLAGS
-
-/* ql->discard_granularity is available */
-#undef HAVE_DISCARD_GRANULARITY
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#undef HAVE_DLFCN_H
-
-/* d_make_root() is available */
-#undef HAVE_D_MAKE_ROOT
-
-/* d_obtain_alias() is available */
-#undef HAVE_D_OBTAIN_ALIAS
-
-/* d_prune_aliases() is available */
-#undef HAVE_D_PRUNE_ALIASES
-
-/* dops->d_revalidate() operation takes nameidata */
-#undef HAVE_D_REVALIDATE_NAMEIDATA
-
-/* d_set_d_op() is available */
-#undef HAVE_D_SET_D_OP
-
-/* elevator_change() is available */
-#undef HAVE_ELEVATOR_CHANGE
-
-/* eops->encode_fh() wants child and parent inodes */
-#undef HAVE_ENCODE_FH_WITH_INODE
-
-/* sops->evict_inode() exists */
-#undef HAVE_EVICT_INODE
-
-/* fops->fallocate() exists */
-#undef HAVE_FILE_FALLOCATE
-
-/* file_inode() is available */
-#undef HAVE_FILE_INODE
-
-/* kernel defines fmode_t */
-#undef HAVE_FMODE_T
-
-/* follow_down_one() is available */
-#undef HAVE_FOLLOW_DOWN_ONE
-
-/* iops->follow_link() cookie */
-#undef HAVE_FOLLOW_LINK_COOKIE
-
-/* iops->follow_link() nameidata */
-#undef HAVE_FOLLOW_LINK_NAMEIDATA
-
-/* sops->free_cached_objects() exists */
-#undef HAVE_FREE_CACHED_OBJECTS
-
-/* fops->fsync() with range */
-#undef HAVE_FSYNC_RANGE
-
-/* fops->fsync() without dentry */
-#undef HAVE_FSYNC_WITHOUT_DENTRY
-
-/* fops->fsync() with dentry */
-#undef HAVE_FSYNC_WITH_DENTRY
-
-/* generic_start_io_acct()/generic_end_io_acct() avaliable */
-#undef HAVE_GENERIC_IO_ACCT
-
-/* iops->get_acl() exists */
-#undef HAVE_GET_ACL
-
-/* blk_disk_ro() is available */
-#undef HAVE_GET_DISK_RO
-
-/* get_gendisk() is available */
-#undef HAVE_GET_GENDISK
-
-/* iops->get_link() cookie */
-#undef HAVE_GET_LINK_COOKIE
-
-/* iops->get_link() delayed */
-#undef HAVE_GET_LINK_DELAYED
-
-/* fops->fallocate() exists */
-#undef HAVE_INODE_FALLOCATE
-
-/* inode_owner_or_capable() exists */
-#undef HAVE_INODE_OWNER_OR_CAPABLE
-
-/* iops->truncate_range() exists */
-#undef HAVE_INODE_TRUNCATE_RANGE
-
-/* insert_inode_locked() is available */
-#undef HAVE_INSERT_INODE_LOCKED
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#undef HAVE_INTTYPES_H
-
-/* is_owner_or_cap() exists */
-#undef HAVE_IS_OWNER_OR_CAP
-
-/* uncached_acl_sentinel() exists */
-#undef HAVE_KERNEL_GET_ACL_HANDLE_CACHE
-
-/* kernel defines KOBJ_NAME_LEN */
-#undef HAVE_KOBJ_NAME_LEN
-
-/* Define if you have libblkid */
-#undef HAVE_LIBBLKID
-
-/* Define if you have libuuid */
-#undef HAVE_LIBUUID
-
-/* Define to 1 if you have the `z' library (-lz). */
-#undef HAVE_LIBZ
-
-/* lookup_bdev() is available */
-#undef HAVE_LOOKUP_BDEV
-
-/* iops->lookup() passes nameidata */
-#undef HAVE_LOOKUP_NAMEIDATA
-
-/* lseek_execute() is available */
-#undef HAVE_LSEEK_EXECUTE
-
-/* Noting that make_request_fn() returns int */
-#undef HAVE_MAKE_REQUEST_FN_RET_INT
-
-/* Noting that make_request_fn() returns blk_qc_t */
-#undef HAVE_MAKE_REQUEST_FN_RET_QC
-
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
-
-/* iops->create()/mkdir()/mknod() take umode_t */
-#undef HAVE_MKDIR_UMODE_T
-
-/* Define to 1 if you have the `mlockall' function. */
-#undef HAVE_MLOCKALL
-
-/* mount_nodev() is available */
-#undef HAVE_MOUNT_NODEV
-
-/* sops->nr_cached_objects() exists */
-#undef HAVE_NR_CACHED_OBJECTS
-
-/* open_bdev_exclusive() is available */
-#undef HAVE_OPEN_BDEV_EXCLUSIVE
-
-/* iops->permission() exists */
-#undef HAVE_PERMISSION
-
-/* iops->permission() with nameidata exists */
-#undef HAVE_PERMISSION_WITH_NAMEIDATA
-
-/* posix_acl_chmod() exists */
-#undef HAVE_POSIX_ACL_CHMOD
-
-/* posix_acl_equiv_mode wants umode_t* */
-#undef HAVE_POSIX_ACL_EQUIV_MODE_UMODE_T
-
-/* posix_acl_from_xattr() needs user_ns */
-#undef HAVE_POSIX_ACL_FROM_XATTR_USERNS
-
-/* posix_acl_release() is available */
-#undef HAVE_POSIX_ACL_RELEASE
-
-/* posix_acl_release() is GPL-only */
-#undef HAVE_POSIX_ACL_RELEASE_GPL_ONLY
-
-/* posix_acl_valid() wants user namespace */
-#undef HAVE_POSIX_ACL_VALID_WITH_NS
-
-/* iops->put_link() cookie */
-#undef HAVE_PUT_LINK_COOKIE
-
-/* iops->put_link() delayed */
-#undef HAVE_PUT_LINK_DELAYED
-
-/* iops->put_link() nameidata */
-#undef HAVE_PUT_LINK_NAMEIDATA
-
-/* REQ_FAILFAST_MASK is defined */
-#undef HAVE_REQ_FAILFAST_MASK
-
-/* REQ_OP_DISCARD is defined */
-#undef HAVE_REQ_OP_DISCARD
-
-/* REQ_OP_FLUSH is defined */
-#undef HAVE_REQ_OP_FLUSH
-
-/* REQ_OP_SECURE_ERASE is defined */
-#undef HAVE_REQ_OP_SECURE_DISCARD
-
-/* set_nlink() is available */
-#undef HAVE_SET_NLINK
-
-/* sops->show_options() with dentry */
-#undef HAVE_SHOW_OPTIONS_WITH_DENTRY
-
-/* struct super_block has s_shrink */
-#undef HAVE_SHRINK
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#undef HAVE_STDINT_H
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#undef HAVE_STDLIB_H
-
-/* Define to 1 if you have the <strings.h> header file. */
-#undef HAVE_STRINGS_H
-
-/* Define to 1 if you have the <string.h> header file. */
-#undef HAVE_STRING_H
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#undef HAVE_SYS_STAT_H
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#undef HAVE_SYS_TYPES_H
-
-/* struct super_block has s_d_op */
-#undef HAVE_S_D_OP
-
-/* struct super_block has s_instances list_head */
-#undef HAVE_S_INSTANCES_LIST_HEAD
-
-/* truncate_setsize() is available */
-#undef HAVE_TRUNCATE_SETSIZE
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#undef HAVE_UNISTD_H
-
-/* fops->iterate() is available */
-#undef HAVE_VFS_ITERATE
-
-/* fops->iterate_shared() is available */
-#undef HAVE_VFS_ITERATE_SHARED
-
-/* fops->readdir() is available */
-#undef HAVE_VFS_READDIR
-
-/* fops->read/write_iter() are available */
-#undef HAVE_VFS_RW_ITERATE
-
-/* xattr_handler->get() wants dentry */
-#undef HAVE_XATTR_GET_DENTRY
-
-/* xattr_handler->get() wants both dentry and inode */
-#undef HAVE_XATTR_GET_DENTRY_INODE
-
-/* xattr_handler->get() wants xattr_handler */
-#undef HAVE_XATTR_GET_HANDLER
-
-/* xattr_handler->get() wants inode */
-#undef HAVE_XATTR_GET_INODE
-
-/* xattr_handler has name */
-#undef HAVE_XATTR_HANDLER_NAME
-
-/* xattr_handler->list() wants dentry */
-#undef HAVE_XATTR_LIST_DENTRY
-
-/* xattr_handler->list() wants xattr_handler */
-#undef HAVE_XATTR_LIST_HANDLER
-
-/* xattr_handler->list() wants inode */
-#undef HAVE_XATTR_LIST_INODE
-
-/* xattr_handler->list() wants simple */
-#undef HAVE_XATTR_LIST_SIMPLE
-
-/* xattr_handler->set() wants dentry */
-#undef HAVE_XATTR_SET_DENTRY
-
-/* xattr_handler->set() wants both dentry and inode */
-#undef HAVE_XATTR_SET_DENTRY_INODE
-
-/* xattr_handler->set() wants xattr_handler */
-#undef HAVE_XATTR_SET_HANDLER
-
-/* xattr_handler->set() wants inode */
-#undef HAVE_XATTR_SET_INODE
-
-/* Define if you have zlib */
-#undef HAVE_ZLIB
-
-/* __posix_acl_chmod() exists */
-#undef HAVE___POSIX_ACL_CHMOD
-
-/* Define to the sub-directory where libtool stores uninstalled libraries. */
-#undef LT_OBJDIR
-
-/* make_request_fn() returns blk_qc_t */
-#undef MAKE_REQUEST_FN_RET
-
-/* Name of package */
-#undef PACKAGE
-
-/* Define to the address where bug reports for this package should be sent. */
-#undef PACKAGE_BUGREPORT
-
-/* Define to the full name of this package. */
-#undef PACKAGE_NAME
-
-/* Define to the full name and version of this package. */
-#undef PACKAGE_STRING
-
-/* Define to the one symbol short name of this package. */
-#undef PACKAGE_TARNAME
-
-/* Define to the home page for this package. */
-#undef PACKAGE_URL
-
-/* Define to the version of this package. */
-#undef PACKAGE_VERSION
-
-/* struct shrink_control has nid */
-#undef SHRINK_CONTROL_HAS_NID
-
-/* Define to 1 if you have the ANSI C header files. */
-#undef STDC_HEADERS
-
-/* Version number of package */
-#undef VERSION
-
-/* zfs debugging enabled */
-#undef ZFS_DEBUG
-
-/* Define to 1 if GPL-only symbols can be used */
-#undef ZFS_IS_GPL_COMPATIBLE
-
-/* Define the project alias string. */
-#undef ZFS_META_ALIAS
-
-/* Define the project author. */
-#undef ZFS_META_AUTHOR
-
-/* Define the project release date. */
-#undef ZFS_META_DATA
-
-/* Define the project license. */
-#undef ZFS_META_LICENSE
-
-/* Define the libtool library 'age' version information. */
-#undef ZFS_META_LT_AGE
-
-/* Define the libtool library 'current' version information. */
-#undef ZFS_META_LT_CURRENT
-
-/* Define the libtool library 'revision' version information. */
-#undef ZFS_META_LT_REVISION
-
-/* Define the project name. */
-#undef ZFS_META_NAME
-
-/* Define the project release. */
-#undef ZFS_META_RELEASE
-
-/* Define the project version. */
-#undef ZFS_META_VERSION
-
-
-#undef PACKAGE
-#undef PACKAGE_BUGREPORT
-#undef PACKAGE_NAME
-#undef PACKAGE_STRING
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
-#undef STDC_HEADERS
-#undef VERSION